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

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