gendesign/tradein-mvp/deploy/import-rosreestr.sh
bot-backend fcf5887225
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m12s
merge(#3051): main (#3421) в ветку импорта по региону — московская дельта поверх region_code/doc_type
#3421 въехал в main параллельно с той же миграцией 288 (deals.doc_type,
параметры region_code/doc_types). Разрешение: 288 — целиком версия main;
наша дельта (FDW-колонки okato/quarter_cad_number/district, выключенный seed
rosreestr_dkp_import_77) переехала в 289. scheduler.py — doc_types из main +
canonical_city-маппинг/raw_payload/per-source чекпоинт. deploy-скрипт —
валидация REGION_CODE и DOC_TYPE (интерполируются в SQL текстом).
2026-09-08 23:19:47 +03:00

117 lines
7.2 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Импорт реальных сделок Росреестра из gendesign-БД в tradein deals.
#
# Источник: gendesign-postgres-1 / rosreestr_deals (6.8М строк, партиц.).
# Берём квартиры (realestate_type_code=002001003000) региона REGION_CODE — по умолчанию
# 66 = вся Свердловская область, все города (не только ЕКБ: city-фильтр снят давно,
# шапка про «ЕКБ квартиры» была неправдой).
# rooms выводим из площади (Росреестр не отдаёт кол-во комнат).
# Координаты — NULL, проставляются отдельно (geocode по street).
#
# DOC_TYPE по умолчанию ДКП (вторичка): ДДУ идут по ценам котлована и скёюят median,
# отделены сознательно (см. PR-A). С #3051 это параметр, а не литерал — для Москвы
# (REGION_CODE=77) типы разделяются колонкой deals.doc_type (миграция 288), которую
# скрипт теперь заполняет.
#
# #3051 п.3: REGION_CODE параметризован (default 66 — Свердловская обл., byte-for-byte
# прежнее поведение). Этот bash-путь — НЕ region-generic: для region_code=77 (Москва) он
# НЕ подставляет canonical_city вместо city источника (Росреестр по Москве отдаёт
# муниципальный округ/поселение, не сам город) и не пишет raw_payload с
# okato/quarter_cad_number/district — эту логику несёт только Python-путь
# (app/services/scheduler.py::import_rosreestr_dkp, боевой планировщик). Если этот
# скрипт когда-нибудь запустят вручную с REGION_CODE=77 — city/address будут
# "муниципальный округ Раменки, ..." как есть из источника, НЕ "Москва, ...". Держать
# паритет фильтров (area/price/doc_type) обязательно, паритет city-override — нет.
#
# Запуск на прод-хосте: ./import-rosreestr.sh
# REGION_CODE=77 DOC_TYPE='ДДУ' ./import-rosreestr.sh # Москва, первичка
# Повторяемо: дедуп по dedup_hash, новый запуск подтянет свежие кварталы.
set -euo pipefail
SRC_PG="${SRC_PG:-gendesign-postgres-1}"
DST_PG="${DST_PG:-tradein-postgres}"
SRC_DB="${SRC_DB:-gendesign}"
SRC_USER="${SRC_USER:-gendesign}"
SINCE="${SINCE:-2024-01-01}"
# #3051: регион и тип документа — параметры со старыми дефолтами (поведение не меняется).
REGION_CODE="${REGION_CODE:-66}"
DOC_TYPE="${DOC_TYPE:-ДКП}"
# Оба значения интерполируются в SQL текстом (не bind-параметром) — валидация здесь
# и есть единственная защита от SQL-инъекции. Паттерн — в переменной (не инлайн в
# [[ =~ ]]): голая кавычка в regex-операнде ломает bash-парсинг команды.
DOC_TYPE_RE="^[^;']+\$"
[[ "$REGION_CODE" =~ ^[0-9]+$ ]] || { echo "REGION_CODE должен быть целым числом, получено: '$REGION_CODE'" >&2; exit 1; }
[[ "$DOC_TYPE" =~ $DOC_TYPE_RE ]] || { echo "DOC_TYPE не должен содержать ' или ;, получено: '$DOC_TYPE'" >&2; exit 1; }
echo "[$(date -u +%H:%M:%S)] import-rosreestr: region=$REGION_CODE doc_type=$DOC_TYPE с $SINCE"
# 1. Staging-таблица в tradein.
docker exec "$DST_PG" psql -U tradein -d tradein -v ON_ERROR_STOP=on -c "
-- DROP перед CREATE: страхует от устаревшей формы staging-таблицы, если прошлый
-- запуск упал между CREATE и финальным DROP под старым кодом (без source_id).
DROP TABLE IF EXISTS deals_ros_staging;
CREATE TABLE deals_ros_staging (
dedup_hash text PRIMARY KEY, source_id text, address text, region_code int, city text,
rooms int, area_m2 numeric,
floor int, year_built int, price_rub bigint, price_per_m2 int, deal_date date,
doc_type text
);
"
# 2. Трансформируем на gendesign-стороне, пайпим CSV в staging.
docker exec "$SRC_PG" psql -U "$SRC_USER" -d "$SRC_DB" -v ON_ERROR_STOP=on -c "
COPY (
SELECT
'ros:dkp:' || id::text AS dedup_hash,
id::text AS source_id,
trim(city) || ', ' || trim(street) AS address,
region_code AS region_code,
trim(city) AS city,
CASE
WHEN area < 30 THEN 0 WHEN area < 44 THEN 1
WHEN area < 62 THEN 2 WHEN area < 85 THEN 3
ELSE 4 END AS rooms,
round(area, 2) AS area_m2,
LEAST(NULLIF(substring(floor from '[0-9]+'), '')::int, 100) AS floor,
year_build AS year_built,
round(deal_price)::bigint AS price_rub,
round(price_per_sqm)::int AS price_per_m2,
period_start_date AS deal_date,
doc_type AS doc_type
FROM rosreestr_deals
WHERE region_code = $REGION_CODE
AND city IS NOT NULL AND trim(city) <> ''
AND realestate_type_code = '002001003000'
AND area BETWEEN 18 AND 200
AND deal_price BETWEEN 1000000 AND 100000000
AND street IS NOT NULL AND trim(street) <> ''
AND doc_type = '$DOC_TYPE'
AND period_start_date >= '$SINCE'
) TO STDOUT WITH CSV
" | docker exec -i "$DST_PG" psql -U tradein -d tradein -v ON_ERROR_STOP=on -c "
COPY deals_ros_staging FROM STDIN WITH CSV
"
STAGED=$(docker exec "$DST_PG" psql -U tradein -d tradein -tAc "SELECT count(*) FROM deals_ros_staging")
echo "[$(date -u +%H:%M:%S)] staged: $STAGED строк"
# 3. Удаляем старые синтетические сделки, вставляем реальные (дедуп).
docker exec "$DST_PG" psql -U tradein -d tradein -v ON_ERROR_STOP=on -c "
DELETE FROM deals WHERE address = 'Екатеринбург, реальная сделка';
INSERT INTO deals (
source, dedup_hash, source_id, address, region_code, city, rooms, area_m2, floor,
year_built, price_rub, price_per_m2, deal_date, doc_type
)
SELECT 'rosreestr', dedup_hash, source_id, address, region_code, city, rooms, area_m2, floor,
year_built, price_rub, price_per_m2, deal_date, doc_type
FROM deals_ros_staging
ON CONFLICT (dedup_hash) DO NOTHING;
DROP TABLE deals_ros_staging;
"
TOTAL=$(docker exec "$DST_PG" psql -U tradein -d tradein -tAc "SELECT count(*) FROM deals")
echo "[$(date -u +%H:%M:%S)] deals всего: $TOTAL"
echo "Координаты проставит geocode-deals (отдельный шаг)."