order-management 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.config = void 0;
|
|
4
|
+
exports.default = sendOrderEmailHandler;
|
|
5
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
6
|
+
const resolve_options_1 = require("../utils/resolve-options");
|
|
7
|
+
const template_1 = require("../utils/template");
|
|
8
|
+
/**
|
|
9
|
+
* Prepare email payload for notification service
|
|
10
|
+
*/
|
|
11
|
+
function prepareEmailPayload(to, subject, htmlContent) {
|
|
12
|
+
// Create plain text version from HTML
|
|
13
|
+
const textContent = htmlContent
|
|
14
|
+
.replace(/<[^>]*>/g, '') // Remove HTML tags
|
|
15
|
+
.replace(/\s+/g, ' ') // Collapse whitespace
|
|
16
|
+
.trim();
|
|
17
|
+
const payload = {
|
|
18
|
+
to,
|
|
19
|
+
channel: "email",
|
|
20
|
+
subject,
|
|
21
|
+
// Root level fields for SMTP providers
|
|
22
|
+
html: htmlContent,
|
|
23
|
+
text: textContent,
|
|
24
|
+
body: htmlContent, // Some providers expect 'body' field
|
|
25
|
+
template: htmlContent, // Some providers expect 'template' field
|
|
26
|
+
data: {
|
|
27
|
+
subject,
|
|
28
|
+
html: htmlContent,
|
|
29
|
+
text: textContent,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
return payload;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Subscriber handler for order.placed event
|
|
36
|
+
* Sends email with order data when an order is placed (if template is configured)
|
|
37
|
+
*/
|
|
38
|
+
async function sendOrderEmailHandler({ event: { data }, container, }) {
|
|
39
|
+
try {
|
|
40
|
+
// Check if email template is configured
|
|
41
|
+
let templatePath = null;
|
|
42
|
+
try {
|
|
43
|
+
const configModule = container.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
|
|
44
|
+
const pluginOptions = (0, resolve_options_1.extractOrderManagementOptions)(configModule);
|
|
45
|
+
const options = (0, resolve_options_1.resolveOrderManagementOptions)(pluginOptions);
|
|
46
|
+
templatePath = options.email.template;
|
|
47
|
+
if (!templatePath) {
|
|
48
|
+
console.log("[Order Email Subscriber] Email template path not configured, skipping email");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
// If config resolution fails, skip email sending
|
|
54
|
+
console.debug("[Order Email Subscriber] Could not resolve config, skipping email");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Extract order ID from event data
|
|
58
|
+
const orderId = data.id;
|
|
59
|
+
if (!orderId) {
|
|
60
|
+
console.error("[Order Email Subscriber] No order ID found in event data");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Query order details if event only provides ID
|
|
64
|
+
// Check if data already has full order object
|
|
65
|
+
let orderData;
|
|
66
|
+
if (data.email && data.items) {
|
|
67
|
+
// Event already contains full order data
|
|
68
|
+
orderData = data;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// Query order details using query service
|
|
72
|
+
const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
73
|
+
const { data: orders = [] } = await query.graph({
|
|
74
|
+
entity: "order",
|
|
75
|
+
fields: [
|
|
76
|
+
"id",
|
|
77
|
+
"status",
|
|
78
|
+
"total",
|
|
79
|
+
"grand_total",
|
|
80
|
+
"email",
|
|
81
|
+
"created_at",
|
|
82
|
+
"updated_at",
|
|
83
|
+
"items.*",
|
|
84
|
+
"shipping_address.*",
|
|
85
|
+
"billing_address.*",
|
|
86
|
+
],
|
|
87
|
+
filters: { id: orderId },
|
|
88
|
+
});
|
|
89
|
+
const order = Array.isArray(orders) ? orders[0] : orders;
|
|
90
|
+
if (!order) {
|
|
91
|
+
console.error(`[Order Email Subscriber] Order with id ${orderId} not found`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
orderData = order;
|
|
95
|
+
}
|
|
96
|
+
// Extract email from order data
|
|
97
|
+
const email = orderData.email;
|
|
98
|
+
if (!email || typeof email !== "string" || !email.includes("@")) {
|
|
99
|
+
console.error(`[Order Email Subscriber] No valid email found for order ${orderId}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Prepare template data
|
|
103
|
+
const totalValue = orderData.total || orderData.grand_total;
|
|
104
|
+
const orderTotal = typeof totalValue === "number"
|
|
105
|
+
? totalValue
|
|
106
|
+
: typeof totalValue === "string"
|
|
107
|
+
? totalValue
|
|
108
|
+
: "N/A";
|
|
109
|
+
const templateData = {
|
|
110
|
+
order_id: orderData.id || "N/A",
|
|
111
|
+
order_status: orderData.status || "N/A",
|
|
112
|
+
order_total: orderTotal,
|
|
113
|
+
order_email: orderData.email || "N/A",
|
|
114
|
+
order_date: (orderData.created_at || orderData.updated_at || new Date().toISOString()),
|
|
115
|
+
order_items: orderData.items || [],
|
|
116
|
+
shipping_address: orderData.shipping_address || {},
|
|
117
|
+
billing_address: orderData.billing_address || {},
|
|
118
|
+
};
|
|
119
|
+
// Load and render template
|
|
120
|
+
const renderedTemplate = (0, template_1.loadAndRenderTemplate)(templatePath, templateData);
|
|
121
|
+
if (!renderedTemplate) {
|
|
122
|
+
console.error(`[Order Email Subscriber] Failed to load or render template from ${templatePath}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Resolve notification service
|
|
126
|
+
const notificationService = container.resolve(utils_1.Modules.NOTIFICATION);
|
|
127
|
+
if (!notificationService) {
|
|
128
|
+
console.error("[Order Email Subscriber] Notification service is not configured");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// Prepare email payload
|
|
132
|
+
const subject = "Order Confirmation";
|
|
133
|
+
const payload = prepareEmailPayload(email, subject, renderedTemplate);
|
|
134
|
+
// Send email
|
|
135
|
+
try {
|
|
136
|
+
if (typeof notificationService.createNotifications === "function") {
|
|
137
|
+
await notificationService.createNotifications([payload]);
|
|
138
|
+
console.log(`[Order Email Subscriber] Email sent successfully for order ${orderId}`);
|
|
139
|
+
}
|
|
140
|
+
else if (typeof notificationService.create === "function") {
|
|
141
|
+
await notificationService.create(payload);
|
|
142
|
+
console.log(`[Order Email Subscriber] Email sent successfully for order ${orderId}`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.error("[Order Email Subscriber] Notification service does not support sending notifications");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
150
|
+
console.error(`[Order Email Subscriber] Failed to send email for order ${orderId}:`, errorMessage);
|
|
151
|
+
// Don't throw - subscriber errors shouldn't break the order flow
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
156
|
+
console.error("[Order Email Subscriber] Error processing order email:", errorMessage);
|
|
157
|
+
// Don't throw - subscriber errors shouldn't break the order flow
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Subscriber configuration
|
|
162
|
+
*/
|
|
163
|
+
exports.config = {
|
|
164
|
+
event: "order.placed",
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC1vcmRlci1lbWFpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdWJzY3JpYmVycy9zZW5kLW9yZGVyLWVtYWlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQWdFQSx3Q0FnSkM7QUEvTUQscURBQThFO0FBRTlFLDhEQUdpQztBQUNqQyxnREFBaUY7QUFPakY7O0dBRUc7QUFDSCxTQUFTLG1CQUFtQixDQUMxQixFQUFVLEVBQ1YsT0FBZSxFQUNmLFdBQW1CO0lBRW5CLHNDQUFzQztJQUN0QyxNQUFNLFdBQVcsR0FBRyxXQUFXO1NBQzVCLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUMsbUJBQW1CO1NBQzNDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsc0JBQXNCO1NBQzNDLElBQUksRUFBRSxDQUFBO0lBRVQsTUFBTSxPQUFPLEdBYVQ7UUFDRixFQUFFO1FBQ0YsT0FBTyxFQUFFLE9BQU87UUFDaEIsT0FBTztRQUNQLHVDQUF1QztRQUN2QyxJQUFJLEVBQUUsV0FBVztRQUNqQixJQUFJLEVBQUUsV0FBVztRQUNqQixJQUFJLEVBQUUsV0FBVyxFQUFFLHFDQUFxQztRQUN4RCxRQUFRLEVBQUUsV0FBVyxFQUFFLHlDQUF5QztRQUNoRSxJQUFJLEVBQUU7WUFDSixPQUFPO1lBQ1AsSUFBSSxFQUFFLFdBQVc7WUFDakIsSUFBSSxFQUFFLFdBQVc7U0FDbEI7S0FDRixDQUFBO0lBRUQsT0FBTyxPQUFPLENBQUE7QUFDaEIsQ0FBQztBQUVEOzs7R0FHRztBQUNZLEtBQUssVUFBVSxxQkFBcUIsQ0FBQyxFQUNsRCxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFDZixTQUFTLEdBQzRCO0lBQ3JDLElBQUksQ0FBQztRQUNILHdDQUF3QztRQUN4QyxJQUFJLFlBQVksR0FBa0IsSUFBSSxDQUFBO1FBQ3RDLElBQUksQ0FBQztZQUNILE1BQU0sWUFBWSxHQUFHLFNBQVMsQ0FB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
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JkZXItbWFuYWdlbWVudC1vcHRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3R5cGVzL29yZGVyLW1hbmFnZW1lbnQtb3B0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveOrderManagementOptions = resolveOrderManagementOptions;
|
|
4
|
+
exports.extractOrderManagementOptions = extractOrderManagementOptions;
|
|
5
|
+
const DEFAULT_OPTIONS = {
|
|
6
|
+
email: {
|
|
7
|
+
template: null,
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Resolve and normalize plugin options with defaults
|
|
12
|
+
*/
|
|
13
|
+
function resolveOrderManagementOptions(options) {
|
|
14
|
+
if (!options) {
|
|
15
|
+
return DEFAULT_OPTIONS;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
email: {
|
|
19
|
+
template: options.email?.template ?? DEFAULT_OPTIONS.email.template,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Extract plugin options from config module
|
|
25
|
+
*/
|
|
26
|
+
function extractOrderManagementOptions(configModule) {
|
|
27
|
+
// Try from projectConfig.plugins first
|
|
28
|
+
const plugins = configModule?.projectConfig?.plugins ?? [];
|
|
29
|
+
for (const plugin of plugins) {
|
|
30
|
+
if (typeof plugin === "string") {
|
|
31
|
+
if (plugin === "order-management") {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (plugin?.resolve === "order-management") {
|
|
37
|
+
return plugin.options;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Try from direct config.plugins (fallback)
|
|
41
|
+
const directPlugins = configModule?.plugins ?? [];
|
|
42
|
+
for (const plugin of directPlugins) {
|
|
43
|
+
if (typeof plugin === "string") {
|
|
44
|
+
if (plugin === "order-management") {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (plugin?.resolve === "order-management") {
|
|
50
|
+
return plugin.options;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS1vcHRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Jlc29sdmUtb3B0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWlCQSxzRUFZQztBQUtELHNFQW9DQztBQTlERCxNQUFNLGVBQWUsR0FBbUM7SUFDdEQsS0FBSyxFQUFFO1FBQ0wsUUFBUSxFQUFFLElBQUk7S0FDZjtDQUNGLENBQUE7QUFFRDs7R0FFRztBQUNILFNBQWdCLDZCQUE2QixDQUMzQyxPQUE2QztJQUU3QyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixPQUFPLGVBQWUsQ0FBQTtJQUN4QixDQUFDO0lBRUQsT0FBTztRQUNMLEtBQUssRUFBRTtZQUNMLFFBQVEsRUFBRSxPQUFPLENBQUMsS0FBSyxFQUFFLFFBQVEsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLFFBQVE7U0FDcEU7S0FDRixDQUFBO0FBQ0gsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsNkJBQTZCLENBQzNDLFlBQWtCO0lBRWxCLHVDQUF1QztJQUN2QyxNQUFNLE9BQU8sR0FBRyxZQUFZLEVBQUUsYUFBYSxFQUFFLE9BQU8sSUFBSSxFQUFFLENBQUE7SUFFMUQsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUM3QixJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQy9CLElBQUksTUFBTSxLQUFLLGtCQUFrQixFQUFFLENBQUM7Z0JBQ2xDLE9BQU8sRUFBRSxDQUFBO1lBQ1gsQ0FBQztZQUNELFNBQVE7UUFDVixDQUFDO1FBRUQsSUFBSSxNQUFNLEVBQUUsT0FBTyxLQUFLLGtCQUFrQixFQUFFLENBQUM7WUFDM0MsT0FBTyxNQUFNLENBQUMsT0FBdUMsQ0FBQTtRQUN2RCxDQUFDO0lBQ0gsQ0FBQztJQUVELDRDQUE0QztJQUM1QyxNQUFNLGFBQWEsR0FBSSxZQUFvQixFQUFFLE9BQU8sSUFBSSxFQUFFLENBQUE7SUFFMUQsS0FBSyxNQUFNLE1BQU0sSUFBSSxhQUFhLEVBQUUsQ0FBQztRQUNuQyxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQy9CLElBQUksTUFBTSxLQUFLLGtCQUFrQixFQUFFLENBQUM7Z0JBQ2xDLE9BQU8sRUFBRSxDQUFBO1lBQ1gsQ0FBQztZQUNELFNBQVE7UUFDVixDQUFDO1FBRUQsSUFBSSxNQUFNLEVBQUUsT0FBTyxLQUFLLGtCQUFrQixFQUFFLENBQUM7WUFDM0MsT0FBTyxNQUFNLENBQUMsT0FBdUMsQ0FBQTtRQUN2RCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sU0FBUyxDQUFBO0FBQ2xCLENBQUMifQ==
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadAndRenderTemplate = loadAndRenderTemplate;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
/**
|
|
40
|
+
* Load and render template from file path
|
|
41
|
+
* Supports HTML templates for email notifications
|
|
42
|
+
*/
|
|
43
|
+
function loadAndRenderTemplate(templatePath, data) {
|
|
44
|
+
try {
|
|
45
|
+
// Use the exact path provided (can be relative or absolute)
|
|
46
|
+
const fullPath = path.isAbsolute(templatePath)
|
|
47
|
+
? templatePath
|
|
48
|
+
: path.join(process.cwd(), templatePath);
|
|
49
|
+
if (!fs.existsSync(fullPath)) {
|
|
50
|
+
throw new Error(`Template file not found: ${fullPath}`);
|
|
51
|
+
}
|
|
52
|
+
let templateContent = fs.readFileSync(fullPath, "utf-8");
|
|
53
|
+
// Replace template variables {{variable_name}} with actual values
|
|
54
|
+
Object.keys(data).forEach((key) => {
|
|
55
|
+
const value = data[key];
|
|
56
|
+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
57
|
+
if (value !== null && value !== undefined) {
|
|
58
|
+
if (typeof value === "object") {
|
|
59
|
+
templateContent = templateContent.replace(regex, JSON.stringify(value));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
templateContent = templateContent.replace(regex, String(value));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
templateContent = templateContent.replace(regex, "");
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// Clean up any remaining placeholders
|
|
70
|
+
templateContent = templateContent.replace(/\{\{[\w]+\}\}/g, "");
|
|
71
|
+
return templateContent;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error(`[order-management] Failed to load template from ${templatePath}:`, error);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVtcGxhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvdGVtcGxhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFtQkEsc0RBMkNDO0FBOURELHVDQUF3QjtBQUN4QiwyQ0FBNEI7QUFjNUI7OztHQUdHO0FBQ0gsU0FBZ0IscUJBQXFCLENBQ25DLFlBQW9CLEVBQ3BCLElBQXVCO0lBRXZCLElBQUksQ0FBQztRQUNILDREQUE0RDtRQUM1RCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQztZQUM1QyxDQUFDLENBQUMsWUFBWTtZQUNkLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxZQUFZLENBQUMsQ0FBQTtRQUUxQyxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsNEJBQTRCLFFBQVEsRUFBRSxDQUFDLENBQUE7UUFDekQsQ0FBQztRQUVELElBQUksZUFBZSxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBRXhELGtFQUFrRTtRQUNsRSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQ2hDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUE4QixDQUFDLENBQUE7WUFDbEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxNQUFNLENBQUMsU0FBUyxHQUFHLFFBQVEsRUFBRSxHQUFHLENBQUMsQ0FBQTtZQUVuRCxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUMxQyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO29CQUM5QixlQUFlLEdBQUcsZUFBZSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO2dCQUN6RSxDQUFDO3FCQUFNLENBQUM7b0JBQ04sZUFBZSxHQUFHLGVBQWUsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO2dCQUNqRSxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLGVBQWUsR0FBRyxlQUFlLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQTtZQUN0RCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUE7UUFFRixzQ0FBc0M7UUFDdEMsZUFBZSxHQUFHLGVBQWUsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFFL0QsT0FBTyxlQUFlLENBQUE7SUFDeEIsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixPQUFPLENBQUMsS0FBSyxDQUNYLG1EQUFtRCxZQUFZLEdBQUcsRUFDbEUsS0FBSyxDQUNOLENBQUE7UUFDRCxPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7QUFDSCxDQUFDIn0=
|
package/README.md
CHANGED
|
@@ -36,6 +36,105 @@
|
|
|
36
36
|
|
|
37
37
|
This starter is compatible with versions >= 2.4.0 of `@medusajs/medusa`.
|
|
38
38
|
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **Order Management**: Cancel and reorder functionality for orders
|
|
42
|
+
- **Order Confirmation Emails**: Automatically sends email notifications when orders are placed (requires template configuration)
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
The plugin can be configured in your `medusa-config.js` file:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
module.exports = defineConfig({
|
|
50
|
+
// ...
|
|
51
|
+
plugins: [
|
|
52
|
+
{
|
|
53
|
+
resolve: "order-management",
|
|
54
|
+
options: {
|
|
55
|
+
email: {
|
|
56
|
+
template: "src/templates/emails/order-confirmation.html", // Path to HTML template file
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Configuration Options
|
|
65
|
+
|
|
66
|
+
| Option | Type | Default | Description |
|
|
67
|
+
|--------|------|---------|-------------|
|
|
68
|
+
| `email.template` | `string \| null` | `null` | Path to HTML template file for order confirmation emails (relative to project root or absolute path) |
|
|
69
|
+
|
|
70
|
+
**Note**: Order confirmation emails are only sent if a template path is provided. If no template is configured, emails will not be sent.
|
|
71
|
+
|
|
72
|
+
## Email Templates
|
|
73
|
+
|
|
74
|
+
The plugin supports custom HTML templates for order confirmation emails. Templates use variable replacement with `{{variable_name}}` syntax.
|
|
75
|
+
|
|
76
|
+
### Creating Templates
|
|
77
|
+
|
|
78
|
+
Create HTML template files for email notifications. Place them in your project, for example:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
your-project/
|
|
82
|
+
src/
|
|
83
|
+
templates/
|
|
84
|
+
emails/
|
|
85
|
+
order-confirmation.html
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Example Email Template** (`src/templates/emails/order-confirmation.html`):
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<!DOCTYPE html>
|
|
92
|
+
<html>
|
|
93
|
+
<head>
|
|
94
|
+
<meta charset="UTF-8">
|
|
95
|
+
<style>
|
|
96
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
|
|
97
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
98
|
+
.header { background-color: #4CAF50; color: white; padding: 20px; text-align: center; }
|
|
99
|
+
.content { padding: 20px; background-color: #ffffff; }
|
|
100
|
+
.order-info { background-color: #f5f5f5; padding: 15px; margin: 15px 0; border-radius: 5px; }
|
|
101
|
+
</style>
|
|
102
|
+
</head>
|
|
103
|
+
<body>
|
|
104
|
+
<div class="container">
|
|
105
|
+
<div class="header">
|
|
106
|
+
<h1>Order Confirmation</h1>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="content">
|
|
109
|
+
<div class="order-info">
|
|
110
|
+
<p><strong>Order ID:</strong> {{order_id}}</p>
|
|
111
|
+
<p><strong>Status:</strong> {{order_status}}</p>
|
|
112
|
+
<p><strong>Total:</strong> {{order_total}}</p>
|
|
113
|
+
<p><strong>Email:</strong> {{order_email}}</p>
|
|
114
|
+
<p><strong>Date:</strong> {{order_date}}</p>
|
|
115
|
+
</div>
|
|
116
|
+
<p>Thank you for your order!</p>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</body>
|
|
120
|
+
</html>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Template Variables
|
|
124
|
+
|
|
125
|
+
The following variables are available in order confirmation email templates:
|
|
126
|
+
|
|
127
|
+
| Variable | Description | Example |
|
|
128
|
+
|----------|-------------|---------|
|
|
129
|
+
| `{{order_id}}` | Order ID | `order_123` |
|
|
130
|
+
| `{{order_status}}` | Order status | `pending` |
|
|
131
|
+
| `{{order_total}}` | Order total amount | `99.99` |
|
|
132
|
+
| `{{order_email}}` | Customer email address | `customer@example.com` |
|
|
133
|
+
| `{{order_date}}` | Order creation date | `2024-01-15T10:30:00Z` |
|
|
134
|
+
| `{{order_items}}` | Order items array (JSON stringified) | `[{"title":"Product","quantity":1}]` |
|
|
135
|
+
| `{{shipping_address}}` | Shipping address object (JSON stringified) | `{"first_name":"John",...}` |
|
|
136
|
+
| `{{billing_address}}` | Billing address object (JSON stringified) | `{"first_name":"John",...}` |
|
|
137
|
+
|
|
39
138
|
## Getting Started
|
|
40
139
|
|
|
41
140
|
Visit the [Quickstart Guide](https://docs.medusajs.com/learn/installation) to set up a server.
|