Skip to content

Commit a101bc5

Browse files
authored
ENGCOM-4673: 12386: Order Status resets to default Status after Partial Refund. #20378
2 parents a628e74 + 8712995 commit a101bc5

File tree

8 files changed

+225
-17
lines changed

8 files changed

+225
-17
lines changed

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public function canCapture()
300300
}
301301

302302
/**
303-
* Check refund availability
303+
* Check refund availability.
304304
*
305305
* @return bool
306306
*/
@@ -310,7 +310,7 @@ public function canRefund()
310310
}
311311

312312
/**
313-
* Check partial refund availability for invoice
313+
* Check partial refund availability for invoice.
314314
*
315315
* @return bool
316316
*/
@@ -320,7 +320,7 @@ public function canRefundPartialPerInvoice()
320320
}
321321

322322
/**
323-
* Check partial capture availability
323+
* Check partial capture availability.
324324
*
325325
* @return bool
326326
*/
@@ -546,9 +546,7 @@ public function cancelInvoice($invoice)
546546
}
547547

548548
/**
549-
* Create new invoice with maximum qty for invoice for each item
550-
*
551-
* Register this invoice and capture
549+
* Create new invoice with maximum qty for invoice for each item register this invoice and capture
552550
*
553551
* @return Invoice
554552
*/
@@ -686,6 +684,7 @@ public function refund($creditmemo)
686684
$gateway->refund($this, $baseAmountToRefund);
687685

688686
$creditmemo->setTransactionId($this->getLastTransId());
687+
// phpcs:ignore Magento2.Exceptions.ThrowCatch
689688
} catch (\Magento\Framework\Exception\LocalizedException $e) {
690689
if (!$captureTxn) {
691690
throw new \Magento\Framework\Exception\LocalizedException(
@@ -732,10 +731,14 @@ public function refund($creditmemo)
732731
$message = $message = $this->prependMessage($message);
733732
$message = $this->_appendTransactionToMessage($transaction, $message);
734733
$orderState = $this->getOrderStateResolver()->getStateForOrder($this->getOrder());
734+
$statuses = $this->getOrder()->getConfig()->getStateStatuses($orderState, false);
735+
$status = in_array($this->getOrder()->getStatus(), $statuses, true)
736+
? $this->getOrder()->getStatus()
737+
: $this->getOrder()->getConfig()->getStateDefaultStatus($orderState);
735738
$this->getOrder()
736739
->addStatusHistoryComment(
737740
$message,
738-
$this->getOrder()->getConfig()->getStateDefaultStatus($orderState)
741+
$status
739742
)->setIsCustomerNotified($creditmemo->getOrder()->getCustomerNoteNotify());
740743
$this->_eventManager->dispatch(
741744
'sales_order_payment_refund',
@@ -1203,7 +1206,7 @@ public function addTransaction($type, $salesDocument = null, $failSafe = false)
12031206
}
12041207

12051208
/**
1206-
* Add message to the specified transaction.
1209+
* Add transaction comments to order.
12071210
*
12081211
* @param Transaction|null $transaction
12091212
* @param string $message

app/code/Magento/Sales/Model/RefundOrder.php

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

89
use Magento\Framework\App\ResourceConnection;
@@ -151,10 +152,13 @@ public function execute(
151152
$creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED);
152153
$order->setCustomerNoteNotify($notify);
153154
$order = $this->refundAdapter->refund($creditmemo, $order);
154-
$order->setState(
155-
$this->orderStateResolver->getStateForOrder($order, [])
156-
);
157-
$order->setStatus($this->config->getStateDefaultStatus($order->getState()));
155+
$orderState = $this->orderStateResolver->getStateForOrder($order, []);
156+
$order->setState($orderState);
157+
$statuses = $this->config->getStateStatuses($orderState, false);
158+
$status = in_array($order->getStatus(), $statuses, true)
159+
? $order->getStatus()
160+
: $this->config->getStateDefaultStatus($orderState);
161+
$order->setStatus($status);
158162

159163
$order = $this->orderRepository->save($order);
160164
$creditmemo = $this->creditmemoRepository->save($creditmemo);

app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Sales\Test\Unit\Model\Order;
78

89
use Magento\Framework\Model\Context;
@@ -1526,7 +1527,7 @@ public function testRefund()
15261527
$this->orderStateResolver->expects($this->once())->method('getStateForOrder')
15271528
->with($this->order)
15281529
->willReturn(Order::STATE_CLOSED);
1529-
$this->mockGetDefaultStatus(Order::STATE_CLOSED, $status);
1530+
$this->mockGetDefaultStatus(Order::STATE_CLOSED, $status, ['first, second']);
15301531
$this->assertOrderUpdated(Order::STATE_PROCESSING, $status, $message);
15311532

15321533
static::assertSame($this->payment, $this->payment->refund($this->creditMemoMock));

app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Sales\Test\Unit\Model;
78

89
use Magento\Framework\App\ResourceConnection;
@@ -245,9 +246,9 @@ public function testOrderCreditmemo($orderId, $notify, $appendComment)
245246
->method('setState')
246247
->with(Order::STATE_CLOSED)
247248
->willReturnSelf();
248-
$this->orderMock->expects($this->once())
249-
->method('getState')
250-
->willReturn(Order::STATE_CLOSED);
249+
$this->configMock->expects($this->once())
250+
->method('getStateStatuses')
251+
->willReturn(['first, second']);
251252
$this->configMock->expects($this->once())
252253
->method('getStateDefaultStatus')
253254
->with(Order::STATE_CLOSED)

dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Sales\Service\V1;
78

89
use Magento\Sales\Model\Order;
@@ -201,6 +202,73 @@ public function testFullRequest()
201202
}
202203
}
203204

205+
/**
206+
* Test order will keep same(custom) status after partial refund, if state has not been changed.
207+
*
208+
* @magentoApiDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
209+
*/
210+
public function testOrderStatusPartialRefund()
211+
{
212+
/** @var \Magento\Sales\Model\Order $existingOrder */
213+
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
214+
->loadByIncrementId('100000001');
215+
216+
$items = $this->getOrderItems($existingOrder);
217+
$items[0]['qty'] -= 1;
218+
$result = $this->_webApiCall(
219+
$this->getServiceData($existingOrder),
220+
[
221+
'orderId' => $existingOrder->getEntityId(),
222+
'items' => $items,
223+
]
224+
);
225+
226+
$this->assertNotEmpty(
227+
$result,
228+
'Failed asserting that the received response is correct'
229+
);
230+
231+
/** @var \Magento\Sales\Model\Order $updatedOrder */
232+
$updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
233+
->loadByIncrementId($existingOrder->getIncrementId());
234+
235+
$this->assertSame('custom_processing', $updatedOrder->getStatus());
236+
$this->assertSame('processing', $updatedOrder->getState());
237+
}
238+
239+
/**
240+
* Test order will change custom status after total refund, when state has been changed.
241+
*
242+
* @magentoApiDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
243+
*/
244+
public function testOrderStatusTotalRefund()
245+
{
246+
/** @var \Magento\Sales\Model\Order $existingOrder */
247+
$existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
248+
->loadByIncrementId('100000001');
249+
250+
$items = $this->getOrderItems($existingOrder);
251+
$result = $this->_webApiCall(
252+
$this->getServiceData($existingOrder),
253+
[
254+
'orderId' => $existingOrder->getEntityId(),
255+
'items' => $items,
256+
]
257+
);
258+
259+
$this->assertNotEmpty(
260+
$result,
261+
'Failed asserting that the received response is correct'
262+
);
263+
264+
/** @var \Magento\Sales\Model\Order $updatedOrder */
265+
$updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
266+
->loadByIncrementId($existingOrder->getIncrementId());
267+
268+
$this->assertSame('complete', $updatedOrder->getStatus());
269+
$this->assertSame('complete', $updatedOrder->getState());
270+
}
271+
204272
/**
205273
* Prepares and returns info for API service.
206274
*

dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77

88
namespace Magento\Sales\Controller\Adminhtml\Order\Creditmemo;
99

10+
use Magento\Framework\App\Request\Http as HttpRequest;
11+
use Magento\Sales\Api\Data\OrderItemInterface;
12+
use Magento\Sales\Model\Order;
1013
use PHPUnit\Framework\Constraint\StringContains;
1114

1215
/**
13-
* Class tests creditmemo creation in backend.
16+
* Provide tests for CreditMemo save controller.
1417
*
1518
* @magentoDbIsolation enabled
1619
* @magentoAppArea adminhtml
@@ -24,6 +27,8 @@ class SaveTest extends AbstractCreditmemoControllerTest
2427
protected $uri = 'backend/sales/order_creditmemo/save';
2528

2629
/**
30+
* @magentoDbIsolation enabled
31+
* @magentoDataFixture Magento/Sales/_files/invoice.php
2732
* @return void
2833
*/
2934
public function testSendEmailOnCreditmemoSave(): void
@@ -54,6 +59,91 @@ public function testSendEmailOnCreditmemoSave(): void
5459
$this->assertThat($message->getRawMessage(), $messageConstraint);
5560
}
5661

62+
/**
63+
* Test order will keep same(custom) status after partial refund, if state has not been changed.
64+
*
65+
* @magentoDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
66+
*/
67+
public function testOrderStatusPartialRefund()
68+
{
69+
/** @var Order $existingOrder */
70+
$existingOrder = $this->_objectManager->create(Order::class)->loadByIncrementId('100000001');
71+
$items = $this->getOrderItems($existingOrder, 1);
72+
$requestParams = [
73+
'creditmemo' => [
74+
'items' => $items,
75+
'do_offline' => '1',
76+
'comment_text' => '',
77+
'shipping_amount' => '0',
78+
'adjustment_positive' => '0',
79+
'adjustment_negative' => '0',
80+
],
81+
'order_id' => $existingOrder->getId(),
82+
];
83+
$this->getRequest()->setMethod(HttpRequest::METHOD_POST);
84+
$this->getRequest()->setParams($requestParams);
85+
$this->dispatch('backend/sales/order_creditmemo/save');
86+
87+
/** @var Order $updatedOrder */
88+
$updatedOrder = $this->_objectManager->create(Order::class)
89+
->loadByIncrementId($existingOrder->getIncrementId());
90+
91+
$this->assertSame('custom_processing', $updatedOrder->getStatus());
92+
$this->assertSame('processing', $updatedOrder->getState());
93+
}
94+
95+
/**
96+
* Test order will change custom status after total refund, when state has been changed.
97+
*
98+
* @magentoDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
99+
*/
100+
public function testOrderStatusTotalRefund()
101+
{
102+
/** @var Order $existingOrder */
103+
$existingOrder = $this->_objectManager->create(Order::class)->loadByIncrementId('100000001');
104+
$requestParams = [
105+
'creditmemo' => [
106+
'items' => $this->getOrderItems($existingOrder),
107+
'do_offline' => '1',
108+
'comment_text' => '',
109+
'shipping_amount' => '0',
110+
'adjustment_positive' => '0',
111+
'adjustment_negative' => '0',
112+
],
113+
'order_id' => $existingOrder->getId(),
114+
];
115+
$this->getRequest()->setMethod(HttpRequest::METHOD_POST);
116+
$this->getRequest()->setParams($requestParams);
117+
$this->dispatch('backend/sales/order_creditmemo/save');
118+
119+
/** @var Order $updatedOrder */
120+
$updatedOrder = $this->_objectManager->create(Order::class)
121+
->loadByIncrementId($existingOrder->getIncrementId());
122+
123+
$this->assertSame('complete', $updatedOrder->getStatus());
124+
$this->assertSame('complete', $updatedOrder->getState());
125+
}
126+
127+
/**
128+
* Gets all items of given Order in proper format.
129+
*
130+
* @param Order $order
131+
* @param int $subQty
132+
* @return array
133+
*/
134+
private function getOrderItems(Order $order, int $subQty = 0)
135+
{
136+
$items = [];
137+
/** @var OrderItemInterface $item */
138+
foreach ($order->getAllItems() as $item) {
139+
$items[$item->getItemId()] = [
140+
'qty' => $item->getQtyOrdered() - $subQty,
141+
];
142+
}
143+
144+
return $items;
145+
}
146+
57147
/**
58148
* @inheritdoc
59149
*/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Sales\Model\Order\Status;
9+
use Magento\TestFramework\Helper\Bootstrap;
10+
11+
// phpcs:ignore Magento2.Security.IncludeFile
12+
require 'invoice.php';
13+
14+
$orderStatus = Bootstrap::getObjectManager()->create(Status::class);
15+
$data = [
16+
'status' => 'custom_processing',
17+
'label' => 'Custom Processing Status',
18+
];
19+
$orderStatus->setData($data)->setStatus('custom_processing');
20+
$orderStatus->save();
21+
$orderStatus->assignState('processing');
22+
23+
$order->setStatus('custom_processing');
24+
$order->save();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Sales\Model\Order\Status;
9+
use Magento\TestFramework\Helper\Bootstrap;
10+
11+
// phpcs:ignore Magento2.Security.IncludeFile
12+
require 'default_rollback.php';
13+
14+
/** @var Status $orderStatus */
15+
$orderStatus = Bootstrap::getObjectManager()->create(Status::class);
16+
$orderStatus->load('custom_processing', 'status');
17+
$orderStatus->delete();

0 commit comments

Comments
 (0)