gendesign/data/sql/182_eesk_heat_reserves.sql
Light1YT 372856c4cc
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (pull_request) Successful in 1m10s
CI / openapi-codegen-check (pull_request) Successful in 2m0s
CI / backend-tests (pull_request) Successful in 14m36s
feat(site-finder): ЕЭСК-резервы городских ПС/ТП + тепло из ФГИС ФАС (#2119 B2)
Городские числа вместо «по запросу» + четвёртый ресурс (тепло) в карточке §3.

- Миграция 182: power_supply_centers +reserve_unit ('МВА'/'МВт') +district;
  heat_system_reserves (UNIQUE NULLS NOT DISTINCT).
- eesk_reserve_loader (RUN-ON-PROD): хаб раскрытия eesk.ru → свежайшие xlsx по
  (год, квартал) из текста ссылки; ПС 35-220 (структура снята: r7+, доля
  0.41→41.0, свободная МВт) → UPDATE 70 городских ПС (только dzo ЕЭСК;
  «ФСК ЕЭС» не матчится — проверено ревью); ТП/РП ниже 35 (r4+, ~2014 строк
  города) → power_tp_rp_reserves. ДОПУЩЕНИЕ: % загрузки в источнике — доля
  (0..1); если ЕЭСК перейдёт на целые проценты, load_pct тихо ×100.
- eias_heat_loader (RUN-ON-PROD, SSL: в CA-бандл добавлен GlobalSign-интермедиат
  — ri.eias.ru не шлёт цепочку): карточка орг (ЕТК 30814352, Екатеринбургэнерго
  26479450) → публикации свежайшего квартала → TemplatePrinter base64-ZIP → tpl
  XLSX → defensive-парс «СТ №N»+правейшее число → heat_system_reserves.
- Celery вт 05:30/06:00; endpoint: power_points +reserve_unit/district,
  heat-блок (per-org MAX(period), graceful); схемы аддитивны, api-types +29/-0.
- Фронт: блок «ТЕПЛО» (бейджи резерв/исчерпана, свёртка >5, суммарно Гкал/ч);
  попап ПС: район + unit ТОЛЬКО на строке резерва (у ЕЭСК installed МВА,
  резерв МВт — разные единицы источника).
- B1-хвост: «(выход №N)» матчится в середине имени ГРС.

64+ тестов зелёные; deep-review  APPROVE.
2026-07-02 21:26:39 +05:00

74 lines
5.3 KiB
PL/PgSQL
Raw 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.

-- 182_eesk_heat_reserves.sql
-- Forgejo #2119 Phase B2 — АО «ЕЭСК» (Екатеринбургская электросетевая компания):
-- (а) резерв мощности по ЦП ПС 35-220 кВ → апдейт power_supply_centers (МВт);
-- (б) резерв ТП/РП напряжением ниже 35 кВ → UPSERT power_tp_rp_reserves;
-- (в) heat_system_reserves — задел под теплоснабжение (Gcal/ч), city-level.
--
-- Источник: eesk.ru «Наличие объёма свободной для технологического присоединения
-- мощности» — статический HTML-хаб со ссылками на xlsx (обычный SSL, БЕЗ гео-блока,
-- но лоадер всё равно RUN-ON-PROD рядом с rosseti/gas/vodokanal).
--
-- ЕЭСК резервы у ЦП измеряются в МВт (не МВА как у Россетей) → добавляем
-- reserve_unit на power_supply_centers (default 'МВА' для старых строк Россетей,
-- лоадер ЕЭСК проставляет 'МВт'). district — адм. район ЕКБ из xlsx ЕЭСК.
--
-- Refresh: weekly via tasks.connection_capacity_sync (отдельный воркер).
-- Порядок применения: миграция ПЕРЕД деплоем кода (schema-first, sql.md).
BEGIN;
-- ── power_supply_centers: единица резерва + адм. район ────────────────────────
-- reserve_unit: у Россетей резерв в МВА, у ЕЭСК ПС 35-220 — в МВт. default 'МВА'
-- сохраняет семантику существующих строк (заполнены Россетями), лоадер ЕЭСК
-- явно проставляет 'МВт'. district — административный район Екатеринбурга (колонка
-- B файла ЕЭСК); у Россети-строк остаётся NULL.
ALTER TABLE power_supply_centers
ADD COLUMN IF NOT EXISTS reserve_unit TEXT DEFAULT 'МВА';
ALTER TABLE power_supply_centers
ADD COLUMN IF NOT EXISTS district TEXT;
COMMENT ON COLUMN power_supply_centers.reserve_unit IS
'Единица reserve_mva/installed_capacity_mva: ''МВА'' (Россети, default) или '
'''МВт'' (ЕЭСК ПС 35-220, capacity_source=''eesk_35_220''). Forgejo #2119 B2.';
COMMENT ON COLUMN power_supply_centers.district IS
'Административный район Екатеринбурга (из xlsx ЕЭСК ПС 35-220). NULL у '
'Россети-строк. Forgejo #2119 Phase B2.';
-- ── heat_system_reserves ──────────────────────────────────────────────────────
-- Резервы тепловой мощности систем теплоснабжения (Gcal/ч), city-level, без geom.
-- sphere зафиксирована 'heat' (задел под другие сферы раскрытия одной таблицей).
-- reserve_gcal_h может быть отрицательным (дефицит) — знак сохраняем. raw jsonb —
-- сырая строка источника целиком (будущие колонки не теряются).
CREATE TABLE IF NOT EXISTS heat_system_reserves (
id SERIAL PRIMARY KEY,
org TEXT NOT NULL, -- организация-держатель (АО «ЕЭСК» и др.)
sphere TEXT NOT NULL DEFAULT 'heat',
system_name TEXT NOT NULL, -- имя системы теплоснабжения
reserve_gcal_h NUMERIC, -- свободная мощность, Гкал/ч (может быть <0)
applications_note TEXT, -- примечание о заявках на подключение
period TEXT, -- напр. '2026-Q2'
source_guid TEXT, -- хэш/идентификатор исходного файла
raw JSONB, -- сырая строка источника целиком
fetched_at TIMESTAMPTZ DEFAULT NOW(),
-- NULLS NOT DISTINCT: period может быть NULL при неудачном разборе даты
-- (те же грабли, что #140 / 180_connection_capacity.sql water_supply_reserves).
UNIQUE NULLS NOT DISTINCT (org, sphere, system_name, period)
);
CREATE INDEX IF NOT EXISTS idx_heat_system_reserves_period
ON heat_system_reserves (period);
CREATE INDEX IF NOT EXISTS idx_heat_system_reserves_sphere
ON heat_system_reserves (sphere);
COMMENT ON TABLE heat_system_reserves IS
'Резервы тепловой мощности систем теплоснабжения (Гкал/ч, city-level, без geom). '
'reserve_gcal_h может быть отрицательным (дефицит). Forgejo #2119 Phase B2.';
COMMENT ON COLUMN heat_system_reserves.reserve_gcal_h IS
'Свободная (резервная) тепловая мощность, Гкал/ч. Отрицательное = дефицит.';
COMMIT;