@flowselections/floriday-verkoop-module 1.0.94 → 1.0.98

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 (174) hide show
  1. package/dist-lib/components/verkoop/AnalyticsCards.d.ts +1 -1
  2. package/dist-lib/components/verkoop/AnalyticsCards.d.ts.map +1 -1
  3. package/dist-lib/components/verkoop/CartAssignmentWizard.d.ts +1 -1
  4. package/dist-lib/components/verkoop/CartAssignmentWizard.d.ts.map +1 -1
  5. package/dist-lib/components/verkoop/CartLayersDialog.d.ts +1 -1
  6. package/dist-lib/components/verkoop/CartLayersDialog.d.ts.map +1 -1
  7. package/dist-lib/components/verkoop/CreateOrderPage.d.ts +1 -1
  8. package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
  9. package/dist-lib/components/verkoop/CreateOrderPage.js +82 -43
  10. package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts +1 -1
  11. package/dist-lib/components/verkoop/DiagnoseConnectionDialog.d.ts.map +1 -1
  12. package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts +1 -1
  13. package/dist-lib/components/verkoop/EditLocalOrderDialog.d.ts.map +1 -1
  14. package/dist-lib/components/verkoop/EngineBufferCard.d.ts +1 -1
  15. package/dist-lib/components/verkoop/EngineBufferCard.d.ts.map +1 -1
  16. package/dist-lib/components/verkoop/FloridayStageLine.d.ts +2 -2
  17. package/dist-lib/components/verkoop/FloridayStageLine.d.ts.map +1 -1
  18. package/dist-lib/components/verkoop/InvoiceTimingSettings.d.ts +1 -1
  19. package/dist-lib/components/verkoop/InvoiceTimingSettings.d.ts.map +1 -1
  20. package/dist-lib/components/verkoop/OrderAfleverbrievenCard.d.ts +1 -1
  21. package/dist-lib/components/verkoop/OrderAfleverbrievenCard.d.ts.map +1 -1
  22. package/dist-lib/components/verkoop/OrderCarrierPicker.d.ts +1 -1
  23. package/dist-lib/components/verkoop/OrderCarrierPicker.d.ts.map +1 -1
  24. package/dist-lib/components/verkoop/OrderControlStatusCard.d.ts +1 -1
  25. package/dist-lib/components/verkoop/OrderControlStatusCard.d.ts.map +1 -1
  26. package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts +1 -1
  27. package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts.map +1 -1
  28. package/dist-lib/components/verkoop/OrderKarindelingCard.js +1 -1
  29. package/dist-lib/components/verkoop/OrderLinePackingCard.d.ts +1 -1
  30. package/dist-lib/components/verkoop/OrderLinePackingCard.d.ts.map +1 -1
  31. package/dist-lib/components/verkoop/OrderPickupMomentPicker.d.ts +1 -1
  32. package/dist-lib/components/verkoop/OrderPickupMomentPicker.d.ts.map +1 -1
  33. package/dist-lib/components/verkoop/OrderPickupMomentPicker.js +2 -1
  34. package/dist-lib/components/verkoop/OrderShipmentsCard.d.ts +1 -1
  35. package/dist-lib/components/verkoop/OrderShipmentsCard.d.ts.map +1 -1
  36. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts +1 -1
  37. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts.map +1 -1
  38. package/dist-lib/components/verkoop/PlanCoverageBadge.js +7 -5
  39. package/dist-lib/components/verkoop/ProductDimensionsSettings.d.ts +1 -1
  40. package/dist-lib/components/verkoop/ProductDimensionsSettings.d.ts.map +1 -1
  41. package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts +1 -1
  42. package/dist-lib/components/verkoop/SalesOrderDetailPage.d.ts.map +1 -1
  43. package/dist-lib/components/verkoop/SalesOrderDetailPage.js +6 -6
  44. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts +1 -1
  45. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
  46. package/dist-lib/components/verkoop/SalesOrderDetailView.js +2 -1
  47. package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts +1 -1
  48. package/dist-lib/components/verkoop/SalesOrdersFilterPanel.d.ts.map +1 -1
  49. package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts +1 -1
  50. package/dist-lib/components/verkoop/SalesOrdersFilters.d.ts.map +1 -1
  51. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts +2 -1
  52. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
  53. package/dist-lib/components/verkoop/SearchableSelect.d.ts +1 -1
  54. package/dist-lib/components/verkoop/SearchableSelect.d.ts.map +1 -1
  55. package/dist-lib/components/verkoop/StockConsumptionAlertsBanner.d.ts +1 -1
  56. package/dist-lib/components/verkoop/StockConsumptionAlertsBanner.d.ts.map +1 -1
  57. package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts +1 -1
  58. package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
  59. package/dist-lib/components/verkoop/WeekCalendar.d.ts +1 -1
  60. package/dist-lib/components/verkoop/WeekCalendar.d.ts.map +1 -1
  61. package/dist-lib/integrations/supabase/client.js +1 -1
  62. package/dist-lib/integrations/supabase/client.server.js +1 -1
  63. package/dist-lib/integrations/supabase/types.d.ts +253 -0
  64. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  65. package/dist-lib/lib/carrier-availability.d.ts +0 -28
  66. package/dist-lib/lib/carrier-availability.d.ts.map +1 -1
  67. package/dist-lib/lib/carrier-availability.js +3 -141
  68. package/dist-lib/lib/cart-replan.functions.d.ts +5 -0
  69. package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
  70. package/dist-lib/lib/cart-replan.functions.js +25 -1
  71. package/dist-lib/lib/create-order.functions.d.ts +5 -0
  72. package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
  73. package/dist-lib/lib/create-order.functions.js +81 -54
  74. package/dist-lib/lib/departure-preview.check.d.ts +2 -0
  75. package/dist-lib/lib/departure-preview.check.d.ts.map +1 -0
  76. package/dist-lib/lib/departure-preview.check.js +37 -0
  77. package/dist-lib/lib/departure-preview.d.ts +47 -0
  78. package/dist-lib/lib/departure-preview.d.ts.map +1 -0
  79. package/dist-lib/lib/departure-preview.functions.d.ts +13 -0
  80. package/dist-lib/lib/departure-preview.functions.d.ts.map +1 -0
  81. package/dist-lib/lib/departure-preview.functions.js +17 -0
  82. package/dist-lib/lib/departure-preview.js +70 -0
  83. package/dist-lib/lib/departure-preview.server.d.ts +10 -0
  84. package/dist-lib/lib/departure-preview.server.d.ts.map +1 -0
  85. package/dist-lib/lib/departure-preview.server.js +29 -0
  86. package/dist-lib/lib/floriday-external-fulfillment.check.d.ts +2 -0
  87. package/dist-lib/lib/floriday-external-fulfillment.check.d.ts.map +1 -0
  88. package/dist-lib/lib/floriday-external-fulfillment.check.js +21 -0
  89. package/dist-lib/lib/floriday-external-fulfillment.d.ts +19 -0
  90. package/dist-lib/lib/floriday-external-fulfillment.d.ts.map +1 -0
  91. package/dist-lib/lib/floriday-external-fulfillment.js +24 -0
  92. package/dist-lib/lib/floriday-external-fulfillment.server.d.ts +5 -0
  93. package/dist-lib/lib/floriday-external-fulfillment.server.d.ts.map +1 -0
  94. package/dist-lib/lib/floriday-external-fulfillment.server.js +110 -0
  95. package/dist-lib/lib/floriday-fulfillment-status.server.d.ts +2 -0
  96. package/dist-lib/lib/floriday-fulfillment-status.server.d.ts.map +1 -1
  97. package/dist-lib/lib/floriday-fulfillment-status.server.js +3 -0
  98. package/dist-lib/lib/floriday-line-key.check.d.ts +2 -0
  99. package/dist-lib/lib/floriday-line-key.check.d.ts.map +1 -0
  100. package/dist-lib/lib/floriday-line-key.check.js +31 -0
  101. package/dist-lib/lib/floriday-line-key.d.ts +12 -0
  102. package/dist-lib/lib/floriday-line-key.d.ts.map +1 -0
  103. package/dist-lib/lib/floriday-line-key.js +20 -0
  104. package/dist-lib/lib/floriday-mirror.functions.d.ts.map +1 -1
  105. package/dist-lib/lib/floriday-mirror.functions.js +38 -2
  106. package/dist-lib/lib/logistics-engine.functions.d.ts +1 -1
  107. package/dist-lib/lib/order-cart-count.server.d.ts +8 -0
  108. package/dist-lib/lib/order-cart-count.server.d.ts.map +1 -0
  109. package/dist-lib/lib/order-cart-count.server.js +69 -0
  110. package/dist-lib/lib/order-departure.server.d.ts +1 -0
  111. package/dist-lib/lib/order-departure.server.d.ts.map +1 -1
  112. package/dist-lib/lib/order-departure.server.js +16 -4
  113. package/dist-lib/lib/order-pickup.functions.d.ts +4 -0
  114. package/dist-lib/lib/order-pickup.functions.d.ts.map +1 -1
  115. package/dist-lib/lib/order-pickup.functions.js +7 -0
  116. package/dist-lib/lib/plan-coverage.d.ts +13 -1
  117. package/dist-lib/lib/plan-coverage.d.ts.map +1 -1
  118. package/dist-lib/lib/plan-coverage.js +20 -1
  119. package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
  120. package/dist-lib/lib/salesorders-list.server.js +6 -6
  121. package/dist-lib/lib/salesorders-mapping.d.ts +5 -0
  122. package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
  123. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
  124. package/dist-lib/lib/salesorders.functions.js +6 -0
  125. package/dist-lib/lib/tradeitems.functions.d.ts +1117 -12
  126. package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -1
  127. package/dist-lib/lib/useBufferEvents.d.ts +2 -2
  128. package/dist-lib/lib/useBufferEvents.d.ts.map +1 -1
  129. package/dist-lib/lib/useLocalSalesOrderDetailQuery.d.ts +2 -2
  130. package/dist-lib/lib/useLocalSalesOrderDetailQuery.d.ts.map +1 -1
  131. package/dist-lib/lib/useSalesOrderDetailQuery.d.ts +1 -1
  132. package/dist-lib/lib/useSalesOrderDetailQuery.d.ts.map +1 -1
  133. package/dist-lib/lib/useSalesOrdersQuery.d.ts +1 -1
  134. package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
  135. package/package.json +1 -1
  136. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts +0 -9
  137. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts.map +0 -1
  138. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.js +0 -26
  139. package/dist-lib/components/karindeling/AfmetingenTab.d.ts +0 -6
  140. package/dist-lib/components/karindeling/AfmetingenTab.d.ts.map +0 -1
  141. package/dist-lib/components/karindeling/AfmetingenTab.js +0 -128
  142. package/dist-lib/components/karindeling/KarindelingPage.d.ts +0 -2
  143. package/dist-lib/components/karindeling/KarindelingPage.d.ts.map +0 -1
  144. package/dist-lib/components/karindeling/KarindelingPage.js +0 -102
  145. package/dist-lib/components/ui/dropdown-menu.d.ts +0 -9
  146. package/dist-lib/components/ui/dropdown-menu.d.ts.map +0 -1
  147. package/dist-lib/components/ui/dropdown-menu.js +0 -14
  148. package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.d.ts +0 -4
  149. package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.d.ts.map +0 -1
  150. package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.js +0 -95
  151. package/dist-lib/components/verkoop/CreateOrderDialog.d.ts +0 -5
  152. package/dist-lib/components/verkoop/CreateOrderDialog.d.ts.map +0 -1
  153. package/dist-lib/components/verkoop/CreateOrderDialog.js +0 -33
  154. package/dist-lib/lib/cron/mirror-floriday-orders.d.ts +0 -4
  155. package/dist-lib/lib/cron/mirror-floriday-orders.d.ts.map +0 -1
  156. package/dist-lib/lib/cron/mirror-floriday-orders.js +0 -23
  157. package/dist-lib/lib/cron/push-order-statuses.d.ts +0 -4
  158. package/dist-lib/lib/cron/push-order-statuses.d.ts.map +0 -1
  159. package/dist-lib/lib/cron/push-order-statuses.js +0 -23
  160. package/dist-lib/lib/floriday/floriday.server.d.ts +0 -14
  161. package/dist-lib/lib/floriday/floriday.server.d.ts.map +0 -1
  162. package/dist-lib/lib/floriday/floriday.server.js +0 -92
  163. package/dist-lib/lib/floriday/sales-orders.functions.d.ts +0 -4736
  164. package/dist-lib/lib/floriday/sales-orders.functions.d.ts.map +0 -1
  165. package/dist-lib/lib/floriday/sales-orders.functions.js +0 -193
  166. package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts +0 -77581
  167. package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts.map +0 -1
  168. package/dist-lib/lib/floriday-auto-fulfillment.functions.js +0 -65
  169. package/dist-lib/lib/floriday-auto-fulfillment.server.d.ts +0 -21
  170. package/dist-lib/lib/floriday-auto-fulfillment.server.d.ts.map +0 -1
  171. package/dist-lib/lib/floriday-auto-fulfillment.server.js +0 -352
  172. package/dist-lib/lib/floriday-status-sync.server.d.ts +0 -14
  173. package/dist-lib/lib/floriday-status-sync.server.d.ts.map +0 -1
  174. package/dist-lib/lib/floriday-status-sync.server.js +0 -130
@@ -0,0 +1,70 @@
1
+ // Voorbeeld van het ophaalmoment vóór er een order is, zoals de Logistiek
2
+ // Engine het geeft (logistics_departure_preview). Alleen normaliseren en
3
+ // beslissen wat je ziet; deze module rekent zelf niets uit.
4
+ import { formatMoment } from "./order-departure.js";
5
+ const s = (v) => (typeof v === "string" && v.trim() !== "" ? v : null);
6
+ export function normalizePreview(raw) {
7
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
8
+ return null;
9
+ const r = raw;
10
+ const moments = Array.isArray(r.moments)
11
+ ? r.moments
12
+ .filter((m) => m && s(m.momentKey))
13
+ .map((m) => ({
14
+ momentKey: String(m.momentKey),
15
+ departureAt: s(m.departureAt),
16
+ signupDeadline: s(m.signupDeadline),
17
+ feasible: m.feasible === true,
18
+ }))
19
+ : [];
20
+ const c = r.chosen && typeof r.chosen === "object" ? r.chosen : null;
21
+ return {
22
+ ok: r.ok === true,
23
+ reason: s(r.reason),
24
+ carrierId: s(r.carrierId),
25
+ moments,
26
+ chosen: c
27
+ ? { momentKey: s(c.momentKey), departureAt: s(c.departureAt), signupDeadline: s(c.signupDeadline) }
28
+ : null,
29
+ deliveryDateFeasible: r.deliveryDateFeasible === true,
30
+ deliveryDateReason: s(r.deliveryDateReason) ?? s(r.reason),
31
+ firstFeasibleDeliveryDate: s(r.firstFeasibleDeliveryDate),
32
+ firstFeasibleReason: s(r.firstFeasibleReason),
33
+ };
34
+ }
35
+ export const PREVIEW_UNKNOWN = "Het ophaalmoment is nu niet bekend. Probeer het over een minuut opnieuw.";
36
+ function momentText(departureAt, signup) {
37
+ const p = formatMoment(departureAt);
38
+ if (!p)
39
+ return null;
40
+ const a = formatMoment(signup);
41
+ return a ? `ophalen ${p} · aanmelden ${a}` : `ophalen ${p}`;
42
+ }
43
+ /**
44
+ * Wat je ziet / of je mag aanmaken.
45
+ * - ok = false of geen antwoord: geblokkeerd, alleen de reden.
46
+ * - leverdatum niet haalbaar: "te laat" — alleen aanmaken na bewuste keuze.
47
+ */
48
+ export function decidePreview(p) {
49
+ if (!p)
50
+ return { kind: "blocked", reason: PREVIEW_UNKNOWN };
51
+ if (!p.ok)
52
+ return { kind: "blocked", reason: p.reason ?? "Voor deze leverdatum is geen ophaalmoment mogelijk." };
53
+ const momentKey = p.chosen?.momentKey ?? null;
54
+ const text = momentText(p.chosen?.departureAt ?? null, p.chosen?.signupDeadline ?? null);
55
+ if (!p.deliveryDateFeasible) {
56
+ return {
57
+ kind: "late",
58
+ reason: p.deliveryDateReason ?? "Aanmelden voor deze leverdatum kan niet meer.",
59
+ firstDate: p.firstFeasibleDeliveryDate,
60
+ firstReason: p.firstFeasibleReason,
61
+ momentKey,
62
+ text,
63
+ };
64
+ }
65
+ return { kind: "ok", momentKey, text };
66
+ }
67
+ export function momentLabel(m) {
68
+ return momentText(m.departureAt, m.signupDeadline) ?? m.momentKey;
69
+ }
70
+ export const LATE_CONFIRM = "Deze order komt na de aanmeldtijd. De vervoerder krijgt hem als te laat aangemeld. Doorgaan?";
@@ -0,0 +1,10 @@
1
+ import { type DeparturePreview } from "./departure-preview.js";
2
+ export declare function loadDeparturePreview(supabase: any, input: {
3
+ carrierId: string | null;
4
+ deliveryLocation: string;
5
+ deliveryDate: string;
6
+ momentKey?: string | null;
7
+ }): Promise<DeparturePreview | null>;
8
+ /** Aanlevertijd opzoeken bij het door de Engine gekozen moment (geen berekening). */
9
+ export declare function deliveryTimeForMoment(supabase: any, carrierId: string | null, momentKey: string | null): Promise<string | null>;
10
+ //# sourceMappingURL=departure-preview.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"departure-preview.server.d.ts","sourceRoot":"","sources":["../../src/lib/departure-preview.server.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE9E,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7G,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAiBlC;AAED,qFAAqF;AACrF,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,GAAG,EACb,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKxB"}
@@ -0,0 +1,29 @@
1
+ // Vraagt het voorbeeld-ophaalmoment op bij de Engine. Fout => null (fail closed).
2
+ import { normalizePreview } from "./departure-preview.js";
3
+ export async function loadDeparturePreview(supabase, input) {
4
+ try {
5
+ const { data, error } = await supabase.rpc("logistics_departure_preview", {
6
+ p_carrier_id: input.carrierId ?? null,
7
+ p_delivery_location: input.deliveryLocation,
8
+ p_delivery_date: input.deliveryDate,
9
+ p_moment_key: input.momentKey ?? null,
10
+ });
11
+ if (error) {
12
+ console.warn("[departure-preview]", error.message);
13
+ return null;
14
+ }
15
+ return normalizePreview(data);
16
+ }
17
+ catch (err) {
18
+ console.warn("[departure-preview]", err);
19
+ return null;
20
+ }
21
+ }
22
+ /** Aanlevertijd opzoeken bij het door de Engine gekozen moment (geen berekening). */
23
+ export async function deliveryTimeForMoment(supabase, carrierId, momentKey) {
24
+ if (!carrierId || !momentKey)
25
+ return null;
26
+ const { data } = await supabase.from("carriers").select("pickup_moments").eq("id", carrierId).maybeSingle();
27
+ const { carrierMomentOptions } = await import("./order-pickup.functions.js");
28
+ return carrierMomentOptions(data ?? null).find((o) => o.key === momentKey)?.deliveryTime ?? null;
29
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=floriday-external-fulfillment.check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-external-fulfillment.check.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-external-fulfillment.check.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ // Controle "afgehandeld in Floriday". Draai: bun src/lib/floriday-external-fulfillment.check.ts
2
+ import { decideExternalFulfillment as d } from "./floriday-external-fulfillment.js";
3
+ let failed = 0;
4
+ const check = (n, got, want) => { const ok = got === want; if (!ok)
5
+ failed++; console.log(`${ok ? "OK " : "FOUT"} ${n}: ${got}${ok ? "" : ` (verwacht ${want})`}`); };
6
+ const base = { status: "Nog te picken", previousIds: [], alreadyFull: false };
7
+ check("één bestelling, minder fust, buiten ERP → verzonden", d({ ...base, salesOrderIds: ["a"], isExternal: () => true }).kind, "full");
8
+ check("door ERP gemaakt → niets", d({ ...base, salesOrderIds: ["a"], isExternal: () => false }).kind, "none");
9
+ check("samengevoegd, alle afgehandeld → verzonden", d({ ...base, salesOrderIds: ["a", "b"], isExternal: () => true }).kind, "full");
10
+ const p = d({ ...base, salesOrderIds: ["a", "b"], isExternal: (id) => id === "a" });
11
+ check("samengevoegd, deel → partial", p.kind, "partial");
12
+ check("deel: alleen a", p.kind === "partial" ? p.fulfilledIds.join() : "", "a");
13
+ check("deel al vastgelegd → niets nieuws", d({ ...base, previousIds: ["a"], salesOrderIds: ["a", "b"], isExternal: (id) => id === "a" }).kind, "none");
14
+ check("al verzonden door ERP → blijft", d({ ...base, status: "Verzonden", salesOrderIds: ["a"], isExternal: () => true }).kind, "none");
15
+ check("geannuleerd → blijft", d({ ...base, status: "geannuleerd", salesOrderIds: ["a"], isExternal: () => true }).kind, "none");
16
+ check("al afgerond → niet nogmaals", d({ ...base, alreadyFull: true, salesOrderIds: ["a"], isExternal: () => true }).kind, "none");
17
+ if (failed) {
18
+ console.error(`${failed} controle(s) mislukt`);
19
+ process.exit(1);
20
+ }
21
+ console.log("Alle controles geslaagd");
@@ -0,0 +1,19 @@
1
+ export declare const FLORIDAY_EXTERNAL_REASON = "Afgehandeld in Floriday";
2
+ export declare const SHIPPED_STATUS = "Verzonden";
3
+ export type ExternalDecision = {
4
+ kind: "none";
5
+ } | {
6
+ kind: "full";
7
+ fulfilledIds: string[];
8
+ } | {
9
+ kind: "partial";
10
+ fulfilledIds: string[];
11
+ };
12
+ export declare function decideExternalFulfillment(input: {
13
+ status: string | null | undefined;
14
+ salesOrderIds: string[];
15
+ isExternal: (salesOrderId: string) => boolean;
16
+ previousIds: string[];
17
+ alreadyFull: boolean;
18
+ }): ExternalDecision;
19
+ //# sourceMappingURL=floriday-external-fulfillment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-external-fulfillment.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-external-fulfillment.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,4BAA4B,CAAC;AAClE,eAAO,MAAM,cAAc,cAAc,CAAC;AAE1C,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEhD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;IAC9C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,gBAAgB,CAcnB"}
@@ -0,0 +1,24 @@
1
+ // Beslisregel "afgehandeld in Floriday" (buiten het ERP om). Zuiver, geen I/O.
2
+ // Per Floriday-bestelling: er bestaat een afhandeling die niet door het ERP is
3
+ // gemaakt. Het aantal fust telt niet mee.
4
+ export const FLORIDAY_EXTERNAL_REASON = "Afgehandeld in Floriday";
5
+ export const SHIPPED_STATUS = "Verzonden";
6
+ export function decideExternalFulfillment(input) {
7
+ const st = String(input.status ?? "").trim().toLowerCase();
8
+ // Al verzonden (ERP) of geannuleerd: blijft zoals hij is.
9
+ if (input.alreadyFull || ["verzonden", "shipped", "geleverd", "delivered", "geannuleerd"].includes(st)) {
10
+ return { kind: "none" };
11
+ }
12
+ const ids = Array.from(new Set(input.salesOrderIds.filter(Boolean)));
13
+ if (ids.length === 0)
14
+ return { kind: "none" };
15
+ const done = ids.filter((id) => input.isExternal(id));
16
+ if (done.length === 0)
17
+ return { kind: "none" };
18
+ if (done.length === ids.length)
19
+ return { kind: "full", fulfilledIds: done };
20
+ const prev = new Set(input.previousIds);
21
+ if (done.length === prev.size && done.every((id) => prev.has(id)))
22
+ return { kind: "none" };
23
+ return { kind: "partial", fulfilledIds: done };
24
+ }
@@ -0,0 +1,5 @@
1
+ import type { FloridayFulfillmentState } from "./floriday-fulfillment-status.server.js";
2
+ export declare function handleFloridayExternalFulfillment(orderId: string, states?: Map<string, FloridayFulfillmentState>): Promise<"none" | "shipped" | "partial">;
3
+ /** Haalt het event-id uit het antwoord van logistics_emit_event (uuid, of object met id/eventId). */
4
+ export declare function extractEventId(data: unknown): string | null;
5
+ //# sourceMappingURL=floriday-external-fulfillment.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-external-fulfillment.server.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-external-fulfillment.server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAErF,wBAAsB,iCAAiC,CACrD,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,GAC7C,OAAO,CAAC,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC,CAgFzC;AAED,qGAAqG;AACrG,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQ3D"}
@@ -0,0 +1,110 @@
1
+ // Order die in Floriday zelf is afgehandeld (buiten het ERP om) netjes afronden.
2
+ // Naar het voorbeeld van handleFloridayCancellation. Geen melding voor kantoor,
3
+ // geen voorraadmutatie (dat is aan Voorraad), schrijft nooit order_carts.
4
+ import { decideExternalFulfillment, FLORIDAY_EXTERNAL_REASON, SHIPPED_STATUS } from "./floriday-external-fulfillment.js";
5
+ import { externalFulfilledIdempotencyKey } from "./floriday-line-key.js";
6
+ export async function handleFloridayExternalFulfillment(orderId, states) {
7
+ const { supabaseAdmin } = await import("../integrations/supabase/client.server.js");
8
+ const { data: order, error } = await supabaseAdmin
9
+ .from("orders")
10
+ .select("id, status, custom_fields")
11
+ .eq("id", orderId)
12
+ .maybeSingle();
13
+ if (error)
14
+ throw new Error(error.message);
15
+ if (!order)
16
+ return "none";
17
+ const o = order;
18
+ const cf = (o.custom_fields ?? {});
19
+ const soIds = Array.isArray(cf.floriday_sales_order_ids) && cf.floriday_sales_order_ids.length > 0
20
+ ? cf.floriday_sales_order_ids.map(String)
21
+ : cf.floriday_sales_order_id ? [String(cf.floriday_sales_order_id)] : [];
22
+ if (soIds.length === 0)
23
+ return "none";
24
+ // Ontbrekende bestellingen in de meegegeven stand: vers lezen (fail closed = niet afgehandeld).
25
+ let map = states ?? new Map();
26
+ if (soIds.some((id) => !map.has(id))) {
27
+ const { loadFloridayFulfillmentStates } = await import("./floriday-fulfillment-status.server.js");
28
+ const fresh = await loadFloridayFulfillmentStates(supabaseAdmin, soIds);
29
+ map = new Map([...map, ...fresh]);
30
+ }
31
+ const decision = decideExternalFulfillment({
32
+ status: o.status,
33
+ salesOrderIds: soIds,
34
+ isExternal: (id) => Boolean(map.get(id)?.external),
35
+ previousIds: Array.isArray(cf.floriday_external_fulfilled_sales_order_ids) ? cf.floriday_external_fulfilled_sales_order_ids : [],
36
+ alreadyFull: Boolean(cf.floriday_external_fulfilled_at),
37
+ });
38
+ if (decision.kind === "none")
39
+ return "none";
40
+ const now = new Date().toISOString();
41
+ const nextCf = { ...cf, floriday_external_fulfilled_sales_order_ids: decision.fulfilledIds };
42
+ let patch;
43
+ if (decision.kind === "full") {
44
+ nextCf.floriday_external_fulfilled_at = now;
45
+ nextCf.floriday_external_fulfilled_notice = FLORIDAY_EXTERNAL_REASON;
46
+ patch = { status: SHIPPED_STATUS, status_sync_token: globalThis.crypto.randomUUID(), custom_fields: nextCf };
47
+ }
48
+ else {
49
+ patch = { custom_fields: nextCf };
50
+ }
51
+ const { error: uErr } = await supabaseAdmin.from("orders").update(patch).eq("id", orderId);
52
+ if (uErr)
53
+ throw new Error(uErr.message);
54
+ if (decision.kind === "full") {
55
+ await supabaseAdmin.from("cart_replan_queue").delete().eq("order_id", orderId);
56
+ }
57
+ // Engine melden via logistics_emit_event (idempotent); event-id of fout op de order bewaren.
58
+ const ids = [...new Set(decision.fulfilledIds.map(String))].sort();
59
+ let eventId = null;
60
+ let emitError = null;
61
+ try {
62
+ const { data, error: rpcErr } = await supabaseAdmin.rpc("logistics_emit_event", {
63
+ p_source_module: "verkoop",
64
+ p_event_type: "order.changed",
65
+ p_order_ref: orderId,
66
+ p_payload: {
67
+ orderId,
68
+ reason: FLORIDAY_EXTERNAL_REASON,
69
+ floridayExternalFulfilledFull: decision.kind === "full",
70
+ floridayExternalFulfilledSalesOrderIds: ids,
71
+ },
72
+ p_idempotency_key: externalFulfilledIdempotencyKey(orderId, ids),
73
+ });
74
+ if (rpcErr)
75
+ emitError = rpcErr.message;
76
+ else
77
+ eventId = extractEventId(data);
78
+ }
79
+ catch (err) {
80
+ emitError = err.message;
81
+ }
82
+ const afterCf = { ...nextCf };
83
+ if (eventId)
84
+ afterCf.floriday_external_engine_event_id = eventId;
85
+ else
86
+ delete afterCf.floriday_external_engine_event_id;
87
+ if (emitError)
88
+ afterCf.floriday_external_engine_error = emitError.slice(0, 300);
89
+ else
90
+ delete afterCf.floriday_external_engine_error;
91
+ const { error: eErr } = await supabaseAdmin.from("orders").update({ custom_fields: afterCf }).eq("id", orderId);
92
+ if (eErr)
93
+ console.warn("[floriday-external] event-id bewaren faalde:", eErr.message);
94
+ if (emitError)
95
+ console.warn("[floriday-external] engine-melding faalde:", emitError);
96
+ console.info(`[floriday-external] order ${orderId}: ${decision.kind} (${decision.fulfilledIds.length}/${soIds.length})`);
97
+ return decision.kind === "full" ? "shipped" : "partial";
98
+ }
99
+ /** Haalt het event-id uit het antwoord van logistics_emit_event (uuid, of object met id/eventId). */
100
+ export function extractEventId(data) {
101
+ if (typeof data === "string" && data.trim())
102
+ return data.trim();
103
+ if (data && typeof data === "object") {
104
+ const d = data;
105
+ const v = d.eventId ?? d.event_id ?? d.id;
106
+ if (typeof v === "string" && v.trim())
107
+ return v.trim();
108
+ }
109
+ return null;
110
+ }
@@ -11,6 +11,8 @@ export interface FloridayFulfillmentState {
11
11
  deliveryNoteCodes: string[];
12
12
  /** Aangemaakt door ons ERP (auto-fulfillment) i.p.v. rechtstreeks in Floriday. */
13
13
  createdByErp: boolean;
14
+ /** Minstens één afhandeling die NIET door het ERP is gemaakt (rechtstreeks in Floriday). */
15
+ external: boolean;
14
16
  }
15
17
  /**
16
18
  * Bouwt een map salesOrderId -> afhandelstatus. Eén query over de
@@ -1 +1 @@
1
- {"version":3,"file":"floriday-fulfillment-status.server.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-fulfillment-status.server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,SAAS,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,kFAAkF;IAClF,YAAY,EAAE,OAAO,CAAC;CACvB;AAID;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,cAAc,EACxB,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CA+DhD;AAED,+EAA+E;AAC/E,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAIhE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,wBAAwB,GAAG,SAAS,EAC3C,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAKT"}
1
+ {"version":3,"file":"floriday-fulfillment-status.server.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-fulfillment-status.server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,SAAS,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,kFAAkF;IAClF,YAAY,EAAE,OAAO,CAAC;IACtB,4FAA4F;IAC5F,QAAQ,EAAE,OAAO,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,cAAc,EACxB,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAiEhD;AAED,+EAA+E;AAC/E,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAIhE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,wBAAwB,GAAG,SAAS,EAC3C,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAKT"}
@@ -50,6 +50,7 @@ export async function loadFloridayFulfillmentStates(supabase, salesOrderIds) {
50
50
  receivedAt: null,
51
51
  deliveryNoteCodes: [],
52
52
  createdByErp: false,
53
+ external: false,
53
54
  };
54
55
  prev.fulfilled = true;
55
56
  prev.packages += Number(item?.numberOfPackages ?? 0) || 0;
@@ -63,6 +64,8 @@ export async function loadFloridayFulfillmentStates(supabase, salesOrderIds) {
63
64
  }
64
65
  if (byErp)
65
66
  prev.createdByErp = true;
67
+ else
68
+ prev.external = true;
66
69
  result.set(soId, prev);
67
70
  }
68
71
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=floriday-line-key.check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-line-key.check.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-line-key.check.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ // Draai met: bun src/lib/floriday-line-key.check.ts
2
+ import { externalFulfilledIdempotencyKey, isValidSalesOrderId, splitByLineKey } from "./floriday-line-key.js";
3
+ import { parseExternal, parsePlanCoverage, parsePlanCoverageListRow } from "./plan-coverage.js";
4
+ import { extractEventId } from "./floriday-external-fulfillment.server.js";
5
+ let fail = 0;
6
+ const ok = (c, m) => {
7
+ if (!c)
8
+ fail++;
9
+ console.log(`${c ? "OK " : "FOUT"} ${m}`);
10
+ };
11
+ const A = "11111111-1111-4111-8111-111111111111";
12
+ const B = "22222222-2222-4222-8222-222222222222";
13
+ ok(isValidSalesOrderId(A), "uuid is geldige sleutel");
14
+ ok(!isValidSalesOrderId("undefined") && !isValidSalesOrderId("") && !isValidSalesOrderId(null), "lege/onzin-sleutel ongeldig");
15
+ const s = splitByLineKey([{ foId: A }, { foId: B }, { foId: "null" }]);
16
+ ok(s.valid.length === 2 && s.invalid.length === 1, "samengevoegde order: twee geldige regels, één apart gemeld");
17
+ ok(s.valid.every((l) => isValidSalesOrderId(l.foId)), "elke opgeslagen regel heeft een uuid-sleutel");
18
+ ok(externalFulfilledIdempotencyKey("o1", [B, A, A]) === `extern-afgehandeld:o1:${A},${B}`, "idempotentiesleutel gesorteerd en ontdubbeld");
19
+ const full = parsePlanCoverage({ state: "afgehandeld_extern", externalFulfilled: { full: true, salesOrderIds: [A] } });
20
+ ok(full.state === "afgehandeld_extern" && full.label === "Afgehandeld in Floriday", "volledig: 'Afgehandeld in Floriday'");
21
+ ok(full.externalFulfilled?.full === true, "externalFulfilled.full gelezen");
22
+ const part = parsePlanCoverage({ state: "deels", progressPct: 40, externalFulfilled: { full: false, salesOrderIds: [A] } });
23
+ ok(part.progressPct === 40 && part.externalFulfilled?.full === false, "deels: voortgang van de Engine overgenomen");
24
+ ok(parseExternal({ full: "ja" }) === null, "full geen boolean → genegeerd");
25
+ ok(parsePlanCoverageListRow({ state: "afgehandeld_extern" }).label === "Afgehandeld in Floriday", "lijst: label");
26
+ ok(extractEventId({ eventId: A }) === A && extractEventId(A) === A && extractEventId({}) === null, "event-id uit antwoord");
27
+ if (fail) {
28
+ console.error(`${fail} controle(s) mislukt`);
29
+ process.exit(1);
30
+ }
31
+ console.log("Alle controles geslaagd");
@@ -0,0 +1,12 @@
1
+ export declare const MISSING_LINE_KEY_NOTICE = "Een regel van deze Floriday-order mist het bestelnummer en is niet overgenomen";
2
+ export declare function isValidSalesOrderId(v: unknown): v is string;
3
+ /** Splitst regels in geldige (met uuid-sleutel) en ongeldige. */
4
+ export declare function splitByLineKey<T extends {
5
+ foId: unknown;
6
+ }>(lines: T[]): {
7
+ valid: T[];
8
+ invalid: T[];
9
+ };
10
+ /** Idempotentiesleutel voor de melding "Afgehandeld in Floriday" (id's gesorteerd). */
11
+ export declare function externalFulfilledIdempotencyKey(orderId: string, salesOrderIds: string[]): string;
12
+ //# sourceMappingURL=floriday-line-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-line-key.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-line-key.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,uBAAuB,mFAC8C,CAAC;AAEnF,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAE3D;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,CAAC,EAAE,CAAA;CAAE,CAKpG;AAED,uFAAuF;AACvF,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAEhG"}
@@ -0,0 +1,20 @@
1
+ // Herkomstsleutel van een Floriday-orderregel: altijd de Floriday-salesOrderId (uuid).
2
+ // Een regel zonder geldige id wordt niet overgenomen, maar nooit stil: de order
3
+ // krijgt een zichtbare melding en het rondeverslag een foutregel.
4
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
+ export const MISSING_LINE_KEY_NOTICE = "Een regel van deze Floriday-order mist het bestelnummer en is niet overgenomen";
6
+ export function isValidSalesOrderId(v) {
7
+ return typeof v === "string" && UUID_RE.test(v.trim());
8
+ }
9
+ /** Splitst regels in geldige (met uuid-sleutel) en ongeldige. */
10
+ export function splitByLineKey(lines) {
11
+ const valid = [];
12
+ const invalid = [];
13
+ for (const l of lines)
14
+ (isValidSalesOrderId(l.foId) ? valid : invalid).push(l);
15
+ return { valid, invalid };
16
+ }
17
+ /** Idempotentiesleutel voor de melding "Afgehandeld in Floriday" (id's gesorteerd). */
18
+ export function externalFulfilledIdempotencyKey(orderId, salesOrderIds) {
19
+ return `extern-afgehandeld:${orderId}:${[...new Set(salesOrderIds)].sort().join(",")}`;
20
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"floriday-mirror.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-mirror.functions.ts"],"names":[],"mappings":"AA+IA,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;AAs3CD,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":"AAgJA,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;AAy5CD,wBAAsB,4BAA4B,CAAC,KAAK,SAAgB,yBAEvE;AAED,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;yBAG0C,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { diffBuyerChanges } from "./floriday-change-diff.js";
2
+ import { MISSING_LINE_KEY_NOTICE, splitByLineKey } from "./floriday-line-key.js";
2
3
  // Spiegelt Floriday-verkooporders (FO's) uit `floriday_salesorders_cache`
3
4
  // naar de lokale `orders`-tabel, zodat ze via `resolveBufferForOrderInternal`
4
5
  // in dezelfde buffer terechtkomen als lokale orders en gedeelde karren
@@ -717,6 +718,7 @@ async function mirrorUnlocked(limit) {
717
718
  lineInfoByFoId.set(l.foId, lineInfoOf(l));
718
719
  // Orders die in deze ronde al door een andere bestelling zijn geschreven.
719
720
  const handledOrderIds = new Set();
721
+ const legacyExternalIds = new Set();
720
722
  // Welke velden per order echt veranderden (voor melding en syncresultaat).
721
723
  const changedFieldsByOrder = new Map();
722
724
  const noteChange = (orderId, field) => {
@@ -756,7 +758,9 @@ async function mirrorUnlocked(limit) {
756
758
  floriday_status: primary.d?.status ?? null,
757
759
  floriday_trade_item_id: primary.tradeItemId || null,
758
760
  floriday_fulfilled: anyFulfilled,
759
- floriday_fulfilled_externally: anyFulfilled && !ffPrimary?.createdByErp,
761
+ // Afgehandeld in Floriday = er is een afhandeling die niet door het ERP
762
+ // is gemaakt; het aantal fust doet er niet toe (koppelprompt 1.0.96).
763
+ floriday_fulfilled_externally: group.some((l) => Boolean(l.ff?.external)),
760
764
  floriday_fulfilled_by_erp: anyFulfilled && Boolean(ffPrimary?.createdByErp),
761
765
  floriday_delivery_notes: ffPrimary?.deliveryNoteCodes ?? [],
762
766
  floriday_received_at: ffPrimary?.receivedAt ?? null,
@@ -921,6 +925,11 @@ async function mirrorUnlocked(limit) {
921
925
  // samenvoegen, nooit overschrijven — de order kan door de Engine uit
922
926
  // meerdere bestellingen zijn samengesteld.
923
927
  const prevCf = { ...(target.custom_fields ?? {}) };
928
+ // Bestaande orders die vóór 1.0.96 al als "buiten het ERP afgehandeld"
929
+ // stonden, worden niet vanzelf omgezet (eerst akkoord gebruiker).
930
+ if (prevCf.floriday_fulfilled_externally === true && !prevCf.floriday_external_fulfilled_sales_order_ids && !prevCf.floriday_external_fulfilled_at) {
931
+ legacyExternalIds.add(String(target.id));
932
+ }
924
933
  // Oudere orders kennen floriday_groups nog niet: hun eigen bestelling
925
934
  // als eerste groep overnemen, zodat die lijst niet verloren gaat.
926
935
  const prevGroups = (prevCf.floriday_groups ??
@@ -952,6 +961,20 @@ async function mirrorUnlocked(limit) {
952
961
  mergedCf.floriday_sales_order_ids = [...allIds].sort();
953
962
  mergedCf.floriday_lines = [...otherLines, ...floridayLines].sort((a, b) => String(a?.sales_order_id).localeCompare(String(b?.sales_order_id)));
954
963
  mergedCf.floriday_line_count = mergedCf.floriday_lines.length;
964
+ // Regels zonder geldige Floriday-salesOrderId worden niet overgenomen,
965
+ // maar nooit stil: zichtbare melding op de order + foutregel.
966
+ {
967
+ const { invalid } = splitByLineKey(group);
968
+ if (invalid.length > 0) {
969
+ mergedCf.floriday_missing_line_key_notice = MISSING_LINE_KEY_NOTICE;
970
+ mergedCf.floriday_missing_line_key_count = invalid.length;
971
+ errors.push(`${primary.foId}: ${invalid.length} regel(s) zonder geldig Floriday-bestelnummer niet overgenomen`);
972
+ }
973
+ else {
974
+ delete mergedCf.floriday_missing_line_key_notice;
975
+ delete mergedCf.floriday_missing_line_key_count;
976
+ }
977
+ }
955
978
  if (Object.keys(failures).length > 0)
956
979
  mergedCf.mirror_failures = failures;
957
980
  else {
@@ -1161,7 +1184,8 @@ async function mirrorUnlocked(limit) {
1161
1184
  // een vaste herkomstsleutel (source_line_key = Floriday sales order id),
1162
1185
  // nooit meer wissen-en-opnieuw-toevoegen: dat veroorzaakte duplicaten
1163
1186
  // zodra de verwijdering op een timeout stuk liep.
1164
- const lineRows = group.map((l) => {
1187
+ // Alleen regels met een geldige Floriday-salesOrderId (uuid) als sleutel.
1188
+ const lineRows = splitByLineKey(group).valid.map((l) => {
1165
1189
  const locked = lockedByKey.get(l.foId);
1166
1190
  return {
1167
1191
  order_id: orderId,
@@ -1346,6 +1370,18 @@ async function mirrorUnlocked(limit) {
1346
1370
  // Batch enqueue voor karherplanning. processed_at resetten, anders blijft een
1347
1371
  // eerder verwerkte order voor altijd overgeslagen door de cron.
1348
1372
  // Annuleringen uit Floriday afhandelen (koppelprompt 1.0.77).
1373
+ // Afgehandeld in Floriday (buiten het ERP om) — na de ronde, per order.
1374
+ for (const oid of Array.from(handledOrderIds)) {
1375
+ if (legacyExternalIds.has(oid))
1376
+ continue;
1377
+ try {
1378
+ const { handleFloridayExternalFulfillment } = await import("./floriday-external-fulfillment.server.js");
1379
+ await handleFloridayExternalFulfillment(oid, fulfillmentStates);
1380
+ }
1381
+ catch (err) {
1382
+ errors.push(`${oid}: afhandeling in Floriday verwerken faalde: ${err.message}`.slice(0, 200));
1383
+ }
1384
+ }
1349
1385
  for (const cid of Array.from(new Set(floridayCancelIds))) {
1350
1386
  try {
1351
1387
  const { handleFloridayCancellation } = await import("./order-cancel.server.js");
@@ -5,7 +5,7 @@ export declare const sendOrderEventToEngine: import("@tanstack/start-client-core
5
5
  claims: import("@supabase/auth-js").User;
6
6
  }, undefined, undefined, undefined>], (input: unknown) => {
7
7
  orderId: string;
8
- type: "order.received" | "order.changed";
8
+ type: "order.changed" | "order.received";
9
9
  }, Promise<{
10
10
  ok: false;
11
11
  error: string;
@@ -0,0 +1,8 @@
1
+ export interface OrderCartInfo {
2
+ count: number;
3
+ carrierTypes: string[];
4
+ sharedCount: number;
5
+ cartIds: string[];
6
+ }
7
+ export declare function loadCartsByOrder(supabase: any, orderIds: string[]): Promise<Map<string, OrderCartInfo>>;
8
+ //# sourceMappingURL=order-cart-count.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-cart-count.server.d.ts","sourceRoot":"","sources":["../../src/lib/order-cart-count.server.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CA2DrC"}
@@ -0,0 +1,69 @@
1
+ // Alleen-lezen telling van karren per order via de KARREGELS.
2
+ //
3
+ // Een order in een buffer ligt op gedeelde karren waarvan order_carts.order_id
4
+ // LEEG is (de kar hoort bij order_carts.buffer_id). Tellen op order_id geeft
5
+ // dan 0. Daarom: actieve order_items -> order_cart_items -> order_carts.
6
+ // Schrijft nooit iets; de indeling is van de Logistiek Engine.
7
+ const CHUNK = 200;
8
+ export async function loadCartsByOrder(supabase, orderIds) {
9
+ const out = new Map();
10
+ const ids = Array.from(new Set(orderIds.filter(Boolean)));
11
+ if (ids.length === 0)
12
+ return out;
13
+ // 1) actieve regels
14
+ const itemOrder = new Map();
15
+ for (let i = 0; i < ids.length; i += CHUNK) {
16
+ const { data, error } = await supabase
17
+ .from("order_items")
18
+ .select("id, order_id")
19
+ .in("order_id", ids.slice(i, i + CHUNK))
20
+ .is("quarantined_at", null);
21
+ if (error)
22
+ throw new Error(`orderregels lezen: ${error.message}`);
23
+ for (const r of (data ?? []))
24
+ itemOrder.set(String(r.id), String(r.order_id));
25
+ }
26
+ const itemIds = Array.from(itemOrder.keys());
27
+ // 2) karregels
28
+ const cartsPerOrder = new Map();
29
+ for (let i = 0; i < itemIds.length; i += CHUNK) {
30
+ const { data, error } = await supabase
31
+ .from("order_cart_items")
32
+ .select("order_item_id, cart_id")
33
+ .in("order_item_id", itemIds.slice(i, i + CHUNK));
34
+ if (error)
35
+ throw new Error(`karregels lezen: ${error.message}`);
36
+ for (const r of (data ?? [])) {
37
+ const oid = itemOrder.get(String(r.order_item_id));
38
+ if (!oid || !r.cart_id)
39
+ continue;
40
+ const s = cartsPerOrder.get(oid) ?? new Set();
41
+ s.add(String(r.cart_id));
42
+ cartsPerOrder.set(oid, s);
43
+ }
44
+ }
45
+ // 3) karren zelf (type + gedeeld)
46
+ const allCartIds = Array.from(new Set([...cartsPerOrder.values()].flatMap((s) => [...s])));
47
+ const cartRow = new Map();
48
+ for (let i = 0; i < allCartIds.length; i += CHUNK) {
49
+ const { data, error } = await supabase
50
+ .from("order_carts")
51
+ .select("id, order_id, carrier_type")
52
+ .in("id", allCartIds.slice(i, i + CHUNK));
53
+ if (error)
54
+ throw new Error(`karren lezen: ${error.message}`);
55
+ for (const r of (data ?? []))
56
+ cartRow.set(String(r.id), { order_id: r.order_id ?? null, carrier_type: r.carrier_type ?? null });
57
+ }
58
+ for (const oid of ids) {
59
+ const set = cartsPerOrder.get(oid);
60
+ const cartIds = set ? [...set].filter((c) => cartRow.has(c)) : [];
61
+ out.set(oid, {
62
+ count: cartIds.length,
63
+ cartIds,
64
+ carrierTypes: cartIds.map((c) => String(cartRow.get(c)?.carrier_type ?? "")),
65
+ sharedCount: cartIds.filter((c) => cartRow.get(c)?.order_id !== oid).length,
66
+ });
67
+ }
68
+ return out;
69
+ }
@@ -1,4 +1,5 @@
1
1
  import { type OrderDeparture } from "./order-departure.js";
2
+ export declare const LIST_CHUNK = 1000;
2
3
  export declare function loadOrderDepartures(supabase: any, orderIds: string[]): Promise<Map<string, OrderDeparture>>;
3
4
  export declare function forgetOrderDeparture(orderId: string): void;
4
5
  //# sourceMappingURL=order-departure.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"order-departure.server.d.ts","sourceRoot":"","sources":["../../src/lib/order-departure.server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAM5E,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAiDtC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,QAEnD"}
1
+ {"version":3,"file":"order-departure.server.d.ts","sourceRoot":"","sources":["../../src/lib/order-departure.server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG5E,eAAO,MAAM,UAAU,OAAO,CAAC;AAI/B,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAwDtC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,QAEnD"}