@flowselections/logistiek-engine 1.0.203 → 1.0.209
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 +1333 -0
- package/dist-lib/components/BeladingIndelingCard.d.ts.map +1 -1
- package/dist-lib/components/BeladingIndelingCard.js +14 -2
- package/dist-lib/components/LadingdragersPage.d.ts.map +1 -1
- package/dist-lib/components/LadingdragersPage.js +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +498 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.server.js +3 -2
- package/dist-lib/lib/hoofdverpakking.d.ts +7 -0
- package/dist-lib/lib/hoofdverpakking.d.ts.map +1 -0
- package/dist-lib/lib/hoofdverpakking.js +19 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts +80 -1
- package/dist-lib/lib/loadCarrierPlanner.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanner.js +353 -280
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +39 -5
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/dist-lib/lib/quarantaine.d.ts +9 -0
- package/dist-lib/lib/quarantaine.d.ts.map +1 -0
- package/dist-lib/lib/quarantaine.js +13 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BeladingIndelingCard.d.ts","sourceRoot":"","sources":["../../src/components/BeladingIndelingCard.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"BeladingIndelingCard.d.ts","sourceRoot":"","sources":["../../src/components/BeladingIndelingCard.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,oBAAoB,gCAwKnC"}
|
|
@@ -12,7 +12,7 @@ import { Boxes, Search } from "lucide-react";
|
|
|
12
12
|
import { previewLoadCarrierPlan, replanOrderLoadCarriers } from "../lib/loadCarrierPlanning.functions.js";
|
|
13
13
|
import { ladingdragerNaam } from "../lib/loadCarrierTypes.js";
|
|
14
14
|
import { useFloricodeLadingdragers } from "../hooks/useFloricodeLadingdragers.js";
|
|
15
|
-
import {
|
|
15
|
+
import { karCapaciteit, karVulgraad } from "../lib/loadCarrierPlanner.js";
|
|
16
16
|
import { karBlokkade, ladingdragerPlatenTekst } from "../lib/extraPlaten.js";
|
|
17
17
|
const db = () => supabase;
|
|
18
18
|
export function BeladingIndelingCard() {
|
|
@@ -79,5 +79,17 @@ export function BeladingIndelingCard() {
|
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
81
|
const safeCarts = Array.isArray(carts) ? carts : [];
|
|
82
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Boxes, { className: "h-5 w-5 text-primary" }), "Beladingindeling"] }), _jsx(CardDescription, { children: "De Engine deelt de orderregels van de hele buffer in over ladingdragers. Bekijk eerst het resultaat en leg het daarna vast." }), _jsxs("div", { className: "flex flex-wrap items-end gap-2 pt-2", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "indeling-order", children: "Ordernummer" }), _jsx(Input, { id: "indeling-order", value: orderNummer, onChange: (e) => setOrderNummer(e.target.value), placeholder: "SO-12345", className: "w-56" })] }), _jsxs(Button, { onClick: () => void bereken(), disabled: bezig || !orderNummer.trim(), children: [_jsx(Search, { className: "mr-2 h-4 w-4" }), "Berekenen"] }), _jsx(Button, { variant: "outline", onClick: () => void vastleggen(), disabled: bezig || !orderId, children: "Vastleggen" })] })] }), _jsxs(CardContent, { className: "space-y-4", children: [warnings.length > 0 && (_jsx("ul", { className: "space-y-1 rounded-lg border border-dashed p-3 text-sm text-muted-foreground", children: warnings.map((w, i) => (_jsx("li", { children: w }, i))) })), safeCarts.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen indeling berekend." })) : (safeCarts.map((cart) =>
|
|
82
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Boxes, { className: "h-5 w-5 text-primary" }), "Beladingindeling"] }), _jsx(CardDescription, { children: "De Engine deelt de orderregels van de hele buffer in over ladingdragers. Bekijk eerst het resultaat en leg het daarna vast." }), _jsxs("div", { className: "flex flex-wrap items-end gap-2 pt-2", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "indeling-order", children: "Ordernummer" }), _jsx(Input, { id: "indeling-order", value: orderNummer, onChange: (e) => setOrderNummer(e.target.value), placeholder: "SO-12345", className: "w-56" })] }), _jsxs(Button, { onClick: () => void bereken(), disabled: bezig || !orderNummer.trim(), children: [_jsx(Search, { className: "mr-2 h-4 w-4" }), "Berekenen"] }), _jsx(Button, { variant: "outline", onClick: () => void vastleggen(), disabled: bezig || !orderId, children: "Vastleggen" })] })] }), _jsxs(CardContent, { className: "space-y-4", children: [warnings.length > 0 && (_jsx("ul", { className: "space-y-1 rounded-lg border border-dashed p-3 text-sm text-muted-foreground", children: warnings.map((w, i) => (_jsx("li", { children: w }, i))) })), safeCarts.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen indeling berekend." })) : (safeCarts.map((cart) => {
|
|
83
|
+
// 1.0.204: capaciteit = hoogste lagen per kar van de producten op de kar; lagen = Σ fust ÷ fusten per laag.
|
|
84
|
+
const regels = Array.isArray(cart.items) ? cart.items : [];
|
|
85
|
+
const alleCpl = regels.length > 0 && regels.every((i) => Number(i.crates_per_layer) > 0);
|
|
86
|
+
const lagen = alleCpl
|
|
87
|
+
? Math.round(regels.reduce((s, i) => s + Number(i.crates) / Number(i.crates_per_layer), 0) * 100) / 100
|
|
88
|
+
: cart.total_layers_used;
|
|
89
|
+
const cap = karCapaciteit(regels.map((i) => i.layers_per_cart), cart.max_layers);
|
|
90
|
+
const vulgraad = karVulgraad(Number(lagen), cap.capaciteit);
|
|
91
|
+
const blok = karBlokkade(cart.cart_number, lagen, cap.capaciteit).blokkade;
|
|
92
|
+
const naam = ladingdragerNaam(cart.carrier_type, floricodeNamen);
|
|
93
|
+
return (_jsxs("div", { className: "space-y-2 rounded-lg border p-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("span", { className: "font-medium", children: ["Ladingdrager ", cart.cart_number] }), _jsx(Badge, { variant: "secondary", children: naam }), vulgraad != null && (_jsxs(Badge, { variant: cart.is_complete ? "default" : "outline", title: `Vulgraad: ${String(lagen).replace(".", ",")} lagen van ${cap.capaciteit} (${cap.bron === "product" ? "hoogste lagen per kar van de producten op deze kar" : "standaard van de ladingdrager"})`, children: [vulgraad, "% vol"] })), _jsxs("span", { className: "text-xs text-muted-foreground", children: [ladingdragerPlatenTekst(naam, lagen), cap.capaciteit != null ? ` · ${String(lagen).replace(".", ",")} van ${cap.capaciteit} lagen` : "", cart.weight_kg ? ` · ${cart.weight_kg} kg` : ""] })] }), blok && (_jsx("p", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-2 text-sm text-destructive", children: blok.tekst })), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Partij" }), _jsx(TableHead, { className: "text-right", children: "Fusten" }), _jsx(TableHead, { className: "text-right", children: "Planten" }), _jsx(TableHead, { className: "text-right", children: "Aandeel" })] }) }), _jsx(TableBody, { children: (Array.isArray(cart.items) ? cart.items : []).map((item, idx) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: item.product_name }), _jsx(TableCell, { className: "text-right", children: item.crates }), _jsx(TableCell, { className: "text-right", children: item.plants }), _jsxs(TableCell, { className: "text-right", children: [Math.round(item.layer_share_pct * 10) / 10, "%"] })] }, `${item.order_item_id}-${idx}`))) })] })] }, cart.cart_number));
|
|
94
|
+
}))] })] }));
|
|
83
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LadingdragersPage.d.ts","sourceRoot":"","sources":["../../src/components/LadingdragersPage.tsx"],"names":[],"mappings":"AAkIA,wBAAgB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"LadingdragersPage.d.ts","sourceRoot":"","sources":["../../src/components/LadingdragersPage.tsx"],"names":[],"mappings":"AAkIA,wBAAgB,iBAAiB,gCA4UhC"}
|
|
@@ -102,5 +102,5 @@ export function LadingdragersPage() {
|
|
|
102
102
|
};
|
|
103
103
|
const set = (key, value) => setForm((prev) => ({ ...prev, [key]: value }));
|
|
104
104
|
const toonLagen = form.capacity_model === "layered" || form.capacity_model === "stacked";
|
|
105
|
-
return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs("h1", { className: "flex items-center gap-2 text-2xl font-semibold tracking-tight", children: [_jsx(Container, { className: "h-6 w-6 text-primary" }), "Ladingdragers"] }), _jsx("p", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: "Hier staat hoe groot elke ladingdrager is. De Beladingindeling gebruikt deze maten om te bepalen hoeveel fusten er per laag en per drager passen. In de Rule Engine bepaal je per strategie welke ladingdragers gebruikt mogen worden." })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: reload, disabled: loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Vernieuwen"] }), _jsxs(Button, { size: "sm", onClick: openNieuw, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Ladingdrager"] }), _jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsx(Link, { to: "/logistiek-engine", children: "Terug" }) })] })] }), _jsx(LadingdragerVoorstellenCard, { onKlaar: reload }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Capaciteit per ladingdrager" }), _jsx(CardDescription, { children: "
|
|
105
|
+
return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs("h1", { className: "flex items-center gap-2 text-2xl font-semibold tracking-tight", children: [_jsx(Container, { className: "h-6 w-6 text-primary" }), "Ladingdragers"] }), _jsx("p", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: "Hier staat hoe groot elke ladingdrager is. De Beladingindeling gebruikt deze maten om te bepalen hoeveel fusten er per laag en per drager passen. In de Rule Engine bepaal je per strategie welke ladingdragers gebruikt mogen worden." })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: reload, disabled: loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Vernieuwen"] }), _jsxs(Button, { size: "sm", onClick: openNieuw, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Ladingdrager"] }), _jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsx(Link, { to: "/logistiek-engine", children: "Terug" }) })] })] }), _jsx(LadingdragerVoorstellenCard, { onKlaar: reload }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Capaciteit per ladingdrager" }), _jsx(CardDescription, { children: "De capaciteit van een kar is het hoogste aantal lagen per kar van de producten op die kar. \"Lagen\" hieronder is de standaard als het product geen eigen lagen per kar heeft." })] }), _jsx(CardContent, { children: loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : safeItems.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen ladingdragers ingesteld." })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Ladingdrager" }), _jsx(TableHead, { children: "Model" }), _jsx(TableHead, { className: "text-right", children: "Lagen" }), _jsx(TableHead, { className: "text-right", children: "Laagmaat" }), _jsx(TableHead, { className: "text-right", children: "Max dozen" }), _jsx(TableHead, { className: "text-right", children: "Max kg" }), _jsx(TableHead, { children: "Mengen" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsx(TableBody, { children: safeItems.map((row) => (_jsxs(TableRow, { className: row.is_active ? "" : "opacity-50", children: [_jsxs(TableCell, { children: [_jsx("div", { className: "font-medium", children: ladingdragerNaam(row.code, floricodeNamen, row.name) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: row.code }), row.is_default ? _jsx(Badge, { variant: "secondary", children: "Standaard" }) : null, !row.is_active ? _jsx(Badge, { variant: "outline", children: "Uit" }) : null] })] }), _jsx(TableCell, { className: "text-sm", children: CAPACITY_MODEL_LABELS[row.capacity_model] }), _jsx(TableCell, { className: "text-right", children: row.layers_per_carrier }), _jsxs(TableCell, { className: "text-right text-sm text-muted-foreground", children: [row.layer_length_cm, " \u00D7 ", row.layer_width_cm, " cm"] }), _jsx(TableCell, { className: "text-right", children: row.max_boxes ?? "—" }), _jsx(TableCell, { className: "text-right", children: row.max_weight_kg ?? "—" }), _jsx(TableCell, { children: _jsx(Badge, { variant: row.allow_mixing === false ? "outline" : "secondary", children: row.allow_mixing === false ? "Nooit mengen" : "Mengen mag" }) }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => openBewerk(row), children: _jsx(Pencil, { className: "h-4 w-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => remove(row.id), children: _jsx(Trash2, { className: "h-4 w-4" }) })] }) })] }, row.id))) })] })) })] }), _jsx(Dialog, { open: open, onOpenChange: setOpen, children: _jsxs(DialogContent, { className: "max-h-[85vh] overflow-y-auto sm:max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: bewerkId ? "Ladingdrager bewerken" : "Nieuwe ladingdrager" }), _jsx(DialogDescription, { children: "Deze maten bepalen hoeveel er per laag en per drager past." })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "code", children: "Code" }), _jsx(Input, { id: "code", value: form.code, onChange: (e) => set("code", e.target.value), placeholder: "pallet", disabled: Boolean(bewerkId) })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "name", children: "Naam" }), _jsx(Input, { id: "name", value: form.name, onChange: (e) => set("name", e.target.value) })] })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { children: "Capaciteitsmodel" }), _jsxs(Select, { value: form.capacity_model, onValueChange: (v) => set("capacity_model", v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: Object.entries(CAPACITY_MODEL_LABELS).map(([value, label]) => (_jsx(SelectItem, { value: value, children: label }, value))) })] })] }), toonLagen ? (_jsxs("div", { className: "grid grid-cols-3 gap-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "lagen", children: "Lagen" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Standaard als het product geen eigen lagen per kar heeft." }), _jsx(Input, { id: "lagen", type: "number", min: 1, value: form.layers_per_carrier, onChange: (e) => set("layers_per_carrier", Number(e.target.value)) })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "lengte", children: "Lengte (cm)" }), _jsx(Input, { id: "lengte", type: "number", min: 0, value: form.layer_length_cm, onChange: (e) => set("layer_length_cm", Number(e.target.value)) })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "breedte", children: "Breedte (cm)" }), _jsx(Input, { id: "breedte", type: "number", min: 0, value: form.layer_width_cm, onChange: (e) => set("layer_width_cm", Number(e.target.value)) })] })] })) : null, _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxfust", children: "Max fusten per laag" }), _jsx(Input, { id: "maxfust", type: "number", min: 1, value: form.max_crates_per_layer, onChange: (e) => set("max_crates_per_layer", e.target.value), placeholder: "Geen grens" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxdozen", children: "Max dozen / fusten totaal" }), _jsx(Input, { id: "maxdozen", type: "number", min: 1, value: form.max_boxes, onChange: (e) => set("max_boxes", e.target.value), placeholder: "Geen grens" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxkg", children: "Max gewicht (kg)" }), _jsx(Input, { id: "maxkg", type: "number", min: 0, value: form.max_weight_kg, onChange: (e) => set("max_weight_kg", e.target.value), placeholder: "Geen grens" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxhoogte", children: "Max hoogte (cm)" }), _jsx(Input, { id: "maxhoogte", type: "number", min: 0, value: form.max_height_cm, onChange: (e) => set("max_height_cm", e.target.value), placeholder: "Geen grens" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxorders", children: "Max orders" }), _jsx(Input, { id: "maxorders", type: "number", min: 1, value: form.max_orders, onChange: (e) => set("max_orders", e.target.value), placeholder: "Geen grens" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxklanten", children: "Max klanten" }), _jsx(Input, { id: "maxklanten", type: "number", min: 1, value: form.max_customers, onChange: (e) => set("max_customers", e.target.value), placeholder: "Geen grens" })] })] }), _jsxs("div", { className: "space-y-3 rounded-lg border p-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { htmlFor: "mengen", children: "Mengen van partijen toestaan" }), _jsx(Switch, { id: "mengen", checked: form.allow_mixing, onCheckedChange: (v) => set("allow_mixing", v) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { htmlFor: "actief", children: "Actief" }), _jsx(Switch, { id: "actief", checked: form.is_active, onCheckedChange: (v) => set("is_active", v) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { htmlFor: "standaard", children: "Standaard ladingdrager" }), _jsx(Switch, { id: "standaard", checked: form.is_default, onCheckedChange: (v) => set("is_default", v) })] }), _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Label, { htmlFor: "volgorde", children: "Volgorde" }), _jsx(Input, { id: "volgorde", type: "number", className: "w-24", value: form.sort_order, onChange: (e) => set("sort_order", Number(e.target.value)) })] })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => setOpen(false), children: "Annuleren" }), _jsx(Button, { onClick: opslaan, disabled: saving || !form.code || !form.name, children: "Opslaan" })] })] }) })] }));
|
|
106
106
|
}
|