@flowselections/floriday-afhandeling-module 1.0.32 → 1.0.34
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.js +1 -1
- package/dist-lib/components/afhandeling/ControleLijstPrint.d.ts +6 -6
- package/dist-lib/components/afhandeling/ControleLijstPrint.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/ControleLijstPrint.js +73 -48
- package/dist-lib/components/afhandeling/ControlePage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/ControlePage.js +25 -5
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.js +48 -24
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +16 -5
- package/dist-lib/components/afhandeling/WerkplekWaarschuwing.d.ts +10 -0
- package/dist-lib/components/afhandeling/WerkplekWaarschuwing.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/WerkplekWaarschuwing.js +28 -0
- package/dist-lib/components/pickstation/PakbonTemplate.js +70 -70
- package/dist-lib/components/pickstation/printDocuments.d.ts +9 -2
- package/dist-lib/components/pickstation/printDocuments.d.ts.map +1 -1
- package/dist-lib/components/pickstation/printDocuments.js +8 -52
- package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -1
- package/dist-lib/components/settings/AfhandelingSettingsCard.js +12 -1
- package/dist-lib/hooks/useEngineTasks.js +1 -1
- package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPlanning.js +32 -14
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +18 -13
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +18 -13
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/{client.d.ts → moduleClient.d.ts} +20 -14
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/moduleClient.js +38 -0
- package/dist-lib/integrations/supabase/types.d.ts +19 -14
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +3 -0
- package/dist-lib/lib/afhandelingSettings.functions.d.ts +36 -26
- 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 +90 -65
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.d.ts +90 -65
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartControl.functions.d.ts +180 -130
- package/dist-lib/lib/cartControl.functions.d.ts.map +1 -1
- package/dist-lib/lib/deliveryNotePrint.d.ts +14 -6
- package/dist-lib/lib/deliveryNotePrint.d.ts.map +1 -1
- package/dist-lib/lib/deliveryNotePrint.js +61 -14
- package/dist-lib/lib/floriday.functions.d.ts +18 -13
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayAutoProcess.js +1 -1
- package/dist-lib/lib/logisticsEngine/capacity.js +1 -1
- package/dist-lib/lib/logisticsEngine/emitQueue.d.ts +20 -0
- package/dist-lib/lib/logisticsEngine/emitQueue.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/emitQueue.js +88 -0
- package/dist-lib/lib/logisticsEngine/engine.js +1 -1
- package/dist-lib/lib/logisticsEngine/reschedule.js +1 -1
- package/dist-lib/lib/logisticsEngine/staffPlanning.js +1 -1
- package/dist-lib/lib/printing.d.ts +56 -0
- package/dist-lib/lib/printing.d.ts.map +1 -0
- package/dist-lib/lib/printing.js +209 -0
- package/package.json +4 -2
- package/dist-lib/integrations/supabase/auth-attacher.d.ts +0 -2
- package/dist-lib/integrations/supabase/auth-attacher.d.ts.map +0 -1
- package/dist-lib/integrations/supabase/auth-attacher.js +0 -12
- package/dist-lib/integrations/supabase/client.d.ts.map +0 -1
- package/dist-lib/integrations/supabase/client.js +0 -13
|
@@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
import { Badge, Button, toast } from "@flowselections/core";
|
|
4
4
|
import { CheckCircle2, Clock, Loader2, PlayCircle, RefreshCw, AlertTriangle } from "lucide-react";
|
|
5
5
|
import { autoProcessSalesOrder, fetchAutoProcessStatuses, } from "../../lib/floridayAutoProcess";
|
|
6
|
-
import { supabase } from "../../integrations/supabase/
|
|
6
|
+
import { supabase } from "../../integrations/supabase/moduleClient";
|
|
7
7
|
const NL_DATE = new Intl.DateTimeFormat("nl-NL", { day: "2-digit", month: "short" });
|
|
8
8
|
function formatWaiting(date) {
|
|
9
9
|
const today = new Date();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ControlCart } from "../../lib/cartControl.functions";
|
|
2
2
|
import { type PickstationLang } from "../../lib/pickstationI18n";
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Rendert de controlelijst als losstaande HTML-pagina (A4 portrait).
|
|
5
|
+
* De HTML gaat naar de printwachtrij van de Layout maker; er wordt
|
|
6
|
+
* geen browser-printdialoog meer gebruikt.
|
|
7
|
+
*/
|
|
8
|
+
export declare function renderControleLijstHtml(carts: ControlCart[], lang?: PickstationLang): string;
|
|
9
9
|
//# sourceMappingURL=ControleLijstPrint.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ControleLijstPrint.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/ControleLijstPrint.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ControleLijstPrint.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/ControleLijstPrint.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,2BAA2B,CAAC;AAuCnC;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,WAAW,EAAE,EACpB,IAAI,GAAE,eAAsB,GAC3B,MAAM,CAoGR"}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import { createPortal } from "react-dom";
|
|
4
|
-
import { Button } from "@flowselections/core";
|
|
5
|
-
import { X, Printer } from "lucide-react";
|
|
6
1
|
import { countryCode } from "../../lib/countries";
|
|
7
2
|
import { getPrintDict, PICKSTATION_LOCALE, } from "../../lib/pickstationI18n";
|
|
8
3
|
const DAY_ABBR_BY_LANG = {
|
|
@@ -28,19 +23,20 @@ function computeKlaarzet(cart, lang) {
|
|
|
28
23
|
const time = `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
|
|
29
24
|
return { label: `${day} - ${time}`, sortKey: d.getTime() };
|
|
30
25
|
}
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
function esc(value) {
|
|
27
|
+
return String(value ?? "")
|
|
28
|
+
.replace(/&/g, "&")
|
|
29
|
+
.replace(/</g, "<")
|
|
30
|
+
.replace(/>/g, ">");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Rendert de controlelijst als losstaande HTML-pagina (A4 portrait).
|
|
34
|
+
* De HTML gaat naar de printwachtrij van de Layout maker; er wordt
|
|
35
|
+
* geen browser-printdialoog meer gebruikt.
|
|
36
|
+
*/
|
|
37
|
+
export function renderControleLijstHtml(carts, lang = "nl") {
|
|
33
38
|
const t = getPrintDict(lang);
|
|
34
39
|
const locale = PICKSTATION_LOCALE[lang] ?? "nl-NL";
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
const timer = setTimeout(() => window.print(), 300);
|
|
37
|
-
const handleAfterPrint = () => onClose();
|
|
38
|
-
window.addEventListener("afterprint", handleAfterPrint);
|
|
39
|
-
return () => {
|
|
40
|
-
clearTimeout(timer);
|
|
41
|
-
window.removeEventListener("afterprint", handleAfterPrint);
|
|
42
|
-
};
|
|
43
|
-
}, [onClose]);
|
|
44
40
|
const statusLabel = (status, printedCount) => {
|
|
45
41
|
switch (status) {
|
|
46
42
|
case "not_printed": return t.statusNotPrinted;
|
|
@@ -58,7 +54,7 @@ export function ControleLijstPrint({ carts, onClose, lang = "nl", }) {
|
|
|
58
54
|
month: "long",
|
|
59
55
|
year: "numeric",
|
|
60
56
|
});
|
|
61
|
-
const
|
|
57
|
+
const sorted = carts
|
|
62
58
|
.map((cart) => ({ cart, klaarzet: computeKlaarzet(cart, lang) }))
|
|
63
59
|
.sort((a, b) => {
|
|
64
60
|
if (a.klaarzet.sortKey !== b.klaarzet.sortKey) {
|
|
@@ -72,35 +68,64 @@ export function ControleLijstPrint({ carts, onClose, lang = "nl", }) {
|
|
|
72
68
|
const bn = b.cart.cartNumber ?? "\uFFFF";
|
|
73
69
|
return an.localeCompare(bn);
|
|
74
70
|
});
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
71
|
+
const rows = sorted.length
|
|
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>
|
|
80
|
+
</tr>`)
|
|
81
|
+
.join("")
|
|
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>
|
|
130
|
+
</html>`;
|
|
106
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":"AAoHA,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,+BA2zBpE"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
-
import { supabase } from "../../integrations/supabase/
|
|
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
5
|
import { Printer, CheckCircle2, AlertTriangle, History, ChevronLeft, ChevronRight } from "lucide-react";
|
|
6
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
9
|
import { getTodaysControlCarts, getControlRescheduleProposals, submitControlSession, listControlHistory, getControlSessionDetail, getControlDraft, saveControlDraft, } from "../../lib/cartControl.functions";
|
|
10
|
-
import {
|
|
10
|
+
import { renderControleLijstHtml } from "./ControleLijstPrint";
|
|
11
|
+
import { printHtmlDocument, printFoutMelding } from "../../lib/printing";
|
|
12
|
+
import { WerkplekWaarschuwing, useWerkplek } from "./WerkplekWaarschuwing";
|
|
11
13
|
function fmtDate(iso) {
|
|
12
14
|
if (!iso)
|
|
13
15
|
return "—";
|
|
@@ -60,7 +62,8 @@ export function ControlePage({ onExit } = {}) {
|
|
|
60
62
|
const [notes, setNotes] = useState("");
|
|
61
63
|
const [checked, setChecked] = useState(new Set());
|
|
62
64
|
const [cartStates, setCartStates] = useState({});
|
|
63
|
-
const [
|
|
65
|
+
const [printBezig, setPrintBezig] = useState(false);
|
|
66
|
+
const werkplek = useWerkplek();
|
|
64
67
|
const [result, setResult] = useState(null);
|
|
65
68
|
const [pendingProposal, setPendingProposal] = useState(null);
|
|
66
69
|
const [confirmApproval, setConfirmApproval] = useState(null);
|
|
@@ -413,7 +416,24 @@ export function ControlePage({ onExit } = {}) {
|
|
|
413
416
|
supabase.removeChannel(channel);
|
|
414
417
|
};
|
|
415
418
|
}, [qc]);
|
|
416
|
-
return (_jsxs("main", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Controle karren" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Dagelijkse eindcontrole \u2014 vandaag ", new Date().toLocaleDateString("nl-NL")] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline",
|
|
419
|
+
return (_jsxs("main", { className: "p-6 space-y-6", children: [_jsx(WerkplekWaarschuwing, { werkplek: werkplek }), _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Controle karren" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Dagelijkse eindcontrole \u2014 vandaag ", new Date().toLocaleDateString("nl-NL")] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", disabled: !werkplek || printBezig || carts.length === 0, onClick: async () => {
|
|
420
|
+
setPrintBezig(true);
|
|
421
|
+
try {
|
|
422
|
+
await printHtmlDocument({
|
|
423
|
+
documenttype: "controlelijst",
|
|
424
|
+
documentnaam: `CTRL-${new Date().toISOString().slice(0, 10)}`,
|
|
425
|
+
html: renderControleLijstHtml(carts, "nl"),
|
|
426
|
+
papierformaat: "A4",
|
|
427
|
+
});
|
|
428
|
+
toast.success("Controlelijst naar de printer gestuurd.");
|
|
429
|
+
}
|
|
430
|
+
catch (err) {
|
|
431
|
+
toast.error(printFoutMelding(err));
|
|
432
|
+
}
|
|
433
|
+
finally {
|
|
434
|
+
setPrintBezig(false);
|
|
435
|
+
}
|
|
436
|
+
}, 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)))
|
|
417
437
|
? true
|
|
418
438
|
: carts.some((c) => checked.has(controlCartKey(c)))
|
|
419
439
|
? "indeterminate"
|
|
@@ -429,7 +449,7 @@ export function ControlePage({ onExit } = {}) {
|
|
|
429
449
|
? "Voortgang automatisch opgeslagen"
|
|
430
450
|
: lastSavedRef.current && notes === lastSavedRef.current
|
|
431
451
|
? "Concept bewaard"
|
|
432
|
-
: "" })] }), _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 ?? [] }),
|
|
452
|
+
: "" })] }), _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: () => {
|
|
433
453
|
setResult(null);
|
|
434
454
|
if (onExit)
|
|
435
455
|
onExit();
|
|
@@ -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;AAwCjE,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;
|
|
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;AAwCjE,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;AAWD,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,oBAAoB,sCAiF1F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
@@ -7,8 +7,8 @@ import { CalendarClock, ChevronDown, ChevronRight, Printer, Users } from "lucide
|
|
|
7
7
|
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "../../components/ui/responsive-dialog";
|
|
8
8
|
import { isSameDay } from "../../lib/pickDate";
|
|
9
9
|
import { getOrderLines, } from "../../lib/cartAssignments.functions";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { printLayoutDocument, printFoutMelding } from "../../lib/printing";
|
|
11
|
+
import { WerkplekWaarschuwing, useWerkplek } from "./WerkplekWaarschuwing";
|
|
12
12
|
import { printDeliveryNotesMerged } from "../../lib/deliveryNotePrint";
|
|
13
13
|
import { AutoProcessStatus } from "./AutoProcessStatus";
|
|
14
14
|
import { CapacityWarning } from "./CapacityWarning";
|
|
@@ -18,6 +18,11 @@ import { VerzetOrderDialog } from "./VerzetOrderDialog";
|
|
|
18
18
|
import { setPickDay } from "../../lib/logisticsEngine/reschedule";
|
|
19
19
|
import { clearDayStaffPlan, computeCapacity, getDayStaffPlan, getEngineStaffDefaults, setDayStaffPlan, toDateKey, } from "../../lib/logisticsEngine/staffPlanning";
|
|
20
20
|
const NL_DATE = new Intl.DateTimeFormat("nl-NL", { dateStyle: "full" });
|
|
21
|
+
/** Eén melding per dagdialoog zolang de werkplek niet is ingesteld. */
|
|
22
|
+
function DagWerkplekBanner() {
|
|
23
|
+
const werkplek = useWerkplek();
|
|
24
|
+
return _jsx(WerkplekWaarschuwing, { werkplek: werkplek });
|
|
25
|
+
}
|
|
21
26
|
export function DagDetailDialog({ open, date, planned, onOpenChange }) {
|
|
22
27
|
if (!date)
|
|
23
28
|
return null;
|
|
@@ -60,7 +65,7 @@ export function DagDetailDialog({ open, date, planned, onOpenChange }) {
|
|
|
60
65
|
runningIdx += a.cartCount;
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
|
-
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(ResponsiveDialogContent, { size: "xl", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsxs(DialogTitle, { children: ["Dagdetails \u2014 ", NL_DATE.format(date)] }), _jsxs(DialogDescription, { children: [ordersOnDay.length, " bestellingen \u00B7 ", cartRows.length, " karren"] })] }), _jsxs(ResponsiveDialogBody, { children: [_jsx(DayCapacityWarning, { date: date }), _jsx(BezettingCard, { date: date, cartsToday: cartRows.length }), _jsxs(Tabs, { defaultValue: "bestellingen", children: [_jsxs(TabsList, { children: [_jsxs(TabsTrigger, { value: "bestellingen", children: ["Bestellingen (", ordersOnDay.length, ")"] }), _jsxs(TabsTrigger, { value: "karren", children: ["Karren (", cartRows.length, ")"] })] }), _jsx(TabsContent, { value: "bestellingen", className: "mt-4", children: _jsx(BestellingenTab, { orders: ordersOnDay, date: date }) }), _jsx(TabsContent, { value: "karren", className: "mt-4", children: _jsx(KarrenTab, { carts: cartRows }) })] })] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Sluiten" }) })] }) }));
|
|
68
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(ResponsiveDialogContent, { size: "xl", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsxs(DialogTitle, { children: ["Dagdetails \u2014 ", NL_DATE.format(date)] }), _jsxs(DialogDescription, { children: [ordersOnDay.length, " bestellingen \u00B7 ", cartRows.length, " karren"] })] }), _jsxs(ResponsiveDialogBody, { children: [_jsx(DagWerkplekBanner, {}), _jsx(DayCapacityWarning, { date: date }), _jsx(BezettingCard, { date: date, cartsToday: cartRows.length }), _jsxs(Tabs, { defaultValue: "bestellingen", children: [_jsxs(TabsList, { children: [_jsxs(TabsTrigger, { value: "bestellingen", children: ["Bestellingen (", ordersOnDay.length, ")"] }), _jsxs(TabsTrigger, { value: "karren", children: ["Karren (", cartRows.length, ")"] })] }), _jsx(TabsContent, { value: "bestellingen", className: "mt-4", children: _jsx(BestellingenTab, { orders: ordersOnDay, date: date }) }), _jsx(TabsContent, { value: "karren", className: "mt-4", children: _jsx(KarrenTab, { carts: cartRows }) })] })] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Sluiten" }) })] }) }));
|
|
64
69
|
}
|
|
65
70
|
function BezettingCard({ date, cartsToday }) {
|
|
66
71
|
const queryClient = useQueryClient();
|
|
@@ -147,6 +152,7 @@ function OrderRow({ planned: p, cartsToday }) {
|
|
|
147
152
|
const [open, setOpen] = useState(false);
|
|
148
153
|
const [printing, setPrinting] = useState(false);
|
|
149
154
|
const [verzetOpen, setVerzetOpen] = useState(false);
|
|
155
|
+
const werkplek = useWerkplek();
|
|
150
156
|
const source = p.order.source;
|
|
151
157
|
const fetchLines = useServerFn(getOrderLines);
|
|
152
158
|
const linesQuery = useQuery({
|
|
@@ -180,22 +186,36 @@ function OrderRow({ planned: p, cartsToday }) {
|
|
|
180
186
|
unit: null,
|
|
181
187
|
}));
|
|
182
188
|
let printed = 0;
|
|
189
|
+
let pakbonFailed = 0;
|
|
183
190
|
for (let idx = 0; idx < cartTotal; idx++) {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
191
|
+
const cartNumber = `${p.order.orderNumber}-${String(idx + 1).padStart(2, "0")}`;
|
|
192
|
+
try {
|
|
193
|
+
// Centrale pakbonlayout uit de Layout maker; de wachtrij kiest
|
|
194
|
+
// zelf de actieve layout en de bijbehorende printer.
|
|
195
|
+
await printLayoutDocument({
|
|
196
|
+
documenttype: "pakbon",
|
|
197
|
+
documentnaam: `PAK-${p.order.orderNumber}-${String(idx + 1).padStart(2, "0")}`,
|
|
198
|
+
payload: {
|
|
199
|
+
order: {
|
|
200
|
+
id: p.order.id,
|
|
201
|
+
orderNumber: p.order.orderNumber,
|
|
202
|
+
customerName: p.order.customerName,
|
|
203
|
+
country: p.order.country ?? null,
|
|
204
|
+
deliveryDate: p.order.deliveryDate,
|
|
205
|
+
pickDate: pickDateIso,
|
|
206
|
+
cartIndex: idx + 1,
|
|
207
|
+
cartTotal,
|
|
208
|
+
cartNumber,
|
|
209
|
+
lines: pakbonLines,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
printed++;
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
pakbonFailed++;
|
|
217
|
+
console.warn("[print-all] pakbon mislukt", cartNumber, err);
|
|
218
|
+
}
|
|
199
219
|
}
|
|
200
220
|
let deliveryOk = 0;
|
|
201
221
|
let deliveryFailed = 0;
|
|
@@ -219,14 +239,18 @@ function OrderRow({ planned: p, cartsToday }) {
|
|
|
219
239
|
const parts = [`${printed} pakbon${printed === 1 ? "" : "nen"}`];
|
|
220
240
|
if (deliveryOk > 0)
|
|
221
241
|
parts.push(`${deliveryOk} afleverbrief`);
|
|
222
|
-
|
|
242
|
+
if (printed > 0 || deliveryOk > 0) {
|
|
243
|
+
toast.success(`Documenten geprint — ${parts.join(", ")}.`);
|
|
244
|
+
}
|
|
245
|
+
if (pakbonFailed > 0) {
|
|
246
|
+
toast.error(`${pakbonFailed} pakbon kon niet worden geprint.`);
|
|
247
|
+
}
|
|
223
248
|
if (deliveryFailed > 0) {
|
|
224
|
-
toast.error(`${deliveryFailed} afleverbrief kon niet worden
|
|
249
|
+
toast.error(`${deliveryFailed} afleverbrief kon niet worden geprint.`);
|
|
225
250
|
}
|
|
226
251
|
}
|
|
227
252
|
catch (err) {
|
|
228
|
-
|
|
229
|
-
toast.error(msg);
|
|
253
|
+
toast.error(printFoutMelding(err));
|
|
230
254
|
console.error("[print-all]", err);
|
|
231
255
|
}
|
|
232
256
|
finally {
|
|
@@ -243,7 +267,7 @@ function OrderRow({ planned: p, cartsToday }) {
|
|
|
243
267
|
const src = p.order.source === "floriday" ? "floriday" : "manual";
|
|
244
268
|
const soId = p.order.salesOrderId ?? (src === "floriday" ? p.order.id : null);
|
|
245
269
|
return soId ? (_jsx(AutoProcessStatus, { salesOrderId: soId })) : null;
|
|
246
|
-
})(), _jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintAll, disabled: printing, title: "Alle pakbonnen en afleverbrieven van deze bestelling afdrukken", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), printing ? "Bezig…" : "Alle documenten afdrukken"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: (e) => {
|
|
270
|
+
})(), _jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintAll, disabled: printing || !werkplek, title: "Alle pakbonnen en afleverbrieven van deze bestelling afdrukken", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), printing ? "Bezig…" : "Alle documenten afdrukken"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: (e) => {
|
|
247
271
|
e.stopPropagation();
|
|
248
272
|
setVerzetOpen(true);
|
|
249
273
|
}, title: "Ophaaldag of ophaaltijd van deze order wijzigen", children: [_jsx(CalendarClock, { className: "mr-1 h-3.5 w-3.5" }), "Verzetten"] })] })] }), _jsx(VerzetOrderDialog, { open: verzetOpen, orderRef: p.order.orderNumber, carrierTarget: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAIlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAUjE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yEAAyE;IACzE,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,KAAK,IAAI,CAAC;IACxD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AA+DD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,EACL,gBAAgB,EAChB,YAAY,EACZ,UAAU,GACX,EAAE,mBAAmB,+BA0JrB"}
|
|
@@ -2,6 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { Button, Badge, toast } from "@flowselections/core";
|
|
4
4
|
import { ChevronLeft, ChevronRight, Package, Truck, Sprout, Clock, CheckCircle2, Scale, Printer } from "lucide-react";
|
|
5
|
+
import { printFoutMelding } from "../../lib/printing";
|
|
6
|
+
import { WerkplekWaarschuwing, useWerkplek } from "./WerkplekWaarschuwing";
|
|
5
7
|
import { isSameDay, startOfWeek, addDays } from "../../lib/pickDate";
|
|
6
8
|
import { printDeliveryNote, printDeliveryNotesMerged, } from "../../lib/deliveryNotePrint";
|
|
7
9
|
import { useCapacityCheck } from "../../hooks/useCapacityCheck";
|
|
@@ -144,12 +146,17 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayCl
|
|
|
144
146
|
d.setHours(0, 0, 0, 0);
|
|
145
147
|
setCursor(startOfWeek(d));
|
|
146
148
|
};
|
|
147
|
-
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title ?? headerLabel }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: goPrev, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), " Vorige week"] }), _jsx(Button, { variant: "outline", size: "sm", onClick: goToday, children: "Deze week" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: goNext, children: ["Volgende week ", _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsx(SummaryCard, { label: MODE_LABELS[mode].summary, value: totals.leveringen, tone: "default" }), _jsx(SummaryCard, { label: "Verzendklaar", value: totals.verzendklaar, tone: "success" }), _jsx(SummaryCard, { label: "In voorbereiding", value: totals.voorbereiding, tone: "muted" }), _jsx(SummaryCard, { label: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }),
|
|
149
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title ?? headerLabel }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: goPrev, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), " Vorige week"] }), _jsx(Button, { variant: "outline", size: "sm", onClick: goToday, children: "Deze week" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: goNext, children: ["Volgende week ", _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsx(SummaryCard, { label: MODE_LABELS[mode].summary, value: totals.leveringen, tone: "default" }), _jsx(SummaryCard, { label: "Verzendklaar", value: totals.verzendklaar, tone: "success" }), _jsx(SummaryCard, { label: "In voorbereiding", value: totals.voorbereiding, tone: "muted" }), _jsx(SummaryCard, { label: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }), _jsxs("div", { className: "max-h-[520px] space-y-2 overflow-y-auto rounded-lg border bg-muted/20 p-2", children: [showPrintButtons && _jsx(AgendaWerkplekBanner, {}), isLoading ? (_jsx("div", { className: "rounded-lg border bg-card p-10 text-center text-sm text-muted-foreground", children: "Laden\u2026" })) : (days.map((day) => (_jsx(DayRow, { day: day, onOrderClick: onOrderClick, onDayClick: onDayClick, showPrintButtons: showPrintButtons, capacity: mode === "delivery" ? undefined : capacity.byDate.get(toDayKey(day.date)) }, day.date.toISOString()))))] })] }));
|
|
148
150
|
}
|
|
149
151
|
function SummaryCard({ label, value, tone, }) {
|
|
150
152
|
const valueClass = tone === "success" ? "text-green-600" : "text-foreground";
|
|
151
153
|
return (_jsxs("div", { className: "rounded-lg border bg-card p-4", children: [_jsx("div", { className: `text-3xl font-bold ${valueClass}`, children: value }), _jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: label })] }));
|
|
152
154
|
}
|
|
155
|
+
/** Eén melding bovenaan de agenda zolang de werkplek ontbreekt. */
|
|
156
|
+
function AgendaWerkplekBanner() {
|
|
157
|
+
const werkplek = useWerkplek();
|
|
158
|
+
return _jsx(WerkplekWaarschuwing, { werkplek: werkplek });
|
|
159
|
+
}
|
|
153
160
|
function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, capacity, }) {
|
|
154
161
|
const weekdayIdx = (day.date.getDay() + 6) % 7;
|
|
155
162
|
const today = new Date();
|
|
@@ -160,6 +167,7 @@ function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, capacity, })
|
|
|
160
167
|
const printableItems = day.entries
|
|
161
168
|
.filter((e) => e.order.source === "floriday" && e.order.salesOrderId)
|
|
162
169
|
.map((e) => ({ id: e.order.id, salesOrderId: e.order.salesOrderId ?? undefined }));
|
|
170
|
+
const werkplek = useWerkplek();
|
|
163
171
|
const handlePrintDay = async () => {
|
|
164
172
|
if (printingDay || printableItems.length === 0)
|
|
165
173
|
return;
|
|
@@ -174,7 +182,7 @@ function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, capacity, })
|
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
184
|
catch (err) {
|
|
177
|
-
toast.error(err
|
|
185
|
+
toast.error(printFoutMelding(err));
|
|
178
186
|
}
|
|
179
187
|
finally {
|
|
180
188
|
setPrintingDay(false);
|
|
@@ -185,16 +193,19 @@ function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, capacity, })
|
|
|
185
193
|
return;
|
|
186
194
|
setPrintingOrderId(order.id);
|
|
187
195
|
try {
|
|
188
|
-
await printDeliveryNote(order.salesOrderId
|
|
196
|
+
await printDeliveryNote(order.salesOrderId, {
|
|
197
|
+
documentnaam: `AFL-${order.orderNumber}`,
|
|
198
|
+
});
|
|
199
|
+
toast.success(`Afleverbrief ${order.orderNumber} naar de printer gestuurd.`);
|
|
189
200
|
}
|
|
190
201
|
catch (err) {
|
|
191
|
-
toast.error(err
|
|
202
|
+
toast.error(printFoutMelding(err));
|
|
192
203
|
}
|
|
193
204
|
finally {
|
|
194
205
|
setPrintingOrderId(null);
|
|
195
206
|
}
|
|
196
207
|
};
|
|
197
|
-
return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-6 px-4 py-4 sm:px-6", children: [_jsxs("div", { className: "w-20 shrink-0", children: [_jsx("div", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: WEEKDAY_LABELS[weekdayIdx] }), _jsx("div", { className: "mt-1 text-3xl font-bold leading-none", children: day.date.getDate() }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [MONTHS_NL_SHORT[day.date.getMonth()], "."] })] }), _jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-6", children: [_jsx(Stat, { icon: _jsx(Package, { className: "h-4 w-4 text-slate-500" }), bg: "bg-slate-100", value: day.bestellingen, label: "bestellingen" }), _jsx(Stat, { icon: _jsx(Truck, { className: "h-4 w-4 text-amber-600" }), bg: "bg-amber-100", value: day.karren, label: "karren" }), _jsx(Stat, { icon: _jsx(Sprout, { className: "h-4 w-4 text-green-600" }), bg: "bg-green-100", value: day.planten, label: "planten" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [day.movedEarlierOrderIds.size > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat vervroegd is ingepland door Pickverdeling.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.movedEarlierOrderIds.size, " vervroegd"] })), day.verzendklaar > 0 && (_jsxs(Badge, { className: "bg-green-500/15 text-green-700 hover:bg-green-500/15", variant: "secondary", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), day.verzendklaar, " verzendklaar"] })), day.voorbereiding > 0 && (_jsxs(Badge, { className: "bg-blue-500/10 text-blue-700 hover:bg-blue-500/10", variant: "secondary", children: [_jsx(Clock, { className: "mr-1 h-3.5 w-3.5" }), day.voorbereiding, " in voorbereiding"] })), showPrintButtons && printableItems.length > 0 && (_jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintDay, disabled: printingDay, children: [_jsx(Printer, { className: "mr-1 h-4 w-4" }), printingDay ? "Printen…" : `Print afleverbrieven (${printableItems.length})`] })), onDayClick && day.bestellingen > 0 && (_jsx(Button, { size: "sm", variant: "outline", onClick: () => onDayClick(day.date), children: "Dagdetails" }))] })] }), _jsx(CapacityWarning, { day: capacity, className: "mx-4 mb-4 sm:mx-6" })] }));
|
|
208
|
+
return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-6 px-4 py-4 sm:px-6", children: [_jsxs("div", { className: "w-20 shrink-0", children: [_jsx("div", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: WEEKDAY_LABELS[weekdayIdx] }), _jsx("div", { className: "mt-1 text-3xl font-bold leading-none", children: day.date.getDate() }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [MONTHS_NL_SHORT[day.date.getMonth()], "."] })] }), _jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-6", children: [_jsx(Stat, { icon: _jsx(Package, { className: "h-4 w-4 text-slate-500" }), bg: "bg-slate-100", value: day.bestellingen, label: "bestellingen" }), _jsx(Stat, { icon: _jsx(Truck, { className: "h-4 w-4 text-amber-600" }), bg: "bg-amber-100", value: day.karren, label: "karren" }), _jsx(Stat, { icon: _jsx(Sprout, { className: "h-4 w-4 text-green-600" }), bg: "bg-green-100", value: day.planten, label: "planten" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [day.movedEarlierOrderIds.size > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat vervroegd is ingepland door Pickverdeling.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.movedEarlierOrderIds.size, " vervroegd"] })), day.verzendklaar > 0 && (_jsxs(Badge, { className: "bg-green-500/15 text-green-700 hover:bg-green-500/15", variant: "secondary", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), day.verzendklaar, " verzendklaar"] })), day.voorbereiding > 0 && (_jsxs(Badge, { className: "bg-blue-500/10 text-blue-700 hover:bg-blue-500/10", variant: "secondary", children: [_jsx(Clock, { className: "mr-1 h-3.5 w-3.5" }), day.voorbereiding, " in voorbereiding"] })), showPrintButtons && printableItems.length > 0 && (_jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintDay, disabled: printingDay || !werkplek, children: [_jsx(Printer, { className: "mr-1 h-4 w-4" }), printingDay ? "Printen…" : `Print afleverbrieven (${printableItems.length})`] })), onDayClick && day.bestellingen > 0 && (_jsx(Button, { size: "sm", variant: "outline", onClick: () => onDayClick(day.date), children: "Dagdetails" }))] })] }), _jsx(CapacityWarning, { day: capacity, className: "mx-4 mb-4 sm:mx-6" })] }));
|
|
198
209
|
}
|
|
199
210
|
function Stat({ icon, bg, value, label, }) {
|
|
200
211
|
return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: `grid h-8 w-8 place-items-center rounded-full ${bg}`, children: icon }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-bold leading-none", children: value }), _jsx("div", { className: "text-xs text-muted-foreground", children: label })] })] }));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Leest de ingestelde werkplek client-side (SSR-veilig). */
|
|
2
|
+
export declare function useWerkplek(): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Eén melding bovenaan een printscherm zolang er geen werkplek is ingesteld.
|
|
5
|
+
* Printknoppen zijn dan uitgeschakeld, zodat er geen fout per printactie komt.
|
|
6
|
+
*/
|
|
7
|
+
export declare function WerkplekWaarschuwing({ werkplek }: {
|
|
8
|
+
werkplek: string | null;
|
|
9
|
+
}): import("react").JSX.Element | null;
|
|
10
|
+
//# sourceMappingURL=WerkplekWaarschuwing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WerkplekWaarschuwing.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WerkplekWaarschuwing.tsx"],"names":[],"mappings":"AAIA,6DAA6D;AAC7D,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAa3C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAW7E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { AlertTriangle } from "lucide-react";
|
|
4
|
+
import { getWerkplek } from "../../lib/printing";
|
|
5
|
+
/** Leest de ingestelde werkplek client-side (SSR-veilig). */
|
|
6
|
+
export function useWerkplek() {
|
|
7
|
+
const [werkplek, setWerkplekState] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setWerkplekState(getWerkplek());
|
|
10
|
+
const onStorage = () => setWerkplekState(getWerkplek());
|
|
11
|
+
window.addEventListener("storage", onStorage);
|
|
12
|
+
window.addEventListener("focus", onStorage);
|
|
13
|
+
return () => {
|
|
14
|
+
window.removeEventListener("storage", onStorage);
|
|
15
|
+
window.removeEventListener("focus", onStorage);
|
|
16
|
+
};
|
|
17
|
+
}, []);
|
|
18
|
+
return werkplek;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Eén melding bovenaan een printscherm zolang er geen werkplek is ingesteld.
|
|
22
|
+
* Printknoppen zijn dan uitgeschakeld, zodat er geen fout per printactie komt.
|
|
23
|
+
*/
|
|
24
|
+
export function WerkplekWaarschuwing({ werkplek }) {
|
|
25
|
+
if (werkplek)
|
|
26
|
+
return null;
|
|
27
|
+
return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), _jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Geen werkplek ingesteld." }), " Printen is uitgeschakeld. Stel de werkplek (pickstation- of computernaam) in bij ", _jsx("strong", { children: "Instellingen" }), "."] })] }));
|
|
28
|
+
}
|