openspec: архив corrections-api-stage-one (AURORA-1540, PR #208)

Change остался неархивированным после слияния #208; все задачи выполнены.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-11-10 13:26:29 +04:00
parent 59ac0d1880
commit 773c9337a1
6 changed files with 97 additions and 0 deletions

View File

@ -0,0 +1,97 @@
# corrections-api Specification
## Purpose
Предоставляет backend-контракт для просмотра, сохранения и экспорта корректировок агрегатов бухгалтерского баланса, вычисленных сервисом разнесения ОСВ.
## Requirements
### Requirement: Чтение таблицы корректировок
Система SHALL вызывать сервис разнесения AURORA-1751 через `CorrectionAggregateSource` и возвращать его агрегаты ББ с компаниями, статьями, счетами, позициями, сопоставленными парами, суммами, отклонением и сохранённой корректировкой. GET MUST NOT записывать вычисленное разнесение, пары или корректировки в БД.
#### Scenario: Чтение доступной версии
- **WHEN** пользователь с правом просмотра запрашивает таблицу доступной версии
- **THEN** система возвращает вычисленные агрегаты, сопоставленные пары и оставшиеся позиции в стабильном порядке
- **THEN** в БД не создаются назначения или корректировки
#### Scenario: Сопоставленная пара
- **WHEN** сервис AURORA-1751 возвращает элемент в `matched` или `with_discrepancy`
- **THEN** агрегат содержит `pairs` с обеими сторонами этого элемента
- **THEN** каждая сторона пары содержит относящиеся к ней идентификаторы строк ОСВ, счета и сумму
- **THEN** суммы и отклонение пары совпадают с результатом AURORA-1751 без повторного сопоставления в сервисе корректировок
#### Scenario: Позиция без сопоставленной стороны
- **WHEN** ручная или односторонняя позиция агрегата не входит ни в одну вычисленную пару
- **THEN** она присутствует в соответствующей стороне агрегата без искусственно созданной встречной позиции
### Requirement: Расчёт отклонения и элиминации
Система SHALL считать абсолютное отклонение и процент к меньшей положительной сумме без предварительного округления. При отклонении не более 5 % справочная сумма элиминации SHALL равняться меньшей сумме; остаток SHALL относиться к большей статье.
#### Scenario: Отклонение не более пяти процентов
- **WHEN** меньшая сторона положительна и отклонение составляет ровно 5 % или меньше
- **THEN** сумма элиминации равна меньшей стороне
- **THEN** разница остаётся в большей статье
#### Scenario: Отклонение больше пяти процентов
- **WHEN** отклонение больше 5 %
- **THEN** агрегат помечается как требующий корректировки
#### Scenario: Нулевая меньшая сторона
- **WHEN** одна сторона равна нулю
- **THEN** процент отклонения равен `null`
- **THEN** агрегат считается односторонним
### Requirement: Сохранение корректировки агрегата
Система SHALL атомарно заменять корневые и дочерние строки корректировки существующего агрегата. Комментарий после trim MUST быть непустым при каждом сохранении. Успешное сохранение SHALL устанавливать статус `APPLIED`.
#### Scenario: Сохранение с комментарием
- **WHEN** аналитик сохраняет допустимые суммы и статьи обеих сторон с непустым комментарием
- **THEN** система полностью заменяет набор корректировки и возвращает `APPLIED`
- **THEN** создаётся аудит `CORRECTION_CREATE` или `CORRECTION_EDIT`
#### Scenario: Пустой комментарий
- **WHEN** аналитик сохраняет корректировку с пустым или состоящим из пробелов комментарием
- **THEN** система возвращает `COMMENT_REQUIRED`
- **THEN** ни одна строка корректировки не изменяется
#### Scenario: Ошибка одной дочерней строки
- **WHEN** одна из сумм или статей недопустима
- **THEN** весь запрос отклоняется без частичной записи
### Requirement: Конкурентное и статусное ограничение
Система MUST разрешать изменение только владельцу активной блокировки редактируемой версии. Клиент SHALL передавать ожидаемую редакцию существующей корректировки.
#### Scenario: Конфликт редакции
- **WHEN** ожидаемая редакция не совпадает с текущей
- **THEN** система возвращает `CORRECTION_VERSION_CONFLICT` без записи
#### Scenario: Верифицированная версия
- **WHEN** пользователь пытается сохранить корректировку после верификации версии
- **THEN** система отклоняет изменение
### Requirement: XLSX-экспорт корректировок
Система SHALL экспортировать таблицу одним листом XLSX. Строка агрегата SHALL сопровождаться следующими за ней раскрываемыми строками детализации; колонка правила у строки детализации SHALL быть пустой. Каждая сопоставленная пара SHALL занимать одну строку с одновременно заполненными колонками обеих компаний.
#### Scenario: Экспорт ББ
- **WHEN** пользователь экспортирует таблицу корректировок
- **THEN** файл называется `Корректировки_<название ГК>_<год>_<квартал>.xlsx`
- **THEN** книга содержит один лист с агрегатами, детализацией и итогами в рублях
- **THEN** позиции сопоставленной пары не дублируются отдельными строками под той же парой
- **THEN** ручные и односторонние позиции выводятся отдельными строками
- **THEN** система создаёт событие аудита `EXPORT`
### Requirement: Граница этапа
Система MUST NOT предоставлять в этом capability импорт XLSX, собственный алгоритм разнесения строк ОСВ, ручной перенос строк между правилами или операции изменения назначений. Вызов готового расчёта AURORA-1751 для чтения таблицы SHALL считаться интеграцией с источником, а не реализацией разнесения в capability корректировок.
#### Scenario: Контракт этапа
- **WHEN** публикуется OpenAPI этапа корректировок
- **THEN** в нём отсутствуют операции импорта и назначения строк правилам
### Requirement: Инвалидация корректировки при ручном назначении
После успешного ASSIGN/UNASSIGN система SHALL определять затронутые пары компаний непосредственно по `entry_ids` в
`osv_entry` и переводить все их `APPLIED`-корректировки в `DRAFT`. Суммы, статьи и комментарий SHALL сохраняться.
Операция MUST NOT выполнять полный расчёт `assignment_candidates`; статус `REVOKED` на этом этапе не устанавливается.
#### Scenario: Изменено назначение строки пары компаний
- **WHEN** аналитик назначает строку правилу или снимает назначение
- **THEN** все `APPLIED`-корректировки этой пары компаний получают `DRAFT`
- **THEN** корректировки других пар и уже находящиеся в `DRAFT` не изменяются