Backend: Verbrauchsgegenstand (Product.bulk) - Gegenstand wie ein Lebensmittel

Neues Flag bulk auf Product: Gegenstand als Charge mit Menge/Einheit/MHD/
Mindestbestand fuehren (z.B. Sonnencreme in ml), ohne eindeutigen Code.
Migration (ADD COLUMN), Schemas und Anlege-Pfad ergaenzt. Kernlogik nutzt
foodLike = kein Gegenstand ODER bulk; Bestand/Einkaufsliste unveraendert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-27 20:29:01 +02:00
parent 1dc249eb79
commit 6c870584dd
5 changed files with 52 additions and 0 deletions

View File

@@ -176,6 +176,9 @@ def _ensure_schema() -> None:
# Einzelstück-Verwaltung (Items mit UID/QR) je Produkt.
"ALTER TABLE products ADD COLUMN IF NOT EXISTS individual BOOLEAN "
"NOT NULL DEFAULT FALSE",
# Verbrauchsgegenstand: Gegenstand wie ein Lebensmittel führen (Chargen).
"ALTER TABLE products ADD COLUMN IF NOT EXISTS bulk BOOLEAN "
"NOT NULL DEFAULT FALSE",
# Kaufpreis (in Rappen/Cent) und Währung am Einzelstück.
"ALTER TABLE items ADD COLUMN IF NOT EXISTS price_cents INTEGER",
"ALTER TABLE items ADD COLUMN IF NOT EXISTS currency VARCHAR(3)",

View File

@@ -251,6 +251,11 @@ class Product(Base):
# Lagerort verwalten. So bekommt jedes physische Stück ein eigenes Kaufdatum,
# eine eigene Garantie und Bezugsquelle (z.B. dieselbe Powerbank 2024 + 2025).
individual: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
# Gegenstände: als Verbrauchsgegenstand wie ein Lebensmittel führen (Chargen,
# Einheit, Packungsgröße, MHD optional, Mindestbestand), aber ohne eindeutigen
# Code z.B. Sonnencreme in ml. Schließt sich mit ``individual`` aus. Für die
# Kernlogik gilt: foodLike = kein Gegenstand ODER bulk.
bulk: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_now)

View File

@@ -370,6 +370,7 @@ def create_product(
shop_id=payload.shop_id,
product_url=payload.product_url or None,
individual=bool(payload.individual),
bulk=bool(payload.bulk),
source="manual",
)
db.add(product)

View File

@@ -299,6 +299,8 @@ class ProductBase(BaseModel):
product_url: str | None = Field(default=None, max_length=1024)
# Gegenstände als Einzelstücke (Items mit UID/QR) statt als Menge führen.
individual: bool = False
# Gegenstand als Verbrauchsgegenstand wie ein Lebensmittel führen (Chargen).
bulk: bool = False
# Selbst definierte Feldwerte: {field_definition_id: Wert-als-Text}.
field_values: dict[int, str | None] | None = None
@@ -325,6 +327,7 @@ class ProductUpdate(BaseModel):
shop_id: int | None = None
product_url: str | None = Field(default=None, max_length=1024)
individual: bool | None = None
bulk: bool | None = None
field_values: dict[int, str | None] | None = None
@@ -350,6 +353,7 @@ class ProductOut(BaseModel):
shop_id: int | None = None
product_url: str | None = None
individual: bool = False
bulk: bool = False
created_at: datetime
# angereichert:
stock: float = 0.0