@flowselections/floriday-verkoop-module 1.0.7 → 1.0.9

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 (67) hide show
  1. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts +9 -0
  2. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts.map +1 -0
  3. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.js +26 -0
  4. package/dist-lib/components/verkoop/AnalyticsCards.js +2 -2
  5. package/dist-lib/components/verkoop/CreateOrderPage.d.ts +2 -0
  6. package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -0
  7. package/dist-lib/components/verkoop/CreateOrderPage.js +218 -0
  8. package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts +5 -0
  9. package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts.map +1 -0
  10. package/dist-lib/components/verkoop/DiagnoseConnectionDialog.js +40 -0
  11. package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts +2 -0
  12. package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts.map +1 -0
  13. package/dist-lib/components/verkoop/SalesOrderDetailPage.js +14 -0
  14. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts +6 -0
  15. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -0
  16. package/dist-lib/components/verkoop/SalesOrderDetailView.js +213 -0
  17. package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts +9 -0
  18. package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts.map +1 -0
  19. package/dist-lib/components/verkoop/SalesOrdersFilterPanel.js +62 -0
  20. package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts +13 -0
  21. package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts.map +1 -1
  22. package/dist-lib/components/verkoop/SalesOrdersFilters.js +123 -23
  23. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts +3 -2
  24. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
  25. package/dist-lib/components/verkoop/SalesOrdersTable.js +3 -3
  26. package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
  27. package/dist-lib/components/verkoop/VerkoopOrdersPage.js +125 -33
  28. package/dist-lib/components/verkoop/WeekCalendar.d.ts +6 -0
  29. package/dist-lib/components/verkoop/WeekCalendar.d.ts.map +1 -0
  30. package/dist-lib/components/verkoop/WeekCalendar.js +101 -0
  31. package/dist-lib/index.d.ts +2 -0
  32. package/dist-lib/index.d.ts.map +1 -1
  33. package/dist-lib/index.js +2 -0
  34. package/dist-lib/integrations/supabase/auth-middleware.d.ts +8509 -937
  35. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  36. package/dist-lib/integrations/supabase/client.d.ts +8509 -937
  37. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  38. package/dist-lib/integrations/supabase/client.server.d.ts +8509 -937
  39. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  40. package/dist-lib/integrations/supabase/types.d.ts +8753 -954
  41. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  42. package/dist-lib/integrations/supabase/types.js +20 -1
  43. package/dist-lib/lib/floriday-gateway.server.d.ts +42 -0
  44. package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -0
  45. package/dist-lib/lib/floriday-gateway.server.js +222 -0
  46. package/dist-lib/lib/floriday-public.functions.d.ts +63971 -0
  47. package/dist-lib/lib/floriday-public.functions.d.ts.map +1 -0
  48. package/dist-lib/lib/floriday-public.functions.js +210 -0
  49. package/dist-lib/lib/floriday-sync.d.ts +32 -0
  50. package/dist-lib/lib/floriday-sync.d.ts.map +1 -0
  51. package/dist-lib/lib/floriday-sync.js +116 -0
  52. package/dist-lib/lib/floriday-writes.functions.d.ts +45678 -0
  53. package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -0
  54. package/dist-lib/lib/floriday-writes.functions.js +110 -0
  55. package/dist-lib/lib/salesorders-mapping.d.ts +85 -0
  56. package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -0
  57. package/dist-lib/lib/salesorders-mapping.js +198 -0
  58. package/dist-lib/lib/salesorders.functions.d.ts +27436 -0
  59. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -0
  60. package/dist-lib/lib/salesorders.functions.js +174 -0
  61. package/dist-lib/lib/tradeitems.functions.d.ts +9139 -0
  62. package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -0
  63. package/dist-lib/lib/tradeitems.functions.js +60 -0
  64. package/dist-lib/lib/useSalesOrdersQuery.d.ts +6 -0
  65. package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -0
  66. package/dist-lib/lib/useSalesOrdersQuery.js +129 -0
  67. package/package.json +16 -3
@@ -1,8 +1,27 @@
1
1
  export const Constants = {
2
2
  public: {
3
3
  Enums: {
4
- app_role: ["admin", "manager", "warehouse", "sales", "developer"],
4
+ app_role: [
5
+ "admin",
6
+ "manager",
7
+ "warehouse",
8
+ "sales",
9
+ "developer",
10
+ "receptie",
11
+ "monteur",
12
+ ],
5
13
  exact_env: ["staging", "live"],
14
+ exact_push_status: ["pending", "sent", "error"],
15
+ quote_status: [
16
+ "concept",
17
+ "verzonden",
18
+ "bekeken",
19
+ "in_behandeling",
20
+ "geaccepteerd",
21
+ "afgewezen",
22
+ "verlopen",
23
+ "gearchiveerd",
24
+ ],
6
25
  },
7
26
  },
8
27
  };
@@ -0,0 +1,42 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ import { type FloridayConnectionRow } from "./floriday-sync";
3
+ export type FlorydayEnvironment = "staging" | "live";
4
+ export declare function apiBaseFor(env: FlorydayEnvironment | string | null | undefined): string;
5
+ export declare function pickActiveConnection(supabase: SupabaseClient, env: FlorydayEnvironment | string): Promise<FloridayConnectionRow & {
6
+ gln_code?: string | null;
7
+ }>;
8
+ export interface FlorydayFetchResult<T = unknown> {
9
+ ok: boolean;
10
+ status: number;
11
+ data: T | null;
12
+ rawText: string;
13
+ connection: FloridayConnectionRow;
14
+ }
15
+ /** Low-level fetch with token-refresh + retry-once on 401/403. */
16
+ export declare function florydayFetch<T = unknown>(supabase: SupabaseClient, conn: FloridayConnectionRow, init: {
17
+ method: string;
18
+ path: string;
19
+ body?: unknown;
20
+ }): Promise<FlorydayFetchResult<T>>;
21
+ export interface EnumCheck {
22
+ field: string;
23
+ listName: string;
24
+ }
25
+ export interface FlorydayWriteArgs {
26
+ module: string;
27
+ action: string;
28
+ method: "POST" | "PUT" | "PATCH" | "DELETE";
29
+ path: string;
30
+ referenceId?: string | null;
31
+ body?: unknown;
32
+ validateEnums?: EnumCheck[];
33
+ }
34
+ export interface FlorydayWriteResult {
35
+ ok: boolean;
36
+ status: number;
37
+ data?: any;
38
+ error?: string;
39
+ attemptId?: string;
40
+ }
41
+ export declare function florydayWrite(supabase: SupabaseClient, env: FlorydayEnvironment | string, args: FlorydayWriteArgs, callerUserId?: string | null): Promise<FlorydayWriteResult>;
42
+ //# sourceMappingURL=floriday-gateway.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-gateway.server.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-gateway.server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAsB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEjF,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAAC;AAKrD,wBAAgB,UAAU,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAIvF;AAMD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,mBAAmB,GAAG,MAAM,GAChC,OAAO,CAAC,qBAAqB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAa/D;AA6BD,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC9C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,qBAAqB,CAAC;CACnC;AAED,kEAAkE;AAClE,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAC7C,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,qBAAqB,EAC3B,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CA8CjC;AAGD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AA4DD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAcD,wBAAsB,aAAa,CACjC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,mBAAmB,GAAG,MAAM,EACjC,IAAI,EAAE,iBAAiB,EACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA6D9B"}
@@ -0,0 +1,222 @@
1
+ // Internal Floriday gateway — server-only.
2
+ // One place that owns: connection-selection, token-refresh + retry-on-401,
3
+ // enum validation, idempotency-key, and write-log persistence.
4
+ // Other modules MUST NOT call fetch on Floriday directly; they use the helpers
5
+ // in floriday-writes.functions.ts and floriday-public.functions.ts.
6
+ import { createHash } from "crypto";
7
+ import { FLORIDAY_API_BASES } from "./floriday-sync";
8
+ const AUTH_MODULE_REFRESH_URL = "https://project--vmicscahrnzpmhagztmx.lovable.app/api/public/cron/refresh-floriday-tokens";
9
+ export function apiBaseFor(env) {
10
+ return env === "live" || env === "production" || env === "prod"
11
+ ? FLORIDAY_API_BASES.production
12
+ : FLORIDAY_API_BASES.staging;
13
+ }
14
+ function normalizeEnvKey(env) {
15
+ return env === "live" || env === "production" || env === "prod" ? "production" : "staging";
16
+ }
17
+ export async function pickActiveConnection(supabase, env) {
18
+ const dbEnv = normalizeEnvKey(env);
19
+ const { data, error } = await supabase
20
+ .from("floriday_connections")
21
+ .select("id, environment, access_token, api_key, is_active, gln_code")
22
+ .eq("environment", dbEnv)
23
+ .eq("is_active", true)
24
+ .order("updated_at", { ascending: false })
25
+ .limit(1)
26
+ .maybeSingle();
27
+ if (error)
28
+ throw new Error(`Floriday connectie ophalen mislukt: ${error.message}`);
29
+ if (!data)
30
+ throw new Error(`Geen actieve Floriday connectie voor "${dbEnv}"`);
31
+ return data;
32
+ }
33
+ async function triggerAuthModuleRefresh() {
34
+ try {
35
+ await fetch(AUTH_MODULE_REFRESH_URL, {
36
+ method: "POST",
37
+ headers: { "Content-Type": "application/json" },
38
+ body: "{}",
39
+ });
40
+ }
41
+ catch {
42
+ // best-effort — caller re-reads the token regardless
43
+ }
44
+ }
45
+ async function reloadConnection(supabase, connectionId) {
46
+ const { data, error } = await supabase
47
+ .from("floriday_connections")
48
+ .select("id, environment, access_token, api_key, is_active")
49
+ .eq("id", connectionId)
50
+ .maybeSingle();
51
+ if (error || !data) {
52
+ throw new Error(`Floriday connectie ${connectionId} herladen mislukt: ${error?.message ?? "not found"}`);
53
+ }
54
+ return data;
55
+ }
56
+ /** Low-level fetch with token-refresh + retry-once on 401/403. */
57
+ export async function florydayFetch(supabase, conn, init) {
58
+ let active = conn;
59
+ let lastRes = null;
60
+ let lastText = "";
61
+ for (let attempt = 0; attempt < 2; attempt += 1) {
62
+ if (!active.access_token) {
63
+ await triggerAuthModuleRefresh();
64
+ active = await reloadConnection(supabase, active.id);
65
+ if (!active.access_token) {
66
+ throw new Error(`Floriday connectie ${active.id} heeft geen access_token`);
67
+ }
68
+ }
69
+ const url = `${apiBaseFor(active.environment)}${init.path}`;
70
+ const res = await fetch(url, {
71
+ method: init.method,
72
+ headers: {
73
+ Accept: "application/json",
74
+ ...(init.body !== undefined ? { "Content-Type": "application/json" } : {}),
75
+ Authorization: `Bearer ${active.access_token}`,
76
+ ...(active.api_key ? { "x-api-key": active.api_key } : {}),
77
+ },
78
+ body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
79
+ });
80
+ const text = await res.text();
81
+ lastRes = res;
82
+ lastText = text;
83
+ if (res.ok) {
84
+ const parsed = text ? JSON.parse(text) : null;
85
+ return { ok: true, status: res.status, data: parsed, rawText: text, connection: active };
86
+ }
87
+ if ((res.status === 401 || res.status === 403) && attempt === 0) {
88
+ await triggerAuthModuleRefresh();
89
+ active = await reloadConnection(supabase, active.id);
90
+ continue;
91
+ }
92
+ break;
93
+ }
94
+ return {
95
+ ok: false,
96
+ status: lastRes?.status ?? 0,
97
+ data: null,
98
+ rawText: lastText,
99
+ connection: active,
100
+ };
101
+ }
102
+ async function fetchAllowedValues(supabase, env, listName) {
103
+ const dbEnv = normalizeEnvKey(env) === "production" ? "live" : "staging";
104
+ const { data, error } = await supabase
105
+ .from("floriday_code_lists_cache")
106
+ .select("code")
107
+ .eq("environment", dbEnv)
108
+ .eq("list_name", listName);
109
+ if (error)
110
+ throw new Error(`code-lists lezen faalde: ${error.message}`);
111
+ return (data ?? []).map((r) => String(r.code));
112
+ }
113
+ function readPathValues(body, path) {
114
+ const parts = path.split(".");
115
+ let nodes = [body];
116
+ for (const part of parts) {
117
+ const next = [];
118
+ const isArray = part.endsWith("[]");
119
+ const key = isArray ? part.slice(0, -2) : part;
120
+ for (const node of nodes) {
121
+ if (node == null || typeof node !== "object")
122
+ continue;
123
+ const v = node[key];
124
+ if (v === undefined)
125
+ continue;
126
+ if (isArray && Array.isArray(v))
127
+ next.push(...v);
128
+ else
129
+ next.push(v);
130
+ }
131
+ nodes = next;
132
+ }
133
+ return nodes;
134
+ }
135
+ async function runEnumChecks(supabase, env, body, checks) {
136
+ for (const check of checks) {
137
+ const values = readPathValues(body, check.field).filter((v) => v != null);
138
+ if (values.length === 0)
139
+ continue;
140
+ const allowed = await fetchAllowedValues(supabase, env, check.listName);
141
+ if (allowed.length === 0)
142
+ continue; // list not cached yet → skip
143
+ const bad = values.find((v) => !allowed.includes(String(v)));
144
+ if (bad !== undefined) {
145
+ return {
146
+ ok: false,
147
+ error: `Veld "${check.field}" heeft ongeldige waarde "${bad}" voor lijst "${check.listName}"`,
148
+ allowed,
149
+ };
150
+ }
151
+ }
152
+ return { ok: true };
153
+ }
154
+ function computeIdempotencyKey(args) {
155
+ const h = createHash("sha256");
156
+ h.update(args.module);
157
+ h.update("|");
158
+ h.update(args.action);
159
+ h.update("|");
160
+ h.update(args.referenceId ?? "");
161
+ h.update("|");
162
+ h.update(JSON.stringify(args.body ?? null));
163
+ return h.digest("hex");
164
+ }
165
+ export async function florydayWrite(supabase, env, args, callerUserId) {
166
+ const idempotencyKey = computeIdempotencyKey(args);
167
+ // 1) Local pre-flight enum validation (saves a Floriday roundtrip on mismatches).
168
+ if (args.validateEnums && args.validateEnums.length > 0) {
169
+ const v = await runEnumChecks(supabase, env, args.body, args.validateEnums);
170
+ if (!v.ok) {
171
+ const ins = await supabase.from("floriday_write_log")
172
+ .insert({
173
+ module: args.module,
174
+ action: args.action,
175
+ resource: args.path,
176
+ floriday_id: args.referenceId ?? null,
177
+ idempotency_key: idempotencyKey,
178
+ request: { body: args.body ?? null, env },
179
+ response: { allowed: v.allowed ?? null },
180
+ http_status: 0,
181
+ ok: false,
182
+ error: v.error,
183
+ user_id: callerUserId ?? null,
184
+ })
185
+ .select("id")
186
+ .maybeSingle();
187
+ return { ok: false, status: 0, error: v.error, attemptId: ins.data?.id };
188
+ }
189
+ }
190
+ const conn = await pickActiveConnection(supabase, env);
191
+ const res = await florydayFetch(supabase, conn, {
192
+ method: args.method,
193
+ path: args.path,
194
+ body: args.body,
195
+ });
196
+ const ins = await supabase.from("floriday_write_log")
197
+ .insert({
198
+ connection_id: conn.id,
199
+ module: args.module,
200
+ action: args.action,
201
+ resource: args.path,
202
+ floriday_id: args.referenceId ?? null,
203
+ idempotency_key: idempotencyKey,
204
+ request: { body: args.body ?? null, env, method: args.method },
205
+ response: res.rawText ? { body: res.rawText.slice(0, 32000) } : null,
206
+ http_status: res.status,
207
+ ok: res.ok,
208
+ error: res.ok ? null : res.rawText.slice(0, 500),
209
+ user_id: callerUserId ?? null,
210
+ })
211
+ .select("id")
212
+ .maybeSingle();
213
+ if (!res.ok) {
214
+ return {
215
+ ok: false,
216
+ status: res.status,
217
+ error: res.rawText ? res.rawText.slice(0, 400) : `HTTP ${res.status}`,
218
+ attemptId: ins.data?.id,
219
+ };
220
+ }
221
+ return { ok: true, status: res.status, data: res.data, attemptId: ins.data?.id };
222
+ }