@flowselections/floriday-afhandeling-module 1.0.31 → 1.0.33

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.
Files changed (66) hide show
  1. package/dist-lib/components/afhandeling/AutoProcessStatus.js +1 -1
  2. package/dist-lib/components/afhandeling/ControleLijstPrint.d.ts +6 -6
  3. package/dist-lib/components/afhandeling/ControleLijstPrint.d.ts.map +1 -1
  4. package/dist-lib/components/afhandeling/ControleLijstPrint.js +73 -48
  5. package/dist-lib/components/afhandeling/ControlePage.d.ts.map +1 -1
  6. package/dist-lib/components/afhandeling/ControlePage.js +47 -14
  7. package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
  8. package/dist-lib/components/afhandeling/DagDetailDialog.js +48 -24
  9. package/dist-lib/components/afhandeling/VervoerdersPage.d.ts +8 -1
  10. package/dist-lib/components/afhandeling/VervoerdersPage.d.ts.map +1 -1
  11. package/dist-lib/components/afhandeling/VervoerdersPage.js +17 -2
  12. package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
  13. package/dist-lib/components/afhandeling/WeekAgendaView.js +16 -5
  14. package/dist-lib/components/afhandeling/WerkplekWaarschuwing.d.ts +10 -0
  15. package/dist-lib/components/afhandeling/WerkplekWaarschuwing.d.ts.map +1 -0
  16. package/dist-lib/components/afhandeling/WerkplekWaarschuwing.js +28 -0
  17. package/dist-lib/components/pickstation/PakbonTemplate.js +70 -70
  18. package/dist-lib/components/pickstation/printDocuments.d.ts +9 -2
  19. package/dist-lib/components/pickstation/printDocuments.d.ts.map +1 -1
  20. package/dist-lib/components/pickstation/printDocuments.js +8 -52
  21. package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -1
  22. package/dist-lib/components/settings/AfhandelingSettingsCard.js +12 -1
  23. package/dist-lib/hooks/useEngineTasks.js +1 -1
  24. package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
  25. package/dist-lib/hooks/useOrderPlanning.js +32 -14
  26. package/dist-lib/integrations/supabase/auth-middleware.d.ts +695 -128
  27. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  28. package/dist-lib/integrations/supabase/client.server.d.ts +695 -128
  29. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  30. package/dist-lib/integrations/supabase/{client.d.ts → moduleClient.d.ts} +697 -129
  31. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -0
  32. package/dist-lib/integrations/supabase/moduleClient.js +38 -0
  33. package/dist-lib/integrations/supabase/types.d.ts +727 -155
  34. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  35. package/dist-lib/integrations/supabase/types.js +3 -0
  36. package/dist-lib/lib/afhandelingSettings.functions.d.ts +1390 -256
  37. package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
  38. package/dist-lib/lib/carrierSignupMail.server.js +26 -26
  39. package/dist-lib/lib/carriers.functions.d.ts +3475 -640
  40. package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
  41. package/dist-lib/lib/cartAssignments.functions.d.ts +3475 -640
  42. package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
  43. package/dist-lib/lib/cartControl.functions.d.ts +6950 -1280
  44. package/dist-lib/lib/cartControl.functions.d.ts.map +1 -1
  45. package/dist-lib/lib/deliveryNotePrint.d.ts +14 -6
  46. package/dist-lib/lib/deliveryNotePrint.d.ts.map +1 -1
  47. package/dist-lib/lib/deliveryNotePrint.js +61 -14
  48. package/dist-lib/lib/floriday.functions.d.ts +695 -128
  49. package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
  50. package/dist-lib/lib/floridayAutoProcess.js +1 -1
  51. package/dist-lib/lib/logisticsEngine/capacity.js +1 -1
  52. package/dist-lib/lib/logisticsEngine/emitQueue.d.ts +20 -0
  53. package/dist-lib/lib/logisticsEngine/emitQueue.d.ts.map +1 -0
  54. package/dist-lib/lib/logisticsEngine/emitQueue.js +88 -0
  55. package/dist-lib/lib/logisticsEngine/engine.js +1 -1
  56. package/dist-lib/lib/logisticsEngine/reschedule.js +1 -1
  57. package/dist-lib/lib/logisticsEngine/staffPlanning.js +1 -1
  58. package/dist-lib/lib/printing.d.ts +56 -0
  59. package/dist-lib/lib/printing.d.ts.map +1 -0
  60. package/dist-lib/lib/printing.js +209 -0
  61. package/package.json +3 -7
  62. package/dist-lib/integrations/supabase/auth-attacher.d.ts +0 -2
  63. package/dist-lib/integrations/supabase/auth-attacher.d.ts.map +0 -1
  64. package/dist-lib/integrations/supabase/auth-attacher.js +0 -12
  65. package/dist-lib/integrations/supabase/client.d.ts.map +0 -1
  66. 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/client";
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
- /** Printbare controlelijst — één regel per kar met checkbox en opmerkingveld. */
4
- export declare function ControleLijstPrint({ carts, onClose, lang, }: {
5
- carts: ControlCart[];
6
- onClose: () => void;
7
- lang?: PickstationLang;
8
- }): import("react").ReactPortal | null;
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":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,2BAA2B,CAAC;AAgCnC,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,OAAO,EACP,IAAW,GACZ,EAAE;IACD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,sCAoJA"}
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
- /** Printbare controlelijst — één regel per kar met checkbox en opmerkingveld. */
32
- export function ControleLijstPrint({ carts, onClose, lang = "nl", }) {
26
+ function esc(value) {
27
+ return String(value ?? "")
28
+ .replace(/&/g, "&")
29
+ .replace(/</g, "&lt;")
30
+ .replace(/>/g, "&gt;");
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 sortedCarts = carts
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 content = (_jsxs("div", { id: "controle-print-root", className: "fixed inset-0 z-[100] bg-white overflow-auto", lang: lang, children: [_jsxs("div", { className: "print:hidden sticky top-0 flex items-center justify-between p-3 border-b bg-white", children: [_jsx("div", { className: "font-semibold", children: t.checklistPrintView }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: () => window.print(), children: [_jsx(Printer, { className: "h-4 w-4 mr-2" }), t.reprint] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: onClose, children: [_jsx(X, { className: "h-4 w-4 mr-2" }), t.close] })] })] }), _jsxs("div", { className: "print-sheet p-8 print:p-0 max-w-[210mm] mx-auto text-black", children: [_jsxs("div", { className: "flex items-baseline justify-between border-b border-black pb-2 mb-4", children: [_jsx("h1", { className: "text-2xl font-bold", children: t.checklistTitle }), _jsx("div", { className: "text-sm", children: today })] }), _jsxs("div", { className: "text-sm mb-3", children: [t.totalCarts, ": ", _jsx("strong", { children: carts.length })] }), _jsxs("table", { className: "w-full text-[11px] border-collapse", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-black", children: [_jsx("th", { className: "text-left py-1 pr-2", children: t.colKarnr }), _jsx("th", { className: "text-right py-1 pr-2", children: t.colFusten }), _jsx("th", { className: "text-left py-1 pr-2", children: t.colLand }), _jsx("th", { className: "text-left py-1 pr-2", children: t.colKlaarzetten }), _jsx("th", { className: "text-left py-1 pr-2", children: t.colStatus })] }) }), _jsxs("tbody", { children: [sortedCarts.map(({ cart: c, klaarzet }) => (_jsxs("tr", { className: "border-b border-gray-300", children: [_jsx("td", { className: "py-2 pr-2 font-mono font-bold whitespace-nowrap", children: c.cartNumber ?? "—" }), _jsx("td", { className: "py-2 pr-2 text-right whitespace-nowrap", children: c.cratesOnCart ?? "—" }), _jsx("td", { className: "py-2 pr-2 whitespace-nowrap font-semibold", children: countryCode(c.country) ?? c.country ?? "—" }), _jsx("td", { className: "py-2 pr-2 whitespace-nowrap font-semibold", children: klaarzet.label }), _jsx("td", { className: "py-2 pr-2 whitespace-nowrap", children: statusLabel(c.status, c.printedCount) })] }, `${c.orderSource}#${c.orderId}#${c.cartIndex}`))), sortedCarts.length === 0 && (_jsx("tr", { children: _jsx("td", { colSpan: 5, className: "py-6 text-center text-gray-500", children: t.noCartsToday }) }))] })] }), _jsxs("div", { className: "mt-6 text-[11px]", children: [_jsxs("div", { children: [t.checkedBy, ": ", _jsx("span", { className: "inline-block border-b border-black w-64" })] }), _jsxs("div", { className: "mt-2", children: [t.dateTime, ": ", _jsx("span", { className: "inline-block border-b border-black w-64" })] }), _jsxs("div", { className: "mt-2", children: [t.signature, ": ", _jsx("span", { className: "inline-block border-b border-black w-64" })] })] })] }), _jsx("style", { children: `
76
- @media print {
77
- @page { size: A4 portrait; margin: 12mm; }
78
- html, body { background: #fff !important; margin: 0 !important; padding: 0 !important; }
79
- body > *:not(#controle-print-portal) { display: none !important; }
80
- #controle-print-portal, #controle-print-root {
81
- position: static !important;
82
- overflow: visible !important;
83
- height: auto !important;
84
- width: auto !important;
85
- background: #fff !important;
86
- }
87
- .print-sheet {
88
- max-width: none !important;
89
- padding: 0 !important;
90
- margin: 0 !important;
91
- }
92
- table { page-break-inside: auto; }
93
- tr { page-break-inside: avoid; page-break-after: auto; }
94
- thead { display: table-header-group; }
95
- }
96
- ` })] }));
97
- if (typeof document === "undefined")
98
- return null;
99
- let portalNode = document.getElementById("controle-print-portal");
100
- if (!portalNode) {
101
- portalNode = document.createElement("div");
102
- portalNode.id = "controle-print-portal";
103
- document.body.appendChild(portalNode);
104
- }
105
- return createPortal(content, portalNode);
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":"AA4GA,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,+BA8uBpE"}
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/client";
4
- import { Button, Card, Checkbox, Dialog, DialogDescription, DialogTitle, Input, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Textarea, Badge, toast, } from "@flowselections/core";
5
- import { Printer, CheckCircle2, AlertTriangle, History } from "lucide-react";
3
+ import { supabase } from "../../integrations/supabase/moduleClient";
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
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 { ControleLijstPrint } from "./ControleLijstPrint";
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 [showPrint, setShowPrint] = useState(false);
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);
@@ -368,6 +371,16 @@ export function ControlePage({ onExit } = {}) {
368
371
  const checkedCount = carts.filter((c) => checked.has(controlCartKey(c))).length;
369
372
  return { total, printed, checked: checkedCount };
370
373
  }, [carts, checked]);
374
+ // Paginering
375
+ const [pageSize, setPageSize] = useState(20);
376
+ const [page, setPage] = useState(1);
377
+ const pageCount = Math.max(1, Math.ceil(carts.length / pageSize));
378
+ const currentPage = Math.min(page, pageCount);
379
+ useEffect(() => {
380
+ if (page > pageCount)
381
+ setPage(pageCount);
382
+ }, [pageCount, page]);
383
+ const pagedCarts = useMemo(() => carts.slice((currentPage - 1) * pageSize, currentPage * pageSize), [carts, currentPage, pageSize]);
371
384
  const pendingProposals = pendingProposal?.proposals ?? [];
372
385
  const pendingBlocked = pendingProposal?.blocked ?? [];
373
386
  const pendingNotReadyCount = pendingProposals.length + pendingBlocked.length;
@@ -403,20 +416,40 @@ export function ControlePage({ onExit } = {}) {
403
416
  supabase.removeChannel(channel);
404
417
  };
405
418
  }, [qc]);
406
- 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", onClick: () => setShowPrint(true), children: [_jsx(Printer, { className: "h-4 w-4 mr-2" }), "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 })] })] }), _jsx(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)))
407
- ? true
408
- : carts.some((c) => checked.has(controlCartKey(c)))
409
- ? "indeterminate"
410
- : false, onCheckedChange: (v) => toggleAll(!!v) }) }), _jsx(TableHead, { children: "Ordernummer" }), _jsx(TableHead, { children: "Ophaaldatum" }), _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." }) })), carts.map((c) => {
411
- const k = controlCartKey(c);
412
- return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Checkbox, { checked: checked.has(k), onCheckedChange: (v) => toggle(k, !!v) }) }), _jsx(TableCell, { className: "font-mono font-semibold", children: (c.orderNumbers?.length ?? 0) > 0 ? (_jsx("div", { className: "flex flex-col gap-0.5", children: c.orderNumbers.map((n) => (_jsx("span", { children: n }, n))) })) : (c.orderNumber || "—") }), _jsx(TableCell, { children: fmtDate(c.pickupDate) }), _jsx(TableCell, { children: (c.printedCount ?? 0) > 0 ? (_jsx(Badge, { variant: "secondary", children: "Ja" })) : (_jsx(Badge, { variant: "outline", children: "Nee" })) })] }, k));
413
- })] })] }) }), _jsxs("div", { className: "max-w-xl", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium", children: "Opmerkingen bij deze controle" }), _jsx("span", { className: "text-xs text-muted-foreground", "aria-live": "polite", children: savingState === "saving"
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)))
437
+ ? true
438
+ : carts.some((c) => checked.has(controlCartKey(c)))
439
+ ? "indeterminate"
440
+ : false, onCheckedChange: (v) => toggleAll(!!v) }) }), _jsx(TableHead, { children: "Ordernummer" }), _jsx(TableHead, { children: "Ophaaldatum" }), _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) => {
441
+ const k = controlCartKey(c);
442
+ return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Checkbox, { checked: checked.has(k), onCheckedChange: (v) => toggle(k, !!v) }) }), _jsx(TableCell, { className: "font-mono font-semibold", children: (c.orderNumbers?.length ?? 0) > 0 ? (_jsx("div", { className: "flex flex-col gap-0.5", children: c.orderNumbers.map((n) => (_jsx("span", { children: n }, n))) })) : (c.orderNumber || "—") }), _jsx(TableCell, { children: fmtDate(c.pickupDate) }), _jsx(TableCell, { children: (c.printedCount ?? 0) > 0 ? (_jsx(Badge, { variant: "secondary", children: "Ja" })) : (_jsx(Badge, { variant: "outline", children: "Nee" })) })] }, k));
443
+ })] })] }), 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) => {
444
+ setPageSize(Number(v));
445
+ setPage(1);
446
+ }, children: [_jsx(SelectTrigger, { className: "h-8 w-[80px]", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: [10, 20, 50, 100].map((n) => (_jsx(SelectItem, { value: String(n), children: n }, n))) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "icon", className: "h-8 w-8", "aria-label": "Vorige pagina", disabled: currentPage <= 1, onClick: () => setPage((p) => Math.max(1, p - 1)), children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsxs("span", { className: "tabular-nums", children: [currentPage, " / ", pageCount] }), _jsx(Button, { variant: "outline", size: "icon", className: "h-8 w-8", "aria-label": "Volgende pagina", disabled: currentPage >= pageCount, onClick: () => setPage((p) => Math.min(pageCount, p + 1)), children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] })] })] }))] }), _jsxs("div", { className: "max-w-xl", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium", children: "Opmerkingen bij deze controle" }), _jsx("span", { className: "text-xs text-muted-foreground", "aria-live": "polite", children: savingState === "saving"
414
447
  ? "Opslaan…"
415
448
  : savingState === "saved"
416
449
  ? "Voortgang automatisch opgeslagen"
417
450
  : lastSavedRef.current && notes === lastSavedRef.current
418
451
  ? "Concept bewaard"
419
- : "" })] }), _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 ?? [] }), showPrint && (_jsx(ControleLijstPrint, { carts: carts, onClose: () => setShowPrint(false) })), _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: () => {
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: () => {
420
453
  setResult(null);
421
454
  if (onExit)
422
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;AAID,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,oBAAoB,sCA8E1F"}
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 { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
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 { renderPakbonHtml } from "../pickstation/PakbonTemplate";
11
- import { printHtml } from "../pickstation/printDocuments";
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 html = renderPakbonHtml({
185
- id: `${p.order.id}#${idx}`,
186
- orderNumber: p.order.orderNumber,
187
- customerName: p.order.customerName,
188
- country: p.order.country ?? null,
189
- deliveryDate: p.order.deliveryDate,
190
- pickDate: pickDateIso,
191
- cartIndex: idx + 1,
192
- cartTotal,
193
- cratesOnCart: null,
194
- cartNumber: `${p.order.orderNumber}-${String(idx + 1).padStart(2, "0")}`,
195
- lines: pakbonLines,
196
- }, "nl");
197
- await printHtml(html);
198
- printed++;
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
- toast.success(`Documenten verstuurd naar printer — ${parts.join(", ")}.`);
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 opgehaald.`);
249
+ toast.error(`${deliveryFailed} afleverbrief kon niet worden geprint.`);
225
250
  }
226
251
  }
227
252
  catch (err) {
228
- const msg = err instanceof Error ? err.message : "Printen mislukt";
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,2 +1,9 @@
1
- export declare function VervoerdersPage(): import("react").JSX.Element;
1
+ /**
2
+ * Bewerken gebeurt via een searchparam (?id=<uuid>) i.p.v. een dynamisch
3
+ * URL-segment, zodat het ook werkt in hosts/shells die alleen statische
4
+ * module-routes registreren.
5
+ */
6
+ export declare function VervoerdersPage({ carrierId }?: {
7
+ carrierId?: string | null;
8
+ }): import("react").JSX.Element;
2
9
  //# sourceMappingURL=VervoerdersPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VervoerdersPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/VervoerdersPage.tsx"],"names":[],"mappings":"AA8BA,wBAAgB,eAAe,gCA2L9B"}
1
+ {"version":3,"file":"VervoerdersPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/VervoerdersPage.tsx"],"names":[],"mappings":"AA+BA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,SAAS,EAAE,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,+BAShF"}
@@ -9,7 +9,22 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
9
9
  import { toServerFnError } from "../../lib/serverFnError";
10
10
  import { listCarriers, deleteCarrier, reorderCarriers } from "../../lib/carriers.functions";
11
11
  import { carrierLeadDaysFromMoments } from "../../lib/carrierPlanning";
12
- export function VervoerdersPage() {
12
+ import { VervoerderForm } from "./VervoerderForm";
13
+ /**
14
+ * Bewerken gebeurt via een searchparam (?id=<uuid>) i.p.v. een dynamisch
15
+ * URL-segment, zodat het ook werkt in hosts/shells die alleen statische
16
+ * module-routes registreren.
17
+ */
18
+ export function VervoerdersPage({ carrierId } = {}) {
19
+ const idFromUrl = carrierId ??
20
+ (typeof window !== "undefined"
21
+ ? new URLSearchParams(window.location.search).get("id")
22
+ : null);
23
+ if (idFromUrl)
24
+ return _jsx(VervoerderForm, { carrierId: idFromUrl });
25
+ return _jsx(VervoerdersLijst, {});
26
+ }
27
+ function VervoerdersLijst() {
13
28
  const queryClient = useQueryClient();
14
29
  const fetchList = useServerFn(listCarriers);
15
30
  const removeCarrier = useServerFn(deleteCarrier);
@@ -54,5 +69,5 @@ export function VervoerdersPage() {
54
69
  [ids[index], ids[target]] = [ids[target], ids[index]];
55
70
  reorderMutation.mutate(ids);
56
71
  };
57
- return (_jsxs("div", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Vervoerders" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Beheer vervoerders en hun verzendtarieven per land." })] }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/afhandeling/vervoerders/nieuw", children: [_jsx(Plus, { className: "w-4 h-4 mr-1" }), "Vervoerder toevoegen"] }) })] }), _jsx("div", { className: "border rounded-md bg-card", children: isLoading ? (_jsx("div", { className: "p-12 text-center text-muted-foreground", children: "Laden..." })) : error ? (_jsxs("div", { className: "p-12 text-center space-y-3", children: [_jsxs("div", { className: "text-destructive", children: ["Fout bij laden: ", error.message] }), _jsx(Button, { variant: "outline", onClick: () => refetch(), children: "Opnieuw proberen" })] })) : carriers.length === 0 ? (_jsxs("div", { className: "p-12 text-center space-y-3", children: [_jsx(Truck, { className: "w-10 h-10 mx-auto text-muted-foreground" }), _jsx("div", { className: "font-medium", children: "Nog geen vervoerders" }), _jsx("div", { className: "text-sm text-muted-foreground", children: "Voeg een vervoerder toe om verzendtarieven in te stellen." }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/afhandeling/vervoerders/nieuw", children: [_jsx(Plus, { className: "w-4 h-4 mr-1" }), "Vervoerder toevoegen"] }) })] })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-32", children: "Prioriteit" }), _jsx(TableHead, { children: "Bedrijfsnaam" }), _jsx(TableHead, { children: "Contactpersoon" }), _jsx(TableHead, { children: "E-mail" }), _jsx(TableHead, { children: "Telefoon" }), _jsx(TableHead, { children: "Levertijd" }), _jsx(TableHead, { children: "Landen" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsx(TableBody, { children: carriers.map((c, index) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "w-6 text-sm font-medium tabular-nums text-muted-foreground", children: index + 1 }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => move(index, -1), disabled: index === 0 || reorderMutation.isPending, "aria-label": "Hoger", children: _jsx(ArrowUp, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => move(index, 1), disabled: index === carriers.length - 1 || reorderMutation.isPending, "aria-label": "Lager", children: _jsx(ArrowDown, { className: "w-4 h-4" }) })] }) }), _jsx(TableCell, { className: "font-medium", children: c.name }), _jsx(TableCell, { children: c.contact_person ?? "—" }), _jsx(TableCell, { children: c.email ?? "—" }), _jsx(TableCell, { children: c.phone ?? "—" }), _jsxs(TableCell, { children: [carrierLeadDaysFromMoments(c.pickup_moments), " werkdagen"] }), _jsx(TableCell, { children: c.rate_count }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsx(Link, { to: "/afhandeling/vervoerders/$carrierId/bewerken", params: { carrierId: c.id }, children: _jsx(Pencil, { className: "w-4 h-4" }) }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setDeletingId(c.id), className: "text-destructive hover:text-destructive", children: _jsx(Trash2, { className: "w-4 h-4" }) })] }) })] }, c.id))) })] })) }), _jsx(AlertDialog, { open: !!deletingId, onOpenChange: (o) => !o && setDeletingId(null), children: _jsxs(ResponsiveAlertDialogContent, { size: "sm", children: [_jsx(ResponsiveAlertDialogHeader, { children: _jsx(AlertDialogTitle, { children: "Vervoerder verwijderen?" }) }), _jsx(ResponsiveAlertDialogBody, { children: _jsx(AlertDialogDescription, { children: "Deze actie kan niet ongedaan gemaakt worden. Alle verzendtarieven worden ook verwijderd." }) }), _jsxs(ResponsiveAlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Annuleren" }), _jsx(AlertDialogAction, { onClick: () => deletingId && deleteMutation.mutate(deletingId), className: "bg-destructive text-destructive-foreground hover:bg-destructive/90", children: "Verwijderen" })] })] }) })] }));
72
+ return (_jsxs("div", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Vervoerders" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Beheer vervoerders en hun verzendtarieven per land." })] }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/afhandeling/vervoerders/nieuw", children: [_jsx(Plus, { className: "w-4 h-4 mr-1" }), "Vervoerder toevoegen"] }) })] }), _jsx("div", { className: "border rounded-md bg-card", children: isLoading ? (_jsx("div", { className: "p-12 text-center text-muted-foreground", children: "Laden..." })) : error ? (_jsxs("div", { className: "p-12 text-center space-y-3", children: [_jsxs("div", { className: "text-destructive", children: ["Fout bij laden: ", error.message] }), _jsx(Button, { variant: "outline", onClick: () => refetch(), children: "Opnieuw proberen" })] })) : carriers.length === 0 ? (_jsxs("div", { className: "p-12 text-center space-y-3", children: [_jsx(Truck, { className: "w-10 h-10 mx-auto text-muted-foreground" }), _jsx("div", { className: "font-medium", children: "Nog geen vervoerders" }), _jsx("div", { className: "text-sm text-muted-foreground", children: "Voeg een vervoerder toe om verzendtarieven in te stellen." }), _jsx(Button, { asChild: true, children: _jsxs(Link, { to: "/afhandeling/vervoerders/nieuw", children: [_jsx(Plus, { className: "w-4 h-4 mr-1" }), "Vervoerder toevoegen"] }) })] })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-32", children: "Prioriteit" }), _jsx(TableHead, { children: "Bedrijfsnaam" }), _jsx(TableHead, { children: "Contactpersoon" }), _jsx(TableHead, { children: "E-mail" }), _jsx(TableHead, { children: "Telefoon" }), _jsx(TableHead, { children: "Levertijd" }), _jsx(TableHead, { children: "Landen" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsx(TableBody, { children: carriers.map((c, index) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "w-6 text-sm font-medium tabular-nums text-muted-foreground", children: index + 1 }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => move(index, -1), disabled: index === 0 || reorderMutation.isPending, "aria-label": "Hoger", children: _jsx(ArrowUp, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => move(index, 1), disabled: index === carriers.length - 1 || reorderMutation.isPending, "aria-label": "Lager", children: _jsx(ArrowDown, { className: "w-4 h-4" }) })] }) }), _jsx(TableCell, { className: "font-medium", children: c.name }), _jsx(TableCell, { children: c.contact_person ?? "—" }), _jsx(TableCell, { children: c.email ?? "—" }), _jsx(TableCell, { children: c.phone ?? "—" }), _jsxs(TableCell, { children: [carrierLeadDaysFromMoments(c.pickup_moments), " werkdagen"] }), _jsx(TableCell, { children: c.rate_count }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsx(Link, { to: "/afhandeling/vervoerders", search: { id: c.id }, children: _jsx(Pencil, { className: "w-4 h-4" }) }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setDeletingId(c.id), className: "text-destructive hover:text-destructive", children: _jsx(Trash2, { className: "w-4 h-4" }) })] }) })] }, c.id))) })] })) }), _jsx(AlertDialog, { open: !!deletingId, onOpenChange: (o) => !o && setDeletingId(null), children: _jsxs(ResponsiveAlertDialogContent, { size: "sm", children: [_jsx(ResponsiveAlertDialogHeader, { children: _jsx(AlertDialogTitle, { children: "Vervoerder verwijderen?" }) }), _jsx(ResponsiveAlertDialogBody, { children: _jsx(AlertDialogDescription, { children: "Deze actie kan niet ongedaan gemaakt worden. Alle verzendtarieven worden ook verwijderd." }) }), _jsxs(ResponsiveAlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Annuleren" }), _jsx(AlertDialogAction, { onClick: () => deletingId && deleteMutation.mutate(deletingId), className: "bg-destructive text-destructive-foreground hover:bg-destructive/90", children: "Verwijderen" })] })] }) })] }));
58
73
  }
@@ -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;AAElE,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,+BAyJrB"}
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"}