vendor/shopware/core/Checkout/Payment/PaymentService.php line 83

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Checkout\Payment;
  3. use Psr\Log\LoggerInterface;
  4. use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionEntity;
  5. use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStateHandler;
  6. use Shopware\Core\Checkout\Payment\Cart\AsyncPaymentTransactionStruct;
  7. use Shopware\Core\Checkout\Payment\Cart\PaymentHandler\AsynchronousPaymentHandlerInterface;
  8. use Shopware\Core\Checkout\Payment\Cart\PaymentHandler\PaymentHandlerRegistry;
  9. use Shopware\Core\Checkout\Payment\Cart\PaymentTransactionChainProcessor;
  10. use Shopware\Core\Checkout\Payment\Cart\Token\TokenFactoryInterfaceV2;
  11. use Shopware\Core\Checkout\Payment\Cart\Token\TokenStruct;
  12. use Shopware\Core\Checkout\Payment\Exception\AsyncPaymentFinalizeException;
  13. use Shopware\Core\Checkout\Payment\Exception\AsyncPaymentProcessException;
  14. use Shopware\Core\Checkout\Payment\Exception\CustomerCanceledAsyncPaymentException;
  15. use Shopware\Core\Checkout\Payment\Exception\InvalidOrderException;
  16. use Shopware\Core\Checkout\Payment\Exception\InvalidTransactionException;
  17. use Shopware\Core\Checkout\Payment\Exception\PaymentProcessException;
  18. use Shopware\Core\Checkout\Payment\Exception\SyncPaymentProcessException;
  19. use Shopware\Core\Checkout\Payment\Exception\TokenExpiredException;
  20. use Shopware\Core\Checkout\Payment\Exception\UnknownPaymentMethodException;
  21. use Shopware\Core\Framework\Context;
  22. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  23. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  24. use Shopware\Core\Framework\Log\Package;
  25. use Shopware\Core\Framework\Uuid\Uuid;
  26. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  27. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceInterface;
  28. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextServiceParameters;
  29. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  30. use Symfony\Component\HttpFoundation\RedirectResponse;
  31. use Symfony\Component\HttpFoundation\Request;
  32. #[Package('checkout')]
  33. class PaymentService
  34. {
  35.     private PaymentTransactionChainProcessor $paymentProcessor;
  36.     private TokenFactoryInterfaceV2 $tokenFactory;
  37.     private PaymentHandlerRegistry $paymentHandlerRegistry;
  38.     private EntityRepositoryInterface $orderTransactionRepository;
  39.     private OrderTransactionStateHandler $transactionStateHandler;
  40.     private LoggerInterface $logger;
  41.     private EntityRepositoryInterface $orderRepository;
  42.     private SalesChannelContextServiceInterface $contextService;
  43.     /**
  44.      * @internal
  45.      */
  46.     public function __construct(
  47.         PaymentTransactionChainProcessor $paymentProcessor,
  48.         TokenFactoryInterfaceV2 $tokenFactory,
  49.         PaymentHandlerRegistry $paymentHandlerRegistry,
  50.         EntityRepositoryInterface $orderTransactionRepository,
  51.         OrderTransactionStateHandler $transactionStateHandler,
  52.         LoggerInterface $logger,
  53.         EntityRepositoryInterface $orderRepository,
  54.         SalesChannelContextServiceInterface $contextService
  55.     ) {
  56.         $this->paymentProcessor $paymentProcessor;
  57.         $this->tokenFactory $tokenFactory;
  58.         $this->paymentHandlerRegistry $paymentHandlerRegistry;
  59.         $this->orderTransactionRepository $orderTransactionRepository;
  60.         $this->transactionStateHandler $transactionStateHandler;
  61.         $this->logger $logger;
  62.         $this->orderRepository $orderRepository;
  63.         $this->contextService $contextService;
  64.     }
  65.     /**
  66.      * @throws AsyncPaymentProcessException
  67.      * @throws InvalidOrderException
  68.      * @throws SyncPaymentProcessException
  69.      * @throws UnknownPaymentMethodException
  70.      */
  71.     public function handlePaymentByOrder(
  72.         string $orderId,
  73.         RequestDataBag $dataBag,
  74.         SalesChannelContext $context,
  75.         ?string $finishUrl null,
  76.         ?string $errorUrl null
  77.     ): ?RedirectResponse {
  78.         if (!Uuid::isValid($orderId)) {
  79.             throw new InvalidOrderException($orderId);
  80.         }
  81.         $criteria = new Criteria([$orderId]);
  82.         $criteria->setTitle('payment-service::load-order');
  83.         $order $this->orderRepository
  84.             ->search($criteria$context->getContext())
  85.             ->first();
  86.         if ($order === null) {
  87.             throw new InvalidOrderException($orderId);
  88.         }
  89.         if ($context->getCurrency()->getId() !== $order->getCurrencyId()) {
  90.             $context $this->contextService->get(
  91.                 new SalesChannelContextServiceParameters(
  92.                     $context->getSalesChannelId(),
  93.                     $context->getToken(),
  94.                     $context->getContext()->getLanguageId(),
  95.                     $order->getCurrencyId()
  96.                 )
  97.             );
  98.         }
  99.         try {
  100.             return $this->paymentProcessor->process($orderId$dataBag$context$finishUrl$errorUrl);
  101.         } catch (PaymentProcessException $e) {
  102.             $transactionId $e->getOrderTransactionId();
  103.             $this->logger->error('An error occurred during processing the payment', ['orderTransactionId' => $transactionId'exceptionMessage' => $e->getMessage()]);
  104.             $this->transactionStateHandler->fail($transactionId$context->getContext());
  105.             if ($errorUrl !== null) {
  106.                 $errorUrl .= (parse_url($errorUrl\PHP_URL_QUERY) ? '&' '?') . 'error-code=' $e->getErrorCode();
  107.                 return new RedirectResponse($errorUrl);
  108.             }
  109.             throw $e;
  110.         }
  111.     }
  112.     /**
  113.      * @throws AsyncPaymentFinalizeException
  114.      * @throws InvalidTransactionException
  115.      * @throws TokenExpiredException
  116.      * @throws UnknownPaymentMethodException
  117.      */
  118.     public function finalizeTransaction(string $paymentTokenRequest $requestSalesChannelContext $context): TokenStruct
  119.     {
  120.         $token $this->tokenFactory->parseToken($paymentToken);
  121.         if ($token->isExpired()) {
  122.             $token->setException(new TokenExpiredException($paymentToken));
  123.             $this->tokenFactory->invalidateToken($token->getToken());
  124.             return $token;
  125.         }
  126.         $transactionId $token->getTransactionId();
  127.         if ($transactionId === null || !Uuid::isValid($transactionId)) {
  128.             throw new AsyncPaymentProcessException((string) $transactionId'Payment JWT didn\'t contain a valid orderTransactionId');
  129.         }
  130.         $transaction $this->getPaymentTransactionStruct($transactionId$context->getContext());
  131.         $paymentHandler $this->getPaymentHandlerById($token->getPaymentMethodId(), $context->getContext());
  132.         try {
  133.             $paymentHandler->finalize($transaction$request$context);
  134.         } catch (CustomerCanceledAsyncPaymentException $e) {
  135.             $this->transactionStateHandler->cancel($transactionId$context->getContext());
  136.             $token->setException($e);
  137.         } catch (PaymentProcessException $e) {
  138.             $this->logger->error('An error occurred during finalizing async payment', ['orderTransactionId' => $transactionId'exceptionMessage' => $e->getMessage()]);
  139.             $this->transactionStateHandler->fail($transactionId$context->getContext());
  140.             $token->setException($e);
  141.         } finally {
  142.             $this->tokenFactory->invalidateToken($token->getToken());
  143.         }
  144.         return $token;
  145.     }
  146.     /**
  147.      * @throws UnknownPaymentMethodException
  148.      */
  149.     private function getPaymentHandlerById(string $paymentMethodIdContext $context): AsynchronousPaymentHandlerInterface
  150.     {
  151.         $handler $this->paymentHandlerRegistry->getAsyncPaymentHandler($paymentMethodId);
  152.         if (!$handler) {
  153.             throw new UnknownPaymentMethodException($paymentMethodId);
  154.         }
  155.         return $handler;
  156.     }
  157.     /**
  158.      * @throws InvalidTransactionException
  159.      */
  160.     private function getPaymentTransactionStruct(string $orderTransactionIdContext $context): AsyncPaymentTransactionStruct
  161.     {
  162.         $criteria = new Criteria([$orderTransactionId]);
  163.         $criteria->setTitle('payment-service::load-transaction');
  164.         $criteria->addAssociation('order');
  165.         $criteria->addAssociation('paymentMethod.appPaymentMethod.app');
  166.         /** @var OrderTransactionEntity|null $orderTransaction */
  167.         $orderTransaction $this->orderTransactionRepository->search($criteria$context)->first();
  168.         if ($orderTransaction === null) {
  169.             throw new InvalidTransactionException($orderTransactionId);
  170.         }
  171.         return new AsyncPaymentTransactionStruct($orderTransaction$orderTransaction->getOrder(), '');
  172.     }
  173. }