custom/plugins/MolliePayments/src/Subscriber/CancelOrderSubscriber.php line 89

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Kiener\MolliePayments\Subscriber;
  3. use Kiener\MolliePayments\Factory\MollieApiFactory;
  4. use Kiener\MolliePayments\Service\OrderService;
  5. use Kiener\MolliePayments\Service\SettingsService;
  6. use Kiener\MolliePayments\Struct\Order\OrderAttributes;
  7. use Mollie\Api\Exceptions\ApiException;
  8. use Mollie\Api\MollieApiClient;
  9. use Mollie\Api\Types\OrderStatus;
  10. use Psr\Log\LoggerInterface;
  11. use Shopware\Core\Framework\Api\Context\SalesChannelApiSource;
  12. use Shopware\Core\System\StateMachine\Aggregation\StateMachineTransition\StateMachineTransitionActions;
  13. use Shopware\Core\System\StateMachine\Event\StateMachineStateChangeEvent;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. class CancelOrderSubscriber implements EventSubscriberInterface
  16. {
  17.     /**
  18.      * These Shopware actions will automatically trigger
  19.      * our cancellation (if enabled in the config).
  20.      */
  21.     public const AUTOMATIC_TRIGGER_ACTIONS = [
  22.         StateMachineTransitionActions::ACTION_CANCEL
  23.     ];
  24.     /**
  25.      * Cancellations are only done for these Mollie states.
  26.      */
  27.     public const ALLOWED_CANCELLABLE_MOLLIE_STATES = [
  28.         OrderStatus::STATUS_CREATED,
  29.         OrderStatus::STATUS_AUTHORIZED,
  30.         OrderStatus::STATUS_SHIPPING
  31.     ];
  32.     /**
  33.      * @var OrderService
  34.      */
  35.     private $orderService;
  36.     /**
  37.      * @var MollieApiFactory
  38.      */
  39.     private $apiFactory;
  40.     /**
  41.      * @var SettingsService
  42.      */
  43.     private $settingsService;
  44.     /**
  45.      * @var LoggerInterface
  46.      */
  47.     private $logger;
  48.     /**
  49.      * @param MollieApiFactory $apiFactory
  50.      * @param OrderService $orderService
  51.      * @param SettingsService $settingsService
  52.      * @param LoggerInterface $loggerService
  53.      */
  54.     public function __construct(MollieApiFactory $apiFactoryOrderService $orderServiceSettingsService $settingsServiceLoggerInterface $loggerService)
  55.     {
  56.         $this->orderService $orderService;
  57.         $this->apiFactory $apiFactory;
  58.         $this->settingsService $settingsService;
  59.         $this->logger $loggerService;
  60.     }
  61.     /**
  62.      * @return array<mixed>
  63.      */
  64.     public static function getSubscribedEvents(): array
  65.     {
  66.         return [
  67.             'state_machine.order.state_changed' => ['onOrderStateChanges']
  68.         ];
  69.     }
  70.     /**
  71.      * @param StateMachineStateChangeEvent $event
  72.      * @return void
  73.      */
  74.     public function onOrderStateChanges(StateMachineStateChangeEvent $event): void
  75.     {
  76.         if ($event->getTransitionSide() !== StateMachineStateChangeEvent::STATE_MACHINE_TRANSITION_SIDE_ENTER) {
  77.             return;
  78.         }
  79.         $apiSource $event->getContext()->getSource();
  80.         if ($apiSource instanceof SalesChannelApiSource) {
  81.             # do NOT cancel directly within the context of a Storefront
  82.             # the user might retry the payment if the first one is cancelled
  83.             # and we must never cancel the full order, because then he cannot retry the payment.
  84.             return;
  85.         }
  86.         $transitionName $event->getTransition()->getTransitionName();
  87.         try {
  88.             # if we don't have at least one of our
  89.             # actions that automatically trigger this feature, continue
  90.             if (!in_array($transitionNameself::AUTOMATIC_TRIGGER_ACTIONStrue)) {
  91.                 return;
  92.             }
  93.             # get order and extract our Mollie Order ID
  94.             $order $this->orderService->getOrder($event->getTransition()->getEntityId(), $event->getContext());
  95.             # -----------------------------------------------------------------------------------------------------------------------
  96.             # check if we have activated this feature in our plugin configuration
  97.             $settings $this->settingsService->getSettings($order->getSalesChannelId());
  98.             if (!$settings->isAutomaticCancellation()) {
  99.                 return;
  100.             }
  101.             # -----------------------------------------------------------------------------------------------------------------------
  102.             $orderAttributes = new OrderAttributes($order);
  103.             $mollieOrderId $orderAttributes->getMollieOrderId();
  104.             # if we don't have a Mollie Order ID continue
  105.             # this can also happen for subscriptions where we only have a tr_xxx Transaction ID.
  106.             # but cancellation only works on orders anyway
  107.             if (empty($mollieOrderId)) {
  108.                 return;
  109.             }
  110.             # -----------------------------------------------------------------------------------------------------------------------
  111.             $apiClient $this->apiFactory->getClient($order->getSalesChannelId());
  112.             $mollieOrder $apiClient->orders->get($mollieOrderId);
  113.             # check if the status of the Mollie order allows
  114.             # a cancellation based on our whitelist.
  115.             if (in_array($mollieOrder->statusself::ALLOWED_CANCELLABLE_MOLLIE_STATEStrue)) {
  116.                 $this->logger->debug('Starting auto-cancellation of order: ' $order->getOrderNumber() . ', ' $mollieOrderId);
  117.                 $apiClient->orders->cancel($mollieOrderId);
  118.                 $this->logger->info('Auto-cancellation of order: ' $order->getOrderNumber() . ', ' $mollieOrderId ' successfully executed after transition: ' $transitionName);
  119.             }
  120.         } catch (ApiException $e) {
  121.             $this->logger->error(
  122.                 'Error when executing auto-cancellation of an order after transition: ' $transitionName,
  123.                 [
  124.                     'error' => $e,
  125.                 ]
  126.             );
  127.         }
  128.     }
  129. }