- ИНН-ячейка строк без сопоставления подсвечена, ссылка «Указать» рядом с ИНН из файла [32-osv-no-inn].
- Модалка «Выбор организации для связи с …» [32-osv-map-counterparty]: поиск с паузой 300 мс,
scope group / весь справочник (от 3 символов), блок «Рекомендуемые», «Связать».
- POST …/osv/entries/{последняя entry_id}/counterparty; 409 ALIAS_TAKEN → перенос алиаса (move_alias),
LOCK_REQUIRED → «Взять версию в работу?» → POST …/lock → повтор, LOCKED_BY_OTHER → имя держателя.
- После успеха перечитываются строки и сводка («Осталось N»).
- Чистые функции counterpartyMapping.ts + тесты; спека consolidated-osv-ui.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
73 lines
7.5 KiB
Markdown
73 lines
7.5 KiB
Markdown
# consolidated-osv-ui Specification
|
||
|
||
## Purpose
|
||
Аналитик видит сводную ОСВ версии [30]: сводку с несопоставленными строками, пробелы по кварталам, таблицу с фильтрами в заголовках колонок и экспорт в xlsx; сопоставляет контрагента строки с ЮЛ справочника [32].
|
||
|
||
## Requirements
|
||
|
||
### Requirement: Сводка версии
|
||
Экран «Сводная ОСВ» [30] SHALL показывать шапку версии (ГК, период, номер, статус) и сводку
|
||
`GET /consolidations/versions/{id}/osv/summary`: строк всего, документов, несопоставленных (`unmapped_total` — счётчик
|
||
«Осталось N»; сопоставление — «Указать» в строке), автоматически сопоставленных.
|
||
|
||
#### Scenario: Контрольные цифры РБ 2024 Q3
|
||
- **WHEN** открыт свод версии РБ 2024 Q3 после подтверждения 22 ОСВ из `fixtures/osv/{rb,schastl}/2024-Q{1,2,3}`
|
||
- **THEN** «строк» = 1385, «документов» = 22, «несопоставленных» = 1381
|
||
|
||
### Requirement: Таблица свода и фильтры
|
||
Экран SHALL показывать строки `GET /consolidations/versions/{id}/osv` постранично (размер страницы ≤ 2000): ЮЛ, счёт,
|
||
контрагент, ИНН контрагента, сальдо на начало Дт/Кт, обороты Дт/Кт, сальдо на конец Дт/Кт (суммы — строками с
|
||
разделителями разрядов) и последней колонкой «Тип контрагента» — бейдж ГСК (синий) / ГК (зелёный) / Внешний (серый), как
|
||
в макете [30]. Фильтры — в заголовках колонок: ЮЛ (`legal_entity_id`), корень счёта (`account_root`), поиск по
|
||
контрагенту (`q`, ≤ 500 символов), тип контрагента (`counterparty_type`, одно значение — на колонке «Тип контрагента»);
|
||
только несопоставленные (`unmapped`) — кнопкой над таблицей. «Применить» и «Сбросить» SHALL закрывать окно фильтра.
|
||
Смена фильтра SHALL перечитывать первую страницу.
|
||
|
||
#### Scenario: Строка из контрольных цифр
|
||
- **WHEN** фильтр ЮЛ «Пекарня Счастливочная» и поиск «бисквит»
|
||
- **THEN** строка `60.01` показывает сальдо нач. Кт 4 454 151.93, обороты Дт 128 058 143.65, Кт 125 950 450.77,
|
||
сальдо кон. Кт 2 346 459.05, признак «ГСК»
|
||
|
||
### Requirement: Ручное сопоставление контрагента
|
||
У строки без сопоставленного ЮЛ (`counterparty_id = null`) ячейка ИНН SHALL быть подсвечена и содержать ссылку
|
||
«Указать» (рядом с ИНН из файла, если он есть), как в макете [32-osv-no-inn]. «Указать» SHALL открывать модалку
|
||
«Выбор организации для связи с <имя контрагента из файла>» [32-osv-map-counterparty]: поиск, таблица ИНН / Организация /
|
||
ГК / ГСК / ГСЗ / «Связать», рекомендуемые (`recommended`) — первыми под заголовком «Рекомендуемые» с зелёной подсветкой.
|
||
Кандидаты — `GET …/counterparty-candidates?scope=&entry_id=&q=` с паузой 300 мс после ввода: по умолчанию `scope=group`
|
||
(периметр и ГК); галочка «Искать во всём справочнике» — `scope=all`, при поиске короче 3 символов запрос не отправляется
|
||
и показывается подсказка.
|
||
«Связать» SHALL отправлять `POST …/osv/entries/{entry_ids.at(-1)}/counterparty {legal_entity_id}`, после успеха —
|
||
сообщение (с кем связано, сколько записей ОСВ сопоставлено автоприменением, создан или перенесён алиас), закрывать
|
||
модалку и перечитывать страницу свода и сводку («Осталось N» на клиенте не вычисляется). Ответы 409:
|
||
- `ALIAS_TAKEN` — подтверждение «Имя уже закреплено за <владельцы>. Перенести?» → повтор с `move_alias = true`;
|
||
- `LOCK_REQUIRED` — подтверждение «Взять версию в работу?» → `POST …/lock` → повтор; отказ — ничего не меняется;
|
||
- `LOCKED_BY_OTHER` (от правки или от `POST …/lock`) — «Версию держит <имя>» (имя — из ответа `POST …/lock` или из
|
||
`lock` карточки версии), без перехвата;
|
||
- `VERSION_NOT_EDITABLE` и прочие ошибки — текстом сервера.
|
||
|
||
#### Scenario: Сопоставление «Пекарня Счастливочная ООО» в ОСВ РБ
|
||
- **WHEN** в своде РБ 2024 Q3 у строки контрагента «Пекарня Счастливочная ООО» без сопоставления нажато «Указать» и у
|
||
рекомендуемой «Пекарни Счастливочной» — «Связать» (версия не взята в работу → «Взять в работу»)
|
||
- **THEN** строка показывает ЮЛ и тип «ГСК», «Осталось N» уменьшается на число сопоставленных строк, у ЮЛ появляется алиас
|
||
|
||
#### Scenario: Алиас занят
|
||
- **WHEN** имя строки уже алиас другого ЮЛ и аналитик выбирает третье ЮЛ
|
||
- **THEN** показан вопрос о переносе с именами владельцев; «Перенести» повторяет запрос с `move_alias = true`
|
||
|
||
### Requirement: Пробелы
|
||
Экран SHALL показывать `gaps[]` сводки списком «ЮЛ — счёт — недостающие кварталы» с пояснением, что строки этих пар в
|
||
своде отсутствуют.
|
||
|
||
#### Scenario: Пробелы РБ 2024 Q3
|
||
- **WHEN** открыт свод версии РБ 2024 Q3
|
||
- **THEN** показано 7 пробелов, у каждого недостающие кварталы «Q1, Q2»
|
||
|
||
### Requirement: Экспорт
|
||
Кнопка «Скачать xlsx» SHALL получать `GET /consolidations/versions/{id}/osv/export` с текущими фильтрами через клиент API
|
||
с токеном и сохранять файл; имя — из `Content-Disposition`, а если заголовок недоступен —
|
||
`Сводная_ОСВ_<ГК>_<год>_<квартал>.xlsx`.
|
||
|
||
#### Scenario: Экспорт с фильтром
|
||
- **WHEN** аналитик скачивает свод с фильтром по ЮЛ
|
||
- **THEN** сохраняется xlsx, а ошибка сервера показывается текстом, а не скачивается
|