@flowselections/floriday-afhandeling-module 1.0.9 → 1.0.10
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 +9 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.js +145 -0
- package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/LeveringenPage.js +11 -5
- package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PickAgendaView.js +13 -4
- package/dist-lib/components/afhandeling/PlanningAgendaPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PlanningAgendaPage.js +2 -2
- package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts +12 -0
- package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ServiceAreaSelect.js +79 -0
- package/dist-lib/components/afhandeling/VervoerderForm.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/VervoerderForm.js +53 -6
- package/dist-lib/components/afhandeling/VervoerdersPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/VervoerdersPage.js +23 -5
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts +2 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +53 -18
- package/dist-lib/components/pickstation/PakbonTemplate.d.ts +5 -2
- package/dist-lib/components/pickstation/PakbonTemplate.d.ts.map +1 -1
- package/dist-lib/components/pickstation/PakbonTemplate.js +12 -10
- package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -1
- package/dist-lib/components/settings/AfhandelingSettingsCard.js +18 -6
- package/dist-lib/hooks/useOrderPlanning.d.ts +3 -0
- package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPlanning.js +47 -6
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2261 -136
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +2261 -136
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +2261 -136
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +2329 -134
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/afhandelingSettings.functions.d.ts +9431 -5172
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.js +27 -2
- package/dist-lib/lib/carrierSignupMail.server.d.ts +56 -0
- package/dist-lib/lib/carrierSignupMail.server.d.ts.map +1 -0
- package/dist-lib/lib/carrierSignupMail.server.js +229 -0
- package/dist-lib/lib/carriers.functions.d.ts +33377 -15579
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/carriers.functions.js +28 -2
- package/dist-lib/lib/cartAssignments.functions.d.ts +46479 -0
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -0
- package/dist-lib/lib/cartAssignments.functions.js +130 -0
- package/dist-lib/lib/cartMoveImpact.d.ts +8 -0
- package/dist-lib/lib/cartMoveImpact.d.ts.map +1 -0
- package/dist-lib/lib/cartMoveImpact.js +26 -0
- package/dist-lib/lib/floriday.functions.d.ts +2265 -136
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +178 -98
- package/dist-lib/lib/geo/euServiceAreas.d.ts +30 -0
- package/dist-lib/lib/geo/euServiceAreas.d.ts.map +1 -0
- package/dist-lib/lib/geo/euServiceAreas.js +277 -0
- package/dist-lib/lib/invalidatePlanning.d.ts +11 -0
- package/dist-lib/lib/invalidatePlanning.d.ts.map +1 -0
- package/dist-lib/lib/invalidatePlanning.js +25 -0
- package/dist-lib/lib/pickstationI18n.d.ts +4 -0
- package/dist-lib/lib/pickstationI18n.d.ts.map +1 -1
- package/dist-lib/lib/pickstationI18n.js +24 -0
- package/dist-lib/lib/pickstationOrders.server.d.ts +1 -1
- package/dist-lib/lib/pickstationOrders.server.d.ts.map +1 -1
- package/dist-lib/lib/pickstationOrders.server.js +305 -177
- package/dist-lib/lib/pickstationTypes.d.ts +11 -2
- package/dist-lib/lib/pickstationTypes.d.ts.map +1 -1
- package/dist-lib/lib/planning.d.ts +18 -2
- package/dist-lib/lib/planning.d.ts.map +1 -1
- package/dist-lib/lib/planning.js +96 -33
- package/package.json +2 -2
|
@@ -6,7 +6,8 @@ export interface WeekAgendaViewProps {
|
|
|
6
6
|
mode: WeekAgendaMode;
|
|
7
7
|
isLoading?: boolean;
|
|
8
8
|
onOrderClick?: (order: FloridayOrder) => void;
|
|
9
|
+
onDayClick?: (date: Date) => void;
|
|
9
10
|
title?: string;
|
|
10
11
|
}
|
|
11
|
-
export declare function WeekAgendaView({ planned, mode, isLoading, onOrderClick, title, }: WeekAgendaViewProps): import("react").JSX.Element;
|
|
12
|
+
export declare function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayClick, title, }: WeekAgendaViewProps): import("react").JSX.Element;
|
|
12
13
|
//# sourceMappingURL=WeekAgendaView.d.ts.map
|
|
@@ -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;AAEjE,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,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
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;AAEjE,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;CAChB;AA4DD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,GACN,EAAE,mBAAmB,+BAwHrB"}
|
|
@@ -37,7 +37,7 @@ const MODE_LABELS = {
|
|
|
37
37
|
"transport-register": { summary: "Aanmeldingen deze week" },
|
|
38
38
|
pick: { summary: "Te picken deze week" },
|
|
39
39
|
};
|
|
40
|
-
export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, title, }) {
|
|
40
|
+
export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayClick, title, }) {
|
|
41
41
|
const [cursor, setCursor] = useState(() => {
|
|
42
42
|
const d = new Date();
|
|
43
43
|
d.setHours(0, 0, 0, 0);
|
|
@@ -49,21 +49,51 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, title,
|
|
|
49
49
|
const days = useMemo(() => {
|
|
50
50
|
return Array.from({ length: 7 }, (_, i) => {
|
|
51
51
|
const date = addDays(weekStart, i);
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
const entries = [];
|
|
53
|
+
for (const p of planned) {
|
|
54
|
+
if (!p.planning)
|
|
55
|
+
continue;
|
|
56
|
+
if (mode === "pick") {
|
|
57
|
+
const assigns = p.planning.pickAssignments ?? [
|
|
58
|
+
{ date: p.planning.scheduledPickDate ?? p.planning.pickStartDate, cartCount: p.order.cartCount ?? 0 },
|
|
59
|
+
];
|
|
60
|
+
const total = assigns.length;
|
|
61
|
+
assigns.forEach((a, idx) => {
|
|
62
|
+
if (!isSameDay(a.date, date))
|
|
63
|
+
return;
|
|
64
|
+
const totalCarts = p.order.cartCount ?? 0;
|
|
65
|
+
const ratio = totalCarts > 0 ? a.cartCount / totalCarts : 1 / Math.max(total, 1);
|
|
66
|
+
entries.push({
|
|
67
|
+
order: p.order,
|
|
68
|
+
cartCount: a.cartCount,
|
|
69
|
+
plantCount: Math.round((p.order.plantCount ?? 0) * ratio),
|
|
70
|
+
movedEarlier: a.date.getTime() !== p.planning.pickStartDate.getTime(),
|
|
71
|
+
splitPart: total > 1 ? { index: idx + 1, total } : undefined,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const d = dateForPlanned(p, mode);
|
|
77
|
+
if (!d || !isSameDay(d, date))
|
|
78
|
+
continue;
|
|
79
|
+
entries.push({
|
|
80
|
+
order: p.order,
|
|
81
|
+
cartCount: p.order.cartCount ?? 0,
|
|
82
|
+
plantCount: p.order.plantCount ?? 0,
|
|
83
|
+
movedEarlier: false,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const karren = entries.reduce((s, e) => s + e.cartCount, 0);
|
|
88
|
+
const planten = entries.reduce((s, e) => s + e.plantCount, 0);
|
|
89
|
+
const verzendklaar = entries.filter((e) => isOrderReady(e.order)).length;
|
|
90
|
+
const voorbereiding = entries.length - verzendklaar;
|
|
91
|
+
const movedEarlierOrderIds = new Set(entries.filter((e) => e.movedEarlier).map((e) => e.order.id));
|
|
62
92
|
return {
|
|
63
93
|
date,
|
|
64
|
-
|
|
94
|
+
entries,
|
|
65
95
|
movedEarlierOrderIds,
|
|
66
|
-
bestellingen:
|
|
96
|
+
bestellingen: entries.length,
|
|
67
97
|
karren,
|
|
68
98
|
planten,
|
|
69
99
|
verzendklaar,
|
|
@@ -86,20 +116,25 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, title,
|
|
|
86
116
|
d.setHours(0, 0, 0, 0);
|
|
87
117
|
setCursor(startOfWeek(d));
|
|
88
118
|
};
|
|
89
|
-
return (_jsxs("div", { className: "space-y-4", 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" })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4", 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: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }), _jsx("div", { className: "space-y-2", children: 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 }, day.date.toISOString()))) })] }));
|
|
119
|
+
return (_jsxs("div", { className: "space-y-4", 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" })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4", 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: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }), _jsx("div", { className: "space-y-2", children: 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 }, day.date.toISOString()))) })] }));
|
|
90
120
|
}
|
|
91
121
|
function SummaryCard({ label, value, tone, }) {
|
|
92
122
|
const valueClass = tone === "success" ? "text-green-600" : "text-foreground";
|
|
93
123
|
return (_jsxs("div", { className: "rounded-lg border bg-card p-4", children: [_jsx("div", { className: `text-3xl font-bold ${valueClass}`, children: value }), _jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: label })] }));
|
|
94
124
|
}
|
|
95
|
-
function DayRow({ day, onOrderClick }) {
|
|
125
|
+
function DayRow({ day, onOrderClick, onDayClick }) {
|
|
96
126
|
const weekdayIdx = (day.date.getDay() + 6) % 7;
|
|
97
127
|
const today = new Date();
|
|
98
128
|
today.setHours(0, 0, 0, 0);
|
|
99
129
|
const isToday = isSameDay(day.date, today);
|
|
100
|
-
return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}`, 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: [day.movedEarlierOrderIds.size > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat vervroegd is ingepland door Pickverdeling.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.movedEarlierOrderIds.size, " vervroegd"] })), 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"] }))] })] }), onOrderClick && day.
|
|
101
|
-
const moved =
|
|
102
|
-
|
|
130
|
+
return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}`, 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: [day.movedEarlierOrderIds.size > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat vervroegd is ingepland door Pickverdeling.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.movedEarlierOrderIds.size, " vervroegd"] })), 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: () => onDayClick(day.date), children: "Dagdetails" }))] })] }), onOrderClick && day.entries.length > 0 && (_jsx("div", { className: "border-t px-4 py-2 sm:px-6", children: _jsx("div", { className: "flex flex-wrap gap-2", children: day.entries.map((e, idx) => {
|
|
131
|
+
const moved = e.movedEarlier;
|
|
132
|
+
const split = e.splitPart;
|
|
133
|
+
return (_jsxs("button", { onClick: () => onOrderClick(e.order), title: split
|
|
134
|
+
? `Deel ${split.index}/${split.total} — ${e.cartCount} karren deze dag (verdeeld picken).`
|
|
135
|
+
: moved
|
|
136
|
+
? "Deze order is eerder ingepland vanwege Pickverdeling."
|
|
137
|
+
: undefined, className: `flex items-center gap-1 rounded border px-2 py-1 text-xs hover:bg-muted ${moved || split ? "border-purple-300 bg-purple-50" : ""}`, children: [(moved || split) && _jsx(Scale, { className: "h-3 w-3 text-purple-600" }), _jsx("span", { className: "font-medium", children: e.order.orderNumber }), _jsxs("span", { className: "ml-1 text-muted-foreground", children: ["\u00B7 ", e.order.customerName] }), _jsxs("span", { className: "ml-1 text-purple-700", children: ["\u00B7 ", e.cartCount, " karren", split ? ` (deel ${split.index}/${split.total})` : ""] })] }, `${e.order.id}-${idx}`));
|
|
103
138
|
}) }) }))] }));
|
|
104
139
|
}
|
|
105
140
|
function Stat({ icon, bg, value, label, }) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PickstationOrder } from "../../lib/pickstationTypes";
|
|
2
|
-
/** Returns a fully self-contained printable HTML document for one packing slip. */
|
|
2
|
+
/** Returns a fully self-contained printable HTML document for one packing slip per cart. */
|
|
3
3
|
export declare function renderPakbonHtml(order: {
|
|
4
4
|
id: string;
|
|
5
5
|
orderNumber: string;
|
|
@@ -7,9 +7,12 @@ export declare function renderPakbonHtml(order: {
|
|
|
7
7
|
country: string | null;
|
|
8
8
|
deliveryDate: string | null;
|
|
9
9
|
pickDate: string;
|
|
10
|
+
cartIndex: number;
|
|
11
|
+
cartTotal: number;
|
|
12
|
+
cratesOnCart: number | null;
|
|
10
13
|
lines: {
|
|
11
14
|
description: string;
|
|
12
|
-
|
|
15
|
+
crates: number | null;
|
|
13
16
|
unit: string | null;
|
|
14
17
|
}[];
|
|
15
18
|
}): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PakbonTemplate.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/PakbonTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,
|
|
1
|
+
{"version":3,"file":"PakbonTemplate.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/PakbonTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CAC9E,GAAG,MAAM,CAqET;AAWD,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Returns a fully self-contained printable HTML document for one packing slip. */
|
|
1
|
+
/** Returns a fully self-contained printable HTML document for one packing slip per cart. */
|
|
2
2
|
export function renderPakbonHtml(order) {
|
|
3
3
|
const fmt = (d) => {
|
|
4
4
|
if (!d)
|
|
@@ -13,21 +13,24 @@ export function renderPakbonHtml(order) {
|
|
|
13
13
|
.map((l) => `
|
|
14
14
|
<tr>
|
|
15
15
|
<td>${escapeHtml(l.description)}</td>
|
|
16
|
-
<td style="text-align:right">${l.
|
|
16
|
+
<td style="text-align:right">${l.crates ?? ""}</td>
|
|
17
17
|
<td>${escapeHtml(l.unit ?? "")}</td>
|
|
18
18
|
</tr>`)
|
|
19
19
|
.join("")
|
|
20
20
|
: `<tr><td colspan="3" style="text-align:center;color:#666">Geen regels</td></tr>`;
|
|
21
|
+
const cartLabel = `Kar ${order.cartIndex} / ${order.cartTotal}`;
|
|
22
|
+
const fustenLabel = order.cratesOnCart != null ? `${order.cratesOnCart}` : "—";
|
|
21
23
|
return `<!doctype html>
|
|
22
24
|
<html lang="nl">
|
|
23
25
|
<head>
|
|
24
26
|
<meta charset="utf-8">
|
|
25
|
-
<title>Pakbon ${escapeHtml(order.orderNumber)}</title>
|
|
27
|
+
<title>Pakbon ${escapeHtml(order.orderNumber)} · ${escapeHtml(cartLabel)}</title>
|
|
26
28
|
<style>
|
|
27
29
|
@page { size: A4; margin: 16mm; }
|
|
28
30
|
body { font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; color:#111; }
|
|
29
31
|
h1 { margin: 0 0 4px; font-size: 26px; }
|
|
30
32
|
.sub { color:#444; margin-bottom: 18px; }
|
|
33
|
+
.cart-badge { display:inline-block; margin-left:8px; padding:2px 10px; border-radius:999px; background:#111; color:#fff; font-size:14px; vertical-align:middle; }
|
|
31
34
|
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 24px; margin: 18px 0 22px; }
|
|
32
35
|
.grid div { font-size: 14px; }
|
|
33
36
|
.label { color:#666; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
|
|
@@ -35,13 +38,12 @@ export function renderPakbonHtml(order) {
|
|
|
35
38
|
table { width:100%; border-collapse: collapse; font-size: 14px; }
|
|
36
39
|
th, td { padding: 8px 6px; border-bottom: 1px solid #ddd; vertical-align: top; }
|
|
37
40
|
th { text-align: left; background:#f5f5f5; }
|
|
38
|
-
.barcode {
|
|
39
|
-
.barcode-fallback { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 18px; letter-spacing: 4px; padding: 8px 12px; border: 2px solid #111; display: inline-block; }
|
|
41
|
+
.barcode-fallback { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 18px; letter-spacing: 4px; padding: 8px 12px; border: 2px solid #111; display: inline-block; margin-top: 18px; }
|
|
40
42
|
.footer { margin-top: 28px; font-size: 11px; color:#666; }
|
|
41
43
|
</style>
|
|
42
44
|
</head>
|
|
43
45
|
<body>
|
|
44
|
-
<h1>Pakbon</h1>
|
|
46
|
+
<h1>Pakbon <span class="cart-badge">${escapeHtml(cartLabel)}</span></h1>
|
|
45
47
|
<div class="sub">Order ${escapeHtml(order.orderNumber)}</div>
|
|
46
48
|
|
|
47
49
|
<div class="grid">
|
|
@@ -49,18 +51,18 @@ export function renderPakbonHtml(order) {
|
|
|
49
51
|
<div><div class="label">Land</div><div class="value">${escapeHtml(order.country ?? "—")}</div></div>
|
|
50
52
|
<div><div class="label">Leverdatum</div><div class="value">${fmt(order.deliveryDate)}</div></div>
|
|
51
53
|
<div><div class="label">Pickdatum</div><div class="value">${fmt(order.pickDate)}</div></div>
|
|
54
|
+
<div><div class="label">Kar</div><div class="value">${escapeHtml(cartLabel)}</div></div>
|
|
55
|
+
<div><div class="label">Fusten op deze kar</div><div class="value">${escapeHtml(fustenLabel)}</div></div>
|
|
52
56
|
</div>
|
|
53
57
|
|
|
54
58
|
<table>
|
|
55
|
-
<thead><tr><th>Omschrijving</th><th style="text-align:right;width:90px">
|
|
59
|
+
<thead><tr><th>Omschrijving</th><th style="text-align:right;width:90px">Fusten</th><th style="width:90px">Eenheid</th></tr></thead>
|
|
56
60
|
<tbody>${rows}</tbody>
|
|
57
61
|
</table>
|
|
58
62
|
|
|
59
|
-
<div class="barcode-fallback">*${escapeHtml(order.orderNumber)}*</div>
|
|
63
|
+
<div class="barcode-fallback">*${escapeHtml(order.orderNumber)}-${order.cartIndex}*</div>
|
|
60
64
|
|
|
61
65
|
<div class="footer">Geprint via Pickstation · ${new Date().toLocaleString("nl-NL")}</div>
|
|
62
|
-
|
|
63
|
-
<script>window.addEventListener("load", function(){ setTimeout(function(){ try{ window.focus(); window.print(); }catch(e){} }, 100); });</script>
|
|
64
66
|
</body>
|
|
65
67
|
</html>`;
|
|
66
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AfhandelingSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/AfhandelingSettingsCard.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"AfhandelingSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/AfhandelingSettingsCard.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,uBAAuB,gCAoMtC"}
|
|
@@ -3,7 +3,7 @@ import { useEffect, 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
|
-
import { CalendarClock, Scale } from "lucide-react";
|
|
6
|
+
import { CalendarClock, Mail, Scale } from "lucide-react";
|
|
7
7
|
import { getAfhandelingSettings, updateAfhandelingSettings, } from "../../lib/afhandelingSettings.functions";
|
|
8
8
|
export function AfhandelingSettingsCard() {
|
|
9
9
|
const qc = useQueryClient();
|
|
@@ -21,6 +21,9 @@ export function AfhandelingSettingsCard() {
|
|
|
21
21
|
transportRegisterDaysBefore: 1,
|
|
22
22
|
pickDistributionEnabled: false,
|
|
23
23
|
maxWorkdaysEarlierPick: 2,
|
|
24
|
+
signupMailEnabled: false,
|
|
25
|
+
signupMailLeadMinutes: 60,
|
|
26
|
+
signupMailPurpose: "afhandeling_carrier_signup",
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
},
|
|
@@ -29,12 +32,18 @@ export function AfhandelingSettingsCard() {
|
|
|
29
32
|
const [registerDays, setRegisterDays] = useState(1);
|
|
30
33
|
const [distributionEnabled, setDistributionEnabled] = useState(false);
|
|
31
34
|
const [maxEarlier, setMaxEarlier] = useState(2);
|
|
35
|
+
const [mailEnabled, setMailEnabled] = useState(false);
|
|
36
|
+
const [mailLead, setMailLead] = useState(60);
|
|
37
|
+
const [mailPurpose, setMailPurpose] = useState("afhandeling_carrier_signup");
|
|
32
38
|
useEffect(() => {
|
|
33
39
|
if (data) {
|
|
34
40
|
setPickDays(data.pickDaysBeforeTransport);
|
|
35
41
|
setRegisterDays(data.transportRegisterDaysBefore);
|
|
36
42
|
setDistributionEnabled(Boolean(data.pickDistributionEnabled));
|
|
37
43
|
setMaxEarlier(data.maxWorkdaysEarlierPick ?? 2);
|
|
44
|
+
setMailEnabled(Boolean(data.signupMailEnabled));
|
|
45
|
+
setMailLead(data.signupMailLeadMinutes ?? 60);
|
|
46
|
+
setMailPurpose(data.signupMailPurpose ?? "afhandeling_carrier_signup");
|
|
38
47
|
}
|
|
39
48
|
}, [data]);
|
|
40
49
|
const mutation = useMutation({
|
|
@@ -44,17 +53,20 @@ export function AfhandelingSettingsCard() {
|
|
|
44
53
|
transportRegisterDaysBefore: registerDays,
|
|
45
54
|
pickDistributionEnabled: distributionEnabled,
|
|
46
55
|
maxWorkdaysEarlierPick: maxEarlier,
|
|
56
|
+
signupMailEnabled: mailEnabled,
|
|
57
|
+
signupMailLeadMinutes: mailLead,
|
|
58
|
+
signupMailPurpose: mailPurpose,
|
|
47
59
|
},
|
|
48
60
|
}),
|
|
49
|
-
onSuccess: () => {
|
|
50
|
-
|
|
51
|
-
qc
|
|
52
|
-
toast.success("Instellingen opgeslagen");
|
|
61
|
+
onSuccess: async () => {
|
|
62
|
+
const { invalidatePlanning } = await import("../../lib/invalidatePlanning");
|
|
63
|
+
await invalidatePlanning(qc);
|
|
64
|
+
toast.success("Instellingen opgeslagen — planning herberekend");
|
|
53
65
|
},
|
|
54
66
|
onError: (e) => {
|
|
55
67
|
toast.error(e instanceof Error ? e.message : "Opslaan mislukt");
|
|
56
68
|
},
|
|
57
69
|
});
|
|
58
70
|
const clamp = (n) => Math.max(0, Math.min(30, Math.floor(n) || 0));
|
|
59
|
-
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: "Centrale werkdag-instellingen voor de automatische order\u00ADplanning. Alle berekeningen tellen alleen werkdagen (ma\u2013vr)." })] }), _jsxs(CardContent, { className: "space-y-5", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "pickDays", children: "Aantal pickdagen (werkdagen v\u00F3\u00F3r ophaaldag)" }), _jsx(Input, { id: "pickDays", type: "number", min: 0, max: 30, value: pickDays, onChange: (e) => setPickDays(clamp(Number(e.target.value))) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Wordt vanaf de berekende ophaaldag teruggeteld om de uiterste pickdatum te bepalen." })] }), _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(Scale, { className: "h-4 w-4 text-primary" }), _jsx(Label, { htmlFor: "pickDistribution", className: "font-semibold", children: "Pickverdeling" })] }), _jsx("p", { className: "text-xs text-muted-foreground max-w-prose", children: "Verdeelt de pickbelasting automatisch over werkdagen. Orders mogen eerder ingepland worden, maar nooit later dan de berekende uiterste pickdatum \u2014 leverbetrouwbaarheid blijft gegarandeerd." })] }), _jsx(Switch, { id: "pickDistribution", checked: distributionEnabled, onCheckedChange: setDistributionEnabled })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "maxEarlier", children: "Maximaal aantal werkdagen eerder picken" }), _jsx(Input, { id: "maxEarlier", type: "number", min: 0, max: 30, value: maxEarlier, disabled: !distributionEnabled, onChange: (e) => setMaxEarlier(clamp(Number(e.target.value))) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "0 = geen vervroeging. Bijv. 2 = orders mogen maximaal 2 werkdagen voor hun uiterste pickdatum ingepland worden." })] })] }), _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" })] })] }));
|
|
71
|
+
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: "Centrale werkdag-instellingen voor de automatische order\u00ADplanning. Alle berekeningen tellen alleen werkdagen (ma\u2013vr)." })] }), _jsxs(CardContent, { className: "space-y-5", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "pickDays", children: "Aantal pickdagen (werkdagen v\u00F3\u00F3r ophaaldag)" }), _jsx(Input, { id: "pickDays", type: "number", min: 0, max: 30, value: pickDays, onChange: (e) => setPickDays(clamp(Number(e.target.value))) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Wordt vanaf de berekende ophaaldag teruggeteld om de uiterste pickdatum te bepalen." })] }), _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(Scale, { className: "h-4 w-4 text-primary" }), _jsx(Label, { htmlFor: "pickDistribution", className: "font-semibold", children: "Pickverdeling" })] }), _jsx("p", { className: "text-xs text-muted-foreground max-w-prose", children: "Verdeelt de pickbelasting automatisch over werkdagen. Orders mogen eerder ingepland worden, maar nooit later dan de berekende uiterste pickdatum \u2014 leverbetrouwbaarheid blijft gegarandeerd." })] }), _jsx(Switch, { id: "pickDistribution", checked: distributionEnabled, onCheckedChange: setDistributionEnabled })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "maxEarlier", children: "Maximaal aantal werkdagen eerder picken" }), _jsx(Input, { id: "maxEarlier", type: "number", min: 0, max: 30, value: maxEarlier, disabled: !distributionEnabled, onChange: (e) => setMaxEarlier(clamp(Number(e.target.value))) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "0 = geen vervroeging. Bijv. 2 = orders mogen maximaal 2 werkdagen voor hun uiterste pickdatum ingepland worden." })] })] }), _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" }), "."] })] })] }), _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" })] })] }));
|
|
60
72
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FloridayOrder } from "../lib/floriday.functions";
|
|
2
|
+
import { type CartOverride } from "../lib/cartAssignments.functions";
|
|
2
3
|
import { type OrderPlanning } from "../lib/planning";
|
|
3
4
|
export interface PlannedOrder {
|
|
4
5
|
order: FloridayOrder;
|
|
@@ -6,8 +7,10 @@ export interface PlannedOrder {
|
|
|
6
7
|
}
|
|
7
8
|
export interface UseOrderPlanningResult {
|
|
8
9
|
planned: PlannedOrder[];
|
|
10
|
+
overrides: CartOverride[];
|
|
9
11
|
isLoading: boolean;
|
|
10
12
|
error?: string;
|
|
13
|
+
warning?: string;
|
|
11
14
|
refetch: () => void;
|
|
12
15
|
}
|
|
13
16
|
export declare function useOrderPlanning(): UseOrderPlanningResult;
|
|
@@ -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;AAI/D,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,gBAAgB,IAAI,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;AAI/D,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACxF,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,gBAAgB,IAAI,sBAAsB,CAuHzD"}
|
|
@@ -4,16 +4,25 @@ import { useServerFn } from "@tanstack/react-start";
|
|
|
4
4
|
import { getFloridayOrders } from "../lib/floriday.functions";
|
|
5
5
|
import { getAfhandelingSettings } from "../lib/afhandelingSettings.functions";
|
|
6
6
|
import { listCarriers } from "../lib/carriers.functions";
|
|
7
|
+
import { listCartOverrides } from "../lib/cartAssignments.functions";
|
|
7
8
|
import { calculateOrderPlanning, distributePickDates, DEFAULT_PICKUP_MOMENT, } from "../lib/planning";
|
|
8
9
|
export function useOrderPlanning() {
|
|
9
10
|
const fetchOrders = useServerFn(getFloridayOrders);
|
|
10
11
|
const fetchSettings = useServerFn(getAfhandelingSettings);
|
|
11
12
|
const fetchCarriers = useServerFn(listCarriers);
|
|
13
|
+
const fetchOverrides = useServerFn(listCartOverrides);
|
|
12
14
|
const ordersQuery = useQuery({
|
|
13
15
|
queryKey: ["floriday", "orders"],
|
|
14
16
|
queryFn: async () => {
|
|
15
17
|
try {
|
|
16
|
-
|
|
18
|
+
const result = await fetchOrders();
|
|
19
|
+
if (result.error) {
|
|
20
|
+
console.warn("[useOrderPlanning] orders loaded with warning", {
|
|
21
|
+
message: result.error,
|
|
22
|
+
orderCount: result.orders.length,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
17
26
|
}
|
|
18
27
|
catch (e) {
|
|
19
28
|
let message = "Onbekende fout";
|
|
@@ -27,6 +36,10 @@ export function useOrderPlanning() {
|
|
|
27
36
|
else {
|
|
28
37
|
message = String(e);
|
|
29
38
|
}
|
|
39
|
+
console.error("[useOrderPlanning] orders load failed", {
|
|
40
|
+
message,
|
|
41
|
+
action: "fetch planning orders",
|
|
42
|
+
});
|
|
30
43
|
return { orders: [], error: message };
|
|
31
44
|
}
|
|
32
45
|
},
|
|
@@ -55,6 +68,18 @@ export function useOrderPlanning() {
|
|
|
55
68
|
},
|
|
56
69
|
retry: false,
|
|
57
70
|
});
|
|
71
|
+
const overridesQuery = useQuery({
|
|
72
|
+
queryKey: ["cart-overrides"],
|
|
73
|
+
queryFn: async () => {
|
|
74
|
+
try {
|
|
75
|
+
return await fetchOverrides();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return { overrides: [] };
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
retry: false,
|
|
82
|
+
});
|
|
58
83
|
const planned = useMemo(() => {
|
|
59
84
|
const orders = ordersQuery.data?.orders ?? [];
|
|
60
85
|
const settings = settingsQuery.data ?? {
|
|
@@ -64,10 +89,18 @@ export function useOrderPlanning() {
|
|
|
64
89
|
maxWorkdaysEarlierPick: 2,
|
|
65
90
|
};
|
|
66
91
|
const carriers = carriersQuery.data?.carriers ?? [];
|
|
92
|
+
const overrides = overridesQuery.data?.overrides ?? [];
|
|
67
93
|
const defaultCarrier = carriers.find((c) => c.is_default);
|
|
68
94
|
const moments = defaultCarrier && defaultCarrier.pickup_moments.length > 0
|
|
69
95
|
? defaultCarrier.pickup_moments
|
|
70
96
|
: [DEFAULT_PICKUP_MOMENT];
|
|
97
|
+
const overrideMap = new Map();
|
|
98
|
+
for (const o of overrides) {
|
|
99
|
+
overrideMap.set(`${o.order_source}#${o.order_id}#${o.cart_index}`, {
|
|
100
|
+
date: new Date(o.pick_date),
|
|
101
|
+
movedFromDate: o.moved_from_date ? new Date(o.moved_from_date) : null,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
71
104
|
const initial = orders.map((order) => ({
|
|
72
105
|
order,
|
|
73
106
|
planning: calculateOrderPlanning(order.deliveryDate, {
|
|
@@ -76,15 +109,23 @@ export function useOrderPlanning() {
|
|
|
76
109
|
orderCreatedAt: order.createdAt,
|
|
77
110
|
}),
|
|
78
111
|
}));
|
|
79
|
-
|
|
112
|
+
const distributed = distributePickDates(initial, {
|
|
80
113
|
enabled: Boolean(settings.pickDistributionEnabled),
|
|
81
114
|
maxWorkdaysEarlier: settings.maxWorkdaysEarlierPick ?? 0,
|
|
115
|
+
getCartCount: (it) => it.order.cartCount ?? 1,
|
|
116
|
+
getCartOverride: (it, idx) => {
|
|
117
|
+
const src = it.order.source;
|
|
118
|
+
return overrideMap.get(`${src}#${it.order.id}#${idx}`) ?? null;
|
|
119
|
+
},
|
|
82
120
|
});
|
|
83
|
-
|
|
121
|
+
return distributed;
|
|
122
|
+
}, [ordersQuery.data, settingsQuery.data, carriersQuery.data, overridesQuery.data]);
|
|
84
123
|
return {
|
|
85
124
|
planned,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
125
|
+
overrides: overridesQuery.data?.overrides ?? [],
|
|
126
|
+
isLoading: ordersQuery.isLoading || settingsQuery.isLoading || carriersQuery.isLoading || overridesQuery.isLoading,
|
|
127
|
+
error: ordersQuery.data?.orders?.length ? undefined : ordersQuery.data?.error,
|
|
128
|
+
warning: ordersQuery.data?.orders?.length ? ordersQuery.data?.error : undefined,
|
|
129
|
+
refetch: () => { void ordersQuery.refetch(); void overridesQuery.refetch(); },
|
|
89
130
|
};
|
|
90
131
|
}
|