@flowselections/floriday-afhandeling-module 1.0.52 → 1.0.54
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/DagDetailDialog.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.js +183 -145
- package/dist-lib/components/afhandeling/NuVersturenButton.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/NuVersturenButton.js +14 -2
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +4 -3
- package/dist-lib/hooks/useKnownOrders.d.ts +1 -0
- package/dist-lib/hooks/useKnownOrders.d.ts.map +1 -1
- package/dist-lib/hooks/useKnownOrders.js +20 -1
- package/dist-lib/hooks/usePickAgenda.d.ts.map +1 -1
- package/dist-lib/hooks/usePickAgenda.js +7 -3
- package/dist-lib/lib/authGateway.server.d.ts.map +1 -1
- package/dist-lib/lib/authGateway.server.js +3 -2
- package/dist-lib/lib/cartAssignments.functions.d.ts +29 -0
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.js +64 -0
- package/dist-lib/lib/floridayFulfillmentSend.server.d.ts +5 -0
- package/dist-lib/lib/floridayFulfillmentSend.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayFulfillmentSend.server.js +15 -6
- package/dist-lib/lib/floridayLoading.functions.js +1 -1
- package/package.json +1 -1
|
@@ -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;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
|
-
|
|
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}
|
|
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
|
-
|
|
257
|
-
|
|
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
|
|
269
|
-
*
|
|
270
|
-
*
|
|
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
|
-
|
|
286
|
-
engineCarts =
|
|
287
|
-
|
|
288
|
-
|
|
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:
|
|
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
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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}:
|
|
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
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
await
|
|
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
|
-
|
|
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
|
-
|
|
389
|
-
|
|
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
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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(
|
|
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
|
-
|
|
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 ? "
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
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,+
|
|
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,+BAmH3G"}
|
|
@@ -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
|
-
|
|
35
|
+
meldFout(e, "Belading samenstellen mislukt");
|
|
28
36
|
}
|
|
29
37
|
finally {
|
|
30
38
|
setLoading(false);
|
|
@@ -52,5 +60,9 @@ export function NuVersturenButton({ orderRef, label = "Nu versturen" }) {
|
|
|
52
60
|
};
|
|
53
61
|
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
62
|
? _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) =>
|
|
63
|
+
: _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) => {
|
|
64
|
+
// Begrijpelijke zin, technische code klein eronder.
|
|
65
|
+
const m = /^(.*?)\s*\[([^\]]+)\]$/s.exec(b);
|
|
66
|
+
return (_jsxs("li", { children: [m ? m[1] : b, m ? _jsx("div", { className: "text-xs text-muted-foreground", children: m[2] }) : null] }, b));
|
|
67
|
+
}) }))] })), _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
68
|
}
|
|
@@ -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,+
|
|
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
|
-
|
|
106
|
-
|
|
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;;
|
|
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;;;;;
|
|
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"}
|
|
@@ -84,7 +84,7 @@ export function usePickAgenda(from, to) {
|
|
|
84
84
|
// Orders die de Verkoop-module niet kent horen hier niet te staan, en orders
|
|
85
85
|
// die de Engine ná hun leverdatum plant gaan terug naar hun eigen dag. De
|
|
86
86
|
// dagtotalen worden opnieuw opgeteld uit wat overblijft.
|
|
87
|
-
const { isKnownRef, isFulfilledRef } = useKnownOrders();
|
|
87
|
+
const { isKnownRef, isFulfilledRef, isCancelledRef } = useKnownOrders();
|
|
88
88
|
const { correctPickDate } = useOrderPickDates(wideFrom, wideTo);
|
|
89
89
|
const days = useMemo(() => {
|
|
90
90
|
const perDay = new Map();
|
|
@@ -94,6 +94,9 @@ export function usePickAgenda(from, to) {
|
|
|
94
94
|
for (const o of d.orders) {
|
|
95
95
|
if (!isKnownRef(o.orderRef))
|
|
96
96
|
continue;
|
|
97
|
+
// Geannuleerde orders tellen niet als open en niet mee in de dag.
|
|
98
|
+
if (isCancelledRef(o.orderRef) || /annul|cancel/i.test(o.status))
|
|
99
|
+
continue;
|
|
97
100
|
const dag = correctPickDate(o.orderRef, d.pickDate);
|
|
98
101
|
const list = perDay.get(dag) ?? [];
|
|
99
102
|
list.push({ ...o, fulfilled: isFulfilledRef(o.orderRef) });
|
|
@@ -106,7 +109,8 @@ export function usePickAgenda(from, to) {
|
|
|
106
109
|
continue;
|
|
107
110
|
if (to && pickDate > to)
|
|
108
111
|
continue;
|
|
109
|
-
|
|
112
|
+
// "Afgehandeld" volgt uitsluitend de Engine (taak afgemeld), niet de Verkoop-status.
|
|
113
|
+
const doneCount = orders.filter((o) => o.status === "done" || o.status === "completed").length;
|
|
110
114
|
const ready = orders.filter((o) => o.status === "ready" || o.status === "done").length;
|
|
111
115
|
out.push({
|
|
112
116
|
pickDate,
|
|
@@ -122,7 +126,7 @@ export function usePickAgenda(from, to) {
|
|
|
122
126
|
}
|
|
123
127
|
out.sort((a, b) => a.pickDate.localeCompare(b.pickDate));
|
|
124
128
|
return out;
|
|
125
|
-
}, [query.data, isKnownRef, isFulfilledRef, correctPickDate, from, to]);
|
|
129
|
+
}, [query.data, isKnownRef, isFulfilledRef, isCancelledRef, correctPickDate, from, to]);
|
|
126
130
|
const byDate = new Map();
|
|
127
131
|
for (const d of days)
|
|
128
132
|
byDate.set(d.pickDate, d);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authGateway.server.d.ts","sourceRoot":"","sources":["../../src/lib/authGateway.server.ts"],"names":[],"mappings":"AA6BA,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAqB9D;AA2BD,iFAAiF;AACjF,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CA6BhC;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB/F;AA4BD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"authGateway.server.d.ts","sourceRoot":"","sources":["../../src/lib/authGateway.server.ts"],"names":[],"mappings":"AA6BA,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAqB9D;AA2BD,iFAAiF;AACjF,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CA6BhC;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB/F;AA4BD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA0ElD"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// message = `${timestamp}.${JSON.stringify(body)}`
|
|
7
7
|
// signature = hex(HMAC-SHA256(AUTH_GATEWAY_HMAC_SECRET, message))
|
|
8
8
|
// headers = { "X-Signature": signature, "X-Timestamp": timestamp }
|
|
9
|
-
// Timestamp =
|
|
9
|
+
// Timestamp = epoch-milliseconden als tekst (String(Date.now())), ±5 min venster.
|
|
10
10
|
// Web Crypto (browser/Node 15+/Workers) — geen node:crypto, want dist-lib
|
|
11
11
|
// wordt ook in de client-bundle van consumer-shells opgenomen.
|
|
12
12
|
import { createClient } from "@supabase/supabase-js";
|
|
@@ -161,7 +161,8 @@ export async function fetchDeliveryNotePdf(salesOrderId) {
|
|
|
161
161
|
deliveryOrderId: deliveryOrderIds[0],
|
|
162
162
|
};
|
|
163
163
|
const bodyStr = JSON.stringify(payload);
|
|
164
|
-
|
|
164
|
+
// De gateway verwacht epoch-milliseconden; we tekenen over precies deze waarde.
|
|
165
|
+
const timestamp = String(Date.now());
|
|
165
166
|
const signature = await signBody(secret, timestamp, bodyStr);
|
|
166
167
|
try {
|
|
167
168
|
const base = await resolveGatewayBaseServer();
|
|
@@ -77,6 +77,8 @@ export declare const getOrderLines: import("@tanstack/start-client-core").Requir
|
|
|
77
77
|
}>>;
|
|
78
78
|
export interface DayCartContent {
|
|
79
79
|
orderRef: string;
|
|
80
|
+
/** Engine-kar-id; leeg als de Engine geen kar-id gaf. */
|
|
81
|
+
cartId: string | null;
|
|
80
82
|
cartNumber: number;
|
|
81
83
|
layersUsed: number | null;
|
|
82
84
|
maxLayers: number | null;
|
|
@@ -133,4 +135,31 @@ export declare const getOrderCartIds: import("@tanstack/start-client-core").Requ
|
|
|
133
135
|
cartNumber: number;
|
|
134
136
|
}[];
|
|
135
137
|
}>>;
|
|
138
|
+
export interface PakbonCartInfo {
|
|
139
|
+
cartId: string;
|
|
140
|
+
/** Vaste LC-code van de kar (logistics_ensure_cart_barcode), dezelfde als op het pickstation. */
|
|
141
|
+
barcode: string;
|
|
142
|
+
/** Bestaande pakbon voor deze kar (documenttype pakbon, niet mislukt/geannuleerd), zoals Pickschermen controleert. */
|
|
143
|
+
bestaand: {
|
|
144
|
+
herkomst: string;
|
|
145
|
+
printer: string | null;
|
|
146
|
+
tijd: string;
|
|
147
|
+
status: string;
|
|
148
|
+
} | null;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Per Engine-kar de vaste kar-barcode en de bestaande pakbon in de Printwachtrij.
|
|
152
|
+
* Match uitsluitend op cart_id; verzendbrieven tellen niet mee.
|
|
153
|
+
*/
|
|
154
|
+
export declare const getPakbonCartInfo: import("@tanstack/start-client-core").RequiredFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
155
|
+
supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
|
|
156
|
+
userId: string;
|
|
157
|
+
claims: import("@supabase/auth-js").JwtPayload;
|
|
158
|
+
}, undefined, undefined, undefined>], (d: {
|
|
159
|
+
cartIds: string[];
|
|
160
|
+
}) => {
|
|
161
|
+
cartIds: string[];
|
|
162
|
+
}, Promise<{
|
|
163
|
+
carts: PakbonCartInfo[];
|
|
164
|
+
}>>;
|
|
136
165
|
//# sourceMappingURL=cartAssignments.functions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cartAssignments.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cartAssignments.functions.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,gBAAgB,GAAG,QAAQ,CAAC;AACnE,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,WAAW,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAUD,eAAO,MAAM,iBAAiB;;;;;eAEuB,YAAY,EAAE;GAQ/D,CAAC;AAEL,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;CACjC;AAED,eAAO,MAAM,QAAQ;;;;0CAEC,aAAa;QACiB,IAAI;cAAY,YAAY;GAqB5E,CAAC;AAEL,eAAO,MAAM,iBAAiB;;;;0CAER;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;aAArD,MAAM;iBAAe,WAAW;eAAa,MAAM;;QAChC,IAAI;GAUpD,CAAC;AAEL,eAAO,MAAM,qBAAqB;;;;;QAEY,IAAI;aAAW,MAAM;GAQ/D,CAAC;AAEL,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa;;;;0CAEJ;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE;aAAlC,MAAM;iBAAe,WAAW;;WACV,SAAS,EAAE;GA0D9D,CAAC;AAEL,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,sEAAsE;IACtE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,OAAO,GAAG,eAAe,GAAG,aAAa,CAAC;AACpF,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAE/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,wFAAwF;IACxF,WAAW,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,YAAY,EAAE,OAAO,CAAC;CACvB;AAKD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;0CAET;IAAE,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE;;;WAMI,cAAc,EAAE;YAAgB,gBAAgB,EAAE;
|
|
1
|
+
{"version":3,"file":"cartAssignments.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cartAssignments.functions.ts"],"names":[],"mappings":"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"}
|
|
@@ -197,6 +197,7 @@ export const getDayCartContents = createServerFn({ method: "POST" })
|
|
|
197
197
|
const lines = arr(k?.lines);
|
|
198
198
|
carts.push({
|
|
199
199
|
orderRef,
|
|
200
|
+
cartId: typeof k?.cartId === "string" && k.cartId ? k.cartId : null,
|
|
200
201
|
cartNumber: num(k?.cartNumber) ?? idx + 1,
|
|
201
202
|
layersUsed: num(s.layersUsed ?? s.totalLayersUsed),
|
|
202
203
|
maxLayers: num(s.maxLayers),
|
|
@@ -255,3 +256,66 @@ export const getOrderCartIds = createServerFn({ method: "POST" })
|
|
|
255
256
|
.filter((k) => k.cartId);
|
|
256
257
|
return { carts };
|
|
257
258
|
});
|
|
259
|
+
/**
|
|
260
|
+
* Per Engine-kar de vaste kar-barcode en de bestaande pakbon in de Printwachtrij.
|
|
261
|
+
* Match uitsluitend op cart_id; verzendbrieven tellen niet mee.
|
|
262
|
+
*/
|
|
263
|
+
export const getPakbonCartInfo = createServerFn({ method: "POST" })
|
|
264
|
+
.middleware([requireSupabaseAuth])
|
|
265
|
+
.inputValidator((d) => ({
|
|
266
|
+
cartIds: Array.from(new Set((d?.cartIds ?? []).map((x) => String(x).trim()).filter(Boolean))).slice(0, 200),
|
|
267
|
+
}))
|
|
268
|
+
.handler(async ({ data, context }) => {
|
|
269
|
+
const supabase = context.supabase;
|
|
270
|
+
if (data.cartIds.length === 0)
|
|
271
|
+
return { carts: [] };
|
|
272
|
+
const barcodes = new Map();
|
|
273
|
+
await Promise.all(data.cartIds.map(async (id) => {
|
|
274
|
+
const { data: bc, error } = await supabase.rpc("logistics_ensure_cart_barcode", { _cart_id: id });
|
|
275
|
+
if (error)
|
|
276
|
+
throw new Error(`Kar-barcode niet opgehaald: ${error.message}`);
|
|
277
|
+
if (typeof bc !== "string" || !bc)
|
|
278
|
+
throw new Error("De Engine gaf geen kar-barcode terug.");
|
|
279
|
+
barcodes.set(id, bc);
|
|
280
|
+
}));
|
|
281
|
+
const { data: jobs, error } = await supabase
|
|
282
|
+
.from("print_jobs")
|
|
283
|
+
.select("payload, herkomst, gebruiker_naam, created_at, status, printer_id")
|
|
284
|
+
.eq("documenttype", "pakbon")
|
|
285
|
+
.not("status", "in", "(mislukt,geannuleerd)")
|
|
286
|
+
.in("payload->>cart_id", data.cartIds)
|
|
287
|
+
.order("created_at", { ascending: true });
|
|
288
|
+
if (error)
|
|
289
|
+
throw new Error(`Printwachtrij niet gelezen: ${error.message}`);
|
|
290
|
+
const printerIds = [...new Set((jobs ?? []).map((j) => j.printer_id).filter(Boolean))];
|
|
291
|
+
const printerNaam = new Map();
|
|
292
|
+
if (printerIds.length) {
|
|
293
|
+
const { data: pr } = await supabase.from("printers").select("id, naam").in("id", printerIds);
|
|
294
|
+
for (const p of pr ?? [])
|
|
295
|
+
printerNaam.set(p.id, p.naam);
|
|
296
|
+
}
|
|
297
|
+
const eerste = new Map();
|
|
298
|
+
for (const j of jobs ?? []) {
|
|
299
|
+
const cid = j?.payload?.cart_id;
|
|
300
|
+
if (typeof cid === "string" && !eerste.has(cid))
|
|
301
|
+
eerste.set(cid, j);
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
carts: data.cartIds.map((id) => {
|
|
305
|
+
const j = eerste.get(id);
|
|
306
|
+
const bron = j ? (j.payload?.source ?? j.herkomst ?? j.gebruiker_naam ?? "onbekend") : null;
|
|
307
|
+
return {
|
|
308
|
+
cartId: id,
|
|
309
|
+
barcode: barcodes.get(id),
|
|
310
|
+
bestaand: j
|
|
311
|
+
? {
|
|
312
|
+
herkomst: String(bron) === "afhandeling" ? "Afhandeling" : String(bron).includes("pick") ? "het pickstation" : String(bron),
|
|
313
|
+
printer: j.printer_id ? printerNaam.get(j.printer_id) ?? null : null,
|
|
314
|
+
tijd: j.created_at,
|
|
315
|
+
status: j.status,
|
|
316
|
+
}
|
|
317
|
+
: null,
|
|
318
|
+
};
|
|
319
|
+
}),
|
|
320
|
+
};
|
|
321
|
+
});
|
|
@@ -2,6 +2,11 @@ export interface GatewayResult {
|
|
|
2
2
|
httpStatus: number;
|
|
3
3
|
body: any;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Begrijpelijke zin met de echte reden (veld error/message/errors van het antwoord),
|
|
7
|
+
* gevolgd door de technische code tussen [ ] die het scherm klein toont.
|
|
8
|
+
*/
|
|
9
|
+
export declare function gatewayFoutTekst(wat: string, r: GatewayResult): string;
|
|
5
10
|
export interface FulfillmentRequestStatus {
|
|
6
11
|
fulfillmentRequestId: string;
|
|
7
12
|
deliveryOrderId: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floridayFulfillmentSend.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayFulfillmentSend.server.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;CACX;
|
|
1
|
+
{"version":3,"file":"floridayFulfillmentSend.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayFulfillmentSend.server.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;CACX;AA6BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,GAAG,MAAM,CAMtE;AAED,MAAM,WAAW,wBAAwB;IACvC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AACD,MAAM,WAAW,sBAAsB;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AACD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,wBAAwB,EAAE,CAAC;IAChD,iBAAiB,EAAE,sBAAsB,EAAE,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,aAAa,EAAE,MAAM,EAAE,EACvB,mBAAmB,GAAE,MAAM,EAAO,GACjC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAoCxC;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAEnG"}
|
|
@@ -9,7 +9,8 @@ async function signedPost(path, payload) {
|
|
|
9
9
|
const secret = await getFloridayGatewaySecret(); // throws als het ontbreekt
|
|
10
10
|
const base = await resolveGatewayBaseServer(); // throws als het ontbreekt
|
|
11
11
|
const bodyStr = JSON.stringify(payload);
|
|
12
|
-
|
|
12
|
+
// De gateway verwacht epoch-milliseconden; we tekenen over precies deze waarde.
|
|
13
|
+
const timestamp = String(Date.now());
|
|
13
14
|
const signature = await signBody(secret, timestamp, bodyStr);
|
|
14
15
|
const res = await fetch(`${base}/api/public/gateway/${path}`, {
|
|
15
16
|
method: "POST",
|
|
@@ -29,6 +30,17 @@ async function signedPost(path, payload) {
|
|
|
29
30
|
}
|
|
30
31
|
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
31
32
|
const str = (v) => (typeof v === "string" && v ? v : null);
|
|
33
|
+
/**
|
|
34
|
+
* Begrijpelijke zin met de echte reden (veld error/message/errors van het antwoord),
|
|
35
|
+
* gevolgd door de technische code tussen [ ] die het scherm klein toont.
|
|
36
|
+
*/
|
|
37
|
+
export function gatewayFoutTekst(wat, r) {
|
|
38
|
+
const b = r.body ?? {};
|
|
39
|
+
const reden = [str(b.error), str(b.message), ...arr(b.errors).map((e) => (typeof e === "string" ? e : str(e?.message)))]
|
|
40
|
+
.filter((x, i, a) => !!x && a.indexOf(x) === i && x !== b.code).join(" — ");
|
|
41
|
+
const tech = [str(b.code), `HTTP ${r.httpStatus}`].filter(Boolean).join(" · ");
|
|
42
|
+
return `Floriday-authenticatie weigerde ${wat}${reden ? `: ${reden}` : "."} [${tech}]`;
|
|
43
|
+
}
|
|
32
44
|
/**
|
|
33
45
|
* Statusoverzicht (Floriday-authenticatie 1.0.64), in porties van maximaal 100.
|
|
34
46
|
* Exact contract per order: salesOrderId, found, salesOrderStatus, floridayStage,
|
|
@@ -46,11 +58,8 @@ export async function fetchFulfillmentStatus(salesOrderIds, fulfillmentOrderIds
|
|
|
46
58
|
salesOrderIds: ids.slice(i, i + 100),
|
|
47
59
|
...(foIds.length ? { fulfillmentOrderIds: foIds, fulfillmentOrderId: foIds[0] } : {}),
|
|
48
60
|
});
|
|
49
|
-
if (r.httpStatus >= 400 || !r.body)
|
|
50
|
-
|
|
51
|
-
.filter((x) => typeof x === "string" && x).join(" — ");
|
|
52
|
-
throw new Error(`Statusoverzicht van Floriday-authenticatie mislukt (HTTP ${r.httpStatus}${detail ? `: ${detail}` : ""}).`);
|
|
53
|
-
}
|
|
61
|
+
if (r.httpStatus >= 400 || !r.body)
|
|
62
|
+
throw new Error(gatewayFoutTekst("het statusoverzicht", r));
|
|
54
63
|
const rows = Array.isArray(r.body) ? r.body : r.body.orders;
|
|
55
64
|
if (!Array.isArray(rows))
|
|
56
65
|
throw new Error("Statusoverzicht heeft geen lijst met orders.");
|
|
@@ -326,7 +326,7 @@ export const sendFloridayLoading = createServerFn({ method: "POST" })
|
|
|
326
326
|
const code = String(body?.code ?? (httpStatus && httpStatus < 400 ? "ok" : `http_${httpStatus}`));
|
|
327
327
|
const accepted = httpStatus === 200 && body?.ok === true && ACCEPTED.has(code);
|
|
328
328
|
const message = accepted ? (code === "created" ? "Belading verstuurd, verzendbrief volgt via de Engine." : "Belading was al verstuurd (niets dubbel aangemaakt), verzendbrief volgt via de Engine.")
|
|
329
|
-
: arr(body?.errors).map((e) => (typeof e === "string" ? e : e?.message ?? JSON.stringify(e))).join("; ") || body?.message || code;
|
|
329
|
+
: [typeof body?.error === "string" ? body.error : null, ...arr(body?.errors).map((e) => (typeof e === "string" ? e : e?.message ?? JSON.stringify(e)))].filter(Boolean).join("; ") || body?.message || code;
|
|
330
330
|
await log(s, {
|
|
331
331
|
step: "send", http_status: httpStatus, code, message,
|
|
332
332
|
warnings: arr(body?.warnings), skipped_requests: arr(body?.skippedRequests), request_summary: summary,
|