MHD wahlweise nur mit Monat und Jahr (Backend)
Auf vielen Verpackungen steht nur "09/2026". Bisher liess sich ausschliesslich
ein Tagesdatum erfassen, was zu erfundener Genauigkeit fuehrte.
Entwurf: best_before bleibt ein echtes DATE, damit FEFO, die Ablauf-Abfragen
und alle bestehenden Sortierungen unveraendert weiterlaufen. Eine Monatsangabe
wird auf den Monatsletzten gelegt - die uebliche Lesart bei Lebensmitteln, und
die sichere Richtung, weil nicht zu frueh aussortiert wird. Zusaetzlich merkt
sich jede Charge in best_before_precision, wie genau die Angabe war; davon
haengt allein die Anzeige ab. Am Produkt steht in date_precision, welche
Genauigkeit dort ueblich ist (Voreinstellung der Eingabe, z.B. Konserven).
Bewusst als VARCHAR statt als DB-Enum gespeichert: So laesst sich die Spalte
auf bestehenden Tabellen per ADD COLUMN IF NOT EXISTS nachziehen, ohne vorher
einen neuen Postgres-Typ anzulegen. Beide Spalten haben ein Server-Default
'day', damit vorhandene Chargen unveraendert gueltig bleiben.
Export/Import bleiben verlustfrei: Das JSON-Backup fuehrt beide Felder mit. Die
CSV bekommt bewusst keine neue Spalte, damit die Datei in Excel unveraendert
bedienbar bleibt - stattdessen wird eine Monatsangabe als "09/2026" geschrieben
und beim Import an der Schreibweise wieder erkannt ("09/2026", "2026-09",
"09.2026"); tagesgenaue Formate werden weiterhin gelesen.
Beim Korrigieren einer Charge werden MHD und Genauigkeit gemeinsam ausgewertet,
sonst bliebe ein auf Monat umgestellter Wert auf dem alten Tag stehen.
Getestet: 40 pytest-Tests gruen (17 neue zu Monatsletztem, Schaltjahr,
Einlagern, Export-Schreibweise und Import-Erkennung). Zusaetzlich ein
Durchlauf ueber die echte API: Produkt mit Monatsvorgabe anlegen und aendern,
Sammel-Einlagern mit gemischten Genauigkeiten, Chargen wieder auslesen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,17 @@ class MovementType(str, enum.Enum):
|
||||
adjust = "adjust"
|
||||
|
||||
|
||||
class DatePrecision(str, enum.Enum):
|
||||
"""Wie genau ein MHD angegeben wurde.
|
||||
|
||||
Bewusst als kurzer String gespeichert und nicht als DB-Enum: So lässt sich
|
||||
die Spalte auf bestehenden Tabellen per ADD COLUMN nachziehen, ohne vorher
|
||||
einen neuen Postgres-Typ anlegen zu müssen.
|
||||
"""
|
||||
day = "day" # 07.09.2026
|
||||
month = "month" # 09/2026
|
||||
|
||||
|
||||
class UnitKind(str, enum.Enum):
|
||||
"""Art einer Einheit. Bestimmt die kanonische Basiseinheit für die Speicherung."""
|
||||
count = "count" # Basis: Stück
|
||||
@@ -121,6 +132,12 @@ class Product(Base):
|
||||
package_size: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
# Bezeichnung eines Gebindes: "Packung", "Glas", "Tüte", "Flasche", …
|
||||
package_label: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
||||
# Welche MHD-Genauigkeit bei diesem Produkt sinnvoll ist. Steuert nur die
|
||||
# Voreinstellung der Eingabe (z.B. Konserven: nur Monat/Jahr aufgedruckt).
|
||||
date_precision: Mapped[str] = mapped_column(
|
||||
String(8), nullable=False, default=DatePrecision.day.value,
|
||||
server_default=DatePrecision.day.value,
|
||||
)
|
||||
|
||||
group_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("groups.id", ondelete="SET NULL"), nullable=True
|
||||
@@ -195,7 +212,14 @@ class Lot(Base):
|
||||
ForeignKey("products.id", ondelete="CASCADE"), nullable=False
|
||||
)
|
||||
quantity: Mapped[float] = mapped_column(Float, nullable=False) # in base units
|
||||
# Immer ein echtes Datum, damit FEFO und Ablauf-Abfragen unverändert bleiben.
|
||||
# Bei Monatsangaben steht hier der Monatsletzte (siehe services/dates.py).
|
||||
best_before: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
# Wie genau die Angabe ursprünglich war – entscheidet nur über die Anzeige.
|
||||
best_before_precision: Mapped[str] = mapped_column(
|
||||
String(8), nullable=False, default=DatePrecision.day.value,
|
||||
server_default=DatePrecision.day.value,
|
||||
)
|
||||
location_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("locations.id", ondelete="SET NULL"), nullable=True
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user