@flowselections/logistiek-engine 1.0.34 → 1.0.89

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 (244) hide show
  1. package/dist-lib/components/AfrondWachtrijCard.d.ts +2 -0
  2. package/dist-lib/components/AfrondWachtrijCard.d.ts.map +1 -0
  3. package/dist-lib/components/AfrondWachtrijCard.js +27 -0
  4. package/dist-lib/components/BeladingsafwijkingenCard.d.ts +2 -0
  5. package/dist-lib/components/BeladingsafwijkingenCard.d.ts.map +1 -0
  6. package/dist-lib/components/BeladingsafwijkingenCard.js +44 -0
  7. package/dist-lib/components/FlowCanvas.d.ts +34 -0
  8. package/dist-lib/components/FlowCanvas.d.ts.map +1 -0
  9. package/dist-lib/components/FlowCanvas.js +490 -0
  10. package/dist-lib/components/FlowOrders.d.ts +8 -0
  11. package/dist-lib/components/FlowOrders.d.ts.map +1 -0
  12. package/dist-lib/components/FlowOrders.js +171 -0
  13. package/dist-lib/components/FlowPage.d.ts +2 -0
  14. package/dist-lib/components/FlowPage.d.ts.map +1 -0
  15. package/dist-lib/components/FlowPage.js +310 -0
  16. package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
  17. package/dist-lib/components/GeblokkeerdeOrdersCard.js +21 -2
  18. package/dist-lib/components/InklapbaarVenster.d.ts +9 -0
  19. package/dist-lib/components/InklapbaarVenster.d.ts.map +1 -0
  20. package/dist-lib/components/InklapbaarVenster.js +10 -0
  21. package/dist-lib/components/KardekkingCard.d.ts +2 -0
  22. package/dist-lib/components/KardekkingCard.d.ts.map +1 -0
  23. package/dist-lib/components/KardekkingCard.js +29 -0
  24. package/dist-lib/components/LogistiekEnginePage.d.ts.map +1 -1
  25. package/dist-lib/components/LogistiekEnginePage.js +15 -3
  26. package/dist-lib/components/LogistiekEngineQueuePage.d.ts +2 -0
  27. package/dist-lib/components/LogistiekEngineQueuePage.d.ts.map +1 -0
  28. package/dist-lib/components/LogistiekEngineQueuePage.js +13 -0
  29. package/dist-lib/components/NodeTracePanel.d.ts +14 -0
  30. package/dist-lib/components/NodeTracePanel.d.ts.map +1 -0
  31. package/dist-lib/components/NodeTracePanel.js +46 -0
  32. package/dist-lib/components/OrderJourneyBar.d.ts +9 -0
  33. package/dist-lib/components/OrderJourneyBar.d.ts.map +1 -0
  34. package/dist-lib/components/OrderJourneyBar.js +26 -0
  35. package/dist-lib/components/OrderLogboek.d.ts +10 -0
  36. package/dist-lib/components/OrderLogboek.d.ts.map +1 -0
  37. package/dist-lib/components/OrderLogboek.js +92 -0
  38. package/dist-lib/components/OrderStopBanner.d.ts +12 -0
  39. package/dist-lib/components/OrderStopBanner.d.ts.map +1 -0
  40. package/dist-lib/components/OrderStopBanner.js +36 -0
  41. package/dist-lib/components/OrderTraceDetails.d.ts +22 -0
  42. package/dist-lib/components/OrderTraceDetails.d.ts.map +1 -0
  43. package/dist-lib/components/OrderTraceDetails.js +88 -0
  44. package/dist-lib/components/PlanWachtrijPage.d.ts +2 -0
  45. package/dist-lib/components/PlanWachtrijPage.d.ts.map +1 -0
  46. package/dist-lib/components/PlanWachtrijPage.js +99 -0
  47. package/dist-lib/components/PlannerDiffCard.d.ts +2 -0
  48. package/dist-lib/components/PlannerDiffCard.d.ts.map +1 -0
  49. package/dist-lib/components/PlannerDiffCard.js +25 -0
  50. package/dist-lib/components/RegiePage.d.ts.map +1 -1
  51. package/dist-lib/components/RegiePage.js +28 -78
  52. package/dist-lib/components/TaakGezondheidCard.d.ts +2 -0
  53. package/dist-lib/components/TaakGezondheidCard.d.ts.map +1 -0
  54. package/dist-lib/components/TaakGezondheidCard.js +31 -0
  55. package/dist-lib/components/WerktijdenCard.d.ts +2 -0
  56. package/dist-lib/components/WerktijdenCard.d.ts.map +1 -0
  57. package/dist-lib/components/WerktijdenCard.js +37 -0
  58. package/dist-lib/components/WerkwijzeHerindelingCard.d.ts.map +1 -1
  59. package/dist-lib/components/WerkwijzeHerindelingCard.js +100 -6
  60. package/dist-lib/hooks/useAfrondWachtrij.d.ts +28 -0
  61. package/dist-lib/hooks/useAfrondWachtrij.d.ts.map +1 -0
  62. package/dist-lib/hooks/useAfrondWachtrij.js +88 -0
  63. package/dist-lib/hooks/useBeladingsafwijkingen.d.ts +39 -0
  64. package/dist-lib/hooks/useBeladingsafwijkingen.d.ts.map +1 -0
  65. package/dist-lib/hooks/useBeladingsafwijkingen.js +119 -0
  66. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +7 -0
  67. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
  68. package/dist-lib/hooks/useGeblokkeerdeOrders.js +28 -2
  69. package/dist-lib/hooks/useLogisticsTrace.d.ts +78 -0
  70. package/dist-lib/hooks/useLogisticsTrace.d.ts.map +1 -0
  71. package/dist-lib/hooks/useLogisticsTrace.js +152 -0
  72. package/dist-lib/hooks/useOrderNodeTrace.d.ts +11 -0
  73. package/dist-lib/hooks/useOrderNodeTrace.d.ts.map +1 -0
  74. package/dist-lib/hooks/useOrderNodeTrace.js +26 -0
  75. package/dist-lib/hooks/useOrderTrace.d.ts +74 -0
  76. package/dist-lib/hooks/useOrderTrace.d.ts.map +1 -0
  77. package/dist-lib/hooks/useOrderTrace.js +134 -0
  78. package/dist-lib/hooks/useOrderVersies.d.ts +47 -0
  79. package/dist-lib/hooks/useOrderVersies.d.ts.map +1 -0
  80. package/dist-lib/hooks/useOrderVersies.js +194 -0
  81. package/dist-lib/hooks/usePlanWachtrij.d.ts +33 -0
  82. package/dist-lib/hooks/usePlanWachtrij.d.ts.map +1 -0
  83. package/dist-lib/hooks/usePlanWachtrij.js +104 -0
  84. package/dist-lib/hooks/useRecalcJob.js +1 -1
  85. package/dist-lib/hooks/useRuleEngine.d.ts +1 -0
  86. package/dist-lib/hooks/useRuleEngine.d.ts.map +1 -1
  87. package/dist-lib/hooks/useRuleEngine.js +1 -0
  88. package/dist-lib/hooks/useShippingNoteDiagnose.d.ts +20 -0
  89. package/dist-lib/hooks/useShippingNoteDiagnose.d.ts.map +1 -0
  90. package/dist-lib/hooks/useShippingNoteDiagnose.js +52 -0
  91. package/dist-lib/hooks/useShippingNoteStatus.d.ts +29 -0
  92. package/dist-lib/hooks/useShippingNoteStatus.d.ts.map +1 -0
  93. package/dist-lib/hooks/useShippingNoteStatus.js +107 -0
  94. package/dist-lib/hooks/useTaakGezondheid.d.ts +16 -0
  95. package/dist-lib/hooks/useTaakGezondheid.d.ts.map +1 -0
  96. package/dist-lib/hooks/useTaakGezondheid.js +43 -0
  97. package/dist-lib/hooks/useWerktijden.d.ts +33 -0
  98. package/dist-lib/hooks/useWerktijden.d.ts.map +1 -0
  99. package/dist-lib/hooks/useWerktijden.js +88 -0
  100. package/dist-lib/hooks/useWerkwijzeStatus.d.ts +12 -1
  101. package/dist-lib/hooks/useWerkwijzeStatus.d.ts.map +1 -1
  102. package/dist-lib/hooks/useWerkwijzeStatus.js +61 -5
  103. package/dist-lib/index.d.ts +23 -0
  104. package/dist-lib/index.d.ts.map +1 -1
  105. package/dist-lib/index.js +23 -0
  106. package/dist-lib/integrations/supabase/auth-middleware.d.ts +4993 -459
  107. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  108. package/dist-lib/integrations/supabase/client.server.d.ts +4993 -459
  109. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  110. package/dist-lib/integrations/supabase/client.server.js +1 -1
  111. package/dist-lib/integrations/supabase/moduleClient.d.ts +4993 -459
  112. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  113. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +1 -1
  114. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
  115. package/dist-lib/integrations/supabase/previewAuthStorage.js +8 -1
  116. package/dist-lib/integrations/supabase/types.d.ts +5022 -432
  117. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  118. package/dist-lib/lib/attachAuthToken.js +1 -1
  119. package/dist-lib/lib/bufferDecision.test.d.ts +2 -0
  120. package/dist-lib/lib/bufferDecision.test.d.ts.map +1 -0
  121. package/dist-lib/lib/bufferDecision.test.js +104 -0
  122. package/dist-lib/lib/cartCoverage.functions.d.ts +30820 -0
  123. package/dist-lib/lib/cartCoverage.functions.d.ts.map +1 -0
  124. package/dist-lib/lib/cartCoverage.functions.js +20 -0
  125. package/dist-lib/lib/cartPlanRequests.server.d.ts +1 -1
  126. package/dist-lib/lib/cartPlanRequests.server.d.ts.map +1 -1
  127. package/dist-lib/lib/cartPlanRequests.server.js +49 -8
  128. package/dist-lib/lib/floridayDocuments.functions.d.ts +13623 -21
  129. package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
  130. package/dist-lib/lib/floridayDocuments.functions.js +5 -5
  131. package/dist-lib/lib/floridayDocuments.server.d.ts +14 -0
  132. package/dist-lib/lib/floridayDocuments.server.d.ts.map +1 -1
  133. package/dist-lib/lib/floridayDocuments.server.js +58 -0
  134. package/dist-lib/lib/floridayGuard.server.d.ts +1 -1
  135. package/dist-lib/lib/floridayGuard.server.d.ts.map +1 -1
  136. package/dist-lib/lib/floridayGuard.server.js +6 -3
  137. package/dist-lib/lib/floridayPush.functions.d.ts +4993 -459
  138. package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
  139. package/dist-lib/lib/floridayPush.functions.js +3 -3
  140. package/dist-lib/lib/flowGraph.d.ts +43 -0
  141. package/dist-lib/lib/flowGraph.d.ts.map +1 -0
  142. package/dist-lib/lib/flowGraph.js +153 -0
  143. package/dist-lib/lib/flowJourney.d.ts +40 -0
  144. package/dist-lib/lib/flowJourney.d.ts.map +1 -0
  145. package/dist-lib/lib/flowJourney.js +156 -0
  146. package/dist-lib/lib/flowNodes.d.ts +26 -0
  147. package/dist-lib/lib/flowNodes.d.ts.map +1 -0
  148. package/dist-lib/lib/flowNodes.js +64 -0
  149. package/dist-lib/lib/flowRoute.d.ts +117 -0
  150. package/dist-lib/lib/flowRoute.d.ts.map +1 -0
  151. package/dist-lib/lib/flowRoute.js +583 -0
  152. package/dist-lib/lib/flowTree.d.ts +149 -0
  153. package/dist-lib/lib/flowTree.d.ts.map +1 -0
  154. package/dist-lib/lib/flowTree.js +908 -0
  155. package/dist-lib/lib/foutTekst.d.ts +4 -0
  156. package/dist-lib/lib/foutTekst.d.ts.map +1 -0
  157. package/dist-lib/lib/foutTekst.js +43 -0
  158. package/dist-lib/lib/handlers/index.d.ts +1 -0
  159. package/dist-lib/lib/handlers/index.d.ts.map +1 -1
  160. package/dist-lib/lib/handlers/index.js +1 -0
  161. package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts +3 -0
  162. package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts.map +1 -0
  163. package/dist-lib/lib/handlers/logistics-shipping-note-now.server.js +100 -0
  164. package/dist-lib/lib/handlers/logistics-tick.server.d.ts +2 -0
  165. package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
  166. package/dist-lib/lib/handlers/logistics-tick.server.js +153 -2
  167. package/dist-lib/lib/handlers/logistics-tick.test.d.ts +2 -0
  168. package/dist-lib/lib/handlers/logistics-tick.test.d.ts.map +1 -0
  169. package/dist-lib/lib/handlers/logistics-tick.test.js +63 -0
  170. package/dist-lib/lib/loadCarrierPlanner.d.ts +2 -0
  171. package/dist-lib/lib/loadCarrierPlanner.d.ts.map +1 -1
  172. package/dist-lib/lib/loadCarrierPlanner.js +18 -0
  173. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +22705 -35
  174. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
  175. package/dist-lib/lib/loadCarrierPlanning.functions.js +7 -7
  176. package/dist-lib/lib/loadCarrierPlanning.server.d.ts +33 -12
  177. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  178. package/dist-lib/lib/loadCarrierPlanning.server.js +534 -228
  179. package/dist-lib/lib/logisticsPlanner.d.ts.map +1 -1
  180. package/dist-lib/lib/logisticsPlanner.js +14 -2
  181. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +9082 -14
  182. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
  183. package/dist-lib/lib/logisticsRecalcJob.functions.js +4 -4
  184. package/dist-lib/lib/logisticsRecalcJob.server.d.ts.map +1 -1
  185. package/dist-lib/lib/logisticsRecalcJob.server.js +17 -2
  186. package/dist-lib/lib/logisticsRecalculate.functions.d.ts +4993 -459
  187. package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
  188. package/dist-lib/lib/logisticsRecalculate.functions.js +2 -2
  189. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  190. package/dist-lib/lib/modulePrompts.js +893 -0
  191. package/dist-lib/lib/nodeTrace.d.ts +65 -0
  192. package/dist-lib/lib/nodeTrace.d.ts.map +1 -0
  193. package/dist-lib/lib/nodeTrace.js +182 -0
  194. package/dist-lib/lib/pickQueueCleanup.server.d.ts +14 -0
  195. package/dist-lib/lib/pickQueueCleanup.server.d.ts.map +1 -0
  196. package/dist-lib/lib/pickQueueCleanup.server.js +80 -0
  197. package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
  198. package/dist-lib/lib/planQueue.server.js +164 -3
  199. package/dist-lib/lib/plannerDiff.d.ts +37 -0
  200. package/dist-lib/lib/plannerDiff.d.ts.map +1 -0
  201. package/dist-lib/lib/plannerDiff.functions.d.ts +30821 -0
  202. package/dist-lib/lib/plannerDiff.functions.d.ts.map +1 -0
  203. package/dist-lib/lib/plannerDiff.functions.js +21 -0
  204. package/dist-lib/lib/plannerDiff.js +74 -0
  205. package/dist-lib/lib/plannerDiff.server.d.ts +5 -0
  206. package/dist-lib/lib/plannerDiff.server.d.ts.map +1 -0
  207. package/dist-lib/lib/plannerDiff.server.js +60 -0
  208. package/dist-lib/lib/plannerDiff.test.d.ts +2 -0
  209. package/dist-lib/lib/plannerDiff.test.d.ts.map +1 -0
  210. package/dist-lib/lib/plannerDiff.test.js +41 -0
  211. package/dist-lib/lib/resolveBuffer.test.d.ts +2 -0
  212. package/dist-lib/lib/resolveBuffer.test.d.ts.map +1 -0
  213. package/dist-lib/lib/resolveBuffer.test.js +38 -0
  214. package/dist-lib/lib/ruleEngineImpact.d.ts.map +1 -1
  215. package/dist-lib/lib/ruleEngineImpact.js +11 -4
  216. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  217. package/dist-lib/lib/ruleEngineSchema.js +102 -6
  218. package/dist-lib/lib/ruleEngineWizard.d.ts.map +1 -1
  219. package/dist-lib/lib/ruleEngineWizard.js +3 -1
  220. package/dist-lib/lib/shippingNoteQueue.server.d.ts +18 -0
  221. package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -0
  222. package/dist-lib/lib/shippingNoteQueue.server.js +304 -0
  223. package/dist-lib/lib/stopReden.d.ts +43 -0
  224. package/dist-lib/lib/stopReden.d.ts.map +1 -0
  225. package/dist-lib/lib/stopReden.js +197 -0
  226. package/dist-lib/lib/taskCounts.d.ts +2 -0
  227. package/dist-lib/lib/taskCounts.d.ts.map +1 -0
  228. package/dist-lib/lib/taskCounts.js +15 -0
  229. package/dist-lib/lib/taskCounts.test.d.ts +2 -0
  230. package/dist-lib/lib/taskCounts.test.d.ts.map +1 -0
  231. package/dist-lib/lib/taskCounts.test.js +12 -0
  232. package/dist-lib/lib/trace.server.d.ts +75 -0
  233. package/dist-lib/lib/trace.server.d.ts.map +1 -0
  234. package/dist-lib/lib/trace.server.js +78 -0
  235. package/dist-lib/lib/vakUitleg.d.ts +19 -0
  236. package/dist-lib/lib/vakUitleg.d.ts.map +1 -0
  237. package/dist-lib/lib/vakUitleg.js +133 -0
  238. package/package.json +158 -131
  239. package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts +0 -2
  240. package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts.map +0 -1
  241. package/dist-lib/components/rule-engine/FloridayConnectionBanner.js +0 -41
  242. package/dist-lib/integrations/supabase/client.d.ts +0 -20293
  243. package/dist-lib/integrations/supabase/client.d.ts.map +0 -1
  244. package/dist-lib/integrations/supabase/client.js +0 -13
@@ -0,0 +1,4 @@
1
+ export declare function foutTekst(ruw: string | null | undefined): string | null;
2
+ /** Of de melding een technische stukloop is, of "alleen" een tijdslimiet/regel. */
3
+ export declare function foutSoort(ruw: string | null | undefined): string | null;
4
+ //# sourceMappingURL=foutTekst.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"foutTekst.d.ts","sourceRoot":"","sources":["../../src/lib/foutTekst.ts"],"names":[],"mappings":"AAQA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAwBvE;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAMvE"}
@@ -0,0 +1,43 @@
1
+ // ============================================================================
2
+ // src/lib/foutTekst.ts — technische foutmeldingen in gewone taal
3
+ // ============================================================================
4
+ // Dezelfde vertaling als in de database (logistics_plan_error_text), zodat ook
5
+ // oudere, al vastgelegde meldingen leesbaar op het scherm komen. De ruwe tekst
6
+ // blijft altijd beschikbaar onder "Technische details".
7
+ // ============================================================================
8
+ export function foutTekst(ruw) {
9
+ const t = typeof ruw === "string" ? ruw.trim() : "";
10
+ if (!t)
11
+ return null;
12
+ const l = t.toLowerCase();
13
+ if (l === "deadline") {
14
+ return "De planronde was vol voordat deze order aan de beurt was. De order schuift door naar de volgende ronde.";
15
+ }
16
+ if (l.includes("statement timeout")) {
17
+ return "Het opslaan van de karrenindeling duurde te lang en is door de database afgebroken. Er is niets half opgeslagen; de order wordt opnieuw geprobeerd.";
18
+ }
19
+ if (l.includes("order_cart_items_cart_id_fkey")) {
20
+ return "Een kar uit deze indeling bestond niet meer toen de inhoud werd weggeschreven. De indeling wordt opnieuw gemaakt.";
21
+ }
22
+ if (l.includes("order_carts_buffer_id_fkey")) {
23
+ return "De buffer waarop deze karren stonden bestaat niet meer. De order wordt los ingedeeld.";
24
+ }
25
+ if (l.includes("foreign key constraint")) {
26
+ return "Een gegeven waar de indeling naar verwees bestond niet meer op het moment van opslaan. De indeling wordt opnieuw gemaakt.";
27
+ }
28
+ if (l.includes("deadlock")) {
29
+ return "Twee bewerkingen wachtten op elkaar bij het opslaan. De order wordt opnieuw geprobeerd.";
30
+ }
31
+ return t;
32
+ }
33
+ /** Of de melding een technische stukloop is, of "alleen" een tijdslimiet/regel. */
34
+ export function foutSoort(ruw) {
35
+ const l = (ruw ?? "").toLowerCase();
36
+ if (!l.trim())
37
+ return null;
38
+ if (l === "deadline" || l.includes("statement timeout") || l.includes("deadlock"))
39
+ return "regel";
40
+ if (l.includes("grens van") || l.includes("geen enkele kar"))
41
+ return "configuratie";
42
+ return "technisch";
43
+ }
@@ -1,2 +1,3 @@
1
1
  export { handleLogisticsTick } from "./logistics-tick.server.js";
2
+ export { handleShippingNoteNow } from "./logistics-shipping-note-now.server.js";
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC"}
@@ -2,3 +2,4 @@
2
2
  // src/lib/handlers/index.ts — server-route handlers voor shells
3
3
  // ============================================================================
4
4
  export { handleLogisticsTick } from "./logistics-tick.server.js";
5
+ export { handleShippingNoteNow } from "./logistics-shipping-note-now.server.js";
@@ -0,0 +1,3 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ export declare function handleShippingNoteNow(request: Request, supabase: SupabaseClient): Promise<Response>;
3
+ //# sourceMappingURL=logistics-shipping-note-now.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logistics-shipping-note-now.server.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/logistics-shipping-note-now.server.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAQ5D,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAiGnB"}
@@ -0,0 +1,100 @@
1
+ // ============================================================================
2
+ // src/lib/handlers/logistics-shipping-note-now.server.ts
3
+ // Verzendbrief direct ophalen op het moment dat de pakbon naar het pickstation
4
+ // wordt gestuurd, in plaats van te wachten op de volgende ronde van de cron.
5
+ //
6
+ // Alleen-lezen richting Floriday: er wordt geen status gewijzigd en geen order
7
+ // of kar afgehandeld. Het maken van de printopdracht is idempotent, dus vaker
8
+ // aanroepen levert nooit een dubbele verzendbrief op.
9
+ // Geen omgevingswaarden in deze code: de sleutel komt uit de omgeving.
10
+ // ============================================================================
11
+ const CORS_HEADERS = {
12
+ "Access-Control-Allow-Origin": "*",
13
+ "Access-Control-Allow-Headers": "apikey, authorization, content-type",
14
+ "Access-Control-Allow-Methods": "POST, OPTIONS",
15
+ };
16
+ export async function handleShippingNoteNow(request, supabase) {
17
+ if (request.method === "OPTIONS") {
18
+ return new Response(null, { status: 204, headers: CORS_HEADERS });
19
+ }
20
+ const apikey = request.headers.get("apikey") ??
21
+ request.headers.get("authorization")?.replace(/^Bearer /i, "") ??
22
+ "";
23
+ const expected = (process.env["SUPABASE_PUBLISHABLE_KEY"] ??
24
+ process.env["SUPABASE_ANON_KEY"] ??
25
+ "").replace(/^["']|["']$/g, "");
26
+ if (!expected || apikey !== expected) {
27
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
28
+ status: 401,
29
+ headers: { "Content-Type": "application/json", ...CORS_HEADERS },
30
+ });
31
+ }
32
+ try {
33
+ const { runShippingNoteQueue } = await import("../shippingNoteQueue.server.js");
34
+ if (typeof runShippingNoteQueue !== "function") {
35
+ throw new Error("Deze versie van de Logistiek Engine bevat geen verzendbriefverwerking. Werk de module bij.");
36
+ }
37
+ // 1. Inhaalslag: pakbonnen die nog geen verzendbriefaanvraag hebben er
38
+ // alsnog bij zetten. Idempotent, dus nooit een tweede aanvraag.
39
+ let backfill = null;
40
+ try {
41
+ const { data } = await supabase.rpc("logistics_ensure_shipping_notes", { p_limit: 500 });
42
+ backfill = data ?? null;
43
+ }
44
+ catch {
45
+ backfill = null;
46
+ }
47
+ // 1b. Foutieve eigen verzendbrieven bij Floriday-orders opruimen.
48
+ try {
49
+ await supabase.rpc("logistics_fix_wrong_shipping_notes");
50
+ }
51
+ catch {
52
+ /* opschonen mag de ronde niet blokkeren */
53
+ }
54
+ // 2. Alle openstaande aanvragen mogen nu meteen worden opgepakt.
55
+ let wake = null;
56
+ try {
57
+ const { data } = await supabase.rpc("logistics_shipping_notes_wake_all");
58
+ wake = data ?? null;
59
+ }
60
+ catch {
61
+ wake = null;
62
+ }
63
+ // 3. Gebundeld verwerken tot alles op is of het tijdbudget vol is; de knop
64
+ // hoeft niet te wachten tot de laatste ronde klaar is.
65
+ const totaal = { claimed: 0, printed: 0, waiting: 0, retrying: 0, failed: 0, errors: [] };
66
+ const deadline = Date.now() + 20000;
67
+ let rondes = 0;
68
+ while (Date.now() < deadline && rondes < 40) {
69
+ const ronde = await runShippingNoteQueue(supabase, { limit: 10 });
70
+ rondes++;
71
+ totaal.claimed += ronde.claimed;
72
+ totaal.printed += ronde.printed;
73
+ totaal.waiting += ronde.waiting;
74
+ totaal.retrying += ronde.retrying;
75
+ totaal.failed += ronde.failed;
76
+ if (Array.isArray(ronde.errors))
77
+ totaal.errors.push(...ronde.errors);
78
+ if (ronde.claimed === 0)
79
+ break;
80
+ }
81
+ return Response.json({
82
+ ok: true,
83
+ shippingNotes: {
84
+ found: totaal.claimed,
85
+ printed: totaal.printed,
86
+ waitingForFloriday: totaal.waiting,
87
+ retrying: totaal.retrying,
88
+ failed: totaal.failed,
89
+ printJobsCreated: totaal.printed,
90
+ rounds: rondes,
91
+ backfill,
92
+ wake,
93
+ errors: totaal.errors.slice(0, 20),
94
+ },
95
+ }, { headers: CORS_HEADERS });
96
+ }
97
+ catch (e) {
98
+ return Response.json({ ok: false, error: String(e?.message ?? e) }, { status: 500, headers: CORS_HEADERS });
99
+ }
100
+ }
@@ -1,3 +1,5 @@
1
1
  import type { SupabaseClient } from "@supabase/supabase-js";
2
2
  export declare function handleLogisticsTick(request: Request, supabase: SupabaseClient): Promise<Response>;
3
+ /** Vaste sleutel van het rondeslot; gelijk aan de check in logistics_plan_kick(). */
4
+ export declare const TICK_ROUND_LOCK_KEY = "tick:ronde";
3
5
  //# sourceMappingURL=logistics-tick.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logistics-tick.server.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/logistics-tick.server.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAQ5D,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CA4KnB"}
1
+ {"version":3,"file":"logistics-tick.server.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/logistics-tick.server.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAQ5D,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CA2EnB;AAED,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,eAAe,CAAC"}
@@ -39,6 +39,51 @@ export async function handleLogisticsTick(request, supabase) {
39
39
  catch {
40
40
  // Een ontbrekende hartslag mag de verwerking nooit tegenhouden.
41
41
  }
42
+ // Rondeslot: nooit twee tick-rondes tegelijk (minuut-cron én wek-aanroep
43
+ // komen hier allebei binnen). Hergebruikt het bestaande planslot met
44
+ // vervaltijd. Fail-closed: bij twijfel wordt de ronde overgeslagen; de
45
+ // volgende minuut-ronde is het vangnet.
46
+ const roundId = crypto.randomUUID();
47
+ let held = false;
48
+ let lockUnknown = false;
49
+ try {
50
+ const { data, error } = await supabase.rpc("logistics_plan_lock_acquire", {
51
+ _key: TICK_ROUND_LOCK_KEY,
52
+ _owner: roundId,
53
+ _ttl_seconds: 120,
54
+ });
55
+ if (error)
56
+ lockUnknown = true;
57
+ held = !error && data === true;
58
+ }
59
+ catch {
60
+ lockUnknown = true;
61
+ held = false;
62
+ }
63
+ if (!held) {
64
+ if (lockUnknown) {
65
+ console.warn("[logistics-tick] rondeslot kon niet worden vastgesteld; ronde overgeslagen");
66
+ }
67
+ return Response.json({ ok: true, skipped: lockUnknown ? "slot_onbekend" : "ronde_loopt_al" }, { status: 200, headers: CORS_HEADERS });
68
+ }
69
+ try {
70
+ return await runTickRound(supabase, tickJob);
71
+ }
72
+ finally {
73
+ try {
74
+ await supabase.rpc("logistics_plan_lock_release", {
75
+ _key: TICK_ROUND_LOCK_KEY,
76
+ _owner: roundId,
77
+ });
78
+ }
79
+ catch {
80
+ // Vrijgeven mag de uitkomst niet omgooien; de lease verloopt vanzelf.
81
+ }
82
+ }
83
+ }
84
+ /** Vaste sleutel van het rondeslot; gelijk aan de check in logistics_plan_kick(). */
85
+ export const TICK_ROUND_LOCK_KEY = "tick:ronde";
86
+ async function runTickRound(supabase, tickJob) {
42
87
  // Meerdere batches per aanroep, met een ruime marge tot de time-out.
43
88
  const deadline = Date.now() + 8000;
44
89
  let last = null;
@@ -72,6 +117,16 @@ export async function handleLogisticsTick(request, supabase) {
72
117
  catch (e) {
73
118
  orphans = { error: String(e?.message ?? e) };
74
119
  }
120
+ // Vangnet: recente orders die nooit in de planwachtrij kwamen alsnog
121
+ // aanmelden, zodat ze in deze zelfde ronde nog worden ingedeeld.
122
+ let reconciledOrders = null;
123
+ try {
124
+ const { data, error } = await supabase.rpc("logistics_reconcile_missing_plan_queue");
125
+ reconciledOrders = error ? { error: error.message } : data;
126
+ }
127
+ catch (e) {
128
+ reconciledOrders = { error: String(e?.message ?? e) };
129
+ }
75
130
  // Planwachtrij: nieuwe/gewijzigde orders incrementeel indelen.
76
131
  let plan = null;
77
132
  try {
@@ -105,6 +160,17 @@ export async function handleLogisticsTick(request, supabase) {
105
160
  catch (e) {
106
161
  buffers = { error: String(e?.message ?? e) };
107
162
  }
163
+ // Na het sluiten of losmaken van een buffer: de pickwachtrij opnieuw vullen,
164
+ // zodat elke eenheid (ook een losgekoppelde order) zijn eigen karaantallen
165
+ // uit het actuele karplan meekrijgt.
166
+ let queueRefresh = null;
167
+ try {
168
+ const { data, error } = await supabase.rpc("logistics_sync_pick_queue");
169
+ queueRefresh = error ? { error: error.message } : data;
170
+ }
171
+ catch (e) {
172
+ queueRefresh = { error: String(e?.message ?? e) };
173
+ }
108
174
  // Floriday-pushwachtrij verwerken binnen dezelfde aanroep, met eigen marge.
109
175
  let push = null;
110
176
  try {
@@ -124,6 +190,53 @@ export async function handleLogisticsTick(request, supabase) {
124
190
  catch (e) {
125
191
  control = { error: String(e?.message ?? e) };
126
192
  }
193
+ // Verzendbrief die meelift met een geprinte pakbon (Floriday-orders).
194
+ // Deze verwerking is verplicht: ontbreekt zij, dan is de draaiende versie te
195
+ // oud en moet de tick dat als fout melden in plaats van "succes".
196
+ let shippingNotes = null;
197
+ let shippingNotesOk = false;
198
+ let shippingNotesBackfill = null;
199
+ try {
200
+ // Inhaalslag: pakbonnen die al in het pickstation staan alsnog van een
201
+ // verzendbrief voorzien. Idempotent, dus veilig bij elke tick.
202
+ const { data: backfill } = await supabase.rpc("logistics_ensure_shipping_notes", {
203
+ p_limit: 200,
204
+ });
205
+ shippingNotesBackfill = backfill ?? null;
206
+ // Zelfherstel: een eigen verzendbrief die bij een Floriday-order hoort wordt
207
+ // geannuleerd en vervangen door de officiele Floriday-aanvraag.
208
+ try {
209
+ await supabase.rpc("logistics_fix_wrong_shipping_notes");
210
+ }
211
+ catch {
212
+ /* zelfherstel mag de ronde niet blokkeren */
213
+ }
214
+ const { runShippingNoteQueue } = await import("../shippingNoteQueue.server.js");
215
+ if (typeof runShippingNoteQueue !== "function") {
216
+ throw new Error("Deze versie van de Logistiek Engine bevat geen verzendbriefverwerking. Werk de module bij.");
217
+ }
218
+ const result = (await runShippingNoteQueue(supabase, { limit: 10 }));
219
+ const verwacht = ["claimed", "printed", "waiting", "retrying", "failed"];
220
+ const ontbreekt = verwacht.filter((k) => typeof result?.[k] !== "number");
221
+ if (ontbreekt.length > 0) {
222
+ throw new Error(`De verzendbriefverwerking levert geen volledige telling (mist: ${ontbreekt.join(", ")}). Werk de module bij.`);
223
+ }
224
+ shippingNotes = {
225
+ found: result["claimed"],
226
+ printed: result["printed"],
227
+ waitingForFloriday: result["waiting"],
228
+ retrying: result["retrying"],
229
+ failed: result["failed"],
230
+ printJobsCreated: result["printed"],
231
+ backfill: shippingNotesBackfill,
232
+ errors: result["errors"] ?? [],
233
+ };
234
+ shippingNotesOk = true;
235
+ }
236
+ catch (e) {
237
+ shippingNotes = { error: String(e?.message ?? e) };
238
+ shippingNotesOk = false;
239
+ }
127
240
  // Seintjes van de pickschermen: karplan ontbreekt. Direct oppakken.
128
241
  let cartPlanRequests = null;
129
242
  try {
@@ -133,6 +246,28 @@ export async function handleLogisticsTick(request, supabase) {
133
246
  catch (e) {
134
247
  cartPlanRequests = { error: String(e?.message ?? e) };
135
248
  }
249
+ // In de karwerkwijze vervangen concrete karregels de oude orderregel. Een
250
+ // reeds geprinte orderregel blijft als historie bestaan, maar mag niet meer
251
+ // als actieve printregel met een verouderde status op het scherm staan.
252
+ let queueCleanup = null;
253
+ try {
254
+ const { retireSupersededOrderRows } = await import("../pickQueueCleanup.server.js");
255
+ queueCleanup = await retireSupersededOrderRows(supabase);
256
+ }
257
+ catch (e) {
258
+ queueCleanup = { error: String(e?.message ?? e) };
259
+ }
260
+ // Pakbonnen zonder kar, of van een kar die na een herindeling niet meer
261
+ // bestaat, kunnen nooit een barcode krijgen. Die worden hier afgesloten met
262
+ // een leesbare reden in plaats van eeuwig te blijven wachten.
263
+ let orphanPrintJobs = null;
264
+ try {
265
+ const { data, error } = await supabase.rpc("logistics_cleanup_orphan_print_jobs");
266
+ orphanPrintJobs = error ? { error: error.message } : data;
267
+ }
268
+ catch (e) {
269
+ orphanPrintJobs = { error: String(e?.message ?? e) };
270
+ }
136
271
  // Barcodeverzoeken van de Layout maker: de Engine bepaalt de kar en levert
137
272
  // de vaste barcode terug in het verzoek én in de printopdracht. Kan het
138
273
  // niet, dan wordt het verzoek geannuleerd met een reden (fail closed).
@@ -146,20 +281,36 @@ export async function handleLogisticsTick(request, supabase) {
146
281
  catch (e) {
147
282
  barcodes = { error: String(e?.message ?? e) };
148
283
  }
284
+ // Laadtoestand per eenheid bijwerken, zodat de pickschermen niet hoeven te
285
+ // wisselen tussen teksten maar een vaste toestand met reden zien.
286
+ let planState = null;
287
+ try {
288
+ const { data, error } = await supabase.rpc("logistics_refresh_plan_state", { p_limit: 500 });
289
+ planState = error ? { error: error.message } : data;
290
+ }
291
+ catch (e) {
292
+ planState = { error: String(e?.message ?? e) };
293
+ }
149
294
  return Response.json({
150
- ok: true,
295
+ ok: shippingNotesOk,
296
+ planState,
151
297
  ticks,
152
298
  status: last?.status ?? "idle",
153
299
  phase: last?.phase ?? null,
154
300
  processed: last?.processed ?? 0,
301
+ reconciledOrders,
155
302
  plan,
156
303
  orphans,
157
304
  bufferQueue,
158
305
  buffers,
306
+ queueRefresh,
159
307
  pickupMoments,
160
308
  push,
161
309
  control,
310
+ shippingNotes,
162
311
  barcodes,
163
312
  cartPlanRequests,
164
- }, { headers: CORS_HEADERS });
313
+ queueCleanup,
314
+ orphanPrintJobs,
315
+ }, { status: shippingNotesOk ? 200 : 500, headers: CORS_HEADERS });
165
316
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=logistics-tick.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logistics-tick.test.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/logistics-tick.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,63 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ const tickJob = vi.fn(async () => null);
3
+ const runPlanQueue = vi.fn(async () => ({}));
4
+ vi.mock("../logisticsRecalcJob.server.js", () => ({ tickJob }));
5
+ vi.mock("../planQueue.server.js", () => ({ runPlanQueue, prunePlanQueue: vi.fn() }));
6
+ import { handleLogisticsTick, TICK_ROUND_LOCK_KEY } from "./logistics-tick.server";
7
+ const KEY = "test-key";
8
+ function makeClient(acquire) {
9
+ const calls = [];
10
+ const rpc = vi.fn(async (fn, args) => {
11
+ calls.push({ fn, args });
12
+ if (fn === "logistics_plan_lock_acquire")
13
+ return acquire();
14
+ return { data: null, error: null };
15
+ });
16
+ return { client: { rpc }, calls };
17
+ }
18
+ const req = () => new Request("http://x/api/public/hooks/logistics-recalc-tick", {
19
+ method: "POST",
20
+ headers: { apikey: KEY },
21
+ });
22
+ beforeEach(() => {
23
+ process.env["SUPABASE_PUBLISHABLE_KEY"] = KEY;
24
+ tickJob.mockClear();
25
+ runPlanQueue.mockClear();
26
+ });
27
+ describe("tick-rondeslot", () => {
28
+ it("slaat een tweede ronde over als er al een ronde loopt", async () => {
29
+ const { client, calls } = makeClient(async () => ({ data: false, error: null }));
30
+ const res = await handleLogisticsTick(req(), client);
31
+ expect(await res.json()).toMatchObject({ skipped: "ronde_loopt_al" });
32
+ expect(tickJob).not.toHaveBeenCalled();
33
+ expect(runPlanQueue).not.toHaveBeenCalled();
34
+ const fns = calls.map((c) => c.fn);
35
+ expect(fns).not.toContain("logistics_buffer_detach_late_orders");
36
+ expect(fns).not.toContain("logistics_sync_pick_queue");
37
+ expect(fns).not.toContain("logistics_plan_lock_release");
38
+ });
39
+ it("slaat over (fail-closed) als het slot niet kan worden vastgesteld", async () => {
40
+ const { client } = makeClient(async () => ({ data: null, error: { message: "boom" } }));
41
+ const res = await handleLogisticsTick(req(), client);
42
+ expect(await res.json()).toMatchObject({ skipped: "slot_onbekend" });
43
+ expect(tickJob).not.toHaveBeenCalled();
44
+ expect(runPlanQueue).not.toHaveBeenCalled();
45
+ });
46
+ it("draait de ronde met slot en geeft het slot daarna vrij, ook bij een fout", async () => {
47
+ tickJob.mockImplementationOnce(async () => {
48
+ throw new Error("stap faalt");
49
+ });
50
+ const { client, calls } = makeClient(async () => ({ data: true, error: null }));
51
+ await expect(handleLogisticsTick(req(), client)).rejects.toThrow("stap faalt");
52
+ const acq = calls.find((c) => c.fn === "logistics_plan_lock_acquire");
53
+ const rel = calls.find((c) => c.fn === "logistics_plan_lock_release");
54
+ expect(rel).toBeTruthy();
55
+ expect(rel.args._key).toBe(TICK_ROUND_LOCK_KEY);
56
+ expect(rel.args._owner).toBe(acq.args._owner);
57
+ });
58
+ it("voert de planwachtrij uit als het slot is verkregen", async () => {
59
+ const { client } = makeClient(async () => ({ data: true, error: null }));
60
+ await handleLogisticsTick(req(), client);
61
+ expect(runPlanQueue).toHaveBeenCalledTimes(1);
62
+ });
63
+ });
@@ -38,6 +38,8 @@ export interface PlannerOptions {
38
38
  maxOrders?: number | null;
39
39
  maxCustomers?: number | null;
40
40
  oneCustomerPerLayer?: boolean;
41
+ /** Maximaal aantal verschillende klanten binnen één laag. */
42
+ maxCustomersPerLayer?: number | null;
41
43
  /** Vanaf zoveel volle lagen krijgt een partij altijd een eigen ladingdrager. */
42
44
  ownCarrierFromLayers?: number | null;
43
45
  sortOrder?: "location" | "customer" | "product" | "size" | "none";
@@ -1 +1 @@
1
- {"version":3,"file":"loadCarrierPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loadCarrierPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanner.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,7 @@ function placeAsFreshLayer(cart, batch, batchIdx, crates) {
43
43
  heightPct: batch.layerHeightPct,
44
44
  crateShare: crates / batch.cratesPerLayer,
45
45
  entries: [{ batchIdx, crates }],
46
+ customerIds: new Set(batch.input.customer_id ? [batch.input.customer_id] : []),
46
47
  });
47
48
  cart.totalHeightPct += batch.layerHeightPct;
48
49
  return true;
@@ -65,6 +66,19 @@ function placeInLayer(cart, batch, batchIdx, crates, r) {
65
66
  // REGEL 4 — dezelfde partij niet twee keer in dezelfde laag
66
67
  if (layer.entries.some((e) => e.batchIdx === batchIdx))
67
68
  continue;
69
+ // REGEL 4b — maximaal aantal verschillende klanten op één laag
70
+ const layerCustomerLimit = r.opts.oneCustomerPerLayer
71
+ ? 1
72
+ : r.opts.maxCustomersPerLayer && r.opts.maxCustomersPerLayer > 0
73
+ ? r.opts.maxCustomersPerLayer
74
+ : null;
75
+ const customerId = batch.input.customer_id ?? null;
76
+ if (layerCustomerLimit != null &&
77
+ customerId &&
78
+ !layer.customerIds.has(customerId) &&
79
+ layer.customerIds.size >= layerCustomerLimit) {
80
+ continue;
81
+ }
68
82
  // REGEL 5 — vloeroppervlak van de laag mag niet over 100%
69
83
  if (layer.crateShare + partyShare > 1 + EPS)
70
84
  continue;
@@ -74,6 +88,8 @@ function placeInLayer(cart, batch, batchIdx, crates, r) {
74
88
  if (cart.totalHeightPct + heightDelta > 100 + EPS)
75
89
  continue;
76
90
  layer.entries.push({ batchIdx, crates });
91
+ if (customerId)
92
+ layer.customerIds.add(customerId);
77
93
  layer.crateShare += partyShare;
78
94
  layer.heightPct = newHeight;
79
95
  cart.totalHeightPct += heightDelta;
@@ -265,6 +281,7 @@ export function planLoadUnits(inputs, options) {
265
281
  neverMixProductIds: options.neverMixProductIds ?? new Set(),
266
282
  maxOrders: options.maxOrders ?? null,
267
283
  maxCustomers: options.maxCustomers ?? null,
284
+ maxCustomersPerLayer: options.maxCustomersPerLayer ?? null,
268
285
  oneCustomerPerLayer: options.oneCustomerPerLayer ?? false,
269
286
  ownCarrierFromLayers: options.ownCarrierFromLayers ?? null,
270
287
  sortOrder: options.sortOrder ?? "none",
@@ -356,6 +373,7 @@ export function planLoadUnits(inputs, options) {
356
373
  heightPct: 100,
357
374
  crateShare: 1,
358
375
  entries: [{ batchIdx: bi, crates: batch.cratesRemaining }],
376
+ customerIds: new Set(batch.input.customer_id ? [batch.input.customer_id] : []),
359
377
  });
360
378
  cart.totalHeightPct = 100;
361
379
  registerPlacement(cart, batch, batch.cratesRemaining);