Плоская форма ОСВ 1С: счёт из шапки, «Итого развернутое», плоский список, контрагенты расчётных счетов (#59) #63

Merged
aep merged 16 commits from feat/59-osv-flat-form into main 2026-10-19 13:21:55 +03:00
5 changed files with 43 additions and 26 deletions
Showing only changes of commit 7cd71677da - Show all commits

View File

@ -182,10 +182,12 @@ ParseOutcome`. Структура ОСВ ищется **по содержимо
показывает счёт нетто, а субсчета и контрагентов — развёрнуто (решение R-21, design №31). Остаточный риск: перестановка
сторон при совпавшем нетто родителя этой проверкой не ловится — её ловят тождество строки и «Итого = корень».
**«Итого».** Основная итоговая строка — первая TOTAL, не являющаяся показателем; она сверяется с первым корнем ACCOUNT либо, если корней
**«Итого».** Основная итоговая строка — первая TOTAL листа, не являющаяся показателем и не «Итого развернутое»; она сверяется с первым корнем ACCOUNT либо, если корней
уровня 0 несколько (лист без строки корневого счёта: верхний уровень — субсчета 58.01, 58.03), с суммой строк уровня 0
(OQ-106, OQ-133; сальдо — по колонкам либо по нетто, если «Итого» свёрнуто, как у родителя выше). Вторая итоговая
строка сразу за «Итого» («Итого развернутое», `total_row_secondary`) — тоже `TOTAL`, в сверку «Итого» и в тождество строки не входит (в 1С у неё только сальдо, без оборотов). Строка сумм
строка в итоговом блоке, и перед «Итого», и после неё («Итого развернутое», `total_row_secondary`), — тоже `TOTAL`, в сверку
«Итого» не входит. Тождество строки на ней пропускается, только если обороты пусты и на листе есть другая «Итого» (перед
«Итого» в 1С только развёрнутые сальдо); с оборотами или единственная итоговая — проверяется как обычная. Строка сумм
без подписи в конце таблицы (1С без «Итого») принимается за итоговую с предупреждением.
**ИНН контрагента** (OQ-100, OQ-130): `counterparty_inn` берётся из колонки ИНН (в том числе склеенного «ИНН/КПП»), затем из

View File

@ -51,7 +51,7 @@
- `s40`: r2 «Оборотно-сальдовая ведомость по счету: 76.Н.1», r3 «Контрагенты», r4 «за 2025 г.», r5 «ООО "Товарное хозяйство"», r7 «Единица измерения: рубль (код по ОКЕИ 383)», r9 «Субконто» + группы, r10 подзаголовки; данные без outline и отступов: «Август - Агро ООО» 1000.00 | — | 500.00 | 300.00 | 1200.00 | —; «АВИС ООО» — | 200.00 | 100.00 | 400.00 | — | 500.00; «Агроаспект ООО» — | — | 50.00 | 50.00 | — | —; «Итого развернутое» 1000.00 | 200.00 | — | — | 1200.00 | 500.00; «Итого» 800.00 | — | 650.00 | 750.00 | 700.00 | —.
- `s41`: r2 «Оборотно-сальдовая ведомость по счету: 60», r3 «Организации», r4 «за 2 Квартал 2026 г. План счетов ООО Хреновская Нива», r5 «Субконто» + группы, r6 подзаголовки; «Автодор-Платные Дороги ООО» 820.21 | — | 5000.00 | 4991.00 | 829.21 | —; «АГРОПРОФИ ООО» — | 2763.79 | — | — | — | 2763.79; «Итого развернутое» 820.21 | 2763.79 | — | — | 829.21 | 2763.79; «Итого» — | 1943.58 | 5000.00 | 4991.00 | — | 1934.58.
- `s42`: r2 «Оборотно-сальдовая ведомость по счету: 76», r3 «за 2025 г.», r4 «ООО "Товарное хозяйство"», r6 «Единица измерения: рубль (код по ОКЕИ 383)», r8 «Субконто» + группы, r9 подзаголовки; «76.2» 1000.00 | — | — | 1000.00 | — | —; «76.5» — | 300.00 | 700.00 | 600.00 | — | 200.00; «76.Н» — | — | 5000.00 | 5000.00 | — | —; «76.Н.1» — | — | 5000.00 | 5000.00 | — | —; «Итого развернутое» 1000.00 | 300.00 | — | — | — | 200.00; «Итого» 700.00 | — | 5700.00 | 6600.00 | — | 200.00.
- `s43`: r1 «ООО "Октябрьское"», r2 «Оборотно-сальдовая ведомость по счету 60», r3 «Период: 9 месяцев 2024 г.», r5 «Субконто» + группы, r6 подзаголовки; «60.01» 34618000.00 | — | 4236500.00 | 38854500.00 | — | —; отступ 1: «ИП Знаменских А.И.» 34618000.00 | — | — | 34618000.00 | — | —; отступ 1: «ООО "ЭСТЕТ ОМСК"» — | — | 4236500.00 | 4236500.00 | — | —; «Итого» и затем «Итого развернутое» — обе 34618000.00 | — | 4236500.00 | 38854500.00 | — | —.
- `s43`: r1 «ООО "Октябрьское"», r2 «Оборотно-сальдовая ведомость по счету 60», r3 «Период: 9 месяцев 2024 г.», r5 «Субконто» + группы, r6 подзаголовки; «60.01» 34618000.00 | — | 4236500.00 | 38854500.00 | — | —; отступ 1: «ИП Иванов А.А.» 34618000.00 | — | — | 34618000.00 | — | —; отступ 1: «ООО "ЭСТЕТ ОМСК"» — | — | 4236500.00 | 4236500.00 | — | —; «Итого» и затем «Итого развернутое» — обе 34618000.00 | — | 4236500.00 | 38854500.00 | — | —.
- `s44`: как `s43`, но счёт 10: r2 «…по счету 10», «10.01» и строки «Мука пшеничная», «Сахар-песок» с теми же суммами.
- [ ] **Step 1: Добавить `_s40`…`_s44` и записи реестра**, по образцу `_s31`/`_s32` (листы через `SheetSpec`/`put`, отступ — `CellSpec(..., indent=1)`).
@ -179,11 +179,11 @@ git -C /Users/andrey.epifancev/projects/awp-ca/.wt/osv-flat/tabular-parser commi
- [ ] **Step 1: Тесты (падают)**
- `test_rules.py::test_counterparty_accounts_match_code_and_subaccounts`: `is_counterparty_account("76.Н.1")`, `("60.01")` — `True`; `("760")`, `("600")`, `("10.01")`, `(None)` — `False` (Review Focus 5).
- `test_classify.py::test_unnamed_first_level_on_settlement_account_is_counterparty`: схема `[ACCOUNT("Субконто")]`, «60.01» → «ИП Знаменских А.И.» (уровень 1) → COUNTERPARTY, `group_name is None`, `counterparty_name == "ИП Знаменских А.И."`, `counterparty_by_account is True`.
- `test_classify.py::test_unnamed_first_level_on_settlement_account_is_counterparty`: схема `[ACCOUNT("Субконто")]`, «60.01» → «ИП Иванов А.А.» (уровень 1) → COUNTERPARTY, `group_name is None`, `counterparty_name == "ИП Иванов А.А."`, `counterparty_by_account is True`.
- `test_unnamed_second_level_stays_other`: под таким контрагентом строка уровня 2 → OTHER.
- `test_named_other_group_is_not_reclassified`: схема `[ACCOUNT, OTHER("Работники организаций")]` на 71 → OTHER.
- `test_non_settlement_account_stays_other`: счёт «10.01» → OTHER, `counterparty_by_account is False`.
- `test_osv_flat_form.py::test_s43_counterparties_with_warning`: разбор `s43` → строки «ИП Знаменских А.И.», «ООО "ЭСТЕТ ОМСК"» — COUNTERPARTY; в `warnings` ровно одно `OSV_ROWS` с текстом «вид субконто в шапке не назван: строки аналитики счёта 60.01 приняты за контрагентов по плану счетов — проверьте»; `status == "done"`.
- `test_osv_flat_form.py::test_s43_counterparties_with_warning`: разбор `s43` → строки «ИП Иванов А.А.», «ООО "ЭСТЕТ ОМСК"» — COUNTERPARTY; в `warnings` ровно одно `OSV_ROWS` с текстом «вид субконто в шапке не назван: строки аналитики счёта 60.01 приняты за контрагентов по плану счетов — проверьте»; `status == "done"`.
- `test_s44_materials_stay_other`: разбор `s44` → строки OTHER, предупреждения «вид субконто…» нет.
- `test_s41_flat_counterparties`: разбор `s41` → строки данных COUNTERPARTY (по схеме с видом «Организации», R-10), `account_code_raw == "60"`, предупреждения «вид субконто…» нет.
- [ ] **Step 2: Запуск — FAIL.**

View File

@ -30,7 +30,8 @@ r11 Август - Агро ООО | … суммы … ← с
**Goals:** разбор плоской формы без `INVALID_FORMAT`; счёт и организация из шапки; «Итого развернутое» — итог в любом
порядке; контрагенты расчётных счетов видны ядру как `COUNTERPARTY`.
**Non-Goals:** см. proposal (валюта и `data_type` — трек A; «Учредители»; «Организации» по имени).
**Non-Goals:** см. proposal (валюта и `data_type` — трек A; «Учредители»; прочие неизвестные виды субконто; «Организации»
узнаются только как синоним COUNTERPARTY по множественному числу, R-10, R-17).
## Decisions
@ -50,8 +51,8 @@ r11 Август - Агро ООО | … суммы … ← с
- **Строка вида субконто** — ячейки шапки строго между строкой названия (ячейка с меткой `account`) и строкой периода
(`_find_period`), если название выше периода. Они не кандидаты в организацию. Их текст (через запятую) — виды
субконто: элемент, который `rules.groups` узнаёт **явной** записью `mapping` (не `default`), добавляется в схему
после ACCOUNT, если схема варианта 1 состоит из одной ACCOUNT («Субконто»). Неузнанный элемент («Организации»,
«Материалы») в схему не добавляется.
после ACCOUNT, если схема варианта 1 состоит из одной ACCOUNT («Субконто»). Неузнанный элемент («Материалы»,
единственное «Организация» — R-17) в схему не добавляется; «Организации» узнаётся как COUNTERPARTY (R-10, R-17).
- **Организация** — порядок: хвост метки «План счетов» (`header_markers.chart_of_accounts`, новый ключ) → первая
не-метка шапки без строки вида субконто → хвост названия ведомости (как сейчас).
- **Итоговый блок** — `collect_body_rows` возвращает номером «Итого» **первую** строку итогового блока: вторые итоговые
@ -71,38 +72,43 @@ r11 Август - Агро ООО | … суммы … ← с
- **Контрагенты по плану счетов** — `osv_groups.yaml: counterparty_accounts` (коды верхнего уровня; запись `76`
покрывает `76`, `76.2`, `76.Н.1`, но не `760` — как `accounts_without_analytic_balance`). В `_classify_row`: позиция
`1` (первая не-счётная) за пределами схемы и счёт ветки из списка → `COUNTERPARTY` без имени группировки; ИНН — по
общим правилам (колонка, строка ИНН, хвост названия). Глубже — `OTHER`, как сейчас. Предупреждение один раз на
документ (`OSV_ROWS`, `osv.py`): «вид субконто в шапке не назван: строки аналитики счёта <код> приняты за контрагентов
по плану счетов — проверьте».
общим правилам (колонка, строка ИНН, хвост названия). Глубже — `OTHER`, как сейчас. Строка, которую словарь групп
явно знает как не-COUNTERPARTY (валюта), остаётся `OTHER` (R-18). Предупреждение по одному на счёт (R-13; `OSV_ROWS`,
`osv.py`): «вид субконто в шапке не назван: строки аналитики счёта <код> приняты за контрагентов по плану счетов —
проверьте».
## Decisions made without discussion
| № | Маркер | Дата | Решение | Обоснование | Цена ошибки |
|---|---|---|---|---|---|
| 1 | R-1 | 19.10.2026 | Строка между названием и периодом — вид субконто, не организация | 6 из 98 xlsx контура (все — «Контрагенты»), в `fixtures` таких строк нет — регрессии golden нет | Организация, напечатанная между названием и периодом, не найдётся: предупреждение «наименование организации не найдено», ядро сверяет по ИНН |
| 2 | R-2 | 19.10.2026 | Известный вид субконто из этой строки — группировка схемы; неизвестный — не добавляется | «Контрагенты» даёт COUNTERPARTY с именем без угадывания по счёту; «Организации» у письма (60) — неизвестно, что это за вид | Неизвестный вид на нерасчётном счёте остаётся OTHER без имени (как сейчас) |
| 2 | R-2 | 19.10.2026 | Известный вид субконто из этой строки — группировка схемы; неизвестный — не добавляется | «Контрагенты» даёт COUNTERPARTY с именем без угадывания по счёту; «Материалы» — не контрагенты (вид «Организации» затем узнан R-10, R-17) | Неизвестный вид на нерасчётном счёте остаётся OTHER без имени (как сейчас) |
| 3 | R-3 | 19.10.2026 | `header_account` — перед `sums`, только без строк-счетов и при счёте в шапке | Плоский список с равными суммами соседей `sums` вложил бы ложно; условие — определение плоской формы 1С | Файл без оформления и счетов, но с реальной вложенностью по суммам станет плоским → «Итого» не сойдётся → `needs_check` (видно) |
| 4 | R-4 | 19.10.2026 | Корень ветки наследует счёт шапки | Ядро группирует свод по `account_code`; без этого у строк плоского файла счёт `null` | Строки до первой строки-счёта в обычных файлах получат счёт шапки вместо `null` (golden покажет) |
| 5 | R-5 | 19.10.2026 | «Итого» без корня ACCOUNT сверяется с суммой уровня 0 | Плоский список — несколько корней без счёта; прежнее R-13 требовало нулевой «Итого» | — (пустая ОСВ — прежнее правило) |
| 6 | R-6 | 19.10.2026 | Правило расчётных счетов — только позиция 1, только без имени в схеме | 1С кладёт контрагентов первым видом на этих счетах; именованные группировки («Работники организаций», «Учредители») не трогаем | Физлица и подотчётные на 71/73/76 без названия вида → COUNTERPARTY: попадут в «Осталось N» сопоставления (OQ-158) |
| 6 | R-6 | 19.10.2026 | Правило расчётных счетов — только позиция 1, только без имени в схеме | 1С кладёт контрагентов первым видом на этих счетах; именованные группировки («Работники организаций», «Учредители») не трогаем | Физлица на 76 без названия вида → COUNTERPARTY: попадут в «Осталось N» сопоставления (OQ-158); 71/73 исключены R-9 |
| 7 | R-7 | 19.10.2026 | Синтетика `s40`–`s44` | Номера `s33`–`s39` оставлены параллельному треку A, чтобы реестр генератора не конфликтовал | Перенумерация при слиянии |
| 8 | R-8 | 19.10.2026 | «Учредители» на счёте 80 не трогаем: именованная группировка остаётся OTHER (R-6 сохраняется) | Принято по рекомендации сессии при одобрении запуска владельцем; именованные группировки правило расчётных счетов не переопределяет | Учредители не станут COUNTERPARTY автоматически — гудвилл (§4 п. 2) потребует ручного сопоставления |
| 9 | R-9 | 19.10.2026 | Счета 71 и 73 исключены из `counterparty_accounts`; итог: 58, 60, 62, 66, 67, 75, 76, 80 | Подотчётные и персонал — физлица, а не контрагенты (OQ-158); принято по рекомендации сессии | Контрагенты на 71/73 без названия вида останутся OTHER и не попадут в сопоставление |
| 10 | R-10 | 19.10.2026 | «Организации» — синоним COUNTERPARTY в `osv_groups.yaml` (`^организаци`) | Вид субконто письма (сч. 60) — организации-контрагенты; принято по рекомендации сессии | Другой смысл вида «Организации» на иных счетах даст COUNTERPARTY; видно в golden/предупреждениях |
| 10 | R-10 (сужен R-17) | 19.10.2026 | «Организации» — синоним COUNTERPARTY в `osv_groups.yaml` (`^организаци`; после R-17 — `^организации\b`) | Вид субконто письма (сч. 60) — организации-контрагенты; принято по рекомендации сессии | Другой смысл вида «Организации» на иных счетах даст COUNTERPARTY; видно в golden/предупреждениях |
| 11 | R-11 (отменён R-16) | 19.10.2026 | Данные синтетики s40, s41, s42 исправлены: у «Итого развернутое» добавлены обороты, равные суммам строк (s40: 650/750, s41: 5000/4991, s42: 5700/6600) | В плане у этой строки обороты пусты, поэтому тождество строки (начало + обороты = конец) не сходилось, и файлы не могли стать `done` независимо от кода; бриф плана ошибочен | s40–s42 расходятся с исходным текстом плана. **Приёмка Task 6 показала:** в реальных файлах контура у «Итого развернутое» обороты тоже пусты (`45e06f7d`, `638ecb3d`, `7e49f8b5`, `f2e0e04e`, `270b41da`, `738bfcf5`, письмо), тождество на этой строке остаётся нарушенным, и файл уходит в `needs_check`: правка данных синтетики скрыла дефект кода, а не данных; решается отдельно (см. отчёт task-6). **Отменён рулингом R-16:** данные s40–s42 возвращены к исходному тексту плана |
| 12 | R-12 | 19.10.2026 | Строка вида субконто не даёт группировку из ячеек-меток шапки («Субконто», «Счет»), меток валюты («Валюта БУ, НУ») и ячеек, на которые срабатывает паттерн `currency` | Ячейка между названием и периодом может быть меткой шапки, а не видом субконто; иначе в схему попали бы ложные группировки (T2.2, ревью задачи 2) | Метка, совпавшая с настоящим видом субконто, не станет группировкой; вид «Организации» уже учтён (R-10) |
| 13 | R-13 | 19.10.2026 | Предупреждение `OSV_ROWS` «вид субконто в шапке не назван…» — одно на каждый различный `account_code_raw` строк, принятых по плану счетов | План требовал «один раз на документ»; у листа с несколькими субсчетами (62.01, 62.02) заметка с точным кодом полезнее одной общей | Больше заметок на листах с несколькими субсчетами (лист `67 сч.` — четыре); на статус не влияют (`info`) |
| 14 | R-14 | 19.10.2026 | `Expect.data_type` в `test_synthetic_files.py` стал `str \| None`: у s40–s44 ожидается `None` | В шапке нет БУ/НУ; умолчание BU — зона трека A (`data_type`) | При слиянии трека A ожидания s40–s44 придётся поправить на `BU` |
| 15 | R-15 | 19.10.2026 | Предупреждение `OSV_TOTAL` при несходимости «Итого» без корня ACCOUNT, но со строками уровня 0, говорит «≠ сумме N строк уровня 0» (T4.1) | Прежний текст «корневого счёта нет» вводил в заблуждение для плоского списка | Текст в `metrics.warnings` изменился; снимков с прежним текстом нет |
| 16 | R-16 | 19.10.2026 | Вторые итоговые строки (`total_row_secondary`, «Итого развернутое») исключены из проверки тождества строки; сверка по основной «Итого» сохранена; R-11 отменён | В 1С «Итого развернутое» содержит только развёрнутые сальдо, без оборотов (подтверждено 7 реальными файлами контура: `638ecb3d`, `45e06f7d`, `f2e0e04e`, `7e49f8b5`, `270b41da`, `738bfcf5`, письмо); решение владельца: «Итого развернутое» — итоговая строка в любом порядке | Тождество на вторых итогах не проверяется: ошибка в сальдо этой строки не будет поймана; основная «Итого» по-прежнему проверяется тождеством и сверкой с корнем/суммой уровня 0 |
| 16 | R-16 (уточнён R-19) | 19.10.2026 | Вторые итоговые строки (`total_row_secondary`, «Итого развернутое») исключены из проверки тождества строки; сверка по основной «Итого» сохранена; R-11 отменён | «Итого развернутое» перед «Итого» содержит только развёрнутые сальдо, без оборотов (подтверждено 7 реальными файлами контура: `638ecb3d`, `45e06f7d`, `f2e0e04e`, `7e49f8b5`, `270b41da`, `738bfcf5`, письмо); решение владельца: «Итого развернутое» — итоговая строка в любом порядке. Исключение оказалось шире обоснования: после «Итого» строка идёт с оборотами и сходящимся тождеством — см. R-19 | Тождество на вторых итогах без оборотов не проверяется: ошибка в сальдо этой строки не будет поймана; основная «Итого» по-прежнему проверяется тождеством и сверкой с корнем/суммой уровня 0 |
| 17 | R-17 (заменяет R-10) | 19.10.2026 | Синоним вида субконто сужен до множественного числа: `^организации\b` → COUNTERPARTY; единственное «Организация» остаётся OTHER и в схему не добавляется | «Организация» в шапке вариантов 1/2 — собственная организация учёта (измерение отчитывающейся организации); на контуре `dae56120` (сч. 83) и `02c5df51` (сч. 80) схема `[Счет, Организация]` из-за широкого паттерна стала `[ACCOUNT, COUNTERPARTY]` (финальное ревью I-1) | Прочие формы написания («Организации-контрагенты» и т. п.) не узнаются; вид во множественном числе с иным смыслом на нерасчётном счёте даст COUNTERPARTY (OQ-171) |
| 18 | R-18 | 19.10.2026 | Правило расчётных счетов (`counterparty_accounts`) не применяется к строке, которую словарь групп явно знает как не-COUNTERPARTY; паттерн валюты расширен до `^(в\s+)?валют` | Строки «Валюта», «Валюта CNY/EUR/USD/руб», «В валюте» под 76.55 становились контрагентами (`270b41da`, `738bfcf5`; финальное ревью I-2) | Контрагент с названием на «Валют…» («Валютные решения ООО») остаётся OTHER без имени и не попадёт в сопоставление |
| 19 | R-19 | 19.10.2026 | Тождество у второй итоговой строки пропускается, только если обе колонки оборотов пусты и на листе есть другая TOTAL; иначе строка проверяется как обычная | На контуре «Итого развернутое» перед «Итого» — без оборотов, после «Итого» — с оборотами и сходящимся тождеством; R-16 пропускал обе (финальное ревью I-4) | Вторая итоговая без оборотов и с ошибочным сальдо не ловится; единственная итоговая без оборотов проверяется, и пустое тождество может дать нарушение |
## Risks / Trade-offs
- [OQ-158] Контрагенты по плану счетов на 71/73/76 — в том числе физлица и подотчётные: «Осталось N» в сопоставлении
вырастет. Смягчение: предупреждение `OSV_ROWS` на документе; вопрос владельцу — сузить список (без 71/73).
- [OQ-158] Контрагенты по плану счетов на 76 и прочих расчётных счетах могут включать физлиц: «Осталось N» в
сопоставлении вырастет. Смягчение: предупреждение `OSV_ROWS` на документе; список уже сужен (без 71/73, R-9).
- [Трек A] До слияния трека A строки без «Выводимые данные» — `data_type = null`; ядро их в свод не берёт.
- [Golden] Изменения затронут снимки, где схема — одна ACCOUNT («Субконто») на расчётном счёте и есть не-счётные строки
(пакет ДКБ, `osv-dkb/**`): OTHER → COUNTERPARTY. Каждое изменение снимка — с просмотром diff.
- [Golden] Правило расчётных счетов срабатывает только при схеме из одной ACCOUNT без названия вида; у реальных файлов
и пакета ДКБ вид назван в шапке, поэтому снимки `osv/**` и `osv-dkb/**` не изменились (OTHER → COUNTERPARTY не
случилось). Эффект проверен на файлах контура.
## Open Questions
@ -111,6 +117,7 @@ OQ-169…OQ-172), в коде действует допущение:
- OQ-169 — «Учредители» на 80 (O-29, `02c5df51`) остаются OTHER (R-8); гудвилл §4 п. 2 — вопрос владельцу.
- OQ-170 — счета 71 и 73 (подотчётные, персонал) исключены из списка расчётных (R-9).
- OQ-171 — «Организации» — синоним COUNTERPARTY (R-10).
- OQ-172 — безымянная аналитика первого уровня на счёте 63 (51 строка в golden) не входит в список расчётных счетов:
нужен ли 63.
- OQ-171 — «Организации» (множественное число) — синоним COUNTERPARTY (R-10, R-17); «Организация» — OTHER.
- OQ-172 — безымянная аналитика первого уровня на счёте 63 не входит в список расчётных счетов: нужен ли 63. На файлах
контура таких строк нет; 51 строка — в fixtures, golden `osv-dkb/nm/2025-Q3/НМ_ОСВ_63_Контрагенты_…json`, и имя файла
(«63_Контрагенты») — довод за включение счёта 63.

View File

@ -50,6 +50,7 @@ arm-ka-docs (`05-domain-rules.md` §1.1, §1.3, §1.4, `07-open-questions.md`),
+ валютная часть 1661). До его слияния строки плоских файлов без «Выводимые данные» приходят с `data_type = null`, и
ядро не берёт их в свод (`SUMMARY_DATA_TYPES = (BU, SUM)`): файлы распознаются, но в сводную ОСВ не попадают.
- «Учредители» на 80 (именованная группировка `OTHER`, O-29) — не меняется (R-8).
- Вид субконто «Организации» — синоним COUNTERPARTY в `osv_groups.yaml` (R-10); прочие неизвестные виды в схему не
- Вид субконто «Организации» (множественное число) — синоним COUNTERPARTY в `osv_groups.yaml` (R-10, R-17), единственное
«Организация» — собственная организация учёта, не вид субконто; прочие неизвестные виды в схему не
добавляются, позиция остаётся без названия и подпадает под правило расчётных счетов.
- Склейка кварталов (O-28), «Итого» с потерянной подписью, буквенные счета первого сегмента (OQ-103) — без изменений.

View File

@ -49,7 +49,7 @@
- **WHEN** разбирается синтетическая ОСВ `s41` (шапка «…по счету: 60», строка «Организации», «за 2 Квартал 2026 г.
План счетов ООО Хреновская Нива»)
- **THEN** `organization_name = "ООО Хреновская Нива"`, `account_code_raw = "60"`,
`group_schema = [ACCOUNT(Субконто), COUNTERPARTY(Организации)]` («Организации» — синоним COUNTERPARTY в словаре)
`group_schema = [ACCOUNT(Субконто), COUNTERPARTY(Организации)]` (множественное «Организации» — синоним COUNTERPARTY в словаре; единственное «Организация» — собственная организация учёта, R-17)
#### Scenario: Счёт шапки важнее строки таблицы
- **WHEN** разбирается синтетическая ОСВ `s42` (шапка «…по счету: 76», первая строка таблицы «76.2»)
@ -161,8 +161,11 @@ balance_identity_violations, parent_sum_violations}`. Результат про
`OSV_XLSB_NO_OUTLINE`); строк вида `sheet=<имя> <текст>` в `metrics.warnings` больше нет. Парсер MUST NOT подгонять
структуру под сходимость.
Вторые итоговые строки (`total_row_secondary`, «Итого развернутое») SHALL NOT участвовать в проверке тождества строки:
в 1С они несут только развёрнутые сальдо, без оборотов (R-16); основная «Итого» проверяется тождеством как прежде.
Вторая итоговая строка (`total_row_secondary`, «Итого развернутое») SHALL NOT участвовать в проверке тождества строки,
только если у неё обе колонки оборотов за период пусты и на листе есть другая строка TOTAL: перед «Итого» она несёт
одни развёрнутые сальдо (R-16, уточнён R-19). Вторая итоговая строка с оборотами (в 1С она бывает и после «Итого», с
оборотами) и единственная итоговая строка листа проверяются тождеством как обычные; основная «Итого» проверяется как
прежде.
Исключение — **счета без сальдо по аналитике** (решение владельца 07.10.2026, OQ-132): у 91 и 99 строки аналитики несут
только обороты, сальдо закрыто на субсчёт закрытия (91.09). Список счетов — данные `rules/osv_checks.yaml`
@ -236,6 +239,10 @@ balance_identity_violations, parent_sum_violations}`. Результат про
- **THEN** `balance_identity_violations` не содержит «Итого развернутое», `status = done`; при нарушении тождества у основной
«Итого» её `row_number` в списке остаётся
#### Scenario: «Итого развернутое» с оборотами
- **WHEN** «Итого развернутое» стоит после «Итого», у неё заполнены обороты, и сальдо на конец не сходится с началом и оборотами
- **THEN** её `row_number` попадает в `balance_identity_violations`; при сходящемся тождестве нарушения нет
#### Scenario: «Итого» плоского списка
- **WHEN** разбирается синтетическая ОСВ `s40` («Итого» = сумма контрагентов, сальдо «Итого» свёрнуто)
- **THEN** `total_row_matches_root = true`, `status = done`; если сумма одного контрагента испорчена — `false`,