"""Einzelstücke (Items): UID-Erzeugung und Anreicherung für die Ausgabe.""" from __future__ import annotations import secrets from sqlalchemy.orm import Session from ..models import Item, ItemLoan from ..schemas import ItemKurz, ItemOut from .loans import loan_to_out # Ohne 0/O/1/I/L, damit die UID auf einem Etikett eindeutig lesbar bleibt. _ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789" def generate_uid(db: Session, length: int = 8) -> str: """Kurze, eindeutige UID erzeugen (bei Kollision neu würfeln).""" while True: code = "".join(secrets.choice(_ALPHABET) for _ in range(length)) if db.query(Item).filter(Item.uid == code).first() is None: return code def _offener(item: Item) -> ItemLoan | None: """Der laufende Verleih aus den schon geladenen Verleihen des Stücks. Bewusst über die Beziehung statt per eigener Abfrage: So bleibt die Einzelstück-Liste bei einer Abfrage, wenn der Aufrufer ``loans`` mitlädt. """ for loan in item.loans: if loan.returned_on is None: return loan return None def item_kurz(item: Item) -> ItemKurz: """Ein verknuepftes Stueck in Kurzform (Zubehoer, Geraet).""" return ItemKurz( id=item.id, uid=item.uid, product_id=item.product_id, product_name=item.product.name if item.product else None, product_brand=item.product.brand if item.product else None, location_name=item.location.name if item.location else None, verliehen=_offener(item) is not None, ) def item_to_out(item: Item) -> ItemOut: """ItemOut inkl. Lagerort-/Shop-/Produktnamen, Verleih und Zubehoer.""" out = ItemOut.model_validate(item) out.location_name = item.location.name if item.location else None out.shop_name = item.shop.name if item.shop else None out.product_name = item.product.name if item.product else None out.product_brand = item.product.brand if item.product else None kategorie = item.product.category if item.product else None out.category_id = kategorie.id if kategorie else None 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 # Beide Richtungen ausdruecklich setzen: model_validate wuerde die Beziehung # zwar finden, aber nur die Spalten fuellen - Artikelname und Lagerort des # verknuepften Stuecks blieben leer. out.zubehoer = [item_kurz(t) for t in item.zubehoer] out.gehoert_zu = item_kurz(item.gehoert_zu) if item.gehoert_zu else None return out