- Updated the `iva_factor` field in the `InvoiceFinancials` model to use a numeric type with precision and scale. - Adjusted related frontend components and API interfaces to reflect the new numeric type for `iva_factor`. - Enhanced Alembic migration scripts to accommodate the schema changes, ensuring proper index management and data type conversions. These changes improve data integrity and consistency for financial calculations in invoices.
768 lines
29 KiB
Python
768 lines
29 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
|
|
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), 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
|
|
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")
|
|
concept: Mapped[Optional[str]] = mapped_column(String(100)) # CONCEPTO / Conce
|