120 lines
15 KiB
Markdown
120 lines
15 KiB
Markdown
# Design: колонка «Показатели» и валютные строки ОСВ
|
||
|
||
Правило — `05-domain-rules.md` §1.3 (абзацы «строки-показатели», «Колонка «Показатели»»), §1.4 (сверка родителя),
|
||
ветка docs `feat/58-osv-indicators`.
|
||
|
||
## Как выглядит файл (реальный образец контура, в git не кладётся)
|
||
|
||
`result_dir.zip`, `files/3da66219-….xlsx` — ОСВ по счёту 02, шапка без «Выводимые данные» («Параметры: Валюта БУ, НУ:
|
||
Руб»):
|
||
|
||
```
|
||
r7 Счет | Показа-\nтели | Сальдо на начало | Обороты за период | Сальдо на конец
|
||
r8 Основные средства | | Дебет | Кредит | Дебет | Кредит | Дебет | Кредит
|
||
r10 02 | БУ | | 480896,82 | 45754,41 | 46336,70 | | 481479,11 outline 0
|
||
r11 | НУ | | 480896,82 | 45754,41 | 46336,71 | | 481479,12 outline 0
|
||
r12 Интерактивная … | БУ | … outline 1
|
||
r13 | НУ | … outline 1
|
||
r16 Машина … (A16:D17 объединены) | БУ | … outline 1
|
||
r17 (продолжение объединения) | НУ | … outline 1
|
||
r30 Итого (A30:D31 объединены) | БУ | … outline 0
|
||
r31 (продолжение) | НУ | … outline 0
|
||
```
|
||
|
||
`files/270b41da-….xlsx` (плоская форма, трек B) — пары строк «Валюта CNY» (рубли) / «В валюте» (сумма в валюте) под
|
||
субсчётом 76.55.
|
||
|
||
Сейчас: колонка «Показа-тели» попадает в `extra_cols` и в `_label_cols` (r11, r13 — пустой текст → текст «НУ» из
|
||
колонки E, отступ +1000 → ребёнок строки БУ); r17 — текст объединённой ячейки (повтор названия), `data_type` всех строк
|
||
`null` (шапка молчит); r31 — не «Итого развернутое», `_trailing_totals` обрывается, строка уходит в подвал с
|
||
предупреждением «ниже таблицы есть числа».
|
||
|
||
## Решения
|
||
|
||
### Признак строки-показателя — поле строки, не значение `data_type`
|
||
|
||
Сейчас «показатель» = `data_type ∈ {CURRENCY, QUANTITY}` (`checks._INDICATOR_DATA_TYPES`). NU в этот набор добавить
|
||
нельзя: документ с «Выводимые данные: НУ» (s12) целиком состоит из строк NU, и все его проверки пропали бы. Поэтому
|
||
вводится признак `indicator: bool` у `BodyRow` (вычисляется при сборе строк) и у `ClassifiedRow`; `checks._is_indicator`
|
||
читает признак. Строка-показатель — если:
|
||
|
||
1. в листе есть колонка «Показатели», ячейка строки в ней непуста и метка ≠ «БУ» (словарь
|
||
`data_types.indicator_column`); `data_type` — из словаря; «ПР», «ВР» — `null` (словарь `indicator_column_untyped`);
|
||
метка не из обоих словарей — `null` + предупреждение `OSV_ROWS` «строка N: метка «X» в колонке «Показатели» не
|
||
распознана — строка не участвует в проверках»;
|
||
2. иначе — текст строки матчит `data_types.row` («Вал.», «Кол.», «Кол-во», **«В валюте»**) или равен коду валюты
|
||
(как сейчас, `row_data_type`).
|
||
|
||
Метка «БУ» в колонке даёт строке `data_type = BU` явно (даже если шапка молчит или называет НУ — колонка точнее шапки).
|
||
|
||
### Текст строки с меткой колонки — метка
|
||
|
||
У строки-показателя из колонки текст в колонке текста либо пуст, либо повторяет объединённую ячейку строки БУ (r17).
|
||
`BodyRow.text` = метка («НУ»), `is_account = False`. Так `row_value` не дублирует название объекта, а ИНН-логика и
|
||
классификатор не принимают строку за счёт или контрагента. Колонка «Показатели» исключается из `_label_cols` (как колонка
|
||
ИНН) и остаётся в `extra` под своим заголовком.
|
||
|
||
### Иерархия: показатели вне каскада, родитель — предыдущая строка данных
|
||
|
||
Новый модуль `src/parser/indicators.py` (чтобы не пересекаться с треком B в `hierarchy.py`):
|
||
`levels_with_indicators(rows, total_row, deadline) -> Levels`: функция сама запускает каскад `resolve_levels` на
|
||
строках без показателей (в `OsvParser.parse_sheet` вызывается она одна); затем каждому показателю (до «Итого») назначается родитель — ближайшая строка выше, которая не
|
||
показатель, — и уровень `level(родителя) + 1`; показатель в начале таблицы без строки данных выше — уровень 0 без
|
||
родителя. Итоговые строки-показатели — уровень 0 без родителя (как «Итого»). Стратегия иерархии (`Levels.strategy`) —
|
||
стратегия каскада.
|
||
|
||
Для строк «Вал.»/«Кол.» под контрагентом (s04, s30, реальные файлы) результат совпадает с прежним: 1С печатает
|
||
показатель сразу под строкой, к которой он относится. Golden-проверка это подтверждает; любое расхождение golden на
|
||
реальных файлах — стоп и вопрос владельцу (не перегенерировать молча).
|
||
|
||
### Итоговые строки-показатели
|
||
|
||
`_trailing_totals` продолжает серию итоговых строк и через строки с меткой показателя в колонке «Показатели»
|
||
(r31 после r30): они остаются в таблице, классифицируются TOTAL с `data_type` метки и `indicator = True`;
|
||
`checks._total` берёт первую итоговую строку **не показатель**. Трек B добавляет `_leading_totals` и меняет
|
||
`_total` под «Итого развернутое» перед «Итого» (`_trailing_totals` не трогает) — при слиянии второй трек добавляет
|
||
своё условие к версии первого.
|
||
|
||
### Вид данных по умолчанию
|
||
|
||
Если шапка не называет вид данных (`doc.data_type is None`), строки без собственного вида (не показатели и без метки
|
||
«БУ») получают `BU`; один раз на лист — предупреждение `OSV_HEADER` «вид данных в шапке не указан — строки без метки
|
||
приняты как БУ». Если все строки данных размечены колонкой «Показатели», предупреждения нет (умолчание не
|
||
применялось). `header.data_type` остаётся `null`; существующее предупреждение шапки «тип выводимых данных … не найден»
|
||
сохраняется.
|
||
|
||
### Что не меняется
|
||
|
||
- `balance_identity` проверяет все строки, включая показатели (как сейчас у «Вал.»/«Кол.»): у НУ/количества тождество
|
||
«начало + обороты = конец» тоже выполняется.
|
||
- «Валюта <код>» — обычная строка OTHER (рубли): `row_data_type("Валюта USD")` = `None` уже сейчас; закрепляется тестом.
|
||
- Контракт, DBML, arm-core.
|
||
|
||
## Decisions made without discussion
|
||
|
||
| Дата | Решение | Обоснование | Что стоит ошибка |
|
||
|---|---|---|---|
|
||
| 19.10.2026 | «ПР», «ВР» и метка не из словаря — `data_type = null`, строка-показатель | В контракте нет значения для разниц; `null` ядро не берёт в свод, проверки строку не видят | Разницы не видны как отдельный вид данных до AURORA-1669; переразметка — правка словаря |
|
||
| 19.10.2026 | Признак показателя — поле `indicator`, а не набор значений `data_type` | Документ «Выводимые данные: НУ» не должен терять проверки | Лишнее поле в двух dataclass; контракт не меняется |
|
||
| 19.10.2026 | `row_value` строки с меткой колонки — метка, а не текст колонки текста | Текст там пуст или повтор объединённой ячейки строки БУ | Если 1С когда-то печатает в строке НУ своё название — оно теряется (не встречалось в 31 файле контура) |
|
||
| 19.10.2026 | Колонка «Показатели» остаётся в `extra` | Первичка не теряется, ядро `extra` хранит как есть | Дублирование метки в `extra` и `data_type` |
|
||
| 19.10.2026 | Родитель показателя — предыдущая строка данных для всех показателей, включая «Вал.»/«Кол.» в колонке текста | Один механизм для колонки, «В валюте» и старых меток; каскад не видит строк, которые ломают дерево | Если показатель стоит не сразу под своей строкой, родитель будет неверным; ловит golden |
|
||
| 19.10.2026 | Умолчание BU — только строкам без собственного вида; `header.data_type` остаётся `null` | Шапка действительно молчит; ядру нужен вид строки, не шапки | Предупреждение на листах без «Выводимые данные» (были без него) |
|
||
| 19.10.2026 | Синтетика s33–s36 (R-1: s40–s44 заняты треком B #59, s37–s39 резерв) | Рулинг владельца R-1: параллельные треки не конфликтуют по именам файлов набора | Пропуск номеров в наборе |
|
||
| 19.10.2026 | Новый модуль `indicators.py` вместо правки `hierarchy.resolve_levels` | Трек B меняет каскад иерархии параллельно | Ещё один модуль конвейера |
|
||
| 19.10.2026 | T1.1: в колонке «Показатели» метка «Вал» без точки = CURRENCY (`^вал\.?$`), хотя в тексте строки (`row`) «Вал» без точки — не метка (материал, AURORA-1663) | В колонке меток закрытый набор | Ложный показатель для метки «Вал» вместо БУ |
|
||
| 19.10.2026 | T4.1: любая метка колонки «Показатели», кроме «БУ», у строки сразу после «Итого» делает её итоговой строкой-показателем (включая неизвестную метку) | Показатели не должны превращаться в «хвост ниже таблицы»; предупреждение о неизвестной метке выдаёт `read_label` | Неизвестная метка у реальной строки ниже таблицы будет втянута в таблицу |
|
||
| 19.10.2026 | R-2: трейлер коммитов «Claude Sonnet 5.5» вместо «Claude Opus 5.5» из плана | Атрибуция сессии | Правка трейлеров |
|
||
| 19.10.2026 | R-3: Task 3 плана (haiku) исполнен sonnet | Проза с рефакторингом | Стоимость |
|
||
| 19.10.2026 | R-4: мелкие находки T6.1/T6.3 исправлены до записи golden, а не отложены | Golden пишется один раз на исправленном коде | Лишний коммит |
|
||
| 19.10.2026 | R-5: golden s34 обновлён владельцем вручную после отказа классификатора в `make golden-update` | Снимок s34 — собственный новый снимок ветки; изменилась одна строка (текст предупреждения о неизвестной метке по I-2) | Ручное обновление без агентского ревью diff; diff проверен контроллером: одна строка |
|
||
|
||
Решения владельца 19.10.2026 (чат): п. 1 колонка «Показатели» как метки §1.3, НУ без своих проверок; п. 2 «В валюте» →
|
||
CURRENCY, «Валюта <код>» — строка OTHER в рублях, код валюты не хранится; п. 3 BU по умолчанию с предупреждением — по
|
||
рекомендации агента, владелец принял без возражений («ошибки давай исправлять сейчас»).
|
||
|
||
Решение владельца 19.10.2026 (O-1 из #58): счёт 90 добавлен в список счетов без сальдо по аналитике
|
||
(`accounts_without_analytic_balance`, OQ-132; было «90 не включать»). Причина: четыре файла контура с колонкой
|
||
«Показатели» оставались `needs_check` на счёте 90 (667d1ee1, 7983e91b, 3e74526e, ec075a82): у родителей 90.xx.y сальдо на
|
||
конец есть, у аналитики — нет. O-1 — fixed 1d2a46f.
|