# Дизайн: экран «Таблица корректировки» (AURORA-1541, arm-core #206) ## Зачем Кредитный аналитик на шаге консолидации видит, где внутригрупповые обороты двух компаний не сошлись, разбирается, из каких строк ОСВ сложилась каждая сторона, переносит строки между правилами и вносит корректировку — сколько и из каких статей ББ исключить. Без экрана корректировки ВГО делаются только вне системы, и тестирование корректировок (AURORA-1542, с 03.11) начать нельзя. ## Что считается готовым (слова владельца, 28.10.2026) - К сроку 02.11 — **рабочий экран на настоящем API**, не демо на моках. Если бэкенд (AURORA-1540) или аналитика не успевают — мы сами помогаем ребятам доделать. - Моки нужны, чтобы фронт не стоял, пока нет API, а не как результат. **Объём плана — только `web/`.** Бэкенд (DBML, `vgo_assignment`, разнесение, эндпоинты, аудит) — AURORA-1540 Цыганкова; помогаем ему на ревью его PR, а не задачами этого плана. Последняя задача плана — подключение к настоящему API, когда 1540 слит: флаг `REACT_APP_CORRECTIONS_MOCK` выключается, если эндпоинты есть в `main`, вкладка открывается на стенде на реальной версии и проходит сценарии спеки; расхождения ответа с контрактом правятся в той ветке, где ошибка (фейк или бэкенд). Сверяем фейк с реальным ответом мы (владелец / этот агент) при подключении. ## Источники и их вес 1. Аналитика Лысенко — DOC-272613, ответы 1–7 (AURORA-1395, 27.10), DOC-274230. **Приоритетна над нашими правилами и черновиками** (решение владельца 28.10). 2. Дизайн от 23.10.2026 — `ДКБ_таблица_корректировок_23_10_26_1.html` (вложение к DOC-272613; в корне workspace). Как лежат строки в дизайне — визуализация; логика — по аналитике. 3. ТЗ 6.8 / Прил. 9 — ниже аналитики, иногда игнорируется. 4. Контракт API — `../docs/dev/api-contract-corrections.md` и `.openapi.yaml` (docs #183, вложение в AURORA-1540). Открытые вопросы аналитику (комментарий `[design-23-10-check]` в AURORA-1395, п. 1–12 + 3 по ТЗ; в AURORA-1396 — ОФР) не блокируют работу: зависящие места сделаны так, чтобы ответ менял поведение точечно. ## Цели - Вкладка «Таблица корректировки» страницы отчёта версии, по виду — как дизайн 23.10. - Таблица агрегатов с раскрытием до строк ОСВ, нераспределённые строки, итоги, фильтры, пресеты по правилам, единицы, настройка колонок, экспорт, полный экран. - Окно «Корректировка операции» агрегата: строки сторон, распределение по статьям, контроль, комментарий, сохранение. - Решения по строкам: флажок «Учитывать в КФО», отнести / перенести / убрать / вернуть к автоматике. - Отмена корректировки агрегата. - Только чтение, когда сервер так говорит (`editable = false`). ## Не цели - Бэкенд и DBML (AURORA-1540), правила §8 в `05-domain-rules.md`. - ОФР (нет в дизайне; AURORA-1396), импорт xlsx (ТЗ 6.8, ждёт ответа). - Корректировка строки ОСВ и нераспределённой строки (аналитика: только агрегат; ждёт п. 2). - Переход из шахматки с фокусом на паре (AURORA-1653), учёт корректировок в шахматке (AURORA-1643). ## Анти-цели (провал, даже если «работает») - Фронт сам считает разнесение строк, отклонения, порог 5 % или статусы агрегата — это делает сервер; фронт только показывает, форматирует и суммирует видимые строки для «Итого». - Деньги через `number`/`float` с потерей копеек. Суммы — строки контракта, сложение — точное десятичное. - Экран, в котором можно что-то нажать и молча потерять изменения окна корректировки. - Кнопки правки у версии, которую сервер считает нередактируемой. ## Ограничения - `web/` arm-core: React 18 + TS strict, antd 6, react-router 7, biome (140, одинарные кавычки), vitest. - Деньги в API — рубли строками с двумя знаками; показ в руб. / тыс. руб. и 0–2 знака — как в шахматке. - Состояние экрана — локальные хуки (стор Redux пуст по соглашению шаблона). - Пользователь слаб во фронте — решения в PR объясняются простыми словами. - Каждый экран сверяется с дизайном в Playwright и проходится руками до сдачи. ## Как устроено ### Данные - `GET …/corrections?statement_type=balance` — одна загрузка всей таблицы; фильтры, сортировка, «Итого» — на клиенте. - Правки: `PUT …/aggregates/{rule}/{c1}/{c2}` (сохранить), `POST …/revoke`, `POST …/allocations` (решение по строке, ответ — вся таблица), `GET …/export`. - Клиент — `web/src/services/api/corrections.ts` поверх `api/client.ts`. При `REACT_APP_CORRECTIONS_MOCK=true` те же функции отвечают из фейка контракта в памяти (данные — из дизайна 23.10, с проверками контракта: обязательный комментарий, `expected_version_no`, применимость правила). Флаг по умолчанию выключен; в production-сборке фейк не используется. ### Таблица Колонки как в дизайне: «Учитывать в КФО»; Дебет — ЮЛ, Строка баланса, Счёт, Сумма; Кредит — то же; Контроль — Отклонение %, Отклонение сумма; Корректировка — Строка баланса, Сумма (Дт), Строка баланса, Сумма (Кт), Комментарий; колонка действий. - **Строка агрегата.** Суммы сторон, счета (`accounts`), отклонение. Процент и сумма отклонения красные при `exceeds_threshold`. Корректировка — статьи и суммы `correction.debit` / `credit` (несколько статей стороны — по строке на статью в ячейке), комментарий. Действия: «Корректировать» (окно), меню «…» — «Отменить корректировку» (если есть). `composition_changed` — подсветка строки и значок с подсказкой «Состав изменился после корректировки». `correction.status = DRAFT` — пометка «черновик» у корректировки. - **Раскрытие.** Под агрегатом — его строки ОСВ (`side_1.entries`, затем `side_2.entries`): строка стороны 1 заполняет блок «Дебет», стороны 2 — «Кредит», остальные ячейки пустые (DOC-272613 п. 3.4; пары строк из дизайна не строим). У строки — флажок «Учитывать в КФО» и меню: «Перенести в правило…» (правила — `candidate_rule_ids` строки; фронт сам не сверяет счета с правилами), «Убрать из правила», «Вернуть к автоматике» (если `decision = ASSIGN`). - **Флажок агрегата** «Учитывать в КФО» — только показ: «Да» — все строки учитываются, «Частично» — часть исключена, «Нет» — все исключены. Сам признак ставится на строке (DOC-272613; ждёт п. 4). - **Нераспределённые строки** — после агрегатов, фон приглушён. Владелец — на своей стороне (дебетовая строка — в «Дебет», кредитовая — в «Кредит»), на другой стороне — только ЮЛ контрагента. Строка баланса не показывается (DOC-272613 п. 4.3). Флажок «Учитывать в КФО», меню «Отнести к правилу…» (список — `candidate_rule_ids`), «Вернуть к автоматике» для `reason = UNASSIGNED`. Кнопки «Корректировать» нет (ждёт п. 2). - **«Итого»** — суммы сторон, отклонения и корректировок по видимым агрегатам, точным сложением строк; процент «Итого» не показываем (смысл не задан). - Подписи «Отнести/Перенести в правило…» показывают правила как пресеты: «Правило N: <статья 1> — <статья 2>». ### Панель - «Отображение»: «Общий» / «По пресету»; при «По пресету» — выбор правила (подпись с номером — снимает одинаковые подписи правил 5 и 8 из дизайна, п. 12); в таблице только агрегаты этого правила и те нераспределённые строки, у которых это правило есть в `candidate_rule_ids` (их можно отнести к нему). - «Тип записи»: «Все» / «Пары счетов» (агрегаты) / «Нераспределенные записи». - Фильтры «ЮЛ» и «Счёт» действуют и на нераспределённые строки; «Строка баланса» и «Отклонение» — только на агрегаты, при заданном одном из них нераспределённые строки скрываются (у них нет статьи и отклонения). - Составная статья правила (`"1450/1550"`, `"1310/1350"`, правила 1 и 2) показывается как «1450 / 1550»; в фильтре «Строка баланса» это два кода; в окне корректировки подставляется первый код, аналитик может выбрать второй. - Единицы и знаки — тот же компонент, что в шахматке. - Фильтры в заголовках: ЮЛ (подстрока, обе стороны), Строка баланса (список), Счёт (начало кода), Отклонение % («Все» / «≥ 5 %» / «< 5 %», по `exceeds_threshold`); «Сбросить фильтры» — когда что-то задано. - «Настройка таблицы» — `GenericTable/ColumnSettings` (видимость групп и колонок); «Экспорт» — файл сервера; «На весь экран» — как в шахматке. ### Окно «Корректировка операции» По дизайну: шапка сторон (компания, статья правила), блоки «Исходные данные ОСВ» и «Распределение корректировки» для каждой стороны, итоги, комментарий, «Отменить» / «Сохранить корректировки». - **Исходные данные ОСВ** — строки стороны агрегата. «×» у строки — «Убрать из правила» (`UNASSIGN`), «Добавить строку ОСВ» — выбор из нераспределённых строк, которые подходят под эту сторону: та же пара компаний (владелец и контрагент), сторона строки = сторона правила, правило агрегата есть в `candidate_rule_ids` (ответ 3(а)). Обе операции идут на сервер сразу (`POST …/allocations`), окно перечитывает агрегат. - **Распределение** — статьи стороны: строка баланса (код статьи) и сумма; «Добавить строку» — дочерняя статья. Без корректировки окно предлагает по стороне одну статью правила с суммой стороны (как в дизайне). - **Контроль** — суммы исходных строк сторон и суммы распределения сторон, разница и процент к меньшему (как в таблице; 79,77 % из дизайна — ошибка дизайна, п. 7). Расхождение не запрещает сохранение (ждёт п. 8). - **Сохранить** — `PUT` с `status = APPLIED`, `expected_version_no` из ответа; ошибки сервера показываются в окне по коду (`COMMENT_REQUIRED` — у поля комментария, `INVALID_LINE_CODE` — у статьи, `CORRECTION_VERSION_CONFLICT` — «Корректировку уже изменили, таблица обновлена», окно перечитывает данные). - **Черновик окна в `localStorage`** (решение владельца 28.10.2026 вместо блокировки переходов): статьи распределения и комментарий сохраняются при каждой правке; ключ — пользователь + версия + агрегат (`rule_id`, компании), в записи — время и `version_no` корректировки, от которой начаты правки. Переход «Назад», закрытие вкладки, переход по ссылке правки не теряют. При открытии окна этого агрегата черновик подставляется с плашкой «Восстановлены несохранённые правки от ЧЧ:ММ» и кнопкой «Сбросить»; если `version_no` на сервере уже другой — плашка «Корректировку изменили после ваших правок» (аналитик решает: оставить или сбросить). Черновик удаляется после успешного сохранения и после «Отменить» с подтверждением «Есть несохранённые изменения. Закрыть без сохранения?». Действия со строками в черновик не входят (они уже на сервере). Доступ к хранилищу — в `try/catch`: недоступно (приватный режим) — работаем без черновика. ### Только чтение `editable = false` — «Корректировать», флажки и меню решений неактивны; подсказка по `read_only_reason`: `VERSION_NOT_EDITABLE` — «Версия закрыта для изменений», `LOCK_REQUIRED` — «Возьмите консолидацию в работу», `LOCKED_BY_OTHER` — «Консолидацию редактирует другой пользователь». Окно корректировки открывается на просмотр. ### Состояния Загрузка — индикатор на месте таблицы; ошибка — уведомление с текстом сервера и «Повторить»; пусто — «Внутригрупповых остатков между компаниями периметра нет»; фильтры ничего не нашли — «Нет записей для выбранных фильтров» (текст дизайна). ## Что оставлено исполнителю Разбиение на компоненты и хуки, имена файлов внутри `widgets/CorrectionTable/`, способ раскрытия (antd `expandable` или собственные строки), вид меню действий, точная раскладка окна в пределах дизайна, состав данных фейка. ## Decisions made without discussion | Дата | Решение | Почему | Цена ошибки | |---|---|---|---| | 28.10.2026 | Контракт API пишем сами (docs #183), markdown + OpenAPI; корректировка в контракте — только на агрегат | API ещё нет; аналитика приоритетна | при ответе «можно на строку» (п. 2) — новый эндпоинт и кнопки на строках | | 28.10.2026 | Раскрытие агрегата — строки ОСВ под своей стороной, не пары из дизайна | DOC-272613 п. 3.4; пары нигде не хранятся | ответ по п. 3 «пары нужны» — доработка раскрытия и контракта | | 28.10.2026 | «Учитывать в КФО» ставится на строке; у агрегата — производное «Да / Частично / Нет» | DOC-272613 (EXCLUDE на `osv_entry`) | ответ по п. 4 «на агрегат» — поменять флажок агрегата на действие | | 28.10.2026 | Действия со строками в окне корректировки идут на сервер сразу, статьи и комментарий — по «Сохранить» | разнесение и корректировка — разные записи (`vgo_assignment` / `correction`); аналитик видит новые суммы до ввода корректировки | отмена окна не откатывает перенос строк — аналитику нужно вернуть строку вручную | | 28.10.2026 | Сохранение сразу применяет (`APPLIED`), черновик не показываем | в дизайне одна кнопка | ответ по п. 9 «нужен черновик» — вторая кнопка | | 28.10.2026 | «Отменить корректировку» — в меню агрегата, с комментарием | `REVOKED` в аналитике есть, в дизайне нет места | ответ по п. 9 — перенести кнопку | | 28.10.2026 | Процент в окне — к меньшему, как в таблице | аналитика; в дизайне две формулы | — | | 28.10.2026 | Без корректировки окно предлагает суммы сторон целиком | так в дизайне; в аналитике подсказка не описана | ответ по п. 8 — поменять подсказку на min | | 28.10.2026 | Фильтр «Отклонение» — по `exceeds_threshold` (≥ 5 % / < 5 %), а не диапазон чисел | порог — главный вопрос аналитика; диапазон в дизайне не описан | доработка фильтра | | 28.10.2026 | «Итого» без процента | смысл процента по итогам не задан | добавить колонку | | 28.10.2026 | Фейк контракта под флагом `REACT_APP_CORRECTIONS_MOCK`, данные из дизайна | фронт не ждёт бэкенд; тот же код ходит в настоящий API | фейк расходится с бэкендом — ловится при подключении API и ревью AURORA-1540 | | 28.10.2026 | Только `statement_type = balance`, переключателя ББ/ОФР нет | в дизайне его нет; ОФР ждёт AURORA-1396 | добавить переключатель | | 28.10.2026 | Ключ черновика — пользователь + версия + агрегат; черновик без срока жизни, удаляется сохранением или «Отменить» | на общем компьютере у разных пользователей разные черновики | старые черновики копятся в `localStorage` — объём мал | | 28.10.2026 | План — только `web/`, бэкенду помогаем на ревью 1540; последняя задача — подключение к API и снятие флага | слова владельца «поможем ребятам на ревью» | если 1540 не успеет к 02.11, экран сдаётся на фейке | | 28.10.2026 | В контракт добавлен `candidate_rule_ids` у строки агрегата | иначе фронту пришлось бы сверять счета с правилами — это разнесение, анти-цель | правка контракта до начала 1540 — дёшево | | 28.10.2026 | `expected_version_no = null`, когда действующей корректировки нет (и после отзыва) | иначе после отзыва фронту неоткуда взять номер | — | | 28.10.2026 | Составная статья правил 1 и 2 — в окне первый код, можно выбрать второй | `line_code` — один код; особый расчёт правил 1 и 2 (DOC-274230) — на сервере | при ответе «нужно распределение по обеим» — аналитик добавляет вторую статью руками | | 28.10.2026 | «По пресету» показывает и подходящие нераспределённые строки; «Строка баланса» и «Отклонение» скрывают нераспределённые | пресет — рабочее место по правилу, строки для отнесения нужны рядом | поменять функцию фильтров | | 28.10.2026 | R-1: список правил в плане — ориентир; при расхождении с api/seed/core/elimination_rules_v1.yaml (в плане статья 1230/1510 встречается дважды) номера и статьи берутся из yaml, тесты плана про правила 1, 3, 6, 7 остаются верными | seed — источник истины | поправка mockData и тестов | | 28.10.2026 | R-2: в фейк добавлен `widgets/CorrectionTable/mockCalc.ts` (пересчёт агрегата и итогов через BigInt-копейки) — общий для `mockData` и `correctionsFake`, иначе циклический импорт | план не называл файл; без него циклический импорт | перенос функций, без поведения | | 28.10.2026 | R-3: в `mockData` сверх дизайна добавлены агрегат правила 6 «ООО "БСК"» — «ПМП ООО» (310000.00 / 300000.00) и агрегат правила 4 «Агро-Холдинг» без второй стороны (ONE_SIDED); `status` в фейке — ONE_SIDED / DISCREPANCY / AUTO, MANUAL не выдаётся | тест фильтра `ооо "бск"` из плана требует агрегат с таким ЮЛ; ONE_SIDED нужен для проверки отображения | поправка данных фейка, на прод не влияет | | 28.10.2026 | R-4: в окне корректировки сумма с пробелами («1 000 000,5») отклоняется с ошибкой «Сумма без пробелов», хотя `parseAmountInput` пробелы принимает | Review Focus плана прямо требует ошибку для этого ввода | если заказчик хочет пробелы — снять одну проверку в `validateLines` | | 28.10.2026 | R-5: `percentOfSmaller`, `toCents`, `fromCents` и порог 5 % (`THRESHOLD_PERCENT_HUNDREDTHS`) вынесены в `utils/money.ts`; `editorModel` и `mockCalc` импортируют оттуда, зависимости `editorModel` → `mockCalc` нет | фейк `mockCalc` вырезается при подключении API, экран не должен от него зависеть (ревью Task 3, T3.1) | поведение то же; тесты перенесены в `utils/money.test.ts` | | 28.10.2026 | R-6: тексты ошибок валидации окна и ключ ошибки `lines` для «Добавьте статью» выбраны исполнителем | бриф их не задаёт; тексты в spec не указаны | правка строк | | 28.10.2026 | R-7: флажки «Учитывать в КФО» и меню строк неактивны всегда (`actionsEnabled=false`) до Task 5–6, подсказка «только чтение» подключена | бриф Task 4: решения по строкам — в Task 5 | забыть включить флаг в Task 5 | | 28.10.2026 | R-8: ошибка загрузки показывается уведомлением с «Повторить» (по спеке) и кнопкой на месте таблицы | после закрытия уведомления аналитик не остаётся без выхода | две кнопки повтора | | 28.10.2026 | R-9: «Итого» показывается только при наличии видимых агрегатов (при «Нераспределенные записи» его нет) | сценарий спеки | показать «Итого» с пустыми значениями |