@flowselections/logistiek-engine 1.0.193 → 1.0.195

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.
@@ -1 +1 @@
1
- {"version":3,"file":"logistics-tick.server.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/logistics-tick.server.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,qFAAqF;AACrF,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE;;;;EAE7D;AAQD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,EACxB,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,OAAO,CAAC,QAAQ,CAAC,CAgGnB;AAED,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,eAAe,CAAC"}
1
+ {"version":3,"file":"logistics-tick.server.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/logistics-tick.server.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,qFAAqF;AACrF,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE;;;;EAE7D;AAQD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,EACxB,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACjC,OAAO,CAAC,QAAQ,CAAC,CAoGnB;AAED,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,eAAe,CAAC"}
@@ -53,13 +53,8 @@ export async function handleLogisticsTick(request, supabase, opts) {
53
53
  catch {
54
54
  // Niet aanvullen = fail closed (verzendbrieven wachten); ronde loopt door.
55
55
  }
56
- // 1.0.190: werkwijze-instelling "Opnieuw indelen bij wijziging" aanvullen waar die ontbreekt.
57
- try {
58
- await supabase.rpc("logistics_ensure_rebuffer_setting");
59
- }
60
- catch {
61
- // Ontbreekt de functie nog (schemasync), dan geldt de standaard (aan).
62
- }
56
+ // 1.0.194: "Opnieuw indelen bij wijziging" aanvullen gebeurt niet meer elke
57
+ // ronde, maar hooguit 1x per uur in logistics_tick() (logistics_ensure_periodiek).
63
58
  // 1.0.190: open orders zonder kar opnieuw inplannen (max. 3 pogingen, daarna melding).
64
59
  try {
65
60
  await supabase.rpc("logistics_bewaak_zonder_kar");
@@ -72,6 +67,7 @@ export async function handleLogisticsTick(request, supabase, opts) {
72
67
  // vervaltijd. Fail-closed: bij twijfel wordt de ronde overgeslagen; de
73
68
  // volgende minuut-ronde is het vangnet.
74
69
  const roundId = crypto.randomUUID();
70
+ const roundStart = new Date(Date.now() - 1000).toISOString();
75
71
  let held = false;
76
72
  let lockUnknown = false;
77
73
  try {
@@ -94,8 +90,15 @@ export async function handleLogisticsTick(request, supabase, opts) {
94
90
  }
95
91
  return Response.json({ ...ident, ok: true, skipped: lockUnknown ? "slot_onbekend" : "ronde_loopt_al" }, { status: 200, headers: CORS_HEADERS });
96
92
  }
93
+ // 1.0.194 (B0): start van de ronde koppelen aan de wek-aanroepen die erop wachtten.
97
94
  try {
98
- return await runTickRound(supabase, tickJob, ident);
95
+ await supabase.rpc("logistics_kick_round_start");
96
+ }
97
+ catch {
98
+ // Alleen meting; mag de ronde niet tegenhouden.
99
+ }
100
+ try {
101
+ return await runTickRound(supabase, tickJob, ident, roundStart);
99
102
  }
100
103
  finally {
101
104
  try {
@@ -111,7 +114,8 @@ export async function handleLogisticsTick(request, supabase, opts) {
111
114
  }
112
115
  /** Vaste sleutel van het rondeslot; gelijk aan de check in logistics_plan_kick(). */
113
116
  export const TICK_ROUND_LOCK_KEY = "tick:ronde";
114
- async function runTickRound(supabase, tickJob, ident) {
117
+ async function runTickRound(supabase, tickJob, ident, roundStart = new Date().toISOString()) {
118
+ const roundStartedMs = Date.now();
115
119
  // Meerdere batches per aanroep, met een ruime marge tot de time-out.
116
120
  const deadline = Date.now() + 8000;
117
121
  let last = null;
@@ -201,17 +205,9 @@ async function runTickRound(supabase, tickJob, ident) {
201
205
  catch (e) {
202
206
  buffers = { error: String(e?.message ?? e) };
203
207
  }
204
- // Na het sluiten of losmaken van een buffer: de pickwachtrij opnieuw vullen,
205
- // zodat elke eenheid (ook een losgekoppelde order) zijn eigen karaantallen
206
- // uit het actuele karplan meekrijgt.
207
- let queueRefresh = null;
208
- try {
209
- const { data, error } = await supabase.rpc("logistics_sync_pick_queue");
210
- queueRefresh = error ? { error: error.message } : data;
211
- }
212
- catch (e) {
213
- queueRefresh = { error: String(e?.message ?? e) };
214
- }
208
+ // 1.0.194: de pickwachtrij wordt elke minuut in logistics_tick() (SQL) gevuld
209
+ // en direct na elke indeling door de planwachtrij; niet meer in deze HTTP-ronde.
210
+ const queueRefresh = "in_sql_ronde";
215
211
  // 1.0.169: rijen die op "alleen lezen" geparkeerd stonden vrijgeven zodra
216
212
  // de Floriday-koppeling weer mag schrijven (doet niets zolang alleen lezen).
217
213
  let floridayReadOnly = null;
@@ -383,19 +379,55 @@ async function runTickRound(supabase, tickJob, ident) {
383
379
  catch (e) {
384
380
  barcodes = { error: String(e?.message ?? e) };
385
381
  }
386
- // Laadtoestand per eenheid bijwerken, zodat de pickschermen niet hoeven te
387
- // wisselen tussen teksten maar een vaste toestand met reden zien.
388
- let planState = null;
382
+ // 1.0.194: laadtoestand draait in logistics_tick() (SQL), alleen bij wijziging.
383
+ const planState = "in_sql_ronde";
384
+ // 1.0.194 (B1): kwam er tijdens deze ronde een wek-aanroep binnen, dan nog
385
+ // één keer (begrensd) indelen vóór het slot vrijgaat.
386
+ let kickPending = null;
389
387
  try {
390
- const { data, error } = await supabase.rpc("logistics_refresh_plan_state", { p_limit: 500 });
391
- planState = error ? { error: error.message } : data;
388
+ const { data: pending, error: pendingError } = await supabase.rpc("logistics_kick_pending_take", { p_since: roundStart });
389
+ if (pendingError) {
390
+ kickPending = { error: pendingError.message };
391
+ }
392
+ else if (pending === true) {
393
+ const { runPlanQueue } = await import("../planQueue.server.js");
394
+ kickPending = { extraRonde: await runPlanQueue(supabase, { deadlineAt: Date.now() + 10000 }) };
395
+ }
396
+ else {
397
+ kickPending = { extraRonde: false };
398
+ }
392
399
  }
393
400
  catch (e) {
394
- planState = { error: String(e?.message ?? e) };
401
+ kickPending = { error: String(e?.message ?? e) };
402
+ }
403
+ // 1.0.194 (A3): fouten van de sticker-sync luid melden en vastleggen.
404
+ const stickerSyncFouten = Array.isArray(stickers?.syncFouten)
405
+ ? stickers.syncFouten
406
+ : stickers && typeof stickers === "object" && "error" in stickers
407
+ ? [{ stap: "stickerronde", functie: "runStickerQueue", fout: stickers.error }]
408
+ : [];
409
+ if (stickerSyncFouten.length > 0) {
410
+ console.error("[logistics-tick] sticker-sync fout:", JSON.stringify(stickerSyncFouten));
411
+ }
412
+ try {
413
+ await supabase.rpc("logistics_tick_http_log", {
414
+ p_steps: {
415
+ gestart: roundStart,
416
+ duurMs: Date.now() - roundStartedMs,
417
+ stickerSyncFouten,
418
+ kickPending,
419
+ shippingNotesOk,
420
+ },
421
+ });
422
+ }
423
+ catch {
424
+ // Vastleggen mag de ronde niet blokkeren; de fout staat al in het antwoord.
395
425
  }
396
426
  return Response.json({
397
427
  ...ident,
398
428
  ok: shippingNotesOk,
429
+ stickerSyncFouten,
430
+ kickPending,
399
431
  planState,
400
432
  ticks,
401
433
  status: last?.status ?? "idle",
@@ -1,2 +1,2 @@
1
- export declare const MODULE_VERSION = "1.0.193";
1
+ export declare const MODULE_VERSION = "1.0.195";
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.193";
2
+ export const MODULE_VERSION = "1.0.195";
@@ -8,6 +8,12 @@ export interface StickerRun {
8
8
  handled: number;
9
9
  warnings: number;
10
10
  errors: string[];
11
+ /** 1.0.194: fouten van de sync-stappen in de database (luid melden). */
12
+ syncFouten: Array<{
13
+ stap: string;
14
+ functie: string;
15
+ fout: string;
16
+ }>;
11
17
  }
12
18
  interface Row {
13
19
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"stickerQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/stickerQueue.server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAuB5D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,UAAU,GAAG;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,mBAAmB,CAAC;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAKD,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAExD,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,CAEzD;AAaD,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAwa5G;AAoGD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGzD"}
1
+ {"version":3,"file":"stickerQueue.server.d.ts","sourceRoot":"","sources":["../../src/lib/stickerQueue.server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAuB5D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,wEAAwE;IACxE,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAED,UAAU,GAAG;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,mBAAmB,CAAC;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAKD,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAExD,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,CAEzD;AAaD,wBAAsB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA+a5G;AAoGD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGzD"}
@@ -38,28 +38,33 @@ function base64NaarBytes(b64) {
38
38
  }
39
39
  export async function runStickerQueue(sb, opts = {}) {
40
40
  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: [] };
41
+ const run = { synced: null, released: 0, printed: 0, blocked: 0, retrying: 0, handled: 0, warnings: 0, errors: [], syncFouten: [] };
42
42
  const nu = () => new Date().toISOString();
43
43
  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
- }
44
+ // 1. Rekenen in de database. 1.0.194: een fout van een sync-stap is een
45
+ // zichtbare melding (syncFouten), niet alleen een regel in errors.
46
+ const syncStap = async (naam, fn) => {
47
+ try {
48
+ const { data, error } = await sb.rpc(fn, { p_limit: 200 });
49
+ if (error) {
50
+ run.errors.push(`${naam}: ${error.message}`);
51
+ run.syncFouten.push({ stap: naam, functie: fn, fout: error.message });
52
+ return null;
53
+ }
54
+ return data ?? null;
55
+ }
56
+ catch (e) {
57
+ const msg = String(e?.message ?? e);
58
+ run.errors.push(`${naam}: ${msg}`);
59
+ run.syncFouten.push({ stap: naam, functie: fn, fout: msg });
60
+ return null;
61
+ }
62
+ };
63
+ run.synced = await syncStap("sync", "logistics_sticker_sync");
51
64
  // 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
- }
65
+ await syncStap("eigen stickers", "logistics_own_sticker_sync");
57
66
  // 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
- }
67
+ await syncStap("eigen traystickers", "logistics_own_traysticker_sync");
63
68
  // 2. Tray-stickers: vrij na geaccepteerde belading.
64
69
  {
65
70
  const { data } = await sb
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.195",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [