- AURORA-1702: таблица в порядке файла — счёт, субсчёт и подразделение с вложенными строками выводятся строками-группами (жирным, со своими сальдо и оборотами), вложенные — с отступом по уровню; фильтр по счёту оставляет счёт и все его субсчета, при поиске строки-группы скрываются. - AURORA-1703: строки-показатели («Кол.», «НУ», «Вал.», «ПР»/«ВР»: OTHER, вид не BU/SUM и не равен виду родителя) в рублёвую таблицу не попадают и родителя группой не делают — строка БУ снова видна с наименованием и рублями. В EntryOut добавлен data_type (ядро его уже отдаёт). - filterRows перенесён в osvRows.ts (чистая функция с тестами); спека document-review-ui обновлена. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
186 lines
21 KiB
Markdown
186 lines
21 KiB
Markdown
# document-review-ui Specification
|
||
|
||
## Purpose
|
||
Аналитик проверяет распознанный документ и подтверждает его: форма ББ/ОФР рядом со сканом PDF (правка значений и шапки, проверки и их акцепт) [41]/[41-02], ОСВ-документ — таблицей строк в порядке файла (как в 1С) только для чтения.
|
||
|
||
## Requirements
|
||
|
||
### Requirement: Экран документа
|
||
Маршрут `/documents/:document_id` SHALL загрузить `GET /documents/{id}` и показать вид по `document_type`: `BALANCE` и
|
||
`INCOME` — проверка формы, `OSV` — просмотр ОСВ; для прочих типов — карточку документа без данных. Шапка экрана SHALL
|
||
показывать тип, ЮЛ-владельца, период и статус документа, кнопку «Назад».
|
||
|
||
#### Scenario: Открытие формы баланса
|
||
- **WHEN** аналитик открывает документ `BALANCE`
|
||
- **THEN** показан экран проверки формы
|
||
|
||
### Requirement: Скан рядом с формой
|
||
Для ББ/ОФР экран SHALL показывать исходный файл документа: PDF — постранично через pdf.js из байт
|
||
`GET /files/{file_id}/content?disposition=inline`, полученных клиентом API с токеном (не через `<iframe>` и не прямой
|
||
ссылкой); изображение (png/jpg) — тегом `<img>` из blob; xlsx — без превью, с кнопкой «Скачать исходник».
|
||
|
||
#### Scenario: PDF под CSP sandbox
|
||
- **WHEN** сервер отдаёт PDF с `Content-Security-Policy: sandbox`
|
||
- **THEN** страницы PDF отрисованы на canvas и листаются
|
||
|
||
### Requirement: Форма ББ/ОФР — просмотр и правка
|
||
Экран SHALL показывать `GET /documents/{id}/statement`: шапку (ИНН, дата отчёта, единицы — значение и исходное при
|
||
правке; наименование, ОКУД/ОКПО) и таблицу «строка (код, наименование) × колонки» с суммами из `values[]`, включая
|
||
строки и ячейки, достроенные сервером по справочнику редакции (`id = null`). Ячейки с `needs_review = true` SHALL
|
||
подсвечиваться как «требует внимания» (подсветки напрямую по `confidence < 100` или `is_recognized = false` нет), с
|
||
`is_modified = true` — как «исправлено» с исходным значением `original_amount` в подсказке; пустая достроенная ячейка не
|
||
подсвечивается. Строки «БАЛАНС» формы `BALANCE` (коды 1600 и 1700) SHALL выделяться фоном `#f9f0ff` и жирным шрифтом;
|
||
подсветка ячейки перекрывает фон строки. Единицы (`header.units`) SHALL выводиться над таблицей. Пока документ не
|
||
`CONFIRMED`, ячейка SHALL быть редактируемой: ввод проверяется по формату суммы (до 2 знаков после точки, знак минус
|
||
допустим, пустое — `null`), сохранение отправляет `PATCH /documents/{id}/statement {values: [...]}` суммой-строкой:
|
||
ячейка строки из БД — `{line_id, column_id, amount}`, ячейка достроенной строки (`id = null`) — `{line_code,
|
||
column_id, amount}`; ответ заменяет состояние экрана. Правка шапки (ИНН, дата отчёта, единицы, наименование
|
||
организации) SHALL отправляться тем же `PATCH` в `header`; `inn: null` не отправляется. Правка строк, колонок и
|
||
подтверждений в том же `PATCH` (`columns`, `lines`, `values[].confirmed`) описана в требовании «Правка строк, колонок и
|
||
подтверждение в режиме «Редактировать»».
|
||
|
||
#### Scenario: Исправление ячейки
|
||
- **WHEN** аналитик меняет значение ячейки и сохраняет
|
||
- **THEN** ячейка помечена «исправлено», проверки пересчитаны по ответу сервера, акцепт снят
|
||
|
||
#### Scenario: Заполнение строки, которой не было в распознавании
|
||
- **WHEN** у формы нет строки 1700 из источника, аналитик вводит сумму в достроенную строку 1700 и сохраняет
|
||
- **THEN** уходит `{line_code: "1700", column_id, amount}`, по ответу строка получила `id`, ячейка помечена «исправлено»
|
||
|
||
#### Scenario: Строки «БАЛАНС»
|
||
- **WHEN** открыта форма `BALANCE`
|
||
- **THEN** строки 1600 и 1700 выделены цветом и жирным, у ОФР выделения нет
|
||
|
||
#### Scenario: Неверный формат суммы
|
||
- **WHEN** аналитик вводит «12,3,4»
|
||
- **THEN** запрос не отправляется, поле показывает ошибку формата
|
||
|
||
### Requirement: Проверки и их акцепт
|
||
Экран SHALL показывать `checks`: жёсткие (`failed`), мягкие (`soft_failed`), межформенную (`cross_form`) и акцепт
|
||
(`accepted`: кто, когда, комментарий). При непустом `failed` и `accepted = null` SHALL быть доступно «Принять с
|
||
комментарием»: комментарий 1–2000 символов → `POST /documents/{id}/statement/checks/accept {comment}`.
|
||
|
||
#### Scenario: Акцепт нарушений
|
||
- **WHEN** есть жёсткие нарушения и аналитик принимает их с комментарием
|
||
- **THEN** блок проверок показывает акцепт, нарушения остаются видимыми
|
||
|
||
### Requirement: Подтверждение документа
|
||
Кнопка «Подтвердить данные» SHALL отправлять `POST /documents/{id}/confirm` и быть недоступна для `CONFIRMED` и `ERROR`, а
|
||
также при наличии строк `unreadable` / `missing` с суммой или нераспознанным текстом в ячейках (подсказка «Разберите
|
||
строки без кода: N» с переходом к первой такой строке). При 409 `CHECKS_NOT_PASSED` экран SHALL показать
|
||
`detail.failures[]` и предложить акцепт; при 409 `PERIOD_REQUIRED` — подсказать исправить дату отчёта; при 409
|
||
`LINES_UNRESOLVED` — показать тот же текст, что у отключённой кнопки; при 409 `DUPLICATE_FORM` — со ссылкой на
|
||
подтверждённую форму; прочие ошибки — `message`. После успеха экран SHALL перейти в режим только чтения.
|
||
|
||
#### Scenario: Подтверждение с неакцептованными нарушениями
|
||
- **WHEN** аналитик подтверждает форму с жёсткими нарушениями без акцепта
|
||
- **THEN** показан список нарушений из ответа и кнопка «Принять с комментарием»
|
||
|
||
#### Scenario: Дубль подтверждённой формы
|
||
- **WHEN** сервер отвечает 409 `DUPLICATE_FORM`
|
||
- **THEN** экран показывает ошибку со ссылкой на уже подтверждённую форму
|
||
|
||
### Requirement: ОСВ-документ
|
||
Для `OSV` экран SHALL показывать строки `GET /documents/{id}/entries` (все страницы, `limit` ≤ 2000) таблицей в порядке
|
||
файла, как в 1С (AURORA-1702): строки счёта, субсчетов и подразделений, у которых есть вложенные строки, — строки-группы
|
||
(жирным, со своими сальдо и оборотами), вложенные строки — с отступом по уровню в колонке аналитики. Договоры отдельными
|
||
строками не идут — их сумма в строке контрагента; субсчёт или подразделение без вложенных строк и без сумм не выводится.
|
||
Строки-показатели колонки «Показатели» и строки «Кол.», «Вал.» (§1.3 правил предметной области: `group_type = OTHER`,
|
||
`data_type` не BU/SUM и не равен виду родителя — NU, QUANTITY, CURRENCY или пусто у «ПР»/«ВР») в рублёвую таблицу
|
||
SHALL NOT попадать и родителя группой не делают: строка БУ остаётся строкой с наименованием и суммами в рублях
|
||
(AURORA-1703). Колонки: субсчёт, подразделение (если в файле есть этот уровень), аналитика (у строки счёта — её текст),
|
||
ИНН (если есть контрагенты), сальдо на начало Дт/Кт, обороты Дт/Кт, сальдо на конец Дт/Кт (суммы — строками с
|
||
разделителями разрядов, рубли), только чтение. Фильтр по счёту оставляет счёт и все его субсчета («62» — 62, 62.01,
|
||
62.02), при поиске по аналитике или ИНН строки-группы скрываются. Кнопка «Подтвердить» — как для форм.
|
||
Заголовок колонки аналитики SHALL зависеть от вида строк-листьев (структурные строки субсчёта и подразделения,
|
||
строки-группы и строки-показатели не учитываются, договоры строками не идут): только `COUNTERPARTY` — «Контрагент»; один другой вид — его `group_name`
|
||
(«Основные средства»); смесь видов или вид без `group_name` — «Аналитика», а перечень видов — во всплывающей подсказке
|
||
заголовка. Колонка «ИНН» и подсказка поиска «Контрагент или ИНН» SHALL показываться только при наличии контрагентов
|
||
(`COUNTERPARTY`); иначе колонки ИНН нет, а поиск подписан «Поиск по аналитике».
|
||
|
||
#### Scenario: ОСВ по основным средствам
|
||
- **WHEN** листья документа — аналитика с `group_name` «Основные средства», контрагентов нет
|
||
- **THEN** колонка называется «Основные средства», колонки ИНН нет, поиск подписан «Поиск по аналитике»
|
||
|
||
#### Scenario: Строки счёта и субсчетов
|
||
- **WHEN** аналитик открывает ОСВ по счёту 62 с субсчетами 62.01 и 62.02 и контрагентами под ними
|
||
- **THEN** в таблице жирным видны строки 62, 62.01, 62.02 с их сальдо и оборотами, контрагенты — под своим субсчётом с отступом
|
||
|
||
#### Scenario: ОСВ с колонкой «Показатели»
|
||
- **WHEN** у позиции номенклатуры счёта 41 в файле строки «БУ» и «Кол.»
|
||
- **THEN** в таблице строка позиции с наименованием и суммами в рублях, строки «Кол.» нет
|
||
|
||
#### Scenario: Подтверждение ОСВ
|
||
- **WHEN** аналитик подтверждает ОСВ-документ `NEEDS_CHECK`
|
||
- **THEN** документ становится «Загружен», версия, к которой он подходит, переходит в `DATA_CORRECTION`
|
||
|
||
### Requirement: Виртуализация таблицы ОСВ-документа
|
||
Таблица строк ОСВ-документа SHALL быть виртуализирована: в DOM находятся только видимые строки, остальные не
|
||
отрисовываются. Строки по-прежнему загружаются целиком, поиск по аналитике (и ИНН) и фильтр по счёту — клиентские;
|
||
серверной пагинации нет. Высота области прокрутки считается числом по высоте окна и пересчитывается при его изменении.
|
||
Строка «Итого по документу» закреплена внизу и выровнена по колонкам, двухъярусная шапка и колонка «Субсчёт»
|
||
закреплены, горизонтальная прокрутка сохраняется. ОСВ любого размера (десятки тысяч строк) SHALL открываться без
|
||
падения вкладки.
|
||
|
||
#### Scenario: Большая ОСВ
|
||
- **WHEN** аналитик открывает ОСВ-документ на ~29 000 строк
|
||
- **THEN** документ открывается, число строк в DOM не зависит от размера документа, прокрутка до конца, поиск и фильтр по субсчёту работают, «Итого по документу» совпадает с суммой по всему документу
|
||
|
||
### Requirement: Раскладка строк формы со статусами
|
||
Экран проверки формы ББ/ОФР ([41]) SHALL сохранять раскладку «как на бумаге» (Р-14): разделы, внутри — строки `ok` по
|
||
возрастанию кода, несколько строк одного кода — в порядке файла (`row_index`), шаблонные строки на своих местах,
|
||
пятизначные подстроки под родителем. Строка `unreadable` / `missing` SHALL стоять под ближайшей предыдущей по
|
||
`row_index` строкой, размещённой по коду, а без такой — в начале первого раздела; она подсвечена целиком, в ячейке
|
||
кода серым — сырой текст `line_code_text` с подсказкой. Строки `detail` SHALL быть скрыты под переключателем
|
||
«Показать расшифровки (N)» и показываться под родителем (`parent_row_index`) с отступом. Экран показывает справочное
|
||
имя строки (`reference_name`), файловое (`line_name`) — рядом, если отличается. Переключателя «как в файле» нет.
|
||
|
||
#### Scenario: Код-мусор на своём месте
|
||
- **WHEN** строка `unreadable` «ИЧ,250» в файле стоит после строки 1240
|
||
- **THEN** на экране она стоит сразу под 1240, подсвечена, в ячейке кода серым «ИЧ,250»
|
||
|
||
#### Scenario: Расшифровки скрыты
|
||
- **WHEN** у формы три строки `detail`
|
||
- **THEN** по умолчанию их не видно, переключатель «Показать расшифровки (3)»; включённый показывает их под родителями
|
||
|
||
### Requirement: Подсветка и предупреждения у места
|
||
Экран SHALL подсвечивать ячейки только по `needs_review` (в подсказке — `text` и уверенность), строки — по
|
||
`needs_review` строки, поля шапки — по `needs_review_fields` (в подсказке у поля — `header.source.<поле>`: сырой текст и
|
||
уверенность). Предупреждения и нарушения (`issues`, `checks`) SHALL показываться у места: у строк (`line_ids`), ячеек
|
||
(`line_ids` + `column_id`), полей шапки (`field`) или у документа (в том числе запись с `column_index` без `column_id` —
|
||
столбец вне колонок формы); уровень `error` отличается от `info`. Подсветки по `confidence < 100` и `is_recognized =
|
||
false` напрямую нет. У значений строк `detail` `needs_review` всегда `false` (Р-23): при показанных расшифровках их
|
||
сомнительные ячейки не подсвечиваются, но подсказка с `text` и уверенностью есть.
|
||
|
||
#### Scenario: Догадка подтверждена проверкой
|
||
- **WHEN** значение `is_recognized = false`, `needs_review = false`
|
||
- **THEN** ячейка не подсвечена; в подсказке сырой текст и уверенность
|
||
|
||
### Requirement: Правка строк, колонок и подтверждение в режиме «Редактировать»
|
||
В режиме «Редактировать» экран SHALL давать: у `unreadable` / `missing` — поле ввода кода с подсказкой из справочника
|
||
(код → справочное имя) и пункт меню строки «Это расшифровка»; у `detail` — «Назначить код»; у строки `ok` — «Сделать
|
||
расшифровкой», смену кода и «Подтвердить код» у строки с `needs_review`; подтверждение ячейки без правки; ввод даты у
|
||
колонки без даты (`period_kind = none`) или с предупреждением о дате (в том числе подтверждение той же даты); снятие подтверждения ячейки и кода (`confirmed:
|
||
false`); правка наименования организации в шапке; подтверждение даты отчёта из `needs_review_fields` без изменения (тем
|
||
же значением). «Сохранить» отправляет один `PATCH …/statement` (`header`, `values`, `columns`, `lines`). Кнопка «Подтвердить данные» при строках `unreadable` / `missing` с суммами
|
||
SHALL быть отключена с подсказкой «Разберите строки без кода: N» и переходом к первой такой строке; ответ сервера 409
|
||
`LINES_UNRESOLVED` показывается тем же текстом, 409 `DUPLICATE_FORM` — со ссылкой на подтверждённую форму, 409
|
||
`LINE_CODE_TAKEN` — у поля кода. Кнопка «Подтвердить данные» учитывает строки `unreadable` / `missing` с суммой или
|
||
нераспознанным текстом в ячейках.
|
||
|
||
#### Scenario: Назначить код
|
||
- **WHEN** аналитик вводит 1250 в ячейку кода строки `unreadable` и сохраняет
|
||
- **THEN** уходит `PATCH` с `lines: [{line_id, line_code: "1250"}]`; после ответа строка встаёт на место 1250
|
||
|
||
#### Scenario: Подтверждение заблокировано
|
||
- **WHEN** у формы две строки `missing` с суммами
|
||
- **THEN** «Подтвердить данные» отключена, подсказка «Разберите строки без кода: 2», клик по подсказке ведёт к первой
|
||
|
||
### Requirement: Предупреждения ОСВ-документа
|
||
Экран ОСВ-документа SHALL показывать предупреждения документа из `DocumentOut.issues[]` (коды `OSV_*`) блоком над
|
||
таблицей; все записи относятся к документу (строки ОСВ `line_ids` не адресуются); уровень `error` отличается от `info`.
|
||
|
||
#### Scenario: Предупреждение листа ОСВ
|
||
- **WHEN** у ОСВ-документа в `issues` есть запись с кодом `OSV_*`
|
||
- **THEN** над таблицей показан блок предупреждений с текстом записи и уровнем
|