feat: Enhance driver and transportation data handling in invoice editing

- Added methods to list drivers and filter by company and tenant in DriverService.
- Updated API routes to include transporters, vehicles, drivers, trailers, customs sections, and code pedimento regimens.
- Modified frontend components to handle new transportation data, including select inputs for transporters, vehicles, drivers, and trailers.
- Improved data fetching in server-side routes to include additional transportation-related data.
- Enhanced UI components to display and select transportation-related information in the invoice editing form.
This commit is contained in:
AlexeerCT
2025-12-30 15:57:27 -06:00
parent 5bb9343f6e
commit 3210e53608
11 changed files with 516 additions and 115 deletions

View File

@@ -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")

View File

@@ -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):

View File

@@ -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")

View File

@@ -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()

View File

@@ -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()

View File

@@ -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
});
});
</script>
<!-- Layout de 2 columnas compacto -->
@@ -206,16 +247,14 @@
<div class="grid grid-cols-4 gap-3 space-y-1.5">
<Select.Root
type="single"
value={formData.provider_header || ''}
value={formData.provider_header || providerHeaderOptions[0]?.value || ''}
onValueChange={(v) => {
formData.provider_header = v ?? '';
}}
>
<Select.Trigger id="provider_header" class="h-7 text-xs">
<Select.Trigger id="provider_header" class="h-7 text-xs min-w-[125px] max-w-[250px]">
<span class="truncate">
{formData.provider_header
? providerHeaderOptions.find(o => o.value === formData.provider_header)?.label || formData.provider_header
: 'Selecciona encabezado...'}
{providerHeaderOptions.find(o => o.value === (formData.provider_header || providerHeaderOptions[0]?.value))?.label || 'Selecciona encabezado...'}
</span>
</Select.Trigger>
<Select.Content>
@@ -233,7 +272,7 @@
formData.provider_id = v ? parseInt(v) : null;
}}
>
<Select.Trigger id="provider_id" class="h-7 text-xs">
<Select.Trigger id="provider_id" class="h-7 text-xs min-w-[120px] max-w-[250px]">
<span class="truncate">
{formData.provider_id
? providers.find(p => p.id === formData.provider_id)?.name || 'Selecciona...'
@@ -253,16 +292,14 @@
<div class="grid grid-cols-4 gap-3 space-y-1.5">
<Select.Root
type="single"
value={formData.sold_to_header || ''}
value={formData.sold_to_header || soldToHeaderOptions[0]?.value || ''}
onValueChange={(v) => {
formData.sold_to_header = v ?? '';
}}
>
<Select.Trigger id="sold_to_header" class="h-7 text-xs">
<Select.Trigger id="sold_to_header" class="h-7 text-xs min-w-[125px] max-w-[250px]">
<span class="truncate">
{formData.sold_to_header
? soldToHeaderOptions.find(o => o.value === formData.sold_to_header)?.label || formData.sold_to_header
: 'Selecciona encabezado...'}
{soldToHeaderOptions.find(o => o.value === (formData.sold_to_header || soldToHeaderOptions[0]?.value))?.label || 'Selecciona encabezado...'}
</span>
</Select.Trigger>
<Select.Content>
@@ -280,7 +317,7 @@
formData.sold_to_id = v ? parseInt(v) : null;
}}
>
<Select.Trigger id="sold_to_id" class="h-7 text-xs">
<Select.Trigger id="sold_to_id" class="h-7 text-xs min-w-[120px] max-w-[250px]">
<span class="truncate">
{formData.sold_to_id
? clients.find(c => c.id === formData.sold_to_id)?.name || 'Selecciona...'
@@ -300,16 +337,14 @@
<div class="grid grid-cols-4 gap-3 space-y-1.5">
<Select.Root
type="single"
value={formData.shipped_to_header || ''}
value={formData.shipped_to_header || shippedToHeaderOptions[0]?.value || ''}
onValueChange={(v) => {
formData.shipped_to_header = v ?? '';
}}
>
<Select.Trigger id="shipped_to_header" class="h-7 text-xs">
<Select.Trigger id="shipped_to_header" class="h-7 text-xs min-w-[125px] max-w-[250px]">
<span class="truncate">
{formData.shipped_to_header
? shippedToHeaderOptions.find(o => o.value === formData.shipped_to_header)?.label || formData.shipped_to_header
: 'Selecciona encabezado...'}
{shippedToHeaderOptions.find(o => o.value === (formData.shipped_to_header || shippedToHeaderOptions[0]?.value))?.label || 'Selecciona encabezado...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
@@ -327,7 +362,7 @@
formData.shipped_to_id = v ? parseInt(v) : null;
}}
>
<Select.Trigger id="shipped_to_id" class="h-7 text-xs">
<Select.Trigger id="shipped_to_id" class="h-7 text-xs min-w-[120px] max-w-[250px]">
<span class="truncate">
{formData.shipped_to_id
? allClientsProviders.find(cp => cp.id === formData.shipped_to_id)?.name || 'Selecciona...'
@@ -349,16 +384,14 @@
<Label for="customs_broker_id" class="text-xs">Agente Aduanal Mex:</Label>
<Select.Root
type="single"
value={formData.customs_broker_id || ''}
value={formData.customs_broker_id || customsBrokers[0]?.broker_key || ''}
onValueChange={(v) => {
formData.customs_broker_id = v || null;
}}
>
<Select.Trigger id="customs_broker_id" class="h-7 text-xs">
<Select.Trigger id="customs_broker_id" class="h-7 text-xs min-w-[150px] max-w-[300px]">
<span class="truncate">
{formData.customs_broker_id
? customsBrokers.find(cb => cb.broker_key === formData.customs_broker_id)?.name || '...'
: '...'}
{customsBrokers.find(cb => cb.broker_key === (formData.customs_broker_id || customsBrokers[0]?.broker_key))?.name || '...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
@@ -380,7 +413,7 @@
formData.customs_broker_us_id = v || null;
}}
>
<Select.Trigger id="customs_broker_us_id" class="h-7 text-xs">
<Select.Trigger id="customs_broker_us_id" class=" min-w-[150px] h-7 text-xs">
<span class="truncate">
{formData.customs_broker_us_id
? customsBrokers.find(cb => cb.broker_key === formData.customs_broker_us_id)?.name || '...'
@@ -402,7 +435,10 @@
<div class="space-y-3">
<!-- Tipo de Moneda - Pesos Netos y Brutos -->
<div class="border rounded-md p-3 space-y-2">
<h4 class="text-xs font-semibold text-muted-foreground uppercase">Tipo de Moneda - Pesos Netos y Brutos</h4>
<div class="flex justify-between">
<h4 class="text-xs font-semibold text-muted-foreground uppercase">Tipo de Moneda - Pesos Netos y Brutos</h4>
<h4 class="text-xs font-semibold text-muted-foreground uppercase">Tipo de cambio: </h4>
</div>
<!-- Radio buttons para tipo de moneda -->
<div class="space-y-1.5">
@@ -421,8 +457,7 @@
</div>
</RadioGroup.Root>
</div>
<div class="grid grid-cols-3 gap-2">
{#if formData.currency_mode === 'captura'}
<div class="space-y-1.5">
<Label for="currency_type" class="text-xs">Moneda:</Label>
<Select.Root
@@ -432,12 +467,12 @@
formData.currency_type = v ?? '';
}}
>
<Select.Trigger id="currency_type" class="h-7 text-xs">
<Select.Trigger id="currency_type" class="h-7 text-xs min-w-[80px]">
<span class="truncate">
{formData.currency_type || '...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
<Select.Content class="min-w-[80px] max-h-[300px]">
{#each currencyTypes as currencyType}
<Select.Item value={currencyType.code}>
{currencyType.code}
@@ -446,7 +481,8 @@
</Select.Content>
</Select.Root>
</div>
{/if}
<div class="grid grid-cols-3 gap-2">
<div class="space-y-1.5">
<Label for="weight_type" class="text-xs">Tipo Peso:</Label>
<Select.Root
@@ -456,15 +492,15 @@
formData.weight_type = v ?? '';
}}
>
<Select.Trigger id="weight_type" class="h-7 text-xs">
<Select.Trigger id="weight_type" class="min-w-[150px] h-7 text-xs">
<span class="truncate">
{formData.weight_type || '...'}
</span>
</Select.Trigger>
<Select.Content>
{#each weightTypeOptions as weightType}
<Select.Item value={weightType.value}>
{weightType.value}
<Select.Item value={weightType.label}>
{weightType.label}
</Select.Item>
{/each}
</Select.Content>
@@ -475,33 +511,7 @@
<Label for="iva_factor" class="text-xs">IVA:</Label>
<Input id="iva_factor" type="number" step="0.0001" bind:value={formData.iva_factor} placeholder="0.16" class="h-7 text-xs" />
</div>
</div>
<div class="space-y-1.5">
<Label for="invoice_type" class="text-xs">Tipo de Cambio:</Label>
<Select.Root
type="single"
value={formData.invoice_type || ''}
onValueChange={(v) => {
formData.invoice_type = v ?? '';
}}
>
<Select.Trigger id="invoice_type" class="h-7 text-xs">
<span class="truncate">
{formData.invoice_type
? `${formData.invoice_type}`
: '...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each invoiceTypes as type}
<Select.Item value={type.key}>
{type.key} - {type.description}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
</div>
</div>
<!-- Transportista -->
@@ -510,8 +520,33 @@
<div class="grid grid-cols-3 gap-2">
<div class="space-y-1.5">
<Label for="carrier_id" class="text-xs">Clave:</Label>
<Input id="carrier_id" type="number" bind:value={formData.carrier_id} class="h-7 text-xs" />
<Label for="carrier_id" class="text-xs">Transportista:</Label>
<Select.Root
type="single"
value={formData.carrier_id ? String(formData.carrier_id) : ''}
onValueChange={(v) => {
formData.carrier_id = v || null;
}}
>
<Select.Trigger id="carrier_id" class="h-7 text-xs min-w-[120px] max-w-[250px]">
<span class="truncate">
{#if formData.carrier_id}
{transporters.find(t => String(t.transporter_key) === String(formData.carrier_id))?.name || formData.carrier_id}
{:else if transporters.length > 0}
Selecciona transportista...
{:else}
Sin datos
{/if}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transporters as transporter}
<Select.Item value={String(transporter.transporter_key)}>
{transporter.transporter_key}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="col-span-2 space-y-1.5">
@@ -523,15 +558,113 @@
formData.transport_type = v ?? '';
}}
>
<Select.Trigger id="transport_type" class="h-7 text-xs">
<Select.Trigger id="transport_type" class="h-7 text-xs min-w-[120px] max-w-[250px]">
<span class="truncate">
{formData.transport_type || '...'}
{#if formData.transport_type}
{vehicles.find(v => v.vehicle_key === formData.transport_type)?.vehicle_key || formData.transport_type}
{:else if vehicles.length > 0}
Selecciona vehículo...
{:else}
Sin datos
{/if}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transportTypes as transportType}
<Select.Item value={transportType.transport_code}>
{transportType.transport_code}
{#each vehicles as vehicle}
<Select.Item value={vehicle.vehicle_key}>
{vehicle.vehicle_key} {vehicle.plate_number ? `- ${vehicle.plate_number}` : ''}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
</div>
<div class="space-y-1.5">
<Label for="driver_name" class="text-xs">Conductor:</Label>
<Select.Root
type="single"
value={formData.driver_name || ''}
onValueChange={(v) => {
formData.driver_name = v ?? '';
}}
>
<Select.Trigger id="driver_name" class="h-7 text-xs w-full">
<span class="truncate">
{#if formData.driver_name}
{formData.driver_name}
{:else if drivers.length > 0}
Selecciona conductor...
{:else}
Sin datos
{/if}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each drivers as driver}
<Select.Item value={driver.driver_name}>
{driver.driver_name}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="grid grid-cols-4 gap-2">
<div class="space-y-1.5">
<Label for="transport_type" class="text-xs">Tipo Transporte:</Label>
<Select.Root
type="single"
value={formData.transport_id || 'Ninguno'}
onValueChange={(v) => {
formData.transport_id = v ?? 'Ninguno';
}}
>
<Select.Trigger id="transport_id" class="h-7 text-xs min-w-[120px] max-w-[250px]">
<span class="truncate">
{formData.transport_id || 'Ninguno'}
</span>
</Select.Trigger>
<Select.Content>
<Select.Item value="Ninguno">Ninguno</Select.Item>
<Select.Item value="Transporte">Transporte</Select.Item>
<Select.Item value="Caja">Caja</Select.Item>
<Select.Item value="Placas">Placas</Select.Item>
<Select.Item value="Camión">Camión</Select.Item>
<Select.Item value="Buque">Buque</Select.Item>
<Select.Item value="Ferrobarcaza">Ferrobarcaza</Select.Item>
<Select.Item value="Contenedor">Contenedor</Select.Item>
<Select.Item value="Avion">Avion</Select.Item>
<Select.Item value="Gondola">Gondola</Select.Item>
<Select.Item value="Plataforma">Plataforma</Select.Item>
</Select.Content>
</Select.Root>
</div>
<div class="space-y-1.5 col-span-3">
<Label for="transport_num" class="text-xs">Placas:</Label>
<Select.Root
type="single"
value={formData.transport_num || ''}
onValueChange={(v) => {
formData.transport_num = v ?? '';
}}
>
<Select.Trigger id="transport_num" class="h-7 text-xs w-full">
<span class="truncate">
{#if formData.transport_num}
{trailers.find(t => t.trailer_number === formData.transport_num)?.plate_number || formData.transport_num}
{:else if trailers.length > 0}
Selecciona remolque...
{:else}
Sin datos
{/if}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each trailers as trailer}
<Select.Item value={trailer.trailer_number}>
{trailer.plate_number || trailer.trailer_number}
</Select.Item>
{/each}
</Select.Content>
@@ -539,31 +672,66 @@
</div>
</div>
<div class="space-y-1.5">
<Label for="driver_name" class="text-xs">Conductor:</Label>
<Input id="driver_name" bind:value={formData.driver_name} class="h-7 text-xs" />
</div>
<div class="grid grid-cols-2 gap-2">
<div class="space-y-1.5">
<Label for="transport_type" class="text-xs">Tipo Transporte:</Label>
<Input id="transport_id" bind:value={formData.transport_id} class="h-7 text-xs" />
</div>
<div class="space-y-1.5">
<Label for="transport_num" class="text-xs">Placas:</Label>
<Input id="transport_num" bind:value={formData.transport_num} class="h-7 text-xs" />
</div>
</div>
<div class="space-y-1.5">
<Label for="aduana" class="text-xs">Aduana y Sección de Despacho:</Label>
<Input id="aduana" bind:value={formData.aduana} class="h-7 text-xs" />
<Select.Root
type="single"
value={formData.aduana || ''}
onValueChange={(v) => {
formData.aduana = v ?? '';
}}
>
<Select.Trigger id="aduana" class="h-7 text-xs w-full">
<span class="truncate">
{#if formData.aduana}
{customsSections.find(cs => cs.customs_code === formData.aduana)?.section_name || formData.aduana}
{:else if customsSections.length > 0}
Selecciona aduana...
{:else}
Sin datos
{/if}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each customsSections as section}
<Select.Item value={section.customs_code}>
{section.customs_code} - {section.section_name}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<div class="space-y-1.5">
<Label for="clave_regimen_aduanero" class="text-xs">Clave de Régimen Aduanero:</Label>
<Input id="clave_regimen_aduanero" bind:value={formData.clave_regimen_aduanero} class="h-7 text-xs" />
<Select.Root
type="single"
value={formData.clave_regimen_aduanero || ''}
onValueChange={(v) => {
formData.clave_regimen_aduanero = v ?? '';
}}
>
<Select.Trigger id="clave_regimen_aduanero" class="h-7 text-xs w-full">
<span class="truncate">
{#if formData.clave_regimen_aduanero}
{formData.clave_regimen_aduanero}
{:else if filteredRegimens.length > 0}
Selecciona régimen...
{:else if formData.operation_type}
Sin regímenes para tipo {formData.operation_type}
{:else}
Selecciona tipo de operación primero
{/if}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each filteredRegimens as regimen}
<Select.Item value={regimen.regimen_code}>
{regimen.regimen_code}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
</div>
</div>

View File

@@ -30,6 +30,12 @@ export const GET: RequestHandler = async ({ params, cookies, fetch }) => {
providersResponse,
currencyTypesResponse,
transportTypesResponse,
transportersResponse,
vehiclesResponse,
driversResponse,
trailersResponse,
customsSectionsResponse,
codePedimentoRegimensResponse,
sealsResponse,
incotermsResponse,
pedimentosResponse
@@ -41,6 +47,12 @@ export const GET: RequestHandler = async ({ params, cookies, fetch }) => {
authenticatedFetch(`v1/a76/clients-providers/?company_id=${companyId}&type=provider&page=1&page_size=1000`, {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/currency-types/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/transport-types/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/transporters/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/vehicles/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/drivers/?company_id=${companyId}`, {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/trailers/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/customs-sections/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/code-pedimento-regimens/?page=1&page_size=1000', {}, cookies, fetch),
authenticatedFetch(`v1/a76/seals/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/incoterms/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch(`v1/a76/pedimentos/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch)
@@ -57,6 +69,12 @@ export const GET: RequestHandler = async ({ params, cookies, fetch }) => {
const providers = providersResponse.ok ? await providersResponse.json() : { items: [] };
const currencyTypes = currencyTypesResponse.ok ? await currencyTypesResponse.json() : { items: [] };
const transportTypes = transportTypesResponse.ok ? await transportTypesResponse.json() : { items: [] };
const transporters = transportersResponse.ok ? await transportersResponse.json() : { items: [] };
const vehicles = vehiclesResponse.ok ? await vehiclesResponse.json() : { items: [] };
const drivers = driversResponse.ok ? await driversResponse.json() : { items: [] };
const trailers = trailersResponse.ok ? await trailersResponse.json() : { items: [] };
const customsSections = customsSectionsResponse.ok ? await customsSectionsResponse.json() : { items: [] };
const codePedimentoRegimens = codePedimentoRegimensResponse.ok ? await codePedimentoRegimensResponse.json() : { items: [] };
const seals = sealsResponse.ok ? await sealsResponse.json() : { items: [] };
const incoterms = incotermsResponse.ok ? await incotermsResponse.json() : { items: [] };
const pedimentos = pedimentosResponse.ok ? await pedimentosResponse.json() : { items: [] };
@@ -69,6 +87,12 @@ export const GET: RequestHandler = async ({ params, cookies, fetch }) => {
providers: providers.items || [],
currencyTypes: currencyTypes.items || [],
transportTypes: transportTypes.items || [],
transporters: transporters.items || [],
vehicles: vehicles.items || [],
drivers: drivers.items || [],
trailers: trailers.items || [],
customsSections: customsSections.items || [],
codePedimentoRegimens: codePedimentoRegimens.items || [],
seals: seals.items || [],
incoterms: incoterms.items || [],
pedimentos: pedimentos.items || []

View File

@@ -23,8 +23,12 @@ export const GET: RequestHandler = async ({ cookies, fetch }) => {
clientsResponse,
providersResponse,
currencyTypesResponse,
transportTypesResponse,
sealsResponse,
transportTypesResponse, transportersResponse,
vehiclesResponse,
driversResponse,
trailersResponse,
customsSectionsResponse,
codePedimentoRegimensResponse, sealsResponse,
incotermsResponse,
pedimentosResponse
] = await Promise.all([
@@ -34,6 +38,12 @@ export const GET: RequestHandler = async ({ cookies, fetch }) => {
authenticatedFetch(`v1/a76/clients-providers/?company_id=${companyId}&type=provider&page=1&page_size=1000`, {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/currency-types/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/transport-types/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/transporters/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/vehicles/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/drivers/?company_id=${companyId}`, {}, cookies, fetch),
authenticatedFetch(`v1/a76/transportation/trailers/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/customs-sections/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/code-pedimento-regimens/?page=1&page_size=1000', {}, cookies, fetch),
authenticatedFetch(`v1/a76/seals/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch),
authenticatedFetch('v1/public/refrence_data/incoterms/?page=1&page_size=100', {}, cookies, fetch),
authenticatedFetch(`v1/a76/pedimentos/?company_id=${companyId}&page=1&page_size=100`, {}, cookies, fetch)
@@ -45,6 +55,12 @@ export const GET: RequestHandler = async ({ cookies, fetch }) => {
const providers = providersResponse.ok ? await providersResponse.json() : { items: [] };
const currencyTypes = currencyTypesResponse.ok ? await currencyTypesResponse.json() : { items: [] };
const transportTypes = transportTypesResponse.ok ? await transportTypesResponse.json() : { items: [] };
const transporters = transportersResponse.ok ? await transportersResponse.json() : { items: [] };
const vehicles = vehiclesResponse.ok ? await vehiclesResponse.json() : { items: [] };
const drivers = driversResponse.ok ? await driversResponse.json() : { items: [] };
const trailers = trailersResponse.ok ? await trailersResponse.json() : { items: [] };
const customsSections = customsSectionsResponse.ok ? await customsSectionsResponse.json() : { items: [] };
const codePedimentoRegimens = codePedimentoRegimensResponse.ok ? await codePedimentoRegimensResponse.json() : { items: [] };
const seals = sealsResponse.ok ? await sealsResponse.json() : { items: [] };
const incoterms = incotermsResponse.ok ? await incotermsResponse.json() : { items: [] };
const pedimentos = pedimentosResponse.ok ? await pedimentosResponse.json() : { items: [] };
@@ -56,6 +72,12 @@ export const GET: RequestHandler = async ({ cookies, fetch }) => {
providers: providers.items || [],
currencyTypes: currencyTypes.items || [],
transportTypes: transportTypes.items || [],
transporters: transporters.items || [],
vehicles: vehicles.items || [],
drivers: drivers.items || [],
trailers: trailers.items || [],
customsSections: customsSections.items || [],
codePedimentoRegimens: codePedimentoRegimens.items || [],
seals: seals.items || [],
incoterms: incoterms.items || [],
pedimentos: pedimentos.items || []

View File

@@ -74,6 +74,48 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
fetch
);
const transportersPromise = authenticatedFetch(
`v1/a76/transportation/transporters/?company_id=${companyId}&page=1&page_size=100`,
{},
cookies,
fetch
);
const vehiclesPromise = authenticatedFetch(
`v1/a76/transportation/vehicles/?company_id=${companyId}&page=1&page_size=100`,
{},
cookies,
fetch
);
const driversPromise = authenticatedFetch(
`v1/a76/transportation/drivers/?company_id=${companyId}`,
{},
cookies,
fetch
);
const trailersPromise = authenticatedFetch(
`v1/a76/transportation/trailers/?company_id=${companyId}&page=1&page_size=100`,
{},
cookies,
fetch
);
const customsSectionsPromise = authenticatedFetch(
'v1/public/refrence_data/customs-sections/?page=1&page_size=100',
{},
cookies,
fetch
);
const codePedimentoRegimensPromise = authenticatedFetch(
'v1/public/refrence_data/code-pedimento-regimens/?page=1&page_size=1000',
{},
cookies,
fetch
);
const sealsPromise = authenticatedFetch(
`v1/a76/seals/?company_id=${companyId}&page=1&page_size=100`,
{},
@@ -105,6 +147,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
providersResponse,
currencyTypesResponse,
transportTypesResponse,
transportersResponse,
vehiclesResponse,
driversResponse,
trailersResponse,
customsSectionsResponse,
codePedimentoRegimensResponse,
sealsResponse,
incotermsResponse,
pedimentosResponse
@@ -115,6 +163,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
providersPromise,
currencyTypesPromise,
transportTypesPromise,
transportersPromise,
vehiclesPromise,
driversPromise,
trailersPromise,
customsSectionsPromise,
codePedimentoRegimensPromise,
sealsPromise,
incotermsPromise,
pedimentosPromise
@@ -126,6 +180,22 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
const providers = providersResponse.ok ? await providersResponse.json() : { items: [] };
const currencyTypes = currencyTypesResponse.ok ? await currencyTypesResponse.json() : { items: [] };
const transportTypes = transportTypesResponse.ok ? await transportTypesResponse.json() : { items: [] };
const transporters = transportersResponse.ok ? await transportersResponse.json() : { items: [] };
const vehicles = vehiclesResponse.ok ? await vehiclesResponse.json() : { items: [] };
const drivers = driversResponse.ok ? await driversResponse.json() : { items: [] };
const trailers = trailersResponse.ok ? await trailersResponse.json() : { items: [] };
const customsSections = customsSectionsResponse.ok ? await customsSectionsResponse.json() : { items: [] };
const codePedimentoRegimens = codePedimentoRegimensResponse.ok ? await codePedimentoRegimensResponse.json() : { items: [] };
// Debug: log transportation data
console.log('Transportation data loaded:', {
transporters: transporters.items?.length || 0,
vehicles: vehicles.items?.length || 0,
drivers: drivers.items?.length || 0,
trailers: trailers.items?.length || 0,
customsSections: customsSections.items?.length || 0,
codePedimentoRegimens: codePedimentoRegimens.items?.length || 0
});
const seals = sealsResponse.ok ? await sealsResponse.json() : { items: [] };
const incoterms = incotermsResponse.ok ? await incotermsResponse.json() : { items: [] };
const pedimentos = pedimentosResponse.ok ? await pedimentosResponse.json() : { items: [] };
@@ -140,6 +210,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
providers: providers.items || [],
currencyTypes: currencyTypes.items || [],
transportTypes: transportTypes.items || [],
transporters: transporters.items || [],
vehicles: vehicles.items || [],
drivers: drivers.items || [],
trailers: trailers.items || [],
customsSections: customsSections.items || [],
codePedimentoRegimens: codePedimentoRegimens.items || [],
seals: seals.items || [],
incoterms: incoterms.items || [],
pedimentos: pedimentos.items || [],
@@ -162,6 +238,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
providers: [],
currencyTypes: [],
transportTypes: [],
transporters: [],
vehicles: [],
drivers: [],
trailers: [],
customsSections: [],
codePedimentoRegimens: [],
seals: [],
incoterms: [],
pedimentos: [],
@@ -201,6 +283,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
providersResponse,
currencyTypesResponse,
transportTypesResponse,
transportersResponse,
vehiclesResponse,
driversResponse,
trailersResponse,
customsSectionsResponse,
codePedimentoRegimensResponse,
sealsResponse,
incotermsResponse,
pedimentosResponse
@@ -211,6 +299,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
providersPromise,
currencyTypesPromise,
transportTypesPromise,
transportersPromise,
vehiclesPromise,
driversPromise,
trailersPromise,
customsSectionsPromise,
codePedimentoRegimensPromise,
sealsPromise,
incotermsPromise,
pedimentosPromise
@@ -222,6 +316,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
const providers = providersResponse.ok ? await providersResponse.json() : { items: [] };
const currencyTypes = currencyTypesResponse.ok ? await currencyTypesResponse.json() : { items: [] };
const transportTypes = transportTypesResponse.ok ? await transportTypesResponse.json() : { items: [] };
const transporters = transportersResponse.ok ? await transportersResponse.json() : { items: [] };
const vehicles = vehiclesResponse.ok ? await vehiclesResponse.json() : { items: [] };
const drivers = driversResponse.ok ? await driversResponse.json() : { items: [] };
const trailers = trailersResponse.ok ? await trailersResponse.json() : { items: [] };
const customsSections = customsSectionsResponse.ok ? await customsSectionsResponse.json() : { items: [] };
const codePedimentoRegimens = codePedimentoRegimensResponse.ok ? await codePedimentoRegimensResponse.json() : { items: [] };
const seals = sealsResponse.ok ? await sealsResponse.json() : { items: [] };
const incoterms = incotermsResponse.ok ? await incotermsResponse.json() : { items: [] };
const pedimentos = pedimentosResponse.ok ? await pedimentosResponse.json() : { items: [] };
@@ -236,6 +336,12 @@ export const load: PageServerLoad = async ({ params, cookies, fetch, url }) => {
providers: providers.items || [],
currencyTypes: currencyTypes.items || [],
transportTypes: transportTypes.items || [],
transporters: transporters.items || [],
vehicles: vehicles.items || [],
drivers: drivers.items || [],
trailers: trailers.items || [],
customsSections: customsSections.items || [],
codePedimentoRegimens: codePedimentoRegimens.items || [],
seals: seals.items || [],
incoterms: incoterms.items || [],
pedimentos: pedimentos.items || [],

View File

@@ -62,6 +62,12 @@
enclosure?: any[];
currencyTypes?: any[];
transportTypes?: any[];
transporters?: any[];
vehicles?: any[];
drivers?: any[];
trailers?: any[];
customsSections?: any[];
codePedimentoRegimens?: any[];
user?: any;
companies?: any[];
authenticated?: boolean;
@@ -225,6 +231,12 @@
providers={data.providers || []}
currencyTypes={data.currencyTypes || []}
transportTypes={data.transportTypes || []}
transporters={data.transporters || []}
vehicles={data.vehicles || []}
drivers={data.drivers || []}
trailers={data.trailers || []}
customsSections={data.customsSections || []}
codePedimentoRegimens={data.codePedimentoRegimens || []}
defaultOperationType={data.filters?.operation_type ?? undefined}
defaultInvoiceType={data.filters?.invoice_type ?? undefined}
/>

View File

@@ -60,6 +60,12 @@ export const load: PageLoad = async ({ params, url, parent }) => {
providers: data.providers || [],
currencyTypes: data.currencyTypes || [],
transportTypes: data.transportTypes || [],
transporters: data.transporters || [],
vehicles: data.vehicles || [],
drivers: data.drivers || [],
trailers: data.trailers || [],
customsSections: data.customsSections || [],
codePedimentoRegimens: data.codePedimentoRegimens || [],
seals: data.seals || [],
incoterms: data.incoterms || [],
pedimentos: data.pedimentos || [],
@@ -80,6 +86,12 @@ export const load: PageLoad = async ({ params, url, parent }) => {
providers: [],
currencyTypes: [],
transportTypes: [],
transporters: [],
vehicles: [],
drivers: [],
trailers: [],
customsSections: [],
codePedimentoRegimens: [],
seals: [],
incoterms: [],
pedimentos: [],
@@ -116,6 +128,12 @@ export const load: PageLoad = async ({ params, url, parent }) => {
providers: data.providers || [],
currencyTypes: data.currencyTypes || [],
transportTypes: data.transportTypes || [],
transporters: data.transporters || [],
vehicles: data.vehicles || [],
drivers: data.drivers || [],
trailers: data.trailers || [],
customsSections: data.customsSections || [],
codePedimentoRegimens: data.codePedimentoRegimens || [],
seals: data.seals || [],
incoterms: data.incoterms || [],
pedimentos: data.pedimentos || [],