Skip to content

Commit 8833576

Browse files
committed
AC-13757: Order cancellation reason validation
1 parent 45cc4db commit 8833576

File tree

8 files changed

+238
-25
lines changed

8 files changed

+238
-25
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*
6+
* NOTICE: All information contained herein is, and remains
7+
* the property of Adobe and its suppliers, if any. The intellectual
8+
* and technical concepts contained herein are proprietary to Adobe
9+
* and its suppliers and are protected by all applicable intellectual
10+
* property laws, including trade secret and copyright laws.
11+
* Dissemination of this information or reproduction of this material
12+
* is strictly forbidden unless prior written permission is obtained
13+
* from Adobe.
14+
*/
15+
declare(strict_types=1);
16+
17+
namespace Magento\OrderCancellationGraphQl\Model\Validator;
18+
19+
use Magento\OrderCancellation\Model\Config\Config;
20+
use Magento\Sales\Model\Order;
21+
22+
/**
23+
* Validate cancellation reason of order
24+
*/
25+
class ValidateOrderCancellationReason
26+
{
27+
/**
28+
* @var Config $config
29+
*/
30+
private Config $config;
31+
32+
/**
33+
* ValidateOrderCancellationReason Constructor
34+
*
35+
* @param Config $config
36+
*/
37+
public function __construct(
38+
Config $config
39+
) {
40+
$this->config = $config;
41+
}
42+
43+
/**
44+
* Validate cancellation reason
45+
*
46+
* @param Order $order
47+
* @param string $reason
48+
* @return bool
49+
*/
50+
public function validateReason(
51+
Order $order,
52+
string $reason
53+
): bool {
54+
$cancellationReasons = array_map(
55+
'strtolower',
56+
$this->config->getCancellationReasons($order->getStore())
57+
);
58+
59+
return !in_array(strtolower(trim($reason)), $cancellationReasons);
60+
}
61+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*
6+
* NOTICE: All information contained herein is, and remains
7+
* the property of Adobe and its suppliers, if any. The intellectual
8+
* and technical concepts contained herein are proprietary to Adobe
9+
* and its suppliers and are protected by all applicable intellectual
10+
* property laws, including trade secret and copyright laws.
11+
* Dissemination of this information or reproduction of this material
12+
* is strictly forbidden unless prior written permission is obtained
13+
* from Adobe.
14+
*/
15+
declare(strict_types=1);
16+
17+
namespace Magento\OrderCancellationGraphQl\Plugin\Model;
18+
19+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
20+
use Magento\OrderCancellationGraphQl\Model\Validator\ValidateOrderCancellationReason;
21+
use Magento\Sales\Model\Order;
22+
use Magento\OrderCancellation\Model\CancelOrder as Subject;
23+
24+
/**
25+
* Plugin for cancel order model
26+
*/
27+
class CancelOrder
28+
{
29+
/**
30+
* @var ValidateOrderCancellationReason $validateOrderCancellationReason
31+
*/
32+
private ValidateOrderCancellationReason $validateOrderCancellationReason;
33+
34+
/**
35+
* @param ValidateOrderCancellationReason $validateOrderCancellationReason
36+
*/
37+
public function __construct(
38+
ValidateOrderCancellationReason $validateOrderCancellationReason
39+
) {
40+
$this->validateOrderCancellationReason = $validateOrderCancellationReason;
41+
}
42+
43+
/**
44+
* Before plugin for reason validation
45+
*
46+
* @param Subject $subject
47+
* @param Order $order
48+
* @param string $reason
49+
* @return array
50+
* @throws GraphQlInputException
51+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
52+
*/
53+
public function beforeExecute(
54+
Subject $subject,
55+
Order $order,
56+
string $reason
57+
) {
58+
if (!empty($reason)) {
59+
if ($this->validateOrderCancellationReason->validateReason($order, $reason)) {
60+
throw new GraphQlInputException(__('Order cancellation reason is invalid.'));
61+
}
62+
}
63+
64+
return [$order, $reason];
65+
}
66+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*
6+
* NOTICE: All information contained herein is, and remains
7+
* the property of Adobe and its suppliers, if any. The intellectual
8+
* and technical concepts contained herein are proprietary to Adobe
9+
* and its suppliers and are protected by all applicable intellectual
10+
* property laws, including trade secret and copyright laws.
11+
* Dissemination of this information or reproduction of this material
12+
* is strictly forbidden unless prior written permission is obtained
13+
* from Adobe.
14+
*/
15+
declare(strict_types=1);
16+
17+
namespace Magento\OrderCancellationGraphQl\Plugin\Model;
18+
19+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
20+
use Magento\OrderCancellationGraphQl\Model\Validator\ValidateOrderCancellationReason;
21+
use Magento\Sales\Model\Order;
22+
use Magento\OrderCancellationGraphQl\Model\CancelOrderGuest as Subject;
23+
24+
/**
25+
* Plugin for guest cancel order model
26+
*/
27+
class CancelOrderGuest
28+
{
29+
/**
30+
* @var ValidateOrderCancellationReason $validateOrderCancellationReason
31+
*/
32+
private ValidateOrderCancellationReason $validateOrderCancellationReason;
33+
34+
/**
35+
* @param ValidateOrderCancellationReason $validateOrderCancellationReason
36+
*/
37+
public function __construct(
38+
ValidateOrderCancellationReason $validateOrderCancellationReason
39+
) {
40+
$this->validateOrderCancellationReason = $validateOrderCancellationReason;
41+
}
42+
43+
/**
44+
* Before plugin for reason validation
45+
*
46+
* @param Subject $subject
47+
* @param Order $order
48+
* @param array $input
49+
* @return array
50+
* @throws GraphQlInputException
51+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
52+
*/
53+
public function beforeExecute(
54+
Subject $subject,
55+
Order $order,
56+
array $input
57+
) {
58+
if (!empty($input['reason'])) {
59+
if ($this->validateOrderCancellationReason->validateReason($order, $input['reason'])) {
60+
throw new GraphQlInputException(__('Order cancellation reason is invalid.'));
61+
}
62+
}
63+
64+
return [$order, $input];
65+
}
66+
}

app/code/Magento/OrderCancellationGraphQl/etc/graphql/di.xml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
615
*/
716
-->
817
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
@@ -34,4 +43,10 @@
3443
</argument>
3544
</arguments>
3645
</type>
46+
<type name="Magento\OrderCancellation\Model\CancelOrder">
47+
<plugin name="validateCancelOrderReason" type="Magento\OrderCancellationGraphQl\Plugin\Model\CancelOrder"/>
48+
</type>
49+
<type name="Magento\OrderCancellationGraphQl\Model\CancelOrderGuest">
50+
<plugin name="validateCancelGuestOrderReason" type="Magento\OrderCancellationGraphQl\Plugin\Model\CancelOrderGuest"/>
51+
</type>
3752
</config>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
"Confirm Your %store_name Order Cancellation","Confirm Your %store_name Order Cancellation"
22
"It seems that you'd like to cancel your order #%order_id. If this is correct, please <a href=""%url_to_confirm"">click here</a> to confirm your cancellation request.","It seems that you'd like to cancel your order #%order_id. If this is correct, please <a href=""%url_to_confirm"">click here</a> to confirm your cancellation request."
3+
"Order cancellation reason is invalid.","Order cancellation reason is invalid."
34

dev/tests/api-functional/testsuite/Magento/GraphQl/OrderCancellation/CancelGuestOrderTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function testAttemptToCancelOrderWhenMissingToken()
7777
mutation {
7878
requestGuestOrderCancel(
7979
input: {
80-
reason: "Cancel sample reason"
80+
reason: "Other"
8181
}
8282
){
8383
error
@@ -127,7 +127,7 @@ public function testAttemptToCancelOrderWithInvalidToken()
127127
requestGuestOrderCancel(
128128
input: {
129129
token: "TestToken"
130-
reason: "Cancel sample reason"
130+
reason: "Other"
131131
}
132132
){
133133
error
@@ -451,7 +451,7 @@ private function getMutation(OrderInterface $order): string
451451
requestGuestOrderCancel(
452452
input: {
453453
token: "{$this->getOrderToken($order)}",
454-
reason: "Sample reason"
454+
reason: "Other"
455455
}
456456
){
457457
errorV2 {

dev/tests/api-functional/testsuite/Magento/GraphQl/OrderCancellation/CancelOrderTest.php

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*
6+
* NOTICE: All information contained herein is, and remains
7+
* the property of Adobe and its suppliers, if any. The intellectual
8+
* and technical concepts contained herein are proprietary to Adobe
9+
* and its suppliers and are protected by all applicable intellectual
10+
* property laws, including trade secret and copyright laws.
11+
* Dissemination of this information or reproduction of this material
12+
* is strictly forbidden unless prior written permission is obtained
13+
* from Adobe.
514
*/
615
declare(strict_types=1);
716

@@ -186,7 +195,7 @@ public function testAttemptToCancelOrderWhenMissingOrderId()
186195
mutation {
187196
cancelOrder(
188197
input: {
189-
reason: "Cancel sample reason"
198+
reason: "Other"
190199
}
191200
){
192201
error
@@ -224,7 +233,7 @@ public function testAttemptToCancelNonExistingOrder()
224233
cancelOrder(
225234
input: {
226235
order_id: 99999999,
227-
reason: "Cancel sample reason"
236+
reason: "Other"
228237
}
229238
){
230239
error
@@ -622,7 +631,7 @@ public function testCancelOrderWithOutAnyAmountPaid()
622631
$this->assertEquals("Order cancellation notification email was sent.", $comment->getComment());
623632

624633
$comment = array_pop($comments);
625-
$this->assertEquals('Cancel sample reason', $comment->getComment());
634+
$this->assertEquals('Other', $comment->getComment());
626635
$this->assertEquals('canceled', $comment->getStatus());
627636
}
628637

@@ -672,7 +681,7 @@ public function testCancelOrderWithOfflinePaymentFullyInvoiced()
672681
$this->assertEquals("Order cancellation notification email was sent.", $comment->getComment());
673682

674683
$comment = array_pop($comments);
675-
$this->assertEquals('Cancel sample reason', $comment->getComment());
684+
$this->assertEquals('Other', $comment->getComment());
676685
$this->assertEquals('closed', $comment->getStatus());
677686
}
678687

@@ -758,7 +767,7 @@ public function testCancelOrderWithOfflinePaymentFullyInvoicedPartiallyRefunded(
758767
$this->assertEquals("Order cancellation notification email was sent.", $comment->getComment());
759768

760769
$comment = array_pop($comments);
761-
$this->assertEquals('Cancel sample reason', $comment->getComment());
770+
$this->assertEquals('Other', $comment->getComment());
762771
$this->assertEquals('closed', $comment->getStatus());
763772
}
764773

@@ -806,19 +815,14 @@ public function testCancelOrderAttemptingXSSPassedThroughReasonField()
806815
[
807816
'cancelOrder' =>
808817
[
809-
'errorV2' => null,
810-
'order' => [
811-
'status' => 'Closed'
812-
]
818+
'errorV2' => [
819+
'message' => 'Order cancellation reason is invalid.'
820+
],
821+
'order' => null
813822
]
814823
],
815824
$response
816825
);
817-
818-
$comments = $order->getStatusHistories();
819-
$comment = reset($comments);
820-
$this->assertEquals('&lt;script&gt;while(true){alert(666);}&lt;/script&gt;', $comment->getComment());
821-
$this->assertEquals('closed', $comment->getStatus());
822826
}
823827

824828
#[
@@ -889,7 +893,7 @@ public function testCancelPartiallyInvoicedOrder()
889893
$this->assertEquals("Order cancellation notification email was sent.", $comment->getComment());
890894

891895
$comment = array_pop($comments);
892-
$this->assertEquals('Cancel sample reason', $comment->getComment());
896+
$this->assertEquals('Other', $comment->getComment());
893897
$this->assertEquals('canceled', $comment->getStatus());
894898
}
895899

@@ -906,7 +910,7 @@ private function getCancelOrderMutation(int $orderId): string
906910
cancelOrder(
907911
input: {
908912
order_id: "{$orderId}"
909-
reason: "Cancel sample reason"
913+
reason: "Other"
910914
}
911915
){
912916
errorV2 {

dev/tests/api-functional/testsuite/Magento/GraphQl/OrderCancellation/ConfirmCancelGuestOrderTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ public function testAttemptToConfirmCancelOrderWithInvalidConfirmationKey()
423423
* @var $order OrderInterface
424424
*/
425425
$order = DataFixtureStorageManager::getStorage()->get('order');
426-
$this->confirmationKey->execute($order, 'Simple reason');
426+
$this->confirmationKey->execute($order, 'Other');
427427

428428
$query = $this->getConfirmCancelOrderMutation($order);
429429
$this->assertEquals(
@@ -459,7 +459,7 @@ public function testConfirmCancelOrderWithOutAnyAmountPaid()
459459
* @var $order OrderInterface
460460
*/
461461
$order = DataFixtureStorageManager::getStorage()->get('order');
462-
$confirmationKey = $this->confirmationKey->execute($order, 'Cancel sample reason');
462+
$confirmationKey = $this->confirmationKey->execute($order, 'Other');
463463

464464
$query = <<<MUTATION
465465
mutation {

0 commit comments

Comments
 (0)