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 {