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\Extension\ErrorMessageExtension;
  13. use KlarnaPayment\Components\Extension\SessionDataExtension;
  14. use KlarnaPayment\Components\Factory\MerchantDataFactoryInterface;
  15. use KlarnaPayment\Components\Helper\OrderFetcherInterface;
  16. use KlarnaPayment\Components\Helper\PaymentHelper\PaymentHelperInterface;
  17. use KlarnaPayment\Installer\Modules\PaymentMethodInstaller;
  18. use LogicException;
  19. use Shopware\Core\Checkout\Cart\Cart;
  20. use Shopware\Core\Checkout\Cart\Order\OrderConverter;
  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 OrderConverter */
  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.         OrderConverter $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 (empty($sessionData->getPaymentMethodCategories())) {
  174.             return;
  175.         }
  176.         if (!method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  177.             return;
  178.         }
  179.         $availablePaymentMethods array_column($sessionData->getPaymentMethodCategories(), 'identifier');
  180.         $page->setPaymentMethods(
  181.             $page->getPaymentMethods()->filter(
  182.                 static function (PaymentMethodEntity $paymentMethod) use ($availablePaymentMethods) {
  183.                     if (!array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  184.                         return true;
  185.                     }
  186.                     return in_array(PaymentMethodInstaller::KLARNA_PAYMENTS_CODES[$paymentMethod->getId()], $availablePaymentMethodstrue);
  187.                 }
  188.             )
  189.         );
  190.     }
  191.     private function removeSeparatePayNowKlarnaPaymentMethods(Page $page): void
  192.     {
  193.         if (!method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  194.             return;
  195.         }
  196.         $page->setPaymentMethods(
  197.             $page->getPaymentMethods()->filter(
  198.                 static function (PaymentMethodEntity $paymentMethod) {
  199.                     if (!array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  200.                         return true;
  201.                     }
  202.                     return in_array($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES_WITH_PAY_NOW_COMBINEDtrue);
  203.                 }
  204.             )
  205.         );
  206.     }
  207.     private function removeCombinedKlarnaPaymentPayNowMethod(Page $page): void
  208.     {
  209.         if (!method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  210.             return;
  211.         }
  212.         $page->setPaymentMethods(
  213.             $page->getPaymentMethods()->filter(
  214.                 static function (PaymentMethodEntity $paymentMethod) {
  215.                     if (!array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  216.                         return true;
  217.                     }
  218.                     return $paymentMethod->getId() !== PaymentMethodInstaller::KLARNA_PAY_NOW;
  219.                 }
  220.             )
  221.         );
  222.     }
  223.     private function removeAllKlarnaPaymentMethods(Struct $page): void
  224.     {
  225.         if (!($page instanceof Page) || !method_exists($page'setPaymentMethods') || !method_exists($page'getPaymentMethods')) {
  226.             return;
  227.         }
  228.         $page->setPaymentMethods(
  229.             $page->getPaymentMethods()->filter(
  230.                 static function (PaymentMethodEntity $paymentMethod) {
  231.                     if (array_key_exists($paymentMethod->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  232.                         return false;
  233.                     }
  234.                     return true;
  235.                 }
  236.             )
  237.         );
  238.     }
  239.     private function createKlarnaSession(Cart $cartSalesChannelContext $context): GenericResponse
  240.     {
  241.         $request $this->requestHydrator->hydrate($cart$context);
  242.         return $this->client->request($request$context->getContext());
  243.     }
  244.     private function getKlarnaCodeFromPaymentMethod(SalesChannelContext $context): string
  245.     {
  246.         if (!array_key_exists($context->getPaymentMethod()->getId(), PaymentMethodInstaller::KLARNA_PAYMENTS_CODES)) {
  247.             return '';
  248.         }
  249.         return PaymentMethodInstaller::KLARNA_PAYMENTS_CODES[$context->getPaymentMethod()->getId()];
  250.     }
  251.     private function convertCartFromOrder(OrderEntity $orderEntityContext $context): Cart
  252.     {
  253.         $order $this->orderFetcher->getOrderFromOrder($orderEntity->getId(), $context);
  254.         if (null === $order) {
  255.             throw new LogicException('could not find order via id');
  256.         }
  257.         return $this->orderConverter->convertToCart($order$context);
  258.     }
  259. }