@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.
Files changed (53) hide show
  1. package/dist-lib/components/voorraad/ArtikelWizard.d.ts +14 -1
  2. package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
  3. package/dist-lib/components/voorraad/ArtikelWizard.js +88 -26
  4. package/dist-lib/components/voorraad/FloridayInfoCard.d.ts.map +1 -1
  5. package/dist-lib/components/voorraad/FloridayInfoCard.js +4 -2
  6. package/dist-lib/components/voorraad/FloridayLoadCarriers.d.ts.map +1 -1
  7. package/dist-lib/components/voorraad/FloridayLoadCarriers.js +3 -2
  8. package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -1
  9. package/dist-lib/components/voorraad/NieuwArtikelPage.js +72 -6
  10. package/dist-lib/components/voorraad/PublishProgressCard.d.ts +7 -0
  11. package/dist-lib/components/voorraad/PublishProgressCard.d.ts.map +1 -1
  12. package/dist-lib/components/voorraad/PublishProgressCard.js +22 -1
  13. package/dist-lib/components/voorraad/StockSyncStatus.d.ts.map +1 -1
  14. package/dist-lib/components/voorraad/StockSyncStatus.js +1 -1
  15. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  16. package/dist-lib/components/voorraad/VoorraadTable.js +1 -1
  17. package/dist-lib/hooks/useLoadCarriers.d.ts +12 -0
  18. package/dist-lib/hooks/useLoadCarriers.d.ts.map +1 -0
  19. package/dist-lib/hooks/useLoadCarriers.js +49 -0
  20. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
  21. package/dist-lib/hooks/useLocalTradeItems.js +3 -1
  22. package/dist-lib/hooks/usePublishJob.d.ts +1 -0
  23. package/dist-lib/hooks/usePublishJob.d.ts.map +1 -1
  24. package/dist-lib/hooks/usePublishJob.js +20 -1
  25. package/dist-lib/hooks/useStockSyncHealth.d.ts +8 -1
  26. package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -1
  27. package/dist-lib/hooks/useStockSyncHealth.js +91 -19
  28. package/dist-lib/integrations/supabase/types.d.ts +400 -0
  29. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  30. package/dist-lib/lib/__tests__/erp-test-123.test.d.ts +2 -0
  31. package/dist-lib/lib/__tests__/erp-test-123.test.d.ts.map +1 -0
  32. package/dist-lib/lib/__tests__/erp-test-123.test.js +43 -0
  33. package/dist-lib/lib/__tests__/load-carriers.test.d.ts +2 -0
  34. package/dist-lib/lib/__tests__/load-carriers.test.d.ts.map +1 -0
  35. package/dist-lib/lib/__tests__/load-carriers.test.js +15 -0
  36. package/dist-lib/lib/buyer-organizations.d.ts +26 -0
  37. package/dist-lib/lib/buyer-organizations.d.ts.map +1 -0
  38. package/dist-lib/lib/buyer-organizations.js +41 -0
  39. package/dist-lib/lib/floriday-customer-offer.functions.d.ts +4 -0
  40. package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
  41. package/dist-lib/lib/floriday-customer-offer.functions.js +54 -16
  42. package/dist-lib/lib/floriday-info.d.ts +0 -1
  43. package/dist-lib/lib/floriday-info.d.ts.map +1 -1
  44. package/dist-lib/lib/floriday-info.js +0 -8
  45. package/dist-lib/lib/simple-packing.d.ts +31 -0
  46. package/dist-lib/lib/simple-packing.d.ts.map +1 -0
  47. package/dist-lib/lib/simple-packing.js +62 -0
  48. package/dist-lib/lib/voorraad-page-head.d.ts +19 -0
  49. package/dist-lib/lib/voorraad-page-head.d.ts.map +1 -0
  50. package/dist-lib/lib/voorraad-page-head.js +11 -0
  51. package/package.json +1 -1
  52. package/sql/AGENTS.md +2 -1
  53. 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, " regel", blockedCount === 1 ? "" : "s", " 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, " regel", data.blockedWithoutProduct === 1 ? "" : "s", " zonder bekend artikel"] }))] })] })), 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"] }))] }));
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,+BAmUA"}
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) && (_jsx("span", { className: "text-[11px] font-medium text-destructive", children: PACKING_INCOMPLETE_TEXT })), _jsxs("div", { role: "status", "aria-label": floriday
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;AAwED;;;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"}
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: null,
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;;;;;EAqDjD;AAED,wBAAgB,cAAc,CAAC,KAAK,SAAK;;;;EAoBxC"}
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 regels zonder bekend artikel. */
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":"AAgBA,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,kDAAkD;IAClD,qBAAqB,EAAE,MAAM,CAAC;CAC/B;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,2EAyGjC"}
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
- // Regels tegengehouden door het verpakkingsverschil (alleen lezen).
85
- const { data: gateRows } = await supabase
86
- .from("floriday_continuous_stock_queue")
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
- if (gateProductIds.length > 0) {
94
- const { data: prods } = await supabase
95
- .from("products")
96
- .select("id, product, article_number")
97
- .in("id", gateProductIds.slice(0, 200));
98
- const byId = new Map((prods ?? []).map((p) => [p.id, p]));
99
- blocked = gateProductIds.slice(0, 200).map((id) => ({
100
- productId: id,
101
- name: byId.get(id)?.product ?? null,
102
- code: byId.get(id)?.article_number ?? null,
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
  });