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:
@@ -7,10 +7,12 @@ Einheiten (z.B. Kilogramm, Liter, Pfund) rechnen über ihren Faktor dorthin um.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import NamedTuple
|
||||
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..models import BaseUnit, Product, Unit, UnitKind
|
||||
from ..models import BaseUnit, Group, Product, Unit, UnitKind
|
||||
|
||||
BASE_OF_KIND: dict[UnitKind, BaseUnit] = {
|
||||
UnitKind.count: BaseUnit.piece,
|
||||
@@ -108,3 +110,37 @@ def article_units(product: Product, quantity_base: float) -> float:
|
||||
"""Rechnet eine Menge in Basiseinheiten in Artikeleinheiten um."""
|
||||
factor, _ = article_unit(product)
|
||||
return quantity_base / factor if factor else quantity_base
|
||||
|
||||
|
||||
class GroupMinContext(NamedTuple):
|
||||
divisor: float # Basiseinheiten je Mindestbestand-Einheit
|
||||
label: str # Einzahl-Label ("Glas", "Gramm", …)
|
||||
is_package: bool # zaehlbares Gebinde (aufrunden) vs. Anzeige-/Basiseinheit
|
||||
base_unit: BaseUnit | None
|
||||
matching: list[Product] # Produkte, die zur Gruppen-Einheit zaehlen
|
||||
|
||||
|
||||
def group_min_context(group: Group) -> GroupMinContext:
|
||||
"""In welcher Einheit der Mindestbestand einer Gruppe zu lesen ist.
|
||||
|
||||
Eine Gruppe zaehlt in ihrer verwalteten Einheit (``min_stock_unit``) oder – wenn
|
||||
ein Gruppen-Gebinde definiert und aktiv ist – in ganzen Packungen. Die
|
||||
Packungsgroesse ist ein **Richtwert der Gruppe** (nicht die der einzelnen
|
||||
Produkte), weil deren Packungen unterschiedlich gross sein koennen.
|
||||
"""
|
||||
unit = group.min_stock_unit
|
||||
if unit is not None:
|
||||
base = BASE_OF_KIND[unit.kind]
|
||||
matching = [p for p in group.products if p.base_unit == base]
|
||||
base_unit: BaseUnit | None = base
|
||||
else:
|
||||
matching = list(group.products)
|
||||
base_unit = None
|
||||
if group.min_stock_in_packages and group.package_size and group.package_size > 0:
|
||||
return GroupMinContext(
|
||||
float(group.package_size), group.package_label or "Packung",
|
||||
True, base_unit, matching,
|
||||
)
|
||||
if unit is not None:
|
||||
return GroupMinContext(unit.factor or 1.0, unit.name, False, base_unit, matching)
|
||||
return GroupMinContext(1.0, "", False, None, matching)
|
||||
|
||||
Reference in New Issue
Block a user