Skip to content

Commit bff7645

Browse files
committed
Merge branch 'ACP2E-2982' of https://github.com/adobe-commerce-tier-4/magento2ce into 04-29-24-Tier4-Bugfix-Delivery
2 parents a1b9be2 + 64eb22d commit bff7645

File tree

2 files changed

+114
-22
lines changed

2 files changed

+114
-22
lines changed

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

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@
55
*/
66
namespace Magento\Sales\Model;
77

8+
use Magento\Framework\App\ObjectManager;
89
use Magento\Framework\App\ResourceConnection;
910
use Magento\Sales\Api\CreditmemoRepositoryInterface;
11+
use Magento\Sales\Api\Data\CreditmemoCommentCreationInterface;
12+
use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
1013
use Magento\Sales\Api\InvoiceRepositoryInterface;
1114
use Magento\Sales\Api\OrderRepositoryInterface;
1215
use Magento\Sales\Api\RefundInvoiceInterface;
16+
use Magento\Sales\Exception\CouldNotRefundException;
17+
use Magento\Sales\Exception\DocumentValidationException;
1318
use Magento\Sales\Model\Order\Config as OrderConfig;
1419
use Magento\Sales\Model\Order\Creditmemo\NotifierInterface;
1520
use Magento\Sales\Model\Order\CreditmemoDocumentFactory;
@@ -19,7 +24,6 @@
1924
use Psr\Log\LoggerInterface;
2025

2126
/**
22-
* Class RefundInvoice
2327
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2428
*/
2529
class RefundInvoice implements RefundInvoiceInterface
@@ -79,6 +83,11 @@ class RefundInvoice implements RefundInvoiceInterface
7983
*/
8084
private $validator;
8185

86+
/**
87+
* @var OrderMutexInterface
88+
*/
89+
private $orderMutex;
90+
8291
/**
8392
* RefundInvoice constructor.
8493
*
@@ -93,6 +102,7 @@ class RefundInvoice implements RefundInvoiceInterface
93102
* @param NotifierInterface $notifier
94103
* @param OrderConfig $config
95104
* @param LoggerInterface $logger
105+
* @param OrderMutexInterface|null $orderMutex
96106
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
97107
*/
98108
public function __construct(
@@ -106,7 +116,8 @@ public function __construct(
106116
CreditmemoDocumentFactory $creditmemoDocumentFactory,
107117
NotifierInterface $notifier,
108118
OrderConfig $config,
109-
LoggerInterface $logger
119+
LoggerInterface $logger,
120+
?OrderMutexInterface $orderMutex = null
110121
) {
111122
$this->resourceConnection = $resourceConnection;
112123
$this->orderStateResolver = $orderStateResolver;
@@ -119,6 +130,7 @@ public function __construct(
119130
$this->notifier = $notifier;
120131
$this->config = $config;
121132
$this->logger = $logger;
133+
$this->orderMutex = $orderMutex ?: ObjectManager::getInstance()->get(OrderMutexInterface::class);
122134
}
123135

124136
/**
@@ -133,7 +145,48 @@ public function execute(
133145
\Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
134146
\Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
135147
) {
136-
$connection = $this->resourceConnection->getConnection('sales');
148+
$invoice = $this->invoiceRepository->get($invoiceId);
149+
$order = $this->orderRepository->get($invoice->getOrderId());
150+
151+
return $this->orderMutex->execute(
152+
(int) $order->getEntityId(),
153+
\Closure::fromCallable([$this, 'processRefund']),
154+
[
155+
$invoiceId,
156+
$items,
157+
$isOnline,
158+
$notify,
159+
$appendComment,
160+
$comment,
161+
$arguments
162+
]
163+
);
164+
}
165+
166+
/**
167+
* Refund process logic
168+
*
169+
* @param int $invoiceId
170+
* @param array $items
171+
* @param bool $isOnline
172+
* @param bool $notify
173+
* @param bool $appendComment
174+
* @param CreditmemoCommentCreationInterface|null $comment
175+
* @param CreditmemoCreationArgumentsInterface|null $arguments
176+
* @return int|null
177+
* @throws CouldNotRefundException
178+
* @throws DocumentValidationException
179+
* @SuppressWarnings(PHPMD.UnusedPrivateMethod) This method is used in closure callback
180+
*/
181+
private function processRefund(
182+
$invoiceId,
183+
array $items = [],
184+
bool $isOnline = false,
185+
bool $notify = false,
186+
bool $appendComment = false,
187+
\Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
188+
\Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
189+
) {
137190
$invoice = $this->invoiceRepository->get($invoiceId);
138191
$order = $this->orderRepository->get($invoice->getOrderId());
139192
$creditmemo = $this->creditmemoDocumentFactory->createFromInvoice(
@@ -160,7 +213,6 @@ public function execute(
160213
__("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages->getMessages()))
161214
);
162215
}
163-
$connection->beginTransaction();
164216
try {
165217
$creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED);
166218
$order->setCustomerNoteNotify($notify);
@@ -178,10 +230,8 @@ public function execute(
178230
$this->invoiceRepository->save($invoice);
179231
$order = $this->orderRepository->save($order);
180232
$creditmemo = $this->creditmemoRepository->save($creditmemo);
181-
$connection->commit();
182233
} catch (\Exception $e) {
183234
$this->logger->critical($e);
184-
$connection->rollBack();
185235
throw new \Magento\Sales\Exception\CouldNotRefundException(
186236
__('Could not save a Creditmemo, see error log for details')
187237
);

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

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use Magento\Framework\App\ResourceConnection;
1111
use Magento\Framework\DB\Adapter\AdapterInterface;
12+
use Magento\Framework\DB\Select;
1213
use Magento\Sales\Api\CreditmemoRepositoryInterface;
1314
use Magento\Sales\Api\Data\CreditmemoCommentCreationInterface;
1415
use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
@@ -28,6 +29,7 @@
2829
use Magento\Sales\Model\Order\OrderStateResolverInterface;
2930
use Magento\Sales\Model\Order\RefundAdapterInterface;
3031
use Magento\Sales\Model\Order\Validation\RefundInvoiceInterface;
32+
use Magento\Sales\Model\OrderMutex;
3133
use Magento\Sales\Model\RefundInvoice;
3234
use Magento\Sales\Model\ValidatorResultInterface;
3335
use PHPUnit\Framework\MockObject\MockObject;
@@ -222,7 +224,8 @@ protected function setUp(): void
222224
$this->creditmemoDocumentFactoryMock,
223225
$this->notifierMock,
224226
$this->configMock,
225-
$this->loggerMock
227+
$this->loggerMock,
228+
new OrderMutex($this->resourceConnectionMock)
226229
);
227230
}
228231

@@ -238,14 +241,17 @@ protected function setUp(): void
238241
*/
239242
public function testOrderCreditmemo($invoiceId, $isOnline, $items, $notify, $appendComment)
240243
{
241-
$this->resourceConnectionMock->expects($this->once())
242-
->method('getConnection')
243-
->with('sales')
244-
->willReturn($this->adapterInterface);
245-
$this->invoiceRepositoryMock->expects($this->once())
244+
$this->mockConnection($invoiceId);
245+
$this->invoiceMock->expects($this->exactly(2))
246+
->method('getOrderId')
247+
->willReturn($invoiceId);
248+
$this->orderMock->expects($this->once())
249+
->method('getEntityId')
250+
->willReturn($invoiceId);
251+
$this->invoiceRepositoryMock->expects($this->exactly(2))
246252
->method('get')
247253
->willReturn($this->invoiceMock);
248-
$this->orderRepositoryMock->expects($this->once())
254+
$this->orderRepositoryMock->expects($this->exactly(2))
249255
->method('get')
250256
->willReturn($this->orderMock);
251257
$this->creditmemoDocumentFactoryMock->expects($this->once())
@@ -341,11 +347,17 @@ public function testDocumentValidationException()
341347
$appendComment = true;
342348
$isOnline = false;
343349
$errorMessages = ['error1', 'error2'];
344-
345-
$this->invoiceRepositoryMock->expects($this->once())
350+
$this->mockConnection($invoiceId);
351+
$this->invoiceMock->expects($this->exactly(2))
352+
->method('getOrderId')
353+
->willReturn($invoiceId);
354+
$this->orderMock->expects($this->once())
355+
->method('getEntityId')
356+
->willReturn($invoiceId);
357+
$this->invoiceRepositoryMock->expects($this->exactly(2))
346358
->method('get')
347359
->willReturn($this->invoiceMock);
348-
$this->orderRepositoryMock->expects($this->once())
360+
$this->orderRepositoryMock->expects($this->exactly(2))
349361
->method('get')
350362
->willReturn($this->orderMock);
351363

@@ -401,15 +413,18 @@ public function testCouldNotCreditmemoException()
401413
$notify = true;
402414
$appendComment = true;
403415
$isOnline = false;
404-
$this->resourceConnectionMock->expects($this->once())
405-
->method('getConnection')
406-
->with('sales')
407-
->willReturn($this->adapterInterface);
408416

409-
$this->invoiceRepositoryMock->expects($this->once())
417+
$this->mockConnection($invoiceId);
418+
$this->invoiceMock->expects($this->exactly(2))
419+
->method('getOrderId')
420+
->willReturn($invoiceId);
421+
$this->orderMock->expects($this->once())
422+
->method('getEntityId')
423+
->willReturn($invoiceId);
424+
$this->invoiceRepositoryMock->expects($this->exactly(2))
410425
->method('get')
411426
->willReturn($this->invoiceMock);
412-
$this->orderRepositoryMock->expects($this->once())
427+
$this->orderRepositoryMock->expects($this->exactly(2))
413428
->method('get')
414429
->willReturn($this->orderMock);
415430

@@ -479,4 +494,31 @@ public function dataProvider()
479494
'TestWithNotifyFalse' => [1, true, [1 => $creditmemoItemCreationMock], false, true],
480495
];
481496
}
497+
498+
private function mockConnection(int $orderId)
499+
{
500+
$select = $this->createMock(Select::class);
501+
$select->expects($this->once())
502+
->method('from')
503+
->with('sales_order', 'entity_id')
504+
->willReturnSelf();
505+
$select->expects($this->once())
506+
->method('where')
507+
->with('entity_id = ?', $orderId)
508+
->willReturnSelf();
509+
$select->expects($this->once())
510+
->method('forUpdate')
511+
->with(true)
512+
->willReturnSelf();
513+
$this->adapterInterface->expects($this->once())
514+
->method('select')
515+
->willReturn($select);
516+
$this->resourceConnectionMock->expects($this->once())
517+
->method('getConnection')
518+
->with('sales')
519+
->willReturn($this->adapterInterface);
520+
$this->resourceConnectionMock->expects($this->once())
521+
->method('getTableName')
522+
->willReturnArgument(0);
523+
}
482524
}

0 commit comments

Comments
 (0)