""" Client Profile Endpoints - ServiceManagerWeb Endpoints para gestión del perfil empresarial de clientes """ from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, or_ from typing import Optional from app.core.database import get_db from app.api.deps import get_current_user, get_current_tenant from app.api.schemas.client_profile import ( ClientProfileCreate, ClientProfileUpdate, ClientProfileResponse, ClientProfileSummary ) from app.models.user import User from app.models.tenant import Tenant from app.models.client_profile import ClientProfile import uuid router = APIRouter() @router.get("/", response_model=ClientProfileResponse) async def get_current_client_profile( current_user: User = Depends(get_current_user), current_tenant: Tenant = Depends(get_current_tenant), db: AsyncSession = Depends(get_db) ): """ Obtener el perfil empresarial del tenant actual. **Permisos**: CLIENT_ADMIN, CLIENT_USER """ # Solo clientes pueden acceder if current_user.role not in ['CLIENT_ADMIN', 'CLIENT_USER']: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Solo los clientes pueden acceder al perfil empresarial" ) # Buscar perfil existente result = await db.execute( select(ClientProfile).where(ClientProfile.tenant_id == current_tenant.id) ) profile = result.scalar_one_or_none() if not profile: # Si no existe, crear uno vacío con valores por defecto explícitos profile = ClientProfile( id=uuid.uuid4(), tenant_id=current_tenant.id ) db.add(profile) await db.commit() await db.refresh(profile) return profile @router.post("/", response_model=ClientProfileResponse) async def create_or_update_client_profile( profile_data: ClientProfileCreate, current_user: User = Depends(get_current_user), current_tenant: Tenant = Depends(get_current_tenant), db: AsyncSession = Depends(get_db) ): """ Crear o actualizar el perfil empresarial del tenant actual. **Permisos**: CLIENT_ADMIN """ # Solo CLIENT_ADMIN puede modificar el perfil if current_user.role != 'CLIENT_ADMIN': raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Solo los administradores de cliente pueden modificar el perfil empresarial" ) # Buscar perfil existente result = await db.execute( select(ClientProfile).where(ClientProfile.tenant_id == current_tenant.id) ) existing_profile = result.scalar_one_or_none() if existing_profile: # Actualizar perfil existente update_data = profile_data.dict(exclude_unset=True) for field, value in update_data.items(): setattr(existing_profile, field, value) profile = existing_profile else: # Crear nuevo perfil profile = ClientProfile( tenant_id=current_tenant.id, **profile_data.dict() ) db.add(profile) await db.commit() await db.refresh(profile) return profile @router.patch("/", response_model=ClientProfileResponse) async def update_client_profile( profile_data: ClientProfileUpdate, current_user: User = Depends(get_current_user), current_tenant: Tenant = Depends(get_current_tenant), db: AsyncSession = Depends(get_db) ): """ Actualizar parcialmente el perfil empresarial del tenant actual. **Permisos**: CLIENT_ADMIN """ # Solo CLIENT_ADMIN puede modificar el perfil if current_user.role != 'CLIENT_ADMIN': raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Solo los administradores de cliente pueden modificar el perfil empresarial" ) # Buscar perfil existente result = await db.execute( select(ClientProfile).where(ClientProfile.tenant_id == current_tenant.id) ) profile = result.scalar_one_or_none() if not profile: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Perfil empresarial no encontrado" ) # Actualizar solo campos proporcionados update_data = profile_data.dict(exclude_unset=True) for field, value in update_data.items(): setattr(profile, field, value) await db.commit() await db.refresh(profile) return profile @router.delete("/") async def delete_client_profile( current_user: User = Depends(get_current_user), current_tenant: Tenant = Depends(get_current_tenant), db: AsyncSession = Depends(get_db) ): """ Eliminar el perfil empresarial del tenant actual. **Permisos**: CLIENT_ADMIN """ # Solo CLIENT_ADMIN puede eliminar el perfil if current_user.role != 'CLIENT_ADMIN': raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Solo los administradores de cliente pueden eliminar el perfil empresarial" ) # Buscar perfil existente result = await db.execute( select(ClientProfile).where(ClientProfile.tenant_id == current_tenant.id) ) profile = result.scalar_one_or_none() if not profile: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Perfil empresarial no encontrado" ) await db.delete(profile) await db.commit() return {"message": "Perfil empresarial eliminado exitosamente"} # === ENDPOINTS ADMINISTRATIVOS (Solo para ADMIN y SUPPORT_MANAGER) === @router.get("/admin/list", response_model=list[ClientProfileSummary]) async def list_all_client_profiles( skip: int = 0, limit: int = 100, search: Optional[str] = None, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): """ Listar todos los perfiles empresariales (solo para administradores). **Permisos**: ADMIN, SUPPORT_MANAGER """ # Solo personal interno puede ver todos los perfiles if current_user.role not in ['ADMIN', 'SUPPORT_MANAGER']: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Acceso denegado" ) query = select(ClientProfile) # Filtro de búsqueda if search: search_filter = or_( ClientProfile.business_name.ilike(f"%{search}%"), ClientProfile.commercial_name.ilike(f"%{search}%"), ClientProfile.rfc.ilike(f"%{search}%"), ClientProfile.client_code.ilike(f"%{search}%") ) query = query.where(search_filter) # Paginación query = query.offset(skip).limit(limit) query = query.order_by(ClientProfile.created_at.desc()) result = await db.execute(query) profiles = result.scalars().all() return profiles @router.get("/admin/{tenant_id}", response_model=ClientProfileResponse) async def get_client_profile_by_tenant( tenant_id: uuid.UUID, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): """ Obtener perfil empresarial de un tenant específico (solo para administradores). **Permisos**: ADMIN, SUPPORT_MANAGER """ # Solo personal interno puede ver perfiles de otros tenants if current_user.role not in ['ADMIN', 'SUPPORT_MANAGER']: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Acceso denegado" ) result = await db.execute( select(ClientProfile).where(ClientProfile.tenant_id == tenant_id) ) profile = result.scalar_one_or_none() if not profile: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Perfil empresarial no encontrado" ) return profile @router.patch("/admin/{tenant_id}", response_model=ClientProfileResponse) async def update_client_profile_by_admin( tenant_id: uuid.UUID, profile_data: ClientProfileUpdate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): """ Actualizar perfil empresarial de un tenant específico (solo para administradores). **Permisos**: ADMIN, SUPPORT_MANAGER """ # Solo personal interno puede modificar perfiles de otros tenants if current_user.role not in ['ADMIN', 'SUPPORT_MANAGER']: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Acceso denegado" ) result = await db.execute( select(ClientProfile).where(ClientProfile.tenant_id == tenant_id) ) profile = result.scalar_one_or_none() if not profile: # Crear perfil si no existe profile = ClientProfile(tenant_id=tenant_id, **profile_data.dict(exclude_unset=True)) db.add(profile) else: # Actualizar perfil existente update_data = profile_data.dict(exclude_unset=True) for field, value in update_data.items(): setattr(profile, field, value) await db.commit() await db.refresh(profile) return profile