10 KiB
cell-formula Specification
Purpose
Формулы ячеек листов бюджетных форм (FORM_1, FORM_2, FORM_4) и отчётов проектов (FORM_3): как формула сохраняется вместе со значением, кто и как её видит, когда она перестаёт показываться и когда удаляется.
Термины: ячейка — (владелец, лист, line_id, column), где владелец — бюджетная форма (budget_form.id) или отчёт проекта (rf_project_report.id); line_id и column — те же, что в cell_updated и PATCH …/cell. Формула — выражение без ведущего «=», например 100+50.
Requirements
Requirement: Формула сохраняется вместе со значением ячейки
Запись ячейки с полем formula (WS cell_updated — data.formula; REST PATCH /form/{id}/sheet/{sheet}/cell, …/cells, PATCH /projects/{id}/report/{year}/{type}/cell, …/cells — поле formula элемента) SHALL сохранять формулу этой ячейки в той же транзакции, что и значение: выражение, значение (value записи), автора (текущий пользователь) и время записи. Предыдущая формула ячейки SHALL заменяться. Формула SHALL сохраняться только если запись значения прошла (те же проверки прав и принадлежности строки, что у значения); при отказе в записи значения формула SHALL NOT сохраняться.
Scenario: Сохранение формулы
- WHEN администратор пишет в ячейку FORM_2/AHR
plan.q1значение 150 с формулой100+50 - THEN чтение формул листа возвращает для этой ячейки выражение
100+50, значение 150, автора — этого администратора и время записи
Scenario: Отказ в праве на ячейку
- WHEN исполнитель без права на колонку (окно закрыто или чужая оргединица) пишет значение с формулой
- THEN запрос отклоняется так же, как без формулы (403)
- AND формула ячейки не появляется и прежняя формула не меняется
Requirement: Ввод без формулы удаляет формулу ячейки
Запись значения ячейки без поля formula (или с formula: null) через любой из путей записи выше SHALL удалять формулу этой ячейки, если она была. Это касается и массовой записи …/cells: для каждого элемента без формулы формула его ячейки удаляется.
Scenario: Перезапись числом
- WHEN у ячейки есть формула
100+50, и пользователь записывает в неё значение 200 без формулы - THEN чтение формул листа не возвращает формулы этой ячейки
Requirement: Проверка выражения
Сервер SHALL принимать выражение длиной от 1 до 500 символов, состоящее только из цифр, пробелов и символов + - * / % ( ) , .; ведущий «=» и пробелы по краям SHALL отбрасываться при нормализации. Сервер SHALL NOT вычислять выражение. Формула с непустым выражением SHALL требовать числовое value. При нарушении сервер SHALL отвечать 422 с кодом ошибки по префиксу invalid_formula:, и значение ячейки в этом запросе SHALL NOT записываться.
Scenario: Недопустимое выражение
- WHEN пользователь пишет значение 150 с формулой
drop table - THEN ответ — 422
invalid_formula - AND значение ячейки осталось прежним, формула не сохранилась
Scenario: Нормализация
- WHEN пользователь пишет формулу
=100+50 - THEN сохраняется выражение
100+50
Requirement: Чтение формул листа
Сервер SHALL отдавать все формулы листа: GET /api/v1/form/{form_id}/sheet/{sheet}/formulas и GET /api/v1/projects/{project_id}/report/{year}/{report_type}/formulas. Каждая запись SHALL содержать line_id, column, expression, value, updated_by (id, full_name) и updated_at. Доступ SHALL проверяться так же, как у GET листа (форма) или отчёта (проект): нет доступа к форме или формы нет — 404 «Форма не найдена»; отчёт проекта не найден или нет доступа — та же ошибка, что у PATCH этого отчёта (400 «Отчёт не найден»).
Scenario: Формулы видны другому пользователю
- WHEN пользователь А сохранил формулу, а пользователь Б с доступом к форме запрашивает формулы листа
- THEN Б получает формулу А с её автором и временем
Requirement: Рассылка формулы по WebSocket
Рассылка cell_updated всем подключённым к листу SHALL содержать в data поле formula — нормализованное сохранённое выражение или null, если формулы у ячейки после записи нет, — и при наличии формулы поле formula_meta с updated_by (id, full_name) и updated_at. Значение data.formula в рассылке SHALL задавать сервер, а не пересылать входящее значение клиента.
Scenario: Второй пользователь видит формулу без перезагрузки
- WHEN пользователь А вводит в ячейку
=100+50 - THEN пользователь Б, открывший тот же лист, получает
cell_updatedсdata.formula = "100+50"и автором А - AND в ячейке у Б отображается 150 с маркером формулы
Scenario: Перезапись снимает маркер у всех
- WHEN пользователь Б записывает в ту же ячейку число 200
- THEN все подключённые клиенты получают
cell_updatedсdata.formula = null, и маркер формулы пропадает
Requirement: Отображение формулы
Фронт SHALL показывать у ячейки маркер формулы fx и подсказку с выражением, ФИО автора и датой-временем, только если для ячейки есть формула и её value совпадает с текущим значением ячейки с точностью 1e-9. Редактор ячейки SHALL открываться с текстом = + выражение при том же условии совпадения. Если значения не совпадают (значение изменилось не через ввод, например синхронизацией), маркер SHALL NOT показываться, и редактор открывается со значением.
Scenario: Формула устарела после пересчёта
- WHEN у ячейки есть формула со значением 150, а текущее значение ячейки стало 170
- THEN маркер формулы не показывается, редактор открывается со значением 170
Requirement: Формулы не хранятся в браузере
Фронт SHALL NOT читать и писать формулы в localStorage. При первом запуске новой версии ключи formula_* SHALL удаляться из localStorage.
Scenario: Формула с другого компьютера
- WHEN автор сохранил формулу и открыл лист на другом компьютере
- THEN он видит маркер формулы и открывает редактор с
=выражением
Requirement: Формулы удаляются вместе с владельцем и строкой
Формулы SHALL удаляться при удалении строки, к которой относится ячейка (строка бюджета, запись сателлита аренды/коммунальных/охраны, запись отчёта ОС OTCH9F, строка отчёта проекта), при окончательном удалении бюджетной формы и при удалении отчёта проекта — независимо от того, какая функция удаляет строку.
Scenario: Удаление строки
- WHEN у строки листа есть формулы, и строку удаляют
- THEN чтение формул листа не возвращает формул этой строки