recompute для DISCLOSURE: полные словари needs_review и родители detail (I-3)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
This commit is contained in:
Andrey Epifancev 2026-10-18 14:28:20 +04:00
parent 8a63ce5196
commit 598ac83855
2 changed files with 35 additions and 3 deletions

View File

@ -127,13 +127,14 @@ def recompute(form: StoredForm, rules: Rules | None = None) -> RecomputeResult:
"""Шаги 6–8 по сохранённым данным: вариант, редакция, §7, `needs_review`, родители `detail`, статус."""
rules = rules if rules is not None else default_rules()
if form.document_type is DocumentType.DISCLOSURE:
ordered = sorted(form.lines, key=_sort_key)
return RecomputeResult(
form_variant=None,
edition=edition_by_date(form.effective_date),
checks=StatementChecks((), ()),
line_needs_review={},
value_needs_review={},
detail_parents={},
line_needs_review={line.key: False for line in ordered},
value_needs_review={(line.key, v.column_key): False for line in ordered for v in line.values},
detail_parents=_detail_parents(ordered),
status=DocStatus.DONE,
)
lines = sorted(form.lines, key=_sort_key)

View File

@ -5,6 +5,7 @@ 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
from arm_statements.structure import edition_by_date
OK, DETAIL = LineStatus.OK, LineStatus.DETAIL
COL = StoredColumn("c1", 2, date(2025, 9, 30), PeriodKind.ABSOLUTE)
@ -85,3 +86,33 @@ 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
def test_disclosure_has_complete_maps(rules: Rules) -> None:
"""I-3: для расшифровки в словарях ключи всех строк и значений, а не пустые словари."""
stored = form(
sl("a", 0, "1110", "10"),
sl("d", 1, None, "7", status=DETAIL),
sl("e", None, "1120", None),
document_type=DocumentType.DISCLOSURE,
)
result = recompute(stored, rules)
assert result.line_needs_review == {"a": False, "d": False, "e": False}
assert result.value_needs_review == {("a", "c1"): False, ("d", "c1"): False, ("e", "c1"): False}
assert result.detail_parents == {"d": "a"}
assert (result.form_variant, result.checks.relations_failed, result.status) == (None, (), DocStatus.DONE)
assert result.edition is edition_by_date(date(2025, 9, 30))
def test_edit_line_without_amount_is_excluded_from_checks_and_variant(rules: Rules) -> None:
"""T18.6: пустая строка правки не участвует в §7 и не влияет на вариант."""
base = [sl("a", 0, "1150", "50"), sl("b", 1, "1600", "50"), sl("c", 2, "1300", "50"), sl("d", 3, "1700", "50")]
with_edit = recompute(form(*base, sl("e", None, "1100", None)), rules)
without = recompute(form(*base), rules)
assert with_edit.form_variant is without.form_variant is FormVariant.SIMPLIFIED
assert with_edit.checks == without.checks
def test_detail_without_row_index_has_no_parent(rules: Rules) -> None:
stored = form(sl("a", 0, "1210", "10"), sl("d", None, None, "3", status=DETAIL))
assert recompute(stored, rules).detail_parents == {"d": None}