2026-10-27 18:33:58 +04:00

7.2 KiB
Raw Blame History

ADDED Requirements

Requirement: Пары участников без встречных записей

Ядро SHALL вычислять по своду версии пары участников без встречных записей (§3 п. 9 05-domain-rules.md, AURORA-1746): для участников периметра А ≠ Б (consolidation_member версии) пара (А, Б) входит в список, если в своде есть хотя бы одна строка ЮЛ А с counterparty_id = Б (сохранённым или дорезолвленным на чтение) и нет ни одной строки ЮЛ Б с counterparty_id = А. А — сторона, у которой записи есть (holder), Б — сторона без встречных записей (missing). Пара, где записей нет ни у А, ни у Б, в список MUST NOT входить. Строки ЮЛ с контрагентом — самим собой не учитываются. Счета, суммы и тип строки (data_type) на признак не влияют: учитываются все строки свода. Расчёт — чистая функция в domain/ от строк свода и периметра; результат MUST NOT сохраняться. Порядок списка — по имени Б, затем по имени А.

У каждой пары SHALL быть: holder_id, holder_name, missing_id, missing_name, holder_rows (число строк А с контрагентом Б), missing_unmapped_rows (число строк Б с unmapped = true), missing_rows_total (число всех строк Б в своде; 0 — у Б нет строк, например не привязано ни одной ОСВ или все её пары счетов — пробелы).

Scenario: Русский бисквит до сопоставления

  • WHEN версия ГК «Русский бисквит» 2024 Q3 с периметром {АО «Русский бисквит», ООО «Пекарня Счастливочная»}, 22 ОСВ из fixtures/osv/{rb,schastl}/2024-Q{1,2,3} подтверждены; у Счастливочной контрагент «Русский бисквит» с ИНН 3528052718 сопоставлен по ИНН; у РБ контрагент «Пекарня Счастливочная ООО» без ИНН не сопоставлен
  • THEN список содержит одну пару: holder — ООО «Пекарня Счастливочная», missing — АО «Русский бисквит», holder_rows ≥ 1, missing_unmapped_rows ≥ 1

Scenario: Пара закрыта ручным сопоставлением

  • WHEN в той же версии строка РБ «Пекарня Счастливочная ООО» связана с ООО «Пекарня Счастливочная» (POST …/osv/entries/{entry_id}/counterparty)
  • THEN список пар пуст

Scenario: Компании не связаны

  • WHEN в периметре три участника; у А и Б нет записей друг с другом ни в одну сторону
  • THEN пары (А, Б) и (Б, А) в списке нет

Scenario: У стороны нет строк

  • WHEN у А есть строки с контрагентом Б, а у Б в своде нет ни одной строки (ОСВ не привязаны)
  • THEN пара (А, Б) в списке, missing_rows_total = 0, missing_unmapped_rows = 0

MODIFIED Requirements

Requirement: Страница свода и сводка

GET …/osv (CONSOLIDATION_VIEW, policy) SHALL отдавать Page строк свода в порядке: имя ЮЛ, account_code, row_number, первый entry_id; limit ≤ 2000 (по умолчанию 500). Фильтры: legal_entity_id, account_root, counterparty_type, counterparty_id (строка с этим counterparty_id после дорезолва; AURORA-1746), unmapped=true (строка требует сопоставления: counterparty_id пуст после дорезолва и counterparty_inn пуст или из пробелов; строка с ИНН из файла, которого нет в справочнике, сопоставления не требует — решение владельца 08.10.2026, отмена П-1; unmapped=false — все остальные строки), match_kind (повторяемый), q (подстрока без регистра в counterparty_name или префикс counterparty_inn). Те же фильтры SHALL принимать GET …/osv/export. GET …/osv/summary SHALL отдавать rows_total, unmapped_total (строки unmapped=true), auto_matched_total (строки с match_kind ∈ {NAME, ALIAS} независимо от match_stored), documents_total (привязанные ОСВ-документы), gaps[] (legal_entity_id, legal_entity_name, account_code, missing_quarters) и counter_pairs[] — пары участников без встречных записей (требование «Пары участников без встречных записей»). Версия в любом статусе, включая CANCELLED, SHALL читаться.

Scenario: Только несопоставленные

  • WHEN запрошено GET …/osv?unmapped=true
  • THEN все строки ответа с counterparty_id = null и без counterparty_inn, total = summary.unmapped_total

Scenario: Строка с ИНН вне справочника не требует сопоставления

  • WHEN у строки counterparty_inn = "7701000001", такого ИНН и имени в справочнике нет (counterparty_id = null)
  • THEN строки нет в GET …/osv?unmapped=true, она не входит в summary.unmapped_total

Scenario: ИНН сопоставленного ЮЛ

  • WHEN строка без ИНН в файле сопоставлена с ЮЛ по алиасу (на лету или хранимо)
  • THEN counterparty_inn = null, counterparty_entity_inn — ИНН этого ЮЛ из справочника

Scenario: Фильтр по способу

  • WHEN запрошено GET …/osv?match_kind=NAME&match_kind=ALIAS
  • THEN в ответе только строки с этими match_kind, total = summary.auto_matched_total

Scenario: Строки одной стороны пары

  • WHEN в summary.counter_pairs есть пара holder_id = А, missing_id = Б и запрошено GET …/osv?legal_entity_id=А&counterparty_id=Б
  • THEN total = holder_rows пары, у всех строк ответа ЮЛ А и counterparty_id = Б

Scenario: Кандидаты другой стороны пары

  • WHEN для той же пары запрошено GET …/osv?legal_entity_id=Б&unmapped=true
  • THEN total = missing_unmapped_rows пары