fix(approval): replay immutable action responses

This commit is contained in:
caoxiaozhu
2026-07-16 15:49:43 +08:00
parent 4940ebc419
commit 28b834edd3
20 changed files with 552 additions and 60 deletions

View File

@@ -15,6 +15,7 @@ from app.models.audit_log import AuditLog
from app.models.employee import Employee
from app.models.expense_case import BusinessEvent
from app.models.financial_record import ExpenseClaim
from app.schemas.reimbursement import ExpenseClaimRead
from app.services.approval_action_protocol import (
ApprovalActionConflictError,
ApprovalActionProtocol,
@@ -117,6 +118,9 @@ def test_approve_replay_persists_one_ledger_event_and_audit(
)
assert first is not None and replay is not None
assert ExpenseClaimRead.model_validate(replay).model_dump(mode="json") == (
ExpenseClaimRead.model_validate(first).model_dump(mode="json")
)
assert replay.approval_stage == "财务审批"
assert db.scalar(select(func.count()).select_from(ApprovalActionLedger)) == 1
assert db.scalar(select(func.count()).select_from(BusinessEvent)) == 1
@@ -130,6 +134,61 @@ def test_approve_replay_persists_one_ledger_event_and_audit(
)
def test_approve_replay_returns_original_snapshot_after_claim_moves_forward(
session_factory: sessionmaker[Session],
) -> None:
with session_factory() as db:
claim = _seed_claim(db, claim_id="claim-action-original-response")
service = ExpenseClaimService(db)
first = service.approve_claim(
claim.id,
_manager_user(),
opinion="同意",
request_id="approve-original-response-1",
expected_status="submitted",
expected_approval_stage="直属领导审批",
)
assert first is not None
first_json = ExpenseClaimRead.model_validate(first).model_dump(mode="json")
current = db.get(ExpenseClaim, claim.id)
assert current is not None
current.status = "pending_payment"
current.approval_stage = "待付款"
current.risk_flags_json = [
*list(current.risk_flags_json or []),
{"source": "future_state", "message": "首次响应之后产生的内部状态"},
]
db.commit()
replay = service.approve_claim(
claim.id,
_manager_user(),
opinion="同意",
request_id="approve-original-response-1",
expected_status="submitted",
expected_approval_stage="直属领导审批",
)
assert replay is not None
assert ExpenseClaimRead.model_validate(replay).model_dump(mode="json") == first_json
assert replay.approval_stage == "财务审批"
assert all(
item.get("source") != "future_state" for item in replay.risk_flags_json or []
)
persisted = db.get(ExpenseClaim, claim.id)
assert persisted is not None
assert persisted.status == "pending_payment"
assert persisted.approval_stage == "待付款"
ledger = db.scalar(
select(ApprovalActionLedger).where(
ApprovalActionLedger.request_id == "approve-original-response-1"
)
)
assert ledger is not None
assert ledger.response_json == first_json
def test_request_id_payload_mismatch_and_stale_preconditions_return_conflict(
session_factory: sessionmaker[Session],
) -> None: