@flowselections/floriday-afhandeling-module 1.0.52 → 1.0.56

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.
@@ -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+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
+ {"version":3,"file":"DagDetailDialog.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/DagDetailDialog.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAmGjE,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"}
@@ -8,7 +8,7 @@ import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter,
8
8
  import { usePickAgenda } from "../../hooks/usePickAgenda";
9
9
  import { useOrderBuffers, useBufferMembers } from "../../hooks/useOrderBuffers";
10
10
  import { isSameDay } from "../../lib/pickDate";
11
- import { getOrderLines, getDayCartContents, getOrderCartIds, } from "../../lib/cartAssignments.functions";
11
+ import { getOrderLines, getDayCartContents, getOrderCartIds, getPakbonCartInfo, } 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";
@@ -124,6 +124,7 @@ function DagDetailContent({ open, date, planned, onOpenChange, }) {
124
124
  const nr = rc?.cartNumber ?? idx + 1;
125
125
  cartRows.push({
126
126
  key: `${o.ref}-${idx}`,
127
+ cartId: rc?.cartId ?? null,
127
128
  orderRef: o.ref,
128
129
  customerName: o.planned?.order.customerName ?? "—",
129
130
  cartIndex: idx,
@@ -247,155 +248,178 @@ function BestellingenTab({ orders, isLoading }) {
247
248
  function isDubbeleAanvraag(err) {
248
249
  return err?.name === "DubbeleAanvraagFout";
249
250
  }
250
- /** Toont de uitkomst van een printactie; groen alleen als er echt opdrachten in de wachtrij staan. */
251
+ function tijdLabel(iso) {
252
+ const d = new Date(iso);
253
+ return Number.isNaN(d.getTime()) ? iso : d.toLocaleString("nl-NL", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
254
+ }
255
+ /** Concreet zoals op het pickstation, met direct een knop "Opnieuw printen" (als herprint). */
256
+ function meldOverslagen(s) {
257
+ const t = toast;
258
+ t(`Pakbon ${s.label} al verstuurd vanuit ${s.herkomst}${s.printer ? ` naar ${s.printer}` : ""} om ${tijdLabel(s.tijd)}`, {
259
+ duration: 15000,
260
+ action: {
261
+ label: "Opnieuw printen",
262
+ onClick: () => {
263
+ s.herprint().then(() => toast.success(`Pakbon ${s.label} opnieuw in de Printwachtrij gezet (herprint).`), (err) => toast.error(printFoutMelding(err)));
264
+ },
265
+ },
266
+ });
267
+ }
268
+ /** Toont de uitkomst direct; de achtergrondopdracht meldt zich later apart. */
251
269
  function meldPrintUitkomst(r) {
252
270
  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).` : ""));
271
+ toast.success(`${r.printed} opdracht${r.printed === 1 ? "" : "en"} in de Printwachtrij gezet.`);
255
272
  }
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) {
273
+ for (const s of r.skipped)
274
+ meldOverslagen(s);
275
+ if (r.printed === 0 && r.skipped.length === 0 && !r.achtergrond) {
260
276
  toast.error(`Er is niets in de Printwachtrij gezet. ${r.reasons[0] ?? ""}`.trim());
261
277
  }
262
278
  else if (r.failed > 0) {
263
279
  toast.error(`${r.failed} document${r.failed === 1 ? "" : "en"} niet in de wachtrij: ${r.reasons[0] ?? ""}`);
264
280
  }
265
281
  }
282
+ async function meldAchtergrond(r) {
283
+ if (!r.achtergrond)
284
+ return;
285
+ const a = await r.achtergrond;
286
+ if (a.printed > 0)
287
+ toast.success(`Verzendbrief in de Printwachtrij gezet.`);
288
+ if (a.failed > 0 || (a.printed === 0 && a.reasons.length > 0)) {
289
+ toast.error(`Verzendbrief niet gemaakt: ${a.reasons[0] ?? "onbekende reden"}`);
290
+ }
291
+ }
292
+ /** Payload in dezelfde vorm als het pickstation; Pickschermen zoekt op documenttype pakbon + payload.cart_id. */
293
+ function pakbonPayload(args) {
294
+ return {
295
+ source: "afhandeling",
296
+ cart_id: args.cartId,
297
+ barcode: args.barcode,
298
+ cart: { id: args.cartId, barcode: args.barcode, number: args.cartNumber },
299
+ order_id: args.order.id,
300
+ order_number: args.order.orderNumber,
301
+ order: {
302
+ ...args.order,
303
+ pickDate: args.pickDate,
304
+ cartIndex: args.cartIndex,
305
+ cartTotal: args.cartTotal,
306
+ cartNumber: args.cartNumber,
307
+ barcode: args.barcode,
308
+ lines: args.lines,
309
+ },
310
+ };
311
+ }
266
312
  /**
267
313
  * 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.
314
+ * (cart_id verplicht) en de verzendbrief/afleverbrief. Pakbonnen gaan direct de
315
+ * wachtrij in (zonder op de printer te wachten); een kar met al een pakbon wordt
316
+ * overgeslagen met herkomst/printer/tijd en een herprintknop. De verzendbrief
317
+ * wordt op de achtergrond gemaakt en meldt zich apart.
271
318
  */
272
- async function printDocumentenVoorOrder(p, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout) {
319
+ async function printDocumentenVoorOrder(p, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout, fetchPakbonInfo) {
273
320
  const source = p.order.source;
274
- let lines = [];
275
- try {
276
- const res = await fetchLines({ data: { orderId: p.order.id, orderSource: source } });
277
- lines = res.lines;
278
- }
279
- catch {
280
- /* doorgaan met lege regels */
281
- }
282
- // De Printwachtrij neemt alleen een pakbon per echte Engine-kar aan (cart_id verplicht).
283
321
  const reasons = [];
322
+ const [linesRes, cartsRes] = await Promise.allSettled([
323
+ fetchLines({ data: { orderId: p.order.id, orderSource: source } }),
324
+ fetchCarts({ data: { orderId: p.order.id } }),
325
+ ]);
326
+ const lines = linesRes.status === "fulfilled" ? linesRes.value.lines : [];
284
327
  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
- }
328
+ if (cartsRes.status === "fulfilled")
329
+ engineCarts = cartsRes.value.carts;
330
+ else
331
+ reasons.push(cartsRes.reason instanceof Error ? cartsRes.reason.message : "Karindeling van de Engine niet opgehaald.");
291
332
  if (engineCarts.length === 0) {
292
333
  if (!reasons.length)
293
334
  reasons.push(`De Engine heeft voor ${p.order.orderNumber} nog geen karren ingedeeld.`);
294
- return { printed: 0, skipped: 0, failed: 1, reasons };
335
+ return { printed: 0, skipped: [], failed: 1, reasons, achtergrond: null };
336
+ }
337
+ let info;
338
+ try {
339
+ info = (await fetchPakbonInfo({ data: { cartIds: engineCarts.map((c) => c.cartId) } })).carts;
295
340
  }
341
+ catch (err) {
342
+ return { printed: 0, skipped: [], failed: engineCarts.length, reasons: [err instanceof Error ? err.message : "Kar-barcodes niet opgehaald."], achtergrond: null };
343
+ }
344
+ const infoById = new Map(info.map((i) => [i.cartId, i]));
296
345
  const cartTotal = engineCarts.length;
297
- const pickDateIso = p.planning?.pickAssignments?.[0]?.date?.toISOString?.().slice(0, 10) ??
298
- new Date().toISOString().slice(0, 10);
299
- const pakbonLines = lines.map((l) => ({
300
- description: l.article,
301
- crates: l.crates,
302
- unit: null,
303
- }));
346
+ const pickDate = p.planning?.pickAssignments?.[0]?.date?.toISOString?.().slice(0, 10) ?? new Date().toISOString().slice(0, 10);
347
+ const orderInfo = {
348
+ id: p.order.id,
349
+ orderNumber: p.order.orderNumber,
350
+ customerName: p.order.customerName,
351
+ country: p.order.country ?? null,
352
+ deliveryDate: p.order.deliveryDate,
353
+ };
354
+ const pakbonLines = lines.map((l) => ({ description: l.article, crates: l.crates, unit: null }));
304
355
  let printed = 0;
305
- let skipped = 0;
306
356
  let failed = 0;
307
- for (let idx = 0; idx < cartTotal; idx++) {
308
- const engineCart = engineCarts[idx];
309
- const cartNumber = `${p.order.orderNumber}-${String(engineCart.cartNumber).padStart(2, "0")}`;
310
- try {
311
- // Centrale pakbonlayout uit de Layout maker; de wachtrij kiest
312
- // zelf de actieve layout en de bijbehorende printer.
313
- await printLayoutDocument({
314
- documenttype: "pakbon",
315
- documentnaam: `PAK-${p.order.orderNumber}-${String(engineCart.cartNumber).padStart(2, "0")}`,
316
- payload: {
317
- cart_id: engineCart.cartId,
318
- order_id: p.order.id,
319
- order_number: p.order.orderNumber,
320
- order: {
321
- id: p.order.id,
322
- orderNumber: p.order.orderNumber,
323
- customerName: p.order.customerName,
324
- country: p.order.country ?? null,
325
- deliveryDate: p.order.deliveryDate,
326
- pickDate: pickDateIso,
327
- cartIndex: idx + 1,
328
- cartTotal,
329
- cartNumber,
330
- lines: pakbonLines,
331
- },
332
- },
333
- });
334
- // printLayoutDocument geeft alleen een opdracht-id terug als de rij echt in de wachtrij staat.
335
- printed++;
357
+ const skipped = [];
358
+ await Promise.all(engineCarts.map(async (engineCart, idx) => {
359
+ const nr = String(engineCart.cartNumber).padStart(2, "0");
360
+ const cartNumber = `${p.order.orderNumber}-${nr}`;
361
+ const ci = infoById.get(engineCart.cartId);
362
+ if (!ci) {
363
+ failed++;
364
+ reasons.push(`Pakbon ${cartNumber}: geen kar-barcode van de Engine.`);
365
+ return;
336
366
  }
337
- catch (err) {
338
- if (isDubbeleAanvraag(err)) {
339
- skipped++;
340
- }
367
+ const opdracht = (isHerprint) => printLayoutDocument({
368
+ documenttype: "pakbon",
369
+ documentnaam: `PAK-${p.order.orderNumber}-${nr}`,
370
+ isHerprint,
371
+ volgStatus: false,
372
+ payload: pakbonPayload({ cartId: ci.cartId, barcode: ci.barcode, cartNumber, cartIndex: idx + 1, cartTotal, order: orderInfo, pickDate, lines: pakbonLines }),
373
+ });
374
+ if (ci.bestaand) {
375
+ skipped.push({ label: cartNumber, herkomst: ci.bestaand.herkomst, printer: ci.bestaand.printer, tijd: ci.bestaand.tijd, herprint: () => opdracht(true) });
376
+ return;
377
+ }
378
+ try {
379
+ const jobId = await opdracht(false);
380
+ if (jobId)
381
+ printed++;
341
382
  else {
342
383
  failed++;
343
- reasons.push(`Pakbon ${cartNumber}: ${printFoutMelding(err)}`);
344
- console.warn("[print-all] pakbon mislukt", cartNumber, err);
384
+ reasons.push(`Pakbon ${cartNumber}: de Printwachtrij gaf geen opdracht-id terug.`);
345
385
  }
346
386
  }
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++;
387
+ catch (err) {
388
+ failed++;
389
+ reasons.push(`Pakbon ${cartNumber}: ${printFoutMelding(err)}`);
390
+ console.warn("[print-all] pakbon mislukt", cartNumber, err);
371
391
  }
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",
392
+ }));
393
+ // Verzendbrief/afleverbrief op de achtergrond: eerst de Engine-layout, anders de Floriday-brief.
394
+ const achtergrond = (async () => {
395
+ try {
396
+ const keuze = await fetchShippingNoteLayout({});
397
+ let jobId = null;
398
+ if (keuze.layoutId) {
399
+ jobId = await printLayoutDocument({
400
+ documenttype: keuze.documenttype ?? "afleverbrief",
381
401
  documentnaam: `AFL-${p.order.orderNumber}`,
382
- pdfBase64: pdf.base64,
402
+ layoutId: keuze.layoutId,
403
+ volgStatus: false,
404
+ payload: { order: { ...orderInfo, cartIndex: 1, cartTotal, cartNumber: p.order.orderNumber } },
383
405
  });
384
- printed++;
385
406
  }
407
+ else {
408
+ const { pdf } = await fetchDeliveryNote({ data: { orderRef: p.order.orderNumber } });
409
+ if (!pdf)
410
+ return { printed: 0, failed: 1, reasons: [`geen Engine-layout en geen Floriday-brief beschikbaar voor ${p.order.orderNumber}.`] };
411
+ jobId = await printPdfDocument({ documenttype: "afleverbrief", documentnaam: `AFL-${p.order.orderNumber}`, pdfBase64: pdf.base64, volgStatus: false });
412
+ }
413
+ return jobId ? { printed: 1, failed: 0, reasons: [] } : { printed: 0, failed: 1, reasons: ["de Printwachtrij gaf geen opdracht-id terug."] };
386
414
  }
387
- }
388
- catch (err) {
389
- if (isDubbeleAanvraag(err)) {
390
- skipped++;
391
- }
392
- else {
393
- failed++;
394
- reasons.push(`Verzendbrief ${p.order.orderNumber}: ${printFoutMelding(err)}`);
415
+ catch (err) {
416
+ if (isDubbeleAanvraag(err))
417
+ return { printed: 0, failed: 0, reasons: [] };
395
418
  console.warn("[print-all] verzendbrief mislukt", p.order.orderNumber, err);
419
+ return { printed: 0, failed: 1, reasons: [printFoutMelding(err)] };
396
420
  }
397
- }
398
- return { printed, skipped, failed, reasons };
421
+ })();
422
+ return { printed, skipped, failed, reasons, achtergrond };
399
423
  }
400
424
  /** Meerdere orders die samen in één buffer zitten; één regel in de agenda. */
401
425
  function BufferGroup({ bufferId, orders: dayOrders }) {
@@ -417,11 +441,17 @@ function BufferGroup({ bufferId, orders: dayOrders }) {
417
441
  const fetchCarts = useServerFn(getOrderCartIds);
418
442
  const fetchDeliveryNote = useServerFn(getDeliveryNotePdf);
419
443
  const fetchShippingNoteLayout = useServerFn(getShippingNoteLayout);
444
+ const fetchPakbonInfo = useServerFn(getPakbonCartInfo);
420
445
  const shipState = useContext(ShipStateCtx);
421
446
  const carts = orders.reduce((s, o) => s + (o.carts || 0), 0);
422
447
  const klant = orders.find((o) => o.planned?.order.customerName)?.planned?.order.customerName ?? null;
423
448
  const alleAf = orders.every((o) => shipState.get(refKey(o.ref))?.floridaySent === true);
424
449
  const refs = orders.map((o) => o.ref).filter(Boolean);
450
+ // Alleen Floriday-orders (op Floriday-id); de bron-kolom is hier niet betrouwbaar.
451
+ const bekend = orders.filter((o) => o.planned);
452
+ const alleFloriday = bekend.length > 0 && bekend.every((o) => !!o.planned?.order.salesOrderId);
453
+ // Pickstatus uit de Engine: goedgekeurde scan of door de Engine afgemeld.
454
+ const engineKlaar = (o) => shipState.get(refKey(o.ref))?.approvedAll === true || voortgang(o.status).done;
425
455
  const verzetOrders = orders.map((o) => ({
426
456
  ref: o.ref,
427
457
  customerName: o.planned?.order.customerName ?? "—",
@@ -463,24 +493,20 @@ function BufferGroup({ bufferId, orders: dayOrders }) {
463
493
  if (printing)
464
494
  return;
465
495
  setPrinting(true);
466
- let printed = 0;
467
- let skipped = 0;
468
- let failed = 0;
469
- const reasons = [];
470
496
  try {
471
- for (const o of orders) {
472
- if (!o.planned) {
473
- failed++;
474
- reasons.push(`${o.ref}: ordergegevens niet geladen op deze dag.`);
475
- continue;
476
- }
477
- const res = await printDocumentenVoorOrder(o.planned, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout);
478
- printed += res.printed;
479
- skipped += res.skipped;
480
- failed += res.failed;
481
- reasons.push(...res.reasons);
482
- }
483
- meldPrintUitkomst({ printed, skipped, failed, reasons });
497
+ const uitkomsten = await Promise.all(orders.map(async (o) => o.planned
498
+ ? printDocumentenVoorOrder(o.planned, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout, fetchPakbonInfo)
499
+ : { printed: 0, skipped: [], failed: 1, reasons: [`${o.ref}: ordergegevens niet geladen op deze dag.`], achtergrond: null }));
500
+ const samen = {
501
+ printed: uitkomsten.reduce((t, u) => t + u.printed, 0),
502
+ skipped: uitkomsten.flatMap((u) => u.skipped),
503
+ failed: uitkomsten.reduce((t, u) => t + u.failed, 0),
504
+ reasons: uitkomsten.flatMap((u) => u.reasons),
505
+ achtergrond: null,
506
+ };
507
+ samen.achtergrond = uitkomsten.some((u) => u.achtergrond) ? Promise.resolve({ printed: 0, failed: 0, reasons: [] }) : null;
508
+ meldPrintUitkomst(samen);
509
+ await Promise.all(uitkomsten.map(meldAchtergrond));
484
510
  }
485
511
  catch (err) {
486
512
  toast.error(printFoutMelding(err));
@@ -489,7 +515,7 @@ function BufferGroup({ bufferId, orders: dayOrders }) {
489
515
  setPrinting(false);
490
516
  }
491
517
  };
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) })] }));
518
+ 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(engineKlaar) ? "Klaar voor verzending" : orders.some(engineKlaar) ? "Deels gescand" : "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] && alleFloriday ? _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 ? "In de Printwachtrij…" : "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) })] }));
493
519
  }
494
520
  /** Bestelling die alleen de Engine kent; verdere ordergegevens ontbreken. */
495
521
  /** Knop "Afhandelen (verzonden)" — zet de bestelling in de orderadministratie op Verzonden. */
@@ -541,6 +567,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
541
567
  const fetchCarts = useServerFn(getOrderCartIds);
542
568
  const fetchDeliveryNote = useServerFn(getDeliveryNotePdf);
543
569
  const fetchShippingNoteLayout = useServerFn(getShippingNoteLayout);
570
+ const fetchPakbonInfo = useServerFn(getPakbonCartInfo);
544
571
  const vg = useVoortgang(p.order.orderNumber, engineStatus ?? p.order.status);
545
572
  const linesQuery = useQuery({
546
573
  queryKey: ["order-lines", source, p.order.id],
@@ -553,7 +580,9 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
553
580
  return;
554
581
  setPrinting(true);
555
582
  try {
556
- meldPrintUitkomst(await printDocumentenVoorOrder(p, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout));
583
+ const r = await printDocumentenVoorOrder(p, fetchLines, fetchCarts, fetchDeliveryNote, fetchShippingNoteLayout, fetchPakbonInfo);
584
+ meldPrintUitkomst(r);
585
+ await meldAchtergrond(r);
557
586
  }
558
587
  catch (err) {
559
588
  toast.error(printFoutMelding(err));
@@ -573,7 +602,7 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
573
602
  const src = p.order.source === "floriday" ? "floriday" : "manual";
574
603
  const soId = p.order.salesOrderId ?? (src === "floriday" ? p.order.id : null);
575
604
  return soId ? (_jsx(AutoProcessStatus, { salesOrderId: soId, orderRef: p.order.orderNumber })) : null;
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) => {
605
+ })(), p.order.orderNumber && p.order.salesOrderId ? _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 ? "In de Printwachtrij…" : "Alle documenten afdrukken"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: (e) => {
577
606
  e.stopPropagation();
578
607
  setVerzetOpen(true);
579
608
  }, 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: {
@@ -654,6 +683,7 @@ function KarRow({ cart: c, cartTotal, selected, onToggle, }) {
654
683
  const fetchLines = useServerFn(getOrderLines);
655
684
  const fetchDeliveryNote = useServerFn(getDeliveryNotePdf);
656
685
  const fetchShippingNoteLayout = useServerFn(getShippingNoteLayout);
686
+ const fetchPakbonInfo = useServerFn(getPakbonCartInfo);
657
687
  const printPakbon = async () => {
658
688
  if (bezig)
659
689
  return;
@@ -676,27 +706,35 @@ function KarRow({ cart: c, cartTotal, selected, onToggle, }) {
676
706
  /* pakbon zonder regels blijft mogelijk */
677
707
  }
678
708
  }
679
- const nr = String(c.cartIndex).padStart(2, "0");
709
+ if (!c.cartId)
710
+ throw new Error(`Pakbon ${c.cartNumber}: de Engine heeft voor deze kar nog geen kar-id.`);
711
+ const [ci] = (await fetchPakbonInfo({ data: { cartIds: [c.cartId] } })).carts;
712
+ if (!ci)
713
+ throw new Error(`Pakbon ${c.cartNumber}: geen kar-barcode van de Engine.`);
714
+ const nr = String(c.cartIndex + 1).padStart(2, "0");
680
715
  await printLayoutDocument({
681
716
  documenttype: "pakbon",
682
717
  documentnaam: `PAK-${c.orderRef}-${nr}`,
683
718
  isHerprint: true,
684
- payload: {
719
+ volgStatus: false,
720
+ payload: pakbonPayload({
721
+ cartId: ci.cartId,
722
+ barcode: ci.barcode,
723
+ cartNumber: c.cartNumber,
724
+ cartIndex: c.cartIndex + 1,
725
+ cartTotal,
685
726
  order: {
686
727
  id: p?.order.id ?? c.orderRef,
687
728
  orderNumber: c.orderRef,
688
729
  customerName: c.customerName,
689
730
  country: p?.order.country ?? null,
690
731
  deliveryDate: p?.order.deliveryDate ?? null,
691
- pickDate: new Date().toISOString().slice(0, 10),
692
- cartIndex: c.cartIndex,
693
- cartTotal,
694
- cartNumber: c.cartNumber,
695
- lines: pakbonLines,
696
732
  },
697
- },
733
+ pickDate: new Date().toISOString().slice(0, 10),
734
+ lines: pakbonLines,
735
+ }),
698
736
  });
699
- toast.success(`Pakbon ${c.cartNumber} is naar de printer gestuurd.`);
737
+ toast.success(`Pakbon ${c.cartNumber} als herprint in de Printwachtrij gezet.`);
700
738
  }
701
739
  catch (err) {
702
740
  toast.error(printFoutMelding(err));
@@ -1 +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"}
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,+BAkH3G"}
@@ -18,13 +18,21 @@ export function NuVersturenButton({ orderRef, label = "Nu versturen" }) {
18
18
  const [sending, setSending] = useState(false);
19
19
  const [preview, setPreview] = useState(null);
20
20
  const load = async () => setPreview(await prepare({ data: { orderRef } }));
21
+ const meldFout = (e, standaard) => {
22
+ const t = e instanceof Error ? e.message : standaard;
23
+ const m = /^(.*?)\s*\[([^\]]+)\]$/s.exec(t);
24
+ if (m)
25
+ toast.error(m[1], { description: m[2] });
26
+ else
27
+ toast.error(t);
28
+ };
21
29
  const open = async () => {
22
30
  setLoading(true);
23
31
  try {
24
32
  await load();
25
33
  }
26
34
  catch (e) {
27
- toast.error(e instanceof Error ? e.message : "Belading samenstellen mislukt");
35
+ meldFout(e, "Belading samenstellen mislukt");
28
36
  }
29
37
  finally {
30
38
  setLoading(false);
@@ -35,11 +43,10 @@ export function NuVersturenButton({ orderRef, label = "Nu versturen" }) {
35
43
  try {
36
44
  const r = await send({ data: { orderRef } });
37
45
  for (const x of r.results) {
38
- const text = x.code === "created" || x.code === "already_fulfilled" ? x.message : `${x.code}: ${x.message}`;
39
46
  if (x.code === "created" || x.code === "already_fulfilled")
40
- toast.success(text);
47
+ toast.success(x.message);
41
48
  else
42
- toast.error(text);
49
+ meldFout(new Error(x.message), "Versturen mislukt");
43
50
  }
44
51
  await load();
45
52
  }
@@ -52,5 +59,9 @@ export function NuVersturenButton({ orderRef, label = "Nu versturen" }) {
52
59
  };
53
60
  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
61
  ? _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"] })] })] }) })] }));
62
+ : _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 === "created" || a.code === "already_fulfilled" ? "geaccepteerd" : (a.message ?? a.code)?.replace(/\s*\[[^\]]+\]$/, "")] }, a.createdAt + a.step)))] })), preview.blockers.length > 0 && (_jsx("ul", { className: "list-disc pl-5 text-destructive", children: preview.blockers.map((b) => {
63
+ // Begrijpelijke zin, technische code klein eronder.
64
+ const m = /^(.*?)\s*\[([^\]]+)\]$/s.exec(b);
65
+ return (_jsxs("li", { children: [m ? m[1] : b, m ? _jsx("div", { className: "text-xs text-muted-foreground", children: m[2] }) : null] }, b));
66
+ }) }))] })), _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
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAOjE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,KAAK,IAAI,CAAC;IACxD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAgFD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,EACL,YAAY,EACZ,UAAU,GACX,EAAE,mBAAmB,+BAwKrB"}
1
+ {"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAOjE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,KAAK,IAAI,CAAC;IACxD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAgFD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,EACL,YAAY,EACZ,UAAU,GACX,EAAE,mBAAmB,+BAqKrB"}
@@ -102,9 +102,8 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayCl
102
102
  planten: row?.plantCount ?? 0,
103
103
  verzendklaar: row?.ready ?? 0,
104
104
  voorbereiding: row?.inPreparation ?? 0,
105
- afgehandeld: row
106
- ? Math.max(row.doneCount, row.orders.filter((o) => o.fulfilled || isDoneStatus(o.status)).length)
107
- : 0,
105
+ // Uitsluitend uit de Engine (taak afgemeld); geannuleerde orders zijn al weggelaten.
106
+ afgehandeld: row?.doneCount ?? 0,
108
107
  };
109
108
  }
110
109
  const entries = [];
@@ -114,6 +113,8 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayCl
114
113
  const d = dateForPlanned(p, mode);
115
114
  if (!d || !isSameDay(d, date))
116
115
  continue;
116
+ if (/annul|cancel/i.test(p.order.status ?? ""))
117
+ continue;
117
118
  entries.push({
118
119
  order: p.order,
119
120
  cartCount: (p.planning.pickAssignments ?? []).reduce((sum, a) => sum + a.cartCount, 0),
@@ -6,6 +6,7 @@ export declare function useKnownOrders(): {
6
6
  refs: Set<string>;
7
7
  isKnownRef: (...candidates: (string | null | undefined)[]) => boolean;
8
8
  isFulfilledRef: (...candidates: (string | null | undefined)[]) => boolean;
9
+ isCancelledRef: (...candidates: (string | null | undefined)[]) => boolean;
9
10
  isReady: boolean;
10
11
  isLoading: boolean;
11
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useKnownOrders.d.ts","sourceRoot":"","sources":["../../src/hooks/useKnownOrders.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,wBAAgB,cAAc;;gCAyCV,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,KAAG,OAAO;oCAavC,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,KAAG,OAAO;;;EAW1D"}
1
+ {"version":3,"file":"useKnownOrders.d.ts","sourceRoot":"","sources":["../../src/hooks/useKnownOrders.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,wBAAgB,cAAc;;gCA+DV,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,KAAG,OAAO;oCAavC,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,KAAG,OAAO;oCA3BvC,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,KAAG,OAAO;;;EAsC1D"}
@@ -54,6 +54,25 @@ export function useKnownOrders() {
54
54
  }
55
55
  return set;
56
56
  }, [query.data]);
57
+ /** Referenties die in de Verkoop-module geannuleerd zijn; tellen nergens als open. */
58
+ const cancelledRefs = useMemo(() => {
59
+ const set = new Set();
60
+ for (const o of query.data?.orders ?? []) {
61
+ if (!/annul|cancel/i.test(String(o.status ?? "")))
62
+ continue;
63
+ const id = keyOf(o.id);
64
+ const num = keyOf(o.orderNumber);
65
+ if (id)
66
+ set.add(id);
67
+ if (num)
68
+ set.add(num);
69
+ }
70
+ return set;
71
+ }, [query.data]);
72
+ const isCancelledRef = useCallback((...candidates) => candidates.some((c) => {
73
+ const k = keyOf(c);
74
+ return !!k && cancelledRefs.has(k);
75
+ }), [cancelledRefs]);
57
76
  // Zodra de lijst geladen is filteren we, ook als er niets open staat.
58
77
  const isReady = !query.isLoading && !!query.data && !query.data.error;
59
78
  /** Onbekende referentie? Dan niet tonen. Zolang de lijst laadt: niets filteren. */
@@ -76,5 +95,5 @@ export function useKnownOrders() {
76
95
  }
77
96
  return false;
78
97
  }, [fulfilledRefs]);
79
- return { refs, isKnownRef, isFulfilledRef, isReady, isLoading: query.isLoading };
98
+ return { refs, isKnownRef, isFulfilledRef, isCancelledRef, isReady, isLoading: query.isLoading };
80
99
  }
@@ -1 +1 @@
1
- {"version":3,"file":"usePickAgenda.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickAgenda.ts"],"names":[],"mappings":"AAQA,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAwCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;;;;;EA6GnE"}
1
+ {"version":3,"file":"usePickAgenda.d.ts","sourceRoot":"","sources":["../../src/hooks/usePickAgenda.ts"],"names":[],"mappings":"AAQA,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAwCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;;;;;EA8GnE"}