Skip to content

Commit a630c90

Browse files
Merge pull request #65 from Itonomy/feature/order-transaction-service
Fix cancel payment in order transaction service
2 parents 7cd6386 + 779508d commit a630c90

File tree

4 files changed

+193
-12
lines changed

4 files changed

+193
-12
lines changed

Client/Model/Response/Payment/Authorization.php

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
class Authorization
1212
{
1313
const STATE_AUTHORIZED = 'AUTHORIZED';
14+
const STATE_CANCELED = 'CANCELED';
1415

1516
/**
1617
* @var int|null

Service/OrderTransactionService.php

+16-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929

3030
class OrderTransactionService implements OrderTransactionServiceInterface
3131
{
32+
/**
33+
* Array of payment methods which should cancel the order when CM.com Payment is canceled.
34+
* @const array
35+
*/
36+
protected const SHOULD_CANCEL_PAYMENT_METHODS = [
37+
'cm_payments_creditcard'
38+
];
39+
3240
/**
3341
* @var OrderRepositoryInterface
3442
*/
@@ -124,7 +132,7 @@ public function process(string $orderReference): void
124132
);
125133
}
126134

127-
if (empty($cmOrderDetails->getConsideredSafe()) || ! $cmOrderDetails->isSafe()) {
135+
if (empty($cmOrderDetails->getConsideredSafe()) || !$cmOrderDetails->isSafe()) {
128136
$this->cancelOrderByPaymentStatus($cmOrder, $order, $cmOrderDetails);
129137

130138
// If order is not considered 'Safe' we don't have to process.
@@ -136,7 +144,6 @@ public function process(string $orderReference): void
136144
'cmOrderDetails' => $cmOrderDetails
137145
]);
138146

139-
// Todo: move to separate method or class
140147
$this->createCMPaymentIfNotExists($cmOrder, $order, $cmOrderDetails);
141148

142149
$this->logger->info('Create invoice and transaction for order '. $orderReference);
@@ -212,9 +219,14 @@ private function cancelOrderByPaymentStatus(
212219
): void {
213220
try {
214221
$cmPayment = $this->cmPaymentRepository->getByOrderKey($cmOrder->getOrderKey());
215-
if ($order->getPayment()->getMethod() === 'cm_payments_creditcard' && $cmPayment) {
222+
if (in_array($order->getPayment()->getMethod(), self::SHOULD_CANCEL_PAYMENT_METHODS) && $cmPayment) {
223+
foreach ($cmOrderDetails->getPayments() as $payment) {
224+
if ($payment->getAuthorization()->getState() === Authorization::STATE_AUTHORIZED) {
225+
return;
226+
}
227+
}
216228
foreach ($cmOrderDetails->getPayments() as $payment) {
217-
if ($payment->getAuthorization()->getState() !== Authorization::STATE_AUTHORIZED) {
229+
if ($payment->getAuthorization()->getState() === Authorization::STATE_CANCELED) {
218230
$order->setState(Order::STATE_CANCELED);
219231
$order->addCommentToStatusHistory(
220232
__('Order cancelled by CM, payment id %1', $payment->getId()),

Test/Integration/Service/OrderTransactionServiceTest.php

+122-8
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66

77
namespace CM\Payments\Test\Integration\Service;
88

9+
use CM\Payments\Api\Model\Data\PaymentInterfaceFactory;
910
use CM\Payments\Api\Model\PaymentRepositoryInterface;
1011
use CM\Payments\Client\Api\ApiClientInterface;
1112
use CM\Payments\Api\Service\OrderTransactionServiceInterface;
1213
use CM\Payments\Model\Data\Order;
14+
use CM\Payments\Model\OrderRepository;
1315
use CM\Payments\Service\OrderTransactionService;
1416
use CM\Payments\Test\Integration\IntegrationTestCase;
1517
use CM\Payments\Test\Mock\MockApiResponse;
@@ -55,13 +57,7 @@ protected function setUp(): void
5557

5658
$magentoOrder = $this->loadOrderById('100000001');
5759

58-
$cmOrder = $this->objectManager->create(Order::class);
59-
$cmOrder->setIncrementId('100000001')
60-
->setOrderId($magentoOrder->getEntityId())
61-
->setOrderKey('test123');
62-
63-
$cmOrderRepository = $this->objectManager->create(\CM\Payments\Model\OrderRepository::class);
64-
$cmOrderRepository->save($cmOrder);
60+
$this->createCmOrder($magentoOrder);
6561

6662
$magentoOrder = $this->loadOrderById('100000001');
6763
$this->adjustMagentoOrder($magentoOrder);
@@ -212,11 +208,100 @@ public function testIfCMPaymentIsCreatedInDatabase()
212208
$this->orderTransactionService->process('100000001');
213209

214210
$cmPaymentRepository = $this->objectManager->create(PaymentRepositoryInterface::class);
215-
216211
$cmPayment = $cmPaymentRepository->getByOrderKey('test123');
217212
$this->assertSame('pid4911203603t', $cmPayment->getPaymentId());
218213
}
219214

215+
/**
216+
* @magentoDataFixture Magento/Sales/_files/order.php
217+
*/
218+
public function testShouldCancelOrderWhenCreditCardDirectPaymentIsCanceled()
219+
{
220+
$this->clientMock
221+
->expects($this->once())->method('execute')
222+
->willReturn($this->mockApiResponse->getOrderDetailCanceledPayment());
223+
224+
$magentoOrder = $this->loadOrderById('100000001');
225+
$magentoOrder->getPayment()->setMethod('cm_payments_creditcard');
226+
$repository = $this->objectManager->get(OrderRepositoryInterface::class);
227+
$repository->save($magentoOrder);
228+
229+
$this->createCmOrder($magentoOrder);
230+
231+
$this->createCMPayment($magentoOrder);
232+
233+
$this->orderTransactionService->process('100000001');
234+
235+
$magentoOrder = $this->loadOrderById('100000001');
236+
$this->assertSame('canceled', $magentoOrder->getStatus());
237+
}
238+
239+
/**
240+
* @magentoDataFixture Magento/Sales/_files/order.php
241+
*/
242+
public function testShouldNotCancelOrderWhenCreditCardDirectPaymentIsRedirectedForAuthentication()
243+
{
244+
$this->clientMock
245+
->expects($this->once())->method('execute')
246+
->willReturn($this->mockApiResponse->getOrderDetailRedirectedForAuthenticationPayment());
247+
248+
$magentoOrder = $this->loadOrderById('100000001');
249+
$magentoOrder->getPayment()->setMethod('cm_payments_creditcard');
250+
$repository = $this->objectManager->get(OrderRepositoryInterface::class);
251+
$repository->save($magentoOrder);
252+
253+
$this->createCmOrder($magentoOrder);
254+
$this->createCMPayment($magentoOrder);
255+
256+
$this->orderTransactionService->process('100000001');
257+
258+
$magentoOrder = $this->loadOrderById('100000001');
259+
$this->assertSame('pending_payment', $magentoOrder->getStatus());
260+
}
261+
262+
/**
263+
* @magentoDataFixture Magento/Sales/_files/order.php
264+
*/
265+
public function testShouldNotCancelOrderWhenIdealPaymentIsCanceled()
266+
{
267+
$this->clientMock
268+
->expects($this->once())->method('execute')
269+
->willReturn($this->mockApiResponse->getOrderDetailCanceledPayment());
270+
271+
$magentoOrder = $this->loadOrderById('100000001');
272+
273+
$magentoOrder->getPayment()->setMethod('cm_payments_ideal');
274+
$repository = $this->objectManager->get(OrderRepositoryInterface::class);
275+
$repository->save($magentoOrder);
276+
277+
$this->createCmOrder($magentoOrder);
278+
$this->orderTransactionService->process('100000001');
279+
280+
$magentoOrder = $this->loadOrderById('100000001');
281+
$this->assertSame('pending_payment', $magentoOrder->getStatus());
282+
}
283+
284+
/**
285+
* @magentoDataFixture Magento/Sales/_files/order.php
286+
*/
287+
public function testShouldNotCancelOrderWhenCMPaymentNotExists()
288+
{
289+
$this->clientMock
290+
->expects($this->once())->method('execute')
291+
->willReturn($this->mockApiResponse->getOrderDetailCanceledPayment());
292+
293+
$magentoOrder = $this->loadOrderById('100000001');
294+
$magentoOrder->getPayment()->setMethod('cm_payments_ideal');
295+
$repository = $this->objectManager->get(OrderRepositoryInterface::class);
296+
$repository->save($magentoOrder);
297+
298+
$this->createCmOrder($magentoOrder);
299+
$this->orderTransactionService->process('100000001');
300+
301+
$magentoOrder = $this->loadOrderById('100000001');
302+
$this->assertSame('pending_payment', $magentoOrder->getStatus());
303+
}
304+
220305
/**
221306
* @param OrderInterface $magentoOrder
222307
* @return OrderInterface
@@ -234,4 +319,33 @@ private function adjustMagentoOrder(OrderInterface $magentoOrder): OrderInterfac
234319

235320
return $magentoOrder;
236321
}
322+
323+
/**
324+
* @param OrderInterface $magentoOrder
325+
*/
326+
private function createCmOrder(OrderInterface $magentoOrder): void
327+
{
328+
$cmOrder = $this->objectManager->create(Order::class);
329+
$cmOrder->setIncrementId('100000001')
330+
->setOrderId($magentoOrder->getEntityId())
331+
->setOrderKey('test123');
332+
333+
$cmOrderRepository = $this->objectManager->create(OrderRepository::class);
334+
$cmOrderRepository->save($cmOrder);
335+
}
336+
337+
/**
338+
* @param OrderInterface $magentoOrder
339+
*/
340+
private function createCMPayment(OrderInterface $magentoOrder): void
341+
{
342+
$cmPaymentRepository = $this->objectManager->create(PaymentRepositoryInterface::class);
343+
$cmPaymentDataFactory = $this->objectManager->create(PaymentInterfaceFactory::class);
344+
$cmPayment = $cmPaymentDataFactory->create();
345+
$cmPayment->setOrderId((int)$magentoOrder->getEntityId());
346+
$cmPayment->setOrderKey('test123');
347+
$cmPayment->setIncrementId($magentoOrder->getIncrementId());
348+
$cmPayment->setPaymentId('pid4911203603t');
349+
$cmPaymentRepository->save($cmPayment);
350+
}
237351
}

Test/Mock/MockApiResponse.php

+54
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,60 @@ public function getOrderDetail()
6464
];
6565
}
6666

67+
public function getOrderDetailCanceledPayment()
68+
{
69+
return [
70+
"order_reference" => "100000001",
71+
"description" => "Order 12345",
72+
"amount" => 50,
73+
"currency" => "USD",
74+
"email" => "[email protected]",
75+
"language" => "be",
76+
"country" => "NL",
77+
"profile" => "test",
78+
"timestamp" => "2021-07-01T11:59:49Z",
79+
"expires_on" => "2021-08-05T11:59:49Z",
80+
"payments" => [
81+
[
82+
"id" => "pid4911203603t",
83+
"method" => "IDEAL",
84+
"authorization" => [
85+
"amount" => 42,
86+
"currency" => "EUR",
87+
"state" => "CANCELED"
88+
]
89+
]
90+
]
91+
];
92+
}
93+
94+
public function getOrderDetailRedirectedForAuthenticationPayment()
95+
{
96+
return [
97+
"order_reference" => "100000001",
98+
"description" => "Order 12345",
99+
"amount" => 50,
100+
"currency" => "USD",
101+
"email" => "[email protected]",
102+
"language" => "be",
103+
"country" => "NL",
104+
"profile" => "test",
105+
"timestamp" => "2021-07-01T11:59:49Z",
106+
"expires_on" => "2021-08-05T11:59:49Z",
107+
"payments" => [
108+
[
109+
"id" => "pid4911203603t",
110+
"method" => "IDEAL",
111+
"authorization" => [
112+
"amount" => 42,
113+
"currency" => "EUR",
114+
"state" => "REDIRECTED_FOR_AUTHENTICATION"
115+
]
116+
]
117+
]
118+
];
119+
}
120+
67121
public function getOrderDetailMultiplePayments()
68122
{
69123
return [

0 commit comments

Comments
 (0)