@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,151 @@
1
+ import { Kind, parse, print, type DocumentNode } from 'graphql';
2
+ import { resolveGraphqlUrl } from './graphqlClient';
3
+
4
+ export const REUSE_RECOVERY_STORAGE = 'movethewheels.empty-reuse.unresolved.v1';
5
+ const MAX_BYTES = 200_000;
6
+ const operations = new Set([
7
+ 'RecordReturnInstruction',
8
+ 'RecordReuseProposal',
9
+ 'RecordReuseApproval',
10
+ 'AcceptReuseReservation',
11
+ 'TerminateReuseReservation',
12
+ ]);
13
+ export interface ReuseRecoveryScope {
14
+ actorId: string;
15
+ workspaceId: string;
16
+ tenantId: string;
17
+ organizationId: string;
18
+ gateway: string;
19
+ projectId: string | null;
20
+ }
21
+ export interface ReuseRecovery {
22
+ version: 1;
23
+ scope: ReuseRecoveryScope;
24
+ operation: string;
25
+ input: Record<string, unknown>;
26
+ key: string;
27
+ success: string;
28
+ }
29
+ function object(value: unknown): value is Record<string, unknown> {
30
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
31
+ }
32
+ /** Claims are context comparison metadata only; the gateway remains the authentication authority. */
33
+ export function reuseRecoveryScope(
34
+ actorId: string | undefined,
35
+ workspaceId: string | undefined,
36
+ tenantId: string | undefined,
37
+ gateway: string | undefined,
38
+ workspaceToken: string | undefined
39
+ ): ReuseRecoveryScope | null {
40
+ if (!actorId || !workspaceId || !workspaceToken) return null;
41
+ try {
42
+ const encoded = workspaceToken.split('.')[1];
43
+ const claims: unknown = JSON.parse(atob(encoded.replace(/-/g, '+').replace(/_/g, '/')));
44
+ if (
45
+ !object(claims) ||
46
+ claims.sub !== actorId ||
47
+ claims.workspaceId !== workspaceId ||
48
+ typeof claims.organizationId !== 'string' ||
49
+ !claims.organizationId ||
50
+ !Object.hasOwn(claims, 'projectId')
51
+ )
52
+ return null;
53
+ const project = claims.projectId;
54
+ if (project !== null && project !== undefined && typeof project !== 'string') return null;
55
+ return {
56
+ actorId,
57
+ workspaceId,
58
+ tenantId: tenantId ?? '',
59
+ organizationId: claims.organizationId,
60
+ gateway: resolveGraphqlUrl(gateway),
61
+ projectId: project ?? null,
62
+ };
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+ /** Stable across token renewal; changing an owner/project context resets unsent forms. */
68
+ export function reuseRecoveryContextKey(scope: ReuseRecoveryScope | null): string {
69
+ return JSON.stringify(scope);
70
+ }
71
+ export function sameReuseRecoveryScope(
72
+ a: ReuseRecoveryScope,
73
+ b: ReuseRecoveryScope | null
74
+ ): boolean {
75
+ return (
76
+ b !== null &&
77
+ a.actorId === b.actorId &&
78
+ a.workspaceId === b.workspaceId &&
79
+ a.tenantId === b.tenantId &&
80
+ a.organizationId === b.organizationId &&
81
+ a.gateway === b.gateway &&
82
+ a.projectId === b.projectId
83
+ );
84
+ }
85
+ export function decodeReuseRecovery(
86
+ raw: string | null,
87
+ documents: readonly DocumentNode[]
88
+ ): ReuseRecovery | null {
89
+ if (!raw || new TextEncoder().encode(raw).byteLength > MAX_BYTES) return null;
90
+ try {
91
+ const value: unknown = JSON.parse(raw);
92
+ if (!object(value) || value.version !== 1 || !object(value.scope) || !object(value.input))
93
+ return null;
94
+ const scope = value.scope;
95
+ if (
96
+ typeof scope.actorId !== 'string' ||
97
+ typeof scope.workspaceId !== 'string' ||
98
+ typeof scope.tenantId !== 'string' ||
99
+ typeof scope.organizationId !== 'string' ||
100
+ typeof scope.gateway !== 'string' ||
101
+ !scope.actorId ||
102
+ !scope.workspaceId ||
103
+ (scope.projectId !== null && typeof scope.projectId !== 'string')
104
+ )
105
+ return null;
106
+ if (typeof value.operation !== 'string' || !documents.some((d) => print(d) === value.operation))
107
+ return null;
108
+ const definitions = parse(value.operation).definitions;
109
+ const op = definitions.find((d) => d.kind === Kind.OPERATION_DEFINITION);
110
+ if (
111
+ !op ||
112
+ op.kind !== Kind.OPERATION_DEFINITION ||
113
+ op.operation !== 'mutation' ||
114
+ !op.name ||
115
+ !operations.has(op.name.value)
116
+ )
117
+ return null;
118
+ if (
119
+ typeof value.key !== 'string' ||
120
+ !value.key ||
121
+ value.key.length > 200 ||
122
+ typeof value.success !== 'string' ||
123
+ value.success.length > 500
124
+ )
125
+ return null;
126
+ // Storage is untrusted. Only the current owning operation document may be executed.
127
+ return {
128
+ version: 1,
129
+ scope: {
130
+ actorId: scope.actorId,
131
+ workspaceId: scope.workspaceId,
132
+ tenantId: scope.tenantId,
133
+ organizationId: scope.organizationId,
134
+ gateway: scope.gateway,
135
+ projectId: scope.projectId,
136
+ },
137
+ operation: value.operation,
138
+ input: value.input,
139
+ key: value.key,
140
+ success: value.success,
141
+ };
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+ export function encodeReuseRecovery(value: ReuseRecovery): string {
147
+ const text = JSON.stringify(value);
148
+ if (new TextEncoder().encode(text).byteLength > MAX_BYTES)
149
+ throw new Error('This request is too large to retain safely.');
150
+ return text;
151
+ }
@@ -0,0 +1,209 @@
1
+ import type {
2
+ RecordMtwStockBindingAssessmentInput,
3
+ StockSourceContextFragment,
4
+ StockAssessmentFragment,
5
+ } from '../../generated/stock-binding-operations';
6
+ import { freeTimeIso } from './freeTimeDate';
7
+ import type { SelectedEvidence } from '../components/ContainerEvidencePicker';
8
+
9
+ export interface StockDraftPin {
10
+ inventoryItemId: string;
11
+ expectedCargoItemId: string;
12
+ expectedWarehouseId: string;
13
+ expectedLocationId: string | null;
14
+ expectedCompositionEpoch: number;
15
+ expectedInventoryUpdatedAt: string;
16
+ expectedCargoUpdatedAt: string;
17
+ expectedWarehouseUpdatedAt: string;
18
+ expectedLocationUpdatedAt: string | null;
19
+ expectedPreviousAssessmentId: string | null;
20
+ expectedVersion: number;
21
+ label: string;
22
+ }
23
+ export type StockFactDraft = Pick<
24
+ RecordMtwStockBindingAssessmentInput,
25
+ 'effectiveAt' | 'facts' | 'evidence'
26
+ >;
27
+ export function stockContextLabel(row: StockSourceContextFragment): string {
28
+ return `${row.warehouse?.name ?? 'Warehouse unavailable'} (${row.warehouse?.code ?? 'unknown code'}) / ${row.cargoItem?.name ?? 'Cargo unavailable'} (${row.cargoItem?.sku ?? 'unknown SKU'}) / ${row.locationId === null ? 'Unbinned' : (row.location?.locationCode ?? 'Bin unavailable')}`;
29
+ }
30
+ export function stockDraftPin(
31
+ row: StockSourceContextFragment,
32
+ predecessor: StockAssessmentFragment | null
33
+ ): StockDraftPin {
34
+ if (
35
+ !row.cargoItem ||
36
+ !row.warehouse ||
37
+ row.cargoItem.id !== row.cargoItemId ||
38
+ row.warehouse.id !== row.warehouseId ||
39
+ (row.locationId === null
40
+ ? row.location != null
41
+ : !row.location ||
42
+ row.location.id !== row.locationId ||
43
+ row.location.warehouseId !== row.warehouseId)
44
+ )
45
+ throw new Error(
46
+ 'This stock line is missing a current owner. Refresh and review it before recording.'
47
+ );
48
+ if (
49
+ !Number.isInteger(row.compositionEpoch) ||
50
+ row.compositionEpoch < 0 ||
51
+ row.compositionEpoch > 2147483647
52
+ )
53
+ throw new Error(
54
+ 'The current continuity revision is unavailable. Refresh and review this stock line.'
55
+ );
56
+ if (predecessor && predecessor.inventoryItemId !== row.id)
57
+ throw new Error('The previous assessment belongs to another stock line.');
58
+ return {
59
+ inventoryItemId: row.id,
60
+ expectedCompositionEpoch: row.compositionEpoch,
61
+ expectedCargoItemId: row.cargoItemId,
62
+ expectedWarehouseId: row.warehouseId,
63
+ expectedLocationId: row.locationId ?? null,
64
+ expectedInventoryUpdatedAt: row.updatedAt,
65
+ expectedCargoUpdatedAt: row.cargoItem.updatedAt,
66
+ expectedWarehouseUpdatedAt: row.warehouse.updatedAt,
67
+ expectedLocationUpdatedAt: row.location?.updatedAt ?? null,
68
+ expectedPreviousAssessmentId: predecessor?.id ?? null,
69
+ expectedVersion: predecessor?.version ?? 0,
70
+ label: stockContextLabel(row),
71
+ };
72
+ }
73
+ export function stockContextMatches(
74
+ pin: StockDraftPin,
75
+ row: StockSourceContextFragment | null | undefined,
76
+ predecessor: StockAssessmentFragment | null
77
+ ): boolean {
78
+ if (!row) return false;
79
+ try {
80
+ const current = stockDraftPin(row, predecessor);
81
+ // current contains only the declared pin keys; UI-only generation metadata is excluded.
82
+ return Object.entries(current).every(
83
+ ([name, value]) => name === 'label' || pin[name as keyof StockDraftPin] === value
84
+ );
85
+ } catch {
86
+ return false;
87
+ }
88
+ }
89
+ export function inputForStockDraft(
90
+ draft: StockFactDraft,
91
+ pin: StockDraftPin,
92
+ row: StockSourceContextFragment | null | undefined,
93
+ predecessor: StockAssessmentFragment | null
94
+ ): Omit<RecordMtwStockBindingAssessmentInput, 'idempotencyKey'> {
95
+ if (!stockContextMatches(pin, row, predecessor))
96
+ throw new Error(
97
+ 'This stock line or its recorded history changed. Refresh and review a new draft.'
98
+ );
99
+ return {
100
+ inventoryItemId: pin.inventoryItemId,
101
+ expectedCompositionEpoch: pin.expectedCompositionEpoch,
102
+ expectedCargoItemId: pin.expectedCargoItemId,
103
+ expectedWarehouseId: pin.expectedWarehouseId,
104
+ expectedLocationId: pin.expectedLocationId,
105
+ expectedInventoryUpdatedAt: pin.expectedInventoryUpdatedAt,
106
+ expectedCargoUpdatedAt: pin.expectedCargoUpdatedAt,
107
+ expectedWarehouseUpdatedAt: pin.expectedWarehouseUpdatedAt,
108
+ expectedLocationUpdatedAt: pin.expectedLocationUpdatedAt,
109
+ expectedPreviousAssessmentId: pin.expectedPreviousAssessmentId,
110
+ expectedVersion: pin.expectedVersion,
111
+ ...draft,
112
+ };
113
+ }
114
+ function optionalText(data: FormData, name: string, max = 255): string | null {
115
+ const value = data.get(name);
116
+ if (value === null || value === '') return null;
117
+ if (typeof value !== 'string') throw new Error('Enter text source facts.');
118
+ const text = value.trim();
119
+ if (!text) return null;
120
+ if (text.length > max) throw new Error(`${name} exceeds ${max} characters.`);
121
+ return text;
122
+ }
123
+ function optionalDate(data: FormData, name: string): string | null {
124
+ const text = optionalText(data, name);
125
+ return text === null ? null : freeTimeIso(text);
126
+ }
127
+ function choice<T extends string>(data: FormData, name: string, allowed: readonly T[]): T {
128
+ const selected = allowed.find((value) => value === data.get(name));
129
+ if (!selected) throw new Error(`Choose a declared ${name}.`);
130
+ return selected;
131
+ }
132
+ export function readStockFactDraft(data: FormData, evidence: SelectedEvidence[]): StockFactDraft {
133
+ const validityPolicy = choice(data, 'validityPolicy', [
134
+ 'UNKNOWN',
135
+ 'TIME_BOUNDED',
136
+ 'NO_REQUIRED_EXPIRY',
137
+ ] as const);
138
+ const from = optionalDate(data, 'validityFrom'),
139
+ until = optionalDate(data, 'validityUntil');
140
+ if (
141
+ (validityPolicy === 'NO_REQUIRED_EXPIRY' && until !== null) ||
142
+ (from && until && Date.parse(from) >= Date.parse(until))
143
+ )
144
+ throw new Error('Source validity cutoff or chronology contradicts its declaration.');
145
+ const lotPresent = choice(data, 'lotPresent', ['UNKNOWN', 'REPORTED'] as const) === 'REPORTED';
146
+ const expiryPolicy = lotPresent
147
+ ? choice(data, 'expiryPolicy', ['UNKNOWN', 'TIME_BOUNDED', 'NO_REQUIRED_EXPIRY'] as const)
148
+ : 'UNKNOWN';
149
+ const expiresAt = optionalDate(data, 'expiresAt');
150
+ if (lotPresent && expiryPolicy === 'NO_REQUIRED_EXPIRY' && expiresAt !== null)
151
+ throw new Error('No-required-expiry lot cannot have a cutoff.');
152
+ if (!evidence.length || evidence.length > 10)
153
+ throw new Error('Choose 1–10 exact evidence versions from shared Files.');
154
+ return {
155
+ effectiveAt: freeTimeIso(optionalText(data, 'effectiveAt') ?? ''),
156
+ evidence: evidence.map(({ fileId, versionId }) => ({ fileId, versionId })),
157
+ facts: {
158
+ scope: choice(data, 'scope', ['UNKNOWN', 'WHOLE_LINE', 'UNSUPPORTED_MIXED_LOT'] as const),
159
+ source: {
160
+ reference: optionalText(data, 'sourceReference'),
161
+ revision: optionalText(data, 'sourceRevision', 120),
162
+ },
163
+ countUnit:
164
+ choice(data, 'unitPresent', ['UNKNOWN', 'COUNT_UNIT'] as const) === 'COUNT_UNIT'
165
+ ? {
166
+ kind: 'COUNT_UNIT',
167
+ reference: optionalText(data, 'unitReference'),
168
+ revision: optionalText(data, 'unitRevision', 120),
169
+ }
170
+ : null,
171
+ scanMapping: {
172
+ reportedItemLabel: optionalText(data, 'itemLabel'),
173
+ reportedBinLabel: optionalText(data, 'binLabel'),
174
+ mappingReference: optionalText(data, 'mappingReference'),
175
+ mappingRevision: optionalText(data, 'mappingRevision', 120),
176
+ },
177
+ declaredLotPolicy: choice(data, 'lotPolicy', [
178
+ 'UNKNOWN',
179
+ 'REQUIRED',
180
+ 'NOT_REQUIRED',
181
+ ] as const),
182
+ lot: lotPresent
183
+ ? {
184
+ reference: optionalText(data, 'lotReference'),
185
+ revision: optionalText(data, 'lotRevision', 120),
186
+ declaredDisposition: choice(data, 'lotDisposition', [
187
+ 'UNKNOWN',
188
+ 'RELEASED',
189
+ 'HELD',
190
+ 'EXPIRED',
191
+ ] as const),
192
+ expiry: {
193
+ policy: expiryPolicy,
194
+ expiresAt,
195
+ sourceReference: optionalText(data, 'expiryReference'),
196
+ sourceRevision: optionalText(data, 'expiryRevision', 120),
197
+ },
198
+ }
199
+ : null,
200
+ sourceValidity: {
201
+ policy: validityPolicy,
202
+ from,
203
+ until,
204
+ sourceReference: optionalText(data, 'validityReference'),
205
+ sourceRevision: optionalText(data, 'validityRevision', 120),
206
+ },
207
+ },
208
+ };
209
+ }
@@ -0,0 +1,41 @@
1
+ export function stockCompletenessLabel(status: string): string {
2
+ if (status === 'SOURCE_FACTS_ONLY') return 'Reported facts';
3
+ if (status === 'INCOMPLETE') return 'Missing facts';
4
+ if (status === 'UNSUPPORTED_MIXED_LOT') return 'Mixed lots need separate handling';
5
+ return 'Unknown';
6
+ }
7
+ export function stockFactLabel(value: string | null | undefined): string {
8
+ if (!value || value === 'UNKNOWN') return 'Unknown';
9
+ if (value === 'NO_REQUIRED_EXPIRY') return 'Source reports no required expiry';
10
+ if (value === 'COUNT_UNIT') return 'Explicit count unit';
11
+ if (value === 'UNSUPPORTED_MIXED_LOT') return 'Mixed lots need separate handling';
12
+ const text = value.toLowerCase().replaceAll('_', ' ');
13
+ return text.charAt(0).toUpperCase() + text.slice(1);
14
+ }
15
+ export function stockMissingFactLabel(value: string): string {
16
+ const text = value
17
+ .toLowerCase()
18
+ .replaceAll('_', ' ')
19
+ .replace(/^declared /, 'Reported ')
20
+ .replace(/ unknown$/, ' is unknown');
21
+ return text.charAt(0).toUpperCase() + text.slice(1);
22
+ }
23
+
24
+ export function stockContinuityLabel(
25
+ assessment: { inventoryItemId: string; capturedCompositionEpoch?: number | null },
26
+ current?: { id: string; compositionEpoch: number } | null
27
+ ): string {
28
+ if (assessment.capturedCompositionEpoch == null) return 'Continuity revision not recorded.';
29
+ const captured = `Recorded continuity revision: ${assessment.capturedCompositionEpoch}.`;
30
+ if (
31
+ !current ||
32
+ current.id !== assessment.inventoryItemId ||
33
+ !Number.isInteger(current.compositionEpoch) ||
34
+ current.compositionEpoch < 0 ||
35
+ current.compositionEpoch > 2147483647
36
+ )
37
+ return `${captured} Current comparison unavailable.`;
38
+ return current.compositionEpoch === assessment.capturedCompositionEpoch
39
+ ? `${captured} Matches the displayed stock revision.`
40
+ : `${captured} Stock context changed since this record.`;
41
+ }
@@ -0,0 +1,73 @@
1
+ import type { RecordMtwStockObservationInput } from '../../generated/stock-observation-operations';
2
+
3
+ function text(form: FormData, name: string, max: number, required = false): string | null {
4
+ const value = form.get(name);
5
+ if (typeof value !== 'string') throw new Error('Reported field is missing.');
6
+ const normalized = value.trim();
7
+ if (normalized.length > max || (required && !normalized))
8
+ throw new Error('Check the reported field length.');
9
+ return normalized || null;
10
+ }
11
+ /** Blank remains unknown, explicit zero remains zero; no inferred stock adjustment. */
12
+ export function reportedCount(value: string): number | null {
13
+ const clean = value.trim();
14
+ if (!clean) return null;
15
+ if (!/^\d+$/.test(clean)) throw new Error('Reported count must be a whole number or blank.');
16
+ const count = Number(clean);
17
+ if (!Number.isSafeInteger(count) || count > 2147483647)
18
+ throw new Error('Reported count is outside the supported range.');
19
+ return count;
20
+ }
21
+ function reportedInstant(value: string): string | null {
22
+ if (!value) return null;
23
+ const time = new Date(value);
24
+ if (!Number.isFinite(time.getTime()) || time.getTime() > Date.now())
25
+ throw new Error('Reported observation time must be valid and no later than now.');
26
+ return time.toISOString();
27
+ }
28
+ export function stockObservationInput(
29
+ inventoryItemId: string,
30
+ form: FormData
31
+ ): Omit<RecordMtwStockObservationInput, 'idempotencyKey'> {
32
+ const kind = text(form, 'kind', 40, true);
33
+ const scope = text(form, 'countScope', 40, true);
34
+ if (
35
+ kind !== 'COUNT_DISCREPANCY' &&
36
+ kind !== 'DAMAGE' &&
37
+ kind !== 'IDENTITY_UNCERTAIN' &&
38
+ kind !== 'OTHER'
39
+ )
40
+ throw new Error('Choose a supported issue.');
41
+ if (scope !== 'WHOLE_LINE' && scope !== 'UNKNOWN')
42
+ throw new Error('Choose a supported count scope.');
43
+ const fileId = text(form, 'fileId', 255),
44
+ versionId = text(form, 'versionId', 255);
45
+ if (!!fileId !== !!versionId)
46
+ throw new Error('Enter both exact file and version references, or leave both blank.');
47
+ const unitReference = text(form, 'unitReference', 255),
48
+ unitRevision = text(form, 'unitRevision', 255);
49
+ const sourceReference = text(form, 'sourceReference', 255),
50
+ sourceRevision = text(form, 'sourceRevision', 255);
51
+ const countUnit = form.get('countUnit');
52
+ if (countUnit !== 'COUNT_UNIT' && countUnit !== 'UNKNOWN')
53
+ throw new Error('Choose a supported reported unit.');
54
+ if (countUnit === 'UNKNOWN' && (unitReference || unitRevision))
55
+ throw new Error('Select count unit before supplying its references.');
56
+ return {
57
+ inventoryItemId,
58
+ kind,
59
+ countScope: scope,
60
+ observedCount: reportedCount(text(form, 'observedCount', 32) ?? ''),
61
+ reportedCountUnit:
62
+ countUnit === 'COUNT_UNIT'
63
+ ? { kind: 'COUNT_UNIT', reference: unitReference, revision: unitRevision }
64
+ : null,
65
+ source:
66
+ sourceReference || sourceRevision
67
+ ? { reference: sourceReference, revision: sourceRevision }
68
+ : null,
69
+ reportedObservedAt: reportedInstant(text(form, 'reportedObservedAt', 50) ?? ''),
70
+ reason: text(form, 'reason', 1000, true) ?? '',
71
+ evidenceDeclarations: fileId && versionId ? [{ fileId, versionId }] : [],
72
+ };
73
+ }
@@ -0,0 +1,61 @@
1
+ import type { RecordMtwTripUtilizationReportInput } from '../../generated/trip-utilization-operations';
2
+ import type { TripReportDraft } from './tripUtilizationForm';
3
+ export interface TripDraftContext {
4
+ routeId: string;
5
+ routeUpdatedAt: string;
6
+ vehicleId: string;
7
+ vehicleUpdatedAt: string;
8
+ routeName: string;
9
+ vehicleNumber: string;
10
+ }
11
+ interface RouteContext {
12
+ id: string;
13
+ updatedAt: string;
14
+ vehicleId?: string | null;
15
+ }
16
+ interface VehicleContext {
17
+ id: string;
18
+ updatedAt: string;
19
+ }
20
+ export function tripRouteStillMatches(
21
+ pin: TripDraftContext,
22
+ route: RouteContext | null | undefined
23
+ ): boolean {
24
+ return (
25
+ !!route &&
26
+ route.id === pin.routeId &&
27
+ route.updatedAt === pin.routeUpdatedAt &&
28
+ route.vehicleId === pin.vehicleId
29
+ );
30
+ }
31
+ export function tripContextStillMatches(
32
+ pin: TripDraftContext,
33
+ route: RouteContext | null | undefined,
34
+ vehicle: VehicleContext | null | undefined
35
+ ): boolean {
36
+ return (
37
+ tripRouteStillMatches(pin, route) &&
38
+ !!vehicle &&
39
+ vehicle.id === pin.vehicleId &&
40
+ vehicle.updatedAt === pin.vehicleUpdatedAt
41
+ );
42
+ }
43
+ /** Fresh reads verify captured intent; they never replace the vehicle or revisions entered against. */
44
+ export function inputForTripDraft(
45
+ draft: TripReportDraft,
46
+ pin: TripDraftContext,
47
+ route: RouteContext | null | undefined,
48
+ vehicle: VehicleContext | null | undefined
49
+ ): Omit<RecordMtwTripUtilizationReportInput, 'idempotencyKey'> {
50
+ if (!tripContextStillMatches(pin, route, vehicle))
51
+ throw new Error(
52
+ 'Route assignment or revision changed since this draft began. Refresh context, review the route and vehicle, and start a new report; the entered measurements will not be reassigned automatically.'
53
+ );
54
+ return {
55
+ ...draft,
56
+ routeId: pin.routeId,
57
+ vehicleId: pin.vehicleId,
58
+ expectedRouteUpdatedAt: pin.routeUpdatedAt,
59
+ expectedVehicleUpdatedAt: pin.vehicleUpdatedAt,
60
+ };
61
+ }
@@ -0,0 +1,105 @@
1
+ import type {
2
+ RecordMtwTripUtilizationReportInput,
3
+ MtwTripUtilizationBasis,
4
+ MtwTripUtilizationCoverage,
5
+ } from '../../generated/trip-utilization-operations';
6
+ import type { SelectedEvidence } from '../components/ContainerEvidencePicker';
7
+ import { freeTimeIso } from './freeTimeDate';
8
+ import { reuseText } from './reuseForm';
9
+ export type TripReportDraft = Omit<
10
+ RecordMtwTripUtilizationReportInput,
11
+ 'routeId' | 'vehicleId' | 'expectedRouteUpdatedAt' | 'expectedVehicleUpdatedAt' | 'idempotencyKey'
12
+ >;
13
+ export function tripQuantity(text: string, maximum: number, positive = false): number | null {
14
+ if (!text.trim()) return null;
15
+ if (!/^(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(text.trim()))
16
+ throw new Error('Enter a nonnegative measurement, or leave it blank for UNKNOWN.');
17
+ const number = Number(text);
18
+ if (
19
+ !Number.isFinite(number) ||
20
+ number > maximum ||
21
+ (number === 0 && /[1-9]/.test(text.trim().split(/[eE]/)[0] ?? '')) ||
22
+ (positive ? number <= 0 : number < 0)
23
+ )
24
+ throw new Error(
25
+ `Measurement must be ${positive ? 'positive' : 'nonnegative'}, finite and no greater than ${maximum}.`
26
+ );
27
+ return number;
28
+ }
29
+ function choice<T extends string>(text: string, choices: readonly T[], label: string): T {
30
+ const found = choices.find((item) => item === text);
31
+ if (!found) throw new Error(`Choose ${label}.`);
32
+ return found;
33
+ }
34
+ export function readTripDraft(
35
+ values: FormData,
36
+ ids: string[],
37
+ basis: MtwTripUtilizationBasis,
38
+ coverage: MtwTripUtilizationCoverage,
39
+ evidence: SelectedEvidence[]
40
+ ): TripReportDraft {
41
+ if (!evidence.length) throw new Error('Select exact readable evidence versions for the report.');
42
+ const intervalFrom = freeTimeIso(reuseText(values, 'intervalFrom'));
43
+ const intervalUntil = freeTimeIso(reuseText(values, 'intervalUntil'));
44
+ if (intervalFrom > intervalUntil)
45
+ throw new Error('The report interval must end at or after its start.');
46
+ const segments = ids.map((segmentId, index) => {
47
+ const text = (field: string) => reuseText(values, `${segmentId}.${field}`);
48
+ const observed = text('observedAt');
49
+ const observedAt = observed ? freeTimeIso(observed) : null;
50
+ if (
51
+ basis === 'OBSERVED' &&
52
+ (!observedAt || observedAt < intervalFrom || observedAt > intervalUntil)
53
+ )
54
+ throw new Error(
55
+ `Segment ${index + 1}: observation time must be within the reported interval.`
56
+ );
57
+ return {
58
+ segmentId,
59
+ sequence: index + 1,
60
+ loadedState: choice(
61
+ text('loadedState'),
62
+ ['EMPTY', 'LOADED', 'UNKNOWN'] as const,
63
+ 'explicit load state'
64
+ ),
65
+ distanceKm: tripQuantity(text('distanceKm'), 10000000),
66
+ payloadKg: tripQuantity(text('payloadKg'), 1000000000),
67
+ payloadCapacityKg: tripQuantity(text('payloadCapacityKg'), 1000000000, true),
68
+ cubeM3: tripQuantity(text('cubeM3'), 1000000000),
69
+ cubeCapacityM3: tripQuantity(text('cubeCapacityM3'), 1000000000, true),
70
+ source: {
71
+ reference: text('reference'),
72
+ revision: text('revision'),
73
+ observedAt,
74
+ distanceBasis: choice(
75
+ text('distanceBasis'),
76
+ basis === 'OBSERVED'
77
+ ? (['MEASURED'] as const)
78
+ : (['PROVIDER_ESTIMATE', 'OPERATOR_ESTIMATE'] as const),
79
+ 'distance source basis'
80
+ ),
81
+ loadBasis: choice(
82
+ text('loadBasis'),
83
+ basis === 'OBSERVED'
84
+ ? (['MEASURED'] as const)
85
+ : (['MEASURED', 'SOURCE_CONFIRMED_PLAN'] as const),
86
+ 'load source basis'
87
+ ),
88
+ capacityBasis: choice(
89
+ text('capacityBasis'),
90
+ ['RATED', 'MEASURED'] as const,
91
+ 'capacity source basis'
92
+ ),
93
+ },
94
+ };
95
+ });
96
+ return {
97
+ tripId: reuseText(values, 'tripReference'),
98
+ basis,
99
+ declaredCoverage: coverage,
100
+ intervalFrom,
101
+ intervalUntil,
102
+ segments,
103
+ evidence: evidence.map(({ fileId, versionId }) => ({ fileId, versionId })),
104
+ };
105
+ }
@@ -0,0 +1,41 @@
1
+ fragment ConditionEvidence on MtwContainerEvidence { fileId versionId sha256Hash checkedAt }
2
+ fragment InspectionSummary on MtwContainerInspection {
3
+ id containerId inspectedAt inspectorActorId templateVersion examinationScheme nextExaminationAt acepReference
4
+ cargoCategory suitability cscPlateVersionId examinationVersionId defectCount severeDefectCount resolvedDefectIds evidence { ...ConditionEvidence }
5
+ }
6
+ fragment HoldSummary on MtwContainerHold {
7
+ id containerId inspectionId reason heldAt status version defectIds releasedAt updatedAt evidence { ...ConditionEvidence }
8
+ }
9
+ fragment QualificationSummary on MtwInspectorQualification {
10
+ id subjectActorId issuerName credentialReference validFrom validUntil scopes status version
11
+ verifierActorId reviewedAt issuerConfirmationReference reviewNote revokedAt revocationReason
12
+ evidence { ...ConditionEvidence } reviewEvidence { ...ConditionEvidence }
13
+ }
14
+ query ConditionContainers($pagination: MtwContainerPagination) {
15
+ mtwContainerPage(pagination: $pagination) { items { id containerNumber equipmentType } hasMore nextOffset }
16
+ }
17
+ query ConditionInspections($containerId: ID!, $pagination: MtwContainerPagination) {
18
+ mtwContainerInspectionPage(containerId: $containerId, pagination: $pagination) { items { ...InspectionSummary } hasMore nextOffset }
19
+ }
20
+ query ConditionHolds($containerId: ID!, $pagination: MtwContainerPagination) {
21
+ mtwContainerHoldPage(containerId: $containerId, pagination: $pagination) { items { ...HoldSummary } hasMore nextOffset }
22
+ }
23
+ query ConditionDefects($inspectionId: ID!, $pagination: MtwContainerPagination) {
24
+ mtwContainerDefectPage(inspectionId: $inspectionId, pagination: $pagination) { items { id code severity details } hasMore nextOffset }
25
+ }
26
+ query ConditionRepairs($holdId: ID!, $pagination: MtwContainerPagination) {
27
+ mtwContainerRepairPage(holdId: $holdId, pagination: $pagination) { items { id completedAt workDescription defectIds evidence { ...ConditionEvidence } } hasMore nextOffset }
28
+ }
29
+ query ConditionReleases($containerId: ID!, $pagination: MtwContainerPagination) {
30
+ mtwContainerReleaseDecisionPage(containerId: $containerId, pagination: $pagination) { items { id holdId inspectionId qualificationId resolutionReview decidedAt evidence { ...ConditionEvidence } } hasMore nextOffset }
31
+ }
32
+ query ConditionQualifications($pagination: MtwContainerPagination) {
33
+ mtwContainerQualificationPage(pagination: $pagination) { items { ...QualificationSummary } hasMore nextOffset }
34
+ }
35
+ mutation RecordInspection($input: RecordMtwContainerInspectionInput!) { recordMtwContainerInspection(input: $input) { ...InspectionSummary } }
36
+ mutation CreateConditionHold($input: HoldMtwContainerInput!) { holdMtwContainer(input: $input) { ...HoldSummary } }
37
+ mutation RecordConditionRepair($input: RecordMtwContainerRepairInput!) { recordMtwContainerRepair(input: $input) { id } }
38
+ mutation SubmitInspectorQualification($input: SubmitMtwInspectorQualificationInput!) { submitMtwInspectorQualification(input: $input) { ...QualificationSummary } }
39
+ mutation ReviewInspectorQualification($input: VerifyMtwInspectorQualificationInput!) { verifyMtwInspectorQualification(input: $input) { ...QualificationSummary } }
40
+ mutation RevokeInspectorQualification($input: RevokeMtwInspectorQualificationInput!) { revokeMtwInspectorQualification(input: $input) { ...QualificationSummary } }
41
+ mutation ReleaseConditionHold($input: ReleaseMtwContainerHoldInput!) { releaseMtwContainerHold(input: $input) { id decidedAt } }