diff --git a/api/src/parser/statements/forms.py b/api/src/parser/statements/forms.py index 6b2e59e..6ac88c9 100644 --- a/api/src/parser/statements/forms.py +++ b/api/src/parser/statements/forms.py @@ -134,8 +134,11 @@ def _candidates(sheet: Sheet, rules: StatementRules) -> list[_Candidate]: for row in range(1, sheet.n_rows + 1): title: tuple[int, int, str] | None = None okud: tuple[int, int, str] | None = None - for col, cell in row_cells(sheet, row): - if title is None and type_hint(None, cell.text, rules) is not None: + cells = row_cells(sheet, row) + # строка-шапка таблицы (есть подпись «Код»): «Пояснения» и т. п. — подписи колонок, не заголовок формы + is_table_header = any(caption_matches([rules.headers.code_caption], cell.text) for _, cell in cells) + for col, cell in cells: + if title is None and not is_table_header and type_hint(None, cell.text, rules) is not None: title = (row, col, cell.text) # маркер продолжения («Форма 0710001 с.2») — не заголовок нового блока по ОКУД if okud is None and not is_continuation(cell.text, rules) and type_hint(cell.text, None, rules) is not None: diff --git a/api/tests/unit/parser/statements/test_forms.py b/api/tests/unit/parser/statements/test_forms.py index 80ba1d3..36d292d 100644 --- a/api/tests/unit/parser/statements/test_forms.py +++ b/api/tests/unit/parser/statements/test_forms.py @@ -118,3 +118,24 @@ def test_labels_with_punctuation_match(rules: StatementRules) -> None: assert matches(rules.headers.labels["okopf_okfs"], "по ОКОПФ / ОКФС") assert matches(rules.headers.legal_form, "АО «Пример»") assert caption_matches([rules.headers.code_caption], "Код") + + +def test_column_caption_in_table_header_is_not_a_form_title(rules: StatementRules) -> None: + rows = [ + ["Форма 0710001 с.2"], + at({1: "Наименование", 2: "Пояснения", 3: "Код", 4: "На 30.09.2025"}), + at({1: "Капитал", 3: 1310, 4: 10}), + ] + sheet = sheet_from_rows(rows) + assert find_blocks(sheet, rules) == [] + assert classify_statement_sheet(sheet, rules) == "continuation" + + +def test_real_title_above_same_table_header_stays_a_block(rules: StatementRules) -> None: + rows = [ + ["Бухгалтерский баланс"], + at({1: "Наименование", 2: "Пояснения", 3: "Код", 4: "На 30.09.2025"}), + at({1: "Капитал", 3: 1310, 4: 10}), + ] + [block] = find_blocks(sheet_from_rows(rows), rules) + assert block.type_hint is DocumentType.BALANCE