MHD nur mit Monat und Jahr in Web-UI und iOS-App

Setzt den Backend-Umbau in beiden Oberflaechen um.

Die Genauigkeit gilt jeweils fuer den ganzen Einlager-Vorgang und nicht je
Charge: Auf einer Packung steht entweder ein Tagesdatum oder nur Monat/Jahr,
gemischt kommt das nicht vor. Vorbelegt wird sie aus dem Produkt, laesst sich
aber im Vorgang umstellen.

Web-UI: Umschalter im Kopf der Chargenliste; das Eingabefeld wechselt zwischen
type="date" und type="month". Im Produktformular gibt es das neue Feld
"MHD-Angabe" neben der Gebinde-Bezeichnung. Anzeige laeuft ueber den
Settings-Context, damit das eingestellte Datumsformat erhalten bleibt und
Monatsangaben ueberall als "09/2026" erscheinen (Auslagern, Uebersicht,
Chargentabelle). Die Abgelaufen-Warnung prueft bei Monatsangaben gegen den
Monatsletzten - sonst haette eine Packung schon am Monatsersten als abgelaufen
gegolten.

iOS: Auswahl "Tagesdatum / nur Monat/Jahr" im Einlagern-Formular und beim
Anlegen eines Artikels. SwiftUI hat keinen DatePicker ohne Tag, deshalb ein
eigener MonthYearPicker aus zwei Auswahlfeldern; die Jahresliste reicht zwei
Jahre zurueck (bereits abgelaufene Ware) und fuenfzehn nach vorn (Konserven).
Die Chargenauswahl beim Auslagern zeigt Monatsangaben ebenfalls ohne Tag.

Getestet: Web-Build (vite) und iOS-Geraetebuild laufen fehlerfrei durch, die
App ist auf dem iPhone installiert. Das Verhalten in der Oberflaeche ist noch
nicht von Hand durchgeklickt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-22 17:57:09 +02:00
parent eed7c9e1de
commit 30307d6cfb
13 changed files with 2090 additions and 25 deletions

View File

@@ -5,7 +5,7 @@ import { useSettings } from "../settings";
import { buildUnitOptions, fmt, isExpired, unitShort } from "../units";
export default function CheckOut() {
const { formatDate } = useSettings();
const { formatBestBefore } = useSettings();
const [barcode, setBarcode] = useState("");
const [search, setSearch] = useState("");
const [results, setResults] = useState([]);
@@ -161,7 +161,7 @@ export default function CheckOut() {
<option value="">Automatisch zuerst ablaufende zuerst (FEFO)</option>
{lots.map((l) => (
<option key={l.id} value={l.id}>
{l.best_before ? `MHD ${formatDate(l.best_before)}` : "ohne MHD"} · {lotAmount(l.quantity)}
{l.best_before ? `MHD ${formatBestBefore(l.best_before, l.best_before_precision)}` : "ohne MHD"} · {lotAmount(l.quantity)}
{isExpired(l.best_before) ? " · abgelaufen" : ""}
</option>
))}
@@ -172,7 +172,7 @@ export default function CheckOut() {
<div className={`alert ${isExpired(selectedLot.best_before) ? "error" : "info"}`}>
<Icon name="alert" size={16} />
Gewählte Charge: {lotAmount(selectedLot.quantity)}
{selectedLot.best_before ? ` · MHD ${formatDate(selectedLot.best_before)}` : " · ohne MHD"}
{selectedLot.best_before ? ` · MHD ${formatBestBefore(selectedLot.best_before, selectedLot.best_before_precision)}` : " · ohne MHD"}
{isExpired(selectedLot.best_before) ? " (abgelaufen)" : ""}
</div>
)}