@infuro/cms-core 1.0.47 → 1.0.51
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 +30 -16
- package/dist/admin.cjs +2012 -437
- package/dist/admin.d.cts +13 -1
- package/dist/admin.d.ts +13 -1
- package/dist/admin.js +2013 -438
- package/dist/api.cjs +37 -37
- package/dist/api.js +5 -5
- package/dist/auth.cjs +52 -23
- package/dist/auth.d.cts +101 -2
- package/dist/auth.d.ts +101 -2
- package/dist/auth.js +3 -2
- package/dist/chunk-3EOM4V2M.cjs +452 -0
- package/dist/{chunk-2HU5R2JE.js → chunk-AYERBA7I.js} +1 -7
- package/dist/{chunk-YXH2UUEZ.js → chunk-CTXBYO2J.js} +290 -59
- package/dist/{chunk-LMJ7RKPF.cjs → chunk-JN4AFHZ4.cjs} +311 -59
- package/dist/{chunk-JE22VP6S.js → chunk-MXIWUFBP.js} +1 -1
- package/dist/{chunk-W42UZLQO.js → chunk-NUXR7BUG.js} +2819 -2597
- package/dist/chunk-RK5ETF2I.js +434 -0
- package/dist/{chunk-4PMK3RNA.cjs → chunk-TJ2MIQUT.cjs} +1 -7
- package/dist/{chunk-KOTXDSQB.cjs → chunk-UQWZUZ5X.cjs} +1 -1
- package/dist/{chunk-YC4NUZCS.js → chunk-WRKV6MHB.js} +414 -2
- package/dist/{chunk-XUCKZPML.cjs → chunk-YOW457RA.cjs} +2872 -2657
- package/dist/{chunk-Q3HQEM4R.cjs → chunk-YV5PK4JW.cjs} +421 -1
- package/dist/cli.cjs +13 -22
- package/dist/cli.js +13 -22
- package/dist/{emit-order-notification-trigger-6XX7LSC4.js → emit-order-notification-trigger-HZQPPSFB.js} +1 -1
- package/dist/{emit-order-notification-trigger-NASG7ZEO.cjs → emit-order-notification-trigger-NR3VN6C6.cjs} +3 -3
- package/dist/{event-order-defaults-7Z3UZOEH.cjs → event-order-defaults-DU7V3YND.cjs} +9 -9
- package/dist/{event-order-defaults-XQ3IDPD7.js → event-order-defaults-H4RT7NMR.js} +1 -1
- package/dist/index.cjs +379 -309
- package/dist/index.d.cts +136 -6
- package/dist/index.d.ts +136 -6
- package/dist/index.js +58 -24
- package/dist/migrations/1782400000000-CreateUserDeviceTokens.ts +36 -0
- package/dist/migrations/1782500000000-AddPushToOrderNotificationBindingsChannelEnum.ts +15 -0
- package/dist/{order-notification-dispatcher-6WNG24NY.js → order-notification-dispatcher-AT4IFAGL.js} +1 -1
- package/dist/{order-notification-dispatcher-6XSU3AR7.cjs → order-notification-dispatcher-YBAWDOIO.cjs} +7 -3
- package/package.json +1 -1
- package/dist/chunk-VUQFARRT.cjs +0 -182
- package/dist/chunk-ZF2RQWXB.js +0 -171
|
@@ -8,11 +8,31 @@ var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
|
|
|
8
8
|
var clientSes = require('@aws-sdk/client-ses');
|
|
9
9
|
var module$1 = require('module');
|
|
10
10
|
var nodemailer = require('nodemailer');
|
|
11
|
+
var crypto = require('crypto');
|
|
11
12
|
|
|
12
13
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
13
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
15
|
|
|
16
|
+
function _interopNamespace(e) {
|
|
17
|
+
if (e && e.__esModule) return e;
|
|
18
|
+
var n = Object.create(null);
|
|
19
|
+
if (e) {
|
|
20
|
+
Object.keys(e).forEach(function (k) {
|
|
21
|
+
if (k !== 'default') {
|
|
22
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
23
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return e[k]; }
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
n.default = e;
|
|
31
|
+
return Object.freeze(n);
|
|
32
|
+
}
|
|
33
|
+
|
|
15
34
|
var nodemailer__default = /*#__PURE__*/_interopDefault(nodemailer);
|
|
35
|
+
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
16
36
|
|
|
17
37
|
// src/lib/event-order-template-context.ts
|
|
18
38
|
function resolvePublicSiteUrl() {
|
|
@@ -33,12 +53,6 @@ function buildOrderTrackUrl(qrToken, siteUrl, orderNumber) {
|
|
|
33
53
|
return `${base}/track/${token}`;
|
|
34
54
|
}
|
|
35
55
|
chunkUSNT2KNT_cjs.__name(buildOrderTrackUrl, "buildOrderTrackUrl");
|
|
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)}`;
|
|
40
|
-
}
|
|
41
|
-
chunkUSNT2KNT_cjs.__name(buildOrderQrImageUrl, "buildOrderQrImageUrl");
|
|
42
56
|
function formatOrderDetailsText(input) {
|
|
43
57
|
const { orderNumber, total, currency, lines } = input;
|
|
44
58
|
const header = `Order: ${orderNumber}
|
|
@@ -60,8 +74,6 @@ chunkUSNT2KNT_cjs.__name(formatOrderDetailsHtml, "formatOrderDetailsHtml");
|
|
|
60
74
|
function buildEventOrderTemplateVariables(input) {
|
|
61
75
|
const { event, order, contact, productNames, vendorName = "", orderLines = [], siteUrl } = input;
|
|
62
76
|
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
77
|
const baseSite = (siteUrl ?? resolvePublicSiteUrl()).replace(/\/+$/, "");
|
|
66
78
|
const invoiceNumber = `INV-${order.orderNumber ?? ""}`;
|
|
67
79
|
const invoiceUrl = baseSite ? `${baseSite}/api/orders/${order.orderNumber ?? ""}/invoice` : `/api/orders/${order.orderNumber ?? ""}/invoice`;
|
|
@@ -71,6 +83,9 @@ function buildEventOrderTemplateVariables(input) {
|
|
|
71
83
|
currency: String(order.currency ?? "INR"),
|
|
72
84
|
lines: orderLines
|
|
73
85
|
};
|
|
86
|
+
const qrToken = order.qrToken?.trim() || order.orderNumber?.trim() || "";
|
|
87
|
+
const fallbackQrUrl = qrToken ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(qrToken)}` : "";
|
|
88
|
+
const fallbackTicketQr = fallbackQrUrl ? `<img src="${fallbackQrUrl}" alt="Ticket QR Code" width="200" height="200" style="display:block;margin:12px 0;border:1px solid #e5e7eb;border-radius:8px;" />` : "";
|
|
74
89
|
return {
|
|
75
90
|
eventName: event.name ?? productNames ?? "",
|
|
76
91
|
vendorName: vendorName.trim(),
|
|
@@ -85,10 +100,10 @@ function buildEventOrderTemplateVariables(input) {
|
|
|
85
100
|
customerPhone: contact.phone?.trim() || "",
|
|
86
101
|
productNames,
|
|
87
102
|
trackUrl,
|
|
88
|
-
qrImageUrl,
|
|
89
|
-
ticketQr,
|
|
90
103
|
invoiceNumber,
|
|
91
104
|
invoiceUrl,
|
|
105
|
+
ticketQr: fallbackTicketQr,
|
|
106
|
+
qrImageUrl: fallbackQrUrl,
|
|
92
107
|
orderDetails: formatOrderDetailsText(orderDetailsPayload),
|
|
93
108
|
orderDetailsHtml: formatOrderDetailsHtml(orderDetailsPayload)
|
|
94
109
|
};
|
|
@@ -504,7 +519,7 @@ var WhatsAppService = class {
|
|
|
504
519
|
let body = opts.body?.trim() ?? "";
|
|
505
520
|
const variables = opts.variables ?? {};
|
|
506
521
|
if (opts.templateKey?.trim() && this.getMessageTemplateRow) {
|
|
507
|
-
const { resolveEventOrderTemplate, EVENT_ORDER_TEMPLATE_KEY } = await import('./event-order-defaults-
|
|
522
|
+
const { resolveEventOrderTemplate, EVENT_ORDER_TEMPLATE_KEY } = await import('./event-order-defaults-DU7V3YND.cjs');
|
|
508
523
|
if (opts.templateKey.trim() === EVENT_ORDER_TEMPLATE_KEY) {
|
|
509
524
|
const resolved = await resolveEventOrderTemplate("whatsapp", async (ch, key) => {
|
|
510
525
|
const row = await this.getMessageTemplateRow(ch, key);
|
|
@@ -1316,7 +1331,7 @@ function renderEmail(templateName, ctx, options) {
|
|
|
1316
1331
|
chunkUSNT2KNT_cjs.__name(renderEmail, "renderEmail");
|
|
1317
1332
|
|
|
1318
1333
|
// 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-
|
|
1334
|
+
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-JN4AFHZ4.cjs', document.baseURI).href)));
|
|
1320
1335
|
var MailComposer = require2("nodemailer/lib/mail-composer");
|
|
1321
1336
|
var SES_REGIONS_WITHOUT_SMTP = /* @__PURE__ */ new Set([
|
|
1322
1337
|
"af-south-1",
|
|
@@ -2068,6 +2083,117 @@ function emailPlugin(config) {
|
|
|
2068
2083
|
};
|
|
2069
2084
|
}
|
|
2070
2085
|
chunkUSNT2KNT_cjs.__name(emailPlugin, "emailPlugin");
|
|
2086
|
+
function base64UrlEncode(str) {
|
|
2087
|
+
const buf = typeof str === "string" ? Buffer.from(str, "utf8") : str;
|
|
2088
|
+
return buf.toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
2089
|
+
}
|
|
2090
|
+
chunkUSNT2KNT_cjs.__name(base64UrlEncode, "base64UrlEncode");
|
|
2091
|
+
async function getGoogleAccessToken(clientEmail, privateKey) {
|
|
2092
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2093
|
+
const header = {
|
|
2094
|
+
alg: "RS256",
|
|
2095
|
+
typ: "JWT"
|
|
2096
|
+
};
|
|
2097
|
+
const claimSet = {
|
|
2098
|
+
iss: clientEmail,
|
|
2099
|
+
scope: "https://www.googleapis.com/auth/firebase.messaging",
|
|
2100
|
+
aud: "https://oauth2.googleapis.com/token",
|
|
2101
|
+
exp: now + 3600,
|
|
2102
|
+
iat: now
|
|
2103
|
+
};
|
|
2104
|
+
const encodedHeader = base64UrlEncode(JSON.stringify(header));
|
|
2105
|
+
const encodedClaimSet = base64UrlEncode(JSON.stringify(claimSet));
|
|
2106
|
+
const signatureInput = `${encodedHeader}.${encodedClaimSet}`;
|
|
2107
|
+
const formattedKey = privateKey.replace(/\\n/g, "\n");
|
|
2108
|
+
const signer = crypto__namespace.createSign("RSA-SHA256");
|
|
2109
|
+
signer.update(signatureInput);
|
|
2110
|
+
const signature = signer.sign(formattedKey, "base64");
|
|
2111
|
+
const jwt = `${signatureInput}.${signature.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_")}`;
|
|
2112
|
+
const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
|
|
2113
|
+
method: "POST",
|
|
2114
|
+
headers: {
|
|
2115
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
2116
|
+
},
|
|
2117
|
+
body: new URLSearchParams({
|
|
2118
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
2119
|
+
assertion: jwt
|
|
2120
|
+
}).toString()
|
|
2121
|
+
});
|
|
2122
|
+
if (!tokenRes.ok) {
|
|
2123
|
+
const errText = await tokenRes.text();
|
|
2124
|
+
throw new Error(`Failed to obtain Google access token: ${errText}`);
|
|
2125
|
+
}
|
|
2126
|
+
const tokenData = await tokenRes.json();
|
|
2127
|
+
if (!tokenData.access_token) {
|
|
2128
|
+
throw new Error("Google OAuth token response missing access_token");
|
|
2129
|
+
}
|
|
2130
|
+
return tokenData.access_token;
|
|
2131
|
+
}
|
|
2132
|
+
chunkUSNT2KNT_cjs.__name(getGoogleAccessToken, "getGoogleAccessToken");
|
|
2133
|
+
async function sendFcmPushNotification(dataSource, entityMap, msg) {
|
|
2134
|
+
try {
|
|
2135
|
+
const pushSettings = await getSettingsGroup(dataSource, entityMap, "push");
|
|
2136
|
+
let projectId = pushSettings.firebase_project_id?.trim();
|
|
2137
|
+
let clientEmail = pushSettings.firebase_client_email?.trim();
|
|
2138
|
+
let privateKey = pushSettings.firebase_private_key?.trim();
|
|
2139
|
+
if (pushSettings.firebase_service_account_json?.trim()) {
|
|
2140
|
+
try {
|
|
2141
|
+
const parsed = JSON.parse(pushSettings.firebase_service_account_json.trim());
|
|
2142
|
+
if (parsed.project_id) projectId = parsed.project_id;
|
|
2143
|
+
if (parsed.client_email) clientEmail = parsed.client_email;
|
|
2144
|
+
if (parsed.private_key) privateKey = parsed.private_key;
|
|
2145
|
+
} catch {
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
if (!projectId || !clientEmail || !privateKey) {
|
|
2149
|
+
return {
|
|
2150
|
+
success: false,
|
|
2151
|
+
error: "Firebase Service Account JSON / credentials are not configured"
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
const accessToken = await getGoogleAccessToken(clientEmail, privateKey);
|
|
2155
|
+
const fcmEndpoint = `https://fcm.googleapis.com/v1/projects/${projectId}/messages:send`;
|
|
2156
|
+
const fcmPayload = {
|
|
2157
|
+
message: {
|
|
2158
|
+
token: msg.token,
|
|
2159
|
+
notification: {
|
|
2160
|
+
title: msg.title,
|
|
2161
|
+
body: msg.body
|
|
2162
|
+
},
|
|
2163
|
+
data: msg.data || {}
|
|
2164
|
+
}
|
|
2165
|
+
};
|
|
2166
|
+
const response = await fetch(fcmEndpoint, {
|
|
2167
|
+
method: "POST",
|
|
2168
|
+
headers: {
|
|
2169
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
2170
|
+
"Content-Type": "application/json"
|
|
2171
|
+
},
|
|
2172
|
+
body: JSON.stringify(fcmPayload)
|
|
2173
|
+
});
|
|
2174
|
+
const resData = await response.json();
|
|
2175
|
+
if (!response.ok) {
|
|
2176
|
+
const errorMsg = resData.error?.message || "FCM request failed";
|
|
2177
|
+
console.error("[fcm-push] Error sending push notification", errorMsg);
|
|
2178
|
+
return {
|
|
2179
|
+
success: false,
|
|
2180
|
+
error: errorMsg
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
return {
|
|
2184
|
+
success: true,
|
|
2185
|
+
messageId: resData.name
|
|
2186
|
+
};
|
|
2187
|
+
} catch (err) {
|
|
2188
|
+
const errorMsg = err instanceof Error ? err.message : "Unknown push error";
|
|
2189
|
+
console.error("[fcm-push] Exception in sendFcmPushNotification", errorMsg);
|
|
2190
|
+
return {
|
|
2191
|
+
success: false,
|
|
2192
|
+
error: errorMsg
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
chunkUSNT2KNT_cjs.__name(sendFcmPushNotification, "sendFcmPushNotification");
|
|
2071
2197
|
|
|
2072
2198
|
// src/lib/order-notification-dispatcher.ts
|
|
2073
2199
|
var initialized = false;
|
|
@@ -2135,59 +2261,69 @@ async function loadBoundTemplate(triggerKey, channel, audienceType = "customers"
|
|
|
2135
2261
|
console.warn("[order-notifications] order_notification_bindings or message_templates missing from entityMap");
|
|
2136
2262
|
return null;
|
|
2137
2263
|
}
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
triggerKey,
|
|
2142
|
-
channel,
|
|
2143
|
-
type: audienceType,
|
|
2144
|
-
enabled: true
|
|
2145
|
-
}
|
|
2146
|
-
});
|
|
2147
|
-
if (!binding && audienceType === "customers") {
|
|
2148
|
-
binding = await bindingRepo.findOne({
|
|
2264
|
+
try {
|
|
2265
|
+
const bindingRepo = dataSource.getRepository(entityMap.order_notification_bindings);
|
|
2266
|
+
let binding = await bindingRepo.findOne({
|
|
2149
2267
|
where: {
|
|
2150
2268
|
triggerKey,
|
|
2151
2269
|
channel,
|
|
2270
|
+
type: audienceType,
|
|
2152
2271
|
enabled: true
|
|
2153
2272
|
}
|
|
2154
|
-
});
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
}
|
|
2164
|
-
const templateId = binding.messageTemplateId;
|
|
2165
|
-
if (templateId == null) {
|
|
2166
|
-
console.warn("[order-notifications] binding exists but no template selected", {
|
|
2167
|
-
triggerKey,
|
|
2168
|
-
channel,
|
|
2169
|
-
audienceType
|
|
2170
|
-
});
|
|
2171
|
-
return null;
|
|
2172
|
-
}
|
|
2173
|
-
const template = await dataSource.getRepository(entityMap.message_templates).findOne({
|
|
2174
|
-
where: {
|
|
2175
|
-
id: templateId,
|
|
2176
|
-
channel,
|
|
2177
|
-
deleted: false,
|
|
2178
|
-
enabled: true
|
|
2273
|
+
}).catch(() => null);
|
|
2274
|
+
if (!binding && audienceType === "customers") {
|
|
2275
|
+
binding = await bindingRepo.findOne({
|
|
2276
|
+
where: {
|
|
2277
|
+
triggerKey,
|
|
2278
|
+
channel,
|
|
2279
|
+
enabled: true
|
|
2280
|
+
}
|
|
2281
|
+
}).catch(() => null);
|
|
2179
2282
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2283
|
+
if (!binding) {
|
|
2284
|
+
console.warn("[order-notifications] no order_notification_bindings row", {
|
|
2285
|
+
triggerKey,
|
|
2286
|
+
channel,
|
|
2287
|
+
audienceType
|
|
2288
|
+
});
|
|
2289
|
+
return null;
|
|
2290
|
+
}
|
|
2291
|
+
const templateId = binding.messageTemplateId;
|
|
2292
|
+
if (templateId == null) {
|
|
2293
|
+
console.warn("[order-notifications] binding exists but no template selected", {
|
|
2294
|
+
triggerKey,
|
|
2295
|
+
channel,
|
|
2296
|
+
audienceType
|
|
2297
|
+
});
|
|
2298
|
+
return null;
|
|
2299
|
+
}
|
|
2300
|
+
const template = await dataSource.getRepository(entityMap.message_templates).findOne({
|
|
2301
|
+
where: {
|
|
2302
|
+
id: templateId,
|
|
2303
|
+
channel,
|
|
2304
|
+
deleted: false,
|
|
2305
|
+
enabled: true
|
|
2306
|
+
}
|
|
2307
|
+
}).catch(() => null);
|
|
2308
|
+
if (!template) {
|
|
2309
|
+
console.warn("[order-notifications] bound template not found or disabled", {
|
|
2310
|
+
triggerKey,
|
|
2311
|
+
channel,
|
|
2312
|
+
audienceType,
|
|
2313
|
+
templateId
|
|
2314
|
+
});
|
|
2315
|
+
return null;
|
|
2316
|
+
}
|
|
2317
|
+
return template;
|
|
2318
|
+
} catch (err) {
|
|
2319
|
+
console.warn("[order-notifications] loadBoundTemplate query failed", {
|
|
2183
2320
|
triggerKey,
|
|
2184
2321
|
channel,
|
|
2185
2322
|
audienceType,
|
|
2186
|
-
|
|
2323
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2187
2324
|
});
|
|
2188
2325
|
return null;
|
|
2189
2326
|
}
|
|
2190
|
-
return template;
|
|
2191
2327
|
}
|
|
2192
2328
|
chunkUSNT2KNT_cjs.__name(loadBoundTemplate, "loadBoundTemplate");
|
|
2193
2329
|
function mergeTriggerVariables(payload, rich) {
|
|
@@ -2204,9 +2340,11 @@ function mergeTriggerVariables(payload, rich) {
|
|
|
2204
2340
|
refundAmount: String(payload.refundAmount)
|
|
2205
2341
|
} : {}
|
|
2206
2342
|
};
|
|
2343
|
+
const extraVars = payload.extraVariables ?? {};
|
|
2207
2344
|
return {
|
|
2208
2345
|
...basic,
|
|
2209
|
-
...rich ?? {}
|
|
2346
|
+
...rich ?? {},
|
|
2347
|
+
...extraVars
|
|
2210
2348
|
};
|
|
2211
2349
|
}
|
|
2212
2350
|
chunkUSNT2KNT_cjs.__name(mergeTriggerVariables, "mergeTriggerVariables");
|
|
@@ -2218,6 +2356,82 @@ async function isAudienceEmailEnabled(dataSource, entityMap, audience) {
|
|
|
2218
2356
|
return settings[key] !== "false" && settings[key] !== "0";
|
|
2219
2357
|
}
|
|
2220
2358
|
chunkUSNT2KNT_cjs.__name(isAudienceEmailEnabled, "isAudienceEmailEnabled");
|
|
2359
|
+
async function isPushNotificationsEnabled(dataSource, entityMap) {
|
|
2360
|
+
const settings = await getSettingsGroup(dataSource, entityMap, "event_notifications");
|
|
2361
|
+
if (settings.enabled === "false" || settings.enabled === "0") return false;
|
|
2362
|
+
return settings.push_enabled !== "false" && settings.push_enabled !== "0";
|
|
2363
|
+
}
|
|
2364
|
+
chunkUSNT2KNT_cjs.__name(isPushNotificationsEnabled, "isPushNotificationsEnabled");
|
|
2365
|
+
async function isAudiencePushEnabled(dataSource, entityMap, audience) {
|
|
2366
|
+
const settings = await getSettingsGroup(dataSource, entityMap, "event_notifications");
|
|
2367
|
+
if (settings.enabled === "false" || settings.enabled === "0") return false;
|
|
2368
|
+
if (settings.push_enabled === "false" || settings.push_enabled === "0") return false;
|
|
2369
|
+
const key = `push_${audience}_enabled`;
|
|
2370
|
+
return settings[key] !== "false" && settings[key] !== "0";
|
|
2371
|
+
}
|
|
2372
|
+
chunkUSNT2KNT_cjs.__name(isAudiencePushEnabled, "isAudiencePushEnabled");
|
|
2373
|
+
async function sendPushNotificationForTrigger(triggerKey, orderId, audienceType, targetId, variables, dataSource, entityMap) {
|
|
2374
|
+
let template = await loadBoundTemplate(triggerKey, "mobile", audienceType, dataSource, entityMap);
|
|
2375
|
+
if (!template) {
|
|
2376
|
+
template = await loadBoundTemplate(triggerKey, "push", audienceType, dataSource, entityMap);
|
|
2377
|
+
}
|
|
2378
|
+
if (!template || !template.body) return;
|
|
2379
|
+
const rawTitle = template.subject?.trim() || "Order Notification";
|
|
2380
|
+
const title = chunkOOTLNH63_cjs.applyTemplateVars(rawTitle, variables);
|
|
2381
|
+
const body = chunkOOTLNH63_cjs.applyTemplateVars(template.body, variables);
|
|
2382
|
+
if (!entityMap.user_device_tokens) return;
|
|
2383
|
+
const tokenRepo = dataSource.getRepository(entityMap.user_device_tokens);
|
|
2384
|
+
let targetTokens = [];
|
|
2385
|
+
try {
|
|
2386
|
+
if (audienceType === "customers") {
|
|
2387
|
+
targetTokens = await tokenRepo.find({
|
|
2388
|
+
where: {
|
|
2389
|
+
userId: targetId,
|
|
2390
|
+
isActive: true
|
|
2391
|
+
},
|
|
2392
|
+
select: [
|
|
2393
|
+
"token"
|
|
2394
|
+
]
|
|
2395
|
+
});
|
|
2396
|
+
} else if (audienceType === "vendors") {
|
|
2397
|
+
targetTokens = await tokenRepo.find({
|
|
2398
|
+
where: {
|
|
2399
|
+
vendorId: targetId,
|
|
2400
|
+
isActive: true
|
|
2401
|
+
},
|
|
2402
|
+
select: [
|
|
2403
|
+
"token"
|
|
2404
|
+
]
|
|
2405
|
+
});
|
|
2406
|
+
} else if (audienceType === "admin") {
|
|
2407
|
+
targetTokens = await tokenRepo.find({
|
|
2408
|
+
where: {
|
|
2409
|
+
isActive: true
|
|
2410
|
+
},
|
|
2411
|
+
select: [
|
|
2412
|
+
"token"
|
|
2413
|
+
]
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2416
|
+
} catch (err) {
|
|
2417
|
+
console.error("[order-notifications] Error querying device tokens for push", err);
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
2420
|
+
for (const t of targetTokens) {
|
|
2421
|
+
if (t.token?.trim()) {
|
|
2422
|
+
await sendFcmPushNotification(dataSource, entityMap, {
|
|
2423
|
+
token: t.token.trim(),
|
|
2424
|
+
title,
|
|
2425
|
+
body,
|
|
2426
|
+
data: {
|
|
2427
|
+
orderId: String(orderId),
|
|
2428
|
+
triggerKey
|
|
2429
|
+
}
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
chunkUSNT2KNT_cjs.__name(sendPushNotificationForTrigger, "sendPushNotificationForTrigger");
|
|
2221
2435
|
async function getOrderVendorEmails(orderId, orderVendorId, dataSource, entityMap) {
|
|
2222
2436
|
const emails = /* @__PURE__ */ new Set();
|
|
2223
2437
|
if (!entityMap.vendors) return [];
|
|
@@ -2326,7 +2540,23 @@ async function getAdminRecipientEmails(dataSource, entityMap) {
|
|
|
2326
2540
|
}
|
|
2327
2541
|
} catch {
|
|
2328
2542
|
}
|
|
2329
|
-
|
|
2543
|
+
const vendorEmails = /* @__PURE__ */ new Set();
|
|
2544
|
+
try {
|
|
2545
|
+
const vRows = await dataSource.query(`SELECT DISTINCT LOWER(TRIM(email)) AS email FROM vendors WHERE COALESCE(deleted, false) = false AND email IS NOT NULL AND TRIM(email) != ''`).catch(() => []);
|
|
2546
|
+
for (const r of vRows) {
|
|
2547
|
+
if (r.email) vendorEmails.add(r.email.toLowerCase());
|
|
2548
|
+
}
|
|
2549
|
+
const vuRows = await dataSource.query(`SELECT DISTINCT LOWER(TRIM(u.email)) AS email
|
|
2550
|
+
FROM users u
|
|
2551
|
+
LEFT JOIN user_groups g ON g.id = u."groupId"
|
|
2552
|
+
WHERE COALESCE(u.deleted, false) = false
|
|
2553
|
+
AND (LOWER(g.name) LIKE '%vendor%' OR u."groupId" = 5)`).catch(() => []);
|
|
2554
|
+
for (const r of vuRows) {
|
|
2555
|
+
if (r.email) vendorEmails.add(r.email.toLowerCase());
|
|
2556
|
+
}
|
|
2557
|
+
} catch {
|
|
2558
|
+
}
|
|
2559
|
+
return Array.from(emails).filter((e) => !vendorEmails.has(e.toLowerCase()));
|
|
2330
2560
|
}
|
|
2331
2561
|
chunkUSNT2KNT_cjs.__name(getAdminRecipientEmails, "getAdminRecipientEmails");
|
|
2332
2562
|
function formatBodyForEmailHtml(body) {
|
|
@@ -2480,12 +2710,13 @@ async function handleTrigger(triggerKey, payload, dataSource, entityMap, getCms)
|
|
|
2480
2710
|
return;
|
|
2481
2711
|
}
|
|
2482
2712
|
}
|
|
2483
|
-
const [emailChannelEnabled, whatsappChannelEnabled] = await Promise.all([
|
|
2713
|
+
const [emailChannelEnabled, whatsappChannelEnabled, pushChannelEnabled] = await Promise.all([
|
|
2484
2714
|
isEmailNotificationsEnabled(dataSource, entityMap),
|
|
2485
|
-
isWhatsappNotificationsEnabled(dataSource, entityMap)
|
|
2715
|
+
isWhatsappNotificationsEnabled(dataSource, entityMap),
|
|
2716
|
+
isPushNotificationsEnabled(dataSource, entityMap)
|
|
2486
2717
|
]);
|
|
2487
|
-
if (!emailChannelEnabled && !whatsappChannelEnabled) {
|
|
2488
|
-
console.warn("[order-notifications] skip:
|
|
2718
|
+
if (!emailChannelEnabled && !whatsappChannelEnabled && !pushChannelEnabled) {
|
|
2719
|
+
console.warn("[order-notifications] skip: Email, WhatsApp, and Mobile Push notifications are disabled");
|
|
2489
2720
|
return;
|
|
2490
2721
|
}
|
|
2491
2722
|
const triggerEnabled = await isTriggerCatalogEnabled(triggerKey, dataSource, entityMap);
|
|
@@ -2524,6 +2755,23 @@ async function handleTrigger(triggerKey, payload, dataSource, entityMap, getCms)
|
|
|
2524
2755
|
} else {
|
|
2525
2756
|
console.log("[order-notifications] skip email: Email notifications channel is disabled");
|
|
2526
2757
|
}
|
|
2758
|
+
if (pushChannelEnabled) {
|
|
2759
|
+
const [pushCustomerEnabled, pushVendorEnabled, pushAdminEnabled] = await Promise.all([
|
|
2760
|
+
isAudiencePushEnabled(dataSource, entityMap, "customer"),
|
|
2761
|
+
isAudiencePushEnabled(dataSource, entityMap, "vendor"),
|
|
2762
|
+
isAudiencePushEnabled(dataSource, entityMap, "admin")
|
|
2763
|
+
]);
|
|
2764
|
+
const targetCustomerId = context?.order?.customerContactId || context?.order?.contactId || context?.order?.userId || context?.order?.id;
|
|
2765
|
+
if (pushCustomerEnabled && targetCustomerId) {
|
|
2766
|
+
await sendPushNotificationForTrigger(triggerKey, payload.orderId, "customers", String(targetCustomerId), variables, dataSource, entityMap);
|
|
2767
|
+
}
|
|
2768
|
+
if (pushVendorEnabled && payload.vendorId) {
|
|
2769
|
+
await sendPushNotificationForTrigger(triggerKey, payload.orderId, "vendors", String(payload.vendorId), variables, dataSource, entityMap);
|
|
2770
|
+
}
|
|
2771
|
+
if (pushAdminEnabled) {
|
|
2772
|
+
await sendPushNotificationForTrigger(triggerKey, payload.orderId, "admin", "admin", variables, dataSource, entityMap);
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2527
2775
|
if (whatsappChannelEnabled) {
|
|
2528
2776
|
if (contactPhone) {
|
|
2529
2777
|
await sendWhatsAppForTrigger(triggerKey, payload.orderId, contactPhone, variables, dataSource, entityMap, getCms);
|
|
@@ -2542,6 +2790,8 @@ function initWhatsappTriggerDispatcher(deps) {
|
|
|
2542
2790
|
if (initialized) return;
|
|
2543
2791
|
initialized = true;
|
|
2544
2792
|
const { dataSource, entityMap, getCms } = deps;
|
|
2793
|
+
void dataSource.query(`ALTER TYPE "order_notification_bindings_channel_enum" ADD VALUE IF NOT EXISTS 'mobile'`).catch(() => {
|
|
2794
|
+
});
|
|
2545
2795
|
chunkUCKN4BBY_cjs.notificationTriggerEmitter.onAnyTrigger((triggerKey, payload) => {
|
|
2546
2796
|
void handleTrigger(triggerKey, payload, dataSource, entityMap, getCms).catch((err) => {
|
|
2547
2797
|
console.error("[order-notifications]", triggerKey, err);
|
|
@@ -2610,6 +2860,7 @@ exports.buildTranscriptForLeadEmail = buildTranscriptForLeadEmail;
|
|
|
2610
2860
|
exports.detectChatLeadIntent = detectChatLeadIntent;
|
|
2611
2861
|
exports.emailPlugin = emailPlugin;
|
|
2612
2862
|
exports.emailTemplates = emailTemplates;
|
|
2863
|
+
exports.getSettingsGroup = getSettingsGroup;
|
|
2613
2864
|
exports.initWhatsappTriggerDispatcher = initWhatsappTriggerDispatcher;
|
|
2614
2865
|
exports.isWhatsAppPluginEnabled = isWhatsAppPluginEnabled;
|
|
2615
2866
|
exports.joinRecipientsForSend = joinRecipientsForSend;
|
|
@@ -2623,5 +2874,6 @@ exports.renderLayout = renderLayout;
|
|
|
2623
2874
|
exports.resendOrderNotification = resendOrderNotification;
|
|
2624
2875
|
exports.resolveChatEmailToolSettings = resolveChatEmailToolSettings;
|
|
2625
2876
|
exports.sendChatLeadEmail = sendChatLeadEmail;
|
|
2877
|
+
exports.sendFcmPushNotification = sendFcmPushNotification;
|
|
2626
2878
|
exports.serializeEmailRecipients = serializeEmailRecipients;
|
|
2627
2879
|
exports.whatsAppConfigured = whatsAppConfigured;
|
|
@@ -59,7 +59,7 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
|
|
|
59
59
|
total: fo.total ?? 0,
|
|
60
60
|
currency: String(fo.currency ?? "INR"),
|
|
61
61
|
vendorId: fo.vendorId ?? null,
|
|
62
|
-
|
|
62
|
+
extraVariables: extra?.extraVariables,
|
|
63
63
|
...extra?.refundAmount != null ? {
|
|
64
64
|
refundAmount: extra.refundAmount
|
|
65
65
|
} : {}
|