#19 - Merge timetable reservations #21
@@ -27,6 +27,9 @@ class RsvReservationService {
|
||||
}
|
||||
|
||||
public function create(RsvReservation $reservation) {
|
||||
$reservation->timetable_reservations =
|
||||
$this->merge_adjacent($reservation->timetable_reservations);
|
||||
|
||||
// Serialise the availability-check + insert per timetable so two
|
||||
// concurrent bookings for the last free slot can't both pass the
|
||||
// capacity check and oversell. Locks are taken in a stable order to
|
||||
@@ -80,6 +83,48 @@ class RsvReservationService {
|
||||
return Db::prefix() . 'rsv_booking_' . $timetable_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse runs of touching reservations into single spans, so a sequence
|
||||
* of back-to-back blocks is stored and notified as one booking.
|
||||
*
|
||||
* @param list<RsvTimetableReservation> $timetable_reservations
|
||||
* @return list<RsvTimetableReservation>
|
||||
*/
|
||||
private function merge_adjacent(array $timetable_reservations): array {
|
||||
$by_timetable = [];
|
||||
foreach ($timetable_reservations as $tr) {
|
||||
$by_timetable[$tr->timetable_id][] = $tr;
|
||||
}
|
||||
|
||||
$merged = [];
|
||||
foreach ($by_timetable as $group) {
|
||||
usort($group, fn($a, $b) => $a->start_utc <=> $b->start_utc);
|
||||
|
||||
$current = null;
|
||||
foreach ($group as $tr) {
|
||||
if ($current !== null && $tr->start_utc <= $current->end_utc) {
|
||||
if ($tr->end_utc > $current->end_utc) {
|
||||
$current->end_utc = $tr->end_utc;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($current !== null) {
|
||||
$merged[] = $current;
|
||||
}
|
||||
$current = new RsvTimetableReservation(
|
||||
null, $tr->timetable_id, $tr->start_utc, $tr->end_utc
|
||||
);
|
||||
}
|
||||
|
||||
if ($current !== null) {
|
||||
$merged[] = $current;
|
||||
}
|
||||
}
|
||||
|
||||
return $merged;
|
||||
}
|
||||
|
||||
/** Delete a reservation and its dependent timetable reservations and confirmations. */
|
||||
public function delete(int $id): void {
|
||||
$this->repo->delete($id);
|
||||
|
||||
Reference in New Issue
Block a user