modules/XC/Stripe/src/EventListener/PaymentProcessor.php line 53

Open in your IDE?
  1. <?php
  2. /**
  3.  * Copyright (c) 2011-present Qualiteam software Ltd. All rights reserved.
  4.  * See https://www.x-cart.com/license-agreement.html for license details.
  5.  */
  6. namespace XC\Stripe\EventListener;
  7. use Stripe\Checkout\Session;
  8. use Stripe\Exception\ApiErrorException;
  9. use XC\Stripe\Main;
  10. use XC\Stripe\Model\Payment\Method;
  11. use XC\Stripe\Model\Payment\Stripe;
  12. use XCart\Event\Payment\PaymentActionEvent;
  13. use XCart\Event\Payment\TransactionData;
  14. use XCart\Payment\RequestProcessor;
  15. use XCart\Payment\URLGenerator\BackendURLGenerator;
  16. use XCart\Payment\URLGenerator\URLGeneratorInterface;
  17. use XLite\Core\Config;
  18. final class PaymentProcessor
  19. {
  20.     public function __construct(
  21.         private BackendURLGenerator $backendURLGenerator
  22.     ) {
  23.     }
  24.     public function onPaymentInitAction(PaymentActionEvent $event): void
  25.     {
  26.         /** @var Session $session */
  27.         $session $this->getSession($event->getMethod(), $event->getTransaction(), $event->getMetaData());
  28.         $event->addOutputTransactionData('stripe_id'$session->payment_intent'Stripe payment intent');
  29.         /** @var Method $method */
  30.         $method $event->getMethod();
  31.         $prefix $method->getProcessor()->isTestMode($method) ? 'Test' '';
  32.         $publishKey $method->getSetting('publishKey' $prefix);
  33.         $event->setOutputData([
  34.             'publishKey' => $publishKey
  35.         ]);
  36.         $event->setOutputMetaData([
  37.             'url' => $session->url,
  38.             'method' => 'get'
  39.         ]);
  40.         $event->setOutputCode(RequestProcessor::OUTPUT_CODE_SILENT);
  41.     }
  42.     public function onPaymentPayAction(PaymentActionEvent $event): void
  43.     {
  44.         $status RequestProcessor::OUTPUT_CODE_FAILED;
  45.         /** @var TransactionData[] $transactionData */
  46.         $transactionData $event->getTransaction()->getData();
  47.         $stripeId '';
  48.         foreach ($transactionData as $data) {
  49.             if ($data->getName() === 'stripe_id') {
  50.                 $stripeId $data->getValue();
  51.                 break;
  52.             }
  53.         }
  54.         try {
  55.             $intent $this->getIntent($event->getMethod(), $stripeId);
  56.         } catch (\Throwable $exception) {
  57.             $event->setOutputNote($exception->getMessage());
  58.             $event->setOutputCode($status);
  59.             return;
  60.         }
  61.         if (in_array($intent->status, ['succeeded''requires_capture''processing'])) {
  62.             if ($intent->status === 'processing') {
  63.                 $status RequestProcessor::OUTPUT_CODE_PENDING;
  64.             } else {
  65.                 $status RequestProcessor::OUTPUT_CODE_COMPLETED;
  66.             }
  67.         }
  68.         $event->addOutputBackendTransaction(
  69.             $status,
  70.             $event->getValue(),
  71.             $event->getTransaction()->getType()
  72.         );
  73.         $event->setOutputNote('');
  74.         $event->setOutputCode($status);
  75.     }
  76.     private function initStripe(\XLite\Model\Payment\Method $method): void
  77.     {
  78.         /** @var Stripe $processor */
  79.         $processor $method->getProcessor();
  80.         $clientKey $processor->getActualClientSecret($method);
  81.         \Stripe\Stripe::setApiKey($clientKey);
  82.         \Stripe\Stripe::setApiVersion(Stripe::API_VERSION);
  83.         \Stripe\Stripe::setAppInfo(
  84.             Stripe::APP_NAME,
  85.             Main::getVersion(),
  86.             'https://market.x-cart.com/addons/stripe-payment-module.html',
  87.             Stripe::APP_PARTNER_ID
  88.         );
  89.     }
  90.     private function getSession(
  91.         \XLite\Model\Payment\Method $method,
  92.         \XLite\Model\Payment\Transaction $transaction,
  93.         array $metaData = []
  94.     ): ?\Stripe\Checkout\Session {
  95.         $this->initStripe($method);
  96.         return \Stripe\Checkout\Session::create($this->getCheckoutSessionParams($transaction$method->getProcessor(), $metaData));
  97.     }
  98.     private function getIntent(
  99.         \XLite\Model\Payment\Method $method,
  100.         string $sessionId
  101.     ) {
  102.         $this->initStripe($method);
  103.         return \Stripe\PaymentIntent::retrieve($sessionId);
  104.     }
  105.     /**
  106.      * @throws ApiErrorException
  107.      */
  108.     private function getCheckoutSessionParams(
  109.         \XLite\Model\Payment\Transaction $transaction,
  110.         Stripe $processor,
  111.         array $metaData = []
  112.     ): array {
  113.         $currency  $transaction->getCurrency();
  114.         $order $transaction->getOrder();
  115.         $lineItems = [
  116.             [
  117.                 'price_data' => [
  118.                     'currency' => strtolower($currency->getCode()),
  119.                     'product_data' => [
  120.                         'name' => Config::getInstance()->Company->company_name,
  121.                     ],
  122.                     'unit_amount' => $currency->roundValueAsInteger($order->getTotal()),
  123.                 ],
  124.                 'quantity' => 1,
  125.             ],
  126.         ];
  127.         $paymentMethods $processor->getEnabledPaymentMethods($order);
  128.         $paymentIntentData $this->getPaymentIntentData($transaction$paymentMethods);
  129.         if (
  130.             in_array('afterpay_clearpay'$paymentMethodstrue)
  131.             && $shippingInfo $processor->getShippingInfoForAfterpayClearpay($order)
  132.         ) {
  133.             $paymentIntentData['shipping'] = $shippingInfo;
  134.         }
  135.         $params = [
  136.             'success_url'            => $metaData['success_url'] ?? $this->backendURLGenerator->generateReturnURL($transactionURLGeneratorInterface::RETURN_TXN_IDtrue),
  137.             'cancel_url'             => $metaData['cancel_url'] ?? $this->backendURLGenerator->generateCancelURL($transactionURLGeneratorInterface::RETURN_TXN_IDtrue),
  138.             'mode'                   => 'payment',
  139.             'payment_method_types'   => $paymentMethods,
  140.             'payment_method_options' => $this->getPaymentMethodOptions($paymentMethods),
  141.             'client_reference_id'    => $order->getOrderId(),
  142.             'customer_email'         => $order->getProfile()->getLogin(),
  143.             'line_items'             => $lineItems,
  144.             'payment_intent_data'    => $paymentIntentData,
  145.         ];
  146.         $shippingAddressCollection $this->prepareShippingAddressCollection(
  147.             $paymentMethods,
  148.             $params,
  149.             $processor->getCountriesAvailableForShipping($order)
  150.         );
  151.         if ($shippingAddressCollection) {
  152.             $params['shipping_address_collection'] = $shippingAddressCollection;
  153.         }
  154.         $origProfile $order->getOrigProfile();
  155.         $stripeCustomerId null;
  156.         if ($origProfile && !$origProfile->getAnonymous()) {
  157.             $stripeCustomerId $origProfile->getStripeCustomerId();
  158.         }
  159.         $stripeCustomer $processor->updateStripeCustomer($order->getProfile(), $stripeCustomerId);
  160.         if ($stripeCustomer && $stripeCustomer->id) {
  161.             $params['customer'] = $stripeCustomer->id;
  162.             unset($params['customer_email']);
  163.         }
  164.         return $params;
  165.     }
  166.     private function getPaymentMethodOptions(array $paymentMethods): array
  167.     {
  168.         $result = [];
  169.         if (in_array('wechat_pay'$paymentMethodstrue)) {
  170.             $result['wechat_pay'] = ['client' => 'web'];
  171.         }
  172.         return $result;
  173.     }
  174.     private function prepareShippingAddressCollection(array $paymentMethods, array $params, array $countriesAvailableForShipping): ?array
  175.     {
  176.         $result null;
  177.         if (
  178.             !empty($countriesAvailableForShipping)
  179.             && empty($sessionParams['payment_intent_data']['shipping'])
  180.             && in_array('afterpay_clearpay'$paymentMethodstrue)
  181.         ) {
  182.             $result = [
  183.                 'allowed_countries' => $countriesAvailableForShipping
  184.             ];
  185.         }
  186.         return $result;
  187.     }
  188.     private function getPaymentIntentData(\XLite\Model\Payment\Transaction $transaction, array $paymentMethods): array
  189.     {
  190.         return [
  191.             'capture_method' => $transaction->getPaymentMethod()->getSetting('type') === \XLite\Model\Payment\BackendTransaction::TRAN_TYPE_SALE
  192.                 'automatic'
  193.                 'manual',
  194.             'description'    => 'Payment transaction ID: ' $transaction->getPublicId(),
  195.             'metadata'       => [
  196.                 'txnId' => $transaction->getPublicTxnId(),
  197.             ],
  198.         ];
  199.     }
  200. }