from typing import Optional, List from sqlalchemy import BigInteger, Date, ForeignKey, Integer, Numeric, String, Text, TIMESTAMP from sqlalchemy.orm import Mapped, mapped_column, relationship from core.database import Base from datetime import datetime from ....common.base_models import TenantScopedMixin, TimestampMixin # --- 1. Invoice Header (invoice_header) --- class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin): __tablename__ = "invoice_header" __tableargs__ = {'schema': 'a76'} id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) # Identifiers legacy_id: Mapped[Optional[int]] = mapped_column(Integer) # CONSECUTIVO operation_type: Mapped[str] = mapped_column(String(20)) # TIPOMOVIMIENTO / Clasifica IMP/EXP/SM 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) # Dates invoice_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAFACTURA capture_date: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=False), default=datetime.now) # FECHACAPTURA + HORAACTUAL # Status & Control status: Mapped[Optional[str]] = mapped_column(String(5)) # ESTATUS traffic_light_status: Mapped[Optional[str]] = mapped_column(String(50)) # SEMAFORO / SEMAFOROEXPO/IMPO process_log: Mapped[Optional[str]] = mapped_column(String(300)) # COMOFUEPROCESADA **<-- AÑADIDO** comments: Mapped[Optional[str]] = mapped_column(Text) # OBSERVACIONE + OBSERVACIONI + COMENTARIOSESTATUS # Digital Archive Links cfdi_uuid: Mapped[Optional[str]] = mapped_column(String(100)) # CFDIUUID path_pdf: Mapped[Optional[str]] = mapped_column(String(500)) # CFDIPATHPDF **<-- AÑADIDO** path_xml: Mapped[Optional[str]] = mapped_column(String(500)) # CFDIPATHXML **<-- AÑADIDO** # 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") 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[List["InvoiceLogistics"]] = relationship(back_populates="header", cascade="all, delete-orphan") # --- 2. Compliance MX (invoice_compliance_mx) --- class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin): __tablename__ = "invoice_compliance_mx" __tableargs__ = {'schema': 'a76'} invoice_id: Mapped[int] = mapped_column(ForeignKey("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) aduana: Mapped[Optional[str]] = mapped_column(String(5)) # ADUANA_CRUCE customs_agent: Mapped[Optional[str]] = mapped_column(String(10)) # AADUANAL # Flags & Specific Regimes is_mixed: Mapped[Optional[str]] = mapped_column(String(2)) # ESMIXTO **<-- AÑADIDO** waste_type: Mapped[Optional[str]] = mapped_column(String(1)) # TIPODESPERDICIO **<-- AÑADIDO** appendix_17: Mapped[Optional[int]] = mapped_column(Integer) # APENDICE17 # 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) # Relationship header: Mapped["InvoiceHeader"] = relationship(back_populates="compliance_mx") # --- 3. Financials (invoice_financials) --- class InvoiceFinancials(Base, TenantScopedMixin, TimestampMixin): __tablename__ = "invoice_financials" __tableargs__ = {'schema': 'a76'} invoice_id: Mapped[int] = mapped_column(ForeignKey("invoice_header.id"), primary_key=True) currency: Mapped[Optional[str]] = mapped_column(String(3)) # CLAVEMONEDA exchange_rate: Mapped[Optional[float]] = mapped_column(Numeric(13, 6)) # TIPOCAMBIO # 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 **<-- AÑADIDO** # 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 # 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 **<-- AÑADIDO** net_weight: Mapped[Optional[float]] = mapped_column(Numeric(19, 8)) # PESONETO **<-- AÑADIDO** bundle_count: Mapped[Optional[int]] = mapped_column(Integer) # CANTBULTOS # Relationship header: Mapped["InvoiceHeader"] = relationship(back_populates="financials") # --- 4. Logistics (invoice_logistics) --- class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin): __tablename__ = "invoice_logistics" __tableargs__ = {'schema': 'a76'} logistics_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) invoice_id: Mapped[int] = mapped_column(ForeignKey("invoice_header.id")) # Carrier Info carrier_id: Mapped[Optional[str]] = mapped_column(String(10)) # TRANSPORTISTA transport_mode: Mapped[Optional[str]] = mapped_column(String(15)) # TRANSPORTE 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 # 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 # Logistics Dates entry_exit_date: Mapped[Optional[datetime]] = mapped_column(Date) # FECHAENTRADA / FECHAENVIO # Relationship header: Mapped["InvoiceHeader"] = relationship(back_populates="logistics") # --- 5. Sales Order Details (invoice_sales_details) --- class InvoiceSalesDetails(Base, TenantScopedMixin, TimestampMixin): __tablename__ = "invoice_sales_details" __tableargs__ = {'schema': 'a76'} detail_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) invoice_id: Mapped[int] = mapped_column(ForeignKey("invoice_header.id")) line_number: Mapped[int] = mapped_column(Integer) # LINEA sales_order: Mapped[Optional[str]] = mapped_column(String(20)) # ORDENVENTA # 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) # Relationship header: Mapped["InvoiceHeader"] = relationship(back_populates="details") # --- 6. Collections (invoice_collections) --- class InvoiceCollections(Base, TenantScopedMixin, TimestampMixin): __tablename__ = "invoice_collections" __tableargs__ = {'schema': 'a76'} collection_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) invoice_id: Mapped[int] = mapped_column(ForeignKey("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 # Relationship header: Mapped["InvoiceHeader"] = relationship(back_populates="collections")