Merge pull request 'Feature/vkz differenzierung' (#20) from feature/VKZ-differenzierung into testing
Release Plugin / release (push) Successful in 4s
Release Plugin / release (push) Successful in 4s
Reviewed-on: #20
This commit was merged in pull request #20.
This commit is contained in:
@@ -9,10 +9,23 @@ from sn_basis.functions import (
|
|||||||
from sn_basis.functions import QMessageBox
|
from sn_basis.functions import QMessageBox
|
||||||
from sn_basis.functions.qt_wrapper import QVariant
|
from sn_basis.functions.qt_wrapper import QVariant
|
||||||
from sn_basis.functions.variable_wrapper import get_variable
|
from sn_basis.functions.variable_wrapper import get_variable
|
||||||
|
from sn_basis.functions.dialog_wrapper import ask_bror_kombination
|
||||||
|
|
||||||
alkis_sf_url = "https://geodienste.sachsen.de/aaa/public_alkis/sf/wfs"
|
alkis_sf_url = "https://geodienste.sachsen.de/aaa/public_alkis/sf/wfs"
|
||||||
typename = "adv:AX_BauRaumOderBodenordnungsrecht"
|
typename = "adv:AX_BauRaumOderBodenordnungsrecht"
|
||||||
|
|
||||||
|
#: Attribute, die aus dem BROR-WFS-Dienst geladen und im Memory-Layer gespeichert werden.
|
||||||
|
BROR_ATTRIBUTE_FELDER = [
|
||||||
|
"artderfestlegung",
|
||||||
|
"ausfuehrendestelle_ax_dienststelle_schluessel_stelle",
|
||||||
|
"adv_name",
|
||||||
|
"bezeichnung",
|
||||||
|
"datumanordnung",
|
||||||
|
"datumbesitzeinweisung",
|
||||||
|
"datumrechtskraft",
|
||||||
|
"datumabgabe",
|
||||||
|
]
|
||||||
|
|
||||||
class LoadStatus(Enum):
|
class LoadStatus(Enum):
|
||||||
"""Status eines Layer-Ladevorgangs.
|
"""Status eines Layer-Ladevorgangs.
|
||||||
|
|
||||||
@@ -83,11 +96,13 @@ def verfahrensgebiet_alkis(tab_widget):
|
|||||||
if status == LoadStatus.KEEP:
|
if status == LoadStatus.KEEP:
|
||||||
return existing, status, []
|
return existing, status, []
|
||||||
|
|
||||||
# WFS mit Filter laden
|
# WFS mit Filter laden – nur erste 5 Stellen der VKZ für den Vergleich verwenden,
|
||||||
|
# da die Daten im Dienst ggf. abweichende Suffixe führen.
|
||||||
|
vkz_prefix = verfahrensnummer[:5]
|
||||||
wfs_uri_find = (
|
wfs_uri_find = (
|
||||||
f"url='{alkis_sf_url}' typename='{typename}' srsname='EPSG:25833' "
|
f"url='{alkis_sf_url}' typename='{typename}' srsname='EPSG:25833' "
|
||||||
f"sql=SELECT * FROM AX_BauRaumOderBodenordnungsrecht "
|
f"sql=SELECT * FROM AX_BauRaumOderBodenordnungsrecht "
|
||||||
f"WHERE bezeichnung LIKE '{verfahrensnummer}%'"
|
f"WHERE bezeichnung LIKE '{vkz_prefix}%'"
|
||||||
)
|
)
|
||||||
temp_layer = QgsVectorLayer(wfs_uri_find, "TempVerfahrensgebiet", "WFS")
|
temp_layer = QgsVectorLayer(wfs_uri_find, "TempVerfahrensgebiet", "WFS")
|
||||||
|
|
||||||
@@ -101,7 +116,32 @@ def verfahrensgebiet_alkis(tab_widget):
|
|||||||
f"Verfahrenskennzeichen {verfahrensnummer} nicht im WFS gefunden.")
|
f"Verfahrenskennzeichen {verfahrensnummer} nicht im WFS gefunden.")
|
||||||
return None, LoadStatus.NONE, []
|
return None, LoadStatus.NONE, []
|
||||||
|
|
||||||
union_geom = QgsGeometry.unaryUnion([f.geometry() for f in features])
|
# Objekte nach (adv_name, bezeichnung) gruppieren
|
||||||
|
kombinationen: dict[tuple[str, str], list] = {}
|
||||||
|
for feat in features:
|
||||||
|
try:
|
||||||
|
adv_name_val = str(feat.attribute("adv_name") or "")
|
||||||
|
bezeichnung_val = str(feat.attribute("bezeichnung") or "")
|
||||||
|
except Exception:
|
||||||
|
adv_name_val = ""
|
||||||
|
bezeichnung_val = ""
|
||||||
|
key = (adv_name_val, bezeichnung_val)
|
||||||
|
if key not in kombinationen:
|
||||||
|
kombinationen[key] = []
|
||||||
|
kombinationen[key].append(feat)
|
||||||
|
|
||||||
|
if len(kombinationen) == 1:
|
||||||
|
selected_key = next(iter(kombinationen))
|
||||||
|
selected_feats = kombinationen[selected_key]
|
||||||
|
else:
|
||||||
|
# Mehrere Kombinationen → Nutzerauswahl
|
||||||
|
key_list = sorted(kombinationen.keys())
|
||||||
|
selected_key = ask_bror_kombination(tab_widget, key_list)
|
||||||
|
if selected_key is None:
|
||||||
|
return None, LoadStatus.NONE, []
|
||||||
|
selected_feats = kombinationen[selected_key]
|
||||||
|
|
||||||
|
union_geom = QgsGeometry.unaryUnion([f.geometry() for f in selected_feats])
|
||||||
if union_geom is None or union_geom.isEmpty():
|
if union_geom is None or union_geom.isEmpty():
|
||||||
QMessageBox.critical(tab_widget, "Fehler", "Keine Geometrien zum Verschmelzen gefunden.")
|
QMessageBox.critical(tab_widget, "Fehler", "Keine Geometrien zum Verschmelzen gefunden.")
|
||||||
return None, LoadStatus.NONE, []
|
return None, LoadStatus.NONE, []
|
||||||
@@ -110,14 +150,30 @@ def verfahrensgebiet_alkis(tab_widget):
|
|||||||
crs = temp_layer.crs().authid()
|
crs = temp_layer.crs().authid()
|
||||||
memory_layer = QgsVectorLayer(f"Polygon?crs={crs}", "Verfahrensgebiet", "memory")
|
memory_layer = QgsVectorLayer(f"Polygon?crs={crs}", "Verfahrensgebiet", "memory")
|
||||||
pr = memory_layer.dataProvider()
|
pr = memory_layer.dataProvider()
|
||||||
pr.addAttributes([QgsField("VKZ", QVariant.String)])
|
pr.addAttributes([QgsField(attr, QVariant.String) for attr in BROR_ATTRIBUTE_FELDER])
|
||||||
memory_layer.updateFields()
|
memory_layer.updateFields()
|
||||||
|
|
||||||
|
# Attributwerte aus dem ersten Feature der gewählten Kombination übernehmen
|
||||||
|
first_feat = selected_feats[0]
|
||||||
|
attrs = []
|
||||||
|
for attr in BROR_ATTRIBUTE_FELDER:
|
||||||
|
try:
|
||||||
|
val = first_feat.attribute(attr)
|
||||||
|
if val is None:
|
||||||
|
attrs.append("")
|
||||||
|
elif type(val).__name__ == "QDate":
|
||||||
|
# QDate-Objekte als DD.MM.YYYY formatieren
|
||||||
|
attrs.append(val.toString("dd.MM.yyyy"))
|
||||||
|
else:
|
||||||
|
attrs.append(str(val))
|
||||||
|
except Exception:
|
||||||
|
attrs.append("")
|
||||||
|
|
||||||
feat_union = QgsFeature()
|
feat_union = QgsFeature()
|
||||||
feat_union.setGeometry(union_geom)
|
feat_union.setGeometry(union_geom)
|
||||||
feat_union.setAttributes([verfahrensnummer])
|
feat_union.setAttributes(attrs)
|
||||||
pr.addFeatures([feat_union])
|
pr.addFeatures([feat_union])
|
||||||
memory_layer.updateExtents()
|
memory_layer.updateExtents()
|
||||||
|
|
||||||
# Status: FIRST oder RELOAD; features für Gemarkungsermittlung weitergeben
|
# Status: FIRST oder RELOAD; selected_feats für Gemarkungsermittlung weitergeben
|
||||||
return memory_layer, status, features
|
return memory_layer, status, selected_feats
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ optionaler Umringsprüfung:
|
|||||||
- Abschlussmeldung mit Zählung.
|
- Abschlussmeldung mit Zählung.
|
||||||
|
|
||||||
Das BROR-Objekt (``AX_BauRaumOderBodenordnungsrecht``) bleibt bei Erfolg als
|
Das BROR-Objekt (``AX_BauRaumOderBodenordnungsrecht``) bleibt bei Erfolg als
|
||||||
temporärer Layer ``BauRaumOrdnungsrecht (ALKIS)`` im Projekt erhalten.
|
temporärer Layer ``BauRaumOderBodenordnungsrecht (ALKIS)`` im Projekt erhalten.
|
||||||
|
|
||||||
**Rückgabe:**
|
**Rückgabe:**
|
||||||
``Tuple[enriched_layer, flst_layer, bror_layer, LoadStatus]``
|
``Tuple[enriched_layer, flst_layer, bror_layer, LoadStatus]``
|
||||||
@@ -71,9 +71,12 @@ from sn_verfahrensgebiet.functions.knickpunkt_pruefung import (
|
|||||||
# Feldname für das Verfahrenskennzeichen im enriched Layer
|
# Feldname für das Verfahrenskennzeichen im enriched Layer
|
||||||
FELD_VKZ = "verfahrensnummer"
|
FELD_VKZ = "verfahrensnummer"
|
||||||
#: Anzeigename des BROR-Layers im Projekt
|
#: Anzeigename des BROR-Layers im Projekt
|
||||||
BROR_LAYER_NAME = "BauRaumOrdnungsrecht (ALKIS)"
|
BROR_LAYER_NAME = "BauRaumOderBodenordnungsrecht (ALKIS)"
|
||||||
#: Projektvariable für die Flächentoleranz (in m²); Default 0
|
#: Projektvariable für die Flächentoleranz (in m²); Default 0
|
||||||
FLAECHEN_TOLERANZ_VARIABLE = "flaechen_toleranz_m2"
|
FLAECHEN_TOLERANZ_VARIABLE = "flaechen_toleranz_m2"
|
||||||
|
#: Minimale implizite Flächentoleranz – Abweichungen unter diesem Wert
|
||||||
|
#: lösen keine Konfliktabfrage aus (Gleitkomma-Ungenauigkeiten vermeiden).
|
||||||
|
MINDEST_FLAECHEN_TOLERANZ_M2 = 0.01
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -223,7 +226,7 @@ def _vergleiche_flaechen(
|
|||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
bror_layer :
|
bror_layer :
|
||||||
BauRaumOrdnungsrecht-Layer.
|
BauRaumOderBodenordnungsrecht-Layer.
|
||||||
vg_layer :
|
vg_layer :
|
||||||
Enriched Verfahrensgebiet-Layer.
|
Enriched Verfahrensgebiet-Layer.
|
||||||
toleranz_m2 :
|
toleranz_m2 :
|
||||||
@@ -236,7 +239,8 @@ def _vergleiche_flaechen(
|
|||||||
"""
|
"""
|
||||||
bror_flaeche = _flaeche_des_layers(bror_layer)
|
bror_flaeche = _flaeche_des_layers(bror_layer)
|
||||||
vg_flaeche = _flaeche_des_layers(vg_layer)
|
vg_flaeche = _flaeche_des_layers(vg_layer)
|
||||||
stimmt_ueberein = abs(bror_flaeche - vg_flaeche) <= toleranz_m2
|
diff = abs(bror_flaeche - vg_flaeche)
|
||||||
|
stimmt_ueberein = diff < MINDEST_FLAECHEN_TOLERANZ_M2 or diff <= toleranz_m2
|
||||||
return bror_flaeche, vg_flaeche, stimmt_ueberein
|
return bror_flaeche, vg_flaeche, stimmt_ueberein
|
||||||
|
|
||||||
|
|
||||||
@@ -260,7 +264,7 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
6. ``_vergleiche_flaechen(...)`` – Flächenvergleich als Gate.
|
6. ``_vergleiche_flaechen(...)`` – Flächenvergleich als Gate.
|
||||||
7. Ggf. ``umringspruefung(...)`` nach Nutzerbestätigung.
|
7. Ggf. ``umringspruefung(...)`` nach Nutzerbestätigung.
|
||||||
|
|
||||||
Der BROR-Layer (``BauRaumOrdnungsrecht (ALKIS)``) bleibt bei Erfolg
|
Der BROR-Layer (``BauRaumOderBodenordnungsrecht (ALKIS)``) bleibt bei Erfolg
|
||||||
im Projekt. Bei Abbruch/Fehler wird er entfernt, falls er in diesem
|
im Projekt. Bei Abbruch/Fehler wird er entfernt, falls er in diesem
|
||||||
Lauf hinzugefügt wurde.
|
Lauf hinzugefügt wurde.
|
||||||
|
|
||||||
@@ -274,7 +278,7 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
Tuple[Optional[enriched_layer], Optional[flst_layer], Optional[bror_layer], LoadStatus]
|
Tuple[Optional[enriched_layer], Optional[flst_layer], Optional[bror_layer], LoadStatus]
|
||||||
- ``enriched_layer``: Memory-Layer „Verfahrensgebiet".
|
- ``enriched_layer``: Memory-Layer „Verfahrensgebiet".
|
||||||
- ``flst_layer``: Flurstücke-Layer (bleibt im Projekt).
|
- ``flst_layer``: Flurstücke-Layer (bleibt im Projekt).
|
||||||
- ``bror_layer``: BROR-Layer ``BauRaumOrdnungsrecht (ALKIS)``
|
- ``bror_layer``: BROR-Layer ``BauRaumOderBodenordnungsrecht (ALKIS)``
|
||||||
(bleibt bei Erfolg im Projekt).
|
(bleibt bei Erfolg im Projekt).
|
||||||
- :class:`LoadStatus`: ``FIRST``, ``RELOAD`` oder ``NONE``.
|
- :class:`LoadStatus`: ``FIRST``, ``RELOAD`` oder ``NONE``.
|
||||||
"""
|
"""
|
||||||
@@ -298,6 +302,7 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
return None, None, None, LoadStatus.NONE
|
return None, None, None, LoadStatus.NONE
|
||||||
|
|
||||||
alkis_vg_layer, vg_status, _ = verfahrensgebiet_alkis(tab_widget)
|
alkis_vg_layer, vg_status, _ = verfahrensgebiet_alkis(tab_widget)
|
||||||
|
progress.raise_to_front()
|
||||||
|
|
||||||
if vg_status == LoadStatus.NONE or not alkis_vg_layer:
|
if vg_status == LoadStatus.NONE or not alkis_vg_layer:
|
||||||
return None, None, None, LoadStatus.NONE
|
return None, None, None, LoadStatus.NONE
|
||||||
@@ -433,9 +438,9 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
entscheidung = ask_detailpruefung_oder_vg_laden(
|
entscheidung = ask_detailpruefung_oder_vg_laden(
|
||||||
tab_widget,
|
tab_widget,
|
||||||
"Abweichung erkannt",
|
"Abweichung erkannt",
|
||||||
f"Abweichung zwischen BauRaumOrdnungsrecht-Objekt und abgeleitetem "
|
f"Abweichung zwischen BauRaumOderBodenordnungsrecht-Objekt und abgeleitetem "
|
||||||
f"Verfahrensgebiet erkannt.\n\n"
|
f"Verfahrensgebiet erkannt.\n\n"
|
||||||
f"BauRaumOrdnungsrecht: {bror_flaeche:.2f} m²\n"
|
f"BauRaumOderBodenordnungsrecht: {bror_flaeche:.2f} m²\n"
|
||||||
f"Verfahrensgebiet: {vg_flaeche:.2f} m²\n"
|
f"Verfahrensgebiet: {vg_flaeche:.2f} m²\n"
|
||||||
f"Differenz: {diff:.2f} m²\n\n"
|
f"Differenz: {diff:.2f} m²\n\n"
|
||||||
f"Wie möchten Sie fortfahren?",
|
f"Wie möchten Sie fortfahren?",
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||||
|
<qgis layerType="Vector" styleCategories="Symbology" version="4.0.1-Norrköping">
|
||||||
|
<renderer-v2 enableorderby="0" forceraster="0" referencescale="-1" symbollevels="0" type="singleSymbol">
|
||||||
|
<symbols>
|
||||||
|
<symbol alpha="1" clip_to_extent="1" force_rhr="0" frame_rate="10" is_animated="0" name="0" type="fill">
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
<layer class="SimpleFill" enabled="1" id="{c32b7d26-d63f-4a20-b079-a5caa68d53db}" locked="0" pass="0">
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="border_width_map_unit_scale" type="QString" value="3x:0,0,0,0,0,0"/>
|
||||||
|
<Option name="color" type="QString" value="214,165,49,40,hsv:0.11719444394111633,0.77273213863372803,0.83793395757675171,0.15686275064945221"/>
|
||||||
|
<Option name="joinstyle" type="QString" value="bevel"/>
|
||||||
|
<Option name="offset" type="QString" value="0,0"/>
|
||||||
|
<Option name="offset_map_unit_scale" type="QString" value="3x:0,0,0,0,0,0"/>
|
||||||
|
<Option name="offset_unit" type="QString" value="MM"/>
|
||||||
|
<Option name="outline_color" type="QString" value="206,185,47,255,hsv:0.14452777802944183,0.77273213863372803,0.80689710378646851,1"/>
|
||||||
|
<Option name="outline_style" type="QString" value="solid"/>
|
||||||
|
<Option name="outline_width" type="QString" value="0.8"/>
|
||||||
|
<Option name="outline_width_unit" type="QString" value="MM"/>
|
||||||
|
<Option name="style" type="QString" value="solid"/>
|
||||||
|
</Option>
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
</layer>
|
||||||
|
</symbol>
|
||||||
|
</symbols>
|
||||||
|
<rotation/>
|
||||||
|
<sizescale/>
|
||||||
|
<data-defined-properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data-defined-properties>
|
||||||
|
</renderer-v2>
|
||||||
|
<selection mode="Default">
|
||||||
|
<selectionColor invalid="1"/>
|
||||||
|
<selectionSymbol>
|
||||||
|
<symbol alpha="1" clip_to_extent="1" force_rhr="0" frame_rate="10" is_animated="0" name="" type="fill">
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
<layer class="SimpleFill" enabled="1" id="{9cbdf1f0-8055-4075-828c-a33555f4068e}" locked="0" pass="0">
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="border_width_map_unit_scale" type="QString" value="3x:0,0,0,0,0,0"/>
|
||||||
|
<Option name="color" type="QString" value="0,0,255,255,rgb:0,0,1,1"/>
|
||||||
|
<Option name="joinstyle" type="QString" value="bevel"/>
|
||||||
|
<Option name="offset" type="QString" value="0,0"/>
|
||||||
|
<Option name="offset_map_unit_scale" type="QString" value="3x:0,0,0,0,0,0"/>
|
||||||
|
<Option name="offset_unit" type="QString" value="MM"/>
|
||||||
|
<Option name="outline_color" type="QString" value="35,35,35,255,rgb:0.1372549,0.1372549,0.1372549,1"/>
|
||||||
|
<Option name="outline_style" type="QString" value="solid"/>
|
||||||
|
<Option name="outline_width" type="QString" value="0.26"/>
|
||||||
|
<Option name="outline_width_unit" type="QString" value="MM"/>
|
||||||
|
<Option name="style" type="QString" value="solid"/>
|
||||||
|
</Option>
|
||||||
|
<data_defined_properties>
|
||||||
|
<Option type="Map">
|
||||||
|
<Option name="name" type="QString" value=""/>
|
||||||
|
<Option name="properties"/>
|
||||||
|
<Option name="type" type="QString" value="collection"/>
|
||||||
|
</Option>
|
||||||
|
</data_defined_properties>
|
||||||
|
</layer>
|
||||||
|
</symbol>
|
||||||
|
</selectionSymbol>
|
||||||
|
</selection>
|
||||||
|
<blendMode>0</blendMode>
|
||||||
|
<featureBlendMode>0</featureBlendMode>
|
||||||
|
<layerGeometryType>2</layerGeometryType>
|
||||||
|
</qgis>
|
||||||
@@ -61,12 +61,16 @@ class _DummyGeom:
|
|||||||
|
|
||||||
|
|
||||||
class _DummyFeature:
|
class _DummyFeature:
|
||||||
def __init__(self, geom=None):
|
def __init__(self, geom=None, attrs=None):
|
||||||
self._geom = geom or _DummyGeom()
|
self._geom = geom or _DummyGeom()
|
||||||
|
self._attrs = attrs or {}
|
||||||
|
|
||||||
def geometry(self):
|
def geometry(self):
|
||||||
return self._geom
|
return self._geom
|
||||||
|
|
||||||
|
def attribute(self, name):
|
||||||
|
return self._attrs.get(name)
|
||||||
|
|
||||||
|
|
||||||
class _DummyTempLayer:
|
class _DummyTempLayer:
|
||||||
def __init__(self, valid=True, features=None):
|
def __init__(self, valid=True, features=None):
|
||||||
@@ -139,7 +143,7 @@ class TestVerfahrensgebietAlkis(unittest.TestCase):
|
|||||||
def test_verfahrensgebiet_alkis_fails_when_verfahrensnummer_missing(self, _mock_get_var):
|
def test_verfahrensgebiet_alkis_fails_when_verfahrensnummer_missing(self, _mock_get_var):
|
||||||
_DummyMessageBox.last_critical = None
|
_DummyMessageBox.last_critical = None
|
||||||
|
|
||||||
layer, status = vg.verfahrensgebiet_alkis(tab_widget=None)
|
layer, status, feats = vg.verfahrensgebiet_alkis(tab_widget=None)
|
||||||
|
|
||||||
self.assertIsNone(layer)
|
self.assertIsNone(layer)
|
||||||
self.assertEqual(status, vg.LoadStatus.NONE)
|
self.assertEqual(status, vg.LoadStatus.NONE)
|
||||||
@@ -153,7 +157,7 @@ class TestVerfahrensgebietAlkis(unittest.TestCase):
|
|||||||
_DummyMessageBox.last_critical = None
|
_DummyMessageBox.last_critical = None
|
||||||
mock_qgsvectorlayer.return_value = _DummyTempLayer(valid=False)
|
mock_qgsvectorlayer.return_value = _DummyTempLayer(valid=False)
|
||||||
|
|
||||||
layer, status = vg.verfahrensgebiet_alkis(tab_widget=None)
|
layer, status, feats = vg.verfahrensgebiet_alkis(tab_widget=None)
|
||||||
|
|
||||||
self.assertIsNone(layer)
|
self.assertIsNone(layer)
|
||||||
self.assertEqual(status, vg.LoadStatus.NONE)
|
self.assertEqual(status, vg.LoadStatus.NONE)
|
||||||
@@ -165,8 +169,10 @@ class TestVerfahrensgebietAlkis(unittest.TestCase):
|
|||||||
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.get_variable", return_value="VKZ123")
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.get_variable", return_value="VKZ123")
|
||||||
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QgsVectorLayer")
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QgsVectorLayer")
|
||||||
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QMessageBox", new=_DummyMessageBox)
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QMessageBox", new=_DummyMessageBox)
|
||||||
def test_verfahrensgebiet_alkis_success_returns_memory_layer(self, mock_qgsvectorlayer, _mock_get_var, _mock_check, _mock_union, mock_feature_cls):
|
def test_verfahrensgebiet_alkis_success_single_kombination(self, mock_qgsvectorlayer, _mock_get_var, _mock_check, _mock_union, mock_feature_cls):
|
||||||
temp_layer = _DummyTempLayer(valid=True, features=[_DummyFeature()])
|
"""Einzelne (adv_name, bezeichnung)-Kombination → kein Dialog, Memory-Layer zurück."""
|
||||||
|
feat = _DummyFeature(attrs={"adv_name": "Bodensanierung", "bezeichnung": "VKZ12/001"})
|
||||||
|
temp_layer = _DummyTempLayer(valid=True, features=[feat])
|
||||||
memory_layer = _DummyMemoryLayer()
|
memory_layer = _DummyMemoryLayer()
|
||||||
mock_qgsvectorlayer.side_effect = [temp_layer, memory_layer]
|
mock_qgsvectorlayer.side_effect = [temp_layer, memory_layer]
|
||||||
|
|
||||||
@@ -174,10 +180,63 @@ class TestVerfahrensgebietAlkis(unittest.TestCase):
|
|||||||
mock_feature.setGeometry.return_value = None
|
mock_feature.setGeometry.return_value = None
|
||||||
mock_feature.setAttributes.return_value = None
|
mock_feature.setAttributes.return_value = None
|
||||||
|
|
||||||
layer, status = vg.verfahrensgebiet_alkis(tab_widget=None)
|
layer, status, feats = vg.verfahrensgebiet_alkis(tab_widget=None)
|
||||||
|
|
||||||
self.assertIs(layer, memory_layer)
|
self.assertIs(layer, memory_layer)
|
||||||
self.assertEqual(status, vg.LoadStatus.FIRST)
|
self.assertEqual(status, vg.LoadStatus.FIRST)
|
||||||
|
self.assertEqual(len(feats), 1)
|
||||||
|
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.ask_bror_kombination")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QgsFeature")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QgsGeometry.unaryUnion", return_value=_DummyGeom(empty=False))
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis._check_existing_layer", return_value=(None, vg.LoadStatus.FIRST))
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.get_variable", return_value="VKZ123")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QgsVectorLayer")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QMessageBox", new=_DummyMessageBox)
|
||||||
|
def test_verfahrensgebiet_alkis_multi_kombination_dialog_auswahl(
|
||||||
|
self, mock_qgsvectorlayer, _mock_get_var, _mock_check, _mock_union, mock_feature_cls, mock_dialog
|
||||||
|
):
|
||||||
|
"""Zwei verschiedene Kombinationen → Dialog wird gezeigt, gewählte Features genutzt."""
|
||||||
|
feat1 = _DummyFeature(attrs={"adv_name": "ADV-A", "bezeichnung": "VKZ12/001"})
|
||||||
|
feat2 = _DummyFeature(attrs={"adv_name": "ADV-B", "bezeichnung": "VKZ12/002"})
|
||||||
|
temp_layer = _DummyTempLayer(valid=True, features=[feat1, feat2])
|
||||||
|
memory_layer = _DummyMemoryLayer()
|
||||||
|
mock_qgsvectorlayer.side_effect = [temp_layer, memory_layer]
|
||||||
|
mock_dialog.return_value = ("ADV-A", "VKZ12/001")
|
||||||
|
|
||||||
|
mock_feature = mock_feature_cls.return_value
|
||||||
|
mock_feature.setGeometry.return_value = None
|
||||||
|
mock_feature.setAttributes.return_value = None
|
||||||
|
|
||||||
|
layer, status, feats = vg.verfahrensgebiet_alkis(tab_widget=None)
|
||||||
|
|
||||||
|
mock_dialog.assert_called_once()
|
||||||
|
self.assertIs(layer, memory_layer)
|
||||||
|
self.assertEqual(status, vg.LoadStatus.FIRST)
|
||||||
|
# Nur feat1 gehört zur gewählten Kombination
|
||||||
|
self.assertEqual(feats, [feat1])
|
||||||
|
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.ask_bror_kombination")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis._check_existing_layer", return_value=(None, vg.LoadStatus.FIRST))
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.get_variable", return_value="VKZ123")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QgsVectorLayer")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.verfahrensgebiet_alkis.QMessageBox", new=_DummyMessageBox)
|
||||||
|
def test_verfahrensgebiet_alkis_multi_kombination_dialog_abbruch(
|
||||||
|
self, mock_qgsvectorlayer, _mock_get_var, _mock_check, mock_dialog
|
||||||
|
):
|
||||||
|
"""Zwei verschiedene Kombinationen → Nutzer bricht Dialog ab → NONE."""
|
||||||
|
feat1 = _DummyFeature(attrs={"adv_name": "ADV-A", "bezeichnung": "VKZ12/001"})
|
||||||
|
feat2 = _DummyFeature(attrs={"adv_name": "ADV-B", "bezeichnung": "VKZ12/002"})
|
||||||
|
temp_layer = _DummyTempLayer(valid=True, features=[feat1, feat2])
|
||||||
|
mock_qgsvectorlayer.return_value = temp_layer
|
||||||
|
mock_dialog.return_value = None # Nutzer bricht ab
|
||||||
|
|
||||||
|
layer, status, feats = vg.verfahrensgebiet_alkis(tab_widget=None)
|
||||||
|
|
||||||
|
mock_dialog.assert_called_once()
|
||||||
|
self.assertIsNone(layer)
|
||||||
|
self.assertEqual(status, vg.LoadStatus.NONE)
|
||||||
|
self.assertEqual(feats, [])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
+2
-29
@@ -169,9 +169,9 @@ class WorkingTab(QWidget):
|
|||||||
apply_style(flst_layer, "GIS_Flst_Beschriftung_ALKIS_NAS.qml")
|
apply_style(flst_layer, "GIS_Flst_Beschriftung_ALKIS_NAS.qml")
|
||||||
self.setze_haken(self.haken_flurst, True)
|
self.setze_haken(self.haken_flurst, True)
|
||||||
|
|
||||||
# BROR-Layer: einfache Darstellung setzen (roter Umring, transparent)
|
# BROR-Layer: QML-Stil anwenden
|
||||||
if bror_layer and bror_layer.isValid():
|
if bror_layer and bror_layer.isValid():
|
||||||
_setze_bror_stil(bror_layer)
|
apply_style(bror_layer, "BauRaumOderBodenordnungsrecht.qml")
|
||||||
|
|
||||||
# Enriched VG-Layer ins Projekt (ggf. bereits registriert, z.B. bei "als VG laden")
|
# Enriched VG-Layer ins Projekt (ggf. bereits registriert, z.B. bei "als VG laden")
|
||||||
if not project.mapLayer(enriched_layer.id()):
|
if not project.mapLayer(enriched_layer.id()):
|
||||||
@@ -547,31 +547,4 @@ class WorkingTab(QWidget):
|
|||||||
# Modul-Hilfsfunktionen
|
# Modul-Hilfsfunktionen
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _setze_bror_stil(layer) -> None:
|
|
||||||
"""Setzt eine einfache Darstellung für den BauRaumOrdnungsrecht-Layer.
|
|
||||||
|
|
||||||
Roter Umring, halbtransparente Füllung; kein QGIS-Kontext → stilles Ignorieren.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
layer :
|
|
||||||
BauRaumOrdnungsrecht-Memory-Layer (Polygon).
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
from qgis.core import ( # type: ignore[import]
|
|
||||||
QgsSimpleFillSymbolLayer,
|
|
||||||
QgsFillSymbol,
|
|
||||||
QgsSingleSymbolRenderer,
|
|
||||||
)
|
|
||||||
from qgis.PyQt.QtGui import QColor # type: ignore[import]
|
|
||||||
from qgis.PyQt.QtCore import Qt # type: ignore[import]
|
|
||||||
|
|
||||||
fill = QgsSimpleFillSymbolLayer()
|
|
||||||
fill.setColor(QColor(220, 50, 50, 40)) # halbtransparent rot
|
|
||||||
fill.setStrokeColor(QColor(220, 50, 50))
|
|
||||||
fill.setStrokeWidth(0.8)
|
|
||||||
symbol = QgsFillSymbol([fill])
|
|
||||||
layer.setRenderer(QgsSingleSymbolRenderer(symbol))
|
|
||||||
layer.triggerRepaint()
|
|
||||||
except Exception:
|
|
||||||
pass # Kein QGIS-Kontext (Tests, Mock-Modus) → Standarddarstellung
|
|
||||||
|
|||||||
Reference in New Issue
Block a user