@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.
@@ -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-UUWAUHUW.cjs', document.baseURI).href)));
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 resolved = await resolveFcmServiceAccount(dataSource, entityMap);
2187
- if (!resolved.ok) {
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: resolved.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
- const bindingRepo = dataSource.getRepository(entityMap.order_notification_bindings);
2305
- let binding = await bindingRepo.findOne({
2306
- where: {
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
- if (!binding) {
2323
- console.warn("[order-notifications] no order_notification_bindings row", {
2324
- triggerKey,
2325
- channel,
2326
- audienceType
2327
- });
2328
- return null;
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
- if (!template) {
2348
- console.warn("[order-notifications] bound template not found or disabled", {
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
- templateId
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
- return Array.from(emails);
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
- ...extra?.extraVariables ?? {},
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, validateFcmCredentials, sendFcmPushNotification, parseEmailRecipientsFromConfig, isWhatsAppPluginEnabled, mergeWhatsAppConfigLayers, whatsAppConfigured, WhatsAppService, registerWhatsAppQueueProcessor, emailPlugin, initWhatsappTriggerDispatcher } from './chunk-IPDHT2UV.js';
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
- if (discountId && entityMap["discounts"]) {
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 discountRow = await discountRepo.findOne({
2974
- where: withDiscountVendorWhere({
2975
- id: discountId
2976
- }, vendorId)
2977
- });
2978
- if (discountRow) {
2979
- const flatRules = rulesRepo ? await rulesRepo.find({
2980
- where: {
2981
- discountId
2982
- }
2983
- }) : [];
2984
- const discountForEval = {
2985
- ...discountRow,
2986
- rules: flatRules
2987
- };
2988
- const cartLines = lines.filter((l) => l.found && l.productId != null).map((l) => ({
2989
- productId: l.productId,
2990
- quantity: l.quantity,
2991
- unitPrice: l.unitPrice,
2992
- subtotal: l.subtotal
2993
- }));
2994
- const evalResult = evaluateDiscount(discountForEval, cartLines);
2995
- if (evalResult.conditionsMet) {
2996
- const totalDiscountApplied = applyDiscountToOrderLines(lines, evalResult, discountRow.maxDiscountAmount);
2997
- for (const line of lines) {
2998
- if (!line.found || line.taxRate === 0) continue;
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-6XX7LSC4.js').then(({ fireOrderNotificationTrigger }) => {
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
- const data = await repo.find({
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 notifyEmails = parseEmailRecipientsFromConfig(emailSettings.salesTeamEmails ?? emailSettings.salesTeamEmail);
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 validateIndiaTaxIds(gstin, pan) {
13228
- if (gstin && !/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/i.test(gstin)) {
13229
- return "Invalid GSTIN format (15 characters, e.g. 22AAAAA0000A1Z5)";
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 = validateIndiaTaxIds(profile.gstin, null);
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 discountId = body?.discountId ? Number(body.discountId) : null;
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, discountId, vendorId);
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, discountId, vendorId);
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-3TA4ETYJ.js');
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-6XX7LSC4.js').then(({ fireOrderNotificationTrigger }) => {
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-6XX7LSC4.js').then(({ fireOrderNotificationTrigger }) => {
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
- ...extra?.extraVariables ?? {},
64
+ extraVariables: extra?.extraVariables,
65
65
  ...extra?.refundAmount != null ? {
66
66
  refundAmount: extra.refundAmount
67
67
  } : {}