@flowselections/logistiek-engine 1.0.120 → 1.0.124

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 (38) hide show
  1. package/dist-lib/components/BeheerPage.d.ts +2 -0
  2. package/dist-lib/components/BeheerPage.d.ts.map +1 -0
  3. package/dist-lib/components/BeheerPage.js +73 -0
  4. package/dist-lib/components/FlowPage.d.ts +1 -0
  5. package/dist-lib/components/FlowPage.d.ts.map +1 -1
  6. package/dist-lib/components/FlowPage.js +7 -1
  7. package/dist-lib/components/LogistiekEnginePage.d.ts.map +1 -1
  8. package/dist-lib/components/LogistiekEnginePage.js +14 -2
  9. package/dist-lib/components/ModulePromptsPage.d.ts +1 -0
  10. package/dist-lib/components/ModulePromptsPage.d.ts.map +1 -1
  11. package/dist-lib/components/ModulePromptsPage.js +7 -1
  12. package/dist-lib/components/RolPoort.d.ts +7 -0
  13. package/dist-lib/components/RolPoort.d.ts.map +1 -0
  14. package/dist-lib/components/RolPoort.js +12 -0
  15. package/dist-lib/components/RuleEnginePage.d.ts +2 -1
  16. package/dist-lib/components/RuleEnginePage.d.ts.map +1 -1
  17. package/dist-lib/components/RuleEnginePage.js +7 -1
  18. package/dist-lib/components/WerkwijzeHerindelingCard.d.ts.map +1 -1
  19. package/dist-lib/components/WerkwijzeHerindelingCard.js +2 -2
  20. package/dist-lib/hooks/useEngineRollen.d.ts +14 -0
  21. package/dist-lib/hooks/useEngineRollen.d.ts.map +1 -0
  22. package/dist-lib/hooks/useEngineRollen.js +50 -0
  23. package/dist-lib/index.d.ts +3 -0
  24. package/dist-lib/index.d.ts.map +1 -1
  25. package/dist-lib/index.js +3 -0
  26. package/dist-lib/integrations/supabase/types.d.ts +543 -3
  27. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  28. package/dist-lib/lib/floridayPush.server.d.ts.map +1 -1
  29. package/dist-lib/lib/floridayPush.server.js +10 -0
  30. package/dist-lib/lib/handlers/logistics-tick.server.js +13 -0
  31. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  32. package/dist-lib/lib/modulePrompts.js +154 -0
  33. package/dist-lib/lib/moduleVersion.d.ts +1 -1
  34. package/dist-lib/lib/moduleVersion.js +1 -1
  35. package/dist-lib/lib/shippingNoteQueue.server.d.ts +5 -0
  36. package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -1
  37. package/dist-lib/lib/shippingNoteQueue.server.js +61 -0
  38. package/package.json +6 -1
@@ -1 +1 @@
1
- {"version":3,"file":"floridayPush.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayPush.server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAc/C,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD;AAaD,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,OAAO,2BAA2B,EAAE,WAAW,EAAE,CAAC;CACjE;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAUnE;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,cAAc,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CACN;IACE,EAAE,EAAE,IAAI,CAAC;IACT,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,cAAc,EAAE,OAAO,2BAA2B,EAAE,oBAAoB,EAAE,CAAC;IAC3E,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAC7C,CAoEA;AAED,8CAA8C;AAC9C,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAyHtB;AAQD,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;AA6BD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,OAAO,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAElF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,eAAe,CAAC,CA+K1B;AAQD,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3F"}
1
+ {"version":3,"file":"floridayPush.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayPush.server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAc/C,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD;AAaD,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,OAAO,2BAA2B,EAAE,WAAW,EAAE,CAAC;CACjE;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAUnE;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,cAAc,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CACN;IACE,EAAE,EAAE,IAAI,CAAC;IACT,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,cAAc,EAAE,OAAO,2BAA2B,EAAE,oBAAoB,EAAE,CAAC;IAC3E,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAC7C,CAoEA;AAED,8CAA8C;AAC9C,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAyHtB;AAQD,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;AA6BD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,OAAO,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAElF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,eAAe,CAAC,CAwL1B;AAQD,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3F"}
@@ -280,6 +280,16 @@ export async function runFloridayPushQueue(sb, opts = {}) {
280
280
  notApplicable: 0,
281
281
  unknown: 0,
282
282
  };
283
+ // Poort 0: alleen als de Engine de belading verstuurt (instelling
284
+ // belading_verstuurder = engine). Ontbreekt of anders: niets versturen.
285
+ try {
286
+ const { data } = await sb.rpc("logistics_belading_verstuurder");
287
+ if (data !== "engine")
288
+ return out;
289
+ }
290
+ catch {
291
+ return out;
292
+ }
283
293
  // Poort 1: staat de schakelaar uit, dan verwerken we de wachtrij niet.
284
294
  // Fail closed: onleesbaar betekent niet versturen.
285
295
  try {
@@ -139,6 +139,19 @@ async function runTickRound(supabase, tickJob, ident) {
139
139
  try {
140
140
  const { runPlanQueue, prunePlanQueue } = await import("../planQueue.server.js");
141
141
  plan = await runPlanQueue(supabase, { deadlineAt: Date.now() + 15000 });
142
+ // M12: een wek-aanroep kan net vóór de order zichtbaar of vrij is binnenkomen
143
+ // (rij nog vergrendeld door de aanmaakende transactie). Dan kort nawachten
144
+ // in plaats van tot de volgende minuutronde te wachten. Begrensd: max. 3 x.
145
+ for (let poging = 0; poging < 3; poging++) {
146
+ const claimed = Number(plan?.claimed ?? 0);
147
+ if (claimed > 0)
148
+ break;
149
+ const { data: due, error: dueError } = await supabase.rpc("logistics_plan_due_count");
150
+ if (dueError || Number(due ?? 0) === 0)
151
+ break;
152
+ await new Promise((r) => setTimeout(r, 1500));
153
+ plan = await runPlanQueue(supabase, { deadlineAt: Date.now() + 15000 });
154
+ }
142
155
  await prunePlanQueue(supabase);
143
156
  }
144
157
  catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"modulePrompts.d.ts","sourceRoot":"","sources":["../../src/lib/modulePrompts.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;CAIvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AA6lJD,eAAO,MAAM,cAAc,EAAE,YAAY,EAUL,CAAC;AAErC,gEAAgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,CAmBR;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,MAAM,CAiB9C;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,eAAe,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAIR"}
1
+ {"version":3,"file":"modulePrompts.d.ts","sourceRoot":"","sources":["../../src/lib/modulePrompts.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;CAIvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AA2vJD,eAAO,MAAM,cAAc,EAAE,YAAY,EAUL,CAAC;AAErC,gEAAgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,CAmBR;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,MAAM,CAiB9C;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,eAAe,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAIR"}
@@ -905,6 +905,79 @@ CONTROLELIJST
905
905
  [ ] Een order zonder bufferpartners telt nog net zo als voorheen.
906
906
  [ ] "Geen kar" verschijnt alleen als geen actieve regel op een kar ligt.`,
907
907
  },
908
+ {
909
+ number: 20,
910
+ title: "Indelingsstatus per order tonen (Geen indeling)",
911
+ date: "2026-10-12",
912
+ withSharedContract: false,
913
+ summary: "Toon per order de indelingsstatus uit logistics_order_plan_coverage, ook voor orders op een gedeelde bufferkar.",
914
+ body: `WAAROM
915
+ Een order kan op een gedeelde bufferkar staan; de kar hangt dan aan de buffer
916
+ en niet aan de order. Tellen via order_carts.order_id geeft dan ten onrechte
917
+ "geen kar". De Engine levert nu per order één leesfunctie die dit wél goed doet.
918
+
919
+ WAT JE GEBRUIKT
920
+ select public.logistics_order_plan_coverage(<order-id>)
921
+
922
+ Antwoord (jsonb):
923
+ - state: ingedeeld | deels | geen_indeling | geen_regels; label in gewone taal
924
+ ("Ingedeeld", "Deels ingedeeld", "Geen indeling").
925
+ - progressPct en reason.
926
+ - carts[]: cartId, cartNumber, bufferId, shared (gedeelde bufferkar),
927
+ carrierType, lines[] met alleen de regels van DEZE order (orderItemId,
928
+ productId, productName, crates, boxes).
929
+ - pickRows[]: queueItemId, documentNumber, cartId, printedAt, completedAt.
930
+ - pickStatus: geen_pickrij | open | bezig | gepickt; pickedAt bij gepickt.
931
+
932
+ REGELS
933
+ - Alleen voor ingelogde gebruikers (niet anoniem).
934
+ - Lees nooit zelf order_carts of order_cart_items; gebruik deze functie.
935
+ - Velden kunnen ontbreken of leeg zijn: altijd Array.isArray-controle.
936
+ - Geen URL's, sleutels, project-refs, klantnamen of vaste database-id's in code
937
+ of migraties.
938
+
939
+ CONTROLELIJST
940
+ [ ] Verkoop toont per order het label; bij Geen indeling in rood met de reden.
941
+ [ ] Een order op een gedeelde bufferkar toont "Ingedeeld", niet "geen kar".
942
+ `,
943
+ },
944
+ {
945
+ number: 21,
946
+ title: "Indelingsstatus voor een lijst orders in één aanroep",
947
+ date: "2026-10-13",
948
+ withSharedContract: false,
949
+ summary: "Laad de indelingsstatus van een overzicht van orders met één aanroep van logistics_order_plan_coverage_list in plaats van één aanroep per order.",
950
+ body: `WAAROM
951
+ Prompt 20 levert de status per order. Een overzicht van honderden orders met
952
+ honderden losse aanroepen is traag (gemeten: 90 orders los ruim 15 seconden).
953
+ De lijstversie geeft dezelfde status voor maximaal 1.000 orders in één aanroep
954
+ (gemeten: 500 order-id's in circa 0,3 seconde).
955
+
956
+ WAT JE GEBRUIKT
957
+ supabase.rpc('logistics_order_plan_coverage_list', { p_order_ids: [<order-id>, ...] })
958
+
959
+ Antwoord: één rij per gevraagde order:
960
+ - order_id, order_number, buffer_id
961
+ - state: ingedeeld | deels | geen_indeling | geen_regels | onbekend
962
+ - label ("Ingedeeld", "Deels ingedeeld", "Geen indeling", "Geen regels", "Onbekend")
963
+ - progress_pct, reason (gewone taal, leeg bij Ingedeeld)
964
+ - cart_count, pick_row_count
965
+ - pick_status: geen_pickrij | open | bezig | gepickt; picked_at bij gepickt
966
+ Geen karren of regels; die haal je bij het openen van één order met prompt 20.
967
+
968
+ REGELS
969
+ - Alleen voor ingelogde gebruikers (niet anoniem).
970
+ - Maximaal 1.000 order-id's per aanroep; meer geeft een foutmelding. Splits in
971
+ stukken van hooguit 1.000.
972
+ - Altijd Array.isArray-controle op het antwoord.
973
+ - Geen URL's, sleutels, project-refs, klantnamen of vaste database-id's in code.
974
+
975
+ CONTROLELIJST
976
+ [ ] Het orderoverzicht doet één aanroep per (stuk van) 1.000 orders.
977
+ [ ] Labels en status gelijk aan prompt 20 voor dezelfde order.
978
+ [ ] Geen indeling in rood met de reden.
979
+ `,
980
+ },
908
981
  ],
909
982
  },
910
983
  afhandeling: {
@@ -1808,6 +1881,42 @@ CONTROLELIJST
1808
1881
  [ ] Een losgekoppelde order staat als aparte regel met eigen karren in de agenda's.
1809
1882
  [ ] Afgehandelde karren houden hun nummer en blijven zichtbaar in de historie.`,
1810
1883
  },
1884
+ {
1885
+ number: 20,
1886
+ title: "Karren, regels en pickstatus per order voor belading",
1887
+ date: "2026-10-12",
1888
+ withSharedContract: false,
1889
+ summary: "Gebruik logistics_order_plan_coverage voor karren, eigen regels, pickrij en gepickt-tijdstip per order (ook in een buffer).",
1890
+ body: `WAAROM
1891
+ Een order kan op een gedeelde bufferkar staan; de kar hangt dan aan de buffer
1892
+ en niet aan de order. Tellen via order_carts.order_id geeft dan ten onrechte
1893
+ "geen kar". De Engine levert nu per order één leesfunctie die dit wél goed doet.
1894
+
1895
+ WAT JE GEBRUIKT
1896
+ select public.logistics_order_plan_coverage(<order-id>)
1897
+
1898
+ Antwoord (jsonb):
1899
+ - state: ingedeeld | deels | geen_indeling | geen_regels; label in gewone taal
1900
+ ("Ingedeeld", "Deels ingedeeld", "Geen indeling").
1901
+ - progressPct en reason.
1902
+ - carts[]: cartId, cartNumber, bufferId, shared (gedeelde bufferkar),
1903
+ carrierType, lines[] met alleen de regels van DEZE order (orderItemId,
1904
+ productId, productName, crates, boxes).
1905
+ - pickRows[]: queueItemId, documentNumber, cartId, printedAt, completedAt.
1906
+ - pickStatus: geen_pickrij | open | bezig | gepickt; pickedAt bij gepickt.
1907
+
1908
+ REGELS
1909
+ - Alleen voor ingelogde gebruikers (niet anoniem).
1910
+ - Lees nooit zelf order_carts of order_cart_items; gebruik deze functie.
1911
+ - Velden kunnen ontbreken of leeg zijn: altijd Array.isArray-controle.
1912
+ - Geen URL's, sleutels, project-refs, klantnamen of vaste database-id's in code
1913
+ of migraties.
1914
+
1915
+ CONTROLELIJST
1916
+ [ ] Belading per verkooporder gebruikt carts[].lines van deze order, ook in een buffer.
1917
+ [ ] Een order op een gedeelde bufferkar toont "Ingedeeld", niet "geen kar".
1918
+ `,
1919
+ },
1811
1920
  ],
1812
1921
  },
1813
1922
  pickschermen: {
@@ -3465,6 +3574,51 @@ CONTROLELIJST
3465
3574
  [ ] isSet true zonder onderdelen: "onderdelen onbekend", afvinken werkt; isSet false: gewone rij.
3466
3575
  [ ] Typecheck en build:lib geslaagd; meld terug met je pakketversie.`,
3467
3576
  },
3577
+ {
3578
+ number: 42,
3579
+ title: "Gedeelde bufferkar: karplanmelding en verversen bij een vervangen rij",
3580
+ date: "2026-10-13",
3581
+ withSharedContract: false,
3582
+ summary: "pick_report_missing_cart_plan telt gedeelde bufferkarren mee en meldt idempotent; het pickscherm ververst bij een pickrij die niet meer bestaat.",
3583
+ body: `WAAROM
3584
+ Shell-test 13-10 (FO-2601401 t/m -404, één gedeelde kar): het pickscherm hield een
3585
+ verouderde rij vast. pick_queue_cart_plan gaf "Dit document bestaat niet meer" (500)
3586
+ en pick_report_missing_cart_plan gaf 409 (duplicate idempotency key).
3587
+ De Engine heeft de oorzaak aan haar kant hersteld (een gedeelde kar blijft bevroren voor
3588
+ alle orders erop; afmelden geldt voor alle orders op de kar). Deze prompt regelt de
3589
+ kant van Pickschermen.
3590
+
3591
+ 1. pick_report_missing_cart_plan (functie van Pickschermen)
3592
+ - Tel een order als "heeft karplan" als er een kar is met order_id = de order
3593
+ OF een gedeelde kar (order_id leeg, buffer_id gevuld) met een regel van die order:
3594
+ EXISTS (SELECT 1 FROM order_cart_items ci
3595
+ JOIN order_items oi ON oi.id = ci.order_item_id
3596
+ WHERE oi.order_id = ANY(<leden>))
3597
+ Nu telt alleen c.order_id = ANY(<leden>); een gedeelde kar wordt dan ten onrechte
3598
+ als "geen karplan" gemeld.
3599
+ - Maak het aanmaken van de melding idempotent: INSERT ... ON CONFLICT (idempotency_key)
3600
+ DO NOTHING. Nu wordt alleen op open meldingen (processed_at IS NULL) gecontroleerd;
3601
+ bestaat er al een afgehandelde melding met dezelfde sleutel, dan volgt 409.
3602
+ - Beveiliging, search_path en rechten gelijk laten; volledige letterlijke definitie.
3603
+
3604
+ 2. Verversen bij een rij die niet meer bestaat
3605
+ - pick_queue_cart_plan geeft bij een verdwenen rij nu foutcode P0002 met de tekst
3606
+ "Deze pickrij bestaat niet meer (vervangen of afgehandeld); ververs de pickwachtrij."
3607
+ - Vang P0002 (of HTTP 404/500 met die tekst) af: geen rode fout, wel de wachtrij opnieuw
3608
+ laden en de gebruiker de tekst tonen. Een geprinte rij nooit lokaal blijven tonen als
3609
+ hij niet meer in pick_queue staat.
3610
+
3611
+ REGELS
3612
+ - Geen URL's, sleutels, project-refs, klantnamen of vaste id's in code of migraties.
3613
+ - Geen DELETE of UPDATE zonder WHERE.
3614
+ - Test teruggedraaid (safeupdate eerst aantonen), niets printen.
3615
+
3616
+ CONTROLELIJST
3617
+ [ ] Order op een gedeelde kar geeft geen "cartplan.missing"-melding.
3618
+ [ ] Twee keer aanroepen, ook na een afgehandelde melding: geen 409.
3619
+ [ ] Verdwenen rij: wachtrij ververst, duidelijke tekst, geen 500 in beeld.
3620
+ [ ] Meld terug met je pakketversie.`,
3621
+ },
3468
3622
  ],
3469
3623
  },
3470
3624
  scanners: {
@@ -1,2 +1,2 @@
1
- export declare const MODULE_VERSION = "1.0.120";
1
+ export declare const MODULE_VERSION = "1.0.124";
2
2
  //# sourceMappingURL=moduleVersion.d.ts.map
@@ -1,2 +1,2 @@
1
1
  // Automatisch gegenereerd door prebuild:lib; niet handmatig aanpassen.
2
- export const MODULE_VERSION = "1.0.120";
2
+ export const MODULE_VERSION = "1.0.124";
@@ -15,4 +15,9 @@ export interface ShippingNoteRun {
15
15
  export declare function runShippingNoteQueue(sb: SupabaseClient, options?: {
16
16
  limit?: number;
17
17
  }): Promise<ShippingNoteRun>;
18
+ export type BeladingVerstuurder = "engine" | "afhandeling" | null;
19
+ /** Leest module_runtime_config.belading_verstuurder. Onleesbaar of ongeldig = null (fail closed). */
20
+ export declare function leesBeladingVerstuurder(sb: SupabaseClient): Promise<BeladingVerstuurder>;
21
+ export declare function parseBeladingVerstuurder(value: unknown): BeladingVerstuurder;
22
+ export declare function beladingWachtReden(verstuurder: BeladingVerstuurder): string;
18
23
  //# sourceMappingURL=shippingNoteQueue.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shippingNoteQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/shippingNoteQueue.server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAO5D,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAoCD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,eAAe,CAAC,CAiZ1B"}
1
+ {"version":3,"file":"shippingNoteQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/shippingNoteQueue.server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAO5D,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAoCD,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,eAAe,CAAC,CA2b1B;AAMD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAC;AAElE,qGAAqG;AACrG,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAQ9F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAG5E;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,mBAAmB,GAAG,MAAM,CAI3E"}
@@ -123,6 +123,20 @@ export async function runShippingNoteQueue(sb, options = {}) {
123
123
  nextStep: "Gaat vanzelf verder na een goedgekeurde controlescan met de poort open",
124
124
  });
125
125
  };
126
+ // Belading is (nog) niet door Afhandeling verstuurd: wachten zonder poging.
127
+ const houdVastBelading = async (reden) => {
128
+ await sb.rpc("logistics_slip_note_hold_belading", { _id: row.id, _reason: reden });
129
+ run.waiting++;
130
+ await trace(sb, {
131
+ ...basis,
132
+ step: "Wacht op belading door Afhandeling",
133
+ status: "wachtend",
134
+ decision: "wacht_op_belading",
135
+ reason: reden,
136
+ rule: "De Engine verstuurt geen belading; Afhandeling doet dat (instelling belading_verstuurder)",
137
+ nextStep: "Over 2 minuten opnieuw kijken of Floriday de verzendbrief heeft",
138
+ });
139
+ };
126
140
  const wacht = async (reden, klasse) => {
127
141
  const code = definitieveFout(reden);
128
142
  if (code) {
@@ -196,7 +210,28 @@ export async function runShippingNoteQueue(sb, options = {}) {
196
210
  // al een fulfillment-order voor deze pakbon, dan wordt er geen tweede
197
211
  // aangemaakt.
198
212
  let bestaandeFo = String(row.fulfillment_order_id ?? "").trim() || null;
213
+ // Wie verstuurt de belading (fulfillment-order)? Alleen bij 'engine' doet
214
+ // de Engine stap 1. Ontbreekt of ongeldig: fail closed, niets versturen.
215
+ let wachtOpBelading = null;
199
216
  if (!bestaandeFo) {
217
+ const verstuurder = await leesBeladingVerstuurder(sb);
218
+ if (verstuurder !== "engine") {
219
+ wachtOpBelading = beladingWachtReden(verstuurder);
220
+ }
221
+ }
222
+ if (!bestaandeFo && wachtOpBelading) {
223
+ // Goedgekeurde controlescan blijft vereist (ook Floriday-authenticatie eist hem).
224
+ const { data: goedgekeurd } = await sb.rpc("logistics_floriday_order_approved", {
225
+ _order_ref: row.order_number,
226
+ });
227
+ if (goedgekeurd !== true) {
228
+ await houdVast("Wacht op een goedgekeurde controlescan; daarna verstuurt Afhandeling de belading.");
229
+ continue;
230
+ }
231
+ // Geen stap 1 en geen stap 2 zonder fulfillment-order: door naar stap 3
232
+ // (alleen lezen). Is de verzendbrief er nog niet, dan wachten zonder poging.
233
+ }
234
+ else if (!bestaandeFo) {
200
235
  // Pas ná een goedgekeurde controlescan laten aanmaken.
201
236
  const { data: goedgekeurd, error: goedError } = await sb.rpc("logistics_floriday_order_approved", {
202
237
  _order_ref: row.order_number,
@@ -290,6 +325,11 @@ export async function runShippingNoteQueue(sb, options = {}) {
290
325
  if (!doc["ok"]) {
291
326
  const message = String(doc["error"] ?? "") ||
292
327
  "Wachten op officiële Floriday-afleverbrief: Floriday heeft het document nog niet aangemaakt.";
328
+ if (wachtOpBelading) {
329
+ // Belading is van Afhandeling: wachten verbruikt geen pogingen.
330
+ await houdVastBelading(`${wachtOpBelading} Laatste antwoord van Floriday: ${message}`);
331
+ continue;
332
+ }
293
333
  await wacht(message, classifyFloridayReason(message));
294
334
  continue;
295
335
  }
@@ -378,3 +418,24 @@ export async function runShippingNoteQueue(sb, options = {}) {
378
418
  }
379
419
  return run;
380
420
  }
421
+ /** Leest module_runtime_config.belading_verstuurder. Onleesbaar of ongeldig = null (fail closed). */
422
+ export async function leesBeladingVerstuurder(sb) {
423
+ try {
424
+ const { data, error } = await sb.rpc("logistics_belading_verstuurder");
425
+ if (error)
426
+ return null;
427
+ return parseBeladingVerstuurder(data);
428
+ }
429
+ catch {
430
+ return null;
431
+ }
432
+ }
433
+ export function parseBeladingVerstuurder(value) {
434
+ const v = typeof value === "string" ? value.trim().toLowerCase() : "";
435
+ return v === "engine" || v === "afhandeling" ? v : null;
436
+ }
437
+ export function beladingWachtReden(verstuurder) {
438
+ return verstuurder === "afhandeling"
439
+ ? "Wacht op belading door Afhandeling."
440
+ : "De instelling belading_verstuurder ontbreekt of is ongeldig; de Engine verstuurt geen belading.";
441
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.120",
3
+ "version": "1.0.124",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [
@@ -47,6 +47,11 @@
47
47
  "export": "PlanWachtrijPage",
48
48
  "route": "logistiek-engine/wachtrij",
49
49
  "title": "Wachtrij"
50
+ },
51
+ {
52
+ "export": "BeheerPage",
53
+ "route": "logistiek-engine/beheer",
54
+ "title": "Beheer"
50
55
  }
51
56
  ],
52
57
  "serverRoutes": [