Skip to content

Commit 506d5ba

Browse files
authored
MAGETWO-80095: Prevent invoice cancelation multiple times #11073
2 parents 0205db6 + 492f6c7 commit 506d5ba

File tree

2 files changed

+72
-5
lines changed

2 files changed

+72
-5
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,9 @@ public function void()
407407
*/
408408
public function cancel()
409409
{
410+
if (!$this->canCancel()) {
411+
return $this;
412+
}
410413
$order = $this->getOrder();
411414
$order->getPayment()->cancelInvoice($this);
412415
foreach ($this->getAllItems() as $item) {

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

+69-5
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88

99
namespace Magento\Sales\Test\Unit\Model\Order;
1010

11+
use Magento\Sales\Api\Data\InvoiceInterface;
12+
use Magento\Sales\Model\Order;
1113
use Magento\Sales\Model\Order\Invoice;
14+
use Magento\Sales\Model\ResourceModel\Order\Invoice\Collection as InvoiceCollection;
1215
use Magento\Sales\Model\ResourceModel\OrderFactory;
13-
use Magento\Sales\Model\Order;
14-
use Magento\TestFramework\Helper\Bootstrap;
1516
use PHPUnit_Framework_MockObject_MockObject as MockObject;
16-
use Magento\Sales\Model\ResourceModel\Order\Invoice\Collection as InvoiceCollection;
1717

1818
/**
1919
* Class InvoiceTest
@@ -72,7 +72,7 @@ protected function setUp()
7272
->setMethods(
7373
[
7474
'getPayment', '__wakeup', 'load', 'setHistoryEntityName', 'getStore', 'getBillingAddress',
75-
'getShippingAddress'
75+
'getShippingAddress', 'getConfig',
7676
]
7777
)
7878
->getMock();
@@ -83,7 +83,7 @@ protected function setUp()
8383
$this->paymentMock = $this->getMockBuilder(
8484
\Magento\Sales\Model\Order\Payment::class
8585
)->disableOriginalConstructor()->setMethods(
86-
['canVoid', '__wakeup', 'canCapture', 'capture', 'pay']
86+
['canVoid', '__wakeup', 'canCapture', 'capture', 'pay', 'cancelInvoice']
8787
)->getMock();
8888

8989
$this->orderFactory = $this->createPartialMock(\Magento\Sales\Model\OrderFactory::class, ['create']);
@@ -407,4 +407,68 @@ private function getOrderInvoiceCollection()
407407

408408
return $collection;
409409
}
410+
411+
/**
412+
* Assert open invoice can be canceled, and its status changes
413+
*/
414+
public function testCancelOpenInvoice()
415+
{
416+
$orderConfigMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Config::class)
417+
->disableOriginalConstructor()->setMethods(
418+
['getStateDefaultStatus']
419+
)->getMock();
420+
421+
$orderConfigMock->expects($this->once())->method('getStateDefaultStatus')
422+
->with(Order::STATE_PROCESSING)
423+
->willReturn(Order::STATE_PROCESSING);
424+
425+
$this->order->expects($this->once())->method('getPayment')->willReturn($this->paymentMock);
426+
$this->order->expects($this->once())->method('getConfig')->willReturn($orderConfigMock);
427+
428+
$this->paymentMock->expects($this->once())
429+
->method('cancelInvoice')
430+
->willReturn($this->paymentMock);
431+
432+
$this->eventManagerMock->expects($this->once())
433+
->method('dispatch')
434+
->with('sales_order_invoice_cancel');
435+
436+
$this->model->setData(InvoiceInterface::ITEMS, []);
437+
$this->model->setState(Invoice::STATE_OPEN);
438+
$this->model->cancel();
439+
440+
self::assertEquals(Invoice::STATE_CANCELED, $this->model->getState());
441+
}
442+
443+
/**
444+
* Assert open invoice can be canceled, and its status changes
445+
*
446+
* @param $initialInvoiceStatus
447+
* @param $finalInvoiceStatus
448+
* @dataProvider getNotOpenedInvoiceStatuses
449+
*/
450+
public function testCannotCancelNotOpenedInvoice($initialInvoiceStatus, $finalInvoiceStatus)
451+
{
452+
$this->order->expects($this->never())->method('getPayment');
453+
$this->paymentMock->expects($this->never())->method('cancelInvoice');
454+
$this->eventManagerMock->expects($this->never())
455+
->method('dispatch')
456+
->with('sales_order_invoice_cancel');
457+
458+
$this->model->setState($initialInvoiceStatus);
459+
$this->model->cancel();
460+
461+
self::assertEquals($finalInvoiceStatus, $this->model->getState());
462+
}
463+
464+
/**
465+
* @return array
466+
*/
467+
public function getNotOpenedInvoiceStatuses()
468+
{
469+
return [
470+
[Invoice::STATE_PAID, Invoice::STATE_PAID],
471+
[Invoice::STATE_CANCELED, Invoice::STATE_CANCELED],
472+
];
473+
}
410474
}

0 commit comments

Comments
 (0)