query('SELECT COUNT(*) FROM products')->fetchColumn() === 0) { $ins = $pdo->prepare('INSERT INTO products (code,name,default_minutes,price_cents,active) VALUES (?,?,?,?,1)'); foreach ($CFG['products'] as $p) { $ins->execute([$p['code'],$p['name'],$p['minutes'],$p['price_cents']]); } } $step = $_GET['step'] ?? 'product'; // Hent aktive produkter $products = $pdo->query('SELECT * FROM products WHERE active=1 ORDER BY id')->fetchAll(); function findProduct(array $prods, int $id): ?array { foreach ($prods as $p) if ((int)$p['id']===$id) return $p; return null; } ?>
Vælg et produkt for at fortsætte:
Ugyldigt produkt.'; exit; } $year = (int)($_GET['y'] ?? (int)date('Y')); $month = (int)($_GET['m'] ?? (int)date('n')); $first = new DateTimeImmutable(sprintf('%04d-%02d-01', $year, $month)); $dow = (int)$first->format('N'); // 1..7 $daysInMonth = (int)$first->format('t'); $prev = $first->modify('-1 month'); $next = $first->modify('+1 month'); ?>= h($product['name']) ?> · = (int)$product['default_minutes'] ?> min · = money_dkk((int)$product['price_cents']) ?>
◀ Forrige = $first->format('F Y') ?> Næste ▶
| Man | Tir | Ons | Tor | Fre | Lør | Søn | '; continue; } $ymd = $first->format('Y-m-') . sprintf('%02d',$d); $isPast = (new DateTimeImmutable($ymd . ' 23:59:59')) < (new DateTimeImmutable('now')); $green = !$isPast && $avail->dateIsGreen($ymd, (int)$product['default_minutes']); if ($green) { echo ' | '.$d.' | '; } else { echo ''.$d.' | '; } $d++; } echo ''; if ($d > $daysInMonth) break; } ?>
|---|
Grøn = ledig (kapacitet), Rød = fuldt optaget eller lukket.
Ugyldig forespørgsel.'; exit; } $slots = $avail->listSlots($date); ?>= h($product['name']) ?> · Dato: = h($date) ?>
Vælg afhentningstidspunkt:
Ugyldig forespørgsel.'; exit; } $pickup_at = $date . ' ' . $time . ':00'; $deadline = $avail->dropoffDeadline($pickup_at); // Kapacitets- og slot-tjek igen (server-side) if (!$avail->dateIsGreen($date, (int)$product['default_minutes'])) { echo 'Denne dato er desværre blevet optaget. Vælg venligst en anden dato.
'; exit; } $slotOk = false; foreach ($avail->listSlots($date) as $s) { if ($s['label']===$time && $s['free']) $slotOk = true; } if (!$slotOk) { echo 'Det valgte klokkeslæt er netop blevet optaget. Vælg et andet.
'; exit; } ?>= h($product['name']) ?> · Afhentning: = h($pickup_at) ?>
Aflever senest: = h($deadline) ?>
Ugyldigt produkt.
'; exit; } $pickup_at = $_POST['pickup_at'] ?? ''; $deadline = $_POST['deadline'] ?? ''; if (!preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/',$pickup_at) || !preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/',$deadline)) { echo 'Ugyldige tider.
'; exit; } // Final kapacitets/slot check $date = substr($pickup_at,0,10); $time = substr($pickup_at,11,5); if (!$avail->dateIsGreen($date, (int)$product['default_minutes'])) { echo 'Datoen blev optaget.
'; exit; } $slotOk = false; foreach ($avail->listSlots($date) as $s) { if ($s['label']===$time && $s['free']) $slotOk = true; } if (!$slotOk) { echo 'Klokkeslættet blev optaget.
'; exit; } // Valider felter $data = [ 'first_name' => trim((string)($_POST['first_name'] ?? '')), 'last_name' => trim((string)($_POST['last_name'] ?? '')), 'address' => trim((string)($_POST['address'] ?? '')), 'house_no' => trim((string)($_POST['house_no'] ?? '')), 'zip' => trim((string)($_POST['zip'] ?? '')), 'city' => trim((string)($_POST['city'] ?? '')), 'phone' => trim((string)($_POST['phone'] ?? '')), 'email' => trim((string)($_POST['email'] ?? '')), 'plate' => trim((string)($_POST['plate'] ?? '')), ]; foreach ($data as $k=>$v) if ($v==='') { echo 'Manglende felt: '.h($k).'
'; exit; } $cancel = bin2hex(random_bytes(16)); $stmt = $pdo->prepare('INSERT INTO bookings (product_id, status, pickup_at, dropoff_deadline, planned_minutes, first_name,last_name,address,house_no,zip,city,phone,email,plate,cancel_token) VALUES (?, "booked", ?, ?, ?, ?,?,?,?,?,?,?,?,?,?)'); $stmt->execute([ $product_id, $pickup_at, $deadline, (int)$product['default_minutes'], $data['first_name'],$data['last_name'],$data['address'],$data['house_no'], $data['zip'],$data['city'],$data['phone'],$data['email'],$data['plate'],$cancel ]); $bookingId = (int)$pdo->lastInsertId(); // Send e-mail $html = 'Tak for din booking.
' . ''.h($product['name']).'
'
. 'Pris: '.money_dkk((int)$product['price_cents']).'
'
. 'Afhentning: '.h($pickup_at).'
'
. 'Aflever senest: '.h($deadline).'
'
. 'Nr.plade: '.h($data['plate']).'
Hvis du har spørgsmål, kontakt os gerne.
'; $mailer->send($data['email'], 'Bekræftelse på værkstedsbooking', $html); // (Valgfrit) log udsendelsen $pdo->prepare('INSERT INTO notifications_log (booking_id, channel, payload) VALUES (?,?,?)') ->execute([$bookingId,'email',$html]); // Bekræftelse echo 'Du har valgt: '.h($product['name']).' – '.money_dkk((int)$product['price_cents']).'
'; echo 'Afhentning: '.h($pickup_at).'
Aflever senest: '.h($deadline).'
En bekræftelse er sendt til '.h($data['email']).'.
'; echo '';Ugyldigt step.