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:
Scarriffle
2026-08-07 18:38:12 +02:00
parent 28785b0a10
commit ecc1570100
8 changed files with 168 additions and 128 deletions

View File

@@ -131,12 +131,17 @@ class GroupOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
name: str
min_stock: float | None = None
min_stock: float | None = None # in der aktuellen Erfassungseinheit (s.u.)
min_stock_unit_id: int | None = None
# Gruppen-Gebinde (Richtwert) + ob der Mindestbestand darin erfasst ist:
package_size: float | None = None
package_label: str | None = None
min_stock_in_packages: bool = False
# angereichert:
product_count: int = 0
stock: float = 0.0 # Bestand in Basiseinheiten
min_stock_unit_name: str | None = None
stock: float = 0.0 # Bestand in der aktuellen Erfassungseinheit
min_stock_unit_name: str | None = None # Name der verwalteten Einheit (g/kg …)
min_stock_unit_factor: float | None = None # Basiseinheiten je verwalteter Einheit
kind: str | None = None # Art der Mindestbestand-Einheit
barcodes: list[BarcodeOut] = [] # EANs, die dieser Gruppe zugeordnet sind
# EANs der Artikel in dieser Gruppe - nur zur Anzeige, nicht bearbeitbar.
@@ -149,12 +154,18 @@ class GroupCreate(BaseModel):
name: str = Field(min_length=1, max_length=120)
min_stock: float | None = Field(default=None, ge=0)
min_stock_unit_id: int | None = None
package_size: float | None = Field(default=None, ge=0)
package_label: str | None = Field(default=None, max_length=32)
min_stock_in_packages: bool = False
class GroupUpdate(BaseModel):
name: str | None = Field(default=None, min_length=1, max_length=120)
min_stock: float | None = Field(default=None, ge=0)
min_stock_unit_id: int | None = None
package_size: float | None = Field(default=None, ge=0)
package_label: str | None = Field(default=None, max_length=32)
min_stock_in_packages: bool | None = None
# ---- Categories ----