@kb0912/notification-brevo 0.0.1 → 1.0.1
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.
- package/.medusa/server/src/config.js +13 -0
- package/.medusa/server/src/jobs/abandoned-cart.js +3 -8
- package/.medusa/server/src/loaders/brevo.js +13 -0
- package/.medusa/server/src/providers/notifications-brevo/index.js +17 -4
- package/.medusa/server/src/providers/notifications-brevo/services.js +35 -24
- package/.medusa/server/src/providers/notifications-brevo/types/index.js +3 -0
- package/.medusa/server/src/subscribers/customer-created.js +4 -17
- package/.medusa/server/src/subscribers/shipment-created.js +17 -0
- package/.medusa/server/src/workflows/send-abandoned-cart.js +3 -3
- package/.medusa/server/src/workflows/send-order-confirmation.js +13 -69
- package/.medusa/server/src/workflows/steps/check-abandoned-carts.js +36 -31
- package/.medusa/server/src/workflows/steps/send-notification.js +1 -1
- package/README.md +95 -63
- package/package.json +3 -3
- package/.medusa/server/src/loaders/abandoned-cart.js +0 -8
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.abandonedCartConfig = void 0;
|
|
4
|
+
exports.abandonedCartConfig = {
|
|
5
|
+
abandoned_carts: process.env.ENABLE_ABANDONED_CARTS === "true" || false,
|
|
6
|
+
checks: [
|
|
7
|
+
{ delay: process.env.BREVO_CART_FIRST_DELAY || 24 },
|
|
8
|
+
{ delay: process.env.BREVO_CART_SECOND_DELAY },
|
|
9
|
+
{ delay: process.env.BREVO_CART_THIRD_DELAY },
|
|
10
|
+
].filter((check) => // Type guard để ép kiểu
|
|
11
|
+
check.delay !== undefined && check.delay !== null && check.delay !== ""),
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFLZSxRQUFBLG1CQUFtQixHQUFHO0lBQ2pDLGVBQWUsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLHNCQUFzQixLQUFLLE1BQU0sSUFBSSxLQUFLO0lBQ3ZFLE1BQU0sRUFBRTtRQUNOLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLElBQUksRUFBRSxFQUFDO1FBQ2xELEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLEVBQUU7UUFDOUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsRUFBRTtLQUM5QyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBa0IsRUFBRSxDQUFDLHdCQUF3QjtLQUMxRCxLQUFLLENBQUMsS0FBSyxLQUFLLFNBQVMsSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLElBQUksSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLEVBQUUsQ0FDeEU7Q0FDRixDQUFDIn0=
|
|
@@ -5,15 +5,10 @@ exports.default = checkAbandonedCartsJob;
|
|
|
5
5
|
const check_abandoned_carts_1 = require("../workflows/steps/check-abandoned-carts");
|
|
6
6
|
async function checkAbandonedCartsJob(container) {
|
|
7
7
|
const logger = container.resolve("logger");
|
|
8
|
-
console.log("Registered services:", container.registrations); // Debug container
|
|
9
|
-
const myNotificationProvider = container.resolve("brevo");
|
|
10
|
-
const providerOptions = myNotificationProvider.options; // Lấy options từ BrevoProviderService
|
|
11
8
|
try {
|
|
12
|
-
logger.info("Running check-abandoned-carts scheduled job...");
|
|
13
9
|
await (0, check_abandoned_carts_1.checkAbandonedCartsWorkflow)(container).run({
|
|
14
10
|
input: {
|
|
15
|
-
container,
|
|
16
|
-
options: providerOptions.abandoned_cart, // Truyền abandoned_cart options
|
|
11
|
+
container,
|
|
17
12
|
},
|
|
18
13
|
});
|
|
19
14
|
}
|
|
@@ -23,6 +18,6 @@ async function checkAbandonedCartsJob(container) {
|
|
|
23
18
|
}
|
|
24
19
|
exports.config = {
|
|
25
20
|
name: "check-abandoned-carts",
|
|
26
|
-
schedule: "
|
|
21
|
+
schedule: "1 * * * *", // Chạy mỗi giờ
|
|
27
22
|
};
|
|
28
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJhbmRvbmVkLWNhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvam9icy9hYmFuZG9uZWQtY2FydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSx5Q0FhQztBQWZELG9GQUF1RjtBQUV4RSxLQUFLLFVBQVUsc0JBQXNCLENBQUMsU0FBMEI7SUFDN0UsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUUzQyxJQUFJLENBQUM7UUFFSCxNQUFNLElBQUEsbURBQTJCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO1lBQy9DLEtBQUssRUFBRTtnQkFDTCxTQUFTO2FBQ1Y7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsK0NBQStDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDdkUsQ0FBQztBQUNILENBQUM7QUFFWSxRQUFBLE1BQU0sR0FBRztJQUNwQixJQUFJLEVBQUUsdUJBQXVCO0lBQzdCLFFBQVEsRUFBRSxXQUFXLEVBQUUsZUFBZTtDQUN2QyxDQUFDIn0=
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = abandonedCartLoader;
|
|
7
|
+
const abandoned_cart_1 = __importDefault(require("../jobs/abandoned-cart"));
|
|
8
|
+
async function abandonedCartLoader({ container, options, }) {
|
|
9
|
+
const logger = container.resolve("logger");
|
|
10
|
+
abandoned_cart_1.default;
|
|
11
|
+
logger.info("Initializing abandoned cart loader...");
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJldm8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbG9hZGVycy9icmV2by50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVlBLHNDQVVDO0FBakJELDRFQUE0RDtBQU83QyxLQUFLLFVBQVUsbUJBQW1CLENBQUMsRUFDOUMsU0FBUyxFQUNULE9BQU8sR0FDTztJQUNoQixNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBRTNDLHdCQUFzQixDQUFBO0lBQ3RCLE1BQU0sQ0FBQyxJQUFJLENBQUMsdUNBQXVDLENBQUMsQ0FBQztBQUd2RCxDQUFDIn0=
|
|
@@ -1,13 +1,26 @@
|
|
|
1
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
18
|
};
|
|
5
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.BREVO_MODULE = void 0;
|
|
7
20
|
const services_1 = __importDefault(require("./services"));
|
|
8
21
|
const utils_1 = require("@medusajs/framework/utils");
|
|
9
|
-
|
|
10
|
-
exports.default = (0, utils_1.ModuleProvider)(
|
|
22
|
+
__exportStar(require("./types"), exports);
|
|
23
|
+
exports.default = (0, utils_1.ModuleProvider)(utils_1.Modules.NOTIFICATION, {
|
|
11
24
|
services: [services_1.default],
|
|
12
25
|
});
|
|
13
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL25vdGlmaWNhdGlvbnMtYnJldm8vaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDBEQUE2QztBQUM3QyxxREFHa0M7QUFFbEMsMENBQXVCO0FBRXZCLGtCQUFlLElBQUEsc0JBQWMsRUFBQyxlQUFPLENBQUMsWUFBWSxFQUFFO0lBQ2xELFFBQVEsRUFBRSxDQUFDLGtCQUFvQixDQUFDO0NBRWpDLENBQUMsQ0FBQSJ9
|
|
@@ -40,12 +40,11 @@ class BrevoProviderService extends utils_1.AbstractNotificationProviderService {
|
|
|
40
40
|
super();
|
|
41
41
|
this.options = options;
|
|
42
42
|
this.logger = logger;
|
|
43
|
-
console.log("BrevoProviderService initialized with options:", options);
|
|
44
43
|
if (!this.options.apiKey) {
|
|
45
|
-
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "BREVO_API_KEY
|
|
44
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "BREVO_API_KEY need to be set");
|
|
46
45
|
}
|
|
47
46
|
if (!this.options.from) {
|
|
48
|
-
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "BREVO_FROM_EMAIL
|
|
47
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "BREVO_FROM_EMAIL need to be set");
|
|
49
48
|
}
|
|
50
49
|
this.apiInstance = new Brevo.TransactionalEmailsApi();
|
|
51
50
|
this.apiInstance.setApiKey(Brevo.TransactionalEmailsApiApiKeys.apiKey, this.options.apiKey);
|
|
@@ -57,18 +56,29 @@ class BrevoProviderService extends utils_1.AbstractNotificationProviderService {
|
|
|
57
56
|
switch (template) {
|
|
58
57
|
case "order.placed":
|
|
59
58
|
templateId = parseInt(this.options.orderPlacedTemplateId);
|
|
59
|
+
const order = data.order;
|
|
60
|
+
// Tạo formatter dựa trên currency_code
|
|
61
|
+
const formatter = new Intl.NumberFormat([], {
|
|
62
|
+
style: "currency",
|
|
63
|
+
currencyDisplay: "narrowSymbol",
|
|
64
|
+
currency: order.currency_code.toUpperCase(), // "VND"
|
|
65
|
+
});
|
|
60
66
|
params = {
|
|
61
|
-
order_id:
|
|
62
|
-
email:
|
|
63
|
-
currency_code:
|
|
64
|
-
display_id:
|
|
65
|
-
total:
|
|
66
|
-
customer_name:
|
|
67
|
-
items:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
order_id: order?.id,
|
|
68
|
+
email: order?.email,
|
|
69
|
+
currency_code: order?.currency_code,
|
|
70
|
+
display_id: order?.display_id,
|
|
71
|
+
total: formatter.format(order?.total),
|
|
72
|
+
customer_name: order?.shipping_address?.first_name,
|
|
73
|
+
items: order?.items.map((item) => ({
|
|
74
|
+
...item,
|
|
75
|
+
unit_price: formatter.format(item.total),
|
|
76
|
+
})),
|
|
77
|
+
shipping_address: order?.shipping_address,
|
|
78
|
+
shipping_subtotal: formatter.format(order?.shipping_subtotal),
|
|
79
|
+
shipping_methods: order?.shipping_methods,
|
|
80
|
+
payment_collections: order?.payment_collections?.payments,
|
|
81
|
+
fulfillments: order?.fulfillments,
|
|
72
82
|
};
|
|
73
83
|
this.logger.info(JSON.stringify(params, null, 2));
|
|
74
84
|
break;
|
|
@@ -76,14 +86,14 @@ class BrevoProviderService extends utils_1.AbstractNotificationProviderService {
|
|
|
76
86
|
templateId = parseInt(this.options.orderCanceledTemplateId);
|
|
77
87
|
params = {
|
|
78
88
|
order_id: data.order?.id,
|
|
79
|
-
customer_name: data.order?.billing_address?.first_name
|
|
89
|
+
customer_name: data.order?.billing_address?.first_name,
|
|
80
90
|
};
|
|
81
91
|
break;
|
|
82
92
|
case "customer.created":
|
|
83
93
|
templateId = parseInt(this.options.customerCreatedTemplateId);
|
|
84
94
|
params = {
|
|
85
95
|
name: data.customer?.first_name + " " + (data.customer?.last_name || ""),
|
|
86
|
-
phone: data.customer?.phone
|
|
96
|
+
phone: data.customer?.phone,
|
|
87
97
|
customer_id: data.customer?.id,
|
|
88
98
|
};
|
|
89
99
|
break;
|
|
@@ -92,18 +102,19 @@ class BrevoProviderService extends utils_1.AbstractNotificationProviderService {
|
|
|
92
102
|
params = {
|
|
93
103
|
cart_id: data.cart?.id,
|
|
94
104
|
created_at: data.cart?.created_at,
|
|
95
|
-
name: data.cart?.name
|
|
96
|
-
phone: data.cart?.phone
|
|
105
|
+
name: data.cart?.name,
|
|
106
|
+
phone: data.cart?.phone,
|
|
107
|
+
items: data.cart?.items,
|
|
97
108
|
};
|
|
98
109
|
break;
|
|
99
110
|
default:
|
|
100
|
-
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Template ${template}
|
|
111
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Template ${template} is not supported`);
|
|
101
112
|
}
|
|
102
113
|
if (isNaN(templateId) || templateId === 0) {
|
|
103
|
-
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, `Template ID
|
|
114
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, `Template ID for ${template} is not set in options`);
|
|
104
115
|
}
|
|
105
116
|
if (!to) {
|
|
106
|
-
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `
|
|
117
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Email is not found for ${template}`);
|
|
107
118
|
}
|
|
108
119
|
const sendSmtpEmail = new Brevo.SendSmtpEmail();
|
|
109
120
|
sendSmtpEmail.sender = { email: this.options.from };
|
|
@@ -118,8 +129,8 @@ class BrevoProviderService extends utils_1.AbstractNotificationProviderService {
|
|
|
118
129
|
};
|
|
119
130
|
}
|
|
120
131
|
catch (error) {
|
|
121
|
-
this.logger.error(`
|
|
122
|
-
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "
|
|
132
|
+
this.logger.error(`Error while sending email ${to}:`, error);
|
|
133
|
+
throw new utils_1.MedusaError(utils_1.MedusaError.Types.UNEXPECTED_STATE, "Email is not send");
|
|
123
134
|
}
|
|
124
135
|
}
|
|
125
136
|
async resend(notification) {
|
|
@@ -128,4 +139,4 @@ class BrevoProviderService extends utils_1.AbstractNotificationProviderService {
|
|
|
128
139
|
}
|
|
129
140
|
BrevoProviderService.identifier = "brevo";
|
|
130
141
|
exports.default = BrevoProviderService;
|
|
131
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
142
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL25vdGlmaWNhdGlvbnMtYnJldm8vc2VydmljZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxxREFHbUM7QUFNbkMsdURBQXlDO0FBS3pDLE1BQU0sb0JBQXFCLFNBQVEsMkNBQW1DO0lBT3BFLFlBQVksRUFBRSxNQUFNLEVBQXNCLEVBQUUsT0FBNEI7UUFDdEUsS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUVyQixJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5Qiw4QkFBOEIsQ0FDL0IsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksbUJBQVcsQ0FDbkIsbUJBQVcsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUM5QixpQ0FBaUMsQ0FDbEMsQ0FBQztRQUNKLENBQUM7UUFFRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksS0FBSyxDQUFDLHNCQUFzQixFQUFFLENBQUM7UUFDdEQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQ3hCLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxNQUFNLEVBQzFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUNwQixDQUFDO0lBQ0osQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJLENBQ1IsWUFBeUM7UUFFekMsTUFBTSxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLEdBQUcs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
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL25vdGlmaWNhdGlvbnMtYnJldm8vdHlwZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
|
|
@@ -4,24 +4,11 @@ exports.config = void 0;
|
|
|
4
4
|
exports.default = customerCreatedHandler;
|
|
5
5
|
const send_customer_created_1 = require("../workflows/send-customer-created");
|
|
6
6
|
async function customerCreatedHandler({ event, container, }) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
// Gọi workflow và in thông tin trước khi chạy
|
|
12
|
-
console.log("Running sendCustomerCreatedWorkflow with input:", { id: event.data.id });
|
|
13
|
-
const result = await (0, send_customer_created_1.sendCustomerCreatedWorkflow)(container).run({
|
|
14
|
-
input: { id: event.data.id },
|
|
15
|
-
});
|
|
16
|
-
console.log("Workflow result:", result);
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
// In lỗi chi tiết nếu có
|
|
20
|
-
console.error("Error in customer.created subscriber:", error);
|
|
21
|
-
throw error; // Ném lại lỗi để Medusa ghi log
|
|
22
|
-
}
|
|
7
|
+
const result = await (0, send_customer_created_1.sendCustomerCreatedWorkflow)(container).run({
|
|
8
|
+
input: { id: event.data.id },
|
|
9
|
+
});
|
|
23
10
|
}
|
|
24
11
|
exports.config = {
|
|
25
12
|
event: "customer.created",
|
|
26
13
|
};
|
|
27
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9tZXItY3JlYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdWJzY3JpYmVycy9jdXN0b21lci1jcmVhdGVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUdBLHlDQVVDO0FBWkQsOEVBQWlGO0FBRWxFLEtBQUssVUFBVSxzQkFBc0IsQ0FBQyxFQUNuRCxLQUFLLEVBQ0wsU0FBUyxHQUNzQjtJQUc3QixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUEsbURBQTJCLEVBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDO1FBQzlELEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRTtLQUM3QixDQUFDLENBQUM7QUFFUCxDQUFDO0FBRVksUUFBQSxNQUFNLEdBQXFCO0lBQ3RDLEtBQUssRUFBRSxrQkFBa0I7Q0FDMUIsQ0FBQyJ9
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.config = void 0;
|
|
4
|
+
exports.default = orderPlacedHandler;
|
|
5
|
+
const send_order_confirmation_1 = require("../workflows/send-order-confirmation");
|
|
6
|
+
async function orderPlacedHandler({ event: { data }, container, }) {
|
|
7
|
+
await (0, send_order_confirmation_1.sendOrderConfirmationWorkflow)(container)
|
|
8
|
+
.run({
|
|
9
|
+
input: {
|
|
10
|
+
id: data.id
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
exports.config = {
|
|
15
|
+
event: "shipment.created",
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hpcG1lbnQtY3JlYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdWJzY3JpYmVycy9zaGlwbWVudC1jcmVhdGVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQVFFLHFDQVVDO0FBWkQsa0ZBQW9GO0FBRXJFLEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxFQUMvQyxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFDZixTQUFTLEdBQ3NCO0lBQy9CLE1BQU0sSUFBQSx1REFBNkIsRUFBQyxTQUFTLENBQUM7U0FDM0MsR0FBRyxDQUFDO1FBQ0gsS0FBSyxFQUFFO1lBQ0wsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFO1NBQ1o7S0FDRixDQUFDLENBQUE7QUFDTixDQUFDO0FBRVksUUFBQSxNQUFNLEdBQXFCO0lBQ3RDLEtBQUssRUFBRSxrQkFBa0I7Q0FDMUIsQ0FBQSJ9
|
|
@@ -20,7 +20,7 @@ exports.sendAbandonedCartWorkflow = (0, workflows_sdk_1.createWorkflow)("send-ab
|
|
|
20
20
|
});
|
|
21
21
|
const prepareNotificationStep = (0, workflows_sdk_1.createStep)("prepare-abandoned-cart-notification", async (input) => {
|
|
22
22
|
const carts = input.data;
|
|
23
|
-
console.log("Cart data retrieved:", carts);
|
|
23
|
+
//console.log("Cart data retrieved:", carts);
|
|
24
24
|
const notificationData = [
|
|
25
25
|
{
|
|
26
26
|
to: carts[0].email,
|
|
@@ -37,11 +37,11 @@ exports.sendAbandonedCartWorkflow = (0, workflows_sdk_1.createWorkflow)("send-ab
|
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
39
|
];
|
|
40
|
-
console.log("Prepared abandoned cart notification data:", notificationData);
|
|
40
|
+
//console.log("Prepared abandoned cart notification data:", notificationData);
|
|
41
41
|
return new workflows_sdk_1.StepResponse(notificationData);
|
|
42
42
|
});
|
|
43
43
|
const notificationData = prepareNotificationStep(cartStep);
|
|
44
44
|
const notificationStep = (0, send_notification_1.sendNotificationStep)(notificationData);
|
|
45
45
|
return new workflows_sdk_1.WorkflowResponse(notificationStep);
|
|
46
46
|
});
|
|
47
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC1hYmFuZG9uZWQtY2FydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3Mvc2VuZC1hYmFuZG9uZWQtY2FydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxRUFBK0c7QUFDL0csNERBQWdFO0FBQ2hFLGlFQUFpRTtBQU9wRCxRQUFBLHlCQUF5QixHQUFHLElBQUEsOEJBQWMsRUFDckQscUJBQXFCLEVBQ3JCLENBQUMsRUFBRSxNQUFNLEVBQWlCLEVBQUUsRUFBRTtJQUM1QixNQUFNLFFBQVEsR0FBRyxJQUFBLDhCQUFpQixFQUFDO1FBQ2pDLE1BQU0sRUFBRSxNQUFNO1FBQ2QsTUFBTSxFQUFFO1lBQ04sSUFBSTtZQUNKLE9BQU87WUFDUCxZQUFZO1lBQ1oscUJBQXFCO1lBQ3JCLG9CQUFvQjtZQUNwQixnQkFBZ0I7WUFDaEIsU0FBUztTQUNWO1FBQ0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRTtLQUN4QixDQUFDLENBQUM7SUFFSCxNQUFNLHVCQUF1QixHQUFHLElBQUEsMEJBQVUsRUFDeEMscUNBQXFDLEVBQ3JDLEtBQUssRUFBRSxLQUFzQixFQUFFLEVBQUU7UUFDL0IsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztRQUN6Qiw2Q0FBNkM7UUFFN0MsTUFBTSxnQkFBZ0IsR0FBNEI7WUFDaEQ7Z0JBQ0UsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLO2dCQUNsQixPQUFPLEVBQUUsT0FBTztnQkFDaEIsUUFBUSxFQUFFLGdCQUFnQjtnQkFDMUIsSUFBSSxFQUFFO29CQUNKLElBQUksRUFBRTt3QkFDSixFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7d0JBQ2YsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVO3dCQUMvQixJQUFJLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLFVBQVUsSUFBSSxFQUFFLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLFNBQVMsSUFBSSxFQUFFLENBQUM7d0JBQ3hGLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLEtBQUssSUFBSSx3QkFBd0I7d0JBQzNELEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLHFDQUFxQztxQkFDNUQ7aUJBQ0Y7YUFDRjtTQUNGLENBQUM7UUFFRiw4RUFBOEU7UUFDOUUsT0FBTyxJQUFJLDRCQUFZLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUM1QyxDQUFDLENBQ0YsQ0FBQztJQUVGLE1BQU0sZ0JBQWdCLEdBQUcsdUJBQXVCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDM0QsTUFBTSxnQkFBZ0IsR0FBRyxJQUFBLHdDQUFvQixFQUFDLGdCQUFnQixDQUFDLENBQUM7SUFFaEUsT0FBTyxJQUFJLGdDQUFnQixDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFDaEQsQ0FBQyxDQUNGLENBQUMifQ==
|
|
@@ -5,78 +5,22 @@ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
|
5
5
|
const core_flows_1 = require("@medusajs/medusa/core-flows");
|
|
6
6
|
const send_notification_1 = require("./steps/send-notification");
|
|
7
7
|
exports.sendOrderConfirmationWorkflow = (0, workflows_sdk_1.createWorkflow)("send-order-confirmation", ({ id }) => {
|
|
8
|
-
|
|
9
|
-
const orderStep = (0, core_flows_1.useQueryGraphStep)({
|
|
8
|
+
const { data: orders } = (0, core_flows_1.useQueryGraphStep)({
|
|
10
9
|
entity: "order",
|
|
11
|
-
fields: [
|
|
12
|
-
"id",
|
|
13
|
-
"email",
|
|
14
|
-
"currency_code",
|
|
15
|
-
"display_id",
|
|
16
|
-
"total",
|
|
17
|
-
"items.*",
|
|
18
|
-
"billing_address.*",
|
|
19
|
-
"shipping_address.*",
|
|
20
|
-
"payment_collections.*",
|
|
21
|
-
"fulfillments.*",
|
|
22
|
-
"shipping_subtotal"
|
|
23
|
-
],
|
|
10
|
+
fields: ["id", "email", "currency_code", "display_id", "shipping_subtotal", "total", "items.*", "shipping_address.*", "payment_collections.*", "payment_collections.payments.*", "fulfillments.*", "shipping_methods.*"],
|
|
24
11
|
filters: { id },
|
|
25
12
|
});
|
|
26
|
-
//
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const order = orders[0];
|
|
37
|
-
// Tạo formatter dựa trên currency_code của đơn hàng
|
|
38
|
-
const formatter = new Intl.NumberFormat([], {
|
|
39
|
-
style: "currency",
|
|
40
|
-
currencyDisplay: "narrowSymbol",
|
|
41
|
-
currency: order.currency_code.toUpperCase(), // "VND"
|
|
42
|
-
});
|
|
43
|
-
// Dùng payment_collections.amount thay vì total
|
|
44
|
-
const formattedShippingTotal = formatter.format(order.shipping_subtotal);
|
|
45
|
-
const formattedTotal = formatter.format(order.total);
|
|
46
|
-
// Định dạng unit_price cho từng item (giả sử dữ liệu gốc cần điều chỉnh)
|
|
47
|
-
const formattedItems = order.items.map((item) => ({
|
|
48
|
-
...item, // Giữ nguyên các trường khác
|
|
49
|
-
unit_price: formatter.format(item.unit_price), // Dùng giá trị từ log
|
|
50
|
-
}));
|
|
51
|
-
const notificationData = [
|
|
52
|
-
{
|
|
53
|
-
to: order.email,
|
|
54
|
-
channel: "email",
|
|
55
|
-
template: "order.placed",
|
|
56
|
-
data: {
|
|
57
|
-
order: {
|
|
58
|
-
id: order.id,
|
|
59
|
-
email: order.email,
|
|
60
|
-
currency_code: order.currency_code,
|
|
61
|
-
display_id: order.display_id,
|
|
62
|
-
total: formattedTotal,
|
|
63
|
-
shipping_total: formattedShippingTotal,
|
|
64
|
-
items: formattedItems,
|
|
65
|
-
billing_address: order.billing_address,
|
|
66
|
-
shipping_address: order.shipping_address,
|
|
67
|
-
payment_collections: order.payment_collections,
|
|
68
|
-
fulfillments: order.fulfillments,
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
];
|
|
73
|
-
console.log("Prepared order confirmed notification data:", JSON.stringify(notificationData, null, 2));
|
|
74
|
-
return new workflows_sdk_1.StepResponse(notificationData);
|
|
75
|
-
});
|
|
76
|
-
// Liên kết các bước
|
|
77
|
-
const resolvedOrders = logOrderDataStep(orderStep);
|
|
78
|
-
const notificationData = prepareNotificationStep(resolvedOrders);
|
|
13
|
+
//console.log("Order data retrieved (resolved):", JSON.stringify(orders, null, 2));
|
|
14
|
+
const notificationData = [
|
|
15
|
+
{
|
|
16
|
+
to: orders[0].email,
|
|
17
|
+
channel: "email",
|
|
18
|
+
template: "order.placed",
|
|
19
|
+
data: { order: orders[0] },
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
//console.log("Prepared order confirmed notification data:", JSON.stringify(notificationData, null, 2));
|
|
79
23
|
const notification = (0, send_notification_1.sendNotificationStep)(notificationData);
|
|
80
24
|
return new workflows_sdk_1.WorkflowResponse(notification);
|
|
81
25
|
});
|
|
82
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC1vcmRlci1jb25maXJtYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL3NlbmQtb3JkZXItY29uZmlybWF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFFQUFxRjtBQUNyRiw0REFBZ0U7QUFDaEUsaUVBQWlFO0FBT3BELFFBQUEsNkJBQTZCLEdBQUcsSUFBQSw4QkFBYyxFQUN6RCx5QkFBeUIsRUFDekIsQ0FBQyxFQUFFLEVBQUUsRUFBaUIsRUFBRSxFQUFFO0lBQ3hCLE1BQU0sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEdBQUcsSUFBQSw4QkFBaUIsRUFBQztRQUN6QyxNQUFNLEVBQUUsT0FBTztRQUNmLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxtQkFBbUIsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLHVCQUF1QixFQUFDLGdDQUFnQyxFQUFFLGdCQUFnQixFQUFFLG9CQUFvQixDQUFDO1FBQ3ZOLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRTtLQUNoQixDQUFDLENBQUM7SUFDSCxtRkFBbUY7SUFFbkYsTUFBTSxnQkFBZ0IsR0FBNEI7UUFDaEQ7WUFDRSxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUs7WUFDbkIsT0FBTyxFQUFFLE9BQU87WUFDaEIsUUFBUSxFQUFFLGNBQWM7WUFDeEIsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRTtTQUMzQjtLQUNGLENBQUM7SUFDRix3R0FBd0c7SUFDeEcsTUFBTSxZQUFZLEdBQUcsSUFBQSx3Q0FBb0IsRUFBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBRTVELE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUM1QyxDQUFDLENBQ0YsQ0FBQyJ9
|
|
@@ -4,22 +4,30 @@ exports.checkAbandonedCartsWorkflow = void 0;
|
|
|
4
4
|
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
5
5
|
const utils_1 = require("@medusajs/framework/utils");
|
|
6
6
|
const send_abandoned_cart_1 = require("../send-abandoned-cart");
|
|
7
|
-
|
|
7
|
+
const config_1 = require("../../config");
|
|
8
|
+
exports.checkAbandonedCartsWorkflow = (0, workflows_sdk_1.createWorkflow)("check-abandoned-carts", ({ container }) => {
|
|
8
9
|
const checkCartsStep = (0, workflows_sdk_1.createStep)("check-abandoned-carts-step", async (_, { container: stepContainer }) => {
|
|
9
10
|
const cartModuleService = stepContainer.resolve(utils_1.Modules.CART);
|
|
10
11
|
const logger = stepContainer.resolve("logger");
|
|
11
12
|
const query = stepContainer.resolve("query");
|
|
13
|
+
if (!config_1.abandonedCartConfig.abandoned_carts) {
|
|
14
|
+
logger.info("Abandoned carts feature is disabled in config.");
|
|
15
|
+
return new workflows_sdk_1.StepResponse(null);
|
|
16
|
+
}
|
|
17
|
+
if (!config_1.abandonedCartConfig.checks.length) {
|
|
18
|
+
logger.info("No abandoned cart checks configured.");
|
|
19
|
+
return new workflows_sdk_1.StepResponse(null);
|
|
20
|
+
}
|
|
21
|
+
logger.info("Running check-abandoned-carts scheduled job...");
|
|
12
22
|
const now = new Date();
|
|
13
23
|
const seventyTwoHoursAgo = new Date(now.getTime() - 72 * 60 * 60 * 1000);
|
|
14
|
-
|
|
15
|
-
const firstCheck = new Date(now.getTime() - parseInt(options.first.delay) * 60 * 60 * 1000);
|
|
16
|
-
const secondCheck = new Date(now.getTime() - parseInt(options.second.delay) * 60 * 60 * 1000);
|
|
17
|
-
const thirdCheck = new Date(now.getTime() - parseInt(options.third.delay) * 60 * 60 * 1000);
|
|
18
|
-
logger.info("Starting to check abandoned carts...");
|
|
19
|
-
logger.info(`Checking intervals: first=${options.first.delay}, second=${options.second.delay}, third=${options.third.delay}`);
|
|
24
|
+
const checkTimes = config_1.abandonedCartConfig.checks.map(check => new Date(now.getTime() - parseInt(check.delay) * 60 * 60 * 1000));
|
|
20
25
|
const { data: carts } = await query.graph({
|
|
21
26
|
entity: "cart",
|
|
22
|
-
fields: [
|
|
27
|
+
fields: [
|
|
28
|
+
"id", "email", "created_at", "updated_at", "completed_at", "metadata",
|
|
29
|
+
"items.id", "items.updated_at"
|
|
30
|
+
],
|
|
23
31
|
filters: {
|
|
24
32
|
completed_at: null,
|
|
25
33
|
email: { $ne: null },
|
|
@@ -28,32 +36,29 @@ exports.checkAbandonedCartsWorkflow = (0, workflows_sdk_1.createWorkflow)("check
|
|
|
28
36
|
});
|
|
29
37
|
logger.info(`Found ${carts.length} carts to check`);
|
|
30
38
|
for (const cart of carts) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
first_abandonedcart_mail: cart.metadata?.first_abandonedcart_mail || false,
|
|
35
|
-
second_abandonedcart_mail: cart.metadata?.second_abandonedcart_mail || false,
|
|
36
|
-
third_abandonedcart_mail: cart.metadata?.third_abandonedcart_mail || false,
|
|
37
|
-
};
|
|
38
|
-
if (updatedAt <= firstCheck && !notifiedFlags.first_abandonedcart_mail) {
|
|
39
|
-
logger.info(`Sending first abandoned cart email to ${cart.email} after ${options.first.delay} hours`);
|
|
40
|
-
await (0, send_abandoned_cart_1.sendAbandonedCartWorkflow)(stepContainer).run({ input: { cartId: cart.id } });
|
|
41
|
-
await cartModuleService.updateCarts(cart.id, {
|
|
42
|
-
metadata: { ...cart.metadata, first_abandonedcart_mail: true },
|
|
43
|
-
});
|
|
39
|
+
if (!cart.items?.length) {
|
|
40
|
+
logger.info(`Cart ${cart.id} skipped: No items in cart`);
|
|
41
|
+
continue;
|
|
44
42
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
const latestItemUpdate = cart.items.sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())[0].updated_at;
|
|
44
|
+
const check = new Date(latestItemUpdate);
|
|
45
|
+
const hoursSinceUpdate = Math.floor((now.getTime() - check.getTime()) / (1000 * 60 * 60));
|
|
46
|
+
const notifiedFlags = cart.metadata || {};
|
|
47
|
+
let actionIndex = -1;
|
|
48
|
+
for (let i = checkTimes.length - 1; i >= 0; i--) {
|
|
49
|
+
if (check < checkTimes[i] && !notifiedFlags[`abandonedcart_mail_${i + 1}`]) {
|
|
50
|
+
actionIndex = i;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
51
53
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
if (actionIndex >= 0) {
|
|
55
|
+
const delay = config_1.abandonedCartConfig.checks[actionIndex].delay;
|
|
56
|
+
const flagKey = `abandonedcart_mail_${actionIndex + 1}`;
|
|
57
|
+
logger.info(`Cart ${cart.id}: check = ${check}, hoursSinceUpdate = ${hoursSinceUpdate}`);
|
|
58
|
+
logger.info(`Sending abandoned cart email #${actionIndex + 1} to ${cart.email} after ${delay} hours`);
|
|
54
59
|
await (0, send_abandoned_cart_1.sendAbandonedCartWorkflow)(stepContainer).run({ input: { cartId: cart.id } });
|
|
55
60
|
await cartModuleService.updateCarts(cart.id, {
|
|
56
|
-
metadata: { ...
|
|
61
|
+
metadata: { ...notifiedFlags, [flagKey]: true },
|
|
57
62
|
});
|
|
58
63
|
}
|
|
59
64
|
}
|
|
@@ -63,4 +68,4 @@ exports.checkAbandonedCartsWorkflow = (0, workflows_sdk_1.createWorkflow)("check
|
|
|
63
68
|
const result = checkCartsStep();
|
|
64
69
|
return new workflows_sdk_1.WorkflowResponse(result);
|
|
65
70
|
});
|
|
66
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2stYWJhbmRvbmVkLWNhcnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9zdGVwcy9jaGVjay1hYmFuZG9uZWQtY2FydHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBQStHO0FBQy9HLHFEQUFvRDtBQUNwRCxnRUFBbUU7QUFDbkUseUNBQW1EO0FBTXRDLFFBQUEsMkJBQTJCLEdBQUcsSUFBQSw4QkFBYyxFQUN2RCx1QkFBdUIsRUFDdkIsQ0FBQyxFQUFFLFNBQVMsRUFBaUIsRUFBRSxFQUFFO0lBQy9CLE1BQU0sY0FBYyxHQUFHLElBQUEsMEJBQVUsRUFDL0IsNEJBQTRCLEVBQzVCLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsYUFBYSxFQUFFLEVBQUUsRUFBRTtRQUN4QyxNQUFNLGlCQUFpQixHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzlELE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDL0MsTUFBTSxLQUFLLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU3QyxJQUFJLENBQUMsNEJBQW1CLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDekMsTUFBTSxDQUFDLElBQUksQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1lBQzlELE9BQU8sSUFBSSw0QkFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hDLENBQUM7UUFFRCxJQUFJLENBQUMsNEJBQW1CLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3ZDLE1BQU0sQ0FBQyxJQUFJLENBQUMsc0NBQXNDLENBQUMsQ0FBQztZQUNwRCxPQUFPLElBQUksNEJBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoQyxDQUFDO1FBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxnREFB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
|
|
@@ -8,4 +8,4 @@ exports.sendNotificationStep = (0, workflows_sdk_1.createStep)("send-notificatio
|
|
|
8
8
|
const notification = await notificationModuleService.createNotifications(data);
|
|
9
9
|
return new workflows_sdk_1.StepResponse(notification);
|
|
10
10
|
});
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC1ub3RpZmljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL3N0ZXBzL3NlbmQtbm90aWZpY2F0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFEQUFtRDtBQUNuRCxxRUFBNEU7QUFJL0QsUUFBQSxvQkFBb0IsR0FBRyxJQUFBLDBCQUFVLEVBQzVDLG1CQUFtQixFQUNuQixLQUFLLEVBQUUsSUFBNkIsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUU7SUFDckQsTUFBTSx5QkFBeUIsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUNqRCxlQUFPLENBQUMsWUFBWSxDQUNyQixDQUFBO0lBSUQsTUFBTSxZQUFZLEdBQUcsTUFBTSx5QkFBeUIsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUM5RSxPQUFPLElBQUksNEJBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQUN2QyxDQUFDLENBQ0YsQ0FBQSJ9
|
package/README.md
CHANGED
|
@@ -1,64 +1,96 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<a href="https://www.medusajs.com">
|
|
3
|
-
<picture>
|
|
4
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/59018053/229103275-b5e482bb-4601-46e6-8142-244f531cebdb.svg">
|
|
5
|
-
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
|
|
6
|
-
<img alt="Medusa logo" src="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
|
|
7
|
-
</picture>
|
|
8
|
-
</a>
|
|
9
|
-
</p>
|
|
10
|
-
<h1 align="center">
|
|
11
|
-
Medusa Plugin Starter
|
|
12
|
-
</h1>
|
|
13
1
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
2
|
+
## Information
|
|
3
|
+
Not a full-time professional developer so Medusa 2.0 is very hard to learn for me.
|
|
4
|
+
If anyone want to improve this plugin, just submit your PR
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# @kb0912/notification-brevo
|
|
9
|
+
|
|
10
|
+
A Medusa plugin to integrate Brevo (Sendinblue) notification provider for sending emails such as order confirmations and abandoned cart reminders.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
- Send email notifications for order placement, order cancellation, customer creation, and abandoned carts using Brevo.
|
|
16
|
+
- Configurable delays for abandoned cart reminders.
|
|
17
|
+
- Supports multiple notification stages (first, second, third).
|
|
18
|
+
|
|
19
|
+
### Installation
|
|
20
|
+
|
|
21
|
+
To install the package, use Yarn:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
yarn add @kb0912/notification-brevo
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Configuration
|
|
28
|
+
Add the plugin to your medusa-config.ts file to enable Brevo notifications in your Medusa project.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
modules: [
|
|
32
|
+
// Other module...
|
|
33
|
+
{
|
|
34
|
+
resolve: "@medusajs/medusa/notification",
|
|
35
|
+
options: {
|
|
36
|
+
providers: [
|
|
37
|
+
{
|
|
38
|
+
resolve: "@kb0912/notification-brevo/providers/notifications-brevo",
|
|
39
|
+
id: "brevo",
|
|
40
|
+
options: {
|
|
41
|
+
channels: ["email"],
|
|
42
|
+
apiKey: process.env.BREVO_API_KEY || "your-brevo-api-key",
|
|
43
|
+
from: process.env.BREVO_FROM_EMAIL || "info@example.com",
|
|
44
|
+
orderPlacedTemplateId: process.env.BREVO_ORDER_PLACED_TEMPLATE_ID || "11",
|
|
45
|
+
orderCanceledTemplateId: process.env.BREVO_ORDER_CANCELED_TEMPLATE_ID || "14",
|
|
46
|
+
customerCreatedTemplateId: process.env.BREVO_CUSTOMER_CREATED_TEMPLATE_ID || "12",
|
|
47
|
+
abandonedCartTemplateId: process.env.BREVO_ABANDONED_CART_TEMPLATE_ID || "13",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
then
|
|
57
|
+
```bash
|
|
58
|
+
const plugins = [
|
|
59
|
+
// Other plugins...
|
|
60
|
+
{
|
|
61
|
+
resolve: "@kb0912/notification-brevo",
|
|
62
|
+
options: {
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Environment Variables
|
|
71
|
+
|
|
72
|
+
You can use environment variables to override default values:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# .env
|
|
76
|
+
BREVO_API_KEY=your-brevo-api-key
|
|
77
|
+
BREVO_FROM_EMAIL=info@example.com
|
|
78
|
+
BREVO_ORDER_PLACED_TEMPLATE_ID=11
|
|
79
|
+
BREVO_ORDER_CANCELED_TEMPLATE_ID=14
|
|
80
|
+
BREVO_CUSTOMER_CREATED_TEMPLATE_ID=12
|
|
81
|
+
BREVO_ABANDONED_CART_TEMPLATE_ID=13
|
|
82
|
+
BREVO_CART_FIRST_DELAY=24
|
|
83
|
+
BREVO_CART_SECOND_DELAY=48
|
|
84
|
+
BREVO_CART_THIRD_DELAY=72
|
|
85
|
+
ENABLE_ABANDONED_CARTS=true
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Usage
|
|
89
|
+
Once configured, the plugin will:
|
|
90
|
+
|
|
91
|
+
Send order confirmation emails when an order is placed.
|
|
92
|
+
Send abandoned cart reminder emails based on the configured delays (e.g., 24, 48, 72 hours) after the cart's last update.
|
|
93
|
+
Prerequisites
|
|
94
|
+
|
|
95
|
+
A Medusa server running v2.x.
|
|
96
|
+
A Brevo account with API key and email templates set up.
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kb0912/notification-brevo",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"author": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Sending email notification using Brevo.",
|
|
5
|
+
"author": "KBa (https://medusajs.com)",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"files": [
|
|
8
8
|
".medusa/server"
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = abandonedCartLoader;
|
|
4
|
-
async function abandonedCartLoader({ container, options, }) {
|
|
5
|
-
const logger = container.resolve("logger");
|
|
6
|
-
logger.info("Initializing abandoned cart loader...");
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJhbmRvbmVkLWNhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbG9hZGVycy9hYmFuZG9uZWQtY2FydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVdBLHNDQVNDO0FBVGMsS0FBSyxVQUFVLG1CQUFtQixDQUFDLEVBQzlDLFNBQVMsRUFDVCxPQUFPLEdBQ087SUFDaEIsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUUzQyxNQUFNLENBQUMsSUFBSSxDQUFDLHVDQUF1QyxDQUFDLENBQUM7QUFHdkQsQ0FBQyJ9
|