"""请假申请 API — 工作流测试""" from __future__ import annotations import logging from typing import Optional from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from app.core.menu_guard import require_admin_or_super_admin from app.core.database import get_db from app.core.response import success_response, error_response from app.crud import leave as leave_crud from app.crud.leave import total_pages from app.schemas.leave import LeaveCreate, LeaveUpdate logger = logging.getLogger(__name__) router = APIRouter(prefix="/web/admin/leave", tags=["请假管理"]) _LEAVE_TYPE_MAP = {"personal": "事假", "sick": "病假", "annual": "年假", "other": "其他"} def _leave_local_callback(db: Session, business_id: str, event: str) -> None: if not business_id: return if event == "completed": leave_crud.update_leave_status(db, business_id, "approved") elif event == "rejected": leave_crud.update_leave_status(db, business_id, "rejected") db.commit() from app.services.workflow_callback import register_local_callback register_local_callback("/api/admin/leave/callback", _leave_local_callback) @router.get("") def list_leaves( page: int = Query(1, ge=1), pageSize: int = Query(10, ge=1, le=100), keyword: Optional[str] = Query(None), status: Optional[str] = Query(None), _user: dict = Depends(require_admin_or_super_admin), db: Session = Depends(get_db), ): tenant_no = _user.get("tenant_no", "") user_id = _user.get("user_id") or _user.get("id", "") items, total = leave_crud.list_leaves( db, page=page, page_size=pageSize, keyword=keyword, status=status, tenant_no=tenant_no, create_by=user_id, user_info=_user, ) for item in items: item["leaveTypeLabel"] = _LEAVE_TYPE_MAP.get(item.get("leaveType", ""), item.get("leaveType", "")) return success_response({ "list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": total_pages(total, pageSize), }) @router.post("") def create_leave( body: LeaveCreate, _user: dict = Depends(require_admin_or_super_admin), db: Session = Depends(get_db), ): tenant_no = _user.get("tenant_no", "") user_id = _user.get("user_id") or _user.get("id", "") dept_id = _user.get("region_id", "") row = leave_crud.create_leave( db, leave_type=body.leaveType, start_date=body.startDate, end_date=body.endDate, days=body.days, reason=body.reason or "", tenant_no=tenant_no, user_id=user_id, dept_id=dept_id, remark=body.remark or "", ) db.commit() return success_response(leave_crud._row_to_dict(row)) @router.post("/{leave_id}/submit") def submit_leave( leave_id: str, _user: dict = Depends(require_admin_or_super_admin), db: Session = Depends(get_db), ): from app.models.models import WfProcessDef from app.services.workflow_engine import WorkflowEngine tenant_no = _user.get("tenant_no", "") user_id = _user.get("user_id") or _user.get("id", "") leave = leave_crud.get_leave(db, leave_id) if not leave: return error_response(404, "请假记录不存在") if leave["status"] not in ("draft", "rejected"): return error_response(400, "只有草稿或已驳回的请假单可以提交") defn = db.query(WfProcessDef).filter( WfProcessDef.process_code == "leave_request", WfProcessDef.del_flag == 0, WfProcessDef.status == "1", ).first() if not defn: return error_response(400, "未找到请假审批流程(leave_request),请先在流程配置中创建并发布") variables = { "days": leave["days"], "leave_days": leave["days"], "leaveType": leave["leaveType"], "applicant": user_id, } try: engine = WorkflowEngine(db) instance = engine.start_process( process_def_id=defn.id, business_type="leave", business_id=leave_id, starter_user_id=user_id, variables=variables, callback_url="/api/admin/leave/callback", tenant_no=tenant_no, user_id=user_id, ) leave_crud.update_leave_status(db, leave_id, "pending", wf_instance_id=instance.id, user_id=user_id) db.commit() return success_response({"instanceId": instance.id, "status": "pending"}) except Exception as e: db.rollback() logger.exception("发起请假审批失败: %s", e) return error_response(500, f"发起审批失败: {e}") @router.post("/callback") def leave_workflow_callback( body: dict, db: Session = Depends(get_db), ): logger.info("请假工作流回调: %s", body) business_id = body.get("businessId", "") event = body.get("event", "") if not business_id: return success_response({"received": True}) if event == "completed": leave_crud.update_leave_status(db, business_id, "approved") elif event == "rejected": leave_crud.update_leave_status(db, business_id, "rejected") db.commit() return success_response({"received": True}) @router.get("/{leave_id}") def get_leave( leave_id: str, _user: dict = Depends(require_admin_or_super_admin), db: Session = Depends(get_db), ): item = leave_crud.get_leave(db, leave_id) if not item: return error_response(404, "请假记录不存在") item["leaveTypeLabel"] = _LEAVE_TYPE_MAP.get(item.get("leaveType", ""), item.get("leaveType", "")) return success_response(item) @router.delete("/{leave_id}") def delete_leave( leave_id: str, _user: dict = Depends(require_admin_or_super_admin), db: Session = Depends(get_db), ): user_id = _user.get("user_id") or _user.get("id", "") leave = leave_crud.get_leave(db, leave_id) if not leave: return error_response(404, "请假记录不存在") if leave["status"] == "pending": return error_response(400, "审批中的请假单不能删除") leave_crud.soft_delete_leave(db, leave_id, user_id=user_id, user_info=_user) db.commit() return success_response(None) @router.put("/{leave_id}") def update_leave( leave_id: str, body: LeaveUpdate, _user: dict = Depends(require_admin_or_super_admin), db: Session = Depends(get_db), ): user_id = _user.get("user_id") or _user.get("id", "") leave = leave_crud.get_leave(db, leave_id) if not leave: return error_response(404, "请假记录不存在") if leave["status"] not in ("draft", "rejected"): return error_response(400, "只有草稿或已驳回状态可以编辑") leave_crud.update_leave(db, leave_id, user_id=user_id, **body.model_dump(exclude_none=True)) db.commit() return success_response(leave_crud.get_leave(db, leave_id))