Merge pull request 'openspec archive: итоги шахматки (#218, #225)' (#226) from chore/archive-matrix-totals into main

This commit is contained in:
aep 2026-11-06 16:22:51 +03:00
commit 8c5d749089
14 changed files with 78 additions and 42 deletions

View File

@ -5,4 +5,4 @@
- [x] 1.3 Матрица: «Итого Дт» / «Итого Кт» из ответа - [x] 1.3 Матрица: «Итого Дт» / «Итого Кт» из ответа
- [x] 1.4 Фильтр «Компании» в запросе, варианты из периметра; выгрузка с выбором компаний - [x] 1.4 Фильтр «Компании» в запросе, варианты из периметра; выгрузка с выбором компаний
- [x] 1.5 Результирующая таблица без строки «Итого» - [x] 1.5 Результирующая таблица без строки «Итого»
- [ ] 1.6 Сценарий на стенде (Playwright) и сверка с макетом 31-01 / 31-01-01 - [x] 1.6 Сценарий на стенде (Playwright, РБ 2024 К3)

View File

@ -9,4 +9,4 @@
## 2. Фронт (AURORA-1757, отдельный PR) ## 2. Фронт (AURORA-1757, отдельный PR)
- [ ] 2.1 Клиент на единый маршрут, итоги из API, фильтр «Компании» в запрос - [x] 2.1 (PR #225) Клиент на единый маршрут, итоги из API, фильтр «Компании» в запрос

View File

@ -147,14 +147,13 @@ ORM-модель `audit_event` MUST NOT использоваться для `UPD
- **THEN** событие `CONSOLIDATION_STATUS_CHANGE` с `user_id` подтвердившего, `before_value.status = INITIATED` - **THEN** событие `CONSOLIDATION_STATUS_CHANGE` с `user_id` подтвердившего, `before_value.status = INITIATED`
### Requirement: Аудит экспорта шахматки ### Requirement: Аудит экспорта шахматки
Каждый успешный `GET …/intercompany-matrix/all/export`, `POST …/intercompany-matrix/manual/export` и Каждый успешный `POST …/intercompany-matrix/export` и `GET …/intercompany-matrix/preset/{rule_id}/export`
`GET …/intercompany-matrix/preset/{rule_id}/export`
SHALL добавлять отдельное неизменяемое событие `audit_event` с `action = EXPORT`, `section = EXPORT`, SHALL добавлять отдельное неизменяемое событие `audit_event` с `action = EXPORT`, `section = EXPORT`,
`object_type = consolidation_version`, `object_id = consolidation_version_id`, `user_id` инициатора, `object_type = consolidation_version`, `object_id = consolidation_version_id`, `user_id` инициатора,
`before_value = null` и `after_value = {report: "intercompany_matrix", mode, debit_account_ids, `before_value = null` и `after_value = {report: "intercompany_matrix", mode, debit_account_ids,
credit_account_ids, cells}`; для `PRESET` в `after_value` SHALL быть дополнительно `rule_id`, `rule_no` и credit_account_ids, legal_entity_ids, cells}`; для `PRESET` в `after_value` SHALL быть дополнительно `rule_id`, `rule_no` и
`rule_version_no` (фактическая версия применённого правила, в том числе при незафиксированной версии правил). `mode` — `ALL`, `rule_version_no` (фактическая версия применённого правила, в том числе при незафиксированной версии правил). `mode` — `ALL`,
`MANUAL` или `PRESET`, массивы счетов — ID из запроса (в ALL и PRESET пустые), `cells` — число ячеек. Выгрузка `MANUAL` или `PRESET`, массивы счетов и ЮЛ — ID из запроса (счета в ALL и PRESET пустые), `cells` — число ячеек. Выгрузка
сводной ОСВ продолжает писать собственное событие `EXPORT`. сводной ОСВ продолжает писать собственное событие `EXPORT`.
#### Scenario: Две выгрузки #### Scenario: Две выгрузки

View File

@ -175,17 +175,20 @@ filename="svod-osv.xlsx"; filename*=UTF-8''svod-osv_<ГК>_<год>-<кварт
— одну строку с `Q2`; `audit_event(EXPORT)` с `after_value.rows = 3` — одну строку с `Q2`; `audit_event(EXPORT)` с `after_value.rows = 3`
### Requirement: Шахматка по сводной ОСВ версии ### Requirement: Шахматка по сводной ОСВ версии
`GET /api/v1/consolidations/versions/{version_id}/intercompany-matrix/all` и `POST /api/v1/consolidations/versions/{version_id}/intercompany-matrix` принимает
`POST /api/v1/consolidations/versions/{version_id}/intercompany-matrix/manual` `{debit_account_ids?: UUID[], credit_account_ids?: UUID[], legal_entity_ids?: UUID[]}`. Если список стороны отсутствует или пуст,
(`CONSOLIDATION_VIEW`, policy) SHALL рассчитывать матрицу без сохранения в БД, из строк сводной ОСВ версии для неё выбираются все подходящие балансовые счета (`is_off_balance = false`); непустой список раскрывается
и её периметра. ALL включает балансовые счета (`is_off_balance = false`) вида `A`/`AP` для дебета и `P`/`AP` для по иерархии и может содержать забалансовые счета. Пустые списки обеих сторон эквивалентны режиму ALL,
кредита; забалансовые счета (001–012) в ALL MUST NOT входить. MANUAL принимает обязательные непустые хотя бы один непустой список — MANUAL. Маршрут (`CONSOLIDATION_VIEW`, policy) SHALL рассчитывать матрицу
`debit_account_ids: UUID[]` и `credit_account_ids: UUID[]`, раскрывает выбранные счета по иерархии и оставляет без сохранения в БД, из строк сводной ОСВ версии и её периметра. Для пустой стороны выбираются счета вида
подходящий вид; забалансовые счета в MANUAL допускаются. Неизвестный счёт SHALL давать 422 `ACCOUNT_NOT_FOUND`, неверный `A`/`AP` для дебета или `P`/`AP` для кредита; забалансовые счета (001–012) MUST NOT входить в такую выборку.
вид — 422 `ACCOUNT_KIND_MISMATCH`; пустой массив — 422 валидации тела. Невидимая и несуществующая версия SHALL Неизвестный счёт SHALL давать 422 `ACCOUNT_NOT_FOUND`, неверный вид — 422 `ACCOUNT_KIND_MISMATCH`.
Пустой `legal_entity_ids` выбирает все ЮЛ периметра; непустой ограничивает обе оси матрицы и суммы выбранными ЮЛ.
ID вне периметра SHALL давать 422 `ENTITY_NOT_IN_PERIMETER`. Невидимая и несуществующая версия SHALL
отвечать одинаковым 404 `NOT_FOUND`. отвечать одинаковым 404 `NOT_FOUND`.
Ответ SHALL содержать `companies[] {id, name}` для всего периметра и `cells[]` для каждой упорядоченной пары Ответ SHALL содержать `companies[] {id, name}` для периметра (при непустом `legal_entity_ids` — только выбранные ЮЛ в порядке периметра), `total_debit` и `total_credit`
с суммой по каждому ЮЛ (ключ — ID ЮЛ, значение — десятичная строка с двумя знаками), и `cells[]` для каждой упорядоченной пары
разных компаний: `company_a_id`, `company_b_id`, `amount_a`, `amount_b`, `variance_amount`, `variance_percent`, разных компаний: `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`. `exceeds_threshold`, `one_sided`, `skipped_osv_entry_count`, `osv_entry_ids_debit`, `osv_entry_ids_credit`.
Для пары `(A, B)` `amount_a` — сумма `closing_debit` строк A с контрагентом B по дебетовым счетам, Для пары `(A, B)` `amount_a` — сумма `closing_debit` строк A с контрагентом B по дебетовым счетам,
@ -197,10 +200,15 @@ filename="svod-osv.xlsx"; filename*=UTF-8''svod-osv_<ГК>_<год>-<кварт
сальдо на признак не влияет. Пара подсвечивается, если `exceeds_threshold` или `one_sided`. `skipped_osv_entry_count` сальдо на признак не влияет. Пара подсвечивается, если `exceeds_threshold` или `one_sided`. `skipped_osv_entry_count`
SHALL считать исходные строки ОСВ пары с `account_id = null` на обеих сторонах; они не входят в суммы. Массивы SHALL считать исходные строки ОСВ пары с `account_id = null` на обеих сторонах; они не входят в суммы. Массивы
`osv_entry_ids_debit/credit` SHALL содержать ID исходных записей соответствующей стороны. `osv_entry_ids_debit/credit` SHALL содержать ID исходных записей соответствующей стороны.
`total_debit` («Итого Дт», колонка справа) суммирует `amount_a` ячеек строки по `company_a_id`, `total_credit`
(«Итого Кт», строка снизу) — `amount_b` ячеек столбца по `company_b_id`; ключи — ID всех ЮЛ из `companies`.
Диагональ не участвует, отрицательные суммы входят со знаком, суммы ячеек точные (`numeric(18,2)`). Для ЮЛ без
подходящих строк, в том числе когда в выборке одно ЮЛ, итог равен `"0.00"` (правило аналитика, DOC-221277
«Итоги шахматки», 03.11.2026).
#### Scenario: Пустой периметр и отсутствие ОСВ #### Scenario: Пустой периметр и отсутствие ОСВ
- **WHEN** у версии нет членов периметра - **WHEN** у версии нет членов периметра
- **THEN** `companies = []`, `cells = []`; если компании есть, но ОСВ по выбранным счетам нет, ячейки присутствуют с нулевыми суммами - **THEN** `companies = []`, `cells = []`, `total_debit = {}`, `total_credit = {}`; если компании есть, но ОСВ по выбранным счетам нет, ячейки присутствуют с нулевыми суммами
#### Scenario: Только одна сторона пары #### Scenario: Только одна сторона пары
- **WHEN** у A есть строка ОСВ с контрагентом B и ненулевым сальдо, а у B встречной строки нет - **WHEN** у A есть строка ОСВ с контрагентом B и ненулевым сальдо, а у B встречной строки нет
@ -230,12 +238,31 @@ SHALL считать исходные строки ОСВ пары с `account_i
- **WHEN** матрица строится по ОСВ РБ и Пекарни Счастливочной из эталонных фикстур - **WHEN** матрица строится по ОСВ РБ и Пекарни Счастливочной из эталонных фикстур
- **THEN** суммы сравниваются с эталоном только для точных пар счетов и компаний; общая сумма элиминации эталона не приравнивается к минимуму по паре в API (решение владельца 08.10.2026) - **THEN** суммы сравниваются с эталоном только для точных пар счетов и компаний; общая сумма элиминации эталона не приравнивается к минимуму по паре в API (решение владельца 08.10.2026)
#### Scenario: Итоги Дт и Кт
- **WHEN** в периметре A, B, C; `amount_a` ячеек (A, B) = 100 и (A, C) = 20, `amount_b` ячеек (A, B) = 70 и (C, B) = 5
- **THEN** `total_debit[A] = "120.00"`, `total_credit[B] = "75.00"`
#### Scenario: Фильтр по ЮЛ
- **WHEN** запрос с `legal_entity_ids = [A, B]` при периметре A, B, C
- **THEN** `companies` и обе оси — только A и B, ячейки и итоги не учитывают C; ID вне периметра — 422 `ENTITY_NOT_IN_PERIMETER`
#### Scenario: Пустая одна сторона
- **WHEN** `debit_account_ids = [62]`, `credit_account_ids` пуст
- **THEN** дебет — счёт 62 с потомками, кредит — все балансовые счета вида `P`/`AP`; режим выгрузки и аудита — `MANUAL`
### Requirement: XLSX шахматки ### Requirement: XLSX шахматки
`GET …/intercompany-matrix/all/export` и `POST …/intercompany-matrix/manual/export` SHALL использовать `POST …/intercompany-matrix/export` принимает то же тело, что единый JSON-маршрут, и строит XLSX
те же режимы, тело и права, что и соответствующие JSON-маршруты. Ответ — XLSX с именем по той же выборке ЮЛ и счетов. В шапке пустая сторона обозначается «Все балансовые счета»; аудит сохраняет
`legal_entity_ids` из запроса и использует
`mode = ALL`, когда пусты обе стороны, иначе `mode = MANUAL`.
Ответ — XLSX с именем
`intercompany-matrix_<ГК>_<год>-<квартал>_v<n>.xlsx`, шапкой (ГК, период, версия, единицы, режим, `intercompany-matrix_<ГК>_<год>-<квартал>_v<n>.xlsx`, шапкой (ГК, период, версия, единицы, режим,
выбранные счета; для ALL — «Все балансовые счета») и строками разницы, дебета, кредита и процента расхождения для выбранные счета; для ALL — «Все балансовые счета») и строками разницы, дебета, кредита и процента расхождения для
каждой пары. Пара SHALL заливаться цветом порога, если `exceeds_threshold` или `one_sided` — так же, как в API. каждой пары. Пара SHALL заливаться цветом порога, если `exceeds_threshold` или `one_sided` — так же, как в API.
Справа от колонок компаний SHALL быть колонка «Итого Дт» с `total_debit` по каждому ЮЛ строки (ячейка объединена
на строки пары); под матрицей SHALL быть строка «Итого Кт» с `total_credit` по каждому ЮЛ колонки; ячейка на
пересечении пустая. Значения — те же, что в JSON.
#### Scenario: Экспорт выбранных счетов #### Scenario: Экспорт выбранных счетов
- **WHEN** пользователь выгружает MANUAL для ГК «Русский бисквит» за 2024 Q1, версия 1 - **WHEN** пользователь выгружает MANUAL для ГК «Русский бисквит» за 2024 Q1, версия 1

View File

@ -260,7 +260,8 @@ account, status, missing_quarters, document_ids}`: `document_type` и `account`
из конечного сальдо нужной стороны и выбранных счетов статьи; `group_total` — сумма по компаниям. из конечного сальдо нужной стороны и выбранных счетов статьи; `group_total` — сумма по компаниям.
`amount` и `group_total` SHALL возвращаться строками с двумя знаками после округления `ROUND_HALF_UP` `amount` и `group_total` SHALL возвращаться строками с двумя знаками после округления `ROUND_HALF_UP`
(например, `"0.00"`). (например, `"0.00"`).
Отсутствие любого необходимого кода счёта SHALL давать 422 `RESULT_ACCOUNTS_MISSING` с перечнем кодов. Итоговой строки по всем статьям (по компании или по группе) в ответе нет: суммы разных статей не складываются
(решение аналитика 03.11.2026, согласовано с заказчиком). Отсутствие любого необходимого кода счёта SHALL давать 422 `RESULT_ACCOUNTS_MISSING` с перечнем кодов.
#### Scenario: Компания без ОСВ #### Scenario: Компания без ОСВ
- **WHEN** в периметре есть компания без подходящих строк ОСВ - **WHEN** в периметре есть компания без подходящих строк ОСВ
@ -270,6 +271,10 @@ account, status, missing_quarters, document_ids}`: `document_type` и `account`
- **WHEN** в плане счетов отсутствует счёт 58.03 - **WHEN** в плане счетов отсутствует счёт 58.03
- **THEN** ответ 422 `RESULT_ACCOUNTS_MISSING`, сообщение содержит `58.03` - **THEN** ответ 422 `RESULT_ACCOUNTS_MISSING`, сообщение содержит `58.03`
#### Scenario: Нет итога по статьям
- **WHEN** запрашивается результирующая таблица
- **THEN** в ответе нет `grand_total` и итогов по компании через все статьи; в XLSX под статьями нет строки «Итого»
### Requirement: XLSX результирующей таблицы ВГО ### Requirement: XLSX результирующей таблицы ВГО
`GET /api/v1/consolidations/versions/{version_id}/intercompany-matrix/result-table/export` (`CONSOLIDATION_VIEW`, `GET /api/v1/consolidations/versions/{version_id}/intercompany-matrix/result-table/export` (`CONSOLIDATION_VIEW`,
policy) SHALL возвращать XLSX с теми же статьями, компаниями и итогами, что `GET …/intercompany-matrix/result-table`, policy) SHALL возвращать XLSX с теми же статьями, компаниями и итогами, что `GET …/intercompany-matrix/result-table`,

View File

@ -39,16 +39,17 @@
- **THEN** одним нажатием открыт список консолидаций ГК - **THEN** одним нажатием открыт список консолидаций ГК
### Requirement: Таблица шахматки ЮЛ × ЮЛ ### Requirement: Таблица шахматки ЮЛ × ЮЛ
Экран SHALL загружать матрицу при открытии вкладки (`GET /consolidations/versions/{id}/intercompany-matrix/all`) и показывать Экран SHALL загружать матрицу при открытии вкладки (`POST /consolidations/versions/{id}/intercompany-matrix`, тело — по требованию «Фильтр счетов Дт и Кт и режимы расчёта») и показывать
таблицу: первая колонка «ДБ / КТ» (закреплена слева) — компании периметра в порядке ответа (`companies[]`), остальные колонки — таблицу: первая колонка «ДБ / КТ» (закреплена слева) — компании периметра в порядке ответа (`companies[]`), остальные колонки —
те же компании. В ячейке пары (строка A, колонка Б) SHALL быть три числа друг под другом: сумма `amount_a`, сумма `amount_b` те же компании. В ячейке пары (строка A, колонка Б) SHALL быть три числа друг под другом: сумма `amount_a`, сумма `amount_b`
и расхождение `variance_amount` в скобках; расхождение выделяется красным, если `exceeds_threshold = true` или и расхождение `variance_amount` в скобках; расхождение выделяется красным, если `exceeds_threshold = true` или
`one_sided = true` (пара без встречной стороны; правило подсветки — как в API и xlsx, AURORA-1651). Если у пары есть `one_sided = true` (пара без встречной стороны; правило подсветки — как в API и xlsx, AURORA-1651). Если у пары есть
строки ОСВ без сопоставленного счёта (`skipped_osv_entry_count > 0`), рядом с первым числом SHALL показываться значок строки ОСВ без сопоставленного счёта (`skipped_osv_entry_count > 0`), рядом с первым числом SHALL показываться значок
предупреждения с подсказкой «Строк ОСВ без сопоставленного счёта: N; в суммы не вошли». Если ячейки пары в ответе нет предупреждения с подсказкой «Строк ОСВ без сопоставленного счёта: N; в суммы не вошли». Если ячейки пары в ответе нет
(в том числе на диагонали), SHALL показываться прочерк «—» на приглушённом фоне. Ниже таблицы закреплена строка «Итого»: до (в том числе на диагонали), SHALL показываться прочерк «—» на приглушённом фоне. Справа закреплена колонка «Итого Дт» —
появления итогов в API (AURORA-1756, AURORA-1757) она временно считается на клиенте точным сложением десятичных строк — сумма `total_debit` ответа для компании строки; ниже таблицы закреплена строка «Итого Кт» — `total_credit` для компании колонки;
`amount_a` по колонке видимых ячеек; итог, который не удалось сложить, показывается прочерком «—», а не нулём. Пока идёт ячейка на их пересечении пустая. Итоги считает сервер (DOC-221277 «Итоги шахматки», AURORA-1756), клиент их только форматирует
(«Единицы и знаки»); отсутствующий в ответе итог — прочерк «—». Пока идёт
загрузка, таблица показывает индикатор загрузки; ошибка API показывается уведомлением с текстом сервера. Панель фильтров загрузка, таблица показывает индикатор загрузки; ошибка API показывается уведомлением с текстом сервера. Панель фильтров
показывает год и квартал версии неактивными полями «Год» и «Период» (например, `2024` и `К1`): версия задаётся адресом. показывает год и квартал версии неактивными полями «Год» и «Период» (например, `2024` и `К1`): версия задаётся адресом.
@ -68,19 +69,22 @@
- **WHEN** у ячейки `skipped_osv_entry_count = 2` - **WHEN** у ячейки `skipped_osv_entry_count = 2`
- **THEN** у первого числа ячейки виден значок предупреждения, подсказка — «Строк ОСВ без сопоставленного счёта: 2; в суммы не вошли» - **THEN** у первого числа ячейки виден значок предупреждения, подсказка — «Строк ОСВ без сопоставленного счёта: 2; в суммы не вошли»
#### Scenario: Итоги из ответа
- **WHEN** сервер вернул `total_debit[A] = "120000.00"` и `total_credit[Б] = "75000.00"`, выбраны «тыс. руб.» и 2 знака
- **THEN** в колонке «Итого Дт» строки A показано `120,00`, в строке «Итого Кт» под колонкой Б — `75,00`, пересечение итогов пустое
### Requirement: Результирующая таблица ВГО ### Requirement: Результирующая таблица ВГО
Под матрицей экран SHALL показывать результирующую таблицу ВГО, загруженную при открытии вкладки Под матрицей экран SHALL показывать результирующую таблицу ВГО, загруженную при открытии вкладки
(`GET /consolidations/versions/{id}/intercompany-matrix/result-table`): первая колонка «Статья» — статьи ответа (`articles[]`, (`GET /consolidations/versions/{id}/intercompany-matrix/result-table`): первая колонка «Статья» — статьи ответа (`articles[]`,
`name`) в порядке ответа, далее колонки компаний (`companies[]`) с суммой статьи по компании (`amounts[]` по `company_id`) и `name`) в порядке ответа, далее колонки компаний (`companies[]`) с суммой статьи по компании (`amounts[]` по `company_id`) и
колонка «Итого» со значением `group_total` из ответа; пустая сумма — прочерк «—». Ниже таблицы закреплена строка «Итого»: до колонка «Итого по группе» со значением `group_total` из ответа; пустая сумма — прочерк «—». Строки итога по всем статьям под
появления итогов в API (AURORA-1756, AURORA-1757) она временно считается на клиенте точным сложением сумм всех статей по таблицей нет: суммы разных статей не складываются (аналитик, 03.11.2026). У таблицы свои выбор единиц и знаков (по правилам требования «Единицы и знаки», независимо от
колонке (итог, который не удалось сложить, — «—»). У таблицы свои выбор единиц и знаков (по правилам требования «Единицы и знаки», независимо от
матрицы), кнопка «Экспорт» и кнопка «На весь экран». Пока идёт загрузка, таблица показывает индикатор; ошибка API (в том числе матрицы), кнопка «Экспорт» и кнопка «На весь экран». Пока идёт загрузка, таблица показывает индикатор; ошибка API (в том числе
422 `RESULT_ACCOUNTS_MISSING`) показывается уведомлением с текстом сервера. 422 `RESULT_ACCOUNTS_MISSING`) показывается уведомлением с текстом сервера.
#### Scenario: Колонка «Итого» из ответа #### Scenario: Колонка «Итого» из ответа
- **WHEN** сервер вернул статью «Дебиторская задолженность» с `group_total = "1296510.00"`, выбраны «тыс. руб.» и 2 знака - **WHEN** сервер вернул статью «Дебиторская задолженность» с `group_total = "1296510.00"`, выбраны «тыс. руб.» и 2 знака
- **THEN** в колонке «Итого» этой статьи показано `1 296,51` - **THEN** в колонке «Итого по группе» этой статьи показано `1 296,51`
#### Scenario: Нет обязательного счёта #### Scenario: Нет обязательного счёта
- **WHEN** сервер ответил 422 `RESULT_ACCOUNTS_MISSING` - **WHEN** сервер ответил 422 `RESULT_ACCOUNTS_MISSING`
@ -107,14 +111,15 @@
- **THEN** показано `0,00`, а не `-0,00` - **THEN** показано `0,00`, а не `-0,00`
### Requirement: Фильтр компаний ### Requirement: Фильтр компаний
Выбор «Компании» (множественный, пустой выбор — «Все компании») SHALL ограничивать матрицу на клиенте: остаются строки и Выбор «Компании» (множественный, пустой выбор — «Все компании») SHALL передаваться в запрос матрицы
колонки выбранных компаний и ячейки, у которых обе компании выбраны. Запрос на сервер при этом не отправляется. Список `legal_entity_ids`: сервер возвращает только выбранные компании, ячейки между ними и итоги «Итого Дт» / «Итого Кт» по ним.
вариантов — компании последнего загруженного ответа. Выпадающее окно выбора — дерево с поиском по названию, кнопками Каждое изменение выбора перезапрашивает матрицу (в состоянии «выбрана одна сторона» — нет). Список вариантов — компании
последнего ответа, полученного без выбора компаний (весь периметр версии); ответы с выбором его не меняют. Выпадающее окно выбора — дерево с поиском по названию, кнопками
применения и сброса. применения и сброса.
#### Scenario: Две компании из периметра #### Scenario: Две компании из периметра
- **WHEN** выбраны две компании из пяти - **WHEN** выбраны две компании из пяти
- **THEN** матрица содержит две строки и две колонки, «Итого» считается по оставшимся ячейкам - **THEN** запрос содержит `legal_entity_ids` этих двух компаний, матрица содержит две строки и две колонки, итоги — из ответа, в списке вариантов по-прежнему пять компаний
### Requirement: Фильтр счетов Дт и Кт и режимы расчёта ### Requirement: Фильтр счетов Дт и Кт и режимы расчёта
Экран SHALL загружать план счетов `GET /directories/accounts` один раз при открытии и строить из него два дерева по иерархии Экран SHALL загружать план счетов `GET /directories/accounts` один раз при открытии и строить из него два дерева по иерархии
@ -127,21 +132,22 @@
отметки при отметке видимых узлов сохраняются. отметки при отметке видимых узлов сохраняются.
Режим расчёта определяется выбором: Режим расчёта определяется выбором:
- ничего не выбрано ни в Дт, ни в Кт — SHALL выполняться `GET …/intercompany-matrix/all` (режим `all`); - ничего не выбрано ни в Дт, ни в Кт — SHALL выполняться `POST …/intercompany-matrix` с пустыми `debit_account_ids` и
- выбраны счета и в Дт, и в Кт — SHALL выполняться `POST …/intercompany-matrix/manual` с `{debit_account_ids, `credit_account_ids` (режим `all`);
credit_account_ids}` (режим `manual`); - выбраны счета и в Дт, и в Кт — SHALL выполняться `POST …/intercompany-matrix` с выбранными `debit_account_ids` и
`credit_account_ids` (режим `manual`);
- выбрана только одна сторона — запрос SHALL NOT отправляться, таблица матрицы SHALL быть пустой и вместо данных показывать - выбрана только одна сторона — запрос SHALL NOT отправляться, таблица матрицы SHALL быть пустой и вместо данных показывать
текст «Для расчёта по счетам выберите счета и в Дт, и в Кт»; тот же текст SHALL показываться у фильтров Дт/Кт (не текст «Для расчёта по счетам выберите счета и в Дт, и в Кт»; тот же текст SHALL показываться у фильтров Дт/Кт (не
всплывающим уведомлением) и только в этом состоянии; кнопка «Экспорт» матрицы SHALL быть недоступна. всплывающим уведомлением) и только в этом состоянии; кнопка «Экспорт» матрицы SHALL быть недоступна.
Каждое изменение выбора счетов, приводящее к режиму `all` или `manual`, перезапрашивает матрицу; на экране остаётся ответ на В тело всегда входит `legal_entity_ids` (требование «Фильтр компаний»). Каждое изменение выбора счетов, приводящее к режиму `all` или `manual`, перезапрашивает матрицу; на экране остаётся ответ на
последний запрос, индикатор загрузки снимается и при переходе в состояние «выбрана одна сторона». Кнопка «Сбросить фильтры» последний запрос, индикатор загрузки снимается и при переходе в состояние «выбрана одна сторона». Кнопка «Сбросить фильтры»
появляется, когда выбрано что-либо в компаниях, Дт или Кт, и очищает все три выбора. Выбор единиц и знаков кнопкой не появляется, когда выбрано что-либо в компаниях, Дт или Кт, и очищает все три выбора. Выбор единиц и знаков кнопкой не
сбрасывается. Ошибка загрузки плана счетов показывается уведомлением. сбрасывается. Ошибка загрузки плана счетов показывается уведомлением.
#### Scenario: Обе стороны выбраны #### Scenario: Обе стороны выбраны
- **WHEN** выбран счёт 60.01 в Дт и счёт 62.01 в Кт - **WHEN** выбран счёт 60.01 в Дт и счёт 62.01 в Кт
- **THEN** отправляется `POST …/intercompany-matrix/manual` с идентификаторами этих счетов и таблица показывает ответ - **THEN** отправляется `POST …/intercompany-matrix` с идентификаторами этих счетов и таблица показывает ответ
#### Scenario: Выбрана одна сторона #### Scenario: Выбрана одна сторона
- **WHEN** выбран счёт только в Дт - **WHEN** выбран счёт только в Дт
@ -165,17 +171,16 @@
- **THEN** все три выбора пусты, матрица перезапрошена в режиме `all`, кнопка исчезла - **THEN** все три выбора пусты, матрица перезапрошена в режиме `all`, кнопка исчезла
### Requirement: Экспорт в XLSX ### Requirement: Экспорт в XLSX
Кнопка «Экспорт» матрицы SHALL скачивать XLSX в том же режиме, что и таблица: в режиме `manual` — Кнопка «Экспорт» матрицы SHALL скачивать XLSX в том же режиме, что и таблица: `POST …/intercompany-matrix/export` с тем же
`POST …/intercompany-matrix/manual/export` с телом `{debit_account_ids, credit_account_ids}`, в режиме `all` — телом, что запрос таблицы (`debit_account_ids`, `credit_account_ids`, `legal_entity_ids`), — итоги в файле совпадают с экраном; при выбранной одной стороне кнопка недоступна. Кнопка «Экспорт» результирующей таблицы
`GET …/intercompany-matrix/all/export`; при выбранной одной стороне кнопка недоступна. Кнопка «Экспорт» результирующей таблицы
SHALL скачивать `GET …/intercompany-matrix/result-table/export`. Файл сохраняется под именем из `Content-Disposition`, при его SHALL скачивать `GET …/intercompany-matrix/result-table/export`. Файл сохраняется под именем из `Content-Disposition`, при его
отсутствии — `Шахматка_<ГК>_<год>_<квартал>.xlsx` и `Результирующая_таблица_ВГО_<ГК>_<год>_<квартал>.xlsx` соответственно. отсутствии — `Шахматка_<ГК>_<год>_<квартал>.xlsx` и `Результирующая_таблица_ВГО_<ГК>_<год>_<квартал>.xlsx` соответственно.
Пока идёт выгрузка, в состоянии загрузки только нажатая кнопка; ошибка API показывается уведомлением. Фильтр компаний, единицы и Пока идёт выгрузка, в состоянии загрузки только нажатая кнопка; ошибка API показывается уведомлением. Единицы и знаки в запрос экспорта
знаки в запрос экспорта не передаются. не передаются.
#### Scenario: Экспорт по всем счетам #### Scenario: Экспорт по всем счетам
- **WHEN** счета не выбраны и нажато «Экспорт» матрицы - **WHEN** счета не выбраны и нажато «Экспорт» матрицы
- **THEN** отправлен `GET …/intercompany-matrix/all/export`, браузер сохраняет файл `intercompany-matrix_….xlsx` - **THEN** отправлен `POST …/intercompany-matrix/export` с пустыми списками, браузер сохраняет файл `intercompany-matrix_….xlsx`
#### Scenario: Экспорт результирующей таблицы #### Scenario: Экспорт результирующей таблицы
- **WHEN** нажато «Экспорт» результирующей таблицы - **WHEN** нажато «Экспорт» результирующей таблицы