@infuro/cms-core 1.0.45 → 1.0.47
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/README.md +19 -2
- package/dist/admin.cjs +4249 -2872
- package/dist/admin.d.cts +24 -4
- package/dist/admin.d.ts +24 -4
- package/dist/admin.js +3179 -1804
- package/dist/api.cjs +41 -39
- package/dist/api.d.cts +10 -4
- package/dist/api.d.ts +10 -4
- package/dist/api.js +9 -7
- package/dist/auth.cjs +55 -51
- package/dist/auth.d.cts +6 -3
- package/dist/auth.d.ts +6 -3
- package/dist/auth.js +3 -3
- package/dist/{chunk-KFFB6EMZ.js → chunk-2HU5R2JE.js} +2 -0
- package/dist/chunk-2IAXTKQN.cjs +19 -0
- package/dist/chunk-2KUCQVAQ.js +936 -0
- package/dist/chunk-3K5AIEIZ.js +256 -0
- package/dist/{chunk-SPQFNIYJ.cjs → chunk-4PMK3RNA.cjs} +2 -0
- package/dist/{chunk-X6UQFV4X.cjs → chunk-77NUXO6A.cjs} +14 -12
- package/dist/chunk-BXYZDMTZ.cjs +953 -0
- package/dist/chunk-DBPSJYLZ.js +47 -0
- package/dist/chunk-EIZKW2PF.js +13 -0
- package/dist/chunk-HY3AXLOI.cjs +265 -0
- package/dist/{chunk-X47PBV4I.js → chunk-JE22VP6S.js} +1 -0
- package/dist/{chunk-DN65KDIA.js → chunk-JIWUVQ6B.js} +14 -13
- package/dist/{chunk-HT5DI3XW.cjs → chunk-KOTXDSQB.cjs} +1 -0
- package/dist/chunk-L3525VXI.js +243 -0
- package/dist/{chunk-22FFHLTO.cjs → chunk-LMJ7RKPF.cjs} +421 -150
- package/dist/chunk-OY2YTBMP.cjs +50 -0
- package/dist/{chunk-TAHX46EI.cjs → chunk-Q3HQEM4R.cjs} +15 -7
- package/dist/chunk-V25RDUOU.cjs +248 -0
- package/dist/{chunk-ZMRQ72F6.cjs → chunk-VUQFARRT.cjs} +10 -10
- package/dist/{chunk-MVXLRANV.js → chunk-W42UZLQO.js} +1977 -891
- package/dist/{chunk-F5XFHYTG.cjs → chunk-XUCKZPML.cjs} +2088 -991
- package/dist/{chunk-I6NH72MO.js → chunk-YC4NUZCS.js} +10 -2
- package/dist/{chunk-NNQBWDCI.js → chunk-YXH2UUEZ.js} +418 -146
- package/dist/{chunk-BLR6H5GL.js → chunk-ZF2RQWXB.js} +4 -4
- package/dist/cli.cjs +9 -4
- package/dist/cli.js +9 -4
- package/dist/{email-queue-TPZWLTIV.cjs → email-queue-6NJY6HNM.cjs} +7 -5
- package/dist/email-queue-OI2HSCGE.js +4 -0
- package/dist/{emit-order-notification-trigger-IVLWKKJL.js → emit-order-notification-trigger-6XX7LSC4.js} +1 -1
- package/dist/{emit-order-notification-trigger-D2N3KFHL.cjs → emit-order-notification-trigger-NASG7ZEO.cjs} +3 -3
- package/dist/erp-order-invoice-3GXDE443.js +3 -0
- package/dist/erp-order-invoice-EYYNR526.cjs +24 -0
- package/dist/{event-order-defaults-EMWBIGL3.cjs → event-order-defaults-7Z3UZOEH.cjs} +9 -9
- package/dist/{event-order-defaults-SDRNAZHC.js → event-order-defaults-XQ3IDPD7.js} +1 -1
- package/dist/hooks.cjs +43 -0
- package/dist/hooks.d.cts +10 -1
- package/dist/hooks.d.ts +10 -1
- package/dist/hooks.js +39 -1
- package/dist/index.cjs +429 -298
- package/dist/index.d.cts +317 -30
- package/dist/index.d.ts +317 -30
- package/dist/index.js +17 -13
- package/dist/migrations/1781810000000-OrderItemsVariantId.ts +44 -0
- package/dist/migrations/1781900000000-UserInviteStatusToken.ts +46 -0
- package/dist/migrations/1782000000000-ComboSlug.ts +58 -0
- package/dist/migrations/1782100000000-DiscountDeviceType.ts +20 -0
- package/dist/migrations/1782200000000-VendorTeamProfiles.ts +233 -0
- package/dist/migrations/1782300000000-AddTypeToOrderNotificationBindings.ts +75 -0
- package/dist/order-inventory-2MYRKEPC.cjs +39 -0
- package/dist/order-inventory-76V4XIGW.js +2 -0
- package/dist/{order-notification-dispatcher-XWIJYDGA.js → order-notification-dispatcher-6WNG24NY.js} +4 -2
- package/dist/{order-notification-dispatcher-RU7BTGGX.cjs → order-notification-dispatcher-6XSU3AR7.cjs} +6 -4
- package/dist/{rbac-debug-db-2SGNLANF.js → rbac-debug-db-6EMIVMGF.js} +1 -1
- package/dist/{rbac-debug-db-4Z6A425H.cjs → rbac-debug-db-6PWTLBEL.cjs} +2 -2
- package/dist/retire-soft-deleted-unique-5VXBA5XX.cjs +15 -0
- package/dist/retire-soft-deleted-unique-NXQIH4BC.js +2 -0
- package/dist/theme.cjs +6 -1
- package/dist/theme.d.cts +4 -1
- package/dist/theme.d.ts +4 -1
- package/dist/theme.js +3 -1
- package/package.json +5 -4
- package/src/admin/admin.css +34 -24
- package/dist/chunk-5ELSW2UP.js +0 -150
- package/dist/chunk-PNOKNSG2.cjs +0 -222
- package/dist/chunk-WEMDMVHQ.js +0 -216
- package/dist/chunk-XW5ATPRW.cjs +0 -155
- package/dist/email-queue-CGZBVVAS.js +0 -2
- package/dist/erp-order-invoice-3YISSOWW.js +0 -3
- package/dist/erp-order-invoice-ZR5F2KTA.cjs +0 -12
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkUCKN4BBY_cjs = require('./chunk-UCKN4BBY.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkV25RDUOU_cjs = require('./chunk-V25RDUOU.cjs');
|
|
5
|
+
var chunkBXYZDMTZ_cjs = require('./chunk-BXYZDMTZ.cjs');
|
|
5
6
|
var chunkOOTLNH63_cjs = require('./chunk-OOTLNH63.cjs');
|
|
6
7
|
var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
|
|
7
8
|
var clientSes = require('@aws-sdk/client-ses');
|
|
9
|
+
var module$1 = require('module');
|
|
8
10
|
var nodemailer = require('nodemailer');
|
|
9
11
|
|
|
12
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
14
|
|
|
12
15
|
var nodemailer__default = /*#__PURE__*/_interopDefault(nodemailer);
|
|
@@ -22,17 +25,18 @@ function resolvePublicSiteUrl() {
|
|
|
22
25
|
return "";
|
|
23
26
|
}
|
|
24
27
|
chunkUSNT2KNT_cjs.__name(resolvePublicSiteUrl, "resolvePublicSiteUrl");
|
|
25
|
-
function buildOrderTrackUrl(qrToken, siteUrl) {
|
|
26
|
-
const token = qrToken?.trim();
|
|
28
|
+
function buildOrderTrackUrl(qrToken, siteUrl, orderNumber) {
|
|
29
|
+
const token = qrToken?.trim() || orderNumber?.trim();
|
|
27
30
|
if (!token) return "";
|
|
28
31
|
const base = (siteUrl ?? resolvePublicSiteUrl()).replace(/\/+$/, "");
|
|
29
32
|
if (!base) return `/track/${token}`;
|
|
30
33
|
return `${base}/track/${token}`;
|
|
31
34
|
}
|
|
32
35
|
chunkUSNT2KNT_cjs.__name(buildOrderTrackUrl, "buildOrderTrackUrl");
|
|
33
|
-
function buildOrderQrImageUrl(trackUrl, size = 200) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
function buildOrderQrImageUrl(trackUrl, size = 200, fallbackData) {
|
|
37
|
+
const data = trackUrl.trim() || fallbackData?.trim() || "";
|
|
38
|
+
if (!data) return "";
|
|
39
|
+
return `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(data)}`;
|
|
36
40
|
}
|
|
37
41
|
chunkUSNT2KNT_cjs.__name(buildOrderQrImageUrl, "buildOrderQrImageUrl");
|
|
38
42
|
function formatOrderDetailsText(input) {
|
|
@@ -54,9 +58,13 @@ function formatOrderDetailsHtml(input) {
|
|
|
54
58
|
}
|
|
55
59
|
chunkUSNT2KNT_cjs.__name(formatOrderDetailsHtml, "formatOrderDetailsHtml");
|
|
56
60
|
function buildEventOrderTemplateVariables(input) {
|
|
57
|
-
const { event, order, contact, productNames, orderLines = [], siteUrl } = input;
|
|
58
|
-
const trackUrl = buildOrderTrackUrl(order.qrToken, siteUrl);
|
|
59
|
-
const qrImageUrl = buildOrderQrImageUrl(trackUrl);
|
|
61
|
+
const { event, order, contact, productNames, vendorName = "", orderLines = [], siteUrl } = input;
|
|
62
|
+
const trackUrl = buildOrderTrackUrl(order.qrToken, siteUrl, order.orderNumber);
|
|
63
|
+
const qrImageUrl = buildOrderQrImageUrl(trackUrl, 200, order.orderNumber);
|
|
64
|
+
const ticketQr = qrImageUrl ? `<img src="${qrImageUrl}" alt="Ticket QR Code" width="200" height="200" style="display:block;margin:12px 0;border:1px solid #e5e7eb;border-radius:8px;" />` : "";
|
|
65
|
+
const baseSite = (siteUrl ?? resolvePublicSiteUrl()).replace(/\/+$/, "");
|
|
66
|
+
const invoiceNumber = `INV-${order.orderNumber ?? ""}`;
|
|
67
|
+
const invoiceUrl = baseSite ? `${baseSite}/api/orders/${order.orderNumber ?? ""}/invoice` : `/api/orders/${order.orderNumber ?? ""}/invoice`;
|
|
60
68
|
const orderDetailsPayload = {
|
|
61
69
|
orderNumber: String(order.orderNumber ?? ""),
|
|
62
70
|
total: String(order.total ?? ""),
|
|
@@ -64,7 +72,8 @@ function buildEventOrderTemplateVariables(input) {
|
|
|
64
72
|
lines: orderLines
|
|
65
73
|
};
|
|
66
74
|
return {
|
|
67
|
-
eventName: event.name ?? "",
|
|
75
|
+
eventName: event.name ?? productNames ?? "",
|
|
76
|
+
vendorName: vendorName.trim(),
|
|
68
77
|
eventSlug: event.slug ?? "",
|
|
69
78
|
venue: event.venue ?? "",
|
|
70
79
|
startDate: formatEventDate(event.startDate),
|
|
@@ -77,6 +86,9 @@ function buildEventOrderTemplateVariables(input) {
|
|
|
77
86
|
productNames,
|
|
78
87
|
trackUrl,
|
|
79
88
|
qrImageUrl,
|
|
89
|
+
ticketQr,
|
|
90
|
+
invoiceNumber,
|
|
91
|
+
invoiceUrl,
|
|
80
92
|
orderDetails: formatOrderDetailsText(orderDetailsPayload),
|
|
81
93
|
orderDetailsHtml: formatOrderDetailsHtml(orderDetailsPayload)
|
|
82
94
|
};
|
|
@@ -174,6 +186,25 @@ async function loadPrimaryEvent(dataSource, entityMap, itemRows) {
|
|
|
174
186
|
};
|
|
175
187
|
}
|
|
176
188
|
chunkUSNT2KNT_cjs.__name(loadPrimaryEvent, "loadPrimaryEvent");
|
|
189
|
+
async function isFeatureGroupEnabled(dataSource, entityMap, group) {
|
|
190
|
+
if (!entityMap.configs) return true;
|
|
191
|
+
try {
|
|
192
|
+
const rows = await dataSource.getRepository(entityMap.configs).find({
|
|
193
|
+
where: {
|
|
194
|
+
settings: group,
|
|
195
|
+
deleted: false
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
const settings = Object.fromEntries(rows.map((r) => [
|
|
199
|
+
r.key,
|
|
200
|
+
r.value
|
|
201
|
+
]));
|
|
202
|
+
return settings.enabled !== "false" && settings.enabled !== "0";
|
|
203
|
+
} catch {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
chunkUSNT2KNT_cjs.__name(isFeatureGroupEnabled, "isFeatureGroupEnabled");
|
|
177
208
|
async function loadOrderNotificationContexts(orderId, deps) {
|
|
178
209
|
if (!deps.entityMap.orders) return null;
|
|
179
210
|
const order = await deps.dataSource.getRepository(deps.entityMap.orders).findOne({
|
|
@@ -187,7 +218,16 @@ async function loadOrderNotificationContexts(orderId, deps) {
|
|
|
187
218
|
});
|
|
188
219
|
if (!order) return null;
|
|
189
220
|
const o = order;
|
|
190
|
-
const
|
|
221
|
+
const meta = o.metadata && typeof o.metadata === "object" && !Array.isArray(o.metadata) ? o.metadata : {};
|
|
222
|
+
const metaBuyerEmail = typeof meta.buyerEmail === "string" && meta.buyerEmail.includes("@") ? meta.buyerEmail.trim() : null;
|
|
223
|
+
const metaCheckoutEmail = typeof meta.checkoutEmail === "string" && meta.checkoutEmail.includes("@") ? meta.checkoutEmail.trim() : null;
|
|
224
|
+
const metaBuyerName = typeof meta.buyerName === "string" && meta.buyerName.trim() ? meta.buyerName.trim() : null;
|
|
225
|
+
const rawContact = o.contact ?? {};
|
|
226
|
+
const contact = {
|
|
227
|
+
name: metaBuyerName || rawContact.name,
|
|
228
|
+
email: metaBuyerEmail || metaCheckoutEmail || rawContact.email,
|
|
229
|
+
phone: rawContact.phone
|
|
230
|
+
};
|
|
191
231
|
const currency = String(o.currency ?? "INR");
|
|
192
232
|
const siteUrl = resolvePublicSiteUrl();
|
|
193
233
|
const itemRows = await deps.dataSource.getRepository(deps.entityMap.order_items).find({
|
|
@@ -205,8 +245,31 @@ async function loadOrderNotificationContexts(orderId, deps) {
|
|
|
205
245
|
const { event, productNames: eventProductNames } = await loadPrimaryEvent(deps.dataSource, deps.entityMap, itemRows);
|
|
206
246
|
const allProductNames = orderLines.map((line) => line.name);
|
|
207
247
|
const productNames = eventProductNames.length > 0 ? eventProductNames.join(", ") : allProductNames.join(", ");
|
|
208
|
-
const
|
|
209
|
-
|
|
248
|
+
const [multiVendorEnabled, eventsEnabled] = await Promise.all([
|
|
249
|
+
isFeatureGroupEnabled(deps.dataSource, deps.entityMap, "multi_vendor"),
|
|
250
|
+
isFeatureGroupEnabled(deps.dataSource, deps.entityMap, "events")
|
|
251
|
+
]);
|
|
252
|
+
let vendorName = "";
|
|
253
|
+
if (multiVendorEnabled) {
|
|
254
|
+
const vendorId = o.vendorId ?? event?.vendorId;
|
|
255
|
+
if (vendorId && deps.entityMap.vendors) {
|
|
256
|
+
try {
|
|
257
|
+
const vRow = await deps.dataSource.getRepository(deps.entityMap.vendors).findOne({
|
|
258
|
+
where: {
|
|
259
|
+
id: vendorId
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
if (vRow) {
|
|
263
|
+
const v = vRow;
|
|
264
|
+
vendorName = String(v.storeName?.trim() || v.name?.trim() || v.companyName?.trim() || "");
|
|
265
|
+
}
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const effectiveEvent = eventsEnabled ? event : void 0;
|
|
271
|
+
const variables = effectiveEvent ? buildEventOrderTemplateVariables({
|
|
272
|
+
event: effectiveEvent,
|
|
210
273
|
order: {
|
|
211
274
|
orderNumber: o.orderNumber,
|
|
212
275
|
total: o.total,
|
|
@@ -215,11 +278,12 @@ async function loadOrderNotificationContexts(orderId, deps) {
|
|
|
215
278
|
},
|
|
216
279
|
contact,
|
|
217
280
|
productNames,
|
|
281
|
+
vendorName,
|
|
218
282
|
orderLines,
|
|
219
283
|
siteUrl
|
|
220
284
|
}) : buildEventOrderTemplateVariables({
|
|
221
285
|
event: {
|
|
222
|
-
name: productNames || "Your order",
|
|
286
|
+
name: eventsEnabled ? productNames || "Your order" : "",
|
|
223
287
|
slug: "",
|
|
224
288
|
venue: "",
|
|
225
289
|
startDate: null
|
|
@@ -232,6 +296,7 @@ async function loadOrderNotificationContexts(orderId, deps) {
|
|
|
232
296
|
},
|
|
233
297
|
contact,
|
|
234
298
|
productNames,
|
|
299
|
+
vendorName,
|
|
235
300
|
orderLines,
|
|
236
301
|
siteUrl
|
|
237
302
|
});
|
|
@@ -439,7 +504,7 @@ var WhatsAppService = class {
|
|
|
439
504
|
let body = opts.body?.trim() ?? "";
|
|
440
505
|
const variables = opts.variables ?? {};
|
|
441
506
|
if (opts.templateKey?.trim() && this.getMessageTemplateRow) {
|
|
442
|
-
const { resolveEventOrderTemplate, EVENT_ORDER_TEMPLATE_KEY } = await import('./event-order-defaults-
|
|
507
|
+
const { resolveEventOrderTemplate, EVENT_ORDER_TEMPLATE_KEY } = await import('./event-order-defaults-7Z3UZOEH.cjs');
|
|
443
508
|
if (opts.templateKey.trim() === EVENT_ORDER_TEMPLATE_KEY) {
|
|
444
509
|
const resolved = await resolveEventOrderTemplate("whatsapp", async (ch, key) => {
|
|
445
510
|
const row = await this.getMessageTemplateRow(ch, key);
|
|
@@ -655,96 +720,6 @@ function renderLayout(options) {
|
|
|
655
720
|
}
|
|
656
721
|
chunkUSNT2KNT_cjs.__name(renderLayout, "renderLayout");
|
|
657
722
|
|
|
658
|
-
// src/plugins/email/templates/types.ts
|
|
659
|
-
function normalizeSocialLinkItem(o) {
|
|
660
|
-
const url = String(o.url ?? "").trim();
|
|
661
|
-
if (!url) return null;
|
|
662
|
-
let iconUrl = String(o.iconUrl ?? o.icon_image ?? "").trim();
|
|
663
|
-
let icon = String(o.icon ?? "").trim();
|
|
664
|
-
if (!iconUrl && /^https?:\/\//i.test(icon)) {
|
|
665
|
-
iconUrl = icon;
|
|
666
|
-
icon = "";
|
|
667
|
-
}
|
|
668
|
-
const item = {
|
|
669
|
-
url
|
|
670
|
-
};
|
|
671
|
-
if (iconUrl) item.iconUrl = iconUrl;
|
|
672
|
-
if (icon) item.icon = icon;
|
|
673
|
-
return item;
|
|
674
|
-
}
|
|
675
|
-
chunkUSNT2KNT_cjs.__name(normalizeSocialLinkItem, "normalizeSocialLinkItem");
|
|
676
|
-
function parseSocialLinksJson(raw) {
|
|
677
|
-
if (raw == null || raw.trim() === "") return void 0;
|
|
678
|
-
try {
|
|
679
|
-
const parsed = JSON.parse(raw);
|
|
680
|
-
if (!Array.isArray(parsed)) return void 0;
|
|
681
|
-
const out = [];
|
|
682
|
-
for (const item of parsed) {
|
|
683
|
-
if (item && typeof item === "object" && "url" in item) {
|
|
684
|
-
const n = normalizeSocialLinkItem(item);
|
|
685
|
-
if (n) out.push(n);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
return out.length ? out : void 0;
|
|
689
|
-
} catch {
|
|
690
|
-
return void 0;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
chunkUSNT2KNT_cjs.__name(parseSocialLinksJson, "parseSocialLinksJson");
|
|
694
|
-
function mergeEmailLayoutCompanyDetails(branding, emailSettings) {
|
|
695
|
-
const fromBranding = getCompanyDetailsFromSettings(branding);
|
|
696
|
-
const pick2 = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name((emailVal, fallback) => {
|
|
697
|
-
const t = emailVal?.trim();
|
|
698
|
-
return t || fallback?.trim() || void 0;
|
|
699
|
-
}, "pick");
|
|
700
|
-
const logoUrl = pick2(emailSettings.logoUrl ?? emailSettings.emailLogoUrl, fromBranding.logoUrl);
|
|
701
|
-
const companyName = pick2(emailSettings.companyName ?? emailSettings.emailCompanyName, fromBranding.companyName);
|
|
702
|
-
const supportEmail = pick2(emailSettings.supportEmail ?? emailSettings.emailSupportEmail, fromBranding.supportEmail);
|
|
703
|
-
const supportPhone = pick2(emailSettings.supportPhone, void 0);
|
|
704
|
-
const footerDisclaimer = pick2(emailSettings.footerDisclaimer, void 0);
|
|
705
|
-
const followUsTitle = pick2(emailSettings.followUsTitle, "Follow Us") || "Follow Us";
|
|
706
|
-
const socialFromEmail = parseSocialLinksJson(emailSettings.socialLinks);
|
|
707
|
-
const socialLinks = socialFromEmail?.length ? socialFromEmail : fromBranding.socialLinks;
|
|
708
|
-
return {
|
|
709
|
-
logoUrl,
|
|
710
|
-
companyName,
|
|
711
|
-
supportEmail,
|
|
712
|
-
supportPhone,
|
|
713
|
-
socialLinks,
|
|
714
|
-
footerDisclaimer,
|
|
715
|
-
followUsTitle
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
chunkUSNT2KNT_cjs.__name(mergeEmailLayoutCompanyDetails, "mergeEmailLayoutCompanyDetails");
|
|
719
|
-
function getCompanyDetailsFromSettings(settingsGroup) {
|
|
720
|
-
const logoUrl = settingsGroup.logo ?? settingsGroup.logoUrl ?? "";
|
|
721
|
-
const companyName = settingsGroup.companyName ?? settingsGroup.company_name ?? "";
|
|
722
|
-
const supportEmail = settingsGroup.supportEmail ?? settingsGroup.support_email ?? "";
|
|
723
|
-
let socialLinks = [];
|
|
724
|
-
const raw = settingsGroup.socialLinks ?? settingsGroup.social_links;
|
|
725
|
-
if (typeof raw === "string") {
|
|
726
|
-
try {
|
|
727
|
-
const arr = JSON.parse(raw);
|
|
728
|
-
if (Array.isArray(arr)) {
|
|
729
|
-
for (const item of arr) {
|
|
730
|
-
if (item && typeof item === "object") {
|
|
731
|
-
const n = normalizeSocialLinkItem(item);
|
|
732
|
-
if (n) socialLinks.push(n);
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
} catch {
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
return {
|
|
740
|
-
logoUrl: logoUrl || void 0,
|
|
741
|
-
companyName: companyName || void 0,
|
|
742
|
-
supportEmail: supportEmail || void 0,
|
|
743
|
-
socialLinks: socialLinks.length ? socialLinks : void 0
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
chunkUSNT2KNT_cjs.__name(getCompanyDetailsFromSettings, "getCompanyDetailsFromSettings");
|
|
747
|
-
|
|
748
723
|
// src/plugins/email/templates/inline-cta.ts
|
|
749
724
|
function escapeHtml2(s) {
|
|
750
725
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -949,7 +924,7 @@ function renderAddressesText(billing, shipping) {
|
|
|
949
924
|
}
|
|
950
925
|
chunkUSNT2KNT_cjs.__name(renderAddressesText, "renderAddressesText");
|
|
951
926
|
function render4(ctx) {
|
|
952
|
-
const { orderNumber, total, subtotal, tax, currency, customerName, companyDetails, audience = "customer", internalCustomerEmail, lineItems = [], billingAddress, shippingAddress } = ctx;
|
|
927
|
+
const { orderNumber, total, subtotal, tax, currency, customerName, companyDetails, audience = "customer", internalCustomerEmail, lineItems = [], billingAddress, shippingAddress, invoiceAttached = false } = ctx;
|
|
953
928
|
const itemsHtml = renderLineItemsHtml(lineItems, currency);
|
|
954
929
|
const itemsText = renderLineItemsText(lineItems, currency);
|
|
955
930
|
const addrHtml = renderAddressesHtml(billingAddress, shippingAddress);
|
|
@@ -988,6 +963,7 @@ ${subtotalLine}${taxLine}${totalLine}`;
|
|
|
988
963
|
${addrHtml}
|
|
989
964
|
${itemsHtml}
|
|
990
965
|
${subtotalLine}${taxLine}${totalLine}
|
|
966
|
+
${invoiceAttached ? `<p style="margin:16px 0 0 0;font-size:14px;line-height:1.5;color:#333;">Your order invoice is attached as a PDF.</p>` : ""}
|
|
991
967
|
<p style="margin:16px 0 0 0;font-size:13px;line-height:1.5;color:#666;">If you have questions, reply to this email or contact us using the details below.</p>`;
|
|
992
968
|
text = [
|
|
993
969
|
`Order confirmed #${orderNumber}`,
|
|
@@ -998,6 +974,7 @@ ${subtotalLine}${taxLine}${totalLine}
|
|
|
998
974
|
subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ""}` : "",
|
|
999
975
|
tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ""}` : "",
|
|
1000
976
|
total != null ? `Order total: ${total}${currency ? ` ${currency}` : ""}` : "",
|
|
977
|
+
invoiceAttached ? "Your order invoice is attached as a PDF." : "",
|
|
1001
978
|
"",
|
|
1002
979
|
"We will process your order shortly."
|
|
1003
980
|
].filter((line, i, arr) => !(line === "" && arr[i - 1] === "")).join("\n");
|
|
@@ -1226,6 +1203,19 @@ ${slugNote}
|
|
|
1226
1203
|
`Owner / invitee: ${ownerName?.trim() || "\u2014"} (${ownerEmail})`,
|
|
1227
1204
|
`Activation: ${activation === "invite" ? "Invitation" : "Password set"}`
|
|
1228
1205
|
].filter(Boolean).join("\n");
|
|
1206
|
+
} else if (kind === "team_invite" && activation === "membership" && inviteLink) {
|
|
1207
|
+
subject = `You're invited to ${storeLabel}`;
|
|
1208
|
+
bodyHtml = `<p style="margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;">${greeting}</p>
|
|
1209
|
+
<p style="margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;">You have been invited to join the vendor team for <strong>${escapeHtml2(storeLabel)}</strong>. You already have an account \u2014 accept below to join this store. You will not need to set a new password.</p>
|
|
1210
|
+
${primaryCtaButton(inviteLink, "Accept invitation")}
|
|
1211
|
+
<p style="margin:16px 0 0 0;font-size:12px;line-height:1.5;color:#888;">If the button does not work, copy and paste this URL into your browser:<br/><span style="word-break:break-all;">${escapeHtml2(inviteLink)}</span></p>`;
|
|
1212
|
+
text = [
|
|
1213
|
+
ownerName?.trim() ? `Hello ${ownerName.trim()},` : "Hello,",
|
|
1214
|
+
"",
|
|
1215
|
+
`You have been invited to join ${storeLabel}.`,
|
|
1216
|
+
"Open this link to accept (no new password required):",
|
|
1217
|
+
inviteLink
|
|
1218
|
+
].join("\n");
|
|
1229
1219
|
} else if (kind === "team_invite" && activation === "invite" && inviteLink) {
|
|
1230
1220
|
subject = `You're invited to ${storeLabel}`;
|
|
1231
1221
|
bodyHtml = `<p style="margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;">${greeting}</p>
|
|
@@ -1326,6 +1316,8 @@ function renderEmail(templateName, ctx, options) {
|
|
|
1326
1316
|
chunkUSNT2KNT_cjs.__name(renderEmail, "renderEmail");
|
|
1327
1317
|
|
|
1328
1318
|
// src/plugins/email/email-service.ts
|
|
1319
|
+
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-LMJ7RKPF.cjs', document.baseURI).href)));
|
|
1320
|
+
var MailComposer = require2("nodemailer/lib/mail-composer");
|
|
1329
1321
|
var SES_REGIONS_WITHOUT_SMTP = /* @__PURE__ */ new Set([
|
|
1330
1322
|
"af-south-1",
|
|
1331
1323
|
"ap-south-2",
|
|
@@ -1346,6 +1338,10 @@ function sesRegionSupportsSmtp(region) {
|
|
|
1346
1338
|
return !SES_REGIONS_WITHOUT_SMTP.has(region.trim());
|
|
1347
1339
|
}
|
|
1348
1340
|
chunkUSNT2KNT_cjs.__name(sesRegionSupportsSmtp, "sesRegionSupportsSmtp");
|
|
1341
|
+
function toBuffer(content) {
|
|
1342
|
+
return Buffer.isBuffer(content) ? content : Buffer.from(content);
|
|
1343
|
+
}
|
|
1344
|
+
chunkUSNT2KNT_cjs.__name(toBuffer, "toBuffer");
|
|
1349
1345
|
var EmailService = class {
|
|
1350
1346
|
static {
|
|
1351
1347
|
chunkUSNT2KNT_cjs.__name(this, "EmailService");
|
|
@@ -1409,14 +1405,47 @@ var EmailService = class {
|
|
|
1409
1405
|
throw new Error(`Unsupported email type: ${config.type}`);
|
|
1410
1406
|
}
|
|
1411
1407
|
}
|
|
1408
|
+
nodemailerAttachments(attachments) {
|
|
1409
|
+
if (!attachments?.length) return void 0;
|
|
1410
|
+
return attachments.map((a) => ({
|
|
1411
|
+
filename: a.filename,
|
|
1412
|
+
content: toBuffer(a.content),
|
|
1413
|
+
contentType: a.contentType || "application/octet-stream"
|
|
1414
|
+
}));
|
|
1415
|
+
}
|
|
1412
1416
|
async send(emailData) {
|
|
1413
1417
|
try {
|
|
1418
|
+
const from = emailData.from || this.config.from;
|
|
1419
|
+
const to = emailData.to || this.config.to;
|
|
1420
|
+
const attachments = this.nodemailerAttachments(emailData.attachments);
|
|
1414
1421
|
if (this.config.type === "AWS" && this.sesClient) {
|
|
1422
|
+
if (attachments?.length) {
|
|
1423
|
+
const composer = new MailComposer({
|
|
1424
|
+
from,
|
|
1425
|
+
to,
|
|
1426
|
+
subject: emailData.subject,
|
|
1427
|
+
html: emailData.html,
|
|
1428
|
+
text: emailData.text,
|
|
1429
|
+
attachments
|
|
1430
|
+
});
|
|
1431
|
+
const raw = await new Promise((resolve, reject) => {
|
|
1432
|
+
composer.compile().build((err, message) => {
|
|
1433
|
+
if (err) reject(err);
|
|
1434
|
+
else resolve(message);
|
|
1435
|
+
});
|
|
1436
|
+
});
|
|
1437
|
+
await this.sesClient.send(new clientSes.SendRawEmailCommand({
|
|
1438
|
+
RawMessage: {
|
|
1439
|
+
Data: raw
|
|
1440
|
+
}
|
|
1441
|
+
}));
|
|
1442
|
+
return true;
|
|
1443
|
+
}
|
|
1415
1444
|
await this.sesClient.send(new clientSes.SendEmailCommand({
|
|
1416
|
-
Source:
|
|
1445
|
+
Source: from,
|
|
1417
1446
|
Destination: {
|
|
1418
1447
|
ToAddresses: [
|
|
1419
|
-
|
|
1448
|
+
to
|
|
1420
1449
|
]
|
|
1421
1450
|
},
|
|
1422
1451
|
Message: {
|
|
@@ -1442,11 +1471,12 @@ var EmailService = class {
|
|
|
1442
1471
|
}
|
|
1443
1472
|
if (this.transporter && (this.config.type === "SMTP" || this.config.type === "GMAIL" || this.config.type === "AWS" && this.awsViaSmtp)) {
|
|
1444
1473
|
await this.transporter.sendMail({
|
|
1445
|
-
from
|
|
1446
|
-
to
|
|
1474
|
+
from,
|
|
1475
|
+
to,
|
|
1447
1476
|
subject: emailData.subject,
|
|
1448
1477
|
html: emailData.html,
|
|
1449
|
-
text: emailData.text
|
|
1478
|
+
text: emailData.text,
|
|
1479
|
+
attachments
|
|
1450
1480
|
});
|
|
1451
1481
|
return true;
|
|
1452
1482
|
}
|
|
@@ -1930,14 +1960,14 @@ async function sendChatLeadEmail(cms, emailSettings, brandingSettings, input) {
|
|
|
1930
1960
|
recipients,
|
|
1931
1961
|
source: input.recipients?.length ? "intent_email_to" : "crm_or_smtp_fallback"
|
|
1932
1962
|
});
|
|
1933
|
-
const companyDetails = mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
|
|
1963
|
+
const companyDetails = chunkBXYZDMTZ_cjs.mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
|
|
1934
1964
|
const ctx = {
|
|
1935
1965
|
...input,
|
|
1936
1966
|
companyDetails: input.companyDetails ?? companyDetails
|
|
1937
1967
|
};
|
|
1938
1968
|
let anySent = false;
|
|
1939
1969
|
for (const to of recipients) {
|
|
1940
|
-
await
|
|
1970
|
+
await chunkV25RDUOU_cjs.queueEmail(cms, {
|
|
1941
1971
|
to,
|
|
1942
1972
|
templateName: "chatLead",
|
|
1943
1973
|
ctx
|
|
@@ -2061,11 +2091,18 @@ async function getSettingsGroup(dataSource, entityMap, group) {
|
|
|
2061
2091
|
]));
|
|
2062
2092
|
}
|
|
2063
2093
|
chunkUSNT2KNT_cjs.__name(getSettingsGroup, "getSettingsGroup");
|
|
2064
|
-
async function
|
|
2094
|
+
async function isEmailNotificationsEnabled(dataSource, entityMap) {
|
|
2065
2095
|
const settings = await getSettingsGroup(dataSource, entityMap, "event_notifications");
|
|
2066
|
-
|
|
2096
|
+
if (settings.enabled === "false" || settings.enabled === "0") return false;
|
|
2097
|
+
return settings.email_enabled !== "false" && settings.email_enabled !== "0";
|
|
2067
2098
|
}
|
|
2068
|
-
chunkUSNT2KNT_cjs.__name(
|
|
2099
|
+
chunkUSNT2KNT_cjs.__name(isEmailNotificationsEnabled, "isEmailNotificationsEnabled");
|
|
2100
|
+
async function isWhatsappNotificationsEnabled(dataSource, entityMap) {
|
|
2101
|
+
const settings = await getSettingsGroup(dataSource, entityMap, "event_notifications");
|
|
2102
|
+
if (settings.enabled === "false" || settings.enabled === "0") return false;
|
|
2103
|
+
return settings.whatsapp_enabled !== "false" && settings.whatsapp_enabled !== "0";
|
|
2104
|
+
}
|
|
2105
|
+
chunkUSNT2KNT_cjs.__name(isWhatsappNotificationsEnabled, "isWhatsappNotificationsEnabled");
|
|
2069
2106
|
async function isTriggerCatalogEnabled(triggerKey, dataSource, entityMap) {
|
|
2070
2107
|
if (!entityMap.order_notification_triggers) {
|
|
2071
2108
|
console.warn("[order-notifications] order_notification_triggers missing \u2014 run migration 1781230000000-AddOrderNotificationTriggers");
|
|
@@ -2093,22 +2130,34 @@ async function isTriggerCatalogEnabled(triggerKey, dataSource, entityMap) {
|
|
|
2093
2130
|
}
|
|
2094
2131
|
}
|
|
2095
2132
|
chunkUSNT2KNT_cjs.__name(isTriggerCatalogEnabled, "isTriggerCatalogEnabled");
|
|
2096
|
-
async function loadBoundTemplate(triggerKey, channel, dataSource, entityMap) {
|
|
2133
|
+
async function loadBoundTemplate(triggerKey, channel, audienceType = "customers", dataSource, entityMap) {
|
|
2097
2134
|
if (!entityMap.order_notification_bindings || !entityMap.message_templates) {
|
|
2098
2135
|
console.warn("[order-notifications] order_notification_bindings or message_templates missing from entityMap");
|
|
2099
2136
|
return null;
|
|
2100
2137
|
}
|
|
2101
|
-
const
|
|
2138
|
+
const bindingRepo = dataSource.getRepository(entityMap.order_notification_bindings);
|
|
2139
|
+
let binding = await bindingRepo.findOne({
|
|
2102
2140
|
where: {
|
|
2103
2141
|
triggerKey,
|
|
2104
2142
|
channel,
|
|
2143
|
+
type: audienceType,
|
|
2105
2144
|
enabled: true
|
|
2106
2145
|
}
|
|
2107
2146
|
});
|
|
2147
|
+
if (!binding && audienceType === "customers") {
|
|
2148
|
+
binding = await bindingRepo.findOne({
|
|
2149
|
+
where: {
|
|
2150
|
+
triggerKey,
|
|
2151
|
+
channel,
|
|
2152
|
+
enabled: true
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2108
2156
|
if (!binding) {
|
|
2109
2157
|
console.warn("[order-notifications] no order_notification_bindings row", {
|
|
2110
2158
|
triggerKey,
|
|
2111
|
-
channel
|
|
2159
|
+
channel,
|
|
2160
|
+
audienceType
|
|
2112
2161
|
});
|
|
2113
2162
|
return null;
|
|
2114
2163
|
}
|
|
@@ -2116,7 +2165,8 @@ async function loadBoundTemplate(triggerKey, channel, dataSource, entityMap) {
|
|
|
2116
2165
|
if (templateId == null) {
|
|
2117
2166
|
console.warn("[order-notifications] binding exists but no template selected", {
|
|
2118
2167
|
triggerKey,
|
|
2119
|
-
channel
|
|
2168
|
+
channel,
|
|
2169
|
+
audienceType
|
|
2120
2170
|
});
|
|
2121
2171
|
return null;
|
|
2122
2172
|
}
|
|
@@ -2132,6 +2182,7 @@ async function loadBoundTemplate(triggerKey, channel, dataSource, entityMap) {
|
|
|
2132
2182
|
console.warn("[order-notifications] bound template not found or disabled", {
|
|
2133
2183
|
triggerKey,
|
|
2134
2184
|
channel,
|
|
2185
|
+
audienceType,
|
|
2135
2186
|
templateId
|
|
2136
2187
|
});
|
|
2137
2188
|
return null;
|
|
@@ -2159,36 +2210,172 @@ function mergeTriggerVariables(payload, rich) {
|
|
|
2159
2210
|
};
|
|
2160
2211
|
}
|
|
2161
2212
|
chunkUSNT2KNT_cjs.__name(mergeTriggerVariables, "mergeTriggerVariables");
|
|
2162
|
-
async function
|
|
2163
|
-
const
|
|
2213
|
+
async function isAudienceEmailEnabled(dataSource, entityMap, audience) {
|
|
2214
|
+
const settings = await getSettingsGroup(dataSource, entityMap, "event_notifications");
|
|
2215
|
+
if (settings.enabled === "false" || settings.enabled === "0") return false;
|
|
2216
|
+
if (settings.email_enabled === "false" || settings.email_enabled === "0") return false;
|
|
2217
|
+
const key = `email_${audience}_enabled`;
|
|
2218
|
+
return settings[key] !== "false" && settings[key] !== "0";
|
|
2219
|
+
}
|
|
2220
|
+
chunkUSNT2KNT_cjs.__name(isAudienceEmailEnabled, "isAudienceEmailEnabled");
|
|
2221
|
+
async function getOrderVendorEmails(orderId, orderVendorId, dataSource, entityMap) {
|
|
2222
|
+
const emails = /* @__PURE__ */ new Set();
|
|
2223
|
+
if (!entityMap.vendors) return [];
|
|
2224
|
+
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
2225
|
+
if (orderVendorId) {
|
|
2226
|
+
try {
|
|
2227
|
+
const v = await vendorRepo.findOne({
|
|
2228
|
+
where: {
|
|
2229
|
+
id: orderVendorId
|
|
2230
|
+
}
|
|
2231
|
+
});
|
|
2232
|
+
if (v) {
|
|
2233
|
+
const row = v;
|
|
2234
|
+
if (row.email?.trim()) emails.add(row.email.trim());
|
|
2235
|
+
if (row.supportEmail?.trim()) emails.add(row.supportEmail.trim());
|
|
2236
|
+
}
|
|
2237
|
+
} catch {
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
if (entityMap.order_items) {
|
|
2241
|
+
try {
|
|
2242
|
+
const items = await dataSource.getRepository(entityMap.order_items).find({
|
|
2243
|
+
where: {
|
|
2244
|
+
orderId
|
|
2245
|
+
},
|
|
2246
|
+
relations: [
|
|
2247
|
+
"product"
|
|
2248
|
+
]
|
|
2249
|
+
});
|
|
2250
|
+
for (const item of items) {
|
|
2251
|
+
const row = item;
|
|
2252
|
+
const vId = row.product?.vendorId;
|
|
2253
|
+
if (vId && vId !== orderVendorId) {
|
|
2254
|
+
const v = await vendorRepo.findOne({
|
|
2255
|
+
where: {
|
|
2256
|
+
id: vId
|
|
2257
|
+
}
|
|
2258
|
+
});
|
|
2259
|
+
if (v) {
|
|
2260
|
+
const vRow = v;
|
|
2261
|
+
if (vRow.email?.trim()) emails.add(vRow.email.trim());
|
|
2262
|
+
if (vRow.supportEmail?.trim()) emails.add(vRow.supportEmail.trim());
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
} catch {
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
return Array.from(emails);
|
|
2270
|
+
}
|
|
2271
|
+
chunkUSNT2KNT_cjs.__name(getOrderVendorEmails, "getOrderVendorEmails");
|
|
2272
|
+
async function getAdminRecipientEmails(dataSource, entityMap) {
|
|
2273
|
+
const emails = /* @__PURE__ */ new Set();
|
|
2274
|
+
const emailSettings = await getSettingsGroup(dataSource, entityMap, "email");
|
|
2275
|
+
const rawRecipients = [
|
|
2276
|
+
emailSettings.salesTeamEmails,
|
|
2277
|
+
emailSettings.salesTeamEmail,
|
|
2278
|
+
emailSettings.fulfilmentTeamEmails,
|
|
2279
|
+
emailSettings.fulfilmentTeamEmail,
|
|
2280
|
+
emailSettings.adminEmail
|
|
2281
|
+
];
|
|
2282
|
+
for (const raw of rawRecipients) {
|
|
2283
|
+
if (!raw) continue;
|
|
2284
|
+
const parts = String(raw).split(/[,;]/);
|
|
2285
|
+
for (const p of parts) {
|
|
2286
|
+
const trimmed = p.trim();
|
|
2287
|
+
if (trimmed && trimmed.includes("@")) emails.add(trimmed.toLowerCase());
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
if (entityMap.users) {
|
|
2291
|
+
try {
|
|
2292
|
+
const userRepo = dataSource.getRepository(entityMap.users);
|
|
2293
|
+
const adminUsers = await userRepo.find({
|
|
2294
|
+
where: [
|
|
2295
|
+
{
|
|
2296
|
+
groupId: 1,
|
|
2297
|
+
blocked: false
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
adminAccess: true,
|
|
2301
|
+
blocked: false
|
|
2302
|
+
}
|
|
2303
|
+
]
|
|
2304
|
+
});
|
|
2305
|
+
for (const u of adminUsers) {
|
|
2306
|
+
const em = u.email?.trim().toLowerCase();
|
|
2307
|
+
if (em && em.includes("@")) {
|
|
2308
|
+
emails.add(em);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
} catch {
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
try {
|
|
2315
|
+
const rows = await dataSource.query(`SELECT DISTINCT LOWER(TRIM(email)) AS email
|
|
2316
|
+
FROM users
|
|
2317
|
+
WHERE ("groupId" = 1 OR "adminAccess" = true)
|
|
2318
|
+
AND COALESCE(blocked, false) = false
|
|
2319
|
+
AND COALESCE(deleted, false) = false
|
|
2320
|
+
AND "deletedAt" IS NULL`);
|
|
2321
|
+
for (const r of rows) {
|
|
2322
|
+
const em = r.email?.trim().toLowerCase();
|
|
2323
|
+
if (em && em.includes("@")) {
|
|
2324
|
+
emails.add(em);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
} catch {
|
|
2328
|
+
}
|
|
2329
|
+
return Array.from(emails);
|
|
2330
|
+
}
|
|
2331
|
+
chunkUSNT2KNT_cjs.__name(getAdminRecipientEmails, "getAdminRecipientEmails");
|
|
2332
|
+
function formatBodyForEmailHtml(body) {
|
|
2333
|
+
if (!body) return "";
|
|
2334
|
+
if (/^\s*<(html|body|table|section)[\s>]/i.test(body.trim())) {
|
|
2335
|
+
return body;
|
|
2336
|
+
}
|
|
2337
|
+
const withBreaks = body.replace(/\r\n/g, "\n").replace(/\n/g, "<br />");
|
|
2338
|
+
return `<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 15px; line-height: 1.6; color: #1f2937;">${withBreaks}</div>`;
|
|
2339
|
+
}
|
|
2340
|
+
chunkUSNT2KNT_cjs.__name(formatBodyForEmailHtml, "formatBodyForEmailHtml");
|
|
2341
|
+
async function sendEmailForTrigger(triggerKey, orderId, audienceType, variables, contactEmail, dataSource, entityMap, getCms) {
|
|
2342
|
+
const template = await loadBoundTemplate(triggerKey, "email", audienceType, dataSource, entityMap);
|
|
2164
2343
|
if (!template) return;
|
|
2165
2344
|
const [branding, emailSettings] = await Promise.all([
|
|
2166
2345
|
getSettingsGroup(dataSource, entityMap, "branding"),
|
|
2167
2346
|
getSettingsGroup(dataSource, entityMap, "email")
|
|
2168
2347
|
]);
|
|
2169
|
-
const companyDetails = mergeEmailLayoutCompanyDetails(branding, emailSettings);
|
|
2348
|
+
const companyDetails = chunkBXYZDMTZ_cjs.mergeEmailLayoutCompanyDetails(branding, emailSettings);
|
|
2170
2349
|
const subject = chunkOOTLNH63_cjs.applyTemplateVars(template.subject ?? "Order update", variables);
|
|
2171
|
-
const
|
|
2350
|
+
const rawBody = chunkOOTLNH63_cjs.applyTemplateVars(template.body, variables);
|
|
2351
|
+
const bodyHtml = formatBodyForEmailHtml(rawBody);
|
|
2172
2352
|
const html = renderLayout({
|
|
2173
2353
|
bodyHtml,
|
|
2174
2354
|
companyDetails
|
|
2175
2355
|
});
|
|
2176
2356
|
const cms = await getCms();
|
|
2177
|
-
|
|
2357
|
+
const isCustomer = audienceType === "customers";
|
|
2358
|
+
await chunkV25RDUOU_cjs.queueEmail(cms, {
|
|
2178
2359
|
to: contactEmail,
|
|
2179
2360
|
subject,
|
|
2180
2361
|
html,
|
|
2181
|
-
text:
|
|
2362
|
+
text: rawBody.replace(/<[^>]+>/g, "").trim(),
|
|
2363
|
+
...isCustomer ? {
|
|
2364
|
+
orderId,
|
|
2365
|
+
attachInvoice: true
|
|
2366
|
+
} : {}
|
|
2182
2367
|
});
|
|
2183
2368
|
console.log("[order-notifications] email queued", {
|
|
2184
2369
|
triggerKey,
|
|
2370
|
+
audienceType,
|
|
2185
2371
|
orderId,
|
|
2186
|
-
to: contactEmail
|
|
2372
|
+
to: contactEmail,
|
|
2373
|
+
attachInvoice: isCustomer
|
|
2187
2374
|
});
|
|
2188
2375
|
}
|
|
2189
2376
|
chunkUSNT2KNT_cjs.__name(sendEmailForTrigger, "sendEmailForTrigger");
|
|
2190
2377
|
async function sendWhatsAppForTrigger(triggerKey, orderId, phone, variables, dataSource, entityMap, getCms) {
|
|
2191
|
-
const template = await loadBoundTemplate(triggerKey, "whatsapp", dataSource, entityMap);
|
|
2378
|
+
const template = await loadBoundTemplate(triggerKey, "whatsapp", "customers", dataSource, entityMap);
|
|
2192
2379
|
if (!template) return;
|
|
2193
2380
|
const paramOrder = template.providerMeta?.paramOrder ?? [];
|
|
2194
2381
|
if (paramOrder.length === 0) {
|
|
@@ -2232,15 +2419,73 @@ async function sendWhatsAppForTrigger(triggerKey, orderId, phone, variables, dat
|
|
|
2232
2419
|
}
|
|
2233
2420
|
}
|
|
2234
2421
|
chunkUSNT2KNT_cjs.__name(sendWhatsAppForTrigger, "sendWhatsAppForTrigger");
|
|
2422
|
+
async function isOrderPaymentConfirmed(orderId, dataSource, entityMap) {
|
|
2423
|
+
if (!entityMap.orders) return true;
|
|
2424
|
+
try {
|
|
2425
|
+
const orderRepo = dataSource.getRepository(entityMap.orders);
|
|
2426
|
+
const order = await orderRepo.findOne({
|
|
2427
|
+
where: {
|
|
2428
|
+
id: orderId
|
|
2429
|
+
}
|
|
2430
|
+
});
|
|
2431
|
+
if (!order) return false;
|
|
2432
|
+
const o = order;
|
|
2433
|
+
const status = String(o.status ?? "").toLowerCase().trim();
|
|
2434
|
+
const total = Number(o.total ?? 0);
|
|
2435
|
+
if (total <= 0) return true;
|
|
2436
|
+
const confirmedStatuses = [
|
|
2437
|
+
"confirmed",
|
|
2438
|
+
"completed",
|
|
2439
|
+
"processing",
|
|
2440
|
+
"paid",
|
|
2441
|
+
"fulfilled",
|
|
2442
|
+
"shipped"
|
|
2443
|
+
];
|
|
2444
|
+
if (confirmedStatuses.includes(status)) {
|
|
2445
|
+
return true;
|
|
2446
|
+
}
|
|
2447
|
+
if (entityMap.payments) {
|
|
2448
|
+
const paymentRepo = dataSource.getRepository(entityMap.payments);
|
|
2449
|
+
const payment = await paymentRepo.findOne({
|
|
2450
|
+
where: {
|
|
2451
|
+
orderId
|
|
2452
|
+
}
|
|
2453
|
+
});
|
|
2454
|
+
if (payment) {
|
|
2455
|
+
const pStatus = String(payment.status ?? "").toLowerCase().trim();
|
|
2456
|
+
if (pStatus === "paid" || pStatus === "captured" || pStatus === "completed") {
|
|
2457
|
+
return true;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
return false;
|
|
2462
|
+
} catch (err) {
|
|
2463
|
+
console.error("[order-notifications] failed to check order payment confirmation", err);
|
|
2464
|
+
return false;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
chunkUSNT2KNT_cjs.__name(isOrderPaymentConfirmed, "isOrderPaymentConfirmed");
|
|
2235
2468
|
async function handleTrigger(triggerKey, payload, dataSource, entityMap, getCms) {
|
|
2236
2469
|
console.log("[order-notifications] received", {
|
|
2237
2470
|
triggerKey,
|
|
2238
2471
|
orderId: payload.orderId,
|
|
2239
2472
|
phone: maskPhone3(payload.customerPhone)
|
|
2240
2473
|
});
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2474
|
+
if (triggerKey === "order_placed") {
|
|
2475
|
+
const isConfirmed = await isOrderPaymentConfirmed(payload.orderId, dataSource, entityMap);
|
|
2476
|
+
if (!isConfirmed) {
|
|
2477
|
+
console.log("[order-notifications] skip order_placed: order payment not confirmed yet", {
|
|
2478
|
+
orderId: payload.orderId
|
|
2479
|
+
});
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
const [emailChannelEnabled, whatsappChannelEnabled] = await Promise.all([
|
|
2484
|
+
isEmailNotificationsEnabled(dataSource, entityMap),
|
|
2485
|
+
isWhatsappNotificationsEnabled(dataSource, entityMap)
|
|
2486
|
+
]);
|
|
2487
|
+
if (!emailChannelEnabled && !whatsappChannelEnabled) {
|
|
2488
|
+
console.warn("[order-notifications] skip: Both Email and WhatsApp notifications are disabled");
|
|
2244
2489
|
return;
|
|
2245
2490
|
}
|
|
2246
2491
|
const triggerEnabled = await isTriggerCatalogEnabled(triggerKey, dataSource, entityMap);
|
|
@@ -2252,21 +2497,44 @@ async function handleTrigger(triggerKey, payload, dataSource, entityMap, getCms)
|
|
|
2252
2497
|
const variables = mergeTriggerVariables(payload, context?.variables);
|
|
2253
2498
|
const contactEmail = context?.contact.email?.trim() || "";
|
|
2254
2499
|
const contactPhone = context?.contact.phone?.trim() || payload.customerPhone?.trim() || "";
|
|
2255
|
-
if (
|
|
2256
|
-
|
|
2500
|
+
if (emailChannelEnabled) {
|
|
2501
|
+
const [customerEnabled, vendorEnabled, adminEnabled] = await Promise.all([
|
|
2502
|
+
isAudienceEmailEnabled(dataSource, entityMap, "customer"),
|
|
2503
|
+
isAudienceEmailEnabled(dataSource, entityMap, "vendor"),
|
|
2504
|
+
isAudienceEmailEnabled(dataSource, entityMap, "admin")
|
|
2505
|
+
]);
|
|
2506
|
+
if (customerEnabled && contactEmail) {
|
|
2507
|
+
await sendEmailForTrigger(triggerKey, payload.orderId, "customers", variables, contactEmail, dataSource, entityMap, getCms);
|
|
2508
|
+
}
|
|
2509
|
+
if (vendorEnabled) {
|
|
2510
|
+
const multiVendorSettings = await getSettingsGroup(dataSource, entityMap, "multi_vendor");
|
|
2511
|
+
if (multiVendorSettings.enabled !== "false" && multiVendorSettings.enabled !== "0") {
|
|
2512
|
+
const vendorEmails = await getOrderVendorEmails(payload.orderId, payload.vendorId, dataSource, entityMap);
|
|
2513
|
+
for (const vEmail of vendorEmails) {
|
|
2514
|
+
await sendEmailForTrigger(triggerKey, payload.orderId, "vendors", variables, vEmail, dataSource, entityMap, getCms);
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
if (adminEnabled) {
|
|
2519
|
+
const adminEmails = await getAdminRecipientEmails(dataSource, entityMap);
|
|
2520
|
+
for (const aEmail of adminEmails) {
|
|
2521
|
+
await sendEmailForTrigger(triggerKey, payload.orderId, "admin", variables, aEmail, dataSource, entityMap, getCms);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2257
2524
|
} else {
|
|
2258
|
-
console.
|
|
2259
|
-
triggerKey,
|
|
2260
|
-
orderId: payload.orderId
|
|
2261
|
-
});
|
|
2525
|
+
console.log("[order-notifications] skip email: Email notifications channel is disabled");
|
|
2262
2526
|
}
|
|
2263
|
-
if (
|
|
2264
|
-
|
|
2527
|
+
if (whatsappChannelEnabled) {
|
|
2528
|
+
if (contactPhone) {
|
|
2529
|
+
await sendWhatsAppForTrigger(triggerKey, payload.orderId, contactPhone, variables, dataSource, entityMap, getCms);
|
|
2530
|
+
} else {
|
|
2531
|
+
console.warn("[order-notifications] skip WhatsApp: no customer phone", {
|
|
2532
|
+
triggerKey,
|
|
2533
|
+
orderId: payload.orderId
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2265
2536
|
} else {
|
|
2266
|
-
console.
|
|
2267
|
-
triggerKey,
|
|
2268
|
-
orderId: payload.orderId
|
|
2269
|
-
});
|
|
2537
|
+
console.log("[order-notifications] skip WhatsApp: WhatsApp notifications channel is disabled");
|
|
2270
2538
|
}
|
|
2271
2539
|
}
|
|
2272
2540
|
chunkUSNT2KNT_cjs.__name(handleTrigger, "handleTrigger");
|
|
@@ -2287,11 +2555,16 @@ async function resendOrderNotification(triggerKey, orderId, deps) {
|
|
|
2287
2555
|
ok: false,
|
|
2288
2556
|
error: "orders entity missing"
|
|
2289
2557
|
};
|
|
2290
|
-
const
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2558
|
+
const [emailEnabled, whatsappEnabled] = await Promise.all([
|
|
2559
|
+
isEmailNotificationsEnabled(deps.dataSource, deps.entityMap),
|
|
2560
|
+
isWhatsappNotificationsEnabled(deps.dataSource, deps.entityMap)
|
|
2561
|
+
]);
|
|
2562
|
+
if (!emailEnabled && !whatsappEnabled) {
|
|
2563
|
+
return {
|
|
2564
|
+
ok: false,
|
|
2565
|
+
error: "Both Email and WhatsApp notifications are disabled"
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2295
2568
|
const triggerEnabled = await isTriggerCatalogEnabled(triggerKey, deps.dataSource, deps.entityMap);
|
|
2296
2569
|
if (!triggerEnabled) {
|
|
2297
2570
|
return {
|
|
@@ -2337,11 +2610,9 @@ exports.buildTranscriptForLeadEmail = buildTranscriptForLeadEmail;
|
|
|
2337
2610
|
exports.detectChatLeadIntent = detectChatLeadIntent;
|
|
2338
2611
|
exports.emailPlugin = emailPlugin;
|
|
2339
2612
|
exports.emailTemplates = emailTemplates;
|
|
2340
|
-
exports.getCompanyDetailsFromSettings = getCompanyDetailsFromSettings;
|
|
2341
2613
|
exports.initWhatsappTriggerDispatcher = initWhatsappTriggerDispatcher;
|
|
2342
2614
|
exports.isWhatsAppPluginEnabled = isWhatsAppPluginEnabled;
|
|
2343
2615
|
exports.joinRecipientsForSend = joinRecipientsForSend;
|
|
2344
|
-
exports.mergeEmailLayoutCompanyDetails = mergeEmailLayoutCompanyDetails;
|
|
2345
2616
|
exports.mergeWhatsAppConfigLayers = mergeWhatsAppConfigLayers;
|
|
2346
2617
|
exports.parseEmailRecipientsFromConfig = parseEmailRecipientsFromConfig;
|
|
2347
2618
|
exports.parseIntentRecipientEmails = parseIntentRecipientEmails;
|