ERP/BillingRequestsBundle/EventSubscriber/WorkflowTransitionNotifier.php line 172

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace ERP\BillingRequestsBundle\EventSubscriber;
  4. use ApiPlatform\Core\EventListener\EventPriorities;
  5. use App\Entity\Project;
  6. use App\Entity\ProjectBudget;
  7. use App\Entity\User;
  8. use App\Entity\Workflow\WorkflowTransitionLog;
  9. use App\Mail\Mailer;
  10. use App\Repository\UserRepository;
  11. use App\Services\CurrencyConverterService;
  12. use App\Services\MoneyEmbeddableService;
  13. use Carbon\Carbon;
  14. use Doctrine\Common\Collections\ArrayCollection;
  15. use Doctrine\ORM\EntityManagerInterface;
  16. use ERP\BillingRequestsBundle\Entity\BillingRequest;
  17. use ERP\BillingRequestsBundle\Services\BillingRequestService;
  18. use ERP\CommentBundle\Entity\Comment;
  19. use ERP\CoreBundle\Exception\LogicException;
  20. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  21. use Symfony\Component\HttpFoundation\RequestStack;
  22. use Symfony\Component\HttpKernel\Event\ViewEvent;
  23. use Symfony\Component\HttpKernel\KernelEvents;
  24. use Symfony\Component\Security\Core\Security;
  25. use Symfony\Component\Workflow\Event\Event;
  26. use Symfony\Component\Workflow\Event\GuardEvent;
  27. use Symfony\Component\Workflow\Registry;
  28. use Symfony\Component\Workflow\Transition;
  29. class WorkflowTransitionNotifier implements EventSubscriberInterface
  30. {
  31.     private Mailer $mailer;
  32.     private Security $security;
  33.     private RequestStack $requestStack;
  34.     private Registry $workflowRegistry;
  35.     private EntityManagerInterface $entityManager;
  36.     private BillingRequestService $billingRequestService;
  37.     private CurrencyConverterService $currencyConverterService;
  38.     private MoneyEmbeddableService $moneyEmbeddableService;
  39.     public function __construct(
  40.         Mailer $mailer,
  41.         Security $security,
  42.         RequestStack $requestStack,
  43.         Registry $workflowRegistry,
  44.         EntityManagerInterface $entityManager,
  45.         BillingRequestService $billingRequestService,
  46.         CurrencyConverterService $currencyConverterService,
  47.         MoneyEmbeddableService $moneyEmbeddableService
  48.     ) {
  49.         $this->mailer $mailer;
  50.         $this->security $security;
  51.         $this->requestStack $requestStack;
  52.         $this->workflowRegistry $workflowRegistry;
  53.         $this->entityManager $entityManager;
  54.         $this->billingRequestService $billingRequestService;
  55.         $this->currencyConverterService $currencyConverterService;
  56.         $this->moneyEmbeddableService $moneyEmbeddableService;
  57.     }
  58.     /**
  59.      * {@inheritdoc}
  60.      */
  61.     public static function getSubscribedEvents(): array
  62.     {
  63.         return [
  64.             KernelEvents::VIEW => [
  65.                 ['onCreateEnterDraft'EventPriorities::POST_WRITE],
  66.             ],
  67.             'workflow.billing_request.entered' => 'onEntered',
  68.             'workflow.billing_request.enter.draft' => 'onEnterDraft',
  69.             'workflow.billing_request.leave.draft' => 'onLeaveDraft',
  70.             'workflow.billing_request.transition.cancel' => 'onExtendedTransition',
  71.             'workflow.billing_request.transition.invoicing' => 'onExtendedTransition',
  72.             'workflow.billing_request.transition.disputing' => 'onExtendedTransition',
  73.             'workflow.billing_request.guard.disputing' => 'onGuardDisputing',
  74.         ];
  75.     }
  76.     public function onCreateEnterDraft(ViewEvent $event): void
  77.     {
  78.         /** @var BillingRequest $billingRequest */
  79.         $billingRequest $event->getControllerResult();
  80.         if ($billingRequest instanceof BillingRequest && 'POST' === $event->getRequest()->getMethod()) {
  81.             $applyTransition 'to_draft';
  82.             $workflow $this->workflowRegistry->get($billingRequest);
  83.             $enabledTransitions = new ArrayCollection($workflow->getEnabledTransitions($billingRequest));
  84.             if ($enabledTransitions->exists(function ($keyTransition $transition) use ($applyTransition) {
  85.                 return $applyTransition === $transition->getName();
  86.             })) {
  87.                 /** @var Transition $transition */
  88.                 $transition $enabledTransitions
  89.                     ->filter(function (Transition $transition) use ($applyTransition) {
  90.                         return $applyTransition === $transition->getName();
  91.                     })
  92.                     ->first()
  93.                 ;
  94.                 $workflow->apply($billingRequest$transition->getName());
  95.                 $this->entityManager->flush();
  96.             }
  97.         }
  98.     }
  99.     public function onEntered(Event $event): void
  100.     {
  101.         /** @var BillingRequest|null $billingRequest */
  102.         $billingRequest $event->getSubject();
  103.         if ($billingRequest instanceof BillingRequest) {
  104.             /** @var WorkflowTransitionLog $lastTransition */
  105.             $lastTransition $billingRequest->getWorkflowTransitionLogs()->last();
  106.             /** @var User $actor */
  107.             $user $billingRequest->getCreatedBy();
  108.             $recipientUsersEmails array_unique($this->billingRequestService->getNotifyees($billingRequest)->map(static function (User $recipient) {
  109.                 return $recipient->getEmail();
  110.             })->toArray());
  111.             $billingRequestNumber $billingRequest->getId();
  112.             /** @var UserRepository $userRepositorey */
  113.             $userRepository $this->entityManager->getRepository(User::class);
  114.             if ($user->getTimezone()) {
  115.                 $timeZone $user->getTimezone()->getName();
  116.                 $timeZoneLabel sprintf('(GMT%s)'$user->getTimezone()->getOffset());
  117.             } elseif ($user->getOrganization() && $user->getOrganization()->getTimezone()) {
  118.                 $timeZone $user->getOrganization()->getTimezone()->getName();
  119.                 $timeZoneLabel sprintf('(GMT%s)'$user->getOrganization()->getTimezone()->getOffset());
  120.             } else {
  121.                 $timeZone 'UTC';
  122.                 $timeZoneLabel '(UTC)';
  123.             }
  124.             if ('created' === $lastTransition->getFrom()) {
  125.                 foreach ($recipientUsersEmails as $recipientUsersEmail) {
  126.                     $recipient $userRepository->findOneBy(['email' => $recipientUsersEmail]);
  127.                     $this->mailer->send(
  128.                         'billing-request/created',
  129.                         compact('user''billingRequest''recipient''timeZone''timeZoneLabel'),
  130.                         [$recipientUsersEmail],
  131.                         null,
  132.                         sprintf('New Billing Request (#%s) from %s %s'$billingRequestNumber$user->getFirstName(), $user->getLastName()),
  133.                          $billingRequest->getAttachments()->toArray()
  134.                     );
  135.                 }
  136.             } else {
  137.                 foreach ($recipientUsersEmails as $recipientUsersEmail) {
  138.                     $recipient $userRepository->findOneBy(['email' => $recipientUsersEmail]);
  139.                     $this->mailer->send(
  140.                         'billing-request/status-change',
  141.                         compact('user''billingRequest''recipient''timeZone''timeZoneLabel'),
  142.                         [$recipientUsersEmail],
  143.                         null,
  144.                         sprintf('Status changed on Billing Request (#%s) from %s %s'$billingRequestNumber$user->getFirstName(), $user->getLastName())
  145.                     );
  146.                 }
  147.             }
  148.         }
  149.     }
  150.     public function onExtendedTransition(Event $event)
  151.     {
  152.         $resource $event->getSubject();
  153.         $transitionName $event->getTransition()->getName();
  154.         if (in_array($transitionName, ['invoicing''disputing''cancel'])) {
  155.             $error false;
  156.             $requestContent json_decode((string) $this->requestStack->getCurrentRequest()->getContent(), true);
  157.             switch ($transitionName) {
  158.                 case 'invoicing':
  159.                     if (empty($requestContent['invoice_number'])) {
  160.                         $error "Transitioning to {$transitionName} can't be done without providing invoice number!";
  161.                     }
  162.                     break;
  163.                 case 'disputing':
  164.                     if (empty($requestContent['dispute_reason'])) {
  165.                         $error "Transitioning to {$transitionName} can't be done without providing dispute reason!";
  166.                     } else {
  167.                         $user $this->security->getUser();
  168.                         if ($user instanceof User) {
  169.                             $comment = new Comment();
  170.                             $comment->setUser($user);
  171.                             $comment->setContent("{$requestContent['dispute_reason']}");
  172.                             $resource->addComment($comment);
  173.                             $comment->workflow_comment true;
  174.                         }
  175.                     }
  176.                     break;
  177.                 case 'cancel':
  178.                     if (empty($requestContent['cancellation_reason'])) {
  179.                         $error "Transitioning to {$transitionName} can't be done without providing cancellation reason!";
  180.                     }
  181.                     break;
  182.                 default:
  183.                     break;
  184.             }
  185.             if ($error) {
  186.                 $event->stopPropagation();
  187.                 throw LogicException::withStatusCode(sprintf('%sTransition.canNot%s'get_class($resource), $transitionName), $error400);
  188.             }
  189.         }
  190.     }
  191.     public function onEnterDraft(Event $event): void
  192.     {
  193. //        $billingRequest = $event->getSubject();
  194. //        if ($billingRequest instanceof BillingRequest) {
  195. //            $project = $billingRequest->getProject();
  196. //
  197. //            if ($project instanceof Project && BillingRequest::BILLING_TYPE_TIME_AND_MATERIALS === $billingRequest->getBillingType()) {
  198. //                $start = Carbon::instance($billingRequest->getDateStart());
  199. //                $end = Carbon::instance($billingRequest->getDateEnd());
  200. //
  201. //                $defaultHourlyRate = $this->moneyEmbeddableService->getNormalizedValue($billingRequest->getDefaultHourlyRateValue(), $project->getCurrency());
  202. //
  203. //                $amount = $this->billingRequestService->calculateTotalValue(
  204. //                    $project,
  205. //                    $start,
  206. //                    $end,
  207. //                    $defaultHourlyRate
  208. //                );
  209. //
  210. //                $billingRequest->setValue($amount);
  211. //            }
  212. //        }
  213.     }
  214.     public function onLeaveDraft(Event $event): void
  215.     {
  216. //        $billingRequest = $event->getSubject();
  217. //        if ($billingRequest instanceof BillingRequest) {
  218. //            if ($billingRequest->getProject() instanceof Project && $billingRequest->getAutomation() && ProjectBudget::ESTIMATE_TYPE_HOURLY_QUOTED === $billingRequest->getProject()->allBudgetsHasSameEstimateType(true)) {
  219. //                $billingRequest->setValue($this->billingRequestService->getBillingRequestValue($billingRequest));
  220. //            }
  221. //        }
  222.     }
  223.     public function onGuardDisputing(GuardEvent $event): void
  224.     {
  225.         /** @var BillingRequest $billingRequest */
  226.         $billingRequest $event->getSubject();
  227.         if ($billingRequest->getProject() && ProjectBudget::ESTIMATE_TYPE_HOURLY_QUOTED != $billingRequest->getProject()->allBudgetsHasSameEstimateType(true)) {
  228.             $event->setBlocked(true);
  229.         }
  230.     }
  231. }