@flowselections/logistiek-engine 1.0.175 → 1.0.180

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 (48) hide show
  1. package/db/schema/logistiek-engine.sql +2112 -0
  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/BeladingIndelingCard.d.ts.map +1 -1
  5. package/dist-lib/components/BeladingIndelingCard.js +2 -0
  6. package/dist-lib/components/DocumentkeuzeCard.d.ts +2 -0
  7. package/dist-lib/components/DocumentkeuzeCard.d.ts.map +1 -0
  8. package/dist-lib/components/DocumentkeuzeCard.js +18 -0
  9. package/dist-lib/index.d.ts +1 -0
  10. package/dist-lib/index.d.ts.map +1 -1
  11. package/dist-lib/index.js +1 -0
  12. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +11 -5
  13. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
  14. package/dist-lib/integrations/supabase/previewAuthStorage.js +38 -21
  15. package/dist-lib/integrations/supabase/types.d.ts +376 -15
  16. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  17. package/dist-lib/lib/beladingRegels.d.ts +78 -0
  18. package/dist-lib/lib/beladingRegels.d.ts.map +1 -0
  19. package/dist-lib/lib/beladingRegels.js +143 -0
  20. package/dist-lib/lib/bulkLoadCarrierPlanning.server.js +2 -2
  21. package/dist-lib/lib/controlScan.server.js +1 -1
  22. package/dist-lib/lib/eigenTraysticker.d.ts +17 -0
  23. package/dist-lib/lib/eigenTraysticker.d.ts.map +1 -0
  24. package/dist-lib/lib/eigenTraysticker.js +32 -0
  25. package/dist-lib/lib/layoutPrint.server.d.ts +10 -1
  26. package/dist-lib/lib/layoutPrint.server.d.ts.map +1 -1
  27. package/dist-lib/lib/layoutPrint.server.js +19 -1
  28. package/dist-lib/lib/loadCarrierPlanning.server.d.ts +35 -3
  29. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  30. package/dist-lib/lib/loadCarrierPlanning.server.js +251 -89
  31. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  32. package/dist-lib/lib/modulePrompts.js +233 -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/planQueue.server.d.ts.map +1 -1
  36. package/dist-lib/lib/planQueue.server.js +26 -2
  37. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  38. package/dist-lib/lib/ruleEngineSchema.js +4 -38
  39. package/dist-lib/lib/ruleEngineWizard.d.ts.map +1 -1
  40. package/dist-lib/lib/ruleEngineWizard.js +0 -2
  41. package/dist-lib/lib/shippingNoteQueue.server.js +1 -1
  42. package/dist-lib/lib/stickerQueue.server.d.ts +25 -0
  43. package/dist-lib/lib/stickerQueue.server.d.ts.map +1 -1
  44. package/dist-lib/lib/stickerQueue.server.js +150 -22
  45. package/dist-lib/lib/stickerRules.d.ts +17 -0
  46. package/dist-lib/lib/stickerRules.d.ts.map +1 -1
  47. package/dist-lib/lib/stickerRules.js +30 -0
  48. package/package.json +1 -1
@@ -17,8 +17,15 @@ import { readFloridayWriteMode } from "./floridayWriteMode.server.js";
17
17
  import { trace, newTraceId } from "./trace.server.js";
18
18
  import { printViaLayoutGecontroleerd, floridayLayout, bucketUitLink } from "./layoutPrint.server.js";
19
19
  import { getFlorydayDocument, getFlorydayFulfillmentStatus } from "./floridayDocuments.server.js";
20
+ import { controleerTrayPayload } from "./eigenTraysticker.js";
20
21
  import { controleerEtiket, parseGeladenEtiketten, pdfFormaat, stickerBackoffMinuten, stickerKopieen, waarschuwingTekst, } from "./stickerRules.js";
21
- 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";
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
+ /** Opslag van eigen stickers (Klanten-module, customer_product_stickers). */
24
+ export const EIGEN_STICKER_BUCKET = "customer-stickers";
25
+ /** Documentsoort voor de centrale documentkeuze. */
26
+ export function documentSoort(soort) {
27
+ return soort === "eigen_sticker" ? "eigen_sticker" : soort;
28
+ }
22
29
  function formaat(r) {
23
30
  return r.breedte_mm && r.hoogte_mm ? { breedteMm: Number(r.breedte_mm), hoogteMm: Number(r.hoogte_mm) } : null;
24
31
  }
@@ -41,6 +48,18 @@ export async function runStickerQueue(sb, opts = {}) {
41
48
  run.errors.push(`sync: ${error.message}`);
42
49
  run.synced = data ?? null;
43
50
  }
51
+ // 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
+ }
57
+ // 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
+ }
44
63
  // 2. Tray-stickers: vrij na geaccepteerde belading.
45
64
  {
46
65
  const { data } = await sb
@@ -132,6 +151,7 @@ export async function runStickerQueue(sb, opts = {}) {
132
151
  .from("logistics_sticker_prints")
133
152
  .select(COLS)
134
153
  .eq("status", "klaar")
154
+ .neq("soort", "eigen_traysticker")
135
155
  .or(`next_attempt_at.is.null,next_attempt_at.lte.${nu()}`)
136
156
  .order("created_at")
137
157
  .limit(limit);
@@ -158,7 +178,7 @@ export async function runStickerQueue(sb, opts = {}) {
158
178
  phase: "stickers",
159
179
  actor: "logistiek-engine:stickerronde",
160
180
  };
161
- const label = r.soort === "sticker" ? "Sticker" : "Tray-stickers";
181
+ const label = r.soort === "sticker" ? "Sticker" : r.soort === "eigen_sticker" ? "Eigen sticker" : "Tray-stickers";
162
182
  const blokkeer = async (reden) => {
163
183
  if (isHerprint) {
164
184
  await zet(r.id, { herprint_requested_at: null, herprint_reden: `Herprint mislukt: ${reden}` });
@@ -202,7 +222,7 @@ export async function runStickerQueue(sb, opts = {}) {
202
222
  await blokkeer("Geen kar bekend voor deze sticker.");
203
223
  continue;
204
224
  }
205
- const kopieen = r.soort === "sticker" ? stickerKopieen(r.kopieen) : Math.max(1, Math.floor(Number(r.kopieen) || 1));
225
+ const kopieen = r.soort !== "traysticker" ? stickerKopieen(r.kopieen) : Math.max(1, Math.floor(Number(r.kopieen) || 1));
206
226
  if (kopieen === null) {
207
227
  await blokkeer(`Aantal afdrukken ongeldig (${String(r.kopieen)}).`);
208
228
  continue;
@@ -211,23 +231,48 @@ export async function runStickerQueue(sb, opts = {}) {
211
231
  await blokkeer("Geen printplek bekend (geen pakbon met printplek en geen pickstation in de werkwijze).");
212
232
  continue;
213
233
  }
214
- // Pdf ophalen via de Floriday-koppeling.
215
- const doc = (await getFlorydayDocument(sb, (r.soort === "sticker"
216
- ? { kind: "customer-sticker", stickerId: r.bron_id }
217
- : { kind: "tray-stickers", deliveryOrderId: r.bron_id })));
218
- if (!doc["ok"]) {
219
- await later(`Floriday: ${String(doc["error"] ?? "pdf niet beschikbaar")}`);
220
- continue;
234
+ const isEigen = r.soort === "eigen_sticker";
235
+ let url = null;
236
+ let b64 = null;
237
+ let doc = {};
238
+ let eigenOpslag = null;
239
+ if (isEigen) {
240
+ // Eigen sticker: afbeelding uit customer_product_stickers, getekend via de eigen stickerlayout.
241
+ if (!r.eigen_sticker_id) {
242
+ await blokkeer("Geen eigen sticker gekoppeld voor deze klant en dit product.");
243
+ continue;
244
+ }
245
+ const { data: s } = await sb
246
+ .from("customer_product_stickers")
247
+ .select("file_path")
248
+ .eq("id", r.eigen_sticker_id)
249
+ .maybeSingle();
250
+ const pad = String(s?.["file_path"] ?? "").trim();
251
+ if (!pad) {
252
+ await blokkeer("Het bestand van de eigen sticker ontbreekt. Voeg de sticker opnieuw toe bij de klant.");
253
+ continue;
254
+ }
255
+ eigenOpslag = { bucket: EIGEN_STICKER_BUCKET, pad };
221
256
  }
222
- const url = (doc["url"] ?? doc["pdfUrl"] ?? doc["documentUrl"] ?? null);
223
- const b64 = (doc["pdfBase64"] ?? doc["base64"] ?? doc["pdf"] ?? null);
224
- if (!url && !b64) {
225
- await later("Floriday gaf nog geen bruikbaar bestand terug.");
226
- continue;
257
+ else {
258
+ // Pdf ophalen via de Floriday-koppeling.
259
+ doc = (await getFlorydayDocument(sb, (r.soort === "sticker"
260
+ ? { kind: "customer-sticker", stickerId: r.bron_id }
261
+ : { kind: "tray-stickers", deliveryOrderId: r.bron_id })));
262
+ if (!doc["ok"]) {
263
+ await later(`Floriday: ${String(doc["error"] ?? "pdf niet beschikbaar")}`);
264
+ continue;
265
+ }
266
+ url = (doc["url"] ?? doc["pdfUrl"] ?? doc["documentUrl"] ?? null);
267
+ b64 = (doc["pdfBase64"] ?? doc["base64"] ?? doc["pdf"] ?? null);
268
+ if (!url && !b64) {
269
+ await later("Floriday gaf nog geen bruikbaar bestand terug.");
270
+ continue;
271
+ }
227
272
  }
228
- // Formaat: van Floriday (stickerSize), anders uit de pdf zelf.
273
+ // Formaat: van Floriday (stickerSize), anders uit de pdf zelf; eigen sticker: uit sticker of layout.
229
274
  let f = formaat(r);
230
- if (!f) {
275
+ if (!f && !isEigen) {
231
276
  try {
232
277
  const bytes = b64 ? base64NaarBytes(b64) : new Uint8Array(await (await fetch(url)).arrayBuffer());
233
278
  f = pdfFormaat(bytes);
@@ -239,16 +284,17 @@ export async function runStickerQueue(sb, opts = {}) {
239
284
  }
240
285
  }
241
286
  const lijst = await etiketten(r.print_plek_id);
242
- const controle = controleerEtiket(f, lijst, r.soort === "sticker" ? "sticker" : "tray-sticker");
287
+ const controle = controleerEtiket(f, lijst, r.soort === "traysticker" ? "tray-sticker" : "sticker");
243
288
  if (f && lijst !== null)
244
289
  await meld(r, f, controle.etiket, controle.ok);
245
290
  if (!controle.ok) {
246
291
  await blokkeer(controle.reden);
247
292
  continue;
248
293
  }
249
- const layout = await floridayLayout(sb, r.soort);
294
+ // 1.0.176: centrale documentkeuze per order; zonder order de Floriday-systeemlayout.
295
+ const layout = await floridayLayout(sb, documentSoort(r.soort), r.order_id);
250
296
  if (!layout.layoutId) {
251
- await blokkeer(layout.reden ?? `Geen actieve Floriday-layout voor ${r.soort}.`);
297
+ await blokkeer(layout.reden ?? `Geen actieve layout voor ${r.soort}.`);
252
298
  continue;
253
299
  }
254
300
  // Blijvende verwijzing naar de opgeslagen pdf (alleen bij precies één rij).
@@ -278,7 +324,7 @@ export async function runStickerQueue(sb, opts = {}) {
278
324
  pdfUrl: url,
279
325
  layoutId: layout.layoutId,
280
326
  printPlekId: r.print_plek_id,
281
- herkomst: "floriday",
327
+ herkomst: isEigen ? "eigen" : "floriday",
282
328
  isHerprint,
283
329
  kopieen,
284
330
  idempotentieSleutel: isHerprint
@@ -298,7 +344,9 @@ export async function runStickerQueue(sb, opts = {}) {
298
344
  ...(isHerprint ? { herprint_reden: r.herprint_reden ?? null } : {}),
299
345
  ...(r.soort === "sticker"
300
346
  ? { sticker_id: r.bron_id, floriday_sticker_id: String(r.bron_id), sticker_type: r.sticker_type ?? null }
301
- : { delivery_order_id: r.bron_id }),
347
+ : r.soort === "eigen_sticker"
348
+ ? { eigen_sticker_id: r.eigen_sticker_id ?? null, sticker_afbeelding: eigenOpslag }
349
+ : { delivery_order_id: r.bron_id }),
302
350
  fulfillment_order_id: r.fulfillment_order_id,
303
351
  sticker_formaat_mm: f ? { breedte: f.breedteMm, hoogte: f.hoogteMm } : null,
304
352
  ...(pdfOpslag ? { pdf_opslag: pdfOpslag } : {}),
@@ -329,6 +377,8 @@ export async function runStickerQueue(sb, opts = {}) {
329
377
  status: "geslaagd",
330
378
  });
331
379
  }
380
+ // 4b. Eigen traystickers (1.0.178): één opdracht per tray via layout_print_document.
381
+ await eigenTraystickersPrinten(sb, run, limit);
332
382
  // 5. Afmelden in Floriday na de goedgekeurde controlescan.
333
383
  run.handled = await afmelden(sb, run);
334
384
  return run;
@@ -468,3 +518,81 @@ async function traystickerLayoutVrijgeven(sb) {
468
518
  .eq("status", "geblokkeerd");
469
519
  return ids.length;
470
520
  }
521
+ /**
522
+ * 1.0.178: eigen traystickers (HO/MO/AO). Layout via de centrale documentkeuze
523
+ * (logistics_document_for_order -> layout_voor_document, 'traysticker').
524
+ * Ontbreekt indeling of layout: alleen deze tray geblokkeerd met uitleg.
525
+ */
526
+ async function eigenTraystickersPrinten(sb, run, limit) {
527
+ const nu = new Date().toISOString();
528
+ const { data } = await sb
529
+ .from("logistics_sticker_prints")
530
+ .select(COLS)
531
+ .eq("soort", "eigen_traysticker")
532
+ .eq("status", "klaar")
533
+ .or(`next_attempt_at.is.null,next_attempt_at.lte.${nu}`)
534
+ .order("created_at")
535
+ .limit(limit);
536
+ for (const r of (Array.isArray(data) ? data : [])) {
537
+ const zet = (velden) => sb.from("logistics_sticker_prints").update(velden).eq("id", r.id);
538
+ const basis = {
539
+ traceId: newTraceId(),
540
+ orderRef: r.order_number ?? r.order_id ?? null,
541
+ orderSource: "eigen",
542
+ cartRef: r.cart_id ?? null,
543
+ phase: "stickers",
544
+ actor: "logistiek-engine:stickerronde",
545
+ };
546
+ const blokkeer = async (reden) => {
547
+ await zet({ status: "geblokkeerd", reden });
548
+ run.blocked++;
549
+ await trace(sb, { ...basis, step: "Eigen traysticker niet geprint", status: "waarschuwing", reason: reden });
550
+ };
551
+ if (!r.order_id || !r.cart_id) {
552
+ await blokkeer("Geen order of kar bekend voor deze traysticker.");
553
+ continue;
554
+ }
555
+ if (!r.print_plek_id) {
556
+ await blokkeer("Geen printplek bekend (geen pakbon met printplek en geen pickstation in de werkwijze).");
557
+ continue;
558
+ }
559
+ const { data: raw, error } = await sb.rpc("logistics_own_traysticker_payload", { p_id: r.id });
560
+ if (error) {
561
+ run.errors.push(`eigen traysticker ${r.id}: ${error.message}`);
562
+ continue;
563
+ }
564
+ const pl = controleerTrayPayload(raw);
565
+ if (!pl.ok) {
566
+ await blokkeer(pl.reden);
567
+ continue;
568
+ }
569
+ const layout = await floridayLayout(sb, "traysticker", r.order_id);
570
+ if (!layout.layoutId) {
571
+ await blokkeer(layout.reden ?? "Maak of activeer een traystickerlayout in Layouts en printers.");
572
+ continue;
573
+ }
574
+ const printed = await printViaLayoutGecontroleerd(sb, {
575
+ documenttype: "traysticker",
576
+ documentnaam: `Traysticker ${r.order_number ?? ""} ${String(pl.payload["tray_nummer"])}/${String(pl.payload["tray_totaal"])}`.trim(),
577
+ layoutId: layout.layoutId,
578
+ printPlekId: r.print_plek_id,
579
+ herkomst: "eigen",
580
+ kopieen: 1,
581
+ idempotentieSleutel: `eigen_traysticker:${r.bron_id}:${layout.layoutId}`,
582
+ payload: { ...pl.payload, print_plek_id: r.print_plek_id, documenttype: "traysticker" },
583
+ });
584
+ if (!printed.ok) {
585
+ if (["GEEN_PRINTER", "GEEN_LAYOUT"].includes(printed.errorCode))
586
+ await blokkeer(printed.error);
587
+ else {
588
+ const attempts = (r.attempts ?? 0) + 1;
589
+ await zet({ attempts, reden: printed.error, next_attempt_at: new Date(Date.now() + stickerBackoffMinuten(attempts) * 60000).toISOString() });
590
+ run.retrying++;
591
+ }
592
+ continue;
593
+ }
594
+ await zet({ status: "in_printwachtrij", print_job_id: printed.jobId, reden: null, next_attempt_at: null });
595
+ run.printed++;
596
+ await trace(sb, { ...basis, step: `Eigen traysticker in de printwachtrij (opdracht ${printed.jobId})`, status: "geslaagd" });
597
+ }
598
+ }
@@ -37,4 +37,21 @@ export declare function waarschuwingTekst(sticker: Formaat, etiket: GeladenEtike
37
37
  export declare function stickerBackoffMinuten(attempts: number): number;
38
38
  /** 1.0.165: aantal afdrukken voor een klantsticker; null = ongeldig (geen stille terugval naar 1, geen maximum). */
39
39
  export declare function stickerKopieen(v: unknown): number | null;
40
+ /**
41
+ * 1.0.176: aantal eigen stickers per orderregel (gelijk aan logistics_own_sticker_count).
42
+ * stuks/planten = aantal planten; fust = aantal × planten per fust (regel, anders product).
43
+ * Onbekend → null: sticker tegenhouden, niet gokken.
44
+ */
45
+ export declare function eigenStickerAantal(unit: string | null | undefined, quantity: number | null | undefined, ppcRegel: number | null | undefined, ppcProduct: number | null | undefined): number | null;
46
+ /** Type-waarden (hoofdletters, deelstring) die als veiling gelden. Aanvullen zodra een echte veilingorder voorkomt. */
47
+ export declare const FLORIDAY_VEILING_TYPE_DELEN: readonly ["CLOCK", "AUCTION"];
48
+ /**
49
+ * 1.0.176: welk verzenddocument levert Floriday (gelijk aan logistics_floriday_shipping_document).
50
+ * null = niet vast te stellen → niet gokken.
51
+ */
52
+ export declare function floridayVerzenddocument(zending: {
53
+ type?: string | null;
54
+ isReAuctioning?: boolean | string | null;
55
+ deliveryNoteCodes?: unknown;
56
+ } | null): "afleverbrief" | "veilingbrief" | null;
40
57
  //# sourceMappingURL=stickerRules.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stickerRules.d.ts","sourceRoot":"","sources":["../../src/lib/stickerRules.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,IAAI,CAY5D;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAG/C;AAED,yEAAyE;AACzE,wBAAgB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,SAAI,GAAG,OAAO,CAG9E;AAOD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,EAAE,GAAG,IAAI,CAsB3E;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACnC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,EAAE,aAAa,EAAE,GAAG,IAAI,EACjC,IAAI,SAAY,GACf,cAAc,CAwBhB;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAItG;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGxD"}
1
+ {"version":3,"file":"stickerRules.d.ts","sourceRoot":"","sources":["../../src/lib/stickerRules.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,IAAI,CAY5D;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAG/C;AAED,yEAAyE;AACzE,wBAAgB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,SAAI,GAAG,OAAO,CAG9E;AAOD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,EAAE,GAAG,IAAI,CAsB3E;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACnC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,SAAS,EAAE,aAAa,EAAE,GAAG,IAAI,EACjC,IAAI,SAAY,GACf,cAAc,CAwBhB;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAItG;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC,MAAM,GAAG,IAAI,CAOf;AAED,uHAAuH;AACvH,eAAO,MAAM,2BAA2B,+BAAgC,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,GAC9G,cAAc,GAAG,cAAc,GAAG,IAAI,CAQxC"}
@@ -114,3 +114,33 @@ export function stickerKopieen(v) {
114
114
  const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
115
115
  return typeof n === "number" && Number.isInteger(n) && n >= 1 ? n : null;
116
116
  }
117
+ /**
118
+ * 1.0.176: aantal eigen stickers per orderregel (gelijk aan logistics_own_sticker_count).
119
+ * stuks/planten = aantal planten; fust = aantal × planten per fust (regel, anders product).
120
+ * Onbekend → null: sticker tegenhouden, niet gokken.
121
+ */
122
+ export function eigenStickerAantal(unit, quantity, ppcRegel, ppcProduct) {
123
+ if (quantity == null || !Number.isFinite(quantity))
124
+ return null;
125
+ if ((unit ?? "").toLowerCase() === "fust") {
126
+ const ppc = ppcRegel || ppcProduct || null;
127
+ return ppc ? Math.round(quantity * ppc) : null;
128
+ }
129
+ return Math.round(quantity);
130
+ }
131
+ /** Type-waarden (hoofdletters, deelstring) die als veiling gelden. Aanvullen zodra een echte veilingorder voorkomt. */
132
+ export const FLORIDAY_VEILING_TYPE_DELEN = ["CLOCK", "AUCTION"];
133
+ /**
134
+ * 1.0.176: welk verzenddocument levert Floriday (gelijk aan logistics_floriday_shipping_document).
135
+ * null = niet vast te stellen → niet gokken.
136
+ */
137
+ export function floridayVerzenddocument(zending) {
138
+ if (!zending)
139
+ return null;
140
+ const t = String(zending.type ?? "").toUpperCase();
141
+ if (String(zending.isReAuctioning ?? "").toLowerCase() === "true" || FLORIDAY_VEILING_TYPE_DELEN.some((d) => t.includes(d)))
142
+ return "veilingbrief";
143
+ if (t === "DIRECT_SALES" && Array.isArray(zending.deliveryNoteCodes) && zending.deliveryNoteCodes.length > 0)
144
+ return "afleverbrief";
145
+ return null;
146
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.175",
3
+ "version": "1.0.180",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [