@flowselections/floriday-afhandeling-module 1.0.48 → 1.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/afhandeling/AutoProcessStatus.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/AutoProcessStatus.js +4 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.js +173 -39
- package/dist-lib/components/afhandeling/NuVersturenButton.d.ts +5 -0
- package/dist-lib/components/afhandeling/NuVersturenButton.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/NuVersturenButton.js +56 -0
- package/dist-lib/hooks/useOrderBuffers.d.ts +6 -0
- package/dist-lib/hooks/useOrderBuffers.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderBuffers.js +21 -0
- package/dist-lib/index.d.ts +0 -2
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +0 -2
- package/dist-lib/integrations/supabase/moduleClient.d.ts +4 -31315
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +3553 -87
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.js +2 -1
- package/dist-lib/lib/authGateway.server.d.ts +2 -0
- package/dist-lib/lib/authGateway.server.d.ts.map +1 -1
- package/dist-lib/lib/authGateway.server.js +2 -2
- package/dist-lib/lib/cartAssignments.functions.d.ts +39 -3
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.js +91 -33
- package/dist-lib/lib/floridayAutoProcess.d.ts +1 -1
- package/dist-lib/lib/floridayAutoProcess.d.ts.map +1 -1
- package/dist-lib/lib/floridayFulfillmentSend.server.d.ts +31 -0
- package/dist-lib/lib/floridayFulfillmentSend.server.d.ts.map +1 -0
- package/dist-lib/lib/floridayFulfillmentSend.server.js +83 -0
- package/dist-lib/lib/floridayLoading.functions.d.ts +93 -0
- package/dist-lib/lib/floridayLoading.functions.d.ts.map +1 -0
- package/dist-lib/lib/floridayLoading.functions.js +339 -0
- package/dist-lib/lib/orderFulfilment.functions.d.ts.map +1 -1
- package/dist-lib/lib/orderFulfilment.functions.js +17 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutoProcessStatus.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/AutoProcessStatus.tsx"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oEAAoE;IACpE,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAeD,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,QAAQ,EACR,eAAe,EACf,kBAAyB,EACzB,OAAe,GAChB,EAAE,KAAK,+
|
|
1
|
+
{"version":3,"file":"AutoProcessStatus.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/AutoProcessStatus.tsx"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oEAAoE;IACpE,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAeD,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,QAAQ,EACR,eAAe,EACf,kBAAyB,EACzB,OAAe,GAChB,EAAE,KAAK,+BAuLP"}
|
|
@@ -113,6 +113,9 @@ export function AutoProcessStatus({ salesOrderId, orderRef, autoProcessDate, all
|
|
|
113
113
|
else if (status === "waiting_for_delivery_order") {
|
|
114
114
|
badge = (_jsxs(Badge, { variant: "outline", className: "gap-1", children: [_jsx(Clock, { className: "h-3 w-3" }), " Wacht op Floriday delivery-order"] }));
|
|
115
115
|
}
|
|
116
|
+
else if (status === "waiting_for_afhandeling") {
|
|
117
|
+
badge = (_jsxs(Badge, { variant: "outline", className: "gap-1", children: [_jsx(Clock, { className: "h-3 w-3" }), " Klaar voor belading"] }));
|
|
118
|
+
}
|
|
116
119
|
else if (status === "ready_to_fulfill") {
|
|
117
120
|
badge = (_jsxs(Badge, { variant: "secondary", className: "gap-1", children: [_jsx(PlayCircle, { className: "h-3 w-3" }), " Klaar voor fulfillment"] }));
|
|
118
121
|
}
|
|
@@ -131,6 +134,6 @@ export function AutoProcessStatus({ salesOrderId, orderRef, autoProcessDate, all
|
|
|
131
134
|
if (compact)
|
|
132
135
|
return _jsx(_Fragment, { children: badge });
|
|
133
136
|
const showRetry = status === "error";
|
|
134
|
-
const showTrigger = allowManualTrigger && status !== "done" && status !== "acknowledging" && !loading;
|
|
137
|
+
const showTrigger = allowManualTrigger && status !== "done" && status !== "acknowledging" && status !== "waiting_for_afhandeling" && !loading;
|
|
135
138
|
return (_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [badge, showTrigger ? (_jsx(Button, { size: "sm", variant: showRetry ? "outline" : "secondary", onClick: handleProcess, disabled: loading, children: showRetry ? (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "h-3 w-3 mr-1" }), " Opnieuw"] })) : (_jsxs(_Fragment, { children: [_jsx(PlayCircle, { className: "h-3 w-3 mr-1" }), " ", orderRef ? "Nu inplannen" : "Nu verwerken"] })) })) : null] }));
|
|
136
139
|
}
|
|
@@ -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;AA+
|
|
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;AA+FjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;AAQD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,sCAG1D"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import { createContext, useContext, useState } from "react";
|
|
3
3
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
5
5
|
import { Badge, Checkbox, Button, Dialog, DialogTitle, DialogDescription, Input, Tabs, TabsContent, TabsList, TabsTrigger, toast, } from "@flowselections/core";
|
|
6
6
|
import { CalendarClock, CheckCircle2, ChevronDown, ChevronRight, Printer, Users } from "lucide-react";
|
|
7
7
|
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "../ui/responsive-dialog.js";
|
|
8
8
|
import { usePickAgenda } from "../../hooks/usePickAgenda";
|
|
9
|
-
import { useOrderBuffers } from "../../hooks/useOrderBuffers";
|
|
9
|
+
import { useOrderBuffers, useBufferMembers } from "../../hooks/useOrderBuffers";
|
|
10
10
|
import { isSameDay } from "../../lib/pickDate";
|
|
11
|
-
import { getOrderLines, getDayCartContents, } from "../../lib/cartAssignments.functions";
|
|
11
|
+
import { getOrderLines, getDayCartContents, getOrderCartIds, } from "../../lib/cartAssignments.functions";
|
|
12
12
|
import { printLayoutDocument, printPdfDocument, printFoutMelding } from "../../lib/printing";
|
|
13
13
|
import { AutoProcessStatus } from "./AutoProcessStatus";
|
|
14
|
+
import { NuVersturenButton } from "./NuVersturenButton";
|
|
14
15
|
import { CapacityWarning } from "./CapacityWarning";
|
|
15
16
|
import { useCapacityCheck } from "../../hooks/useCapacityCheck";
|
|
16
17
|
import { toDayKey } from "../../lib/logisticsEngine/capacity";
|
|
@@ -33,6 +34,16 @@ function voortgang(status) {
|
|
|
33
34
|
}
|
|
34
35
|
return { label: "Nog te picken", done: false, variant: "outline" };
|
|
35
36
|
}
|
|
37
|
+
const ShipStateCtx = createContext(new Map());
|
|
38
|
+
/** Voortgang met voorrang voor de echte verzendstatus: eerst Floriday, dan de scan. */
|
|
39
|
+
function useVoortgang(ref, status) {
|
|
40
|
+
const st = useContext(ShipStateCtx).get(refKey(ref));
|
|
41
|
+
if (st?.floridaySent)
|
|
42
|
+
return { label: "Verzonden naar Floriday", done: true, variant: "default" };
|
|
43
|
+
if (st?.approvedAll)
|
|
44
|
+
return { label: "Klaar voor verzending", done: false, variant: "secondary" };
|
|
45
|
+
return voortgang(status);
|
|
46
|
+
}
|
|
36
47
|
const NL_DATE = new Intl.DateTimeFormat("nl-NL", { dateStyle: "full" });
|
|
37
48
|
function refKey(value) {
|
|
38
49
|
return (value ?? "").trim().toUpperCase();
|
|
@@ -97,11 +108,17 @@ function DagDetailContent({ open, date, planned, onOpenChange, }) {
|
|
|
97
108
|
list.push(c);
|
|
98
109
|
contentsByRef.set(k, list);
|
|
99
110
|
}
|
|
100
|
-
|
|
111
|
+
const coverageByRef = new Map();
|
|
112
|
+
const shipState = new Map();
|
|
113
|
+
for (const o of contentsQuery.data?.orders ?? []) {
|
|
114
|
+
coverageByRef.set(refKey(o.orderRef), o.label);
|
|
115
|
+
shipState.set(refKey(o.orderRef), { approvedAll: o.approvedAll, floridaySent: o.floridaySent });
|
|
116
|
+
}
|
|
117
|
+
// Eén rij per kar die op deze dag valt (Engine-dekking is leidend, ook voor bufferkarren).
|
|
101
118
|
const cartRows = [];
|
|
102
119
|
for (const o of ordersOnDay) {
|
|
103
|
-
const total = Math.max(0, o.carts);
|
|
104
120
|
const real = contentsByRef.get(refKey(o.ref)) ?? [];
|
|
121
|
+
const total = Math.max(0, real.length || o.carts);
|
|
105
122
|
for (let idx = 0; idx < total; idx++) {
|
|
106
123
|
const rc = real[idx] ?? null;
|
|
107
124
|
const nr = rc?.cartNumber ?? idx + 1;
|
|
@@ -118,13 +135,15 @@ function DagDetailContent({ open, date, planned, onOpenChange, }) {
|
|
|
118
135
|
plants: rc?.plants ?? null,
|
|
119
136
|
occupancy: rc?.occupancy ?? null,
|
|
120
137
|
layerUtilization: rc?.layerUtilization ?? null,
|
|
138
|
+
shared: rc?.shared ?? false,
|
|
139
|
+
coverageLabel: coverageByRef.get(refKey(o.ref)) ?? null,
|
|
121
140
|
hasContent: !!rc,
|
|
122
141
|
contentLoading: contentsQuery.isLoading,
|
|
123
142
|
status: o.status,
|
|
124
143
|
});
|
|
125
144
|
}
|
|
126
145
|
}
|
|
127
|
-
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 \u00B7", " ", ordersOnDay.filter((o) => voortgang(o.status).done).length, " van ", ordersOnDay.length, " ", "bestellingen afgehandeld \u00B7 ", cartRows.filter((c) => voortgang(c.status).done).length, " van", " ", cartRows.length, " karren afgehandeld"] })] }), _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, isLoading: agenda.isLoading }) }), _jsx(TabsContent, { value: "karren", className: "mt-4", children: _jsx(KarrenTab, { carts: cartRows }) })] })] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Sluiten" }) })] }) }));
|
|
146
|
+
return (_jsx(ShipStateCtx.Provider, { value: shipState, children: _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 \u00B7", " ", ordersOnDay.filter((o) => voortgang(o.status).done).length, " van ", ordersOnDay.length, " ", "bestellingen afgehandeld \u00B7 ", cartRows.filter((c) => voortgang(c.status).done).length, " van", " ", cartRows.length, " karren afgehandeld"] })] }), _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, isLoading: agenda.isLoading }) }), _jsx(TabsContent, { value: "karren", className: "mt-4", children: _jsx(KarrenTab, { carts: cartRows }) })] })] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Sluiten" }) })] }) }) }));
|
|
128
147
|
}
|
|
129
148
|
function BezettingCard({ date, cartsToday }) {
|
|
130
149
|
const queryClient = useQueryClient();
|
|
@@ -222,10 +241,35 @@ function BestellingenTab({ orders, isLoading }) {
|
|
|
222
241
|
if (orders.length === 0) {
|
|
223
242
|
return (_jsx("p", { className: "text-sm text-muted-foreground", children: isLoading ? "Bestellingen laden…" : "Geen bestellingen op deze dag." }));
|
|
224
243
|
}
|
|
225
|
-
return (_jsx("div", { className: "space-y-3", children: groups.map((g) => g.bufferId && g.orders.length > 1 ? (_jsx(BufferGroup, { orders: g.orders }, g.key)) : (g.orders.map((o) => o.planned ? (_jsx(OrderRow, { planned: o.planned, cartsToday: o.carts, engineStatus: o.status }, o.ref)) : (_jsx(EngineOrderRow, { order: o }, o.ref))))) }));
|
|
244
|
+
return (_jsx("div", { className: "space-y-3", children: groups.map((g) => g.bufferId && g.orders.length > 1 ? (_jsx(BufferGroup, { bufferId: g.bufferId, orders: g.orders }, g.key)) : (g.orders.map((o) => o.planned ? (_jsx(OrderRow, { planned: o.planned, cartsToday: o.carts, engineStatus: o.status }, o.ref)) : (_jsx(EngineOrderRow, { order: o }, o.ref))))) }));
|
|
226
245
|
}
|
|
227
|
-
/**
|
|
228
|
-
|
|
246
|
+
/** Al aangevraagd in de wachtrij = de bestaande herprint-regel; niet opnieuw aanmaken. */
|
|
247
|
+
function isDubbeleAanvraag(err) {
|
|
248
|
+
return err?.name === "DubbeleAanvraagFout";
|
|
249
|
+
}
|
|
250
|
+
/** Toont de uitkomst van een printactie; groen alleen als er echt opdrachten in de wachtrij staan. */
|
|
251
|
+
function meldPrintUitkomst(r) {
|
|
252
|
+
if (r.printed > 0) {
|
|
253
|
+
toast.success(`${r.printed} document${r.printed === 1 ? "" : "en"} in de Printwachtrij gezet.` +
|
|
254
|
+
(r.skipped > 0 ? ` ${r.skipped} overgeslagen (al geprint).` : ""));
|
|
255
|
+
}
|
|
256
|
+
if (r.printed === 0 && r.skipped > 0 && r.failed === 0) {
|
|
257
|
+
toast.success(`Alles was al geprint: ${r.skipped} document${r.skipped === 1 ? "" : "en"} overgeslagen.`);
|
|
258
|
+
}
|
|
259
|
+
if (r.printed === 0 && r.skipped === 0) {
|
|
260
|
+
toast.error(`Er is niets in de Printwachtrij gezet. ${r.reasons[0] ?? ""}`.trim());
|
|
261
|
+
}
|
|
262
|
+
else if (r.failed > 0) {
|
|
263
|
+
toast.error(`${r.failed} document${r.failed === 1 ? "" : "en"} niet in de wachtrij: ${r.reasons[0] ?? ""}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Print alle documentsoorten van één bestelling: per echte Engine-kar een pakbon
|
|
268
|
+
* (cart_id verplicht in de Printwachtrij) plus de verzendbrief/afleverbrief van de
|
|
269
|
+
* order. Een document dat voor die kar al in de wachtrij staat wordt overgeslagen
|
|
270
|
+
* (bestaande herprint-regel) en als zodanig gemeld.
|
|
271
|
+
*/
|
|
272
|
+
async function printDocumentenVoorOrder(p, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout) {
|
|
229
273
|
const source = p.order.source;
|
|
230
274
|
let lines = [];
|
|
231
275
|
try {
|
|
@@ -235,7 +279,21 @@ async function printPakbonnenVoorOrder(p, fetchLines) {
|
|
|
235
279
|
catch {
|
|
236
280
|
/* doorgaan met lege regels */
|
|
237
281
|
}
|
|
238
|
-
|
|
282
|
+
// De Printwachtrij neemt alleen een pakbon per echte Engine-kar aan (cart_id verplicht).
|
|
283
|
+
const reasons = [];
|
|
284
|
+
let engineCarts = [];
|
|
285
|
+
try {
|
|
286
|
+
engineCarts = (await fetchCarts({ data: { orderId: p.order.id } })).carts;
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
reasons.push(err instanceof Error ? err.message : "Karindeling van de Engine niet opgehaald.");
|
|
290
|
+
}
|
|
291
|
+
if (engineCarts.length === 0) {
|
|
292
|
+
if (!reasons.length)
|
|
293
|
+
reasons.push(`De Engine heeft voor ${p.order.orderNumber} nog geen karren ingedeeld.`);
|
|
294
|
+
return { printed: 0, skipped: 0, failed: 1, reasons };
|
|
295
|
+
}
|
|
296
|
+
const cartTotal = engineCarts.length;
|
|
239
297
|
const pickDateIso = p.planning?.pickAssignments?.[0]?.date?.toISOString?.().slice(0, 10) ??
|
|
240
298
|
new Date().toISOString().slice(0, 10);
|
|
241
299
|
const pakbonLines = lines.map((l) => ({
|
|
@@ -244,16 +302,21 @@ async function printPakbonnenVoorOrder(p, fetchLines) {
|
|
|
244
302
|
unit: null,
|
|
245
303
|
}));
|
|
246
304
|
let printed = 0;
|
|
305
|
+
let skipped = 0;
|
|
247
306
|
let failed = 0;
|
|
248
307
|
for (let idx = 0; idx < cartTotal; idx++) {
|
|
249
|
-
const
|
|
308
|
+
const engineCart = engineCarts[idx];
|
|
309
|
+
const cartNumber = `${p.order.orderNumber}-${String(engineCart.cartNumber).padStart(2, "0")}`;
|
|
250
310
|
try {
|
|
251
311
|
// Centrale pakbonlayout uit de Layout maker; de wachtrij kiest
|
|
252
312
|
// zelf de actieve layout en de bijbehorende printer.
|
|
253
313
|
await printLayoutDocument({
|
|
254
314
|
documenttype: "pakbon",
|
|
255
|
-
documentnaam: `PAK-${p.order.orderNumber}-${String(
|
|
315
|
+
documentnaam: `PAK-${p.order.orderNumber}-${String(engineCart.cartNumber).padStart(2, "0")}`,
|
|
256
316
|
payload: {
|
|
317
|
+
cart_id: engineCart.cartId,
|
|
318
|
+
order_id: p.order.id,
|
|
319
|
+
order_number: p.order.orderNumber,
|
|
257
320
|
order: {
|
|
258
321
|
id: p.order.id,
|
|
259
322
|
orderNumber: p.order.orderNumber,
|
|
@@ -268,17 +331,82 @@ async function printPakbonnenVoorOrder(p, fetchLines) {
|
|
|
268
331
|
},
|
|
269
332
|
},
|
|
270
333
|
});
|
|
334
|
+
// printLayoutDocument geeft alleen een opdracht-id terug als de rij echt in de wachtrij staat.
|
|
271
335
|
printed++;
|
|
272
336
|
}
|
|
273
337
|
catch (err) {
|
|
338
|
+
if (isDubbeleAanvraag(err)) {
|
|
339
|
+
skipped++;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
failed++;
|
|
343
|
+
reasons.push(`Pakbon ${cartNumber}: ${printFoutMelding(err)}`);
|
|
344
|
+
console.warn("[print-all] pakbon mislukt", cartNumber, err);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Verzendbrief/afleverbrief van de order: eerst de layout die de Engine koppelt,
|
|
349
|
+
// anders de Floriday-brief als die er is.
|
|
350
|
+
try {
|
|
351
|
+
const keuze = await fetchShippingNoteLayout({});
|
|
352
|
+
if (keuze.layoutId) {
|
|
353
|
+
await printLayoutDocument({
|
|
354
|
+
documenttype: keuze.documenttype ?? "afleverbrief",
|
|
355
|
+
documentnaam: `AFL-${p.order.orderNumber}`,
|
|
356
|
+
layoutId: keuze.layoutId,
|
|
357
|
+
payload: {
|
|
358
|
+
order: {
|
|
359
|
+
id: p.order.id,
|
|
360
|
+
orderNumber: p.order.orderNumber,
|
|
361
|
+
customerName: p.order.customerName,
|
|
362
|
+
country: p.order.country ?? null,
|
|
363
|
+
deliveryDate: p.order.deliveryDate,
|
|
364
|
+
cartIndex: 1,
|
|
365
|
+
cartTotal,
|
|
366
|
+
cartNumber: p.order.orderNumber,
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
printed++;
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
const { pdf } = await fetchDeliveryNote({ data: { orderRef: p.order.orderNumber } });
|
|
374
|
+
if (!pdf) {
|
|
375
|
+
skipped++;
|
|
376
|
+
reasons.push(`Verzendbrief ${p.order.orderNumber}: geen Engine-layout en geen Floriday-brief beschikbaar.`);
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
await printPdfDocument({
|
|
380
|
+
documenttype: "afleverbrief",
|
|
381
|
+
documentnaam: `AFL-${p.order.orderNumber}`,
|
|
382
|
+
pdfBase64: pdf.base64,
|
|
383
|
+
});
|
|
384
|
+
printed++;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
catch (err) {
|
|
389
|
+
if (isDubbeleAanvraag(err)) {
|
|
390
|
+
skipped++;
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
274
393
|
failed++;
|
|
275
|
-
|
|
394
|
+
reasons.push(`Verzendbrief ${p.order.orderNumber}: ${printFoutMelding(err)}`);
|
|
395
|
+
console.warn("[print-all] verzendbrief mislukt", p.order.orderNumber, err);
|
|
276
396
|
}
|
|
277
397
|
}
|
|
278
|
-
return { printed, failed };
|
|
398
|
+
return { printed, skipped, failed, reasons };
|
|
279
399
|
}
|
|
280
400
|
/** Meerdere orders die samen in één buffer zitten; één regel in de agenda. */
|
|
281
|
-
function BufferGroup({ orders }) {
|
|
401
|
+
function BufferGroup({ bufferId, orders: dayOrders }) {
|
|
402
|
+
// Alle orders van de buffer (koppeling op buffer-id), ook als ze op een andere dag staan.
|
|
403
|
+
const members = useBufferMembers(bufferId);
|
|
404
|
+
const orders = [...dayOrders];
|
|
405
|
+
for (const m of members.data ?? []) {
|
|
406
|
+
if (!orders.some((o) => refKey(o.ref) === refKey(m.orderNumber))) {
|
|
407
|
+
orders.push({ ref: m.orderNumber, carts: 0, plants: 0, status: m.status ?? "", planned: null });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
282
410
|
const [open, setOpen] = useState(false);
|
|
283
411
|
const [verzetOpen, setVerzetOpen] = useState(false);
|
|
284
412
|
const [printing, setPrinting] = useState(false);
|
|
@@ -286,9 +414,13 @@ function BufferGroup({ orders }) {
|
|
|
286
414
|
const queryClient = useQueryClient();
|
|
287
415
|
const mark = useServerFn(markOrderShipped);
|
|
288
416
|
const fetchLines = useServerFn(getOrderLines);
|
|
417
|
+
const fetchCarts = useServerFn(getOrderCartIds);
|
|
418
|
+
const fetchDeliveryNote = useServerFn(getDeliveryNotePdf);
|
|
419
|
+
const fetchShippingNoteLayout = useServerFn(getShippingNoteLayout);
|
|
420
|
+
const shipState = useContext(ShipStateCtx);
|
|
289
421
|
const carts = orders.reduce((s, o) => s + (o.carts || 0), 0);
|
|
290
422
|
const klant = orders.find((o) => o.planned?.order.customerName)?.planned?.order.customerName ?? null;
|
|
291
|
-
const alleAf = orders.every((o) =>
|
|
423
|
+
const alleAf = orders.every((o) => shipState.get(refKey(o.ref))?.floridaySent === true);
|
|
292
424
|
const refs = orders.map((o) => o.ref).filter(Boolean);
|
|
293
425
|
const verzetOrders = orders.map((o) => ({
|
|
294
426
|
ref: o.ref,
|
|
@@ -305,14 +437,16 @@ function BufferGroup({ orders }) {
|
|
|
305
437
|
await mark({ data: { orderRef: ref } });
|
|
306
438
|
ok++;
|
|
307
439
|
}
|
|
308
|
-
catch {
|
|
309
|
-
failed.push(ref);
|
|
440
|
+
catch (err) {
|
|
441
|
+
failed.push(err instanceof Error ? err.message : `${ref}: afhandelen mislukt.`);
|
|
310
442
|
}
|
|
311
443
|
}
|
|
312
444
|
if (ok > 0)
|
|
313
|
-
toast.success(`${ok} bestelling${
|
|
445
|
+
toast.success(`${ok} van ${refs.length} bestelling${refs.length === 1 ? "" : "en"} uit deze buffer afgehandeld (verzonden).`);
|
|
314
446
|
if (failed.length > 0)
|
|
315
|
-
toast.error(`Niet
|
|
447
|
+
toast.error(`Niet afgehandeld: ${failed.join(" · ")}`);
|
|
448
|
+
if (ok === 0 && failed.length === 0)
|
|
449
|
+
toast.error("Er is niets afgehandeld: de buffer heeft geen bestellingen.");
|
|
316
450
|
for (const key of [
|
|
317
451
|
["logistics-pick-agenda"],
|
|
318
452
|
["engine"],
|
|
@@ -330,22 +464,23 @@ function BufferGroup({ orders }) {
|
|
|
330
464
|
return;
|
|
331
465
|
setPrinting(true);
|
|
332
466
|
let printed = 0;
|
|
467
|
+
let skipped = 0;
|
|
333
468
|
let failed = 0;
|
|
469
|
+
const reasons = [];
|
|
334
470
|
try {
|
|
335
471
|
for (const o of orders) {
|
|
336
472
|
if (!o.planned) {
|
|
337
473
|
failed++;
|
|
474
|
+
reasons.push(`${o.ref}: ordergegevens niet geladen op deze dag.`);
|
|
338
475
|
continue;
|
|
339
476
|
}
|
|
340
|
-
const res = await
|
|
477
|
+
const res = await printDocumentenVoorOrder(o.planned, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout);
|
|
341
478
|
printed += res.printed;
|
|
479
|
+
skipped += res.skipped;
|
|
342
480
|
failed += res.failed;
|
|
481
|
+
reasons.push(...res.reasons);
|
|
343
482
|
}
|
|
344
|
-
|
|
345
|
-
toast.success(`Documenten geprint — ${printed} pakbon${printed === 1 ? "" : "nen"}.`);
|
|
346
|
-
}
|
|
347
|
-
if (failed > 0)
|
|
348
|
-
toast.error(`${failed} pakbon kon niet worden geprint.`);
|
|
483
|
+
meldPrintUitkomst({ printed, skipped, failed, reasons });
|
|
349
484
|
}
|
|
350
485
|
catch (err) {
|
|
351
486
|
toast.error(printFoutMelding(err));
|
|
@@ -354,7 +489,7 @@ function BufferGroup({ orders }) {
|
|
|
354
489
|
setPrinting(false);
|
|
355
490
|
}
|
|
356
491
|
};
|
|
357
|
-
return (_jsxs("div", { className: "rounded-lg border border-primary/40 bg-primary/5", children: [_jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), className: "-m-1 flex items-start gap-3 rounded-md p-1 text-left hover:bg-primary/10", children: [open ? (_jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" })) : (_jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" })), _jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm", children: [_jsx(Badge, { variant: "secondary", children: "Buffer" }), _jsxs("span", { className: "font-medium", children: [orders.length, " bestellingen samen"] }), klant ? _jsx("span", { className: "text-xs text-muted-foreground", children: klant }) : null] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [carts, " ", carts === 1 ? "kar" : "karren", " vandaag"] }), _jsx(Badge, { variant: alleAf ? "default" : "outline", children: alleAf ? "
|
|
492
|
+
return (_jsxs("div", { className: "rounded-lg border border-primary/40 bg-primary/5", children: [_jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), className: "-m-1 flex items-start gap-3 rounded-md p-1 text-left hover:bg-primary/10", children: [open ? (_jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" })) : (_jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" })), _jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm", children: [_jsx(Badge, { variant: "secondary", children: "Buffer" }), _jsxs("span", { className: "font-medium", children: [orders.length, " bestellingen samen"] }), klant ? _jsx("span", { className: "text-xs text-muted-foreground", children: klant }) : null] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [carts, " ", carts === 1 ? "kar" : "karren", " vandaag"] }), _jsx(Badge, { variant: alleAf ? "default" : "outline", children: alleAf ? "Verzonden naar Floriday" : orders.every((o) => shipState.get(refKey(o.ref))?.approvedAll) ? "Klaar voor verzending" : "Nog te picken" }), _jsx("span", { className: "text-xs text-muted-foreground", children: refs.join(", ") })] })] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 border-t pt-3", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: afhandelen, disabled: busy || alleAf, title: "Alle bestellingen in deze buffer in \u00E9\u00E9n keer afhandelen", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), alleAf ? "Afgehandeld" : busy ? "Bezig…" : "Buffer afhandelen (verzonden)"] }), refs[0] ? _jsx(NuVersturenButton, { orderRef: refs[0], label: "Buffer naar Floriday versturen" }) : null, _jsxs(Button, { size: "sm", variant: "outline", onClick: printAlles, disabled: printing, title: "Alle pakbonnen van deze buffer afdrukken", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), printing ? "Bezig…" : "Documenten afdrukken"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => setVerzetOpen(true), title: "Alle bestellingen van deze buffer verzetten", children: [_jsx(CalendarClock, { className: "mr-1 h-3.5 w-3.5" }), "Verzetten"] })] })] }), open && (_jsx("div", { className: "space-y-2 border-t border-primary/30 px-2 py-2", children: orders.map((o) => o.planned ? (_jsx(OrderRow, { planned: o.planned, cartsToday: o.carts, engineStatus: o.status }, o.ref)) : (_jsx(EngineOrderRow, { order: o }, o.ref))) })), _jsx(BulkVerzetDialog, { open: verzetOpen, orders: verzetOrders, cartCount: carts, onOpenChange: setVerzetOpen, onDone: () => setVerzetOpen(false) })] }));
|
|
358
493
|
}
|
|
359
494
|
/** Bestelling die alleen de Engine kent; verdere ordergegevens ontbreken. */
|
|
360
495
|
/** Knop "Afhandelen (verzonden)" — zet de bestelling in de orderadministratie op Verzonden. */
|
|
@@ -394,7 +529,8 @@ function AfhandelenButton({ orderRef, done }) {
|
|
|
394
529
|
return (_jsxs(Button, { size: "sm", variant: "outline", onClick: handle, disabled: busy || done, title: "Deze bestelling afhandelen en op verzonden zetten", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), done ? "Afgehandeld" : busy ? "Bezig…" : "Afhandelen (verzonden)"] }));
|
|
395
530
|
}
|
|
396
531
|
function EngineOrderRow({ order }) {
|
|
397
|
-
|
|
532
|
+
const vg = useVoortgang(order.ref, order.status);
|
|
533
|
+
return (_jsx("div", { className: "rounded-lg border bg-card px-4 py-3", children: _jsxs("div", { className: "grid grid-cols-2 gap-3 text-sm md:grid-cols-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium", children: order.ref }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Alleen bekend bij de Engine" })] }), _jsxs("div", { children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Karren vandaag" }), _jsx("div", { children: order.carts })] }), _jsxs("div", { children: [_jsx("div", { className: "text-xs text-muted-foreground", children: "Planten" }), _jsx("div", { children: order.plants })] }), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Badge, { variant: vg.variant, children: vg.label }), _jsx(AfhandelenButton, { orderRef: order.ref, done: vg.done })] })] }) }));
|
|
398
534
|
}
|
|
399
535
|
function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
400
536
|
const [open, setOpen] = useState(false);
|
|
@@ -402,6 +538,10 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
402
538
|
const [verzetOpen, setVerzetOpen] = useState(false);
|
|
403
539
|
const source = p.order.source;
|
|
404
540
|
const fetchLines = useServerFn(getOrderLines);
|
|
541
|
+
const fetchCarts = useServerFn(getOrderCartIds);
|
|
542
|
+
const fetchDeliveryNote = useServerFn(getDeliveryNotePdf);
|
|
543
|
+
const fetchShippingNoteLayout = useServerFn(getShippingNoteLayout);
|
|
544
|
+
const vg = useVoortgang(p.order.orderNumber, engineStatus ?? p.order.status);
|
|
405
545
|
const linesQuery = useQuery({
|
|
406
546
|
queryKey: ["order-lines", source, p.order.id],
|
|
407
547
|
queryFn: () => fetchLines({ data: { orderId: p.order.id, orderSource: source } }),
|
|
@@ -413,13 +553,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
413
553
|
return;
|
|
414
554
|
setPrinting(true);
|
|
415
555
|
try {
|
|
416
|
-
|
|
417
|
-
if (printed > 0) {
|
|
418
|
-
toast.success(`Documenten geprint — ${printed} pakbon${printed === 1 ? "" : "nen"}.`);
|
|
419
|
-
}
|
|
420
|
-
if (failed > 0) {
|
|
421
|
-
toast.error(`${failed} pakbon kon niet worden geprint.`);
|
|
422
|
-
}
|
|
556
|
+
meldPrintUitkomst(await printDocumentenVoorOrder(p, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout));
|
|
423
557
|
}
|
|
424
558
|
catch (err) {
|
|
425
559
|
toast.error(printFoutMelding(err));
|
|
@@ -431,7 +565,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
431
565
|
};
|
|
432
566
|
return (_jsxs("div", { className: "rounded-lg border bg-card", children: [_jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), className: "-m-1 flex items-start gap-3 rounded-md p-1 text-left hover:bg-muted/50", children: [open ? (_jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" })) : (_jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" })), _jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-6 gap-y-1 text-sm", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "font-medium", children: p.order.orderNumber }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: p.order.customerName })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Type ", _jsx("span", { className: "text-foreground", children: p.order.deliveryType })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Leverdatum", " ", _jsx("span", { className: "text-foreground", children: p.order.deliveryDate
|
|
433
567
|
? new Date(p.order.deliveryDate).toLocaleDateString("nl-NL")
|
|
434
|
-
: "—" })] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [cartsToday, " karren vandaag"] }), _jsx(Badge, { variant:
|
|
568
|
+
: "—" })] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [cartsToday, " karren vandaag"] }), _jsx(Badge, { variant: vg.variant, children: vg.label }), _jsx(Badge, { variant: "outline", children: p.order.status }), (() => {
|
|
435
569
|
const src = p.order.source === "floriday" ? "floriday" : "manual";
|
|
436
570
|
const soId = p.order.salesOrderId ?? (src === "floriday" ? p.order.id : null);
|
|
437
571
|
return soId ? (_jsx(AutoProcessStatus, { salesOrderId: soId, compact: true, allowManualTrigger: false })) : null;
|
|
@@ -439,7 +573,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
439
573
|
const src = p.order.source === "floriday" ? "floriday" : "manual";
|
|
440
574
|
const soId = p.order.salesOrderId ?? (src === "floriday" ? p.order.id : null);
|
|
441
575
|
return soId ? (_jsx(AutoProcessStatus, { salesOrderId: soId, orderRef: p.order.orderNumber })) : null;
|
|
442
|
-
})(), _jsx(
|
|
576
|
+
})(), p.order.orderNumber ? _jsx(NuVersturenButton, { orderRef: p.order.orderNumber }) : null, _jsx(AfhandelenButton, { orderRef: p.order.orderNumber, done: vg.done }), _jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintAll, disabled: printing, title: "Alle documenten van deze bestelling afdrukken (pakbonnen per kar en de verzendbrief)", 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) => {
|
|
443
577
|
e.stopPropagation();
|
|
444
578
|
setVerzetOpen(true);
|
|
445
579
|
}, 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: {
|
|
@@ -622,9 +756,9 @@ function KarRow({ cart: c, cartTotal, selected, onToggle, }) {
|
|
|
622
756
|
setBezig(null);
|
|
623
757
|
}
|
|
624
758
|
};
|
|
625
|
-
return (_jsxs("div", { className: `rounded-md border p-3 ${selected ? "border-primary bg-primary/5" : ""}`, children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx(Checkbox, { checked: selected, onCheckedChange: onToggle, className: "mt-1" }), _jsxs("div", { className: "grid flex-1 gap-3 lg:grid-cols-[1fr_1.4fr_1fr_auto] lg:items-center", children: [_jsx(Field, { label: "Karnummer", value: c.cartNumber }), _jsx(Field, { label: "Klant", value: c.customerName }), _jsx(Field, { label: "Bestelling", value: c.orderRef }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: voortgang(c.status).variant, children: voortgang(c.status).label }), c.hasContent ? (_jsxs(_Fragment, { children: [_jsxs(Badge, { variant: "outline", children: [c.occupancy ?? "—", "%", c.layerUtilization != null
|
|
759
|
+
return (_jsxs("div", { className: `rounded-md border p-3 ${selected ? "border-primary bg-primary/5" : ""}`, children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx(Checkbox, { checked: selected, onCheckedChange: onToggle, className: "mt-1" }), _jsxs("div", { className: "grid flex-1 gap-3 lg:grid-cols-[1fr_1.4fr_1fr_auto] lg:items-center", children: [_jsx(Field, { label: "Karnummer", value: c.cartNumber }), _jsx(Field, { label: "Klant", value: c.customerName }), _jsx(Field, { label: "Bestelling", value: c.orderRef }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: voortgang(c.status).variant, children: voortgang(c.status).label }), c.coverageLabel && _jsx(Badge, { variant: "secondary", children: c.coverageLabel }), c.hasContent ? (_jsxs(_Fragment, { children: [c.shared && _jsx(Badge, { variant: "outline", children: "Gedeelde bufferkar" }), _jsxs(Badge, { variant: "outline", children: [c.occupancy ?? "—", "%", c.layerUtilization != null
|
|
626
760
|
? ` · ${Number(c.layerUtilization.toFixed(1)).toLocaleString("nl-NL")}% van de kar`
|
|
627
|
-
: ""] }), _jsxs(Badge, { variant: "outline", children: [c.layers ?? "—", c.maxLayers != null ? ` / ${c.maxLayers}` : "", " lagen"] }), _jsxs(Badge, { variant: "outline", children: [c.crates ?? "—", " fusten"] }), _jsxs(Badge, { variant: "outline", children: [c.plants ?? "—", " planten"] })] })) : (_jsx(Badge, { variant: "outline", className: "text-muted-foreground", children: c.contentLoading ? "Karinhoud laden…" : "Nog geen karindeling" })), _jsxs(Button, { size: "sm", variant: "outline", disabled: bezig !== null, onClick: printPakbon, title: "Pakbon van deze kar opnieuw printen", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), bezig === "pakbon" ? "Bezig…" : "Pakbon"] }), _jsxs(Button, { size: "sm", variant: "outline", disabled: bezig !== null, onClick: printVerzendbrief, title: "Verzendbrief van deze bestelling printen", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), bezig === "brief" ? "Bezig…" : "Verzendbrief"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => setVerzetOpen(true), title: "Ophaaldag of ophaaltijd van de bestelling van deze kar wijzigen", children: [_jsx(CalendarClock, { className: "mr-1 h-3.5 w-3.5" }), "Verzetten"] })] })] })] }), _jsx(VerzetOrderDialog, { open: verzetOpen, orderRef: c.orderRef, carrierTarget: {
|
|
761
|
+
: ""] }), _jsxs(Badge, { variant: "outline", children: [c.layers ?? "—", c.maxLayers != null ? ` / ${c.maxLayers}` : "", " lagen"] }), _jsxs(Badge, { variant: "outline", children: [c.crates ?? "—", " fusten"] }), _jsxs(Badge, { variant: "outline", children: [c.plants ?? "—", " planten"] })] })) : (_jsx(Badge, { variant: "outline", className: "text-muted-foreground", children: c.contentLoading ? "Karinhoud laden…" : c.coverageLabel ? "Geen kar in deze indeling" : "Nog geen karindeling" })), _jsxs(Button, { size: "sm", variant: "outline", disabled: bezig !== null, onClick: printPakbon, title: "Pakbon van deze kar opnieuw printen", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), bezig === "pakbon" ? "Bezig…" : "Pakbon"] }), _jsxs(Button, { size: "sm", variant: "outline", disabled: bezig !== null, onClick: printVerzendbrief, title: "Verzendbrief van deze bestelling printen", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), bezig === "brief" ? "Bezig…" : "Verzendbrief"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => setVerzetOpen(true), title: "Ophaaldag of ophaaltijd van de bestelling van deze kar wijzigen", children: [_jsx(CalendarClock, { className: "mr-1 h-3.5 w-3.5" }), "Verzetten"] })] })] })] }), _jsx(VerzetOrderDialog, { open: verzetOpen, orderRef: c.orderRef, carrierTarget: {
|
|
628
762
|
carrierId: c.order?.order.carrierId ?? null,
|
|
629
763
|
country: c.order?.order.country ?? null,
|
|
630
764
|
province: c.order?.order.province ?? null,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NuVersturenButton.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/NuVersturenButton.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,KAAsB,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,+BAmG3G"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
4
|
+
import { Button, toast, AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@flowselections/core";
|
|
5
|
+
import { Send, Loader2, CheckCircle2, XCircle } from "lucide-react";
|
|
6
|
+
import { prepareFloridayLoading, sendFloridayLoading, } from "../../lib/floridayLoading.functions";
|
|
7
|
+
/** "Nu versturen": toont eerst een samenvatting met controles en vraagt bevestiging. */
|
|
8
|
+
const PICK_LABEL = {
|
|
9
|
+
geen_pickrij: "geen pickrij bij de Engine",
|
|
10
|
+
open: "nog te picken",
|
|
11
|
+
bezig: "wordt gepickt",
|
|
12
|
+
gepickt: "gepickt",
|
|
13
|
+
};
|
|
14
|
+
export function NuVersturenButton({ orderRef, label = "Nu versturen" }) {
|
|
15
|
+
const prepare = useServerFn(prepareFloridayLoading);
|
|
16
|
+
const send = useServerFn(sendFloridayLoading);
|
|
17
|
+
const [loading, setLoading] = useState(false);
|
|
18
|
+
const [sending, setSending] = useState(false);
|
|
19
|
+
const [preview, setPreview] = useState(null);
|
|
20
|
+
const load = async () => setPreview(await prepare({ data: { orderRef } }));
|
|
21
|
+
const open = async () => {
|
|
22
|
+
setLoading(true);
|
|
23
|
+
try {
|
|
24
|
+
await load();
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
toast.error(e instanceof Error ? e.message : "Belading samenstellen mislukt");
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
setLoading(false);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const doSend = async () => {
|
|
34
|
+
setSending(true);
|
|
35
|
+
try {
|
|
36
|
+
const r = await send({ data: { orderRef } });
|
|
37
|
+
for (const x of r.results) {
|
|
38
|
+
const text = x.code === "created" || x.code === "already_fulfilled" ? x.message : `${x.code}: ${x.message}`;
|
|
39
|
+
if (x.code === "created" || x.code === "already_fulfilled")
|
|
40
|
+
toast.success(text);
|
|
41
|
+
else
|
|
42
|
+
toast.error(text);
|
|
43
|
+
}
|
|
44
|
+
await load();
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
toast.error(e instanceof Error ? e.message : "Versturen mislukt");
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
setSending(false);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: open, disabled: loading, children: [loading ? _jsx(Loader2, { className: "h-3 w-3 mr-1 animate-spin" }) : _jsx(Send, { className: "h-3 w-3 mr-1" }), label] }), _jsx(AlertDialog, { open: !!preview, onOpenChange: (o) => !o && !sending && setPreview(null), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Belading naar Floriday versturen?" }), _jsx(AlertDialogDescription, { children: "Een geaccepteerde opdracht start de verzendbrief, vooraankondiging, fust-administratie en afrekening, en is op productie niet terug te draaien." })] }), preview && (_jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-muted-foreground", children: "Orders:" }), " ", preview.orderRefs.join(", ")] }), _jsxs("div", { children: [_jsx("span", { className: "text-muted-foreground", children: "Leveringen:" }), " ", preview.shipments.length] }), _jsxs("div", { children: [_jsx("span", { className: "text-muted-foreground", children: "Karren:" }), " ", preview.cartCount, preview.carriers.some((c) => c.shared) ? " (waarvan gedeeld)" : ""] }), _jsxs("div", { children: [_jsx("span", { className: "text-muted-foreground", children: "Regels:" }), " ", preview.lineCount] }), _jsx("ul", { className: "space-y-1", children: preview.orders.map((o) => (_jsxs("li", { className: "flex items-center gap-2", children: [o.controlled
|
|
54
|
+
? _jsx(CheckCircle2, { className: "h-3.5 w-3.5 text-primary" })
|
|
55
|
+
: _jsx(XCircle, { className: "h-3.5 w-3.5 text-destructive" }), _jsxs("span", { children: [o.orderRef, ": ", o.cartsControlled, " van ", o.cartsTotal, " karren goedgekeurd op de Scan-controle", o.controlled ? " — klaar voor verzending" : "", o.pickStatus ? ` · pickstatus: ${PICK_LABEL[o.pickStatus] ?? o.pickStatus}` : "", o.autoStatus ? ` · auto-verwerking: ${o.autoStatus}` : ""] })] }, o.orderRef))) }), preview.shipments.filter((sh) => sh.floridayStatus || preview.lastAttempts.some((a) => a.fulfillmentOrderId === sh.fulfillmentOrderId && (a.code === "created" || a.code === "already_fulfilled"))).map((sh) => (_jsxs("div", { className: "rounded border border-border p-2", children: ["Verzonden naar Floriday", sh.floridayStatus ? ` (Floriday: ${sh.floridayStatus})` : "", " \u00B7", " ", sh.deliveryNoteReady === true ? "verzendbrief klaar" : "verzendbrief volgt via de Engine"] }, sh.fulfillmentOrderId))), preview.lastAttempts.length > 0 && (_jsxs("div", { className: "rounded border border-border p-2", children: [_jsx("div", { className: "text-muted-foreground mb-1", children: "Laatste pogingen" }), preview.lastAttempts.slice(0, 4).map((a) => (_jsxs("div", { children: [new Date(a.createdAt).toLocaleString("nl-NL"), " \u00B7 versturen \u00B7 ", a.code] }, a.createdAt + a.step)))] })), preview.blockers.length > 0 && (_jsx("ul", { className: "list-disc pl-5 text-destructive", children: preview.blockers.map((b) => _jsx("li", { children: b }, b)) }))] })), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: sending, children: "Annuleren" }), _jsxs(Button, { onClick: doSend, disabled: !preview?.canSend || sending, children: [sending ? _jsx(Loader2, { className: "h-3 w-3 mr-1 animate-spin" }) : null, "Versturen"] })] })] }) })] }));
|
|
56
|
+
}
|
|
@@ -14,4 +14,10 @@ export declare function useOrderBuffers(orderRefs: string[]): {
|
|
|
14
14
|
bufferFor: (ref: string | null | undefined) => OrderBufferInfo | null;
|
|
15
15
|
isLoading: boolean;
|
|
16
16
|
};
|
|
17
|
+
/** Alle orders van één buffer (koppeling op buffer-id), ook van andere dagen. */
|
|
18
|
+
export declare function useBufferMembers(bufferId: string | null): import("@tanstack/react-query").UseQueryResult<{
|
|
19
|
+
id: string;
|
|
20
|
+
orderNumber: string;
|
|
21
|
+
status: string | null;
|
|
22
|
+
}[], Error>;
|
|
17
23
|
//# sourceMappingURL=useOrderBuffers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOrderBuffers.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrderBuffers.ts"],"names":[],"mappings":"AAIA,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;CACjB;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE;;qBA2C9B,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,eAAe,GAAG,IAAI;;EAItE"}
|
|
1
|
+
{"version":3,"file":"useOrderBuffers.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrderBuffers.ts"],"names":[],"mappings":"AAIA,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;CACjB;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE;;qBA2C9B,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,eAAe,GAAG,IAAI;;EAItE;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;QAMnB,MAAM;iBAAe,MAAM;YAAU,MAAM,GAAG,IAAI;YAYtF"}
|
|
@@ -51,3 +51,24 @@ export function useOrderBuffers(orderRefs) {
|
|
|
51
51
|
isLoading: query.isLoading,
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
+
/** Alle orders van één buffer (koppeling op buffer-id), ook van andere dagen. */
|
|
55
|
+
export function useBufferMembers(bufferId) {
|
|
56
|
+
return useQuery({
|
|
57
|
+
queryKey: ["order-buffers", "members", bufferId],
|
|
58
|
+
enabled: !!bufferId,
|
|
59
|
+
staleTime: 60000,
|
|
60
|
+
retry: false,
|
|
61
|
+
queryFn: async () => {
|
|
62
|
+
const { data, error } = await supabase
|
|
63
|
+
.from("orders")
|
|
64
|
+
.select("id, order_number, status")
|
|
65
|
+
.eq("buffer_id", bufferId)
|
|
66
|
+
.is("deleted_at", null);
|
|
67
|
+
if (error)
|
|
68
|
+
throw new Error(error.message);
|
|
69
|
+
return (data ?? [])
|
|
70
|
+
.filter((r) => !!r.order_number)
|
|
71
|
+
.map((r) => ({ id: r.id, orderNumber: r.order_number, status: r.status }));
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -9,8 +9,6 @@ export { PickAgendaView } from "./components/afhandeling/PickAgendaView";
|
|
|
9
9
|
export { PickingPage } from "./components/afhandeling/PickingPage";
|
|
10
10
|
export { PlanningAgendaPage } from "./components/afhandeling/PlanningAgendaPage";
|
|
11
11
|
export { ControlePage } from "./components/afhandeling/ControlePage";
|
|
12
|
-
export { AfhandelingSettingsCard } from "./components/settings/AfhandelingSettingsCard";
|
|
13
|
-
export { VervoerdersSettingsCard } from "./components/settings/VervoerdersSettingsCard";
|
|
14
12
|
export { calculateEarliestDeliveryDate, calculateOrderPlanning, DEFAULT_PICKUP_MOMENT, type EarliestDeliveryRules, type OrderPlanning, type PickupMoment, } from "./lib/planning";
|
|
15
13
|
export { carrierLeadDaysFromMoments, normalizePickupMoments, sanitizeWeekdays, selectCarrierForTarget, type CarrierOrderTarget, type CarrierPlanningInfo, } from "./lib/carrierPlanning";
|
|
16
14
|
export { ensurePickMode, fetchPickMode, getPickMode, refreshPickMode, startPickModeWatch, subscribePickMode, type PickMode, type PickModeInfo } from "./lib/pickMode";
|
package/dist-lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iDAAiD,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,+CAA+C,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iDAAiD,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,+CAA+C,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAErE,OAAO,EACL,6BAA6B,EAC7B,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtK,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist-lib/index.js
CHANGED
|
@@ -9,8 +9,6 @@ export { PickAgendaView } from "./components/afhandeling/PickAgendaView";
|
|
|
9
9
|
export { PickingPage } from "./components/afhandeling/PickingPage";
|
|
10
10
|
export { PlanningAgendaPage } from "./components/afhandeling/PlanningAgendaPage";
|
|
11
11
|
export { ControlePage } from "./components/afhandeling/ControlePage";
|
|
12
|
-
export { AfhandelingSettingsCard } from "./components/settings/AfhandelingSettingsCard";
|
|
13
|
-
export { VervoerdersSettingsCard } from "./components/settings/VervoerdersSettingsCard";
|
|
14
12
|
export { calculateEarliestDeliveryDate, calculateOrderPlanning, DEFAULT_PICKUP_MOMENT, } from "./lib/planning";
|
|
15
13
|
export { carrierLeadDaysFromMoments, normalizePickupMoments, sanitizeWeekdays, selectCarrierForTarget, } from "./lib/carrierPlanning";
|
|
16
14
|
export { ensurePickMode, fetchPickMode, getPickMode, refreshPickMode, startPickModeWatch, subscribePickMode } from "./lib/pickMode";
|