Tankstellenmarke als eigenes Feld, Belegfelder in der App richtig zugeordnet

Die Marke steht auf jedem Beleg, war aber nirgends gespeichert: der Parser
erkennt sie seit dem 16.08.2026, faltete sie aber nur in station_name.
Fuer jeden Beleg, den eine aeltere Fassung eingelesen hat, blieb dort der
Betreibername stehen und die Marke war danach nicht mehr zu holen.

- shell_beleg_parser: station_brand als eigenes Feld aus beiden Parserwegen,
  dazu marke_aus_text()/marke_aus_pdf() - sie lesen nur den Belegkopf und
  haengen nicht am vollstaendigen Einlesen.
- belege.marken_nachtragen(): traegt die Marke einmal beim Start aus der
  abgelegten Belegdatei nach. Nur wo das Feld gar nicht vorkommt und die
  Datei liegt; ein einmal eingetragenes Feld wird nie ueberschrieben.
- Panel und App: die gespeicherte Marke geht vor, geraten wird nur, wo keine
  da ist. Ein Teil, der fuer sich genommen eine Kopfmarke ist, taugt zudem
  nie als Ort.

Dazu Punkt 5 der Meldung vom 04.09.2026: ein eingelesener Beleg fuellte nur
Datum und Uhrzeit. Der Parser las ihn immer vollstaendig - die App fragte
liter/kosten/station/ersparnis/kraftstoff ab, veroeffentlicht werden aber die
Namen des Belegs (liters/fuel_total_eur/station_name/discount/fuel_type).
Uebereingestimmt hat allein ts. Die Zuordnung steht jetzt als
belegFormularwerte() in daten/belegentwurf.ts und wird gegen die echte
Nutzlast dieses Belegs geprueft.

tsc sauber, 258 Tests (die drei neuen Marken-Tests gegen den alten Stand als
scheiternd nachgewiesen), vite build sauber, Panel als Modul geparst,
Parser-Suite 11 Tests gegen elf echte Belege. Panel und App liefern fuer elf
Faelle byteweise dasselbe. Live in audi_ha_test auf 2026.9.4.21 ohne
Traceback: Uebersicht "Shell, Nuernberger Str., Ansbach", Einzelbeleg
zweizeilig mit Marke, und der echte geteilte Beleg fuellt durchs Backend das
ganze Formular.
This commit is contained in:
2026-09-04 17:00:22 +02:00
parent a99ae432fc
commit bdbdb4a010
17 changed files with 572 additions and 60 deletions
+129
View File
@@ -10726,3 +10726,132 @@ Beleg liest sich `Nürnberger Str., Ansbach`, und der Einzelbeleg zeigt
**Nicht geprueft, weil es ohne Mac nicht geht:** dass die Registrierung auf dem
Geraet greift. Das zeigt erst der naechste Xcode-Lauf - und der bricht jetzt ab,
wenn sie fehlt.
## CN. Die Marke stand auf jedem Beleg - und war nirgends gespeichert. Dazu: warum ein eingelesener Beleg nur Datum und Uhrzeit fuellte (2026.9.4.21)
### 1. "In einem Beleg soll die Marke, falls vorhanden, erkannt werden"
Der Einzelbeleg vom 10.11.2025 las sich nach Abschnitt CM
`Nürnberger Str. 74` / `91522 Ansbach` - richtig zerlegt, aber ohne Marke. Die
Frage war also nicht, ob die Zerlegung stimmt, sondern woher die Marke kommen
soll.
**Sie steht auf dem Beleg.** Nachgesehen statt vermutet - die erste Zeile jedes
abgelegten PDFs:
| Beleg | Zeile 0 | gespeicherter `station_name` |
|---|---|---|
| e-receipt9 | `Shell-Station` | `Hermann Mogler Mineralölg. GmbH` |
| e-receipt5 | `Shell Station` | `TC Sengül GmbH` |
| e-receipt | `SHELL STATION` | `A. Zrenner GmbH` |
| receipt_2026… | `SHELL TANKSTELLE, 6450 SÖLDEN` | `Shell, SÖLDEN` |
Der Parser **erkennt** die Marke seit dem 16.08.2026 (`_marke()`, nur im
Belegkopf gesucht) - er hat sie aber nur in den Anzeigenamen gefaltet
(`_tankstelle()`). Fuer jeden Beleg, den eine aeltere Fassung eingelesen hat,
blieb dort der Betreibername stehen, und die Marke war danach **nirgends mehr
zu holen**. Ein Feld, das nur als Nebenprodukt einer Zeichenkette existiert,
ist kein Feld.
**Jetzt eigenes Feld** `station_brand`, aus beiden Parser-Wegen. Dazu zwei
oeffentliche Funktionen: `marke_aus_text()` und `marke_aus_pdf()` - sie lesen
nur den Kopf und haengen damit **nicht** am vollstaendigen Einlesen. Ein Beleg,
an dem beide Parser scheitern wuerden, gibt seine Marke trotzdem her.
**Das Nachtragen** (`belege.marken_nachtragen`) laeuft einmal beim Start, an
genau der Stelle, die dafuer schon da war (`_nach_start`, direkt hinter
`screening.durchfuehren` - deren Kommentar beschreibt woertlich diesen Fall:
"was ihre neuen Felder nachtragen koennen, soll nicht bis zur naechsten Fahrt
warten"). Vorsichtig gehalten:
* angefasst wird nur, wo `station_brand` **gar nicht vorkommt** und die
Belegdatei tatsaechlich liegt;
* ein einmal eingetragenes Feld - auch mit Wert `None` - wird nie
ueberschrieben. Damit ueberschreibt es keine Korrektur von Hand und laeuft
nicht bei jedem Start erneut ueber dieselben Belege;
* geschrieben wird nur, wenn sich wirklich etwas geaendert hat.
Am Testcontainer geprueft: erster Start
`Tankstellenmarke bei 5 Beleg(en) nachgetragen (Shell)`, zweiter Start **keine
Zeile mehr**. Genau die fuenf Vorgaenge mit Belegdatei tragen das Feld.
**Gespeichert schlaegt geraten.** In beiden Codebasen nimmt
`tankstelleTeile(name, adresse, marke)` die gespeicherte Angabe vorweg und
faellt nur dort auf `markeErkennen(name)` zurueck, wo keine da ist: bei
Vorgaengen ohne Beleg, bei von Hand eingetragenen Tankstellen, und solange das
Nachtragen nicht gelaufen ist.
Beim Nebeneinanderlegen von Panel und App fiel noch etwas auf, das vorher nicht
auffallen konnte: steht im Namen eine ANDERE Marke als die gespeicherte, rutschte
die aus dem Namen in den **Ort** ("Aral" als Ortsname). Die alte Regel verglich
nur mit der gewaehlten Marke. Jetzt gilt: ein Teil, der fuer sich genommen eine
Kopfmarke IST, taugt nie als Ort.
### 2. Punkt 5 aus Abschnitt CM: der Beleg kam mit Datum und Uhrzeit an
Der Eigentuemer hat den Beleg geschickt (Shell, Richard-Wagner-Str. 9,
Ingolstadt, 43,87 l fuer 95,60 EUR) - liegt als
`tests/belegparser/belege/geteilt-2026-09-04.pdf`, gitignored.
**Der Parser liest ihn vollstaendig.** `_parsen()` greift, alle Werte stimmen.
Der Fehler sass in der App:
| App fragte ab | belege.py veroeffentlicht |
|---|---|
| `liter` | `liters` |
| `kosten` | `fuel_total_eur` |
| `ersparnis` | `discount` |
| `station` | `station_name` |
| `kraftstoff` | `fuel_type` |
| `km` | *(gar nicht - §7.7 Regel 2)* |
| `ts` | `ts` |
Uebereingestimmt hat **allein `ts`** - deshalb Datum und Uhrzeit und sonst
nichts. Der Kraftstoff im Bildschirmfoto war nicht vom Beleg, sondern
`KRAFTSTOFFSORTEN[0]`. Das Panel hat die Namen in `tankFelder()` immer richtig
benutzt; die App hatte sich ihre eigenen ausgedacht.
**Meine Einschaetzung in Abschnitt CM war zu kurz gegriffen.** Dass der
Teilen-Weg und die Dateiauswahl denselben `belegLesen()` benutzen, stimmte -
daraus folgte aber nicht "also nicht die App". Beide Wege waren gleich kaputt.
Richtig war nur, es nicht ohne den Beleg zu entscheiden.
Die Zuordnung steht jetzt als `belegFormularwerte()` in
`daten/belegentwurf.ts`, nicht mehr als `if`-Zeilen im Bildschirm - **als
Funktion laesst sie sich gegen eine echte Nutzlast pruefen, in den `if`-Zeilen
konnte sie es nicht**. Die Nutzlast im Test ist die echte Ausgabe fuer diesen
Beleg, kein erfundenes Beispiel.
Nebenbei mitgenommen: `0` ist ein Wert, kein fehlendes Feld. Ein Beleg mit
0,00 EUR Rabatt darf nicht wie "kein Rabatt angegeben" aussehen - deshalb
`== null` und nicht `!wert`.
### Verifiziert
`tsc --noEmit` sauber, **258 Tests** (von 246: 6 fuer die gespeicherte Marke,
6 fuer die Formularwerte), `vite build` sauber, Panel als **Modul** geparst,
Parser-Suite **11 Tests** gegen jetzt elf echte Belege.
**Die drei Marken-Tests gegen den alten Stand laufen lassen** (`marke`-Parameter
ignoriert): 3 von 36 scheitern, danach wieder 36 gruen. Der Test misst also,
was er behauptet.
**Panel und App byteweise gleich** fuer elf Faelle mit und ohne gespeicherte
Marke - die Panel-Funktionen aus dem Buendel geschnitten und in Node gegen
dieselben Eingaben laufen lassen, nicht nachgebaut.
**Live in `audi_ha_test` (2026.9.4.21, 0 Tracebacks):**
* Uebersicht `Shell, Nürnberger Str., Ansbach`, Einzelbeleg
`Shell, Nürnberger Str. 74` / `91522 Ansbach`.
* Den echten geteilten Beleg ueber `beleg_hochladen` durchs Backend geschickt
und die veroeffentlichte Entitaet gelesen: `station_brand: "Shell"`, und die
Formularzuordnung ergibt daraus `43.87` / `95.6` / `11.84` /
`Shell, Richard-Wagner-Str. 9, Ingolstadt` / `V-Power Racing` /
`2026-04-03T00:55` - also das ganze Formular, nicht nur die Uhrzeit.
* Die Prueflast danach wieder entfernt (`/config/www/pruefbeleg.pdf` und die
verwaiste `belege/geteilt-pruefung.pdf`; kein Tankvorgang zeigte darauf).
**Nicht geprueft:** die iOS-Huelle - die Aenderungen der App liegen im
OTA-Buendel (2026.9.4.21) und brauchen keinen Xcode-Lauf. Der offene Punkt aus
Abschnitt CM bleibt: dass die `packageClassList`-Registrierung auf dem Geraet
greift, zeigt erst der naechste Xcode-Lauf.