"""Блоки форм на листе, тип формы, лист-продолжение (design D-2, D-3; spec «Листы форм и их продолжения находятся по содержимому»).""" import pytest from gridbuilder import at, sheet_from_rows from src.parser.detect import SheetKind, classify_sheet from src.parser.rules import Rules, load_rules from src.parser.statements.detect import classify_statement_sheet, continuation_form, find_forms @pytest.fixture(scope="module") def rules() -> Rules: return load_rules() NPZ_FIRST_SHEET = [ [None, None, "Бухгалтерская отчетность"], [None, None, "за январь - сентябрь 2025 г."], [*at({3: "Организация:", 7: 'ООО "НПЗ"', 22: "по ОКПО", 23: "16098811"})], [ *at( { 3: "Идентификационный номер налогоплательщика", 22: "ИНН", 23: "2315995868", } ) ], [], [None, None, "Бухгалтерский баланс"], [None, None, "на 30 сентября 2025 г."], [*at({22: "Форма по ОКУД", 23: "0710001"})], [ *at( { 3: "Пояснения", 5: "Наименование показателя", 13: "Код", 16: "На 30 сентября 2025 г.", 21: "На 31 декабря 2024 г.", } ) ], [*at({5: "Гудвил", 13: "1105", 16: 0, 21: 0})], [*at({5: "Нематериальные активы", 13: "1110", 16: 586260, 21: 905786})], [*at({5: "Итого по разделу I", 13: "1100", 16: 586260, 21: 905786})], ] def test_title_after_report_header_gives_one_balance_block(rules: Rules) -> None: sheet = sheet_from_rows(NPZ_FIRST_SHEET) blocks, warnings = find_forms(sheet, rules) assert len(blocks) == 1 and warnings == [] block = blocks[0] assert block.kind == "BALANCE" and block.form_name == "Бухгалтерский баланс" and block.okud == "0710001" assert (block.title_row, block.first_row, block.last_row) == (6, 1, sheet.n_rows) def test_two_forms_on_one_sheet_split_at_second_title(rules: Rules) -> None: sheet = sheet_from_rows( [ ["Бухгалтерский баланс"], ["Наименование", "Код", "На 31.12.2024"], ["Запасы", "1210", 10], ["БАЛАНС", "1600", 10], [], ["Отчет о финансовых результатах"], ["Наименование", "Код", "За 2024 г."], ["Выручка", "2110", 100], ] ) blocks, _ = find_forms(sheet, rules) assert [(block.kind, block.first_row, block.last_row) for block in blocks] == [("BALANCE", 1, 5), ("INCOME", 6, 8)] def test_okud_without_title_and_disclosure(rules: Rules) -> None: sheet = sheet_from_rows([["Форма по ОКУД", "0710002"], ["Код", "За 2024 г."], ["2110", 1]]) assert find_forms(sheet, rules)[0][0].kind == "INCOME" disclosure = sheet_from_rows([["Пояснения к бухгалтерскому балансу и отчету о финансовых результатах"], ["текст"]]) assert find_forms(disclosure, rules)[0][0].kind == "DISCLOSURE" odds = sheet_from_rows([["Отчет о движении денежных средств"], ["Код", "За 2024 г."], ["4110", 1]]) assert find_forms(odds, rules)[0][0].kind == "DISCLOSURE" def test_title_and_okud_conflict_prefers_okud_with_warning(rules: Rules) -> None: sheet = sheet_from_rows([["Бухгалтерский баланс"], ["Форма по ОКУД", "0710002"]]) blocks, warnings = find_forms(sheet, rules) assert blocks[0].kind == "INCOME" and warnings and "0710002" in warnings[0] def test_classify_statement_continuation_and_other(rules: Rules) -> None: one_c_page_two = sheet_from_rows( [ [*at({17: "Форма 0710001 с.2"})], ["Пояснения", "Наименование показателя", "Код", "На 31 декабря 2024 г."], [None, "Уставный капитал", "1310", 250000], ] ) npz_page = sheet_from_rows( [ ["в том числе:"], ["Биологические активы", "11901", 0, 0], ["Итого по разделу I", "1100", 5, 5], ["Запасы", "1210", 1, 1], ] ) header_only = sheet_from_rows( [ ["Пояснения", "Наименование показателя", "Код", "На 31 декабря 2024 г."], ["Запасы", None, None, 5], ] ) other = sheet_from_rows([["Справка"], ["Наименование", "Сумма"], ["Аренда", 100]]) assert classify_statement_sheet(sheet_from_rows(NPZ_FIRST_SHEET), rules) == "statement" assert classify_statement_sheet(one_c_page_two, rules) == "continuation" assert classify_statement_sheet(npz_page, rules) == "continuation" assert classify_statement_sheet(header_only, rules) == "continuation" assert classify_statement_sheet(other, rules) == "other" assert continuation_form(one_c_page_two, rules) == ("BALANCE", "Форма 0710001 с.2") assert continuation_form(npz_page, rules) == (None, None) def test_sheet_kind_wiring(rules: Rules) -> None: assert classify_sheet(sheet_from_rows(NPZ_FIRST_SHEET), rules) is SheetKind.STATEMENT statement_continuation_sheet = sheet_from_rows([["Форма 0710002 с.2"], ["Код", "За 2024 г."], ["2510", 0]]) assert classify_sheet(statement_continuation_sheet, rules) is SheetKind.STATEMENT_CONTINUATION osv_sheet = sheet_from_rows([["Оборотно-сальдовая ведомость по счету 60"], ["Бухгалтерский баланс"]]) assert classify_sheet(osv_sheet, rules) is SheetKind.OSV