<?php
declare(strict_types=1);
namespace App\Subscriber\Payment;
use App\Event\Cinema\CinemaContextOnDemandEvent;
use App\Event\Order\OrderPaymentTransactionHandledEvent;
use App\Event\Payment\WebhookNotificationEvent;
use App\Exception\Order\BasketDoesNotExistException;
use App\Exception\Order\BasketOrderLockedException;
use App\Manager\OrderManager;
use App\Payment\Model\Response as PaymentProviderResponse;
use App\Payment\PaymentFactory;
use App\Service\Payment\PaymentProviderService;
use Ramsey\Uuid\Uuid;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class WebhookSubscriber implements EventSubscriberInterface
{
private PaymentFactory $paymentFactory;
private PaymentProviderService $paymentProviderService;
private EventDispatcherInterface $eventDispatcher;
private OrderManager $orderManager;
public function __construct(
PaymentFactory $paymentFactory,
PaymentProviderService $paymentProviderService,
EventDispatcherInterface $eventDispatcher,
OrderManager $orderManager
)
{
$this->paymentFactory = $paymentFactory;
$this->paymentProviderService = $paymentProviderService;
$this->eventDispatcher = $eventDispatcher;
$this->orderManager = $orderManager;
}
public static function getSubscribedEvents(): array
{
return [
WebhookNotificationEvent::class => 'onNotification'
];
}
public function onNotification(WebhookNotificationEvent $event): void
{
$client = $this->paymentFactory->get(
$this->paymentProviderService->getPaymentProviderServiceIdentifier($event->getPaymentProvider())
);
$paymentProviderResponse = $client->dispatch($event->getRequest());
if ($paymentProviderResponse !== null) {
$this->eventDispatcher->dispatch(
new CinemaContextOnDemandEvent($paymentProviderResponse->getCinemaId())
);
$order = $this->orderManager->get(Uuid::fromString($paymentProviderResponse->getId()));
$client->flushLogger();
} else {
return;
}
if ($order === null) {
throw new BasketDoesNotExistException();
}
if ($paymentProviderResponse->getStatus() !== PaymentProviderResponse::PENDING_TRANSACTION) {
if ($this->orderManager->isOrderLocked(Uuid::fromString($paymentProviderResponse->getId()))) {
throw new BasketOrderLockedException();
}
$this->orderManager->lockOrder(Uuid::fromString($paymentProviderResponse->getId()));
}
try {
$this->orderManager->handlePaymentProviderResponse(
$paymentProviderResponse,
$order,
$client,
$event->getPaymentChannel(),
['isProcessingExpired' => false, 'isProcessingAllowed' => true],
);
} catch (\Exception $exception) {
throw $exception;
} finally {
$this->eventDispatcher->dispatch(
new OrderPaymentTransactionHandledEvent($order, $paymentProviderResponse,
$client, $event->getPaymentChannel()
)
);
}
}
}