feat: automatically purge applications with date ranges overlapping an accepted application

closes #869aug4uz
This commit is contained in:
Björn Fromme
2025-10-21 09:18:15 +02:00
parent 6c5115d5e7
commit f4b0dda38b
2 changed files with 412 additions and 0 deletions
@@ -0,0 +1,80 @@
<?php
namespace App\EventListener;
use App\Entity\Application;
use App\Entity\Upload;
use App\Event\DocumentConfirmedEvent;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: DocumentConfirmedEvent::NAME, method: 'onDocumentConfirmed')]
class InvalidateApplicationsListener
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger,
) {
}
public function onDocumentConfirmed(DocumentConfirmedEvent $event): void
{
$document = $event->getDocument();
if (Upload::TYPE_CONTRACT !== $document->getType()) {
return;
}
$disposition = $document->getDisposition();
$assignment = $disposition->getAssignment();
$teamer = $disposition->getTeamer();
$period = $assignment->getEffectivePeriod();
// Find other applications by this teamer with overlapping date ranges
// Two periods overlap when: (start1 < end2) AND (end1 > start2)
// This catches all overlap scenarios while excluding boundary-only touching:
// - Partial overlaps from either direction
// - Complete containment in either direction
// - Exact date matches
// Note: Periods that only touch at boundaries (e.g., Jan 1-7 and Jan 7-12) are NOT considered overlapping
$qb = $this
->entityManager
->getRepository(Application::class)
->createQueryBuilder('application');
/** @var array<Application> $applications */
$applications = $qb
->innerJoin('application.assignment', 'assignment')
->where($qb->expr()->andX(
$qb->expr()->eq('application.teamer', ':teamer'),
$qb->expr()->lt('assignment.dateFrom', ':dateTo'),
$qb->expr()->gt('assignment.dateTo', ':dateFrom'),
$qb->expr()->neq('application.status', ':status')
))
->setParameter('teamer', $teamer)
->setParameter('dateFrom', $period->start->toDateTimeImmutable())
->setParameter('dateTo', $period->end->toDateTimeImmutable())
->setParameter('status', Application::STATUS_REJECTED)
->getQuery()
->getResult()
;
if (0 === count($applications)) {
return;
}
foreach ($applications as $application) {
$destination = $application->getAssignment()->getDestination();
$this->logger->info('Deleted overlapping application', [
'teamer' => $teamer,
'destination' => $destination->getHotelCode(),
'date_from' => $destination->getDateFrom()->format('Y-m-d'),
'date_to' => $destination->getDateTo()->format('Y-m-d'),
]);
$this->entityManager->remove($application);
}
$this->entityManager->flush();
}
}