strtotime($to)) { echo json_encode(['error' => 'Bitte wählen Sie einen gültigen Zeitraum.'], JSON_UNESCAPED_UNICODE); exit; } $sql = "SELECT e.title, DATE(e.starts_at) AS event_day, r.name FROM sufw_booking_registrations r JOIN sufw_booking_events e ON e.id = r.event_id WHERE r.status = 'confirmed' AND e.starts_at BETWEEN :fromDate AND :toDate"; $parameters = ['fromDate' => $from.' 00:00:00', 'toDate' => $to.' 23:59:59']; if ($exportProject !== 'all') { $sql .= ' AND e.project = :exportProject'; $parameters['exportProject'] = $exportProject; } $statement = $database->prepare($sql.' ORDER BY e.starts_at, r.name'); $statement->execute($parameters); echo json_encode(['registrations' => $statement->fetchAll()], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!hash_equals($csrf, (string) ($_POST['csrf'] ?? ''))) { http_response_code(403); exit('Ungültige Sitzung.'); } $action = (string) ($_POST['action'] ?? ''); if ($action === 'save_event') { $id = (string) ($_POST['id'] ?? '') ?: bookingUuid(); $title = trim((string) ($_POST['title'] ?? '')); $startsAt = str_replace('T', ' ', (string) ($_POST['starts_at'] ?? '')); $endsAt = str_replace('T', ' ', (string) ($_POST['ends_at'] ?? '')); $capacity = (int) ($_POST['capacity'] ?? 0); $format = (string) ($_POST['format'] ?? 'vor_ort'); $contactName = trim((string) ($_POST['contact_name'] ?? '')); $contactEmail = trim((string) ($_POST['contact_email'] ?? '')); $contactPhone = trim((string) ($_POST['contact_phone'] ?? '')); if ($title === '' || $capacity < 1 || $capacity > 100 || !in_array($format, ['vor_ort', 'telefonisch'], true) || $contactName === '' || $contactPhone === '' || !filter_var($contactEmail, FILTER_VALIDATE_EMAIL) || !isQuarterHourDateTime($startsAt) || !isQuarterHourDateTime($endsAt) || strtotime($endsAt) <= strtotime($startsAt)) adminBack($project, 'events', 'Bitte prüfen Sie die Termindaten. Uhrzeiten sind nur im 15-Minuten-Raster zulässig.'); $save = $database->prepare("INSERT INTO sufw_booking_events (id, project, title, starts_at, ends_at, capacity, format, introduction_required, contact_name, contact_email, contact_phone) VALUES (:id, :project, :title, :startsAt, :endsAt, :capacity, :format, :introductionRequired, :contactName, :contactEmail, :contactPhone) ON DUPLICATE KEY UPDATE title = VALUES(title), starts_at = VALUES(starts_at), ends_at = VALUES(ends_at), capacity = VALUES(capacity), format = VALUES(format), introduction_required = VALUES(introduction_required), contact_name = VALUES(contact_name), contact_email = VALUES(contact_email), contact_phone = VALUES(contact_phone)"); $save->execute(['id' => $id, 'project' => $project, 'title' => $title, 'startsAt' => $startsAt, 'endsAt' => $endsAt, 'capacity' => $capacity, 'format' => $format, 'introductionRequired' => isset($_POST['introduction_required']) ? 1 : 0, 'contactName' => $contactName, 'contactEmail' => $contactEmail, 'contactPhone' => $contactPhone]); adminBack($project, 'events', 'Termin gespeichert.'); } if ($action === 'toggle_event') { $database->prepare('UPDATE sufw_booking_events SET is_active = 1 - is_active WHERE id = :id AND project = :project')->execute(['id' => $_POST['id'] ?? '', 'project' => $project]); adminBack($project, 'events', 'Terminstatus geändert.'); } if ($action === 'remove_registration') { $database->prepare("UPDATE sufw_booking_registrations SET status = 'removed', removed_at = UTC_TIMESTAMP() WHERE id = :id AND status IN ('pending_confirmation', 'confirmed')")->execute(['id' => $_POST['id'] ?? '']); adminBack($project, 'registrations', 'Teilnahme entfernt; die Kapazität ist wieder frei.'); } if ($action === 'run_jobs') { $result = bookingRunJobs($database); adminBack($project, $view, "Jobs ausgeführt: {$result['expired']} abgelaufen, {$result['remindersConsidered']} Erinnerungen geprüft."); } } $titles = $database->prepare('SELECT DISTINCT title FROM sufw_booking_events WHERE project = :project ORDER BY title'); $titles->execute(['project' => $project]); $titles = $titles->fetchAll(PDO::FETCH_COLUMN); $contacts = $database->prepare('SELECT DISTINCT contact_name, contact_email, contact_phone FROM sufw_booking_events WHERE project = :project ORDER BY contact_name, contact_email'); $contacts->execute(['project' => $project]); $contactByName = []; $contactByEmail = []; foreach ($contacts as $contact) { $contactByName[$contact['contact_name']] ??= ['email' => $contact['contact_email'], 'phone' => $contact['contact_phone']]; $contactByEmail[$contact['contact_email']] ??= ['name' => $contact['contact_name'], 'phone' => $contact['contact_phone']]; } $settings = $database->prepare('SELECT feed_token FROM sufw_booking_project_settings WHERE project = :project'); $settings->execute(['project' => $project]); $feedToken = (string) $settings->fetchColumn(); $notice = (string) ($_GET['notice'] ?? ''); $events = []; $edit = null; if ($view === 'events') { $statement = $database->prepare("SELECT e.*, COUNT(CASE WHEN r.status = 'confirmed' THEN 1 END) AS confirmed_count FROM sufw_booking_events e LEFT JOIN sufw_booking_registrations r ON r.event_id = e.id WHERE e.project = :project GROUP BY e.id ORDER BY e.starts_at"); $statement->execute(['project' => $project]); $events = $statement->fetchAll(); foreach ($events as $event) if ($event['id'] === ($_GET['edit'] ?? '')) $edit = $event; } $registrations = []; if ($view === 'registrations') { $statement = $database->prepare("SELECT r.*, e.title, e.starts_at FROM sufw_booking_registrations r JOIN sufw_booking_events e ON e.id = r.event_id WHERE e.project = :project ORDER BY r.created_at DESC LIMIT 200"); $statement->execute(['project' => $project]); $registrations = $statement->fetchAll(); } $outbox = []; if ($view === 'events') { $statement = $database->prepare("SELECT o.*, r.name FROM sufw_booking_outbox o JOIN sufw_booking_registrations r ON r.id = o.registration_id JOIN sufw_booking_events e ON e.id = r.event_id WHERE e.project = :project ORDER BY o.created_at DESC LIMIT 20"); $statement->execute(['project' => $project]); $outbox = $statement->fetchAll(); } $defaultFrom = date('Y-m-01'); $defaultTo = date('Y-m-t'); ?> Terminbuchung · Testverwaltung

Terminbuchung · Testverwaltung

Abbrechen

Termine

TerminZeitKapazitätStatus


bis
/ bestätigtBearbeiten

Lokaler Mailausgang

·

Teilnahmen ·

PersonTerminStatus



Bestätigte Teilnahmen anzeigen

Der Zeitraum umfasst jeweils vollständige Kalendertage (00:00 bis 23:59 Uhr) und aktualisiert die Liste unmittelbar.

Lade Teilnahmen …