@flowselections/floriday-voorraad 1.0.122 → 1.0.127
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/voorraad/ArtikelWizard.d.ts +14 -1
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ArtikelWizard.js +88 -26
- package/dist-lib/components/voorraad/FloridayInfoCard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/FloridayInfoCard.js +4 -2
- package/dist-lib/components/voorraad/FloridayLoadCarriers.d.ts.map +1 -1
- package/dist-lib/components/voorraad/FloridayLoadCarriers.js +3 -2
- package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/NieuwArtikelPage.js +72 -6
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts +7 -0
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/PublishProgressCard.js +22 -1
- package/dist-lib/components/voorraad/StockSyncStatus.d.ts.map +1 -1
- package/dist-lib/components/voorraad/StockSyncStatus.js +1 -1
- package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadTable.js +1 -1
- package/dist-lib/hooks/useLoadCarriers.d.ts +12 -0
- package/dist-lib/hooks/useLoadCarriers.d.ts.map +1 -0
- package/dist-lib/hooks/useLoadCarriers.js +49 -0
- package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
- package/dist-lib/hooks/useLocalTradeItems.js +3 -1
- package/dist-lib/hooks/usePublishJob.d.ts +1 -0
- package/dist-lib/hooks/usePublishJob.d.ts.map +1 -1
- package/dist-lib/hooks/usePublishJob.js +20 -1
- package/dist-lib/hooks/useStockSyncHealth.d.ts +8 -1
- package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -1
- package/dist-lib/hooks/useStockSyncHealth.js +91 -19
- package/dist-lib/integrations/supabase/types.d.ts +400 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/__tests__/erp-test-123.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/erp-test-123.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/erp-test-123.test.js +43 -0
- package/dist-lib/lib/__tests__/load-carriers.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/load-carriers.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/load-carriers.test.js +15 -0
- package/dist-lib/lib/buyer-organizations.d.ts +26 -0
- package/dist-lib/lib/buyer-organizations.d.ts.map +1 -0
- package/dist-lib/lib/buyer-organizations.js +41 -0
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts +4 -0
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-customer-offer.functions.js +54 -16
- package/dist-lib/lib/floriday-info.d.ts +0 -1
- package/dist-lib/lib/floriday-info.d.ts.map +1 -1
- package/dist-lib/lib/floriday-info.js +0 -8
- package/dist-lib/lib/simple-packing.d.ts +31 -0
- package/dist-lib/lib/simple-packing.d.ts.map +1 -0
- package/dist-lib/lib/simple-packing.js +62 -0
- package/dist-lib/lib/voorraad-page-head.d.ts +19 -0
- package/dist-lib/lib/voorraad-page-head.d.ts.map +1 -0
- package/dist-lib/lib/voorraad-page-head.js +11 -0
- package/package.json +1 -1
- package/sql/AGENTS.md +2 -1
- package/sql/floriday-voorraad-schema.sql +465 -52
|
@@ -44,5 +44,5 @@ export function StockSyncStatus() {
|
|
|
44
44
|
if (stalePending > 0) {
|
|
45
45
|
parts.push(`${stalePending} wacht${stalePending === 1 ? "" : "en"} langer dan 10 minuten`);
|
|
46
46
|
}
|
|
47
|
-
return (_jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-sm text-amber-800", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("div", { className: "flex-1 space-y-0.5", children: [parts.length > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Voorraadsync naar Floriday: " }), parts.join(" · "), " (laatste 24 uur), voor ", articleCount, " artikel", articleCount === 1 ? "" : "en", ".", oldestPendingAt && (_jsxs("span", { className: "opacity-80", children: [" ", "Oudste wachtende regel: ", new Date(oldestPendingAt).toLocaleString("nl-NL"), "."] }))] })), cause && (_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Oorzaak: " }), cause] })), blockedCount > 0 && (_jsxs("div", { className: "space-y-0.5", children: [_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Wacht op Floriday \u2013 verpakkingsverschil: " }), blockedCount, "
|
|
47
|
+
return (_jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-sm text-amber-800", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("div", { className: "flex-1 space-y-0.5", children: [parts.length > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Voorraadsync naar Floriday: " }), parts.join(" · "), " (laatste 24 uur), voor ", articleCount, " artikel", articleCount === 1 ? "" : "en", ".", oldestPendingAt && (_jsxs("span", { className: "opacity-80", children: [" ", "Oudste wachtende regel: ", new Date(oldestPendingAt).toLocaleString("nl-NL"), "."] }))] })), cause && (_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Oorzaak: " }), cause] })), blockedCount > 0 && (_jsxs("div", { className: "space-y-0.5", children: [_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Wacht op Floriday \u2013 verpakkingsverschil: " }), blockedCount, " artikel", blockedCount === 1 ? "" : "en", " tegengehouden."] }), _jsxs("ul", { className: "list-disc pl-5 text-xs", children: [blocked.map((b) => (_jsx("li", { children: _jsx(Link, { to: "/voorraad/$id", params: { id: b.productId }, className: "underline hover:no-underline", children: gateBlockedText({ name: b.name, code: b.code }) }) }, b.productId))), data.blockedWithoutProduct > 0 && (_jsxs("li", { children: [data.blockedWithoutProduct, " Floriday-artikel", data.blockedWithoutProduct === 1 ? "" : "en", " zonder lokaal artikel"] }))] }), data.blockedOther.length > 0 && (_jsxs("div", { className: "mt-1", children: [_jsx("span", { className: "font-medium", children: "Ook tegengehouden (geen artikel): " }), data.blockedOther.map((o) => `${o.kind}: ${o.ref ?? "onbekend"}`).join(" · ")] }))] })), topReason && (_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Meest voorkomende reden: " }), topReason, "."] })), noPriceCount > 0 && (_jsxs("div", { className: "opacity-90", children: [noPriceCount, " van deze artikelen ", noPriceCount === 1 ? "heeft" : "hebben", " nog geen prijs in het weekaanbod; het aantal wordt dan zonder prijs doorgezet."] }))] }), failed > 0 && (_jsxs("button", { type: "button", className: "inline-flex shrink-0 items-center rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-1 text-xs font-medium text-amber-900 hover:bg-amber-500/20 disabled:opacity-50", disabled: mutation.isPending, onClick: () => mutation.mutate(), children: [_jsx(RotateCw, { className: `mr-1 h-3.5 w-3.5 ${mutation.isPending ? "animate-spin" : ""}` }), "Opnieuw proberen"] }))] }));
|
|
48
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAgFzE,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAE3D;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,EACP,aAAa,EACb,QAAQ,EACR,cAAc,EACd,WAAW,EACX,cAAc,GACf,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,+
|
|
1
|
+
{"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAgFzE,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAE3D;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,EACP,aAAa,EACb,QAAQ,EACR,cAAc,EACd,WAAW,EACX,cAAc,GACf,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,+BAoUA"}
|
|
@@ -155,7 +155,7 @@ export function VoorraadTable({ items, loading, settingsByKey, selected, onToggl
|
|
|
155
155
|
open();
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
: undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [onToggleSelect && (_jsx("td", { className: "p-3", onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: settingProductId ? selected?.has(settingProductId) : false, disabled: !settingProductId, onCheckedChange: () => settingProductId && onToggleSelect(settingProductId), "aria-label": `Selecteer ${item.name}` }) })), _jsx("td", { className: "p-2", children: thumbUrl ? (_jsx("img", { src: thumbUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [_jsxs("div", { className: "flex flex-col items-start gap-1", children: [_jsx("span", { className: "font-medium text-foreground", children: item.name }), item.productId && incompletePacking.has(item.productId) && (
|
|
158
|
+
: undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [onToggleSelect && (_jsx("td", { className: "p-3", onClick: (e) => e.stopPropagation(), children: _jsx(Checkbox, { checked: settingProductId ? selected?.has(settingProductId) : false, disabled: !settingProductId, onCheckedChange: () => settingProductId && onToggleSelect(settingProductId), "aria-label": `Selecteer ${item.name}` }) })), _jsx("td", { className: "p-2", children: thumbUrl ? (_jsx("img", { src: thumbUrl, alt: item.name, className: "h-10 w-10 rounded object-cover", loading: "lazy" })) : (_jsx("div", { className: "h-10 w-10 rounded bg-muted flex items-center justify-center", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) })) }), _jsxs("td", { className: "p-3", children: [_jsxs("div", { className: "flex flex-col items-start gap-1", children: [_jsx("span", { className: "font-medium text-foreground", children: item.name }), item.productId && incompletePacking.has(item.productId) && (_jsxs("span", { className: "text-[11px] font-medium text-destructive", children: [PACKING_INCOMPLETE_TEXT, item.linkError && _jsx("span", { className: "block", children: item.linkError })] })), _jsxs("div", { role: "status", "aria-label": floriday
|
|
159
159
|
? "Online in Floriday"
|
|
160
160
|
: "Niet online in Floriday", title: floriday
|
|
161
161
|
? "Online in Floriday"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface LoadCarrierType {
|
|
2
|
+
code: string;
|
|
3
|
+
naam: string;
|
|
4
|
+
volgorde: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function loadCarriersFromRows(rows: unknown): LoadCarrierType[];
|
|
7
|
+
export declare function useLoadCarriers(): {
|
|
8
|
+
items: LoadCarrierType[];
|
|
9
|
+
error: string | null;
|
|
10
|
+
label: (code: string | null | undefined) => string;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=useLoadCarriers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLoadCarriers.d.ts","sourceRoot":"","sources":["../../src/hooks/useLoadCarriers.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,EAAE,CAKrE;AAQD,wBAAgB,eAAe;;;kBAqBR,MAAM,GAAG,IAAI,GAAG,SAAS;EAE/C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gedeelde lijst ladingdragers uit de database (`voorraad_load_carriers()`).
|
|
3
|
+
* Codes zijn Floriday-codes (DANISH_TROLLEY enz.), zoals bewaard in
|
|
4
|
+
* `product_packings.load_carrier`. Productontwerp leest dezelfde functie.
|
|
5
|
+
* Geen vaste kopie in de code en geen terugvallijst: lukt lezen niet, dan `error`.
|
|
6
|
+
*/
|
|
7
|
+
import { useEffect, useMemo, useState } from "react";
|
|
8
|
+
import { supabase } from "../integrations/supabase/client.js";
|
|
9
|
+
let cache = null;
|
|
10
|
+
let pending = null;
|
|
11
|
+
export function loadCarriersFromRows(rows) {
|
|
12
|
+
return (rows ?? [])
|
|
13
|
+
.filter((r) => r && typeof r.code === "string" && r.code)
|
|
14
|
+
.map((r) => ({ code: String(r.code), naam: String(r.naam ?? r.code), volgorde: Number(r.volgorde ?? 0) }))
|
|
15
|
+
.sort((a, b) => a.volgorde - b.volgorde);
|
|
16
|
+
}
|
|
17
|
+
async function fetchLoadCarriers() {
|
|
18
|
+
const { data, error } = await supabase.rpc("voorraad_load_carriers");
|
|
19
|
+
if (error)
|
|
20
|
+
throw new Error(`Ladingdragers konden niet worden gelezen: ${error.message}`);
|
|
21
|
+
return loadCarriersFromRows(data);
|
|
22
|
+
}
|
|
23
|
+
export function useLoadCarriers() {
|
|
24
|
+
const [items, setItems] = useState(cache ?? []);
|
|
25
|
+
const [error, setError] = useState(null);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (cache)
|
|
28
|
+
return;
|
|
29
|
+
let alive = true;
|
|
30
|
+
pending ?? (pending = fetchLoadCarriers());
|
|
31
|
+
pending
|
|
32
|
+
.then((list) => {
|
|
33
|
+
cache = list;
|
|
34
|
+
if (alive)
|
|
35
|
+
setItems(list);
|
|
36
|
+
})
|
|
37
|
+
.catch((e) => {
|
|
38
|
+
pending = null;
|
|
39
|
+
if (alive)
|
|
40
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
41
|
+
});
|
|
42
|
+
return () => {
|
|
43
|
+
alive = false;
|
|
44
|
+
};
|
|
45
|
+
}, []);
|
|
46
|
+
const labels = useMemo(() => new Map(items.map((i) => [i.code, i.naam])), [items]);
|
|
47
|
+
const label = (code) => (code ? labels.get(code) ?? code : "—");
|
|
48
|
+
return { items, error, label };
|
|
49
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLocalTradeItems.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalTradeItems.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAwB,KAAK,kBAAkB,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGvG;;;;;GAKG;AAEH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uBAAuB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"useLocalTradeItems.d.ts","sourceRoot":"","sources":["../../src/hooks/useLocalTradeItems.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAwB,KAAK,kBAAkB,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGvG;;;;;GAKG;AAEH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uBAAuB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AA0ED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;;;;EA0B9D;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CA4BrF;AAED,MAAM,WAAW,SAAS;IACxB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAC;CACpC;AAED,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAWjF;AAqBD,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqGlB;AAED,wEAAwE;AACxE,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAGD;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhF;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
|
|
@@ -41,7 +41,9 @@ function productToTradeItem(row) {
|
|
|
41
41
|
published: Boolean(floridayId),
|
|
42
42
|
linkStatus: floridayId ? "published" : "linked",
|
|
43
43
|
missingFields: [],
|
|
44
|
-
linkError:
|
|
44
|
+
linkError: cf.voorraad_packing_link?.ok === false
|
|
45
|
+
? String(cf.voorraad_packing_link.melding ?? "Hoofdverpakking niet overgenomen")
|
|
46
|
+
: null,
|
|
45
47
|
lastSyncAt: null,
|
|
46
48
|
floridayId,
|
|
47
49
|
packingConfigurations,
|
|
@@ -4,6 +4,7 @@ export declare function usePublishJob(jobId: string | null): {
|
|
|
4
4
|
steps: PublishStepRow[];
|
|
5
5
|
loading: boolean;
|
|
6
6
|
reload: () => Promise<void>;
|
|
7
|
+
reloadFor: (id: string) => Promise<void>;
|
|
7
8
|
};
|
|
8
9
|
export declare function usePublishJobs(limit?: number): {
|
|
9
10
|
jobs: PublishJobRow[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePublishJob.d.ts","sourceRoot":"","sources":["../../src/hooks/usePublishJob.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAEjC,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;;;;;
|
|
1
|
+
{"version":3,"file":"usePublishJob.d.ts","sourceRoot":"","sources":["../../src/hooks/usePublishJob.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAEjC,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;;;;;oBAuBP,MAAM;EAiDhD;AAED,wBAAgB,cAAc,CAAC,KAAK,SAAK;;;;EAoBxC"}
|
|
@@ -23,6 +23,25 @@ export function usePublishJob(jobId) {
|
|
|
23
23
|
useEffect(() => {
|
|
24
24
|
void reload();
|
|
25
25
|
}, [reload]);
|
|
26
|
+
/** Laadt een opgegeven opdracht direct (na afronden in dezelfde klik). */
|
|
27
|
+
const reloadFor = useCallback(async (id) => {
|
|
28
|
+
const res = await loadPublishJob(id);
|
|
29
|
+
setJob(res.job);
|
|
30
|
+
setSteps(res.steps);
|
|
31
|
+
}, []);
|
|
32
|
+
// Vangnet als een seintje uitblijft: zolang de opdracht loopt en het
|
|
33
|
+
// tabblad zichtbaar is, elke 15 seconden de stand ophalen.
|
|
34
|
+
const running = job?.status === "running";
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!jobId || !running)
|
|
37
|
+
return;
|
|
38
|
+
const t = setInterval(() => {
|
|
39
|
+
if (typeof document !== "undefined" && document.visibilityState !== "visible")
|
|
40
|
+
return;
|
|
41
|
+
void reload();
|
|
42
|
+
}, 15000);
|
|
43
|
+
return () => clearInterval(t);
|
|
44
|
+
}, [jobId, running, reload]);
|
|
26
45
|
useEffect(() => {
|
|
27
46
|
if (!jobId)
|
|
28
47
|
return;
|
|
@@ -45,7 +64,7 @@ export function usePublishJob(jobId) {
|
|
|
45
64
|
void supabase.removeChannel(channel);
|
|
46
65
|
};
|
|
47
66
|
}, [jobId, reload]);
|
|
48
|
-
return { job, steps, loading, reload };
|
|
67
|
+
return { job, steps, loading, reload, reloadFor };
|
|
49
68
|
}
|
|
50
69
|
export function usePublishJobs(limit = 50) {
|
|
51
70
|
const [jobs, setJobs] = useState([]);
|
|
@@ -11,8 +11,15 @@ export interface StockSyncHealth {
|
|
|
11
11
|
noPriceCount: number;
|
|
12
12
|
/** Artikelen met regels die door het verpakkingsverschil zijn tegengehouden. */
|
|
13
13
|
blocked: BlockedArticle[];
|
|
14
|
-
/** Tegengehouden
|
|
14
|
+
/** Tegengehouden artikelen zonder bekend lokaal artikel. */
|
|
15
15
|
blockedWithoutProduct: number;
|
|
16
|
+
/** Bron van de telling: Floriday-auth (v2 of v1) of (oude bron) de wachtrij. */
|
|
17
|
+
blockedSource: "floriday-auth-v2" | "floriday-auth" | "wachtrij";
|
|
18
|
+
/** v2: tegengehouden bronnen die geen artikel zijn (bv. verkooporder), met source_ref. */
|
|
19
|
+
blockedOther: {
|
|
20
|
+
kind: string;
|
|
21
|
+
ref: string | null;
|
|
22
|
+
}[];
|
|
16
23
|
}
|
|
17
24
|
export interface BlockedArticle {
|
|
18
25
|
productId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStockSyncHealth.d.ts","sourceRoot":"","sources":["../../src/hooks/useStockSyncHealth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useStockSyncHealth.d.ts","sourceRoot":"","sources":["../../src/hooks/useStockSyncHealth.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,4DAA4D;IAC5D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gFAAgF;IAChF,aAAa,EAAE,kBAAkB,GAAG,eAAe,GAAG,UAAU,CAAC;IACjE,0FAA0F;IAC1F,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CACtD;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS3E;AAED,wBAAgB,kBAAkB,2EA2KjC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query";
|
|
2
2
|
import { supabase } from "../integrations/supabase/client.js";
|
|
3
|
+
import { isMissingFunctionError } from "../lib/buyer-organizations.js";
|
|
3
4
|
const STALE_MINUTES = 10;
|
|
4
5
|
const WINDOW_HOURS = 24;
|
|
5
6
|
export function reasonLabel(error) {
|
|
@@ -81,26 +82,95 @@ export function useStockSyncHealth() {
|
|
|
81
82
|
const withPrice = new Set((priced ?? []).map((p) => p.trade_item_id));
|
|
82
83
|
noPriceCount = ids.filter((id) => !withPrice.has(id)).length;
|
|
83
84
|
}
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
.select("product_id, trade_item_id")
|
|
88
|
-
.eq("status", "blocked_by_gate")
|
|
89
|
-
.limit(500);
|
|
90
|
-
const gateProductIds = Array.from(new Set((gateRows ?? []).map((r) => r.product_id).filter(Boolean)));
|
|
91
|
-
const gateNoProduct = (gateRows ?? []).filter((r) => !r.product_id).length;
|
|
85
|
+
// Tegengehouden artikelen: bron = Floriday-auth `floriday_packing_blocked_items`
|
|
86
|
+
// (zelfde als de Floriday-koppelingspagina). Bestaat die nog niet: oude bron
|
|
87
|
+
// (wachtrijregels met status blocked_by_gate). Altijd artikelen tellen.
|
|
92
88
|
let blocked = [];
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
89
|
+
let gateNoProduct = 0;
|
|
90
|
+
let blockedSource = "wachtrij";
|
|
91
|
+
const { data: ctx } = await supabase.rpc("get_stock_context", { p_ensure: false });
|
|
92
|
+
const ctxRow = Array.isArray(ctx) ? ctx[0] : ctx;
|
|
93
|
+
const connectionId = ctxRow?.connection_id ?? null;
|
|
94
|
+
let viaAuth = false;
|
|
95
|
+
const blockedOther = [];
|
|
96
|
+
if (connectionId) {
|
|
97
|
+
// v2 (source_kind/source_ref/source_paths) alleen als die bestaat; anders v1.
|
|
98
|
+
let { data: items, error: itemsErr } = await supabase.rpc("floriday_packing_blocked_items_v2", {
|
|
99
|
+
p_connection_id: connectionId,
|
|
100
|
+
});
|
|
101
|
+
let isV2 = !itemsErr;
|
|
102
|
+
if (itemsErr && isMissingFunctionError(itemsErr)) {
|
|
103
|
+
({ data: items, error: itemsErr } = await supabase.rpc("floriday_packing_blocked_items", {
|
|
104
|
+
p_connection_id: connectionId,
|
|
105
|
+
}));
|
|
106
|
+
isV2 = false;
|
|
107
|
+
}
|
|
108
|
+
if (!itemsErr) {
|
|
109
|
+
viaAuth = true;
|
|
110
|
+
blockedSource = isV2 ? "floriday-auth-v2" : "floriday-auth";
|
|
111
|
+
// Match uitsluitend op trade_item_id; alleen lezen. In v2 telt alleen source_kind='artikel'.
|
|
112
|
+
let all = (items ?? []);
|
|
113
|
+
if (isV2) {
|
|
114
|
+
const seenOther = new Set();
|
|
115
|
+
for (const r of all) {
|
|
116
|
+
if (r?.source_kind === "artikel")
|
|
117
|
+
continue;
|
|
118
|
+
const key = `${r?.source_kind}|${r?.source_ref}`;
|
|
119
|
+
if (seenOther.has(key))
|
|
120
|
+
continue;
|
|
121
|
+
seenOther.add(key);
|
|
122
|
+
blockedOther.push({ kind: String(r?.source_kind ?? "onbekend"), ref: r?.source_ref ?? null });
|
|
123
|
+
}
|
|
124
|
+
all = all.filter((r) => r?.source_kind === "artikel");
|
|
125
|
+
}
|
|
126
|
+
const rows = all.filter((r) => r?.trade_item_id);
|
|
127
|
+
const tradeIds = Array.from(new Set(rows.map((r) => String(r.trade_item_id))));
|
|
128
|
+
const prodByTrade = new Map();
|
|
129
|
+
if (tradeIds.length) {
|
|
130
|
+
const { data: prods } = await supabase
|
|
131
|
+
.from("products")
|
|
132
|
+
.select("id, floriday_trade_item_id")
|
|
133
|
+
.in("floriday_trade_item_id", tradeIds.slice(0, 500));
|
|
134
|
+
for (const p of (prods ?? []))
|
|
135
|
+
prodByTrade.set(String(p.floriday_trade_item_id), String(p.id));
|
|
136
|
+
}
|
|
137
|
+
const seen = new Set();
|
|
138
|
+
for (const r of rows) {
|
|
139
|
+
const tid = String(r.trade_item_id);
|
|
140
|
+
if (seen.has(tid))
|
|
141
|
+
continue;
|
|
142
|
+
seen.add(tid);
|
|
143
|
+
const pid = prodByTrade.get(tid);
|
|
144
|
+
if (pid)
|
|
145
|
+
blocked.push({ productId: pid, name: r.article_name ?? null, code: r.article_code ?? null });
|
|
146
|
+
else
|
|
147
|
+
gateNoProduct += 1;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (!isMissingFunctionError(itemsErr)) {
|
|
151
|
+
throw new Error(`Tegengehouden artikelen konden niet worden gelezen: ${itemsErr.message}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!viaAuth) {
|
|
155
|
+
const { data: gateRows } = await supabase
|
|
156
|
+
.from("floriday_continuous_stock_queue")
|
|
157
|
+
.select("product_id, trade_item_id")
|
|
158
|
+
.eq("status", "blocked_by_gate")
|
|
159
|
+
.limit(500);
|
|
160
|
+
const gateProductIds = Array.from(new Set((gateRows ?? []).map((r) => r.product_id).filter(Boolean)));
|
|
161
|
+
gateNoProduct = new Set((gateRows ?? []).filter((r) => !r.product_id).map((r) => r.trade_item_id)).size;
|
|
162
|
+
if (gateProductIds.length > 0) {
|
|
163
|
+
const { data: prods } = await supabase
|
|
164
|
+
.from("products")
|
|
165
|
+
.select("id, product, article_number")
|
|
166
|
+
.in("id", gateProductIds.slice(0, 200));
|
|
167
|
+
const byId = new Map((prods ?? []).map((p) => [p.id, p]));
|
|
168
|
+
blocked = gateProductIds.slice(0, 200).map((id) => ({
|
|
169
|
+
productId: id,
|
|
170
|
+
name: byId.get(id)?.product ?? null,
|
|
171
|
+
code: byId.get(id)?.article_number ?? null,
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
104
174
|
}
|
|
105
175
|
return {
|
|
106
176
|
failed,
|
|
@@ -112,6 +182,8 @@ export function useStockSyncHealth() {
|
|
|
112
182
|
noPriceCount,
|
|
113
183
|
blocked,
|
|
114
184
|
blockedWithoutProduct: gateNoProduct,
|
|
185
|
+
blockedSource,
|
|
186
|
+
blockedOther,
|
|
115
187
|
};
|
|
116
188
|
},
|
|
117
189
|
});
|