From 598d2c8fae7528bb491c11264b3a1191a60f8fea Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Mon, 19 Oct 2026 12:17:18 +0400 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BC=D0=BE=D0=BB=D1=87=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=91=D0=A3=20=D0=BF=D0=BE=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BA=D0=B0=D0=BC=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?,=20=D0=B1=D0=B5=D0=B7=20=D1=80=D0=B5=D1=8D=D0=BA=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D1=80=D1=82=D0=B0=20row=5Fdata=5Ftype=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- api/src/parser/classify.py | 3 +- api/src/parser/osv.py | 2 +- api/tests/unit/parser/test_classify.py | 3 +- api/tests/unit/parser/test_inn_rows_osv.py | 38 ++++++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/api/src/parser/classify.py b/api/src/parser/classify.py index a2f80e2..eddb1a6 100644 --- a/api/src/parser/classify.py +++ b/api/src/parser/classify.py @@ -31,7 +31,7 @@ from src.parser.deadline import Deadline from src.parser.detect import GROUP_ORDER, ColumnMap, TableHeader, first_data_row, is_header_repeat from src.parser.grid import Sheet, column_letter from src.parser.hierarchy import BodyRow, Levels -from src.parser.indicators import is_indicator_total, read_label, row_data_type +from src.parser.indicators import is_indicator_total, read_label from src.parser.numbers import column_inn, split_inn_suffix, to_money from src.parser.rules import GroupType, Rules @@ -43,7 +43,6 @@ __all__ = [ "RowGroupType", "classify_rows", "collect_body_rows", - "row_data_type", ] # Код счёта: две-три цифры и до двух сегментов субсчёта («60», «60.01», «76.07.1», «001»); сегмент — 1–2 цифры или diff --git a/api/src/parser/osv.py b/api/src/parser/osv.py index 69ec6c4..3c0809c 100644 --- a/api/src/parser/osv.py +++ b/api/src/parser/osv.py @@ -200,7 +200,7 @@ class OsvParser: data_type = doc.data_type or DEFAULT_DATA_TYPE # Вид данных шапки не указан: строки без метки приняты как БУ — предупреждение, если умолчание сработало defaulted = doc.data_type is None and any( - not item.indicator and item.label_data_type is None for item in body + not item.indicator and item.label_data_type is None for item in glue.rows ) classified = classify_rows( glue.rows, diff --git a/api/tests/unit/parser/test_classify.py b/api/tests/unit/parser/test_classify.py index 75eba01..e120156 100644 --- a/api/tests/unit/parser/test_classify.py +++ b/api/tests/unit/parser/test_classify.py @@ -12,13 +12,14 @@ import pytest from gridbuilder import C, L, M, sheet_from_rows from src.contract.common import DataType -from src.parser.classify import ACCOUNT_RE, ClassifiedRow, classify_rows, collect_body_rows, row_data_type +from src.parser.classify import ACCOUNT_RE, ClassifiedRow, classify_rows, collect_body_rows from src.parser.deadline import Deadline from src.parser.detect import find_table_header from src.parser.errors import ParseTimeoutError from src.parser.grid import Sheet from src.parser.header import build_group_levels from src.parser.hierarchy import TRIVIAL_STRATEGY, Levels, resolve_levels +from src.parser.indicators import row_data_type from src.parser.inn_rows import glue_inn_rows from src.parser.rules import Rules, load_rules diff --git a/api/tests/unit/parser/test_inn_rows_osv.py b/api/tests/unit/parser/test_inn_rows_osv.py index 3c44a80..6d90416 100644 --- a/api/tests/unit/parser/test_inn_rows_osv.py +++ b/api/tests/unit/parser/test_inn_rows_osv.py @@ -47,3 +47,41 @@ def test_inn_glued_to_row_that_is_not_a_counterparty_needs_check(rules: Rules) - assert not ok expected = f"строка 10: ИНН {INN_A} отнесён к строке 11, но она не контрагент — проверьте" assert expected in warnings, warnings + + +# --- Умолчание вида данных (#58, T6.1) --- + +BU_DEFAULT_WARNING = "вид данных в шапке не указан — строки без метки приняты как БУ" + + +def _labelled_sheet(bu_label: object) -> object: + return sheet_from_rows( + [ + ["Оборотно-сальдовая ведомость по счету 60 за 1 квартал 2025 г."], + [ + "Счет", + None, + M("Сальдо на начало периода", 2), + M("Обороты за период", 2), + M("Сальдо на конец периода", 2), + ], + ["Контрагенты", "Показатели", "Дебет", "Кредит", "Дебет", "Кредит", "Дебет", "Кредит"], + [L(0), "60", bu_label, *A], + [L(1), "ООО Альфа", bu_label, *A], + [L(1), None, "НУ", *A], + [L(0), "Итого", bu_label, *A], + ] + ) + + +def test_default_warning_not_given_when_all_rows_are_labelled(rules: Rules) -> None: + result = OsvParser(rules).parse_sheet(_labelled_sheet("БУ"), Deadline(TIMEOUT_SECONDS)) # type: ignore[arg-type] + + assert BU_DEFAULT_WARNING not in [note.message for note in result.notes] + assert result.document.header.data_type is None + + +def test_default_warning_given_once_when_rows_have_no_label(rules: Rules) -> None: + result = OsvParser(rules).parse_sheet(_labelled_sheet(None), Deadline(TIMEOUT_SECONDS)) # type: ignore[arg-type] + + assert [note.message for note in result.notes].count(BU_DEFAULT_WARNING) == 1