From 0cb89ceeecf2244775641f7c4ff213009fc222d6 Mon Sep 17 00:00:00 2001 From: acazares Date: Fri, 5 Dec 2025 17:27:19 -0600 Subject: [PATCH 1/9] feat: update pedimento dates model, add PATCH method to API, and enhance edit forms --- .../a76/pedmientos/dtos/pedimento_dates.py | 2 +- .../a76/pedmientos/models/pedimento_dates.py | 4 +- .../a76/pedmientos/models/pedimentos.py | 2 +- .../a76/pedmientos/services/pedimentos.py | 151 ++++++---- frontend/src/lib/api.ts | 6 + .../api/dashboard/a76/clients-providers.ts | 34 +-- .../pedimentos/edit/dates-tab-form.svelte | 62 +---- .../pedimentos/edit/general-tab-form.svelte | 259 +++++++++++------- .../pedimentos/edit/[id]/+page.svelte | 67 ++--- 9 files changed, 310 insertions(+), 277 deletions(-) diff --git a/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py b/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py index 101b58b0..524a7e9e 100644 --- a/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py +++ b/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py @@ -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): diff --git a/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py b/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py index cea9f34d..533cdc00 100644 --- a/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py +++ b/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py @@ -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( diff --git a/backend/api/v1/modules/a76/pedmientos/models/pedimentos.py b/backend/api/v1/modules/a76/pedmientos/models/pedimentos.py index 7a2b5e99..e9bf1752 100644 --- a/backend/api/v1/modules/a76/pedmientos/models/pedimentos.py +++ b/backend/api/v1/modules/a76/pedmientos/models/pedimentos.py @@ -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)) diff --git a/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py b/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py index b2ef0719..d6506226 100644 --- a/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py +++ b/backend/api/v1/modules/a76/pedmientos/services/pedimentos.py @@ -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 diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index bd2b92fd..8bc86a87 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -254,6 +254,12 @@ export const api = { method: 'PUT', body: JSON.stringify(body) }), + + patch: (endpoint: string, body: any) => + fetchApi(endpoint, { + method: 'PATCH', + body: JSON.stringify(body) + }), delete: (endpoint: string) => fetchApi(endpoint, { method: 'DELETE' }), diff --git a/frontend/src/lib/api/dashboard/a76/clients-providers.ts b/frontend/src/lib/api/dashboard/a76/clients-providers.ts index 773de3b0..26d31d69 100644 --- a/frontend/src/lib/api/dashboard/a76/clients-providers.ts +++ b/frontend/src/lib/api/dashboard/a76/clients-providers.ts @@ -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( - `/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( - `/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( - `/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(`/v1/a76/clients-providers/${id}?company_id=${companyId}`, data), + api.patch(`/v1/a76/clients-providers/${id}?company_id=${companyId}`, data), /** * Alterna el estado activo/inactivo de un cliente/proveedor diff --git a/frontend/src/lib/components/dashboard/pedimentos/edit/dates-tab-form.svelte b/frontend/src/lib/components/dashboard/pedimentos/edit/dates-tab-form.svelte index 5377d232..106ca429 100644 --- a/frontend/src/lib/components/dashboard/pedimentos/edit/dates-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/pedimentos/edit/dates-tab-form.svelte @@ -62,57 +62,7 @@
- -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - +
- -
- - -
-
diff --git a/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte b/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte index 6c7e5ffc..facb4ad0 100644 --- a/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte @@ -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 @@ -
- -
+
+
-
+
-
-
+ -
+
formData.customs_office = v ?? ''} > - + {formData.customs_office || 'Sel...'} @@ -275,17 +282,17 @@
-
-
+ -
+
formData.license = v ?? ''} > - + {formData.license || 'Sel...'} @@ -303,10 +310,10 @@
-
-
+ -
+
+ + +
+ + +
+
+ +
+ +
+ + formData.pedimento_code = v ?? ''} + > + + + {pedimentoCodes.find(o => o.code === formData.pedimento_code)?.code || 'Sel...'} + + + + {#each pedimentoCodes as code} + + + {code.code} - {code.description} + + + {/each} + + +
+ + +
+ + formData.regime = v ?? ''} + > + + + {formData.regime || 'Sel...'} + + + + {#each filteredRegimens() as regimen} + + + {regimen.code} + + + {/each} + + +
+ + +
+ + formData.operation_type = v ? Number(v) : null} + > + + {operationOptions.find(o => o.value === formData.operation_type)?.label || 'Seleccionar...'} + + + {#each filteredOperationTypes() as option} + + {/each} + + +
@@ -356,80 +446,8 @@
- - -
- -
- - formData.pedimento_code = v ?? ''} - > - - - {pedimentoCodes.find(o => o.code === formData.pedimento_code)?.code || 'Sel...'} - - - - {#each pedimentoCodes as code} - - - {code.code} - {code.description} - - - {/each} - - -
- - -
- - formData.regime = v ?? ''} - > - - - {formData.regime || 'Sel...'} - - - - {#each filteredRegimens() as regimen} - - - {regimen.code} - - - {/each} - - -
- - -
- - formData.operation_type = v ? Number(v) : null} - > - - {operationOptions.find(o => o.value === formData.operation_type)?.label || 'Seleccionar...'} - - - {#each filteredOperationTypes() as option} - - {/each} - - -
-
- -
+ +
@@ -484,17 +502,68 @@ bind:value={formData.gross_weight} placeholder="Ej: 100.00" /> +
+
+ + +
+ +
+ +
- +
- + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
diff --git a/frontend/src/routes/dashboard/pedimentos/edit/[id]/+page.svelte b/frontend/src/routes/dashboard/pedimentos/edit/[id]/+page.svelte index 27e9f9b8..36aa4ba5 100644 --- a/frontend/src/routes/dashboard/pedimentos/edit/[id]/+page.svelte +++ b/frontend/src/routes/dashboard/pedimentos/edit/[id]/+page.svelte @@ -1,7 +1,5 @@