classe destinazione * idservice= servizio della classe * bookingstart= data/ora lezione (dateschedule) * bkmode= * user_id= utente esistente (0 se nuovo) * name, surname, email per creare l'utente se user_id=0 * idorder= solo per 'scala' * new_expiry= solo per 'nuovo' * * Regole identiche alla webapp: * - status sempre 'booked' * - omaggio: idorder NULL, is_gift='Y' * - nuovo: crea orderbook (1 ticket, maxreschedule 0), is_gift='N' * - scala: aggancia ordine esistente (verifica proprietà + scadenza) * - idorder mai 0 (FK): NULL o id reale * - crea utente se user_id=0 (riusa email esistente) * - anti-duplicato: stesso utente già in questa classe * -------------------------------------------------------------------------- */ require_once __DIR__ . '/_bootstrap.php'; // Gate staff $roleId = (int) $user->role_id; if (!in_array($roleId, [1, 3], true)) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'Forbidden']); exit; } // --- Input --- $name = trim($_POST['name'] ?? ''); $surname = trim($_POST['surname'] ?? ''); $email = trim($_POST['email'] ?? ''); $userid = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0; $idserviceschedule = isset($_POST['idserviceschedule']) ? (int) $_POST['idserviceschedule'] : 0; $idservice = isset($_POST['idservice']) ? (int) $_POST['idservice'] : 0; $bookingstart = trim($_POST['bookingstart'] ?? ''); $bkmode = trim($_POST['bkmode'] ?? 'scala'); // scala | omaggio | nuovo $idorderRaw = $_POST['idorder'] ?? ''; $newExpiry = trim($_POST['new_expiry'] ?? ''); $status = 'booked'; // inserimento da insegnante: sempre booked // --- Validazione minima --- if ($idserviceschedule <= 0 || $idservice <= 0) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Dati mancanti (classe/servizio)']); exit; } // Se nuovo utente, servono almeno nome e cognome if ($userid <= 0 && ($name === '' || $surname === '')) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Nome e cognome obbligatori per un nuovo utente']); exit; } try { $db->beginTransaction(); // ------------------------------------------------------------------ // 1) Risolvi / crea utente // ------------------------------------------------------------------ if ($userid <= 0) { if ($email !== '') { $check = $db->prepare("SELECT id FROM auth_users WHERE email = :email LIMIT 1"); $check->execute([':email' => $email]); $existing = $check->fetchColumn(); if ($existing) { $userid = (int) $existing; } } if ($userid <= 0) { $randomPassword = bin2hex(random_bytes(8)); $hashed = password_hash($randomPassword, PASSWORD_BCRYPT); $insUser = $db->prepare( "INSERT INTO auth_users (first_name, last_name, email, password, role_id, status, created_at, avatar) VALUES (:first, :last, :email, :password, :role, :status, :created, :avatar)" ); $insUser->execute([ ':first' => $name, ':last' => $surname, ':email' => $email !== '' ? $email : null, ':password' => $hashed, ':role' => 2, ':status' => 'Active', ':created' => date('Y-m-d H:i:s'), ':avatar' => 'mediationb.png', ]); $userid = (int) $db->lastInsertId(); } } // ------------------------------------------------------------------ // 2) Determina idorder e is_gift in base alla modalità // ------------------------------------------------------------------ $idorder = null; $isGift = 'N'; if ($bkmode === 'omaggio') { $idorder = null; $isGift = 'Y'; } elseif ($bkmode === 'nuovo') { if ($newExpiry === '') { throw new RuntimeException('Scadenza mancante per il nuovo ordine.'); } $uStmt = $db->prepare( "SELECT first_name, last_name, email FROM auth_users WHERE id = :uid LIMIT 1" ); $uStmt->execute([':uid' => $userid]); $uRow = $uStmt->fetch(PDO::FETCH_ASSOC) ?: []; $uEmail = $uRow['email'] ?? ($email !== '' ? $email : null); $uFirst = $uRow['first_name'] ?? $name; $uLast = $uRow['last_name'] ?? $surname; $sStmt = $db->prepare( "SELECT servicename FROM service WHERE idservice = :sid LIMIT 1" ); $sStmt->execute([':sid' => $idservice]); $serviceName = (string) ($sStmt->fetchColumn() ?: ''); $firstLessonDate = null; if ($bookingstart !== '') { try { $firstLessonDate = (new DateTime($bookingstart))->format('Y-m-d'); } catch (Throwable $e) { $firstLessonDate = null; } } $insOrder = $db->prepare( "INSERT INTO orderbook (iduser, idservice, nticket, quantity, quantityclass, expireon, maxreschedule, reprogrammed, status, order_billing_email, cod, product_name, first_name, last_name, first_lesson_date, order_date_created) VALUES (:uid, :service, 1, 1, 1, :expire, 0, 0, 'booked', :bemail, :cod, :pname, :first, :last, :firstlesson, :created)" ); $insOrder->execute([ ':uid' => $userid, ':service' => $idservice, ':expire' => $newExpiry, ':bemail' => $uEmail, ':cod' => $serviceName, ':pname' => $serviceName, ':first' => $uFirst, ':last' => $uLast, ':firstlesson' => $firstLessonDate, ':created' => date('Y-m-d'), ]); $idorder = (int) $db->lastInsertId(); $isGift = 'N'; } else { // 'scala' $idorder = ($idorderRaw !== '' && (int) $idorderRaw > 0) ? (int) $idorderRaw : null; if ($idorder !== null) { $chk = $db->prepare( "SELECT expireon FROM orderbook WHERE idorderbook = :oid AND iduser = :uid LIMIT 1" ); $chk->execute([':oid' => $idorder, ':uid' => $userid]); $row = $chk->fetch(PDO::FETCH_ASSOC); if (!$row) { throw new RuntimeException('Ordine non valido per questo utente.'); } $exp = $row['expireon'] ?? null; if ($exp !== null && $exp < date('Y-m-d')) { throw new RuntimeException('Il pacchetto selezionato è scaduto.'); } } else { throw new RuntimeException('Nessun pacchetto selezionato.'); } $isGift = 'N'; } // ------------------------------------------------------------------ // 2b) Anti-duplicato // ------------------------------------------------------------------ $dup = $db->prepare( "SELECT status FROM bookingclass WHERE iduser = :uid AND idserviceschedule = :idschedule AND status != 'cancelled' LIMIT 1" ); $dup->execute([':uid' => $userid, ':idschedule' => $idserviceschedule]); $dupStatus = $dup->fetchColumn(); if ($dupStatus !== false) { $db->rollBack(); http_response_code(409); $msg = ($dupStatus === 'pending') ? 'Questo utente ha una prenotazione in attesa in questa classe: confermala o rimuovila dalla sezione "In attesa".' : 'Questo utente è già prenotato in questa classe.'; echo json_encode(['success' => false, 'message' => $msg]); exit; } // ------------------------------------------------------------------ // 3) Inserimento prenotazione // ------------------------------------------------------------------ $insBooking = $db->prepare( "INSERT INTO bookingclass (iduser, idserviceschedule, status, idorder, idservice, bookingstart, is_gift) VALUES (:iduser, :idschedule, :status, :idorder, :idservice, :bookingstart, :isgift)" ); $insBooking->execute([ ':iduser' => $userid, ':idschedule' => $idserviceschedule, ':status' => $status, ':idorder' => $idorder, ':idservice' => $idservice, ':bookingstart' => $bookingstart !== '' ? $bookingstart : null, ':isgift' => $isGift, ]); $db->commit(); echo json_encode([ 'success' => true, 'user_id' => $userid, 'is_gift' => $isGift, 'idorder' => $idorder, ], JSON_UNESCAPED_UNICODE); } catch (Throwable $ex) { if ($db->inTransaction()) { $db->rollBack(); } error_log('api_teacher_add_booking error: ' . $ex->getMessage()); http_response_code(500); echo json_encode(['success' => false, 'message' => 'Errore inserimento: ' . $ex->getMessage()]); }