Backup: old custom PHP API code removed from fahrschultermin.de

This commit is contained in:
Hermes Agent
2026-05-20 16:36:12 +02:00
parent 8ab4e532fd
commit 8fccf0e406
59 changed files with 5146 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Repositories\AppointmentRepository;
use App\Repositories\ReferenceDataRepository;
use DateInterval;
use DateTimeImmutable;
final class CalendarService
{
public function validate(int $tenantId, array $payload, ?int $appointmentId = null): array
{
$appointmentRepository = new AppointmentRepository();
$lessonType = (new ReferenceDataRepository())->findLessonType($tenantId, (int) $payload['lesson_type_id']);
$warnings = [
'conflicts' => [],
'rest_period_warnings' => [],
];
$conflicts = $appointmentRepository->overlappingForInstructor(
$tenantId,
(int) $payload['instructor_id'],
$payload['start_at'],
$payload['end_at'],
$appointmentId
);
foreach ($conflicts as $conflict) {
$warnings['conflicts'][] = [
'type' => 'instructor_overlap',
'message' => 'Fahrlehrer ist in diesem Zeitraum bereits verplant.',
'appointment_id' => (int) $conflict['id'],
];
}
if (!empty($payload['student_id'])) {
$studentConflicts = $appointmentRepository->overlappingForStudent(
$tenantId,
(int) $payload['student_id'],
$payload['start_at'],
$payload['end_at'],
$appointmentId
);
foreach ($studentConflicts as $conflict) {
$warnings['conflicts'][] = [
'type' => 'student_overlap',
'message' => 'Fahrschueler ist in diesem Zeitraum bereits verplant.',
'appointment_id' => (int) $conflict['id'],
];
}
}
if ($lessonType !== null && (int) $lessonType['is_rest_relevant'] === 1) {
$newStart = new DateTimeImmutable($payload['start_at']);
$dayStart = $newStart->setTime(0, 0, 0);
$dayEnd = $dayStart->modify('+1 day');
$hasLaterRelevantOnDay = $appointmentRepository->hasRestRelevantAfterStartOnDay(
$tenantId,
(int) $payload['instructor_id'],
$dayStart->format(DATE_ATOM),
$dayEnd->format(DATE_ATOM),
$payload['start_at']
);
if ($hasLaterRelevantOnDay) {
return $warnings;
}
$lastRelevant = $appointmentRepository->lastRestRelevantForInstructor(
$tenantId,
(int) $payload['instructor_id'],
$payload['start_at'],
$appointmentId
);
if ($lastRelevant !== null) {
$restEnds = (new DateTimeImmutable($lastRelevant['end_at']))->add(new DateInterval('PT11H'));
if ($newStart < $restEnds) {
$warnings['rest_period_warnings'][] = [
'type' => 'rest_period',
'message' => 'Achtung: Dieser Termin liegt innerhalb der 11-Stunden-Ruhezeit.',
'rest_until' => $restEnds->format(DATE_ATOM),
'blocking_appointment_id' => (int) $lastRelevant['id'],
];
}
}
}
return $warnings;
}
}