diff --git a/backend/app/api/v1/parcels.py b/backend/app/api/v1/parcels.py index a996bb30..173e1af8 100644 --- a/backend/app/api/v1/parcels.py +++ b/backend/app/api/v1/parcels.py @@ -779,8 +779,31 @@ def analyze_parcel( logger.warning("market_trend query failed for %s: %s", cad_num, e) market_trend = None - # 10b) Zoning — территориальная зона ПЗЗ из Росреестр PKK6 - zoning: dict[str, Any] | None = None + # 10b) Zoning — территориальная зона ПЗЗ. + # NB: Росреестр PKK6 API закрыт в 2024 → редирект на NSPD (anti-bot WAF). + # Open-data shapefile ПЗЗ ЕКБ публично не выкладывается (data.midural.ru + # содержит только metadata). Реальный per-parcel zoning требует либо + # ручного импорта shapefile из ГИС ЕКБ (с авторизацией) либо платный + # API (egrn.reestr.net). Здесь — fallback на pzz_zones_ekb (если есть) + # + deep-links на публичные геопорталы для drill-down. + zoning: dict[str, Any] = { + "zone_code": None, + "zone_name": None, + "description": None, + "data_available": False, + "note": ( + "Автоматический per-parcel zoning недоступен: Росреестр PKK6 API " + "закрыт (2024), NSPD блокирует bot-доступ. Используй внешние " + "геопорталы для определения зоны вручную." + ), + "links": { + "nspd_portal": f"https://nspd.gov.ru/map?lat={centroid_lat}&lng={centroid_lon}&z=17", + "ekb_geoportal": "https://xn--80acgfbsl1azdqr.xn--p1ai/", + "midural_data": "https://data.midural.ru/", + }, + "lat": centroid_lat, + "lon": centroid_lon, + } try: zoning_row = ( db.execute( @@ -799,20 +822,18 @@ def analyze_parcel( .first() ) if zoning_row: - zoning = { - "zone_code": zoning_row["zone_code"], - "zone_name": zoning_row["zone_name"], - "description": zoning_row["description"], - "rosreestr_id": zoning_row["rosreestr_id"], - "source": "rosreestr-pkk6", - "note": ( - "Зона из ЕГРН (Росреестр). Регламенты (макс. высота, КЗ, ВРИ) " - "не хранятся в ЕГРН — для них нужен текст ПЗЗ муниципалитета." - ), - } + zoning.update( + { + "zone_code": zoning_row["zone_code"], + "zone_name": zoning_row["zone_name"], + "description": zoning_row["description"], + "rosreestr_id": zoning_row["rosreestr_id"], + "data_available": True, + "source": "rosreestr-pkk6-cached", + } + ) except Exception as e: logger.warning("zoning query failed for %s: %s", cad_num, e) - zoning = None # 10c) Success recommendation — топ квартирография по district из v_bucket_success_score success_recommendation: dict[str, Any] | None = None