diff --git a/src/Controller/Admin/Application/DeleteController.php b/src/Controller/Admin/Application/DeleteController.php index 18d8887..021905a 100644 --- a/src/Controller/Admin/Application/DeleteController.php +++ b/src/Controller/Admin/Application/DeleteController.php @@ -3,17 +3,20 @@ namespace App\Controller\Admin\Application; use App\Entity\Application; +use App\Event\ApplicationDeletedEvent; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class DeleteController extends AbstractController { public function __construct( private readonly EntityManagerInterface $entityManager, + private readonly EventDispatcherInterface $eventDispatcher, private readonly LoggerInterface $logger ) { } @@ -26,10 +29,13 @@ class DeleteController extends AbstractController $this->entityManager->remove($application); $this->entityManager->flush(); - $application->getAssignment()->updateStaffingStatus(); - $this->entityManager->flush(); + $this->eventDispatcher->dispatch( + new ApplicationDeletedEvent($application), + ApplicationDeletedEvent::NAME + ); $this->addFlash('success', 'Die Bewerbung wurde gelöscht'); + $this->logger->info('Delete application', [ 'destination' => (string) $application->getAssignment()->getDestination(), 'teamer' => (string) $application->getTeamer(), @@ -39,4 +45,4 @@ class DeleteController extends AbstractController 'uuid' => $application->getAssignment()->getUuid(), ]); } -} \ No newline at end of file +} diff --git a/src/Controller/Admin/Application/DisposeController.php b/src/Controller/Admin/Application/DisposeController.php index 2f5419c..7a16daa 100644 --- a/src/Controller/Admin/Application/DisposeController.php +++ b/src/Controller/Admin/Application/DisposeController.php @@ -39,11 +39,10 @@ class DisposeController extends AbstractController $this->entityManager->remove($application); $this->entityManager->flush(); - // Update staffing status of related assignment - $disposition->getAssignment()->updateStaffingStatus(); - $this->entityManager->flush(); - - $this->eventDispatcher->dispatch(new DispositionCreatedEvent($disposition), DispositionCreatedEvent::NAME); + $this->eventDispatcher->dispatch( + new DispositionCreatedEvent($disposition), + DispositionCreatedEvent::NAME + ); $this->addFlash('success', 'Teamer:in wurde eingeteilt'); $this->logger->info('Create disposition', [ diff --git a/src/Controller/Admin/Application/StatusController.php b/src/Controller/Admin/Application/StatusController.php index 06c99f8..bd8e2dd 100644 --- a/src/Controller/Admin/Application/StatusController.php +++ b/src/Controller/Admin/Application/StatusController.php @@ -36,7 +36,6 @@ class StatusController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $this->eventDispatcher->dispatch(new ApplicationStatusEvent($statusDto), ApplicationStatusEvent::NAME); $application ->setStatus($statusDto->getStatus()) ->setComment($statusDto->getComment()) @@ -44,6 +43,11 @@ class StatusController extends AbstractController ; $this->entityManager->flush(); + $this->eventDispatcher->dispatch( + new ApplicationStatusEvent($statusDto), + ApplicationStatusEvent::NAME + ); + $this->addFlash('success', 'Der Status der Bewerbung wurde aktualisiert'); $this->logger->info('Update application status', [ 'application_id' => $application->getId(), diff --git a/src/Controller/Admin/Disposition/DeleteController.php b/src/Controller/Admin/Disposition/DeleteController.php index 18d6396..1909641 100644 --- a/src/Controller/Admin/Disposition/DeleteController.php +++ b/src/Controller/Admin/Disposition/DeleteController.php @@ -43,8 +43,6 @@ class DeleteController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $this->eventDispatcher->dispatch(new DispositionDeletedEvent($disposition), DispositionDeletedEvent::NAME); - $this->addFlash('success', 'Die Einteilung wurde gelöscht'); $this->logger->info('Delete disposition', [ 'disposition_id' => $disposition->getId(), @@ -54,9 +52,10 @@ class DeleteController extends AbstractController $this->entityManager->remove($disposition); $this->entityManager->flush(); - // Update staffing status of related assignment - $disposition->getAssignment()->updateStaffingStatus(); - $this->entityManager->flush(); + $this->eventDispatcher->dispatch( + new DispositionDeletedEvent($disposition), + DispositionDeletedEvent::NAME + ); return new HxRedirectResponse($this->generateUrl('app_administrative_assignment_detail', [ 'uuid' => $disposition->getAssignment()->getUuid(), diff --git a/src/Controller/Administrative/Document/CheckController.php b/src/Controller/Administrative/Document/CheckController.php index cca08f2..6500541 100644 --- a/src/Controller/Administrative/Document/CheckController.php +++ b/src/Controller/Administrative/Document/CheckController.php @@ -4,6 +4,7 @@ namespace App\Controller\Administrative\Document; use App\Controller\Traits\ReturnUrlTrait; use App\Entity\Upload; +use App\Event\DocumentConfirmedEvent; use App\Event\DocumentRejectedEvent; use App\Form\DocumentCheckType; use App\Htmx\HxRedirectResponse; @@ -46,16 +47,20 @@ class CheckController extends AbstractController switch ($formData->getStatus()) { case Upload::STATUS_CHECKED: $this->confirmDocument($document, 'confirm_contract', Upload::STATUS_CHECKED, $formData); - // Contract confirmed: Update staffing status of related assignment - $document->getDisposition()->getAssignment()->updateStaffingStatus(); - $this->entityManager->flush(); + $this->eventDispatcher->dispatch( + new DocumentConfirmedEvent($document), + DocumentConfirmedEvent::NAME + ); break; case Upload::STATUS_PAID: $this->confirmDocument($document, 'confirm_invoice', Upload::STATUS_PAID, $formData); break; case Upload::STATUS_REJECTED: $this->rejectDocument($document, $formData->getComment()); - $this->eventDispatcher->dispatch(new DocumentRejectedEvent($formData), DocumentRejectedEvent::NAME); + $this->eventDispatcher->dispatch( + new DocumentRejectedEvent($formData), + DocumentRejectedEvent::NAME + ); break; default: $document diff --git a/src/Controller/Teamer/Application/CreateController.php b/src/Controller/Teamer/Application/CreateController.php index d62966c..2797bf4 100644 --- a/src/Controller/Teamer/Application/CreateController.php +++ b/src/Controller/Teamer/Application/CreateController.php @@ -5,6 +5,7 @@ namespace App\Controller\Teamer\Application; use App\Entity\Application; use App\Entity\Assignment; use App\Entity\User; +use App\Event\ApplicationCreatedEvent; use App\Form\TeamerApplicationType; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; @@ -13,11 +14,13 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class CreateController extends AbstractController { public function __construct( private readonly EntityManagerInterface $entityManager, + private readonly EventDispatcherInterface $eventDispatcher, private readonly LoggerInterface $logger ) { } @@ -39,9 +42,10 @@ class CreateController extends AbstractController $this->entityManager->persist($application); $this->entityManager->flush(); - // Update staffing status of related assignment - $assignment->updateStaffingStatus(); - $this->entityManager->flush(); + $this->eventDispatcher->dispatch( + new ApplicationCreatedEvent($application), + ApplicationCreatedEvent::NAME + ); $this->addFlash('success', 'Deine Bewerbung wurde entgegengenommen'); $this->logger->info('Create application', [ diff --git a/src/Controller/Teamer/Application/WithdrawController.php b/src/Controller/Teamer/Application/WithdrawController.php index 8b6efe2..c08809b 100644 --- a/src/Controller/Teamer/Application/WithdrawController.php +++ b/src/Controller/Teamer/Application/WithdrawController.php @@ -5,6 +5,7 @@ namespace App\Controller\Teamer\Application; use App\Controller\Traits\ReturnUrlTrait; use App\Entity\Application; use App\Entity\User; +use App\Event\ApplicationDeletedEvent; use App\Htmx\HxRedirectResponse; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; @@ -13,6 +14,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class WithdrawController extends AbstractController { @@ -20,6 +22,7 @@ class WithdrawController extends AbstractController public function __construct( private readonly EntityManagerInterface $entityManager, + private readonly EventDispatcherInterface $eventDispatcher, private readonly LoggerInterface $logger ) { } @@ -37,9 +40,10 @@ class WithdrawController extends AbstractController $this->entityManager->remove($application); $this->entityManager->flush(); - // Update staffing status of related assignment - $assignment->updateStaffingStatus(); - $this->entityManager->flush(); + $this->eventDispatcher->dispatch( + new ApplicationDeletedEvent($application), + ApplicationDeletedEvent::NAME + ); $this->logger->info('Withdraw application', [ 'teamer_id' => $teamer->getId(), diff --git a/src/Entity/Assignment.php b/src/Entity/Assignment.php index 92e3cfe..86f181c 100644 --- a/src/Entity/Assignment.php +++ b/src/Entity/Assignment.php @@ -136,6 +136,7 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa public function updateStaffingStatus(): void { $confirmedDispositions = $this->getConfirmedDispositions(); + $validApplications = $this->getValidApplications(); if ($this->availableDispositions === $confirmedDispositions->count()) { $this->setStaffingStatus(Assignment::STATUS_STAFFED); @@ -145,8 +146,8 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa ) { $this->setStaffingStatus(Assignment::STATUS_PARTLY_STAFFED); } elseif ( - $this->availableDispositions > $this->dispositions->count() - && 0 < $this->applications->count() + $this->availableDispositions > $confirmedDispositions->count() + && 0 < $validApplications->count() ) { $this->setStaffingStatus(Assignment::STATUS_STAFFING); } else { diff --git a/src/Event/ApplicationCreatedEvent.php b/src/Event/ApplicationCreatedEvent.php new file mode 100644 index 0000000..79f007b --- /dev/null +++ b/src/Event/ApplicationCreatedEvent.php @@ -0,0 +1,19 @@ +application; + } +} \ No newline at end of file diff --git a/src/Event/ApplicationDeletedEvent.php b/src/Event/ApplicationDeletedEvent.php new file mode 100644 index 0000000..bdab566 --- /dev/null +++ b/src/Event/ApplicationDeletedEvent.php @@ -0,0 +1,19 @@ +application; + } +} \ No newline at end of file diff --git a/src/Event/DocumentConfirmedEvent.php b/src/Event/DocumentConfirmedEvent.php new file mode 100644 index 0000000..04bc647 --- /dev/null +++ b/src/Event/DocumentConfirmedEvent.php @@ -0,0 +1,20 @@ +document; + } +} \ No newline at end of file diff --git a/src/EventListener/StaffingStatusSubscriber.php b/src/EventListener/StaffingStatusSubscriber.php new file mode 100644 index 0000000..1551488 --- /dev/null +++ b/src/EventListener/StaffingStatusSubscriber.php @@ -0,0 +1,82 @@ + 'onApplicationCreated', + ApplicationDeletedEvent::NAME => 'onApplicationDeleted', + ApplicationStatusEvent::NAME => 'onApplicationStatusUpdated', + DispositionCreatedEvent::NAME => 'onDispositionCreated', + DispositionDeletedEvent::NAME => 'onDispositionDeleted', + DocumentConfirmedEvent::NAME => 'onDocumentConfirmed', + ]; + } + + public function onApplicationCreated(ApplicationCreatedEvent $event): void + { + $application = $event->getApplication(); + $application->getAssignment()->updateStaffingStatus(); + + $this->entityManager->flush(); + } + + public function onApplicationDeleted(ApplicationDeletedEvent $event): void + { + $assignment = $event->getApplication()->getAssignment(); + + $this->updateStaffingStatus($assignment); + } + + public function onApplicationStatusUpdated(ApplicationStatusEvent $event): void + { + $assignment = $event->getApplication()->getAssignment(); + + $this->updateStaffingStatus($assignment); + } + + public function onDispositionCreated(DispositionCreatedEvent $event): void + { + $assignment = $event->getDisposition()->getAssignment(); + + $this->updateStaffingStatus($assignment); + } + + public function onDispositionDeleted(DispositionDeletedEvent $event): void + { + $assignment = $event->getDisposition()->getAssignment(); + + $this->updateStaffingStatus($assignment); + } + + public function onDocumentConfirmed(DocumentConfirmedEvent $event): void + { + $assignment = $event->getDocument()->getDisposition()->getAssignment(); + + $this->updateStaffingStatus($assignment); + } + + private function updateStaffingStatus(Assignment $assignment): void + { + $assignment->updateStaffingStatus(); + + $this->entityManager->flush(); + } +} \ No newline at end of file diff --git a/src/Repository/AssignmentRepository.php b/src/Repository/AssignmentRepository.php index b0fe066..17af212 100644 --- a/src/Repository/AssignmentRepository.php +++ b/src/Repository/AssignmentRepository.php @@ -37,9 +37,10 @@ class AssignmentRepository extends ServiceEntityRepository ->innerJoin('assignment.destination', 'destination') ->innerJoin('assignment.jobProfile', 'job_profile') ->where($qb->expr()->isNull('assignment.deletedAt')) - ->leftJoin('assignment.applications', 'application') + ->leftJoin('assignment.applications', 'application', Join::WITH, $qb->expr()->neq('application.status', ':applicationStatus')) ->leftJoin('assignment.dispositions', 'disposition') ->leftJoin('disposition.teamer', 'teamer') + ->setParameter('applicationStatus', Application::STATUS_REJECTED) ; $this->applyFilterSettings($filterDto, $qb);