Skip to content

Commit

Permalink
Merge pull request #176 from Invertus/fix-loop-and-assert-write
Browse files Browse the repository at this point in the history
[SL-240,SV-15] Fix infinite loop after payment
  • Loading branch information
GytisZum authored Aug 1, 2024
2 parents 3c89b8b + 9c9e747 commit 008f558
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 229 deletions.
75 changes: 75 additions & 0 deletions controllers/front/ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Invertus\SaferPay\Controller\Front\CheckoutController;
use Invertus\SaferPay\Core\Payment\DTO\CheckoutData;
use Invertus\SaferPay\Enum\ControllerName;
use Invertus\SaferPay\Repository\SaferPayOrderRepository;

if (!defined('_PS_VERSION_')) {
exit;
Expand All @@ -43,7 +44,81 @@ public function postProcess()
case 'submitHostedFields':
$this->submitHostedFields();
break;
case 'getStatus':
$this->processGetStatus();
break;
}
}

/**
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
*/
protected function processGetStatus()
{
header('Content-Type: application/json;charset=UTF-8');
/** @var SaferPayOrderRepository $saferPayOrderRepository */
$saferPayOrderRepository = $this->module->getService(SaferPayOrderRepository::class);
$cartId = Tools::getValue('cartId');
$secureKey = Tools::getValue('secureKey');
$isBusinessLicence = (int) Tools::getValue(SaferPayConfig::IS_BUSINESS_LICENCE);
$fieldToken = Tools::getValue('fieldToken');
$moduleId = $this->module->id;
$selectedCard = Tools::getValue('selectedCard');
$saferPayOrderId = $saferPayOrderRepository->getIdByCartId($cartId);
$saferPayOrder = new SaferPayOrder($saferPayOrderId);

if (!$saferPayOrder->id || $saferPayOrder->canceled) {
$this->ajaxDie(json_encode([
'isFinished' => true,
'href' => $this->getFailControllerLink($cartId, $secureKey, $moduleId)
]));
}

$this->ajaxDie(json_encode([
'saferpayOrder' => json_encode($saferPayOrder),
'isFinished' => $saferPayOrder->authorized || $saferPayOrder->captured || $saferPayOrder->pending,
'href' => $this->context->link->getModuleLink(
$this->module->name,
$this->getSuccessControllerName($isBusinessLicence, $fieldToken),
[
'cartId' => $cartId,
'orderId' => $saferPayOrder->id_order,
'moduleId' => $moduleId,
'secureKey' => $secureKey,
'selectedCard' => $selectedCard,
]
)
]));
}

private function getFailControllerLink($cartId, $secureKey, $moduleId)
{
return $this->context->link->getModuleLink(
$this->module->name,
ControllerName::FAIL,
[
'cartId' => $cartId,
'secureKey' => $secureKey,
'moduleId' => $moduleId,
],
true
);
}

private function getSuccessControllerName($isBusinessLicence, $fieldToken)
{
$successController = ControllerName::SUCCESS;

if ($isBusinessLicence) {
$successController = ControllerName::SUCCESS_IFRAME;
}

if ($fieldToken) {
$successController = ControllerName::SUCCESS_HOSTED;
}

return $successController;
}

private function submitHostedFields()
Expand Down
51 changes: 40 additions & 11 deletions controllers/front/notify.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,23 @@ public function postProcess()
$secureKey
));

if (!$lockResult->isSuccessful()) {
die($this->module->l('Lock already exist', self::FILENAME));
if (!SaferPayConfig::isVersion17()) {
if ($lockResult > 200) {
die($this->module->l('Lock already exists', self::FILENAME));
}
} else {
if (!$lockResult->isSuccessful()) {
die($this->module->l('Lock already exists', self::FILENAME));
}
}

if ($cart->orderExists()) {
$order = new Order($this->getOrderId($cartId));
$completed = (int) Configuration::get(SaferPayConfig::SAFERPAY_PAYMENT_COMPLETED);

if ((int) $order->current_state === $completed) {
die($this->module->l('Order already complete', self::FILENAME));
}
}

/** @var SaferPayOrderRepository $saferPayOrderRepository */
Expand All @@ -87,6 +102,7 @@ public function postProcess()

$checkoutData->setOrderStatus($transactionStatus);
$checkoutProcessor->run($checkoutData);

$orderId = $this->getOrderId($cartId);

//TODO look into pipeline design pattern to use when object is modified in multiple places to avoid this issue.
Expand Down Expand Up @@ -129,28 +145,40 @@ public function postProcess()
$orderStatusService->capture($order);
}
} catch (Exception $e) {
$this->releaseLock();
// this might be executed after pending transaction is declined (e.g. with accountToAccount payment)
if (!isset($order)) {
$orderId = $this->getOrderId($cartId);
$order = new Order($orderId);
$order = new Order($this->getOrderId($cartId));
}

if ($order->id) {
$orderId = (int) $order->id;

if ($orderId) {
$saferPayCapturedStatus = (int) Configuration::get(\Invertus\SaferPay\Config\SaferPayConfig::SAFERPAY_PAYMENT_COMPLETED);

if ((int) $order->current_state === $saferPayCapturedStatus) {
die($this->module->l('Order already created', self::FILENAME));
}

// assuming order transaction was declined
$order->setCurrentState(_SAFERPAY_PAYMENT_AUTHORIZATION_FAILED_);
$order->update();
$saferPayOrder = new SaferPayOrder($saferPayOrderRepository->getIdByOrderId($order->id));
} else {
// assuming order transaction was cancelled before ps order was even made
$saferPayOrder = new SaferPayOrder($saferPayOrderRepository->getIdByCartId($cartId));
}

// using cartId, because ps order might not be assigned yet
$saferPayOrder = new SaferPayOrder($saferPayOrderRepository->getIdByCartId($cartId));

if ($saferPayOrder->id) {
$saferPayOrder->authorized = false;
$saferPayOrder->pending = false;
$saferPayOrder->canceled = true;

if ($orderId) {
// assign ps order to saferpay order id in case it was not assigned previously
$saferPayOrder->id_order = $orderId;
}

$saferPayOrder->update();
$this->releaseLock();
die('canceled');
}

PrestaShopLogger::addLog(
Expand All @@ -166,6 +194,7 @@ public function postProcess()
true
);
$this->releaseLock();

die($this->module->l($e->getMessage(), self::FILENAME));
}

Expand Down
101 changes: 5 additions & 96 deletions controllers/front/return.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
use Invertus\SaferPay\DTO\Response\Assert\AssertBody;
use Invertus\SaferPay\Enum\ControllerName;
use Invertus\SaferPay\Exception\Api\SaferPayApiException;
use Invertus\SaferPay\Repository\SaferPayOrderRepository;
use Invertus\SaferPay\Service\SaferPayOrderStatusService;
use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionAssertion;
use Invertus\SaferPay\Service\TransactionFlow\SaferPayTransactionAuthorization;
Expand All @@ -43,26 +42,20 @@ class SaferPayOfficialReturnModuleFrontController extends AbstractSaferPayContro
public function postProcess()
{
$cartId = (int) Tools::getValue('cartId');
$isBusinessLicence = (int) Tools::getValue(SaferPayConfig::IS_BUSINESS_LICENCE);
$selectedCard = (int) Tools::getValue('selectedCard');
$order = new Order($this->getOrderId($cartId));

if (!$order->id) {
return;
}

try {
if ($isBusinessLicence) {
$response = $this->executeTransaction($cartId, $selectedCard);
} else {
$response = $this->assertTransaction($cartId);
}

\PrestaShopLogger::addLog($response->getTransaction()->getStatus());
/** @var SaferPayTransactionAssertion $transactionAssert */
$transactionAssert = $this->module->getService(SaferPayTransactionAssertion::class);
$transactionResponse = $transactionAssert->assert($cartId, false);

/** @var SaferPayOrderStatusService $orderStatusService */
$orderStatusService = $this->module->getService(SaferPayOrderStatusService::class);
if ($response->getTransaction()->getStatus() === TransactionStatus::PENDING) {
if ($transactionResponse->getTransaction()->getStatus() === TransactionStatus::PENDING) {
$orderStatusService->setPending($order);
}
} catch (SaferPayApiException $e) {
Expand All @@ -75,13 +68,6 @@ public function postProcess()
*/
public function initContent()
{
if (Tools::getValue('ajax')) {
$this->processAjax();
exit;
}

parent::initContent();

$cartId = Tools::getValue('cartId');
$secureKey = Tools::getValue('secureKey');
$isBusinessLicence = (int) Tools::getValue(SaferPayConfig::IS_BUSINESS_LICENCE);
Expand Down Expand Up @@ -136,7 +122,7 @@ public function initContent()
'checkStatusEndpoint',
$this->context->link->getModuleLink(
$this->module->name,
'return',
'ajax',
[
'ajax' => 1,
'action' => 'getStatus',
Expand All @@ -155,62 +141,6 @@ public function initContent()
$this->setTemplate('saferpay_wait_16.tpl');
}

protected function processAjax()
{
if (empty($this->context->customer->id)) {
return;
}

switch (Tools::getValue('action')) {
case 'getStatus':
$this->processGetStatus();
break;
}

exit;
}

/**
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
*/
protected function processGetStatus()
{
header('Content-Type: application/json;charset=UTF-8');
/** @var SaferPayOrderRepository $saferPayOrderRepository */
$saferPayOrderRepository = $this->module->getService(SaferPayOrderRepository::class);
$cartId = Tools::getValue('cartId');
$secureKey = Tools::getValue('secureKey');
$isBusinessLicence = (int) Tools::getValue(SaferPayConfig::IS_BUSINESS_LICENCE);
$fieldToken = Tools::getValue('fieldToken');
$moduleId = $this->module->id;
$selectedCard = Tools::getValue('selectedCard');
$saferPayOrderId = $saferPayOrderRepository->getIdByCartId($cartId);
$saferPayOrder = new SaferPayOrder($saferPayOrderId);

if (!$saferPayOrder->id || $saferPayOrder->canceled) {
$this->ajaxDie(json_encode([
'isFinished' => true,
'href' => $this->getFailControllerLink($cartId, $secureKey, $moduleId)
]));
}

$this->ajaxDie(json_encode([
'isFinished' => $saferPayOrder->authorized || $saferPayOrder->captured || $saferPayOrder->pending,
'href' => $this->context->link->getModuleLink(
$this->module->name,
$this->getSuccessControllerName($isBusinessLicence, $fieldToken),
[
'cartId' => $cartId,
'orderId' => $saferPayOrder->id_order,
'moduleId' => $moduleId,
'secureKey' => $secureKey,
'selectedCard' => $selectedCard,
]
)
]));
}

private function getSuccessControllerName($isBusinessLicence, $fieldToken)
{
$successController = ControllerName::SUCCESS;
Expand All @@ -226,20 +156,6 @@ private function getSuccessControllerName($isBusinessLicence, $fieldToken)
return $successController;
}

private function getFailControllerLink($cartId, $secureKey, $moduleId)
{
return $this->context->link->getModuleLink(
$this->module->name,
ControllerName::FAIL,
[
'cartId' => $cartId,
'secureKey' => $secureKey,
'moduleId' => $moduleId,
],
true
);
}

/**
* @param int $orderId
* @param int $selectedCard
Expand All @@ -259,13 +175,6 @@ private function executeTransaction($orderId, $selectedCard)
);
}

private function assertTransaction($cartId) {
/** @var SaferPayTransactionAssertion $transactionAssert */
$transactionAssert = $this->module->getService(SaferPayTransactionAssertion::class);

return $transactionAssert->assert($cartId);
}

/**
* @param int $cartId
*
Expand Down
Loading

0 comments on commit 008f558

Please sign in to comment.