@flowselections/floriday-verkoop-module 1.0.77 → 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.
Files changed (68) hide show
  1. package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
  2. package/dist-lib/components/verkoop/CreateOrderPage.js +33 -8
  3. package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts.map +1 -1
  4. package/dist-lib/components/verkoop/EditLocalOrderDialog.js +1 -1
  5. package/dist-lib/components/verkoop/FloridayStageLine.d.ts +11 -0
  6. package/dist-lib/components/verkoop/FloridayStageLine.d.ts.map +1 -0
  7. package/dist-lib/components/verkoop/FloridayStageLine.js +17 -0
  8. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts +1 -1
  9. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts.map +1 -1
  10. package/dist-lib/components/verkoop/PlanCoverageBadge.js +5 -2
  11. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
  12. package/dist-lib/components/verkoop/SalesOrderDetailView.js +33 -5
  13. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
  14. package/dist-lib/components/verkoop/SalesOrdersTable.js +4 -8
  15. package/dist-lib/components/verkoop/VerkoopOrdersPage.js +1 -1
  16. package/dist-lib/integrations/supabase/types.d.ts +1158 -0
  17. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  18. package/dist-lib/lib/belading.server.d.ts +0 -11
  19. package/dist-lib/lib/belading.server.d.ts.map +1 -1
  20. package/dist-lib/lib/belading.server.js +4 -41
  21. package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
  22. package/dist-lib/lib/cart-replan.functions.js +3 -22
  23. package/dist-lib/lib/central-secrets.server.d.ts +5 -0
  24. package/dist-lib/lib/central-secrets.server.d.ts.map +1 -0
  25. package/dist-lib/lib/central-secrets.server.js +65 -0
  26. package/dist-lib/lib/create-order.functions.d.ts +15 -0
  27. package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
  28. package/dist-lib/lib/create-order.functions.js +28 -13
  29. package/dist-lib/lib/engine-block-alerts.d.ts +22 -0
  30. package/dist-lib/lib/engine-block-alerts.d.ts.map +1 -0
  31. package/dist-lib/lib/engine-block-alerts.js +43 -0
  32. package/dist-lib/lib/engine-block-alerts.server.d.ts +7 -0
  33. package/dist-lib/lib/engine-block-alerts.server.d.ts.map +1 -0
  34. package/dist-lib/lib/engine-block-alerts.server.js +75 -0
  35. package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
  36. package/dist-lib/lib/floriday-mirror.functions.js +21 -36
  37. package/dist-lib/lib/floriday-status.d.ts +40 -0
  38. package/dist-lib/lib/floriday-status.d.ts.map +1 -0
  39. package/dist-lib/lib/floriday-status.js +80 -0
  40. package/dist-lib/lib/floriday-status.server.d.ts +7 -0
  41. package/dist-lib/lib/floriday-status.server.d.ts.map +1 -0
  42. package/dist-lib/lib/floriday-status.server.js +74 -0
  43. package/dist-lib/lib/load-carriers.server.d.ts +1 -1
  44. package/dist-lib/lib/load-carriers.server.d.ts.map +1 -1
  45. package/dist-lib/lib/load-carriers.server.js +3 -6
  46. package/dist-lib/lib/logistics-engine.server.d.ts.map +1 -1
  47. package/dist-lib/lib/logistics-engine.server.js +2 -22
  48. package/dist-lib/lib/order-block-mail.server.d.ts.map +1 -1
  49. package/dist-lib/lib/order-block-mail.server.js +31 -15
  50. package/dist-lib/lib/order-cancel.server.d.ts +9 -0
  51. package/dist-lib/lib/order-cancel.server.d.ts.map +1 -1
  52. package/dist-lib/lib/order-cancel.server.js +90 -0
  53. package/dist-lib/lib/plan-coverage.check.d.ts +2 -0
  54. package/dist-lib/lib/plan-coverage.check.d.ts.map +1 -0
  55. package/dist-lib/lib/plan-coverage.check.js +17 -0
  56. package/dist-lib/lib/plan-coverage.d.ts +12 -0
  57. package/dist-lib/lib/plan-coverage.d.ts.map +1 -1
  58. package/dist-lib/lib/plan-coverage.js +27 -1
  59. package/dist-lib/lib/plan-coverage.server.d.ts.map +1 -1
  60. package/dist-lib/lib/plan-coverage.server.js +20 -13
  61. package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
  62. package/dist-lib/lib/salesorders-list.server.js +54 -0
  63. package/dist-lib/lib/salesorders-mapping.d.ts +11 -0
  64. package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
  65. package/dist-lib/lib/salesorders.functions.d.ts +1 -5
  66. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
  67. package/dist-lib/lib/salesorders.functions.js +26 -2
  68. 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":"AAQA,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,CAyO3C;AAED,eAAO,MAAM,yBAAyB,yFACkD,CAAC;AAEzF;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE,KAAK,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,CAAC,iBAqBH"}
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
- // De Logistics Engine bepaalt welke ladingdragers zijn ingeschakeld; een
3
- // belading met een uitgeschakelde ladingdrager wordt nergens getoond en mag
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, allowedCarriers] = await Promise.all([
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.filter((c) => carrierAllowed(c.cart_code));
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,CAoaD;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;;;QAvf3B,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAqfhB,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
- const { error: blockErr } = await supabaseAdmin.rpc("logistics_plan_block", {
267
- p_order_ids: blockedOrderIds,
268
- p_reason: reason,
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;;;;;;;;;;;;;;;;;;;;;;;aA+OY,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;;;aAgKG,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"}
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: alleen wat de Logistics Engine toestaat.
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,7 @@
1
+ export declare const ENGINE_BLOCK_REASON_KEY = "engine_definitief";
2
+ export declare function checkDefinitiveBlocks(): Promise<{
3
+ mailed: number;
4
+ closed: number;
5
+ warnings: string[];
6
+ }>;
7
+ //# sourceMappingURL=engine-block-alerts.server.d.ts.map
@@ -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;AA42CD,wBAAsB,4BAA4B,CAAC,KAAK,SAAgB,yBAEvE;AAED,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;yBAG0C,CAAC"}
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
- const statusPatch = floridayStatusChanged && lvl.status !== localStatus
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
- // Belading-veiligheidscontrole — dezelfde als bij handmatig aanmaken.
1269
- // Een belading met een in de Logistics Engine uitgezette ladingdrager
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"}