Chargen: Anzeige und Bearbeitung in derselben Einheit + Zweitangabe

- Chargen werden in der Produkteinheit angezeigt, darunter die Zweitangabe
  (Basiseinheit falls abweichend und/oder Packungen).
- Bearbeiten laeuft jetzt ebenfalls in der Produkteinheit (mit Einheit neben dem
  Feld) und rechnet beim Speichern in die Basiseinheit um - vorher zeigte die
  Bearbeitung einen anderen Wert als die Anzeige.
- Produktkopf zeigt den Bestand zusaetzlich in Packungen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-22 12:44:30 +02:00
parent 6960f9e28d
commit 7a4258a238

View File

@@ -206,6 +206,7 @@ export default function ProductForm() {
{!isNew && product && (
<div className="sub">
Bestand: {fmt(product.stock / (product.unit_factor || 1))} {product.unit_name}
{product.package_size ? ` · ${fmt(product.stock / product.package_size)} Pkg` : ""}
</div>
)}
</div>
@@ -287,7 +288,7 @@ export default function ProductForm() {
{!isNew && (
<LotsCard
productId={id}
product={product}
lots={lots}
baseShort={baseShort}
warnDays={warnDays}
@@ -305,20 +306,31 @@ export default function ProductForm() {
);
}
/** Chargen-Karte mit Bearbeiten/Löschen. */
function LotsCard({ productId, lots, baseShort, warnDays, isAdmin, imageUrl, onChanged, onError }) {
/** Chargen-Karte mit Bearbeiten/Löschen. Bearbeitet wird in der Produkteinheit. */
function LotsCard({ product, lots, baseShort, warnDays, isAdmin, imageUrl, onChanged, onError }) {
const [editId, setEditId] = useState(null);
const [draft, setDraft] = useState({ quantity: "", best_before: "" });
const factor = product?.unit_factor || 1;
const unitName = product?.unit_name || baseShort;
const pkgSize = product?.package_size || 0;
// Zweitangabe: Basiseinheit (falls abweichend) und/oder Packungen.
function secondary(qty) {
const parts = [];
if (factor !== 1) parts.push(`${fmt(qty)} ${baseShort}`);
if (pkgSize > 0) parts.push(`${fmt(qty / pkgSize)} Pkg`);
return parts.join(" · ");
}
function startEdit(l) {
setEditId(l.id);
setDraft({ quantity: l.quantity, best_before: l.best_before || "" });
setDraft({ quantity: l.quantity / factor, best_before: l.best_before || "" });
}
async function saveEdit(l) {
try {
await api.updateLot(l.id, {
quantity: Number(draft.quantity),
quantity: Number(draft.quantity) * factor,
best_before: draft.best_before || null,
});
setEditId(null);
@@ -361,11 +373,19 @@ function LotsCard({ productId, lots, baseShort, warnDays, isAdmin, imageUrl, onC
<tr key={l.id} className={cls}>
<td className="num">
{editing ? (
<input type="number" step="any" min="0" value={draft.quantity}
onChange={(e) => setDraft({ ...draft, quantity: e.target.value })}
style={{ maxWidth: 100, marginTop: 0 }} />
<div className="field-inline" style={{ justifyContent: "flex-end" }}>
<input type="number" step="any" min="0" value={draft.quantity}
onChange={(e) => setDraft({ ...draft, quantity: e.target.value })}
style={{ maxWidth: 90, marginTop: 0 }} />
<span className="muted small">{unitName}</span>
</div>
) : (
<>{fmt(l.quantity)} {baseShort}</>
<>
{fmt(l.quantity / factor)} {unitName}
{secondary(l.quantity) && (
<div className="muted small">{secondary(l.quantity)}</div>
)}
</>
)}
</td>
<td>
@@ -406,7 +426,10 @@ function LotsCard({ productId, lots, baseShort, warnDays, isAdmin, imageUrl, onC
</tbody>
</table>
</div>
<p className="muted small">Mengen sind in der Basiseinheit ({baseShort}) angegeben.</p>
<p className="muted small">
Mengen in {unitName}
{pkgSize > 0 ? `; 1 Packung = ${fmt(pkgSize)} ${baseShort}` : ""}.
</p>
</section>
);
}