feat: update pedimento dates model, add PATCH method to API, and enhance edit forms
This commit is contained in:
@@ -31,7 +31,7 @@ class PedimentoDatesCreate(BaseModel):
|
||||
eucan_date: Optional[datetime] = Field(None, description="EUCAN date")
|
||||
original_date: Optional[datetime] = Field(None, description="Original date")
|
||||
start_date: Optional[datetime] = Field(None, description="Start date")
|
||||
end_date: Optional[datetime] = Field(None, description="End date")
|
||||
end_date: Optional[datetime] = Field(None, description="End date")
|
||||
|
||||
|
||||
class PedimentoDatesUpdate(BaseModel):
|
||||
|
||||
@@ -49,7 +49,7 @@ class PedimentoDates(Base, TenantScopedMixin, TimestampMixin):
|
||||
pedimento_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
|
||||
entry_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
pedimento_date: Mapped[datetime] = mapped_column(DateTime)
|
||||
pedimento_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
payment_date: Mapped[datetime] = mapped_column(DateTime)
|
||||
rectification_payment_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
extraction_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
@@ -58,7 +58,7 @@ class PedimentoDates(Base, TenantScopedMixin, TimestampMixin):
|
||||
original_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
start_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
end_date: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
capture_date: Mapped[datetime] = mapped_column(DateTime)
|
||||
|
||||
capture_time: Mapped[datetime_time] = mapped_column(Time)
|
||||
|
||||
pedimento: Mapped["Pedimentos"] = relationship(
|
||||
|
||||
@@ -106,7 +106,7 @@ class Pedimentos(Base, TenantScopedMixin, TimestampMixin):
|
||||
client_id: Mapped[int] = mapped_column(Integer)
|
||||
operation_type: Mapped[int] = mapped_column(Integer)
|
||||
pedimento_type: Mapped[int] = mapped_column(Integer)
|
||||
pedimento_code = mapped_column(String(2))
|
||||
pedimento_code: Mapped[str] = mapped_column(String(2))
|
||||
regime: Mapped[str] = mapped_column(String(3))
|
||||
status: Mapped[str] = mapped_column(String(30))
|
||||
usd_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(17, 6))
|
||||
|
||||
@@ -8,6 +8,7 @@ from typing import Any, Dict, List, Optional
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from sqlalchemy.orm import selectinload
|
||||
from datetime import datetime
|
||||
|
||||
from ..dtos.pedimentos import PedimentosCreate, PedimentosUpdate
|
||||
|
||||
@@ -75,18 +76,20 @@ class PedimentosService:
|
||||
Returns:
|
||||
Tuple of (list of pedimentos, total count)
|
||||
"""
|
||||
query = db.query(Pedimentos).filter(Pedimentos.tenant_id == tenant_id, Pedimentos.company_id == company_id)
|
||||
query = db.query(Pedimentos).filter(
|
||||
Pedimentos.tenant_id == tenant_id, Pedimentos.company_id == company_id)
|
||||
|
||||
if filters:
|
||||
if filters.get("status"):
|
||||
query = query.filter(Pedimentos.status == filters["status"])
|
||||
if filters.get("client_id"):
|
||||
query = query.filter(Pedimentos.client_id == filters["client_id"])
|
||||
query = query.filter(
|
||||
Pedimentos.client_id == filters["client_id"])
|
||||
if filters.get("year"):
|
||||
query = query.filter(Pedimentos.year == filters["year"])
|
||||
|
||||
total = query.count()
|
||||
|
||||
|
||||
# Eager load all relationships for the response schema
|
||||
items = (
|
||||
query.options(
|
||||
@@ -134,10 +137,10 @@ class PedimentosService:
|
||||
query = db.query(Pedimentos).filter(
|
||||
Pedimentos.id == pedimento_id, Pedimentos.tenant_id == tenant_id, Pedimentos.company_id == company_id
|
||||
)
|
||||
|
||||
|
||||
if company_id is not None:
|
||||
query = query.filter(Pedimentos.company_id == company_id)
|
||||
|
||||
|
||||
# Eager load all relationships for the response schema
|
||||
query = query.options(
|
||||
selectinload(Pedimentos.pedimento_dates),
|
||||
@@ -157,7 +160,7 @@ class PedimentosService:
|
||||
selectinload(Pedimentos.pedimento_config_update_rectification),
|
||||
selectinload(Pedimentos.pedimento_config_updates),
|
||||
)
|
||||
|
||||
|
||||
return query.first()
|
||||
|
||||
@staticmethod
|
||||
@@ -196,7 +199,7 @@ class PedimentosService:
|
||||
'pedimento_config_update_rectification': pedimento_data.pedimento_config_update_rectification,
|
||||
'pedimento_config_updates': pedimento_data.pedimento_config_updates,
|
||||
}
|
||||
|
||||
|
||||
# Crear pedimento principal (excluyendo relaciones)
|
||||
pedimento_dict = pedimento_data.model_dump(exclude={
|
||||
'pedimento_dates', 'pedimento_decrementables', 'pedimento_incrementables',
|
||||
@@ -207,7 +210,7 @@ class PedimentosService:
|
||||
'pedimento_config_parameters', 'pedimento_config_surcharges',
|
||||
'pedimento_config_update_rectification', 'pedimento_config_updates'
|
||||
})
|
||||
|
||||
|
||||
pedimento = Pedimentos(**pedimento_dict)
|
||||
pedimento.tenant_id = tenant_id
|
||||
pedimento.company_id = company_id
|
||||
@@ -216,36 +219,59 @@ class PedimentosService:
|
||||
db.flush() # Flush para obtener el ID sin commit
|
||||
|
||||
# Helper function para crear objetos relacionados
|
||||
def create_related(model_class, data):
|
||||
if data:
|
||||
obj_dict = data.model_dump()
|
||||
def create_related(model_class, data, extra_fields=None):
|
||||
if data or extra_fields:
|
||||
# Inicializar obj_dict desde data si existe, sino como dict vacío
|
||||
obj_dict = data.model_dump() if data else {}
|
||||
# Agregar campos extra si se proporcionan
|
||||
if extra_fields:
|
||||
obj_dict.update(extra_fields)
|
||||
obj = model_class(**obj_dict)
|
||||
obj.pedimento_id = pedimento.id
|
||||
obj.tenant_id = tenant_id
|
||||
obj.company_id = company_id
|
||||
db.add(obj)
|
||||
db.add(obj)
|
||||
|
||||
create_related(PedimentoDates, related_data['pedimento_dates'])
|
||||
create_related(PedimentoDecrementables, related_data['pedimento_decrementables'])
|
||||
create_related(PedimentoIncrementables, related_data['pedimento_incrementables'])
|
||||
# Crear PedimentoDates con capture_time automático
|
||||
create_related(
|
||||
PedimentoDates,
|
||||
related_data['pedimento_dates'],
|
||||
extra_fields={'capture_time': datetime.now().time()}
|
||||
)
|
||||
create_related(PedimentoDecrementables,
|
||||
related_data['pedimento_decrementables'])
|
||||
create_related(PedimentoIncrementables,
|
||||
related_data['pedimento_incrementables'])
|
||||
create_related(PedimentoIndexes, related_data['pedimento_indexes'])
|
||||
create_related(PedimentoValidation, related_data['pedimento_validation'])
|
||||
create_related(PedimentoCustomsOffices, related_data['pedimento_customs_offices'])
|
||||
create_related(PedimentoPayments, related_data['pedimento_payments'])
|
||||
create_related(PedimentoRectificationDestination, related_data['pedimento_rectification_destination'])
|
||||
create_related(PedimentoRectificationOrigin, related_data['pedimento_rectification_origin'])
|
||||
create_related(PedimentoTransportMeans, related_data['pedimento_transport_means'])
|
||||
create_related(PedimentoConfigAdditional, related_data['pedimento_config_additional'])
|
||||
create_related(PedimentoConfigCalculations, related_data['pedimento_config_calculations'])
|
||||
create_related(PedimentoConfigParameters, related_data['pedimento_config_parameters'])
|
||||
create_related(PedimentoConfigSurcharges, related_data['pedimento_config_surcharges'])
|
||||
create_related(PedimentoConfigUpdateRectification, related_data['pedimento_config_update_rectification'])
|
||||
create_related(PedimentoConfigUpdates, related_data['pedimento_config_updates'])
|
||||
create_related(PedimentoValidation,
|
||||
related_data['pedimento_validation'])
|
||||
create_related(PedimentoCustomsOffices,
|
||||
related_data['pedimento_customs_offices'])
|
||||
create_related(PedimentoPayments,
|
||||
related_data['pedimento_payments'])
|
||||
create_related(PedimentoRectificationDestination,
|
||||
related_data['pedimento_rectification_destination'])
|
||||
create_related(PedimentoRectificationOrigin,
|
||||
related_data['pedimento_rectification_origin'])
|
||||
create_related(PedimentoTransportMeans,
|
||||
related_data['pedimento_transport_means'])
|
||||
create_related(PedimentoConfigAdditional,
|
||||
related_data['pedimento_config_additional'])
|
||||
create_related(PedimentoConfigCalculations,
|
||||
related_data['pedimento_config_calculations'])
|
||||
create_related(PedimentoConfigParameters,
|
||||
related_data['pedimento_config_parameters'])
|
||||
create_related(PedimentoConfigSurcharges,
|
||||
related_data['pedimento_config_surcharges'])
|
||||
create_related(PedimentoConfigUpdateRectification,
|
||||
related_data['pedimento_config_update_rectification'])
|
||||
create_related(PedimentoConfigUpdates,
|
||||
related_data['pedimento_config_updates'])
|
||||
|
||||
db.commit()
|
||||
db.refresh(pedimento)
|
||||
return pedimento
|
||||
|
||||
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Error creating pedimento with related data: {e}")
|
||||
@@ -268,7 +294,8 @@ class PedimentosService:
|
||||
Returns:
|
||||
Updated pedimento or None if not found
|
||||
"""
|
||||
pedimento = PedimentosService.get_by_id(db, pedimento_id, tenant_id, company_id)
|
||||
pedimento = PedimentosService.get_by_id(
|
||||
db, pedimento_id, tenant_id, company_id)
|
||||
if not pedimento:
|
||||
return None
|
||||
|
||||
@@ -283,7 +310,7 @@ class PedimentosService:
|
||||
'pedimento_config_parameters', 'pedimento_config_surcharges',
|
||||
'pedimento_config_update_rectification', 'pedimento_config_updates'
|
||||
})
|
||||
|
||||
|
||||
for field, value in update_data.items():
|
||||
setattr(pedimento, field, value)
|
||||
|
||||
@@ -293,15 +320,16 @@ class PedimentosService:
|
||||
def update_or_create_related(service_class, model_class, data_attr):
|
||||
# Obtener datos del payload completo (no solo exclude_unset)
|
||||
full_data = pedimento_data.model_dump()
|
||||
|
||||
|
||||
if data_attr not in full_data:
|
||||
return
|
||||
|
||||
|
||||
data = full_data[data_attr]
|
||||
if not data:
|
||||
return
|
||||
|
||||
existing = service_class.get_by_pedimento_id(db, pedimento_id, tenant_id)
|
||||
|
||||
existing = service_class.get_by_pedimento_id(
|
||||
db, pedimento_id, tenant_id)
|
||||
if existing:
|
||||
# Actualizar existente
|
||||
for field, value in data.items():
|
||||
@@ -313,30 +341,46 @@ class PedimentosService:
|
||||
obj.pedimento_id = pedimento_id
|
||||
obj.tenant_id = tenant_id
|
||||
obj.company_id = company_id
|
||||
db.add(obj)
|
||||
db.add(obj)
|
||||
|
||||
# Actualizar o crear tablas relacionadas
|
||||
update_or_create_related(PedimentoDatesService, PedimentoDates, 'pedimento_dates')
|
||||
update_or_create_related(PedimentoDecrementablesService, PedimentoDecrementables, 'pedimento_decrementables')
|
||||
update_or_create_related(PedimentoIncrementablesService, PedimentoIncrementables, 'pedimento_incrementables')
|
||||
update_or_create_related(PedimentoIndexesService, PedimentoIndexes, 'pedimento_indexes')
|
||||
update_or_create_related(PedimentoValidationService, PedimentoValidation, 'pedimento_validation')
|
||||
update_or_create_related(PedimentoCustomsOfficesService, PedimentoCustomsOffices, 'pedimento_customs_offices')
|
||||
update_or_create_related(PedimentoPaymentsService, PedimentoPayments, 'pedimento_payments')
|
||||
update_or_create_related(PedimentoRectificationDestinationService, PedimentoRectificationDestination, 'pedimento_rectification_destination')
|
||||
update_or_create_related(PedimentoRectificationOriginService, PedimentoRectificationOrigin, 'pedimento_rectification_origin')
|
||||
update_or_create_related(PedimentoTransportMeansService, PedimentoTransportMeans, 'pedimento_transport_means')
|
||||
update_or_create_related(PedimentoConfigAdditionalService, PedimentoConfigAdditional, 'pedimento_config_additional')
|
||||
update_or_create_related(PedimentoConfigCalculationsService, PedimentoConfigCalculations, 'pedimento_config_calculations')
|
||||
update_or_create_related(PedimentoConfigParametersService, PedimentoConfigParameters, 'pedimento_config_parameters')
|
||||
update_or_create_related(PedimentoConfigSurchargesService, PedimentoConfigSurcharges, 'pedimento_config_surcharges')
|
||||
update_or_create_related(PedimentoConfigUpdateRectificationService, PedimentoConfigUpdateRectification, 'pedimento_config_update_rectification')
|
||||
update_or_create_related(PedimentoConfigUpdatesService, PedimentoConfigUpdates, 'pedimento_config_updates')
|
||||
update_or_create_related(
|
||||
PedimentoDatesService, PedimentoDates, 'pedimento_dates')
|
||||
update_or_create_related(
|
||||
PedimentoDecrementablesService, PedimentoDecrementables, 'pedimento_decrementables')
|
||||
update_or_create_related(
|
||||
PedimentoIncrementablesService, PedimentoIncrementables, 'pedimento_incrementables')
|
||||
update_or_create_related(
|
||||
PedimentoIndexesService, PedimentoIndexes, 'pedimento_indexes')
|
||||
update_or_create_related(
|
||||
PedimentoValidationService, PedimentoValidation, 'pedimento_validation')
|
||||
update_or_create_related(
|
||||
PedimentoCustomsOfficesService, PedimentoCustomsOffices, 'pedimento_customs_offices')
|
||||
update_or_create_related(
|
||||
PedimentoPaymentsService, PedimentoPayments, 'pedimento_payments')
|
||||
update_or_create_related(PedimentoRectificationDestinationService,
|
||||
PedimentoRectificationDestination, 'pedimento_rectification_destination')
|
||||
update_or_create_related(PedimentoRectificationOriginService,
|
||||
PedimentoRectificationOrigin, 'pedimento_rectification_origin')
|
||||
update_or_create_related(
|
||||
PedimentoTransportMeansService, PedimentoTransportMeans, 'pedimento_transport_means')
|
||||
update_or_create_related(PedimentoConfigAdditionalService,
|
||||
PedimentoConfigAdditional, 'pedimento_config_additional')
|
||||
update_or_create_related(PedimentoConfigCalculationsService,
|
||||
PedimentoConfigCalculations, 'pedimento_config_calculations')
|
||||
update_or_create_related(PedimentoConfigParametersService,
|
||||
PedimentoConfigParameters, 'pedimento_config_parameters')
|
||||
update_or_create_related(PedimentoConfigSurchargesService,
|
||||
PedimentoConfigSurcharges, 'pedimento_config_surcharges')
|
||||
update_or_create_related(PedimentoConfigUpdateRectificationService,
|
||||
PedimentoConfigUpdateRectification, 'pedimento_config_update_rectification')
|
||||
update_or_create_related(
|
||||
PedimentoConfigUpdatesService, PedimentoConfigUpdates, 'pedimento_config_updates')
|
||||
|
||||
db.commit()
|
||||
db.refresh(pedimento)
|
||||
return pedimento
|
||||
|
||||
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Error updating pedimento with related data: {e}")
|
||||
@@ -356,7 +400,8 @@ class PedimentosService:
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
"""
|
||||
pedimento = PedimentosService.get_by_id(db, pedimento_id, tenant_id, company_id)
|
||||
pedimento = PedimentosService.get_by_id(
|
||||
db, pedimento_id, tenant_id, company_id)
|
||||
if not pedimento:
|
||||
return False
|
||||
|
||||
|
||||
@@ -254,6 +254,12 @@ export const api = {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(body)
|
||||
}),
|
||||
|
||||
patch: <T = any>(endpoint: string, body: any) =>
|
||||
fetchApi<T>(endpoint, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(body)
|
||||
}),
|
||||
|
||||
delete: <T = any>(endpoint: string) => fetchApi<T>(endpoint, { method: 'DELETE' }),
|
||||
|
||||
|
||||
@@ -114,38 +114,6 @@ export const clientsProvidersApi = {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Lista solo clientes (client_or_provider = 'client')
|
||||
* @param companyId - ID de la compañía
|
||||
* @param skip - Número de registros a saltar
|
||||
* @param limit - Límite de registros
|
||||
*/
|
||||
listClients: (companyId: number, skip = 0, limit = 100) =>
|
||||
api.get<ClientProviderBasic[]>(
|
||||
`/v1/a76/clients-providers/clients?company_id=${companyId}&skip=${skip}&limit=${limit}`
|
||||
),
|
||||
|
||||
/**
|
||||
* Lista solo proveedores (client_or_provider = 'provider')
|
||||
* @param companyId - ID de la compañía
|
||||
* @param skip - Número de registros a saltar
|
||||
* @param limit - Límite de registros
|
||||
*/
|
||||
listProviders: (companyId: number, skip = 0, limit = 100) =>
|
||||
api.get<ClientProviderBasic[]>(
|
||||
`/v1/a76/clients-providers/providers?company_id=${companyId}&skip=${skip}&limit=${limit}`
|
||||
),
|
||||
|
||||
/**
|
||||
* Busca clientes/proveedores por RFC
|
||||
* @param companyId - ID de la compañía
|
||||
* @param rfc - RFC a buscar
|
||||
*/
|
||||
searchByRfc: (companyId: number, rfc: string) =>
|
||||
api.get<ClientProviderBasic[]>(
|
||||
`/v1/a76/clients-providers/search/rfc/${rfc}?company_id=${companyId}`
|
||||
),
|
||||
|
||||
/**
|
||||
* Obtiene un cliente/proveedor por ID
|
||||
* @param id - ID del cliente/proveedor
|
||||
@@ -179,7 +147,7 @@ export const clientsProvidersApi = {
|
||||
* @param data - Datos a actualizar
|
||||
*/
|
||||
update: (id: number, companyId: number, data: UpdateClientProviderData) =>
|
||||
api.put<ClientProvider>(`/v1/a76/clients-providers/${id}?company_id=${companyId}`, data),
|
||||
api.patch<ClientProvider>(`/v1/a76/clients-providers/${id}?company_id=${companyId}`, data),
|
||||
|
||||
/**
|
||||
* Alterna el estado activo/inactivo de un cliente/proveedor
|
||||
|
||||
@@ -62,57 +62,7 @@
|
||||
<Card.Content>
|
||||
<div class="space-y-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<!-- Fecha de Entrada -->
|
||||
<div class="space-y-2">
|
||||
<Label for="entry_date">Fecha de Entrada</Label>
|
||||
<Input
|
||||
id="entry_date"
|
||||
type="date"
|
||||
bind:value={formData.entry_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Presentación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="pedimento_date">Fecha de Presentación</Label>
|
||||
<Input
|
||||
id="pedimento_date"
|
||||
type="date"
|
||||
bind:value={formData.pedimento_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Pago -->
|
||||
<div class="space-y-2">
|
||||
<Label for="payment_date">Fecha de Pago</Label>
|
||||
<Input
|
||||
id="payment_date"
|
||||
type="date"
|
||||
bind:value={formData.payment_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Pago Rectificación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="rectification_payment_date">Fecha de Pago Rectificación</Label>
|
||||
<Input
|
||||
id="rectification_payment_date"
|
||||
type="date"
|
||||
bind:value={formData.rectification_payment_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Extracción -->
|
||||
<div class="space-y-2">
|
||||
<Label for="extraction_date">Fecha de Extracción</Label>
|
||||
<Input
|
||||
id="extraction_date"
|
||||
type="date"
|
||||
bind:value={formData.extraction_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Presentación (Submission) -->
|
||||
<!-- Fecha de Envío -->
|
||||
<div class="space-y-2">
|
||||
<Label for="submission_date">Fecha de Envío</Label>
|
||||
<Input
|
||||
@@ -132,16 +82,6 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha Original -->
|
||||
<div class="space-y-2">
|
||||
<Label for="original_date">Fecha Original</Label>
|
||||
<Input
|
||||
id="original_date"
|
||||
type="date"
|
||||
bind:value={formData.original_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Inicio -->
|
||||
<div class="space-y-2">
|
||||
<Label for="start_date">Fecha de Inicio</Label>
|
||||
|
||||
@@ -172,6 +172,7 @@
|
||||
|
||||
// Inicializar formData con los valores del pedimento (o vacío si es null)
|
||||
if (!formData) {
|
||||
const datesData = pedimento?.pedimento_dates;
|
||||
formData = {
|
||||
year: pedimento?.year || currentYear,
|
||||
customs_office: pedimento?.customs_office || '',
|
||||
@@ -186,7 +187,14 @@
|
||||
usd_value: pedimento?.usd_value ?? null,
|
||||
paid_price: pedimento?.paid_price ?? null,
|
||||
gross_weight: pedimento?.gross_weight ?? null,
|
||||
exchange_rate: pedimento?.exchange_rate ?? null
|
||||
exchange_rate: pedimento?.exchange_rate ?? null,
|
||||
// Date fields
|
||||
entry_date: datesData?.entry_date ? datesData.entry_date.substring(0, 10) : '',
|
||||
pedimento_date: datesData?.pedimento_date ? datesData.pedimento_date.substring(0, 10) : '',
|
||||
extraction_date: datesData?.extraction_date ? datesData.extraction_date.substring(0, 10) : '',
|
||||
rectification_payment_date: datesData?.rectification_payment_date ? datesData.rectification_payment_date.substring(0, 10) : '',
|
||||
original_date: datesData?.original_date ? datesData.original_date.substring(0, 10) : '',
|
||||
payment_date: datesData?.payment_date ? datesData.payment_date.substring(0, 10) : ''
|
||||
};
|
||||
}
|
||||
|
||||
@@ -229,35 +237,34 @@
|
||||
</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="space-y-6">
|
||||
<!-- Fila 1: Año (2), Aduana (2), Patente (4), Número de Pedimento (7) -->
|
||||
<div class="flex items-end gap-2">
|
||||
<div class="space-y-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-[auto_auto_auto_auto_auto_auto_auto_auto_auto_1fr_auto] md:items-end gap-4 md:gap-2">
|
||||
<!-- Año -->
|
||||
<div class="space-y-2 w-16">
|
||||
<div class="space-y-2">
|
||||
<Label for="year">Año</Label>
|
||||
<Input
|
||||
id="year"
|
||||
bind:value={formData.year}
|
||||
placeholder="23"
|
||||
maxlength={2}
|
||||
class="text-center"
|
||||
class="text-center md:w-16"
|
||||
disabled
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Separador -->
|
||||
<div class="pb-2 text-2xl font-semibold text-muted-foreground">-</div>
|
||||
<div class="hidden md:block pb-2 text-2xl font-semibold text-muted-foreground">-</div>
|
||||
|
||||
<!-- Aduana -->
|
||||
<div class="space-y-2 w-20">
|
||||
<div class="space-y-2">
|
||||
<Label for="customs_office">Aduana</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.customs_office || ''}
|
||||
onValueChange={(v: string) => formData.customs_office = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<Select.Trigger class="w-full md:w-20">
|
||||
<span class="truncate">
|
||||
{formData.customs_office || 'Sel...'}
|
||||
</span>
|
||||
@@ -275,17 +282,17 @@
|
||||
</div>
|
||||
|
||||
<!-- Separador -->
|
||||
<div class="pb-2 text-2xl font-semibold text-muted-foreground">-</div>
|
||||
<div class="hidden md:block pb-2 text-2xl font-semibold text-muted-foreground">-</div>
|
||||
|
||||
<!-- Patente -->
|
||||
<div class="space-y-2 w-24">
|
||||
<div class="space-y-2">
|
||||
<Label for="license">Patente</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.license || ''}
|
||||
onValueChange={(v: string) => formData.license = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<Select.Trigger class="w-full md:w-24">
|
||||
<span class="truncate">
|
||||
{formData.license || 'Sel...'}
|
||||
</span>
|
||||
@@ -303,10 +310,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Separador -->
|
||||
<div class="pb-2 text-2xl font-semibold text-muted-foreground">-</div>
|
||||
<div class="hidden md:block pb-2 text-2xl font-semibold text-muted-foreground">-</div>
|
||||
|
||||
<!-- Número de Pedimento -->
|
||||
<div class="space-y-2 flex-1">
|
||||
<div class="space-y-2">
|
||||
<Label for="pedimento_number">Número de Pedimento</Label>
|
||||
<Input
|
||||
id="pedimento_number"
|
||||
@@ -316,6 +323,89 @@
|
||||
class="text-left"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Tipo de Cambio -->
|
||||
<div class="space-y-2">
|
||||
<Label for="exchange_rate">Tipo de Cambio</Label>
|
||||
<Input
|
||||
id="exchange_rate"
|
||||
type="number"
|
||||
step="0.0001"
|
||||
bind:value={formData.exchange_rate}
|
||||
placeholder="Ej: 17.5000"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-2">
|
||||
<!-- Clave del Pedimento -->
|
||||
<div class="space-y-2">
|
||||
<Label for="pedimento_code">Clave</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.pedimento_code || ''}
|
||||
onValueChange={(v: string) => formData.pedimento_code = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{pedimentoCodes.find(o => o.code === formData.pedimento_code)?.code || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[200px]">
|
||||
{#each pedimentoCodes as code}
|
||||
<Select.Item value={code.code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={`${code.code} - ${code.description}`}>
|
||||
{code.code} - {code.description}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Régimen -->
|
||||
<div class="space-y-2">
|
||||
<Label for="regime">Régimen</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.regime || ''}
|
||||
onValueChange={(v: string) => formData.regime = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{formData.regime || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[200px]">
|
||||
{#each filteredRegimens() as regimen}
|
||||
<Select.Item value={regimen.code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={regimen.code}>
|
||||
{regimen.code}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Tipo de Operación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="operation_type">Tipo de Operación</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={String(formData.operation_type ?? '')}
|
||||
onValueChange={(v: string) => formData.operation_type = v ? Number(v) : null}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
{operationOptions.find(o => o.value === formData.operation_type)?.label || 'Seleccionar...'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each filteredOperationTypes() as option}
|
||||
<Select.Item value={String(option.value)} label={option.label} />
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
@@ -356,80 +446,8 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Fila: Clave (2), Régimen (3), Tipo de Operación (11) -->
|
||||
<div class="flex items-end gap-2">
|
||||
<!-- Clave del Pedimento -->
|
||||
<div class="space-y-2 w-20">
|
||||
<Label for="pedimento_code">Clave</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.pedimento_code || ''}
|
||||
onValueChange={(v: string) => formData.pedimento_code = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{pedimentoCodes.find(o => o.code === formData.pedimento_code)?.code || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[200px]">
|
||||
{#each pedimentoCodes as code}
|
||||
<Select.Item value={code.code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={`${code.code} - ${code.description}`}>
|
||||
{code.code} - {code.description}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Régimen -->
|
||||
<div class="space-y-2 w-24">
|
||||
<Label for="regime">Régimen</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.regime || ''}
|
||||
onValueChange={(v: string) => formData.regime = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
<span class="truncate">
|
||||
{formData.regime || 'Sel...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-w-[200px]">
|
||||
{#each filteredRegimens() as regimen}
|
||||
<Select.Item value={regimen.code}>
|
||||
<span class="truncate overflow-hidden text-ellipsis whitespace-nowrap" title={regimen.code}>
|
||||
{regimen.code}
|
||||
</span>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<!-- Tipo de Operación -->
|
||||
<div class="space-y-2 flex-1">
|
||||
<Label for="operation_type">Tipo de Operación</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={String(formData.operation_type ?? '')}
|
||||
onValueChange={(v: string) => formData.operation_type = v ? Number(v) : null}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
{operationOptions.find(o => o.value === formData.operation_type)?.label || 'Seleccionar...'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each filteredOperationTypes() as option}
|
||||
<Select.Item value={String(option.value)} label={option.label} />
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
|
||||
<!-- Estado -->
|
||||
<div class="space-y-2">
|
||||
@@ -484,17 +502,68 @@
|
||||
bind:value={formData.gross_weight}
|
||||
placeholder="Ej: 100.00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fechas -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<!-- Fecha de Entrada -->
|
||||
<div class="space-y-2">
|
||||
<Label for="entry_date">Fecha de Entrada</Label>
|
||||
<Input
|
||||
id="entry_date"
|
||||
type="date"
|
||||
bind:value={formData.entry_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Tipo de Cambio -->
|
||||
<!-- Fecha de Presentación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="exchange_rate">Tipo de Cambio</Label>
|
||||
<Label for="pedimento_date">Fecha de Presentación</Label>
|
||||
<Input
|
||||
id="exchange_rate"
|
||||
type="number"
|
||||
step="0.0001"
|
||||
bind:value={formData.exchange_rate}
|
||||
placeholder="Ej: 17.5000"
|
||||
id="pedimento_date"
|
||||
type="date"
|
||||
bind:value={formData.pedimento_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Extracción -->
|
||||
<div class="space-y-2">
|
||||
<Label for="extraction_date">Fecha de Extracción</Label>
|
||||
<Input
|
||||
id="extraction_date"
|
||||
type="date"
|
||||
bind:value={formData.extraction_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Pago Rectificación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="rectification_payment_date">Fecha de Pago R1</Label>
|
||||
<Input
|
||||
id="rectification_payment_date"
|
||||
type="date"
|
||||
bind:value={formData.rectification_payment_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha Original -->
|
||||
<div class="space-y-2">
|
||||
<Label for="original_date">Fecha de Pago Original</Label>
|
||||
<Input
|
||||
id="original_date"
|
||||
type="date"
|
||||
bind:value={formData.original_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Pago -->
|
||||
<div class="space-y-2">
|
||||
<Label for="payment_date">Fecha de Pago</Label>
|
||||
<Input
|
||||
id="payment_date"
|
||||
type="date"
|
||||
bind:value={formData.payment_date}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { goto } from '$app/navigation';
|
||||
import * as Tabs from '$lib/components/ui/tabs';
|
||||
import * as Alert from '$lib/components/ui/alert';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
@@ -18,8 +16,8 @@
|
||||
ShieldCheck,
|
||||
LoaderCircle,
|
||||
Save
|
||||
} from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
} from 'lucide-svelte';
|
||||
import { useSidebar } from '$lib/components/ui/sidebar/context.svelte';
|
||||
|
||||
// Importar los componentes de cada pestaña (ahora sin botones de guardar propios)
|
||||
import GeneralTabForm from '$lib/components/dashboard/pedimentos/edit/general-tab-form.svelte';
|
||||
@@ -35,6 +33,9 @@
|
||||
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/refrence_data/code_pedimento_regimens';
|
||||
|
||||
// Get sidebar context
|
||||
const sidebar = useSidebar();
|
||||
|
||||
interface ExtendedPageData {
|
||||
pedimentoId?: number | null;
|
||||
@@ -146,7 +147,7 @@
|
||||
|
||||
// Solo agregar sub-recursos en modo UPDATE (no en CREATE)
|
||||
// Y solo si tienen valores reales (no enviar objetos vacíos/null)
|
||||
if (!data.isCreate) {
|
||||
|
||||
// Dates - solo enviar si hay al menos un campo con valor
|
||||
if (datesFormData) {
|
||||
const hasDateValue = datesFormData.entry_date || datesFormData.pedimento_date ||
|
||||
@@ -227,8 +228,7 @@
|
||||
responsible_id: validationFormData.responsible_id || null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminar campos undefined para no enviarlos
|
||||
Object.keys(payload).forEach(key => {
|
||||
@@ -381,32 +381,37 @@
|
||||
</div>
|
||||
|
||||
<!-- Footer fijo en la parte inferior - Fuera del contenedor principal -->
|
||||
<div class="fixed bottom-0 inset-x-0 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-t shadow-lg z-50 group-has-[[data-sidebar]]/sidebar-wrapper:left-[var(--sidebar-width)]">
|
||||
<div
|
||||
class="fixed bottom-0 left-0 right-0 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-t shadow-lg z-[5] transition-[left] duration-200 ease-linear"
|
||||
style:left={sidebar.isMobile ? '0' : (sidebar.open ? 'var(--sidebar-width)' : '0')}
|
||||
>
|
||||
<div class="px-4 py-4 space-y-4 max-w-[1400px] mx-auto">
|
||||
<!-- Tabs Navigation -->
|
||||
<Tabs.Root bind:value={activeTab}>
|
||||
<Tabs.List class="grid w-full grid-cols-5">
|
||||
<Tabs.Trigger value="general" disabled={false}>
|
||||
<FileText size={16} class="mr-2" />
|
||||
General
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="dates" disabled={false}>
|
||||
<Calendar size={16} class="mr-2" />
|
||||
Fechas
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="payments" disabled={false}>
|
||||
<CreditCard size={16} class="mr-2" />
|
||||
Pagos
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="transport" disabled={false}>
|
||||
<Truck size={16} class="mr-2" />
|
||||
Transporte
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="validation" disabled={false}>
|
||||
<ShieldCheck size={16} class="mr-2" />
|
||||
Validación
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<div class="w-full overflow-x-auto pb-2">
|
||||
<Tabs.List class="inline-flex md:grid md:w-full md:grid-cols-5">
|
||||
<Tabs.Trigger value="general" disabled={false} class="whitespace-nowrap">
|
||||
<FileText size={16} class="mr-2" />
|
||||
General
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="dates" disabled={false} class="whitespace-nowrap">
|
||||
<Calendar size={16} class="mr-2" />
|
||||
Fechas
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="payments" disabled={false} class="whitespace-nowrap">
|
||||
<CreditCard size={16} class="mr-2" />
|
||||
Pagos
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="transport" disabled={false} class="whitespace-nowrap">
|
||||
<Truck size={16} class="mr-2" />
|
||||
Transporte
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="validation" disabled={false} class="whitespace-nowrap">
|
||||
<ShieldCheck size={16} class="mr-2" />
|
||||
Validación
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
</Tabs.Root>
|
||||
|
||||
<!-- Botones de acción -->
|
||||
|
||||
Reference in New Issue
Block a user