""" 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) ) ``` """