getConnection(); // Ruolo Owner (da headscript: ROLE_OWNER = 2) const ROLE_OWNER = 2; function setFlash(string $type, string $text): void { $_SESSION['flash'] = ['type' => $type, 'text' => $text]; } function backToCheckout(array $post, string $msg): void { // Ripopola il form e torna al checkout con l'errore $_SESSION['checkout_old'] = $post; setFlash('danger', $msg); $plan = (int)($post['plan_id'] ?? 0); $cycle = ($post['cycle'] ?? 'monthly') === 'yearly' ? 'yearly' : 'monthly'; header("Location: checkout.php?plan={$plan}&cycle={$cycle}"); exit; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { header('Location: pricing.php'); exit; } $post = $_POST; // --- Raccolta dati --- $plan_id = (int)($post['plan_id'] ?? 0); $cycle = ($post['cycle'] ?? 'monthly') === 'yearly' ? 'yearly' : 'monthly'; $first_name = trim($post['first_name'] ?? ''); $last_name = trim($post['last_name'] ?? ''); $email = trim($post['email'] ?? ''); $password = (string)($post['password'] ?? ''); $password2 = (string)($post['password_confirm'] ?? ''); $shop_name = trim($post['shop_name'] ?? ''); $business_name = trim($post['business_name'] ?? ''); $vat_number = trim($post['vat_number'] ?? ''); $tax_code = trim($post['tax_code'] ?? ''); $address = trim($post['address'] ?? ''); $city = trim($post['city'] ?? ''); $province = trim($post['province'] ?? ''); $zip_code = trim($post['zip_code'] ?? ''); $pec = trim($post['pec'] ?? ''); $sdi_code = trim($post['sdi_code'] ?? ''); // --- Validazioni --- if ($plan_id <= 0) { header('Location: pricing.php'); exit; } if ($first_name === '' || $last_name === '' || $email === '' || $password === '') { backToCheckout($post, 'Compila tutti i campi obbligatori dell\'account.'); } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { backToCheckout($post, 'Inserisci un indirizzo email valido.'); } if (strlen($password) < 8) { backToCheckout($post, 'La password deve avere almeno 8 caratteri.'); } if ($password !== $password2) { backToCheckout($post, 'Le due password non coincidono.'); } if ($shop_name === '') { backToCheckout($post, 'Inserisci il nome del salone.'); } if ($business_name === '' || $vat_number === '' || $address === '' || $city === '' || $zip_code === '') { backToCheckout($post, 'Compila tutti i dati di fatturazione obbligatori.'); } // Normativa IT: almeno uno tra PEC e SDI if ($pec === '' && $sdi_code === '') { backToCheckout($post, 'Per la fattura elettronica inserisci almeno la PEC o il Codice SDI.'); } if ($pec !== '' && !filter_var($pec, FILTER_VALIDATE_EMAIL)) { backToCheckout($post, 'La PEC non è un indirizzo valido.'); } try { // Email già registrata? $chk = $pdo->prepare("SELECT id FROM auth_users WHERE email = ?"); $chk->execute([$email]); if ($chk->fetch()) { backToCheckout($post, 'Esiste già un account con questa email. Prova ad accedere.'); } // Piano valido + prezzo $ps = $pdo->prepare("SELECT id, price FROM subscription_plans WHERE id = ? AND is_active = 1"); $ps->execute([$plan_id]); $plan = $ps->fetch(PDO::FETCH_ASSOC); if (!$plan) { backToCheckout($post, 'Il piano selezionato non è più disponibile.'); } // Slug salone univoco (generazione al volo, finché non c'è il sistema slug dedicato) $baseSlug = strtolower(trim(preg_replace('/[^a-z0-9]+/i', '-', $shop_name), '-')); if ($baseSlug === '') $baseSlug = 'salone'; $slug = $baseSlug; $i = 1; $slugChk = $pdo->prepare("SELECT id FROM shops WHERE slug = ?"); while (true) { $slugChk->execute([$slug]); if (!$slugChk->fetch()) break; $slug = $baseSlug . '-' . (++$i); } // Durata abbonamento $expires = $cycle === 'yearly' ? date('Y-m-d', strtotime('+1 year')) : date('Y-m-d', strtotime('+1 month')); // ---- TRANSAZIONE: tutto o niente ---- $pdo->beginTransaction(); // 1. Utente Owner $hash = password_hash($password, PASSWORD_BCRYPT); $insU = $pdo->prepare(" INSERT INTO auth_users (email, password, role_id, status, first_name, last_name, created_at) VALUES (?, ?, ?, 'Active', ?, ?, NOW()) "); $insU->execute([$email, $hash, ROLE_OWNER, $first_name, $last_name]); $user_id = (int)$pdo->lastInsertId(); // 2. Salone (indirizzo iniziale = indirizzo fiscale; modificabile poi dal profilo) $insS = $pdo->prepare(" INSERT INTO shops (owner_id, name, slug, address, city, province, zip_code, email, active, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, NOW()) "); $insS->execute([$user_id, $shop_name, $slug, $address, $city, ($province ?: null), $zip_code, $email]); $shop_id = (int)$pdo->lastInsertId(); // 3. Profilo fiscale $insB = $pdo->prepare(" INSERT INTO billing_profiles (user_id, shop_id, business_name, vat_number, tax_code, address, zip_code, city, province, pec, sdi_code) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "); $insB->execute([ $user_id, $shop_id, $business_name, $vat_number, ($tax_code ?: null), $address, $zip_code, $city, ($province ?: null), ($pec ?: null), ($sdi_code ?: null) ]); // 4. Abbonamento attivo (pagamento SIMULATO riuscito) $insSub = $pdo->prepare(" INSERT INTO shop_subscriptions (shop_id, plan_id, status, started_at, expires_at) VALUES (?, ?, 'active', CURDATE(), ?) "); $insSub->execute([$shop_id, $plan_id, $expires]); $pdo->commit(); // --- Login: impostiamo la sessione userarea come fa il resto del sito --- // NB: headscript usa Auth::user() (Laravel). Qui creiamo comunque le chiavi // di sessione PHP native usate nelle pagine userarea, così l'utente è "dentro". $_SESSION['iduserlogin'] = $user_id; $_SESSION['nameuser'] = $first_name; $_SESSION['surnameuser'] = $last_name; $_SESSION['emailuser'] = $email; setFlash('success', 'Benvenuto! Il tuo salone è attivo. Completa il profilo e inizia a ricevere prenotazioni.'); // Va in area titolare (l'agenda). Se la sessione Laravel non è attiva, // la pagina rimanderà al login: in tal caso l'utente accede con le sue credenziali. header('Location: userarea/appointments.php'); exit; } catch (Throwable $e) { if ($pdo->inTransaction()) $pdo->rollBack(); error_log('checkout_process: ' . $e->getMessage()); backToCheckout($post, 'Si è verificato un errore durante l\'attivazione. Riprova.'); }