Web: Mindestbestaende per Loesch-Knopf entfernbar
Loeschen ging bisher nur uebers Leeren des Zahlenfeldes - das war weder auffindbar noch (bei Gesamt-Werten, deren Zeile bestehen bleibt) sichtbar. Jetzt hat jede gesetzte Zeile einen Papierkorb-Knopf: Gesamt-Wert -> NULL, je-Lagerort-Eintrag faellt raus. Mit Rueckfrage ueber den App-Dialog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { api } from "../api";
|
import { api } from "../api";
|
||||||
import { useAuth } from "../auth";
|
import { useAuth } from "../auth";
|
||||||
|
import { useConfirm } from "../confirm";
|
||||||
import Icon from "../components/Icon";
|
import Icon from "../components/Icon";
|
||||||
import DataTable from "../components/DataTable";
|
import DataTable from "../components/DataTable";
|
||||||
import CategoryPathLabel, { pathParts } from "../components/CategoryPathLabel";
|
import CategoryPathLabel, { pathParts } from "../components/CategoryPathLabel";
|
||||||
@@ -30,6 +31,7 @@ const EMPTY_DRAFT = { kind: "product", targetId: "", scope: "global", locId: "",
|
|||||||
|
|
||||||
export default function MinStock() {
|
export default function MinStock() {
|
||||||
const { isAdmin } = useAuth();
|
const { isAdmin } = useAuth();
|
||||||
|
const confirm = useConfirm();
|
||||||
const [products, setProducts] = useState([]);
|
const [products, setProducts] = useState([]);
|
||||||
const [groups, setGroups] = useState([]);
|
const [groups, setGroups] = useState([]);
|
||||||
const [locations, setLocations] = useState([]);
|
const [locations, setLocations] = useState([]);
|
||||||
@@ -132,6 +134,35 @@ export default function MinStock() {
|
|||||||
} catch (err) { setError(err.message); }
|
} catch (err) { setError(err.message); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mindestbestand ganz entfernen: Gesamt-Wert auf NULL, je-Lagerort-Eintrag raus.
|
||||||
|
// Das Feld leeren tut dasselbe – aber ein eigener Knopf macht das Löschen
|
||||||
|
// eindeutig (und bei Gesamt-Werten sichtbar, da die Zeile sonst bestehen bleibt).
|
||||||
|
async function deleteRow(row) {
|
||||||
|
const ziel = row.kind === "group" ? `Gruppe „${row.name}"` : `„${row.name}"`;
|
||||||
|
const wo = row.scope === "loc" ? ` am Lagerort „${row.ort}"` : "";
|
||||||
|
if (!(await confirm({
|
||||||
|
title: "Mindestbestand löschen?",
|
||||||
|
message: `Mindestbestand von ${ziel}${wo} entfernen?`,
|
||||||
|
confirmLabel: "Löschen", danger: true,
|
||||||
|
}))) return;
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
if (row.kind === "product" && row.scope === "global") {
|
||||||
|
await api.updateProduct(row.entity.id, {
|
||||||
|
min_stock: null, min_stock_in_packages: false,
|
||||||
|
min_stock_unit_id: row.entity.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, null));
|
||||||
|
} else if (row.kind === "group" && row.scope === "global") {
|
||||||
|
await api.updateGroup(row.entity.id, { min_stock: null });
|
||||||
|
} else if (row.kind === "group" && row.scope === "loc") {
|
||||||
|
await api.setGroupLocationMinStock(row.entity.id, mergeLoc(row.entity.location_min_stocks, row.locId, null));
|
||||||
|
}
|
||||||
|
await load();
|
||||||
|
} catch (err) { setError(err.message); }
|
||||||
|
}
|
||||||
|
|
||||||
// Ausgewähltes Ziel des Dialogs + dessen Einheit (Menge wird darin erfasst).
|
// Ausgewähltes Ziel des Dialogs + dessen Einheit (Menge wird darin erfasst).
|
||||||
const draftTarget = draft.kind === "product"
|
const draftTarget = draft.kind === "product"
|
||||||
? products.find((p) => String(p.id) === String(draft.targetId))
|
? products.find((p) => String(p.id) === String(draft.targetId))
|
||||||
@@ -195,12 +226,18 @@ export default function MinStock() {
|
|||||||
: <span className="muted">–</span>) },
|
: <span className="muted">–</span>) },
|
||||||
{ key: "ort", header: "Ort", width: 220, filterText: (r) => r.ort, sortValue: (r) => r.ort,
|
{ key: "ort", header: "Ort", width: 220, filterText: (r) => r.ort, sortValue: (r) => r.ort,
|
||||||
render: (r) => (r.scope === "global" ? <span className="muted">{r.ort}</span> : r.ort) },
|
render: (r) => (r.scope === "global" ? <span className="muted">{r.ort}</span> : r.ort) },
|
||||||
{ key: "soll", header: "Mindestbestand", width: 150,
|
{ key: "soll", header: "Mindestbestand", width: 190,
|
||||||
sortValue: (r) => r.soll ?? -1,
|
sortValue: (r) => r.soll ?? -1,
|
||||||
render: (r) => (isAdmin ? (
|
render: (r) => (isAdmin ? (
|
||||||
<input type="number" step="any" min="0" style={{ marginTop: 0, minWidth: 80 }}
|
<div className="field-inline" style={{ gap: "var(--sp-1)", flexWrap: "nowrap" }}>
|
||||||
key={r.soll ?? "none"} defaultValue={r.soll ?? ""}
|
<input type="number" step="any" min="0" style={{ marginTop: 0, minWidth: 80 }}
|
||||||
onBlur={(e) => saveSoll(r, e.target.value)} />
|
key={r.soll ?? "none"} defaultValue={r.soll ?? ""}
|
||||||
|
onBlur={(e) => saveSoll(r, e.target.value)} />
|
||||||
|
{r.soll != null && (
|
||||||
|
<button type="button" className="btn-icon danger" title="Mindestbestand löschen"
|
||||||
|
onClick={() => deleteRow(r)}><Icon name="trash" size={15} /></button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
) : (r.soll != null ? fmt(r.soll) : "–")) },
|
) : (r.soll != null ? fmt(r.soll) : "–")) },
|
||||||
{ key: "unit", header: "Einheit", width: 120, filterText: (r) => r.unit || "",
|
{ key: "unit", header: "Einheit", width: 120, filterText: (r) => r.unit || "",
|
||||||
render: (r) => <span className="muted">{r.unit || "–"}</span> },
|
render: (r) => <span className="muted">{r.unit || "–"}</span> },
|
||||||
|
|||||||
Reference in New Issue
Block a user