Files
plantillas-proyectos/backend/api/v1/modules/a76/client_and_provider/routes.py

310 lines
11 KiB
Python

"""
Endpoints API para gestión de clientes y proveedores
"""
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session
from typing import List, Optional
from core.database import get_core_db
from core.security import get_current_user, has_role
from .service import ClientProviderService
from .dto import (
ClientProviderCreateDTO,
ClientProviderUpdateDTO,
ClientProviderResponseDTO,
ClientProviderBasicDTO,
ClientProviderListDTO
)
router = APIRouter(prefix="/clients-providers")
@router.post("/", response_model=ClientProviderResponseDTO, status_code=status.HTTP_201_CREATED)
async def create_client_provider(
client_data: ClientProviderCreateDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Create a new client or provider in the system
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
# Ensure the client_data is associated with the correct tenant and company
if client_data.tenant_id != tenant_id or client_data.company_id != company_id:
raise HTTPException(status_code=400, detail="Mismatch in tenant or company association")
service = ClientProviderService(db)
return service.create_client_provider(client_data)
@router.get("/", response_model=ClientProviderListDTO)
async def list_clients_providers(
skip: int = Query(0, ge=0, description="Number of records to skip"),
limit: int = Query(100, ge=1, le=1000, description="Maximum number of records to return"),
search: Optional[str] = Query(None, description="Search text for name, RFC, or ID"),
client_or_provider: Optional[str] = Query(None, regex="^[CP]$", description="Filter by type: C=Client, P=Provider"),
enabled_only: bool = Query(False, description="Show only enabled records"),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
List clients and providers with optional filters and pagination
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
return service.list_clients_providers(skip, limit, search, client_or_provider, enabled_only)
@router.get("/clients", response_model=List[ClientProviderBasicDTO])
async def get_clients_only(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Get only clients (client_or_provider = 'C')
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
return service.get_clients_only(skip, limit)
@router.get("/providers", response_model=List[ClientProviderBasicDTO])
async def get_providers_only(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Get only providers (client_or_provider = 'P')
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
return service.get_providers_only(skip, limit)
@router.get("/search/rfc/{rfc}", response_model=List[ClientProviderBasicDTO])
async def search_by_rfc(
rfc: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Search clients/providers by RFC
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
return service.search_by_rfc(rfc)
@router.get("/{client_id}", response_model=ClientProviderResponseDTO)
async def get_client_provider(
client_id: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Get client/provider by ID with all related information
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
client = service.get_client_provider(client_id)
if not client:
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
return client
@router.put("/{client_id}", response_model=ClientProviderResponseDTO)
async def update_client_provider(
client_id: str,
client_data: ClientProviderUpdateDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Update client/provider information
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
client = service.update_client_provider(client_id, client_data)
if not client:
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
return client
@router.delete("/{client_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_client_provider(
client_id: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Delete client/provider from the system
Note: This will completely remove the client/provider and all related data.
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
if not service.delete_client_provider(client_id):
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
@router.patch("/{client_id}/toggle-status", response_model=ClientProviderResponseDTO)
async def toggle_client_provider_status(
client_id: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Toggle client/provider enabled/disabled status
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
client = service.toggle_status(client_id)
if not client:
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
return client
# Endpoints específicos para información detallada
@router.get("/{client_id}/address", response_model=dict)
async def get_client_provider_address(
client_id: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Get only address information for a client/provider
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
client = service.get_client_provider(client_id)
if not client:
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
return {
"client_id": client.client_id,
"address": client.address
}
@router.get("/{client_id}/programs", response_model=dict)
async def get_client_provider_programs(
client_id: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Get only programs information for a client/provider
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
client = service.get_client_provider(client_id)
if not client:
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
return {
"client_id": client.client_id,
"programs": client.programs
}
@router.get("/{client_id}/basic", response_model=ClientProviderBasicDTO)
async def get_client_provider_basic_info(
client_id: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
):
"""
Get basic information for a client/provider (without address and programs)
"""
# Validate access to the tenant and company
tenant_id = current_user.get("tenant_id")
company_id = current_user.get("company_id")
if not tenant_id or not company_id:
raise HTTPException(status_code=403, detail="Access denied: Tenant or Company not found")
service = ClientProviderService(db)
client = service.get_client_provider(client_id)
if not client:
raise HTTPException(status_code=404, detail=f"Client/Provider with ID '{client_id}' not found")
return ClientProviderBasicDTO(
client_id=client.client_id,
name=client.name,
short_name=client.short_name,
rfc=client.rfc,
client_or_provider=client.client_or_provider,
enabled_disabled=client.enabled_disabled
)