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

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Kiener\MolliePayments\Subscriber;
  4. use Kiener\MolliePayments\Factory\MollieApiFactory;
  5. use Kiener\MolliePayments\Service\OrderService;
  6. use Kiener\MolliePayments\Service\SettingsService;
  7. use Kiener\MolliePayments\Struct\Order\OrderAttributes;
  8. use Mollie\Api\Exceptions\ApiException;
  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.     public function __construct(MollieApiFactory $apiFactoryOrderService $orderServiceSettingsService $settingsServiceLoggerInterface $loggerService)
  49.     {
  50.         $this->orderService $orderService;
  51.         $this->apiFactory $apiFactory;
  52.         $this->settingsService $settingsService;
  53.         $this->logger $loggerService;
  54.     }
  55.     /**
  56.      * @return array<mixed>
  57.      */
  58.     public static function getSubscribedEvents(): array
  59.     {
  60.         return [
  61.             'state_machine.order.state_changed' => ['onOrderStateChanges'],
  62.         ];
  63.     }
  64.     public function onOrderStateChanges(StateMachineStateChangeEvent $event): void
  65.     {
  66.         if ($event->getTransitionSide() !== StateMachineStateChangeEvent::STATE_MACHINE_TRANSITION_SIDE_ENTER) {
  67.             return;
  68.         }
  69.         $apiSource $event->getContext()->getSource();
  70.         if ($apiSource instanceof SalesChannelApiSource) {
  71.             // do NOT cancel directly within the context of a Storefront
  72.             // the user might retry the payment if the first one is cancelled
  73.             // and we must never cancel the full order, because then he cannot retry the payment.
  74.             return;
  75.         }
  76.         $transitionName $event->getTransition()->getTransitionName();
  77.         try {
  78.             // if we don't have at least one of our
  79.             // actions that automatically trigger this feature, continue
  80.             if (! in_array($transitionNameself::AUTOMATIC_TRIGGER_ACTIONStrue)) {
  81.                 return;
  82.             }
  83.             // get order and extract our Mollie Order ID
  84.             $order $this->orderService->getOrder($event->getTransition()->getEntityId(), $event->getContext());
  85.             // -----------------------------------------------------------------------------------------------------------------------
  86.             // check if we have activated this feature in our plugin configuration
  87.             $settings $this->settingsService->getSettings($order->getSalesChannelId());
  88.             if (! $settings->isAutomaticCancellation()) {
  89.                 return;
  90.             }
  91.             // -----------------------------------------------------------------------------------------------------------------------
  92.             $orderAttributes = new OrderAttributes($order);
  93.             $mollieOrderId $orderAttributes->getMollieOrderId();
  94.             // if we don't have a Mollie Order ID continue
  95.             // this can also happen for subscriptions where we only have a tr_xxx Transaction ID.
  96.             // but cancellation only works on orders anyway
  97.             if (empty($mollieOrderId)) {
  98.                 return;
  99.             }
  100.             // -----------------------------------------------------------------------------------------------------------------------
  101.             $apiClient $this->apiFactory->getClient($order->getSalesChannelId());
  102.             $mollieOrder $apiClient->orders->get($mollieOrderId);
  103.             // check if the status of the Mollie order allows
  104.             // a cancellation based on our whitelist.
  105.             if (in_array($mollieOrder->statusself::ALLOWED_CANCELLABLE_MOLLIE_STATEStrue)) {
  106.                 $this->logger->debug('Starting auto-cancellation of order: ' $order->getOrderNumber() . ', ' $mollieOrderId);
  107.                 $apiClient->orders->cancel($mollieOrderId);
  108.                 $this->logger->info('Auto-cancellation of order: ' $order->getOrderNumber() . ', ' $mollieOrderId ' successfully executed after transition: ' $transitionName);
  109.             }
  110.         } catch (ApiException $e) {
  111.             $this->logger->error(
  112.                 'Error when executing auto-cancellation of an order after transition: ' $transitionName,
  113.                 [
  114.                     'error' => $e,
  115.                 ]
  116.             );
  117.         }
  118.     }
  119. }