feat: add two- and four-weekly series and drop the weekday picker

This commit is contained in:
fromme committed 2026-09-14 08:25:05 +02:00
1 parent 8b88384d68
commit faef4d70a8
10 files changed
+166 -103

No files matched your search

+55 -20
View File
@@ -101,27 +101,62 @@ class BookingManagerTest extends KernelTestCase
public function testASeriesMaterialisesOneBookingPerOccurrence(): void
{
// 2026-10-05 is a Monday.
$series = new BookingSeries(
$this->user('[email protected]'),
$this->resource('D1'),
RecurrenceRule::WEEKLY,
new \DateTimeImmutable('2026-10-05'),
new \DateTimeImmutable('2026-10-30'),
TimeRange::fromMinutes(540, 720),
[1, 4],
);
// 2026-10-05 is a Monday; the Mondays up to the 30th are the 5th, 12th, 19th and 26th.
$series = $this->weeklySeries();
$result = $this->manager->bookSeries($series);
self::assertSame(8, $result->createdCount());
self::assertSame(4, $result->createdCount());
self::assertSame(0, $result->skippedCount());
foreach ($result->created as $booking) {
self::assertContains((int) $booking->getDate()->format('N'), [1, 4]);
self::assertSame(1, (int) $booking->getDate()->format('N'));
self::assertSame($series, $booking->getSeries());
}
}
public function testATwoWeeklySeriesSkipsEveryOtherWeek(): void
{
$result = $this->manager->bookSeries(new BookingSeries(
$this->user('[email protected]'),
$this->resource('D1'),
RecurrenceRule::TWO_WEEKLY,
new \DateTimeImmutable('2026-10-05'),
new \DateTimeImmutable('2026-11-30'),
TimeRange::fromMinutes(540, 720),
));
self::assertSame(5, $result->createdCount());
self::assertSame(
['2026-10-05', '2026-10-19', '2026-11-02', '2026-11-16', '2026-11-30'],
array_map(static fn (Booking $booking): string => $booking->getDate()->format('Y-m-d'), $result->created),
);
}
/**
* The property the weekday field was removed in favour of: a stride that is a whole number of
* weeks lands on the same weekday every time, so nothing has to store which one it is. A
* four-weekly series is the one where this is easy to get wrong by reaching for months.
*/
public function testAFourWeeklySeriesAlwaysLandsOnTheSameWeekday(): void
{
$result = $this->manager->bookSeries(new BookingSeries(
$this->user('[email protected]'),
$this->resource('D1'),
RecurrenceRule::FOUR_WEEKLY,
new \DateTimeImmutable('2026-10-05'),
new \DateTimeImmutable('2026-12-31'),
TimeRange::fromMinutes(540, 720),
));
self::assertSame(4, $result->createdCount());
foreach ($result->created as $booking) {
self::assertSame(1, (int) $booking->getDate()->format('N'), 'every occurrence is a Monday');
}
// Crossing a month boundary is where a "monthly" reading would diverge: 28 days after
// 2 November is 30 November, not 2 December.
self::assertSame('2026-11-30', $result->created[2]->getDate()->format('Y-m-d'));
}
public function testADailySeriesCoversEveryDay(): void
{
$result = $this->manager->bookSeries(new BookingSeries(
@@ -142,7 +177,8 @@ class BookingManagerTest extends KernelTestCase
public function testASeriesSkipsDaysThatAreAlreadyTaken(): void
{
$desk = $this->resource('D1');
$this->manager->book($this->user('[email protected]'), $desk, new \DateTimeImmutable('2026-10-08'), TimeRange::fromMinutes(600, 660));
// The 12th is one of the series' own Mondays.
$this->manager->book($this->user('[email protected]'), $desk, new \DateTimeImmutable('2026-10-12'), TimeRange::fromMinutes(600, 660));
$result = $this->manager->bookSeries(new BookingSeries(
$this->user('[email protected]'),
@@ -151,11 +187,10 @@ class BookingManagerTest extends KernelTestCase
new \DateTimeImmutable('2026-10-05'),
new \DateTimeImmutable('2026-10-30'),
TimeRange::fromMinutes(540, 720),
[1, 4],
));
self::assertSame(7, $result->createdCount());
self::assertSame(['8.10.'], $result->skippedDates());
self::assertSame(3, $result->createdCount());
self::assertSame(['12.10.'], $result->skippedDates());
self::assertFalse($result->isCompletelyBlocked());
}
@@ -232,7 +267,7 @@ class BookingManagerTest extends KernelTestCase
$removed = $this->manager->endSeries($series, new \DateTimeImmutable('2026-10-05'));
self::assertSame(8, $removed);
self::assertSame(4, $removed);
self::assertSame([], $this->em->getRepository(Booking::class)->findBy(['series' => $id]));
// Nothing of the series is left, so the series row goes too -- note $series has no id
// any more at this point, which is why the lookup goes through the captured one.
@@ -244,10 +279,11 @@ class BookingManagerTest extends KernelTestCase
$series = $this->weeklySeries();
$this->manager->bookSeries($series);
// Leaves the Mondays on the 5th and 12th, removes the 19th and 26th.
$removed = $this->manager->endSeries($series, new \DateTimeImmutable('2026-10-15'));
self::assertSame(5, $removed);
self::assertCount(3, $this->em->getRepository(Booking::class)->findBy(['series' => $series]));
self::assertSame(2, $removed);
self::assertCount(2, $this->em->getRepository(Booking::class)->findBy(['series' => $series]));
self::assertSame('2026-10-14', $series->getEndDate()->format('Y-m-d'));
}
@@ -260,7 +296,6 @@ class BookingManagerTest extends KernelTestCase
new \DateTimeImmutable('2026-10-05'),
new \DateTimeImmutable('2026-10-30'),
TimeRange::fromMinutes(540, 720),
[1, 4],
);
}