Eigentümersuche mit Trefferliste im Tab „Eigentümer“ (#56)

Eigentümerdatei (CSV-Layer mit Nachname/Vorname) wählen, Name und/oder
Vorname eingeben: Eine nicht modale Trefferliste zeigt Name, Anschrift,
E-Mail und die Kennzeichen „verstorben“/„Rechtsperson“. Gleiche Personen
mit gleicher Anschrift werden zusammengefasst; Groß-/Kleinschreibung und
Umlautschreibweise spielen keine Rolle. Von QGIS als Zahl gelesene PLZ
bekommen ihre führende Null zurück. Meldungen enthalten keine Namen.

Die Auswahltabelle aus „Verfahrensgebiete aus Landkreis laden“ ist als
baue_auswahltabelle herausgelöst und wird von der Trefferliste mitgenutzt.

Zweiter Schritt von #56; Anzeigefenster und Korrekturen folgen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 13:04:16 +02:00
co-authored by Claude Opus 5.5
parent c9a5b8ee2b
commit 29719a8a99
8 changed files with 823 additions and 61 deletions
+84 -1
View File
@@ -1,4 +1,7 @@
"""Tests für den Tab „Eigentümer“ – Flurstückssuche (#56)."""
"""Tests für den Tab „Eigentümer“ – Flurstückssuche und Eigentümersuche (#56).
Alle Namen und Anschriften sind erfunden.
"""
import sys
import types
@@ -21,6 +24,9 @@ from sn_verfahrensgebiet.functions.flurstueck_suche import (
KeinFlurstueckslayer,
SuchErgebnis,
)
from sn_verfahrensgebiet.functions.eigentuemer_suche import Eigentuemer, EigentuemerSucheFehler
from sn_verfahrensgebiet.ui import eigentuemer_treffer as treffer_modul
from sn_verfahrensgebiet.ui.eigentuemer_treffer import EigentuemerTrefferFenster, trefferzeile
def _tab(gemarkung="0268", flurstueck="562"):
@@ -86,6 +92,83 @@ class TestFlurstueckSuchen(unittest.TestCase):
self.assertIn("1 Flurstück", erfolg.call_args[0][1])
def _eig_tab(nachname="Beispiel", vorname="", layer_id="csv1"):
tab = EigentuemerTab.__new__(EigentuemerTab)
tab.nachname_edit = types.SimpleNamespace(text=lambda: nachname)
tab.vorname_edit = types.SimpleNamespace(text=lambda: vorname)
tab.eigentuemer_layer_combo = MagicMock()
tab.eigentuemer_layer_combo.currentData.return_value = layer_id
tab._trefferfenster = None
return tab
_ANNA = Eigentuemer(vorname="Anna", nachname="Beispiel", strasse="Hauptstraße 1", plz="01234",
wohnort="Musterstadt", emails=("anna@example.org",), verstorben=True)
@patch.object(et, "info")
@patch.object(et, "warning")
class TestEigentuemerSuchen(unittest.TestCase):
def test_ohne_eigentuemerdatei_warnung(self, warnung, hinweis):
"""Prüft, dass ohne gewählte Eigentümerdatei die Liste aufgefrischt und dann auf das Laden der CSV hingewiesen wird."""
tab = _eig_tab(layer_id=None)
with patch.object(et, "hole_layer", return_value=None), patch.object(et, "suche_eigentuemer") as suche:
tab._on_eigentuemer_suchen()
tab.eigentuemer_layer_combo.aktualisieren.assert_called_once()
warnung.assert_called_once()
self.assertIn("CSV", warnung.call_args[0][1])
suche.assert_not_called()
def test_suchfehler_als_warnung(self, warnung, hinweis):
"""Prüft, dass ein Fehler der Suche (z. B. leere Eingabe) als Warnung erscheint."""
with patch.object(et, "hole_layer", return_value=object()), patch.object(et, "suche_eigentuemer", side_effect=EigentuemerSucheFehler("Bitte eingeben")):
_eig_tab()._on_eigentuemer_suchen()
warnung.assert_called_once_with("Eigentümersuche", "Bitte eingeben")
def test_kein_treffer_ohne_namen_in_meldung(self, warnung, hinweis):
"""Prüft, dass ohne Treffer ein Hinweis erscheint, der den gesuchten Namen nicht wiederholt (Datenschutz)."""
with patch.object(et, "hole_layer", return_value=object()), patch.object(et, "suche_eigentuemer", return_value=[]), patch.object(et, "EigentuemerTrefferFenster") as fenster:
_eig_tab(nachname="Beispiel")._on_eigentuemer_suchen()
hinweis.assert_called_once()
self.assertNotIn("Beispiel", hinweis.call_args[0][1])
fenster.assert_not_called()
def test_treffer_oeffnen_trefferliste_und_ersetzen_die_alte(self, warnung, hinweis):
"""Prüft, dass Treffer in einer neuen Trefferliste erscheinen, eine offene alte Liste geschlossen wird und die Eingaben an die Suche gehen."""
layer = object()
tab = _eig_tab(nachname="Beisp", vorname="An")
altes_fenster = MagicMock()
tab._trefferfenster = altes_fenster
with patch.object(et, "hole_layer", return_value=layer), patch.object(et, "suche_eigentuemer", return_value=[_ANNA]) as suche, patch.object(et, "EigentuemerTrefferFenster") as fenster:
tab._on_eigentuemer_suchen()
suche.assert_called_once_with(layer, "Beisp", "An")
altes_fenster.close.assert_called_once()
fenster.assert_called_once_with([_ANNA], tab)
fenster.return_value.show.assert_called_once()
self.assertIs(tab._trefferfenster, fenster.return_value)
class TestTrefferliste(unittest.TestCase):
def test_trefferzeile_mit_hinweis(self):
"""Prüft, dass die Trefferliste Name, Anschrift, E-Mail und die Kennzeichen „verstorben“/„Rechtsperson“ zeigt."""
self.assertEqual(
trefferzeile(_ANNA),
("Beispiel, Anna", "Hauptstraße 1, 01234 Musterstadt", "anna@example.org", "verstorben"),
)
def test_ausgewaehlte_eigentuemer(self):
"""Prüft, dass das Trefferfenster die in der Tabelle gewählten Einträge zurückgibt."""
bernd = Eigentuemer(vorname="Bernd", nachname="Muster")
fenster = EigentuemerTrefferFenster.__new__(EigentuemerTrefferFenster)
fenster.treffer = [_ANNA, bernd]
fenster.tabelle = object()
with patch.object(treffer_modul, "ausgewaehlte_indizes", return_value=[1]) as indizes:
self.assertEqual(fenster.ausgewaehlte_eigentuemer(), [bernd])
indizes.assert_called_once_with(fenster.tabelle)
class TestDockWidgetTabs(unittest.TestCase):
def test_tab_ist_im_dockwidget_eingetragen(self):