Files
2026-08-21 19:26:42 +02:00

199 lines
6.6 KiB
PHP

<?php
/**
* book_from_ticket.php
* --------------------------------------------------------------------------
* Prenota una NUOVA lezione usando un ticket residuo di un ordine.
* Basata su bookandgo.php, con prepared statement e controlli di sicurezza.
*
* Posizione: public/api/book_from_ticket.php
* Metodo: POST
* Auth: Bearer token (Sanctum)
*
* Body (JSON):
* - order_id (int) -> idorderbook da cui pescare il ticket
* - new_schedule_id (int) -> idserviceschedule dello slot scelto
*
* Logica:
* 1. Verifica che l'ordine sia dell'utente e abbia ticket residui.
* 2. Verifica che lo slot esista e sia compatibile col servizio dell'ordine.
* 3. Verifica posto libero e non-già-prenotato.
* 4. Inserisce bookingclass status 'pending' (come bookandgo.php).
* --------------------------------------------------------------------------
*/
require_once __DIR__ . '/_bootstrap.php';
$userId = (int) $user->id;
// ==========================================================================
// INPUT
// ==========================================================================
$raw = file_get_contents('php://input');
$json = json_decode($raw, true);
if (is_array($json)) {
$orderId = (int) ($json['order_id'] ?? 0);
$newScheduleId = (int) ($json['new_schedule_id'] ?? 0);
} else {
$orderId = (int) ($_POST['order_id'] ?? 0);
$newScheduleId = (int) ($_POST['new_schedule_id'] ?? 0);
}
if ($orderId <= 0 || $newScheduleId <= 0) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Parametri mancanti']);
exit;
}
// ==========================================================================
// 1) Ordine dell'utente + ticket residui
// ==========================================================================
$stmt = $db->prepare("
SELECT idorderbook, iduser, idservice, nticket, expireon
FROM orderbook
WHERE idorderbook = :oid AND iduser = :uid
LIMIT 1
");
$stmt->execute([':oid' => $orderId, ':uid' => $userId]);
$order = $stmt->fetch();
if (!$order) {
http_response_code(404);
echo json_encode(['success' => false, 'error' => 'Ordine non trovato']);
exit;
}
$orderServiceId = (int) $order['idservice'];
$nticket = (int) ($order['nticket'] ?? 0);
$expireon = $order['expireon'] ?? null;
// Scadenza ordine
if ($expireon !== null && $expireon < date('Y-m-d')) {
http_response_code(409);
echo json_encode([
'success' => false,
'error' => 'Questo pacchetto è scaduto.',
'code' => 'expired',
]);
exit;
}
// Calcolo ticket residui: nticket - (prenotazioni non cancellate su questo ordine)
$stmt = $db->prepare("
SELECT COUNT(*) AS n
FROM bookingclass
WHERE idorder = :oid AND iduser = :uid AND status != 'cancelled'
");
$stmt->execute([':oid' => $orderId, ':uid' => $userId]);
$used = (int) ($stmt->fetch()['n'] ?? 0);
$residui = $nticket - $used;
if ($residui <= 0) {
http_response_code(409);
echo json_encode([
'success' => false,
'error' => 'Non hai lezioni residue su questo pacchetto.',
'code' => 'no_tickets',
]);
exit;
}
// ==========================================================================
// 2) Slot esiste + compatibile col servizio dell'ordine
// ==========================================================================
$stmt = $db->prepare("
SELECT ss.idserviceschedule, ss.idservice, ss.dateschedule, s.maxcapacity
FROM serviceschedule ss
LEFT JOIN service s ON ss.idservice = s.idservice
WHERE ss.idserviceschedule = :sched
LIMIT 1
");
$stmt->execute([':sched' => $newScheduleId]);
$slot = $stmt->fetch();
if (!$slot) {
http_response_code(404);
echo json_encode(['success' => false, 'error' => 'Slot non trovato']);
exit;
}
$newServiceId = (int) $slot['idservice'];
$newTime = $slot['dateschedule'];
$maxCap = (int) ($slot['maxcapacity'] ?? 0);
$compatible = [$orderServiceId];
$cs = $db->prepare("SELECT idassociateservice FROM associateclass WHERE idmainservice = :sid");
$cs->execute([':sid' => $orderServiceId]);
foreach ($cs->fetchAll() as $r) {
$compatible[] = (int) $r['idassociateservice'];
}
if (!in_array($newServiceId, $compatible, true)) {
http_response_code(409);
echo json_encode([
'success' => false,
'error' => 'Lo slot scelto non è compatibile con questo pacchetto.',
'code' => 'not_compatible',
]);
exit;
}
// ==========================================================================
// 3) Posto libero + non già prenotato
// ==========================================================================
$stmt = $db->prepare("
SELECT COUNT(*) AS n FROM bookingclass
WHERE idserviceschedule = :sched AND status = 'booked'
");
$stmt->execute([':sched' => $newScheduleId]);
$bookedCount = (int) ($stmt->fetch()['n'] ?? 0);
if ($maxCap > 0 && $bookedCount >= $maxCap) {
http_response_code(409);
echo json_encode(['success' => false, 'error' => 'La classe scelta è piena.', 'code' => 'full']);
exit;
}
$stmt = $db->prepare("
SELECT COUNT(*) AS n FROM bookingclass
WHERE idserviceschedule = :sched AND iduser = :uid AND status IN ('booked','pending')
");
$stmt->execute([':sched' => $newScheduleId, ':uid' => $userId]);
if (((int) ($stmt->fetch()['n'] ?? 0)) > 0) {
http_response_code(409);
echo json_encode(['success' => false, 'error' => 'Sei già prenotato/a su questa classe.', 'code' => 'already_booked']);
exit;
}
// ==========================================================================
// 4) Inserimento (status pending, come bookandgo.php)
// ==========================================================================
try {
$ins = $db->prepare("
INSERT INTO bookingclass
(idserviceschedule, iduser, prevbookingstart, idprevserviceschedule,
idservice, idorder, bookingstart, status)
VALUES
(:sched, :uid, NULL, 0, :service, :order, :newstart, 'pending')
");
$ins->execute([
':sched' => $newScheduleId,
':uid' => $userId,
':service' => $newServiceId,
':order' => $orderId,
':newstart' => $newTime,
]);
} catch (Throwable $e) {
http_response_code(500);
echo json_encode(['success' => false, 'error' => 'Errore durante la prenotazione']);
exit;
}
// ==========================================================================
// OUTPUT
// ==========================================================================
echo json_encode([
'success' => true,
'message' => 'Prenotazione richiesta. In attesa di conferma.',
'new_datetime' => $newTime,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);