@flowselections/logistiek-engine 1.0.239 → 1.0.241
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 +2097 -0
- package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
- package/dist-lib/components/GeblokkeerdeOrdersCard.js +2 -2
- package/dist-lib/components/KarplanStatusCard.d.ts.map +1 -1
- package/dist-lib/components/KarplanStatusCard.js +7 -2
- package/dist-lib/components/StandaardgegevensCard.d.ts.map +1 -1
- package/dist-lib/components/StandaardgegevensCard.js +67 -4
- package/dist-lib/components/TaakGezondheidCard.d.ts.map +1 -1
- package/dist-lib/components/TaakGezondheidCard.js +5 -3
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +2 -0
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
- package/dist-lib/hooks/useGeblokkeerdeOrders.js +13 -0
- package/dist-lib/integrations/supabase/types.d.ts +750 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/engineStatusTeksten.d.ts +7 -0
- package/dist-lib/lib/engineStatusTeksten.d.ts.map +1 -0
- package/dist-lib/lib/engineStatusTeksten.js +22 -0
- package/dist-lib/lib/flowTree.js +3 -3
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +44 -0
- package/dist-lib/lib/moduleVersion.d.ts +1 -1
- package/dist-lib/lib/moduleVersion.js +1 -1
- package/dist-lib/lib/ophaalmomentTeksten.d.ts +9 -0
- package/dist-lib/lib/ophaalmomentTeksten.d.ts.map +1 -0
- package/dist-lib/lib/ophaalmomentTeksten.js +29 -0
- package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineSchema.js +27 -2
- package/dist-lib/lib/taakTeLaat.d.ts +7 -0
- package/dist-lib/lib/taakTeLaat.d.ts.map +1 -0
- package/dist-lib/lib/taakTeLaat.js +62 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GeblokkeerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GeblokkeerdeOrdersCard.tsx"],"names":[],"mappings":"AA8BA,wBAAgB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"GeblokkeerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GeblokkeerdeOrdersCard.tsx"],"names":[],"mappings":"AA8BA,wBAAgB,sBAAsB,gCAgNrC"}
|
|
@@ -10,7 +10,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
10
10
|
import { useEffect, useMemo, useState } from "react";
|
|
11
11
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, supabase, } from "@flowselections/core";
|
|
12
12
|
import { AlertTriangle, RefreshCw, RotateCcw } from "lucide-react";
|
|
13
|
-
import { useGeblokkeerdeOrders, redenLabel } from "../hooks/useGeblokkeerdeOrders.js";
|
|
13
|
+
import { useGeblokkeerdeOrders, redenLabel, redenUitleg } from "../hooks/useGeblokkeerdeOrders.js";
|
|
14
14
|
function datum(waarde) {
|
|
15
15
|
if (!waarde)
|
|
16
16
|
return "—";
|
|
@@ -68,7 +68,7 @@ export function GeblokkeerdeOrdersCard() {
|
|
|
68
68
|
setMelding(e?.message ? String(e.message) : "Opruimen is niet gelukt.");
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), "Vastgelopen orders"] }), _jsx(CardDescription, { children: "Deze orders krijgen geen karrenindeling tot er iets aan de order verandert of je ze hier opnieuw aanbiedt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [zichtbaar.length > 0 && (_jsxs(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw(zichtbaar.map((r) => r.orderId)), children: [_jsx(RotateCcw, { className: "mr-2 h-4 w-4" }), "Alles opnieuw proberen"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void refresh(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] })] }), _jsxs(CardContent, { className: "space-y-4", children: [overzicht?.tickStale && (_jsx("p", { className: "rounded-md bg-muted p-3 text-sm text-muted-foreground", children: "De verwerking op de achtergrond heeft zich langer dan tien minuten niet gemeld. Opnieuw proberen zet de order wel klaar, maar hij wordt pas opgepakt zodra de verwerking weer draait." })), error && _jsx("p", { className: "text-sm text-destructive", children: error }), melding && _jsx("p", { className: "text-sm text-muted-foreground", children: melding }), loading && safeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-6 w-full" }), _jsx(Skeleton, { className: "h-6 w-full" })] })) : safeRows.length === 0 ? (_jsxs("p", { className: "text-sm text-muted-foreground", children: ["Geen vastgelopen orders. Alles is ingedeeld of staat nog in de wachtrij", overzicht ? ` (${overzicht.pending} wachtend)` : "", "."] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: filter === "" ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(""), children: ["Alles (", safeRows.length, ")"] }), codes.map(([code, aantal]) => (_jsxs(Badge, { variant: filter === code ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(code), children: [redenLabel(code), " (", aantal, ")"] }, code)))] }), _jsx("div", { className: "divide-y rounded-md border", children: zichtbaar.map((r) => (_jsxs("div", { className: "flex items-start justify-between gap-4 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: r.orderRef }), _jsx(Badge, { variant: "secondary", children: redenLabel(r.reasonCode) }), _jsx(Badge, { variant: "outline", children: "Wacht op actie" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", datum(r.deliveryDate), " \u00B7 sinds ", datum(r.blockedSince)] })] }), r.reason && (_jsx("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: r.reason }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [(["belading_onvolledig", "gewicht_onbekend"].includes(String(r.reasonCode)) ||
|
|
71
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), "Vastgelopen orders"] }), _jsx(CardDescription, { children: "Deze orders krijgen geen karrenindeling tot er iets aan de order verandert of je ze hier opnieuw aanbiedt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [zichtbaar.length > 0 && (_jsxs(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw(zichtbaar.map((r) => r.orderId)), children: [_jsx(RotateCcw, { className: "mr-2 h-4 w-4" }), "Alles opnieuw proberen"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void refresh(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] })] }), _jsxs(CardContent, { className: "space-y-4", children: [overzicht?.tickStale && (_jsx("p", { className: "rounded-md bg-muted p-3 text-sm text-muted-foreground", children: "De verwerking op de achtergrond heeft zich langer dan tien minuten niet gemeld. Opnieuw proberen zet de order wel klaar, maar hij wordt pas opgepakt zodra de verwerking weer draait." })), error && _jsx("p", { className: "text-sm text-destructive", children: error }), melding && _jsx("p", { className: "text-sm text-muted-foreground", children: melding }), loading && safeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-6 w-full" }), _jsx(Skeleton, { className: "h-6 w-full" })] })) : safeRows.length === 0 ? (_jsxs("p", { className: "text-sm text-muted-foreground", children: ["Geen vastgelopen orders. Alles is ingedeeld of staat nog in de wachtrij", overzicht ? ` (${overzicht.pending} wachtend)` : "", "."] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: filter === "" ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(""), children: ["Alles (", safeRows.length, ")"] }), codes.map(([code, aantal]) => (_jsxs(Badge, { variant: filter === code ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(code), children: [redenLabel(code), " (", aantal, ")"] }, code)))] }), _jsx("div", { className: "divide-y rounded-md border", children: zichtbaar.map((r) => (_jsxs("div", { className: "flex items-start justify-between gap-4 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: r.orderRef }), _jsx(Badge, { variant: "secondary", children: redenLabel(r.reasonCode) }), _jsx(Badge, { variant: "outline", children: "Wacht op actie" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", datum(r.deliveryDate), " \u00B7 sinds ", datum(r.blockedSince)] })] }), r.reason && (_jsx("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: r.reason })), redenUitleg(r.reasonCode) && (_jsx("p", { className: "mt-1 text-sm", children: redenUitleg(r.reasonCode) }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [(["belading_onvolledig", "gewicht_onbekend"].includes(String(r.reasonCode)) ||
|
|
72
72
|
String(r.reason ?? "").startsWith("Belading fysiek onmogelijk")) && (_jsx("a", { className: "text-sm underline", href: "/logistiek-engine/beheer#gegevens-voor-karindeling", children: "Gegevens invullen" })), r.reasonCode === "ladingdrager_niet_in_beheer" && (_jsx("a", { className: "text-sm underline", href: "/logistiek-engine/ladingdragers", children: "Naar ladingdragers" })), r.reasonCode === "belading_onwaarschijnlijk" &&
|
|
73
73
|
!String(r.reason ?? "").startsWith("Belading fysiek onmogelijk") && (_jsx(Button, { size: "sm", disabled: busy, onClick: () => void bevestigen(r.orderId, r.orderRef), children: "Belading bevestigen" })), r.reasonCode === "dubbele_regels" && (_jsx(Button, { variant: "secondary", size: "sm", disabled: busy, onClick: () => void opruimen(r.orderId, r.orderRef), children: "Dubbele regels opruimen" })), _jsx(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw([r.orderId]), children: "Opnieuw" })] })] }, r.queueId))) })] })), _jsx(BeladingWaarschuwingen, {})] })] }));
|
|
74
74
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KarplanStatusCard.d.ts","sourceRoot":"","sources":["../../src/components/KarplanStatusCard.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"KarplanStatusCard.d.ts","sourceRoot":"","sources":["../../src/components/KarplanStatusCard.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,iBAAiB,gCA2FhC"}
|
|
@@ -13,11 +13,16 @@ import { ClipboardList, RefreshCw } from "lucide-react";
|
|
|
13
13
|
export function KarplanStatusCard() {
|
|
14
14
|
const [rijen, setRijen] = useState([]);
|
|
15
15
|
const [loading, setLoading] = useState(true);
|
|
16
|
+
const [fout, setFout] = useState(null);
|
|
16
17
|
const laden = useCallback(async () => {
|
|
17
18
|
setLoading(true);
|
|
18
|
-
const { data } = await supabase.rpc("logistics_cart_plan_overview", {
|
|
19
|
+
const { data, error } = await supabase.rpc("logistics_cart_plan_overview", {
|
|
19
20
|
p_days: 3,
|
|
20
21
|
});
|
|
22
|
+
// Een leesfout is nooit "geen orders": toon dat de controle niet lukte.
|
|
23
|
+
if (error)
|
|
24
|
+
console.error("logistics_cart_plan_overview", error);
|
|
25
|
+
setFout(error ? String(error.message ?? "onbekende fout") : null);
|
|
21
26
|
setRijen(Array.isArray(data) ? data : []);
|
|
22
27
|
setLoading(false);
|
|
23
28
|
}, []);
|
|
@@ -25,7 +30,7 @@ export function KarplanStatusCard() {
|
|
|
25
30
|
void laden();
|
|
26
31
|
}, [laden]);
|
|
27
32
|
const zonderPlan = rijen.filter((r) => !r.plan_ready).length;
|
|
28
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(ClipboardList, { className: "h-5 w-5 text-primary" }), "Karplanning per order"] }), _jsx(CardDescription, { children: "Orders van vandaag en de komende dagen. Een order hoort pas op het pickscherm te staan als het karplan klaar is \u00E9n de order is vrijgegeven." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: `mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}` }), "Vernieuwen"] })] }), _jsx(CardContent, { className: "space-y-3", children: loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : rijen.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders met een leverdatum in deze periode." })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-sm text-muted-foreground", children: zonderPlan === 0
|
|
33
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(ClipboardList, { className: "h-5 w-5 text-primary" }), "Karplanning per order"] }), _jsx(CardDescription, { children: "Orders van vandaag en de komende dagen. Een order hoort pas op het pickscherm te staan als het karplan klaar is \u00E9n de order is vrijgegeven." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: `mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}` }), "Vernieuwen"] })] }), _jsx(CardContent, { className: "space-y-3", children: loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : fout ? (_jsx("p", { className: "text-sm text-destructive", children: "De karplanning kon niet worden gelezen. Mogelijk is Supabase bijwerken nodig; neem contact op met de beheerder." })) : rijen.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders met een leverdatum in deze periode." })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-sm text-muted-foreground", children: zonderPlan === 0
|
|
29
34
|
? "Alle orders in deze periode hebben een sluitend karplan."
|
|
30
35
|
: `${zonderPlan} order(s) hebben nog geen sluitend karplan.` }), _jsx("div", { className: "divide-y rounded-md border", children: rijen.map((r) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium", children: r.order_ref }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", r.delivery_date ?? "onbekend", r.reason ? ` — ${r.reason}` : ""] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Badge, { variant: r.plan_ready ? "secondary" : "destructive", children: r.plan_ready ? `${r.cart_total ?? 0} karren` : "Geen karplan" }), _jsx(Badge, { variant: r.released ? "default" : "outline", children: r.released ? "Vrijgegeven" : "Nog niet vrij" })] })] }, r.order_ref))) })] })) })] }));
|
|
31
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StandaardgegevensCard.d.ts","sourceRoot":"","sources":["../../src/components/StandaardgegevensCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StandaardgegevensCard.d.ts","sourceRoot":"","sources":["../../src/components/StandaardgegevensCard.tsx"],"names":[],"mappings":"AAeA,wBAAgB,qBAAqB,gCAmDpC"}
|
|
@@ -7,8 +7,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
7
7
|
// GEEN <Header /> hier — die levert de shell.
|
|
8
8
|
// ============================================================================
|
|
9
9
|
import { useEffect, useState } from "react";
|
|
10
|
-
import { Badge, Card, CardContent, CardDescription, CardHeader, CardTitle, formatDatumTijd, supabase } from "@flowselections/core";
|
|
10
|
+
import { Badge, Card, CardContent, CardDescription, CardHeader, CardTitle, formatDatum, formatDatumTijd, supabase } from "@flowselections/core";
|
|
11
|
+
import { ophaalmomentMeldingen } from "../lib/ophaalmomentTeksten.js";
|
|
11
12
|
import { Database } from "lucide-react";
|
|
13
|
+
import { meldingGewoneTaal, schemaVersieOud, VERWACHTE_SCHEMA_VERSIE } from "../lib/engineStatusTeksten.js";
|
|
12
14
|
import { aangevuldeOnderdelen, useEngineZelfherstel } from "../hooks/useEngineZelfherstel.js";
|
|
13
15
|
export function StandaardgegevensCard() {
|
|
14
16
|
const { resultaat, fout } = useEngineZelfherstel();
|
|
@@ -24,7 +26,7 @@ export function StandaardgegevensCard() {
|
|
|
24
26
|
const eerder = aangevuldeOnderdelen(laatste);
|
|
25
27
|
const meldingen = Array.isArray(resultaat?.meldingen) ? resultaat.meldingen : [];
|
|
26
28
|
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(Database, { className: "h-4 w-4" }), " Standaardgegevens", fout ? _jsx(Badge, { variant: "destructive", children: "Controle mislukt" })
|
|
27
|
-
: resultaat ? _jsx(Badge, { variant: "secondary", children: nu.length ? "Aangevuld" : "Compleet" }) : null] }), _jsx(CardDescription, { children: "Ladingdragers, Floriday-vertalingen, planinstellingen, tijdinstelling en strategie." })] }), _jsxs(CardContent, { className: "space-y-2 text-sm", children: [fout && _jsxs("p", { className: "text-destructive", children: ["Kon niet controleren: ", fout] }), nu.length > 0 && (_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Zojuist aangevuld:" }), _jsx("ul", { className: "list-disc pl-5", children: nu.map((t) => _jsx("li", { children: t }, t)) })] })), nu.length === 0 && eerder.length > 0 && laatste?.op && (_jsxs("div", { children: [_jsxs("p", { className: "text-muted-foreground", children: ["Laatst aangevuld op ", new Date(laatste.op).toLocaleString("nl-NL"), ":"] }), _jsx("ul", { className: "list-disc pl-5 text-muted-foreground", children: eerder.map((t) => _jsx("li", { children: t }, t)) })] })), resultaat && nu.length === 0 && eerder.length === 0 && _jsx("p", { className: "text-muted-foreground", children: "Alle standaardgegevens zijn aanwezig." }), meldingen.map((m) => _jsx("p", { className: "text-destructive", children: m }, m)), _jsx(OnderhoudStatus, {}), _jsx(ProductiebonStatus, {}), _jsx(SamenvoeggroepenStatus, {}), _jsx(StickerSyncStatus, {})] })] }));
|
|
29
|
+
: resultaat ? _jsx(Badge, { variant: "secondary", children: nu.length ? "Aangevuld" : "Compleet" }) : null] }), _jsx(CardDescription, { children: "Ladingdragers, Floriday-vertalingen, planinstellingen, tijdinstelling en strategie." })] }), _jsxs(CardContent, { className: "space-y-2 text-sm", children: [fout && _jsxs("p", { className: "text-destructive", children: ["Kon niet controleren: ", fout] }), nu.length > 0 && (_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Zojuist aangevuld:" }), _jsx("ul", { className: "list-disc pl-5", children: nu.map((t) => _jsx("li", { children: t }, t)) })] })), nu.length === 0 && eerder.length > 0 && laatste?.op && (_jsxs("div", { children: [_jsxs("p", { className: "text-muted-foreground", children: ["Laatst aangevuld op ", new Date(laatste.op).toLocaleString("nl-NL"), ":"] }), _jsx("ul", { className: "list-disc pl-5 text-muted-foreground", children: eerder.map((t) => _jsx("li", { children: t }, t)) })] })), resultaat && nu.length === 0 && eerder.length === 0 && _jsx("p", { className: "text-muted-foreground", children: "Alle standaardgegevens zijn aanwezig." }), meldingen.map((m) => _jsx("p", { className: "text-destructive", children: meldingGewoneTaal(m) }, m)), _jsx(SchemaVersieStatus, {}), _jsx(OnderhoudStatus, {}), _jsx(ProductiebonStatus, {}), _jsx(SamenvoeggroepenStatus, {}), _jsx(StickerSyncStatus, {}), _jsx(SamenvoegenStatus, {}), _jsx(OphaalmomentStatus, {})] })] }));
|
|
28
30
|
}
|
|
29
31
|
// 1.0.228: wachtrij per status, oudste trace-regel en laatste opruimronde.
|
|
30
32
|
function OnderhoudStatus() {
|
|
@@ -62,7 +64,7 @@ function SamenvoeggroepenStatus() {
|
|
|
62
64
|
const groepen = info.stand?.totaalGroepen ?? 0;
|
|
63
65
|
return (_jsxs("div", { className: "border-t pt-2", children: [_jsx("p", { className: "font-medium", children: "Samenvoeggroepen" }), _jsx("p", { className: "text-muted-foreground", children: groepen > 0
|
|
64
66
|
? `${groepen} groep(en) hersteld: ${info.stand?.totaalOrders ?? 0} geannuleerde of verwijderde order(s) eruit gehaald${info.stand?.laatsteOp ? ` (laatst ${formatDatumTijd(info.stand.laatsteOp)})` : ""}.`
|
|
65
|
-
: "
|
|
67
|
+
: "Nog geen groepen hersteld." }), (info.wachten ?? 0) > 0 && (_jsxs("p", { className: "text-destructive", children: [info.wachten, " geannuleerde order(s) staan nog in een groep; de volgende controle haalt ze eruit."] })), (info.blijvenStaan ?? 0) > 0 && (_jsxs("p", { className: "text-muted-foreground", children: [info.blijvenStaan, " geannuleerde order(s) blijven in hun groep, omdat hun kar al geprint of gescand is. Die karren worden niet automatisch opnieuw ingedeeld."] })), (info.nogInGroep ?? 0) === 0 && (_jsx("p", { className: "text-muted-foreground", children: "Geen geannuleerde orders meer in een groep." })), fouten.map((f, i) => (_jsxs("p", { className: "text-destructive", children: [formatDatumTijd(f.op), ": ", f.melding] }, i)))] }));
|
|
66
68
|
}
|
|
67
69
|
function ProductiebonStatus() {
|
|
68
70
|
const [info, setInfo] = useState(null);
|
|
@@ -105,5 +107,66 @@ function StickerSyncStatus() {
|
|
|
105
107
|
if (!info || !info.bekend)
|
|
106
108
|
return null;
|
|
107
109
|
const fouten = Array.isArray(info.fouten) ? info.fouten : [];
|
|
108
|
-
return (_jsxs("div", { className: "border-t pt-2", children: [_jsx("p", { className: "font-medium", children: "Stickers" }), fouten.length === 0 ? (_jsxs("p", { className: "text-muted-foreground", children: ["Laatste ronde zonder fouten", info.op ? ` (${formatDatumTijd(info.op)})` : "", "."] })) : (_jsxs(_Fragment, { children: [_jsxs("p", { className: "text-destructive", children: ["
|
|
110
|
+
return (_jsxs("div", { className: "border-t pt-2", children: [_jsx("p", { className: "font-medium", children: "Stickers" }), fouten.length === 0 ? (_jsxs("p", { className: "text-muted-foreground", children: ["Laatste ronde zonder fouten", info.op ? ` (${formatDatumTijd(info.op)})` : "", "."] })) : (_jsxs(_Fragment, { children: [fouten.map((f, i) => (_jsxs("p", { className: "text-destructive", children: ["Stickers bijwerken lukt niet: ", f.fout ?? "onbekende fout", info.op ? ` (${formatDatumTijd(info.op)})` : ""] }, i))), _jsx("p", { className: "text-muted-foreground", children: "De minuutronde loopt gewoon door; dit telt niet als niet-afgeronde ronde." })] }))] }));
|
|
111
|
+
}
|
|
112
|
+
// Samenvoegen van Floriday-orders: alleen meldingen, geen knoppen (alleen voor beheer).
|
|
113
|
+
function SamenvoegenStatus() {
|
|
114
|
+
const [info, setInfo] = useState(null);
|
|
115
|
+
const [fout, setFout] = useState(null);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
supabase.rpc("logistics_merge_status").then(({ data, error }) => {
|
|
118
|
+
if (error) {
|
|
119
|
+
console.error("logistics_merge_status", error);
|
|
120
|
+
// Geen beheerrechten: deze melding is alleen voor beheerders.
|
|
121
|
+
if (error.code !== "42501")
|
|
122
|
+
setFout(error.message);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
setInfo(data && typeof data === "object" ? data : null);
|
|
126
|
+
});
|
|
127
|
+
}, []);
|
|
128
|
+
if (fout)
|
|
129
|
+
return _jsx("p", { className: "border-t pt-2 text-destructive", children: "Orders combineren: status kon niet worden gelezen." });
|
|
130
|
+
if (!info)
|
|
131
|
+
return null;
|
|
132
|
+
const teGroot = Number(info.groepTeGroot ?? 0);
|
|
133
|
+
const verwijderd = Number(info.nieuwVerwijderd ?? 0);
|
|
134
|
+
const fouten = Number(info.fouten ?? 0);
|
|
135
|
+
return (_jsxs("div", { className: "border-t pt-2", children: [_jsx("p", { className: "font-medium", children: "Orders combineren" }), teGroot === 0 && verwijderd === 0 && fouten === 0 && _jsx("p", { className: "text-muted-foreground", children: "Geen meldingen." }), teGroot > 0 && _jsxs("p", { className: "text-destructive", children: [teGroot, " orders zijn samengevoegd in een groep van meer dan 20."] }), verwijderd > 0 && (_jsxs("p", { className: "text-destructive", children: [verwijderd, " nieuwe orders zijn als verwijderd binnengekomen; ze krijgen geen karindeling."] })), fouten > 0 && (_jsxs("p", { className: "text-destructive", children: ["Combineren lukte ", fouten, " keer niet", info.laatsteFout?.melding ? `; laatste: ${info.laatsteFout.melding}` : "", ". De order wordt dan los ingedeeld."] }))] }));
|
|
136
|
+
}
|
|
137
|
+
// Ophaalmomenten: orders zonder moment en of de momenten ver genoeg vooruit bekend zijn (alleen meldingen).
|
|
138
|
+
function OphaalmomentStatus() {
|
|
139
|
+
const [info, setInfo] = useState(null);
|
|
140
|
+
const [fout, setFout] = useState(null);
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
supabase.rpc("logistics_pickup_status").then(({ data, error }) => {
|
|
143
|
+
if (error) {
|
|
144
|
+
console.error("logistics_pickup_status", error);
|
|
145
|
+
if (error.code !== "42501")
|
|
146
|
+
setFout(error.message);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
setInfo(data && typeof data === "object" ? data : null);
|
|
150
|
+
});
|
|
151
|
+
}, []);
|
|
152
|
+
if (fout)
|
|
153
|
+
return _jsx("p", { className: "border-t pt-2 text-destructive", children: "Ophaalmomenten: status kon niet worden gelezen." });
|
|
154
|
+
if (!info)
|
|
155
|
+
return null;
|
|
156
|
+
const regels = ophaalmomentMeldingen(info, (d) => formatDatum(d));
|
|
157
|
+
return (_jsxs("div", { className: "border-t pt-2", children: [_jsx("p", { className: "font-medium", children: "Ophaalmomenten" }), regels.length === 0 && _jsx("p", { className: "text-muted-foreground", children: "Geen meldingen." }), regels.map((t, i) => (_jsx("p", { className: "text-destructive", children: t }, i)))] }));
|
|
158
|
+
}
|
|
159
|
+
// Punt 8: is de database van deze shell bijgewerkt voor deze moduleversie?
|
|
160
|
+
function SchemaVersieStatus() {
|
|
161
|
+
const [oud, setOud] = useState(null);
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
supabase.rpc("logistics_schema_versie").then(({ data, error }) => {
|
|
164
|
+
if (error)
|
|
165
|
+
console.error("logistics_schema_versie", error);
|
|
166
|
+
setOud(schemaVersieOud(error ? null : typeof data === "string" ? data : null));
|
|
167
|
+
});
|
|
168
|
+
}, []);
|
|
169
|
+
if (!oud)
|
|
170
|
+
return null;
|
|
171
|
+
return (_jsxs("p", { className: "border-t pt-2 text-destructive", children: ["Supabase bijwerken nodig: de database van deze shell is ouder dan de module (verwacht ", VERWACHTE_SCHEMA_VERSIE, "). Sommige controles kunnen tot die tijd niet worden gelezen."] }));
|
|
109
172
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaakGezondheidCard.d.ts","sourceRoot":"","sources":["../../src/components/TaakGezondheidCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TaakGezondheidCard.d.ts","sourceRoot":"","sources":["../../src/components/TaakGezondheidCard.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,kBAAkB,gCAoEjC"}
|
|
@@ -7,6 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
// ============================================================================
|
|
8
8
|
import { AlertTriangle, CheckCircle2, RefreshCw } from "lucide-react";
|
|
9
9
|
import { useTaakGezondheid } from "../hooks/useTaakGezondheid.js";
|
|
10
|
+
import { taakFoutGewoneTaal, taakTeLaat } from "../lib/taakTeLaat.js";
|
|
10
11
|
function geleden(tijd) {
|
|
11
12
|
if (!tijd)
|
|
12
13
|
return "nooit gedraaid";
|
|
@@ -23,9 +24,10 @@ function geleden(tijd) {
|
|
|
23
24
|
export function TaakGezondheidCard() {
|
|
24
25
|
const { taken, laden, fout, herlaad } = useTaakGezondheid();
|
|
25
26
|
const veilig = Array.isArray(taken) ? taken : [];
|
|
26
|
-
const problemen = veilig.filter((t) => !t.actief || t.mislukt24u > 0 || t.laatsteStatus === "failed");
|
|
27
|
+
const problemen = veilig.filter((t) => !t.actief || t.mislukt24u > 0 || t.laatsteStatus === "failed" || (t.actief && taakTeLaat(t.laatsteStart, t.schema)));
|
|
27
28
|
return (_jsxs("div", { className: "rounded-lg border bg-card p-4 text-card-foreground", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("h3", { className: "font-semibold", children: "Achtergrondtaken" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Indelen, taken uitvoeren, afronden en opruimen draaien automatisch." })] }), _jsx("button", { type: "button", onClick: () => void herlaad(), className: "rounded-md border px-3 py-1.5 text-sm hover:bg-accent", "aria-label": "Vernieuwen", children: _jsx(RefreshCw, { className: "h-4 w-4" }) })] }), fout ? _jsx("p", { className: "mb-3 text-sm text-destructive", children: fout }) : null, !laden && problemen.length === 0 && veilig.length > 0 ? (_jsxs("p", { className: "mb-3 flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), " Alle taken draaien zonder fouten."] })) : null, _jsx("ul", { className: "space-y-2", children: veilig.map((t) => {
|
|
28
|
-
const
|
|
29
|
-
|
|
29
|
+
const teLaat = t.actief && taakTeLaat(t.laatsteStart, t.schema);
|
|
30
|
+
const slecht = !t.actief || t.mislukt24u > 0 || t.laatsteStatus === "failed" || teLaat;
|
|
31
|
+
return (_jsxs("li", { className: "rounded-md border p-3 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "font-medium", children: t.naam }), _jsx("span", { className: slecht ? "text-destructive" : "text-muted-foreground", children: geleden(t.laatsteStart) })] }), _jsxs("p", { className: "text-muted-foreground", children: [t.actief ? "actief" : "uitgezet", " \u00B7 ", t.schema, t.mislukt24u > 0 ? ` · ${t.mislukt24u} keer mislukt in 24 uur` : ""] }), teLaat ? (_jsxs("p", { className: "mt-1 flex items-start gap-2 text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), "Deze taak heeft langer dan twee keer zijn normale tussentijd niet gedraaid."] })) : null, t.laatsteStatus === "failed" && t.laatsteBericht ? (_jsxs("p", { className: "mt-1 flex items-start gap-2 text-destructive", title: t.laatsteBericht, children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), taakFoutGewoneTaal(t.laatsteBericht)] })) : null] }, t.naam));
|
|
30
32
|
}) })] }));
|
|
31
33
|
}
|
|
@@ -15,6 +15,8 @@ export interface BlokkadeOverzicht {
|
|
|
15
15
|
tickStale: boolean;
|
|
16
16
|
}
|
|
17
17
|
export declare const REDEN_LABEL: Record<string, string>;
|
|
18
|
+
export declare const REDEN_UITLEG: Record<string, string>;
|
|
19
|
+
export declare function redenUitleg(code: string | null | undefined): string | null;
|
|
18
20
|
export declare function redenLabel(code: string | null | undefined): string;
|
|
19
21
|
export declare function useGeblokkeerdeOrders(): {
|
|
20
22
|
rows: GeblokkeerdeOrder[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useGeblokkeerdeOrders.d.ts","sourceRoot":"","sources":["../../src/hooks/useGeblokkeerdeOrders.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAoB9C,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,UAGzD;AAED,wBAAgB,qBAAqB;;;;;;;sBAqDhB,MAAM,EAAE;gCAwBT,MAAM;;;;;;;kCA8BN,MAAM;EA4BzB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB;;;;;;iCAsCjB,MAAM,EAAE;EAmB5B"}
|
|
1
|
+
{"version":3,"file":"useGeblokkeerdeOrders.d.ts","sourceRoot":"","sources":["../../src/hooks/useGeblokkeerdeOrders.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAoB9C,CAAC;AAGF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAW/C,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAE1E;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,UAGzD;AAED,wBAAgB,qBAAqB;;;;;;;sBAqDhB,MAAM,EAAE;gCAwBT,MAAM;;;;;;;kCA8BN,MAAM;EA4BzB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB;;;;;;iCAsCjB,MAAM,EAAE;EAmB5B"}
|
|
@@ -25,6 +25,19 @@ export const REDEN_LABEL = {
|
|
|
25
25
|
indeling_te_lang: "Indeling duurde te lang",
|
|
26
26
|
other: "Overige reden",
|
|
27
27
|
};
|
|
28
|
+
// Wat is er mis en wat moet de gebruiker doen — in gewone taal.
|
|
29
|
+
export const REDEN_UITLEG = {
|
|
30
|
+
belading_onwaarschijnlijk: "De belading van een of meer producten lijkt niet te kloppen, bijvoorbeeld 1 stuk per fust. Controleer de belading bij het product of de orderregel en bevestig hem; daarna wordt de order vanzelf ingedeeld.",
|
|
31
|
+
belading_onvolledig: "Bij een of meer producten ontbreekt een deel van de belading (stuks per fust, fusten per laag of lagen per kar). Vul die aan; daarna wordt de order vanzelf ingedeeld.",
|
|
32
|
+
belading_onbekend: "Van een of meer producten is de belading niet bekend. Vul de belading in bij het product; daarna wordt de order vanzelf ingedeeld.",
|
|
33
|
+
gewicht_onbekend: "Het gewicht per fust ontbreekt. Vul het in bij het product.",
|
|
34
|
+
ladingdrager_onbekend: "De ladingdrager van een regel is onbekend. Kies de juiste ladingdrager bij het product.",
|
|
35
|
+
ladingdrager_niet_in_beheer: "Deze ladingdrager staat niet in het beheer van ladingdragers. Voeg hem toe of kies een andere.",
|
|
36
|
+
artikel_ontbreekt: "Een regel heeft nog geen artikel. Kies het juiste artikel bij de orderregel.",
|
|
37
|
+
};
|
|
38
|
+
export function redenUitleg(code) {
|
|
39
|
+
return code ? REDEN_UITLEG[code] ?? null : null;
|
|
40
|
+
}
|
|
28
41
|
export function redenLabel(code) {
|
|
29
42
|
if (!code)
|
|
30
43
|
return REDEN_LABEL.other;
|