Hauptuntersuchung: Ableitung aus Erstzulassung und Wartungsplan, drittes Feld entfernt

Gemeldet: Wartungsplan leer, Erstzulassung 01.03.2025, erwartet 01.03.2028 -
gezeigt wurden drei verschiedene Antworten (Uebersicht 01.08.2026, Mein Audi
"August 2026", Service "kein Eintrag im Wartungsplan").

Ursache war das Profilfeld hauptuntersuchung_faellig ("08/2026"), das die
Ableitung ueberstimmte, in keiner Oberflaeche ein Eingabefeld hatte und im
Backend kein Schema. Drei Bildschirme verarbeiteten denselben Wert
verschieden. Das Feld ist samt Lese- und Schreibweg entfernt; es gibt jetzt
zwei Quellen: Wartungsplan + 24 Monate, sonst Erstzulassung + 36 Monate.

Dabei mitbehoben:

* Die Service-Kachel verschluckte abgeleitete Termine, sobald kein
  Wartungsplan-Eintrag dahinterstand.
* monatePlus() in der App verlor einen Tag ueber die Zeitumstellung (drei von
  fuenf gemessenen Faellen) - betraf Oelwechsel- und Inspektionsprognose
  genauso. Das Panel rechnete dort seit jeher richtig.
* Die App verlangte fuer jeden Wartungsplan-Eintrag eine Kilometerangabe. Eine
  Hauptuntersuchung ist rein datumsbasiert; ohne km waere der erste HU-Eintrag
  ignoriert worden. Ausserdem nahm das Panel den ersten Treffer der Liste, die
  App den juengsten - beide nehmen jetzt den juengsten.
* Monatsgenauigkeit ("03/2025") bleibt auf beiden Seiten erhalten.

Neu: paritaet_hu.test.ts vergleicht die App gegen die aus der Panel-Quelle
herausgeschnittenen Originalfunktionen, 15 Faelle. Gesamt 292 App-Tests, 73
Python-Tests mit 231 Untertests, 0 Tracebacks. Live an der Testinstanz auf
allen drei gemeldeten Bildschirmen geprueft.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-05 01:56:11 +02:00
co-authored by Claude Opus 5
parent 5621b818cc
commit 863284e540
25 changed files with 505 additions and 243 deletions
+10 -9
View File
@@ -34,7 +34,6 @@ T_WECHSEL = datetime.datetime(2026, 9, 2, 21, 22, 12, tzinfo=datetime.UTC)
class FakeWerte:
TRIP_SENSOR = "binary_sensor.trip"
ZUENDUNG_SENSOR = "binary_sensor.zuendung"
@@ -50,10 +49,9 @@ class FakeKoordinator:
self.fahrt_sperre = asyncio.Lock()
self.beendet = []
self.veroeffentlicht = 0
# Dieser Test beschreibt die Welt MIT Trip-Signal: dort bringt das
# Geraet seine Pausentoleranz mit, _pausenzeit_s() gibt 0 zurueck und
# es wird sofort geschlossen. Gegenstand ist hier die Sperre, nicht
# die Wartezeit - die hat test_zuendungspause.py.
# Gegenstand ist hier die SPERRE, nicht die Wartezeit - die hat
# test_zuendungspause.py. Deshalb ist die Pausenzeit unten auf 0
# gesetzt, dann schliesst _signalwechsel() sofort.
self.zuordnung = FakeZuordnung()
# Seit die Pausenregel in Geraetezeit rechnet, liest _signalwechsel() das
@@ -72,7 +70,10 @@ class FakeKoordinator:
class SignalwechselTest(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
self._echt = (f._geraetezeit, f._echtes_ende, f.fahrt_beenden)
self._echt = (f._geraetezeit, f._echtes_ende, f.fahrt_beenden, f._pausenzeit_s)
async def pausenzeit(k):
return 0
async def geraetezeit(k, ereigniszeit, standard):
# Der eigentliche Punkt: dieser Schritt wartet wirklich (in echt
@@ -88,12 +89,12 @@ class SignalwechselTest(unittest.IsolatedAsyncioTestCase):
k.beendet.append((start_ts, ende_ts))
await k.fahrt_start_setzen(None)
f._geraetezeit, f._echtes_ende, f.fahrt_beenden = (
geraetezeit, echtes_ende, beenden,
f._geraetezeit, f._echtes_ende, f.fahrt_beenden, f._pausenzeit_s = (
geraetezeit, echtes_ende, beenden, pausenzeit,
)
async def asyncTearDown(self):
f._geraetezeit, f._echtes_ende, f.fahrt_beenden = self._echt
f._geraetezeit, f._echtes_ende, f.fahrt_beenden, f._pausenzeit_s = self._echt
async def test_off_und_on_in_derselben_sekunde(self):
"""Der genaue Fall vom 02.09.2026: die neue Fahrt darf nicht verloren