prepare("SHOW TABLES LIKE :table"); $st->execute(['table' => $table]); return (bool)$st->fetchColumn(); } } if (!function_exists('impfTableHasColumn')) { function impfTableHasColumn(PDO $pdo, string $table, string $column): bool { static $cache = []; $cacheKey = $table . '.' . $column; if (array_key_exists($cacheKey, $cache)) { return $cache[$cacheKey]; } $st = $pdo->prepare("SHOW COLUMNS FROM `" . $table . "` LIKE :column"); $st->execute(['column' => $column]); $cache[$cacheKey] = (bool)$st->fetch(PDO::FETCH_ASSOC); return $cache[$cacheKey]; } } if (!function_exists('impfTableHasIndex')) { function impfTableHasIndex(PDO $pdo, string $table, string $index): bool { $st = $pdo->prepare("SHOW INDEX FROM `" . $table . "` WHERE Key_name = :index_name"); $st->execute(['index_name' => $index]); return (bool)$st->fetch(PDO::FETCH_ASSOC); } } 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 { $map = [ 1 => 'Montag', 2 => 'Dienstag', 3 => 'Mittwoch', 4 => 'Donnerstag', 5 => 'Freitag', 6 => 'Samstag', 7 => 'Sonntag', ]; return $map[$day] ?? 'Unbekannt'; } } if (!function_exists('impfLimitLabelLength')) { function impfLimitLabelLength(string $text, int $maxLength = 50): string { $text = trim($text); if ($text === '') { return $text; } if (function_exists('mb_strimwidth')) { return rtrim(mb_strimwidth($text, 0, $maxLength, '...', 'UTF-8')); } if (strlen($text) <= $maxLength) { return $text; } return rtrim(substr($text, 0, max(0, $maxLength - 3))) . '...'; } } if (!function_exists('impfWorkflowEnsureTables')) { function impfWorkflowEnsureTables(PDO $pdo): void { 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"); 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"); impfEnsureTable($pdo, 'impfstoff_wochenplan', "CREATE TABLE impfstoff_wochenplan ( plan_id INT NOT NULL AUTO_INCREMENT, impfstoff_id INT NOT NULL, wochentag TINYINT NOT NULL, start TIME NOT NULL, ende TIME NOT NULL, impfortid INT NOT NULL, aktiv TINYINT NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (plan_id), INDEX idx_impfstoff_wochenplan_impfstoff (impfstoff_id), INDEX idx_impfstoff_wochenplan_wochentag (wochentag) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3"); 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, start TIME NOT NULL, ende TIME NOT NULL, impfortid INT NOT NULL, aktiv TINYINT NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (zeitraum_id), INDEX idx_impf_zeitraum_wochentag (wochentag), INDEX idx_impf_zeitraum_impfort (impfortid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3"); if (!impfTableHasColumn($pdo, 'impf_zeitraum', 'bezeichnung')) { $pdo->exec("ALTER TABLE impf_zeitraum ADD COLUMN bezeichnung VARCHAR(120) NOT NULL DEFAULT '' AFTER zeitraum_id"); } 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, PRIMARY KEY (zeitraum_id, impfstoff_id), 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"); } if (impfTableExists($pdo, 'warteliste') && !impfTableHasIndex($pdo, 'warteliste', 'idx_warteliste_zeitraum')) { $pdo->exec("ALTER TABLE warteliste ADD INDEX idx_warteliste_zeitraum (zeitraum_id)"); } impfWorkflowMigrateLegacyPlans($pdo); impfWorkflowMigrateLegacyWartelisteZeitraeume($pdo); } } if (!function_exists('impfWorkflowGetMeta')) { function impfWorkflowGetMeta(PDO $pdo, string $key): ?string { $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('impfWorkflowSetMeta')) { function impfWorkflowSetMeta(PDO $pdo, string $key, string $value): void { $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('impfWorkflowMigrateLegacyPlans')) { function impfWorkflowMigrateLegacyPlans(PDO $pdo): void { if (impfWorkflowGetMeta($pdo, 'legacy_wochenplan_migrated') === '1') { return; } if (!impfTableExists($pdo, 'impfstoff_wochenplan')) { return; } $stLegacy = $pdo->query("SELECT plan_id, impfstoff_id, wochentag, start, ende, impfortid, aktiv FROM impfstoff_wochenplan"); $legacyRows = $stLegacy ? $stLegacy->fetchAll(PDO::FETCH_ASSOC) : []; if (empty($legacyRows)) { impfWorkflowSetMeta($pdo, 'legacy_wochenplan_migrated', '1'); return; } $manageTransaction = !$pdo->inTransaction(); if ($manageTransaction) { $pdo->beginTransaction(); } try { $stFindZeitraum = $pdo->prepare("SELECT zeitraum_id FROM impf_zeitraum WHERE wochentag = :wochentag AND start = :start AND ende = :ende AND impfortid = :impfortid AND aktiv = :aktiv LIMIT 1"); $stInsertZeitraum = $pdo->prepare("INSERT INTO impf_zeitraum (bezeichnung, wochentag, start, ende, impfortid, aktiv) VALUES ('', :wochentag, :start, :ende, :impfortid, :aktiv)"); $stInsertMap = $pdo->prepare("INSERT INTO impf_zeitraum_impfstoff (zeitraum_id, impfstoff_id) VALUES (:zeitraum_id, :impfstoff_id) ON DUPLICATE KEY UPDATE impfstoff_id = VALUES(impfstoff_id)"); foreach ($legacyRows as $row) { $params = [ 'wochentag' => (int)$row['wochentag'], 'start' => (string)$row['start'], 'ende' => (string)$row['ende'], 'impfortid' => (int)$row['impfortid'], 'aktiv' => (int)$row['aktiv'], ]; $stFindZeitraum->execute($params); $zeitraumId = (int)($stFindZeitraum->fetchColumn() ?: 0); if ($zeitraumId <= 0) { $stInsertZeitraum->execute($params); $zeitraumId = (int)$pdo->lastInsertId(); } if ($zeitraumId > 0 && (int)$row['impfstoff_id'] > 0) { $stInsertMap->execute([ 'zeitraum_id' => $zeitraumId, 'impfstoff_id' => (int)$row['impfstoff_id'], ]); } } impfWorkflowSetMeta($pdo, 'legacy_wochenplan_migrated', '1'); if ($manageTransaction) { $pdo->commit(); } } catch (Throwable $e) { if ($manageTransaction && $pdo->inTransaction()) { $pdo->rollBack(); } throw $e; } } } 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 { if ($csv === null || trim($csv) === '') { return []; } $werte = array_filter(array_map('trim', explode(',', $csv)), static function ($wert): bool { return $wert !== ''; }); return array_values(array_map('intval', $werte)); } } if (!function_exists('impfZeitraumLabel')) { 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'] ?? '')); $ortText = trim($ort, " -"); if ($ortText !== '') { $zeitText .= ' (' . $ortText . ')'; } return impfLimitLabelLength($zeitText, 50); } } if (!function_exists('impfGetZeitraumRows')) { function impfGetZeitraumRows(PDO $pdo, bool $onlyActive = true): array { $sql = "SELECT z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, o.anzeigename, o.adresse, GROUP_CONCAT(DISTINCT m.impfstoff_id ORDER BY m.impfstoff_id SEPARATOR ',') AS impfstoff_ids, GROUP_CONCAT(DISTINCT i.impfname ORDER BY i.impfname SEPARATOR '||') AS impfstoff_namen FROM impf_zeitraum z LEFT JOIN impfort o ON o.ortid = z.impfortid LEFT JOIN impf_zeitraum_impfstoff m ON m.zeitraum_id = z.zeitraum_id LEFT JOIN impfstoff i ON i.impfid = m.impfstoff_id"; if ($onlyActive) { $sql .= " WHERE z.aktiv = 1"; } $sql .= " GROUP BY z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, o.anzeigename, o.adresse ORDER BY z.wochentag, z.start, z.ende, z.bezeichnung, z.zeitraum_id"; $st = $pdo->prepare($sql); $st->execute(); $rows = $st->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as &$row) { $row['impfstoff_id_list'] = impfCsvToIntList($row['impfstoff_ids'] ?? null); $row['impfstoff_name_list'] = []; if (!empty($row['impfstoff_namen'])) { $row['impfstoff_name_list'] = array_values(array_filter(explode('||', (string)$row['impfstoff_namen']), static function ($name): bool { return trim((string)$name) !== ''; })); } $row['label'] = impfZeitraumLabel($row); } unset($row); return $rows; } } if (!function_exists('impfLoadZeitraumById')) { function impfLoadZeitraumById(PDO $pdo, int $zeitraumId, bool $onlyActive = true): ?array { if ($zeitraumId <= 0) { return null; } $sql = "SELECT z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, o.anzeigename, o.adresse, GROUP_CONCAT(DISTINCT m.impfstoff_id ORDER BY m.impfstoff_id SEPARATOR ',') AS impfstoff_ids, GROUP_CONCAT(DISTINCT i.impfname ORDER BY i.impfname SEPARATOR '||') AS impfstoff_namen FROM impf_zeitraum z LEFT JOIN impfort o ON o.ortid = z.impfortid LEFT JOIN impf_zeitraum_impfstoff m ON m.zeitraum_id = z.zeitraum_id LEFT JOIN impfstoff i ON i.impfid = m.impfstoff_id WHERE z.zeitraum_id = :zeitraum_id"; if ($onlyActive) { $sql .= " AND z.aktiv = 1"; } $sql .= " GROUP BY z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, o.anzeigename, o.adresse LIMIT 1"; $st = $pdo->prepare($sql); $st->execute(['zeitraum_id' => $zeitraumId]); $row = $st->fetch(PDO::FETCH_ASSOC); if (!$row) { return null; } $row['impfstoff_id_list'] = impfCsvToIntList($row['impfstoff_ids'] ?? null); $row['impfstoff_name_list'] = []; if (!empty($row['impfstoff_namen'])) { $row['impfstoff_name_list'] = array_values(array_filter(explode('||', (string)$row['impfstoff_namen']), static function ($name): bool { return trim((string)$name) !== ''; })); } $row['label'] = impfZeitraumLabel($row); return $row; } } if (!function_exists('impfGetZeitraeumeByImpfstoff')) { function impfGetZeitraeumeByImpfstoff(PDO $pdo, bool $onlyActive = true): array { $zeitraeume = impfGetZeitraumRows($pdo, $onlyActive); $result = []; foreach ($zeitraeume as $zeitraum) { foreach ($zeitraum['impfstoff_id_list'] as $impfstoffId) { if (!isset($result[$impfstoffId])) { $result[$impfstoffId] = []; } $result[$impfstoffId][] = $zeitraum; } } return $result; } } if (!function_exists('impfGetWartelistenFormOptions')) { function impfGetWartelistenFormOptions(PDO $pdo): array { $impfstoffe = []; $zeitfenster = []; $stImpfstoffe = $pdo->prepare("SELECT r.impfstoff_id, 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) AND r.dosen_pro_flasche > 0 ORDER BY i.impfname"); $stImpfstoffe->execute(); foreach ($stImpfstoffe->fetchAll(PDO::FETCH_ASSOC) as $row) { $impfstoffe[(int)$row['impfstoff_id']] = (string)$row['impfname']; } $zeitraeumeByImpfstoff = impfGetZeitraeumeByImpfstoff($pdo, true); foreach ($zeitraeumeByImpfstoff as $impfstoffId => $zeitraeume) { if (!isset($impfstoffe[$impfstoffId])) { continue; } foreach ($zeitraeume as $zeitraum) { if (!isset($zeitfenster[$impfstoffId])) { $zeitfenster[$impfstoffId] = []; } $zeitfenster[$impfstoffId][] = [ 'id' => (int)$zeitraum['zeitraum_id'], 'label' => impfZeitraumLabel($zeitraum, false), ]; } } foreach (array_keys($impfstoffe) as $impfstoffId) { if (empty($zeitfenster[$impfstoffId])) { unset($impfstoffe[$impfstoffId]); } } return [ 'impfstoffe' => $impfstoffe, 'zeitfenster' => $zeitfenster, ]; } } 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('impfGetWartelistenZeitraeumeLabelsMap')) { function impfGetWartelistenZeitraeumeLabelsMap(PDO $pdo, array $warteids, bool $onlyActive = false): array { $warteids = array_values(array_unique(array_filter(array_map('intval', $warteids), static function (int $warteid): bool { return $warteid > 0; }))); if (empty($warteids) || !impfTableExists($pdo, 'warteliste_zeitraum')) { return []; } $result = []; foreach ($warteids as $warteid) { $result[$warteid] = []; } $placeholders = []; $params = []; foreach ($warteids as $index => $warteid) { $key = 'wid' . $index; $placeholders[] = ':' . $key; $params[$key] = $warteid; } $inList = implode(', ', $placeholders); $sql = "SELECT wz.warteid, 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 IN (" . $inList . ")"; if ($onlyActive) { $sql .= " AND z.aktiv = 1"; } $sql .= " ORDER BY wz.warteid, z.wochentag, z.start, z.ende, z.bezeichnung, z.zeitraum_id"; $st = $pdo->prepare($sql); $st->execute($params); $rows = $st->fetchAll(PDO::FETCH_ASSOC); foreach ($rows as $row) { $warteid = (int)($row['warteid'] ?? 0); if ($warteid <= 0) { continue; } $row['label'] = impfZeitraumLabel($row); $result[$warteid][] = (string)$row['label']; } $missing = array_values(array_filter($warteids, static function (int $warteid) use ($result): bool { return empty($result[$warteid]); })); if (empty($missing)) { return $result; } $fallbackPlaceholders = []; $fallbackParams = []; foreach ($missing as $index => $warteid) { $key = 'f_wid' . $index; $fallbackPlaceholders[] = ':' . $key; $fallbackParams[$key] = $warteid; } $fallbackInList = implode(', ', $fallbackPlaceholders); $fallbackSql = "SELECT w.warteid, 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 IN (" . $fallbackInList . ") AND w.zeitraum_id IS NOT NULL"; if ($onlyActive) { $fallbackSql .= " AND z.aktiv = 1"; } $stFallback = $pdo->prepare($fallbackSql); $stFallback->execute($fallbackParams); $fallbackRows = $stFallback->fetchAll(PDO::FETCH_ASSOC); foreach ($fallbackRows as $row) { $warteid = (int)($row['warteid'] ?? 0); if ($warteid <= 0) { continue; } $row['label'] = impfZeitraumLabel($row); $result[$warteid] = [(string)$row['label']]; } return $result; } } 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, $zeitraumIds, int $impfart, ?string $letzteImpfung = null, int $checked = 1 ): array { if ($personId <= 0) { return [false, 'Keine gueltige Person uebergeben.', null]; } if ($impfstoffId <= 0) { return [false, 'Bitte einen Impfstoff 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; } elseif ($letzteImpfung === null || $letzteImpfung === '') { return [false, 'Bitte das Datum der letzten Impfung angeben.', null]; } elseif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $letzteImpfung)) { return [false, 'Das Datum der letzten Impfung ist ungueltig.', null]; } $stPerson = $pdo->prepare("SELECT person_id, patientenart, vorname, nachname FROM persons WHERE person_id = :pid LIMIT 1"); $stPerson->execute(['pid' => $personId]); $person = $stPerson->fetch(PDO::FETCH_ASSOC); if (!$person) { return [false, 'Die Person wurde nicht gefunden.', 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 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, 'impfart' => $impfart, ]); if ($stDup->fetchColumn()) { return [false, 'Diese Anfrage ist fuer diese Person bereits auf der aktiven Warteliste vorhanden.', null]; } $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); $manageTransaction = !$pdo->inTransaction(); if ($manageTransaction) { $pdo->beginTransaction(); } 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, ]); $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; } } }