@flowselections/logistiek-engine 1.0.189 → 1.0.191
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 +1273 -0
- package/dist-lib/components/BeladingIndelingCard.d.ts.map +1 -1
- package/dist-lib/components/BeladingIndelingCard.js +4 -2
- package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
- package/dist-lib/components/GeblokkeerdeOrdersCard.js +43 -4
- package/dist-lib/components/LadingdragersPage.d.ts.map +1 -1
- package/dist-lib/components/LadingdragersPage.js +4 -1
- package/dist-lib/components/OrdersZonderKarCard.d.ts +2 -0
- package/dist-lib/components/OrdersZonderKarCard.d.ts.map +1 -0
- package/dist-lib/components/OrdersZonderKarCard.js +36 -0
- package/dist-lib/components/RegiePage.d.ts.map +1 -1
- package/dist-lib/components/RegiePage.js +2 -1
- package/dist-lib/components/RuleEnginePage.js +8 -3
- package/dist-lib/hooks/useFloricodeLadingdragers.d.ts +2 -0
- package/dist-lib/hooks/useFloricodeLadingdragers.d.ts.map +1 -0
- package/dist-lib/hooks/useFloricodeLadingdragers.js +25 -0
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +1 -0
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
- package/dist-lib/hooks/useGeblokkeerdeOrders.js +38 -1
- package/dist-lib/hooks/useRecalcJob.d.ts +1 -0
- package/dist-lib/hooks/useRecalcJob.d.ts.map +1 -1
- package/dist-lib/hooks/useRecalcJob.js +11 -1
- package/dist-lib/integrations/supabase/types.d.ts +407 -1
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/beladingRegels.d.ts +18 -0
- package/dist-lib/lib/beladingRegels.d.ts.map +1 -1
- package/dist-lib/lib/beladingRegels.js +28 -0
- package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
- package/dist-lib/lib/handlers/logistics-tick.server.js +14 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts +3 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanner.js +18 -13
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts +16 -0
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +394 -24
- package/dist-lib/lib/loadCarrierTypes.d.ts +7 -0
- package/dist-lib/lib/loadCarrierTypes.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierTypes.js +17 -0
- package/dist-lib/lib/logisticsRecalcJob.server.d.ts +1 -0
- package/dist-lib/lib/logisticsRecalcJob.server.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.server.js +3 -1
- package/dist-lib/lib/logisticsRecalculate.functions.js +2 -2
- 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 +6 -1
- package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineSchema.js +9 -0
- package/dist-lib/lib/scheduleTasks.server.d.ts +18 -0
- package/dist-lib/lib/scheduleTasks.server.d.ts.map +1 -0
- package/dist-lib/lib/scheduleTasks.server.js +65 -0
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ import { fallbackCarrierProfile } from "./loadCarrierTypes.js";
|
|
|
12
12
|
import { planByDimensions, DIMENSION_PLANNER_VERSION } from "./dimensionPlanner.js";
|
|
13
13
|
import { buildDimensionItems, carrierDimensions } from "./dimensionData.server.js";
|
|
14
14
|
import { zonderExternAfgehandeld } from "./externalFulfillment.js";
|
|
15
|
-
import { vulBeladingAan, deelUitFloridayVerpakking, plantenVanRegel,
|
|
15
|
+
import { vulBeladingAan, deelUitFloridayVerpakking, plantenVanRegel, beladingBeoordeling, fustPerKarOnmogelijk, karrenOnwaarschijnlijk, verpakkingSleutel, controleerInvariant, VELD_NAAM, } from "./beladingRegels.js";
|
|
16
16
|
// ---------------------------------------------------------------------------
|
|
17
17
|
// Buffer
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
@@ -241,8 +241,14 @@ export async function expandOrderItemsForPlanner(sb, rows, options = {}) {
|
|
|
241
241
|
continue;
|
|
242
242
|
}
|
|
243
243
|
if (kind === "onbekend") {
|
|
244
|
-
// Regel zonder artikel: niet raden (ook niet via de naam)
|
|
245
|
-
|
|
244
|
+
// Regel zonder artikel: niet raden (ook niet via de naam). 1.0.190: alleen deze order wacht.
|
|
245
|
+
const reden = `Regel "${row.product_name ?? "onbekend"}" heeft geen artikel: kies een artikel bij deze orderregel. ` +
|
|
246
|
+
"Alleen deze order wacht; de rest van de buffer wordt gewoon ingedeeld.";
|
|
247
|
+
if (options.orderBlokkades && orderKey) {
|
|
248
|
+
options.orderBlokkades.set(orderKey, reden);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
throw new Error(`Indeling geblokkeerd: ${reden}`);
|
|
246
252
|
}
|
|
247
253
|
if (kind === "fout") {
|
|
248
254
|
throw new Error(`Indeling geblokkeerd voor ${row.product_name ?? "onbekend artikel"}: ${lines[0]?.note ?? "fout in de samenstelling"}.`);
|
|
@@ -273,7 +279,13 @@ export async function expandOrderItemsForPlanner(sb, rows, options = {}) {
|
|
|
273
279
|
continue;
|
|
274
280
|
const p = l.product_id ? prodById.get(String(l.product_id)) : null;
|
|
275
281
|
if (!p) {
|
|
276
|
-
|
|
282
|
+
const reden = `Groepslid ${l.trade_item_key ?? "onbekend"} van ${row.product_name ?? "groep"} heeft geen artikel: kies een artikel. ` +
|
|
283
|
+
"Alleen deze order wacht.";
|
|
284
|
+
if (options.orderBlokkades && orderKey) {
|
|
285
|
+
options.orderBlokkades.set(orderKey, reden);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
throw new Error(`Indeling geblokkeerd: ${reden}`);
|
|
277
289
|
}
|
|
278
290
|
const eigenLijn = lineMap?.get(String(p.floriday_trade_item_id ?? "")) ?? lineMap?.get(String(p.id)) ?? null;
|
|
279
291
|
const lid = source === "handmatig"
|
|
@@ -314,7 +326,7 @@ async function bevestigdeSleutels(sb, orderIds) {
|
|
|
314
326
|
set.add(`${r.order_id}|${r.verpakking_sleutel}`);
|
|
315
327
|
return set;
|
|
316
328
|
}
|
|
317
|
-
async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile) {
|
|
329
|
+
async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPerRegel) {
|
|
318
330
|
const fustIds = Array.from(new Set(rawRows.map((r) => r.products?.fust_type_id).filter((x) => !!x).map(String)));
|
|
319
331
|
const fustById = new Map();
|
|
320
332
|
if (fustIds.length > 0) {
|
|
@@ -327,28 +339,54 @@ async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile) {
|
|
|
327
339
|
if (r.product_id)
|
|
328
340
|
fustPerProduct.set(String(r.product_id), r.products?.fust_type_id ?? null);
|
|
329
341
|
const kandidaten = [];
|
|
342
|
+
const waarschuwingen = [];
|
|
330
343
|
for (const i of inputs) {
|
|
331
344
|
if (i.plants <= 0)
|
|
332
345
|
continue;
|
|
333
346
|
const fustId = i.product_id ? fustPerProduct.get(String(i.product_id)) ?? null : null;
|
|
334
|
-
const
|
|
347
|
+
const oordeel = beladingBeoordeling({
|
|
335
348
|
belading: { plants_per_crate: i.plants_per_crate, crates_per_layer: i.crates_per_layer, layers_per_cart: i.layers_per_cart },
|
|
336
349
|
fust: fustId ? fustById.get(fustId) ?? null : null,
|
|
337
|
-
maxLagenLadingdrager: i.
|
|
350
|
+
maxLagenLadingdrager: (profielPerRegel?.get(i.order_item_id) ?? profile).layers_per_carrier,
|
|
351
|
+
metBron: Boolean(i.packing_authoritative),
|
|
338
352
|
});
|
|
339
|
-
|
|
353
|
+
for (const w of oordeel.waarschuwen) {
|
|
354
|
+
waarschuwingen.push({ order_id: i.order_id ?? null, sleutel: `lagen:${verpakkingSleutel(i.product_id, i)}`, tekst: `${i.product_name}: ${w}` });
|
|
355
|
+
}
|
|
356
|
+
if (oordeel.blokkeren.length === 0)
|
|
340
357
|
continue;
|
|
341
358
|
kandidaten.push({
|
|
342
359
|
order_id: i.order_id ?? null,
|
|
343
360
|
product: i.product_name,
|
|
344
361
|
sleutel: verpakkingSleutel(i.product_id, i),
|
|
345
|
-
redenen,
|
|
362
|
+
redenen: oordeel.blokkeren,
|
|
346
363
|
});
|
|
347
364
|
}
|
|
348
365
|
if (kandidaten.length === 0)
|
|
349
|
-
return [];
|
|
366
|
+
return { blokkeren: [], waarschuwingen };
|
|
350
367
|
const ok = await bevestigdeSleutels(sb, Array.from(new Set(kandidaten.map((k) => k.order_id).filter((x) => !!x))));
|
|
351
|
-
return kandidaten.filter((k) => !ok.has(`${k.order_id}|${k.sleutel}`));
|
|
368
|
+
return { blokkeren: kandidaten.filter((k) => !ok.has(`${k.order_id}|${k.sleutel}`)), waarschuwingen };
|
|
369
|
+
}
|
|
370
|
+
/** Standaardladingdrager uit de werkwijze (karrenindeling.default_carrier_type); alleen terugval. */
|
|
371
|
+
async function standaardLadingdragerUitWerkwijze(sb) {
|
|
372
|
+
const { data } = await sb
|
|
373
|
+
.from("logistics_rule_configs")
|
|
374
|
+
.select("settings")
|
|
375
|
+
.eq("is_active", true)
|
|
376
|
+
.order("updated_at", { ascending: false })
|
|
377
|
+
.limit(1);
|
|
378
|
+
const st = Array.isArray(data) && data.length > 0 ? data[0]?.settings : null;
|
|
379
|
+
const v = st?.karrenindeling?.fields?.default_carrier_type ?? st?.karrenindeling?.default_carrier_type;
|
|
380
|
+
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
381
|
+
}
|
|
382
|
+
/** Actuele beladingwaarschuwingen per order vastleggen (vervangt de vorige van die orders). */
|
|
383
|
+
async function bewaarBeladingWaarschuwingen(sb, orderIds, items, warnings) {
|
|
384
|
+
const { error } = await sb.rpc("logistics_belading_waarschuwingen_zet", {
|
|
385
|
+
p_order_ids: orderIds,
|
|
386
|
+
p_items: items.filter((w) => w.order_id),
|
|
387
|
+
});
|
|
388
|
+
if (error)
|
|
389
|
+
warnings.push(`Beladingwaarschuwingen konden niet worden vastgelegd: ${error.message}`);
|
|
352
390
|
}
|
|
353
391
|
/** Invariant: elk fust van elke ingedeelde regel staat op precies één kar en de planten kloppen. */
|
|
354
392
|
export function invariantFouten(inputs, carts) {
|
|
@@ -369,6 +407,114 @@ export async function loadCarrierProfiles(sb) {
|
|
|
369
407
|
.order("sort_order", { ascending: true });
|
|
370
408
|
return Array.isArray(data) ? data : [];
|
|
371
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* 1.0.190 (E): Floriday-ladingdrager (packaging.loadCarrier) naar ladingdragertype.
|
|
412
|
+
* Vaste referentiedata, geen omgevingswaarde. Onbekende waarde = geen keuze.
|
|
413
|
+
*/
|
|
414
|
+
export const FLORIDAY_LADINGDRAGER = {
|
|
415
|
+
DANISH_TROLLEY: "danish_container",
|
|
416
|
+
DANISH_TROLLEY_NON_CC_RFID: "danish_container",
|
|
417
|
+
DANISH_TROLLEY_WATER_TRAY: "danish_container",
|
|
418
|
+
// Floriday-authenticatie 1.0.117: AUCTION_TROLLEY = "Stapelwagen (veilingkar)".
|
|
419
|
+
AUCTION_TROLLEY: "trolley",
|
|
420
|
+
EURO_TROLLEY: "euro_rolcontainer",
|
|
421
|
+
HT_EURO_PALLET: "euro_pallet",
|
|
422
|
+
EURO_PALLET: "euro_pallet",
|
|
423
|
+
PALLET: "pallet",
|
|
424
|
+
BLOCK_PALLET: "pallet",
|
|
425
|
+
DISPOSABLE_PALLET: "pallet",
|
|
426
|
+
EURO_ROLL_CONTAINER: "euro_rolcontainer",
|
|
427
|
+
NONE: "loose",
|
|
428
|
+
};
|
|
429
|
+
export function ladingdragerUitVerpakking(waarde, actieveCodes) {
|
|
430
|
+
const w = String(waarde ?? "").trim();
|
|
431
|
+
if (!w)
|
|
432
|
+
return null;
|
|
433
|
+
if (actieveCodes.has(w))
|
|
434
|
+
return w;
|
|
435
|
+
const c = FLORIDAY_LADINGDRAGER[w.toUpperCase()];
|
|
436
|
+
return c && actieveCodes.has(c) ? c : null;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Ladingdrager per planregel: handmatige keuze → orderregel → primaire verpakking
|
|
440
|
+
* van het product. Geen standaardtype: zonder bron blijft de regel leeg (blokkeren).
|
|
441
|
+
*/
|
|
442
|
+
async function bepaalLadingdragers(sb, inputs, rawRows, profiles, handmatig, standaardGebruikt, standaardCode) {
|
|
443
|
+
const codes = new Set(profiles.map((p) => String(p.code)));
|
|
444
|
+
const uit = new Map();
|
|
445
|
+
const perRegel = new Map();
|
|
446
|
+
for (const r of rawRows)
|
|
447
|
+
perRegel.set(String(r.id), ladingdragerUitVerpakking(r.load_carrier_type, codes));
|
|
448
|
+
const productIds = Array.from(new Set(inputs.map((i) => i.product_id).filter((x) => !!x)));
|
|
449
|
+
const perProduct = new Map();
|
|
450
|
+
if (productIds.length > 0) {
|
|
451
|
+
const { data, error } = await sb
|
|
452
|
+
.from("product_packings")
|
|
453
|
+
.select("product_id, load_carrier, is_primary, sort_order")
|
|
454
|
+
.in("product_id", productIds);
|
|
455
|
+
if (error)
|
|
456
|
+
throw new Error(`Verpakkingen konden niet worden gelezen: ${error.message}`);
|
|
457
|
+
const rijen = (Array.isArray(data) ? data : []).sort((a, b) => Number(Boolean(b.is_primary)) - Number(Boolean(a.is_primary)) || Number(a.sort_order ?? 0) - Number(b.sort_order ?? 0));
|
|
458
|
+
for (const r of rijen) {
|
|
459
|
+
const pid = String(r.product_id);
|
|
460
|
+
if (perProduct.get(pid))
|
|
461
|
+
continue;
|
|
462
|
+
perProduct.set(pid, ladingdragerUitVerpakking(r.load_carrier, codes));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
// 1.0.190: eerst de Floriday-verpakking van het artikel
|
|
466
|
+
// (floriday_trade_items_cache.data.packingConfigurations[].loadCarrier, primaire eerst).
|
|
467
|
+
const perFloriday = new Map();
|
|
468
|
+
if (productIds.length > 0) {
|
|
469
|
+
const { data: prods } = await sb
|
|
470
|
+
.from("products")
|
|
471
|
+
.select("id, floriday_trade_item_id")
|
|
472
|
+
.in("id", productIds);
|
|
473
|
+
const tiPerProduct = new Map();
|
|
474
|
+
for (const p of (Array.isArray(prods) ? prods : [])) {
|
|
475
|
+
if (p?.floriday_trade_item_id)
|
|
476
|
+
tiPerProduct.set(String(p.id), String(p.floriday_trade_item_id));
|
|
477
|
+
}
|
|
478
|
+
const tiIds = Array.from(new Set(tiPerProduct.values()));
|
|
479
|
+
if (tiIds.length > 0) {
|
|
480
|
+
const { data: tis } = await sb
|
|
481
|
+
.from("floriday_trade_items_cache")
|
|
482
|
+
.select("floriday_id, data, is_deleted")
|
|
483
|
+
.in("floriday_id", tiIds);
|
|
484
|
+
const lcPerTi = new Map();
|
|
485
|
+
for (const t of (Array.isArray(tis) ? tis : [])) {
|
|
486
|
+
if (t?.is_deleted)
|
|
487
|
+
continue;
|
|
488
|
+
const confs = Array.isArray(t?.data?.packingConfigurations) ? t.data.packingConfigurations : [];
|
|
489
|
+
const sorted = [...confs].sort((a, b) => Number(Boolean(b?.primary)) - Number(Boolean(a?.primary)));
|
|
490
|
+
let code = null;
|
|
491
|
+
for (const c of sorted) {
|
|
492
|
+
code = ladingdragerUitVerpakking(c?.loadCarrier, codes);
|
|
493
|
+
if (code)
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
lcPerTi.set(String(t.floriday_id), code);
|
|
497
|
+
}
|
|
498
|
+
for (const [pid, ti] of tiPerProduct)
|
|
499
|
+
perFloriday.set(pid, lcPerTi.get(ti) ?? null);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
const handmatigeCode = handmatig && codes.has(handmatig) ? handmatig : null;
|
|
503
|
+
const terugval = standaardCode && codes.has(standaardCode) ? standaardCode : null;
|
|
504
|
+
for (const i of inputs) {
|
|
505
|
+
const base = i.order_item_id.includes("::") ? i.order_item_id.split("::")[0] : i.order_item_id;
|
|
506
|
+
const pid = i.product_id ? String(i.product_id) : null;
|
|
507
|
+
const uitFloriday = pid ? perFloriday.get(pid) || null : null;
|
|
508
|
+
const uitProduct = pid ? perProduct.get(pid) || null : null;
|
|
509
|
+
let code = handmatigeCode || perRegel.get(base) || uitFloriday || uitProduct || null;
|
|
510
|
+
if (!code && terugval) {
|
|
511
|
+
code = terugval;
|
|
512
|
+
standaardGebruikt?.add(i.order_item_id);
|
|
513
|
+
}
|
|
514
|
+
uit.set(i.order_item_id, code);
|
|
515
|
+
}
|
|
516
|
+
return uit;
|
|
517
|
+
}
|
|
372
518
|
function profileFor(profiles, code) {
|
|
373
519
|
return profiles.find((p) => p.code === code) ?? fallbackCarrierProfile(code);
|
|
374
520
|
}
|
|
@@ -637,6 +783,9 @@ function isReservationOrTerminal(order) {
|
|
|
637
783
|
return true;
|
|
638
784
|
if (order.is_reservation === true)
|
|
639
785
|
return true;
|
|
786
|
+
// 1.0.190 (F): geannuleerde orders horen nooit in een buffer of op een kar.
|
|
787
|
+
if (order.cancelled_at)
|
|
788
|
+
return true;
|
|
640
789
|
const status = String(order.status ?? "").trim().toLowerCase();
|
|
641
790
|
return TERMINALE_STATUSSEN.has(status);
|
|
642
791
|
}
|
|
@@ -824,13 +973,14 @@ export async function replanBufferInternal(sb, bufferId, options = {}) {
|
|
|
824
973
|
export const BUFFER_BUSY_MESSAGE = "Deze orderbuffer wordt op dit moment al bijgewerkt; probeer het zo opnieuw.";
|
|
825
974
|
async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
826
975
|
const warnings = [];
|
|
976
|
+
const beladingWaarschuwingen = [];
|
|
827
977
|
// Bevroren karren blijven staan; al het overige van de héle buffer wordt
|
|
828
978
|
// samen ingedeeld, zodat orders van de buffer op dezelfde karren komen.
|
|
829
979
|
const keepCartIds = (options.keepCartIds ?? []).map(String).filter(Boolean);
|
|
830
980
|
const isSupplement = keepCartIds.length > 0;
|
|
831
981
|
const { data: orders } = await sb
|
|
832
982
|
.from("orders")
|
|
833
|
-
.select("id, order_number, customer_id, custom_fields, plan_locked_at, status, is_reservation")
|
|
983
|
+
.select("id, order_number, customer_id, custom_fields, plan_locked_at, status, is_reservation, cancelled_at")
|
|
834
984
|
.eq("buffer_id", bufferId)
|
|
835
985
|
.is("deleted_at", null);
|
|
836
986
|
const allOrderRows = Array.isArray(orders) ? orders : [];
|
|
@@ -938,7 +1088,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
938
1088
|
const { data: rawItems } = await sb
|
|
939
1089
|
.from("order_items")
|
|
940
1090
|
.select("id, order_id, product_id, product_name, quantity, unit, plants_per_crate, crates_per_layer, layers_per_cart, " +
|
|
941
|
-
"packing_locked_at, packing_locked_by, source_line_key, " +
|
|
1091
|
+
"packing_locked_at, packing_locked_by, source_line_key, load_carrier_type, " +
|
|
942
1092
|
"products(plants_per_crate, crates_per_layer, layers_per_cart, weight, floriday_trade_item_id, fust_type_id)")
|
|
943
1093
|
.in("order_id", idList)
|
|
944
1094
|
// Regels in quarantaine (Verkoop-herstel) nooit inplannen.
|
|
@@ -1028,6 +1178,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1028
1178
|
const expandNotes = [];
|
|
1029
1179
|
const ontbrekendeVelden = new Map();
|
|
1030
1180
|
const onbekendePlanten = [];
|
|
1181
|
+
const orderBlokkades = new Map();
|
|
1031
1182
|
let inputs = await expandOrderItemsForPlanner(sb, rawRows, {
|
|
1032
1183
|
packingByOrder,
|
|
1033
1184
|
packingByOrderLine,
|
|
@@ -1036,7 +1187,92 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1036
1187
|
notes: expandNotes,
|
|
1037
1188
|
ontbrekend: ontbrekendeVelden,
|
|
1038
1189
|
onbekendePlanten,
|
|
1190
|
+
orderBlokkades,
|
|
1039
1191
|
});
|
|
1192
|
+
// 1.0.190 (G): regel zonder artikel blokkeert alleen die order, nooit de hele buffer.
|
|
1193
|
+
if (orderBlokkades.size > 0) {
|
|
1194
|
+
const geblokkeerd = new Set(orderBlokkades.keys());
|
|
1195
|
+
inputs = inputs.filter((i) => !i.order_id || !geblokkeerd.has(String(i.order_id)));
|
|
1196
|
+
if (!options.dryRun) {
|
|
1197
|
+
for (const [oid, reden] of orderBlokkades) {
|
|
1198
|
+
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1199
|
+
p_order_ids: [oid],
|
|
1200
|
+
p_reason: reden,
|
|
1201
|
+
p_details: { reason_code: "artikel_ontbreekt", bufferId, path: "typescript" },
|
|
1202
|
+
});
|
|
1203
|
+
if (blockError)
|
|
1204
|
+
warnings.push(`Blokkade kon niet worden vastgelegd: ${blockError.message}`);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
warnings.push(...orderBlokkades.values());
|
|
1208
|
+
}
|
|
1209
|
+
// 1.0.190 (E): ladingdrager per regel uit de verpakking (loadCarrier), nooit een stille standaard.
|
|
1210
|
+
const profilesVroeg = await loadCarrierProfiles(sb);
|
|
1211
|
+
const standaardGebruikt = new Set();
|
|
1212
|
+
const standaardType = profilesVroeg.find((p) => p.is_default)?.code ??
|
|
1213
|
+
(await standaardLadingdragerUitWerkwijze(sb));
|
|
1214
|
+
const ladingdragerPerRegel = await bepaalLadingdragers(sb, inputs, rawRows, profilesVroeg, options.carrierType ?? null, standaardGebruikt, standaardType ?? null);
|
|
1215
|
+
if (standaardGebruikt.size > 0) {
|
|
1216
|
+
const perOrder = new Map();
|
|
1217
|
+
for (const i of inputs) {
|
|
1218
|
+
if (!standaardGebruikt.has(i.order_item_id))
|
|
1219
|
+
continue;
|
|
1220
|
+
const l = perOrder.get(String(i.order_id ?? "")) ?? [];
|
|
1221
|
+
l.push(i.product_name);
|
|
1222
|
+
perOrder.set(String(i.order_id ?? ""), l);
|
|
1223
|
+
}
|
|
1224
|
+
for (const [oid, namen] of perOrder) {
|
|
1225
|
+
beladingWaarschuwingen.push({
|
|
1226
|
+
order_id: oid || null,
|
|
1227
|
+
sleutel: "ladingdrager_standaard",
|
|
1228
|
+
tekst: `Ladingdrager niet bekend uit verpakking, standaard gebruikt (${namen.slice(0, 5).join(", ")}).`,
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
{
|
|
1233
|
+
const onbekend = new Map();
|
|
1234
|
+
for (const i of inputs) {
|
|
1235
|
+
if (ladingdragerPerRegel.get(i.order_item_id))
|
|
1236
|
+
continue;
|
|
1237
|
+
const oid = String(i.order_id ?? "");
|
|
1238
|
+
if (!oid)
|
|
1239
|
+
continue;
|
|
1240
|
+
const l = onbekend.get(oid) ?? [];
|
|
1241
|
+
l.push(i.product_name);
|
|
1242
|
+
onbekend.set(oid, l);
|
|
1243
|
+
}
|
|
1244
|
+
if (onbekend.size > 0) {
|
|
1245
|
+
inputs = inputs.filter((i) => !onbekend.has(String(i.order_id ?? "")));
|
|
1246
|
+
for (const [oid, namen] of onbekend) {
|
|
1247
|
+
const reden = `Ladingdrager onbekend voor ${namen.slice(0, 5).join(", ")}: de verpakking noemt geen ladingdrager ` +
|
|
1248
|
+
"en er is er geen gekozen. Alleen deze order wacht.";
|
|
1249
|
+
warnings.push(reden);
|
|
1250
|
+
if (!options.dryRun) {
|
|
1251
|
+
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1252
|
+
p_order_ids: [oid],
|
|
1253
|
+
p_reason: reden,
|
|
1254
|
+
p_details: { reason_code: "ladingdrager_onbekend", bufferId, path: "typescript" },
|
|
1255
|
+
});
|
|
1256
|
+
if (blockError)
|
|
1257
|
+
warnings.push(`Blokkade kon niet worden vastgelegd: ${blockError.message}`);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
if (inputs.length === 0 && (orderBlokkades.size > 0 || [...ladingdragerPerRegel.values()].some((v) => !v))) {
|
|
1263
|
+
const reden = "Alle orders van deze buffer wachten op een artikel of ladingdrager; bestaande karren blijven staan.";
|
|
1264
|
+
return {
|
|
1265
|
+
ok: false,
|
|
1266
|
+
bufferId,
|
|
1267
|
+
orderIds,
|
|
1268
|
+
cartsCreated: 0,
|
|
1269
|
+
replacedManualCount: 0,
|
|
1270
|
+
usedFloridayPacking: false,
|
|
1271
|
+
warnings: [...warnings, reden],
|
|
1272
|
+
skipped: "blocked",
|
|
1273
|
+
blockedReason: reden,
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1040
1276
|
// Groepsregel naast ledenregels: niet ingedeeld, wel zichtbaar gemeld bij de order.
|
|
1041
1277
|
for (const n of expandNotes) {
|
|
1042
1278
|
if (!n.order_id)
|
|
@@ -1160,7 +1396,21 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1160
1396
|
const neverMix = new Set((overrides ?? []).filter((o) => o.never_mix && o.product_id).map((o) => String(o.product_id)));
|
|
1161
1397
|
const profiles = await loadCarrierProfiles(sb);
|
|
1162
1398
|
const rules = await loadBeladingRules(sb);
|
|
1163
|
-
|
|
1399
|
+
// 1.0.190 (E): geen standaard-'trolley' meer. Hoofdladingdrager = meest voorkomende van de regels.
|
|
1400
|
+
const telling = new Map();
|
|
1401
|
+
for (const i of inputs) {
|
|
1402
|
+
const c = ladingdragerPerRegel.get(i.order_item_id);
|
|
1403
|
+
if (c)
|
|
1404
|
+
telling.set(c, (telling.get(c) ?? 0) + 1);
|
|
1405
|
+
}
|
|
1406
|
+
const hoofdCode = [...telling.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? null;
|
|
1407
|
+
const defaultProfile = { code: options.carrierType ?? hoofdCode ?? "" };
|
|
1408
|
+
const profielPerRegel = new Map();
|
|
1409
|
+
for (const i of inputs) {
|
|
1410
|
+
const c = ladingdragerPerRegel.get(i.order_item_id);
|
|
1411
|
+
if (c)
|
|
1412
|
+
profielPerRegel.set(i.order_item_id, profileFor(profiles, c));
|
|
1413
|
+
}
|
|
1164
1414
|
// Guard: zonder beladingbron mag er niet gegokt worden. Ladingdragers zonder
|
|
1165
1415
|
// lagenmodel (los product / enkele eenheid) hebben de belading niet nodig.
|
|
1166
1416
|
const guardProfile = profileFor(profiles, options.carrierType ?? defaultProfile.code);
|
|
@@ -1231,7 +1481,12 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1231
1481
|
}
|
|
1232
1482
|
// 1.0.179 (punt 3): plausibiliteit, alle ordersoorten. Eén bevestiging per order en verpakking.
|
|
1233
1483
|
if (!options.dryRun) {
|
|
1234
|
-
const
|
|
1484
|
+
const oordeel = await beladingOnwaarschijnlijk(sb, inputs, rawRows, guardProfile, profielPerRegel);
|
|
1485
|
+
const onwaarschijnlijk = oordeel.blokkeren;
|
|
1486
|
+
beladingWaarschuwingen.push(...oordeel.waarschuwingen);
|
|
1487
|
+
for (const w of beladingWaarschuwingen)
|
|
1488
|
+
warnings.push(w.tekst);
|
|
1489
|
+
await bewaarBeladingWaarschuwingen(sb, orderIds, beladingWaarschuwingen, warnings);
|
|
1235
1490
|
if (onwaarschijnlijk.length > 0) {
|
|
1236
1491
|
const reason = `Belading onwaarschijnlijk: ${onwaarschijnlijk.slice(0, 10).map((o) => `${o.product}: ${o.redenen.join("; ")}`).join(" | ")}. ` +
|
|
1237
1492
|
"Kantoor moet dit bevestigen voordat er wordt ingedeeld.";
|
|
@@ -1360,7 +1615,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1360
1615
|
// Ladingdrager per orderregel bepalen en per type een ronde draaien.
|
|
1361
1616
|
const groups = new Map();
|
|
1362
1617
|
for (const input of inputs) {
|
|
1363
|
-
const code =
|
|
1618
|
+
const code = ladingdragerPerRegel.get(input.order_item_id) ?? defaultProfile.code;
|
|
1364
1619
|
const list = groups.get(code) ?? [];
|
|
1365
1620
|
list.push(input);
|
|
1366
1621
|
groups.set(code, list);
|
|
@@ -1437,17 +1692,31 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1437
1692
|
// 1.0.179 (punt 11): invariant; bij een verschil wordt niets weggeschreven en niets geprint.
|
|
1438
1693
|
if (!options.dryRun) {
|
|
1439
1694
|
const perOrder = new Map();
|
|
1695
|
+
const fustTeVeel = new Map();
|
|
1440
1696
|
for (const c of plannedCarts) {
|
|
1441
1697
|
for (const oid of new Set(c.items.map((it) => it.order_id).filter((x) => !!x))) {
|
|
1442
1698
|
perOrder.set(oid, (perOrder.get(oid) ?? 0) + 1);
|
|
1443
1699
|
}
|
|
1444
1700
|
}
|
|
1445
|
-
|
|
1701
|
+
// 1.0.190: meer dan 200 fusten op één kar is onmogelijk; per order blokkeren.
|
|
1702
|
+
for (const c of plannedCarts) {
|
|
1703
|
+
const fusten = c.items.reduce((t, it) => t + Number(it.crates ?? 0), 0);
|
|
1704
|
+
const tekst = fustPerKarOnmogelijk(fusten);
|
|
1705
|
+
if (!tekst)
|
|
1706
|
+
continue;
|
|
1707
|
+
for (const oid of new Set(c.items.map((it) => it.order_id).filter((x) => !!x))) {
|
|
1708
|
+
perOrder.set(oid, Math.max(perOrder.get(oid) ?? 0, 0));
|
|
1709
|
+
fustTeVeel.set(oid, tekst);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
const teVeel = Array.from(perOrder.entries()).filter(([oid, n]) => karrenOnwaarschijnlijk(n) != null || fustTeVeel.has(oid));
|
|
1446
1713
|
if (teVeel.length > 0) {
|
|
1447
1714
|
const ok = await bevestigdeSleutels(sb, teVeel.map(([oid]) => oid));
|
|
1448
|
-
const
|
|
1715
|
+
const sleutelVan = (oid, n) => (fustTeVeel.has(oid) ? "fust_per_kar" : `karren:${n}`);
|
|
1716
|
+
const tekstVan = (oid, n) => fustTeVeel.get(oid) ?? karrenOnwaarschijnlijk(n) ?? "";
|
|
1717
|
+
const open = teVeel.filter(([oid, n]) => !ok.has(`${oid}|${sleutelVan(oid, n)}`));
|
|
1449
1718
|
if (open.length > 0) {
|
|
1450
|
-
const reason = `Belading onwaarschijnlijk: ${open.map(([oid, n]) => `order ${orderRows.find((o) => String(o.id) === oid)?.order_number ?? oid}: ${
|
|
1719
|
+
const reason = `Belading onwaarschijnlijk: ${open.map(([oid, n]) => `order ${orderRows.find((o) => String(o.id) === oid)?.order_number ?? oid}: ${tekstVan(oid, n)}`).join("; ")}. ` +
|
|
1451
1720
|
"Kantoor moet dit bevestigen voordat er wordt ingedeeld.";
|
|
1452
1721
|
await sb.rpc("logistics_plan_block", {
|
|
1453
1722
|
p_order_ids: orderIds,
|
|
@@ -1456,7 +1725,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1456
1725
|
reason_code: "belading_onwaarschijnlijk",
|
|
1457
1726
|
bufferId,
|
|
1458
1727
|
path: "typescript",
|
|
1459
|
-
bevestigen: open.map(([oid, n]) => ({ order_id: oid, sleutel:
|
|
1728
|
+
bevestigen: open.map(([oid, n]) => ({ order_id: oid, sleutel: sleutelVan(oid, n), redenen: [tekstVan(oid, n)] })),
|
|
1460
1729
|
},
|
|
1461
1730
|
});
|
|
1462
1731
|
return {
|
|
@@ -1596,6 +1865,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1596
1865
|
getal(r["crates_per_layer"]),
|
|
1597
1866
|
getal(r["layers_per_cart"]),
|
|
1598
1867
|
getal(r["layer_fraction"]),
|
|
1868
|
+
getal(r["lagen"]),
|
|
1599
1869
|
getal(r["layer_share_pct"]),
|
|
1600
1870
|
getal(r["layer_index"]),
|
|
1601
1871
|
getal(r["crates_in_layer"]),
|
|
@@ -1653,7 +1923,11 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1653
1923
|
plants_per_crate: i.plants_per_crate,
|
|
1654
1924
|
crates_per_layer: i.crates_per_layer,
|
|
1655
1925
|
layers_per_cart: i.layers_per_cart,
|
|
1656
|
-
|
|
1926
|
+
// 1.0.190: layer_fraction = vulling per laag (0–1); lagen = fusten ÷ fusten per laag.
|
|
1927
|
+
layer_fraction: Math.min(1, Math.max(0, Number(i.layer_fraction ?? 0))),
|
|
1928
|
+
lagen: Number(i.crates_per_layer) > 0
|
|
1929
|
+
? Math.round((Number(i.crates) / Number(i.crates_per_layer)) * 1000) / 1000
|
|
1930
|
+
: null,
|
|
1657
1931
|
layer_share_pct: i.layer_share_pct,
|
|
1658
1932
|
layer_index: i.layer_index ?? null,
|
|
1659
1933
|
crates_in_layer: i.crates_in_layer ?? null,
|
|
@@ -1684,7 +1958,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1684
1958
|
const { data: rijen, error: itemsError } = await sb
|
|
1685
1959
|
.from("order_cart_items")
|
|
1686
1960
|
.select("cart_id, order_item_id, product_id, crates, boxes, weight_kg, plants_per_crate, " +
|
|
1687
|
-
"crates_per_layer, layers_per_cart, layer_fraction, layer_share_pct, layer_index, crates_in_layer")
|
|
1961
|
+
"crates_per_layer, layers_per_cart, layer_fraction, lagen, layer_share_pct, layer_index, crates_in_layer")
|
|
1688
1962
|
.in("cart_id", slice);
|
|
1689
1963
|
if (itemsError) {
|
|
1690
1964
|
throw new Error(`Inhoud van bestaande karren kon niet worden gelezen: ${itemsError.message}`);
|
|
@@ -1714,9 +1988,76 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1714
1988
|
else
|
|
1715
1989
|
nieuw.push(g);
|
|
1716
1990
|
}
|
|
1717
|
-
const
|
|
1991
|
+
const teVerwijderenAlle = [];
|
|
1718
1992
|
for (const lijst of beschikbaarPerSig.values())
|
|
1719
|
-
|
|
1993
|
+
teVerwijderenAlle.push(...lijst);
|
|
1994
|
+
// 1.0.190 (B): een order die in deze ronde niet is ingedeeld (wacht op artikel,
|
|
1995
|
+
// ladingdrager of bevestiging) houdt zijn bestaande karren. Alleen karren waarvan
|
|
1996
|
+
// alle inhoud bij wél ingedeelde orders hoort, mogen vervangen worden.
|
|
1997
|
+
const ingedeeld = new Set(inputs.map((i) => String(i.order_id ?? "")).filter(Boolean));
|
|
1998
|
+
const orderVanRegel = new Map();
|
|
1999
|
+
for (const r of rawRows)
|
|
2000
|
+
orderVanRegel.set(String(r.id), String(r.order_id ?? ""));
|
|
2001
|
+
const karOrder = new Map();
|
|
2002
|
+
for (const c of vergelijkbaar)
|
|
2003
|
+
karOrder.set(String(c.id), c.order_id ? String(c.order_id) : null);
|
|
2004
|
+
// 1.0.190 (FO-2601368): regels van orders die deze buffer al hebben verlaten
|
|
2005
|
+
// ("verhuizers") staan niet in rawRows. Hun kar mag pas weg zodra die order in
|
|
2006
|
+
// zijn nieuwe buffer een kar heeft; anders zou hij zonder indeling achterblijven.
|
|
2007
|
+
const onbekendeRegels = new Set();
|
|
2008
|
+
for (const id of teVerwijderenAlle) {
|
|
2009
|
+
for (const it of huidigeItems.get(id) ?? []) {
|
|
2010
|
+
const rid = String(it.order_item_id ?? "");
|
|
2011
|
+
if (rid && !orderVanRegel.has(rid))
|
|
2012
|
+
onbekendeRegels.add(rid);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
const verhuizerZonderKar = new Set();
|
|
2016
|
+
if (onbekendeRegels.size > 0) {
|
|
2017
|
+
const ids = [...onbekendeRegels];
|
|
2018
|
+
const verhuizers = new Set();
|
|
2019
|
+
for (let s = 0; s < ids.length; s += 200) {
|
|
2020
|
+
const { data: rr, error: rrErr } = await sb.from("order_items").select("id, order_id").is("quarantined_at", null).in("id", ids.slice(s, s + 200));
|
|
2021
|
+
if (rrErr)
|
|
2022
|
+
throw new Error(`Orderregels van eerdere bufferleden konden niet worden gelezen: ${rrErr.message}`);
|
|
2023
|
+
for (const r of Array.isArray(rr) ? rr : []) {
|
|
2024
|
+
orderVanRegel.set(String(r.id), String(r.order_id ?? ""));
|
|
2025
|
+
if (r.order_id)
|
|
2026
|
+
verhuizers.add(String(r.order_id));
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
const scopeIds = new Set(huidigeIds);
|
|
2030
|
+
for (const oid of verhuizers) {
|
|
2031
|
+
const { data: elders } = await sb
|
|
2032
|
+
.from("order_cart_items")
|
|
2033
|
+
.select("cart_id, order_items!inner(order_id), order_carts!inner(id, archived_at)")
|
|
2034
|
+
.eq("order_items.order_id", oid)
|
|
2035
|
+
.is("order_carts.archived_at", null)
|
|
2036
|
+
.limit(50);
|
|
2037
|
+
const heeftElders = (Array.isArray(elders) ? elders : []).some((e) => !scopeIds.has(String(e.cart_id)));
|
|
2038
|
+
if (!heeftElders)
|
|
2039
|
+
verhuizerZonderKar.add(oid);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
const teVerwijderen = teVerwijderenAlle.filter((id) => {
|
|
2043
|
+
const eigen = karOrder.get(id);
|
|
2044
|
+
if (eigen && !ingedeeld.has(eigen))
|
|
2045
|
+
return false;
|
|
2046
|
+
for (const it of huidigeItems.get(id) ?? []) {
|
|
2047
|
+
const oid = orderVanRegel.get(String(it.order_item_id ?? ""));
|
|
2048
|
+
if (oid && verhuizerZonderKar.has(oid))
|
|
2049
|
+
return false;
|
|
2050
|
+
if (oid && !ingedeeld.has(oid) && !onbekendeRegels.has(String(it.order_item_id ?? "")))
|
|
2051
|
+
return false;
|
|
2052
|
+
}
|
|
2053
|
+
return true;
|
|
2054
|
+
});
|
|
2055
|
+
if (verhuizerZonderKar.size > 0) {
|
|
2056
|
+
warnings.push(`${verhuizerZonderKar.size} order(s) zijn naar een andere buffer verhuisd en houden hun oude kar tot de nieuwe indeling klaar is.`);
|
|
2057
|
+
}
|
|
2058
|
+
if (teVerwijderen.length < teVerwijderenAlle.length) {
|
|
2059
|
+
warnings.push(`${teVerwijderenAlle.length - teVerwijderen.length} bestaande kar(ren) blijven staan omdat hun order nu wacht; de indeling wordt vervangen zodra de order weer ingedeeld kan worden.`);
|
|
2060
|
+
}
|
|
1720
2061
|
let created = behouden.size;
|
|
1721
2062
|
const idByPlanIndex = new Map(behouden);
|
|
1722
2063
|
// A3: verouderde karren weg en nieuwe karren erbij in één transactie. Mislukt dit,
|
|
@@ -1739,6 +2080,35 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1739
2080
|
}
|
|
1740
2081
|
created += mapping.length;
|
|
1741
2082
|
}
|
|
2083
|
+
// 1.0.190 (FO-2601368): staan ingedeelde orders van deze buffer nog op een kar
|
|
2084
|
+
// van hun vorige buffer, laat die vorige buffer dan opnieuw indelen; daar gaat
|
|
2085
|
+
// de oude kar pas weg nu de nieuwe klaar is.
|
|
2086
|
+
if (ingedeeld.size > 0) {
|
|
2087
|
+
try {
|
|
2088
|
+
const nieuweIds = new Set([...idByPlanIndex.values(), ...keepCartIds.map(String)]);
|
|
2089
|
+
const { data: oud } = await sb
|
|
2090
|
+
.from("order_cart_items")
|
|
2091
|
+
.select("cart_id, order_items!inner(order_id), order_carts!inner(buffer_id, archived_at)")
|
|
2092
|
+
.in("order_items.order_id", [...ingedeeld])
|
|
2093
|
+
.is("order_carts.archived_at", null)
|
|
2094
|
+
.limit(1000);
|
|
2095
|
+
const oudeBuffers = new Set();
|
|
2096
|
+
for (const r of Array.isArray(oud) ? oud : []) {
|
|
2097
|
+
const b = r.order_carts?.buffer_id;
|
|
2098
|
+
if (!nieuweIds.has(String(r.cart_id)) && b && String(b) !== String(bufferId))
|
|
2099
|
+
oudeBuffers.add(String(b));
|
|
2100
|
+
}
|
|
2101
|
+
for (const b of oudeBuffers) {
|
|
2102
|
+
const { data: lid } = await sb.from("orders").select("id").eq("buffer_id", b).is("deleted_at", null).limit(1);
|
|
2103
|
+
const peer = Array.isArray(lid) && lid[0] ? String(lid[0].id) : null;
|
|
2104
|
+
if (peer)
|
|
2105
|
+
await sb.rpc("logistics_plan_enqueue", { p_order_id: peer, p_reason: "vorige buffer opruimen na verhuizing" });
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
catch (e) {
|
|
2109
|
+
console.error(`[logistiek-engine] buffer ${bufferId}: vorige buffer opruimen niet ingepland`, e);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
1742
2112
|
if (nieuw.length === 0) {
|
|
1743
2113
|
console.log(`[logistiek-engine] buffer ${bufferId}: indeling ongewijzigd, ${behouden.size} kar(ren) behouden, ` +
|
|
1744
2114
|
`${teVerwijderen.length} verouderde kar(ren) verwijderd.`);
|
|
@@ -16,4 +16,11 @@ export declare const CARRIER_LABELS: Record<string, string>;
|
|
|
16
16
|
export declare function carrierLabel(code: string, fallback?: string): string;
|
|
17
17
|
/** Fallbackprofiel als een type nog niet in de database staat. */
|
|
18
18
|
export declare function fallbackCarrierProfile(code: string): CarrierProfile;
|
|
19
|
+
/**
|
|
20
|
+
* 1.0.190: Floriday-code per eigen ladingdragertype. Wordt alleen gebruikt om de
|
|
21
|
+
* naam uit floricode_load_carriers() te tonen; koppelen gebeurt altijd op code.
|
|
22
|
+
*/
|
|
23
|
+
export declare const FLORIDAY_CODE_VOOR_TYPE: Record<string, string>;
|
|
24
|
+
/** Naam op het scherm: eerst de Floricode-naam (op code), anders eigen label. */
|
|
25
|
+
export declare function ladingdragerNaam(code: string, floricode: Map<string, string> | null, fallback?: string): string;
|
|
19
26
|
//# sourceMappingURL=loadCarrierTypes.d.ts.map
|
|
@@ -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"}
|
|
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"}
|
|
@@ -39,3 +39,20 @@ export function fallbackCarrierProfile(code) {
|
|
|
39
39
|
...(map[code] ?? {}),
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* 1.0.190: Floriday-code per eigen ladingdragertype. Wordt alleen gebruikt om de
|
|
44
|
+
* naam uit floricode_load_carriers() te tonen; koppelen gebeurt altijd op code.
|
|
45
|
+
*/
|
|
46
|
+
export const FLORIDAY_CODE_VOOR_TYPE = {
|
|
47
|
+
danish_container: "DANISH_TROLLEY",
|
|
48
|
+
trolley: "AUCTION_TROLLEY",
|
|
49
|
+
euro_rolcontainer: "EURO_TROLLEY",
|
|
50
|
+
pallet: "PALLET",
|
|
51
|
+
euro_pallet: "EURO_PALLET",
|
|
52
|
+
loose: "NONE",
|
|
53
|
+
};
|
|
54
|
+
/** Naam op het scherm: eerst de Floricode-naam (op code), anders eigen label. */
|
|
55
|
+
export function ladingdragerNaam(code, floricode, fallback) {
|
|
56
|
+
const f = FLORIDAY_CODE_VOOR_TYPE[code] ?? code;
|
|
57
|
+
return floricode?.get(f) ?? floricode?.get(code) ?? carrierLabel(code, fallback);
|
|
58
|
+
}
|
|
@@ -24,6 +24,7 @@ export declare function getLatestJob(sb: SupabaseClient): Promise<RecalcJob | nu
|
|
|
24
24
|
export declare function startJob(sb: SupabaseClient, startedBy: string | null, strategyId: string | null): Promise<RecalcJob>;
|
|
25
25
|
/** Verwerkt één batch van de lopende job. Geeft de bijgewerkte job terug. */
|
|
26
26
|
export declare function tickJob(sb: SupabaseClient): Promise<RecalcJob | null>;
|
|
27
|
+
export { scheduleTasksPerOrder } from "./scheduleTasks.server.js";
|
|
27
28
|
/** Draait de afsluitende herberekenstappen (planning, tellingen, capaciteit). */
|
|
28
29
|
export declare function runFinalSteps(sb: SupabaseClient, days?: number): Promise<{
|
|
29
30
|
step: string;
|
|
@@ -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,iFAAiF;AACjF,wBAAsB,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK;
|
|
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;AAGlE,iFAAiF;AACjF,wBAAsB,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK;UAiBpC,MAAM;QAAM,OAAO;YAAU,MAAM;KAO/D"}
|