diff --git a/backend/api/v1/modules/a76/pedmientos/catalog_service.py b/backend/api/v1/modules/a76/pedmientos/catalog_service.py index b78bd8b8..13b4a01e 100644 --- a/backend/api/v1/modules/a76/pedmientos/catalog_service.py +++ b/backend/api/v1/modules/a76/pedmientos/catalog_service.py @@ -17,6 +17,7 @@ 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 .dtos.pedimentos import PedimentosResponse from .schemas import PedimentoCatalogsResponse, PedimentoCreationResponse, PedimentoEditionResponse @@ -111,10 +112,13 @@ class PedimentoCatalogService: if not pedimento: return None + + # Convert SQLAlchemy object to Pydantic DTO + pedimento_dto = PedimentosResponse.model_validate(pedimento) return PedimentoEditionResponse( **catalogs.model_dump(), is_create=False, - pedimento=pedimento, + pedimento=pedimento_dto, pedimento_id=pedimento_id ) diff --git a/backend/api/v1/modules/a76/pedmientos/schemas.py b/backend/api/v1/modules/a76/pedmientos/schemas.py index fb673d64..aeec5ee3 100644 --- a/backend/api/v1/modules/a76/pedmientos/schemas.py +++ b/backend/api/v1/modules/a76/pedmientos/schemas.py @@ -2,7 +2,7 @@ Consolidated schemas for Pedimento catalog responses """ -from typing import List, Optional, Any +from typing import List, Optional from pydantic import BaseModel # Import DTOs for catalog items @@ -11,6 +11,7 @@ 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 .dtos.pedimentos import PedimentosResponse class PedimentoCatalogsResponse(BaseModel): @@ -33,5 +34,5 @@ class PedimentoEditionResponse(PedimentoCatalogsResponse): """Response for editing an existing pedimento (catalogs + pedimento data)""" is_create: bool = False - pedimento: Optional[Any] = None # Will be PedimentosResponse but avoiding circular import + pedimento: Optional[PedimentosResponse] = None pedimento_id: Optional[int] = None diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte index 5bf87a1c..ea64e1f0 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte @@ -24,6 +24,7 @@ invoice, onSave, onCancel, + isTargetingPreset = false, isSaving = false }: { open: boolean; @@ -32,6 +33,7 @@ invoice: Invoice | null; onSave: () => void; onCancel?: () => void; + isTargetingPreset?: boolean; isSaving?: boolean; } = $props(); diff --git a/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte b/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte index 1e1d88b1..c76ab8f0 100644 --- a/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte +++ b/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte @@ -222,29 +222,199 @@ return { ...skeleton, ...filtered }; } + // Función para mapear la factura existente a los formData + function mapInvoiceToTopFields(invoice: any) { + if (!invoice) return topFieldsSkeleton; + + let operationType: string | null = null; + if (invoice.operation_type) { + operationType = invoice.operation_type; + } else if (data.filters?.operation_type !== undefined) { + operationType = data.filters.operation_type ?? null; + } + + return { + is_pedimento_pending: invoice.compliance_mx?.is_pedimento_pending || false, + pedimento_id: invoice.compliance_mx?.pedimento_id || '', + remesa: invoice.compliance_mx?.remesa || '', + invoice_number: invoice.invoice_number || '', + invoice_date: invoice.invoice_date || new Date().toISOString().split('T')[0], + emission_date: invoice.emission_date || new Date().toISOString().split('T')[0], + operation_type: operationType, + invoice_type: invoice.invoice_type || (data.filters?.invoice_type ?? ''), + fecha_pedimento_del: '', + fecha_pedimento_al: '', + clave_pedimento: '', + regimen_pedimento: '' + }; + } + + function mapInvoiceToGeneral(invoice: any) { + if (!invoice) return generalSkeleton; + + return { + provider_header: invoice.compliance_mx?.provider_header || 'proveedor', + provider_id: invoice.compliance_mx?.provider_id || null, + sold_to_header: invoice.compliance_mx?.sold_to_header || 'consignado_a', + sold_to_id: invoice.compliance_mx?.sold_to_id || null, + shipped_to_header: invoice.compliance_mx?.shipped_to_header || 'enviado_a', + shipped_to_id: invoice.compliance_mx?.shipped_to_id || null, + customs_broker_id: invoice.compliance_mx?.customs_broker_id || null, + customs_broker_us_id: invoice.compliance_mx?.customs_broker_us_id || null, + currency_type: invoice.financials?.currency_type || '', + currency: invoice.financials?.currency || 'foreign', + exchange_rate: invoice.financials?.exchange_rate || null, + weight_type: 'kgs', + iva_factor: invoice.financials?.iva_factor || null, + carrier_id: invoice.logistics?.carrier_id || null, + transport_id: invoice.logistics?.transport_id || '', + driver_name: invoice.logistics?.driver_name || '', + transport_type: invoice.logistics?.transport_type || '', + transport_num: invoice.logistics?.vehicle_num || '', + aduana: invoice.compliance_mx?.aduana || '', + document_type: invoice.document_type || '' + }; + } + + function mapInvoiceToObservations(invoice: any) { + if (!invoice) return observationSkeleton; + + return { + observation_es: invoice.observation_es || '', + observation_en: invoice.observation_en || '', + freight: invoice.financials?.freight || null, + insurance_value: invoice.financials?.insurance_value || null, + insurance: invoice.financials?.insurance || null, + packaging: invoice.financials?.packaging || null, + other_increments: invoice.financials?.other_increments || null, + total_increments_mn: invoice.financials?.total_increments_mn || null, + total_increments_me: invoice.financials?.total_increments_me || null, + incoterm: invoice.logistics?.incoterm || null, + enclosure: invoice.compliance_mx?.enclosure || null, + num_seals: null, + movement_type: invoice.compliance_mx?.movement_type || '', + alternate_invoice: invoice.alternate_invoice || '', + valuation_method: invoice.compliance_mx?.value_method || null + }; + } + + function mapInvoiceToItems(invoice: any) { + if (!invoice) return ensureItemsFormData(null); + + return { + items: invoice.items || [] + }; + } + + function mapInvoiceToOthers(invoice: any) { + if (!invoice) return othersSkeleton; + + return { + comments_status: invoice.comments_status || '', + transport_mode: invoice.logistics?.transport_mode || 'TRUCK', + is_mixed: invoice.compliance_mx?.is_mixed || false, + print_stamp: invoice.print_stamp || false, + rule_3121_parties_ii: invoice.compliance_mx?.rule_3121_parties_ii || false, + related_doc_id: invoice.related_doc_id || null, + code_signature: invoice.compliance_mx?.code_signature || '', + electronic_signature: invoice.compliance_mx?.electronic_signature || '', + mandatory_person: invoice.compliance_mx?.mandatory_person || '', + contingency_mode: invoice.compliance_mx?.contingency_mode || false, + cove: invoice.compliance_mx?.cove || '', + operation_num: invoice.compliance_mx?.operation_num || '', + adendas: invoice.compliance_mx?.adendas || '', + observations_vu: invoice.compliance_mx?.observations_vu || '', + certified_number: invoice.compliance_mx?.certified_number || '', + bill_number: invoice.logistics?.bill_number || '', + guide_number: invoice.logistics?.guide_number || '', + shipment_number: invoice.logistics?.shipment_number || '', + option_iv18: invoice.compliance_mx?.option_iv18 || '', + delivered_status: invoice.delivered_status || false, + received_by: invoice.received_by || '', + delivery_date: invoice.delivery_date || '' + }; + } + + function mapInvoiceToContinuation(invoice: any) { + if (!invoice) return continuationSkeleton; + + return { + numero_tipo_transporte: invoice.logistics?.numero_tipo_transporte || '', + es_ferrocarril: invoice.logistics?.es_ferrocarril || 'no', + numero_bl: invoice.logistics?.numero_bl || '', + cantidad_guias_embarque: invoice.logistics?.cantidad_guias_embarque || null, + destino_origen: invoice.logistics?.destino_origen || '', + puerto_entrada: invoice.logistics?.puerto_entrada || '', + vehicle_data: invoice.logistics?.vehicle_data || '', + fue_revisado_equipo: invoice.logistics?.fue_revisado_equipo || false, + sub_division: invoice.compliance_mx?.subdivision || false, + funge_como_cd: invoice.logistics?.acts_as_cd || false, + llego_pedimento: invoice.compliance_mx?.llego_pedimento || false, + errores_facturacion: invoice.errores_facturacion || [], + semaforo_verde_aduana_mexicana: invoice.compliance_mx?.semaforo_verde_aduana_mexicana || false, + semaforo_verde_aduana_americana: invoice.compliance_mx?.semaforo_verde_aduana_americana || false, + semaforo_rojo_aduana_mexicana: invoice.compliance_mx?.semaforo_rojo_aduana_mexicana || false, + semaforo_rojo_aduana_americana: invoice.compliance_mx?.semaforo_rojo_aduana_americana || false, + is_mixed: invoice.compliance_mx?.is_mixed || false, + reason_export: invoice.compliance_mx?.reason_export || '1', + purchase_order: invoice.purchase_order || '', + payment_terms: invoice.payment_terms || '', + handling_fees: invoice.financials?.handling_fees || 0, + cfdi_uuid: invoice.cfdi_uuid || '', + path_pdf: invoice.path_pdf || '', + path_xml: invoice.path_xml || '' + }; + } + // Referencias a los componentes de formulario para obtener sus datos + // Si estamos en modo edición (!data.isCreate) y tenemos una factura, usarla + // Si estamos en modo creación, usar defaultSettings let InvoiceTopFieldsFormData = $state( - mergeDefaults(topFieldsSkeleton, data.defaultSettings?.InvoiceTopFieldsFormData) + !data.isCreate && data.invoice + ? mapInvoiceToTopFields(data.invoice) + : mergeDefaults(topFieldsSkeleton, data.defaultSettings?.InvoiceTopFieldsFormData) ); let generalFormData = $state( - mergeDefaults(generalSkeleton, data.defaultSettings?.generalFormData) + !data.isCreate && data.invoice + ? mapInvoiceToGeneral(data.invoice) + : mergeDefaults(generalSkeleton, data.defaultSettings?.generalFormData) ); let observationFormData = $state( - mergeDefaults(observationSkeleton, data.defaultSettings?.observationFormData) + !data.isCreate && data.invoice + ? mapInvoiceToObservations(data.invoice) + : mergeDefaults(observationSkeleton, data.defaultSettings?.observationFormData) + ); + let itemsFormData = $state( + !data.isCreate && data.invoice + ? mapInvoiceToItems(data.invoice) + : ensureItemsFormData(data.defaultSettings?.itemsFormData) ); - let itemsFormData = $state(ensureItemsFormData(data.defaultSettings?.itemsFormData)); let othersFormData = $state( - mergeDefaults(othersSkeleton, data.defaultSettings?.othersFormData) + !data.isCreate && data.invoice + ? mapInvoiceToOthers(data.invoice) + : mergeDefaults(othersSkeleton, data.defaultSettings?.othersFormData) ); let continuationFormData = $state( - mergeDefaults(continuationSkeleton, data.defaultSettings?.continuationFormData) + !data.isCreate && data.invoice + ? mapInvoiceToContinuation(data.invoice) + : mergeDefaults(continuationSkeleton, data.defaultSettings?.continuationFormData) ); // Estados para saber si existen datos previos - let observationExists = $state(!!data.defaultSettings?.observationFormData); - let itemsExists = $state(!!data.defaultSettings?.itemsFormData?.items?.length); - let othersExists = $state(!!data.defaultSettings?.othersFormData); - let continuationExists = $state(!!data.defaultSettings?.continuationFormData); + let observationExists = $state( + !data.isCreate ? !!data.invoice : !!data.defaultSettings?.observationFormData + ); + let itemsExists = $state( + !data.isCreate + ? !!(data.invoice?.items && data.invoice.items.length > 0) + : !!data.defaultSettings?.itemsFormData?.items?.length + ); + let othersExists = $state( + !data.isCreate ? !!data.invoice : !!data.defaultSettings?.othersFormData + ); + let continuationExists = $state( + !data.isCreate ? !!data.invoice : !!data.defaultSettings?.continuationFormData + ); let calculatedExchangeRate = $state( data.invoice?.financials?.exchange_rate ?? null