feat: Introduce customs office and transport means fields to pedimento data models and forms.

This commit is contained in:
Galindo97
2026-02-25 11:41:35 -06:00
parent d6ab2f47d7
commit 72db67e161
6 changed files with 231 additions and 23 deletions

View File

@@ -6,6 +6,8 @@ from sqlalchemy.orm import Session
from api.v1.modules.public.reference_data.pedimento_codes.models import PedimentoCode
from api.v1.modules.public.reference_data.customs_sections.models import CustomsSection
from api.v1.modules.public.reference_data.code_pedimento_regimens.models import CodePedimentoRegimen
from api.v1.modules.public.reference_data.transport_types.models import TransportType
from api.v1.modules.public.reference_data.transport_modes.models import TransportMode
# Import A76 Services
from api.v1.modules.a76.customs_brokers.services import CustomsBrokerService
@@ -15,6 +17,8 @@ from api.v1.modules.a76.clients_and_providers.service import ClientProviderServi
from api.v1.modules.public.reference_data.pedimento_codes.dto import PedimentoCodeDTO
from api.v1.modules.public.reference_data.customs_sections.dto import CustomsSectionDTO
from api.v1.modules.public.reference_data.code_pedimento_regimens.dto import CodePedimentoRegimenDTO
from api.v1.modules.public.reference_data.transport_types.dto import TransportTypeDTO
from api.v1.modules.public.reference_data.transport_modes.dto import TransportModeDTO
from api.v1.modules.a76.customs_brokers.dto import CustomsBrokerResponseDTO
from api.v1.modules.a76.clients_and_providers.dto import ClientProviderResponseDTO
from .dtos.pedimentos import PedimentosResponse
@@ -53,6 +57,20 @@ class PedimentoCatalogService:
except Exception as e:
print(f"Error fetching code_pedimento_regimens: {e}")
try:
response.transport_types = [
TransportTypeDTO.model_validate(obj) for obj in db.query(TransportType).limit(200).all()
]
except Exception as e:
print(f"Error fetching transport_types: {e}")
try:
response.transport_modes = [
TransportModeDTO.model_validate(obj) for obj in db.query(TransportMode).limit(100).all()
]
except Exception as e:
print(f"Error fetching transport_modes: {e}")
# Helper to fetch tenant/company specific data
def fetch_tenant_data():
# Customs Brokers

View File

@@ -11,6 +11,8 @@ from api.v1.modules.public.reference_data.customs_sections.dto import CustomsSec
from api.v1.modules.public.reference_data.code_pedimento_regimens.dto import CodePedimentoRegimenDTO
from api.v1.modules.a76.customs_brokers.dto import CustomsBrokerResponseDTO
from api.v1.modules.a76.clients_and_providers.dto import ClientProviderResponseDTO
from api.v1.modules.public.reference_data.transport_types.dto import TransportTypeDTO
from api.v1.modules.public.reference_data.transport_modes.dto import TransportModeDTO
from .dtos.pedimentos import PedimentosResponse
@@ -22,6 +24,8 @@ class PedimentoCatalogsResponse(BaseModel):
code_pedimento_regimens: List[CodePedimentoRegimenDTO] = []
customs_brokers: List[CustomsBrokerResponseDTO] = []
clients: List[ClientProviderResponseDTO] = []
transport_types: List[TransportTypeDTO] = []
transport_modes: List[TransportModeDTO] = []
class PedimentoCreationResponse(PedimentoCatalogsResponse):

View File

@@ -39,6 +39,11 @@ export interface PedimentoTransportMeans {
departure?: string | null;
}
export interface PedimentoCustomsOffices {
dispatch_customs?: string | null;
entry_exit_customs?: string | null;
}
export interface PedimentoValidation {
validator?: string | null;
validation_ack?: string | null;
@@ -186,6 +191,7 @@ export interface Pedimento {
pedimento_config_parameters?: PedimentoConfigParameters | null;
pedimento_config_updates?: PedimentoConfigUpdates | null;
pedimento_config_update_rectification?: PedimentoConfigUpdateRectification | null;
pedimento_customs_offices?: PedimentoCustomsOffices | null;
identificadores?: Identificador[] | null;
}
@@ -226,6 +232,7 @@ export interface CreatePedimentoData {
pedimento_config_parameters?: PedimentoConfigParameters | null;
pedimento_config_updates?: PedimentoConfigUpdates | null;
pedimento_config_update_rectification?: PedimentoConfigUpdateRectification | null;
pedimento_customs_offices?: PedimentoCustomsOffices | null;
identificadores?: Identificador[] | null;
}
@@ -259,6 +266,7 @@ export interface UpdatePedimentoData {
pedimento_config_parameters?: PedimentoConfigParameters | null;
pedimento_config_updates?: PedimentoConfigUpdates | null;
pedimento_config_update_rectification?: PedimentoConfigUpdateRectification | null;
pedimento_customs_offices?: PedimentoCustomsOffices | null;
identificadores?: Identificador[] | null;
}

View File

@@ -12,6 +12,8 @@
import type { CustomsBroker } from '$lib/api/dashboard/a76/customs-brokers';
import type { ClientProvider } from '$lib/api/dashboard/a76/clients-providers';
import type { CodePedimentoRegimen } from '$lib/api/dashboard/reference_data/code_pedimento_regimens';
import type { TransportType } from '$lib/api/dashboard/reference_data/transport_types';
import type { TransportMode } from '$lib/api/dashboard/reference_data/transport_modes';
import IdentificadoresTabForm from './identifiers-tab-form.svelte';
import ExchangeRateDialog from '$lib/components/dashboard/exchange_rate/create-edit-dialog.svelte';
import { Calendar, Clock } from 'lucide-svelte';
@@ -36,6 +38,8 @@
customsBrokers = [],
clients = [],
codePedimentoRegimens = [],
transportTypes = [],
transportModes = [],
isActive = false
}: {
pedimento: Pedimento | null;
@@ -46,6 +50,8 @@
customsBrokers?: CustomsBroker[];
clients?: ClientProvider[];
codePedimentoRegimens?: CodePedimentoRegimen[];
transportTypes?: TransportType[];
transportModes?: TransportMode[];
isActive?: boolean;
} = $props();
@@ -312,10 +318,19 @@
entry_date: loadServerDate(datesData?.entry_date) || currentDate,
end_date: loadServerDate(datesData?.end_date) || end_date,
payment_date: loadServerDate(datesData?.payment_date) || payment_date,
pedimento_date: loadServerDate(datesData?.pedimento_date),
extraction_date: loadServerDate(datesData?.extraction_date),
rectification_payment_date: loadServerDate(datesData?.rectification_payment_date),
original_date: loadServerDate(datesData?.original_date),
extraction_date: loadServerDate(datesData?.entry_date) || null,
original_date: loadServerDate(datesData?.original_date) || null,
// Mapeos de sub-recursos
pedimento_customs_offices: {
dispatch_customs: pedimento?.pedimento_customs_offices?.dispatch_customs || '',
entry_exit_customs: pedimento?.pedimento_customs_offices?.entry_exit_customs || ''
},
pedimento_transport_means: {
destination: pedimento?.pedimento_transport_means?.destination || null,
entry_exit: pedimento?.pedimento_transport_means?.entry_exit || '',
arrival: pedimento?.pedimento_transport_means?.arrival || '',
departure: pedimento?.pedimento_transport_means?.departure || ''
},
// Campos de captura automática (Local)
fecha_captura: currentDate,
hora_captura: currentTime
@@ -370,7 +385,7 @@
{ value: 'automobile', label: 'Automóvil' },
{ value: 'complementary', label: 'Complementario' },
{ value: 'consolidated', label: 'Consolidado' },
{ value: 'normal', label: 'Normal' }
{ value: 'normal', label: 'Normal (Individual)' }
];
const tipoOperacionOptions = [
@@ -443,11 +458,9 @@
<Input
id="year"
bind:value={formData.year}
placeholder="23"
maxlength={2}
class="text-center md:w-16"
disabled
readonly
placeholder="25"
maxlength={4}
class="text-center md:w-20"
/>
</div>
@@ -747,19 +760,144 @@
<!-- Despacho -->
<div class="space-y-2">
<Label for="despacho">Despacho</Label>
<Input id="despacho" type="number" bind:value={formData.despacho} placeholder="0" />
<Select.Root
type="single"
value={formData.pedimento_customs_offices.dispatch_customs || ''}
onValueChange={(v: string) =>
(formData.pedimento_customs_offices.dispatch_customs = v || '')}
>
<Select.Trigger id="despacho" class="w-full">
{formData.pedimento_customs_offices.dispatch_customs || 'Sel...'}
</Select.Trigger>
<Select.Content>
{#each customsSections.filter((s) => !formData.customs_office || s.customs_code.startsWith(formData.customs_office.substring(0, 2))) as section}
<Select.Item value={section.customs_code}>
{section.customs_code} - {section.section_name}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<!-- Destino -->
<div class="space-y-2">
<Label for="destino">Destino <span class="text-red-500">*</span></Label>
<Select.Root
type="single"
value={formData.pedimento_transport_means.destination
? String(formData.pedimento_transport_means.destination)
: ''}
onValueChange={(v: string) =>
(formData.pedimento_transport_means.destination = v ? Number(v) : null)}
>
<Select.Trigger id="destino" class="w-full">
{formData.pedimento_transport_means.destination === 1
? '1 - REGION FRONTERIZA'
: formData.pedimento_transport_means.destination === 8
? '8 - RECTIFICACION REGION FRONTERIZA'
: formData.pedimento_transport_means.destination === 9
? '9 - INTERIOR DEL PAIS'
: 'Seleccionar...'}
</Select.Trigger>
<Select.Content>
<Select.Item value="1">1 - REGION FRONTERIZA</Select.Item>
<Select.Item value="8">8 - RECTIFICACION REGION FRONTERIZA</Select.Item>
<Select.Item value="9">9 - INTERIOR DEL PAIS</Select.Item>
</Select.Content>
</Select.Root>
</div>
<!-- Aduana E/S -->
<div class="space-y-2">
<Label for="aduana_es">Aduana E/S</Label>
<Input id="aduana_es" type="number" bind:value={formData.aduana_es} placeholder="0" />
<Label for="entry_exit_customs">Aduana E/S</Label>
<Input
id="entry_exit_customs"
type="text"
maxlength={3}
bind:value={formData.pedimento_customs_offices.entry_exit_customs}
placeholder="000"
/>
</div>
<!-- E/S -->
<!-- Método de Entrada/Salida -->
<div class="space-y-2">
<Label for="es">E/S</Label>
<Input id="es" type="number" bind:value={formData.es} placeholder="0" />
<Label for="entry_exit">Método de Entrada</Label>
<Select.Root
type="single"
value={formData.pedimento_transport_means.entry_exit || ''}
onValueChange={(v: string) => (formData.pedimento_transport_means.entry_exit = v || '')}
>
<Select.Trigger id="entry_exit" class="w-full">
<span class="truncate">
{transportModes.find((m) => m.key === formData.pedimento_transport_means.entry_exit)
?.name ||
transportTypes.find(
(t) => t.transport_code === formData.pedimento_transport_means.entry_exit
)?.description ||
formData.pedimento_transport_means.entry_exit ||
'Seleccionar...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transportModes as mode}
<Select.Item value={mode.key}>{mode.key} - {mode.name}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<!-- Arribo -->
<div class="space-y-2">
<Label for="arrival">Arribo</Label>
<Select.Root
type="single"
value={formData.pedimento_transport_means.arrival || ''}
onValueChange={(v: string) => (formData.pedimento_transport_means.arrival = v || '')}
>
<Select.Trigger id="arrival" class="w-full">
<span class="truncate">
{transportModes.find((m) => m.key === formData.pedimento_transport_means.arrival)
?.name ||
transportTypes.find(
(t) => t.transport_code === formData.pedimento_transport_means.arrival
)?.description ||
formData.pedimento_transport_means.arrival ||
'Seleccionar...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transportModes as mode}
<Select.Item value={mode.key}>{mode.key} - {mode.name}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
<!-- Salida -->
<div class="space-y-2">
<Label for="departure">Salida</Label>
<Select.Root
type="single"
value={formData.pedimento_transport_means.departure || ''}
onValueChange={(v: string) => (formData.pedimento_transport_means.departure = v || '')}
>
<Select.Trigger id="departure" class="w-full">
<span class="truncate">
{transportModes.find((m) => m.key === formData.pedimento_transport_means.departure)
?.name ||
transportTypes.find(
(t) => t.transport_code === formData.pedimento_transport_means.departure
)?.description ||
formData.pedimento_transport_means.departure ||
'Seleccionar...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transportModes as mode}
<Select.Item value={mode.key}>{mode.key} - {mode.name}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
</div>

View File

@@ -39,6 +39,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
customsBrokers: [],
clients: [],
codePedimentoRegimens: [],
transportTypes: [],
transportModes: [],
error: 'Error al cargar catálogos. Verifique la conexión con el backend.'
};
}
@@ -53,7 +55,9 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
customsSections: data.customs_sections || [],
customsBrokers: data.customs_brokers || [],
clients: data.clients || [],
codePedimentoRegimens: data.code_pedimento_regimens || []
codePedimentoRegimens: data.code_pedimento_regimens || [],
transportTypes: data.transport_types || [],
transportModes: data.transport_modes || []
};
} catch (e) {
console.error('❌ Error loading new pedimento data:', e);
@@ -67,6 +71,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
customsBrokers: [],
clients: [],
codePedimentoRegimens: [],
transportTypes: [],
transportModes: [],
error: 'Error al cargar catálogos. Verifique la conexión con el backend.'
};
}
@@ -106,7 +112,9 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
customsSections: data.customs_sections || [],
customsBrokers: data.customs_brokers || [],
clients: data.clients || [],
codePedimentoRegimens: data.code_pedimento_regimens || []
codePedimentoRegimens: data.code_pedimento_regimens || [],
transportTypes: data.transport_types || [],
transportModes: data.transport_modes || []
};
} catch (e) {
console.error('Error loading pedimento:', e);

View File

@@ -54,6 +54,8 @@
import type { CustomsBroker } from '$lib/api/dashboard/a76/customs-brokers';
import type { ClientProvider } from '$lib/api/dashboard/a76/clients-providers';
import type { CodePedimentoRegimen } from '$lib/api/dashboard/reference_data/code_pedimento_regimens';
import type { TransportType } from '$lib/api/dashboard/reference_data/transport_types';
import type { TransportMode } from '$lib/api/dashboard/reference_data/transport_modes';
// Get sidebar context
const sidebar = useSidebar();
@@ -67,6 +69,8 @@
customsBrokers?: CustomsBroker[];
clients?: ClientProvider[];
codePedimentoRegimens?: CodePedimentoRegimen[];
transportTypes?: TransportType[];
transportModes?: TransportMode[];
user?: any;
companies?: any[];
authenticated?: boolean;
@@ -463,6 +467,32 @@
end_date: generalFormData.end_date || null
};
}
// Aduanas (Despacho y Entrada/Salida)
const hasCustomsValue =
generalFormData.pedimento_customs_offices?.dispatch_customs ||
generalFormData.pedimento_customs_offices?.entry_exit_customs;
if (hasCustomsValue) {
payload.pedimento_customs_offices = {
dispatch_customs: generalFormData.pedimento_customs_offices.dispatch_customs || null,
entry_exit_customs: generalFormData.pedimento_customs_offices.entry_exit_customs || null
};
}
// Transportes y Destino
const hasTransportValue =
generalFormData.pedimento_transport_means?.destination ||
generalFormData.pedimento_transport_means?.entry_exit ||
generalFormData.pedimento_transport_means?.arrival ||
generalFormData.pedimento_transport_means?.departure;
if (hasTransportValue) {
payload.pedimento_transport_means = {
destination: generalFormData.pedimento_transport_means.destination || null,
entry_exit: generalFormData.pedimento_transport_means.entry_exit || null,
arrival: generalFormData.pedimento_transport_means.arrival || null,
departure: generalFormData.pedimento_transport_means.departure || null
};
}
}
// Solo agregar sub-recursos en modo UPDATE (no en CREATE)
@@ -1060,11 +1090,13 @@
pedimento={data.pedimento}
bind:formData={generalFormData}
bind:identificadoresFormData
pedimentoCodes={data.pedimentoCodes || []}
customsSections={data.customsSections || []}
customsBrokers={data.customsBrokers || []}
clients={data.clients || []}
codePedimentoRegimens={data.codePedimentoRegimens || []}
pedimentoCodes={data.pedimentoCodes}
customsSections={data.customsSections}
customsBrokers={data.customsBrokers}
clients={data.clients}
codePedimentoRegimens={data.codePedimentoRegimens}
transportTypes={data.transportTypes}
transportModes={data.transportModes}
isActive={activeTab === 'general'}
/>
</Tabs.Content>