Files
yogibook_aury_new/public/api/api_teacher_add_booking.php
T
2026-08-24 16:30:35 +02:00

256 lines
9.6 KiB
PHP

<?php
/**
* api_teacher_add_booking.php
* --------------------------------------------------------------------------
* Inserisce un partecipante in una classe. Solo staff (Admin=1 / teacher=3).
* Replica inserisci_record.php della webapp (risposta JSON invece di redirect).
*
* Posizione: public/api/api_teacher_add_booking.php
* Metodo: POST
* Auth: Bearer token (Sanctum) via _bootstrap.php
*
* Body:
* idserviceschedule=<int> classe destinazione
* idservice=<int> servizio della classe
* bookingstart=<datetime> data/ora lezione (dateschedule)
* bkmode=<scala|omaggio|nuovo>
* user_id=<int> utente esistente (0 se nuovo)
* name, surname, email per creare l'utente se user_id=0
* idorder=<int> solo per 'scala'
* new_expiry=<YYYY-MM-DD> 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()]);
}