@burdenoff/microfe-movethewheels 2026.930.5 → 2026.1010.1

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 (373) hide show
  1. package/dist/MoveTheWheelsRoot.js +177 -102
  2. package/dist/MoveTheWheelsRoutes.js +55 -11
  3. package/dist/_virtual/_rolldown/runtime.js +1 -1
  4. package/dist/components/ContainerEvidencePicker.js +143 -0
  5. package/dist/components/FreeTimeAgreementForm.js +496 -0
  6. package/dist/components/ReturnInstructionForm.js +108 -0
  7. package/dist/components/ReuseControls.js +91 -0
  8. package/dist/components/ReusePermissionForm.js +114 -0
  9. package/dist/components/ReuseProposalForm.js +455 -0
  10. package/dist/components/ReuseSourceFields.js +78 -0
  11. package/dist/components/consolidation/ConsolidationHistory.js +244 -0
  12. package/dist/components/consolidation/ConsolidationLotEditor.js +133 -0
  13. package/dist/components/consolidation/ConsolidationManifestWorkbench.js +143 -0
  14. package/dist/components/consolidation/ConsolidationPlanForm.js +172 -0
  15. package/dist/components/consolidation/ConsolidationPlanWorkbench.js +321 -0
  16. package/dist/components/consolidation/ConsolidationReportForm.js +94 -0
  17. package/dist/components/consolidation/ConsolidationReportsWorkbench.js +195 -0
  18. package/dist/components/consolidation/ConsolidationSummary.js +76 -0
  19. package/dist/components/consolidation/OriginalConsolidationHistory.js +112 -0
  20. package/dist/components/freight-cost/FreightDraftForm.js +213 -0
  21. package/dist/components/freight-cost/FreightFields.js +70 -0
  22. package/dist/components/freight-cost/FreightFxEditor.js +90 -0
  23. package/dist/components/freight-cost/FreightHistory.js +164 -0
  24. package/dist/components/freight-cost/FreightLineEditor.js +191 -0
  25. package/dist/components/freight-cost/FreightScopeEditor.js +72 -0
  26. package/dist/components/freight-cost/FreightTotals.js +66 -0
  27. package/dist/components/logistics-procedure/ProcedureDecisionForm.js +197 -0
  28. package/dist/components/logistics-procedure/ProcedureFields.js +31 -0
  29. package/dist/components/logistics-procedure/ProcedureHistory.js +177 -0
  30. package/dist/components/logistics-procedure/ProcedurePolicyForm.js +227 -0
  31. package/dist/components/logistics-procedure/ProcedurePolicyWorkbench.js +155 -0
  32. package/dist/components/logistics-procedure/ProcedureReviewWorkbench.js +221 -0
  33. package/dist/components/logistics-procedure/ProcedureRunWorkbench.js +190 -0
  34. package/dist/components/logistics-procedure/ProcedureSubjectPicker.js +130 -0
  35. package/dist/components/pending-pick/PendingPickDraft.js +84 -0
  36. package/dist/components/pending-pick/PendingPickHistory.js +113 -0
  37. package/dist/components/pending-pick/PickCapture.js +166 -0
  38. package/dist/components/pending-pick/PickLineSelection.js +111 -0
  39. package/dist/components/stock-binding/StockAssessmentDraft.js +48 -0
  40. package/dist/components/stock-binding/StockAssessmentHistory.js +61 -0
  41. package/dist/components/stock-binding/StockAssessmentSummary.js +199 -0
  42. package/dist/components/stock-binding/StockFactForm.js +232 -0
  43. package/dist/components/stock-observation/StockIssueForm.js +148 -0
  44. package/dist/components/stock-observation/StockIssueHistory.js +116 -0
  45. package/dist/components/stock-observation/StockIssueReadPanel.js +70 -0
  46. package/dist/components/trip-utilization/TripReportForm.js +118 -0
  47. package/dist/components/trip-utilization/TripReportHistory.js +54 -0
  48. package/dist/components/trip-utilization/TripReportSummary.js +216 -0
  49. package/dist/components/trip-utilization/TripSegmentFields.js +166 -0
  50. package/dist/generated/consolidation-operations.d.ts +1060 -0
  51. package/dist/generated/container-condition-operations.d.ts +868 -0
  52. package/dist/generated/container-operations.d.ts +356 -0
  53. package/dist/generated/empty-reuse-operations.d.ts +1578 -0
  54. package/dist/generated/free-time-operations.d.ts +938 -0
  55. package/dist/generated/freight-cost-operations.d.ts +716 -0
  56. package/dist/generated/logistics-procedure-operations.d.ts +938 -0
  57. package/dist/generated/pending-pick-operations.d.ts +1969 -0
  58. package/dist/generated/stock-binding-operations.d.ts +930 -0
  59. package/dist/generated/stock-observation-operations.d.ts +476 -0
  60. package/dist/generated/trip-utilization-operations.d.ts +651 -0
  61. package/dist/generated/wspace-operations.d.ts +143 -50
  62. package/dist/hooks/useConsolidationAction.js +119 -0
  63. package/dist/hooks/useContainerCondition.js +105 -0
  64. package/dist/hooks/useContainerLifecycle.js +192 -0
  65. package/dist/hooks/useEmptyReuseAction.js +45 -0
  66. package/dist/hooks/useFreightRecoveryAction.js +117 -0
  67. package/dist/hooks/useProcedureAction.js +119 -0
  68. package/dist/hooks/useProcedureSelection.js +53 -0
  69. package/dist/hooks/useReuseRecoveryAction.js +116 -0
  70. package/dist/movethewheels/components/ContainerEvidencePicker.d.ts +10 -0
  71. package/dist/movethewheels/components/FreeTimeAgreementForm.d.ts +14 -0
  72. package/dist/movethewheels/components/ReturnInstructionForm.d.ts +8 -0
  73. package/dist/movethewheels/components/ReuseControls.d.ts +42 -0
  74. package/dist/movethewheels/components/ReusePermissionForm.d.ts +9 -0
  75. package/dist/movethewheels/components/ReuseProposalForm.d.ts +11 -0
  76. package/dist/movethewheels/components/ReuseSourceFields.d.ts +9 -0
  77. package/dist/movethewheels/components/consolidation/ConsolidationHistory.d.ts +13 -0
  78. package/dist/movethewheels/components/consolidation/ConsolidationLotEditor.d.ts +6 -0
  79. package/dist/movethewheels/components/consolidation/ConsolidationManifestWorkbench.d.ts +8 -0
  80. package/dist/movethewheels/components/consolidation/ConsolidationPlanForm.d.ts +8 -0
  81. package/dist/movethewheels/components/consolidation/ConsolidationPlanWorkbench.d.ts +5 -0
  82. package/dist/movethewheels/components/consolidation/ConsolidationReportForm.d.ts +9 -0
  83. package/dist/movethewheels/components/consolidation/ConsolidationReportsWorkbench.d.ts +7 -0
  84. package/dist/movethewheels/components/consolidation/ConsolidationSummary.d.ts +6 -0
  85. package/dist/movethewheels/components/consolidation/OriginalConsolidationHistory.d.ts +8 -0
  86. package/dist/movethewheels/components/freight-cost/FreightDraftForm.d.ts +8 -0
  87. package/dist/movethewheels/components/freight-cost/FreightFields.d.ts +23 -0
  88. package/dist/movethewheels/components/freight-cost/FreightFxEditor.d.ts +6 -0
  89. package/dist/movethewheels/components/freight-cost/FreightHistory.d.ts +5 -0
  90. package/dist/movethewheels/components/freight-cost/FreightLineEditor.d.ts +8 -0
  91. package/dist/movethewheels/components/freight-cost/FreightScopeEditor.d.ts +6 -0
  92. package/dist/movethewheels/components/freight-cost/FreightTotals.d.ts +6 -0
  93. package/dist/movethewheels/components/logistics-procedure/ProcedureDecisionForm.d.ts +20 -0
  94. package/dist/movethewheels/components/logistics-procedure/ProcedureFields.d.ts +17 -0
  95. package/dist/movethewheels/components/logistics-procedure/ProcedureHistory.d.ts +7 -0
  96. package/dist/movethewheels/components/logistics-procedure/ProcedurePolicyForm.d.ts +10 -0
  97. package/dist/movethewheels/components/logistics-procedure/ProcedurePolicyWorkbench.d.ts +5 -0
  98. package/dist/movethewheels/components/logistics-procedure/ProcedureReviewWorkbench.d.ts +5 -0
  99. package/dist/movethewheels/components/logistics-procedure/ProcedureRunWorkbench.d.ts +6 -0
  100. package/dist/movethewheels/components/logistics-procedure/ProcedureSubjectPicker.d.ts +7 -0
  101. package/dist/movethewheels/components/pending-pick/PendingPickDraft.d.ts +16 -0
  102. package/dist/movethewheels/components/pending-pick/PendingPickHistory.d.ts +5 -0
  103. package/dist/movethewheels/components/pending-pick/PickCapture.d.ts +6 -0
  104. package/dist/movethewheels/components/pending-pick/PickLineSelection.d.ts +17 -0
  105. package/dist/movethewheels/components/stock-binding/StockAssessmentDraft.d.ts +13 -0
  106. package/dist/movethewheels/components/stock-binding/StockAssessmentHistory.d.ts +18 -0
  107. package/dist/movethewheels/components/stock-binding/StockAssessmentSummary.d.ts +9 -0
  108. package/dist/movethewheels/components/stock-binding/StockFactForm.d.ts +6 -0
  109. package/dist/movethewheels/components/stock-observation/StockIssueForm.d.ts +7 -0
  110. package/dist/movethewheels/components/stock-observation/StockIssueHistory.d.ts +7 -0
  111. package/dist/movethewheels/components/stock-observation/StockIssueReadPanel.d.ts +5 -0
  112. package/dist/movethewheels/components/trip-utilization/TripReportForm.d.ts +6 -0
  113. package/dist/movethewheels/components/trip-utilization/TripReportHistory.d.ts +14 -0
  114. package/dist/movethewheels/components/trip-utilization/TripReportSummary.d.ts +5 -0
  115. package/dist/movethewheels/components/trip-utilization/TripSegmentFields.d.ts +9 -0
  116. package/dist/movethewheels/hooks/useConsolidationAction.d.ts +19 -0
  117. package/dist/movethewheels/hooks/useContainerCondition.d.ts +21 -0
  118. package/dist/movethewheels/hooks/useContainerLifecycle.d.ts +40 -0
  119. package/dist/movethewheels/hooks/useEmptyReuseAction.d.ts +14 -0
  120. package/dist/movethewheels/hooks/useFreightRecoveryAction.d.ts +23 -0
  121. package/dist/movethewheels/hooks/useProcedureAction.d.ts +18 -0
  122. package/dist/movethewheels/hooks/useProcedureSelection.d.ts +51 -0
  123. package/dist/movethewheels/hooks/useReuseRecoveryAction.d.ts +18 -0
  124. package/dist/movethewheels/pages/ConsolidationPage.d.ts +1 -0
  125. package/dist/movethewheels/pages/ContainerConditionPage.d.ts +1 -0
  126. package/dist/movethewheels/pages/ContainersPage.d.ts +2 -0
  127. package/dist/movethewheels/pages/EmptyReusePage.d.ts +1 -0
  128. package/dist/movethewheels/pages/FreeTimePage.d.ts +1 -0
  129. package/dist/movethewheels/pages/FreightEstimatePage.d.ts +1 -0
  130. package/dist/movethewheels/pages/LogisticsProceduresPage.d.ts +1 -0
  131. package/dist/movethewheels/pages/PendingPickPage.d.ts +1 -0
  132. package/dist/movethewheels/pages/StockBindingPage.d.ts +1 -0
  133. package/dist/movethewheels/pages/StockObservationsPage.d.ts +1 -0
  134. package/dist/movethewheels/pages/TripUtilizationPage.d.ts +1 -0
  135. package/dist/movethewheels/utils/consolidationHistoryTarget.d.ts +12 -0
  136. package/dist/movethewheels/utils/consolidationInput.d.ts +15 -0
  137. package/dist/movethewheels/utils/consolidationLot.d.ts +3 -0
  138. package/dist/movethewheels/utils/consolidationPins.d.ts +20 -0
  139. package/dist/movethewheels/utils/consolidationRecovery.d.ts +5 -0
  140. package/dist/movethewheels/utils/consolidationReportHead.d.ts +5 -0
  141. package/dist/movethewheels/utils/freeTimeDate.d.ts +1 -0
  142. package/dist/movethewheels/utils/freightAcknowledgement.d.ts +2 -0
  143. package/dist/movethewheels/utils/freightDraft.d.ts +36 -0
  144. package/dist/movethewheels/utils/freightRecovery.d.ts +5 -0
  145. package/dist/movethewheels/utils/graphqlClient.d.ts +2 -1
  146. package/dist/movethewheels/utils/pendingPickDraft.d.ts +8 -0
  147. package/dist/movethewheels/utils/procedureInput.d.ts +18 -0
  148. package/dist/movethewheels/utils/procedureRecovery.d.ts +5 -0
  149. package/dist/movethewheels/utils/reuseAttempt.d.ts +7 -0
  150. package/dist/movethewheels/utils/reuseForm.d.ts +6 -0
  151. package/dist/movethewheels/utils/reuseRecovery.d.ts +26 -0
  152. package/dist/movethewheels/utils/stockBindingForm.d.ts +23 -0
  153. package/dist/movethewheels/utils/stockBindingLabels.d.ts +10 -0
  154. package/dist/movethewheels/utils/stockObservationForm.d.ts +5 -0
  155. package/dist/movethewheels/utils/tripDraftContext.d.ts +25 -0
  156. package/dist/movethewheels/utils/tripUtilizationForm.d.ts +6 -0
  157. package/dist/node_modules/@react-leaflet/core/lib/component.js +5 -5
  158. package/dist/node_modules/fast-equals/dist/es/index.js +87 -74
  159. package/dist/node_modules/leaflet/dist/leaflet-src.js +8 -5
  160. package/dist/node_modules/lodash/_Stack.js +2 -1
  161. package/dist/node_modules/lucide-react/dist/esm/icons/clipboard-list.js +35 -0
  162. package/dist/node_modules/lucide-react/dist/esm/icons/repeat-2.js +22 -0
  163. package/dist/node_modules/react-leaflet/lib/MapContainer.js +3 -3
  164. package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
  165. package/dist/node_modules/recharts/es6/cartesian/Area.js +13 -13
  166. package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
  167. package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
  168. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
  169. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +13 -13
  170. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
  171. package/dist/node_modules/recharts/es6/cartesian/Line.js +10 -10
  172. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
  173. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
  174. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
  175. package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
  176. package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
  177. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
  178. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
  179. package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
  180. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
  181. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
  182. package/dist/node_modules/recharts/es6/component/Label.js +14 -14
  183. package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
  184. package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
  185. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
  186. package/dist/node_modules/recharts/es6/component/Text.js +2 -2
  187. package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
  188. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
  189. package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
  190. package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
  191. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
  192. package/dist/node_modules/recharts/es6/polar/Pie.js +13 -13
  193. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js +8 -8
  194. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js +6 -6
  195. package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
  196. package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
  197. package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
  198. package/dist/node_modules/recharts/es6/shape/Polygon.js +4 -4
  199. package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
  200. package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
  201. package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
  202. package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
  203. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
  204. package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
  205. package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
  206. package/dist/node_modules/recharts/es6/util/PolarUtils.js +1 -1
  207. package/dist/node_modules/recharts/es6/util/ReactUtils.js +2 -2
  208. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
  209. package/dist/node_modules/recharts/es6/util/types.js +1 -1
  210. package/dist/node_modules/{react-is → recharts/node_modules/react-is}/cjs/react-is.development.js +2 -2
  211. package/dist/node_modules/{react-is → recharts/node_modules/react-is}/cjs/react-is.production.min.js +2 -2
  212. package/dist/node_modules/{react-is → recharts/node_modules/react-is}/index.js +2 -2
  213. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +97 -18
  214. package/dist/node_modules/zustand/esm/middleware.js +2 -2
  215. package/dist/pages/ConsolidationPage.js +76 -0
  216. package/dist/pages/ContainerConditionPage.js +972 -0
  217. package/dist/pages/ContainersPage.js +522 -0
  218. package/dist/pages/EmptyReusePage.js +777 -0
  219. package/dist/pages/FreeTimePage.js +657 -0
  220. package/dist/pages/FreightEstimatePage.js +284 -0
  221. package/dist/pages/LogisticsProceduresPage.js +100 -0
  222. package/dist/pages/PendingPickPage.js +155 -0
  223. package/dist/pages/StockBindingPage.js +236 -0
  224. package/dist/pages/StockObservationsPage.js +168 -0
  225. package/dist/pages/TripUtilizationPage.js +227 -0
  226. package/dist/src/generated/consolidation-operations.js +505 -0
  227. package/dist/src/generated/container-condition-operations.js +208 -0
  228. package/dist/src/generated/container-operations.js +101 -0
  229. package/dist/src/generated/empty-reuse-operations.js +749 -0
  230. package/dist/src/generated/free-time-operations.js +235 -0
  231. package/dist/src/generated/freight-cost-operations.js +325 -0
  232. package/dist/src/generated/logistics-procedure-operations.js +362 -0
  233. package/dist/src/generated/pending-pick-operations.js +1128 -0
  234. package/dist/src/generated/stock-binding-operations.js +175 -0
  235. package/dist/src/generated/stock-observation-operations.js +93 -0
  236. package/dist/src/generated/trip-utilization-operations.js +140 -0
  237. package/dist/src/generated/wspace-operations.js +708 -0
  238. package/dist/utils/consolidationHistoryTarget.js +27 -0
  239. package/dist/utils/consolidationInput.js +21 -0
  240. package/dist/utils/consolidationLot.js +29 -0
  241. package/dist/utils/consolidationPins.js +13 -0
  242. package/dist/utils/consolidationRecovery.js +40 -0
  243. package/dist/utils/consolidationReportHead.js +18 -0
  244. package/dist/utils/freeTimeDate.js +26 -0
  245. package/dist/utils/freightAcknowledgement.js +8 -0
  246. package/dist/utils/freightDraft.js +125 -0
  247. package/dist/utils/freightRecovery.js +36 -0
  248. package/dist/utils/graphqlClient.js +28 -28
  249. package/dist/utils/pendingPickDraft.js +46 -0
  250. package/dist/utils/procedureInput.js +43 -0
  251. package/dist/utils/procedureRecovery.js +42 -0
  252. package/dist/utils/reuseAttempt.js +20 -0
  253. package/dist/utils/reuseForm.js +25 -0
  254. package/dist/utils/reuseRecovery.js +71 -0
  255. package/dist/utils/stockBindingForm.js +142 -0
  256. package/dist/utils/stockBindingLabels.js +23 -0
  257. package/dist/utils/stockObservationForm.js +55 -0
  258. package/dist/utils/tripDraftContext.js +19 -0
  259. package/dist/utils/tripUtilizationForm.js +60 -0
  260. package/package.json +19 -5
  261. package/src/generated/consolidation-operations.ts +1138 -0
  262. package/src/generated/container-condition-operations.ts +771 -0
  263. package/src/generated/container-operations.ts +376 -0
  264. package/src/generated/empty-reuse-operations.ts +1648 -0
  265. package/src/generated/free-time-operations.ts +814 -0
  266. package/src/generated/freight-cost-operations.ts +753 -0
  267. package/src/generated/logistics-procedure-operations.ts +1047 -0
  268. package/src/generated/pending-pick-operations.ts +1508 -0
  269. package/src/generated/stock-binding-operations.ts +631 -0
  270. package/src/generated/stock-observation-operations.ts +373 -0
  271. package/src/generated/trip-utilization-operations.ts +500 -0
  272. package/src/generated/wspace-operations.ts +116 -0
  273. package/src/movethewheels/MoveTheWheelsRoot.tsx +79 -0
  274. package/src/movethewheels/MoveTheWheelsRoutes.tsx +22 -0
  275. package/src/movethewheels/components/ContainerEvidencePicker.tsx +146 -0
  276. package/src/movethewheels/components/FreeTimeAgreementForm.tsx +483 -0
  277. package/src/movethewheels/components/ReturnInstructionForm.tsx +102 -0
  278. package/src/movethewheels/components/ReuseControls.tsx +138 -0
  279. package/src/movethewheels/components/ReusePermissionForm.tsx +123 -0
  280. package/src/movethewheels/components/ReuseProposalForm.tsx +484 -0
  281. package/src/movethewheels/components/ReuseSourceFields.tsx +80 -0
  282. package/src/movethewheels/components/consolidation/ConsolidationHistory.tsx +159 -0
  283. package/src/movethewheels/components/consolidation/ConsolidationLotEditor.tsx +144 -0
  284. package/src/movethewheels/components/consolidation/ConsolidationManifestWorkbench.tsx +168 -0
  285. package/src/movethewheels/components/consolidation/ConsolidationPlanForm.tsx +185 -0
  286. package/src/movethewheels/components/consolidation/ConsolidationPlanWorkbench.tsx +395 -0
  287. package/src/movethewheels/components/consolidation/ConsolidationReportForm.tsx +124 -0
  288. package/src/movethewheels/components/consolidation/ConsolidationReportsWorkbench.tsx +233 -0
  289. package/src/movethewheels/components/consolidation/ConsolidationSummary.tsx +84 -0
  290. package/src/movethewheels/components/consolidation/OriginalConsolidationHistory.tsx +133 -0
  291. package/src/movethewheels/components/freight-cost/FreightDraftForm.tsx +224 -0
  292. package/src/movethewheels/components/freight-cost/FreightFields.tsx +91 -0
  293. package/src/movethewheels/components/freight-cost/FreightFxEditor.tsx +98 -0
  294. package/src/movethewheels/components/freight-cost/FreightHistory.tsx +91 -0
  295. package/src/movethewheels/components/freight-cost/FreightLineEditor.tsx +192 -0
  296. package/src/movethewheels/components/freight-cost/FreightScopeEditor.tsx +64 -0
  297. package/src/movethewheels/components/freight-cost/FreightTotals.tsx +68 -0
  298. package/src/movethewheels/components/logistics-procedure/ProcedureDecisionForm.tsx +204 -0
  299. package/src/movethewheels/components/logistics-procedure/ProcedureFields.tsx +43 -0
  300. package/src/movethewheels/components/logistics-procedure/ProcedureHistory.tsx +102 -0
  301. package/src/movethewheels/components/logistics-procedure/ProcedurePolicyForm.tsx +226 -0
  302. package/src/movethewheels/components/logistics-procedure/ProcedurePolicyWorkbench.tsx +174 -0
  303. package/src/movethewheels/components/logistics-procedure/ProcedureReviewWorkbench.tsx +278 -0
  304. package/src/movethewheels/components/logistics-procedure/ProcedureRunWorkbench.tsx +292 -0
  305. package/src/movethewheels/components/logistics-procedure/ProcedureSubjectPicker.tsx +111 -0
  306. package/src/movethewheels/components/pending-pick/PendingPickDraft.tsx +82 -0
  307. package/src/movethewheels/components/pending-pick/PendingPickHistory.tsx +93 -0
  308. package/src/movethewheels/components/pending-pick/PickCapture.tsx +70 -0
  309. package/src/movethewheels/components/pending-pick/PickLineSelection.tsx +130 -0
  310. package/src/movethewheels/components/stock-binding/StockAssessmentDraft.tsx +52 -0
  311. package/src/movethewheels/components/stock-binding/StockAssessmentHistory.tsx +56 -0
  312. package/src/movethewheels/components/stock-binding/StockAssessmentSummary.tsx +108 -0
  313. package/src/movethewheels/components/stock-binding/StockFactForm.tsx +186 -0
  314. package/src/movethewheels/components/stock-observation/StockIssueForm.tsx +103 -0
  315. package/src/movethewheels/components/stock-observation/StockIssueHistory.tsx +96 -0
  316. package/src/movethewheels/components/stock-observation/StockIssueReadPanel.tsx +72 -0
  317. package/src/movethewheels/components/trip-utilization/TripReportForm.tsx +116 -0
  318. package/src/movethewheels/components/trip-utilization/TripReportHistory.tsx +51 -0
  319. package/src/movethewheels/components/trip-utilization/TripReportSummary.tsx +127 -0
  320. package/src/movethewheels/components/trip-utilization/TripSegmentFields.tsx +118 -0
  321. package/src/movethewheels/hooks/useConsolidationAction.ts +196 -0
  322. package/src/movethewheels/hooks/useContainerCondition.ts +129 -0
  323. package/src/movethewheels/hooks/useContainerLifecycle.ts +291 -0
  324. package/src/movethewheels/hooks/useEmptyReuseAction.ts +72 -0
  325. package/src/movethewheels/hooks/useFreightRecoveryAction.ts +201 -0
  326. package/src/movethewheels/hooks/useProcedureAction.ts +196 -0
  327. package/src/movethewheels/hooks/useProcedureSelection.ts +75 -0
  328. package/src/movethewheels/hooks/useReuseRecoveryAction.ts +192 -0
  329. package/src/movethewheels/pages/ConsolidationPage.tsx +70 -0
  330. package/src/movethewheels/pages/ContainerConditionPage.tsx +959 -0
  331. package/src/movethewheels/pages/ContainersPage.tsx +490 -0
  332. package/src/movethewheels/pages/EmptyReusePage.tsx +823 -0
  333. package/src/movethewheels/pages/FreeTimePage.tsx +720 -0
  334. package/src/movethewheels/pages/FreightEstimatePage.tsx +353 -0
  335. package/src/movethewheels/pages/LogisticsProceduresPage.tsx +86 -0
  336. package/src/movethewheels/pages/PendingPickPage.tsx +226 -0
  337. package/src/movethewheels/pages/StockBindingPage.tsx +299 -0
  338. package/src/movethewheels/pages/StockObservationsPage.tsx +181 -0
  339. package/src/movethewheels/pages/TripUtilizationPage.tsx +315 -0
  340. package/src/movethewheels/utils/consolidationHistoryTarget.ts +39 -0
  341. package/src/movethewheels/utils/consolidationInput.ts +70 -0
  342. package/src/movethewheels/utils/consolidationLot.ts +24 -0
  343. package/src/movethewheels/utils/consolidationPins.ts +52 -0
  344. package/src/movethewheels/utils/consolidationRecovery.ts +88 -0
  345. package/src/movethewheels/utils/consolidationReportHead.ts +29 -0
  346. package/src/movethewheels/utils/freeTimeDate.ts +31 -0
  347. package/src/movethewheels/utils/freightAcknowledgement.ts +31 -0
  348. package/src/movethewheels/utils/freightDraft.ts +170 -0
  349. package/src/movethewheels/utils/freightRecovery.ts +79 -0
  350. package/src/movethewheels/utils/graphqlClient.ts +14 -5
  351. package/src/movethewheels/utils/pendingPickDraft.ts +61 -0
  352. package/src/movethewheels/utils/procedureInput.ts +98 -0
  353. package/src/movethewheels/utils/procedureRecovery.ts +92 -0
  354. package/src/movethewheels/utils/reuseAttempt.ts +29 -0
  355. package/src/movethewheels/utils/reuseForm.ts +30 -0
  356. package/src/movethewheels/utils/reuseRecovery.ts +151 -0
  357. package/src/movethewheels/utils/stockBindingForm.ts +209 -0
  358. package/src/movethewheels/utils/stockBindingLabels.ts +41 -0
  359. package/src/movethewheels/utils/stockObservationForm.ts +73 -0
  360. package/src/movethewheels/utils/tripDraftContext.ts +61 -0
  361. package/src/movethewheels/utils/tripUtilizationForm.ts +105 -0
  362. package/src/operations/condition/container-condition.graphql +41 -0
  363. package/src/operations/consolidation/consolidation.graphql +490 -0
  364. package/src/operations/container/container-lifecycle.graphql +80 -0
  365. package/src/operations/empty-reuse/empty-reuse.graphql +737 -0
  366. package/src/operations/free-time/free-time.graphql +47 -0
  367. package/src/operations/freight-cost/freight.graphql +6 -0
  368. package/src/operations/logistics-procedure/procedure.graphql +15 -0
  369. package/src/operations/pending-pick/pending-pick.graphql +1122 -0
  370. package/src/operations/stock-binding/stock-binding.graphql +160 -0
  371. package/src/operations/stock-observation/stock-observation.graphql +20 -0
  372. package/src/operations/trip-utilization/trip-utilization.graphql +126 -0
  373. package/src/operations/wspace/container-evidence.graphql +6 -0
@@ -0,0 +1,315 @@
1
+ import { useRef, useState } from 'react';
2
+ import { Gauge } from 'lucide-react';
3
+ import { PageLayout } from '../components/PageLayout';
4
+ import { Button } from '../components/ui';
5
+ import { PinnedSelect, ReusePager, ReuseState, reuseCard } from '../components/ReuseControls';
6
+ import { TripReportForm } from '../components/trip-utilization/TripReportForm';
7
+ import { TripReportHistory } from '../components/trip-utilization/TripReportHistory';
8
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
9
+ import { useConditionApi, useConditionQuery } from '../hooks/useContainerCondition';
10
+ import { useEmptyReuseAction } from '../hooks/useEmptyReuseAction';
11
+ import type { TripReportDraft } from '../utils/tripUtilizationForm';
12
+ import {
13
+ inputForTripDraft,
14
+ tripRouteStillMatches,
15
+ tripContextStillMatches,
16
+ type TripDraftContext,
17
+ } from '../utils/tripDraftContext';
18
+ import {
19
+ UtilizationRoutesDocument,
20
+ UtilizationCurrentRouteDocument,
21
+ UtilizationCurrentVehicleDocument,
22
+ UtilizationReportsDocument,
23
+ RecordUtilizationReportDocument,
24
+ type UtilizationRoutesQuery,
25
+ type UtilizationCurrentRouteQuery,
26
+ type UtilizationCurrentVehicleQuery,
27
+ type UtilizationReportsQuery,
28
+ type UtilizationReportFragment,
29
+ type RecordUtilizationReportMutation,
30
+ } from '../../generated/trip-utilization-operations';
31
+ export default function TripUtilizationPage() {
32
+ const { workspaceId, tenantId, currentUser, apiGatewayUrl } = useMoveTheWheels();
33
+ return (
34
+ <PageLayout
35
+ title="Reported trip utilization"
36
+ subtitle="Measured or estimated segment facts, separate ratios and immutable source history."
37
+ icon={<Gauge aria-hidden="true" />}
38
+ >
39
+ <TripUtilizationWorkbench
40
+ key={`${workspaceId}:${tenantId}:${currentUser?.id}:${apiGatewayUrl}`}
41
+ />
42
+ </PageLayout>
43
+ );
44
+ }
45
+ function TripUtilizationWorkbench() {
46
+ const [routeOffset, setRouteOffset] = useState(0);
47
+ const [reportOffset, setReportOffset] = useState(0);
48
+ const [routeSelection, setRouteSelection] = useState<{ id: string; label: string } | null>(null);
49
+ const [draftContext, setDraftContext] = useState<
50
+ (TripDraftContext & { generation: string }) | null
51
+ >(null);
52
+ const [contextMismatch, setContextMismatch] = useState(false);
53
+ const [selected, setSelected] = useState<UtilizationReportFragment | null>(null);
54
+ const checkingNow = useRef(false);
55
+ const [checking, setChecking] = useState(false);
56
+ const [error, setError] = useState<string | null>(null);
57
+ const actions = useEmptyReuseAction();
58
+ const request = useConditionApi();
59
+ const routes = useConditionQuery<UtilizationRoutesQuery>(
60
+ UtilizationRoutesDocument,
61
+ { pagination: { limit: 25, offset: routeOffset } },
62
+ actions.revision
63
+ );
64
+ const current = useConditionQuery<UtilizationCurrentRouteQuery>(
65
+ UtilizationCurrentRouteDocument,
66
+ routeSelection ? { id: routeSelection.id } : null,
67
+ actions.revision
68
+ );
69
+ const route = current.data?.route;
70
+ const reports = useConditionQuery<UtilizationReportsQuery>(
71
+ UtilizationReportsDocument,
72
+ routeSelection
73
+ ? { routeId: routeSelection.id, pagination: { limit: 25, offset: reportOffset } }
74
+ : null,
75
+ actions.revision
76
+ );
77
+ const busy = actions.busy || checking;
78
+ const routePage = routes.data
79
+ ? {
80
+ total: routes.data.routesCount,
81
+ limit: 25,
82
+ offset: routeOffset,
83
+ hasMore: routeOffset + routes.data.routes.length < routes.data.routesCount,
84
+ nextOffset: routeOffset + 25,
85
+ }
86
+ : undefined;
87
+ const routeOptions =
88
+ routes.data?.routes.map((item) => ({
89
+ id: item.id,
90
+ label: `${item.name} — ${item.status} — ${item.vehicle?.vehicleNumber ?? 'No assigned vehicle'}`,
91
+ })) ?? [];
92
+ if (routeSelection && !routeOptions.some((item) => item.id === routeSelection.id))
93
+ routeOptions.unshift({
94
+ id: routeSelection.id,
95
+ label: `${route?.name ?? routeSelection.label} — selected outside this page`,
96
+ });
97
+ const displayedContextChanged =
98
+ !!draftContext &&
99
+ !!current.data &&
100
+ !tripContextStillMatches(draftContext, route, route?.vehicle);
101
+ const record = async (draft: TripReportDraft) => {
102
+ if (checkingNow.current) return;
103
+ if (!draftContext)
104
+ throw new Error('Review the displayed route and assigned vehicle before starting a report.');
105
+ const pin = draftContext;
106
+ checkingNow.current = true;
107
+ setChecking(true);
108
+ setError(null);
109
+ try {
110
+ const latest = await request<UtilizationCurrentRouteQuery>(UtilizationCurrentRouteDocument, {
111
+ id: pin.routeId,
112
+ });
113
+ const freshRoute = latest.route;
114
+ if (!tripRouteStillMatches(pin, freshRoute)) {
115
+ setContextMismatch(true);
116
+ throw new Error(
117
+ 'The route or assigned vehicle changed since this draft began. Refresh context and review it before starting a new report. No measurements were rebound.'
118
+ );
119
+ }
120
+ const vehicleResult = await request<UtilizationCurrentVehicleQuery>(
121
+ UtilizationCurrentVehicleDocument,
122
+ { id: pin.vehicleId }
123
+ );
124
+ if (!tripContextStillMatches(pin, freshRoute, vehicleResult.vehicle))
125
+ setContextMismatch(true);
126
+ const input = inputForTripDraft(draft, pin, freshRoute, vehicleResult.vehicle);
127
+ const result = await actions.run<RecordUtilizationReportMutation>(
128
+ RecordUtilizationReportDocument,
129
+ input,
130
+ 'Immutable operator report recorded; assignments and operational state unchanged.'
131
+ );
132
+ if (result) {
133
+ setSelected(result.recordMtwTripUtilizationReport);
134
+ setReportOffset(0);
135
+ }
136
+ } catch (failure) {
137
+ setError(
138
+ failure instanceof Error ? failure.message : 'Unable to verify the captured report context.'
139
+ );
140
+ throw failure;
141
+ } finally {
142
+ checkingNow.current = false;
143
+ setChecking(false);
144
+ }
145
+ };
146
+ return (
147
+ <div className="min-w-0 space-y-6 break-words">
148
+ <p className="rounded border p-4 text-sm">
149
+ These are operator-reported interval facts. COMPLETE coverage and measured/source labels are
150
+ declarations, not independently certified whole-trip measurements. Ratios do not establish
151
+ axle/road legality, physical packing, dispatch feasibility, fuel consumption or savings.
152
+ This page does not assign work or start a route.
153
+ </p>
154
+ <section className={reuseCard} aria-label="Choose route and current assigned vehicle">
155
+ <h2 className="text-lg font-semibold">Route and assigned vehicle</h2>
156
+ <PinnedSelect
157
+ label="Route"
158
+ value={routeSelection?.id ?? ''}
159
+ disabled={busy || actions.uncertain}
160
+ options={routeOptions}
161
+ onChange={(id) => {
162
+ const row = routes.data?.routes.find((item) => item.id === id);
163
+ setRouteSelection(row ? { id: row.id, label: row.name } : null);
164
+ setDraftContext(null);
165
+ setContextMismatch(false);
166
+ setSelected(null);
167
+ setReportOffset(0);
168
+ setError(null);
169
+ actions.discardAttempt();
170
+ }}
171
+ />
172
+ <ReuseState {...routes} />
173
+ <ReusePager
174
+ page={routePage}
175
+ offset={routeOffset}
176
+ onChange={setRouteOffset}
177
+ busy={busy || routes.loading}
178
+ />
179
+ {routeSelection && (
180
+ <p>
181
+ Selected route {route?.name ?? routeSelection.label}.{' '}
182
+ {route
183
+ ? `Current status ${route.status}; revision ${route.updatedAt}.`
184
+ : 'Current record not loaded; new report blocked.'}
185
+ </p>
186
+ )}
187
+ <ReuseState {...current} />
188
+ {route && (
189
+ <p>
190
+ Currently assigned vehicle:{' '}
191
+ {route.vehicle
192
+ ? `${route.vehicle.vehicleNumber}${route.vehicle.licensePlate ? ` (${route.vehicle.licensePlate})` : ''} — ${route.vehicle.type} — ${route.vehicle.status}; revision ${route.vehicle.updatedAt}`
193
+ : 'unavailable / unassigned'}
194
+ . Assignment changes belong to the existing route workflow.
195
+ </p>
196
+ )}
197
+ <Button
198
+ type="button"
199
+ variant="outline"
200
+ disabled={busy}
201
+ onClick={() => {
202
+ setContextMismatch(false);
203
+ setError(null);
204
+ actions.refresh();
205
+ }}
206
+ >
207
+ Refresh current context and history
208
+ </Button>
209
+ </section>
210
+ {routeSelection && (
211
+ <>
212
+ <section className={reuseCard} aria-label="Record reported utilization">
213
+ <h2 className="text-lg font-semibold">Record interval facts</h2>
214
+ <p className="text-sm">
215
+ Start a report only after reviewing the displayed route and assigned vehicle. The
216
+ draft retains those identities and revisions. Fresh reads verify them; they do not
217
+ substitute a new vehicle or retag entered measurements.
218
+ </p>
219
+ {draftContext && (
220
+ <p>
221
+ Draft context: {draftContext.routeName} / {draftContext.vehicleNumber}; route
222
+ revision {draftContext.routeUpdatedAt}; vehicle revision{' '}
223
+ {draftContext.vehicleUpdatedAt}.
224
+ </p>
225
+ )}
226
+ {(contextMismatch || displayedContextChanged) && (
227
+ <p role="alert">
228
+ The draft context changed. Unsaved measurement fields are cleared. Refresh and
229
+ review the current context before starting a replacement report. An uncertain
230
+ original request remains separate.
231
+ </p>
232
+ )}
233
+ {actions.uncertain && (
234
+ <p>
235
+ Resolve the uncertain original request or explicitly abandon it after inspecting
236
+ history before starting another draft.
237
+ </p>
238
+ )}
239
+ <Button
240
+ type="button"
241
+ variant="outline"
242
+ disabled={
243
+ busy ||
244
+ actions.uncertain ||
245
+ contextMismatch ||
246
+ current.loading ||
247
+ !route?.vehicle ||
248
+ route.vehicleId !== route.vehicle.id
249
+ }
250
+ onClick={() => {
251
+ if (!route?.vehicle || route.vehicleId !== route.vehicle.id) return;
252
+ setDraftContext({
253
+ routeId: route.id,
254
+ routeUpdatedAt: route.updatedAt,
255
+ vehicleId: route.vehicle.id,
256
+ vehicleUpdatedAt: route.vehicle.updatedAt,
257
+ routeName: route.name,
258
+ vehicleNumber: route.vehicle.vehicleNumber,
259
+ generation: crypto.randomUUID(),
260
+ });
261
+ setContextMismatch(false);
262
+ setError(null);
263
+ }}
264
+ >
265
+ Review current context and start a new report
266
+ </Button>
267
+ {draftContext && !contextMismatch && !displayedContextChanged && (
268
+ <TripReportForm
269
+ key={`${draftContext.generation}:${draftContext.routeId}:${draftContext.routeUpdatedAt}:${draftContext.vehicleId}:${draftContext.vehicleUpdatedAt}`}
270
+ busy={
271
+ busy ||
272
+ actions.uncertain ||
273
+ current.loading ||
274
+ !route?.vehicleId ||
275
+ !route.vehicle
276
+ }
277
+ onSubmit={record}
278
+ />
279
+ )}
280
+ </section>
281
+ <TripReportHistory
282
+ query={reports}
283
+ offset={reportOffset}
284
+ onPage={setReportOffset}
285
+ selected={selected}
286
+ onSelect={setSelected}
287
+ busy={busy}
288
+ />
289
+ </>
290
+ )}
291
+ {error && <p role="alert">{error}</p>}
292
+ {actions.error && <p role="alert">{actions.error}</p>}
293
+ {actions.notice && <p role="status">{actions.notice}</p>}
294
+ {actions.uncertain && (
295
+ <div className="space-y-3 rounded border p-4">
296
+ <p>
297
+ Result may be uncertain. Inspect refreshed history first. Retry original request sends
298
+ the original submitted body, route/vehicle revisions and key, ignoring edited form
299
+ fields. A new submitted semantic payload starts a new key. Attempts are not retained
300
+ after a browser reload.
301
+ </p>
302
+ <Button type="button" variant="outline" disabled={busy} onClick={actions.refresh}>
303
+ Refresh report history
304
+ </Button>
305
+ <Button type="button" disabled={busy} onClick={actions.retryOriginal}>
306
+ Retry original request
307
+ </Button>
308
+ <Button type="button" variant="outline" disabled={busy} onClick={actions.discardAttempt}>
309
+ Abandon retry after inspecting history
310
+ </Button>
311
+ </div>
312
+ )}
313
+ </div>
314
+ );
315
+ }
@@ -0,0 +1,39 @@
1
+ import { print } from 'graphql';
2
+ import {
3
+ SaveConsolidationPlanDocument,
4
+ RecordConsolidationObservationDocument,
5
+ SaveConsolidationManifestDocument,
6
+ } from '../../generated/consolidation-operations';
7
+ import {
8
+ sameReuseRecoveryScope,
9
+ type ReuseRecovery,
10
+ type ReuseRecoveryScope,
11
+ } from './reuseRecovery';
12
+
13
+ export type OriginalConsolidationHistoryTarget =
14
+ | { kind: 'plan'; shipmentId: string; planReference: string }
15
+ | { kind: 'observation' | 'manifest'; planId: string };
16
+
17
+ function reference(value: unknown): value is string {
18
+ return typeof value === 'string' && value.trim().length > 0 && value.length <= 200;
19
+ }
20
+
21
+ /** Retained input supplies read targets only in its original context; it never rebinds a draft. */
22
+ export function originalConsolidationHistoryTarget(
23
+ pending: ReuseRecovery | null,
24
+ scope: ReuseRecoveryScope | null
25
+ ): OriginalConsolidationHistoryTarget | null {
26
+ if (!pending || !sameReuseRecoveryScope(pending.scope, scope)) return null;
27
+ if (pending.operation === print(SaveConsolidationPlanDocument)) {
28
+ const { shipmentId, planReference } = pending.input;
29
+ return reference(shipmentId) && reference(planReference)
30
+ ? { kind: 'plan', shipmentId, planReference }
31
+ : null;
32
+ }
33
+ if (!reference(pending.input.planId)) return null;
34
+ if (pending.operation === print(RecordConsolidationObservationDocument))
35
+ return { kind: 'observation', planId: pending.input.planId };
36
+ if (pending.operation === print(SaveConsolidationManifestDocument))
37
+ return { kind: 'manifest', planId: pending.input.planId };
38
+ return null;
39
+ }
@@ -0,0 +1,70 @@
1
+ import { object, localProcedureInstant } from './procedureInput';
2
+ export const consolidationInstant = localProcedureInstant;
3
+ export function nullableText(value: string): string | null {
4
+ return value.trim() || null;
5
+ }
6
+ /** Keep decimal source text exact. Blank facts are unknown, and explicit zero remains zero. */
7
+ export function consolidationQuantity(value: string): string | null {
8
+ const text = value.trim();
9
+ if (!text) return null;
10
+ if (!/^(?:0|[1-9]\d{0,19})(?:\.\d{1,6})?$/.test(text))
11
+ throw new Error('Use a nonnegative decimal with at most six decimal places.');
12
+ return text;
13
+ }
14
+ export function sameConsolidationPin(
15
+ a: { id: string; version: number } | null,
16
+ b: { id: string; version: number } | null
17
+ ): boolean {
18
+ return a?.id === b?.id && a?.version === b?.version;
19
+ }
20
+ /** Require the scoped immutable acknowledgement before clearing the original request. */
21
+ export function consolidationAcknowledgement(
22
+ result: Record<string, unknown>,
23
+ input: Record<string, unknown>,
24
+ actorId?: string
25
+ ): boolean {
26
+ const field =
27
+ 'facts' in input
28
+ ? 'saveMtwConsolidationPlan'
29
+ : 'kind' in input
30
+ ? 'recordMtwConsolidationObservation'
31
+ : 'saveMtwConsolidationManifest';
32
+ const row = result[field];
33
+ if (
34
+ !object(row) ||
35
+ typeof row.id !== 'string' ||
36
+ !row.id.trim() ||
37
+ row.createdBy !== actorId ||
38
+ typeof input.expectedVersion !== 'number' ||
39
+ !Number.isInteger(input.expectedVersion) ||
40
+ input.expectedVersion < 0 ||
41
+ row.version !== input.expectedVersion + 1 ||
42
+ row.previousVersionId !== input.expectedPreviousVersionId
43
+ )
44
+ return false;
45
+ if ('facts' in input)
46
+ return (
47
+ row.shipmentId === input.shipmentId &&
48
+ row.cycleId === input.cycleId &&
49
+ row.planReference === input.planReference &&
50
+ object(row.sourceCapture) &&
51
+ row.sourceCapture.shipmentUpdatedAt === input.expectedShipmentUpdatedAt &&
52
+ row.sourceCapture.cycleVersion === input.expectedCycleVersion
53
+ );
54
+ if ('kind' in input)
55
+ return (
56
+ row.planId === input.planId &&
57
+ row.lotId === input.lotId &&
58
+ row.kind === input.kind &&
59
+ row.issueReference === input.issueReference &&
60
+ row.reportedQuantity === input.reportedQuantity &&
61
+ Number.isInteger(row.receiptSequence)
62
+ );
63
+ return (
64
+ row.planId === input.planId &&
65
+ row.observationSequence === input.expectedObservationSequence &&
66
+ object(row.snapshot) &&
67
+ row.snapshot.planId === input.planId &&
68
+ row.snapshot.observationSequence === input.expectedObservationSequence
69
+ );
70
+ }
@@ -0,0 +1,24 @@
1
+ import type { MtwConsolidationLotInput } from '../../generated/consolidation-operations';
2
+ export function emptyConsolidationLot(): MtwConsolidationLotInput {
3
+ return {
4
+ id: crypto.randomUUID(),
5
+ supplierReference: '',
6
+ lotReference: '',
7
+ consignmentReference: '',
8
+ sourceRevision: '',
9
+ quantityBasis: 'UNKNOWN',
10
+ unitReference: null,
11
+ unitRevision: null,
12
+ balanceRevision: null,
13
+ reportedAvailableQuantity: null,
14
+ plannedQuantity: null,
15
+ grossKg: null,
16
+ cubeM3: null,
17
+ originReference: null,
18
+ destinationReference: null,
19
+ importerReference: null,
20
+ transportReference: null,
21
+ documentReference: null,
22
+ source: { reference: null, revision: null },
23
+ };
24
+ }
@@ -0,0 +1,52 @@
1
+ import type {
2
+ ConsolidationContainersQuery,
3
+ ConsolidationCyclesQuery,
4
+ ConsolidationShipmentQuery,
5
+ } from '../../generated/consolidation-operations';
6
+ import { sameConsolidationPin } from './consolidationInput';
7
+ export type ConsolidationContextPin = {
8
+ shipmentId: string;
9
+ shipmentUpdatedAt: string;
10
+ cycleId: string;
11
+ cycleVersion: number;
12
+ containerId: string;
13
+ };
14
+ export function matchesConsolidationContext(
15
+ pin: ConsolidationContextPin,
16
+ shipment: ConsolidationShipmentQuery['shipment'],
17
+ cycle: ConsolidationCyclesQuery['mtwContainerCyclePage']['items'][number] | null
18
+ ): boolean {
19
+ return (
20
+ !!shipment &&
21
+ !!cycle &&
22
+ shipment.id === pin.shipmentId &&
23
+ shipment.updatedAt === pin.shipmentUpdatedAt &&
24
+ cycle.id === pin.cycleId &&
25
+ cycle.containerId === pin.containerId &&
26
+ cycle.shipmentId === pin.shipmentId &&
27
+ cycle.version === pin.cycleVersion &&
28
+ cycle.status === 'OPEN'
29
+ );
30
+ }
31
+ export function assertConsolidationPredecessor(
32
+ pin: { id: string; version: number } | null,
33
+ current: { id: string; version: number } | null
34
+ ): void {
35
+ if (!sameConsolidationPin(pin, current))
36
+ throw new Error('Recorded history changed. Refresh and review before opening a new form.');
37
+ }
38
+
39
+ export type ConsolidationContainerOption = Pick<
40
+ ConsolidationContainersQuery['mtwContainerPage']['items'][number],
41
+ 'id' | 'containerNumber' | 'equipmentType'
42
+ >;
43
+ /** Retain the selected label across pagination without asserting current source validity. */
44
+ export function offPageConsolidationContainer(
45
+ selectedId: string,
46
+ selected: ConsolidationContainerOption | null,
47
+ visible: readonly ConsolidationContainerOption[]
48
+ ): ConsolidationContainerOption | null {
49
+ return selected?.id === selectedId && !visible.some((row) => row.id === selectedId)
50
+ ? selected
51
+ : null;
52
+ }
@@ -0,0 +1,88 @@
1
+ import { print } from 'graphql';
2
+ import {
3
+ SaveConsolidationPlanDocument,
4
+ RecordConsolidationObservationDocument,
5
+ SaveConsolidationManifestDocument,
6
+ } from '../../generated/consolidation-operations';
7
+ import type { ReuseRecovery } from './reuseRecovery';
8
+ export const CONSOLIDATION_RECOVERY_STORAGE = 'movethewheels.consolidation.unresolved.v1';
9
+ export function decodeConsolidationRecovery(raw: string | null): ReuseRecovery | null {
10
+ if (!raw || new TextEncoder().encode(raw).byteLength > 200000) return null;
11
+ try {
12
+ const value: unknown = JSON.parse(raw);
13
+ if (
14
+ typeof value !== 'object' ||
15
+ value === null ||
16
+ !('version' in value) ||
17
+ value.version !== 1 ||
18
+ !('scope' in value) ||
19
+ !('input' in value) ||
20
+ !('operation' in value) ||
21
+ typeof value.operation !== 'string' ||
22
+ ![
23
+ SaveConsolidationPlanDocument,
24
+ RecordConsolidationObservationDocument,
25
+ SaveConsolidationManifestDocument,
26
+ ].some((item) => print(item) === value.operation) ||
27
+ !('key' in value) ||
28
+ typeof value.key !== 'string' ||
29
+ !value.key ||
30
+ value.key.length > 200 ||
31
+ !('success' in value) ||
32
+ typeof value.success !== 'string' ||
33
+ value.success.length > 500
34
+ )
35
+ return null;
36
+ if (
37
+ typeof value.input !== 'object' ||
38
+ value.input === null ||
39
+ Array.isArray(value.input) ||
40
+ typeof value.scope !== 'object' ||
41
+ value.scope === null
42
+ )
43
+ return null;
44
+ const scope = value.scope;
45
+ if (
46
+ !('actorId' in scope) ||
47
+ typeof scope.actorId !== 'string' ||
48
+ !scope.actorId ||
49
+ !('workspaceId' in scope) ||
50
+ typeof scope.workspaceId !== 'string' ||
51
+ !scope.workspaceId ||
52
+ !('tenantId' in scope) ||
53
+ typeof scope.tenantId !== 'string' ||
54
+ !('organizationId' in scope) ||
55
+ typeof scope.organizationId !== 'string' ||
56
+ !scope.organizationId ||
57
+ !('gateway' in scope) ||
58
+ typeof scope.gateway !== 'string' ||
59
+ !('projectId' in scope) ||
60
+ (scope.projectId !== null && typeof scope.projectId !== 'string')
61
+ )
62
+ return null;
63
+ return {
64
+ version: 1,
65
+ scope: {
66
+ actorId: scope.actorId,
67
+ workspaceId: scope.workspaceId,
68
+ tenantId: scope.tenantId,
69
+ organizationId: scope.organizationId,
70
+ gateway: scope.gateway,
71
+ projectId: scope.projectId,
72
+ },
73
+ operation: value.operation,
74
+ // The owning document is exact and input is an object; field authority remains backend-validated.
75
+ input: structuredClone(value.input) as Record<string, unknown>,
76
+ key: value.key,
77
+ success: value.success,
78
+ };
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
83
+ export function encodeConsolidationRecovery(attempt: ReuseRecovery): string {
84
+ const raw = JSON.stringify(attempt);
85
+ if (!decodeConsolidationRecovery(raw))
86
+ throw new Error('Cannot safely retain this consolidation request. Nothing was sent.');
87
+ return raw;
88
+ }
@@ -0,0 +1,29 @@
1
+ import {
2
+ ConsolidationObservationsDocument,
3
+ type ConsolidationObservationsQuery,
4
+ type MtwConsolidationReportKind,
5
+ } from '../../generated/consolidation-operations';
6
+ type Report = ConsolidationObservationsQuery['mtwConsolidationObservationPage']['items'][number];
7
+ export async function findConsolidationReportHead(
8
+ request: <T>(
9
+ document: typeof ConsolidationObservationsDocument,
10
+ variables: Record<string, unknown>
11
+ ) => Promise<T>,
12
+ planId: string,
13
+ lotId: string,
14
+ kind: MtwConsolidationReportKind
15
+ ): Promise<Report | null> {
16
+ // Receipt ordering makes the first matching row the current cumulative chain head.
17
+ for (let offset = 0; offset < 500; offset += 25) {
18
+ const page = await request<ConsolidationObservationsQuery>(ConsolidationObservationsDocument, {
19
+ planId,
20
+ pagination: { limit: 25, offset },
21
+ });
22
+ const head = page.mtwConsolidationObservationPage.items.find(
23
+ (row) => row.lotId === lotId && row.kind === kind
24
+ );
25
+ if (head) return head;
26
+ if (!page.mtwConsolidationObservationPage.hasMore) return null;
27
+ }
28
+ throw new Error('History exceeds the supported review window. No report will be sent.');
29
+ }
@@ -0,0 +1,31 @@
1
+ export function freeTimeIso(value: string): string {
2
+ const parts =
3
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,3})?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/i.exec(
4
+ value
5
+ );
6
+ if (!parts)
7
+ throw new Error('Use an ISO date and time with seconds and Z or an explicit timezone offset.');
8
+ const year = Number(parts[1]);
9
+ const month = Number(parts[2]);
10
+ const day = Number(parts[3]);
11
+ const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
12
+ const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
13
+ if (
14
+ month < 1 ||
15
+ month > 12 ||
16
+ day < 1 ||
17
+ day > (days[month - 1] ?? 0) ||
18
+ Number(parts[4]) > 23 ||
19
+ Number(parts[5]) > 59 ||
20
+ Number(parts[6]) > 59
21
+ )
22
+ throw new Error(
23
+ 'Enter a real calendar date and time; invalid dates are not moved to another day.'
24
+ );
25
+ if (!/(?:Z|[+-]\d{2}:\d{2})$/i.test(value))
26
+ throw new Error('Include Z or an explicit timezone offset.');
27
+ const date = new Date(value);
28
+ if (!Number.isFinite(date.getTime()))
29
+ throw new Error('Enter a valid time with an explicit timezone.');
30
+ return date.toISOString();
31
+ }
@@ -0,0 +1,31 @@
1
+ /** Validate the minimum immutable receipt identity before resolving a retained request. */
2
+ export function matchesFreightAcknowledgement(
3
+ result: unknown,
4
+ input: Record<string, unknown>
5
+ ): boolean {
6
+ if (
7
+ typeof result !== 'object' ||
8
+ result === null ||
9
+ !('saveMtwFreightEstimate' in result) ||
10
+ typeof result.saveMtwFreightEstimate !== 'object' ||
11
+ result.saveMtwFreightEstimate === null
12
+ )
13
+ return false;
14
+ const receipt = result.saveMtwFreightEstimate;
15
+ return (
16
+ 'id' in receipt &&
17
+ typeof receipt.id === 'string' &&
18
+ receipt.id.trim().length > 0 &&
19
+ 'shipmentId' in receipt &&
20
+ receipt.shipmentId === input.shipmentId &&
21
+ 'estimateReference' in receipt &&
22
+ receipt.estimateReference === input.estimateReference &&
23
+ 'version' in receipt &&
24
+ Number.isInteger(input.expectedVersion) &&
25
+ typeof input.expectedVersion === 'number' &&
26
+ input.expectedVersion >= 0 &&
27
+ receipt.version === input.expectedVersion + 1 &&
28
+ 'previousVersionId' in receipt &&
29
+ receipt.previousVersionId === input.expectedPreviousVersionId
30
+ );
31
+ }