@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.
- package/dist-lib/components/AfrondWachtrijCard.d.ts +2 -0
- package/dist-lib/components/AfrondWachtrijCard.d.ts.map +1 -0
- package/dist-lib/components/AfrondWachtrijCard.js +27 -0
- package/dist-lib/components/BeladingsafwijkingenCard.d.ts +2 -0
- package/dist-lib/components/BeladingsafwijkingenCard.d.ts.map +1 -0
- package/dist-lib/components/BeladingsafwijkingenCard.js +44 -0
- package/dist-lib/components/FlowCanvas.d.ts +34 -0
- package/dist-lib/components/FlowCanvas.d.ts.map +1 -0
- package/dist-lib/components/FlowCanvas.js +490 -0
- package/dist-lib/components/FlowOrders.d.ts +8 -0
- package/dist-lib/components/FlowOrders.d.ts.map +1 -0
- package/dist-lib/components/FlowOrders.js +171 -0
- package/dist-lib/components/FlowPage.d.ts +2 -0
- package/dist-lib/components/FlowPage.d.ts.map +1 -0
- package/dist-lib/components/FlowPage.js +310 -0
- package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
- package/dist-lib/components/GeblokkeerdeOrdersCard.js +21 -2
- package/dist-lib/components/InklapbaarVenster.d.ts +9 -0
- package/dist-lib/components/InklapbaarVenster.d.ts.map +1 -0
- package/dist-lib/components/InklapbaarVenster.js +10 -0
- package/dist-lib/components/KardekkingCard.d.ts +2 -0
- package/dist-lib/components/KardekkingCard.d.ts.map +1 -0
- package/dist-lib/components/KardekkingCard.js +29 -0
- package/dist-lib/components/LogistiekEnginePage.d.ts.map +1 -1
- package/dist-lib/components/LogistiekEnginePage.js +15 -3
- package/dist-lib/components/LogistiekEngineQueuePage.d.ts +2 -0
- package/dist-lib/components/LogistiekEngineQueuePage.d.ts.map +1 -0
- package/dist-lib/components/LogistiekEngineQueuePage.js +13 -0
- package/dist-lib/components/NodeTracePanel.d.ts +14 -0
- package/dist-lib/components/NodeTracePanel.d.ts.map +1 -0
- package/dist-lib/components/NodeTracePanel.js +46 -0
- package/dist-lib/components/OrderJourneyBar.d.ts +9 -0
- package/dist-lib/components/OrderJourneyBar.d.ts.map +1 -0
- package/dist-lib/components/OrderJourneyBar.js +26 -0
- package/dist-lib/components/OrderLogboek.d.ts +10 -0
- package/dist-lib/components/OrderLogboek.d.ts.map +1 -0
- package/dist-lib/components/OrderLogboek.js +92 -0
- package/dist-lib/components/OrderStopBanner.d.ts +12 -0
- package/dist-lib/components/OrderStopBanner.d.ts.map +1 -0
- package/dist-lib/components/OrderStopBanner.js +36 -0
- package/dist-lib/components/OrderTraceDetails.d.ts +22 -0
- package/dist-lib/components/OrderTraceDetails.d.ts.map +1 -0
- package/dist-lib/components/OrderTraceDetails.js +88 -0
- package/dist-lib/components/PlanWachtrijPage.d.ts +2 -0
- package/dist-lib/components/PlanWachtrijPage.d.ts.map +1 -0
- package/dist-lib/components/PlanWachtrijPage.js +99 -0
- package/dist-lib/components/PlannerDiffCard.d.ts +2 -0
- package/dist-lib/components/PlannerDiffCard.d.ts.map +1 -0
- package/dist-lib/components/PlannerDiffCard.js +25 -0
- package/dist-lib/components/RegiePage.d.ts.map +1 -1
- package/dist-lib/components/RegiePage.js +28 -78
- package/dist-lib/components/TaakGezondheidCard.d.ts +2 -0
- package/dist-lib/components/TaakGezondheidCard.d.ts.map +1 -0
- package/dist-lib/components/TaakGezondheidCard.js +31 -0
- package/dist-lib/components/WerktijdenCard.d.ts +2 -0
- package/dist-lib/components/WerktijdenCard.d.ts.map +1 -0
- package/dist-lib/components/WerktijdenCard.js +37 -0
- package/dist-lib/components/WerkwijzeHerindelingCard.d.ts.map +1 -1
- package/dist-lib/components/WerkwijzeHerindelingCard.js +100 -6
- package/dist-lib/hooks/useAfrondWachtrij.d.ts +28 -0
- package/dist-lib/hooks/useAfrondWachtrij.d.ts.map +1 -0
- package/dist-lib/hooks/useAfrondWachtrij.js +88 -0
- package/dist-lib/hooks/useBeladingsafwijkingen.d.ts +39 -0
- package/dist-lib/hooks/useBeladingsafwijkingen.d.ts.map +1 -0
- package/dist-lib/hooks/useBeladingsafwijkingen.js +119 -0
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +7 -0
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
- package/dist-lib/hooks/useGeblokkeerdeOrders.js +28 -2
- package/dist-lib/hooks/useLogisticsTrace.d.ts +78 -0
- package/dist-lib/hooks/useLogisticsTrace.d.ts.map +1 -0
- package/dist-lib/hooks/useLogisticsTrace.js +152 -0
- package/dist-lib/hooks/useOrderNodeTrace.d.ts +11 -0
- package/dist-lib/hooks/useOrderNodeTrace.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderNodeTrace.js +26 -0
- package/dist-lib/hooks/useOrderTrace.d.ts +74 -0
- package/dist-lib/hooks/useOrderTrace.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderTrace.js +134 -0
- package/dist-lib/hooks/useOrderVersies.d.ts +47 -0
- package/dist-lib/hooks/useOrderVersies.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderVersies.js +194 -0
- package/dist-lib/hooks/usePlanWachtrij.d.ts +33 -0
- package/dist-lib/hooks/usePlanWachtrij.d.ts.map +1 -0
- package/dist-lib/hooks/usePlanWachtrij.js +104 -0
- package/dist-lib/hooks/useRecalcJob.js +1 -1
- package/dist-lib/hooks/useRuleEngine.d.ts +1 -0
- package/dist-lib/hooks/useRuleEngine.d.ts.map +1 -1
- package/dist-lib/hooks/useRuleEngine.js +1 -0
- package/dist-lib/hooks/useShippingNoteDiagnose.d.ts +20 -0
- package/dist-lib/hooks/useShippingNoteDiagnose.d.ts.map +1 -0
- package/dist-lib/hooks/useShippingNoteDiagnose.js +52 -0
- package/dist-lib/hooks/useShippingNoteStatus.d.ts +29 -0
- package/dist-lib/hooks/useShippingNoteStatus.d.ts.map +1 -0
- package/dist-lib/hooks/useShippingNoteStatus.js +107 -0
- package/dist-lib/hooks/useTaakGezondheid.d.ts +16 -0
- package/dist-lib/hooks/useTaakGezondheid.d.ts.map +1 -0
- package/dist-lib/hooks/useTaakGezondheid.js +43 -0
- package/dist-lib/hooks/useWerktijden.d.ts +33 -0
- package/dist-lib/hooks/useWerktijden.d.ts.map +1 -0
- package/dist-lib/hooks/useWerktijden.js +88 -0
- package/dist-lib/hooks/useWerkwijzeStatus.d.ts +12 -1
- package/dist-lib/hooks/useWerkwijzeStatus.d.ts.map +1 -1
- package/dist-lib/hooks/useWerkwijzeStatus.js +61 -5
- package/dist-lib/index.d.ts +23 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +23 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +4993 -459
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +4993 -459
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +4993 -459
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.js +8 -1
- package/dist-lib/integrations/supabase/types.d.ts +5022 -432
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/attachAuthToken.js +1 -1
- package/dist-lib/lib/bufferDecision.test.d.ts +2 -0
- package/dist-lib/lib/bufferDecision.test.d.ts.map +1 -0
- package/dist-lib/lib/bufferDecision.test.js +104 -0
- package/dist-lib/lib/cartCoverage.functions.d.ts +30820 -0
- package/dist-lib/lib/cartCoverage.functions.d.ts.map +1 -0
- package/dist-lib/lib/cartCoverage.functions.js +20 -0
- package/dist-lib/lib/cartPlanRequests.server.d.ts +1 -1
- package/dist-lib/lib/cartPlanRequests.server.d.ts.map +1 -1
- package/dist-lib/lib/cartPlanRequests.server.js +49 -8
- package/dist-lib/lib/floridayDocuments.functions.d.ts +13623 -21
- package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.functions.js +5 -5
- package/dist-lib/lib/floridayDocuments.server.d.ts +14 -0
- package/dist-lib/lib/floridayDocuments.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.server.js +58 -0
- package/dist-lib/lib/floridayGuard.server.d.ts +1 -1
- package/dist-lib/lib/floridayGuard.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayGuard.server.js +6 -3
- package/dist-lib/lib/floridayPush.functions.d.ts +4993 -459
- package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.functions.js +3 -3
- package/dist-lib/lib/flowGraph.d.ts +43 -0
- package/dist-lib/lib/flowGraph.d.ts.map +1 -0
- package/dist-lib/lib/flowGraph.js +153 -0
- package/dist-lib/lib/flowJourney.d.ts +40 -0
- package/dist-lib/lib/flowJourney.d.ts.map +1 -0
- package/dist-lib/lib/flowJourney.js +156 -0
- package/dist-lib/lib/flowNodes.d.ts +26 -0
- package/dist-lib/lib/flowNodes.d.ts.map +1 -0
- package/dist-lib/lib/flowNodes.js +64 -0
- package/dist-lib/lib/flowRoute.d.ts +117 -0
- package/dist-lib/lib/flowRoute.d.ts.map +1 -0
- package/dist-lib/lib/flowRoute.js +583 -0
- package/dist-lib/lib/flowTree.d.ts +149 -0
- package/dist-lib/lib/flowTree.d.ts.map +1 -0
- package/dist-lib/lib/flowTree.js +908 -0
- package/dist-lib/lib/foutTekst.d.ts +4 -0
- package/dist-lib/lib/foutTekst.d.ts.map +1 -0
- package/dist-lib/lib/foutTekst.js +43 -0
- package/dist-lib/lib/handlers/index.d.ts +1 -0
- package/dist-lib/lib/handlers/index.d.ts.map +1 -1
- package/dist-lib/lib/handlers/index.js +1 -0
- package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts +3 -0
- package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts.map +1 -0
- package/dist-lib/lib/handlers/logistics-shipping-note-now.server.js +100 -0
- package/dist-lib/lib/handlers/logistics-tick.server.d.ts +2 -0
- package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
- package/dist-lib/lib/handlers/logistics-tick.server.js +153 -2
- package/dist-lib/lib/handlers/logistics-tick.test.d.ts +2 -0
- package/dist-lib/lib/handlers/logistics-tick.test.d.ts.map +1 -0
- package/dist-lib/lib/handlers/logistics-tick.test.js +63 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts +2 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanner.js +18 -0
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +22705 -35
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.functions.js +7 -7
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts +33 -12
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +534 -228
- package/dist-lib/lib/logisticsPlanner.d.ts.map +1 -1
- package/dist-lib/lib/logisticsPlanner.js +14 -2
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +9082 -14
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.functions.js +4 -4
- package/dist-lib/lib/logisticsRecalcJob.server.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.server.js +17 -2
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts +4993 -459
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalculate.functions.js +2 -2
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +893 -0
- package/dist-lib/lib/nodeTrace.d.ts +65 -0
- package/dist-lib/lib/nodeTrace.d.ts.map +1 -0
- package/dist-lib/lib/nodeTrace.js +182 -0
- package/dist-lib/lib/pickQueueCleanup.server.d.ts +14 -0
- package/dist-lib/lib/pickQueueCleanup.server.d.ts.map +1 -0
- package/dist-lib/lib/pickQueueCleanup.server.js +80 -0
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +164 -3
- package/dist-lib/lib/plannerDiff.d.ts +37 -0
- package/dist-lib/lib/plannerDiff.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.functions.d.ts +30821 -0
- package/dist-lib/lib/plannerDiff.functions.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.functions.js +21 -0
- package/dist-lib/lib/plannerDiff.js +74 -0
- package/dist-lib/lib/plannerDiff.server.d.ts +5 -0
- package/dist-lib/lib/plannerDiff.server.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.server.js +60 -0
- package/dist-lib/lib/plannerDiff.test.d.ts +2 -0
- package/dist-lib/lib/plannerDiff.test.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.test.js +41 -0
- package/dist-lib/lib/resolveBuffer.test.d.ts +2 -0
- package/dist-lib/lib/resolveBuffer.test.d.ts.map +1 -0
- package/dist-lib/lib/resolveBuffer.test.js +38 -0
- package/dist-lib/lib/ruleEngineImpact.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineImpact.js +11 -4
- package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineSchema.js +102 -6
- package/dist-lib/lib/ruleEngineWizard.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineWizard.js +3 -1
- package/dist-lib/lib/shippingNoteQueue.server.d.ts +18 -0
- package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -0
- package/dist-lib/lib/shippingNoteQueue.server.js +304 -0
- package/dist-lib/lib/stopReden.d.ts +43 -0
- package/dist-lib/lib/stopReden.d.ts.map +1 -0
- package/dist-lib/lib/stopReden.js +197 -0
- package/dist-lib/lib/taskCounts.d.ts +2 -0
- package/dist-lib/lib/taskCounts.d.ts.map +1 -0
- package/dist-lib/lib/taskCounts.js +15 -0
- package/dist-lib/lib/taskCounts.test.d.ts +2 -0
- package/dist-lib/lib/taskCounts.test.d.ts.map +1 -0
- package/dist-lib/lib/taskCounts.test.js +12 -0
- package/dist-lib/lib/trace.server.d.ts +75 -0
- package/dist-lib/lib/trace.server.d.ts.map +1 -0
- package/dist-lib/lib/trace.server.js +78 -0
- package/dist-lib/lib/vakUitleg.d.ts +19 -0
- package/dist-lib/lib/vakUitleg.d.ts.map +1 -0
- package/dist-lib/lib/vakUitleg.js +133 -0
- package/package.json +158 -131
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts +0 -2
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts.map +0 -1
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.js +0 -41
- package/dist-lib/integrations/supabase/client.d.ts +0 -20293
- package/dist-lib/integrations/supabase/client.d.ts.map +0 -1
- 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 +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 @@
|
|
|
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,
|
|
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:
|
|
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
|
-
|
|
313
|
+
queueCleanup,
|
|
314
|
+
orphanPrintJobs,
|
|
315
|
+
}, { status: shippingNotesOk ? 200 : 500, headers: CORS_HEADERS });
|
|
165
316
|
}
|
|
@@ -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":"AAYA,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,aAAa,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAGD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gFAAgF;IAChF,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;CACnE;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAGD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"loadCarrierPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanner.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,aAAa,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAGD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,gFAAgF;IAChF,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;CACnE;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAGD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAmVD,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,aAAa,CA4IhG"}
|
|
@@ -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);
|