import { useEffect, useState } from "react"; import { api } from "../api"; import { useConfirm } from "../confirm"; import { useToast } from "../toast"; import Icon from "./Icon"; import { fmt } from "../units"; // Gründe zum Entfernen (Wert = Backend-Enum, Label = Anzeige). export const REASONS = [ { value: "broken", label: "kaputt" }, { value: "lost", label: "verloren" }, { value: "given_away", label: "verschenkt" }, { value: "sold", label: "verkauft" }, { value: "used_up", label: "aufgebraucht" }, { value: "other", label: "sonstiges" }, ]; const reasonLabel = (v) => REASONS.find((r) => r.value === v)?.label || v; /** * Bestand eines Gegenstands je Lagerort – das Gegenstück zur Chargen-Karte der * Lebensmittel. Erlaubt Hinzufügen, Umlagern (ohne Grund) und Entfernen (mit * Pflicht-Grund) und zeigt eine kleine Entnahme-Statistik. */ export default function ObjektBestand({ product, lots, locations, isAdmin, onChanged, onError }) { const confirm = useConfirm(); const toast = useToast(); const einheit = product?.unit_name || "Stück"; const nameById = Object.fromEntries((locations || []).map((l) => [l.id, l.name])); const ortName = (id) => (id == null ? "Ohne Lagerort" : nameById[id] || `Ort ${id}`); const [addForm, setAddForm] = useState({ location_id: "", quantity: "" }); const [move, setMove] = useState(null); // { from, to, quantity } | null const [remove, setRemove] = useState(null); // { location_id, quantity, reason, note } | null const [editId, setEditId] = useState(null); const [editQty, setEditQty] = useState(""); const [removals, setRemovals] = useState({ stats: [], history: [] }); async function ladeRemovals() { try { setRemovals(await api.productRemovals(product.id)); } catch { /* Statistik ist optional */ } } useEffect(() => { ladeRemovals(); /* eslint-disable-next-line */ }, [product.id, lots]); async function nachAktion() { await onChanged(); await ladeRemovals(); } async function hinzufuegen(e) { e.preventDefault(); const menge = Number(addForm.quantity); if (!menge || menge <= 0) return; try { await api.checkIn({ product_id: product.id, quantity: menge, unit: einheit, location_id: addForm.location_id === "" ? null : Number(addForm.location_id), }); setAddForm({ location_id: addForm.location_id, quantity: "" }); await nachAktion(); } catch (err) { onError(err.message); } } async function speichereMenge(lot) { const menge = Number(editQty); try { await api.updateLot(lot.id, { quantity: menge }); setEditId(null); await nachAktion(); } catch (err) { onError(err.message); } } async function loescheZeile(lot) { const ok = await confirm({ title: `Bestand in „${ortName(lot.location_id)}“ entfernen?`, message: "Die Menge wird als Korrektur im Verlauf protokolliert.", confirmLabel: "Entfernen", danger: true, }); if (!ok) return; try { await api.deleteLot(lot.id); await nachAktion(); } catch (err) { onError(err.message); } } async function umlagern(e) { e.preventDefault(); const menge = Number(move.quantity); if (!menge || menge <= 0) return; try { await api.relocateStock({ product_id: product.id, quantity: menge, from_location_id: move.from === "" ? null : Number(move.from), to_location_id: move.to === "" ? null : Number(move.to), }); setMove(null); toast("Umgelagert."); await nachAktion(); } catch (err) { onError(err.message); } } async function entfernen(e) { e.preventDefault(); const menge = Number(remove.quantity); if (!menge || menge <= 0) return; try { await api.removeStock({ product_id: product.id, quantity: menge, location_id: remove.location_id === "" ? null : Number(remove.location_id), reason: remove.reason, note: remove.note || null, }); setRemove(null); toast("Aus dem Bestand entfernt."); await nachAktion(); } catch (err) { onError(err.message); } } const gesamt = lots.reduce((s, l) => s + l.quantity, 0); return (

Bestand je Lagerort

gesamt {fmt(gesamt)} {einheit}
{lots.map((l) => ( ))} {lots.length === 0 && }
LagerortMenge
{ortName(l.location_id)} {editId === l.id ? ( setEditQty(e.target.value)} /> ) : ( <>{fmt(l.quantity)} {einheit} )} {isAdmin && (editId === l.id ? (
) : (
))}
Noch kein Bestand.
{isAdmin && (
)} {/* Umlagern-Dialog */} {isAdmin && move && (

Umlagern

)} {/* Entfernen-Dialog (Grund Pflicht) */} {isAdmin && remove && (

Aus Bestand entfernen

)} {/* Entnahme-Statistik */} {removals.stats.length > 0 && (
Bereits entnommen: {removals.stats.map((s) => ( {reasonLabel(s.reason)}: {fmt(s.quantity)} ))}
{removals.history.length > 0 && ( )}
)}
); }