Verlauf zeigt Mengen in Artikeleinheiten (Gebinde) statt nur Basiseinheit

MovementOut liefert jetzt package_size, package_label sowie Name/Faktor der
Anzeigeeinheit mit. Die Verlauf-Tabelle zeigt die Bewegung als Leitangabe in
Gebinden (z.B. "1 Glas") und darunter klein die Basiseinheit ("195 g").
Ohne Gebinde/abweichende Einheit bleibt es bei einer Zeile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-22 13:58:50 +02:00
parent 0bc141a1be
commit 2f1be8e2dd
3 changed files with 34 additions and 3 deletions

View File

@@ -7,7 +7,7 @@ from ..database import get_db
from ..deps import get_current_user
from ..models import Group, Lot, Movement, Product, User
from ..schemas import ExpiringItem, GroupShoppingItem, MovementOut, ShoppingItem
from ..services.conversion import BASE_OF_KIND
from ..services.conversion import BASE_OF_KIND, display_unit_info
from ..services.stock import current_stock
from .settings import get_expiry_warning_days
@@ -138,6 +138,7 @@ def movements(
result: list[MovementOut] = []
for movement, product, user in rows:
unit_name, unit_factor = display_unit_info(product)
result.append(
MovementOut(
id=movement.id,
@@ -150,6 +151,10 @@ def movements(
username=user.username if user else None,
note=movement.note,
created_at=movement.created_at,
package_size=product.package_size,
package_label=product.package_label,
unit_name=unit_name,
unit_factor=unit_factor,
)
)
return result

View File

@@ -265,12 +265,17 @@ class MovementOut(BaseModel):
product_id: int
product_name: str
type: str
quantity: float
quantity: float # in Basiseinheiten
base_unit: BaseUnit
unit_used: str
username: str | None
note: str | None
created_at: datetime
# Für die Anzeige in Artikeleinheiten:
package_size: float | None = None
package_label: str | None = None
unit_name: str = ""
unit_factor: float = 1.0
class SettingOut(BaseModel):

View File

@@ -5,6 +5,22 @@ import { fmt, unitShort } from "../units";
const TYPE_LABEL = { in: "Eingelagert", out: "Ausgelagert", adjust: "Korrektur" };
// Leitangabe in Artikeleinheiten (Gebinde), sonst in der Produkteinheit.
function primaryAmount(m) {
if (m.package_size > 0) {
return `${fmt(m.quantity / m.package_size)} ${m.package_label || "Packung"}`;
}
return `${fmt(m.quantity / (m.unit_factor || 1))} ${m.unit_name || unitShort(m.base_unit)}`;
}
// Untermenge in der Basiseinheit nur wenn sie sich von der Leitangabe unterscheidet.
function secondaryAmount(m) {
if (m.package_size > 0 || (m.unit_factor || 1) !== 1) {
return `${fmt(m.quantity)} ${unitShort(m.base_unit)}`;
}
return "";
}
export default function History() {
const [movements, setMovements] = useState([]);
const [error, setError] = useState(null);
@@ -46,7 +62,12 @@ export default function History() {
</span>
</td>
<td>{m.product_name}</td>
<td className="num">{fmt(m.quantity)} {unitShort(m.base_unit)}</td>
<td className="num">
{primaryAmount(m)}
{secondaryAmount(m) && (
<div className="muted small">{secondaryAmount(m)}</div>
)}
</td>
<td className="muted">{m.username || ""}</td>
</tr>
))}