from datetime import datetime, timezone from fastapi import HTTPException, status from sqlalchemy.orm import Session from .dto import PipelineCreate, PipelineUpdate, StageCreate, StageUpdate from .models import Pipeline, PipelineStage # ----- Pipelines ----- def get_pipelines(db: Session, tenant_id: int, company_id: int) -> list[Pipeline]: return ( db.query(Pipeline) .filter( Pipeline.tenant_id == tenant_id, Pipeline.company_id == company_id, Pipeline.deleted_at.is_(None), ) .order_by(Pipeline.is_default.desc(), Pipeline.name.asc()) .all() ) def get_pipeline(db: Session, pipeline_id: int, tenant_id: int, company_id: int) -> Pipeline: pipeline = ( db.query(Pipeline) .filter( Pipeline.id == pipeline_id, Pipeline.tenant_id == tenant_id, Pipeline.company_id == company_id, Pipeline.deleted_at.is_(None), ) .first() ) if not pipeline: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Embudo no encontrado") return pipeline def _clear_default(db: Session, tenant_id: int, company_id: int) -> None: """Solo un embudo puede ser el predeterminado por company.""" db.query(Pipeline).filter( Pipeline.tenant_id == tenant_id, Pipeline.company_id == company_id, Pipeline.is_default.is_(True), ).update({Pipeline.is_default: False}) def create_pipeline(db: Session, payload: PipelineCreate, tenant_id: int, company_id: int) -> Pipeline: if payload.is_default: _clear_default(db, tenant_id, company_id) pipeline = Pipeline(**payload.model_dump(), tenant_id=tenant_id, company_id=company_id) db.add(pipeline) db.commit() db.refresh(pipeline) return pipeline def update_pipeline( db: Session, pipeline_id: int, payload: PipelineUpdate, tenant_id: int, company_id: int ) -> Pipeline: pipeline = get_pipeline(db, pipeline_id, tenant_id, company_id) data = payload.model_dump(exclude_unset=True) if data.get("is_default"): _clear_default(db, tenant_id, company_id) for field, value in data.items(): setattr(pipeline, field, value) db.commit() db.refresh(pipeline) return pipeline def delete_pipeline(db: Session, pipeline_id: int, tenant_id: int, company_id: int) -> None: pipeline = get_pipeline(db, pipeline_id, tenant_id, company_id) pipeline.deleted_at = datetime.now(timezone.utc) db.commit() # ----- Stages ----- def get_stages(db: Session, tenant_id: int, company_id: int, pipeline_id: int | None = None) -> list[PipelineStage]: query = db.query(PipelineStage).filter( PipelineStage.tenant_id == tenant_id, PipelineStage.company_id == company_id, PipelineStage.deleted_at.is_(None), ) if pipeline_id is not None: query = query.filter(PipelineStage.pipeline_id == pipeline_id) return query.order_by(PipelineStage.position.asc()).all() def get_stage(db: Session, stage_id: int, tenant_id: int, company_id: int) -> PipelineStage: stage = ( db.query(PipelineStage) .filter( PipelineStage.id == stage_id, PipelineStage.tenant_id == tenant_id, PipelineStage.company_id == company_id, PipelineStage.deleted_at.is_(None), ) .first() ) if not stage: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Etapa no encontrada") return stage def create_stage(db: Session, payload: StageCreate, tenant_id: int, company_id: int) -> PipelineStage: # La etapa debe pertenecer a un embudo del mismo tenant/company get_pipeline(db, payload.pipeline_id, tenant_id, company_id) stage = PipelineStage(**payload.model_dump(), tenant_id=tenant_id, company_id=company_id) db.add(stage) db.commit() db.refresh(stage) return stage def update_stage( db: Session, stage_id: int, payload: StageUpdate, tenant_id: int, company_id: int ) -> PipelineStage: stage = get_stage(db, stage_id, tenant_id, company_id) for field, value in payload.model_dump(exclude_unset=True).items(): setattr(stage, field, value) db.commit() db.refresh(stage) return stage def delete_stage(db: Session, stage_id: int, tenant_id: int, company_id: int) -> None: stage = get_stage(db, stage_id, tenant_id, company_id) stage.deleted_at = datetime.now(timezone.utc) db.commit()