@flowselections/floriday-afhandeling-module 1.0.61 → 1.0.64
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/AutoSendStatus.d.ts +9 -2
- package/dist-lib/components/afhandeling/AutoSendStatus.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/AutoSendStatus.js +70 -6
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/DagDetailDialog.js +40 -24
- package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/LeveringenPage.js +3 -1
- package/dist-lib/components/afhandeling/NuVersturenButton.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/NuVersturenButton.js +4 -4
- package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PickAgendaView.js +9 -7
- package/dist-lib/components/afhandeling/ScanControleView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/ScanControleView.js +2 -2
- package/dist-lib/components/afhandeling/SignupMailMoments.d.ts +8 -0
- package/dist-lib/components/afhandeling/SignupMailMoments.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/SignupMailMoments.js +72 -0
- package/dist-lib/components/afhandeling/VerzetOrderDialog.js +3 -3
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +6 -2
- package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -1
- package/dist-lib/components/settings/AfhandelingSettingsCard.js +47 -2
- package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPlanning.js +7 -6
- package/dist-lib/hooks/usePickAgenda.d.ts +4 -0
- package/dist-lib/hooks/usePickAgenda.d.ts.map +1 -1
- package/dist-lib/hooks/usePickAgenda.js +36 -5
- package/dist-lib/integrations/supabase/types.d.ts +335 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/carrierSignup.functions.d.ts +100 -0
- package/dist-lib/lib/carrierSignup.functions.d.ts.map +1 -0
- package/dist-lib/lib/carrierSignup.functions.js +117 -0
- package/dist-lib/lib/cartAssignments.functions.d.ts +4 -0
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.js +5 -1
- package/dist-lib/lib/floridayLoading.functions.d.ts +7 -0
- package/dist-lib/lib/floridayLoading.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayLoading.functions.js +11 -4
- package/dist-lib/lib/printing.js +1 -1
- package/dist-lib/lib/serverRoutes/autoSend.handler.d.ts +2 -1
- package/dist-lib/lib/serverRoutes/autoSend.handler.d.ts.map +1 -1
- package/dist-lib/lib/serverRoutes/autoSend.handler.js +26 -5
- package/dist-lib/lib/serverRoutes/dispatchCarrierSignups.handler.d.ts +1 -1
- package/dist-lib/lib/serverRoutes/dispatchCarrierSignups.handler.d.ts.map +1 -1
- package/dist-lib/lib/serverRoutes/dispatchCarrierSignups.handler.js +2 -325
- package/dist-lib/lib/serverRoutes/index.d.ts +1 -0
- package/dist-lib/lib/serverRoutes/index.d.ts.map +1 -1
- package/dist-lib/lib/serverRoutes/index.js +1 -0
- package/dist-lib/lib/signupMailText.d.ts +4 -0
- package/dist-lib/lib/signupMailText.d.ts.map +1 -0
- package/dist-lib/lib/signupMailText.js +35 -0
- package/package.json +12 -1
|
@@ -171,7 +171,7 @@ export function VerzetOrderDialog({ open, orderRef, carrierTarget, onOpenChange
|
|
|
171
171
|
`(${result.next?.pickupFrom ?? "—"}–${result.next?.pickupTo ?? "—"}), ` +
|
|
172
172
|
`leverdatum ${fmtDate(result.next?.deliveryDate)}. ` +
|
|
173
173
|
(result.customerNotified
|
|
174
|
-
? "De
|
|
174
|
+
? "De klant is per e-mail geïnformeerd."
|
|
175
175
|
: "Klant is niet geïnformeerd."));
|
|
176
176
|
onOpenChange(false);
|
|
177
177
|
}
|
|
@@ -193,11 +193,11 @@ export function VerzetOrderDialog({ open, orderRef, carrierTarget, onOpenChange
|
|
|
193
193
|
}
|
|
194
194
|
void submit(false);
|
|
195
195
|
};
|
|
196
|
-
return (_jsxs(Dialog, { open: open, onOpenChange: onOpenChange, children: [_jsxs(ResponsiveDialogContent, { size: "lg", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsxs(DialogTitle, { children: ["Order verzetten \u2014 ", orderRef] }), _jsx(DialogDescription, { children: "De
|
|
196
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: onOpenChange, children: [_jsxs(ResponsiveDialogContent, { size: "lg", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsxs(DialogTitle, { children: ["Order verzetten \u2014 ", orderRef] }), _jsx(DialogDescription, { children: "De planning wordt automatisch aangepast." })] }), _jsxs(ResponsiveDialogBody, { className: "space-y-4", children: [_jsxs("div", { className: "rounded-md border p-3 space-y-2", children: [_jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Pickmoment (dag waarop de order gemaakt wordt)" }), pickMoments.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen pickmoment bekend." })) : (_jsxs(_Fragment, { children: [_jsxs("p", { className: "text-sm", children: ["Nu ingepland: ", fmtDateTime(pickMoments[0]?.plannedStart)] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Nieuwe pickdag" }), _jsx(Input, { type: "date", value: pickDay, onChange: (e) => setPickDayValue(e.target.value), className: "sm:w-56" })] }), pickDayChanged && (_jsxs("p", { className: "text-xs text-muted-foreground", children: [pickMoments.length, " pick-taak(en) worden naar deze dag verzet; het tijdstip blijft gelijk."] }))] }))] }), _jsxs("div", { className: "rounded-md border p-3 space-y-2", children: [_jsxs("p", { className: "text-xs font-medium text-muted-foreground", children: ["Vervoerder", carrier ? `: ${carrier.name}` : ""] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Vervoersdatum" }), _jsx(Input, { type: "date", value: pickupDate, onChange: (e) => setPickupDate(e.target.value), className: "sm:w-56" })] }), carrierMoments.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen vervoerder gekoppeld \u2014 aanmeldtijden zijn niet bekend." })) : (_jsxs(_Fragment, { children: [_jsxs("p", { className: "text-sm", children: ["Huidige aanmeldtijd: ", pickupFrom || "—", pickupTo && pickupTo !== pickupFrom ? `–${pickupTo}` : ""] }), _jsx("div", { className: "flex flex-wrap gap-2", children: carrierMoments.map((m, i) => {
|
|
197
197
|
const active = pickupFrom === m.signup_time;
|
|
198
198
|
return (_jsxs(Button, { type: "button", size: "sm", variant: active ? "default" : "outline", onClick: () => {
|
|
199
199
|
setPickupFrom(m.signup_time);
|
|
200
200
|
setPickupTo(m.signup_time);
|
|
201
201
|
}, children: [m.signup_time, _jsxs("span", { className: "ml-1 text-xs opacity-70", children: ["(", m.signup_days, " wd vooraf \u00B7 ophalen ", m.pickup_time, ")"] })] }, `${m.signup_time}-${i}`));
|
|
202
|
-
}) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Kies een aanmeldtijd van deze vervoerder." })] }))] }), preview?.current && (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Huidig aanmeldmoment: ", fmtDate(preview.current.pickupDate), " ", preview.current.pickupFrom ?? "—", "\u2013", preview.current.pickupTo ?? "—", " \u00B7 leverdatum ", fmtDate(preview.current.deliveryDate)] })), loadingPreview && _jsx("p", { className: "text-sm text-muted-foreground", children: "Voorvertoning ophalen\u2026" }), preview && preview.ok === false && (_jsx("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive", children: preview.error ?? "
|
|
202
|
+
}) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Kies een aanmeldtijd van deze vervoerder." })] }))] }), preview?.current && (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Huidig aanmeldmoment: ", fmtDate(preview.current.pickupDate), " ", preview.current.pickupFrom ?? "—", "\u2013", preview.current.pickupTo ?? "—", " \u00B7 leverdatum ", fmtDate(preview.current.deliveryDate)] })), loadingPreview && _jsx("p", { className: "text-sm text-muted-foreground", children: "Voorvertoning ophalen\u2026" }), preview && preview.ok === false && (_jsx("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive", children: preview.error ?? "Deze wijziging kan nu niet worden verwerkt." })), preview && preview.ok !== false && (_jsxs("div", { className: "rounded-md border bg-muted/40 p-3 text-sm space-y-2", children: [_jsx("p", { children: summary }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [preview.affectedTasks ?? 0, " taken worden opnieuw ingepland."] }), preview.planLocked && (_jsx(Badge, { variant: "outline", children: "Deze order ligt vast en kan nu niet worden verzet." }))] })), needsCustomerChoice && (_jsxs("div", { className: "space-y-1 rounded-md border p-3", children: [_jsx(Label, { children: "Reden voor de klantmelding (optioneel)" }), _jsx(Textarea, { value: reason, onChange: (e) => setReason(e.target.value), maxLength: 500, placeholder: "Bijv. Aanvoer bloemen vertraagd" })] })), history.length > 0 && (_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Verzetgeschiedenis" }), _jsx("ul", { className: "space-y-1 text-xs text-muted-foreground", children: history.map((h) => (_jsxs("li", { children: [new Date(h.created_at).toLocaleString("nl-NL"), " \u2014", " ", String(h.direction ?? ""), " ", String(h.reason ?? "")] }, h.id))) })] }))] }), _jsxs(ResponsiveDialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Annuleren" }), _jsx(Button, { onClick: handleVerzetten, disabled: saving || loadingPreview || (!pickDayChanged && (!transportChanged || blocked)), children: saving ? "Opslaan…" : "Verzetten" })] })] }), _jsx(AlertDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Klant informeren?" }), _jsx(AlertDialogDescription, { children: "De leverdatum is gewijzigd naar een latere datum. Wilt u de klant hierover informeren?" })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { onClick: () => void submit(false), children: "Nee" }), _jsx(AlertDialogAction, { onClick: () => void submit(true), children: "Ja" })] })] }) })] }));
|
|
203
203
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAQjE,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;AAiGD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,EACL,YAAY,EACZ,UAAU,GACX,EAAE,mBAAmB,+BAsMrB"}
|
|
@@ -10,6 +10,7 @@ import { useCapacityCheck } from "../../hooks/useCapacityCheck";
|
|
|
10
10
|
import { usePickAgenda } from "../../hooks/usePickAgenda";
|
|
11
11
|
import { useConsistencyCheck } from "../../hooks/useConsistencyCheck";
|
|
12
12
|
import { CapacityWarning } from "./CapacityWarning";
|
|
13
|
+
import { SignupMailMoments } from "./SignupMailMoments";
|
|
13
14
|
import { toDayKey } from "../../lib/logisticsEngine/capacity";
|
|
14
15
|
const SHIPPED = new Set(["verzonden", "gereed voor facturatie", "gefactureerd", "geleverd", "afgeleverd", "afgerond", "afgehandeld", "afgemeld", "shipped", "delivered", "completed", "invoiced"]);
|
|
15
16
|
/** Eén indeling per order. Floriday herkend op Floriday-id; afmeldstand uit de order. */
|
|
@@ -205,7 +206,7 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayCl
|
|
|
205
206
|
d.setHours(0, 0, 0, 0);
|
|
206
207
|
setCursor(startOfWeek(d));
|
|
207
208
|
};
|
|
208
|
-
return (_jsxs("div", { className: "flex h-full flex-col gap-4 overflow-hidden", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title ?? headerLabel }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: goPrev, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), " Vorige week"] }), _jsx(Button, { variant: "outline", size: "sm", onClick: goToday, children: "Deze week" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: goNext, children: ["Volgende week ", _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })] })] }), misaligned && (_jsx("div", { className: "rounded-md border bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: "
|
|
209
|
+
return (_jsxs("div", { className: "flex h-full flex-col gap-4 overflow-hidden", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title ?? headerLabel }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: goPrev, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), " Vorige week"] }), _jsx(Button, { variant: "outline", size: "sm", onClick: goToday, children: "Deze week" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: goNext, children: ["Volgende week ", _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })] })] }), misaligned && (_jsx("div", { className: "rounded-md border bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: "De aantallen worden bijgewerkt." })), _jsxs("div", { className: "grid shrink-0 grid-cols-1 gap-3 sm:grid-cols-3 lg:grid-cols-6", children: [_jsx(SummaryCard, { label: MODE_LABELS[mode].summary, value: totals.leveringen, tone: "default" }), _jsx(SummaryCard, { label: "Verzendklaar", value: totals.verzendklaar, tone: "success" }), _jsx(SummaryCard, { label: "In voorbereiding", value: totals.voorbereiding, tone: "muted" }), _jsx(SummaryCard, { label: "Afgehandeld", value: totals.afgehandeld, tone: "success" }), _jsx(SummaryCard, { label: "Afgehandeld, nog niet gemeld bij Floriday", value: totals.nietAfgemeld, tone: "warning" }), _jsx(SummaryCard, { label: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }), mode !== "pick" ? _jsx(SignupMailMoments, { from: toDayKey(weekStart), to: toDayKey(weekEnd), compact: true }) : null, _jsx("div", { className: "min-h-0 flex-1 space-y-2 overflow-y-auto rounded-lg border bg-muted/20 p-2", children: isLoading || (mode === "pick" && pickAgenda.isLoading) ? (_jsx("div", { className: "rounded-lg border bg-card p-10 text-center text-sm text-muted-foreground", children: "Laden\u2026" })) : (days.map((day) => (_jsx(DayRow, { day: day, onOrderClick: onOrderClick, onDayClick: onDayClick, capacity: mode === "delivery" ? undefined : capacity.byDate.get(toDayKey(day.date)) }, day.date.toISOString())))) })] }));
|
|
209
210
|
}
|
|
210
211
|
function SummaryCard({ label, value, tone, }) {
|
|
211
212
|
const valueClass = tone === "success" ? "text-green-600" : tone === "warning" ? "text-amber-600" : "text-foreground";
|
|
@@ -218,7 +219,10 @@ function DayRow({ day, onOrderClick, onDayClick, capacity, }) {
|
|
|
218
219
|
const isToday = isSameDay(day.date, today);
|
|
219
220
|
// Alles van deze dag is afgehandeld: toon een groene bevestiging.
|
|
220
221
|
const dagAfgesloten = day.bestellingen > 0 && day.afgehandeld >= day.bestellingen && day.nietAfgemeld === 0;
|
|
221
|
-
return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}
|
|
222
|
+
return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""} ${onDayClick && day.bestellingen > 0 ? "cursor-pointer transition-colors hover:bg-muted/40" : ""}`, role: onDayClick && day.bestellingen > 0 ? "button" : undefined, tabIndex: onDayClick && day.bestellingen > 0 ? 0 : undefined, onClick: onDayClick && day.bestellingen > 0 ? () => onDayClick(day.date) : undefined, onKeyDown: onDayClick && day.bestellingen > 0 ? (e) => { if (e.key === "Enter" || e.key === " ") {
|
|
223
|
+
e.preventDefault();
|
|
224
|
+
onDayClick(day.date);
|
|
225
|
+
} } : undefined, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-6 px-4 py-4 sm:px-6", children: [_jsxs("div", { className: "w-20 shrink-0", children: [_jsx("div", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: WEEKDAY_LABELS[weekdayIdx] }), _jsx("div", { className: "mt-1 text-3xl font-bold leading-none", children: day.date.getDate() }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [MONTHS_NL_SHORT[day.date.getMonth()], "."] })] }), _jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-6", children: [_jsx(Stat, { icon: _jsx(Package, { className: "h-4 w-4 text-slate-500" }), bg: "bg-slate-100", value: day.bestellingen, label: "bestellingen" }), _jsx(Stat, { icon: _jsx(Truck, { className: "h-4 w-4 text-amber-600" }), bg: "bg-amber-100", value: day.karren, label: "karren" }), _jsx(Stat, { icon: _jsx(Sprout, { className: "h-4 w-4 text-green-600" }), bg: "bg-green-100", value: day.planten, label: "planten" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [dagAfgesloten && (_jsxs("div", { className: "flex items-center gap-2 rounded-md border border-green-600/30 bg-green-500/15 px-3 py-1.5 text-sm font-medium text-green-700", children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), "Dag is afgesloten"] })), day.shiftedCount > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat te laat is aangemeld en door de planning is verschoven.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.shiftedCount, " te laat aangemeld"] })), day.nietAfgemeld > 0 && (_jsxs(Badge, { className: "bg-amber-500/15 text-amber-700 hover:bg-amber-500/15", variant: "secondary", children: [day.nietAfgemeld, " nog niet afgemeld bij Floriday"] })), day.verzendklaar > 0 && (_jsxs(Badge, { className: "bg-green-500/15 text-green-700 hover:bg-green-500/15", variant: "secondary", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), day.verzendklaar, " verzendklaar"] })), day.voorbereiding > 0 && (_jsxs(Badge, { className: "bg-blue-500/10 text-blue-700 hover:bg-blue-500/10", variant: "secondary", children: [_jsx(Clock, { className: "mr-1 h-3.5 w-3.5" }), day.voorbereiding, " in voorbereiding"] })), onDayClick && day.bestellingen > 0 && (_jsx(Button, { size: "sm", variant: "outline", onClick: (e) => { e.stopPropagation(); onDayClick(day.date); }, children: "Dagdetails" }))] })] }), _jsx(CapacityWarning, { day: capacity, className: "mx-4 mb-4 sm:mx-6" })] }));
|
|
222
226
|
}
|
|
223
227
|
function Stat({ icon, bg, value, label, }) {
|
|
224
228
|
return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: `grid h-8 w-8 place-items-center rounded-full ${bg}`, children: icon }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-bold leading-none", children: value }), _jsx("div", { className: "text-xs text-muted-foreground", children: label })] })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AfhandelingSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/AfhandelingSettingsCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AfhandelingSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/AfhandelingSettingsCard.tsx"],"names":[],"mappings":"AAuBA,wBAAgB,uBAAuB,gCAyJtC"}
|
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
5
5
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle, Button, Input, Label, Switch, toast, } from "@flowselections/core";
|
|
6
6
|
import { CalendarClock, Mail } from "lucide-react";
|
|
7
7
|
import { getAfhandelingSettings, updateAfhandelingSettings, } from "../../lib/afhandelingSettings.functions";
|
|
8
|
+
import { getSignupCronStatus } from "../../lib/carrierSignup.functions";
|
|
9
|
+
import { fmtTime, signupReasonText } from "../../lib/signupMailText";
|
|
8
10
|
export function AfhandelingSettingsCard() {
|
|
9
11
|
const qc = useQueryClient();
|
|
10
12
|
const fetchSettings = useServerFn(getAfhandelingSettings);
|
|
11
13
|
const saveSettings = useServerFn(updateAfhandelingSettings);
|
|
14
|
+
const fetchCronStatus = useServerFn(getSignupCronStatus);
|
|
15
|
+
// Openen van de kaart leest de status en herstelt de taak als hij ontbreekt.
|
|
16
|
+
const cron = useQuery({
|
|
17
|
+
queryKey: ["afhandeling", "signup-status"],
|
|
18
|
+
queryFn: () => fetchCronStatus({ data: { sync: false } }),
|
|
19
|
+
refetchInterval: 60000,
|
|
20
|
+
});
|
|
21
|
+
const healedShown = useRef(false);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (cron.data?.healed && !healedShown.current) {
|
|
24
|
+
healedShown.current = true;
|
|
25
|
+
toast.info("De automatische controle ontbrak en is opnieuw aangezet.");
|
|
26
|
+
}
|
|
27
|
+
}, [cron.data?.healed]);
|
|
12
28
|
const { data } = useQuery({
|
|
13
29
|
queryKey: ["afhandeling", "settings"],
|
|
14
30
|
queryFn: async () => {
|
|
@@ -41,11 +57,40 @@ export function AfhandelingSettingsCard() {
|
|
|
41
57
|
onSuccess: async () => {
|
|
42
58
|
const { invalidatePlanning } = await import("../../lib/invalidatePlanning");
|
|
43
59
|
await invalidatePlanning(qc);
|
|
60
|
+
try {
|
|
61
|
+
const st = await fetchCronStatus({ data: { sync: true } });
|
|
62
|
+
qc.setQueryData(["afhandeling", "signup-status"], st);
|
|
63
|
+
if (!st.cronAvailable) {
|
|
64
|
+
toast.error("Automatisch versturen is in deze omgeving niet beschikbaar. Vraag je beheerder om dit aan te zetten.");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (st.syncCode === null && st.enabled !== st.active) {
|
|
68
|
+
toast.error("Alleen een beheerder kan de automatische controle aan- of uitzetten.");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
toast.error(e instanceof Error ? e.message : "Automatische controle kon niet worden ingesteld");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
44
76
|
toast.success("Instellingen opgeslagen");
|
|
45
77
|
},
|
|
46
78
|
onError: (e) => {
|
|
47
79
|
toast.error(e instanceof Error ? e.message : "Opslaan mislukt");
|
|
48
80
|
},
|
|
49
81
|
});
|
|
50
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CalendarClock, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { children: "Afhandeling \u2014 Planning" })] }), _jsx(CardDescription, { children: "De pickplanning (pickdagen, picktijd en verdeling over de week) wordt volledig bepaald door de
|
|
82
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CalendarClock, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { children: "Afhandeling \u2014 Planning" })] }), _jsx(CardDescription, { children: "De pickplanning (pickdagen, picktijd en verdeling over de week) wordt volledig bepaald door de planning. Hieronder staan alleen de instellingen van deze module zelf." })] }), _jsxs(CardContent, { className: "space-y-5", children: [_jsxs("div", { className: "rounded-md border p-4 space-y-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "h-4 w-4 text-primary" }), _jsx(Label, { htmlFor: "mailEnabled", className: "font-semibold", children: "Aanmeldmail vervoerders" })] }), _jsx("p", { className: "text-xs text-muted-foreground max-w-prose", children: "Verstuurt automatisch een mail met de te verwachten karren naar de vervoerder v\u00F3\u00F3r de aanmelddeadline van het ophaalmoment. E\u00E9n mail per ophaaldag/-moment per vervoerder." })] }), _jsx(Switch, { id: "mailEnabled", checked: mailEnabled, onCheckedChange: setMailEnabled })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "mailLead", children: "Minuten v\u00F3\u00F3r aanmelddeadline versturen" }), _jsx(Input, { id: "mailLead", type: "number", min: 0, max: 1440, value: mailLead, disabled: !mailEnabled, onChange: (e) => setMailLead(Math.max(0, Math.min(1440, Math.floor(Number(e.target.value)) || 0))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "mailPurpose", children: "E-mail-doeleinde (purpose)" }), _jsx(Input, { id: "mailPurpose", value: mailPurpose, disabled: !mailEnabled, onChange: (e) => setMailPurpose(e.target.value) }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Koppel dit doeleinde in de module ", _jsx("strong", { children: "E-mailkoppeling" }), " aan een actief send-adres. Standaard: ", _jsx("code", { children: "afhandeling_carrier_signup" }), "."] })] })] }), _jsx(SignupStatusBlock, { status: cron.data ?? null, loading: cron.isLoading, failed: cron.isError }), _jsxs("div", { className: "rounded-md bg-muted/50 p-3 text-xs text-muted-foreground", children: [_jsx("strong", { children: "Ophaaltijd" }), " en ", _jsx("strong", { children: "Aanmeldtijd" }), " stel je per vervoerder in (werkdagen v\u00F3\u00F3r bezorgdag). De vervoerder die als ", _jsx("strong", { children: "standaard" }), " is gemarkeerd, wordt gebruikt voor orders zonder eigen vervoerder."] }), _jsx(Button, { onClick: () => mutation.mutate(), disabled: mutation.isPending, children: mutation.isPending ? "Opslaan…" : "Opslaan" })] })] }));
|
|
83
|
+
}
|
|
84
|
+
function SignupStatusBlock({ status, loading, failed, }) {
|
|
85
|
+
if (loading)
|
|
86
|
+
return null;
|
|
87
|
+
if (failed || !status) {
|
|
88
|
+
return _jsx("div", { className: "rounded-md border p-3 text-xs text-muted-foreground", children: "Automatische controle: stand onbekend." });
|
|
89
|
+
}
|
|
90
|
+
const tz = status.timezone;
|
|
91
|
+
const run = status.lastRun;
|
|
92
|
+
const reason = status.enabled
|
|
93
|
+
? signupReasonText(status.reason) ?? (run && !run.ok ? signupReasonText(run.reason) : null)
|
|
94
|
+
: null;
|
|
95
|
+
return (_jsxs("div", { className: "space-y-1 rounded-md border p-3 text-xs", children: [_jsxs("div", { children: [_jsx("strong", { children: "Automatische controle:" }), " ", !status.cronAvailable ? (_jsx("span", { className: "text-destructive", children: "niet beschikbaar in deze omgeving. Vraag je beheerder om automatische taken aan te zetten." })) : status.active ? (_jsx("span", { className: "text-primary", children: "actief" })) : (_jsx("span", { className: "text-muted-foreground", children: "niet actief" }))] }), run ? (_jsxs("div", { className: "text-muted-foreground", children: ["Laatst gecontroleerd om ", fmtTime(run.started_at, tz), " \u00B7 ", status.sentToday, " ", status.sentToday === 1 ? "mail" : "mails", " verstuurd vandaag"] })) : (_jsx("div", { className: "text-muted-foreground", children: "Nog niet gecontroleerd." })), reason ? _jsx("div", { className: "text-destructive", children: reason }) : null] }));
|
|
51
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOrderPlanning.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrderPlanning.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAK/D,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAYtG;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,iBAAiB,GACjB,gBAAgB,GAChB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAC;IACxB,iDAAiD;IACjD,KAAK,EAAE,aAAa,CAAC;IACrB,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,wEAAwE;IACxE,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,wDAAwD;IACxD,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAClC,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAGD,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,
|
|
1
|
+
{"version":3,"file":"useOrderPlanning.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrderPlanning.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAK/D,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAYtG;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,iBAAiB,GACjB,gBAAgB,GAChB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAC;IACxB,iDAAiD;IACjD,KAAK,EAAE,aAAa,CAAC;IACrB,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,wEAAwE;IACxE,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,wDAAwD;IACxD,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAClC,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAGD,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,CAmTxF"}
|
|
@@ -11,7 +11,7 @@ import { useCartIndex } from "./useCartIndex";
|
|
|
11
11
|
import { emitEngineEvent, listComposeTaskRefs } from "../lib/logisticsEngine/engine";
|
|
12
12
|
import { orderRefsFor } from "../lib/orderRefs";
|
|
13
13
|
import { isOpenOrderStatus } from "../lib/orderStatus";
|
|
14
|
-
import {
|
|
14
|
+
import { emitQueueStatus, markInFlight, markResult, resetEmitQueue, selectEmitBatch, } from "../lib/logisticsEngine/emitQueue";
|
|
15
15
|
export function useOrderPlanning(range) {
|
|
16
16
|
const from = range?.from ?? null;
|
|
17
17
|
const to = range?.to ?? null;
|
|
@@ -34,7 +34,8 @@ export function useOrderPlanning(range) {
|
|
|
34
34
|
let message = "Onbekende fout";
|
|
35
35
|
if (e instanceof Response) {
|
|
36
36
|
const text = await e.clone().text().catch(() => "");
|
|
37
|
-
message =
|
|
37
|
+
message = "Floriday reageert nu niet goed. Probeer het over een paar minuten opnieuw.";
|
|
38
|
+
console.warn(`Floriday-aanvraag mislukt (${e.status}): ${text.slice(0, 200) || e.statusText}`);
|
|
38
39
|
}
|
|
39
40
|
else if (e instanceof Error) {
|
|
40
41
|
message = e.message;
|
|
@@ -182,7 +183,7 @@ export function useOrderPlanning(range) {
|
|
|
182
183
|
cartIndexes: Array.from({ length: carrierCount }, (_, i) => i),
|
|
183
184
|
},
|
|
184
185
|
],
|
|
185
|
-
reason: `Ingepland door de
|
|
186
|
+
reason: `Ingepland door de planning (taak ${(pickTask ?? task).task_type}, regelversie ${(pickTask ?? task).rule_version ?? "-"}).`,
|
|
186
187
|
carrierName: carrier?.name ?? base.carrierName,
|
|
187
188
|
};
|
|
188
189
|
return { order, planning, engineTask: task, awaitingEngine: false, state: "planned", hasComposeTask: true };
|
|
@@ -223,7 +224,7 @@ export function useOrderPlanning(range) {
|
|
|
223
224
|
if (!batch.length) {
|
|
224
225
|
const status = emitQueueStatus(refs);
|
|
225
226
|
if (status.gaveUp.length) {
|
|
226
|
-
setSignalError(
|
|
227
|
+
setSignalError(`${status.gaveUp.length} order(s) konden niet automatisch worden ingepland. Open de order en kies ‘Opnieuw inplannen’.`);
|
|
227
228
|
}
|
|
228
229
|
return;
|
|
229
230
|
}
|
|
@@ -257,8 +258,8 @@ export function useOrderPlanning(range) {
|
|
|
257
258
|
else {
|
|
258
259
|
const status = emitQueueStatus(refs);
|
|
259
260
|
setSignalError(status.gaveUp.length
|
|
260
|
-
?
|
|
261
|
-
:
|
|
261
|
+
? `${status.gaveUp.length} order(s) konden niet automatisch worden ingepland. Open de order en kies ‘Opnieuw inplannen’.`
|
|
262
|
+
: "Inplannen lukt nog niet; er volgt automatisch een nieuwe poging.");
|
|
262
263
|
}
|
|
263
264
|
}
|
|
264
265
|
})();
|
|
@@ -6,6 +6,10 @@ export interface PickAgendaOrder {
|
|
|
6
6
|
carts: number;
|
|
7
7
|
plants: number;
|
|
8
8
|
shifted: boolean;
|
|
9
|
+
/** Orders in deze (buffer)taak; leeg = alleen orderRef. */
|
|
10
|
+
bufferOrders: string[];
|
|
11
|
+
/** Unieke kar-id's van deze taak. */
|
|
12
|
+
cartIds: string[];
|
|
9
13
|
/** Verkoop-module zegt: deze order is afgehandeld (verzonden/geleverd). */
|
|
10
14
|
fulfilled?: boolean;
|
|
11
15
|
}
|
|
@@ -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;
|
|
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,2DAA2D;IAC3D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qCAAqC;IACrC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,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;AA4CD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;;;;;EAoInE"}
|
|
@@ -16,6 +16,10 @@ function toOrders(value) {
|
|
|
16
16
|
carts: Number(r.carts ?? 0),
|
|
17
17
|
plants: Number(r.plants ?? 0),
|
|
18
18
|
shifted: Boolean(r.shifted),
|
|
19
|
+
bufferOrders: Array.isArray(r.bufferOrders) ? r.bufferOrders.map(String).filter(Boolean) : [],
|
|
20
|
+
cartIds: Array.isArray(r.cartList)
|
|
21
|
+
? r.cartList.map((c) => c?.cartId).filter((x) => typeof x === "string" && !!x)
|
|
22
|
+
: [],
|
|
19
23
|
};
|
|
20
24
|
});
|
|
21
25
|
}
|
|
@@ -110,16 +114,43 @@ export function usePickAgenda(from, to) {
|
|
|
110
114
|
if (to && pickDate > to)
|
|
111
115
|
continue;
|
|
112
116
|
// "Afgehandeld" volgt uitsluitend de Engine (taak afgemeld), niet de Verkoop-status.
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
// Tellen per losse order (ook elke order in een buffer) en per unieke kar-id,
|
|
118
|
+
// gelijk aan Dagdetails. "Afgehandeld" = taak afgemeld of Verkoop-status afgehandeld,
|
|
119
|
+
// gelijk aan Planning en leveringen.
|
|
120
|
+
const refsOf = (o) => (o.bufferOrders.length ? o.bufferOrders : [o.orderRef]);
|
|
121
|
+
const allRefs = new Set();
|
|
122
|
+
const doneRefs = new Set();
|
|
123
|
+
const readyRefs = new Set();
|
|
124
|
+
for (const o of orders) {
|
|
125
|
+
for (const r of refsOf(o)) {
|
|
126
|
+
if (isCancelledRef(r))
|
|
127
|
+
continue;
|
|
128
|
+
allRefs.add(r);
|
|
129
|
+
const engineDone = o.status === "done" || o.status === "completed";
|
|
130
|
+
if (engineDone || isFulfilledRef(r))
|
|
131
|
+
doneRefs.add(r);
|
|
132
|
+
if (o.status === "ready" || engineDone || isFulfilledRef(r))
|
|
133
|
+
readyRefs.add(r);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const cartIds = new Set();
|
|
137
|
+
let cartsWithoutId = 0;
|
|
138
|
+
for (const o of orders) {
|
|
139
|
+
if (o.cartIds.length)
|
|
140
|
+
o.cartIds.forEach((c) => cartIds.add(c));
|
|
141
|
+
else
|
|
142
|
+
cartsWithoutId += o.carts || 0;
|
|
143
|
+
}
|
|
144
|
+
const doneCount = doneRefs.size;
|
|
145
|
+
const ready = readyRefs.size;
|
|
115
146
|
out.push({
|
|
116
147
|
pickDate,
|
|
117
148
|
orders,
|
|
118
|
-
orderCount:
|
|
119
|
-
cartCount:
|
|
149
|
+
orderCount: allRefs.size,
|
|
150
|
+
cartCount: cartIds.size + cartsWithoutId,
|
|
120
151
|
plantCount: orders.reduce((s, o) => s + (o.plants || 0), 0),
|
|
121
152
|
ready,
|
|
122
|
-
inPreparation: Math.max(0,
|
|
153
|
+
inPreparation: Math.max(0, allRefs.size - ready),
|
|
123
154
|
shiftedCount: orders.filter((o) => o.shifted).length,
|
|
124
155
|
doneCount,
|
|
125
156
|
});
|