custom/plugins/NetiNextEasyCoupon/src/Subscriber/OrderSubscriber.php line 252

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (c) 2020, Net Inventors GmbH
  4.  * @category  Shopware
  5.  * @author    mpeters
  6.  */
  7. declare(strict_types=1);
  8. namespace NetInventors\NetiNextEasyCoupon\Subscriber;
  9. use NetInventors\NetiNextEasyCoupon\Core\Content\EasyCoupon\EasyCouponEntity;
  10. use NetInventors\NetiNextEasyCoupon\Core\Framework\Exception\InvalidTypeException;
  11. use NetInventors\NetiNextEasyCoupon\Service\OrderVoucherService;
  12. use NetInventors\NetiNextEasyCoupon\Service\PluginConfigFactory;
  13. use NetInventors\NetiNextEasyCoupon\Service\RedemptionAndChargebackTransactionsService;
  14. use NetInventors\NetiNextEasyCoupon\Service\Repository\VoucherRepository;
  15. use NetInventors\NetiNextEasyCoupon\Service\RequestedDelivery\RequestedDeliveryMailer;
  16. use NetInventors\NetiNextEasyCoupon\Service\RequestedDelivery\RequestedDeliveryProcessor;
  17. use NetInventors\NetiNextEasyCoupon\Service\SalesChannelContextRestorer;
  18. use NetInventors\NetiNextEasyCoupon\Struct\PluginConfigStruct;
  19. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  20. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemCollection;
  21. use Shopware\Core\Checkout\Order\OrderEntity;
  22. use Shopware\Core\Defaults;
  23. use Shopware\Core\Framework\Api\Context\SalesChannelApiSource;
  24. use Shopware\Core\Framework\Context;
  25. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  26. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  27. use Shopware\Core\System\SalesChannel\Context\AbstractSalesChannelContextFactory;
  28. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;
  29. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  30. use Shopware\Core\System\SalesChannel\Event\SalesChannelContextSwitchEvent;
  31. use Shopware\Core\System\StateMachine\Event\StateMachineStateChangeEvent;
  32. use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
  33. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  34. use Symfony\Component\HttpFoundation\RequestStack;
  35. class OrderSubscriber implements EventSubscriberInterface
  36. {
  37.     protected PluginConfigStruct                         $pluginConfig;
  38.     protected OrderVoucherService                        $orderVoucherService;
  39.     private RequestStack                                 $requestStack;
  40.     private SalesChannelContextServiceInterface          $salesChannelContextService;
  41.     private AbstractSalesChannelContextFactory           $salesChannelContextFactory;
  42.     private EntityRepositoryInterface                    $orderRepository;
  43.     protected RedemptionAndChargebackTransactionsService $redemptionAndChargebackTransactionsService;
  44.     private VoucherRepository                            $voucherRepository;
  45.     private RequestedDeliveryProcessor                   $deliveryProcessor;
  46.     private RequestedDeliveryMailer                      $deliveryMailer;
  47.     private PluginConfigFactory                          $pluginConfigFactory;
  48.     private string                                       $swVersion;
  49.     private SalesChannelContextRestorer                  $salesChannelContextRestorer;
  50.     public function __construct(
  51.         PluginConfigStruct                         $pluginConfig,
  52.         OrderVoucherService                        $orderVoucherService,
  53.         RequestStack                               $requestStack,
  54.         SalesChannelContextServiceInterface        $salesChannelContextService,
  55.         AbstractSalesChannelContextFactory         $salesChannelContextFactory,
  56.         EntityRepositoryInterface                  $orderRepository,
  57.         RedemptionAndChargebackTransactionsService $redemptionAndChargebackTransactionsService,
  58.         VoucherRepository                          $voucherRepository,
  59.         RequestedDeliveryProcessor                 $deliveryProcessor,
  60.         RequestedDeliveryMailer                    $deliveryMailer,
  61.         PluginConfigFactory                        $pluginConfigFactory,
  62.         ?string                                    $swVersion,
  63.         SalesChannelContextRestorer                $salesChannelContextRestorer
  64.     ) {
  65.         $this->pluginConfig                               $pluginConfig;
  66.         $this->orderVoucherService                        $orderVoucherService;
  67.         $this->requestStack                               $requestStack;
  68.         $this->salesChannelContextService                 $salesChannelContextService;
  69.         $this->orderRepository                            $orderRepository;
  70.         $this->salesChannelContextFactory                 $salesChannelContextFactory;
  71.         $this->redemptionAndChargebackTransactionsService $redemptionAndChargebackTransactionsService;
  72.         $this->voucherRepository                          $voucherRepository;
  73.         $this->deliveryProcessor                          $deliveryProcessor;
  74.         $this->deliveryMailer                             $deliveryMailer;
  75.         $this->pluginConfigFactory                        $pluginConfigFactory;
  76.         $this->swVersion                                  = (string) $swVersion;
  77.         $this->salesChannelContextRestorer                $salesChannelContextRestorer;
  78.     }
  79.     public static function getSubscribedEvents(): array
  80.     {
  81.         return [
  82.             CheckoutOrderPlacedEvent::class => [
  83.                 [ 'createVoucherByLineItems'],
  84.                 [ 'createTransactions'5000 ],
  85.             ],
  86.             'state_machine.order_transaction.state_changed' => [
  87.                 'sendVoucherActivateMailByOrderTransaction',
  88.             ],
  89.             // @TODO Also remove redemption voucher on context switch
  90.             SalesChannelContextSwitchEvent::class           => [
  91.                 'removePurchaseVoucherFromCart',
  92.             ],
  93.             CheckoutFinishPageLoadedEvent::class => [
  94.                 [ 'displayPurchaseVouchers'],
  95.                 [ 'displayVoucherRestValue'5000 ],
  96.                 [ 'removeVoucherCodesFromSession'9000 ],
  97.             ],
  98.             'order_line_item.written'           => 'onOrderLineItemWritten',
  99.             'state_machine.order.state_changed' => 'onOrderStateChange',
  100.         ];
  101.     }
  102.     /**
  103.      * @param StateMachineStateChangeEvent $event
  104.      *
  105.      * @return void
  106.      * @throws InvalidTypeException
  107.      */
  108.     public function onOrderStateChange(StateMachineStateChangeEvent $event): void
  109.     {
  110.         $order               $this->getOrder($event->getTransition()->getEntityId(), $event->getContext());
  111.         $pluginConfigOfOrder $this->pluginConfigFactory->create($order->getSalesChannelId());
  112.         if (!$pluginConfigOfOrder->isActive()) {
  113.             return;
  114.         }
  115.         $this->redemptionAndChargebackTransactionsService->chargebackTransaction(
  116.             $order,
  117.             $event->getContext(),
  118.             \in_array(
  119.                 $event->getNextState()->getId(),
  120.                 $pluginConfigOfOrder->getVoucherCancelOrderStatus(),
  121.                 true
  122.             )
  123.         );
  124.     }
  125.     protected function getOrder(string $orderIdContext $context): ?OrderEntity
  126.     {
  127.         $criteria = new Criteria([ $orderId ]);
  128.         $criteria->addAssociation('lineItems');
  129.         return $this->orderRepository->search($criteria$context)->first();
  130.     }
  131.     public function onOrderLineItemWritten(EntityWrittenEvent $event): void
  132.     {
  133.         // if the live version of the order_line_item is updated, the associated transaction should be updated, too.
  134.         foreach ($event->getWriteResults() as $writeResult) {
  135.             $existence $writeResult->getExistence();
  136.             if (null === $existence || !$existence->exists()) {
  137.                 continue; // we don't care about deleted items here
  138.             }
  139.             $payload $writeResult->getPayload();
  140.             if ($payload['versionId'] !== Defaults::LIVE_VERSION) {
  141.                 continue; // we only update the transaction if the live version order_line_item is updated
  142.             }
  143.             $this->orderVoucherService->updateTransactionValueFromOrderLineItem(
  144.                 $writeResult->getPrimaryKey(),
  145.                 $event->getContext()
  146.             );
  147.         }
  148.     }
  149.     public function createVoucherByLineItems(CheckoutOrderPlacedEvent $event): void
  150.     {
  151.         if (!$this->pluginConfig->isActive()) {
  152.             return;
  153.         }
  154.         if (!$event->getOrder()->getLineItems() instanceof OrderLineItemCollection) {
  155.             return;
  156.         }
  157.         if (!$this->isProperCheckoutOrderPlacedEvent($event)) {
  158.             return;
  159.         }
  160.         $filteredItems $this->orderVoucherService->filterLineItemsByEnteredValued($event->getOrder()->getLineItems());
  161.         if ([] === $filteredItems->getElements()) {
  162.             return;
  163.         }
  164.         $order               $event->getOrder();
  165.         $salesChannelContext $this->salesChannelContextRestorer->restoreSalesChannelByOrderContext(
  166.             $order->getSalesChannelId(),
  167.             $order->getLanguageId(),
  168.             $order
  169.         );
  170.         $this->orderVoucherService->createVoucherByLineItems(
  171.             $event->getOrder()->getLineItems(),
  172.             $salesChannelContext->getContext(),
  173.             $salesChannelContext,
  174.             $event->getOrder()
  175.         );
  176.     }
  177.     public function displayPurchaseVouchers(CheckoutFinishPageLoadedEvent $event): void
  178.     {
  179.         if (!$this->pluginConfig->isActive() || !$this->pluginConfig->isVouchersInfoAtCheckoutActive()) {
  180.             return;
  181.         }
  182.         $this->orderVoucherService->addPurchaseVouchersToCheckoutConfirmPage($event->getPage(), $event->getContext());
  183.     }
  184.     public function displayVoucherRestValue(CheckoutFinishPageLoadedEvent $event): void
  185.     {
  186.         if (!$this->pluginConfig->isActive() || !$this->pluginConfig->isVouchersInfoAtCheckoutActive()) {
  187.             return;
  188.         }
  189.         $this->orderVoucherService->displayVoucherRestValueAtCheckoutConfirmPage(
  190.             $event->getPage(),
  191.             $event->getContext(),
  192.             $event->getSalesChannelContext()
  193.         );
  194.     }
  195.     public function createTransactions(CheckoutOrderPlacedEvent $event): void
  196.     {
  197.         if (!$this->pluginConfig->isActive()) {
  198.             return;
  199.         }
  200.         if (!$this->isProperCheckoutOrderPlacedEvent($event)) {
  201.             return;
  202.         }
  203.         $this->orderVoucherService->createTransactionsForRedeemedVouchers($event->getOrder(), $event->getContext());
  204.     }
  205.     public function sendVoucherActivateMailByOrderTransaction(StateMachineStateChangeEvent $event): void
  206.     {
  207.         $context           $event->getContext();
  208.         $order             $this->orderVoucherService->getOrderFromTransactionId(
  209.             $event->getTransition()->getEntityId(),
  210.             $context
  211.         );
  212.         if ($order instanceof OrderEntity) {
  213.             $salesSalesContext $this->salesChannelContextRestorer->restoreSalesChannelByOrderContext(
  214.                 $order->getSalesChannelId(),
  215.                 $order->getLanguageId(),
  216.                 $order
  217.             );
  218.             $context $salesSalesContext->getContext();
  219.         }
  220.         /** @var array<string, EasyCouponEntity> $orderedVouchers */
  221.         $orderedVouchers $this->voucherRepository->collectOrderedVouchersByTransactionId(
  222.             $event->getTransition()->getEntityId(),
  223.             $context
  224.         )->getElements();
  225.         if ([] === $orderedVouchers) {
  226.             return;
  227.         }
  228.         if ($order instanceof OrderEntity) {
  229.             $orderPluginConfig $this->pluginConfigFactory->create($order->getSalesChannelId());
  230.         } else {
  231.             $orderPluginConfig $this->pluginConfig;
  232.         }
  233.         if (
  234.             !$orderPluginConfig->isActive()
  235.             || !\in_array($event->getNextState()->getId(), $orderPluginConfig->getVoucherActivatePaymentStatus(), true)
  236.         ) {
  237.             return;
  238.         }
  239.         if ($orderPluginConfig->isActivationMailRequired()) {
  240.             // Send voucher activation mails
  241.             $this->orderVoucherService->sendVoucherActivateMailByOrderTransaction(
  242.                 $orderedVouchers,
  243.                 $context
  244.             );
  245.         }
  246.         // Send requested delivery mails
  247.         $easyCouponIds array_map(static function(EasyCouponEntity $voucher) {
  248.             return $voucher->getId();
  249.         }, $orderedVouchers);
  250.         $deliveries $this->deliveryProcessor->collectDeliveries($context$easyCouponIds);
  251.         if (null === $deliveries) {
  252.             return;
  253.         }
  254.         $this->deliveryMailer->deliverVouchers($deliveries$context);
  255.     }
  256.     public function removePurchaseVoucherFromCart(SalesChannelContextSwitchEvent $event): void
  257.     {
  258.         if (!$this->pluginConfig->isActive()) {
  259.             return;
  260.         }
  261.         $currencyId $event->getRequestDataBag()->get('currencyId');
  262.         if (!(\is_string($currencyId) && '' !== $currencyId)) {
  263.             return;
  264.         }
  265.         $this->orderVoucherService->removePurchaseVoucherFromCart($event->getSalesChannelContext());
  266.     }
  267.     public function removeVoucherCodesFromSession(CheckoutFinishPageLoadedEvent $event): void
  268.     {
  269.         if (!$this->pluginConfig->isActive()) {
  270.             return;
  271.         }
  272.         $event->getRequest()->getSession()->remove('EasyCouponVoucherCodes');
  273.     }
  274.     private function isProperCheckoutOrderPlacedEvent(CheckoutOrderPlacedEvent $event): bool
  275.     {
  276.         $contextSource $event->getContext()->getSource();
  277.         $contextStates $event->getContext()->getStates();
  278.         return (
  279.             \version_compare($this->swVersion'6.4.11.0''<')
  280.             || !$contextSource instanceof SalesChannelApiSource
  281.             || (\in_array('checkout-order-route'$contextStatestrue))
  282.         );
  283.     }
  284. }