@flowselections/floriday-afhandeling-module 1.0.48 → 1.0.52

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 (36) hide show
  1. package/dist-lib/components/afhandeling/AutoProcessStatus.d.ts.map +1 -1
  2. package/dist-lib/components/afhandeling/AutoProcessStatus.js +4 -1
  3. package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
  4. package/dist-lib/components/afhandeling/DagDetailDialog.js +173 -39
  5. package/dist-lib/components/afhandeling/NuVersturenButton.d.ts +5 -0
  6. package/dist-lib/components/afhandeling/NuVersturenButton.d.ts.map +1 -0
  7. package/dist-lib/components/afhandeling/NuVersturenButton.js +56 -0
  8. package/dist-lib/hooks/useOrderBuffers.d.ts +6 -0
  9. package/dist-lib/hooks/useOrderBuffers.d.ts.map +1 -1
  10. package/dist-lib/hooks/useOrderBuffers.js +21 -0
  11. package/dist-lib/index.d.ts +0 -2
  12. package/dist-lib/index.d.ts.map +1 -1
  13. package/dist-lib/index.js +0 -2
  14. package/dist-lib/integrations/supabase/moduleClient.d.ts +4 -31315
  15. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  16. package/dist-lib/integrations/supabase/types.d.ts +3553 -87
  17. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  18. package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
  19. package/dist-lib/lib/afhandelingSettings.functions.js +2 -1
  20. package/dist-lib/lib/authGateway.server.d.ts +2 -0
  21. package/dist-lib/lib/authGateway.server.d.ts.map +1 -1
  22. package/dist-lib/lib/authGateway.server.js +2 -2
  23. package/dist-lib/lib/cartAssignments.functions.d.ts +39 -3
  24. package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
  25. package/dist-lib/lib/cartAssignments.functions.js +91 -33
  26. package/dist-lib/lib/floridayAutoProcess.d.ts +1 -1
  27. package/dist-lib/lib/floridayAutoProcess.d.ts.map +1 -1
  28. package/dist-lib/lib/floridayFulfillmentSend.server.d.ts +31 -0
  29. package/dist-lib/lib/floridayFulfillmentSend.server.d.ts.map +1 -0
  30. package/dist-lib/lib/floridayFulfillmentSend.server.js +83 -0
  31. package/dist-lib/lib/floridayLoading.functions.d.ts +93 -0
  32. package/dist-lib/lib/floridayLoading.functions.d.ts.map +1 -0
  33. package/dist-lib/lib/floridayLoading.functions.js +339 -0
  34. package/dist-lib/lib/orderFulfilment.functions.d.ts.map +1 -1
  35. package/dist-lib/lib/orderFulfilment.functions.js +17 -0
  36. package/package.json +2 -2
@@ -0,0 +1,339 @@
1
+ // Stap 3 — belading (ladingdragers) samenstellen voor een Floriday fulfillment-opdracht.
2
+ // Bron van karren/regels: Engine `logistics_order_plan_coverage` (ook gedeelde bufferkarren).
3
+ // Vaste kenmerken worden door deze module gemaakt en bewaard in
4
+ // `floriday_loading_identifiers`; de Floriday-koppeling geeft ze ongewijzigd door.
5
+ // Sets: Floriday knipt een set op in losse verkooporders → één regel per onderdeel.
6
+ import { createServerFn } from "@tanstack/react-start";
7
+ import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
8
+ const arr = (v) => (Array.isArray(v) ? v : []);
9
+ const num = (v) => v == null || v === "" || !Number.isFinite(Number(v)) ? null : Number(v);
10
+ async function ensureIds(supabase, scope, keys) {
11
+ const out = new Map();
12
+ const uniq = [...new Set(keys)];
13
+ if (!uniq.length)
14
+ return out;
15
+ const { error: insErr } = await supabase
16
+ .from("floriday_loading_identifiers")
17
+ .upsert(uniq.map((k) => ({ scope, natural_key: k })), { onConflict: "scope,natural_key", ignoreDuplicates: true });
18
+ if (insErr)
19
+ throw new Error(insErr.message);
20
+ const { data, error } = await supabase
21
+ .from("floriday_loading_identifiers")
22
+ .select("natural_key, identifier")
23
+ .eq("scope", scope)
24
+ .in("natural_key", uniq);
25
+ if (error)
26
+ throw new Error(error.message);
27
+ for (const r of data ?? [])
28
+ out.set(r.natural_key, r.identifier);
29
+ for (const k of uniq)
30
+ if (!out.has(k))
31
+ throw new Error("Vast kenmerk kon niet worden vastgelegd.");
32
+ return out;
33
+ }
34
+ // Auto-verwerking (1.0.64) neemt alleen aan; deze statussen betekenen dat de oude
35
+ // route tóch al belading/verzendbrief heeft gedaan → nooit nog eens versturen.
36
+ const AUTO_ALREADY_SENT = new Set(["sending_fulfillment", "generating_delivery_note", "done"]);
37
+ const ACCEPTED = new Set(["created", "already_fulfilled"]);
38
+ async function buildLoading(supabase, orderRef) {
39
+ if (!orderRef)
40
+ throw new Error("Geen order opgegeven.");
41
+ const blockers = [];
42
+ const loadOrder = async (ref) => {
43
+ const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(ref);
44
+ const q = supabase.from("orders").select("id, order_number, order_source, custom_fields, buffer_id").is("deleted_at", null);
45
+ const { data: row, error } = await (isUuid ? q.eq("id", ref) : q.eq("order_number", ref)).maybeSingle();
46
+ if (error)
47
+ throw new Error(error.message);
48
+ return row;
49
+ };
50
+ const coverage = new Map();
51
+ const queue = [orderRef];
52
+ const bufferIds = new Set();
53
+ while (queue.length && coverage.size < 200) {
54
+ const ref = queue.shift();
55
+ const o = await loadOrder(ref);
56
+ if (!o) {
57
+ blockers.push(`Order ${ref} niet gevonden.`);
58
+ continue;
59
+ }
60
+ if (coverage.has(o.id))
61
+ continue;
62
+ const { data: cov, error } = await supabase.rpc("logistics_order_plan_coverage", { p_order_id: o.id });
63
+ if (error)
64
+ throw new Error(error.message);
65
+ const cf = o.custom_fields ?? {};
66
+ const soId = typeof cf.floriday_sales_order_id === "string" ? cf.floriday_sales_order_id
67
+ : typeof cf.salesOrderId === "string" ? cf.salesOrderId : null;
68
+ coverage.set(o.id, { ref: o.order_number ?? o.id, source: o.order_source, salesOrderId: soId, cov: cov ?? {}, bufferId: o.buffer_id });
69
+ // Andere orders op dezelfde (gedeelde) kar.
70
+ for (const k of arr(cov?.carts)) {
71
+ for (const id of arr(k?.orderIds))
72
+ if (typeof id === "string" && !coverage.has(id))
73
+ queue.push(id);
74
+ for (const r of arr(k?.orderRefs)) {
75
+ const s2 = String(r);
76
+ if (![...coverage.values()].some((c) => c.ref === s2))
77
+ queue.push(s2);
78
+ }
79
+ }
80
+ // Alle orders van dezelfde buffer (koppeling op buffer-id van de Engine).
81
+ if (o.buffer_id && !bufferIds.has(o.buffer_id)) {
82
+ bufferIds.add(o.buffer_id);
83
+ const { data: sib, error: sErr } = await supabase.from("orders").select("id").eq("buffer_id", o.buffer_id).is("deleted_at", null);
84
+ if (sErr)
85
+ throw new Error(sErr.message);
86
+ for (const s of sib ?? [])
87
+ if (!coverage.has(s.id))
88
+ queue.push(s.id);
89
+ }
90
+ }
91
+ // Gecontroleerd = elke kar van de order is bij de controlebalie afgemeld (scan of "Controle uitvoeren").
92
+ const orderIds = [...coverage.keys()].sort();
93
+ // Zelfde regel als Floriday-authenticatie: per Engine-kar (ook gedeeld) een rij in
94
+ // logistics_control_scan met approved_at gevuld (goedgekeurd op de Scan-controle).
95
+ const allCartIds = [...new Set([...coverage.values()].flatMap((c) => arr(c.cov.carts).map((k) => k?.cartId).filter((x) => typeof x === "string")))];
96
+ const approvedCarts = new Set();
97
+ if (allCartIds.length) {
98
+ const { data: sc, error } = await supabase
99
+ .from("logistics_control_scan").select("cart_id").in("cart_id", allCartIds).not("approved_at", "is", null);
100
+ if (error)
101
+ throw new Error(error.message);
102
+ for (const r of sc ?? [])
103
+ approvedCarts.add(r.cart_id);
104
+ }
105
+ // Vaste sleutel voor de opdracht: één buffer → buffer-id, anders de gesorteerde order-id's.
106
+ // Deterministisch: dubbele klik of herhaling geeft dezelfde fulfillmentOrderId.
107
+ const bufs = [...new Set([...coverage.values()].map((c) => c.bufferId))];
108
+ const foKey = bufs.length === 1 && bufs[0] ? `buffer:${bufs[0]}` : orderIds.join("|");
109
+ const baseFo = orderIds.length ? (await ensureIds(supabase, "fulfillment_order", [foKey])).get(foKey) : null;
110
+ // Statusoverzicht van Floriday-authenticatie: fulfillmentRequestId + deliveryOrderId per order.
111
+ const soIds = [...coverage.values()].map((c) => c.salesOrderId).filter((x) => !!x);
112
+ let status = new Map();
113
+ let statusFailed = false;
114
+ try {
115
+ const { fetchFulfillmentStatus } = await import("./floridayFulfillmentSend.server");
116
+ status = await fetchFulfillmentStatus(soIds, baseFo ? [baseFo] : []);
117
+ }
118
+ catch (e) {
119
+ statusFailed = true;
120
+ blockers.push(e instanceof Error ? e.message : "Statusoverzicht ophalen mislukt.");
121
+ }
122
+ // Oude auto-verwerking: laatste logregel per order.
123
+ const autoBySo = new Map();
124
+ if (soIds.length) {
125
+ const { data: logs } = await supabase
126
+ .from("floriday_auto_fulfillment_log")
127
+ .select("sales_order_id, status, fulfillment_order_id, updated_at")
128
+ .in("sales_order_id", soIds).order("updated_at", { ascending: false });
129
+ for (const l of logs ?? [])
130
+ if (!autoBySo.has(l.sales_order_id))
131
+ autoBySo.set(l.sales_order_id, { status: l.status, fo: l.fulfillment_order_id });
132
+ }
133
+ const orders = [];
134
+ for (const [id, { ref, salesOrderId, cov }] of coverage) {
135
+ const cartsTotal = arr(cov.carts).length;
136
+ const cartIds = arr(cov.carts).map((k) => k?.cartId);
137
+ const done = cartIds.filter((c) => typeof c === "string" && approvedCarts.has(c)).length;
138
+ const controlled = cartsTotal > 0 && done === cartsTotal;
139
+ const st = salesOrderId ? status.get(salesOrderId) : undefined;
140
+ const fr = st?.fulfillmentRequests ?? [];
141
+ const auto = salesOrderId ? autoBySo.get(salesOrderId) : undefined;
142
+ orders.push({
143
+ orderRef: ref, salesOrderId, pickStatus: cov.pickStatus ?? null, controlled,
144
+ cartsTotal, cartsControlled: done,
145
+ deliveryOrderId: fr.length === 1 ? fr[0].deliveryOrderId : null,
146
+ autoStatus: auto?.status ?? null,
147
+ });
148
+ if (!salesOrderId)
149
+ blockers.push(`Order ${ref} heeft geen Floriday-verkooporder.`);
150
+ // "Gepickt" = alle karren goedgekeurd op de Scan-controle (logistics_control_scan.approved_at).
151
+ if (!cartsTotal)
152
+ blockers.push(`Order ${ref} heeft geen karindeling.`);
153
+ else if (!controlled)
154
+ blockers.push(`Order ${ref}: ${done} van ${cartsTotal} karren goedgekeurd op de Scan-controle.`);
155
+ // Bij een mislukt statusoverzicht geen gevolgfouten per order tonen.
156
+ if (!statusFailed) {
157
+ if (salesOrderId && !st)
158
+ blockers.push(`Order ${ref} staat niet in het statusoverzicht van Floriday.`);
159
+ if (st && !st.found)
160
+ blockers.push(`Order ${ref} is niet gevonden in Floriday.`);
161
+ if (st && st.found && fr.length !== 1)
162
+ blockers.push(`Order ${ref}: ${fr.length === 0 ? "geen" : "meerdere"} fulfillmentRequest in het statusoverzicht.`);
163
+ if (fr.length === 1 && !fr[0].deliveryOrderId)
164
+ blockers.push(`Order ${ref}: nog geen levering (deliveryOrderId) in het statusoverzicht.`);
165
+ }
166
+ if (auto && (AUTO_ALREADY_SENT.has(auto.status) || auto.fo))
167
+ blockers.push(`Order ${ref} is al via de oude auto-verwerking verstuurd (${auto.status}); niet nogmaals versturen.`);
168
+ }
169
+ const orderInfo = new Map([...coverage.keys()].map((id, i) => [id, orders[i]]));
170
+ const carts = new Map();
171
+ for (const [orderId, { ref, salesOrderId, cov }] of coverage) {
172
+ const st = salesOrderId ? status.get(salesOrderId) : undefined;
173
+ const frs = st?.fulfillmentRequests ?? [];
174
+ arr(cov.carts).forEach((k, ci) => {
175
+ const cartKey = String(k?.cartId ?? `${orderId}:${ci}`);
176
+ const c = carts.get(cartKey) ?? { label: String(k?.label ?? k?.cartNumber ?? ci + 1), shared: k?.shared === true, layers: num(k?.additionalLayers ?? k?.numberOfAdditionalLayers), lines: [] };
177
+ arr(k?.lines).forEach((l, li) => {
178
+ c.lines.push({
179
+ orderId, ref, so: salesOrderId,
180
+ key: String(l?.orderItemId ?? l?.lineId ?? l?.salesOrderLineId ?? l?.id ?? li),
181
+ packages: num(l?.crates),
182
+ frId: frs.length === 1 ? frs[0].fulfillmentRequestId : null,
183
+ dl: orderInfo.get(orderId)?.deliveryOrderId ?? null,
184
+ });
185
+ });
186
+ carts.set(cartKey, c);
187
+ });
188
+ }
189
+ const allLines = [...carts.values()].flatMap((c) => c.lines);
190
+ if (allLines.some((l) => !l.packages || l.packages <= 0))
191
+ blockers.push("Niet elke regel heeft een aantal fusten van de Engine.");
192
+ for (const [, c] of carts) {
193
+ if (new Set(c.lines.map((l) => l.dl ?? "")).size > 1)
194
+ blockers.push(`Kar ${c.label} bevat orders van verschillende leveringen; één kar kan maar in één opdracht.`);
195
+ }
196
+ // Opdrachten per levering. Eén levering → de vaste sleutel van de order of buffer.
197
+ const deliveries = [...new Set(orders.map((o) => o.deliveryOrderId ?? ""))];
198
+ const shipKey = (dl) => (deliveries.length <= 1 ? foKey : `${foKey}|${dl}`);
199
+ const [foIds, lcIds, itemIds] = await Promise.all([
200
+ ensureIds(supabase, "fulfillment_order", orderIds.length ? deliveries.map(shipKey) : []),
201
+ ensureIds(supabase, "load_carrier", [...carts.keys()]),
202
+ ensureIds(supabase, "load_carrier_item", [...carts].flatMap(([ck, c]) => c.lines.map((l) => `${ck}|${l.orderId}|${l.key}`))),
203
+ ]);
204
+ const carriers = [...carts].map(([ck, c], i) => ({
205
+ loadCarrierReference: lcIds.get(ck),
206
+ cartLabel: c.label,
207
+ sortIndex: i + 1,
208
+ additionalLayers: c.layers,
209
+ shared: c.shared || new Set(c.lines.map((l) => l.orderId)).size > 1,
210
+ items: c.lines.map((l, j) => ({
211
+ loadCarrierItemId: itemIds.get(`${ck}|${l.orderId}|${l.key}`),
212
+ orderRef: l.ref,
213
+ salesOrderId: l.so,
214
+ fulfillmentRequestId: l.frId,
215
+ numberOfPackages: l.packages ?? 0,
216
+ sortIndex: j + 1,
217
+ })),
218
+ }));
219
+ const cartDl = new Map([...carts].map(([ck, c]) => [lcIds.get(ck), c.lines[0]?.dl ?? ""]));
220
+ const shipments = orderIds.length ? deliveries.map((dl) => {
221
+ const os = orders.filter((o) => (o.deliveryOrderId ?? "") === dl);
222
+ return {
223
+ fulfillmentOrderId: foIds.get(shipKey(dl)),
224
+ deliveryOrderId: dl || null,
225
+ orderRefs: os.map((o) => o.orderRef),
226
+ salesOrderIds: os.map((o) => o.salesOrderId).filter((x) => !!x),
227
+ carriers: carriers.filter((c) => (cartDl.get(c.loadCarrierReference) ?? "") === dl),
228
+ ...(() => {
229
+ const fo = foIds.get(shipKey(dl));
230
+ const hit = os.flatMap((o) => (o.salesOrderId ? status.get(o.salesOrderId)?.fulfillmentOrders ?? [] : []))
231
+ .find((x) => x.fulfillmentOrderId === fo);
232
+ return { floridayStatus: hit?.status ?? null, deliveryNoteReady: hit?.deliveryNoteReady ?? null };
233
+ })(),
234
+ };
235
+ }) : [];
236
+ if (!statusFailed) {
237
+ for (const ref of new Set(allLines.filter((l) => !l.frId).map((l) => l.ref))) {
238
+ blockers.push(`Order ${ref}: nog geen fulfillmentRequestId van Floriday.`);
239
+ }
240
+ }
241
+ let lastAttempts = [];
242
+ if (shipments.length) {
243
+ const { data: at } = await supabase.from("floriday_loading_attempts")
244
+ .select("fulfillment_order_id, step, code, message, created_at")
245
+ .in("fulfillment_order_id", shipments.map((s) => s.fulfillmentOrderId))
246
+ .order("created_at", { ascending: false }).limit(10);
247
+ lastAttempts = (at ?? []).map((a) => ({
248
+ fulfillmentOrderId: a.fulfillment_order_id, step: a.step, code: a.code, message: a.message,
249
+ createdAt: a.created_at,
250
+ }));
251
+ }
252
+ const uniqBlockers = [...new Set(blockers)];
253
+ return {
254
+ fulfillmentOrderId: shipments[0]?.fulfillmentOrderId ?? null,
255
+ orderRefs: orders.map((o) => o.orderRef),
256
+ carriers,
257
+ cartCount: carriers.length,
258
+ lineCount: carriers.reduce((s2, c) => s2 + c.items.length, 0),
259
+ orders,
260
+ shipments,
261
+ lastAttempts,
262
+ blockers: uniqBlockers,
263
+ canSend: uniqBlockers.length === 0 && shipments.length > 0,
264
+ };
265
+ }
266
+ /** Stelt de belading samen en toont de controles. Verstuurt niets. */
267
+ export const prepareFloridayLoading = createServerFn({ method: "POST" })
268
+ .middleware([requireSupabaseAuth])
269
+ .inputValidator((d) => ({ orderRef: String(d?.orderRef ?? "").trim() }))
270
+ .handler(async ({ data, context }) => buildLoading(context.supabase, data.orderRef));
271
+ /**
272
+ * "Nu versturen": bouwt de belading opnieuw op (zelfde vaste kenmerken), controleert
273
+ * alles nogmaals op de server en verstuurt via fulfillment-order/send. Na acceptatie
274
+ * (created / already_fulfilled) volgt de verzendbrief via de Logistieke Engine. Elke poging komt in
275
+ * floriday_loading_attempts. Herhalen gebruikt altijd dezelfde fulfillmentOrderId.
276
+ */
277
+ export const sendFloridayLoading = createServerFn({ method: "POST" })
278
+ .middleware([requireSupabaseAuth])
279
+ .inputValidator((d) => ({ orderRef: String(d?.orderRef ?? "").trim() }))
280
+ .handler(async ({ data, context }) => {
281
+ const supabase = context.supabase;
282
+ const p = await buildLoading(supabase, data.orderRef);
283
+ if (!p.canSend)
284
+ throw new Error(`Niet verstuurd: ${p.blockers.join(" ") || "geen opdracht."}`);
285
+ const { sendFulfillmentOrder } = await import("./floridayFulfillmentSend.server");
286
+ const log = async (s, row) => {
287
+ const { error } = await supabase.from("floriday_loading_attempts").insert({
288
+ fulfillment_order_id: s.fulfillmentOrderId, delivery_order_id: s.deliveryOrderId,
289
+ sales_order_ids: s.salesOrderIds, order_refs: s.orderRefs, created_by: context.userId, ...row,
290
+ });
291
+ if (error)
292
+ console.warn("[belading] log mislukt", error.message);
293
+ };
294
+ const results = [];
295
+ for (const s of p.shipments) {
296
+ const payload = {
297
+ deliveryOrderId: s.deliveryOrderId,
298
+ fulfillmentOrderId: s.fulfillmentOrderId,
299
+ loadCarriers: s.carriers.map((c) => ({
300
+ loadCarrierReference: c.loadCarrierReference,
301
+ sortIndex: c.sortIndex,
302
+ // Floriday 2026v1 AddLoadCarrierConfiguration: alleen meesturen als de Engine het kent.
303
+ ...(c.additionalLayers != null ? { numberOfAdditionalLayers: c.additionalLayers } : {}),
304
+ items: c.items.map((it) => ({
305
+ fulfillmentRequestId: it.fulfillmentRequestId,
306
+ loadCarrierItemId: it.loadCarrierItemId,
307
+ numberOfPackages: it.numberOfPackages,
308
+ sortIndex: it.sortIndex,
309
+ })),
310
+ })),
311
+ };
312
+ const summary = { carts: s.carriers.length, lines: s.carriers.reduce((n, c) => n + c.items.length, 0) };
313
+ let httpStatus = null;
314
+ let body = null;
315
+ try {
316
+ const r = await sendFulfillmentOrder(payload);
317
+ httpStatus = r.httpStatus;
318
+ body = r.body;
319
+ }
320
+ catch (e) {
321
+ const msg = e instanceof Error ? e.message : String(e);
322
+ await log(s, { step: "send", code: "no_response", message: `Uitkomst onbekend: ${msg}. Opnieuw proberen gebruikt dezelfde opdracht.`, request_summary: summary });
323
+ results.push({ fulfillmentOrderId: s.fulfillmentOrderId, code: "no_response", httpStatus: null, message: msg, deliveryNote: "—" });
324
+ continue;
325
+ }
326
+ const code = String(body?.code ?? (httpStatus && httpStatus < 400 ? "ok" : `http_${httpStatus}`));
327
+ const accepted = httpStatus === 200 && body?.ok === true && ACCEPTED.has(code);
328
+ const message = accepted ? (code === "created" ? "Belading verstuurd, verzendbrief volgt via de Engine." : "Belading was al verstuurd (niets dubbel aangemaakt), verzendbrief volgt via de Engine.")
329
+ : arr(body?.errors).map((e) => (typeof e === "string" ? e : e?.message ?? JSON.stringify(e))).join("; ") || body?.message || code;
330
+ await log(s, {
331
+ step: "send", http_status: httpStatus, code, message,
332
+ warnings: arr(body?.warnings), skipped_requests: arr(body?.skippedRequests), request_summary: summary,
333
+ });
334
+ // Verzendbrief: eigendom van de Logistieke Engine (runPdf delivery-note + herhalingen).
335
+ const deliveryNote = accepted ? "volgt via de Engine" : "—";
336
+ results.push({ fulfillmentOrderId: s.fulfillmentOrderId, code, httpStatus, message, deliveryNote });
337
+ }
338
+ return { ok: results.every((r) => ACCEPTED.has(r.code)), results };
339
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"orderFulfilment.functions.d.ts","sourceRoot":"","sources":["../../src/lib/orderFulfilment.functions.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;8CAEH,qBAAqB;;mCAsB3C,CAAC"}
1
+ {"version":3,"file":"orderFulfilment.functions.d.ts","sourceRoot":"","sources":["../../src/lib/orderFulfilment.functions.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;8CAEH,qBAAqB;;mCAoC3C,CAAC"}
@@ -17,6 +17,23 @@ export const markOrderShipped = createServerFn({ method: "POST" })
17
17
  })
18
18
  .handler(async ({ data, context }) => {
19
19
  const { supabase } = context;
20
+ // Floriday-orders: "Verzonden" pas nadat Floriday de belading heeft geaccepteerd.
21
+ const { data: ord, error: oErr } = await supabase
22
+ .from("orders").select("id, order_source").eq("order_number", data.orderRef).is("deleted_at", null).maybeSingle();
23
+ if (oErr)
24
+ throw new Error(oErr.message);
25
+ if (!ord)
26
+ throw new Error(`Bestelling ${data.orderRef} niet gevonden in de orderadministratie.`);
27
+ if (ord.order_source === "floriday") {
28
+ const { data: acc, error: aErr } = await supabase
29
+ .from("floriday_loading_attempts").select("id")
30
+ .contains("order_refs", [data.orderRef]).in("code", ["created", "already_fulfilled"]).limit(1);
31
+ if (aErr)
32
+ throw new Error(aErr.message);
33
+ if (!acc?.length) {
34
+ throw new Error(`${data.orderRef}: nog niet door Floriday geaccepteerd. Verstuur eerst de belading met "Nu versturen".`);
35
+ }
36
+ }
20
37
  const { data: rows, error } = await supabase
21
38
  .from("orders")
22
39
  .update({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/floriday-afhandeling-module",
3
- "version": "1.0.48",
3
+ "version": "1.0.52",
4
4
  "private": false,
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -49,7 +49,7 @@
49
49
  "@cloudflare/vite-plugin": "^1.25.5",
50
50
  "@eslint/js": "^9.32.0",
51
51
  "@flowselections/core": "1.0.29",
52
- "@lovable.dev/vite-tanstack-config": "2.23.1",
52
+ "@lovable.dev/vite-tanstack-config": "2.25.3",
53
53
  "@rsbuild/core": "^1.0.0",
54
54
  "@tailwindcss/vite": "^4.2.1",
55
55
  "@tanstack/react-query": "^5.83.0",