feat: notify configured recipients when something is booked

This commit is contained in:
fromme committed 2026-09-28 16:40:56 +02:00
1 parent be37fc81f6
commit d287cb2600
23 files changed
+1014 -1

No files matched your search

+88
View File
@@ -7,6 +7,7 @@ namespace App\Tests\Service;
use App\Entity\Booking;
use App\Entity\BookingSeries;
use App\Entity\Resource;
use App\Entity\ResourceTypeSettings;
use App\Entity\User;
use App\Enum\RecurrenceRule;
use App\Enum\ResourceType;
@@ -15,6 +16,7 @@ use App\Model\TimeRange;
use App\Service\BookingManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Bundle\FrameworkBundle\Test\MailerAssertionsTrait;
/**
* The double-booking guard now lives here rather than in a unique index, so this is where it is
@@ -24,6 +26,8 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
*/
class BookingManagerTest extends KernelTestCase
{
use MailerAssertionsTrait;
private EntityManagerInterface $em;
private BookingManager $manager;
@@ -292,6 +296,89 @@ class BookingManagerTest extends KernelTestCase
self::assertSame('2026-10-14', $series->getEndDate()->format('Y-m-d'));
}
public function testABookingNotifiesTheRecipientsOfItsType(): void
{
$this->recipientsFor(ResourceType::DESK, ['[email protected]', '[email protected]']);
$this->manager->book($this->user('[email protected]'), $this->resource('D1'), $this->date(), TimeRange::fromMinutes(540, 780));
// One mail each, addressed to them alone: no recipient learns who else is on the list.
self::assertEmailCount(2);
$emails = self::getMailerMessages();
self::assertSame(
['[email protected]', '[email protected]'],
array_map(static fn ($email): string => $email->getTo()[0]->getAddress(), $emails),
);
foreach ($emails as $email) {
self::assertCount(1, $email->getTo());
self::assertSame([], $email->getBcc());
self::assertSame('Neue Buchung: D1 am 01.10.2026', $email->getSubject());
self::assertStringContainsString('D1', $email->getTextBody());
// Both parts render: the MyE&P layout, and the text fallback beside it.
self::assertStringContainsString('D1', $email->getHtmlBody());
self::assertStringContainsString('Neue Buchung', $email->getHtmlBody());
// The logo resolved through the @images Twig path and was embedded, not hotlinked.
self::assertStringContainsString('cid:', $email->getHtmlBody());
}
}
public function testAKindWithNoRecipientsNotifiesNobody(): void
{
$this->recipientsFor(ResourceType::PARKING, ['[email protected]']);
$this->manager->book($this->user('[email protected]'), $this->resource('D1'), $this->date());
self::assertEmailCount(0);
}
/**
* One mail per recipient for the series rather than one per occurrence -- four Mondays and two
* recipients make two mails, and a yearly series would otherwise be a hundred and four.
*/
public function testASeriesSendsOneMailPerRecipientNotPerOccurrence(): void
{
$this->recipientsFor(ResourceType::DESK, ['[email protected]', '[email protected]']);
$result = $this->manager->bookSeries($this->weeklySeries());
self::assertSame(4, $result->createdCount());
self::assertEmailCount(2);
self::assertStringContainsString('4', (string) self::getMailerMessage()?->getTextBody());
}
public function testASeriesThatBookedNothingNotifiesNobody(): void
{
$this->recipientsFor(ResourceType::DESK, ['[email protected]']);
$desk = $this->resource('D1');
$this->manager->book($this->user('[email protected]'), $desk, new \DateTimeImmutable('2026-10-05'));
$result = $this->manager->bookSeries(new BookingSeries(
$this->user('[email protected]'),
$desk,
RecurrenceRule::WEEKLY,
new \DateTimeImmutable('2026-10-05'),
new \DateTimeImmutable('2026-10-09'),
TimeRange::fromMinutes(540, 720),
));
self::assertTrue($result->isCompletelyBlocked());
// The one booking above is the only mail-worthy event, and it happened before recipients
// could matter for the series -- so exactly one mail, for that booking.
self::assertEmailCount(1);
}
/**
* @param list<string> $recipients
*/
private function recipientsFor(ResourceType $type, array $recipients): void
{
$settings = new ResourceTypeSettings($type);
$settings->setNotificationRecipients($recipients);
$this->em->persist($settings);
$this->em->flush();
}
private function weeklySeries(): BookingSeries
{
return new BookingSeries(
@@ -334,6 +421,7 @@ class BookingManagerTest extends KernelTestCase
$connection->executeStatement('DELETE FROM booking');
$connection->executeStatement('DELETE FROM booking_series');
$connection->executeStatement('DELETE FROM resource');
$connection->executeStatement('DELETE FROM resource_type_settings');
$connection->executeStatement('DELETE FROM `user`');
$this->em->clear();
}