@flowselections/floriday-afhandeling-module 1.0.50 → 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/ControlePage.js +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.js +165 -37
- package/dist-lib/components/afhandeling/NuVersturenButton.d.ts +2 -2
- package/dist-lib/components/afhandeling/NuVersturenButton.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/NuVersturenButton.js +9 -3
- package/dist-lib/components/afhandeling/ScanControleView.js +1 -1
- package/dist-lib/components/afhandeling/VervoerdersPage.js +1 -1
- package/dist-lib/components/afhandeling/VerzetOrderDialog.js +1 -1
- package/dist-lib/components/afhandeling/WerkplekWaarschuwing.d.ts +9 -9
- package/dist-lib/components/afhandeling/WerkplekWaarschuwing.js +28 -28
- package/dist-lib/components/ui/responsive-dialog.js +1 -1
- 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/hooks/usePickMode.d.ts +1 -1
- 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/client.server.js +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +14 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.d.ts +19 -0
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.js +47 -0
- package/dist-lib/lib/deliveryNotePrint.d.ts +33 -33
- package/dist-lib/lib/deliveryNotePrint.js +219 -219
- package/dist-lib/lib/floridayFulfillmentSend.server.d.ts +1 -1
- package/dist-lib/lib/floridayFulfillmentSend.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayFulfillmentSend.server.js +11 -3
- package/dist-lib/lib/floridayLoading.functions.d.ts +2 -0
- package/dist-lib/lib/floridayLoading.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayLoading.functions.js +51 -23
- package/dist-lib/lib/logisticsEngine/capacity.js +1 -1
- package/dist-lib/lib/logisticsEngine/staffPlanning.js +1 -1
- package/dist-lib/lib/orderFulfilment.functions.d.ts.map +1 -1
- package/dist-lib/lib/orderFulfilment.functions.js +17 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { Button, Card, Checkbox, Dialog, DialogDescription, DialogTitle, Input, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Textarea, Badge, toast, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
|
|
4
4
|
import { Printer, CheckCircle2, AlertTriangle, History, ChevronLeft, ChevronRight, ScanLine } from "lucide-react";
|
|
5
|
-
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "
|
|
5
|
+
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "../ui/responsive-dialog.js";
|
|
6
6
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
7
7
|
import { useServerFn } from "@tanstack/react-start";
|
|
8
8
|
import { getTodaysControlCarts, getControlRescheduleProposals, submitControlSession, listControlHistory, getControlSessionDetail, getControlDraft, listDeliveredToday, saveControlDraft, } from "../../lib/cartControl.functions";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DagDetailDialog.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/DagDetailDialog.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"DagDetailDialog.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/DagDetailDialog.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;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,14 +1,14 @@
|
|
|
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
|
-
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "
|
|
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
14
|
import { NuVersturenButton } from "./NuVersturenButton";
|
|
@@ -34,6 +34,16 @@ function voortgang(status) {
|
|
|
34
34
|
}
|
|
35
35
|
return { label: "Nog te picken", done: false, variant: "outline" };
|
|
36
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
|
+
}
|
|
37
47
|
const NL_DATE = new Intl.DateTimeFormat("nl-NL", { dateStyle: "full" });
|
|
38
48
|
function refKey(value) {
|
|
39
49
|
return (value ?? "").trim().toUpperCase();
|
|
@@ -99,8 +109,11 @@ function DagDetailContent({ open, date, planned, onOpenChange, }) {
|
|
|
99
109
|
contentsByRef.set(k, list);
|
|
100
110
|
}
|
|
101
111
|
const coverageByRef = new Map();
|
|
102
|
-
|
|
112
|
+
const shipState = new Map();
|
|
113
|
+
for (const o of contentsQuery.data?.orders ?? []) {
|
|
103
114
|
coverageByRef.set(refKey(o.orderRef), o.label);
|
|
115
|
+
shipState.set(refKey(o.orderRef), { approvedAll: o.approvedAll, floridaySent: o.floridaySent });
|
|
116
|
+
}
|
|
104
117
|
// Eén rij per kar die op deze dag valt (Engine-dekking is leidend, ook voor bufferkarren).
|
|
105
118
|
const cartRows = [];
|
|
106
119
|
for (const o of ordersOnDay) {
|
|
@@ -130,7 +143,7 @@ function DagDetailContent({ open, date, planned, onOpenChange, }) {
|
|
|
130
143
|
});
|
|
131
144
|
}
|
|
132
145
|
}
|
|
133
|
-
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" }) })] }) }) }));
|
|
134
147
|
}
|
|
135
148
|
function BezettingCard({ date, cartsToday }) {
|
|
136
149
|
const queryClient = useQueryClient();
|
|
@@ -228,10 +241,35 @@ function BestellingenTab({ orders, isLoading }) {
|
|
|
228
241
|
if (orders.length === 0) {
|
|
229
242
|
return (_jsx("p", { className: "text-sm text-muted-foreground", children: isLoading ? "Bestellingen laden…" : "Geen bestellingen op deze dag." }));
|
|
230
243
|
}
|
|
231
|
-
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))))) }));
|
|
232
245
|
}
|
|
233
|
-
/**
|
|
234
|
-
|
|
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) {
|
|
235
273
|
const source = p.order.source;
|
|
236
274
|
let lines = [];
|
|
237
275
|
try {
|
|
@@ -241,7 +279,21 @@ async function printPakbonnenVoorOrder(p, fetchLines) {
|
|
|
241
279
|
catch {
|
|
242
280
|
/* doorgaan met lege regels */
|
|
243
281
|
}
|
|
244
|
-
|
|
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;
|
|
245
297
|
const pickDateIso = p.planning?.pickAssignments?.[0]?.date?.toISOString?.().slice(0, 10) ??
|
|
246
298
|
new Date().toISOString().slice(0, 10);
|
|
247
299
|
const pakbonLines = lines.map((l) => ({
|
|
@@ -250,16 +302,21 @@ async function printPakbonnenVoorOrder(p, fetchLines) {
|
|
|
250
302
|
unit: null,
|
|
251
303
|
}));
|
|
252
304
|
let printed = 0;
|
|
305
|
+
let skipped = 0;
|
|
253
306
|
let failed = 0;
|
|
254
307
|
for (let idx = 0; idx < cartTotal; idx++) {
|
|
255
|
-
const
|
|
308
|
+
const engineCart = engineCarts[idx];
|
|
309
|
+
const cartNumber = `${p.order.orderNumber}-${String(engineCart.cartNumber).padStart(2, "0")}`;
|
|
256
310
|
try {
|
|
257
311
|
// Centrale pakbonlayout uit de Layout maker; de wachtrij kiest
|
|
258
312
|
// zelf de actieve layout en de bijbehorende printer.
|
|
259
313
|
await printLayoutDocument({
|
|
260
314
|
documenttype: "pakbon",
|
|
261
|
-
documentnaam: `PAK-${p.order.orderNumber}-${String(
|
|
315
|
+
documentnaam: `PAK-${p.order.orderNumber}-${String(engineCart.cartNumber).padStart(2, "0")}`,
|
|
262
316
|
payload: {
|
|
317
|
+
cart_id: engineCart.cartId,
|
|
318
|
+
order_id: p.order.id,
|
|
319
|
+
order_number: p.order.orderNumber,
|
|
263
320
|
order: {
|
|
264
321
|
id: p.order.id,
|
|
265
322
|
orderNumber: p.order.orderNumber,
|
|
@@ -274,17 +331,82 @@ async function printPakbonnenVoorOrder(p, fetchLines) {
|
|
|
274
331
|
},
|
|
275
332
|
},
|
|
276
333
|
});
|
|
334
|
+
// printLayoutDocument geeft alleen een opdracht-id terug als de rij echt in de wachtrij staat.
|
|
277
335
|
printed++;
|
|
278
336
|
}
|
|
279
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 {
|
|
280
393
|
failed++;
|
|
281
|
-
|
|
394
|
+
reasons.push(`Verzendbrief ${p.order.orderNumber}: ${printFoutMelding(err)}`);
|
|
395
|
+
console.warn("[print-all] verzendbrief mislukt", p.order.orderNumber, err);
|
|
282
396
|
}
|
|
283
397
|
}
|
|
284
|
-
return { printed, failed };
|
|
398
|
+
return { printed, skipped, failed, reasons };
|
|
285
399
|
}
|
|
286
400
|
/** Meerdere orders die samen in één buffer zitten; één regel in de agenda. */
|
|
287
|
-
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
|
+
}
|
|
288
410
|
const [open, setOpen] = useState(false);
|
|
289
411
|
const [verzetOpen, setVerzetOpen] = useState(false);
|
|
290
412
|
const [printing, setPrinting] = useState(false);
|
|
@@ -292,9 +414,13 @@ function BufferGroup({ orders }) {
|
|
|
292
414
|
const queryClient = useQueryClient();
|
|
293
415
|
const mark = useServerFn(markOrderShipped);
|
|
294
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);
|
|
295
421
|
const carts = orders.reduce((s, o) => s + (o.carts || 0), 0);
|
|
296
422
|
const klant = orders.find((o) => o.planned?.order.customerName)?.planned?.order.customerName ?? null;
|
|
297
|
-
const alleAf = orders.every((o) =>
|
|
423
|
+
const alleAf = orders.every((o) => shipState.get(refKey(o.ref))?.floridaySent === true);
|
|
298
424
|
const refs = orders.map((o) => o.ref).filter(Boolean);
|
|
299
425
|
const verzetOrders = orders.map((o) => ({
|
|
300
426
|
ref: o.ref,
|
|
@@ -311,14 +437,16 @@ function BufferGroup({ orders }) {
|
|
|
311
437
|
await mark({ data: { orderRef: ref } });
|
|
312
438
|
ok++;
|
|
313
439
|
}
|
|
314
|
-
catch {
|
|
315
|
-
failed.push(ref);
|
|
440
|
+
catch (err) {
|
|
441
|
+
failed.push(err instanceof Error ? err.message : `${ref}: afhandelen mislukt.`);
|
|
316
442
|
}
|
|
317
443
|
}
|
|
318
444
|
if (ok > 0)
|
|
319
|
-
toast.success(`${ok} bestelling${
|
|
445
|
+
toast.success(`${ok} van ${refs.length} bestelling${refs.length === 1 ? "" : "en"} uit deze buffer afgehandeld (verzonden).`);
|
|
320
446
|
if (failed.length > 0)
|
|
321
|
-
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.");
|
|
322
450
|
for (const key of [
|
|
323
451
|
["logistics-pick-agenda"],
|
|
324
452
|
["engine"],
|
|
@@ -336,22 +464,23 @@ function BufferGroup({ orders }) {
|
|
|
336
464
|
return;
|
|
337
465
|
setPrinting(true);
|
|
338
466
|
let printed = 0;
|
|
467
|
+
let skipped = 0;
|
|
339
468
|
let failed = 0;
|
|
469
|
+
const reasons = [];
|
|
340
470
|
try {
|
|
341
471
|
for (const o of orders) {
|
|
342
472
|
if (!o.planned) {
|
|
343
473
|
failed++;
|
|
474
|
+
reasons.push(`${o.ref}: ordergegevens niet geladen op deze dag.`);
|
|
344
475
|
continue;
|
|
345
476
|
}
|
|
346
|
-
const res = await
|
|
477
|
+
const res = await printDocumentenVoorOrder(o.planned, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout);
|
|
347
478
|
printed += res.printed;
|
|
479
|
+
skipped += res.skipped;
|
|
348
480
|
failed += res.failed;
|
|
481
|
+
reasons.push(...res.reasons);
|
|
349
482
|
}
|
|
350
|
-
|
|
351
|
-
toast.success(`Documenten geprint — ${printed} pakbon${printed === 1 ? "" : "nen"}.`);
|
|
352
|
-
}
|
|
353
|
-
if (failed > 0)
|
|
354
|
-
toast.error(`${failed} pakbon kon niet worden geprint.`);
|
|
483
|
+
meldPrintUitkomst({ printed, skipped, failed, reasons });
|
|
355
484
|
}
|
|
356
485
|
catch (err) {
|
|
357
486
|
toast.error(printFoutMelding(err));
|
|
@@ -360,7 +489,7 @@ function BufferGroup({ orders }) {
|
|
|
360
489
|
setPrinting(false);
|
|
361
490
|
}
|
|
362
491
|
};
|
|
363
|
-
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) })] }));
|
|
364
493
|
}
|
|
365
494
|
/** Bestelling die alleen de Engine kent; verdere ordergegevens ontbreken. */
|
|
366
495
|
/** Knop "Afhandelen (verzonden)" — zet de bestelling in de orderadministratie op Verzonden. */
|
|
@@ -400,7 +529,8 @@ function AfhandelenButton({ orderRef, done }) {
|
|
|
400
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)"] }));
|
|
401
530
|
}
|
|
402
531
|
function EngineOrderRow({ order }) {
|
|
403
|
-
|
|
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 })] })] }) }));
|
|
404
534
|
}
|
|
405
535
|
function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
406
536
|
const [open, setOpen] = useState(false);
|
|
@@ -408,6 +538,10 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
408
538
|
const [verzetOpen, setVerzetOpen] = useState(false);
|
|
409
539
|
const source = p.order.source;
|
|
410
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);
|
|
411
545
|
const linesQuery = useQuery({
|
|
412
546
|
queryKey: ["order-lines", source, p.order.id],
|
|
413
547
|
queryFn: () => fetchLines({ data: { orderId: p.order.id, orderSource: source } }),
|
|
@@ -419,13 +553,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
419
553
|
return;
|
|
420
554
|
setPrinting(true);
|
|
421
555
|
try {
|
|
422
|
-
|
|
423
|
-
if (printed > 0) {
|
|
424
|
-
toast.success(`Documenten geprint — ${printed} pakbon${printed === 1 ? "" : "nen"}.`);
|
|
425
|
-
}
|
|
426
|
-
if (failed > 0) {
|
|
427
|
-
toast.error(`${failed} pakbon kon niet worden geprint.`);
|
|
428
|
-
}
|
|
556
|
+
meldPrintUitkomst(await printDocumentenVoorOrder(p, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout));
|
|
429
557
|
}
|
|
430
558
|
catch (err) {
|
|
431
559
|
toast.error(printFoutMelding(err));
|
|
@@ -437,7 +565,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
437
565
|
};
|
|
438
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
|
|
439
567
|
? new Date(p.order.deliveryDate).toLocaleDateString("nl-NL")
|
|
440
|
-
: "—" })] })] }), _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 }), (() => {
|
|
441
569
|
const src = p.order.source === "floriday" ? "floriday" : "manual";
|
|
442
570
|
const soId = p.order.salesOrderId ?? (src === "floriday" ? p.order.id : null);
|
|
443
571
|
return soId ? (_jsx(AutoProcessStatus, { salesOrderId: soId, compact: true, allowManualTrigger: false })) : null;
|
|
@@ -445,7 +573,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
|
|
|
445
573
|
const src = p.order.source === "floriday" ? "floriday" : "manual";
|
|
446
574
|
const soId = p.order.salesOrderId ?? (src === "floriday" ? p.order.id : null);
|
|
447
575
|
return soId ? (_jsx(AutoProcessStatus, { salesOrderId: soId, orderRef: p.order.orderNumber })) : null;
|
|
448
|
-
})(), p.order.orderNumber ? _jsx(NuVersturenButton, { orderRef: p.order.orderNumber }) : null, _jsx(AfhandelenButton, { orderRef: p.order.orderNumber, done:
|
|
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) => {
|
|
449
577
|
e.stopPropagation();
|
|
450
578
|
setVerzetOpen(true);
|
|
451
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: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function NuVersturenButton({ orderRef }: {
|
|
1
|
+
export declare function NuVersturenButton({ orderRef, label }: {
|
|
3
2
|
orderRef: string;
|
|
3
|
+
label?: string;
|
|
4
4
|
}): import("react").JSX.Element;
|
|
5
5
|
//# sourceMappingURL=NuVersturenButton.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NuVersturenButton.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/NuVersturenButton.tsx"],"names":[],"mappings":"
|
|
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"}
|
|
@@ -5,7 +5,13 @@ import { Button, toast, AlertDialog, AlertDialogCancel, AlertDialogContent, Aler
|
|
|
5
5
|
import { Send, Loader2, CheckCircle2, XCircle } from "lucide-react";
|
|
6
6
|
import { prepareFloridayLoading, sendFloridayLoading, } from "../../lib/floridayLoading.functions";
|
|
7
7
|
/** "Nu versturen": toont eerst een samenvatting met controles en vraagt bevestiging. */
|
|
8
|
-
|
|
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" }) {
|
|
9
15
|
const prepare = useServerFn(prepareFloridayLoading);
|
|
10
16
|
const send = useServerFn(sendFloridayLoading);
|
|
11
17
|
const [loading, setLoading] = useState(false);
|
|
@@ -44,7 +50,7 @@ export function NuVersturenButton({ orderRef }) {
|
|
|
44
50
|
setSending(false);
|
|
45
51
|
}
|
|
46
52
|
};
|
|
47
|
-
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" }),
|
|
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
|
|
48
54
|
? _jsx(CheckCircle2, { className: "h-3.5 w-3.5 text-primary" })
|
|
49
|
-
: _jsx(XCircle, { className: "h-3.5 w-3.5 text-destructive" }), _jsxs("span", { children: [o.orderRef, ": ", o.cartsControlled, "
|
|
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"] })] })] }) })] }));
|
|
50
56
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
-
import { supabase } from "../../integrations/supabase/moduleClient";
|
|
3
|
+
import { supabase } from "../../integrations/supabase/moduleClient.js";
|
|
4
4
|
import { Button, Badge, Card, Input, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, } from "@flowselections/core";
|
|
5
5
|
import { AlertTriangle, CheckCircle2, RefreshCw, ScanLine } from "lucide-react";
|
|
6
6
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogDescription, AlertDialogTitle, toast, } from "@flowselections/core";
|
|
4
4
|
import { Plus, Pencil, Trash2, Truck, ArrowUp, ArrowDown } from "lucide-react";
|
|
5
|
-
import { ResponsiveAlertDialogBody, ResponsiveAlertDialogContent, ResponsiveAlertDialogFooter, ResponsiveAlertDialogHeader, } from "
|
|
5
|
+
import { ResponsiveAlertDialogBody, ResponsiveAlertDialogContent, ResponsiveAlertDialogFooter, ResponsiveAlertDialogHeader, } from "../ui/responsive-dialog.js";
|
|
6
6
|
import { Link } from "@tanstack/react-router";
|
|
7
7
|
import { useServerFn } from "@tanstack/react-start";
|
|
8
8
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from "react";
|
|
|
3
3
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
5
5
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Dialog, DialogTitle, DialogDescription, Input, Label, Textarea, toast, } from "@flowselections/core";
|
|
6
|
-
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "
|
|
6
|
+
import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "../ui/responsive-dialog.js";
|
|
7
7
|
import { applyReschedule, listRescheduleHistory, previewReschedule, getPickMoments, setPickDay, } from "../../lib/logisticsEngine/reschedule";
|
|
8
8
|
import { ENGINE_TASKS_KEY } from "../../hooks/useEngineTasks";
|
|
9
9
|
import { listCarriers } from "../../lib/carriers.functions";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Leest de ingestelde werkplek client-side (SSR-veilig). */
|
|
2
|
-
export declare function useWerkplek(): string | null;
|
|
3
|
-
/**
|
|
4
|
-
* Eén melding bovenaan een printscherm zolang er geen werkplek is ingesteld.
|
|
5
|
-
* Printknoppen zijn dan uitgeschakeld, zodat er geen fout per printactie komt.
|
|
6
|
-
*/
|
|
7
|
-
export declare function WerkplekWaarschuwing({ werkplek }: {
|
|
8
|
-
werkplek: string | null;
|
|
9
|
-
}): import("react").JSX.Element | null;
|
|
1
|
+
/** Leest de ingestelde werkplek client-side (SSR-veilig). */
|
|
2
|
+
export declare function useWerkplek(): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Eén melding bovenaan een printscherm zolang er geen werkplek is ingesteld.
|
|
5
|
+
* Printknoppen zijn dan uitgeschakeld, zodat er geen fout per printactie komt.
|
|
6
|
+
*/
|
|
7
|
+
export declare function WerkplekWaarschuwing({ werkplek }: {
|
|
8
|
+
werkplek: string | null;
|
|
9
|
+
}): import("react").JSX.Element | null;
|
|
10
10
|
//# sourceMappingURL=WerkplekWaarschuwing.d.ts.map
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { AlertTriangle } from "lucide-react";
|
|
4
|
-
import { getWerkplek } from "../../lib/printing";
|
|
5
|
-
/** Leest de ingestelde werkplek client-side (SSR-veilig). */
|
|
6
|
-
export function useWerkplek() {
|
|
7
|
-
const [werkplek, setWerkplekState] = useState(null);
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
setWerkplekState(getWerkplek());
|
|
10
|
-
const onStorage = () => setWerkplekState(getWerkplek());
|
|
11
|
-
window.addEventListener("storage", onStorage);
|
|
12
|
-
window.addEventListener("focus", onStorage);
|
|
13
|
-
return () => {
|
|
14
|
-
window.removeEventListener("storage", onStorage);
|
|
15
|
-
window.removeEventListener("focus", onStorage);
|
|
16
|
-
};
|
|
17
|
-
}, []);
|
|
18
|
-
return werkplek;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Eén melding bovenaan een printscherm zolang er geen werkplek is ingesteld.
|
|
22
|
-
* Printknoppen zijn dan uitgeschakeld, zodat er geen fout per printactie komt.
|
|
23
|
-
*/
|
|
24
|
-
export function WerkplekWaarschuwing({ werkplek }) {
|
|
25
|
-
if (werkplek)
|
|
26
|
-
return null;
|
|
27
|
-
return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), _jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Geen werkplek ingesteld." }), " Printen is uitgeschakeld. Stel de werkplek (pickstation- of computernaam) in bij ", _jsx("strong", { children: "Instellingen" }), "."] })] }));
|
|
28
|
-
}
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { AlertTriangle } from "lucide-react";
|
|
4
|
+
import { getWerkplek } from "../../lib/printing";
|
|
5
|
+
/** Leest de ingestelde werkplek client-side (SSR-veilig). */
|
|
6
|
+
export function useWerkplek() {
|
|
7
|
+
const [werkplek, setWerkplekState] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setWerkplekState(getWerkplek());
|
|
10
|
+
const onStorage = () => setWerkplekState(getWerkplek());
|
|
11
|
+
window.addEventListener("storage", onStorage);
|
|
12
|
+
window.addEventListener("focus", onStorage);
|
|
13
|
+
return () => {
|
|
14
|
+
window.removeEventListener("storage", onStorage);
|
|
15
|
+
window.removeEventListener("focus", onStorage);
|
|
16
|
+
};
|
|
17
|
+
}, []);
|
|
18
|
+
return werkplek;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Eén melding bovenaan een printscherm zolang er geen werkplek is ingesteld.
|
|
22
|
+
* Printknoppen zijn dan uitgeschakeld, zodat er geen fout per printactie komt.
|
|
23
|
+
*/
|
|
24
|
+
export function WerkplekWaarschuwing({ werkplek }) {
|
|
25
|
+
if (werkplek)
|
|
26
|
+
return null;
|
|
27
|
+
return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-3 py-2 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), _jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Geen werkplek ingesteld." }), " Printen is uitgeschakeld. Stel de werkplek (pickstation- of computernaam) in bij ", _jsx("strong", { children: "Instellingen" }), "."] })] }));
|
|
28
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { AlertDialogContent, AlertDialogFooter, AlertDialogHeader, DialogContent, DialogFooter, DialogHeader, } from "@flowselections/core";
|
|
3
|
-
import { cn } from "../../lib/utils";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
4
|
const WIDTH_BY_SIZE = {
|
|
5
5
|
sm: "min(40rem, calc(100vw - 2rem))",
|
|
6
6
|
md: "min(48rem, calc(100vw - 2rem))",
|
|
@@ -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
|
+
}
|