diff --git a/web/src/pages/MinStock.jsx b/web/src/pages/MinStock.jsx index 39ab182..e85c109 100644 --- a/web/src/pages/MinStock.jsx +++ b/web/src/pages/MinStock.jsx @@ -8,14 +8,15 @@ import { categoryInfoMap } from "../categoryPath"; import { locationPathById } from "../locationPath"; import { fmt } from "../units"; -// Artikeleinheit eines Produkts (Gebinde oder Produkteinheit) – wie in der Produktliste. -// Wichtig: Zahl (articleUnit) und Bezeichnung (articleLabel) müssen zusammenpassen – -// bei vorhandener Packungsgröße also „Packung" und NICHT die Basiseinheit, sonst steht -// z.B. „1 Gramm" statt „1 Packung" (500 g) da. +// Anzeigeeinheit eines Produkts: die im Formular gewählte Einheit (Gramm, +// Milliliter, Stück) – NICHT die Packung. „1 Packung" ist nichtssagend, weil eine +// Packung 500 g, 1 kg oder 25 ml sein kann; deshalb rechnen wir alles in die +// echte Einheit um. dispFactor = Basiseinheiten je Anzeigeeinheit. +const dispFactor = (p) => (p.unit_factor && p.unit_factor > 0 ? p.unit_factor : 1); +const dispLabel = (p) => (p.unit_name || "Stück"); +// Artikeleinheit (Packung, sonst Anzeigeeinheit): nur noch nötig, um die je-Lagerort- +// Mindestbestände umzurechnen, die in Artikeleinheiten gespeichert sind. const articleUnit = (p) => (p.package_size && p.package_size > 0 ? p.package_size : (p.unit_factor || 1)); -const articleLabel = (p) => ( - p.package_size && p.package_size > 0 ? (p.package_label || "Packung") : (p.unit_name || "Stück") -); /** * Zentrale Liste aller Mindestbestände: je Produkt/Gruppe der Gesamt-Wert und die @@ -53,15 +54,19 @@ export default function MinStock() { out.push({ key: `p:${p.id}:global`, kind: "product", scope: "global", entity: p, name: p.name, catId: p.category_id, ort: "(Gesamt)", - soll: p.min_stock_display, unit: p.min_stock_unit_label || articleLabel(p), - bestand: p.stock / articleUnit(p), bestandUnit: articleLabel(p), + // Alles in der Anzeigeeinheit (Gramm/Milliliter/Stück): min_stock ist in + // Basiseinheiten gespeichert. + soll: p.min_stock != null ? p.min_stock / dispFactor(p) : null, + unit: dispLabel(p), + bestand: p.stock / dispFactor(p), bestandUnit: dispLabel(p), }); for (const l of (p.location_min_stocks || [])) { out.push({ key: `p:${p.id}:${l.location_id}`, kind: "product", scope: "loc", entity: p, locId: l.location_id, name: p.name, catId: p.category_id, ort: locationPathById(l.location_id, locations) || "?", - soll: l.min_stock, unit: articleLabel(p), bestand: null, + // je-Lagerort ist in Artikeleinheiten gespeichert → in Anzeigeeinheit umrechnen. + soll: (l.min_stock * articleUnit(p)) / dispFactor(p), unit: dispLabel(p), bestand: null, }); } } @@ -96,20 +101,17 @@ export default function MinStock() { try { if (row.kind === "product" && row.scope === "global") { const p = row.entity; - // Faktor aus dem bestehenden Wert ableiten (erhält die erfasste Einheit); - // ohne bestehenden Wert in Artikeleinheiten setzen. - if (p.min_stock != null && p.min_stock_display) { - const faktor = p.min_stock / p.min_stock_display; - await api.updateProduct(p.id, { min_stock: num == null ? null : Math.round(num * faktor) }); - } else { - await api.updateProduct(p.id, { - min_stock: num == null ? null : Math.round(num * articleUnit(p)), - min_stock_in_packages: (p.package_size || 0) > 0, - min_stock_unit_id: null, - }); - } + // Eingabe in der Anzeigeeinheit → Basiseinheiten speichern. + await api.updateProduct(p.id, { + min_stock: num == null ? null : Math.round(num * dispFactor(p)), + min_stock_in_packages: false, + min_stock_unit_id: p.display_unit_id ?? null, + }); } else if (row.kind === "product" && row.scope === "loc") { - await api.setProductLocationMinStock(row.entity.id, mergeLoc(row.entity.location_min_stocks, row.locId, num)); + const p = row.entity; + // Eingabe in der Anzeigeeinheit → Artikeleinheiten (so gespeichert). + const artikel = num == null ? null : (num * dispFactor(p)) / articleUnit(p); + await api.setProductLocationMinStock(p.id, mergeLoc(p.location_min_stocks, row.locId, artikel)); } else if (row.kind === "group" && row.scope === "global") { await api.updateGroup(row.entity.id, { min_stock: num }); } else if (row.kind === "group" && row.scope === "loc") { @@ -124,7 +126,7 @@ export default function MinStock() { ? products.find((p) => String(p.id) === String(draft.targetId)) : groups.find((g) => String(g.id) === String(draft.targetId)); const draftUnit = draft.kind === "product" - ? (draftTarget ? articleLabel(draftTarget) : "") + ? (draftTarget ? dispLabel(draftTarget) : "") : (draftTarget ? (draftTarget.min_stock_unit_name || "Stück") : ""); function resetAdd() { @@ -143,15 +145,16 @@ export default function MinStock() { if (draft.kind === "product") { const p = draftTarget; if (draft.scope === "global") { - // Menge in der Artikeleinheit erfasst → in Basiseinheiten speichern, - // wie beim Inline-Editieren ohne bestehenden Wert. + // Menge in der Anzeigeeinheit erfasst → in Basiseinheiten speichern. await api.updateProduct(p.id, { - min_stock: Math.round(num * articleUnit(p)), - min_stock_in_packages: (p.package_size || 0) > 0, - min_stock_unit_id: null, + min_stock: Math.round(num * dispFactor(p)), + min_stock_in_packages: false, + min_stock_unit_id: p.display_unit_id ?? null, }); } else { - await api.setProductLocationMinStock(p.id, mergeLoc(p.location_min_stocks, draft.locId, num)); + // Anzeigeeinheit → Artikeleinheiten (so gespeichert). + const artikel = (num * dispFactor(p)) / articleUnit(p); + await api.setProductLocationMinStock(p.id, mergeLoc(p.location_min_stocks, draft.locId, artikel)); } } else { const g = draftTarget;