@flowselections/floriday-voorraad 1.0.23 → 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 (55) 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 +633 -101
  4. package/dist-lib/components/voorraad/StepSamenstelling.d.ts +10 -0
  5. package/dist-lib/components/voorraad/StepSamenstelling.d.ts.map +1 -0
  6. package/dist-lib/components/voorraad/StepSamenstelling.js +333 -0
  7. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  8. package/dist-lib/components/voorraad/VoorraadPage.js +14 -3
  9. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  10. package/dist-lib/components/voorraad/VoorraadTable.js +6 -13
  11. package/dist-lib/hooks/useFloridayPriceGroups.d.ts +20 -0
  12. package/dist-lib/hooks/useFloridayPriceGroups.d.ts.map +1 -0
  13. package/dist-lib/hooks/useFloridayPriceGroups.js +55 -0
  14. package/dist-lib/hooks/useFloridayVbnRequired.d.ts +5 -0
  15. package/dist-lib/hooks/useFloridayVbnRequired.d.ts.map +1 -0
  16. package/dist-lib/hooks/useFloridayVbnRequired.js +16 -0
  17. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
  18. package/dist-lib/hooks/useLocalTradeItems.js +14 -0
  19. package/dist-lib/hooks/useTradeItemSpec.d.ts.map +1 -1
  20. package/dist-lib/hooks/useTradeItemSpec.js +48 -1
  21. package/dist-lib/integrations/supabase/auth-middleware.d.ts +2378 -361
  22. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  23. package/dist-lib/integrations/supabase/client.d.ts +2378 -361
  24. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  25. package/dist-lib/integrations/supabase/client.server.d.ts +2378 -361
  26. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  27. package/dist-lib/integrations/supabase/types.d.ts +2412 -344
  28. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  29. package/dist-lib/integrations/supabase/types.js +11 -9
  30. package/dist-lib/lib/centralSecrets.server.d.ts +21 -0
  31. package/dist-lib/lib/centralSecrets.server.d.ts.map +1 -0
  32. package/dist-lib/lib/centralSecrets.server.js +111 -0
  33. package/dist-lib/lib/floricode-required-features.functions.d.ts +2378 -361
  34. package/dist-lib/lib/floricode-required-features.functions.d.ts.map +1 -1
  35. package/dist-lib/lib/floriday-customer-offer.functions.d.ts +2378 -361
  36. package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
  37. package/dist-lib/lib/floriday-gateway.functions.d.ts +10760 -675
  38. package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -1
  39. package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -1
  40. package/dist-lib/lib/floriday-gateway.server.js +34 -9
  41. package/dist-lib/lib/floriday-payload.d.ts +21 -3
  42. package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
  43. package/dist-lib/lib/floriday-payload.js +167 -34
  44. package/dist-lib/lib/floriday-vbn-required.functions.d.ts +27769 -0
  45. package/dist-lib/lib/floriday-vbn-required.functions.d.ts.map +1 -0
  46. package/dist-lib/lib/floriday-vbn-required.functions.js +85 -0
  47. package/dist-lib/lib/floriday-warehouse.functions.d.ts +6542 -491
  48. package/dist-lib/lib/floriday-warehouse.functions.d.ts.map +1 -1
  49. package/dist-lib/lib/floriday-writes.functions.d.ts +4647 -612
  50. package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
  51. package/dist-lib/lib/floriday-writes.functions.js +36 -1
  52. package/dist-lib/lib/trade-item-prices.d.ts +43 -0
  53. package/dist-lib/lib/trade-item-prices.d.ts.map +1 -0
  54. package/dist-lib/lib/trade-item-prices.js +229 -0
  55. package/package.json +3 -3
@@ -0,0 +1,10 @@
1
+ import type { PackingConfigurationInput } from "../../lib/floriday-payload";
2
+ interface Props {
3
+ productId: string | null;
4
+ floridayId: string | null;
5
+ packings: PackingConfigurationInput[];
6
+ packagingTypeLabel: (code: string) => string;
7
+ }
8
+ export declare function StepSamenstelling({ productId, floridayId, packings, packagingTypeLabel, }: Props): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=StepSamenstelling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StepSamenstelling.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StepSamenstelling.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAsB5E,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC9C;AAUD,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,UAAU,EACV,QAAQ,EACR,kBAAkB,GACnB,EAAE,KAAK,2CA+ZP"}
@@ -0,0 +1,333 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { Button, Input, Popover, PopoverContent, PopoverTrigger, toast, } from "@flowselections/core";
4
+ import { Loader2, Package, Plus, Search, Trash2 } from "lucide-react";
5
+ import { supabase } from "../../integrations/supabase/client";
6
+ function newRowId() {
7
+ return `new:${typeof crypto !== "undefined" && "randomUUID" in crypto
8
+ ? crypto.randomUUID()
9
+ : Date.now().toString(36) + Math.random().toString(36).slice(2)}`;
10
+ }
11
+ export function StepSamenstelling({ productId, floridayId, packings, packagingTypeLabel, }) {
12
+ const [loading, setLoading] = useState(true);
13
+ const [saving, setSaving] = useState(false);
14
+ const [rows, setRows] = useState([]);
15
+ const [names, setNames] = useState(new Map());
16
+ const [activeTab, setActiveTab] = useState("__base__");
17
+ const hasParent = Boolean(productId || floridayId);
18
+ const load = useCallback(async () => {
19
+ if (!hasParent) {
20
+ setRows([]);
21
+ setLoading(false);
22
+ return;
23
+ }
24
+ setLoading(true);
25
+ let q = supabase
26
+ .from("product_bom_items")
27
+ .select("id,packing_configuration_id,component_product_id,component_trade_item_floriday_id,quantity,sort_order")
28
+ .order("sort_order", { ascending: true });
29
+ if (productId && floridayId) {
30
+ q = q.or(`parent_product_id.eq.${productId},parent_trade_item_floriday_id.eq.${floridayId}`);
31
+ }
32
+ else if (productId) {
33
+ q = q.eq("parent_product_id", productId);
34
+ }
35
+ else if (floridayId) {
36
+ q = q.eq("parent_trade_item_floriday_id", floridayId);
37
+ }
38
+ const { data, error } = await q;
39
+ if (error) {
40
+ toast.error("Kon samenstelling niet laden");
41
+ setRows([]);
42
+ setLoading(false);
43
+ return;
44
+ }
45
+ const list = (data ?? []).map((r) => ({
46
+ id: r.id,
47
+ packing_configuration_id: r.packing_configuration_id ?? null,
48
+ component_product_id: r.component_product_id ?? null,
49
+ component_trade_item_floriday_id: r.component_trade_item_floriday_id ?? null,
50
+ quantity: Number(r.quantity ?? 1),
51
+ sort_order: Number(r.sort_order ?? 0),
52
+ }));
53
+ setRows(list);
54
+ await resolveNames(list);
55
+ setLoading(false);
56
+ }, [productId, floridayId, hasParent]);
57
+ const resolveNames = useCallback(async (list) => {
58
+ const prodIds = Array.from(new Set(list.map((r) => r.component_product_id).filter((v) => !!v)));
59
+ const flIds = Array.from(new Set(list
60
+ .map((r) => r.component_trade_item_floriday_id)
61
+ .filter((v) => !!v)));
62
+ const map = new Map();
63
+ if (prodIds.length) {
64
+ const { data } = await supabase
65
+ .from("products")
66
+ .select("id,product,barcode,article_number")
67
+ .in("id", prodIds);
68
+ (data ?? []).forEach((p) => {
69
+ map.set(`product:${p.id}`, {
70
+ kind: "product",
71
+ id: p.id,
72
+ name: String(p.product ?? p.id),
73
+ code: p.barcode ? String(p.barcode) : p.article_number ? String(p.article_number) : undefined,
74
+ });
75
+ });
76
+ }
77
+ if (flIds.length) {
78
+ const { data } = await supabase
79
+ .from("floriday_trade_items_cache")
80
+ .select("floriday_id,data")
81
+ .in("floriday_id", flIds);
82
+ (data ?? []).forEach((n) => {
83
+ const nm = n.data?.tradeItemName?.nl ??
84
+ n.data?.tradeItemName?.en ??
85
+ Object.values(n.data?.tradeItemName ?? {})[0] ??
86
+ n.floriday_id;
87
+ const code = n.data?.supplierArticleCode ??
88
+ n.data?.articleGtin ??
89
+ undefined;
90
+ map.set(`floriday:${n.floriday_id}`, {
91
+ kind: "floriday",
92
+ id: n.floriday_id,
93
+ name: String(nm),
94
+ code: code ? String(code) : undefined,
95
+ });
96
+ });
97
+ }
98
+ setNames((prev) => {
99
+ const merged = new Map(prev);
100
+ map.forEach((v, k) => merged.set(k, v));
101
+ return merged;
102
+ });
103
+ }, []);
104
+ useEffect(() => {
105
+ load();
106
+ }, [load]);
107
+ // Tabs = base + one per current packing.
108
+ const tabs = useMemo(() => [
109
+ { key: "__base__", label: "Basissamenstelling" },
110
+ ...packings.map((p, i) => ({
111
+ key: p.id,
112
+ label: `Belading ${i + 1}${p.isPrimary ? " (primair)" : ""}${p.packagingType ? " · " + packagingTypeLabel(p.packagingType) : ""}`,
113
+ })),
114
+ ], [packings, packagingTypeLabel]);
115
+ // If the active tab no longer exists (packing removed), fall back to base.
116
+ useEffect(() => {
117
+ if (!tabs.some((t) => t.key === activeTab))
118
+ setActiveTab("__base__");
119
+ }, [tabs, activeTab]);
120
+ const currentPackingId = activeTab === "__base__" ? null : activeTab;
121
+ const currentRows = rows.filter((r) => r.packing_configuration_id === currentPackingId);
122
+ const baseRows = rows.filter((r) => r.packing_configuration_id === null);
123
+ const addRow = (opt) => {
124
+ const sortOrder = currentRows.length;
125
+ setRows((prev) => [
126
+ ...prev,
127
+ {
128
+ id: newRowId(),
129
+ packing_configuration_id: currentPackingId,
130
+ component_product_id: opt.kind === "product" ? opt.id : null,
131
+ component_trade_item_floriday_id: opt.kind === "floriday" ? opt.id : null,
132
+ quantity: 1,
133
+ sort_order: sortOrder,
134
+ _new: true,
135
+ _dirty: true,
136
+ },
137
+ ]);
138
+ setNames((prev) => {
139
+ const m = new Map(prev);
140
+ m.set(`${opt.kind}:${opt.id}`, opt);
141
+ return m;
142
+ });
143
+ };
144
+ const updateRow = (id, patch) => {
145
+ setRows((prev) => prev.map((r) => (r.id === id ? { ...r, ...patch, _dirty: true } : r)));
146
+ };
147
+ const removeRow = async (id) => {
148
+ const row = rows.find((r) => r.id === id);
149
+ if (!row)
150
+ return;
151
+ if (!row._new) {
152
+ const { error } = await supabase.from("product_bom_items").delete().eq("id", id);
153
+ if (error) {
154
+ toast.error("Verwijderen mislukt");
155
+ return;
156
+ }
157
+ }
158
+ setRows((prev) => prev.filter((r) => r.id !== id));
159
+ };
160
+ const saveAll = async () => {
161
+ if (!hasParent) {
162
+ toast.error("Sla het artikel eerst op voordat je een samenstelling toevoegt.");
163
+ return;
164
+ }
165
+ const dirty = rows.filter((r) => r._dirty);
166
+ if (dirty.length === 0)
167
+ return;
168
+ setSaving(true);
169
+ try {
170
+ const inserts = dirty
171
+ .filter((r) => r._new)
172
+ .map((r) => ({
173
+ parent_product_id: productId,
174
+ parent_trade_item_floriday_id: floridayId,
175
+ packing_configuration_id: r.packing_configuration_id,
176
+ component_product_id: r.component_product_id,
177
+ component_trade_item_floriday_id: r.component_trade_item_floriday_id,
178
+ quantity: r.quantity,
179
+ unit: "PIECE",
180
+ sort_order: r.sort_order,
181
+ }));
182
+ const updates = dirty.filter((r) => !r._new);
183
+ if (inserts.length) {
184
+ const { data, error } = await supabase
185
+ .from("product_bom_items")
186
+ .insert(inserts)
187
+ .select("id");
188
+ if (error)
189
+ throw error;
190
+ // Map new ids back onto local rows (align by index of the "new" rows we sent)
191
+ const newIds = (data ?? []).map((d) => d.id);
192
+ const newLocal = dirty.filter((r) => r._new);
193
+ setRows((prev) => {
194
+ const map = new Map();
195
+ newLocal.forEach((r, i) => {
196
+ if (newIds[i])
197
+ map.set(r.id, newIds[i]);
198
+ });
199
+ return prev.map((r) => map.has(r.id)
200
+ ? { ...r, id: map.get(r.id), _new: false, _dirty: false }
201
+ : r);
202
+ });
203
+ }
204
+ for (const r of updates) {
205
+ const { error } = await supabase
206
+ .from("product_bom_items")
207
+ .update({
208
+ quantity: r.quantity,
209
+ sort_order: r.sort_order,
210
+ })
211
+ .eq("id", r.id);
212
+ if (error)
213
+ throw error;
214
+ }
215
+ setRows((prev) => prev.map((r) => ({ ...r, _dirty: false })));
216
+ toast.success("Samenstelling opgeslagen");
217
+ }
218
+ catch (e) {
219
+ toast.error("Opslaan mislukt: " + e.message);
220
+ }
221
+ finally {
222
+ setSaving(false);
223
+ }
224
+ };
225
+ const hasUnsaved = rows.some((r) => r._dirty);
226
+ if (!hasParent) {
227
+ return (_jsx("div", { className: "rounded-md border border-dashed p-6 text-center text-sm text-muted-foreground", children: "Sla het artikel eerst op om een samenstelling te configureren." }));
228
+ }
229
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "rounded-md border bg-muted/30 p-3 text-xs text-muted-foreground", children: "Configureer een basissamenstelling en optioneel afwijkende onderdelen per belading. Rijen op de belading-tabbladen gelden bovenop of in plaats van de basissamenstelling." }), _jsx("div", { className: "flex flex-wrap gap-1 border-b", children: tabs.map((t) => {
230
+ const active = t.key === activeTab;
231
+ const count = rows.filter((r) => r.packing_configuration_id === (t.key === "__base__" ? null : t.key)).length;
232
+ return (_jsxs("button", { type: "button", onClick: () => setActiveTab(t.key), className: `-mb-px border-b-2 px-3 py-2 text-sm ${active
233
+ ? "border-primary text-foreground font-medium"
234
+ : "border-transparent text-muted-foreground hover:text-foreground"}`, children: [t.label, _jsx("span", { className: "ml-2 rounded bg-muted px-1.5 py-0.5 text-xs", children: count })] }, t.key));
235
+ }) }), currentPackingId && baseRows.length > 0 && (_jsxs("div", { className: "rounded-md border bg-muted/20 p-3", children: [_jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: "Basissamenstelling (referentie)" }), _jsx("ul", { className: "divide-y", children: baseRows.map((r) => {
236
+ const key = r.component_product_id
237
+ ? `product:${r.component_product_id}`
238
+ : `floriday:${r.component_trade_item_floriday_id}`;
239
+ const info = names.get(key);
240
+ return (_jsxs("li", { className: "flex items-center gap-3 py-1.5 text-sm", children: [_jsx(Package, { className: "h-3.5 w-3.5 text-muted-foreground shrink-0" }), _jsxs("div", { className: "flex-1 min-w-0 truncate", children: [info?.name ?? key, info?.code && (_jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: info.code }))] }), _jsxs("div", { className: "text-xs tabular-nums text-muted-foreground", children: [r.quantity, "\u00D7"] })] }, r.id));
241
+ }) })] })), loading ? (_jsxs("div", { className: "flex items-center gap-2 py-6 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Samenstelling laden\u2026"] })) : currentRows.length === 0 ? (_jsx("div", { className: "rounded-md border border-dashed p-6 text-center", children: _jsx("p", { className: "text-sm text-muted-foreground", children: currentPackingId
242
+ ? "Nog geen afwijkende onderdelen voor deze belading."
243
+ : "Nog geen onderdelen in de basissamenstelling." }) })) : (_jsx("div", { className: "overflow-hidden rounded-md border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-muted/50 text-left text-xs uppercase text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-3 py-2 font-medium", children: "Onderdeel" }), _jsx("th", { className: "px-3 py-2 font-medium w-32", children: "Aantal per verpakking" }), _jsx("th", { className: "px-3 py-2" })] }) }), _jsx("tbody", { className: "divide-y", children: currentRows.map((r) => {
244
+ const key = r.component_product_id
245
+ ? `product:${r.component_product_id}`
246
+ : `floriday:${r.component_trade_item_floriday_id}`;
247
+ const info = names.get(key);
248
+ return (_jsxs("tr", { children: [_jsx("td", { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("div", { className: "h-8 w-8 rounded bg-muted flex items-center justify-center shrink-0", children: _jsx(Package, { className: "h-4 w-4 text-muted-foreground" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "font-medium truncate", children: info?.name ?? key }), info?.code && (_jsx("div", { className: "text-xs text-muted-foreground truncate", children: info.code }))] })] }) }), _jsx("td", { className: "px-3 py-2", children: _jsx(Input, { type: "number", inputMode: "decimal", min: 0, step: "0.01", value: r.quantity, onChange: (e) => updateRow(r.id, { quantity: Number(e.target.value) }), className: "h-8 w-24" }) }), _jsx("td", { className: "px-3 py-2 text-right", children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeRow(r.id), children: _jsx(Trash2, { className: "h-4 w-4" }) }) })] }, r.id));
249
+ }) })] }) })), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(ComponentPicker, { excludeKeys: new Set(currentRows.map((r) => r.component_product_id
250
+ ? `product:${r.component_product_id}`
251
+ : `floriday:${r.component_trade_item_floriday_id}`)), onPick: addRow }), _jsxs("div", { className: "ml-auto flex items-center gap-2", children: [hasUnsaved && (_jsx("span", { className: "text-xs text-amber-700", children: "Niet-opgeslagen wijzigingen" })), _jsxs(Button, { type: "button", size: "sm", onClick: saveAll, disabled: !hasUnsaved || saving, children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Opslaan"] })] })] })] }));
252
+ }
253
+ // ============================================================
254
+ // Component picker
255
+ // ============================================================
256
+ function ComponentPicker({ onPick, excludeKeys, }) {
257
+ const [open, setOpen] = useState(false);
258
+ const [query, setQuery] = useState("");
259
+ const [loading, setLoading] = useState(false);
260
+ const [results, setResults] = useState([]);
261
+ useEffect(() => {
262
+ if (!open)
263
+ return;
264
+ const q = query.trim();
265
+ let cancelled = false;
266
+ setLoading(true);
267
+ const timer = setTimeout(async () => {
268
+ try {
269
+ const [prodRes, flRes] = await Promise.all([
270
+ q.length > 0
271
+ ? supabase
272
+ .from("products")
273
+ .select("id,product,barcode,article_number")
274
+ .or(`product.ilike.%${q}%,barcode.ilike.%${q}%,article_number.ilike.%${q}%`)
275
+ .limit(25)
276
+ : supabase
277
+ .from("products")
278
+ .select("id,product,barcode,article_number")
279
+ .order("updated_at", { ascending: false })
280
+ .limit(15),
281
+ supabase
282
+ .from("floriday_trade_items_cache")
283
+ .select("floriday_id,data")
284
+ .eq("is_deleted", false)
285
+ .limit(200),
286
+ ]);
287
+ if (cancelled)
288
+ return;
289
+ const prodOpts = (prodRes.data ?? []).map((p) => ({
290
+ kind: "product",
291
+ id: p.id,
292
+ name: String(p.product ?? p.id),
293
+ code: p.barcode
294
+ ? String(p.barcode)
295
+ : p.article_number
296
+ ? String(p.article_number)
297
+ : undefined,
298
+ }));
299
+ const flOptsAll = (flRes.data ?? []).map((n) => {
300
+ const nm = n.data?.tradeItemName?.nl ??
301
+ n.data?.tradeItemName?.en ??
302
+ Object.values(n.data?.tradeItemName ?? {})[0] ??
303
+ n.floriday_id;
304
+ const code = n.data?.supplierArticleCode ?? n.data?.articleGtin ?? undefined;
305
+ return {
306
+ kind: "floriday",
307
+ id: n.floriday_id,
308
+ name: String(nm),
309
+ code: code ? String(code) : undefined,
310
+ };
311
+ });
312
+ const flOpts = q.length
313
+ ? flOptsAll.filter((o) => o.name.toLowerCase().includes(q.toLowerCase()) ||
314
+ (o.code ?? "").toLowerCase().includes(q.toLowerCase()))
315
+ : flOptsAll.slice(0, 15);
316
+ setResults([...prodOpts, ...flOpts].filter((o) => !excludeKeys.has(`${o.kind}:${o.id}`)));
317
+ }
318
+ finally {
319
+ if (!cancelled)
320
+ setLoading(false);
321
+ }
322
+ }, 200);
323
+ return () => {
324
+ cancelled = true;
325
+ clearTimeout(timer);
326
+ };
327
+ }, [open, query, excludeKeys]);
328
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", size: "sm", children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Onderdeel toevoegen"] }) }), _jsxs(PopoverContent, { className: "w-96 p-0", align: "start", children: [_jsx("div", { className: "border-b p-2", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { autoFocus: true, placeholder: "Zoek artikel of Floriday-item\u2026", value: query, onChange: (e) => setQuery(e.target.value), className: "h-8 pl-8" })] }) }), _jsx("div", { className: "max-h-80 overflow-y-auto", children: loading ? (_jsxs("div", { className: "flex items-center gap-2 p-3 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Zoeken\u2026"] })) : results.length === 0 ? (_jsx("div", { className: "p-3 text-sm text-muted-foreground", children: "Geen resultaten." })) : (_jsx("ul", { className: "divide-y", children: results.map((r) => (_jsx("li", { children: _jsxs("button", { type: "button", className: "flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted", onClick: () => {
329
+ onPick(r);
330
+ setOpen(false);
331
+ setQuery("");
332
+ }, children: [_jsx(Package, { className: "h-4 w-4 text-muted-foreground shrink-0" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-medium", children: r.name }), _jsxs("div", { className: "truncate text-xs text-muted-foreground", children: [r.kind === "product" ? "Lokaal artikel" : "Floriday", " \u00B7", " ", r.code ?? r.id] })] })] }) }, `${r.kind}:${r.id}`))) })) })] })] }));
333
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AA6EA,wBAAgB,YAAY,4CAiM3B"}
1
+ {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AA4FA,wBAAgB,YAAY,4CAkO3B"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
3
  import { Link } from "@tanstack/react-router";
4
- import { Button, Card, Input } from "@flowselections/core";
4
+ import { Button, Card, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
5
5
  import { AlertTriangle, CheckCircle2, FileText, PackageX, Plus, Search, } from "lucide-react";
6
6
  import { useFloridayConnection } from "../../hooks/useFloridayConnection";
7
7
  import { useVoorraadData } from "../../hooks/useVoorraadData";
@@ -9,6 +9,9 @@ import { ExcelExportButton } from "./ExcelExportButton";
9
9
  import { StockBulkButtons } from "./StockBulkButtons";
10
10
  import { VoorraadTable } from "./VoorraadTable";
11
11
  import { VoorraadPagination } from "./VoorraadPagination";
12
+ function isLinkedToFloriday(i) {
13
+ return Boolean(i.floridayId) || i.source === "published";
14
+ }
12
15
  function toneClasses(tone) {
13
16
  switch (tone) {
14
17
  case "emerald":
@@ -34,6 +37,8 @@ export function VoorraadPage() {
34
37
  const { items, loading, error, reload } = useVoorraadData(activeId);
35
38
  const [search, setSearch] = useState("");
36
39
  const [stockFilter, setStockFilter] = useState("all");
40
+ const [floridayFilter, setFloridayFilter] = useState("all");
41
+ const [typeFilter, setTypeFilter] = useState("all");
37
42
  const [page, setPage] = useState(1);
38
43
  const [pageSize, setPageSize] = useState(25);
39
44
  const counts = useMemo(() => {
@@ -62,12 +67,18 @@ export function VoorraadPage() {
62
67
  if (stockFilter === "below_min" &&
63
68
  !((i.minQuantity ?? 0) > 0 && avail < i.minQuantity))
64
69
  return false;
70
+ if (floridayFilter === "linked" && !isLinkedToFloriday(i))
71
+ return false;
72
+ if (floridayFilter === "unlinked" && isLinkedToFloriday(i))
73
+ return false;
74
+ if (typeFilter !== "all" && (i.itemType ?? "artikel") !== typeFilter)
75
+ return false;
65
76
  if (!q)
66
77
  return true;
67
78
  return (i.name.toLowerCase().includes(q) ||
68
79
  (i.articleNumber ?? "").toLowerCase().includes(q));
69
80
  });
70
- }, [items, search, stockFilter]);
81
+ }, [items, search, stockFilter, floridayFilter, typeFilter]);
71
82
  const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
72
83
  useEffect(() => {
73
84
  if (page > totalPages)
@@ -86,5 +97,5 @@ export function VoorraadPage() {
86
97
  return (_jsxs("button", { type: "button", onClick: () => setStockFilter(t.id), className: `relative py-3 px-3 text-sm font-medium whitespace-nowrap transition-colors ${active
87
98
  ? "text-foreground"
88
99
  : "text-muted-foreground hover:text-foreground"}`, children: [t.label, _jsx("span", { className: `ml-2 text-xs ${active ? "text-primary" : "text-muted-foreground/70"}`, children: t.count }), active && (_jsx("span", { className: "absolute left-2 right-2 -bottom-px h-0.5 bg-primary rounded-full" }))] }, t.id));
89
- }) }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 p-4 border-b", children: [_jsxs("div", { className: "relative flex-1 min-w-[220px] max-w-md", children: [_jsx(Search, { className: "w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { placeholder: "Zoek op product of artikelnummer...", className: "pl-9", value: search, onChange: (e) => setSearch(e.target.value) })] }), _jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [_jsx(ExcelExportButton, { items: filtered }), _jsx(StockBulkButtons, { items: items, activeConnectionId: activeId, onImported: reload })] })] }), _jsx("div", { className: "overflow-x-auto", children: _jsx(VoorraadTable, { items: paged, loading: loading }) }), _jsx(VoorraadPagination, { total: filtered.length, page: page, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize })] })] }));
100
+ }) }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 p-4 border-b", children: [_jsxs("div", { className: "relative flex-1 min-w-[220px] max-w-md", children: [_jsx(Search, { className: "w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { placeholder: "Zoek op product of artikelnummer...", className: "pl-9", value: search, onChange: (e) => setSearch(e.target.value) })] }), _jsxs(Select, { value: floridayFilter, onValueChange: (v) => setFloridayFilter(v), children: [_jsx(SelectTrigger, { className: "h-9 w-[190px]", children: _jsx(SelectValue, { placeholder: "Floriday" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "Alle (Floriday)" }), _jsx(SelectItem, { value: "linked", children: "Gekoppeld aan Floriday" }), _jsx(SelectItem, { value: "unlinked", children: "Niet gekoppeld" })] })] }), _jsxs(Select, { value: typeFilter, onValueChange: (v) => setTypeFilter(v), children: [_jsx(SelectTrigger, { className: "h-9 w-[170px]", children: _jsx(SelectValue, { placeholder: "Type" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "Alle types" }), _jsx(SelectItem, { value: "artikel", children: "Artikel" }), _jsx(SelectItem, { value: "productgroep", children: "Productgroep" }), _jsx(SelectItem, { value: "samenstelling", children: "Samenstelling" })] })] }), _jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [_jsx(ExcelExportButton, { items: filtered }), _jsx(StockBulkButtons, { items: items, activeConnectionId: activeId, onImported: reload })] })] }), _jsx("div", { className: "overflow-x-auto", children: _jsx(VoorraadTable, { items: paged, loading: loading }) }), _jsx(VoorraadPagination, { total: filtered.length, page: page, pageSize: pageSize, onPageChange: setPage, onPageSizeChange: setPageSize })] })] }));
90
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAW3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,2CA0IA"}
1
+ {"version":3,"file":"VoorraadTable.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAY3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,2CA6IA"}
@@ -29,18 +29,6 @@ export function VoorraadTable({ items, loading, }) {
29
29
  };
30
30
  const floriday = item.floriday ?? null;
31
31
  const thumbUrl = floriday?.photoUrl || item.imageUrl;
32
- const floridayTooltip = floriday
33
- ? [
34
- `Naam (Floriday): ${floriday.name || "—"}`,
35
- `Artikelnr (Floriday): ${floriday.supplierArticleCode || "—"}`,
36
- `GTIN: ${floriday.articleGtin || "—"}`,
37
- floriday.vbnProductCode
38
- ? `VBN-code: ${floriday.vbnProductCode}`
39
- : null,
40
- ]
41
- .filter(Boolean)
42
- .join("\n")
43
- : null;
44
32
  return (_jsxs("tr", { className: `border-t hover:bg-muted/30 ${clickable ? "cursor-pointer" : ""}`, onClick: clickable ? open : undefined, role: clickable ? "button" : undefined, tabIndex: clickable ? 0 : undefined, onKeyDown: clickable
45
33
  ? (e) => {
46
34
  if (e.key === "Enter" || e.key === " ") {
@@ -48,6 +36,11 @@ export function VoorraadTable({ items, loading, }) {
48
36
  open();
49
37
  }
50
38
  }
51
- : undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [_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 items-center gap-2 flex-wrap", children: [_jsx("span", { className: "font-medium text-foreground", children: item.name }), floriday && (_jsx("span", { className: "inline-flex items-center justify-center h-4 min-w-4 px-1 rounded-full bg-emerald-500/15 text-emerald-700 border border-emerald-500/30 text-[10px] font-semibold leading-none", title: floridayTooltip ?? "Gekoppeld met Floriday", "aria-label": "Gekoppeld met Floriday", children: "F" }))] }), low && (_jsx("div", { className: "text-xs text-destructive", children: "onder minimumvoorraad" }))] }), _jsx("td", { className: "p-3", children: item.itemType === "productgroep" ? (_jsx(Badge, { className: "bg-indigo-500/15 text-indigo-700 border-indigo-500/30", children: "Productgroep" })) : item.itemType === "samenstelling" ? (_jsx(Badge, { className: "bg-emerald-500/15 text-emerald-700 border-emerald-500/30", children: "Samenstelling" })) : (_jsx(Badge, { variant: "secondary", children: "Artikel" })) }), _jsx("td", { className: "p-3 font-mono text-xs", children: item.articleNumber || "—" }), columns.map((c) => (_jsx("td", { className: "p-3 text-right tabular-nums text-muted-foreground", children: Number(item[c.key] ?? 0) }, c.key)))] }, item.id));
39
+ : undefined, "aria-label": clickable ? `Bewerk ${item.name}` : undefined, children: [_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 }), _jsxs("div", { role: "status", "aria-label": floriday
40
+ ? "Online in Floriday"
41
+ : "Niet online in Floriday", title: floriday
42
+ ? "Online in Floriday"
43
+ : "Niet online in Floriday", className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-2 py-0.5 text-[11px] font-medium leading-none text-muted-foreground", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full " +
44
+ (floriday ? "bg-emerald-500" : "bg-red-500"), "aria-hidden": true }), _jsx("span", { children: "Floriday" })] })] }), low && (_jsx("div", { className: "text-xs text-destructive", children: "onder minimumvoorraad" }))] }), _jsx("td", { className: "p-3", children: item.itemType === "productgroep" ? (_jsx(Badge, { className: "bg-indigo-500/15 text-indigo-700 border-indigo-500/30", children: "Productgroep" })) : item.itemType === "samenstelling" ? (_jsx(Badge, { className: "bg-emerald-500/15 text-emerald-700 border-emerald-500/30", children: "Samenstelling" })) : (_jsx(Badge, { variant: "secondary", children: "Artikel" })) }), _jsx("td", { className: "p-3 font-mono text-xs", children: item.articleNumber || "—" }), columns.map((c) => (_jsx("td", { className: "p-3 text-right tabular-nums text-muted-foreground", children: Number(item[c.key] ?? 0) }, c.key)))] }, item.id));
52
45
  }) })] }) }));
53
46
  }
@@ -0,0 +1,20 @@
1
+ export interface FloridayPriceGroup {
2
+ /** Floriday priceGroupId (UUID). */
3
+ id: string;
4
+ name: string;
5
+ currency: string;
6
+ salesUnit: string;
7
+ /** Floriday buyer-organization ids die tot deze prijsgroep behoren. */
8
+ customerOrganizationIds: string[];
9
+ }
10
+ /**
11
+ * Leest alle actieve (niet verwijderde) Floriday-prijsgroepen voor de opgegeven
12
+ * connectie uit `floriday_price_groups_cache`. De sync wordt door de
13
+ * Authenticatie-module beheerd; dit is puur een read-side hook.
14
+ */
15
+ export declare function useFloridayPriceGroups(activeId: string | null): {
16
+ priceGroups: FloridayPriceGroup[];
17
+ loading: boolean;
18
+ error: string | null;
19
+ };
20
+ //# sourceMappingURL=useFloridayPriceGroups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFloridayPriceGroups.d.ts","sourceRoot":"","sources":["../../src/hooks/useFloridayPriceGroups.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,uBAAuB,EAAE,MAAM,EAAE,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;;;;EA+C7D"}
@@ -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"}