arm-ka-docs/dev/api-contract-corrections.openapi.yaml
Andrey Epifancev 735e6fb187 Контракт API таблицы корректировок (#183)
Markdown и OpenAPI для AURORA-1540 (бэкенд) и AURORA-1541 (фронт):
таблица агрегатов и нераспределённых строк, сохранение и отзыв
корректировки агрегата, решения по строке (vgo_assignment), экспорт.
Основа — аналитика Лысенко (DOC-272613, ответы 1–7, DOC-274230)
и дизайн 23.10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 20:47:50 +04:00

450 lines
19 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

openapi: 3.1.0
info:
title: АРМ КА — таблица корректировок
version: 0.1.0-draft
description: >
Черновик контракта AURORA-1540 (бэкенд) / AURORA-1541 (фронт). Текстовое описание, источники и открытые вопросы —
dev/api-contract-corrections.md; оба файла держатся одинаковыми. Деньги — строки с двумя знаками в рублях, проценты —
строки с двумя знаками. Чтение — CONSOLIDATION_VIEW, правки — CONSOLIDATION_EDIT.
servers:
- url: /api/v1
security:
- bearerAuth: []
paths:
/consolidations/versions/{version_id}/corrections:
get:
operationId: getCorrectionTable
summary: Таблица корректировок версии
x-permission: CONSOLIDATION_VIEW
parameters:
- $ref: '#/components/parameters/VersionId'
- $ref: '#/components/parameters/StatementTypeQuery'
responses:
'200':
description: Агрегаты со строками, нераспределённые строки, итоги
content:
application/json:
schema: { $ref: '#/components/schemas/CorrectionTableOut' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/DomainError' }
/consolidations/versions/{version_id}/corrections/aggregates/{rule_id}/{company_1_id}/{company_2_id}:
put:
operationId: saveCorrection
summary: Сохранить корректировку агрегата (создать или заменить целиком)
description: >
Аудит CORRECTION_CREATE (первая) / CORRECTION_EDIT; version_no++; результат КФО устаревает.
Ошибки 409 — VERSION_NOT_EDITABLE, LOCK_REQUIRED, LOCKED_BY_OTHER, CORRECTION_VERSION_CONFLICT;
422 — COMMENT_REQUIRED, EMPTY_CORRECTION, INVALID_LINE_CODE (detail.line_code).
x-permission: CONSOLIDATION_EDIT
parameters:
- $ref: '#/components/parameters/VersionId'
- $ref: '#/components/parameters/RuleId'
- $ref: '#/components/parameters/Company1Id'
- $ref: '#/components/parameters/Company2Id'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/CorrectionIn' }
responses:
'200':
description: Пересчитанный агрегат
content:
application/json:
schema: { $ref: '#/components/schemas/CorrectionAggregateOut' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/DomainError' }
'409': { $ref: '#/components/responses/DomainError' }
'422': { $ref: '#/components/responses/DomainOrValidationError' }
/consolidations/versions/{version_id}/corrections/aggregates/{rule_id}/{company_1_id}/{company_2_id}/revoke:
post:
operationId: revokeCorrection
summary: Отозвать действующую корректировку агрегата
description: >
Статус REVOKED, запись остаётся в истории; аудит CORRECTION_REVOKE.
409 — правки версии, CORRECTION_NOT_APPLIED; 422 — COMMENT_REQUIRED.
x-permission: CONSOLIDATION_EDIT
parameters:
- $ref: '#/components/parameters/VersionId'
- $ref: '#/components/parameters/RuleId'
- $ref: '#/components/parameters/Company1Id'
- $ref: '#/components/parameters/Company2Id'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/CorrectionRevokeIn' }
responses:
'200':
description: Пересчитанный агрегат
content:
application/json:
schema: { $ref: '#/components/schemas/CorrectionAggregateOut' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/DomainError' }
'409': { $ref: '#/components/responses/DomainError' }
'422': { $ref: '#/components/responses/DomainOrValidationError' }
/consolidations/versions/{version_id}/corrections/allocations:
post:
operationId: allocateEntry
summary: Решение по строке сводной ОСВ (vgo_assignment)
description: >
ASSIGN — отнести/перенести в правило; UNASSIGN — убрать из агрегата; EXCLUDE / INCLUDE — «Не включать в КФО» и снятие;
RESET — вернуть к автоматике. 409 — правки версии; 422 — ENTRY_NOT_IN_VERSION, RULE_NOT_APPLICABLE (detail.reason),
RULE_REQUIRED. Ответ — вся таблица.
x-permission: CONSOLIDATION_EDIT
parameters:
- $ref: '#/components/parameters/VersionId'
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/AllocationIn' }
responses:
'200':
description: Пересчитанная таблица
content:
application/json:
schema: { $ref: '#/components/schemas/CorrectionTableOut' }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/DomainError' }
'409': { $ref: '#/components/responses/DomainError' }
'422': { $ref: '#/components/responses/DomainOrValidationError' }
/consolidations/versions/{version_id}/corrections/export:
get:
operationId: exportCorrectionTable
summary: Выгрузка таблицы корректировок в xlsx
description: Аудит EXPORT.
x-permission: CONSOLIDATION_VIEW
parameters:
- $ref: '#/components/parameters/VersionId'
- $ref: '#/components/parameters/StatementTypeQuery'
responses:
'200':
description: Файл xlsx
content:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
schema: { type: string, format: binary }
'401': { $ref: '#/components/responses/Unauthorized' }
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/DomainError' }
components:
securitySchemes:
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
parameters:
VersionId:
name: version_id
in: path
required: true
schema: { type: string, format: uuid }
RuleId:
name: rule_id
in: path
required: true
schema: { type: string, format: uuid }
Company1Id:
name: company_1_id
in: path
required: true
description: Компания стороны 1 правила (дебетовая сторона агрегата)
schema: { type: string, format: uuid }
Company2Id:
name: company_2_id
in: path
required: true
description: Компания стороны 2 правила (кредитовая сторона агрегата)
schema: { type: string, format: uuid }
StatementTypeQuery:
name: statement_type
in: query
required: false
schema: { $ref: '#/components/schemas/StatementType' }
responses:
Unauthorized:
description: Нет или плохой токен
Forbidden:
description: Нет права
content:
application/json:
schema:
type: object
properties: { detail: { type: string } }
DomainError:
description: Доменная ошибка
content:
application/json:
schema: { $ref: '#/components/schemas/DomainErrorOut' }
DomainOrValidationError:
description: Доменная ошибка или массив ошибок валидации pydantic
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/DomainErrorOut'
- type: object
properties:
detail:
type: array
items:
type: object
properties:
loc: { type: array, items: {} }
msg: { type: string }
type: { type: string }
schemas:
Money:
type: string
pattern: '^-?\d+\.\d{2}$'
description: Сумма в рублях, два знака
examples: ['1000000.00']
MoneyIn:
type: string
pattern: '^\d+(\.\d{1,2})?$'
description: Неотрицательная сумма в рублях, не более двух знаков
Percent:
type: [string, 'null']
pattern: '^\d+\.\d{2}$'
description: Процент с двумя знаками; null — не определён
StatementType:
type: string
enum: [balance, income]
default: balance
Side:
type: string
enum: [D, K]
Ref:
type: object
required: [id, name]
properties:
id: { type: string, format: uuid }
name: { type: string }
DomainErrorOut:
type: object
required: [detail]
properties:
detail:
type: object
required: [code, message]
properties:
code:
type: string
enum:
- NOT_FOUND
- VERSION_NOT_EDITABLE
- LOCK_REQUIRED
- LOCKED_BY_OTHER
- CORRECTION_VERSION_CONFLICT
- CORRECTION_NOT_APPLIED
- COMMENT_REQUIRED
- EMPTY_CORRECTION
- INVALID_LINE_CODE
- ENTRY_NOT_IN_VERSION
- RULE_NOT_APPLICABLE
- RULE_REQUIRED
message: { type: string, description: Текст по-русски }
additionalProperties: true
CorrectionTableOut:
type: object
required: [version_id, statement_type, rules_version_no, editable, read_only_reason, rules, aggregates, unallocated, totals]
properties:
version_id: { type: string, format: uuid }
statement_type: { $ref: '#/components/schemas/StatementType' }
rules_version_no: { type: integer }
editable: { type: boolean, description: Может ли текущий пользователь править таблицу }
read_only_reason:
type: [string, 'null']
enum: [VERSION_NOT_EDITABLE, LOCK_REQUIRED, LOCKED_BY_OTHER, null]
rules:
type: array
items: { $ref: '#/components/schemas/CorrectionRuleOut' }
aggregates:
type: array
items: { $ref: '#/components/schemas/CorrectionAggregateOut' }
unallocated:
type: array
items: { $ref: '#/components/schemas/UnallocatedEntryOut' }
totals: { $ref: '#/components/schemas/CorrectionTotalsOut' }
CorrectionRuleOut:
type: object
required: [id, rule_no, article_1_line, article_2_line, side_1, measure, company_1_accounts, company_2_accounts, company_1_excluded, company_2_excluded]
properties:
id: { type: string, format: uuid }
rule_no: { type: integer }
article_1_line: { type: string, description: 'Код статьи; составная — коды через «/» ("1450/1550")' }
article_2_line: { type: string, description: 'Код статьи; составная — коды через «/» ("1310/1350")' }
side_1: { $ref: '#/components/schemas/Side' }
measure: { type: string, enum: [closing, turnover] }
company_1_accounts: { type: array, items: { type: string }, description: Коды счетов стороны 1 }
company_2_accounts: { type: array, items: { type: string } }
company_1_excluded: { type: array, items: { type: string } }
company_2_excluded: { type: array, items: { type: string } }
CorrectionAggregateOut:
type: object
required: [rule_id, rule_no, company_1, company_2, side_1, side_2, deviation_amount, deviation_percent, exceeds_threshold, status, eliminated_amount, composition_changed, correction]
properties:
rule_id: { type: string, format: uuid }
rule_no: { type: integer }
company_1: { $ref: '#/components/schemas/Ref' }
company_2: { $ref: '#/components/schemas/Ref' }
side_1: { $ref: '#/components/schemas/AggregateSideOut' }
side_2: { $ref: '#/components/schemas/AggregateSideOut' }
deviation_amount: { $ref: '#/components/schemas/Money' }
deviation_percent: { $ref: '#/components/schemas/Percent' }
exceeds_threshold:
type: boolean
description: deviation_percent ≥ 5, или одна сторона пуста при ненулевой другой
status: { type: string, enum: [AUTO, DISCREPANCY, ONE_SIDED, MANUAL] }
eliminated_amount: { $ref: '#/components/schemas/Money' }
composition_changed: { type: boolean, description: Состав или суммы изменились после применённой корректировки }
correction:
oneOf:
- $ref: '#/components/schemas/CorrectionOut'
- type: 'null'
AggregateSideOut:
type: object
required: [article_line, accounts, amount, entries]
properties:
article_line: { type: string }
accounts: { type: array, items: { type: string }, description: Коды счетов строк, вошедших в сторону }
amount: { $ref: '#/components/schemas/Money' }
entries:
type: array
items: { $ref: '#/components/schemas/CorrectionEntryOut' }
CorrectionEntryOut:
type: object
required: [entry_ids, legal_entity_id, counterparty_id, account_code, side, amount, decision, excluded, candidate_rule_ids]
properties:
entry_ids: { type: array, items: { type: string, format: uuid }, minItems: 1 }
legal_entity_id: { type: string, format: uuid }
counterparty_id: { type: string, format: uuid }
account_code: { type: string }
side: { $ref: '#/components/schemas/Side' }
amount: { $ref: '#/components/schemas/Money' }
decision: { type: string, enum: [AUTO, ASSIGN] }
excluded: { type: boolean }
candidate_rule_ids:
type: array
items: { type: string, format: uuid }
description: Другие правила, под которые строка подходит по счёту и стороне
UnallocatedEntryOut:
type: object
required: [entry_ids, owner, counterparty, account_code, side, amount, candidate_rule_ids, reason, excluded]
properties:
entry_ids: { type: array, items: { type: string, format: uuid }, minItems: 1 }
owner: { $ref: '#/components/schemas/Ref' }
counterparty: { $ref: '#/components/schemas/Ref' }
account_code: { type: string }
side: { $ref: '#/components/schemas/Side' }
amount: { $ref: '#/components/schemas/Money' }
candidate_rule_ids: { type: array, items: { type: string, format: uuid } }
reason: { type: string, enum: [MULTIPLE_RULES, UNASSIGNED] }
excluded: { type: boolean }
CorrectionOut:
type: object
required: [status, version_no, debit, credit, comment, reason_code, balance, updated_by, updated_at]
properties:
status: { type: string, enum: [DRAFT, APPLIED] }
version_no: { type: integer }
debit:
type: array
items: { $ref: '#/components/schemas/CorrectionLineOut' }
description: Статьи стороны 1, первая — основная
credit:
type: array
items: { $ref: '#/components/schemas/CorrectionLineOut' }
description: Статьи стороны 2, первая — основная
comment: { type: string }
reason_code: { type: [string, 'null'] }
balance: { $ref: '#/components/schemas/CorrectionBalanceOut' }
updated_by:
oneOf:
- $ref: '#/components/schemas/Ref'
- type: 'null'
updated_at: { type: string, format: date-time }
CorrectionLineOut:
type: object
required: [line_code, amount]
properties:
line_code: { type: string }
amount: { $ref: '#/components/schemas/Money' }
CorrectionBalanceOut:
type: object
required: [debit_total, credit_total, difference, difference_percent, remainder_1, remainder_2]
properties:
debit_total: { $ref: '#/components/schemas/Money' }
credit_total: { $ref: '#/components/schemas/Money' }
difference: { $ref: '#/components/schemas/Money' }
difference_percent: { $ref: '#/components/schemas/Percent' }
remainder_1: { $ref: '#/components/schemas/Money', description: Сумма стороны 1 минус debit_total }
remainder_2: { $ref: '#/components/schemas/Money', description: Сумма стороны 2 минус credit_total }
CorrectionTotalsOut:
type: object
required: [amount_1, amount_2, deviation_amount, correction_debit, correction_credit]
properties:
amount_1: { $ref: '#/components/schemas/Money' }
amount_2: { $ref: '#/components/schemas/Money' }
deviation_amount: { $ref: '#/components/schemas/Money' }
correction_debit: { $ref: '#/components/schemas/Money' }
correction_credit: { $ref: '#/components/schemas/Money' }
CorrectionLineIn:
type: object
required: [line_code, amount]
properties:
line_code: { type: string, minLength: 1 }
amount: { $ref: '#/components/schemas/MoneyIn' }
CorrectionIn:
type: object
required: [debit, credit, comment, expected_version_no]
properties:
debit: { type: array, items: { $ref: '#/components/schemas/CorrectionLineIn' } }
credit: { type: array, items: { $ref: '#/components/schemas/CorrectionLineIn' } }
comment: { type: string, maxLength: 1000 }
reason_code: { type: [string, 'null'] }
status: { type: string, enum: [APPLIED, DRAFT], default: APPLIED }
expected_version_no:
type: [integer, 'null']
description: >
Редакция действующей (DRAFT/APPLIED) корректировки, которую видел аналитик; null — действующей нет
(в том числе после отзыва). Несовпадение — 409 CORRECTION_VERSION_CONFLICT.
CorrectionRevokeIn:
type: object
required: [comment]
properties:
comment: { type: string, maxLength: 1000 }
AllocationIn:
type: object
required: [statement_type, entry_ids, action]
properties:
statement_type: { $ref: '#/components/schemas/StatementType' }
entry_ids: { type: array, items: { type: string, format: uuid }, minItems: 1 }
action: { type: string, enum: [ASSIGN, UNASSIGN, EXCLUDE, INCLUDE, RESET] }
rule_id: { type: [string, 'null'], format: uuid, description: Обязателен для ASSIGN }