@flowselections/floriday-voorraad 1.0.22 → 1.0.26

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 (65) hide show
  1. package/dist-lib/assets/floriday-logo.png.asset.json +4 -4
  2. package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
  3. package/dist-lib/components/voorraad/ArtikelWizard.js +655 -93
  4. package/dist-lib/components/voorraad/FloridayInfoCard.d.ts +12 -0
  5. package/dist-lib/components/voorraad/FloridayInfoCard.d.ts.map +1 -0
  6. package/dist-lib/components/voorraad/FloridayInfoCard.js +85 -0
  7. package/dist-lib/components/voorraad/StepSamenstelling.d.ts +10 -0
  8. package/dist-lib/components/voorraad/StepSamenstelling.d.ts.map +1 -0
  9. package/dist-lib/components/voorraad/StepSamenstelling.js +333 -0
  10. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  11. package/dist-lib/components/voorraad/VoorraadPage.js +14 -3
  12. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  13. package/dist-lib/components/voorraad/VoorraadTable.js +8 -1
  14. package/dist-lib/hooks/useFloridayPriceGroups.d.ts +20 -0
  15. package/dist-lib/hooks/useFloridayPriceGroups.d.ts.map +1 -0
  16. package/dist-lib/hooks/useFloridayPriceGroups.js +55 -0
  17. package/dist-lib/hooks/useFloridayVbnRequired.d.ts +5 -0
  18. package/dist-lib/hooks/useFloridayVbnRequired.d.ts.map +1 -0
  19. package/dist-lib/hooks/useFloridayVbnRequired.js +16 -0
  20. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
  21. package/dist-lib/hooks/useLocalTradeItems.js +14 -0
  22. package/dist-lib/hooks/useTradeItemSpec.d.ts.map +1 -1
  23. package/dist-lib/hooks/useTradeItemSpec.js +48 -1
  24. package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
  25. package/dist-lib/hooks/useVoorraadData.js +36 -5
  26. package/dist-lib/integrations/supabase/auth-middleware.d.ts +2388 -345
  27. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  28. package/dist-lib/integrations/supabase/client.d.ts +2388 -345
  29. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  30. package/dist-lib/integrations/supabase/client.server.d.ts +2388 -345
  31. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  32. package/dist-lib/integrations/supabase/types.d.ts +2437 -343
  33. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  34. package/dist-lib/integrations/supabase/types.js +11 -9
  35. package/dist-lib/lib/centralSecrets.server.d.ts +21 -0
  36. package/dist-lib/lib/centralSecrets.server.d.ts.map +1 -0
  37. package/dist-lib/lib/centralSecrets.server.js +111 -0
  38. package/dist-lib/lib/floricode-required-features.functions.d.ts +2388 -345
  39. package/dist-lib/lib/floricode-required-features.functions.d.ts.map +1 -1
  40. package/dist-lib/lib/floriday-client.d.ts +4 -0
  41. package/dist-lib/lib/floriday-client.d.ts.map +1 -1
  42. package/dist-lib/lib/floriday-customer-offer.functions.d.ts +2388 -345
  43. package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
  44. package/dist-lib/lib/floriday-gateway.functions.d.ts +10860 -645
  45. package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -1
  46. package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -1
  47. package/dist-lib/lib/floriday-gateway.server.js +34 -9
  48. package/dist-lib/lib/floriday-info.d.ts +54 -0
  49. package/dist-lib/lib/floriday-info.d.ts.map +1 -0
  50. package/dist-lib/lib/floriday-info.js +114 -0
  51. package/dist-lib/lib/floriday-payload.d.ts +21 -3
  52. package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
  53. package/dist-lib/lib/floriday-payload.js +167 -34
  54. package/dist-lib/lib/floriday-vbn-required.functions.d.ts +27769 -0
  55. package/dist-lib/lib/floriday-vbn-required.functions.d.ts.map +1 -0
  56. package/dist-lib/lib/floriday-vbn-required.functions.js +85 -0
  57. package/dist-lib/lib/floriday-warehouse.functions.d.ts +6602 -473
  58. package/dist-lib/lib/floriday-warehouse.functions.d.ts.map +1 -1
  59. package/dist-lib/lib/floriday-writes.functions.d.ts +4681 -594
  60. package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
  61. package/dist-lib/lib/floriday-writes.functions.js +36 -1
  62. package/dist-lib/lib/trade-item-prices.d.ts +43 -0
  63. package/dist-lib/lib/trade-item-prices.d.ts.map +1 -0
  64. package/dist-lib/lib/trade-item-prices.js +229 -0
  65. package/package.json +3 -3
@@ -0,0 +1,55 @@
1
+ import { useEffect, useState } from "react";
2
+ import { supabase } from "../integrations/supabase/client";
3
+ /**
4
+ * Leest alle actieve (niet verwijderde) Floriday-prijsgroepen voor de opgegeven
5
+ * connectie uit `floriday_price_groups_cache`. De sync wordt door de
6
+ * Authenticatie-module beheerd; dit is puur een read-side hook.
7
+ */
8
+ export function useFloridayPriceGroups(activeId) {
9
+ const [priceGroups, setPriceGroups] = useState([]);
10
+ const [loading, setLoading] = useState(Boolean(activeId));
11
+ const [error, setError] = useState(null);
12
+ useEffect(() => {
13
+ if (!activeId) {
14
+ setPriceGroups([]);
15
+ setLoading(false);
16
+ return;
17
+ }
18
+ let cancelled = false;
19
+ setLoading(true);
20
+ (async () => {
21
+ const { data, error } = await supabase
22
+ .from("floriday_price_groups_cache")
23
+ .select("floriday_id,data")
24
+ .eq("connection_id", activeId)
25
+ .eq("is_deleted", false);
26
+ if (cancelled)
27
+ return;
28
+ if (error) {
29
+ setError(error.message);
30
+ setPriceGroups([]);
31
+ }
32
+ else {
33
+ const rows = (data ?? []).map((row) => {
34
+ const raw = row.data ?? {};
35
+ const customers = Array.isArray(raw.customers) ? raw.customers : [];
36
+ return {
37
+ id: String(raw.priceGroupId ?? row.floriday_id),
38
+ name: String(raw.name ?? "Prijsgroep"),
39
+ currency: String(raw.currency ?? "EUR"),
40
+ salesUnit: String(raw.salesUnit ?? "PIECE"),
41
+ customerOrganizationIds: customers.map((c) => String(c)),
42
+ };
43
+ });
44
+ rows.sort((a, b) => a.name.localeCompare(b.name, "nl"));
45
+ setPriceGroups(rows);
46
+ setError(null);
47
+ }
48
+ setLoading(false);
49
+ })();
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ }, [activeId]);
54
+ return { priceGroups, loading, error };
55
+ }
@@ -0,0 +1,5 @@
1
+ export declare function useFloridayVbnRequired(vbnCode: string | null | undefined): import("@tanstack/react-query").UseQueryResult<{
2
+ vbnCode: string;
3
+ requiredCodes: string[];
4
+ }, Error>;
5
+ //# sourceMappingURL=useFloridayVbnRequired.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFloridayVbnRequired.d.ts","sourceRoot":"","sources":["../../src/hooks/useFloridayVbnRequired.ts"],"names":[],"mappings":"AAOA,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;;;UASxE"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Leest de gedeelde cache van door Floriday afgedwongen verplichte
3
+ * characteristic-codes per VBN-productcode.
4
+ */
5
+ import { useQuery } from "@tanstack/react-query";
6
+ import { getFloridayVbnRequired } from "../lib/floriday-vbn-required.functions";
7
+ export function useFloridayVbnRequired(vbnCode) {
8
+ const code = String(vbnCode ?? "").trim();
9
+ const enabled = /^\d{5,6}$/.test(code);
10
+ return useQuery({
11
+ queryKey: ["floriday-vbn-required", code],
12
+ queryFn: () => getFloridayVbnRequired({ data: { vbnCode: code } }),
13
+ enabled,
14
+ staleTime: 10 * 60 * 1000,
15
+ });
16
+ }
@@ -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;AA2DD;;;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,CAsBrF;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;;;GAGG;AACH,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;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DlB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhF;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;AA2DD;;;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,CAsBrF;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;;;GAGG;AACH,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;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2ElB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhF;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
@@ -128,6 +128,14 @@ export async function upsertLocalTradeItem(params) {
128
128
  const firstImageUrl = firstImage?.url || firstImage?.previewUrl;
129
129
  if (firstImageUrl)
130
130
  productPatch.image_url = firstImageUrl;
131
+ if (payload.vatRate !== undefined) {
132
+ const v = payload.vatRate;
133
+ productPatch.vat_rate = v === null || v === "" || Number.isNaN(Number(v)) ? null : Number(v);
134
+ }
135
+ if (payload.vatCode !== undefined) {
136
+ const c = payload.vatCode;
137
+ productPatch.vat_code = c && String(c).length > 0 ? String(c) : null;
138
+ }
131
139
  if (targetId) {
132
140
  const { error } = await supabase
133
141
  .from("products")
@@ -153,6 +161,12 @@ export async function upsertLocalTradeItem(params) {
153
161
  floriday_payload: payload,
154
162
  floriday_trade_item_id: params.meta?.floridayId ?? null,
155
163
  floriday_active: params.meta?.floridayLinkStatus === "published",
164
+ vat_rate: payload.vatRate !== null && payload.vatRate !== undefined && payload.vatRate !== ""
165
+ ? Number(payload.vatRate)
166
+ : null,
167
+ vat_code: payload.vatCode && String(payload.vatCode).length > 0
168
+ ? String(payload.vatCode)
169
+ : null,
156
170
  };
157
171
  const { error } = await supabase.from("products").insert(insertRow);
158
172
  if (error)
@@ -1 +1 @@
1
- {"version":3,"file":"useTradeItemSpec.d.ts","sourceRoot":"","sources":["../../src/hooks/useTradeItemSpec.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,eAAe,CAAC;AAEzE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,aAAa,EAAE,uBAAuB,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,eAAe,EAAE,kBAAkB,EAAE,CAAC;IACtC,2DAA2D;IAC3D,2BAA2B,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,0FAA0F;IAC1F,2BAA2B,EAAE,OAAO,CAAC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mGAAmG;IACnG,0BAA0B,EAAE,OAAO,CAAC;IACpC,4FAA4F;IAC5F,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,uBAAuB,EAAE,OAAO,CAAC;CAClC;AA8bD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IAC/C,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3C;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,kBAAkB,CAAC,EAAE,sBAAsB,EAAE,GAAG,IAAI,GACnD,aAAa,CAsEf"}
1
+ {"version":3,"file":"useTradeItemSpec.d.ts","sourceRoot":"","sources":["../../src/hooks/useTradeItemSpec.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,eAAe,CAAC;AAEzE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,aAAa,EAAE,uBAAuB,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,eAAe,EAAE,kBAAkB,EAAE,CAAC;IACtC,2DAA2D;IAC3D,2BAA2B,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,0FAA0F;IAC1F,2BAA2B,EAAE,OAAO,CAAC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mGAAmG;IACnG,0BAA0B,EAAE,OAAO,CAAC;IACpC,4FAA4F;IAC5F,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAgeD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IAC/C,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3C;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,kBAAkB,CAAC,EAAE,sBAAsB,EAAE,GAAG,IAAI,GACnD,aAAa,CAsFf"}
@@ -389,6 +389,37 @@ function deriveVbnProductCharacteristics(schema, vbnCode) {
389
389
  productGroupId,
390
390
  };
391
391
  }
392
+ /**
393
+ * Alle VBN-karakteristieken uit `codeLists['vbn-characteristic']` als
394
+ * optionele pool — hetzelfde superset dat Floriday's eigen UI aanbiedt.
395
+ */
396
+ function allVbnCharacteristicsAsOptional(schema) {
397
+ const list = schema?.codeLists?.["vbn-characteristic"] ?? [];
398
+ if (!Array.isArray(list) || list.length === 0)
399
+ return [];
400
+ const map = new Map();
401
+ for (const item of list) {
402
+ if (!isRecord(item))
403
+ continue;
404
+ const payload = payloadOf(item);
405
+ const code = pickCharacteristicCode(String(item.code ?? payload.code ?? payload.vbn_code ?? ""));
406
+ if (!code || map.has(code))
407
+ continue;
408
+ const label = payload.description ??
409
+ payload.short_name ??
410
+ item.description ??
411
+ item.label ??
412
+ code;
413
+ map.set(code, {
414
+ code,
415
+ label: String(label),
416
+ required: false,
417
+ listName: code,
418
+ allowedValues: [],
419
+ });
420
+ }
421
+ return hydrateLabels(Array.from(map.values()), schema);
422
+ }
392
423
  export function useTradeItemSpec(schema, vbnCode, productGroup, regulatoryFeatures) {
393
424
  return useMemo(() => {
394
425
  const fromVbn = deriveVbnProductCharacteristics(schema, vbnCode);
@@ -410,11 +441,27 @@ export function useTradeItemSpec(schema, vbnCode, productGroup, regulatoryFeatur
410
441
  allowedValues: f.values,
411
442
  }));
412
443
  }
413
- const characteristics = fromRegulatory.length
444
+ const primary = fromRegulatory.length
414
445
  ? fromRegulatory
415
446
  : fromVbn.characteristics.length
416
447
  ? fromVbn.characteristics
417
448
  : schemaCharacteristics;
449
+ // Verbreed met alle VBN-karakteristieken als optionele pool, zodat de UI
450
+ // dezelfde superset toont als Floriday zelf (S01, S05, S50, …). Codes uit
451
+ // `primary` blijven leidend inclusief hun `required`-flag.
452
+ const optionalPool = allVbnCharacteristicsAsOptional(schema);
453
+ const merged = new Map();
454
+ for (const c of primary)
455
+ merged.set(c.code, c);
456
+ for (const c of optionalPool) {
457
+ if (!merged.has(c.code))
458
+ merged.set(c.code, c);
459
+ }
460
+ const characteristics = Array.from(merged.values()).sort((a, b) => {
461
+ if (a.required !== b.required)
462
+ return Number(b.required) - Number(a.required);
463
+ return a.code.localeCompare(b.code);
464
+ });
418
465
  const requiredCharacteristicCodes = new Set(characteristics.filter((c) => c.required).map((c) => c.code));
419
466
  const required = new Set((schema?.requiredFields ?? []).map((f) => f));
420
467
  const canDetermineCharacteristics = !vbnCode
@@ -1 +1 @@
1
- {"version":3,"file":"useVoorraadData.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAqB5E;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;;EAuS1D"}
1
+ {"version":3,"file":"useVoorraadData.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoorraadData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAsB5E;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;;;;;EA+T1D"}
@@ -1,6 +1,7 @@
1
1
  import { useCallback, useEffect, useState } from "react";
2
2
  import { supabase } from "../integrations/supabase/client";
3
3
  import { normaliseTradeItem } from "../lib/floriday-client";
4
+ import { floridayInfoFromCache } from "../lib/floriday-info";
4
5
  import { useLocalTradeItems } from "./useLocalTradeItems";
5
6
  import { fetchStockMap } from "./useTradeItemStock";
6
7
  import { useFloridayContinuousStockMap } from "./useFloridayContinuousStock";
@@ -29,6 +30,7 @@ function applyStock(item, s) {
29
30
  */
30
31
  export function useVoorraadData(connectionId) {
31
32
  const [publishedItems, setPublishedItems] = useState([]);
33
+ const [floridayInfoMap, setFloridayInfoMap] = useState(new Map());
32
34
  const [stockMap, setStockMap] = useState(new Map());
33
35
  const [typeSets, setTypeSets] = useState({
34
36
  groupProdIds: new Set(),
@@ -72,6 +74,13 @@ export function useVoorraadData(connectionId) {
72
74
  ]);
73
75
  if (pubRes.error)
74
76
  throw pubRes.error;
77
+ const infoMap = new Map();
78
+ for (const row of pubRes.data ?? []) {
79
+ const info = floridayInfoFromCache({ ...row.data, id: row.floriday_id });
80
+ if (info)
81
+ infoMap.set(row.floriday_id, info);
82
+ }
83
+ setFloridayInfoMap(infoMap);
75
84
  const normalised = (pubRes.data ?? [])
76
85
  .map((row) => normaliseTradeItem({ ...row.data, id: row.floriday_id }))
77
86
  .filter((i) => i.id)
@@ -81,6 +90,7 @@ export function useVoorraadData(connectionId) {
81
90
  floridayActive: true,
82
91
  source: "published",
83
92
  tradeItemKey: i.id,
93
+ floriday: infoMap.get(i.id) ?? null,
84
94
  }));
85
95
  setPublishedItems(normalised);
86
96
  setStockMap(stock);
@@ -247,12 +257,33 @@ export function useVoorraadData(connectionId) {
247
257
  };
248
258
  };
249
259
  // Voorkom dubbele rijen: Floriday-cache-items waar we al een lokaal product voor hebben
250
- // (op `floriday_trade_item_id`) tonen we niet apart — het lokale product wint.
251
- const localFloridayIds = new Set(localItems
252
- .map((i) => i.floridayId)
253
- .filter((id) => Boolean(id)));
260
+ // tonen we niet apart — het lokale product wint. We matchen breed zodat ook half-gelegde
261
+ // koppelingen (lege `floriday_trade_item_id` maar zelfde id/trade_item_key als de cache)
262
+ // niet dubbel verschijnen.
263
+ const localFloridayIds = new Set();
264
+ for (const i of localItems) {
265
+ if (i.floridayId)
266
+ localFloridayIds.add(i.floridayId);
267
+ // Zelfde UUID op products.id als op cache.floriday_id → legacy koppeling.
268
+ if (i.productId)
269
+ localFloridayIds.add(i.productId);
270
+ // Rauwe trade_item_key die een floriday-id-vorm heeft.
271
+ const key = i.tradeItemKey ?? "";
272
+ if (key && !key.startsWith("product:") && !key.startsWith("draft:")) {
273
+ localFloridayIds.add(key);
274
+ }
275
+ }
276
+ const attachFloriday = (i) => {
277
+ const fid = i.floridayId ?? null;
278
+ if (!fid)
279
+ return i;
280
+ const info = floridayInfoMap.get(fid);
281
+ if (!info)
282
+ return i;
283
+ return { ...i, floriday: info };
284
+ };
254
285
  const merged = [
255
- ...localItems.map((i) => applyProductGroupReservation(classify(applyStock(i, stockMap.get(i.tradeItemKey ?? ""))))),
286
+ ...localItems.map((i) => applyProductGroupReservation(classify(attachFloriday(applyStock(i, stockMap.get(i.tradeItemKey ?? "")))))),
256
287
  ...publishedItems
257
288
  .filter((i) => !i.id || !localFloridayIds.has(i.id))
258
289
  .map((i) => applyProductGroupReservation(classify(applyFloridayOverride(applyStock(i, stockMap.get(i.id)))))),