@flowselections/floriday-verkoop-module 1.0.77 → 1.0.82

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 (90) 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 +15 -0
  6. package/dist-lib/components/verkoop/FloridayStageLine.d.ts.map +1 -0
  7. package/dist-lib/components/verkoop/FloridayStageLine.js +25 -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/SalesOrderDetailPage.d.ts.map +1 -1
  12. package/dist-lib/components/verkoop/SalesOrderDetailPage.js +1 -1
  13. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
  14. package/dist-lib/components/verkoop/SalesOrderDetailView.js +38 -6
  15. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
  16. package/dist-lib/components/verkoop/SalesOrdersTable.js +4 -8
  17. package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
  18. package/dist-lib/components/verkoop/VerkoopOrdersPage.js +7 -1
  19. package/dist-lib/integrations/supabase/types.d.ts +1486 -2
  20. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  21. package/dist-lib/integrations/supabase/types.js +1 -0
  22. package/dist-lib/lib/belading.server.d.ts +0 -11
  23. package/dist-lib/lib/belading.server.d.ts.map +1 -1
  24. package/dist-lib/lib/belading.server.js +4 -41
  25. package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
  26. package/dist-lib/lib/cart-replan.functions.js +3 -22
  27. package/dist-lib/lib/central-secrets.server.d.ts +5 -0
  28. package/dist-lib/lib/central-secrets.server.d.ts.map +1 -0
  29. package/dist-lib/lib/central-secrets.server.js +65 -0
  30. package/dist-lib/lib/create-order.functions.d.ts +15 -0
  31. package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
  32. package/dist-lib/lib/create-order.functions.js +28 -13
  33. package/dist-lib/lib/customer-name.d.ts +8 -0
  34. package/dist-lib/lib/customer-name.d.ts.map +1 -0
  35. package/dist-lib/lib/customer-name.js +9 -0
  36. package/dist-lib/lib/engine-block-alerts.d.ts +22 -0
  37. package/dist-lib/lib/engine-block-alerts.d.ts.map +1 -0
  38. package/dist-lib/lib/engine-block-alerts.js +43 -0
  39. package/dist-lib/lib/engine-block-alerts.server.d.ts +7 -0
  40. package/dist-lib/lib/engine-block-alerts.server.d.ts.map +1 -0
  41. package/dist-lib/lib/engine-block-alerts.server.js +75 -0
  42. package/dist-lib/lib/floriday-change-diff.check.d.ts +2 -0
  43. package/dist-lib/lib/floriday-change-diff.check.d.ts.map +1 -0
  44. package/dist-lib/lib/floriday-change-diff.check.js +27 -0
  45. package/dist-lib/lib/floriday-change-diff.d.ts +7 -0
  46. package/dist-lib/lib/floriday-change-diff.d.ts.map +1 -0
  47. package/dist-lib/lib/floriday-change-diff.js +51 -0
  48. package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
  49. package/dist-lib/lib/floriday-mirror.functions.js +38 -39
  50. package/dist-lib/lib/floriday-status.d.ts +48 -0
  51. package/dist-lib/lib/floriday-status.d.ts.map +1 -0
  52. package/dist-lib/lib/floriday-status.js +99 -0
  53. package/dist-lib/lib/floriday-status.server.d.ts +7 -0
  54. package/dist-lib/lib/floriday-status.server.d.ts.map +1 -0
  55. package/dist-lib/lib/floriday-status.server.js +74 -0
  56. package/dist-lib/lib/load-carriers.server.d.ts +1 -1
  57. package/dist-lib/lib/load-carriers.server.d.ts.map +1 -1
  58. package/dist-lib/lib/load-carriers.server.js +3 -6
  59. package/dist-lib/lib/logistics-engine.server.d.ts.map +1 -1
  60. package/dist-lib/lib/logistics-engine.server.js +2 -22
  61. package/dist-lib/lib/order-block-mail.server.d.ts.map +1 -1
  62. package/dist-lib/lib/order-block-mail.server.js +31 -15
  63. package/dist-lib/lib/order-cancel.server.d.ts +9 -0
  64. package/dist-lib/lib/order-cancel.server.d.ts.map +1 -1
  65. package/dist-lib/lib/order-cancel.server.js +90 -0
  66. package/dist-lib/lib/plan-coverage.check.d.ts +2 -0
  67. package/dist-lib/lib/plan-coverage.check.d.ts.map +1 -0
  68. package/dist-lib/lib/plan-coverage.check.js +17 -0
  69. package/dist-lib/lib/plan-coverage.d.ts +12 -0
  70. package/dist-lib/lib/plan-coverage.d.ts.map +1 -1
  71. package/dist-lib/lib/plan-coverage.js +27 -1
  72. package/dist-lib/lib/plan-coverage.server.d.ts.map +1 -1
  73. package/dist-lib/lib/plan-coverage.server.js +20 -13
  74. package/dist-lib/lib/review-dismissals.server.d.ts +3 -0
  75. package/dist-lib/lib/review-dismissals.server.d.ts.map +1 -0
  76. package/dist-lib/lib/review-dismissals.server.js +26 -0
  77. package/dist-lib/lib/salesorders-list.functions.d.ts +1 -1
  78. package/dist-lib/lib/salesorders-list.functions.js +1 -1
  79. package/dist-lib/lib/salesorders-list.server.d.ts +1 -1
  80. package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
  81. package/dist-lib/lib/salesorders-list.server.js +104 -3
  82. package/dist-lib/lib/salesorders-mapping.d.ts +17 -0
  83. package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
  84. package/dist-lib/lib/salesorders-mapping.js +1 -0
  85. package/dist-lib/lib/salesorders.functions.d.ts +1 -5
  86. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
  87. package/dist-lib/lib/salesorders.functions.js +32 -2
  88. package/dist-lib/lib/useSalesOrdersQuery.d.ts +1 -1
  89. package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
  90. package/package.json +5 -5
@@ -1,3 +1,4 @@
1
+ import { diffBuyerChanges } from "./floriday-change-diff";
1
2
  // Spiegelt Floriday-verkooporders (FO's) uit `floriday_salesorders_cache`
2
3
  // naar de lokale `orders`-tabel, zodat ze via `resolveBufferForOrderInternal`
3
4
  // in dezelfde buffer terechtkomen als lokale orders en gedeelde karren
@@ -385,6 +386,7 @@ async function mirrorUnlocked(limit) {
385
386
  let inserted = 0, updated = 0, skipped = 0, unchanged = 0, failed = 0;
386
387
  const errors = [];
387
388
  const affectedOrderIds = [];
389
+ const floridayCancelIds = [];
388
390
  // Orders die in deze ronde echt zijn aangemaakt of gewijzigd: alleen die
389
391
  // melden we expliciet aan bij de planwachtrij van de logistiek-engine.
390
392
  const changedOrderIds = [];
@@ -829,12 +831,21 @@ async function mirrorUnlocked(limit) {
829
831
  frozenCandidates.set(String(c.id), c);
830
832
  }
831
833
  if (frozenCandidates.size > 0) {
834
+ // Alleen echte koperwijzigingen (artikel, aantal, leverdatum,
835
+ // bestelling erbij/weg). Status, belading en Floriday-echo niet.
832
836
  const signature = JSON.stringify({
833
- status: primary.d?.status ?? null,
834
- lines: floridayLines,
837
+ lines: floridayLines.map((l) => ({
838
+ id: l.sales_order_id,
839
+ t: l.trade_item_id,
840
+ p: l.pieces,
841
+ })),
842
+ d: groupLvl.deliveryDate ?? null,
835
843
  });
836
844
  for (const fo of frozenCandidates.values()) {
837
845
  const cf = (fo.custom_fields ?? {});
846
+ const changes = diffBuyerChanges(cf.floriday_lines, floridayLines, fo.delivery_date, groupLvl.deliveryDate);
847
+ if (changes.length === 0)
848
+ continue; // niets door de koper gewijzigd
838
849
  if (cf.floriday_change_signature === signature)
839
850
  continue; // al gemeld
840
851
  const { error: revErr } = await supabaseAdmin.from("orders")
@@ -845,7 +856,8 @@ async function mirrorUnlocked(limit) {
845
856
  floriday_change_detected_at: new Date().toISOString(),
846
857
  floriday_change_signature: signature,
847
858
  needs_manual_review: true,
848
- manual_review_reason: "Wijziging binnengekomen na afronding — handmatige beoordeling nodig",
859
+ floriday_change_summary: changes,
860
+ manual_review_reason: `Wijziging door de koper na afronding: ${changes.join("; ")} — handmatige beoordeling nodig`,
849
861
  },
850
862
  updated_at: new Date().toISOString(),
851
863
  })
@@ -855,6 +867,9 @@ async function mirrorUnlocked(limit) {
855
867
  }
856
868
  }
857
869
  skipped += group.length;
870
+ // Afgeronde order: deze ronde overslaan; alleen melden bij echte wijziging.
871
+ if (![...frozenCandidates.values()].some((fo) => diffBuyerChanges((fo.custom_fields ?? {}).floriday_lines, floridayLines, fo.delivery_date, groupLvl.deliveryDate).length > 0))
872
+ continue;
858
873
  errors.push(`${primary.foId}: wijziging na afronding — order gemarkeerd voor handmatige beoordeling`);
859
874
  continue;
860
875
  }
@@ -992,7 +1007,12 @@ async function mirrorUnlocked(limit) {
992
1007
  const prevFloridayStatus = prevCf.floriday_status ?? null;
993
1008
  const floridayStatusChanged = String(lvl.floridayStatusSummary ?? "") !== String(prevFloridayStatus ?? "");
994
1009
  const localStatus = String(target?.status ?? "");
995
- const statusPatch = floridayStatusChanged && lvl.status !== localStatus
1010
+ // Annulering uit Floriday: niet zelf de status zetten, maar na de ronde
1011
+ // via handleFloridayCancellation (pickstand bij de Engine controleren).
1012
+ const isFloridayCancel = lvl.status === "geannuleerd" && localStatus.toLowerCase() !== "geannuleerd";
1013
+ if (floridayStatusChanged && isFloridayCancel)
1014
+ floridayCancelIds.push(String(target.id));
1015
+ const statusPatch = floridayStatusChanged && lvl.status !== localStatus && !isFloridayCancel
996
1016
  ? { status: lvl.status, status_sync_token: globalThis.crypto.randomUUID() }
997
1017
  : {};
998
1018
  // Alleen regels die eerder bij déze bestelling hoorden mogen als
@@ -1265,41 +1285,8 @@ async function mirrorUnlocked(limit) {
1265
1285
  foIds: memberIds,
1266
1286
  });
1267
1287
  }
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
- }
1288
+ // Geen eigen beladings-/ladingdragercontrole: alleen de Logistiek Engine
1289
+ // beslist of een belading kan (koppelprompt 22).
1303
1290
  // Buffer resolven en in de replan-queue zetten. Alleen orders die buiten
1304
1291
  // ons ERP om in Floriday zijn afgehandeld hoeven niet meer gepland te
1305
1292
  // worden.
@@ -1351,6 +1338,18 @@ async function mirrorUnlocked(limit) {
1351
1338
  }
1352
1339
  // Batch enqueue voor karherplanning. processed_at resetten, anders blijft een
1353
1340
  // eerder verwerkte order voor altijd overgeslagen door de cron.
1341
+ // Annuleringen uit Floriday afhandelen (koppelprompt 1.0.77).
1342
+ for (const cid of Array.from(new Set(floridayCancelIds))) {
1343
+ try {
1344
+ const { handleFloridayCancellation } = await import("./order-cancel.server");
1345
+ const res = await handleFloridayCancellation(cid);
1346
+ if (res !== "cancelled")
1347
+ errors.push(`${cid}: ${res}`);
1348
+ }
1349
+ catch (err) {
1350
+ errors.push(`${cid}: annulering uit Floriday faalde: ${err.message}`.slice(0, 200));
1351
+ }
1352
+ }
1354
1353
  if (affectedOrderIds.length > 0) {
1355
1354
  const queueRows = affectedOrderIds.map((oid) => ({
1356
1355
  order_id: oid,
@@ -0,0 +1,48 @@
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
+ /** Eigen kenmerk: verzonden in het ERP en nog niet afgemeld bij Floriday. */
41
+ export declare function isNotReportedLocally(erp: OrderStage | undefined, floridayFulfilled: boolean): boolean;
42
+ export type NotReportedState = "waarschuwing" | "waarschuwing_onbekend" | "al_afgehandeld" | null;
43
+ /**
44
+ * Welke melding hoort bij een verzonden order? Floriday-stand gaat voor;
45
+ * bij onbekende stand valt het terug op ons eigen kenmerk. Alleen weergave.
46
+ */
47
+ export declare function notReportedState(erp: OrderStage | undefined, floriday: FloridayStatusSummary["stage"] | null | undefined, floridayFulfilled: boolean): NotReportedState;
48
+ //# 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;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,EAAE,iBAAiB,EAAE,OAAO,GAAG,OAAO,CAErG;AAED,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,uBAAuB,GAAG,gBAAgB,GAAG,IAAI,CAAC;AAElG;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,UAAU,GAAG,SAAS,EAC3B,QAAQ,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3D,iBAAiB,EAAE,OAAO,GACzB,gBAAgB,CAMlB"}
@@ -0,0 +1,99 @@
1
+ const STAGES = ["open", "partially_fulfilled", "fulfilled", "cancelled", "expired", "unknown"];
2
+ const str = (v) => (typeof v === "string" && v.trim() ? v : null);
3
+ const arr = (v) => (Array.isArray(v) ? v : []);
4
+ export function parseFloridayStatusEntry(raw) {
5
+ if (!raw || typeof raw !== "object")
6
+ return null;
7
+ const id = str(raw.salesOrderId);
8
+ if (!id)
9
+ return null;
10
+ const stage = STAGES.includes(raw.floridayStage) ? raw.floridayStage : "unknown";
11
+ return {
12
+ salesOrderId: id,
13
+ found: raw.found === true,
14
+ salesOrderStatus: str(raw.salesOrderStatus),
15
+ floridayStage: stage,
16
+ fulfillmentRequests: arr(raw.fulfillmentRequests).map((r) => ({
17
+ fulfillmentRequestId: str(r?.fulfillmentRequestId),
18
+ deliveryOrderId: str(r?.deliveryOrderId),
19
+ fulfillmentOrderIds: arr(r?.fulfillmentOrderIds).map(String),
20
+ })),
21
+ fulfillmentOrders: arr(raw.fulfillmentOrders).map((f) => ({
22
+ fulfillmentOrderId: str(f?.fulfillmentOrderId),
23
+ status: str(f?.status),
24
+ })),
25
+ salesChannel: str(raw.salesChannel),
26
+ tradeInstrument: str(raw.tradeInstrument),
27
+ incoterm: str(raw.incoterm),
28
+ customerOrderId: str(raw.customerOrderId),
29
+ salesChannelOrderId: str(raw.salesChannelOrderId),
30
+ customerOrganizationId: str(raw.customerOrganizationId),
31
+ customerGln: str(raw.customerGln),
32
+ lastModifiedDateTime: str(raw.lastModifiedDateTime),
33
+ cachedAt: str(raw.cachedAt),
34
+ };
35
+ }
36
+ /** Eén stand voor een order met meerdere Floriday-bestellingen. */
37
+ export function combineStages(stages) {
38
+ if (stages.length === 0)
39
+ return "unknown";
40
+ const all = (s) => stages.every((x) => x === s);
41
+ if (all("cancelled"))
42
+ return "cancelled";
43
+ if (all("expired"))
44
+ return "expired";
45
+ if (stages.every((x) => x === "cancelled" || x === "expired"))
46
+ return "cancelled";
47
+ const active = stages.filter((x) => x !== "cancelled" && x !== "expired");
48
+ if (active.includes("unknown"))
49
+ return "unknown";
50
+ if (active.every((x) => x === "fulfilled"))
51
+ return "fulfilled";
52
+ if (active.some((x) => x === "fulfilled" || x === "partially_fulfilled"))
53
+ return "partially_fulfilled";
54
+ return "open";
55
+ }
56
+ export function floridayStageLabel(stage) {
57
+ switch (stage) {
58
+ case "open": return "open";
59
+ case "partially_fulfilled": return "deels geleverd";
60
+ case "fulfilled": return "geleverd";
61
+ case "cancelled": return "geannuleerd";
62
+ case "expired": return "vervallen";
63
+ case "unknown": return "onbekend";
64
+ default: return "stand onbekend";
65
+ }
66
+ }
67
+ /** Wijkt de Floriday-stand af van de ERP-stand? Alleen voor weergave. */
68
+ export function deviatesFromFloriday(stage, erp) {
69
+ if (!erp || stage === "onbekend" || stage === "unknown")
70
+ return false;
71
+ const erpCancelled = erp === "cancelled";
72
+ const erpShipped = erp === "shipped";
73
+ if (stage === "cancelled" || stage === "expired")
74
+ return !erpCancelled;
75
+ if (stage === "fulfilled")
76
+ return !erpShipped && !erpCancelled;
77
+ if (stage === "open")
78
+ return erpCancelled; // verzonden+open: aparte melding
79
+ return false;
80
+ }
81
+ /** Eigen kenmerk: verzonden in het ERP en nog niet afgemeld bij Floriday. */
82
+ export function isNotReportedLocally(erp, floridayFulfilled) {
83
+ return erp === "shipped" && !floridayFulfilled;
84
+ }
85
+ /**
86
+ * Welke melding hoort bij een verzonden order? Floriday-stand gaat voor;
87
+ * bij onbekende stand valt het terug op ons eigen kenmerk. Alleen weergave.
88
+ */
89
+ export function notReportedState(erp, floriday, floridayFulfilled) {
90
+ if (erp !== "shipped")
91
+ return null;
92
+ if (floriday === "open" || floriday === "partially_fulfilled")
93
+ return "waarschuwing";
94
+ if (floriday === "fulfilled")
95
+ return floridayFulfilled ? null : "al_afgehandeld";
96
+ if (floriday === "cancelled" || floriday === "expired")
97
+ return null;
98
+ return floridayFulfilled ? null : "waarschuwing_onbekend";
99
+ }
@@ -0,0 +1,7 @@
1
+ import { type FloridayStatusEntry } from "./floriday-status";
2
+ export interface FloridayStatusResult {
3
+ entries: Map<string, FloridayStatusEntry>;
4
+ error: string | null;
5
+ }
6
+ export declare function loadFloridayStatuses(salesOrderIds: string[]): Promise<FloridayStatusResult>;
7
+ //# sourceMappingURL=floriday-status.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-status.server.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-status.server.ts"],"names":[],"mappings":"AAOA,OAAO,EAA4B,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAoBvF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAsB,oBAAoB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAmDjG"}
@@ -0,0 +1,74 @@
1
+ // Server-only: Floriday-stand per verkooporder ophalen bij de gateway van de
2
+ // Authenticatie-module (POST /api/public/gateway/fulfillment-order/status).
3
+ // - Alleen lezen; schrijft nooit iets.
4
+ // - Ondertekend volgens het gatewaycontract: tijd in epoch-ms, HMAC-SHA256 over
5
+ // precies `${timestamp}.${body}`, header `x-floriday-signature: sha256=<hex>`.
6
+ // - Max 100 id's per verzoek, kort geheugen (30 s) per id.
7
+ // - Fail closed: bij een fout geen stand, wel de foutcode (bv. invalid_signature).
8
+ import { parseFloridayStatusEntry } from "./floriday-status";
9
+ const TTL_MS = 30000;
10
+ const MAX_IDS = 100;
11
+ const cache = new Map();
12
+ async function hmacHex(secret, payload) {
13
+ const key = await globalThis.crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
14
+ const sig = await globalThis.crypto.subtle.sign("HMAC", key, new TextEncoder().encode(payload));
15
+ return Array.from(new Uint8Array(sig))
16
+ .map((b) => b.toString(16).padStart(2, "0"))
17
+ .join("");
18
+ }
19
+ export async function loadFloridayStatuses(salesOrderIds) {
20
+ const entries = new Map();
21
+ const now = Date.now();
22
+ const wanted = [];
23
+ for (const id of Array.from(new Set(salesOrderIds.filter(Boolean)))) {
24
+ const hit = cache.get(id);
25
+ if (hit && now - hit.at < TTL_MS)
26
+ entries.set(id, hit.value);
27
+ else
28
+ wanted.push(id);
29
+ }
30
+ if (wanted.length === 0)
31
+ return { entries, error: null };
32
+ let error = null;
33
+ try {
34
+ const { getFloridayGatewaySecret, getGatewayBaseUrl } = await import("./central-secrets.server");
35
+ const secret = await getFloridayGatewaySecret();
36
+ const base = await getGatewayBaseUrl();
37
+ for (let i = 0; i < wanted.length; i += MAX_IDS) {
38
+ const chunk = wanted.slice(i, i + MAX_IDS);
39
+ const body = JSON.stringify({ salesOrderIds: chunk });
40
+ const timestamp = String(Date.now());
41
+ const signature = await hmacHex(secret, `${timestamp}.${body}`);
42
+ const res = await fetch(`${base}/api/public/gateway/fulfillment-order/status`, {
43
+ method: "POST",
44
+ headers: {
45
+ "Content-Type": "application/json",
46
+ "x-floriday-timestamp": timestamp,
47
+ "x-floriday-signature": `sha256=${signature}`,
48
+ "x-floriday-caller": "verkoop",
49
+ },
50
+ body,
51
+ });
52
+ const json = await res.json().catch(() => null);
53
+ if (!res.ok || json?.ok === false) {
54
+ const code = json?.code ?? json?.error ?? `HTTP ${res.status}`;
55
+ error = String(code);
56
+ console.warn("[floriday-status] gateway weigerde:", error, json?.error ?? "");
57
+ break;
58
+ }
59
+ const rows = Array.isArray(json?.orders) ? json.orders : [];
60
+ for (const r of rows) {
61
+ const e = parseFloridayStatusEntry(r);
62
+ if (!e)
63
+ continue;
64
+ entries.set(e.salesOrderId, e);
65
+ cache.set(e.salesOrderId, { at: Date.now(), value: e });
66
+ }
67
+ }
68
+ }
69
+ catch (err) {
70
+ error = err.message;
71
+ console.warn("[floriday-status] ophalen faalde:", error);
72
+ }
73
+ return { entries, error };
74
+ }
@@ -1,7 +1,7 @@
1
1
  export declare function fetchAllowedLoadCarriers(supabase: any, strategyId?: string | null): Promise<import("./load-carriers").AllowedLoadCarriers>;
2
2
  /**
3
3
  * Valideert de gekozen ladingdrager. Zonder keuze wordt de default van de
4
- * Engine teruggegeven. Gooit bij een uitgeschakelde drager.
4
+ * Engine teruggegeven. Geen eigen controle: alleen de Engine beslist.
5
5
  */
6
6
  export declare function resolveLoadCarrierType(supabase: any, value: string | null | undefined, strategyId?: string | null): Promise<string | null>;
7
7
  //# sourceMappingURL=load-carriers.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load-carriers.server.d.ts","sourceRoot":"","sources":["../../src/lib/load-carriers.server.ts"],"names":[],"mappings":"AAQA,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,GAAG,EACb,UAAU,GAAE,MAAM,GAAG,IAAW,0DAOjC;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,UAAU,GAAE,MAAM,GAAG,IAAW,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMxB"}
1
+ {"version":3,"file":"load-carriers.server.d.ts","sourceRoot":"","sources":["../../src/lib/load-carriers.server.ts"],"names":[],"mappings":"AAMA,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,GAAG,EACb,UAAU,GAAE,MAAM,GAAG,IAAW,0DAOjC;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,UAAU,GAAE,MAAM,GAAG,IAAW,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKxB"}
@@ -1,6 +1,5 @@
1
- // Server-side bewaking: een order mag nooit worden opgeslagen met een
2
- // ladingdrager die de Engine heeft uitgeschakeld.
3
- import { DISABLED_LOAD_CARRIER_MESSAGE, normalizeAllowedLoadCarriers, normalizeLoadCarrierCode, } from "./load-carriers";
1
+ // Leest de ladingdragerlijst van de Engine. Geen eigen blokkade (koppelprompt 22).
2
+ import { normalizeAllowedLoadCarriers, normalizeLoadCarrierCode, } from "./load-carriers";
4
3
  export async function fetchAllowedLoadCarriers(supabase, strategyId = null) {
5
4
  const { data, error } = await supabase.rpc("logistics_allowed_load_carriers", {
6
5
  p_strategy_id: strategyId,
@@ -11,14 +10,12 @@ export async function fetchAllowedLoadCarriers(supabase, strategyId = null) {
11
10
  }
12
11
  /**
13
12
  * Valideert de gekozen ladingdrager. Zonder keuze wordt de default van de
14
- * Engine teruggegeven. Gooit bij een uitgeschakelde drager.
13
+ * Engine teruggegeven. Geen eigen controle: alleen de Engine beslist.
15
14
  */
16
15
  export async function resolveLoadCarrierType(supabase, value, strategyId = null) {
17
16
  const allowed = await fetchAllowedLoadCarriers(supabase, strategyId);
18
17
  if (value == null || String(value).trim() === "")
19
18
  return allowed.default;
20
19
  const code = normalizeLoadCarrierCode(value) ?? String(value).trim();
21
- if (!allowed.allowed.includes(code))
22
- throw new Error(DISABLED_LOAD_CARRIER_MESSAGE);
23
20
  return code;
24
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"logistics-engine.server.d.ts","sourceRoot":"","sources":["../../src/lib/logistics-engine.server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,MAAM,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,OAAO,GACP,aAAa,GACb,MAAM,GACN,SAAS,GACT,WAAW,GACX,QAAQ,CAAC;AAEb,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1D;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAyEpC;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,gBAAgB,GAAG,eAAe,GAAG,eAAe,GAAG,MAAM,CAAC;IACzE,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnE;AAED,iEAAiE;AACjE,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,gBAAgB,GAAG,eAAe,GACvC,OAAO,CAAC,IAAI,CAAC,CAWf"}
1
+ {"version":3,"file":"logistics-engine.server.d.ts","sourceRoot":"","sources":["../../src/lib/logistics-engine.server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,MAAM,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,OAAO,GACP,aAAa,GACb,MAAM,GACN,SAAS,GACT,WAAW,GACX,QAAQ,CAAC;AAEb,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1D;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAuDpC;AAED,mEAAmE;AACnE,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,gBAAgB,GAAG,eAAe,GAAG,eAAe,GAAG,MAAM,CAAC;IACzE,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnE;AAED,iEAAiE;AACjE,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,gBAAgB,GAAG,eAAe,GACvC,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -41,28 +41,8 @@ export async function buildEngineOrderPayload(orderId) {
41
41
  const reason = rawCarrier == null || String(rawCarrier).trim() === ""
42
42
  ? `Order ${orderRef}: geen ladingdrager bekend — niet ingedeeld, er wordt geen type geraden.`
43
43
  : `Order ${orderRef}: onbekende ladingdrager "${String(rawCarrier)}" — niet ingedeeld, er wordt geen type geraden.`;
44
- const { error: blockErr } = await supabaseAdmin.rpc("logistics_plan_block", {
45
- p_order_ids: [o.id],
46
- p_reason: reason,
47
- p_details: {
48
- source: "floriday-verkoop-module/logistics-engine",
49
- load_carrier_type: rawCarrier ?? null,
50
- },
51
- });
52
- if (blockErr)
53
- console.warn("[logistics-engine] blokkade vastleggen faalde:", blockErr.message, reason);
54
- else
55
- console.warn("[logistics-engine]", reason);
56
- // Eenmalige mailmelding naar het interne adres uit de e-mailmodule.
57
- const { notifyOrderBlocked } = await import("./order-block-mail.server");
58
- const mail = await notifyOrderBlocked({
59
- orderIds: [String(o.id)],
60
- reasonKey: "ladingdrager_onbekend",
61
- reason,
62
- details: { load_carrier_type: rawCarrier ?? null },
63
- });
64
- for (const w of mail.warnings)
65
- console.warn("[logistics-engine]", w);
44
+ // Geen eigen blokkade of mail meer (koppelprompt 22): de Engine beslist.
45
+ console.warn("[logistics-engine]", reason);
66
46
  return null;
67
47
  }
68
48
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"order-block-mail.server.d.ts","sourceRoot":"","sources":["../../src/lib/order-block-mail.server.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AASD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAwGhC;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CASpF"}
1
+ {"version":3,"file":"order-block-mail.server.d.ts","sourceRoot":"","sources":["../../src/lib/order-block-mail.server.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AASD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAwHhC;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CASpF"}
@@ -6,6 +6,7 @@
6
6
  //
7
7
  // De mail wordt in public.email_auth_outbox gezet; de e-mailmodule verstuurt
8
8
  // hem in haar eigen verwerkingsronde.
9
+ import { buildBlockMailLines, buyerLabel } from "./engine-block-alerts";
9
10
  const EMAIL_PURPOSE = "internal";
10
11
  function escapeHtml(value) {
11
12
  return value
@@ -52,34 +53,49 @@ export async function notifyOrderBlocked(input) {
52
53
  warnings.push('Geen actieve e-mailverbinding met doel "intern" — melding van geblokkeerde order(s) niet verstuurd.');
53
54
  return { sent: 0, warnings };
54
55
  }
55
- // 3) Ordergegevens voor een leesbare mail.
56
+ // 3) Ordergegevens voor een leesbare mail. Klant = koper via klant-id;
57
+ // afleverlocatie op een eigen regel (op id, nooit op naam).
56
58
  const { data: orderRows } = await supabaseAdmin
57
59
  .from("orders")
58
- .select("id, order_number, delivery_date, customer_id")
60
+ .select("id, order_number, delivery_date, customer_id, custom_fields")
59
61
  .in("id", claimed);
60
- const customerIds = Array.from(new Set((orderRows ?? []).map((o) => o.customer_id).filter(Boolean)));
62
+ const rowsArr = (orderRows ?? []);
63
+ const customerIds = Array.from(new Set(rowsArr.map((o) => o.customer_id).filter(Boolean)));
61
64
  const customerNames = new Map();
62
65
  if (customerIds.length > 0) {
63
66
  const { data: custRows } = await supabaseAdmin
64
67
  .from("customers")
65
- .select("id, company_name")
68
+ .select("id, company_name, commercial_name")
66
69
  .in("id", customerIds);
67
70
  for (const c of (custRows ?? [])) {
68
- customerNames.set(String(c.id), String(c.company_name ?? ""));
71
+ customerNames.set(String(c.id), buyerLabel(c.company_name, c.commercial_name));
72
+ }
73
+ }
74
+ const locIds = Array.from(new Set(rowsArr.map((o) => o.custom_fields?.delivery_location_id).filter(Boolean).map(String)));
75
+ const locNames = new Map();
76
+ if (locIds.length > 0) {
77
+ const { data: locRows } = await supabaseAdmin
78
+ .from("customer_delivery_locations")
79
+ .select("id, name, gln")
80
+ .in("id", locIds);
81
+ for (const l of (locRows ?? [])) {
82
+ locNames.set(String(l.id), String(l.name ?? l.gln ?? ""));
69
83
  }
70
84
  }
71
85
  let sent = 0;
72
- for (const o of (orderRows ?? [])) {
86
+ for (const o of rowsArr) {
73
87
  const nummer = o.order_number ? String(o.order_number) : String(o.id).slice(0, 8);
74
- const klant = o.customer_id ? (customerNames.get(String(o.customer_id)) ?? "") : "";
75
- const datum = o.delivery_date ? String(o.delivery_date) : "onbekend";
76
- const regels = [
77
- `Order ${nummer} kan niet worden ingedeeld.`,
78
- "",
79
- `Klant: ${klant || "onbekend"}`,
80
- `Leverdatum: ${datum}`,
81
- `Reden: ${input.reason}`,
82
- ];
88
+ const cf = (o.custom_fields ?? {});
89
+ const locId = cf.delivery_location_id ? String(cf.delivery_location_id) : null;
90
+ const afleverlocatie = (locId && locNames.get(locId)) ||
91
+ (cf.delivery_location_gln ? `GLN ${String(cf.delivery_location_gln)}` : null);
92
+ const regels = buildBlockMailLines({
93
+ orderNumber: nummer,
94
+ klant: o.customer_id ? (customerNames.get(String(o.customer_id)) ?? "") : "",
95
+ afleverlocatie,
96
+ leverdatum: o.delivery_date ? String(o.delivery_date) : null,
97
+ reden: input.reason,
98
+ });
83
99
  const text = regels.join("\n");
84
100
  const html = `<p>${regels.map((r) => escapeHtml(r)).join("<br/>")}</p>`;
85
101
  const { error: outErr } = await supabaseAdmin.from("email_auth_outbox").insert({
@@ -21,4 +21,13 @@ export declare function cancelLocalOrderInternal(input: {
21
21
  alreadyCancelled: boolean;
22
22
  reversedKeys: number;
23
23
  }>;
24
+ export declare const FLORIDAY_CANCEL_REASON = "Koper heeft geannuleerd in Floriday";
25
+ export declare const FLORIDAY_CANCEL_PICKED_MESSAGE = "Koper heeft geannuleerd in Floriday, order is al gepickt";
26
+ /**
27
+ * Annulering uit Floriday (op order-id). Nog niet gepickt/gescand → order
28
+ * annuleren (voorraad terug, uit herplanning en buffer, Engine melden).
29
+ * Al gepickt/gescand, of pickstand onbekend → niet annuleren, wel een duidelijke
30
+ * melding voor handmatige beoordeling. Schrijft nooit order_carts (Engine).
31
+ */
32
+ export declare function handleFloridayCancellation(orderId: string): Promise<"cancelled" | "already_picked" | "pick_unknown" | "already_cancelled">;
24
33
  //# sourceMappingURL=order-cancel.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"order-cancel.server.d.ts","sourceRoot":"","sources":["../../src/lib/order-cancel.server.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5E,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC,CAsE5D;AAED,oFAAoF;AACpF,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAqDzE"}
1
+ {"version":3,"file":"order-cancel.server.d.ts","sourceRoot":"","sources":["../../src/lib/order-cancel.server.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5E,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC,CAsE5D;AAED,oFAAoF;AACpF,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAqDzE;AAED,eAAO,MAAM,sBAAsB,wCAAwC,CAAC;AAC5E,eAAO,MAAM,8BAA8B,6DACiB,CAAC;AAE7D;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,GAAG,gBAAgB,GAAG,cAAc,GAAG,mBAAmB,CAAC,CA+EhF"}