@flowselections/floriday-authenticatie-module 1.0.74 → 1.0.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist-lib/components/floriday/FlorydayApiLogPage.d.ts.map +1 -1
  2. package/dist-lib/components/floriday/FlorydayApiLogPage.js +12 -1
  3. package/dist-lib/components/floriday/FlorydayConnectionPage.d.ts.map +1 -1
  4. package/dist-lib/components/floriday/FlorydayConnectionPage.js +2 -1
  5. package/dist-lib/components/floriday/FlorydayCronStallBanner.d.ts +3 -0
  6. package/dist-lib/components/floriday/FlorydayCronStallBanner.d.ts.map +1 -0
  7. package/dist-lib/components/floriday/FlorydayCronStallBanner.js +13 -0
  8. package/dist-lib/integrations/supabase/types.d.ts +904 -0
  9. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  10. package/dist-lib/lib/cron/process-stock-queue.d.ts +5 -0
  11. package/dist-lib/lib/cron/process-stock-queue.d.ts.map +1 -1
  12. package/dist-lib/lib/cron/process-stock-queue.js +31 -1
  13. package/dist-lib/lib/cron/retry-floriday-documents.d.ts.map +1 -1
  14. package/dist-lib/lib/cron/retry-floriday-documents.js +14 -1
  15. package/dist-lib/lib/document-version.d.ts +33 -0
  16. package/dist-lib/lib/document-version.d.ts.map +1 -0
  17. package/dist-lib/lib/document-version.js +55 -0
  18. package/dist-lib/lib/floriday-api-log.functions.d.ts +1 -0
  19. package/dist-lib/lib/floriday-api-log.functions.d.ts.map +1 -1
  20. package/dist-lib/lib/floriday-api-log.functions.js +1 -1
  21. package/dist-lib/lib/floriday-api-log.server.js +1 -1
  22. package/dist-lib/lib/floriday-auction-letters.functions.d.ts.map +1 -1
  23. package/dist-lib/lib/floriday-auction-letters.functions.js +5 -8
  24. package/dist-lib/lib/floriday-cron-status.functions.d.ts +11 -0
  25. package/dist-lib/lib/floriday-cron-status.functions.d.ts.map +1 -0
  26. package/dist-lib/lib/floriday-cron-status.functions.js +9 -0
  27. package/dist-lib/lib/floriday-labels.functions.d.ts +2 -0
  28. package/dist-lib/lib/floriday-labels.functions.d.ts.map +1 -1
  29. package/dist-lib/lib/floriday-labels.functions.js +7 -8
  30. package/dist-lib/lib/floriday-stickers.functions.d.ts +2 -0
  31. package/dist-lib/lib/floriday-stickers.functions.d.ts.map +1 -1
  32. package/dist-lib/lib/floriday-stickers.functions.js +7 -8
  33. package/dist-lib/lib/floriday-sync.functions.d.ts +690 -0
  34. package/dist-lib/lib/floriday-sync.functions.d.ts.map +1 -1
  35. package/dist-lib/lib/floriday-sync.functions.js +16 -2
  36. package/dist-lib/lib/floriday-tray-stickers.functions.d.ts +29 -4
  37. package/dist-lib/lib/floriday-tray-stickers.functions.d.ts.map +1 -1
  38. package/dist-lib/lib/floriday-tray-stickers.functions.js +61 -60
  39. package/dist-lib/lib/floriday.functions.d.ts +13 -4
  40. package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
  41. package/dist-lib/lib/floriday.functions.js +70 -18
  42. package/dist-lib/lib/gateway/customer-stickers.d.ts +93 -0
  43. package/dist-lib/lib/gateway/customer-stickers.d.ts.map +1 -0
  44. package/dist-lib/lib/gateway/customer-stickers.js +279 -0
  45. package/dist-lib/lib/gateway/floriday-error-map.d.ts +11 -0
  46. package/dist-lib/lib/gateway/floriday-error-map.d.ts.map +1 -0
  47. package/dist-lib/lib/gateway/floriday-error-map.js +30 -0
  48. package/dist-lib/lib/gateway/fulfillment-order-send.d.ts.map +1 -1
  49. package/dist-lib/lib/gateway/fulfillment-order-send.js +19 -2
  50. package/dist-lib/lib/gateway/fulfillment-order-status.d.ts.map +1 -1
  51. package/dist-lib/lib/gateway/fulfillment-order-status.js +5 -3
  52. package/dist-lib/lib/gateway/fulfillment-order-validate.d.ts +8 -0
  53. package/dist-lib/lib/gateway/fulfillment-order-validate.d.ts.map +1 -0
  54. package/dist-lib/lib/gateway/fulfillment-order-validate.js +56 -0
  55. package/dist-lib/lib/gateway/index.d.ts +1 -0
  56. package/dist-lib/lib/gateway/index.d.ts.map +1 -1
  57. package/dist-lib/lib/gateway/index.js +1 -0
  58. package/dist-lib/lib/gateway/pdf.d.ts +4 -1
  59. package/dist-lib/lib/gateway/pdf.d.ts.map +1 -1
  60. package/dist-lib/lib/gateway/pdf.js +26 -4
  61. package/dist-lib/lib/module-version.d.ts +1 -1
  62. package/dist-lib/lib/module-version.js +1 -1
  63. package/dist-lib/lib/shell-routes.d.ts +1 -1
  64. package/dist-lib/lib/shell-routes.d.ts.map +1 -1
  65. package/dist-lib/lib/shell-routes.js +1 -0
  66. package/package.json +11 -2
@@ -0,0 +1,279 @@
1
+ // Gateway: klantstickers afmelden en stickeraanvragen van kopers.
2
+ // Gecontroleerd tegen Suppliers API 2026v1 (staging Swagger, 15-10-2026):
3
+ // - PATCH /customer-stickers/handled?stickerIds=<uuid>&stickerIds=<uuid>
4
+ // (query, collectionFormat multi; geen body; 200 zonder inhoud) → isHandled=true.
5
+ // - GET /customer-sticker-upload-requests/sync/{sequenceNumber} → SyncResultOfCustomerStickerUploadRequest
6
+ // - GET /customer-sticker-upload-requests/{id}/pdf-preview → bestand
7
+ // - PATCH /customer-sticker-upload-requests/{id}/accept|decline (geen body; 200)
8
+ // Status: PENDING | APPROVED | REJECTED | EXPIRED | DELETED.
9
+ // Deze module beslist nooit zelf: Afhandeling kiest accept of decline.
10
+ import { SUPPLIERS_API_VERSION, florydayFetch, florydayWrite, getActiveFlorydayCredentials, syncFloridayEntityBySequence, } from "../floriday.functions.js";
11
+ import { mapFloridayFailure } from "./floriday-error-map.js";
12
+ import { storeVersionedDocument } from "../document-version.js";
13
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14
+ const BUCKET = "floriday-customer-stickers";
15
+ const MAX_STICKER_IDS = 100;
16
+ async function connectionFor(supabase, env) {
17
+ const conn = await getActiveFlorydayCredentials(supabase, env);
18
+ return conn ? { id: conn.id } : null;
19
+ }
20
+ // ---------------------------------------------------------------------------
21
+ // Afmelden
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * Meldt stickers af bij Floriday. Herhaling is veilig: Floriday zet alleen
25
+ * isHandled=true; dezelfde set id's heeft één idempotentiesleutel. De cache
26
+ * wordt pas bijgewerkt na een 2xx; bij een fout blijft alles staan.
27
+ */
28
+ export async function runCustomerStickersHandled(supabase, input) {
29
+ const ids = Array.from(new Set((input.stickerIds ?? []).map((s) => String(s).trim()).filter(Boolean))).sort();
30
+ if (ids.length === 0 || ids.length > MAX_STICKER_IDS) {
31
+ return { ok: false, status: 400, code: "invalid_request", error: `stickerIds: 1 tot ${MAX_STICKER_IDS} id's` };
32
+ }
33
+ const bad = ids.filter((i) => !UUID.test(i));
34
+ if (bad.length)
35
+ return { ok: false, status: 400, code: "invalid_request", error: `Geen uuid: ${bad.join(", ")}` };
36
+ const conn = await connectionFor(supabase, input.environment);
37
+ if (!conn)
38
+ return { ok: false, status: 409, code: "no_active_connection", error: "Geen actieve Floriday-koppeling" };
39
+ const qs = ids.map((i) => `stickerIds=${encodeURIComponent(i)}`).join("&");
40
+ const res = await florydayWrite(supabase, input.environment, {
41
+ module: "customer-stickers",
42
+ action: "customer-stickers-handled",
43
+ method: "PATCH",
44
+ path: `/customer-stickers/handled?${qs}`,
45
+ referenceId: ids.length === 1 ? ids[0] : `${ids.length} stickers`,
46
+ idempotencyKey: `customer-stickers-handled:${input.environment}:${ids.join(",")}`,
47
+ caller: input.caller ?? "gateway",
48
+ });
49
+ if (!res.ok) {
50
+ const m = mapFloridayFailure(res.status, res.data);
51
+ return { ok: false, status: m.status, code: m.code, error: res.error ?? `Floriday ${res.status}`, floridayErrors: m.floridayErrors };
52
+ }
53
+ for (const id of ids) {
54
+ const { data: row } = await supabase.from("floriday_customer_stickers_cache")
55
+ .select("data").eq("connection_id", conn.id).eq("floriday_id", id).maybeSingle();
56
+ if (row) {
57
+ await supabase.from("floriday_customer_stickers_cache")
58
+ .update({ data: { ...row.data, isHandled: true } })
59
+ .eq("connection_id", conn.id).eq("floriday_id", id);
60
+ }
61
+ }
62
+ return { ok: true, stickerIds: ids };
63
+ }
64
+ /** Inhaalronde op de sequence-sync; ook gebruikt door de sticker-cron. */
65
+ export async function syncStickerUploadRequests(supabase, env, connectionId, opts = {}) {
66
+ return syncFloridayEntityBySequence(supabase, env, connectionId, {
67
+ entityType: "customer-sticker-upload-requests",
68
+ maxSequenceEndpoint: `/${SUPPLIERS_API_VERSION}/customer-sticker-upload-requests/current-max-sequence`,
69
+ bySequenceEndpointBase: `/${SUPPLIERS_API_VERSION}/customer-sticker-upload-requests/sync`,
70
+ maxBatches: opts.maxBatches,
71
+ deadlineMs: opts.deadlineMs,
72
+ onBatch: async (items) => {
73
+ const stickerIds = Array.from(new Set(items.map((i) => i?.customerStickerId).filter(Boolean).map(String)));
74
+ const soByS = new Map();
75
+ if (stickerIds.length) {
76
+ const { data } = await supabase.from("floriday_customer_stickers_cache")
77
+ .select("floriday_id, sales_order_id").eq("connection_id", connectionId).in("floriday_id", stickerIds);
78
+ for (const r of (data ?? []))
79
+ soByS.set(String(r.floriday_id), r.sales_order_id ?? null);
80
+ }
81
+ const rows = items
82
+ .filter((i) => i?.customerStickerUploadRequestId)
83
+ .map((i) => ({
84
+ connection_id: connectionId,
85
+ floriday_id: String(i.customerStickerUploadRequestId),
86
+ customer_sticker_id: i.customerStickerId ?? null,
87
+ // Orderkoppeling via de sticker (op id); het schema heeft geen salesOrderId op de aanvraag.
88
+ sales_order_id: i.customerStickerId ? soByS.get(String(i.customerStickerId)) ?? null : null,
89
+ status: i.status ?? null,
90
+ expires_on: i.expiresOn ?? null,
91
+ responded_on: i.respondedOn ?? null,
92
+ sequence_number: Number(i.sequenceNumber ?? 0),
93
+ data: i,
94
+ fetched_at: new Date().toISOString(),
95
+ }));
96
+ if (rows.length) {
97
+ const { error } = await supabase.from("floriday_customer_sticker_upload_requests_cache")
98
+ .upsert(rows, { onConflict: "connection_id,floriday_id" });
99
+ if (error)
100
+ throw new Error(`Stickeraanvragen opslaan: ${error.message}`);
101
+ }
102
+ },
103
+ });
104
+ }
105
+ /** Pure regel: alleen PENDING en niet verlopen mag beantwoord worden. */
106
+ export function canRespondToUploadRequest(status, expiresOn, now = Date.now()) {
107
+ const expired = !!expiresOn && Date.parse(expiresOn) <= now;
108
+ return { expired, canRespond: status === "PENDING" && !expired };
109
+ }
110
+ function toRequest(r, now = Date.now()) {
111
+ const d = r.data ?? {};
112
+ const { expired, canRespond } = canRespondToUploadRequest(r.status ?? null, r.expires_on ?? null, now);
113
+ return {
114
+ customerStickerUploadRequestId: String(r.floriday_id),
115
+ customerStickerId: r.customer_sticker_id ?? null,
116
+ salesOrderId: r.sales_order_id ?? null,
117
+ status: r.status ?? null,
118
+ expiresOn: r.expires_on ?? null,
119
+ respondedOn: r.responded_on ?? null,
120
+ addedOn: d.addedOn ?? null,
121
+ stickerFileInformation: d.stickerFileInformation ?? null,
122
+ expired,
123
+ canRespond,
124
+ };
125
+ }
126
+ export async function runStickerUploadRequestsList(supabase, input) {
127
+ const conn = await connectionFor(supabase, input.environment);
128
+ if (!conn)
129
+ return { ok: false, status: 409, code: "no_active_connection", error: "Geen actieve Floriday-koppeling" };
130
+ if (input.refresh !== false) {
131
+ try {
132
+ await syncStickerUploadRequests(supabase, input.environment, conn.id, { maxBatches: 3, deadlineMs: Date.now() + 8000 });
133
+ }
134
+ catch { /* lokale stand blijft bruikbaar */ }
135
+ }
136
+ let q = supabase.from("floriday_customer_sticker_upload_requests_cache")
137
+ .select("floriday_id, customer_sticker_id, sales_order_id, status, expires_on, responded_on, data")
138
+ .eq("connection_id", conn.id).order("expires_on", { ascending: true }).limit(500);
139
+ if (input.salesOrderIds?.length)
140
+ q = q.in("sales_order_id", input.salesOrderIds);
141
+ if (input.customerStickerIds?.length)
142
+ q = q.in("customer_sticker_id", input.customerStickerIds);
143
+ if (input.status)
144
+ q = q.eq("status", input.status);
145
+ const { data, error } = await q;
146
+ if (error)
147
+ return { ok: false, status: 500, code: "internal_error", error: error.message };
148
+ return { ok: true, requests: (data ?? []).map((r) => toRequest(r)) };
149
+ }
150
+ export async function runStickerUploadRequestPdf(supabase, input) {
151
+ if (!UUID.test(input.requestId ?? ""))
152
+ return { ok: false, status: 400, code: "invalid_request", error: "requestId moet een uuid zijn" };
153
+ const conn = await connectionFor(supabase, input.environment);
154
+ if (!conn)
155
+ return { ok: false, status: 409, code: "no_active_connection", error: "Geen actieve Floriday-koppeling" };
156
+ const res = await florydayFetch(supabase, input.environment, `/${SUPPLIERS_API_VERSION}/customer-sticker-upload-requests/${input.requestId}/pdf-preview`, { cache: "no-store", headers: { Accept: "application/pdf" } });
157
+ if (!res.ok) {
158
+ const text = await res.text().catch(() => "");
159
+ let parsed = text;
160
+ try {
161
+ parsed = JSON.parse(text);
162
+ }
163
+ catch { /* tekst */ }
164
+ const m = mapFloridayFailure(res.status, parsed, { notFoundAs404: true });
165
+ return { ok: false, status: m.status, code: m.code, error: `Floriday ${res.status}: ${text}`, floridayErrors: m.floridayErrors };
166
+ }
167
+ const contentType = (res.headers.get("content-type") ?? "application/pdf").toLowerCase();
168
+ const bytes = new Uint8Array(await res.arrayBuffer());
169
+ const stored = await storeVersionedDocument(supabase, {
170
+ connectionId: conn.id, kind: "customer-sticker", documentId: `upload-request:${input.requestId}`,
171
+ bucket: BUCKET, basePath: `${conn.id}/upload-requests/${input.requestId}`, bytes, contentType,
172
+ });
173
+ const { data: signed, error } = await supabase.storage.from(stored.bucket).createSignedUrl(stored.storagePath, 3600);
174
+ if (error || !signed?.signedUrl)
175
+ return { ok: false, status: 500, code: "internal_error", error: `Signed URL: ${error?.message ?? "onbekend"}` };
176
+ return { ok: true, bucket: stored.bucket, storagePath: stored.storagePath, version: stored.version,
177
+ url: signed.signedUrl, expiresAt: new Date(Date.now() + 3600000).toISOString(), contentType };
178
+ }
179
+ /**
180
+ * Beantwoordt een aanvraag namens Afhandeling. Vooraf: inhaalronde en
181
+ * opnieuw de actuele status lezen; na expiresOn of als de status niet
182
+ * PENDING is → 409 zonder schrijfactie.
183
+ */
184
+ export async function runStickerUploadRequestRespond(supabase, input) {
185
+ if (!UUID.test(input.requestId ?? ""))
186
+ return { ok: false, status: 400, code: "invalid_request", error: "requestId moet een uuid zijn" };
187
+ if (input.decision !== "accept" && input.decision !== "decline") {
188
+ return { ok: false, status: 400, code: "invalid_request", error: 'decision moet "accept" of "decline" zijn' };
189
+ }
190
+ const conn = await connectionFor(supabase, input.environment);
191
+ if (!conn)
192
+ return { ok: false, status: 409, code: "no_active_connection", error: "Geen actieve Floriday-koppeling" };
193
+ try {
194
+ await syncStickerUploadRequests(supabase, input.environment, conn.id, { maxBatches: 3, deadlineMs: Date.now() + 8000 });
195
+ }
196
+ catch (e) {
197
+ return { ok: false, status: 502, code: "floriday_unavailable", error: `Actuele status niet op te halen: ${e?.message ?? e}` };
198
+ }
199
+ const readRow = async () => (await supabase.from("floriday_customer_sticker_upload_requests_cache")
200
+ .select("floriday_id, customer_sticker_id, sales_order_id, status, expires_on, responded_on, data")
201
+ .eq("connection_id", conn.id).eq("floriday_id", input.requestId).maybeSingle()).data;
202
+ const row = await readRow();
203
+ if (!row)
204
+ return { ok: false, status: 404, code: "not_found", error: "Stickeraanvraag niet bekend bij Floriday-authenticatie" };
205
+ const current = toRequest(row);
206
+ if (current.expired)
207
+ return { ok: false, status: 409, code: "request_expired", error: `Aanvraag verlopen op ${current.expiresOn}` };
208
+ if (!current.canRespond)
209
+ return { ok: false, status: 409, code: "request_not_pending", error: `Aanvraag heeft status ${current.status}` };
210
+ const res = await florydayWrite(supabase, input.environment, {
211
+ module: "customer-stickers",
212
+ action: `customer-sticker-upload-request-${input.decision}`,
213
+ method: "PATCH",
214
+ path: `/customer-sticker-upload-requests/${input.requestId}/${input.decision}`,
215
+ referenceId: input.requestId,
216
+ idempotencyKey: `csur:${input.environment}:${input.requestId}:${input.decision}`,
217
+ caller: input.caller ?? "gateway",
218
+ });
219
+ if (!res.ok) {
220
+ const m = mapFloridayFailure(res.status, res.data, { notFoundAs404: true });
221
+ return { ok: false, status: m.status, code: m.code, error: res.error ?? `Floriday ${res.status}`, floridayStatus: m.floridayStatus, floridayErrors: m.floridayErrors };
222
+ }
223
+ try {
224
+ await syncStickerUploadRequests(supabase, input.environment, conn.id, { maxBatches: 1, deadlineMs: Date.now() + 4000 });
225
+ }
226
+ catch { /* volgende ronde */ }
227
+ return { ok: true, request: toRequest((await readRow()) ?? row) };
228
+ }
229
+ // ---------------------------------------------------------------------------
230
+ // HTTP-handler: POST /api/public/gateway/customer-stickers (HMAC)
231
+ // body.action: "handled" | "upload-requests" | "upload-request-pdf" | "upload-request-respond"
232
+ // ---------------------------------------------------------------------------
233
+ import { verifyGatewayCaller, corsPreflight, withCors, resolveGatewayEnvironment } from "../floriday-gateway-auth.js";
234
+ import { MODULE_VERSION } from "../module-version.js";
235
+ const _csJson = (data, status = 200) => withCors(Response.json({ ...data, moduleVersion: MODULE_VERSION }, { status }));
236
+ export async function handleCustomerStickers(request, supabase) {
237
+ if (request.method === "OPTIONS")
238
+ return corsPreflight();
239
+ const auth = await verifyGatewayCaller(request, supabase);
240
+ if (!auth.ok)
241
+ return _csJson({ ok: false, code: auth.code, error: auth.error }, auth.status);
242
+ let body;
243
+ try {
244
+ body = JSON.parse(auth.rawBody || "{}");
245
+ }
246
+ catch {
247
+ return _csJson({ ok: false, code: "invalid_request", error: "Ongeldige JSON-body" }, 400);
248
+ }
249
+ if (body?.environment !== undefined && body.environment !== "staging" && body.environment !== "live") {
250
+ return _csJson({ ok: false, code: "invalid_request", error: "environment moet staging of live zijn" }, 400);
251
+ }
252
+ try {
253
+ const environment = await resolveGatewayEnvironment(supabase, body?.environment);
254
+ const caller = auth.caller;
255
+ let out;
256
+ switch (body?.action) {
257
+ case "handled":
258
+ out = await runCustomerStickersHandled(supabase, { stickerIds: body.stickerIds, environment, caller });
259
+ break;
260
+ case "upload-requests":
261
+ out = await runStickerUploadRequestsList(supabase, { environment, salesOrderIds: body.salesOrderIds,
262
+ customerStickerIds: body.customerStickerIds, status: body.status, refresh: body.refresh });
263
+ break;
264
+ case "upload-request-pdf":
265
+ out = await runStickerUploadRequestPdf(supabase, { environment, requestId: body.requestId });
266
+ break;
267
+ case "upload-request-respond":
268
+ out = await runStickerUploadRequestRespond(supabase, { environment, requestId: body.requestId, decision: body.decision, caller });
269
+ break;
270
+ default:
271
+ return _csJson({ ok: false, code: "invalid_request", error: 'action moet "handled", "upload-requests", "upload-request-pdf" of "upload-request-respond" zijn' }, 400);
272
+ }
273
+ const { status, ...rest } = out;
274
+ return _csJson(rest, out.ok ? 200 : status ?? 500);
275
+ }
276
+ catch (e) {
277
+ return _csJson({ ok: false, code: "internal_error", error: String(e?.message ?? e) }, 500);
278
+ }
279
+ }
@@ -0,0 +1,11 @@
1
+ export interface MappedFailure {
2
+ status: number;
3
+ code: "floriday_validation" | "floriday_auth" | "floriday_rate_limited" | "floriday_unavailable" | "not_found";
4
+ floridayStatus: number;
5
+ floridayErrors?: unknown;
6
+ retryAfterMs?: number;
7
+ }
8
+ export declare function mapFloridayFailure(floridayStatus: number, data: unknown, opts?: {
9
+ notFoundAs404?: boolean;
10
+ }): MappedFailure;
11
+ //# sourceMappingURL=floriday-error-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-error-map.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/floriday-error-map.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,qBAAqB,GAAG,eAAe,GAAG,uBAAuB,GAAG,sBAAsB,GAAG,WAAW,CAAC;IAC/G,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,aAAa,CAgB/H"}
@@ -0,0 +1,30 @@
1
+ // Zet een mislukte Floriday-aanroep om naar een eigen gatewaycode.
2
+ // 4xx (behalve 401/403/429) = de aanvraag klopt niet → 422 floriday_validation
3
+ // met de volledige errors van Floriday. 502 alleen als Floriday niet antwoordt
4
+ // of een 5xx geeft.
5
+ export function mapFloridayFailure(floridayStatus, data, opts = {}) {
6
+ const errors = extractErrors(data);
7
+ if (!floridayStatus || floridayStatus >= 500) {
8
+ return { status: 502, code: "floriday_unavailable", floridayStatus, floridayErrors: errors };
9
+ }
10
+ if (floridayStatus === 401 || floridayStatus === 403) {
11
+ return { status: 502, code: "floriday_auth", floridayStatus, floridayErrors: errors };
12
+ }
13
+ if (floridayStatus === 429) {
14
+ const ra = Number(data?.retryAfterMs ?? NaN);
15
+ return { status: 503, code: "floriday_rate_limited", floridayStatus, retryAfterMs: Number.isFinite(ra) ? ra : 1000 };
16
+ }
17
+ if (floridayStatus === 404 && opts.notFoundAs404) {
18
+ return { status: 404, code: "not_found", floridayStatus, floridayErrors: errors };
19
+ }
20
+ return { status: 422, code: "floriday_validation", floridayStatus, floridayErrors: errors };
21
+ }
22
+ function extractErrors(data) {
23
+ if (data == null)
24
+ return undefined;
25
+ if (typeof data === "object") {
26
+ const d = data;
27
+ return d.errors ?? d.validationErrors ?? d;
28
+ }
29
+ return data;
30
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"fulfillment-order-send.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/fulfillment-order-send.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAyB5D,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,0BAA0B,CAAC,CA0OrC;AAeD,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAmCnB"}
1
+ {"version":3,"file":"fulfillment-order-send.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/fulfillment-order-send.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AA2B5D,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,0BAA0B,CAAC,CA0PrC;AAeD,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAmCnB"}
@@ -1,6 +1,8 @@
1
1
  // Gateway module: verstuur fulfillment-order (2026v1).
2
2
  // Spiegel van src/routes/api/public/gateway/fulfillment-order.send.ts.
3
3
  import { resolveGatewayEnvironment } from "./shared.js";
4
+ import { validateFulfillmentOrderBody } from "./fulfillment-order-validate.js";
5
+ import { mapFloridayFailure } from "./floriday-error-map.js";
4
6
  import { florydayWrite, getActiveFlorydayCredentials } from "../floriday.functions.js";
5
7
  import { buildFulfillmentOrderBody, detectFulfillmentState, } from "./fulfillment-order-body.js";
6
8
  import { checkCartApproval } from "../floriday-cart-approval.server.js";
@@ -164,6 +166,17 @@ export async function runFulfillmentOrderSend(supabase, body, caller) {
164
166
  }
165
167
  }
166
168
  }
169
+ // Schemacontrole (2026v1) vóór elke Floriday-aanroep; alleen bij belading.
170
+ if (hasCartLoad) {
171
+ const fieldErrors = validateFulfillmentOrderBody(writeBody);
172
+ if (fieldErrors.length > 0) {
173
+ return {
174
+ status: 400,
175
+ payload: { ok: false, code: "invalid_request", skipped: true, errors: fieldErrors,
176
+ error: fieldErrors.map((e) => `${e.field}: ${e.reason}`).join("; "), warnings },
177
+ };
178
+ }
179
+ }
167
180
  // Laatste poort: zijn alle karren van de order afgemeld aan de controlebalie?
168
181
  const approval = await checkCartApproval(supabase, {
169
182
  connectionId: conn.id,
@@ -222,11 +235,15 @@ export async function runFulfillmentOrderSend(supabase, body, caller) {
222
235
  },
223
236
  };
224
237
  }
238
+ const mapped = mapFloridayFailure(result.status, result.data);
225
239
  return {
226
- status: 502,
240
+ status: mapped.status,
227
241
  payload: {
228
242
  ok: false,
229
- code: "write_failed",
243
+ code: mapped.code,
244
+ floridayStatus: mapped.floridayStatus,
245
+ floridayErrors: mapped.floridayErrors,
246
+ retryAfterMs: mapped.retryAfterMs,
230
247
  skipped: false,
231
248
  skippedRequests: skipped,
232
249
  fulfillmentOrderId,
@@ -1 +1 @@
1
- {"version":3,"file":"fulfillment-order-status.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/fulfillment-order-status.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,WAAW,EAGjB,MAAM,uBAAuB,CAAC;AAI/B,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AA2DD;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE;IACL,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7B,GACA,OAAO,CAAC,4BAA4B,CAAC,CA4IvC;AAED,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE;IAAE,kBAAkB,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GACtE,OAAO,CAAC,4BAA4B,CAAC,CA8CvC;AAmBD,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CA8CnB"}
1
+ {"version":3,"file":"fulfillment-order-status.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/fulfillment-order-status.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,WAAW,EAGjB,MAAM,uBAAuB,CAAC;AAI/B,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AA2DD;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE;IACL,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7B,GACA,OAAO,CAAC,4BAA4B,CAAC,CA4IvC;AAED,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE;IAAE,kBAAkB,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GACtE,OAAO,CAAC,4BAA4B,CAAC,CA8CvC;AAmBD,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAmDnB"}
@@ -65,7 +65,7 @@ async function readLocal(db, connId, ids) {
65
65
  const foIds = Array.from(new Set(Array.from(requests.values()).flat().flatMap((r) => r.fulfillmentOrderIds)));
66
66
  const foRows = foIds.length ? await inChunks(foIds, 100, async (c) => {
67
67
  const { data, error } = await db.from("floriday_fulfillment_orders_cache")
68
- .select("floriday_id, status, data, updated_at").eq("connection_id", connId).in("floriday_id", c);
68
+ .select("floriday_id, status, data, fetched_at").eq("connection_id", connId).in("floriday_id", c);
69
69
  if (error)
70
70
  throw new Error(error.message);
71
71
  return data ?? [];
@@ -102,7 +102,7 @@ export async function runSalesOrderStatusOverview(supabase, input) {
102
102
  local = await readLocal(db, conn.id, ids);
103
103
  }
104
104
  catch (e) {
105
- return { status: 502, payload: { ok: false, code: "floriday_unavailable", error: `Lokale gegevens niet leesbaar: ${String(e?.message ?? e)}` } };
105
+ return { status: 500, payload: { ok: false, code: "internal_error", error: `Lokale gegevens niet leesbaar: ${String(e?.message ?? e)}` } };
106
106
  }
107
107
  // Inhaalronde (alleen bij mode auto).
108
108
  const mode = input.refresh ?? "auto";
@@ -312,6 +312,8 @@ export async function handleFulfillmentOrderStatus(request, supabase) {
312
312
  if (/actieve Floriday-koppeling/i.test(msg)) {
313
313
  return _fosStatusJson({ ok: false, code: "no_active_connection", error: msg }, { status: 409 });
314
314
  }
315
- return _fosStatusJson({ ok: false, code: "floriday_unavailable", error: msg }, { status: 502 });
315
+ // Alleen een echte Floriday-storing is floriday_unavailable; al het andere is intern.
316
+ const floriday = e?.floridayStatus != null || /floriday|fetch failed|network|timed? ?out/i.test(msg);
317
+ return _fosStatusJson({ ok: false, code: floriday ? "floriday_unavailable" : "internal_error", error: msg }, { status: floriday ? 502 : 500 });
316
318
  }
317
319
  }
@@ -0,0 +1,8 @@
1
+ export interface FieldError {
2
+ field: string;
3
+ reason: string;
4
+ value?: unknown;
5
+ }
6
+ export declare const LOAD_CARRIER_REFERENCE_MAX = 14;
7
+ export declare function validateFulfillmentOrderBody(body: any): FieldError[];
8
+ //# sourceMappingURL=fulfillment-order-validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fulfillment-order-validate.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/fulfillment-order-validate.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAGD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAI7C,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,GAAG,GAAG,UAAU,EAAE,CA+CpE"}
@@ -0,0 +1,56 @@
1
+ // Controle van de FulfillmentOrderCreate-body vóór de Floriday-aanroep
2
+ // (Suppliers API 2026v1). Alleen velden die het schema vastlegt; loadCarrierType
3
+ // controleert Floriday zelf (de lijst verschilt per API-versie).
4
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
+ export const LOAD_CARRIER_REFERENCE_MAX = 14;
6
+ const isInt = (v) => typeof v === "number" && Number.isInteger(v);
7
+ export function validateFulfillmentOrderBody(body) {
8
+ const errs = [];
9
+ if (!body || typeof body !== "object")
10
+ return [{ field: "body", reason: "ontbreekt" }];
11
+ if (!UUID.test(String(body.fulfillmentOrderId ?? ""))) {
12
+ errs.push({ field: "fulfillmentOrderId", reason: "verplicht, uuid", value: body.fulfillmentOrderId });
13
+ }
14
+ if (body.oneLabelOnly !== undefined && typeof body.oneLabelOnly !== "boolean") {
15
+ errs.push({ field: "oneLabelOnly", reason: "moet true of false zijn", value: body.oneLabelOnly });
16
+ }
17
+ const carriers = body.loadCarriers;
18
+ if (!Array.isArray(carriers) || carriers.length === 0) {
19
+ errs.push({ field: "loadCarriers", reason: "verplicht, minimaal één kar" });
20
+ return errs;
21
+ }
22
+ carriers.forEach((c, i) => {
23
+ const p = `loadCarriers[${i}]`;
24
+ const ref = c?.loadCarrierReference;
25
+ if (typeof ref !== "string" || !ref.trim())
26
+ errs.push({ field: `${p}.loadCarrierReference`, reason: "verplicht", value: ref });
27
+ else if (ref.length > LOAD_CARRIER_REFERENCE_MAX) {
28
+ errs.push({ field: `${p}.loadCarrierReference`, reason: `maximaal ${LOAD_CARRIER_REFERENCE_MAX} tekens (nu ${ref.length})`, value: ref });
29
+ }
30
+ if (typeof c?.loadCarrierType !== "string" || !c.loadCarrierType.trim()) {
31
+ errs.push({ field: `${p}.loadCarrierType`, reason: "verplicht", value: c?.loadCarrierType });
32
+ }
33
+ if (!isInt(c?.numberOfAdditionalLayers) || c.numberOfAdditionalLayers < 0) {
34
+ errs.push({ field: `${p}.numberOfAdditionalLayers`, reason: "verplicht, geheel getal ≥ 0", value: c?.numberOfAdditionalLayers });
35
+ }
36
+ if (c?.sortIndex !== undefined && (!isInt(c.sortIndex) || c.sortIndex < 0 || c.sortIndex > 9999)) {
37
+ errs.push({ field: `${p}.sortIndex`, reason: "geheel getal 0–9999", value: c.sortIndex });
38
+ }
39
+ const items = c?.items ?? c?.loadCarrierItems;
40
+ if (Array.isArray(items)) {
41
+ items.forEach((it, j) => {
42
+ const q = `${p}.items[${j}]`;
43
+ if (it?.loadCarrierItemId !== undefined && !UUID.test(String(it.loadCarrierItemId))) {
44
+ errs.push({ field: `${q}.loadCarrierItemId`, reason: "uuid", value: it.loadCarrierItemId });
45
+ }
46
+ if (it?.fulfillmentRequestId !== undefined && !UUID.test(String(it.fulfillmentRequestId))) {
47
+ errs.push({ field: `${q}.fulfillmentRequestId`, reason: "uuid", value: it.fulfillmentRequestId });
48
+ }
49
+ if (it?.numberOfPackages !== undefined && (!isInt(it.numberOfPackages) || it.numberOfPackages < 1)) {
50
+ errs.push({ field: `${q}.numberOfPackages`, reason: "geheel getal ≥ 1", value: it.numberOfPackages });
51
+ }
52
+ });
53
+ }
54
+ });
55
+ return errs;
56
+ }
@@ -16,6 +16,7 @@ export * from "./diagnostics.js";
16
16
  export * from "./media.js";
17
17
  export * from "./media-upload.js";
18
18
  export * from "./supply-line.js";
19
+ export * from "./customer-stickers.js";
19
20
  export * from "./auto-process.js";
20
21
  export * from "./cron-scan.js";
21
22
  export * from "./documents.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
@@ -16,6 +16,7 @@ export * from "./diagnostics.js";
16
16
  export * from "./media.js";
17
17
  export * from "./media-upload.js";
18
18
  export * from "./supply-line.js";
19
+ export * from "./customer-stickers.js";
19
20
  export * from "./auto-process.js";
20
21
  export * from "./cron-scan.js";
21
22
  export * from "./documents.js";
@@ -1,5 +1,5 @@
1
1
  import type { SupabaseClient } from "@supabase/supabase-js";
2
- type Kind = "logistic-label" | "delivery-note" | "auction-letter" | "customer-sticker" | "tray-stickers";
2
+ type Kind = "logistic-label" | "delivery-note" | "auction-letter" | "customer-sticker" | "tray-stickers" | "stored";
3
3
  export interface PdfInput {
4
4
  environment?: "staging" | "live";
5
5
  kind: Kind;
@@ -10,6 +10,9 @@ export interface PdfInput {
10
10
  clockSupplyId?: string;
11
11
  auctionLetterCode?: string;
12
12
  stickerId?: string;
13
+ /** kind "stored": opnieuw ondertekenen van een bewaard bestand (herprint). */
14
+ bucket?: string;
15
+ storagePath?: string;
13
16
  }
14
17
  export type PdfResult = ({
15
18
  ok: true;
@@ -1 +1 @@
1
- {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/pdf.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,KAAK,IAAI,GACL,gBAAgB,GAChB,eAAe,GACf,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,CAAC;AAGpB,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,SAAS,GACjB,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GACpC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEN,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,SAAS,GAAG,MAAM,GAC9B,OAAO,CAAC,SAAS,CAAC,CAkFpB;AAgBD,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAuCnB"}
1
+ {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../../../src/lib/gateway/pdf.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,KAAK,IAAI,GACL,gBAAgB,GAChB,eAAe,GACf,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,QAAQ,CAAC;AAGb,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,MAAM,SAAS,GACjB,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GACpC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEN,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,SAAS,GAAG,MAAM,GAC9B,OAAO,CAAC,SAAS,CAAC,CAsGpB;AAgBD,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAuCnB"}
@@ -2,6 +2,7 @@
2
2
  // Verplaatst uit de route; byte-identiek gedrag.
3
3
  // De adapter resolvet environment vooraf (409-catch) en geeft die mee.
4
4
  import { resolveFulfillmentOrderIds, resolveLogisticLabel } from "./shared.js";
5
+ const OWN_DOCUMENT_BUCKETS = ["floriday-logistic-labels", "floriday-customer-stickers", "floriday-auction-letters"];
5
6
  export async function runPdf(supabase, parsed, environment) {
6
7
  if (parsed.kind === "logistic-label" || parsed.kind === "delivery-note") {
7
8
  // Voor "delivery-note" mag de caller ook via deliveryOrderId of
@@ -61,15 +62,36 @@ export async function runPdf(supabase, parsed, environment) {
61
62
  return { ok: true, ...result };
62
63
  }
63
64
  if (parsed.kind === "tray-stickers") {
64
- if (!parsed.deliveryOrderId) {
65
- return { ok: false, status: 400, error: "deliveryOrderId is verplicht" };
66
- }
67
65
  const { resolveTrayStickers } = await import("../floriday-tray-stickers.functions.js");
68
66
  const result = await resolveTrayStickers(supabase, {
69
67
  environment,
68
+ fulfillmentOrderId: parsed.fulfillmentOrderId,
70
69
  deliveryOrderId: parsed.deliveryOrderId,
71
70
  });
72
- return { ok: true, ...result };
71
+ if (!result.ok)
72
+ return result;
73
+ return result;
74
+ }
75
+ if (parsed.kind === "stored") {
76
+ // Herprint: een verlopen pdf_url mag nooit blokkeren; alleen bekende
77
+ // documentversies in de eigen buckets.
78
+ const bucket = parsed.bucket?.trim() ?? "";
79
+ const storagePath = parsed.storagePath?.trim() ?? "";
80
+ if (!OWN_DOCUMENT_BUCKETS.includes(bucket) || !storagePath || storagePath.includes("..")) {
81
+ return { ok: false, status: 400, error: "bucket en storagePath van een Floriday-document zijn verplicht" };
82
+ }
83
+ const { data: known } = await supabase.from("floriday_document_versions")
84
+ .select("document_kind, document_id, version").eq("bucket", bucket).eq("storage_path", storagePath).maybeSingle();
85
+ const { data: legacy } = known ? { data: true } : await supabase.storage.from(bucket)
86
+ .list(storagePath.split("/").slice(0, -1).join("/"), { search: storagePath.split("/").pop() });
87
+ if (!known && !(Array.isArray(legacy) && legacy.length > 0)) {
88
+ return { ok: false, status: 404, error: "Bestand niet gevonden" };
89
+ }
90
+ const { data: signed, error } = await supabase.storage.from(bucket).createSignedUrl(storagePath, 60 * 60);
91
+ if (error || !signed?.signedUrl)
92
+ return { ok: false, status: 500, error: `Signed URL: ${error?.message ?? "onbekend"}` };
93
+ return { ok: true, bucket, storagePath, version: known?.version ?? 1, url: signed.signedUrl,
94
+ expiresAt: new Date(Date.now() + 3600000).toISOString() };
73
95
  }
74
96
  return { ok: false, status: 400, error: `Onbekend kind: ${parsed.kind}` };
75
97
  }
@@ -1,2 +1,2 @@
1
- export declare const MODULE_VERSION = "1.0.74";
1
+ export declare const MODULE_VERSION = "1.0.77";
2
2
  //# sourceMappingURL=module-version.d.ts.map
@@ -1,2 +1,2 @@
1
1
  // GEGENEREERD door scripts/write-module-version.mjs uit package.json — niet handmatig wijzigen.
2
- export const MODULE_VERSION = "1.0.74";
2
+ export const MODULE_VERSION = "1.0.77";
@@ -1,5 +1,5 @@
1
1
  /** Moet gelijk zijn aan de gateway-routes in package.json (bewaakt door test). */
2
- export declare const SHELL_GATEWAY_ROUTES: readonly ["/api/public/gateway/active-environment", "/api/public/gateway/auto-process", "/api/public/gateway/cached-list", "/api/public/gateway/code-list", "/api/public/gateway/cron/scan", "/api/public/gateway/diagnostics", "/api/public/gateway/floricode-records", "/api/public/gateway/fulfillment-order/send", "/api/public/gateway/fulfillment-order/status", "/api/public/gateway/media", "/api/public/gateway/media-upload", "/api/public/gateway/pdf", "/api/public/gateway/pdf/bulk", "/api/public/gateway/pdf/bulk-merged", "/api/public/gateway/product-characteristics", "/api/public/gateway/schema", "/api/public/gateway/supply-line", "/api/public/gateway/floriday-get", "/api/public/gateway/write", "/api/public/gateway/trade-item-version", "/api/public/gateway/webhook-in"];
2
+ export declare const SHELL_GATEWAY_ROUTES: readonly ["/api/public/gateway/active-environment", "/api/public/gateway/auto-process", "/api/public/gateway/cached-list", "/api/public/gateway/code-list", "/api/public/gateway/cron/scan", "/api/public/gateway/diagnostics", "/api/public/gateway/floricode-records", "/api/public/gateway/fulfillment-order/send", "/api/public/gateway/fulfillment-order/status", "/api/public/gateway/media", "/api/public/gateway/media-upload", "/api/public/gateway/pdf", "/api/public/gateway/pdf/bulk", "/api/public/gateway/pdf/bulk-merged", "/api/public/gateway/product-characteristics", "/api/public/gateway/schema", "/api/public/gateway/supply-line", "/api/public/gateway/customer-stickers", "/api/public/gateway/floriday-get", "/api/public/gateway/write", "/api/public/gateway/trade-item-version", "/api/public/gateway/webhook-in"];
3
3
  export type ShellRouteState = {
4
4
  path: string;
5
5
  present: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"shell-routes.d.ts","sourceRoot":"","sources":["../../src/lib/shell-routes.ts"],"names":[],"mappings":"AAYA,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,wwBAsBvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAKF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAShG;AAqBD,0FAA0F;AAC1F,wBAAsB,gBAAgB,CAAC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4CvH;AAED,8FAA8F;AAC9F,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBlH"}
1
+ {"version":3,"file":"shell-routes.d.ts","sourceRoot":"","sources":["../../src/lib/shell-routes.ts"],"names":[],"mappings":"AAYA,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,izBAuBvB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAKF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAShG;AAqBD,0FAA0F;AAC1F,wBAAsB,gBAAgB,CAAC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4CvH;AAED,8FAA8F;AAC9F,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBlH"}
@@ -28,6 +28,7 @@ export const SHELL_GATEWAY_ROUTES = [
28
28
  "/api/public/gateway/product-characteristics",
29
29
  "/api/public/gateway/schema",
30
30
  "/api/public/gateway/supply-line",
31
+ "/api/public/gateway/customer-stickers",
31
32
  "/api/public/gateway/floriday-get",
32
33
  "/api/public/gateway/write",
33
34
  "/api/public/gateway/trade-item-version",