Skip to content

Commit

Permalink
[ECP-9425] Implement payment proxy controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Can Demiralp committed Aug 26, 2024
1 parent ccf34e4 commit 94e5d02
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/Handlers/PaymentResponseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@
use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStateHandler;
use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStates;
use Shopware\Core\Checkout\Payment\Cart\AsyncPaymentTransactionStruct;
use Shopware\Core\Checkout\Payment\Cart\Token\TokenStruct;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;

class PaymentResponseHandler
{
Expand Down Expand Up @@ -459,4 +462,22 @@ private function isTransactionHandled(

return false;
}

public function handleInvalidatedTokenResponse(TokenStruct $paymentToken): Response {
$transactionId = $paymentToken->getTransactionId();
$orderTransaction = $this->adyenOrderTransactionRepository->getWithId($transactionId);

$requiresManualCapture = $this->captureService->isManualCapture(
$orderTransaction->getPaymentMethod()->getHandlerIdentifier()
);

$stateMachineTechnicalName = $orderTransaction->getStateMachineState()->getTechnicalName();

if (($requiresManualCapture && $stateMachineTechnicalName === OrderTransactionStates::STATE_OPEN) ||
(!$requiresManualCapture && $stateMachineTechnicalName === OrderTransactionStates::STATE_AUTHORIZED)) {
return new RedirectResponse($paymentToken->getFinishUrl());
} else {
return new RedirectResponse($paymentToken->getErrorUrl());
}
}
}
8 changes: 8 additions & 0 deletions src/Resources/config/services/controllers.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,13 @@
<argument type="service" key="$logger" id="monolog.logger.adyen_api"/>
<tag name="controller.service_arguments"/>
</service>
<service id="Adyen\Shopware\Storefront\Controller\PaymentProxyController" autowire="true">
<argument key="$tokenFactoryInterfaceV2" type="service" id="Adyen\Shopware\Model\JWTFactoryV2"/>
<argument key="$orderRepository" type="service" id="order.repository"/>
<call method="setContainer">
<argument type="service" id="service_container"/>
</call>
<tag name="controller.service_arguments"/>
</service>
</services>
</container>
144 changes: 144 additions & 0 deletions src/Storefront/Controller/PaymentProxyController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php declare(strict_types=1);
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment Module
*
* Copyright (c) 2020 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*
* Author: Adyen <[email protected]>
*/

namespace Adyen\Shopware\Storefront\Controller;

use Adyen\Shopware\Handlers\PaymentResponseHandler;
use Shopware\Core\Checkout\Cart\Order\OrderConverter;
use Shopware\Core\Checkout\Order\OrderEntity;
use Shopware\Core\Checkout\Payment\Cart\Token\TokenFactoryInterfaceV2;
use Shopware\Core\Checkout\Payment\Cart\Token\TokenStruct;
use Shopware\Core\Checkout\Payment\PaymentException;
use Shopware\Core\Checkout\Payment\PaymentService;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Routing\RoutingException;
use Shopware\Core\Framework\ShopwareException;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

#[Route(defaults: ['_routeScope' => ['storefront']])]
class PaymentProxyController extends AbstractController
{
public function __construct(
private readonly PaymentService $paymentService,
private readonly OrderConverter $orderConverter,
private readonly TokenFactoryInterfaceV2 $tokenFactoryInterfaceV2,
private readonly EntityRepository $orderRepository,
private readonly PaymentResponseHandler $paymentResponseHandler
) {
}

#[Route(path: '/adyen/finalize-transaction', name: 'adyen.finalize.transaction', methods: ['GET', 'POST'])]
public function finalizeTransaction(Request $request): Response
{
$paymentToken = $request->get('_sw_payment_token');

if ($paymentToken === null) {
throw RoutingException::missingRequestParameter('_sw_payment_token');
}

$salesChannelContext = $this->assembleSalesChannelContext($paymentToken);

try {
$result = $this->paymentService->finalizeTransaction(
$paymentToken,
$request,
$salesChannelContext
);
} catch (PaymentException $exception) {
if ($exception->getErrorCode() === PaymentException::PAYMENT_TOKEN_INVALIDATED) {
return $this->paymentResponseHandler->handleInvalidatedTokenResponse(
$this->tokenFactoryInterfaceV2->parseToken($paymentToken)
);
}
}

$response = $this->handleException($result);
if ($response !== null) {
return $response;
}

$finishUrl = $result->getFinishUrl();
if ($finishUrl) {
return new RedirectResponse($finishUrl);
}

return new JsonResponse(null, Response::HTTP_NO_CONTENT);
}

private function handleException(TokenStruct $token): ?Response
{
if ($token->getException() === null) {
return null;
}

if ($token->getErrorUrl() === null) {
return null;
}

$url = $token->getErrorUrl();

$exception = $token->getException();
if ($exception instanceof ShopwareException) {
return new RedirectResponse(
$url . (parse_url($url, \PHP_URL_QUERY) ? '&' : '?') . 'error-code=' . $exception->getErrorCode()
);
}

return new RedirectResponse($url);
}

private function assembleSalesChannelContext(string $paymentToken): SalesChannelContext
{
$context = Context::createDefaultContext();

$transactionId = $this->tokenFactoryInterfaceV2->parseToken($paymentToken)->getTransactionId();
if ($transactionId === null) {
throw PaymentException::invalidToken($paymentToken);
}

$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('transactions.id', $transactionId));
$criteria->addAssociation('transactions');
$criteria->addAssociation('orderCustomer');

/** @var OrderEntity|null $order */
$order = $this->orderRepository->search($criteria, $context)->first();

if ($order === null) {
throw PaymentException::invalidToken($paymentToken);
}

return $this->orderConverter->assembleSalesChannelContext($order, $context);
}
}

0 comments on commit 94e5d02

Please sign in to comment.