Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
88 lines
3.6 KiB
Python
88 lines
3.6 KiB
Python
from dataclasses import replace
|
||
from datetime import date
|
||
from decimal import Decimal as D
|
||
|
||
from arm_statements import StoredColumn, StoredForm, StoredLine, StoredValue, choose_edition, recompute
|
||
from arm_statements.loader import Rules
|
||
from arm_statements.model import DocStatus, DocumentType, Edition, FormVariant, LineStatus, PeriodKind
|
||
|
||
OK, DETAIL = LineStatus.OK, LineStatus.DETAIL
|
||
COL = StoredColumn("c1", 2, date(2025, 9, 30), PeriodKind.ABSOLUTE)
|
||
|
||
|
||
def sl( # noqa: PLR0913 -- конструктор тестовых строк
|
||
key: str,
|
||
row: int | None,
|
||
code: str | None,
|
||
amount: str | None,
|
||
*,
|
||
status: LineStatus = OK,
|
||
conf: float = 100.0,
|
||
code_fixed: bool = False,
|
||
value_conf: float = 100.0,
|
||
value_fixed: bool = False,
|
||
recognized: bool = True,
|
||
) -> StoredLine:
|
||
value = StoredValue("c1", None if amount is None else D(amount), amount, value_conf, recognized, value_fixed)
|
||
return StoredLine(key, row, status, code, conf, None, code_fixed, None, (value,))
|
||
|
||
|
||
def form(*lines: StoredLine, document_type: DocumentType = DocumentType.BALANCE) -> StoredForm:
|
||
return StoredForm(document_type, date(2025, 9, 30), True, True, (), False, (), (COL,), tuple(lines))
|
||
|
||
|
||
def test_recompute_after_edit(rules: Rules) -> None:
|
||
result = recompute(
|
||
form(
|
||
sl("l1210", 0, "1210", "100"),
|
||
sl("l1230", 1, "1230", "300", value_conf=60.0, value_fixed=True),
|
||
sl("l1250", 2, "1250", "50", conf=40.0, code_fixed=True),
|
||
sl("l1260", None, "1260", "50"),
|
||
sl("ldet", 3, None, "7", status=DETAIL, value_conf=60.0),
|
||
sl("l1200", 4, "1200", "500"),
|
||
),
|
||
rules,
|
||
)
|
||
# 1200 = 100 + 300 + 50 + 50 (с 1250 и строкой правки 1260) — сходится; 1600 нет — «пустая цель»
|
||
assert [(f.relation, f.column_key, f.column_index) for f in result.checks.relations_failed] == [
|
||
("1600 = 1100 + 1200", "c1", 2)
|
||
]
|
||
assert result.value_needs_review[("l1230", "c1")] is False
|
||
assert result.value_needs_review[("ldet", "c1")] is False
|
||
assert result.line_needs_review["l1250"] is False
|
||
assert result.detail_parents == {"ldet": "l1250"}
|
||
assert (result.edition, result.form_variant, result.status) == (
|
||
Edition.FSBU4,
|
||
FormVariant.FULL,
|
||
DocStatus.NEEDS_CHECK,
|
||
)
|
||
|
||
|
||
def test_code_change_switches_variant(rules: Rules) -> None:
|
||
simplified = form(
|
||
sl("a", 0, "1150", "50"), sl("b", 1, "1600", "50"), sl("c", 2, "1300", "50"), sl("d", 3, "1700", "50")
|
||
)
|
||
assert recompute(simplified, rules).form_variant is FormVariant.SIMPLIFIED
|
||
edited = form(
|
||
sl("a", 0, "1100", "50", code_fixed=True),
|
||
sl("b", 1, "1600", "50"),
|
||
sl("c", 2, "1300", "50"),
|
||
sl("d", 3, "1700", "50"),
|
||
)
|
||
result = recompute(edited, rules)
|
||
assert result.form_variant is FormVariant.FULL
|
||
assert result.status is DocStatus.NEEDS_CHECK
|
||
|
||
|
||
def test_edition_equals_choose_edition(rules: Rules) -> None:
|
||
stored = form(sl("a", 0, "1110", "10"), sl("b", 1, "1120", "5", conf=60.0), sl("c", 2, "1130", "5"))
|
||
pairs = [("1110", True), ("1120", False), ("1130", True)]
|
||
expected = choose_edition(DocumentType.BALANCE, pairs, date(2025, 9, 30), rules)
|
||
assert recompute(stored, rules).edition is expected is Edition.RAS_66N
|
||
|
||
|
||
def test_accepted_and_empty_edit_line(rules: Rules) -> None:
|
||
broken = form(sl("a", 0, "1600", "100"), sl("b", 1, "1700", "90"), sl("e", None, "1220", None))
|
||
assert recompute(broken, rules).status is DocStatus.NEEDS_CHECK
|
||
assert recompute(replace(broken, accepted=True), rules).status is DocStatus.DONE
|