vendor/bluue/sales-bundle/src/EventSubscriber/CustomerEditSubscriber.php line 304

Open in your IDE?
  1. <?php
  2. /**
  3.  * @author Thomas HERISSON (contact@scaledev.fr)
  4.  * @copyright 2021 - ScaleDEV SAS, 12 RUE CHARLES MORET, 10120 ST ANDRE LES VERGERS
  5.  * @license commercial
  6.  */
  7. declare(strict_types=1);
  8. namespace Bluue\SalesBundle\EventSubscriber;
  9. use App\Entity\TaxRule;
  10. use Bluue\SalesBundle\Entity\Order;
  11. use App\Services\CheckBundleInstall;
  12. use Bluue\SalesBundle\Entity\OrderState;
  13. use Bluue\SalesBundle\Entity\PaymentMethod;
  14. use Bluue\SalesBundle\Entity\PaymentTerm;
  15. use Bluue\SalesBundle\Services\Document;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Bluue\CustomersBundle\Entity\Customer;
  18. use Bluue\SalesBundle\Entity\DeliveryNote;
  19. use Symfony\Bridge\Doctrine\Form\Type\EntityType;
  20. use Symfony\Component\Security\Core\Security;
  21. use Bluue\SalesBundle\Repository\OrderRepository;
  22. use Bluue\CustomersBundle\Event\CustomerEditEvent;
  23. use Symfony\Component\HttpFoundation\RequestStack;
  24. use Symfony\Contracts\Translation\TranslatorInterface;
  25. use Bluue\SalesBundle\Repository\DeliveryNoteRepository;
  26. use Bluue\SalesBundle\Repository\CustomerOptionsRepository;
  27. use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
  28. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  29. use Doctrine\ORM\Query\Expr\Join;
  30. class CustomerEditSubscriber implements EventSubscriberInterface
  31. {
  32.     /**
  33.      * @var TranslatorInterface
  34.      */
  35.     private TranslatorInterface $tr;
  36.     /**
  37.      * @var RequestStack
  38.      */
  39.     protected RequestStack $requestStack;
  40.     /**
  41.      * @var Security
  42.      */
  43.     private Security $security;
  44.     /**
  45.      * @var CustomerOptionsRepository
  46.      */
  47.     private CustomerOptionsRepository $customerOptionsRepo;
  48.     /**
  49.      * @var EntityManagerInterface
  50.      */
  51.     private EntityManagerInterface $em;
  52.     /**
  53.      * @param RequestStack $requestStack
  54.      * @param TranslatorInterface $tr
  55.      * @param Security $security
  56.      * @param CustomerOptionsRepository $customerOptionsRepo
  57.      * @param EntityManagerInterface $em
  58.      */
  59.     public function __construct(
  60.         RequestStack $requestStack,
  61.         TranslatorInterface $tr,
  62.         Security $security,
  63.         CustomerOptionsRepository $customerOptionsRepo,
  64.         EntityManagerInterface $em
  65.     ) {
  66.         $this->requestStack $requestStack;
  67.         $this->tr $tr;
  68.         $this->security $security;
  69.         $this->customerOptionsRepo $customerOptionsRepo;
  70.         $this->em $em;
  71.     }
  72.     /**
  73.      * @return string[]
  74.      */
  75.     public static function getSubscribedEvents(): array
  76.     {
  77.         return [
  78.             CustomerEditEvent::PRE_SET_DATA => 'addFields',
  79.             CustomerEditEvent::POST_SUBMIT => 'postSubmit',
  80.             CustomerEditEvent::TABS => 'tabs'
  81.         ];
  82.     }
  83.     /**
  84.      * @param CustomerEditEvent $event
  85.      * @return void
  86.      */
  87.     public function addFields(CustomerEditEvent $event): void
  88.     {
  89.         if (!$this->security->isGranted('ROLE__SALES__READ_ONLY')) {
  90.             return;
  91.         }
  92.         $switchAttrs = [
  93.             'required' => false,
  94.             'mapped' => false,
  95.             'label_attr' => [
  96.                 'class' => 'custom-control-label cursor-pointer'
  97.             ],
  98.             'row_attr' => [
  99.                 'class' => 'custom-control custom-switch pl-3 mb-0'
  100.             ],
  101.             'attr' => [
  102.                 'class' => 'custom-control-input'
  103.             ]
  104.         ];
  105.         $builder $event->getBuilder();
  106.         $customer $builder->getOptions()['data'];
  107.         if ($customer instanceof Customer) {
  108.             $customerOptions $this->customerOptionsRepo->findOneBy([
  109.                 'customer' => $customer
  110.             ]);
  111.         }
  112.         $builder
  113.             ->add(
  114.                 'forQuotation',
  115.                 CheckboxType::class,
  116.                 array_merge([
  117.                     'label' => $this->tr->trans('Quotation', [], 'SalesBundle'),
  118.                     'data' => !empty($customerOptions) && $customerOptions->isForQuotation()
  119.                 ], $switchAttrs)
  120.             )
  121.             ->add(
  122.                 'forOrder',
  123.                 CheckboxType::class,
  124.                 array_merge([
  125.                     'label' => $this->tr->trans('Order', [], 'SalesBundle'),
  126.                     'data' => !empty($customerOptions) && $customerOptions->isForOrder()
  127.                 ], $switchAttrs)
  128.             )
  129.             ->add(
  130.                 'forDeliveryNote',
  131.                 CheckboxType::class,
  132.                 array_merge([
  133.                     'label' => $this->tr->trans('Delivery note', [], 'SalesBundle'),
  134.                     'data' => !empty($customerOptions) && $customerOptions->isForDeliveryNote()
  135.                 ], $switchAttrs)
  136.             )
  137.             ->add(
  138.                 'forInvoice',
  139.                 CheckboxType::class,
  140.                 array_merge([
  141.                     'label' => $this->tr->trans('Invoice', [], 'SalesBundle'),
  142.                     'data' => !empty($customerOptions) && $customerOptions->isForInvoice()
  143.                 ], $switchAttrs)
  144.             )
  145.             ->add(
  146.                 'forCreditNote',
  147.                 CheckboxType::class,
  148.                 array_merge([
  149.                     'label' => $this->tr->trans('Credit note', [], 'SalesBundle'),
  150.                     'data' => !empty($customerOptions) && $customerOptions->isForCreditNote()
  151.                 ], $switchAttrs)
  152.             );
  153.         if (!$customer->getParent()) {
  154.             $builder
  155.                 ->add('defaultPaymentMethod'EntityType::class, [
  156.                     'label' => $this->tr->trans('Default payment method', [], 'SalesBundle'),
  157.                     'required' => false,
  158.                     'mapped' => false,
  159.                     'class' => PaymentMethod::class,
  160.                     'choice_label' => 'name',
  161.                     'placeholder' => $this->tr->trans('No payment method', [], 'SalesBundle'),
  162.                     'data' => !empty($customerOptions) ? $customerOptions->getDefaultPaymentMethod() : null
  163.                 ])
  164.                 ->add('defaultPaymentTerm'EntityType::class, [
  165.                     'label' => $this->tr->trans('Default payment term', [], 'SalesBundle'),
  166.                     'required' => false,
  167.                     'mapped' => false,
  168.                     'class' => PaymentTerm::class,
  169.                     'choice_label' => 'name',
  170.                     'placeholder' => $this->tr->trans('No payment term', [], 'SalesBundle'),
  171.                     'data' => !empty($customerOptions) ? $customerOptions->getDefaultPaymentTerm() : null
  172.                 ])
  173.                 ->add('defaultOrderState'EntityType::class, [
  174.                     'label' => $this->tr->trans('Default order state', [], 'SalesBundle'),
  175.                     'required' => false,
  176.                     'mapped' => false,
  177.                     'class' => OrderState::class,
  178.                     'choice_label' => 'name',
  179.                     'placeholder' => $this->tr->trans('No order state', [], 'SalesBundle'),
  180.                     'data' => !empty($customerOptions) ? $customerOptions->getDefaultOrderState() : null
  181.                 ])
  182.                 ->add('defaultReducedTaxRule'EntityType::class, [
  183.                     'label' => $this->tr->trans('Default reduced tax rule', [], 'SalesBundle'),
  184.                     'required' => false,
  185.                     'mapped' => false,
  186.                     'class' => TaxRule::class,
  187.                     'choice_label' => 'name',
  188.                     'placeholder' => $this->tr->trans('No tax rule', [], 'SalesBundle'),
  189.                     'data' => !empty($customerOptions) ? $customerOptions->getDefaultReducedTaxRule() : null
  190.                 ])
  191.                 ->add('defaultReducedVat'CheckboxType::class, array_merge([
  192.                     'label' => $this->tr->trans('Default reduced VAT', [], 'SalesBundle'),
  193.                     'data' => !empty($customerOptions) && $customerOptions->isDefaultReducedVat()
  194.                 ], $switchAttrs))
  195.                 ->add('relaunchUnpaidInvoices'CheckboxType::class, array_merge([
  196.                     'label' => $this->tr->trans('Relaunch unpaid invoices', [], 'SalesBundle'),
  197.                     'data' => !empty($customerOptions) && $customerOptions->isRelaunchUnpaidInvoices()
  198.                 ], $switchAttrs))
  199.             ;
  200.         }
  201.         $event->setBuilder($builder);
  202.     }
  203.     /**
  204.      * @param CustomerEditEvent $event
  205.      * @return void
  206.      */
  207.     public function postSubmit(CustomerEditEvent $event): void
  208.     {
  209.         if (!$this->security->isGranted('ROLE__SALES__READ_ONLY')) {
  210.             return;
  211.         }
  212.         $form $event->getForm();
  213.         $customer $form->getData();
  214.         if ($customer instanceof Customer) {
  215.             $options = [
  216.                 'setForQuotation' => $form->get('forQuotation')->getData(),
  217.                 'setForOrder' => $form->get('forOrder')->getData(),
  218.                 'setForDeliveryNote' => $form->get('forDeliveryNote')->getData(),
  219.                 'setForInvoice' => $form->get('forInvoice')->getData(),
  220.                 'setForCreditNote' => $form->get('forCreditNote')->getData()
  221.             ];
  222.             if (!$customer->getParent()) {
  223.                 $options['setDefaultPaymentMethod'] = $form->get('defaultPaymentMethod')->getData();
  224.                 $options['setDefaultPaymentTerm'] = $form->get('defaultPaymentTerm')->getData();
  225.                 $options['setDefaultOrderState'] = $form->get('defaultOrderState')->getData();
  226.                 $options['setDefaultReducedTaxRule'] = $form->get('defaultReducedTaxRule')->getData();
  227.                 $options['setDefaultReducedVat'] = $form->get('defaultReducedVat')->getData();
  228.                 $options['setRelaunchUnpaidInvoices'] = $form->get('relaunchUnpaidInvoices')->getData();
  229.             }
  230.             $this->customerOptionsRepo->addOptions($customer$options);
  231.             if ($customer->getParent()) {
  232.                 /** @var OrderRepository $orderRepo */
  233.                 $orderRepo $this->em->getRepository(Order::class);
  234.                 $ordersAssociated $orderRepo->createQueryBuilder('o')
  235.                     ->andWhere('o.delivery_address = :delivery_address')
  236.                     ->setParameter('delivery_address'$customer->getId()->toBinary())
  237.                     ->andWhere('o.validatedAt IS NOT NULL')
  238.                     ->join('o.lines''ol')
  239.                     ->andWhere('(ol.quantity - ol.quantity_delivered > 0 OR ol.quantity_delivered IS NULL)')
  240.                     ->getQuery()->getResult();
  241.                 foreach ($ordersAssociated as $order) {
  242.                     $options $order->getOptions();
  243.                     $options['delivery_address'] = Document::normalizeAddress($order->getDeliveryAddress());
  244.                     $order->setOptions($options);
  245.                     $this->em->persist($order);
  246.                 }
  247.                 if (CheckBundleInstall::exist('shipments-bundle')) {
  248.                     /** @var DeliveryNoteRepository $deliveryNoteRepo */
  249.                     $deliveryNoteRepo $this->em->getRepository(DeliveryNote::class);
  250.                     $deliveryNotesAssociated $deliveryNoteRepo->createQueryBuilder('dn')
  251.                         ->innerJoin(
  252.                             'ShipmentsBundle:OrderOptions',
  253.                             'op',
  254.                             Join::WITH,
  255.                             'dn = op.delivery_note AND op.status = 1'
  256.                         )
  257.                         ->andWhere('dn.delivery_address = :delivery_address')
  258.                         ->setParameter('delivery_address'$customer->getId()->toBinary())
  259.                         ->getQuery()->getResult()
  260.                     ;
  261.                     foreach ($deliveryNotesAssociated as $deliveryNote) {
  262.                         $deliveryNote->addOptions([
  263.                             'delivery_address' => Document::normalizeAddress($customer)
  264.                         ]);
  265.                     }
  266.                 }
  267.                 if (!empty($ordersAssociated) || !empty($deliveryNotesAssociated)) {
  268.                     $this->em->flush();
  269.                 }
  270.             }
  271.         }
  272.     }
  273.     /**
  274.      * @param CustomerEditEvent $event
  275.      * @return void
  276.      */
  277.     public function tabs(CustomerEditEvent $event): void
  278.     {
  279.         if (!$this->security->isGranted('ROLE__SALES__READ_ONLY')) {
  280.             return;
  281.         }
  282.         $tabs $event->getTabs();
  283.         $newTabs = [
  284.             [
  285.                 'template' => '@Sales/CustomersBundle/_options.html.twig',
  286.                 'name' => $this->tr->trans('Sales', [], 'SalesBundle'),
  287.                 'icon' => 'fas fa-money-bill-alt',
  288.                 'key' => 'sales'
  289.             ]
  290.         ];
  291.         $event->setTabs(array_merge($tabs$newTabs));
  292.     }
  293. }