Skip to content

Commit

Permalink
Merge pull request #6 from sherlockode/feature/allow_retry_payment
Browse files Browse the repository at this point in the history
Allow user to retry a new payment
  • Loading branch information
Vowow authored Apr 28, 2022
2 parents 21776d7 + ab50012 commit 1a51345
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 11 deletions.
22 changes: 13 additions & 9 deletions src/Controller/CheckoutController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Payum\Core\Payum;
use Sherlockode\SyliusCheckoutPlugin\Checkout\Model\Charge;
use Sherlockode\SyliusCheckoutPlugin\Payum\Request\Confirm;
use Sherlockode\SyliusCheckoutPlugin\Payum\Request\Decline;
use Sylius\Component\Core\Model\PaymentInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
Expand Down Expand Up @@ -69,18 +70,21 @@ public function failureAction(Request $request)
$identity = $token->getDetails();
/** @var PaymentInterface $payment */
$payment = $this->payum->getStorage($identity->getClass())->find($identity);
$details = $payment->getDetails();

$details['checkout']['state'] = Charge::STATE_DECLINED;
$payment->setDetails($details);
$gateway = $this->payum->getGateway('checkout');
$gateway->execute(new Decline($payment));

$this->payum->getHttpRequestVerifier()->invalidate($token);
$afterPayToken = $this->payum->getTokenFactory()->createToken(
'checkout',
$payment,
'sylius_shop_order_after_pay'
);
$tokenFactory = $this->payum->getTokenFactory();

return new RedirectResponse($afterPayToken->getTargetUrl());
$details = $payment->getDetails();

if (isset($details['checkout']['state']) && Charge::STATE_DECLINED === $details['checkout']['state']) {
$nextToken = $tokenFactory->createToken('checkout', $payment, 'sylius_shop_order_after_pay');
} else {
$nextToken = $tokenFactory->createCaptureToken('checkout', $payment, 'sylius_shop_order_after_pay');
}

return new RedirectResponse($nextToken->getTargetUrl());
}
}
4 changes: 4 additions & 0 deletions src/Form/Type/CheckoutConfigurationType.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
->add('webhook_signature', TextType::class, [
'label' => 'sherlockode.checkout.webhook_signature',
'required' => false,
])
->add('retry_declined_payment', CheckboxType::class, [
'label' => 'sherlockode.checkout.retry_declined_payment',
'required' => false,
]);
}
}
1 change: 1 addition & 0 deletions src/Payum/Action/CreateChargeAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public function execute($request): void
$details['checkout'] = [
'id' => $charge->getId(),
'state' => $charge->getStatus(),
'history' => $details['checkout']['history'] ?? [],
];
$payment->setDetails($details);

Expand Down
81 changes: 81 additions & 0 deletions src/Payum/Action/DeclineAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace Sherlockode\SyliusCheckoutPlugin\Payum\Action;

use Payum\Core\Action\ActionInterface;
use Payum\Core\ApiAwareInterface;
use Payum\Core\Exception\LogicException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\GatewayAwareInterface;
use Payum\Core\GatewayAwareTrait;
use Payum\Core\Request\Generic;
use Sherlockode\SyliusCheckoutPlugin\Checkout\Model\Charge;
use Sherlockode\SyliusCheckoutPlugin\Payum\Request\Decline;
use Sylius\Component\Core\Model\PaymentInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

/**
* Class CreateChargeAction
*/
class DeclineAction implements ActionInterface, GatewayAwareInterface, ApiAwareInterface
{
use ApiAwareTrait;
use GatewayAwareTrait;

/**
* @var SessionInterface
*/
private $session;

/**
* DeclineAction constructor.
*
* @param SessionInterface $session
*/
public function __construct(SessionInterface $session)
{
$this->session = $session;
}

/**
* @param Generic $request
*
* @throws LogicException
*/
public function execute($request): void
{
/** @var $request Decline */
RequestNotSupportedException::assertSupports($this, $request);

/** @var PaymentInterface $payment */
$payment = $request->getModel();
$details = $payment->getDetails();

$details['checkout']['state'] = Charge::STATE_DECLINED;

if ($this->api->isRetryDeclinedPayment()) {
$history = $details['checkout']['history'] ?? [];
$current = array_merge($details['checkout'], ['date' => date('Y-d-m H:i:s')]);
unset($current['history']);

$details['checkout'] = [
'history' => array_merge($history, [$current])
];

$payment->setState(PaymentInterface::STATE_NEW);
$this->session->getFlashBag()->add('info', 'sylius.payment.failed');
}

$payment->setDetails($details);
}

/**
* @param Generic $request
*
* @return bool
*/
public function supports($request): bool
{
return $request instanceof Decline && $request->getModel() instanceof PaymentInterface;
}
}
2 changes: 2 additions & 0 deletions src/Payum/Action/ObtainTokenAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public function execute($request): void
'token' => $token,
'instrument' => null,
'persist_instrument' => $form->has('rememberCard') ? $form->get('rememberCard')->getData() : false,
'history' => $details['checkout']['history'] ?? [],
];
$payment->setDetails($details);

Expand All @@ -110,6 +111,7 @@ public function execute($request): void
'token' => null,
'instrument' => $instrument,
'persist_instrument' => false,
'history' => $details['checkout']['history'] ?? [],
];
$payment->setDetails($details);

Expand Down
30 changes: 29 additions & 1 deletion src/Payum/CheckoutApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,32 @@ class CheckoutApi
*/
private $webhookSignature;

/**
* @var bool
*/
private $retryDeclinedPayment;

/**
* CheckoutApi constructor.
*
* @param string $publicKey
* @param string $secretKey
* @param bool $production
* @param string|null $webhookSignature
* @param bool $retryDeclinedPayment
*/
public function __construct(
string $publicKey,
string $secretKey,
bool $production,
?string $webhookSignature = null
?string $webhookSignature = null,
bool $retryDeclinedPayment = false
) {
$this->publicKey = $publicKey;
$this->secretKey = $secretKey;
$this->production = $production;
$this->webhookSignature = $webhookSignature;
$this->retryDeclinedPayment = $retryDeclinedPayment;
}

/**
Expand Down Expand Up @@ -123,4 +131,24 @@ public function setWebhookSignature(?string $webhookSignature): self

return $this;
}

/**
* @return bool
*/
public function isRetryDeclinedPayment(): bool
{
return $this->retryDeclinedPayment;
}

/**
* @param bool $retryDeclinedPayment
*
* @return $this
*/
public function setRetryDeclinedPayment(bool $retryDeclinedPayment): self
{
$this->retryDeclinedPayment = $retryDeclinedPayment;

return $this;
}
}
3 changes: 2 additions & 1 deletion src/Payum/CheckoutGatewayFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ protected function populateConfig(ArrayObject $config): void
$config['public_key'],
$config['secret_key'],
(bool)$config['production'],
$config['webhook_signature']
$config['webhook_signature'],
(bool)$config['retry_declined_payment']
);
};

Expand Down
13 changes: 13 additions & 0 deletions src/Payum/Request/Decline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Sherlockode\SyliusCheckoutPlugin\Payum\Request;

use Payum\Core\Request\Generic;

/**
* Class Decline
*/
class Decline extends Generic
{

}
5 changes: 5 additions & 0 deletions src/Resources/config/services/payum.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
<tag name="payum.action" factory="sylius.checkout" alias="payum.action.create_charge" />
</service>

<service id="Sherlockode\SyliusCheckoutPlugin\Payum\Action\DeclineAction" public="true">
<argument type="service" id="session" />
<tag name="payum.action" factory="sylius.checkout" alias="payum.action.decline" />
</service>

<service id="Sherlockode\SyliusCheckoutPlugin\Payum\Action\ObtainTokenAction" public="true">
<argument type="service" id="form.factory" />
<argument type="service" id="request_stack" />
Expand Down
1 change: 1 addition & 0 deletions src/Resources/translations/messages.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ sherlockode:
pay_order: Pay my order
pay: Pay
webhook_signature: Webhooks authorization header Key
retry_declined_payment: Allow user to retry after payment has been declined
1 change: 1 addition & 0 deletions src/Resources/translations/messages.fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ sherlockode:
pay_order: Payer ma commande
pay: Payer
webhook_signature: Clé d'autorisation pour les webhooks
retry_declined_payment: Autoriser les utilisateurs à réessayer de payer après un paiement échoué

0 comments on commit 1a51345

Please sign in to comment.