@flowselections/logistiek-engine 1.0.177 → 1.0.181
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.
- package/db/schema/logistiek-engine.sql +850 -0
- package/dist-lib/components/BeladingIndelingCard.d.ts.map +1 -1
- package/dist-lib/components/BeladingIndelingCard.js +2 -0
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +11 -5
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.js +38 -21
- package/dist-lib/integrations/supabase/types.d.ts +137 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/beladingRegels.d.ts +78 -0
- package/dist-lib/lib/beladingRegels.d.ts.map +1 -0
- package/dist-lib/lib/beladingRegels.js +143 -0
- package/dist-lib/lib/bulkLoadCarrierPlanning.server.js +2 -2
- package/dist-lib/lib/eigenTraysticker.d.ts +17 -0
- package/dist-lib/lib/eigenTraysticker.d.ts.map +1 -0
- package/dist-lib/lib/eigenTraysticker.js +32 -0
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts +35 -3
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +251 -89
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +76 -0
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +26 -2
- package/dist-lib/lib/stickerQueue.server.d.ts +1 -1
- package/dist-lib/lib/stickerQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/stickerQueue.server.js +88 -0
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@ import { attachIndelingToTasks } from "./loadCarrierTaskSync.server.js";
|
|
|
12
12
|
import { trace, newTraceId, classifyError } from "./trace.server.js";
|
|
13
13
|
import { FLOW_NODE } from "./flowNodes.js";
|
|
14
14
|
import { completePlannerDiffRuns, skipPlannerDiffRuns } from "./plannerDiff.server.js";
|
|
15
|
+
import { opnieuwOverSeconden } from "./beladingRegels.js";
|
|
15
16
|
const EMPTY = {
|
|
16
17
|
claimed: 0,
|
|
17
18
|
planned: 0,
|
|
@@ -103,6 +104,7 @@ export async function runPlanQueue(sb, options = {}) {
|
|
|
103
104
|
const bufferId = group.find((g) => g.buffer_id)?.buffer_id ?? null;
|
|
104
105
|
let blocked = false;
|
|
105
106
|
let blockedReasonFor = null;
|
|
107
|
+
let bezet = false;
|
|
106
108
|
await trace(sb, {
|
|
107
109
|
...basis,
|
|
108
110
|
nodeId: FLOW_NODE.ontvangst,
|
|
@@ -120,7 +122,10 @@ export async function runPlanQueue(sb, options = {}) {
|
|
|
120
122
|
if (!plannedBuffers.has(bufferId)) {
|
|
121
123
|
plannedBuffers.add(bufferId);
|
|
122
124
|
const plan = await replanBufferInternal(sb, bufferId);
|
|
123
|
-
if (plan.skipped === "
|
|
125
|
+
if (plan.skipped === "busy") {
|
|
126
|
+
bezet = true;
|
|
127
|
+
}
|
|
128
|
+
else if (plan.skipped === "locked") {
|
|
124
129
|
result.skippedLocked++;
|
|
125
130
|
await trace(sb, {
|
|
126
131
|
...basis,
|
|
@@ -177,7 +182,10 @@ export async function runPlanQueue(sb, options = {}) {
|
|
|
177
182
|
}
|
|
178
183
|
else {
|
|
179
184
|
const plan = await replanOrderInternal(sb, row.order_id);
|
|
180
|
-
if (plan?.skipped === "
|
|
185
|
+
if (plan?.skipped === "busy") {
|
|
186
|
+
bezet = true;
|
|
187
|
+
}
|
|
188
|
+
else if (plan?.skipped === "locked") {
|
|
181
189
|
result.skippedLocked++;
|
|
182
190
|
await trace(sb, {
|
|
183
191
|
...basis,
|
|
@@ -230,6 +238,22 @@ export async function runPlanQueue(sb, options = {}) {
|
|
|
230
238
|
// De blokkade zet de wachtrijregel zelf al op 'geblokkeerd'; die mag niet
|
|
231
239
|
// alsnog als afgerond worden weggeschreven. Een wachtende vergelijking
|
|
232
240
|
// krijgt geen "na"-stand en wordt daarom als overgeslagen afgesloten.
|
|
241
|
+
// 1.0.179 (punt 5): lease bezet is geen "klaar". Opdracht blijft open en komt later terug.
|
|
242
|
+
if (bezet) {
|
|
243
|
+
const sec = opnieuwOverSeconden(Number(row.attempts ?? 0));
|
|
244
|
+
await sb.rpc("logistics_plan_retry_later", { p_id: row.id, p_seconds: sec });
|
|
245
|
+
result.skippedLocked++;
|
|
246
|
+
await trace(sb, {
|
|
247
|
+
...basis,
|
|
248
|
+
step: "Indeling later opnieuw",
|
|
249
|
+
status: "wachtend",
|
|
250
|
+
decision: "Opdracht blijft open",
|
|
251
|
+
reason: "Deze buffer werd op hetzelfde moment al ingedeeld. De order wordt over " + sec + " seconden opnieuw geprobeerd.",
|
|
252
|
+
errorClass: "regel",
|
|
253
|
+
nextStep: "Volgende planronde",
|
|
254
|
+
});
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
233
257
|
if (blocked) {
|
|
234
258
|
// De blokkade raakt soms alleen de buffer-leden zonder kar, niet de
|
|
235
259
|
// order die deze ronde oppakte (FO-2601389). Sluit die claim dan hier
|
|
@@ -11,7 +11,7 @@ export interface StickerRun {
|
|
|
11
11
|
}
|
|
12
12
|
interface Row {
|
|
13
13
|
id: string;
|
|
14
|
-
soort: "sticker" | "traysticker" | "eigen_sticker";
|
|
14
|
+
soort: "sticker" | "traysticker" | "eigen_sticker" | "eigen_traysticker";
|
|
15
15
|
bron_id: string;
|
|
16
16
|
eigen_sticker_id?: string | null;
|
|
17
17
|
order_id: string | null;
|
|
@@ -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;
|
|
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;AAkB5D,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,CAuW5G;AAoGD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGzD"}
|
|
@@ -17,6 +17,7 @@ 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
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";
|
|
22
23
|
/** Opslag van eigen stickers (Klanten-module, customer_product_stickers). */
|
|
@@ -53,6 +54,12 @@ export async function runStickerQueue(sb, opts = {}) {
|
|
|
53
54
|
if (error)
|
|
54
55
|
run.errors.push(`eigen stickers: ${error.message}`);
|
|
55
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
|
+
}
|
|
56
63
|
// 2. Tray-stickers: vrij na geaccepteerde belading.
|
|
57
64
|
{
|
|
58
65
|
const { data } = await sb
|
|
@@ -144,6 +151,7 @@ export async function runStickerQueue(sb, opts = {}) {
|
|
|
144
151
|
.from("logistics_sticker_prints")
|
|
145
152
|
.select(COLS)
|
|
146
153
|
.eq("status", "klaar")
|
|
154
|
+
.neq("soort", "eigen_traysticker")
|
|
147
155
|
.or(`next_attempt_at.is.null,next_attempt_at.lte.${nu()}`)
|
|
148
156
|
.order("created_at")
|
|
149
157
|
.limit(limit);
|
|
@@ -369,6 +377,8 @@ export async function runStickerQueue(sb, opts = {}) {
|
|
|
369
377
|
status: "geslaagd",
|
|
370
378
|
});
|
|
371
379
|
}
|
|
380
|
+
// 4b. Eigen traystickers (1.0.178): één opdracht per tray via layout_print_document.
|
|
381
|
+
await eigenTraystickersPrinten(sb, run, limit);
|
|
372
382
|
// 5. Afmelden in Floriday na de goedgekeurde controlescan.
|
|
373
383
|
run.handled = await afmelden(sb, run);
|
|
374
384
|
return run;
|
|
@@ -508,3 +518,81 @@ async function traystickerLayoutVrijgeven(sb) {
|
|
|
508
518
|
.eq("status", "geblokkeerd");
|
|
509
519
|
return ids.length;
|
|
510
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
|
+
}
|