fix: address account valuation review findings
This commit is contained in:
@@ -31,12 +31,12 @@ def test_empty_conditional_close_is_closed_and_second_close_requires_correction(
|
||||
assert second["success"] is False and second["error_code"] == "validation_error"
|
||||
|
||||
|
||||
def test_preview_marks_approval_eligible_missing_valuation_as_conditional(tmp_path):
|
||||
def test_preview_marks_approval_eligible_missing_valuation_as_incomplete_draft(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
service.create_ledger_account("미확인 계좌", db_path=path)
|
||||
preview = service.preview_asset_snapshot_close("2026-06-30", db_path=path)
|
||||
assert preview["success"] is True
|
||||
assert preview["close_status"] == "conditional"
|
||||
assert preview["close_status"] == "incomplete_draft"
|
||||
assert any(warning["code"] == "missing_verified_exact_valuation" for warning in preview["warnings"])
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ def test_snapshot_close_idempotency_fingerprint_and_concurrent_first_close(tmp_p
|
||||
"2026-06-30", source_note="source-a", memo="memo-b",
|
||||
idempotency_key="close-1", db_path=path,
|
||||
)
|
||||
assert first["success"] and same["success"] and same["reused"] is True
|
||||
assert first["success"] and same["success"] and same == first
|
||||
assert changed["success"] is False and changed["error_code"] == "idempotency_conflict"
|
||||
|
||||
other_asset = first["included_items"][0]["source_id"]
|
||||
@@ -390,6 +390,122 @@ def test_snapshot_idempotency_binds_redacted_candidate_state(tmp_path):
|
||||
assert retry["error_code"] == "idempotency_conflict"
|
||||
|
||||
|
||||
def test_reconciliation_requires_balance_coverage_through_requested_basis(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
account = service.create_ledger_account(
|
||||
"계좌", last_balance=1_000, last_synced_at="2026-06-30", db_path=path,
|
||||
)["account"]["id"]
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-01", "income", 1_000, account_id=account,
|
||||
balance_after=1_000, db_path=path,
|
||||
)
|
||||
|
||||
item = service.get_balance_reconciliation_report(
|
||||
account_id=account, baseline_balance=1_000,
|
||||
baseline_at="2026-06-30T00:00:00+09:00", db_path=path,
|
||||
)["items"][0]
|
||||
|
||||
assert item["calculation_basis"] == "latest_transaction_balance_after"
|
||||
assert item["calculation_complete"] is False
|
||||
assert item["status"] == "INCOMPLETE_CALCULATION"
|
||||
assert item["difference"] is None
|
||||
|
||||
|
||||
def test_reconciliation_accepts_balance_coverage_at_requested_basis(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
account = service.create_ledger_account(
|
||||
"계좌", last_balance=1_000, last_synced_at="2026-06-30", db_path=path,
|
||||
)["account"]["id"]
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-30", "income", 1_000, account_id=account,
|
||||
balance_after=1_000, db_path=path,
|
||||
)
|
||||
|
||||
item = service.get_balance_reconciliation_report(
|
||||
account_id=account, baseline_balance=1_000,
|
||||
baseline_at="2026-06-30T00:00:00+09:00", db_path=path,
|
||||
)["items"][0]
|
||||
|
||||
assert item["calculation_complete"] is True
|
||||
assert item["status"] == "OK"
|
||||
assert item["difference"] == 0
|
||||
|
||||
|
||||
def test_reconciliation_requires_start_balance_for_transaction_coverage(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
account = service.create_ledger_account(
|
||||
"계좌", last_balance=1_000, last_synced_at="2026-06-30", db_path=path,
|
||||
)["account"]["id"]
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-01", "income", 1_000, account_id=account, db_path=path,
|
||||
)
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-30", "expense", 100, account_id=account,
|
||||
balance_after=900, db_path=path,
|
||||
)
|
||||
|
||||
item = service.get_balance_reconciliation_report(
|
||||
account_id=account, baseline_balance=900,
|
||||
baseline_at="2026-06-30T00:00:00+09:00", db_path=path,
|
||||
)["items"][0]
|
||||
|
||||
assert item["calculation_complete"] is False
|
||||
assert item["status"] == "INCOMPLETE_CALCULATION"
|
||||
assert item["difference"] is None
|
||||
|
||||
|
||||
def test_reconciliation_requires_authoritative_opening_evidence_for_multi_transaction_coverage(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
account = service.create_ledger_account(
|
||||
"계좌", last_balance=1_000, last_synced_at="2026-06-30", db_path=path,
|
||||
)["account"]["id"]
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-15", "income", 100, account_id=account,
|
||||
balance_after=900, db_path=path,
|
||||
)
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-30", "income", 100, account_id=account,
|
||||
balance_after=1_000, db_path=path,
|
||||
)
|
||||
|
||||
item = service.get_balance_reconciliation_report(
|
||||
account_id=account, baseline_balance=1_000,
|
||||
baseline_at="2026-06-30T00:00:00+09:00", db_path=path,
|
||||
)["items"][0]
|
||||
|
||||
assert item["calculation_complete"] is False
|
||||
assert item["status"] == "INCOMPLETE_CALCULATION"
|
||||
assert item["difference"] is None
|
||||
|
||||
|
||||
def test_reconciliation_accepts_continuous_transactions_with_verified_opening_evidence(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
account = service.create_ledger_account(
|
||||
"계좌", last_balance=1_000, last_synced_at="2026-06-30", db_path=path,
|
||||
)["account"]["id"]
|
||||
service.register_account_valuation(
|
||||
account, "2026-06-14", 800, valuation_kind="balance",
|
||||
verification_status="verified", db_path=path,
|
||||
)
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-15", "income", 100, account_id=account,
|
||||
balance_after=900, db_path=path,
|
||||
)
|
||||
service.create_ledger_transaction(
|
||||
"2026-06-30", "income", 100, account_id=account,
|
||||
balance_after=1_000, db_path=path,
|
||||
)
|
||||
|
||||
item = service.get_balance_reconciliation_report(
|
||||
account_id=account, baseline_balance=1_000,
|
||||
baseline_at="2026-06-30T00:00:00+09:00", db_path=path,
|
||||
)["items"][0]
|
||||
|
||||
assert item["calculation_complete"] is True
|
||||
assert item["status"] == "OK"
|
||||
assert item["difference"] == 0
|
||||
|
||||
|
||||
def test_reconciliation_fails_closed_on_ambiguous_verified_leaf(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
account = service.create_ledger_account(
|
||||
@@ -483,6 +599,7 @@ def test_legacy_snapshot_rows_do_not_override_live_authority_or_claim_closed(tmp
|
||||
|
||||
def test_snapshot_public_api_preserves_legacy_db_path_position(tmp_path):
|
||||
path = str(tmp_path / "ledger.sqlite3")
|
||||
init_db(path)
|
||||
preview = service.preview_asset_snapshot_close("2026-06-30", path)
|
||||
closed = service.close_asset_snapshot("2026-06-30", "", "", "", path)
|
||||
report = service.get_asset_snapshot_report("2026-06-30", path)
|
||||
|
||||
Reference in New Issue
Block a user