Документация: модуль строк ИНН, tasks change (#35)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-13 15:50:10 +04:00
parent ce776f6ab7
commit 79ffe602f6
4 changed files with 29 additions and 8 deletions

View File

@ -56,8 +56,8 @@ CORS, регистрация SMB-сессии, импорт `raisa_fastapi_prote
- `grid.py` + `readers/` — модель листа и чтение xlsx/xls/xlsb; единственное место, где допустимы индексы и буквы колонок - `grid.py` + `readers/` — модель листа и чтение xlsx/xls/xlsb; единственное место, где допустимы индексы и буквы колонок
(`column_letter` — только диагностика). `read_book(data, file_type) -> (листы, предупреждения)`, формат — по сигнатуре. (`column_letter` — только диагностика). `read_book(data, file_type) -> (листы, предупреждения)`, формат — по сигнатуре.
- `rules.py` — загрузчик словарей `api/rules/*.yaml`; `detect.py` — вид листа и заголовок таблицы; `header.py` — шапка - `rules.py` — загрузчик словарей `api/rules/*.yaml`; `detect.py` — вид листа и заголовок таблицы; `header.py` — шапка
и `group_schema`; `hierarchy.py` — каскад `outline → indent → account_pattern → sums` (+ `trivial`); `numbers.py` — и `group_schema`; `hierarchy.py` — каскад `outline → indent → account_pattern → sums` (+ `trivial`); `inn_rows.py` —
`Decimal` и ИНН; `classify.py` — строки и группировки; `checks.py` — контрольные суммы §1.4; `osv.py` — строки ИНН рядом с контрагентом (OQ-163); `numbers.py` — `Decimal` и ИНН (контрольная сумма); `classify.py` — строки и группировки; `checks.py` — контрольные суммы §1.4; `osv.py` —
оркестратор `OsvParser`; `deadline.py` — кооперативный таймаут; `errors.py` — коды ошибок; `cli.py` — разбор файла. оркестратор `OsvParser`; `deadline.py` — кооперативный таймаут; `errors.py` — коды ошибок; `cli.py` — разбор файла.
- `get_parser(settings)` создаёт `OsvParser` один раз при старте (кэша нет); `NullParser` — только для тестов воркера. - `get_parser(settings)` создаёт `OsvParser` один раз при старте (кэша нет); `NullParser` — только для тестов воркера.
@ -70,7 +70,7 @@ CORS, регистрация SMB-сессии, импорт `raisa_fastapi_prote
обращения к ячейке константами. Значения enum контракта вычисляются из `src.contract` и под линтер не попадают. обращения к ячейке константами. Значения enum контракта вычисляются из `src.contract` и под линтер не попадают.
- Каждая запись словаря должна срабатывать хотя бы на одном реальном или синтетическом файле - Каждая запись словаря должна срабатывать хотя бы на одном реальном или синтетическом файле
(`tests/fixtures/test_rules_coverage.py`); мёртвый синоним удаляется, пробел в фикстурах закрывается синтетикой. (`tests/fixtures/test_rules_coverage.py`); мёртвый синоним удаляется, пробел в фикстурах закрывается синтетикой.
- Golden-снимки (`../fixtures/golden/expected_osv_parse/`, 113 файлов: 72 реальных + 22 пакета ДКБ (`osv-dkb/**` до 1 МиБ, снимки в `osv-dkb/`) + 19 синтетических) — регрессия, а не - Golden-снимки (`../fixtures/golden/expected_osv_parse/`, 123 файла: 72 реальных + 23 пакета ДКБ (`osv-dkb/**` до 1 МиБ, снимки в `osv-dkb/`) + 28 синтетических) — регрессия, а не
оракул; правятся только `make golden-update` с просмотром diff и отдельным коммитом в `fixtures`. Корректность оракул; правятся только `make golden-update` с просмотром diff и отдельным коммитом в `fixtures`. Корректность
проверяют property-тест и ручная сверка «Итого». проверяют property-тест и ручная сверка «Итого».
- Деньги — `Decimal`, `float` в домене нет; `needs_check` — только по контрольным суммам, структуру под сходимость не - Деньги — `Decimal`, `float` в домене нет; `needs_check` — только по контрольным суммам, структуру под сходимость не

View File

@ -119,6 +119,7 @@ ParseOutcome`. Структура ОСВ ищется **по содержимо
| `header.py` | шапка документа (организация, счёт, период, тип данных, валюта) и схема группировок `group_schema` (варианты шапки 1 и 2) | | `header.py` | шапка документа (организация, счёт, период, тип данных, валюта) и схема группировок `group_schema` (варианты шапки 1 и 2) |
| `hierarchy.py` | каскад стратегий уровней строк: `outline` → `indent` → `account_pattern` → `sums`; `trivial` — меньше двух строк данных; выбранная стратегия пишется в `metrics.warnings` как `hierarchy=<имя>` | | `hierarchy.py` | каскад стратегий уровней строк: `outline` → `indent` → `account_pattern` → `sums`; `trivial` — меньше двух строк данных; выбранная стратегия пишется в `metrics.warnings` как `hierarchy=<имя>` |
| `numbers.py` | суммы в `Decimal` с двумя знаками (`to_money`), ИНН из текста ячейки (`inn_digits`); `float` в домене нет | | `numbers.py` | суммы в `Decimal` с двумя знаками (`to_money`), ИНН из текста ячейки (`inn_digits`); `float` в домене нет |
| `inn_rows.py` | строки ИНН рядом с контрагентом (восемь раскладок, контрольная сумма без подсказки шапки, противоречие подсказке, OQ-163); выполняется над деревом до классификации |
| `classify.py` | сбор строк таблицы (`collect_body_rows`: «Итого», свёрнутое сальдо) и тип группировки, счёт, контрагент, `data_type`, `extra` (`classify_rows`) | | `classify.py` | сбор строк таблицы (`collect_body_rows`: «Итого», свёрнутое сальдо) и тип группировки, счёт, контрагент, `data_type`, `extra` (`classify_rows`) |
| `checks.py` | контрольные суммы §1.4: тождество сальдо строки, «сумма детей = родитель», «Итого» = корень; счета без сальдо по аналитике (91, 99) — вне тождества строки (`osv_checks.yaml`) | | `checks.py` | контрольные суммы §1.4: тождество сальдо строки, «сумма детей = родитель», «Итого» = корень; счета без сальдо по аналитике (91, 99) — вне тождества строки (`osv_checks.yaml`) |
| `osv.py` | оркестратор `OsvParser`: лимит размера → чтение (с лимитами чтения) → лист за листом → статус и метрики | | `osv.py` | оркестратор `OsvParser`: лимит размера → чтение (с лимитами чтения) → лист за листом → статус и метрики |
@ -174,11 +175,12 @@ ParseOutcome`. Структура ОСВ ищется **по содержимо
**Реквизит «Контрагенты.ИНН»** (OQ-162, #32): элемент `<группировка>.ИНН` в шапке — в варианте 2 («субконто: Контрагенты, **Реквизит «Контрагенты.ИНН»** (OQ-162, #32): элемент `<группировка>.ИНН` в шапке — в варианте 2 («субконто: Контрагенты,
Контрагенты.ИНН») или строкой блока заголовка в варианте 1 — не группировка, а реквизит: в `group_schema` его нет, у владельца `has_inn = true` Контрагенты.ИНН») или строкой блока заголовка в варианте 1 — не группировка, а реквизит: в `group_schema` его нет, у владельца `has_inn = true`
(`header.GroupSchema.positions` держит его позицию для классификатора). 1С выводит ИНН строкой под контрагентом, с теми же (`header.GroupSchema.positions` держит его позицию для классификатора). подсказка для строк ИНН: порядок элементов задаёт направление (после владельца — ИНН под наименованием, перед — над) и снимает
суммами; `classify.glue_inn_attributes` отдаёт ИНН контрагенту (извлечение — как из колонки ИНН, R-24), строку убирает, проверку контрольной суммы. Склейку выполняет `inn_rows.py` (OQ-163): ИНН строки отдаётся наименованию (извлечение — как из
её детей поднимает на уровень; предупреждение «ИНН … отнесён к контрагенту в строке …». Пустая ячейка (физлицо без ИНН) — колонки ИНН, R-24), строка убирается, её дети переходят на уровень; предупреждение «ИНН … отнесён к контрагенту в строке …».
склейка без ИНН. Не склеилось (несколько строк ИНН, суммы не равны, ИНН не распознан или расходится) — строка `OTHER`, Пустая ячейка (физлицо без ИНН) — склейка без ИНН. Не склеилось (несколько строк ИНН, суммы не равны, ИНН не распознан или
предупреждение с причиной, документ `needs_check`. Число из xls читается без «.0» у целых (`readers/_common.make_cell`). расходится, направление неизвестно) — строка `OTHER`, предупреждение с причиной, документ `needs_check`; раскладка, противоречащая
подсказке шапки, склеивается с отдельным предупреждением и `needs_check`. Число из xls читается без «.0» у целых (`readers/_common.make_cell`).
**Период-диапазон.** «Октябрь 2024 г. – Сентябрь 2025 г.» (`periods.yaml`: `months`, `range`): январь–конец квартала — **Период-диапазон.** «Октябрь 2024 г. – Сентябрь 2025 г.» (`periods.yaml`: `months`, `range`): январь–конец квартала —
нарастающий, ровно квартал — квартальный, остальное (скользящие 12 месяцев) — `period_year` = год конца, `period_quarter` нарастающий, ровно квартал — квартальный, остальное (скользящие 12 месяцев) — `period_year` = год конца, `period_quarter`

View File

@ -154,3 +154,4 @@ Issue RSHB/arm-tabular-parser#35 (входит #34). Правило — `../docs
| 18 | 13.10.2026 | Task 4: параметризованный `test_header_status_and_hierarchy[s18_inn_row_above.xlsx]` (ожидает `done`) и golden s18 не правятся в Task 4 — оба падают только из-за ИНН s18 с неверной контрольной суммой и чинятся вместе с файлом в Task 5–6; в коммите упавшие тесты выведены из прогона (`--deselect`), `test_s18_…` помечен strict xfail | Бриф Task 4 прямо запрещает обновлять golden; ожидание `done` в параметризации относится к тому же файлу | Если Task 5 забудет снять xfail/починить параметризацию, strict xfail упадёт (XPASS) и напомнит | | 18 | 13.10.2026 | Task 4: параметризованный `test_header_status_and_hierarchy[s18_inn_row_above.xlsx]` (ожидает `done`) и golden s18 не правятся в Task 4 — оба падают только из-за ИНН s18 с неверной контрольной суммой и чинятся вместе с файлом в Task 5–6; в коммите упавшие тесты выведены из прогона (`--deselect`), `test_s18_…` помечен strict xfail | Бриф Task 4 прямо запрещает обновлять golden; ожидание `done` в параметризации относится к тому же файлу | Если Task 5 забудет снять xfail/починить параметризацию, strict xfail упадёт (XPASS) и напомнит |
| 19 | 13.10.2026 | H-2: направление фактической раскладки определяется по номерам строк пары (строка пары выше строки ИНН — ИНН «под», ниже — «над»), одинаково для пар в дереве и соседей; проверка выполняется только при подсказке и только для склеенных пар с непустым ИНН и без расхождения с колонкой ИНН | Номер строки однозначно отражает порядок на листе при любом пути поиска пары; пары без ИНН, без пары и с колонкой-победителем уже подсвечены своими предупреждениями | Нет: предупреждение лишь добавляется к уже состоявшейся склейке; результат склейки не меняется | | 19 | 13.10.2026 | H-2: направление фактической раскладки определяется по номерам строк пары (строка пары выше строки ИНН — ИНН «под», ниже — «над»), одинаково для пар в дереве и соседей; проверка выполняется только при подсказке и только для склеенных пар с непустым ИНН и без расхождения с колонкой ИНН | Номер строки однозначно отражает порядок на листе при любом пути поиска пары; пары без ИНН, без пары и с колонкой-победителем уже подсвечены своими предупреждениями | Нет: предупреждение лишь добавляется к уже состоявшейся склейке; результат склейки не меняется |
| 20 | 13.10.2026 | H-1: в s28 строка «7701234567» после классификации попадает в `rows` как контрагент (обычная строка по правилам классификатора) — тест фиксирует это «как есть» и проверяет её наличие среди контрагентов без ИНН | Спека: строка «классифицируется как обычно»; подгонки парсера нет | Нет: поведение соответствует ожиданию владельца | | 20 | 13.10.2026 | H-1: в s28 строка «7701234567» после классификации попадает в `rows` как контрагент (обычная строка по правилам классификатора) — тест фиксирует это «как есть» и проверяет её наличие среди контрагентов без ИНН | Спека: строка «классифицируется как обычно»; подгонки парсера нет | Нет: поведение соответствует ожиданию владельца |
| 21 | 13.10.2026 | Task 7: в tasks.md добавлены пункты 1.5 (H-2) и 2.2 (s28, H-1) сверх брифа; число golden в CLAUDE.md пересчитано по факту (123: 72 + 23 + 28, ранее значилось 113 = 72 + 22 + 19) | Бриф писался до H-1/H-2; счёт — по `find` | Нет: только документация |

View File

@ -0,0 +1,18 @@
## 1. Код (tabular-parser)
- [x] 1.1 Контрольная сумма ИНН и ИНН строки (`numbers.py`)
- [x] 1.2 Модуль `inn_rows.py`: склейка в дереве, контрольная сумма, защита «над, в дереве»
- [x] 1.3 Модуль `inn_rows.py`: соседи по суммам и направление листа
- [x] 1.4 Подключение в `osv.py`, подсказка шапки в обоих порядках, удаление `_glue_inn_rows` и `glue_inn_attributes`
- [x] 1.5 H-2: предупреждение о противоречии раскладки подсказке шапки (`needs_check`)
## 2. Данные (fixtures)
- [x] 2.1 Синтетика `s20`–`s27`, `s18` с верными ИНН
- [x] 2.2 Синтетика `s28` (H-1: неверная контрольная сумма среди верных ИНН)
- [x] 2.3 Сравнение main и ветки на всех fixtures, golden после согласования с владельцем
## 3. Документация
- [x] 3.1 docs: `05-domain-rules.md` §1.1, §1.3 (с H-1 и H-2), OQ-163
- [x] 3.2 README и CLAUDE.md tabular-parser