docs(#136): OQ-169 закрыт — каскад по остатку в порядке rule_no

§5: сумма элиминации пары (A, B) считается по правилам в порядке rule_no, каждое берёт
min из остатка сторон после предыдущих (как правило № 1 Прил. 3) — без двойной
элиминации по общим счетам № 3–8; упаковка в том же порядке, ничьей между правилами
нет; зеркальные № 9–16 — те же правила для (B, A). OQ-169 закрыт решением владельца
19.10.2026. Документ для аналитика: раздел 3.2, 3.3, пример, В-12.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-19 14:36:44 +04:00
parent a12c0779db
commit c6768fad56
4 changed files with 61 additions and 29 deletions

View File

@ -1,6 +1,6 @@
# Элиминация ВГО: правила, расчёт, корректировки
Документ для аналитика, 19.10.2026 (RSHB/arm-ka-docs#132; сопоставление — по решению OQ-07, #136). Основа — модель данных
Документ для аналитика, 19.10.2026 (RSHB/arm-ka-docs#132; сопоставление — по решениям OQ-07 и OQ-169, #136). Основа — модель данных
[`model/data-model-v5.19.dbml`](../model/data-model-v5.19.dbml) и правила предметной области
[`context/05-domain-rules.md`](../context/05-domain-rules.md) §3–§6, §8. Источник истины — они: при расхождении прав
DBML и `05-domain-rules.md`, а этот документ поправь следом. Где написано наше прочтение ТЗ, а не прямая цитата, это
@ -131,27 +131,42 @@ DBML и `05-domain-rules.md`, а этот документ поправь сле
### 3.2. Автоматическое сопоставление пар (DOC-223044, `05-domain-rules.md` §5)
Единица расчёта — **тройка** (правило, компания A, компания B). У неё два уровня (решение владельца 19.10.2026, OQ-07):
Единица расчёта — **тройка** (правило, компания A, компания B). Правила считаются для каждой упорядоченной пары
компаний — и (A, B), и (B, A), поэтому зеркальные правила № 9–16 Прил. 3 отдельно не заводятся (№ 14 для (A, B) — это
№ 6 для (B, A)). У тройки два уровня (решения владельца 19.10.2026, OQ-07 и OQ-169):
**Сумма элиминации** — агрегат, идёт в КФО:
**Сумма элиминации** — агрегат, идёт в КФО. Считается **каскадом по остатку**: правила пары (A, B) идут по порядку
`rule_no`, каждое берёт min из того, что осталось после предыдущих правил:
```
ΣA = Σ стороны правила строк A с контрагентом B по счетам стороны 1 (с исключениями)
ΣB = Σ противоположной стороны строк B с контрагентом A по счетам стороны 2
deviation_amount = |ΣA − ΣB|; deviation_percent = deviation_amount / min(ΣA, ΣB) × 100
для правил по возрастанию rule_no:
ΣA = Σ остатка строк A с контрагентом B по счетам стороны 1 (с исключениями)
ΣB = Σ остатка строк B с контрагентом A по счетам стороны 2
deviation_amount = |ΣA − ΣB|; deviation_percent = deviation_amount / min(ΣA, ΣB) × 100
элиминация = min(ΣA, ΣB) при расхождении ≤ 5 % (раздел 3.3); остатки сторон уменьшаются на неё
```
Зачем каскад: счета правил пересекаются (дебиторка у № 5–8 общая; 67.03 входит и в № 3, и в маску 67 у № 7; 66.03 — в
№ 4 и в № 8). По буквальным формулам Прил. 3 одна дебиторка элиминировалась бы несколько раз. Порядок `rule_no` в Прил. 3
уже идёт от частного к общему (№ 3/4 раньше № 7/8, № 5 раньше № 6, № 6 → 7 → 8), а сам принцип «списывать по очереди до
обнуления» Прил. 3 задаёт в правиле № 1.
Пример: у A дебиторка на B 100; у B кредиторка на A 70 и долгосрочный заём (67) на A 50. Буквально: № 6 = 70,
№ 7 = 50, итого 120 — больше самой дебиторки. Каскадом: № 6 = 70, остаток A = 30; № 7 = min(30, 50) = 30; итого 100;
20 по 67 у B — расхождение, разбирается корректировкой.
**Упаковка строк** — какие строки ОСВ с какими сопоставлены (детализация и строки без пары). Правило охватывает
несколько счетов, поэтому строки сопоставляются группами **1:1, 1:N, N:1**; N:M нет, N ≤ 5. Выбирается **минимальная
упаковка** — группа с меньшим числом строк: если сумму закрывают и «1 Дт ↔ 2 Кт», и «1 Дт ↔ 3 Кт», берётся 1:2.
```
правила пары — по возрастанию rule_no; строка, сопоставленная в раннем правиле, в следующих не участвует
для k = 2 … 6 (число строк группы: 1:1, затем 1:2 и 2:1, … до 1:5 и 5:1):
кандидаты размера k из ещё не сопоставленных строк, закрывающие сумму:
сначала точные, затем с расхождением ≤ 5 % к меньшей — по возрастанию расхождения
группа без соперников → пара, её строки выбывают
две и более группы с тем же k и тем же расхождением, делящие строку (в том числе по разным правилам) → на ручное
оставшиеся строки → «без пары»
две и более группы с тем же k и тем же расхождением, делящие строку → на ручное (между правилами ничьей нет)
строки, не сопоставленные ни одним правилом → «без пары»
```
Способ упаковки сумму элиминации не меняет: в КФО идёт агрегат тройки.
@ -169,8 +184,8 @@ deviation_amount = |ΣA − ΣB|; deviation_percent = deviation_amount / min(ΣA
| нет второй стороны (ΣB = 0) | элиминируется 0, строки — «без пары» (вопрос В-4) |
| правило с `mode = manual` (№ 1, № 2) | автоматически не элиминируется, только корректировкой / гудвиллом |
Строка, чей счёт входит в несколько правил (дебет № 5–8; кредит 67.03 — № 3 и 7, 66.03 — № 4 и 8), попадает в сумму
стороны каждого из них — возможна двойная элиминация (вопрос В-12, OQ-169).
Суммы сторон — остатки после предыдущих правил пары (каскад, раздел 3.2), поэтому двойной элиминации по общим счетам
нет.
Алгоритм — по ТЗ (решение владельца 08.10.2026, OQ-155): пары, `min`, порог 5 %. Эталонный Excel «Консолидация_Группа
РБ» элиминирует у каждой компании полную сумму её строк на группу — это сознательное расхождение с эталоном.
@ -284,7 +299,8 @@ vgo_amount = eliminated_auto + eliminated_manual
выбирается). 62.01 «БП Аренда», 76.06, 76.АВ — без пары.
**Сумма элиминации (правило № 6):** ΣA = 110 429 113,15, ΣB = 106 311 116,46, расхождение 3,87 % ≤ 5 % →
элиминируется `min` = 106 311 116,46: статья 1230 у Счастливочной, 1520 у РБ.
элиминируется `min` = 106 311 116,46: статья 1230 у Счастливочной, 1520 у РБ. Это при условии, что у РБ нет 66.04 / 67.04
на Счастливочную: иначе по каскаду 76.06 и 76.АВ сначала уйдут в правило № 5, и ΣA правила № 6 уменьшится.
**76.АВ** (НДС по авансам) сейчас входит в дебиторку по правилу «76 кроме 76.07.5/76.07.9». Эталон его исключает —
вопрос OQ-164 (В-9).
@ -309,4 +325,4 @@ vgo_amount = eliminated_auto + eliminated_manual
| В-9 | 76.АВ / 76.ВА (НДС по авансам) — исключать из ДЗ / КЗ? Есть ли ещё такие субсчета 76? | OQ-164 открыт, вопрос в AURORA-1373 |
| В-10 | Округление при элиминации: рубли → тыс. руб. на выходе, ROUND_HALF_UP? | допущение OQ-26 |
| В-11 | Правило № 1: если у компании А нет ОСВ по 03 — результат в строку «ППА»? | открыто в §4 |
| В-12 | Счета правил пересекаются (дебет № 5–8; кредит 67.03 — № 3 и 7, 66.03 — № 4 и 8): строка входит в сумму стороны каждого правила, сумма элиминаций может превысить сумму стороны. Считать сумму правила только по строкам, которые упаковка отнесла к нему? Или распределять по правилам в фиксированном порядке? | OQ-169 открыт; AURORA-1536 считает по всем строкам счетов правила |
| В-12 | ~~Счета правил пересекаются — как избежать двойной элиминации?~~ | **решено 19.10.2026 (OQ-169):** каскад по остатку в порядке `rule_no` (раздел 3.2) |

View File

@ -482,38 +482,53 @@ closing_* = closing_* строки Qn
---
## §5. Автоматическое сопоставление ВГО (DOC-223044; OQ-07 — решение владельца 19.10.2026)
## §5. Автоматическое сопоставление ВГО (DOC-223044; OQ-07, OQ-169 — решения владельца 19.10.2026)
Границы: только `closing_debit` / `closing_credit`; только компании периметра версии; правила и счета сторон — из §4
(версия правил — `consolidation_version.elimination_rules_version`); строки `group_type = COUNTERPARTY`,
`data_type ∈ (BU, SUM)`. Единица расчёта — **тройка** (правило r, компания A, компания B).
`data_type ∈ (BU, SUM)`. Единица расчёта — **тройка** (правило r, компания A, компания B). Правила считаются для каждой
упорядоченной пары компаний — и (A, B), и (B, A); поэтому зеркальные правила № 9–16 Прил. 3 в seed не нужны (№ 14 для
(A, B) — это № 6 для (B, A)).
Два уровня: **сумма элиминации** по тройке — агрегат, идёт в КФО; **упаковка** — какие строки ОСВ с какими сопоставлены
(детализация, строки без пары). Способ упаковки сумму элиминации не меняет (решение владельца 19.10.2026).
**1. Сумма элиминации по тройке** (AURORA-1536):
**1. Сумма элиминации по тройке — каскадом по остатку** (AURORA-1536; OQ-169). Счета правил пересекаются (дебет
№ 5–8 общий; кредит 67.03 — № 3 и маска 67 у № 7, 66.03 — № 4 и маска 66 у № 8), и по буквальным формулам Прил. 3 одна
и та же сумма элиминировалась бы несколькими правилами. Поэтому правила пары (A, B) считаются **по порядку `rule_no`**, и
каждое берёт min из **остатка** сторон после предыдущих — тот же принцип, что Прил. 3 задаёт в правиле № 1 («сначала из
1450 до обнуления, остаток — из 1150, затем из 1550»). Порядок `rule_no` в Прил. 3 уже идёт от частного к общему:
№ 3/4 (58.03 ↔ 67.03 / 66.03) раньше № 7/8 (↔ 67 / 66), № 5 (76 ↔ проценты 66.04/67.04) раньше № 6 (↔ кредиторка),
№ 6 → № 7 → № 8 (дебиторка гасится кредиторкой, потом долгосрочными, потом краткосрочными займами). Отдельное поле
порядка не нужно.
```
ΣA = Σ стороны side_1 строк A с counterparty_id = B по счетам стороны 1 правила r (с исключениями is_excluded)
ΣB = Σ противоположной стороны строк B с counterparty_id = A по счетам стороны 2 правила r
deviation_amount = |ΣA − ΣB|; deviation_percent = deviation_amount / min(ΣA, ΣB) * 100
mode = min: расхождение ≤ 5 % → элиминируется min(ΣA, ΣB); > 5 % → подсветка, автоматически 0, ждёт корректировки
mode = manual: автоматически 0 — только корректировка / гудвилл (§8)
остаток(строка) = сумма строки (сторона side_1 у A по B, противоположная у B по A)
для r по возрастанию rule_no:
ΣA = Σ остатка строк A с counterparty_id = B по счетам стороны 1 правила r (с исключениями is_excluded)
ΣB = Σ остатка строк B с counterparty_id = A по счетам стороны 2 правила r
deviation_amount = |ΣA − ΣB|; deviation_percent = deviation_amount / min(ΣA, ΣB) * 100
mode = min: расхождение ≤ 5 % → элиминация_r = min(ΣA, ΣB); > 5 % → подсветка, элиминация_r = 0, ждёт корректировки
mode = manual: элиминация_r = 0 — только корректировка / гудвилл (§8)
остаток строк правила r на каждой стороне уменьшается на элиминация_r (по строкам — в порядке упаковки п. 2,
затем нераспределённые; на сумму КФО порядок внутри стороны не влияет)
```
Строка, чей счёт входит в несколько правил (дебет № 5–8; кредит 67.03 — № 3 и 7, 66.03 — № 4 и 8), попадает в Σ стороны
каждого из них — OQ-169.
Пример: у A дебиторка на B 100; у B кредиторка на A 70 и долгосрочный заём (67) на A 50. Буквально по Прил. 3:
№ 6 = 70, № 7 = 50, итого 120 — больше самой дебиторки. Каскадом: № 6 = min(100, 70) = 70, остаток A = 30;
№ 7 = min(30, 50) = 30; итого 100; 20 по 67 у B — расхождение пары, разбирается корректировкой.
**2. Упаковка строк в тройке** — группами **1:1, 1:N, N:1** (правило охватывает несколько счетов, поэтому одной
строке на одной стороне могут соответствовать несколько строк на другой). N:M нет. Выбирается **минимальная упаковка** —
группа с меньшим числом строк: если сумму закрывают и «1 Дт ↔ 2 Кт», и «1 Дт ↔ 3 Кт», берётся 1:2.
```
вход: строки a стороны 1 (A → B) и строки b стороны 2 (B → A) по счетам правила r; по каждому правилу — свой набор
правила пары (A, B) — по возрастанию rule_no; строка, сопоставленная в раннем правиле, в следующих не участвует
вход правила r: ещё не сопоставленные строки a стороны 1 (A → B) и b стороны 2 (B → A) по счетам правила r
для k = 2 … 6 (число строк группы: 1:1, затем 1:2 и 2:1, … до 1:5 и 5:1; N ≤ 5):
кандидаты размера k из ещё не сопоставленных строк, «закрывающие» сумму:
точные (Σ одной стороны == Σ другой), затем с расхождением ≤ 5 % к меньшей — по возрастанию расхождения
группа без соперников → пара, её строки выбывают
две и более группы с тем же k и тем же расхождением, делящие строку (в том числе по разным правилам) →
не сопоставляем, на ручное
оставшиеся строки → «без пары»
две и более группы с тем же k и тем же расхождением, делящие строку → не сопоставляем, на ручное
(между разными правилами ничьей нет — её решает порядок rule_no)
строки, не сопоставленные ни одним правилом → «без пары»
результат пары: rule, A, B, osv_entry.id обеих сторон, Σ A, Σ B, deviation_amount, deviation_percent
```
Результат **не хранится** (DECISION-5) — возвращается как структура для шахматки, корректировок и КФО. Ручное решение по
@ -523,7 +538,8 @@ mode = manual: автоматически 0 — только корректир
стороны, как в эталонном Excel. Пример на фикстурах (Q3 2024, правило № 6): у Счастливочной на «Русский бисквит» 62.01
«БП Производство» 106 311 116,46, 62.01 «БП Аренда» 1 401 330, 76.06 350 000, 76.АВ 2 366 666,69; у РБ — одна строка
60.01 106 311 116,46. Упаковка: точная пара 1:1 (106 311 116,46), остальные три строки Счастливочной — без пары.
Сумма элиминации: ΣA = 110 429 113,15, ΣB = 106 311 116,46, расхождение 3,87 % ≤ 5 % → min = 106 311 116,46.
Сумма элиминации: ΣA = 110 429 113,15, ΣB = 106 311 116,46, расхождение 3,87 % ≤ 5 % → min = 106 311 116,46 (если у РБ нет
66.04/67.04 на Счастливочную; иначе 76.06 и 76.АВ сначала уйдут в правило № 5 и ΣA правила № 6 уменьшится).
---

View File

@ -174,4 +174,4 @@
| OQ-166 | Упрощённая форма ББ/ОФР (приказ 66н, прил. 5): признак — по структуре кодов (ББ: есть 1600, нет 1100 и 1200; ОФР: есть 2400 или 2110, нет 2100, 2200, 2300), ОКУД 0710096 признаком не служит. Набор соотношений §7 и перечень кодов упрощённой формы заданы по бланку (`05-domain-rules.md` §7, решение S-5 спеки; ББ — жёсткие, ОФР `2400 = 2110 − 2120 − 2330 + 2340 − 2350 − 2410` — мягкое, как `2400` полного набора, решение владельца 18.10.2026, Р-22; перечни — `contracts/statement-code-orders.yaml`, у `fsbu4` — как у 66н) без образца в `fixtures/` | change `unified-statement-normalization`, design (Decisions № 14) | `arm_statements` `statement_checks.yaml`, перечень кодов, `form_variant` | открыт: допущение — формулы §7 «Упрощённый набор»; нужен реальный образец упрощённой отчётности (Excel и скан) в `fixtures/` для проверки признака и формул |
| OQ-167 | Несколько отчётных периодов в одном файле, отданном в ИС Сканирование (например, ББ за два квартала в одном PDF): шапка в json ИС одна на json и копируется во все его таблицы | change `unified-statement-normalization`, design шаг 1 (допущение владельца 17.10.2026) | scan-gateway (адаптер шага 1), период документа | допущение владельца: ИС отдаёт разные периоды разными json; образца нет — проверить на первом таком файле, при расхождении — шапка из json неверна для части таблиц |
| OQ-168 | Коды упорядоченного перечня форм без образца в `fixtures/` (`contracts/statement-code-orders.yaml`, §11.9): в перечень вошли только коды шаблонов банка и коды печатных форм 1С и сканов, найденные в `fixtures/` (1105, 1130, 1140, 1215, 1231, 1530, 2420, 2460, 2530, 2930, повторы 1220 / 1520 / 2410 у `fsbu4`, раздел III НКО у `66n`). Не подтверждены образцом: 1120 в `fsbu4`; 1105, 1215, 2420 в `66n`; 2421, 2430, 2450 (прежние строки ОФР 66н); 2930 и раздел III НКО в `fsbu4`; клиентский 1231 в `fsbu4`; упрощённые перечни обеих редакций (OQ-166). Добавлять ли их без образца | change `unified-statement-normalization`, ревью спеки K-5 (18.10.2026) | `arm_statements` (перечень кодов, структурное подтверждение неуверенного кода), ядро (`CODE_NOT_IN_EDITION`) | открыт до появления образцов; **временное правило принято владельцем 18.10.2026 (Р-26):** коды без образца (2421 / 2430 / 2450 в `66n`, 1120 и другие в `fsbu4`) в перечень не входят; неуверенный такой код на скане не подтверждается структурой — `needs_review` строки, `needs_check`; у Excel и уверенного кода — только `info` ядра `CODE_NOT_IN_EDITION`. Пополнение — строкой в yaml с источником (файл fixtures), когда образец появится |
| OQ-169 | Пересечение правил в сумме элиминации: счета сторон правил §4 пересекаются — дебет № 5–8 (76 у № 5; 60/62/76 у № 6–8), кредит: 67.03 (№ 3 и маска 67 у № 7), 66.03 (№ 4 и маска 66 у № 8), 66.04/67.04 (№ 5 и № 7/8). Строка такого счёта входит в Σ стороны каждого правила, и сумма min(ΣA, ΣB) по правилам может превысить Σ самой стороны — двойная элиминация. Считать ΣA правила только по строкам, которые упаковка (§5 п. 2) отнесла к этому правилу? Или распределять сторону по правилам в фиксированном порядке? | решение по OQ-07 (docs #136, 19.10.2026), описание AURORA-1536 | §5 п. 1, AURORA-1536, КФО (§8 `eliminated_auto`) | открыт: AURORA-1536 считает Σ сторон по всем строкам счетов правила; на фикстурах не проверялось |
| OQ-169 | Пересечение правил в сумме элиминации: счета сторон правил §4 пересекаются — дебет № 5–8 (76 у № 5; 60/62/76 у № 6–8), кредит: 67.03 (№ 3 и маска 67 у № 7), 66.03 (№ 4 и маска 66 у № 8), 66.04/67.04 (№ 5 и № 7/8). Строка такого счёта входит в Σ стороны каждого правила, и сумма min(ΣA, ΣB) по правилам может превысить Σ самой стороны — двойная элиминация. Считать ΣA правила только по строкам, которые упаковка (§5 п. 2) отнесла к этому правилу? Или распределять сторону по правилам в фиксированном порядке? | решение по OQ-07 (docs #136, 19.10.2026), описание AURORA-1536 | §5 п. 1, AURORA-1536, КФО (§8 `eliminated_auto`) | **закрыт решением владельца 19.10.2026 (docs #136):** каскад по остатку — правила пары (A, B) считаются по порядку `rule_no` (в Прил. 3 он уже от частного к общему: № 3/4 раньше № 7/8, № 5 раньше № 6, № 6 → 7 → 8), каждое берёт min из остатка сторон после предыдущих, как в правиле № 1 Прил. 3 («сначала из 1450 до обнуления…»); упаковка — в том же порядке, строка сопоставляется одним правилом; ничьей между правилами нет. Поле порядка не нужно. Алгоритм — `05-domain-rules.md` §5 |

View File

@ -60,7 +60,7 @@
| Файл | Что | Опирается на |
|---|---|---|
| `analyst/eliminations-vgo.md` | элиминация ВГО: что хранится и что считается (DECISION-5), раскладка правил `elimination_rule` / `elimination_rule_account` (Прил. 3/4), сопоставление пар, шахматка, путь до КФО, корректировки, гудвилл; пример на фикстурах РБ Q3 2024; вопросы В-1…В-12 (19.10.2026, #132; сопоставление по OQ-07 — #136) | DBML v5.19; §3–§6, §8 правил; DOC-223044, DOC-221277, DOC-227278, DOC-259025 |
| `analyst/eliminations-vgo.md` | элиминация ВГО: что хранится и что считается (DECISION-5), раскладка правил `elimination_rule` / `elimination_rule_account` (Прил. 3/4), сопоставление пар, шахматка, путь до КФО, корректировки, гудвилл; пример на фикстурах РБ Q3 2024; вопросы В-1…В-12 (19.10.2026, #132; сопоставление по OQ-07 и OQ-169 — #136) | DBML v5.19; §3–§6, §8 правил; DOC-223044, DOC-221277, DOC-227278, DOC-259025 |
## Макет UI