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:
36
backend/app/services/dates.py
Normal file
36
backend/app/services/dates.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Genauigkeit von Mindesthaltbarkeitsdaten.
|
||||
|
||||
Auf vielen Verpackungen steht nur "09/2026" statt eines Tagesdatums. Damit die
|
||||
FEFO-Sortierung und alle Ablauf-Abfragen weiter mit einem echten DATE arbeiten
|
||||
können, wird ein solcher Monatswert auf den **Monatsletzten** gelegt – das ist
|
||||
die übliche Lesart bei Lebensmitteln. Wie genau die Angabe ursprünglich war,
|
||||
merkt sich die Charge zusätzlich in ``best_before_precision``; nur davon hängt
|
||||
ab, ob in der Anzeige "30.09.2026" oder "09/2026" steht.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from calendar import monthrange
|
||||
from datetime import date
|
||||
|
||||
from ..models import DatePrecision
|
||||
|
||||
DAY = DatePrecision.day.value
|
||||
MONTH = DatePrecision.month.value
|
||||
|
||||
VALID_PRECISIONS = (DAY, MONTH)
|
||||
|
||||
|
||||
def normalize_best_before(value: date | None, precision: str | None) -> date | None:
|
||||
"""Legt ein Monats-MHD auf den letzten Tag dieses Monats.
|
||||
|
||||
Tagesgenaue Angaben und ``None`` bleiben unverändert.
|
||||
"""
|
||||
if value is None or precision != MONTH:
|
||||
return value
|
||||
return date(value.year, value.month, monthrange(value.year, value.month)[1])
|
||||
|
||||
|
||||
def clean_precision(precision: str | None) -> str:
|
||||
"""Unbekannte oder fehlende Angaben gelten als tagesgenau."""
|
||||
return precision if precision in VALID_PRECISIONS else DAY
|
||||
Reference in New Issue
Block a user