@burdenoff/microfe-movethewheels 2026.1016.2 → 2026.1016.4

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 (113) hide show
  1. package/README.md +10 -0
  2. package/dist/MoveTheWheelsRoot.js +5 -0
  3. package/dist/MoveTheWheelsRoutes.js +25 -21
  4. package/dist/components/ContainerEvidencePicker.js +55 -55
  5. package/dist/components/FleetAlertsPanel.js +2 -2
  6. package/dist/components/freight-cost/FreightCommercialEditor.js +217 -0
  7. package/dist/components/freight-cost/FreightCommercialFactEditor.js +217 -0
  8. package/dist/components/freight-cost/FreightCommercialHistory.js +115 -0
  9. package/dist/components/freight-cost/FreightDraftForm.js +106 -91
  10. package/dist/components/freight-cost/FreightHistory.js +42 -40
  11. package/dist/components/freight-invoice/InvoiceForm.js +366 -0
  12. package/dist/components/freight-invoice/InvoiceResults.js +240 -0
  13. package/dist/generated/consolidation-operations.d.ts +195 -265
  14. package/dist/generated/container-condition-operations.d.ts +124 -187
  15. package/dist/generated/container-operations.d.ts +59 -85
  16. package/dist/generated/empty-reuse-operations.d.ts +165 -271
  17. package/dist/generated/free-time-operations.d.ts +120 -184
  18. package/dist/generated/freight-cost-operations.d.ts +955 -165
  19. package/dist/generated/freight-invoice-operations.d.ts +1447 -0
  20. package/dist/generated/logistics-procedure-operations.d.ts +100 -156
  21. package/dist/generated/pending-pick-operations.d.ts +769 -1025
  22. package/dist/generated/shipment-status-authority-operations.d.ts +82 -103
  23. package/dist/generated/stock-binding-operations.d.ts +188 -260
  24. package/dist/generated/stock-observation-operations.d.ts +103 -138
  25. package/dist/generated/tracking-quality-operations.d.ts +27 -41
  26. package/dist/generated/trip-utilization-operations.d.ts +137 -185
  27. package/dist/generated/wspace-operations.d.ts +628 -2272
  28. package/dist/generated/wspace-types.d.ts +4 -23
  29. package/dist/hooks/useFreightRecoveryAction.js +20 -20
  30. package/dist/hooks/useInvoiceComparisonRecovery.js +118 -0
  31. package/dist/movethewheels/components/ContainerEvidencePicker.d.ts +2 -1
  32. package/dist/movethewheels/components/freight-cost/FreightCommercialEditor.d.ts +8 -0
  33. package/dist/movethewheels/components/freight-cost/FreightCommercialFactEditor.d.ts +8 -0
  34. package/dist/movethewheels/components/freight-cost/FreightCommercialHistory.d.ts +4 -0
  35. package/dist/movethewheels/components/freight-cost/FreightDraftForm.d.ts +4 -2
  36. package/dist/movethewheels/components/freight-cost/FreightHistory.d.ts +2 -2
  37. package/dist/movethewheels/components/freight-invoice/InvoiceForm.d.ts +19 -0
  38. package/dist/movethewheels/components/freight-invoice/InvoiceResults.d.ts +9 -0
  39. package/dist/movethewheels/hooks/useFleet.d.ts +1 -1
  40. package/dist/movethewheels/hooks/useFleetIntelligence.d.ts +1 -1
  41. package/dist/movethewheels/hooks/useInvoiceComparisonRecovery.d.ts +22 -0
  42. package/dist/movethewheels/hooks/useProcedureSelection.d.ts +1 -3
  43. package/dist/movethewheels/pages/FreightInvoicePage.d.ts +10 -0
  44. package/dist/movethewheels/utils/driverLicenseExpiry.d.ts +6 -0
  45. package/dist/movethewheels/utils/freightCommercial.d.ts +44 -0
  46. package/dist/movethewheels/utils/invoiceComparison.d.ts +32 -0
  47. package/dist/pages/DriverDetailsPage.js +306 -282
  48. package/dist/pages/FreightEstimatePage.js +97 -92
  49. package/dist/pages/FreightInvoicePage.js +346 -0
  50. package/dist/src/generated/consolidation-operations.js +3961 -503
  51. package/dist/src/generated/container-condition-operations.js +2968 -206
  52. package/dist/src/generated/container-operations.js +997 -99
  53. package/dist/src/generated/empty-reuse-operations.js +4811 -747
  54. package/dist/src/generated/free-time-operations.js +2824 -233
  55. package/dist/src/generated/freight-cost-operations.js +4852 -323
  56. package/dist/src/generated/freight-invoice-operations.js +4894 -0
  57. package/dist/src/generated/logistics-procedure-operations.js +2707 -360
  58. package/dist/src/generated/pending-pick-operations.js +8244 -1196
  59. package/dist/src/generated/shipment-status-authority-operations.js +1157 -84
  60. package/dist/src/generated/stock-binding-operations.js +2779 -173
  61. package/dist/src/generated/stock-observation-operations.js +1274 -91
  62. package/dist/src/generated/tracking-quality-operations.js +407 -42
  63. package/dist/src/generated/trip-utilization-operations.js +1765 -138
  64. package/dist/src/generated/wspace-operations.js +428 -706
  65. package/dist/utils/driverLicenseExpiry.js +14 -0
  66. package/dist/utils/freightAcknowledgement.js +6 -5
  67. package/dist/utils/freightCommercial.js +194 -0
  68. package/dist/utils/freightRecovery.js +22 -22
  69. package/dist/utils/invoiceComparison.js +272 -0
  70. package/package.json +30 -29
  71. package/src/generated/consolidation-operations.ts +60 -559
  72. package/src/generated/container-condition-operations.ts +63 -265
  73. package/src/generated/container-operations.ts +37 -132
  74. package/src/generated/empty-reuse-operations.ts +83 -824
  75. package/src/generated/free-time-operations.ts +55 -284
  76. package/src/generated/freight-cost-operations.ts +373 -349
  77. package/src/generated/freight-invoice-operations.ts +830 -0
  78. package/src/generated/logistics-procedure-operations.ts +60 -414
  79. package/src/generated/pending-pick-operations.ts +48 -1239
  80. package/src/generated/shipment-status-authority-operations.ts +33 -113
  81. package/src/generated/stock-binding-operations.ts +29 -198
  82. package/src/generated/stock-observation-operations.ts +24 -111
  83. package/src/generated/tracking-quality-operations.ts +19 -57
  84. package/src/generated/trip-utilization-operations.ts +32 -166
  85. package/src/generated/wspace-operations.ts +284 -2906
  86. package/src/generated/wspace-types.ts +2 -8
  87. package/src/movethewheels/MoveTheWheelsRoot.tsx +6 -0
  88. package/src/movethewheels/MoveTheWheelsRoutes.tsx +2 -0
  89. package/src/movethewheels/components/ContainerEvidencePicker.tsx +12 -4
  90. package/src/movethewheels/components/FleetAlertsPanel.tsx +4 -2
  91. package/src/movethewheels/components/freight-cost/FreightCommercialEditor.tsx +236 -0
  92. package/src/movethewheels/components/freight-cost/FreightCommercialFactEditor.tsx +258 -0
  93. package/src/movethewheels/components/freight-cost/FreightCommercialHistory.tsx +90 -0
  94. package/src/movethewheels/components/freight-cost/FreightDraftForm.tsx +33 -4
  95. package/src/movethewheels/components/freight-cost/FreightHistory.tsx +4 -2
  96. package/src/movethewheels/components/freight-invoice/InvoiceForm.tsx +412 -0
  97. package/src/movethewheels/components/freight-invoice/InvoiceResults.tsx +162 -0
  98. package/src/movethewheels/hooks/useFleet.ts +1 -1
  99. package/src/movethewheels/hooks/useFleetIntelligence.ts +5 -1
  100. package/src/movethewheels/hooks/useFreightRecoveryAction.ts +2 -1
  101. package/src/movethewheels/hooks/useInvoiceComparisonRecovery.ts +227 -0
  102. package/src/movethewheels/pages/DriverDetailsPage.tsx +35 -9
  103. package/src/movethewheels/pages/FreightEstimatePage.tsx +15 -7
  104. package/src/movethewheels/pages/FreightInvoicePage.tsx +477 -0
  105. package/src/movethewheels/utils/driverLicenseExpiry.ts +25 -0
  106. package/src/movethewheels/utils/freightAcknowledgement.ts +3 -1
  107. package/src/movethewheels/utils/freightCommercial.ts +388 -0
  108. package/src/movethewheels/utils/freightRecovery.ts +6 -2
  109. package/src/movethewheels/utils/invoiceComparison.ts +520 -0
  110. package/src/operations/freight-cost/commercial.graphql +483 -0
  111. package/src/operations/freight-invoice/comparison.graphql +40 -0
  112. package/src/operations/wspace/freight-invoice-evidence.graphql +6 -0
  113. package/patches/braces@3.0.3.patch +0 -87
@@ -0,0 +1,14 @@
1
+ //#region src/movethewheels/utils/driverLicenseExpiry.ts
2
+ var e = (e) => e ? e.toISOString().slice(0, -1) : "", t = (e) => {
3
+ if (e === "") return null;
4
+ let t = /^(\d{4}-\d\d-\d\dT\d\d:\d\d)(?::(\d\d)(?:\.(\d{1,3}))?)?$/.exec(e);
5
+ if (!t) throw Error("Enter a valid licence expiry date and time in UTC.");
6
+ let n = `${t[1]}:${t[2] ?? "00"}.${(t[3] ?? "").padEnd(3, "0")}Z`, r = new Date(n);
7
+ if (!Number.isFinite(r.getTime()) || r.toISOString() !== n) throw Error("Enter a valid licence expiry date and time in UTC.");
8
+ return n;
9
+ }, n = (e, n) => {
10
+ let r = t(e);
11
+ return r === (n?.toISOString() ?? null) ? void 0 : r;
12
+ };
13
+ //#endregion
14
+ export { e as driverLicenseExpiryInput, n as driverLicenseExpiryUpdate, t as parseDriverLicenseExpiry };
@@ -1,8 +1,9 @@
1
+ import { matchesCommercialCapture as e } from "./freightCommercial.js";
1
2
  //#region src/movethewheels/utils/freightAcknowledgement.ts
2
- function e(e, t) {
3
- if (typeof e != "object" || !e || !("saveMtwFreightEstimate" in e) || typeof e.saveMtwFreightEstimate != "object" || e.saveMtwFreightEstimate === null) return !1;
4
- let n = e.saveMtwFreightEstimate;
5
- return "id" in n && typeof n.id == "string" && n.id.trim().length > 0 && "shipmentId" in n && n.shipmentId === t.shipmentId && "estimateReference" in n && n.estimateReference === t.estimateReference && "version" in n && Number.isInteger(t.expectedVersion) && typeof t.expectedVersion == "number" && t.expectedVersion >= 0 && n.version === t.expectedVersion + 1 && "previousVersionId" in n && n.previousVersionId === t.expectedPreviousVersionId;
3
+ function t(t, n) {
4
+ if (typeof t != "object" || !t || !("saveMtwFreightEstimate" in t) || typeof t.saveMtwFreightEstimate != "object" || t.saveMtwFreightEstimate === null) return !1;
5
+ let r = t.saveMtwFreightEstimate;
6
+ return "id" in r && typeof r.id == "string" && r.id.trim().length > 0 && "shipmentId" in r && r.shipmentId === n.shipmentId && "estimateReference" in r && r.estimateReference === n.estimateReference && "version" in r && Number.isInteger(n.expectedVersion) && typeof n.expectedVersion == "number" && n.expectedVersion >= 0 && r.version === n.expectedVersion + 1 && "previousVersionId" in r && r.previousVersionId === n.expectedPreviousVersionId && (n.commercialCapture == null || e(r, n));
6
7
  }
7
8
  //#endregion
8
- export { e as matchesFreightAcknowledgement };
9
+ export { t as matchesFreightAcknowledgement };
@@ -0,0 +1,194 @@
1
+ //#region src/movethewheels/utils/freightCommercial.ts
2
+ var e = [
3
+ "origin",
4
+ "destination",
5
+ "carrier",
6
+ "service",
7
+ "cargo",
8
+ "weight",
9
+ "volume",
10
+ "equipment"
11
+ ], t = "Not recorded for this cost version";
12
+ function n() {
13
+ return {
14
+ facts: i(),
15
+ selectedLegs: [],
16
+ reviewed: null
17
+ };
18
+ }
19
+ function r(e = "UNKNOWN") {
20
+ return {
21
+ status: e,
22
+ reason: e === "UNKNOWN" ? t : "",
23
+ label: "",
24
+ reference: "",
25
+ description: "",
26
+ kind: "",
27
+ jurisdiction: "",
28
+ amount: "",
29
+ unit: "",
30
+ zeroReason: "",
31
+ count: "",
32
+ sourceReference: "",
33
+ sourceRevision: "",
34
+ observedAt: "",
35
+ evidenceLinks: []
36
+ };
37
+ }
38
+ function i() {
39
+ return {
40
+ origin: r(),
41
+ destination: r(),
42
+ carrier: r(),
43
+ service: r(),
44
+ cargo: r(),
45
+ weight: r(),
46
+ volume: r(),
47
+ equipment: r()
48
+ };
49
+ }
50
+ function a(e, t, n) {
51
+ let r = e.trim();
52
+ if (!r || r.length > t) throw Error(`${n}: enter 1–${t} characters.`);
53
+ return r;
54
+ }
55
+ function o(e) {
56
+ if (!/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(e) || new Date(e).toISOString() !== e || Date.parse(e) > Date.now()) throw Error("Use a valid observed time no later than now.");
57
+ return e;
58
+ }
59
+ function s(e, t) {
60
+ if (!/^(0|[1-9][0-9]{0,17})(\.[0-9]{0,5}[1-9])?$/.test(e)) throw Error("Use a canonical nonnegative decimal: up to 18 integer and 6 fractional digits, no exponent or trailing fractional zero.");
61
+ if (e === "0") return a(t, 255, "Recorded zero reason");
62
+ if (t.trim()) throw Error("A zero reason belongs only to an amount of zero.");
63
+ return null;
64
+ }
65
+ function c(e, t) {
66
+ let n = e.evidenceLinks;
67
+ if (n.length < 1 || n.length > 2 || new Set(n.map((e) => JSON.stringify([e.fileId, e.versionId]))).size !== n.length || n.some((e) => !t.some((t) => t.fileId === e.fileId && t.versionId === e.versionId))) throw Error("Choose 1–2 distinct exact evidence versions already selected for this cost record.");
68
+ return {
69
+ sourceReference: a(e.sourceReference, 255, "Fact source"),
70
+ sourceRevision: a(e.sourceRevision, 255, "Fact source revision"),
71
+ observedAt: e.observedAt ? o(e.observedAt) : null,
72
+ evidenceLinks: [...n].sort((e, t) => JSON.stringify([e.fileId, e.versionId]) < JSON.stringify([t.fileId, t.versionId]) ? -1 : +(JSON.stringify([e.fileId, e.versionId]) > JSON.stringify([t.fileId, t.versionId]))).map((e) => ({ ...e }))
73
+ };
74
+ }
75
+ function l(e, t, n) {
76
+ let r = (t) => {
77
+ let r = e[t];
78
+ if (r.status === "UNKNOWN") return {
79
+ status: r.status,
80
+ value: null,
81
+ reason: a(r.reason, 255, t),
82
+ provenance: null
83
+ };
84
+ if (r.status !== "SOURCED" && r.status !== "NOT_APPLICABLE") throw Error("Choose a supported commercial fact status.");
85
+ return {
86
+ status: r.status,
87
+ value: null,
88
+ reason: r.status === "NOT_APPLICABLE" ? a(r.reason, 255, t) : null,
89
+ provenance: c(r, n)
90
+ };
91
+ }, i = (t) => {
92
+ let n = r(t), i = e[t];
93
+ if (n.status !== "SOURCED") return n;
94
+ if (i.kind !== "ADDRESS_LABEL" && i.kind !== "PORT_LABEL" && i.kind !== "TERMINAL_LABEL" && i.kind !== "POSTCODE_LABEL" && i.kind !== "CUSTOM_LABEL") throw Error("Choose a location label kind.");
95
+ return {
96
+ ...n,
97
+ value: {
98
+ kind: i.kind,
99
+ label: a(i.label, 255, t),
100
+ jurisdictionLabel: i.jurisdiction.trim() ? a(i.jurisdiction, 120, "Jurisdiction label") : null
101
+ }
102
+ };
103
+ }, o = r("weight"), l = r("volume"), u = r("carrier"), d = r("service"), f = r("cargo"), p = r("equipment"), m = e.weight, h = e.volume;
104
+ if (m.status === "SOURCED" && m.unit !== "KG" && m.unit !== "TONNE" && m.unit !== "LB") throw Error("Choose a recorded weight unit.");
105
+ if (h.status === "SOURCED" && h.unit !== "M3" && h.unit !== "FT3") throw Error("Choose a recorded volume unit.");
106
+ if (e.equipment.status === "SOURCED" && (!/^[1-9][0-9]{0,5}$/.test(e.equipment.count) || Number(e.equipment.count) > 1e5)) throw Error("Equipment count must be an integer from 1 to 100000.");
107
+ if (t.length > 16 || new Set(t.map((e) => e.id)).size !== t.length) throw Error("Select at most 16 distinct reviewed legs.");
108
+ let g = {
109
+ schemaVersion: 1,
110
+ selectedLegs: t.map((e) => ({
111
+ id: a(e.id, 200, "Leg ID"),
112
+ expectedUpdatedAt: e.expectedUpdatedAt
113
+ })).sort((e, t) => e.id < t.id ? -1 : +(e.id > t.id)),
114
+ origin: i("origin"),
115
+ destination: i("destination"),
116
+ carrier: u.status === "SOURCED" ? {
117
+ ...u,
118
+ value: {
119
+ reference: a(e.carrier.reference, 120, "Carrier reference"),
120
+ label: a(e.carrier.label, 255, "Carrier label")
121
+ }
122
+ } : u,
123
+ service: d.status === "SOURCED" ? {
124
+ ...d,
125
+ value: a(e.service.label, 120, "Service")
126
+ } : d,
127
+ cargo: f.status === "SOURCED" ? {
128
+ ...f,
129
+ value: {
130
+ classificationLabel: a(e.cargo.label, 120, "Cargo classification"),
131
+ description: a(e.cargo.description, 500, "Cargo description")
132
+ }
133
+ } : f,
134
+ weight: o.status === "SOURCED" ? {
135
+ ...o,
136
+ value: {
137
+ amount: m.amount,
138
+ unit: m.unit === "KG" ? "KG" : m.unit === "TONNE" ? "TONNE" : "LB",
139
+ zeroReason: s(m.amount, m.zeroReason)
140
+ }
141
+ } : o,
142
+ volume: l.status === "SOURCED" ? {
143
+ ...l,
144
+ value: {
145
+ amount: h.amount,
146
+ unit: h.unit === "M3" ? "M3" : "FT3",
147
+ zeroReason: s(h.amount, h.zeroReason)
148
+ }
149
+ } : l,
150
+ equipment: p.status === "SOURCED" ? {
151
+ ...p,
152
+ value: {
153
+ typeLabel: a(e.equipment.label, 120, "Equipment type"),
154
+ count: Number(e.equipment.count)
155
+ }
156
+ } : p
157
+ };
158
+ if (new TextEncoder().encode(JSON.stringify(g)).byteLength > 32768) throw Error("Commercial capture exceeds 32768 bytes. Shorten facts before saving.");
159
+ return g;
160
+ }
161
+ function u(e) {
162
+ function t(e) {
163
+ return Array.isArray(e) ? e.map(t) : e && typeof e == "object" ? Object.fromEntries(Object.entries(e).filter(([e]) => e !== "__typename").sort(([e], [t]) => e.localeCompare(t)).map(([e, n]) => [e, t(n)])) : e;
164
+ }
165
+ return JSON.stringify(t(e));
166
+ }
167
+ function d(e, t) {
168
+ if (!e || typeof e != "object" || !("commercialCapture" in e) || !e.commercialCapture || typeof e.commercialCapture != "object") return !1;
169
+ let n = e.commercialCapture;
170
+ if (!t.commercialCapture || typeof t.commercialCapture != "object" || !("selectedLegs" in t.commercialCapture) || !Array.isArray(t.commercialCapture.selectedLegs) || !("ownerShipment" in n) || !n.ownerShipment || typeof n.ownerShipment != "object" || !("shipmentId" in n.ownerShipment) || n.ownerShipment.shipmentId !== t.shipmentId || !("updatedAt" in n.ownerShipment) || n.ownerShipment.updatedAt !== t.expectedShipmentUpdatedAt || !("primaryMode" in n.ownerShipment) || typeof n.ownerShipment.primaryMode != "string" || ![
171
+ "AIR",
172
+ "OCEAN",
173
+ "RAIL",
174
+ "ROAD"
175
+ ].includes(n.ownerShipment.primaryMode) || !("ownerLegs" in n) || !Array.isArray(n.ownerLegs) || u(Object.fromEntries(Object.entries(n).filter(([e]) => e !== "ownerShipment" && e !== "ownerLegs"))) !== u(t.commercialCapture)) return !1;
176
+ let r = t.commercialCapture.selectedLegs, i = n.ownerLegs;
177
+ return i.length === r.length && r.every((e) => e && typeof e == "object" && "id" in e && "expectedUpdatedAt" in e && i.some((t) => t && typeof t == "object" && "id" in t && t.id === e.id && "updatedAt" in t && t.updatedAt === e.expectedUpdatedAt && "legNumber" in t && typeof t.legNumber == "number" && Number.isInteger(t.legNumber) && t.legNumber > 0 && "mode" in t && typeof t.mode == "string" && [
178
+ "AIR",
179
+ "OCEAN",
180
+ "RAIL",
181
+ "ROAD"
182
+ ].includes(t.mode) && ["carrierId", "carrierName"].every((e) => e in t && (Reflect.get(t, e) === null || typeof Reflect.get(t, e) == "string")) && [
183
+ "weightKg",
184
+ "volumeCbm",
185
+ "containerCount"
186
+ ].every((e) => e in t && (Reflect.get(t, e) === null || typeof Reflect.get(t, e) == "number" && Number.isFinite(Reflect.get(t, e)))) && "containerType" in t && (t.containerType === null || typeof t.containerType == "string" && [
187
+ "FCL_20FT",
188
+ "FCL_40FT",
189
+ "FCL_40FT_HC",
190
+ "LCL"
191
+ ].includes(t.containerType))));
192
+ }
193
+ //#endregion
194
+ export { u as commercialCanonical, l as commercialCaptureInput, e as commercialSlots, d as matchesCommercialCapture, n as newCommercialEditor, r as newCommercialFact };
@@ -1,36 +1,36 @@
1
- import { SaveFreightCostsDocument as e } from "../src/generated/freight-cost-operations.js";
2
- import { print as t } from "graphql";
1
+ import { SaveFreightCommercialCostsDocument as e, SaveFreightCostsDocument as t } from "../src/generated/freight-cost-operations.js";
2
+ import { print as n } from "graphql";
3
3
  //#region src/movethewheels/utils/freightRecovery.ts
4
- var n = "movethewheels.freight.unresolved.v1";
5
- function r(n) {
6
- if (!n || new TextEncoder().encode(n).byteLength > 2e5) return null;
4
+ var r = "movethewheels.freight.unresolved.v1";
5
+ function i(r) {
6
+ if (!r || new TextEncoder().encode(r).byteLength > 2e5) return null;
7
7
  try {
8
- let r = JSON.parse(n);
9
- if (typeof r != "object" || !r || !("version" in r) || r.version !== 1 || !("scope" in r) || !("input" in r) || !("operation" in r) || r.operation !== t(e) || !("key" in r) || typeof r.key != "string" || !r.key || r.key.length > 200 || !("success" in r) || typeof r.success != "string" || r.success.length > 500 || typeof r.input != "object" || r.input === null || Array.isArray(r.input) || typeof r.scope != "object" || r.scope === null) return null;
10
- let i = r.scope;
11
- return !("actorId" in i) || typeof i.actorId != "string" || !i.actorId || !("workspaceId" in i) || typeof i.workspaceId != "string" || !i.workspaceId || !("tenantId" in i) || typeof i.tenantId != "string" || !("organizationId" in i) || typeof i.organizationId != "string" || !i.organizationId || !("gateway" in i) || typeof i.gateway != "string" || !("projectId" in i) || i.projectId !== null && typeof i.projectId != "string" ? null : {
8
+ let i = JSON.parse(r);
9
+ if (typeof i != "object" || !i || !("version" in i) || i.version !== 1 || !("scope" in i) || !("input" in i) || !("operation" in i) || i.operation !== n(t) && i.operation !== n(e) || !("key" in i) || typeof i.key != "string" || !i.key || i.key.length > 200 || !("success" in i) || typeof i.success != "string" || i.success.length > 500 || typeof i.input != "object" || i.input === null || Array.isArray(i.input) || typeof i.scope != "object" || i.scope === null) return null;
10
+ let a = i.scope;
11
+ return !("actorId" in a) || typeof a.actorId != "string" || !a.actorId || !("workspaceId" in a) || typeof a.workspaceId != "string" || !a.workspaceId || !("tenantId" in a) || typeof a.tenantId != "string" || !("organizationId" in a) || typeof a.organizationId != "string" || !a.organizationId || !("gateway" in a) || typeof a.gateway != "string" || !("projectId" in a) || a.projectId !== null && typeof a.projectId != "string" ? null : {
12
12
  version: 1,
13
13
  scope: {
14
- actorId: i.actorId,
15
- workspaceId: i.workspaceId,
16
- tenantId: i.tenantId,
17
- organizationId: i.organizationId,
18
- gateway: i.gateway,
19
- projectId: i.projectId
14
+ actorId: a.actorId,
15
+ workspaceId: a.workspaceId,
16
+ tenantId: a.tenantId,
17
+ organizationId: a.organizationId,
18
+ gateway: a.gateway,
19
+ projectId: a.projectId
20
20
  },
21
- operation: r.operation,
22
- input: structuredClone(r.input),
23
- key: r.key,
24
- success: r.success
21
+ operation: i.operation,
22
+ input: structuredClone(i.input),
23
+ key: i.key,
24
+ success: i.success
25
25
  };
26
26
  } catch {
27
27
  return null;
28
28
  }
29
29
  }
30
- function i(e) {
30
+ function a(e) {
31
31
  let t = JSON.stringify(e);
32
- if (!r(t)) throw Error("Cannot safely retain this freight request. Nothing was sent.");
32
+ if (!i(t)) throw Error("Cannot safely retain this freight request. Nothing was sent.");
33
33
  return t;
34
34
  }
35
35
  //#endregion
36
- export { n as FREIGHT_RECOVERY_STORAGE, r as decodeFreightRecovery, i as encodeFreightRecovery };
36
+ export { r as FREIGHT_RECOVERY_STORAGE, i as decodeFreightRecovery, a as encodeFreightRecovery };
@@ -0,0 +1,272 @@
1
+ import { freightMoney as e } from "./freightDraft.js";
2
+ //#region src/movethewheels/utils/invoiceComparison.ts
3
+ var t = "movethewheels.freight-invoice.unresolved.v1";
4
+ function n(e) {
5
+ throw Error(e);
6
+ }
7
+ function r(e, t) {
8
+ return (!e || typeof e != "object" || Array.isArray(e) || Object.keys(e).some((e) => !t.includes(e))) && n("Invoice fields are not supported. Nothing was sent."), Object.fromEntries(Object.entries(e));
9
+ }
10
+ function i(e, t) {
11
+ return (typeof e != "string" || !e.trim() || e.trim().length > t) && n("Complete the bounded invoice source fields. Nothing was sent."), e.trim();
12
+ }
13
+ function a(e, t) {
14
+ return e == null || e === "" ? null : i(e, t);
15
+ }
16
+ function o(e, t) {
17
+ return (typeof e != "number" || !Number.isInteger(e) || e < 0 || e > t) && n("Invoice numeric convention is invalid. Nothing was sent."), e;
18
+ }
19
+ function s(e) {
20
+ let t = r(e, ["code", "minorUnitDigits"]), a = i(t.code, 3);
21
+ return /^[A-Z]{3}$/.test(a) || n("Declare an uppercase three-letter invoice currency."), {
22
+ code: a,
23
+ minorUnitDigits: o(t.minorUnitDigits, 4)
24
+ };
25
+ }
26
+ function c(e) {
27
+ if (e === null || typeof e == "string" || typeof e == "boolean" || typeof e == "number" && Number.isFinite(e)) return JSON.stringify(e);
28
+ if (Array.isArray(e)) return "[" + e.map(c).join(",") + "]";
29
+ if (e && typeof e == "object") {
30
+ let t = Object.fromEntries(Object.entries(e)), n = Object.keys(t).filter((e) => t[e] !== void 0);
31
+ return n.sort((e, t) => e < t ? -1 : +(e > t)), "{" + n.map((e) => JSON.stringify(e) + ":" + c(t[e])).join(",") + "}";
32
+ }
33
+ return n("Cannot safely retain this invoice intent. Nothing was sent.");
34
+ }
35
+ function l(e) {
36
+ let t = r(e, [
37
+ "schemaVersion",
38
+ "supplierReference",
39
+ "supplierLabel",
40
+ "invoiceReference",
41
+ "sourceReference",
42
+ "sourceRevision",
43
+ "invoiceDate",
44
+ "currency",
45
+ "rows"
46
+ ]);
47
+ (t.schemaVersion !== 1 || !Array.isArray(t.rows) || t.rows.length < 1 || t.rows.length > 100) && n("Provide 1–100 reported invoice rows.");
48
+ let o = s(t.currency), l = a(t.invoiceDate, 10);
49
+ if (l !== null) {
50
+ let e = /* @__PURE__ */ new Date(l + "T00:00:00.000Z");
51
+ (!/^\d{4}-\d{2}-\d{2}$/.test(l) || l.startsWith("0000") || !Number.isFinite(e.getTime()) || e.toISOString().slice(0, 10) !== l) && n("Invoice date must be an exact source date or left unknown.");
52
+ }
53
+ let u = t.rows.map((e) => {
54
+ let t = r(e, [
55
+ "id",
56
+ "description",
57
+ "estimateLineId",
58
+ "currency",
59
+ "payerReference",
60
+ "payerLabel",
61
+ "quantity",
62
+ "unit",
63
+ "unitRateMajor",
64
+ "amountMinor",
65
+ "zeroReason"
66
+ ]), l = {
67
+ id: i(t.id, 120),
68
+ description: i(t.description, 1e3),
69
+ estimateLineId: a(t.estimateLineId, 120),
70
+ currency: s(t.currency),
71
+ payerReference: a(t.payerReference, 255),
72
+ payerLabel: a(t.payerLabel, 255),
73
+ quantity: a(t.quantity, 40),
74
+ unit: a(t.unit, 255),
75
+ unitRateMajor: a(t.unitRateMajor, 40),
76
+ amountMinor: a(t.amountMinor, 38),
77
+ zeroReason: a(t.zeroReason, 255)
78
+ };
79
+ c(l.currency) !== c(o) && n("Every row must declare the same invoice currency and scale."), l.payerReference === null != (l.payerLabel === null) && n("Supply both payer reference and label, or leave both unknown.");
80
+ for (let e of [l.quantity, l.unitRateMajor]) e !== null && !/^(0|[1-9]\d{0,19})(\.\d{1,18})?$/.test(e) && n("Quantity and rate require nonnegative decimal strings; no credits or exponent notation.");
81
+ return l.amountMinor !== null && !/^(0|[1-9]\d{0,37})$/.test(l.amountMinor) && n("Amount requires a nonnegative integer minor-unit string or unknown."), l.amountMinor === "0" && l.zeroReason === null && n("Record the source reason for an explicit zero charge."), l;
82
+ });
83
+ return u.sort((e, t) => e.id < t.id ? -1 : +(e.id > t.id)), new Set(u.map((e) => e.id)).size !== u.length && n("Invoice row IDs must be unique."), {
84
+ schemaVersion: 1,
85
+ supplierReference: a(t.supplierReference, 255),
86
+ supplierLabel: a(t.supplierLabel, 255),
87
+ invoiceReference: a(t.invoiceReference, 120),
88
+ sourceReference: i(t.sourceReference, 255),
89
+ sourceRevision: i(t.sourceRevision, 255),
90
+ invoiceDate: l,
91
+ currency: o,
92
+ rows: u
93
+ };
94
+ }
95
+ function u(e) {
96
+ let t = r(e, [
97
+ "shipmentId",
98
+ "estimateVersionId",
99
+ "facts",
100
+ "evidence",
101
+ "expectedPreviousComparisonId",
102
+ "expectedRevision",
103
+ "correctionReason",
104
+ "idempotencyKey"
105
+ ]), s = l(t.facts);
106
+ (!s.supplierReference || !s.invoiceReference) && n("Source stable supplier and invoice references before recording."), (!Array.isArray(t.evidence) || t.evidence.length < 1 || t.evidence.length > 10) && n("Select 1–10 current exact evidence versions.");
107
+ let u = t.evidence.map((e) => {
108
+ let t = r(e, ["fileId", "versionId"]);
109
+ return {
110
+ fileId: i(t.fileId, 255),
111
+ versionId: i(t.versionId, 255)
112
+ };
113
+ });
114
+ u.sort((e, t) => {
115
+ let n = JSON.stringify([e.fileId, e.versionId]), r = JSON.stringify([t.fileId, t.versionId]);
116
+ return n < r ? -1 : +(n > r);
117
+ }), new Set(u.map((e) => e.versionId)).size !== u.length && n("Select distinct exact evidence versions.");
118
+ let d = o(t.expectedRevision, 2147483646), f = a(t.expectedPreviousComparisonId, 255), p = a(t.correctionReason, 1e3);
119
+ (d === 0 != (f === null) || d === 0 != (p === null)) && n("A correction needs the exact previous revision and a reason.");
120
+ let m = {
121
+ shipmentId: i(t.shipmentId, 255),
122
+ estimateVersionId: i(t.estimateVersionId, 255),
123
+ facts: s,
124
+ evidence: u,
125
+ expectedPreviousComparisonId: f,
126
+ expectedRevision: d,
127
+ correctionReason: p,
128
+ idempotencyKey: i(t.idempotencyKey, 120)
129
+ };
130
+ return new TextEncoder().encode(c(m)).byteLength > 131072 && n("This normalized invoice request exceeds 131072 bytes."), m;
131
+ }
132
+ function d(e, t) {
133
+ return t !== null && c(e) === c(t);
134
+ }
135
+ function f(e) {
136
+ if (!e || new TextEncoder().encode(e).byteLength > 2e5) return null;
137
+ try {
138
+ let t = r(JSON.parse(e), [
139
+ "version",
140
+ "scope",
141
+ "input",
142
+ "estimate"
143
+ ]);
144
+ if (t.version !== 1) return null;
145
+ let n = r(t.scope, [
146
+ "actorId",
147
+ "workspaceId",
148
+ "tenantId",
149
+ "organizationId",
150
+ "projectId",
151
+ "gateway"
152
+ ]), s = {
153
+ actorId: i(n.actorId, 255),
154
+ workspaceId: i(n.workspaceId, 255),
155
+ tenantId: a(n.tenantId, 255),
156
+ organizationId: i(n.organizationId, 255),
157
+ projectId: a(n.projectId, 255),
158
+ gateway: i(n.gateway, 2048)
159
+ }, c = u(t.input), l = r(t.estimate, [
160
+ "id",
161
+ "estimateReference",
162
+ "version",
163
+ "kind",
164
+ "sourceReference",
165
+ "sourceRevision",
166
+ "quotedAt",
167
+ "validFrom",
168
+ "validUntil",
169
+ "acceptance"
170
+ ]);
171
+ if (l.kind !== "ESTIMATE" && l.kind !== "QUOTE" || l.acceptance !== "NOT_ESTABLISHED" || l.id !== c.estimateVersionId) return null;
172
+ let d = o(l.version, 2147483647);
173
+ return d < 1 ? null : {
174
+ version: 1,
175
+ scope: s,
176
+ input: c,
177
+ estimate: {
178
+ id: i(l.id, 255),
179
+ estimateReference: i(l.estimateReference, 120),
180
+ version: d,
181
+ kind: l.kind,
182
+ sourceReference: i(l.sourceReference, 255),
183
+ sourceRevision: i(l.sourceRevision, 255),
184
+ quotedAt: a(l.quotedAt, 32),
185
+ validFrom: a(l.validFrom, 32),
186
+ validUntil: a(l.validUntil, 32),
187
+ acceptance: l.acceptance
188
+ }
189
+ };
190
+ } catch {
191
+ return null;
192
+ }
193
+ }
194
+ function p(e) {
195
+ let t = JSON.stringify(e);
196
+ return f(t) || n("Cannot retain the original invoice intent. Nothing was sent."), t;
197
+ }
198
+ function m(e) {
199
+ return typeof e == "string" && Number.isFinite(new Date(e).getTime()) && new Date(e).toISOString() === e;
200
+ }
201
+ var h = new Set([
202
+ "MATCHED",
203
+ "RATE_CHANGED",
204
+ "QUANTITY_CHANGED",
205
+ "AMOUNT_CHANGED",
206
+ "CURRENCY_CHANGED",
207
+ "PAYER_CHANGED",
208
+ "UNMATCHED_INVOICE_LINE",
209
+ "MISSING_EXPECTED_LINE",
210
+ "DUPLICATE_MATCH",
211
+ "EXCLUDED_CHARGE_APPEARED",
212
+ "UNKNOWN_COMPARISON"
213
+ ]), g = new Set([
214
+ "MISSING_AMOUNT",
215
+ "MISSING_PAYER",
216
+ "MISSING_UNIT",
217
+ "UNIT_MISMATCH",
218
+ "MISSING_QUANTITY",
219
+ "MISSING_RATE",
220
+ "SCALE_MISMATCH",
221
+ "UNKNOWN_BASIS",
222
+ "UNKNOWN_DISPOSITION",
223
+ "INCLUDED_CHILD_BILLED_SEPARATELY",
224
+ "UNKNOWN_EXPECTED_CHARGE_COVERAGE"
225
+ ]);
226
+ function _(e, t, n = !1) {
227
+ return Array.isArray(e) && e.length <= t.size && (!n || e.length > 0) && e.every((e) => typeof e == "string" && t.has(e)) && new Set(e).size === e.length;
228
+ }
229
+ function v(e, t) {
230
+ let n = e.outcome;
231
+ if (!n || typeof n.allLinesMatched != "boolean" || !_(n.flags, h, !0) || !Array.isArray(n.rows) || n.rows.length !== t.length || new Set(n.rows.map((e) => e.invoiceLineId)).size !== t.length || !Array.isArray(n.missingExpectedLineIds) || n.missingExpectedLineIds.length > 100 || n.missingExpectedLineIds.some((e) => typeof e != "string" || !e || e.length > 120) || new Set(n.missingExpectedLineIds).size !== n.missingExpectedLineIds.length || !Array.isArray(n.unknownExpectedCoverage) || n.unknownExpectedCoverage.length > 100 || n.rows.some((e) => !t.some((t) => t.id === e.invoiceLineId && (t.estimateLineId ?? null) === e.estimateLineId) || !_(e.flags, h, !0) || !_(e.reasons, g) || e.deltaMinor !== null && (typeof e.deltaMinor != "string" || !/^(-?[1-9]\d{0,39}|0)$/.test(e.deltaMinor))) || n.unknownExpectedCoverage.some((e) => typeof e.estimateLineId != "string" || !e.estimateLineId || e.estimateLineId.length > 120 || e.flag !== "UNKNOWN_COMPARISON" || e.reason !== "UNKNOWN_EXPECTED_CHARGE_COVERAGE") || n.allLinesMatched && (n.flags.length !== 1 || n.flags[0] !== "MATCHED" || n.missingExpectedLineIds.length > 0 || n.unknownExpectedCoverage.length > 0 || n.rows.some((e) => e.flags.length !== 1 || e.flags[0] !== "MATCHED")) || !Array.isArray(n.comparableSubtotals) || n.comparableSubtotals.length > 100) return !1;
232
+ let r = [];
233
+ for (let e of n.comparableSubtotals) {
234
+ s(e.currency), i(e.payerReference, 255);
235
+ for (let t of [e.estimateMinor, e.invoiceMinor]) if (typeof t != "string" || !/^(0|[1-9]\d{0,39})$/.test(t)) return !1;
236
+ if (typeof e.deltaMinor != "string" || !/^(-?[1-9]\d{0,39}|0)$/.test(e.deltaMinor) || !Array.isArray(e.invoiceLineIds) || !e.invoiceLineIds.length || e.invoiceLineIds.some((e) => !t.some((t) => t.id === e))) return !1;
237
+ r.push(...e.invoiceLineIds);
238
+ }
239
+ if (new Set(r).size !== r.length) return !1;
240
+ for (let t of [e.estimateDeclaredSubtotals, e.invoiceDeclaredSubtotals]) {
241
+ if (!Array.isArray(t) || t.length > 100) return !1;
242
+ for (let e of t) if (s(e.currency), a(e.payerReference, 255), a(e.payerLabel, 255), typeof e.knownAmountMinor != "string" || !/^(0|[1-9]\d{0,39})$/.test(e.knownAmountMinor) || e.totalAmountMinor !== null && (typeof e.totalAmountMinor != "string" || !/^(0|[1-9]\d{0,39})$/.test(e.totalAmountMinor))) return !1;
243
+ }
244
+ return !0;
245
+ }
246
+ function y(e, t) {
247
+ try {
248
+ if (!e || typeof e.id != "string" || !/^([a-f0-9]{8}-){1}[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(e.id) || typeof e.invoiceIdentityId != "string" || !e.invoiceIdentityId || e.invoiceIdentityId.length > 255 || e.invoiceIdentityId !== e.invoiceIdentityId.trim() || e.shipmentId !== t.input.shipmentId || e.idempotencyKey !== t.input.idempotencyKey || typeof e.requestFingerprint != "string" || !/^([a-f0-9]{64})$/.test(e.requestFingerprint) || e.methodVersion !== 1 || e.revision !== t.input.expectedRevision + 1 || e.previousComparisonId !== (t.input.expectedPreviousComparisonId ?? null) || e.correctionReason !== (t.input.correctionReason ?? null) || e.createdBy !== t.scope.actorId || e.actorProvenance !== "direct_human" || e.onBehalfOf !== null && e.onBehalfOf !== t.scope.actorId || !m(e.recordedAt) || c(e.estimate) !== c(t.estimate) || c(l(e.facts)) !== c(t.input.facts) || !v(e, t.input.facts.rows)) return !1;
249
+ let n = t.input.evidence.map((e) => JSON.stringify([e.fileId, e.versionId])), r = e.evidence.map((e) => JSON.stringify([e.fileId, e.versionId]));
250
+ return r.length !== n.length || new Set(r).size !== r.length || r.some((e, t) => e !== n[t]) ? !1 : e.evidence.every((t) => typeof t.sha256Hash == "string" && /^[a-f0-9]{64}$/.test(t.sha256Hash) && m(t.checkedAt) && new Date(t.checkedAt) <= new Date(e.recordedAt) && new Date(e.recordedAt).getTime() - new Date(t.checkedAt).getTime() <= 6e4);
251
+ } catch {
252
+ return !1;
253
+ }
254
+ }
255
+ function b(e, t, n) {
256
+ try {
257
+ return !!e && e.methodVersion === 1 && typeof e.recordable == "boolean" && Array.isArray(e.blockers) && e.blockers.length <= 4 && e.recordable === (e.blockers.length === 0) && e.blockers.every((e) => e === "SUPPLIER_UNKNOWN" || e === "INVOICE_REFERENCE_UNKNOWN" || e === "EVIDENCE_REQUIRED" || e === "SHIPMENT_NOT_LIVE") && c(e.estimate) === c(n) && c(l(e.facts)) === c(l(t)) && v(e, t.rows);
258
+ } catch {
259
+ return !1;
260
+ }
261
+ }
262
+ function x(t, n) {
263
+ if (t == null) return "Unknown";
264
+ let r = t.startsWith("-");
265
+ return `${n.code} ${r ? "-" : ""}${e(r ? t.slice(1) : t, n.minorUnitDigits)}`;
266
+ }
267
+ function S(e, t) {
268
+ let n = e.facts.rows.find((e) => e.id === t), r = e.outcome.rows.find((e) => e.invoiceLineId === t), i = e.outcome.comparableSubtotals.find((e) => e.invoiceLineIds.includes(t));
269
+ return !n || !r || r.deltaMinor === null || !i || n.currency.code !== i.currency.code || n.currency.minorUnitDigits !== i.currency.minorUnitDigits || n.payerReference !== i.payerReference ? "Not comparable" : x(r.deltaMinor, n.currency);
270
+ }
271
+ //#endregion
272
+ export { t as INVOICE_RECOVERY_STORAGE, f as decodeInvoiceIntent, p as encodeInvoiceIntent, c as invoiceCanonical, l as invoiceFactsInput, x as invoiceMoney, u as invoiceRecordInput, S as invoiceRowDifference, b as matchesInvoicePreview, y as matchesInvoiceReceipt, d as sameInvoiceScope };