diff --git a/backend/api/v1/modules/a76/router.py b/backend/api/v1/modules/a76/router.py index 78cac9b3..6129f616 100644 --- a/backend/api/v1/modules/a76/router.py +++ b/backend/api/v1/modules/a76/router.py @@ -71,14 +71,14 @@ router.include_router( ) router.include_router(exchange_rate_router, prefix="/a76", tags=["a76 / exchange_rate"]) -router.include_router(trailers_router, prefix="/a76", tags=["a76 / trailers"]) +router.include_router(trailers_router, prefix="/a76/transportation", tags=["a76 / trailers"]) router.include_router( customs_broker_router, prefix="/a76", tags=["a76 / customs_broker"] ) -router.include_router(drivers_router, prefix="/a76", tags=["a76 / drivers"]) -router.include_router(transporters_router, prefix="/a76", +router.include_router(drivers_router, prefix="/a76/transportation", tags=["a76 / drivers"]) +router.include_router(transporters_router, prefix="/a76/transportation", tags=["a76 / transporters"]) -router.include_router(vehicles_router, prefix="/a76", tags=["a76 / vehicles"]) +router.include_router(vehicles_router, prefix="/a76/transportation", tags=["a76 / vehicles"]) # Registrar catálogos generales adicionales router.include_router(concepts_router, prefix="/a76") diff --git a/backend/api/v1/modules/a76/transportation/drivers/dto.py b/backend/api/v1/modules/a76/transportation/drivers/dto.py index 014459a6..f07e4b4c 100644 --- a/backend/api/v1/modules/a76/transportation/drivers/dto.py +++ b/backend/api/v1/modules/a76/transportation/drivers/dto.py @@ -28,8 +28,8 @@ class DriverBaseDTO(BaseModel): badge_number: Optional[str] class_type: Optional[str] unique_badge_number: Optional[str] - company_id: str - tenant_id: str + company_id: int + tenant_id: int class DriverCreateDTO(DriverBaseDTO): diff --git a/backend/api/v1/modules/a76/transportation/drivers/routes.py b/backend/api/v1/modules/a76/transportation/drivers/routes.py index ebab5154..981ab353 100644 --- a/backend/api/v1/modules/a76/transportation/drivers/routes.py +++ b/backend/api/v1/modules/a76/transportation/drivers/routes.py @@ -1,31 +1,53 @@ -from typing import List +from typing import Any, Dict, List from core.database import get_core_db -from core.security import get_current_user -from fastapi import APIRouter, Depends, HTTPException, status +from core.security import get_current_user, validate_access_to_resource +from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.orm import Session from .dto import DriverCreateDTO, DriverResponseDTO +from .models import Driver from .services import DriverService router = APIRouter(prefix="/drivers") -@router.get("/", response_model=List[DriverResponseDTO]) +@router.get("/", response_model=Dict[str, Any]) async def list_drivers( - db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user) + company_id: int = Query(..., description="Company ID for filtering"), + page: int = Query(1, ge=1, description="Page number"), + page_size: int = Query(50, ge=1, le=100, description="Page size"), + db: Session = Depends(get_core_db), + current_user: dict = Depends(get_current_user), ): - return db.query(DriverService).all() + tenant_id = validate_access_to_resource(db, company_id, current_user) + drivers = DriverService.list_drivers(db, str(company_id), tenant_id) + total = len(drivers) + + # Aplicar paginación manualmente + skip = (page - 1) * page_size + paginated_drivers = drivers[skip : skip + page_size] + + return { + "items": [DriverResponseDTO.model_validate(driver) for driver in paginated_drivers], + "total": total, + "page": page, + "page_size": page_size, + } @router.get("/{transporter_key}/{line}", response_model=DriverResponseDTO) async def read_driver( transporter_key: str, line: int, + company_id: int = Query(..., description="Company ID for filtering"), db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user), ): - driver = DriverService.get_driver_by_key_and_line(db, transporter_key, line) + tenant_id = validate_access_to_resource(db, company_id, current_user) + driver = DriverService.get_driver_by_key_and_line( + db, transporter_key, line, str(company_id), tenant_id + ) if not driver: raise HTTPException(status_code=404, detail="Driver not found") return driver @@ -44,9 +66,13 @@ async def create_driver( async def delete_driver( transporter_key: str, line: int, + company_id: int = Query(..., description="Company ID for filtering"), db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user), ): - driver = DriverService.delete_driver(db, transporter_key, line) + tenant_id = validate_access_to_resource(db, company_id, current_user) + driver = DriverService.delete_driver( + db, transporter_key, line, str(company_id), tenant_id + ) if not driver: raise HTTPException(status_code=404, detail="Driver not found") diff --git a/backend/api/v1/modules/a76/transportation/drivers/services.py b/backend/api/v1/modules/a76/transportation/drivers/services.py index 9800b62f..c22a49c0 100644 --- a/backend/api/v1/modules/a76/transportation/drivers/services.py +++ b/backend/api/v1/modules/a76/transportation/drivers/services.py @@ -1,3 +1,5 @@ +from typing import List, Optional + from sqlalchemy.orm import Session from . import dto, models @@ -5,15 +7,30 @@ from . import dto, models class DriverService: @staticmethod - def get_driver_by_key_and_line(db: Session, transporter_key: str, line: int): - return ( - db.query(models.Driver) - .filter( - models.Driver.transporter_key == transporter_key, - models.Driver.line == line, - ) - .first() + def list_drivers( + db: Session, company_id: str, tenant_id: Optional[str] = None + ) -> List[models.Driver]: + query = db.query(models.Driver).filter(models.Driver.company_id == company_id) + if tenant_id: + query = query.filter(models.Driver.tenant_id == tenant_id) + return query.all() + + @staticmethod + def get_driver_by_key_and_line( + db: Session, + transporter_key: str, + line: int, + company_id: str, + tenant_id: Optional[str] = None, + ) -> Optional[models.Driver]: + query = db.query(models.Driver).filter( + models.Driver.transporter_key == transporter_key, + models.Driver.line == line, + models.Driver.company_id == company_id, ) + if tenant_id: + query = query.filter(models.Driver.tenant_id == tenant_id) + return query.first() @staticmethod def create_driver(db: Session, driver_data: dto.DriverCreateDTO): @@ -24,8 +41,16 @@ class DriverService: return new_driver @staticmethod - def delete_driver(db: Session, transporter_key: str, line: int): - driver = DriverService.get_driver_by_key_and_line(db, transporter_key, line) + def delete_driver( + db: Session, + transporter_key: str, + line: int, + company_id: str, + tenant_id: Optional[str] = None, + ) -> Optional[models.Driver]: + driver = DriverService.get_driver_by_key_and_line( + db, transporter_key, line, company_id, tenant_id + ) if driver: db.delete(driver) db.commit() diff --git a/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py b/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py index 76533e83..6d421350 100644 --- a/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py +++ b/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py @@ -14,7 +14,7 @@ router = APIRouter(prefix="/code-pedimento-regimens") @router.get("/", response_model=Dict[str, Any]) def list_code_pedimento_regimens( page: int = Query(1, ge=1, description="Número de página"), - page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"), + page_size: int = Query(50, ge=1, le=1000, description="Tamaño de página"), code: str = Query(None, description="Filter by code"), regime: str = Query(None, description="Filter by regime"), type: str = Query(None, description="Filter by type"), @@ -27,9 +27,9 @@ def list_code_pedimento_regimens( if code is not None: query = query.filter(CodePedimentoRegimen.pedimento_code == code) if regime is not None: - query = query.filter(CodePedimentoRegimen.regime == regime) + query = query.filter(CodePedimentoRegimen.regimen_code == regime) if type is not None: - query = query.filter(CodePedimentoRegimen.type == type) + query = query.filter(CodePedimentoRegimen.type_code == type) items = query.offset(skip).limit(page_size).all() total = query.count() diff --git a/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte b/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte index 508208a7..196da7d9 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte @@ -17,6 +17,12 @@ providers = [], currencyTypes = [], transportTypes = [], + transporters = [], + vehicles = [], + drivers = [], + trailers = [], + customsSections = [], + codePedimentoRegimens = [], defaultOperationType = undefined, defaultInvoiceType = undefined }: { @@ -28,10 +34,27 @@ providers?: any[]; currencyTypes?: any[]; transportTypes?: any[]; + transporters?: any[]; + vehicles?: any[]; + drivers?: any[]; + trailers?: any[]; + customsSections?: any[]; + codePedimentoRegimens?: any[]; defaultOperationType?: number | null; defaultInvoiceType?: string | null; } = $props(); + $effect(() => { + console.log('GeneralTabForm - Datos recibidos:', { + transporters: transporters?.length, + vehicles: vehicles?.length, + drivers: drivers?.length, + trailers: trailers?.length, + customsSections: customsSections?.length, + codePedimentoRegimens: codePedimentoRegimens?.length + }); + }); + if (!formData) { if (invoice) { // Editando una factura existente @@ -174,6 +197,24 @@ // Combinar clientes y proveedores para shipped_to const allClientsProviders = [...clients, ...providers]; + + // Filtrar regímenes por tipo de operación (1='1' exp, 2='2' imp) + const filteredRegimens = $derived( + codePedimentoRegimens.filter(r => + r.type_code === String(formData.operation_type) + ) + ); + + $effect(() => { + console.log('Datos recibidos:', { + transporters, + vehicles, + drivers, + trailers, + customsSections, + codePedimentoRegimens + }); +}); @@ -206,16 +247,14 @@