@flowselections/floriday-voorraad 1.0.59 → 1.0.62

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.
@@ -1 +1 @@
1
- {"version":3,"file":"StockSyncStatus.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockSyncStatus.tsx"],"names":[],"mappings":"AAYA,wBAAgB,eAAe,uCA8D9B"}
1
+ {"version":3,"file":"StockSyncStatus.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/StockSyncStatus.tsx"],"names":[],"mappings":"AAYA,wBAAgB,eAAe,uCA6E9B"}
@@ -26,7 +26,7 @@ export function StockSyncStatus() {
26
26
  });
27
27
  if (!data)
28
28
  return null;
29
- const { failed, stalePending, oldestPendingAt } = data;
29
+ const { failed, stalePending, oldestPendingAt, topReason, articleCount, noPriceCount } = data;
30
30
  if (failed === 0 && stalePending === 0)
31
31
  return null;
32
32
  const parts = [];
@@ -36,5 +36,5 @@ export function StockSyncStatus() {
36
36
  if (stalePending > 0) {
37
37
  parts.push(`${stalePending} wacht${stalePending === 1 ? "" : "en"} langer dan 10 minuten`);
38
38
  }
39
- return (_jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-sm text-amber-800", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "font-medium", children: "Voorraadsync naar Floriday: " }), parts.join(" · "), " (laatste 24 uur).", oldestPendingAt && (_jsxs("span", { className: "opacity-80", children: [" ", "Oudste wachtende regel: ", new Date(oldestPendingAt).toLocaleString("nl-NL"), "."] }))] }), failed > 0 && (_jsxs("button", { type: "button", className: "inline-flex shrink-0 items-center rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-1 text-xs font-medium text-amber-900 hover:bg-amber-500/20 disabled:opacity-50", disabled: mutation.isPending, onClick: () => mutation.mutate(), children: [_jsx(RotateCw, { className: `mr-1 h-3.5 w-3.5 ${mutation.isPending ? "animate-spin" : ""}` }), "Opnieuw proberen"] }))] }));
39
+ return (_jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-sm text-amber-800", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsxs("div", { className: "flex-1 space-y-0.5", children: [_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Voorraadsync naar Floriday: " }), parts.join(" · "), " (laatste 24 uur), voor ", articleCount, " artikel", articleCount === 1 ? "" : "en", ".", oldestPendingAt && (_jsxs("span", { className: "opacity-80", children: [" ", "Oudste wachtende regel: ", new Date(oldestPendingAt).toLocaleString("nl-NL"), "."] }))] }), topReason && (_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: "Meest voorkomende reden: " }), topReason, "."] })), noPriceCount > 0 && (_jsxs("div", { className: "opacity-90", children: [noPriceCount, " van deze artikelen ", noPriceCount === 1 ? "heeft" : "hebben", " nog geen prijs in het weekaanbod; het aantal wordt dan zonder prijs doorgezet."] }))] }), failed > 0 && (_jsxs("button", { type: "button", className: "inline-flex shrink-0 items-center rounded-md border border-amber-500/40 bg-amber-500/10 px-2 py-1 text-xs font-medium text-amber-900 hover:bg-amber-500/20 disabled:opacity-50", disabled: mutation.isPending, onClick: () => mutation.mutate(), children: [_jsx(RotateCw, { className: `mr-1 h-3.5 w-3.5 ${mutation.isPending ? "animate-spin" : ""}` }), "Opnieuw proberen"] }))] }));
40
40
  }
@@ -3,6 +3,13 @@ export interface StockSyncHealth {
3
3
  pending: number;
4
4
  stalePending: number;
5
5
  oldestPendingAt: string | null;
6
+ /** Meest voorkomende reden bij probleemregels, in gewone taal. */
7
+ topReason: string | null;
8
+ /** Aantal verschillende artikelen met een probleemregel. */
9
+ articleCount: number;
10
+ /** Aantal van die artikelen zonder prijs in het weekaanbod. */
11
+ noPriceCount: number;
6
12
  }
13
+ export declare function reasonLabel(error: string | null | undefined): string | null;
7
14
  export declare function useStockSyncHealth(): import("@tanstack/react-query").UseQueryResult<StockSyncHealth, Error>;
8
15
  //# sourceMappingURL=useStockSyncHealth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStockSyncHealth.d.ts","sourceRoot":"","sources":["../../src/hooks/useStockSyncHealth.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wBAAgB,kBAAkB,2EAqCjC"}
1
+ {"version":3,"file":"useStockSyncHealth.d.ts","sourceRoot":"","sources":["../../src/hooks/useStockSyncHealth.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS3E;AAED,wBAAgB,kBAAkB,2EA6EjC"}
@@ -4,11 +4,27 @@
4
4
  * Bewust een venster van 24 uur: oude, allang achterhaalde fouten mogen de
5
5
  * gebruiker niet eindeloos blijven waarschuwen. Regels die door een nieuwere
6
6
  * voorraadstand zijn vervangen (`superseded`) tellen niet mee.
7
+ * Toont ook de meest voorkomende reden, het aantal artikelen en hoeveel
8
+ * daarvan geen prijs in het weekaanbod hebben.
7
9
  */
8
10
  import { useQuery } from "@tanstack/react-query";
9
11
  import { supabase } from "../integrations/supabase/client";
10
12
  const STALE_MINUTES = 10;
11
13
  const WINDOW_HOURS = 24;
14
+ export function reasonLabel(error) {
15
+ const e = (error ?? "").trim();
16
+ if (!e)
17
+ return null;
18
+ if (/gateway/i.test(e) && /(404|niet-JSON|not found|niet gevonden)/i.test(e))
19
+ return "Schrijfroute van de Authenticatiemodule niet bereikbaar";
20
+ if (/429|rate limit|snelheidslimiet/i.test(e))
21
+ return "Snelheidslimiet van Floriday";
22
+ if (/Floriday-cache/i.test(e))
23
+ return "Artikel staat niet in de Floriday-cache";
24
+ if (/timeout|fetch failed|network|50[234]/i.test(e))
25
+ return "Floriday tijdelijk niet bereikbaar";
26
+ return e.length > 120 ? `${e.slice(0, 117)}…` : e;
27
+ }
12
28
  export function useStockSyncHealth() {
13
29
  return useQuery({
14
30
  queryKey: ["stock-sync-health"],
@@ -17,7 +33,7 @@ export function useStockSyncHealth() {
17
33
  const since = new Date(Date.now() - WINDOW_HOURS * 3600000).toISOString();
18
34
  const { data, error } = await supabase
19
35
  .from("floriday_continuous_stock_queue")
20
- .select("status, created_at")
36
+ .select("status, created_at, last_error, trade_item_id, connection_id")
21
37
  .in("status", ["pending", "failed"])
22
38
  .gte("created_at", since)
23
39
  .limit(1000);
@@ -29,20 +45,58 @@ export function useStockSyncHealth() {
29
45
  let pending = 0;
30
46
  let stalePending = 0;
31
47
  let oldestPendingAt = null;
48
+ const reasons = new Map();
49
+ const problemItems = new Set();
32
50
  for (const r of rows) {
51
+ let problem = false;
33
52
  if (r.status === "failed") {
34
53
  failed++;
35
- continue;
54
+ problem = true;
55
+ }
56
+ else {
57
+ pending++;
58
+ const ts = Date.parse(r.created_at);
59
+ if (Number.isFinite(ts) && ts < cutoff) {
60
+ stalePending++;
61
+ problem = true;
62
+ }
63
+ if (!oldestPendingAt || r.created_at < oldestPendingAt)
64
+ oldestPendingAt = r.created_at;
36
65
  }
37
- pending++;
38
- const ts = Date.parse(r.created_at);
39
- if (Number.isFinite(ts) && ts < cutoff)
40
- stalePending++;
41
- if (!oldestPendingAt || r.created_at < oldestPendingAt) {
42
- oldestPendingAt = r.created_at;
66
+ if (problem) {
67
+ problemItems.add(r.trade_item_id);
68
+ const label = reasonLabel(r.last_error);
69
+ if (label)
70
+ reasons.set(label, (reasons.get(label) ?? 0) + 1);
71
+ }
72
+ }
73
+ let topReason = null;
74
+ let best = 0;
75
+ for (const [k, v] of reasons)
76
+ if (v > best) {
77
+ best = v;
78
+ topReason = k;
43
79
  }
80
+ let noPriceCount = 0;
81
+ const ids = Array.from(problemItems);
82
+ if (ids.length > 0) {
83
+ const { data: priced } = await supabase
84
+ .from("trade_item_supply_lines")
85
+ .select("trade_item_id")
86
+ .in("trade_item_id", ids)
87
+ .gt("price_per_piece", 0);
88
+ const withPrice = new Set((priced ?? []).map((p) => p.trade_item_id));
89
+ noPriceCount = ids.filter((id) => !withPrice.has(id)).length;
44
90
  }
45
- return { failed, pending, stalePending, oldestPendingAt };
91
+ return {
92
+ failed,
93
+ pending,
94
+ stalePending,
95
+ oldestPendingAt,
96
+ topReason,
97
+ articleCount: ids.length,
98
+ noPriceCount,
99
+ };
46
100
  },
47
101
  });
48
102
  }
@@ -6653,6 +6653,7 @@ export type Database = {
6653
6653
  dead_lettered_at: string | null;
6654
6654
  desired_available: boolean | null;
6655
6655
  gateway_attempt_id: string | null;
6656
+ gateway_unreachable_since: string | null;
6656
6657
  id: string;
6657
6658
  last_error: string | null;
6658
6659
  locked_at: string | null;
@@ -6680,6 +6681,7 @@ export type Database = {
6680
6681
  dead_lettered_at?: string | null;
6681
6682
  desired_available?: boolean | null;
6682
6683
  gateway_attempt_id?: string | null;
6684
+ gateway_unreachable_since?: string | null;
6683
6685
  id?: string;
6684
6686
  last_error?: string | null;
6685
6687
  locked_at?: string | null;
@@ -6707,6 +6709,7 @@ export type Database = {
6707
6709
  dead_lettered_at?: string | null;
6708
6710
  desired_available?: boolean | null;
6709
6711
  gateway_attempt_id?: string | null;
6712
+ gateway_unreachable_since?: string | null;
6710
6713
  id?: string;
6711
6714
  last_error?: string | null;
6712
6715
  locked_at?: string | null;
@@ -8902,6 +8905,8 @@ export type Database = {
8902
8905
  queue_cleanup_batch: number;
8903
8906
  queue_cleanup_max_batches: number;
8904
8907
  queue_failed_days: number;
8908
+ queue_gateway_backoff_minutes: number[];
8909
+ queue_gateway_give_up_hours: number;
8905
8910
  queue_sent_days: number;
8906
8911
  queue_skipped_days: number;
8907
8912
  queue_superseded_days: number;
@@ -8920,6 +8925,8 @@ export type Database = {
8920
8925
  queue_cleanup_batch?: number;
8921
8926
  queue_cleanup_max_batches?: number;
8922
8927
  queue_failed_days?: number;
8928
+ queue_gateway_backoff_minutes?: number[];
8929
+ queue_gateway_give_up_hours?: number;
8923
8930
  queue_sent_days?: number;
8924
8931
  queue_skipped_days?: number;
8925
8932
  queue_superseded_days?: number;
@@ -8938,6 +8945,8 @@ export type Database = {
8938
8945
  queue_cleanup_batch?: number;
8939
8946
  queue_cleanup_max_batches?: number;
8940
8947
  queue_failed_days?: number;
8948
+ queue_gateway_backoff_minutes?: number[];
8949
+ queue_gateway_give_up_hours?: number;
8941
8950
  queue_sent_days?: number;
8942
8951
  queue_skipped_days?: number;
8943
8952
  queue_superseded_days?: number;
@@ -11173,6 +11182,33 @@ export type Database = {
11173
11182
  };
11174
11183
  Relationships: [];
11175
11184
  };
11185
+ logistics_allocation_fingerprint: {
11186
+ Row: {
11187
+ created_at: string;
11188
+ fingerprint: string;
11189
+ last_replan_at: string | null;
11190
+ order_id: string;
11191
+ pending_since: string | null;
11192
+ updated_at: string;
11193
+ };
11194
+ Insert: {
11195
+ created_at?: string;
11196
+ fingerprint: string;
11197
+ last_replan_at?: string | null;
11198
+ order_id: string;
11199
+ pending_since?: string | null;
11200
+ updated_at?: string;
11201
+ };
11202
+ Update: {
11203
+ created_at?: string;
11204
+ fingerprint?: string;
11205
+ last_replan_at?: string | null;
11206
+ order_id?: string;
11207
+ pending_since?: string | null;
11208
+ updated_at?: string;
11209
+ };
11210
+ Relationships: [];
11211
+ };
11176
11212
  logistics_autolink_audit: {
11177
11213
  Row: {
11178
11214
  created_at: string;
@@ -12788,6 +12824,7 @@ export type Database = {
12788
12824
  created_at: string;
12789
12825
  group_id: string | null;
12790
12826
  id: string;
12827
+ line_qty: number | null;
12791
12828
  order_item_id: string;
12792
12829
  qty: number;
12793
12830
  source: string;
@@ -12799,6 +12836,7 @@ export type Database = {
12799
12836
  created_at?: string;
12800
12837
  group_id?: string | null;
12801
12838
  id?: string;
12839
+ line_qty?: number | null;
12802
12840
  order_item_id: string;
12803
12841
  qty: number;
12804
12842
  source: string;
@@ -12810,6 +12848,7 @@ export type Database = {
12810
12848
  created_at?: string;
12811
12849
  group_id?: string | null;
12812
12850
  id?: string;
12851
+ line_qty?: number | null;
12813
12852
  order_item_id?: string;
12814
12853
  qty?: number;
12815
12854
  source?: string;
@@ -15565,6 +15604,7 @@ export type Database = {
15565
15604
  Row: {
15566
15605
  boxes: number | null;
15567
15606
  cart_id: string;
15607
+ components: Json | null;
15568
15608
  crates: number;
15569
15609
  crates_in_layer: number | null;
15570
15610
  crates_per_layer: number;
@@ -15583,6 +15623,7 @@ export type Database = {
15583
15623
  Insert: {
15584
15624
  boxes?: number | null;
15585
15625
  cart_id: string;
15626
+ components?: Json | null;
15586
15627
  crates: number;
15587
15628
  crates_in_layer?: number | null;
15588
15629
  crates_per_layer?: number;
@@ -15601,6 +15642,7 @@ export type Database = {
15601
15642
  Update: {
15602
15643
  boxes?: number | null;
15603
15644
  cart_id?: string;
15645
+ components?: Json | null;
15604
15646
  crates?: number;
15605
15647
  crates_in_layer?: number | null;
15606
15648
  crates_per_layer?: number;
@@ -27593,6 +27635,7 @@ export type Database = {
27593
27635
  dead_lettered_at: string | null;
27594
27636
  desired_available: boolean | null;
27595
27637
  gateway_attempt_id: string | null;
27638
+ gateway_unreachable_since: string | null;
27596
27639
  id: string;
27597
27640
  last_error: string | null;
27598
27641
  locked_at: string | null;
@@ -29253,6 +29296,24 @@ export type Database = {
29253
29296
  };
29254
29297
  Returns: string;
29255
29298
  };
29299
+ logistics_allocation_check_changes: {
29300
+ Args: {
29301
+ p_order_item_ids?: string[];
29302
+ };
29303
+ Returns: Json;
29304
+ };
29305
+ logistics_allocation_fp: {
29306
+ Args: {
29307
+ p_order_id: string;
29308
+ };
29309
+ Returns: string;
29310
+ };
29311
+ logistics_allocation_frozen: {
29312
+ Args: {
29313
+ p_order_id: string;
29314
+ };
29315
+ Returns: boolean;
29316
+ };
29256
29317
  logistics_allowed_load_carriers: {
29257
29318
  Args: {
29258
29319
  p_strategy_id?: string;
@@ -29949,6 +30010,15 @@ export type Database = {
29949
30010
  };
29950
30011
  Returns: Database["public"]["Enums"]["doc_layout_type"][];
29951
30012
  };
30013
+ logistics_double_group_lines: {
30014
+ Args: {
30015
+ p_order_id?: string;
30016
+ };
30017
+ Returns: {
30018
+ group_id: string;
30019
+ order_item_id: string;
30020
+ }[];
30021
+ };
29952
30022
  logistics_emit_event: {
29953
30023
  Args: {
29954
30024
  p_event_type: string;
@@ -30207,6 +30277,18 @@ export type Database = {
30207
30277
  };
30208
30278
  Returns: boolean;
30209
30279
  };
30280
+ logistics_frozen_allocation_scaled: {
30281
+ Args: {
30282
+ p_new_qty: number;
30283
+ p_order_item_id: string;
30284
+ };
30285
+ Returns: {
30286
+ group_id: string;
30287
+ qty: number;
30288
+ source: string;
30289
+ trade_item_key: string;
30290
+ }[];
30291
+ };
30210
30292
  logistics_fulfill_barcode_requests: {
30211
30293
  Args: {
30212
30294
  p_limit?: number;
@@ -30240,6 +30322,12 @@ export type Database = {
30240
30322
  };
30241
30323
  Returns: boolean;
30242
30324
  };
30325
+ logistics_key_product: {
30326
+ Args: {
30327
+ p_key: string;
30328
+ };
30329
+ Returns: string;
30330
+ };
30243
30331
  logistics_layout_method_status: {
30244
30332
  Args: never;
30245
30333
  Returns: Json;
@@ -30342,6 +30430,12 @@ export type Database = {
30342
30430
  };
30343
30431
  Returns: undefined;
30344
30432
  };
30433
+ logistics_order_current_warnings: {
30434
+ Args: {
30435
+ p_order_id: string;
30436
+ };
30437
+ Returns: string[];
30438
+ };
30345
30439
  logistics_order_documents_ready: {
30346
30440
  Args: {
30347
30441
  p_order_ref: string;
@@ -30824,6 +30918,23 @@ export type Database = {
30824
30918
  Args: never;
30825
30919
  Returns: number;
30826
30920
  };
30921
+ logistics_planner_lines: {
30922
+ Args: {
30923
+ p_order_id: string;
30924
+ };
30925
+ Returns: {
30926
+ components: Json;
30927
+ frozen: boolean;
30928
+ group_id: string;
30929
+ note: string;
30930
+ order_item_id: string;
30931
+ product_id: string;
30932
+ product_name: string;
30933
+ qty: number;
30934
+ trade_item_key: string;
30935
+ unit_kind: string;
30936
+ }[];
30937
+ };
30827
30938
  logistics_prepare_pick_documents: {
30828
30939
  Args: {
30829
30940
  p_limit?: number;
@@ -30954,6 +31065,13 @@ export type Database = {
30954
31065
  };
30955
31066
  Returns: Json;
30956
31067
  };
31068
+ logistics_replan_selected_orders: {
31069
+ Args: {
31070
+ p_order_ids: string[];
31071
+ p_reason?: string;
31072
+ };
31073
+ Returns: Json;
31074
+ };
30957
31075
  logistics_report_delay: {
30958
31076
  Args: {
30959
31077
  p_expected_date?: string;
@@ -30970,6 +31088,12 @@ export type Database = {
30970
31088
  };
30971
31089
  Returns: string;
30972
31090
  };
31091
+ logistics_report_frozen_shortage: {
31092
+ Args: {
31093
+ p_order_item_ids: string[];
31094
+ };
31095
+ Returns: undefined;
31096
+ };
30973
31097
  logistics_rescan_orders: {
30974
31098
  Args: {
30975
31099
  p_days?: number;