@flowselections/floriday-afhandeling-module 1.0.42 → 1.0.43
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/dist-lib/components/afhandeling/AutoProcessStatus.d.ts +3 -1
- package/dist-lib/components/afhandeling/AutoProcessStatus.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/AutoProcessStatus.js +36 -3
- package/dist-lib/components/afhandeling/ControleLijstPrint.js +54 -54
- package/dist-lib/components/afhandeling/ControlePage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/ControlePage.js +23 -25
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.js +410 -121
- package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PickAgendaView.js +4 -4
- package/dist-lib/components/afhandeling/PickingPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PickingPage.js +1 -1
- package/dist-lib/components/afhandeling/ScanControleView.d.ts +2 -0
- package/dist-lib/components/afhandeling/ScanControleView.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ScanControleView.js +158 -0
- package/dist-lib/components/afhandeling/VervoerdersPage.js +1 -1
- package/dist-lib/components/afhandeling/VerzetOrderDialog.js +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +1 -1
- package/dist-lib/components/pickstation/PakbonTemplate.js +70 -70
- package/dist-lib/hooks/useCartIndex.d.ts.map +1 -1
- package/dist-lib/hooks/useCartIndex.js +6 -1
- package/dist-lib/hooks/useEngineTasks.js +1 -1
- package/dist-lib/hooks/useKnownOrders.d.ts +11 -0
- package/dist-lib/hooks/useKnownOrders.d.ts.map +1 -0
- package/dist-lib/hooks/useKnownOrders.js +54 -0
- package/dist-lib/hooks/useOrderBuffers.d.ts +17 -0
- package/dist-lib/hooks/useOrderBuffers.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderBuffers.js +53 -0
- package/dist-lib/hooks/useOrderPickDates.d.ts +10 -0
- package/dist-lib/hooks/useOrderPickDates.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderPickDates.js +62 -0
- package/dist-lib/hooks/useOrderPlanning.d.ts +1 -3
- package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPlanning.js +9 -13
- package/dist-lib/hooks/usePickAgenda.d.ts +0 -5
- package/dist-lib/hooks/usePickAgenda.d.ts.map +1 -1
- package/dist-lib/hooks/usePickAgenda.js +62 -9
- package/dist-lib/hooks/usePickMode.d.ts +10 -0
- package/dist-lib/hooks/usePickMode.d.ts.map +1 -0
- package/dist-lib/hooks/usePickMode.js +31 -0
- package/dist-lib/index.d.ts +2 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +19 -6
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2027 -86
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +2027 -86
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +2027 -86
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +2097 -114
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/afhandelingSettings.functions.d.ts +4018 -140
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/carrierSignupMail.server.js +26 -26
- package/dist-lib/lib/carriers.functions.d.ts +10072 -367
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.d.ts +10072 -367
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartControl.functions.d.ts +45879 -579
- package/dist-lib/lib/cartControl.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartControl.functions.js +134 -10
- package/dist-lib/lib/deliveryNote.functions.d.ts +25891 -0
- package/dist-lib/lib/deliveryNote.functions.d.ts.map +1 -0
- package/dist-lib/lib/deliveryNote.functions.js +32 -0
- package/dist-lib/lib/engineLayouts.functions.d.ts +25889 -0
- package/dist-lib/lib/engineLayouts.functions.d.ts.map +1 -0
- package/dist-lib/lib/engineLayouts.functions.js +42 -0
- package/dist-lib/lib/floriday.functions.d.ts +27885 -52
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +118 -343
- package/dist-lib/lib/logisticsEngine/reschedule.d.ts +17 -0
- package/dist-lib/lib/logisticsEngine/reschedule.d.ts.map +1 -1
- package/dist-lib/lib/logisticsEngine/reschedule.js +63 -0
- package/dist-lib/lib/orderFulfilment.functions.d.ts +25891 -0
- package/dist-lib/lib/orderFulfilment.functions.d.ts.map +1 -0
- package/dist-lib/lib/orderFulfilment.functions.js +35 -0
- package/dist-lib/lib/orderStatus.d.ts +10 -0
- package/dist-lib/lib/orderStatus.d.ts.map +1 -0
- package/dist-lib/lib/orderStatus.js +81 -0
- package/dist-lib/lib/pickDates.functions.d.ts +25896 -0
- package/dist-lib/lib/pickDates.functions.d.ts.map +1 -0
- package/dist-lib/lib/pickDates.functions.js +56 -0
- package/dist-lib/lib/pickMode.d.ts +14 -0
- package/dist-lib/lib/pickMode.d.ts.map +1 -0
- package/dist-lib/lib/pickMode.js +103 -0
- package/dist-lib/lib/printing.d.ts +3 -1
- package/dist-lib/lib/printing.d.ts.map +1 -1
- package/dist-lib/lib/printing.js +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
interface Props {
|
|
2
2
|
salesOrderId: string;
|
|
3
|
+
/** Ordernummer (order_ref) — nodig om opnieuw in te plannen via de Engine. */
|
|
4
|
+
orderRef?: string | null;
|
|
3
5
|
/** Datum waarop de auto-verwerking mag starten (targetPickDate). */
|
|
4
6
|
autoProcessDate?: Date | null;
|
|
5
7
|
/** Toon knop "Nu verwerken" ook als datum nog niet bereikt. */
|
|
@@ -7,6 +9,6 @@ interface Props {
|
|
|
7
9
|
/** Compact = alleen badge, geen knoppen. */
|
|
8
10
|
compact?: boolean;
|
|
9
11
|
}
|
|
10
|
-
export declare function AutoProcessStatus({ salesOrderId, autoProcessDate, allowManualTrigger, compact, }: Props): import("react").JSX.Element;
|
|
12
|
+
export declare function AutoProcessStatus({ salesOrderId, orderRef, autoProcessDate, allowManualTrigger, compact, }: Props): import("react").JSX.Element;
|
|
11
13
|
export {};
|
|
12
14
|
//# sourceMappingURL=AutoProcessStatus.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutoProcessStatus.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/AutoProcessStatus.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AutoProcessStatus.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/AutoProcessStatus.tsx"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oEAAoE;IACpE,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAeD,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,QAAQ,EACR,eAAe,EACf,kBAAyB,EACzB,OAAe,GAChB,EAAE,KAAK,+BAiLP"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
4
|
import { Badge, Button, toast } from "@flowselections/core";
|
|
4
5
|
import { CheckCircle2, Clock, Loader2, PlayCircle, RefreshCw, AlertTriangle } from "lucide-react";
|
|
5
6
|
import { autoProcessSalesOrder, fetchAutoProcessStatuses, } from "../../lib/floridayAutoProcess";
|
|
6
7
|
import { supabase } from "../../integrations/supabase/moduleClient";
|
|
8
|
+
import { replanToNextDeliveryMoment } from "../../lib/logisticsEngine/reschedule";
|
|
7
9
|
const NL_DATE = new Intl.DateTimeFormat("nl-NL", { day: "2-digit", month: "short" });
|
|
8
10
|
function formatWaiting(date) {
|
|
9
11
|
const today = new Date();
|
|
@@ -17,17 +19,20 @@ function formatWaiting(date) {
|
|
|
17
19
|
return "Verwerkt morgen";
|
|
18
20
|
return `Wacht tot ${NL_DATE.format(target)} (${diffDays} dagen)`;
|
|
19
21
|
}
|
|
20
|
-
export function AutoProcessStatus({ salesOrderId, autoProcessDate, allowManualTrigger = true, compact = false, }) {
|
|
22
|
+
export function AutoProcessStatus({ salesOrderId, orderRef, autoProcessDate, allowManualTrigger = true, compact = false, }) {
|
|
21
23
|
const [row, setRow] = useState(null);
|
|
22
24
|
const [loading, setLoading] = useState(false);
|
|
25
|
+
const queryClient = useQueryClient();
|
|
23
26
|
useEffect(() => {
|
|
24
27
|
let cancelled = false;
|
|
25
28
|
fetchAutoProcessStatuses([salesOrderId]).then((m) => {
|
|
26
29
|
if (!cancelled)
|
|
27
30
|
setRow(m.get(salesOrderId) ?? null);
|
|
28
31
|
});
|
|
32
|
+
// Unieke kanaalnaam per instantie: dezelfde order kan meerdere keren in
|
|
33
|
+
// beeld staan en Supabase hergebruikt anders een al geabonneerd kanaal.
|
|
29
34
|
const channel = supabase
|
|
30
|
-
.channel(`auto-process-${salesOrderId}`)
|
|
35
|
+
.channel(`auto-process-${salesOrderId}-${Math.random().toString(36).slice(2)}`)
|
|
31
36
|
.on("postgres_changes", {
|
|
32
37
|
event: "*",
|
|
33
38
|
schema: "public",
|
|
@@ -48,6 +53,34 @@ export function AutoProcessStatus({ salesOrderId, autoProcessDate, allowManualTr
|
|
|
48
53
|
const handleProcess = async () => {
|
|
49
54
|
setLoading(true);
|
|
50
55
|
try {
|
|
56
|
+
if (orderRef) {
|
|
57
|
+
// Opnieuw inplannen op het eerstvolgende aflevermoment; de Engine
|
|
58
|
+
// bepaalt daarna zelf de pickdag en de bijbehorende taken.
|
|
59
|
+
const res = await replanToNextDeliveryMoment(orderRef);
|
|
60
|
+
if (!res.ok) {
|
|
61
|
+
toast.error(res.error ?? "Opnieuw inplannen mislukt");
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const d = res.moment
|
|
65
|
+
? new Date(`${res.moment.date}T00:00:00`).toLocaleDateString("nl-NL")
|
|
66
|
+
: null;
|
|
67
|
+
toast.success(d
|
|
68
|
+
? `Ingepland op ${d}${res.moment?.time ? ` om ${res.moment.time}` : ""}`
|
|
69
|
+
: "Order opnieuw ingepland");
|
|
70
|
+
// Direct verversen zodat de nieuwe leverdatum en de status meteen
|
|
71
|
+
// in beeld staan, precies zoals bij de andere bestellingen.
|
|
72
|
+
await Promise.all([
|
|
73
|
+
queryClient.invalidateQueries({ queryKey: ["logistics-pick-agenda"] }),
|
|
74
|
+
queryClient.invalidateQueries({ queryKey: ["engine", "tasks"] }),
|
|
75
|
+
queryClient.invalidateQueries({ queryKey: ["order-buffers"] }),
|
|
76
|
+
queryClient.invalidateQueries({ queryKey: ["floriday", "orders"] }),
|
|
77
|
+
queryClient.invalidateQueries({ queryKey: ["logistics-cart-index"] }),
|
|
78
|
+
queryClient.invalidateQueries({ queryKey: ["known-orders"] }),
|
|
79
|
+
]);
|
|
80
|
+
await queryClient.refetchQueries({ queryKey: ["logistics-pick-agenda"], type: "active" });
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
51
84
|
const res = await autoProcessSalesOrder(salesOrderId);
|
|
52
85
|
toast.success(res.status === "done"
|
|
53
86
|
? "Verwerkt — afleverbrief wordt aangemaakt"
|
|
@@ -99,5 +132,5 @@ export function AutoProcessStatus({ salesOrderId, autoProcessDate, allowManualTr
|
|
|
99
132
|
return _jsx(_Fragment, { children: badge });
|
|
100
133
|
const showRetry = status === "error";
|
|
101
134
|
const showTrigger = allowManualTrigger && status !== "done" && status !== "acknowledging" && !loading;
|
|
102
|
-
return (_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [badge, showTrigger ? (_jsx(Button, { size: "sm", variant: showRetry ? "outline" : "secondary", onClick: handleProcess, disabled: loading, children: showRetry ? (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "h-3 w-3 mr-1" }), " Opnieuw"] })) : (_jsxs(_Fragment, { children: [_jsx(PlayCircle, { className: "h-3 w-3 mr-1" }), " Nu verwerken"] })) })) : null] }));
|
|
135
|
+
return (_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [badge, showTrigger ? (_jsx(Button, { size: "sm", variant: showRetry ? "outline" : "secondary", onClick: handleProcess, disabled: loading, children: showRetry ? (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "h-3 w-3 mr-1" }), " Opnieuw"] })) : (_jsxs(_Fragment, { children: [_jsx(PlayCircle, { className: "h-3 w-3 mr-1" }), " ", orderRef ? "Nu inplannen" : "Nu verwerken"] })) })) : null] }));
|
|
103
136
|
}
|
|
@@ -70,62 +70,62 @@ export function renderControleLijstHtml(carts, lang = "nl") {
|
|
|
70
70
|
});
|
|
71
71
|
const rows = sorted.length
|
|
72
72
|
? sorted
|
|
73
|
-
.map(({ cart: c, klaarzet }) => `
|
|
74
|
-
<tr>
|
|
75
|
-
<td class="mono bold">${esc(c.cartNumber ?? "—")}</td>
|
|
76
|
-
<td class="right">${esc(c.cratesOnCart ?? "—")}</td>
|
|
77
|
-
<td class="bold">${esc(countryCode(c.country) ?? c.country ?? "—")}</td>
|
|
78
|
-
<td class="bold">${esc(klaarzet.label)}</td>
|
|
79
|
-
<td>${esc(statusLabel(c.status, c.printedCount))}</td>
|
|
73
|
+
.map(({ cart: c, klaarzet }) => `
|
|
74
|
+
<tr>
|
|
75
|
+
<td class="mono bold">${esc(c.cartNumber ?? "—")}</td>
|
|
76
|
+
<td class="right">${esc(c.cratesOnCart ?? "—")}</td>
|
|
77
|
+
<td class="bold">${esc(countryCode(c.country) ?? c.country ?? "—")}</td>
|
|
78
|
+
<td class="bold">${esc(klaarzet.label)}</td>
|
|
79
|
+
<td>${esc(statusLabel(c.status, c.printedCount))}</td>
|
|
80
80
|
</tr>`)
|
|
81
81
|
.join("")
|
|
82
82
|
: `<tr><td colspan="5" class="empty">${esc(t.noCartsToday)}</td></tr>`;
|
|
83
|
-
return `<!DOCTYPE html>
|
|
84
|
-
<html lang="${esc(lang)}">
|
|
85
|
-
<head>
|
|
86
|
-
<meta charset="utf-8" />
|
|
87
|
-
<title>${esc(t.checklistTitle)}</title>
|
|
88
|
-
<style>
|
|
89
|
-
@page { size: A4 portrait; margin: 12mm; }
|
|
90
|
-
body { font-family: Arial, Helvetica, sans-serif; color: #000; margin: 0; }
|
|
91
|
-
h1 { font-size: 20px; margin: 0; }
|
|
92
|
-
.head { display: flex; align-items: baseline; justify-content: space-between;
|
|
93
|
-
border-bottom: 1px solid #000; padding-bottom: 6px; margin-bottom: 12px; }
|
|
94
|
-
.total { font-size: 12px; margin-bottom: 10px; }
|
|
95
|
-
table { width: 100%; border-collapse: collapse; font-size: 11px; }
|
|
96
|
-
th { text-align: left; border-bottom: 1px solid #000; padding: 3px 6px 3px 0; }
|
|
97
|
-
td { border-bottom: 1px solid #ccc; padding: 6px 6px 6px 0; white-space: nowrap; }
|
|
98
|
-
td.right, th.right { text-align: right; }
|
|
99
|
-
.mono { font-family: "Courier New", monospace; }
|
|
100
|
-
.bold { font-weight: 700; }
|
|
101
|
-
.empty { text-align: center; color: #666; padding: 24px 0; border: none; }
|
|
102
|
-
.sign { margin-top: 24px; font-size: 11px; }
|
|
103
|
-
.sign div { margin-top: 8px; }
|
|
104
|
-
.line { display: inline-block; border-bottom: 1px solid #000; width: 220px; }
|
|
105
|
-
tr { page-break-inside: avoid; }
|
|
106
|
-
thead { display: table-header-group; }
|
|
107
|
-
</style>
|
|
108
|
-
</head>
|
|
109
|
-
<body>
|
|
110
|
-
<div class="head"><h1>${esc(t.checklistTitle)}</h1><div>${esc(today)}</div></div>
|
|
111
|
-
<div class="total">${esc(t.totalCarts)}: <strong>${carts.length}</strong></div>
|
|
112
|
-
<table>
|
|
113
|
-
<thead>
|
|
114
|
-
<tr>
|
|
115
|
-
<th>${esc(t.colKarnr)}</th>
|
|
116
|
-
<th class="right">${esc(t.colFusten)}</th>
|
|
117
|
-
<th>${esc(t.colLand)}</th>
|
|
118
|
-
<th>${esc(t.colKlaarzetten)}</th>
|
|
119
|
-
<th>${esc(t.colStatus)}</th>
|
|
120
|
-
</tr>
|
|
121
|
-
</thead>
|
|
122
|
-
<tbody>${rows}</tbody>
|
|
123
|
-
</table>
|
|
124
|
-
<div class="sign">
|
|
125
|
-
<div>${esc(t.checkedBy)}: <span class="line"></span></div>
|
|
126
|
-
<div>${esc(t.dateTime)}: <span class="line"></span></div>
|
|
127
|
-
<div>${esc(t.signature)}: <span class="line"></span></div>
|
|
128
|
-
</div>
|
|
129
|
-
</body>
|
|
83
|
+
return `<!DOCTYPE html>
|
|
84
|
+
<html lang="${esc(lang)}">
|
|
85
|
+
<head>
|
|
86
|
+
<meta charset="utf-8" />
|
|
87
|
+
<title>${esc(t.checklistTitle)}</title>
|
|
88
|
+
<style>
|
|
89
|
+
@page { size: A4 portrait; margin: 12mm; }
|
|
90
|
+
body { font-family: Arial, Helvetica, sans-serif; color: #000; margin: 0; }
|
|
91
|
+
h1 { font-size: 20px; margin: 0; }
|
|
92
|
+
.head { display: flex; align-items: baseline; justify-content: space-between;
|
|
93
|
+
border-bottom: 1px solid #000; padding-bottom: 6px; margin-bottom: 12px; }
|
|
94
|
+
.total { font-size: 12px; margin-bottom: 10px; }
|
|
95
|
+
table { width: 100%; border-collapse: collapse; font-size: 11px; }
|
|
96
|
+
th { text-align: left; border-bottom: 1px solid #000; padding: 3px 6px 3px 0; }
|
|
97
|
+
td { border-bottom: 1px solid #ccc; padding: 6px 6px 6px 0; white-space: nowrap; }
|
|
98
|
+
td.right, th.right { text-align: right; }
|
|
99
|
+
.mono { font-family: "Courier New", monospace; }
|
|
100
|
+
.bold { font-weight: 700; }
|
|
101
|
+
.empty { text-align: center; color: #666; padding: 24px 0; border: none; }
|
|
102
|
+
.sign { margin-top: 24px; font-size: 11px; }
|
|
103
|
+
.sign div { margin-top: 8px; }
|
|
104
|
+
.line { display: inline-block; border-bottom: 1px solid #000; width: 220px; }
|
|
105
|
+
tr { page-break-inside: avoid; }
|
|
106
|
+
thead { display: table-header-group; }
|
|
107
|
+
</style>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<div class="head"><h1>${esc(t.checklistTitle)}</h1><div>${esc(today)}</div></div>
|
|
111
|
+
<div class="total">${esc(t.totalCarts)}: <strong>${carts.length}</strong></div>
|
|
112
|
+
<table>
|
|
113
|
+
<thead>
|
|
114
|
+
<tr>
|
|
115
|
+
<th>${esc(t.colKarnr)}</th>
|
|
116
|
+
<th class="right">${esc(t.colFusten)}</th>
|
|
117
|
+
<th>${esc(t.colLand)}</th>
|
|
118
|
+
<th>${esc(t.colKlaarzetten)}</th>
|
|
119
|
+
<th>${esc(t.colStatus)}</th>
|
|
120
|
+
</tr>
|
|
121
|
+
</thead>
|
|
122
|
+
<tbody>${rows}</tbody>
|
|
123
|
+
</table>
|
|
124
|
+
<div class="sign">
|
|
125
|
+
<div>${esc(t.checkedBy)}: <span class="line"></span></div>
|
|
126
|
+
<div>${esc(t.dateTime)}: <span class="line"></span></div>
|
|
127
|
+
<div>${esc(t.signature)}: <span class="line"></span></div>
|
|
128
|
+
</div>
|
|
129
|
+
</body>
|
|
130
130
|
</html>`;
|
|
131
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ControlePage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/ControlePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ControlePage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/ControlePage.tsx"],"names":[],"mappings":"AAkJA,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,+BAu3BpE"}
|
|
@@ -2,11 +2,12 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { supabase } from "../../integrations/supabase/moduleClient";
|
|
4
4
|
import { Button, Card, Checkbox, Dialog, DialogDescription, DialogTitle, Input, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Textarea, Badge, toast, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
|
|
5
|
-
import { Printer, CheckCircle2, AlertTriangle, History, ChevronLeft, ChevronRight } from "lucide-react";
|
|
6
|
-
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "
|
|
5
|
+
import { Printer, CheckCircle2, AlertTriangle, History, ChevronLeft, ChevronRight, ScanLine } from "lucide-react";
|
|
6
|
+
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "../../components/ui/responsive-dialog";
|
|
7
7
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
8
8
|
import { useServerFn } from "@tanstack/react-start";
|
|
9
|
-
import { getTodaysControlCarts, getControlRescheduleProposals, submitControlSession, listControlHistory, getControlSessionDetail, getControlDraft, saveControlDraft, } from "../../lib/cartControl.functions";
|
|
9
|
+
import { getTodaysControlCarts, getControlRescheduleProposals, submitControlSession, listControlHistory, getControlSessionDetail, getControlDraft, listDeliveredToday, saveControlDraft, } from "../../lib/cartControl.functions";
|
|
10
|
+
import { ScanControleView } from "./ScanControleView";
|
|
10
11
|
import { renderControleLijstHtml } from "./ControleLijstPrint";
|
|
11
12
|
import { printHtmlDocument, printFoutMelding } from "../../lib/printing";
|
|
12
13
|
function dayDiffFromToday(iso) {
|
|
@@ -36,24 +37,6 @@ function relDayLabel(iso) {
|
|
|
36
37
|
return `${Math.abs(diff)} dagen geleden`;
|
|
37
38
|
return d.toLocaleDateString("nl-NL", { weekday: "short", day: "2-digit", month: "2-digit" });
|
|
38
39
|
}
|
|
39
|
-
function fmtTime(time) {
|
|
40
|
-
if (!time)
|
|
41
|
-
return null;
|
|
42
|
-
const m = /^(\d{1,2}):(\d{2})/.exec(time.trim());
|
|
43
|
-
if (!m)
|
|
44
|
-
return null;
|
|
45
|
-
return `${m[1].padStart(2, "0")}:${m[2]}`;
|
|
46
|
-
}
|
|
47
|
-
/** "vandaag - 10:00" */
|
|
48
|
-
function fmtPickup(iso, time) {
|
|
49
|
-
if (!iso)
|
|
50
|
-
return "—";
|
|
51
|
-
const d = new Date(iso);
|
|
52
|
-
if (Number.isNaN(d.getTime()))
|
|
53
|
-
return iso;
|
|
54
|
-
const t = fmtTime(time);
|
|
55
|
-
return t ? `${relDayLabel(iso)} - ${t}` : relDayLabel(iso);
|
|
56
|
-
}
|
|
57
40
|
function fmtDate(iso) {
|
|
58
41
|
if (!iso)
|
|
59
42
|
return "—";
|
|
@@ -114,6 +97,7 @@ export function ControlePage({ onExit } = {}) {
|
|
|
114
97
|
const fetchProposals = useServerFn(getControlRescheduleProposals);
|
|
115
98
|
const submit = useServerFn(submitControlSession);
|
|
116
99
|
const fetchDraft = useServerFn(getControlDraft);
|
|
100
|
+
const fetchDelivered = useServerFn(listDeliveredToday);
|
|
117
101
|
const saveDraft = useServerFn(saveControlDraft);
|
|
118
102
|
const cartsQ = useQuery({
|
|
119
103
|
queryKey: ["control", "today"],
|
|
@@ -129,6 +113,13 @@ export function ControlePage({ onExit } = {}) {
|
|
|
129
113
|
refetchOnMount: "always",
|
|
130
114
|
refetchOnWindowFocus: true,
|
|
131
115
|
});
|
|
116
|
+
const deliveredQ = useQuery({
|
|
117
|
+
queryKey: ["control", "delivered"],
|
|
118
|
+
queryFn: () => fetchDelivered(),
|
|
119
|
+
enabled: tab === "afgeleverd",
|
|
120
|
+
refetchOnMount: "always",
|
|
121
|
+
refetchOnWindowFocus: true,
|
|
122
|
+
});
|
|
132
123
|
const draftQ = useQuery({
|
|
133
124
|
queryKey: controlDraftQueryKey,
|
|
134
125
|
queryFn: async () => (await fetchDraft()),
|
|
@@ -450,6 +441,7 @@ export function ControlePage({ onExit } = {}) {
|
|
|
450
441
|
setPage(pageCount);
|
|
451
442
|
}, [pageCount, page]);
|
|
452
443
|
const pagedCarts = useMemo(() => carts.slice((currentPage - 1) * pageSize, currentPage * pageSize), [carts, currentPage, pageSize]);
|
|
444
|
+
// Geen eigen hernummering meer: het karnummer komt uitsluitend uit de Engine.
|
|
453
445
|
const pendingProposals = pendingProposal?.proposals ?? [];
|
|
454
446
|
const pendingBlocked = pendingProposal?.blocked ?? [];
|
|
455
447
|
const pendingNotReadyCount = pendingProposals.length + pendingBlocked.length;
|
|
@@ -507,13 +499,13 @@ export function ControlePage({ onExit } = {}) {
|
|
|
507
499
|
finally {
|
|
508
500
|
setPrintBezig(false);
|
|
509
501
|
}
|
|
510
|
-
}, children: [_jsx(Printer, { className: "h-4 w-4 mr-2" }), printBezig ? "Bezig met printen…" : "Controlelijst afdrukken"] }), _jsxs(Button, { onClick: runControl, disabled: submitM.isPending || proposalM.isPending || carts.length === 0 || tab !== "controle", children: [_jsx(CheckCircle2, { className: "h-4 w-4 mr-2" }), proposalM.isPending ? "Controleren…" : "Controle uitvoeren"] })] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: tab === "controle" ? "default" : "outline", onClick: () => setTab("controle"), children: "Controle" }), _jsxs(Button, { variant: tab === "historie" ? "default" : "outline", onClick: () => setTab("historie"), children: [_jsx(History, { className: "h-4 w-4 mr-2" }), "Historie"] })] }), tab === "controle" && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-3 items-center", children: [_jsxs(Card, { className: "p-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Totaal karren vandaag" }), _jsx("div", { className: "text-2xl font-semibold", children: stats.total })] }), _jsxs(Card, { className: "p-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Geprint" }), _jsx("div", { className: "text-2xl font-semibold", children: stats.printed })] }), _jsxs(Card, { className: "p-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Aangevinkt" }), _jsx("div", { className: "text-2xl font-semibold", children: stats.checked })] })] }), _jsxs(Card, { className: "p-0 overflow-hidden", children: [_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-12", children: _jsx(Checkbox, { checked: carts.length > 0 && carts.every((c) => checked.has(controlCartKey(c)))
|
|
502
|
+
}, children: [_jsx(Printer, { className: "h-4 w-4 mr-2" }), printBezig ? "Bezig met printen…" : "Controlelijst afdrukken"] }), _jsxs(Button, { onClick: runControl, disabled: submitM.isPending || proposalM.isPending || carts.length === 0 || tab !== "controle", children: [_jsx(CheckCircle2, { className: "h-4 w-4 mr-2" }), proposalM.isPending ? "Controleren…" : "Controle uitvoeren"] })] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: tab === "controle" ? "default" : "outline", onClick: () => setTab("controle"), children: "Controle" }), _jsxs(Button, { variant: tab === "scan" ? "default" : "outline", onClick: () => setTab("scan"), children: [_jsx(ScanLine, { className: "h-4 w-4 mr-2" }), "Scancontrole"] }), _jsxs(Button, { variant: tab === "afgeleverd" ? "default" : "outline", onClick: () => setTab("afgeleverd"), children: [_jsx(CheckCircle2, { className: "h-4 w-4 mr-2" }), "Afgeleverd"] }), _jsxs(Button, { variant: tab === "historie" ? "default" : "outline", onClick: () => setTab("historie"), children: [_jsx(History, { className: "h-4 w-4 mr-2" }), "Historie"] })] }), tab === "controle" && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-3 items-center", children: [_jsxs(Card, { className: "p-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Totaal karren vandaag" }), _jsx("div", { className: "text-2xl font-semibold", children: stats.total })] }), _jsxs(Card, { className: "p-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Geprint" }), _jsx("div", { className: "text-2xl font-semibold", children: stats.printed })] }), _jsxs(Card, { className: "p-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Aangevinkt" }), _jsx("div", { className: "text-2xl font-semibold", children: stats.checked })] })] }), _jsxs(Card, { className: "p-0 overflow-hidden", children: [_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-12", children: _jsx(Checkbox, { checked: carts.length > 0 && carts.every((c) => checked.has(controlCartKey(c)))
|
|
511
503
|
? true
|
|
512
504
|
: carts.some((c) => checked.has(controlCartKey(c)))
|
|
513
505
|
? "indeterminate"
|
|
514
|
-
: false, onCheckedChange: (v) => toggleAll(!!v) }) }), _jsx(TableHead, { children: "Ordernummer" }), _jsx(TableHead, { children: "
|
|
506
|
+
: false, onCheckedChange: (v) => toggleAll(!!v) }) }), _jsx(TableHead, { children: "Ordernummer" }), _jsx(TableHead, { children: "Karnummer" }), _jsx(TableHead, { children: "Uitgeprint" })] }) }), _jsxs(TableBody, { children: [cartsQ.isLoading && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, className: "text-center text-muted-foreground py-8", children: "Laden\u2026" }) })), !cartsQ.isLoading && carts.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, className: "text-center text-muted-foreground py-8", children: "Geen karren om vandaag te controleren." }) })), pagedCarts.map((c) => {
|
|
515
507
|
const k = controlCartKey(c);
|
|
516
|
-
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Checkbox, { checked: checked.has(k), onCheckedChange: (v) => toggle(k, !!v) }) }),
|
|
508
|
+
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Checkbox, { checked: checked.has(k), onCheckedChange: (v) => toggle(k, !!v) }) }), _jsxs(TableCell, { className: "font-mono font-semibold", children: [c.orderNumber || "—", _jsxs("span", { className: "ml-2 text-muted-foreground font-normal", children: ["[", c.cartSeq, " - ", c.cartTotal ?? c.cartSeq, "]"] })] }), _jsx(TableCell, { className: "font-mono font-semibold", children: c.cartNumber ?? "—" }), _jsx(TableCell, { children: (c.printedToday ?? (c.printedCount ?? 0) > 0) ? (_jsx(Badge, { variant: "secondary", children: "Ja" })) : (_jsx(Badge, { variant: "outline", children: "Nee" })) })] }, k));
|
|
517
509
|
})] })] }), carts.length > 0 && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t bg-muted/20 px-4 py-3 text-sm", children: [_jsxs("span", { className: "text-muted-foreground", children: [carts.length, " resultaten"] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-muted-foreground", children: "Resultaten per pagina" }), _jsxs(Select, { value: String(pageSize), onValueChange: (v) => {
|
|
518
510
|
setPageSize(Number(v));
|
|
519
511
|
setPage(1);
|
|
@@ -523,7 +515,7 @@ export function ControlePage({ onExit } = {}) {
|
|
|
523
515
|
? "Voortgang automatisch opgeslagen"
|
|
524
516
|
: lastSavedRef.current && notes === lastSavedRef.current
|
|
525
517
|
? "Concept bewaard"
|
|
526
|
-
: "" })] }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: "Bijzonderheden, afwijkingen\u2026", rows: 3 }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Wordt automatisch bewaard tot de controle definitief is goedgekeurd." })] })] })), tab === "historie" && _jsx(HistorieView, { loading: histQ.isLoading, sessions: histQ.data?.sessions ?? [] }), _jsx(Dialog, { open: !!result, onOpenChange: (v) => !v && setResult(null), children: _jsxs(ResponsiveDialogContent, { size: "md", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsx(DialogTitle, { children: "Resultaat controle" }), _jsxs(DialogDescription, { children: [result?.checkedCount, " klaar \u00B7 ", result?.rescheduledCount, " doorgeschoven \u00B7", " ", result?.blockedCount, " geblokkeerd"] })] }), _jsxs(ResponsiveDialogBody, { className: "space-y-4", children: [result?.blocked && result.blocked.length > 0 && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-3 space-y-2", children: [_jsxs("div", { className: "flex items-start gap-2 text-destructive font-medium", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: "De volgende karren kunnen niet automatisch worden doorgeschoven omdat hierdoor de planning of levering in gevaar komt." })] }), _jsx(BlockedTable, { blocked: result.blocked })] })), result?.rescheduled && result.rescheduled.length > 0 && (_jsxs("div", { className: "border rounded-md p-3", children: [_jsx("div", { className: "font-medium mb-2", children: "Doorgeschoven karren" }), _jsx("ul", { className: "text-sm space-y-1", children: result.rescheduled.map((r, i) => (_jsxs("li", { children: [_jsx("span", { className: "font-mono", children: r.cartNumber ?? "—" }), " \u2014", " ", r.customerName, " \u2192 nieuwe pickdatum", " ", _jsx("strong", { children: fmtDate(r.newPickDate) })] }, i))) })] }))] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { onClick: () => {
|
|
518
|
+
: "" })] }), _jsx(Textarea, { value: notes, onChange: (e) => setNotes(e.target.value), placeholder: "Bijzonderheden, afwijkingen\u2026", rows: 3 }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Wordt automatisch bewaard tot de controle definitief is goedgekeurd." })] })] })), tab === "scan" && _jsx(ScanControleView, {}), tab === "afgeleverd" && (_jsx(AfgeleverdView, { loading: deliveredQ.isLoading, carts: deliveredQ.data?.carts ?? [] })), tab === "historie" && _jsx(HistorieView, { loading: histQ.isLoading, sessions: histQ.data?.sessions ?? [] }), _jsx(Dialog, { open: !!result, onOpenChange: (v) => !v && setResult(null), children: _jsxs(ResponsiveDialogContent, { size: "md", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsx(DialogTitle, { children: "Resultaat controle" }), _jsxs(DialogDescription, { children: [result?.checkedCount, " klaar \u00B7 ", result?.rescheduledCount, " doorgeschoven \u00B7", " ", result?.blockedCount, " geblokkeerd"] })] }), _jsxs(ResponsiveDialogBody, { className: "space-y-4", children: [result?.blocked && result.blocked.length > 0 && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-3 space-y-2", children: [_jsxs("div", { className: "flex items-start gap-2 text-destructive font-medium", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { children: "De volgende karren kunnen niet automatisch worden doorgeschoven omdat hierdoor de planning of levering in gevaar komt." })] }), _jsx(BlockedTable, { blocked: result.blocked })] })), result?.rescheduled && result.rescheduled.length > 0 && (_jsxs("div", { className: "border rounded-md p-3", children: [_jsx("div", { className: "font-medium mb-2", children: "Doorgeschoven karren" }), _jsx("ul", { className: "text-sm space-y-1", children: result.rescheduled.map((r, i) => (_jsxs("li", { children: [_jsx("span", { className: "font-mono", children: r.cartNumber ?? "—" }), " \u2014", " ", r.customerName, " \u2192 nieuwe pickdatum", " ", _jsx("strong", { children: fmtDate(r.newPickDate) })] }, i))) })] }))] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { onClick: () => {
|
|
527
519
|
setResult(null);
|
|
528
520
|
if (onExit)
|
|
529
521
|
onExit();
|
|
@@ -570,3 +562,9 @@ function SummaryTile({ label, value, tone = "default", }) {
|
|
|
570
562
|
}
|
|
571
563
|
// Silence unused Input import (may be used later); keep tree-shakeable
|
|
572
564
|
void Input;
|
|
565
|
+
function AfgeleverdView({ loading, carts }) {
|
|
566
|
+
return (_jsx(Card, { className: "p-0 overflow-hidden", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Ordernummer" }), _jsx(TableHead, { children: "Karnummer" }), _jsx(TableHead, { children: "Gecontroleerd om" })] }) }), _jsxs(TableBody, { children: [loading && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, className: "text-center text-muted-foreground py-8", children: "Laden\u2026" }) })), !loading && carts.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, className: "text-center text-muted-foreground py-8", children: "Vandaag zijn er nog geen karren afgeleverd." }) })), carts.map((c, i) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-mono font-semibold", children: c.orderNumber || "—" }), _jsx(TableCell, { className: "font-mono", children: c.cartNumberLabel || "—" }), _jsx(TableCell, { children: new Date(c.deliveredAt).toLocaleTimeString("nl-NL", {
|
|
567
|
+
hour: "2-digit",
|
|
568
|
+
minute: "2-digit",
|
|
569
|
+
}) })] }, `${c.orderNumber ?? "?"}-${c.cartNumberLabel ?? i}-${i}`)))] })] }) }));
|
|
570
|
+
}
|
|
@@ -5,5 +5,5 @@ export interface DagDetailDialogProps {
|
|
|
5
5
|
planned: PlannedOrder[];
|
|
6
6
|
onOpenChange: (open: boolean) => void;
|
|
7
7
|
}
|
|
8
|
-
export declare function DagDetailDialog(
|
|
8
|
+
export declare function DagDetailDialog(props: DagDetailDialogProps): import("react").JSX.Element | null;
|
|
9
9
|
//# sourceMappingURL=DagDetailDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DagDetailDialog.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/DagDetailDialog.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"DagDetailDialog.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/DagDetailDialog.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAyEjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;AAQD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,sCAG1D"}
|