@flowselections/floriday-afhandeling-module 1.0.52 → 1.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"authGateway.server.d.ts","sourceRoot":"","sources":["../../src/lib/authGateway.server.ts"],"names":[],"mappings":"AA6BA,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAqB9D;AA2BD,iFAAiF;AACjF,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CA6BhC;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB/F;AA4BD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAyElD"}
1
+ {"version":3,"file":"authGateway.server.d.ts","sourceRoot":"","sources":["../../src/lib/authGateway.server.ts"],"names":[],"mappings":"AA6BA,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAqB9D;AA2BD,iFAAiF;AACjF,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CA6BhC;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgB/F;AA4BD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA0ElD"}
@@ -6,7 +6,7 @@
6
6
  // message = `${timestamp}.${JSON.stringify(body)}`
7
7
  // signature = hex(HMAC-SHA256(AUTH_GATEWAY_HMAC_SECRET, message))
8
8
  // headers = { "X-Signature": signature, "X-Timestamp": timestamp }
9
- // Timestamp = ISO 8601 UTC, ±5 min venster.
9
+ // Timestamp = epoch-milliseconden als tekst (String(Date.now())), ±5 min venster.
10
10
  // Web Crypto (browser/Node 15+/Workers) — geen node:crypto, want dist-lib
11
11
  // wordt ook in de client-bundle van consumer-shells opgenomen.
12
12
  import { createClient } from "@supabase/supabase-js";
@@ -161,7 +161,8 @@ export async function fetchDeliveryNotePdf(salesOrderId) {
161
161
  deliveryOrderId: deliveryOrderIds[0],
162
162
  };
163
163
  const bodyStr = JSON.stringify(payload);
164
- const timestamp = new Date().toISOString();
164
+ // De gateway verwacht epoch-milliseconden; we tekenen over precies deze waarde.
165
+ const timestamp = String(Date.now());
165
166
  const signature = await signBody(secret, timestamp, bodyStr);
166
167
  try {
167
168
  const base = await resolveGatewayBaseServer();
@@ -77,6 +77,8 @@ export declare const getOrderLines: import("@tanstack/start-client-core").Requir
77
77
  }>>;
78
78
  export interface DayCartContent {
79
79
  orderRef: string;
80
+ /** Engine-kar-id; leeg als de Engine geen kar-id gaf. */
81
+ cartId: string | null;
80
82
  cartNumber: number;
81
83
  layersUsed: number | null;
82
84
  maxLayers: number | null;
@@ -133,4 +135,31 @@ export declare const getOrderCartIds: import("@tanstack/start-client-core").Requ
133
135
  cartNumber: number;
134
136
  }[];
135
137
  }>>;
138
+ export interface PakbonCartInfo {
139
+ cartId: string;
140
+ /** Vaste LC-code van de kar (logistics_ensure_cart_barcode), dezelfde als op het pickstation. */
141
+ barcode: string;
142
+ /** Bestaande pakbon voor deze kar (documenttype pakbon, niet mislukt/geannuleerd), zoals Pickschermen controleert. */
143
+ bestaand: {
144
+ herkomst: string;
145
+ printer: string | null;
146
+ tijd: string;
147
+ status: string;
148
+ } | null;
149
+ }
150
+ /**
151
+ * Per Engine-kar de vaste kar-barcode en de bestaande pakbon in de Printwachtrij.
152
+ * Match uitsluitend op cart_id; verzendbrieven tellen niet mee.
153
+ */
154
+ export declare const getPakbonCartInfo: import("@tanstack/start-client-core").RequiredFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
155
+ supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
156
+ userId: string;
157
+ claims: import("@supabase/auth-js").JwtPayload;
158
+ }, undefined, undefined, undefined>], (d: {
159
+ cartIds: string[];
160
+ }) => {
161
+ cartIds: string[];
162
+ }, Promise<{
163
+ carts: PakbonCartInfo[];
164
+ }>>;
136
165
  //# sourceMappingURL=cartAssignments.functions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cartAssignments.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cartAssignments.functions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cartAssignments.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cartAssignments.functions.ts"],"names":[],"mappings":"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"}
@@ -197,6 +197,7 @@ export const getDayCartContents = createServerFn({ method: "POST" })
197
197
  const lines = arr(k?.lines);
198
198
  carts.push({
199
199
  orderRef,
200
+ cartId: typeof k?.cartId === "string" && k.cartId ? k.cartId : null,
200
201
  cartNumber: num(k?.cartNumber) ?? idx + 1,
201
202
  layersUsed: num(s.layersUsed ?? s.totalLayersUsed),
202
203
  maxLayers: num(s.maxLayers),
@@ -255,3 +256,66 @@ export const getOrderCartIds = createServerFn({ method: "POST" })
255
256
  .filter((k) => k.cartId);
256
257
  return { carts };
257
258
  });
259
+ /**
260
+ * Per Engine-kar de vaste kar-barcode en de bestaande pakbon in de Printwachtrij.
261
+ * Match uitsluitend op cart_id; verzendbrieven tellen niet mee.
262
+ */
263
+ export const getPakbonCartInfo = createServerFn({ method: "POST" })
264
+ .middleware([requireSupabaseAuth])
265
+ .inputValidator((d) => ({
266
+ cartIds: Array.from(new Set((d?.cartIds ?? []).map((x) => String(x).trim()).filter(Boolean))).slice(0, 200),
267
+ }))
268
+ .handler(async ({ data, context }) => {
269
+ const supabase = context.supabase;
270
+ if (data.cartIds.length === 0)
271
+ return { carts: [] };
272
+ const barcodes = new Map();
273
+ await Promise.all(data.cartIds.map(async (id) => {
274
+ const { data: bc, error } = await supabase.rpc("logistics_ensure_cart_barcode", { _cart_id: id });
275
+ if (error)
276
+ throw new Error(`Kar-barcode niet opgehaald: ${error.message}`);
277
+ if (typeof bc !== "string" || !bc)
278
+ throw new Error("De Engine gaf geen kar-barcode terug.");
279
+ barcodes.set(id, bc);
280
+ }));
281
+ const { data: jobs, error } = await supabase
282
+ .from("print_jobs")
283
+ .select("payload, herkomst, gebruiker_naam, created_at, status, printer_id")
284
+ .eq("documenttype", "pakbon")
285
+ .not("status", "in", "(mislukt,geannuleerd)")
286
+ .in("payload->>cart_id", data.cartIds)
287
+ .order("created_at", { ascending: true });
288
+ if (error)
289
+ throw new Error(`Printwachtrij niet gelezen: ${error.message}`);
290
+ const printerIds = [...new Set((jobs ?? []).map((j) => j.printer_id).filter(Boolean))];
291
+ const printerNaam = new Map();
292
+ if (printerIds.length) {
293
+ const { data: pr } = await supabase.from("printers").select("id, naam").in("id", printerIds);
294
+ for (const p of pr ?? [])
295
+ printerNaam.set(p.id, p.naam);
296
+ }
297
+ const eerste = new Map();
298
+ for (const j of jobs ?? []) {
299
+ const cid = j?.payload?.cart_id;
300
+ if (typeof cid === "string" && !eerste.has(cid))
301
+ eerste.set(cid, j);
302
+ }
303
+ return {
304
+ carts: data.cartIds.map((id) => {
305
+ const j = eerste.get(id);
306
+ const bron = j ? (j.payload?.source ?? j.herkomst ?? j.gebruiker_naam ?? "onbekend") : null;
307
+ return {
308
+ cartId: id,
309
+ barcode: barcodes.get(id),
310
+ bestaand: j
311
+ ? {
312
+ herkomst: String(bron) === "afhandeling" ? "Afhandeling" : String(bron).includes("pick") ? "het pickstation" : String(bron),
313
+ printer: j.printer_id ? printerNaam.get(j.printer_id) ?? null : null,
314
+ tijd: j.created_at,
315
+ status: j.status,
316
+ }
317
+ : null,
318
+ };
319
+ }),
320
+ };
321
+ });
@@ -2,6 +2,12 @@ export interface GatewayResult {
2
2
  httpStatus: number;
3
3
  body: any;
4
4
  }
5
+ /**
6
+ * Begrijpelijke zin met de echte reden, gevolgd door veld(en) en technische code
7
+ * tussen [ ] die het scherm klein toont.
8
+ */
9
+ export declare function floridayFoutTekst(inleiding: string, r: GatewayResult): string;
10
+ export declare function gatewayFoutTekst(wat: string, r: GatewayResult): string;
5
11
  export interface FulfillmentRequestStatus {
6
12
  fulfillmentRequestId: string;
7
13
  deliveryOrderId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"floridayFulfillmentSend.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayFulfillmentSend.server.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;CACX;AA4BD,MAAM,WAAW,wBAAwB;IACvC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AACD,MAAM,WAAW,sBAAsB;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AACD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,wBAAwB,EAAE,CAAC;IAChD,iBAAiB,EAAE,sBAAsB,EAAE,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,aAAa,EAAE,MAAM,EAAE,EACvB,mBAAmB,GAAE,MAAM,EAAO,GACjC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAwCxC;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAEnG"}
1
+ {"version":3,"file":"floridayFulfillmentSend.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayFulfillmentSend.server.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC;CACX;AA8ED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,GAAG,MAAM,CAI7E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,GAAG,MAAM,CAEtE;AAED,MAAM,WAAW,wBAAwB;IACvC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AACD,MAAM,WAAW,sBAAsB;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AACD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,wBAAwB,EAAE,CAAC;IAChD,iBAAiB,EAAE,sBAAsB,EAAE,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,aAAa,EAAE,MAAM,EAAE,EACvB,mBAAmB,GAAE,MAAM,EAAO,GACjC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAoCxC;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAEnG"}
@@ -9,7 +9,8 @@ async function signedPost(path, payload) {
9
9
  const secret = await getFloridayGatewaySecret(); // throws als het ontbreekt
10
10
  const base = await resolveGatewayBaseServer(); // throws als het ontbreekt
11
11
  const bodyStr = JSON.stringify(payload);
12
- const timestamp = new Date().toISOString();
12
+ // De gateway verwacht epoch-milliseconden; we tekenen over precies deze waarde.
13
+ const timestamp = String(Date.now());
13
14
  const signature = await signBody(secret, timestamp, bodyStr);
14
15
  const res = await fetch(`${base}/api/public/gateway/${path}`, {
15
16
  method: "POST",
@@ -29,6 +30,85 @@ async function signedPost(path, payload) {
29
30
  }
30
31
  const arr = (v) => (Array.isArray(v) ? v : []);
31
32
  const str = (v) => (typeof v === "string" && v ? v : null);
33
+ /** Floriday-veldfout omzetten naar gewone taal. */
34
+ function veldUitleg(field, msg) {
35
+ const f = field.toLowerCase();
36
+ const max = /maximum length of '?(\d+)'?|max(?:imum)? length (\d+)|maxlength (\d+)/i.exec(msg);
37
+ const n = max ? (max[1] ?? max[2] ?? max[3]) : null;
38
+ if (f.endsWith("loadcarrierreference"))
39
+ return n ? `het karkenmerk is te lang (maximaal ${n} tekens)` : "het karkenmerk klopt niet";
40
+ if (f.endsWith("loadcarrieritemid"))
41
+ return "het regelkenmerk is geen geldige uuid";
42
+ if (f.endsWith("fulfillmentrequestid"))
43
+ return "het Floriday-verzoek van een regel klopt niet";
44
+ if (f.endsWith("numberofpackages"))
45
+ return "het aantal fusten van een regel klopt niet";
46
+ if (f.endsWith("numberofadditionallayers"))
47
+ return "het aantal extra lagen van een kar ontbreekt of klopt niet";
48
+ if (f.endsWith("loadcarriertype"))
49
+ return "het type kar ontbreekt of klopt niet";
50
+ if (f.endsWith("deliveryorderid"))
51
+ return "de levering is niet bekend bij Floriday";
52
+ if (f.endsWith("fulfillmentorderid"))
53
+ return "het opdrachtkenmerk klopt niet";
54
+ return msg;
55
+ }
56
+ /** Verzamelt alle foutvormen die de gateway kan doorgeven (ook een doorgegeven Floriday-antwoord). */
57
+ function verzamelFouten(b) {
58
+ const zinnen = [];
59
+ const velden = [];
60
+ let code = null;
61
+ const visit = (x, depth) => {
62
+ if (!x || typeof x !== "object" || depth > 3)
63
+ return;
64
+ code = code ?? str(x.code) ?? str(x.type) ?? str(x.errorCode);
65
+ const errs = x.errors;
66
+ if (Array.isArray(errs)) {
67
+ for (const e of errs) {
68
+ if (typeof e === "string")
69
+ zinnen.push(e);
70
+ else if (e && typeof e === "object") {
71
+ const fld = str(e.field) ?? str(e.propertyName) ?? str(e.property) ?? str(e.name);
72
+ const m = str(e.message) ?? str(e.errorMessage) ?? str(e.detail) ?? "";
73
+ if (fld) {
74
+ velden.push(fld);
75
+ zinnen.push(veldUitleg(fld, m));
76
+ }
77
+ else if (m)
78
+ zinnen.push(m);
79
+ }
80
+ }
81
+ }
82
+ else if (errs && typeof errs === "object") {
83
+ for (const [fld, v] of Object.entries(errs)) {
84
+ const m = Array.isArray(v) ? v.filter((y) => typeof y === "string").join(" ") : String(v ?? "");
85
+ velden.push(fld);
86
+ zinnen.push(veldUitleg(fld, m));
87
+ }
88
+ }
89
+ for (const k of ["detail", "title", "error", "message"]) {
90
+ const s = str(x[k]);
91
+ if (s && !/^http_\d+$/.test(s) && s !== code)
92
+ zinnen.push(s);
93
+ }
94
+ for (const k of ["floriday", "upstream", "response", "body", "details", "data"])
95
+ visit(x[k], depth + 1);
96
+ };
97
+ visit(b, 0);
98
+ return { zinnen: [...new Set(zinnen)], velden: [...new Set(velden)], code };
99
+ }
100
+ /**
101
+ * Begrijpelijke zin met de echte reden, gevolgd door veld(en) en technische code
102
+ * tussen [ ] die het scherm klein toont.
103
+ */
104
+ export function floridayFoutTekst(inleiding, r) {
105
+ const { zinnen, velden, code } = verzamelFouten(r.body ?? {});
106
+ const tech = [...velden, code, `HTTP ${r.httpStatus}`].filter(Boolean).join(" · ");
107
+ return `${inleiding}${zinnen.length ? `: ${zinnen.join("; ")}.` : " zonder reden te geven."} [${tech}]`;
108
+ }
109
+ export function gatewayFoutTekst(wat, r) {
110
+ return floridayFoutTekst(`Floriday-authenticatie weigerde ${wat}`, r);
111
+ }
32
112
  /**
33
113
  * Statusoverzicht (Floriday-authenticatie 1.0.64), in porties van maximaal 100.
34
114
  * Exact contract per order: salesOrderId, found, salesOrderStatus, floridayStage,
@@ -46,11 +126,8 @@ export async function fetchFulfillmentStatus(salesOrderIds, fulfillmentOrderIds
46
126
  salesOrderIds: ids.slice(i, i + 100),
47
127
  ...(foIds.length ? { fulfillmentOrderIds: foIds, fulfillmentOrderId: foIds[0] } : {}),
48
128
  });
49
- if (r.httpStatus >= 400 || !r.body) {
50
- const detail = [r.body?.code, r.body?.message, ...arr(r.body?.errors).map((e) => (typeof e === "string" ? e : e?.message))]
51
- .filter((x) => typeof x === "string" && x).join(" — ");
52
- throw new Error(`Statusoverzicht van Floriday-authenticatie mislukt (HTTP ${r.httpStatus}${detail ? `: ${detail}` : ""}).`);
53
- }
129
+ if (r.httpStatus >= 400 || !r.body)
130
+ throw new Error(gatewayFoutTekst("het statusoverzicht", r));
54
131
  const rows = Array.isArray(r.body) ? r.body : r.body.orders;
55
132
  if (!Array.isArray(rows))
56
133
  throw new Error("Statusoverzicht heeft geen lijst met orders.");
@@ -65,6 +65,8 @@ export interface SendResult {
65
65
  deliveryNote: string;
66
66
  }[];
67
67
  }
68
+ /** Floriday 2026v1 AddLoadCarrierConfiguration.loadCarrierReference: maximaal 14 tekens. */
69
+ export declare const LOAD_CARRIER_REF_MAX = 14;
68
70
  /** Stelt de belading samen en toont de controles. Verstuurt niets. */
69
71
  export declare const prepareFloridayLoading: import("@tanstack/start-client-core").RequiredFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
70
72
  supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
@@ -1 +1 @@
1
- {"version":3,"file":"floridayLoading.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floridayLoading.functions.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AACD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AACD,MAAM,WAAW,eAAe;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AACD,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AACD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3H;AA0PD,sEAAsE;AACtE,eAAO,MAAM,sBAAsB;;;;0CAEb;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE;;2BAC4E,CAAC;AAEvH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;0CAEV;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE;;uBA0DtC,CAAC"}
1
+ {"version":3,"file":"floridayLoading.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floridayLoading.functions.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AACD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AACD,MAAM,WAAW,eAAe;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AACD,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AACD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3H;AAQD,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,KAAK,CAAC;AA+TvC,sEAAsE;AACtE,eAAO,MAAM,sBAAsB;;;;0CAEb;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE;;2BAC4E,CAAC;AAEvH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;0CAEV;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE;;uBA0DtC,CAAC"}
@@ -7,30 +7,81 @@ import { createServerFn } from "@tanstack/react-start";
7
7
  import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
8
8
  const arr = (v) => (Array.isArray(v) ? v : []);
9
9
  const num = (v) => v == null || v === "" || !Number.isFinite(Number(v)) ? null : Number(v);
10
- async function ensureIds(supabase, scope, keys) {
10
+ /** Floriday 2026v1 AddLoadCarrierConfiguration.loadCarrierReference: maximaal 14 tekens. */
11
+ export const LOAD_CARRIER_REF_MAX = 14;
12
+ /** Deterministische korte code uit het cart_id: "K" + 8 tekens (FNV-1a, base36). */
13
+ function shortCartCode(cartId, salt = 0) {
14
+ let h = 0x811c9dc5 ^ salt;
15
+ for (let i = 0; i < cartId.length; i++) {
16
+ h ^= cartId.charCodeAt(i);
17
+ h = Math.imul(h, 0x01000193) >>> 0;
18
+ }
19
+ let h2 = 0x9e3779b9 ^ salt;
20
+ for (let i = cartId.length - 1; i >= 0; i--) {
21
+ h2 ^= cartId.charCodeAt(i);
22
+ h2 = Math.imul(h2, 0x01000193) >>> 0;
23
+ }
24
+ return ("K" + (h.toString(36) + h2.toString(36)).toUpperCase().padStart(8, "0").slice(0, 8));
25
+ }
26
+ /** Leesbaar karkenmerk: ordernummer zonder streepjes + "-K" + karnummer, bijv. FO2601418-K1. */
27
+ function readableCartRef(orderRef, cartLabel) {
28
+ const o = orderRef.replace(/[^A-Za-z0-9]/g, "").toUpperCase();
29
+ const k = cartLabel.replace(/[^A-Za-z0-9]/g, "").toUpperCase();
30
+ if (!o || !k)
31
+ return null;
32
+ const ref = `${o}-K${k}`;
33
+ return ref.length <= LOAD_CARRIER_REF_MAX ? ref : null;
34
+ }
35
+ async function ensureIds(supabase, scope, keys, makeIdentifier) {
11
36
  const out = new Map();
12
37
  const uniq = [...new Set(keys)];
13
38
  if (!uniq.length)
14
39
  return out;
15
- const { error: insErr } = await supabase
16
- .from("floriday_loading_identifiers")
17
- .upsert(uniq.map((k) => ({ scope, natural_key: k })), { onConflict: "scope,natural_key", ignoreDuplicates: true });
18
- if (insErr)
19
- throw new Error(insErr.message);
20
- const { data, error } = await supabase
21
- .from("floriday_loading_identifiers")
22
- .select("natural_key, identifier")
23
- .eq("scope", scope)
24
- .in("natural_key", uniq);
25
- if (error)
26
- throw new Error(error.message);
27
- for (const r of data ?? [])
28
- out.set(r.natural_key, r.identifier);
40
+ const read = async () => {
41
+ const { data, error } = await supabase
42
+ .from("floriday_loading_identifiers")
43
+ .select("natural_key, identifier")
44
+ .eq("scope", scope)
45
+ .in("natural_key", uniq);
46
+ if (error)
47
+ throw new Error(error.message);
48
+ for (const r of data ?? [])
49
+ out.set(r.natural_key, r.identifier);
50
+ };
51
+ if (!makeIdentifier) {
52
+ const { error: insErr } = await supabase
53
+ .from("floriday_loading_identifiers")
54
+ .upsert(uniq.map((k) => ({ scope, natural_key: k })), { onConflict: "scope,natural_key", ignoreDuplicates: true });
55
+ if (insErr)
56
+ throw new Error(insErr.message);
57
+ await read();
58
+ }
59
+ else {
60
+ // Eén keer aanmaken met een eigen kenmerk; bestaande kenmerken nooit wijzigen.
61
+ await read();
62
+ for (const k of uniq.filter((x) => !out.has(x))) {
63
+ for (const candidate of makeIdentifier(k)) {
64
+ const { error } = await supabase.from("floriday_loading_identifiers")
65
+ .insert({ scope, natural_key: k, identifier: candidate });
66
+ if (!error)
67
+ break;
68
+ if (error.code !== "23505")
69
+ throw new Error(error.message);
70
+ // Conflict: óf de kar heeft intussen een kenmerk (klaar), óf het kenmerk is al bezet (volgende kandidaat).
71
+ const { data } = await supabase.from("floriday_loading_identifiers")
72
+ .select("identifier").eq("scope", scope).eq("natural_key", k).maybeSingle();
73
+ if (data?.identifier)
74
+ break;
75
+ }
76
+ }
77
+ await read();
78
+ }
29
79
  for (const k of uniq)
30
80
  if (!out.has(k))
31
81
  throw new Error("Vast kenmerk kon niet worden vastgelegd.");
32
82
  return out;
33
83
  }
84
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
34
85
  // Auto-verwerking (1.0.64) neemt alleen aan; deze statussen betekenen dat de oude
35
86
  // route tóch al belading/verzendbrief heeft gedaan → nooit nog eens versturen.
36
87
  const AUTO_ALREADY_SENT = new Set(["sending_fulfillment", "generating_delivery_note", "done"]);
@@ -198,7 +249,12 @@ async function buildLoading(supabase, orderRef) {
198
249
  const shipKey = (dl) => (deliveries.length <= 1 ? foKey : `${foKey}|${dl}`);
199
250
  const [foIds, lcIds, itemIds] = await Promise.all([
200
251
  ensureIds(supabase, "fulfillment_order", orderIds.length ? deliveries.map(shipKey) : []),
201
- ensureIds(supabase, "load_carrier", [...carts.keys()]),
252
+ ensureIds(supabase, "load_carrier", [...carts.keys()], (ck) => {
253
+ const c = carts.get(ck);
254
+ const firstRef = [...new Set(c.lines.map((l) => l.ref))].sort()[0] ?? "";
255
+ const readable = readableCartRef(firstRef, c.label);
256
+ return [...(readable ? [readable] : []), shortCartCode(ck), shortCartCode(ck, 1), shortCartCode(ck, 2)];
257
+ }),
202
258
  ensureIds(supabase, "load_carrier_item", [...carts].flatMap(([ck, c]) => c.lines.map((l) => `${ck}|${l.orderId}|${l.key}`))),
203
259
  ]);
204
260
  const carriers = [...carts].map(([ck, c], i) => ({
@@ -249,6 +305,43 @@ async function buildLoading(supabase, orderRef) {
249
305
  createdAt: a.created_at,
250
306
  }));
251
307
  }
308
+ // Controle tegen Floriday Suppliers API 2026v1 (FulfillmentOrderCreate / AddLoadCarrierConfiguration).
309
+ for (const s of shipments) {
310
+ const nm = s.orderRefs.join(", ");
311
+ if (!UUID_RE.test(s.fulfillmentOrderId))
312
+ blockers.push(`Opdracht voor ${nm} heeft geen geldig opdrachtkenmerk (uuid). [fulfillmentOrderId]`);
313
+ if (s.deliveryOrderId && !UUID_RE.test(s.deliveryOrderId))
314
+ blockers.push(`Levering voor ${nm} heeft geen geldig Floriday-kenmerk (uuid). [deliveryOrderId]`);
315
+ if (!s.carriers.length)
316
+ blockers.push(`Opdracht voor ${nm} heeft geen karren. [loadCarriers]`);
317
+ const seen = new Set();
318
+ s.carriers.forEach((c, ci) => {
319
+ const f = `LoadCarriers[${ci}]`;
320
+ const ref = c.loadCarrierReference ?? "";
321
+ if (!ref)
322
+ blockers.push(`Kar ${c.cartLabel} heeft geen karkenmerk. [${f}.LoadCarrierReference]`);
323
+ else if (ref.length > LOAD_CARRIER_REF_MAX)
324
+ blockers.push(`Kar ${c.cartLabel} heeft een kenmerk van ${ref.length} tekens; Floriday staat er maximaal ${LOAD_CARRIER_REF_MAX} toe. [${f}.LoadCarrierReference]`);
325
+ if (ref && seen.has(ref))
326
+ blockers.push(`Karkenmerk ${ref} komt twee keer voor in dezelfde opdracht. [${f}.LoadCarrierReference]`);
327
+ seen.add(ref);
328
+ if (!(c.sortIndex >= 1))
329
+ blockers.push(`Kar ${c.cartLabel} heeft geen geldige volgorde. [${f}.SortIndex]`);
330
+ if (c.additionalLayers != null && !(Number.isInteger(c.additionalLayers) && c.additionalLayers >= 0))
331
+ blockers.push(`Kar ${c.cartLabel}: aantal extra lagen moet een heel getal van 0 of meer zijn. [${f}.NumberOfAdditionalLayers]`);
332
+ if (!c.items.length)
333
+ blockers.push(`Kar ${c.cartLabel} heeft geen regels. [${f}.Items]`);
334
+ c.items.forEach((it, ii) => {
335
+ const g = `${f}.Items[${ii}]`;
336
+ if (!UUID_RE.test(it.loadCarrierItemId))
337
+ blockers.push(`Regel ${ii + 1} op kar ${c.cartLabel} heeft geen geldig regelkenmerk (uuid). [${g}.LoadCarrierItemId]`);
338
+ if (it.fulfillmentRequestId && !UUID_RE.test(it.fulfillmentRequestId))
339
+ blockers.push(`Regel ${ii + 1} op kar ${c.cartLabel} (${it.orderRef}) heeft geen geldig Floriday-verzoek (uuid). [${g}.FulfillmentRequestId]`);
340
+ if (!(Number.isInteger(it.numberOfPackages) && it.numberOfPackages >= 1))
341
+ blockers.push(`Regel ${ii + 1} op kar ${c.cartLabel} (${it.orderRef}) heeft geen geldig aantal fusten. [${g}.NumberOfPackages]`);
342
+ });
343
+ });
344
+ }
252
345
  const uniqBlockers = [...new Set(blockers)];
253
346
  return {
254
347
  fulfillmentOrderId: shipments[0]?.fulfillmentOrderId ?? null,
@@ -282,7 +375,7 @@ export const sendFloridayLoading = createServerFn({ method: "POST" })
282
375
  const p = await buildLoading(supabase, data.orderRef);
283
376
  if (!p.canSend)
284
377
  throw new Error(`Niet verstuurd: ${p.blockers.join(" ") || "geen opdracht."}`);
285
- const { sendFulfillmentOrder } = await import("./floridayFulfillmentSend.server");
378
+ const { sendFulfillmentOrder, floridayFoutTekst } = await import("./floridayFulfillmentSend.server");
286
379
  const log = async (s, row) => {
287
380
  const { error } = await supabase.from("floriday_loading_attempts").insert({
288
381
  fulfillment_order_id: s.fulfillmentOrderId, delivery_order_id: s.deliveryOrderId,
@@ -326,7 +419,7 @@ export const sendFloridayLoading = createServerFn({ method: "POST" })
326
419
  const code = String(body?.code ?? (httpStatus && httpStatus < 400 ? "ok" : `http_${httpStatus}`));
327
420
  const accepted = httpStatus === 200 && body?.ok === true && ACCEPTED.has(code);
328
421
  const message = accepted ? (code === "created" ? "Belading verstuurd, verzendbrief volgt via de Engine." : "Belading was al verstuurd (niets dubbel aangemaakt), verzendbrief volgt via de Engine.")
329
- : arr(body?.errors).map((e) => (typeof e === "string" ? e : e?.message ?? JSON.stringify(e))).join("; ") || body?.message || code;
422
+ : floridayFoutTekst("Floriday weigert de opdracht", { httpStatus: httpStatus ?? 0, body });
330
423
  await log(s, {
331
424
  step: "send", http_status: httpStatus, code, message,
332
425
  warnings: arr(body?.warnings), skipped_requests: arr(body?.skippedRequests), request_summary: summary,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/floriday-afhandeling-module",
3
- "version": "1.0.52",
3
+ "version": "1.0.56",
4
4
  "private": false,
5
5
  "sideEffects": false,
6
6
  "type": "module",