@infuro/cms-core 1.0.67 → 1.0.68

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.
Files changed (48) hide show
  1. package/dist/admin.cjs +121 -12
  2. package/dist/admin.js +121 -12
  3. package/dist/api.cjs +43 -40
  4. package/dist/api.js +11 -8
  5. package/dist/auth.cjs +12 -12
  6. package/dist/auth.js +2 -2
  7. package/dist/{chunk-BVLN75LP.cjs → chunk-22XKONB5.cjs} +201 -71
  8. package/dist/{chunk-TU23GJPJ.js → chunk-7JCCPQEF.js} +1 -1
  9. package/dist/{chunk-WMMZZRDJ.cjs → chunk-GN4LKG4V.cjs} +1 -1
  10. package/dist/chunk-IKTBZJHT.js +16 -0
  11. package/dist/chunk-M5GPOPGX.cjs +49 -0
  12. package/dist/{chunk-GLLCLRCQ.js → chunk-MYUGQHU4.js} +158 -28
  13. package/dist/{chunk-NV5IRHI3.js → chunk-N4LBZXBG.js} +2 -2
  14. package/dist/chunk-P6S4XFZO.cjs +18 -0
  15. package/dist/{chunk-RCE5SJBA.js → chunk-SKJH7PX4.js} +1 -1
  16. package/dist/{chunk-5MZFQRDW.cjs → chunk-SMHQV3WL.cjs} +4 -4
  17. package/dist/chunk-SUUD7OUG.cjs +455 -0
  18. package/dist/{chunk-XFDIIVZB.cjs → chunk-UMC7W5G3.cjs} +3 -3
  19. package/dist/chunk-WKDBMDUX.js +45 -0
  20. package/dist/chunk-Z5OB5QGN.js +465 -0
  21. package/dist/chunk-ZIT4IP6N.js +445 -0
  22. package/dist/chunk-ZX5U3VCB.cjs +471 -0
  23. package/dist/email-queue-3QBQ63F7.js +8 -0
  24. package/dist/{email-queue-4OY45JIU.cjs → email-queue-K4E4OFI7.cjs} +9 -6
  25. package/dist/{emit-order-notification-trigger-ZD5YN3JM.cjs → emit-order-notification-trigger-ROASTYQP.cjs} +3 -3
  26. package/dist/{emit-order-notification-trigger-EJJZ6XTS.js → emit-order-notification-trigger-YUQTPELC.js} +1 -1
  27. package/dist/{erp-order-invoice-YUSPZ7CE.cjs → erp-order-invoice-AZ5MX2JB.cjs} +8 -5
  28. package/dist/{erp-order-invoice-H6HCJ7YS.js → erp-order-invoice-XSYHAMBS.js} +4 -1
  29. package/dist/generate-local-invoice-pdf-BQTCL5MW.cjs +12 -0
  30. package/dist/generate-local-invoice-pdf-OCFG47SE.js +3 -0
  31. package/dist/index.cjs +286 -283
  32. package/dist/index.d.cts +7 -1
  33. package/dist/index.d.ts +7 -1
  34. package/dist/index.js +16 -13
  35. package/dist/invoice-templates-GZ33OENC.js +2 -0
  36. package/dist/invoice-templates-RB462AQN.cjs +19 -0
  37. package/dist/{order-completion-otp-handlers-DZAXK4GQ.cjs → order-completion-otp-handlers-DDQREULW.cjs} +8 -5
  38. package/dist/{order-completion-otp-handlers-HFGCPC4O.js → order-completion-otp-handlers-NROWBGXN.js} +6 -3
  39. package/dist/{order-notification-dispatcher-LL7ETKLU.cjs → order-notification-dispatcher-6HCJ6Q75.cjs} +12 -9
  40. package/dist/{order-notification-dispatcher-ECPFI7CD.js → order-notification-dispatcher-KM2SY7TX.js} +7 -4
  41. package/dist/resolve-invoice-asset-url-JEZRENJW.cjs +11 -0
  42. package/dist/resolve-invoice-asset-url-QZ2FRDHI.js +2 -0
  43. package/package.json +1 -1
  44. package/dist/chunk-GLD263KW.cjs +0 -862
  45. package/dist/chunk-OPJEV44S.js +0 -847
  46. package/dist/email-queue-HGXB2FIS.js +0 -5
  47. package/dist/{chunk-SS3K7OIM.cjs → chunk-HBUV73RB.cjs} +1 -1
  48. package/dist/{chunk-2ISSXYBZ.js → chunk-Z5G54EGD.js} +1 -1
@@ -0,0 +1,445 @@
1
+ import { isErpIntegrationEnabled } from './chunk-JC6DLWTE.js';
2
+ import { generateLocalInvoicePdf } from './chunk-Z5OB5QGN.js';
3
+ import { normalizeInvoiceTemplateId } from './chunk-WKDBMDUX.js';
4
+ import { resolveInvoiceAssetUrl } from './chunk-IKTBZJHT.js';
5
+ import { mergeEmailLayoutCompanyDetails, getCompanyDetailsFromSettings } from './chunk-YRCKEGL2.js';
6
+ import { __name } from './chunk-SHUYVCID.js';
7
+
8
+ // src/plugins/erp/erp-response-map.ts
9
+ function pickString(o, keys) {
10
+ for (const k of keys) {
11
+ const v = o[k];
12
+ if (typeof v === "string" && v.trim()) return v.trim();
13
+ }
14
+ return void 0;
15
+ }
16
+ __name(pickString, "pickString");
17
+ function unwrapErpReadData(json) {
18
+ if (!json || typeof json !== "object") return null;
19
+ const o = json;
20
+ const d = o.data;
21
+ if (d && typeof d === "object" && !Array.isArray(d)) return d;
22
+ return o;
23
+ }
24
+ __name(unwrapErpReadData, "unwrapErpReadData");
25
+ function firstObject(data, keys) {
26
+ for (const k of keys) {
27
+ const v = data[k];
28
+ if (v && typeof v === "object" && !Array.isArray(v)) return v;
29
+ }
30
+ return null;
31
+ }
32
+ __name(firstObject, "firstObject");
33
+ function extractEvents(src) {
34
+ const timeline = src.timeline ?? src.events ?? src.history ?? src.trackingEvents;
35
+ if (!Array.isArray(timeline) || !timeline.length) return void 0;
36
+ const events = [];
37
+ for (const row of timeline) {
38
+ if (!row || typeof row !== "object") continue;
39
+ const r = row;
40
+ const at = pickString(r, [
41
+ "at",
42
+ "timestamp",
43
+ "date",
44
+ "occurredAt"
45
+ ]) ?? (r.at instanceof Date ? r.at.toISOString() : void 0);
46
+ const label = pickString(r, [
47
+ "label",
48
+ "status",
49
+ "title",
50
+ "message",
51
+ "description"
52
+ ]);
53
+ const detail = pickString(r, [
54
+ "detail",
55
+ "notes",
56
+ "description"
57
+ ]);
58
+ if (at || label || detail) events.push({
59
+ at,
60
+ label,
61
+ detail
62
+ });
63
+ }
64
+ return events.length ? events : void 0;
65
+ }
66
+ __name(extractEvents, "extractEvents");
67
+ function mapErpPayloadToFulfillment(data) {
68
+ const nested = firstObject(data, [
69
+ "fulfillment",
70
+ "packaging",
71
+ "shipment",
72
+ "shipping",
73
+ "delivery"
74
+ ]);
75
+ const src = nested || data;
76
+ const status = pickString(src, [
77
+ "status",
78
+ "fulfillmentStatus",
79
+ "state",
80
+ "label",
81
+ "packagingStatus"
82
+ ]);
83
+ const trackingId = pickString(src, [
84
+ "trackingId",
85
+ "tracking_id",
86
+ "trackingNumber",
87
+ "awb",
88
+ "trackingUrl"
89
+ ]);
90
+ const events = extractEvents(src);
91
+ if (!status && !trackingId && !(events && events.length)) return void 0;
92
+ return {
93
+ status,
94
+ trackingId,
95
+ events
96
+ };
97
+ }
98
+ __name(mapErpPayloadToFulfillment, "mapErpPayloadToFulfillment");
99
+ function mapErpPayloadToInvoiceNumber(data) {
100
+ const nested = firstObject(data, [
101
+ "invoice",
102
+ "latestInvoice",
103
+ "postedInvoice"
104
+ ]);
105
+ const src = nested || data;
106
+ return pickString(src, [
107
+ "invoiceNumber",
108
+ "invoice_number",
109
+ "number",
110
+ "name",
111
+ "id"
112
+ ]);
113
+ }
114
+ __name(mapErpPayloadToInvoiceNumber, "mapErpPayloadToInvoiceNumber");
115
+ function extractChildOrderRefsFromSalePayload(data) {
116
+ const lists = [
117
+ data.returns,
118
+ data.returnOrders,
119
+ data.relatedReturns,
120
+ data.childOrders,
121
+ data.children
122
+ ];
123
+ const seen = /* @__PURE__ */ new Set();
124
+ const out = [];
125
+ for (const list of lists) {
126
+ if (!Array.isArray(list)) continue;
127
+ for (const item of list) {
128
+ if (!item || typeof item !== "object") continue;
129
+ const o = item;
130
+ const ref = pickString(o, [
131
+ "platformReturnId",
132
+ "platform_return_id",
133
+ "refId",
134
+ "ref_id"
135
+ ]) ?? (typeof o.id === "string" ? o.id : void 0);
136
+ if (!ref || seen.has(ref)) continue;
137
+ seen.add(ref);
138
+ const t = (pickString(o, [
139
+ "kind",
140
+ "type",
141
+ "orderKind"
142
+ ]) || "").toLowerCase();
143
+ const orderKind = /replac/.test(t) ? "replacement" : "return";
144
+ out.push({
145
+ ref,
146
+ orderKind
147
+ });
148
+ }
149
+ }
150
+ return out;
151
+ }
152
+ __name(extractChildOrderRefsFromSalePayload, "extractChildOrderRefsFromSalePayload");
153
+
154
+ // src/lib/invoice/build-local-invoice-for-order.ts
155
+ async function loadSettingsGroup(ds, entityMap, group) {
156
+ if (!entityMap.configs) return {};
157
+ const rows = await ds.getRepository(entityMap.configs).find({
158
+ where: {
159
+ settings: group,
160
+ deleted: false
161
+ }
162
+ });
163
+ return Object.fromEntries(rows.map((r) => [
164
+ r.key,
165
+ String(r.value ?? "")
166
+ ]));
167
+ }
168
+ __name(loadSettingsGroup, "loadSettingsGroup");
169
+ function addrFromRow(row) {
170
+ if (!row || typeof row !== "object") return null;
171
+ const a = row;
172
+ return {
173
+ line1: String(a.line1 ?? "").trim() || void 0,
174
+ line2: a.line2 != null ? String(a.line2).trim() || null : null,
175
+ city: String(a.city ?? "").trim() || void 0,
176
+ state: String(a.state ?? "").trim() || void 0,
177
+ postalCode: String(a.postalCode ?? "").trim() || void 0,
178
+ country: String(a.country ?? "").trim() || void 0
179
+ };
180
+ }
181
+ __name(addrFromRow, "addrFromRow");
182
+ async function buildLocalInvoicePdfForOrder(ds, entityMap, orderId) {
183
+ if (!entityMap.orders || !entityMap.order_items) {
184
+ return {
185
+ error: "Orders not configured",
186
+ status: 503
187
+ };
188
+ }
189
+ const orderRepo = ds.getRepository(entityMap.orders);
190
+ let order = null;
191
+ try {
192
+ order = await orderRepo.findOne({
193
+ where: {
194
+ id: orderId,
195
+ deleted: false
196
+ },
197
+ relations: [
198
+ "contact",
199
+ "billingAddress",
200
+ "shippingAddress",
201
+ "items",
202
+ "items.product",
203
+ "assignedUser"
204
+ ]
205
+ });
206
+ } catch {
207
+ try {
208
+ order = await orderRepo.findOne({
209
+ where: {
210
+ id: orderId,
211
+ deleted: false
212
+ },
213
+ relations: [
214
+ "contact",
215
+ "billingAddress",
216
+ "shippingAddress",
217
+ "items",
218
+ "assignedUser"
219
+ ]
220
+ });
221
+ } catch {
222
+ order = await orderRepo.findOne({
223
+ where: {
224
+ id: orderId,
225
+ deleted: false
226
+ },
227
+ relations: [
228
+ "contact",
229
+ "billingAddress",
230
+ "shippingAddress",
231
+ "items"
232
+ ]
233
+ });
234
+ }
235
+ }
236
+ if (!order) return {
237
+ error: "Not found",
238
+ status: 404
239
+ };
240
+ const o = order;
241
+ const kind = o.orderKind || "sale";
242
+ if (kind !== "sale") return {
243
+ error: "Invoice only for sale orders",
244
+ status: 400
245
+ };
246
+ const [store, branding, email] = await Promise.all([
247
+ loadSettingsGroup(ds, entityMap, "store"),
248
+ loadSettingsGroup(ds, entityMap, "branding"),
249
+ loadSettingsGroup(ds, entityMap, "email")
250
+ ]);
251
+ const companyDetails = mergeEmailLayoutCompanyDetails(branding, email, store);
252
+ const fromBranding = getCompanyDetailsFromSettings(branding);
253
+ const rawLogo = store.invoiceLogoUrl || store.companyLogo || store.logo || companyDetails.logoUrl || fromBranding.logoUrl || null;
254
+ const logoUrl = resolveInvoiceAssetUrl(rawLogo);
255
+ const companyName = store.companyName || store.invoiceCompanyName || store.name || companyDetails.companyName || fromBranding.companyName || "Store";
256
+ const supportEmail = store.companyEmail || store.invoiceEmail || store.email || companyDetails.supportEmail || fromBranding.supportEmail;
257
+ const supportPhone = store.companyPhone || store.invoicePhone || store.phone || companyDetails.supportPhone;
258
+ const address = store.companyAddress || store.invoiceAddress || store.address;
259
+ const lineItems = (o.items ?? []).map((it) => {
260
+ const name = it.product?.name && String(it.product.name).trim() || `Product #${it.productId ?? ""}`;
261
+ return {
262
+ name,
263
+ quantity: Math.max(0, Math.floor(Number(it.quantity) || 0)),
264
+ unitPrice: Number(it.unitPrice) || 0,
265
+ tax: Number(it.tax) || 0,
266
+ total: Number(it.total) || 0,
267
+ sku: it.product?.sku ?? null
268
+ };
269
+ });
270
+ const rawMeta = o.metadata || {};
271
+ const serviceDate = rawMeta.serviceDate || rawMeta.bookingDate || rawMeta.date || null;
272
+ const timeSlot = rawMeta.timeSlot || rawMeta.slot || rawMeta.time || null;
273
+ const assignedTo = o.assignedUser?.name || null;
274
+ const qrToken = o.qrToken || null;
275
+ const baseUrl = process.env.NEXTAUTH_URL || process.env.PUBLIC_APP_URL || "";
276
+ const qrData = qrToken ? baseUrl ? `${baseUrl.replace(/\/$/, "")}/track/${qrToken}` : `/track/${qrToken}` : String(o.orderNumber || orderId);
277
+ const includeQrCode = store.invoice_include_qr === "true" || store.invoiceIncludeQr === "true";
278
+ const bytes = await generateLocalInvoicePdf({
279
+ templateId: normalizeInvoiceTemplateId(store.invoiceTemplate),
280
+ orderNumber: String(o.orderNumber || orderId),
281
+ orderDate: o.createdAt || /* @__PURE__ */ new Date(),
282
+ serviceDate,
283
+ timeSlot,
284
+ assignedTo,
285
+ qrToken,
286
+ qrData,
287
+ includeQrCode,
288
+ currency: String(o.currency || store.currency || "INR"),
289
+ customerName: String(o.contact?.name ?? "").trim() || "Customer",
290
+ customerEmail: o.contact?.email ?? null,
291
+ customerPhone: o.contact?.phone ?? null,
292
+ billingAddress: addrFromRow(o.billingAddress),
293
+ shippingAddress: addrFromRow(o.shippingAddress),
294
+ lineItems,
295
+ subtotal: Number(o.subtotal) || 0,
296
+ tax: Number(o.tax) || 0,
297
+ discount: Number(o.discount) || 0,
298
+ total: Number(o.total) || 0,
299
+ company: {
300
+ name: companyName,
301
+ logoUrl,
302
+ supportEmail,
303
+ supportPhone,
304
+ address
305
+ }
306
+ });
307
+ return {
308
+ bytes,
309
+ filename: `invoice-${String(o.orderNumber || orderId).replace(/[^\w.-]+/g, "_")}.pdf`
310
+ };
311
+ }
312
+ __name(buildLocalInvoicePdfForOrder, "buildLocalInvoicePdfForOrder");
313
+
314
+ // src/plugins/erp/erp-order-invoice.ts
315
+ function pickInvoiceId(data) {
316
+ const nested = data.invoice && typeof data.invoice === "object" && !Array.isArray(data.invoice) ? data.invoice : null;
317
+ const src = nested || data;
318
+ for (const k of [
319
+ "invoiceId",
320
+ "invoice_id",
321
+ "id"
322
+ ]) {
323
+ const v = src[k];
324
+ if (typeof v === "string" && v.trim()) return v.trim();
325
+ }
326
+ return void 0;
327
+ }
328
+ __name(pickInvoiceId, "pickInvoiceId");
329
+ function jsonErr(msg, status) {
330
+ return new Response(JSON.stringify({
331
+ error: msg
332
+ }), {
333
+ status,
334
+ headers: {
335
+ "Content-Type": "application/json"
336
+ }
337
+ });
338
+ }
339
+ __name(jsonErr, "jsonErr");
340
+ var ORDER_INVOICE_EMAIL_ELIGIBLE_STATUSES = /* @__PURE__ */ new Set([
341
+ "pending",
342
+ "placed",
343
+ "confirmed",
344
+ "processing",
345
+ "completed"
346
+ ]);
347
+ function isOrderEligibleForInvoiceEmail(status, orderKind) {
348
+ const kind = (orderKind || "sale").trim().toLowerCase();
349
+ if (kind !== "sale") return false;
350
+ return ORDER_INVOICE_EMAIL_ELIGIBLE_STATUSES.has(String(status ?? "").trim().toLowerCase());
351
+ }
352
+ __name(isOrderEligibleForInvoiceEmail, "isOrderEligibleForInvoiceEmail");
353
+ async function resolveOrderInvoicePdfBytes(cms, dataSource, entityMap, orderId, options = {}) {
354
+ try {
355
+ const orderRepo = dataSource.getRepository(entityMap.orders);
356
+ const order = await orderRepo.findOne({
357
+ where: {
358
+ id: orderId,
359
+ deleted: false
360
+ }
361
+ });
362
+ if (!order) return {
363
+ error: "Not found",
364
+ status: 404
365
+ };
366
+ const kind = order.orderKind || "sale";
367
+ if (kind !== "sale") return {
368
+ error: "Invoice only for sale orders",
369
+ status: 400
370
+ };
371
+ if (options.ownerContactId != null && order.contactId !== options.ownerContactId) {
372
+ return {
373
+ error: "Not found",
374
+ status: 404
375
+ };
376
+ }
377
+ const on = await isErpIntegrationEnabled(cms, dataSource, entityMap);
378
+ const erp = cms.getPlugin("erp");
379
+ if (on && erp?.submission) {
380
+ const meta = order.metadata && typeof order.metadata === "object" && !Array.isArray(order.metadata) ? order.metadata : {};
381
+ const inv = meta.invoice && typeof meta.invoice === "object" && !Array.isArray(meta.invoice) ? meta.invoice : {};
382
+ let invoiceId = typeof inv.invoiceId === "string" ? inv.invoiceId.trim() : "";
383
+ if (!invoiceId) {
384
+ const refId = String(order.orderNumber || "");
385
+ try {
386
+ const r = await erp.submission.postErpReadAction("get-invoice", {
387
+ platformOrderId: refId
388
+ });
389
+ const d = r.ok ? unwrapErpReadData(r.json) : null;
390
+ invoiceId = d ? pickInvoiceId(d) || "" : "";
391
+ } catch {
392
+ invoiceId = "";
393
+ }
394
+ }
395
+ if (invoiceId) {
396
+ const pdf = await erp.submission.fetchInvoicePdf(invoiceId);
397
+ if (pdf.ok && pdf.buffer) {
398
+ return {
399
+ bytes: new Uint8Array(pdf.buffer),
400
+ filename: `order-invoice-${orderId}.pdf`,
401
+ contentType: pdf.contentType || "application/pdf",
402
+ source: "erp"
403
+ };
404
+ }
405
+ }
406
+ }
407
+ const local = await buildLocalInvoicePdfForOrder(dataSource, entityMap, orderId);
408
+ if ("error" in local) return {
409
+ error: local.error,
410
+ status: local.status
411
+ };
412
+ return {
413
+ bytes: local.bytes,
414
+ filename: local.filename.startsWith("invoice-") ? local.filename.replace(/^invoice-/, "order-invoice-") : local.filename,
415
+ contentType: "application/pdf",
416
+ source: "local"
417
+ };
418
+ } catch (err) {
419
+ const msg = err instanceof Error ? err.message : String(err);
420
+ console.error("[invoice] resolveOrderInvoicePdfBytes failed", {
421
+ orderId,
422
+ error: msg
423
+ });
424
+ return {
425
+ error: `Invoice failed: ${msg}`,
426
+ status: 500
427
+ };
428
+ }
429
+ }
430
+ __name(resolveOrderInvoicePdfBytes, "resolveOrderInvoicePdfBytes");
431
+ async function streamOrderInvoicePdf(cms, dataSource, entityMap, orderId, options) {
432
+ const resolved = await resolveOrderInvoicePdfBytes(cms, dataSource, entityMap, orderId, options);
433
+ if ("error" in resolved) return jsonErr(resolved.error, resolved.status);
434
+ return new Response(Buffer.from(resolved.bytes), {
435
+ status: 200,
436
+ headers: {
437
+ "Content-Type": resolved.contentType,
438
+ "Content-Disposition": `attachment; filename="${resolved.filename}"`,
439
+ "X-Invoice-Source": resolved.source
440
+ }
441
+ });
442
+ }
443
+ __name(streamOrderInvoicePdf, "streamOrderInvoicePdf");
444
+
445
+ export { ORDER_INVOICE_EMAIL_ELIGIBLE_STATUSES, buildLocalInvoicePdfForOrder, extractChildOrderRefsFromSalePayload, isOrderEligibleForInvoiceEmail, mapErpPayloadToFulfillment, mapErpPayloadToInvoiceNumber, resolveOrderInvoicePdfBytes, streamOrderInvoicePdf, unwrapErpReadData };