Refs #14 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
123 lines
4.0 KiB
Python
123 lines
4.0 KiB
Python
"""Соотношения §7 как данные (design D-7; spec «Соотношения §7 — данные, проверка по колонкам»)."""
|
||
|
||
from decimal import Decimal
|
||
|
||
import pytest
|
||
|
||
from src.contract.result import StatementLine, StatementValue
|
||
from src.parser.rules import Rules, load_rules
|
||
from src.parser.statements.checks import run_statement_checks
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def rules() -> Rules:
|
||
return load_rules()
|
||
|
||
|
||
def line(code: str, *amounts: str | None) -> StatementLine:
|
||
values = [
|
||
StatementValue(
|
||
column_index=index,
|
||
amount=None if amount is None else Decimal(amount),
|
||
confidence=100,
|
||
is_recognized=True,
|
||
)
|
||
for index, amount in enumerate(amounts)
|
||
]
|
||
return StatementLine(
|
||
line_code=code,
|
||
line_code_confidence=100,
|
||
line_name=code,
|
||
line_name_confidence=100,
|
||
values=values,
|
||
)
|
||
|
||
|
||
def test_balance_relations_hold_with_missing_codes_as_zero(rules: Rules) -> None:
|
||
lines = [
|
||
line("1150", "100", "90"),
|
||
line("1100", "100", "90"),
|
||
line("1210", "50", "40"),
|
||
line("1200", "50", "40"),
|
||
line("1600", "150", "130"),
|
||
line("1310", "150", "130"),
|
||
line("1300", "150", "130"),
|
||
line("1700", "150", "130"),
|
||
]
|
||
|
||
checks, warnings = run_statement_checks(lines, 2, "BALANCE", rules)
|
||
|
||
assert checks.relations_failed == []
|
||
assert checks.soft_relations_failed == []
|
||
assert warnings == []
|
||
|
||
|
||
def test_broken_total_reported_per_column(rules: Rules) -> None:
|
||
lines = [
|
||
line("1100", "100", "100"),
|
||
line("1200", "50", "50"),
|
||
line("1600", "155", "150"),
|
||
]
|
||
|
||
checks, warnings = run_statement_checks(lines, 2, "BALANCE", rules)
|
||
|
||
failed = [(item.column_index, item.relation, item.expected, item.actual) for item in checks.relations_failed]
|
||
assert (0, "1600 = 1100 + 1200", Decimal("155"), Decimal("150")) in failed
|
||
assert not any(item.column_index == 1 and item.relation == "1600 = 1100 + 1200" for item in checks.relations_failed)
|
||
assert any("1600 = 1100 + 1200" in warning and "колонка 0" in warning for warning in warnings)
|
||
|
||
|
||
def test_tolerance_one_unit(rules: Rules) -> None:
|
||
lines = [
|
||
line("1100", "100"),
|
||
line("1200", "50"),
|
||
line("1600", "151"),
|
||
line("1700", "151"),
|
||
line("1300", "151"),
|
||
]
|
||
|
||
checks, _ = run_statement_checks(lines, 1, "BALANCE", rules)
|
||
|
||
assert checks.relations_failed == []
|
||
|
||
|
||
def test_relation_holds_with_abs_terms(rules: Rules) -> None:
|
||
"""Review Focus 3: 1С пишет расходы со знаком минус, 66н — в скобках; оба варианта сходятся."""
|
||
one_c = [line("2110", "1000"), line("2120", "-600"), line("2100", "400")]
|
||
brackets = [
|
||
line("2110", "1000"),
|
||
line("2120", "600"),
|
||
line("2100", "400"),
|
||
]
|
||
|
||
assert run_statement_checks(one_c, 1, "INCOME", rules)[0].relations_failed == []
|
||
assert run_statement_checks(brackets, 1, "INCOME", rules)[0].relations_failed == []
|
||
|
||
|
||
def test_soft_relation_and_sublines(rules: Rules) -> None:
|
||
lines = [
|
||
line("2400", "-100"),
|
||
line("2410", "-100"),
|
||
line("2411", "-80"),
|
||
line("2412", "-30"),
|
||
line("1110", "10"),
|
||
line("11101", "6"),
|
||
line("11102", "3"),
|
||
]
|
||
|
||
checks, warnings = run_statement_checks(lines, 1, "INCOME", rules)
|
||
balance, _ = run_statement_checks(lines, 1, "BALANCE", rules)
|
||
|
||
assert [item.relation for item in checks.soft_relations_failed] == ["2410 = 2411 + 2412"]
|
||
assert checks.relations_failed == []
|
||
assert [item.relation for item in balance.soft_relations_failed] == ["1110 = 11101 + 11102"]
|
||
assert any("мягкое" in warning for warning in warnings)
|
||
|
||
|
||
def test_null_values_count_as_zero_and_empty_form_passes(rules: Rules) -> None:
|
||
lines = [line("1100", None), line("1200", None), line("1600", None)]
|
||
|
||
checks, _ = run_statement_checks(lines, 1, "BALANCE", rules)
|
||
|
||
assert checks.relations_failed == []
|