feat(sf): ????? ???-??????? ? ???-???? analyze #1152
2 changed files with 49 additions and 1 deletions
|
|
@ -34,6 +34,7 @@ from app.services.scrapers.ekb_geoportal_client import EKBGeoportalClient
|
|||
from app.services.site_finder.functional_zone_lookup import parcel_functional_zones
|
||||
from app.services.site_finder.ird_overlay_lookup import parcel_ird_overlaps
|
||||
from app.services.site_finder.krt_lookup import parcel_krt_requisites
|
||||
from app.services.site_finder.okn_lookup import parcel_okn_objects
|
||||
from app.services.site_finder.planning_lookup import parcel_planning_overlaps
|
||||
from app.services.site_finder.reservation_lookup import parcel_reservations
|
||||
from app.services.site_finder.zone_regulation import get_or_fetch_zone_regulation
|
||||
|
|
@ -129,7 +130,9 @@ def build_ird_analyze_block(
|
|||
``functional_zones`` (list, генплан-зоны из ekb_genplan_functional_zone, #1058),
|
||||
``functional_zone`` (первая зона|None, back-compat; dict|None),
|
||||
``krt`` (list, КРТ-геометрии из DB ekb_krt_geometry, #1130),
|
||||
``zone_regulation`` (dict|None).
|
||||
``zone_regulation`` (dict|None),
|
||||
``okn_objects`` (list, ОКН в радиусе 100 м от участка из okn_objects, #1066;
|
||||
[{source_id, category, distance_m}], пусто при отсутствии объектов/таблицы).
|
||||
Любой источник деградирует независимо — блок всегда well-formed.
|
||||
"""
|
||||
overlay = parcel_ird_overlaps(db, geom_wkt)
|
||||
|
|
@ -141,6 +144,9 @@ def build_ird_analyze_block(
|
|||
"opportunity_overlaps": opportunity,
|
||||
"planning_projects": parcel_planning_overlaps(db, geom_wkt),
|
||||
"reservations": parcel_reservations(db, cad_num),
|
||||
# ОКН-объекты (#1066): ST_DWithin к okn_objects (428 строк, GIST), дёшево, graceful.
|
||||
# Идёт рядом с reservations — DB-источники основного потока, без сетевых зависимостей.
|
||||
"okn_objects": parcel_okn_objects(db, geom_wkt),
|
||||
# КРТ-реквизиты (DB, дёшево, graceful): planning_projects ⋈ ekb_krt_sites (#1060).
|
||||
# Идёт рядом с planning_projects — оба DB-источника, не в geoportal-конкурентной части.
|
||||
"krt_requisites": parcel_krt_requisites(db, geom_wkt),
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ def _patch_overlay(monkeypatch: Any, overlay: dict[str, Any]) -> None:
|
|||
monkeypatch.setattr(ird_analyze, "parcel_krt_requisites", lambda db, wkt: list(_KRT_REQUISITES))
|
||||
# По умолчанию: пустой список — functional_zone=None (back-compat).
|
||||
monkeypatch.setattr(ird_analyze, "parcel_functional_zones", lambda db, wkt: [])
|
||||
# По умолчанию: пустой список — okn_objects=[] (graceful, таблица может не быть задеплоена).
|
||||
monkeypatch.setattr(ird_analyze, "parcel_okn_objects", lambda db, wkt: [])
|
||||
|
||||
|
||||
def test_full_block_assembly(monkeypatch: Any) -> None:
|
||||
|
|
@ -367,3 +369,43 @@ def test_functional_zones_empty(monkeypatch: Any) -> None:
|
|||
assert block["functional_zone"] is None
|
||||
assert "functional_zones" in block # ключ всегда присутствует
|
||||
assert "functional_zone" in block
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ОКН-объекты (#1066)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_OKN_ROWS: list[dict[str, Any]] = [
|
||||
{"source_id": "66-001", "category": "федеральный", "distance_m": 42},
|
||||
{"source_id": "66-002", "category": "региональный", "distance_m": 88},
|
||||
]
|
||||
|
||||
|
||||
def test_okn_objects_wired_to_block(monkeypatch: Any) -> None:
|
||||
"""parcel_okn_objects возвращает 2 объекта → block['okn_objects'] список из двух элементов."""
|
||||
_patch_overlay(monkeypatch, _OVERLAY)
|
||||
monkeypatch.setattr(ird_analyze, "parcel_okn_objects", lambda db, wkt: list(_OKN_ROWS))
|
||||
monkeypatch.setattr(ird_analyze, "get_or_fetch_zone_regulation", lambda *a, **kw: None)
|
||||
monkeypatch.setattr(ird_analyze, "_krt_at", lambda db, lon, lat: [])
|
||||
client = _FakeClient(fz=[])
|
||||
|
||||
block = ird_analyze.build_ird_analyze_block(object(), "POINT(60 56)", 60.6, 56.8, client=client)
|
||||
|
||||
assert "okn_objects" in block
|
||||
assert len(block["okn_objects"]) == 2
|
||||
assert block["okn_objects"][0]["source_id"] == "66-001"
|
||||
assert block["okn_objects"][1]["category"] == "региональный"
|
||||
|
||||
|
||||
def test_okn_objects_empty_when_none(monkeypatch: Any) -> None:
|
||||
"""parcel_okn_objects пуст (нет объектов / таблица не задеплоена) → okn_objects == []."""
|
||||
_patch_overlay(monkeypatch, _OVERLAY)
|
||||
monkeypatch.setattr(ird_analyze, "parcel_okn_objects", lambda db, wkt: [])
|
||||
monkeypatch.setattr(ird_analyze, "get_or_fetch_zone_regulation", lambda *a, **kw: None)
|
||||
monkeypatch.setattr(ird_analyze, "_krt_at", lambda db, lon, lat: [])
|
||||
client = _FakeClient(fz=[])
|
||||
|
||||
block = ird_analyze.build_ird_analyze_block(object(), "POINT(60 56)", 60.6, 56.8, client=client)
|
||||
|
||||
assert "okn_objects" in block
|
||||
assert block["okn_objects"] == []
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue