@flowselections/logistiek-engine 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +1134 -189
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +1134 -189
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +1134 -189
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +1161 -185
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.functions.d.ts +3162 -327
- package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.server.d.ts +14 -1
- package/dist-lib/lib/floridayDocuments.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.server.js +1 -1
- package/dist-lib/lib/floridayPush.functions.d.ts +1134 -189
- package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.server.d.ts +27 -21
- package/dist-lib/lib/floridayPush.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.server.js +160 -43
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +5270 -545
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +2108 -218
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts +1134 -189
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floridayPush.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayPush.server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAc/C,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD;
|
|
1
|
+
{"version":3,"file":"floridayPush.server.d.ts","sourceRoot":"","sources":["../../src/lib/floridayPush.server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAc/C,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUlD;AAcD,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAUnE;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,cAAc,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CACN;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAC7C,CAqDA;AAED,8CAA8C;AAC9C,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CA+EtB;AAQD,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG;AA6BD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,cAAc,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,eAAe,CAAC,CA0H1B;AAQD,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAS3F"}
|
|
@@ -36,51 +36,126 @@ export function hashPayload(value) {
|
|
|
36
36
|
}
|
|
37
37
|
return h1.toString(16).padStart(8, "0") + h2.toString(16).padStart(8, "0");
|
|
38
38
|
}
|
|
39
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Zoekt de delivery-order die bij een sales-order hoort. De koppeling ligt op
|
|
41
|
+
* de delivery-order: data->'fulfillmentRequests'[]->>'salesOrderId'.
|
|
42
|
+
* Bij meerdere treffers wint de meest recent opgehaalde rij (fetched_at desc).
|
|
43
|
+
*/
|
|
44
|
+
export async function findDeliveryOrderForSalesOrder(sb, salesOrderId) {
|
|
45
|
+
const { data, error } = await sb
|
|
46
|
+
.from("floriday_delivery_orders_cache")
|
|
47
|
+
.select("floriday_id, data, fetched_at")
|
|
48
|
+
.contains("data", { fulfillmentRequests: [{ salesOrderId }] })
|
|
49
|
+
.order("fetched_at", { ascending: false })
|
|
50
|
+
.limit(10);
|
|
51
|
+
if (error) {
|
|
52
|
+
return { ok: false, code: "db_error_delivery_orders", error: `Delivery-ordercache niet leesbaar: ${error.message}` };
|
|
53
|
+
}
|
|
54
|
+
const rows = Array.isArray(data) ? data : [];
|
|
55
|
+
if (rows.length === 0) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
code: "delivery_order_not_found_local",
|
|
59
|
+
error: `Nog geen delivery-order in de cache voor sales-order ${salesOrderId}. De push wacht tot de synchronisatie hem binnenhaalt.`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (rows.length > 1) {
|
|
63
|
+
console.info(`[floridayPush] ${rows.length} delivery-orders gevonden voor sales-order ${salesOrderId}; meest recent gefetchte gekozen.`);
|
|
64
|
+
}
|
|
65
|
+
const row = rows[0];
|
|
66
|
+
const payloadData = (row["data"] ?? {});
|
|
67
|
+
const requests = Array.isArray(payloadData["fulfillmentRequests"])
|
|
68
|
+
? payloadData["fulfillmentRequests"]
|
|
69
|
+
: [];
|
|
70
|
+
const fulfillmentRequestIds = requests
|
|
71
|
+
.filter((r) => String(r["salesOrderId"] ?? "") === salesOrderId)
|
|
72
|
+
.map((r) => String(r["fulfillmentRequestId"] ?? r["id"] ?? ""))
|
|
73
|
+
.filter((s) => s.length > 0)
|
|
74
|
+
.sort();
|
|
75
|
+
if (fulfillmentRequestIds.length === 0) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
code: "delivery_order_without_requests",
|
|
79
|
+
error: `Delivery-order ${String(row["floriday_id"] ?? "")} bevat geen fulfillmentRequests voor sales-order ${salesOrderId}.`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
ok: true,
|
|
84
|
+
deliveryOrderId: String(row["floriday_id"] ?? ""),
|
|
85
|
+
fulfillmentRequestIds,
|
|
86
|
+
matches: rows.length,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** Bouwt de gewenste stand voor één order. */
|
|
40
90
|
export async function buildFloridayPayload(sb, orderRef) {
|
|
41
|
-
const { data: order } = await sb
|
|
91
|
+
const { data: order, error: orderError } = await sb
|
|
42
92
|
.from("orders")
|
|
43
93
|
.select("id, order_number, floriday_sales_order_id")
|
|
44
94
|
.eq("order_number", orderRef)
|
|
45
95
|
.maybeSingle();
|
|
46
|
-
if (
|
|
47
|
-
return
|
|
96
|
+
if (orderError) {
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
code: "db_error_orders",
|
|
100
|
+
error: `Order niet leesbaar: ${orderError.message}`,
|
|
101
|
+
permanent: false,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (!order) {
|
|
105
|
+
return { ok: false, code: "order_missing", error: "Order niet gevonden in de Engine.", permanent: true };
|
|
106
|
+
}
|
|
48
107
|
const row = order;
|
|
49
|
-
const
|
|
108
|
+
const salesOrderId = row["floriday_sales_order_id"] ?? null;
|
|
109
|
+
if (!salesOrderId) {
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
code: "sales_order_missing",
|
|
113
|
+
error: "Order heeft geen Floriday sales-order; er valt niets te pushen.",
|
|
114
|
+
permanent: true,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const found = await findDeliveryOrderForSalesOrder(sb, salesOrderId);
|
|
118
|
+
if (!found.ok) {
|
|
119
|
+
// Wachttoestand, geen mislukking: de delivery-order kan later binnenkomen.
|
|
120
|
+
return { ok: false, code: found.code, error: found.error, permanent: false };
|
|
121
|
+
}
|
|
122
|
+
const { data: carts, error: cartsError } = await sb
|
|
50
123
|
.from("order_carts")
|
|
51
124
|
.select("id, cart_number, carrier_type, total_layers_used, max_layers, occupancy_pct, weight_kg, order_cart_items(product_id, product_name, crates, boxes, plants_per_crate)")
|
|
52
125
|
.eq("order_id", row["id"])
|
|
53
126
|
.order("cart_number", { ascending: true });
|
|
54
|
-
|
|
127
|
+
if (cartsError) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
code: "db_error_carts",
|
|
131
|
+
error: `Karindeling niet leesbaar: ${cartsError.message}`,
|
|
132
|
+
permanent: false,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const indeling = (Array.isArray(carts) ? carts : []).map((c) => {
|
|
136
|
+
const cart = c;
|
|
137
|
+
const items = Array.isArray(cart["order_cart_items"])
|
|
138
|
+
? cart["order_cart_items"]
|
|
139
|
+
: [];
|
|
140
|
+
return {
|
|
141
|
+
cartNumber: cart["cart_number"] ?? null,
|
|
142
|
+
carrierType: cart["carrier_type"] ?? null,
|
|
143
|
+
layersUsed: cart["total_layers_used"] ?? null,
|
|
144
|
+
items: items
|
|
145
|
+
.map((i) => ({
|
|
146
|
+
productId: i["product_id"] ?? null,
|
|
147
|
+
crates: i["crates"] ?? null,
|
|
148
|
+
boxes: i["boxes"] ?? null,
|
|
149
|
+
}))
|
|
150
|
+
.sort((a, b) => String(a.productId).localeCompare(String(b.productId))),
|
|
151
|
+
};
|
|
152
|
+
});
|
|
55
153
|
const payload = {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
salesOrderId: row["floriday_sales_order_id"] ?? null,
|
|
59
|
-
loadCarriers: safeCarts.map((c) => {
|
|
60
|
-
const cart = c;
|
|
61
|
-
const items = Array.isArray(cart["order_cart_items"])
|
|
62
|
-
? cart["order_cart_items"]
|
|
63
|
-
: [];
|
|
64
|
-
return {
|
|
65
|
-
cartNumber: cart["cart_number"] ?? null,
|
|
66
|
-
carrierType: cart["carrier_type"] ?? null,
|
|
67
|
-
layersUsed: cart["total_layers_used"] ?? null,
|
|
68
|
-
maxLayers: cart["max_layers"] ?? null,
|
|
69
|
-
occupancyPct: cart["occupancy_pct"] ?? null,
|
|
70
|
-
weightKg: cart["weight_kg"] ?? null,
|
|
71
|
-
items: items
|
|
72
|
-
.map((i) => ({
|
|
73
|
-
productId: i["product_id"] ?? null,
|
|
74
|
-
productName: i["product_name"] ?? null,
|
|
75
|
-
crates: i["crates"] ?? null,
|
|
76
|
-
boxes: i["boxes"] ?? null,
|
|
77
|
-
plantsPerCrate: i["plants_per_crate"] ?? null,
|
|
78
|
-
}))
|
|
79
|
-
.sort((a, b) => String(a.productId).localeCompare(String(b.productId))),
|
|
80
|
-
};
|
|
81
|
-
}),
|
|
154
|
+
deliveryOrderId: found.deliveryOrderId,
|
|
155
|
+
fulfillmentRequestIds: found.fulfillmentRequestIds,
|
|
82
156
|
};
|
|
83
|
-
|
|
157
|
+
// De hash bewaakt ook de karindeling, zodat een herindeling opnieuw pusht.
|
|
158
|
+
return { ok: true, payload, hash: hashPayload({ payload, indeling }) };
|
|
84
159
|
}
|
|
85
160
|
// ---------------------------------------------------------------------------
|
|
86
161
|
// In de wachtrij zetten — snel, zonder netwerk, veilig overal aan te roepen
|
|
@@ -116,6 +191,21 @@ function isPermanent(status, message) {
|
|
|
116
191
|
return true;
|
|
117
192
|
return /validat|ongeldig|invalid|schema|not found|bestaat niet/i.test(message);
|
|
118
193
|
}
|
|
194
|
+
/** Korte, stabiele foutcode om later op te kunnen filteren. */
|
|
195
|
+
function gatewayErrorCode(status, payloadOk) {
|
|
196
|
+
if (status === null)
|
|
197
|
+
return "unknown";
|
|
198
|
+
if (status >= 200 && status < 300)
|
|
199
|
+
return payloadOk === true ? "unknown" : "gateway_ok_unreadable";
|
|
200
|
+
if (status >= 500)
|
|
201
|
+
return "gateway_5xx";
|
|
202
|
+
if (status === 400 || status === 401 || status === 404 || status === 429) {
|
|
203
|
+
return `gateway_${status}`;
|
|
204
|
+
}
|
|
205
|
+
if (status >= 400)
|
|
206
|
+
return "gateway_4xx";
|
|
207
|
+
return "unknown";
|
|
208
|
+
}
|
|
119
209
|
export async function runFloridayPushQueue(sb, opts = {}) {
|
|
120
210
|
const limit = opts.limit ?? FLORIDAY_PUSH_BATCH;
|
|
121
211
|
const deadlineAt = opts.deadlineAt ?? Date.now() + 10000;
|
|
@@ -148,13 +238,18 @@ export async function runFloridayPushQueue(sb, opts = {}) {
|
|
|
148
238
|
let error = null;
|
|
149
239
|
let sentHash = null;
|
|
150
240
|
let fulfillmentOrderId = null;
|
|
241
|
+
let gatewayStatus = null;
|
|
242
|
+
let errorCode = null;
|
|
243
|
+
let response = null;
|
|
151
244
|
try {
|
|
152
245
|
const built = await buildFloridayPayload(sb, orderRef);
|
|
153
|
-
if (!built) {
|
|
154
|
-
//
|
|
246
|
+
if (!built.ok) {
|
|
247
|
+
// Wachttoestand (delivery-order nog niet gesynchroniseerd) of een
|
|
248
|
+
// databasefout; permanent alleen als de order zelf niet kan bestaan.
|
|
155
249
|
ok = false;
|
|
156
|
-
permanent =
|
|
157
|
-
error =
|
|
250
|
+
permanent = built.permanent;
|
|
251
|
+
error = built.error;
|
|
252
|
+
errorCode = built.code;
|
|
158
253
|
}
|
|
159
254
|
else if (built.hash === lastSentHash) {
|
|
160
255
|
// Identieke stand: niets versturen, wel als geslaagd afronden.
|
|
@@ -163,22 +258,41 @@ export async function runFloridayPushQueue(sb, opts = {}) {
|
|
|
163
258
|
out.skipped++;
|
|
164
259
|
}
|
|
165
260
|
else {
|
|
166
|
-
const res =
|
|
167
|
-
|
|
261
|
+
const res = await sendFlorydayFulfillmentOrder(sb, built.payload);
|
|
262
|
+
gatewayStatus = typeof res?.status === "number" ? res.status : null;
|
|
263
|
+
// Nieuw contract: { status, payload: { ok, error, fulfillmentOrderId } }.
|
|
264
|
+
// Defensief: een oudere gatewayversie gaf ok/error op het hoogste niveau.
|
|
265
|
+
const payload = (res?.payload ?? null);
|
|
266
|
+
if (!payload && res && ("ok" in res || "error" in res)) {
|
|
267
|
+
console.warn("[floridayPush] gateway gaf de oude responsvorm terug (ok/error op hoofdniveau)");
|
|
268
|
+
}
|
|
269
|
+
const payloadOk = payload?.ok ?? res?.ok;
|
|
270
|
+
const payloadError = payload?.error ?? res?.error;
|
|
271
|
+
ok = payloadOk === true;
|
|
168
272
|
sentHash = built.hash;
|
|
169
|
-
fulfillmentOrderId =
|
|
273
|
+
fulfillmentOrderId = payload?.fulfillmentOrderId ?? null;
|
|
274
|
+
response = {
|
|
275
|
+
ok: payloadOk ?? null,
|
|
276
|
+
error: payloadError ?? null,
|
|
277
|
+
fulfillmentOrderId: payload?.fulfillmentOrderId ?? null,
|
|
278
|
+
};
|
|
170
279
|
if (!ok) {
|
|
171
|
-
error =
|
|
172
|
-
|
|
280
|
+
error =
|
|
281
|
+
payloadError && String(payloadError).length > 0
|
|
282
|
+
? String(payloadError)
|
|
283
|
+
: `Floriday gaf geen bevestiging. (gatewaystatus ${gatewayStatus ?? "onbekend"})`;
|
|
284
|
+
errorCode = gatewayErrorCode(gatewayStatus, payloadOk);
|
|
285
|
+
permanent = isPermanent(gatewayStatus, error);
|
|
173
286
|
}
|
|
174
287
|
}
|
|
175
288
|
}
|
|
176
289
|
catch (e) {
|
|
177
290
|
error = String(e?.message ?? e);
|
|
291
|
+
errorCode = errorCode ?? "unknown";
|
|
178
292
|
permanent = isPermanent(null, error);
|
|
179
293
|
}
|
|
180
294
|
try {
|
|
181
|
-
const { data: outcome } = await sb.rpc("
|
|
295
|
+
const { data: outcome } = await sb.rpc("logistics_floriday_finish_push_v2", {
|
|
182
296
|
_id: id,
|
|
183
297
|
_revision: revision,
|
|
184
298
|
_ok: ok,
|
|
@@ -186,6 +300,9 @@ export async function runFloridayPushQueue(sb, opts = {}) {
|
|
|
186
300
|
_fulfillment_order_id: fulfillmentOrderId,
|
|
187
301
|
_sent_hash: sentHash,
|
|
188
302
|
_permanent: permanent,
|
|
303
|
+
_gateway_status: gatewayStatus,
|
|
304
|
+
_error_code: errorCode,
|
|
305
|
+
_response: response,
|
|
189
306
|
});
|
|
190
307
|
const status = String(outcome ?? "");
|
|
191
308
|
if (status === "sent")
|