@flowselections/floriday-voorraad 1.0.70 → 1.0.71

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":"ArtikelWizard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelWizard.tsx"],"names":[],"mappings":"AA6MA,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,cAAc,EACvB,WAAW,EACX,SAAS,EACT,WAAW,GACZ,GAAE;IACD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,+BAorEL"}
1
+ {"version":3,"file":"ArtikelWizard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ArtikelWizard.tsx"],"names":[],"mappings":"AA6MA,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,cAAc,EACvB,WAAW,EACX,SAAS,EACT,WAAW,GACZ,GAAE;IACD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,+BAssEL"}
@@ -291,7 +291,7 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
291
291
  setProductLoading(true);
292
292
  (async () => {
293
293
  try {
294
- const baseCols = "id,product,barcode,article_number,quantity,image_url,plants_per_crate,crates_per_layer,layers_per_cart,trade_item_key,floriday_trade_item_id,custom_fields";
294
+ const baseCols = "id,product,sale_price,unit,barcode,article_number,quantity,image_url,plants_per_crate,crates_per_layer,layers_per_cart,trade_item_key,floriday_trade_item_id,custom_fields";
295
295
  let { data: product, error } = await supabase
296
296
  .from("products")
297
297
  .select(`${baseCols},floriday_packing_confirmed_at,floriday_packing_source`)
@@ -487,7 +487,10 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
487
487
  : validGtin
488
488
  ? barcode
489
489
  : (payload.gtin ?? ""),
490
- salePricePerPiece: Number(customFields.sale_price ?? customFields.salePrice ?? payload.salePricePerPiece) || 0,
490
+ // M26: de verkoopprijs van het artikel is leidend (zelfde veld als "Prijs opslaan").
491
+ salePricePerPiece: Number(product.sale_price) > 0
492
+ ? Number(product.sale_price)
493
+ : Number(customFields.sale_price ?? customFields.salePrice ?? payload.salePricePerPiece) || 0,
491
494
  // Voorkeur: werkelijke voorraad uit trade_item_stock.
492
495
  // Fallback: opgeslagen payload-waarde. `products.quantity` wordt
493
496
  // bewust NIET meer gelezen — die staat structureel op 0.
@@ -925,18 +928,34 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
925
928
  }, [spec.characteristics]);
926
929
  const wantsPublish = (isEditingPublished && Boolean(tradeItemId)) ||
927
930
  (!isEditingPublished && publishToFloriday);
928
- const readiness = useMemo(() => buildReadinessReport({
929
- data,
930
- spec,
931
- connectionOk: Boolean(activeId) && connectionReadiness.data?.ready === true,
932
- connectionLoading: connLoading || connectionReadiness.isLoading,
933
- environment: activeConnection?.active_environment ?? null,
934
- connectionMessage: connectionReadiness.data?.message ?? null,
935
- schemaReady: schemaQuery.isSuccess,
936
- learnedCharacteristicCodes: serverRequiredCodes,
937
- characteristicLabels,
938
- wantsPublish,
939
- }), [
931
+ const readiness = useMemo(() => {
932
+ const r = buildReadinessReport({
933
+ data,
934
+ spec,
935
+ connectionOk: Boolean(activeId) && connectionReadiness.data?.ready === true,
936
+ connectionLoading: connLoading || connectionReadiness.isLoading,
937
+ environment: activeConnection?.active_environment ?? null,
938
+ connectionMessage: connectionReadiness.data?.message ?? null,
939
+ schemaReady: schemaQuery.isSuccess,
940
+ learnedCharacteristicCodes: serverRequiredCodes,
941
+ characteristicLabels,
942
+ wantsPublish,
943
+ });
944
+ // M26: één controle — elke onvolledige stap (zelfde check als de teller) telt mee.
945
+ const extra = steps
946
+ .filter((s, i) => !stepValidity[i])
947
+ .filter((s) => !r.items.some((it) => it.stepKey === s.key && !it.ok))
948
+ .map((s) => ({
949
+ key: `step-${s.key}`,
950
+ label: `Stap "${s.label}" is nog onvolledig`,
951
+ ok: false,
952
+ stepKey: s.key,
953
+ blocking: true,
954
+ }));
955
+ const items = [...r.items, ...extra];
956
+ const blockers = items.filter((i) => i.blocking && !i.ok);
957
+ return { ok: blockers.length === 0, items, blockers };
958
+ }, [
940
959
  data,
941
960
  spec,
942
961
  activeId,
@@ -948,6 +967,8 @@ export function ArtikelWizard({ draftId: initialDraftId, tradeItemId, productId,
948
967
  serverRequiredCodes,
949
968
  characteristicLabels,
950
969
  wantsPublish,
970
+ steps,
971
+ stepValidity,
951
972
  ]);
952
973
  const goToStepKey = useCallback((key) => {
953
974
  const idx = visibleSteps(data).findIndex((s) => s.key === key);
@@ -1 +1 @@
1
- {"version":3,"file":"FloridaySentCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridaySentCard.tsx"],"names":[],"mappings":"AAUA,KAAK,GAAG,GAAG;IACT,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAUF,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,GAAG,YAAY,GAAG,aAAa,CAAC,GAAG,MAAM,CA0BxI;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,EAAE;IACD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,+BAmGA"}
1
+ {"version":3,"file":"FloridaySentCard.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridaySentCard.tsx"],"names":[],"mappings":"AAWA,KAAK,GAAG,GAAG;IACT,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAUF,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,GAAG,YAAY,GAAG,aAAa,CAAC,GAAG,MAAM,CA0BxI;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,EAAE;IACD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,+BAiIA"}
@@ -8,6 +8,7 @@ import { useEffect, useState } from "react";
8
8
  import { Card, CardContent } from "@flowselections/core";
9
9
  import { Send } from "lucide-react";
10
10
  import { supabase } from "../../integrations/supabase/client";
11
+ import { priceProblem } from "../../lib/floriday-base-supply";
11
12
  const MODE_LABEL = {
12
13
  FOLLOW_ERP: "Volgt ERP",
13
14
  MAXIMUM: "Maximum",
@@ -46,6 +47,8 @@ export function resultText(r) {
46
47
  }
47
48
  export function FloridaySentCard({ connectionId, productId, tradeItemId, productType, }) {
48
49
  const [rows, setRows] = useState([]);
50
+ const [weekPrice, setWeekPrice] = useState({});
51
+ const [reason, setReason] = useState(null);
49
52
  useEffect(() => {
50
53
  if (!connectionId || (!productId && !tradeItemId))
51
54
  return;
@@ -76,10 +79,41 @@ export function FloridaySentCard({ connectionId, productId, tradeItemId, product
76
79
  out.push(r);
77
80
  }
78
81
  setRows(out.slice(0, 8));
82
+ // M26: laatst verzonden prijs per week, ook van inmiddels vervangen regels
83
+ // (latere aantal-wijzigingen sturen geen prijs; die blijft in Floriday staan).
84
+ const { data: priced } = await supabase
85
+ .from("floriday_continuous_stock_queue")
86
+ .select("target_year,target_week,price_sent,updated_at")
87
+ .eq("connection_id", connectionId)
88
+ .or(ors)
89
+ .not("price_sent", "is", null)
90
+ .order("updated_at", { ascending: false })
91
+ .limit(100);
92
+ const wp = {};
93
+ for (const r of (priced ?? [])) {
94
+ const k = `${r.target_year ?? ""}-${r.target_week ?? ""}`;
95
+ if (!(k in wp))
96
+ wp[k] = Number(r.price_sent);
97
+ }
98
+ // M26: werkelijke reden bij "Prijs ontbreekt" uit het artikel zelf.
99
+ let why = null;
100
+ if (productId) {
101
+ const { data: p } = await supabase
102
+ .from("products").select("sale_price,unit").eq("id", productId).maybeSingle();
103
+ if (p)
104
+ why = priceProblem(p.sale_price, p.unit);
105
+ }
106
+ if (cancelled)
107
+ return;
108
+ setWeekPrice(wp);
109
+ setReason(why);
79
110
  })();
80
111
  return () => {
81
112
  cancelled = true;
82
113
  };
83
114
  }, [connectionId, productId, tradeItemId]);
84
- return (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-3 p-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Send, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium", children: "Laatst naar Floriday" })] }), _jsxs("p", { className: "text-xs text-muted-foreground break-all", children: ["Floriday-id: ", tradeItemId ? _jsx("span", { className: "font-mono", children: tradeItemId }) : "nog niet gekoppeld"] }), (productType === "GROUP" || productType === "SET" || productType === "COMPOSITION") && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Productgroep (ERP): leden met eigen voorraad; alleen het totaal gaat naar Floriday. Set (Floriday): \u00E9\u00E9n artikel samengesteld uit onderdelen; de voorraad gaat pas naar Floriday na akkoord." })), rows.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog niets naar Floriday gestuurd." })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-xs", children: [_jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-1 pr-3", children: "Week" }), _jsx("th", { className: "py-1 pr-3 text-right", children: "Aantal" }), _jsx("th", { className: "py-1 pr-3 text-right", children: "Prijs (excl. btw)" }), _jsx("th", { className: "py-1 pr-3", children: "Modus" }), _jsx("th", { className: "py-1 pr-3", children: "Tijd" }), _jsx("th", { className: "py-1", children: "Resultaat" })] }) }), _jsx("tbody", { children: rows.map((r) => (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "py-1 pr-3 whitespace-nowrap", children: r.target_week ? `${r.target_year}-${r.target_week}` : "—" }), _jsx("td", { className: "py-1 pr-3 text-right tabular-nums", children: r.number_of_pieces ?? "—" }), _jsx("td", { className: "py-1 pr-3 text-right tabular-nums", children: r.price_sent != null ? `€ ${Number(r.price_sent).toFixed(2)}` : "—" }), _jsx("td", { className: "py-1 pr-3 whitespace-nowrap", children: r.stock_mode ? MODE_LABEL[r.stock_mode] ?? r.stock_mode : "—" }), _jsx("td", { className: "py-1 pr-3 whitespace-nowrap", children: new Date(r.sent_at ?? r.updated_at).toLocaleString("nl-NL") }), _jsxs("td", { className: "py-1", children: [resultText(r), r.price_note && r.price_note !== resultText(r) && (_jsx("div", { className: "text-xs text-muted-foreground", children: r.price_note }))] })] }, r.id))) })] }) }))] }) }));
115
+ return (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-3 p-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Send, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium", children: "Laatst naar Floriday" })] }), _jsxs("p", { className: "text-xs text-muted-foreground break-all", children: ["Floriday-id: ", tradeItemId ? _jsx("span", { className: "font-mono", children: tradeItemId }) : "nog niet gekoppeld"] }), (productType === "GROUP" || productType === "SET" || productType === "COMPOSITION") && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Productgroep (ERP): leden met eigen voorraad; alleen het totaal gaat naar Floriday. Set (Floriday): \u00E9\u00E9n artikel samengesteld uit onderdelen; de voorraad gaat pas naar Floriday na akkoord." })), rows.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog niets naar Floriday gestuurd." })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-xs", children: [_jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-1 pr-3", children: "Week" }), _jsx("th", { className: "py-1 pr-3 text-right", children: "Aantal" }), _jsx("th", { className: "py-1 pr-3 text-right", children: "Prijs (excl. btw)" }), _jsx("th", { className: "py-1 pr-3", children: "Modus" }), _jsx("th", { className: "py-1 pr-3", children: "Tijd" }), _jsx("th", { className: "py-1", children: "Resultaat" })] }) }), _jsx("tbody", { children: rows.map((r) => (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "py-1 pr-3 whitespace-nowrap", children: r.target_week ? `${r.target_year}-${r.target_week}` : "—" }), _jsx("td", { className: "py-1 pr-3 text-right tabular-nums", children: r.number_of_pieces ?? "—" }), _jsx("td", { className: "py-1 pr-3 text-right tabular-nums", children: (() => {
116
+ const p = r.price_sent ?? weekPrice[`${r.target_year ?? ""}-${r.target_week ?? ""}`];
117
+ return p != null ? `€ ${Number(p).toFixed(2)}` : "—";
118
+ })() }), _jsx("td", { className: "py-1 pr-3 whitespace-nowrap", children: r.stock_mode ? MODE_LABEL[r.stock_mode] ?? r.stock_mode : "—" }), _jsx("td", { className: "py-1 pr-3 whitespace-nowrap", children: new Date(r.sent_at ?? r.updated_at).toLocaleString("nl-NL") }), _jsxs("td", { className: "py-1", children: [r.status === "skipped_no_price" && reason ? reason : resultText(r), r.price_note && r.price_note !== resultText(r) && (_jsx("div", { className: "text-xs text-muted-foreground", children: r.price_note }))] })] }, r.id))) })] }) }))] }) }));
85
119
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PriceStatusBadge.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/PriceStatusBadge.tsx"],"names":[],"mappings":"AAGA,KAAK,KAAK,GAAG;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAeF,wBAAgB,gBAAgB,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,KAAK,sCAkEpE"}
1
+ {"version":3,"file":"PriceStatusBadge.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/PriceStatusBadge.tsx"],"names":[],"mappings":"AAmCA,KAAK,KAAK,GAAG;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAeF,wBAAgB,gBAAgB,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,KAAK,sCA8EpE"}
@@ -1,6 +1,36 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CircleDollarSign, Clock, MinusCircle, Loader2 } from "lucide-react";
3
+ import { useEffect, useState } from "react";
3
4
  import { useTradeItemSupplyLine } from "../../hooks/useTradeItemSupplyLine.js";
5
+ import { supabase } from "../../integrations/supabase/client.js";
6
+ /** M26: laatst naar Floriday verzonden weekprijs (weekaanbod), uit de wachtrij. */
7
+ function useLastSentPrice(tradeItemId) {
8
+ const [v, setV] = useState(null);
9
+ useEffect(() => {
10
+ if (!tradeItemId)
11
+ return;
12
+ let cancelled = false;
13
+ const load = async () => {
14
+ const { data } = await supabase
15
+ .from("floriday_continuous_stock_queue")
16
+ .select("price_sent,target_week,target_year,updated_at")
17
+ .eq("trade_item_id", tradeItemId)
18
+ .not("price_sent", "is", null)
19
+ .order("updated_at", { ascending: false })
20
+ .limit(1)
21
+ .maybeSingle();
22
+ if (!cancelled)
23
+ setV(data ? { price: Number(data.price_sent), week: data.target_week, year: data.target_year, at: data.updated_at } : null);
24
+ };
25
+ void load();
26
+ const t = setInterval(load, 30000);
27
+ return () => {
28
+ cancelled = true;
29
+ clearInterval(t);
30
+ };
31
+ }, [tradeItemId]);
32
+ return v;
33
+ }
4
34
  function formatDate(iso) {
5
35
  if (!iso)
6
36
  return "—";
@@ -17,11 +47,15 @@ function formatDate(iso) {
17
47
  }
18
48
  export function PriceStatusBadge({ tradeItemId, offerForSale }) {
19
49
  const { data: supplyLine, isLoading } = useTradeItemSupplyLine(tradeItemId);
50
+ const sent = useLastSentPrice(tradeItemId);
20
51
  if (!tradeItemId)
21
52
  return null;
22
53
  if (isLoading) {
23
54
  return (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs px-2 py-0.5 rounded-full bg-muted text-muted-foreground", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin" }), " Prijsstatus laden\u2026"] }));
24
55
  }
56
+ if (!supplyLine && sent) {
57
+ return (_jsxs("span", { className: "inline-flex items-center gap-1 text-xs px-2 py-0.5 rounded-full cursor-help bg-emerald-100 text-emerald-700", title: `Weekaanbod verzonden op ${new Date(sent.at).toLocaleString("nl-NL")}`, children: [_jsx(CircleDollarSign, { className: "h-3 w-3" }), " Prijs live in Floriday \u00B7 week ", sent.week ?? "?", " \u00B7 \u20AC ", sent.price.toFixed(2)] }));
58
+ }
25
59
  const now = Date.now();
26
60
  const endMs = supplyLine?.period_end ? new Date(supplyLine.period_end).getTime() : null;
27
61
  const qty = supplyLine?.available_quantity ?? 0;
@@ -1 +1 @@
1
- {"version":3,"file":"ProductSalePriceField.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ProductSalePriceField.tsx"],"names":[],"mappings":"AAkBA,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,OAAO,GACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,sCAkGA;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,sCAmCtE"}
1
+ {"version":3,"file":"ProductSalePriceField.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/ProductSalePriceField.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,OAAO,GACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,sCAkGA;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,sCAqCtE"}
@@ -11,6 +11,7 @@ import { Link } from "@tanstack/react-router";
11
11
  import { Button, Input, Label, toast } from "@flowselections/core";
12
12
  import { AlertTriangle, Loader2 } from "lucide-react";
13
13
  import { supabase } from "../../integrations/supabase/client";
14
+ import { priceProblem } from "../../lib/floriday-base-supply";
14
15
  function isPieceUnit(unit) {
15
16
  const u = String(unit ?? "").trim().toLowerCase();
16
17
  return u === "" || u === "stuks" || u === "stuk";
@@ -81,11 +82,12 @@ export function ProductSalePriceField({ productId, onSaved, }) {
81
82
  };
82
83
  if (!exists)
83
84
  return null;
84
- return (_jsxs("div", { id: "verkoopprijs", className: "space-y-2 rounded-md border p-4", children: [_jsx(Label, { htmlFor: `price-${productId}`, children: "Verkoopprijs per stuk (excl. btw)" }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Input, { id: `price-${productId}`, inputMode: "decimal", className: "w-40", placeholder: "Bijv. 1,40", disabled: !loaded || saving, value: value, onChange: (e) => setValue(e.target.value) }), _jsxs(Button, { size: "sm", disabled: !dirty || saving, onClick: () => void save(), children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), saving ? "Bezig met opslaan…" : "Prijs opslaan"] })] }), value.trim() !== "" && !valid && (_jsx("p", { className: "text-xs text-destructive", children: "Vul een prijs groter dan 0 in, met maximaal 5 decimalen." })), loaded && !isPieceUnit(unit) && (_jsxs("p", { className: "text-xs text-amber-700", children: ["Eenheid onduidelijk (", unit, "): de prijs telt voor Floriday alleen bij eenheid \"stuks\"."] })), loaded && !(saved && saved > 0) && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Zonder prijs komt dit artikel niet in Floriday (\"Prijs ontbreekt\")." })), error && _jsx("p", { role: "alert", className: "text-xs text-destructive", children: error })] }));
85
+ return (_jsxs("div", { id: "verkoopprijs", className: "space-y-2 rounded-md border p-4", children: [_jsx(Label, { htmlFor: `price-${productId}`, children: "Verkoopprijs per stuk (excl. btw)" }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Input, { id: `price-${productId}`, inputMode: "decimal", className: "w-40", placeholder: "Bijv. 1,40", disabled: !loaded || saving, value: value, onChange: (e) => setValue(e.target.value) }), _jsxs(Button, { size: "sm", disabled: !dirty || saving, onClick: () => void save(), children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), saving ? "Bezig met opslaan…" : "Prijs opslaan"] })] }), value.trim() !== "" && !valid && (_jsx("p", { className: "text-xs text-destructive", children: "Vul een prijs groter dan 0 in, met maximaal 5 decimalen." })), loaded && !isPieceUnit(unit) && (_jsxs("p", { className: "text-xs text-amber-700", children: ["Eenheid is geen stuks (nu: ", unit, "): de prijs telt voor Floriday alleen bij eenheid \"stuks\"."] })), loaded && !(saved && saved > 0) && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Zonder prijs komt dit artikel niet in Floriday (\"Prijs ontbreekt\")." })), error && _jsx("p", { role: "alert", className: "text-xs text-destructive", children: error })] }));
85
86
  }
86
87
  /** Melding met directe link naar het prijsveld; toont niets als de prijs in orde is. */
87
88
  export function MissingPriceNotice({ productId }) {
88
89
  const [state, setState] = useState(null);
90
+ const [why, setWhy] = useState(null);
89
91
  useEffect(() => {
90
92
  let cancelled = false;
91
93
  (async () => {
@@ -96,6 +98,7 @@ export function MissingPriceNotice({ productId }) {
96
98
  .maybeSingle();
97
99
  if (cancelled || !data)
98
100
  return;
101
+ setWhy(priceProblem(data.sale_price, data.unit));
99
102
  if (!isPieceUnit(data.unit))
100
103
  setState("unit");
101
104
  else
@@ -107,5 +110,5 @@ export function MissingPriceNotice({ productId }) {
107
110
  }, [productId]);
108
111
  if (state !== "missing" && state !== "unit")
109
112
  return null;
110
- return (_jsxs("div", { className: "flex flex-wrap items-center 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: "h-4 w-4 shrink-0" }), _jsx("span", { className: "flex-1", children: state === "missing" ? "Prijs ontbreekt: dit artikel gaat niet naar Floriday." : "Eenheid onduidelijk: de prijs telt alleen per stuk." }), _jsx(Link, { to: "/voorraad/$id", params: { id: productId }, hash: "verkoopprijs", className: "font-medium underline", children: "Prijs invullen" })] }));
113
+ return (_jsxs("div", { className: "flex flex-wrap items-center 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: "h-4 w-4 shrink-0" }), _jsxs("span", { className: "flex-1", children: [why ?? (state === "missing" ? "Prijs ontbreekt" : "Eenheid is geen stuks"), ": dit artikel gaat niet naar Floriday."] }), _jsx(Link, { to: "/voorraad/$id", params: { id: productId }, hash: "verkoopprijs", className: "font-medium underline", children: "Prijs invullen" })] }));
111
114
  }
@@ -26394,6 +26394,7 @@ export type Database = {
26394
26394
  created_by: string;
26395
26395
  customer_id: string | null;
26396
26396
  id: string;
26397
+ offerte_id: string | null;
26397
26398
  payload: Json;
26398
26399
  reden: string | null;
26399
26400
  status: string;
@@ -26409,6 +26410,7 @@ export type Database = {
26409
26410
  created_by?: string;
26410
26411
  customer_id?: string | null;
26411
26412
  id?: string;
26413
+ offerte_id?: string | null;
26412
26414
  payload?: Json;
26413
26415
  reden?: string | null;
26414
26416
  status?: string;
@@ -26424,6 +26426,7 @@ export type Database = {
26424
26426
  created_by?: string;
26425
26427
  customer_id?: string | null;
26426
26428
  id?: string;
26429
+ offerte_id?: string | null;
26427
26430
  payload?: Json;
26428
26431
  reden?: string | null;
26429
26432
  status?: string;
@@ -29810,6 +29813,12 @@ export type Database = {
29810
29813
  };
29811
29814
  Returns: string;
29812
29815
  };
29816
+ logistics_afhandeling_fulfillment_order: {
29817
+ Args: {
29818
+ _order_id: string;
29819
+ };
29820
+ Returns: Json;
29821
+ };
29813
29822
  logistics_allocation_check_changes: {
29814
29823
  Args: {
29815
29824
  p_order_item_ids?: string[];
@@ -31934,6 +31943,14 @@ export type Database = {
31934
31943
  };
31935
31944
  Returns: Json;
31936
31945
  };
31946
+ logistics_shipping_note_wait_reasons: {
31947
+ Args: never;
31948
+ Returns: {
31949
+ order_number: string;
31950
+ reden: string;
31951
+ wacht_sinds: string;
31952
+ }[];
31953
+ };
31937
31954
  logistics_shipping_note_wake: {
31938
31955
  Args: {
31939
31956
  _slip_job_id: string;
@@ -35375,6 +35392,13 @@ export type Database = {
35375
35392
  };
35376
35393
  Returns: Json;
35377
35394
  };
35395
+ wo_send_proposal_to_quote: {
35396
+ Args: {
35397
+ _id: string;
35398
+ _overrides?: Json;
35399
+ };
35400
+ Returns: Json;
35401
+ };
35378
35402
  wo_send_to_quote: {
35379
35403
  Args: {
35380
35404
  _werkbon_id: string;