From ebc1f438dab97f0be2da1e37f1ff4b68bc872202 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sun, 18 Oct 2026 20:28:39 +0400 Subject: [PATCH] =?UTF-8?q?fix(statements):=20=D0=BF=D0=BE=D0=B4=D0=BF?= =?UTF-8?q?=D0=B8=D1=81=D1=8C=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B5-=D1=88=D0=B0?= =?UTF-8?q?=D0=BF=D0=BA=D0=B5=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B?= =?UTF-8?q?=20=D0=BD=D0=B5=20=D0=B7=D0=B0=D0=B3=D0=BE=D0=BB=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=BA=20=D1=84=D0=BE=D1=80=D0=BC=D1=8B=20(R-8,=20#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ячейка в строке с подписью «Код» (словарь пакета) не открывает блок формы: «Пояснения» на листах-продолжениях НПЗ больше не даёт DISCLOSURE. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W --- api/src/parser/statements/forms.py | 7 +++++-- .../unit/parser/statements/test_forms.py | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) 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