diff --git a/Api/QuoteRepositoryInterface.php b/Api/QuoteRepositoryInterface.php index 4f6edc25..55d766f3 100644 --- a/Api/QuoteRepositoryInterface.php +++ b/Api/QuoteRepositoryInterface.php @@ -39,5 +39,5 @@ public function save(QuoteInterface $quote); * @return QuoteInterface * @throws NoSuchEntityException */ - public function loadByOrderId($orderId): ?QuoteInterface; + public function loadByOrderId($orderId): QuoteInterface; } diff --git a/Controller/Payment/Fallback.php b/Controller/Payment/Fallback.php index 4ad498c1..449ec8ec 100644 --- a/Controller/Payment/Fallback.php +++ b/Controller/Payment/Fallback.php @@ -20,12 +20,12 @@ 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; @@ -33,12 +33,14 @@ 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; /** @@ -96,7 +98,7 @@ class Fallback implements ActionInterface, CsrfAwareActionInterface /** * @var QuoteInterface */ - private $vippsQuote = null; + private $vippsQuote; /** * @var ResultFactory @@ -108,6 +110,16 @@ class Fallback implements ActionInterface, CsrfAwareActionInterface */ private $config; + /** + * @var OrderLocator + */ + private $orderLocator; + + /** + * @var OrderInterface|null + */ + private $order; + /** * Fallback constructor. * @@ -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 @@ -134,6 +147,7 @@ public function __construct( ManagerInterface $messageManager, QuoteRepositoryInterface $vippsQuoteRepository, OrderManagementInterface $orderManagement, + OrderLocator $orderLocator, Compliance $compliance, LoggerInterface $logger, ConfigInterface $config @@ -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; @@ -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]); @@ -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 @@ -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()); } /** @@ -359,7 +371,7 @@ 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 { @@ -367,4 +379,20 @@ private function defineRedirectPath(Redirect $resultRedirect, Transaction $trans } } } + + /** + * @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; + } } diff --git a/Model/Quote/CancelFacade.php b/Model/Quote/CancelFacade.php index f82653c8..804c5b92 100644 --- a/Model/Quote/CancelFacade.php +++ b/Model/Quote/CancelFacade.php @@ -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; @@ -65,6 +66,11 @@ class CancelFacade implements CancelFacadeInterface */ private $orderRepository; + /** + * @var OrderLocator + */ + private $orderLocator; + /** * @var LoggerInterface */ @@ -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, @@ -87,6 +95,7 @@ public function __construct( AttemptManagement $attemptManagement, CartRepositoryInterface $cartRepository, OrderRepositoryInterface $orderRepository, + OrderLocator $orderLocator, LoggerInterface $logger ) { $this->commandManager = $commandManager; @@ -95,6 +104,7 @@ public function __construct( $this->attemptManagement = $attemptManagement; $this->cartRepository = $cartRepository; $this->orderRepository = $orderRepository; + $this->orderLocator = $orderLocator; $this->logger = $logger; } @@ -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 */ diff --git a/Model/QuoteRepository.php b/Model/QuoteRepository.php index 035a946c..3ce0cb84 100644 --- a/Model/QuoteRepository.php +++ b/Model/QuoteRepository.php @@ -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; @@ -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; diff --git a/Model/ResourceModel/Quote.php b/Model/ResourceModel/Quote.php index 55689155..7985b18b 100644 --- a/Model/ResourceModel/Quote.php +++ b/Model/ResourceModel/Quote.php @@ -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(); @@ -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); diff --git a/Model/TransactionProcessor.php b/Model/TransactionProcessor.php index 45e782f7..7269163e 100644 --- a/Model/TransactionProcessor.php +++ b/Model/TransactionProcessor.php @@ -73,6 +73,11 @@ class TransactionProcessor */ private $quoteLocator; + /** + * @var OrderLocator + */ + private $orderLocator; + /** * @var Processor */ @@ -140,6 +145,7 @@ public function __construct( CartRepositoryInterface $cartRepository, CartManagementInterface $cartManagement, QuoteLocator $quoteLocator, + OrderLocator $orderLocator, Processor $processor, QuoteUpdater $quoteUpdater, LockManager $lockManager, @@ -154,6 +160,7 @@ public function __construct( $this->cartRepository = $cartRepository; $this->cartManagement = $cartManagement; $this->quoteLocator = $quoteLocator; + $this->orderLocator = $orderLocator; $this->processor = $processor; $this->quoteUpdater = $quoteUpdater; $this->lockManager = $lockManager; @@ -187,9 +194,6 @@ public function process(QuoteInterface $vippsQuote) $vippsQuote->getReservedOrderId() ); - // reload quote because it could be changed by another process - $vippsQuote = $this->quoteManagement->reload($vippsQuote); - if ($transaction->transactionWasCancelled() || $transaction->transactionWasVoided()) { $this->processCancelledTransaction($vippsQuote); } elseif ($transaction->isTransactionReserved()) { @@ -213,8 +217,9 @@ public function process(QuoteInterface $vippsQuote) */ private function processCancelledTransaction(QuoteInterface $vippsQuote) { - if ($vippsQuote->getOrderId()) { - $this->cancelOrder($vippsQuote->getOrderId()); + $order = $this->orderLocator->get($vippsQuote->getReservedOrderId()); + if ($order) { + $this->cancelOrder($order); } $vippsQuote->setStatus(QuoteStatusInterface::STATUS_CANCELED); @@ -234,9 +239,8 @@ private function processCancelledTransaction(QuoteInterface $vippsQuote) */ private function processReservedTransaction(QuoteInterface $vippsQuote, Transaction $transaction) { - if ($vippsQuote->getOrderId()) { - $order = $this->orderRepository->get($vippsQuote->getOrderId()); - } else { + $order = $this->orderLocator->get($vippsQuote->getReservedOrderId()); + if (!$order) { $order = $this->placeOrder($vippsQuote, $transaction); } @@ -260,8 +264,9 @@ private function processReservedTransaction(QuoteInterface $vippsQuote, Transact */ private function processExpiredTransaction(QuoteInterface $vippsQuote) { - if ($vippsQuote->getOrderId()) { - $this->orderManagement->cancel($vippsQuote->getOrderId()); + $order = $this->orderLocator->get($vippsQuote->getReservedOrderId()); + if ($order) { + $this->cancelOrder($order); } $vippsQuote->setStatus(QuoteStatusInterface::STATUS_EXPIRED); @@ -495,15 +500,14 @@ private function notify(OrderInterface $order) } /** - * @param int $orderId + * @param $order * * @throws \Exception */ - private function cancelOrder($orderId): void + private function cancelOrder($order): void { - $order = $this->orderRepository->get($orderId); if ($order->getState() === Order::STATE_NEW) { - $this->orderManagement->cancel($orderId); + $this->orderManagement->cancel($order->getEntityId()); } else { $connection = $this->resourceConnection->getConnection(); try { @@ -511,7 +515,7 @@ private function cancelOrder($orderId): void $order->setState(Order::STATE_NEW); $this->orderRepository->save($order); - $this->orderManagement->cancel($orderId); + $this->orderManagement->cancel($order->getEntityId()); $connection->commit(); } catch (\Exception $e) { diff --git a/composer.json b/composer.json index b3a54d8f..9176ffad 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "type": "magento2-module", "description": "Vipps Payment Method", "license": "proprietary", - "version": "2.4.16", + "version": "2.4.17", "require": { "magento/framework": "103.0.*", "magento/module-sales": "103.0.*",