@flowselections/floriday-verkoop-module 1.0.74 → 1.0.76

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 (32) hide show
  1. package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts.map +1 -1
  2. package/dist-lib/components/verkoop/OrderKarindelingCard.js +36 -114
  3. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts +6 -0
  4. package/dist-lib/components/verkoop/PlanCoverageBadge.d.ts.map +1 -0
  5. package/dist-lib/components/verkoop/PlanCoverageBadge.js +23 -0
  6. package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
  7. package/dist-lib/components/verkoop/SalesOrderDetailView.js +2 -1
  8. package/dist-lib/components/verkoop/SalesOrdersTable.d.ts.map +1 -1
  9. package/dist-lib/components/verkoop/SalesOrdersTable.js +2 -1
  10. package/dist-lib/integrations/supabase/types.d.ts +483 -3
  11. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  12. package/dist-lib/lib/cart-replan.functions.d.ts +2 -22
  13. package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -1
  14. package/dist-lib/lib/cart-replan.functions.js +10 -163
  15. package/dist-lib/lib/create-order.functions.d.ts +0 -57
  16. package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
  17. package/dist-lib/lib/create-order.functions.js +1 -205
  18. package/dist-lib/lib/logistics-engine.server.d.ts.map +1 -1
  19. package/dist-lib/lib/logistics-engine.server.js +8 -3
  20. package/dist-lib/lib/plan-coverage.d.ts +56 -0
  21. package/dist-lib/lib/plan-coverage.d.ts.map +1 -0
  22. package/dist-lib/lib/plan-coverage.js +120 -0
  23. package/dist-lib/lib/plan-coverage.server.d.ts +3 -0
  24. package/dist-lib/lib/plan-coverage.server.d.ts.map +1 -0
  25. package/dist-lib/lib/plan-coverage.server.js +97 -0
  26. package/dist-lib/lib/salesorders-list.server.d.ts.map +1 -1
  27. package/dist-lib/lib/salesorders-list.server.js +43 -82
  28. package/dist-lib/lib/salesorders-mapping.d.ts +5 -0
  29. package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
  30. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
  31. package/dist-lib/lib/salesorders.functions.js +21 -18
  32. package/package.json +1 -1
@@ -70,35 +70,15 @@ export declare function drainCartReplanQueue(_limit?: number): Promise<{
70
70
  error?: string;
71
71
  }>;
72
72
  }>;
73
- export declare const listOrderCarts: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
73
+ export declare const getOrderPlanCoverage: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
74
74
  supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
75
75
  userId: string;
76
76
  claims: import("@supabase/auth-js").User;
77
77
  }, undefined, undefined, undefined>], (input: unknown) => {
78
78
  orderId: string;
79
79
  }, Promise<{
80
- carts: any[];
81
- bufferId: string | null;
82
80
  orderId: string;
83
- planLockedAt: string | null;
84
- orders: {
85
- id: string;
86
- order_number: string | null;
87
- }[];
88
- itemOrders: {
89
- id: string;
90
- order_id: string;
91
- }[];
92
- blocked: {
93
- reason: string | null;
94
- explanation: string | null;
95
- at: string | null;
96
- } | null;
97
- planState: {
98
- status: string;
99
- reason: string | null;
100
- at: string | null;
101
- } | null;
81
+ coverage: import("./plan-coverage").PlanCoverage;
102
82
  }>>;
103
83
  export declare const replanBufferForOrder: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
104
84
  supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
@@ -1 +1 @@
1
- {"version":3,"file":"cart-replan.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cart-replan.functions.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,sBAAsB,CAAC;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM;QAYrD,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAlBnB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GAAG,OAAO,CAAC;IACV,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC,CAoaD;AA4BD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM;QAzBxD,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAoBnB;AAED,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;QA/B3B,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GA6BhB,CAAC;AAML,wBAAsB,oBAAoB,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC;IAC/D,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE,CAAC,CAED;AAQD,eAAO,MAAM,cAAc;;;;8CAED,OAAO;;;;;;;;YAuDL,MAAM;sBAAgB,MAAM,GAAG,IAAI;;;YAkB/B,MAAM;kBAAY,MAAM;;;gBAe7B,MAAM,GAAG,IAAI;qBAAe,MAAM,GAAG,IAAI;YAAM,MAAM,GAAG,IAAI;;;gBAqD1D,MAAM;gBAAU,MAAM,GAAG,IAAI;YAAM,MAAM,GAAG,IAAI;;GA6BzE,CAAC;AAIL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;QA3pB3B,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAypBhB,CAAC"}
1
+ {"version":3,"file":"cart-replan.functions.d.ts","sourceRoot":"","sources":["../../src/lib/cart-replan.functions.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,sBAAsB,CAAC;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM;QAYrD,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAlBnB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GAAG,OAAO,CAAC;IACV,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC,CAoaD;AA4BD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM;QAzBxD,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAoBnB;AAED,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;QA/B3B,OAAO;aACF,MAAM;kBACD,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GA6BhB,CAAC;AAML,wBAAsB,oBAAoB,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC;IAC/D,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE,CAAC,CAED;AAMD,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;;;GAU7B,CAAC;AAEL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;QAvf3B,OAAO;cACD,MAAM,GAAG,IAAI;cACb,MAAM,EAAE;kBACJ,MAAM;yBACC,MAAM;yBACN,OAAO;cAClB,MAAM,EAAE;kBACJ,WAAW,EAAE;cACjB,QAAQ;GAqfhB,CAAC"}
@@ -399,173 +399,20 @@ export async function drainCartReplanQueue(_limit = 50) {
399
399
  return { ok: true, processed: 0, failed: 0, results: [] };
400
400
  }
401
401
  // ─── Lezen — voor de UI ─────────────────────────────────────────────────────
402
- // Retourneert alle karren van de buffer waarin de order valt, zodat karren
403
- // die items van meerdere orders bevatten volledig zichtbaar zijn.
404
- // Levert ook de order-context (nummers per orderregel) en, als er geen karren
405
- // zijn, de laatste blokkadereden uit de engine (logistics_decisions /
406
- // logistics_plan_queue). De UI berekent NIETS zelf: hij toont wat er staat.
407
- export const listOrderCarts = createServerFn({ method: "GET" })
402
+ // De karindeling van een order komt uitsluitend uit de Logistiek Engine
403
+ // (logistics_order_plan_coverage). Deze module leest order_carts/
404
+ // order_cart_items niet zelf. Fail closed: bij een fout "Indeling onbekend".
405
+ export const getOrderPlanCoverage = createServerFn({ method: "GET" })
408
406
  .middleware([requireSupabaseAuth])
409
407
  .inputValidator((input) => z.object({ orderId: z.string().min(1) }).parse(input))
410
408
  .handler(async ({ data, context }) => {
411
- // Elke query faalt HARD. "Geen karren" en "kon niet laden" zijn twee
412
- // verschillende dingen; stilzwijgend een lege array teruggeven verbergt
413
- // fouten (RLS, kolomnaam, embed) als "nog geen karindeling".
414
- const fail = (what, error) => {
415
- throw new Error(`Karindeling laden mislukt (${what}): ${error?.message ?? "onbekende fout"}`);
416
- };
417
- // De DTO-id is voor Floriday-orders het salesOrderId, niet orders.id.
418
- // resolveOrderRow doet de twee-staps-lookup + botsingswaarschuwing.
419
409
  const orderRow = await resolveOrderRow(context.supabase, data.orderId);
420
- const dbOrderId = orderRow.id;
421
- const bufferId = orderRow.buffer_id;
422
- const lockRes = await context.supabase
423
- .from("orders")
424
- .select("plan_locked_at")
425
- .eq("id", dbOrderId)
426
- .maybeSingle();
427
- if (lockRes.error)
428
- fail("plan-lock lezen", lockRes.error);
429
- const planLockedAt = lockRes.data?.plan_locked_at ?? null;
430
- const select = "id, order_id, buffer_id, cart_number, source, is_complete, occupancy_pct, total_layers_used, algorithm_version, carrier_type, max_layers, notes, order_cart_items(id, order_item_id, product_id, product_name, crates, plants_per_crate, crates_per_layer, layers_per_cart, layer_fraction, layer_share_pct)";
431
- const readCarts = async () => {
432
- const base = context.supabase.from("order_carts").select(select);
433
- const res = await (bufferId
434
- ? base.eq("buffer_id", bufferId)
435
- : base.eq("order_id", dbOrderId)).order("cart_number");
436
- if (res.error)
437
- fail("karren lezen", res.error);
438
- return (res.data ?? []);
439
- };
440
- let carts = await readCarts();
441
- // Terugval via de karregels: gedeelde karren hebben order_id = NULL.
442
- if (carts.length === 0) {
443
- const { loadCartsByOrder } = await import("./order-cart-count.server");
444
- const ids = (await loadCartsByOrder(context.supabase, [dbOrderId])).get(dbOrderId)?.cartIds ?? [];
445
- if (ids.length) {
446
- const res = await context.supabase.from("order_carts").select(select).in("id", ids).order("cart_number");
447
- if (res.error)
448
- fail("karren lezen", res.error);
449
- carts = (res.data ?? []);
450
- }
451
- }
452
- // Lezen blijft lezen: is er nog geen indeling, dan wordt die door de
453
- // Logistiek Engine gemaakt in haar eigen minuut-ronde.
454
- const autoPlanError = null;
455
- // Orders in de scope + ordernummer per orderregel (voor de badges).
456
- let orders = [];
457
- if (bufferId) {
458
- const sibs = await context.supabase
459
- .from("orders")
460
- .select("id, order_number")
461
- .eq("buffer_id", bufferId)
462
- .is("deleted_at", null);
463
- if (sibs.error)
464
- fail("orders in buffer lezen", sibs.error);
465
- orders = (sibs.data ?? []).map((o) => ({
466
- id: o.id,
467
- order_number: o.order_number ?? null,
468
- }));
469
- }
470
- if (orders.length === 0) {
471
- orders = [{ id: dbOrderId, order_number: orderRow.order_number ?? null }];
472
- }
473
- const orderIds = orders.map((o) => o.id);
474
- let itemOrders = [];
475
- if (orderIds.length > 0) {
476
- const its = await context.supabase
477
- .from("order_items")
478
- .select("id, order_id")
479
- .in("order_id", orderIds)
480
- .is("quarantined_at", null);
481
- if (its.error)
482
- fail("orderregels lezen", its.error);
483
- itemOrders = (its.data ?? []).map((i) => ({
484
- id: i.id,
485
- order_id: i.order_id,
486
- }));
487
- }
488
- // Blokkadereden alleen ophalen als er — ook na het direct plannen — niets staat.
489
- let blocked = null;
490
- if (carts.length === 0 && autoPlanError) {
491
- blocked = {
492
- reason: "planningsfout",
493
- explanation: `De karindeling kon niet worden berekend: ${autoPlanError}`,
494
- at: new Date().toISOString(),
495
- };
496
- }
497
- if (!blocked && carts.length === 0 && orderIds.length > 0) {
498
- const dec = await context.supabase
499
- .from("logistics_decisions")
500
- .select("subject_id, slot, explanation, result, created_at")
501
- .in("subject_id", orderIds)
502
- .order("created_at", { ascending: false })
503
- .limit(1);
504
- if (dec.error)
505
- fail("blokkadereden lezen", dec.error);
506
- const d = (dec.data ?? [])[0];
507
- if (d) {
508
- blocked = {
509
- reason: d.result?.reason ?? d.slot ?? null,
510
- explanation: d.explanation ?? null,
511
- at: d.created_at ?? null,
512
- };
513
- }
514
- if (!blocked) {
515
- const q = await context.supabase
516
- .from("logistics_plan_queue")
517
- .select("order_id, status, reason, error, updated_at")
518
- .in("order_id", orderIds)
519
- .order("updated_at", { ascending: false })
520
- .limit(1);
521
- if (q.error)
522
- fail("planqueue lezen", q.error);
523
- const r = (q.data ?? [])[0];
524
- // `reason` is de AANLEIDING van de herplanning ("items", "UPDATE"),
525
- // geen blokkade. Alleen een echte fout is nog een blokkade: een
526
- // wachtende wachtrijregel hebben we hierboven zelf al ingehaald.
527
- const status = (r?.status ?? "").toLowerCase();
528
- const err = r?.error ?? null;
529
- if (r && (err || status === "failed" || status === "error")) {
530
- blocked = {
531
- reason: err ? "planningsfout" : status,
532
- explanation: err ?? "De karrenplanning is mislukt. Probeer opnieuw te plannen.",
533
- at: r.updated_at ?? null,
534
- };
535
- }
536
- }
537
- }
538
- // Werkelijke stand bij de planwachtrij: zo ziet de gebruiker of de order
539
- // is aangemeld en nog wacht, of dat er niets klaarstaat.
540
- let planState = null;
541
- if (carts.length === 0 && orderIds.length > 0) {
542
- const ps = await context.supabase
543
- .from("logistics_plan_queue")
544
- .select("status, reason, updated_at")
545
- .in("order_id", orderIds)
546
- .order("updated_at", { ascending: false })
547
- .limit(1);
548
- if (ps.error)
549
- fail("planstand lezen", ps.error);
550
- const row = (ps.data ?? [])[0];
551
- if (row) {
552
- planState = {
553
- status: String(row.status ?? ""),
554
- reason: row.reason ?? null,
555
- at: row.updated_at ?? null,
556
- };
557
- }
558
- }
559
- return {
560
- carts,
561
- bufferId,
562
- orderId: dbOrderId,
563
- planLockedAt,
564
- orders,
565
- itemOrders,
566
- blocked,
567
- planState,
568
- };
410
+ const dbOrderId = String(orderRow.id);
411
+ const { loadPlanCoverage } = await import("./plan-coverage.server");
412
+ const { unknownCoverage } = await import("./plan-coverage");
413
+ const cov = (await loadPlanCoverage(context.supabase, [dbOrderId])).get(dbOrderId) ??
414
+ unknownCoverage("Geen antwoord van de Engine");
415
+ return { orderId: dbOrderId, coverage: cov };
569
416
  });
570
417
  export const replanBufferForOrder = createServerFn({ method: "POST" })
571
418
  .middleware([requireSupabaseAuth])
@@ -186,63 +186,6 @@ export declare const deleteMailboxProposal: import("@tanstack/start-client-core"
186
186
  }, Promise<{
187
187
  ok: true;
188
188
  }>>;
189
- export declare const planAndSaveAutoCarts: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
190
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
191
- userId: string;
192
- claims: import("@supabase/auth-js").User;
193
- }, undefined, undefined, undefined>], (input: unknown) => {
194
- orderId: string;
195
- }, Promise<{
196
- ok: true;
197
- autoCarts: {
198
- cart_number: number;
199
- product_name: string;
200
- crates: number;
201
- plants: number;
202
- capacity: number;
203
- }[];
204
- remainders: {
205
- crates_remaining: number;
206
- order_item_id: string;
207
- product_id: string | null;
208
- product_name: string;
209
- plants_per_crate: number;
210
- crates_per_layer: number;
211
- layers_per_cart: number;
212
- }[];
213
- existingManualCarts: {
214
- cart_number: number;
215
- notes: string | null;
216
- items: any;
217
- }[];
218
- nextCartNumber: number;
219
- blockedLines: {
220
- order_item_id: string;
221
- product_name: string;
222
- missing: string[];
223
- }[];
224
- }>>;
225
- export declare const saveManualCarts: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
226
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
227
- userId: string;
228
- claims: import("@supabase/auth-js").User;
229
- }, undefined, undefined, undefined>], (input: unknown) => {
230
- orderId: string;
231
- carts: {
232
- items: {
233
- order_item_id: string | null;
234
- product_id: string | null;
235
- product_name: string;
236
- crates: number;
237
- plants_per_crate: number;
238
- crates_per_layer: number;
239
- }[];
240
- is_complete?: boolean | undefined;
241
- notes?: string | null | undefined;
242
- }[];
243
- }, Promise<{
244
- ok: true;
245
- }>>;
246
189
  export declare const getLocalOrderForEdit: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
247
190
  supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
248
191
  userId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"create-order.functions.d.ts","sourceRoot":"","sources":["../../src/lib/create-order.functions.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,2BAA2B;;;;;;GA+CpC,CAAC;AAIL,eAAO,MAAM,2BAA2B;;;;0CAElB,OAAO;;;;GAoDzB,CAAC;AAWL,eAAO,MAAM,0BAA0B;;;;;;YA+D7B,MAAM;iBACD,MAAM;sBACD,MAAM,GAAG,IAAI;cACrB,MAAM;oBACA,MAAM,GAAG,IAAI;0BACP,MAAM;0BACN,MAAM;yBACP,MAAM;wBACP,MAAM;wBACN,MAAM;yBACL,MAAM;kBACb,OAAO;gBACT,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS;;GA6RpD,CAAC;AAGL,eAAO,MAAM,kCAAkC;;;;0CAEzB,OAAO;;;;;;;;;;;;;;;;;;;;;;GAkDzB,CAAC;AAKL,eAAO,MAAM,qBAAqB;;;;;;YAoBI,MAAM;;;GAIxC,CAAC;AAGL,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;GAWnC,CAAC;AASL,eAAO,MAAM,8BAA8B;;;;8CAEjB,OAAO;;;;GAU7B,CAAC;AASL,eAAO,MAAM,mBAAmB;;;;;;;;0BAgBuB,MAAM;0BAAoB,MAAM;yBAAmB,MAAM;;;GA8C5G,CAAC;AAGL,eAAO,MAAM,kBAAkB;;;;;;GAU3B,CAAC;AA2CL,eAAO,MAAM,iBAAiB;;;;8CAEJ,OAAO;;;;;;;;;;;;;;;;;;;;;;;aA+OY,MAAM;GAE/C,CAAC;AAKL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;GAY7B,CAAC;AAQL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;GAoG7B,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;8CAER,OAAO;;;;GAyB7B,CAAC;AAeL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;;;qBAmBS,MAAM;sBAAgB,MAAM;gBAAU,MAAM;gBAAU,MAAM;kBAAY,MAAM;;;;uBA9BvG,MAAM;oBACT,MAAM,GAAG,IAAI;sBACX,MAAM;0BAEF,MAAM;0BACN,MAAM;yBACP,MAAM;;;qBA2GW,MAAM;eAClB,MAAM,GAAG,IAAI;;;;;uBAlFU,MAAM;sBAAgB,MAAM;iBAAW,MAAM,EAAE;;GAgI1F,CAAC;AAgBL,eAAO,MAAM,eAAe;;;;8CAEF,OAAO;;;;;;;;;;;;;;;;GAyC7B,CAAC;AAuCL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;aAgKG,MAAM;iBACQ,MAAM,GAAG,IAAI;kBACX,MAAM;;YAEnB,MAAM,GAAG,IAAI;;;;YAkB7B,MAAM;mBACS,MAAM,GAAG,IAAI;qBACT,MAAM;;cAErB,MAAM,GAAG,IAAI;;;;;;GAQpC,CAAC;AAIL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;;;;;;;;;;;;;;GAoN7B,CAAC"}
1
+ {"version":3,"file":"create-order.functions.d.ts","sourceRoot":"","sources":["../../src/lib/create-order.functions.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,2BAA2B;;;;;;GA+CpC,CAAC;AAIL,eAAO,MAAM,2BAA2B;;;;0CAElB,OAAO;;;;GAoDzB,CAAC;AAWL,eAAO,MAAM,0BAA0B;;;;;;YA+D7B,MAAM;iBACD,MAAM;sBACD,MAAM,GAAG,IAAI;cACrB,MAAM;oBACA,MAAM,GAAG,IAAI;0BACP,MAAM;0BACN,MAAM;yBACP,MAAM;wBACP,MAAM;wBACN,MAAM;yBACL,MAAM;kBACb,OAAO;gBACT,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS;;GA6RpD,CAAC;AAGL,eAAO,MAAM,kCAAkC;;;;0CAEzB,OAAO;;;;;;;;;;;;;;;;;;;;;;GAkDzB,CAAC;AAKL,eAAO,MAAM,qBAAqB;;;;;;YAoBI,MAAM;;;GAIxC,CAAC;AAGL,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;GAWnC,CAAC;AASL,eAAO,MAAM,8BAA8B;;;;8CAEjB,OAAO;;;;GAU7B,CAAC;AASL,eAAO,MAAM,mBAAmB;;;;;;;;0BAgBuB,MAAM;0BAAoB,MAAM;yBAAmB,MAAM;;;GA8C5G,CAAC;AAGL,eAAO,MAAM,kBAAkB;;;;;;GAU3B,CAAC;AA2CL,eAAO,MAAM,iBAAiB;;;;8CAEJ,OAAO;;;;;;;;;;;;;;;;;;;;;;;aA+OY,MAAM;GAE/C,CAAC;AAKL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;GAY7B,CAAC;AAQL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;GAoG7B,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;8CAER,OAAO;;;;GAyB7B,CAAC;AAyCL,eAAO,MAAM,oBAAoB;;;;8CAEP,OAAO;;;aAgKG,MAAM;iBACQ,MAAM,GAAG,IAAI;kBACX,MAAM;;YAEnB,MAAM,GAAG,IAAI;;;;YAkB7B,MAAM;mBACS,MAAM,GAAG,IAAI;qBACT,MAAM;;cAErB,MAAM,GAAG,IAAI;;;;;;GAQpC,CAAC;AAIL,eAAO,MAAM,gBAAgB;;;;8CAEH,OAAO;;;;;;;;;;;;;;;;;;;;GAoN7B,CAAC"}
@@ -5,7 +5,6 @@ import { createServerFn } from "@tanstack/react-start";
5
5
  import { productNameForStorage } from "./product-name";
6
6
  import { z } from "zod";
7
7
  import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
8
- import { CART_PLANNER_VERSION } from "./cart-planner";
9
8
  // ─── Klanten ────────────────────────────────────────────────────────────────
10
9
  // Bron 1: lokale `customers` (incl. eerder geïmporteerde Twinfield-klanten).
11
10
  // Bron 2: `twinfield_customers_cache` — klanten die alleen in Twinfield staan.
@@ -727,7 +726,7 @@ export const createManualOrder = createServerFn({ method: "POST" })
727
726
  const { supabaseAdmin } = await import("../integrations/supabase/client.server");
728
727
  // Zorg dat elk product_id (= identiteit uit de voorraadmodule) een rij
729
728
  // in `products` heeft — de order_items FK vereist dit én de karindeling
730
- // (planAndSaveAutoCarts) joined op products voor de packing-waarden.
729
+ // van de Engine joined op products voor de packing-waarden.
731
730
  //
732
731
  // BELANGRIJK: de wizard geeft als product_id een identiteit terug die uit
733
732
  // 1 van 4 bronnen komt: floriday_trade_items_cache.floriday_id,
@@ -1035,209 +1034,6 @@ export const deleteMailboxProposal = createServerFn({ method: "POST" })
1035
1034
  throw new Error(`Voorstel verwijderen faalde: ${dErr.message}`);
1036
1035
  return { ok: true };
1037
1036
  });
1038
- export const planAndSaveAutoCarts = createServerFn({ method: "POST" })
1039
- .middleware([requireSupabaseAuth])
1040
- .inputValidator((input) => z.object({ orderId: z.string().uuid() }).parse(input))
1041
- .handler(async ({ data, context }) => {
1042
- const { data: items, error: itErr } = await context.supabase
1043
- .from("order_items")
1044
- .select("id, product_id, product_name, quantity, products(plants_per_crate, crates_per_layer, layers_per_cart)")
1045
- .eq("order_id", data.orderId)
1046
- .is("quarantined_at", null);
1047
- if (itErr)
1048
- throw new Error(itErr.message);
1049
- const { supabaseAdmin } = await import("../integrations/supabase/client.server");
1050
- await supabaseAdmin.from("order_carts").delete().eq("order_id", data.orderId).eq("is_auto", true);
1051
- let cartNumber = 1;
1052
- const { data: existingMax } = await supabaseAdmin
1053
- .from("order_carts").select("cart_number").eq("order_id", data.orderId)
1054
- .order("cart_number", { ascending: false }).limit(1);
1055
- if (existingMax && existingMax[0])
1056
- cartNumber = existingMax[0].cart_number + 1;
1057
- const autoCarts = [];
1058
- const remainders = [];
1059
- const blockedLines = [];
1060
- for (const it of items ?? []) {
1061
- const prod = it.products ?? {};
1062
- // Onbekend blijft onbekend: geen terugval op 1 (1x1x1 = 1 plant per kar).
1063
- const pos = (v) => {
1064
- if (v === null || v === undefined)
1065
- return null;
1066
- const n = Math.round(Number(v));
1067
- return Number.isFinite(n) && n > 0 ? n : null;
1068
- };
1069
- const ppc = pos(prod.plants_per_crate);
1070
- const cpl = pos(prod.crates_per_layer);
1071
- const lpc = pos(prod.layers_per_cart);
1072
- if (ppc === null || cpl === null || lpc === null) {
1073
- blockedLines.push({
1074
- order_item_id: it.id,
1075
- product_name: it.product_name,
1076
- missing: [
1077
- ppc === null ? "plants_per_crate" : null,
1078
- cpl === null ? "crates_per_layer" : null,
1079
- lpc === null ? "layers_per_cart" : null,
1080
- ].filter((m) => m !== null),
1081
- });
1082
- continue;
1083
- }
1084
- const cratesPerCart = cpl * lpc;
1085
- const totalPlants = Math.max(0, Number(it.quantity ?? 0));
1086
- const totalCrates = Math.ceil(totalPlants / ppc);
1087
- const fullCarts = Math.floor(totalCrates / cratesPerCart);
1088
- const remainder = totalCrates - fullCarts * cratesPerCart;
1089
- for (let i = 0; i < fullCarts; i++) {
1090
- const { data: cart, error: cErr } = await supabaseAdmin
1091
- .from("order_carts").insert({
1092
- order_id: data.orderId,
1093
- cart_number: cartNumber,
1094
- is_auto: true,
1095
- is_complete: true,
1096
- // Expliciet zetten: nooit op de kolom-default leunen.
1097
- source: "auto",
1098
- algorithm_version: CART_PLANNER_VERSION,
1099
- }).select("id").single();
1100
- if (cErr)
1101
- throw new Error(cErr.message);
1102
- await supabaseAdmin.from("order_cart_items").insert({
1103
- cart_id: cart.id,
1104
- order_item_id: it.id,
1105
- product_id: it.product_id,
1106
- product_name: it.product_name,
1107
- crates: cratesPerCart,
1108
- plants_per_crate: ppc,
1109
- crates_per_layer: cpl,
1110
- });
1111
- autoCarts.push({
1112
- cart_number: cartNumber,
1113
- product_name: it.product_name,
1114
- crates: cratesPerCart,
1115
- plants: cratesPerCart * ppc,
1116
- capacity: cratesPerCart,
1117
- });
1118
- cartNumber++;
1119
- }
1120
- if (remainder > 0) {
1121
- remainders.push({
1122
- order_item_id: it.id,
1123
- product_id: it.product_id,
1124
- product_name: it.product_name,
1125
- crates_remaining: remainder,
1126
- plants_per_crate: ppc,
1127
- crates_per_layer: cpl,
1128
- layers_per_cart: lpc,
1129
- });
1130
- }
1131
- }
1132
- const { data: manualCartsRaw } = await supabaseAdmin
1133
- .from("order_carts")
1134
- .select("id, cart_number, notes, order_cart_items(order_item_id, product_id, product_name, crates, plants_per_crate, crates_per_layer)")
1135
- .eq("order_id", data.orderId).eq("is_auto", false)
1136
- .order("cart_number");
1137
- const existingManualCarts = (manualCartsRaw ?? []).map((c) => ({
1138
- cart_number: c.cart_number,
1139
- notes: c.notes,
1140
- items: (c.order_cart_items ?? []).map((i) => ({
1141
- order_item_id: i.order_item_id,
1142
- product_id: i.product_id,
1143
- product_name: i.product_name,
1144
- crates: Number(i.crates ?? 0),
1145
- plants_per_crate: Number(i.plants_per_crate ?? 1),
1146
- crates_per_layer: Number(i.crates_per_layer ?? 1),
1147
- })),
1148
- }));
1149
- const assignedByItem = {};
1150
- existingManualCarts.forEach((c) => c.items.forEach((i) => {
1151
- if (!i.order_item_id)
1152
- return;
1153
- assignedByItem[i.order_item_id] = (assignedByItem[i.order_item_id] ?? 0) + Number(i.crates ?? 0);
1154
- }));
1155
- const adjustedRemainders = remainders
1156
- .map((r) => ({ ...r, crates_remaining: Math.max(0, r.crates_remaining - (assignedByItem[r.order_item_id] ?? 0)) }))
1157
- .filter((r) => r.crates_remaining > 0);
1158
- if (blockedLines.length > 0) {
1159
- const { error: blockErr } = await supabaseAdmin.rpc("logistics_plan_block", {
1160
- p_order_ids: [data.orderId],
1161
- p_reason: "belading_onbekend",
1162
- p_details: { source: "floriday-verkoop-module/planAndSaveAutoCarts", items: blockedLines },
1163
- });
1164
- if (blockErr) {
1165
- console.warn("[karindeling] blokkade niet vastgelegd:", blockErr.message, blockedLines);
1166
- }
1167
- // Eenmalige mailmelding naar het interne adres uit de e-mailmodule.
1168
- const { notifyOrderBlocked } = await import("./order-block-mail.server");
1169
- const mail = await notifyOrderBlocked({
1170
- orderIds: [data.orderId],
1171
- reasonKey: "belading_onbekend",
1172
- reason: "Karindeling geblokkeerd: orderregel(s) zonder volledige belading.",
1173
- details: { items: blockedLines },
1174
- });
1175
- for (const w of mail.warnings)
1176
- console.warn("[karindeling]", w);
1177
- }
1178
- return {
1179
- ok: true,
1180
- autoCarts,
1181
- remainders: adjustedRemainders,
1182
- existingManualCarts,
1183
- nextCartNumber: cartNumber,
1184
- blockedLines,
1185
- };
1186
- });
1187
- const ManualCartItemSchema = z.object({
1188
- order_item_id: z.string().uuid().nullable(),
1189
- product_id: z.string().uuid().nullable(),
1190
- product_name: z.string().min(1).max(255),
1191
- crates: z.number().int().min(1),
1192
- plants_per_crate: z.number().int().min(1),
1193
- crates_per_layer: z.number().int().min(1),
1194
- });
1195
- const ManualCartSchema = z.object({
1196
- is_complete: z.boolean().optional(),
1197
- notes: z.string().max(500).nullable().optional(),
1198
- items: z.array(ManualCartItemSchema).min(1),
1199
- });
1200
- export const saveManualCarts = createServerFn({ method: "POST" })
1201
- .middleware([requireSupabaseAuth])
1202
- .inputValidator((input) => z.object({ orderId: z.string().uuid(), carts: z.array(ManualCartSchema) }).parse(input))
1203
- .handler(async ({ data }) => {
1204
- const { supabaseAdmin } = await import("../integrations/supabase/client.server");
1205
- await supabaseAdmin.from("order_carts").delete()
1206
- .eq("order_id", data.orderId).eq("is_auto", false);
1207
- const { data: existingMax } = await supabaseAdmin
1208
- .from("order_carts").select("cart_number").eq("order_id", data.orderId)
1209
- .order("cart_number", { ascending: false }).limit(1);
1210
- let cartNumber = existingMax && existingMax[0] ? existingMax[0].cart_number + 1 : 1;
1211
- for (const cart of data.carts) {
1212
- const { data: inserted, error: cErr } = await supabaseAdmin
1213
- .from("order_carts").insert({
1214
- order_id: data.orderId,
1215
- cart_number: cartNumber,
1216
- is_auto: false,
1217
- is_complete: !!cart.is_complete,
1218
- notes: cart.notes ?? null,
1219
- // Expliciet zetten: nooit op de kolom-default leunen.
1220
- source: "manual",
1221
- algorithm_version: CART_PLANNER_VERSION,
1222
- }).select("id").single();
1223
- if (cErr)
1224
- throw new Error(cErr.message);
1225
- const rows = cart.items.map((i) => ({
1226
- cart_id: inserted.id,
1227
- order_item_id: i.order_item_id,
1228
- product_id: i.product_id,
1229
- product_name: i.product_name,
1230
- crates: i.crates,
1231
- plants_per_crate: i.plants_per_crate,
1232
- crates_per_layer: i.crates_per_layer,
1233
- }));
1234
- const { error: iErr } = await supabaseAdmin.from("order_cart_items").insert(rows);
1235
- if (iErr)
1236
- throw new Error(iErr.message);
1237
- cartNumber++;
1238
- }
1239
- return { ok: true };
1240
- });
1241
1037
  // ─── Lokale bestelling bewerken (aantal + leverdatum) ─────────────────────
1242
1038
  // Alleen voor lokale/handmatige bestellingen. FO-orders worden geweigerd.
1243
1039
  // Stock (reserved) en karindeling worden automatisch bijgewerkt door
@@ -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,CAoEpC;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,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"}
@@ -23,9 +23,14 @@ export async function buildEngineOrderPayload(orderId) {
23
23
  return null;
24
24
  const o = order;
25
25
  const cf = (o.custom_fields ?? {});
26
- // Via de karregels: gedeelde bufferkarren hebben order_id = NULL.
27
- const { loadCartsByOrder } = await import("./order-cart-count.server");
28
- const cartCount = (await loadCartsByOrder(supabaseAdmin, [orderId])).get(orderId)?.count ?? 0;
26
+ // Karren uit de Engine-leesfunctie (gedeelde bufferkarren inbegrepen).
27
+ // Fail closed: lukt de vraag niet, dan geen payload (zoals voorheen bij een leesfout).
28
+ const { loadPlanCoverage } = await import("./plan-coverage.server");
29
+ const cov = (await loadPlanCoverage(supabaseAdmin, [orderId])).get(orderId);
30
+ if (!cov || cov.state === "onbekend") {
31
+ throw new Error(cov?.error ?? "Indeling niet beschikbaar bij de Logistiek Engine");
32
+ }
33
+ const cartCount = cov.carts.length;
29
34
  const pickupAt = cf.pickup_moment ?? cf.pickup_datetime ?? cf.pickup_date ?? o.delivery_date ?? null;
30
35
  // Ladingdrager NOOIT gokken. Een onbekende of ontbrekende drager blokkeert:
31
36
  // een verzonnen "trolley" leidt tot een verkeerde karrenberekening.
@@ -0,0 +1,56 @@
1
+ export type PlanCoverageState = "ingedeeld" | "deels" | "geen_indeling" | "geen_regels" | "onbekend";
2
+ export interface PlanCoverageLine {
3
+ orderItemId: string | null;
4
+ productId: string | null;
5
+ productName: string | null;
6
+ crates: number;
7
+ boxes: number;
8
+ }
9
+ export interface PlanCoverageCart {
10
+ cartId: string;
11
+ cartNumber: number | null;
12
+ bufferId: string | null;
13
+ shared: boolean;
14
+ carrierType: string | null;
15
+ lines: PlanCoverageLine[];
16
+ }
17
+ export interface PlanCoveragePickRow {
18
+ queueItemId: string | null;
19
+ documentNumber: string | null;
20
+ cartId: string | null;
21
+ printedAt: string | null;
22
+ completedAt: string | null;
23
+ }
24
+ export interface PlanCoverage {
25
+ state: PlanCoverageState;
26
+ label: string;
27
+ progressPct: number | null;
28
+ reason: string | null;
29
+ carts: PlanCoverageCart[];
30
+ pickRows: PlanCoveragePickRow[];
31
+ pickStatus: "geen_pickrij" | "open" | "bezig" | "gepickt" | null;
32
+ pickedAt: string | null;
33
+ /** Alleen uit de lijstversie (geen karregels): aantal karren volgens de Engine. */
34
+ cartCount?: number | null;
35
+ /** Alleen uit de lijstversie: order staat in een buffer (gedeelde kar). */
36
+ shared?: boolean | null;
37
+ /** Gezet als de Engine-vraag mislukte (fail closed: niets geschreven). */
38
+ error?: string | null;
39
+ }
40
+ export declare function defaultLabel(state: PlanCoverageState): string;
41
+ export declare function unknownCoverage(error: string): PlanCoverage;
42
+ /** Leest het jsonb-antwoord defensief in; ontbrekende velden worden leeg. */
43
+ export declare function parsePlanCoverage(raw: unknown): PlanCoverage;
44
+ /** Leest één rij van logistics_order_plan_coverage_list (platte kolommen, geen karregels). */
45
+ export declare function parsePlanCoverageListRow(r: any): PlanCoverage;
46
+ /** Samenvatting voor één rij in de lijst (buffer: de zwakste status wint). */
47
+ export interface PlanCoverageSummary {
48
+ state: PlanCoverageState;
49
+ label: string;
50
+ progressPct: number | null;
51
+ reason: string | null;
52
+ shared: boolean;
53
+ }
54
+ export declare function summarize(c: PlanCoverage): PlanCoverageSummary;
55
+ export declare function mergeSummaries(list: (PlanCoverageSummary | null | undefined)[]): PlanCoverageSummary | null;
56
+ //# sourceMappingURL=plan-coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-coverage.d.ts","sourceRoot":"","sources":["../../src/lib/plan-coverage.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,OAAO,GAAG,eAAe,GAAG,aAAa,GAAG,UAAU,CAAC;AAErG,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,UAAU,EAAE,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IACjE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAYD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAa7D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAY3D;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAsC5D;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,GAAG,GAAG,YAAY,CAgB7D;AAED,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AAUD,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,GAAG,mBAAmB,CAQ9D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,CAAC,mBAAmB,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,mBAAmB,GAAG,IAAI,CAK3G"}