feat: replace SVG icons with Lucide icons in reference data pages
- Updated the "Nueva Sección" button in customs_sections, customs_warehouses, incoterms, invoice_types, material_types, payment_methods, pedimento_codes, pedimento_regimens, sectors, states, transport_modes, and transport_types pages to use the Plus icon from Lucide. - Updated the "Actualizar" button in the same pages to use the RefreshCw icon from Lucide. - Added a new edit dialog component for customs brokers with a comprehensive form for editing broker details, including validation and loading states.
This commit is contained in:
@@ -9,136 +9,57 @@ from core.security import get_current_user, validate_access_to_resource
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from api.v1.common.tenant_crud_routes import TenantCRUDRoutes
|
||||
from .models import ClientOrProviderEnum
|
||||
|
||||
from .dto import (
|
||||
ClientProviderBasicDTO,
|
||||
ClientProviderCreateDTO,
|
||||
ClientProviderResponseDTO,
|
||||
ClientProviderUpdateDTO,
|
||||
ClientProviderPaginatedResponseDTO,
|
||||
)
|
||||
from .service import ClientProviderService
|
||||
from .models import ClientProvider
|
||||
|
||||
# Create base CRUD router using TenantCRUDRoutes factory
|
||||
base_router = TenantCRUDRoutes(
|
||||
service=ClientProviderService,
|
||||
create_schema=ClientProviderCreateDTO,
|
||||
update_schema=ClientProviderUpdateDTO,
|
||||
response_schema=ClientProviderResponseDTO,
|
||||
prefix="",
|
||||
tags=[],
|
||||
resource_name="Client/Provider",
|
||||
id_name="id", # Using numeric ID
|
||||
enable_list=True, # Enable GET /clients-providers with pagination
|
||||
enable_filters=True, # Enable filtering
|
||||
default_page_size=50,
|
||||
max_page_size=100,
|
||||
).router
|
||||
|
||||
# Create main router to add custom endpoints
|
||||
router = APIRouter(prefix="/clients-providers")
|
||||
|
||||
# Include base CRUD routes
|
||||
router.include_router(base_router, prefix="")
|
||||
|
||||
|
||||
# Custom endpoints
|
||||
@router.get("/clients", response_model=List[ClientProviderBasicDTO])
|
||||
async def get_clients_only(
|
||||
@router.get("/", response_model=ClientProviderPaginatedResponseDTO)
|
||||
async def get_clients_and_providers(
|
||||
company_id: int = Query(..., description="Company ID"),
|
||||
type: Optional[ClientOrProviderEnum] = Query(
|
||||
None, description="Type of entity (client or provider)"
|
||||
),
|
||||
active: Optional[bool] = Query(None, description="Active status"),
|
||||
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 = 'client')"""
|
||||
"""Get clients and providers"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
clients = (
|
||||
db.query(ClientProvider)
|
||||
.filter(
|
||||
ClientProvider.tenant_id == tenant_id,
|
||||
ClientProvider.company_id == company_id,
|
||||
ClientProvider.client_or_provider == "client"
|
||||
)
|
||||
.offset(skip)
|
||||
.limit(limit)
|
||||
.all()
|
||||
|
||||
query = db.query(ClientProvider).filter(
|
||||
ClientProvider.tenant_id == tenant_id,
|
||||
ClientProvider.company_id == company_id,
|
||||
)
|
||||
return [ClientProviderBasicDTO.model_validate(c) for c in clients]
|
||||
|
||||
if type is not None:
|
||||
query = query.filter(ClientProvider.client_or_provider == type)
|
||||
|
||||
@router.get("/providers", response_model=List[ClientProviderBasicDTO])
|
||||
async def get_providers_only(
|
||||
company_id: int = Query(..., description="Company ID"),
|
||||
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 = 'provider')"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
providers = (
|
||||
db.query(ClientProvider)
|
||||
.filter(
|
||||
ClientProvider.tenant_id == tenant_id,
|
||||
ClientProvider.company_id == company_id,
|
||||
ClientProvider.client_or_provider == "provider"
|
||||
)
|
||||
.offset(skip)
|
||||
.limit(limit)
|
||||
.all()
|
||||
)
|
||||
return [ClientProviderBasicDTO.model_validate(p) for p in providers]
|
||||
if active is not None:
|
||||
query = query.filter(ClientProvider.is_active == active)
|
||||
|
||||
total = query.count()
|
||||
clients = query.offset(skip).limit(limit).all()
|
||||
|
||||
@router.get("/search/rfc/{rfc}", response_model=List[ClientProviderBasicDTO])
|
||||
async def search_by_rfc(
|
||||
rfc: str,
|
||||
company_id: int = Query(..., description="Company ID"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""Search clients/providers by RFC"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
clients = (
|
||||
db.query(ClientProvider)
|
||||
.filter(
|
||||
ClientProvider.tenant_id == tenant_id,
|
||||
ClientProvider.company_id == company_id,
|
||||
ClientProvider.rfc.ilike(f"%{rfc}%")
|
||||
)
|
||||
.all()
|
||||
)
|
||||
return [ClientProviderBasicDTO.model_validate(c) for c in clients]
|
||||
|
||||
|
||||
@router.patch("/{client_id}/toggle-status", response_model=ClientProviderResponseDTO)
|
||||
async def toggle_clients_and_providers_status(
|
||||
client_id: int,
|
||||
company_id: int = Query(..., description="Company ID"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""Toggle client/provider enabled/disabled status"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
client = ClientProviderService.get_by_id(db, client_id, tenant_id, company_id)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail="Client/Provider not found")
|
||||
|
||||
# Toggle status (1 = enabled, 0 = disabled)
|
||||
client.enabled_disabled = 1 if client.enabled_disabled == 0 else 0
|
||||
|
||||
try:
|
||||
db.commit()
|
||||
db.refresh(client)
|
||||
return client
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
raise HTTPException(status_code=500, detail="Error updating status")
|
||||
return {
|
||||
"items": [ClientProviderResponseDTO.model_validate(c) for c in clients],
|
||||
"total": total,
|
||||
"page": (skip // limit) + 1,
|
||||
"page_size": limit,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{client_id}/basic", response_model=ClientProviderBasicDTO)
|
||||
@@ -150,9 +71,59 @@ async def get_clients_and_providers_basic_info(
|
||||
):
|
||||
"""Get basic information for a client/provider (without address and programs)"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
|
||||
client = ClientProviderService.get_by_id(db, client_id, tenant_id, company_id)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail="Client/Provider not found")
|
||||
|
||||
|
||||
return ClientProviderBasicDTO.model_validate(client)
|
||||
|
||||
|
||||
@router.post("/", response_model=ClientProviderResponseDTO)
|
||||
async def create_client_provider(
|
||||
client_data: ClientProviderCreateDTO,
|
||||
company_id: int = Query(..., description="Company ID"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""Create a new client/provider"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
return ClientProviderService.create(db, client_data, tenant_id, company_id)
|
||||
|
||||
|
||||
@router.patch("/{client_id}", response_model=ClientProviderResponseDTO)
|
||||
async def update_client_provider(
|
||||
client_id: int,
|
||||
client_data: ClientProviderUpdateDTO,
|
||||
company_id: int = Query(..., description="Company ID"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""Update a client/provider"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
client = ClientProviderService.update(
|
||||
db, client_id, tenant_id, company_id, client_data
|
||||
)
|
||||
if not client:
|
||||
raise HTTPException(status_code=404, detail="Client/Provider not found")
|
||||
|
||||
return client
|
||||
|
||||
|
||||
@router.delete("/{client_id}", response_model=bool)
|
||||
async def delete_client_provider(
|
||||
client_id: int,
|
||||
company_id: int = Query(..., description="Company ID"),
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""Delete a client/provider"""
|
||||
tenant_id = validate_access_to_resource(db, company_id, current_user)
|
||||
|
||||
success = ClientProviderService.delete(db, client_id, tenant_id, company_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Client/Provider not found")
|
||||
|
||||
return success
|
||||
|
||||
Reference in New Issue
Block a user