@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.
- package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts +9 -0
- package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts.map +1 -0
- package/dist-lib/components/floriday/FlorydaySyncHealthBanner.js +26 -0
- package/dist-lib/components/verkoop/AnalyticsCards.js +2 -2
- package/dist-lib/components/verkoop/CreateOrderPage.d.ts +2 -0
- package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -0
- package/dist-lib/components/verkoop/CreateOrderPage.js +218 -0
- package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts +5 -0
- package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts.map +1 -0
- package/dist-lib/components/verkoop/DiagnoseConnectionDialog.js +40 -0
- package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts +2 -0
- package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts.map +1 -0
- package/dist-lib/components/verkoop/SalesOrderDetailPage.js +14 -0
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts +6 -0
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -0
- package/dist-lib/components/verkoop/SalesOrderDetailView.js +213 -0
- package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts +9 -0
- package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts.map +1 -0
- package/dist-lib/components/verkoop/SalesOrdersFilterPanel.js +62 -0
- package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts +13 -0
- package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersFilters.js +123 -23
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts +3 -2
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.js +3 -3
- package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/VerkoopOrdersPage.js +125 -33
- package/dist-lib/components/verkoop/WeekCalendar.d.ts +6 -0
- package/dist-lib/components/verkoop/WeekCalendar.d.ts.map +1 -0
- package/dist-lib/components/verkoop/WeekCalendar.js +101 -0
- package/dist-lib/index.d.ts +2 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +2 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +8509 -937
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +8509 -937
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +8509 -937
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +8753 -954
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +20 -1
- package/dist-lib/lib/floriday-gateway.server.d.ts +42 -0
- package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-gateway.server.js +222 -0
- package/dist-lib/lib/floriday-public.functions.d.ts +63971 -0
- package/dist-lib/lib/floriday-public.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-public.functions.js +210 -0
- package/dist-lib/lib/floriday-sync.d.ts +32 -0
- package/dist-lib/lib/floriday-sync.d.ts.map +1 -0
- package/dist-lib/lib/floriday-sync.js +116 -0
- package/dist-lib/lib/floriday-writes.functions.d.ts +45678 -0
- package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-writes.functions.js +110 -0
- package/dist-lib/lib/salesorders-mapping.d.ts +85 -0
- package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -0
- package/dist-lib/lib/salesorders-mapping.js +198 -0
- package/dist-lib/lib/salesorders.functions.d.ts +27436 -0
- package/dist-lib/lib/salesorders.functions.d.ts.map +1 -0
- package/dist-lib/lib/salesorders.functions.js +174 -0
- package/dist-lib/lib/tradeitems.functions.d.ts +9139 -0
- package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -0
- package/dist-lib/lib/tradeitems.functions.js +60 -0
- package/dist-lib/lib/useSalesOrdersQuery.d.ts +6 -0
- package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -0
- package/dist-lib/lib/useSalesOrdersQuery.js +129 -0
- package/package.json +16 -3
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// Public-read helpers (server functions) — used by all other modules.
|
|
2
|
+
// Reads gaan via de lokale Supabase-cache; geen directe Floriday API-calls.
|
|
3
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
|
|
6
|
+
const EnvSchema = z.enum(["staging", "live"]);
|
|
7
|
+
// Toegestane cache-entities en hun tabel-mapping.
|
|
8
|
+
const ENTITY_TABLE = {
|
|
9
|
+
"sales-orders": "floriday_salesorders_cache",
|
|
10
|
+
"trade-items": "floriday_trade_items_cache",
|
|
11
|
+
"customer-organizations": "floriday_customers_cache",
|
|
12
|
+
carriers: "floriday_carriers_cache",
|
|
13
|
+
"fulfillment-orders": "floriday_fulfillment_orders_cache",
|
|
14
|
+
"delivery-orders": "floriday_delivery_orders_cache",
|
|
15
|
+
"clock-supplies": "floriday_clock_supplies_cache",
|
|
16
|
+
"clock-presales": "floriday_clock_presales_cache",
|
|
17
|
+
contracts: "floriday_contracts_cache",
|
|
18
|
+
"blanket-orders": "floriday_blanket_orders_cache",
|
|
19
|
+
warehouses: "floriday_warehouses_cache",
|
|
20
|
+
"delivery-locations": "floriday_delivery_locations_cache",
|
|
21
|
+
packings: "floriday_packings_cache",
|
|
22
|
+
connections: "floriday_connections_cache",
|
|
23
|
+
"customer-stickers": "floriday_customer_stickers_cache",
|
|
24
|
+
"additional-services": "floriday_additional_services_cache",
|
|
25
|
+
"commercial-service-types": "floriday_commercial_service_types_cache",
|
|
26
|
+
collections: "floriday_collections_cache",
|
|
27
|
+
"price-groups": "floriday_price_groups_cache",
|
|
28
|
+
"delivery-condition-sets": "floriday_delivery_condition_sets_cache",
|
|
29
|
+
"sales-strategies": "floriday_sales_strategies_cache",
|
|
30
|
+
"base-items": "floriday_base_items_cache",
|
|
31
|
+
"contract-trade-item-groups": "floriday_contract_trade_item_groups_cache",
|
|
32
|
+
};
|
|
33
|
+
const CachedListSchema = z.object({
|
|
34
|
+
environment: EnvSchema,
|
|
35
|
+
entity: z.string().min(1),
|
|
36
|
+
limit: z.number().int().positive().max(5000).optional(),
|
|
37
|
+
});
|
|
38
|
+
export const getFlorydayCachedList = createServerFn({ method: "POST" })
|
|
39
|
+
.middleware([requireSupabaseAuth])
|
|
40
|
+
.inputValidator((d) => CachedListSchema.parse(d))
|
|
41
|
+
.handler(async ({ data, context }) => {
|
|
42
|
+
const table = ENTITY_TABLE[data.entity];
|
|
43
|
+
if (!table) {
|
|
44
|
+
throw new Error(`Onbekende entity "${data.entity}" — toegestane waarden: ${Object.keys(ENTITY_TABLE).join(", ")}`);
|
|
45
|
+
}
|
|
46
|
+
const limit = data.limit ?? 1000;
|
|
47
|
+
let q = context.supabase.from(table).select("*").limit(limit);
|
|
48
|
+
// Most cache-tables have an is_deleted column; filter when present.
|
|
49
|
+
const hasIsDeleted = [
|
|
50
|
+
"floriday_salesorders_cache",
|
|
51
|
+
"floriday_trade_items_cache",
|
|
52
|
+
].includes(table);
|
|
53
|
+
if (hasIsDeleted)
|
|
54
|
+
q = q.eq("is_deleted", false);
|
|
55
|
+
const { data: rows, error } = await q;
|
|
56
|
+
if (error)
|
|
57
|
+
throw new Error(`${table} lezen faalde: ${error.message}`);
|
|
58
|
+
return { entity: data.entity, rows: rows ?? [] };
|
|
59
|
+
});
|
|
60
|
+
const CodeListSchema = z.object({
|
|
61
|
+
environment: EnvSchema,
|
|
62
|
+
listName: z.string().min(1),
|
|
63
|
+
});
|
|
64
|
+
export const getFlorydayCodeList = createServerFn({ method: "POST" })
|
|
65
|
+
.middleware([requireSupabaseAuth])
|
|
66
|
+
.inputValidator((d) => CodeListSchema.parse(d))
|
|
67
|
+
.handler(async ({ data, context }) => {
|
|
68
|
+
const { data: rows, error } = await context.supabase
|
|
69
|
+
.from("floriday_code_lists_cache")
|
|
70
|
+
.select("code, label, payload")
|
|
71
|
+
.eq("environment", data.environment)
|
|
72
|
+
.eq("list_name", data.listName);
|
|
73
|
+
if (error)
|
|
74
|
+
throw new Error(`code-list lezen faalde: ${error.message}`);
|
|
75
|
+
return { listName: data.listName, items: rows ?? [] };
|
|
76
|
+
});
|
|
77
|
+
export const getFlorydayAllowedValues = createServerFn({ method: "POST" })
|
|
78
|
+
.middleware([requireSupabaseAuth])
|
|
79
|
+
.inputValidator((d) => CodeListSchema.parse(d))
|
|
80
|
+
.handler(async ({ data, context }) => {
|
|
81
|
+
const { data: rows, error } = await context.supabase
|
|
82
|
+
.from("floriday_code_lists_cache")
|
|
83
|
+
.select("code")
|
|
84
|
+
.eq("environment", data.environment)
|
|
85
|
+
.eq("list_name", data.listName);
|
|
86
|
+
if (error)
|
|
87
|
+
throw new Error(`allowed-values lezen faalde: ${error.message}`);
|
|
88
|
+
return { listName: data.listName, values: (rows ?? []).map((r) => String(r.code)) };
|
|
89
|
+
});
|
|
90
|
+
const AssertSchema = z.object({
|
|
91
|
+
environment: EnvSchema,
|
|
92
|
+
listName: z.string().min(1),
|
|
93
|
+
value: z.string(),
|
|
94
|
+
});
|
|
95
|
+
export const assertFlorydayValue = createServerFn({ method: "POST" })
|
|
96
|
+
.middleware([requireSupabaseAuth])
|
|
97
|
+
.inputValidator((d) => AssertSchema.parse(d))
|
|
98
|
+
.handler(async ({ data, context }) => {
|
|
99
|
+
const { data: rows, error } = await context.supabase
|
|
100
|
+
.from("floriday_code_lists_cache")
|
|
101
|
+
.select("code")
|
|
102
|
+
.eq("environment", data.environment)
|
|
103
|
+
.eq("list_name", data.listName);
|
|
104
|
+
if (error)
|
|
105
|
+
throw new Error(`assert lezen faalde: ${error.message}`);
|
|
106
|
+
const allowed = (rows ?? []).map((r) => String(r.code));
|
|
107
|
+
if (allowed.length === 0) {
|
|
108
|
+
return { ok: false, error: `Lijst "${data.listName}" leeg of niet gecached`, allowed };
|
|
109
|
+
}
|
|
110
|
+
if (allowed.includes(data.value))
|
|
111
|
+
return { ok: true, allowed };
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
error: `Waarde "${data.value}" niet toegestaan in "${data.listName}"`,
|
|
115
|
+
allowed,
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
const VbnSchema = z.object({
|
|
119
|
+
environment: EnvSchema,
|
|
120
|
+
code: z.string().optional(),
|
|
121
|
+
search: z.string().optional(),
|
|
122
|
+
});
|
|
123
|
+
export const getFlorydayVbnProduct = createServerFn({ method: "POST" })
|
|
124
|
+
.middleware([requireSupabaseAuth])
|
|
125
|
+
.inputValidator((d) => VbnSchema.parse(d))
|
|
126
|
+
.handler(async ({ data, context }) => {
|
|
127
|
+
let q = context.supabase
|
|
128
|
+
.from("floriday_code_lists_cache")
|
|
129
|
+
.select("code, label, payload")
|
|
130
|
+
.eq("environment", data.environment)
|
|
131
|
+
.eq("list_name", "vbn-products");
|
|
132
|
+
if (data.code)
|
|
133
|
+
q = q.eq("code", data.code);
|
|
134
|
+
else if (data.search)
|
|
135
|
+
q = q.ilike("label", `%${data.search}%`).limit(50);
|
|
136
|
+
else
|
|
137
|
+
q = q.limit(50);
|
|
138
|
+
const { data: rows, error } = await q;
|
|
139
|
+
if (error)
|
|
140
|
+
throw new Error(`vbn-products lezen faalde: ${error.message}`);
|
|
141
|
+
return { items: rows ?? [] };
|
|
142
|
+
});
|
|
143
|
+
const SchemaArgs = z.object({
|
|
144
|
+
resource: z.string().min(1),
|
|
145
|
+
version: z.string().optional(),
|
|
146
|
+
});
|
|
147
|
+
export const getFlorydayResourceSchema = createServerFn({ method: "POST" })
|
|
148
|
+
.middleware([requireSupabaseAuth])
|
|
149
|
+
.inputValidator((d) => SchemaArgs.parse(d))
|
|
150
|
+
.handler(async ({ data, context }) => {
|
|
151
|
+
let q = context.supabase
|
|
152
|
+
.from("floriday_resource_schemas")
|
|
153
|
+
.select("resource, version, schema, enums, fetched_at")
|
|
154
|
+
.eq("resource", data.resource);
|
|
155
|
+
if (data.version)
|
|
156
|
+
q = q.eq("version", data.version);
|
|
157
|
+
const { data: rows, error } = await q.order("fetched_at", { ascending: false }).limit(1);
|
|
158
|
+
if (error)
|
|
159
|
+
throw new Error(`resource-schema lezen faalde: ${error.message}`);
|
|
160
|
+
return rows?.[0] ?? null;
|
|
161
|
+
});
|
|
162
|
+
const SyncHealthSchema = z.object({
|
|
163
|
+
environment: EnvSchema,
|
|
164
|
+
resources: z.array(z.string()).min(1),
|
|
165
|
+
});
|
|
166
|
+
// Voor de FlorydaySyncHealthBanner — leest sync-state voor de actieve connectie
|
|
167
|
+
// van de gevraagde environment en geeft per resource laatste sync-info terug.
|
|
168
|
+
export const getFlorydaySyncHealth = createServerFn({ method: "POST" })
|
|
169
|
+
.middleware([requireSupabaseAuth])
|
|
170
|
+
.inputValidator((d) => SyncHealthSchema.parse(d))
|
|
171
|
+
.handler(async ({ data, context }) => {
|
|
172
|
+
const dbEnv = data.environment === "live" ? "production" : "staging";
|
|
173
|
+
const { data: conns } = await context.supabase
|
|
174
|
+
.from("floriday_connections")
|
|
175
|
+
.select("id")
|
|
176
|
+
.eq("environment", dbEnv)
|
|
177
|
+
.eq("is_active", true)
|
|
178
|
+
.limit(1);
|
|
179
|
+
const connectionId = (conns ?? [])[0]?.id ?? null;
|
|
180
|
+
if (!connectionId) {
|
|
181
|
+
return { connectionId: null, resources: [] };
|
|
182
|
+
}
|
|
183
|
+
// Map resource → entity_type used in floriday_sync_state.
|
|
184
|
+
const RES_TO_ENTITY = {
|
|
185
|
+
"sales-orders": "salesorders",
|
|
186
|
+
"trade-items": "tradeitems",
|
|
187
|
+
"customer-organizations": "customers",
|
|
188
|
+
"fulfillment-orders": "fulfillment-orders",
|
|
189
|
+
};
|
|
190
|
+
const { data: rows } = await context.supabase
|
|
191
|
+
.from("floriday_sync_state")
|
|
192
|
+
.select("entity_type, last_sequence_number, last_synced_at, last_success_at, last_error")
|
|
193
|
+
.eq("connection_id", connectionId);
|
|
194
|
+
const stateByEntity = new Map((rows ?? []).map((r) => [String(r.entity_type), r]));
|
|
195
|
+
return {
|
|
196
|
+
connectionId,
|
|
197
|
+
resources: data.resources.map((res) => {
|
|
198
|
+
const entity = RES_TO_ENTITY[res] ?? res;
|
|
199
|
+
const s = stateByEntity.get(entity) ?? null;
|
|
200
|
+
return {
|
|
201
|
+
resource: res,
|
|
202
|
+
entityType: entity,
|
|
203
|
+
lastSyncedAt: s?.last_synced_at ?? null,
|
|
204
|
+
lastSuccessAt: s?.last_success_at ?? null,
|
|
205
|
+
lastSequenceNumber: s?.last_sequence_number ?? null,
|
|
206
|
+
lastError: s?.last_error ?? null,
|
|
207
|
+
};
|
|
208
|
+
}),
|
|
209
|
+
};
|
|
210
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
export declare const FLORIDAY_API_BASES: {
|
|
3
|
+
readonly staging: "https://api.staging.floriday.io/suppliers-api-2026v1";
|
|
4
|
+
readonly production: "https://api.floriday.io/suppliers-api-2026v1";
|
|
5
|
+
};
|
|
6
|
+
export interface FloridayConnectionRow {
|
|
7
|
+
id: string;
|
|
8
|
+
environment: string | null;
|
|
9
|
+
access_token: string | null;
|
|
10
|
+
api_key: string | null;
|
|
11
|
+
is_active: boolean | null;
|
|
12
|
+
}
|
|
13
|
+
export interface SyncOptions<TRow> {
|
|
14
|
+
connection: FloridayConnectionRow;
|
|
15
|
+
entityType: string;
|
|
16
|
+
maxEndpoint: string;
|
|
17
|
+
syncEndpointBase: string;
|
|
18
|
+
cacheTable: string;
|
|
19
|
+
conflictTarget: string;
|
|
20
|
+
mapRow: (record: any, connectionId: string) => TRow;
|
|
21
|
+
}
|
|
22
|
+
export interface SyncResult {
|
|
23
|
+
ok: boolean;
|
|
24
|
+
entityType: string;
|
|
25
|
+
connectionId: string;
|
|
26
|
+
synced: number;
|
|
27
|
+
fromSequence: number;
|
|
28
|
+
toSequence: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function syncBySequence<TRow extends Record<string, any>>(supabase: SupabaseClient, opts: SyncOptions<TRow>): Promise<SyncResult>;
|
|
31
|
+
export declare function loadActiveConnections(supabase: SupabaseClient): Promise<FloridayConnectionRow[]>;
|
|
32
|
+
//# sourceMappingURL=floriday-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floriday-sync.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-sync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,kBAAkB;;;CAGrB,CAAC;AAEX,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW,CAAC,IAAI;IAC/B,UAAU,EAAE,qBAAqB,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAkCD,wBAAsB,cAAc,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACnE,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,GACtB,OAAO,CAAC,UAAU,CAAC,CA+FrB;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAOlC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export const FLORIDAY_API_BASES = {
|
|
2
|
+
staging: "https://api.staging.floriday.io/suppliers-api-2026v1",
|
|
3
|
+
production: "https://api.floriday.io/suppliers-api-2026v1",
|
|
4
|
+
};
|
|
5
|
+
async function readLastSequence(supabase, connectionId, entityType) {
|
|
6
|
+
const { data } = await supabase
|
|
7
|
+
.from("floriday_sync_state")
|
|
8
|
+
.select("last_sequence_number")
|
|
9
|
+
.eq("connection_id", connectionId)
|
|
10
|
+
.eq("entity_type", entityType)
|
|
11
|
+
.maybeSingle();
|
|
12
|
+
const v = data?.last_sequence_number;
|
|
13
|
+
return typeof v === "number" ? v : Number(v ?? 0) || 0;
|
|
14
|
+
}
|
|
15
|
+
async function writeLastSequence(supabase, connectionId, entityType, lastSequenceNumber) {
|
|
16
|
+
await supabase.from("floriday_sync_state").upsert({
|
|
17
|
+
connection_id: connectionId,
|
|
18
|
+
entity_type: entityType,
|
|
19
|
+
last_sequence_number: lastSequenceNumber,
|
|
20
|
+
last_synced_at: new Date().toISOString(),
|
|
21
|
+
}, { onConflict: "connection_id,entity_type" });
|
|
22
|
+
}
|
|
23
|
+
export async function syncBySequence(supabase, opts) {
|
|
24
|
+
// Lazy import vermijdt circular dependency tussen sync en gateway.
|
|
25
|
+
const { florydayFetch } = await import("./floriday-gateway.server");
|
|
26
|
+
const { connection, entityType, maxEndpoint, syncEndpointBase, cacheTable, conflictTarget, mapRow } = opts;
|
|
27
|
+
let active = connection;
|
|
28
|
+
const maxCall = await florydayFetch(supabase, active, {
|
|
29
|
+
method: "GET",
|
|
30
|
+
path: maxEndpoint,
|
|
31
|
+
});
|
|
32
|
+
if (!maxCall.ok) {
|
|
33
|
+
throw new Error(`Floriday GET ${maxEndpoint} faalde [${maxCall.status}]: ${maxCall.rawText.slice(0, 400)}`);
|
|
34
|
+
}
|
|
35
|
+
active = maxCall.connection;
|
|
36
|
+
const maxRes = maxCall.data;
|
|
37
|
+
const maxSequence = Number((typeof maxRes === "number" ? maxRes : maxRes?.maxSequenceNumber ?? maxRes?.sequenceNumber ?? 0) ?? 0);
|
|
38
|
+
const fromSequence = await readLastSequence(supabase, active.id, entityType);
|
|
39
|
+
let cursor = fromSequence;
|
|
40
|
+
let synced = 0;
|
|
41
|
+
let safetyHops = 0;
|
|
42
|
+
const MAX_HOPS = 1000;
|
|
43
|
+
let effectiveMax = maxSequence;
|
|
44
|
+
while (cursor < effectiveMax && safetyHops < MAX_HOPS) {
|
|
45
|
+
safetyHops += 1;
|
|
46
|
+
const batchCall = await florydayFetch(supabase, active, {
|
|
47
|
+
method: "GET",
|
|
48
|
+
path: `${syncEndpointBase}/${cursor}`,
|
|
49
|
+
});
|
|
50
|
+
if (!batchCall.ok) {
|
|
51
|
+
throw new Error(`Floriday GET ${syncEndpointBase}/${cursor} faalde [${batchCall.status}]: ${batchCall.rawText.slice(0, 400)}`);
|
|
52
|
+
}
|
|
53
|
+
active = batchCall.connection;
|
|
54
|
+
const batch = batchCall.data;
|
|
55
|
+
let list = [];
|
|
56
|
+
let respSeq = null;
|
|
57
|
+
let respMaxSeq = null;
|
|
58
|
+
if (Array.isArray(batch)) {
|
|
59
|
+
list = batch;
|
|
60
|
+
}
|
|
61
|
+
else if (batch && typeof batch === "object") {
|
|
62
|
+
list = (batch.results ?? batch.items ?? batch.salesOrders ?? batch.data ?? []);
|
|
63
|
+
const s = Number(batch.sequenceNumber);
|
|
64
|
+
const m = Number(batch.maximumSequenceNumber);
|
|
65
|
+
if (Number.isFinite(s))
|
|
66
|
+
respSeq = s;
|
|
67
|
+
if (Number.isFinite(m))
|
|
68
|
+
respMaxSeq = m;
|
|
69
|
+
}
|
|
70
|
+
if (list.length > 0) {
|
|
71
|
+
const rows = list.map((r) => mapRow(r, active.id));
|
|
72
|
+
const { error: upErr } = await supabase.from(cacheTable).upsert(rows, { onConflict: conflictTarget });
|
|
73
|
+
if (upErr)
|
|
74
|
+
throw new Error(`Upsert ${cacheTable} faalde: ${upErr.message}`);
|
|
75
|
+
synced += list.length;
|
|
76
|
+
}
|
|
77
|
+
const seqs = list
|
|
78
|
+
.map((r) => Number(r?.sequenceNumber ?? 0))
|
|
79
|
+
.filter((n) => Number.isFinite(n));
|
|
80
|
+
const highestInList = seqs.length ? Math.max(...seqs) : -Infinity;
|
|
81
|
+
let nextCursor = cursor;
|
|
82
|
+
if (highestInList > cursor)
|
|
83
|
+
nextCursor = highestInList;
|
|
84
|
+
else if (respSeq !== null && respSeq > cursor)
|
|
85
|
+
nextCursor = respSeq;
|
|
86
|
+
else if (list.length === 0 && respMaxSeq !== null && respMaxSeq > cursor) {
|
|
87
|
+
nextCursor = respMaxSeq;
|
|
88
|
+
}
|
|
89
|
+
else if (list.length === 0) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
if (nextCursor <= cursor)
|
|
93
|
+
break;
|
|
94
|
+
cursor = nextCursor;
|
|
95
|
+
await writeLastSequence(supabase, active.id, entityType, cursor);
|
|
96
|
+
if (respMaxSeq !== null && respMaxSeq > effectiveMax)
|
|
97
|
+
effectiveMax = respMaxSeq;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
ok: true,
|
|
101
|
+
entityType,
|
|
102
|
+
connectionId: active.id,
|
|
103
|
+
synced,
|
|
104
|
+
fromSequence,
|
|
105
|
+
toSequence: cursor,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export async function loadActiveConnections(supabase) {
|
|
109
|
+
const { data, error } = await supabase
|
|
110
|
+
.from("floriday_connections")
|
|
111
|
+
.select("id, environment, access_token, api_key, is_active")
|
|
112
|
+
.eq("is_active", true);
|
|
113
|
+
if (error)
|
|
114
|
+
throw new Error(`floriday_connections lezen faalde: ${error.message}`);
|
|
115
|
+
return (data ?? []);
|
|
116
|
+
}
|