Skip to content

Commit 15375b2

Browse files
MC-34261: [MAGENTO CLOUD] Incorrect refund amount refunded to customer
1 parent f8b9214 commit 15375b2

File tree

7 files changed

+252
-21
lines changed

7 files changed

+252
-21
lines changed

app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function __construct(
5151
* @param string $value
5252
* @param int $length
5353
* @param string $etc
54-
* @param string &$remainder
54+
* @param string $remainder
5555
* @param bool $breakWords
5656
* @return string
5757
*/
@@ -83,6 +83,7 @@ public function getChildren($item)
8383
}
8484

8585
if ($items) {
86+
$itemsArray[$item->getOrderItem()->getId()][$item->getOrderItemId()] = $item;
8687
foreach ($items as $value) {
8788
$parentItem = $value->getOrderItem()->getParentItem();
8889
if ($parentItem) {

app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/Items/RendererTest.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
use PHPUnit\Framework\MockObject\MockObject;
1818
use PHPUnit\Framework\TestCase;
1919

20+
/**
21+
* Test Renderer order item
22+
*/
2023
class RendererTest extends TestCase
2124
{
2225
/** @var Item|MockObject */
@@ -98,25 +101,27 @@ public function testGetChildren($parentItem)
98101
$parentItem = $this->createPartialMock(Item::class, ['getId', '__wakeup']);
99102
$parentItem->expects($this->any())->method('getId')->willReturn(1);
100103
}
101-
$this->orderItem->expects($this->any())->method('getOrderItem')->willReturnSelf();
102-
$this->orderItem->expects($this->any())->method('getParentItem')->willReturn($parentItem);
103-
$this->orderItem->expects($this->any())->method('getOrderItemId')->willReturn(2);
104-
$this->orderItem->expects($this->any())->method('getId')->willReturn(1);
104+
$this->orderItem->method('getOrderItem')->willReturnSelf();
105+
$this->orderItem->method('getParentItem')->willReturn($parentItem);
106+
$this->orderItem->method('getOrderItemId')->willReturn(2);
107+
$this->orderItem->method('getId')->willReturn(1);
105108

106109
$salesModel = $this->createPartialMock(
107110
Invoice::class,
108111
['getAllItems', '__wakeup']
109112
);
110-
$salesModel->expects($this->once())->method('getAllItems')->willReturn([$this->orderItem]);
113+
$salesModel->method('getAllItems')->willReturn([$this->orderItem]);
111114

112115
$item = $this->createPartialMock(
113116
\Magento\Sales\Model\Order\Invoice\Item::class,
114-
['getInvoice', 'getOrderItem', '__wakeup']
117+
['getInvoice', 'getOrderItem', 'getOrderItemId', '__wakeup']
115118
);
116-
$item->expects($this->once())->method('getInvoice')->willReturn($salesModel);
117-
$item->expects($this->any())->method('getOrderItem')->willReturn($this->orderItem);
119+
$item->method('getInvoice')->willReturn($salesModel);
120+
$item->method('getOrderItem')->willReturn($this->orderItem);
121+
$item->method('getOrderItemId')->willReturn($this->orderItem->getOrderItemId());
118122

119-
$this->assertSame([2 => $this->orderItem], $this->model->getChildren($item));
123+
$orderItem = $this->model->getChildren($item);
124+
$this->assertSame([2 => $this->orderItem], $orderItem);
120125
}
121126

122127
/**
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?php
2+
/**
3+
*
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Magento\Sales\Test\Unit\ViewModel\CreditMemo\Create;
10+
11+
use Magento\Sales\Model\Convert\Order as ConvertOrder;
12+
use Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Items as BlockItems;
13+
use Magento\Sales\Model\Order\Creditmemo\Item as CreditmemoItem;
14+
use Magento\Sales\Model\Order\Creditmemo;
15+
use Magento\Sales\Model\Order\Item as OrderItem;
16+
use Magento\Sales\ViewModel\CreditMemo\Create\ItemsToRender;
17+
use PHPUnit\Framework\MockObject\MockObject;
18+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
19+
use PHPUnit\Framework\TestCase;
20+
21+
/**
22+
* Test creditmemo items to render
23+
*/
24+
class ItemsToRenderTest extends TestCase
25+
{
26+
/**
27+
* @var ItemsToRender
28+
*/
29+
private $itemsToRender;
30+
31+
/**
32+
* @var ConvertOrder|MockObject
33+
*/
34+
private $converter;
35+
36+
/**
37+
* @var BlockItems|MockObject
38+
*/
39+
private $blockItems;
40+
41+
/**
42+
* @var Creditmemo|MockObject
43+
*/
44+
private $creditmemo;
45+
46+
/**
47+
* @var CreditmemoItem|MockObject
48+
*/
49+
private $creditmemoItem;
50+
51+
/**
52+
* @var CreditmemoItem|MockObject
53+
*/
54+
private $creditmemoItemParent;
55+
56+
/**
57+
* @var OrderItem|MockObject
58+
*/
59+
private $orderItem;
60+
61+
/**
62+
* @var OrderItem|MockObject
63+
*/
64+
private $orderItemParent;
65+
66+
/**
67+
* @inheritdoc
68+
*/
69+
protected function setUp(): void
70+
{
71+
$this->converter = $this->getMockBuilder(ConvertOrder::class)
72+
->onlyMethods(['itemToCreditmemoItem'])
73+
->disableOriginalConstructor()
74+
->getMock();
75+
$this->blockItems = $this->getMockBuilder(BlockItems::class)
76+
->onlyMethods(['getCreditmemo'])
77+
->disableOriginalConstructor()
78+
->getMock();
79+
$this->creditmemo = $this->getMockBuilder(Creditmemo::class)
80+
->onlyMethods(['getAllItems', 'getId', 'getStoreId'])
81+
->disableOriginalConstructor()
82+
->getMock();
83+
$this->creditmemoItem = $this->getMockBuilder(CreditmemoItem::class)
84+
->onlyMethods(['getOrderItem', 'getCreditMemo'])
85+
->disableOriginalConstructor()
86+
->getMock();
87+
$this->creditmemoItemParent = $this->getMockBuilder(CreditmemoItem::class)
88+
->onlyMethods(['setCreditmemo', 'setParentId'])
89+
->disableOriginalConstructor()
90+
->getMock();
91+
$this->creditmemoItemParent = $this->getMockBuilder(CreditmemoItem::class)
92+
->addMethods(['getItemId', 'setStoreId'])
93+
->disableOriginalConstructor()
94+
->getMock();
95+
$this->orderItem = $this->getMockBuilder(OrderItem::class)
96+
->onlyMethods(['getParentItem'])
97+
->disableOriginalConstructor()
98+
->getMock();
99+
$this->orderItemParent = $this->getMockBuilder(OrderItem::class)
100+
->onlyMethods(['getItemId'])
101+
->disableOriginalConstructor()
102+
->getMock();
103+
/** @var ObjectManager */
104+
$objectManager = new ObjectManager($this);
105+
$this->itemsToRender = $objectManager->getObject(
106+
ItemsToRender::class,
107+
[
108+
'items' => $this->blockItems,
109+
'converter' => $this->converter
110+
]
111+
);
112+
}
113+
114+
/**
115+
* Test get items
116+
*/
117+
public function testGetItems(): void
118+
{
119+
$this->blockItems->method('getCreditmemo')
120+
->willReturn($this->creditmemo);
121+
$this->creditmemo->method('getAllItems')
122+
->willReturn([$this->creditmemoItem]);
123+
$this->creditmemo->method('getId')
124+
->willReturn(1);
125+
$this->creditmemoItem->method('getCreditmemo')
126+
->willReturn($this->creditmemo);
127+
$this->creditmemo->method('getStoreId')
128+
->willReturn(1);
129+
$this->creditmemoItem->method('getOrderItem')
130+
->willReturn($this->orderItem);
131+
$this->orderItem->method('getParentItem')
132+
->willReturn($this->orderItemParent);
133+
$this->orderItemParent->method('getItemId')
134+
->willReturn(1);
135+
$this->converter->method('itemToCreditmemoItem')
136+
->willReturn($this->creditmemoItemParent);
137+
138+
$this->assertEquals(
139+
[$this->creditmemoItemParent, $this->creditmemoItem],
140+
$this->itemsToRender->getItems()
141+
);
142+
}
143+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Sales\ViewModel\CreditMemo\Create;
10+
11+
use Magento\Framework\View\Element\Block\ArgumentInterface;
12+
use Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Items;
13+
use Magento\Sales\Model\Convert\OrderFactory;
14+
use Magento\Sales\Model\Convert\Order as ConvertOrder;
15+
use Magento\Sales\Model\Order\Creditmemo\Item;
16+
17+
/**
18+
* View model to return creditmemo items for rendering
19+
*/
20+
class ItemsToRender implements ArgumentInterface
21+
{
22+
/**
23+
* @var Items
24+
*/
25+
private $items;
26+
27+
/**
28+
* @var ConvertOrder
29+
*/
30+
private $converter;
31+
32+
/**
33+
* @param Items $items
34+
* @param OrderFactory $convertOrderFactory
35+
*/
36+
public function __construct(
37+
Items $items,
38+
OrderFactory $convertOrderFactory
39+
) {
40+
$this->items = $items;
41+
$this->converter = $convertOrderFactory->create();
42+
}
43+
44+
/**
45+
* Return creditmemo items for rendering and make sure all its parents are included
46+
*
47+
* @return Item[]
48+
*/
49+
public function getItems(): array
50+
{
51+
$creditMemo = null;
52+
$parents = [];
53+
$items = [];
54+
foreach ($this->items->getCreditmemo()->getAllItems() as $item) {
55+
if (!$creditMemo) {
56+
$creditMemo = $item->getCreditmemo();
57+
}
58+
$orderItem = $item->getOrderItem();
59+
if ($orderItem->getChildrenItems()) {
60+
$parents[] = $orderItem->getItemId();
61+
}
62+
}
63+
foreach ($this->items->getCreditmemo()->getAllItems() as $item) {
64+
$orderItemParent = $item->getOrderItem()->getParentItem();
65+
if ($orderItemParent && !in_array($orderItemParent->getItemId(), $parents)) {
66+
$itemParent = $this->converter->itemToCreditmemoItem($orderItemParent);
67+
$itemParent->setCreditmemo($creditMemo)
68+
->setParentId($creditMemo->getId())
69+
->setStoreId($creditMemo->getStoreId());
70+
$items[] = $itemParent;
71+
$parents[] = $orderItemParent->getItemId();
72+
}
73+
$items[] = $item;
74+
}
75+
return $items;
76+
}
77+
}

app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<block class="Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Items" name="order_items" template="Magento_Sales::order/creditmemo/create/items.phtml">
2121
<arguments>
2222
<argument name="viewModel" xsi:type="object">Magento\Sales\ViewModel\CreditMemo\Create\UpdateTotalsButton</argument>
23+
<argument name="itemsToRenderViewModel" xsi:type="object">Magento\Sales\ViewModel\CreditMemo\Create\ItemsToRender</argument>
2324
</arguments>
2425
<block class="Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRenderer" name="order_items.default" as="default" template="Magento_Sales::order/creditmemo/create/items/renderer/default.phtml"/>
2526
<block class="Magento\Sales\Block\Adminhtml\Items\Column\Qty" name="column_qty" template="Magento_Sales::items/column/qty.phtml" group="column"/>

app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<block class="Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Items" name="order_items" template="Magento_Sales::order/creditmemo/create/items.phtml">
1212
<arguments>
1313
<argument name="viewModel" xsi:type="object">Magento\Sales\ViewModel\CreditMemo\Create\UpdateTotalsButton</argument>
14+
<argument name="itemsToRenderViewModel" xsi:type="object">Magento\Sales\ViewModel\CreditMemo\Create\ItemsToRender</argument>
1415
</arguments>
1516
<block class="Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRenderer" name="order_items.default" as="default" template="Magento_Sales::order/creditmemo/create/items/renderer/default.phtml"/>
1617
<block class="Magento\Sales\Block\Adminhtml\Items\Column\Qty" name="column_qty" template="Magento_Sales::items/column/qty.phtml" group="column"/>

app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,26 @@
99
<?php
1010
/** @var Magento\Sales\ViewModel\CreditMemo\Create\UpdateTotalsButton $viewModel */
1111
$viewModel = $block->getData('viewModel');
12-
$_items = $block->getCreditmemo()->getAllItems();
12+
/** @var Magento\Sales\ViewModel\CreditMemo\Create\ItemsToRender $itemsToRenderViewModel */
13+
$itemsToRenderViewModel = $block->getData('itemsToRenderViewModel');
14+
$_items = $itemsToRenderViewModel->getItems();
15+
$commentText = $block->getCreditmemo()->getCommentText();
1316
?>
1417

1518
<section class="admin__page-section">
1619
<div class="admin__page-section-title">
1720
<span class="title"><?= $block->escapeHtml(__('Items to Refund')) ?></span>
1821
</div>
1922

20-
<?php if (count($_items)) : ?>
23+
<?php if (count($_items)): ?>
2124
<div class="admin__table-wrapper">
2225
<table class="data-table admin__table-primary order-creditmemo-tables">
2326
<thead>
2427
<tr class="headings">
2528
<th class="col-product"><span><?= $block->escapeHtml(__('Product')) ?></span></th>
2629
<th class="col-price"><span><?= $block->escapeHtml(__('Price')) ?></span></th>
2730
<th class="col-ordered-qty"><span><?= $block->escapeHtml(__('Qty')) ?></span></th>
28-
<?php if ($block->canReturnToStock()) : ?>
31+
<?php if ($block->canReturnToStock()): ?>
2932
<th class="col-return-to-stock"><span><?= $block->escapeHtml(__('Return to Stock')) ?></span></th>
3033
<?php endif; ?>
3134
<th class="col-refund"><span><?= $block->escapeHtml(__('Qty to Refund')) ?></span></th>
@@ -35,7 +38,7 @@ $_items = $block->getCreditmemo()->getAllItems();
3538
<th class="col-total last"><span><?= $block->escapeHtml(__('Row Total')) ?></span></th>
3639
</tr>
3740
</thead>
38-
<?php if ($block->canEditQty()) : ?>
41+
<?php if ($block->canEditQty()): ?>
3942
<tfoot>
4043
<tr>
4144
<td colspan="4">&nbsp;</td>
@@ -46,10 +49,10 @@ $_items = $block->getCreditmemo()->getAllItems();
4649
</tr>
4750
</tfoot>
4851
<?php endif; ?>
49-
<?php $i = 0; foreach ($_items as $_item) : ?>
50-
<?php if ($_item->getOrderItem()->getParentItem()) :
52+
<?php $i = 0; foreach ($_items as $_item): ?>
53+
<?php if ($_item->getOrderItem()->getParentItem()):
5154
continue;
52-
else :
55+
else:
5356
$i++;
5457
endif; ?>
5558
<tbody class="<?= /* @noEscape */ $i%2 ? 'even' : 'odd' ?>">
@@ -59,7 +62,7 @@ $_items = $block->getCreditmemo()->getAllItems();
5962
<?php endforeach; ?>
6063
</table>
6164
</div>
62-
<?php else : ?>
65+
<?php else: ?>
6366
<div class="no-items">
6467
<?= $block->escapeHtml(__('No Items To Refund')) ?>
6568
</div>
@@ -68,7 +71,7 @@ $_items = $block->getCreditmemo()->getAllItems();
6871

6972
<?php $orderTotalBar = $block->getChildHtml('order_totalbar'); ?>
7073

71-
<?php if (!empty($orderTotalBar)) : ?>
74+
<?php if (!empty($orderTotalBar)): ?>
7275
<section class="fieldset-wrapper">
7376
<?= /* @noEscape */ $orderTotalBar ?>
7477
</section>
@@ -94,7 +97,7 @@ $_items = $block->getCreditmemo()->getAllItems();
9497
class="admin__control-textarea"
9598
name="creditmemo[comment_text]"
9699
rows="3"
97-
cols="5"><?= $block->escapeHtml($block->getCreditmemo()->getCommentText()) ?></textarea>
100+
cols="5"><?= $block->escapeHtml($commentText) ?></textarea>
98101
</div>
99102
</div>
100103
</div>
@@ -116,7 +119,7 @@ $_items = $block->getCreditmemo()->getAllItems();
116119
<span><?= $block->escapeHtml(__('Append Comments')) ?></span>
117120
</label>
118121
</div>
119-
<?php if ($block->canSendCreditmemoEmail()) :?>
122+
<?php if ($block->canSendCreditmemoEmail()):?>
120123
<div class="field choice admin__field admin__field-option field-email-copy">
121124
<input id="send_email"
122125
class="admin__control-checkbox"

0 commit comments

Comments
 (0)