@flowselections/logistiek-engine 1.0.99 → 1.0.100

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 (47) hide show
  1. package/dist-lib/components/BeladingIndelingCard.d.ts.map +1 -1
  2. package/dist-lib/components/BeladingIndelingCard.js +5 -1
  3. package/dist-lib/integrations/supabase/auth-middleware.d.ts +448 -6
  4. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  5. package/dist-lib/integrations/supabase/client.server.d.ts +448 -6
  6. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  7. package/dist-lib/integrations/supabase/moduleClient.d.ts +448 -6
  8. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  9. package/dist-lib/integrations/supabase/types.d.ts +462 -6
  10. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  11. package/dist-lib/lib/cartCoverage.functions.d.ts +448 -6
  12. package/dist-lib/lib/cartCoverage.functions.d.ts.map +1 -1
  13. package/dist-lib/lib/controlScan.server.d.ts +8 -0
  14. package/dist-lib/lib/controlScan.server.d.ts.map +1 -1
  15. package/dist-lib/lib/controlScan.server.js +49 -5
  16. package/dist-lib/lib/floridayCancellation.server.d.ts +15 -0
  17. package/dist-lib/lib/floridayCancellation.server.d.ts.map +1 -0
  18. package/dist-lib/lib/floridayCancellation.server.js +89 -0
  19. package/dist-lib/lib/floridayCancellation.test.d.ts +2 -0
  20. package/dist-lib/lib/floridayCancellation.test.d.ts.map +1 -0
  21. package/dist-lib/lib/floridayCancellation.test.js +42 -0
  22. package/dist-lib/lib/floridayDocuments.functions.d.ts +1344 -18
  23. package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
  24. package/dist-lib/lib/floridayPush.functions.d.ts +448 -6
  25. package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
  26. package/dist-lib/lib/layerUtilization.d.ts +2 -0
  27. package/dist-lib/lib/layerUtilization.d.ts.map +1 -0
  28. package/dist-lib/lib/layerUtilization.js +11 -0
  29. package/dist-lib/lib/layerUtilization.test.d.ts +2 -0
  30. package/dist-lib/lib/layerUtilization.test.d.ts.map +1 -0
  31. package/dist-lib/lib/layerUtilization.test.js +11 -0
  32. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +2240 -30
  33. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
  34. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  35. package/dist-lib/lib/loadCarrierPlanning.server.js +10 -1
  36. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +896 -12
  37. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
  38. package/dist-lib/lib/logisticsRecalculate.functions.d.ts +448 -6
  39. package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
  40. package/dist-lib/lib/moduleVersion.d.ts +1 -1
  41. package/dist-lib/lib/moduleVersion.d.ts.map +1 -1
  42. package/dist-lib/lib/moduleVersion.js +1 -1
  43. package/dist-lib/lib/plannerDiff.functions.d.ts +448 -6
  44. package/dist-lib/lib/plannerDiff.functions.d.ts.map +1 -1
  45. package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -1
  46. package/dist-lib/lib/shippingNoteQueue.server.js +11 -0
  47. package/package.json +2 -2
@@ -8,6 +8,14 @@ export interface ControlScanRun {
8
8
  }
9
9
  /** Maximaal aantal wachtrondes op Floriday voordat de controle als mislukt stopt. */
10
10
  export declare const CONTROL_SCAN_MAX_ATTEMPTS = 60;
11
+ /** Maximale wachttijd sinds goedkeuring (uren). */
12
+ export declare const CONTROL_SCAN_MAX_HOURS = 24;
13
+ /** Is de wachtgrens (pogingen of tijd) bereikt? */
14
+ export declare function controlWaitExceeded(row: {
15
+ attempts?: number | null;
16
+ approved_at?: string | null;
17
+ created_at?: string | null;
18
+ }, now?: number): "pogingen" | "tijd" | null;
11
19
  export declare function runControlScanQueue(sb: SupabaseClient, options?: {
12
20
  limit?: number;
13
21
  }): Promise<ControlScanRun>;
@@ -1 +1 @@
1
- {"version":3,"file":"controlScan.server.d.ts","sourceRoot":"","sources":["../../src/lib/controlScan.server.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAcD,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAwC5C,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,cAAc,CAAC,CAmKzB"}
1
+ {"version":3,"file":"controlScan.server.d.ts","sourceRoot":"","sources":["../../src/lib/controlScan.server.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAiBD,qFAAqF;AACrF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,mDAAmD;AACnD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAgBzC,mDAAmD;AACnD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC1F,GAAG,GAAE,MAAmB,GACvB,UAAU,GAAG,MAAM,GAAG,IAAI,CAK5B;AA6BD,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,cAAc,EAClB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,cAAc,CAAC,CAiMzB"}
@@ -15,8 +15,12 @@
15
15
  // klantwaarden in deze code; de printer komt uit de werkwijze in de database.
16
16
  // ============================================================================
17
17
  import { printViaLayout } from "./layoutPrint.server.js";
18
+ import { isFloridayCancelled, FLORIDAY_CANCELLED_REASON } from "./floridayCancellation.server.js";
19
+ import { trace } from "./trace.server.js";
18
20
  /** Maximaal aantal wachtrondes op Floriday voordat de controle als mislukt stopt. */
19
21
  export const CONTROL_SCAN_MAX_ATTEMPTS = 60;
22
+ /** Maximale wachttijd sinds goedkeuring (uren). */
23
+ export const CONTROL_SCAN_MAX_HOURS = 24;
20
24
  function pickPdf(result) {
21
25
  const base64 = result["pdfBase64"] ??
22
26
  result["base64"] ??
@@ -28,20 +32,31 @@ function pickPdf(result) {
28
32
  null;
29
33
  return { base64: base64 ?? null, url: url ?? null };
30
34
  }
35
+ /** Is de wachtgrens (pogingen of tijd) bereikt? */
36
+ export function controlWaitExceeded(row, now = Date.now()) {
37
+ if (Number(row.attempts ?? 0) >= CONTROL_SCAN_MAX_ATTEMPTS)
38
+ return "pogingen";
39
+ const start = Date.parse(String(row.approved_at ?? row.created_at ?? ""));
40
+ if (Number.isFinite(start) && now - start >= CONTROL_SCAN_MAX_HOURS * 3600000)
41
+ return "tijd";
42
+ return null;
43
+ }
31
44
  /**
32
- * Laat de controle wachten op Floriday. Pogingen blijven meetellen; na het
33
- * maximum eindigt de controle als mislukt in plaats van eeuwig te wachten.
45
+ * Laat de controle wachten op Floriday. Na het maximum (pogingen of 24 uur)
46
+ * eindigt de controle als mislukt in plaats van eeuwig te wachten.
34
47
  * Geeft true terug als de controle nu terminaal is afgesloten.
35
48
  */
36
49
  async function keepWaiting(sb, row) {
37
- const attempts = Number(row.attempts ?? 0);
38
- if (attempts >= CONTROL_SCAN_MAX_ATTEMPTS) {
50
+ const grens = controlWaitExceeded(row);
51
+ if (grens) {
39
52
  await sb.rpc("logistics_control_scan_finish", {
40
53
  _id: row.id,
41
54
  _ok: false,
42
55
  _status: "mislukt",
43
56
  _error_code: "wachtlimiet",
44
- _error: `Na ${attempts} pogingen kende Floriday deze order nog steeds niet; de controle is gestopt. Controleer de order in Floriday en scan opnieuw.`,
57
+ _error: grens === "pogingen"
58
+ ? `Na ${row.attempts} pogingen kende Floriday deze order nog steeds niet; de controle is gestopt.`
59
+ : `Na ${CONTROL_SCAN_MAX_HOURS} uur kende Floriday deze order nog steeds niet; de controle is gestopt.`,
45
60
  });
46
61
  return true;
47
62
  }
@@ -84,6 +99,35 @@ export async function runControlScanQueue(sb, options = {}) {
84
99
  run.failed++;
85
100
  continue;
86
101
  }
102
+ // Geannuleerd in Floriday? Dan direct stoppen.
103
+ const annulering = await isFloridayCancelled(sb, {
104
+ orderId: row.order_id,
105
+ orderNumber: row.order_number,
106
+ fulfillmentOrderId: row.fulfillment_order_id ?? null,
107
+ });
108
+ if (annulering.cancelled) {
109
+ await sb.rpc("logistics_control_scan_finish", {
110
+ _id: row.id,
111
+ _ok: false,
112
+ _status: "mislukt",
113
+ _error_code: "floriday_geannuleerd",
114
+ _error: `${FLORIDAY_CANCELLED_REASON} (${annulering.bron}).`,
115
+ });
116
+ await trace(sb, {
117
+ orderRef: row.order_number,
118
+ orderSource: "floriday",
119
+ cartRef: row.cart_id,
120
+ phase: "controle",
121
+ step: "Afleverbrief gestopt: order geannuleerd",
122
+ status: "mislukt",
123
+ actor: "engine:controlepost",
124
+ errorClass: "extern",
125
+ reason: `${FLORIDAY_CANCELLED_REASON} (${annulering.bron}).`,
126
+ error: FLORIDAY_CANCELLED_REASON,
127
+ });
128
+ run.failed++;
129
+ continue;
130
+ }
87
131
  // Stand van de push naar Floriday. De belading gaat via de bestaande
88
132
  // pushwachtrij; wij wachten tot Floriday de fulfillment-order kent.
89
133
  const { data: push } = await sb
@@ -0,0 +1,15 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ export type CancellationResult = {
3
+ cancelled: true;
4
+ bron: string;
5
+ } | {
6
+ cancelled: false;
7
+ unknown?: boolean;
8
+ };
9
+ export declare const FLORIDAY_CANCELLED_REASON = "Floriday heeft deze order geannuleerd";
10
+ export declare function isFloridayCancelled(sb: SupabaseClient, input: {
11
+ orderId?: string | null;
12
+ orderNumber?: string | null;
13
+ fulfillmentOrderId?: string | null;
14
+ }): Promise<CancellationResult>;
15
+ //# sourceMappingURL=floridayCancellation.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floridayCancellation.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayCancellation.server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,kBAAkB,GAC1B;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5C,eAAO,MAAM,yBAAyB,0CAA0C,CAAC;AAIjF,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAClG,OAAO,CAAC,kBAAkB,CAAC,CAuE7B"}
@@ -0,0 +1,89 @@
1
+ // ============================================================================
2
+ // src/lib/floridayCancellation.server.ts — is de order in Floriday geannuleerd?
3
+ // ============================================================================
4
+ // Leest alleen de gegevens die de Floriday-koppelmodule al periodiek ophaalt
5
+ // (salesorders, fulfillment-orders, delivery-orders). Geen extra API-aanroep.
6
+ // Niet leesbaar of geen gegevens => "onbekend": de wachtlus gaat dan gewoon
7
+ // door en de eindgrens vangt het op. Er wordt nooit een annulering verzonnen.
8
+ // ============================================================================
9
+ export const FLORIDAY_CANCELLED_REASON = "Floriday heeft deze order geannuleerd";
10
+ const isCancelledStatus = (s) => String(s ?? "").toUpperCase() === "CANCELLED";
11
+ export async function isFloridayCancelled(sb, input) {
12
+ try {
13
+ let unknown = false;
14
+ // Salesorder-id: eerst van de order zelf, anders via de nummerkoppeling.
15
+ let salesOrderId = null;
16
+ if (input.orderId) {
17
+ const { data, error } = await sb
18
+ .from("orders")
19
+ .select("floriday_sales_order_id")
20
+ .eq("id", input.orderId)
21
+ .maybeSingle();
22
+ if (error)
23
+ unknown = true;
24
+ salesOrderId = String(data?.floriday_sales_order_id ?? "").trim() || null;
25
+ }
26
+ if (!salesOrderId && input.orderNumber) {
27
+ const { data, error } = await sb
28
+ .from("floriday_order_number_map")
29
+ .select("floriday_id")
30
+ .eq("order_number", input.orderNumber)
31
+ .limit(1)
32
+ .maybeSingle();
33
+ if (error)
34
+ unknown = true;
35
+ salesOrderId = String(data?.floriday_id ?? "").trim() || null;
36
+ }
37
+ if (salesOrderId) {
38
+ const { data, error } = await sb
39
+ .from("floriday_salesorders_cache")
40
+ .select("status, is_deleted, data")
41
+ .eq("floriday_id", salesOrderId)
42
+ .maybeSingle();
43
+ if (error)
44
+ unknown = true;
45
+ const so = data;
46
+ if (so) {
47
+ if (isCancelledStatus(so.status) || isCancelledStatus(so.data?.status)) {
48
+ return { cancelled: true, bron: "salesorder" };
49
+ }
50
+ if (so.data?.automaticallyCancelledOn)
51
+ return { cancelled: true, bron: "salesorder (automatisch geannuleerd)" };
52
+ }
53
+ }
54
+ if (input.fulfillmentOrderId) {
55
+ const { data, error } = await sb
56
+ .from("floriday_fulfillment_orders_cache")
57
+ .select("status, is_deleted, delivery_order_id")
58
+ .eq("floriday_id", input.fulfillmentOrderId)
59
+ .maybeSingle();
60
+ if (error)
61
+ unknown = true;
62
+ const fo = data;
63
+ if (fo) {
64
+ if (isCancelledStatus(fo.status))
65
+ return { cancelled: true, bron: "fulfillment-order" };
66
+ if (fo.is_deleted === true)
67
+ return { cancelled: true, bron: "fulfillment-order (verwijderd)" };
68
+ if (fo.delivery_order_id) {
69
+ const { data: d, error: dErr } = await sb
70
+ .from("floriday_delivery_orders_cache")
71
+ .select("status, is_deleted")
72
+ .eq("floriday_id", fo.delivery_order_id)
73
+ .maybeSingle();
74
+ if (dErr)
75
+ unknown = true;
76
+ const del = d;
77
+ if (del && isCancelledStatus(del.status))
78
+ return { cancelled: true, bron: "delivery-order" };
79
+ if (del && del.is_deleted === true)
80
+ return { cancelled: true, bron: "delivery-order (verwijderd)" };
81
+ }
82
+ }
83
+ }
84
+ return unknown ? { cancelled: false, unknown: true } : { cancelled: false };
85
+ }
86
+ catch {
87
+ return { cancelled: false, unknown: true };
88
+ }
89
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=floridayCancellation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floridayCancellation.test.d.ts","sourceRoot":"","sources":["../../src/lib/floridayCancellation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isFloridayCancelled } from "./floridayCancellation.server";
3
+ import { controlWaitExceeded } from "./controlScan.server";
4
+ function stub(rows) {
5
+ return {
6
+ from(table) {
7
+ const q = {
8
+ select: () => q,
9
+ eq: () => q,
10
+ limit: () => q,
11
+ maybeSingle: async () => {
12
+ const r = rows[table];
13
+ return r === "error" ? { data: null, error: { message: "x" } } : { data: r ?? null, error: null };
14
+ },
15
+ };
16
+ return q;
17
+ },
18
+ };
19
+ }
20
+ describe("isFloridayCancelled", () => {
21
+ it("geannuleerde salesorder", async () => {
22
+ const r = await isFloridayCancelled(stub({ orders: { floriday_sales_order_id: "so1" }, floriday_salesorders_cache: { status: "CANCELLED", data: {} } }), { orderId: "o1" });
23
+ expect(r.cancelled).toBe(true);
24
+ });
25
+ it("geannuleerde fulfillment-order", async () => {
26
+ const r = await isFloridayCancelled(stub({ orders: null, floriday_fulfillment_orders_cache: { status: "CANCELLED" } }), { orderId: "o1", fulfillmentOrderId: "fo1" });
27
+ expect(r).toEqual({ cancelled: true, bron: "fulfillment-order" });
28
+ });
29
+ it("onleesbare gegevens => niet geannuleerd, onbekend", async () => {
30
+ const r = await isFloridayCancelled(stub({ orders: "error", floriday_order_number_map: "error" }), {
31
+ orderId: "o1",
32
+ orderNumber: "FO-1",
33
+ });
34
+ expect(r).toEqual({ cancelled: false, unknown: true });
35
+ });
36
+ });
37
+ describe("controlWaitExceeded", () => {
38
+ const now = Date.parse("2026-10-02T12:00:00Z");
39
+ it("na 24 uur", () => expect(controlWaitExceeded({ attempts: 3, approved_at: "2026-10-01T11:00:00Z" }, now)).toBe("tijd"));
40
+ it("na 60 pogingen", () => expect(controlWaitExceeded({ attempts: 60 }, now)).toBe("pogingen"));
41
+ it("binnen grens", () => expect(controlWaitExceeded({ attempts: 5, approved_at: "2026-10-02T10:00:00Z" }, now)).toBeNull());
42
+ });