diff --git a/analyst/eliminations-vgo.md b/analyst/eliminations-vgo.md index 063ae9d..4db4648 100644 --- a/analyst/eliminations-vgo.md +++ b/analyst/eliminations-vgo.md @@ -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) | diff --git a/context/05-domain-rules.md b/context/05-domain-rules.md index 0be99d1..a6fbdf1 100644 --- a/context/05-domain-rules.md +++ b/context/05-domain-rules.md @@ -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 уменьшится). --- diff --git a/context/07-open-questions.md b/context/07-open-questions.md index e50af23..b6ed951 100644 --- a/context/07-open-questions.md +++ b/context/07-open-questions.md @@ -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 | diff --git a/context/08-source-docs-index.md b/context/08-source-docs-index.md index 12677c9..133bad0 100644 --- a/context/08-source-docs-index.md +++ b/context/08-source-docs-index.md @@ -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