Skip to content

Commit 73abf07

Browse files
Merge pull request #1046 from buckaroo-it/BP-3755-iDEAL-fast-checkout-shopping-cart-should-not-be-empty-after-cancellation-go-back
BP-3755-iDEAL-fast-checkout-shopping-cart-should-not-be-empty-after-cancellation-go-back
2 parents a7f439d + a666cb1 commit 73abf07

File tree

4 files changed

+198
-129
lines changed

4 files changed

+198
-129
lines changed

Controller/Redirect/Process.php

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -480,27 +480,12 @@ protected function handleFailed($statusCode)
480480
$this->removeCoupon();
481481
$this->removeAmastyGiftcardOnFailed();
482482

483-
// Exit early if skipping quote recreation
484-
if ($this->getSkipHandleFailedRecreate()) {
485-
return $this->processFailedOrder($statusCode);
486-
}
487-
488-
// Exit early if the action is from payfastcheckout
489-
if ($this->response['add_service_action_from_magento'] === 'payfastcheckout') {
490-
return $this->processFailedOrder($statusCode);
491-
}
492-
493-
// Attempt to recreate the quote and log an error if it fails
494-
if (!$this->quoteRecreate->recreate($this->quote)) {
495-
$this->logger->addError('Could not recreate the quote.');
496-
return $this->processFailedOrder($statusCode);
483+
if (!$this->getSkipHandleFailedRecreate()) {
484+
if (!$this->quoteRecreate->recreate($this->quote, $this->response)) {
485+
$this->logging->addError('Could not recreate the quote.');
486+
}
497487
}
498488

499-
return $this->processFailedOrder($statusCode);
500-
}
501-
502-
protected function processFailedOrder($statusCode)
503-
{
504489
/*
505490
* Something went wrong, so we're going to have to
506491
* 1) recreate the quote for the user

Observer/RestoreQuote.php

Lines changed: 142 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -24,68 +24,30 @@
2424
use Magento\Checkout\Model\Session;
2525
use Buckaroo\Magento2\Model\Service\Order;
2626
use Buckaroo\Magento2\Model\Method\Payconiq;
27-
use Buckaroo\Magento2\Model\Method\Giftcards;
2827
use Magento\Quote\Api\CartRepositoryInterface;
2928
use Buckaroo\Magento2\Model\ConfigProvider\Account;
3029
use Buckaroo\Magento2\Helper\PaymentGroupTransaction;
3130
use Buckaroo\Magento2\Model\Giftcard\Remove as GiftcardRemove;
32-
use Buckaroo\Magento2\Model\Method\AbstractMethod;
33-
use Buckaroo\Magento2\Service\Sales\Quote\Recreate as QuoteRecreate;
31+
use Magento\Framework\Event\Observer;
32+
use Magento\Framework\Event\ObserverInterface;
33+
use Magento\Quote\Model\Quote;
3434

35-
class RestoreQuote implements \Magento\Framework\Event\ObserverInterface
35+
class RestoreQuote implements ObserverInterface
3636
{
37-
/**
38-
* @var \Magento\Checkout\Model\Session
39-
*/
4037
private $checkoutSession;
41-
42-
/**
43-
* @var \Buckaroo\Magento2\Model\ConfigProvider\Account
44-
*/
4538
protected $accountConfig;
46-
47-
/**
48-
* @var \Buckaroo\Magento2\Helper\Data
49-
*/
50-
private \Buckaroo\Magento2\Helper\Data $helper;
51-
52-
53-
54-
/**
55-
* @var \Magento\Quote\Api\CartRepositoryInterface
56-
*/
39+
private $helper;
5740
protected $quoteRepository;
58-
59-
/**
60-
* @var \Buckaroo\Magento2\Model\Service\Order
61-
*/
6241
protected $orderService;
63-
64-
/**
65-
* @var \Buckaroo\Magento2\Model\Giftcard\Remove
66-
*/
6742
protected $giftcardRemoveService;
68-
69-
/**
70-
* @var \Buckaroo\Magento2\Helper\PaymentGroupTransaction
71-
*/
7243
protected $groupTransaction;
7344

74-
75-
/**
76-
* @param Session $checkoutSession
77-
* @param Account $accountConfig
78-
* @param Data $helper
79-
* @param QuoteRecreate $quoteRecreate
80-
* @param CartRepositoryInterface $quoteRepository
81-
* @param Order $orderService
82-
*/
8345
public function __construct(
84-
\Magento\Checkout\Model\Session $checkoutSession,
85-
\Buckaroo\Magento2\Model\ConfigProvider\Account $accountConfig,
86-
\Buckaroo\Magento2\Helper\Data $helper,
87-
\Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
88-
\Buckaroo\Magento2\Model\Service\Order $orderService,
46+
Session $checkoutSession,
47+
Account $accountConfig,
48+
Data $helper,
49+
CartRepositoryInterface $quoteRepository,
50+
Order $orderService,
8951
GiftcardRemove $giftcardRemoveService,
9052
PaymentGroupTransaction $groupTransaction
9153
) {
@@ -101,57 +63,38 @@ public function __construct(
10163
/**
10264
* Restore Quote and Cancel LastRealOrder
10365
*
104-
* @param \Magento\Framework\Event\Observer $observer
66+
* @param Observer $observer
10567
* @return void
10668
*/
107-
public function execute(\Magento\Framework\Event\Observer $observer)
69+
public function execute(Observer $observer)
10870
{
10971
$this->helper->addDebug(__METHOD__ . '|1|' . var_export($this->checkoutSession->getData(), true));
11072

11173
$lastRealOrder = $this->checkoutSession->getLastRealOrder();
11274
$previousOrderId = $lastRealOrder->getId();
11375

11476
if ($payment = $lastRealOrder->getPayment()) {
115-
if ($this->shouldSkipFurtherEventHandling()
116-
|| strpos($payment->getMethod(), 'buckaroo_magento2') === false
117-
|| in_array($payment->getMethod(), [Payconiq::PAYMENT_METHOD_CODE])) {
77+
if ($this->shouldSkipFurtherEventHandling() || $this->isPayconiqPaymentMethod($payment)) {
11878
$this->helper->addDebug(__METHOD__ . '|10|');
11979
return;
12080
}
12181

122-
if ($payment->getMethod() === 'buckaroo_magento2_ideal' &&
123-
isset($payment->getAdditionalInformation()['issuer']) &&
124-
$payment->getAdditionalInformation()['issuer'] === 'fastcheckout') {
125-
$this->helper->addDebug(__METHOD__ . '|Detected buckaroo_magento2_ideal with issuer fastcheckout, handling accordingly.');
126-
return;
127-
}
128-
12982
if ($this->accountConfig->getCartKeepAlive($lastRealOrder->getStore())) {
13083
$this->helper->addDebug(__METHOD__ . '|20|');
13184

132-
if ($this->checkoutSession->getQuote()
133-
&& $this->checkoutSession->getQuote()->getId()
134-
&& ($quote = $this->quoteRepository->getActive($this->checkoutSession->getQuote()->getId()))
135-
) {
136-
$this->helper->addDebug(__METHOD__ . '|25|');
137-
$shippingAddress = $quote->getShippingAddress();
138-
if (!$shippingAddress->getShippingMethod()) {
139-
$this->helper->addDebug(__METHOD__ . '|35|');
140-
$shippingAddress->load($shippingAddress->getAddressId());
141-
}
85+
$quote = $this->getActiveQuote();
86+
if ($quote) {
87+
$this->processShippingAddress($quote);
14288
}
14389

144-
145-
if (
146-
(
147-
$this->helper->getRestoreQuoteLastOrder() &&
148-
($lastRealOrder->getData('state') === 'new') &&
149-
($lastRealOrder->getData('status') === 'pending') &&
150-
$payment->getMethodInstance()->usesRedirect
151-
) || $this->canRestoreFailedFromSpam()
152-
) {
90+
if ($this->shouldRestoreQuote($lastRealOrder, $payment)) {
15391
$this->helper->addDebug(__METHOD__ . '|40|');
15492
$this->checkoutSession->restoreQuote();
93+
94+
if ($this->isFastCheckout($payment)) {
95+
$this->clearRestoredQuoteAddresses($this->checkoutSession->getQuote());
96+
}
97+
15598
$this->rollbackPartialPayment($lastRealOrder->getIncrementId());
15699
$this->setOrderToCancel($previousOrderId);
157100
}
@@ -166,10 +109,126 @@ public function execute(\Magento\Framework\Event\Observer $observer)
166109
}
167110

168111
/**
169-
* Check if order has failed from max spam payment attempts
112+
* Get the active quote from the checkout session.
113+
*
114+
* @return Quote|null
115+
*/
116+
private function getActiveQuote()
117+
{
118+
$quote = null;
119+
if ($this->checkoutSession->getQuote() && $this->checkoutSession->getQuote()->getId()) {
120+
try {
121+
$quote = $this->quoteRepository->getActive($this->checkoutSession->getQuote()->getId());
122+
} catch (\Exception $e) {
123+
$this->helper->addError(__METHOD__ . '|Error fetching active quote: ' . $e->getMessage());
124+
}
125+
}
126+
return $quote;
127+
}
128+
129+
/**
130+
* Process the shipping address of the quote.
131+
*
132+
* @param Quote $quote
133+
*/
134+
private function processShippingAddress($quote)
135+
{
136+
$this->helper->addDebug(__METHOD__ . '|25|');
137+
$shippingAddress = $quote->getShippingAddress();
138+
if ($shippingAddress && !$shippingAddress->getShippingMethod()) {
139+
$this->helper->addDebug(__METHOD__ . '|35|');
140+
try {
141+
$shippingAddress->load($shippingAddress->getAddressId());
142+
} catch (\Exception $e) {
143+
$this->helper->addError(__METHOD__ . '|Error loading shipping address: ' . $e->getMessage());
144+
}
145+
}
146+
}
147+
148+
/**
149+
* Check if the quote should be restored.
150+
*
151+
* @param $lastRealOrder
152+
* @param $payment
153+
* @return bool
154+
*/
155+
private function shouldRestoreQuote($lastRealOrder, $payment)
156+
{
157+
return (
158+
($this->helper->getRestoreQuoteLastOrder() &&
159+
($lastRealOrder->getData('state') === 'new') &&
160+
($lastRealOrder->getData('status') === 'pending') &&
161+
$payment->getMethodInstance()->usesRedirect) || $this->canRestoreFailedFromSpam()
162+
);
163+
}
164+
165+
/**
166+
* Clear addresses after quote restoration to ensure they are not unintentionally restored.
167+
*
168+
* @param Quote $quote
169+
*/
170+
private function clearRestoredQuoteAddresses($quote)
171+
{
172+
if ($quote && $quote->getId()) {
173+
$quote->setCustomerEmail(null);
174+
175+
// Remove existing addresses if they exist
176+
$this->clearAddress($quote, $quote->getBillingAddress());
177+
$this->clearAddress($quote, $quote->getShippingAddress());
178+
179+
// Save the modified quote to ensure addresses are cleared
180+
try {
181+
$this->quoteRepository->save($quote);
182+
$this->helper->addDebug(__METHOD__ . '|Addresses cleared after restoreQuote()');
183+
} catch (\Exception $e) {
184+
$this->helper->addDebug(__METHOD__ . '|Error clearing addresses: ' . $e->getMessage());
185+
}
186+
}
187+
}
188+
189+
190+
/**
191+
* Clear address data and remove the address object from the quote.
192+
*
193+
* @param Quote $quote
194+
* @param $address
195+
*/
196+
private function clearAddress($quote, $address)
197+
{
198+
if ($address) {
199+
// Remove the address from the quote
200+
$quote->removeAddress($address->getId());
201+
202+
// Optionally clear address data if needed to reset but keep structure intact
203+
$address->addData([]);
204+
}
205+
}
206+
207+
/**
208+
* Check if the payment method is fastcheckout.
209+
*
210+
* @param $payment
211+
* @return bool
212+
*/
213+
private function isFastCheckout($payment)
214+
{
215+
return $payment->getMethod() === 'buckaroo_magento2_ideal' &&
216+
isset($payment->getAdditionalInformation()['issuer']) &&
217+
$payment->getAdditionalInformation()['issuer'] === 'fastcheckout';
218+
}
219+
220+
/**
221+
* Check if the payment method should be skipped.
170222
*
171-
* @return boolean
223+
* @param $payment
224+
* @return bool
172225
*/
226+
private function isPayconiqPaymentMethod($payment)
227+
{
228+
return strpos($payment->getMethod(), 'buckaroo_magento2') === false ||
229+
in_array($payment->getMethod(), [Payconiq::PAYMENT_METHOD_CODE]);
230+
}
231+
173232
public function canRestoreFailedFromSpam()
174233
{
175234
return $this->helper->getRestoreQuoteLastOrder() &&
@@ -181,18 +240,11 @@ public function shouldSkipFurtherEventHandling()
181240
return false;
182241
}
183242

184-
/**
185-
* Set previous order id on the payment object for the next payment
186-
*
187-
* @param int $previousOrderId
188-
*
189-
* @return void
190-
*/
191243
private function setOrderToCancel($previousOrderId)
192244
{
193245
$this->checkoutSession->getQuote()
194-
->getPayment()
195-
->setAdditionalInformation('buckaroo_cancel_order_id', $previousOrderId);
246+
->getPayment()
247+
->setAdditionalInformation('buckaroo_cancel_order_id', $previousOrderId);
196248
$this->quoteRepository->save($this->checkoutSession->getQuote());
197249
}
198250

@@ -206,6 +258,5 @@ public function rollbackPartialPayment($incrementId)
206258
} catch (\Throwable $th) {
207259
$this->helper->addDebug(__METHOD__ . (string)$th);
208260
}
209-
210261
}
211262
}

Service/Sales/Quote/Recreate.php

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,45 @@ public function __construct(
4040
}
4141

4242
/**
43-
* @param Order $order
44-
*
45-
* @throws \Magento\Framework\Exception\NoSuchEntityException
43+
* @param $quote
44+
* @param array $response
45+
* @return false|mixed
4646
*/
47-
public function recreate($quote)
47+
public function recreate($quote, $response = [])
4848
{
4949
// @codingStandardsIgnoreStart
5050
try {
5151
$quote->setIsActive(true);
52-
$quote->setTriggerRecollect('1');
52+
// $quote->setTriggerRecollect('1');
5353
$quote->setReservedOrderId(null);
5454
$quote->setBuckarooFee(null);
5555
$quote->setBaseBuckarooFee(null);
5656
$quote->setBuckarooFeeTaxAmount(null);
5757
$quote->setBuckarooFeeBaseTaxAmount(null);
5858
$quote->setBuckarooFeeInclTax(null);
5959
$quote->setBaseBuckarooFeeInclTax(null);
60+
61+
if (isset($response['add_service_action_from_magento']) && $response['add_service_action_from_magento'] === 'payfastcheckout') {
62+
$this->logger->addDebug(__METHOD__ . '|Handling payfastcheckout specific logic.');
63+
64+
$quote->setCustomerEmail(null);
65+
66+
// Remove existing addresses if they exist
67+
if ($billingAddress = $quote->getBillingAddress()) {
68+
$quote->removeAddress($billingAddress->getId());
69+
$billingAddress->addData([]); // Optionally clear address data
70+
}
71+
72+
if ($shippingAddress = $quote->getShippingAddress()) {
73+
$quote->removeAddress($shippingAddress->getId());
74+
$shippingAddress->addData([]); // Optionally clear address data
75+
}
76+
}
77+
6078
$quote->save();
6179
$this->cart->setQuote($quote);
6280
$this->cart->save();
81+
6382
return $quote;
6483
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
6584
//No such entity

0 commit comments

Comments
 (0)