Skip to content

Commit 2a722c7

Browse files
committed
MAGETWO-53060: Cannot refund order partially
1 parent 692b5e1 commit 2a722c7

File tree

2 files changed

+94
-79
lines changed

2 files changed

+94
-79
lines changed

app/code/Magento/Sales/Model/Order/Creditmemo/Item.php

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class Item extends AbstractModel implements CreditmemoItemInterface
4242
*/
4343
protected $_orderItemFactory;
4444

45+
/**
46+
* @var bool
47+
*/
48+
private $qtyProcessed = false;
49+
4550
/**
4651
* @param \Magento\Framework\Model\Context $context
4752
* @param \Magento\Framework\Registry $registry
@@ -127,28 +132,16 @@ public function setOrderItem(\Magento\Sales\Model\Order\Item $item)
127132
public function getOrderItem()
128133
{
129134
if ($this->_orderItem === null) {
130-
$this->_orderItem = $this->getOrderItemWithoutCaching();
135+
if ($this->getCreditmemo()) {
136+
$orderItem = $this->getCreditmemo()->getOrder()->getItemById($this->getOrderItemId());
137+
} else {
138+
$orderItem = $this->_orderItemFactory->create()->load($this->getOrderItemId());
139+
}
140+
$this->_orderItem = $orderItem;
131141
}
132142
return $this->_orderItem;
133143
}
134144

135-
/**
136-
* Retrieve order item instance without set it to property.
137-
* It is need for ability to process setQty on api when credit memo and order has not built yet.
138-
*
139-
* @return \Magento\Sales\Model\Order\Item
140-
*/
141-
private function getOrderItemWithoutCaching()
142-
{
143-
if ($this->getCreditmemo()) {
144-
$orderItem = $this->getCreditmemo()->getOrder()->getItemById($this->getOrderItemId());
145-
} else {
146-
$orderItem = $this->_orderItemFactory->create()->load($this->getOrderItemId());
147-
}
148-
149-
return $orderItem;
150-
}
151-
152145
/**
153146
* Checks if quantity available for refund
154147
*
@@ -164,26 +157,13 @@ private function isQtyAvailable($qty, \Magento\Sales\Model\Order\Item $orderItem
164157
/**
165158
* Declare qty
166159
*
167-
* @param float $qty
160+
* @param float $qty
168161
* @return $this
169-
* @throws \Magento\Framework\Exception\LocalizedException
170162
*/
171163
public function setQty($qty)
172164
{
173-
$orderItem = $this->getOrderItem();
174-
if ($orderItem->getIsQtyDecimal()) {
175-
$qty = (double)$qty;
176-
} else {
177-
$qty = (int)$qty;
178-
}
179-
$qty = $qty > 0 ? $qty : 0;
180-
if ($this->isQtyAvailable($qty, $orderItem)) {
181-
$this->setData('qty', $qty);
182-
} else {
183-
throw new \Magento\Framework\Exception\LocalizedException(
184-
__('We found an invalid quantity to refund item "%1".', $this->getName())
185-
);
186-
}
165+
$this->setData('qty', $qty);
166+
$this->qtyProcessed = false;
187167
return $this;
188168
}
189169

@@ -213,6 +193,29 @@ public function register()
213193
return $this;
214194
}
215195

196+
/**
197+
* @return void
198+
* @throws \Magento\Framework\Exception\LocalizedException
199+
*/
200+
private function processQty()
201+
{
202+
$orderItem = $this->getOrderItem();
203+
$qty = $this->getData(CreditmemoItemInterface::QTY);
204+
if ($orderItem->getIsQtyDecimal()) {
205+
$qty = (double)$qty;
206+
} else {
207+
$qty = (int)$qty;
208+
}
209+
$qty = $qty > 0 ? $qty : 0;
210+
if ($this->isQtyAvailable($qty, $orderItem)) {
211+
$this->setData('qty', $qty);
212+
} else {
213+
throw new \Magento\Framework\Exception\LocalizedException(
214+
__('We found an invalid quantity to refund item "%1".', $this->getName())
215+
);
216+
}
217+
}
218+
216219
/**
217220
* @return $this
218221
*/
@@ -511,6 +514,10 @@ public function getProductId()
511514
*/
512515
public function getQty()
513516
{
517+
if (!$this->qtyProcessed) {
518+
$this->processQty();
519+
$this->qtyProcessed = true;
520+
}
514521
return $this->getData(CreditmemoItemInterface::QTY);
515522
}
516523

app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/ItemTest.php

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,10 @@ public function testSetQtyDecimalException()
111111
$orderItemMock->expects($this->once())
112112
->method('getQtyToRefund')
113113
->willReturn($orderItemQty);
114-
$orderItemMock->expects($this->atLeastOnce())
115-
->method('load')
116-
->willReturnSelf();
117-
$this->orderItemFactoryMock->expects($this->atLeastOnce())
118-
->method('create')
119-
->willReturn($orderItemMock);
120114
$this->item->setData(CreditmemoItemInterface::NAME, $name);
121115
$this->item->setOrderItem($orderItemMock);
122116
$this->item->setQty($qty);
117+
$this->item->getQty();
123118
}
124119

125120
/**
@@ -141,15 +136,10 @@ public function testSetQtyNumericException()
141136
$orderItemMock->expects($this->once())
142137
->method('getQtyToRefund')
143138
->willReturn($orderItemQty);
144-
$orderItemMock->expects($this->atLeastOnce())
145-
->method('load')
146-
->willReturnSelf();
147-
$this->orderItemFactoryMock->expects($this->atLeastOnce())
148-
->method('create')
149-
->willReturn($orderItemMock);
150139
$this->item->setData(CreditmemoItemInterface::NAME, $name);
151140
$this->item->setOrderItem($orderItemMock);
152141
$this->item->setQty($qty);
142+
$this->item->getQty();
153143
}
154144

155145
public function testSetQty()
@@ -166,12 +156,6 @@ public function testSetQty()
166156
$orderItemMock->expects($this->once())
167157
->method('getQtyToRefund')
168158
->willReturn($orderItemQty);
169-
$orderItemMock->expects($this->atLeastOnce())
170-
->method('load')
171-
->willReturnSelf();
172-
$this->orderItemFactoryMock->expects($this->atLeastOnce())
173-
->method('create')
174-
->willReturn($orderItemMock);
175159
$this->item->setOrderItem($orderItemMock);
176160
$this->item->setQty($qty);
177161
$this->assertEquals($qty, $this->item->getQty());
@@ -209,19 +193,19 @@ public function testRegister()
209193
$orderItemMock->expects($this->once())
210194
->method('getBaseDiscountRefunded')
211195
->willReturn(1);
212-
$data = [
213-
'qty' => 1,
214-
'tax_amount' => 1,
215-
'base_tax_amount' => 1,
216-
'discount_tax_compensation_amount' => 1,
217-
'base_discount_tax_compensation_amount' => 1,
218-
'row_total' => 1,
219-
'base_row_total' => 1,
220-
'discount_amount' => 1,
221-
'base_discount_amount' => 1
222-
];
196+
$orderItemMock->expects($this->once())
197+
->method('getQtyToRefund')
198+
->willReturn(1);
199+
$this->item->setQty(1);
200+
$this->item->setTaxAmount(1);
201+
$this->item->setBaseTaxAmount(1);
202+
$this->item->setDiscountTaxCompensationAmount(1);
203+
$this->item->setBaseDiscountTaxCompensationAmount(1);
204+
$this->item->setRowTotal(1);
205+
$this->item->setBaseRowTotal(1);
206+
$this->item->setDiscountAmount(1);
207+
$this->item->setBaseDiscountAmount(1);
223208
$this->item->setOrderItem($orderItemMock);
224-
$this->item->setData($data);
225209
$result = $this->item->register();
226210
$this->assertInstanceOf('Magento\Sales\Model\Order\Creditmemo\Item', $result);
227211
}
@@ -230,19 +214,6 @@ public function testCancel()
230214
{
231215
$orderItemMock = $this->getMockBuilder('Magento\Sales\Model\Order\Item')
232216
->disableOriginalConstructor()
233-
->setMethods(
234-
[
235-
'setQtyRefunded',
236-
'getQtyRefunded',
237-
'getTaxRefunded',
238-
'getBaseTaxAmount',
239-
'getQtyOrdered',
240-
'setTaxRefunded',
241-
'setDiscountTaxCompensationRefunded',
242-
'getDiscountTaxCompensationRefunded',
243-
'getDiscountTaxCompensationAmount'
244-
]
245-
)
246217
->getMock();
247218
$orderItemMock->expects($this->once())
248219
->method('getQtyRefunded')
@@ -272,8 +243,11 @@ public function testCancel()
272243
$orderItemMock->expects($this->once())
273244
->method('getDiscountTaxCompensationAmount')
274245
->willReturn(10);
246+
$orderItemMock->expects($this->once())
247+
->method('getQtyToRefund')
248+
->willReturn(1);
275249

276-
$this->item->setData('qty', 1);
250+
$this->item->setQty(1);
277251
$this->item->setOrderItem($orderItemMock);
278252
$result = $this->item->cancel();
279253
$this->assertInstanceOf('Magento\Sales\Model\Order\Creditmemo\Item', $result);
@@ -342,7 +316,7 @@ function ($arg) {
342316
->method('getQtyToRefund')
343317
->willReturn($qtyAvailable);
344318

345-
$this->item->setData('qty', $qty);
319+
$this->item->setQty($qty);
346320
$this->item->setCreditmemo($creditmemoMock);
347321
$this->item->setOrderItem($orderItemMock);
348322
$result = $this->item->calcRowTotal();
@@ -362,4 +336,38 @@ public function calcRowTotalDataProvider()
362336
'qty 0' => [0],
363337
];
364338
}
339+
340+
public function testSetQtyWithProcess()
341+
{
342+
$orderItemMock = $this->getMockBuilder('Magento\Sales\Model\Order\Item')
343+
->disableOriginalConstructor()
344+
->setMethods(['getQtyToRefund'])
345+
->getMock();
346+
$orderItemMock->expects($this->once())
347+
->method('getQtyToRefund')
348+
->willReturn(2);
349+
350+
$this->item->setOrderItem($orderItemMock);
351+
352+
$this->item->setQty(2);
353+
$this->assertEquals(2, $this->item->getQty());
354+
}
355+
356+
public function testSetQtyWithProcessDecimal()
357+
{
358+
$orderItemMock = $this->getMockBuilder('Magento\Sales\Model\Order\Item')
359+
->disableOriginalConstructor()
360+
->setMethods(['getQtyToRefund', 'getIsQtyDecimal'])
361+
->getMock();
362+
$orderItemMock->expects($this->once())
363+
->method('getQtyToRefund')
364+
->willReturn(3.3);
365+
$orderItemMock->expects($this->once())
366+
->method('getIsQtyDecimal')
367+
->willReturn(true);
368+
$this->item->setOrderItem($orderItemMock);
369+
370+
$this->item->setQty(3.3);
371+
$this->assertEquals(3.3, $this->item->getQty());
372+
}
365373
}

0 commit comments

Comments
 (0)