Skip to content

Commit

Permalink
Replace webhook controller with payum notifynull and notify implement…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
LucaGallinari committed Sep 12, 2024
1 parent 886df2e commit 2f6daf7
Show file tree
Hide file tree
Showing 13 changed files with 318 additions and 181 deletions.
5 changes: 0 additions & 5 deletions config/routes/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,4 @@
->controller(['webgriffe_sylius_pausepay.controller.payment', 'statusAction'])
->methods(['GET'])
;

$routes->add('webgriffe_sylius_pausepay_plugin_payment_webhook', '/pausepay/webhook')
->controller(['webgriffe_sylius_pausepay.controller.webhook', 'indexAction'])
->methods(['POST'])
;
};
19 changes: 19 additions & 0 deletions config/services/action.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use Webgriffe\SyliusPausePayPlugin\Payum\Action\CancelAction;
use Webgriffe\SyliusPausePayPlugin\Payum\Action\CaptureAction;
use Webgriffe\SyliusPausePayPlugin\Payum\Action\NotifyAction;
use Webgriffe\SyliusPausePayPlugin\Payum\Action\NotifyNullAction;
use Webgriffe\SyliusPausePayPlugin\Payum\Action\StatusAction;
use Webgriffe\SyliusPausePayPlugin\Payum\PausePayApi;

Expand Down Expand Up @@ -40,4 +42,21 @@
])
->tag('payum.action', ['factory' => PausePayApi::GATEWAY_CODE, 'alias' => 'payum.action.cancel']);

$services->set('webgriffe_sylius_pausepay.payum.action.notify_null', NotifyNullAction::class)
->public()
->args([
service('serializer'),
service('webgriffe_sylius_pausepay.repository.payment_order'),
service('webgriffe_sylius_pausepay.logger'),
])
->tag('payum.action', ['factory' => PausePayApi::GATEWAY_CODE, 'alias' => 'payum.action.notify_null']);

$services->set('webgriffe_sylius_pausepay.payum.action.notify', NotifyAction::class)
->public()
->args([
service('serializer'),
service('webgriffe_sylius_pausepay.logger'),
])
->tag('payum.action', ['factory' => PausePayApi::GATEWAY_CODE, 'alias' => 'payum.action.notify']);

};
11 changes: 0 additions & 11 deletions config/services/controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,4 @@
->call('setContainer', [service('service_container')])
->tag('controller.service_arguments')
;

$services->set('webgriffe_sylius_pausepay.controller.webhook', WebhookController::class)
->args([
service('serializer'),
service('sylius.repository.payment'),
service('sylius.repository.payment'),
service('webgriffe_sylius_pausepay.logger'),
])
->call('setContainer', [service('service_container')])
->tag('controller.service_arguments')
;
};
101 changes: 0 additions & 101 deletions src/Controller/WebhookController.php

This file was deleted.

4 changes: 1 addition & 3 deletions src/Payum/Action/CaptureAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,7 @@ public function execute($request): void
),
);

$payment->setDetails(
PaymentDetailsHelper::createFromContractCreateResult($createOrderResult),
);
$payment->setDetails(PaymentDetailsHelper::createFromContractCreateResult($createOrderResult));

throw new HttpRedirect($redirectUrl);
}
Expand Down
106 changes: 106 additions & 0 deletions src/Payum/Action/NotifyAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace Webgriffe\SyliusPausePayPlugin\Payum\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Reply\HttpResponse;
use Payum\Core\Request\GetHttpRequest;
use Payum\Core\Request\Notify;
use Payum\Core\Security\TokenInterface;
use Psr\Log\LoggerInterface;
use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface;
use Sylius\Component\Core\Model\PaymentInterface;
use Sylius\Component\Core\Model\PaymentInterface as SyliusPaymentInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Webgriffe\SyliusPausePayPlugin\Client\PaymentState;
use Webgriffe\SyliusPausePayPlugin\Helper\PaymentDetailsHelper;
use Webgriffe\SyliusPausePayPlugin\Payum\PausePayApi;
use Webgriffe\SyliusPausePayPlugin\ValueObject\WebhookPayload;
use Webmozart\Assert\Assert;

/**
* @psalm-suppress PropertyNotSetInConstructor
*
* @psalm-type PaymentDetails array{uuid: string, redirect_url: string, created_at: string, status?: string}
*/
class NotifyAction implements ActionInterface, GatewayAwareInterface
{
use GatewayAwareTrait;

public function __construct(
private SerializerInterface $serializer,
private LoggerInterface $logger,
) {
}

/**
* @param Notify|mixed $request
*/
public function execute($request): void
{
RequestNotSupportedException::assertSupports($this, $request);
Assert::isInstanceOf($request, Notify::class);

/** @var SyliusPaymentInterface $syliusPayment */
$syliusPayment = $request->getModel();

$this->logInfo($syliusPayment, 'Start notify action');

$notifyToken = $request->getToken();
Assert::isInstanceOf($notifyToken, TokenInterface::class);

$this->gateway->execute($httpRequest = new GetHttpRequest());
$content = $httpRequest->content;

$this->logInfo($syliusPayment, sprintf('Received notify action call with payload: %s', $content));

$payload = $this->serializer->deserialize($content, WebhookPayload::class, 'json');
Assert::isInstanceOf($payload, WebhookPayload::class);

$this->assertPausePayPayment($syliusPayment);

$paymentDetails = $syliusPayment->getDetails();
if (!PaymentDetailsHelper::areValid($paymentDetails)) {
// todo
throw new HttpResponse('Not found', 404);
}

$status = $payload->isSuccessful() ? PaymentState::SUCCESS : PaymentState::CANCELLED;
$syliusPayment->setDetails(PaymentDetailsHelper::addPaymentStatus($paymentDetails, $status));

$this->logInfo($syliusPayment, sprintf('Saved payment status: %s', $status));
}

public function supports($request): bool
{
return $request instanceof Notify && $request->getModel() instanceof SyliusPaymentInterface;
}

private function assertPausePayPayment(PaymentInterface $syliusPayment): void
{
$paymentMethod = $syliusPayment->getMethod();
if (!$paymentMethod instanceof PaymentMethodInterface) {
throw new HttpResponse('Access denied', 403);
}

$paymentGatewayConfig = $paymentMethod->getGatewayConfig();
if (!$paymentGatewayConfig instanceof GatewayConfigInterface) {
throw new HttpResponse('Access denied', 403);
}
/** @psalm-suppress DeprecatedMethod */
if ($paymentGatewayConfig->getFactoryName() !== PausePayApi::GATEWAY_CODE) {
throw new HttpResponse('Access denied', 403);
}
}

private function logInfo(SyliusPaymentInterface $payment, string $message, array $context = []): void
{
$this->logger->info(sprintf('[Payment #%s]: %s.', (string) $payment->getId(), $message, ), $context);
}
}
76 changes: 76 additions & 0 deletions src/Payum/Action/NotifyNullAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

namespace Webgriffe\SyliusPausePayPlugin\Payum\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Reply\HttpResponse;
use Payum\Core\Request\GetHttpRequest;
use Payum\Core\Request\Notify;
use Psr\Log\LoggerInterface;
use Sylius\Bundle\PayumBundle\Model\PaymentSecurityTokenInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Webgriffe\SyliusPausePayPlugin\Entity\PaymentOrderInterface;
use Webgriffe\SyliusPausePayPlugin\Repository\PaymentOrderRepositoryInterface;
use Webgriffe\SyliusPausePayPlugin\ValueObject\WebhookPayload;
use Webmozart\Assert\Assert;

/**
* @psalm-suppress PropertyNotSetInConstructor
*
* @psalm-type PaymentDetails array{uuid: string, redirect_url: string, created_at: string, status?: string}
*/
class NotifyNullAction implements ActionInterface, GatewayAwareInterface
{
use GatewayAwareTrait;

public function __construct(
private SerializerInterface $serializer,
private PaymentOrderRepositoryInterface $paymentOrderRepository,
private LoggerInterface $logger,
) {
}

/**
* @param Notify|mixed $request
*/
public function execute($request): void
{
RequestNotSupportedException::assertSupports($this, $request);
Assert::isInstanceOf($request, Notify::class);

$this->logger->info('Start notify null action');
$this->gateway->execute($httpRequest = new GetHttpRequest());
$notifyToken = $this->retrieveNotifyTokenFromRequest($httpRequest);
$this->logger->info(sprintf('Calling notify action with token: %s', $notifyToken->getHash()));
$this->gateway->execute(new Notify($notifyToken));
}

public function supports($request): bool
{
return $request instanceof Notify && null === $request->getModel();
}

private function retrieveNotifyTokenFromRequest(GetHttpRequest $httpRequest): PaymentSecurityTokenInterface
{
// todo: validate signature in X-Pausepay-Signature
$content = $httpRequest->content;

$this->logger->info(sprintf('Received notify null action call with payload: %s', $content));

$payload = $this->serializer->deserialize($content, WebhookPayload::class, 'json');
Assert::isInstanceOf($payload, WebhookPayload::class);

$paymentOrder = $this->paymentOrderRepository->findOneByPausePayOrderId($payload->getOrderID());
if (!$paymentOrder instanceof PaymentOrderInterface) {
// todo
throw new HttpResponse('Not found', 404);
}

return $paymentOrder->getPaymentToken();
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
parameters:
payment_orderToShip_details:
uuid: 'A6BBDBAE-658F-43DA-A534-B289DAB2271E'
created_at: '<(new DateTime())>'
redirect_url: 'https://test-app.pausepay.it/8e68640bb8'

Sylius\Component\Core\Model\Order:
orderToShip:
number: '000000123'
Expand Down Expand Up @@ -28,3 +34,17 @@ Sylius\Component\Core\Model\Payment:
order: '@orderToShip'
currency_code: 'EUR'
state: 'new'
__calls:
- setDetails: ['<{payment_orderToShip_details}>']

Sylius\Bundle\PayumBundle\Model\PaymentSecurityToken:
paymentToken_orderToShip:
hash: '3ocZLKOx41X04m63TnS9nrBFP6CN6Tu_lHBPvpGwn1o'
afterUrl: 'http://localhost:8080/checkout/thank-you/000000123'
targetUrl: 'http://localhost:8080/checkout/thank-you/000000123'
gatewayName: 'pausepay'

Tests\Webgriffe\SyliusPausePayPlugin\App\Entity\Payment\PaymentOrder:
paymentOrder_orderToShip:
orderId: '0b58e4e4-1edc-4f2c-991f-112db59e982d'
paymentToken: '@paymentToken_orderToShip'
Loading

0 comments on commit 2f6daf7

Please sign in to comment.