mostra pagina di conferma (NON annulla: * evita che gli scanner email prefetchino il link e annullino da soli) * POST (token + confirm=1) -> annulla e, se la prenotazione occupava posti, * promuove automaticamente la prima in lista d'attesa. */ $pdo = pdo_conn(); $token = trim($_POST['token'] ?? $_GET['token'] ?? ''); $isPost = ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST'; $booking = null; if ($token !== '') { $q = $pdo->prepare("SELECT b.*, e.title AS ev_title, e.starts_at AS ev_starts, e.id AS eid FROM event_bookings b JOIN events e ON e.id = b.event_id WHERE b.token = ?"); $q->execute([$token]); $booking = $q->fetch(PDO::FETCH_ASSOC); } $state = 'form'; // form | notfound | already | toolate | done $promotedCount = 0; $didCancel = false; if (!$booking) { $state = 'notfound'; } elseif ($booking['status'] === 'cancelled') { $state = 'already'; } elseif (strtotime($booking['ev_starts']) <= time()) { $state = 'toolate'; } elseif ($isPost && !empty($_POST['confirm'])) { try { $pdo->beginTransaction(); // Lock evento per serializzare con eventuali prenotazioni concorrenti $pdo->prepare("SELECT id FROM events WHERE id = ? FOR UPDATE")->execute([(int) $booking['eid']]); // Rileggo lo stato aggiornato della prenotazione $bl = $pdo->prepare("SELECT * FROM event_bookings WHERE id = ?"); $bl->execute([(int) $booking['id']]); $fresh = $bl->fetch(PDO::FETCH_ASSOC); if ($fresh && $fresh['status'] !== 'cancelled') { $wasOccupying = in_array($fresh['status'], ['confirmed', 'pending'], true); $pdo->prepare("UPDATE event_bookings SET status = 'cancelled', updated_at = NOW() WHERE id = ?") ->execute([(int) $fresh['id']]); if ($wasOccupying) { $promoted = promoteFromWaitlist($pdo, (int) $booking['eid']); $promotedCount = count($promoted); // Nota: l'email di promozione (E, con riconferma) si attiva nel secondo tempo. } $didCancel = true; } $pdo->commit(); $state = 'done'; // Email di conferma disdetta all'utente (best-effort) if ($didCancel) { try { $evStmt = pdo_conn()->prepare("SELECT * FROM events WHERE id = ?"); $evStmt->execute([(int) $booking['eid']]); $evRow = $evStmt->fetch(PDO::FETCH_ASSOC); if ($evRow) { yse_mail_user_cancel($booking, $evRow); } } catch (Throwable $mailEx) { error_log('[cancel mail] ' . $mailEx->getMessage()); } } } catch (Throwable $ex) { if ($pdo->inTransaction()) { $pdo->rollBack(); } error_log('[apiwp/cancel] ' . $ex->getMessage()); $state = 'error'; } } if (!function_exists('e')) { function e($v): string { return htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8'); } } ?>
Questa prenotazione non esiste o il link è errato.
Questa prenotazione risulta già annullata.
L'evento è già iniziato: non è più possibile annullare online. Contattaci per assistenza.
Riprova tra poco. Se il problema persiste, contattaci.
La tua prenotazione per è stata annullata.
0) : ?>Un posto è stato assegnato alla prima persona in lista d'attesa.
Confermi di voler annullare la prenotazione a nome di ?
Se hai cambiato idea, chiudi pure questa pagina.
Questa prenotazione non esiste o il link è errato.
Questa prenotazione risulta già annullata.
L'evento è già iniziato: non è più possibile annullare online. Contattaci per assistenza.
Riprova tra poco. Se il problema persiste, contattaci.
La tua prenotazione per è stata annullata.
0) : ?>Un posto è stato assegnato alla prima persona in lista d'attesa.
Confermi di voler annullare la prenotazione a nome di ?
Se hai cambiato idea, chiudi pure questa pagina.