feat: формулы ячеек на сервере, маркер fx для всех пользователей (AURORA-1896) #323
Loading…
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/320-aurora-1896-cell-formulas"
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 #320. Jira: AURORA-1896 (замечание заказчика №8 «Формулы и факт»).
Что сделано
Формулы ячеек теперь хранятся на сервере и видны всем пользователям, а не только в localStorage автора.
0060_cell_formula):v3.cell_formula— последняя формула ячейки: выражение, значение, автор, время;budget_formиrf_project_report;v3.set_cell_formulasиv3.v_cell_formulas;budget_line,rent_detail,utility_detail,security_detail,fixed_asset_reportиrf_project_report_line.formulaвPATCH …/cellи…/cellsдля форм и отчётов проектов. Формула пишется в той же транзакции, что и значение;invalid_formula;/form/{id}/sheet/{sheet}/formulasи/projects/{id}/report/{year}/{type}/formulas.cell_updatedнесётdata.formulaиdata.formula_meta. Значения выставляет сервер, а не пересылает присланные клиентом, в том числе при отказе в доступе (I-1).formulaStore,RealtimeContext);fxс подсказкой «=выражение · ФИО · дата время», если значение формулы совпадает с текущим значением ячейки;=выражениемс сервера;formula_*удаляются.Спека:
openspec/changes/aurora-1896-cell-formulas/. План:docs/superpowers/plans/2026-11-11-aurora-1896-cell-formulas.md.⚠️ Порядок мержа: #315 → #317 → #319 → #323
Миграция —
0061_cell_formula,down_revision = "0060". Это0060_form_phase_direction_fixиз PR #315 (AURORA-1879).Этот PR вливается только после #315, иначе Alembic не найдёт ревизию 0060. Проверено на временном слиянии всего стека (#315/#317/#319) с этой веткой, результат — в разделе «Проверка».
Обратить внимание
core/exception_handlers.py: снимается обёртка asyncpg<class …>:перед сопоставлением префикса. Из-за этого все validation-префиксы на реальной БД теперь отвечают 422 вместо 400, и полеfieldзаполняется. Фронт не различает 400 и 422.valueчисловое. SQL не знает типов колонок (design D3).Проверка
pytest --init_dbна чистой БД: 947 passed, 10 failed, 4 skipped. Все 10 падений — известные падения базовойtest, список совпадает один в один.node --testпо всем тестам: 300 pass, 1 fail — известныйSMETA.test.js.npm run buildпроходит. Biome: новых ошибок нет.openspec validate aurora-1896-cell-formulas: valid.pytest --init_db: 957 passed, 10 failed (те же 10 известных падений), 4 skipped. Alembic доходит до 0061 одной цепочкой.Rulings I made
Co-Authored-By: Claude Opus 5.5по Global Constraints планаinvalid_formula: owner|line_id|length|chars|value. Пустойline_idилиcolumnдаётinvalid_formula: line_id. Владелец проверяется и вv_cell_formulas. Своя фикстураsvod2_sqlс откатомupd_form3_cellsработает по тому же правилу, чтоcells:exclude={"formula"}, ключformulaдобавляется только если он не Noneexception_handlers.py: 422 вместо 400 для validation-префиксов на реальной БДFormsSheetApi.getFormulasиProjectsApi.getReportFormulas0061поверх0060из #315. Порядок мержа #315 → #317 → #319 → #323 подтвердил человекНаходки
84dbaaf84dbaafNaNпринимается как value84dbaafp_sheetили неизвестный пользователь дают сырую ошибку БДdowngrade = passfloat(value)при NULLplan.q1в тестах84dbaaf84dbaaf84dbaaf84dbaafportal.callв тестеtest_projects_api_smokeпропускаются18573d618573d618573d6hasattr(updated_at, 'isoformat')3bee5e7updated_atи нулевые id3bee5e7r.data.resultisConnected=falsefxможет налезать на левый текст5-1без «=» в числовой колонке блокируетсяfxна один кадрecef6eb\s, сервер принимал только ASCII-пробелe569d1838036b3(0061, порядок мержа зафиксирован)e107fa4v_cell_formulasне использует индекс владельцаe107fa4Infinityпринимается, GET листа даёт 500e107fa454e60dcformulaStore.size()нужен только тестам, WS-тесты привязаны к seed| O-4 | Подсказка формулы появляется только при наведении на значок
fx(около 8×9 px), а не на всю ячейку | deferred (UX, на усмотрение фронта) |Deferred (уйдут в follow-up при закрытии): T1.4, T3.3, T7.1, T7.2, T7.5, M-4, M-6, M-8, O-4.
🤖 Generated with Claude Code
SheetService.update_cell_with_formula/update_cells пишут формулу после значения в одной транзакции, GET /form/{id}/sheet/{sheet}/formulas. Ошибки БД с обёрткой asyncpg "<class ...>: invalid_formula: ..." теперь корректно мапятся в 422. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>PATCH cell/cells отчёта проекта пишут формулу в той же транзакции, GET .../report/{year}/{report_type}/formulas возвращает формулы отчёта. Тесты: roundtrip, снятие формулы, каскад удаления проекта, триггер rf_project_report_line (del_form3_line и прямой DELETE). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>- RealtimeContext: стор карты формул (formulaStore), загрузка при открытии листа и переподключении (формы и отчёты проектов), обновление на каждом cell_updated, защита от устаревших ответов при смене листа; useCellFormula; updateCell(..., { formula }) - Cell: маркер fx только при актуальной формуле, подсказка с единицей при displayFactor != 1 - EditCell: начальный текст «=выражение», выражение уходит в data.formula, без localStorage; ввод «100+50» без «=» не отправляется (тост «Формула начинается с =») - удалены resolveEditorState и clearLegacyFormulaKeys; T6.1/T6.2 в cellFormulaUtils Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Проверка в браузере (12.11)
Проверено локально: API и фронт из этой ветки, чистая БД с сидом.
=100+50fxв левом нижнем углуfx, подсказка «=100+50 · admin · 12.11.2026 01:00»=100+50=10*3=10*3formula_*в localStorage100+50без «=»=7*6fxу автора и во второй вкладке, подсказка с авторомCell,tableColumns)…/formulasдля формы и отчётаНаблюдения:
fx(около 8×9 px), а не на всю ячейку. На усмотрение фронта.value prop on textarea should not be nullпри открытии пустой ячейки. Оно было и до PR: пустое значение передавалось в редактор как null и раньше.fxна текст) не подтвердилась: формулы живут в числовых колонках, числа выровнены вправо.Миграция
Переименована в
0061_cell_formulaповерх0060_form_phase_direction_fixиз #315 (коммит38036b3). Порядок мержа: #315 → #317 → #319 → #323.🤖 Generated with Claude Code