feat: add a booking event history for admins

This commit is contained in:
Admin authored and Björn Fromme committed 2026-10-29 12:59:36 +01:00
1 parent d68b6b156c
commit 0ab39d810b
18 files changed
+1578 -6

No files matched your search

+112
View File
@@ -5,10 +5,12 @@ declare(strict_types=1);
namespace App\Tests\Service;
use App\Entity\Booking;
use App\Entity\BookingEvent;
use App\Entity\BookingSeries;
use App\Entity\Resource;
use App\Entity\ResourceTypeSettings;
use App\Entity\User;
use App\Enum\BookingEventType;
use App\Enum\RecurrenceRule;
use App\Enum\ResourceType;
use App\Exception\ResourceAlreadyBookedException;
@@ -368,6 +370,99 @@ class BookingManagerTest extends KernelTestCase
self::assertEmailCount(1);
}
public function testABookingRecordsAnEvent(): void
{
$booking = $this->manager->book($this->user('[email protected]'), $this->resource('D1'), $this->date(), TimeRange::fromMinutes(540, 780));
$event = $this->onlyEvent();
self::assertSame(BookingEventType::BOOKING_CREATED, $event->getType());
self::assertSame($booking->getId(), $event->getBookingId());
self::assertSame('D1', $event->getResourceLabel());
self::assertSame('Test', $event->getHolderName());
self::assertSame('2026-10-01', $event->getDate()?->format('Y-m-d'));
self::assertSame('09:00–13:00', (string) $event->getTimeRange());
// No token in a kernel test, as for a console command.
self::assertNull($event->getActor());
self::assertSame(BookingEvent::SYSTEM_ACTOR, $event->getActorName());
}
/**
* The event is written in the booking's transaction, so a refusal leaves nothing behind.
*/
public function testARefusedBookingRecordsNoEvent(): void
{
$desk = $this->resource('D1');
$this->manager->book($this->user('[email protected]'), $desk, $this->date());
try {
$this->manager->book($this->user('[email protected]'), $desk, $this->date());
self::fail('The second booking should have been refused.');
} catch (ResourceAlreadyBookedException) {
}
self::assertSame(1, $this->em->getRepository(BookingEvent::class)->count([]));
}
public function testReschedulingRecordsTheOldAndTheNewTimes(): void
{
$booking = $this->manager->book($this->user('[email protected]'), $this->resource('D1'), $this->date(), TimeRange::fromMinutes(540, 780));
$this->manager->reschedule($booking, TimeRange::fromMinutes(600, 720));
$event = $this->latestEvent();
self::assertSame(BookingEventType::BOOKING_RESCHEDULED, $event->getType());
self::assertSame('09:00–13:00', (string) $event->getPreviousTimeRange());
self::assertSame('10:00–12:00', (string) $event->getTimeRange());
}
public function testReleasingRecordsTheBookingThatWent(): void
{
$booking = $this->manager->book($this->user('[email protected]'), $this->resource('D1'), $this->date());
$id = $booking->getId();
$this->manager->release($booking);
$event = $this->latestEvent();
self::assertSame(BookingEventType::BOOKING_RELEASED, $event->getType());
self::assertSame($id, $event->getBookingId());
self::assertSame('D1', $event->getResourceLabel());
}
/**
* One event for the series, not one per day -- the same rule as the audit log.
*/
public function testASeriesRecordsOneEvent(): void
{
$series = $this->weeklySeries();
$this->manager->bookSeries($series);
$event = $this->onlyEvent();
self::assertSame(BookingEventType::SERIES_CREATED, $event->getType());
self::assertSame($series->getId(), $event->getSeriesId());
self::assertSame(RecurrenceRule::WEEKLY, $event->getRule());
self::assertSame(4, $event->getDetails()['created']);
self::assertSame('2026-10-30', $event->getEndDate()?->format('Y-m-d'));
}
/**
* Ending a series that has nothing left deletes it, so the id has to survive from before.
*/
public function testEndingASeriesRecordsItsIdEvenWhenTheSeriesIsGone(): void
{
$series = $this->weeklySeries();
$this->manager->bookSeries($series);
$id = $series->getId();
$this->manager->endSeries($series, new \DateTimeImmutable('2026-10-05'));
$event = $this->latestEvent();
self::assertSame(BookingEventType::SERIES_ENDED, $event->getType());
self::assertSame($id, $event->getSeriesId());
self::assertSame(4, $event->getDetails()['removed']);
self::assertSame('2026-10-05', $event->getDate()?->format('Y-m-d'));
}
/**
* @param list<string> $recipients
*/
@@ -415,9 +510,26 @@ class BookingManagerTest extends KernelTestCase
return $resource;
}
private function onlyEvent(): BookingEvent
{
$events = $this->em->getRepository(BookingEvent::class)->findAll();
self::assertCount(1, $events);
return $events[0];
}
private function latestEvent(): BookingEvent
{
$event = $this->em->getRepository(BookingEvent::class)->findOneBy([], ['id' => 'DESC']);
self::assertInstanceOf(BookingEvent::class, $event);
return $event;
}
private function wipe(): void
{
$connection = $this->em->getConnection();
$connection->executeStatement('DELETE FROM booking_event');
$connection->executeStatement('DELETE FROM booking');
$connection->executeStatement('DELETE FROM booking_series');
$connection->executeStatement('DELETE FROM resource');