<?php
namespace App\EventSubscriber;
use App\Entity\Event as SubscriptionEvent;
use App\Entity\Invoice;
use App\Entity\PriceInquiry;
use App\Repository\CustomerQuotationsRepository;
use App\Security\Voters\UserVoter;
use App\Service\Constants\InvoiceType;
use Doctrine\Common\Util\ClassUtils;
use App\Repository\SubscriptionRepository;
use App\Service\RabbitMQ\RabbitMQDispatcher;
use App\Service\Subscription\SubscriptionService;
use App\Service\UserLog;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Workflow\Event\GuardEvent;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Workflow\Event\Event;
use App\Service\Api\PipeDriveService;
use App\Service\Mailing\MailContentQuotation;
use App\Service\Mailing\MailingService;
use App\Service\Log\QuotationLogService;
use Symfony\Component\Workflow\Registry;
use App\Service\Invoice\InvoiceService;
class QuotationWorkflowSubscriber implements EventSubscriberInterface
{
private Security $security;
private QuotationLogService $logService;
private UserLog $userLog;
private Registry $workflows;
private RabbitMQDispatcher $rabbitMQDispatcher;
private CustomerQuotationsRepository $quotationRepo;
private InvoiceService $invoiceService;
private SubscriptionService $subscriptionService;
private SubscriptionRepository $subscriptionRepo;
private EntityManagerInterface $em;
public function __construct(
Security $security,
CustomerQuotationsRepository $quotationRepo,
QuotationLogService $logService,
Registry $workflows,
RabbitMQDispatcher $rabbitMQDispatcher,
UserLog $userLog,
InvoiceService $invoiceService,
SubscriptionRepository $subscriptionRepo,
SubscriptionService $subscriptionService,
EntityManagerInterface $em
)
{
$this->em = $em;
$this->workflows = $workflows;
$this->security = $security;
$this->rabbitMQDispatcher = $rabbitMQDispatcher;
$this->subscriptionService = $subscriptionService;
$this->quotationRepo = $quotationRepo;
$this->logService = $logService;
$this->userLog = $userLog;
$this->invoiceService = $invoiceService;
$this->subscriptionRepo = $subscriptionRepo;
}
public static function getSubscribedEvents()
{
return [
'workflow.quotation_status.guard.to_ready' => ['toReadyGuard'],
'workflow.quotation_status.guard.to_deleted' => ['canBeDeletedGuard'],
'workflow.quotation_status.guard.to_inquiries_sent' => ['inquiriesSentGuard'],
'workflow.quotation_status.guard.to_offers_partially_received' => ['offersPartiallyReceivedGuard'],
'workflow.quotation_status.guard.to_offers_received' => ['offersReceivedGuard'],
'workflow.quotation_status.guard.to_ordered' => ['toOrderedGuard'],
'workflow.quotation_status.guard.to_waiting_payment' => ['toWaitingPaymentGuard'],
'workflow.quotation_status.guard.to_accepted' => ['toAcceptedGuard'],
'workflow.quotation_status.completed.to_draft' => [
['createSubscriptions'],
['quotationCreatedNotify']
],
'workflow.quotation_status.completed.to_new' => [
['webOrShopNewQuotationNotify', 30],
['quotationDataUpdate', 20],
['pipeDriveRegister', 10],
],
'workflow.quotation_status.completed.to_processing' => [
['setQuotationManager'],
['createManagerSubscriptions']
],
'workflow.quotation_status.completed.to_production' => [
['updatePlannedDeadline']
],
'workflow.quotation_status.completed.to_delivered' => [
['logDeliveryDate'],
],
'workflow.quotation_status.completed.to_finished' => [
['removeSubscriptions'],
['updateCustomerOrderCount'],
['updateManufacturerOrderCount'],
],
'workflow.quotation_status.completed.to_rejected' => [
['quotationInquiriesToDeclined'],
['quotationInvoicesToCanceled'],
['removeSubscriptions']
],
'workflow.quotation_status.completed.to_deleted' => [
['removeSubscriptions']
],
'workflow.quotation_status.announce' => [
['addLastUpdateTime'],
['logTransition'],
['quotationStatusChangeNotify']
],
];
}
public function toReadyGuard(GuardEvent $event)
{
if ( !$this->security->isGranted('ROLE_SALES_MANAGER') ) {
$event->setBlocked(true);
}
if ( !$event->getSubject()->getCustomer() ) {
$event->setBlocked(true);
}
}
public function canBeDeletedGuard(GuardEvent $event)
{
$quotation = $event->getSubject();
if ( !$this->security->isGranted('ROLE_QUOTATION_CAN_DELETE') ) {
$event->setBlocked(true);
}
if ( count($quotation->getPriceInquiries()) > 0 ) {
$event->setBlocked(true);
}
}
public function inquiriesSentGuard(GuardEvent $event)
{
if ( !$this->security->isGranted('ROLE_CAN_CREATE_INQUIRIES') ) {
$event->setBlocked(true);
}
if ( !count($event->getSubject()->getPriceInquiries()) ) {
$event->setBlocked(true);
}
}
public function offersPartiallyReceivedGuard(GuardEvent $event)
{
if ( $event->getSubject()->getPriceInquiries() ) {
foreach ( $event->getSubject()->getPriceInquiries() as $inquiry ) {
if ( $inquiry->getStatus() == PriceInquiry::STATUS_OFFER ) {
return;
}
}
}
$event->setBlocked(true);
}
public function offersReceivedGuard(GuardEvent $event)
{
if ( !$this->security->isGranted('ROLE_CAN_CREATE_INQUIRIES') ) {
$event->setBlocked(true);
}
if ( $event->getSubject()->getPriceInquiries() ) {
foreach ( $event->getSubject()->getPriceInquiries() as $inquiry ) {
if ( $inquiry->getStatus() == PriceInquiry::STATUS_OFFER && $inquiry->getOfferVerified() ) {
return;
}
}
}
$event->setBlocked(true);
}
public function toOrderedGuard(Event $event)
{
if ( $event->getSubject()->getPriceInquiries() ) {
foreach ( $event->getSubject()->getPriceInquiries() as $inquiry ) {
if ( $inquiry->getStatus() == PriceInquiry::STATUS_ACCEPTED ) {
return;
}
}
}
$event->setBlocked(true);
}
public function toWaitingPaymentGuard(GuardEvent $event)
{
if ( $this->security->getUser() && !$this->security->isGranted('ROLE_SALES_MANAGER') ) {
$event->setBlocked(true);
}
}
public function toAcceptedGuard(GuardEvent $event)
{
if (
$this->security->isGranted('ROLE_SALES_MANAGER')
||
$this->security->isGranted(UserVoter::IS_APP_CUSTOMER, $this->security->getUser())
) {
return;
}
$event->setBlocked(true);
}
public function createSubscriptions(Event $event)
{
$this->subscriptionService->generateSubscriptions($event->getSubject(), $event->getSubject()->getCreatedBy());
}
public function quotationCreatedNotify(Event $event)
{
$this->subscriptionService->proceedEvent(
SubscriptionEvent::QUOTATION_CREATED_DRAFT,
$event->getSubject(),
['data' => ['uuid' => $event->getSubject()->getUuid()]]
);
}
public function webOrShopNewQuotationNotify(Event $event)
{
if (!$event->getSubject()->getCreatedBy() ) {
$this->subscriptionService->proceedEvent(
$event->getSubject()->getIsWebShopRelated() ? SubscriptionEvent::QUOTATION_CREATED_SHOP : SubscriptionEvent::QUOTATION_CREATED_WEB,
$event->getSubject(),
['data' => ['uuid' => $event->getSubject()->getUuid()]]
);
}
}
public function quotationDataUpdate(Event $event)
{
$event->getSubject()->setDateSubmitted(new \DateTime());
$event->getSubject()->setOrderNumber($this->quotationRepo->getTodaysIterator());
}
public function pipeDriveRegister(Event $event)
{
$customer = $event->getSubject()->getCustomer();
if (!$customer || !$customer->getEmail()) {
return;
}
$this->rabbitMQDispatcher->dispatch([
'data' => [
'organization' => $customer->getName(),
'name' => $customer->getPersonName() ?? $customer->getName(),
'email' => $customer->getEmail(),
'phone' => $customer->getPhone(),
'order_number' => $event->getSubject()->getOrderNumber(),
],
'action_name' => 'pipeDriveRegister',
'consumer_name' => 'pipe_drive_consumer'
]);
}
public function setQuotationManager(Event $event)
{
$event->getSubject()->setManager($this->security->getUser());
}
public function createManagerSubscriptions(Event $event)
{
if ($event->getSubject()->getManager() !== $event->getSubject()->getCreatedBy()) {
$this->subscriptionService->generateSubscriptions($event->getSubject(), $event->getSubject()->getManager());
}
}
public function updatePlannedDeadline(Event $event)
{
if ( $event->getSubject()->getOrderInquiry() ) {
$date = (new \DateTime())->modify('+' . $event->getSubject()->getOrderInquiry()->getFullLeadDays() .' day');
$event->getSubject()->setPlannedDeadline($date);
}
}
public function logDeliveryDate(Event $event)
{
$this->logService->logAction(
$event->getSubject(),
'log.quotation.delivery.date',
$event->getSubject()->getDeliveryDate()->format('Y.m.d')
);
}
public function updateCustomerOrderCount(Event $event)
{
if ($customer = $event->getSubject()->getCustomer()) {
$count = $customer->getOrderCount();
$count++;
$customer->setOrderCount($count);
$this->em->flush();
}
}
public function updateManufacturerOrderCount(Event $event)
{
if ($manufacturer = $event->getSubject()->getOrderInquiry()->getManufacturer()) {
$count = $manufacturer->getOrderCount();
$count++;
$manufacturer->setOrderCount($count);
$this->em->flush();
}
}
public function quotationInquiriesToDeclined(Event $event)
{
if ( $event->getSubject()->getPriceInquiries() ) {
foreach ( $event->getSubject()->getPriceInquiries() as $inquiry ) {
if ( !in_array($inquiry->getStatus(), [PriceInquiry::STATUS_DECLINED, PriceInquiry::STATUS_REJECTED]) ) {
$workflow = $this->workflows->get($inquiry);
if ( $workflow->can($inquiry, 'to_declined') ) {
$workflow->apply($inquiry, 'to_declined');
}
}
}
}
}
public function quotationInvoicesToCanceled(Event $event)
{
if ( $event->getSubject()->getInvoices() ) {
foreach ( $event->getSubject()->getInvoices() as $invoice ) {
if ($invoice->getInvoiceDirection() !== Invoice::INVOICE_DIRECTION_INCOMING){
$this->invoiceService->setCanceled($invoice);
}
}
}
}
public function quotationStatusChangeNotify(Event $event)
{
$this->subscriptionService->proceedEvent(
'quotation.transition.' . $event->getTransition()->getName(),
$event->getSubject(),
['data' => [
'uuid' => $event->getSubject()->getUuid(),
'status' => $event->getSubject()->getStatus()
]]
);
}
public function removeSubscriptions(Event $event)
{
if ($subscriptions = $this->subscriptionRepo->getAll([
ClassUtils::getClass($event->getSubject()) => $event->getSubject()
])) {
$this->subscriptionService->removeSubs($subscriptions);
}
}
public function addLastUpdateTime(Event $event)
{
$event->getSubject()->setLastUpdate(new \DateTime());
}
public function logTransition(Event $event)
{
$this->logService->logAction(
$event->getSubject(),
implode(', ', $event->getTransition()->getTos())
// implode(', ', array_keys($event->getMarking()->getPlaces()))
);
$this->userLog->log(
'quotation',
'status.update.'.$event->getTransition()->getName(),
$event->getSubject()->getId(),
'Quotation status update: '.$event->getTransition()->getName(). ' ' . $event->getSubject()->getUuid()
);
}
}