@flowselections/floriday-verkoop-module 1.0.45 → 1.0.47
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/OrderAfleverbrievenCard.d.ts +3 -1
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.d.ts.map +1 -1
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.js +90 -19
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.js +1 -1
- package/dist-lib/components/verkoop/StockConsumptionAlertsBanner.d.ts +6 -0
- package/dist-lib/components/verkoop/StockConsumptionAlertsBanner.d.ts.map +1 -0
- package/dist-lib/components/verkoop/StockConsumptionAlertsBanner.js +26 -0
- package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/VerkoopOrdersPage.js +2 -1
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +864 -161
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +864 -161
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.js +2 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +864 -161
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +6 -0
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/previewAuthStorage.js +92 -0
- package/dist-lib/integrations/supabase/types.d.ts +904 -185
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/cart-lock.functions.d.ts +864 -161
- package/dist-lib/lib/cart-lock.functions.d.ts.map +1 -1
- package/dist-lib/lib/cart-planning-settings.functions.d.ts +9577 -1844
- package/dist-lib/lib/cart-planning-settings.functions.d.ts.map +1 -1
- package/dist-lib/lib/cart-replan.functions.d.ts +2544 -435
- package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.d.ts +14914 -2963
- package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts +2544 -435
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-logistic-labels.functions.d.ts +864 -161
- package/dist-lib/lib/floriday-logistic-labels.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-mirror.functions.d.ts +864 -161
- package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-mirror.functions.js +39 -10
- package/dist-lib/lib/floriday-public.functions.d.ts +6019 -1098
- package/dist-lib/lib/floriday-public.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-writes.functions.d.ts +4240 -725
- package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
- package/dist-lib/lib/invoice-timing.functions.d.ts +3392 -580
- package/dist-lib/lib/invoice-timing.functions.d.ts.map +1 -1
- package/dist-lib/lib/load-carriers.functions.d.ts +864 -161
- package/dist-lib/lib/load-carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/logistics-engine.functions.d.ts +4240 -725
- package/dist-lib/lib/logistics-engine.functions.d.ts.map +1 -1
- package/dist-lib/lib/logistics-stock.functions.d.ts +1696 -290
- package/dist-lib/lib/logistics-stock.functions.d.ts.map +1 -1
- package/dist-lib/lib/order-addresses.functions.d.ts +864 -161
- package/dist-lib/lib/order-addresses.functions.d.ts.map +1 -1
- package/dist-lib/lib/order-buffers.functions.d.ts +2544 -435
- package/dist-lib/lib/order-buffers.functions.d.ts.map +1 -1
- package/dist-lib/lib/order-carrier.functions.d.ts +1696 -290
- package/dist-lib/lib/order-carrier.functions.d.ts.map +1 -1
- package/dist-lib/lib/order-pickup.functions.d.ts +1696 -290
- package/dist-lib/lib/order-pickup.functions.d.ts.map +1 -1
- package/dist-lib/lib/order-shipments.functions.d.ts +3392 -580
- package/dist-lib/lib/order-shipments.functions.d.ts.map +1 -1
- package/dist-lib/lib/salesorders-list.functions.d.ts +864 -161
- package/dist-lib/lib/salesorders-list.functions.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.d.ts +4240 -725
- package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
- package/dist-lib/lib/stock-consumption-alerts.functions.d.ts +45850 -0
- package/dist-lib/lib/stock-consumption-alerts.functions.d.ts.map +1 -0
- package/dist-lib/lib/stock-consumption-alerts.functions.js +50 -0
- package/dist-lib/lib/tradeitems.functions.d.ts +864 -161
- package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export declare function OrderAfleverbrievenCard({ salesOrderId }: {
|
|
1
|
+
export declare function OrderAfleverbrievenCard({ salesOrderId, orderNumber, werkplek, }: {
|
|
2
2
|
salesOrderId: string;
|
|
3
|
+
orderNumber?: string;
|
|
4
|
+
werkplek?: string;
|
|
3
5
|
}): import("react/jsx-runtime").JSX.Element;
|
|
4
6
|
//# sourceMappingURL=OrderAfleverbrievenCard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrderAfleverbrievenCard.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/OrderAfleverbrievenCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OrderAfleverbrievenCard.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/OrderAfleverbrievenCard.tsx"],"names":[],"mappings":"AAuCA,wBAAgB,uBAAuB,CAAC,EACtC,YAAY,EACZ,WAAW,EACX,QAAQ,GACT,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,2CAmLA"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
3
|
import { useQuery } from "@tanstack/react-query";
|
|
3
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
4
5
|
import { Badge, Button, Card, CardContent, CardHeader, CardTitle } from "@flowselections/core";
|
|
5
|
-
import { FileText, Printer, ExternalLink, RefreshCw } from "lucide-react";
|
|
6
|
+
import { FileText, Printer, ExternalLink, RefreshCw, Loader2 } from "lucide-react";
|
|
7
|
+
import { toast } from "sonner";
|
|
8
|
+
import { printPdf, printerVoorWerkplek, printerVoorDocumenttype, volgJobStatus, } from "@flowselections/layout-maker";
|
|
6
9
|
import { listLogisticLabelsForOrder } from "../../lib/floriday-logistic-labels.functions";
|
|
7
10
|
const LC_SHORT = {
|
|
8
11
|
DANISH_TROLLEY: "DC",
|
|
@@ -13,32 +16,100 @@ const LC_SHORT = {
|
|
|
13
16
|
BLOCK_PALLET: "BP",
|
|
14
17
|
BOX: "BX",
|
|
15
18
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
}, 1200);
|
|
30
|
-
w.addEventListener?.("beforeunload", () => clearTimeout(timer));
|
|
19
|
+
const GEEN_PRINTER = "Geen printer gekoppeld — stel dit in bij Layouts & printers > Routering";
|
|
20
|
+
async function urlNaarBase64(url) {
|
|
21
|
+
const res = await fetch(url);
|
|
22
|
+
if (!res.ok)
|
|
23
|
+
throw new Error(`PDF ophalen mislukt (${res.status})`);
|
|
24
|
+
const buf = new Uint8Array(await res.arrayBuffer());
|
|
25
|
+
let binair = "";
|
|
26
|
+
const blok = 0x8000;
|
|
27
|
+
for (let i = 0; i < buf.length; i += blok) {
|
|
28
|
+
binair += String.fromCharCode(...buf.subarray(i, i + blok));
|
|
29
|
+
}
|
|
30
|
+
return btoa(binair);
|
|
31
31
|
}
|
|
32
|
-
export function OrderAfleverbrievenCard({ salesOrderId }) {
|
|
32
|
+
export function OrderAfleverbrievenCard({ salesOrderId, orderNumber, werkplek, }) {
|
|
33
33
|
const fetchLabels = useServerFn(listLogisticLabelsForOrder);
|
|
34
34
|
const { data, isLoading, error, refetch, isFetching } = useQuery({
|
|
35
35
|
queryKey: ["floriday-logistic-labels", salesOrderId],
|
|
36
36
|
queryFn: () => fetchLabels({ data: { salesOrderId } }),
|
|
37
37
|
staleTime: 60000,
|
|
38
38
|
});
|
|
39
|
+
const [bezig, setBezig] = useState(null);
|
|
40
|
+
const [jobStatus, setJobStatus] = useState({});
|
|
41
|
+
const stoppers = useRef([]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const huidige = stoppers.current;
|
|
44
|
+
return () => {
|
|
45
|
+
huidige.forEach((stop) => {
|
|
46
|
+
try {
|
|
47
|
+
stop();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* ignore */
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
huidige.length = 0;
|
|
54
|
+
};
|
|
55
|
+
}, []);
|
|
39
56
|
const labels = data?.labels ?? [];
|
|
40
|
-
|
|
57
|
+
async function printLabel(l) {
|
|
58
|
+
if (!l.signedUrl)
|
|
59
|
+
return;
|
|
60
|
+
const sleutel = `${l.fulfillmentOrderId}-${l.code}`;
|
|
61
|
+
setBezig(sleutel);
|
|
62
|
+
try {
|
|
63
|
+
// Printer alleen zelf bepalen wanneer de shell een expliciete werkplek kent.
|
|
64
|
+
let printerId = null;
|
|
65
|
+
if (werkplek) {
|
|
66
|
+
printerId = await printerVoorWerkplek(werkplek, "A4");
|
|
67
|
+
if (!printerId)
|
|
68
|
+
printerId = await printerVoorDocumenttype("afleverbrief", "A4", werkplek);
|
|
69
|
+
if (!printerId)
|
|
70
|
+
throw new Error(GEEN_PRINTER);
|
|
71
|
+
}
|
|
72
|
+
const pdfBase64 = await urlNaarBase64(l.signedUrl);
|
|
73
|
+
const documentnaam = `Afleverbrief ${orderNumber ?? l.code}${l.letter ? `-${l.letter}` : ""}`;
|
|
74
|
+
const { jobId } = await printPdf({
|
|
75
|
+
documenttype: "afleverbrief",
|
|
76
|
+
documentnaam,
|
|
77
|
+
pdfBase64,
|
|
78
|
+
herkomst: "floriday",
|
|
79
|
+
...(werkplek ? { werkplek } : {}),
|
|
80
|
+
...(printerId ? { printerId } : {}),
|
|
81
|
+
payload: { order_id: salesOrderId, ordernummer: orderNumber ?? l.code },
|
|
82
|
+
isHerprint: true,
|
|
83
|
+
});
|
|
84
|
+
setJobStatus((s) => ({ ...s, [sleutel]: "wachtend" }));
|
|
85
|
+
const stop = volgJobStatus(jobId, (st) => {
|
|
86
|
+
setJobStatus((s) => ({
|
|
87
|
+
...s,
|
|
88
|
+
[sleutel]: st.foutmelding ? `mislukt: ${st.foutmelding}` : st.status,
|
|
89
|
+
}));
|
|
90
|
+
});
|
|
91
|
+
stoppers.current.push(stop);
|
|
92
|
+
toast.success(`${documentnaam} naar de printer gestuurd`);
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
const msg = e.message || "Printen mislukt";
|
|
96
|
+
toast.error(/printer/i.test(msg) ? GEEN_PRINTER : msg);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
setBezig(null);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function printAlles() {
|
|
103
|
+
for (const l of labels) {
|
|
104
|
+
if (!l.hasPdf || !l.signedUrl)
|
|
105
|
+
continue;
|
|
106
|
+
await printLabel(l);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsx(CardTitle, { className: "text-base", children: "Afleverbrieven" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [labels.length, " brief(en)"] }), labels.some((l) => l.hasPdf && l.signedUrl) && (_jsxs(Button, { variant: "outline", size: "sm", onClick: printAlles, disabled: bezig !== null, children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), "Alles printen"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => refetch(), disabled: isFetching, title: "Opnieuw ophalen bij Floriday", children: _jsx(RefreshCw, { className: `h-4 w-4 ${isFetching ? "animate-spin" : ""}` }) })] })] }), _jsxs(CardContent, { children: [isLoading && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Afleverbrieven ophalen\u2026" })), error && (_jsx("p", { className: "text-sm text-destructive", children: error.message })), !isLoading && !error && labels.length === 0 && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen afleverbrief beschikbaar (order nog niet vrijgegeven door Floriday)." })), labels.length > 0 && (_jsx("div", { className: "divide-y divide-border rounded-md border border-border", children: labels.map((l) => {
|
|
41
110
|
const lcShort = l.loadCarrierType ? LC_SHORT[l.loadCarrierType] ?? l.loadCarrierType.slice(0, 2) : "";
|
|
42
|
-
|
|
111
|
+
const sleutel = `${l.fulfillmentOrderId}-${l.code}`;
|
|
112
|
+
const status = jobStatus[sleutel];
|
|
113
|
+
return (_jsxs("div", { className: "flex items-center justify-between gap-4 px-3 py-2 text-sm", children: [_jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [_jsx(FileText, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "font-mono font-medium", children: [l.code, l.letter ? _jsxs("span", { className: "ml-1 text-primary", children: ["\u00B7", l.letter] }) : null] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Kar ", l.loadCarrierIndex, lcShort ? ` · ${lcShort}` : "", l.packages ? ` · ${l.packages} fusten` : "", status ? ` · print: ${status}` : ""] })] })] }), _jsx("div", { className: "flex items-center gap-2", children: l.hasPdf && l.signedUrl ? (_jsxs(_Fragment, { children: [_jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsxs("a", { href: l.signedUrl, target: "_blank", rel: "noreferrer", children: [_jsx(ExternalLink, { className: "mr-1 h-3.5 w-3.5" }), "Openen"] }) }), _jsxs(Button, { variant: "default", size: "sm", onClick: () => printLabel(l), disabled: bezig !== null, children: [bezig === sleutel ? (_jsx(Loader2, { className: "mr-1 h-3.5 w-3.5 animate-spin" })) : (_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" })), "Printen"] })] })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: "PDF nog niet vrijgegeven" })) })] }, `${l.fulfillmentOrderId}-${l.code}-${l.letter ?? ""}`));
|
|
43
114
|
}) }))] })] }));
|
|
44
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SalesOrderDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAiKnE,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,cAAc,EACd,eAAuB,GACxB,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,
|
|
1
|
+
{"version":3,"file":"SalesOrderDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/SalesOrderDetailView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAiKnE,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,cAAc,EACd,eAAuB,GACxB,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,2CAoVA"}
|
|
@@ -252,5 +252,5 @@ export function SalesOrderDetailView({ order, sellerFallback, hideKarindeling =
|
|
|
252
252
|
.join(" "),
|
|
253
253
|
resolvedAddresses.pickup.country,
|
|
254
254
|
].filter((v) => !!v && v.trim().length > 0)
|
|
255
|
-
: [], extra: resolvedAddresses?.pickup?.gln ?? null }) }), _jsx(Row, { label: "Vervoerder", children: _jsx(OrderCarrierPicker, { orderId: String(order.id), locked: !!order.isReservation }) }), _jsx(Row, { label: "Ophaalmoment", children: _jsx(OrderPickupMomentPicker, { orderId: String(order.id) }) })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Klant" }), _jsx(Row, { label: "Naam", children: _jsx("span", { className: "font-medium", children: customerName }) }), _jsx(Row, { label: "GLN", children: customerGln }), _jsx(Row, { label: "Administratienummer", children: customerAdmin }), _jsx(Row, { label: "Telefoonnummer", children: customerPhone })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Prijs per stuk" }), _jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Product" }), _jsxs("span", { children: [oldProductPrice !== null && (_jsx("span", { className: "mr-2 text-destructive line-through", children: eurFlex.format(oldProductPrice) })), eurFlex.format(productUnit)] })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Transportkosten" }), _jsx("span", { children: eurFlex.format(transportPerPiece) })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Inkoopprijs" }), _jsx("span", { children: eurFlex.format(purchaseUnit) })] }), _jsxs("div", { className: "mt-2 flex justify-between border-t border-border pt-2 font-semibold", children: [_jsx("span", { children: "Totaal" }), _jsxs("span", { children: [_jsxs("span", { className: "mr-2 text-xs font-normal text-muted-foreground", children: ["(", packages, " \u00D7 ", piecesPerPackage, " \u00D7 ", eurFlex.format(productUnit), ")"] }), eurFlex.format(totalAmount)] })] })] })] }), _jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Status" }), _jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Bestelling" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), bestellingLabel] })] }), hasCorrection && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Correctie" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), "Correctie is verwerkt"] })] }))] })] })] })] }), _jsx(OrderShipmentsCard, { order: order }), !hideKarindeling && _jsx(OrderKarindelingCard, { order: order }), o?.salesOrderId ? (_jsxs(_Fragment, { children: [_jsx(OrderControlStatusCard, { floridayId: String(o.salesOrderId), isControlled: order.status.isControlled, controlledAt: order.status.controlledAt }), _jsx(AutoFulfillmentStatusCard, { salesOrderId: String(o.salesOrderId) }), _jsx(OrderAfleverbrievenCard, { salesOrderId: String(o.salesOrderId) })] })) : null] }));
|
|
255
|
+
: [], extra: resolvedAddresses?.pickup?.gln ?? null }) }), _jsx(Row, { label: "Vervoerder", children: _jsx(OrderCarrierPicker, { orderId: String(order.id), locked: !!order.isReservation }) }), _jsx(Row, { label: "Ophaalmoment", children: _jsx(OrderPickupMomentPicker, { orderId: String(order.id) }) })] }), _jsxs("div", { children: [_jsx(SectionTitle, { children: "Klant" }), _jsx(Row, { label: "Naam", children: _jsx("span", { className: "font-medium", children: customerName }) }), _jsx(Row, { label: "GLN", children: customerGln }), _jsx(Row, { label: "Administratienummer", children: customerAdmin }), _jsx(Row, { label: "Telefoonnummer", children: customerPhone })] })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Prijs per stuk" }), _jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Product" }), _jsxs("span", { children: [oldProductPrice !== null && (_jsx("span", { className: "mr-2 text-destructive line-through", children: eurFlex.format(oldProductPrice) })), eurFlex.format(productUnit)] })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Transportkosten" }), _jsx("span", { children: eurFlex.format(transportPerPiece) })] }), _jsxs("div", { className: "flex justify-between", children: [_jsx("span", { className: "text-muted-foreground", children: "Inkoopprijs" }), _jsx("span", { children: eurFlex.format(purchaseUnit) })] }), _jsxs("div", { className: "mt-2 flex justify-between border-t border-border pt-2 font-semibold", children: [_jsx("span", { children: "Totaal" }), _jsxs("span", { children: [_jsxs("span", { className: "mr-2 text-xs font-normal text-muted-foreground", children: ["(", packages, " \u00D7 ", piecesPerPackage, " \u00D7 ", eurFlex.format(productUnit), ")"] }), eurFlex.format(totalAmount)] })] })] })] }), _jsxs("div", { className: "rounded-md border border-border p-4", children: [_jsx("div", { className: "mb-3 text-sm font-semibold", children: "Status" }), _jsxs("div", { className: "space-y-3 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Bestelling" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), bestellingLabel] })] }), hasCorrection && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-muted-foreground", children: "Correctie" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), "Correctie is verwerkt"] })] }))] })] })] })] }), _jsx(OrderShipmentsCard, { order: order }), !hideKarindeling && _jsx(OrderKarindelingCard, { order: order }), o?.salesOrderId ? (_jsxs(_Fragment, { children: [_jsx(OrderControlStatusCard, { floridayId: String(o.salesOrderId), isControlled: order.status.isControlled, controlledAt: order.status.controlledAt }), _jsx(AutoFulfillmentStatusCard, { salesOrderId: String(o.salesOrderId) }), _jsx(OrderAfleverbrievenCard, { salesOrderId: String(o.salesOrderId), orderNumber: order.orderNumber ?? undefined })] })) : null] }));
|
|
256
256
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toont voorraadafboekingen die zijn overgeslagen (product niet gekoppeld) of
|
|
3
|
+
* geblokkeerd (statusovergang zonder bewijs van vertrek).
|
|
4
|
+
*/
|
|
5
|
+
export declare function StockConsumptionAlertsBanner(): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
//# sourceMappingURL=StockConsumptionAlertsBanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StockConsumptionAlertsBanner.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/StockConsumptionAlertsBanner.tsx"],"names":[],"mappings":"AAQA;;;GAGG;AACH,wBAAgB,4BAA4B,mDA6C3C"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
4
|
+
import { AlertTriangle, X } from "lucide-react";
|
|
5
|
+
import { listOpenStockConsumptionAlerts, resolveStockConsumptionAlert, } from "../../lib/stock-consumption-alerts.functions";
|
|
6
|
+
/**
|
|
7
|
+
* Toont voorraadafboekingen die zijn overgeslagen (product niet gekoppeld) of
|
|
8
|
+
* geblokkeerd (statusovergang zonder bewijs van vertrek).
|
|
9
|
+
*/
|
|
10
|
+
export function StockConsumptionAlertsBanner() {
|
|
11
|
+
const fetchAlerts = useServerFn(listOpenStockConsumptionAlerts);
|
|
12
|
+
const resolveAlert = useServerFn(resolveStockConsumptionAlert);
|
|
13
|
+
const qc = useQueryClient();
|
|
14
|
+
const { data } = useQuery({
|
|
15
|
+
queryKey: ["stock-consumption-alerts"],
|
|
16
|
+
queryFn: () => fetchAlerts(),
|
|
17
|
+
refetchInterval: 60000,
|
|
18
|
+
});
|
|
19
|
+
const alerts = data ?? [];
|
|
20
|
+
if (!alerts.length)
|
|
21
|
+
return null;
|
|
22
|
+
return (_jsxs("div", { className: "space-y-2 rounded-lg border border-amber-500/40 bg-amber-500/5 p-3 text-sm", children: [_jsxs("div", { className: "flex items-center gap-2 font-medium text-amber-700 dark:text-amber-400", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), "Voorraad niet afgeboekt (", alerts.length, ")"] }), _jsx("ul", { className: "space-y-1", children: alerts.slice(0, 8).map((a) => (_jsxs("li", { className: "flex items-start justify-between gap-3 text-muted-foreground", children: [_jsxs("span", { children: [_jsx("span", { className: "font-medium text-foreground", children: a.order_number ?? a.order_id ?? "onbekende order" }), " — ", a.alert_type === "consumption_blocked" ? "geblokkeerd" : "overgeslagen", " (", a.qty, " stuks):", " ", a.reason ?? "geen reden vastgelegd"] }), _jsx("button", { type: "button", className: "shrink-0 rounded p-1 hover:bg-muted", title: "Afhandelen", onClick: async () => {
|
|
23
|
+
await resolveAlert({ data: { id: a.id } });
|
|
24
|
+
await qc.invalidateQueries({ queryKey: ["stock-consumption-alerts"] });
|
|
25
|
+
}, children: _jsx(X, { className: "h-3.5 w-3.5" }) })] }, a.id))) })] }));
|
|
26
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerkoopOrdersPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/VerkoopOrdersPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VerkoopOrdersPage.d.ts","sourceRoot":"","sources":["../../../src/components/verkoop/VerkoopOrdersPage.tsx"],"names":[],"mappings":"AA+DA,wBAAgB,iBAAiB,4CAgnBhC"}
|
|
@@ -17,6 +17,7 @@ import { SalesOrdersFilters } from "./SalesOrdersFilters";
|
|
|
17
17
|
import { SalesOrdersFilterPanel, countActiveFilters, } from "./SalesOrdersFilterPanel";
|
|
18
18
|
import { SalesOrdersTable, salesOrderRowId } from "./SalesOrdersTable";
|
|
19
19
|
import { EditLocalOrderDialog } from "./EditLocalOrderDialog";
|
|
20
|
+
import { StockConsumptionAlertsBanner } from "./StockConsumptionAlertsBanner";
|
|
20
21
|
import { ORDER_STAGES } from "../../lib/order-status";
|
|
21
22
|
const STATUS_TABS = [
|
|
22
23
|
{ id: "all", label: "Alle" },
|
|
@@ -270,7 +271,7 @@ export function VerkoopOrdersPage() {
|
|
|
270
271
|
(active
|
|
271
272
|
? "bg-primary text-primary-foreground"
|
|
272
273
|
: "bg-muted text-muted-foreground"), children: count })] }, t.id));
|
|
273
|
-
}) }) }), _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx(SalesOrdersFilters, { value: filters, onChange: setFilters }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setFilterPanelOpen(true), "aria-label": "Filters", children: [_jsx(Filter, { className: "mr-2 h-4 w-4" }), "Filters", activeFilterCount > 0 && (_jsx("span", { className: "ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground", children: activeFilterCount }))] }), _jsx(Button, { variant: "outline", size: "icon", onClick: handleSync, disabled: syncing, "aria-label": "Synchroniseren", title: "Synchroniseren", children: _jsx(RefreshCw, { className: "h-4 w-4 " + (syncing ? "animate-spin" : "") }) }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleExport, children: [_jsx(Download, { className: "mr-2 h-4 w-4" }), " Exporteren"] }), _jsxs(Button, { size: "sm", onClick: () => navigate({ to: "/floriday-verkoop/verkooporders/nieuw" }), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Bestelling aanmaken"] })] })] }), _jsx(AnalyticsCards, { totals: totals, loading: isLoading }), error && (_jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-5 w-5 shrink-0 text-destructive" }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "font-medium text-destructive", children: "Floriday gegevens konden niet geladen worden" }), _jsx("div", { className: "mt-1 text-muted-foreground", children: error.message })] }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => refetch(), disabled: isFetching, children: "Opnieuw proberen" })] })), (warnings.length > 0 || truncated) && (_jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), _jsxs("div", { className: "space-y-1 text-muted-foreground", children: [warnings.map((w) => (_jsx("div", { children: w }, w))), truncated && (_jsx("div", { children: "Niet alle orders konden worden meegenomen. Kies een kortere periode voor een volledig overzicht." }))] })] })), selectedRows.length > 0 && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-lg border border-primary/30 bg-primary/5 p-3", children: [_jsxs("div", { className: "text-sm text-foreground", children: [_jsx("span", { className: "font-medium", children: selectedRows.length }), " geselecteerd", selectedPlan.total !== selectedRows.length && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.total, " onderliggende bestelling(en)"] })), selectedPlan.skipped > 0 && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.skipped, " Floriday-order(s) worden overgeslagen"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setSelectedRowIds([]), children: "Selectie wissen" }), _jsx(Button, { size: "sm", className: "bg-destructive text-destructive-foreground hover:bg-destructive/90", disabled: selectedPlan.deletable.length === 0, onClick: () => {
|
|
274
|
+
}) }) }), _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx(SalesOrdersFilters, { value: filters, onChange: setFilters }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setFilterPanelOpen(true), "aria-label": "Filters", children: [_jsx(Filter, { className: "mr-2 h-4 w-4" }), "Filters", activeFilterCount > 0 && (_jsx("span", { className: "ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground", children: activeFilterCount }))] }), _jsx(Button, { variant: "outline", size: "icon", onClick: handleSync, disabled: syncing, "aria-label": "Synchroniseren", title: "Synchroniseren", children: _jsx(RefreshCw, { className: "h-4 w-4 " + (syncing ? "animate-spin" : "") }) }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleExport, children: [_jsx(Download, { className: "mr-2 h-4 w-4" }), " Exporteren"] }), _jsxs(Button, { size: "sm", onClick: () => navigate({ to: "/floriday-verkoop/verkooporders/nieuw" }), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Bestelling aanmaken"] })] })] }), _jsx(AnalyticsCards, { totals: totals, loading: isLoading }), _jsx(StockConsumptionAlertsBanner, {}), error && (_jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-5 w-5 shrink-0 text-destructive" }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "font-medium text-destructive", children: "Floriday gegevens konden niet geladen worden" }), _jsx("div", { className: "mt-1 text-muted-foreground", children: error.message })] }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => refetch(), disabled: isFetching, children: "Opnieuw proberen" })] })), (warnings.length > 0 || truncated) && (_jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), _jsxs("div", { className: "space-y-1 text-muted-foreground", children: [warnings.map((w) => (_jsx("div", { children: w }, w))), truncated && (_jsx("div", { children: "Niet alle orders konden worden meegenomen. Kies een kortere periode voor een volledig overzicht." }))] })] })), selectedRows.length > 0 && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-lg border border-primary/30 bg-primary/5 p-3", children: [_jsxs("div", { className: "text-sm text-foreground", children: [_jsx("span", { className: "font-medium", children: selectedRows.length }), " geselecteerd", selectedPlan.total !== selectedRows.length && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.total, " onderliggende bestelling(en)"] })), selectedPlan.skipped > 0 && (_jsxs("span", { className: "text-muted-foreground", children: [" ", "\u00B7 ", selectedPlan.skipped, " Floriday-order(s) worden overgeslagen"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setSelectedRowIds([]), children: "Selectie wissen" }), _jsx(Button, { size: "sm", className: "bg-destructive text-destructive-foreground hover:bg-destructive/90", disabled: selectedPlan.deletable.length === 0, onClick: () => {
|
|
274
275
|
setCancelReason("");
|
|
275
276
|
setPendingAction({
|
|
276
277
|
rows: selectedRows,
|