Skip to content

Commit 4d60033

Browse files
authored
LYNX-505 - Allow guest to cancel order via GraphQL
1 parent 6c45e1a commit 4d60033

File tree

21 files changed

+2034
-92
lines changed

21 files changed

+2034
-92
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
/**
3+
* Copyright 2024 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\OrderCancellation\Model\Email;
18+
19+
use Magento\Framework\App\Area;
20+
use Magento\Framework\Escaper;
21+
use Magento\Framework\Exception\LocalizedException;
22+
use Magento\Framework\Exception\MailException;
23+
use Magento\Framework\Mail\Template\TransportBuilder;
24+
use Magento\Framework\UrlInterface;
25+
use Magento\Sales\Model\Order;
26+
use Magento\Sales\Model\Order\Email\Container\OrderIdentity;
27+
28+
/**
29+
* To send order return confirmation key related email
30+
*/
31+
class ConfirmationKeySender
32+
{
33+
/**
34+
* Email template id
35+
*/
36+
private const TEMPLATE_ID = 'sales_cancellation_confirm_guest';
37+
38+
/**
39+
* Order view page
40+
*/
41+
private const ORDER_VIEW_PATH = 'sales/guest/view';
42+
43+
/**
44+
* ConfirmationKeySender constructor
45+
*
46+
* @param TransportBuilder $transportBuilder
47+
* @param Escaper $escaper
48+
* @param OrderIdentity $orderIdentity
49+
* @param UrlInterface $url
50+
*/
51+
public function __construct(
52+
private readonly TransportBuilder $transportBuilder,
53+
private readonly Escaper $escaper,
54+
private readonly OrderIdentity $orderIdentity,
55+
private readonly UrlInterface $url
56+
) {
57+
}
58+
59+
/**
60+
* Send email to guest user with confirmation key.
61+
*
62+
* @param Order $order
63+
* @param string $confirmationKey
64+
* @return void
65+
* @throws LocalizedException
66+
*/
67+
public function execute(
68+
Order $order,
69+
string $confirmationKey,
70+
):void {
71+
try {
72+
$storeId = (int)$order->getStoreId();
73+
$guestOrderUrl = $this->url->getUrl(
74+
self::ORDER_VIEW_PATH,
75+
[
76+
'_query' => [
77+
'confirmation_key' => $confirmationKey,
78+
'order_id' => $order->getIncrementId()
79+
]
80+
]
81+
);
82+
$templateParams = [
83+
'customer_name' => $order->getCustomerName(),
84+
'order_id' => $order->getIncrementId(),
85+
'guest_order_url' => $guestOrderUrl,
86+
'escaper' => $this->escaper,
87+
];
88+
89+
$this->transportBuilder
90+
->setTemplateIdentifier(self::TEMPLATE_ID)
91+
->setTemplateOptions(['area' => Area::AREA_FRONTEND, 'store' => $storeId])
92+
->setTemplateVars($templateParams)
93+
->setFromByScope($this->orderIdentity->getEmailIdentity(), $storeId)
94+
->addTo($order->getCustomerEmail(), $order->getCustomerName())
95+
->getTransport()
96+
->sendMessage();
97+
} catch (MailException $e) {
98+
throw new LocalizedException(__('Email sending failed: %1', $e->getMessage()));
99+
}
100+
}
101+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/**
3+
* Copyright 2024 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\OrderCancellation\Model;
18+
19+
use Magento\Framework\Exception\LocalizedException;
20+
use Magento\Framework\Math\Random;
21+
use Magento\OrderCancellation\Model\ResourceModel\SalesOrderConfirmCancel
22+
as SalesOrderConfirmCancelResourceModel;
23+
use Magento\Sales\Model\Order;
24+
25+
class GetConfirmationKey
26+
{
27+
/**
28+
* Length for confirmation key
29+
*/
30+
public const CONFIRMATION_KEY_LENGTH = 32;
31+
32+
/**
33+
* GetConfirmationKey Constructor
34+
*
35+
* @param SalesOrderConfirmCancelResourceModel $confirmationKeyResourceModel
36+
* @param Random $mathRandom
37+
*/
38+
public function __construct(
39+
private readonly SalesOrderConfirmCancelResourceModel $confirmationKeyResourceModel,
40+
private readonly Random $mathRandom,
41+
) {
42+
}
43+
44+
/**
45+
* Returns confirmation key if exists, generates a new one otherwise
46+
*
47+
* @param Order $order
48+
* @param string $reason
49+
* @return string
50+
* @throws LocalizedException
51+
*/
52+
public function execute(Order $order, string $reason): string
53+
{
54+
$confirmationKey = $this->confirmationKeyResourceModel->get((int)$order->getId());
55+
56+
if (!$confirmationKey) {
57+
$confirmationKey['confirmation_key'] = $this->generateRandom();
58+
59+
$this->confirmationKeyResourceModel->insert(
60+
(int)$order->getId(),
61+
$confirmationKey['confirmation_key'],
62+
$reason
63+
);
64+
}
65+
66+
return $confirmationKey['confirmation_key'];
67+
}
68+
69+
/**
70+
* Generates a random string
71+
*
72+
* @return string
73+
* @throws LocalizedException
74+
*/
75+
private function generateRandom(): string
76+
{
77+
return $this->mathRandom->getRandomString(self::CONFIRMATION_KEY_LENGTH);
78+
}
79+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
/**
3+
* Copyright 2024 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\OrderCancellation\Model\ResourceModel;
18+
19+
use Magento\Framework\App\ResourceConnection;
20+
21+
/**
22+
* Sales order cancel confirmation resource model.
23+
*/
24+
class SalesOrderConfirmCancel
25+
{
26+
/**
27+
* Sales order cancellation table to store confirmation key and reason for guest order
28+
*/
29+
private const TABLE_NAME = 'sales_order_confirm_cancel';
30+
31+
/**
32+
* SalesOrderConfirmCancel Constructor
33+
*
34+
* @param ResourceConnection $resourceConnection
35+
*/
36+
public function __construct(
37+
private readonly ResourceConnection $resourceConnection
38+
) {
39+
}
40+
41+
/**
42+
* Fetch row from table if entry exists against the order
43+
*
44+
* @param int $orderId
45+
* @return array|null
46+
*/
47+
public function get(int $orderId): ?array
48+
{
49+
$connection = $this->resourceConnection->getConnection();
50+
return $connection->fetchRow(
51+
$connection->select()->from(
52+
self::TABLE_NAME
53+
)->where(
54+
'order_id = ?',
55+
$orderId
56+
)
57+
) ?: [];
58+
}
59+
60+
/**
61+
* Insert confirmation key & cancellation reason against an order into the table
62+
*
63+
* @param int $orderId
64+
* @param string $confirmationKey
65+
* @param string $reason
66+
* @return void
67+
*/
68+
public function insert(int $orderId, string $confirmationKey, string $reason): void
69+
{
70+
$connection = $this->resourceConnection->getConnection();
71+
$connection->insertOnDuplicate(
72+
self::TABLE_NAME,
73+
[
74+
'order_id' => $orderId,
75+
'confirmation_key' => $confirmationKey,
76+
'reason' => $reason
77+
],
78+
['confirmation_key', 'reason']
79+
);
80+
}
81+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright 2024 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.
15+
*/
16+
-->
17+
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18+
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
19+
<table name="sales_order_confirm_cancel" resource="default" engine="innodb" comment="Save the confirmation key to cancel guest order">
20+
<column xsi:type="int" name="order_id" unsigned="true" nullable="false" identity="false"
21+
comment="Order ID"/>
22+
<column xsi:type="varchar" name="confirmation_key" nullable="false" length="32"
23+
comment="Random key"/>
24+
<column xsi:type="varchar" name="reason" nullable="false"
25+
comment="Cancellation reason"/>
26+
<column xsi:type="datetime" name="created_at" on_update="false" nullable="false" default="CURRENT_TIMESTAMP" comment="created at"/>
27+
<constraint xsi:type="primary" referenceId="PRIMARY">
28+
<column name="order_id"/>
29+
</constraint>
30+
<constraint xsi:type="foreign" referenceId="SALES_ORDER_CONFIRM_CANCEL_ORDER_ID_SALES_ORDER_ENTITY_ID"
31+
table="sales_order_confirm_cancel" column="order_id"
32+
referenceTable="sales_order" referenceColumn="entity_id" onDelete="CASCADE" />
33+
</table>
34+
</schema>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"sales_order_confirm_cancel": {
3+
"column": {
4+
"order_id": true,
5+
"confirmation_key": true,
6+
"reason": true,
7+
"created_at": true
8+
},
9+
"constraint": {
10+
"PRIMARY": true,
11+
"SALES_ORDER_CONFIRM_CANCEL_ORDER_ID_SALES_ORDER_ENTITY_ID": true
12+
}
13+
}
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright 2024 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.
15+
*/
16+
-->
17+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">
18+
<template id="sales_cancellation_confirm_guest" label="Cancellation key email for guest order" file="confirmation_key.html" type="html" module="Magento_OrderCancellation" area="frontend"/>
19+
</config>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<!--
2+
/**
3+
* Copyright 2024 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+
-->
16+
<!--@subject {{trans "Confirm Your %store_name Order Cancellation" store_name=$store.frontend_name}} @-->
17+
<!--@vars {
18+
"var customer_name":"Guest Customer Name",
19+
"var order_id":"Order Id",
20+
"var guest_order_url":"Guest order cancel confirm URL",
21+
"var store.frontend_name":"Store Frontend Name",
22+
"var store_email":"Store Email",
23+
"var store_phone":"Store Phone",
24+
"var store_hours":"Store Hours"
25+
} @-->
26+
{{template config_path="design/email/header_template"}}
27+
28+
<table>
29+
<tr class="email-intro">
30+
<td>
31+
<p class="greeting">{{trans "%name," name=$customer_name}}</p>
32+
<p>
33+
{{trans 'It seems that you'd like to cancel your order #%order_id. If this is correct, please <a href="%guest_order_url" target="_blank">click here</a> to confirm your cancellation request.'
34+
order_id=$order_id
35+
guest_order_url=$guest_order_url
36+
|raw}}
37+
</p>
38+
<p>
39+
{{trans 'If you have questions about your order, you can email us at <a href="mailto:%store_email">%store_email</a>' store_email=$store_email |raw}}{{depend store_phone}} {{trans 'or call us at <a href="tel:%store_phone">%store_phone</a>' store_phone=$store_phone |raw}}{{/depend}}.
40+
{{depend store_hours}}
41+
{{trans 'Our hours are <span class="no-link">%store_hours</span>.' store_hours=$store_hours |raw}}
42+
{{/depend}}
43+
</p>
44+
</td>
45+
</tr>
46+
</table>
47+
48+
{{template config_path="design/email/footer_template"}}

0 commit comments

Comments
 (0)