src/EventSubscriber/Finance/Quotation/QuotationStatusSubscriber.php line 34
<?php
namespace App\EventSubscriber\Finance\Quotation;
use App\Doctrine\Type\Expediting\ShippingPlanStatus;
use App\Doctrine\Type\Expediting\ShippingSegmentStatus;
use App\Doctrine\Type\Finance\PayableStatus;
use App\Doctrine\Type\Scheduler\TaskStatus;
use App\Entity\Finance\Quotation;
use App\Entity\Scheduler\Task;
use App\Event\Finance\QuotationStatusUpdateEvent;
use App\EventSubscriber\TasksCancelerTrait;
use App\Repository\Scheduler\TaskRepository;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
readonly class QuotationStatusSubscriber implements EventSubscriberInterface
{
use TasksCancelerTrait;
public function __construct(
private EntityManagerInterface $entityManager,
private TaskRepository $taskRepository,
) {}
public static function getSubscribedEvents(): array
{
return [
QuotationStatusUpdateEvent::IDENTIFIER => ['process', 0],
];
}
public function process(QuotationStatusUpdateEvent $event): void
{
$quotation = $event->getQuotation();
if (PayableStatus::ACCEPTED === $quotation->getStatus()) {
$this->updateShippingPlan($quotation, status: ShippingPlanStatus::APPROVED);
$this->closeReviewTask($quotation);
$this->closeWorkAwardTask($quotation);
$this->closeRemainingQuotations($quotation);
$this->scheduleApprovalIssuance($quotation);
} elseif (PayableStatus::DECLINED === $quotation->getStatus()) {
$this->updateShippingPlan($quotation);
$this->closeReviewTask($quotation);
$this->cancelApprovalIssuance($quotation);
} else {
$this->updateShippingPlan($quotation);
$this->cancelApprovalIssuance($quotation);
$this->resetWorkAwardTask($quotation);
$this->resetQuotationReviewTask($quotation);
$this->rescheduleRemainingQuotations($quotation);
}
$this->entityManager->flush();
}
private function updateShippingPlan(Quotation $quotation, ?ShippingPlanStatus $status = ShippingPlanStatus::DRAFTED): void
{
$shippingPlan = $quotation->getShippingPlan()
->setStatus($status);
$this->entityManager->persist($shippingPlan);
$segmentsStatus = ($status === ShippingPlanStatus::DRAFTED)
? ShippingSegmentStatus::PLANNED
: ShippingSegmentStatus::APPROVED;
foreach ($shippingPlan->getShippingSegments() as $segment) {
$segment->setStatus($segmentsStatus);
$this->entityManager->persist($segment);
}
}
private function closeReviewTask(Quotation $quotation): void
{
$task = $this->taskRepository->getQuotationReviewTask($quotation, createIfNull: true);
$task->setStatus(TaskStatus::COMPLETED);
$task->setCompletedOn(new DateTime());
$this->entityManager->persist($task);
}
private function closeWorkAwardTask(Quotation $quotation): void
{
$task = $this->taskRepository->getWorkAwardTask($quotation->getShippingPlan(), createIfNull: true);
$task->setStatus(TaskStatus::COMPLETED);
$task->setCompletedOn(new DateTime());
$this->entityManager->persist($task);
}
private function closeRemainingQuotations(Quotation $currentQuotation): void
{
$quotations = $currentQuotation->getShippingPlan()->getQuotations();
foreach ($quotations as $quotation) {
if ($currentQuotation->getId() !== $quotation->getId() && PayableStatus::AMENDED !== $quotation->getStatus()) {
$this->declineQuotation($quotation);
}
}
}
private function declineQuotation(Quotation $quotation): void
{
// First, Update quotation status
$quotation->setStatus(PayableStatus::QUOTED);
$this->entityManager->persist($quotation);
// Then, cancel pending attached tasks
$pickupQuotationRequestTask = $this->taskRepository->getPickupQuotationRequestTask($quotation);
$pickupQuotationFillingTask = $this->taskRepository->getPickupQuotationFillingTask($quotation);
$quotationReviewTask = $this->taskRepository->getQuotationReviewTask($quotation);
$this->cancelTasks([$pickupQuotationRequestTask, $pickupQuotationFillingTask, $quotationReviewTask]);
}
private function scheduleApprovalIssuance(Quotation $quotation): void
{
$quotationApprovalIssuanceTask = $this->taskRepository->getQuotationApprovalIssuanceTask($quotation, createIfNull: true);
$this->entityManager->persist($quotationApprovalIssuanceTask);
}
private function rescheduleRemainingQuotations(Quotation $currentQuotation): void
{
$quotations = $currentQuotation->getShippingPlan()->getQuotations();
foreach ($quotations as $quotation) {
if ($quotation->getId() !== $currentQuotation->getId()) {
$this->rescheduleQuotations($quotation);
}
}
}
private function cancelApprovalIssuance(Quotation $quotation): void
{
$quotationApprovalIssuanceTask = $this->taskRepository->getQuotationApprovalIssuanceTask($quotation);
$this->cancelTasks([$quotationApprovalIssuanceTask]);
}
private function rescheduleQuotations(Quotation $quotation): void
{
// Only process quotations that were automatically declined by the system
if (PayableStatus::QUOTED !== $quotation->getStatus()) {
return;
}
// Only reschedule tasks that were canceled, cancel pending attached tasks
$pickupQuotationRequestTask = $this->taskRepository->getPickupQuotationRequestTask($quotation);
if (!$pickupQuotationRequestTask instanceof Task) {
$pickupQuotationRequestTask = $this->taskRepository->getPickupQuotationRequestTask($quotation, createIfNull: true);
$this->entityManager->persist($pickupQuotationRequestTask);
}
$pickupQuotationFillingTask = $this->taskRepository->getPickupQuotationFillingTask($quotation);
if (!$pickupQuotationFillingTask instanceof Task) {
$pickupQuotationFillingTask = $this->taskRepository->getPickupQuotationRequestTask($quotation, createIfNull: true);
$this->entityManager->persist($pickupQuotationFillingTask);
}
$quotationReviewTask = $this->taskRepository->getQuotationReviewTask($quotation);
if (!$quotationReviewTask instanceof Task) {
$quotationReviewTask = $this->taskRepository->getPickupQuotationRequestTask($quotation, createIfNull: true);
$this->entityManager->persist($quotationReviewTask);
}
}
private function resetWorkAwardTask(Quotation $quotation): void
{
$workOrder = $quotation->getShippingPlan()->getWorkOrder();
if (null === $workOrder) {
return;
}
$task = $this->taskRepository->getWorkAwardTask($quotation->getShippingPlan(), createIfNull: true);
$task->setStatus(TaskStatus::PLANNED);
$task->setCompletedOn(null);
$this->entityManager->persist($task);
}
private function resetQuotationReviewTask(Quotation $quotation): void
{
$task = $this->taskRepository->getQuotationReviewTask($quotation, createIfNull: true);
$task->setStatus(TaskStatus::PLANNED);
$task->setCompletedOn(null);
$this->entityManager->persist($task);
}
}