@flowselections/floriday-klanten-module 1.0.34 → 1.0.35

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 (90) hide show
  1. package/dist-lib/assets/floriday-logo.png.asset.json +11 -0
  2. package/dist-lib/components/klanten/CustomerAssortmentTab.d.ts +5 -0
  3. package/dist-lib/components/klanten/CustomerAssortmentTab.d.ts.map +1 -0
  4. package/dist-lib/components/klanten/CustomerAssortmentTab.js +74 -0
  5. package/dist-lib/components/klanten/FloridayPriceImportDialog.d.ts +5 -0
  6. package/dist-lib/components/klanten/FloridayPriceImportDialog.d.ts.map +1 -0
  7. package/dist-lib/components/klanten/FloridayPriceImportDialog.js +55 -0
  8. package/dist-lib/components/klanten/GroupedKlantDetail.d.ts.map +1 -1
  9. package/dist-lib/components/klanten/GroupedKlantDetail.js +4 -3
  10. package/dist-lib/components/klanten/KlantDetail.d.ts.map +1 -1
  11. package/dist-lib/components/klanten/KlantDetail.js +10 -2
  12. package/dist-lib/components/klanten/KlantenOverzicht.d.ts.map +1 -1
  13. package/dist-lib/components/klanten/KlantenOverzicht.js +24 -3
  14. package/dist-lib/components/klanten/pricegroups/CustomerPriceGroupSelect.d.ts +4 -0
  15. package/dist-lib/components/klanten/pricegroups/CustomerPriceGroupSelect.d.ts.map +1 -0
  16. package/dist-lib/components/klanten/pricegroups/CustomerPriceGroupSelect.js +47 -0
  17. package/dist-lib/components/klanten/pricegroups/PriceGroupFormPage.d.ts.map +1 -1
  18. package/dist-lib/components/klanten/pricegroups/PriceGroupFormPage.js +2 -1
  19. package/dist-lib/components/klanten/pricegroups/PriceGroupItemPrices.d.ts +5 -0
  20. package/dist-lib/components/klanten/pricegroups/PriceGroupItemPrices.d.ts.map +1 -0
  21. package/dist-lib/components/klanten/pricegroups/PriceGroupItemPrices.js +83 -0
  22. package/dist-lib/index.d.ts +8 -0
  23. package/dist-lib/index.d.ts.map +1 -1
  24. package/dist-lib/index.js +8 -0
  25. package/dist-lib/integrations/supabase/auth-middleware.d.ts +595 -0
  26. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  27. package/dist-lib/integrations/supabase/client.d.ts +595 -0
  28. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  29. package/dist-lib/integrations/supabase/client.server.d.ts +595 -0
  30. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  31. package/dist-lib/integrations/supabase/types.d.ts +597 -0
  32. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  33. package/dist-lib/lib/accounting/twinfield/mapping.js +13 -13
  34. package/dist-lib/lib/accounting/twinfield/worker.functions.d.ts +1785 -0
  35. package/dist-lib/lib/accounting/twinfield/worker.functions.d.ts.map +1 -1
  36. package/dist-lib/lib/accounting.functions.d.ts +1785 -0
  37. package/dist-lib/lib/accounting.functions.d.ts.map +1 -1
  38. package/dist-lib/lib/customer-analytics.functions.d.ts +595 -0
  39. package/dist-lib/lib/customer-analytics.functions.d.ts.map +1 -1
  40. package/dist-lib/lib/customer-assortment.functions.d.ts +26666 -0
  41. package/dist-lib/lib/customer-assortment.functions.d.ts.map +1 -0
  42. package/dist-lib/lib/customer-assortment.functions.js +280 -0
  43. package/dist-lib/lib/customer-notes.functions.d.ts +1190 -0
  44. package/dist-lib/lib/customer-notes.functions.d.ts.map +1 -1
  45. package/dist-lib/lib/customer-revenue.functions.d.ts +595 -0
  46. package/dist-lib/lib/customer-revenue.functions.d.ts.map +1 -1
  47. package/dist-lib/lib/customers.functions.d.ts +5355 -0
  48. package/dist-lib/lib/customers.functions.d.ts.map +1 -1
  49. package/dist-lib/lib/delivery-locations.functions.d.ts +2975 -0
  50. package/dist-lib/lib/delivery-locations.functions.d.ts.map +1 -1
  51. package/dist-lib/lib/errors.d.ts +12 -0
  52. package/dist-lib/lib/errors.d.ts.map +1 -1
  53. package/dist-lib/lib/errors.js +24 -0
  54. package/dist-lib/lib/external-customers.functions.d.ts +2380 -0
  55. package/dist-lib/lib/external-customers.functions.d.ts.map +1 -1
  56. package/dist-lib/lib/floriday-assortment.functions.d.ts +595 -0
  57. package/dist-lib/lib/floriday-assortment.functions.d.ts.map +1 -1
  58. package/dist-lib/lib/floriday-catalog-prices.d.ts +33 -0
  59. package/dist-lib/lib/floriday-catalog-prices.d.ts.map +1 -0
  60. package/dist-lib/lib/floriday-catalog-prices.js +98 -0
  61. package/dist-lib/lib/floriday-discounts.functions.d.ts +1190 -0
  62. package/dist-lib/lib/floriday-discounts.functions.d.ts.map +1 -1
  63. package/dist-lib/lib/floriday-price-import.functions.d.ts +53265 -0
  64. package/dist-lib/lib/floriday-price-import.functions.d.ts.map +1 -0
  65. package/dist-lib/lib/floriday-price-import.functions.js +219 -0
  66. package/dist-lib/lib/floriday-trade-items.functions.d.ts +595 -0
  67. package/dist-lib/lib/floriday-trade-items.functions.d.ts.map +1 -1
  68. package/dist-lib/lib/floriday.server.d.ts +55 -0
  69. package/dist-lib/lib/floriday.server.d.ts.map +1 -0
  70. package/dist-lib/lib/floriday.server.js +765 -0
  71. package/dist-lib/lib/local-discounts.functions.d.ts +4165 -0
  72. package/dist-lib/lib/local-discounts.functions.d.ts.map +1 -1
  73. package/dist-lib/lib/logistics-events.functions.d.ts +595 -0
  74. package/dist-lib/lib/logistics-events.functions.d.ts.map +1 -1
  75. package/dist-lib/lib/logistics-strategy.functions.d.ts +2380 -0
  76. package/dist-lib/lib/logistics-strategy.functions.d.ts.map +1 -1
  77. package/dist-lib/lib/overdue-invoices.functions.d.ts +595 -0
  78. package/dist-lib/lib/overdue-invoices.functions.d.ts.map +1 -1
  79. package/dist-lib/lib/price-groups-local.functions.d.ts +137905 -27
  80. package/dist-lib/lib/price-groups-local.functions.d.ts.map +1 -1
  81. package/dist-lib/lib/price-groups-local.functions.js +145 -0
  82. package/dist-lib/lib/price-groups.functions.d.ts +601 -1
  83. package/dist-lib/lib/price-groups.functions.d.ts.map +1 -1
  84. package/dist-lib/lib/twinfield-adopt.functions.d.ts +1190 -0
  85. package/dist-lib/lib/twinfield-adopt.functions.d.ts.map +1 -1
  86. package/dist-lib/lib/twinfield-ledger.functions.d.ts +595 -0
  87. package/dist-lib/lib/twinfield-ledger.functions.d.ts.map +1 -1
  88. package/dist-lib/lib/twinfield-ledger.server.js +21 -21
  89. package/package.json +1 -1
  90. package/public/flowselections-assets/Klanten/twinfield-logo.svg +217 -217
@@ -0,0 +1,219 @@
1
+ import { createServerFn } from "@tanstack/react-start";
2
+ import { z } from "zod";
3
+ import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
4
+ import { loadFloridayCatalogPrices } from "./floriday-catalog-prices";
5
+ function str(...vals) {
6
+ for (const v of vals) {
7
+ if (typeof v === "string" && v.trim())
8
+ return v.trim();
9
+ if (typeof v === "number" && Number.isFinite(v))
10
+ return String(v);
11
+ }
12
+ return null;
13
+ }
14
+ function num(...vals) {
15
+ for (const v of vals) {
16
+ if (typeof v === "number" && Number.isFinite(v))
17
+ return v;
18
+ if (typeof v === "string" && v.trim() && !Number.isNaN(Number(v)))
19
+ return Number(v);
20
+ }
21
+ return null;
22
+ }
23
+ function itemName(d) {
24
+ const n = d?.tradeItemName ?? d?.name ?? d?.productName;
25
+ if (typeof n === "string")
26
+ return n.trim() || null;
27
+ if (n && typeof n === "object")
28
+ return str(n.nl, n.NL, n.en, n.EN, ...Object.values(n));
29
+ return null;
30
+ }
31
+ async function buildPreview(sb, customerKey, orgId) {
32
+ const { data: member } = await sb
33
+ .from("customer_price_group_members")
34
+ .select("price_group_id")
35
+ .eq("customer_key", customerKey)
36
+ .limit(1)
37
+ .maybeSingle();
38
+ let group = null;
39
+ if (member?.price_group_id) {
40
+ const { data: g } = await sb
41
+ .from("customer_price_groups")
42
+ .select("id, name, currency")
43
+ .eq("id", member.price_group_id)
44
+ .maybeSingle();
45
+ group = g ?? null;
46
+ }
47
+ const floriday = new Map();
48
+ const groupNames = [group?.name ?? null];
49
+ if (orgId) {
50
+ const { data: pgRows } = await sb
51
+ .from("floriday_price_groups_cache")
52
+ .select("data")
53
+ .eq("is_deleted", false);
54
+ for (const row of pgRows ?? []) {
55
+ const d = row?.data ?? {};
56
+ const buyers = [d?.customers, d?.buyerOrganizationIds, d?.customerOrganizationIds, d?.organizationIds]
57
+ .flatMap((a) => (Array.isArray(a) ? a : []));
58
+ const match = buyers.some((v) => (typeof v === "string" ? v : v?.organizationId ?? v?.id) === orgId);
59
+ if (!match)
60
+ continue;
61
+ const label = str(d?.name, d?.priceGroupName, d?.code) ?? "Floriday-prijsgroep";
62
+ groupNames.push(label);
63
+ const lines = [d?.priceGroupLines, d?.tradeItemPrices, d?.lines, d?.priceLines].find(Array.isArray) ?? [];
64
+ for (const line of lines) {
65
+ const id = str(line?.tradeItemId, line?.tradeItem?.tradeItemId, line?.id);
66
+ const price = num(line?.price, line?.amount, line?.unitPrice);
67
+ if (!id || price == null)
68
+ continue;
69
+ floriday.set(id, {
70
+ price,
71
+ currency: str(line?.currency, line?.currencyCode) ?? str(d?.currency),
72
+ label,
73
+ });
74
+ }
75
+ }
76
+ const { data: ctRows } = await sb
77
+ .from("floriday_contracts_cache")
78
+ .select("data")
79
+ .eq("is_deleted", false);
80
+ for (const row of ctRows ?? []) {
81
+ const d = row?.data ?? {};
82
+ const buyer = str(d?.customerOrganizationId, d?.buyerOrganizationId, d?.organizationId);
83
+ if (buyer !== orgId)
84
+ continue;
85
+ const label = `Contract ${str(d?.contractNumber, d?.number, d?.code) ?? ""}`.trim() || "Contract";
86
+ const lines = [d?.contractLines, d?.lines, d?.tradeItems].find(Array.isArray) ?? [];
87
+ for (const line of lines) {
88
+ const id = str(line?.tradeItemId, line?.tradeItem?.tradeItemId, line?.id);
89
+ const price = num(line?.agreedPrice, line?.price, line?.amount, line?.unitPrice);
90
+ if (!id || price == null)
91
+ continue;
92
+ floriday.set(id, {
93
+ price,
94
+ currency: str(line?.currency, line?.currencyCode) ?? str(d?.currency),
95
+ label,
96
+ });
97
+ }
98
+ }
99
+ }
100
+ // Catalogusprijzen (supply lines) — hoofdbron; vult aan waar geen
101
+ // prijsgroep-/contractafspraak staat.
102
+ const catalog = await loadFloridayCatalogPrices(sb, { priceGroupNames: groupNames });
103
+ const catalogCodes = new Map();
104
+ for (const [id, c] of catalog) {
105
+ catalogCodes.set(id, c.supplier_article_code);
106
+ if (!floriday.has(id)) {
107
+ floriday.set(id, { price: c.price, currency: c.currency, label: c.label });
108
+ }
109
+ }
110
+ // Namen bij de artikelen zoeken
111
+ const names = new Map();
112
+ if (floriday.size > 0) {
113
+ const { data: cacheRows } = await sb
114
+ .from("floriday_trade_items_cache")
115
+ .select("floriday_id, data")
116
+ .eq("is_deleted", false);
117
+ for (const row of cacheRows ?? []) {
118
+ const id = String(row?.floriday_id ?? row?.data?.tradeItemId ?? "");
119
+ if (!id)
120
+ continue;
121
+ names.set(id, {
122
+ name: itemName(row?.data) ?? id,
123
+ code: str(row?.data?.supplierArticleCode, row?.data?.tradeItemReference),
124
+ });
125
+ }
126
+ }
127
+ // Bestaande handmatige prijzen in de prijsgroep
128
+ const existing = new Map();
129
+ if (group?.id) {
130
+ const { data: tip } = await sb
131
+ .from("trade_item_prices")
132
+ .select("trade_item_key, price_per_piece")
133
+ .eq("price_group_id", group.id);
134
+ for (const r of tip ?? []) {
135
+ if (r?.trade_item_key == null || r?.price_per_piece == null)
136
+ continue;
137
+ existing.set(String(r.trade_item_key), Number(r.price_per_piece));
138
+ }
139
+ }
140
+ const rows = [];
141
+ for (const [id, fl] of floriday) {
142
+ const current = existing.get(id) ?? null;
143
+ const action = current == null ? "new" : Math.abs(current - fl.price) < 0.0001 ? "unchanged" : "update";
144
+ const meta = names.get(id);
145
+ rows.push({
146
+ trade_item_id: id,
147
+ name: meta?.name ?? id,
148
+ supplier_article_code: meta?.code ?? catalogCodes.get(id) ?? null,
149
+ floriday_price: fl.price,
150
+ currency: fl.currency ?? group?.currency ?? "EUR",
151
+ source_label: fl.label,
152
+ current_price: current,
153
+ action,
154
+ });
155
+ }
156
+ rows.sort((a, b) => a.name.localeCompare(b.name, "nl"));
157
+ return {
158
+ priceGroup: group ? { id: group.id, name: group.name, currency: group.currency ?? "EUR" } : null,
159
+ rows,
160
+ summary: {
161
+ total: rows.length,
162
+ new: rows.filter((r) => r.action === "new").length,
163
+ update: rows.filter((r) => r.action === "update").length,
164
+ unchanged: rows.filter((r) => r.action === "unchanged").length,
165
+ },
166
+ };
167
+ }
168
+ const input = z.object({
169
+ customerKey: z.string().min(1),
170
+ organizationId: z.string().nullable().optional(),
171
+ });
172
+ export const previewFloridayPriceImport = createServerFn({ method: "POST" })
173
+ .middleware([requireSupabaseAuth])
174
+ .inputValidator((raw) => input.parse(raw))
175
+ .handler(async ({ data, context }) => {
176
+ const sb = context.supabase;
177
+ return buildPreview(sb, data.customerKey, data.organizationId ?? null);
178
+ });
179
+ export const applyFloridayPriceImport = createServerFn({ method: "POST" })
180
+ .middleware([requireSupabaseAuth])
181
+ .inputValidator((raw) => input.parse(raw))
182
+ .handler(async ({ data, context }) => {
183
+ const sb = context.supabase;
184
+ const userId = context.userId;
185
+ const preview = await buildPreview(sb, data.customerKey, data.organizationId ?? null);
186
+ if (!preview.priceGroup) {
187
+ throw new Error("Deze klant heeft nog geen prijsgroep. Kies eerst een prijsgroep bij de klant.");
188
+ }
189
+ const todo = preview.rows.filter((r) => r.action !== "unchanged");
190
+ if (todo.length === 0)
191
+ return { imported: 0 };
192
+ for (const r of todo) {
193
+ if (r.current_price == null) {
194
+ const { error } = await sb.from("trade_item_prices").insert({
195
+ user_id: userId,
196
+ price_group_id: preview.priceGroup.id,
197
+ trade_item_key: r.trade_item_id,
198
+ price_per_piece: r.floriday_price,
199
+ currency: r.currency,
200
+ });
201
+ if (error)
202
+ throw new Error(error.message);
203
+ }
204
+ else {
205
+ const { error } = await sb
206
+ .from("trade_item_prices")
207
+ .update({
208
+ price_per_piece: r.floriday_price,
209
+ currency: r.currency,
210
+ updated_at: new Date().toISOString(),
211
+ })
212
+ .eq("price_group_id", preview.priceGroup.id)
213
+ .eq("trade_item_key", r.trade_item_id);
214
+ if (error)
215
+ throw new Error(error.message);
216
+ }
217
+ }
218
+ return { imported: todo.length };
219
+ });