Verwendungsstatus: Backend fuer "getragen / in Reinigung / in Reparatur"
Einzelstuecke hatten bisher keinen Zustand - der Lagerort sagt, wohin ein
Stueck gehoert, aber nicht, woran es gerade ist. Neue Tabelle item_usages
nach dem Vorbild von item_loans: ein Zeitraum je Zustand, ended_at NULL
heisst "laeuft noch", und ein Teilindex laesst nur einen laufenden zu.
"Verfuegbar" wird bewusst nicht gespeichert - keine offene Zeile IST
verfuegbar, wie bei lots.opened_on und beim Verleih. Damit kostet der
Ruhezustand nichts und die Tabelle fuellt sich nicht mit Rauschen.
Abgeschlossene Zeilen bleiben stehen, sie sind der Verlauf.
Eigener Endpunkt (PUT /items/{id}/verwendung) und ausdruecklich nicht
PATCH /items/{id}: Das ist Admins vorbehalten, und die App schickt dort
immer alle Felder mitsamt null - jedes Speichern wuerde den Status
stillschweigend zuruecksetzen. Umstellen darf deshalb jeder angemeldete
Benutzer, wie Verleihen.
Der Zustand aendert den Bestand nicht und schreibt keine Bewegung: ein
getragenes Hemd ist weiterhin im Haushalt, anders als ein verliehenes.
Sichtbar nur bei Kategorien mit usage_tracking. Ein Haken an einer
Oberkategorie wandert in den Unterbaum, weil die Garderobe als
Kategoriebaum ja schon existiert. Die Markierung fahrt in beiden
Sicherungswegen mit; der Verlauf nicht, weil Einzelstuecke dort
ueberhaupt nicht vorkommen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8c752e3d1f
commit
98e2d18142
@@ -6,8 +6,8 @@ import secrets
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models import Item, ItemLoan
|
||||
from ..schemas import ItemKurz, ItemOut
|
||||
from ..models import Item, ItemLoan, ItemUsage
|
||||
from ..schemas import ItemKurz, ItemOut, VerwendungOut
|
||||
from .loans import loan_to_out
|
||||
|
||||
# Ohne 0/O/1/I/L, damit die UID auf einem Etikett eindeutig lesbar bleibt.
|
||||
@@ -34,6 +34,26 @@ def _offener(item: Item) -> ItemLoan | None:
|
||||
return None
|
||||
|
||||
|
||||
def _offene_verwendung(item: Item) -> ItemUsage | None:
|
||||
"""Der laufende Verwendungszustand aus den schon geladenen Zeitraeumen.
|
||||
|
||||
Wie ``_offener``: ueber die Beziehung statt per eigener Abfrage, damit die
|
||||
Einzelstueck-Liste nicht je Zeile nachfragt. Keine offene Zeile heisst
|
||||
verfuegbar - dafuer gibt es keinen gespeicherten Wert.
|
||||
"""
|
||||
for usage in item.usages:
|
||||
if usage.ended_at is None:
|
||||
return usage
|
||||
return None
|
||||
|
||||
|
||||
def verwendung_to_out(usage: ItemUsage) -> VerwendungOut:
|
||||
"""VerwendungOut samt Konto, das umgestellt hat."""
|
||||
out = VerwendungOut.model_validate(usage)
|
||||
out.username = usage.user.username if usage.user else None
|
||||
return out
|
||||
|
||||
|
||||
def item_kurz(item: Item) -> ItemKurz:
|
||||
"""Ein verknuepftes Stueck in Kurzform (Zubehoer, Geraet)."""
|
||||
return ItemKurz(
|
||||
@@ -59,6 +79,11 @@ def item_to_out(item: Item) -> ItemOut:
|
||||
out.category_name = kategorie.name if kategorie else None
|
||||
loan = _offener(item)
|
||||
out.loan = loan_to_out(loan) if loan is not None else None
|
||||
# Die Kategorie steckt schon oben in ``kategorie`` - die Markierung kostet
|
||||
# deshalb keine zusaetzliche Abfrage (siehe Category.usage_tracking).
|
||||
out.verwendung_moeglich = bool(kategorie.usage_tracking) if kategorie else False
|
||||
verwendung = _offene_verwendung(item)
|
||||
out.verwendung = verwendung_to_out(verwendung) if verwendung is not None else None
|
||||
# Beide Richtungen ausdruecklich setzen: model_validate wuerde die Beziehung
|
||||
# zwar finden, aber nur die Spalten fuellen - Artikelname und Lagerort des
|
||||
# verknuepften Stuecks blieben leer.
|
||||
|
||||
@@ -35,7 +35,8 @@ def export_master_data(db: Session) -> dict:
|
||||
return {
|
||||
FORMAT_KEY: FORMAT_VERSION,
|
||||
"categories": [
|
||||
{"id": c.id, "name": c.name, "parent_id": c.parent_id, "tracking": c.tracking}
|
||||
{"id": c.id, "name": c.name, "parent_id": c.parent_id,
|
||||
"tracking": c.tracking, "usage_tracking": c.usage_tracking}
|
||||
for c in db.query(Category).order_by(Category.id).all()
|
||||
],
|
||||
"field_definitions": [
|
||||
@@ -152,6 +153,7 @@ def import_master_data(db: Session, data: dict, mode: str = "skip") -> dict:
|
||||
for row in cats:
|
||||
upsert(Category, row, "categories", lambda r: {
|
||||
"name": r["name"], "tracking": r.get("tracking") or "food",
|
||||
"usage_tracking": bool(r.get("usage_tracking", False)),
|
||||
}, is_tree=True)
|
||||
set_parents(Category, cats)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user