Nachschlagen: Lagerort-QR zeigt alle Artikel an diesem Ort
Neuer Endpunkt GET /location/{code} liefert alle Artikel an einem Lagerort inkl. der Unterorte (Lot-Bestaende und Einzelstuecke), sortiert nach Name mit Menge in Artikeleinheiten. In der App loest der /l/-QR beim Nachschlagen jetzt diese Liste auf; ein Tipp auf einen Eintrag oeffnet den Artikel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from collections import defaultdict
|
||||
from datetime import date, timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..database import get_db
|
||||
@@ -9,6 +9,7 @@ from ..deps import get_current_user
|
||||
from ..models import (
|
||||
Group,
|
||||
GroupLocationMinStock,
|
||||
Item,
|
||||
Location,
|
||||
Lot,
|
||||
Movement,
|
||||
@@ -19,6 +20,8 @@ from ..models import (
|
||||
from ..schemas import (
|
||||
ExpiringItem,
|
||||
GroupShoppingItem,
|
||||
LocationContentEntry,
|
||||
LocationContents,
|
||||
LocationNeedGroup,
|
||||
LocationNeedProduct,
|
||||
LocationNeeds,
|
||||
@@ -26,7 +29,11 @@ from ..schemas import (
|
||||
ShoppingItem,
|
||||
)
|
||||
from ..services.conversion import BASE_OF_KIND, article_unit, display_unit_info
|
||||
from ..services.stock import current_stock, location_subtree_stock_base
|
||||
from ..services.stock import (
|
||||
current_stock,
|
||||
descendant_location_ids,
|
||||
location_subtree_stock_base,
|
||||
)
|
||||
from .settings import get_expiry_warning_days
|
||||
|
||||
router = APIRouter(tags=["views"])
|
||||
@@ -159,6 +166,47 @@ def shopping_list_by_location(
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/location/{code}", response_model=LocationContents)
|
||||
def location_contents(
|
||||
code: str,
|
||||
db: Session = Depends(get_db),
|
||||
_: User = Depends(get_current_user),
|
||||
) -> LocationContents:
|
||||
"""Alle Artikel, die an einem Lagerort liegen – inklusive der Unterorte.
|
||||
|
||||
Ziel des Lagerort-QR (`/l/<code>`) beim Nachschlagen: einmal scannen und
|
||||
sehen, was im Regal/Fach (und allem darunter) steht. Zählt sowohl
|
||||
Lot-Bestände (Lebensmittel/Objekte) als auch Einzelstücke.
|
||||
"""
|
||||
loc = db.get(Location, code)
|
||||
if loc is None:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, "Lagerort nicht gefunden")
|
||||
|
||||
ids = {code} | descendant_location_ids(db, code)
|
||||
product_ids: set[int] = {
|
||||
pid for (pid,) in db.query(Lot.product_id).filter(Lot.location_id.in_(ids)).distinct()
|
||||
}
|
||||
product_ids |= {
|
||||
pid for (pid,) in db.query(Item.product_id).filter(Item.location_id.in_(ids)).distinct()
|
||||
}
|
||||
|
||||
entries: list[LocationContentEntry] = []
|
||||
for pid in product_ids:
|
||||
product = db.get(Product, pid)
|
||||
if product is None:
|
||||
continue
|
||||
faktor, label = article_unit(product)
|
||||
stock = location_subtree_stock_base(db, product, code) / (faktor or 1.0)
|
||||
if stock <= 0:
|
||||
continue
|
||||
entries.append(LocationContentEntry(
|
||||
product_id=product.id, name=product.name, brand=product.brand,
|
||||
stock=round(stock, 3), unit_label=label, individual=product.individual,
|
||||
))
|
||||
entries.sort(key=lambda e: e.name.lower())
|
||||
return LocationContents(location_id=code, location_name=loc.name, products=entries)
|
||||
|
||||
|
||||
@router.get("/expiring", response_model=list[ExpiringItem])
|
||||
def expiring(
|
||||
days: int | None = None,
|
||||
|
||||
Reference in New Issue
Block a user