App: /expiring kann jetzt ohne MHD kommen - das hat sie nicht ausgehalten
Beim Zusammenstellen der Testliste fuer den naechsten iOS-Build
aufgefallen, bevor es jemandem begegnet ist: Seit den angebrochenen
Packungen liefert /expiring auch Chargen OHNE aufgedrucktes MHD - eine
geoeffnete Packung hat nur ein Verbrauchsdatum, und genau die gehoert in
diese Liste. `best_before` ist dort seither null.
Im Swift-Modell stand `let bestBefore: String`, nicht optional. Eine
einzige solche Charge haette das Entschluesseln der GANZEN Antwort
scheitern lassen: keine Ablaufliste, keine Ablaufkarte - und keine
Erinnerungen, denn der Planer laedt dieselbe Antwort.
Gegen den laufenden Server geprueft: Eine angebrochene Packung ohne MHD
kommt als {"best_before": null, "consume_by": "2026-10-05",
"warn_date": "2026-10-05", "warn_source": "consume_by"}.
Mitgenommen, weil es ohnehin an derselben Stelle sitzt: Das Modell kennt
jetzt opened_on, consume_by, warn_date und warn_source. Die Erinnerungen
haengen am Warndatum statt am MHD - eine angebrochene Packung ohne
aufgedrucktes Datum braucht sie am dringendsten und bekam bisher keine.
Liste und Dashboard-Karte schreiben "verbrauchen bis 05.10." statt
"MHD ohne MHD", denn das sind zwei verschiedene Aussagen.
Nicht kompiliert: Auf dieser Maschine gibt es kein Xcode. Geprueft sind
Klammerbalance, Anfuehrungszeichen, dass item.bestBefore nirgends mehr
nicht-optional benutzt wird, dass ExpiringItem nirgends von Hand erzeugt
wird (nur entschluesselt), und der Abgleich jedes Feldnamens gegen eine
echte Serverantwort. Der Build in Xcode bleibt die Probe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
25e7f23c6c
commit
892c52e49a
@@ -291,7 +291,7 @@ struct ExpiryCard: View {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 1) {
|
||||
Text(item.productName).font(.callout)
|
||||
Text("MHD \(display.formatBestBefore(item.bestBefore, precision: item.bestBeforePrecision))")
|
||||
Text("\(item.fristLabel) \(display.formatBestBefore(item.warnDate, precision: item.fristPrecision))")
|
||||
.font(.caption2).foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -146,7 +146,7 @@ struct ExpiringView: View {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(item.productName)
|
||||
Text("MHD \(display.formatBestBefore(item.bestBefore, precision: item.bestBeforePrecision)) · \(articleAmount(item))")
|
||||
Text("\(item.fristLabel) \(display.formatBestBefore(item.warnDate, precision: item.fristPrecision)) · \(articleAmount(item))")
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -617,8 +617,19 @@ struct ExpiringItem: Codable, Identifiable {
|
||||
let productName: String
|
||||
let quantity: Double
|
||||
let baseUnit: String
|
||||
let bestBefore: String
|
||||
/// Darf fehlen! Eine angebrochene Packung ohne aufgedrucktes MHD hat nur ein
|
||||
/// Verbrauchsdatum - und genau die gehoert in diese Liste. Stand hier frueher
|
||||
/// ein nicht-optionaler String, scheiterte das Entschluesseln der GANZEN
|
||||
/// Liste an einer einzigen solchen Charge, samt Erinnerungen.
|
||||
let bestBefore: String?
|
||||
let bestBeforePrecision: String?
|
||||
let openedOn: String?
|
||||
let consumeBy: String?
|
||||
/// Das Datum, nach dem gewarnt wird: das fruehere von MHD und
|
||||
/// Verbrauchsdatum. Immer gesetzt - der Server rechnet es aus.
|
||||
let warnDate: String
|
||||
/// "best_before" oder "consume_by" - sagt, welches der beiden Daten gewann.
|
||||
let warnSource: String?
|
||||
let daysLeft: Int
|
||||
let packageSize: Double?
|
||||
let packageLabel: String?
|
||||
@@ -627,6 +638,17 @@ struct ExpiringItem: Codable, Identifiable {
|
||||
|
||||
var id: Int { lotId }
|
||||
|
||||
/// Ist die Packung angebrochen und draengt deshalb?
|
||||
var istAngebrochen: Bool { warnSource == "consume_by" }
|
||||
|
||||
/// Beschriftung vor dem Datum. "MHD 05.10." und "verbrauchen bis 05.10."
|
||||
/// sind zwei verschiedene Aussagen, und die Liste zeigt beide nebeneinander.
|
||||
var fristLabel: String { istAngebrochen ? "verbrauchen bis" : "MHD" }
|
||||
|
||||
/// Genauigkeit des angezeigten Datums. Ein Verbrauchsdatum ist immer
|
||||
/// taggenau, auch wenn auf der Packung nur ein Monat stand.
|
||||
var fristPrecision: String? { istAngebrochen ? "day" : bestBeforePrecision }
|
||||
|
||||
/// Restlaufzeit als kurzer Text. „0 Tage" ergibt keinen Sinn - am Ablauftag
|
||||
/// selbst steht „heute". Karte und Liste nutzen dieselbe Formulierung.
|
||||
var restlaufzeitText: String {
|
||||
@@ -644,6 +666,10 @@ struct ExpiringItem: Codable, Identifiable {
|
||||
case baseUnit = "base_unit"
|
||||
case bestBefore = "best_before"
|
||||
case bestBeforePrecision = "best_before_precision"
|
||||
case openedOn = "opened_on"
|
||||
case consumeBy = "consume_by"
|
||||
case warnDate = "warn_date"
|
||||
case warnSource = "warn_source"
|
||||
case daysLeft = "days_left"
|
||||
case packageSize = "package_size"
|
||||
case packageLabel = "package_label"
|
||||
|
||||
@@ -75,7 +75,9 @@ enum ExpiryPlanner {
|
||||
}
|
||||
|
||||
for item in snapshot.expiring {
|
||||
guard let mhd = parseTag(item.bestBefore, calendar: calendar) else { continue }
|
||||
// Das Warndatum, nicht das MHD: Eine angebrochene Packung ohne
|
||||
// aufgedrucktes Datum braucht die Erinnerung am dringendsten.
|
||||
guard let mhd = parseTag(item.warnDate, calendar: calendar) else { continue }
|
||||
let mhdTag = calendar.startOfDay(for: mhd)
|
||||
|
||||
// Welche Regeln gelten fuer dieses Produkt? Kategorie ersetzt Allgemeine:
|
||||
|
||||
Reference in New Issue
Block a user