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:
@@ -1331,6 +1331,13 @@ function markeErkennen(name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* NUR DER ZWEITE WEG: seit dem 04.09.2026 speichert die Integration die Marke
|
||||
als eigenes Feld `station_brand` (shell_beleg_parser._marke, aus dem
|
||||
Belegkopf), und fuer Altbelege traegt sie belege.marken_nachtragen() aus der
|
||||
abgelegten Belegdatei nach. Wo dieses Feld etwas hergibt, gilt es - hier
|
||||
geraten wird nur, wo es fehlt: bei Vorgaengen ohne Beleg, bei von Hand
|
||||
eingetragenen Tankstellen und solange das Nachtragen nicht gelaufen ist. */
|
||||
|
||||
/* Kennzeichen einer Firmierung. Ein Teil, der so etwas enthaelt, ist der
|
||||
BETREIBER und gehoert nach Vorgabe des Eigentuemers nicht in die Anzeige. */
|
||||
const FIRMA_MUSTER = /\b(gmbh|mbh|ohg|kg|ag|e\.\s?k\.|inh\.|& co)\b/i;
|
||||
@@ -1357,13 +1364,23 @@ function strasseKuerzen(strasse) {
|
||||
Die Markenerkennung lief bis hierher nur ueber den Namen - bei den aelteren
|
||||
Belegen steht die Marke dort gar nicht, deshalb blieb in der Uebersicht die
|
||||
Firmierung stehen ("...GmbH", Nutzerbefund 04.09.2026), waehrend die
|
||||
Anschrift daneben ungenutzt blieb. Gelesen werden jetzt beide Felder. */
|
||||
function tankstelleTeile(name, adresse) {
|
||||
const teile = { marke: markeErkennen(name) || "", strasse: "", hausnummer: "", plz: "", ort: "", roh: (name || "").trim() };
|
||||
Anschrift daneben ungenutzt blieb. Gelesen werden jetzt beide Felder.
|
||||
|
||||
`marke` ist die gespeicherte Angabe des Belegs (station_brand). Sie geht
|
||||
vor, weil sie vom Belegkopf stammt und nicht aus dem Anzeigenamen geraten
|
||||
ist - genau die Luecke, durch die der Beleg vom 10.11.2025 ohne Marke
|
||||
dastand, obwohl "Shell Station" auf ihm steht. */
|
||||
function tankstelleTeile(name, adresse, marke) {
|
||||
const teile = { marke: (marke || "").trim() || markeErkennen(name) || "", strasse: "", hausnummer: "", plz: "", ort: "", roh: (name || "").trim() };
|
||||
const quellen = (adresse || "").split(",");
|
||||
for (const stueck of (name || "").split(",")) {
|
||||
const t = stueck.trim();
|
||||
if (teile.marke && t.toLowerCase() === teile.marke.toLowerCase()) continue;
|
||||
// Ein Teil, der fuer sich genommen eine Kopfmarke IST, taugt nie als Ort.
|
||||
// Frueher stand hier nur der Vergleich mit der gewaehlten Marke; seit die
|
||||
// gespeicherte Angabe vorgeht, koennen beide auseinanderfallen, und dann
|
||||
// rutschte die Marke aus dem Namen in den Ort.
|
||||
const eigen = t ? markeErkennen(t) : null;
|
||||
if (eigen && eigen.toLowerCase() === t.toLowerCase()) continue;
|
||||
quellen.push(t);
|
||||
}
|
||||
for (const stueck of quellen) {
|
||||
@@ -1395,16 +1412,16 @@ function tankstelleTeile(name, adresse) {
|
||||
(Vorgabe des Eigentuemers, 04.09.2026). Ergibt die Zerlegung nichts, bleibt
|
||||
der rohe Name stehen - ihn wegzulassen hiesse, eine bekannte Tankstelle
|
||||
"unbekannt" zu nennen. */
|
||||
function tankstelleKurz(name, adresse) {
|
||||
const t = tankstelleTeile(name, adresse);
|
||||
function tankstelleKurz(name, adresse, marke) {
|
||||
const t = tankstelleTeile(name, adresse, marke);
|
||||
return [t.marke, t.strasse, t.ort].filter(Boolean).join(", ") || t.roh || "unbekannt";
|
||||
}
|
||||
|
||||
/* Die beiden Zeilen im Einzelbeleg: oben Marke und Strasse mit Hausnummer,
|
||||
unten Postleitzahl und Ort - geschrieben wie eine Anschrift, das Komma
|
||||
trennt nur die Marke ab. `oben` ist nie leer. */
|
||||
function tankstelleZeilen(name, adresse) {
|
||||
const t = tankstelleTeile(name, adresse);
|
||||
function tankstelleZeilen(name, adresse, marke) {
|
||||
const t = tankstelleTeile(name, adresse, marke);
|
||||
const strasse = [t.strasse, t.hausnummer].filter(Boolean).join(" ");
|
||||
let oben = [t.marke, strasse].filter(Boolean).join(", ");
|
||||
let unten = [t.plz, t.ort].filter(Boolean).join(" ");
|
||||
@@ -1442,10 +1459,10 @@ function tankstelleSuchtext(name, adresse) {
|
||||
/* Ziel fuer den Kartendienst. Hier gehoeren Name UND Anschrift zusammen:
|
||||
Apple Karten und Google Maps kennen Betriebsnamen und treffen damit die
|
||||
Zapfsaeule statt des Nachbargebaeudes. */
|
||||
function tankstelleZiel(name, adresse) {
|
||||
function tankstelleZiel(name, adresse, marke) {
|
||||
const a = (adresse || "").trim();
|
||||
if (!a) return (name || "").trim();
|
||||
return [markeErkennen(name) || "", a].filter(Boolean).join(", ");
|
||||
return [(marke || "").trim() || markeErkennen(name) || "", a].filter(Boolean).join(", ");
|
||||
}
|
||||
|
||||
/* Die Kandidaten der Reihe nach nachschlagen, erster Treffer gewinnt. */
|
||||
@@ -1467,9 +1484,9 @@ function apfelgeraet() {
|
||||
Tankstellen-Verweis im Einzelbeleg will das Zweite (Vorgabe des
|
||||
Eigentuemers, 04.09.2026): erst sehen, wo sie liegt - eine Route erwartet
|
||||
dort niemand, und sie ist im Kartendienst einen Tipp entfernt. */
|
||||
function kartendienstUrl(name, adresse, pos, modus = "route") {
|
||||
function kartendienstUrl(name, adresse, pos, modus = "route", marke) {
|
||||
const beschriftung = (name || "").trim();
|
||||
const ziel = pos ? `${pos.lat},${pos.lon}` : tankstelleZiel(name, adresse);
|
||||
const ziel = pos ? `${pos.lat},${pos.lon}` : tankstelleZiel(name, adresse, marke);
|
||||
if (!ziel) return null;
|
||||
if (apfelgeraet()) {
|
||||
if (modus === "zeigen") {
|
||||
@@ -1499,7 +1516,7 @@ function tankstelleAufKarteZeigen(karte, pos, f) {
|
||||
// Dieselben zwei Zeilen wie in der Wertezeile darunter (tankstelleZeilen) -
|
||||
// die Nadel soll nicht die Firmierung des Betreibers nennen, wenn die Zeile
|
||||
// die Kopfmarke zeigt.
|
||||
const zeilen = tankstelleZeilen(f.station_name, f.station_address);
|
||||
const zeilen = tankstelleZeilen(f.station_name, f.station_address, f.station_brand);
|
||||
window.L.marker([pos.lat, pos.lon], { icon }).addTo(karte)
|
||||
.bindPopup(esc(zeilen.oben) + (zeilen.unten ? "<br>" + esc(zeilen.unten) : ""));
|
||||
// Position merken und den Knopf scharf schalten - er kann erst jetzt etwas
|
||||
@@ -4752,7 +4769,7 @@ function vFuel() {
|
||||
<span>Ø ${de(schnittpreis(fm), 2)} €/l</span></span></button>
|
||||
<div class="acc-b ${mi === 0 ? "on" : ""}" id="fm${j}${m}">`;
|
||||
fm.forEach((f) => { const preis = literpreis(f); h += swipeZeile(`fill:${f.tank_id}`, `<button class="leaf" data-go="fill:${f.tank_id}">
|
||||
<span class="k">${dedat(new Date(f.ts))}<small>${esc(tankstelleKurz(f.station_name, f.station_address))}</small></span>
|
||||
<span class="k">${dedat(new Date(f.ts))}<small>${esc(tankstelleKurz(f.station_name, f.station_address, f.station_brand))}</small></span>
|
||||
<span class="v">${f.liters != null ? de(f.liters, 2) + " l" : ""}<small>${preis != null ? de(preis, 2) + " €/l" : ""}</small></span>
|
||||
<svg class="chev" viewBox="0 0 6 10"><polyline points="1,1 5,5 1,9"/></svg></button>`); });
|
||||
h += `</div></div>`;
|
||||
@@ -4793,8 +4810,8 @@ function belegKarte(f) {
|
||||
Geraets; ohne Name und ohne Anschrift bleibt es eine stumme Zeile, denn
|
||||
ein Verweis, der nirgendwohin fuehrt, waere schlechter als keiner. */
|
||||
function tankstellenZeile(f) {
|
||||
const { oben, unten } = tankstelleZeilen(f.station_name, f.station_address);
|
||||
const url = kartendienstUrl(f.station_name, f.station_address, null, "zeigen");
|
||||
const { oben, unten } = tankstelleZeilen(f.station_name, f.station_address, f.station_brand);
|
||||
const url = kartendienstUrl(f.station_name, f.station_address, null, "zeigen", f.station_brand);
|
||||
const inhalt =
|
||||
`<span class="tankstellenzeile-ort">${esc(oben)}${unten ? `<small>${esc(unten)}</small>` : ""}</span>` +
|
||||
(url ? `<svg class="chev" viewBox="0 0 6 10" aria-hidden="true"><polyline points="1,1 5,5 1,9"/></svg>` : "");
|
||||
|
||||
Reference in New Issue
Block a user