custom/plugins/PolPaymentPayolutionSW6/src/EventListener/StateMachineEventListener.php line 170

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace PolPaymentPayolutionSW6\EventListener;
  4. use PolPaymentPayolutionSW6\Component\Configuration\ConfigurationServiceInterface;
  5. use PolPaymentPayolutionSW6\Component\CustomFields\CustomFieldsInterface;
  6. use PolPaymentPayolutionSW6\Component\DataHandler\OrderTransactionDataHandler\OrderTransactionDataHandlerInterface;
  7. use PolPaymentPayolutionSW6\Component\DataHandler\OrderTransactionStatusHandler\OrderTransactionStatusHandlerInterface;
  8. use PolPaymentPayolutionSW6\Component\Validator\PaymentMethodValidator\PaymentMethodValidatorInterface;
  9. use PolPaymentPayolutionSW6\Component\Validator\PaymentRequestValidator\PaymentRequestValidatorInterface;
  10. use PolPaymentPayolutionSW6\PayolutionApi\Client\Exception\InvalidXmlException;
  11. use PolPaymentPayolutionSW6\PayolutionApi\Process\Exception\ProcessFailedException;
  12. use PolPaymentPayolutionSW6\PayolutionApi\Request\RequestFactory\PaymentRequestFactoryInterface;
  13. use PolPaymentPayolutionSW6\PayolutionApi\Request\RequestFactory\Transaction\TransactionRequestFactoryInterface;
  14. use PolPaymentPayolutionSW6\PayolutionApi\Request\RequestProcessor\RequestProcessorInterface;
  15. use Psr\Log\LoggerInterface;
  16. use Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryEntity;
  17. use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionEntity;
  18. use Shopware\Core\Framework\Context;
  19. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  21. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  22. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  23. use Shopware\Core\System\StateMachine\Event\StateMachineStateChangeEvent;
  24. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  25. class StateMachineEventListener implements EventSubscriberInterface
  26. {
  27.     /**
  28.      * @var EntityRepositoryInterface
  29.      */
  30.     private $orderTransactionRepository;
  31.     /**
  32.      * @var EntityRepositoryInterface
  33.      */
  34.     private $orderDeliveryRepository;
  35.     /**
  36.      * @var OrderTransactionDataHandlerInterface
  37.      */
  38.     private $orderTransactionDataHandler;
  39.     /**
  40.      * @var OrderTransactionStatusHandlerInterface
  41.      */
  42.     private $orderTransactionStatusHandler;
  43.     /**
  44.      * @var TransactionRequestFactoryInterface
  45.      */
  46.     private $transactionRequestFactory;
  47.     /**
  48.      * @var PaymentRequestFactoryInterface
  49.      */
  50.     private $paymentRequestFactory;
  51.     /**
  52.      * @var RequestProcessorInterface
  53.      */
  54.     private $captureRequestProcessor;
  55.     /**
  56.      * @var RequestProcessorInterface
  57.      */
  58.     private $refundRequestProcessor;
  59.     /**
  60.      * @var RequestProcessorInterface
  61.      */
  62.     private $reversalRequestProcessor;
  63.     /**
  64.      * @var ConfigurationServiceInterface
  65.      */
  66.     private $configurationService;
  67.     /**
  68.      * @var PaymentMethodValidatorInterface
  69.      */
  70.     private $paymentMethodValidator;
  71.     /**
  72.      * @var LoggerInterface
  73.      */
  74.     private $logger;
  75.     public function __construct(
  76.         EntityRepositoryInterface $orderTransactionRepository,
  77.         EntityRepositoryInterface $orderDeliveryRepository,
  78.         OrderTransactionDataHandlerInterface $orderTransactionDataHandler,
  79.         OrderTransactionStatusHandlerInterface $orderTransactionStatusHandler,
  80.         TransactionRequestFactoryInterface $transactionRequestFactory,
  81.         PaymentRequestFactoryInterface $paymentRequestFactory,
  82.         RequestProcessorInterface $captureRequestProcessor,
  83.         RequestProcessorInterface $refundRequestProcessor,
  84.         RequestProcessorInterface $reversalRequestProcessor,
  85.         ConfigurationServiceInterface $configurationService,
  86.         PaymentMethodValidatorInterface $paymentMethodValidator,
  87.         LoggerInterface $logger
  88.     ) {
  89.         $this->orderTransactionRepository $orderTransactionRepository;
  90.         $this->orderDeliveryRepository $orderDeliveryRepository;
  91.         $this->orderTransactionDataHandler $orderTransactionDataHandler;
  92.         $this->orderTransactionStatusHandler $orderTransactionStatusHandler;
  93.         $this->transactionRequestFactory $transactionRequestFactory;
  94.         $this->paymentRequestFactory $paymentRequestFactory;
  95.         $this->captureRequestProcessor $captureRequestProcessor;
  96.         $this->refundRequestProcessor $refundRequestProcessor;
  97.         $this->reversalRequestProcessor $reversalRequestProcessor;
  98.         $this->configurationService $configurationService;
  99.         $this->paymentMethodValidator $paymentMethodValidator;
  100.         $this->logger $logger;
  101.     }
  102.     public static function getSubscribedEvents(): array
  103.     {
  104.         return [
  105.             'state_machine.order.state_changed' => 'onOrderStateChange',
  106.             'state_machine.order_delivery.state_changed' => 'onOrderDeliveryStateChange',
  107.             'state_machine.order_transaction.state_changed' => 'onOrderTransactionStateChange',
  108.         ];
  109.     }
  110.     public function onOrderStateChange(StateMachineStateChangeEvent $event): void
  111.     {
  112.         $orderId $event->getTransition()->getEntityId();
  113.         try {
  114.             $orderTransaction $this->getOrderTransactionByOrderId($orderId$event->getContext());
  115.         } catch (\RuntimeException $e) {
  116.             $this->logger->error($e->getMessage());
  117.             return;
  118.         }
  119.         $this->handleOrderStatusChange(
  120.             $orderTransaction,
  121.             $event,
  122.             ConfigurationServiceInterface::ORDER_STATUS_CAPTURE,
  123.             ConfigurationServiceInterface::ORDER_STATUS_REFUND,
  124.             ConfigurationServiceInterface::ORDER_STATUS_REVERSAL
  125.         );
  126.     }
  127.     public function onOrderDeliveryStateChange(StateMachineStateChangeEvent $event): void
  128.     {
  129.         $orderDeliveryId $event->getTransition()->getEntityId();
  130.         try {
  131.             $orderTransaction $this->getOrderTransactionByDeliveryId($orderDeliveryId$event->getContext());
  132.         } catch (\RuntimeException $e) {
  133.             $this->logger->error($e->getMessage());
  134.             return;
  135.         }
  136.         $this->handleOrderStatusChange(
  137.             $orderTransaction,
  138.             $event,
  139.             ConfigurationServiceInterface::DELIVERY_STATUS_CAPTURE,
  140.             ConfigurationServiceInterface::DELIVERY_STATUS_REFUND,
  141.             ConfigurationServiceInterface::DELIVERY_STATUS_REVERSAL
  142.         );
  143.     }
  144.     public function onOrderTransactionStateChange(StateMachineStateChangeEvent $event): void
  145.     {
  146.         $orderTransactionId $event->getTransition()->getEntityId();
  147.         try {
  148.             $orderTransaction $this->getOrderTransactionById($orderTransactionId$event->getContext());
  149.         } catch (\RuntimeException $e) {
  150.             $this->logger->error($e->getMessage());
  151.             return;
  152.         }
  153.         $this->handleOrderStatusChange(
  154.             $orderTransaction,
  155.             $event,
  156.             ConfigurationServiceInterface::PAYMENT_STATUS_CAPTURE,
  157.             ConfigurationServiceInterface::PAYMENT_STATUS_REFUND,
  158.             ConfigurationServiceInterface::PAYMENT_STATUS_REVERSAL
  159.         );
  160.     }
  161.     private function handleOrderStatusChange(
  162.         OrderTransactionEntity $orderTransaction,
  163.         StateMachineStateChangeEvent $event,
  164.         string $configurationNameStatusCapture,
  165.         string $configurationNameStatusRefund,
  166.         string $configurationNameStatusReversal
  167.     ): void {
  168.         if (!$this->paymentMethodValidator->isPayolutionPaymentMethod($orderTransaction->getPaymentMethod())) {
  169.             return;
  170.         }
  171.         $salesChannelId $orderTransaction->getOrder()->getSalesChannel()->getId();
  172.         $context $event->getContext();
  173.         $statusCapture $this->configurationService->getConfiguration($configurationNameStatusCapture$salesChannelId);
  174.         if ($event->getTransition()->getTransitionName() === $statusCapture) {
  175.             $this->captureOrder($orderTransaction$context);
  176.             $this->orderTransactionStatusHandler->setPaid($orderTransaction$context);
  177.         }
  178.         $statusRefund $this->configurationService->getConfiguration($configurationNameStatusRefund$salesChannelId);
  179.         if ($event->getTransition()->getTransitionName() === $statusRefund) {
  180.             $this->refundOrder($orderTransaction$context);
  181.             $this->orderTransactionStatusHandler->setRefund($orderTransaction$context);
  182.         }
  183.         $statusReversal $this->configurationService->getConfiguration($configurationNameStatusReversal$salesChannelId);
  184.         if ($event->getTransition()->getTransitionName() === $statusReversal) {
  185.             $this->reversalOrder($orderTransaction$context);
  186.             $this->orderTransactionStatusHandler->setCancelled($orderTransaction$context);
  187.         }
  188.     }
  189.     private function captureOrder(OrderTransactionEntity $orderTransactionContext $context): void
  190.     {
  191.         try {
  192.             if ((bool) $orderTransaction->getCustomFields()[CustomFieldsInterface::IS_PAYMENT_CAPTURED]) {
  193.                 return;
  194.             }
  195.             $transaction $this->transactionRequestFactory->createTransaction(
  196.                 $orderTransaction,
  197.                 new RequestDataBag(),
  198.                 $orderTransaction->getAmount()->getTotalPrice(),
  199.                 null,
  200.                 [PaymentRequestValidatorInterface::IS_CAPTURE_REQUEST => true]
  201.             );
  202.             $captureRequest $this->paymentRequestFactory->createRequest($orderTransaction$transaction$orderTransaction->getOrder()->getSalesChannel()->getId());
  203.             $captureRequest->setPreAuthorizationUniqueId($orderTransaction->getCustomFields()[CustomFieldsInterface::UNIQUE_ID]);
  204.             $captureResponse $this->captureRequestProcessor->processRequest($captureRequest);
  205.             $this->orderTransactionDataHandler->updateOrderTransactionData($orderTransaction$context, [
  206.                 CustomFieldsInterface::IS_PAYMENT_CAPTURED => true,
  207.                 CustomFieldsInterface::REMAINING_CAPTURE_AMOUNT => 0,
  208.                 CustomFieldsInterface::REMAINING_REFUND_AMOUNT => $orderTransaction->getAmount()->getTotalPrice(),
  209.             ]);
  210.             foreach ($orderTransaction->getOrder()->getLineItems() as $orderLineItem) {
  211.                 $this->orderTransactionDataHandler->updateOrderLineItemData($orderLineItem$context, [CustomFieldsInterface::IS_PAYMENT_CAPTURED => true]);
  212.             }
  213.             $this->logger->info('order successfully captured'$captureResponse->getResponseAsArray());
  214.         } catch (InvalidXmlException $xmlException) {
  215.             $this->logger->error('order could not captured invalid xml', ['message' => $xmlException->getMessage()]);
  216.         } catch (ProcessFailedException $processFailedException) {
  217.             $this->logger->error('order could not captured process failed'$processFailedException->getResponse()->getResponseAsArray());
  218.         } catch (\Throwable $e) {
  219.             $this->logger->error('order could not captured error occurred', ['message' => $e->getMessage()]);
  220.         }
  221.     }
  222.     private function refundOrder(OrderTransactionEntity $orderTransactionContext $context): void
  223.     {
  224.         try {
  225.             if ((bool) $orderTransaction->getCustomFields()[CustomFieldsInterface::IS_PAYMENT_REFUNDED]) {
  226.                 return;
  227.             }
  228.             $transaction $this->transactionRequestFactory->createTransaction(
  229.                 $orderTransaction,
  230.                 new RequestDataBag(),
  231.                 $orderTransaction->getAmount()->getTotalPrice(),
  232.                 null,
  233.                 [PaymentRequestValidatorInterface::IS_REFUND_REQUEST => true]
  234.             );
  235.             $refundRequest $this->paymentRequestFactory->createRequest($orderTransaction$transaction$orderTransaction->getOrder()->getSalesChannel()->getId());
  236.             $refundRequest->setPreAuthorizationUniqueId($orderTransaction->getCustomFields()[CustomFieldsInterface::UNIQUE_ID]);
  237.             $refundResponse $this->refundRequestProcessor->processRequest($refundRequest);
  238.             $this->orderTransactionDataHandler->updateOrderTransactionData($orderTransaction$context, [
  239.                 CustomFieldsInterface::IS_PAYMENT_REFUNDED => true,
  240.                 CustomFieldsInterface::REMAINING_REFUND_AMOUNT => 0,
  241.             ]);
  242.             foreach ($orderTransaction->getOrder()->getLineItems() as $orderLineItem) {
  243.                 $this->orderTransactionDataHandler->updateOrderLineItemData($orderLineItem$context, [CustomFieldsInterface::IS_PAYMENT_REFUNDED => true]);
  244.             }
  245.             $this->logger->info('order successfully refunded'$refundResponse->getResponseAsArray());
  246.         } catch (InvalidXmlException $xmlException) {
  247.             $this->logger->error('order could not refunded invalid xml', ['message' => $xmlException->getMessage()]);
  248.         } catch (ProcessFailedException $processFailedException) {
  249.             $this->logger->error('order could not refunded process failed'$processFailedException->getResponse()->getResponseAsArray());
  250.         } catch (\Throwable $e) {
  251.             $this->logger->error('order could not refunded error occurred', ['message' => $e->getMessage()]);
  252.         }
  253.     }
  254.     private function reversalOrder(OrderTransactionEntity $orderTransactionContext $context): void
  255.     {
  256.         try {
  257.             if ((bool) $orderTransaction->getCustomFields()[CustomFieldsInterface::IS_PAYMENT_CANCELLED]) {
  258.                 return;
  259.             }
  260.             $transaction $this->transactionRequestFactory->createTransaction(
  261.                 $orderTransaction,
  262.                 new RequestDataBag(),
  263.                 $orderTransaction->getAmount()->getTotalPrice(),
  264.                 null,
  265.                 [PaymentRequestValidatorInterface::IS_REVERSAL_REQUEST => true]
  266.             );
  267.             $reversalRequest $this->paymentRequestFactory->createRequest($orderTransaction$transaction$orderTransaction->getOrder()->getSalesChannel()->getId());
  268.             $reversalRequest->setPreAuthorizationUniqueId($orderTransaction->getCustomFields()[CustomFieldsInterface::UNIQUE_ID]);
  269.             $reversalResponse $this->reversalRequestProcessor->processRequest($reversalRequest);
  270.             $this->orderTransactionDataHandler->updateOrderTransactionData($orderTransaction$context, [
  271.                 CustomFieldsInterface::IS_PAYMENT_CANCELLED => true,
  272.             ]);
  273.             $this->logger->info('order successfully cancelled'$reversalResponse->getResponseAsArray());
  274.         } catch (InvalidXmlException $xmlException) {
  275.             $this->logger->error('order could not cancelled invalid xml', ['message' => $xmlException->getMessage()]);
  276.         } catch (ProcessFailedException $processFailedException) {
  277.             $this->logger->error('order could not cancelled process failed'$processFailedException->getResponse()->getResponseAsArray());
  278.         } catch (\Throwable $e) {
  279.             $this->logger->error('order could not cancelled error occurred', ['message' => $e->getMessage()]);
  280.         }
  281.     }
  282.     private function getOrderTransactionById(string $idContext $context): OrderTransactionEntity
  283.     {
  284.         $criteria = new Criteria();
  285.         $criteria->addFilter(new EqualsFilter('id'$id));
  286.         $criteria->addAssociations(['order.customer''order.currency''order.lineItems''order.deliveries''order.salesChannel''paymentMethod']);
  287.         /** @var OrderTransactionEntity $orderTransaction */
  288.         $orderTransaction $this->orderTransactionRepository->search($criteria$context)->first();
  289.         if ($orderTransaction === null) {
  290.             throw new \RuntimeException(sprintf('order transaction by id %s not found.'$id));
  291.         }
  292.         return $orderTransaction;
  293.     }
  294.     private function getOrderTransactionByOrderId(string $orderIdContext $context): OrderTransactionEntity
  295.     {
  296.         $criteria = new Criteria();
  297.         $criteria->addFilter(new EqualsFilter('orderId'$orderId));
  298.         $criteria->addAssociations(['order.customer''order.currency''order.lineItems''order.deliveries''order.salesChannel''paymentMethod']);
  299.         /** @var OrderTransactionEntity $orderTransaction */
  300.         $orderTransaction $this->orderTransactionRepository->search($criteria$context)->first();
  301.         if ($orderTransaction === null) {
  302.             throw new \RuntimeException(sprintf('order transaction by order id %s not found.'$orderId));
  303.         }
  304.         return $orderTransaction;
  305.     }
  306.     private function getOrderTransactionByDeliveryId(string $deliveryIdContext $context): OrderTransactionEntity
  307.     {
  308.         $criteria = new Criteria();
  309.         $criteria->addFilter(new EqualsFilter('id'$deliveryId));
  310.         $criteria->addAssociations(['order''order.transactions']);
  311.         /** @var OrderDeliveryEntity $orderDeliveryEntity */
  312.         $orderDeliveryEntity $this->orderDeliveryRepository->search($criteria$context)->first();
  313.         if ($orderDeliveryEntity === null) {
  314.             throw new \RuntimeException(sprintf('order delivery by delivery id %s not found.'$deliveryId));
  315.         }
  316.         /** @var OrderTransactionEntity $orderTransaction */
  317.         $orderTransaction $orderDeliveryEntity->getOrder()->getTransactions()->first();
  318.         if (!$orderTransaction instanceof OrderTransactionEntity) {
  319.             throw new \RuntimeException(sprintf('order transaction by delivery id %s not found.'$deliveryId));
  320.         }
  321.         return $this->getOrderTransactionByOrderId($orderTransaction->getOrderId(), $context);
  322.     }
  323. }