231 lines
7.8 KiB
PHP
231 lines
7.8 KiB
PHP
<?php
|
|
|
|
/**
|
|
* reschedule.php
|
|
* --------------------------------------------------------------------------
|
|
* Riprogramma una lezione esistente su un nuovo slot.
|
|
* Fedele a rebookandgo.php, ma con prepared statement e controlli di sicurezza.
|
|
*
|
|
* Posizione: public/api/reschedule.php
|
|
* Metodo: POST
|
|
* Auth: Bearer token (Sanctum, gestito da _bootstrap.php)
|
|
*
|
|
* Body (JSON):
|
|
* - booking_id (int) -> idbookingclass della lezione da spostare
|
|
* - new_schedule_id (int) -> idserviceschedule del nuovo slot scelto
|
|
*
|
|
* Logica (come rebookandgo.php):
|
|
* 1. Verifica che il booking sia dell'utente. Legge idorder, idservice vecchi.
|
|
* 2. Controlla maxreschedule (reprogrammed < maxreschedule).
|
|
* 3. Verifica che il nuovo slot esista e sia di un servizio COMPATIBILE.
|
|
* 4. Verifica posto libero e che l'utente non sia già su quello slot.
|
|
* 5. Cancella il vecchio booking, inserisce il nuovo con status 'pending',
|
|
* salvando prevbookingstart / idprevserviceschedule.
|
|
* 6. Incrementa orderbook.reprogrammed.
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
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)) {
|
|
$bookingId = (int) ($json['booking_id'] ?? 0);
|
|
$newScheduleId = (int) ($json['new_schedule_id'] ?? 0);
|
|
} else {
|
|
$bookingId = (int) ($_POST['booking_id'] ?? 0);
|
|
$newScheduleId = (int) ($_POST['new_schedule_id'] ?? 0);
|
|
}
|
|
|
|
if ($bookingId <= 0 || $newScheduleId <= 0) {
|
|
http_response_code(400);
|
|
echo json_encode(['success' => false, 'error' => 'Parametri mancanti']);
|
|
exit;
|
|
}
|
|
|
|
// ==========================================================================
|
|
// 1) Vecchio booking (con ownership)
|
|
// ==========================================================================
|
|
$stmt = $db->prepare("
|
|
SELECT bc.idbookingclass, bc.iduser, bc.idservice, bc.idorder,
|
|
bc.bookingstart, bc.idserviceschedule
|
|
FROM bookingclass bc
|
|
WHERE bc.idbookingclass = :bid AND bc.iduser = :uid
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute([':bid' => $bookingId, ':uid' => $userId]);
|
|
$old = $stmt->fetch();
|
|
|
|
if (!$old) {
|
|
http_response_code(404);
|
|
echo json_encode(['success' => false, 'error' => 'Prenotazione non trovata']);
|
|
exit;
|
|
}
|
|
|
|
$oldServiceId = (int) $old['idservice'];
|
|
$oldOrderId = (int) $old['idorder'];
|
|
$oldSchedId = (int) $old['idserviceschedule'];
|
|
$oldBookingStart = $old['bookingstart'];
|
|
|
|
// ==========================================================================
|
|
// 2) Controllo maxreschedule sull'ordine
|
|
// ==========================================================================
|
|
$stmt = $db->prepare("
|
|
SELECT maxreschedule, reprogrammed
|
|
FROM orderbook
|
|
WHERE idorderbook = :oid
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute([':oid' => $oldOrderId]);
|
|
$order = $stmt->fetch();
|
|
|
|
if ($order) {
|
|
$maxr = (int) ($order['maxreschedule'] ?? 0);
|
|
$repr = (int) ($order['reprogrammed'] ?? 0);
|
|
if ($repr >= $maxr) {
|
|
http_response_code(409);
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => 'Hai raggiunto il numero massimo di riprogrammazioni per questo pacchetto.',
|
|
'code' => 'max_reschedule',
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// ==========================================================================
|
|
// 3) Nuovo slot: esiste? servizio compatibile?
|
|
// ==========================================================================
|
|
$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);
|
|
|
|
// Servizi compatibili col vecchio servizio (associateclass) + se stesso
|
|
$compatible = [$oldServiceId];
|
|
$cs = $db->prepare("SELECT idassociateservice FROM associateclass WHERE idmainservice = :sid");
|
|
$cs->execute([':sid' => $oldServiceId]);
|
|
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 la tua lezione.',
|
|
'code' => 'not_compatible',
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// ==========================================================================
|
|
// 4) Posto libero + non già prenotato dall'utente su quello slot
|
|
// ==========================================================================
|
|
$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;
|
|
}
|
|
|
|
// ==========================================================================
|
|
// 5) + 6) Transazione: cancella vecchio, inserisci nuovo, incrementa reprogrammed
|
|
// ==========================================================================
|
|
try {
|
|
$db->beginTransaction();
|
|
|
|
// Cancella il vecchio (con ownership)
|
|
$del = $db->prepare("
|
|
DELETE FROM bookingclass WHERE idbookingclass = :bid AND iduser = :uid LIMIT 1
|
|
");
|
|
$del->execute([':bid' => $bookingId, ':uid' => $userId]);
|
|
|
|
// Inserisci il nuovo (status pending)
|
|
$ins = $db->prepare("
|
|
INSERT INTO bookingclass
|
|
(idserviceschedule, iduser, prevbookingstart, idprevserviceschedule,
|
|
idservice, idorder, bookingstart, status)
|
|
VALUES
|
|
(:sched, :uid, :prevstart, :prevsched, :service, :order, :newstart, 'pending')
|
|
");
|
|
$ins->execute([
|
|
':sched' => $newScheduleId,
|
|
':uid' => $userId,
|
|
':prevstart' => $oldBookingStart,
|
|
':prevsched' => $oldSchedId,
|
|
':service' => $newServiceId,
|
|
':order' => $oldOrderId,
|
|
':newstart' => $newTime,
|
|
]);
|
|
|
|
// Incrementa reprogrammed
|
|
$upd = $db->prepare("
|
|
UPDATE orderbook SET reprogrammed = reprogrammed + 1 WHERE idorderbook = :oid
|
|
");
|
|
$upd->execute([':oid' => $oldOrderId]);
|
|
|
|
$db->commit();
|
|
} catch (Throwable $e) {
|
|
if ($db->inTransaction()) {
|
|
$db->rollBack();
|
|
}
|
|
http_response_code(500);
|
|
echo json_encode(['success' => false, 'error' => 'Errore durante la riprogrammazione']);
|
|
exit;
|
|
}
|
|
|
|
// ==========================================================================
|
|
// OUTPUT
|
|
// ==========================================================================
|
|
echo json_encode([
|
|
'success' => true,
|
|
'message' => 'Riprogrammazione richiesta. In attesa di conferma.',
|
|
'new_datetime' => $newTime,
|
|
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|