@flowselections/logistiek-engine 1.0.211 → 1.0.214
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 +233 -0
- package/dist-lib/components/DataGereedheidCard.d.ts.map +1 -1
- package/dist-lib/components/DataGereedheidCard.js +24 -5
- package/dist-lib/index.d.ts +2 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +2 -0
- package/dist-lib/integrations/supabase/types.d.ts +61 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanner.d.ts +13 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanner.js +25 -7
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +41 -13
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/dist-lib/lib/planPreview.d.ts +39 -0
- package/dist-lib/lib/planPreview.d.ts.map +1 -0
- package/dist-lib/lib/planPreview.functions.d.ts +13 -0
- package/dist-lib/lib/planPreview.functions.d.ts.map +1 -0
- package/dist-lib/lib/planPreview.functions.js +34 -0
- package/dist-lib/lib/planPreview.js +87 -0
- package/package.json +1 -1
|
@@ -31,6 +31,12 @@ export interface PlannerInputItem {
|
|
|
31
31
|
* Afknijpen op layers_per_carrier zou kunstmatig extra karren opleveren.
|
|
32
32
|
*/
|
|
33
33
|
packing_authoritative?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* 1.0.213: fysiek maximum aantal lagen op de gekozen ladingdrager =
|
|
36
|
+
* floor(hoogte ladingdrager ÷ max(fusthoogte, planthoogte incl. pot)). Alleen gezet
|
|
37
|
+
* als al die maten bekend zijn; nooit een standaardwaarde.
|
|
38
|
+
*/
|
|
39
|
+
fysiek_max_lagen?: number | null;
|
|
34
40
|
}
|
|
35
41
|
export interface PlannerOptions {
|
|
36
42
|
carrier: CarrierProfile;
|
|
@@ -160,5 +166,12 @@ export declare function karCapaciteit(productLagen: Array<number | null | undefi
|
|
|
160
166
|
};
|
|
161
167
|
/** Vulgraad in procenten (heel getal), of null als de capaciteit onbekend is. */
|
|
162
168
|
export declare function karVulgraad(lagen: number, capaciteit: number | null): number | null;
|
|
169
|
+
/**
|
|
170
|
+
* 1.0.213: fysiek maximum aantal lagen = floor(hoogte ladingdrager ÷ laaghoogte),
|
|
171
|
+
* alleen als beide maten bekend zijn (nooit een standaardwaarde). null = niet te controleren.
|
|
172
|
+
*/
|
|
173
|
+
export declare function fysiekeMaxLagen(item: PlannerInputItem, _carrier?: CarrierProfile): number | null;
|
|
174
|
+
/** Fysiek maximum lagen uit hoogte ladingdrager en laaghoogte; null als een maat ontbreekt. */
|
|
175
|
+
export declare function berekenFysiekMaxLagen(dragerHoogteCm: number | null | undefined, fustHoogteCm: number | null | undefined, plantHoogteCm: number | null | undefined): number | null;
|
|
163
176
|
export declare function planLoadUnits(inputs: PlannerInputItem[], options: PlannerOptions): PlannerOutput;
|
|
164
177
|
//# sourceMappingURL=loadCarrierPlanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadCarrierPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanner.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,aAAa,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,8FAA8F;IAC9F,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"loadCarrierPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -210,6 +210,21 @@ export function karVulgraad(lagen, capaciteit) {
|
|
|
210
210
|
return null;
|
|
211
211
|
return Math.round((100 * lagen) / capaciteit);
|
|
212
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* 1.0.213: fysiek maximum aantal lagen = floor(hoogte ladingdrager ÷ laaghoogte),
|
|
215
|
+
* alleen als beide maten bekend zijn (nooit een standaardwaarde). null = niet te controleren.
|
|
216
|
+
*/
|
|
217
|
+
export function fysiekeMaxLagen(item, _carrier) {
|
|
218
|
+
const n = Number(item.fysiek_max_lagen ?? 0);
|
|
219
|
+
return n >= 1 ? Math.floor(n) : null;
|
|
220
|
+
}
|
|
221
|
+
/** Fysiek maximum lagen uit hoogte ladingdrager en laaghoogte; null als een maat ontbreekt. */
|
|
222
|
+
export function berekenFysiekMaxLagen(dragerHoogteCm, fustHoogteCm, plantHoogteCm) {
|
|
223
|
+
const h = Number(dragerHoogteCm ?? 0), f = Number(fustHoogteCm ?? 0), p = Number(plantHoogteCm ?? 0);
|
|
224
|
+
if (!(h > 0) || !(f > 0) || !(p > 0))
|
|
225
|
+
return null;
|
|
226
|
+
return Math.max(1, Math.floor(h / Math.max(f, p) + 1e-9));
|
|
227
|
+
}
|
|
213
228
|
function productLagen(item, carrier) {
|
|
214
229
|
if (carrier.capacity_model === "single")
|
|
215
230
|
return 1;
|
|
@@ -217,6 +232,9 @@ function productLagen(item, carrier) {
|
|
|
217
232
|
const grens = carrier.werkwijze_max_lagen;
|
|
218
233
|
if (typeof grens === "number" && grens > 0 && !item.packing_authoritative)
|
|
219
234
|
l = Math.min(l, Math.round(grens));
|
|
235
|
+
const fys = fysiekeMaxLagen(item, carrier);
|
|
236
|
+
if (fys != null)
|
|
237
|
+
l = Math.min(l, fys);
|
|
220
238
|
return l;
|
|
221
239
|
}
|
|
222
240
|
function accepteert(kar, rest, crates, r) {
|
|
@@ -397,11 +415,9 @@ export function planLoadUnits(inputs, options) {
|
|
|
397
415
|
}))
|
|
398
416
|
.filter((i) => i.plants > 0), r.opts.sortOrder);
|
|
399
417
|
if (carrier.capacity_model === "none") {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
carts.push(fullCart(it, crates, crates, 1, ++n, r));
|
|
404
|
-
}
|
|
418
|
+
// 1.0.213: zonder ladingdrager kan niets op een kar; geen indeling.
|
|
419
|
+
if (items.length > 0)
|
|
420
|
+
warnings.push("ladingdrager ontbreekt");
|
|
405
421
|
return { carts, warnings };
|
|
406
422
|
}
|
|
407
423
|
// STAP A: volle karren per product (capaciteit = lagen per kar van dat product).
|
|
@@ -468,6 +484,8 @@ export function planLoadUnits(inputs, options) {
|
|
|
468
484
|
}
|
|
469
485
|
for (const kar of open)
|
|
470
486
|
carts.push(samenvatten(kar, rests, carts.length + 1, r));
|
|
471
|
-
|
|
472
|
-
|
|
487
|
+
// 1.0.213: een kar zonder fusten bestaat niet.
|
|
488
|
+
const gevuld = carts.filter((c) => (Array.isArray(c.items) ? c.items : []).some((x) => Number(x?.crates ?? 0) > 0));
|
|
489
|
+
gevuld.forEach((c, i) => { c.cart_number = i + 1; });
|
|
490
|
+
return { carts: gevuld, warnings };
|
|
473
491
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadCarrierPlanning.server.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanning.server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"loadCarrierPlanning.server.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanning.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// draait de pure planner per ladingdragertype en schrijft het resultaat weg
|
|
6
6
|
// naar order_carts / order_cart_items.
|
|
7
7
|
// ============================================================================
|
|
8
|
-
import { planLoadUnits, LOAD_CARRIER_PLANNER_VERSION, bepaalLaagMenging, } from "./loadCarrierPlanner.js";
|
|
8
|
+
import { planLoadUnits, LOAD_CARRIER_PLANNER_VERSION, bepaalLaagMenging, berekenFysiekMaxLagen, } from "./loadCarrierPlanner.js";
|
|
9
9
|
import { traceBatch } from "./trace.server.js";
|
|
10
10
|
import { zonderQuarantaine } from "./quarantaine.js";
|
|
11
11
|
import { zonderStandaardBelading } from "./hoofdverpakking.js";
|
|
@@ -431,6 +431,8 @@ async function beladingOnwaarschijnlijk(sb, inputs, rawRows, profile, profielPer
|
|
|
431
431
|
max_crates_per_layer: d?.maxPerLaag ?? (prof.max_crates_per_layer ?? null),
|
|
432
432
|
standaard_lagen: prof.layers_per_carrier,
|
|
433
433
|
});
|
|
434
|
+
// 1.0.213: fysieke grens aan de lagen per kar voor de planner (alleen met bekende maten).
|
|
435
|
+
i.fysiek_max_lagen = berekenFysiekMaxLagen(d?.h ?? null, mt?.height_mm ? mt.height_mm / 10 : null, mt?.plant ?? null);
|
|
434
436
|
for (const w of fysiek.waarschuwen) {
|
|
435
437
|
waarschuwingen.push({ order_id: i.order_id ?? null, sleutel: `fysiek:${verpakkingSleutel(i.product_id, i)}`, tekst: w });
|
|
436
438
|
}
|
|
@@ -1368,7 +1370,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1368
1370
|
}
|
|
1369
1371
|
// Groepsregel naast ledenregels: niet ingedeeld, wel zichtbaar gemeld bij de order.
|
|
1370
1372
|
for (const n of expandNotes) {
|
|
1371
|
-
if (!n.order_id)
|
|
1373
|
+
if (!n.order_id || options.dryRun)
|
|
1372
1374
|
continue;
|
|
1373
1375
|
const { error: noteError } = await sb.rpc("logistics_trace_order_step", {
|
|
1374
1376
|
p_order_id: n.order_id,
|
|
@@ -1533,9 +1535,9 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1533
1535
|
}
|
|
1534
1536
|
if (options.carrierType && !bekendeCodes.has(options.carrierType))
|
|
1535
1537
|
nietInBeheer.set(options.carrierType, []);
|
|
1536
|
-
if (nietInBeheer.size > 0
|
|
1538
|
+
if (nietInBeheer.size > 0) {
|
|
1537
1539
|
const reason = ladingdragerNietInBeheerTekst(nietInBeheer);
|
|
1538
|
-
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1540
|
+
const { error: blockError } = options.dryRun ? { error: null } : await sb.rpc("logistics_plan_block", {
|
|
1539
1541
|
p_order_ids: orderIds,
|
|
1540
1542
|
p_reason: reason,
|
|
1541
1543
|
p_details: {
|
|
@@ -1599,9 +1601,9 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1599
1601
|
// 1.0.198: gewicht alleen relevant als de ladingdrager een kg-grens heeft.
|
|
1600
1602
|
const heeftKgGrens = Number(guardProfile.max_weight_kg) > 0;
|
|
1601
1603
|
const zonderGewicht = heeftKgGrens ? inputs.filter((i) => !(Number(i.weight_per_crate) > 0) && i.plants > 0) : [];
|
|
1602
|
-
if (zonderGewicht.length > 0 && rules?.gewichtVerplicht === true
|
|
1604
|
+
if (zonderGewicht.length > 0 && rules?.gewichtVerplicht === true) {
|
|
1603
1605
|
const reason = gewichtOnbekendTekst(zonderGewicht.map((i) => i.product_name));
|
|
1604
|
-
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1606
|
+
const { error: blockError } = options.dryRun ? { error: null } : await sb.rpc("logistics_plan_block", {
|
|
1605
1607
|
p_order_ids: orderIds,
|
|
1606
1608
|
p_reason: reason,
|
|
1607
1609
|
p_details: { reason_code: "gewicht_onbekend", bufferId, path: "typescript",
|
|
@@ -1629,7 +1631,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1629
1631
|
}
|
|
1630
1632
|
// Planten per fust is altijd nodig (ook zonder lagenmodel): fusten = planten / planten per fust.
|
|
1631
1633
|
const blokkeerOnvolledig = onvolledig.filter((o) => o.velden.includes("plants_per_crate") || (needsBelading && !useDimensions));
|
|
1632
|
-
if ((blokkeerOnvolledig.length > 0 || onbekendePlanten.length > 0)
|
|
1634
|
+
if ((blokkeerOnvolledig.length > 0 || onbekendePlanten.length > 0)) {
|
|
1633
1635
|
const delen = [
|
|
1634
1636
|
...blokkeerOnvolledig.slice(0, 10).map((o) => `${o.item.product_name}: ${o.velden.map((v) => VELD_NAAM[v]).join(", ")} onbekend`),
|
|
1635
1637
|
...onbekendePlanten.slice(0, 10).map((o) => `${o.naam}: eenheid fust zonder planten per fust`),
|
|
@@ -1637,7 +1639,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1637
1639
|
const reason = `Belading onvolledig voor ${blokkeerOnvolledig.length + onbekendePlanten.length} orderregel(s): ${delen.join("; ")}. ` +
|
|
1638
1640
|
WAAR_INVULLEN;
|
|
1639
1641
|
console.error(`[logistiek-engine] buffer ${bufferId} geblokkeerd: ${reason}`);
|
|
1640
|
-
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1642
|
+
const { error: blockError } = options.dryRun ? { error: null } : await sb.rpc("logistics_plan_block", {
|
|
1641
1643
|
p_order_ids: orderIds,
|
|
1642
1644
|
p_reason: reason,
|
|
1643
1645
|
p_details: {
|
|
@@ -1668,16 +1670,18 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1668
1670
|
};
|
|
1669
1671
|
}
|
|
1670
1672
|
// 1.0.179 (punt 3): plausibiliteit, alle ordersoorten. Eén bevestiging per order en verpakking.
|
|
1671
|
-
|
|
1673
|
+
// 1.0.213: ook in droge modus rekenen (alleen lezen); schrijven alleen buiten droge modus.
|
|
1674
|
+
{
|
|
1672
1675
|
const oordeel = await beladingOnwaarschijnlijk(sb, inputs, rawRows, guardProfile, profielPerRegel);
|
|
1673
1676
|
const onwaarschijnlijk = oordeel.blokkeren;
|
|
1674
1677
|
// 1.0.197: fysiek onmogelijk = altijd blokkeren, niet te bevestigen; alleen gegevens aanpassen helpt.
|
|
1675
1678
|
if (oordeel.onmogelijk.length > 0) {
|
|
1676
1679
|
beladingWaarschuwingen.push(...oordeel.waarschuwingen);
|
|
1677
|
-
|
|
1680
|
+
if (!options.dryRun)
|
|
1681
|
+
await bewaarBeladingWaarschuwingen(sb, orderIds, beladingWaarschuwingen, warnings);
|
|
1678
1682
|
const reason = `Belading fysiek onmogelijk: ${oordeel.onmogelijk.slice(0, 10).map((o) => o.redenen.join("; ")).join(" | ")}. ` +
|
|
1679
1683
|
"Pas de gegevens aan in Beheer → Gegevens voor karindeling; bevestigen is hier niet mogelijk.";
|
|
1680
|
-
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1684
|
+
const { error: blockError } = options.dryRun ? { error: null } : await sb.rpc("logistics_plan_block", {
|
|
1681
1685
|
p_order_ids: orderIds,
|
|
1682
1686
|
p_reason: reason,
|
|
1683
1687
|
p_details: {
|
|
@@ -1707,11 +1711,12 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1707
1711
|
beladingWaarschuwingen.push(...oordeel.waarschuwingen);
|
|
1708
1712
|
for (const w of beladingWaarschuwingen)
|
|
1709
1713
|
warnings.push(w.tekst);
|
|
1710
|
-
|
|
1714
|
+
if (!options.dryRun)
|
|
1715
|
+
await bewaarBeladingWaarschuwingen(sb, orderIds, beladingWaarschuwingen, warnings);
|
|
1711
1716
|
if (onwaarschijnlijk.length > 0) {
|
|
1712
1717
|
const reason = `Belading onwaarschijnlijk: ${onwaarschijnlijk.slice(0, 10).map((o) => `${o.product}: ${o.redenen.join("; ")}`).join(" | ")}. ` +
|
|
1713
1718
|
"Kantoor moet dit bevestigen voordat er wordt ingedeeld.";
|
|
1714
|
-
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1719
|
+
const { error: blockError } = options.dryRun ? { error: null } : await sb.rpc("logistics_plan_block", {
|
|
1715
1720
|
p_order_ids: orderIds,
|
|
1716
1721
|
p_reason: reason,
|
|
1717
1722
|
p_details: { reason_code: "belading_onwaarschijnlijk", bufferId, path: "typescript", bevestigen: onwaarschijnlijk.slice(0, 50) },
|
|
@@ -1838,6 +1843,7 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1838
1843
|
}
|
|
1839
1844
|
else {
|
|
1840
1845
|
// Ladingdrager per orderregel bepalen en per type een ronde draaien.
|
|
1846
|
+
const geenLadingdrager = [];
|
|
1841
1847
|
const groups = new Map();
|
|
1842
1848
|
for (const input of inputs) {
|
|
1843
1849
|
const code = ladingdragerPerRegel.get(input.order_item_id) ?? defaultProfile.code;
|
|
@@ -1871,12 +1877,34 @@ async function replanBufferUnlocked(sb, bufferId, options = {}) {
|
|
|
1871
1877
|
ownCarrierFromLayers: settings?.own_cart_from_layers ?? null,
|
|
1872
1878
|
sortOrder: "none",
|
|
1873
1879
|
});
|
|
1880
|
+
if (profile.capacity_model === "none" && list.length > 0) {
|
|
1881
|
+
geenLadingdrager.push(...list.map((x) => x.product_name));
|
|
1882
|
+
continue;
|
|
1883
|
+
}
|
|
1874
1884
|
plannedCarts = plannedCarts.concat(result.carts);
|
|
1875
1885
|
warnings.push(...result.warnings);
|
|
1876
1886
|
}
|
|
1877
1887
|
plannedCarts.forEach((c, idx) => {
|
|
1878
1888
|
c.cart_number = idx + 1;
|
|
1879
1889
|
});
|
|
1890
|
+
// 1.0.213: een product zonder ladingdrager (NONE / losse levering) kan niet op een kar: geen indeling.
|
|
1891
|
+
if (geenLadingdrager.length > 0) {
|
|
1892
|
+
const namen = Array.from(new Set(geenLadingdrager)).slice(0, 10).join(", ");
|
|
1893
|
+
const reason = `Geen indeling: ladingdrager ontbreekt (${namen}). Stel de ladingdrager van de hoofdverpakking in.`;
|
|
1894
|
+
if (!options.dryRun) {
|
|
1895
|
+
const { error: blockError } = await sb.rpc("logistics_plan_block", {
|
|
1896
|
+
p_order_ids: orderIds,
|
|
1897
|
+
p_reason: reason,
|
|
1898
|
+
p_details: { reason_code: "ladingdrager_ontbreekt", bufferId, path: "typescript", producten: Array.from(new Set(geenLadingdrager)).slice(0, 50) },
|
|
1899
|
+
});
|
|
1900
|
+
if (blockError)
|
|
1901
|
+
warnings.push(`Blokkade kon niet worden vastgelegd: ${blockError.message}`);
|
|
1902
|
+
}
|
|
1903
|
+
return {
|
|
1904
|
+
ok: false, bufferId, orderIds, cartsCreated: 0, replacedManualCount: 0, usedFloridayPacking,
|
|
1905
|
+
warnings: [...warnings, reason], skipped: "blocked", blockedReason: reason, beladingSources,
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1880
1908
|
}
|
|
1881
1909
|
// Veiligheidsgrens: een onrealistisch grote uitkomst wordt niet afgekapt maar
|
|
1882
1910
|
// geblokkeerd. Een half plan laat planten stilzwijgend uit de pickstroom vallen.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const MODULE_VERSION = "1.0.
|
|
1
|
+
export declare const MODULE_VERSION = "1.0.214";
|
|
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.
|
|
2
|
+
export const MODULE_VERSION = "1.0.214";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PlannedLoadUnit } from "./loadCarrierPlanner.js";
|
|
2
|
+
export interface PlanPreviewRegel {
|
|
3
|
+
orderItemId: string;
|
|
4
|
+
product: string;
|
|
5
|
+
fust: number;
|
|
6
|
+
stuks: number;
|
|
7
|
+
}
|
|
8
|
+
export interface PlanPreviewKar {
|
|
9
|
+
karNummer: number;
|
|
10
|
+
ladingdrager: string;
|
|
11
|
+
lagen: number;
|
|
12
|
+
platen: number;
|
|
13
|
+
vulgraadPct: number;
|
|
14
|
+
teHoog: boolean;
|
|
15
|
+
karTekst: string;
|
|
16
|
+
regels: PlanPreviewRegel[];
|
|
17
|
+
}
|
|
18
|
+
export interface PlanPreviewOrder {
|
|
19
|
+
orderId: string;
|
|
20
|
+
orderNummer: string | null;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
reden: string | null;
|
|
23
|
+
waarschuwingen: string[];
|
|
24
|
+
karren: PlanPreviewKar[];
|
|
25
|
+
}
|
|
26
|
+
type DryRun = (sb: any, bufferId: string) => Promise<{
|
|
27
|
+
ok: boolean;
|
|
28
|
+
blockedReason?: string;
|
|
29
|
+
warnings?: string[];
|
|
30
|
+
carts?: PlannedLoadUnit[];
|
|
31
|
+
} | null>;
|
|
32
|
+
/** Vulgraad zoals Floriday: Σ per regel (lagen ÷ lagen per kar van die regel). */
|
|
33
|
+
export declare function vulgraadFloriday(items: PlannedLoadUnit["items"]): number;
|
|
34
|
+
export declare function lagenVanKar(kar: PlannedLoadUnit): number;
|
|
35
|
+
/** Zelfde vorm als karTekst in de database: "6,6 lagen · Deense container + 6 platen · 83 %". */
|
|
36
|
+
export declare function karTekstVan(lagen: number, ladingdrager: string, pct: number): string;
|
|
37
|
+
export declare function bouwPlanPreview(sb: any, orderIds: string[], dryRun: DryRun): Promise<PlanPreviewOrder[]>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=planPreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planPreview.d.ts","sourceRoot":"","sources":["../../src/lib/planPreview.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AACD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,KAAK,MAAM,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AAIrJ,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,MAAM,CAOxE;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAKxD;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpF;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAyD9G"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type PlanPreviewOrder } from "./planPreview.js";
|
|
2
|
+
export declare const logisticsPlanPreview: import("@tanstack/start-client-core").RequiredFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, undefined, undefined, undefined>, import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
3
|
+
supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
|
|
4
|
+
userId: string;
|
|
5
|
+
claims: import("@supabase/auth-js").User;
|
|
6
|
+
}, undefined, undefined, undefined>], (input: {
|
|
7
|
+
orderIds: string[];
|
|
8
|
+
}) => {
|
|
9
|
+
orderIds: string[];
|
|
10
|
+
}, Promise<{
|
|
11
|
+
orders: PlanPreviewOrder[];
|
|
12
|
+
}>>;
|
|
13
|
+
//# sourceMappingURL=planPreview.functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planPreview.functions.d.ts","sourceRoot":"","sources":["../../src/lib/planPreview.functions.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAIvE,eAAO,MAAM,oBAAoB;;;;8CAEP;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE;;;YAQQ,gBAAgB,EAAE;GAatE,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// 1.0.213: logistics_plan_preview — karindeling narekenen zonder iets te schrijven.
|
|
2
|
+
// Zelfde planner en werkwijze als de wachtrij (replanBufferInternal), maar in droge modus:
|
|
3
|
+
// geen karren, geen wachtrij, geen events, geen blokkades, geen bufferbesluit.
|
|
4
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware.js";
|
|
6
|
+
import { readableServerErrors } from "./readableServerErrors.js";
|
|
7
|
+
import { bouwPlanPreview } from "./planPreview.js";
|
|
8
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9
|
+
export const logisticsPlanPreview = createServerFn({ method: "POST" })
|
|
10
|
+
.middleware([readableServerErrors, requireSupabaseAuth])
|
|
11
|
+
.inputValidator((input) => {
|
|
12
|
+
const ids = Array.isArray(input?.orderIds) ? input.orderIds.map(String) : [];
|
|
13
|
+
if (ids.length === 0)
|
|
14
|
+
throw new Error("Geef minimaal één order op.");
|
|
15
|
+
if (ids.length > 50)
|
|
16
|
+
throw new Error(`Maximaal 50 orders per voorbeeld (ontvangen: ${ids.length}).`);
|
|
17
|
+
const fout = ids.find((x) => !UUID_RE.test(x));
|
|
18
|
+
if (fout)
|
|
19
|
+
throw new Error(`Ongeldig order-id: ${fout}`);
|
|
20
|
+
return { orderIds: Array.from(new Set(ids)) };
|
|
21
|
+
})
|
|
22
|
+
.handler(async ({ data, context }) => {
|
|
23
|
+
// Toegang: ingelogd, via dezelfde interne guard als de rest van de Engine (fail-closed).
|
|
24
|
+
const { error: gErr } = await context.supabase.rpc("logistics_acc_guard", {
|
|
25
|
+
p_level: "ingelogd",
|
|
26
|
+
p_fn: "logistics_plan_preview",
|
|
27
|
+
});
|
|
28
|
+
if (gErr)
|
|
29
|
+
throw new Error(`Geen toegang: ${gErr.message}`);
|
|
30
|
+
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
31
|
+
const { replanBufferInternal } = await import("./loadCarrierPlanning.server.js");
|
|
32
|
+
const orders = await bouwPlanPreview(supabaseAdmin, data.orderIds, (sb, bufferId) => replanBufferInternal(sb, bufferId, { dryRun: true }));
|
|
33
|
+
return { orders };
|
|
34
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { extraPlaten } from "./extraPlaten.js";
|
|
2
|
+
const nl1 = (n) => String(Math.round(n * 10) / 10).replace(".", ",");
|
|
3
|
+
/** Vulgraad zoals Floriday: Σ per regel (lagen ÷ lagen per kar van die regel). */
|
|
4
|
+
export function vulgraadFloriday(items) {
|
|
5
|
+
let v = 0;
|
|
6
|
+
for (const it of Array.isArray(items) ? items : []) {
|
|
7
|
+
const cpl = Number(it.crates_per_layer) || 0, lpc = Number(it.layers_per_cart) || 0;
|
|
8
|
+
if (cpl > 0 && lpc > 0)
|
|
9
|
+
v += Number(it.crates) / cpl / lpc;
|
|
10
|
+
}
|
|
11
|
+
return v;
|
|
12
|
+
}
|
|
13
|
+
export function lagenVanKar(kar) {
|
|
14
|
+
const t = Number(kar.total_layers_used);
|
|
15
|
+
if (Number.isFinite(t) && t > 0)
|
|
16
|
+
return t;
|
|
17
|
+
return (Array.isArray(kar.items) ? kar.items : []).reduce((s, it) => s + (Number(it.crates_per_layer) > 0 ? Number(it.crates) / Number(it.crates_per_layer) : 0), 0);
|
|
18
|
+
}
|
|
19
|
+
/** Zelfde vorm als karTekst in de database: "6,6 lagen · Deense container + 6 platen · 83 %". */
|
|
20
|
+
export function karTekstVan(lagen, ladingdrager, pct) {
|
|
21
|
+
const p = extraPlaten(lagen) ?? 0;
|
|
22
|
+
const laagWoord = Math.round(lagen * 10) / 10 === 1 ? "laag" : "lagen";
|
|
23
|
+
const platen = p === 0 ? "" : p === 1 ? " + 1 plaat" : ` + ${p} platen`;
|
|
24
|
+
return `${nl1(lagen)} ${laagWoord} · ${ladingdrager}${platen} · ${Math.round(pct)} %`;
|
|
25
|
+
}
|
|
26
|
+
export async function bouwPlanPreview(sb, orderIds, dryRun) {
|
|
27
|
+
const { data: rows, error } = await sb.from("orders").select("id, order_number, buffer_id").in("id", orderIds);
|
|
28
|
+
if (error)
|
|
29
|
+
throw new Error(`Orders konden niet worden gelezen: ${error.message}`);
|
|
30
|
+
const orders = Array.isArray(rows) ? rows : [];
|
|
31
|
+
const { data: typen } = await sb.from("load_carrier_types").select("code, name");
|
|
32
|
+
const naamVan = new Map((Array.isArray(typen) ? typen : []).map((t) => [String(t.code), String(t.name ?? t.code)]));
|
|
33
|
+
const perBuffer = new Map();
|
|
34
|
+
const uit = [];
|
|
35
|
+
for (const id of orderIds) {
|
|
36
|
+
const o = orders.find((x) => String(x.id) === id);
|
|
37
|
+
if (!o) {
|
|
38
|
+
uit.push({ orderId: id, orderNummer: null, ok: false, reden: "Order niet gevonden.", waarschuwingen: [], karren: [] });
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Geen bufferbesluit nemen in een voorbeeld: dat zou schrijven.
|
|
42
|
+
if (!o.buffer_id) {
|
|
43
|
+
uit.push({ orderId: id, orderNummer: o.order_number ?? null, ok: false,
|
|
44
|
+
reden: "De order heeft nog geen buffer; het voorbeeld neemt dat besluit niet (zou iets opslaan).", waarschuwingen: [], karren: [] });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const bid = String(o.buffer_id);
|
|
48
|
+
if (!perBuffer.has(bid))
|
|
49
|
+
perBuffer.set(bid, await dryRun(sb, bid));
|
|
50
|
+
const res = perBuffer.get(bid);
|
|
51
|
+
const carts = Array.isArray(res?.carts) ? res.carts : [];
|
|
52
|
+
const karren = carts
|
|
53
|
+
.filter((c) => (Array.isArray(c.items) ? c.items : []).some((it) => String(it.order_id ?? "") === id))
|
|
54
|
+
.map((c) => {
|
|
55
|
+
const lagen = lagenVanKar(c);
|
|
56
|
+
const vul = vulgraadFloriday(c.items);
|
|
57
|
+
const drager = naamVan.get(String(c.carrier_type)) ?? String(c.carrier_type ?? "Ladingdrager");
|
|
58
|
+
return {
|
|
59
|
+
karNummer: c.cart_number,
|
|
60
|
+
ladingdrager: drager,
|
|
61
|
+
lagen: Math.round(lagen * 100) / 100,
|
|
62
|
+
platen: extraPlaten(lagen) ?? 0,
|
|
63
|
+
vulgraadPct: Math.round(vul * 100),
|
|
64
|
+
teHoog: vul > 1.001,
|
|
65
|
+
karTekst: karTekstVan(lagen, drager, vul * 100),
|
|
66
|
+
regels: (Array.isArray(c.items) ? c.items : [])
|
|
67
|
+
.filter((it) => String(it.order_id ?? "") === id)
|
|
68
|
+
.map((it) => ({ orderItemId: it.order_item_id, product: it.product_name, fust: Number(it.crates) || 0, stuks: Number(it.plants) || 0 })),
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
uit.push({
|
|
72
|
+
orderId: id,
|
|
73
|
+
orderNummer: o.order_number ?? null,
|
|
74
|
+
ok: Boolean(res?.ok),
|
|
75
|
+
reden: res
|
|
76
|
+
? res.ok
|
|
77
|
+
? karren.length === 0
|
|
78
|
+
? "Geen nieuwe karren: alle fusten staan al op vastgelegde karren (geprint, gescand of gecontroleerd); die blijven zoals ze zijn."
|
|
79
|
+
: null
|
|
80
|
+
: res.blockedReason ?? "Niet ingedeeld."
|
|
81
|
+
: "Geen buffer gevonden.",
|
|
82
|
+
waarschuwingen: Array.isArray(res?.warnings) ? res.warnings : [],
|
|
83
|
+
karren,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return uit;
|
|
87
|
+
}
|