""" 对账执行 API 执行对账任务 """ from typing import Any, Dict, List, Optional from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from app.core.database import get_db from app.core.tenant import get_current_company_id from app.models.reconciliation_task import ReconciliationTask from app.services.reconciliation.engine import run_reconciliation router = APIRouter(prefix="/api/reconciliation", tags=["对账执行"]) @router.post("/execute/{task_id}") async def execute_reconciliation( task_id: int, db: AsyncSession = Depends(get_db), company_id: int = Depends(get_current_company_id), ) -> Dict[str, Any]: """ 执行对账 触发对账引擎,处理上传的数据并返回结果 """ # 获取任务 task = await db.get(ReconciliationTask, task_id) if not task: raise HTTPException(status_code=404, detail="任务不存在") if task.company_id != company_id: raise HTTPException(status_code=403, detail="无权访问该任务") if task.status not in ["MAPPING_COMPLETED", "DATA_UPLOADED"]: raise HTTPException(status_code=400, detail="任务状态不允许执行对账") try: # 获取上传的数据 salary_data = task.salary_data or [] social_security_data = task.social_security_data or [] tax_data = task.tax_data or [] bank_data = task.bank_data if hasattr(task, 'bank_data') else None # 执行对账 result = await run_reconciliation( db=db, company_id=company_id, task_id=task_id, period=task.period, salary_records=salary_data, social_security_records=social_security_data, tax_records=tax_data, bank_records=bank_data, enable_bank_rules=bool(bank_data), ) return { "success": True, "task_id": task_id, "result": { "total_employees": result.total_employees, "matched_employees": result.matched_employees, "exception_count": result.exception_count, "exceptions_by_type": result.exceptions_by_type, "exceptions_by_severity": result.exceptions_by_severity, "execution_time_ms": result.execution_time_ms, "completed_at": result.completed_at, }, } except Exception as e: raise HTTPException(status_code=500, detail=f"对账执行失败: {str(e)}") @router.get("/result/{task_id}") async def get_reconciliation_result( task_id: int, db: AsyncSession = Depends(get_db), company_id: int = Depends(get_current_company_id), ) -> Dict[str, Any]: """ 获取对账结果 返回已执行的对账结果汇总 """ task = await db.get(ReconciliationTask, task_id) if not task: raise HTTPException(status_code=404, detail="任务不存在") if task.company_id != company_id: raise HTTPException(status_code=403, detail="无权访问该任务") # 获取异常统计 from app.services.exception_service import ExceptionService service = ExceptionService(db) summary = await service.get_exception_summary(task_id=task_id, company_id=company_id) return { "task_id": task_id, "period": task.period, "total_employees": task.total_employees, "matched_employees": task.matched_count, "exception_count": task.exception_count, "exceptions_by_type": summary.get("by_type", {}), "exceptions_by_severity": summary.get("by_severity", {}), "exceptions_by_status": summary.get("by_status", {}), "completed_at": task.updated_at.isoformat() if task.updated_at else None, } @router.post("/retry/{task_id}") async def retry_reconciliation( task_id: int, db: AsyncSession = Depends(get_db), company_id: int = Depends(get_current_company_id), ) -> Dict[str, Any]: """ 重试对账 重新执行已完成的或失败的对账任务 """ task = await db.get(ReconciliationTask, task_id) if not task: raise HTTPException(status_code=404, detail="任务不存在") if task.company_id != company_id: raise HTTPException(status_code=403, detail="无权访问该任务") # 重置任务状态 task.status = "PROCESSING" task.matched_count = 0 task.exception_count = 0 await db.commit() # 执行对账 return await execute_reconciliation(task_id, db, company_id)