"""Task service: CRUD + assignment + status management.""" from sqlalchemy.orm import Session from typing import List, Optional from datetime import datetime from app.models.task import Task from app.schemas.task import TaskCreate, TaskUpdate, TaskAssign class TaskService: @staticmethod def list_tasks( db: Session, tenant_id: int, project_id: Optional[int] = None, status: Optional[str] = None, assignee_id: Optional[int] = None, skip: int = 0, limit: int = 100, ) -> List[Task]: q = db.query(Task).filter(Task.tenant_id == tenant_id) if project_id: q = q.filter(Task.project_id == project_id) if status: q = q.filter(Task.status == status) if assignee_id: q = q.filter(Task.assignee_id == assignee_id) return q.order_by(Task.created_at.desc()).offset(skip).limit(limit).all() @staticmethod def get_task(db: Session, tenant_id: int, task_id: int) -> Optional[Task]: return ( db.query(Task) .filter(Task.id == task_id, Task.tenant_id == tenant_id) .first() ) @staticmethod def create_task( db: Session, tenant_id: int, project_id: int, req: TaskCreate ) -> Task: task = Task( tenant_id=tenant_id, project_id=project_id, title=req.title, description=req.description, status="pending", priority=req.priority, task_type=req.task_type, input_data=req.input_data, requires_review=req.requires_review, assignee_id=req.assignee_id, worker_id=req.worker_id, due_date=req.due_date, depends_on=req.depends_on, ) db.add(task) db.commit() db.refresh(task) return task @staticmethod def update_task( db: Session, tenant_id: int, task_id: int, req: TaskUpdate ) -> Task: task = TaskService.get_task(db, tenant_id, task_id) if not task: raise ValueError(f"Task #{task_id} not found") for field, value in req.model_dump(exclude_unset=True).items(): setattr(task, field, value) db.commit() db.refresh(task) return task @staticmethod def delete_task(db: Session, tenant_id: int, task_id: int) -> bool: task = TaskService.get_task(db, tenant_id, task_id) if not task: return False db.delete(task) db.commit() return True @staticmethod def assign_task( db: Session, tenant_id: int, task_id: int, req: TaskAssign ) -> Task: task = TaskService.get_task(db, tenant_id, task_id) if not task: raise ValueError(f"Task #{task_id} not found") if req.assignee_id is not None: task.assignee_id = req.assignee_id if req.worker_id is not None: task.worker_id = req.worker_id if task.status == "pending": task.status = "assigned" db.commit() db.refresh(task) return task @staticmethod def mark_status( db: Session, tenant_id: int, task_id: int, status: str, output: str = "" ) -> Task: task = TaskService.get_task(db, tenant_id, task_id) if not task: raise ValueError(f"Task #{task_id} not found") task.status = status if output: task.output_data = output if status == "in_progress": task.started_at = datetime.utcnow() elif status in ("done", "review", "rejected", "cancelled"): task.completed_at = datetime.utcnow() db.commit() db.refresh(task) return task