Merge branch 'feature/facturas' into development
This commit is contained in:
34
backend/api/v1/modules/a24/fa/fa_item_lines/models.py
Normal file
34
backend/api/v1/modules/a24/fa/fa_item_lines/models.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from typing import Optional
|
||||
from sqlalchemy import Boolean, ForeignKey, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from core.database import Base
|
||||
|
||||
class LineItem(Base):
|
||||
__tablename__ = "line_items"
|
||||
__table_args__ = (
|
||||
{"schema": "a24"}
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_id: Mapped[int] = mapped_column(ForeignKey("a76.items.id"))
|
||||
|
||||
# Asset information (SCAF specific)
|
||||
asset_number: Mapped[Optional[str]] = mapped_column(String(25)) # ASSETNUMBER
|
||||
asset_photo: Mapped[Optional[str]] = mapped_column(String(255)) # FOTOACTIVOFIJO
|
||||
equipment_message: Mapped[Optional[str]] = mapped_column(String(40)) # EQI_MENSAJE
|
||||
invoice_type_asset: Mapped[Optional[str]] = mapped_column(String(6)) # TIPOFACTURAASSET
|
||||
return_import_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURAIMPORET
|
||||
return_import_date: Mapped[Optional[int]] = mapped_column(Integer) # FECHAFACIMPORET
|
||||
movement_type_import: Mapped[Optional[str]] = mapped_column(String(3)) # TIPOMOVIMPO
|
||||
|
||||
# Cross-references IN CASE OF IMPORT REPAIR
|
||||
search_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURAEXPO (when line is import) / FACTURAIMPO (when line is export)
|
||||
search_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEAEXPO (when line is import) / LINEAIMPO (when line is export)
|
||||
|
||||
# Search type
|
||||
search_type: Mapped[Optional[str]] = mapped_column(String(10)) # TIPOBUSQUEDA
|
||||
|
||||
# Special flags
|
||||
download: Mapped[Optional[bool]] = mapped_column(Boolean) # DESCARGA
|
||||
own_equipment: Mapped[Optional[bool]] = mapped_column(Boolean) # EQUIPOPROPIO
|
||||
omit_annex31: Mapped[Optional[bool]] = mapped_column(Boolean) # OMITITENANEXO31
|
||||
@@ -10,74 +10,98 @@ from ....common.base_models import TenantScopedMixin, TimestampMixin
|
||||
class OperationType(str, Enum):
|
||||
IMP = "imp" # Importación
|
||||
EXP = "exp" # Exportación
|
||||
SM_IN = "sm_in" # Entrada SM
|
||||
SM_OUT = "sm_out" # Salida SM
|
||||
CTM_SEND = "ctm_send" # Envío CTM
|
||||
CTM_RECEIVE = "ctm_receive" # Recibo CTM
|
||||
|
||||
|
||||
class TransportType(str, Enum):
|
||||
NONE = "none" # Ninguno
|
||||
TRANSPORT = "transport" # Transporte
|
||||
BOX = "box" # Caja
|
||||
PLATES = "licence plates" # Placas
|
||||
TRUCK = "truck" # Camión
|
||||
VESSEL = "vessel" # Buque
|
||||
BARGE = "rail barge" # Ferrobarcaza
|
||||
CONTAINER = "container" # Contenedor
|
||||
AIRPLANE = "airplane" # Avión
|
||||
GONDOLA = "gondola" # Góndola
|
||||
FLATBED = "flatbed" # Plataforma
|
||||
NONE = "none"
|
||||
TRANSPORT = "transport"
|
||||
BOX = "box"
|
||||
PLATES = "licence plates"
|
||||
TRUCK = "truck"
|
||||
VESSEL = "vessel"
|
||||
BARGE = "rail barge"
|
||||
CONTAINER = "container"
|
||||
AIRPLANE = "airplane"
|
||||
GONDOLA = "gondola"
|
||||
FLATBED = "flatbed"
|
||||
|
||||
|
||||
# --- 1. Invoice Header (invoice_header) ---
|
||||
class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin):
|
||||
__tablename__ = "invoice_header"
|
||||
__table_args__ = (
|
||||
{"schema": "a76"},
|
||||
)
|
||||
__table_args__ = ({"schema": "a76"},)
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BigInteger, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
|
||||
# Identifiers
|
||||
operation_type: Mapped[OperationType] = mapped_column(
|
||||
String(3)) # TIPOMOVIMIENTO / Clasifica imp/exp
|
||||
invoice_type: Mapped[Optional[str]] = mapped_column(ForeignKey(
|
||||
"public.invoice_types.key")) # TIPOFACTURA (invoice_types)
|
||||
invoice_number: Mapped[Optional[str]] = mapped_column(
|
||||
String(20)) # FACTURAIMPO/FACTURAEXPO/FACTURAREMISION
|
||||
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)
|
||||
system: Mapped[Optional[str]] = mapped_column(String(10)) # 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
|
||||
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
|
||||
alternate_invoice: Mapped[Optional[str]] = mapped_column(String(99)) # FACTURAALTERNA
|
||||
invoice_ref: Mapped[Optional[str]] = mapped_column(String(19)) # FACTURAEXPOREF
|
||||
proforma_number: Mapped[Optional[str]] = mapped_column(String(20)) # NUMEROPROFORMA
|
||||
|
||||
# Dates
|
||||
invoice_date: Mapped[Optional[datetime]
|
||||
] = mapped_column(Date) # FECHAFACTURA
|
||||
capture_date: Mapped[datetime] = mapped_column(
|
||||
TIMESTAMP(timezone=False), default=datetime.now) # FECHACAPTURA + HORAACTUAL
|
||||
invoice_date: Mapped[Optional[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[str]] = mapped_column(Boolean) # ESTATUS
|
||||
updated_date: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP(timezone=False)) # FECHAACTUALIZACION
|
||||
who_updated: Mapped[Optional[str]] = mapped_column(String(20)) # QUIENA ACTUALIZO
|
||||
|
||||
is_updated: Mapped[Optional[bool]] = mapped_column(Boolean) # ESTATUS
|
||||
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
|
||||
|
||||
# Comments
|
||||
observation_es: Mapped[Optional[str]] = mapped_column(Text) #OBSERVACIONE
|
||||
observation_en: Mapped[Optional[str]] = mapped_column(Text) #OBSERVACIONI
|
||||
comments_status: Mapped[Optional[str]] = mapped_column(Text) #COMENTARIOSESTATUS
|
||||
# Comments
|
||||
observation_es: Mapped[Optional[str]] = mapped_column(Text) # OBSERVACIONE / Observaciones en español
|
||||
observation_en: Mapped[Optional[str]] = mapped_column(Text) # OBSERVACIONI / Observaciones en inglés
|
||||
comments_status: Mapped[Optional[str]] = mapped_column(Text) # COMENTARIOSESTATUS
|
||||
vu_observations: Mapped[Optional[str]] = mapped_column(String(500)) # OBSERVACIONESVU / Observaciones VUCEM
|
||||
|
||||
# Digital Archive Links
|
||||
cfdi_uuid: Mapped[Optional[str]] = mapped_column(String(100)) # CFDIUUID
|
||||
path_pdf: Mapped[Optional[str]] = mapped_column(String(500)) # CFDIPATHPDF
|
||||
path_xml: Mapped[Optional[str]] = mapped_column(String(500)) # CFDIPATHXML
|
||||
|
||||
# Relationships (Para navegacion ORM)
|
||||
compliance_mx: Mapped["InvoiceComplianceMx"] = relationship(
|
||||
back_populates="header", cascade="all, delete-orphan")
|
||||
financials: Mapped["InvoiceFinancials"] = relationship(
|
||||
back_populates="header", cascade="all, delete-orphan")
|
||||
# Control & Subcompany
|
||||
subcompany: Mapped[Optional[str]] = mapped_column(String(5)) # SUBEMPRESA
|
||||
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_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
|
||||
|
||||
# Bulk & Downloads
|
||||
is_bulk: Mapped[Optional[bool]] = mapped_column(Boolean) # ESAGRANEL / Es a granel
|
||||
download_substance: Mapped[Optional[bool]] = mapped_column(Boolean) # DESCARGASUST / Descarga de sustancia
|
||||
download_class: Mapped[Optional[bool]] = mapped_column(Boolean) # DESCARGACLASE / Descarga de clase
|
||||
download_def: Mapped[Optional[bool]] = mapped_column(Boolean) # DESCARGADEF / Descarga definitiva
|
||||
|
||||
# Additional fields
|
||||
payment_terms: Mapped[Optional[str]] = mapped_column(String(200)) # TERMINOSPAGO / Términos de pago
|
||||
handling_fees: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # MANIOBRAS
|
||||
option_iv18: Mapped[Optional[str]] = mapped_column(String(50)) # OPCIONIV18
|
||||
enajenation_goods: Mapped[Optional[bool]] = mapped_column(Boolean) # ENAJENACIONBIENES / Enajenación de bienes
|
||||
|
||||
# Relationships
|
||||
compliance_mx: Mapped[Optional["InvoiceComplianceMx"]] = relationship(
|
||||
back_populates="header", cascade="all, delete-orphan", uselist=False)
|
||||
financials: Mapped[Optional["InvoiceFinancials"]] = relationship(
|
||||
back_populates="header", cascade="all, delete-orphan", uselist=False)
|
||||
details: Mapped[List["InvoiceSalesDetails"]] = relationship(
|
||||
back_populates="header", cascade="all, delete-orphan")
|
||||
collections: Mapped[List["InvoiceCollections"]] = relationship(
|
||||
@@ -89,79 +113,150 @@ class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin):
|
||||
# --- 2. Compliance MX (invoice_compliance_mx) ---
|
||||
class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin):
|
||||
__tablename__ = "invoice_compliance_mx"
|
||||
__table_args__ = (
|
||||
{"schema": "a76"},
|
||||
)
|
||||
__table_args__ = ({"schema": "a76"},)
|
||||
|
||||
invoice_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("a76.invoice_header.id"), primary_key=True)
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"), primary_key=True)
|
||||
|
||||
# Core Customs Data
|
||||
pedimento: Mapped[Optional[str]] = mapped_column(
|
||||
String(19)) # PEDIMENTO/PEDIMENTOIMPO/EXPO
|
||||
pedimento_code: Mapped[Optional[str]] = mapped_column(
|
||||
String(5)) # PEDIMENTOR1, K1
|
||||
remesa: Mapped[Optional[int]] = mapped_column(Integer)
|
||||
pedimento: Mapped[Optional[str]] = mapped_column(String(19)) # PEDIMENTO/PEDIMENTOIMPO/EXPO
|
||||
pedimento_code: Mapped[Optional[str]] = mapped_column(String(5)) # PEDIMENTOR1
|
||||
pedimento_k1: Mapped[Optional[str]] = mapped_column(String(15)) # PEDIMENTOK1
|
||||
remesa: Mapped[Optional[int]] = mapped_column(Integer) # REMESA
|
||||
aduana: Mapped[Optional[str]] = mapped_column(ForeignKey("public.customs_sections.customs_code")) # ADUANA_CRUCE
|
||||
port_of_entry: Mapped[Optional[str]] = mapped_column(String(6)) # PUERTOENTRADA / Puerto de entrada
|
||||
destination: Mapped[Optional[str]] = mapped_column(String(3)) # DESTINO / Código de destino
|
||||
manifest_number: Mapped[Optional[str]] = mapped_column(String(15)) # MANIFIESTO / Número de manifiesto
|
||||
|
||||
# Clients & Providers
|
||||
provider_header: Mapped[Optional[str]] = mapped_column(String(20)) # PROVEEDOREXPORTADOR
|
||||
provider_header: Mapped[Optional[str]] = mapped_column(String(20)) # PROVEEDOREXPORTADOR
|
||||
provider_id: Mapped[Optional[str]] = 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
|
||||
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[str]] = 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
|
||||
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
|
||||
|
||||
customs_broker_id: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.customs_brokers.id")) # AADUANAL
|
||||
# Broker Invoice
|
||||
broker_invoice_num: Mapped[Optional[str]] = mapped_column(String(20)) # NUMFACTURABROKER / Número factura broker
|
||||
broker_invoice_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAFACBROKER / Fecha factura broker
|
||||
|
||||
# Flags & Specific Regimes
|
||||
is_mixed: Mapped[Optional[bool]] = mapped_column(Boolean) # ESMIXTO
|
||||
waste_type: Mapped[Optional[str]] = mapped_column(String(1)) # TIPODESPERDICIO
|
||||
appendix_17: Mapped[Optional[int]] = mapped_column(Integer) # APENDICE17
|
||||
is_mixed: Mapped[Optional[bool]] = mapped_column(Boolean) # ESMIXTO / Es mixto
|
||||
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
|
||||
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
|
||||
was_reviewed_by_company: Mapped[Optional[bool]] = mapped_column(Boolean) # FUEREVISADAMCIA / Fue revisada por la compañía
|
||||
|
||||
# VUCEM / Digital
|
||||
edocument: Mapped[Optional[str]] = mapped_column(String(50)) # EDOCUMENT
|
||||
electronic_signature: Mapped[Optional[str]] = mapped_column(String(999)) # FIRMAELECTRONICA
|
||||
sem_id: Mapped[Optional[int]] = mapped_column(Integer) # SEM (de SFacEntradaSM/SFacSalidaSM)
|
||||
edocument: Mapped[Optional[str]] = mapped_column(String(50)) # EDOCUMENT / Documento electrónico
|
||||
electronic_signature: Mapped[Optional[str]] = mapped_column(String(999)) # FIRMAELECTRONICA / Firma electrónica
|
||||
certificate_number: Mapped[Optional[str]] = mapped_column(String(99)) # NUMEROCERTIFICADO / Número de certificado
|
||||
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
|
||||
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
|
||||
|
||||
# Additional Control
|
||||
contingency_mode: Mapped[Optional[bool]] = mapped_column(Boolean) # MODOCONTINGENCIA / Modo contingencia
|
||||
enclosure: Mapped[Optional[str]] = mapped_column(String(4)) # RECINTO / Recinto fiscal
|
||||
guide_type_to_identify: Mapped[Optional[str]] = mapped_column(String(1)) # TIPODEGUIAAIDENTIFICAR / Tipo de guía a identificar
|
||||
location: Mapped[Optional[str]] = mapped_column(String(200)) # LOCALIZACION / Localización
|
||||
|
||||
# DOT & Official
|
||||
dot_code: Mapped[Optional[str]] = mapped_column(String(20)) # CLAVEDOT / Clave DOT
|
||||
subdivision: Mapped[Optional[str]] = mapped_column(String(20)) # SUBDIVISION / Subdivisión
|
||||
acts_as: Mapped[Optional[str]] = mapped_column(String(20)) # FUNGECOMOCO / Funge como
|
||||
movement_type: Mapped[Optional[str]] = mapped_column(String(31)) # TIPOMOV / Tipo de movimiento
|
||||
office_document: Mapped[Optional[str]] = mapped_column(String(30)) # OFICIO / Oficio
|
||||
reason_export: Mapped[Optional[str]] = mapped_column(String(1)) # RAZONEXPORTACION / Razón de exportación
|
||||
signature_key: Mapped[Optional[str]] = mapped_column(String(10)) # CLAVEFIRMA / Clave de firma
|
||||
|
||||
# SM specific
|
||||
sem_id: Mapped[Optional[int]] = mapped_column(Integer) # SEM / ID SEM (de SFacEntradaSM/SFacSalidaSM)
|
||||
|
||||
# Relationship
|
||||
header: Mapped["InvoiceHeader"] = relationship(
|
||||
back_populates="compliance_mx")
|
||||
header: Mapped["InvoiceHeader"] = relationship(back_populates="compliance_mx")
|
||||
|
||||
|
||||
# --- 3. Financials (invoice_financials) ---
|
||||
class InvoiceFinancials(Base, TenantScopedMixin, TimestampMixin):
|
||||
__tablename__ = "invoice_financials"
|
||||
__table_args__ = (
|
||||
{"schema": "a76"},
|
||||
)
|
||||
__table_args__ = ({"schema": "a76"},)
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BigInteger, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))
|
||||
|
||||
currency: Mapped[Optional[str]] = mapped_column(String(3)) # CLAVEMONEDA
|
||||
currency_type: Mapped[Optional[str]] = mapped_column(ForeignKey("public.currency_types.code")) # TIPOCLAVEMONEDA
|
||||
exchange_rate: Mapped[Optional[float]] = mapped_column(Numeric(13, 6)) # TIPOCAMBIO
|
||||
# Currency
|
||||
currency: Mapped[Optional[str]] = mapped_column(String(3)) # 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
|
||||
|
||||
# Merchandise Values
|
||||
value_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORIMPOMN/EXPOMN
|
||||
value_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0)
|
||||
customs_value_mn: Mapped[Optional[float]] = mapped_column( Numeric(23, 8), default=0) # VALORADUANASMN
|
||||
# Merchandise Values (MN = National Currency, ME = Foreign Currency, MC = Third Currency)
|
||||
value_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORIMPOMN/VALOREXPOMN/VALORENTMN/VALORSALMN
|
||||
value_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORIMPOME/VALOREXPOME/VALORENTME/VALORSALME
|
||||
value_mc: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORIMPOMC/VALOREXPOMC
|
||||
|
||||
# Customs Value
|
||||
customs_value_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORADUANASMN / Valor en aduanas MN
|
||||
customs_value_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORADUANASME / Valor en aduanas ME
|
||||
|
||||
# Costs & Taxes
|
||||
freight: Mapped[Optional[float]] = mapped_column(Numeric(19, 8), default=0) # FLETE
|
||||
insurance: Mapped[Optional[float]] = mapped_column(Numeric(19, 8), default=0) # VALSEGUROS/SEGUROS
|
||||
iva_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # IVAEXPOMN / VALORIVAMN
|
||||
iva_factor: Mapped[Optional[float]] = mapped_column(Numeric(17, 4)) # FACTORIVA
|
||||
# Raw Materials
|
||||
raw_material_value_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORMPMN / Valor materia prima MN
|
||||
raw_material_value_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORMPME / Valor materia prima ME
|
||||
|
||||
# Aggregate Value
|
||||
aggregate_value_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORAGREMN / Valor agregado MN
|
||||
aggregate_value_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORAGREME / Valor agregado ME
|
||||
aggregate_value_mc: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORAGREMC / Valor agregado MC
|
||||
|
||||
# Mexican Merchandise Value
|
||||
mexican_value_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORVMEXMN / Valor mercancía mexicana MN
|
||||
mexican_value_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORVMEXME / Valor mercancía mexicana ME
|
||||
mexican_value_mc: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORVMEXMC / Valor mercancía mexicana MC
|
||||
|
||||
# National Packaging
|
||||
national_packaging_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALEMPAQUENACMN / Valor empaque nacional MN
|
||||
national_packaging_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALEMPAQUENACME / Valor empaque nacional ME
|
||||
national_packaging_mc: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALEMPAQUENACMC / Valor empaque nacional MC
|
||||
|
||||
# Costs & Increments
|
||||
freight: Mapped[Optional[float]] = mapped_column(Numeric(19, 8), default=0) # FLETE / Flete
|
||||
insurance: Mapped[Optional[float]] = mapped_column(Numeric(19, 8), default=0) # SEGUROS / Seguros
|
||||
insurance_value: Mapped[Optional[float]] = mapped_column(Numeric(19, 8), default=0) # VALSEGUROS / Valor seguros
|
||||
packaging: Mapped[Optional[float]] = mapped_column(Numeric(19, 8), default=0) # EMBALAJES / Embalajes
|
||||
other_increments: Mapped[Optional[float]] = mapped_column(Numeric(19, 8), default=0) # OTROSINCREMENTA / Otros incrementables
|
||||
total_increments_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # TOTALINCREMMN / Total incrementables MN
|
||||
total_increments_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # TOTALINCREMME / Total incrementables ME
|
||||
|
||||
# Taxes
|
||||
iva_mn: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # IVAEXPOMN/VALORIVAMN / IVA en MN
|
||||
iva_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # IVAEXPOME/VALORIVAME / IVA en ME
|
||||
iva_mc: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # IVAEXPOMC / IVA en MC
|
||||
iva_factor: Mapped[Optional[str]] = mapped_column(String(10)) # FACTORIVA / Factor IVA (puede ser varchar en imports)
|
||||
tax_value_me: Mapped[Optional[float]] = mapped_column(Numeric(23, 8), default=0) # VALORIMPUESTOME / Valor impuesto ME
|
||||
seal_value_2500: Mapped[Optional[bool]] = mapped_column(Boolean) # SELLOVALOR2500 / Sello valor 2500
|
||||
|
||||
# Weights & Quantities
|
||||
total_quantity: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # CANTEXPO / CANTIMPO
|
||||
gross_weight: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # PESOBRUTO
|
||||
net_weight: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # PESONETO
|
||||
bundle_count: Mapped[Optional[int]] = mapped_column(Integer) # CANTBULTOS
|
||||
total_quantity: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # CANTEXPO/CANTIMPO / Cantidad total
|
||||
gross_weight: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # PESOBRUTO / Peso bruto
|
||||
net_weight: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # PESONETO / Peso neto
|
||||
bundle_count: Mapped[Optional[int]] = mapped_column(Integer) # CANTBULTOS / Cantidad de bultos
|
||||
weight_factor: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # FACTORPESO / Factor de peso
|
||||
|
||||
# Relationship
|
||||
header: Mapped["InvoiceHeader"] = relationship(back_populates="financials")
|
||||
@@ -170,38 +265,67 @@ class InvoiceFinancials(Base, TenantScopedMixin, TimestampMixin):
|
||||
# --- 4. Logistics (invoice_logistics) ---
|
||||
class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin):
|
||||
__tablename__ = "invoice_logistics"
|
||||
__table_args__ = (
|
||||
{"schema": "a76"},
|
||||
)
|
||||
__table_args__ = ({"schema": "a76"},)
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BigInteger, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))
|
||||
|
||||
# Carrier Info
|
||||
carrier_id: Mapped[Optional[str]] = mapped_column(
|
||||
String(10)) # TRANSPORTISTA
|
||||
transport_type: Mapped[TransportType] = mapped_column(
|
||||
String(15), default="none") # TRANSPORTE
|
||||
transport_mode: Mapped[Optional[str]] = mapped_column(
|
||||
String(15)) # MODTRANS
|
||||
driver_name: Mapped[Optional[str]] = mapped_column(String(80)) # CONDUCTOR
|
||||
is_rail: Mapped[Optional[str]] = mapped_column(String(2)) # ESFERROCARRIL
|
||||
rail_id: Mapped[Optional[str]] = mapped_column(
|
||||
String(31)) # IDFERRORCARRIL
|
||||
# Carrier Info
|
||||
carrier_id: Mapped[Optional[str]] = mapped_column(String(10)) # TRANSPORTISTA / Transportista
|
||||
transport_id: Mapped[Optional[str]] = mapped_column(String(10)) # NUMTRAILER / Transportista
|
||||
transport_us_id: Mapped[Optional[str]] = mapped_column(String(10)) # TRANSPORTISTAAME / Transportista americano
|
||||
transport_type: Mapped[TransportType] = mapped_column(String(15), default="none") # TRANSPORTE / Tipo de transporte
|
||||
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
|
||||
rail_id: Mapped[Optional[str]] = mapped_column(String(31)) # IDFERRORCARRIL / ID ferrocarril
|
||||
|
||||
# Vehicle & Tracking
|
||||
vehicle_num: Mapped[Optional[str]] = mapped_column(
|
||||
String(20)) # NUMVEHICULO / NUMTRAILER
|
||||
license_plate: Mapped[Optional[str]] = mapped_column(
|
||||
String(20)) # NUMTRASPORTE
|
||||
seal_number: Mapped[Optional[str]] = mapped_column(String(15)) # PRECINTO
|
||||
guide_number: Mapped[Optional[str]] = mapped_column(
|
||||
String(20)) # NUMEROGUIA
|
||||
vehicle_num: Mapped[Optional[str]] = mapped_column(String(20)) # NUMVEHICULO / Número de vehículo
|
||||
license_plate: Mapped[Optional[str]] = mapped_column(String(20)) # NUMTRASPORTE / Número de transporte/placa
|
||||
license_plate_complete: Mapped[Optional[str]] = mapped_column(String(40)) # NUMTRASPORTECOMPLE / Número transporte completo
|
||||
trailer_num: Mapped[Optional[str]] = mapped_column(String(20)) # NUMTRAILER / Número de trailer
|
||||
seal_number: Mapped[Optional[str]] = mapped_column(String(15)) # PRECINTO / Precinto
|
||||
guide_number: Mapped[Optional[str]] = mapped_column(String(20)) # NUMEROGUIA / Número de guía
|
||||
bill_number: Mapped[Optional[str]] = mapped_column(String(15)) # BILLNUMBER / Número de bill
|
||||
reference_number: Mapped[Optional[str]] = mapped_column(String(14)) # NUMREFERENCIA / Número de referencia
|
||||
shipment_number: Mapped[Optional[str]] = mapped_column(String(19)) # NUMEMBARQUE / Número de embarque
|
||||
|
||||
# Incoterms
|
||||
incoterm: Mapped[Optional[str]] = mapped_column(String(5)) # INCOTERM / Término de comercio internacional
|
||||
|
||||
# Identifiers & Complements
|
||||
identifier_1: Mapped[Optional[str]] = mapped_column(String(2)) # IDENTIFICADOR / Identificador 1
|
||||
complement_1: Mapped[Optional[str]] = mapped_column(String(30)) # COMPLEMENTO1 / Complemento 1
|
||||
identifier_2: Mapped[Optional[str]] = mapped_column(String(2)) # IDENTIFICADOR2 / Identificador 2
|
||||
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
|
||||
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
|
||||
|
||||
# Locations & Routes
|
||||
origin_location: Mapped[Optional[str]] = mapped_column(String(200)) # ORIGENUBICACION / Ubicación de origen
|
||||
destination_location: Mapped[Optional[str]] = mapped_column(String(200)) # DESTINOUBICACION / Ubicación de destino
|
||||
transport_itinerary: Mapped[Optional[str]] = mapped_column(String(1000)) # ITINERARIOTRANPORTE / Itinerario del transporte
|
||||
destination_goods: Mapped[Optional[str]] = mapped_column(String(50)) # DESTINOMCIA / Destino de mercancía
|
||||
|
||||
# Logistics Dates
|
||||
entry_exit_date: Mapped[Optional[datetime]] = mapped_column(
|
||||
Date) # FECHAENTRADA / FECHAENVIO
|
||||
entry_exit_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAENTRADA/FECHAENVIO/FECHARECIBO / Fecha entrada/salida
|
||||
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
|
||||
received_by: Mapped[Optional[str]] = mapped_column(String(50)) # RECIBIDOPOR / Recibido por
|
||||
|
||||
# Payment Info
|
||||
payment_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAPAGO / Fecha de pago
|
||||
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
|
||||
|
||||
# Relationship
|
||||
header: Mapped["InvoiceHeader"] = relationship(back_populates="logistics")
|
||||
@@ -210,25 +334,18 @@ class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin):
|
||||
# --- 5. Sales Order Details (invoice_sales_details) ---
|
||||
class InvoiceSalesDetails(Base, TenantScopedMixin, TimestampMixin):
|
||||
__tablename__ = "invoice_sales_details"
|
||||
__table_args__ = (
|
||||
{"schema": "a76"},
|
||||
)
|
||||
__table_args__ = ({"schema": "a76"},)
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BigInteger, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))
|
||||
|
||||
line_number: Mapped[int] = mapped_column(Integer) # LINEA
|
||||
sales_order: Mapped[Optional[str]] = mapped_column(
|
||||
String(20)) # ORDENVENTA
|
||||
line_number: Mapped[int] = mapped_column(Integer) # LINEA / Número de línea
|
||||
sales_order: Mapped[Optional[str]] = mapped_column(String(20)) # ORDENVENTA / Orden de venta
|
||||
|
||||
# Specific Custom Fields
|
||||
colors_description: Mapped[Optional[str]
|
||||
] = mapped_column(String(49)) # COLORES
|
||||
square_color_code: Mapped[Optional[str]] = mapped_column(
|
||||
String(1)) # COLORCUADRITO
|
||||
line_bundles: Mapped[Optional[int]] = mapped_column(
|
||||
Integer) # CANTBULTOS (de la linea)
|
||||
colors_description: Mapped[Optional[str]] = mapped_column(String(49)) # COLORES / Descripción de colores
|
||||
square_color_code: Mapped[Optional[str]] = mapped_column(String(1)) # COLORCUADRITO / Código de color cuadrito
|
||||
line_bundles: Mapped[Optional[int]] = mapped_column(Integer) # CANTBULTOS / Cantidad de bultos de la línea
|
||||
|
||||
# Relationship
|
||||
header: Mapped["InvoiceHeader"] = relationship(back_populates="details")
|
||||
@@ -237,23 +354,15 @@ class InvoiceSalesDetails(Base, TenantScopedMixin, TimestampMixin):
|
||||
# --- 6. Collections (invoice_collections) ---
|
||||
class InvoiceCollections(Base, TenantScopedMixin, TimestampMixin):
|
||||
__tablename__ = "invoice_collections"
|
||||
__table_args__ = (
|
||||
{"schema": "a76"},
|
||||
)
|
||||
__table_args__ = ({"schema": "a76"},)
|
||||
|
||||
id: Mapped[int] = mapped_column(
|
||||
BigInteger, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))
|
||||
|
||||
concept: Mapped[Optional[str]] = mapped_column(String(100)) # CONCEPTO
|
||||
is_collected: Mapped[Optional[int]] = mapped_column(Integer) # COBRADO
|
||||
collection_date: Mapped[Optional[datetime]
|
||||
] = mapped_column(Date) # FECHACOBRANZA
|
||||
amount: Mapped[Optional[float]] = mapped_column(Numeric(23, 8)) # VALOR
|
||||
|
||||
collector_user: Mapped[Optional[str]] = mapped_column(
|
||||
String(20)) # FACTCOBRADOR
|
||||
|
||||
line_number: Mapped[int] = mapped_column(Integer) # LINEA / Número de línea
|
||||
invoice_number: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURA / Número de factura
|
||||
concept: Mapped[Optional[str]] = mapped_column(String(100)) # CONCEPTO / Concepto
|
||||
|
||||
# Relationship
|
||||
header: Mapped["InvoiceHeader"] = relationship(
|
||||
back_populates="collections")
|
||||
header: Mapped["InvoiceHeader"] = relationship(back_populates="collections")
|
||||
concept: Mapped[Optional[str]] = mapped_column(String(100)) # CONCEPTO / Conce
|
||||
@@ -8,8 +8,10 @@ from .models import OperationType
|
||||
# --- Base Schemas ---
|
||||
class InvoiceHeaderBase(BaseModel):
|
||||
"""Base fields for Invoice Header"""
|
||||
system: Optional[str] = Field(
|
||||
None, max_length=10, description="System of origin")
|
||||
operation_type: Optional[OperationType] = Field(
|
||||
None, max_length=20, description="Operation type: imp/exp")
|
||||
None, max_length=10, description="Operation type: imp/exp/sm/ctm")
|
||||
invoice_type: Optional[str] = Field(
|
||||
None, max_length=5, description="Invoice type key")
|
||||
invoice_number: Optional[str] = Field(
|
||||
@@ -20,20 +22,64 @@ class InvoiceHeaderBase(BaseModel):
|
||||
None, max_length=50, description="Purchase order")
|
||||
related_doc_id: Optional[int] = Field(
|
||||
None, description="Related document ID for rectifications")
|
||||
alternate_invoice: Optional[str] = Field(
|
||||
None, max_length=99, description="Alternate invoice")
|
||||
invoice_ref: Optional[str] = Field(
|
||||
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")
|
||||
emission_date: Optional[date] = Field(None, description="Emission date")
|
||||
is_updated: Optional[bool] = Field(None, description="Status")
|
||||
updated_date: Optional[datetime] = Field(None, description="Update date")
|
||||
who_updated: Optional[str] = Field(
|
||||
None, max_length=20, description="Who updated")
|
||||
capture_user: Optional[str] = Field(
|
||||
None, max_length=20, description="Capture user")
|
||||
traffic_light_status: Optional[str] = Field(
|
||||
None, max_length=50, description="Traffic light status (SEMAFORO)")
|
||||
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(
|
||||
None, max_length=2, description="Report status")
|
||||
observation_es: Optional[str] = Field(
|
||||
None, description="Observations in Spanish")
|
||||
observation_en: Optional[str] = Field(
|
||||
None, description="Observations in English")
|
||||
comments_status: Optional[str] = Field(
|
||||
None, description="Comments and observations")
|
||||
None, description="Comments status")
|
||||
vu_observations: Optional[str] = Field(
|
||||
None, max_length=500, description="VUCEM observations")
|
||||
cfdi_uuid: Optional[str] = Field(
|
||||
None, max_length=100, description="CFDI UUID")
|
||||
path_pdf: Optional[str] = Field(
|
||||
None, max_length=500, description="Path to PDF file")
|
||||
path_xml: Optional[str] = Field(
|
||||
None, max_length=500, description="Path to XML file")
|
||||
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_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")
|
||||
is_bulk: Optional[bool] = Field(None, description="Is bulk")
|
||||
download_substance: Optional[bool] = Field(
|
||||
None, description="Download substance")
|
||||
download_class: Optional[bool] = Field(
|
||||
None, description="Download class")
|
||||
download_def: Optional[bool] = Field(
|
||||
None, description="Definitive download")
|
||||
payment_terms: Optional[str] = Field(
|
||||
None, max_length=200, description="Payment terms")
|
||||
handling_fees: Optional[Decimal] = Field(None, description="Handling fees")
|
||||
option_iv18: Optional[str] = Field(
|
||||
None, max_length=50, description="Option IV18")
|
||||
enajenation_goods: Optional[bool] = Field(
|
||||
None, description="Enajenation of goods")
|
||||
|
||||
|
||||
class InvoiceComplianceMxBase(BaseModel):
|
||||
@@ -41,21 +87,105 @@ class InvoiceComplianceMxBase(BaseModel):
|
||||
pedimento: Optional[str] = Field(
|
||||
None, max_length=19, description="Pedimento number")
|
||||
pedimento_code: Optional[str] = Field(
|
||||
None, max_length=5, description="Pedimento code (R1/K1)")
|
||||
None, max_length=5, description="Pedimento code (R1)")
|
||||
pedimento_k1: Optional[str] = Field(
|
||||
None, max_length=15, description="Pedimento K1")
|
||||
remesa: Optional[int] = Field(None, description="Remesa")
|
||||
aduana: Optional[str] = Field(
|
||||
None, max_length=5, description="Customs office")
|
||||
customs_agent: Optional[str] = Field(
|
||||
None, max_length=10, description="Customs agent")
|
||||
port_of_entry: Optional[str] = Field(
|
||||
None, max_length=6, description="Port of entry")
|
||||
destination: Optional[str] = Field(
|
||||
None, max_length=3, description="Destination code")
|
||||
manifest_number: Optional[str] = Field(
|
||||
None, max_length=15, description="Manifest number")
|
||||
provider_header: Optional[str] = Field(
|
||||
None, max_length=20, description="Provider header")
|
||||
provider_id: Optional[str] = Field(
|
||||
None, description="Provider ID")
|
||||
sold_to_header: Optional[str] = Field(
|
||||
None, max_length=20, description="Sold to header")
|
||||
sold_to_id: Optional[str] = Field(
|
||||
None, description="Sold to ID")
|
||||
shipped_to_header: Optional[str] = Field(
|
||||
None, max_length=20, description="Shipped to header")
|
||||
shipped_to_id: Optional[str] = Field(
|
||||
None, description="Shipped to ID")
|
||||
shipped_by_header: Optional[str] = Field(
|
||||
None, max_length=20, description="Shipped by header")
|
||||
shipped_by_id: Optional[str] = Field(
|
||||
None, description="Shipped by ID")
|
||||
customs_broker_id: Optional[str] = Field(
|
||||
None, description="Customs broker ID")
|
||||
customs_broker_us_id: Optional[str] = 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")
|
||||
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")
|
||||
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")
|
||||
was_reviewed_by_company: Optional[bool] = Field(
|
||||
None, description="Was reviewed by company")
|
||||
edocument: Optional[str] = Field(
|
||||
None, max_length=50, description="E-document")
|
||||
electronic_signature: Optional[str] = Field(
|
||||
None, max_length=999, description="Electronic signature")
|
||||
certificate_number: Optional[str] = Field(
|
||||
None, max_length=99, description="Certificate number")
|
||||
niu_number: Optional[str] = Field(
|
||||
None, max_length=19, description="NIU number")
|
||||
bill_of_lading_count: Optional[str] = Field(
|
||||
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")
|
||||
vucem_operation_num: Optional[str] = Field(
|
||||
None, max_length=19, description="VUCEM operation number")
|
||||
customs_person_line: Optional[int] = Field(
|
||||
None, description="Customs person line")
|
||||
contingency_mode: Optional[bool] = Field(
|
||||
None, description="Contingency mode")
|
||||
enclosure: Optional[str] = Field(
|
||||
None, max_length=4, description="Enclosure")
|
||||
guide_type_to_identify: Optional[str] = Field(
|
||||
None, max_length=1, description="Guide type to identify")
|
||||
location: Optional[str] = Field(
|
||||
None, max_length=200, description="Location")
|
||||
dot_code: Optional[str] = Field(
|
||||
None, max_length=20, description="DOT code")
|
||||
subdivision: Optional[str] = Field(
|
||||
None, max_length=20, description="Subdivision")
|
||||
acts_as: Optional[str] = Field(
|
||||
None, max_length=20, description="Acts as")
|
||||
movement_type: Optional[str] = Field(
|
||||
None, max_length=31, description="Movement type")
|
||||
office_document: Optional[str] = Field(
|
||||
None, max_length=30, description="Office document")
|
||||
reason_export: Optional[str] = Field(
|
||||
None, max_length=1, description="Reason for export")
|
||||
signature_key: Optional[str] = Field(
|
||||
None, max_length=10, description="Signature key")
|
||||
sem_id: Optional[int] = Field(None, description="SEM ID")
|
||||
|
||||
|
||||
@@ -63,44 +193,148 @@ class InvoiceFinancialsBase(BaseModel):
|
||||
"""Base fields for Financials"""
|
||||
currency: Optional[str] = Field(
|
||||
None, max_length=3, description="Currency code")
|
||||
currency_type: Optional[str] = Field(
|
||||
None, description="Currency type")
|
||||
exchange_rate: Optional[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")
|
||||
value_me: Optional[Decimal] = Field(
|
||||
None, description="Value in foreign currency")
|
||||
value_mc: Optional[Decimal] = Field(
|
||||
None, description="Value in third currency")
|
||||
customs_value_mn: Optional[Decimal] = Field(
|
||||
None, description="Customs value in MXN")
|
||||
customs_value_me: Optional[Decimal] = Field(
|
||||
None, description="Customs value in foreign currency")
|
||||
raw_material_value_mn: Optional[Decimal] = Field(
|
||||
None, description="Raw material value in MXN")
|
||||
raw_material_value_me: Optional[Decimal] = Field(
|
||||
None, description="Raw material value in foreign currency")
|
||||
aggregate_value_mn: Optional[Decimal] = Field(
|
||||
None, description="Aggregate value in MXN")
|
||||
aggregate_value_me: Optional[Decimal] = Field(
|
||||
None, description="Aggregate value in foreign currency")
|
||||
aggregate_value_mc: Optional[Decimal] = Field(
|
||||
None, description="Aggregate value in third currency")
|
||||
mexican_value_mn: Optional[Decimal] = Field(
|
||||
None, description="Mexican merchandise value in MXN")
|
||||
mexican_value_me: Optional[Decimal] = Field(
|
||||
None, description="Mexican merchandise value in foreign currency")
|
||||
mexican_value_mc: Optional[Decimal] = Field(
|
||||
None, description="Mexican merchandise value in third currency")
|
||||
national_packaging_mn: Optional[Decimal] = Field(
|
||||
None, description="National packaging in MXN")
|
||||
national_packaging_me: Optional[Decimal] = Field(
|
||||
None, description="National packaging in foreign currency")
|
||||
national_packaging_mc: Optional[Decimal] = Field(
|
||||
None, description="National packaging in third currency")
|
||||
freight: Optional[Decimal] = Field(None, description="Freight cost")
|
||||
insurance: Optional[Decimal] = Field(None, description="Insurance cost")
|
||||
insurance_value: Optional[Decimal] = Field(
|
||||
None, description="Insurance value")
|
||||
packaging: Optional[Decimal] = Field(None, description="Packaging")
|
||||
other_increments: Optional[Decimal] = Field(
|
||||
None, description="Other increments")
|
||||
total_increments_mn: Optional[Decimal] = Field(
|
||||
None, description="Total increments in MXN")
|
||||
total_increments_me: Optional[Decimal] = Field(
|
||||
None, description="Total increments in foreign currency")
|
||||
iva_mn: Optional[Decimal] = Field(None, description="IVA in MXN")
|
||||
iva_factor: Optional[Decimal] = Field(None, description="IVA factor")
|
||||
iva_me: Optional[Decimal] = Field(
|
||||
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")
|
||||
tax_value_me: Optional[Decimal] = Field(
|
||||
None, description="Tax value in foreign currency")
|
||||
seal_value_2500: Optional[bool] = Field(
|
||||
None, description="Seal value 2500")
|
||||
total_quantity: Optional[Decimal] = Field(
|
||||
None, description="Total quantity")
|
||||
gross_weight: Optional[Decimal] = Field(None, description="Gross weight")
|
||||
net_weight: Optional[Decimal] = Field(None, description="Net weight")
|
||||
bundle_count: Optional[int] = Field(None, description="Bundle count")
|
||||
weight_factor: Optional[Decimal] = Field(None, description="Weight factor")
|
||||
|
||||
|
||||
class InvoiceLogisticsBase(BaseModel):
|
||||
"""Base fields for Logistics"""
|
||||
carrier_id: Optional[str] = Field(
|
||||
None, max_length=10, description="Carrier ID")
|
||||
transport_id: Optional[str] = Field(
|
||||
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_num: Optional[str] = Field(
|
||||
None, max_length=20, description="Transport number")
|
||||
transport_mode: Optional[str] = Field(
|
||||
None, 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")
|
||||
rail_id: Optional[str] = Field(None, max_length=31, description="Rail ID")
|
||||
rail_id: Optional[str] = Field(
|
||||
None, max_length=31, description="Rail ID")
|
||||
vehicle_num: Optional[str] = Field(
|
||||
None, max_length=20, description="Vehicle number")
|
||||
license_plate: Optional[str] = Field(
|
||||
None, max_length=20, description="License plate")
|
||||
license_plate_complete: Optional[str] = Field(
|
||||
None, max_length=40, description="Complete license plate")
|
||||
trailer_num: Optional[str] = Field(
|
||||
None, max_length=20, description="Trailer number")
|
||||
seal_number: Optional[str] = Field(
|
||||
None, max_length=15, description="Seal number")
|
||||
guide_number: Optional[str] = Field(
|
||||
None, max_length=20, description="Guide number")
|
||||
bill_number: Optional[str] = Field(
|
||||
None, max_length=15, description="Bill number")
|
||||
reference_number: Optional[str] = Field(
|
||||
None, max_length=14, description="Reference number")
|
||||
shipment_number: Optional[str] = Field(
|
||||
None, max_length=19, description="Shipment number")
|
||||
incoterm: Optional[str] = Field(
|
||||
None, max_length=5, description="Incoterm")
|
||||
identifier_1: Optional[str] = Field(
|
||||
None, max_length=2, description="Identifier 1")
|
||||
complement_1: Optional[str] = Field(
|
||||
None, max_length=30, description="Complement 1")
|
||||
identifier_2: Optional[str] = Field(
|
||||
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")
|
||||
container_types: Optional[str] = Field(
|
||||
None, max_length=500, description="Container types")
|
||||
vehicle_data: Optional[str] = Field(
|
||||
None, max_length=500, description="Vehicle data")
|
||||
origin_location: Optional[str] = Field(
|
||||
None, max_length=200, description="Origin location")
|
||||
destination_location: Optional[str] = Field(
|
||||
None, max_length=200, description="Destination location")
|
||||
transport_itinerary: Optional[str] = Field(
|
||||
None, max_length=1000, description="Transport itinerary")
|
||||
destination_goods: Optional[str] = Field(
|
||||
None, max_length=50, description="Destination of goods")
|
||||
entry_exit_date: Optional[date] = Field(
|
||||
None, description="Entry/Exit date")
|
||||
delivery_date: Optional[date] = Field(
|
||||
None, description="Delivery date")
|
||||
delivered_status: Optional[str] = Field(
|
||||
None, max_length=2, description="Delivered status")
|
||||
received_by: Optional[str] = Field(
|
||||
None, max_length=50, description="Received by")
|
||||
payment_date: Optional[date] = Field(
|
||||
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")
|
||||
|
||||
|
||||
class InvoiceSalesDetailsBase(BaseModel):
|
||||
@@ -117,13 +351,10 @@ class InvoiceSalesDetailsBase(BaseModel):
|
||||
|
||||
class InvoiceCollectionsBase(BaseModel):
|
||||
"""Base fields for Collections"""
|
||||
line_number: int = Field(..., description="Line number")
|
||||
invoice_number: Optional[str] = Field(
|
||||
None, max_length=15, description="Invoice number")
|
||||
concept: Optional[str] = Field(None, max_length=100, description="Concept")
|
||||
is_collected: Optional[int] = Field(None, description="Is collected flag")
|
||||
collection_date: Optional[date] = Field(
|
||||
None, description="Collection date")
|
||||
amount: Optional[Decimal] = Field(None, description="Amount")
|
||||
collector_user: Optional[str] = Field(
|
||||
None, max_length=20, description="Collector user")
|
||||
|
||||
|
||||
# --- Create Schemas ---
|
||||
@@ -186,7 +417,7 @@ class InvoiceSalesDetailsUpdate(InvoiceSalesDetailsBase):
|
||||
|
||||
class InvoiceCollectionsUpdate(InvoiceCollectionsBase):
|
||||
"""Schema for updating Collections"""
|
||||
pass
|
||||
line_number: Optional[int] = None
|
||||
|
||||
|
||||
class InvoiceHeaderUpdate(InvoiceHeaderBase):
|
||||
@@ -210,6 +441,7 @@ class InvoiceComplianceMxResponse(InvoiceComplianceMxBase):
|
||||
|
||||
class InvoiceFinancialsResponse(InvoiceFinancialsBase):
|
||||
"""Schema for Financials response"""
|
||||
id: int
|
||||
invoice_id: int
|
||||
|
||||
class Config:
|
||||
@@ -218,7 +450,7 @@ class InvoiceFinancialsResponse(InvoiceFinancialsBase):
|
||||
|
||||
class InvoiceLogisticsResponse(InvoiceLogisticsBase):
|
||||
"""Schema for Logistics response"""
|
||||
logistics_id: int
|
||||
id: int
|
||||
invoice_id: int
|
||||
|
||||
class Config:
|
||||
@@ -227,7 +459,7 @@ class InvoiceLogisticsResponse(InvoiceLogisticsBase):
|
||||
|
||||
class InvoiceSalesDetailsResponse(InvoiceSalesDetailsBase):
|
||||
"""Schema for Sales Details response"""
|
||||
detail_id: int
|
||||
id: int
|
||||
invoice_id: int
|
||||
|
||||
class Config:
|
||||
@@ -236,7 +468,7 @@ class InvoiceSalesDetailsResponse(InvoiceSalesDetailsBase):
|
||||
|
||||
class InvoiceCollectionsResponse(InvoiceCollectionsBase):
|
||||
"""Schema for Collections response"""
|
||||
collection_id: int
|
||||
id: int
|
||||
invoice_id: int
|
||||
|
||||
class Config:
|
||||
|
||||
620
backend/api/v1/modules/a76/items/models.py
Normal file
620
backend/api/v1/modules/a76/items/models.py
Normal file
@@ -0,0 +1,620 @@
|
||||
"""
|
||||
Normalized Database Schema for SCAF (Fixed Assets) and SCAII (Parts Inventory)
|
||||
SQLAlchemy v2 - Annex 24 Compliance
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from enum import Enum
|
||||
from sqlalchemy import Boolean, String, Integer, Numeric, Text, SmallInteger, ForeignKey
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from core.database import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .series.models import Serie
|
||||
|
||||
# ============================================================================
|
||||
# CORE ENTITIES
|
||||
# ============================================================================
|
||||
|
||||
class Item(Base):
|
||||
"""
|
||||
Unified item header table for all import/export operations
|
||||
Consolidates headers from both SCAF and SCAII systems
|
||||
"""
|
||||
__tablename__ = "items"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id")) # CONSECUTIVO
|
||||
item_type: Mapped[str] = mapped_column(String(20)) # Type: IMPORT_TEMP, IMPORT_DEF, EXPORT, REPAIR, etc.
|
||||
system_origin: Mapped[str] = mapped_column(String(10)) # SCAF or SCAII
|
||||
|
||||
# Item references
|
||||
invoice_number: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURAIMPO/FACTURAEXPO
|
||||
reference_number: Mapped[Optional[str]] = mapped_column(String(20)) # NUMREFERENCIA
|
||||
order: Mapped[Optional[str]] = mapped_column(String(50)) # ORDENCOMPRA / ORDENVENTA
|
||||
guide_number: Mapped[Optional[str]] = mapped_column(String(50)) # NUMEROGUIA/NUMERODEGUIA
|
||||
|
||||
# Dates
|
||||
invoice_date: Mapped[Optional[int]] = mapped_column(Integer) # FECHAFACTURA
|
||||
depreciation_date: Mapped[Optional[int]] = mapped_column(Integer) # FECHADEPRECIACION
|
||||
|
||||
# Administrative fields
|
||||
rectification: Mapped[Optional[int]] = mapped_column(SmallInteger) # RECTIFICACION
|
||||
warehouse: Mapped[Optional[str]] = mapped_column(String(30)) # BODEGA
|
||||
location: Mapped[Optional[str]] = mapped_column(String(200)) # LOCALIZACION
|
||||
|
||||
# Relationships
|
||||
lines: Mapped[list["LineItem"]] = relationship(back_populates="item", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class LineItem(Base):
|
||||
"""
|
||||
Unified line items for all items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "item_lines"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_id: Mapped[int] = mapped_column(ForeignKey("a76.items.id"))
|
||||
line_number: Mapped[int] = mapped_column(Integer) # LINEAIMPO/LINEAEXPO/LINEA
|
||||
|
||||
# Part identification
|
||||
part_number: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.parts.id")) # NUMPARTE
|
||||
component_part_number: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.parts.id")) # NUMPARTECOM
|
||||
class_code: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.classes.id")) # CLASE
|
||||
|
||||
# Unit of measure
|
||||
unit_of_measure: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.units_of_measure_general.id")) # UNIDADMEDIDA/UNIMED
|
||||
alternate_unit: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.units_of_measure_general.id")) # UNIMEDALTERNA
|
||||
uma_key: Mapped[Optional[str]] = mapped_column(String(2)) # CLAVEUMA
|
||||
auxiliary_unit: Mapped[Optional[str]] = mapped_column(String(5)) # UNIMEDAUXILIAR
|
||||
|
||||
# Permits and certificates
|
||||
permit_number: Mapped[Optional[str]] = mapped_column(String(20)) # NUMPERMISO
|
||||
page_line: Mapped[Optional[str]] = mapped_column(String(10)) # PAGRENGLON
|
||||
has_certificate: Mapped[Optional[bool]] = mapped_column(Boolean) # TIENECO/CERTORIGEN
|
||||
certificate_number: Mapped[Optional[str]] = mapped_column(String(10)) # NOCERTIFICADO
|
||||
octave_permit: Mapped[Optional[str]] = mapped_column(String(20)) # PERMISOROCTAVA
|
||||
permits_ped: Mapped[Optional[str]] = mapped_column(String(500)) # PERMISOSPED
|
||||
|
||||
# FDA
|
||||
has_fda_code: Mapped[Optional[bool]] = mapped_column(Boolean) # LLEVACODFDA
|
||||
fda_key: Mapped[Optional[str]] = mapped_column(String(10)) # CLAVEFDA
|
||||
|
||||
# Subitem flags
|
||||
is_subitem: Mapped[Optional[bool]] = mapped_column(Boolean) # ESSUBPARTIDA
|
||||
contains_subitems: Mapped[Optional[bool]] = mapped_column(Boolean) # CONTIENESUBP
|
||||
includes_subitems: Mapped[Optional[bool]] = mapped_column(Boolean) # INCUYESUBPARTIDAS
|
||||
subitem_number: Mapped[Optional[bool]] = mapped_column(Boolean) # SUBPARTIDA
|
||||
|
||||
# Special flags
|
||||
is_military_mcia: Mapped[Optional[bool]] = mapped_column(Boolean) # ESMCIAMILITAR
|
||||
|
||||
# IV32 (Tax identification)
|
||||
iv32_type_key: Mapped[Optional[str]] = mapped_column(String(5)) # CLAVETIPOIV32
|
||||
iv32_number: Mapped[Optional[str]] = mapped_column(String(35)) # NUMEROIV32
|
||||
|
||||
|
||||
|
||||
# IN CASE OF EXPO
|
||||
scrap_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURASCRAP
|
||||
consecutive_destination: Mapped[Optional[int]] = mapped_column(Integer) # CONSECUTIVODES
|
||||
ctm_section: Mapped[Optional[str]] = mapped_column(String(3)) # APARTADOCTM
|
||||
|
||||
# Tax payment
|
||||
tax_payment: Mapped[Optional[bool]] = mapped_column(Boolean) # PAGOIMPUESTO
|
||||
payment_method: Mapped[Optional[str]] = mapped_column(String(9)) # FORMAPAGO/FORMAPAGOTIGI
|
||||
igi_amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # MONTOIGI
|
||||
igi_payment_method: Mapped[Optional[str]] = mapped_column(String(9)) # FORMAPAGOTIGI
|
||||
|
||||
# FCC
|
||||
fcc_key: Mapped[Optional[str]] = mapped_column(String(30)) # CLAVEFCC
|
||||
|
||||
# Valuation method
|
||||
valuation_method: Mapped[Optional[str]] = mapped_column(String(2)) # METVALOR
|
||||
valuation_determined_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # METVALORVALORDETERMINADO/METVALORACIONVALORDETERMINADO
|
||||
valuation_reason: Mapped[Optional[str]] = mapped_column(String(500)) # METVALORMOTIVODEUSO/METVALORACIONMOTIVODEUSO
|
||||
|
||||
# Container rules
|
||||
container_rule: Mapped[Optional[str]] = mapped_column(String(50)) # CONTENEDORREGLA
|
||||
container_parts_ii: Mapped[Optional[str]] = mapped_column(String(50)) # CONTENEDORPARTESII
|
||||
|
||||
# APHIS
|
||||
consecutive_aphis: Mapped[Optional[int]] = mapped_column(Integer) # CONSECUTIVOAPHIS
|
||||
|
||||
# BOM/Commercial
|
||||
bom_version: Mapped[Optional[int]] = mapped_column(Integer) # VERSIONBOM
|
||||
bill_version: Mapped[Optional[int]] = mapped_column(Integer) # VERSIONBILL
|
||||
|
||||
# TLCAN value
|
||||
tlcan_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTLCAN
|
||||
|
||||
# Identifier
|
||||
identifier: Mapped[Optional[str]] = mapped_column(String(2)) # IDENTIFICADOR
|
||||
|
||||
# Validation fields
|
||||
validation_zero: Mapped[Optional[int]] = mapped_column(Integer) # VALIDACIONZERO
|
||||
validation_one: Mapped[Optional[int]] = mapped_column(Integer) # VALIDACIONUNO
|
||||
|
||||
# Material type
|
||||
material_type: Mapped[Optional[str]] = mapped_column(String(50)) # TIPOMAT/TIPODENUMPARTE
|
||||
|
||||
# Order concept
|
||||
order_type: Mapped[Optional[str]] = mapped_column(String(50)) # TIPODEORDEN
|
||||
line_concept: Mapped[Optional[str]] = mapped_column(String(50)) # CONCEPTODELAPARTIDA
|
||||
|
||||
# Review dispatch
|
||||
review_dispatch: Mapped[Optional[str]] = mapped_column(String(10)) # REVISARDESP
|
||||
|
||||
# Take component from PT
|
||||
take_component_pt: Mapped[Optional[int]] = mapped_column(Integer) # TOMARCOMOPT
|
||||
|
||||
# Pallet
|
||||
pallet2: Mapped[Optional[int]] = mapped_column(SmallInteger) # PALLET2
|
||||
|
||||
# Wildcard field
|
||||
wildcard_field: Mapped[Optional[str]] = mapped_column(String(100)) # CAMPOCOMODIN
|
||||
|
||||
# Relationships
|
||||
item: Mapped["Item"] = relationship(back_populates="lines")
|
||||
|
||||
class LineFinancial(Base):
|
||||
"""
|
||||
Financial details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_financials"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Costs - Capture
|
||||
unit_cost_capture: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOCAPTURA
|
||||
|
||||
# Costs - USD
|
||||
unit_cost_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIODLLS/COSTOUNITARIOME
|
||||
unit_cost_commercial_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUCOMDLLS
|
||||
unit_cost_current_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOACTUALDLLS
|
||||
unit_cost_depreciated_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTODEPRECME
|
||||
unit_cost_subitem_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOSUBPDLLS
|
||||
unit_cost_auxiliary_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUAUXILIARME
|
||||
sales_cost_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOVENTAME
|
||||
commercial_unit_cost: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNICOMERCIAL
|
||||
|
||||
# Costs - MXN
|
||||
unit_cost_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOPESOS/COSTOUNITARIOMN
|
||||
unit_cost_commercial_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUCOMPESOS
|
||||
unit_cost_current_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOACTUALMN
|
||||
unit_cost_depreciated_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTODEPRECMN
|
||||
unit_cost_subitem_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOSUBPPESOS
|
||||
sales_cost_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOVENTAMN
|
||||
|
||||
# Costs - MC (Custom Currency)
|
||||
unit_cost_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # COSTOUNITARIOMC
|
||||
|
||||
# Values - MXN
|
||||
value_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMN/VALORIMPOMN/VALOREXPOMN
|
||||
value_commercial_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALOREXPOCOMMN
|
||||
value_updated_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORACTUALIZADOMN
|
||||
value_subitem_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORSUBPMN
|
||||
sub_import_value_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # SUBVALORIMPOMN
|
||||
value_returned_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORRETORNADOMN
|
||||
value_depreciated_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORDEPRECIADOMN
|
||||
customs_value_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORADUANASMN
|
||||
value_total_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALMN
|
||||
value_temp_material_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPTEMPMN
|
||||
value_def_material_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPDEFMN
|
||||
value_added_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORAGREMN
|
||||
value_national_packing_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUENACMN
|
||||
vat_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # IVAIMPOMN/IVAEXPOMN/VALORIVAMN
|
||||
vat_used_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORIVAMNUSADO
|
||||
advalorem_line_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # ADVALORMNLINEAPED
|
||||
|
||||
# Values - USD
|
||||
value_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # VALORME/VALORIMPOME/VALOREXPOME
|
||||
value_commercial_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALOREXPOCOMME
|
||||
value_updated_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORACTUALIZADOME
|
||||
value_subitem_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORSUBPME
|
||||
sub_import_value_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # SUBVALORIMPOME
|
||||
value_returned_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORRETORNADOME
|
||||
value_depreciated_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORDEPRECIADOME
|
||||
customs_value_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORADUANASME
|
||||
value_auxiliary_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORIMPOAUXILIARME / VALOREXPORAUXILIARME
|
||||
value_total_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALME
|
||||
value_temp_material_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPTEMPME
|
||||
value_def_material_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPDEFME
|
||||
value_added_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORAGREME
|
||||
value_national_packing_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUENACME
|
||||
value_us_packing_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUEUSME
|
||||
vat_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # IVAIMPOME/IVAEXPOME/VALORIVAME
|
||||
vat_used_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORIVAMEUSADO
|
||||
value_non_originating_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORNOORIGINARIOME
|
||||
value_originating_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORORIGINARIOME
|
||||
igi_amount_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # MONTOIGIME
|
||||
exempt_amount_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # MONTOEXCENTOME
|
||||
total_commercial_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALCOMERCIAL
|
||||
advalorem_line_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # ADVALORMELINEAPED
|
||||
|
||||
# Values - MC
|
||||
value_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # VALORIMPOMC/VALOREXPOMC
|
||||
sub_import_value_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # SUBVALORIMPOMC
|
||||
vat_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # IVAIMPOMC/IVAEXPOMC
|
||||
value_added_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORAGREMC
|
||||
value_national_packing_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUENACMC
|
||||
value_total_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALMC
|
||||
value_temp_material_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPTEMPMC
|
||||
value_def_material_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPDEFMC
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineQuantity(Base):
|
||||
"""
|
||||
Quantity details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_quantities"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Quantities
|
||||
quantity: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTIMPO / CANTEXPO / CANTIMPODEF
|
||||
alternate_quantity: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTALTERNA
|
||||
quantity_uma: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTIMPOUMA / CANTEXPOUMA
|
||||
auxiliary_quantity: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTIMPOAUXILIAR / CANTEXPOAUXILIAR
|
||||
|
||||
# Quantities - Special (SCAF specific)
|
||||
quantity_temp_export: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTEXPOTEMP
|
||||
quantity_existence: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTEXISTENCIA
|
||||
quantity_returned: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTRETORNADA
|
||||
quantity_returned_temp: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTRETORNADATEMP
|
||||
serial_count: Mapped[Optional[int]] = mapped_column(Integer) # CANT_SERIES/CANT_SERIESDEF
|
||||
|
||||
# Weight
|
||||
weight_unit: Mapped[Optional[str]] = mapped_column(String(3)) # 'KG' o 'LB'
|
||||
net_weight: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # PESONETO
|
||||
gross_weight: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # PESOBRUTO
|
||||
|
||||
# Packaging
|
||||
package_key: Mapped[Optional[str]] = mapped_column(String(5)) # CLAVEBULTOS
|
||||
package_quantity: Mapped[Optional[int]] = mapped_column(Integer) # CANTBULTOS
|
||||
package_description: Mapped[Optional[str]] = mapped_column(String(40)) # DESCBULTOS
|
||||
container_quantity: Mapped[Optional[int]] = mapped_column(SmallInteger) # CANTBULCONT
|
||||
container_description: Mapped[Optional[str]] = mapped_column(String(40)) # DESCCONTENEDOR
|
||||
box_count: Mapped[Optional[str]] = mapped_column(String(30)) # NOCAJAS
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineCustoms(Base):
|
||||
"""
|
||||
Customs details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_customs"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Tariff/Customs Classifications
|
||||
fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCION / FRACCIONIMPO / FRACCIONEXPO
|
||||
fraction_type: Mapped[Optional[str]] = mapped_column(String(7)) # TIPOFRACCION / TIPOFRACCIONIMPO / TIPOFRACCIONEXPO
|
||||
american_fraction: Mapped[Optional[str]] = mapped_column(String(16)) # FRACCIONAMERICANA
|
||||
alternate_fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCIONALTERNA
|
||||
reference_fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCIONREFERENCIA
|
||||
octave_fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCIONROCTAVA
|
||||
tlcan_fraction: Mapped[Optional[str]] = mapped_column(String(13)) # FRACCIONTLCAN
|
||||
extra_american_fraction: Mapped[Optional[str]] = mapped_column(String(16)) # FRACAMESELEXTRA
|
||||
garment_fraction: Mapped[Optional[str]] = mapped_column(String(19)) # FRACCIONDELAPRENDA/FRACCIONDELAPARTIDA
|
||||
|
||||
# Ad Valorem
|
||||
advalorem: Mapped[Optional[str]] = mapped_column(String(10)) # ADVIMPO / ADVEXPO
|
||||
advalorem_numeric: Mapped[Optional[Decimal]] = mapped_column(Numeric(7, 2)) # ADVIMPONUM / ADVEXPONUM
|
||||
advalorem_american: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2)) # ADVAME
|
||||
advalorem_tlcan: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2)) # ADVTLCAN
|
||||
|
||||
# Rates
|
||||
rate: Mapped[Optional[str]] = mapped_column(String(10)) # TASAIM / TASAEX
|
||||
depreciation_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2)) # TASADEPRECIA
|
||||
|
||||
# Origin/Destination
|
||||
origin_country: Mapped[Optional[str]] = mapped_column(String(3)) # PAISORIGEN
|
||||
destination_country: Mapped[Optional[str]] = mapped_column(String(3)) # PAISDESTINO
|
||||
optional_country: Mapped[Optional[str]] = mapped_column(String(3)) # PAISOPCIONAL
|
||||
origin_procedure: Mapped[Optional[str]] = mapped_column(String(3)) # PROCEDENCIA
|
||||
scrap_procedure: Mapped[Optional[str]] = mapped_column(String(3)) # PROCSCRAP
|
||||
|
||||
# Sector
|
||||
sector: Mapped[Optional[str]] = mapped_column(String(8)) # SECTOR
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineDescription(Base):
|
||||
"""
|
||||
Description details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_descriptions"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Descriptions
|
||||
description_spanish: Mapped[Optional[str]] = mapped_column(String(4999)) # DESCRIPCIONE
|
||||
description_english: Mapped[Optional[str]] = mapped_column(String(4999)) # DESCRIPCIONI
|
||||
extra_description: Mapped[Optional[str]] = mapped_column(Text) # DESCRIPCIONEEXTRA
|
||||
part_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONPARTE
|
||||
class_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONCLASE
|
||||
|
||||
# Product attributes
|
||||
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA
|
||||
model: Mapped[Optional[str]] = mapped_column(String(50)) # MODELO
|
||||
has_serial: Mapped[Optional[bool]] = mapped_column(Boolean) # LLEVASERIE
|
||||
|
||||
# Additional information
|
||||
additional_info_spanish: Mapped[Optional[str]] = mapped_column(String(1000)) # INFOADICIONESP
|
||||
additional_info_english: Mapped[Optional[str]] = mapped_column(String(1000)) # INFOADICIONING
|
||||
|
||||
# Lot and entry tracking
|
||||
lot: Mapped[Optional[str]] = mapped_column(String(254)) # LOTE
|
||||
entry_number: Mapped[Optional[str]] = mapped_column(String(50)) # NUMENTRADA/NUMERODEENTRADA
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineReference(Base):
|
||||
"""
|
||||
Reference details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_references"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
serie_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.item_line_series.id")) # SERIEPARTIDA
|
||||
|
||||
# Customer/Vendor
|
||||
customer_invoice: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # CLIENTEFACTURAR
|
||||
assigned_client: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # CLIENTEASIGNADO
|
||||
supplier: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # PROVEEDOR
|
||||
requisitioner: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # REQUISITOR
|
||||
sent_to: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # ENVIADOA
|
||||
|
||||
# PED line reference
|
||||
ped_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEAPED
|
||||
ro_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEARO
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
# ============================================================================
|
||||
# SUPPORTING TABLES
|
||||
# ============================================================================
|
||||
|
||||
class PackingList(Base):
|
||||
"""
|
||||
Packing list items
|
||||
From: SPartidasPackingList
|
||||
"""
|
||||
__tablename__ = "packing_lists"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(Integer) # LINEA
|
||||
packing_list_number: Mapped[Optional[str]] = mapped_column(String(100)) # NUMPACKINGLIST
|
||||
|
||||
|
||||
class RepairPart(Base):
|
||||
"""
|
||||
Repair parts (orphan table without primary key in original)
|
||||
From: SPartidasRep
|
||||
"""
|
||||
__tablename__ = "repair_parts"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
import_line: Mapped[int] = mapped_column(Integer) # LINEAIMPO
|
||||
|
||||
|
||||
class CTMShipment(Base):
|
||||
"""
|
||||
CTM Shipment lines (temporary manufacturing)
|
||||
From: SPartidasEnviaCTM
|
||||
"""
|
||||
__tablename__ = "ctm_shipments"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
shipment_line: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEAENVIO
|
||||
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA
|
||||
model: Mapped[Optional[str]] = mapped_column(String(50)) # MODELO
|
||||
serial_numbers: Mapped[Optional[str]] = mapped_column(String(50)) # SERIES
|
||||
|
||||
|
||||
class CTMReceipt(Base):
|
||||
"""
|
||||
CTM Receipt lines (temporary manufacturing)
|
||||
From: SPartidasReciboCTM
|
||||
"""
|
||||
__tablename__ = "ctm_receipts"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
receipt_line: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEARECIBO
|
||||
|
||||
option: Mapped[Optional[str]] = mapped_column(String(3)) # OPCION
|
||||
exit_invoice: Mapped[Optional[str]] = mapped_column(String(19)) # FACTURASALIDA
|
||||
|
||||
|
||||
class SubassemblyEntry(Base):
|
||||
"""
|
||||
Subassembly/Submanufacturing Entry lines
|
||||
From: SPartidasEntradaSM
|
||||
"""
|
||||
__tablename__ = "subassembly_entries"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
remission_line: Mapped[int] = mapped_column(Integer) # LINEAREMISION
|
||||
exit_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURASALIDA
|
||||
exit_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEASALIDA
|
||||
|
||||
|
||||
class SubassemblyExit(Base):
|
||||
"""
|
||||
Subassembly/Submanufacturing Exit lines
|
||||
From: SPartidasSalidaSM
|
||||
"""
|
||||
__tablename__ = "subassembly_exits"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
exit_line: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEASALIDA
|
||||
|
||||
|
||||
class ImpositionPart(Base):
|
||||
"""
|
||||
Imposition parts (orphan table without primary key constraint)
|
||||
From: SPartidasImposion
|
||||
"""
|
||||
__tablename__ = "imposition_parts"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
import_line: Mapped[int] = mapped_column(Integer) # LINEAIMPO
|
||||
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# INDEXES AND CONSTRAINTS
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
Recommended indexes for optimal query performance:
|
||||
|
||||
CREATE INDEX idx_items_consecutive ON items(consecutive);
|
||||
CREATE INDEX idx_items_invoice ON items(invoice_number);
|
||||
CREATE INDEX idx_items_type_system ON items(item_type, system_origin);
|
||||
CREATE INDEX idx_items_dates ON items(invoice_date, depreciation_date);
|
||||
|
||||
CREATE INDEX idx_lines_item ON item_lines(item_id);
|
||||
CREATE INDEX idx_lines_part ON item_lines(part_number);
|
||||
CREATE INDEX idx_lines_class ON item_lines(class_code);
|
||||
CREATE INDEX idx_lines_invoice_refs ON item_lines(import_invoice, export_invoice);
|
||||
CREATE INDEX idx_lines_fractions ON item_lines(import_fraction, export_fraction);
|
||||
|
||||
CREATE INDEX idx_packing_consecutive ON packing_lists(consecutive);
|
||||
CREATE INDEX idx_packing_part ON packing_lists(part_number);
|
||||
|
||||
CREATE INDEX idx_repair_invoice ON repair_parts(import_invoice, import_line);
|
||||
CREATE INDEX idx_ctm_ship_consec ON ctm_shipments(consecutive);
|
||||
CREATE INDEX idx_ctm_rcpt_consec ON ctm_receipts(consecutive);
|
||||
CREATE INDEX idx_sub_entry_consec ON subassembly_entries(consecutive);
|
||||
CREATE INDEX idx_sub_exit_consec ON subassembly_exits(consecutive);
|
||||
CREATE INDEX idx_imposition_consec ON imposition_parts(consecutive);
|
||||
"""
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# MIGRATION NOTES
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
MIGRATION STRATEGY FROM ORIGINAL TABLES TO NORMALIZED SCHEMA:
|
||||
|
||||
1. DOCUMENT MAPPING:
|
||||
- QEqeMaq (Equipment Import Temp) → items (type='EQUIPMENT_IMPORT_TEMP', system='SCAF')
|
||||
- QEqeMaqRep (Equipment Repair Export) → items (type='EQUIPMENT_REPAIR_EXPORT', system='SCAF')
|
||||
- QEqiDef (Equipment Import Definitive) → items (type='EQUIPMENT_IMPORT_DEF', system='SCAF')
|
||||
- QEqiMaq (Equipment Machinery) → items (type='EQUIPMENT_MACHINERY', system='SCAF')
|
||||
- QEqiMaqRep (Equipment Machinery Repair) → items (type='EQUIPMENT_REPAIR_IMPORT', system='SCAF')
|
||||
- SPartidasCM (Common Commerce) → items (type='COMMON_COMMERCE', system='SCAII')
|
||||
- SPartidasExpo (Export) → items (type='EXPORT', system='SCAII')
|
||||
- SPartidasImpo (Import) → items (type='IMPORT', system='SCAII')
|
||||
|
||||
2. LINE MAPPING:
|
||||
All line items from Q* and SPartidas* tables map to item_lines with appropriate
|
||||
field mapping based on the original column names (preserved as comments).
|
||||
|
||||
3. FIELD CONSOLIDATION RULES:
|
||||
- Costs: Unified under unit_cost_* with currency suffix (usd/mxn/mc)
|
||||
- Values: Unified under value_* with currency suffix
|
||||
- Quantities: Unified under quantity_* with specific purpose suffixes
|
||||
- Descriptions: Consolidated into description_spanish/english/extra
|
||||
- Fractions: All fraction fields preserved with clear naming
|
||||
|
||||
4. DATA INTEGRITY:
|
||||
- Original CONSECUTIVO + LINE number preserved for traceability
|
||||
- Foreign key relationships established via item_id
|
||||
- All original fields retained to prevent data loss
|
||||
|
||||
5. SPECIAL TABLES:
|
||||
- PackingList, RepairPart, CTM*, Subassembly*, ImpositionPart remain separate
|
||||
as they serve specific purposes and don't fit the main item/line pattern
|
||||
|
||||
6. BENEFITS:
|
||||
- Eliminates redundancy across 13 original tables
|
||||
- Unified query interface for all operations
|
||||
- Maintains full audit trail with original field names
|
||||
- Enables cross-system reporting (SCAF + SCAII)
|
||||
- Simplifies maintenance with single schema
|
||||
|
||||
7. QUERYING EXAMPLES:
|
||||
```python
|
||||
# Get all imports (both systems)
|
||||
session.query(Item).filter(
|
||||
Item.item_type.in_(['IMPORT', 'EQUIPMENT_IMPORT_TEMP', 'EQUIPMENT_IMPORT_DEF'])
|
||||
)
|
||||
|
||||
# Get all lines for a specific part across all items
|
||||
session.query(LineItem).filter(
|
||||
LineItem.part_number == 'ABC123'
|
||||
)
|
||||
|
||||
# Get SCAF equipment with depreciation
|
||||
session.query(Item).join(LineItem).filter(
|
||||
Item.system_origin == 'SCAF',
|
||||
LineItem.value_depreciated_usd.isnot(None)
|
||||
)
|
||||
```
|
||||
"""
|
||||
23
backend/api/v1/modules/a76/items/series/models.py
Normal file
23
backend/api/v1/modules/a76/items/series/models.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from typing import Optional
|
||||
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, Numeric, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from core.database import Base
|
||||
|
||||
class Serie(Base):
|
||||
__tablename__ = "item_line_series"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
line_item_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEAIMPO / LINEAEXPO
|
||||
row: Mapped[int] = mapped_column(Integer) # RENGLON
|
||||
serial_numbers: Mapped[Optional[str]] = mapped_column(String(50)) # SERIEEXPO
|
||||
model: Mapped[Optional[str]] = mapped_column(String(50)) # MODELOEXPO
|
||||
sub_model: Mapped[Optional[str]] = mapped_column(String(50)) # SUBMODELOEXPO
|
||||
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA
|
||||
expo_brad: Mapped[Optional[str]] = mapped_column(String(50)) # MARCAEXPO
|
||||
number_id: Mapped[Optional[str]] = mapped_column(String(25)) # NUMIDEXPO
|
||||
|
||||
|
||||
|
||||
@@ -9,12 +9,10 @@ from typing import TYPE_CHECKING, Optional
|
||||
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
|
||||
from core.database import Base
|
||||
from sqlalchemy import (
|
||||
ForeignKey,
|
||||
ForeignKeyConstraint,
|
||||
Integer,
|
||||
Numeric,
|
||||
PrimaryKeyConstraint,
|
||||
SmallInteger,
|
||||
String,
|
||||
UniqueConstraint,
|
||||
Boolean,
|
||||
@@ -57,7 +55,7 @@ class Part(Base, TenantScopedMixin, TimestampMixin):
|
||||
|
||||
# Unique constraint compuesta
|
||||
client_id: Mapped[int] = mapped_column(Integer)
|
||||
part_number: Mapped[str] = mapped_column(String(49))
|
||||
part_number: Mapped[str] = mapped_column(String(50))
|
||||
|
||||
# Basic information
|
||||
fraction: Mapped[Optional[str]] = mapped_column(String(10))
|
||||
|
||||
Reference in New Issue
Block a user