TANK_DISTANZ_SENSOR + Datensatz sichern/laden mit echtem CSV-Import (Panel)
- Neuer optionaler Sensor TANK_DISTANZ_SENSOR ersetzt die eigene Kilometerstand-Subtraktion fuer die Tankvorgang-Strecke, wo zugeordnet (Live-Erkennung, manuelle Erfassung, historischer Import) - "Fahrzeugprofil" und "Daten ausgeben" zu einer Kachel zusammengelegt: "Datensatz sichern" (4 Exporte wie bisher) / "Datensatz laden" (neu: echter CSV-Import fuer Fahrten/Tankvorgaenge/Wartungsplan) - Import gleicht per ID ab (Fahrten/Tankvorgaenge) bzw. Datum+Art (Wartungsplan, hat keine eigene ID) und aktualisiert nur die in der CSV enthaltenen Spalten - alles andere am Datensatz bleibt unangetastet - Nebenbei gefunden und behoben: belege.tankvorgang_aktualisieren() ueberschrieb bisher immer alle Felder, auch mit None, wenn irgendeins geaendert wurde - fuer den CSV-Import gefaehrlich, jetzt nur noch tatsaechlich uebergebene Felder - Ebenfalls gefunden und behoben: Panel las das Import-Ergebnis per HASS.states direkt nach dem Dienstaufruf - ein Wettlauf mit dem state_changed-Push. Nutzt jetzt denselben HASS.callWS(get_states)-Weg wie der bestehende historie_importieren-Ablauf. companion-app-Portierung von "Datensatz sichern/laden" steht noch aus. Version 2026.8.28.3, live im Testcontainer verifiziert (alle drei CSV-Datensatztypen: anlegen + aktualisieren per ID/Datum+Art getestet, Testdaten danach geloescht). Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -33,6 +33,7 @@ import os
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from . import shell_beleg_parser
|
||||
from . import tankerkennung
|
||||
from .tankerkennung import leerer_tankvorgang
|
||||
from .veroeffentlichung import zustand_oder_none
|
||||
from .verlauf import zeit_normalisiert
|
||||
@@ -195,10 +196,10 @@ async def tankvorgang_manuell(k: Koordinator, daten: dict) -> None:
|
||||
odometer_km = km if km is not None else _km_aus_sensor(k)
|
||||
distanz = daten.get("distanz")
|
||||
if distanz is None:
|
||||
# Vorschlag aus der Differenz zum letzten Tankvorgang, aber wie
|
||||
# odometer_km selbst frei überschreibbar - ein übergebener Wert hat
|
||||
# deshalb immer Vorrang vor der Berechnung.
|
||||
distanz = await k.ablage.distanz_seit_letzter_tankung(odometer_km)
|
||||
# Vorschlag aus TANK_DISTANZ_SENSOR oder, ohne ihn, der Differenz zum
|
||||
# letzten Tankvorgang - aber wie odometer_km selbst frei
|
||||
# überschreibbar, ein übergebener Wert hat deshalb immer Vorrang.
|
||||
distanz = await tankerkennung.distanz_seit_tankung(k, odometer_km)
|
||||
|
||||
ts_roh = daten.get("ts")
|
||||
ts = zeit_normalisiert(ts_roh) if ts_roh else datetime.datetime.now(datetime.UTC)
|
||||
@@ -236,26 +237,41 @@ def _km_aus_sensor(k: Koordinator) -> float | None:
|
||||
|
||||
async def tankvorgang_aktualisieren(k: Koordinator, daten: dict) -> None:
|
||||
"""Bearbeitet einen bestehenden Tankvorgang (Einzelbeleg-Seite, egal ob
|
||||
ursprünglich per Beleg oder manuell angelegt)."""
|
||||
ursprünglich per Beleg oder manuell angelegt).
|
||||
|
||||
Nur tatsächlich in `daten` enthaltene Schlüssel werden geändert - fehlt
|
||||
ein Feld ganz (statt nur leer/None zu sein), bleibt der bisherige Wert
|
||||
unangetastet. Das bestehende Bearbeiten-Formular (Einzelbeleg-Seite)
|
||||
schickt ohnehin immer alle Felder mit, verhält sich also unverändert;
|
||||
ein schlankerer Aufrufer wie der CSV-Import (csv_import.py) kann so
|
||||
gezielt nur einzelne Spalten aktualisieren, ohne den Rest des
|
||||
Datensatzes (odometer_km, discount, fuel_type, receipt_key, ...)
|
||||
stillschweigend auf None zu setzen."""
|
||||
tank_id = daten.get("tank_id")
|
||||
if not tank_id:
|
||||
_LOGGER.warning("tankvorgang_aktualisieren ohne tank_id aufgerufen")
|
||||
return
|
||||
|
||||
liter = daten.get("liter")
|
||||
kosten = daten.get("kosten")
|
||||
ts_normalisiert = zeit_normalisiert(daten.get("ts"))
|
||||
aenderungen = {
|
||||
"ts": ts_normalisiert.isoformat() if ts_normalisiert else daten.get("ts"),
|
||||
"liters": liter,
|
||||
"fuel_total_eur": kosten,
|
||||
"price_per_l": preis_je_liter(kosten, liter),
|
||||
"odometer_km": daten.get("km"),
|
||||
"discount": daten.get("ersparnis"),
|
||||
"station_name": daten.get("station"),
|
||||
"distance_km": daten.get("distanz"),
|
||||
"fuel_type": daten.get("kraftstoff"),
|
||||
}
|
||||
aenderungen: dict = {}
|
||||
if "ts" in daten:
|
||||
ts_normalisiert = zeit_normalisiert(daten.get("ts"))
|
||||
aenderungen["ts"] = ts_normalisiert.isoformat() if ts_normalisiert else daten.get("ts")
|
||||
if "liter" in daten or "kosten" in daten:
|
||||
liter = daten.get("liter")
|
||||
kosten = daten.get("kosten")
|
||||
aenderungen["liters"] = liter
|
||||
aenderungen["fuel_total_eur"] = kosten
|
||||
aenderungen["price_per_l"] = preis_je_liter(kosten, liter)
|
||||
if "km" in daten:
|
||||
aenderungen["odometer_km"] = daten.get("km")
|
||||
if "ersparnis" in daten:
|
||||
aenderungen["discount"] = daten.get("ersparnis")
|
||||
if "station" in daten:
|
||||
aenderungen["station_name"] = daten.get("station")
|
||||
if "distanz" in daten:
|
||||
aenderungen["distance_km"] = daten.get("distanz")
|
||||
if "kraftstoff" in daten:
|
||||
aenderungen["fuel_type"] = daten.get("kraftstoff")
|
||||
if daten.get("receipt_key"):
|
||||
aenderungen["receipt_key"] = daten["receipt_key"]
|
||||
aenderungen["receipt_file"] = daten.get("receipt_file")
|
||||
|
||||
Reference in New Issue
Block a user