281 lines
9.5 KiB
PHP
281 lines
9.5 KiB
PHP
<?php
|
|
require_once('Connections/bkngstm.php');
|
|
require_once('webassist/mysqli/rsobj.php');
|
|
include('include/headscript.php'); // $iduserlogin
|
|
|
|
/***********************
|
|
* LOG (mail + debug)
|
|
***********************/
|
|
$logDir = __DIR__ . '/logs';
|
|
if (!is_dir($logDir)) {
|
|
@mkdir($logDir, 0755, true);
|
|
}
|
|
$mailLogFile = $logDir . '/mail_cancel.log';
|
|
|
|
function mail_log($file, $msg)
|
|
{
|
|
@file_put_contents($file, "[" . date("Y-m-d H:i:s") . "] " . $msg . PHP_EOL, FILE_APPEND);
|
|
}
|
|
|
|
/***********************
|
|
* INPUT
|
|
***********************/
|
|
if (!isset($_GET['id'])) {
|
|
die("ID non fornito.");
|
|
}
|
|
|
|
$id = (int)$_GET['id'];
|
|
$userId = (int)$iduserlogin;
|
|
|
|
/***********************
|
|
* DB
|
|
***********************/
|
|
$conn = $bkngstm;
|
|
|
|
/***********************
|
|
* 1) USER INFO (auth_users)
|
|
***********************/
|
|
$stmt = $conn->prepare("SELECT email, first_name, last_name FROM auth_users WHERE id = ? LIMIT 1");
|
|
$stmt->bind_param("i", $userId);
|
|
$stmt->execute();
|
|
$res = $stmt->get_result();
|
|
$u = $res->fetch_assoc();
|
|
$stmt->close();
|
|
|
|
$userEmail = $u['email'] ?? '';
|
|
$userName = trim(($u['first_name'] ?? '') . ' ' . ($u['last_name'] ?? ''));
|
|
|
|
/***********************
|
|
* 2) BOOKING INFO (nome classe + data) + ownership check
|
|
***********************/
|
|
$stmt = $conn->prepare("
|
|
SELECT
|
|
bc.idbookingclass,
|
|
bc.idorder,
|
|
bc.status,
|
|
bc.bookingstart,
|
|
s.servicename,
|
|
ss.dateschedule
|
|
FROM bookingclass bc
|
|
LEFT JOIN service s ON bc.idservice = s.idservice
|
|
LEFT JOIN serviceschedule ss ON bc.idserviceschedule = ss.idserviceschedule
|
|
WHERE bc.idbookingclass = ? AND bc.iduser = ?
|
|
LIMIT 1
|
|
");
|
|
$stmt->bind_param("ii", $id, $userId);
|
|
$stmt->execute();
|
|
$res = $stmt->get_result();
|
|
$bk = $res->fetch_assoc();
|
|
$stmt->close();
|
|
|
|
if (!$bk) {
|
|
header("Location: userpanel.php?deleted=0&err=notfound");
|
|
exit();
|
|
}
|
|
|
|
$className = $bk['servicename'] ?? 'Lezione';
|
|
$classDateRaw = $bk['dateschedule'] ?? null;
|
|
|
|
$classDateTxt = $classDateRaw ? date("d-m-Y H:i", strtotime($classDateRaw)) : 'N/D';
|
|
$cancelDateTxt = date("d-m-Y H:i");
|
|
|
|
/***********************
|
|
* 3) CONTROLLI (stesse regole di userpanel.php)
|
|
***********************/
|
|
// Solo prenotazioni confermate: pending e lista d'attesa hanno i loro percorsi
|
|
if (($bk['status'] ?? '') !== 'booked') {
|
|
header("Location: userpanel.php?deleted=0&err=status");
|
|
exit();
|
|
}
|
|
|
|
// Finestra oraria
|
|
$classTime = new DateTime($classDateRaw ?: $bk['bookingstart']);
|
|
$currentTime = new DateTime();
|
|
|
|
// Lezione già iniziata o passata: non si cancella
|
|
if ($classTime <= $currentTime) {
|
|
header("Location: userpanel.php?deleted=0&err=window");
|
|
exit();
|
|
}
|
|
|
|
// Lezione di oggi: fino alle 17:00 entro le 00:01, dopo le 17:00 entro le 12:00
|
|
if ($classTime->format('Y-m-d') === $currentTime->format('Y-m-d')) {
|
|
$classHour = (int) $classTime->format('H');
|
|
$classMinute = (int) $classTime->format('i');
|
|
$isBefore1700 = ($classHour < 17) || ($classHour === 17 && $classMinute === 0);
|
|
$deadline = new DateTime($classTime->format($isBefore1700 ? 'Y-m-d 00:01:00' : 'Y-m-d 12:00:00'));
|
|
if ($currentTime > $deadline) {
|
|
header("Location: userpanel.php?deleted=0&err=window");
|
|
exit();
|
|
}
|
|
}
|
|
|
|
/***********************
|
|
* 3b) STORICO + RIPROGRAMMAZIONE + CANCELLAZIONE
|
|
* Tutto in una transazione: o riesce tutto o niente.
|
|
***********************/
|
|
$idOrder = $bk['idorder'] !== null ? (int) $bk['idorder'] : null;
|
|
$ord = null;
|
|
$incremented = 'N';
|
|
$ticketLost = false;
|
|
|
|
try {
|
|
$conn->begin_transaction();
|
|
|
|
// Limite riprogrammazioni (stessa regola del pulsante Riprogramma).
|
|
// FOR UPDATE: blocca la riga dell'ordine contro doppi click.
|
|
if ($idOrder !== null) {
|
|
$stmt = $conn->prepare("SELECT reprogrammed, maxreschedule FROM orderbook WHERE idorderbook = ? FOR UPDATE");
|
|
$stmt->bind_param("i", $idOrder);
|
|
$stmt->execute();
|
|
$ord = $stmt->get_result()->fetch_assoc();
|
|
$stmt->close();
|
|
|
|
if ($ord) {
|
|
if ((int) $ord['reprogrammed'] >= (int) $ord['maxreschedule']) {
|
|
// Limite raggiunto: può cancellare (libera il posto) ma il ticket va perso
|
|
$ticketLost = true;
|
|
} else {
|
|
$incremented = 'Y';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copia nello storico (prima di eliminare)
|
|
$stmt = $conn->prepare("
|
|
INSERT INTO bookingclass_cancellations
|
|
(idbookingclass, idserviceschedule, bookingstart, status, idservice, iduser, idorder,
|
|
prevbookingstart, is_reprogrammed, is_gift, booking_created_at,
|
|
cancelled_at, cancelled_by, reprogrammed_incremented)
|
|
SELECT idbookingclass, idserviceschedule, bookingstart, status, idservice, iduser, idorder,
|
|
prevbookingstart, is_reprogrammed, is_gift, created_at,
|
|
NOW(), ?, ?
|
|
FROM bookingclass
|
|
WHERE idbookingclass = ? AND iduser = ?
|
|
");
|
|
$storicoFlag = $ticketLost ? 'L' : $incremented;
|
|
$stmt->bind_param("isii", $userId, $storicoFlag, $id, $userId);
|
|
$stmt->execute();
|
|
$copied = $stmt->affected_rows;
|
|
$stmt->close();
|
|
if ($copied !== 1) {
|
|
throw new RuntimeException('notfound');
|
|
}
|
|
|
|
// La cancellazione conta come una riprogrammazione
|
|
if ($incremented === 'Y') {
|
|
$stmt = $conn->prepare("UPDATE orderbook SET reprogrammed = reprogrammed + 1 WHERE idorderbook = ?");
|
|
$stmt->bind_param("i", $idOrder);
|
|
$stmt->execute();
|
|
$stmt->close();
|
|
}
|
|
|
|
// Limite raggiunto: la prenotazione resta come persa (status 'lost'),
|
|
// il posto in sala si libera ma il ticket non torna da programmare.
|
|
// Altrimenti eliminazione normale: il ticket torna disponibile.
|
|
if ($ticketLost) {
|
|
$stmt = $conn->prepare("UPDATE bookingclass SET status = 'lost', lostlesson = 'Y' WHERE idbookingclass = ? AND iduser = ?");
|
|
} else {
|
|
$stmt = $conn->prepare("DELETE FROM bookingclass WHERE idbookingclass = ? AND iduser = ?");
|
|
}
|
|
$stmt->bind_param("ii", $id, $userId);
|
|
$stmt->execute();
|
|
$deleted = $stmt->affected_rows;
|
|
$stmt->close();
|
|
if ($deleted !== 1) {
|
|
throw new RuntimeException('notfound');
|
|
}
|
|
|
|
$conn->commit();
|
|
} catch (Throwable $e) {
|
|
try {
|
|
$conn->rollback();
|
|
} catch (Throwable $ignored) {
|
|
}
|
|
|
|
$code = in_array($e->getMessage(), ['limit', 'notfound'], true) ? $e->getMessage() : 'db';
|
|
if ($code === 'db') {
|
|
error_log("delete_lesson #{$id} utente #{$userId}: " . $e->getMessage());
|
|
}
|
|
header("Location: userpanel.php?deleted=0&err=" . $code);
|
|
exit();
|
|
}
|
|
// Connessione $bkngstm gestita globalmente: non la chiudiamo qui
|
|
|
|
/***********************
|
|
* 4) EMAIL (TO utente + CC info@yogasoul.it)
|
|
* Usa le chiavi del tuo .env: MAIL_HOST, MAIL_PORT, MAIL_USERNAME, ...
|
|
***********************/
|
|
try {
|
|
// Carica vendor/autoload + dotenv (il tuo file esistente)
|
|
require_once(__DIR__ . '/class/mailer.php');
|
|
|
|
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
|
|
|
|
// Legge le variabili in stile Laravel (con trim per eventuali virgolette)
|
|
$host = trim($_ENV['MAIL_HOST'] ?? 'mail.yogasoul.it', "\" \t\n\r\0\x0B");
|
|
$port = (int)($_ENV['MAIL_PORT'] ?? 465);
|
|
$user = $_ENV['MAIL_USERNAME'] ?? '';
|
|
$pass = $_ENV['MAIL_PASSWORD'] ?? '';
|
|
$enc = strtolower(trim($_ENV['MAIL_ENCRYPTION'] ?? 'ssl', "\" \t\n\r\0\x0B"));
|
|
|
|
$fromEmail = trim($_ENV['MAIL_FROM_ADDRESS'] ?? 'info@yogasoul.it', "\" \t\n\r\0\x0B");
|
|
$fromName = trim($_ENV['MAIL_FROM_NAME'] ?? 'YogiBook', "\" \t\n\r\0\x0B");
|
|
|
|
// Config SMTP
|
|
$mail->isSMTP();
|
|
$mail->Host = $host;
|
|
$mail->SMTPAuth = true;
|
|
$mail->Username = $user;
|
|
$mail->Password = $pass;
|
|
$mail->Port = $port;
|
|
|
|
if (in_array($enc, ['tls', 'ssl'], true)) {
|
|
$mail->SMTPSecure = $enc;
|
|
}
|
|
|
|
// Timeout (utile su SMTP hosting)
|
|
$mail->Timeout = 20;
|
|
|
|
$mail->setFrom($fromEmail, $fromName);
|
|
$mail->CharSet = 'UTF-8';
|
|
$mail->isHTML(true);
|
|
|
|
// Destinatari
|
|
if (!empty($userEmail)) {
|
|
$mail->addAddress($userEmail, $userName ?: '');
|
|
}
|
|
$mail->addCC('info@yogasoul.it');
|
|
|
|
// Log impostazioni usate (senza password)
|
|
mail_log($mailLogFile, "SMTP in uso host={$host} porta={$port} enc={$enc} user={$user}");
|
|
|
|
// Contenuto (ITALIANO)
|
|
$mail->Subject = "Lezione cancellata - {$className}";
|
|
$mail->Body = "
|
|
<div style='font-family:Arial,sans-serif;font-size:14px;color:#222'>
|
|
<p>Ciao " . htmlspecialchars($userName ?: 'Yogi') . ",</p>
|
|
<p>La tua lezione è stata <b>cancellata</b>.</p>" . ($ticketLost ? "
|
|
<p>Avendo già usato tutte le riprogrammazioni del pacchetto, questa lezione non potrà essere recuperata.</p>" : "") . "
|
|
<p>
|
|
<b>Lezione:</b> " . htmlspecialchars($className) . "<br>
|
|
<b>Data/ora prevista:</b> " . htmlspecialchars($classDateTxt) . "<br>
|
|
<b>Data/ora cancellazione:</b> " . htmlspecialchars($cancelDateTxt) . "<br>
|
|
<b>ID prenotazione:</b> #{$id}
|
|
</p>
|
|
<p>Grazie,<br>— " . htmlspecialchars($fromName) . "</p>
|
|
</div>
|
|
";
|
|
|
|
$mail->send();
|
|
|
|
mail_log($mailLogFile, "OK inviata. booking_id={$id} user_id={$userId} to={$userEmail} lezione='" . $className . "' prevista='{$classDateTxt}' cancellata='{$cancelDateTxt}'");
|
|
} catch (Throwable $e) {
|
|
mail_log($mailLogFile, "ERRORE invio. booking_id={$id} user_id={$userId} to={$userEmail} :: " . $e->getMessage());
|
|
error_log("Mailer error (delete booking #{$id}, user #{$userId}): " . $e->getMessage());
|
|
}
|
|
|
|
// Redirect
|
|
header("Location: userpanel.php?deleted=" . ($ticketLost ? 'lost' : '1'));
|
|
exit();
|