@flowselections/floriday-voorraad 1.0.115 → 1.0.121

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,8 +1,7 @@
1
1
  import type { TradeItem } from "../../lib/floriday-client.js";
2
2
  /**
3
- * 1.0.114: "Op voorraad" telt liggende voorraad (fysiek > 0), niet vrij
4
- * beschikbaar. Reserveringen voor orders op "Nog te picken" lieten anders alles
5
- * als "Niet op voorraad" zien zonder dat er iets was afgeboekt.
3
+ * "Op voorraad" = artikelen met liggende voorraad (fysiek > 0).
4
+ * "Vrij beschikbaar" = artikelen waarvan liggend min gereserveerd > 0.
6
5
  */
7
6
  export declare function countStock(items: Array<Pick<TradeItem, "quantity" | "availableQuantity" | "minQuantity">>): {
8
7
  total: number;
@@ -10,6 +9,7 @@ export declare function countStock(items: Array<Pick<TradeItem, "quantity" | "av
10
9
  outOfStock: number;
11
10
  belowMin: number;
12
11
  fullyReserved: number;
12
+ freeAvailable: number;
13
13
  };
14
14
  export declare function VoorraadPage(): import("react").JSX.Element;
15
15
  //# sourceMappingURL=VoorraadPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAiF3D;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,mBAAmB,GAAG,aAAa,CAAC,CAAC;;;;;;EAczG;AAED,wBAAgB,YAAY,gCAiW3B"}
1
+ {"version":3,"file":"VoorraadPage.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/VoorraadPage.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAqF3D;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,mBAAmB,GAAG,aAAa,CAAC,CAAC;;;;;;;EAgBzG;AAED,wBAAgB,YAAY,gCA0W3B"}
@@ -37,23 +37,23 @@ function toneClasses(tone) {
37
37
  return { icon: "bg-primary/10 text-primary", value: "text-foreground" };
38
38
  }
39
39
  }
40
- function KpiCard({ icon, label, count, tone, active, onClick, }) {
40
+ function KpiCard({ icon, label, count, tone, active, onClick, hint, }) {
41
41
  const cls = toneClasses(tone);
42
- return (_jsxs("button", { type: "button", onClick: onClick, className: `text-left rounded-lg border bg-card p-4 transition-colors hover:border-primary/50 ${active ? "border-primary ring-1 ring-primary" : "border-border"}`, children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `inline-flex h-8 w-8 items-center justify-center rounded-md ${cls.icon}`, children: icon }), _jsx("span", { className: "text-sm font-medium text-foreground", children: label })] }), _jsx("div", { className: `mt-3 text-3xl font-bold tabular-nums ${cls.value}`, children: count })] }));
42
+ return (_jsxs("button", { type: "button", onClick: onClick, title: hint, className: `text-left rounded-lg border bg-card p-4 transition-colors hover:border-primary/50 ${active ? "border-primary ring-1 ring-primary" : "border-border"}`, children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `inline-flex h-8 w-8 items-center justify-center rounded-md ${cls.icon}`, children: icon }), _jsx("span", { className: "text-sm font-medium text-foreground", children: label })] }), _jsx("div", { className: `mt-3 text-3xl font-bold tabular-nums ${cls.value}`, children: count }), hint && _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: hint })] }));
43
43
  }
44
44
  function availableOf(i) {
45
45
  return i.availableQuantity ?? i.quantity ?? 0;
46
46
  }
47
47
  /**
48
- * 1.0.114: "Op voorraad" telt liggende voorraad (fysiek > 0), niet vrij
49
- * beschikbaar. Reserveringen voor orders op "Nog te picken" lieten anders alles
50
- * als "Niet op voorraad" zien zonder dat er iets was afgeboekt.
48
+ * "Op voorraad" = artikelen met liggende voorraad (fysiek > 0).
49
+ * "Vrij beschikbaar" = artikelen waarvan liggend min gereserveerd > 0.
51
50
  */
52
51
  export function countStock(items) {
53
52
  let inStock = 0;
54
53
  let outOfStock = 0;
55
54
  let belowMin = 0;
56
55
  let fullyReserved = 0;
56
+ let freeAvailable = 0;
57
57
  for (const i of items) {
58
58
  const physical = Number(i.quantity ?? 0);
59
59
  const avail = availableOf(i);
@@ -61,12 +61,14 @@ export function countStock(items) {
61
61
  inStock++;
62
62
  else
63
63
  outOfStock++;
64
+ if (avail > 0)
65
+ freeAvailable++;
64
66
  if (physical > 0 && avail <= 0)
65
67
  fullyReserved++;
66
68
  if ((i.minQuantity ?? 0) > 0 && avail < (i.minQuantity ?? 0))
67
69
  belowMin++;
68
70
  }
69
- return { total: items.length, inStock, outOfStock, belowMin, fullyReserved };
71
+ return { total: items.length, inStock, outOfStock, belowMin, fullyReserved, freeAvailable };
70
72
  }
71
73
  export function VoorraadPage() {
72
74
  const auth = useAuthState();
@@ -150,7 +152,7 @@ export function VoorraadPage() {
150
152
  noPriceBreakdown.unit > 0 ? `${noPriceBreakdown.unit} met een andere eenheid dan stuks` : null,
151
153
  ]
152
154
  .filter(Boolean)
153
- .join(", "), "."] }), " ", "Kies \"Toon deze artikelen\", open een artikel en vul bij Artikel regulier de verkoopprijs per stuk (excl. btw) in. De voorraadsturing van elk artikel heeft ook een link \"Prijs invullen\"."] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => setNoPriceOnly((v) => !v), children: noPriceOnly ? "Alle artikelen tonen" : "Toon deze artikelen" })] })), _jsx(FloridayLeadingSummary, { connectionId: activeId ?? null }), auth.isAdmin && _jsx(FloridayTakeoverPanel, { connectionId: activeId ?? null }), auth.isAdmin && _jsx(StockPushMonitor, { connectionId: activeId ?? null }), _jsx(FloridayConnectionNotice, { status: conn.status, environment: conn.selectedEnvironment, error: connError }), error && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 text-destructive p-3 text-sm", children: ["Voorraad laden mislukt: ", error] })), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4", children: [_jsx(KpiCard, { icon: _jsx(FileText, { className: "h-4 w-4" }), tone: "primary", label: "Artikelen", count: counts.total, active: stockFilter === "all", onClick: () => toggle("all") }), _jsx(KpiCard, { icon: _jsx(CheckCircle2, { className: "h-4 w-4" }), tone: "emerald", label: "Op voorraad", count: counts.inStock, active: stockFilter === "in_stock", onClick: () => toggle("in_stock") }), _jsx(KpiCard, { icon: _jsx(PackageX, { className: "h-4 w-4" }), tone: "rose", label: "Niet op voorraad", count: counts.outOfStock, active: stockFilter === "out_of_stock", onClick: () => toggle("out_of_stock") }), _jsx(KpiCard, { icon: _jsx(AlertTriangle, { className: "h-4 w-4" }), tone: "amber", label: "Onder minimum", count: counts.belowMin, active: stockFilter === "below_min", onClick: () => toggle("below_min") })] }), _jsxs(Card, { className: "overflow-hidden p-0", children: [_jsx("div", { className: "flex flex-wrap items-center gap-1 border-b px-4", children: TABS.map((t) => {
155
+ .join(", "), "."] }), " ", "Kies \"Toon deze artikelen\", open een artikel en vul bij Artikel regulier de verkoopprijs per stuk (excl. btw) in. De voorraadsturing van elk artikel heeft ook een link \"Prijs invullen\"."] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => setNoPriceOnly((v) => !v), children: noPriceOnly ? "Alle artikelen tonen" : "Toon deze artikelen" })] })), _jsx(FloridayLeadingSummary, { connectionId: activeId ?? null }), auth.isAdmin && _jsx(FloridayTakeoverPanel, { connectionId: activeId ?? null }), auth.isAdmin && _jsx(StockPushMonitor, { connectionId: activeId ?? null }), _jsx(FloridayConnectionNotice, { status: conn.status, environment: conn.selectedEnvironment, error: connError }), error && (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 text-destructive p-3 text-sm", children: ["Voorraad laden mislukt: ", error] })), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4", children: [_jsx(KpiCard, { icon: _jsx(FileText, { className: "h-4 w-4" }), tone: "primary", label: "Artikelen", count: counts.total, active: stockFilter === "all", onClick: () => toggle("all") }), _jsx(KpiCard, { icon: _jsx(CheckCircle2, { className: "h-4 w-4" }), tone: "emerald", label: "Op voorraad", count: counts.inStock, active: stockFilter === "in_stock", onClick: () => toggle("in_stock"), hint: "Artikelen waarvan nu iets op de kwekerij staat." }), _jsx(KpiCard, { icon: _jsx(CheckCircle2, { className: "h-4 w-4" }), tone: "primary", label: "Vrij beschikbaar", count: counts.freeAvailable, active: false, hint: "Artikelen waarvan na aftrek van wat voor orders gereserveerd is nog iets over is." }), _jsx(KpiCard, { icon: _jsx(PackageX, { className: "h-4 w-4" }), tone: "rose", label: "Niet op voorraad", count: counts.outOfStock, active: stockFilter === "out_of_stock", onClick: () => toggle("out_of_stock") }), _jsx(KpiCard, { icon: _jsx(AlertTriangle, { className: "h-4 w-4" }), tone: "amber", label: "Onder minimum", count: counts.belowMin, active: stockFilter === "below_min", onClick: () => toggle("below_min") })] }), _jsxs(Card, { className: "overflow-hidden p-0", children: [_jsx("div", { className: "flex flex-wrap items-center gap-1 border-b px-4", children: TABS.map((t) => {
154
156
  const active = stockFilter === t.id;
155
157
  return (_jsxs("button", { type: "button", onClick: () => setStockFilter(t.id), className: `relative py-3 px-3 text-sm font-medium whitespace-nowrap transition-colors ${active
156
158
  ? "text-foreground"
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=count-stock-free.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"count-stock-free.test.d.ts","sourceRoot":"","sources":["../../../../src/components/voorraad/__tests__/count-stock-free.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { countStock } from "../VoorraadPage.js";
3
+ describe("countStock vrij beschikbaar", () => {
4
+ it("liggend 100 met 100 gereserveerd: op voorraad, niet vrij", () => {
5
+ const c = countStock([{ quantity: 100, availableQuantity: 0, minQuantity: 0 }]);
6
+ expect(c.inStock).toBe(1);
7
+ expect(c.freeAvailable).toBe(0);
8
+ });
9
+ it("liggend 100 met 40 gereserveerd: vrij", () => {
10
+ expect(countStock([{ quantity: 100, availableQuantity: 60, minQuantity: 0 }]).freeAvailable).toBe(1);
11
+ });
12
+ });