impfwarteliste angepasst

This commit is contained in:
2026-03-23 17:14:09 +01:00
parent 70a78c9586
commit 4b4c1f74df
10 changed files with 1128 additions and 177 deletions
+155 -79
View File
@@ -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 {
<?php echo esc((string)$w['tele']); ?>
</td>
<td><?php echo esc((string)($w['impfname'] ?: 'Unbekannt')); ?></td>
<td><?php echo esc((string)$w['impfenzeitraum']); ?></td>
<td>
<?php if (!empty($w['zeitraum_labels'])): ?>
<?php echo implode('<br>', array_map('esc', $w['zeitraum_labels'])); ?>
<?php else: ?>
<?php echo esc((string)$w['impfenzeitraum']); ?>
<?php endif; ?>
</td>
<td>
<?php echo esc(workflowImpfartName((int)$w['impfart'])); ?>
<?php if (!empty($w['letzteimpfung'])): ?>
@@ -806,12 +877,12 @@ try {
</select>
<label style="margin-left:10px;">Zeitfenster</label>
<select class="form-control" name="wl_plan_id" id="existing_plan">
<option value="0" <?php echo ((int)($_POST['wl_plan_id'] ?? 0) === 0) ? 'selected' : ''; ?>>Ohne Zeitfenster</option>
<?php $selectedExistingPlanIds = impfNormalizeZeitraumIds($_POST['wl_plan_ids'] ?? ($_POST['wl_plan_id'] ?? [])); ?>
<select class="form-control" name="wl_plan_ids[]" id="existing_plan" multiple size="6">
<?php foreach ($plans as $p): ?>
<?php
$planId = (int)$p['zeitraum_id'];
$selected = ((int)($_POST['wl_plan_id'] ?? 0) === $planId) ? 'selected' : '';
$selected = in_array($planId, $selectedExistingPlanIds, true) ? 'selected' : '';
$impfstoffeCsv = implode(',', $p['impfstoff_id_list']);
$impfstoffeText = empty($p['impfstoff_name_list']) ? 'ohne Impfstoff' : implode(', ', $p['impfstoff_name_list']);
?>
@@ -897,12 +968,12 @@ try {
</div>
<div class="col-sm-3">
<label>Zeitfenster</label>
<select class="form-control" name="new_plan_id" id="new_plan">
<option value="0" <?php echo ((int)($_POST['new_plan_id'] ?? 0) === 0) ? 'selected' : ''; ?>>Ohne Zeitfenster</option>
<?php $selectedNewPlanIds = impfNormalizeZeitraumIds($_POST['new_plan_ids'] ?? ($_POST['new_plan_id'] ?? [])); ?>
<select class="form-control" name="new_plan_ids[]" id="new_plan" multiple size="6">
<?php foreach ($plans as $p): ?>
<?php
$planId = (int)$p['zeitraum_id'];
$selected = ((int)($_POST['new_plan_id'] ?? 0) === $planId) ? 'selected' : '';
$selected = in_array($planId, $selectedNewPlanIds, true) ? 'selected' : '';
$impfstoffeCsv = implode(',', $p['impfstoff_id_list']);
$impfstoffeText = empty($p['impfstoff_name_list']) ? 'ohne Impfstoff' : implode(', ', $p['impfstoff_name_list']);
?>
@@ -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 = '';
}
}