Skip to content

Commit 35ca8ee

Browse files
Merge pull request #1340 from buckaroo-it/BP-4513-Failed-cancelled-Riverty-transaction-increases-the-stock
BP-4513-Failed-cancelled-Riverty-transaction-increases-the-stock
2 parents f2d67ba + 14ef2ab commit 35ca8ee

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

Plugin/OrderManagement.php

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
<?php
2+
/**
3+
* NOTICE OF LICENSE
4+
*
5+
* This source file is subject to the MIT License
6+
* It is available through the world-wide-web at this URL:
7+
* https://tldrlegal.com/license/mit-license
8+
* If you are unable to obtain it through the world-wide-web, please send an email
9+
* to support@buckaroo.nl so we can send you a copy immediately.
10+
*
11+
* DISCLAIMER
12+
*
13+
* Do not edit or add to this file if you wish to upgrade this module to newer
14+
* versions in the future. If you wish to customize this module for your
15+
* needs please contact support@buckaroo.nl for more information.
16+
*
17+
* @copyright Copyright (c) Buckaroo B.V.
18+
* @license https://tldrlegal.com/license/mit-license
19+
*/
20+
21+
namespace Buckaroo\Magento2\Plugin;
22+
23+
use Magento\Framework\App\ResourceConnection;
24+
use Magento\Sales\Api\OrderManagementInterface;
25+
use Magento\Sales\Model\Order;
26+
use Buckaroo\Magento2\Logging\Log;
27+
28+
/**
29+
* Plugin to prevent stock release when canceling orders that never reserved stock
30+
*/
31+
class OrderManagement
32+
{
33+
/**
34+
* @var ResourceConnection
35+
*/
36+
private $resourceConnection;
37+
38+
/**
39+
* @var Log
40+
*/
41+
private $logger;
42+
43+
/**
44+
* @param ResourceConnection $resourceConnection
45+
* @param Log $logger
46+
*/
47+
public function __construct(
48+
ResourceConnection $resourceConnection,
49+
Log $logger
50+
) {
51+
$this->resourceConnection = $resourceConnection;
52+
$this->logger = $logger;
53+
}
54+
55+
/**
56+
*
57+
* @param OrderManagementInterface $subject
58+
* @param int $orderId
59+
* @return array
60+
*/
61+
public function beforeCancel(OrderManagementInterface $subject, $orderId)
62+
{
63+
try {
64+
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
65+
$orderRepository = $objectManager->get(\Magento\Sales\Api\OrderRepositoryInterface::class);
66+
$order = $orderRepository->get($orderId);
67+
68+
$this->logger->addDebug(sprintf(
69+
'[ORDER_CANCEL_PLUGIN] Checking order %s (State: %s, Status: %s, Payment: %s)',
70+
$order->getIncrementId(),
71+
$order->getState(),
72+
$order->getStatus(),
73+
$order->getPayment() ? $order->getPayment()->getMethod() : 'No payment'
74+
));
75+
76+
if ($this->isBuckarooPendingOrder($order)) {
77+
$this->logger->addDebug(sprintf(
78+
'[ORDER_CANCEL_PLUGIN] Intercepting cancellation for Buckaroo pending order %s',
79+
$order->getIncrementId()
80+
));
81+
82+
$stockReserved = $this->wasStockReservedForOrder($order);
83+
$this->logger->addDebug(sprintf(
84+
'[ORDER_CANCEL_PLUGIN] Order %s stock reserved: %s',
85+
$order->getIncrementId(),
86+
$stockReserved ? 'YES' : 'NO'
87+
));
88+
89+
if (!$stockReserved) {
90+
$this->logger->addDebug(sprintf(
91+
'[ORDER_CANCEL_PLUGIN] Order %s never reserved stock, preventing standard cancellation',
92+
$order->getIncrementId()
93+
));
94+
95+
$this->cancelOrderWithoutStockRelease($order);
96+
97+
throw new \Exception('Order canceled without stock release');
98+
}
99+
} else {
100+
$this->logger->addDebug(sprintf(
101+
'[ORDER_CANCEL_PLUGIN] Order %s is not a Buckaroo pending order, allowing standard cancellation',
102+
$order->getIncrementId()
103+
));
104+
}
105+
} catch (\Throwable $e) {
106+
$this->logger->addDebug('[ORDER_CANCEL_PLUGIN] Error in beforeCancel: ' . $e->getMessage());
107+
}
108+
109+
return [$orderId];
110+
}
111+
112+
/**
113+
* Check if this is a Buckaroo order in pending state
114+
*
115+
* @param Order $order
116+
* @return bool
117+
*/
118+
private function isBuckarooPendingOrder(Order $order): bool
119+
{
120+
$payment = $order->getPayment();
121+
if (!$payment) {
122+
return false;
123+
}
124+
125+
$method = $payment->getMethod();
126+
$isBuckaroo = strpos($method, 'buckaroo_magento2_') === 0;
127+
$isPending = $order->getState() === Order::STATE_NEW && $order->getStatus() === 'pending';
128+
129+
return $isBuckaroo && $isPending;
130+
}
131+
132+
/**
133+
* Check if stock was actually reserved for this order
134+
*
135+
* @param Order $order
136+
* @return bool
137+
*/
138+
private function wasStockReservedForOrder(Order $order): bool
139+
{
140+
try {
141+
$connection = $this->resourceConnection->getConnection();
142+
$table = $this->resourceConnection->getTableName('inventory_reservation');
143+
144+
$select = $connection->select()
145+
->from($table, ['cnt' => new \Zend_Db_Expr('COUNT(*)')])
146+
->where('metadata LIKE ?', '%"object_id":"' . $order->getIncrementId() . '"%')
147+
->limit(1);
148+
149+
$count = (int)$connection->fetchOne($select);
150+
151+
$this->logger->addDebug(sprintf(
152+
'[STOCK_CHECK] Order %s has %d inventory reservations',
153+
$order->getIncrementId(),
154+
$count
155+
));
156+
157+
return $count > 0;
158+
} catch (\Throwable $e) {
159+
$this->logger->addDebug('[STOCK_CHECK] Error checking stock reservations: ' . $e->getMessage());
160+
return true;
161+
}
162+
}
163+
164+
/**
165+
* Cancel the order without releasing stock
166+
*
167+
* @param Order $order
168+
* @return void
169+
*/
170+
private function cancelOrderWithoutStockRelease(Order $order): void
171+
{
172+
try {
173+
$order->setState(Order::STATE_CANCELED);
174+
$order->setStatus(Order::STATE_CANCELED);
175+
176+
$order->addCommentToStatusHistory(
177+
__('Order canceled manually. No stock was released as this order never reserved inventory.'),
178+
false,
179+
false
180+
);
181+
182+
$order->save();
183+
184+
$this->logger->addDebug(sprintf(
185+
'[ORDER_CANCEL_PLUGIN] Order %s canceled without stock release',
186+
$order->getIncrementId()
187+
));
188+
} catch (\Throwable $e) {
189+
$this->logger->addDebug('[ORDER_CANCEL_PLUGIN] Error canceling order without stock release: ' . $e->getMessage());
190+
}
191+
}
192+
}

etc/di.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@
4040
sortOrder="1"/>
4141
</type>
4242

43+
<type name="Magento\Sales\Api\OrderManagementInterface">
44+
<plugin name="buckaroo_order_management_stock_fix"
45+
type="Buckaroo\Magento2\Plugin\OrderManagement"
46+
sortOrder="10"/>
47+
</type>
48+
4349
// TODO: check those two plugins if they are working after this change
4450
<type name="Onestepcheckout\Iosc\Plugin\GuestSaveManager">
4551
<plugin name="buckaroo_guest_save_manager" type="Buckaroo\Magento2\Plugin\GuestSaveManager" sortOrder="10" />

0 commit comments

Comments
 (0)