Skip to content

Commit

Permalink
Merge pull request #102 from vippsas/publication-2.4.17
Browse files Browse the repository at this point in the history
VIPPS-385: Duplicate and missing order issue
  • Loading branch information
voleye authored Jun 4, 2021
2 parents d8d4b7c + 169a09b commit 99ae1ff
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 53 deletions.
2 changes: 1 addition & 1 deletion Api/QuoteRepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ public function save(QuoteInterface $quote);
* @return QuoteInterface
* @throws NoSuchEntityException
*/
public function loadByOrderId($orderId): ?QuoteInterface;
public function loadByOrderId($orderId): QuoteInterface;
}
76 changes: 52 additions & 24 deletions Controller/Payment/Fallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,27 @@
use Magento\Checkout\Model\Session;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\Request\InvalidRequestException;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\Request\InvalidRequestException;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Message\ManagerInterface;
use Magento\Framework\Session\SessionManagerInterface;
use Magento\Payment\Gateway\ConfigInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\Quote;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\OrderManagementInterface;
use Psr\Log\LoggerInterface;
use Vipps\Payment\Api\Data\QuoteInterface;
use Vipps\Payment\Api\QuoteRepositoryInterface;
use Vipps\Payment\Gateway\Transaction\Transaction;
use Vipps\Payment\Model\Gdpr\Compliance;
use Vipps\Payment\Model\OrderLocator;
use Vipps\Payment\Model\TransactionProcessor;

/**
Expand Down Expand Up @@ -96,7 +98,7 @@ class Fallback implements ActionInterface, CsrfAwareActionInterface
/**
* @var QuoteInterface
*/
private $vippsQuote = null;
private $vippsQuote;

/**
* @var ResultFactory
Expand All @@ -108,6 +110,16 @@ class Fallback implements ActionInterface, CsrfAwareActionInterface
*/
private $config;

/**
* @var OrderLocator
*/
private $orderLocator;

/**
* @var OrderInterface|null
*/
private $order;

/**
* Fallback constructor.
*
Expand All @@ -119,6 +131,7 @@ class Fallback implements ActionInterface, CsrfAwareActionInterface
* @param ManagerInterface $messageManager
* @param QuoteRepositoryInterface $vippsQuoteRepository
* @param OrderManagementInterface $orderManagement
* @param OrderLocator $orderLocator
* @param Compliance $compliance
* @param LoggerInterface $logger
* @param ConfigInterface $config
Expand All @@ -134,6 +147,7 @@ public function __construct(
ManagerInterface $messageManager,
QuoteRepositoryInterface $vippsQuoteRepository,
OrderManagementInterface $orderManagement,
OrderLocator $orderLocator,
Compliance $compliance,
LoggerInterface $logger,
ConfigInterface $config
Expand All @@ -145,6 +159,7 @@ public function __construct(
$this->cartRepository = $cartRepository;
$this->messageManager = $messageManager;
$this->vippsQuoteRepository = $vippsQuoteRepository;
$this->orderLocator = $orderLocator;
$this->gdprCompliance = $compliance;
$this->orderManagement = $orderManagement;
$this->logger = $logger;
Expand Down Expand Up @@ -178,16 +193,18 @@ public function execute()
} finally {
$vippsQuote = $this->getVippsQuote(true);
$cartPersistence = $this->config->getValue('cancellation_cart_persistence');
$transactionWasCancelled = $transaction && $transaction->transactionWasCancelled();
$quoteCouldBeRestored = $transaction
&& ($transaction->transactionWasCancelled() || $transaction->isTransactionExpired());
$order = $this->getOrder();

if ($transactionWasCancelled && $cartPersistence) {
if ($quoteCouldBeRestored && $cartPersistence) {
$this->restoreQuote($vippsQuote);
} elseif ($vippsQuote->getOrderId()) {
$this->storeLastOrder($vippsQuote);
} elseif ($order) {
$this->storeLastOrder($order);
}

if (isset($e)) {
if (!$cartPersistence && $this->getVippsQuote()->getOrderId()) {
if (!$cartPersistence && $order) {
$resultRedirect->setPath('checkout/onepage/failure', ['_secure' => true]);
} else {
$resultRedirect->setPath('checkout/cart', ['_secure' => true]);
Expand Down Expand Up @@ -262,7 +279,7 @@ private function authorize()
* @return QuoteInterface
* @throws NoSuchEntityException
*/
private function getVippsQuote($forceReload = false): ?QuoteInterface
private function getVippsQuote($forceReload = false): QuoteInterface
{
if (null === $this->vippsQuote || $forceReload) {
$this->vippsQuote = $this->vippsQuoteRepository
Expand All @@ -288,22 +305,17 @@ private function prepareResponse(Redirect $resultRedirect, Transaction $transact
}

/**
* Method to update Checkout session with Last Placed Order
* Or restore quote if order was not placed (ex. Express Checkout)
* Method store order info to checkout session
*/
private function storeLastOrder(QuoteInterface $vippsQuote)
private function storeLastOrder(OrderInterface $order)
{
if ($vippsQuote->getOrderId()) {
$this->checkoutSession
->clearStorage()
->setLastQuoteId($vippsQuote->getQuoteId())
->setLastSuccessQuoteId($vippsQuote->getQuoteId())
->setLastOrderId($vippsQuote->getOrderId())
->setLastRealOrderId($vippsQuote->getReservedOrderId())
->setLastOrderStatus(
$this->orderManagement->getStatus($vippsQuote->getOrderId())
);
}
$this->checkoutSession
->clearStorage()
->setLastQuoteId($order->getQuoteId())
->setLastSuccessQuoteId($order->getQuoteId())
->setLastOrderId($order->getEntityId())
->setLastRealOrderId($order->getIncrementId())
->setLastOrderStatus($order->getStatus());
}

/**
Expand Down Expand Up @@ -359,12 +371,28 @@ private function defineRedirectPath(Redirect $resultRedirect, Transaction $trans
if ($transaction->isTransactionReserved() || $transaction->isTransactionCaptured()) {
$resultRedirect->setPath('checkout/onepage/success', ['_secure' => true]);
} else {
$orderId = $this->getVippsQuote() ? $this->getVippsQuote()->getOrderId() : null;
$orderId = $this->getOrder() ? $this->getOrder()->getEntityId() : null;
if (!$this->isCartPersistent() && $orderId) {
$resultRedirect->setPath('checkout/onepage/failure', ['_secure' => true]);
} else {
$resultRedirect->setPath('checkout/cart', ['_secure' => true]);
}
}
}

/**
* @param false $forceReload
*
* @return OrderInterface|null
* @throws NoSuchEntityException
*/
private function getOrder($forceReload = false)
{
if (null === $this->order || $forceReload) {
$vippsQuote = $this->getVippsQuote($forceReload);
$this->order = $this->orderLocator->get($vippsQuote->getReservedOrderId());
}

return $this->order;
}
}
17 changes: 13 additions & 4 deletions Model/Quote/CancelFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Vipps\Payment\Api\Data\QuoteInterface;
use Vipps\Payment\Api\Data\QuoteStatusInterface;
use Vipps\Payment\Api\Quote\CancelFacadeInterface;
use Vipps\Payment\Model\OrderLocator;
use Vipps\Payment\Model\Quote;
use Vipps\Payment\Model\QuoteRepository;

Expand Down Expand Up @@ -65,6 +66,11 @@ class CancelFacade implements CancelFacadeInterface
*/
private $orderRepository;

/**
* @var OrderLocator
*/
private $orderLocator;

/**
* @var LoggerInterface
*/
Expand All @@ -79,6 +85,8 @@ class CancelFacade implements CancelFacadeInterface
* @param AttemptManagement $attemptManagement
* @param CartRepositoryInterface $cartRepository
* @param OrderRepositoryInterface $orderRepository
* @param OrderLocator $orderLocator
* @param LoggerInterface $logger
*/
public function __construct(
CommandManagerInterface $commandManager,
Expand All @@ -87,6 +95,7 @@ public function __construct(
AttemptManagement $attemptManagement,
CartRepositoryInterface $cartRepository,
OrderRepositoryInterface $orderRepository,
OrderLocator $orderLocator,
LoggerInterface $logger
) {
$this->commandManager = $commandManager;
Expand All @@ -95,6 +104,7 @@ public function __construct(
$this->attemptManagement = $attemptManagement;
$this->cartRepository = $cartRepository;
$this->orderRepository = $orderRepository;
$this->orderLocator = $orderLocator;
$this->logger = $logger;
}

Expand All @@ -106,10 +116,9 @@ public function __construct(
public function cancel(QuoteInterface $vippsQuote)
{
try {
if ($vippsQuote->getOrderId()) {
/** @var Order $order */
$order = $this->orderRepository->get($vippsQuote->getOrderId());
$this->orderManagement->cancel($vippsQuote->getOrderId());
$order = $this->orderLocator->get($vippsQuote->getReservedOrderId());
if ($order) {
$this->orderManagement->cancel($order->getEntityId());
$this->commandManager->cancel($order->getPayment());
} else {
/** @var \Magento\Quote\Model\Quote $quote */
Expand Down
13 changes: 8 additions & 5 deletions Model/QuoteRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
Expand Down Expand Up @@ -127,18 +128,20 @@ public function loadByQuote($quoteId): QuoteInterface
/**
* Load monitoring quote by quote.
*
* @param $quoteId
* @param int $quoteId
* @param string $status
*
* @return Quote
* @return QuoteInterface
* @throws LocalizedException
* @throws NoSuchEntityException
*/
public function loadNewByQuote($quoteId): QuoteInterface
public function loadNewByQuote($quoteId, $status = QuoteInterface::STATUS_NEW): QuoteInterface
{
$vippsQuote = $this->quoteFactory->create();
$this->quoteResource->loadNewByQuote($vippsQuote, $quoteId, 'quote_id');
$this->quoteResource->loadNewByQuote($vippsQuote, $quoteId, 'quote_id', $status);

if (!$vippsQuote->getId()) {
throw NoSuchEntityException::singleField('quote_id', $quoteId);
throw NoSuchEntityException::doubleField('quote_id', $quoteId, 'status', $status);
}

return $vippsQuote;
Expand Down
12 changes: 9 additions & 3 deletions Model/ResourceModel/Quote.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,17 @@ protected function _construct() //@codingStandardsIgnoreLine
* @param AbstractModel $object
* @param $value
* @param null $field
* @param string $status
*
* @return $this
* @throws LocalizedException
*/
public function loadNewByQuote(AbstractModel $object, $value, $field = null)
{
public function loadNewByQuote(
AbstractModel $object,
$value,
$field = null,
$status = QuoteInterface::STATUS_NEW
) {
$object->beforeLoad($value, $field);
if ($field === null) {
$field = $this->getIdFieldName();
Expand All @@ -67,7 +72,8 @@ public function loadNewByQuote(AbstractModel $object, $value, $field = null)
$select = $connection->select()
->from($this->getMainTable())
->where("$field = ?", $value)
->where('status = ?', QuoteInterface::STATUS_NEW)
->where('status = ?', $status)
->order($this->getIdFieldName() . ' DESC')
->limit(1);
$data = $connection->fetchRow($select);

Expand Down
Loading

0 comments on commit 99ae1ff

Please sign in to comment.