from unittest.mock import AsyncMock, MagicMock import pytest from app.core.exceptions import AppException from app.models.entities import OperationAudit, RiskItem, UserAccount from app.services.risk_items import RiskItemService @pytest.mark.asyncio async def test_pending_risk_item_can_be_withdrawn_with_audit() -> None: item = RiskItem(id=12, source_type="表单", status="待审核", photos=[], ocr_payload={}) operator = UserAccount(id=3, emp_no="admin-1", name="管理员", role="admin", status="启用") session = MagicMock() session.get = AsyncMock(return_value=item) session.flush = AsyncMock() await RiskItemService(session).withdraw(item.id, operator) assert item.status == "已撤回" audit = next(call.args[0] for call in session.add.call_args_list if isinstance(call.args[0], OperationAudit)) assert audit.action == "risk_item.withdraw" assert audit.audit_metadata == {"previous_status": "待审核"} session.flush.assert_awaited_once() @pytest.mark.asyncio async def test_reviewed_risk_item_cannot_be_withdrawn() -> None: item = RiskItem(id=13, source_type="表单", status="已通过", photos=[], ocr_payload={}) operator = UserAccount(id=3, emp_no="admin-1", name="管理员", role="admin", status="启用") session = MagicMock() session.get = AsyncMock(return_value=item) with pytest.raises(AppException, match="只有待处理风险项可以撤回"): await RiskItemService(session).withdraw(item.id, operator) session.add.assert_not_called()