Initial CAT application and deployment update

This commit is contained in:
2026-09-19 23:27:40 +00:00
commit 6684062400
22 changed files with 3690 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
function loadRoomPlanningSettings(PDO $pdo): array
{
$defaults = [
'single' => 0,
'double' => 0,
'multi' => 0,
];
$statement = $pdo->query(
"SELECT setting_key, price FROM pricing_settings
WHERE setting_key IN ('room_count_single', 'room_count_double', 'room_count_multi')"
);
foreach ($statement->fetchAll(PDO::FETCH_KEY_PAIR) as $key => $value) {
$type = str_replace('room_count_', '', (string) $key);
if (array_key_exists($type, $defaults)) {
$defaults[$type] = max(0, (int) $value);
}
}
return $defaults;
}
function normalizedRoommateName(string $name): string
{
return mb_strtolower(preg_replace('/\\s+/u', ' ', trim($name)) ?? '', 'UTF-8');
}
function buildRoomPlan(array $participants, array $roomCounts): array
{
$rooms = [];
$warnings = [];
$unassigned = [];
$available = [
'single' => max(0, (int) ($roomCounts['single'] ?? 0)),
'double' => max(0, (int) ($roomCounts['double'] ?? 0)),
'multi' => max(0, (int) ($roomCounts['multi'] ?? 0)),
];
$roomNumber = ['single' => 0, 'double' => 0, 'multi' => 0];
$assigned = [];
$blocked = [];
$byName = [];
foreach ($participants as &$participant) {
$participant['roommate_key'] = normalizedRoommateName((string) ($participant['roommate_requests'] ?? ''));
$participant['name_key'] = normalizedRoommateName((string) $participant['name']);
$byName[$participant['name_key']][] = $participant;
}
unset($participant);
$addRoom = static function (string $type, array $members) use (&$rooms, &$roomNumber, &$available, &$assigned): bool {
if (($available[$type] ?? 0) < 1) {
return false;
}
$roomNumber[$type]++;
$capacity = $type === 'single' ? 1 : ($type === 'double' ? 2 : 4);
$rooms[] = [
'type' => $type,
'number' => $roomNumber[$type],
'capacity' => $capacity,
'members' => $members,
];
$available[$type]--;
foreach ($members as $member) {
$assigned[(string) $member['id']] = true;
}
return true;
};
// Mutual wishes are handled first, but only when both participants requested the same room type.
foreach ($participants as $participant) {
$id = (string) $participant['id'];
if (isset($assigned[$id]) || $participant['roommate_key'] === '') {
continue;
}
foreach ($byName[$participant['roommate_key']] ?? [] as $requested) {
$requestedId = (string) $requested['id'];
if ($requestedId === $id || isset($assigned[$requestedId])) {
continue;
}
$mutual = $requested['roommate_key'] === $participant['name_key'];
$sameType = $requested['room_type'] === $participant['room_type'];
if (!$mutual || !$sameType) {
continue;
}
if (!$addRoom((string) $participant['room_type'], [$participant, $requested])) {
$warnings[] = sprintf(
'Der gegenseitige Zimmerwunsch von %s und %s konnte nicht erfüllt werden: kein %s-Zimmer verfügbar.',
$participant['name'],
$requested['name'],
$participant['room_type'] === 'double' ? 'Doppel' : 'Mehrbett'
);
$unassigned[$id] = $participant;
$unassigned[$requestedId] = $requested;
$blocked[$id] = true;
$blocked[$requestedId] = true;
}
break;
}
}
foreach (['single', 'double', 'multi'] as $type) {
$waiting = [];
foreach ($participants as $participant) {
$id = (string) $participant['id'];
if (!isset($assigned[$id]) && !isset($blocked[$id]) && $participant['room_type'] === $type) {
$waiting[] = $participant;
}
}
$capacity = $type === 'single' ? 1 : ($type === 'double' ? 2 : 4);
while ($waiting !== []) {
$group = array_splice($waiting, 0, $capacity);
if (!$addRoom($type, $group)) {
foreach ($group as $participant) {
$unassigned[(string) $participant['id']] = $participant;
}
$warnings[] = sprintf(
'%d Teilnehmer mit Wunsch %s konnten keinem verfügbaren Zimmer zugeordnet werden.',
count($group),
$type === 'single' ? 'Einzelzimmer' : ($type === 'double' ? 'Doppelzimmer' : 'Mehrbettzimmer')
);
}
}
}
foreach ($unassigned as $participant) {
$warnings[] = sprintf('Nicht eingeplant: %s (%s).', $participant['name'], $participant['email']);
}
return [
'rooms' => $rooms,
'warnings' => array_values(array_unique($warnings)),
'unassigned' => array_values($unassigned),
'available' => $available,
];
}