""" 异常处理服务 处理异常的查询、更新、批量操作等 """ from datetime import datetime from typing import Any, Dict, List, Optional, Tuple from sqlalchemy import select, update, func, and_, or_ from sqlalchemy.ext.asyncio import AsyncSession from app.models.exception_item import ExceptionItem, ExceptionStatus from app.models.reconciliation_task import ReconciliationTask class ExceptionService: """异常处理服务""" def __init__(self, db: AsyncSession): self.db = db async def get_exceptions( self, task_id: Optional[int] = None, company_id: Optional[int] = None, status: Optional[str] = None, severity: Optional[str] = None, exception_type: Optional[str] = None, page: int = 1, page_size: int = 20, ) -> Tuple[List[ExceptionItem], int]: """ 查询异常列表 Args: task_id: 任务ID company_id: 企业ID status: 状态 severity: 严重程度 exception_type: 异常类型 page: 页码 page_size: 每页数量 Returns: (异常列表, 总数) """ from sqlalchemy.orm import selectinload query = select(ExceptionItem).options(selectinload(ExceptionItem.handler)) count_query = select(func.count(ExceptionItem.id)) # 条件 filters = [] if task_id: filters.append(ExceptionItem.task_id == task_id) if company_id: filters.append(ExceptionItem.company_id == company_id) if status: filters.append(ExceptionItem.status == status) if severity: filters.append(ExceptionItem.severity == severity) if exception_type: filters.append(ExceptionItem.exception_type == exception_type) if filters: query = query.where(and_(*filters)) count_query = count_query.where(and_(*filters)) # 总数 total_result = await self.db.execute(count_query) total = total_result.scalar() or 0 # 分页 query = query.order_by( ExceptionItem.created_at.desc() ).offset((page - 1) * page_size).limit(page_size) result = await self.db.execute(query) exceptions = result.scalars().all() return list(exceptions), total async def get_exception(self, exception_id: int) -> Optional[ExceptionItem]: """获取单个异常""" return await self.db.get(ExceptionItem, exception_id) async def update_exception( self, exception_id: int, status: Optional[str] = None, handling_note: Optional[str] = None, handled_by: Optional[int] = None, ) -> Optional[ExceptionItem]: """ 更新异常 Args: exception_id: 异常ID status: 新状态 handling_note: 处理备注 handled_by: 处理人ID Returns: 更新后的异常 """ exception = await self.db.get(ExceptionItem, exception_id) if not exception: return None if status: exception.status = status if handling_note: exception.handling_note = handling_note if handled_by: exception.handled_by = handled_by exception.updated_at = datetime.utcnow() await self.db.commit() await self.db.refresh(exception) return exception async def batch_update_status( self, exception_ids: List[int], status: str, ) -> int: """ 批量更新状态 Args: exception_ids: 异常ID列表 status: 新状态 Returns: 更新的数量 """ if not exception_ids: return 0 stmt = ( update(ExceptionItem) .where(ExceptionItem.id.in_(exception_ids)) .values( status=status, updated_at=datetime.utcnow(), ) ) result = await self.db.execute(stmt) await self.db.commit() return result.rowcount or 0 async def batch_resolve( self, exception_ids: List[int], handling_note: str, handled_by: Optional[int] = None, ) -> int: """ 批量处理异常 Args: exception_ids: 异常ID列表 handling_note: 处理备注 handled_by: 处理人ID Returns: 处理的数量 """ if not exception_ids: return 0 update_data = { "status": ExceptionStatus.RESOLVED.value, "handling_note": handling_note, "updated_at": datetime.utcnow(), } if handled_by: update_data["handled_by"] = handled_by stmt = ( update(ExceptionItem) .where(ExceptionItem.id.in_(exception_ids)) .values(**update_data) ) result = await self.db.execute(stmt) await self.db.commit() return result.rowcount or 0 async def get_exception_summary( self, task_id: Optional[int] = None, company_id: Optional[int] = None, ) -> Dict[str, Any]: """ 获取异常汇总统计 Args: task_id: 任务ID company_id: 企业ID Returns: 汇总统计 """ # 按状态统计 status_query = select( ExceptionItem.status, func.count(ExceptionItem.id).label("count") ).group_by(ExceptionItem.status) # 按严重程度统计 severity_query = select( ExceptionItem.severity, func.count(ExceptionItem.id).label("count") ).group_by(ExceptionItem.severity) # 按类型统计 type_query = select( ExceptionItem.exception_type, func.count(ExceptionItem.id).label("count") ).group_by(ExceptionItem.exception_type) # 条件 filters = [] if task_id: filters.append(ExceptionItem.task_id == task_id) if company_id: filters.append(ExceptionItem.company_id == company_id) if filters: status_query = status_query.where(and_(*filters)) severity_query = severity_query.where(and_(*filters)) type_query = type_query.where(and_(*filters)) # 执行查询 status_result = await self.db.execute(status_query) severity_result = await self.db.execute(severity_query) type_result = await self.db.execute(type_query) return { "by_status": { row.status: row.count for row in status_result.all() }, "by_severity": { row.severity: row.count for row in severity_result.all() }, "by_type": { row.exception_type: row.count for row in type_result.all() }, } async def get_pending_exceptions( self, company_id: int, limit: int = 10, ) -> List[ExceptionItem]: """获取待处理的异常""" query = ( select(ExceptionItem) .where( and_( ExceptionItem.company_id == company_id, ExceptionItem.status == ExceptionStatus.PENDING.value, ) ) .order_by(ExceptionItem.created_at.desc()) .limit(limit) ) result = await self.db.execute(query) return list(result.scalars().all()) # 便捷函数 async def get_exceptions( db: AsyncSession, **kwargs, ) -> Tuple[List[ExceptionItem], int]: """查询异常列表""" service = ExceptionService(db) return await service.get_exceptions(**kwargs) async def update_exception( db: AsyncSession, exception_id: int, **kwargs, ) -> Optional[ExceptionItem]: """更新异常""" service = ExceptionService(db) return await service.update_exception(exception_id, **kwargs) async def batch_resolve_exceptions( db: AsyncSession, exception_ids: List[int], handling_note: str, handled_by: Optional[int] = None, ) -> int: """批量处理异常""" service = ExceptionService(db) return await service.batch_resolve(exception_ids, handling_note, handled_by)