diff --git a/analyst/eliminations-vgo.md b/analyst/eliminations-vgo.md new file mode 100644 index 0000000..91ac6e6 --- /dev/null +++ b/analyst/eliminations-vgo.md @@ -0,0 +1,301 @@ +# Элиминация ВГО: правила, расчёт, корректировки + +Документ для аналитика, 19.10.2026 (RSHB/arm-ka-docs#132). Основа — модель данных +[`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`, а этот документ поправь следом. Где написано наше прочтение ТЗ, а не прямая цитата, это +помечено; такие места собраны в раздел 6 вопросами. + +**Что нужно от аналитика:** подтвердить разделы 1–4 (или поправить) и ответить на вопросы раздела 6. Ответы попадают в +`05-domain-rules.md` и `07-open-questions.md`, затем — сюда. + +--- + +## 1. Что хранится в БД, а что считается + +Главный принцип модели (DECISION-5): **производные консолидации не хранятся, пока версия в работе**. Они каждый раз +считаются заново из первички, периметра версии и правил. В БД лежат только исходные данные и ручные решения аналитика. + +| Хранится | Что это | +|---|---| +| `osv_entry` | строки ОСВ как пришли из файла + сопоставленный контрагент (`counterparty_id`, `counterparty_match_kind`) | +| `consolidation_member`, `consolidation_document` | периметр версии и привязанные к ней документы | +| `elimination_rule`, `elimination_rule_account` | правила элиминации Прил. 3 / Прил. 4 (раздел 2) | +| `consolidation_version.elimination_rules_version` | по какой версии правил считалась версия консолидации | +| `correction` | ручные корректировки аналитика (раздел 4) | +| `goodwill` | гудвилл: доля владения, решение «учитывать в КФО», комментарий | +| `kfo_result`, `kfo_result_line` | результат КФО | + +| Не хранится, считается на лету | Почему | +|---|---| +| сводная ОСВ, признак контрагента ГСК / ГК / Внешний | функция от `osv_entry` и периметра версии | +| пары ВГО (кто с кем сопоставлен, по какому правилу, суммы сторон, расхождение, id строк ОСВ) | функция от `osv_entry` × периметр × правила | +| шахматка | функция от `osv_entry` × периметр × выбранный набор счетов | +| суммы «с учётом корректировок» | сумма пары ± применённые корректировки | + +Таблиц сопоставления в модели нет: `vgo_match` (строки 1:1) убрана в v5.3 — её нет ни в ТЗ, ни в UI; агрегат +`vgo_pair_match` убран в v5.10 по DECISION-5. + +**Заморозка.** При переходе версии в `VERIFIED` всё посчитанное фиксируется один раз в `ex_snapshot_item.payload` +(jsonb, `item_type` = `vgo_pairs`, `chess`, `corrections`, `goodwill`, `kfo_balance`, `kfo_income`, `summary_osv`). +Срез самодостаточен и не ссылается на таблицы консолидации. Версия после `VERIFIED` — только чтение; изменения — через +новую версию консолидации. + +--- + +## 2. Как разложены правила элиминации + +Правила — **данные, а не код**: две таблицы, версионируются. + +### 2.1. `elimination_rule` — одна строка приложения + +| Поле | Значение | +|---|---| +| `statement_type` | `balance` — Прил. 3 (ББ), `income` — Прил. 4 (ОФР) | +| `rule_no` | № строки приложения | +| `article_1_line` | статья Компании 1 — код строки ББ/ОФР (например, `1230`) | +| `article_2_line` | статья Компании 2 (например, `1520`) | +| `side_1` | сторона Компании 1: `D` или `K` (у Компании 2 — противоположная) | +| `measure` | `closing` — сальдо на конец (ББ), `turnover` — оборот (ОФР) | +| `elimination_mode` | `min` — min(A, B); `full` — вся сумма стороны А (выручка ОФР); `manual` — только вручную | +| `vat_handling` | только ОФР: `none` / `check_90_01_vs_2110` / `weighted_rate` | +| `excise_adjust` | учитывать акциз | +| `version_no`, `valid_from`, `valid_to` | версия набора правил; уникально (`statement_type`, `rule_no`, `version_no`) | + +### 2.2. `elimination_rule_account` — счета сторон правила + +| Поле | Значение | +|---|---| +| `rule_id` | правило | +| `company_no` | `1` или `2` — сторона | +| `account_id` | счёт или субсчёт из плана счетов (`chart_of_account`) | +| `is_excluded` | `true` — исключение внутри маски («76 кроме 76.07.1») | + +Счёт-родитель покрывает свои субсчета (иерархия `chart_of_account.parent_id`), исключения перечисляются отдельными +строками с `is_excluded = true`. + +**Пример — правило № 6 ББ** (основная пара «дебиторка ↔ кредиторка»): + +| `company_no` | `account` | `is_excluded` | +|---|---|---| +| 1 | 60.02, 60.22, 60.32, 62.01, 62.03, 62.21, 62.31 | false | +| 1 | 76 | false | +| 1 | 76.07.5, 76.07.9 | **true** | +| 2 | 60.01, 60.03, 60.21, 60.31, 62.02, 62.22, 62.32 | false | +| 2 | 76 | false | +| 2 | 76.07.1 | **true** | + +(каждый счёт — отдельная строка таблицы; в примере сгруппированы для краткости) + +### 2.3. Версии правил + +Правила меняются выпуском новой версии (`version_no`), старая не правится. Версия, по которой посчитана версия +консолидации, фиксируется в `consolidation_version.elimination_rules_version` при первом расчёте и замораживается при +`VERIFIED` — так расчёт верифицированной версии объясним и воспроизводим, даже если правила потом поменялись. + +### 2.4. Стартовый набор — Прил. 3 (ББ, `measure = closing`) + +| № | Статья А (Дт) | Счета А | Статья Б (Кт) | Счета Б | mode | Примечание | +|---|---|---|---|---|---|---| +| 1 | 1150 ОС | 03, 76.07.9 (01 — резервный) | 1450 / 1550 | 76.07.1 | manual | лизинг/аренда внутри группы; у Б: 76.07.1 − 76.07.5 − 76.07.9 | +| 2 | 1170 ФВ долгосрочные | 58.01 | 1310 / 1350 | 80, 83 | manual | гудвилл (раздел 4.5) | +| 3 | 1170 ФВ долгосрочные | 58.03 | 1410 Займы долгосрочные | 67.03 | min | | +| 4 | 1240 ФВ краткосрочные | 58.03 | 1510 Займы краткосрочные | 66.03 | min | | +| 5 | 1230 Дебиторка | 76 (кроме 76.07.5, 76.07.9) | 1510 | 66.04, 67.04 | min | проценты | +| 6 | 1230 Дебиторка | 60.02, 60.22, 60.32, 62.01, 62.03, 62.21, 62.31, 76 (кроме 76.07.5, 76.07.9) | 1520 Кредиторка | 60.01, 60.03, 60.21, 60.31, 62.02, 62.22, 62.32, 76 (кроме 76.07.1) | min | основная пара | +| 7 | 1230 Дебиторка | те же, что № 6 | 1410 | 67 | min | | +| 8 | 1230 Дебиторка | те же, что № 6 | 1510 | 66 | min | | + +### 2.5. Прил. 4 (ОФР, `measure = turnover`) — не формализовано + +| Статья | Сторона А | Сторона Б | mode / НДС | +|---|---|---|---| +| 2110 Выручка | Кт 90.01 (с НДС, приоритет) либо Дт 62.01/62.21/62.31 | Кт 60.01/60.21/60.31 + 76 (кроме 76.07.*, 76.03.*, плюс 76.07.2) | `full`; без НДС = с НДС / (1 + средневзвешенная ставка / 100) | +| 2120 Себестоимость | — | — | = ВГО по 2110, зеркально, без НДС | +| 2310 Доходы от участия | Дт 76.03 | Кт 76.03 | сторона А | +| 2320 Проценты к получению | Дт 76.03/76.05/76.08/76.09 | Кт 66.02/.04/.06/.22/.24/.26, 67.02/.04/.06/.22/.24/.26 | min | +| 2330 Проценты к уплате | Кт чётных субсчетов 66/67 + 76.07.5/76.08/76.28/76.38 | Дт 76.03/.05/.08/.09 | min | + +Это выжимка из FNR03; в правила-данные её можно превратить только после формализации с методологами (вопрос В-8). + +--- + +## 3. Как считаем + +### 3.1. Вход + +- Периметр — `consolidation_member` версии (не текущий состав ГСК). +- ОСВ — документы, привязанные к версии (`consolidation_document`), только `CONFIRMED`. +- Строки — `group_type = COUNTERPARTY`, `data_type ∈ (BU, SUM)`, контрагент сопоставлен с ЮЛ **из периметра**. +- Для ББ — только сальдо на конец (`closing_debit` / `closing_credit`). + +### 3.2. Автоматическое сопоставление пар (DOC-223044, `05-domain-rules.md` §5) + +``` +для каждой строки a компании A с контрагентом B из периметра: + сторона a = closing_debit, если > 0, иначе closing_credit + кандидаты = строки b компании B с контрагентом A, противоположная сторона, + (счёт a, счёт b) входит в пару счетов правила r — по каждому правилу отдельно + 1. точное совпадение сумм, единственный вариант → пара, обе строки выбывают + 2. несколько точных по РАЗНЫМ правилам → не сопоставляем, на ручное + 3. точного нет: по каждому правилу — минимальное |a − b|; берём правило с наименьшим расхождением; + равные минимумы по разным правилам → не сопоставляем, на ручное +``` + +Сопоставление **1:1**: строка участвует в одной паре целиком. Агрегировать ли строки перед сопоставлением — открыто +(вопрос В-2). + +**Результат пары** (структура в памяти, в БД не пишется): правило, компания A, компания B, сумма A, сумма B, +`deviation_amount = |A − B|`, `deviation_percent = deviation / min(A, B) × 100`, id строк `osv_entry` обеих сторон. + +### 3.3. Сколько элиминируется по паре + +| Ситуация | Что происходит | +|---|---| +| суммы равны | пара сопоставлена, элиминируется сумма | +| расхождение ≤ 5 % (к меньшей) | пара сопоставлена, элиминируется `min(A, B)` | +| расхождение > 5 % | подсветка, автоматически не элиминируется, ждёт корректировки | +| неоднозначность (несколько правил) | не сопоставляется, на ручное решение | +| нет встречной строки | пара без второй стороны — вопрос В-4 | +| правило с `mode = manual` (№ 1, № 2) | автоматически не элиминируется, только корректировкой / гудвиллом | + +Алгоритм — по ТЗ (решение владельца 08.10.2026, OQ-155): пары, `min`, порог 5 %. Эталонный Excel «Консолидация_Группа +РБ» элиминирует у каждой компании полную сумму её строк на группу — это сознательное расхождение с эталоном. + +**Куда идёт сумма** (наше прочтение — подтвердить, В-3): элиминируемая сумма пары уменьшает статью `article_1_line` у +Компании 1 и статью `article_2_line` у Компании 2. + +### 3.4. Шахматка (DOC-221277, `05-domain-rules.md` §6) + +Шахматка — **сверочный инструмент**, она ничего не элиминирует. Строки и столбцы — компании периметра, диагональ пуста. + +``` +amount_a(A,B) = Σ closing_debit строк A с контрагентом B по выбранным дебетовым счетам (kind ∈ A, AP) +amount_b(A,B) = Σ closing_credit строк B с контрагентом A по выбранным кредитовым счетам (kind ∈ P, AP) +variance = |amount_a − amount_b|; variance_pct = variance / min(amount_a, amount_b) × 100; > 5 % — подсветка +``` + +Предустановки — **наборы счетов**: «58.03 vs 67.03 + 66.03», «60 + 62 + 76 vs 60 + 62 + 76», «все счета». Так +решено 15.10.2026 и так сделано в arm-core (AURORA-1537): шахматка — по наборам счетов, а пары по правилам Прил. 3, +элиминируемая сумма и версия правил — отдельная задача AURORA-1536 (§5). Шахматка по правилу элиминации — вопрос В-1. + +Результирующая таблица «компания против группы» по статьям: Дебиторка, Кредиторка, ФВ, Долгосрочные займы, +Краткосрочные займы; колонка «Итого по группе» (состав счетов — §6). + +### 3.5. Путь до КФО (`05-domain-rules.md` §8) + +По каждому коду строки ББ/ОФР: + +``` +sum_amount = Σ по компаниям периметра (отчётная колонка ББ / ОФР, тыс. руб.) +eliminated_auto = элиминация по парам (3.2–3.3), в тыс. руб. +eliminated_manual = Σ корректировок со статусом APPLIED +goodwill_adjust = гудвилл, если «учитывать в КФО» +consolidated = sum_amount − eliminated_auto − eliminated_manual ± goodwill_adjust +vgo_amount = eliminated_auto + eliminated_manual +``` + +Единицы: ОСВ — рубли, ББ/ОФР — тыс. руб.; считаем в рублях, округляем до тыс. на выходе (допущение OQ-26, В-10). +Пороги существенности (ТЗ 6.8): ББ — 1 % валюты баланса или 10 % ЧА; ОФР — 1 % выручки или 10 % валовой прибыли; +превышение требует обоснования (`threshold_justification`). + +--- + +## 4. Как производятся корректировки + +### 4.1. Принцип + +Корректировка — **наложение поверх первички**: строки ОСВ и формы не меняются, итог = свод первички − Σ применённых +корректировок. Корректировка — единственное, что аналитик хранит по паре ВГО; сама пара не хранится. + +### 4.2. Привязка к паре + +Корректировка ссылается на пару **по естественному ключу**, а не на id строк ОСВ: + +`(consolidation_version_id, rule_id, legal_entity_id, counterparty_id)` + `statement_type` + +- `rule_id` — правило; `NULL` — ручная корректировка без пары; +- `legal_entity_id` — компания 1 (чья первичка корректируется); +- `counterparty_id` — компания 2. + +Благодаря этому корректировка переживает пересчёт: пары каждый раз строятся заново, а корректировка находит свою пару по +ключу. Что делать, если пара после перезагрузки ОСВ исчезла, — вопрос В-6. + +### 4.3. Поля `correction` + +| Поле | Значение | +|---|---| +| `statement_type` | ББ или ОФР (ТЗ 6.8 — отдельные формы) | +| `debit_line_code`, `debit_account_id`, `debit_adjustment` | дебетовая сторона: строка формы, счёт, сумма | +| `credit_line_code`, `credit_account_id`, `credit_adjustment` | кредитовая сторона | +| `deviation_amount`, `deviation_percent` | расхождение пары — справочно, пересчитывается | +| `reason_code` | ТЗ 6.4: нереализованная выручка, акциз, агентское вознаграждение, амортизация по внутригрупповой аренде, проценты по внутригрупповым займам, доходы от участия, прочее | +| `comment` | **обязателен** (ТЗ 6.8) | +| `status` | `DRAFT` → `APPLIED` / `REVOKED`; в расчёт входят только `APPLIED` | +| `parent_correction_id` | распределение суммы одной стороны по нескольким статьям — дочерние записи, глубина 1 | +| `version_no` | растёт при каждом изменении | + +### 4.4. Правила + +- **Контроль полноты:** `Σ debit_adjustment ≈ Σ credit_adjustment` (±5 %), иначе ВГО распределено не полностью. +- **История:** каждое изменение — `audit_event(CORRECTION_*)` со значениями до/после, `version_no++` (сноска 22 ТЗ). +- **Кто и когда:** право `CONSOLIDATION_EDIT`, версия «в работе», своя блокировка версии. После `VERIFIED` — только + чтение. +- **Типичный сценарий:** пара с расхождением > 5 % → аналитик разбирается в причине → создаёт корректировку по паре с + причиной и комментарием → применяет (`APPLIED`) → КФО пересчитывается. + +### 4.5. Гудвилл (правило № 2) — отдельно от корректировок + +Таблица `goodwill`, по каждой паре ГО → ДО периметра: `FV = Σ closing_debit 58.01` (контрагент ДО), `UK = 1310 ББ ДО` +(FNR03: Кт 80 + Кт 83, при отсутствии — 1310), `share` — ручной ввод, `participation = 1310 × share / 100`, +`goodwill = FV − participation` (может быть < 0), `include_in_kfo` + обязательный комментарий. Положительный итог — +строка «Гудвилл» в разделе I КФО. + +--- + +## 5. Сквозной пример: «Пекарня Счастливочная» ↔ «Русский бисквит», 30.09.2024 + +Данные — фикстуры, ОСВ Q3 2024. Строки Счастливочной с контрагентом «Русский бисквит» на дебетовых счетах правила № 6: + +| Счёт | Аналитика | Сумма, руб. | +|---|---|---| +| 62.01 | «БП Производство» | 106 311 116,46 | +| 62.01 | «БП Аренда» | 1 401 330,00 | +| 76.06 | | 350 000,00 | +| 76.АВ | НДС по авансам | 2 366 666,69 | + +У «Русского бисквита» — одна строка 60.01 (кредиторка) на Счастливочную: 106 311 116,46. + +**Как сопоставится (строго 1:1):** + +1. 62.01 «БП Производство» 106 311 116,46 ↔ 60.01 РБ 106 311 116,46 — точное совпадение по правилу № 6 → пара, + элиминируется 106 311 116,46: статья 1230 у Счастливочной, 1520 у РБ. +2. 62.01 «БП Аренда», 76.06, 76.АВ — встречных строк у РБ нет → без пары, остаются в 1230 Счастливочной (В-4). + +**Если агрегировать перед сопоставлением (В-2):** 62.01 = 106 311 116,46 + 1 401 330 = 107 712 446,46 против +106 311 116,46 — расхождение 1,32 % ≤ 5 % → пара, элиминируется `min` = 106 311 116,46. Сумма та же, но строка +«БП Аренда» уже не висит отдельно, а входит в пару с расхождением. + +**76.АВ** (НДС по авансам) сейчас входит в дебиторку по правилу «76 кроме 76.07.5/76.07.9». Эталон его исключает — +вопрос OQ-164 (В-9). + +**Эталон** («Консолидация_Группа РБ.xlsx», лист `01.10.2024`) элиминирует у Счастливочной 108 062 тыс. — всё, кроме +76.АВ. Разница с нашим расчётом (1 751 тыс. = 1 401 330 + 350 000) — ожидаемая (OQ-155). + +--- + +## 6. Вопросы к аналитику + +| № | Вопрос | Что сейчас | +|---|---|---| +| В-1 | Шахматка: предустановки — наборы счетов (§6) или правила элиминации? Если правила — как быть с «58.03 vs 67.03 + 66.03» (это правила № 3 и № 4 сразу) и «все счета» (не правило)? | решено 15.10: наборы счетов, сделано (AURORA-1537); правила — в сопоставлении пар (AURORA-1536) | +| В-2 | Сопоставление строго 1:1 по строкам (DOC-223044) или с агрегацией по (компания, контрагент, счёт, сторона) (FNR03)? Или гибрид: сначала точные 1:1, потом агрегация остатка? | OQ-07 открыт | +| В-3 | Элиминация списывается со статей `article_1_line` / `article_2_line` правила? Как выбирать статью у правил с двумя статьями: «1450 / 1550» (№ 1), «1310 / 1350» (№ 2)? | наше прочтение, не подтверждено | +| В-4 | Строка без встречной стороны (у второй компании нет строки на первую): не элиминируется до корректировки, элиминируется целиком или показывается как отдельная категория? | подсвечивается как пара без второй стороны | +| В-5 | Корректировка по паре добавляется к автоматической элиминации или заменяет её? Как проводится корректировка «односторонней» пары, если контроль требует Σ Дт ≈ Σ Кт (±5 %)? | по §8: добавляется (`eliminated_manual` отдельно от `eliminated_auto`) | +| В-6 | Пара исчезла после перезагрузки ОСВ (суммы изменились, пара не собралась) — что с её корректировками: остаются, помечаются, снимаются? | не описано | +| В-7 | Средневзвешенная ставка НДС для выручки ОФР: ставка считается из ОСВ (по какому правилу) или вводится вручную? Хранить её негде: в модели она жила в `vgo_pair_match`, убранной в v5.10 | не описано | +| В-8 | Правила ОФР (Прил. 4): нужна формализация с методологами — счета сторон, режимы, НДС, акциз | открыто | +| В-9 | 76.АВ / 76.ВА (НДС по авансам) — исключать из ДЗ / КЗ? Есть ли ещё такие субсчета 76? | OQ-164 открыт, вопрос в AURORA-1373 | +| В-10 | Округление при элиминации: рубли → тыс. руб. на выходе, ROUND_HALF_UP? | допущение OQ-26 | +| В-11 | Правило № 1: если у компании А нет ОСВ по 03 — результат в строку «ППА»? | открыто в §4 | diff --git a/context/08-source-docs-index.md b/context/08-source-docs-index.md index 44091e7..de6b23b 100644 --- a/context/08-source-docs-index.md +++ b/context/08-source-docs-index.md @@ -53,6 +53,15 @@ | `diagrams/part01…09.{svg,png}` | диаграммы v5.19 по частям; перерисовываются `make diagrams` (`scripts/gen_model_diagrams.py`) | | `source/tz/data-model-part1_4.dbml` (лежит не в `model/`, а в экспорте ТЗ) | v4 часть 1 — историческое | +## Материалы для аналитика (`docs/analyst/`) + +Наши документы для аналитика заказчика: выжимка модели и правил по одной теме с вопросами. Источником истины не являются +— при расхождении правы DBML и `05-domain-rules.md`, документ правится следом. + +| Файл | Что | Опирается на | +|---|---|---| +| `analyst/eliminations-vgo.md` | элиминация ВГО: что хранится и что считается (DECISION-5), раскладка правил `elimination_rule` / `elimination_rule_account` (Прил. 3/4), сопоставление пар, шахматка, путь до КФО, корректировки, гудвилл; пример на фикстурах РБ Q3 2024; вопросы В-1…В-11 (19.10.2026, #132) | DBML v5.19; §3–§6, §8 правил; DOC-223044, DOC-221277, DOC-227278, DOC-259025 | + ## Макет UI `dkb_24.09.26` — HTML-макет экранов (у пользователя; в экспорт не вошёл). В DBML ссылки «Макет: …» указывают на экран