Andrey Epifancev 5682897ed0 OpenSpec change intercompany-matrix: требования шахматки из specs/ в дельты (#114)
Требования AURORA-1537, дописанные в openspec/specs/{audit-trail,consolidated-osv,
consolidations-api,directories-api}, перенесены в дельты change'а; specs/ возвращены к main.
Известные дефекты (AURORA-1651/1652/1653) зафиксированы в design.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:42:30 +04:00

5.3 KiB
Raw Blame History

ADDED Requirements

Requirement: Шахматка по сводной ОСВ версии

GET /api/v1/consolidations/versions/{version_id}/intercompany-matrix/all и POST /api/v1/consolidations/versions/{version_id}/intercompany-matrix/manual (CONSOLIDATION_VIEW, policy) SHALL рассчитывать матрицу без сохранения в БД, из строк сводной ОСВ версии и её периметра. ALL включает все счета вида A/AP для дебета и P/AP для кредита. MANUAL принимает обязательные непустые debit_account_ids: UUID[] и credit_account_ids: UUID[], раскрывает выбранные счета по иерархии и оставляет подходящий вид. Неизвестный счёт SHALL давать 422 ACCOUNT_NOT_FOUND, неверный вид — 422 ACCOUNT_KIND_MISMATCH; пустой массив — 422 валидации тела. Невидимая и несуществующая версия SHALL отвечать одинаковым 404 NOT_FOUND.

Ответ SHALL содержать companies[] {id, name} для всего периметра и cells[] для каждой упорядоченной пары разных компаний: company_a_id, company_b_id, amount_a, amount_b, variance_amount, variance_percent, exceeds_threshold, one_sided, skipped_osv_entry_count, osv_entry_ids_debit, osv_entry_ids_credit. Для пары (A, B) amount_a — сумма closing_debit строк A с контрагентом B по дебетовым счетам, amount_b — сумма closing_credit строк B с контрагентом A по кредитовым. Расхождение — модуль разности; процент — расхождение / меньшую сумму × 100 или null при нуле. exceeds_threshold SHALL быть true при точном проценте > 5, до округления; суммы и процент в JSON SHALL быть десятичными строками с двумя знаками после запятой (ROUND_HALF_UP). one_sided SHALL быть true при наличии исходных записей ОСВ только с одной стороны, в том числе при нулевой сумме. skipped_osv_entry_count SHALL считать исходные строки ОСВ пары с account_id = null на обеих сторонах; они не входят в суммы. Массивы osv_entry_ids_debit/credit SHALL содержать ID исходных записей соответствующей стороны.

Scenario: Пустой периметр и отсутствие ОСВ

  • WHEN у версии нет членов периметра
  • THEN companies = [], cells = []; если компании есть, но ОСВ по выбранным счетам нет, ячейки присутствуют с нулевыми суммами

Scenario: Только одна сторона пары

  • WHEN у A есть строка ОСВ с контрагентом B, а у B встречной строки нет
  • THEN для (A, B) one_sided = true, variance_percent = null, соответствующий массив osv_entry_ids_* пуст

Scenario: Счёт не сопоставлен

  • WHEN у пары есть строка свода с account_id = null и двумя entry_ids
  • THEN она не входит в суммы, skipped_osv_entry_count обеих направленных ячеек пары увеличивается на 2

Scenario: Эталон «Русский бисквит»

  • WHEN матрица строится по ОСВ РБ и Пекарни Счастливочной из эталонных фикстур
  • THEN суммы сравниваются с эталоном только для точных пар счетов и компаний; общая сумма элиминации эталона не приравнивается к минимуму по паре в API (решение владельца 08.10.2026)

Requirement: XLSX шахматки

GET …/intercompany-matrix/all/export и POST …/intercompany-matrix/manual/export SHALL использовать те же режимы, тело и права, что и соответствующие JSON-маршруты. Ответ — XLSX с именем intercompany-matrix_<ГК>_<год>-<квартал>_v<n>.xlsx, шапкой (ГК, период, версия, единицы, режим, выбранные счета) и строками разницы, дебета, кредита и процента расхождения для каждой пары.

Scenario: Экспорт выбранных счетов

  • WHEN пользователь выгружает MANUAL для ГК «Русский бисквит» за 2024 Q1, версия 1
  • THEN имя содержит Русский бисквит_2024-Q1_v1.xlsx, шапка содержит выбранные счета, ячейки процента показывают два знака и символ % без повторного масштабирования