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);