Backend: Product.updated_at (Zuletzt geaendert)

Neue Spalte updated_at, die bei jeder Stammdaten-Aenderung automatisch nachzieht
(onupdate). Migration legt sie nullable an und setzt Altbestaende auf created_at.
In ProductOut ausgegeben - Basis fuer eine "Zuletzt geaendert"-Spalte im Web.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-28 11:12:03 +02:00
parent 9ca7291c68
commit 45031df1f4
4 changed files with 28 additions and 0 deletions

View File

@@ -179,6 +179,11 @@ def _ensure_schema() -> None:
# Verbrauchsgegenstand: Gegenstand wie ein Lebensmittel führen (Chargen). # Verbrauchsgegenstand: Gegenstand wie ein Lebensmittel führen (Chargen).
"ALTER TABLE products ADD COLUMN IF NOT EXISTS bulk BOOLEAN " "ALTER TABLE products ADD COLUMN IF NOT EXISTS bulk BOOLEAN "
"NOT NULL DEFAULT FALSE", "NOT NULL DEFAULT FALSE",
# Zeitpunkt der letzten Änderung an den Stammdaten (für „Zuletzt geändert").
# Nullable anlegen und Altbestände auf created_at zurücksetzen; neue Zeilen
# füllt die ORM-Spalte (default/onupdate).
"ALTER TABLE products ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ",
"UPDATE products SET updated_at = created_at WHERE updated_at IS NULL",
# Kaufpreis (in Rappen/Cent) und Währung am Einzelstück. # 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 price_cents INTEGER",
"ALTER TABLE items ADD COLUMN IF NOT EXISTS currency VARCHAR(3)", "ALTER TABLE items ADD COLUMN IF NOT EXISTS currency VARCHAR(3)",

View File

@@ -258,6 +258,11 @@ class Product(Base):
bulk: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) bulk: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_now) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_now)
# Zeitpunkt der letzten Änderung an den Stammdaten des Artikels (nicht am
# Bestand). Wird bei jedem ORM-UPDATE der Zeile automatisch nachgezogen.
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=_now, onupdate=_now
)
group: Mapped[Group | None] = relationship(back_populates="products") group: Mapped[Group | None] = relationship(back_populates="products")
category: Mapped[Category | None] = relationship() category: Mapped[Category | None] = relationship()

View File

@@ -355,6 +355,7 @@ class ProductOut(BaseModel):
individual: bool = False individual: bool = False
bulk: bool = False bulk: bool = False
created_at: datetime created_at: datetime
updated_at: datetime | None = None
# angereichert: # angereichert:
stock: float = 0.0 stock: float = 0.0
expired_count: int = 0 expired_count: int = 0

View File

@@ -331,3 +331,20 @@ def test_verbrauchsgegenstand_unter_mindestbestand(db):
db.commit() db.commit()
# Unter dem Mindestbestand -> gehört auf die Einkaufsliste (wie ein Lebensmittel). # Unter dem Mindestbestand -> gehört auf die Einkaufsliste (wie ein Lebensmittel).
assert current_stock(db, product.id) < product.min_stock assert current_stock(db, product.id) < product.min_stock
# ---- Zuletzt geändert ----
def test_updated_at_wird_bei_aenderung_nachgezogen(db):
import time
product = Product(name="Alt")
db.add(product)
db.commit()
db.refresh(product)
erst = product.updated_at
assert erst is not None
time.sleep(0.01)
product.name = "Neu"
db.commit()
db.refresh(product)
assert product.updated_at > erst