Gruppen: Bestand in der richtigen Einheit, Baumansicht, Gruppen-Spalte
Anzeigefehler: die Gruppenliste klebte immer min_stock_unit_name hinter den
Bestand - auch wenn die Gruppe laengst im Gruppen-Gebinde zaehlt. Aus 790 g bei
einem 190-g-Glas wurde so "4,16 Gramm" statt "4,16 Glaeser". Gerechnet war
richtig, beschriftet falsch.
Ursache war doppelte Logik: MinStock.jsx hatte grpPkgMode/grpFactor/grpUnit
lokal, Groups.jsx gar nicht. Die drei stehen jetzt in units.js und werden von
beiden benutzt. Die Einheiten-Spalte sagt ausserdem, wenn eine Gruppe im
Gebinde zaehlt ("zaehlt in Glaeser a 190 g") und bietet den Weg zurueck an.
Gruppenliste als Baum: eine Gruppe mit zwei Obergruppen erscheint unter beiden -
das ist die ehrliche Darstellung eines Graphen. Jede Zeile traegt ihren PFAD als
Schluessel, damit die vorhandene Baumlogik der DataTable unveraendert zurecht
kommt; die kennt nur einen Elternteil je Zeile, und ein Pfad hat genau einen.
Beim Sortieren/Filtern flacht sie wie gewohnt ab.
"1 Untergruppen" heisst jetzt "1 Untergruppe" - an allen vier Stellen ueber
einen gemeinsamen Helfer (anzahlWort), Web und App.
Lebensmittelliste bekommt eine Spalte "Gruppe" mit Filter. Dafuer liefert
ProductOut jetzt group_name, symmetrisch zu category_name, mit joinedload gegen
N+1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -101,6 +101,7 @@ def product_to_out(db: Session, product: Product) -> ProductOut:
|
||||
for b in db.query(Barcode).filter(Barcode.product_id == product.id).order_by(Barcode.id).all()
|
||||
]
|
||||
out.category_name = product.category.name if product.category else None
|
||||
out.group_name = product.group.name if product.group else None
|
||||
# Bild-Version = Epoch der letzten Bildänderung (identisch zum ETag der
|
||||
# Bild-Route), damit der Client nur geänderte Bilder neu lädt. None = kein Bild.
|
||||
bild_ts = (
|
||||
@@ -198,6 +199,7 @@ def products_to_out_bulk(db: Session, products: list[Product]) -> list[ProductOu
|
||||
o.expired_count = expired.get(product.id, 0)
|
||||
o.barcodes = [BarcodeOut.model_validate(b) for b in codes.get(product.id, [])]
|
||||
o.category_name = product.category.name if product.category else None
|
||||
o.group_name = product.group.name if product.group else None
|
||||
ts = imgs.get(product.id)
|
||||
o.image_version = int(ts.timestamp()) if ts is not None else None
|
||||
o.tracking = CategoryTracking(product_tracking(db, product))
|
||||
|
||||
@@ -141,6 +141,7 @@ def list_products(
|
||||
query = db.query(Product).options(
|
||||
# Relationen vorab laden, damit products_to_out_bulk kein N+1 auslöst.
|
||||
joinedload(Product.category),
|
||||
joinedload(Product.group),
|
||||
joinedload(Product.shop),
|
||||
joinedload(Product.display_unit),
|
||||
joinedload(Product.min_stock_unit),
|
||||
|
||||
@@ -393,6 +393,9 @@ class ProductOut(BaseModel):
|
||||
secondary_factor: float | None = None
|
||||
date_precision: DatePrecision = DatePrecision.day
|
||||
group_id: int | None
|
||||
# Name der Gruppe – wie category_name, damit die Listen danach filtern
|
||||
# koennen, ohne die Gruppen zusaetzlich zu laden.
|
||||
group_name: str | None = None
|
||||
category_id: int | None = None
|
||||
category_name: str | None = None
|
||||
min_stock: float | None
|
||||
|
||||
Reference in New Issue
Block a user