@flowselections/floriday-verkoop-module 1.0.76 → 1.0.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.js +33 -8
- package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts.map +1 -1
- package/dist-lib/components/verkoop/EditLocalOrderDialog.js +1 -1
- package/dist-lib/components/verkoop/FloridayStageLine.d.ts +11 -0
- package/dist-lib/components/verkoop/FloridayStageLine.d.ts.map +1 -0
- package/dist-lib/components/verkoop/FloridayStageLine.js +17 -0
- package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts +1 -1
- package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts.map +1 -1
- package/dist-lib/components/verkoop/PlanCoverageBadge.js +5 -2
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.js +33 -5
- package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrdersTable.js +4 -8
- package/dist-lib/components/verkoop/VerkoopOrdersPage.js +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +1158 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/belading.server.d.ts +0 -11
- package/dist-lib/lib/belading.server.d.ts.map +1 -1
- package/dist-lib/lib/belading.server.js +4 -41
- package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
- package/dist-lib/lib/cart-replan.functions.js +3 -22
- package/dist-lib/lib/central-secrets.server.d.ts +5 -0
- package/dist-lib/lib/central-secrets.server.d.ts.map +1 -0
- package/dist-lib/lib/central-secrets.server.js +65 -0
- package/dist-lib/lib/create-order.functions.d.ts +15 -0
- package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.js +28 -13
- package/dist-lib/lib/engine-block-alerts.d.ts +22 -0
- package/dist-lib/lib/engine-block-alerts.d.ts.map +1 -0
- package/dist-lib/lib/engine-block-alerts.js +43 -0
- package/dist-lib/lib/engine-block-alerts.server.d.ts +7 -0
- package/dist-lib/lib/engine-block-alerts.server.d.ts.map +1 -0
- package/dist-lib/lib/engine-block-alerts.server.js +75 -0
- package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-mirror.functions.js +21 -36
- package/dist-lib/lib/floriday-status.d.ts +40 -0
- package/dist-lib/lib/floriday-status.d.ts.map +1 -0
- package/dist-lib/lib/floriday-status.js +80 -0
- package/dist-lib/lib/floriday-status.server.d.ts +7 -0
- package/dist-lib/lib/floriday-status.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-status.server.js +74 -0
- package/dist-lib/lib/load-carriers.server.d.ts +1 -1
- package/dist-lib/lib/load-carriers.server.d.ts.map +1 -1
- package/dist-lib/lib/load-carriers.server.js +3 -6
- package/dist-lib/lib/logistics-engine.server.d.ts.map +1 -1
- package/dist-lib/lib/logistics-engine.server.js +2 -22
- package/dist-lib/lib/order-block-mail.server.d.ts.map +1 -1
- package/dist-lib/lib/order-block-mail.server.js +31 -15
- package/dist-lib/lib/order-cancel.server.d.ts +9 -0
- package/dist-lib/lib/order-cancel.server.d.ts.map +1 -1
- package/dist-lib/lib/order-cancel.server.js +90 -0
- package/dist-lib/lib/plan-coverage.check.d.ts +2 -0
- package/dist-lib/lib/plan-coverage.check.d.ts.map +1 -0
- package/dist-lib/lib/plan-coverage.check.js +17 -0
- package/dist-lib/lib/plan-coverage.d.ts +12 -0
- package/dist-lib/lib/plan-coverage.d.ts.map +1 -1
- package/dist-lib/lib/plan-coverage.js +27 -1
- package/dist-lib/lib/plan-coverage.server.d.ts.map +1 -1
- package/dist-lib/lib/plan-coverage.server.js +20 -13
- package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
- package/dist-lib/lib/salesorders-list.server.js +54 -0
- package/dist-lib/lib/salesorders-mapping.d.ts +11 -0
- package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.d.ts +1 -5
- package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.js +26 -2
- package/package.json +2 -2
|
@@ -14,15 +14,4 @@ export interface BeladingOption {
|
|
|
14
14
|
* gebruik wijzigen.
|
|
15
15
|
*/
|
|
16
16
|
export declare function computeBeladingByProduct(supabase: any, productIds: string[]): Promise<Record<string, BeladingOption[]>>;
|
|
17
|
-
export declare const DISABLED_BELADING_MESSAGE = "Deze belading gebruikt een ladingdrager die is uitgeschakeld in de Logistics Engine.";
|
|
18
|
-
/**
|
|
19
|
-
* Blokkeert opslaan van een order met een belading die de Engine niet toestaat.
|
|
20
|
-
* Regels zonder expliciete belading worden overgeslagen.
|
|
21
|
-
*/
|
|
22
|
-
export declare function assertBeladingAllowed(supabase: any, lines: Array<{
|
|
23
|
-
product_id: string;
|
|
24
|
-
plants_per_crate?: number | null;
|
|
25
|
-
crates_per_layer?: number | null;
|
|
26
|
-
layers_per_cart?: number | null;
|
|
27
|
-
}>): Promise<void>;
|
|
28
17
|
//# sourceMappingURL=belading.server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"belading.server.d.ts","sourceRoot":"","sources":["../../src/lib/belading.server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"belading.server.d.ts","sourceRoot":"","sources":["../../src/lib/belading.server.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAWD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC,CA6N3C"}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
// Beladingen (packing-configuraties) per product — centrale bron.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// ook niet worden opgeslagen.
|
|
2
|
+
// Geen eigen controle op ladingdragers: alleen de Logistiek Engine beslist
|
|
3
|
+
// of een belading kan (koppelprompt 22).
|
|
5
4
|
import { cratePackageName, loadCarrierName } from "./load-carrier-labels";
|
|
6
|
-
import { fetchAllowedLoadCarriers } from "./load-carriers.server";
|
|
7
|
-
import { normalizeLoadCarrierCode } from "./load-carriers";
|
|
8
5
|
/**
|
|
9
6
|
* Alle beladingen per product, al gefilterd op de ladingdragers die de
|
|
10
7
|
* Logistics Engine toestaat. Nooit cachen: de Engine-instelling kan tijdens
|
|
@@ -27,7 +24,7 @@ export async function computeBeladingByProduct(supabase, productIds) {
|
|
|
27
24
|
membersByGroup.set(gid, arr);
|
|
28
25
|
}
|
|
29
26
|
const lookupIds = Array.from(new Set([...ids, ...Array.from(membersByGroup.values()).flat()]));
|
|
30
|
-
const [tiRes, draftRes, prodRes
|
|
27
|
+
const [tiRes, draftRes, prodRes] = await Promise.all([
|
|
31
28
|
supabase
|
|
32
29
|
.from("floriday_trade_items_cache")
|
|
33
30
|
.select("floriday_id, data")
|
|
@@ -37,7 +34,6 @@ export async function computeBeladingByProduct(supabase, productIds) {
|
|
|
37
34
|
.from("products")
|
|
38
35
|
.select("id, plants_per_crate, crates_per_layer, layers_per_cart, custom_fields, trade_item_key")
|
|
39
36
|
.in("id", lookupIds),
|
|
40
|
-
fetchAllowedLoadCarriers(supabase),
|
|
41
37
|
]);
|
|
42
38
|
const packsById = new Map();
|
|
43
39
|
const push = (key, ppc, cpl, lpc, isDefault, crateCode, cartCode) => {
|
|
@@ -140,18 +136,6 @@ export async function computeBeladingByProduct(supabase, productIds) {
|
|
|
140
136
|
crateDescriptions[String(d.code)] = desc;
|
|
141
137
|
}
|
|
142
138
|
}
|
|
143
|
-
// Engine-filter: een belading met een uitgeschakelde ladingdrager valt af.
|
|
144
|
-
const allowed = allowedCarriers.allowed;
|
|
145
|
-
const carrierAllowed = (cartCode) => {
|
|
146
|
-
// Fail-closed: zonder herkenbare ladingdrager kan niet worden vastgesteld
|
|
147
|
-
// dat de Engine deze belading toestaat.
|
|
148
|
-
if (!cartCode)
|
|
149
|
-
return false;
|
|
150
|
-
const norm = normalizeLoadCarrierCode(cartCode);
|
|
151
|
-
if (!norm)
|
|
152
|
-
return false;
|
|
153
|
-
return allowed.includes(norm);
|
|
154
|
-
};
|
|
155
139
|
for (const id of ids) {
|
|
156
140
|
const own = packsById.get(id) ?? [];
|
|
157
141
|
const memberCombos = [];
|
|
@@ -167,7 +151,7 @@ export async function computeBeladingByProduct(supabase, productIds) {
|
|
|
167
151
|
continue;
|
|
168
152
|
merged.push({ ...c, is_default: c.is_default && own.includes(c) });
|
|
169
153
|
}
|
|
170
|
-
const filtered = merged
|
|
154
|
+
const filtered = merged; // geen eigen dragerfilter: de Engine beslist
|
|
171
155
|
if (filtered.length && !filtered.some((x) => x.is_default))
|
|
172
156
|
filtered[0].is_default = true;
|
|
173
157
|
byProduct[id] = filtered
|
|
@@ -187,24 +171,3 @@ export async function computeBeladingByProduct(supabase, productIds) {
|
|
|
187
171
|
}
|
|
188
172
|
return byProduct;
|
|
189
173
|
}
|
|
190
|
-
export const DISABLED_BELADING_MESSAGE = "Deze belading gebruikt een ladingdrager die is uitgeschakeld in de Logistics Engine.";
|
|
191
|
-
/**
|
|
192
|
-
* Blokkeert opslaan van een order met een belading die de Engine niet toestaat.
|
|
193
|
-
* Regels zonder expliciete belading worden overgeslagen.
|
|
194
|
-
*/
|
|
195
|
-
export async function assertBeladingAllowed(supabase, lines) {
|
|
196
|
-
const relevant = lines.filter((l) => l.plants_per_crate && l.crates_per_layer && l.layers_per_cart);
|
|
197
|
-
if (!relevant.length)
|
|
198
|
-
return;
|
|
199
|
-
const byProduct = await computeBeladingByProduct(supabase, relevant.map((l) => l.product_id));
|
|
200
|
-
for (const l of relevant) {
|
|
201
|
-
const opts = byProduct[l.product_id];
|
|
202
|
-
if (!opts || opts.length === 0)
|
|
203
|
-
throw new Error(DISABLED_BELADING_MESSAGE);
|
|
204
|
-
const ok = opts.some((o) => o.plants_per_crate === Number(l.plants_per_crate) &&
|
|
205
|
-
o.crates_per_layer === Number(l.crates_per_layer) &&
|
|
206
|
-
o.layers_per_cart === Number(l.layers_per_cart));
|
|
207
|
-
if (!ok)
|
|
208
|
-
throw new Error(DISABLED_BELADING_MESSAGE);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-replan.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cart-replan.functions.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,sBAAsB,CAAC;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM;QAYrD,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAlBnB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GAAG,OAAO,CAAC;IACV,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC,
|
|
1
|
+
{"version":3,"file":"cart-replan.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cart-replan.functions.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,sBAAsB,CAAC;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM;QAYrD,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAlBnB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GAAG,OAAO,CAAC;IACV,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC,CA+YD;AA4BD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM;QAzBxD,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAoBnB;AAED,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;QA/B3B,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GA6BhB,CAAC;AAML,wBAAsB,oBAAoB,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC;IAC/D,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE,CAAC,CAED;AAMD,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;;;GAU7B,CAAC;AAEL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;QAle3B,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAgehB,CAAC"}
|
|
@@ -263,28 +263,9 @@ export async function replanScopeInternal(scope) {
|
|
|
263
263
|
const reason = `Karindeling geblokkeerd voor order(s) ${nummers}: ` +
|
|
264
264
|
`${blockedItems.length} orderregel(s) zonder volledige belading` +
|
|
265
265
|
(velden ? ` (ontbreekt: ${velden})` : "") + ".";
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
p_details: { source: "floriday-verkoop-module/cart-replan", items: blockedItems },
|
|
270
|
-
});
|
|
271
|
-
if (blockErr) {
|
|
272
|
-
warnings.push(`Blokkade kon niet worden vastgelegd in de engine (${blockErr.message}); regels overgeslagen.`);
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
warnings.push(`Blokkade gemeld aan engine voor ${blockedOrderIds.length} order(s).`);
|
|
276
|
-
}
|
|
277
|
-
// Eenmalige mailmelding naar het interne adres uit de e-mailmodule.
|
|
278
|
-
const { notifyOrderBlocked } = await import("./order-block-mail.server");
|
|
279
|
-
const mail = await notifyOrderBlocked({
|
|
280
|
-
orderIds: blockedOrderIds,
|
|
281
|
-
reasonKey: blockedItems.some((b) => b.reason === "onvolledige_belading")
|
|
282
|
-
? "onvolledige_belading"
|
|
283
|
-
: "geen_belading",
|
|
284
|
-
reason,
|
|
285
|
-
details: { items: blockedItems },
|
|
286
|
-
});
|
|
287
|
-
warnings.push(...mail.warnings);
|
|
266
|
+
// Geen eigen blokkade of mail meer (koppelprompt 22): de Engine
|
|
267
|
+
// beslist zelf en meldt een definitieve blokkade.
|
|
268
|
+
warnings.push(reason);
|
|
288
269
|
}
|
|
289
270
|
}
|
|
290
271
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Gedeeld gateway-geheim: AUTH_GATEWAY_HMAC_SECRET, anders de centrale route. */
|
|
2
|
+
export declare function getFloridayGatewaySecret(): Promise<string>;
|
|
3
|
+
/** Adres van de Shell-host waar de gateway draait: PUBLIC_BASE_URL, anders centraal. */
|
|
4
|
+
export declare function getGatewayBaseUrl(): Promise<string>;
|
|
5
|
+
//# sourceMappingURL=central-secrets.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"central-secrets.server.d.ts","sourceRoot":"","sources":["../../src/lib/central-secrets.server.ts"],"names":[],"mappings":"AA+BA,kFAAkF;AAClF,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAchE;AAED,wFAAwF;AACxF,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAczD"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Server-only: geheimen en adressen uit de centrale route (zelfde werkwijze als
|
|
2
|
+
// de Afhandeling-module). Geen vaste waarden; ontbreekt iets, dan een fout
|
|
3
|
+
// (fail closed). Waarden worden nooit gelogd.
|
|
4
|
+
const TTL_MS = 60000;
|
|
5
|
+
const cache = new Map();
|
|
6
|
+
async function memo(key, fetcher) {
|
|
7
|
+
const hit = cache.get(key);
|
|
8
|
+
if (hit && hit.expiresAt > Date.now())
|
|
9
|
+
return hit.value;
|
|
10
|
+
const v = await fetcher();
|
|
11
|
+
cache.set(key, { value: v, expiresAt: Date.now() + TTL_MS });
|
|
12
|
+
return v;
|
|
13
|
+
}
|
|
14
|
+
function centralEnv() {
|
|
15
|
+
const url = process.env.CENTRAL_AUTH_URL?.trim();
|
|
16
|
+
const secret = process.env.CENTRAL_AUTH_SECRET;
|
|
17
|
+
if (!url || !secret) {
|
|
18
|
+
throw new Error("CENTRAL_AUTH_URL of CENTRAL_AUTH_SECRET ontbreekt — centrale route niet bereikbaar");
|
|
19
|
+
}
|
|
20
|
+
return { url: url.replace(/\/+$/, ""), secret };
|
|
21
|
+
}
|
|
22
|
+
function stripBase(url) {
|
|
23
|
+
const t = url.trim().replace(/\/+$/, "");
|
|
24
|
+
if (!/^https?:\/\//i.test(t))
|
|
25
|
+
throw new Error("Ongeldig gateway-adres (zonder http/https)");
|
|
26
|
+
return t;
|
|
27
|
+
}
|
|
28
|
+
/** Gedeeld gateway-geheim: AUTH_GATEWAY_HMAC_SECRET, anders de centrale route. */
|
|
29
|
+
export async function getFloridayGatewaySecret() {
|
|
30
|
+
const local = process.env.AUTH_GATEWAY_HMAC_SECRET;
|
|
31
|
+
if (local)
|
|
32
|
+
return local;
|
|
33
|
+
return memo("floriday-gateway-secret", async () => {
|
|
34
|
+
const { url, secret } = centralEnv();
|
|
35
|
+
const res = await fetch(`${url}/api/secret/floriday_gateway_secret`, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { Authorization: `Bearer ${secret}` },
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok)
|
|
40
|
+
throw new Error(`Gateway-geheim niet beschikbaar (centrale route HTTP ${res.status})`);
|
|
41
|
+
const data = (await res.json().catch(() => null));
|
|
42
|
+
if (!data?.value)
|
|
43
|
+
throw new Error("Gateway-geheim niet beschikbaar (leeg antwoord van de centrale route)");
|
|
44
|
+
return data.value;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Adres van de Shell-host waar de gateway draait: PUBLIC_BASE_URL, anders centraal. */
|
|
48
|
+
export async function getGatewayBaseUrl() {
|
|
49
|
+
const env = process.env.PUBLIC_BASE_URL?.trim();
|
|
50
|
+
if (env)
|
|
51
|
+
return stripBase(env);
|
|
52
|
+
return memo("shell-host", async () => {
|
|
53
|
+
const { url, secret } = centralEnv();
|
|
54
|
+
const res = await fetch(`${url}/api/shell-host`, {
|
|
55
|
+
method: "GET",
|
|
56
|
+
headers: { Authorization: `Bearer ${secret}` },
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok)
|
|
59
|
+
throw new Error(`Gateway-adres niet beschikbaar (centrale route HTTP ${res.status})`);
|
|
60
|
+
const data = (await res.json().catch(() => null));
|
|
61
|
+
if (!data?.shell_host)
|
|
62
|
+
throw new Error("Gateway-adres niet beschikbaar (shell_host ontbreekt)");
|
|
63
|
+
return stripBase(data.shell_host);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -237,4 +237,19 @@ export declare const updateLocalOrder: import("@tanstack/start-client-core").Opt
|
|
|
237
237
|
}, Promise<{
|
|
238
238
|
ok: true;
|
|
239
239
|
}>>;
|
|
240
|
+
export declare const getEffectivePrices: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
241
|
+
supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
|
|
242
|
+
userId: string;
|
|
243
|
+
claims: import("@supabase/auth-js").User;
|
|
244
|
+
}, undefined, undefined, undefined>], (input: unknown) => {
|
|
245
|
+
customerId: string;
|
|
246
|
+
lines: {
|
|
247
|
+
productId: string;
|
|
248
|
+
quantity?: number | undefined;
|
|
249
|
+
}[];
|
|
250
|
+
onDate?: string | undefined;
|
|
251
|
+
}, Promise<Record<string, {
|
|
252
|
+
price: number;
|
|
253
|
+
source: string | null;
|
|
254
|
+
} | null>>>;
|
|
240
255
|
//# sourceMappingURL=create-order.functions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-order.functions.d.ts","sourceRoot":"","sources":["../../src/lib/create-order.functions.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,2BAA2B;;;;;;GA+CpC,CAAC;AAIL,eAAO,MAAM,2BAA2B;;;;0CAElB,OAAO;;;;GAoDzB,CAAC;AAWL,eAAO,MAAM,0BAA0B;;;;;;YA+D7B,MAAM;iBACD,MAAM;sBACD,MAAM,GAAG,IAAI;cACrB,MAAM;oBACA,MAAM,GAAG,IAAI;0BACP,MAAM;0BACN,MAAM;yBACP,MAAM;wBACP,MAAM;wBACN,MAAM;yBACL,MAAM;kBACb,OAAO;gBACT,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS;;GA6RpD,CAAC;AAGL,eAAO,MAAM,kCAAkC;;;;0CAEzB,OAAO;;;;;;;;;;;;;;;;;;;;;;GAkDzB,CAAC;AAKL,eAAO,MAAM,qBAAqB;;;;;;YAoBI,MAAM;;;GAIxC,CAAC;AAGL,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;GAWnC,CAAC;AASL,eAAO,MAAM,8BAA8B;;;;8CAEjB,OAAO;;;;GAU7B,CAAC;AASL,eAAO,MAAM,mBAAmB;;;;;;;;0BAgBuB,MAAM;0BAAoB,MAAM;yBAAmB,MAAM;;;GA8C5G,CAAC;AAGL,eAAO,MAAM,kBAAkB;;;;;;GAU3B,CAAC;AA2CL,eAAO,MAAM,iBAAiB;;;;8CAEJ,OAAO;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"create-order.functions.d.ts","sourceRoot":"","sources":["../../src/lib/create-order.functions.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,2BAA2B;;;;;;GA+CpC,CAAC;AAIL,eAAO,MAAM,2BAA2B;;;;0CAElB,OAAO;;;;GAoDzB,CAAC;AAWL,eAAO,MAAM,0BAA0B;;;;;;YA+D7B,MAAM;iBACD,MAAM;sBACD,MAAM,GAAG,IAAI;cACrB,MAAM;oBACA,MAAM,GAAG,IAAI;0BACP,MAAM;0BACN,MAAM;yBACP,MAAM;wBACP,MAAM;wBACN,MAAM;yBACL,MAAM;kBACb,OAAO;gBACT,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS;;GA6RpD,CAAC;AAGL,eAAO,MAAM,kCAAkC;;;;0CAEzB,OAAO;;;;;;;;;;;;;;;;;;;;;;GAkDzB,CAAC;AAKL,eAAO,MAAM,qBAAqB;;;;;;YAoBI,MAAM;;;GAIxC,CAAC;AAGL,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;GAWnC,CAAC;AASL,eAAO,MAAM,8BAA8B;;;;8CAEjB,OAAO;;;;GAU7B,CAAC;AASL,eAAO,MAAM,mBAAmB;;;;;;;;0BAgBuB,MAAM;0BAAoB,MAAM;yBAAmB,MAAM;;;GA8C5G,CAAC;AAGL,eAAO,MAAM,kBAAkB;;;;;;GAU3B,CAAC;AA2CL,eAAO,MAAM,iBAAiB;;;;8CAEJ,OAAO;;;;;;;;;;;;;;;;;;;;;;;aA0OY,MAAM;GAE/C,CAAC;AAKL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;GAY7B,CAAC;AAQL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;GAoG7B,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;8CAER,OAAO;;;;GAyB7B,CAAC;AAyCL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;aA0JG,MAAM;iBACQ,MAAM,GAAG,IAAI;kBACX,MAAM;;YAEnB,MAAM,GAAG,IAAI;;;;YAkB7B,MAAM;mBACS,MAAM,GAAG,IAAI;qBACT,MAAM;;cAErB,MAAM,GAAG,IAAI;;;;;;GAQpC,CAAC;AAIL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;;;;;;;;;;;;;;GAoN7B,CAAC;AAKL,eAAO,MAAM,kBAAkB;;;;8CAEL,OAAO;;;;;;;;WAUM,MAAM;YAAU,MAAM,GAAG,IAAI;WAahE,CAAC"}
|
|
@@ -677,19 +677,13 @@ export const createManualOrder = createServerFn({ method: "POST" })
|
|
|
677
677
|
const { assertOrderAllowed } = await import("./logistics-stock.server");
|
|
678
678
|
await assertOrderAllowed(context.supabase, data.lines.map((l) => ({ productId: l.product_id, quantity: Number(l.quantity) })));
|
|
679
679
|
}
|
|
680
|
-
// Belading: alleen configuraties met een door de Engine toegestane
|
|
681
|
-
// ladingdrager mogen worden opgeslagen.
|
|
682
|
-
{
|
|
683
|
-
const { assertBeladingAllowed } = await import("./belading.server");
|
|
684
|
-
await assertBeladingAllowed(context.supabase, data.lines);
|
|
685
|
-
}
|
|
686
680
|
// Validatie eerst mogelijke leverdatum — o.b.v. de aanmeldmomenten van de
|
|
687
681
|
// vervoerder (pickup_moments), niet enkel kalenderdagen. Een reservering
|
|
688
682
|
// heeft nog geen vervoerder en dus geen leverdatumvalidatie.
|
|
689
683
|
if (!data.isReservation && !data.carrierId) {
|
|
690
684
|
throw new Error("Selecteer een vervoerder");
|
|
691
685
|
}
|
|
692
|
-
// Ladingdrager:
|
|
686
|
+
// Ladingdrager: zonder keuze de standaard van de Engine; geen eigen controle.
|
|
693
687
|
const { resolveLoadCarrierType } = await import("./load-carriers.server");
|
|
694
688
|
const loadCarrierType = await resolveLoadCarrierType(context.supabase, data.loadCarrierType);
|
|
695
689
|
const c = data.carrierId
|
|
@@ -1083,12 +1077,6 @@ export const getLocalOrderForEdit = createServerFn({ method: "POST" })
|
|
|
1083
1077
|
if (src === "floriday" || src === "fo") {
|
|
1084
1078
|
throw new Error("FO-orders kunnen niet bewerkt worden.");
|
|
1085
1079
|
}
|
|
1086
|
-
// Opslaan blokkeren zolang de order een door de Engine uitgeschakelde
|
|
1087
|
-
// ladingdrager heeft.
|
|
1088
|
-
{
|
|
1089
|
-
const { resolveLoadCarrierType } = await import("./load-carriers.server");
|
|
1090
|
-
await resolveLoadCarrierType(context.supabase, cf.load_carrier_type ?? null);
|
|
1091
|
-
}
|
|
1092
1080
|
const { data: items, error: iErr } = await context.supabase
|
|
1093
1081
|
.from("order_items")
|
|
1094
1082
|
.select("id, product_id, product_name, quantity, unit, products(plants_per_crate)")
|
|
@@ -1448,3 +1436,30 @@ export const updateLocalOrder = createServerFn({ method: "POST" })
|
|
|
1448
1436
|
}
|
|
1449
1437
|
return { ok: true };
|
|
1450
1438
|
});
|
|
1439
|
+
// ─── Prijs uit prijsgroep of artikel ────────────────────────────────────────
|
|
1440
|
+
// Leest per product de geldende prijs via local_effective_price (prijsgroep,
|
|
1441
|
+
// klantafspraak of artikel). Alleen lezen; geen prijs = null.
|
|
1442
|
+
export const getEffectivePrices = createServerFn({ method: "POST" })
|
|
1443
|
+
.middleware([requireSupabaseAuth])
|
|
1444
|
+
.inputValidator((input) => z
|
|
1445
|
+
.object({
|
|
1446
|
+
customerId: z.string().uuid(),
|
|
1447
|
+
onDate: z.string().optional(),
|
|
1448
|
+
lines: z.array(z.object({ productId: z.string().uuid(), quantity: z.number().optional() })).max(200),
|
|
1449
|
+
})
|
|
1450
|
+
.parse(input))
|
|
1451
|
+
.handler(async ({ data, context }) => {
|
|
1452
|
+
const out = {};
|
|
1453
|
+
for (const l of data.lines) {
|
|
1454
|
+
const { data: rows, error } = await context.supabase.rpc("local_effective_price", {
|
|
1455
|
+
_customer_id: data.customerId,
|
|
1456
|
+
_product_id: l.productId,
|
|
1457
|
+
...(data.onDate ? { _on_date: data.onDate } : {}),
|
|
1458
|
+
...(l.quantity ? { _quantity: l.quantity } : {}),
|
|
1459
|
+
});
|
|
1460
|
+
const r = Array.isArray(rows) ? rows[0] : rows;
|
|
1461
|
+
const price = Number(r?.net_price);
|
|
1462
|
+
out[l.productId] = !error && Number.isFinite(price) && price > 0 ? { price, source: r?.source ?? null } : null;
|
|
1463
|
+
}
|
|
1464
|
+
return out;
|
|
1465
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface DefinitiveBlockInfo {
|
|
2
|
+
orderId: string;
|
|
3
|
+
definitief: boolean;
|
|
4
|
+
status: string | null;
|
|
5
|
+
pogingen: number | null;
|
|
6
|
+
redenCode: string | null;
|
|
7
|
+
reden: string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseDefinitiveBlock(raw: any, fallbackOrderId: string): DefinitiveBlockInfo | null;
|
|
10
|
+
export type AlertAction = "mail" | "close" | "none";
|
|
11
|
+
/** Mail alleen bij definitief; sluiten alleen bij niet-definitief én done. */
|
|
12
|
+
export declare function decideAlertAction(info: DefinitiveBlockInfo | null, hasOpenAlert: boolean): AlertAction;
|
|
13
|
+
/** Klantnaam voor de mail: koper-naam, met handelsnaam als die afwijkt. */
|
|
14
|
+
export declare function buyerLabel(name: string | null | undefined, commercial: string | null | undefined): string;
|
|
15
|
+
export declare function buildBlockMailLines(input: {
|
|
16
|
+
orderNumber: string;
|
|
17
|
+
klant: string;
|
|
18
|
+
afleverlocatie: string | null;
|
|
19
|
+
leverdatum: string | null;
|
|
20
|
+
reden: string;
|
|
21
|
+
}): string[];
|
|
22
|
+
//# sourceMappingURL=engine-block-alerts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-block-alerts.d.ts","sourceRoot":"","sources":["../../src/lib/engine-block-alerts.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAWlG;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEpD,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,EAAE,YAAY,EAAE,OAAO,GAAG,WAAW,CAKtG;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKzG;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,EAAE,CASX"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Client-veilige beslisregels voor blokkade-alarmen (koppelprompt 22).
|
|
2
|
+
// Alleen de Logistiek Engine bepaalt of een order definitief geblokkeerd is.
|
|
3
|
+
export function parseDefinitiveBlock(raw, fallbackOrderId) {
|
|
4
|
+
const d = Array.isArray(raw) ? raw[0] : raw;
|
|
5
|
+
if (!d || typeof d !== "object")
|
|
6
|
+
return null;
|
|
7
|
+
return {
|
|
8
|
+
orderId: String(d.orderId ?? fallbackOrderId),
|
|
9
|
+
definitief: d.definitief === true,
|
|
10
|
+
status: d.status == null ? null : String(d.status),
|
|
11
|
+
pogingen: d.pogingen == null ? null : Number(d.pogingen),
|
|
12
|
+
redenCode: d.redenCode == null ? null : String(d.redenCode),
|
|
13
|
+
reden: d.reden == null ? null : String(d.reden),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Mail alleen bij definitief; sluiten alleen bij niet-definitief én done. */
|
|
17
|
+
export function decideAlertAction(info, hasOpenAlert) {
|
|
18
|
+
if (!info)
|
|
19
|
+
return "none"; // fail closed
|
|
20
|
+
if (info.definitief)
|
|
21
|
+
return "mail";
|
|
22
|
+
if (hasOpenAlert && info.status === "done")
|
|
23
|
+
return "close";
|
|
24
|
+
return "none";
|
|
25
|
+
}
|
|
26
|
+
/** Klantnaam voor de mail: koper-naam, met handelsnaam als die afwijkt. */
|
|
27
|
+
export function buyerLabel(name, commercial) {
|
|
28
|
+
const n = (name ?? "").trim();
|
|
29
|
+
const c = (commercial ?? "").trim();
|
|
30
|
+
if (n && c && c !== n)
|
|
31
|
+
return `${n} (${c})`;
|
|
32
|
+
return n || c || "onbekend";
|
|
33
|
+
}
|
|
34
|
+
export function buildBlockMailLines(input) {
|
|
35
|
+
return [
|
|
36
|
+
`Order ${input.orderNumber} kan niet worden ingedeeld.`,
|
|
37
|
+
"",
|
|
38
|
+
`Klant: ${input.klant || "onbekend"}`,
|
|
39
|
+
`Afleverlocatie: ${input.afleverlocatie || "onbekend"}`,
|
|
40
|
+
`Leverdatum: ${input.leverdatum || "onbekend"}`,
|
|
41
|
+
`Reden: ${input.reden}`,
|
|
42
|
+
];
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-block-alerts.server.d.ts","sourceRoot":"","sources":["../../src/lib/engine-block-alerts.server.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAG3D,wBAAsB,qBAAqB,IAAI,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAiE7G"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Blokkade-alarm op basis van de Logistiek Engine (koppelprompt 22).
|
|
2
|
+
// - Mail alleen als logistics_order_definitively_blocked definitief = true meldt,
|
|
3
|
+
// met de reden van de Engine.
|
|
4
|
+
// - Open alarm sluit vanzelf zodra de Engine definitief = false en status "done" meldt.
|
|
5
|
+
// - Fail closed: lukt een vraag niet, dan geen mail en niets vrijgeven.
|
|
6
|
+
import { decideAlertAction, parseDefinitiveBlock } from "./engine-block-alerts";
|
|
7
|
+
export const ENGINE_BLOCK_REASON_KEY = "engine_definitief";
|
|
8
|
+
const MAX_CHECKS = 200;
|
|
9
|
+
export async function checkDefinitiveBlocks() {
|
|
10
|
+
const warnings = [];
|
|
11
|
+
let mailed = 0;
|
|
12
|
+
let closed = 0;
|
|
13
|
+
try {
|
|
14
|
+
const { supabaseAdmin } = await import("../integrations/supabase/client.server");
|
|
15
|
+
const sb = supabaseAdmin;
|
|
16
|
+
// Open alarmen (op order-id).
|
|
17
|
+
const { data: openRows, error: openErr } = await sb
|
|
18
|
+
.from("order_block_notifications")
|
|
19
|
+
.select("order_id");
|
|
20
|
+
if (openErr)
|
|
21
|
+
throw new Error(openErr.message);
|
|
22
|
+
const openIds = new Set((openRows ?? []).map((r) => String(r.order_id)));
|
|
23
|
+
// Open orders vanaf vandaag die de Engine niet als "Ingedeeld" meldt.
|
|
24
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
25
|
+
const { data: orders, error: oErr } = await sb
|
|
26
|
+
.from("orders")
|
|
27
|
+
.select("id")
|
|
28
|
+
.is("deleted_at", null)
|
|
29
|
+
.not("status", "in", "(cancelled,geannuleerd,shipped,verzonden,delivered,geleverd,invoiced,gefactureerd)")
|
|
30
|
+
.gte("delivery_date", today)
|
|
31
|
+
.limit(1000);
|
|
32
|
+
if (oErr)
|
|
33
|
+
throw new Error(oErr.message);
|
|
34
|
+
const candidateIds = (orders ?? []).map((o) => String(o.id));
|
|
35
|
+
const { loadPlanCoverage } = await import("./plan-coverage.server");
|
|
36
|
+
const coverage = candidateIds.length ? await loadPlanCoverage(sb, candidateIds, "list") : new Map();
|
|
37
|
+
const toCheck = new Set(openIds);
|
|
38
|
+
for (const id of candidateIds) {
|
|
39
|
+
const cov = coverage.get(id);
|
|
40
|
+
if (cov && cov.state !== "ingedeeld" && cov.state !== "geen_regels" && cov.state !== "onbekend") {
|
|
41
|
+
toCheck.add(id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const { notifyOrderBlocked, clearOrderBlockNotifications } = await import("./order-block-mail.server");
|
|
45
|
+
for (const orderId of Array.from(toCheck).slice(0, MAX_CHECKS)) {
|
|
46
|
+
const { data, error } = await sb.rpc("logistics_order_definitively_blocked", { p_order_id: orderId });
|
|
47
|
+
if (error) {
|
|
48
|
+
warnings.push(`Definitieve blokkade opvragen faalde voor ${orderId}: ${error.message}`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const info = parseDefinitiveBlock(data, orderId);
|
|
52
|
+
const action = decideAlertAction(info, openIds.has(orderId));
|
|
53
|
+
if (action === "mail" && info) {
|
|
54
|
+
const res = await notifyOrderBlocked({
|
|
55
|
+
orderIds: [orderId],
|
|
56
|
+
reasonKey: ENGINE_BLOCK_REASON_KEY,
|
|
57
|
+
reason: info.reden || "Reden niet opgegeven door de Logistiek Engine",
|
|
58
|
+
details: { redenCode: info.redenCode, pogingen: info.pogingen, status: info.status },
|
|
59
|
+
});
|
|
60
|
+
mailed += res.sent;
|
|
61
|
+
warnings.push(...res.warnings);
|
|
62
|
+
}
|
|
63
|
+
else if (action === "close") {
|
|
64
|
+
await clearOrderBlockNotifications([orderId]);
|
|
65
|
+
closed++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
warnings.push(`Blokkade-alarm controleren faalde: ${err.message}`);
|
|
71
|
+
}
|
|
72
|
+
for (const w of warnings)
|
|
73
|
+
console.warn("[engine-block-alerts]", w);
|
|
74
|
+
return { mailed, closed, warnings };
|
|
75
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floriday-mirror.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-mirror.functions.ts"],"names":[],"mappings":"AA8IA,UAAU,YAAY;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,OAAO,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACnD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"floriday-mirror.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-mirror.functions.ts"],"names":[],"mappings":"AA8IA,UAAU,YAAY;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,OAAO,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACnD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA41CD,wBAAsB,4BAA4B,CAAC,KAAK,SAAgB,yBAEvE;AAED,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;yBAG0C,CAAC"}
|
|
@@ -385,6 +385,7 @@ async function mirrorUnlocked(limit) {
|
|
|
385
385
|
let inserted = 0, updated = 0, skipped = 0, unchanged = 0, failed = 0;
|
|
386
386
|
const errors = [];
|
|
387
387
|
const affectedOrderIds = [];
|
|
388
|
+
const floridayCancelIds = [];
|
|
388
389
|
// Orders die in deze ronde echt zijn aangemaakt of gewijzigd: alleen die
|
|
389
390
|
// melden we expliciet aan bij de planwachtrij van de logistiek-engine.
|
|
390
391
|
const changedOrderIds = [];
|
|
@@ -992,7 +993,12 @@ async function mirrorUnlocked(limit) {
|
|
|
992
993
|
const prevFloridayStatus = prevCf.floriday_status ?? null;
|
|
993
994
|
const floridayStatusChanged = String(lvl.floridayStatusSummary ?? "") !== String(prevFloridayStatus ?? "");
|
|
994
995
|
const localStatus = String(target?.status ?? "");
|
|
995
|
-
|
|
996
|
+
// Annulering uit Floriday: niet zelf de status zetten, maar na de ronde
|
|
997
|
+
// via handleFloridayCancellation (pickstand bij de Engine controleren).
|
|
998
|
+
const isFloridayCancel = lvl.status === "geannuleerd" && localStatus.toLowerCase() !== "geannuleerd";
|
|
999
|
+
if (floridayStatusChanged && isFloridayCancel)
|
|
1000
|
+
floridayCancelIds.push(String(target.id));
|
|
1001
|
+
const statusPatch = floridayStatusChanged && lvl.status !== localStatus && !isFloridayCancel
|
|
996
1002
|
? { status: lvl.status, status_sync_token: globalThis.crypto.randomUUID() }
|
|
997
1003
|
: {};
|
|
998
1004
|
// Alleen regels die eerder bij déze bestelling hoorden mogen als
|
|
@@ -1265,41 +1271,8 @@ async function mirrorUnlocked(limit) {
|
|
|
1265
1271
|
foIds: memberIds,
|
|
1266
1272
|
});
|
|
1267
1273
|
}
|
|
1268
|
-
//
|
|
1269
|
-
//
|
|
1270
|
-
// mag ook via Floriday niet doorlopen: blokkeren met reden i.p.v. plannen.
|
|
1271
|
-
try {
|
|
1272
|
-
const { assertBeladingAllowed } = await import("./belading.server");
|
|
1273
|
-
await assertBeladingAllowed(supabaseAdmin, lineRows
|
|
1274
|
-
.filter((r) => r.product_id)
|
|
1275
|
-
.map((r) => ({
|
|
1276
|
-
product_id: r.product_id,
|
|
1277
|
-
plants_per_crate: r.plants_per_crate,
|
|
1278
|
-
crates_per_layer: r.crates_per_layer,
|
|
1279
|
-
layers_per_cart: r.layers_per_cart,
|
|
1280
|
-
})));
|
|
1281
|
-
}
|
|
1282
|
-
catch (belErr) {
|
|
1283
|
-
const reason = `Order ${orderId}: ${belErr.message}`;
|
|
1284
|
-
const { error: blockErr } = await supabaseAdmin.rpc("logistics_plan_block", {
|
|
1285
|
-
p_order_ids: [orderId],
|
|
1286
|
-
p_reason: reason,
|
|
1287
|
-
p_details: { source: "floriday-verkoop-module/floriday-mirror" },
|
|
1288
|
-
});
|
|
1289
|
-
if (blockErr)
|
|
1290
|
-
console.warn("[floriday-mirror] blokkade vastleggen faalde:", blockErr.message);
|
|
1291
|
-
// Eenmalige mailmelding naar het interne adres uit de e-mailmodule.
|
|
1292
|
-
const { notifyOrderBlocked } = await import("./order-block-mail.server");
|
|
1293
|
-
const mail = await notifyOrderBlocked({
|
|
1294
|
-
orderIds: [orderId],
|
|
1295
|
-
reasonKey: "belading_niet_toegestaan",
|
|
1296
|
-
reason: belErr.message,
|
|
1297
|
-
details: { source: "floriday-verkoop-module/floriday-mirror" },
|
|
1298
|
-
});
|
|
1299
|
-
for (const w of mail.warnings)
|
|
1300
|
-
console.warn("[floriday-mirror]", w);
|
|
1301
|
-
errors.push(`${primary.foId}: ${reason.slice(0, 200)}`);
|
|
1302
|
-
}
|
|
1274
|
+
// Geen eigen beladings-/ladingdragercontrole: alleen de Logistiek Engine
|
|
1275
|
+
// beslist of een belading kan (koppelprompt 22).
|
|
1303
1276
|
// Buffer resolven en in de replan-queue zetten. Alleen orders die buiten
|
|
1304
1277
|
// ons ERP om in Floriday zijn afgehandeld hoeven niet meer gepland te
|
|
1305
1278
|
// worden.
|
|
@@ -1351,6 +1324,18 @@ async function mirrorUnlocked(limit) {
|
|
|
1351
1324
|
}
|
|
1352
1325
|
// Batch enqueue voor karherplanning. processed_at resetten, anders blijft een
|
|
1353
1326
|
// eerder verwerkte order voor altijd overgeslagen door de cron.
|
|
1327
|
+
// Annuleringen uit Floriday afhandelen (koppelprompt 1.0.77).
|
|
1328
|
+
for (const cid of Array.from(new Set(floridayCancelIds))) {
|
|
1329
|
+
try {
|
|
1330
|
+
const { handleFloridayCancellation } = await import("./order-cancel.server");
|
|
1331
|
+
const res = await handleFloridayCancellation(cid);
|
|
1332
|
+
if (res !== "cancelled")
|
|
1333
|
+
errors.push(`${cid}: ${res}`);
|
|
1334
|
+
}
|
|
1335
|
+
catch (err) {
|
|
1336
|
+
errors.push(`${cid}: annulering uit Floriday faalde: ${err.message}`.slice(0, 200));
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1354
1339
|
if (affectedOrderIds.length > 0) {
|
|
1355
1340
|
const queueRows = affectedOrderIds.map((oid) => ({
|
|
1356
1341
|
order_id: oid,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { OrderStage } from "./order-status";
|
|
2
|
+
export type FloridayStage = "open" | "partially_fulfilled" | "fulfilled" | "cancelled" | "expired" | "unknown";
|
|
3
|
+
export interface FloridayStatusEntry {
|
|
4
|
+
salesOrderId: string;
|
|
5
|
+
found: boolean;
|
|
6
|
+
salesOrderStatus: string | null;
|
|
7
|
+
floridayStage: FloridayStage;
|
|
8
|
+
fulfillmentRequests: {
|
|
9
|
+
fulfillmentRequestId: string | null;
|
|
10
|
+
deliveryOrderId: string | null;
|
|
11
|
+
fulfillmentOrderIds: string[];
|
|
12
|
+
}[];
|
|
13
|
+
fulfillmentOrders: {
|
|
14
|
+
fulfillmentOrderId: string | null;
|
|
15
|
+
status: string | null;
|
|
16
|
+
}[];
|
|
17
|
+
salesChannel: string | null;
|
|
18
|
+
tradeInstrument: string | null;
|
|
19
|
+
incoterm: string | null;
|
|
20
|
+
customerOrderId: string | null;
|
|
21
|
+
salesChannelOrderId: string | null;
|
|
22
|
+
customerOrganizationId: string | null;
|
|
23
|
+
customerGln: string | null;
|
|
24
|
+
lastModifiedDateTime: string | null;
|
|
25
|
+
cachedAt: string | null;
|
|
26
|
+
}
|
|
27
|
+
/** Samenvatting op orderniveau (een order kan meerdere bestellingen hebben). */
|
|
28
|
+
export interface FloridayStatusSummary {
|
|
29
|
+
stage: FloridayStage | "onbekend";
|
|
30
|
+
/** Foutcode als het ophalen mislukte (bv. invalid_signature). */
|
|
31
|
+
error: string | null;
|
|
32
|
+
entries: FloridayStatusEntry[];
|
|
33
|
+
}
|
|
34
|
+
export declare function parseFloridayStatusEntry(raw: any): FloridayStatusEntry | null;
|
|
35
|
+
/** Eén stand voor een order met meerdere Floriday-bestellingen. */
|
|
36
|
+
export declare function combineStages(stages: FloridayStage[]): FloridayStage;
|
|
37
|
+
export declare function floridayStageLabel(stage: FloridayStatusSummary["stage"]): string;
|
|
38
|
+
/** Wijkt de Floriday-stand af van de ERP-stand? Alleen voor weergave. */
|
|
39
|
+
export declare function deviatesFromFloriday(stage: FloridayStatusSummary["stage"], erp: OrderStage | undefined): boolean;
|
|
40
|
+
//# sourceMappingURL=floriday-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"floriday-status.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-status.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,qBAAqB,GACrB,WAAW,GACX,WAAW,GACX,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,mBAAmB,EAAE;QAAE,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,mBAAmB,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAC9H,iBAAiB,EAAE;QAAE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IAClF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,aAAa,GAAG,UAAU,CAAC;IAClC,iEAAiE;IACjE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAChC;AAMD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,GAAG,mBAAmB,GAAG,IAAI,CA6B7E;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,aAAa,CAWpE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,MAAM,CAUhF;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAQhH"}
|