custom/plugins/KlarnaPayment/src/Components/EventListener/SessionEventListener.php line 94

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace KlarnaPayment\Components\EventListener;
  4. use KlarnaPayment\Components\CartHasher\CartHasherInterface;
  5. use KlarnaPayment\Components\Client\ClientInterface;
  6. use KlarnaPayment\Components\Client\Hydrator\Request\CreateSession\CreateSessionRequestHydratorInterface;
  7. use KlarnaPayment\Components\Client\Hydrator\Struct\Address\AddressStructHydrator;
  8. use KlarnaPayment\Components\Client\Hydrator\Struct\Address\AddressStructHydratorInterface;
  9. use KlarnaPayment\Components\Client\Hydrator\Struct\Customer\CustomerStructHydratorInterface;
  10. use KlarnaPayment\Components\Client\Response\GenericResponse;
  11. use KlarnaPayment\Components\Client\Struct\Attachment;
  12. use KlarnaPayment\Components\Converter\CustomOrderConverter;
  13. use KlarnaPayment\Components\Extension\ErrorMessageExtension;
  14. use KlarnaPayment\Components\Extension\SessionDataExtension;
  15. use KlarnaPayment\Components\Factory\MerchantDataFactoryInterface;
  16. use KlarnaPayment\Components\Helper\OrderFetcherInterface;
  17. use KlarnaPayment\Components\Helper\PaymentHelper\PaymentHelperInterface;
  18. use KlarnaPayment\Installer\Modules\PaymentMethodInstaller;
  19. use LogicException;
  20. use Shopware\Core\Checkout\Cart\Cart;
  21. use Shopware\Core\Checkout\Order\OrderEntity;
  22. use Shopware\Core\Checkout\Payment\PaymentMethodEntity;
  23. use Shopware\Core\Framework\Context;
  24. use Shopware\Core\Framework\Struct\Struct;
  25. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  26. use Shopware\Storefront\Page\Account\Order\AccountEditOrderPageLoadedEvent;
  27. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
  28. use Shopware\Storefront\Page\Page;
  29. use Shopware\Storefront\Page\PageLoadedEvent;
  30. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  31. class SessionEventListener implements EventSubscriberInterface
  32. {
  33.     /** @var PaymentHelperInterface */
  34.     private $paymentHelper;
  35.     /** @var CreateSessionRequestHydratorInterface */
  36.     private $requestHydrator;
  37.     /** @var AddressStructHydratorInterface */
  38.     private $addressHydrator;
  39.     /** @var CustomerStructHydratorInterface */
  40.     private $customerHydrator;
  41.     /** @var ClientInterface */
  42.     private $client;
  43.     /** @var CartHasherInterface */
  44.     private $cartHasher;
  45.     /** @var MerchantDataFactoryInterface */
  46.     private $merchantDataFactory;
  47.     /** @var CustomOrderConverter */
  48.     private $orderConverter;
  49.     /** @var OrderFetcherInterface */
  50.     private $orderFetcher;
  51.     public function __construct(
  52.         PaymentHelperInterface $paymentHelper,
  53.         CreateSessionRequestHydratorInterface $requestHydrator,
  54.         AddressStructHydratorInterface $addressHydrator,
  55.         CustomerStructHydratorInterface $customerHydrator,
  56.         ClientInterface $client,
  57.         CartHasherInterface $cartHasher,
  58.         MerchantDataFactoryInterface $merchantDataFactory,
  59.         CustomOrderConverter $orderConverter,
  60.         OrderFetcherInterface $orderFetcher
  61.     ) {
  62.         $this->paymentHelper       $paymentHelper;
  63.         $this->requestHydrator     $requestHydrator;
  64.         $this->addressHydrator     $addressHydrator;
  65.         $this->customerHydrator    $customerHydrator;
  66.         $this->client              $client;
  67.         $this->cartHasher          $cartHasher;
  68.         $this->merchantDataFactory $merchantDataFactory;
  69.         $this->orderConverter      $orderConverter;
  70.         $this->orderFetcher        $orderFetcher;
  71.     }
  72.     public static function getSubscribedEvents(): array
  73.     {
  74.         return [
  75.             CheckoutConfirmPageLoadedEvent::class  => 'startKlarnaSession',
  76.             AccountEditOrderPageLoadedEvent::class => 'startKlarnaSession',
  77.         ];
  78.     }
  79.     public function startKlarnaSession(PageLoadedEvent $event): void
  80.     {
  81.         $context $event->getSalesChannelContext();
  82.         if (!$this->paymentHelper->isKlarnaPaymentsEnabled($context)) {
  83.             return;
  84.         }
  85.         if ($event instanceof CheckoutConfirmPageLoadedEvent) {
  86.             $cart $event->getPage()->getCart();
  87.         } elseif ($event instanceof AccountEditOrderPageLoadedEvent) {
  88.             /** @phpstan-ignore-next-line */
  89.             $cart $this->convertCartFromOrder($event->getPage()->getOrder(), $event->getContext());
  90.         } else {
  91.             return;
  92.         }
  93.         $response $this->createKlarnaSession($cart$context);
  94.         if ($response->getHttpStatus() !== 200) {
  95.             if ($this->paymentHelper->isKlarnaPaymentsSelected($context)) {
  96.                 $this->createErrorMessageExtension($event);
  97.             }
  98.             $this->removeAllKlarnaPaymentMethods($event->getPage());
  99.             return;
  100.         }
  101.         $this->createSessionDataExtension($response$event->getPage(), $cart$context);
  102.         $this->removeDisabledKlarnaPaymentMethods($event->getPage());
  103.         $this->filterPayNowMethods($event->getPage());
  104.     }
  105.     private function filterPayNowMethods(Struct $page): void
  106.     {
  107.         if (!($page instanceof Page)) {
  108.             return;
  109.         }
  110.         /** @var null|SessionDataExtension $sessionData */
  111.         $sessionData $page->getExtension(SessionDataExtension::EXTENSION_NAME);
  112.         if (null === $sessionData) {
  113.             return;
  114.         }
  115.         foreach ($sessionData->getPaymentMethodCategories() as $paymentCategory) {
  116.             if ($paymentCategory['identifier'] === PaymentMethodInstaller::KLARNA_PAYMENTS_PAY_NOW_CODE) {
  117.                 $this->removeSeparatePayNowKlarnaPaymentMethods($page);
  118.                 return;
  119.             }
  120.         }
  121.         $this->removeCombinedKlarnaPaymentPayNowMethod($page);
  122.     }
  123.     private function createErrorMessageExtension(PageLoadedEvent $event): void
  124.     {
  125.         $errorMessageExtension = new ErrorMessageExtension(ErrorMessageExtension::GENERIC_ERROR);
  126.         $event->getPage()->addExtension(ErrorMessageExtension::EXTENSION_NAME$errorMessageExtension);
  127.     }
  128.     private function createSessionDataExtension(GenericResponse $responseStruct $pageCart $cartSalesChannelContext $context): void
  129.     {
  130.         if (!($page instanceof Page)) {
  131.             return;
  132.         }
  133.         $sessionData = new SessionDataExtension();
  134.         $sessionData->assign([
  135.             'sessionId'                     => $response->getResponse()['session_id'],
  136.             'clientToken'                   => $response->getResponse()['client_token'],
  137.             'paymentMethodCategories'       => $response->getResponse()['payment_method_categories'],
  138.             'selectedPaymentMethodCategory' => $this->getKlarnaCodeFromPaymentMethod($context),
  139.             'cartHash'                      => $this->cartHasher->generate($cart$context),
  140.         ]);
  141.         if ($this->paymentHelper->isKlarnaPaymentsSelected($context)) {
  142.             $extraMerchantData $this->merchantDataFactory->getExtraMerchantData($sessionData$cart$context);
  143.             if (!empty($extraMerchantData->getAttachment())) {
  144.                 $attachment = new Attachment();
  145.                 $attachment->assign([
  146.                     'data' => $extraMerchantData->getAttachment(),
  147.                 ]);
  148.             } else {
  149.                 $attachment null;
  150.             }
  151.             $sessionData->assign([
  152.                 'customerData' => [
  153.                     'billing_address'  => $this->addressHydrator->hydrateFromContext($contextAddressStructHydrator::TYPE_BILLING),
  154.                     'shipping_address' => $this->addressHydrator->hydrateFromContext($contextAddressStructHydrator::TYPE_SHIPPING),
  155.                     'customer'         => $this->customerHydrator->hydrate($context),
  156.                     'merchant_data'    => $extraMerchantData->getMerchantData(),
  157.                     'attachment'       => $attachment,
  158.                 ],
  159.             ]);
  160.         }
  161.         $page->addExtension(SessionDataExtension::EXTENSION_NAME$sessionData);
  162.     }
  163.     private function removeDisabledKlarnaPaymentMethods(Struct $page): void
  164.     {
  165.         if (!($page instanceof Page)) {
  166.             return;
  167.         }
  168.         /** @var null|SessionDataExtension $sessionData */
  169.         $sessionData $page->getExtension(SessionDataExtension::EXTENSION_NAME);
  170.         if (null === $sessionData) {
  171.             return;
  172.         }
  173.         if (!method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  174.             return;
  175.         }
  176.         $availablePaymentMethods = !empty($sessionData->getPaymentMethodCategories())
  177.             ? array_column($sessionData->getPaymentMethodCategories(), 'identifier')
  178.             : [];
  179.         $page->setPaymentMethods(
  180.             $page->getPaymentMethods()->filter(
  181.                 static function (PaymentMethodEntity $paymentMethod) use ($availablePaymentMethods) {
  182.                     if (!array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  183.                         return true;
  184.                     }
  185.                     return in_array(PaymentMethodInstaller::KLARNA_PAYMENTS_CODES[$paymentMethod->getId()], $availablePaymentMethodstrue);
  186.                 }
  187.             )
  188.         );
  189.     }
  190.     private function removeSeparatePayNowKlarnaPaymentMethods(Page $page): void
  191.     {
  192.         if (!method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  193.             return;
  194.         }
  195.         $page->setPaymentMethods(
  196.             $page->getPaymentMethods()->filter(
  197.                 static function (PaymentMethodEntity $paymentMethod) {
  198.                     if (!array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  199.                         return true;
  200.                     }
  201.                     return in_array($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES_WITH_PAY_NOW_COMBINEDtrue);
  202.                 }
  203.             )
  204.         );
  205.     }
  206.     private function removeCombinedKlarnaPaymentPayNowMethod(Page $page): void
  207.     {
  208.         if (!method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  209.             return;
  210.         }
  211.         $page->setPaymentMethods(
  212.             $page->getPaymentMethods()->filter(
  213.                 static function (PaymentMethodEntity $paymentMethod) {
  214.                     if (!array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  215.                         return true;
  216.                     }
  217.                     return $paymentMethod->getId() !== PaymentMethodInstaller::KLARNA_PAY_NOW;
  218.                 }
  219.             )
  220.         );
  221.     }
  222.     private function removeAllKlarnaPaymentMethods(Struct $page): void
  223.     {
  224.         if (!($page instanceof Page) || !method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  225.             return;
  226.         }
  227.         $page->setPaymentMethods(
  228.             $page->getPaymentMethods()->filter(
  229.                 static function (PaymentMethodEntity $paymentMethod) {
  230.                     if (array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  231.                         return false;
  232.                     }
  233.                     return true;
  234.                 }
  235.             )
  236.         );
  237.     }
  238.     private function createKlarnaSession(Cart $cartSalesChannelContext $context): GenericResponse
  239.     {
  240.         $request $this->requestHydrator->hydrate($cart$context);
  241.         return $this->client->request($request$context->getContext());
  242.     }
  243.     private function getKlarnaCodeFromPaymentMethod(SalesChannelContext $context): string
  244.     {
  245.         if (!array_key_exists($context->getPaymentMethod()->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  246.             return '';
  247.         }
  248.         return PaymentMethodInstaller::KLARNA_PAYMENTS_CODES[$context->getPaymentMethod()->getId()];
  249.     }
  250.     private function convertCartFromOrder(OrderEntity $orderEntityContext $context): Cart
  251.     {
  252.         $order $this->orderFetcher->getOrderFromOrder($orderEntity->getId(), $context);
  253.         if (null === $order) {
  254.             throw new LogicException('could not find order via id');
  255.         }
  256.         return $this->orderConverter->convertOrderToCart($order$context);
  257.     }
  258. }