@infuro/cms-core 1.0.14 → 1.0.15

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/index.cjs CHANGED
@@ -38,6 +38,153 @@ var __decorateClass = (decorators, target, key, kind) => {
38
38
  return result;
39
39
  };
40
40
 
41
+ // src/plugins/erp/erp-queue.ts
42
+ async function queueErp(cms, payload) {
43
+ const queue = cms.getPlugin("queue");
44
+ if (!queue) return;
45
+ await queue.add(ERP_QUEUE_NAME, payload);
46
+ }
47
+ function registerErpQueueProcessor(cms) {
48
+ const queue = cms.getPlugin("queue");
49
+ if (!queue) return;
50
+ queue.registerProcessor(ERP_QUEUE_NAME, async (data) => {
51
+ const erp = cms.getPlugin("erp");
52
+ if (!erp) return;
53
+ const payload = data;
54
+ if (payload.kind === "lead") {
55
+ await erp.submission.submitContact(payload.contact);
56
+ } else if (payload.kind === "formOpportunity") {
57
+ await erp.submission.submitFormOpportunity(payload.contact);
58
+ } else if (payload.kind === "createContact") {
59
+ await erp.submission.submitCreateContact(payload.contact);
60
+ } else if (payload.kind === "order") {
61
+ await erp.submission.submitOrder(payload.order);
62
+ } else if (payload.kind === "productUpsert") {
63
+ await erp.submission.submitProductUpsert(payload.product);
64
+ }
65
+ });
66
+ }
67
+ var ERP_QUEUE_NAME;
68
+ var init_erp_queue = __esm({
69
+ "src/plugins/erp/erp-queue.ts"() {
70
+ "use strict";
71
+ ERP_QUEUE_NAME = "erp";
72
+ }
73
+ });
74
+
75
+ // src/plugins/erp/paid-order-erp.ts
76
+ var paid_order_erp_exports = {};
77
+ __export(paid_order_erp_exports, {
78
+ queueErpPaidOrderForOrderId: () => queueErpPaidOrderForOrderId
79
+ });
80
+ function roundMoney(major) {
81
+ return Math.round(major * 100) / 100;
82
+ }
83
+ function addressToWebhookDto(a) {
84
+ if (!a) return {};
85
+ return {
86
+ line1: a.line1 ?? "",
87
+ line2: a.line2 ?? "",
88
+ city: a.city ?? "",
89
+ state: a.state ?? "",
90
+ postalCode: a.postalCode ?? "",
91
+ country: a.country ?? ""
92
+ };
93
+ }
94
+ function orderStatusLabel(status) {
95
+ const s = (status || "").toLowerCase();
96
+ if (s === "confirmed") return "Confirmed";
97
+ if (s === "pending") return "Pending";
98
+ if (!status) return "Pending";
99
+ return status.charAt(0).toUpperCase() + status.slice(1);
100
+ }
101
+ function paymentRowToWebhookDto(p, amountMajorOverride) {
102
+ const currency = String(p.currency || "INR");
103
+ const amountMajor = amountMajorOverride != null && Number.isFinite(amountMajorOverride) ? amountMajorOverride : Number(p.amount);
104
+ const meta = { ...p.metadata || {} };
105
+ delete meta.amount;
106
+ delete meta.currency;
107
+ return {
108
+ id: String(p.externalReference || `payment_${p.id}`),
109
+ amount: roundMoney(amountMajor),
110
+ currency_code: currency,
111
+ captured_at: p.paidAt ? new Date(p.paidAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
112
+ provider_id: String(p.method || "unknown"),
113
+ data: { status: "captured", ...meta }
114
+ };
115
+ }
116
+ async function queueErpPaidOrderForOrderId(cms, dataSource, entityMap, orderId) {
117
+ try {
118
+ const configRepo = dataSource.getRepository(entityMap.configs);
119
+ const cfgRows = await configRepo.find({ where: { settings: "erp", deleted: false } });
120
+ for (const row of cfgRows) {
121
+ const r = row;
122
+ if (r.key === "enabled" && r.value === "false") return;
123
+ }
124
+ if (!cms.getPlugin("erp")) return;
125
+ const orderRepo = dataSource.getRepository(entityMap.orders);
126
+ const ord = await orderRepo.findOne({
127
+ where: { id: orderId },
128
+ relations: ["items", "items.product", "contact", "billingAddress", "shippingAddress", "payments"]
129
+ });
130
+ if (!ord) return;
131
+ const o = ord;
132
+ const okKind = o.orderKind === void 0 || o.orderKind === null || o.orderKind === "sale";
133
+ if (!okKind) return;
134
+ const rawPayments = o.payments ?? [];
135
+ const completedPayments = rawPayments.filter((pay) => pay.status === "completed" && pay.deleted !== true);
136
+ if (!completedPayments.length) return;
137
+ const rawItems = o.items ?? [];
138
+ const lines = rawItems.filter((it) => it.product).map((it) => {
139
+ const p = it.product;
140
+ const sku = p.sku || `SKU-${p.id}`;
141
+ const itemType = typeof it.productType === "string" && it.productType.trim() ? String(it.productType).trim() : p.type === "service" ? "service" : "product";
142
+ return {
143
+ sku,
144
+ quantity: Number(it.quantity) || 1,
145
+ unitPrice: Number(it.unitPrice),
146
+ title: p.name || sku,
147
+ discount: 0,
148
+ tax: Number(it.tax) || 0,
149
+ uom: (typeof it.uom === "string" && it.uom.trim() ? it.uom : p.uom) || void 0,
150
+ tax_code: typeof it.taxCode === "string" && it.taxCode.trim() ? String(it.taxCode).trim() : void 0,
151
+ hsn_number: (typeof it.hsn === "string" && it.hsn.trim() ? it.hsn : p.hsn) || void 0,
152
+ type: itemType
153
+ };
154
+ });
155
+ if (!lines.length) return;
156
+ const contact = o.contact;
157
+ const orderTotalMajor = Number(o.total);
158
+ const paymentDtos = completedPayments.length === 1 && Number.isFinite(orderTotalMajor) ? [paymentRowToWebhookDto(completedPayments[0], orderTotalMajor)] : completedPayments.map((pay) => paymentRowToWebhookDto(pay));
159
+ const baseMeta = o.metadata && typeof o.metadata === "object" && !Array.isArray(o.metadata) ? { ...o.metadata } : {};
160
+ const orderDto = {
161
+ platformType: "website",
162
+ platformOrderId: String(o.orderNumber),
163
+ platformOrderNumber: String(o.orderNumber),
164
+ order_date: o.createdAt ? new Date(o.createdAt).toISOString() : void 0,
165
+ status: orderStatusLabel(o.status),
166
+ customer: {
167
+ name: contact?.name || "",
168
+ email: contact?.email || "",
169
+ phone: contact?.phone || ""
170
+ },
171
+ shippingAddress: addressToWebhookDto(o.shippingAddress),
172
+ billingAddress: addressToWebhookDto(o.billingAddress),
173
+ items: lines,
174
+ payments: paymentDtos,
175
+ metadata: { ...baseMeta, source: "storefront" }
176
+ };
177
+ await queueErp(cms, { kind: "order", order: orderDto });
178
+ } catch {
179
+ }
180
+ }
181
+ var init_paid_order_erp = __esm({
182
+ "src/plugins/erp/paid-order-erp.ts"() {
183
+ "use strict";
184
+ init_erp_queue();
185
+ }
186
+ });
187
+
41
188
  // src/plugins/erp/erp-response-map.ts
42
189
  function pickString(o, keys) {
43
190
  for (const k of keys) {
@@ -114,6 +261,10 @@ var init_erp_response_map = __esm({
114
261
  });
115
262
 
116
263
  // src/plugins/erp/erp-config-enabled.ts
264
+ var erp_config_enabled_exports = {};
265
+ __export(erp_config_enabled_exports, {
266
+ isErpIntegrationEnabled: () => isErpIntegrationEnabled
267
+ });
117
268
  async function isErpIntegrationEnabled(cms, dataSource, entityMap) {
118
269
  if (!cms.getPlugin("erp")) return false;
119
270
  const configRepo = dataSource.getRepository(entityMap.configs);
@@ -228,14 +379,31 @@ async function queueEmail(cms, payload) {
228
379
  }
229
380
  }
230
381
  async function queueOrderPlacedEmails(cms, payload) {
231
- const { orderNumber, total, currency, customerName, customerEmail, salesTeamEmails, companyDetails, lineItems } = payload;
382
+ const {
383
+ orderNumber,
384
+ total,
385
+ subtotal,
386
+ tax,
387
+ currency,
388
+ customerName,
389
+ customerEmail,
390
+ salesTeamEmails,
391
+ companyDetails,
392
+ lineItems,
393
+ billingAddress,
394
+ shippingAddress
395
+ } = payload;
232
396
  const base = {
233
397
  orderNumber,
234
398
  total: total != null ? String(total) : void 0,
399
+ subtotal: subtotal != null ? String(subtotal) : void 0,
400
+ tax: tax != null ? String(tax) : void 0,
235
401
  currency,
236
402
  customerName,
237
403
  companyDetails: companyDetails ?? {},
238
- lineItems: lineItems ?? []
404
+ lineItems: lineItems ?? [],
405
+ billingAddress,
406
+ shippingAddress
239
407
  };
240
408
  const customerLower = customerEmail?.trim().toLowerCase() ?? "";
241
409
  const jobs = [];
@@ -881,149 +1049,12 @@ var ERPSubmissionService = class {
881
1049
  }
882
1050
  };
883
1051
 
884
- // src/plugins/erp/erp-queue.ts
885
- var ERP_QUEUE_NAME = "erp";
886
- async function queueErp(cms, payload) {
887
- const queue = cms.getPlugin("queue");
888
- if (!queue) return;
889
- await queue.add(ERP_QUEUE_NAME, payload);
890
- }
891
- function registerErpQueueProcessor(cms) {
892
- const queue = cms.getPlugin("queue");
893
- if (!queue) return;
894
- queue.registerProcessor(ERP_QUEUE_NAME, async (data) => {
895
- const erp = cms.getPlugin("erp");
896
- if (!erp) return;
897
- const payload = data;
898
- if (payload.kind === "lead") {
899
- await erp.submission.submitContact(payload.contact);
900
- } else if (payload.kind === "formOpportunity") {
901
- await erp.submission.submitFormOpportunity(payload.contact);
902
- } else if (payload.kind === "createContact") {
903
- await erp.submission.submitCreateContact(payload.contact);
904
- } else if (payload.kind === "order") {
905
- await erp.submission.submitOrder(payload.order);
906
- } else if (payload.kind === "productUpsert") {
907
- await erp.submission.submitProductUpsert(payload.product);
908
- }
909
- });
910
- }
911
-
912
- // src/plugins/erp/paid-order-erp.ts
913
- function amountToMinorUnits(major, currency) {
914
- const c = currency.toUpperCase();
915
- const zeroDecimal = /* @__PURE__ */ new Set([
916
- "BIF",
917
- "CLP",
918
- "DJF",
919
- "GNF",
920
- "JPY",
921
- "KMF",
922
- "KRW",
923
- "MGA",
924
- "PYG",
925
- "RWF",
926
- "UGX",
927
- "VND",
928
- "VUV",
929
- "XAF",
930
- "XOF",
931
- "XPF"
932
- ]);
933
- if (zeroDecimal.has(c)) return Math.round(major);
934
- return Math.round(major * 100);
935
- }
936
- function addressToWebhookDto(a) {
937
- if (!a) return {};
938
- return {
939
- line1: a.line1 ?? "",
940
- line2: a.line2 ?? "",
941
- city: a.city ?? "",
942
- state: a.state ?? "",
943
- postalCode: a.postalCode ?? "",
944
- country: a.country ?? ""
945
- };
946
- }
947
- function orderStatusLabel(status) {
948
- const s = (status || "").toLowerCase();
949
- if (s === "confirmed") return "Confirmed";
950
- if (s === "pending") return "Pending";
951
- if (!status) return "Pending";
952
- return status.charAt(0).toUpperCase() + status.slice(1);
953
- }
954
- function paymentRowToWebhookDto(p) {
955
- const currency = String(p.currency || "INR");
956
- const amountMajor = Number(p.amount);
957
- const meta = p.metadata || {};
958
- return {
959
- id: String(p.externalReference || `payment_${p.id}`),
960
- amount: amountToMinorUnits(amountMajor, currency),
961
- currency_code: currency,
962
- captured_at: p.paidAt ? new Date(p.paidAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
963
- provider_id: String(p.method || "unknown"),
964
- data: { status: "captured", ...meta }
965
- };
966
- }
967
- async function queueErpPaidOrderForOrderId(cms, dataSource, entityMap, orderId) {
968
- try {
969
- const configRepo = dataSource.getRepository(entityMap.configs);
970
- const cfgRows = await configRepo.find({ where: { settings: "erp", deleted: false } });
971
- for (const row of cfgRows) {
972
- const r = row;
973
- if (r.key === "enabled" && r.value === "false") return;
974
- }
975
- if (!cms.getPlugin("erp")) return;
976
- const orderRepo = dataSource.getRepository(entityMap.orders);
977
- const ord = await orderRepo.findOne({
978
- where: { id: orderId },
979
- relations: ["items", "items.product", "contact", "billingAddress", "shippingAddress", "payments"]
980
- });
981
- if (!ord) return;
982
- const o = ord;
983
- const okKind = o.orderKind === void 0 || o.orderKind === null || o.orderKind === "sale";
984
- if (!okKind) return;
985
- const rawPayments = o.payments ?? [];
986
- const completedPayments = rawPayments.filter((pay) => pay.status === "completed" && pay.deleted !== true);
987
- if (!completedPayments.length) return;
988
- const rawItems = o.items ?? [];
989
- const lines = rawItems.filter((it) => it.product).map((it) => {
990
- const p = it.product;
991
- const sku = p.sku || `SKU-${p.id}`;
992
- return {
993
- sku,
994
- quantity: Number(it.quantity) || 1,
995
- unitPrice: Number(it.unitPrice),
996
- title: p.name || sku,
997
- discount: 0,
998
- tax: Number(it.tax) || 0
999
- };
1000
- });
1001
- if (!lines.length) return;
1002
- const contact = o.contact;
1003
- const paymentDtos = completedPayments.map((pay) => paymentRowToWebhookDto(pay));
1004
- const baseMeta = o.metadata && typeof o.metadata === "object" && !Array.isArray(o.metadata) ? { ...o.metadata } : {};
1005
- const orderDto = {
1006
- platformType: "website",
1007
- platformOrderId: String(o.orderNumber),
1008
- platformOrderNumber: String(o.orderNumber),
1009
- status: orderStatusLabel(o.status),
1010
- customer: {
1011
- name: contact?.name || "",
1012
- email: contact?.email || "",
1013
- phone: contact?.phone || ""
1014
- },
1015
- shippingAddress: addressToWebhookDto(o.shippingAddress),
1016
- billingAddress: addressToWebhookDto(o.billingAddress),
1017
- items: lines,
1018
- payments: paymentDtos,
1019
- metadata: { ...baseMeta, source: "storefront" }
1020
- };
1021
- await queueErp(cms, { kind: "order", order: orderDto });
1022
- } catch {
1023
- }
1024
- }
1052
+ // src/plugins/erp/index.ts
1053
+ init_erp_queue();
1054
+ init_paid_order_erp();
1025
1055
 
1026
1056
  // src/plugins/erp/erp-contact-sync.ts
1057
+ init_erp_queue();
1027
1058
  function splitName(full) {
1028
1059
  const t = (full || "").trim();
1029
1060
  if (!t) return { firstName: "Contact", lastName: "" };
@@ -1267,6 +1298,7 @@ init_erp_order_invoice();
1267
1298
  init_erp_config_enabled();
1268
1299
 
1269
1300
  // src/plugins/erp/erp-product-sync.ts
1301
+ init_erp_queue();
1270
1302
  init_erp_config_enabled();
1271
1303
  async function queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, product) {
1272
1304
  try {
@@ -1274,14 +1306,21 @@ async function queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, produc
1274
1306
  if (!sku) return;
1275
1307
  const on = await isErpIntegrationEnabled(cms, dataSource, entityMap);
1276
1308
  if (!on) return;
1309
+ const rawMeta = product.metadata;
1310
+ let metadata;
1311
+ if (rawMeta && typeof rawMeta === "object" && !Array.isArray(rawMeta)) {
1312
+ const { description: _d, ...rest } = rawMeta;
1313
+ metadata = Object.keys(rest).length ? rest : void 0;
1314
+ }
1277
1315
  const payload = {
1278
1316
  sku,
1279
1317
  title: product.name || sku,
1280
1318
  name: product.name,
1281
- description: typeof product.metadata === "object" && product.metadata && "description" in product.metadata ? String(product.metadata.description ?? "") : void 0,
1282
1319
  hsn_number: product.hsn,
1320
+ uom: product.uom != null && String(product.uom).trim() ? String(product.uom).trim() : void 0,
1321
+ type: product.type === "service" ? "service" : "product",
1283
1322
  is_active: product.status === "available",
1284
- metadata: product.metadata ?? void 0
1323
+ metadata
1285
1324
  };
1286
1325
  await queueErp(cms, { kind: "productUpsert", product: payload });
1287
1326
  } catch {
@@ -1567,8 +1606,10 @@ function renderLineItemsHtml(items, currency) {
1567
1606
  const rows = items.map((it) => {
1568
1607
  const name = escapeHtml2(it.productName);
1569
1608
  const sku = it.sku && String(it.sku).trim() ? `<span style="font-size:12px;color:#888;"> (${escapeHtml2(String(it.sku).trim())})</span>` : "";
1609
+ const hsn = it.hsn && String(it.hsn).trim() ? `<br/><span style="font-size:11px;color:#888;">HSN: ${escapeHtml2(String(it.hsn).trim())}</span>` : "";
1610
+ const taxNote = it.tax != null && String(it.tax).trim() && Number(it.tax) !== 0 ? `<br/><span style="font-size:11px;color:#888;">Tax: ${escapeHtml2(formatMoney(it.tax, currency))}</span>` : "";
1570
1611
  return `<tr>
1571
- <td style="padding:10px 8px 10px 0;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;">${name}${sku}</td>
1612
+ <td style="padding:10px 8px 10px 0;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;">${name}${sku}${hsn}${taxNote}</td>
1572
1613
  <td align="right" style="padding:10px 8px;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;white-space:nowrap;">${escapeHtml2(String(it.quantity))}</td>
1573
1614
  <td align="right" style="padding:10px 8px;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;white-space:nowrap;">${escapeHtml2(formatMoney(it.unitPrice, currency))}</td>
1574
1615
  <td align="right" style="padding:10px 0 10px 8px;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;white-space:nowrap;">${escapeHtml2(formatMoney(it.lineTotal, currency))}</td>
@@ -1587,24 +1628,64 @@ ${rows}
1587
1628
  }
1588
1629
  function renderLineItemsText(items, currency) {
1589
1630
  if (!items.length) return "";
1590
- const lines = items.map(
1591
- (it) => `- ${it.productName} \xD7 ${it.quantity} @ ${formatMoney(it.unitPrice, currency)} = ${formatMoney(it.lineTotal, currency)}${it.sku ? ` [${it.sku}]` : ""}`
1592
- );
1631
+ const lines = items.map((it) => {
1632
+ let s = `- ${it.productName} \xD7 ${it.quantity} @ ${formatMoney(it.unitPrice, currency)} = ${formatMoney(it.lineTotal, currency)}`;
1633
+ if (it.sku) s += ` [${it.sku}]`;
1634
+ if (it.hsn && String(it.hsn).trim()) s += ` HSN:${it.hsn}`;
1635
+ if (it.tax != null && Number(it.tax) !== 0) s += ` tax:${formatMoney(it.tax, currency)}`;
1636
+ return s;
1637
+ });
1593
1638
  return ["Items:", ...lines].join("\n");
1594
1639
  }
1640
+ function formatAddressLines(addr) {
1641
+ if (!addr || typeof addr !== "object") return [];
1642
+ const parts = [addr.line1, addr.line2, [addr.city, addr.state].filter(Boolean).join(", "), addr.postalCode, addr.country].filter(
1643
+ (x) => x != null && String(x).trim() !== ""
1644
+ );
1645
+ return parts.map((p) => String(p).trim()).filter(Boolean);
1646
+ }
1647
+ function renderAddressesHtml(billing, shipping) {
1648
+ const bLines = formatAddressLines(billing);
1649
+ const sLines = formatAddressLines(shipping);
1650
+ if (!bLines.length && !sLines.length) return "";
1651
+ let html = '<p style="margin:16px 0 8px 0;font-size:14px;font-weight:600;color:#111;">Addresses</p>';
1652
+ if (bLines.length) {
1653
+ html += `<p style="margin:0 0 4px 0;font-size:12px;font-weight:600;color:#555;">Billing</p><p style="margin:0 0 12px 0;font-size:14px;line-height:1.5;color:#333;">${bLines.map((l) => escapeHtml2(l)).join("<br/>")}</p>`;
1654
+ }
1655
+ if (sLines.length) {
1656
+ html += `<p style="margin:0 0 4px 0;font-size:12px;font-weight:600;color:#555;">Shipping</p><p style="margin:0 0 0 0;font-size:14px;line-height:1.5;color:#333;">${sLines.map((l) => escapeHtml2(l)).join("<br/>")}</p>`;
1657
+ }
1658
+ return html;
1659
+ }
1660
+ function renderAddressesText(billing, shipping) {
1661
+ const bLines = formatAddressLines(billing);
1662
+ const sLines = formatAddressLines(shipping);
1663
+ const out = [];
1664
+ if (bLines.length) out.push("Billing:", ...bLines.map((l) => ` ${l}`));
1665
+ if (sLines.length) out.push("Shipping:", ...sLines.map((l) => ` ${l}`));
1666
+ return out.length ? out.join("\n") : "";
1667
+ }
1595
1668
  function render4(ctx) {
1596
1669
  const {
1597
1670
  orderNumber,
1598
1671
  total,
1672
+ subtotal,
1673
+ tax,
1599
1674
  currency,
1600
1675
  customerName,
1601
1676
  companyDetails,
1602
1677
  audience = "customer",
1603
1678
  internalCustomerEmail,
1604
- lineItems = []
1679
+ lineItems = [],
1680
+ billingAddress,
1681
+ shippingAddress
1605
1682
  } = ctx;
1606
1683
  const itemsHtml = renderLineItemsHtml(lineItems, currency);
1607
1684
  const itemsText = renderLineItemsText(lineItems, currency);
1685
+ const addrHtml = renderAddressesHtml(billingAddress, shippingAddress);
1686
+ const addrText = renderAddressesText(billingAddress, shippingAddress);
1687
+ const subtotalLine = subtotal != null && String(subtotal).trim() !== "" ? `<p style="margin:8px 0 0 0;font-size:14px;line-height:1.5;color:#333;"><strong>Subtotal:</strong> ${escapeHtml2(String(subtotal))}${currency ? ` ${escapeHtml2(currency)}` : ""}</p>` : "";
1688
+ const taxLine = tax != null && String(tax).trim() !== "" && Number(tax) !== 0 ? `<p style="margin:4px 0 0 0;font-size:14px;line-height:1.5;color:#333;"><strong>Tax:</strong> ${escapeHtml2(String(tax))}${currency ? ` ${escapeHtml2(currency)}` : ""}</p>` : "";
1608
1689
  const totalLine = total != null && String(total).trim() !== "" ? `<p style="margin:12px 0 0 0;font-size:15px;line-height:1.5;color:#333;"><strong>Order total:</strong> ${escapeHtml2(String(total))}${currency ? ` ${escapeHtml2(currency)}` : ""}</p>` : "";
1609
1690
  let subject;
1610
1691
  let bodyHtml;
@@ -1615,13 +1696,17 @@ function render4(ctx) {
1615
1696
  bodyHtml = `<p style="margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;">A new order has been placed and payment completed.</p>
1616
1697
  <p style="margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;"><strong>Order number:</strong> ${escapeHtml2(orderNumber)}</p>
1617
1698
  ${who}
1699
+ ${addrHtml}
1618
1700
  ${itemsHtml}
1619
- ${totalLine}`;
1701
+ ${subtotalLine}${taxLine}${totalLine}`;
1620
1702
  text = [
1621
1703
  `New order #${orderNumber}`,
1622
1704
  customerName ? `Customer: ${customerName}` : "",
1623
1705
  internalCustomerEmail ? `Email: ${internalCustomerEmail}` : "",
1706
+ addrText,
1624
1707
  itemsText,
1708
+ subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ""}` : "",
1709
+ tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ""}` : "",
1625
1710
  total != null ? `Order total: ${total}${currency ? ` ${currency}` : ""}` : ""
1626
1711
  ].filter(Boolean).join("\n\n");
1627
1712
  } else {
@@ -1630,14 +1715,18 @@ ${totalLine}`;
1630
1715
  const thanksHtml = `${escapeHtml2(thanksPlain)} We\u2019ve received your order and will process it shortly.`;
1631
1716
  bodyHtml = `<p style="margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;">${thanksHtml}</p>
1632
1717
  <p style="margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;"><strong>Order number:</strong> ${escapeHtml2(orderNumber)}</p>
1718
+ ${addrHtml}
1633
1719
  ${itemsHtml}
1634
- ${totalLine}
1720
+ ${subtotalLine}${taxLine}${totalLine}
1635
1721
  <p style="margin:16px 0 0 0;font-size:13px;line-height:1.5;color:#666;">If you have questions, reply to this email or contact us using the details below.</p>`;
1636
1722
  text = [
1637
1723
  `Order confirmed #${orderNumber}`,
1638
1724
  `${thanksPlain} We\u2019ve received your order and will process it shortly.`,
1639
1725
  "",
1726
+ addrText,
1640
1727
  itemsText,
1728
+ subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ""}` : "",
1729
+ tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ""}` : "",
1641
1730
  total != null ? `Order total: ${total}${currency ? ` ${currency}` : ""}` : "",
1642
1731
  "",
1643
1732
  "We will process your order shortly."
@@ -5026,6 +5115,8 @@ var Product = class {
5026
5115
  categoryId;
5027
5116
  sku;
5028
5117
  hsn;
5118
+ uom;
5119
+ type;
5029
5120
  slug;
5030
5121
  name;
5031
5122
  price;
@@ -5067,6 +5158,12 @@ __decorateClass([
5067
5158
  __decorateClass([
5068
5159
  (0, import_typeorm29.Column)("varchar", { nullable: true })
5069
5160
  ], Product.prototype, "hsn", 2);
5161
+ __decorateClass([
5162
+ (0, import_typeorm29.Column)("varchar", { nullable: true })
5163
+ ], Product.prototype, "uom", 2);
5164
+ __decorateClass([
5165
+ (0, import_typeorm29.Column)("varchar", { default: "product" })
5166
+ ], Product.prototype, "type", 2);
5070
5167
  __decorateClass([
5071
5168
  (0, import_typeorm29.Column)("varchar", { unique: true, nullable: true })
5072
5169
  ], Product.prototype, "slug", 2);
@@ -5375,6 +5472,11 @@ var OrderItem = class {
5375
5472
  unitPrice;
5376
5473
  tax;
5377
5474
  total;
5475
+ hsn;
5476
+ uom;
5477
+ productType;
5478
+ taxRate;
5479
+ taxCode;
5378
5480
  metadata;
5379
5481
  createdAt;
5380
5482
  updatedAt;
@@ -5402,6 +5504,21 @@ __decorateClass([
5402
5504
  __decorateClass([
5403
5505
  (0, import_typeorm34.Column)("decimal", { precision: 12, scale: 2 })
5404
5506
  ], OrderItem.prototype, "total", 2);
5507
+ __decorateClass([
5508
+ (0, import_typeorm34.Column)("varchar", { nullable: true })
5509
+ ], OrderItem.prototype, "hsn", 2);
5510
+ __decorateClass([
5511
+ (0, import_typeorm34.Column)("varchar", { nullable: true })
5512
+ ], OrderItem.prototype, "uom", 2);
5513
+ __decorateClass([
5514
+ (0, import_typeorm34.Column)("varchar", { nullable: true })
5515
+ ], OrderItem.prototype, "productType", 2);
5516
+ __decorateClass([
5517
+ (0, import_typeorm34.Column)("decimal", { precision: 5, scale: 2, nullable: true })
5518
+ ], OrderItem.prototype, "taxRate", 2);
5519
+ __decorateClass([
5520
+ (0, import_typeorm34.Column)("varchar", { nullable: true })
5521
+ ], OrderItem.prototype, "taxCode", 2);
5405
5522
  __decorateClass([
5406
5523
  (0, import_typeorm34.Column)("jsonb", { nullable: true })
5407
5524
  ], OrderItem.prototype, "metadata", 2);
@@ -6298,6 +6415,24 @@ function createCrudHandler(dataSource, entityMap, options) {
6298
6415
  } else if (search) {
6299
6416
  where = buildSearchWhereClause(repo, search);
6300
6417
  }
6418
+ const intFilterKeys = ["productId", "attributeId", "taxId"];
6419
+ const extraWhere = {};
6420
+ for (const key of intFilterKeys) {
6421
+ const v = searchParams.get(key);
6422
+ if (v != null && v !== "" && columnNames.has(key)) {
6423
+ const n = Number(v);
6424
+ if (Number.isFinite(n)) extraWhere[key] = n;
6425
+ }
6426
+ }
6427
+ if (Object.keys(extraWhere).length > 0) {
6428
+ if (Array.isArray(where)) {
6429
+ where = where.map((w) => ({ ...w, ...extraWhere }));
6430
+ } else if (where && typeof where === "object" && Object.keys(where).length > 0) {
6431
+ where = { ...where, ...extraWhere };
6432
+ } else {
6433
+ where = extraWhere;
6434
+ }
6435
+ }
6301
6436
  const [data, total] = await repo.findAndCount({
6302
6437
  skip,
6303
6438
  take: limit,
@@ -6755,6 +6890,7 @@ function createUserAuthApiRouter(config) {
6755
6890
  // src/api/cms-handlers.ts
6756
6891
  var import_typeorm42 = require("typeorm");
6757
6892
  init_email_queue();
6893
+ init_erp_queue();
6758
6894
  function createDashboardStatsHandler(config) {
6759
6895
  const { dataSource, entityMap, json, requireAuth, requirePermission, requireEntityPermission } = config;
6760
6896
  return async function GET(req) {
@@ -8156,6 +8292,29 @@ function createCmsApiHandler(config) {
8156
8292
  if (!Number.isFinite(oid)) return config.json({ error: "Invalid id" }, { status: 400 });
8157
8293
  return streamOrderInvoicePdf2(cms, dataSource, entityMap, oid, {});
8158
8294
  }
8295
+ if (path[0] === "orders" && path.length === 3 && path[2] === "repost-erp" && getCms) {
8296
+ const a = await config.requireAuth(req);
8297
+ if (a) return a;
8298
+ if (perm) {
8299
+ const pe = await perm(req, "orders", method === "GET" ? "read" : "update");
8300
+ if (pe) return pe;
8301
+ }
8302
+ const oid = Number(path[1]);
8303
+ if (!Number.isFinite(oid)) return config.json({ error: "Invalid id" }, { status: 400 });
8304
+ const cms = await getCms();
8305
+ const { isErpIntegrationEnabled: isErpIntegrationEnabled3 } = await Promise.resolve().then(() => (init_erp_config_enabled(), erp_config_enabled_exports));
8306
+ const enabled = await isErpIntegrationEnabled3(cms, dataSource, entityMap);
8307
+ if (method === "GET") {
8308
+ return config.json({ enabled });
8309
+ }
8310
+ if (method === "POST") {
8311
+ if (!enabled) return config.json({ error: "ERP integration is disabled" }, { status: 409 });
8312
+ const { queueErpPaidOrderForOrderId: queueErpPaidOrderForOrderId2 } = await Promise.resolve().then(() => (init_paid_order_erp(), paid_order_erp_exports));
8313
+ await queueErpPaidOrderForOrderId2(cms, dataSource, entityMap, oid);
8314
+ return config.json({ ok: true });
8315
+ }
8316
+ return config.json({ error: "Method not allowed" }, { status: 405 });
8317
+ }
8159
8318
  if (path.length === 0) return config.json({ error: "Not found" }, { status: 404 });
8160
8319
  const resource = resolveResource(path[0]);
8161
8320
  if (!crudResources.includes(resource)) return config.json({ error: "Invalid resource" }, { status: 400 });
@@ -8252,6 +8411,152 @@ function createStorefrontApiHandler(config) {
8252
8411
  const tokenRepo = () => dataSource.getRepository(entityMap.password_reset_tokens);
8253
8412
  const collectionRepo = () => dataSource.getRepository(entityMap.collections);
8254
8413
  const groupRepo = () => dataSource.getRepository(entityMap.user_groups);
8414
+ const configRepo = () => dataSource.getRepository(entityMap.configs);
8415
+ const CART_CHECKOUT_RELATIONS = ["items", "items.product", "items.product.taxes", "items.product.taxes.tax"];
8416
+ function roundMoney2(n) {
8417
+ return Math.round(n * 100) / 100;
8418
+ }
8419
+ async function getStoreDefaultTaxRate() {
8420
+ const rows = await configRepo().find({ where: { settings: "store", deleted: false } });
8421
+ for (const row of rows) {
8422
+ const r = row;
8423
+ if (r.key === "defaultTaxRate") {
8424
+ const n = parseFloat(String(r.value ?? "").trim());
8425
+ return Number.isFinite(n) && n >= 0 ? n : null;
8426
+ }
8427
+ }
8428
+ return null;
8429
+ }
8430
+ function computeTaxForProductLine(p, lineSubtotal, defaultRate) {
8431
+ const pts = p.taxes ?? [];
8432
+ const activePts = pts.filter((pt) => {
8433
+ const t = pt.tax;
8434
+ return t != null && t.active !== false;
8435
+ });
8436
+ if (activePts.length) {
8437
+ let sumRate = 0;
8438
+ const slugs = [];
8439
+ for (const pt of activePts) {
8440
+ const t = pt.tax;
8441
+ const r = Number(pt.rate != null && pt.rate !== "" ? pt.rate : t.rate ?? 0);
8442
+ if (Number.isFinite(r)) sumRate += r;
8443
+ const slug = String(t.slug ?? "").trim();
8444
+ if (slug) slugs.push(slug);
8445
+ }
8446
+ const tax = roundMoney2(lineSubtotal * sumRate / 100);
8447
+ return {
8448
+ tax,
8449
+ taxRate: sumRate > 0 ? roundMoney2(sumRate) : null,
8450
+ taxCode: slugs.length ? [...new Set(slugs)].sort().join(",") : null
8451
+ };
8452
+ }
8453
+ if (defaultRate != null && defaultRate > 0) {
8454
+ return {
8455
+ tax: roundMoney2(lineSubtotal * defaultRate / 100),
8456
+ taxRate: roundMoney2(defaultRate),
8457
+ taxCode: null
8458
+ };
8459
+ }
8460
+ return { tax: 0, taxRate: null, taxCode: null };
8461
+ }
8462
+ function parseInlineAddress(raw) {
8463
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
8464
+ const o = raw;
8465
+ const line1 = String(o.line1 ?? "").trim();
8466
+ if (!line1) return null;
8467
+ return {
8468
+ line1,
8469
+ line2: o.line2 != null ? String(o.line2) : "",
8470
+ city: o.city != null ? String(o.city) : "",
8471
+ state: o.state != null ? String(o.state) : "",
8472
+ postalCode: o.postalCode != null ? String(o.postalCode) : "",
8473
+ country: o.country != null ? String(o.country) : ""
8474
+ };
8475
+ }
8476
+ function intFromBody(v) {
8477
+ if (typeof v === "number" && Number.isInteger(v)) return v;
8478
+ if (typeof v === "string" && /^\d+$/.test(v)) return parseInt(v, 10);
8479
+ return void 0;
8480
+ }
8481
+ async function resolveCheckoutAddress(contactId, idVal, inlineVal) {
8482
+ const aid = intFromBody(idVal);
8483
+ if (aid != null) {
8484
+ const existing = await addressRepo().findOne({
8485
+ where: { id: aid, contactId }
8486
+ });
8487
+ if (!existing) return { id: null, error: "Address not found" };
8488
+ return { id: aid };
8489
+ }
8490
+ const addr = parseInlineAddress(inlineVal);
8491
+ if (addr) {
8492
+ const saved = await addressRepo().save(
8493
+ addressRepo().create({
8494
+ contactId,
8495
+ line1: addr.line1,
8496
+ line2: addr.line2?.trim() ? addr.line2 : null,
8497
+ city: addr.city?.trim() ? addr.city : null,
8498
+ state: addr.state?.trim() ? addr.state : null,
8499
+ postalCode: addr.postalCode?.trim() ? addr.postalCode : null,
8500
+ country: addr.country?.trim() ? addr.country : null
8501
+ })
8502
+ );
8503
+ return { id: saved.id };
8504
+ }
8505
+ return { id: null };
8506
+ }
8507
+ async function prepareCheckoutFromCart(b, cart, contactId) {
8508
+ const defaultRate = await getStoreDefaultTaxRate();
8509
+ const lines = [];
8510
+ let subtotal = 0;
8511
+ let orderTax = 0;
8512
+ let needsShipping = false;
8513
+ for (const it of cart.items || []) {
8514
+ const p = it.product;
8515
+ if (!p || p.deleted || p.status !== "available") continue;
8516
+ const unit = Number(p.price);
8517
+ const qty = it.quantity || 1;
8518
+ const lineSubtotal = unit * qty;
8519
+ const pType = p.type === "service" ? "service" : "product";
8520
+ if (pType === "product") needsShipping = true;
8521
+ const { tax, taxRate, taxCode } = computeTaxForProductLine(p, lineSubtotal, defaultRate);
8522
+ const lineTotal = roundMoney2(lineSubtotal + tax);
8523
+ subtotal = roundMoney2(subtotal + lineSubtotal);
8524
+ orderTax = roundMoney2(orderTax + tax);
8525
+ lines.push({
8526
+ productId: p.id,
8527
+ quantity: qty,
8528
+ unitPrice: unit,
8529
+ tax,
8530
+ total: lineTotal,
8531
+ hsn: p.hsn ?? null,
8532
+ uom: p.uom ?? null,
8533
+ productType: pType,
8534
+ taxRate,
8535
+ taxCode
8536
+ });
8537
+ }
8538
+ if (!lines.length) return { ok: false, status: 400, message: "No available items in cart" };
8539
+ const bill = await resolveCheckoutAddress(contactId, b.billingAddressId, b.billingAddress);
8540
+ if (bill.error) return { ok: false, status: 400, message: bill.error };
8541
+ if (bill.id == null) return { ok: false, status: 400, message: "Billing address required" };
8542
+ const ship = await resolveCheckoutAddress(contactId, b.shippingAddressId, b.shippingAddress);
8543
+ if (ship.error) return { ok: false, status: 400, message: ship.error };
8544
+ let shippingAddressId = ship.id;
8545
+ if (needsShipping && shippingAddressId == null) shippingAddressId = bill.id;
8546
+ if (needsShipping && shippingAddressId == null) {
8547
+ return { ok: false, status: 400, message: "Shipping address required" };
8548
+ }
8549
+ const orderTotal = roundMoney2(subtotal + orderTax);
8550
+ return {
8551
+ ok: true,
8552
+ lines,
8553
+ subtotal,
8554
+ orderTax,
8555
+ orderTotal,
8556
+ billingAddressId: bill.id,
8557
+ shippingAddressId
8558
+ };
8559
+ }
8255
8560
  async function syncContactToErp(contact) {
8256
8561
  if (!getCms) return;
8257
8562
  try {
@@ -8377,6 +8682,7 @@ function createStorefrontApiHandler(config) {
8377
8682
  slug: p.slug,
8378
8683
  price: p.price,
8379
8684
  sku: p.sku,
8685
+ type: p.type === "service" ? "service" : "product",
8380
8686
  image: primaryProductImageUrl(p.metadata)
8381
8687
  } : null
8382
8688
  };
@@ -8404,6 +8710,8 @@ function createStorefrontApiHandler(config) {
8404
8710
  slug: p.slug,
8405
8711
  sku: p.sku,
8406
8712
  hsn: p.hsn,
8713
+ uom: p.uom ?? null,
8714
+ type: p.type === "service" ? "service" : "product",
8407
8715
  price: p.price,
8408
8716
  compareAtPrice: p.compareAtPrice,
8409
8717
  status: p.status,
@@ -9105,7 +9413,7 @@ function createStorefrontApiHandler(config) {
9105
9413
  contactId = contact.id;
9106
9414
  cart = await cartRepo().findOne({
9107
9415
  where: { contactId },
9108
- relations: ["items", "items.product"]
9416
+ relations: [...CART_CHECKOUT_RELATIONS]
9109
9417
  });
9110
9418
  } else {
9111
9419
  const email = String(b.email ?? "").trim();
@@ -9138,25 +9446,14 @@ function createStorefrontApiHandler(config) {
9138
9446
  if (!guestToken) return json({ error: "Cart not found" }, { status: 400 });
9139
9447
  cart = await cartRepo().findOne({
9140
9448
  where: { guestToken },
9141
- relations: ["items", "items.product"]
9449
+ relations: [...CART_CHECKOUT_RELATIONS]
9142
9450
  });
9143
9451
  }
9144
9452
  if (!cart || !(cart.items || []).length) {
9145
9453
  return json({ error: "Cart is empty" }, { status: 400 });
9146
9454
  }
9147
- let subtotal = 0;
9148
- const lines = [];
9149
- for (const it of cart.items || []) {
9150
- const p = it.product;
9151
- if (!p || p.deleted || p.status !== "available") continue;
9152
- const unit = Number(p.price);
9153
- const qty = it.quantity || 1;
9154
- const lineTotal = unit * qty;
9155
- subtotal += lineTotal;
9156
- lines.push({ productId: p.id, quantity: qty, unitPrice: unit, tax: 0, total: lineTotal });
9157
- }
9158
- if (!lines.length) return json({ error: "No available items in cart" }, { status: 400 });
9159
- const total = subtotal;
9455
+ const prepOrd = await prepareCheckoutFromCart(b, cart, contactId);
9456
+ if (!prepOrd.ok) return json({ error: prepOrd.message }, { status: prepOrd.status });
9160
9457
  const cartId = cart.id;
9161
9458
  const ord = await orderRepo().save(
9162
9459
  orderRepo().create({
@@ -9164,13 +9461,13 @@ function createStorefrontApiHandler(config) {
9164
9461
  orderKind: "sale",
9165
9462
  parentOrderId: null,
9166
9463
  contactId,
9167
- billingAddressId: typeof b.billingAddressId === "number" ? b.billingAddressId : null,
9168
- shippingAddressId: typeof b.shippingAddressId === "number" ? b.shippingAddressId : null,
9464
+ billingAddressId: prepOrd.billingAddressId,
9465
+ shippingAddressId: prepOrd.shippingAddressId,
9169
9466
  status: "pending",
9170
- subtotal,
9171
- tax: 0,
9467
+ subtotal: prepOrd.subtotal,
9468
+ tax: prepOrd.orderTax,
9172
9469
  discount: 0,
9173
- total,
9470
+ total: prepOrd.orderTotal,
9174
9471
  currency: cart.currency || "INR",
9175
9472
  metadata: { cartId }
9176
9473
  })
@@ -9179,7 +9476,7 @@ function createStorefrontApiHandler(config) {
9179
9476
  await orderRepo().update(oid, {
9180
9477
  orderNumber: buildCanonicalOrderNumber("sale", oid, ord.createdAt ?? /* @__PURE__ */ new Date())
9181
9478
  });
9182
- for (const line of lines) {
9479
+ for (const line of prepOrd.lines) {
9183
9480
  await orderItemRepo().save(
9184
9481
  orderItemRepo().create({
9185
9482
  orderId: oid,
@@ -9187,14 +9484,21 @@ function createStorefrontApiHandler(config) {
9187
9484
  quantity: line.quantity,
9188
9485
  unitPrice: line.unitPrice,
9189
9486
  tax: line.tax,
9190
- total: line.total
9487
+ total: line.total,
9488
+ hsn: line.hsn,
9489
+ uom: line.uom,
9490
+ productType: line.productType,
9491
+ taxRate: line.taxRate,
9492
+ taxCode: line.taxCode
9191
9493
  })
9192
9494
  );
9193
9495
  }
9194
9496
  return json({
9195
9497
  orderId: oid,
9196
9498
  orderNumber: ord.orderNumber,
9197
- total,
9499
+ subtotal: prepOrd.subtotal,
9500
+ tax: prepOrd.orderTax,
9501
+ total: prepOrd.orderTotal,
9198
9502
  currency: cart.currency || "INR"
9199
9503
  });
9200
9504
  }
@@ -9212,7 +9516,7 @@ function createStorefrontApiHandler(config) {
9212
9516
  contactId = contact.id;
9213
9517
  cart = await cartRepo().findOne({
9214
9518
  where: { contactId },
9215
- relations: ["items", "items.product"]
9519
+ relations: [...CART_CHECKOUT_RELATIONS]
9216
9520
  });
9217
9521
  } else {
9218
9522
  const email = String(b.email ?? "").trim();
@@ -9245,38 +9549,27 @@ function createStorefrontApiHandler(config) {
9245
9549
  if (!guestToken) return json({ error: "Cart not found" }, { status: 400 });
9246
9550
  cart = await cartRepo().findOne({
9247
9551
  where: { guestToken },
9248
- relations: ["items", "items.product"]
9552
+ relations: [...CART_CHECKOUT_RELATIONS]
9249
9553
  });
9250
9554
  }
9251
9555
  if (!cart || !(cart.items || []).length) {
9252
9556
  return json({ error: "Cart is empty" }, { status: 400 });
9253
9557
  }
9254
- let subtotal = 0;
9255
- const lines = [];
9256
- for (const it of cart.items || []) {
9257
- const p = it.product;
9258
- if (!p || p.deleted || p.status !== "available") continue;
9259
- const unit = Number(p.price);
9260
- const qty = it.quantity || 1;
9261
- const lineTotal = unit * qty;
9262
- subtotal += lineTotal;
9263
- lines.push({ productId: p.id, quantity: qty, unitPrice: unit, tax: 0, total: lineTotal });
9264
- }
9265
- if (!lines.length) return json({ error: "No available items in cart" }, { status: 400 });
9266
- const total = subtotal;
9558
+ const prepChk = await prepareCheckoutFromCart(b, cart, contactId);
9559
+ if (!prepChk.ok) return json({ error: prepChk.message }, { status: prepChk.status });
9267
9560
  const ord = await orderRepo().save(
9268
9561
  orderRepo().create({
9269
9562
  orderNumber: temporaryOrderNumberPlaceholder(),
9270
9563
  orderKind: "sale",
9271
9564
  parentOrderId: null,
9272
9565
  contactId,
9273
- billingAddressId: typeof b.billingAddressId === "number" ? b.billingAddressId : null,
9274
- shippingAddressId: typeof b.shippingAddressId === "number" ? b.shippingAddressId : null,
9566
+ billingAddressId: prepChk.billingAddressId,
9567
+ shippingAddressId: prepChk.shippingAddressId,
9275
9568
  status: "pending",
9276
- subtotal,
9277
- tax: 0,
9569
+ subtotal: prepChk.subtotal,
9570
+ tax: prepChk.orderTax,
9278
9571
  discount: 0,
9279
- total,
9572
+ total: prepChk.orderTotal,
9280
9573
  currency: cart.currency || "INR"
9281
9574
  })
9282
9575
  );
@@ -9284,7 +9577,7 @@ function createStorefrontApiHandler(config) {
9284
9577
  await orderRepo().update(oid, {
9285
9578
  orderNumber: buildCanonicalOrderNumber("sale", oid, ord.createdAt ?? /* @__PURE__ */ new Date())
9286
9579
  });
9287
- for (const line of lines) {
9580
+ for (const line of prepChk.lines) {
9288
9581
  await orderItemRepo().save(
9289
9582
  orderItemRepo().create({
9290
9583
  orderId: oid,
@@ -9292,7 +9585,12 @@ function createStorefrontApiHandler(config) {
9292
9585
  quantity: line.quantity,
9293
9586
  unitPrice: line.unitPrice,
9294
9587
  tax: line.tax,
9295
- total: line.total
9588
+ total: line.total,
9589
+ hsn: line.hsn,
9590
+ uom: line.uom,
9591
+ productType: line.productType,
9592
+ taxRate: line.taxRate,
9593
+ taxCode: line.taxCode
9296
9594
  })
9297
9595
  );
9298
9596
  }
@@ -9301,7 +9599,9 @@ function createStorefrontApiHandler(config) {
9301
9599
  return json({
9302
9600
  orderId: oid,
9303
9601
  orderNumber: ord.orderNumber,
9304
- total
9602
+ subtotal: prepChk.subtotal,
9603
+ tax: prepChk.orderTax,
9604
+ total: prepChk.orderTotal
9305
9605
  });
9306
9606
  }
9307
9607
  if (path[0] === "orders" && path.length === 1 && method === "GET") {