Files
comelifacciamo/public/book_save.php
T

146 lines
5.6 KiB
PHP

<?php
// book_save.php — Conferma prenotazione: crea/trova il customer e inserisce l'appointment (pending)
// Riceve POST da book.php. Richiede utente loggato.
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once(__DIR__ . '/userarea/class/db-functions.php');
$pdo = DBHandlerSelect::getInstance()->getConnection();
// Helper flash (se non già definito altrove nel progetto)
if (!function_exists('setFlash')) {
function setFlash($type, $text)
{
$_SESSION['flash'] = ['type' => $type, 'text' => $text];
}
}
// --- 1. Deve essere loggato ---
if (empty($_SESSION['iduserlogin'])) {
// Torna a book.php mantenendo la selezione, che poi rimanderà al login
$qs = http_build_query([
'shop' => (int)($_POST['shop_id'] ?? 0),
'service' => (int)($_POST['service_id'] ?? 0),
'staff' => (int)($_POST['staff_id'] ?? 0),
'date' => $_POST['date'] ?? '',
'time' => $_POST['time'] ?? '',
'need_login' => 1,
]);
header('Location: book.php?' . $qs);
exit;
}
$user_id = (int)$_SESSION['iduserlogin'];
$shop_id = (int)($_POST['shop_id'] ?? 0);
$service_id = (int)($_POST['service_id'] ?? 0);
$staff_id = (int)($_POST['staff_id'] ?? 0);
$date = trim($_POST['date'] ?? '');
$time = trim($_POST['time'] ?? '');
$notes = trim($_POST['notes'] ?? '');
// --- 2. Validazione input ---
if ($shop_id <= 0 || $service_id <= 0 || $staff_id <= 0 || $date === '' || $time === '') {
setFlash('danger', 'Dati di prenotazione incompleti. Riprova.');
header('Location: book.php?shop=' . $shop_id . '&service=' . $service_id);
exit;
}
$startDT = DateTime::createFromFormat('Y-m-d H:i', $date . ' ' . $time);
if (!$startDT) {
setFlash('danger', 'Data o ora non valida.');
header('Location: book.php?shop=' . $shop_id . '&service=' . $service_id);
exit;
}
try {
// --- 3. Servizio → durata per calcolare end_at ---
$svc = $pdo->prepare("SELECT duration_minutes FROM services WHERE id = ? AND shop_id = ? AND is_active = 1");
$svc->execute([$service_id, $shop_id]);
$service = $svc->fetch(PDO::FETCH_ASSOC);
if (!$service) {
setFlash('danger', 'Servizio non disponibile.');
header('Location: search.php');
exit;
}
$duration = (int)$service['duration_minutes'] ?: 30;
$endDT = (clone $startDT)->modify("+{$duration} minutes");
$startStr = $startDT->format('Y-m-d H:i:s');
$endStr = $endDT->format('Y-m-d H:i:s');
// --- 4. Ricontrollo lato server che lo slot sia ancora libero ---
// (fondamentale: tra quando l'utente ha visto lo slot e ora, qualcuno
// potrebbe averlo preso. Non ci fidiamo solo del JS.)
$clash = $pdo->prepare("
SELECT id FROM appointments
WHERE staff_id = ?
AND status IN ('pending','confirmed','completed')
AND start_at < ? AND end_at > ?
LIMIT 1
");
$clash->execute([$staff_id, $endStr, $startStr]);
if ($clash->fetch()) {
setFlash('warning', 'Spiacenti, questo orario è appena stato prenotato. Scegline un altro.');
header('Location: book.php?shop=' . $shop_id . '&service=' . $service_id . '&staff=' . $staff_id . '&date=' . urlencode($date));
exit;
}
// --- 5. Trova o crea il customer di QUESTO salone per l'utente loggato ---
// customers è per-salone (multi-tenant): stesso utente = record diverso per ogni shop.
$cust = $pdo->prepare("SELECT id FROM customers WHERE shop_id = ? AND user_id = ? LIMIT 1");
$cust->execute([$shop_id, $user_id]);
$customerRow = $cust->fetch(PDO::FETCH_ASSOC);
if ($customerRow) {
$customer_id = (int)$customerRow['id'];
} else {
// Recupero i dati anagrafici dall'utente loggato per popolare il customer.
// Nomi colonne reali di auth_users: first_name, last_name, phone, email.
$u = $pdo->prepare("SELECT first_name, last_name, email, phone FROM auth_users WHERE id = ?");
$u->execute([$user_id]);
$urow = $u->fetch(PDO::FETCH_ASSOC) ?: [];
// customers.phone è NOT NULL: se l'utente non ha telefono usiamo stringa vuota,
// così l'INSERT non fallisce. Lo aggiornerà poi lui/il salone.
$ins = $pdo->prepare("
INSERT INTO customers (shop_id, user_id, first_name, last_name, phone, email)
VALUES (?, ?, ?, ?, ?, ?)
");
$ins->execute([
$shop_id,
$user_id,
($urow['first_name'] ?? '') !== '' ? $urow['first_name'] : 'Cliente',
$urow['last_name'] ?? '',
$urow['phone'] ?? '', // NOT NULL → mai null
$urow['email'] ?? null, // email ammette NULL, ok
]);
$customer_id = (int)$pdo->lastInsertId();
}
// --- 6. Inserimento appuntamento (stato pending: il salone deve confermare) ---
$insAppt = $pdo->prepare("
INSERT INTO appointments (shop_id, customer_id, staff_id, service_id, start_at, end_at, status, notes)
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?)
");
$insAppt->execute([
$shop_id,
$customer_id,
$staff_id,
$service_id,
$startStr,
$endStr,
($notes !== '' ? $notes : null)
]);
setFlash('success', 'Prenotazione inviata! Il salone la confermerà a breve. La trovi in "I miei appuntamenti".');
header('Location: userarea/my_appointments.php');
exit;
} catch (Throwable $e) {
error_log('book_save: ' . $e->getMessage());
setFlash('danger', 'Si è verificato un errore durante la prenotazione. Riprova.');
header('Location: book.php?shop=' . $shop_id . '&service=' . $service_id);
exit;
}