@flowselections/floriday-verkoop-module 1.0.66 → 1.0.67
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/verkoop/AnalyticsCards.d.ts +1 -1
- package/dist-lib/components/verkoop/AnalyticsCards.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CartAssignmentWizard.d.ts +1 -1
- package/dist-lib/components/verkoop/CartAssignmentWizard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CartAssignmentWizard.js +1 -1
- package/dist-lib/components/verkoop/CartLayersDialog.d.ts +1 -1
- package/dist-lib/components/verkoop/CartLayersDialog.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CartLayersDialog.js +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.d.ts +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.js +5 -5
- package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts +1 -1
- package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts.map +1 -1
- package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts +1 -1
- package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts.map +1 -1
- package/dist-lib/components/verkoop/EngineBufferCard.d.ts +1 -1
- package/dist-lib/components/verkoop/EngineBufferCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/EngineBufferCard.js +1 -1
- package/dist-lib/components/verkoop/InvoiceTimingSettings.d.ts +1 -1
- package/dist-lib/components/verkoop/InvoiceTimingSettings.d.ts.map +1 -1
- package/dist-lib/components/verkoop/InvoiceTimingSettings.js +2 -2
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.d.ts +1 -1
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.js +1 -1
- package/dist-lib/components/verkoop/OrderCarrierPicker.d.ts +1 -1
- package/dist-lib/components/verkoop/OrderCarrierPicker.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderCarrierPicker.js +1 -1
- package/dist-lib/components/verkoop/OrderControlStatusCard.d.ts +1 -1
- package/dist-lib/components/verkoop/OrderControlStatusCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts +2 -2
- package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderKarindelingCard.js +4 -4
- package/dist-lib/components/verkoop/OrderLinePackingCard.d.ts +1 -1
- package/dist-lib/components/verkoop/OrderLinePackingCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderPickupMomentPicker.d.ts +1 -1
- package/dist-lib/components/verkoop/OrderPickupMomentPicker.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderPickupMomentPicker.js +1 -1
- package/dist-lib/components/verkoop/OrderShipmentsCard.d.ts +2 -2
- package/dist-lib/components/verkoop/OrderShipmentsCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderShipmentsCard.js +2 -2
- package/dist-lib/components/verkoop/ProductDimensionsSettings.d.ts +1 -1
- package/dist-lib/components/verkoop/ProductDimensionsSettings.d.ts.map +1 -1
- package/dist-lib/components/verkoop/ProductDimensionsSettings.js +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailPage.js +12 -12
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts +1 -1
- package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts +1 -1
- package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts +2 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.js +3 -3
- package/dist-lib/components/verkoop/SearchableSelect.d.ts +1 -1
- package/dist-lib/components/verkoop/SearchableSelect.d.ts.map +1 -1
- package/dist-lib/components/verkoop/StockConsumptionAlertsBanner.d.ts +1 -1
- package/dist-lib/components/verkoop/StockConsumptionAlertsBanner.d.ts.map +1 -1
- package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts +1 -1
- package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/WeekCalendar.d.ts +1 -1
- package/dist-lib/components/verkoop/WeekCalendar.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.js +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/lib/tradeitems.functions.d.ts +1117 -12
- package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -1
- package/dist-lib/lib/useBufferEvents.d.ts +2 -2
- package/dist-lib/lib/useBufferEvents.d.ts.map +1 -1
- package/dist-lib/lib/useLocalSalesOrderDetailQuery.d.ts +2 -2
- package/dist-lib/lib/useLocalSalesOrderDetailQuery.d.ts.map +1 -1
- package/dist-lib/lib/useSalesOrderDetailQuery.d.ts +1 -1
- package/dist-lib/lib/useSalesOrderDetailQuery.d.ts.map +1 -1
- package/dist-lib/lib/useSalesOrdersQuery.d.ts +1 -1
- package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
- package/package.json +131 -131
- package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts +0 -9
- package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts.map +0 -1
- package/dist-lib/components/floriday/FlorydaySyncHealthBanner.js +0 -26
- package/dist-lib/components/karindeling/AfmetingenTab.d.ts +0 -6
- package/dist-lib/components/karindeling/AfmetingenTab.d.ts.map +0 -1
- package/dist-lib/components/karindeling/AfmetingenTab.js +0 -128
- package/dist-lib/components/karindeling/KarindelingPage.d.ts +0 -2
- package/dist-lib/components/karindeling/KarindelingPage.d.ts.map +0 -1
- package/dist-lib/components/karindeling/KarindelingPage.js +0 -102
- package/dist-lib/components/ui/dropdown-menu.d.ts +0 -9
- package/dist-lib/components/ui/dropdown-menu.d.ts.map +0 -1
- package/dist-lib/components/ui/dropdown-menu.js +0 -14
- package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.d.ts +0 -4
- package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.d.ts.map +0 -1
- package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.js +0 -95
- package/dist-lib/components/verkoop/CreateOrderDialog.d.ts +0 -5
- package/dist-lib/components/verkoop/CreateOrderDialog.d.ts.map +0 -1
- package/dist-lib/components/verkoop/CreateOrderDialog.js +0 -33
- package/dist-lib/lib/cron/mirror-floriday-orders.d.ts +0 -4
- package/dist-lib/lib/cron/mirror-floriday-orders.d.ts.map +0 -1
- package/dist-lib/lib/cron/mirror-floriday-orders.js +0 -23
- package/dist-lib/lib/cron/push-order-statuses.d.ts +0 -4
- package/dist-lib/lib/cron/push-order-statuses.d.ts.map +0 -1
- package/dist-lib/lib/cron/push-order-statuses.js +0 -23
- package/dist-lib/lib/floriday/floriday.server.d.ts +0 -14
- package/dist-lib/lib/floriday/floriday.server.d.ts.map +0 -1
- package/dist-lib/lib/floriday/floriday.server.js +0 -92
- package/dist-lib/lib/floriday/sales-orders.functions.d.ts +0 -4736
- package/dist-lib/lib/floriday/sales-orders.functions.d.ts.map +0 -1
- package/dist-lib/lib/floriday/sales-orders.functions.js +0 -193
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts +0 -77581
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts.map +0 -1
- package/dist-lib/lib/floriday-auto-fulfillment.functions.js +0 -65
- package/dist-lib/lib/floriday-auto-fulfillment.server.d.ts +0 -21
- package/dist-lib/lib/floriday-auto-fulfillment.server.d.ts.map +0 -1
- package/dist-lib/lib/floriday-auto-fulfillment.server.js +0 -352
- package/dist-lib/lib/floriday-status-sync.server.d.ts +0 -14
- package/dist-lib/lib/floriday-status-sync.server.d.ts.map +0 -1
- package/dist-lib/lib/floriday-status-sync.server.js +0 -130
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
-
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Checkbox, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, toast, } from "@flowselections/core";
|
|
6
|
-
import { Trash2 } from "lucide-react";
|
|
7
|
-
import { deletePickTime, getCartPlanningBundle, updateCartPlanningSettings, upsertPickTime, } from "../../lib/cart-planning-settings.functions";
|
|
8
|
-
import { rebufferAllOrders } from "../../lib/order-buffers.functions";
|
|
9
|
-
import { AfmetingenTab } from "./AfmetingenTab";
|
|
10
|
-
export function KarindelingPage() {
|
|
11
|
-
const fetchBundle = useServerFn(getCartPlanningBundle);
|
|
12
|
-
const { data, isLoading } = useQuery({
|
|
13
|
-
queryKey: ["cart-planning-bundle"],
|
|
14
|
-
queryFn: () => fetchBundle(),
|
|
15
|
-
});
|
|
16
|
-
return (_jsxs("div", { className: "p-6 space-y-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: "Karindeling" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Bepaal hoe de karplanner orders indeelt op karren." })] }), _jsxs(Tabs, { defaultValue: "regels", className: "space-y-4", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "regels", children: "Regels" }), _jsx(TabsTrigger, { value: "afmetingen", children: "Afmetingen" }), _jsx(TabsTrigger, { value: "picktijden", children: "Picktijden" }), _jsx(TabsTrigger, { value: "combineren", children: "Combineren" }), _jsx(TabsTrigger, { value: "orderbuffer", children: "Orderbuffer" }), _jsx(TabsTrigger, { value: "pickstation", children: "Pickstation" })] }), isLoading || !data ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Laden\u2026" })) : (_jsxs(_Fragment, { children: [_jsx(TabsContent, { value: "regels", children: _jsx(RegelsTab, { settings: data.settings }) }), _jsx(TabsContent, { value: "afmetingen", children: _jsx(AfmetingenTab, { cartTypes: data.cartTypes, crateTypes: data.crateTypes }) }), _jsx(TabsContent, { value: "picktijden", children: _jsx(PicktijdenTab, { settings: data.settings, pickTimes: data.pickTimes }) }), _jsx(TabsContent, { value: "combineren", children: _jsx(CombinerenTab, { settings: data.settings }) }), _jsx(TabsContent, { value: "orderbuffer", children: _jsx(OrderbufferTab, { settings: data.settings }) }), _jsx(TabsContent, { value: "pickstation", children: _jsx(PickstationTab, { settings: data.settings }) })] }))] })] }));
|
|
17
|
-
}
|
|
18
|
-
function useSaveSettings() {
|
|
19
|
-
const qc = useQueryClient();
|
|
20
|
-
const save = useServerFn(updateCartPlanningSettings);
|
|
21
|
-
return useMutation({
|
|
22
|
-
mutationFn: (input) => save({ data: input }),
|
|
23
|
-
onSuccess: () => {
|
|
24
|
-
toast.success("Opgeslagen");
|
|
25
|
-
qc.invalidateQueries({ queryKey: ["cart-planning-bundle"] });
|
|
26
|
-
},
|
|
27
|
-
onError: (e) => toast.error(e?.message ?? "Opslaan mislukt"),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
function stripId(s) {
|
|
31
|
-
const { id: _id, ...rest } = s;
|
|
32
|
-
return rest;
|
|
33
|
-
}
|
|
34
|
-
function RegelsTab({ settings }) {
|
|
35
|
-
const [s, setS] = useState(settings);
|
|
36
|
-
const mut = useSaveSettings();
|
|
37
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Globale planner-regels" }), _jsx(CardDescription, { children: "Deze regels gelden voor alle orders die automatisch op karren worden ingedeeld." })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Max % per partij per laag" }), _jsx(Input, { type: "number", min: 1, max: 100, value: s.max_party_share_per_layer_pct, onChange: (e) => setS({ ...s, max_party_share_per_layer_pct: Number(e.target.value) }) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Hoeveel van \u00E9\u00E9n laag mag door \u00E9\u00E9n partij bezet worden. Standaard 50%." })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Max verschillende beladingen per laag" }), _jsx(Input, { type: "number", min: 1, max: 999, value: s.max_beladingen_per_layer >= 999 ? "" : s.max_beladingen_per_layer, disabled: s.max_beladingen_per_layer >= 999, onChange: (e) => setS({ ...s, max_beladingen_per_layer: Number(e.target.value) }) }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: s.max_beladingen_per_layer >= 999, onCheckedChange: (v) => setS({ ...s, max_beladingen_per_layer: v ? 999 : 2 }) }), "Onbeperkt aantal soorten per belading"] }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Hoeveel verschillende artikelen samen in \u00E9\u00E9n laag mogen. Standaard 2." })] }), _jsxs("div", { className: "space-y-2 lg:col-span-2", children: [_jsx(Label, { children: "Optimalisatie-strategie" }), _jsxs(Select, { value: s.optimization_strategy, onValueChange: (v) => setS({ ...s, optimization_strategy: v }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "min_carts", children: "Minimaal aantal karren" }), _jsx(SelectItem, { value: "min_mixing", children: "Minimaal mengen (voorkeur voor pure karren)" })] })] })] })] }), _jsx(Button, { disabled: mut.isPending, onClick: () => mut.mutate(stripId(s)), children: "Opslaan" })] })] }));
|
|
38
|
-
}
|
|
39
|
-
function PicktijdenTab({ settings, pickTimes, }) {
|
|
40
|
-
const qc = useQueryClient();
|
|
41
|
-
const upsert = useServerFn(upsertPickTime);
|
|
42
|
-
const remove = useServerFn(deletePickTime);
|
|
43
|
-
const [potSize, setPotSize] = useState("");
|
|
44
|
-
const [minutes, setMinutes] = useState(0);
|
|
45
|
-
const saveSettings = useSaveSettings();
|
|
46
|
-
const addMut = useMutation({
|
|
47
|
-
mutationFn: () => upsert({ data: { pot_size: potSize.trim(), seconds_per_cart: Math.round(minutes * 60) } }),
|
|
48
|
-
onSuccess: () => {
|
|
49
|
-
toast.success("Toegevoegd");
|
|
50
|
-
setPotSize("");
|
|
51
|
-
setMinutes(0);
|
|
52
|
-
qc.invalidateQueries({ queryKey: ["cart-planning-bundle"] });
|
|
53
|
-
},
|
|
54
|
-
onError: (e) => toast.error(e?.message ?? "Fout"),
|
|
55
|
-
});
|
|
56
|
-
const delMut = useMutation({
|
|
57
|
-
mutationFn: (id) => remove({ data: { id } }),
|
|
58
|
-
onSuccess: () => qc.invalidateQueries({ queryKey: ["cart-planning-bundle"] }),
|
|
59
|
-
});
|
|
60
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Picktijden" }), _jsx(CardDescription, { children: "Kies hoe je de picksnelheid meet: per potmaat (minuten per kar) of als planten per uur." })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Meetmethode" }), _jsxs(Select, { value: settings.pick_time_mode, onValueChange: (v) => saveSettings.mutate({ ...stripId(settings), pick_time_mode: v }), children: [_jsx(SelectTrigger, { className: "max-w-md", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "per_pot_size", children: "Minuten per kar per potmaat" }), _jsx(SelectItem, { value: "plants_per_hour", children: "Planten per uur" }), _jsx(SelectItem, { value: "plants_per_day", children: "Planten per dag" })] })] })] }), settings.pick_time_mode === "plants_per_hour" ? (_jsx(PlantsPerHourEditor, { settings: settings })) : settings.pick_time_mode === "plants_per_day" ? (_jsx(PlantsPerDayEditor, { settings: settings })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-end gap-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Potmaat" }), _jsx(Input, { value: potSize, onChange: (e) => setPotSize(e.target.value), placeholder: "bv. P12" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Minuten per kar per medewerker" }), _jsx(Input, { type: "number", min: 0, step: 0.5, value: minutes, onChange: (e) => setMinutes(Number(e.target.value)) })] }), _jsx(Button, { disabled: addMut.isPending || !potSize.trim(), onClick: () => addMut.mutate(), children: "Toevoegen / bijwerken" })] }), _jsx(Separator, {}), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Potmaat" }), _jsx(TableHead, { className: "text-right", children: "Minuten / kar / medewerker" }), _jsx(TableHead, { className: "w-16" })] }) }), _jsx(TableBody, { children: pickTimes.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 3, className: "text-sm text-muted-foreground", children: "Nog geen picktijden ingesteld." }) })) : (pickTimes.map((pt) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: pt.pot_size }), _jsx(TableCell, { className: "text-right", children: (pt.seconds_per_cart / 60).toLocaleString("nl-NL", { maximumFractionDigits: 2 }) }), _jsx(TableCell, { children: _jsx(Button, { variant: "ghost", size: "sm", onClick: () => delMut.mutate(pt.id), children: _jsx(Trash2, { className: "h-4 w-4" }) }) })] }, pt.id)))) })] })] }))] })] }));
|
|
61
|
-
}
|
|
62
|
-
function PlantsPerHourEditor({ settings }) {
|
|
63
|
-
const [pph, setPph] = useState(settings.plants_per_hour);
|
|
64
|
-
const save = useSaveSettings();
|
|
65
|
-
return (_jsxs("div", { className: "flex items-end gap-2 rounded-md border p-3", children: [_jsxs("div", { className: "space-y-2 flex-1 max-w-md", children: [_jsx(Label, { children: "Planten per uur per medewerker" }), _jsx(Input, { type: "number", min: 0, value: pph, onChange: (e) => setPph(Number(e.target.value)) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Wordt gebruikt om de totale picktijd te schatten op basis van het aantal planten." })] }), _jsx(Button, { disabled: save.isPending, onClick: () => save.mutate({ ...stripId(settings), plants_per_hour: pph }), children: "Opslaan" })] }));
|
|
66
|
-
}
|
|
67
|
-
function PlantsPerDayEditor({ settings }) {
|
|
68
|
-
const [ppd, setPpd] = useState(settings.plants_per_day ?? 0);
|
|
69
|
-
const save = useSaveSettings();
|
|
70
|
-
return (_jsxs("div", { className: "flex items-end gap-2 rounded-md border p-3", children: [_jsxs("div", { className: "space-y-2 flex-1 max-w-md", children: [_jsx(Label, { children: "Planten per dag per medewerker" }), _jsx(Input, { type: "number", min: 0, value: ppd, onChange: (e) => setPpd(Number(e.target.value)) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Wordt gebruikt om de totale picktijd te schatten op basis van het aantal planten per dag." })] }), _jsx(Button, { disabled: save.isPending, onClick: () => save.mutate({ ...stripId(settings), plants_per_day: ppd }), children: "Opslaan" })] }));
|
|
71
|
-
}
|
|
72
|
-
function CombinerenTab({ settings }) {
|
|
73
|
-
const [s, setS] = useState(settings);
|
|
74
|
-
const mut = useSaveSettings();
|
|
75
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Orders combineren op \u00E9\u00E9n kar" }), _jsx(CardDescription, { children: "Wanneer mogen order_items van verschillende (Floriday-)orders op dezelfde kar samengebracht worden?" })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between rounded-md border p-3", children: [_jsxs("div", { children: [_jsx(Label, { children: "Floriday-orders combineren" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Aan = de planner mag Floriday-orders bundelen; uit = elke order krijgt zijn eigen karren." })] }), _jsx(Switch, { checked: s.combine_floriday_orders, onCheckedChange: (v) => setS({ ...s, combine_floriday_orders: v }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Combineer-venster" }), _jsxs(Select, { value: s.combine_floriday_orders_window, onValueChange: (v) => setS({ ...s, combine_floriday_orders_window: v }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "same_day", children: "Zelfde leverdag" }), _jsx(SelectItem, { value: "same_delivery_slot", children: "Zelfde levermoment" }), _jsx(SelectItem, { value: "same_week", children: "Zelfde week" })] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Bereik" }), _jsxs(Select, { value: s.combine_orders_scope, onValueChange: (v) => setS({ ...s, combine_orders_scope: v }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "same_customer", children: "Alleen zelfde klant" }), _jsx(SelectItem, { value: "same_delivery_location", children: "Zelfde leverlocatie" }), _jsx(SelectItem, { value: "never", children: "Nooit combineren" })] })] })] }), _jsx(Separator, {}), _jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Vanaf hoeveel lagen krijgt een klant een eigen kar?" }), _jsx(Input, { type: "number", min: 1, value: s.own_cart_from_layers, onChange: (e) => setS({ ...s, own_cart_from_layers: Number(e.target.value) }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Maximaal aantal klanten op \u00E9\u00E9n kar" }), _jsx(Input, { type: "number", min: 1, value: s.max_customers_per_cart, onChange: (e) => setS({ ...s, max_customers_per_cart: Number(e.target.value) }) })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Klanten per laag" }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: s.max_one_customer_per_layer ? "outline" : "default", onClick: () => setS({ ...s, max_one_customer_per_layer: false }), children: "Meerdere klanten op \u00E9\u00E9n laag" }), _jsx(Button, { variant: s.max_one_customer_per_layer ? "default" : "outline", onClick: () => setS({ ...s, max_one_customer_per_layer: true }), children: "Max \u00E9\u00E9n klant per laag" })] })] }), _jsxs("div", { className: "grid gap-3 lg:grid-cols-2", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: s.require_same_carrier, onCheckedChange: (v) => setS({ ...s, require_same_carrier: !!v }) }), "Alleen dezelfde vervoerder"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: s.require_same_delivery_location, onCheckedChange: (v) => setS({ ...s, require_same_delivery_location: !!v }) }), "Alleen dezelfde afleverlocatie"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: s.require_same_crate_type, onCheckedChange: (v) => setS({ ...s, require_same_crate_type: !!v }) }), "Alleen hetzelfde fusttype"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx(Checkbox, { checked: s.require_same_delivery_date, onCheckedChange: (v) => setS({ ...s, require_same_delivery_date: !!v }) }), "Alleen dezelfde leverdatum"] })] }), _jsx(Button, { disabled: mut.isPending, onClick: () => mut.mutate(stripId(s)), children: "Opslaan" })] })] }));
|
|
76
|
-
}
|
|
77
|
-
function PickstationTab({ settings }) {
|
|
78
|
-
const [s, setS] = useState(settings);
|
|
79
|
-
const mut = useSaveSettings();
|
|
80
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Na verzending naar pickstation" }), _jsx(CardDescription, { children: "Wanneer een kar-pakbon eenmaal geprint is voor het pickstation, mag de karindeling dan nog wijzigen?" })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between rounded-md border p-3", children: [_jsxs("div", { children: [_jsx(Label, { children: "Wijzigen na pickstation-print toestaan" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Standaard uit: zodra de pakbon geprint is wordt de karindeling vergrendeld." })] }), _jsx(Switch, { checked: s.allow_editing_after_pickstation_send, onCheckedChange: (v) => setS({ ...s, allow_editing_after_pickstation_send: v }) })] }), _jsx(Badge, { variant: "outline", children: s.allow_editing_after_pickstation_send ? "Bewerken toegestaan" : "Vergrendeld na print" }), _jsx("div", { children: _jsx(Button, { disabled: mut.isPending, onClick: () => mut.mutate(stripId(s)), children: "Opslaan" }) })] })] }));
|
|
81
|
-
}
|
|
82
|
-
function OrderbufferTab({ settings }) {
|
|
83
|
-
const [s, setS] = useState(settings);
|
|
84
|
-
const mut = useSaveSettings();
|
|
85
|
-
const rebuffer = useServerFn(rebufferAllOrders);
|
|
86
|
-
const [rebuffering, setRebuffering] = useState(false);
|
|
87
|
-
const save = async () => {
|
|
88
|
-
await mut.mutateAsync(stripId(s));
|
|
89
|
-
setRebuffering(true);
|
|
90
|
-
try {
|
|
91
|
-
const res = await rebuffer();
|
|
92
|
-
toast.success(`Buffer bijgewerkt · ${res.processed} order(s) hergegroepeerd`);
|
|
93
|
-
}
|
|
94
|
-
catch (err) {
|
|
95
|
-
toast.error(`Herbufferen faalde: ${err.message}`);
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
98
|
-
setRebuffering(false);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Orderbuffer" }), _jsx(CardDescription, { children: "Bepaal wanneer orders in dezelfde buffer worden geplaatst voordat ze op karren worden ingedeeld." })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Wanneer horen orders in dezelfde buffer?" }), _jsxs(Select, { value: s.buffer_grouping_mode, onValueChange: (v) => setS({ ...s, buffer_grouping_mode: v }), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "same_pickup_and_location", children: "Zelfde ophaalmoment \u00E9n zelfde afleverlocatie (aanbevolen)" }), _jsx(SelectItem, { value: "same_pickup", children: "Alleen zelfde ophaalmoment" }), _jsx(SelectItem, { value: "same_location", children: "Alleen zelfde afleverlocatie" }), _jsx(SelectItem, { value: "same_customer", children: "Alleen zelfde klant" }), _jsx(SelectItem, { value: "never", children: "Nooit samenvoegen \u2014 elke order eigen buffer" })] })] }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Na opslaan worden alle bestaande orders opnieuw in de juiste buffer geplaatst. De karindeling per buffer wordt bij de eerstvolgende (her)berekening opnieuw uitgevoerd." })] }), _jsx(Button, { disabled: mut.isPending || rebuffering, onClick: save, children: rebuffering ? "Bezig met herbufferen…" : "Opslaan" })] })] }));
|
|
102
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
3
|
-
declare const DropdownMenu: React.FC<DropdownMenuPrimitive.DropdownMenuProps>;
|
|
4
|
-
declare const DropdownMenuTrigger: React.ForwardRefExoticComponent<DropdownMenuPrimitive.DropdownMenuTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
5
|
-
declare const DropdownMenuContent: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
-
declare const DropdownMenuItem: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
-
declare const DropdownMenuSeparator: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuSeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
-
export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, };
|
|
9
|
-
//# sourceMappingURL=dropdown-menu.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dropdown-menu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,qBAAqB,MAAM,+BAA+B,CAAC;AAGvE,QAAA,MAAM,YAAY,mDAA6B,CAAC;AAChD,QAAA,MAAM,mBAAmB,0HAAgC,CAAC;AAE1D,QAAA,MAAM,mBAAmB,0KAgBvB,CAAC;AAGH,QAAA,MAAM,gBAAgB,uKAapB,CAAC;AAGH,QAAA,MAAM,qBAAqB,4KASzB,CAAC;AAGH,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
5
|
-
import { cn } from "@flowselections/core";
|
|
6
|
-
const DropdownMenu = DropdownMenuPrimitive.Root;
|
|
7
|
-
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
8
|
-
const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(DropdownMenuPrimitive.Portal, { children: _jsx(DropdownMenuPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn("z-50 min-w-[10rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props }) })));
|
|
9
|
-
DropdownMenuContent.displayName = "DropdownMenuContent";
|
|
10
|
-
const DropdownMenuItem = React.forwardRef(({ className, ...props }, ref) => (_jsx(DropdownMenuPrimitive.Item, { ref: ref, className: cn("relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors", "focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props })));
|
|
11
|
-
DropdownMenuItem.displayName = "DropdownMenuItem";
|
|
12
|
-
const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx(DropdownMenuPrimitive.Separator, { ref: ref, className: cn("-mx-1 my-1 h-px bg-muted", className), ...props })));
|
|
13
|
-
DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
|
|
14
|
-
export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AutoFulfillmentStatusCard.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/AutoFulfillmentStatusCard.tsx"],"names":[],"mappings":"AAyDA,wBAAgB,yBAAyB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,kDA6FnF"}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
|
-
import { useServerFn } from "@tanstack/react-start";
|
|
4
|
-
import { useEffect } from "react";
|
|
5
|
-
import { supabase } from "../../integrations/supabase/client";
|
|
6
|
-
import { getAutoFulfillmentStatus, retryAutoFulfillment, getPreferredWarehouseStatus, } from "../../lib/floriday-auto-fulfillment.functions";
|
|
7
|
-
import { Button } from "@flowselections/core";
|
|
8
|
-
import { toast } from "sonner";
|
|
9
|
-
const REASON_LABELS = {
|
|
10
|
-
"no-preferred-warehouse": "Er is nog geen voorkeursmagazijn ingesteld op de Floriday-connectie.",
|
|
11
|
-
"no-warehouse": "Geen despatch-magazijn gevonden (voorkeur, salesorder, én cache leeg).",
|
|
12
|
-
"no-delivery-order": "Nog geen delivery order (met fulfillment-requests) ontvangen van Floriday voor deze salesorder.",
|
|
13
|
-
"existing-fulfillment": "Er bestaat al een fulfillment order voor deze salesorder.",
|
|
14
|
-
"sales-order-deleted": "Salesorder is verwijderd bij Floriday.",
|
|
15
|
-
"already-created": "Fulfillment order is al automatisch aangemaakt.",
|
|
16
|
-
"connection-not-found": "Floriday-connectie niet gevonden.",
|
|
17
|
-
"no-packing-fallback": "Belading ontbreekt; er is een enkele kar als fallback gebruikt.",
|
|
18
|
-
"warehouse-fallback:order": "Despatch-magazijn overgenomen uit de salesorder (geen voorkeursmagazijn ingesteld).",
|
|
19
|
-
"warehouse-fallback:cache": "Fallback-magazijn uit cache gebruikt; stel eventueel een voorkeur in bij de Authenticatiemodule.",
|
|
20
|
-
};
|
|
21
|
-
function statusStyle(status) {
|
|
22
|
-
switch (status) {
|
|
23
|
-
case "created":
|
|
24
|
-
return "bg-emerald-50 text-emerald-800 border-emerald-200";
|
|
25
|
-
case "failed":
|
|
26
|
-
return "bg-red-50 text-red-800 border-red-200";
|
|
27
|
-
case "skipped":
|
|
28
|
-
return "bg-amber-50 text-amber-800 border-amber-200";
|
|
29
|
-
default:
|
|
30
|
-
return "bg-slate-50 text-slate-700 border-slate-200";
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function statusLabel(status) {
|
|
34
|
-
switch (status) {
|
|
35
|
-
case "created":
|
|
36
|
-
return "Fulfillment order automatisch aangemaakt";
|
|
37
|
-
case "failed":
|
|
38
|
-
return "Automatische fulfillment mislukt";
|
|
39
|
-
case "skipped":
|
|
40
|
-
return "Automatische fulfillment overgeslagen";
|
|
41
|
-
default:
|
|
42
|
-
return "Fulfillment nog niet automatisch aangemaakt";
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
export function AutoFulfillmentStatusCard({ salesOrderId }) {
|
|
46
|
-
const queryClient = useQueryClient();
|
|
47
|
-
const fetchStatus = useServerFn(getAutoFulfillmentStatus);
|
|
48
|
-
const retryFn = useServerFn(retryAutoFulfillment);
|
|
49
|
-
const queryKey = ["auto-fulfillment-status", salesOrderId];
|
|
50
|
-
const { data, isLoading } = useQuery({
|
|
51
|
-
queryKey,
|
|
52
|
-
queryFn: () => fetchStatus({ data: { salesOrderId } }),
|
|
53
|
-
});
|
|
54
|
-
const fetchWarehouse = useServerFn(getPreferredWarehouseStatus);
|
|
55
|
-
const { data: warehouseStatus } = useQuery({
|
|
56
|
-
queryKey: ["preferred-warehouse-status"],
|
|
57
|
-
queryFn: () => fetchWarehouse(),
|
|
58
|
-
staleTime: 60000,
|
|
59
|
-
});
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
const channel = supabase
|
|
62
|
-
.channel(`auto-fulfillment-${salesOrderId}`)
|
|
63
|
-
.on("postgres_changes", {
|
|
64
|
-
event: "*",
|
|
65
|
-
schema: "public",
|
|
66
|
-
table: "floriday_auto_fulfillment_log",
|
|
67
|
-
filter: `sales_order_id=eq.${salesOrderId}`,
|
|
68
|
-
}, () => queryClient.invalidateQueries({ queryKey }))
|
|
69
|
-
.subscribe();
|
|
70
|
-
return () => {
|
|
71
|
-
supabase.removeChannel(channel);
|
|
72
|
-
};
|
|
73
|
-
}, [salesOrderId, queryClient]);
|
|
74
|
-
const mutation = useMutation({
|
|
75
|
-
mutationFn: () => retryFn({ data: { salesOrderId } }),
|
|
76
|
-
onSuccess: (res) => {
|
|
77
|
-
queryClient.invalidateQueries({ queryKey });
|
|
78
|
-
if (res.status === "created")
|
|
79
|
-
toast.success("Fulfillment order aangemaakt");
|
|
80
|
-
else if (res.status === "failed")
|
|
81
|
-
toast.error(`Mislukt: ${res.reason ?? "onbekend"}`);
|
|
82
|
-
else
|
|
83
|
-
toast.info(`Overgeslagen: ${res.reason ?? ""}`);
|
|
84
|
-
},
|
|
85
|
-
onError: (err) => toast.error(err.message),
|
|
86
|
-
});
|
|
87
|
-
if (isLoading)
|
|
88
|
-
return null;
|
|
89
|
-
const row = data?.row ?? null;
|
|
90
|
-
const status = row?.status ?? "pending";
|
|
91
|
-
const canRetry = status === "failed" || status === "skipped" || !row;
|
|
92
|
-
return (_jsx("div", { className: `mt-4 rounded-md border p-3 text-sm ${statusStyle(status)}`, children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium", children: statusLabel(status) }), row?.fulfillment_order_id ? (_jsxs("div", { className: "mt-1 text-xs opacity-80", children: ["Fulfillment ID: ", _jsx("code", { children: row.fulfillment_order_id })] })) : null, row?.reason ? (_jsx("div", { className: "mt-1 text-xs opacity-80", children: REASON_LABELS[row.reason] ?? row.reason })) : null, row?.error ? (_jsxs("div", { className: "mt-1 text-xs opacity-80", children: ["Fout: ", row.error] })) : null, warehouseStatus &&
|
|
93
|
-
!warehouseStatus.hasPreferredWarehouse &&
|
|
94
|
-
(row?.reason === "no-preferred-warehouse" || row?.reason === "no-warehouse") ? (_jsx("div", { className: "mt-2 rounded border border-amber-300 bg-amber-50 p-2 text-xs text-amber-900", children: "Er is nog geen voorkeursmagazijn ingesteld. Ga naar de Floriday-authenticatiemodule en kies een voorkeursmagazijn \u2014 daarna worden fulfillment orders automatisch aangemaakt." })) : null] }), canRetry ? (_jsx(Button, { size: "sm", variant: "outline", disabled: mutation.isPending, onClick: () => mutation.mutate(), children: mutation.isPending ? "Bezig..." : "Opnieuw proberen" })) : null] }) }));
|
|
95
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CreateOrderDialog.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/CreateOrderDialog.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,YAAY,GACb,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,2CAgFA"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Input, Label, toast, } from "@flowselections/core";
|
|
4
|
-
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
-
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { createSalesOrder } from "../../lib/floriday/sales-orders.functions";
|
|
7
|
-
export function CreateOrderDialog({ open, onOpenChange, }) {
|
|
8
|
-
const queryClient = useQueryClient();
|
|
9
|
-
const createFn = useServerFn(createSalesOrder);
|
|
10
|
-
const [customerOrganizationId, setCustomerId] = useState("");
|
|
11
|
-
const [tradeItemId, setTradeItemId] = useState("");
|
|
12
|
-
const [deliveryDateTime, setDelivery] = useState("");
|
|
13
|
-
const [numberOfPieces, setPieces] = useState(1);
|
|
14
|
-
const [pricePerPiece, setPrice] = useState(0);
|
|
15
|
-
const [reference, setReference] = useState("");
|
|
16
|
-
const m = useMutation({
|
|
17
|
-
mutationFn: createFn,
|
|
18
|
-
onSuccess: () => {
|
|
19
|
-
toast.success("Verkooporder aangemaakt");
|
|
20
|
-
queryClient.invalidateQueries({ queryKey: ["floriday", "sales-orders"] });
|
|
21
|
-
onOpenChange(false);
|
|
22
|
-
},
|
|
23
|
-
onError: (e) => toast.error(e?.message ?? "Aanmaken mislukt"),
|
|
24
|
-
});
|
|
25
|
-
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Bestelling aanmaken" }), _jsx(DialogDescription, { children: "Maak een nieuwe verkooporder aan in Floriday." })] }), _jsxs("div", { className: "grid gap-3 py-2", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "ref", children: "Referentie" }), _jsx(Input, { id: "ref", value: reference, onChange: (e) => setReference(e.target.value), placeholder: "ORD-2026-\u2026" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "cust", children: "Klant organisatie ID" }), _jsx(Input, { id: "cust", value: customerOrganizationId, onChange: (e) => setCustomerId(e.target.value), placeholder: "GLN of organization id" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "item", children: "Artikel (tradeItemId)" }), _jsx(Input, { id: "item", value: tradeItemId, onChange: (e) => setTradeItemId(e.target.value) })] }), _jsxs("div", { className: "grid grid-cols-3 gap-3", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "qty", children: "Aantal stuks" }), _jsx(Input, { id: "qty", type: "number", min: 1, value: numberOfPieces, onChange: (e) => setPieces(Number(e.target.value)) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "price", children: "Prijs/stuk (\u20AC)" }), _jsx(Input, { id: "price", type: "number", step: "0.01", min: 0, value: pricePerPiece, onChange: (e) => setPrice(Number(e.target.value)) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "del", children: "Levering" }), _jsx(Input, { id: "del", type: "datetime-local", value: deliveryDateTime, onChange: (e) => setDelivery(e.target.value) })] })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: m.isPending, children: "Annuleren" }), _jsx(Button, { onClick: () => m.mutate({
|
|
26
|
-
data: {
|
|
27
|
-
customerOrganizationId,
|
|
28
|
-
deliveryDateTime: deliveryDateTime ? new Date(deliveryDateTime).toISOString() : "",
|
|
29
|
-
reference: reference || undefined,
|
|
30
|
-
lines: [{ tradeItemId, numberOfPieces, pricePerPiece }],
|
|
31
|
-
},
|
|
32
|
-
}), disabled: m.isPending || !customerOrganizationId || !tradeItemId || !deliveryDateTime, children: m.isPending ? "Aanmaken…" : "Aanmaken" })] })] }) }));
|
|
33
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
export declare function mirrorFloridayOrdersCron(request: Request, _supabase: SupabaseClient): Promise<Response>;
|
|
3
|
-
export declare function mirrorFloridayOrdersCronHint(_request: Request, _supabase: SupabaseClient): Promise<Response>;
|
|
4
|
-
//# sourceMappingURL=mirror-floriday-orders.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mirror-floriday-orders.d.ts","sourceRoot":"","sources":["../../../src/lib/cron/mirror-floriday-orders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,QAAQ,CAAC,CAmBnB;AAED,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,QAAQ,CAAC,CAKnB"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { mirrorFloridayOrdersFromCron } from "../floriday-mirror.functions";
|
|
2
|
-
export async function mirrorFloridayOrdersCron(request, _supabase) {
|
|
3
|
-
const apikey = request.headers.get("apikey") ?? request.headers.get("x-api-key");
|
|
4
|
-
const expected = process.env.SUPABASE_PUBLISHABLE_KEY;
|
|
5
|
-
if (!expected || !apikey || apikey !== expected) {
|
|
6
|
-
return new Response("Unauthorized", { status: 401 });
|
|
7
|
-
}
|
|
8
|
-
try {
|
|
9
|
-
const url = new URL(request.url);
|
|
10
|
-
const limit = Number(url.searchParams.get("limit") ?? "200");
|
|
11
|
-
const result = await mirrorFloridayOrdersFromCron(Number.isFinite(limit) && limit > 0 ? Math.min(1000, limit) : 200);
|
|
12
|
-
return Response.json(result);
|
|
13
|
-
}
|
|
14
|
-
catch (err) {
|
|
15
|
-
return Response.json({ ok: false, error: err.message }, { status: 500 });
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
export async function mirrorFloridayOrdersCronHint(_request, _supabase) {
|
|
19
|
-
return Response.json({
|
|
20
|
-
ok: true,
|
|
21
|
-
hint: "POST to mirror recent Floriday sales orders into local orders",
|
|
22
|
-
});
|
|
23
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
export declare function pushOrderStatusesCron(request: Request, _supabase: SupabaseClient): Promise<Response>;
|
|
3
|
-
export declare function pushOrderStatusesCronHint(_request: Request, _supabase: SupabaseClient): Promise<Response>;
|
|
4
|
-
//# sourceMappingURL=push-order-statuses.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"push-order-statuses.d.ts","sourceRoot":"","sources":["../../../src/lib/cron/push-order-statuses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,QAAQ,CAAC,CAiBnB;AAED,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,QAAQ,CAAC,CAKnB"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export async function pushOrderStatusesCron(request, _supabase) {
|
|
2
|
-
const apikey = request.headers.get("apikey") ?? request.headers.get("x-api-key");
|
|
3
|
-
const expected = process.env.SUPABASE_PUBLISHABLE_KEY;
|
|
4
|
-
if (!expected || !apikey || apikey !== expected) {
|
|
5
|
-
return new Response("Unauthorized", { status: 401 });
|
|
6
|
-
}
|
|
7
|
-
try {
|
|
8
|
-
const url = new URL(request.url);
|
|
9
|
-
const limit = Number(url.searchParams.get("limit") ?? "100");
|
|
10
|
-
const { pushOrderStatusesToFloriday } = await import("../floriday-status-sync.server");
|
|
11
|
-
const result = await pushOrderStatusesToFloriday(Number.isFinite(limit) && limit > 0 ? Math.min(500, limit) : 100);
|
|
12
|
-
return Response.json(result);
|
|
13
|
-
}
|
|
14
|
-
catch (err) {
|
|
15
|
-
return Response.json({ ok: false, error: err.message }, { status: 500 });
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
export async function pushOrderStatusesCronHint(_request, _supabase) {
|
|
19
|
-
return Response.json({
|
|
20
|
-
ok: true,
|
|
21
|
-
hint: "POST to push ERP order status changes to Floriday",
|
|
22
|
-
});
|
|
23
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export interface FlorIdayConn {
|
|
2
|
-
id: string;
|
|
3
|
-
environment: "staging" | "production" | string;
|
|
4
|
-
client_id: string;
|
|
5
|
-
client_secret: string;
|
|
6
|
-
api_key: string;
|
|
7
|
-
access_token: string | null;
|
|
8
|
-
token_expires_at: string | null;
|
|
9
|
-
organization_name: string | null;
|
|
10
|
-
gln_code: string | null;
|
|
11
|
-
}
|
|
12
|
-
export declare function getActiveConnection(): Promise<FlorIdayConn>;
|
|
13
|
-
export declare function florIdayFetch<T = unknown>(path: string, init?: RequestInit): Promise<T>;
|
|
14
|
-
//# sourceMappingURL=floriday.server.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"floriday.server.d.ts","sourceRoot":"","sources":["../../../src/lib/floriday/floriday.server.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAiBD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,YAAY,CAAC,CAsBjE;AAqCD,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAC7C,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,CAAC,CAAC,CAoBZ"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// Floriday Suppliers API client (server-only)
|
|
2
|
-
import { supabaseAdmin } from "../../integrations/supabase/client.server";
|
|
3
|
-
function endpoints(env) {
|
|
4
|
-
const isProd = env === "production" || env === "prod";
|
|
5
|
-
return {
|
|
6
|
-
auth: isProd
|
|
7
|
-
? "https://accounts.floriday.io/oauth/token"
|
|
8
|
-
: "https://accounts.staging.floriday.io/oauth/token",
|
|
9
|
-
audience: isProd
|
|
10
|
-
? "https://api.floriday.io"
|
|
11
|
-
: "https://api.staging.floriday.io",
|
|
12
|
-
api: isProd
|
|
13
|
-
? "https://api.floriday.io/suppliers-api-2026v1"
|
|
14
|
-
: "https://api.staging.floriday.io/suppliers-api-2026v1",
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
export async function getActiveConnection() {
|
|
18
|
-
const { data: settings } = await supabaseAdmin
|
|
19
|
-
.from("floriday_settings")
|
|
20
|
-
.select("active_environment")
|
|
21
|
-
.eq("id", 1)
|
|
22
|
-
.maybeSingle();
|
|
23
|
-
const env = settings?.active_environment ?? "staging";
|
|
24
|
-
const { data, error } = await supabaseAdmin
|
|
25
|
-
.from("floriday_connections")
|
|
26
|
-
.select("id,environment,client_id,client_secret,api_key,access_token,token_expires_at,organization_name,gln_code,is_active")
|
|
27
|
-
.eq("environment", env)
|
|
28
|
-
.eq("is_active", true)
|
|
29
|
-
.order("updated_at", { ascending: false })
|
|
30
|
-
.limit(1)
|
|
31
|
-
.maybeSingle();
|
|
32
|
-
if (error)
|
|
33
|
-
throw new Error(`Floriday connectie ophalen mislukt: ${error.message}`);
|
|
34
|
-
if (!data)
|
|
35
|
-
throw new Error(`Geen actieve Floriday connectie voor omgeving "${env}"`);
|
|
36
|
-
return data;
|
|
37
|
-
}
|
|
38
|
-
async function fetchToken(conn) {
|
|
39
|
-
const ep = endpoints(conn.environment);
|
|
40
|
-
const body = new URLSearchParams({
|
|
41
|
-
grant_type: "client_credentials",
|
|
42
|
-
client_id: conn.client_id,
|
|
43
|
-
client_secret: conn.client_secret,
|
|
44
|
-
audience: ep.audience,
|
|
45
|
-
});
|
|
46
|
-
const res = await fetch(ep.auth, {
|
|
47
|
-
method: "POST",
|
|
48
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
49
|
-
body,
|
|
50
|
-
});
|
|
51
|
-
const text = await res.text();
|
|
52
|
-
if (!res.ok) {
|
|
53
|
-
throw new Error(`Floriday OAuth fout [${res.status}]: ${text.slice(0, 300)}`);
|
|
54
|
-
}
|
|
55
|
-
const json = JSON.parse(text);
|
|
56
|
-
const token = json.access_token;
|
|
57
|
-
const expiresIn = json.expires_in ?? 3600;
|
|
58
|
-
const expiresAt = new Date(Date.now() + (expiresIn - 60) * 1000).toISOString();
|
|
59
|
-
await supabaseAdmin
|
|
60
|
-
.from("floriday_connections")
|
|
61
|
-
.update({ access_token: token, token_expires_at: expiresAt })
|
|
62
|
-
.eq("id", conn.id);
|
|
63
|
-
return { token, expiresAt };
|
|
64
|
-
}
|
|
65
|
-
async function ensureToken(conn) {
|
|
66
|
-
const exp = conn.token_expires_at ? new Date(conn.token_expires_at).getTime() : 0;
|
|
67
|
-
if (conn.access_token && exp > Date.now() + 60000)
|
|
68
|
-
return conn.access_token;
|
|
69
|
-
const { token } = await fetchToken(conn);
|
|
70
|
-
return token;
|
|
71
|
-
}
|
|
72
|
-
export async function florIdayFetch(path, init = {}) {
|
|
73
|
-
const conn = await getActiveConnection();
|
|
74
|
-
const token = await ensureToken(conn);
|
|
75
|
-
const ep = endpoints(conn.environment);
|
|
76
|
-
const url = path.startsWith("http") ? path : `${ep.api}${path}`;
|
|
77
|
-
const res = await fetch(url, {
|
|
78
|
-
...init,
|
|
79
|
-
headers: {
|
|
80
|
-
Accept: "application/json",
|
|
81
|
-
"Content-Type": "application/json",
|
|
82
|
-
Authorization: `Bearer ${token}`,
|
|
83
|
-
"x-api-key": conn.api_key,
|
|
84
|
-
...init.headers,
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
const text = await res.text();
|
|
88
|
-
if (!res.ok) {
|
|
89
|
-
throw new Error(`Floriday API ${res.status} ${path}: ${text.slice(0, 400)}`);
|
|
90
|
-
}
|
|
91
|
-
return (text ? JSON.parse(text) : null);
|
|
92
|
-
}
|