vendor/lnb/shopware6-lnb-subscription/src/Subscriber/Subscription/SubscriptionSubscriber.php line 164

Open in your IDE?
  1. <?php
  2. /**
  3.  * Permission is hereby granted, free of charge, to any person obtaining a
  4.  * copy of this software and associated documentation files (the "Software"),
  5.  * to deal in the Software without restriction, including without limitation
  6.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7.  * and/or sell copies of the Software, and to permit persons to whom the
  8.  * Software is furnished to do so, subject to the following conditions:
  9.  *
  10.  * The above copyright notice and this permission notice shall be included in
  11.  * all copies or substantial portions of the Software.
  12.  *
  13.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19.  * IN THE SOFTWARE.
  20.  *
  21.  * @package    LnbSubscription
  22.  * @author     Michael Lämmlein <michael.laemmlein@liebscher-bracht.com>
  23.  * @copyright  ©2022 Liebscher & Bracht
  24.  * @license    http://www.opensource.org/licenses/mit-license.php MIT-License
  25.  * @version    1.0.0
  26.  * @since      04.03.22
  27.  */
  28. declare(strict_types=1);
  29. namespace Lnb\Shopware6\LnbSubscription\Subscriber\Subscription;
  30. use Lnb\Shopware6\LnbSubscription\Event\OrderCreatedEvent;
  31. use Lnb\Shopware6\LnbSubscription\Service\SubscriptionRenewService;
  32. use Lnb\Shopware6\LnbSubscription\Struct\LineItemPayloadStruct;
  33. use Psr\Log\LoggerInterface;
  34. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
  35. use Shopware\Core\Checkout\Order\OrderEntity;
  36. use Shopware\Core\Checkout\Payment\Exception\InvalidOrderException;
  37. use Shopware\Core\Checkout\Payment\Exception\PaymentProcessException;
  38. use Shopware\Core\Checkout\Payment\Exception\UnknownPaymentMethodException;
  39. use Shopware\Core\Checkout\Payment\PaymentService;
  40. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  41. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  42. use Shopware\Core\Framework\ShopwareException;
  43. use Shopware\Core\Profiling\Profiler;
  44. use Symfony\Component\DependencyInjection\Attribute\Target;
  45. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  46. use Symfony\Component\HttpFoundation\RedirectResponse;
  47. use Symfony\Component\HttpFoundation\Request;
  48. readonly class SubscriptionSubscriber implements EventSubscriberInterface
  49. {
  50.     public function __construct(
  51.         private SubscriptionRenewService $subscriptionRenewService,
  52.         private PaymentService $paymentService,
  53.         #[Target('order.repository')] private EntityRepository $orderRepository,
  54.         #[Target('order_line_item.repository')] private EntityRepository $orderLineItemRepository,
  55.         #[Target('lnb_subscription.logger')] private LoggerInterface $logger
  56.     ) {
  57.     }
  58.     public static function getSubscribedEvents()
  59.     {
  60.         return [
  61.             OrderCreatedEvent::class => [
  62.                 ['onRenew'],
  63.                 ['addSubscriptionOrderIdToOrder'],
  64.                 ['addSubscriptionOrderIdToOrderLineItem'],
  65.                 ['onHandlePayment', -2],
  66.             ]];
  67.     }
  68.     public function onRenew(OrderCreatedEvent $event): void
  69.     {
  70.         $this->subscriptionRenewService->renew($event->getSubscriptionOrderEntity(), $event->getContext());
  71.         $this->logger->info('OrderCreatedEvent renew subscription', [
  72.             'subscriptionOrderNumber' => $event->getSubscriptionOrderEntity()->getSubscriptionOrderNumber(),
  73.             'subscriptionOrderId' => $event->getSubscriptionOrderEntity()->getId(),
  74.         ]);
  75.     }
  76.     public function onHandlePayment(OrderCreatedEvent $event): void
  77.     {
  78.         $orderId $event->getOrderId();
  79.         $data $event->getData();
  80.         $salesChannelContext $event->getSalesChannelContext();
  81.         $finishUrl null;
  82.         $errorUrl null;
  83.         try {
  84.             $response Profiler::trace(
  85.                 'lnb-subscription-recurring-handle-payment',
  86.                 function () use ($orderId$data$salesChannelContext$finishUrl$errorUrl): ?RedirectResponse {
  87.                     return $this->paymentService->handlePaymentByOrder(
  88.                         $orderId,
  89.                         $data,
  90.                         $salesChannelContext,
  91.                         $finishUrl,
  92.                         $errorUrl
  93.                     );
  94.                 }
  95.             );
  96.             $this->logger->info('OrderCreatedEvent::onHandlePayment: handlePaymentByOrder', [
  97.                 'subscriptionOrderNumber' => $event->getSubscriptionOrderEntity()->getSubscriptionOrderNumber(),
  98.                 'subscriptionOrderId' => $event->getSubscriptionOrderEntity()->getId(),
  99.                 'payment_response_url' => $response?->getTargetUrl()
  100.             ]);
  101.         } catch (PaymentProcessException InvalidOrderException UnknownPaymentMethodException $e) {
  102.             $this->logger->error(
  103.                 'OrderCreatedEvent::onHandlePayment: An error occurred during processing the payment',
  104.                 [
  105.                 'subscriptionOrderNumber' => $event->getSubscriptionOrderEntity()->getSubscriptionOrderNumber(),
  106.                 'subscriptionOrderId' => $event->getSubscriptionOrderEntity()->getId(),
  107.                 'exceptionMessage' => $e->getMessage()
  108.                 ]
  109.             );
  110.             // @todo on error change payment method
  111.             throw $e;
  112.         }
  113.         // Try to finalize the payment
  114.         if (!$response) {
  115.             return;
  116.         }
  117.         $request $this->getRequestForTransaction($response);
  118.         if (!$request->get('_sw_payment_token')) {
  119.             return;
  120.         }
  121.         try {
  122.             $tokenStruct $this->paymentService->finalizeTransaction(
  123.                 $request->get('_sw_payment_token'),
  124.                 $request,
  125.                 $salesChannelContext
  126.             );
  127.             $exception $tokenStruct->getException();
  128.             if ($exception instanceof ShopwareException) {
  129.                 throw $exception;
  130.             }
  131.             $this->logger->info('OrderCreatedEvent::onHandlePayment: finalizeTransaction', [
  132.                 'subscriptionOrderNumber' => $event->getSubscriptionOrderEntity()->getSubscriptionOrderNumber(),
  133.                 'subscriptionOrderId' => $event->getSubscriptionOrderEntity()->getId(),
  134.                 'tokenStruct' => $tokenStruct
  135.             ]);
  136.         } catch (PaymentProcessException InvalidOrderException UnknownPaymentMethodException $e) {
  137.             $this->logger->error(
  138.                 'OrderCreatedEvent::onHandlePayment: An error occurred during finalize the payment',
  139.                 [
  140.                     'subscriptionOrderNumber' => $event->getSubscriptionOrderEntity()->getSubscriptionOrderNumber(),
  141.                     'subscriptionOrderId' => $event->getSubscriptionOrderEntity()->getId(),
  142.                     'exceptionMessage' => $e->getMessage()
  143.                 ]
  144.             );
  145.             throw $e;
  146.         }
  147.     }
  148.     public function addSubscriptionOrderIdToOrder(OrderCreatedEvent $event): void
  149.     {
  150.         $criteria = new Criteria([$event->getOrderId()]);
  151.         /** @var OrderEntity $order */
  152.         $order $this->orderRepository->search($criteria$event->getContext())->first();
  153.         $customFields $order->getCustomFields();
  154.         $customFields['LnbSubscription']['lnbSubscriptionOrderId'] = $event->getSubscriptionOrderEntity()->getId();
  155.         $this->orderRepository->upsert([[
  156.             'id' => $order->getId(),
  157.             'customFields' => $customFields,
  158.             'lnbSubscriptions' => [
  159.                 [
  160.                     'id' => $event->getSubscriptionOrderEntity()->getId()
  161.                 ]
  162.             ],
  163.         ]], $event->getContext());
  164.         $this->logger->info('OrderCreatedEvent add subscriptionOrderId to order', [
  165.             'subscriptionOrderNumber' => $event->getSubscriptionOrderEntity()->getSubscriptionOrderNumber(),
  166.             'subscriptionOrderId' => $event->getSubscriptionOrderEntity()->getId(),
  167.             'orderId' => $order->getId(),
  168.         ]);
  169.     }
  170.     public function addSubscriptionOrderIdToOrderLineItem(OrderCreatedEvent $event): void
  171.     {
  172.         $subscriptionOrderId $event->getSubscriptionOrderEntity()->getId();
  173.         $criteria = new Criteria([$event->getOrderId()]);
  174.         $criteria->addAssociation('lineItems');
  175.         /** @var OrderEntity $order */
  176.         $order $this->orderRepository->search($criteria$event->getContext())->first();
  177.         $orderLineItems $order->getLineItems()
  178.             ->filter(function (OrderLineItemEntity $orderLineItem) use ($subscriptionOrderId): bool {
  179.                 if (!isset($orderLineItem->getPayload()['LnbSubscription'])) {
  180.                     return false;
  181.                 }
  182.                 $struct = new LineItemPayloadStruct($orderLineItem->getPayload()['LnbSubscription']);
  183.                 if ($struct->getLnbSubscriptionOrderId() === $subscriptionOrderId) {
  184.                     return true;
  185.                 }
  186.                 return false;
  187.             })
  188.         ;
  189.         if (>= $orderLineItems->count()) {
  190.             return;
  191.         }
  192.         $update_data = [];
  193.         /** @var OrderLineItemEntity $orderLineItem */
  194.         foreach ($orderLineItems as $orderLineItem) {
  195.             $customFields $orderLineItem->getCustomFields();
  196.             $customFields['LnbSubscription']['lnbSubscriptionOrderId'] = $subscriptionOrderId;
  197.             $update_data[] = [
  198.                 'id' => $orderLineItem->getId(),
  199.                 'customFields' => $customFields,
  200.             ];
  201.         }
  202.         $this->orderLineItemRepository->update($update_data$event->getContext());
  203.         $this->logger->info('OrderCreatedEvent add subscriptionOrderId to orderLineItems', [
  204.             'subscriptionOrderNumber' => $event->getSubscriptionOrderEntity()->getSubscriptionOrderNumber(),
  205.             'subscriptionOrderId' => $event->getSubscriptionOrderEntity()->getId(),
  206.             'update_data' => $update_data,
  207.         ]);
  208.     }
  209.     private function getRequestForTransaction(RedirectResponse $response): Request
  210.     {
  211.         $query = (string) parse_url($response->getTargetUrl(), PHP_URL_QUERY);
  212.         parse_str($query$result);
  213.         return new Request($result);
  214.     }
  215. }