AURORA-1887: скрыть сателлитные строки на листе АХР, заблокировать добавление для аренды/коммуналки/охраны #273
Loading…
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/272-aurora-1887-ahr-hide-satellite-rows"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #272.
Контекст
Упрощённый дизайн (согласован в чате с человеком 2026-10-31) — расходится с исходным архитектурным текстом тикета AURORA-1887 (который предлагал слить budget_line по статье + лист-источник, снять UNIQUE(target_line_id) в form2_ahr_satellite_line_source, миграцию данных и правку протокола WS). Согласованная версия ограничивается визуальным скрытием и UI-гейтом, без изменения модели данных:
Что сделано
Скрытие сателлитных INPUT-строк на листе AHR.
v3.v_form2_sheet_jsonb(новая миграция0054_form2_ahr_hide_satellite_rows.sql, CREATE OR REPLACE полным актуальным текстом + 3 точечных изменения) теперь приp_sheet = 'AHR'не возвращаетINPUT-строки, у которыхbudget_line.source_sheet IN ('AHR_LIMIT','AHR_RENT','AHR_UTILITY','AHR_SECURITY'). Ручные строки (source_sheet IS NULL, включая «сверх лимита» из AURORA-1907) остаются видимыми без изменений. Листы-источники (AHR_LIMIT/AHR_RENT/AHR_UTILITY/AHR_SECURITY) не затронуты — полная детализация там сохраняется.Суммы на заголовках статей (
plan.year/plan.limit_year/plan.over_limit_year) считаются вv3.v_form2_sheet_sections(CTEtw_agg) и вlimit_treeCTE независимо от видимости строк в финальной выдаче — фильтр применяется только к финальномуSELECT, логика агрегации не тронута.Блокировка «Добавить строку» для аренды/коммуналки/охраны. Новое поле
header.can_add_row(только приp_sheet = 'AHR') —falseдля статей аренды/коммуналки/охраны,trueдля всех прочих (включая лимитные — AURORA-1907 «сверх лимита» не трогаем). Новый небольшой helperv3._form2_satellite_expense_item(p_sheet)возвращает единственныйexpense_item_idдля'AHR_RENT'/'AHR_UTILITY'/'AHR_SECURITY'(314/24/779 соответственно — для'AHR_LIMIT'единого id нет, там множество LEAF-статей).Фронт (
RealtimeTable.jsxhandleAddRow, через чистую функциюcanAddRowForHeaderвutils/rowUtils.js) читает флаг и блокирует клик с тостом «Добавление строк недоступно для этой статьи» — до вызова API.Рулинги
header.can_add_row, читаемый фронтом, без серверной валидации вv3.add_budget_line. Обоснование: это консистентно с существующими паттернами в этом же компоненте —FormsNoCanAddRow,isVspAdditionRow,isAdditionExpenseItem— ни один из них тоже не продублирован проверкой на backend.v3.add_budget_lineи так принимает произвольныйexpense_item_idна любом сочетании sheet/статья без серверной валидации специфичных для UI правил (убедился чтением кода — тот же паттерн уже используется дляAHR_LIMITвFormsNoCanAddRow, которая тоже чисто фронтовая).psqlна разовой тестовой Postgres 16 (SELECT id, item_id, name, sheet, direction, depth FROM v3.expense_item WHERE id IN (314,24,779)): все три —sheet='AHR',direction='Support'. Совпадают с актуальным кодомv3.add_budget_line(0051) иv3.sync_form2_ahr_satellite_lines(0052), где эти же id уже захардкожены как текущие (не как "старые" из 0034) — т.е. это не было новым открытием, но было дважды подтверждено независимо.notify_ahr_about_satellite_change/get_form2_ahr_satellite_delta(websocket.py, 0053) иcellUtils.js/RealtimeContext.jsна фронте.get_form2_ahr_satellite_deltaсама вызываетv3.v_form_view(..., 'AHR', ...), то есть автоматически наследует новый фильтр — скрытая INPUT-строка просто не попадёт в WS-дельту, аwebsocket.pyпри отсутствии INPUT-строки в дельте дляrow_addedуже (без изменений с моей стороны) откатывается наcell_updated-событие с заголовками. На фронтеcellUtils.deleteRow/updateCells— no-op при несуществующемline_id/row_type+depth+sort_order(прочитано, не изменено). Протокол WS НЕ менялся.test_form2_ahr_limit.py,test_form2_ahr_satellite_spod_integration.py, частьtest_form2_ahr_satellite_integration.py) проверяли суммы/источник напрямую на теперь скрытых INPUT-строках листа AHR. Переведены на сравнение через заголовок статьи (ITEM/SUB_ITEM/SUB_SUB_ITEM — глубина статьи в дереве расходов разная для разных категорий, проверено эмпирически) по схеме «до/после патча» (устойчиво к существующим сидовым данным), либо через лист-источник, где детализация не пряталась.Тесты
Интеграционные (
api/tests/integration/test_form2_ahr_satellite_integration.py, общий файл серии задач 1907/1909/1887) — 10 новых тестов на все пункты приёмки (скрытие лимитных LEAF с верной суммой на заголовке, скрытие записи аренды/коммуналки/охраны с видимостью на листе-источнике, регрессия на ручную «сверх лимита» строку,can_add_row=false/true, регрессия на обычную статью). Плюс адаптация 3 ранее существовавших тестов, сломанных скрытием строк (см. R-4).Фронт:
canAddRowForHeader(чистая функция вutils/rowUtils.js) покрытаnode --test(rowUtils.test.js).Одноразовая Postgres 16 в Docker (не
perf-pg, снесена после работы).cd api && pytest: 247 passed, 3 failed (прежний известный набор, не связанный с этой веткой:test_backend_calls_form3_add_project_and_add_line_functions,test_export_full_form_ignores_non_applicable_params_for_other_sheets,test_export_form_payload_forwards_ignore_flag), 4 skipped — итого 254 (было 244 до +10 новых).cd web && node --test src/components/RealtimeTable/utils/*.test.js: 15 passed.Test plan
api/pytest: разница — ровно +10 новых тестов, прежние 3 известных падения без измененийnode --test: 15/15 зелёныхperf-pgне затронут (использовалась отдельная одноразовая Postgres 16, снесена)🤖 Generated with Claude Code
Миграция 0053: v3.budget_line.source_sheet (NULL | AHR_LIMIT | AHR_RENT | AHR_UTILITY | AHR_SECURITY) — явный признак источника строки вместо сопоставления по совпадению имени с LEAF limit_template. Backfill существующих строк: сателлиты — из v3.form2_ahr_satellite_line_source, лимитные — минимальный id в группе (форма, статья, имя LEAF), остальные совпавшие по имени становятся ручными (RAISE NOTICE со списком). _ensure_form2_ahr_limit_sync_line теперь ищет строку по source_sheet='AHR_LIMIT' (а не по имени) — тот же класс бага, что чинил #265/AURORA-1909 для сателлитов аренды/коммуналки/охраны, теперь для лимитов. is_form2_ahr_satellite_line, del_budget_line (guard на удаление) и get_form2_ahr_satellite_delta переведены на признак источника. Новая v3._form2_expense_item_has_limit выносит правило «у статьи есть лимит» в отдельную функцию. v_form2_sheet_jsonb: header.source ('AHR_LIMIT'/'AHR_RENT'/'AHR_UTILITY'/ 'AHR_SECURITY'/'MANUAL'), header.is_over_limit для ручных строк на статьях с лимитом; plan.limit_year/over_limit_year (только на листе AHR, свёрнуты по дереву статей через mv_expense_item_tree.desc_ids) — plan.year не меняется, остаётся суммой всех строк. Фронт: AHR.js — колонки «В пределах лимита, год»/«Сверх лимита, год» после «План, год» (нередактируемые — нет случая в v3._apply_form_cell); Cell.jsx — чип «сверх лимита» в ячейке наименования по header.is_over_limit, без заливки строки. export_mappings.py — те же два поля в экспорт АХР. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>Упрощённый дизайн (согласован в чате 2026-10-31, расходится с архитектурным предложением из тикета): без слияния budget_line, без миграции данных, без изменения протокола WS, без изменения v_svod2_rf. - v3.v_form2_sheet_jsonb (0054): при p_sheet='AHR' не возвращает INPUT-строки с budget_line.source_sheet IN ('AHR_LIMIT','AHR_RENT','AHR_UTILITY', 'AHR_SECURITY'); ручные строки (включая «сверх лимита», AURORA-1907) остаются видимыми. Листы-источники не затронуты. Суммы на заголовках статей считаются независимо от видимости строк — не меняются. - header.can_add_row (новое поле, только p_sheet='AHR'): false для статей аренды/коммуналки/охраны (v3._form2_satellite_expense_item, новый helper), true для лимитных и обычных статей. Фронт (RealtimeTable.jsx handleAddRow, utils/rowUtils.js canAddRowForHeader) блокирует «Добавить строку» по этому флагу — тот же паттерн, что у FormsNoCanAddRow/isVspAdditionRow (без серверной валидации в add_budget_line). - Обновлены тесты, которые проверяли суммы/источник через теперь скрытые INPUT-строки на AHR (test_form2_ahr_limit.py, test_form2_ahr_satellite_spod_integration.py, test_form2_ahr_satellite_integration.py) — сравнение переведено на заголовок статьи (до/после патча) и на лист-источник. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>