Files
plantillas-proyectos/backend/api/v1/modules/a76/invoices/models.py

776 lines
30 KiB
Python

from enum import Enum
from typing import Optional, List, TYPE_CHECKING
from sqlalchemy import (
BigInteger,
Boolean,
Date,
ForeignKey,
Integer,
Numeric,
String,
Text,
TIMESTAMP,
func,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from datetime import datetime
from ....common.base_models import TenantScopedMixin, TimestampMixin
if TYPE_CHECKING:
from api.v1.modules.a76.pedmientos.models.pedimentos import Pedimentos
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
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"
TRANSPORT = "transport"
BOX = "box"
PLATES = "licence plates"
TRUCK = "truck"
VESSEL = "vessel"
BARGE = "rail_barge"
CONTAINER = "container"
AIRPLANE = "airplane"
GONDOLA = "gondola"
FLATBED = "flatbed"
class InvoiceStatus(str, Enum):
PENDING = "pending"
PROCESSED = "processed"
REVERSED = "reversed"
# --- 1. Invoice Header (invoice_header) ---
class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "invoice_header"
__table_args__ = ({"schema": "a76"},)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
# Identifiers
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[Optional[str]] = mapped_column(
ForeignKey("public.pedimento_regimens.code"), nullable=True
)
# 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
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[datetime] = mapped_column(Date) # FECHAFACTURA
capture_date: Mapped[datetime] = mapped_column(
TIMESTAMP(timezone=False), server_default=func.now()
) # FECHACAPTURA + HORAACTUAL
emission_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAEMISION
# Status & Control
status: Mapped[InvoiceStatus] = mapped_column(String(10)) # ESTATUS
status_rec: Mapped[Optional[InvoiceStatus]] = mapped_column(
String(10)
) # ESTATUSREC / Estatus de recepción
status_rep: Mapped[Optional[InvoiceStatus]] = mapped_column(
String(10)
) # ESTATUSREP / Estatus de reporte
processed_date: Mapped[Optional[datetime]] = mapped_column(
TIMESTAMP(timezone=False)
) # FECHAACTUALIZACION / FECHAACTUAL
who_processed: 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
# 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
# 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[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # GENERAID
generate_desc_parties: Mapped[Optional[str]] = mapped_column(
String(12)
) # GENDESCPARTIDAS / Generar descripción de partidas
apply_manual_discount: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # 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(
back_populates="header", cascade="all, delete-orphan"
)
logistics: Mapped[Optional["InvoiceLogistics"]] = relationship(
back_populates="header", cascade="all, delete-orphan", uselist=False
)
# --- 2. Compliance MX (invoice_compliance_mx) ---
class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "invoice_compliance_mx"
__table_args__ = ({"schema": "a76"},)
invoice_id: Mapped[int] = mapped_column(
ForeignKey("a76.invoice_header.id"), primary_key=True
)
# Core Customs Data
pedimento_id: Mapped[Optional[int]] = mapped_column(
ForeignKey("a76.pedimentos.id")
) # PEDIMENTO/PEDIMENTOIMPO/EXPO
pedimento_r1: Mapped[Optional[int]] = mapped_column(
ForeignKey("a76.pedimentos.id")
) # PEDIMENTOR1
pedimento_k1: Mapped[Optional[int]] = mapped_column(
ForeignKey("a76.pedimentos.id")
) # 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_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[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[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[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
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 / 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[bool]] = mapped_column(
Boolean, default=False, server_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
rule_3121_parties_ii: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # REGLA3121PARTESII / Regla 3.1.21 Partes II
is_pedimento_pending: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # PED_PENDIENTE_ASIGNAR (Mapear 1 -> True, 0 -> False)
# Ownership & Balances
is_owner_of_goods: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # ESDUENOMCIA / Es dueño de mercancía
generate_balances: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # 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 / 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[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
# 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(100)
) # CLAVEFIRMA / Clave de firma
# SM specific
sem_id: Mapped[Optional[int]] = mapped_column(
Integer
) # SEM / ID SEM (de SFacEntradaSM/SFacSalidaSM)
# Relationships
header: Mapped["InvoiceHeader"] = relationship(back_populates="compliance_mx")
pedimento: Mapped[Optional["Pedimentos"]] = relationship(
foreign_keys=[pedimento_id], lazy="joined"
)
# --- 3. Financials (invoice_financials) ---
class InvoiceFinancials(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "invoice_financials"
__table_args__ = ({"schema": "a76"},)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))
# Currency
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
# Merchandise Values (MN = National Currency, ME = Foreign Currency, MC = Third Currency)
value_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORIMPOMN/VALOREXPOMN/VALORENTMN/VALORSALMN
value_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORIMPOME/VALOREXPOME/VALORENTME/VALORSALME
value_mc: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORIMPOMC/VALOREXPOMC
# Customs Value
customs_value_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORADUANASMN / Valor en aduanas MN
customs_value_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORADUANASME / Valor en aduanas ME
# Raw Materials
raw_material_value_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORMPMN / Valor materia prima MN
raw_material_value_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORMPME / Valor materia prima ME
# Aggregate Value
aggregate_value_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORAGREMN / Valor agregado MN
aggregate_value_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORAGREME / Valor agregado ME
aggregate_value_mc: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORAGREMC / Valor agregado MC
# Mexican Merchandise Value
mexican_value_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORVMEXMN / Valor mercancía mexicana MN
mexican_value_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORVMEXME / Valor mercancía mexicana ME
mexican_value_mc: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALORVMEXMC / Valor mercancía mexicana MC
# National Packaging
national_packaging_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALEMPAQUENACMN / Valor empaque nacional MN
national_packaging_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALEMPAQUENACME / Valor empaque nacional ME
national_packaging_mc: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # VALEMPAQUENACMC / Valor empaque nacional MC
# Costs & Increments
freight: Mapped[Optional[float]] = mapped_column(
Numeric(19, 8), default=0, server_default="0"
) # FLETE / Flete
insurance: Mapped[Optional[float]] = mapped_column(
Numeric(19, 8), default=0, server_default="0"
) # SEGUROS / Seguros
insurance_value: Mapped[Optional[float]] = mapped_column(
Numeric(19, 8), default=0, server_default="0"
) # VALSEGUROS / Valor seguros
packaging: Mapped[Optional[float]] = mapped_column(
Numeric(19, 8), default=0, server_default="0"
) # EMBALAJES / Embalajes
other_increments: Mapped[Optional[float]] = mapped_column(
Numeric(19, 8), default=0, server_default="0"
) # OTROSINCREMENTA / Otros incrementables
other_deductibles: Mapped[Optional[float]] = mapped_column(
Numeric(19, 8), default=0, server_default="0"
) # OTROSDEDUCIBLES / Otros deducibles
total_increments_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # TOTALINCREMMN / Total incrementables MN
total_increments_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # TOTALINCREMME / Total incrementables ME
# Taxes
iva_mn: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # IVAEXPOMN/VALORIVAMN / IVA en MN
iva_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # IVAEXPOME/VALORIVAME / IVA en ME
iva_mc: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # IVAEXPOMC / IVA en MC
iva_factor: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_default="0"
) # FACTORIVA / Factor IVA
tax_value_me: Mapped[Optional[float]] = mapped_column(
Numeric(23, 8), default=0, server_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 / Cantidad total
total_packages: Mapped[Optional[int]] = mapped_column(
Integer
) # CANTBULTOS / Cantidad de bultos
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")
# --- 4. Logistics (invoice_logistics) ---
class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "invoice_logistics"
__table_args__ = ({"schema": "a76"},)
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 / Transportista
carrier_int_id: Mapped[Optional[int]] = mapped_column(
BigInteger, ForeignKey("a76.transporter.transporter_id"), nullable=True
) # Internal surrogate ID for Transporter (by transporter_key)
transport_id: Mapped[Optional[str]] = mapped_column(
String(10)
) # NUMTRAILER / Transportista
transport_int_id: Mapped[Optional[int]] = mapped_column(
BigInteger, ForeignKey("a76.vehicle.vehicle_id"), nullable=True
) # Internal surrogate ID for Vehicle (by vehicle_key)
transport_us_id: Mapped[Optional[str]] = mapped_column(
String(10)
) # TRANSPORTISTAAME / Transportista americano
transport_type: Mapped[TransportType] = mapped_column(
String(15), server_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[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # 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 / 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
trailer_int_id: Mapped[Optional[int]] = mapped_column(
BigInteger, ForeignKey("a76.trailer.trailer_id"), nullable=True
) # Internal surrogate ID for Trailer (by trailer_number)
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[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
# 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/FECHARECIBO / Fecha entrada/salida
delivery_date: Mapped[Optional[datetime]] = mapped_column(
Date
) # FECHAENTREGA / Fecha de entrega
# Delivery Control
delivered_status: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # 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[bool]] = mapped_column(
Boolean, default=False, server_default="false"
) # SETRATAPROCESOCTM / Se trata de proceso CTM
# Continuation Tab Fields
equipment_reviewed: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Fue revisado el equipo
is_subdivision: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Sub división
acts_as_cd: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Funge como CD
pedimento_arrived: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Llegó el pedimento
green_light_mx: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Semáforo verde México
green_light_us: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Semáforo verde USA
red_light_mx: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Semáforo rojo México
red_light_us: Mapped[Optional[bool]] = mapped_column(
Boolean, default=False
) # Semáforo rojo USA
# Relationship
header: Mapped["InvoiceHeader"] = relationship(back_populates="logistics")
# --- 5. Sales Order Details (invoice_sales_details) ---
class InvoiceSalesDetails(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "invoice_sales_details"
__table_args__ = ({"schema": "a76"},)
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 / 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 / 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")
# --- 6. Collections (invoice_collections) ---
class InvoiceCollections(Base, TenantScopedMixin, TimestampMixin):
__tablename__ = "invoice_collections"
__table_args__ = ({"schema": "a76"},)
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 / 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")