Lagerorte: Baum-Picker beim Anlegen; Unter-Ort-Bestand zählt zum Bedarf
- Web: der übergeordnete Lagerort wird beim Anlegen jetzt über den aufklappbaren Baum (CategorySelect) gewählt statt über das flache Dropdown. - Backend: Mindestbestand je Lagerort wird jetzt gegen den Bestand INKL. aller Unter-Lagerorte geprueft. Ein Bedarf auf „Hedingen" gilt also als gedeckt, wenn der Vorrat in „Hedingen -> Keller" liegt. Helfer location_subtree_stock_base; 2 neue Tests, Suite 157 gruen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,16 @@ from datetime import date
|
||||
from sqlalchemy import asc
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models import DatePrecision, Item, Lot, Movement, MovementType, Product, User
|
||||
from ..models import (
|
||||
DatePrecision,
|
||||
Item,
|
||||
Location,
|
||||
Lot,
|
||||
Movement,
|
||||
MovementType,
|
||||
Product,
|
||||
User,
|
||||
)
|
||||
from .conversion import to_base
|
||||
from .dates import clean_precision, normalize_best_before
|
||||
|
||||
@@ -226,6 +235,29 @@ def location_stock_base(db: Session, product: Product, location_id: int) -> floa
|
||||
return float(sum(q for (q,) in total))
|
||||
|
||||
|
||||
def descendant_location_ids(db: Session, location_id: int) -> set[int]:
|
||||
"""Alle Unter-Lagerorte (rekursiv) eines Lagerorts."""
|
||||
result: set[int] = set()
|
||||
stack = [location_id]
|
||||
while stack:
|
||||
cur = stack.pop()
|
||||
for (lid,) in db.query(Location.id).filter(Location.parent_id == cur).all():
|
||||
if lid not in result:
|
||||
result.add(lid)
|
||||
stack.append(lid)
|
||||
return result
|
||||
|
||||
|
||||
def location_subtree_stock_base(db: Session, product: Product, location_id: int) -> float:
|
||||
"""Bestand an einem Lagerort INKL. aller Unter-Lagerorte (Basiseinheiten).
|
||||
|
||||
So gilt ein Mindestbestand auf „Hedingen" als gedeckt, wenn der Vorrat
|
||||
irgendwo darunter liegt (z.B. „Hedingen → Keller").
|
||||
"""
|
||||
ids = {location_id} | descendant_location_ids(db, location_id)
|
||||
return float(sum(location_stock_base(db, product, lid) for lid in ids))
|
||||
|
||||
|
||||
def check_in(
|
||||
db: Session,
|
||||
product: Product,
|
||||
|
||||
Reference in New Issue
Block a user