fix(eias-heat): не терять резерв при одинаковых именах систем (#2119 B2) #2191
2 changed files with 57 additions and 0 deletions
|
|
@ -317,10 +317,18 @@ def parse_heat_sheet(xlsx_bytes: bytes) -> tuple[list[dict], list[list[object]]]
|
||||||
return [], all_cells
|
return [], all_cells
|
||||||
|
|
||||||
systems: list[dict] = []
|
systems: list[dict] = []
|
||||||
|
name_counts: dict[str, int] = {}
|
||||||
for j, name in _system_columns(header_cells):
|
for j, name in _system_columns(header_cells):
|
||||||
reserve = parse_reserve_number(reserve_cells[j] if j < len(reserve_cells) else None)
|
reserve = parse_reserve_number(reserve_cells[j] if j < len(reserve_cells) else None)
|
||||||
if reserve is None:
|
if reserve is None:
|
||||||
continue # непарсибельная ячейка резерва (текст/пусто) → систему скипаем
|
continue # непарсибельная ячейка резерва (текст/пусто) → систему скипаем
|
||||||
|
# Разные системы могут носить БАЙТ-В-БАЙТ одинаковое имя в соседних колонках
|
||||||
|
# (живой пример ЕЭ: две «Локальные зоны … МУП "Екатеринбургэнерго"» с 62.198
|
||||||
|
# и 0). UPSERT по (org, sphere, system_name, period) схлопнул бы их с потерей
|
||||||
|
# данных — вторым и далее вхождениям добавляем порядковый суффикс « (N)».
|
||||||
|
name_counts[name] = name_counts.get(name, 0) + 1
|
||||||
|
if name_counts[name] > 1:
|
||||||
|
name = f"{name} ({name_counts[name]})"
|
||||||
systems.append({"system_name": name, "reserve_gcal_h": reserve})
|
systems.append({"system_name": name, "reserve_gcal_h": reserve})
|
||||||
|
|
||||||
return systems, all_cells
|
return systems, all_cells
|
||||||
|
|
|
||||||
|
|
@ -327,6 +327,55 @@ def test_parse_heat_sheet_ignores_anketa_rubrics_flag_row_size() -> None:
|
||||||
assert 52.0 not in reserves
|
assert 52.0 not in reserves
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_heat_sheet_suffixes_duplicate_system_names() -> None:
|
||||||
|
"""Разные системы с БАЙТ-В-БАЙТ одинаковым именем не схлопываются.
|
||||||
|
|
||||||
|
Живой прод-кейс (Екатеринбургэнерго, guid fe0c8c57): col7 и col8 обе называются
|
||||||
|
«Локальные зоны теплоснабжения МУП "Екатеринбургэнерго"» с резервами 62.198 и 0 —
|
||||||
|
UPSERT по (org, sphere, system_name, period) перезаписывал 62.198 нулём. Вторым
|
||||||
|
и далее вхождениям добавляется суффикс « (N)».
|
||||||
|
"""
|
||||||
|
wb = openpyxl.Workbook()
|
||||||
|
ws = wb.active
|
||||||
|
ws.title = "ТП"
|
||||||
|
dup = 'Локальные зоны теплоснабжения МУП "Екатеринбургэнерго"'
|
||||||
|
ws.append(
|
||||||
|
_pad(
|
||||||
|
{
|
||||||
|
4: "Централизованная система",
|
||||||
|
7: dup,
|
||||||
|
8: dup,
|
||||||
|
9: 'Локальные зоны теплоснабжения ПАО "Т Плюс"',
|
||||||
|
_ROW_SIZE_COL: 15,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ws.append(
|
||||||
|
_pad(
|
||||||
|
{
|
||||||
|
3: 5,
|
||||||
|
4: "Резерв мощности источников тепловой энергии, в т.ч.:",
|
||||||
|
5: "Гкал/час",
|
||||||
|
7: 62.198,
|
||||||
|
8: 0,
|
||||||
|
9: 0,
|
||||||
|
_ROW_SIZE_COL: 57,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
buf = io.BytesIO()
|
||||||
|
wb.save(buf)
|
||||||
|
|
||||||
|
systems, _ = eh.parse_heat_sheet(buf.getvalue())
|
||||||
|
|
||||||
|
pairs = [(s["system_name"], s["reserve_gcal_h"]) for s in systems]
|
||||||
|
assert pairs == [
|
||||||
|
(dup, 62.198), # первое вхождение — без суффикса, 62.198 НЕ теряется
|
||||||
|
(f"{dup} (2)", 0.0),
|
||||||
|
('Локальные зоны теплоснабжения ПАО "Т Плюс"', 0.0),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_parse_heat_sheet_no_systems_header_returns_empty() -> None:
|
def test_parse_heat_sheet_no_systems_header_returns_empty() -> None:
|
||||||
"""Нет строки «Централизованная система» → ([], all_cells) (graceful, не падаем)."""
|
"""Нет строки «Централизованная система» → ([], all_cells) (graceful, не падаем)."""
|
||||||
wb = openpyxl.Workbook()
|
wb = openpyxl.Workbook()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue