diff --git a/backend/api/v1/modules/a76/customs_brokers/dto.py b/backend/api/v1/modules/a76/customs_brokers/dto.py index 07923e14..fa11b268 100644 --- a/backend/api/v1/modules/a76/customs_brokers/dto.py +++ b/backend/api/v1/modules/a76/customs_brokers/dto.py @@ -5,6 +5,7 @@ from pydantic import BaseModel class CustomsBrokerBaseDTO(BaseModel): """Base fields for CustomsBroker""" + type: Optional[str] = None name: Optional[str] = None address: Optional[str] = None @@ -25,16 +26,20 @@ class CustomsBrokerBaseDTO(BaseModel): class CustomsBrokerCreateDTO(CustomsBrokerBaseDTO): """Schema for creating a new CustomsBroker""" + broker_key: str class CustomsBrokerUpdateDTO(CustomsBrokerBaseDTO): """Schema for updating an existing CustomsBroker""" + pass class CustomsBrokerResponseDTO(CustomsBrokerBaseDTO): """Schema for CustomsBroker response""" + + id: int broker_key: str tenant_id: int company_id: int diff --git a/backend/api/v1/modules/a76/invoices/models.py b/backend/api/v1/modules/a76/invoices/models.py index 10d22c0c..76974fac 100644 --- a/backend/api/v1/modules/a76/invoices/models.py +++ b/backend/api/v1/modules/a76/invoices/models.py @@ -6,6 +6,23 @@ from core.database import Base from datetime import datetime from ....common.base_models import TenantScopedMixin, TimestampMixin +class Currency(str, Enum): + FOREIGN = "foreign" + LOCAL = "local" + MANUAL = "manual" + +class WeightUnit(str, Enum): + KGS = "kgs" + LBS = "lbs" + +class DestinationOriginCove(str, Enum): + EDO_BC_PARC_SON = "edo_bc_parc_son" + ESTADO_BCS = "estado_bcs" + ESTADO_ROO = "estado_roo" + MPIO_SALINA_CRUZ_OAX = "mpio_salina_cruz_oxa" + FRANJA_FRONT_NORTE = "franja_front_norte" + INTERIOR_PAIS = "interior_pais" + MPIO_CABORCA_SON = "mpio_caborca_son" class OperationType(str, Enum): IMP = "imp" # Importación @@ -38,10 +55,11 @@ class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin): id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) # Identifiers - system: Mapped[Optional[str]] = mapped_column(String(12)) # SISTEMA / Sistema de origen <-- no tiene campo en la antigua base de datos, sera para fixed_asset(scaf), inventory(scaii) - operation_type: Mapped[OperationType] = mapped_column(String(10)) # TIPOMOVIMIENTO / Clasifica imp/exp/sm/ctm - invoice_type: Mapped[Optional[str]] = mapped_column(ForeignKey("public.invoice_types.key")) # TIPOFACTURA / TIPODOC - invoice_number: Mapped[Optional[str]] = mapped_column(String(20)) # FACTURAIMPO/FACTURAEXPO/FACTURAREMISION/FACTURAENVIO/FACTURASALIDA + system: Mapped[str] = mapped_column(String(12)) # SISTEMA / Sistema de origen <-- no tiene campo en la antigua base de datos, sera para fixed_asset(scaf), inventory(scaii) + operation_type: Mapped[OperationType] = mapped_column(String(11)) # TIPOMOVIMIENTO / Clasifica imp/exp/sm/ctm + invoice_type: Mapped[str] = mapped_column(ForeignKey("public.invoice_types.key")) # TIPOFACTURA / TIPODOC + document_type: Mapped[str] = mapped_column(ForeignKey("public.pedimento_regimens.code")) # CLAVEDOCUMENTO / Clave de documento + invoice_number: Mapped[str] = mapped_column(String(100)) # FACTURAIMPO/FACTURAEXPO/FACTURAREMISION/FACTURAENVIO/FACTURASALIDA project_number: Mapped[Optional[str]] = mapped_column(String(14)) # NUMPROYECTO purchase_order: Mapped[Optional[str]] = mapped_column(String(50)) # ORDENCOMPRA related_doc_id: Mapped[Optional[int]] = mapped_column(Integer) # IDRELDOC / Para Rectificaciones @@ -50,20 +68,20 @@ class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin): proforma_number: Mapped[Optional[str]] = mapped_column(String(20)) # NUMEROPROFORMA # Dates - invoice_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAFACTURA + invoice_date: Mapped[datetime] = mapped_column(Date) # FECHAFACTURA capture_date: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=False), default=datetime.now) # FECHACAPTURA + HORAACTUAL emission_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAEMISION # Status & Control - is_updated: Mapped[Optional[bool]] = mapped_column(Boolean) # ESTATUS + is_updated: Mapped[bool] = mapped_column(Boolean) # ESTATUS + is_updated_rec: Mapped[Optional[bool]] = mapped_column(Boolean) # ESTATUSREC / Estatus de recepción + is_updated_rep: Mapped[Optional[bool]] = mapped_column(Boolean) # ESTATUSREP / Estatus de reporte updated_date: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP(timezone=False)) # FECHAACTUALIZACION / FECHAACTUAL who_updated: Mapped[Optional[str]] = mapped_column(String(20)) # USUARIOACT / Quien actualizó capture_user: Mapped[Optional[str]] = mapped_column(String(20)) # USUARIOCAP / Usuario que capturó traffic_light_status: Mapped[Optional[str]] = mapped_column(String(50)) # SEMAFORO / SEMAFOROEXPO/IMPO - process_log: Mapped[Optional[str]] = mapped_column(String(300)) # COMOFUEPROCESADA - status_rec: Mapped[Optional[int]] = mapped_column(Integer) # ESTATUSREC / Estatus de recepción - status_rep: Mapped[Optional[str]] = mapped_column(String(2)) # ESTATUSREP / Estatus de reporte + process_log: Mapped[Optional[str]] = mapped_column(String(300)) # COMOFUEPROCESADA # Comments observation_es: Mapped[Optional[str]] = mapped_column(Text) # OBSERVACIONE / Observaciones en español @@ -81,9 +99,9 @@ class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin): party_count: Mapped[Optional[int]] = mapped_column(Integer) # CANT_PARTIDAS / Cantidad de partidas # Generation flags - generate_id: Mapped[Optional[str]] = mapped_column(String(1)) # GENERAID + generate_id: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # GENERAID generate_desc_parties: Mapped[Optional[str]] = mapped_column(String(12)) # GENDESCPARTIDAS / Generar descripción de partidas - apply_manual_discount: Mapped[Optional[str]] = mapped_column(String(1)) # APLICADESCMANUAL + apply_manual_discount: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # APLICADESCMANUAL # Bulk & Downloads is_bulk: Mapped[Optional[bool]] = mapped_column(Boolean) # ESAGRANEL / Es a granel @@ -129,15 +147,15 @@ class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin): # Clients & Providers provider_header: Mapped[Optional[str]] = mapped_column(String(20)) # PROVEEDOREXPORTADOR - provider_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # PROVEEDOR + provider_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # PROVEEDOR sold_to_header: Mapped[Optional[str]] = mapped_column(String(20)) # VENDIDOCONSIGNADO - sold_to_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # VENDIDOA + sold_to_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # VENDIDOA shipped_to_header: Mapped[Optional[str]] = mapped_column(String(20)) # ENVIADOTRANSFERIDO - shipped_to_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # ENVIADOA + shipped_to_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # ENVIADOA shipped_by_header: Mapped[Optional[str]] = mapped_column(String(20)) # ENVIADOPORVENDIDOPOR - shipped_by_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # VENDIDOPOR/ENVIADOPOR - customs_broker_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.customs_brokers.id")) # AADUANAL / Agente aduanal - customs_broker_us_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.customs_brokers.id")) # AADUANALAME / Agente aduanal americano + shipped_by_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # VENDIDOPOR/ENVIADOPOR + customs_broker_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.customs_brokers.id")) # AADUANAL / Agente aduanal + customs_broker_us_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.customs_brokers.id")) # AADUANALAME / Agente aduanal americano # Broker Invoice broker_invoice_num: Mapped[Optional[str]] = mapped_column(String(20)) # NUMFACTURABROKER / Número factura broker @@ -148,15 +166,15 @@ class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin): waste_type: Mapped[Optional[str]] = mapped_column(String(1)) # TIPODESPERDICIO / Tipo de desperdicio scrap_type: Mapped[Optional[str]] = mapped_column(String(1)) # TIPOSCRAP / Tipo de scrap appendix_17: Mapped[Optional[int]] = mapped_column(Integer) # APENDICE17 / Apéndice 17 - is_regime_change: Mapped[Optional[str]] = mapped_column(String(1)) # ESCAMBIOREGIMEN / Es cambio de régimen + is_regime_change: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # ESCAMBIOREGIMEN / Es cambio de régimen which_exchange_rate: Mapped[Optional[str]] = mapped_column(String(5)) # CUALTIPOCAMBIO / Cuál tipo de cambio value_method: Mapped[Optional[str]] = mapped_column(String(2)) # METVALOR / Método de valoración act_value: Mapped[Optional[str]] = mapped_column(String(5)) # ACTVALOR / Actualizar valor is_pedimento_pending: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # PED_PENDIENTE_ASIGNAR (Mapear 1 -> True, 0 -> False) # Ownership & Balances - is_owner_of_goods: Mapped[Optional[str]] = mapped_column(String(2)) # ESDUENOMCIA / Es dueño de mercancía - generate_balances: Mapped[Optional[str]] = mapped_column(String(2)) # GENERARSALDOS / Generar saldos + is_owner_of_goods: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # ESDUENOMCIA / Es dueño de mercancía + generate_balances: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # GENERARSALDOS / Generar saldos was_reviewed_by_company: Mapped[Optional[bool]] = mapped_column(Boolean) # FUEREVISADAMCIA / Fue revisada por la compañía # VUCEM / Digital @@ -166,7 +184,7 @@ class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin): niu_number: Mapped[Optional[str]] = mapped_column(String(19)) # NUMERONIU / Número NIU bill_of_lading_count: Mapped[Optional[str]] = mapped_column(String(12)) # CANTGUIASEMBARQUE / Cantidad guías embarque addendum_vu: Mapped[Optional[str]] = mapped_column(String(204)) # ADENDAVU / Adenda VUCEM - origin_destination_cove: Mapped[Optional[str]] = mapped_column(String(19)) # DESTINOORIGENCOVE / Destino/Origen COVE + origin_destination_cove: Mapped[Optional[DestinationOriginCove]] = mapped_column(String(20)) # DESTINOORIGENCOVE / Destino/Origen COVE vucem_operation_num: Mapped[Optional[str]] = mapped_column(String(19)) # NUMOPERACIONVU / Número operación VUCEM customs_person_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEAPERSONAAA / Línea persona agente aduanal @@ -201,7 +219,7 @@ class InvoiceFinancials(Base, TenantScopedMixin, TimestampMixin): invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id")) # Currency - currency: Mapped[Optional[str]] = mapped_column(String(3)) # CLAVEMONEDA / Clave de moneda + currency: Mapped[Currency] = mapped_column(String(7)) # CLAVEMONEDA / Clave de moneda currency_type: Mapped[Optional[str]] = mapped_column(ForeignKey("public.currency_types.code")) # TIPOMONEDA / TIPOCLAVEMONEDA exchange_rate: Mapped[Optional[float]] = mapped_column(Numeric(13, 6)) # TIPOCAMBIO / Tipo de cambio exchange_rate_mm: Mapped[Optional[float]] = mapped_column(Numeric(13, 6)) # TIPOCAMBIOMM / Tipo de cambio moneda a moneda @@ -278,7 +296,7 @@ class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin): transport_num: Mapped[Optional[str]] = mapped_column(String(20)) # NUMTRASPORTE / Número de transporte transport_mode: Mapped[Optional[str]] = mapped_column(String(15)) # MODTRANS / Modo de transporte driver_name: Mapped[Optional[str]] = mapped_column(String(80)) # CONDUCTOR / Nombre del conductor - is_rail: Mapped[Optional[str]] = mapped_column(String(2)) # ESFERROCARRIL / Es ferrocarril + is_rail: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # ESFERROCARRIL / Es ferrocarril rail_id: Mapped[Optional[str]] = mapped_column(String(31)) # IDFERRORCARRIL / ID ferrocarril # Vehicle & Tracking @@ -302,7 +320,7 @@ class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin): complement_2: Mapped[Optional[str]] = mapped_column(String(30)) # COMPLEMENTO2 / Complemento 2 # Weight & Container Info - weight_type: Mapped[Optional[str]] = mapped_column(String(6)) # TIPOPESO / Tipo de peso + weight_type: Mapped[WeightUnit] = mapped_column(String(3)) # TIPOPESO / Tipo de peso container_types: Mapped[Optional[str]] = mapped_column(String(500)) # CONTENEDORESTIPO / Tipos de contenedores vehicle_data: Mapped[Optional[str]] = mapped_column(String(500)) # DATOSVEHICULO / Datos del vehículo @@ -317,7 +335,7 @@ class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin): delivery_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAENTREGA / Fecha de entrega # Delivery Control - delivered_status: Mapped[Optional[str]] = mapped_column(String(2)) # ENTREGADO / Estado de entrega + delivered_status: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # ENTREGADO / Estado de entrega received_by: Mapped[Optional[str]] = mapped_column(String(50)) # RECIBIDOPOR / Recibido por # Payment Info @@ -325,7 +343,7 @@ class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin): payment_receipt_num: Mapped[Optional[str]] = mapped_column(String(20)) # NUMRECIBOPAGO / Número de recibo de pago # CTM Process - is_ctm_process: Mapped[Optional[str]] = mapped_column(String(2)) # SETRATAPROCESOCTM / Se trata de proceso CTM + is_ctm_process: Mapped[Optional[bool]] = mapped_column(Boolean, default=False) # SETRATAPROCESOCTM / Se trata de proceso CTM # Relationship header: Mapped["InvoiceHeader"] = relationship(back_populates="logistics") diff --git a/backend/api/v1/modules/a76/invoices/schemas.py b/backend/api/v1/modules/a76/invoices/schemas.py index 16c77e70..1e1938d3 100644 --- a/backend/api/v1/modules/a76/invoices/schemas.py +++ b/backend/api/v1/modules/a76/invoices/schemas.py @@ -1,8 +1,8 @@ -from typing import Optional, List +from typing import Literal, Optional, List from datetime import datetime, date from decimal import Decimal from pydantic import BaseModel, Field -from .models import OperationType +from .models import DestinationOriginCove, OperationType, Currency, TransportType, WeightUnit # --- Base Schemas --- @@ -11,11 +11,13 @@ class InvoiceHeaderBase(BaseModel): system: Optional[str] = Field( None, max_length=12, description="System of origin") operation_type: Optional[OperationType] = Field( - None, max_length=10, description="Operation type: imp/exp/sm/ctm") + ..., description="Operation type: imp/exp/sm/ctm") invoice_type: Optional[str] = Field( None, max_length=5, description="Invoice type key") + document_type: str = Field( + ..., max_length=3, description="Document type (Regimen Aduanero)") invoice_number: Optional[str] = Field( - None, max_length=20, description="Invoice number") + None, max_length=100, description="Invoice number") project_number: Optional[str] = Field( None, max_length=14, description="Project number") purchase_order: Optional[str] = Field( @@ -28,9 +30,9 @@ class InvoiceHeaderBase(BaseModel): None, max_length=19, description="Invoice reference") proforma_number: Optional[str] = Field( None, max_length=20, description="Proforma number") - invoice_date: Optional[date] = Field(None, description="Invoice date") + invoice_date: date = Field(..., description="Invoice date") emission_date: Optional[date] = Field(None, description="Emission date") - is_updated: Optional[bool] = Field(None, description="Status") + is_updated: bool = Field(False, description="Status") updated_date: Optional[datetime] = Field(None, description="Update date") who_updated: Optional[str] = Field( None, max_length=20, description="Who updated") @@ -40,8 +42,8 @@ class InvoiceHeaderBase(BaseModel): None, max_length=50, description="Traffic light status") process_log: Optional[str] = Field( None, max_length=300, description="Processing log") - status_rec: Optional[int] = Field(None, description="Reception status") - status_rep: Optional[str] = Field( + is_updated_rec: Optional[int] = Field(None, description="Reception status") + is_updated_rep: Optional[str] = Field( None, max_length=2, description="Report status") observation_es: Optional[str] = Field( None, description="Observations in Spanish") @@ -60,12 +62,10 @@ class InvoiceHeaderBase(BaseModel): subcompany: Optional[str] = Field( None, max_length=5, description="Subcompany") party_count: Optional[int] = Field(None, description="Quantity of parties") - generate_id: Optional[str] = Field( - None, max_length=1, description="Generate ID") + generate_id: Optional[bool] = Field(False, description="Generate ID") generate_desc_parties: Optional[str] = Field( None, max_length=12, description="Generate description of parties") - apply_manual_discount: Optional[str] = Field( - None, max_length=1, description="Apply manual discount") + apply_manual_discount: Optional[bool] = Field(False, description="Apply manual discount") is_bulk: Optional[bool] = Field(None, description="Is bulk") download_substance: Optional[bool] = Field( None, description="Download substance") @@ -99,51 +99,50 @@ class InvoiceComplianceMxBase(BaseModel): None, max_length=3, description="Destination code") manifest_number: Optional[str] = Field( None, max_length=15, description="Manifest number") - provider_header: Optional[str] = Field( + provider_header: str = Field( None, max_length=20, description="Provider header") - provider_id: Optional[str] = Field( + provider_id: int = Field( None, description="Provider ID") - sold_to_header: Optional[str] = Field( + sold_to_header: str = Field( None, max_length=20, description="Sold to header") - sold_to_id: Optional[str] = Field( + sold_to_id: int = Field( None, description="Sold to ID") - shipped_to_header: Optional[str] = Field( + shipped_to_header: str = Field( None, max_length=20, description="Shipped to header") - shipped_to_id: Optional[str] = Field( + shipped_to_id:int = Field( None, description="Shipped to ID") - shipped_by_header: Optional[str] = Field( + shipped_by_header: Optional[int] = Field( None, max_length=20, description="Shipped by header") - shipped_by_id: Optional[str] = Field( + shipped_by_id: Optional[int] = Field( None, description="Shipped by ID") - customs_broker_id: Optional[str] = Field( + customs_broker_id: int = Field( None, description="Customs broker ID") - customs_broker_us_id: Optional[str] = Field( + customs_broker_us_id: Optional[int] = Field( None, description="US customs broker ID") broker_invoice_num: Optional[str] = Field( None, max_length=20, description="Broker invoice number") broker_invoice_date: Optional[date] = Field( None, description="Broker invoice date") is_mixed: Optional[bool] = Field( - None, description="Is mixed operation") + False, description="Is mixed operation") waste_type: Optional[str] = Field( None, max_length=1, description="Waste type") scrap_type: Optional[str] = Field( None, max_length=1, description="Scrap type") appendix_17: Optional[int] = Field(None, description="Appendix 17") - is_regime_change: Optional[str] = Field( - None, max_length=1, description="Is regime change") + is_regime_change: Optional[bool] = Field( + False, description="Is regime change") which_exchange_rate: Optional[str] = Field( None, max_length=5, description="Which exchange rate") value_method: Optional[str] = Field( None, max_length=2, description="Value method") act_value: Optional[str] = Field( None, max_length=5, description="Act value") - is_pedimento_pending: Optional[bool] = Field( - None, description="Is pedimento pending") - is_owner_of_goods: Optional[str] = Field( - None, max_length=2, description="Is owner of goods") - generate_balances: Optional[str] = Field( - None, max_length=2, description="Generate balances") + is_pedimento_pending: bool = Field(..., description="Is pedimento pending") + is_owner_of_goods: Optional[bool] = Field( + False, description="Is owner of goods") + generate_balances: Optional[bool] = Field( + False, description="Generate balances") was_reviewed_by_company: Optional[bool] = Field( None, description="Was reviewed by company") edocument: Optional[str] = Field( @@ -158,8 +157,7 @@ class InvoiceComplianceMxBase(BaseModel): None, max_length=12, description="Bill of lading count") addendum_vu: Optional[str] = Field( None, max_length=204, description="VUCEM addendum") - origin_destination_cove: Optional[str] = Field( - None, max_length=19, description="Origin/Destination COVE") + origin_destination_cove: Optional[DestinationOriginCove] = Field('franja_front_norte', max_length=20, description="Origin/Destination COVE") vucem_operation_num: Optional[str] = Field( None, max_length=19, description="VUCEM operation number") customs_person_line: Optional[int] = Field( @@ -191,11 +189,11 @@ class InvoiceComplianceMxBase(BaseModel): class InvoiceFinancialsBase(BaseModel): """Base fields for Financials""" - currency: Optional[str] = Field( - None, max_length=3, description="Currency code") + currency: Currency = Field( + None, max_length=7, description="Currency code") currency_type: Optional[str] = Field( - None, description="Currency type") - exchange_rate: Optional[Decimal] = Field(None, description="Exchange rate") + "USD", description="Currency type") + exchange_rate: Decimal = Field(None, description="Exchange rate") exchange_rate_mm: Optional[Decimal] = Field( None, description="Exchange rate currency to currency") value_mn: Optional[Decimal] = Field(None, description="Value in MXN") @@ -245,8 +243,7 @@ class InvoiceFinancialsBase(BaseModel): None, description="IVA in foreign currency") iva_mc: Optional[Decimal] = Field( None, description="IVA in third currency") - iva_factor: Optional[str] = Field( - None, max_length=10, description="IVA factor") + iva_factor: Optional[Decimal] = Field(None, description="IVA factor") tax_value_me: Optional[Decimal] = Field( None, description="Tax value in foreign currency") seal_value_2500: Optional[bool] = Field( @@ -267,16 +264,16 @@ class InvoiceLogisticsBase(BaseModel): None, max_length=10, description="Transport ID") transport_us_id: Optional[str] = Field( None, max_length=10, description="US transport ID") - transport_type: Optional[str] = Field( - None, max_length=15, description="Transport type") + transport_type: TransportType = Field( + 'none', max_length=15, description="Transport type") transport_num: Optional[str] = Field( None, max_length=20, description="Transport number") transport_mode: Optional[str] = Field( - None, max_length=15, description="Transport mode") + 30, max_length=15, description="Transport mode") driver_name: Optional[str] = Field( None, max_length=80, description="Driver name") - is_rail: Optional[str] = Field( - None, max_length=2, description="Is rail transport") + is_rail: Optional[bool] = Field( + False, description="Is rail transport") rail_id: Optional[str] = Field( None, max_length=31, description="Rail ID") vehicle_num: Optional[str] = Field( @@ -307,8 +304,8 @@ class InvoiceLogisticsBase(BaseModel): None, max_length=2, description="Identifier 2") complement_2: Optional[str] = Field( None, max_length=30, description="Complement 2") - weight_type: Optional[str] = Field( - None, max_length=6, description="Weight type") + weight_type: WeightUnit = Field( + default="kgs", max_length=3, description="Weight type") container_types: Optional[str] = Field( None, max_length=500, description="Container types") vehicle_data: Optional[str] = Field( @@ -333,8 +330,8 @@ class InvoiceLogisticsBase(BaseModel): None, description="Payment date") payment_receipt_num: Optional[str] = Field( None, max_length=20, description="Payment receipt number") - is_ctm_process: Optional[str] = Field( - None, max_length=2, description="Is CTM process") + is_ctm_process: Optional[bool] = Field( + False, description="Is CTM process") class InvoiceSalesDetailsBase(BaseModel): diff --git a/frontend/src/lib/api/dashboard/a76/customs-brokers.ts b/frontend/src/lib/api/dashboard/a76/customs-brokers.ts index 9f18da9e..dababc56 100644 --- a/frontend/src/lib/api/dashboard/a76/customs-brokers.ts +++ b/frontend/src/lib/api/dashboard/a76/customs-brokers.ts @@ -2,6 +2,7 @@ import { api } from '$lib/api'; export interface CustomsBroker { + id: number; type?: string | null; broker_key: string; name?: string | null; @@ -111,15 +112,15 @@ export const customsBrokersApi = { * Elimina un agente aduanal */ delete: (brokerKey: string, companyId: string) => { - return api.delete(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`); + return api.delete(`/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`); }, - + /** * Actualiza la información de un agente aduanal */ update: (brokerKey: string, data: CreateCustomsBrokerData) => { const companyId = data.company_id; - return api.put(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`, data); + return api.put(`/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`, data); }, /** diff --git a/frontend/src/lib/api/dashboard/a76/invoices.ts b/frontend/src/lib/api/dashboard/a76/invoices.ts index 7dbb1c0d..cedb7e74 100644 --- a/frontend/src/lib/api/dashboard/a76/invoices.ts +++ b/frontend/src/lib/api/dashboard/a76/invoices.ts @@ -20,22 +20,22 @@ export interface InvoiceComplianceMx { destination?: string | null; manifest_number?: string | null; provider_header?: string | null; - provider_id?: string | null; + provider_id?: number | null; sold_to_header?: string | null; - sold_to_id?: string | null; + sold_to_id?: number | null; shipped_to_header?: string | null; shipped_to_id?: string | null; shipped_by_header?: string | null; - shipped_by_id?: string | null; - customs_broker_id?: string | null; - customs_broker_us_id?: string | null; + shipped_by_id?: number | null; + customs_broker_id?: number | null; + customs_broker_us_id?: number | null; broker_invoice_num?: string | null; broker_invoice_date?: string | null; is_mixed?: boolean | null; waste_type?: string | null; scrap_type?: string | null; appendix_17?: number | null; - is_regime_change?: string | null; + is_regime_change?: boolean | null; which_exchange_rate?: string | null; value_method?: string | null; act_value?: string | null; @@ -179,6 +179,7 @@ export interface Invoice { system?: string | null; operation_type?: OperationType | null; invoice_type?: string | null; + document_type?: string | null; invoice_number?: string | null; project_number?: string | null; purchase_order?: string | null; @@ -195,8 +196,8 @@ export interface Invoice { capture_user?: string | null; traffic_light_status?: string | null; process_log?: string | null; - status_rec?: number | null; - status_rep?: string | null; + is_updated_rec?: number | null; + is_updated_rep?: string | null; observation_es?: string | null; observation_en?: string | null; comments_status?: string | null; @@ -206,9 +207,9 @@ export interface Invoice { path_xml?: string | null; subcompany?: string | null; party_count?: number | null; - generate_id?: string | null; + generate_id?: boolean | null; generate_desc_parties?: string | null; - apply_manual_discount?: string | null; + apply_manual_discount?: boolean | null; is_bulk?: boolean | null; download_substance?: boolean | null; download_class?: boolean | null; @@ -235,6 +236,7 @@ export interface CreateInvoiceData { system: string; operation_type: OperationType; invoice_type: string; + document_type: string; invoice_number: string; project_number?: string | null; purchase_order?: string | null; @@ -250,8 +252,8 @@ export interface CreateInvoiceData { capture_user?: string | null; traffic_light_status?: string | null; process_log?: string | null; - status_rec?: number | null; - status_rep?: string | null; + is_updated_rec?: number | null; + is_updated_rep?: string | null; observation_es?: string | null; observation_en?: string | null; comments_status?: string | null; @@ -261,9 +263,9 @@ export interface CreateInvoiceData { path_xml?: string | null; subcompany?: string | null; party_count?: number | null; - generate_id?: string | null; + generate_id?: boolean | null; generate_desc_parties?: string | null; - apply_manual_discount?: string | null; + apply_manual_discount?: boolean | null; is_bulk?: boolean | null; download_substance?: boolean | null; download_class?: boolean | null; @@ -282,6 +284,7 @@ export interface CreateInvoiceData { export interface UpdateInvoiceData { operation_type?: OperationType | null; invoice_type?: string | null; + document_type?: string | null; invoice_number?: string | null; project_number?: string | null; purchase_order?: string | null; @@ -355,7 +358,7 @@ export const invoicesApi = { const params = new URLSearchParams({ company_id: companyId.toString() }); - return api.put(`/v1/a76/invoices/${invoiceId}?${params.toString()}`, data); + return api.put(`/v1/a76/invoices/${invoiceId}/?${params.toString()}`, data); }, /** diff --git a/frontend/src/lib/components/dashboard/invoices/columns.ts b/frontend/src/lib/components/dashboard/invoices/columns.ts index bee37d2d..c087fae8 100644 --- a/frontend/src/lib/components/dashboard/invoices/columns.ts +++ b/frontend/src/lib/components/dashboard/invoices/columns.ts @@ -100,20 +100,6 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { return renderSnippet(typeSnippet, { label, colorClass }); } }, - { - accessorKey: "invoice_number", - header: "Número de Factura", - cell: ({ row }) => { - const numberSnippet = createRawSnippet<[{ number?: string | null }]>((getNumber) => { - const { number } = getNumber(); - return { - render: () => - `${number || 'N/A'}` - }; - }); - return renderSnippet(numberSnippet, { number: row.original.invoice_number }); - } - }, { accessorKey: "invoice_type", header: "Tipo", @@ -128,6 +114,20 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { return renderSnippet(typeSnippet, { type: row.original.invoice_type }); } }, + { + accessorKey: "invoice_number", + header: "Número de Factura", + cell: ({ row }) => { + const numberSnippet = createRawSnippet<[{ number?: string | null }]>((getNumber) => { + const { number } = getNumber(); + return { + render: () => + `${number || 'N/A'}` + }; + }); + return renderSnippet(numberSnippet, { number: row.original.invoice_number }); + } + }, { accessorKey: "project_number", header: "Proyecto", diff --git a/frontend/src/lib/components/dashboard/invoices/edit/continuation-tab-form.svelte b/frontend/src/lib/components/dashboard/invoices/edit/continuation-tab-form.svelte index 63d613fd..efd1ed4f 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/continuation-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/continuation-tab-form.svelte @@ -16,56 +16,9 @@ exists?: boolean; } = $props(); - if (!formData && invoice?.financials) { + if (!formData && invoice) { formData = { - // Currency & Exchange - currency: invoice.financials.currency || '', - currency_type: invoice.financials.currency_type || '', - exchange_rate: invoice.financials.exchange_rate || null, - exchange_rate_mm: invoice.financials.exchange_rate_mm || null, - // Values - value_mn: invoice.financials.value_mn || null, - value_me: invoice.financials.value_me || null, - value_mc: invoice.financials.value_mc || null, - customs_value_mn: invoice.financials.customs_value_mn || null, - customs_value_me: invoice.financials.customs_value_me || null, - // Raw materials - raw_material_value_mn: invoice.financials.raw_material_value_mn || null, - raw_material_value_me: invoice.financials.raw_material_value_me || null, - // Aggregate values - aggregate_value_mn: invoice.financials.aggregate_value_mn || null, - aggregate_value_me: invoice.financials.aggregate_value_me || null, - aggregate_value_mc: invoice.financials.aggregate_value_mc || null, - // Mexican values - mexican_value_mn: invoice.financials.mexican_value_mn || null, - mexican_value_me: invoice.financials.mexican_value_me || null, - mexican_value_mc: invoice.financials.mexican_value_mc || null, - // National packaging - national_packaging_mn: invoice.financials.national_packaging_mn || null, - national_packaging_me: invoice.financials.national_packaging_me || null, - national_packaging_mc: invoice.financials.national_packaging_mc || null, - // Costs & increments - freight: invoice.financials.freight || null, - insurance: invoice.financials.insurance || null, - insurance_value: invoice.financials.insurance_value || 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, - // Taxes - iva_mn: invoice.financials.iva_mn || null, - iva_me: invoice.financials.iva_me || null, - iva_mc: invoice.financials.iva_mc || null, - iva_factor: invoice.financials.iva_factor || '', - tax_value_me: invoice.financials.tax_value_me || null, - seal_value_2500: invoice.financials.seal_value_2500 || false, - // Weights & quantities - total_quantity: invoice.financials.total_quantity || null, - gross_weight: invoice.financials.gross_weight || null, - net_weight: invoice.financials.net_weight || null, - bundle_count: invoice.financials.bundle_count || null, - weight_factor: invoice.financials.weight_factor || null, - // Additional fields not in backend + // Campos de esta pestaña numero_tipo_transporte: '', es_ferrocarril: 'no', numero_bl: '', @@ -88,54 +41,7 @@ exists = true; } else if (!formData) { formData = { - // Currency & Exchange - currency: '', - currency_type: '', - exchange_rate: null, - exchange_rate_mm: null, - // Values - value_mn: null, - value_me: null, - value_mc: null, - customs_value_mn: null, - customs_value_me: null, - // Raw materials - raw_material_value_mn: null, - raw_material_value_me: null, - // Aggregate values - aggregate_value_mn: null, - aggregate_value_me: null, - aggregate_value_mc: null, - // Mexican values - mexican_value_mn: null, - mexican_value_me: null, - mexican_value_mc: null, - // National packaging - national_packaging_mn: null, - national_packaging_me: null, - national_packaging_mc: null, - // Costs & increments - freight: null, - insurance: null, - insurance_value: null, - packaging: null, - other_increments: null, - total_increments_mn: null, - total_increments_me: null, - // Taxes - iva_mn: null, - iva_me: null, - iva_mc: null, - iva_factor: '', - tax_value_me: null, - seal_value_2500: false, - // Weights & quantities - total_quantity: null, - gross_weight: null, - net_weight: null, - bundle_count: null, - weight_factor: null, - // Additional fields not in backend + // Campos de esta pestaña numero_tipo_transporte: '', es_ferrocarril: 'no', numero_bl: '', diff --git a/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte b/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte index 6b7a613b..f29fbd97 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/general-tab-form.svelte @@ -24,7 +24,8 @@ customsSections = [], codePedimentoRegimens = [], defaultOperationType = undefined, - defaultInvoiceType = undefined + defaultInvoiceType = undefined, + operationType = undefined }: { invoice: Invoice | null; formData?: any; @@ -42,48 +43,27 @@ codePedimentoRegimens?: any[]; defaultOperationType?: number | null; defaultInvoiceType?: string | null; + operationType?: number | null; } = $props(); if (!formData) { if (invoice) { // Editando una factura existente - let operationType: number | null = null; - if (invoice.operation_type) { - operationType = invoice.operation_type === 'exp' ? 1 : 2; - } - formData = { - // TOP fields - is_pedimento_pending: false, - pedimento: invoice.compliance_mx?.pedimento || '', - remesa: invoice.compliance_mx?.remesa || '', - invoice_number: invoice.invoice_number || '', - invoice_date: invoice.invoice_date || '', - emission_date: '', - - // Extra fields - operation_type: operationType, - - // RANGO DE FECHAS fields - fecha_pedimento_del: '', - fecha_pedimento_al: '', - clave_pedimento: '', - regimen_pedimento: '', - // LEFT fields - provider_header: invoice.compliance_mx?.provider_header || '', + 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 || '', + 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 || '', + 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: null, + customs_broker_us_id: invoice.compliance_mx?.customs_broker_us_id || null, // RIGHT fields currency_type: invoice.financials?.currency_type || '', - currency_mode: 'extranjera', // extranjera, nacional, captura - weight_type: '', + currency: invoice.financials?.currency || 'foreign', // foreign, local, manual + weight_type: 'kgs', iva_factor: invoice.financials?.iva_factor || null, carrier_id: invoice.logistics?.[0]?.carrier_id || null, transport_id: '', @@ -91,43 +71,26 @@ transport_type: invoice.logistics?.[0]?.transport_type || '', transport_num: invoice.logistics?.[0]?.vehicle_num || '', aduana: invoice.compliance_mx?.aduana || '', - invoice_type: invoice.invoice_type || '', - clave_regimen_aduanero: '', + document_type: invoice.document_type || '', }; + console.log('FormData cargado para edición:', formData); } else { // Creando una nueva factura formData = { - // TOP fields - is_pedimento_pending: false, - pedimento: '', - remesa: '', - invoice_number: '', - invoice_date: '', - emission_date: '', - - // Extra fields - operation_type: defaultOperationType ?? null, - - // RANGO DE FECHAS fields - fecha_pedimento_del: '', - fecha_pedimento_al: '', - clave_pedimento: '', - regimen_pedimento: '', - // LEFT fields - provider_header: '', + provider_header: 'proveedor', provider_id: null, - sold_to_header: '', + sold_to_header: 'consignado_a', sold_to_id: null, - shipped_to_header: '', + shipped_to_header: 'enviado_a', shipped_to_id: null, customs_broker_id: null, customs_broker_us_id: null, // RIGHT fields currency_type: '', - currency_mode: 'extranjera', // extranjera, nacional, captura - weight_type: '', + currency: 'foreign', // foreign, local, manual + weight_type: 'kgs', iva_factor: null, carrier_id: null, transport_id: '', @@ -135,21 +98,29 @@ transport_type: '', transport_num: '', aduana: '', - invoice_type: defaultInvoiceType ?? '', - clave_regimen_aduanero: '', + document_type: '', }; } } else { - // Si formData ya existe, asegurar que tiene currency_mode - if (formData.currency_mode === undefined) { - formData.currency_mode = 'extranjera'; + // Si formData ya existe, asegurar que tiene valores por defecto + if (formData.currency === undefined) { + formData.currency = 'foreign'; + } + if (!formData.provider_header) { + formData.provider_header = 'proveedor'; + } + if (!formData.sold_to_header) { + formData.sold_to_header = 'consignado_a'; + } + if (!formData.shipped_to_header) { + formData.shipped_to_header = 'enviado_a'; } } // Opciones de tipo de peso const weightTypeOptions = [ - { value: 'kg', label: 'Kilogramos (kg)' }, - { value: 'lb', label: 'Libras (lb)' } + { value: 'kgs', label: 'Kilogramos (kg)' }, + { value: 'lbs', label: 'Libras (lb)' } ]; // Opciones de encabezados @@ -161,11 +132,11 @@ const soldToHeaderOptions = $derived([ { value: 'consignado_a', label: 'Consignado a' }, { value: 'vendido_a', label: 'Vendido a' }, - { value: formData.operation_type === 1 ? 'exportado_a' : 'importador', label: formData.operation_type === 1 ? 'Exportado a' : 'Importador' } + { value: operationType === 1 ? 'exportado_a' : 'importador', label: operationType === 1 ? 'Exportado a' : 'Importador' } ]); const shippedToHeaderOptions = $derived( - formData.operation_type === 1 + operationType === 1 ? [ { value: 'enviado_por', label: 'Enviado Por' }, { value: 'destinatario', label: 'Destinatario' }, @@ -189,7 +160,7 @@ // Filtrar regímenes por tipo de operación (1='E' exp, 2='I' imp) y obtener valores únicos const filteredRegimens = $derived.by(() => { - const typeCode = formData.operation_type === 1 ? 'E' : formData.operation_type === 2 ? 'I' : null; + const typeCode = operationType === 1 ? 'E' : operationType === 2 ? 'I' : null; const filtered = codePedimentoRegimens.filter(r => r.type_code === typeCode); // Obtener solo regímenes únicos por regimen_code @@ -205,10 +176,10 @@ // Efecto: Limpiar régimen si no existe en los regímenes filtrados al cambiar operation_type $effect(() => { - if (formData.clave_regimen_aduanero && filteredRegimens.length > 0) { - const regimenExists = filteredRegimens.some(r => r.regimen_code === formData.clave_regimen_aduanero); + if (formData.document_type && filteredRegimens.length > 0) { + const regimenExists = filteredRegimens.some(r => r.regimen_code === formData.document_type); if (!regimenExists) { - formData.clave_regimen_aduanero = ''; + formData.document_type = ''; } } }); @@ -283,7 +254,8 @@ {/each} - + + *
@@ -328,7 +300,8 @@ {/each} - + + *
@@ -374,52 +347,55 @@ {/each} + *
- + { - formData.customs_broker_id = v || null; + formData.customs_broker_id = v ? parseInt(v) : null; }} > - {customsBrokers.find(cb => cb.broker_key === (formData.customs_broker_id || customsBrokers[0]?.broker_key))?.name || '...'} + {formData.customs_broker_id + ? customsBrokers.find(cb => cb.id === formData.customs_broker_id)?.name || 'Selecciona...' + : 'Selecciona...'} {#each customsBrokers as broker} - + {broker.name} {/each} - +
{ - formData.customs_broker_us_id = v || null; + formData.customs_broker_us_id = v ? parseInt(v) : null; }} > {formData.customs_broker_us_id - ? customsBrokers.find(cb => cb.broker_key === formData.customs_broker_us_id)?.name || '...' - : '...'} + ? customsBrokers.find(cb => cb.id === formData.customs_broker_us_id)?.name || 'Selecciona...' + : 'Selecciona...'} {#each customsBrokers as broker} - + {broker.name} {/each} @@ -439,22 +415,22 @@
- +
- - + +
- - + +
- - + +
- {#if formData.currency_mode === 'captura'} + {#if formData.currency === 'manual'}
Tipo Peso: { - formData.weight_type = v ?? ''; + formData.weight_type = v ?? 'kgs'; }} > - {formData.weight_type || '...'} + {weightTypeOptions.find(w => w.value === formData.weight_type)?.label || 'Kilogramos (kg)'} {#each weightTypeOptions as weightType} - + {weightType.label} {/each} @@ -508,7 +484,7 @@
-
+ @@ -700,22 +676,22 @@
- + { - formData.clave_regimen_aduanero = v ?? ''; + formData.document_type = v ?? ''; }} > - + - {#if formData.clave_regimen_aduanero} - {codePedimentoRegimens.find(r => r.regimen_code === formData.clave_regimen_aduanero)?.regimen_code || formData.clave_regimen_aduanero} + {#if formData.document_type} + {codePedimentoRegimens.find(r => r.regimen_code === formData.document_type)?.regimen_code || formData.document_type} {:else if filteredRegimens.length > 0} Selecciona régimen... - {:else if formData.operation_type} - Sin regímenes para tipo {formData.operation_type} + {:else if operationType} + Sin regímenes para tipo {operationType} {:else} Selecciona tipo de operación primero {/if} diff --git a/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte b/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte index 8e4700a4..e8305f70 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/invoice-top-fields.svelte @@ -70,7 +70,7 @@
- +
- +
- +
- +
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/observations-tab-form.svelte b/frontend/src/lib/components/dashboard/invoices/edit/observations-tab-form.svelte index 1f9c1204..91b069f9 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/observations-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/observations-tab-form.svelte @@ -23,64 +23,10 @@ if (!formData && invoice) { formData = { - // Invoice header fields + // Campos de observaciones observation_es: invoice.observation_es || '', - observation_en: invoice.observation_en || '', - alternate_invoice: invoice.alternate_invoice || '', - // Compliance MX fields - pedimento: invoice.compliance_mx?.pedimento || '', - pedimento_code: invoice.compliance_mx?.pedimento_code || '', - pedimento_k1: invoice.compliance_mx?.pedimento_k1 || '', - remesa: invoice.compliance_mx?.remesa || null, - aduana: invoice.compliance_mx?.aduana || '', - port_of_entry: invoice.compliance_mx?.port_of_entry || '', - destination: invoice.compliance_mx?.destination || '', - manifest_number: invoice.compliance_mx?.manifest_number || '', - provider_header: invoice.compliance_mx?.provider_header || '', - provider_id: invoice.compliance_mx?.provider_id || null, - sold_to_header: invoice.compliance_mx?.sold_to_header || '', - sold_to_id: invoice.compliance_mx?.sold_to_id || null, - shipped_to_header: invoice.compliance_mx?.shipped_to_header || '', - shipped_to_id: invoice.compliance_mx?.shipped_to_id || null, - shipped_by_header: invoice.compliance_mx?.shipped_by_header || '', - shipped_by_id: invoice.compliance_mx?.shipped_by_id || null, - customs_broker_id: invoice.compliance_mx?.customs_broker_id || null, - broker_invoice_num: invoice.compliance_mx?.broker_invoice_num || '', - broker_invoice_date: invoice.compliance_mx?.broker_invoice_date || '', - is_mixed: invoice.compliance_mx?.is_mixed || null, - waste_type: invoice.compliance_mx?.waste_type || '', - scrap_type: invoice.compliance_mx?.scrap_type || '', - appendix_17: invoice.compliance_mx?.appendix_17 || null, - is_regime_change: invoice.compliance_mx?.is_regime_change || '', - which_exchange_rate: invoice.compliance_mx?.which_exchange_rate || '', - value_method: invoice.compliance_mx?.value_method || '', - act_value: invoice.compliance_mx?.act_value || '', - is_pedimento_pending: invoice.compliance_mx?.is_pedimento_pending || false, - is_owner_of_goods: invoice.compliance_mx?.is_owner_of_goods || '', - generate_balances: invoice.compliance_mx?.generate_balances || '', - was_reviewed_by_company: invoice.compliance_mx?.was_reviewed_by_company || false, - edocument: invoice.compliance_mx?.edocument || '', - electronic_signature: invoice.compliance_mx?.electronic_signature || '', - certificate_number: invoice.compliance_mx?.certificate_number || '', - niu_number: invoice.compliance_mx?.niu_number || '', - bill_of_lading_count: invoice.compliance_mx?.bill_of_lading_count || '', - addendum_vu: invoice.compliance_mx?.addendum_vu || '', - origin_destination_cove: invoice.compliance_mx?.origin_destination_cove || '', - vucem_operation_num: invoice.compliance_mx?.vucem_operation_num || '', - customs_person_line: invoice.compliance_mx?.customs_person_line || null, - contingency_mode: invoice.compliance_mx?.contingency_mode || false, - enclosure: invoice.compliance_mx?.enclosure || '', - guide_type_to_identify: invoice.compliance_mx?.guide_type_to_identify || '', - location: invoice.compliance_mx?.location || '', - dot_code: invoice.compliance_mx?.dot_code || '', - subdivision: invoice.compliance_mx?.subdivision || '', - acts_as: invoice.compliance_mx?.acts_as || '', - movement_type: invoice.compliance_mx?.movement_type || '', - office_document: invoice.compliance_mx?.office_document || '', - reason_export: invoice.compliance_mx?.reason_export || '', - signature_key: invoice.compliance_mx?.signature_key || '', - sem_id: invoice.compliance_mx?.sem_id || null, - // Financials fields (incrementables) + observation_en: invoice.observation_en || '', + // Incrementables freight: invoice.financials?.freight || null, insurance_value: invoice.financials?.insurance_value || null, insurance: invoice.financials?.insurance || null, @@ -88,70 +34,22 @@ 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, - // Logistics fields - incoterm: invoice.logistics?.[0]?.incoterm || '' + // Incoterm y recinto + incoterm: invoice.logistics?.[0]?.incoterm || null, + enclosure: invoice.compliance_mx?.enclosure || null, + // Campos de esta pestaña + num_seals: null, + movement_type: invoice.compliance_mx?.movement_type || '', + alternate_invoice: invoice.alternate_invoice || '', + valuation_method: null }; exists = true; } else if (!formData) { formData = { - // Invoice header fields + // Campos de observaciones observation_es: '', - observation_en: '', - alternate_invoice: '', - // Compliance MX fields - pedimento: '', - pedimento_code: '', - pedimento_k1: '', - remesa: null, - aduana: '', - port_of_entry: '', - destination: '', - manifest_number: '', - provider_header: '', - provider_id: null, - sold_to_header: '', - sold_to_id: null, - shipped_to_header: '', - shipped_to_id: null, - shipped_by_header: '', - shipped_by_id: null, - customs_broker_id: null, - broker_invoice_num: '', - broker_invoice_date: '', - is_mixed: null, - waste_type: '', - scrap_type: '', - appendix_17: null, - is_regime_change: '', - which_exchange_rate: '', - value_method: '', - act_value: '', - is_pedimento_pending: false, - is_owner_of_goods: '', - generate_balances: '', - was_reviewed_by_company: false, - edocument: '', - electronic_signature: '', - certificate_number: '', - niu_number: '', - bill_of_lading_count: '', - addendum_vu: '', - origin_destination_cove: '', - vucem_operation_num: '', - customs_person_line: null, - contingency_mode: false, - enclosure: '', - guide_type_to_identify: '', - location: '', - dot_code: '', - subdivision: '', - acts_as: '', - movement_type: '', - office_document: '', - reason_export: '', - signature_key: '', - sem_id: null, - // Financials fields + observation_en: '', + // Incrementables freight: null, insurance_value: null, insurance: null, @@ -159,8 +57,14 @@ other_increments: null, total_increments_mn: null, total_increments_me: null, - // Logistics fields - incoterm: '' + // Incoterm y recinto + incoterm: null, + enclosure: null, + // Campos de esta pestaña + num_seals: null, + movement_type: '', + alternate_invoice: '', + valuation_method: null }; exists = false; } diff --git a/frontend/src/lib/components/dashboard/invoices/edit/others-tab-form.svelte b/frontend/src/lib/components/dashboard/invoices/edit/others-tab-form.svelte index 46e84244..23fed8a6 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/others-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/others-tab-form.svelte @@ -13,116 +13,63 @@ let { invoice, formData = $bindable(), - exists = $bindable() + exists = $bindable(), + transportModes = [] }: { invoice: Invoice | null; formData?: any; exists?: boolean; + transportModes?: any[]; } = $props(); - if (!formData && invoice?.logistics && invoice.logistics.length > 0) { - formData = invoice.logistics.map(l => ({ - // Carrier info - carrier_id: l.carrier_id || '', - transport_id: l.transport_id || '', - transport_us_id: l.transport_us_id || '', - transport_type: l.transport_type || null, - transport_num: l.transport_num || '', - transport_mode: l.transport_mode || '', - driver_name: l.driver_name || '', - is_rail: l.is_rail || '', - rail_id: l.rail_id || '', - // Vehicle & tracking - vehicle_num: l.vehicle_num || '', - license_plate: l.license_plate || '', - license_plate_complete: l.license_plate_complete || '', - trailer_num: l.trailer_num || '', - seal_number: l.seal_number || '', - guide_number: l.guide_number || '', - bill_number: l.bill_number || '', - reference_number: l.reference_number || '', - shipment_number: l.shipment_number || '', - // Incoterms - incoterm: l.incoterm || '', - // Identifiers - identifier_1: l.identifier_1 || '', - complement_1: l.complement_1 || '', - identifier_2: l.identifier_2 || '', - complement_2: l.complement_2 || '', - // Weight & container - weight_type: l.weight_type || '', - container_types: l.container_types || '', - vehicle_data: l.vehicle_data || '', - // Locations - origin_location: l.origin_location || '', - destination_location: l.destination_location || '', - transport_itinerary: l.transport_itinerary || '', - destination_goods: l.destination_goods || '', - // Dates - entry_exit_date: l.entry_exit_date || '', - delivery_date: l.delivery_date || '', - // Delivery control - delivered_status: l.delivered_status || '', - received_by: l.received_by || '', - // Payment - payment_date: l.payment_date || '', - payment_receipt_num: l.payment_receipt_num || '', - // CTM - is_ctm_process: l.is_ctm_process || '' - })); + if (!formData && invoice) { + formData = { + // Campo de comentario estatus + comments_status: invoice.comments_status || '', + // Campos que van en diferentes recursos pero se editan aquí + transport_mode: invoice.logistics?.[0]?.transport_mode || null, + is_mixed: invoice.compliance_mx?.is_mixed || null, + print_stamp: invoice.financials?.seal_value_2500 || false, + 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: '', + contingency_mode: invoice.compliance_mx?.contingency_mode || false, + cove: invoice.compliance_mx?.origin_destination_cove || '', + operation_num: invoice.compliance_mx?.vucem_operation_num || '', + adendas: invoice.compliance_mx?.addendum_vu || '', + observations_vu: invoice.vu_observations || '', + certified_number: invoice.compliance_mx?.certificate_number || '', + }; exists = true; } else if (!formData) { - formData = []; + formData = { + // Campo de comentario estatus + comments_status: '', + // Campos que van en diferentes recursos pero se editan aquí + transport_mode: 'TRUCK', + is_mixed: null, + print_stamp: false, + rule_3121_parties_ii: false, + related_doc_id: null, + code_signature: '', + electronic_signature: '', + mandatory_person: '', + contingency_mode: false, + cove: '', + operation_num: '', + adendas: '', + observations_vu: '', + certified_number: '', + }; exists = false; } - // Campos adicionales que van en otros recursos - let transportMode = $state('TRUCK'); - // is_mixed va en compliance_mx - let isMixed = $state(invoice?.compliance_mx?.is_mixed ? 'yes' : 'no'); - // related_doc_id va en invoice header - let relationDocsId = $state(invoice?.related_doc_id?.toString() || '0'); - // electronic_signature va en compliance_mx - let code_signature = $state(invoice?.compliance_mx?.code_signature || ''); - let electronicSignature = $state(invoice?.compliance_mx?.electronic_signature || ''); - // Estos campos no existen en el schema del backend - let mandatoryPerson = $state('0'); + // Campos que no están en el backend let rfc = $state(''); - let contingencyMode = $state(invoice?.compliance_mx?.contingency_mode || false); let curp = $state(''); - let rule3121PartiesII = $state(false); - // origin_destination_cove va en compliance_mx - let cove = $state(invoice?.compliance_mx?.origin_destination_cove || ''); - // vucem_operation_num va en compliance_mx - let operationNum = $state(invoice?.compliance_mx?.vucem_operation_num || ''); - // addendum_vu va en compliance_mx - let adendas = $state(invoice?.compliance_mx?.addendum_vu || ''); - // vu_observations va en invoice header - let observationsVU = $state(invoice?.vu_observations || ''); - // certificate_number va en compliance_mx - let certifiedNumber = $state(invoice?.compliance_mx?.certificate_number || ''); - // seal_value_2500 va en financials - let printStamp = $state(invoice?.financials?.seal_value_2500 || false); - // comments_status va en invoice header - let commentsStatus = $state(invoice?.comments_status || ''); - const transportModes = [ - { value: 'TRUCK', label: 'Camión' }, - { value: 'TRAIN', label: 'Tren' }, - { value: 'SHIP', label: 'Marítimo' }, - { value: 'AIR', label: 'Aéreo' }, - { value: 'OTHER', label: 'Otro' } - ]; - - function addLogistic() { - formData = [...formData, { - carrier_id: '', - transport_type: null, - driver_name: '', - vehicle_num: '', - license_plate: '' - }]; - } function loadInfo() { // Función para cargar información @@ -136,14 +83,18 @@
- transportMode = value || 'TRUCK'}> + formData.transport_mode = value || 'TRUCK'} + > - {transportModes.find(m => m.value === transportMode)?.label || 'Seleccionar modo'} + {transportModes.find(m => m.key === formData.transport_mode)?.name || 'Seleccionar modo'} {#each transportModes as mode} - - {mode.label} + + {mode.name} {/each} @@ -154,7 +105,7 @@
- + @@ -165,7 +116,11 @@
- + formData.is_mixed = v === 'yes'} + class="flex gap-4" + >
@@ -179,7 +134,7 @@
- +
@@ -188,8 +143,8 @@