Gruppen-Gebinde: Mindestbestand/Bestand in Packungen (Backend)
Gruppen bekommen ein eigenes Richt-Gebinde (package_size/label) plus min_stock_in_packages. Weil die Produkte einer Gruppe unterschiedlich große Packungen haben können (Pesto 99 g vs. 160 g), legt die Gruppe einen gemeinsamen Richtwert fest (1 Glas ≈ X g). - Neuer Helfer group_min_context() zentralisiert, in welcher Einheit der Gruppen-Mindestbestand zaehlt (Gebinde ODER verwaltete Einheit). - Einkaufsliste (gesamt + je Ort), Dashboard-Bedarf und GroupOut nutzen ihn; need.text kommt so als 'x Glaeser (y g)'. - update_group rechnet bestehende Werte beim Umschalten der Einheit um, damit der physische Bedarf gleich bleibt. - Migration: groups.package_size/package_label/min_stock_in_packages. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ from ..schemas import (
|
||||
LocationMinStockOut,
|
||||
ProductBarcodeOut,
|
||||
)
|
||||
from ..services.conversion import BASE_OF_KIND
|
||||
from ..services.conversion import group_min_context
|
||||
from ..services.stock import current_stock, location_subtree_stock_base
|
||||
|
||||
router = APIRouter(prefix="/groups", tags=["groups"])
|
||||
@@ -67,23 +67,21 @@ def _group_to_out(db: Session, group: Group) -> GroupOut:
|
||||
)
|
||||
out.product_barcodes = product_codes
|
||||
|
||||
# Bestand in derselben Einheit, in der auch der Mindestbestand erfasst ist
|
||||
# (Gruppen-Gebinde ODER verwaltete Einheit) – so ist beides vergleichbar.
|
||||
ctx = group_min_context(group)
|
||||
stock_base = float(sum(current_stock(db, p.id) for p in ctx.matching))
|
||||
out.stock = round(stock_base / ctx.divisor, 3)
|
||||
unit = group.min_stock_unit
|
||||
if unit is not None:
|
||||
# Bestand nur über Produkte gleicher Art, in der Gruppen-Einheit ausgedrückt.
|
||||
base = BASE_OF_KIND[unit.kind]
|
||||
matching = [p for p in products if p.base_unit == base]
|
||||
stock_base = float(sum(current_stock(db, p.id) for p in matching))
|
||||
out.stock = stock_base / unit.factor
|
||||
out.min_stock_unit_name = unit.name
|
||||
out.min_stock_unit_factor = unit.factor
|
||||
out.kind = unit.kind.value
|
||||
else:
|
||||
matching = list(products)
|
||||
out.stock = float(sum(current_stock(db, p.id) for p in products))
|
||||
|
||||
# Bestand je Lagerort (inkl. Unterorte) in derselben Einheit wie out.stock.
|
||||
def _loc_stock(loc_id: str) -> float:
|
||||
total = sum(location_subtree_stock_base(db, p, loc_id) for p in matching)
|
||||
return total / unit.factor if unit is not None else float(total)
|
||||
total = sum(location_subtree_stock_base(db, p, loc_id) for p in ctx.matching)
|
||||
return round(total / ctx.divisor, 3)
|
||||
|
||||
out.location_min_stocks = [
|
||||
LocationMinStockOut(
|
||||
@@ -149,6 +147,9 @@ def create_group(
|
||||
name=payload.name,
|
||||
min_stock=payload.min_stock,
|
||||
min_stock_unit_id=payload.min_stock_unit_id,
|
||||
package_size=payload.package_size,
|
||||
package_label=payload.package_label,
|
||||
min_stock_in_packages=payload.min_stock_in_packages,
|
||||
)
|
||||
db.add(group)
|
||||
db.commit()
|
||||
@@ -175,8 +176,25 @@ def update_group(
|
||||
)
|
||||
if clash:
|
||||
raise HTTPException(status.HTTP_409_CONFLICT, "Name bereits vergeben")
|
||||
|
||||
# Wird nur die Erfassungseinheit umgestellt (Gebinde <-> verwaltete Einheit),
|
||||
# ohne dass der Aufrufer neue Zahlen mitschickt, rechnen wir die vorhandenen
|
||||
# Mindestbestände so um, dass der *physische* Bedarf gleich bleibt.
|
||||
alt = group_min_context(group)
|
||||
umschaltung = (
|
||||
any(k in data for k in ("min_stock_in_packages", "package_size", "package_label"))
|
||||
and "min_stock" not in data
|
||||
)
|
||||
for field, value in data.items():
|
||||
setattr(group, field, value)
|
||||
if umschaltung:
|
||||
neu = group_min_context(group)
|
||||
if neu.divisor != alt.divisor and neu.divisor:
|
||||
faktor = alt.divisor / neu.divisor
|
||||
if group.min_stock is not None:
|
||||
group.min_stock = round(group.min_stock * faktor, 3)
|
||||
for e in group.location_min_stocks:
|
||||
e.min_stock = round(e.min_stock * faktor, 3)
|
||||
db.commit()
|
||||
db.refresh(group)
|
||||
return _group_to_out(db, group)
|
||||
|
||||
Reference in New Issue
Block a user