Refs #14 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
138 lines
6.0 KiB
Python
138 lines
6.0 KiB
Python
"""Блоки форм на листе, тип формы, лист-продолжение (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
|