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:
@@ -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)",
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user