@infuro/cms-core 1.0.50 → 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/dist/admin.cjs +843 -402
- package/dist/admin.d.cts +13 -1
- package/dist/admin.d.ts +13 -1
- package/dist/admin.js +843 -402
- package/dist/api.cjs +33 -33
- package/dist/api.js +2 -2
- package/dist/{chunk-IPDHT2UV.js → chunk-CTXBYO2J.js} +94 -104
- package/dist/{chunk-UUWAUHUW.cjs → chunk-JN4AFHZ4.cjs} +94 -105
- package/dist/{chunk-JE22VP6S.js → chunk-MXIWUFBP.js} +1 -1
- package/dist/{chunk-LT2WOPKA.js → chunk-NUXR7BUG.js} +179 -59
- package/dist/{chunk-KOTXDSQB.cjs → chunk-UQWZUZ5X.cjs} +1 -1
- package/dist/{chunk-JCMOOPNX.cjs → chunk-YOW457RA.cjs} +208 -88
- 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/index.cjs +280 -246
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +54 -20
- package/dist/{order-notification-dispatcher-3TA4ETYJ.js → order-notification-dispatcher-AT4IFAGL.js} +1 -1
- package/dist/{order-notification-dispatcher-ZEAZ5SHV.cjs → order-notification-dispatcher-YBAWDOIO.cjs} +4 -4
- package/package.json +1 -1
|
@@ -83,6 +83,9 @@ function buildEventOrderTemplateVariables(input) {
|
|
|
83
83
|
currency: String(order.currency ?? "INR"),
|
|
84
84
|
lines: orderLines
|
|
85
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;" />` : "";
|
|
86
89
|
return {
|
|
87
90
|
eventName: event.name ?? productNames ?? "",
|
|
88
91
|
vendorName: vendorName.trim(),
|
|
@@ -99,6 +102,8 @@ function buildEventOrderTemplateVariables(input) {
|
|
|
99
102
|
trackUrl,
|
|
100
103
|
invoiceNumber,
|
|
101
104
|
invoiceUrl,
|
|
105
|
+
ticketQr: fallbackTicketQr,
|
|
106
|
+
qrImageUrl: fallbackQrUrl,
|
|
102
107
|
orderDetails: formatOrderDetailsText(orderDetailsPayload),
|
|
103
108
|
orderDetailsHtml: formatOrderDetailsHtml(orderDetailsPayload)
|
|
104
109
|
};
|
|
@@ -1326,7 +1331,7 @@ function renderEmail(templateName, ctx, options) {
|
|
|
1326
1331
|
chunkUSNT2KNT_cjs.__name(renderEmail, "renderEmail");
|
|
1327
1332
|
|
|
1328
1333
|
// src/plugins/email/email-service.ts
|
|
1329
|
-
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)));
|
|
1330
1335
|
var MailComposer = require2("nodemailer/lib/mail-composer");
|
|
1331
1336
|
var SES_REGIONS_WITHOUT_SMTP = /* @__PURE__ */ new Set([
|
|
1332
1337
|
"af-south-1",
|
|
@@ -2125,72 +2130,27 @@ async function getGoogleAccessToken(clientEmail, privateKey) {
|
|
|
2125
2130
|
return tokenData.access_token;
|
|
2126
2131
|
}
|
|
2127
2132
|
chunkUSNT2KNT_cjs.__name(getGoogleAccessToken, "getGoogleAccessToken");
|
|
2128
|
-
async function resolveFcmServiceAccount(dataSource, entityMap) {
|
|
2129
|
-
const pushSettings = await getSettingsGroup(dataSource, entityMap, "push");
|
|
2130
|
-
let projectId = pushSettings.firebase_project_id?.trim();
|
|
2131
|
-
let clientEmail = pushSettings.firebase_client_email?.trim();
|
|
2132
|
-
let privateKey = pushSettings.firebase_private_key?.trim();
|
|
2133
|
-
if (pushSettings.firebase_service_account_json?.trim()) {
|
|
2134
|
-
try {
|
|
2135
|
-
const parsed = JSON.parse(pushSettings.firebase_service_account_json.trim());
|
|
2136
|
-
if (parsed.project_id) projectId = parsed.project_id;
|
|
2137
|
-
if (parsed.client_email) clientEmail = parsed.client_email;
|
|
2138
|
-
if (parsed.private_key) privateKey = parsed.private_key;
|
|
2139
|
-
} catch {
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
if (!projectId || !clientEmail || !privateKey) {
|
|
2143
|
-
return {
|
|
2144
|
-
ok: false,
|
|
2145
|
-
error: "Firebase Service Account JSON / credentials are not configured"
|
|
2146
|
-
};
|
|
2147
|
-
}
|
|
2148
|
-
return {
|
|
2149
|
-
ok: true,
|
|
2150
|
-
account: {
|
|
2151
|
-
projectId,
|
|
2152
|
-
clientEmail,
|
|
2153
|
-
privateKey
|
|
2154
|
-
}
|
|
2155
|
-
};
|
|
2156
|
-
}
|
|
2157
|
-
chunkUSNT2KNT_cjs.__name(resolveFcmServiceAccount, "resolveFcmServiceAccount");
|
|
2158
|
-
async function validateFcmCredentials(dataSource, entityMap) {
|
|
2159
|
-
try {
|
|
2160
|
-
const resolved = await resolveFcmServiceAccount(dataSource, entityMap);
|
|
2161
|
-
if (!resolved.ok) {
|
|
2162
|
-
return {
|
|
2163
|
-
success: false,
|
|
2164
|
-
error: resolved.error
|
|
2165
|
-
};
|
|
2166
|
-
}
|
|
2167
|
-
const { projectId, clientEmail, privateKey } = resolved.account;
|
|
2168
|
-
await getGoogleAccessToken(clientEmail, privateKey);
|
|
2169
|
-
return {
|
|
2170
|
-
success: true,
|
|
2171
|
-
projectId,
|
|
2172
|
-
clientEmail
|
|
2173
|
-
};
|
|
2174
|
-
} catch (err) {
|
|
2175
|
-
const errorMsg = err instanceof Error ? err.message : "Unknown credential validation error";
|
|
2176
|
-
console.error("[fcm-push] Exception in validateFcmCredentials", errorMsg);
|
|
2177
|
-
return {
|
|
2178
|
-
success: false,
|
|
2179
|
-
error: errorMsg
|
|
2180
|
-
};
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
chunkUSNT2KNT_cjs.__name(validateFcmCredentials, "validateFcmCredentials");
|
|
2184
2133
|
async function sendFcmPushNotification(dataSource, entityMap, msg) {
|
|
2185
2134
|
try {
|
|
2186
|
-
const
|
|
2187
|
-
|
|
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) {
|
|
2188
2149
|
return {
|
|
2189
2150
|
success: false,
|
|
2190
|
-
error:
|
|
2151
|
+
error: "Firebase Service Account JSON / credentials are not configured"
|
|
2191
2152
|
};
|
|
2192
2153
|
}
|
|
2193
|
-
const { projectId, clientEmail, privateKey } = resolved.account;
|
|
2194
2154
|
const accessToken = await getGoogleAccessToken(clientEmail, privateKey);
|
|
2195
2155
|
const fcmEndpoint = `https://fcm.googleapis.com/v1/projects/${projectId}/messages:send`;
|
|
2196
2156
|
const fcmPayload = {
|
|
@@ -2301,59 +2261,69 @@ async function loadBoundTemplate(triggerKey, channel, audienceType = "customers"
|
|
|
2301
2261
|
console.warn("[order-notifications] order_notification_bindings or message_templates missing from entityMap");
|
|
2302
2262
|
return null;
|
|
2303
2263
|
}
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
triggerKey,
|
|
2308
|
-
channel,
|
|
2309
|
-
type: audienceType,
|
|
2310
|
-
enabled: true
|
|
2311
|
-
}
|
|
2312
|
-
});
|
|
2313
|
-
if (!binding && audienceType === "customers") {
|
|
2314
|
-
binding = await bindingRepo.findOne({
|
|
2264
|
+
try {
|
|
2265
|
+
const bindingRepo = dataSource.getRepository(entityMap.order_notification_bindings);
|
|
2266
|
+
let binding = await bindingRepo.findOne({
|
|
2315
2267
|
where: {
|
|
2316
2268
|
triggerKey,
|
|
2317
2269
|
channel,
|
|
2270
|
+
type: audienceType,
|
|
2318
2271
|
enabled: true
|
|
2319
2272
|
}
|
|
2320
|
-
});
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
}
|
|
2330
|
-
const templateId = binding.messageTemplateId;
|
|
2331
|
-
if (templateId == null) {
|
|
2332
|
-
console.warn("[order-notifications] binding exists but no template selected", {
|
|
2333
|
-
triggerKey,
|
|
2334
|
-
channel,
|
|
2335
|
-
audienceType
|
|
2336
|
-
});
|
|
2337
|
-
return null;
|
|
2338
|
-
}
|
|
2339
|
-
const template = await dataSource.getRepository(entityMap.message_templates).findOne({
|
|
2340
|
-
where: {
|
|
2341
|
-
id: templateId,
|
|
2342
|
-
channel,
|
|
2343
|
-
deleted: false,
|
|
2344
|
-
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);
|
|
2345
2282
|
}
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
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", {
|
|
2349
2320
|
triggerKey,
|
|
2350
2321
|
channel,
|
|
2351
2322
|
audienceType,
|
|
2352
|
-
|
|
2323
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2353
2324
|
});
|
|
2354
2325
|
return null;
|
|
2355
2326
|
}
|
|
2356
|
-
return template;
|
|
2357
2327
|
}
|
|
2358
2328
|
chunkUSNT2KNT_cjs.__name(loadBoundTemplate, "loadBoundTemplate");
|
|
2359
2329
|
function mergeTriggerVariables(payload, rich) {
|
|
@@ -2370,9 +2340,11 @@ function mergeTriggerVariables(payload, rich) {
|
|
|
2370
2340
|
refundAmount: String(payload.refundAmount)
|
|
2371
2341
|
} : {}
|
|
2372
2342
|
};
|
|
2343
|
+
const extraVars = payload.extraVariables ?? {};
|
|
2373
2344
|
return {
|
|
2374
2345
|
...basic,
|
|
2375
|
-
...rich ?? {}
|
|
2346
|
+
...rich ?? {},
|
|
2347
|
+
...extraVars
|
|
2376
2348
|
};
|
|
2377
2349
|
}
|
|
2378
2350
|
chunkUSNT2KNT_cjs.__name(mergeTriggerVariables, "mergeTriggerVariables");
|
|
@@ -2568,7 +2540,23 @@ async function getAdminRecipientEmails(dataSource, entityMap) {
|
|
|
2568
2540
|
}
|
|
2569
2541
|
} catch {
|
|
2570
2542
|
}
|
|
2571
|
-
|
|
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()));
|
|
2572
2560
|
}
|
|
2573
2561
|
chunkUSNT2KNT_cjs.__name(getAdminRecipientEmails, "getAdminRecipientEmails");
|
|
2574
2562
|
function formatBodyForEmailHtml(body) {
|
|
@@ -2802,6 +2790,8 @@ function initWhatsappTriggerDispatcher(deps) {
|
|
|
2802
2790
|
if (initialized) return;
|
|
2803
2791
|
initialized = true;
|
|
2804
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
|
+
});
|
|
2805
2795
|
chunkUCKN4BBY_cjs.notificationTriggerEmitter.onAnyTrigger((triggerKey, payload) => {
|
|
2806
2796
|
void handleTrigger(triggerKey, payload, dataSource, entityMap, getCms).catch((err) => {
|
|
2807
2797
|
console.error("[order-notifications]", triggerKey, err);
|
|
@@ -2886,5 +2876,4 @@ exports.resolveChatEmailToolSettings = resolveChatEmailToolSettings;
|
|
|
2886
2876
|
exports.sendChatLeadEmail = sendChatLeadEmail;
|
|
2887
2877
|
exports.sendFcmPushNotification = sendFcmPushNotification;
|
|
2888
2878
|
exports.serializeEmailRecipients = serializeEmailRecipients;
|
|
2889
|
-
exports.validateFcmCredentials = validateFcmCredentials;
|
|
2890
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
|
} : {}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validateInventoryForConfirmedOrderLines, orderStatusHoldsStock, reconcileOrderInventoryBetweenSnapshots, orderInventorySnapshotFromRow, validateInventoryForOrderBecomingConfirmed } from './chunk-3K5AIEIZ.js';
|
|
2
|
-
import { resolveChatEmailToolSettings, CHAT_EMAIL_LOG, detectChatLeadIntent, parseIntentRecipientEmails, sendChatLeadEmail, buildTranscriptForLeadEmail, buildChatbotSystemPromptWithEmailTool,
|
|
2
|
+
import { resolveChatEmailToolSettings, CHAT_EMAIL_LOG, detectChatLeadIntent, parseIntentRecipientEmails, sendChatLeadEmail, buildTranscriptForLeadEmail, buildChatbotSystemPromptWithEmailTool, sendFcmPushNotification, parseEmailRecipientsFromConfig, isWhatsAppPluginEnabled, mergeWhatsAppConfigLayers, whatsAppConfigured, WhatsAppService, registerWhatsAppQueueProcessor, emailPlugin, initWhatsappTriggerDispatcher } from './chunk-CTXBYO2J.js';
|
|
3
3
|
import { inviteStatusForActivation } from './chunk-JXF23MPG.js';
|
|
4
4
|
import { queueEmail, queueVendorOnboardEmails, registerEmailQueueProcessor } from './chunk-L3525VXI.js';
|
|
5
5
|
import { mergeEmailLayoutCompanyDetails, unwrapErpReadData, mapErpPayloadToFulfillment, extractChildOrderRefsFromSalePayload, mapErpPayloadToInvoiceNumber, streamOrderInvoicePdf } from './chunk-2KUCQVAQ.js';
|
|
@@ -2966,46 +2966,51 @@ async function calculateOrderTotalsFromLines(dataSource, entityMap, lineInputs,
|
|
|
2966
2966
|
total
|
|
2967
2967
|
});
|
|
2968
2968
|
}
|
|
2969
|
-
|
|
2969
|
+
const dIds = Array.isArray(discountId) ? discountId.filter((id) => id != null && Number.isFinite(id) && id > 0) : discountId != null && Number.isFinite(discountId) && discountId > 0 ? [
|
|
2970
|
+
discountId
|
|
2971
|
+
] : [];
|
|
2972
|
+
if (dIds.length > 0 && entityMap["discounts"]) {
|
|
2970
2973
|
try {
|
|
2971
2974
|
const discountRepo = dataSource.getRepository(entityMap["discounts"]);
|
|
2972
2975
|
const rulesRepo = entityMap["discount_rules"] ? dataSource.getRepository(entityMap["discount_rules"]) : null;
|
|
2973
|
-
const
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
const discountedAmount = line.subtotal - (line.discount ?? 0);
|
|
3000
|
-
line.tax = discountedAmount * line.taxRate / 100;
|
|
3001
|
-
line.total = discountedAmount + line.tax;
|
|
2976
|
+
for (const dId of dIds) {
|
|
2977
|
+
const discountRow = await discountRepo.findOne({
|
|
2978
|
+
where: withDiscountVendorWhere({
|
|
2979
|
+
id: dId
|
|
2980
|
+
}, vendorId)
|
|
2981
|
+
});
|
|
2982
|
+
if (discountRow) {
|
|
2983
|
+
const flatRules = rulesRepo ? await rulesRepo.find({
|
|
2984
|
+
where: {
|
|
2985
|
+
discountId: dId
|
|
2986
|
+
}
|
|
2987
|
+
}) : [];
|
|
2988
|
+
const discountForEval = {
|
|
2989
|
+
...discountRow,
|
|
2990
|
+
rules: flatRules
|
|
2991
|
+
};
|
|
2992
|
+
const cartLines = lines.filter((l) => l.found && l.productId != null).map((l) => ({
|
|
2993
|
+
productId: l.productId,
|
|
2994
|
+
quantity: l.quantity,
|
|
2995
|
+
unitPrice: l.unitPrice,
|
|
2996
|
+
subtotal: l.subtotal
|
|
2997
|
+
}));
|
|
2998
|
+
const evalResult = evaluateDiscount(discountForEval, cartLines);
|
|
2999
|
+
if (evalResult.conditionsMet) {
|
|
3000
|
+
const totalDiscountApplied = applyDiscountToOrderLines(lines, evalResult, discountRow.maxDiscountAmount);
|
|
3001
|
+
orderDiscount += totalDiscountApplied;
|
|
3002
3002
|
}
|
|
3003
|
-
orderDiscount = totalDiscountApplied;
|
|
3004
|
-
orderTotal = lines.reduce((s, l) => s + l.total, 0);
|
|
3005
|
-
orderSubTotal = lines.reduce((s, l) => s + l.subtotal, 0);
|
|
3006
|
-
orderTax = lines.reduce((s, l) => s + l.tax, 0);
|
|
3007
3003
|
}
|
|
3008
3004
|
}
|
|
3005
|
+
for (const line of lines) {
|
|
3006
|
+
if (!line.found || line.taxRate === 0) continue;
|
|
3007
|
+
const discountedAmount = Math.max(0, line.subtotal - (line.discount ?? 0));
|
|
3008
|
+
line.tax = discountedAmount * line.taxRate / 100;
|
|
3009
|
+
line.total = discountedAmount + line.tax;
|
|
3010
|
+
}
|
|
3011
|
+
orderTotal = lines.reduce((s, l) => s + l.total, 0);
|
|
3012
|
+
orderSubTotal = lines.reduce((s, l) => s + l.subtotal, 0);
|
|
3013
|
+
orderTax = lines.reduce((s, l) => s + l.tax, 0);
|
|
3009
3014
|
} catch (err) {
|
|
3010
3015
|
logCrudServerError("discount evaluation failed", {
|
|
3011
3016
|
discountId,
|
|
@@ -5039,7 +5044,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5039
5044
|
await recordDiscountUsage2(dataSource, entityMap, created.id, orderDiscountId, persistBody.contactId, discount);
|
|
5040
5045
|
}
|
|
5041
5046
|
const orderIdForNotify = created.id;
|
|
5042
|
-
void import('./emit-order-notification-trigger-
|
|
5047
|
+
void import('./emit-order-notification-trigger-HZQPPSFB.js').then(({ fireOrderNotificationTrigger }) => {
|
|
5043
5048
|
fireOrderNotificationTrigger("order_placed", orderIdForNotify, {
|
|
5044
5049
|
dataSource,
|
|
5045
5050
|
entityMap
|
|
@@ -5216,9 +5221,14 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5216
5221
|
const where = hasDeleted ? {
|
|
5217
5222
|
deleted: false
|
|
5218
5223
|
} : {};
|
|
5219
|
-
|
|
5224
|
+
let data = await repo.find({
|
|
5220
5225
|
where
|
|
5221
5226
|
});
|
|
5227
|
+
const scope = await resolveScope();
|
|
5228
|
+
const flags = await getVendorCatalogCreateFlags(dataSource);
|
|
5229
|
+
if (scope.type !== "all") {
|
|
5230
|
+
data = data.filter((row) => vendorScopeRowAccess(row, scope, resource, flags) === "ok");
|
|
5231
|
+
}
|
|
5222
5232
|
const excludeCols = /* @__PURE__ */ new Set([
|
|
5223
5233
|
"deletedAt",
|
|
5224
5234
|
"deletedBy",
|
|
@@ -12995,17 +13005,80 @@ async function getSettingsGroup(deps, group) {
|
|
|
12995
13005
|
]));
|
|
12996
13006
|
}
|
|
12997
13007
|
__name(getSettingsGroup, "getSettingsGroup");
|
|
13008
|
+
async function getSuperAdminEmails(deps) {
|
|
13009
|
+
try {
|
|
13010
|
+
const ds = await deps.getDataSource();
|
|
13011
|
+
if (!deps.entityMap.users) return [];
|
|
13012
|
+
const userRepo = ds.getRepository(deps.entityMap.users);
|
|
13013
|
+
const superAdmins = await userRepo.createQueryBuilder("u").leftJoin("u.group", "g").where("u.deleted = false").andWhere("u.blocked = false").andWhere("(u.groupId = 1 OR LOWER(g.name) IN (:...adminGroupNames) OR u.adminAccess = true)", {
|
|
13014
|
+
adminGroupNames: [
|
|
13015
|
+
"administrator",
|
|
13016
|
+
"admin",
|
|
13017
|
+
"super admin",
|
|
13018
|
+
"superadmin"
|
|
13019
|
+
]
|
|
13020
|
+
}).select([
|
|
13021
|
+
"u.email"
|
|
13022
|
+
]).getMany();
|
|
13023
|
+
return superAdmins.map((u) => String(u.email ?? "").trim().toLowerCase()).filter((e) => Boolean(e));
|
|
13024
|
+
} catch {
|
|
13025
|
+
return [];
|
|
13026
|
+
}
|
|
13027
|
+
}
|
|
13028
|
+
__name(getSuperAdminEmails, "getSuperAdminEmails");
|
|
13029
|
+
async function getVendorEmails(deps) {
|
|
13030
|
+
const emails = /* @__PURE__ */ new Set();
|
|
13031
|
+
try {
|
|
13032
|
+
const ds = await deps.getDataSource();
|
|
13033
|
+
if (deps.entityMap.vendors) {
|
|
13034
|
+
const vendors = await ds.getRepository(deps.entityMap.vendors).find({
|
|
13035
|
+
where: {
|
|
13036
|
+
deleted: false
|
|
13037
|
+
},
|
|
13038
|
+
select: [
|
|
13039
|
+
"email"
|
|
13040
|
+
]
|
|
13041
|
+
});
|
|
13042
|
+
for (const v of vendors) {
|
|
13043
|
+
const e = String(v.email ?? "").trim().toLowerCase();
|
|
13044
|
+
if (e) emails.add(e);
|
|
13045
|
+
}
|
|
13046
|
+
}
|
|
13047
|
+
if (deps.entityMap.users) {
|
|
13048
|
+
const vendorUsers = await ds.getRepository(deps.entityMap.users).createQueryBuilder("u").leftJoin("u.group", "g").where("u.deleted = false").andWhere("(LOWER(g.name) LIKE :vGroup OR u.groupId = 5)", {
|
|
13049
|
+
vGroup: "%vendor%"
|
|
13050
|
+
}).select([
|
|
13051
|
+
"u.email"
|
|
13052
|
+
]).getMany();
|
|
13053
|
+
for (const u of vendorUsers) {
|
|
13054
|
+
const e = String(u.email ?? "").trim().toLowerCase();
|
|
13055
|
+
if (e) emails.add(e);
|
|
13056
|
+
}
|
|
13057
|
+
}
|
|
13058
|
+
} catch {
|
|
13059
|
+
}
|
|
13060
|
+
return emails;
|
|
13061
|
+
}
|
|
13062
|
+
__name(getVendorEmails, "getVendorEmails");
|
|
12998
13063
|
async function sendVendorOnboardEmails(input, deps) {
|
|
12999
13064
|
let ownerEmailSent = false;
|
|
13000
13065
|
try {
|
|
13001
|
-
const [branding, emailSettings] = await Promise.all([
|
|
13066
|
+
const [branding, emailSettings, superAdminEmails, vendorEmailSet] = await Promise.all([
|
|
13002
13067
|
getSettingsGroup(deps, "branding"),
|
|
13003
|
-
getSettingsGroup(deps, "email")
|
|
13068
|
+
getSettingsGroup(deps, "email"),
|
|
13069
|
+
getSuperAdminEmails(deps),
|
|
13070
|
+
getVendorEmails(deps)
|
|
13004
13071
|
]);
|
|
13005
13072
|
const companyDetails = mergeEmailLayoutCompanyDetails(branding, emailSettings);
|
|
13006
|
-
const
|
|
13007
|
-
const sendToOwner = input.sendToOwner !== false;
|
|
13073
|
+
const configuredNotify = parseEmailRecipientsFromConfig(emailSettings.salesTeamEmails ?? emailSettings.salesTeamEmail);
|
|
13008
13074
|
const ownerEmail = input.ownerEmail?.trim() || "";
|
|
13075
|
+
const ownerEmailLower = ownerEmail.toLowerCase();
|
|
13076
|
+
const sendToOwner = input.sendToOwner !== false;
|
|
13077
|
+
const combined = [
|
|
13078
|
+
...configuredNotify,
|
|
13079
|
+
...superAdminEmails
|
|
13080
|
+
];
|
|
13081
|
+
const notifyEmails = Array.from(new Set(combined.map((e) => e.trim().toLowerCase()).filter((e) => e && e !== ownerEmailLower && !vendorEmailSet.has(e))));
|
|
13009
13082
|
const cms = await deps.getCms();
|
|
13010
13083
|
await queueVendorOnboardEmails(cms, {
|
|
13011
13084
|
vendorName: input.vendorName,
|
|
@@ -13152,8 +13225,6 @@ async function getDefaultStaffRoleIdForVendor(em, vendorId) {
|
|
|
13152
13225
|
return id != null ? Number(id) : null;
|
|
13153
13226
|
}
|
|
13154
13227
|
__name(getDefaultStaffRoleIdForVendor, "getDefaultStaffRoleIdForVendor");
|
|
13155
|
-
|
|
13156
|
-
// src/lib/vendor-profile.ts
|
|
13157
13228
|
var VENDOR_REGISTRATION_STATUSES = [
|
|
13158
13229
|
{
|
|
13159
13230
|
value: "pending",
|
|
@@ -13172,6 +13243,30 @@ var VENDOR_REGISTRATION_STATUSES = [
|
|
|
13172
13243
|
label: "Suspended"
|
|
13173
13244
|
}
|
|
13174
13245
|
];
|
|
13246
|
+
(() => {
|
|
13247
|
+
const list = [];
|
|
13248
|
+
const seenCodes = /* @__PURE__ */ new Set();
|
|
13249
|
+
for (const c of Country.getAllCountries()) {
|
|
13250
|
+
if (!c.phonecode) continue;
|
|
13251
|
+
const rawCode = c.phonecode.replace(/^\+/, "").trim();
|
|
13252
|
+
if (!rawCode) continue;
|
|
13253
|
+
const code = `+${rawCode}`;
|
|
13254
|
+
const key = `${code}-${c.name}`;
|
|
13255
|
+
if (seenCodes.has(key)) continue;
|
|
13256
|
+
seenCodes.add(key);
|
|
13257
|
+
list.push({
|
|
13258
|
+
code,
|
|
13259
|
+
country: c.name,
|
|
13260
|
+
isoCode: c.isoCode,
|
|
13261
|
+
label: `${code} (${c.name})`
|
|
13262
|
+
});
|
|
13263
|
+
}
|
|
13264
|
+
return list.sort((a, b) => {
|
|
13265
|
+
if (a.code === "+91" && b.code !== "+91") return -1;
|
|
13266
|
+
if (b.code === "+91" && a.code !== "+91") return 1;
|
|
13267
|
+
return a.country.localeCompare(b.country);
|
|
13268
|
+
});
|
|
13269
|
+
})();
|
|
13175
13270
|
function trimOrNull(value) {
|
|
13176
13271
|
if (typeof value !== "string") return null;
|
|
13177
13272
|
const trimmed = value.trim();
|
|
@@ -13224,11 +13319,27 @@ function parseVendorPersonProfileFromBody(raw, fallbacks) {
|
|
|
13224
13319
|
};
|
|
13225
13320
|
}
|
|
13226
13321
|
__name(parseVendorPersonProfileFromBody, "parseVendorPersonProfileFromBody");
|
|
13227
|
-
function
|
|
13228
|
-
|
|
13229
|
-
|
|
13322
|
+
function validateGstin(gstin, options) {
|
|
13323
|
+
const required = options?.required === true;
|
|
13324
|
+
if (!gstin || !gstin.trim()) {
|
|
13325
|
+
if (required) return "GSTIN number is required";
|
|
13326
|
+
return null;
|
|
13327
|
+
}
|
|
13328
|
+
if (!/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/i.test(gstin.trim())) {
|
|
13329
|
+
return "Invalid GSTIN number (15 characters, e.g. 22AAAAA0000A1Z5)";
|
|
13330
|
+
}
|
|
13331
|
+
return null;
|
|
13332
|
+
}
|
|
13333
|
+
__name(validateGstin, "validateGstin");
|
|
13334
|
+
function validateIndiaTaxIds(gstin, pan, options) {
|
|
13335
|
+
const gstinErr = validateGstin(gstin, {
|
|
13336
|
+
required: options?.requiredGstin
|
|
13337
|
+
});
|
|
13338
|
+
if (gstinErr) return gstinErr;
|
|
13339
|
+
if (options?.requiredPan && (!pan || !pan.trim())) {
|
|
13340
|
+
return "PAN is required";
|
|
13230
13341
|
}
|
|
13231
|
-
if (pan && !/^[A-Z]{5}[0-9]{4}[A-Z]$/i.test(pan)) {
|
|
13342
|
+
if (pan && !/^[A-Z]{5}[0-9]{4}[A-Z]$/i.test(pan.trim())) {
|
|
13232
13343
|
return "Invalid PAN format (e.g. ABCDE1234F)";
|
|
13233
13344
|
}
|
|
13234
13345
|
return null;
|
|
@@ -13236,7 +13347,7 @@ function validateIndiaTaxIds(gstin, pan) {
|
|
|
13236
13347
|
__name(validateIndiaTaxIds, "validateIndiaTaxIds");
|
|
13237
13348
|
function validateAadhaar(aadhaar) {
|
|
13238
13349
|
if (!aadhaar) return null;
|
|
13239
|
-
if (!/^[0-9]{12}$/.test(aadhaar)) {
|
|
13350
|
+
if (!/^[0-9]{12}$/.test(aadhaar.replace(/\s+/g, ""))) {
|
|
13240
13351
|
return "Invalid Aadhaar number (12 digits)";
|
|
13241
13352
|
}
|
|
13242
13353
|
return null;
|
|
@@ -13244,11 +13355,13 @@ function validateAadhaar(aadhaar) {
|
|
|
13244
13355
|
__name(validateAadhaar, "validateAadhaar");
|
|
13245
13356
|
function validatePersonKyc(person, options) {
|
|
13246
13357
|
const required = options?.required === true;
|
|
13247
|
-
if (required && !person.aadhaarNo) return "Aadhaar number is required";
|
|
13248
|
-
if (required && !person.panNo) return "PAN is required";
|
|
13358
|
+
if (required && (!person.aadhaarNo || !person.aadhaarNo.trim())) return "Aadhaar number is required";
|
|
13359
|
+
if (required && (!person.panNo || !person.panNo.trim())) return "PAN is required";
|
|
13249
13360
|
const aadhaarErr = validateAadhaar(person.aadhaarNo ?? null);
|
|
13250
13361
|
if (aadhaarErr) return aadhaarErr;
|
|
13251
|
-
const panErr = validateIndiaTaxIds(null, person.panNo ?? null
|
|
13362
|
+
const panErr = validateIndiaTaxIds(null, person.panNo ?? null, {
|
|
13363
|
+
requiredPan: required
|
|
13364
|
+
});
|
|
13252
13365
|
if (panErr) return panErr;
|
|
13253
13366
|
return null;
|
|
13254
13367
|
}
|
|
@@ -13594,7 +13707,9 @@ function createVendorOnboardHandlers(config) {
|
|
|
13594
13707
|
}, {
|
|
13595
13708
|
getDataSource: /* @__PURE__ */ __name(async () => dataSource, "getDataSource"),
|
|
13596
13709
|
entityMap: {
|
|
13597
|
-
configs: entityMap.configs
|
|
13710
|
+
configs: entityMap.configs,
|
|
13711
|
+
users: entityMap.users,
|
|
13712
|
+
vendors: entityMap.vendors
|
|
13598
13713
|
},
|
|
13599
13714
|
getCms
|
|
13600
13715
|
});
|
|
@@ -13720,7 +13835,9 @@ function createVendorOnboardHandlers(config) {
|
|
|
13720
13835
|
const profile = parseVendorProfileFromBody(body.vendor, {
|
|
13721
13836
|
defaultRegistrationStatus: "approved"
|
|
13722
13837
|
});
|
|
13723
|
-
const gstError =
|
|
13838
|
+
const gstError = validateGstin(profile.gstin, {
|
|
13839
|
+
required: true
|
|
13840
|
+
});
|
|
13724
13841
|
if (gstError) return json({
|
|
13725
13842
|
error: gstError
|
|
13726
13843
|
}, {
|
|
@@ -29361,7 +29478,10 @@ function createCmsApiHandler(config) {
|
|
|
29361
29478
|
if (pe) return pe;
|
|
29362
29479
|
try {
|
|
29363
29480
|
const body = await req.json();
|
|
29364
|
-
const
|
|
29481
|
+
const discountIdsRaw = Array.isArray(body?.discountIds) ? body.discountIds : body?.discountId ? [
|
|
29482
|
+
body.discountId
|
|
29483
|
+
] : [];
|
|
29484
|
+
const discountIds = discountIdsRaw.map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
29365
29485
|
const currency = typeof body?.currency === "string" ? body.currency.trim().toUpperCase() : "INR";
|
|
29366
29486
|
let vendorId = null;
|
|
29367
29487
|
if (resolveSessionUser) {
|
|
@@ -29371,7 +29491,7 @@ function createCmsApiHandler(config) {
|
|
|
29371
29491
|
}
|
|
29372
29492
|
const orderLinesNorm = normalizeOrderLinesInput(body?.orderLines);
|
|
29373
29493
|
if (orderLinesNorm && orderLinesNorm.length > 0) {
|
|
29374
|
-
const result2 = await calculateOrderTotalsFromLines(dataSource, entityMap, orderLinesNorm, currency,
|
|
29494
|
+
const result2 = await calculateOrderTotalsFromLines(dataSource, entityMap, orderLinesNorm, currency, discountIds.length > 0 ? discountIds : null, vendorId);
|
|
29375
29495
|
return config.json(result2);
|
|
29376
29496
|
}
|
|
29377
29497
|
const itemsSummary = String(body?.itemsSummary ?? "").trim();
|
|
@@ -29384,7 +29504,7 @@ function createCmsApiHandler(config) {
|
|
|
29384
29504
|
lines: []
|
|
29385
29505
|
});
|
|
29386
29506
|
}
|
|
29387
|
-
const result = await calculateOrderTotals(dataSource, entityMap, itemsSummary,
|
|
29507
|
+
const result = await calculateOrderTotals(dataSource, entityMap, itemsSummary, discountIds[0] ?? null, vendorId);
|
|
29388
29508
|
return config.json(result);
|
|
29389
29509
|
} catch (err) {
|
|
29390
29510
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -29572,7 +29692,7 @@ function createCmsApiHandler(config) {
|
|
|
29572
29692
|
status: 400
|
|
29573
29693
|
});
|
|
29574
29694
|
}
|
|
29575
|
-
const { resendOrderNotification } = await import('./order-notification-dispatcher-
|
|
29695
|
+
const { resendOrderNotification } = await import('./order-notification-dispatcher-AT4IFAGL.js');
|
|
29576
29696
|
const result = await resendOrderNotification(triggerKey, orderId, {
|
|
29577
29697
|
dataSource,
|
|
29578
29698
|
entityMap,
|
|
@@ -29672,7 +29792,7 @@ function createCmsApiHandler(config) {
|
|
|
29672
29792
|
status: "cancelled"
|
|
29673
29793
|
});
|
|
29674
29794
|
const fireOrderCancelledNotification = /* @__PURE__ */ __name((refundAmount) => {
|
|
29675
|
-
void import('./emit-order-notification-trigger-
|
|
29795
|
+
void import('./emit-order-notification-trigger-HZQPPSFB.js').then(({ fireOrderNotificationTrigger }) => {
|
|
29676
29796
|
fireOrderNotificationTrigger("order_cancelled", orderId, {
|
|
29677
29797
|
dataSource,
|
|
29678
29798
|
entityMap
|
|
@@ -30705,7 +30825,7 @@ function createStorefrontApiHandler(config) {
|
|
|
30705
30825
|
const otpPepper = config.otpPepper;
|
|
30706
30826
|
const defaultPhoneCc = config.defaultPhoneCountryCode;
|
|
30707
30827
|
function fireOrderPlacedNotification(orderId) {
|
|
30708
|
-
void import('./emit-order-notification-trigger-
|
|
30828
|
+
void import('./emit-order-notification-trigger-HZQPPSFB.js').then(({ fireOrderNotificationTrigger }) => {
|
|
30709
30829
|
fireOrderNotificationTrigger("order_placed", orderId, {
|
|
30710
30830
|
dataSource,
|
|
30711
30831
|
entityMap
|
|
@@ -61,7 +61,7 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
|
|
|
61
61
|
total: fo.total ?? 0,
|
|
62
62
|
currency: String(fo.currency ?? "INR"),
|
|
63
63
|
vendorId: fo.vendorId ?? null,
|
|
64
|
-
|
|
64
|
+
extraVariables: extra?.extraVariables,
|
|
65
65
|
...extra?.refundAmount != null ? {
|
|
66
66
|
refundAmount: extra.refundAmount
|
|
67
67
|
} : {}
|