Словари: колонка «Показатели», «В валюте» (#58)

Словари для колонки вида суммы «Показатели» (БУ/НУ/Кол./Вал./ПР/ВР) и строки «В валюте» (AURORA-1613, AURORA-1661).
Код их пока не читает — это Task 2–3 плана.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-19 11:34:33 +04:00
parent d564d4998d
commit 74ba89c417
4 changed files with 53 additions and 3 deletions

View File

@ -18,6 +18,22 @@ standalone_header:
row:
- ['^вал\.$', CURRENCY]
- ['^кол(ичество|\s?во)?\.?$', QUANTITY]
# строка суммы в валюте под «Валюта <код>» (AURORA-1661); сама «Валюта USD» — обычная строка в рублях
- ['^в\s+валюте$', CURRENCY]
# Метка колонки «Показатели» (§1.3, AURORA-1613): БУ — обычная строка с data_type BU; остальные — строки-показатели
# (вид сумм предыдущей строки данных, вне проверок «дети = родитель» и «Итого»)
indicator_column:
- ['^бу$', BU]
- ['^ну$', NU]
- ['^кол\.?$', QUANTITY]
- ['^вал\.?$', CURRENCY]
# Метки-показатели без значения data_type в контракте (постоянные и временные разницы): data_type = null.
# Прикладной сценарий НУ и разниц — аналитика AURORA-1669
indicator_column_untyped:
- '^пр$'
- '^вр$'
# Коды валют ISO 4217 (буквенные): строка, целиком равная коду, — валютная; код же — результат `currency_aliases`
currency_codes: [RUB, USD, EUR, CNY, KZT, BYN, GBP, CHF, JPY, TRY, AED]

View File

@ -31,12 +31,16 @@ debit:
credit:
- '^(кредит|кт|к т)\b'
# Служебные колонки таблицы по тексту заголовка. Код знает только колонку ИНН; прочие колонки таблицы (КПП, код,
# Служебные колонки таблицы по тексту заголовка. Код знает колонки ИНН и «Показатели»; прочие колонки таблицы (КПП, код,
# количество, валюта и т. п.) попадают в `rows[].extra` под текстом своего заголовка и словаря не требуют.
# (Записи kpp/code/quantity/currency удалены: код их не читал, тест покрытия словарей R-22 их не находил.)
service_columns:
inn:
- '\bинн\b'
# Колонка вида суммы строки 1С («Показатели», в шапке часто с переносом «Показа-тели»): метки БУ/НУ/Кол./Вал./ПР/ВР
# (§1.3, AURORA-1613). Метки читает `data_types.yaml` — `indicator_column`
indicator:
- '^показа\s?тели$'
# Итоговая строка таблицы (начало текста первой колонки)
total_row:

View File

@ -317,6 +317,8 @@ class DataTypeRules(_Model):
header: list[tuple[Pattern, DataType]]
standalone_header: list[tuple[Pattern, DataType]]
row: list[tuple[Pattern, RowDataType]]
indicator_column: list[tuple[Pattern, DataType]]
indicator_column_untyped: list[Pattern]
currency_codes: list[str]
currency_aliases: dict[str, list[Pattern]]

View File

@ -384,8 +384,9 @@ def test_service_columns(rules: Rules, kind: str, text: str) -> None:
def test_service_columns_hold_only_what_the_code_reads(rules: Rules) -> None:
"""R-22: КПП, код, количество и валюта словаря не требуют — они идут в `extra` под своим заголовком."""
assert list(rules.headers.service_columns) == ["inn"]
"""R-22: КПП, код, количество и валюта словаря не требуют — они идут в `extra` под своим заголовком.
Ключ `indicator` (колонка «Показатели», AURORA-1613) читает код — поэтому он в списке."""
assert list(rules.headers.service_columns) == ["inn", "indicator"]
@pytest.mark.parametrize("text", ["Итого", "ИТОГО", "Итого по счету"])
@ -666,3 +667,30 @@ def test_account_code_in_osv_checks_must_be_digits_with_dots(tmp_path: Path, bad
with pytest.raises(RuntimeError, match=r"osv_checks\.yaml.*accounts_without_analytic_balance"):
load_rules(target)
# --- Колонка «Показатели» (§1.3, AURORA-1613) и «В валюте» (AURORA-1661) ---
@pytest.mark.parametrize(
("label", "expected"),
[("БУ", "BU"), ("НУ", "NU"), ("Кол.", "QUANTITY"), ("Кол", "QUANTITY"), ("Вал.", "CURRENCY")],
)
def test_indicator_column_labels(rules: Rules, label: str, expected: str) -> None:
assert first_match(rules.data_types.indicator_column, label) == expected
@pytest.mark.parametrize("label", ["ПР", "ВР"])
def test_indicator_column_untyped_labels(rules: Rules, label: str) -> None:
assert first_match(rules.data_types.indicator_column, label) is None
assert any(pattern.search(label) for pattern in rules.data_types.indicator_column_untyped)
def test_v_valyute_row_is_currency(rules: Rules) -> None:
assert first_match(rules.data_types.row, "В валюте") == "CURRENCY"
assert first_match(rules.data_types.row, "Валюта USD") is None
@pytest.mark.parametrize("title", ["Показа-\nтели", "Показатели", "ПОКАЗАТЕЛИ"])
def test_indicator_service_column(rules: Rules, title: str) -> None:
assert any(pattern.search(title) for pattern in rules.headers.service_columns["indicator"])