@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.js CHANGED
@@ -17,6 +17,153 @@ var __decorateClass = (decorators, target, key, kind) => {
17
17
  return result;
18
18
  };
19
19
 
20
+ // src/plugins/erp/erp-queue.ts
21
+ async function queueErp(cms, payload) {
22
+ const queue = cms.getPlugin("queue");
23
+ if (!queue) return;
24
+ await queue.add(ERP_QUEUE_NAME, payload);
25
+ }
26
+ function registerErpQueueProcessor(cms) {
27
+ const queue = cms.getPlugin("queue");
28
+ if (!queue) return;
29
+ queue.registerProcessor(ERP_QUEUE_NAME, async (data) => {
30
+ const erp = cms.getPlugin("erp");
31
+ if (!erp) return;
32
+ const payload = data;
33
+ if (payload.kind === "lead") {
34
+ await erp.submission.submitContact(payload.contact);
35
+ } else if (payload.kind === "formOpportunity") {
36
+ await erp.submission.submitFormOpportunity(payload.contact);
37
+ } else if (payload.kind === "createContact") {
38
+ await erp.submission.submitCreateContact(payload.contact);
39
+ } else if (payload.kind === "order") {
40
+ await erp.submission.submitOrder(payload.order);
41
+ } else if (payload.kind === "productUpsert") {
42
+ await erp.submission.submitProductUpsert(payload.product);
43
+ }
44
+ });
45
+ }
46
+ var ERP_QUEUE_NAME;
47
+ var init_erp_queue = __esm({
48
+ "src/plugins/erp/erp-queue.ts"() {
49
+ "use strict";
50
+ ERP_QUEUE_NAME = "erp";
51
+ }
52
+ });
53
+
54
+ // src/plugins/erp/paid-order-erp.ts
55
+ var paid_order_erp_exports = {};
56
+ __export(paid_order_erp_exports, {
57
+ queueErpPaidOrderForOrderId: () => queueErpPaidOrderForOrderId
58
+ });
59
+ function roundMoney(major) {
60
+ return Math.round(major * 100) / 100;
61
+ }
62
+ function addressToWebhookDto(a) {
63
+ if (!a) return {};
64
+ return {
65
+ line1: a.line1 ?? "",
66
+ line2: a.line2 ?? "",
67
+ city: a.city ?? "",
68
+ state: a.state ?? "",
69
+ postalCode: a.postalCode ?? "",
70
+ country: a.country ?? ""
71
+ };
72
+ }
73
+ function orderStatusLabel(status) {
74
+ const s = (status || "").toLowerCase();
75
+ if (s === "confirmed") return "Confirmed";
76
+ if (s === "pending") return "Pending";
77
+ if (!status) return "Pending";
78
+ return status.charAt(0).toUpperCase() + status.slice(1);
79
+ }
80
+ function paymentRowToWebhookDto(p, amountMajorOverride) {
81
+ const currency = String(p.currency || "INR");
82
+ const amountMajor = amountMajorOverride != null && Number.isFinite(amountMajorOverride) ? amountMajorOverride : Number(p.amount);
83
+ const meta = { ...p.metadata || {} };
84
+ delete meta.amount;
85
+ delete meta.currency;
86
+ return {
87
+ id: String(p.externalReference || `payment_${p.id}`),
88
+ amount: roundMoney(amountMajor),
89
+ currency_code: currency,
90
+ captured_at: p.paidAt ? new Date(p.paidAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
91
+ provider_id: String(p.method || "unknown"),
92
+ data: { status: "captured", ...meta }
93
+ };
94
+ }
95
+ async function queueErpPaidOrderForOrderId(cms, dataSource, entityMap, orderId) {
96
+ try {
97
+ const configRepo = dataSource.getRepository(entityMap.configs);
98
+ const cfgRows = await configRepo.find({ where: { settings: "erp", deleted: false } });
99
+ for (const row of cfgRows) {
100
+ const r = row;
101
+ if (r.key === "enabled" && r.value === "false") return;
102
+ }
103
+ if (!cms.getPlugin("erp")) return;
104
+ const orderRepo = dataSource.getRepository(entityMap.orders);
105
+ const ord = await orderRepo.findOne({
106
+ where: { id: orderId },
107
+ relations: ["items", "items.product", "contact", "billingAddress", "shippingAddress", "payments"]
108
+ });
109
+ if (!ord) return;
110
+ const o = ord;
111
+ const okKind = o.orderKind === void 0 || o.orderKind === null || o.orderKind === "sale";
112
+ if (!okKind) return;
113
+ const rawPayments = o.payments ?? [];
114
+ const completedPayments = rawPayments.filter((pay) => pay.status === "completed" && pay.deleted !== true);
115
+ if (!completedPayments.length) return;
116
+ const rawItems = o.items ?? [];
117
+ const lines = rawItems.filter((it) => it.product).map((it) => {
118
+ const p = it.product;
119
+ const sku = p.sku || `SKU-${p.id}`;
120
+ const itemType = typeof it.productType === "string" && it.productType.trim() ? String(it.productType).trim() : p.type === "service" ? "service" : "product";
121
+ return {
122
+ sku,
123
+ quantity: Number(it.quantity) || 1,
124
+ unitPrice: Number(it.unitPrice),
125
+ title: p.name || sku,
126
+ discount: 0,
127
+ tax: Number(it.tax) || 0,
128
+ uom: (typeof it.uom === "string" && it.uom.trim() ? it.uom : p.uom) || void 0,
129
+ tax_code: typeof it.taxCode === "string" && it.taxCode.trim() ? String(it.taxCode).trim() : void 0,
130
+ hsn_number: (typeof it.hsn === "string" && it.hsn.trim() ? it.hsn : p.hsn) || void 0,
131
+ type: itemType
132
+ };
133
+ });
134
+ if (!lines.length) return;
135
+ const contact = o.contact;
136
+ const orderTotalMajor = Number(o.total);
137
+ const paymentDtos = completedPayments.length === 1 && Number.isFinite(orderTotalMajor) ? [paymentRowToWebhookDto(completedPayments[0], orderTotalMajor)] : completedPayments.map((pay) => paymentRowToWebhookDto(pay));
138
+ const baseMeta = o.metadata && typeof o.metadata === "object" && !Array.isArray(o.metadata) ? { ...o.metadata } : {};
139
+ const orderDto = {
140
+ platformType: "website",
141
+ platformOrderId: String(o.orderNumber),
142
+ platformOrderNumber: String(o.orderNumber),
143
+ order_date: o.createdAt ? new Date(o.createdAt).toISOString() : void 0,
144
+ status: orderStatusLabel(o.status),
145
+ customer: {
146
+ name: contact?.name || "",
147
+ email: contact?.email || "",
148
+ phone: contact?.phone || ""
149
+ },
150
+ shippingAddress: addressToWebhookDto(o.shippingAddress),
151
+ billingAddress: addressToWebhookDto(o.billingAddress),
152
+ items: lines,
153
+ payments: paymentDtos,
154
+ metadata: { ...baseMeta, source: "storefront" }
155
+ };
156
+ await queueErp(cms, { kind: "order", order: orderDto });
157
+ } catch {
158
+ }
159
+ }
160
+ var init_paid_order_erp = __esm({
161
+ "src/plugins/erp/paid-order-erp.ts"() {
162
+ "use strict";
163
+ init_erp_queue();
164
+ }
165
+ });
166
+
20
167
  // src/plugins/erp/erp-response-map.ts
21
168
  function pickString(o, keys) {
22
169
  for (const k of keys) {
@@ -93,6 +240,10 @@ var init_erp_response_map = __esm({
93
240
  });
94
241
 
95
242
  // src/plugins/erp/erp-config-enabled.ts
243
+ var erp_config_enabled_exports = {};
244
+ __export(erp_config_enabled_exports, {
245
+ isErpIntegrationEnabled: () => isErpIntegrationEnabled
246
+ });
96
247
  async function isErpIntegrationEnabled(cms, dataSource, entityMap) {
97
248
  if (!cms.getPlugin("erp")) return false;
98
249
  const configRepo = dataSource.getRepository(entityMap.configs);
@@ -207,14 +358,31 @@ async function queueEmail(cms, payload) {
207
358
  }
208
359
  }
209
360
  async function queueOrderPlacedEmails(cms, payload) {
210
- const { orderNumber, total, currency, customerName, customerEmail, salesTeamEmails, companyDetails, lineItems } = payload;
361
+ const {
362
+ orderNumber,
363
+ total,
364
+ subtotal,
365
+ tax,
366
+ currency,
367
+ customerName,
368
+ customerEmail,
369
+ salesTeamEmails,
370
+ companyDetails,
371
+ lineItems,
372
+ billingAddress,
373
+ shippingAddress
374
+ } = payload;
211
375
  const base = {
212
376
  orderNumber,
213
377
  total: total != null ? String(total) : void 0,
378
+ subtotal: subtotal != null ? String(subtotal) : void 0,
379
+ tax: tax != null ? String(tax) : void 0,
214
380
  currency,
215
381
  customerName,
216
382
  companyDetails: companyDetails ?? {},
217
- lineItems: lineItems ?? []
383
+ lineItems: lineItems ?? [],
384
+ billingAddress,
385
+ shippingAddress
218
386
  };
219
387
  const customerLower = customerEmail?.trim().toLowerCase() ?? "";
220
388
  const jobs = [];
@@ -725,149 +893,12 @@ var ERPSubmissionService = class {
725
893
  }
726
894
  };
727
895
 
728
- // src/plugins/erp/erp-queue.ts
729
- var ERP_QUEUE_NAME = "erp";
730
- async function queueErp(cms, payload) {
731
- const queue = cms.getPlugin("queue");
732
- if (!queue) return;
733
- await queue.add(ERP_QUEUE_NAME, payload);
734
- }
735
- function registerErpQueueProcessor(cms) {
736
- const queue = cms.getPlugin("queue");
737
- if (!queue) return;
738
- queue.registerProcessor(ERP_QUEUE_NAME, async (data) => {
739
- const erp = cms.getPlugin("erp");
740
- if (!erp) return;
741
- const payload = data;
742
- if (payload.kind === "lead") {
743
- await erp.submission.submitContact(payload.contact);
744
- } else if (payload.kind === "formOpportunity") {
745
- await erp.submission.submitFormOpportunity(payload.contact);
746
- } else if (payload.kind === "createContact") {
747
- await erp.submission.submitCreateContact(payload.contact);
748
- } else if (payload.kind === "order") {
749
- await erp.submission.submitOrder(payload.order);
750
- } else if (payload.kind === "productUpsert") {
751
- await erp.submission.submitProductUpsert(payload.product);
752
- }
753
- });
754
- }
755
-
756
- // src/plugins/erp/paid-order-erp.ts
757
- function amountToMinorUnits(major, currency) {
758
- const c = currency.toUpperCase();
759
- const zeroDecimal = /* @__PURE__ */ new Set([
760
- "BIF",
761
- "CLP",
762
- "DJF",
763
- "GNF",
764
- "JPY",
765
- "KMF",
766
- "KRW",
767
- "MGA",
768
- "PYG",
769
- "RWF",
770
- "UGX",
771
- "VND",
772
- "VUV",
773
- "XAF",
774
- "XOF",
775
- "XPF"
776
- ]);
777
- if (zeroDecimal.has(c)) return Math.round(major);
778
- return Math.round(major * 100);
779
- }
780
- function addressToWebhookDto(a) {
781
- if (!a) return {};
782
- return {
783
- line1: a.line1 ?? "",
784
- line2: a.line2 ?? "",
785
- city: a.city ?? "",
786
- state: a.state ?? "",
787
- postalCode: a.postalCode ?? "",
788
- country: a.country ?? ""
789
- };
790
- }
791
- function orderStatusLabel(status) {
792
- const s = (status || "").toLowerCase();
793
- if (s === "confirmed") return "Confirmed";
794
- if (s === "pending") return "Pending";
795
- if (!status) return "Pending";
796
- return status.charAt(0).toUpperCase() + status.slice(1);
797
- }
798
- function paymentRowToWebhookDto(p) {
799
- const currency = String(p.currency || "INR");
800
- const amountMajor = Number(p.amount);
801
- const meta = p.metadata || {};
802
- return {
803
- id: String(p.externalReference || `payment_${p.id}`),
804
- amount: amountToMinorUnits(amountMajor, currency),
805
- currency_code: currency,
806
- captured_at: p.paidAt ? new Date(p.paidAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
807
- provider_id: String(p.method || "unknown"),
808
- data: { status: "captured", ...meta }
809
- };
810
- }
811
- async function queueErpPaidOrderForOrderId(cms, dataSource, entityMap, orderId) {
812
- try {
813
- const configRepo = dataSource.getRepository(entityMap.configs);
814
- const cfgRows = await configRepo.find({ where: { settings: "erp", deleted: false } });
815
- for (const row of cfgRows) {
816
- const r = row;
817
- if (r.key === "enabled" && r.value === "false") return;
818
- }
819
- if (!cms.getPlugin("erp")) return;
820
- const orderRepo = dataSource.getRepository(entityMap.orders);
821
- const ord = await orderRepo.findOne({
822
- where: { id: orderId },
823
- relations: ["items", "items.product", "contact", "billingAddress", "shippingAddress", "payments"]
824
- });
825
- if (!ord) return;
826
- const o = ord;
827
- const okKind = o.orderKind === void 0 || o.orderKind === null || o.orderKind === "sale";
828
- if (!okKind) return;
829
- const rawPayments = o.payments ?? [];
830
- const completedPayments = rawPayments.filter((pay) => pay.status === "completed" && pay.deleted !== true);
831
- if (!completedPayments.length) return;
832
- const rawItems = o.items ?? [];
833
- const lines = rawItems.filter((it) => it.product).map((it) => {
834
- const p = it.product;
835
- const sku = p.sku || `SKU-${p.id}`;
836
- return {
837
- sku,
838
- quantity: Number(it.quantity) || 1,
839
- unitPrice: Number(it.unitPrice),
840
- title: p.name || sku,
841
- discount: 0,
842
- tax: Number(it.tax) || 0
843
- };
844
- });
845
- if (!lines.length) return;
846
- const contact = o.contact;
847
- const paymentDtos = completedPayments.map((pay) => paymentRowToWebhookDto(pay));
848
- const baseMeta = o.metadata && typeof o.metadata === "object" && !Array.isArray(o.metadata) ? { ...o.metadata } : {};
849
- const orderDto = {
850
- platformType: "website",
851
- platformOrderId: String(o.orderNumber),
852
- platformOrderNumber: String(o.orderNumber),
853
- status: orderStatusLabel(o.status),
854
- customer: {
855
- name: contact?.name || "",
856
- email: contact?.email || "",
857
- phone: contact?.phone || ""
858
- },
859
- shippingAddress: addressToWebhookDto(o.shippingAddress),
860
- billingAddress: addressToWebhookDto(o.billingAddress),
861
- items: lines,
862
- payments: paymentDtos,
863
- metadata: { ...baseMeta, source: "storefront" }
864
- };
865
- await queueErp(cms, { kind: "order", order: orderDto });
866
- } catch {
867
- }
868
- }
896
+ // src/plugins/erp/index.ts
897
+ init_erp_queue();
898
+ init_paid_order_erp();
869
899
 
870
900
  // src/plugins/erp/erp-contact-sync.ts
901
+ init_erp_queue();
871
902
  function splitName(full) {
872
903
  const t = (full || "").trim();
873
904
  if (!t) return { firstName: "Contact", lastName: "" };
@@ -1111,6 +1142,7 @@ init_erp_order_invoice();
1111
1142
  init_erp_config_enabled();
1112
1143
 
1113
1144
  // src/plugins/erp/erp-product-sync.ts
1145
+ init_erp_queue();
1114
1146
  init_erp_config_enabled();
1115
1147
  async function queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, product) {
1116
1148
  try {
@@ -1118,14 +1150,21 @@ async function queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, produc
1118
1150
  if (!sku) return;
1119
1151
  const on = await isErpIntegrationEnabled(cms, dataSource, entityMap);
1120
1152
  if (!on) return;
1153
+ const rawMeta = product.metadata;
1154
+ let metadata;
1155
+ if (rawMeta && typeof rawMeta === "object" && !Array.isArray(rawMeta)) {
1156
+ const { description: _d, ...rest } = rawMeta;
1157
+ metadata = Object.keys(rest).length ? rest : void 0;
1158
+ }
1121
1159
  const payload = {
1122
1160
  sku,
1123
1161
  title: product.name || sku,
1124
1162
  name: product.name,
1125
- description: typeof product.metadata === "object" && product.metadata && "description" in product.metadata ? String(product.metadata.description ?? "") : void 0,
1126
1163
  hsn_number: product.hsn,
1164
+ uom: product.uom != null && String(product.uom).trim() ? String(product.uom).trim() : void 0,
1165
+ type: product.type === "service" ? "service" : "product",
1127
1166
  is_active: product.status === "available",
1128
- metadata: product.metadata ?? void 0
1167
+ metadata
1129
1168
  };
1130
1169
  await queueErp(cms, { kind: "productUpsert", product: payload });
1131
1170
  } catch {
@@ -1411,8 +1450,10 @@ function renderLineItemsHtml(items, currency) {
1411
1450
  const rows = items.map((it) => {
1412
1451
  const name = escapeHtml2(it.productName);
1413
1452
  const sku = it.sku && String(it.sku).trim() ? `<span style="font-size:12px;color:#888;"> (${escapeHtml2(String(it.sku).trim())})</span>` : "";
1453
+ const hsn = it.hsn && String(it.hsn).trim() ? `<br/><span style="font-size:11px;color:#888;">HSN: ${escapeHtml2(String(it.hsn).trim())}</span>` : "";
1454
+ 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>` : "";
1414
1455
  return `<tr>
1415
- <td style="padding:10px 8px 10px 0;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;">${name}${sku}</td>
1456
+ <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>
1416
1457
  <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>
1417
1458
  <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>
1418
1459
  <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>
@@ -1431,24 +1472,64 @@ ${rows}
1431
1472
  }
1432
1473
  function renderLineItemsText(items, currency) {
1433
1474
  if (!items.length) return "";
1434
- const lines = items.map(
1435
- (it) => `- ${it.productName} \xD7 ${it.quantity} @ ${formatMoney(it.unitPrice, currency)} = ${formatMoney(it.lineTotal, currency)}${it.sku ? ` [${it.sku}]` : ""}`
1436
- );
1475
+ const lines = items.map((it) => {
1476
+ let s = `- ${it.productName} \xD7 ${it.quantity} @ ${formatMoney(it.unitPrice, currency)} = ${formatMoney(it.lineTotal, currency)}`;
1477
+ if (it.sku) s += ` [${it.sku}]`;
1478
+ if (it.hsn && String(it.hsn).trim()) s += ` HSN:${it.hsn}`;
1479
+ if (it.tax != null && Number(it.tax) !== 0) s += ` tax:${formatMoney(it.tax, currency)}`;
1480
+ return s;
1481
+ });
1437
1482
  return ["Items:", ...lines].join("\n");
1438
1483
  }
1484
+ function formatAddressLines(addr) {
1485
+ if (!addr || typeof addr !== "object") return [];
1486
+ const parts = [addr.line1, addr.line2, [addr.city, addr.state].filter(Boolean).join(", "), addr.postalCode, addr.country].filter(
1487
+ (x) => x != null && String(x).trim() !== ""
1488
+ );
1489
+ return parts.map((p) => String(p).trim()).filter(Boolean);
1490
+ }
1491
+ function renderAddressesHtml(billing, shipping) {
1492
+ const bLines = formatAddressLines(billing);
1493
+ const sLines = formatAddressLines(shipping);
1494
+ if (!bLines.length && !sLines.length) return "";
1495
+ let html = '<p style="margin:16px 0 8px 0;font-size:14px;font-weight:600;color:#111;">Addresses</p>';
1496
+ if (bLines.length) {
1497
+ 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>`;
1498
+ }
1499
+ if (sLines.length) {
1500
+ 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>`;
1501
+ }
1502
+ return html;
1503
+ }
1504
+ function renderAddressesText(billing, shipping) {
1505
+ const bLines = formatAddressLines(billing);
1506
+ const sLines = formatAddressLines(shipping);
1507
+ const out = [];
1508
+ if (bLines.length) out.push("Billing:", ...bLines.map((l) => ` ${l}`));
1509
+ if (sLines.length) out.push("Shipping:", ...sLines.map((l) => ` ${l}`));
1510
+ return out.length ? out.join("\n") : "";
1511
+ }
1439
1512
  function render4(ctx) {
1440
1513
  const {
1441
1514
  orderNumber,
1442
1515
  total,
1516
+ subtotal,
1517
+ tax,
1443
1518
  currency,
1444
1519
  customerName,
1445
1520
  companyDetails,
1446
1521
  audience = "customer",
1447
1522
  internalCustomerEmail,
1448
- lineItems = []
1523
+ lineItems = [],
1524
+ billingAddress,
1525
+ shippingAddress
1449
1526
  } = ctx;
1450
1527
  const itemsHtml = renderLineItemsHtml(lineItems, currency);
1451
1528
  const itemsText = renderLineItemsText(lineItems, currency);
1529
+ const addrHtml = renderAddressesHtml(billingAddress, shippingAddress);
1530
+ const addrText = renderAddressesText(billingAddress, shippingAddress);
1531
+ 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>` : "";
1532
+ 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>` : "";
1452
1533
  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>` : "";
1453
1534
  let subject;
1454
1535
  let bodyHtml;
@@ -1459,13 +1540,17 @@ function render4(ctx) {
1459
1540
  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>
1460
1541
  <p style="margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;"><strong>Order number:</strong> ${escapeHtml2(orderNumber)}</p>
1461
1542
  ${who}
1543
+ ${addrHtml}
1462
1544
  ${itemsHtml}
1463
- ${totalLine}`;
1545
+ ${subtotalLine}${taxLine}${totalLine}`;
1464
1546
  text = [
1465
1547
  `New order #${orderNumber}`,
1466
1548
  customerName ? `Customer: ${customerName}` : "",
1467
1549
  internalCustomerEmail ? `Email: ${internalCustomerEmail}` : "",
1550
+ addrText,
1468
1551
  itemsText,
1552
+ subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ""}` : "",
1553
+ tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ""}` : "",
1469
1554
  total != null ? `Order total: ${total}${currency ? ` ${currency}` : ""}` : ""
1470
1555
  ].filter(Boolean).join("\n\n");
1471
1556
  } else {
@@ -1474,14 +1559,18 @@ ${totalLine}`;
1474
1559
  const thanksHtml = `${escapeHtml2(thanksPlain)} We\u2019ve received your order and will process it shortly.`;
1475
1560
  bodyHtml = `<p style="margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;">${thanksHtml}</p>
1476
1561
  <p style="margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;"><strong>Order number:</strong> ${escapeHtml2(orderNumber)}</p>
1562
+ ${addrHtml}
1477
1563
  ${itemsHtml}
1478
- ${totalLine}
1564
+ ${subtotalLine}${taxLine}${totalLine}
1479
1565
  <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>`;
1480
1566
  text = [
1481
1567
  `Order confirmed #${orderNumber}`,
1482
1568
  `${thanksPlain} We\u2019ve received your order and will process it shortly.`,
1483
1569
  "",
1570
+ addrText,
1484
1571
  itemsText,
1572
+ subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ""}` : "",
1573
+ tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ""}` : "",
1485
1574
  total != null ? `Order total: ${total}${currency ? ` ${currency}` : ""}` : "",
1486
1575
  "",
1487
1576
  "We will process your order shortly."
@@ -4879,6 +4968,8 @@ var Product = class {
4879
4968
  categoryId;
4880
4969
  sku;
4881
4970
  hsn;
4971
+ uom;
4972
+ type;
4882
4973
  slug;
4883
4974
  name;
4884
4975
  price;
@@ -4920,6 +5011,12 @@ __decorateClass([
4920
5011
  __decorateClass([
4921
5012
  Column27("varchar", { nullable: true })
4922
5013
  ], Product.prototype, "hsn", 2);
5014
+ __decorateClass([
5015
+ Column27("varchar", { nullable: true })
5016
+ ], Product.prototype, "uom", 2);
5017
+ __decorateClass([
5018
+ Column27("varchar", { default: "product" })
5019
+ ], Product.prototype, "type", 2);
4923
5020
  __decorateClass([
4924
5021
  Column27("varchar", { unique: true, nullable: true })
4925
5022
  ], Product.prototype, "slug", 2);
@@ -5228,6 +5325,11 @@ var OrderItem = class {
5228
5325
  unitPrice;
5229
5326
  tax;
5230
5327
  total;
5328
+ hsn;
5329
+ uom;
5330
+ productType;
5331
+ taxRate;
5332
+ taxCode;
5231
5333
  metadata;
5232
5334
  createdAt;
5233
5335
  updatedAt;
@@ -5255,6 +5357,21 @@ __decorateClass([
5255
5357
  __decorateClass([
5256
5358
  Column32("decimal", { precision: 12, scale: 2 })
5257
5359
  ], OrderItem.prototype, "total", 2);
5360
+ __decorateClass([
5361
+ Column32("varchar", { nullable: true })
5362
+ ], OrderItem.prototype, "hsn", 2);
5363
+ __decorateClass([
5364
+ Column32("varchar", { nullable: true })
5365
+ ], OrderItem.prototype, "uom", 2);
5366
+ __decorateClass([
5367
+ Column32("varchar", { nullable: true })
5368
+ ], OrderItem.prototype, "productType", 2);
5369
+ __decorateClass([
5370
+ Column32("decimal", { precision: 5, scale: 2, nullable: true })
5371
+ ], OrderItem.prototype, "taxRate", 2);
5372
+ __decorateClass([
5373
+ Column32("varchar", { nullable: true })
5374
+ ], OrderItem.prototype, "taxCode", 2);
5258
5375
  __decorateClass([
5259
5376
  Column32("jsonb", { nullable: true })
5260
5377
  ], OrderItem.prototype, "metadata", 2);
@@ -6151,6 +6268,24 @@ function createCrudHandler(dataSource, entityMap, options) {
6151
6268
  } else if (search) {
6152
6269
  where = buildSearchWhereClause(repo, search);
6153
6270
  }
6271
+ const intFilterKeys = ["productId", "attributeId", "taxId"];
6272
+ const extraWhere = {};
6273
+ for (const key of intFilterKeys) {
6274
+ const v = searchParams.get(key);
6275
+ if (v != null && v !== "" && columnNames.has(key)) {
6276
+ const n = Number(v);
6277
+ if (Number.isFinite(n)) extraWhere[key] = n;
6278
+ }
6279
+ }
6280
+ if (Object.keys(extraWhere).length > 0) {
6281
+ if (Array.isArray(where)) {
6282
+ where = where.map((w) => ({ ...w, ...extraWhere }));
6283
+ } else if (where && typeof where === "object" && Object.keys(where).length > 0) {
6284
+ where = { ...where, ...extraWhere };
6285
+ } else {
6286
+ where = extraWhere;
6287
+ }
6288
+ }
6154
6289
  const [data, total] = await repo.findAndCount({
6155
6290
  skip,
6156
6291
  take: limit,
@@ -6607,6 +6742,7 @@ function createUserAuthApiRouter(config) {
6607
6742
 
6608
6743
  // src/api/cms-handlers.ts
6609
6744
  init_email_queue();
6745
+ init_erp_queue();
6610
6746
  import { MoreThanOrEqual, ILike as ILike2 } from "typeorm";
6611
6747
  function createDashboardStatsHandler(config) {
6612
6748
  const { dataSource, entityMap, json, requireAuth, requirePermission, requireEntityPermission } = config;
@@ -8009,6 +8145,29 @@ function createCmsApiHandler(config) {
8009
8145
  if (!Number.isFinite(oid)) return config.json({ error: "Invalid id" }, { status: 400 });
8010
8146
  return streamOrderInvoicePdf2(cms, dataSource, entityMap, oid, {});
8011
8147
  }
8148
+ if (path[0] === "orders" && path.length === 3 && path[2] === "repost-erp" && getCms) {
8149
+ const a = await config.requireAuth(req);
8150
+ if (a) return a;
8151
+ if (perm) {
8152
+ const pe = await perm(req, "orders", method === "GET" ? "read" : "update");
8153
+ if (pe) return pe;
8154
+ }
8155
+ const oid = Number(path[1]);
8156
+ if (!Number.isFinite(oid)) return config.json({ error: "Invalid id" }, { status: 400 });
8157
+ const cms = await getCms();
8158
+ const { isErpIntegrationEnabled: isErpIntegrationEnabled3 } = await Promise.resolve().then(() => (init_erp_config_enabled(), erp_config_enabled_exports));
8159
+ const enabled = await isErpIntegrationEnabled3(cms, dataSource, entityMap);
8160
+ if (method === "GET") {
8161
+ return config.json({ enabled });
8162
+ }
8163
+ if (method === "POST") {
8164
+ if (!enabled) return config.json({ error: "ERP integration is disabled" }, { status: 409 });
8165
+ const { queueErpPaidOrderForOrderId: queueErpPaidOrderForOrderId2 } = await Promise.resolve().then(() => (init_paid_order_erp(), paid_order_erp_exports));
8166
+ await queueErpPaidOrderForOrderId2(cms, dataSource, entityMap, oid);
8167
+ return config.json({ ok: true });
8168
+ }
8169
+ return config.json({ error: "Method not allowed" }, { status: 405 });
8170
+ }
8012
8171
  if (path.length === 0) return config.json({ error: "Not found" }, { status: 404 });
8013
8172
  const resource = resolveResource(path[0]);
8014
8173
  if (!crudResources.includes(resource)) return config.json({ error: "Invalid resource" }, { status: 400 });
@@ -8105,6 +8264,152 @@ function createStorefrontApiHandler(config) {
8105
8264
  const tokenRepo = () => dataSource.getRepository(entityMap.password_reset_tokens);
8106
8265
  const collectionRepo = () => dataSource.getRepository(entityMap.collections);
8107
8266
  const groupRepo = () => dataSource.getRepository(entityMap.user_groups);
8267
+ const configRepo = () => dataSource.getRepository(entityMap.configs);
8268
+ const CART_CHECKOUT_RELATIONS = ["items", "items.product", "items.product.taxes", "items.product.taxes.tax"];
8269
+ function roundMoney2(n) {
8270
+ return Math.round(n * 100) / 100;
8271
+ }
8272
+ async function getStoreDefaultTaxRate() {
8273
+ const rows = await configRepo().find({ where: { settings: "store", deleted: false } });
8274
+ for (const row of rows) {
8275
+ const r = row;
8276
+ if (r.key === "defaultTaxRate") {
8277
+ const n = parseFloat(String(r.value ?? "").trim());
8278
+ return Number.isFinite(n) && n >= 0 ? n : null;
8279
+ }
8280
+ }
8281
+ return null;
8282
+ }
8283
+ function computeTaxForProductLine(p, lineSubtotal, defaultRate) {
8284
+ const pts = p.taxes ?? [];
8285
+ const activePts = pts.filter((pt) => {
8286
+ const t = pt.tax;
8287
+ return t != null && t.active !== false;
8288
+ });
8289
+ if (activePts.length) {
8290
+ let sumRate = 0;
8291
+ const slugs = [];
8292
+ for (const pt of activePts) {
8293
+ const t = pt.tax;
8294
+ const r = Number(pt.rate != null && pt.rate !== "" ? pt.rate : t.rate ?? 0);
8295
+ if (Number.isFinite(r)) sumRate += r;
8296
+ const slug = String(t.slug ?? "").trim();
8297
+ if (slug) slugs.push(slug);
8298
+ }
8299
+ const tax = roundMoney2(lineSubtotal * sumRate / 100);
8300
+ return {
8301
+ tax,
8302
+ taxRate: sumRate > 0 ? roundMoney2(sumRate) : null,
8303
+ taxCode: slugs.length ? [...new Set(slugs)].sort().join(",") : null
8304
+ };
8305
+ }
8306
+ if (defaultRate != null && defaultRate > 0) {
8307
+ return {
8308
+ tax: roundMoney2(lineSubtotal * defaultRate / 100),
8309
+ taxRate: roundMoney2(defaultRate),
8310
+ taxCode: null
8311
+ };
8312
+ }
8313
+ return { tax: 0, taxRate: null, taxCode: null };
8314
+ }
8315
+ function parseInlineAddress(raw) {
8316
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
8317
+ const o = raw;
8318
+ const line1 = String(o.line1 ?? "").trim();
8319
+ if (!line1) return null;
8320
+ return {
8321
+ line1,
8322
+ line2: o.line2 != null ? String(o.line2) : "",
8323
+ city: o.city != null ? String(o.city) : "",
8324
+ state: o.state != null ? String(o.state) : "",
8325
+ postalCode: o.postalCode != null ? String(o.postalCode) : "",
8326
+ country: o.country != null ? String(o.country) : ""
8327
+ };
8328
+ }
8329
+ function intFromBody(v) {
8330
+ if (typeof v === "number" && Number.isInteger(v)) return v;
8331
+ if (typeof v === "string" && /^\d+$/.test(v)) return parseInt(v, 10);
8332
+ return void 0;
8333
+ }
8334
+ async function resolveCheckoutAddress(contactId, idVal, inlineVal) {
8335
+ const aid = intFromBody(idVal);
8336
+ if (aid != null) {
8337
+ const existing = await addressRepo().findOne({
8338
+ where: { id: aid, contactId }
8339
+ });
8340
+ if (!existing) return { id: null, error: "Address not found" };
8341
+ return { id: aid };
8342
+ }
8343
+ const addr = parseInlineAddress(inlineVal);
8344
+ if (addr) {
8345
+ const saved = await addressRepo().save(
8346
+ addressRepo().create({
8347
+ contactId,
8348
+ line1: addr.line1,
8349
+ line2: addr.line2?.trim() ? addr.line2 : null,
8350
+ city: addr.city?.trim() ? addr.city : null,
8351
+ state: addr.state?.trim() ? addr.state : null,
8352
+ postalCode: addr.postalCode?.trim() ? addr.postalCode : null,
8353
+ country: addr.country?.trim() ? addr.country : null
8354
+ })
8355
+ );
8356
+ return { id: saved.id };
8357
+ }
8358
+ return { id: null };
8359
+ }
8360
+ async function prepareCheckoutFromCart(b, cart, contactId) {
8361
+ const defaultRate = await getStoreDefaultTaxRate();
8362
+ const lines = [];
8363
+ let subtotal = 0;
8364
+ let orderTax = 0;
8365
+ let needsShipping = false;
8366
+ for (const it of cart.items || []) {
8367
+ const p = it.product;
8368
+ if (!p || p.deleted || p.status !== "available") continue;
8369
+ const unit = Number(p.price);
8370
+ const qty = it.quantity || 1;
8371
+ const lineSubtotal = unit * qty;
8372
+ const pType = p.type === "service" ? "service" : "product";
8373
+ if (pType === "product") needsShipping = true;
8374
+ const { tax, taxRate, taxCode } = computeTaxForProductLine(p, lineSubtotal, defaultRate);
8375
+ const lineTotal = roundMoney2(lineSubtotal + tax);
8376
+ subtotal = roundMoney2(subtotal + lineSubtotal);
8377
+ orderTax = roundMoney2(orderTax + tax);
8378
+ lines.push({
8379
+ productId: p.id,
8380
+ quantity: qty,
8381
+ unitPrice: unit,
8382
+ tax,
8383
+ total: lineTotal,
8384
+ hsn: p.hsn ?? null,
8385
+ uom: p.uom ?? null,
8386
+ productType: pType,
8387
+ taxRate,
8388
+ taxCode
8389
+ });
8390
+ }
8391
+ if (!lines.length) return { ok: false, status: 400, message: "No available items in cart" };
8392
+ const bill = await resolveCheckoutAddress(contactId, b.billingAddressId, b.billingAddress);
8393
+ if (bill.error) return { ok: false, status: 400, message: bill.error };
8394
+ if (bill.id == null) return { ok: false, status: 400, message: "Billing address required" };
8395
+ const ship = await resolveCheckoutAddress(contactId, b.shippingAddressId, b.shippingAddress);
8396
+ if (ship.error) return { ok: false, status: 400, message: ship.error };
8397
+ let shippingAddressId = ship.id;
8398
+ if (needsShipping && shippingAddressId == null) shippingAddressId = bill.id;
8399
+ if (needsShipping && shippingAddressId == null) {
8400
+ return { ok: false, status: 400, message: "Shipping address required" };
8401
+ }
8402
+ const orderTotal = roundMoney2(subtotal + orderTax);
8403
+ return {
8404
+ ok: true,
8405
+ lines,
8406
+ subtotal,
8407
+ orderTax,
8408
+ orderTotal,
8409
+ billingAddressId: bill.id,
8410
+ shippingAddressId
8411
+ };
8412
+ }
8108
8413
  async function syncContactToErp(contact) {
8109
8414
  if (!getCms) return;
8110
8415
  try {
@@ -8230,6 +8535,7 @@ function createStorefrontApiHandler(config) {
8230
8535
  slug: p.slug,
8231
8536
  price: p.price,
8232
8537
  sku: p.sku,
8538
+ type: p.type === "service" ? "service" : "product",
8233
8539
  image: primaryProductImageUrl(p.metadata)
8234
8540
  } : null
8235
8541
  };
@@ -8257,6 +8563,8 @@ function createStorefrontApiHandler(config) {
8257
8563
  slug: p.slug,
8258
8564
  sku: p.sku,
8259
8565
  hsn: p.hsn,
8566
+ uom: p.uom ?? null,
8567
+ type: p.type === "service" ? "service" : "product",
8260
8568
  price: p.price,
8261
8569
  compareAtPrice: p.compareAtPrice,
8262
8570
  status: p.status,
@@ -8958,7 +9266,7 @@ function createStorefrontApiHandler(config) {
8958
9266
  contactId = contact.id;
8959
9267
  cart = await cartRepo().findOne({
8960
9268
  where: { contactId },
8961
- relations: ["items", "items.product"]
9269
+ relations: [...CART_CHECKOUT_RELATIONS]
8962
9270
  });
8963
9271
  } else {
8964
9272
  const email = String(b.email ?? "").trim();
@@ -8991,25 +9299,14 @@ function createStorefrontApiHandler(config) {
8991
9299
  if (!guestToken) return json({ error: "Cart not found" }, { status: 400 });
8992
9300
  cart = await cartRepo().findOne({
8993
9301
  where: { guestToken },
8994
- relations: ["items", "items.product"]
9302
+ relations: [...CART_CHECKOUT_RELATIONS]
8995
9303
  });
8996
9304
  }
8997
9305
  if (!cart || !(cart.items || []).length) {
8998
9306
  return json({ error: "Cart is empty" }, { status: 400 });
8999
9307
  }
9000
- let subtotal = 0;
9001
- const lines = [];
9002
- for (const it of cart.items || []) {
9003
- const p = it.product;
9004
- if (!p || p.deleted || p.status !== "available") continue;
9005
- const unit = Number(p.price);
9006
- const qty = it.quantity || 1;
9007
- const lineTotal = unit * qty;
9008
- subtotal += lineTotal;
9009
- lines.push({ productId: p.id, quantity: qty, unitPrice: unit, tax: 0, total: lineTotal });
9010
- }
9011
- if (!lines.length) return json({ error: "No available items in cart" }, { status: 400 });
9012
- const total = subtotal;
9308
+ const prepOrd = await prepareCheckoutFromCart(b, cart, contactId);
9309
+ if (!prepOrd.ok) return json({ error: prepOrd.message }, { status: prepOrd.status });
9013
9310
  const cartId = cart.id;
9014
9311
  const ord = await orderRepo().save(
9015
9312
  orderRepo().create({
@@ -9017,13 +9314,13 @@ function createStorefrontApiHandler(config) {
9017
9314
  orderKind: "sale",
9018
9315
  parentOrderId: null,
9019
9316
  contactId,
9020
- billingAddressId: typeof b.billingAddressId === "number" ? b.billingAddressId : null,
9021
- shippingAddressId: typeof b.shippingAddressId === "number" ? b.shippingAddressId : null,
9317
+ billingAddressId: prepOrd.billingAddressId,
9318
+ shippingAddressId: prepOrd.shippingAddressId,
9022
9319
  status: "pending",
9023
- subtotal,
9024
- tax: 0,
9320
+ subtotal: prepOrd.subtotal,
9321
+ tax: prepOrd.orderTax,
9025
9322
  discount: 0,
9026
- total,
9323
+ total: prepOrd.orderTotal,
9027
9324
  currency: cart.currency || "INR",
9028
9325
  metadata: { cartId }
9029
9326
  })
@@ -9032,7 +9329,7 @@ function createStorefrontApiHandler(config) {
9032
9329
  await orderRepo().update(oid, {
9033
9330
  orderNumber: buildCanonicalOrderNumber("sale", oid, ord.createdAt ?? /* @__PURE__ */ new Date())
9034
9331
  });
9035
- for (const line of lines) {
9332
+ for (const line of prepOrd.lines) {
9036
9333
  await orderItemRepo().save(
9037
9334
  orderItemRepo().create({
9038
9335
  orderId: oid,
@@ -9040,14 +9337,21 @@ function createStorefrontApiHandler(config) {
9040
9337
  quantity: line.quantity,
9041
9338
  unitPrice: line.unitPrice,
9042
9339
  tax: line.tax,
9043
- total: line.total
9340
+ total: line.total,
9341
+ hsn: line.hsn,
9342
+ uom: line.uom,
9343
+ productType: line.productType,
9344
+ taxRate: line.taxRate,
9345
+ taxCode: line.taxCode
9044
9346
  })
9045
9347
  );
9046
9348
  }
9047
9349
  return json({
9048
9350
  orderId: oid,
9049
9351
  orderNumber: ord.orderNumber,
9050
- total,
9352
+ subtotal: prepOrd.subtotal,
9353
+ tax: prepOrd.orderTax,
9354
+ total: prepOrd.orderTotal,
9051
9355
  currency: cart.currency || "INR"
9052
9356
  });
9053
9357
  }
@@ -9065,7 +9369,7 @@ function createStorefrontApiHandler(config) {
9065
9369
  contactId = contact.id;
9066
9370
  cart = await cartRepo().findOne({
9067
9371
  where: { contactId },
9068
- relations: ["items", "items.product"]
9372
+ relations: [...CART_CHECKOUT_RELATIONS]
9069
9373
  });
9070
9374
  } else {
9071
9375
  const email = String(b.email ?? "").trim();
@@ -9098,38 +9402,27 @@ function createStorefrontApiHandler(config) {
9098
9402
  if (!guestToken) return json({ error: "Cart not found" }, { status: 400 });
9099
9403
  cart = await cartRepo().findOne({
9100
9404
  where: { guestToken },
9101
- relations: ["items", "items.product"]
9405
+ relations: [...CART_CHECKOUT_RELATIONS]
9102
9406
  });
9103
9407
  }
9104
9408
  if (!cart || !(cart.items || []).length) {
9105
9409
  return json({ error: "Cart is empty" }, { status: 400 });
9106
9410
  }
9107
- let subtotal = 0;
9108
- const lines = [];
9109
- for (const it of cart.items || []) {
9110
- const p = it.product;
9111
- if (!p || p.deleted || p.status !== "available") continue;
9112
- const unit = Number(p.price);
9113
- const qty = it.quantity || 1;
9114
- const lineTotal = unit * qty;
9115
- subtotal += lineTotal;
9116
- lines.push({ productId: p.id, quantity: qty, unitPrice: unit, tax: 0, total: lineTotal });
9117
- }
9118
- if (!lines.length) return json({ error: "No available items in cart" }, { status: 400 });
9119
- const total = subtotal;
9411
+ const prepChk = await prepareCheckoutFromCart(b, cart, contactId);
9412
+ if (!prepChk.ok) return json({ error: prepChk.message }, { status: prepChk.status });
9120
9413
  const ord = await orderRepo().save(
9121
9414
  orderRepo().create({
9122
9415
  orderNumber: temporaryOrderNumberPlaceholder(),
9123
9416
  orderKind: "sale",
9124
9417
  parentOrderId: null,
9125
9418
  contactId,
9126
- billingAddressId: typeof b.billingAddressId === "number" ? b.billingAddressId : null,
9127
- shippingAddressId: typeof b.shippingAddressId === "number" ? b.shippingAddressId : null,
9419
+ billingAddressId: prepChk.billingAddressId,
9420
+ shippingAddressId: prepChk.shippingAddressId,
9128
9421
  status: "pending",
9129
- subtotal,
9130
- tax: 0,
9422
+ subtotal: prepChk.subtotal,
9423
+ tax: prepChk.orderTax,
9131
9424
  discount: 0,
9132
- total,
9425
+ total: prepChk.orderTotal,
9133
9426
  currency: cart.currency || "INR"
9134
9427
  })
9135
9428
  );
@@ -9137,7 +9430,7 @@ function createStorefrontApiHandler(config) {
9137
9430
  await orderRepo().update(oid, {
9138
9431
  orderNumber: buildCanonicalOrderNumber("sale", oid, ord.createdAt ?? /* @__PURE__ */ new Date())
9139
9432
  });
9140
- for (const line of lines) {
9433
+ for (const line of prepChk.lines) {
9141
9434
  await orderItemRepo().save(
9142
9435
  orderItemRepo().create({
9143
9436
  orderId: oid,
@@ -9145,7 +9438,12 @@ function createStorefrontApiHandler(config) {
9145
9438
  quantity: line.quantity,
9146
9439
  unitPrice: line.unitPrice,
9147
9440
  tax: line.tax,
9148
- total: line.total
9441
+ total: line.total,
9442
+ hsn: line.hsn,
9443
+ uom: line.uom,
9444
+ productType: line.productType,
9445
+ taxRate: line.taxRate,
9446
+ taxCode: line.taxCode
9149
9447
  })
9150
9448
  );
9151
9449
  }
@@ -9154,7 +9452,9 @@ function createStorefrontApiHandler(config) {
9154
9452
  return json({
9155
9453
  orderId: oid,
9156
9454
  orderNumber: ord.orderNumber,
9157
- total
9455
+ subtotal: prepChk.subtotal,
9456
+ tax: prepChk.orderTax,
9457
+ total: prepChk.orderTotal
9158
9458
  });
9159
9459
  }
9160
9460
  if (path[0] === "orders" && path.length === 1 && method === "GET") {