@flowselections/floriday-authenticatie-module 1.0.54 → 1.0.56
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/settings/FlorydaySettingsCard.d.ts.map +1 -1
- package/dist-lib/components/settings/FlorydaySettingsCard.js +26 -48
- package/dist-lib/index.js +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +913 -4
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/cron/process-stock-queue.d.ts +18 -1
- package/dist-lib/lib/cron/process-stock-queue.d.ts.map +1 -1
- package/dist-lib/lib/cron/process-stock-queue.js +71 -23
- package/dist-lib/lib/floriday-gln.d.ts +6 -0
- package/dist-lib/lib/floriday-gln.d.ts.map +1 -0
- package/dist-lib/lib/floriday-gln.js +22 -0
- package/dist-lib/lib/floriday-own-config.d.ts +68 -0
- package/dist-lib/lib/floriday-own-config.d.ts.map +1 -0
- package/dist-lib/lib/floriday-own-config.js +73 -0
- package/dist-lib/lib/floriday-sync.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-sync.functions.js +8 -0
- package/dist-lib/lib/floriday.functions.d.ts +38 -12
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +145 -41
- package/package.json +4 -504
|
@@ -7,27 +7,8 @@
|
|
|
7
7
|
import { createServerFn } from "@tanstack/react-start";
|
|
8
8
|
import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware.js";
|
|
9
9
|
import { FLORYDAY_CLOCK_SUPPLY_PERMISSION_MESSAGE, FLORYDAY_CONTRACT_PERMISSION_MESSAGE, FLORYDAY_SALES_STRATEGY_PERMISSION_MESSAGE, FLORYDAY_STANDARD_SCOPE, getFlorydayScopeForPath, isClockSupplyScope, isContractScope, isSalesStrategyScope, } from "./floriday-scopes.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* Retourneert null als geldig, anders een nl-foutmelding.
|
|
13
|
-
*/
|
|
14
|
-
export function validateGln(input) {
|
|
15
|
-
const v = input.trim();
|
|
16
|
-
if (!v)
|
|
17
|
-
return "GLN-code is verplicht";
|
|
18
|
-
if (!/^\d{13}$/.test(v))
|
|
19
|
-
return "GLN-code moet uit precies 13 cijfers bestaan";
|
|
20
|
-
const digits = v.split("").map(Number);
|
|
21
|
-
// GS1 mod-10: positie 1 (meest links) ×3, positie 2 ×1, … t/m positie 12.
|
|
22
|
-
let sum = 0;
|
|
23
|
-
for (let i = 0; i < 12; i++) {
|
|
24
|
-
sum += digits[i] * (i % 2 === 0 ? 3 : 1);
|
|
25
|
-
}
|
|
26
|
-
const check = (10 - (sum % 10)) % 10;
|
|
27
|
-
if (check !== digits[12])
|
|
28
|
-
return "GLN-code heeft een ongeldig controlecijfer";
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
10
|
+
export { validateGln } from "./floriday-gln.js";
|
|
11
|
+
import { decideGln, decidePreferredWarehouse, isOwnWarehouse, warehouseLabel } from "./floriday-own-config.js";
|
|
31
12
|
const FLORYDAY_ENDPOINTS = {
|
|
32
13
|
staging: {
|
|
33
14
|
tokenUrl: "https://idm.staging.floriday.io/oauth2/ausmw6b47z1BnlHkw0h7/v1/token",
|
|
@@ -281,20 +262,36 @@ async function fetchAndStoreFlorydayOrganizationName(supabase, env, connectionId
|
|
|
281
262
|
}
|
|
282
263
|
const orgJson = await orgRes.json().catch(() => null);
|
|
283
264
|
const name = orgJson?.name ?? orgJson?.commercialName ?? null;
|
|
284
|
-
const
|
|
285
|
-
if (!name)
|
|
286
|
-
return null;
|
|
287
|
-
// Lees huidige rij om gln_code niet te overschrijven als die al gezet is.
|
|
265
|
+
const remoteGln = orgJson?.companyGln ?? null;
|
|
288
266
|
const { data: existing } = await supabaseAdmin
|
|
289
267
|
.from("floriday_connections")
|
|
290
268
|
.select("gln_code")
|
|
291
269
|
.eq("id", connectionId)
|
|
292
270
|
.maybeSingle();
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
271
|
+
const storedGln = existing?.gln_code ?? null;
|
|
272
|
+
const decision = decideGln({ stored: storedGln, fromFloriday: remoteGln });
|
|
273
|
+
if (name) {
|
|
274
|
+
await supabaseAdmin
|
|
275
|
+
.from("floriday_connections")
|
|
276
|
+
.update({ organization_name: name })
|
|
277
|
+
.eq("id", connectionId);
|
|
278
|
+
}
|
|
279
|
+
if (decision.kind === "fill") {
|
|
280
|
+
// Alleen een leeg veld vullen; filter op null voorkomt overschrijven.
|
|
281
|
+
await supabaseAdmin
|
|
282
|
+
.from("floriday_connections")
|
|
283
|
+
.update({ gln_code: decision.gln })
|
|
284
|
+
.eq("id", connectionId)
|
|
285
|
+
.is("gln_code", null);
|
|
286
|
+
console.log(`[floriday] gln_code automatisch ingevuld uit Floriday (connection ${connectionId})`);
|
|
287
|
+
}
|
|
288
|
+
else if (decision.kind === "mismatch") {
|
|
289
|
+
console.warn(`[floriday] GLN in Floriday wijkt af van opgeslagen GLN (connection ${connectionId}); niet overschreven`);
|
|
296
290
|
}
|
|
297
|
-
|
|
291
|
+
else if (decision.kind === "invalid") {
|
|
292
|
+
console.warn(`[floriday] companyGln uit Floriday ongeldig (${decision.error}); niet opgeslagen`);
|
|
293
|
+
}
|
|
294
|
+
await autoFillPreferredWarehouse(supabaseAdmin, connectionId).catch(() => null);
|
|
298
295
|
return name;
|
|
299
296
|
}
|
|
300
297
|
catch (e) {
|
|
@@ -302,6 +299,113 @@ async function fetchAndStoreFlorydayOrganizationName(supabase, env, connectionId
|
|
|
302
299
|
return null;
|
|
303
300
|
}
|
|
304
301
|
}
|
|
302
|
+
/** Haalt companyGln van de eigen organisatie op (null als niet beschikbaar). */
|
|
303
|
+
async function fetchOwnCompanyGln(supabase, env) {
|
|
304
|
+
try {
|
|
305
|
+
const tsRes = await florydayFetch(supabase, env, `/${SUPPLIERS_API_VERSION}/trade-settings/supplier/current-organization`);
|
|
306
|
+
if (!tsRes.ok)
|
|
307
|
+
return null;
|
|
308
|
+
const orgId = (await tsRes.json().catch(() => null))?.supplierOrganizationId;
|
|
309
|
+
if (!orgId)
|
|
310
|
+
return null;
|
|
311
|
+
const orgRes = await florydayFetch(supabase, env, `/${SUPPLIERS_API_VERSION}/organizations/${orgId}`);
|
|
312
|
+
if (!orgRes.ok)
|
|
313
|
+
return null;
|
|
314
|
+
return (await orgRes.json().catch(() => null))?.companyGln ?? null;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/** Eigen magazijnen van een koppeling uit de cache (op id). */
|
|
321
|
+
export async function loadOwnWarehousesFromCache(admin, connectionId) {
|
|
322
|
+
const { data } = await admin
|
|
323
|
+
.from("floriday_warehouses_cache")
|
|
324
|
+
.select("floriday_id, name, gln_code, data")
|
|
325
|
+
.eq("connection_id", connectionId)
|
|
326
|
+
.limit(500);
|
|
327
|
+
return (data ?? [])
|
|
328
|
+
.map((r) => ({
|
|
329
|
+
id: String(r.floriday_id ?? r?.data?.warehouseId ?? ""),
|
|
330
|
+
name: warehouseLabel(r),
|
|
331
|
+
gln: r.gln_code ?? r?.data?.location?.gln ?? null,
|
|
332
|
+
isDefault: r?.data?.isDefault === true,
|
|
333
|
+
isDeleted: r?.data?.isDeleted === true,
|
|
334
|
+
isExternal: r?.data?.isExternal === true,
|
|
335
|
+
hasAccess: r?.data?.hasAccess !== false,
|
|
336
|
+
}))
|
|
337
|
+
.filter((w) => w.id && isOwnWarehouse(w));
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Vult preferred_warehouse_id alleen als die leeg is: bij precies één eigen
|
|
341
|
+
* magazijn, of bij meerdere met precies één Floriday-standaardmagazijn.
|
|
342
|
+
* Altijd op id; bestaande keuze wordt nooit overschreven.
|
|
343
|
+
*/
|
|
344
|
+
export async function autoFillPreferredWarehouse(admin, connectionId) {
|
|
345
|
+
const { data: conn } = await admin
|
|
346
|
+
.from("floriday_connections")
|
|
347
|
+
.select("preferred_warehouse_id")
|
|
348
|
+
.eq("id", connectionId)
|
|
349
|
+
.maybeSingle();
|
|
350
|
+
const own = await loadOwnWarehousesFromCache(admin, connectionId);
|
|
351
|
+
const decision = decidePreferredWarehouse({ currentId: conn?.preferred_warehouse_id ?? null, warehouses: own });
|
|
352
|
+
if (decision.kind === "fill") {
|
|
353
|
+
const chosen = own.find((w) => w.id === decision.id);
|
|
354
|
+
const { data: updated } = await admin
|
|
355
|
+
.from("floriday_connections")
|
|
356
|
+
.update({ preferred_warehouse_id: decision.id, preferred_warehouse_name: chosen?.name ?? null })
|
|
357
|
+
.eq("id", connectionId)
|
|
358
|
+
.is("preferred_warehouse_id", null)
|
|
359
|
+
.select("id");
|
|
360
|
+
if (Array.isArray(updated) && updated.length > 0) {
|
|
361
|
+
console.log(`[floriday] voorkeursmagazijn automatisch ingevuld (${decision.reason}) voor connection ${connectionId}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return decision;
|
|
365
|
+
}
|
|
366
|
+
export const getFlorydayOwnConfigStatus = createServerFn({ method: "POST" })
|
|
367
|
+
.middleware([requireSupabaseAuth])
|
|
368
|
+
.inputValidator((input) => {
|
|
369
|
+
if (!["staging", "live"].includes(input.environment))
|
|
370
|
+
throw new Error("Ongeldige environment");
|
|
371
|
+
return input;
|
|
372
|
+
})
|
|
373
|
+
.handler(async ({ data, context }) => {
|
|
374
|
+
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
375
|
+
const row = await getActiveFlorydayCredentials(context.supabase, data.environment);
|
|
376
|
+
if (!row) {
|
|
377
|
+
return { connected: false, gln: null, storedGln: null, warehouse: null, preferredWarehouseId: null, preferredWarehouseName: null, ownWarehouses: [] };
|
|
378
|
+
}
|
|
379
|
+
// GLN: lezen uit Floriday, alleen een leeg veld vullen.
|
|
380
|
+
const remote = await fetchOwnCompanyGln(context.supabase, data.environment);
|
|
381
|
+
const { data: cur } = await supabaseAdmin
|
|
382
|
+
.from("floriday_connections")
|
|
383
|
+
.select("gln_code")
|
|
384
|
+
.eq("id", row.id)
|
|
385
|
+
.maybeSingle();
|
|
386
|
+
const gln = decideGln({ stored: cur?.gln_code ?? null, fromFloriday: remote });
|
|
387
|
+
if (gln.kind === "fill") {
|
|
388
|
+
await supabaseAdmin.from("floriday_connections").update({ gln_code: gln.gln }).eq("id", row.id).is("gln_code", null);
|
|
389
|
+
}
|
|
390
|
+
const warehouse = await autoFillPreferredWarehouse(supabaseAdmin, row.id);
|
|
391
|
+
const { data: after } = await supabaseAdmin
|
|
392
|
+
.from("floriday_connections")
|
|
393
|
+
.select("gln_code, preferred_warehouse_id, preferred_warehouse_name")
|
|
394
|
+
.eq("id", row.id)
|
|
395
|
+
.maybeSingle();
|
|
396
|
+
const own = await loadOwnWarehousesFromCache(supabaseAdmin, row.id);
|
|
397
|
+
return {
|
|
398
|
+
connected: true,
|
|
399
|
+
gln,
|
|
400
|
+
storedGln: after?.gln_code ?? null,
|
|
401
|
+
warehouse,
|
|
402
|
+
preferredWarehouseId: after?.preferred_warehouse_id ?? null,
|
|
403
|
+
preferredWarehouseName: after?.preferred_warehouse_name ?? null,
|
|
404
|
+
ownWarehouses: own
|
|
405
|
+
.map((w) => ({ id: w.id, name: w.name, gln: w.gln, isDefault: w.isDefault }))
|
|
406
|
+
.sort((a, b) => (a.isDefault !== b.isDefault ? (a.isDefault ? -1 : 1) : a.name.localeCompare(b.name, "nl"))),
|
|
407
|
+
};
|
|
408
|
+
});
|
|
305
409
|
export async function getActiveFlorydayEnvironment(supabase) {
|
|
306
410
|
const { data } = await supabase
|
|
307
411
|
.from("floriday_settings")
|
|
@@ -1097,8 +1201,7 @@ export const listFlorydayWarehouses = createServerFn({ method: "POST" })
|
|
|
1097
1201
|
const json = await res.json().catch(() => null);
|
|
1098
1202
|
const raw = Array.isArray(json) ? json : [];
|
|
1099
1203
|
const warehouses = raw
|
|
1100
|
-
.filter((w) => w
|
|
1101
|
-
w?.hasAccess !== false &&
|
|
1204
|
+
.filter((w) => isOwnWarehouse(w ?? {}) &&
|
|
1102
1205
|
Boolean(String(w?.name ?? "").trim() ||
|
|
1103
1206
|
String(w?.location?.address?.addressLine ?? "").trim() ||
|
|
1104
1207
|
String(w?.location?.gln ?? w?.location?.glnCode ?? "").trim()))
|
|
@@ -1131,25 +1234,26 @@ export const updateFlorydayPublishingSettings = createServerFn({ method: "POST"
|
|
|
1131
1234
|
if (!["staging", "live"].includes(input.environment)) {
|
|
1132
1235
|
throw new Error("Ongeldige environment");
|
|
1133
1236
|
}
|
|
1134
|
-
const
|
|
1135
|
-
if (
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
return { ...input, gln_code: trimmed || null };
|
|
1237
|
+
const id = String(input.preferred_warehouse_id ?? "").trim();
|
|
1238
|
+
if (!id)
|
|
1239
|
+
throw new Error("Kies een magazijn");
|
|
1240
|
+
// GLN wordt niet meer aangenomen: die komt altijd uit Floriday.
|
|
1241
|
+
return { environment: input.environment, preferred_warehouse_id: id };
|
|
1141
1242
|
})
|
|
1142
1243
|
.handler(async ({ data, context }) => {
|
|
1143
1244
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
|
|
1144
1245
|
const row = await getActiveFlorydayCredentials(context.supabase, data.environment);
|
|
1145
1246
|
if (!row)
|
|
1146
1247
|
throw new Error(`Geen actieve Floriday-koppeling voor ${data.environment}`);
|
|
1248
|
+
const own = await loadOwnWarehousesFromCache(supabaseAdmin, row.id);
|
|
1249
|
+
const chosen = own.find((w) => w.id === data.preferred_warehouse_id);
|
|
1250
|
+
if (!chosen)
|
|
1251
|
+
throw new Error("Dit magazijn is geen eigen magazijn van deze koppeling");
|
|
1147
1252
|
const { error } = await supabaseAdmin
|
|
1148
1253
|
.from("floriday_connections")
|
|
1149
1254
|
.update({
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
preferred_warehouse_name: data.preferred_warehouse_name || null,
|
|
1255
|
+
preferred_warehouse_id: chosen.id,
|
|
1256
|
+
preferred_warehouse_name: chosen.name,
|
|
1153
1257
|
})
|
|
1154
1258
|
.eq("id", row.id);
|
|
1155
1259
|
if (error)
|