@flowselections/logistiek-engine 1.0.242 → 1.0.243

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 (61) hide show
  1. package/db/schema/logistiek-engine.sql +7919 -34
  2. package/dist-lib/components/BeheerPage.d.ts.map +1 -1
  3. package/dist-lib/components/BeheerPage.js +2 -1
  4. package/dist-lib/components/DataGereedheidCard.d.ts +1 -0
  5. package/dist-lib/components/DataGereedheidCard.d.ts.map +1 -1
  6. package/dist-lib/components/DataGereedheidCard.js +4 -3
  7. package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
  8. package/dist-lib/components/GeblokkeerdeOrdersCard.js +14 -3
  9. package/dist-lib/components/GereedheidCard.d.ts +14 -0
  10. package/dist-lib/components/GereedheidCard.d.ts.map +1 -0
  11. package/dist-lib/components/GereedheidCard.js +60 -0
  12. package/dist-lib/components/LadingdragersPage.d.ts.map +1 -1
  13. package/dist-lib/components/LadingdragersPage.js +5 -1
  14. package/dist-lib/components/MinuutrondeCard.js +1 -1
  15. package/dist-lib/components/StartlijstCard.d.ts.map +1 -1
  16. package/dist-lib/components/StartlijstCard.js +4 -1
  17. package/dist-lib/components/rule-engine/RuleFieldInput.d.ts.map +1 -1
  18. package/dist-lib/components/rule-engine/RuleFieldInput.js +1 -1
  19. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +14 -0
  20. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
  21. package/dist-lib/hooks/useGeblokkeerdeOrders.js +40 -3
  22. package/dist-lib/index.d.ts +1 -0
  23. package/dist-lib/index.d.ts.map +1 -1
  24. package/dist-lib/index.js +1 -0
  25. package/dist-lib/integrations/supabase/types.d.ts +2962 -95
  26. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  27. package/dist-lib/lib/beladingRegels.d.ts +17 -0
  28. package/dist-lib/lib/beladingRegels.d.ts.map +1 -1
  29. package/dist-lib/lib/beladingRegels.js +29 -3
  30. package/dist-lib/lib/dimensionPlanner.d.ts +10 -0
  31. package/dist-lib/lib/dimensionPlanner.d.ts.map +1 -1
  32. package/dist-lib/lib/dimensionPlanner.js +20 -0
  33. package/dist-lib/lib/engineStatusTeksten.d.ts +1 -1
  34. package/dist-lib/lib/engineStatusTeksten.js +1 -1
  35. package/dist-lib/lib/flowRoute.d.ts.map +1 -1
  36. package/dist-lib/lib/flowRoute.js +2 -2
  37. package/dist-lib/lib/handlers/logistics-tick.server.d.ts +2 -0
  38. package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
  39. package/dist-lib/lib/handlers/logistics-tick.server.js +259 -184
  40. package/dist-lib/lib/loadCarrierPlanning.server.d.ts +21 -0
  41. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  42. package/dist-lib/lib/loadCarrierPlanning.server.js +162 -21
  43. package/dist-lib/lib/loadCarrierTypes.d.ts +2 -0
  44. package/dist-lib/lib/loadCarrierTypes.d.ts.map +1 -1
  45. package/dist-lib/lib/logisticsRecalcJob.server.d.ts.map +1 -1
  46. package/dist-lib/lib/logisticsRecalcJob.server.js +8 -1
  47. package/dist-lib/lib/moduleVersion.d.ts +1 -1
  48. package/dist-lib/lib/moduleVersion.js +1 -1
  49. package/dist-lib/lib/ruleEngineSchema.d.ts +2 -0
  50. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  51. package/dist-lib/lib/ruleEngineSchema.js +38 -1
  52. package/dist-lib/lib/scheduleTasks.server.d.ts +3 -1
  53. package/dist-lib/lib/scheduleTasks.server.d.ts.map +1 -1
  54. package/dist-lib/lib/scheduleTasks.server.js +5 -2
  55. package/dist-lib/lib/statusFase.d.ts +11 -0
  56. package/dist-lib/lib/statusFase.d.ts.map +1 -0
  57. package/dist-lib/lib/statusFase.js +58 -0
  58. package/dist-lib/lib/werkers.server.d.ts +17 -0
  59. package/dist-lib/lib/werkers.server.d.ts.map +1 -0
  60. package/dist-lib/lib/werkers.server.js +31 -0
  61. package/package.json +31 -1
@@ -5,6 +5,7 @@
5
5
  // draait de pure planner per ladingdragertype en schrijft het resultaat weg
6
6
  // naar order_carts / order_cart_items.
7
7
  // ============================================================================
8
+ import { isTerminaleFase } from "./statusFase.js";
8
9
  import { planLoadUnits, LOAD_CARRIER_PLANNER_VERSION, bepaalLaagMenging, berekenFysiekMaxLagen, } from "./loadCarrierPlanner.js";
9
10
  import { traceBatch } from "./trace.server.js";
10
11
  import { zonderQuarantaine } from "./quarantaine.js";
@@ -12,7 +13,7 @@ import { zonderStandaardBelading } from "./hoofdverpakking.js";
12
13
  import { MODULE_VERSION } from "./moduleVersion.js";
13
14
  import { fallbackCarrierProfile } from "./loadCarrierTypes.js";
14
15
  import { WAAR_INVULLEN, gewichtOnbekendTekst, ladingdragerNietInBeheerTekst } from "./invoerTeksten.js";
15
- import { planByDimensions, DIMENSION_PLANNER_VERSION, maxFustenPerLaag } from "./dimensionPlanner.js";
16
+ import { planByDimensions, DIMENSION_PLANNER_VERSION, maxFustenPerLaag, maxFustenPerLaagMetOverstek, fustSleutel, STANDAARD_OVERSTEK_CM } from "./dimensionPlanner.js";
16
17
  import { buildDimensionItems, carrierDimensions } from "./dimensionData.server.js";
17
18
  import { zonderExternAfgehandeld } from "./externalFulfillment.js";
18
19
  import { vulBeladingAan, deelUitFloridayVerpakking, plantenVanRegel, beladingBeoordeling, fysiekeBelading, fustPerKarOnmogelijk, karrenOnwaarschijnlijk, verpakkingSleutel, controleerInvariant, VELD_NAAM, } from "./beladingRegels.js";
@@ -95,6 +96,72 @@ export function beladingPerRegelUitOrder(customFields) {
95
96
  }
96
97
  return out;
97
98
  }
99
+ /**
100
+ * Golf 1 / 12: vul alleen LEGE velden van de Floriday-regel aan uit de Floriday-cache.
101
+ * Een lege waarde overschrijft nooit een gevulde.
102
+ */
103
+ export function vulDeelAan(regel, cache) {
104
+ if (!regel && !cache)
105
+ return null;
106
+ const uit = { ...(regel ?? {}) };
107
+ for (const v of ["plants_per_crate", "crates_per_layer", "layers_per_cart"]) {
108
+ if (positive(uit[v]) == null && positive(cache?.[v]) != null)
109
+ uit[v] = positive(cache?.[v]);
110
+ }
111
+ return uit;
112
+ }
113
+ /**
114
+ * Golf 1 / 12: per Floriday-regel de verpakking uit floriday_salesorders_cache (packingConfiguration)
115
+ * gebruiken voor velden die op de order ontbreken. Fout bij lezen = zichtbare waarschuwing, geen stille terugval.
116
+ */
117
+ async function vulRegelVerpakkingUitCache(sb, orderRows, packingByOrderLine, warnings) {
118
+ const nodig = [];
119
+ for (const o of orderRows) {
120
+ const lines = Array.isArray(o.custom_fields?.floriday_lines) ? o.custom_fields.floriday_lines : [];
121
+ for (const raw of lines) {
122
+ const line = (raw ?? {});
123
+ const ti = line.trade_item_id ? String(line.trade_item_id) : null;
124
+ const so = line.sales_order_id ? String(line.sales_order_id) : null;
125
+ if (!ti || !so)
126
+ continue;
127
+ const huidig = packingByOrderLine.get(String(o.id))?.get(ti) ?? null;
128
+ const compleet = huidig && positive(huidig.plants_per_crate) != null && positive(huidig.crates_per_layer) != null && positive(huidig.layers_per_cart) != null;
129
+ if (!compleet)
130
+ nodig.push({ orderId: String(o.id), tradeItemId: ti, salesOrderId: so });
131
+ }
132
+ }
133
+ if (nodig.length === 0)
134
+ return;
135
+ const perSo = new Map();
136
+ const ids = Array.from(new Set(nodig.map((n) => n.salesOrderId)));
137
+ for (let i = 0; i < ids.length; i += 200) {
138
+ const { data, error } = await sb
139
+ .from("floriday_salesorders_cache")
140
+ .select("floriday_id, packing:data->packingConfiguration")
141
+ .in("floriday_id", ids.slice(i, i + 200));
142
+ if (error) {
143
+ const ontbreekt = /does not exist|42P01|PGRST205|schema cache/i.test(`${error.code ?? ""} ${error.message}`);
144
+ if (!ontbreekt)
145
+ warnings.push(`Floriday-verpakking per regel kon niet uit de Floriday-gegevens worden gelezen: ${error.message}`);
146
+ return;
147
+ }
148
+ for (const r of (Array.isArray(data) ? data : [])) {
149
+ const d = deelUitFloridayVerpakking(r.packing);
150
+ if (d)
151
+ perSo.set(String(r.floriday_id), d);
152
+ }
153
+ }
154
+ for (const n of nodig) {
155
+ const cache = perSo.get(n.salesOrderId);
156
+ if (!cache)
157
+ continue;
158
+ const map = packingByOrderLine.get(n.orderId) ?? new Map();
159
+ const nieuw = vulDeelAan(map.get(n.tradeItemId) ?? null, cache);
160
+ if (nieuw)
161
+ map.set(n.tradeItemId, nieuw);
162
+ packingByOrderLine.set(n.orderId, map);
163
+ }
164
+ }
98
165
  /** Waarden van de orderregel zelf (per veld; 0 of leeg = onbekend). */
99
166
  function deelVanRij(row) {
100
167
  if (!row)
@@ -335,6 +402,23 @@ export async function expandOrderItemsForPlanner(sb, rows, options = {}) {
335
402
  }
336
403
  return out;
337
404
  }
405
+ /** Golf 1 / 11: bevestigde aantallen per laag (sleutel product|fust|ladingdrager). */
406
+ async function laagBevestigingen(sb, productIds) {
407
+ const uit = new Map();
408
+ for (let s = 0; s < productIds.length; s += 500) {
409
+ const { data, error } = await sb
410
+ .from("logistics_laag_bevestigingen")
411
+ .select("product_id, fust_sleutel, ladingdrager_code, fusten_per_laag")
412
+ .in("product_id", productIds.slice(s, s + 500));
413
+ if (error)
414
+ throw new Error(`Indeling geblokkeerd: bevestigingen van fusten per laag konden niet worden gelezen (${error.message}).`);
415
+ for (const r of (Array.isArray(data) ? data : [])) {
416
+ const k = `${r.product_id}|${r.fust_sleutel}|${r.ladingdrager_code}`;
417
+ uit.set(k, Math.max(uit.get(k) ?? 0, Number(r.fusten_per_laag) || 0));
418
+ }
419
+ }
420
+ return uit;
421
+ }
338
422
  async function bevestigdeSleutels(sb, orderIds) {
339
423
  const set = new Set();
340
424
  if (orderIds.length === 0)
@@ -349,7 +433,7 @@ async function bevestigdeSleutels(sb, orderIds) {
349
433
  set.add(`${r.order_id}|${r.verpakking_sleutel}`);
350
434
  return set;
351
435
  }
352
- async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPerRegel) {
436
+ async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPerRegel, blokkeerFactor = null) {
353
437
  // 1.0.198: fustmaten en planthoogte (inclusief pot) uit één bron: logistics_product_maten
354
438
  // (Voorraad als die functies bestaan, anders Floricode → Floriday → handmatig). Nooit gegokt.
355
439
  const productIds = Array.from(new Set(inputs.map((i) => i.product_id).filter((x) => !!x)));
@@ -382,20 +466,22 @@ async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPer
382
466
  const codes = Array.from(new Set([profile.code, ...Array.from(profielPerRegel?.values() ?? []).map((p) => p.code)]));
383
467
  const drager = new Map();
384
468
  {
385
- const { data } = await sb
386
- .from("load_carrier_types")
387
- .select("code, name, layer_length_cm, layer_width_cm, max_height_cm, max_crates_per_layer")
388
- .in("code", codes);
469
+ // Golf 1 / 11: alle kolommen (ook overstek_cm); ontbreekt het overstek, dan de standaard van 2 cm.
470
+ const { data } = await sb.from("load_carrier_types").select("*").in("code", codes);
389
471
  for (const d of (Array.isArray(data) ? data : [])) {
472
+ const o = Number(d.overstek_cm);
390
473
  drager.set(String(d.code), {
391
474
  naam: String(d.name ?? d.code),
392
475
  l: getal(d.layer_length_cm),
393
476
  b: getal(d.layer_width_cm),
394
477
  h: getal(d.max_height_cm),
395
478
  maxPerLaag: getal(d.max_crates_per_layer),
479
+ overstek: d.overstek_cm != null && Number.isFinite(o) && o >= 0 ? o : STANDAARD_OVERSTEK_CM,
396
480
  });
397
481
  }
398
482
  }
483
+ const bevestigdPerLaag = await laagBevestigingen(sb, productIds);
484
+ const vragen = [];
399
485
  const kandidaten = [];
400
486
  const onmogelijk = [];
401
487
  const waarschuwingen = [];
@@ -416,6 +502,8 @@ async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPer
416
502
  }
417
503
  const d = drager.get(prof.code);
418
504
  const mt = i.product_id ? maten.get(String(i.product_id)) : undefined;
505
+ const fs = fustSleutel(mt?.length_mm, mt?.width_mm);
506
+ const bevestigd = i.product_id && fs ? bevestigdPerLaag.get(`${i.product_id}|${fs}|${prof.code}`) ?? null : null;
419
507
  const fysiek = fysiekeBelading({
420
508
  product: i.product_name,
421
509
  bron: i.packing_authoritative ? "Floriday-verpakking" : "product",
@@ -424,13 +512,24 @@ async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPer
424
512
  fust_hoogte_cm: mt?.height_mm ? mt.height_mm / 10 : null,
425
513
  plant_hoogte_cm: mt?.plant ?? null,
426
514
  plant_hoogte_bron: mt?.plantBron ?? null,
427
- layerspace_max: maxFustenPerLaag(d?.l, d?.b, mt?.length_mm ? mt.length_mm / 10 : null, mt?.width_mm ? mt.width_mm / 10 : null),
515
+ layerspace_max: maxFustenPerLaagMetOverstek(d?.l, d?.b, mt?.length_mm ? mt.length_mm / 10 : null, mt?.width_mm ? mt.width_mm / 10 : null, d?.overstek ?? STANDAARD_OVERSTEK_CM),
428
516
  layerspace_strikt: maxFustenPerLaag(d?.l, d?.b, mt?.length_mm ? mt.length_mm / 10 : null, mt?.width_mm ? mt.width_mm / 10 : null, 0),
429
517
  ladingdrager: d?.naam ?? prof.name,
430
518
  ladingdrager_hoogte_cm: d?.h ?? null,
431
519
  max_crates_per_layer: d?.maxPerLaag ?? (prof.max_crates_per_layer ?? null),
432
520
  standaard_lagen: prof.layers_per_carrier,
521
+ blokkeer_factor: blokkeerFactor,
522
+ laag_bevestigd: bevestigd,
433
523
  });
524
+ for (const v of fysiek.vragen) {
525
+ if (!i.product_id || !fs)
526
+ continue;
527
+ vragen.push({
528
+ order_id: i.order_id ?? null, product_id: String(i.product_id), product: i.product_name,
529
+ fust_sleutel: fs, ladingdrager_code: prof.code, ladingdrager: d?.naam ?? prof.name,
530
+ opgegeven: v.opgegeven, berekend: v.berekend, tekst: `${i.product_name}: ${v.tekst}`,
531
+ });
532
+ }
434
533
  // 1.0.213: fysieke grens aan de lagen per kar voor de planner (alleen met bekende maten).
435
534
  i.fysiek_max_lagen = berekenFysiekMaxLagen(d?.h ?? null, mt?.height_mm ? mt.height_mm / 10 : null, mt?.plant ?? null);
436
535
  for (const w of fysiek.waarschuwen) {
@@ -449,9 +548,9 @@ async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPer
449
548
  });
450
549
  }
451
550
  if (kandidaten.length === 0)
452
- return { blokkeren: [], onmogelijk, waarschuwingen };
551
+ return { blokkeren: [], onmogelijk, waarschuwingen, vragen };
453
552
  const ok = await bevestigdeSleutels(sb, Array.from(new Set(kandidaten.map((k) => k.order_id).filter((x) => !!x))));
454
- return { blokkeren: kandidaten.filter((k) => !ok.has(`${k.order_id}|${k.sleutel}`)), onmogelijk, waarschuwingen };
553
+ return { blokkeren: kandidaten.filter((k) => !ok.has(`${k.order_id}|${k.sleutel}`)), onmogelijk, waarschuwingen, vragen };
455
554
  }
456
555
  function getal(v) {
457
556
  const n = Number(v);
@@ -566,6 +665,14 @@ async function bepaalLadingdragers(sb, inputs, rawRows, profiles, handmatig, sta
566
665
  function profileFor(profiles, code) {
567
666
  return profiles.find((p) => p.code === code) ?? fallbackCarrierProfile(code);
568
667
  }
668
+ /** Golf 1 / 11: blokkeergrens uit de werkwijze, tussen 1 en 5 (standaard 1,5). Zelfde als public.logistics_laag_blokkeer_factor. */
669
+ export function leesBlokkeerFactor(k) {
670
+ const raw = k?.laag_blokkeer_factor;
671
+ const n = typeof raw === "string" ? Number(raw.replace(",", ".")) : Number(raw);
672
+ if (raw == null || raw === "" || !Number.isFinite(n))
673
+ return 1.5;
674
+ return Math.min(5, Math.max(1, n));
675
+ }
569
676
  const numOrNull = (v) => {
570
677
  const n = typeof v === "string" ? Number(v) : v;
571
678
  return Number.isFinite(n) && n > 0 ? Math.round(n) : null;
@@ -595,6 +702,7 @@ export async function loadBeladingRules(sb) {
595
702
  layoutMethod: k.cart_layout_method === "afmetingen" ? "afmetingen" : "belading",
596
703
  aanvullenUitLadingdrager: k.aanvullen_uit_ladingdrager === true,
597
704
  gewichtVerplicht: k.gewicht_verplicht === true,
705
+ laagBlokkeerFactor: leesBlokkeerFactor(k),
598
706
  };
599
707
  }
600
708
  /**
@@ -819,15 +927,6 @@ export function dimensionCartsToPlannedUnits(carts) {
819
927
  * opgeblazen aantallen zonder echte grote orders te blokkeren.
820
928
  */
821
929
  const MAX_CARTS_PER_BUFFER = 1000;
822
- /** Statussen waarbij een order niet meer ingedeeld hoeft te worden. */
823
- const TERMINALE_STATUSSEN = new Set([
824
- "verzonden",
825
- "afgehandeld",
826
- "geannuleerd",
827
- "cancelled",
828
- "geleverd",
829
- "afgerond",
830
- ]);
831
930
  /** Reservering of al afgehandelde order: niet plannen, ook niet blokkeren. */
832
931
  function isReservationOrTerminal(order) {
833
932
  if (!order)
@@ -837,8 +936,8 @@ function isReservationOrTerminal(order) {
837
936
  // 1.0.190 (F): geannuleerde orders horen nooit in een buffer of op een kar.
838
937
  if (order.cancelled_at)
839
938
  return true;
840
- const status = String(order.status ?? "").trim().toLowerCase();
841
- return TERMINALE_STATUSSEN.has(status);
939
+ // Golf 1: vaste fase uit de statuslijst (zelfde indeling als logistics_status_fase).
940
+ return isTerminaleFase(order.status);
842
941
  }
843
942
  /**
844
943
  * Duidelijk teveel identieke bestelregels wijst op een synchronisatie die
@@ -1226,6 +1325,8 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
1226
1325
  if (perRegel.size > 0)
1227
1326
  packingByOrderLine.set(String(o.id), perRegel);
1228
1327
  }
1328
+ // Golf 1 / 12: ontbrekende velden per Floriday-regel eerst uit de Floriday-cache (nooit gevuld overschrijven).
1329
+ await vulRegelVerpakkingUitCache(sb, orderRows, packingByOrderLine, warnings);
1229
1330
  const sources = new Map();
1230
1331
  const setComponents = new Map();
1231
1332
  const expandNotes = [];
@@ -1630,7 +1731,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
1630
1731
  // 1.0.179 (punt 3): plausibiliteit, alle ordersoorten. Eén bevestiging per order en verpakking.
1631
1732
  // 1.0.213: ook in droge modus rekenen (alleen lezen); schrijven alleen buiten droge modus.
1632
1733
  {
1633
- const oordeel = await beladingOnwaarschijnlijk(sb, inputs, rawRows, guardProfile, profielPerRegel);
1734
+ const oordeel = await beladingOnwaarschijnlijk(sb, inputs, rawRows, guardProfile, profielPerRegel, rules?.laagBlokkeerFactor ?? 1.5);
1634
1735
  const onwaarschijnlijk = oordeel.blokkeren;
1635
1736
  // 1.0.197: fysiek onmogelijk = altijd blokkeren, niet te bevestigen; alleen gegevens aanpassen helpt.
1636
1737
  if (oordeel.onmogelijk.length > 0) {
@@ -1671,6 +1772,46 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
1671
1772
  warnings.push(w.tekst);
1672
1773
  if (!options.dryRun)
1673
1774
  await bewaarBeladingWaarschuwingen(sb, orderIds, beladingWaarschuwingen, warnings);
1775
+ // Golf 1 / 11: wijkt de bron af van de berekening (binnen de blokkeergrens), dan eerst één vraag
1776
+ // per product + fust + ladingdrager: "Floriday zegt 6 per laag, de berekening 5. Klopt 6?".
1777
+ if (oordeel.vragen.length > 0) {
1778
+ const uniek = new Map();
1779
+ for (const v of oordeel.vragen)
1780
+ uniek.set(`${v.product_id}|${v.fust_sleutel}|${v.ladingdrager_code}`, v);
1781
+ const lijst = Array.from(uniek.values());
1782
+ const reason = `Vraag over de belading: ${lijst.slice(0, 10).map((v) => v.tekst).join(" | ")}` +
1783
+ (onwaarschijnlijk.length > 0
1784
+ ? ` | Belading onwaarschijnlijk: ${onwaarschijnlijk.slice(0, 10).map((o) => `${o.product}: ${o.redenen.join("; ")}`).join(" | ")}`
1785
+ : "") +
1786
+ ". Bevestig dit bij Vastgelopen orders; daarna wordt de order vanzelf ingedeeld.";
1787
+ const { error: blockError } = options.dryRun ? { error: null } : await sb.rpc("logistics_plan_block", {
1788
+ p_order_ids: orderIds,
1789
+ p_reason: reason,
1790
+ p_details: {
1791
+ reason_code: "belading_onwaarschijnlijk",
1792
+ soort: "laag_vraag",
1793
+ bevestigbaar: true,
1794
+ bufferId,
1795
+ path: "typescript",
1796
+ laag_vragen: oordeel.vragen.slice(0, 50),
1797
+ bevestigen: onwaarschijnlijk.slice(0, 50),
1798
+ },
1799
+ });
1800
+ if (blockError)
1801
+ warnings.push(`Blokkade kon niet worden vastgelegd: ${blockError.message}`);
1802
+ return {
1803
+ ok: false,
1804
+ bufferId,
1805
+ orderIds,
1806
+ cartsCreated: 0,
1807
+ replacedManualCount: 0,
1808
+ usedFloridayPacking: false,
1809
+ warnings: [...warnings, reason],
1810
+ skipped: "blocked",
1811
+ blockedReason: reason,
1812
+ beladingSources,
1813
+ };
1814
+ }
1674
1815
  if (onwaarschijnlijk.length > 0) {
1675
1816
  const reason = `Belading onwaarschijnlijk: ${onwaarschijnlijk.slice(0, 10).map((o) => `${o.product}: ${o.redenen.join("; ")}`).join(" | ")}. ` +
1676
1817
  "Kantoor moet dit bevestigen voordat er wordt ingedeeld.";
@@ -5,6 +5,8 @@ export interface LoadCarrierTypeRow extends CarrierProfile {
5
5
  layer_length_cm: number;
6
6
  layer_width_cm: number;
7
7
  max_height_cm: number | null;
8
+ /** Golf 1 / 11: overstek in cm bij het berekenen van fusten per laag (standaard 2). */
9
+ overstek_cm?: number | null;
8
10
  max_orders: number | null;
9
11
  max_customers: number | null;
10
12
  is_active: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"loadCarrierTypes.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierTypes.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE1E,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,kBAAkB,GAClB,mBAAmB,GACnB,QAAQ,GACR,aAAa,GACb,OAAO,CAAC;AAEZ,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAK/D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOjD,CAAC;AAEF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAmBnE;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO1D,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAG/G"}
1
+ {"version":3,"file":"loadCarrierTypes.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierTypes.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE1E,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,kBAAkB,GAClB,mBAAmB,GACnB,QAAQ,GACR,aAAa,GACb,OAAO,CAAC;AAEZ,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAK/D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOjD,CAAC;AAEF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAmBnE;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO1D,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAG/G"}
@@ -1 +1 @@
1
- {"version":3,"file":"logisticsRecalcJob.server.d.ts","sourceRoot":"","sources":["../../src/lib/logisticsRecalcJob.server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAM5D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IACzC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAGjF;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAOhF;AAED,8DAA8D;AAC9D,wBAAsB,QAAQ,CAC5B,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,SAAS,CAAC,CAsBpB;AAED,6EAA6E;AAC7E,wBAAsB,OAAO,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA2D3E;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAIlE,iFAAiF;AACjF,wBAAsB,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK;UAiBpC,MAAM;QAAM,OAAO;YAAU,MAAM;KAO/D"}
1
+ {"version":3,"file":"logisticsRecalcJob.server.d.ts","sourceRoot":"","sources":["../../src/lib/logisticsRecalcJob.server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAM5D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IACzC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAGjF;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAOhF;AAED,8DAA8D;AAC9D,wBAAsB,QAAQ,CAC5B,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,SAAS,CAAC,CAsBpB;AAED,6EAA6E;AAC7E,wBAAsB,OAAO,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA2D3E;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAIlE,iFAAiF;AACjF,wBAAsB,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK;UAiBpC,MAAM;QAAM,OAAO;YAAU,MAAM;KAc/D"}
@@ -124,8 +124,15 @@ export async function runFinalSteps(sb, days = 21) {
124
124
  },
125
125
  ];
126
126
  const steps = [];
127
- steps.push(await scheduleTasksPerOrder(sb));
127
+ const { werkersActief } = await import("./werkers.server.js");
128
+ const werkers = await werkersActief(sb);
129
+ steps.push(await scheduleTasksPerOrder(sb, Date.now, werkers.taken ? { totaalBudgetMs: 0 } : {}));
128
130
  for (const call of calls) {
131
+ // De pickwachtrij-werker houdt de pickwachtrij al elke minuut bij.
132
+ if (werkers.pickwachtrij && call.fn === "logistics_sync_pick_queue") {
133
+ steps.push({ step: call.step, ok: true });
134
+ continue;
135
+ }
129
136
  const { error } = await sb.rpc(call.fn, call.args);
130
137
  steps.push({ step: call.step, ok: !error, ...(error ? { error: voorraadFoutTekst(error) } : {}) });
131
138
  }
@@ -1,2 +1,2 @@
1
- export declare const MODULE_VERSION = "1.0.242";
1
+ export declare const MODULE_VERSION = "1.0.243";
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.242";
2
+ export const MODULE_VERSION = "1.0.243";
@@ -20,6 +20,8 @@ export interface RuleField {
20
20
  options?: FieldOption[];
21
21
  min?: number;
22
22
  max?: number;
23
+ /** Stapgrootte bij type "number" (bijv. 0.1 voor een factor). */
24
+ step?: number;
23
25
  unit?: string;
24
26
  default?: unknown;
25
27
  /** Alleen bij type "layout": welke documenttypes uit de Layout maker gekozen mogen worden. */
@@ -1 +1 @@
1
- {"version":3,"file":"ruleEngineSchema.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineSchema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ruleEngineSchema.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineSchema.ts"],"names":[],"mappings":"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"}
@@ -259,6 +259,16 @@ export const RULE_STEPS = [
259
259
  default: false,
260
260
  description: "Uit (standaard): ontbreekt het gewicht, dan krijgt de kar een waarschuwing dat de kilo's niet zijn gecontroleerd. Aan: de order wordt dan niet ingedeeld.",
261
261
  },
262
+ {
263
+ key: "laag_blokkeer_factor",
264
+ label: "Grens voor te veel fusten per laag (× de berekening)",
265
+ type: "number",
266
+ default: 1.5,
267
+ min: 1,
268
+ max: 5,
269
+ step: 0.1,
270
+ description: "Geeft Floriday of het artikel meer fusten per laag op dan volgens fustmaat en laagmaat (met overstek) past, dan vraagt het systeem één keer per product, fust en ladingdrager of dat klopt. Alleen boven deze grens blijft de order geblokkeerd. Standaard 1,5.",
271
+ },
262
272
  {
263
273
  key: "mode",
264
274
  label: "Hoe ontstaat een belading?",
@@ -1060,7 +1070,25 @@ export const RULE_STEPS = [
1060
1070
  type: "number",
1061
1071
  min: 1,
1062
1072
  max: 3650,
1063
- description: "Na deze termijn worden logboekregels van orders opgeruimd. Laat leeg om niets op te ruimen.",
1073
+ description: "Na deze termijn worden logboekregels van orders opgeruimd. Het logboek is per week opgedeeld; een verlopen week wordt in zijn geheel weggegooid.",
1074
+ },
1075
+ {
1076
+ key: "trace_error_retention_days",
1077
+ default: 90,
1078
+ label: "Foutregels in het logboek bewaren (dagen)",
1079
+ type: "number",
1080
+ min: 1,
1081
+ max: 365,
1082
+ description: "Logboekregels met een fout blijven langer bewaard, zodat je ze later nog kunt terugzoeken.",
1083
+ },
1084
+ {
1085
+ key: "worker_budget_seconds",
1086
+ default: 20,
1087
+ label: "Maximale duur van een achtergrondronde (seconden)",
1088
+ type: "number",
1089
+ min: 5,
1090
+ max: 50,
1091
+ description: "Elke minuut werken vier achtergrondrondes (planning, pickwachtrij, taken en onderhoud) de open orders bij. Na deze tijd stopt een ronde; wat nog niet af is, gaat mee met de volgende ronde.",
1064
1092
  },
1065
1093
  {
1066
1094
  key: "pick_history_retention_days",
@@ -1080,6 +1108,15 @@ export const RULE_STEPS = [
1080
1108
  max: 3650,
1081
1109
  description: "Alleen barcodes van karren die niet meer bestaan en nooit zijn geprint, gescand of gecontroleerd. Laat leeg om niets op te ruimen.",
1082
1110
  },
1111
+ {
1112
+ key: "archive_after_days",
1113
+ default: 14,
1114
+ label: "Niet geleverde orders archiveren na (dagen)",
1115
+ type: "number",
1116
+ min: 3,
1117
+ max: 90,
1118
+ description: "Een order die niet ingedeeld kon worden en waarvan de leverdag zo lang voorbij is, gaat naar het archief van de wachtrij. Planners krijgen daarvan een melding; met \"Opnieuw aanbieden\" zet je hem terug.",
1119
+ },
1083
1120
  ],
1084
1121
  },
1085
1122
  ],
@@ -20,5 +20,7 @@ export type InplanStap = {
20
20
  error?: string;
21
21
  voortgang?: string;
22
22
  };
23
- export declare function scheduleTasksPerOrder(sb: SupabaseClient, nu?: () => number): Promise<InplanStap>;
23
+ export declare function scheduleTasksPerOrder(sb: SupabaseClient, nu?: () => number, opties?: {
24
+ totaalBudgetMs?: number;
25
+ }): Promise<InplanStap>;
24
26
  //# sourceMappingURL=scheduleTasks.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scheduleTasks.server.d.ts","sourceRoot":"","sources":["../../src/lib/scheduleTasks.server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,gBAAgB,QAAS,CAAC;AACvC,eAAO,MAAM,gBAAgB,SAAU,CAAC;AAUxC,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,GAAE,MAAM,MAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAoChH"}
1
+ {"version":3,"file":"scheduleTasks.server.d.ts","sourceRoot":"","sources":["../../src/lib/scheduleTasks.server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,gBAAgB,QAAS,CAAC;AACvC,eAAO,MAAM,gBAAgB,SAAU,CAAC;AAUxC,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,cAAc,EAClB,EAAE,GAAE,MAAM,MAAiB,EAC3B,MAAM,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,UAAU,CAAC,CAuCrB"}
@@ -16,9 +16,12 @@ export const TOTAAL_BUDGET_MS = 110000;
16
16
  export function isOntbrekendeFunctie(msg) {
17
17
  return /could not find the function|does not exist|PGRST202/i.test(msg);
18
18
  }
19
- export async function scheduleTasksPerOrder(sb, nu = Date.now) {
19
+ export async function scheduleTasksPerOrder(sb, nu = Date.now, opties = {}) {
20
20
  const step = "Taken opnieuw inplannen";
21
21
  const start = nu();
22
+ // Golf 1: draait de taken-werker in de database, dan maakt de shell alleen de
23
+ // eerste portie en loopt de rest daar verder (logistics_schedule_tasks_vervolg).
24
+ const totaalBudget = Math.max(0, opties.totaalBudgetMs ?? TOTAAL_BUDGET_MS);
22
25
  try {
23
26
  let runId = null;
24
27
  let laatste = {};
@@ -42,7 +45,7 @@ export async function scheduleTasksPerOrder(sb, nu = Date.now) {
42
45
  }
43
46
  if (!laatste.resterend || laatste.resterend <= 0)
44
47
  break;
45
- if (nu() - start > TOTAAL_BUDGET_MS) {
48
+ if (nu() - start > totaalBudget) {
46
49
  return {
47
50
  step,
48
51
  ok: true,
@@ -0,0 +1,11 @@
1
+ export type StatusFase = "concept" | "open" | "te_picken" | "gepickt" | "verzonden" | "gereed_voor_facturatie" | "gefactureerd" | "geannuleerd" | "gereserveerd" | "afgehandeld_floriday" | "onbekend";
2
+ export declare const STATUS_FASEN_STANDAARD: Readonly<Record<string, StatusFase>>;
3
+ /** Zelfde regel als logistics_status_fase(): hoofdletters en spaties rondom tellen niet mee. */
4
+ export declare function statusFase(status: string | null | undefined): StatusFase;
5
+ /** Fases waarin de order klaar is met de logistiek: niet meer indelen. */
6
+ export declare const AFGERONDE_FASEN: ReadonlySet<StatusFase>;
7
+ /** Order hoeft niet (meer) ingedeeld te worden: afgerond of geannuleerd. */
8
+ export declare function isTerminaleFase(status: string | null | undefined): boolean;
9
+ /** Order is logistiek afgerond (niet geannuleerd). */
10
+ export declare function isAfgerondeFase(status: string | null | undefined): boolean;
11
+ //# sourceMappingURL=statusFase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusFase.d.ts","sourceRoot":"","sources":["../../src/lib/statusFase.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,MAAM,GACN,WAAW,GACX,SAAS,GACT,WAAW,GACX,wBAAwB,GACxB,cAAc,GACd,aAAa,GACb,cAAc,GACd,sBAAsB,GACtB,UAAU,CAAC;AAEf,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CA2BvE,CAAC;AAEF,gGAAgG;AAChG,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,CAIxE;AAED,0EAA0E;AAC1E,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,UAAU,CAKlD,CAAC;AAEH,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG1E;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE1E"}
@@ -0,0 +1,58 @@
1
+ // ============================================================================
2
+ // src/lib/statusFase.ts — orderstatus naar vaste fase
3
+ // ============================================================================
4
+ // Spiegel van public.logistics_status_fasen_standaard() in de database. De
5
+ // database vult de statuslijst alleen uit die standaard (logistics_ensure_defaults),
6
+ // dus deze indeling is gelijk aan wat logistics_status_fase() teruggeeft. Een test
7
+ // (tests/lib/statusFase.test.ts) bewaakt dat beide lijsten gelijk blijven.
8
+ export const STATUS_FASEN_STANDAARD = {
9
+ concept: "concept",
10
+ draft: "concept",
11
+ open: "open",
12
+ nieuw: "open",
13
+ new: "open",
14
+ "nog te picken": "te_picken",
15
+ "te picken": "te_picken",
16
+ gepickt: "gepickt",
17
+ picked: "gepickt",
18
+ verzonden: "verzonden",
19
+ shipped: "verzonden",
20
+ geleverd: "verzonden",
21
+ delivered: "verzonden",
22
+ afgerond: "verzonden",
23
+ afgehandeld: "verzonden",
24
+ afgemeld: "verzonden",
25
+ "gereed voor facturatie": "gereed_voor_facturatie",
26
+ gefactureerd: "gefactureerd",
27
+ invoiced: "gefactureerd",
28
+ geannuleerd: "geannuleerd",
29
+ cancelled: "geannuleerd",
30
+ canceled: "geannuleerd",
31
+ gereserveerd: "gereserveerd",
32
+ reserved: "gereserveerd",
33
+ "afgehandeld floriday": "afgehandeld_floriday",
34
+ "afgehandeld via floriday": "afgehandeld_floriday",
35
+ };
36
+ /** Zelfde regel als logistics_status_fase(): hoofdletters en spaties rondom tellen niet mee. */
37
+ export function statusFase(status) {
38
+ const sleutel = String(status ?? "").trim().toLowerCase();
39
+ if (!sleutel)
40
+ return "onbekend";
41
+ return STATUS_FASEN_STANDAARD[sleutel] ?? "onbekend";
42
+ }
43
+ /** Fases waarin de order klaar is met de logistiek: niet meer indelen. */
44
+ export const AFGERONDE_FASEN = new Set([
45
+ "verzonden",
46
+ "gereed_voor_facturatie",
47
+ "gefactureerd",
48
+ "afgehandeld_floriday",
49
+ ]);
50
+ /** Order hoeft niet (meer) ingedeeld te worden: afgerond of geannuleerd. */
51
+ export function isTerminaleFase(status) {
52
+ const fase = statusFase(status);
53
+ return fase === "geannuleerd" || AFGERONDE_FASEN.has(fase);
54
+ }
55
+ /** Order is logistiek afgerond (niet geannuleerd). */
56
+ export function isAfgerondeFase(status) {
57
+ return AFGERONDE_FASEN.has(statusFase(status));
58
+ }
@@ -0,0 +1,17 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ /**
3
+ * Golf 1 stap 2: databasewerkers (planning, pickwachtrij, taken, onderhoud).
4
+ * Draait een werker (laatste ronde < 5 min geleden), dan slaat de HTTP-ronde
5
+ * van de shell diens SQL-stappen over. Draait hij niet (nog niet ingepland,
6
+ * oud schema), dan doet de HTTP-ronde alles zelf zoals voorheen.
7
+ */
8
+ export type WerkersActief = {
9
+ planning: boolean;
10
+ pickwachtrij: boolean;
11
+ taken: boolean;
12
+ onderhoud: boolean;
13
+ };
14
+ export declare const GEEN_WERKERS: WerkersActief;
15
+ export declare function leesWerkersActief(data: unknown): WerkersActief;
16
+ export declare function werkersActief(sb: SupabaseClient): Promise<WerkersActief>;
17
+ //# sourceMappingURL=werkers.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"werkers.server.d.ts","sourceRoot":"","sources":["../../src/lib/werkers.server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,aAK1B,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAS9D;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAY9E"}
@@ -0,0 +1,31 @@
1
+ export const GEEN_WERKERS = {
2
+ planning: false,
3
+ pickwachtrij: false,
4
+ taken: false,
5
+ onderhoud: false,
6
+ };
7
+ export function leesWerkersActief(data) {
8
+ if (!data || typeof data !== "object")
9
+ return { ...GEEN_WERKERS };
10
+ const d = data;
11
+ return {
12
+ planning: d.planning === true,
13
+ pickwachtrij: d.pickwachtrij === true,
14
+ taken: d.taken === true,
15
+ onderhoud: d.onderhoud === true,
16
+ };
17
+ }
18
+ export async function werkersActief(sb) {
19
+ try {
20
+ const { data, error } = await sb.rpc("logistics_werkers_actief");
21
+ if (error) {
22
+ console.warn("[logistics-werkers] stand niet leesbaar; ronde doet alles zelf:", error.message);
23
+ return { ...GEEN_WERKERS };
24
+ }
25
+ return leesWerkersActief(data);
26
+ }
27
+ catch (e) {
28
+ console.warn("[logistics-werkers] stand niet leesbaar; ronde doet alles zelf:", String(e?.message ?? e));
29
+ return { ...GEEN_WERKERS };
30
+ }
31
+ }