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:
86
backend/tests/test_dates.py
Normal file
86
backend/tests/test_dates.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from datetime import date
|
||||
|
||||
import pytest
|
||||
|
||||
from app.services.dates import DAY, MONTH, clean_precision, normalize_best_before
|
||||
from app.services.stock import check_in
|
||||
|
||||
|
||||
def test_monatsangabe_wird_auf_den_monatsletzten_gelegt():
|
||||
assert normalize_best_before(date(2026, 9, 1), MONTH) == date(2026, 9, 30)
|
||||
|
||||
|
||||
def test_monatsletzter_beachtet_schaltjahre():
|
||||
assert normalize_best_before(date(2028, 2, 1), MONTH) == date(2028, 2, 29)
|
||||
assert normalize_best_before(date(2027, 2, 1), MONTH) == date(2027, 2, 28)
|
||||
|
||||
|
||||
def test_tagesgenaues_mhd_bleibt_unveraendert():
|
||||
assert normalize_best_before(date(2026, 9, 7), DAY) == date(2026, 9, 7)
|
||||
|
||||
|
||||
def test_ohne_mhd_bleibt_none():
|
||||
assert normalize_best_before(None, MONTH) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("wert", [None, "", "woche", "jahr"])
|
||||
def test_unbekannte_genauigkeit_gilt_als_tagesgenau(wert):
|
||||
assert clean_precision(wert) == DAY
|
||||
|
||||
|
||||
def test_bekannte_genauigkeiten_bleiben_erhalten():
|
||||
assert clean_precision(MONTH) == MONTH
|
||||
assert clean_precision(DAY) == DAY
|
||||
|
||||
|
||||
def test_einlagern_mit_monatsangabe_speichert_monatsletzten(db, rice):
|
||||
lot = check_in(
|
||||
db, rice, 1, "package", date(2026, 9, 1), None, None,
|
||||
best_before_precision=MONTH,
|
||||
)
|
||||
db.commit()
|
||||
# Gespeichert wird ein echtes Datum, damit FEFO unveraendert funktioniert ...
|
||||
assert lot.best_before == date(2026, 9, 30)
|
||||
# ... die Herkunft der Angabe bleibt aber erhalten.
|
||||
assert lot.best_before_precision == MONTH
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"text,erwartet",
|
||||
[
|
||||
("09/2026", date(2026, 9, 30)),
|
||||
("2026-09", date(2026, 9, 30)),
|
||||
("09.2026", date(2026, 9, 30)),
|
||||
],
|
||||
)
|
||||
def test_import_erkennt_monatsangaben_an_der_schreibweise(text, erwartet):
|
||||
from app.routers.transfer import _parse_best_before
|
||||
|
||||
wert, genauigkeit = _parse_best_before(text)
|
||||
assert (wert, genauigkeit) == (erwartet, MONTH)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text", ["2026-09-07", "07.09.2026"])
|
||||
def test_import_erkennt_tagesgenaue_angaben(text):
|
||||
from app.routers.transfer import _parse_best_before
|
||||
|
||||
wert, genauigkeit = _parse_best_before(text)
|
||||
assert (wert, genauigkeit) == (date(2026, 9, 7), DAY)
|
||||
|
||||
|
||||
def test_export_schreibt_monatsangabe_lesbar(db, rice):
|
||||
from app.routers.transfer import _format_best_before
|
||||
|
||||
lot = check_in(
|
||||
db, rice, 1, "package", date(2026, 9, 1), None, None,
|
||||
best_before_precision=MONTH,
|
||||
)
|
||||
db.commit()
|
||||
assert _format_best_before(lot) == "09/2026"
|
||||
|
||||
|
||||
def test_einlagern_ohne_angabe_bleibt_tagesgenau(db, rice):
|
||||
lot = check_in(db, rice, 1, "package", date(2026, 9, 7), None, None)
|
||||
db.commit()
|
||||
assert lot.best_before == date(2026, 9, 7)
|
||||
assert lot.best_before_precision == DAY
|
||||
Reference in New Issue
Block a user