199 lines
6.6 KiB
PHP
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);
|