Andrey Epifancev b861646a86 Merge branch 'test' into feat/38-osv-virtual-table
Слияние с #39 (PR #40): scroll.x считается от фактических колонок, scroll.y — числом
для virtual. Колонки сумм расширены до 160 px: итоги из 17 цифр («Итого по документу»)
переносились на две строки и обрезались внизу таблицы (O-3). Спека: поиск — по аналитике.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 14:46:10 +04:00

11 KiB
Raw Blame History

document-review-ui Specification

Purpose

Аналитик проверяет распознанный документ и подтверждает его: форма ББ/ОФР рядом со сканом PDF (правка значений и шапки, проверки и их акцепт) [41]/[41-02], ОСВ-документ — плоской таблицей строк только для чтения.

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). Ячейки с confidence < 100 или is_recognized = false SHALL подсвечиваться как «требует внимания», с 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 не отправляется.

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. При 409 CHECKS_NOT_PASSED экран SHALL показать detail.failures[] и предложить акцепт; при 409 PERIOD_REQUIRED — подсказать исправить дату отчёта; прочие ошибки — message. После успеха экран SHALL перейти в режим только чтения.

Scenario: Подтверждение с неакцептованными нарушениями

  • WHEN аналитик подтверждает форму с жёсткими нарушениями без акцепта
  • THEN показан список нарушений из ответа и кнопка «Принять с комментарием»

Requirement: ОСВ-документ

Для OSV экран SHALL показывать строки GET /documents/{id}/entries (все страницы, limit ≤ 2000) плоской таблицей строк нижнего уровня (договоры отдельными строками не идут — их сумма в строке контрагента) с колонками: субсчёт, подразделение (если в файле есть этот уровень), аналитика, ИНН (если есть контрагенты), сальдо на начало Дт/Кт, обороты Дт/Кт, сальдо на конец Дт/Кт (суммы — строками с разделителями разрядов, рубли), только чтение. Кнопка «Подтвердить» — как для форм. Заголовок колонки аналитики SHALL зависеть от вида строк-листьев (структурные строки субсчёта и подразделения не учитываются, договоры строками не идут): только COUNTERPARTY — «Контрагент»; один другой вид — его group_name («Основные средства»); смесь видов или вид без group_name — «Аналитика», а перечень видов — во всплывающей подсказке заголовка. Колонка «ИНН» и подсказка поиска «Контрагент или ИНН» SHALL показываться только при наличии контрагентов (COUNTERPARTY); иначе колонки ИНН нет, а поиск подписан «Поиск по аналитике».

Scenario: ОСВ по основным средствам

  • WHEN листья документа — аналитика с group_name «Основные средства», контрагентов нет
  • THEN колонка называется «Основные средства», колонки ИНН нет, поиск подписан «Поиск по аналитике»

Scenario: Подтверждение ОСВ

  • WHEN аналитик подтверждает ОСВ-документ NEEDS_CHECK
  • THEN документ становится «Загружен», версия, к которой он подходит, переходит в DATA_CORRECTION

Requirement: Виртуализация таблицы ОСВ-документа

Таблица строк ОСВ-документа SHALL быть виртуализирована: в DOM находятся только видимые строки, остальные не отрисовываются. Строки по-прежнему загружаются целиком, поиск по аналитике (и ИНН) и фильтр по субсчёту — клиентские; серверной пагинации нет. Высота области прокрутки считается числом по высоте окна и пересчитывается при его изменении. Строка «Итого по документу» закреплена внизу и выровнена по колонкам, двухъярусная шапка и колонка «Субсчёт» закреплены, горизонтальная прокрутка сохраняется. ОСВ любого размера (десятки тысяч строк) SHALL открываться без падения вкладки.

Scenario: Большая ОСВ

  • WHEN аналитик открывает ОСВ-документ на ~29 000 строк
  • THEN документ открывается, число строк в DOM не зависит от размера документа, прокрутка до конца, поиск и фильтр по субсчёту работают, «Итого по документу» совпадает с суммой по всему документу