<?php
declare(strict_types=1);
namespace PolPaymentPayolutionSW6\EventListener;
use PolPaymentPayolutionSW6\Component\CustomFields\CustomFieldsInterface;
use PolPaymentPayolutionSW6\Component\DataHandler\OrderTransactionDataHandler\OrderTransactionDataHandlerInterface;
use PolPaymentPayolutionSW6\Component\DataHandler\OrderTransactionStatusHandler\OrderTransactionStatusHandlerInterface;
use PolPaymentPayolutionSW6\Component\PaymentMethodConfiguration\PaymentMethodConfigurationServiceInterface;
use PolPaymentPayolutionSW6\Component\Validator\PaymentRequestValidator\PaymentRequestValidatorInterface;
use PolPaymentPayolutionSW6\Event\PreAuthFinished;
use PolPaymentPayolutionSW6\PayolutionApi\Client\Exception\InvalidXmlException;
use PolPaymentPayolutionSW6\PayolutionApi\Process\Exception\ProcessFailedException;
use PolPaymentPayolutionSW6\PayolutionApi\Request\RequestFactory\PaymentRequestFactoryInterface;
use PolPaymentPayolutionSW6\PayolutionApi\Request\RequestFactory\Transaction\TransactionRequestFactoryInterface;
use PolPaymentPayolutionSW6\PayolutionApi\Request\RequestProcessor\RequestProcessorInterface;
use Psr\Log\LoggerInterface;
use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Storefront\Event\RouteRequest\HandlePaymentMethodRouteRequestEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CheckoutFinishEventListener implements EventSubscriberInterface
{
/**
* @var EntityRepositoryInterface
*/
private $orderTransactionRepository;
/**
* @var OrderTransactionDataHandlerInterface
*/
private $orderTransactionDataHandler;
/**
* @var OrderTransactionStatusHandlerInterface
*/
private $orderTransactionStatusHandler;
/**
* @var TransactionRequestFactoryInterface
*/
private $transactionRequestFactory;
/**
* @var PaymentRequestFactoryInterface
*/
private $paymentRequestFactory;
/**
* @var RequestProcessorInterface
*/
private $captureRequestProcessor;
/**
* @var PaymentMethodConfigurationServiceInterface
*/
private $paymentMethodConfigurationService;
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(
EntityRepositoryInterface $orderTransactionRepository,
OrderTransactionDataHandlerInterface $orderTransactionDataHandler,
OrderTransactionStatusHandlerInterface $orderTransactionStatusHandler,
TransactionRequestFactoryInterface $transactionRequestFactory,
PaymentRequestFactoryInterface $paymentRequestFactory,
RequestProcessorInterface $captureRequestProcessor,
PaymentMethodConfigurationServiceInterface $paymentMethodConfigurationService,
LoggerInterface $logger
) {
$this->orderTransactionRepository = $orderTransactionRepository;
$this->orderTransactionDataHandler = $orderTransactionDataHandler;
$this->orderTransactionStatusHandler = $orderTransactionStatusHandler;
$this->transactionRequestFactory = $transactionRequestFactory;
$this->paymentRequestFactory = $paymentRequestFactory;
$this->captureRequestProcessor = $captureRequestProcessor;
$this->paymentMethodConfigurationService = $paymentMethodConfigurationService;
$this->logger = $logger;
}
public static function getSubscribedEvents(): array
{
return [
PreAuthFinished::class => 'onPreAuthFinish',
HandlePaymentMethodRouteRequestEvent::class => 'addRequiredRequestParameter',
];
}
public function onPreAuthFinish(PreAuthFinished $event): void
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('orderId', $event->getOrder()->getId()));
$criteria->addAssociations(['order.customer', 'order.currency', 'order.lineItems', 'order.deliveries', 'order.salesChannel', 'paymentMethod']);
$context = $event->getContext();
/** @var OrderTransactionEntity $orderTransaction */
$orderTransaction = $this->orderTransactionRepository->search($criteria, $context)->filter(function (OrderTransactionEntity $orderTransaction) use ($event): bool {
return $orderTransaction->getPaymentMethodId() === $event->getSalesChannelContext()->getPaymentMethod()->getId();
})->last();
$this->updateOrderTransactionLineItems($orderTransaction, $context);
if (!$this->paymentMethodConfigurationService->paymentMethodSupportsAutoCapture($event->getSalesChannelContext()->getPaymentMethod()) || $orderTransaction->getCustomFields()[CustomFieldsInterface::IS_PAYMENT_CAPTURED]) {
return;
}
try {
$transaction = $this->transactionRequestFactory->createTransaction(
$orderTransaction,
new RequestDataBag(),
$orderTransaction->getAmount()->getTotalPrice(),
null,
[PaymentRequestValidatorInterface::IS_CAPTURE_REQUEST => true]
);
$captureRequest = $this->paymentRequestFactory->createRequest($orderTransaction, $transaction, $orderTransaction->getOrder()->getSalesChannel()->getId());
$captureRequest->setPreAuthorizationUniqueId($orderTransaction->getCustomFields()[CustomFieldsInterface::UNIQUE_ID]);
$captureResponse = $this->captureRequestProcessor->processRequest($captureRequest);
$this->orderTransactionDataHandler->updateOrderTransactionData($orderTransaction, $context, [
CustomFieldsInterface::IS_PAYMENT_CAPTURED => true,
CustomFieldsInterface::REMAINING_CAPTURE_AMOUNT => 0,
CustomFieldsInterface::REMAINING_REFUND_AMOUNT => $orderTransaction->getAmount()->getTotalPrice(),
]);
foreach ($orderTransaction->getOrder()->getLineItems() as $orderLineItem) {
$this->orderTransactionDataHandler->updateOrderLineItemData($orderLineItem, $context, [CustomFieldsInterface::IS_PAYMENT_CAPTURED => true]);
}
$this->orderTransactionStatusHandler->setPaid($orderTransaction, $context);
$this->logger->info('payment auto captured due enabled setting', $captureResponse->getResponseAsArray());
} catch (InvalidXmlException $xmlException) {
$this->logger->error('payment auto capture invalid xml', ['message' => $xmlException->getMessage()]);
} catch (ProcessFailedException $processFailedException) {
$this->logger->error('payment auto capture process failed', $processFailedException->getResponse()->getResponseAsArray());
} catch (\Throwable $e) {
$this->logger->error('payment auto capture error occurred', ['message' => $e->getMessage()]);
}
}
public function addRequiredRequestParameter(HandlePaymentMethodRouteRequestEvent $event): void
{
$this->logger->debug('Adding request parameter');
$storefrontRequest = $event->getStorefrontRequest();
$storeApiRequest = $event->getStoreApiRequest();
$originalRoute = $storefrontRequest->attributes->get('_route');
if ($originalRoute !== 'frontend.account.edit-order.update-order') {
return;
}
$requiredRequestParameter = $this->getRequiredRequestParameter();
foreach ($requiredRequestParameter as $requestParameter) {
$storeApiRequest->request->set(
$requestParameter,
$storefrontRequest->request->get($requestParameter)
);
$storeApiRequest->request->set(
$requestParameter,
$storefrontRequest->request->get($requestParameter)
);
}
$this->logger->debug('Added request parameter');
}
private function getRequiredRequestParameter(): array
{
return [
PaymentRequestValidatorInterface::PRE_CHECK_ID,
PaymentRequestValidatorInterface::TRANSACTION_ID,
PaymentRequestValidatorInterface::CALCULATION_ID,
PaymentRequestValidatorInterface::B2B_COMPANY_TYPE,
PaymentRequestValidatorInterface::B2B_COMPANY_NAME,
PaymentRequestValidatorInterface::B2B_COMPANY_VAT_ID,
PaymentRequestValidatorInterface::B2B_COMPANY_OWNER_FIRST_NAME,
PaymentRequestValidatorInterface::B2B_COMPANY_OWNER_LAST_NAME,
PaymentRequestValidatorInterface::B2B_COMPANY_ACCEPT_CREDIT_CHECK,
PaymentRequestValidatorInterface::BIRTHDAY_DAY,
PaymentRequestValidatorInterface::BIRTHDAY_MONTH,
PaymentRequestValidatorInterface::BIRTHDAY_YEAR,
PaymentRequestValidatorInterface::INVOICE_ACCEPT_CREDIT_CHECK,
PaymentRequestValidatorInterface::INSTALLMENTS_ACCEPT_CREDIT_CHECK,
PaymentRequestValidatorInterface::INSTALLMENTS_DURATION,
PaymentRequestValidatorInterface::INSTALLMENTS_ACCOUNT_HOLDER,
PaymentRequestValidatorInterface::INSTALLMENTS_ACCOUNT_IBAN,
PaymentRequestValidatorInterface::DIRECT_DEBIT_MANDATE_OWNER,
PaymentRequestValidatorInterface::DIRECT_DEBIT_MANDATE_IBAN,
PaymentRequestValidatorInterface::DIRECT_DEBIT_ACCEPT_CREDIT_CHECK,
PaymentRequestValidatorInterface::DIRECT_DEBIT_ACCEPT_MANDATE,
];
}
private function updateOrderTransactionLineItems(OrderTransactionEntity $orderTransaction, Context $context): void
{
foreach ($orderTransaction->getOrder()->getLineItems() as $orderLineItem) {
$this->orderTransactionDataHandler->updateOrderLineItemData(
$orderLineItem,
$context,
[
CustomFieldsInterface::IS_PAYOLUTION_PAYMENT => true,
CustomFieldsInterface::IS_PAYMENT_CAPTURED => false,
CustomFieldsInterface::IS_PAYMENT_REFUNDED => false,
]
);
}
}
}