From 3b5f6025aa2fe902431c320d73c1fc2b2bb02566 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 11 Nov 2026 15:40:03 +0400 Subject: [PATCH] =?UTF-8?q?fix(export):=20=D0=B7=D0=B0=D0=BB=D0=B8=D0=B2?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BB=D0=B8=D1=81=D1=82=D0=B0=D1=85=20=D0=9E?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B0=D1=86/=D0=90=D0=A5=D0=A0/=D0=9A=D0=92?= =?UTF-8?q?=20=D0=A1=D0=BC=D0=B5=D1=82=D1=8B=20=D0=A0=D0=A4=20(AURORA-1902?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Возврат тестирования 10.11: в выгрузке формы 2 не было цветных заливок. XlsxDepthSheetWriter._set_palette искал цвет только по пути ключей дерева колонок (section_code, god.….q2), а FORM2_COLORS ключуется путём данных (header.section_code, booking.y2026.q2) — совпадений 0 из 162. Теперь, если по пути дерева цвета нет, он берётся по плоскому ключу данных колонки. Форма 1 не меняется (её цвета находятся по пути дерева, как раньше). Co-Authored-By: Claude Opus 5.5 --- .../services/export_service/export_writers.py | 4 ++ api/tests/unit/test_export_form2_mapping.py | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/api/src/services/export_service/export_writers.py b/api/src/services/export_service/export_writers.py index fbd528a..ed94047 100644 --- a/api/src/services/export_service/export_writers.py +++ b/api/src/services/export_service/export_writers.py @@ -413,6 +413,10 @@ class XlsxDepthSheetWriter(AbstractWriter): color = self.colors_config.get(full_key) if color and "palette" in color: self.palette[key] = color["palette"] + # AURORA-1902: цвета Сметы РФ (FORM2_COLORS) ключуются путём данных + # (header.section_code, plan.q1), а не путём ключей дерева колонок. + if key not in self.palette and (color := self.colors_config.get(key)) and "palette" in color: + self.palette[key] = color["palette"] def _get_header_max_row(self, column_dict: dict) -> int: max_depth = 0 diff --git a/api/tests/unit/test_export_form2_mapping.py b/api/tests/unit/test_export_form2_mapping.py index b7a9d7b..2f93bdf 100644 --- a/api/tests/unit/test_export_form2_mapping.py +++ b/api/tests/unit/test_export_form2_mapping.py @@ -200,3 +200,42 @@ async def test_resolve_form2_vsp_numbers_skips_db_call_when_no_vsp_ids(): await service._resolve_form2_vsp_numbers(rows) service.vsp_repo.get_reg_numbers_by_ids.assert_not_awaited() + + +# AURORA-1902, возврат 10.11: FORM2_COLORS ключуется путём данных (header.section_code, plan.q1), +# а writer искал цвет только по пути ключей дерева колонок — заливок на листах не было. +@pytest.mark.parametrize("sheet", ["OPER", "AHR", "CAP"]) +def test_form2_writer_applies_sheet_palette_to_every_column(sheet): + service = ExportService(AsyncMock()) + writer = service._create_xlsxwriter_sheet_writers(XlsxWorkbook(), FormTypeEnum.FORM_2.value, 2026)[sheet] + + assert set(writer.palette) == set(writer.columns) + for key in writer.columns: + assert writer.palette[key] == FORM2_COLORS[sheet][key]["palette"], key + + +def test_form1_writer_palette_is_unaffected(): + service = ExportService(AsyncMock()) + writer = service._create_xlsxwriter_sheet_writers(XlsxWorkbook(), FormTypeEnum.FORM_1.value, 2026)["OPER"] + + assert len(writer.palette) == len(writer.columns) - 1 + assert writer.palette["section"] == "blue" + + +def test_form2_export_fills_group_row_with_sheet_colors(tmp_path): + from openpyxl import load_workbook + + path = tmp_path / "form2.xlsx" + workbook = XlsxWorkbook(str(path)) + service = ExportService(AsyncMock()) + writer = service._create_xlsxwriter_sheet_writers(workbook, FormTypeEnum.FORM_2.value, 2026)["OPER"] + worksheet = workbook.add_worksheet("OPER") + writer.write(worksheet, [("GROUP", 1, 1, {"header": {"name": "Группа"}, "plan": {"q1": 10}})]) + workbook.close() + + sheet = load_workbook(path).active + plan_q1_column = writer.columns.index("plan.q1") + 1 + group_row = sheet.max_row + fill = sheet.cell(row=group_row, column=plan_q1_column).fill + assert fill.fill_type == "solid" + assert fill.fgColor.rgb not in (None, "00000000", "FFFFFFFF") -- 2.47.2