@flowselections/logistiek-engine 1.0.193 → 1.0.199

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 (59) hide show
  1. package/db/schema/logistiek-engine.sql +2782 -13
  2. package/dist-lib/components/BeheerPage.d.ts.map +1 -1
  3. package/dist-lib/components/BeheerPage.js +3 -1
  4. package/dist-lib/components/DataGereedheidCard.d.ts +47 -0
  5. package/dist-lib/components/DataGereedheidCard.d.ts.map +1 -0
  6. package/dist-lib/components/DataGereedheidCard.js +133 -0
  7. package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
  8. package/dist-lib/components/GeblokkeerdeOrdersCard.js +3 -1
  9. package/dist-lib/components/GeblokkeerdeStickersCard.d.ts.map +1 -1
  10. package/dist-lib/components/GeblokkeerdeStickersCard.js +11 -1
  11. package/dist-lib/components/LadingdragerVoorstellenCard.d.ts +4 -0
  12. package/dist-lib/components/LadingdragerVoorstellenCard.d.ts.map +1 -0
  13. package/dist-lib/components/LadingdragerVoorstellenCard.js +44 -0
  14. package/dist-lib/components/LadingdragersPage.d.ts.map +1 -1
  15. package/dist-lib/components/LadingdragersPage.js +2 -1
  16. package/dist-lib/components/StartlijstCard.d.ts +2 -0
  17. package/dist-lib/components/StartlijstCard.d.ts.map +1 -0
  18. package/dist-lib/components/StartlijstCard.js +54 -0
  19. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
  20. package/dist-lib/hooks/useGeblokkeerdeOrders.js +2 -0
  21. package/dist-lib/index.d.ts +3 -0
  22. package/dist-lib/index.d.ts.map +1 -1
  23. package/dist-lib/index.js +3 -0
  24. package/dist-lib/integrations/supabase/types.d.ts +681 -121
  25. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  26. package/dist-lib/integrations/supabase/types.js +1 -0
  27. package/dist-lib/lib/beladingRegels.d.ts +22 -0
  28. package/dist-lib/lib/beladingRegels.d.ts.map +1 -1
  29. package/dist-lib/lib/beladingRegels.js +46 -4
  30. package/dist-lib/lib/dimensionData.server.js +15 -12
  31. package/dist-lib/lib/dimensionPlanner.d.ts +11 -0
  32. package/dist-lib/lib/dimensionPlanner.d.ts.map +1 -1
  33. package/dist-lib/lib/dimensionPlanner.js +30 -2
  34. package/dist-lib/lib/handlers/index.d.ts +1 -0
  35. package/dist-lib/lib/handlers/index.d.ts.map +1 -1
  36. package/dist-lib/lib/handlers/index.js +1 -0
  37. package/dist-lib/lib/handlers/logistics-plan-now.server.d.ts +18 -0
  38. package/dist-lib/lib/handlers/logistics-plan-now.server.d.ts.map +1 -0
  39. package/dist-lib/lib/handlers/logistics-plan-now.server.js +113 -0
  40. package/dist-lib/lib/handlers/logistics-tick.server.d.ts +5 -0
  41. package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
  42. package/dist-lib/lib/handlers/logistics-tick.server.js +65 -26
  43. package/dist-lib/lib/invoerTeksten.d.ts +4 -0
  44. package/dist-lib/lib/invoerTeksten.d.ts.map +1 -0
  45. package/dist-lib/lib/invoerTeksten.js +19 -0
  46. package/dist-lib/lib/layoutPrint.server.d.ts +8 -0
  47. package/dist-lib/lib/layoutPrint.server.d.ts.map +1 -1
  48. package/dist-lib/lib/layoutPrint.server.js +32 -0
  49. package/dist-lib/lib/loadCarrierPlanning.server.d.ts +4 -0
  50. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  51. package/dist-lib/lib/loadCarrierPlanning.server.js +209 -12
  52. package/dist-lib/lib/moduleVersion.d.ts +1 -1
  53. package/dist-lib/lib/moduleVersion.js +1 -1
  54. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  55. package/dist-lib/lib/ruleEngineSchema.js +14 -0
  56. package/dist-lib/lib/stickerQueue.server.d.ts +18 -0
  57. package/dist-lib/lib/stickerQueue.server.d.ts.map +1 -1
  58. package/dist-lib/lib/stickerQueue.server.js +63 -20
  59. package/package.json +11 -1
@@ -22,6 +22,8 @@ import { controleerEtiket, ETIKET_ONTBREEKT, MAAT_ONBEKEND, maatSleutel, pastOpE
22
22
  const COLS = "id, soort, bron_id, order_id, order_number, cart_id, kopieen, breedte_mm, hoogte_mm, print_plek_id, fulfillment_order_id, status, attempts, sticker_type, print_job_id, herprint_reden, herprint_requested_at, eigen_sticker_id";
23
23
  /** Opslag van eigen stickers (Klanten-module, customer_product_stickers). */
24
24
  export const EIGEN_STICKER_BUCKET = "customer-stickers";
25
+ /** Foutcodes die een sticker blokkeren (status 'geblokkeerd' + reden) in plaats van later opnieuw. */
26
+ export const STICKER_BLOKKEER_CODES = ["GEEN_PRINTER", "GEEN_LAYOUT", "GEEN_EXTERN_DOCUMENT", "DUBBEL_ORIGINEEL_ANDERE_BRON"];
25
27
  /** Documentsoort voor de centrale documentkeuze. */
26
28
  export function documentSoort(soort) {
27
29
  return soort === "eigen_sticker" ? "eigen_sticker" : soort;
@@ -38,28 +40,33 @@ function base64NaarBytes(b64) {
38
40
  }
39
41
  export async function runStickerQueue(sb, opts = {}) {
40
42
  const limit = Math.max(1, opts.limit ?? 10);
41
- const run = { synced: null, released: 0, printed: 0, blocked: 0, retrying: 0, handled: 0, warnings: 0, errors: [] };
43
+ const run = { synced: null, released: 0, printed: 0, blocked: 0, retrying: 0, handled: 0, warnings: 0, errors: [], syncFouten: [] };
42
44
  const nu = () => new Date().toISOString();
43
45
  const zet = (id, velden) => sb.from("logistics_sticker_prints").update(velden).eq("id", id);
44
- // 1. Rekenen in de database.
45
- {
46
- const { data, error } = await sb.rpc("logistics_sticker_sync", { p_limit: 200 });
47
- if (error)
48
- run.errors.push(`sync: ${error.message}`);
49
- run.synced = data ?? null;
50
- }
46
+ // 1. Rekenen in de database. 1.0.194: een fout van een sync-stap is een
47
+ // zichtbare melding (syncFouten), niet alleen een regel in errors.
48
+ const syncStap = async (naam, fn) => {
49
+ try {
50
+ const { data, error } = await sb.rpc(fn, { p_limit: 200 });
51
+ if (error) {
52
+ run.errors.push(`${naam}: ${error.message}`);
53
+ run.syncFouten.push({ stap: naam, functie: fn, fout: error.message });
54
+ return null;
55
+ }
56
+ return data ?? null;
57
+ }
58
+ catch (e) {
59
+ const msg = String(e?.message ?? e);
60
+ run.errors.push(`${naam}: ${msg}`);
61
+ run.syncFouten.push({ stap: naam, functie: fn, fout: msg });
62
+ return null;
63
+ }
64
+ };
65
+ run.synced = await syncStap("sync", "logistics_sticker_sync");
51
66
  // 1b. Eigen stickers (1.0.176): needs_sticker per orderregel, vrij met de pakbon.
52
- {
53
- const { error } = await sb.rpc("logistics_own_sticker_sync", { p_limit: 200 });
54
- if (error)
55
- run.errors.push(`eigen stickers: ${error.message}`);
56
- }
67
+ await syncStap("eigen stickers", "logistics_own_sticker_sync");
57
68
  // 1c. Eigen traystickers (1.0.178): één per tray volgens de karindeling.
58
- {
59
- const { error } = await sb.rpc("logistics_own_traysticker_sync", { p_limit: 200 });
60
- if (error)
61
- run.errors.push(`eigen traystickers: ${error.message}`);
62
- }
69
+ await syncStap("eigen traystickers", "logistics_own_traysticker_sync");
63
70
  // 2. Tray-stickers: vrij na geaccepteerde belading.
64
71
  {
65
72
  const { data } = await sb
@@ -377,6 +384,17 @@ export async function runStickerQueue(sb, opts = {}) {
377
384
  pdfOpslag = { bucket, pad: doc["storagePath"] };
378
385
  }
379
386
  }
387
+ // 1.0.197: Layouts kan het aantal kopieën per documentsoort begrenzen. Nooit stil minder
388
+ // printen dan nodig: dan tegenhouden met uitleg (geweigerd = zichtbaar + opnieuw proberen).
389
+ const toegestaan = await layoutsKopieenToegestaan(sb, r.soort, kopieen);
390
+ if (toegestaan.fout) {
391
+ await later(toegestaan.fout);
392
+ continue;
393
+ }
394
+ if (toegestaan.max !== null && toegestaan.max < kopieen) {
395
+ await blokkeer(kopieenBegrensdTekst(label, kopieen, toegestaan.max));
396
+ continue;
397
+ }
380
398
  const printed = await printViaLayoutGecontroleerd(sb, {
381
399
  documenttype: r.soort,
382
400
  documentnaam: `${label} ${r.order_number ?? ""}`.trim(),
@@ -390,6 +408,7 @@ export async function runStickerQueue(sb, opts = {}) {
390
408
  idempotentieSleutel: isHerprint
391
409
  ? `${r.soort}:${r.bron_id}:${r.cart_id}:${layout.layoutId}:herprint:${r.herprint_requested_at}`
392
410
  : `${r.soort}:${r.bron_id}:${r.cart_id}:${layout.layoutId}`,
411
+ zelfdeBronVerplicht: true,
393
412
  payload: {
394
413
  source: "logistiek-engine",
395
414
  documenttype: r.soort,
@@ -413,7 +432,7 @@ export async function runStickerQueue(sb, opts = {}) {
413
432
  },
414
433
  });
415
434
  if (!printed.ok) {
416
- if (["GEEN_PRINTER", "GEEN_LAYOUT", "GEEN_EXTERN_DOCUMENT"].includes(printed.errorCode) || printed.errorCode.startsWith("FORMAAT")) {
435
+ if (STICKER_BLOKKEER_CODES.includes(printed.errorCode) || printed.errorCode.startsWith("FORMAAT")) {
417
436
  await blokkeer(printed.error);
418
437
  }
419
438
  else {
@@ -639,10 +658,11 @@ async function eigenTraystickersPrinten(sb, run, limit) {
639
658
  herkomst: "eigen",
640
659
  kopieen: 1,
641
660
  idempotentieSleutel: `eigen_traysticker:${r.bron_id}:${layout.layoutId}`,
661
+ zelfdeBronVerplicht: true,
642
662
  payload: { ...pl.payload, print_plek_id: r.print_plek_id, documenttype: "traysticker" },
643
663
  });
644
664
  if (!printed.ok) {
645
- if (["GEEN_PRINTER", "GEEN_LAYOUT"].includes(printed.errorCode))
665
+ if (["GEEN_PRINTER", "GEEN_LAYOUT", "DUBBEL_ORIGINEEL_ANDERE_BRON"].includes(printed.errorCode))
646
666
  await blokkeer(printed.error);
647
667
  else {
648
668
  const attempts = (r.attempts ?? 0) + 1;
@@ -656,3 +676,26 @@ async function eigenTraystickersPrinten(sb, run, limit) {
656
676
  await trace(sb, { ...basis, step: `Eigen traysticker in de printwachtrij (opdracht ${printed.jobId})`, status: "geslaagd" });
657
677
  }
658
678
  }
679
+ /**
680
+ * 1.0.197: vraag Layouts (print_kopieen_aantal, Layouts-eigendom) hoeveel kopieën het
681
+ * toestaat. Ontbreekt die functie in deze Shell → geen begrenzing bekend (max null).
682
+ * Andere fout → later opnieuw (fail-closed: niet printen).
683
+ */
684
+ export async function layoutsKopieenToegestaan(sb, soort, kopieen) {
685
+ const { data, error } = await sb.rpc("print_kopieen_aantal", {
686
+ _type: soort,
687
+ _kopieen: kopieen,
688
+ _payload: { kopieen },
689
+ });
690
+ if (error) {
691
+ const code = error.code;
692
+ if (code === "42883" || code === "PGRST202")
693
+ return { max: null, fout: null };
694
+ return { max: null, fout: `Kopieëncontrole Layouts mislukt: ${error.message}` };
695
+ }
696
+ const n = Number(data);
697
+ return Number.isFinite(n) && n >= 1 ? { max: Math.floor(n), fout: null } : { max: null, fout: null };
698
+ }
699
+ export function kopieenBegrensdTekst(label, nodig, max) {
700
+ return `${label}: ${nodig} kopieën nodig, maar Layouts staat voor dit documenttype maximaal ${max} toe. Niet geprint om geen onvolledige set te maken. Laat Layouts de grens aanpassen en kies daarna "Opnieuw proberen".`;
701
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.193",
3
+ "version": "1.0.199",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [
@@ -82,6 +82,15 @@
82
82
  "GET",
83
83
  "OPTIONS"
84
84
  ]
85
+ },
86
+ {
87
+ "routePath": "/api/public/hooks/logistics-plan-now",
88
+ "import": "@flowselections/logistiek-engine/hooks",
89
+ "handler": "handleLogisticsPlanNow",
90
+ "methods": [
91
+ "POST",
92
+ "OPTIONS"
93
+ ]
85
94
  }
86
95
  ],
87
96
  "schema": {
@@ -142,6 +151,7 @@
142
151
  },
143
152
  "devDependencies": {
144
153
  "@cloudflare/vite-plugin": "^1.25.5",
154
+ "@electric-sql/pglite": "^0.5.12",
145
155
  "@eslint/js": "^9.32.0",
146
156
  "@flowselections/core": "1.0.30",
147
157
  "@lovable.dev/vite-tanstack-config": "2.26.5",