@flowselections/floriday-klanten-module 1.0.46 → 1.0.48
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/klanten/BewerkKlant.d.ts.map +1 -1
- package/dist-lib/components/klanten/BewerkKlant.js +1 -1
- package/dist-lib/components/klanten/CustomerAnalyticsTab.d.ts.map +1 -1
- package/dist-lib/components/klanten/CustomerAnalyticsTab.js +2 -2
- package/dist-lib/components/klanten/FloridayNetworkStatus.d.ts +5 -0
- package/dist-lib/components/klanten/FloridayNetworkStatus.d.ts.map +1 -0
- package/dist-lib/components/klanten/FloridayNetworkStatus.js +18 -0
- package/dist-lib/components/klanten/KlantDetailLayout.d.ts +2 -0
- package/dist-lib/components/klanten/KlantDetailLayout.d.ts.map +1 -1
- package/dist-lib/components/klanten/KlantDetailLayout.js +6 -1
- package/dist-lib/components/klanten/KlantFormulier.d.ts +3 -1
- package/dist-lib/components/klanten/KlantFormulier.d.ts.map +1 -1
- package/dist-lib/components/klanten/KlantFormulier.js +16 -4
- package/dist-lib/components/klanten/NetwerkPagina.d.ts.map +1 -1
- package/dist-lib/components/klanten/NetwerkPagina.js +9 -5
- package/dist-lib/components/klanten/pricegroups/CustomerPickerDialog.d.ts.map +1 -1
- package/dist-lib/components/klanten/pricegroups/CustomerPickerDialog.js +10 -2
- package/dist-lib/components/klanten/pricegroups/PriceGroupsPage.d.ts.map +1 -1
- package/dist-lib/components/klanten/pricegroups/PriceGroupsPage.js +4 -7
- package/dist-lib/components/klanten/pricegroups/UnknownFloridayMembers.d.ts +11 -0
- package/dist-lib/components/klanten/pricegroups/UnknownFloridayMembers.d.ts.map +1 -0
- package/dist-lib/components/klanten/pricegroups/UnknownFloridayMembers.js +43 -0
- package/dist-lib/index.js +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +126 -2
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/customers.functions.d.ts +3 -0
- package/dist-lib/lib/customers.functions.d.ts.map +1 -1
- package/dist-lib/lib/customers.functions.js +6 -2
- package/dist-lib/lib/floriday-network-status.functions.d.ts +18 -0
- package/dist-lib/lib/floriday-network-status.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-network-status.functions.js +41 -0
- package/dist-lib/lib/price-groups-local.functions.d.ts +42 -0
- package/dist-lib/lib/price-groups-local.functions.d.ts.map +1 -1
- package/dist-lib/lib/price-groups-local.functions.js +120 -1
- package/dist-lib/lib/vat-format.d.ts +17 -0
- package/dist-lib/lib/vat-format.d.ts.map +1 -0
- package/dist-lib/lib/vat-format.js +64 -0
- package/package.json +4 -4
|
@@ -583,11 +583,13 @@ export declare const listFloridayNetwork: import("@tanstack/start-client-core").
|
|
|
583
583
|
types?: string[];
|
|
584
584
|
includeExpired?: boolean;
|
|
585
585
|
limit?: number;
|
|
586
|
+
offset?: number;
|
|
586
587
|
}) => {
|
|
587
588
|
search: string;
|
|
588
589
|
types: string[];
|
|
589
590
|
includeExpired: boolean;
|
|
590
591
|
limit: number;
|
|
592
|
+
offset: number;
|
|
591
593
|
}, Promise<{
|
|
592
594
|
organizations: {
|
|
593
595
|
connection_id: any;
|
|
@@ -609,6 +611,7 @@ export declare const listFloridayNetwork: import("@tanstack/start-client-core").
|
|
|
609
611
|
}[];
|
|
610
612
|
total: number;
|
|
611
613
|
limit: number;
|
|
614
|
+
offset: number;
|
|
612
615
|
truncated: boolean;
|
|
613
616
|
}>>;
|
|
614
617
|
export declare const listCustomerClasses: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customers.functions.d.ts","sourceRoot":"","sources":["../../src/lib/customers.functions.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAK5B,KAAK,cAAc,GAAG;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAqCF,gFAAgF;AAChF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;GAQzC,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;;;8CAEX;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;GAYpC,CAAC;AAEL,eAAO,MAAM,qBAAqB;;;;8CAER;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,KACiD;IAC9F,KAAK,EAAE,cAAc,CAAC;CACvB;;;;;;GAaD,CAAC;AAGL,eAAO,MAAM,aAAa;;;;8CAEA,gBAAgB;;;;;;;;;;GAiDtC,CAAC;AAEL,eAAO,MAAM,WAAW;;;;8CAEE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EpC,CAAC;AAwDL,eAAO,MAAM,cAAc;;;;8CAED,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YApDlB,MAAM;sBAAgB,MAAM;gBAAU,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8GnE,CAAC;AAEL,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAmCS,MAAM;aAAO,MAAM;gBAAU,MAAM;;GAwDnE,CAAC;AAEL,eAAO,MAAM,cAAc;;;;8CAED;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;GAQpC,CAAC;AAEL,eAAO,MAAM,mBAAmB;;;;8CAGpB;IACN,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"customers.functions.d.ts","sourceRoot":"","sources":["../../src/lib/customers.functions.ts"],"names":[],"mappings":"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"}
|
|
@@ -424,6 +424,7 @@ export const listFloridayNetwork = createServerFn({ method: "POST" })
|
|
|
424
424
|
: ["CUSTOMER", "AGENT"],
|
|
425
425
|
includeExpired: !!input?.includeExpired,
|
|
426
426
|
limit: Math.min(Math.max(Number(input?.limit) || 500, 1), 2000),
|
|
427
|
+
offset: Math.max(Number(input?.offset) || 0, 0),
|
|
427
428
|
}))
|
|
428
429
|
.handler(async ({ data, context }) => {
|
|
429
430
|
const nowIso = new Date().toISOString();
|
|
@@ -431,7 +432,9 @@ export const listFloridayNetwork = createServerFn({ method: "POST" })
|
|
|
431
432
|
.from("floriday_network_cache")
|
|
432
433
|
.select("connection_id, organization_id, organization_name, gln, country, city, data, fetched_at", { count: "exact" })
|
|
433
434
|
.in("data->>organizationType", data.types)
|
|
434
|
-
.
|
|
435
|
+
.order("organization_name", { ascending: true, nullsFirst: false })
|
|
436
|
+
.order("organization_id", { ascending: true })
|
|
437
|
+
.range(data.offset, data.offset + data.limit - 1);
|
|
435
438
|
if (!data.includeExpired) {
|
|
436
439
|
q = q.or(`data->>endDate.is.null,data->>endDate.gt.${nowIso}`);
|
|
437
440
|
}
|
|
@@ -486,7 +489,8 @@ export const listFloridayNetwork = createServerFn({ method: "POST" })
|
|
|
486
489
|
organizations,
|
|
487
490
|
total: count ?? organizations.length,
|
|
488
491
|
limit: data.limit,
|
|
489
|
-
|
|
492
|
+
offset: data.offset,
|
|
493
|
+
truncated: (count ?? 0) > data.offset + organizations.length,
|
|
490
494
|
};
|
|
491
495
|
});
|
|
492
496
|
export const listCustomerClasses = createServerFn({ method: "POST" })
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type FloridayNetworkStatus = {
|
|
2
|
+
/** null = onbekend (geen actieve Floriday-koppeling). */
|
|
3
|
+
inNetwork: boolean | null;
|
|
4
|
+
endDate: string | null;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* "In je Floriday-netwerk": alleen lezen uit de caches van de Floriday-module, op organisatie-id.
|
|
8
|
+
* Ja = rij in floriday_connections_cache voor de actieve koppeling met dit customerOrganizationId
|
|
9
|
+
* en isDeleted = false.
|
|
10
|
+
*/
|
|
11
|
+
export declare const getFloridayNetworkStatus: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
12
|
+
supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
|
|
13
|
+
userId: string;
|
|
14
|
+
claims: import("@supabase/auth-js").JwtPayload;
|
|
15
|
+
}, undefined, undefined, undefined>], (input: unknown) => {
|
|
16
|
+
organizationId: string;
|
|
17
|
+
}, Promise<FloridayNetworkStatus>>;
|
|
18
|
+
//# sourceMappingURL=floriday-network-status.functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floriday-network-status.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-network-status.functions.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,qBAAqB,GAAG;IAClC,yDAAyD;IACzD,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;8CAEX,OAAO;;kCAgC7B,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createServerFn } from "@tanstack/react-start";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
|
|
4
|
+
/**
|
|
5
|
+
* "In je Floriday-netwerk": alleen lezen uit de caches van de Floriday-module, op organisatie-id.
|
|
6
|
+
* Ja = rij in floriday_connections_cache voor de actieve koppeling met dit customerOrganizationId
|
|
7
|
+
* en isDeleted = false.
|
|
8
|
+
*/
|
|
9
|
+
export const getFloridayNetworkStatus = createServerFn({ method: "GET" })
|
|
10
|
+
.middleware([requireSupabaseAuth])
|
|
11
|
+
.inputValidator((input) => z.object({ organizationId: z.string().min(1).max(64) }).parse(input))
|
|
12
|
+
.handler(async ({ data, context }) => {
|
|
13
|
+
const sb = context.supabase;
|
|
14
|
+
const { data: conn } = await sb
|
|
15
|
+
.from("floriday_connections")
|
|
16
|
+
.select("id")
|
|
17
|
+
.eq("is_active", true)
|
|
18
|
+
.order("updated_at", { ascending: false })
|
|
19
|
+
.limit(1)
|
|
20
|
+
.maybeSingle();
|
|
21
|
+
let inNetwork = null;
|
|
22
|
+
if (conn?.id) {
|
|
23
|
+
const { data: rows, error } = await sb
|
|
24
|
+
.from("floriday_connections_cache")
|
|
25
|
+
.select("connection_id")
|
|
26
|
+
.eq("connection_id", conn.id)
|
|
27
|
+
.eq("data->>customerOrganizationId", data.organizationId)
|
|
28
|
+
.eq("data->>isDeleted", "false")
|
|
29
|
+
.limit(1);
|
|
30
|
+
inNetwork = error ? null : (rows ?? []).length > 0;
|
|
31
|
+
}
|
|
32
|
+
const { data: cust } = await sb
|
|
33
|
+
.from("floriday_customers_cache")
|
|
34
|
+
.select("data, fetched_at")
|
|
35
|
+
.eq("organization_id", data.organizationId)
|
|
36
|
+
.order("fetched_at", { ascending: false })
|
|
37
|
+
.limit(1)
|
|
38
|
+
.maybeSingle();
|
|
39
|
+
const end = cust?.data?.endDate;
|
|
40
|
+
return { inNetwork, endDate: typeof end === "string" && end.trim() ? end : null };
|
|
41
|
+
});
|
|
@@ -250,6 +250,8 @@ export type FloridayImportPreviewItem = {
|
|
|
250
250
|
name: string;
|
|
251
251
|
action: "create" | "update" | "deactivate";
|
|
252
252
|
customers: number;
|
|
253
|
+
/** lastModifiedDateTime uit Floriday. */
|
|
254
|
+
last_modified_in_floriday?: string | null;
|
|
253
255
|
};
|
|
254
256
|
export type FloridayImportResult = {
|
|
255
257
|
preview: boolean;
|
|
@@ -259,6 +261,7 @@ export type FloridayImportResult = {
|
|
|
259
261
|
deactivated: number;
|
|
260
262
|
membersLinked: number;
|
|
261
263
|
unmatchedOrganizations: string[];
|
|
264
|
+
unmatchedDetails: UnknownFloridayMember[];
|
|
262
265
|
};
|
|
263
266
|
export declare const importFloridayPriceGroups: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
264
267
|
supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
|
|
@@ -267,6 +270,45 @@ export declare const importFloridayPriceGroups: import("@tanstack/start-client-c
|
|
|
267
270
|
}, undefined, undefined, undefined>], (input: unknown) => {
|
|
268
271
|
preview: boolean;
|
|
269
272
|
}, Promise<FloridayImportResult>>;
|
|
273
|
+
export type UnknownFloridayMember = {
|
|
274
|
+
organization_id: string;
|
|
275
|
+
name: string;
|
|
276
|
+
commercial_name: string | null;
|
|
277
|
+
city: string | null;
|
|
278
|
+
/** Reden waarom deze klant niet is ingedeeld. */
|
|
279
|
+
reason: string;
|
|
280
|
+
/** Prijsgroepen (Floriday-id + naam) waarin deze organisatie in Floriday zit. */
|
|
281
|
+
groups: {
|
|
282
|
+
external_id: string;
|
|
283
|
+
name: string;
|
|
284
|
+
}[];
|
|
285
|
+
};
|
|
286
|
+
/** Floriday-leden van één prijsgroep die nog geen ERP-klant zijn (live uit de cache, niets vastgelegd). */
|
|
287
|
+
export declare const listUnknownFloridayMembers: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
288
|
+
supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
|
|
289
|
+
userId: string;
|
|
290
|
+
claims: import("@supabase/auth-js").JwtPayload;
|
|
291
|
+
}, undefined, undefined, undefined>], (input: unknown) => {
|
|
292
|
+
priceGroupId: string;
|
|
293
|
+
}, Promise<{
|
|
294
|
+
members: UnknownFloridayMember[];
|
|
295
|
+
lastModifiedInFloriday: string | null;
|
|
296
|
+
}>>;
|
|
297
|
+
/**
|
|
298
|
+
* "Toevoegen": maakt van een Floriday-organisatie een ERP-klant (bron Floriday, dus géén
|
|
299
|
+
* Twinfield-debiteur) en deelt die op klant-id in bij de prijsgroep.
|
|
300
|
+
*/
|
|
301
|
+
export declare const addFloridayMemberToPriceGroup: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
302
|
+
supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
|
|
303
|
+
userId: string;
|
|
304
|
+
claims: import("@supabase/auth-js").JwtPayload;
|
|
305
|
+
}, undefined, undefined, undefined>], (input: unknown) => {
|
|
306
|
+
organizationId: string;
|
|
307
|
+
priceGroupId: string;
|
|
308
|
+
}, Promise<{
|
|
309
|
+
customerId: string;
|
|
310
|
+
customerKey: string;
|
|
311
|
+
}>>;
|
|
270
312
|
export type PriceGroupItemPrice = {
|
|
271
313
|
trade_item_key: string;
|
|
272
314
|
price_per_piece: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"price-groups-local.functions.d.ts","sourceRoot":"","sources":["../../src/lib/price-groups-local.functions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgBzB,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;0EAwBhC,CAAC;AAEL,eAAO,MAAM,qBAAqB;;;;8CAER,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoB7B,CAAC;AAEL,eAAO,MAAM,wBAAwB;;;;8CAEX,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgB7B,CAAC;AAEL,eAAO,MAAM,wBAAwB;;;;8CAEX,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAY7B,CAAC;AAEL,eAAO,MAAM,wBAAwB;;;;8CAEX,OAAO;;;;GAQ7B,CAAC;AAEL,eAAO,MAAM,0BAA0B;;;;8CAEb,OAAO;;;;GAO7B,CAAC;AAEL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;;;;GAqB7B,CAAC;AAKL,eAAO,MAAM,yBAAyB;;;;8CAEZ,OAAO;;;mBAUuB,MAAM,EAAE;YAAgB;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE;GAU1G,CAAC;AAEL,6EAA6E;AAC7E,eAAO,MAAM,kCAAkC;;;;8CAErB,OAAO;;;iBAgBC,MAAM,GAAG,IAAI;GAC3C,CAAC;AAEL,eAAO,MAAM,wBAAwB;;;;8CAEX,OAAO;;;;;GAyB7B,CAAC;AAML,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,YAAY,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"price-groups-local.functions.d.ts","sourceRoot":"","sources":["../../src/lib/price-groups-local.functions.ts"],"names":[],"mappings":"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"}
|
|
@@ -270,6 +270,7 @@ export const importFloridayPriceGroups = createServerFn({ method: "POST" })
|
|
|
270
270
|
}
|
|
271
271
|
const items = [];
|
|
272
272
|
const unmatched = new Set();
|
|
273
|
+
const unmatchedGroups = new Map();
|
|
273
274
|
const seen = new Set();
|
|
274
275
|
let created = 0;
|
|
275
276
|
let updated = 0;
|
|
@@ -321,6 +322,7 @@ export const importFloridayPriceGroups = createServerFn({ method: "POST" })
|
|
|
321
322
|
name: payload.name,
|
|
322
323
|
action: current ? "update" : "create",
|
|
323
324
|
customers: customerOrgIds.length,
|
|
325
|
+
last_modified_in_floriday: d.lastModifiedDateTime ?? null,
|
|
324
326
|
});
|
|
325
327
|
let groupId = current?.id ?? null;
|
|
326
328
|
if (current) {
|
|
@@ -350,8 +352,12 @@ export const importFloridayPriceGroups = createServerFn({ method: "POST" })
|
|
|
350
352
|
const key = orgToKey.get(orgId);
|
|
351
353
|
if (key)
|
|
352
354
|
keys.push(key);
|
|
353
|
-
else
|
|
355
|
+
else {
|
|
354
356
|
unmatched.add(orgId);
|
|
357
|
+
const list = unmatchedGroups.get(orgId) ?? [];
|
|
358
|
+
list.push({ external_id: externalId, name: payload.name });
|
|
359
|
+
unmatchedGroups.set(orgId, list);
|
|
360
|
+
}
|
|
355
361
|
}
|
|
356
362
|
membersLinked += keys.length;
|
|
357
363
|
if (!data.preview && groupId) {
|
|
@@ -379,6 +385,7 @@ export const importFloridayPriceGroups = createServerFn({ method: "POST" })
|
|
|
379
385
|
await sb.from("customer_price_groups").update({ is_active: false }).eq("id", row.id);
|
|
380
386
|
}
|
|
381
387
|
}
|
|
388
|
+
const unmatchedDetails = await describeUnknownOrganizations(sb, Array.from(unmatched), unmatchedGroups);
|
|
382
389
|
return {
|
|
383
390
|
preview: data.preview,
|
|
384
391
|
items,
|
|
@@ -387,8 +394,120 @@ export const importFloridayPriceGroups = createServerFn({ method: "POST" })
|
|
|
387
394
|
deactivated,
|
|
388
395
|
membersLinked,
|
|
389
396
|
unmatchedOrganizations: Array.from(unmatched),
|
|
397
|
+
unmatchedDetails,
|
|
398
|
+
};
|
|
399
|
+
});
|
|
400
|
+
/** Zoekt namen op in de Floriday-cache (alleen lezen, op organisatie-id). */
|
|
401
|
+
async function describeUnknownOrganizations(sb, orgIds, groupsByOrg) {
|
|
402
|
+
if (orgIds.length === 0)
|
|
403
|
+
return [];
|
|
404
|
+
const info = new Map();
|
|
405
|
+
for (let i = 0; i < orgIds.length; i += 200) {
|
|
406
|
+
const { data: rows } = await sb
|
|
407
|
+
.from("floriday_customers_cache")
|
|
408
|
+
.select("organization_id, name, data, fetched_at")
|
|
409
|
+
.in("organization_id", orgIds.slice(i, i + 200))
|
|
410
|
+
.order("fetched_at", { ascending: false });
|
|
411
|
+
for (const r of rows ?? [])
|
|
412
|
+
if (!info.has(r.organization_id))
|
|
413
|
+
info.set(r.organization_id, r);
|
|
414
|
+
}
|
|
415
|
+
return orgIds.map((org) => {
|
|
416
|
+
const r = info.get(org);
|
|
417
|
+
const d = (r?.data ?? {});
|
|
418
|
+
const addr = d.physicalAddress ?? d.mailingAddress ?? {};
|
|
419
|
+
const name = (d.name || r?.name || d.commercialName || "").toString().trim();
|
|
420
|
+
const commercial = (d.commercialName ?? "").toString().trim();
|
|
421
|
+
return {
|
|
422
|
+
organization_id: org,
|
|
423
|
+
name: name || `Floriday-organisatie ${org.slice(0, 8)}`,
|
|
424
|
+
commercial_name: commercial && commercial !== name ? commercial : null,
|
|
425
|
+
city: addr.city ?? null,
|
|
426
|
+
reason: r ? "Nog geen klant in het ERP" : "Niet gevonden in de Floriday-klantgegevens",
|
|
427
|
+
groups: groupsByOrg.get(org) ?? [],
|
|
428
|
+
};
|
|
429
|
+
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
430
|
+
}
|
|
431
|
+
/** Floriday-leden van één prijsgroep die nog geen ERP-klant zijn (live uit de cache, niets vastgelegd). */
|
|
432
|
+
export const listUnknownFloridayMembers = createServerFn({ method: "GET" })
|
|
433
|
+
.middleware([requireSupabaseAuth])
|
|
434
|
+
.inputValidator((input) => z.object({ priceGroupId: z.string().uuid() }).parse(input))
|
|
435
|
+
.handler(async ({ data, context }) => {
|
|
436
|
+
const sb = context.supabase;
|
|
437
|
+
const { data: group, error } = await sb
|
|
438
|
+
.from("customer_price_groups")
|
|
439
|
+
.select("id, name, source, external_id")
|
|
440
|
+
.eq("id", data.priceGroupId)
|
|
441
|
+
.maybeSingle();
|
|
442
|
+
if (error)
|
|
443
|
+
throw new Error(error.message);
|
|
444
|
+
if (!group || group.source !== "floriday" || !group.external_id) {
|
|
445
|
+
return { members: [], lastModifiedInFloriday: null };
|
|
446
|
+
}
|
|
447
|
+
const { data: cache } = await sb
|
|
448
|
+
.from("floriday_price_groups_cache")
|
|
449
|
+
.select("data, fetched_at")
|
|
450
|
+
.eq("floriday_id", group.external_id)
|
|
451
|
+
.order("fetched_at", { ascending: false })
|
|
452
|
+
.limit(1)
|
|
453
|
+
.maybeSingle();
|
|
454
|
+
const d = (cache?.data ?? {});
|
|
455
|
+
const orgIds = (Array.isArray(d.customers) ? d.customers : []).filter((c) => typeof c === "string");
|
|
456
|
+
const known = await knownFloridayOrgs(sb, orgIds);
|
|
457
|
+
const unknown = orgIds.filter((o) => !known.has(o));
|
|
458
|
+
const groups = new Map(unknown.map((o) => [o, [{ external_id: String(group.external_id), name: String(group.name) }]]));
|
|
459
|
+
return {
|
|
460
|
+
members: await describeUnknownOrganizations(sb, unknown, groups),
|
|
461
|
+
lastModifiedInFloriday: d.lastModifiedDateTime ?? null,
|
|
390
462
|
};
|
|
391
463
|
});
|
|
464
|
+
/** Organisatie-id's die al als ERP-klant bestaan (op id, nooit op naam). */
|
|
465
|
+
async function knownFloridayOrgs(sb, orgIds) {
|
|
466
|
+
const out = new Set();
|
|
467
|
+
for (let i = 0; i < orgIds.length; i += 200) {
|
|
468
|
+
const { data: rows } = await sb
|
|
469
|
+
.from("customers")
|
|
470
|
+
.select("floriday_organization_id")
|
|
471
|
+
.in("floriday_organization_id", orgIds.slice(i, i + 200));
|
|
472
|
+
for (const r of rows ?? [])
|
|
473
|
+
if (r.floriday_organization_id)
|
|
474
|
+
out.add(String(r.floriday_organization_id));
|
|
475
|
+
}
|
|
476
|
+
return out;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* "Toevoegen": maakt van een Floriday-organisatie een ERP-klant (bron Floriday, dus géén
|
|
480
|
+
* Twinfield-debiteur) en deelt die op klant-id in bij de prijsgroep.
|
|
481
|
+
*/
|
|
482
|
+
export const addFloridayMemberToPriceGroup = createServerFn({ method: "POST" })
|
|
483
|
+
.middleware([requireSupabaseAuth])
|
|
484
|
+
.inputValidator((input) => z.object({ organizationId: z.string().min(1).max(64), priceGroupId: z.string().uuid() }).parse(input))
|
|
485
|
+
.handler(async ({ data, context }) => {
|
|
486
|
+
const sb = context.supabase;
|
|
487
|
+
const { data: customerId, error } = await sb.rpc("promote_floriday_customer", { _org_id: data.organizationId });
|
|
488
|
+
if (error)
|
|
489
|
+
throw new Error(error.message);
|
|
490
|
+
// Debiteur alleen na bewuste bevestiging: kenmerk uit, zodat ook latere wijzigingen niets versturen.
|
|
491
|
+
await sb.from("customers").update({ twinfield_create_on_insert: false }).eq("id", customerId).is("twinfield_code", null);
|
|
492
|
+
// Klanten met een Floriday-organisatie-id krijgen in het overzicht altijd de sleutel fd:<org-id>.
|
|
493
|
+
const customerKey = `fd:${data.organizationId}`;
|
|
494
|
+
const { data: existing } = await sb
|
|
495
|
+
.from("customer_price_group_members")
|
|
496
|
+
.select("id")
|
|
497
|
+
.eq("price_group_id", data.priceGroupId)
|
|
498
|
+
.eq("customer_key", customerKey)
|
|
499
|
+
.maybeSingle();
|
|
500
|
+
if (!existing) {
|
|
501
|
+
const { error: insErr } = await sb.from("customer_price_group_members").insert({
|
|
502
|
+
price_group_id: data.priceGroupId,
|
|
503
|
+
customer_key: customerKey,
|
|
504
|
+
owner_id: context.userId,
|
|
505
|
+
});
|
|
506
|
+
if (insErr)
|
|
507
|
+
throw new Error(insErr.message);
|
|
508
|
+
}
|
|
509
|
+
return { customerId: String(customerId), customerKey };
|
|
510
|
+
});
|
|
392
511
|
export const listPriceGroupItemPrices = createServerFn({ method: "POST" })
|
|
393
512
|
.middleware([requireSupabaseAuth])
|
|
394
513
|
.inputValidator((input) => z.object({ priceGroupId: z.string().uuid() }).parse(input))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function normalizeVat(v: string | null | undefined): string;
|
|
2
|
+
export type VatCheck = {
|
|
3
|
+
status: "empty";
|
|
4
|
+
} | {
|
|
5
|
+
status: "unchecked";
|
|
6
|
+
} | {
|
|
7
|
+
status: "valid";
|
|
8
|
+
} | {
|
|
9
|
+
status: "invalid";
|
|
10
|
+
message: string;
|
|
11
|
+
example?: string;
|
|
12
|
+
};
|
|
13
|
+
/** @param iso2 ISO-landcode van de klant (gebruik toIsoCountry voor een landnaam). */
|
|
14
|
+
export declare function checkVatFormat(vat: string | null | undefined, iso2: string | null | undefined): VatCheck;
|
|
15
|
+
/** Herkent een Twinfield-fout die over het btw-nummer (field4) gaat. */
|
|
16
|
+
export declare function isTwinfieldVatError(msg: string | null | undefined): boolean;
|
|
17
|
+
//# sourceMappingURL=vat-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vat-format.d.ts","sourceRoot":"","sources":["../../src/lib/vat-format.ts"],"names":[],"mappings":"AAyCA,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEjE;AAED,MAAM,MAAM,QAAQ,GAChB;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACnB;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACnB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,CAaxG;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE3E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vorm van btw-nummers per EU-land (referentiedata, VIES-formaten).
|
|
3
|
+
* Alleen een vormcontrole: of het nummer echt bestaat, controleert dit niet.
|
|
4
|
+
* Onbekende landen worden niet gecontroleerd.
|
|
5
|
+
*/
|
|
6
|
+
const VAT_PATTERNS = {
|
|
7
|
+
AT: /^ATU\d{8}$/,
|
|
8
|
+
BE: /^BE[01]\d{9}$/,
|
|
9
|
+
BG: /^BG\d{9,10}$/,
|
|
10
|
+
CY: /^CY\d{8}[A-Z]$/,
|
|
11
|
+
CZ: /^CZ\d{8,10}$/,
|
|
12
|
+
DE: /^DE\d{9}$/,
|
|
13
|
+
DK: /^DK\d{8}$/,
|
|
14
|
+
EE: /^EE\d{9}$/,
|
|
15
|
+
GR: /^EL\d{9}$/,
|
|
16
|
+
ES: /^ES[A-Z0-9]\d{7}[A-Z0-9]$/,
|
|
17
|
+
FI: /^FI\d{8}$/,
|
|
18
|
+
FR: /^FR[A-HJ-NP-Z0-9]{2}\d{9}$/,
|
|
19
|
+
HR: /^HR\d{11}$/,
|
|
20
|
+
HU: /^HU\d{8}$/,
|
|
21
|
+
IE: /^IE\d{7}[A-W][A-I]?$|^IE\d[A-Z+*]\d{5}[A-W]$/,
|
|
22
|
+
IT: /^IT\d{11}$/,
|
|
23
|
+
LT: /^LT(\d{9}|\d{12})$/,
|
|
24
|
+
LU: /^LU\d{8}$/,
|
|
25
|
+
LV: /^LV\d{11}$/,
|
|
26
|
+
MT: /^MT\d{8}$/,
|
|
27
|
+
NL: /^NL\d{9}B\d{2}$/,
|
|
28
|
+
PL: /^PL\d{10}$/,
|
|
29
|
+
PT: /^PT\d{9}$/,
|
|
30
|
+
RO: /^RO\d{2,10}$/,
|
|
31
|
+
SE: /^SE\d{12}$/,
|
|
32
|
+
SI: /^SI\d{8}$/,
|
|
33
|
+
SK: /^SK\d{10}$/,
|
|
34
|
+
};
|
|
35
|
+
/** Voorbeeld per land voor de melding. */
|
|
36
|
+
const VAT_EXAMPLES = {
|
|
37
|
+
NL: "NL123456789B01", BE: "BE0123456789", DE: "DE123456789", FR: "FRXX123456789",
|
|
38
|
+
ES: "ESX1234567X", IT: "IT12345678901", AT: "ATU12345678", PL: "PL1234567890",
|
|
39
|
+
};
|
|
40
|
+
export function normalizeVat(v) {
|
|
41
|
+
return String(v ?? "").replace(/[\s.\-]/g, "").toUpperCase();
|
|
42
|
+
}
|
|
43
|
+
/** @param iso2 ISO-landcode van de klant (gebruik toIsoCountry voor een landnaam). */
|
|
44
|
+
export function checkVatFormat(vat, iso2) {
|
|
45
|
+
const v = normalizeVat(vat);
|
|
46
|
+
if (!v)
|
|
47
|
+
return { status: "empty" };
|
|
48
|
+
const cc = String(iso2 ?? "").toUpperCase();
|
|
49
|
+
const pattern = VAT_PATTERNS[cc];
|
|
50
|
+
if (!pattern)
|
|
51
|
+
return { status: "unchecked" };
|
|
52
|
+
if (pattern.test(v))
|
|
53
|
+
return { status: "valid" };
|
|
54
|
+
const example = VAT_EXAMPLES[cc];
|
|
55
|
+
return {
|
|
56
|
+
status: "invalid",
|
|
57
|
+
message: `Btw-nummer ongeldig voor dit land${example ? ` (voorbeeld: ${example})` : ""}`,
|
|
58
|
+
example,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Herkent een Twinfield-fout die over het btw-nummer (field4) gaat. */
|
|
62
|
+
export function isTwinfieldVatError(msg) {
|
|
63
|
+
return !!msg && /field4|btw-?nummer|vat/i.test(msg);
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowselections/floriday-klanten-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.48",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
"@rsbuild/core": "^1.0.0",
|
|
57
57
|
"@tailwindcss/vite": "^4.2.1",
|
|
58
58
|
"@tanstack/react-query": "^5.83.0",
|
|
59
|
-
"@tanstack/react-router": "
|
|
60
|
-
"@tanstack/react-start": "
|
|
61
|
-
"@tanstack/router-plugin": "
|
|
59
|
+
"@tanstack/react-router": "1.169.1",
|
|
60
|
+
"@tanstack/react-start": "1.167.63",
|
|
61
|
+
"@tanstack/router-plugin": "1.167.33",
|
|
62
62
|
"@types/node": "^22.16.5",
|
|
63
63
|
"@types/react": "^19.2.0",
|
|
64
64
|
"@types/react-dom": "^19.2.0",
|