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

View File

@@ -265,12 +265,17 @@ class MovementOut(BaseModel):
product_id: int product_id: int
product_name: str product_name: str
type: str type: str
quantity: float quantity: float # in Basiseinheiten
base_unit: BaseUnit base_unit: BaseUnit
unit_used: str unit_used: str
username: str | None username: str | None
note: str | None note: str | None
created_at: datetime 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): class SettingOut(BaseModel):

View File

@@ -5,6 +5,22 @@ import { fmt, unitShort } from "../units";
const TYPE_LABEL = { in: "Eingelagert", out: "Ausgelagert", adjust: "Korrektur" }; 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() { export default function History() {
const [movements, setMovements] = useState([]); const [movements, setMovements] = useState([]);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -46,7 +62,12 @@ export default function History() {
</span> </span>
</td> </td>
<td>{m.product_name}</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> <td className="muted">{m.username || ""}</td>
</tr> </tr>
))} ))}