@flowselections/floriday-authenticatie-module 1.0.53 → 1.0.55
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/FlorydayConnectionPage.d.ts.map +1 -1
- package/dist-lib/components/floriday/FlorydayConnectionPage.js +2 -1
- package/dist-lib/components/floriday/FlorydayShellRoutesCard.d.ts +2 -0
- package/dist-lib/components/floriday/FlorydayShellRoutesCard.d.ts.map +1 -0
- package/dist-lib/components/floriday/FlorydayShellRoutesCard.js +22 -0
- 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/client.server.d.ts +2 -32082
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +1418 -6
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/cron/process-stock-queue.d.ts +44 -5
- package/dist-lib/lib/cron/process-stock-queue.d.ts.map +1 -1
- package/dist-lib/lib/cron/process-stock-queue.js +167 -96
- 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-scopes.d.ts +7 -0
- package/dist-lib/lib/floriday-scopes.d.ts.map +1 -1
- package/dist-lib/lib/floriday-scopes.js +34 -0
- package/dist-lib/lib/floriday-sync.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-sync.functions.js +12 -2
- package/dist-lib/lib/floriday.functions.d.ts +49 -12
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +221 -63
- package/dist-lib/lib/gateway/diagnostics.d.ts.map +1 -1
- package/dist-lib/lib/gateway/diagnostics.js +12 -0
- package/dist-lib/lib/gateway/floriday-get.d.ts +55 -0
- package/dist-lib/lib/gateway/floriday-get.d.ts.map +1 -0
- package/dist-lib/lib/gateway/floriday-get.js +185 -0
- package/dist-lib/lib/gateway/index.d.ts +1 -0
- package/dist-lib/lib/gateway/index.d.ts.map +1 -1
- package/dist-lib/lib/gateway/index.js +1 -0
- package/dist-lib/lib/gateway/webhook-subscribe.d.ts.map +1 -1
- package/dist-lib/lib/gateway/webhook-subscribe.js +13 -1
- package/dist-lib/lib/shell-base.d.ts +2 -0
- package/dist-lib/lib/shell-base.d.ts.map +1 -0
- package/dist-lib/lib/shell-base.js +31 -0
- package/dist-lib/lib/shell-routes.d.ts +25 -0
- package/dist-lib/lib/shell-routes.d.ts.map +1 -0
- package/dist-lib/lib/shell-routes.js +127 -0
- package/package.json +6 -489
|
@@ -16,20 +16,59 @@ export declare function isoWeekParts(input?: string | Date): {
|
|
|
16
16
|
/** Tijdelijk (netwerk/5xx/429) versus definitief (gegevensfout). */
|
|
17
17
|
export declare function isPermanentError(message: string): boolean;
|
|
18
18
|
export declare function isRateLimited(message: string): boolean;
|
|
19
|
-
type
|
|
19
|
+
export type WarehouseSource = "per_item" | "on_item" | "preferred";
|
|
20
|
+
/**
|
|
21
|
+
* Kiest het magazijn zonder te raden. Volgorde: magazijn per artikel,
|
|
22
|
+
* magazijn op het artikel, voorkeursmagazijn van de koppeling. Een kandidaat
|
|
23
|
+
* telt alleen als het id een eigen magazijn is (op id, nooit op naam).
|
|
24
|
+
*/
|
|
25
|
+
export declare function decideWarehouse(input: {
|
|
26
|
+
perItem?: string | null;
|
|
27
|
+
onItem?: string | null;
|
|
28
|
+
preferred?: string | null;
|
|
29
|
+
ownIds: Iterable<string>;
|
|
30
|
+
}): {
|
|
31
|
+
id: string;
|
|
32
|
+
source: WarehouseSource;
|
|
33
|
+
} | null;
|
|
34
|
+
export declare const SKIPPED_NO_PRICE_MESSAGE = "Prijs ontbreekt, nog niet verzonden";
|
|
35
|
+
export declare const SKIPPED_NO_WAREHOUSE_MESSAGE = "Geen voorkeursmagazijn voor deze koppeling; kies er een op de Connectie-pagina";
|
|
36
|
+
export type StockOutcome = {
|
|
37
|
+
outcome: "quantity_sent" | "skipped_no_price" | "skipped_no_warehouse" | "error";
|
|
38
|
+
availabilitySent: boolean;
|
|
39
|
+
quantitySent: boolean;
|
|
40
|
+
error: string | null;
|
|
41
|
+
permanent: boolean;
|
|
42
|
+
attemptId: string | null;
|
|
43
|
+
};
|
|
44
|
+
type WriteResult = {
|
|
20
45
|
ok: boolean;
|
|
21
|
-
|
|
46
|
+
status?: number;
|
|
22
47
|
error?: string;
|
|
23
48
|
attemptId?: string | null;
|
|
24
|
-
quantitySkipped?: string;
|
|
25
49
|
};
|
|
26
|
-
/**
|
|
27
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Bepaalt de afsluiting van een regel uit de twee Floriday-antwoorden.
|
|
52
|
+
* Puur (geen I/O) zodat het los te testen is.
|
|
53
|
+
* - quantity_sent alleen bij een 2xx op de base-supply-PATCH.
|
|
54
|
+
* - 404 op de PATCH (geen weekaanbod) = skipped_no_price, nooit verzonden.
|
|
55
|
+
* - beschikbaarheid alleen is nooit quantity_sent.
|
|
56
|
+
*/
|
|
57
|
+
export declare function decideOutcome(availability: WriteResult | null, quantity: WriteResult | null): StockOutcome;
|
|
58
|
+
/**
|
|
59
|
+
* Zet één wachtrijregel door naar Floriday. Gooit nooit.
|
|
60
|
+
* Er wordt bewust GEEN PUT met basePricePerPiece gedaan zolang het prijsplan
|
|
61
|
+
* van de Voorraad-module niet is goedgekeurd: alleen een PATCH op een
|
|
62
|
+
* bestaand weekaanbod (numberOfPieces als queryparameter, geen body).
|
|
63
|
+
*/
|
|
64
|
+
export declare function pushStockRow(supabase: SupabaseClient, env: FlorydayEnvironment, row: StockQueueRow): Promise<StockOutcome>;
|
|
28
65
|
/** Eén verwerkingsronde. Retourneert een compacte samenvatting. */
|
|
29
66
|
export declare function runStockQueueRound(supabase: SupabaseClient, limit?: number): Promise<{
|
|
30
67
|
ok: true;
|
|
31
68
|
claimed: number;
|
|
32
69
|
succeeded: number;
|
|
70
|
+
skippedNoPrice: number;
|
|
71
|
+
skippedNoWarehouse: number;
|
|
33
72
|
failed: number;
|
|
34
73
|
rateLimited: boolean;
|
|
35
74
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-stock-queue.d.ts","sourceRoot":"","sources":["../../../src/lib/cron/process-stock-queue.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"process-stock-queue.d.ts","sourceRoot":"","sources":["../../../src/lib/cron/process-stock-queue.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,0BAA0B,CAAC;AAMlC,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,kCAAkC;AAClC,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAYlF;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAazD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC1B,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG,IAAI,CAYjD;AA6CD,eAAO,MAAM,wBAAwB,wCAAwC,CAAC;AAC9E,eAAO,MAAM,4BAA4B,mFACyC,CAAC;AAEnF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,eAAe,GAAG,kBAAkB,GAAG,sBAAsB,GAAG,OAAO,CAAC;IACjF,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,KAAK,WAAW,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE/F;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,WAAW,GAAG,IAAI,EAChC,QAAQ,EAAE,WAAW,GAAG,IAAI,GAC3B,YAAY,CA0Bd;AAMD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,mBAAmB,EACxB,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,YAAY,CAAC,CAiEvB;AAeD,mEAAmE;AACnE,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,cAAc,EACxB,KAAK,SAAa,GACjB,OAAO,CAAC;IACT,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CAsCD;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAoCnB;AAOD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAUlE"}
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
// pakt het weer op.
|
|
14
14
|
// ============================================================================
|
|
15
15
|
import { florydayWrite, getActiveFlorydayEnvironment, syncShellHostRuntimeConfig, } from "../floriday.functions.js";
|
|
16
|
+
import { verifyGatewayRequest, GATEWAY_HEADER_TIMESTAMP } from "../floriday-gateway-hmac.js";
|
|
17
|
+
import { isOwnWarehouse } from "../floriday-own-config.js";
|
|
16
18
|
const BATCH_SIZE = 25;
|
|
17
19
|
/** ISO-weeknummer van vandaag. */
|
|
18
20
|
export function isoWeekParts(input) {
|
|
@@ -48,31 +50,108 @@ export function isPermanentError(message) {
|
|
|
48
50
|
export function isRateLimited(message) {
|
|
49
51
|
return /\b429\b|rate limit|too many requests/i.test(message);
|
|
50
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Kiest het magazijn zonder te raden. Volgorde: magazijn per artikel,
|
|
55
|
+
* magazijn op het artikel, voorkeursmagazijn van de koppeling. Een kandidaat
|
|
56
|
+
* telt alleen als het id een eigen magazijn is (op id, nooit op naam).
|
|
57
|
+
*/
|
|
58
|
+
export function decideWarehouse(input) {
|
|
59
|
+
const own = new Set(input.ownIds);
|
|
60
|
+
const candidates = [
|
|
61
|
+
[input.perItem, "per_item"],
|
|
62
|
+
[input.onItem, "on_item"],
|
|
63
|
+
[input.preferred, "preferred"],
|
|
64
|
+
];
|
|
65
|
+
for (const [raw, source] of candidates) {
|
|
66
|
+
const id = typeof raw === "string" ? raw.trim() : "";
|
|
67
|
+
if (id && own.has(id))
|
|
68
|
+
return { id, source };
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
51
72
|
async function resolveWarehouseId(supabase, connectionId, tradeItemId, cachedItem) {
|
|
52
|
-
const { data: pref } = await
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
const [{ data: pref }, { data: conn }, { data: whs }] = await Promise.all([
|
|
74
|
+
supabase
|
|
75
|
+
.from("trade_item_warehouse_preferences")
|
|
76
|
+
.select("warehouse_id")
|
|
77
|
+
.eq("connection_id", connectionId)
|
|
78
|
+
.eq("trade_item_id", tradeItemId)
|
|
79
|
+
.maybeSingle(),
|
|
80
|
+
supabase
|
|
81
|
+
.from("floriday_connections")
|
|
82
|
+
.select("preferred_warehouse_id")
|
|
83
|
+
.eq("id", connectionId)
|
|
84
|
+
.maybeSingle(),
|
|
85
|
+
supabase
|
|
86
|
+
.from("floriday_warehouses_cache")
|
|
87
|
+
.select("floriday_id, data")
|
|
88
|
+
.eq("connection_id", connectionId)
|
|
89
|
+
.limit(500),
|
|
90
|
+
]);
|
|
91
|
+
const ownIds = (whs ?? [])
|
|
92
|
+
.filter((w) => isOwnWarehouse({
|
|
93
|
+
isDeleted: w?.data?.isDeleted,
|
|
94
|
+
isExternal: w?.data?.isExternal,
|
|
95
|
+
hasAccess: w?.data?.hasAccess,
|
|
96
|
+
}))
|
|
97
|
+
.map((w) => String(w?.floriday_id ?? w?.data?.warehouseId ?? ""))
|
|
98
|
+
.filter(Boolean);
|
|
99
|
+
const chosen = decideWarehouse({
|
|
100
|
+
perItem: pref?.warehouse_id ?? null,
|
|
101
|
+
onItem: cachedItem?.warehouseId ?? cachedItem?.warehouse?.warehouseId ?? null,
|
|
102
|
+
preferred: conn?.preferred_warehouse_id ?? null,
|
|
103
|
+
ownIds,
|
|
104
|
+
});
|
|
105
|
+
return chosen?.id;
|
|
106
|
+
}
|
|
107
|
+
export const SKIPPED_NO_PRICE_MESSAGE = "Prijs ontbreekt, nog niet verzonden";
|
|
108
|
+
export const SKIPPED_NO_WAREHOUSE_MESSAGE = "Geen voorkeursmagazijn voor deze koppeling; kies er een op de Connectie-pagina";
|
|
109
|
+
/**
|
|
110
|
+
* Bepaalt de afsluiting van een regel uit de twee Floriday-antwoorden.
|
|
111
|
+
* Puur (geen I/O) zodat het los te testen is.
|
|
112
|
+
* - quantity_sent alleen bij een 2xx op de base-supply-PATCH.
|
|
113
|
+
* - 404 op de PATCH (geen weekaanbod) = skipped_no_price, nooit verzonden.
|
|
114
|
+
* - beschikbaarheid alleen is nooit quantity_sent.
|
|
115
|
+
*/
|
|
116
|
+
export function decideOutcome(availability, quantity) {
|
|
117
|
+
const availabilitySent = availability?.ok === true;
|
|
118
|
+
const attemptId = quantity?.attemptId ?? availability?.attemptId ?? null;
|
|
119
|
+
if (availability && !availability.ok) {
|
|
120
|
+
const message = availability.error ?? `HTTP ${availability.status}`;
|
|
121
|
+
return { outcome: "error", availabilitySent: false, quantitySent: false, error: message, permanent: isPermanentError(message), attemptId };
|
|
122
|
+
}
|
|
123
|
+
if (!quantity) {
|
|
124
|
+
return { outcome: "skipped_no_price", availabilitySent, quantitySent: false, error: SKIPPED_NO_PRICE_MESSAGE, permanent: false, attemptId };
|
|
125
|
+
}
|
|
126
|
+
if (quantity.ok) {
|
|
127
|
+
return { outcome: "quantity_sent", availabilitySent, quantitySent: true, error: null, permanent: false, attemptId };
|
|
128
|
+
}
|
|
129
|
+
if (quantity.status === 404) {
|
|
130
|
+
return {
|
|
131
|
+
outcome: "skipped_no_price",
|
|
132
|
+
availabilitySent,
|
|
133
|
+
quantitySent: false,
|
|
134
|
+
error: `${SKIPPED_NO_PRICE_MESSAGE} (geen weekaanbod in Floriday)`,
|
|
135
|
+
permanent: false,
|
|
136
|
+
attemptId,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const message = quantity.error ?? `HTTP ${quantity.status}`;
|
|
140
|
+
return { outcome: "error", availabilitySent, quantitySent: false, error: message, permanent: isPermanentError(message), attemptId };
|
|
141
|
+
}
|
|
142
|
+
function errorOutcome(message, permanent) {
|
|
143
|
+
return { outcome: "error", availabilitySent: false, quantitySent: false, error: message, permanent, attemptId: null };
|
|
71
144
|
}
|
|
72
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Zet één wachtrijregel door naar Floriday. Gooit nooit.
|
|
147
|
+
* Er wordt bewust GEEN PUT met basePricePerPiece gedaan zolang het prijsplan
|
|
148
|
+
* van de Voorraad-module niet is goedgekeurd: alleen een PATCH op een
|
|
149
|
+
* bestaand weekaanbod (numberOfPieces als queryparameter, geen body).
|
|
150
|
+
*/
|
|
73
151
|
export async function pushStockRow(supabase, env, row) {
|
|
74
|
-
const pieces = Math.max(0, Number(row.number_of_pieces ?? 0) || 0);
|
|
152
|
+
const pieces = Math.max(0, Math.floor(Number(row.number_of_pieces ?? 0) || 0));
|
|
75
153
|
const available = row.desired_available ?? pieces > 0;
|
|
154
|
+
const { year, week } = isoWeekParts();
|
|
76
155
|
try {
|
|
77
156
|
const { data: cached } = await supabase
|
|
78
157
|
.from("floriday_trade_items_cache")
|
|
@@ -81,75 +160,65 @@ export async function pushStockRow(supabase, env, row) {
|
|
|
81
160
|
.eq("floriday_id", row.trade_item_id)
|
|
82
161
|
.maybeSingle();
|
|
83
162
|
if (!cached) {
|
|
84
|
-
return
|
|
85
|
-
ok: false,
|
|
86
|
-
permanent: true,
|
|
87
|
-
error: "Dit artikel staat nog niet in de lokale Floriday-cache. Synchroniseer de artikelen en probeer opnieuw.",
|
|
88
|
-
};
|
|
163
|
+
return errorOutcome("Dit artikel staat nog niet in de lokale Floriday-cache. Synchroniseer de artikelen en probeer opnieuw.", true);
|
|
89
164
|
}
|
|
90
165
|
const item = cached.data ?? {};
|
|
91
166
|
const warehouseId = await resolveWarehouseId(supabase, row.connection_id, row.trade_item_id, item);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
let quantitySkipped;
|
|
104
|
-
if (Number.isFinite(pricePerPiece) && pricePerPiece > 0) {
|
|
105
|
-
const qty = await florydayWrite(supabase, env, {
|
|
106
|
-
module: "inventory",
|
|
107
|
-
action: "edit-weekly-base-supply",
|
|
108
|
-
method: "PUT",
|
|
109
|
-
path: `/trade-items/${row.trade_item_id}/base-supply/${year}/${week}`,
|
|
110
|
-
referenceId: row.trade_item_id,
|
|
111
|
-
idempotencyKey: `inventory:weekly-base-supply:${row.trade_item_id}:${year}:${week}:${pieces}`,
|
|
112
|
-
body: {
|
|
113
|
-
basePricePerPiece: {
|
|
114
|
-
currency: supply?.currency ?? "EUR",
|
|
115
|
-
value: pricePerPiece,
|
|
116
|
-
},
|
|
117
|
-
numberOfPieces: pieces,
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
if (!qty.ok) {
|
|
121
|
-
const message = qty.error ?? `HTTP ${qty.status}`;
|
|
122
|
-
return { ok: false, permanent: isPermanentError(message), error: message };
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
quantitySkipped =
|
|
127
|
-
"Aantal niet doorgezet: er is nog geen prijs bekend voor dit artikel.";
|
|
167
|
+
if (!warehouseId) {
|
|
168
|
+
// Niet raden: niets naar Floriday. De Voorraad-module zet de regel
|
|
169
|
+
// zelf terug op pending zodra er een magazijn is.
|
|
170
|
+
return {
|
|
171
|
+
outcome: "skipped_no_warehouse",
|
|
172
|
+
availabilitySent: false,
|
|
173
|
+
quantitySent: false,
|
|
174
|
+
error: SKIPPED_NO_WAREHOUSE_MESSAGE,
|
|
175
|
+
permanent: false,
|
|
176
|
+
attemptId: null,
|
|
177
|
+
};
|
|
128
178
|
}
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const res = await florydayWrite(supabase, env, {
|
|
179
|
+
// 1. Beschikbaarheid. Sleutel zonder aantal, zodat een latere echte
|
|
180
|
+
// aantal-verzending (eigen sleutel) nooit wordt overgeslagen.
|
|
181
|
+
const body = { available, warehouseId };
|
|
182
|
+
const availability = (await florydayWrite(supabase, env, {
|
|
134
183
|
module: "inventory",
|
|
135
184
|
action: "publish-continuous-stock",
|
|
136
185
|
method: "PUT",
|
|
137
186
|
path: `/trade-items/${row.trade_item_id}/continuous-stock`,
|
|
138
187
|
referenceId: row.trade_item_id,
|
|
139
|
-
idempotencyKey: `inventory:continuous-stock:${row.trade_item_id}:${available}:${
|
|
188
|
+
idempotencyKey: `inventory:continuous-stock:${row.trade_item_id}:${year}:${week}:${available}:${row.id}`,
|
|
140
189
|
body,
|
|
141
|
-
});
|
|
142
|
-
if (!
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
190
|
+
}));
|
|
191
|
+
if (!availability.ok)
|
|
192
|
+
return decideOutcome(availability, null);
|
|
193
|
+
// 2. Aantal: alleen PATCH op bestaand weekaanbod.
|
|
194
|
+
const quantity = (await florydayWrite(supabase, env, {
|
|
195
|
+
module: "inventory",
|
|
196
|
+
action: "patch-weekly-base-supply",
|
|
197
|
+
method: "PATCH",
|
|
198
|
+
path: `/trade-items/${row.trade_item_id}/base-supply/${year}/${week}?numberOfPieces=${pieces}`,
|
|
199
|
+
referenceId: row.trade_item_id,
|
|
200
|
+
idempotencyKey: `inventory:patch-weekly-base-supply:${row.trade_item_id}:${year}:${week}:${pieces}:${row.id}`,
|
|
201
|
+
}));
|
|
202
|
+
return decideOutcome(availability, quantity);
|
|
147
203
|
}
|
|
148
204
|
catch (e) {
|
|
149
205
|
const message = e instanceof Error ? e.message : String(e);
|
|
150
|
-
return
|
|
206
|
+
return errorOutcome(message, isPermanentError(message));
|
|
151
207
|
}
|
|
152
208
|
}
|
|
209
|
+
async function completeRow(supabase, id, o) {
|
|
210
|
+
const { error } = await supabase.rpc("complete_floriday_stock_queue_outcome", {
|
|
211
|
+
p_id: id,
|
|
212
|
+
p_outcome: o.outcome,
|
|
213
|
+
p_availability_sent: o.availabilitySent,
|
|
214
|
+
p_quantity_sent: o.quantitySent,
|
|
215
|
+
p_error: o.error,
|
|
216
|
+
p_attempt_id: o.attemptId,
|
|
217
|
+
p_permanent: o.permanent,
|
|
218
|
+
});
|
|
219
|
+
if (error)
|
|
220
|
+
console.error("[stock-queue] afsluiten mislukt:", id, error.message);
|
|
221
|
+
}
|
|
153
222
|
/** Eén verwerkingsronde. Retourneert een compacte samenvatting. */
|
|
154
223
|
export async function runStockQueueRound(supabase, limit = BATCH_SIZE) {
|
|
155
224
|
const env = await getActiveFlorydayEnvironment(supabase);
|
|
@@ -158,48 +227,50 @@ export async function runStockQueueRound(supabase, limit = BATCH_SIZE) {
|
|
|
158
227
|
throw new Error(error.message);
|
|
159
228
|
const rows = (claimed ?? []);
|
|
160
229
|
let succeeded = 0;
|
|
230
|
+
let skippedNoPrice = 0;
|
|
231
|
+
let skippedNoWarehouse = 0;
|
|
161
232
|
let failed = 0;
|
|
162
233
|
let rateLimited = false;
|
|
163
234
|
for (const row of rows) {
|
|
164
235
|
if (rateLimited) {
|
|
165
|
-
|
|
166
|
-
await supabase.rpc("complete_floriday_stock_queue", {
|
|
167
|
-
p_id: row.id,
|
|
168
|
-
p_ok: false,
|
|
169
|
-
p_error: "Snelheidslimiet van Floriday bereikt; volgende ronde opnieuw.",
|
|
170
|
-
p_permanent: false,
|
|
171
|
-
p_attempt_id: null,
|
|
172
|
-
});
|
|
236
|
+
await completeRow(supabase, row.id, errorOutcome("Snelheidslimiet van Floriday bereikt; volgende ronde opnieuw.", false));
|
|
173
237
|
continue;
|
|
174
238
|
}
|
|
175
239
|
const outcome = await pushStockRow(supabase, env, row);
|
|
176
|
-
if (outcome.
|
|
240
|
+
if (outcome.outcome === "quantity_sent")
|
|
177
241
|
succeeded += 1;
|
|
242
|
+
else if (outcome.outcome === "skipped_no_price")
|
|
243
|
+
skippedNoPrice += 1;
|
|
244
|
+
else if (outcome.outcome === "skipped_no_warehouse")
|
|
245
|
+
skippedNoWarehouse += 1;
|
|
178
246
|
else {
|
|
179
247
|
failed += 1;
|
|
180
248
|
if (outcome.error && isRateLimited(outcome.error))
|
|
181
249
|
rateLimited = true;
|
|
182
250
|
}
|
|
183
|
-
await supabase.
|
|
184
|
-
p_id: row.id,
|
|
185
|
-
p_ok: outcome.ok,
|
|
186
|
-
p_error: outcome.ok ? outcome.quantitySkipped ?? null : outcome.error ?? "Onbekende fout",
|
|
187
|
-
p_permanent: outcome.permanent ?? false,
|
|
188
|
-
p_attempt_id: outcome.attemptId ?? null,
|
|
189
|
-
});
|
|
251
|
+
await completeRow(supabase, row.id, outcome);
|
|
190
252
|
}
|
|
191
|
-
return { ok: true, claimed: rows.length, succeeded, failed, rateLimited };
|
|
253
|
+
return { ok: true, claimed: rows.length, succeeded, skippedNoPrice, skippedNoWarehouse, failed, rateLimited };
|
|
192
254
|
}
|
|
193
255
|
/**
|
|
194
256
|
* Cron-handler, zelfde vorm en beveiliging als de overige cron-routes:
|
|
195
257
|
* `apikey`-header moet gelijk zijn aan `SUPABASE_PUBLISHABLE_KEY`.
|
|
196
258
|
*/
|
|
197
259
|
export async function handleProcessStockQueue(request, supabase) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
260
|
+
// Voorkeur: gedeelde HMAC-handtekening. Terugval (tijdelijk, tot de
|
|
261
|
+
// herinplanning in een nieuwe Shell): de bestaande apikey-header.
|
|
262
|
+
let authorized = false;
|
|
263
|
+
if (request.headers.get(GATEWAY_HEADER_TIMESTAMP)) {
|
|
264
|
+
const auth = await verifyGatewayRequest(request.clone());
|
|
265
|
+
authorized = auth.ok;
|
|
202
266
|
}
|
|
267
|
+
if (!authorized) {
|
|
268
|
+
const apikey = request.headers.get("apikey") ?? request.headers.get("x-api-key");
|
|
269
|
+
const expected = process.env.SUPABASE_PUBLISHABLE_KEY;
|
|
270
|
+
authorized = !!expected && !!apikey && apikey === expected;
|
|
271
|
+
}
|
|
272
|
+
if (!authorized)
|
|
273
|
+
return new Response("Unauthorized", { status: 401 });
|
|
203
274
|
// Zelfherstel van de shell-host (fire-and-forget): draait elke minuut mee,
|
|
204
275
|
// zodat een nieuwe of verhuisde shell binnen één cron-tick de juiste
|
|
205
276
|
// callback-URL in `module_runtime_config` heeft staan. De functie cachet
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floriday-gln.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-gln.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAaxD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// GS1 GLN-validatie (zonder serverimports).
|
|
2
|
+
/**
|
|
3
|
+
* Valideert een GS1 GLN: exact 13 cijfers met geldige check digit.
|
|
4
|
+
* Retourneert null als geldig, anders een nl-foutmelding.
|
|
5
|
+
*/
|
|
6
|
+
export function validateGln(input) {
|
|
7
|
+
const v = input.trim();
|
|
8
|
+
if (!v)
|
|
9
|
+
return "GLN-code is verplicht";
|
|
10
|
+
if (!/^\d{13}$/.test(v))
|
|
11
|
+
return "GLN-code moet uit precies 13 cijfers bestaan";
|
|
12
|
+
const digits = v.split("").map(Number);
|
|
13
|
+
// GS1 mod-10 voor GLN-13: positie 1 (meest links) ×1, positie 2 ×3, … positie 12 ×3.
|
|
14
|
+
let sum = 0;
|
|
15
|
+
for (let i = 0; i < 12; i++) {
|
|
16
|
+
sum += digits[i] * (i % 2 === 0 ? 1 : 3);
|
|
17
|
+
}
|
|
18
|
+
const check = (10 - (sum % 10)) % 10;
|
|
19
|
+
if (check !== digits[12])
|
|
20
|
+
return "GLN-code heeft een ongeldig controlecijfer";
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export interface OwnWarehouseInput {
|
|
2
|
+
id: string;
|
|
3
|
+
name?: string | null;
|
|
4
|
+
isDeleted?: boolean | null;
|
|
5
|
+
isExternal?: boolean | null;
|
|
6
|
+
hasAccess?: boolean | null;
|
|
7
|
+
isDefault?: boolean | null;
|
|
8
|
+
}
|
|
9
|
+
/** Eigen magazijn: niet verwijderd, niet extern, met toegang. */
|
|
10
|
+
export declare function isOwnWarehouse(w: {
|
|
11
|
+
isDeleted?: boolean | null;
|
|
12
|
+
isExternal?: boolean | null;
|
|
13
|
+
hasAccess?: boolean | null;
|
|
14
|
+
}): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Leesbare naam voor een magazijn uit de cache. Lege tekst telt als
|
|
17
|
+
* ontbrekend. Volgorde: naam, adresregel + plaats, plaats, GLN, id.
|
|
18
|
+
* Alleen voor weergave; de keuze loopt altijd op id.
|
|
19
|
+
*/
|
|
20
|
+
export declare function warehouseLabel(row: {
|
|
21
|
+
name?: unknown;
|
|
22
|
+
gln_code?: unknown;
|
|
23
|
+
floriday_id?: unknown;
|
|
24
|
+
data?: any;
|
|
25
|
+
}): string;
|
|
26
|
+
export type PreferredWarehouseDecision = {
|
|
27
|
+
kind: "keep";
|
|
28
|
+
id: string;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "missing";
|
|
31
|
+
id: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: "fill";
|
|
34
|
+
id: string;
|
|
35
|
+
reason: "single" | "default";
|
|
36
|
+
} | {
|
|
37
|
+
kind: "choice_needed";
|
|
38
|
+
} | {
|
|
39
|
+
kind: "none";
|
|
40
|
+
};
|
|
41
|
+
export declare function decidePreferredWarehouse(input: {
|
|
42
|
+
currentId: string | null | undefined;
|
|
43
|
+
warehouses: OwnWarehouseInput[];
|
|
44
|
+
}): PreferredWarehouseDecision;
|
|
45
|
+
export type GlnDecision = {
|
|
46
|
+
kind: "keep";
|
|
47
|
+
gln: string;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "fill";
|
|
50
|
+
gln: string;
|
|
51
|
+
} | {
|
|
52
|
+
kind: "mismatch";
|
|
53
|
+
stored: string;
|
|
54
|
+
fromFloriday: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: "unavailable";
|
|
57
|
+
stored: string | null;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "invalid";
|
|
60
|
+
stored: string | null;
|
|
61
|
+
fromFloriday: string;
|
|
62
|
+
error: string;
|
|
63
|
+
};
|
|
64
|
+
export declare function decideGln(input: {
|
|
65
|
+
stored: string | null | undefined;
|
|
66
|
+
fromFloriday: string | null | undefined;
|
|
67
|
+
}): GlnDecision;
|
|
68
|
+
//# sourceMappingURL=floriday-own-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floriday-own-config.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-own-config.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5B;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,CAAC,EAAE;IAChC,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5B,GAAG,OAAO,CAEV;AAQD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,GAAG,MAAM,CAcT;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,UAAU,EAAE,iBAAiB,EAAE,CAAC;CACjC,GAAG,0BAA0B,CAa7B;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACzC,GAAG,WAAW,CASd"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Pure beslisregels voor GLN en voorkeursmagazijn van de eigen organisatie.
|
|
3
|
+
// Geen serverimports: bruikbaar in server, client en tests.
|
|
4
|
+
// Regel: alleen lege velden worden automatisch gevuld, altijd op id; een
|
|
5
|
+
// bestaande (gebruikers)keuze wordt nooit overschreven.
|
|
6
|
+
// ============================================================================
|
|
7
|
+
import { validateGln } from "./floriday-gln.js";
|
|
8
|
+
/** Eigen magazijn: niet verwijderd, niet extern, met toegang. */
|
|
9
|
+
export function isOwnWarehouse(w) {
|
|
10
|
+
return w.isDeleted !== true && w.isExternal !== true && w.hasAccess !== false;
|
|
11
|
+
}
|
|
12
|
+
function txt(v) {
|
|
13
|
+
if (typeof v !== "string")
|
|
14
|
+
return null;
|
|
15
|
+
const t = v.trim();
|
|
16
|
+
return t ? t : null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Leesbare naam voor een magazijn uit de cache. Lege tekst telt als
|
|
20
|
+
* ontbrekend. Volgorde: naam, adresregel + plaats, plaats, GLN, id.
|
|
21
|
+
* Alleen voor weergave; de keuze loopt altijd op id.
|
|
22
|
+
*/
|
|
23
|
+
export function warehouseLabel(row) {
|
|
24
|
+
const d = row?.data ?? {};
|
|
25
|
+
const name = txt(row?.name) ?? txt(d?.name);
|
|
26
|
+
if (name)
|
|
27
|
+
return name;
|
|
28
|
+
const addr = d?.location?.address ?? d?.address ?? {};
|
|
29
|
+
const line = txt(addr?.addressLine) ?? txt(addr?.street);
|
|
30
|
+
const city = txt(addr?.city) ?? txt(d?.location?.city);
|
|
31
|
+
if (line && city)
|
|
32
|
+
return `${line}, ${city}`;
|
|
33
|
+
if (line)
|
|
34
|
+
return line;
|
|
35
|
+
if (city)
|
|
36
|
+
return city;
|
|
37
|
+
const gln = txt(row?.gln_code) ?? txt(d?.location?.gln);
|
|
38
|
+
if (gln)
|
|
39
|
+
return `Magazijn zonder naam (GLN ${gln})`;
|
|
40
|
+
const id = txt(row?.floriday_id) ?? txt(d?.warehouseId);
|
|
41
|
+
return id ? `Magazijn zonder naam (id ${id.slice(0, 8)}…)` : "Magazijn zonder naam";
|
|
42
|
+
}
|
|
43
|
+
export function decidePreferredWarehouse(input) {
|
|
44
|
+
const own = input.warehouses.filter((w) => w.id && isOwnWarehouse(w));
|
|
45
|
+
const current = input.currentId?.trim() || null;
|
|
46
|
+
if (current) {
|
|
47
|
+
return own.some((w) => w.id === current)
|
|
48
|
+
? { kind: "keep", id: current }
|
|
49
|
+
: { kind: "missing", id: current };
|
|
50
|
+
}
|
|
51
|
+
if (own.length === 0)
|
|
52
|
+
return { kind: "none" };
|
|
53
|
+
if (own.length === 1)
|
|
54
|
+
return { kind: "fill", id: own[0].id, reason: "single" };
|
|
55
|
+
const defaults = own.filter((w) => w.isDefault === true);
|
|
56
|
+
if (defaults.length === 1)
|
|
57
|
+
return { kind: "fill", id: defaults[0].id, reason: "default" };
|
|
58
|
+
return { kind: "choice_needed" };
|
|
59
|
+
}
|
|
60
|
+
export function decideGln(input) {
|
|
61
|
+
const stored = input.stored?.trim() || null;
|
|
62
|
+
const remote = input.fromFloriday?.trim() || null;
|
|
63
|
+
if (!remote)
|
|
64
|
+
return { kind: "unavailable", stored };
|
|
65
|
+
const err = validateGln(remote);
|
|
66
|
+
if (err)
|
|
67
|
+
return { kind: "invalid", stored, fromFloriday: remote, error: err };
|
|
68
|
+
if (!stored)
|
|
69
|
+
return { kind: "fill", gln: remote };
|
|
70
|
+
if (stored === remote)
|
|
71
|
+
return { kind: "keep", gln: stored };
|
|
72
|
+
return { kind: "mismatch", stored, fromFloriday: remote };
|
|
73
|
+
}
|
|
@@ -26,4 +26,11 @@ export declare const FLORYDAY_CLOCK_SUPPLY_PERMISSION_MESSAGE = "Floriday heeft
|
|
|
26
26
|
export declare const FLORYDAY_CONTRACT_PERMISSION_MESSAGE = "Floriday heeft de Contracten-module nog niet vrijgegeven voor deze koppeling. Laat dit recht in Floriday activeren en vernieuw daarna de verbinding.";
|
|
27
27
|
export declare const FLORYDAY_SALES_STRATEGY_PERMISSION_MESSAGE = "Floriday heeft Verkoopstrategie\u00EBn nog niet vrijgegeven voor deze koppeling. Laat het recht `sales-strategy:read` in Floriday activeren en vernieuw daarna de verbinding.";
|
|
28
28
|
export declare const FLORYDAY_SUPPLY_PERMISSION_MESSAGE = "Floriday heeft het recht `supply:read` (aanvoerregels met prijzen) nog niet vrijgegeven voor deze koppeling. Laat dit recht in Floriday activeren en vernieuw daarna de verbinding.";
|
|
29
|
+
/**
|
|
30
|
+
* Toont een Floriday-foutbody/-bericht aantoonbaar een ontbrekend recht/scope?
|
|
31
|
+
* Een kale `403 Forbidden` (bv. onbekend pad bij Floriday's voordeur) telt NIET.
|
|
32
|
+
*/
|
|
33
|
+
export declare function floridayErrorShowsMissingPermission(text: string | null | undefined): boolean;
|
|
34
|
+
/** Scopes uit een JWT-toegangstoken lezen (alleen payload; token nooit loggen). */
|
|
35
|
+
export declare function scopesFromAccessToken(token: string): string[] | null;
|
|
29
36
|
//# sourceMappingURL=floriday-scopes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floriday-scopes.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-scopes.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,2QAe3B,CAAC;AAOX,eAAO,MAAM,4BAA4B,sDAG/B,CAAC;AACX,eAAO,MAAM,iCAAiC,gCAAiC,CAAC;AAChF,eAAO,MAAM,kCAAkC,iCAAkC,CAAC;AAElF,eAAO,MAAM,wBAAwB,8CAG3B,CAAC;AACX,eAAO,MAAM,6BAA6B,4BAA6B,CAAC;AACxE,eAAO,MAAM,8BAA8B,6BAA8B,CAAC;AAM1E,eAAO,MAAM,8BAA8B,0DAGjC,CAAC;AACX,eAAO,MAAM,mCAAmC,kCAAmC,CAAC;AACpF,eAAO,MAAM,oCAAoC,mCAAoC,CAAC;AAKtF,eAAO,MAAM,uBAAuB,QAAqC,CAAC;AAE1E,eAAO,MAAM,2BAA2B,QAG7B,CAAC;AACZ,eAAO,MAAM,gCAAgC,QAGlC,CAAC;AACZ,eAAO,MAAM,iCAAiC,QAGnC,CAAC;AAEZ,eAAO,MAAM,uBAAuB,QAGzB,CAAC;AACZ,eAAO,MAAM,4BAA4B,QAG9B,CAAC;AACZ,eAAO,MAAM,6BAA6B,QAG/B,CAAC;AAEZ,eAAO,MAAM,6BAA6B,QAG/B,CAAC;AACZ,eAAO,MAAM,kCAAkC,QAGpC,CAAC;AACZ,eAAO,MAAM,mCAAmC,QAGrC,CAAC;AAGZ,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAQ,GAAG,MAAM,CA4C5E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,eAAO,MAAM,wCAAwC,mJAC6F,CAAC;AAEnJ,eAAO,MAAM,oCAAoC,yJACuG,CAAC;AAEzJ,eAAO,MAAM,0CAA0C,kLACqH,CAAC;AAE7K,eAAO,MAAM,kCAAkC,wLACwI,CAAC"}
|
|
1
|
+
{"version":3,"file":"floriday-scopes.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-scopes.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,2QAe3B,CAAC;AAOX,eAAO,MAAM,4BAA4B,sDAG/B,CAAC;AACX,eAAO,MAAM,iCAAiC,gCAAiC,CAAC;AAChF,eAAO,MAAM,kCAAkC,iCAAkC,CAAC;AAElF,eAAO,MAAM,wBAAwB,8CAG3B,CAAC;AACX,eAAO,MAAM,6BAA6B,4BAA6B,CAAC;AACxE,eAAO,MAAM,8BAA8B,6BAA8B,CAAC;AAM1E,eAAO,MAAM,8BAA8B,0DAGjC,CAAC;AACX,eAAO,MAAM,mCAAmC,kCAAmC,CAAC;AACpF,eAAO,MAAM,oCAAoC,mCAAoC,CAAC;AAKtF,eAAO,MAAM,uBAAuB,QAAqC,CAAC;AAE1E,eAAO,MAAM,2BAA2B,QAG7B,CAAC;AACZ,eAAO,MAAM,gCAAgC,QAGlC,CAAC;AACZ,eAAO,MAAM,iCAAiC,QAGnC,CAAC;AAEZ,eAAO,MAAM,uBAAuB,QAGzB,CAAC;AACZ,eAAO,MAAM,4BAA4B,QAG9B,CAAC;AACZ,eAAO,MAAM,6BAA6B,QAG/B,CAAC;AAEZ,eAAO,MAAM,6BAA6B,QAG/B,CAAC;AACZ,eAAO,MAAM,kCAAkC,QAGpC,CAAC;AACZ,eAAO,MAAM,mCAAmC,QAGrC,CAAC;AAGZ,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAQ,GAAG,MAAM,CA4C5E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,eAAO,MAAM,wCAAwC,mJAC6F,CAAC;AAEnJ,eAAO,MAAM,oCAAoC,yJACuG,CAAC;AAEzJ,eAAO,MAAM,0CAA0C,kLACqH,CAAC;AAE7K,eAAO,MAAM,kCAAkC,wLACwI,CAAC;AAExL;;;GAGG;AACH,wBAAgB,mCAAmC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAY5F;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAapE"}
|
|
@@ -129,3 +129,37 @@ export const FLORYDAY_CLOCK_SUPPLY_PERMISSION_MESSAGE = "Floriday heeft Klokaanv
|
|
|
129
129
|
export const FLORYDAY_CONTRACT_PERMISSION_MESSAGE = "Floriday heeft de Contracten-module nog niet vrijgegeven voor deze koppeling. Laat dit recht in Floriday activeren en vernieuw daarna de verbinding.";
|
|
130
130
|
export const FLORYDAY_SALES_STRATEGY_PERMISSION_MESSAGE = "Floriday heeft Verkoopstrategieën nog niet vrijgegeven voor deze koppeling. Laat het recht `sales-strategy:read` in Floriday activeren en vernieuw daarna de verbinding.";
|
|
131
131
|
export const FLORYDAY_SUPPLY_PERMISSION_MESSAGE = "Floriday heeft het recht `supply:read` (aanvoerregels met prijzen) nog niet vrijgegeven voor deze koppeling. Laat dit recht in Floriday activeren en vernieuw daarna de verbinding.";
|
|
132
|
+
/**
|
|
133
|
+
* Toont een Floriday-foutbody/-bericht aantoonbaar een ontbrekend recht/scope?
|
|
134
|
+
* Een kale `403 Forbidden` (bv. onbekend pad bij Floriday's voordeur) telt NIET.
|
|
135
|
+
*/
|
|
136
|
+
export function floridayErrorShowsMissingPermission(text) {
|
|
137
|
+
const t = String(text ?? "").toLowerCase();
|
|
138
|
+
return (t.includes("insufficient_scope") ||
|
|
139
|
+
t.includes("insufficient scope") ||
|
|
140
|
+
t.includes("missing scope") ||
|
|
141
|
+
t.includes("scope") ||
|
|
142
|
+
t.includes("permission") ||
|
|
143
|
+
t.includes("policy evaluation failed") ||
|
|
144
|
+
t.includes("access_denied") ||
|
|
145
|
+
t.includes("not authorized for"));
|
|
146
|
+
}
|
|
147
|
+
/** Scopes uit een JWT-toegangstoken lezen (alleen payload; token nooit loggen). */
|
|
148
|
+
export function scopesFromAccessToken(token) {
|
|
149
|
+
try {
|
|
150
|
+
const part = token.split(".")[1];
|
|
151
|
+
if (!part)
|
|
152
|
+
return null;
|
|
153
|
+
const b64 = part.replace(/-/g, "+").replace(/_/g, "/");
|
|
154
|
+
const json = JSON.parse(atob(b64 + "=".repeat((4 - (b64.length % 4)) % 4)));
|
|
155
|
+
const s = json.scope ?? json.scp;
|
|
156
|
+
if (Array.isArray(s))
|
|
157
|
+
return s.map(String);
|
|
158
|
+
if (typeof s === "string")
|
|
159
|
+
return s.split(/\s+/).filter(Boolean);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|