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:
@@ -85,6 +85,9 @@ export interface Tankvorgang {
|
||||
/** Immer aus fuel_total_eur/liters berechnet, nie aus dem Beleg gelesen. */
|
||||
price_per_l: number | null;
|
||||
station_name?: string | null;
|
||||
/** Kopfmarke des Belegs (shell_beleg_parser). Fehlt bei Vorgaengen ohne
|
||||
Beleg und bei Belegen, deren Datei nicht mehr liegt. */
|
||||
station_brand?: string | null;
|
||||
station_id?: string | null;
|
||||
station_address?: string | null;
|
||||
fuel_type?: string | null;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Tests zur Uebernahme eines eingelesenen Belegs ins Tankformular.
|
||||
*
|
||||
* Die Nutzlast unten ist KEIN erfundenes Beispiel: sie ist die Ausgabe von
|
||||
* shell_beleg_parser._parsen() fuer den Beleg, den der Eigentuemer am
|
||||
* 04.09.2026 ueber das Teilen-Blatt hereingereicht hat und der in der App nur
|
||||
* mit Datum und Uhrzeit ankam (Shell, Richard-Wagner-Str. 9, Ingolstadt,
|
||||
* 43,87 l fuer 95,60 EUR). Genau dieser Fall gehoert in einen Test.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import { belegFormularwerte } from "./belegentwurf"
|
||||
|
||||
/* Wortgleich mit dem, was belege._beleg_felder() fuer diesen Beleg
|
||||
veroeffentlicht - die Feldnamen sind der Punkt dieser Suite. */
|
||||
const GETEILT = {
|
||||
receipt_key: "0000000459_3368-082-00082_2026-04-03T00:55",
|
||||
receipt_no: "3368/082/00082",
|
||||
tse_beleg_nr: "73912",
|
||||
ts: "2026-04-03T00:55:00",
|
||||
ts_payment: "2026-04-03T00:52:43",
|
||||
ts_tse: "2026-04-03T00:55:01",
|
||||
station_id: "0000000459",
|
||||
station_brand: "Shell",
|
||||
station_name: "Shell, Richard-Wagner-Str. 9, Ingolstadt",
|
||||
station_address: "Richard-Wagner-Str. 9, 85057 Ingolstadt",
|
||||
article_no: "000013",
|
||||
product_name: "V-Power Racing",
|
||||
fuel_type: "V-Power Racing",
|
||||
liters: 43.87,
|
||||
fuel_total_eur: 95.6,
|
||||
price_per_l: 2.1792,
|
||||
discount: 11.84,
|
||||
discount_per_l: 0.27,
|
||||
list_price_per_l: 2.449,
|
||||
receipt_total_eur: 95.6,
|
||||
net_eur: 80.34,
|
||||
vat_eur: 15.26,
|
||||
receipt_file: "/config/audi_dashboard/belege/e-receipt (7).pdf",
|
||||
}
|
||||
|
||||
describe("belegFormularwerte", () => {
|
||||
it("fuellt das ganze Formular, nicht nur Datum und Uhrzeit", () => {
|
||||
// Der gemeldete Fehler: alles ausser zeitpunkt blieb leer, weil die App
|
||||
// liter/kosten/station/ersparnis/kraftstoff abfragte statt der
|
||||
// Belegfelder.
|
||||
expect(belegFormularwerte(GETEILT)).toEqual({
|
||||
zeitpunkt: "2026-04-03T00:55",
|
||||
liter: "43.87",
|
||||
kosten: "95.6",
|
||||
ersparnis: "11.84",
|
||||
station: "Shell, Richard-Wagner-Str. 9, Ingolstadt",
|
||||
kraftstoff: "V-Power Racing",
|
||||
})
|
||||
})
|
||||
|
||||
it("nimmt den realen Betrag, nicht den Listenpreis", () => {
|
||||
// fuel_total_eur ist bereits rabattiert; receipt_total_eur waere hier
|
||||
// zufaellig gleich, list_price_per_l dagegen ein Preis je Liter.
|
||||
expect(belegFormularwerte(GETEILT).kosten).toBe(String(GETEILT.fuel_total_eur))
|
||||
})
|
||||
|
||||
it("laesst Felder leer, die der Beleg nicht nennt", () => {
|
||||
// Ein Beleg ohne Rabatt ist normal (BelegOhneRabatt im Parsertest) - das
|
||||
// Formularfeld soll dann nicht auf "null" stehen.
|
||||
expect(belegFormularwerte({ ...GETEILT, discount: null })).toMatchObject({ ersparnis: "" })
|
||||
expect(belegFormularwerte({ ts: "2026-04-03T00:55:00" })).toEqual({
|
||||
zeitpunkt: "2026-04-03T00:55",
|
||||
liter: "",
|
||||
kosten: "",
|
||||
ersparnis: "",
|
||||
station: "",
|
||||
kraftstoff: "",
|
||||
})
|
||||
})
|
||||
|
||||
it("laesst eine echte Null durch", () => {
|
||||
// 0 ist ein Wert, kein fehlendes Feld - ein Beleg mit 0,00 EUR Rabatt
|
||||
// darf nicht wie "kein Rabatt angegeben" aussehen.
|
||||
expect(belegFormularwerte({ ...GETEILT, discount: 0 }).ersparnis).toBe("0")
|
||||
})
|
||||
|
||||
it("kommt mit gar keinem Beleg zurecht", () => {
|
||||
expect(belegFormularwerte(null).zeitpunkt).toBe("")
|
||||
expect(belegFormularwerte(undefined).liter).toBe("")
|
||||
})
|
||||
|
||||
it("uebernimmt keinen Kilometerstand", () => {
|
||||
// SPECIFICATION.md §7.7 Regel 2: der kommt immer vom Fahrzeug.
|
||||
expect(Object.keys(belegFormularwerte(GETEILT))).not.toContain("km")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Was ein eingelesener Beleg ins Tankformular traegt.
|
||||
*
|
||||
* WARUM DAS HIER STEHT UND NICHT IM BILDSCHIRM
|
||||
* -------------------------------------------
|
||||
* Bis zum 04.09.2026 stand die Uebernahme als Folge von `if`-Zeilen in
|
||||
* `Tanken.tsx` - und fragte `liter`/`kosten`/`station`/`ersparnis`/
|
||||
* `kraftstoff` ab, also die Namen der FORMULARFELDER. Veroeffentlicht werden
|
||||
* aber die Namen des BELEGS (`_beleg_felder` in belege.py, dieselben, die auch
|
||||
* im Tankvorgang landen). Uebereingestimmt hat allein `ts`.
|
||||
*
|
||||
* Sichtbar war das als: ein eingelesener Beleg fuellte Datum und Uhrzeit,
|
||||
* sonst nichts (Befund des Eigentuemers, 04.09.2026 - gemeldet fuer einen
|
||||
* ueber das Teilen-Blatt hereingereichten Beleg, betraf aber jeden Weg
|
||||
* gleichermassen, weil beide durch `belegLesen()` laufen). Als eigene
|
||||
* Funktion laesst sich die Zuordnung gegen eine echte Nutzlast pruefen; in
|
||||
* den `if`-Zeilen des Bildschirms konnte sie es nicht.
|
||||
*
|
||||
* KEIN KILOMETERSTAND
|
||||
* -------------------
|
||||
* Er kommt immer vom Fahrzeug, nie vom Beleg (SPECIFICATION.md §7.7 Regel 2).
|
||||
* Das Panel haelt es in `tankFelder()` genauso.
|
||||
*/
|
||||
|
||||
/** Die Felder, die belege.py nach dem Lesen eines Belegs veroeffentlicht. */
|
||||
export interface BelegEntwurf {
|
||||
ts?: string
|
||||
liters?: number | null
|
||||
/** Der reale, bereits rabattierte Betrag. */
|
||||
fuel_total_eur?: number | null
|
||||
/** SmartDeal-Ersparnis. */
|
||||
discount?: number | null
|
||||
station_name?: string | null
|
||||
fuel_type?: string | null
|
||||
receipt_key?: string | null
|
||||
receipt_file?: string | null
|
||||
}
|
||||
|
||||
/** Was davon in welches Formularfeld geht - leere Zeichenkette heisst: nicht
|
||||
setzen, das Feld behaelt seinen bisherigen Wert. */
|
||||
export interface Formularwerte {
|
||||
zeitpunkt: string
|
||||
liter: string
|
||||
kosten: string
|
||||
ersparnis: string
|
||||
station: string
|
||||
kraftstoff: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Zahl in die Zeichenkette eines Zahlenfelds. `0` ist ein gueltiger Wert und
|
||||
* muss durchkommen - nur `null`/`undefined` bedeuten "steht nicht im Beleg".
|
||||
*/
|
||||
function zahl(wert: number | null | undefined): string {
|
||||
return wert == null ? "" : String(wert)
|
||||
}
|
||||
|
||||
export function belegFormularwerte(e: BelegEntwurf | null | undefined): Formularwerte {
|
||||
return {
|
||||
// Das Eingabefeld will "JJJJ-MM-TTThh:mm", der Beleg liefert Sekunden mit.
|
||||
zeitpunkt: e?.ts ? e.ts.slice(0, 16) : "",
|
||||
liter: zahl(e?.liters),
|
||||
kosten: zahl(e?.fuel_total_eur),
|
||||
ersparnis: zahl(e?.discount),
|
||||
station: e?.station_name ?? "",
|
||||
kraftstoff: e?.fuel_type ?? "",
|
||||
}
|
||||
}
|
||||
@@ -249,3 +249,60 @@ describe("tankstelleKurz und tankstelleZeilen an echten Belegen", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("gespeicherte Marke (station_brand)", () => {
|
||||
/* Der Beleg vom 10.11.2025, wie er wirklich gespeichert ist: der Name traegt
|
||||
den BETREIBER, die Marke steht nur auf dem PDF. Seit dem 04.09.2026 liest
|
||||
sie shell_beleg_parser._marke aus dem Belegkopf, belege.marken_nachtragen
|
||||
traegt sie fuer Altbelege nach - und hier kommt sie an. */
|
||||
const NAME = "TC Sengül GmbH"
|
||||
const ADRESSE = "Nürnberger Str.74, 91522 Ansbach"
|
||||
|
||||
it("nimmt die gespeicherte Marke, wo der Name keine hergibt", () => {
|
||||
// Ohne sie stand der Einzelbeleg ohne Marke da, obwohl "Shell Station"
|
||||
// auf dem Beleg steht (Befund des Eigentuemers, 04.09.2026).
|
||||
expect(tankstelleZeilen(NAME, ADRESSE)).toEqual({
|
||||
oben: "Nürnberger Str. 74",
|
||||
unten: "91522 Ansbach",
|
||||
})
|
||||
expect(tankstelleZeilen(NAME, ADRESSE, "Shell")).toEqual({
|
||||
oben: "Shell, Nürnberger Str. 74",
|
||||
unten: "91522 Ansbach",
|
||||
})
|
||||
})
|
||||
|
||||
it("nimmt sie auch in der Uebersicht", () => {
|
||||
expect(tankstelleKurz(NAME, ADRESSE, "Shell")).toBe("Shell, Nürnberger Str., Ansbach")
|
||||
})
|
||||
|
||||
it("geht der Erkennung aus dem Namen vor", () => {
|
||||
// Die gespeicherte Angabe stammt vom Belegkopf, die andere ist geraten.
|
||||
expect(tankstelleTeile("Aral, Musterweg 1, Musterort", null, "Shell").marke).toBe("Shell")
|
||||
})
|
||||
|
||||
it("faellt auf die Erkennung zurueck, wo nichts gespeichert ist", () => {
|
||||
// Vorgaenge ohne Beleg und von Hand eingetragene Tankstellen haben das
|
||||
// Feld nie - dort bleibt es beim bisherigen Weg.
|
||||
expect(tankstelleKurz("Shell, Pascalstr. 8, Ingolstadt", null, null)).toBe(
|
||||
"Shell, Pascalstr., Ingolstadt",
|
||||
)
|
||||
expect(tankstelleKurz("Shell, SÖLDEN", null, undefined).startsWith("Shell")).toBe(true)
|
||||
})
|
||||
|
||||
it("behandelt eine leere gespeicherte Marke wie gar keine", () => {
|
||||
// marken_nachtragen schreibt null, wenn der Beleg keine Marke nennt.
|
||||
expect(tankstelleTeile("Shell, SÖLDEN", null, "").marke).toBe("Shell")
|
||||
expect(tankstelleTeile("Shell, SÖLDEN", null, " ").marke).toBe("Shell")
|
||||
})
|
||||
|
||||
it("gibt sie dem Kartendienst mit", () => {
|
||||
// Apple Karten und Google Maps treffen mit der Marke die Zapfsaeule statt
|
||||
// des Nachbargebaeudes - die Firmierung hilft dort nirgends.
|
||||
expect(tankstelleZiel(NAME, ADRESSE, "Shell")).toBe(
|
||||
"Shell, Nürnberger Str.74, 91522 Ansbach",
|
||||
)
|
||||
expect(kartendienstUrl(NAME, ADRESSE, null, "zeigen", "Shell")).toContain(
|
||||
encodeURIComponent("Shell, Nürnberger Str.74, 91522 Ansbach"),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -61,6 +61,13 @@ const MARKEN = [
|
||||
* sichtbar ist die Kopfmarke.
|
||||
*
|
||||
* Wortgrenzen sind Absicht: "Star" darf nicht in "Starnberg" treffen.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
export function markeErkennen(name: string | null | undefined): string | null {
|
||||
const roh = (name ?? "").trim()
|
||||
@@ -132,13 +139,19 @@ export interface Tankstellenteile {
|
||||
* waehrend die Anschrift daneben ungenutzt blieb. Gelesen werden deshalb
|
||||
* beide Felder: die Anschrift zuerst (sie ist die strukturierte Quelle), der
|
||||
* Name danach fuer Marke und alles, was die Anschrift nicht hergibt.
|
||||
*
|
||||
* `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.
|
||||
*/
|
||||
export function tankstelleTeile(
|
||||
name: string | null | undefined,
|
||||
adresse: string | null | undefined,
|
||||
marke?: string | null | undefined,
|
||||
): Tankstellenteile {
|
||||
const teile: Tankstellenteile = {
|
||||
marke: markeErkennen(name) ?? "",
|
||||
marke: (marke ?? "").trim() || markeErkennen(name) || "",
|
||||
strasse: "",
|
||||
hausnummer: "",
|
||||
plz: "",
|
||||
@@ -150,8 +163,11 @@ export function tankstelleTeile(
|
||||
for (const stueck of (adresse ?? "").split(",")) quellen.push(stueck)
|
||||
for (const stueck of (name ?? "").split(",")) {
|
||||
const t = stueck.trim()
|
||||
// Die Marke steht schon fest; als Ort taugt sie nicht.
|
||||
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.
|
||||
if (t && markeErkennen(t)?.toLowerCase() === t.toLowerCase()) continue
|
||||
quellen.push(t)
|
||||
}
|
||||
|
||||
@@ -195,8 +211,9 @@ export function tankstelleTeile(
|
||||
export function tankstelleKurz(
|
||||
name: string | null | undefined,
|
||||
adresse: string | null | undefined,
|
||||
marke?: string | null | undefined,
|
||||
): string {
|
||||
const t = tankstelleTeile(name, adresse)
|
||||
const t = tankstelleTeile(name, adresse, marke)
|
||||
const zeile = [t.marke, t.strasse, t.ort].filter(Boolean).join(", ")
|
||||
return zeile || t.roh || "unbekannt"
|
||||
}
|
||||
@@ -215,8 +232,9 @@ export function tankstelleKurz(
|
||||
export function tankstelleZeilen(
|
||||
name: string | null | undefined,
|
||||
adresse: string | null | undefined,
|
||||
marke?: string | null | undefined,
|
||||
): { oben: string; unten: string } {
|
||||
const t = tankstelleTeile(name, adresse)
|
||||
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(" ")
|
||||
@@ -283,10 +301,11 @@ export function tankstelleSuchtext(
|
||||
export function tankstelleZiel(
|
||||
name: string | null | undefined,
|
||||
adresse: string | null | undefined,
|
||||
marke?: string | null | undefined,
|
||||
): string {
|
||||
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(", ")
|
||||
}
|
||||
|
||||
/** Apple-Gerät? Dort ist Karten der Standarddienst. */
|
||||
@@ -315,9 +334,10 @@ export function kartendienstUrl(
|
||||
adresse: string | null | undefined,
|
||||
pos?: Koordinate | null,
|
||||
modus: Kartenmodus = "route",
|
||||
marke?: string | null | undefined,
|
||||
): string | null {
|
||||
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") {
|
||||
|
||||
@@ -72,7 +72,11 @@ export function TankDetail({ id, geheZu }: { id: string | undefined; geheZu: (na
|
||||
return (
|
||||
<>
|
||||
<Tile className="dm-kartenkachel">
|
||||
<TankstellenKarte name={tank.station_name} adresse={tank.station_address} />
|
||||
<TankstellenKarte
|
||||
name={tank.station_name}
|
||||
adresse={tank.station_address}
|
||||
marke={tank.station_brand}
|
||||
/>
|
||||
</Tile>
|
||||
|
||||
<Tile variant="flat" className="dm-distanzkachel">
|
||||
@@ -125,7 +129,11 @@ export function TankDetail({ id, geheZu }: { id: string | undefined; geheZu: (na
|
||||
wert={`${eur(tank.discount)} €`}
|
||||
/>
|
||||
)}
|
||||
<Tankstellenzeile name={tank.station_name} adresse={tank.station_address} />
|
||||
<Tankstellenzeile
|
||||
name={tank.station_name}
|
||||
adresse={tank.station_address}
|
||||
marke={tank.station_brand}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
@@ -153,12 +161,14 @@ export function TankDetail({ id, geheZu }: { id: string | undefined; geheZu: (na
|
||||
function Tankstellenzeile({
|
||||
name,
|
||||
adresse,
|
||||
marke,
|
||||
}: {
|
||||
name: string | null | undefined
|
||||
adresse: string | null | undefined
|
||||
marke?: string | null | undefined
|
||||
}) {
|
||||
const { oben, unten } = tankstelleZeilen(name, adresse)
|
||||
const url = kartendienstUrl(name, adresse, null, "zeigen")
|
||||
const { oben, unten } = tankstelleZeilen(name, adresse, marke)
|
||||
const url = kartendienstUrl(name, adresse, null, "zeigen", marke)
|
||||
const inhalt = (
|
||||
<>
|
||||
<span className="dm-tankstellenzeile__ort">
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import { Blattzeile, KRAFTSTOFFSORTEN, Leerzustand } from "./bausteine"
|
||||
import { BelegPopup } from "./BelegPopup"
|
||||
import { markenlogoUrl } from "./bilder"
|
||||
import { belegFormularwerte, type BelegEntwurf } from "../daten/belegentwurf"
|
||||
import { tankstelleKurz } from "../daten/tankstelle"
|
||||
import { LOESCH_HINWEIS } from "./bestaetigung"
|
||||
import { Zeilenmenue } from "./Zeilenmenue"
|
||||
@@ -125,7 +126,11 @@ export function Tanken({ geheZu }: { geheZu: (name: SeitenName, id?: string) =>
|
||||
kinder={
|
||||
<Blattzeile
|
||||
label={datum(tank.ts)}
|
||||
labelZusatz={tankstelleKurz(tank.station_name, tank.station_address)}
|
||||
labelZusatz={tankstelleKurz(
|
||||
tank.station_name,
|
||||
tank.station_address,
|
||||
tank.station_brand,
|
||||
)}
|
||||
wert={tank.liters != null ? `${de(tank.liters, 2)} l` : ""}
|
||||
wertZusatz={preis != null ? `${de(preis, 2)} €/l` : ""}
|
||||
beiKlick={() => geheZu("fill", tank.tank_id)}
|
||||
@@ -157,19 +162,6 @@ export function Tanken({ geheZu }: { geheZu: (name: SeitenName, id?: string) =>
|
||||
)
|
||||
}
|
||||
|
||||
/** Felder, die belege.py nach dem Lesen eines Belegs veröffentlicht. */
|
||||
interface BelegEntwurf {
|
||||
ts?: string
|
||||
liter?: number | null
|
||||
kosten?: number | null
|
||||
km?: number | null
|
||||
ersparnis?: number | null
|
||||
station?: string | null
|
||||
kraftstoff?: string | null
|
||||
receipt_key?: string | null
|
||||
receipt_file?: string | null
|
||||
}
|
||||
|
||||
/** Monatsname allein, wie im Panel. */
|
||||
function monatName(jahr: number, monat: number): string {
|
||||
return new Date(jahr, monat, 1).toLocaleDateString("de-DE", { month: "long" })
|
||||
@@ -275,13 +267,13 @@ function TankFormular({
|
||||
setzeFehler(e.fehler)
|
||||
} else {
|
||||
setzeBeleg(e)
|
||||
if (e.liter != null) setzeLiter(String(e.liter))
|
||||
if (e.kosten != null) setzeKosten(String(e.kosten))
|
||||
if (e.station) setzeStation(e.station)
|
||||
if (e.km != null) setzeKm(String(e.km))
|
||||
if (e.ersparnis != null) setzeErsparnis(String(e.ersparnis))
|
||||
if (e.kraftstoff) setzeKraftstoff(e.kraftstoff)
|
||||
if (e.ts) setzeZeitpunkt(e.ts.slice(0, 16))
|
||||
const w = belegFormularwerte(e)
|
||||
if (w.zeitpunkt) setzeZeitpunkt(w.zeitpunkt)
|
||||
if (w.liter) setzeLiter(w.liter)
|
||||
if (w.kosten) setzeKosten(w.kosten)
|
||||
if (w.ersparnis) setzeErsparnis(w.ersparnis)
|
||||
if (w.station) setzeStation(w.station)
|
||||
if (w.kraftstoff) setzeKraftstoff(w.kraftstoff)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -32,9 +32,11 @@ import { Karte } from "./Karte"
|
||||
export function TankstellenKarte({
|
||||
name,
|
||||
adresse,
|
||||
marke,
|
||||
}: {
|
||||
name?: string | null | undefined
|
||||
adresse: string | null | undefined
|
||||
marke?: string | null | undefined
|
||||
}) {
|
||||
const [position, setzePosition] = useState<Koordinate | null>(null)
|
||||
const [geprueft, setzeGeprueft] = useState(false)
|
||||
@@ -68,7 +70,7 @@ export function TankstellenKarte({
|
||||
|
||||
// Wie im Panel (tankstelleAufKarteZeigen): die CI-Nadel mit Name und
|
||||
// Anschrift im Popup, dazu der Knopf, der wieder darauf zentriert.
|
||||
if (position) return <Karte start={position} nadel={tankstelleZeilen(name, adresse)} />
|
||||
if (position) return <Karte start={position} nadel={tankstelleZeilen(name, adresse, marke)} />
|
||||
// Solange die Auflösung läuft: eine leere Kartenfläche, wie im Panel (die
|
||||
// Karte steht dort schon, die Nadel kommt nach). Bewusst nicht die
|
||||
// Ladeanzeige der Seite - die meldet „der Bildschirm ist noch nicht da".
|
||||
|
||||
Reference in New Issue
Block a user