AURORA-1903: лист «Смета» — своя раскладка колонок для каждой формы #287

Merged
aep merged 1 commits from feat/286-aurora-1903-smeta-export-layout into test 2026-11-02 20:37:03 +03:00
Owner

Что сделано

Issue: #286
Jira: AURORA-1903

Лист «Смета» всех форм (FORM_1/FORM_2/FORM_4) выгружался одной плоской раскладкой SMETA_COLUMNS (41 колонка: план/утверждено/факт ×(поддержка+развитие+ИТОГО), корректировка поддержка/развитие). На экране у каждой формы свой набор — выгрузка с ним расходилась.

  1. api/src/services/export_service/export_mappings.py — добавлен SMETA_COLUMNS_BY_FORM = {"FORM_1": [...41...], "FORM_2": [...20, только поддержка...], "FORM_4": [...20, только развитие...]}, списки строго в порядке экрана (web/src/components/RealtimeTable/constants/FORM_*/SMETA.js). SMETA_COLUMNS оставлен алиасом на SMETA_COLUMNS_BY_FORM["FORM_1"] — на него ссылается неиспользуемый openpyxl-словарь писателей и старый тест test_sheet_column_contracts_are_stable (len(SMETA_COLUMNS) == 41 не ломается).
  2. api/src/services/export_service/export_service.py — _create_xlsxwriter_sheet_writers выбирает раскладку по form_type_code: SMETA_COLUMNS_BY_FORM.get(form_type_code, SMETA_COLUMNS_BY_FORM["FORM_1"]).
  3. api/src/services/export_service/export_writers.py — TabularSheetWriter.write и XlsxTabularSheetWriter.write теперь пропускают строку row[0] == "META" (как уже делают depth-писатели через _hierarchical_rows). Раньше служебная строка META от v_form_view давала пустую вторую строку на листе «Смета».
  4. web/src/components/RealtimeTable/constants/FORM_1/SMETA.js — добавлены две колонки по образцу «Итого: {year}»: data.approved.total_year (columnLetter Z, после Y) и data.fact.total_year (columnLetter AL, после AK). SQL (v_form_view, ветка FORM_1 SMETA) всегда отдавал approved.total_year/fact.total_year, выгрузка их писала — на экране их потеряли, теперь добавлены.

FORM_2 раскладка уже учитывает результат AURORA-1901 (новый порядок экрана FORM_2 после группировки итогов по кварталам) — взята литерально из текста тикета AURORA-1903, а не через стекование на ветку AURORA-1901/PR #258.

Тесты

Backend (cd api && pytest tests/unit/test_export_writers.py -v, без БД — 19/19 passed):

  • test_smeta_writer_columns_match_screen_order_per_form[FORM_1|FORM_2|FORM_4] — ключи колонок писателя "SMETA" из _create_xlsxwriter_sheet_writers совпадают с эталонным порядком экрана каждой формы.
  • test_smeta_writer_falls_back_to_form1_layout_for_unknown_form_type — неизвестный/None form_type_code падает на раскладку FORM_1.
  • test_xlsx_tabular_sheet_writer_skips_meta_row, test_tabular_sheet_writer_skips_meta_row_openpyxl — строка META не пишется ни в xlsxwriter-, ни в openpyxl-варианте; ровно одна строка данных пишется.
  • test_sheet_column_contracts_are_stable — расширен: SMETA_COLUMNS is SMETA_COLUMNS_BY_FORM["FORM_1"], длины FORM_2/FORM_4 раскладок.
  • Полный pytest tests/unit — 93 passed, 2 failed (оба failed — test_export_service_query_params.py::test_export_full_form_ignores_non_applicable_params_for_other_sheets и test_export_form_payload_forwards_ignore_flag, оба с TypeError: unexpected keyword argument 'ignore_non_applicable_query_params'; это предсуществующий разрыв сигнатуры, не связанный с этой веткой — подтверждено прогоном того же теста на f407b5c (HEAD ветки test на момент создания worktree) без моих изменений: тот же результат).

Frontend (cd web && node --test src/components/RealtimeTable/constants/FORM_1/SMETA.test.js — 2/2 passed):

  • Новый FORM_1/SMETA.test.js — порядок accessorKey в FORM_1/SMETA.js совпадает с ключами SMETA_COLUMNS_BY_FORM["FORM_1"]; ровно одна колонка data.approved.total_year (Z) и одна data.fact.total_year (AL).
    • Тест сопоставляет текст файла регулярным выражением, а не импортирует модуль: SMETA.js импортирует columnColors без расширения .js — такой путь резолвит только бандлер (Rsbuild), а не нативный ESM-резолвер node --test (ERR_MODULE_NOT_FOUND). Это существующее свойство файла, не трогал.
    • В этом worktree не установлен web/node_modules — остальные utils/*.test.js (кроме columnLayoutUtils.test.js, которому нужен @tanstack/table-core) не запускал в комплекте; свой тест не зависит от npm-пакетов (только node:fs/node:assert).

Rulings

  • Зависимость от AURORA-1901 не стекована. Ветка создана заново от test, не от PR #258 (AURORA-1901, новый порядок экрана FORM_2). Причина: AURORA-1901 трогает только web/src/components/RealtimeTable/constants/FORM_2/* (порядок столбцов экрана), а этот тикет не читает тот файл — итоговый порядок колонок FORM_2 для выгрузки взят литерально из текста тикета AURORA-1903 (который сам по себе уже учитывает результат AURORA-1901). Разные файлы, нет пересечения — стекование не дало бы ничего, кроме лишней зависимости от незамерженного PR.
  • FORM_1-раскладка (41 колонка) не менялась — она уже включала approved_total_year/fact_total_year (SQL их всегда отдавал); несоответствие было только на экране. Изменения backend для FORM_1 ограничены переносом существующего списка в SMETA_COLUMNS_BY_FORM["FORM_1"] с сохранением алиаса SMETA_COLUMNS для обратной совместимости.
  • Вариант по умолчанию для вопроса к заказчику принят без дополнительного обсуждения (так и было сформулировано в тикете: "по умолчанию из вопроса к заказчику... не спрашивать повторно") — добавил approved.total_year/fact.total_year на экран FORM_1, а не убрал их из выгрузки.
  • Заголовки колонок остаются плоскими («План поддержка I квартал» и т.п.), год в TabularSheetWriter/XlsxTabularSheetWriter не подставляется — не менял это поведение, как и указано в тикете.

🤖 Generated with Claude Code

## Что сделано Issue: https://git.aepif.ru/RSHB/DFiP_Budget_planing/issues/286 Jira: AURORA-1903 Лист «Смета» всех форм (FORM_1/FORM_2/FORM_4) выгружался одной плоской раскладкой `SMETA_COLUMNS` (41 колонка: план/утверждено/факт ×(поддержка+развитие+ИТОГО), корректировка поддержка/развитие). На экране у каждой формы свой набор — выгрузка с ним расходилась. 1. `api/src/services/export_service/export_mappings.py` — добавлен `SMETA_COLUMNS_BY_FORM = {"FORM_1": [...41...], "FORM_2": [...20, только поддержка...], "FORM_4": [...20, только развитие...]}`, списки строго в порядке экрана (`web/src/components/RealtimeTable/constants/FORM_*/SMETA.js`). `SMETA_COLUMNS` оставлен алиасом на `SMETA_COLUMNS_BY_FORM["FORM_1"]` — на него ссылается неиспользуемый openpyxl-словарь писателей и старый тест `test_sheet_column_contracts_are_stable` (`len(SMETA_COLUMNS) == 41` не ломается). 2. `api/src/services/export_service/export_service.py` — `_create_xlsxwriter_sheet_writers` выбирает раскладку по `form_type_code`: `SMETA_COLUMNS_BY_FORM.get(form_type_code, SMETA_COLUMNS_BY_FORM["FORM_1"])`. 3. `api/src/services/export_service/export_writers.py` — `TabularSheetWriter.write` и `XlsxTabularSheetWriter.write` теперь пропускают строку `row[0] == "META"` (как уже делают depth-писатели через `_hierarchical_rows`). Раньше служебная строка META от `v_form_view` давала пустую вторую строку на листе «Смета». 4. `web/src/components/RealtimeTable/constants/FORM_1/SMETA.js` — добавлены две колонки по образцу «Итого: {year}»: `data.approved.total_year` (columnLetter `Z`, после Y) и `data.fact.total_year` (columnLetter `AL`, после AK). SQL (`v_form_view`, ветка FORM_1 SMETA) всегда отдавал `approved.total_year`/`fact.total_year`, выгрузка их писала — на экране их потеряли, теперь добавлены. FORM_2 раскладка уже учитывает результат AURORA-1901 (новый порядок экрана FORM_2 после группировки итогов по кварталам) — взята литерально из текста тикета AURORA-1903, а не через стекование на ветку AURORA-1901/PR #258. ## Тесты Backend (`cd api && pytest tests/unit/test_export_writers.py -v`, без БД — 19/19 passed): - `test_smeta_writer_columns_match_screen_order_per_form[FORM_1|FORM_2|FORM_4]` — ключи колонок писателя "SMETA" из `_create_xlsxwriter_sheet_writers` совпадают с эталонным порядком экрана каждой формы. - `test_smeta_writer_falls_back_to_form1_layout_for_unknown_form_type` — неизвестный/`None` `form_type_code` падает на раскладку FORM_1. - `test_xlsx_tabular_sheet_writer_skips_meta_row`, `test_tabular_sheet_writer_skips_meta_row_openpyxl` — строка META не пишется ни в xlsxwriter-, ни в openpyxl-варианте; ровно одна строка данных пишется. - `test_sheet_column_contracts_are_stable` — расширен: `SMETA_COLUMNS is SMETA_COLUMNS_BY_FORM["FORM_1"]`, длины FORM_2/FORM_4 раскладок. - Полный `pytest tests/unit` — 93 passed, 2 failed (оба failed — `test_export_service_query_params.py::test_export_full_form_ignores_non_applicable_params_for_other_sheets` и `test_export_form_payload_forwards_ignore_flag`, оба с `TypeError: unexpected keyword argument 'ignore_non_applicable_query_params'`; это предсуществующий разрыв сигнатуры, не связанный с этой веткой — подтверждено прогоном того же теста на `f407b5c` (HEAD ветки `test` на момент создания worktree) без моих изменений: тот же результат). Frontend (`cd web && node --test src/components/RealtimeTable/constants/FORM_1/SMETA.test.js` — 2/2 passed): - Новый `FORM_1/SMETA.test.js` — порядок `accessorKey` в `FORM_1/SMETA.js` совпадает с ключами `SMETA_COLUMNS_BY_FORM["FORM_1"]`; ровно одна колонка `data.approved.total_year` (Z) и одна `data.fact.total_year` (AL). - Тест сопоставляет текст файла регулярным выражением, а не импортирует модуль: `SMETA.js` импортирует `columnColors` без расширения `.js` — такой путь резолвит только бандлер (Rsbuild), а не нативный ESM-резолвер `node --test` (`ERR_MODULE_NOT_FOUND`). Это существующее свойство файла, не трогал. - В этом worktree не установлен `web/node_modules` — остальные `utils/*.test.js` (кроме `columnLayoutUtils.test.js`, которому нужен `@tanstack/table-core`) не запускал в комплекте; свой тест не зависит от npm-пакетов (только `node:fs`/`node:assert`). ## Rulings - **Зависимость от AURORA-1901 не стекована.** Ветка создана заново от `test`, не от PR #258 (AURORA-1901, новый порядок экрана FORM_2). Причина: AURORA-1901 трогает только `web/src/components/RealtimeTable/constants/FORM_2/*` (порядок столбцов экрана), а этот тикет не читает тот файл — итоговый порядок колонок FORM_2 для выгрузки взят литерально из текста тикета AURORA-1903 (который сам по себе уже учитывает результат AURORA-1901). Разные файлы, нет пересечения — стекование не дало бы ничего, кроме лишней зависимости от незамерженного PR. - **FORM_1-раскладка (41 колонка) не менялась** — она уже включала `approved_total_year`/`fact_total_year` (SQL их всегда отдавал); несоответствие было только на экране. Изменения backend для FORM_1 ограничены переносом существующего списка в `SMETA_COLUMNS_BY_FORM["FORM_1"]` с сохранением алиаса `SMETA_COLUMNS` для обратной совместимости. - **Вариант по умолчанию для вопроса к заказчику принят без дополнительного обсуждения** (так и было сформулировано в тикете: "по умолчанию из вопроса к заказчику... не спрашивать повторно") — добавил `approved.total_year`/`fact.total_year` на экран FORM_1, а не убрал их из выгрузки. - Заголовки колонок остаются плоскими («План поддержка I квартал» и т.п.), год в `TabularSheetWriter`/`XlsxTabularSheetWriter` не подставляется — не менял это поведение, как и указано в тикете. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 1 commit 2026-11-01 15:02:18 +03:00
До этой правки лист "Смета" всех форм выгружался одной плоской
раскладкой SMETA_COLUMNS (41 колонка) — для FORM_2/FORM_4 в выгрузке
были лишние колонки другого направления (поддержка/развитие), которых
нет на экране. Добавлена SMETA_COLUMNS_BY_FORM{"FORM_1","FORM_2","FORM_4"}
с раскладкой колонок строго в порядке экрана каждой формы;
_create_xlsxwriter_sheet_writers теперь выбирает нужный список по
form_type_code. SMETA_COLUMNS остаётся алиасом на FORM_1-раскладку для
обратной совместимости (неиспользуемый openpyxl-словарь, старый тест).

Также TabularSheetWriter.write и XlsxTabularSheetWriter.write теперь
пропускают служебную строку META (как уже делают depth-писатели) —
раньше она давала пустую вторую строку на листе "Смета".

На экране FORM_1/SMETA.js добавлены "Утверждено ИТОГО Год" (Z) и
"Факт ИТОГО Год" (AL) — SQL (v_form_view) всегда их отдавал и
выгрузка Excel их писала, но экран их терял.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
tsygankoviva approved these changes 2026-11-02 12:27:58 +03:00
aep merged commit 12aae02504 into test 2026-11-02 20:37:03 +03:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/DFiP_Budget_planing#287
No description provided.