Skip to content

Commit a56d1d8

Browse files
committed
MAGETWO-61268: [Backport] - Creditmemo return to stock only one unit of configurable product - for 2.0.11
2 parents 9b7fcb0 + 2b9f22d commit a56d1d8

File tree

14 files changed

+477
-172
lines changed

14 files changed

+477
-172
lines changed

app/code/Magento/CatalogInventory/etc/events.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@
3333
<event name="sales_order_item_cancel">
3434
<observer name="inventory" instance="Magento\CatalogInventory\Observer\CancelOrderItemObserver"/>
3535
</event>
36-
<event name="sales_order_creditmemo_save_after">
37-
<observer name="inventory" instance="Magento\CatalogInventory\Observer\RefundOrderInventoryObserver"/>
38-
</event>
3936
<event name="catalog_product_save_after">
4037
<observer name="inventory" instance="Magento\CatalogInventory\Observer\SaveInventoryDataObserver"/>
4138
</event>

app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,9 @@ public function load()
217217
foreach ($creditmemo->getAllItems() as $creditmemoItem) {
218218
$orderItem = $creditmemoItem->getOrderItem();
219219
$parentId = $orderItem->getParentItemId();
220-
if (isset($backToStock[$orderItem->getId()])) {
220+
if ($parentId && isset($backToStock[$parentId]) && $backToStock[$parentId]) {
221221
$creditmemoItem->setBackToStock(true);
222-
} elseif ($orderItem->getParentItem() && isset($backToStock[$parentId]) && $backToStock[$parentId]) {
222+
} elseif (isset($backToStock[$orderItem->getId()])) {
223223
$creditmemoItem->setBackToStock(true);
224224
} elseif (empty($savedData)) {
225225
$creditmemoItem->setBackToStock(

app/code/Magento/Sales/Model/Order/CreditmemoFactory.php

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Copyright © 2016 Magento. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6-
76
namespace Magento\Sales\Model\Order;
87

98
/**
@@ -23,6 +22,11 @@ class CreditmemoFactory
2322
*/
2423
protected $taxConfig;
2524

25+
/**
26+
* @var \Magento\Framework\Unserialize\Unserialize
27+
*/
28+
protected $unserialize;
29+
2630
/**
2731
* Factory constructor
2832
*
@@ -57,7 +61,12 @@ public function createByOrder(\Magento\Sales\Model\Order $order, array $data = [
5761

5862
$item = $this->convertor->itemToCreditmemoItem($orderItem);
5963
if ($orderItem->isDummy()) {
60-
$qty = 1;
64+
if (isset($data['qtys'][$orderItem->getParentItemId()])) {
65+
$parentQty = $data['qtys'][$orderItem->getParentItemId()];
66+
} else {
67+
$parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1;
68+
}
69+
$qty = $this->calculateProductOptions($orderItem, $parentQty);
6170
$orderItem->setLockedDoShip(true);
6271
} else {
6372
if (isset($qtys[$orderItem->getId()])) {
@@ -132,7 +141,12 @@ public function createByInvoice(\Magento\Sales\Model\Order\Invoice $invoice, arr
132141

133142
$item = $this->convertor->itemToCreditmemoItem($orderItem);
134143
if ($orderItem->isDummy()) {
135-
$qty = 1;
144+
if (isset($data['qtys'][$orderItem->getParentItemId()])) {
145+
$parentQty = $data['qtys'][$orderItem->getParentItemId()];
146+
} else {
147+
$parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1;
148+
}
149+
$qty = $this->calculateProductOptions($orderItem, $parentQty);
136150
} else {
137151
if (isset($qtys[$orderItem->getId()])) {
138152
$qty = (double)$qtys[$orderItem->getId()];
@@ -245,4 +259,38 @@ protected function initData($creditmemo, $data)
245259
$creditmemo->setAdjustmentNegative($data['adjustment_negative']);
246260
}
247261
}
262+
263+
/**
264+
* @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem
265+
* @param array $qtys
266+
* @return int
267+
*/
268+
private function calculateProductOptions(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, $parentQty)
269+
{
270+
$qty = $parentQty;
271+
$productOptions = $orderItem->getProductOptions();
272+
if (isset($productOptions['bundle_selection_attributes'])) {
273+
$bundleSelectionAttributes = $this->getUnserialize()
274+
->unserialize($productOptions['bundle_selection_attributes']);
275+
if ($bundleSelectionAttributes) {
276+
$qty = $bundleSelectionAttributes['qty'] * $parentQty;
277+
}
278+
}
279+
return $qty;
280+
}
281+
282+
/**
283+
* Get Unserialize
284+
*
285+
* @return \Magento\Framework\Unserialize\Unserialize
286+
* @deprecated
287+
*/
288+
private function getUnserialize()
289+
{
290+
if (!$this->unserialize) {
291+
$this->unserialize = \Magento\Framework\App\ObjectManager::getInstance()
292+
->get(\Magento\Framework\Unserialize\Unserialize::class);
293+
}
294+
return $this->unserialize;
295+
}
248296
}

app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
namespace Magento\SalesInventory\Model\Order;
77

88
use Magento\Sales\Api\Data\CreditmemoInterface;
9-
use Magento\Sales\Api\Data\CreditmemoItemInterface;
109
use Magento\Sales\Api\Data\OrderInterface;
1110

1211
/**
@@ -29,75 +28,58 @@ class ReturnProcessor
2928
*/
3029
private $priceIndexer;
3130

32-
/**
33-
* @var \Magento\Sales\Api\CreditmemoRepositoryInterface
34-
*/
35-
private $creditmemoRepository;
36-
3731
/**
3832
* @var \Magento\Store\Model\StoreManagerInterface
3933
*/
4034
private $storeManager;
4135

42-
/**
43-
* @var \Magento\Sales\Api\OrderRepositoryInterface
44-
*/
45-
private $orderRepository;
46-
4736
/**
4837
* @var \Magento\Sales\Api\OrderItemRepositoryInterface
4938
*/
5039
private $orderItemRepository;
5140

5241
/**
53-
* ReturnToStockPlugin constructor.
54-
* @param \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration
42+
* ReturnProcessor constructor.
5543
* @param \Magento\CatalogInventory\Api\StockManagementInterface $stockManagement
5644
* @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexer
5745
* @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
58-
* @param \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository
5946
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
60-
* @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
6147
* @param \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository
6248
*/
6349
public function __construct(
6450
\Magento\CatalogInventory\Api\StockManagementInterface $stockManagement,
6551
\Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexer,
6652
\Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer,
67-
\Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository,
6853
\Magento\Store\Model\StoreManagerInterface $storeManager,
69-
\Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
7054
\Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository
7155
) {
7256
$this->stockManagement = $stockManagement;
7357
$this->stockIndexerProcessor = $stockIndexer;
7458
$this->priceIndexer = $priceIndexer;
75-
$this->creditmemoRepository = $creditmemoRepository;
7659
$this->storeManager = $storeManager;
77-
$this->orderRepository = $orderRepository;
7860
$this->orderItemRepository = $orderItemRepository;
7961
}
8062

8163
/**
8264
* @param CreditmemoInterface $creditmemo
8365
* @param OrderInterface $order
8466
* @param array $returnToStockItems
67+
* @param bool $isAutoReturn
8568
* @return void
8669
*/
8770
public function execute(
8871
CreditmemoInterface $creditmemo,
8972
OrderInterface $order,
90-
array $returnToStockItems = []
73+
array $returnToStockItems = [],
74+
$isAutoReturn = false
9175
) {
9276
$itemsToUpdate = [];
9377
foreach ($creditmemo->getItems() as $item) {
94-
$qty = $item->getQty();
9578
$productId = $item->getProductId();
9679
$orderItem = $this->orderItemRepository->get($item->getOrderItemId());
9780
$parentItemId = $orderItem->getParentItemId();
98-
if ($this->canReturnItem($item, $qty, $parentItemId, $returnToStockItems)) {
99-
$parentItem = $parentItemId ? $this->getItemByOrderId($creditmemo, $parentItemId) : false;
100-
$qty = $parentItem ? $parentItem->getQty() * $qty : $qty;
81+
$qty = $item->getQty();
82+
if ($isAutoReturn || $this->canReturnItem($item, $qty, $parentItemId, $returnToStockItems)) {
10183
if (isset($itemsToUpdate[$productId])) {
10284
$itemsToUpdate[$productId] += $qty;
10385
} else {
@@ -122,21 +104,6 @@ public function execute(
122104
}
123105
}
124106

125-
/**
126-
* @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
127-
* @param int $parentItemId
128-
* @return bool|CreditmemoItemInterface
129-
*/
130-
private function getItemByOrderId(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo, $parentItemId)
131-
{
132-
foreach ($creditmemo->getItems() as $item) {
133-
if ($item->getOrderItemId() == $parentItemId) {
134-
return $item;
135-
}
136-
}
137-
return false;
138-
}
139-
140107
/**
141108
* @param \Magento\Sales\Api\Data\CreditmemoItemInterface $item
142109
* @param int $qty

app/code/Magento/CatalogInventory/Observer/RefundOrderInventoryObserver.php renamed to app/code/Magento/SalesInventory/Observer/RefundOrderInventoryObserver.php

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,74 @@
44
* See COPYING.txt for license details.
55
*/
66

7-
namespace Magento\CatalogInventory\Observer;
7+
namespace Magento\SalesInventory\Observer;
88

99
use Magento\CatalogInventory\Api\StockConfigurationInterface;
1010
use Magento\CatalogInventory\Api\StockManagementInterface;
1111
use Magento\Framework\Event\Observer as EventObserver;
1212
use Magento\Framework\Event\ObserverInterface;
13+
use Magento\Sales\Model\OrderRepository;
14+
use Magento\SalesInventory\Model\Order\ReturnProcessor;
1315

1416
/**
1517
* Catalog inventory module observer
18+
* @deprecated
1619
*/
1720
class RefundOrderInventoryObserver implements ObserverInterface
1821
{
1922
/**
2023
* @var StockConfigurationInterface
2124
*/
22-
protected $stockConfiguration;
25+
private $stockConfiguration;
2326

2427
/**
2528
* @var StockManagementInterface
2629
*/
27-
protected $stockManagement;
30+
private $stockManagement;
2831

2932
/**
3033
* @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor
3134
*/
32-
protected $stockIndexerProcessor;
35+
private $stockIndexerProcessor;
3336

3437
/**
3538
* @var \Magento\Catalog\Model\Indexer\Product\Price\Processor
3639
*/
37-
protected $priceIndexer;
40+
private $priceIndexer;
3841

3942
/**
43+
* @var \Magento\SalesInventory\Model\Order\ReturnProcessor
44+
*/
45+
private $returnProcessor;
46+
47+
/**
48+
* @var \Magento\Sales\Api\OrderRepositoryInterface
49+
*/
50+
private $orderRepository;
51+
52+
/**
53+
* RefundOrderInventoryObserver constructor.
4054
* @param StockConfigurationInterface $stockConfiguration
4155
* @param StockManagementInterface $stockManagement
4256
* @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor
4357
* @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
58+
* @param ReturnProcessor $returnProcessor
59+
* @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
4460
*/
4561
public function __construct(
4662
StockConfigurationInterface $stockConfiguration,
4763
StockManagementInterface $stockManagement,
4864
\Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor,
49-
\Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
65+
\Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer,
66+
\Magento\SalesInventory\Model\Order\ReturnProcessor $returnProcessor,
67+
\Magento\Sales\Api\OrderRepositoryInterface $orderRepository
5068
) {
5169
$this->stockConfiguration = $stockConfiguration;
5270
$this->stockManagement = $stockManagement;
5371
$this->stockIndexerProcessor = $stockIndexerProcessor;
5472
$this->priceIndexer = $priceIndexer;
73+
$this->returnProcessor = $returnProcessor;
74+
$this->orderRepository = $orderRepository;
5575
}
5676

5777
/**
@@ -64,31 +84,18 @@ public function execute(EventObserver $observer)
6484
{
6585
/* @var $creditmemo \Magento\Sales\Model\Order\Creditmemo */
6686
$creditmemo = $observer->getEvent()->getCreditmemo();
67-
$itemsToUpdate = [];
68-
foreach ($creditmemo->getAllItems() as $item) {
69-
$qty = $item->getQty();
70-
if (($item->getBackToStock() && $qty) || $this->stockConfiguration->isAutoReturnEnabled()) {
71-
$productId = $item->getProductId();
72-
$parentItemId = $item->getOrderItem()->getParentItemId();
73-
/* @var $parentItem \Magento\Sales\Model\Order\Creditmemo\Item */
74-
$parentItem = $parentItemId ? $creditmemo->getItemByOrderId($parentItemId) : false;
75-
$qty = $parentItem ? $parentItem->getQty() * $qty : $qty;
76-
if (isset($itemsToUpdate[$productId])) {
77-
$itemsToUpdate[$productId] += $qty;
78-
} else {
79-
$itemsToUpdate[$productId] = $qty;
80-
}
87+
$order = $this->orderRepository->get($creditmemo->getOrderId());
88+
$returnToStockItems = [];
89+
foreach ($creditmemo->getItems() as $item) {
90+
if ($item->getBackToStock()) {
91+
$returnToStockItems[] = $item->getOrderItemId();
8192
}
8293
}
83-
if (!empty($itemsToUpdate)) {
84-
$this->stockManagement->revertProductsSale(
85-
$itemsToUpdate,
86-
$creditmemo->getStore()->getWebsiteId()
87-
);
88-
89-
$updatedItemIds = array_keys($itemsToUpdate);
90-
$this->stockIndexerProcessor->reindexList($updatedItemIds);
91-
$this->priceIndexer->reindexList($updatedItemIds);
92-
}
94+
$this->returnProcessor->execute(
95+
$creditmemo,
96+
$order,
97+
$returnToStockItems,
98+
$this->stockConfiguration->isAutoReturnEnabled()
99+
);
93100
}
94101
}

0 commit comments

Comments
 (0)