Web: Mindestbestaende in echter Einheit statt Packung
"1 Packung" ist nichtssagend (kann 500 g, 1 kg oder 25 ml sein). Die Seite zeigt und bearbeitet Produkt-Mindestbestaende jetzt in der Anzeigeeinheit des Artikels (Gramm/Milliliter/Stueck): global (Basiseinheiten) und je Lagerort (Artikel- einheiten) werden dafuer umgerechnet. Rigatoni zeigt jetzt z.B. "500 Gramm". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,14 +8,15 @@ import { categoryInfoMap } from "../categoryPath";
|
|||||||
import { locationPathById } from "../locationPath";
|
import { locationPathById } from "../locationPath";
|
||||||
import { fmt } from "../units";
|
import { fmt } from "../units";
|
||||||
|
|
||||||
// Artikeleinheit eines Produkts (Gebinde oder Produkteinheit) – wie in der Produktliste.
|
// Anzeigeeinheit eines Produkts: die im Formular gewählte Einheit (Gramm,
|
||||||
// Wichtig: Zahl (articleUnit) und Bezeichnung (articleLabel) müssen zusammenpassen –
|
// Milliliter, Stück) – NICHT die Packung. „1 Packung" ist nichtssagend, weil eine
|
||||||
// bei vorhandener Packungsgröße also „Packung" und NICHT die Basiseinheit, sonst steht
|
// Packung 500 g, 1 kg oder 25 ml sein kann; deshalb rechnen wir alles in die
|
||||||
// z.B. „1 Gramm" statt „1 Packung" (500 g) da.
|
// 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 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
|
* Zentrale Liste aller Mindestbestände: je Produkt/Gruppe der Gesamt-Wert und die
|
||||||
@@ -53,15 +54,19 @@ export default function MinStock() {
|
|||||||
out.push({
|
out.push({
|
||||||
key: `p:${p.id}:global`, kind: "product", scope: "global", entity: p,
|
key: `p:${p.id}:global`, kind: "product", scope: "global", entity: p,
|
||||||
name: p.name, catId: p.category_id, ort: "(Gesamt)",
|
name: p.name, catId: p.category_id, ort: "(Gesamt)",
|
||||||
soll: p.min_stock_display, unit: p.min_stock_unit_label || articleLabel(p),
|
// Alles in der Anzeigeeinheit (Gramm/Milliliter/Stück): min_stock ist in
|
||||||
bestand: p.stock / articleUnit(p), bestandUnit: articleLabel(p),
|
// 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 || [])) {
|
for (const l of (p.location_min_stocks || [])) {
|
||||||
out.push({
|
out.push({
|
||||||
key: `p:${p.id}:${l.location_id}`, kind: "product", scope: "loc", entity: p,
|
key: `p:${p.id}:${l.location_id}`, kind: "product", scope: "loc", entity: p,
|
||||||
locId: l.location_id, name: p.name, catId: p.category_id,
|
locId: l.location_id, name: p.name, catId: p.category_id,
|
||||||
ort: locationPathById(l.location_id, locations) || "?",
|
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 {
|
try {
|
||||||
if (row.kind === "product" && row.scope === "global") {
|
if (row.kind === "product" && row.scope === "global") {
|
||||||
const p = row.entity;
|
const p = row.entity;
|
||||||
// Faktor aus dem bestehenden Wert ableiten (erhält die erfasste Einheit);
|
// Eingabe in der Anzeigeeinheit → Basiseinheiten speichern.
|
||||||
// ohne bestehenden Wert in Artikeleinheiten setzen.
|
await api.updateProduct(p.id, {
|
||||||
if (p.min_stock != null && p.min_stock_display) {
|
min_stock: num == null ? null : Math.round(num * dispFactor(p)),
|
||||||
const faktor = p.min_stock / p.min_stock_display;
|
min_stock_in_packages: false,
|
||||||
await api.updateProduct(p.id, { min_stock: num == null ? null : Math.round(num * faktor) });
|
min_stock_unit_id: p.display_unit_id ?? null,
|
||||||
} 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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (row.kind === "product" && row.scope === "loc") {
|
} 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") {
|
} else if (row.kind === "group" && row.scope === "global") {
|
||||||
await api.updateGroup(row.entity.id, { min_stock: num });
|
await api.updateGroup(row.entity.id, { min_stock: num });
|
||||||
} else if (row.kind === "group" && row.scope === "loc") {
|
} 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))
|
? products.find((p) => String(p.id) === String(draft.targetId))
|
||||||
: groups.find((g) => String(g.id) === String(draft.targetId));
|
: groups.find((g) => String(g.id) === String(draft.targetId));
|
||||||
const draftUnit = draft.kind === "product"
|
const draftUnit = draft.kind === "product"
|
||||||
? (draftTarget ? articleLabel(draftTarget) : "")
|
? (draftTarget ? dispLabel(draftTarget) : "")
|
||||||
: (draftTarget ? (draftTarget.min_stock_unit_name || "Stück") : "");
|
: (draftTarget ? (draftTarget.min_stock_unit_name || "Stück") : "");
|
||||||
|
|
||||||
function resetAdd() {
|
function resetAdd() {
|
||||||
@@ -143,15 +145,16 @@ export default function MinStock() {
|
|||||||
if (draft.kind === "product") {
|
if (draft.kind === "product") {
|
||||||
const p = draftTarget;
|
const p = draftTarget;
|
||||||
if (draft.scope === "global") {
|
if (draft.scope === "global") {
|
||||||
// Menge in der Artikeleinheit erfasst → in Basiseinheiten speichern,
|
// Menge in der Anzeigeeinheit erfasst → in Basiseinheiten speichern.
|
||||||
// wie beim Inline-Editieren ohne bestehenden Wert.
|
|
||||||
await api.updateProduct(p.id, {
|
await api.updateProduct(p.id, {
|
||||||
min_stock: Math.round(num * articleUnit(p)),
|
min_stock: Math.round(num * dispFactor(p)),
|
||||||
min_stock_in_packages: (p.package_size || 0) > 0,
|
min_stock_in_packages: false,
|
||||||
min_stock_unit_id: null,
|
min_stock_unit_id: p.display_unit_id ?? null,
|
||||||
});
|
});
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
const g = draftTarget;
|
const g = draftTarget;
|
||||||
|
|||||||
Reference in New Issue
Block a user