@flowselections/logistiek-engine 1.0.162 → 1.0.167

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 (37) hide show
  1. package/dist-lib/components/BeheerPage.d.ts.map +1 -1
  2. package/dist-lib/components/BeheerPage.js +3 -1
  3. package/dist-lib/components/GeblokkeerdeStickersCard.d.ts +2 -0
  4. package/dist-lib/components/GeblokkeerdeStickersCard.d.ts.map +1 -0
  5. package/dist-lib/components/GeblokkeerdeStickersCard.js +31 -0
  6. package/dist-lib/components/HerindelingMeldingCard.d.ts +2 -0
  7. package/dist-lib/components/HerindelingMeldingCard.d.ts.map +1 -0
  8. package/dist-lib/components/HerindelingMeldingCard.js +37 -0
  9. package/dist-lib/index.d.ts +2 -0
  10. package/dist-lib/index.d.ts.map +1 -1
  11. package/dist-lib/index.js +2 -0
  12. package/dist-lib/integrations/supabase/types.d.ts +253 -0
  13. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  14. package/dist-lib/lib/autoSend.server.d.ts.map +1 -1
  15. package/dist-lib/lib/autoSend.server.js +14 -0
  16. package/dist-lib/lib/externalFulfillment.d.ts +14 -0
  17. package/dist-lib/lib/externalFulfillment.d.ts.map +1 -0
  18. package/dist-lib/lib/externalFulfillment.js +26 -0
  19. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  20. package/dist-lib/lib/loadCarrierPlanning.server.js +12 -2
  21. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  22. package/dist-lib/lib/modulePrompts.js +243 -0
  23. package/dist-lib/lib/moduleVersion.d.ts +1 -1
  24. package/dist-lib/lib/moduleVersion.js +1 -1
  25. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  26. package/dist-lib/lib/ruleEngineSchema.js +1 -0
  27. package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -1
  28. package/dist-lib/lib/shippingNoteQueue.server.js +12 -0
  29. package/dist-lib/lib/shippingNoteStates.d.ts +4 -0
  30. package/dist-lib/lib/shippingNoteStates.d.ts.map +1 -1
  31. package/dist-lib/lib/shippingNoteStates.js +4 -0
  32. package/dist-lib/lib/stickerQueue.server.d.ts.map +1 -1
  33. package/dist-lib/lib/stickerQueue.server.js +85 -9
  34. package/dist-lib/lib/stickerRules.d.ts +2 -0
  35. package/dist-lib/lib/stickerRules.d.ts.map +1 -1
  36. package/dist-lib/lib/stickerRules.js +5 -0
  37. package/package.json +1 -1
@@ -15,8 +15,8 @@
15
15
  import { trace, newTraceId } from "./trace.server.js";
16
16
  import { printViaLayoutGecontroleerd, floridayLayout, bucketUitLink } from "./layoutPrint.server.js";
17
17
  import { getFlorydayDocument, getFlorydayFulfillmentStatus } from "./floridayDocuments.server.js";
18
- import { controleerEtiket, parseGeladenEtiketten, pdfFormaat, stickerBackoffMinuten, waarschuwingTekst, } from "./stickerRules.js";
19
- 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";
18
+ import { controleerEtiket, parseGeladenEtiketten, pdfFormaat, stickerBackoffMinuten, stickerKopieen, waarschuwingTekst, } from "./stickerRules.js";
19
+ 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";
20
20
  function formaat(r) {
21
21
  return r.breedte_mm && r.hoogte_mm ? { breedteMm: Number(r.breedte_mm), hoogteMm: Number(r.hoogte_mm) } : null;
22
22
  }
@@ -131,7 +131,20 @@ export async function runStickerQueue(sb, opts = {}) {
131
131
  .or(`next_attempt_at.is.null,next_attempt_at.lte.${nu()}`)
132
132
  .order("created_at")
133
133
  .limit(limit);
134
- for (const r of (Array.isArray(klaar) ? klaar : [])) {
134
+ // Expliciet gevraagde herprints (pickstation_sticker_reprint). Een pakbon-herprint komt hier nooit.
135
+ const { data: herprints } = await sb
136
+ .from("logistics_sticker_prints")
137
+ .select(COLS)
138
+ .eq("soort", "sticker")
139
+ .not("herprint_requested_at", "is", null)
140
+ .in("status", ["in_printwachtrij", "afgemeld"])
141
+ .limit(limit);
142
+ const teDoen = [
143
+ ...(Array.isArray(klaar) ? klaar : []),
144
+ ...(Array.isArray(herprints) ? herprints : []),
145
+ ];
146
+ for (const r of teDoen) {
147
+ const isHerprint = r.status !== "klaar" && !!r.herprint_requested_at;
135
148
  const traceId = newTraceId();
136
149
  const basis = {
137
150
  traceId,
@@ -143,21 +156,53 @@ export async function runStickerQueue(sb, opts = {}) {
143
156
  };
144
157
  const label = r.soort === "sticker" ? "Sticker" : "Tray-stickers";
145
158
  const blokkeer = async (reden) => {
159
+ if (isHerprint) {
160
+ await zet(r.id, { herprint_requested_at: null, herprint_reden: `Herprint mislukt: ${reden}` });
161
+ await trace(sb, { ...basis, step: `${label}: herprint mislukt`, status: "waarschuwing", reason: reden });
162
+ return;
163
+ }
146
164
  await zet(r.id, { status: "geblokkeerd", reden });
147
165
  run.blocked++;
148
166
  await trace(sb, { ...basis, step: `${label} niet geprint`, status: "waarschuwing", reason: reden });
149
167
  };
150
168
  const later = async (reden) => {
169
+ if (isHerprint) {
170
+ await trace(sb, { ...basis, step: `${label}: herprint opnieuw proberen`, status: "wachtend", reason: reden });
171
+ return;
172
+ }
151
173
  const attempts = (r.attempts ?? 0) + 1;
152
174
  const volgende = new Date(Date.now() + stickerBackoffMinuten(attempts) * 60000).toISOString();
153
175
  await zet(r.id, { attempts, next_attempt_at: volgende, reden });
154
176
  run.retrying++;
155
177
  await trace(sb, { ...basis, step: `${label}: opnieuw proberen`, status: "wachtend", reason: reden, attempts, nextAttemptAt: volgende });
156
178
  };
179
+ // 1.0.166: order/bestelling afgehandeld in Floriday => niet printen, nooit afmelden.
180
+ {
181
+ const { data: extern, error: externError } = await sb.rpc("logistics_sticker_external_fulfilled", { p_sticker_print_id: r.id });
182
+ if (externError) {
183
+ await later(`Afhandeling in Floriday niet leesbaar: ${externError.message}`);
184
+ continue;
185
+ }
186
+ if (extern === true) {
187
+ if (isHerprint) {
188
+ await zet(r.id, { herprint_requested_at: null, herprint_reden: "Afgehandeld in Floriday; niet opnieuw geprint." });
189
+ }
190
+ else {
191
+ await zet(r.id, { status: "niet_printen", reden: "Afgehandeld in Floriday; door ons niet geprint en niet afgemeld." });
192
+ }
193
+ await trace(sb, { ...basis, step: `${label} niet geprint`, status: "overgeslagen", reason: "Afgehandeld in Floriday" });
194
+ continue;
195
+ }
196
+ }
157
197
  if (!r.cart_id) {
158
198
  await blokkeer("Geen kar bekend voor deze sticker.");
159
199
  continue;
160
200
  }
201
+ const kopieen = r.soort === "sticker" ? stickerKopieen(r.kopieen) : Math.max(1, Math.floor(Number(r.kopieen) || 1));
202
+ if (kopieen === null) {
203
+ await blokkeer(`Aantal afdrukken ongeldig (${String(r.kopieen)}).`);
204
+ continue;
205
+ }
161
206
  if (!r.print_plek_id) {
162
207
  await blokkeer("Geen printplek bekend (geen pakbon met printplek en geen pickstation in de werkwijze).");
163
208
  continue;
@@ -230,8 +275,11 @@ export async function runStickerQueue(sb, opts = {}) {
230
275
  layoutId: layout.layoutId,
231
276
  printPlekId: r.print_plek_id,
232
277
  herkomst: "floriday",
233
- kopieen: r.kopieen,
234
- idempotentieSleutel: `${r.soort}:${r.bron_id}:${r.cart_id}:${layout.layoutId}`,
278
+ isHerprint,
279
+ kopieen,
280
+ idempotentieSleutel: isHerprint
281
+ ? `${r.soort}:${r.bron_id}:${r.cart_id}:${layout.layoutId}:herprint:${r.herprint_requested_at}`
282
+ : `${r.soort}:${r.bron_id}:${r.cart_id}:${layout.layoutId}`,
235
283
  payload: {
236
284
  source: "logistiek-engine",
237
285
  documenttype: r.soort,
@@ -241,8 +289,12 @@ export async function runStickerQueue(sb, opts = {}) {
241
289
  ordernummer: r.order_number,
242
290
  order_number: r.order_number,
243
291
  cart_id: r.cart_id,
244
- kopieen: r.kopieen,
245
- ...(r.soort === "sticker" ? { sticker_id: r.bron_id } : { delivery_order_id: r.bron_id }),
292
+ kopieen,
293
+ is_herprint: isHerprint,
294
+ ...(isHerprint ? { herprint_reden: r.herprint_reden ?? null } : {}),
295
+ ...(r.soort === "sticker"
296
+ ? { sticker_id: r.bron_id, floriday_sticker_id: String(r.bron_id), sticker_type: r.sticker_type ?? null }
297
+ : { delivery_order_id: r.bron_id }),
246
298
  fulfillment_order_id: r.fulfillment_order_id,
247
299
  sticker_formaat_mm: f ? { breedte: f.breedteMm, hoogte: f.hoogteMm } : null,
248
300
  ...(pdfOpslag ? { pdf_opslag: pdfOpslag } : {}),
@@ -257,13 +309,19 @@ export async function runStickerQueue(sb, opts = {}) {
257
309
  }
258
310
  continue;
259
311
  }
312
+ if (isHerprint) {
313
+ await zet(r.id, { herprint_requested_at: null, print_job_id: printed.jobId });
314
+ run.printed++;
315
+ await trace(sb, { ...basis, step: `${label} opnieuw geprint (opdracht ${printed.jobId}, ${kopieen}×)`, status: "geslaagd" });
316
+ continue;
317
+ }
260
318
  await zet(r.id, { status: "in_printwachtrij", print_job_id: printed.jobId, reden: null, next_attempt_at: null });
261
319
  run.printed++;
262
320
  await trace(sb, {
263
321
  ...basis,
264
322
  step: printed.bestaand
265
323
  ? `${label} staat in de printwachtrij (opdracht ${printed.jobId})`
266
- : `${label} in de printwachtrij gezet (opdracht ${printed.jobId}, ${r.kopieen}×)`,
324
+ : `${label} in de printwachtrij gezet (opdracht ${printed.jobId}, ${kopieen}×)`,
267
325
  status: "geslaagd",
268
326
  });
269
327
  }
@@ -289,15 +347,33 @@ async function afmelden(sb, run) {
289
347
  perSticker.set(r.bron_id, [...(perSticker.get(r.bron_id) ?? []), r.id]);
290
348
  const klaarVoorAfmelden = [];
291
349
  for (const stickerId of perSticker.keys()) {
350
+ // 1.0.166: nooit afmelden voor een order/bestelling die in Floriday is afgehandeld.
351
+ {
352
+ const eerste = (perSticker.get(stickerId) ?? [])[0];
353
+ const { data: extern, error: externError } = eerste
354
+ ? await sb.rpc("logistics_sticker_external_fulfilled", { p_sticker_print_id: eerste })
355
+ : { data: null, error: null };
356
+ if (externError || extern === true)
357
+ continue;
358
+ }
292
359
  const { data: alle } = await sb
293
360
  .from("logistics_sticker_prints")
294
- .select("cart_id, status")
361
+ .select("cart_id, status, print_job_id")
295
362
  .eq("soort", "sticker")
296
363
  .eq("bron_id", stickerId)
297
364
  .neq("status", "niet_printen");
298
365
  const regels = (Array.isArray(alle) ? alle : []);
366
+ // Nooit afmelden bij geblokkeerd/wachtend; shouldBePrinted=false (niet_printen) telt niet als geprint.
299
367
  if (regels.length === 0 || regels.some((x) => x.status !== "in_printwachtrij" || !x.cart_id))
300
368
  continue;
369
+ // "Printed and placed" (swagger): de printopdracht moet echt voltooid zijn in Layouts.
370
+ const jobIds = regels.map((x) => x.print_job_id).filter((x) => !!x);
371
+ if (jobIds.length !== regels.length)
372
+ continue;
373
+ const { data: jobs } = await sb.from("print_jobs").select("id, status").in("id", jobIds);
374
+ const voltooid = (Array.isArray(jobs) ? jobs : []).filter((j) => j.status === "voltooid");
375
+ if (voltooid.length !== new Set(jobIds).size)
376
+ continue;
301
377
  const carts = regels.map((x) => x.cart_id);
302
378
  const { data: scans } = await sb
303
379
  .from("logistics_control_scan")
@@ -35,4 +35,6 @@ export declare function controleerEtiket(sticker: Formaat | null, etiketten: Gel
35
35
  export declare function waarschuwingTekst(sticker: Formaat, etiket: GeladenEtiket | null, plek: string): string;
36
36
  /** Wachttijd na een mislukte poging: 5, 15, daarna 60 minuten. */
37
37
  export declare function stickerBackoffMinuten(attempts: number): number;
38
+ /** 1.0.165: aantal afdrukken voor een klantsticker; null = ongeldig (geen stille terugval naar 1, geen maximum). */
39
+ export declare function stickerKopieen(v: unknown): number | null;
38
40
  //# 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"}
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"}
@@ -109,3 +109,8 @@ export function stickerBackoffMinuten(attempts) {
109
109
  return 15;
110
110
  return 60;
111
111
  }
112
+ /** 1.0.165: aantal afdrukken voor een klantsticker; null = ongeldig (geen stille terugval naar 1, geen maximum). */
113
+ export function stickerKopieen(v) {
114
+ const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
115
+ return typeof n === "number" && Number.isInteger(n) && n >= 1 ? n : null;
116
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.162",
3
+ "version": "1.0.167",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [