@flowselections/logistiek-engine 1.0.26 → 1.0.27

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.
@@ -0,0 +1,27 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ import type { PlannerInputItem } from "./loadCarrierPlanner";
3
+ import type { LoadCarrierTypeRow } from "./loadCarrierTypes";
4
+ import type { DimensionCarrier, DimensionItem } from "./dimensionPlanner";
5
+ export interface MissingDimension {
6
+ /** product | fust | ladingdrager */
7
+ subject: "product" | "fust" | "ladingdrager";
8
+ name: string;
9
+ field: string;
10
+ message: string;
11
+ }
12
+ export interface DimensionDataResult {
13
+ items: DimensionItem[];
14
+ missing: MissingDimension[];
15
+ }
16
+ /** Bruikbare afmetingen van een ladingdrager, of de ontbrekende velden. */
17
+ export declare function carrierDimensions(row: LoadCarrierTypeRow | null | undefined): {
18
+ carrier: DimensionCarrier | null;
19
+ missing: MissingDimension[];
20
+ };
21
+ /**
22
+ * Haalt fust- en planthoogtegegevens op bij de producten van de plannerinvoer.
23
+ * Groepsleden gebruiken hun eigen product; regels zonder product_id kunnen niet
24
+ * op afmetingen worden ingedeeld.
25
+ */
26
+ export declare function buildDimensionItems(sb: SupabaseClient, inputs: PlannerInputItem[]): Promise<DimensionDataResult>;
27
+ //# sourceMappingURL=dimensionData.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dimensionData.server.d.ts","sourceRoot":"","sources":["../../src/lib/dimensionData.server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE1E,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,cAAc,CAAC;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAOD,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAAG;IAC7E,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B,CAsCA;AAMD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,gBAAgB,EAAE,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAuG9B"}
@@ -0,0 +1,157 @@
1
+ // ============================================================================
2
+ // src/lib/dimensionData.server.ts — afmetingen ophalen en controleren
3
+ // ============================================================================
4
+ // Zet plannerinvoer om naar fysieke afmetingen. Er wordt nooit een afmeting
5
+ // verzonnen: ontbreekt er een gegeven, dan komt het als leesbare regel terug
6
+ // en wordt er niets ingedeeld.
7
+ // ============================================================================
8
+ const posNum = (v) => {
9
+ const n = Number(v);
10
+ return Number.isFinite(n) && n > 0 ? n : null;
11
+ };
12
+ /** Bruikbare afmetingen van een ladingdrager, of de ontbrekende velden. */
13
+ export function carrierDimensions(row) {
14
+ const missing = [];
15
+ if (!row) {
16
+ return {
17
+ carrier: null,
18
+ missing: [
19
+ {
20
+ subject: "ladingdrager",
21
+ name: "onbekend",
22
+ field: "ladingdrager",
23
+ message: "De ladingdrager kon niet worden gevonden in het beheerscherm Ladingdragers.",
24
+ },
25
+ ],
26
+ };
27
+ }
28
+ const name = row.name ?? row.code;
29
+ const length = posNum(row.layer_length_cm);
30
+ const width = posNum(row.layer_width_cm);
31
+ const height = posNum(row.max_height_cm);
32
+ if (length == null)
33
+ missing.push({ subject: "ladingdrager", name, field: "lengte", message: missingText("ladingdrager", name, "lengte") });
34
+ if (width == null)
35
+ missing.push({ subject: "ladingdrager", name, field: "breedte", message: missingText("ladingdrager", name, "breedte") });
36
+ if (height == null)
37
+ missing.push({ subject: "ladingdrager", name, field: "hoogte", message: missingText("ladingdrager", name, "hoogte") });
38
+ if (missing.length > 0)
39
+ return { carrier: null, missing };
40
+ return {
41
+ carrier: {
42
+ id: row.id ?? null,
43
+ code: row.code,
44
+ name,
45
+ length_cm: length,
46
+ width_cm: width,
47
+ height_cm: height,
48
+ max_weight_kg: row.max_weight_kg ?? null,
49
+ },
50
+ missing,
51
+ };
52
+ }
53
+ function missingText(subject, name, field) {
54
+ return `De karrenindeling kan niet worden berekend. De ${field} van ${subject} ${name} ontbreekt. Vul eerst de ${field} in.`;
55
+ }
56
+ /**
57
+ * Haalt fust- en planthoogtegegevens op bij de producten van de plannerinvoer.
58
+ * Groepsleden gebruiken hun eigen product; regels zonder product_id kunnen niet
59
+ * op afmetingen worden ingedeeld.
60
+ */
61
+ export async function buildDimensionItems(sb, inputs) {
62
+ const missing = [];
63
+ const items = [];
64
+ const productIds = [...new Set(inputs.map((i) => i.product_id).filter((v) => Boolean(v)))];
65
+ const productById = new Map();
66
+ if (productIds.length > 0) {
67
+ const { data } = await sb
68
+ .from("products")
69
+ .select("id, product, plant_height_cm, fust_type_id, plants_per_crate, weight")
70
+ .in("id", productIds);
71
+ for (const p of data ?? [])
72
+ productById.set(String(p.id), p);
73
+ }
74
+ const fustIds = [
75
+ ...new Set([...productById.values()].map((p) => p.fust_type_id).filter((v) => Boolean(v))),
76
+ ];
77
+ const fustById = new Map();
78
+ if (fustIds.length > 0) {
79
+ const { data } = await sb
80
+ .from("fust_types")
81
+ .select("id, name, length_mm, width_mm, height_mm")
82
+ .in("id", fustIds);
83
+ for (const f of data ?? [])
84
+ fustById.set(String(f.id), f);
85
+ }
86
+ const seen = new Set();
87
+ const addMissing = (m) => {
88
+ const key = `${m.subject}|${m.name}|${m.field}`;
89
+ if (seen.has(key))
90
+ return;
91
+ seen.add(key);
92
+ missing.push(m);
93
+ };
94
+ for (const input of inputs) {
95
+ if (input.plants <= 0)
96
+ continue;
97
+ const label = input.product_name || "onbekend product";
98
+ const product = input.product_id ? productById.get(input.product_id) : null;
99
+ if (!product) {
100
+ addMissing({
101
+ subject: "product",
102
+ name: label,
103
+ field: "productkoppeling",
104
+ message: `De karrenindeling kan niet worden berekend. De orderregel ${label} is niet aan een product ` +
105
+ `gekoppeld, dus de afmetingen zijn onbekend.`,
106
+ });
107
+ continue;
108
+ }
109
+ const plantHeight = posNum(product.plant_height_cm);
110
+ if (plantHeight == null) {
111
+ addMissing({
112
+ subject: "product",
113
+ name: product.product ?? label,
114
+ field: "planthoogte",
115
+ message: missingText("product", product.product ?? label, "planthoogte"),
116
+ });
117
+ }
118
+ const fust = product.fust_type_id ? fustById.get(String(product.fust_type_id)) : null;
119
+ if (!fust) {
120
+ addMissing({
121
+ subject: "product",
122
+ name: product.product ?? label,
123
+ field: "fusttype",
124
+ message: missingText("product", product.product ?? label, "fusttype"),
125
+ });
126
+ continue;
127
+ }
128
+ const l = posNum(fust.length_mm);
129
+ const w = posNum(fust.width_mm);
130
+ const h = posNum(fust.height_mm);
131
+ if (l == null)
132
+ addMissing({ subject: "fust", name: fust.name, field: "lengte", message: missingText("fust", fust.name, "lengte") });
133
+ if (w == null)
134
+ addMissing({ subject: "fust", name: fust.name, field: "breedte", message: missingText("fust", fust.name, "breedte") });
135
+ if (h == null)
136
+ addMissing({ subject: "fust", name: fust.name, field: "hoogte", message: missingText("fust", fust.name, "hoogte") });
137
+ if (plantHeight == null || l == null || w == null || h == null)
138
+ continue;
139
+ const ppc = Math.max(1, Math.round(input.plants_per_crate || product.plants_per_crate || 1));
140
+ const crates = Math.max(1, Math.ceil(input.plants / ppc));
141
+ items.push({
142
+ order_item_id: input.order_item_id,
143
+ order_id: input.order_id ?? null,
144
+ customer_id: input.customer_id ?? null,
145
+ product_id: input.product_id,
146
+ product_name: input.product_name,
147
+ crates,
148
+ plants_per_crate: ppc,
149
+ crate_length_cm: l / 10,
150
+ crate_width_cm: w / 10,
151
+ crate_height_cm: h / 10,
152
+ plant_height_cm: plantHeight,
153
+ weight_per_crate: input.weight_per_crate ?? null,
154
+ });
155
+ }
156
+ return { items, missing };
157
+ }
@@ -0,0 +1,70 @@
1
+ export declare const DIMENSION_PLANNER_VERSION = 4;
2
+ export interface DimensionItem {
3
+ order_item_id: string;
4
+ order_id: string | null;
5
+ customer_id: string | null;
6
+ product_id: string | null;
7
+ product_name: string;
8
+ /** Aantal fusten van dit product. */
9
+ crates: number;
10
+ plants_per_crate: number;
11
+ /** Afmetingen van één fust in cm. */
12
+ crate_length_cm: number;
13
+ crate_width_cm: number;
14
+ crate_height_cm: number;
15
+ /** Hoogte van de plant/het product boven het fust, in cm. */
16
+ plant_height_cm: number;
17
+ weight_per_crate?: number | null;
18
+ }
19
+ export interface DimensionCarrier {
20
+ id?: string | null;
21
+ code: string;
22
+ name: string;
23
+ /** Bruikbare afmetingen van de ladingdrager in cm. */
24
+ length_cm: number;
25
+ width_cm: number;
26
+ height_cm: number;
27
+ /** Optionele bovengrens uit de werkwijze. */
28
+ max_layers?: number | null;
29
+ max_orders?: number | null;
30
+ max_customers?: number | null;
31
+ max_weight_kg?: number | null;
32
+ }
33
+ export interface DimensionPlacement {
34
+ order_item_id: string;
35
+ order_id: string | null;
36
+ product_id: string | null;
37
+ product_name: string;
38
+ crates: number;
39
+ plants: number;
40
+ plants_per_crate: number;
41
+ weight_kg: number | null;
42
+ /** Rotatie waarmee de fusten op deze laag staan. */
43
+ rotated: boolean;
44
+ }
45
+ export interface DimensionLayer {
46
+ layer_index: number;
47
+ height_cm: number;
48
+ /** Benutting van het laagoppervlak in procenten. */
49
+ area_used_pct: number;
50
+ placements: DimensionPlacement[];
51
+ }
52
+ export interface DimensionCart {
53
+ cart_number: number;
54
+ carrier_code: string;
55
+ carrier_id: string | null;
56
+ height_used_cm: number;
57
+ height_available_cm: number;
58
+ occupancy_pct: number;
59
+ is_complete: boolean;
60
+ weight_kg: number | null;
61
+ layers: DimensionLayer[];
62
+ }
63
+ export interface DimensionPlanResult {
64
+ carts: DimensionCart[];
65
+ warnings: string[];
66
+ /** Gevuld als er niets ingedeeld kan worden; dan is carts leeg. */
67
+ error?: string;
68
+ }
69
+ export declare function planByDimensions(items: DimensionItem[], carrier: DimensionCarrier): DimensionPlanResult;
70
+ //# sourceMappingURL=dimensionPlanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dimensionPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/dimensionPlanner.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,kBAAkB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA6ED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EAAE,EACtB,OAAO,EAAE,gBAAgB,GACxB,mBAAmB,CAwJrB"}
@@ -0,0 +1,217 @@
1
+ // ============================================================================
2
+ // src/lib/dimensionPlanner.ts — karrenindeling op basis van fysieke afmetingen
3
+ // ============================================================================
4
+ // Pure functie: geen database, geen netwerk, deterministisch.
5
+ //
6
+ // Werkwijze:
7
+ // 1. Per fust wordt de laaghoogte bepaald: fusthoogte + planthoogte.
8
+ // 2. Een laag wordt 2D ingedeeld op de bruikbare lengte x breedte van de
9
+ // ladingdrager. Elk fust wordt ook 90 graden gedraaid geprobeerd.
10
+ // 3. Lagen worden gestapeld tot de bruikbare hoogte van de drager op is.
11
+ // 4. Is de drager vol, dan volgt een nieuwe drager.
12
+ //
13
+ // Er wordt nooit een afmeting verzonnen: ontbrekende gegevens worden vooraf
14
+ // gecontroleerd door de aanroeper (zie dimensionData / collectMissingDimensions).
15
+ // ============================================================================
16
+ export const DIMENSION_PLANNER_VERSION = 4;
17
+ class LayerSpace {
18
+ constructor(length, width) {
19
+ this.length = length;
20
+ this.width = width;
21
+ this.shelves = [];
22
+ this.totalDepth = 0;
23
+ this.usedArea = 0;
24
+ }
25
+ /** Probeert één fust te plaatsen. Geeft de gebruikte rotatie terug, of null. */
26
+ place(l, w) {
27
+ const options = [
28
+ { a: l, b: w, rotated: false },
29
+ { a: w, b: l, rotated: true },
30
+ ];
31
+ for (const o of options) {
32
+ if (o.a > this.length || o.b > this.width)
33
+ continue;
34
+ for (let i = 0; i < this.shelves.length; i++) {
35
+ const shelf = this.shelves[i];
36
+ const last = i === this.shelves.length - 1;
37
+ const fitsLength = shelf.usedLength + o.a <= this.length + 1e-9;
38
+ if (!fitsLength)
39
+ continue;
40
+ if (o.b <= shelf.depth + 1e-9) {
41
+ shelf.usedLength += o.a;
42
+ this.usedArea += o.a * o.b;
43
+ return { rotated: o.rotated };
44
+ }
45
+ if (last && this.totalDepth - shelf.depth + o.b <= this.width + 1e-9) {
46
+ this.totalDepth = this.totalDepth - shelf.depth + o.b;
47
+ shelf.depth = o.b;
48
+ shelf.usedLength += o.a;
49
+ this.usedArea += o.a * o.b;
50
+ return { rotated: o.rotated };
51
+ }
52
+ }
53
+ if (this.totalDepth + o.b <= this.width + 1e-9) {
54
+ this.shelves.push({ depth: o.b, usedLength: o.a });
55
+ this.totalDepth += o.b;
56
+ this.usedArea += o.a * o.b;
57
+ return { rotated: o.rotated };
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+ get areaPct() {
63
+ const total = this.length * this.width;
64
+ return total > 0 ? Number(((100 * this.usedArea) / total).toFixed(1)) : 0;
65
+ }
66
+ get isEmpty() {
67
+ return this.shelves.length === 0;
68
+ }
69
+ }
70
+ export function planByDimensions(items, carrier) {
71
+ const warnings = [];
72
+ if (!(carrier.length_cm > 0) || !(carrier.width_cm > 0) || !(carrier.height_cm > 0)) {
73
+ return {
74
+ carts: [],
75
+ warnings,
76
+ error: `De afmetingen van ladingdrager ${carrier.name} zijn niet volledig ingevuld (lengte, breedte en hoogte).`,
77
+ };
78
+ }
79
+ const batches = items
80
+ .filter((i) => i.crates > 0)
81
+ .map((item) => ({
82
+ item,
83
+ left: Math.max(0, Math.round(item.crates)),
84
+ height: item.crate_height_cm + item.plant_height_cm,
85
+ }));
86
+ for (const b of batches) {
87
+ const fitsFlat = b.item.crate_length_cm <= carrier.length_cm && b.item.crate_width_cm <= carrier.width_cm;
88
+ const fitsTurned = b.item.crate_width_cm <= carrier.length_cm && b.item.crate_length_cm <= carrier.width_cm;
89
+ if (!fitsFlat && !fitsTurned) {
90
+ return {
91
+ carts: [],
92
+ warnings,
93
+ error: `Het fust van ${b.item.product_name} (${b.item.crate_length_cm} x ${b.item.crate_width_cm} cm) ` +
94
+ `past niet op ladingdrager ${carrier.name} (${carrier.length_cm} x ${carrier.width_cm} cm).`,
95
+ };
96
+ }
97
+ if (b.height > carrier.height_cm) {
98
+ return {
99
+ carts: [],
100
+ warnings,
101
+ error: `Eén laag van ${b.item.product_name} is ${round1(b.height)} cm hoog en past niet in de ` +
102
+ `bruikbare hoogte van ladingdrager ${carrier.name} (${carrier.height_cm} cm).`,
103
+ };
104
+ }
105
+ }
106
+ const carts = [];
107
+ let guard = 0;
108
+ while (batches.some((b) => b.left > 0)) {
109
+ if (++guard > 5000) {
110
+ return { carts: [], warnings, error: "De indeling op afmetingen kwam niet tot een einde." };
111
+ }
112
+ const cartOrders = new Set();
113
+ const cartCustomers = new Set();
114
+ const layers = [];
115
+ let heightLeft = carrier.height_cm;
116
+ while (heightLeft > 0) {
117
+ if (carrier.max_layers != null && layers.length >= carrier.max_layers)
118
+ break;
119
+ // Hoogste fusten eerst; bij gelijke hoogte het grootste grondvlak eerst.
120
+ const pool = batches
121
+ .filter((b) => b.left > 0)
122
+ .filter((b) => allowedOnCart(b, cartOrders, cartCustomers, carrier))
123
+ .filter((b) => b.height <= heightLeft + 1e-9)
124
+ .sort((a, b) => b.height - a.height ||
125
+ b.item.crate_length_cm * b.item.crate_width_cm - a.item.crate_length_cm * a.item.crate_width_cm);
126
+ if (pool.length === 0)
127
+ break;
128
+ const space = new LayerSpace(carrier.length_cm, carrier.width_cm);
129
+ const perItem = new Map();
130
+ let layerHeight = 0;
131
+ for (const b of pool) {
132
+ while (b.left > 0) {
133
+ // Een laag mag niet hoger worden dan wat er nog op de drager past.
134
+ const newHeight = Math.max(layerHeight, b.height);
135
+ if (newHeight > heightLeft + 1e-9)
136
+ break;
137
+ const placed = space.place(b.item.crate_length_cm, b.item.crate_width_cm);
138
+ if (!placed)
139
+ break;
140
+ layerHeight = newHeight;
141
+ b.left -= 1;
142
+ const acc = perItem.get(b) ?? { crates: 0, rotated: placed.rotated };
143
+ acc.crates += 1;
144
+ perItem.set(b, acc);
145
+ }
146
+ }
147
+ if (space.isEmpty || perItem.size === 0)
148
+ break;
149
+ const placements = [];
150
+ for (const [batch, acc] of perItem) {
151
+ const item = batch.item;
152
+ if (item.order_id)
153
+ cartOrders.add(item.order_id);
154
+ if (item.customer_id)
155
+ cartCustomers.add(item.customer_id);
156
+ placements.push({
157
+ order_item_id: item.order_item_id,
158
+ order_id: item.order_id,
159
+ product_id: item.product_id,
160
+ product_name: item.product_name,
161
+ crates: acc.crates,
162
+ plants: acc.crates * Math.max(1, item.plants_per_crate),
163
+ plants_per_crate: Math.max(1, item.plants_per_crate),
164
+ weight_kg: item.weight_per_crate != null ? Number((item.weight_per_crate * acc.crates).toFixed(2)) : null,
165
+ rotated: acc.rotated,
166
+ });
167
+ }
168
+ layers.push({
169
+ layer_index: layers.length + 1,
170
+ height_cm: round1(layerHeight),
171
+ area_used_pct: space.areaPct,
172
+ placements,
173
+ });
174
+ heightLeft = round1(heightLeft - layerHeight);
175
+ }
176
+ if (layers.length === 0) {
177
+ return {
178
+ carts: [],
179
+ warnings,
180
+ error: `Er kon geen enkele laag worden gevuld op ladingdrager ${carrier.name}. ` +
181
+ `Controleer de afmetingen van de fusten en van de ladingdrager.`,
182
+ };
183
+ }
184
+ const usedHeight = round1(layers.reduce((s, l) => s + l.height_cm, 0));
185
+ const weights = layers.flatMap((l) => l.placements.map((p) => p.weight_kg));
186
+ carts.push({
187
+ cart_number: carts.length + 1,
188
+ carrier_code: carrier.code,
189
+ carrier_id: carrier.id ?? null,
190
+ height_used_cm: usedHeight,
191
+ height_available_cm: carrier.height_cm,
192
+ occupancy_pct: Number(((100 * usedHeight) / carrier.height_cm).toFixed(1)),
193
+ is_complete: false,
194
+ weight_kg: weights.some((w) => w != null)
195
+ ? Number(weights.reduce((s, w) => s + (w ?? 0), 0).toFixed(2))
196
+ : null,
197
+ layers,
198
+ });
199
+ }
200
+ // Alle dragers behalve de laatste zijn vol geladen.
201
+ carts.forEach((c, idx) => {
202
+ c.is_complete = idx < carts.length - 1 || c.occupancy_pct >= 99.9;
203
+ });
204
+ return { carts, warnings };
205
+ }
206
+ function allowedOnCart(batch, orders, customers, carrier) {
207
+ const oid = batch.item.order_id;
208
+ const cid = batch.item.customer_id;
209
+ if (carrier.max_orders != null && oid && !orders.has(oid) && orders.size >= carrier.max_orders)
210
+ return false;
211
+ if (carrier.max_customers != null && cid && !customers.has(cid) && customers.size >= carrier.max_customers)
212
+ return false;
213
+ return true;
214
+ }
215
+ function round1(n) {
216
+ return Number(n.toFixed(1));
217
+ }
@@ -56,6 +56,9 @@ export interface PlannedLoadUnitItem {
56
56
  layers_per_cart: number;
57
57
  layer_fraction: number;
58
58
  layer_share_pct: number;
59
+ /** Alleen bij indelen op afmetingen: op welke laag deze fusten staan. */
60
+ layer_index?: number | null;
61
+ crates_in_layer?: number | null;
59
62
  }
60
63
  export interface PlannedLoadUnit {
61
64
  cart_number: number;
@@ -1 +1 @@
1
- {"version":3,"file":"loadCarrierPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loadCarrierPlanner.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanner.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { type CarrierProfile, type PlannedLoadUnit, type PlannerInputItem } from "./loadCarrierPlanner";
3
3
  import { type LoadCarrierTypeRow } from "./loadCarrierTypes";
4
+ import { type DimensionCart } from "./dimensionPlanner";
4
5
  export declare function buildBufferKey(order: {
5
6
  id: string;
6
7
  customer_id?: string | null;
@@ -40,6 +41,8 @@ export interface BeladingRules {
40
41
  maxLayers: number | null;
41
42
  maxBoxes: number | null;
42
43
  optimalFill: boolean;
44
+ /** Globale methode voor de karrenindeling. */
45
+ layoutMethod: "belading" | "afmetingen";
43
46
  }
44
47
  /** Leest de actieve werkwijze en vertaalt "2. Beladingindeling" naar plannergrenzen. */
45
48
  export declare function loadBeladingRules(sb: SupabaseClient): Promise<BeladingRules | null>;
@@ -51,6 +54,7 @@ export declare function applyRulesToProfile(profile: CarrierProfile, rules: Bela
51
54
  * Geen optimalisatie, geen mengregels, geen laagherverdeling — alleen vullen.
52
55
  */
53
56
  export declare function planByFloridayPacking(inputs: PlannerInputItem[], profile: CarrierProfile, packing: Belading): PlannedLoadUnit[];
57
+ export declare function dimensionCartsToPlannedUnits(carts: DimensionCart[]): PlannedLoadUnit[];
54
58
  export interface ReplanResult {
55
59
  ok: boolean;
56
60
  bufferId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"loadCarrierPlanning.server.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanning.server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loadCarrierPlanning.server.d.ts","sourceRoot":"","sources":["../../src/lib/loadCarrierPlanning.server.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@
7
7
  // ============================================================================
8
8
  import { planLoadUnits, LOAD_CARRIER_PLANNER_VERSION, } from "./loadCarrierPlanner";
9
9
  import { fallbackCarrierProfile } from "./loadCarrierTypes";
10
+ import { planByDimensions, DIMENSION_PLANNER_VERSION } from "./dimensionPlanner";
11
+ import { buildDimensionItems, carrierDimensions } from "./dimensionData.server";
10
12
  // ---------------------------------------------------------------------------
11
13
  // Buffer
12
14
  // ---------------------------------------------------------------------------
@@ -328,6 +330,7 @@ export async function loadBeladingRules(sb) {
328
330
  maxLayers: k.fill_layers_as_much_as_fits ? null : numOrNull(k.max_layers),
329
331
  maxBoxes: k.fill_boxes_as_much_as_fits ? null : numOrNull(k.max_boxes_per_pallet),
330
332
  optimalFill: k.optimal_fill !== false,
333
+ layoutMethod: k.cart_layout_method === "afmetingen" ? "afmetingen" : "belading",
331
334
  };
332
335
  }
333
336
  /** Past de grenzen uit de werkwijze toe op het capaciteitsprofiel van een ladingdrager. */
@@ -414,6 +417,50 @@ export function planByFloridayPacking(inputs, profile, packing) {
414
417
  return carts;
415
418
  }
416
419
  // ---------------------------------------------------------------------------
420
+ // Indeling op afmetingen omzetten naar het bestaande opslagmodel
421
+ // ---------------------------------------------------------------------------
422
+ export function dimensionCartsToPlannedUnits(carts) {
423
+ return carts.map((cart) => {
424
+ const layerCount = cart.layers.length || 1;
425
+ const items = [];
426
+ for (const layer of cart.layers) {
427
+ const cratesInLayer = layer.placements.reduce((s, p) => s + p.crates, 0) || 1;
428
+ for (const p of layer.placements) {
429
+ const fraction = p.crates / cratesInLayer;
430
+ items.push({
431
+ order_item_id: p.order_item_id,
432
+ order_id: p.order_id,
433
+ product_id: p.product_id,
434
+ product_name: p.product_name,
435
+ crates: p.crates,
436
+ plants: p.plants,
437
+ boxes: p.crates,
438
+ weight_kg: p.weight_kg,
439
+ plants_per_crate: p.plants_per_crate,
440
+ crates_per_layer: cratesInLayer,
441
+ layers_per_cart: layerCount,
442
+ layer_fraction: Number(fraction.toFixed(3)),
443
+ layer_share_pct: Number(((100 * fraction) / layerCount).toFixed(2)),
444
+ layer_index: layer.layer_index,
445
+ crates_in_layer: p.crates,
446
+ });
447
+ }
448
+ }
449
+ return {
450
+ cart_number: cart.cart_number,
451
+ carrier_type: cart.carrier_code,
452
+ carrier_type_id: cart.carrier_id,
453
+ source: "auto",
454
+ is_complete: cart.is_complete,
455
+ occupancy_pct: cart.occupancy_pct,
456
+ total_layers_used: layerCount,
457
+ max_layers: layerCount,
458
+ weight_kg: cart.weight_kg,
459
+ items,
460
+ };
461
+ });
462
+ }
463
+ // ---------------------------------------------------------------------------
417
464
  // Herplannen van een buffer
418
465
  // ---------------------------------------------------------------------------
419
466
  /** Maximaal aantal ladingdragers dat één orderbuffer mag opleveren. */
@@ -487,7 +534,8 @@ export async function replanBufferInternal(sb, bufferId, options = {}) {
487
534
  const guardProfile = profileFor(profiles, options.carrierType ?? defaultProfile.code);
488
535
  const needsBelading = guardProfile.capacity_model !== "single" && guardProfile.capacity_model !== "none";
489
536
  const unknownItems = inputs.filter((i) => sources.get(i.order_item_id) === "geen" && i.plants > 0);
490
- if (needsBelading && unknownItems.length > 0 && !options.dryRun) {
537
+ const useDimensions = rules?.layoutMethod === "afmetingen";
538
+ if (!useDimensions && needsBelading && unknownItems.length > 0 && !options.dryRun) {
491
539
  const reason = `Belading onbekend voor ${unknownItems.length} orderregel(s): geen Floriday-verpakking, ` +
492
540
  `geen waarden op de orderregel en geen productinstelling. Er is niets ingedeeld.`;
493
541
  console.error(`[logistiek-engine] buffer ${bufferId} geblokkeerd: ${reason}`);
@@ -528,7 +576,66 @@ export async function replanBufferInternal(sb, bufferId, options = {}) {
528
576
  const soloPacking = solo ? beladingFromFloridayPacking(solo.custom_fields?.floriday_packing) : null;
529
577
  const takeoverProfile = profileFor(profiles, options.carrierType ?? defaultProfile.code);
530
578
  const takeoverAllowed = takeoverProfile.capacity_model === "layered" || takeoverProfile.capacity_model === "stacked";
531
- if (solo && soloPacking && takeoverAllowed) {
579
+ if (useDimensions) {
580
+ // Globale methode: indelen op basis van fysieke afmetingen.
581
+ const carrierRow = profiles.find((p) => p.code === (options.carrierType ?? defaultProfile.code)) ?? null;
582
+ const { carrier, missing: carrierMissing } = carrierDimensions(carrierRow);
583
+ const { items: dimItems, missing: itemMissing } = await buildDimensionItems(sb, inputs);
584
+ const missing = [...carrierMissing, ...itemMissing];
585
+ let planError = null;
586
+ if (missing.length === 0 && carrier) {
587
+ const result = planByDimensions(dimItems, carrier);
588
+ if (result.error)
589
+ planError = result.error;
590
+ else {
591
+ plannedCarts = dimensionCartsToPlannedUnits(result.carts);
592
+ warnings.push(...result.warnings);
593
+ }
594
+ }
595
+ if (missing.length > 0 || planError) {
596
+ const reason = planError ?? `Afmetingen onbekend: ${missing.map((m) => m.message).join(" ")}`;
597
+ if (options.dryRun) {
598
+ return {
599
+ ok: false,
600
+ bufferId,
601
+ orderIds,
602
+ cartsCreated: 0,
603
+ replacedManualCount: 0,
604
+ usedFloridayPacking: false,
605
+ warnings: [...warnings, reason],
606
+ skipped: "blocked",
607
+ blockedReason: reason,
608
+ beladingSources,
609
+ };
610
+ }
611
+ console.error(`[logistiek-engine] buffer ${bufferId} geblokkeerd (afmetingen): ${reason}`);
612
+ const { error: blockError } = await sb.rpc("logistics_plan_block", {
613
+ p_order_ids: orderIds,
614
+ p_reason: reason,
615
+ p_details: {
616
+ bufferId,
617
+ path: "afmetingen",
618
+ carrier: carrierRow?.code ?? null,
619
+ missing: missing.slice(0, 20),
620
+ },
621
+ });
622
+ if (blockError)
623
+ warnings.push(`Blokkade kon niet worden vastgelegd: ${blockError.message}`);
624
+ return {
625
+ ok: false,
626
+ bufferId,
627
+ orderIds,
628
+ cartsCreated: 0,
629
+ replacedManualCount: 0,
630
+ usedFloridayPacking: false,
631
+ warnings: [...warnings, reason],
632
+ skipped: "blocked",
633
+ blockedReason: reason,
634
+ beladingSources,
635
+ };
636
+ }
637
+ }
638
+ else if (solo && soloPacking && takeoverAllowed) {
532
639
  usedFloridayPacking = true;
533
640
  plannedCarts = planByFloridayPacking(inputs, takeoverProfile, soloPacking);
534
641
  console.log(`[logistiek-engine] buffer ${bufferId}: overname Floriday-verpakking ` +
@@ -639,7 +746,8 @@ export async function replanBufferInternal(sb, bufferId, options = {}) {
639
746
  carrier_type_id: cart.carrier_type_id,
640
747
  max_layers: cart.max_layers,
641
748
  weight_kg: cart.weight_kg,
642
- algorithm_version: LOAD_CARRIER_PLANNER_VERSION,
749
+ algorithm_version: useDimensions ? DIMENSION_PLANNER_VERSION : LOAD_CARRIER_PLANNER_VERSION,
750
+ layout_method: useDimensions ? "afmetingen" : "belading",
643
751
  };
644
752
  });
645
753
  const { data: insertedCarts, error } = await sb
@@ -674,6 +782,8 @@ export async function replanBufferInternal(sb, bufferId, options = {}) {
674
782
  layers_per_cart: i.layers_per_cart,
675
783
  layer_fraction: i.layer_fraction,
676
784
  layer_share_pct: i.layer_share_pct,
785
+ layer_index: i.layer_index ?? null,
786
+ crates_in_layer: i.crates_in_layer ?? null,
677
787
  });
678
788
  }
679
789
  }
@@ -1 +1 @@
1
- {"version":3,"file":"modulePrompts.d.ts","sourceRoot":"","sources":["../../src/lib/modulePrompts.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;CAGvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AA47DD,eAAO,MAAM,cAAc,EAAE,YAAY,EAUL,CAAC;AAErC,gEAAgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,CAeR;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,MAAM,CAiB9C;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,eAAe,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAIR"}
1
+ {"version":3,"file":"modulePrompts.d.ts","sourceRoot":"","sources":["../../src/lib/modulePrompts.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;CAGvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AA49DD,eAAO,MAAM,cAAc,EAAE,YAAY,EAUL,CAAC;AAErC,gEAAgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,CAeR;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,IAAI,MAAM,CAiB9C;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,eAAe,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAIR"}
@@ -466,6 +466,36 @@ CONTROLELIJST
466
466
  [ ] Verkoop, pick agenda, lever agenda, controle en picking station tonen hetzelfde aantal.
467
467
  [ ] Geen eigen kartelling meer in de verkoopcode.`,
468
468
  },
469
+ {
470
+ number: 9,
471
+ title: "Stamgegevens voor indelen op afmetingen",
472
+ date: "2026-09-03",
473
+ summary: "Producten krijgen een fusttype en een planthoogte, zodat de Engine op fysieke afmetingen kan indelen.",
474
+ body: `AANVULLING op prompt 1 t/m 8 (die blijven geldig).
475
+
476
+ WAT ER VERANDERT
477
+ De Logistiek Engine kent één globale instelling "Methode voor karrenindeling":
478
+ "belading" (huidig gedrag) of "afmetingen". Bij "afmetingen" rekent de Engine
479
+ met echte maten en verzint hij niets.
480
+
481
+ WAT JIJ BOUWT
482
+ 1. In het productbeheer twee velden tonen en opslaan op public.products:
483
+ - fust_type_id -> keuzelijst uit public.fust_types (naam tonen)
484
+ - plant_height_cm -> hoogte van de plant boven het fust, in centimeters
485
+ Beide mogen leeg blijven; ze zijn alleen nodig bij methode "afmetingen".
486
+ 2. Toon per product een discrete markering "afmetingen onvolledig" wanneer
487
+ fust_type_id of plant_height_cm leeg is. Geen standaardwaarde invullen.
488
+ 3. Verzin nooit maten en kopieer ze niet van een ander product.
489
+
490
+ WAT JE NIET DOET
491
+ - Geen keuze per order voor de indelingsmethode: die staat alleen in de Engine.
492
+ - Geen eigen karrenberekening; de Engine blijft de enige bron.
493
+
494
+ CONTROLELIJST
495
+ [ ] Fusttype en planthoogte zijn per product in te vullen en op te slaan.
496
+ [ ] Producten met ontbrekende maten zijn herkenbaar in de lijst.
497
+ [ ] Geen standaardwaardes of gekopieerde maten.`,
498
+ },
469
499
  ],
470
500
  },
471
501
  afhandeling: {
@@ -1 +1 @@
1
- {"version":3,"file":"ruleEngineSchema.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineSchema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ruleEngineSchema.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineSchema.ts"],"names":[],"mappings":"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"}
@@ -174,6 +174,17 @@ export const RULE_STEPS = [
174
174
  id: "werkwijze",
175
175
  label: "Werkwijze",
176
176
  fields: [
177
+ {
178
+ key: "cart_layout_method",
179
+ label: "Methode voor karrenindeling",
180
+ type: "select",
181
+ default: "belading",
182
+ description: "Geldt voor alle orders. Bij afmetingen worden fust- en planthoogtes gebruikt; ontbreekt een maat, dan wordt er niets ingedeeld.",
183
+ options: [
184
+ { value: "belading", label: "Indelen op basis van belading" },
185
+ { value: "afmetingen", label: "Indelen op basis van afmetingen" },
186
+ ],
187
+ },
177
188
  {
178
189
  key: "mode",
179
190
  label: "Hoe ontstaat een belading?",
@@ -1 +1 @@
1
- {"version":3,"file":"ruleEngineWizard.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineWizard.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,SAAS,EAEf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,2EAA2E;IAC3E,cAAc,EAAE,OAAO,CAAC;CACzB;AAeD,eAAO,MAAM,YAAY,EAAE,UAAU,EAsDpC,CAAC;AA+BF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEzD;AA8DD,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAE9D;AAyCD,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAStF"}
1
+ {"version":3,"file":"ruleEngineWizard.d.ts","sourceRoot":"","sources":["../../src/lib/ruleEngineWizard.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,SAAS,EAEf,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,2EAA2E;IAC3E,cAAc,EAAE,OAAO,CAAC;CACzB;AAeD,eAAO,MAAM,YAAY,EAAE,UAAU,EAsDpC,CAAC;AA+BF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEzD;AAgED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAE9D;AAyCD,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAStF"}
@@ -108,6 +108,7 @@ export function isAdvancedField(field) {
108
108
  const EXTRA_HELP = {
109
109
  load_carrier_types: "Zet alleen de ladingdragers aan die je in de praktijk gebruikt.",
110
110
  mix_carrier_types: "Aan: één order mag over verschillende soorten dragers verdeeld worden.",
111
+ cart_layout_method: "Belading: het systeem rekent met het aantal planten per fust, fusten per laag en lagen per kar. Afmetingen: het systeem legt de fusten fysiek in op lengte, breedte en hoogte en draait ze waar nodig. Deze keuze geldt voor alle orders.",
111
112
  mode: "Automatisch: het systeem maakt de indeling. Scannen: een medewerker bepaalt het zelf.",
112
113
  multi_order: "Aan: orders van meerdere bestellingen mogen op dezelfde drager staan.",
113
114
  max_orders: "Meer orders op één drager betekent minder karren, maar wel meer sorteerwerk.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/logistiek-engine",
3
- "version": "1.0.26",
3
+ "version": "1.0.27",
4
4
  "flowselections": {
5
5
  "moduleId": "logistiek-engine",
6
6
  "pages": [