feat(bx): add advance apply withdraw API
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
ac713070ab
commit
9d06e1830e
3 files changed
+89
No files matched your search
@@ -613,6 +613,23 @@ def reject_advance(
|
|||||||
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/{advance_id}/withdraw", response_model=ApiResponse[AdvanceApplyOut])
|
||||||
|
def withdraw_advance(
|
||||||
|
advance_id: str,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
user: BxUserContext = Depends(get_bx_current_user),
|
||||||
|
):
|
||||||
|
advance = AdvanceService.withdraw(db, advance_id, user)
|
||||||
|
if not advance:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail="备用金申请不存在、非本人申请或当前状态不可撤回",
|
||||||
|
)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(advance)
|
||||||
|
return ApiResponse(data=AdvanceApplyOut.model_validate(advance))
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{advance_id}", response_model=ApiResponse[None])
|
@router.delete("/{advance_id}", response_model=ApiResponse[None])
|
||||||
def delete_advance(
|
def delete_advance(
|
||||||
advance_id: str,
|
advance_id: str,
|
||||||
|
|||||||
@@ -347,6 +347,22 @@ class AdvanceService:
|
|||||||
db.flush()
|
db.flush()
|
||||||
return apply_obj
|
return apply_obj
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def withdraw(db: Session, apply_id: str, user: BxUserContext) -> Optional[BxAdvanceApply]:
|
||||||
|
tenant_no = AdvanceService._tenant_no(db, user)
|
||||||
|
apply_obj = AdvanceService.get_by_id(db, apply_id, tenant_no, user=user)
|
||||||
|
if not apply_obj:
|
||||||
|
return None
|
||||||
|
if apply_obj.applicant_id != user.id:
|
||||||
|
return None
|
||||||
|
if apply_obj.status != "pending":
|
||||||
|
return None
|
||||||
|
apply_obj.status = "draft"
|
||||||
|
apply_obj.current_node = None
|
||||||
|
apply_obj.update_by = user.id
|
||||||
|
db.flush()
|
||||||
|
return apply_obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _approval_record_dict(approval: BxAdvanceApproval, apply_id: str) -> Dict[str, Any]:
|
def _approval_record_dict(approval: BxAdvanceApproval, apply_id: str) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
"""备用金撤回:仅申请人且审批中可回草稿。"""
|
||||||
|
from types import SimpleNamespace
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from app.services.bx.advance import AdvanceService
|
||||||
|
|
||||||
|
|
||||||
|
def _user(uid="u1"):
|
||||||
|
return SimpleNamespace(id=uid, name="张三", dept_id="d1")
|
||||||
|
|
||||||
|
|
||||||
|
def _apply(**kwargs):
|
||||||
|
base = {
|
||||||
|
"id": "a1",
|
||||||
|
"applicant_id": "u1",
|
||||||
|
"status": "pending",
|
||||||
|
"current_node": "一级审批",
|
||||||
|
"update_by": None,
|
||||||
|
}
|
||||||
|
base.update(kwargs)
|
||||||
|
return SimpleNamespace(**base)
|
||||||
|
|
||||||
|
|
||||||
|
@patch.object(AdvanceService, "_tenant_no", return_value="T1")
|
||||||
|
@patch.object(AdvanceService, "get_by_id")
|
||||||
|
def test_withdraw_pending_by_applicant(mock_get, _tenant):
|
||||||
|
apply_obj = _apply()
|
||||||
|
mock_get.return_value = apply_obj
|
||||||
|
db = MagicMock()
|
||||||
|
out = AdvanceService.withdraw(db, "a1", _user("u1"))
|
||||||
|
assert out is apply_obj
|
||||||
|
assert apply_obj.status == "draft"
|
||||||
|
assert apply_obj.current_node is None
|
||||||
|
assert apply_obj.update_by == "u1"
|
||||||
|
db.flush.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@patch.object(AdvanceService, "_tenant_no", return_value="T1")
|
||||||
|
@patch.object(AdvanceService, "get_by_id")
|
||||||
|
def test_withdraw_rejects_non_applicant(mock_get, _tenant):
|
||||||
|
mock_get.return_value = _apply(applicant_id="u1")
|
||||||
|
assert AdvanceService.withdraw(MagicMock(), "a1", _user("u2")) is None
|
||||||
|
|
||||||
|
|
||||||
|
@patch.object(AdvanceService, "_tenant_no", return_value="T1")
|
||||||
|
@patch.object(AdvanceService, "get_by_id")
|
||||||
|
def test_withdraw_rejects_non_pending(mock_get, _tenant):
|
||||||
|
mock_get.return_value = _apply(status="draft")
|
||||||
|
assert AdvanceService.withdraw(MagicMock(), "a1", _user("u1")) is None
|
||||||
|
|
||||||
|
|
||||||
|
@patch.object(AdvanceService, "_tenant_no", return_value="T1")
|
||||||
|
@patch.object(AdvanceService, "get_by_id")
|
||||||
|
def test_withdraw_missing_returns_none(mock_get, _tenant):
|
||||||
|
mock_get.return_value = None
|
||||||
|
assert AdvanceService.withdraw(MagicMock(), "a1", _user("u1")) is None
|
||||||
Reference in new issue
Block a user