diff --git a/admin/impfworkflow.php b/admin/impfworkflow.php index 6e77124..ab418ed 100644 --- a/admin/impfworkflow.php +++ b/admin/impfworkflow.php @@ -4,6 +4,7 @@ session_start(); require_once __DIR__ . "/../inc/config.inc.php"; require_once __DIR__ . "/../inc/functions.inc.php"; require_once __DIR__ . "/../inc/functions.impfen.inc.php"; +require_once __DIR__ . "/../inc/impfworkflow_notifications.inc.php"; $user = check_admin_user(); include __DIR__ . "/templates/header.inc.php"; @@ -78,11 +79,60 @@ function ensureWorkflowTables(PDO $pdo): void impfWorkflowEnsureTables($pdo); } +function workflowDeleteWaitlistEntry(PDO $pdo, int $warteid): void +{ + if ($warteid <= 0) { + return; + } + + $stDeleteMap = $pdo->prepare("DELETE FROM warteliste_zeitraum WHERE warteid = :wid"); + $stDeleteMap->execute(['wid' => $warteid]); + + $stDelete = $pdo->prepare("DELETE FROM warteliste WHERE warteid = :wid"); + $stDelete->execute(['wid' => $warteid]); +} + +function workflowCountWaitersForPlan(PDO $pdo, int $impfstoffId, int $planId): int +{ + return impfWorkflowNotificationCountWaitersForPlan($pdo, $impfstoffId, $planId); +} + +function workflowLoadWaitRowsForPlan(PDO $pdo, int $impfstoffId, int $planId): array +{ + $stW = $pdo->prepare("SELECT w.warteid, w.userid, w.hash, w.impfart, w.Impfaufklaerung, w.WeitereFragen, w.letzteimpfung, w.date_created + FROM warteliste w + WHERE w.checked = 1 + AND (w.impfstoff = :iid OR w.impfstoff = 0) + AND ( + EXISTS ( + SELECT 1 + FROM warteliste_zeitraum wz + WHERE wz.warteid = w.warteid + AND wz.zeitraum_id = :zid + ) + OR ( + NOT EXISTS ( + SELECT 1 + FROM warteliste_zeitraum wz_none + WHERE wz_none.warteid = w.warteid + ) + AND (w.zeitraum_id = :zid OR w.zeitraum_id IS NULL) + ) + ) + ORDER BY w.date_created ASC, w.warteid ASC"); + $stW->execute([ + 'iid' => $impfstoffId, + 'zid' => $planId, + ]); + + return $stW->fetchAll(PDO::FETCH_ASSOC); +} + function workflowAddWartelisteEntry( PDO $pdo, int $personId, int $impfstoffId, - int $planId, + $planIds, int $impfart, ?string $letzteImpfung, int $checked @@ -92,7 +142,7 @@ function workflowAddWartelisteEntry( } $impfstoffId = max(0, $impfstoffId); - $planId = max(0, $planId); + $planIds = impfNormalizeZeitraumIds($planIds); $impfart = ($impfart >= 1 && $impfart <= 4) ? $impfart : 1; if ($impfart > 1 && !$letzteImpfung) { $impfart = 1; @@ -112,38 +162,39 @@ function workflowAddWartelisteEntry( $impfstoffName = 'ohne Vorgabe'; $zeitraum = 'Flexibel'; - if ($planId > 0) { - $plan = impfLoadZeitraumById($pdo, $planId, true); - if (!$plan) { - return [false, "Das ausgewaehlte Zeitfenster ist nicht mehr verfuegbar."]; - } + if (!empty($planIds)) { + $zeitraumLabels = []; + foreach ($planIds as $planId) { + $plan = impfLoadZeitraumById($pdo, $planId, true); + if (!$plan) { + return [false, "Mindestens ein ausgewaehltes Zeitfenster ist nicht mehr verfuegbar."]; + } - $zugeordneteImpfstoffe = $plan['impfstoff_id_list'] ?? []; - if ($impfstoffId > 0 && !in_array($impfstoffId, $zugeordneteImpfstoffe, true)) { - return [false, "Impfstoff und Zeitfenster passen nicht zusammen."]; + $zugeordneteImpfstoffe = $plan['impfstoff_id_list'] ?? []; + if ($impfstoffId > 0 && !in_array($impfstoffId, $zugeordneteImpfstoffe, true)) { + return [false, "Impfstoff und Zeitfenster passen nicht zusammen."]; + } + + if ($impfstoffId <= 0) { + if (count($zugeordneteImpfstoffe) !== 1) { + return [false, "Bitte einen Impfstoff auswaehlen, der allen Zeitfenstern eindeutig zugeordnet ist."]; + } + $currentImpfstoffId = (int)$zugeordneteImpfstoffe[0]; + if ($impfstoffValue > 0 && $impfstoffValue !== $currentImpfstoffId) { + return [false, "Die ausgewaehlten Zeitfenster gehoeren zu unterschiedlichen Impfstoffen."]; + } + $impfstoffValue = $currentImpfstoffId; + } + + $zeitraumLabels[] = workflowPlanLabel($plan); } if ($impfstoffId <= 0) { - if (count($zugeordneteImpfstoffe) !== 1) { - return [false, "Bitte einen Impfstoff auswaehlen, der dem Zeitfenster zugeordnet ist."]; - } - $impfstoffId = (int)$zugeordneteImpfstoffe[0]; + $impfstoffId = $impfstoffValue; } + } - $stImpfstoff = $pdo->prepare("SELECT impfid, impfname - FROM impfstoff - WHERE impfid = :iid - LIMIT 1"); - $stImpfstoff->execute(['iid' => $impfstoffId]); - $impfstoff = $stImpfstoff->fetch(PDO::FETCH_ASSOC); - if (!$impfstoff) { - return [false, "Der ausgewaehlte Impfstoff wurde nicht gefunden."]; - } - - $impfstoffValue = $impfstoffId; - $impfstoffName = (string)$impfstoff['impfname']; - $zeitraum = workflowPlanLabel($plan); - } elseif ($impfstoffId > 0) { + if ($impfstoffId > 0) { $stImpfstoff = $pdo->prepare("SELECT impfid, impfname FROM impfstoff WHERE impfid = :iid @@ -158,6 +209,10 @@ function workflowAddWartelisteEntry( $impfstoffValue = 0; } + if (!empty($planIds)) { + $zeitraum = implode(' | ', $zeitraumLabels); + } + $stDup = $pdo->prepare("SELECT warteid FROM warteliste WHERE userid = :uid @@ -172,7 +227,7 @@ function workflowAddWartelisteEntry( $hash = md5('admin-warte-' . $personId . '-' . microtime(true) . '-' . random_int(1000, 9999)); $checkedValue = ($checked === 0) ? 0 : 1; $letzteValue = ($impfart === 1) ? null : ($letzteImpfung ?: null); - $zeitraumIdValue = ($planId > 0) ? $planId : null; + $zeitraumIdValue = !empty($planIds) ? (int)$planIds[0] : null; $stInsert = $pdo->prepare("INSERT INTO warteliste (userid, checked, hash, impfenangebot, impfstoff, Patientenart, Impfaufklaerung, WeitereFragen, impfart, impfenmit, letzteimpfung, impfenzeitraum, zeitraum_id, date_created) @@ -190,6 +245,11 @@ function workflowAddWartelisteEntry( 'zeitraum_id' => $zeitraumIdValue, ]); + $warteid = (int)$pdo->lastInsertId(); + if (!empty($planIds)) { + impfSetWartelistenZeitraeume($pdo, $warteid, $planIds); + } + $personName = trim((string)$person['vorname'] . ' ' . (string)$person['nachname']); return [true, "Wartelistenplatz fuer {$personName} ({$impfstoffName}) gespeichert."]; } @@ -235,16 +295,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } else { $dosen = (int)$rule['dosen_pro_flasche']; - $stCount = $pdo->prepare("SELECT COUNT(DISTINCT userid) - FROM warteliste - WHERE checked = 1 - AND (impfstoff = :iid OR impfstoff = 0) - AND (zeitraum_id = :zid OR zeitraum_id IS NULL)"); - $stCount->execute([ - 'iid' => $impfstoffId, - 'zid' => $planId, - ]); - $wartende = (int)$stCount->fetchColumn(); + $wartende = workflowCountWaitersForPlan($pdo, $impfstoffId, $planId); if ($wartende < $dosen) { $error = "Nicht genug bestätigte Warteteilnehmer: {$wartende} von {$dosen}."; @@ -286,16 +337,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { ]); $timeid = (int)$pdo->lastInsertId(); - $stW = $pdo->prepare("SELECT warteid, userid, hash, impfart, Impfaufklaerung, WeitereFragen, letzteimpfung - FROM warteliste - WHERE checked = 1 - AND (impfstoff = :iid OR impfstoff = 0) - AND (zeitraum_id = :zid OR zeitraum_id IS NULL) - ORDER BY date_created ASC, warteid ASC"); - $stW->bindValue(':iid', $impfstoffId, PDO::PARAM_INT); - $stW->bindValue(':zid', $planId, PDO::PARAM_INT); - $stW->execute(); - $warteRowsRaw = $stW->fetchAll(PDO::FETCH_ASSOC); + $warteRowsRaw = workflowLoadWaitRowsForPlan($pdo, $impfstoffId, $planId); $warteRows = []; $seenUserIds = []; foreach ($warteRowsRaw as $warteRow) { @@ -333,6 +375,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { ]); $terminIds[] = (int)$pdo->lastInsertId(); $stDelW->execute(['wid' => (int)$w['warteid']]); + $pdo->prepare("DELETE FROM warteliste_zeitraum WHERE warteid = :wid") + ->execute(['wid' => (int)$w['warteid']]); } $stReduce = $pdo->prepare("UPDATE timeslots SET impfdosen = GREATEST(impfdosen - :cnt, 0) WHERE timeid = :timeid"); @@ -363,13 +407,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } elseif ($aktion === 'add_waitlist_existing') { $personId = (int)($_POST['wl_person_id'] ?? 0); $impfstoffId = (int)($_POST['wl_impfstoff_id'] ?? 0); - $planId = (int)($_POST['wl_plan_id'] ?? 0); + $planIds = impfNormalizeZeitraumIds($_POST['wl_plan_ids'] ?? ($_POST['wl_plan_id'] ?? [])); [$ok, $msg] = workflowAddWartelisteEntry( $pdo, $personId, $impfstoffId, - $planId, + $planIds, 1, null, 1 @@ -391,7 +435,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $patientenart = ((int)($_POST['new_patientenart'] ?? 0) === 1) ? 1 : 0; $impfstoffId = (int)($_POST['new_impfstoff_id'] ?? 0); - $planId = (int)($_POST['new_plan_id'] ?? 0); + $planIds = impfNormalizeZeitraumIds($_POST['new_plan_ids'] ?? ($_POST['new_plan_id'] ?? [])); if ($vorname === '' || $nachname === '' || $geburtstag === '') { $error = "Für neue Patienten sind Vorname, Nachname und Geburtstag erforderlich."; @@ -414,7 +458,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $pdo, $personId, $impfstoffId, - $planId, + $planIds, 1, null, 1 @@ -529,9 +573,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($warteid <= 0) { $error = "Ungültiger Wartelisten-Eintrag."; } else { - $stDelete = $pdo->prepare("DELETE FROM warteliste WHERE warteid = :wid"); + $stDelete = $pdo->prepare("SELECT warteid FROM warteliste WHERE warteid = :wid"); $stDelete->execute(['wid' => $warteid]); - if ($stDelete->rowCount() > 0) { + $exists = (bool)$stDelete->fetch(PDO::FETCH_ASSOC); + workflowDeleteWaitlistEntry($pdo, $warteid); + if ($exists) { $message = "Wartelisten-Eintrag wurde gelöscht."; } else { $error = "Wartelisten-Eintrag nicht gefunden."; @@ -548,6 +594,7 @@ $personResults = []; $waitRows = []; $upcomingRows = []; $eventOverview = []; +$planWaitCounts = []; try { $stRules = $pdo->prepare("SELECT r.impfstoff_id, r.dosen_pro_flasche, i.impfname, @@ -571,11 +618,26 @@ try { foreach ($rules as $r) { $iid = (int)$r['impfstoff_id']; $dosen = (int)$r['dosen_pro_flasche']; - if ($dosen > 0 && isset($planExistsForImpfstoff[$iid])) { - $configuredImpfstoffe[] = $r; - if ((int)$r['wartende'] >= $dosen) { - $eligible[] = $r; + if ($dosen <= 0 || !isset($planExistsForImpfstoff[$iid])) { + continue; + } + + $configuredImpfstoffe[] = $r; + $hasEligiblePlan = false; + foreach ($plans as $plan) { + if (!in_array($iid, $plan['impfstoff_id_list'] ?? [], true)) { + continue; } + + $planId = (int)$plan['zeitraum_id']; + $planWaitCounts[$iid][$planId] = workflowCountWaitersForPlan($pdo, $iid, $planId); + if ($planWaitCounts[$iid][$planId] >= $dosen) { + $hasEligiblePlan = true; + } + } + + if ($hasEligiblePlan) { + $eligible[] = $r; } } @@ -611,16 +673,19 @@ try { $waitRows = $stWait->fetchAll(PDO::FETCH_ASSOC); foreach ($waitRows as &$waitRow) { - $zeitraumId = (int)($waitRow['zeitraum_id'] ?? 0); - if ($zeitraumId > 0) { - $zeitraum = impfLoadZeitraumById($pdo, $zeitraumId, true); - if ($zeitraum) { - $waitRow['impfenzeitraum'] = $zeitraum['label']; - } + $waitRow['zeitraum_labels'] = impfGetWartelistenZeitraeumeLabels($pdo, (int)$waitRow['warteid'], false); + if (!empty($waitRow['zeitraum_labels'])) { + $waitRow['impfenzeitraum'] = implode(' | ', $waitRow['zeitraum_labels']); } } unset($waitRow); + $notificationEvents = impfWorkflowNotificationProcess($pdo); + if (!empty($notificationEvents)) { + $notificationText = count($notificationEvents) . " Impfworkflow-Benachrichtigung(en) wurden versendet."; + $message = ($message === '') ? $notificationText : ($message . ' ' . $notificationText); + } + $stUpcoming = $pdo->prepare("SELECT ts.timeid, ts.date, ts.start, ts.ende, ts.impfdosen, i.impfname, o.anzeigename, o.adresse, it.terminid, it.checked, it.behandelt, it.impfart, @@ -728,7 +793,13 @@ try { - + + + ', array_map('esc', $w['zeitraum_labels'])); ?> + + + + @@ -806,12 +877,12 @@ try { - @@ -897,12 +968,12 @@ try {
- @@ -1061,15 +1132,18 @@ try { function filterPlans() { var val = impfstoff.value; var needsFilter = (val !== "" && val !== "0"); - var selectedValid = false; + var selectedValues = []; + for (var s = 0; s < plan.options.length; s++) { + if (plan.options[s].selected && plan.options[s].value !== '') { + selectedValues.push(plan.options[s].value); + } + } + var selectedValid = 0; for (var i = 0; i < plan.options.length; i++) { var opt = plan.options[i]; var optionImpfstoffe = opt.getAttribute('data-impfstoffe'); if (!optionImpfstoffe) { opt.hidden = false; - if (opt.value === plan.value) { - selectedValid = true; - } continue; } var ids = optionImpfstoffe.split(','); @@ -1083,11 +1157,13 @@ try { } } opt.hidden = !visible; - if (visible && opt.value === plan.value) { - selectedValid = true; + if (!visible) { + opt.selected = false; + } else if (selectedValues.indexOf(opt.value) !== -1) { + selectedValid++; } } - if (!selectedValid) { + if (selectedValues.length > 0 && selectedValid === 0) { plan.value = ''; } } diff --git a/admin/settings.php b/admin/settings.php index 23e8ddc..9ba8125 100644 --- a/admin/settings.php +++ b/admin/settings.php @@ -1,17 +1,19 @@

Erst anmelden: Login


"; @@ -22,11 +24,12 @@ if(isset($_GET['save'])) { $save = $_GET['save']; if($save == 'personal_data') { + $activeTab = 'data'; $vorname = trim($_POST['vorname']); $nachname = trim($_POST['nachname']); if($vorname == "" || $nachname == "") { - $error_msg = "Bitte Vor- und Nachname ausfüllen."; + $error_msg = "Bitte Vor- und Nachname ausfüllen."; } else { $statement = $pdo->prepare("UPDATE users SET vorname = :vorname, nachname = :nachname, updated_at=NOW() WHERE id = :userid"); $result = $statement->execute(array('vorname' => $vorname, 'nachname'=> $nachname, 'userid' => $user['id'] )); @@ -34,14 +37,15 @@ if(isset($_GET['save'])) { $success_msg = "Daten erfolgreich gespeichert."; } } else if($save == 'email') { + $activeTab = 'email'; $passwort = $_POST['passwort']; $email = trim($_POST['email']); $email2 = trim($_POST['email2']); if($email != $email2) { - $error_msg = "Die eingegebenen E-Mail-Adressen stimmten nicht überein."; + $error_msg = "Die eingegebenen E-Mail-Adressen stimmten nicht überein."; } else if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { - $error_msg = "Bitte eine gültige E-Mail-Adresse eingeben."; + $error_msg = "Bitte eine gültige E-Mail-Adresse eingeben."; } else if(!password_verify($passwort, $user['passwort'])) { $error_msg = "Bitte korrektes Passwort eingeben."; } else { @@ -51,13 +55,31 @@ if(isset($_GET['save'])) { $success_msg = "E-Mail-Adresse erfolgreich gespeichert."; } + } else if($save == 'impfworkflow_notification') { + $activeTab = 'impfworkflow'; + $benachrichtigungEmail = trim((string)($_POST['benachrichtigung_email'] ?? '')); + + if ($benachrichtigungEmail !== '' && !filter_var($benachrichtigungEmail, FILTER_VALIDATE_EMAIL)) { + $error_msg = "Bitte eine gueltige E-Mail-Adresse fuer die Impfworkflow-Benachrichtigung eingeben."; + } else { + try { + impfWorkflowNotificationSetEmail($pdo, $benachrichtigungEmail); + $success_msg = ($benachrichtigungEmail !== '') + ? "Impfworkflow-Benachrichtigungsadresse gespeichert." + : "Impfworkflow-Benachrichtigungsadresse geloescht."; + } catch (Throwable $e) { + $error_msg = "Die Impfworkflow-Benachrichtigungsadresse konnte nicht gespeichert werden: " . $e->getMessage(); + } + } + } else if($save == 'passwort') { + $activeTab = 'passwort'; $passwortAlt = $_POST['passwortAlt']; $passwortNeu = trim($_POST['passwortNeu']); $passwortNeu2 = trim($_POST['passwortNeu2']); if($passwortNeu != $passwortNeu2) { - $error_msg = "Die eingegebenen Passwörter stimmten nicht überein."; + $error_msg = "Die eingegebenen Passwörter stimmten nicht überein."; } else if($passwortNeu == "") { $error_msg = "Das Passwort darf nicht leer sein."; } else if(!password_verify($passwortAlt, $user['passwort'])) { @@ -107,14 +129,15 @@ endif; - +
-
+

@@ -139,10 +162,10 @@ endif;
- -
+ +

-

Zum Änderen deiner E-Mail-Adresse gib bitte dein aktuelles Passwort sowie die neue E-Mail-Adresse ein.

+

Zum Änderen deiner E-Mail-Adresse gib bitte dein aktuelles Passwort sowie die neue E-Mail-Adresse ein.

@@ -174,10 +197,31 @@ endif;
- -
+

-

Zum Änderen deines Passworts gib bitte dein aktuelles Passwort sowie das neue Passwort ein.

+

Hier hinterlegst du die E-Mail-Adresse, an die spaeter Impfworkflow-Benachrichtigungen gesendet werden sollen.

+ +
+
+ +
+ +
+
+ +
+
+

Leer lassen, um Benachrichtigungen zu deaktivieren.

+ +
+
+
+
+ + +
+
+

Zum Änderen deines Passworts gib bitte dein aktuelles Passwort sowie das neue Passwort ein.

diff --git a/admin/sql/2026-03-20_schema_check.sql b/admin/sql/2026-03-20_schema_check.sql index fac5035..c710ee6 100644 --- a/admin/sql/2026-03-20_schema_check.sql +++ b/admin/sql/2026-03-20_schema_check.sql @@ -17,6 +17,7 @@ FROM ( UNION ALL SELECT 'impfstoff_wochenplan' UNION ALL SELECT 'impf_zeitraum' UNION ALL SELECT 'impf_zeitraum_impfstoff' + UNION ALL SELECT 'warteliste_zeitraum' UNION ALL SELECT 'warteliste' ) t LEFT JOIN information_schema.tables it @@ -51,6 +52,9 @@ FROM ( UNION ALL SELECT 'impf_zeitraum', 'impfortid' UNION ALL SELECT 'impf_zeitraum_impfstoff', 'zeitraum_id' UNION ALL SELECT 'impf_zeitraum_impfstoff', 'impfstoff_id' + UNION ALL SELECT 'warteliste_zeitraum', 'warteid' + UNION ALL SELECT 'warteliste_zeitraum', 'zeitraum_id' + UNION ALL SELECT 'warteliste_zeitraum', 'created_at' UNION ALL SELECT 'warteliste', 'warteid' UNION ALL SELECT 'warteliste', 'userid' UNION ALL SELECT 'warteliste', 'impfenzeitraum' @@ -71,6 +75,7 @@ SELECT END AS status FROM ( SELECT 'warteliste' AS table_name, 'idx_warteliste_zeitraum' AS index_name + UNION ALL SELECT 'warteliste_zeitraum', 'idx_warteliste_zeitraum_zeitraum' UNION ALL SELECT 'impfstoff_wochenplan', 'idx_impfstoff_wochenplan_impfstoff' UNION ALL SELECT 'impfstoff_wochenplan', 'idx_impfstoff_wochenplan_wochentag' UNION ALL SELECT 'impf_zeitraum', 'idx_impf_zeitraum_wochentag' @@ -102,6 +107,24 @@ SELECT ELSE 'TABLE_MISSING' END AS status; +SELECT + 'meta' AS check_type, + 'impf_workflow_meta.legacy_warteliste_zeitraeume_migrated' AS object_name, + CASE + WHEN EXISTS ( + SELECT 1 + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name = 'impf_workflow_meta' + ) THEN COALESCE(( + SELECT CONCAT('VALUE=', meta_value) + FROM impf_workflow_meta + WHERE meta_key = 'legacy_warteliste_zeitraeume_migrated' + LIMIT 1 + ), 'MISSING') + ELSE 'TABLE_MISSING' + END AS status; + SELECT 'data' AS check_type, 'impfstoff_wochenplan rows' AS object_name, @@ -154,3 +177,16 @@ SELECT ) THEN CAST((SELECT COUNT(*) FROM warteliste WHERE zeitraum_id IS NOT NULL) AS CHAR) ELSE 'COLUMN_MISSING' END AS status; + +SELECT + 'data' AS check_type, + 'warteliste_zeitraum rows' AS object_name, + CASE + WHEN EXISTS ( + SELECT 1 + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name = 'warteliste_zeitraum' + ) THEN CAST((SELECT COUNT(*) FROM warteliste_zeitraum) AS CHAR) + ELSE 'TABLE_MISSING' + END AS status; diff --git a/admin/sql/2026-03-20_schema_migration.sql b/admin/sql/2026-03-20_schema_migration.sql index 2e1c519..789abf6 100644 --- a/admin/sql/2026-03-20_schema_migration.sql +++ b/admin/sql/2026-03-20_schema_migration.sql @@ -51,6 +51,14 @@ CREATE TABLE IF NOT EXISTS `impf_zeitraum_impfstoff` ( INDEX `idx_impf_zeitraum_impfstoff_impfstoff` (`impfstoff_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE TABLE IF NOT EXISTS `warteliste_zeitraum` ( + `warteid` INT NOT NULL, + `zeitraum_id` INT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`warteid`, `zeitraum_id`), + INDEX `idx_warteliste_zeitraum_zeitraum` (`zeitraum_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + DROP PROCEDURE IF EXISTS `migrate_praxis_schema_20260320`; DELIMITER $$ CREATE PROCEDURE `migrate_praxis_schema_20260320`() @@ -60,6 +68,8 @@ BEGIN DECLARE v_warteliste_exists INT DEFAULT 0; DECLARE v_zeitraum_id_exists INT DEFAULT 0; DECLARE v_warteliste_index_exists INT DEFAULT 0; + DECLARE v_warteliste_zeitraum_exists INT DEFAULT 0; + DECLARE v_warteliste_zeitraum_index_exists INT DEFAULT 0; DECLARE v_legacy_plan_exists INT DEFAULT 0; SELECT COUNT(*) @@ -114,6 +124,35 @@ BEGIN END IF; END IF; + SELECT COUNT(*) + INTO v_warteliste_zeitraum_exists + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name = 'warteliste_zeitraum'; + + IF v_warteliste_zeitraum_exists = 0 THEN + CREATE TABLE `warteliste_zeitraum` ( + `warteid` INT NOT NULL, + `zeitraum_id` INT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`warteid`, `zeitraum_id`), + INDEX `idx_warteliste_zeitraum_zeitraum` (`zeitraum_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + SET v_warteliste_zeitraum_exists = 1; + ELSE + SELECT COUNT(*) + INTO v_warteliste_zeitraum_index_exists + FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'warteliste_zeitraum' + AND index_name = 'idx_warteliste_zeitraum_zeitraum'; + + IF v_warteliste_zeitraum_index_exists = 0 THEN + ALTER TABLE `warteliste_zeitraum` + ADD INDEX `idx_warteliste_zeitraum_zeitraum` (`zeitraum_id`); + END IF; + END IF; + SELECT COUNT(*) INTO v_legacy_plan_exists FROM information_schema.tables @@ -159,6 +198,18 @@ BEGIN VALUES ('legacy_wochenplan_migrated', '1') AS `incoming` ON DUPLICATE KEY UPDATE `meta_value` = `incoming`.`meta_value`; END IF; + + IF v_warteliste_exists > 0 AND v_warteliste_zeitraum_exists > 0 THEN + INSERT IGNORE INTO `warteliste_zeitraum` (`warteid`, `zeitraum_id`) + SELECT `warteid`, `zeitraum_id` + FROM `warteliste` + WHERE `zeitraum_id` IS NOT NULL + AND `zeitraum_id` > 0; + + INSERT INTO `impf_workflow_meta` (`meta_key`, `meta_value`) + VALUES ('legacy_warteliste_zeitraeume_migrated', '1') AS `incoming` + ON DUPLICATE KEY UPDATE `meta_value` = `incoming`.`meta_value`; + END IF; END $$ DELIMITER ; diff --git a/admin/sql/2026-03-22_warteliste_mehrfach_zeitfenster_migration.sql b/admin/sql/2026-03-22_warteliste_mehrfach_zeitfenster_migration.sql new file mode 100644 index 0000000..8c2652f --- /dev/null +++ b/admin/sql/2026-03-22_warteliste_mehrfach_zeitfenster_migration.sql @@ -0,0 +1,99 @@ +-- Migration fuer Mehrfach-Zeitfenster in der Impfwarteliste. +-- Idempotent: kann mehrfach ausgefuehrt werden. +-- Bestehende Tabellen werden nicht neu aufgebaut, sondern nur erweitert. + +CREATE TABLE IF NOT EXISTS `impf_workflow_meta` ( + `meta_key` VARCHAR(100) NOT NULL, + `meta_value` VARCHAR(255) NOT NULL DEFAULT '', + `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`meta_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +DROP PROCEDURE IF EXISTS `migrate_warteliste_multi_zeitfenster_20260322`; +DELIMITER $$ +CREATE PROCEDURE `migrate_warteliste_multi_zeitfenster_20260322`() +BEGIN + DECLARE v_warteliste_exists INT DEFAULT 0; + DECLARE v_zeitraum_id_exists INT DEFAULT 0; + DECLARE v_warteliste_index_exists INT DEFAULT 0; + DECLARE v_warteliste_zeitraum_exists INT DEFAULT 0; + DECLARE v_warteliste_zeitraum_index_exists INT DEFAULT 0; + + SELECT COUNT(*) + INTO v_warteliste_exists + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name = 'warteliste'; + + IF v_warteliste_exists = 0 THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'Tabelle warteliste wurde nicht gefunden.'; + END IF; + + SELECT COUNT(*) + INTO v_zeitraum_id_exists + FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = 'warteliste' + AND column_name = 'zeitraum_id'; + + IF v_zeitraum_id_exists = 0 THEN + ALTER TABLE `warteliste` + ADD COLUMN `zeitraum_id` INT NULL AFTER `impfenzeitraum`; + END IF; + + SELECT COUNT(*) + INTO v_warteliste_index_exists + FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'warteliste' + AND index_name = 'idx_warteliste_zeitraum'; + + IF v_warteliste_index_exists = 0 THEN + ALTER TABLE `warteliste` + ADD INDEX `idx_warteliste_zeitraum` (`zeitraum_id`); + END IF; + + SELECT COUNT(*) + INTO v_warteliste_zeitraum_exists + FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name = 'warteliste_zeitraum'; + + IF v_warteliste_zeitraum_exists = 0 THEN + CREATE TABLE `warteliste_zeitraum` ( + `warteid` INT NOT NULL, + `zeitraum_id` INT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`warteid`, `zeitraum_id`), + INDEX `idx_warteliste_zeitraum_zeitraum` (`zeitraum_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + SET v_warteliste_zeitraum_exists = 1; + END IF; + + SELECT COUNT(*) + INTO v_warteliste_zeitraum_index_exists + FROM information_schema.statistics + WHERE table_schema = DATABASE() + AND table_name = 'warteliste_zeitraum' + AND index_name = 'idx_warteliste_zeitraum_zeitraum'; + + IF v_warteliste_zeitraum_index_exists = 0 THEN + ALTER TABLE `warteliste_zeitraum` + ADD INDEX `idx_warteliste_zeitraum_zeitraum` (`zeitraum_id`); + END IF; + + INSERT IGNORE INTO `warteliste_zeitraum` (`warteid`, `zeitraum_id`) + SELECT `warteid`, `zeitraum_id` + FROM `warteliste` + WHERE `zeitraum_id` IS NOT NULL + AND `zeitraum_id` > 0; + + INSERT INTO `impf_workflow_meta` (`meta_key`, `meta_value`) + VALUES ('legacy_warteliste_zeitraeume_migrated', '1') AS `incoming` + ON DUPLICATE KEY UPDATE `meta_value` = `incoming`.`meta_value`; +END $$ +DELIMITER ; + +CALL `migrate_warteliste_multi_zeitfenster_20260322`(); +DROP PROCEDURE IF EXISTS `migrate_warteliste_multi_zeitfenster_20260322`; diff --git a/impfwarteliste.php b/impfwarteliste.php index a1caadc..a80bf42 100644 --- a/impfwarteliste.php +++ b/impfwarteliste.php @@ -8,6 +8,32 @@ ' + . '

Fehler in impfwarteliste.php

' + . '

Die Seite ist wegen eines PHP-Fehlers abgebrochen.

' + . '

Meldung: ' . htmlspecialchars((string)$error['message'], ENT_QUOTES, 'UTF-8') . '
' + . 'Datei: ' . htmlspecialchars((string)$error['file'], ENT_QUOTES, 'UTF-8') . '
' + . 'Zeile: ' . (int)$error['line'] . '

' + . '
'; + }); + include('header.php'); ?> @@ -26,11 +52,17 @@ include_once("inc/config.inc.php"); include_once("inc/functions.inc.php"); include_once('inc/functions.impfen.inc.php'); + include_once('inc/impfworkflow_notifications.inc.php'); + $workflowSetupError = ''; if ($con instanceof mysqli) { mysqli_set_charset($con, "utf8mb4"); } if (isset($pdo) && $pdo instanceof PDO) { - impfWorkflowEnsureTables($pdo); + try { + impfWorkflowEnsureTables($pdo); + } catch (Throwable $e) { + $workflowSetupError = $e->getMessage(); + } } $zeitOptionenJson = "{}"; ?> @@ -57,11 +89,20 @@ $mailbetreff = "Ihr Wartelistenplatz für eine Impfung bei Praxis Creutzburg";

Impfwarteliste

+ +
+ Die Impfworkflow-Tabellen konnten nicht automatisch geprueft werden:
+ Bitte fuehren Sie zuerst das Migrationsskript aus. +
+ ', array_map(static function ($label) { + return e((string)$label); + }, $ausgewaehlteZeitraeume)); + } else { + $impfenzeitraum = htmlspecialchars((string)$impfenzeitraum, ENT_QUOTES, 'UTF-8'); + } //echo $userid; $queryuser = mysqli_query($con, "SELECT * FROM persons WHERE person_id='" . $userid . "'"); $rowuser = $queryuser->fetch_assoc(); @@ -133,7 +185,7 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ echo "

Art: $Patientenart

"; echo "

Telefon: $tel

"; echo "

Impfstoff: $impfstofftext

"; - echo "

Zeitraum: $impfenzeitraum


"; + echo "

Zeitraum:
$impfenzeitraum


"; echo ""; echo ''; @@ -151,6 +203,13 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ echo "Sie haben die folgenden Angaben:

"; echo "

Name: $userausgabe

"; echo "

Impfstoff: $impfstofftext


"; + if (!empty($ausgewaehlteZeitraeume)) { + echo "

Ausgewählte Zeitfenster:
" . implode('
', array_map(static function ($label) { + return e((string)$label); + }, $ausgewaehlteZeitraeume)) . "

"; + } else { + echo "

Zeitraum: $impfenzeitraum

"; + } echo "

Wir informieren Sie, sobald ein konkreter Impftermin für Ihren Impfstoff festgelegt wurde.

"; echo "Die Terminvergabe erfolgt durch das Praxisteam, sobald eine komplette Impfflasche mit passenden Wartelistenplätzen gefüllt ist.

"; echo "Können Sie Ihren Warteplatz nicht wahrnehmen oder benötigen diesen nicht mehr, dann tragen Sie sich bitte aus:
"; @@ -198,6 +257,24 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ echo "\n"; continue; } + if($key === "impfenzeitraeume" && is_array($value)){ + $zeitraumIds = impfNormalizeZeitraumIds($value); + $zeitraumLabels = []; + foreach ($zeitraumIds as $zeitraumId) { + $zeitraumRow = null; + if (isset($pdo) && $pdo instanceof PDO) { + $zeitraumRow = impfLoadZeitraumById($pdo, (int)$zeitraumId, true); + } + if ($zeitraumRow) { + $zeitraumLabels[] = (string)$zeitraumRow['label']; + echo '' . "\n"; + } + } + echo "$key:" . implode("
", array_map(static function ($label) { + return e((string)$label); + }, $zeitraumLabels)) . "\n"; + continue; + } if($value !== ""){ if($key == "Impfstoff"){ $sqlimpfstoffstring = "SELECT * FROM impfstoff WHERE impfid ='" . $value . "' order by sortierung"; @@ -215,6 +292,7 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ } $zeitraumText = $zeitraumRow ? $zeitraumRow['label'] : 'Unbekannter Zeitraum'; echo "$key:$zeitraumText\n"; + echo"\n"; echo"\n"; }else{ echo "$key:$value\n"; @@ -249,12 +327,12 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ $Impfaufklaerung = mysqli_real_escape_string($con, $_POST["Impfaufklaerung"] ?? "Nein"); $WeitereFragen = mysqli_real_escape_string($con, $_POST["WeitereFragen"] ?? "Nein"); $impfenmit = mysqli_real_escape_string($con, $_POST["zusammenmit"] ?? ""); - $impfenzeitraumId = (int)($_POST["impfenzeitraum"] ?? 0); + $impfenzeitraumIds = impfNormalizeZeitraumIds($_POST["impfenzeitraeume"] ?? ($_POST["impfenzeitraum"] ?? [])); $impfart = (int)($_POST["impfart"] ?? 0); $letzteimpfung = trim($_POST["letzteimpfung"] ?? ""); - if ($impfstoff <= 0 || $impfart <= 0 || $impfenzeitraumId <= 0) { - echo "

Pflichtfelder fehlen


Bitte wählen Sie Impfstoff, Zeitraum und Impfungsart aus.

"; + if ($impfstoff <= 0 || $impfart <= 0 || empty($impfenzeitraumIds)) { + echo "

Pflichtfelder fehlen


Bitte wählen Sie Impfstoff, mindestens einen Zeitraum und die Impfungsart aus.

"; goto end_aktion_1; } @@ -267,12 +345,19 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ $letzteimpfung = ""; } - $zeitraumRow = (isset($pdo) && $pdo instanceof PDO) ? impfLoadZeitraumById($pdo, $impfenzeitraumId, true) : null; - if (!$zeitraumRow || !in_array($impfstoff, $zeitraumRow['impfstoff_id_list'] ?? [], true)) { - echo "

Ungültiger Zeitraum


Bitte wählen Sie einen gültigen Zeitraum für den ausgewählten Impfstoff.

"; - goto end_aktion_1; + $zeitraumLabels = []; + if (isset($pdo) && $pdo instanceof PDO) { + foreach ($impfenzeitraumIds as $impfenzeitraumId) { + $zeitraumRow = impfLoadZeitraumById($pdo, (int)$impfenzeitraumId, true); + if (!$zeitraumRow || !in_array($impfstoff, $zeitraumRow['impfstoff_id_list'] ?? [], true)) { + echo "

Ungültiger Zeitraum


Bitte wählen Sie einen gültigen Zeitraum für den ausgewählten Impfstoff aus.

"; + goto end_aktion_1; + } + $zeitraumLabels[] = (string)$zeitraumRow['label']; + } } - $impfenzeitraum = mysqli_real_escape_string($con, $zeitraumRow['label']); + $impfenzeitraum = mysqli_real_escape_string($con, implode(' | ', $zeitraumLabels)); + $impfenzeitraumId = (int)($impfenzeitraumIds[0] ?? 0); //echo $impfenmit; @@ -333,12 +418,43 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ $letzteimpfungSql = ($letzteimpfung !== "") ? ("'" . mysqli_real_escape_string($con, $letzteimpfung) . "'") : "NULL"; $query = mysqli_query($con, "SELECT * FROM warteliste WHERE userid='" . (int)$userid . "'"); if($query && $query->num_rows == 0){ - $query = mysqli_query($con, "INSERT INTO warteliste (userid, hash, impfenangebot, impfstoff, Patientenart,Impfaufklaerung, WeitereFragen, date_created, impfenmit, impfenzeitraum, zeitraum_id, impfart, letzteimpfung, checked) VALUES ('". (int)$userid ."', '".$hash."', '".$impfenangebot."', '".$impfstoff."', '".$Patientenart."', '".$Impfaufklaerung."', '".$WeitereFragen."', now(), '".$impfenmit."', '".$impfenzeitraum."', '". (int)$impfenzeitraumId ."', '".$impfart."', ".$letzteimpfungSql.", '0')"); - if($query){ - $warteid = mysqli_insert_id($con); - SendMailMessageVorlage($pdo, "2", $warteid , "8" ); + $warteid = 0; + $saveOk = false; + $saveErrorShown = false; + try { + if (isset($pdo) && $pdo instanceof PDO) { + [$ok, $msg, $newWarteid] = impfCreateWaitlistEntryForPerson( + $pdo, + (int)$userid, + $impfstoff, + $impfenzeitraumIds, + $impfart, + ($letzteimpfung !== "") ? $letzteimpfung : null, + 0 + ); + if (!$ok) { + throw new RuntimeException($msg); + } + $warteid = (int)$newWarteid; + $pdo->prepare("UPDATE warteliste SET impfenangebot = :impfenangebot, impfenmit = :impfenmit, Impfaufklaerung = :aufklaerung, WeitereFragen = :fragen WHERE warteid = :warteid") + ->execute([ + 'impfenangebot' => $impfenangebot, + 'impfenmit' => $impfenmit, + 'aufklaerung' => $Impfaufklaerung, + 'fragen' => $WeitereFragen, + 'warteid' => $warteid, + ]); + $saveOk = true; + } else { + throw new RuntimeException("PDO Verbindungsobjekt fehlt."); + } + SendMailMessageVorlage($pdo, "2", (int)$warteid, "8" ); echo "

Nachricht abgeschickt!


Sie müssen die Eintragung in der Warteliste noch bestätigen!
Überprüfen Sie auch Ihren Spam-Filter!

"; - }else{ + } catch (Throwable $e) { + echo "

Speicherung nicht erfolgreich


" . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8') . "

"; + $saveErrorShown = true; + } + if(!$saveOk && !$saveErrorShown){ echo "

Speicherung nicht erfolgreich


Ihre Anfrage konnte nicht gespeichert werden.
Nutzen Sie das Formular erneut

"; } }else{ @@ -381,6 +497,13 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ $userausgabe = $vorname . " " . $nachname; SendMailMessageVorlage($pdo, "2", $warteid , "9" ); + if (isset($pdo) && $pdo instanceof PDO) { + try { + impfWorkflowNotificationProcess($pdo); + } catch (Throwable $e) { + error_log('impfWorkflowNotificationProcess failed in impfwarteliste confirm: ' . $e->getMessage()); + } + } @@ -398,11 +521,22 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ $queryimpf = mysqli_query($con, "SELECT * FROM warteliste WHERE warteid='" . $_POST["warteid"] . "'"); $rowimpf = $queryimpf->fetch_assoc() ; SendMailMessageVorlage($pdo, "2", $_POST["warteid"], "10" ); + if (isset($pdo) && $pdo instanceof PDO) { + $pdo->prepare("DELETE FROM warteliste_zeitraum WHERE warteid = :warteid")->execute([ + 'warteid' => (int)$_POST["warteid"], + ]); + } $query = mysqli_query($con, "DELETE FROM warteliste WHERE warteid ='".$_POST["warteid"]."'"); if($query){ echo "

Ihr Warteplatz wurde erfolgreich gelöscht!


"; echo "Sie erhalten gleiche eine schriftliche Bestätigung per E-Mail
"; - + if (isset($pdo) && $pdo instanceof PDO) { + try { + impfWorkflowNotificationProcess($pdo); + } catch (Throwable $e) { + error_log('impfWorkflowNotificationProcess failed in impfwarteliste delete: ' . $e->getMessage()); + } + } } } @@ -443,9 +577,12 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ echo "

Mail wird gleich versendet!

"; echo "
Überprüfen Sie auch Ihren SPAM Ordner!
"; SendMailMessageVorlage($pdo, "1", (int)$terminid, "1" ); - - - $query = mysqli_query($con, "DELETE FROM warteliste WHERE warteid ='".$warteid."'"); + if (isset($pdo) && $pdo instanceof PDO) { + $pdo->prepare("DELETE FROM warteliste_zeitraum WHERE warteid = :warteid")->execute([ + 'warteid' => (int)$warteid, + ]); + } + $query = mysqli_query($con, "DELETE FROM warteliste WHERE warteid ='".$warteid."'"); }else{ echo "

Fehler bei Speichern der Anfragen!

"; echo "
Versuchen Sie es später erneut!
"; @@ -512,7 +649,7 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ } $zeitOptionenByImpfstoff[$iid][] = [ 'id' => (int)$zeitraum['zeitraum_id'], - 'label' => (string)$zeitraum['label'], + 'label' => impfZeitraumLabel($zeitraum, false), ]; } } @@ -602,9 +739,9 @@ if(isset($_POST["id"]) || isset($_GET["id"])){

- +
-
@@ -680,6 +817,7 @@ if(isset($_POST["id"]) || isset($_GET["id"])){ diff --git a/inc/functions.impfen.inc.php b/inc/functions.impfen.inc.php index ceb70d8..6a83e65 100644 --- a/inc/functions.impfen.inc.php +++ b/inc/functions.impfen.inc.php @@ -35,6 +35,41 @@ if (!function_exists('impfTableHasIndex')) { } } +if (!function_exists('impfEnsureTable')) { + function impfEnsureTable(PDO $pdo, string $table, string $createSql): void + { + if (impfTableExists($pdo, $table)) { + return; + } + + $pdo->exec($createSql); + } +} + +if (!function_exists('impfNormalizeZeitraumIds')) { + function impfNormalizeZeitraumIds($zeitraumIds): array + { + if ($zeitraumIds === null) { + return []; + } + + if (!is_array($zeitraumIds)) { + $zeitraumIds = [$zeitraumIds]; + } + + $result = []; + foreach ($zeitraumIds as $zeitraumId) { + $zeitraumId = (int)$zeitraumId; + if ($zeitraumId <= 0 || isset($result[$zeitraumId])) { + continue; + } + $result[$zeitraumId] = $zeitraumId; + } + + return array_values($result); + } +} + if (!function_exists('impfWeekdayName')) { function impfWeekdayName(int $day): string { @@ -55,21 +90,21 @@ if (!function_exists('impfWeekdayName')) { if (!function_exists('impfWorkflowEnsureTables')) { function impfWorkflowEnsureTables(PDO $pdo): void { - $pdo->exec("CREATE TABLE IF NOT EXISTS impf_workflow_meta ( + impfEnsureTable($pdo, 'impf_workflow_meta', "CREATE TABLE impf_workflow_meta ( meta_key VARCHAR(100) NOT NULL, meta_value VARCHAR(255) NOT NULL DEFAULT '', updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (meta_key) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3"); - $pdo->exec("CREATE TABLE IF NOT EXISTS impfstoff_workflow ( + impfEnsureTable($pdo, 'impfstoff_workflow', "CREATE TABLE impfstoff_workflow ( impfstoff_id INT NOT NULL, dosen_pro_flasche INT NOT NULL, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (impfstoff_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3"); - $pdo->exec("CREATE TABLE IF NOT EXISTS impfstoff_wochenplan ( + impfEnsureTable($pdo, 'impfstoff_wochenplan', "CREATE TABLE impfstoff_wochenplan ( plan_id INT NOT NULL AUTO_INCREMENT, impfstoff_id INT NOT NULL, wochentag TINYINT NOT NULL, @@ -83,7 +118,7 @@ if (!function_exists('impfWorkflowEnsureTables')) { INDEX idx_impfstoff_wochenplan_wochentag (wochentag) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3"); - $pdo->exec("CREATE TABLE IF NOT EXISTS impf_zeitraum ( + impfEnsureTable($pdo, 'impf_zeitraum', "CREATE TABLE impf_zeitraum ( zeitraum_id INT NOT NULL AUTO_INCREMENT, bezeichnung VARCHAR(120) NOT NULL DEFAULT '', wochentag TINYINT NOT NULL, @@ -101,7 +136,7 @@ if (!function_exists('impfWorkflowEnsureTables')) { $pdo->exec("ALTER TABLE impf_zeitraum ADD COLUMN bezeichnung VARCHAR(120) NOT NULL DEFAULT '' AFTER zeitraum_id"); } - $pdo->exec("CREATE TABLE IF NOT EXISTS impf_zeitraum_impfstoff ( + impfEnsureTable($pdo, 'impf_zeitraum_impfstoff', "CREATE TABLE impf_zeitraum_impfstoff ( zeitraum_id INT NOT NULL, impfstoff_id INT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -109,6 +144,18 @@ if (!function_exists('impfWorkflowEnsureTables')) { INDEX idx_impf_zeitraum_impfstoff_impfstoff (impfstoff_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3"); + impfEnsureTable($pdo, 'warteliste_zeitraum', "CREATE TABLE warteliste_zeitraum ( + warteid INT NOT NULL, + zeitraum_id INT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (warteid, zeitraum_id), + INDEX idx_warteliste_zeitraum_zeitraum (zeitraum_id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3"); + + if (impfTableExists($pdo, 'warteliste_zeitraum') && !impfTableHasIndex($pdo, 'warteliste_zeitraum', 'idx_warteliste_zeitraum_zeitraum')) { + $pdo->exec("ALTER TABLE warteliste_zeitraum ADD INDEX idx_warteliste_zeitraum_zeitraum (zeitraum_id)"); + } + if (impfTableExists($pdo, 'warteliste') && !impfTableHasColumn($pdo, 'warteliste', 'zeitraum_id')) { $pdo->exec("ALTER TABLE warteliste ADD COLUMN zeitraum_id INT NULL AFTER impfenzeitraum"); } @@ -117,6 +164,7 @@ if (!function_exists('impfWorkflowEnsureTables')) { } impfWorkflowMigrateLegacyPlans($pdo); + impfWorkflowMigrateLegacyWartelisteZeitraeume($pdo); } } @@ -227,6 +275,42 @@ if (!function_exists('impfWorkflowMigrateLegacyPlans')) { } } +if (!function_exists('impfWorkflowMigrateLegacyWartelisteZeitraeume')) { + function impfWorkflowMigrateLegacyWartelisteZeitraeume(PDO $pdo): void + { + if (!impfTableExists($pdo, 'warteliste') || !impfTableExists($pdo, 'warteliste_zeitraum')) { + return; + } + + if (impfWorkflowGetMeta($pdo, 'legacy_warteliste_zeitraeume_migrated') === '1') { + return; + } + + $manageTransaction = !$pdo->inTransaction(); + if ($manageTransaction) { + $pdo->beginTransaction(); + } + + try { + $pdo->exec("INSERT IGNORE INTO warteliste_zeitraum (warteid, zeitraum_id) + SELECT warteid, zeitraum_id + FROM warteliste + WHERE zeitraum_id IS NOT NULL + AND zeitraum_id > 0"); + impfWorkflowSetMeta($pdo, 'legacy_warteliste_zeitraeume_migrated', '1'); + + if ($manageTransaction) { + $pdo->commit(); + } + } catch (Throwable $e) { + if ($manageTransaction && $pdo->inTransaction()) { + $pdo->rollBack(); + } + throw $e; + } + } +} + if (!function_exists('impfCsvToIntList')) { function impfCsvToIntList(?string $csv): array { @@ -243,7 +327,7 @@ if (!function_exists('impfCsvToIntList')) { } if (!function_exists('impfZeitraumLabel')) { - function impfZeitraumLabel(array $zeitraum): string + function impfZeitraumLabel(array $zeitraum, bool $includeName = true): string { $zeitText = impfWeekdayName((int)$zeitraum['wochentag']) . ' ' . substr((string)$zeitraum['start'], 0, 5) . '-' . substr((string)$zeitraum['ende'], 0, 5); $ort = trim((string)($zeitraum['anzeigename'] ?? '') . ' - ' . (string)($zeitraum['adresse'] ?? '')); @@ -253,7 +337,7 @@ if (!function_exists('impfZeitraumLabel')) { } $bezeichnung = trim((string)($zeitraum['bezeichnung'] ?? '')); - if ($bezeichnung !== '') { + if ($includeName && $bezeichnung !== '') { return $bezeichnung . ': ' . $zeitText; } @@ -388,7 +472,7 @@ if (!function_exists('impfGetWartelistenFormOptions')) { } $zeitfenster[$impfstoffId][] = [ 'id' => (int)$zeitraum['zeitraum_id'], - 'label' => (string)$zeitraum['label'], + 'label' => impfZeitraumLabel($zeitraum, false), ]; } } @@ -406,12 +490,112 @@ if (!function_exists('impfGetWartelistenFormOptions')) { } } +if (!function_exists('impfGetWartelistenZeitraeume')) { + function impfGetWartelistenZeitraeume(PDO $pdo, int $warteid, bool $onlyActive = false): array + { + if ($warteid <= 0 || !impfTableExists($pdo, 'warteliste_zeitraum')) { + return []; + } + + $sql = "SELECT z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, + o.anzeigename, o.adresse + FROM warteliste_zeitraum wz + INNER JOIN impf_zeitraum z ON z.zeitraum_id = wz.zeitraum_id + LEFT JOIN impfort o ON o.ortid = z.impfortid + WHERE wz.warteid = :warteid"; + if ($onlyActive) { + $sql .= " AND z.aktiv = 1"; + } + $sql .= " ORDER BY z.wochentag, z.start, z.ende, z.bezeichnung, z.zeitraum_id"; + + $st = $pdo->prepare($sql); + $st->execute(['warteid' => $warteid]); + $rows = $st->fetchAll(PDO::FETCH_ASSOC); + + foreach ($rows as &$row) { + $row['label'] = impfZeitraumLabel($row); + } + unset($row); + + if (!empty($rows)) { + return $rows; + } + + $stFallback = $pdo->prepare("SELECT w.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, + o.anzeigename, o.adresse + FROM warteliste w + LEFT JOIN impf_zeitraum z ON z.zeitraum_id = w.zeitraum_id + LEFT JOIN impfort o ON o.ortid = z.impfortid + WHERE w.warteid = :warteid + AND w.zeitraum_id IS NOT NULL + LIMIT 1"); + $stFallback->execute(['warteid' => $warteid]); + $row = $stFallback->fetch(PDO::FETCH_ASSOC); + if (!$row) { + return []; + } + + $row['label'] = impfZeitraumLabel($row); + return [$row]; + } +} + +if (!function_exists('impfGetWartelistenZeitraeumeLabels')) { + function impfGetWartelistenZeitraeumeLabels(PDO $pdo, int $warteid, bool $onlyActive = false): array + { + $rows = impfGetWartelistenZeitraeume($pdo, $warteid, $onlyActive); + return array_values(array_map(static function (array $row): string { + return (string)($row['label'] ?? ''); + }, $rows)); + } +} + +if (!function_exists('impfSetWartelistenZeitraeume')) { + function impfSetWartelistenZeitraeume(PDO $pdo, int $warteid, $zeitraumIds): void + { + $zeitraumIds = impfNormalizeZeitraumIds($zeitraumIds); + if ($warteid <= 0) { + throw new InvalidArgumentException('Unguelige Wartelisten-ID.'); + } + + $manageTransaction = !$pdo->inTransaction(); + if ($manageTransaction) { + $pdo->beginTransaction(); + } + + try { + $stDelete = $pdo->prepare("DELETE FROM warteliste_zeitraum WHERE warteid = :warteid"); + $stDelete->execute(['warteid' => $warteid]); + + if (!empty($zeitraumIds)) { + $stInsert = $pdo->prepare("INSERT INTO warteliste_zeitraum (warteid, zeitraum_id) + VALUES (:warteid, :zeitraum_id)"); + foreach ($zeitraumIds as $zeitraumId) { + $stInsert->execute([ + 'warteid' => $warteid, + 'zeitraum_id' => $zeitraumId, + ]); + } + } + + if ($manageTransaction) { + $pdo->commit(); + } + } catch (Throwable $e) { + if ($manageTransaction && $pdo->inTransaction()) { + $pdo->rollBack(); + } + throw $e; + } + } +} + if (!function_exists('impfCreateWaitlistEntryForPerson')) { function impfCreateWaitlistEntryForPerson( PDO $pdo, int $personId, int $impfstoffId, - int $zeitraumId, + $zeitraumIds, int $impfart, ?string $letzteImpfung = null, int $checked = 1 @@ -422,13 +606,15 @@ if (!function_exists('impfCreateWaitlistEntryForPerson')) { if ($impfstoffId <= 0) { return [false, 'Bitte einen Impfstoff auswaehlen.', null]; } - if ($zeitraumId <= 0) { - return [false, 'Bitte ein Zeitfenster auswaehlen.', null]; - } if ($impfart < 1 || $impfart > 4) { return [false, 'Bitte eine gueltige Impfungsart auswaehlen.', null]; } + $zeitraumIds = impfNormalizeZeitraumIds($zeitraumIds); + if (empty($zeitraumIds)) { + return [false, 'Bitte mindestens ein Zeitfenster auswaehlen.', null]; + } + $letzteImpfung = $letzteImpfung !== null ? trim($letzteImpfung) : null; if ($impfart === 1) { $letzteImpfung = null; @@ -448,26 +634,32 @@ if (!function_exists('impfCreateWaitlistEntryForPerson')) { return [false, 'Die Person wurde nicht gefunden.', null]; } - $zeitraum = impfLoadZeitraumById($pdo, $zeitraumId, true); - if (!$zeitraum) { - return [false, 'Das ausgewaehlte Zeitfenster ist nicht mehr verfuegbar.', null]; - } - if (!in_array($impfstoffId, $zeitraum['impfstoff_id_list'] ?? [], true)) { - return [false, 'Impfstoff und Zeitfenster passen nicht zusammen.', null]; + $zeitraumRows = []; + $zeitraumLabels = []; + foreach ($zeitraumIds as $zeitraumId) { + $row = impfLoadZeitraumById($pdo, $zeitraumId, true); + if (!$row) { + return [false, 'Mindestens ein ausgewaehltes Zeitfenster ist nicht mehr verfuegbar.', null]; + } + if (!in_array($impfstoffId, $row['impfstoff_id_list'] ?? [], true)) { + return [false, 'Impfstoff und Zeitfenster passen nicht zusammen.', null]; + } + $zeitraumRows[$zeitraumId] = $row; + $zeitraumLabels[] = (string)$row['label']; } - $stDup = $pdo->prepare("SELECT warteid - FROM warteliste - WHERE userid = :uid - AND checked IN (0, 1) - AND impfstoff = :impfstoff - AND COALESCE(zeitraum_id, 0) = :zeitraum_id - AND impfart = :impfart + $stDup = $pdo->prepare("SELECT w.warteid + FROM warteliste w + LEFT JOIN warteliste_zeitraum wz ON wz.warteid = w.warteid + WHERE w.userid = :uid + AND w.checked IN (0, 1) + AND w.impfstoff = :impfstoff + AND w.impfart = :impfart + GROUP BY w.warteid LIMIT 1"); $stDup->execute([ 'uid' => $personId, 'impfstoff' => $impfstoffId, - 'zeitraum_id' => $zeitraumId, 'impfart' => $impfart, ]); if ($stDup->fetchColumn()) { @@ -477,26 +669,45 @@ if (!function_exists('impfCreateWaitlistEntryForPerson')) { $patientenart = ((int)($person['patientenart'] ?? 0) === 1) ? 1 : 0; $hash = bin2hex(random_bytes(16)); $checkedValue = ($checked === 0) ? 0 : 1; + $primaerZeitraumId = (int)$zeitraumIds[0]; + $impfenzeitraum = implode(' | ', $zeitraumLabels); - $stInsert = $pdo->prepare("INSERT INTO warteliste - (userid, checked, hash, impfenangebot, impfstoff, Patientenart, Impfaufklaerung, WeitereFragen, impfart, impfenmit, letzteimpfung, impfenzeitraum, zeitraum_id, date_created) - VALUES - (:userid, :checked, :hash, 1, :impfstoff, :patientenart, 0, 0, :impfart, '', :letzteimpfung, :impfenzeitraum, :zeitraum_id, NOW())"); - $stInsert->execute([ - 'userid' => $personId, - 'checked' => $checkedValue, - 'hash' => $hash, - 'impfstoff' => $impfstoffId, - 'patientenart' => $patientenart, - 'impfart' => $impfart, - 'letzteimpfung' => $letzteImpfung, - 'impfenzeitraum' => (string)$zeitraum['label'], - 'zeitraum_id' => $zeitraumId, - ]); + $manageTransaction = !$pdo->inTransaction(); + if ($manageTransaction) { + $pdo->beginTransaction(); + } - $warteid = (int)$pdo->lastInsertId(); - $personName = trim((string)$person['vorname'] . ' ' . (string)$person['nachname']); + try { + $stInsert = $pdo->prepare("INSERT INTO warteliste + (userid, checked, hash, impfenangebot, impfstoff, Patientenart, Impfaufklaerung, WeitereFragen, impfart, impfenmit, letzteimpfung, impfenzeitraum, zeitraum_id, date_created) + VALUES + (:userid, :checked, :hash, 1, :impfstoff, :patientenart, 0, 0, :impfart, '', :letzteimpfung, :impfenzeitraum, :zeitraum_id, NOW())"); + $stInsert->execute([ + 'userid' => $personId, + 'checked' => $checkedValue, + 'hash' => $hash, + 'impfstoff' => $impfstoffId, + 'patientenart' => $patientenart, + 'impfart' => $impfart, + 'letzteimpfung' => $letzteImpfung, + 'impfenzeitraum' => $impfenzeitraum, + 'zeitraum_id' => $primaerZeitraumId, + ]); - return [true, 'Wartelistenplatz fuer ' . $personName . ' wurde gespeichert.', $warteid]; + $warteid = (int)$pdo->lastInsertId(); + impfSetWartelistenZeitraeume($pdo, $warteid, $zeitraumIds); + + if ($manageTransaction) { + $pdo->commit(); + } + + $personName = trim((string)$person['vorname'] . ' ' . (string)$person['nachname']); + return [true, 'Wartelistenplatz fuer ' . $personName . ' wurde gespeichert.', $warteid]; + } catch (Throwable $e) { + if ($manageTransaction && $pdo->inTransaction()) { + $pdo->rollBack(); + } + throw $e; + } } } diff --git a/inc/functions.inc.php b/inc/functions.inc.php index ae4d36e..f6a4da5 100644 --- a/inc/functions.inc.php +++ b/inc/functions.inc.php @@ -1262,6 +1262,8 @@ function Userspeichern($vorname, $nachname, $geburtstag, $mail, $tele, $ort, $pl UPDATE persons SET vorname=:vorname, nachname=:nachname, + geburtstag=:geburtstag, + email=:email, tele=:tele, ort=:ort, plz=:plz, diff --git a/inc/impfworkflow_notifications.inc.php b/inc/impfworkflow_notifications.inc.php new file mode 100644 index 0000000..24502c7 --- /dev/null +++ b/inc/impfworkflow_notifications.inc.php @@ -0,0 +1,256 @@ +exec("CREATE TABLE IF NOT EXISTS impf_workflow_meta ( + meta_key VARCHAR(100) NOT NULL, + meta_value VARCHAR(255) NOT NULL DEFAULT '', + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (meta_key) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); + } +} + +if (!function_exists('impfWorkflowNotificationGetMeta')) { + function impfWorkflowNotificationGetMeta(PDO $pdo, string $key): ?string + { + impfWorkflowNotificationEnsureMetaTable($pdo); + + $st = $pdo->prepare("SELECT meta_value + FROM impf_workflow_meta + WHERE meta_key = :meta_key + LIMIT 1"); + $st->execute(['meta_key' => $key]); + $value = $st->fetchColumn(); + + return ($value === false) ? null : (string)$value; + } +} + +if (!function_exists('impfWorkflowNotificationSetMeta')) { + function impfWorkflowNotificationSetMeta(PDO $pdo, string $key, string $value): void + { + impfWorkflowNotificationEnsureMetaTable($pdo); + + $st = $pdo->prepare("INSERT INTO impf_workflow_meta (meta_key, meta_value) + VALUES (:meta_key, :meta_value) + ON DUPLICATE KEY UPDATE meta_value = VALUES(meta_value)"); + $st->execute([ + 'meta_key' => $key, + 'meta_value' => $value, + ]); + } +} + +if (!function_exists('impfWorkflowNotificationGetEmail')) { + function impfWorkflowNotificationGetEmail(PDO $pdo): string + { + return trim((string)(impfWorkflowNotificationGetMeta($pdo, 'benachrichtigung_email') ?? '')); + } +} + +if (!function_exists('impfWorkflowNotificationSetEmail')) { + function impfWorkflowNotificationSetEmail(PDO $pdo, string $email): void + { + $email = trim($email); + impfWorkflowNotificationSetMeta($pdo, 'benachrichtigung_email', $email); + } +} + +if (!function_exists('impfWorkflowNotificationIsReady')) { + function impfWorkflowNotificationIsReady(PDO $pdo): bool + { + return impfWorkflowNotificationGetEmail($pdo) !== ''; + } +} + +if (!function_exists('impfWorkflowNotificationShouldTrigger')) { + function impfWorkflowNotificationShouldTrigger(int $wartende, int $dosen): bool + { + if ($wartende < 5) { + return false; + } + + if ($dosen > 5) { + return $wartende >= $dosen; + } + + return true; + } +} + +if (!function_exists('impfWorkflowNotificationStateKey')) { + function impfWorkflowNotificationStateKey(int $impfstoffId, int $zeitraumId): string + { + return 'notification_sent_' . $impfstoffId . '_' . $zeitraumId; + } +} + +if (!function_exists('impfWorkflowNotificationCountWaitersForPlan')) { + function impfWorkflowNotificationCountWaitersForPlan(PDO $pdo, int $impfstoffId, int $zeitraumId): int + { + if ($impfstoffId <= 0 || $zeitraumId <= 0) { + return 0; + } + + $st = $pdo->prepare("SELECT COUNT(DISTINCT w.userid) + FROM warteliste w + WHERE w.checked = 1 + AND (w.impfstoff = :iid OR w.impfstoff = 0) + AND ( + EXISTS ( + SELECT 1 + FROM warteliste_zeitraum wz + WHERE wz.warteid = w.warteid + AND wz.zeitraum_id = :zid + ) + OR ( + NOT EXISTS ( + SELECT 1 + FROM warteliste_zeitraum wz_none + WHERE wz_none.warteid = w.warteid + ) + AND (w.zeitraum_id = :zid OR w.zeitraum_id IS NULL) + ) + )"); + $st->execute([ + 'iid' => $impfstoffId, + 'zid' => $zeitraumId, + ]); + + return (int)$st->fetchColumn(); + } +} + +if (!function_exists('impfWorkflowNotificationSendForPlan')) { + function impfWorkflowNotificationSendForPlan( + PDO $pdo, + int $impfstoffId, + string $impfstoffName, + int $zeitraumId, + string $zeitraumLabel, + int $wartende, + int $dosen + ): array { + if ($impfstoffId <= 0 || $zeitraumId <= 0) { + return []; + } + + $stateKey = impfWorkflowNotificationStateKey($impfstoffId, $zeitraumId); + $alreadySent = impfWorkflowNotificationGetMeta($pdo, $stateKey) === '1'; + $shouldTrigger = impfWorkflowNotificationShouldTrigger($wartende, $dosen); + + if (!$shouldTrigger) { + if ($alreadySent) { + impfWorkflowNotificationSetMeta($pdo, $stateKey, '0'); + } + return []; + } + + if ($alreadySent) { + return []; + } + + $email = impfWorkflowNotificationGetEmail($pdo); + if ($email === '') { + return []; + } + + $thresholdText = ($dosen > 5) + ? 'Die Flasche hat mehr als 5 Dosen, daher wird erst bei einer vollen Flasche benachrichtigt.' + : 'Es sind mindestens 5 Interessenten fuer dieses Zeitfenster vorhanden.'; + + $subject = 'Impfworkflow: Warteliste ist bereit fuer ' . $impfstoffName; + $body = '

Fuer den Impfworkflow ist ein Zeitfenster benachrichtigungsreif.

' + . '

Impfstoff: ' . htmlspecialchars($impfstoffName, ENT_QUOTES, 'UTF-8') . '
' + . 'Zeitfenster: ' . htmlspecialchars($zeitraumLabel, ENT_QUOTES, 'UTF-8') . '
' + . 'Interessenten: ' . $wartende . '
' + . 'Dosen pro Flasche: ' . $dosen . '

' + . '

' . htmlspecialchars($thresholdText, ENT_QUOTES, 'UTF-8') . '

'; + + if (!SendMailMessage($pdo, $email, $subject, $body)) { + throw new RuntimeException('Benachrichtigungs-E-Mail konnte nicht versendet werden.'); + } + + impfWorkflowNotificationSetMeta($pdo, $stateKey, '1'); + + return [[ + 'impfstoff_id' => $impfstoffId, + 'zeitraum_id' => $zeitraumId, + 'email' => $email, + 'impfstoff' => $impfstoffName, + 'zeitraum' => $zeitraumLabel, + 'wartende' => $wartende, + 'dosen' => $dosen, + ]]; + } +} + +if (!function_exists('impfWorkflowNotificationProcess')) { + function impfWorkflowNotificationProcess(PDO $pdo, int $impfstoffId = 0, array $zeitraumIds = []): array + { + if (!function_exists('impfGetZeitraeumeByImpfstoff') || !function_exists('impfLoadZeitraumById')) { + return []; + } + + $zeitraumIds = array_values(array_unique(array_filter(array_map('intval', $zeitraumIds), static function (int $zeitraumId): bool { + return $zeitraumId > 0; + }))); + + $sql = "SELECT r.impfstoff_id, r.dosen_pro_flasche, i.impfname + FROM impfstoff_workflow r + INNER JOIN impfstoff i ON i.impfid = r.impfstoff_id + WHERE (i.aktiv = 1 OR i.aktivwarteliste = 1 OR i.aktivtermin = 1 OR i.aktivgrippe = 1)"; + $params = []; + if ($impfstoffId > 0) { + $sql .= " AND r.impfstoff_id = :iid"; + $params['iid'] = $impfstoffId; + } + $sql .= " ORDER BY i.impfname"; + + $stRules = $pdo->prepare($sql); + $stRules->execute($params); + $rules = $stRules->fetchAll(PDO::FETCH_ASSOC); + if (empty($rules)) { + return []; + } + + $zeitraeumeByImpfstoff = impfGetZeitraeumeByImpfstoff($pdo, true); + $sent = []; + + foreach ($rules as $rule) { + $currentImpfstoffId = (int)$rule['impfstoff_id']; + $dosen = (int)$rule['dosen_pro_flasche']; + if ($currentImpfstoffId <= 0 || $dosen <= 0 || empty($zeitraeumeByImpfstoff[$currentImpfstoffId])) { + continue; + } + + foreach ($zeitraeumeByImpfstoff[$currentImpfstoffId] as $zeitraum) { + $currentZeitraumId = (int)($zeitraum['zeitraum_id'] ?? 0); + if ($currentZeitraumId <= 0) { + continue; + } + if (!empty($zeitraumIds) && !in_array($currentZeitraumId, $zeitraumIds, true)) { + continue; + } + + $wartende = impfWorkflowNotificationCountWaitersForPlan($pdo, $currentImpfstoffId, $currentZeitraumId); + $sent = array_merge( + $sent, + impfWorkflowNotificationSendForPlan( + $pdo, + $currentImpfstoffId, + (string)$rule['impfname'], + $currentZeitraumId, + (string)($zeitraum['label'] ?? ''), + $wartende, + $dosen + ) + ); + } + } + + return $sent; + } +} diff --git a/intern/impfwarteliste.php b/intern/impfwarteliste.php index 11516ee..bb0c762 100644 --- a/intern/impfwarteliste.php +++ b/intern/impfwarteliste.php @@ -3,6 +3,7 @@ require_once(__DIR__ . "/../inc/config.inc.php"); require_once(__DIR__ . "/../inc/functions.inc.php"); require_once(__DIR__ . "/../inc/functions.impfen.inc.php"); +require_once(__DIR__ . "/../inc/impfworkflow_notifications.inc.php"); ini_set('display_errors', '1'); error_reporting(E_ALL); @@ -66,7 +67,7 @@ $zeitOptionenJson = json_encode($zeitOptionenByImpfstoff, JSON_UNESCAPED_UNICODE $form = [ 'impfstoff_id' => (int)($_POST['impfstoff_id'] ?? 0), - 'zeitraum_id' => (int)($_POST['zeitraum_id'] ?? 0), + 'zeitraum_ids' => impfNormalizeZeitraumIds($_POST['zeitraum_ids'] ?? ($_POST['zeitraum_id'] ?? [])), 'impfart' => (int)($_POST['impfart'] ?? 0), 'letzteimpfung' => trim((string)($_POST['letzteimpfung'] ?? '')), ]; @@ -82,6 +83,10 @@ $stActive = $pdo->prepare("SELECT w.warteid, w.checked, w.impfart, w.letzteimpfu ORDER BY w.date_created DESC, w.warteid DESC"); $stActive->execute(['pid' => $personId]); $activeWaitRows = $stActive->fetchAll(PDO::FETCH_ASSOC); +foreach ($activeWaitRows as &$activeWaitRow) { + $activeWaitRow['zeitfenster_labels'] = impfGetWartelistenZeitraeumeLabels($pdo, (int)$activeWaitRow['warteid'], false); +} +unset($activeWaitRow); if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && (string)($_POST['aktion'] ?? '') === 'create_waitlist') { try { @@ -89,7 +94,7 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && (string)($_POST['aktion' $pdo, $personId, (int)$form['impfstoff_id'], - (int)$form['zeitraum_id'], + $form['zeitraum_ids'], (int)$form['impfart'], $form['letzteimpfung'] !== '' ? $form['letzteimpfung'] : null, 1 @@ -106,6 +111,13 @@ if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && (string)($_POST['aktion' $stActive->execute(['pid' => $personId]); $activeWaitRows = $stActive->fetchAll(PDO::FETCH_ASSOC); + foreach ($activeWaitRows as &$activeWaitRow) { + $activeWaitRow['zeitfenster_labels'] = impfGetWartelistenZeitraeumeLabels($pdo, (int)$activeWaitRow['warteid'], false); + } + unset($activeWaitRow); + if (isset($pdo) && $pdo instanceof PDO) { + impfWorkflowNotificationProcess($pdo); + } } else { $errorMessage = (string)$message; } @@ -141,12 +153,17 @@ if (!empty($activeWaitRows)) { echo "Sie koennen im internen Bereich mehrere verschiedene Wartelistenanfragen anlegen. Exakte Duplikate werden weiterhin geblockt."; echo "
"; echo ""; - echo ""; + echo ""; foreach ($activeWaitRows as $activeWaitRow) { $statusText = ((int)$activeWaitRow['checked'] === 1) ? 'Bestaetigt' : 'Unbestaetigt'; + $zeitfensterText = !empty($activeWaitRow['zeitfenster_labels']) + ? implode('
', array_map(static function (string $label): string { + return e($label); + }, $activeWaitRow['zeitfenster_labels'])) + : e((string)($activeWaitRow['impfenzeitraum'] ?? '')); echo ""; echo ""; - echo ""; + echo ""; echo ""; echo ""; echo ""; @@ -178,8 +195,8 @@ if (empty($verfuegbareImpfstoffe)) {
- -
@@ -215,11 +232,11 @@ if (empty($verfuegbareImpfstoffe)) {
ImpfstoffZeitraumImpfungsartStatusLetzte Impfung
ImpfstoffZeitraeumeImpfungsartStatusLetzte Impfung
" . e((string)($activeWaitRow['impfname'] ?? 'Unbekannt')) . "" . e((string)($activeWaitRow['impfenzeitraum'] ?? '')) . "" . $zeitfensterText . "" . e((string)($impfartLabels[(int)$activeWaitRow['impfart']] ?? ('Status ' . (int)$activeWaitRow['impfart']))) . "" . e($statusText) . "" . e((string)($activeWaitRow['letzteimpfung'] ?? '')) . "