@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
@@ -24,6 +24,36 @@ const DEFAULT_VALIDATE_ENUMS = [
24
24
  { field: "loadCarrierType", listName: "SupplyLoadCarrierType" },
25
25
  { field: "country", listName: "Country" },
26
26
  ];
27
+ /**
28
+ * Parseer Floriday's "Missing characteristics" 400 detail naar een lijst
29
+ * VBN characteristic-codes (S01, A02, L11, …). Ondersteunt beide vormen:
30
+ * "Missing characteristics are: Potmaat (S01), Min planthoogte (S02)"
31
+ * "Missing characteristics are: S01, S02"
32
+ * Retourneert lege array als er geen match is.
33
+ */
34
+ function parseMissingCharacteristicCodes(message) {
35
+ const idx = message.toLowerCase().indexOf("missing characteristics are:");
36
+ if (idx < 0)
37
+ return [];
38
+ const tail = message.slice(idx + "missing characteristics are:".length);
39
+ const codes = new Set();
40
+ const re = /\b([A-Z]\d{1,4})\b/g;
41
+ let m;
42
+ while ((m = re.exec(tail)) !== null)
43
+ codes.add(m[1].toUpperCase());
44
+ return Array.from(codes);
45
+ }
46
+ /**
47
+ * Prefix waar de wizard op parseert om exact te weten welke codes Floriday
48
+ * miste. Formaat: `MISSING_CHARACTERISTICS:S01,S02:<originele detail>`.
49
+ */
50
+ const MISSING_PREFIX = "MISSING_CHARACTERISTICS";
51
+ export function isMissingCharacteristicsError(msg) {
52
+ const m = msg.match(new RegExp(`${MISSING_PREFIX}:([A-Z0-9,]+):`));
53
+ if (!m)
54
+ return [];
55
+ return m[1].split(",").filter(Boolean);
56
+ }
27
57
  async function safe(label, fn) {
28
58
  try {
29
59
  return await fn();
@@ -33,8 +63,13 @@ async function safe(label, fn) {
33
63
  const text = await e.text().catch(() => "");
34
64
  throw new Error(`${label}: ${e.status} ${text || e.statusText}`);
35
65
  }
36
- if (e instanceof Error)
66
+ if (e instanceof Error) {
67
+ const codes = parseMissingCharacteristicCodes(e.message);
68
+ if (codes.length > 0) {
69
+ throw new Error(`${label}: ${MISSING_PREFIX}:${codes.join(",")}: ${e.message}`);
70
+ }
37
71
  throw new Error(`${label}: ${e.message}`);
72
+ }
38
73
  throw new Error(`${label}: ${String(e)}`);
39
74
  }
40
75
  }
@@ -0,0 +1,43 @@
1
+ import type { FloridayPriceGroup } from "../hooks/useFloridayPriceGroups";
2
+ export interface TradeItemPriceRow {
3
+ price_group_id: string | null;
4
+ price_per_piece: number;
5
+ currency: string;
6
+ supply_line_id: string | null;
7
+ last_pushed_at: string | null;
8
+ last_push_error: string | null;
9
+ }
10
+ export declare function readTradeItemPrices(tradeItemKey: string): Promise<TradeItemPriceRow[]>;
11
+ export declare function readTradeItemPricesBulk(tradeItemKeys: string[]): Promise<Map<string, TradeItemPriceRow[]>>;
12
+ export interface SyncPricesInput {
13
+ tradeItemId: string;
14
+ tradeItemKey: string;
15
+ availableQuantity: number;
16
+ currency?: string;
17
+ periodStart?: string;
18
+ /** Basisprijs (0 of leeg = geen basisprijs pushen). */
19
+ basePricePerPiece: number;
20
+ /** Prijs per Floriday-prijsgroepId. Leeg / 0 = niet publiceren voor die groep. */
21
+ pricesByGroupId: Record<string, number>;
22
+ /** Lijst van beschikbare prijsgroepen (voor customerOrganizationIds). */
23
+ priceGroups: FloridayPriceGroup[];
24
+ packingConfigurationId?: string;
25
+ }
26
+ export interface SyncPricesResult {
27
+ basePriceOk: boolean;
28
+ baseError?: string;
29
+ groupResults: Array<{
30
+ priceGroupId: string;
31
+ name: string;
32
+ ok: boolean;
33
+ error?: string;
34
+ supplyLineId?: string;
35
+ }>;
36
+ }
37
+ /**
38
+ * Push basisprijs + alle prijsgroep-prijzen naar Floriday en spiegel het
39
+ * resultaat naar `trade_item_prices`. Werkt best-effort: één falende call
40
+ * blokkeert de andere niet.
41
+ */
42
+ export declare function syncTradeItemPrices(input: SyncPricesInput): Promise<SyncPricesResult>;
43
+ //# sourceMappingURL=trade-item-prices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trade-item-prices.d.ts","sourceRoot":"","sources":["../../src/lib/trade-item-prices.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAU9B;AAED,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAiB3C;AA6DD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kFAAkF;IAClF,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,yEAAyE;IACzE,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,KAAK,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACJ;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAwI3B"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Lokale spiegel + Floriday-sync voor de basisprijs en prijzen per prijsgroep
3
+ * van een trade-item. `price_group_id = NULL` betekent basisprijs.
4
+ *
5
+ * De push naar Floriday loopt via:
6
+ * - Basisprijs → `weekly-base-supply` (via `gatewaySupplyLineFn` met
7
+ * supplyType `CATALOG_PRICE`).
8
+ * - Prijs per prijsgroep → `weekly-supply-lines` (supplyType
9
+ * `WEEKLY_SUPPLY_LINE`, met de `customerOrganizationIds` van de groep).
10
+ *
11
+ * Elk succesvolle push updatet `last_pushed_at`; falen zet `last_push_error`
12
+ * maar rollt de lokale rij niet terug.
13
+ */
14
+ import { supabase } from "../integrations/supabase/client";
15
+ import { postSupplyLine } from "./floriday-supply-line";
16
+ export async function readTradeItemPrices(tradeItemKey) {
17
+ const userRes = await supabase.auth.getUser();
18
+ const userId = userRes.data.user?.id;
19
+ if (!userId)
20
+ return [];
21
+ const { data } = await supabase
22
+ .from("trade_item_prices")
23
+ .select("price_group_id,price_per_piece,currency,supply_line_id,last_pushed_at,last_push_error")
24
+ .eq("user_id", userId)
25
+ .eq("trade_item_key", tradeItemKey);
26
+ return (data ?? []);
27
+ }
28
+ export async function readTradeItemPricesBulk(tradeItemKeys) {
29
+ const map = new Map();
30
+ if (tradeItemKeys.length === 0)
31
+ return map;
32
+ const userRes = await supabase.auth.getUser();
33
+ const userId = userRes.data.user?.id;
34
+ if (!userId)
35
+ return map;
36
+ const { data } = await supabase
37
+ .from("trade_item_prices")
38
+ .select("trade_item_key,price_group_id,price_per_piece,currency,supply_line_id,last_pushed_at,last_push_error")
39
+ .eq("user_id", userId)
40
+ .in("trade_item_key", tradeItemKeys);
41
+ for (const row of (data ?? [])) {
42
+ const arr = map.get(row.trade_item_key) ?? [];
43
+ arr.push(row);
44
+ map.set(row.trade_item_key, arr);
45
+ }
46
+ return map;
47
+ }
48
+ async function upsertLocalPrice(params) {
49
+ const row = {
50
+ user_id: params.userId,
51
+ trade_item_key: params.tradeItemKey,
52
+ price_group_id: params.priceGroupId,
53
+ price_per_piece: params.pricePerPiece,
54
+ currency: params.currency ?? "EUR",
55
+ supply_line_id: params.supplyLineId ?? null,
56
+ last_pushed_at: params.lastPushedAt ?? null,
57
+ last_push_error: params.lastPushError ?? null,
58
+ };
59
+ // Er zijn twee partial unique indexes (base vs. groep) — geen combined onConflict.
60
+ // Doe dus expliciet find-or-insert.
61
+ const query = supabase
62
+ .from("trade_item_prices")
63
+ .select("id")
64
+ .eq("user_id", params.userId)
65
+ .eq("trade_item_key", params.tradeItemKey);
66
+ const filtered = params.priceGroupId === null
67
+ ? query.is("price_group_id", null)
68
+ : query.eq("price_group_id", params.priceGroupId);
69
+ const { data: existing } = await filtered.maybeSingle();
70
+ if (existing?.id) {
71
+ await supabase
72
+ .from("trade_item_prices")
73
+ .update(row)
74
+ .eq("id", existing.id);
75
+ }
76
+ else {
77
+ await supabase.from("trade_item_prices").insert(row);
78
+ }
79
+ }
80
+ async function deleteLocalPrice(userId, tradeItemKey, priceGroupId) {
81
+ const query = supabase
82
+ .from("trade_item_prices")
83
+ .delete()
84
+ .eq("user_id", userId)
85
+ .eq("trade_item_key", tradeItemKey);
86
+ const filtered = priceGroupId === null
87
+ ? query.is("price_group_id", null)
88
+ : query.eq("price_group_id", priceGroupId);
89
+ await filtered;
90
+ }
91
+ /**
92
+ * Push basisprijs + alle prijsgroep-prijzen naar Floriday en spiegel het
93
+ * resultaat naar `trade_item_prices`. Werkt best-effort: één falende call
94
+ * blokkeert de andere niet.
95
+ */
96
+ export async function syncTradeItemPrices(input) {
97
+ const userRes = await supabase.auth.getUser();
98
+ const userId = userRes.data.user?.id;
99
+ if (!userId)
100
+ throw new Error("Niet ingelogd");
101
+ const result = { basePriceOk: false, groupResults: [] };
102
+ // -------- Basisprijs -----------------------------------------------------
103
+ if (input.basePricePerPiece > 0) {
104
+ try {
105
+ await postSupplyLine({
106
+ tradeItemId: input.tradeItemId,
107
+ pricePerPiece: input.basePricePerPiece,
108
+ availableQuantity: input.availableQuantity,
109
+ packingConfigurationId: input.packingConfigurationId,
110
+ supplyType: "CATALOG_PRICE",
111
+ currency: input.currency,
112
+ periodStart: input.periodStart,
113
+ });
114
+ await upsertLocalPrice({
115
+ userId,
116
+ tradeItemKey: input.tradeItemKey,
117
+ priceGroupId: null,
118
+ pricePerPiece: input.basePricePerPiece,
119
+ currency: input.currency,
120
+ lastPushedAt: new Date().toISOString(),
121
+ });
122
+ result.basePriceOk = true;
123
+ }
124
+ catch (e) {
125
+ const msg = String(e?.message ?? e);
126
+ result.baseError = msg;
127
+ await upsertLocalPrice({
128
+ userId,
129
+ tradeItemKey: input.tradeItemKey,
130
+ priceGroupId: null,
131
+ pricePerPiece: input.basePricePerPiece,
132
+ currency: input.currency,
133
+ lastPushError: msg,
134
+ });
135
+ }
136
+ }
137
+ else {
138
+ // Basisprijs verwijderd — lokaal opruimen (Floriday zelf laat je niet
139
+ // ongedaan maken zonder aparte "remove"-call; die is niet in scope).
140
+ await deleteLocalPrice(userId, input.tradeItemKey, null);
141
+ }
142
+ // -------- Per prijsgroep -------------------------------------------------
143
+ const existingRows = await readTradeItemPrices(input.tradeItemKey);
144
+ const existingByGroup = new Map();
145
+ for (const row of existingRows) {
146
+ if (row.price_group_id)
147
+ existingByGroup.set(row.price_group_id, row);
148
+ }
149
+ for (const group of input.priceGroups) {
150
+ const nextPrice = Number(input.pricesByGroupId[group.id] ?? 0);
151
+ const existing = existingByGroup.get(group.id);
152
+ if (!(nextPrice > 0)) {
153
+ // Was gezet, nu leeggemaakt → lokaal opruimen.
154
+ // (De weekly-supply-line in Floriday zelf blijft staan tot de gebruiker
155
+ // via de Floriday-UI de regel verwijdert; dat is een bewuste keuze
156
+ // omdat DELETE via de API buiten scope van deze wijziging valt.)
157
+ if (existing) {
158
+ await deleteLocalPrice(userId, input.tradeItemKey, group.id);
159
+ }
160
+ continue;
161
+ }
162
+ if (group.customerOrganizationIds.length === 0) {
163
+ const msg = "Prijsgroep heeft geen gekoppelde klanten in Floriday";
164
+ result.groupResults.push({
165
+ priceGroupId: group.id,
166
+ name: group.name,
167
+ ok: false,
168
+ error: msg,
169
+ });
170
+ await upsertLocalPrice({
171
+ userId,
172
+ tradeItemKey: input.tradeItemKey,
173
+ priceGroupId: group.id,
174
+ pricePerPiece: nextPrice,
175
+ currency: group.currency,
176
+ supplyLineId: existing?.supply_line_id ?? null,
177
+ lastPushError: msg,
178
+ });
179
+ continue;
180
+ }
181
+ try {
182
+ const supplyRes = await postSupplyLine({
183
+ tradeItemId: input.tradeItemId,
184
+ pricePerPiece: nextPrice,
185
+ availableQuantity: input.availableQuantity,
186
+ packingConfigurationId: input.packingConfigurationId,
187
+ supplyType: "WEEKLY_SUPPLY_LINE",
188
+ currency: group.currency,
189
+ periodStart: input.periodStart,
190
+ supplyLineId: existing?.supply_line_id ?? undefined,
191
+ customerOrganizationIds: group.customerOrganizationIds,
192
+ });
193
+ await upsertLocalPrice({
194
+ userId,
195
+ tradeItemKey: input.tradeItemKey,
196
+ priceGroupId: group.id,
197
+ pricePerPiece: nextPrice,
198
+ currency: group.currency,
199
+ supplyLineId: supplyRes.supplyLineId ?? existing?.supply_line_id ?? null,
200
+ lastPushedAt: new Date().toISOString(),
201
+ });
202
+ result.groupResults.push({
203
+ priceGroupId: group.id,
204
+ name: group.name,
205
+ ok: true,
206
+ supplyLineId: supplyRes.supplyLineId,
207
+ });
208
+ }
209
+ catch (e) {
210
+ const msg = String(e?.message ?? e);
211
+ await upsertLocalPrice({
212
+ userId,
213
+ tradeItemKey: input.tradeItemKey,
214
+ priceGroupId: group.id,
215
+ pricePerPiece: nextPrice,
216
+ currency: group.currency,
217
+ supplyLineId: existing?.supply_line_id ?? null,
218
+ lastPushError: msg,
219
+ });
220
+ result.groupResults.push({
221
+ priceGroupId: group.id,
222
+ name: group.name,
223
+ ok: false,
224
+ error: msg,
225
+ });
226
+ }
227
+ }
228
+ return result;
229
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/floriday-voorraad",
3
- "version": "1.0.22",
3
+ "version": "1.0.26",
4
4
  "sideEffects": false,
5
5
  "type": "module",
6
6
  "main": "./dist-lib/index.js",
@@ -44,8 +44,8 @@
44
44
  "devDependencies": {
45
45
  "@cloudflare/vite-plugin": "^1.25.5",
46
46
  "@eslint/js": "^9.32.0",
47
- "@flowselections/core": "1.0.12",
48
- "@lovable.dev/vite-tanstack-config": "2.7.1",
47
+ "@flowselections/core": "1.0.16",
48
+ "@lovable.dev/vite-tanstack-config": "2.7.7",
49
49
  "@rsbuild/core": "^1.0.0",
50
50
  "@tailwindcss/vite": "^4.2.1",
51
51
  "@tanstack/router-plugin": "^1.167.10",