Merge pull request 'feat: Add models for line items and their series, including detailed attributes for item tracking and classification' (#28) from feature/item_lines into feature/facturas
Reviewed-on: ADUANASOFT/anexo76#28
This commit is contained in:
34
backend/api/v1/modules/a24/fa/fa_item_lines/models.py
Normal file
34
backend/api/v1/modules/a24/fa/fa_item_lines/models.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from typing import Optional
|
||||
from sqlalchemy import Boolean, ForeignKey, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from core.database import Base
|
||||
|
||||
class LineItem(Base):
|
||||
__tablename__ = "line_items"
|
||||
__table_args__ = (
|
||||
{"schema": "a24"}
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_id: Mapped[int] = mapped_column(ForeignKey("a76.items.id"))
|
||||
|
||||
# Asset information (SCAF specific)
|
||||
asset_number: Mapped[Optional[str]] = mapped_column(String(25)) # ASSETNUMBER
|
||||
asset_photo: Mapped[Optional[str]] = mapped_column(String(255)) # FOTOACTIVOFIJO
|
||||
equipment_message: Mapped[Optional[str]] = mapped_column(String(40)) # EQI_MENSAJE
|
||||
invoice_type_asset: Mapped[Optional[str]] = mapped_column(String(6)) # TIPOFACTURAASSET
|
||||
return_import_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURAIMPORET
|
||||
return_import_date: Mapped[Optional[int]] = mapped_column(Integer) # FECHAFACIMPORET
|
||||
movement_type_import: Mapped[Optional[str]] = mapped_column(String(3)) # TIPOMOVIMPO
|
||||
|
||||
# Cross-references IN CASE OF IMPORT REPAIR
|
||||
search_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURAEXPO (when line is import) / FACTURAIMPO (when line is export)
|
||||
search_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEAEXPO (when line is import) / LINEAIMPO (when line is export)
|
||||
|
||||
# Search type
|
||||
search_type: Mapped[Optional[str]] = mapped_column(String(10)) # TIPOBUSQUEDA
|
||||
|
||||
# Special flags
|
||||
download: Mapped[Optional[bool]] = mapped_column(Boolean) # DESCARGA
|
||||
own_equipment: Mapped[Optional[bool]] = mapped_column(Boolean) # EQUIPOPROPIO
|
||||
omit_annex31: Mapped[Optional[bool]] = mapped_column(Boolean) # OMITITENANEXO31
|
||||
620
backend/api/v1/modules/a76/items/models.py
Normal file
620
backend/api/v1/modules/a76/items/models.py
Normal file
@@ -0,0 +1,620 @@
|
||||
"""
|
||||
Normalized Database Schema for SCAF (Fixed Assets) and SCAII (Parts Inventory)
|
||||
SQLAlchemy v2 - Annex 24 Compliance
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from enum import Enum
|
||||
from sqlalchemy import Boolean, String, Integer, Numeric, Text, SmallInteger, ForeignKey
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from core.database import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .series.models import Serie
|
||||
|
||||
# ============================================================================
|
||||
# CORE ENTITIES
|
||||
# ============================================================================
|
||||
|
||||
class Item(Base):
|
||||
"""
|
||||
Unified item header table for all import/export operations
|
||||
Consolidates headers from both SCAF and SCAII systems
|
||||
"""
|
||||
__tablename__ = "items"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id")) # CONSECUTIVO
|
||||
item_type: Mapped[str] = mapped_column(String(20)) # Type: IMPORT_TEMP, IMPORT_DEF, EXPORT, REPAIR, etc.
|
||||
system_origin: Mapped[str] = mapped_column(String(10)) # SCAF or SCAII
|
||||
|
||||
# Item references
|
||||
invoice_number: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURAIMPO/FACTURAEXPO
|
||||
reference_number: Mapped[Optional[str]] = mapped_column(String(20)) # NUMREFERENCIA
|
||||
order: Mapped[Optional[str]] = mapped_column(String(50)) # ORDENCOMPRA / ORDENVENTA
|
||||
guide_number: Mapped[Optional[str]] = mapped_column(String(50)) # NUMEROGUIA/NUMERODEGUIA
|
||||
|
||||
# Dates
|
||||
invoice_date: Mapped[Optional[int]] = mapped_column(Integer) # FECHAFACTURA
|
||||
depreciation_date: Mapped[Optional[int]] = mapped_column(Integer) # FECHADEPRECIACION
|
||||
|
||||
# Administrative fields
|
||||
rectification: Mapped[Optional[int]] = mapped_column(SmallInteger) # RECTIFICACION
|
||||
warehouse: Mapped[Optional[str]] = mapped_column(String(30)) # BODEGA
|
||||
location: Mapped[Optional[str]] = mapped_column(String(200)) # LOCALIZACION
|
||||
|
||||
# Relationships
|
||||
lines: Mapped[list["LineItem"]] = relationship(back_populates="item", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class LineItem(Base):
|
||||
"""
|
||||
Unified line items for all items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "item_lines"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_id: Mapped[int] = mapped_column(ForeignKey("a76.items.id"))
|
||||
line_number: Mapped[int] = mapped_column(Integer) # LINEAIMPO/LINEAEXPO/LINEA
|
||||
|
||||
# Part identification
|
||||
part_number: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.parts.id")) # NUMPARTE
|
||||
component_part_number: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.parts.id")) # NUMPARTECOM
|
||||
class_code: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.classes.id")) # CLASE
|
||||
|
||||
# Unit of measure
|
||||
unit_of_measure: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.units_of_measure_general.id")) # UNIDADMEDIDA/UNIMED
|
||||
alternate_unit: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.units_of_measure_general.id")) # UNIMEDALTERNA
|
||||
uma_key: Mapped[Optional[str]] = mapped_column(String(2)) # CLAVEUMA
|
||||
auxiliary_unit: Mapped[Optional[str]] = mapped_column(String(5)) # UNIMEDAUXILIAR
|
||||
|
||||
# Permits and certificates
|
||||
permit_number: Mapped[Optional[str]] = mapped_column(String(20)) # NUMPERMISO
|
||||
page_line: Mapped[Optional[str]] = mapped_column(String(10)) # PAGRENGLON
|
||||
has_certificate: Mapped[Optional[bool]] = mapped_column(Boolean) # TIENECO/CERTORIGEN
|
||||
certificate_number: Mapped[Optional[str]] = mapped_column(String(10)) # NOCERTIFICADO
|
||||
octave_permit: Mapped[Optional[str]] = mapped_column(String(20)) # PERMISOROCTAVA
|
||||
permits_ped: Mapped[Optional[str]] = mapped_column(String(500)) # PERMISOSPED
|
||||
|
||||
# FDA
|
||||
has_fda_code: Mapped[Optional[bool]] = mapped_column(Boolean) # LLEVACODFDA
|
||||
fda_key: Mapped[Optional[str]] = mapped_column(String(10)) # CLAVEFDA
|
||||
|
||||
# Subitem flags
|
||||
is_subitem: Mapped[Optional[bool]] = mapped_column(Boolean) # ESSUBPARTIDA
|
||||
contains_subitems: Mapped[Optional[bool]] = mapped_column(Boolean) # CONTIENESUBP
|
||||
includes_subitems: Mapped[Optional[bool]] = mapped_column(Boolean) # INCUYESUBPARTIDAS
|
||||
subitem_number: Mapped[Optional[bool]] = mapped_column(Boolean) # SUBPARTIDA
|
||||
|
||||
# Special flags
|
||||
is_military_mcia: Mapped[Optional[bool]] = mapped_column(Boolean) # ESMCIAMILITAR
|
||||
|
||||
# IV32 (Tax identification)
|
||||
iv32_type_key: Mapped[Optional[str]] = mapped_column(String(5)) # CLAVETIPOIV32
|
||||
iv32_number: Mapped[Optional[str]] = mapped_column(String(35)) # NUMEROIV32
|
||||
|
||||
|
||||
|
||||
# IN CASE OF EXPO
|
||||
scrap_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURASCRAP
|
||||
consecutive_destination: Mapped[Optional[int]] = mapped_column(Integer) # CONSECUTIVODES
|
||||
ctm_section: Mapped[Optional[str]] = mapped_column(String(3)) # APARTADOCTM
|
||||
|
||||
# Tax payment
|
||||
tax_payment: Mapped[Optional[bool]] = mapped_column(Boolean) # PAGOIMPUESTO
|
||||
payment_method: Mapped[Optional[str]] = mapped_column(String(9)) # FORMAPAGO/FORMAPAGOTIGI
|
||||
igi_amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # MONTOIGI
|
||||
igi_payment_method: Mapped[Optional[str]] = mapped_column(String(9)) # FORMAPAGOTIGI
|
||||
|
||||
# FCC
|
||||
fcc_key: Mapped[Optional[str]] = mapped_column(String(30)) # CLAVEFCC
|
||||
|
||||
# Valuation method
|
||||
valuation_method: Mapped[Optional[str]] = mapped_column(String(2)) # METVALOR
|
||||
valuation_determined_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # METVALORVALORDETERMINADO/METVALORACIONVALORDETERMINADO
|
||||
valuation_reason: Mapped[Optional[str]] = mapped_column(String(500)) # METVALORMOTIVODEUSO/METVALORACIONMOTIVODEUSO
|
||||
|
||||
# Container rules
|
||||
container_rule: Mapped[Optional[str]] = mapped_column(String(50)) # CONTENEDORREGLA
|
||||
container_parts_ii: Mapped[Optional[str]] = mapped_column(String(50)) # CONTENEDORPARTESII
|
||||
|
||||
# APHIS
|
||||
consecutive_aphis: Mapped[Optional[int]] = mapped_column(Integer) # CONSECUTIVOAPHIS
|
||||
|
||||
# BOM/Commercial
|
||||
bom_version: Mapped[Optional[int]] = mapped_column(Integer) # VERSIONBOM
|
||||
bill_version: Mapped[Optional[int]] = mapped_column(Integer) # VERSIONBILL
|
||||
|
||||
# TLCAN value
|
||||
tlcan_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTLCAN
|
||||
|
||||
# Identifier
|
||||
identifier: Mapped[Optional[str]] = mapped_column(String(2)) # IDENTIFICADOR
|
||||
|
||||
# Validation fields
|
||||
validation_zero: Mapped[Optional[int]] = mapped_column(Integer) # VALIDACIONZERO
|
||||
validation_one: Mapped[Optional[int]] = mapped_column(Integer) # VALIDACIONUNO
|
||||
|
||||
# Material type
|
||||
material_type: Mapped[Optional[str]] = mapped_column(String(50)) # TIPOMAT/TIPODENUMPARTE
|
||||
|
||||
# Order concept
|
||||
order_type: Mapped[Optional[str]] = mapped_column(String(50)) # TIPODEORDEN
|
||||
line_concept: Mapped[Optional[str]] = mapped_column(String(50)) # CONCEPTODELAPARTIDA
|
||||
|
||||
# Review dispatch
|
||||
review_dispatch: Mapped[Optional[str]] = mapped_column(String(10)) # REVISARDESP
|
||||
|
||||
# Take component from PT
|
||||
take_component_pt: Mapped[Optional[int]] = mapped_column(Integer) # TOMARCOMOPT
|
||||
|
||||
# Pallet
|
||||
pallet2: Mapped[Optional[int]] = mapped_column(SmallInteger) # PALLET2
|
||||
|
||||
# Wildcard field
|
||||
wildcard_field: Mapped[Optional[str]] = mapped_column(String(100)) # CAMPOCOMODIN
|
||||
|
||||
# Relationships
|
||||
item: Mapped["Item"] = relationship(back_populates="lines")
|
||||
|
||||
class LineFinancial(Base):
|
||||
"""
|
||||
Financial details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_financials"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Costs - Capture
|
||||
unit_cost_capture: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOCAPTURA
|
||||
|
||||
# Costs - USD
|
||||
unit_cost_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIODLLS/COSTOUNITARIOME
|
||||
unit_cost_commercial_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUCOMDLLS
|
||||
unit_cost_current_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOACTUALDLLS
|
||||
unit_cost_depreciated_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTODEPRECME
|
||||
unit_cost_subitem_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOSUBPDLLS
|
||||
unit_cost_auxiliary_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUAUXILIARME
|
||||
sales_cost_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOVENTAME
|
||||
commercial_unit_cost: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNICOMERCIAL
|
||||
|
||||
# Costs - MXN
|
||||
unit_cost_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOPESOS/COSTOUNITARIOMN
|
||||
unit_cost_commercial_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUCOMPESOS
|
||||
unit_cost_current_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOACTUALMN
|
||||
unit_cost_depreciated_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTODEPRECMN
|
||||
unit_cost_subitem_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOUNITARIOSUBPPESOS
|
||||
sales_cost_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # COSTOVENTAMN
|
||||
|
||||
# Costs - MC (Custom Currency)
|
||||
unit_cost_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # COSTOUNITARIOMC
|
||||
|
||||
# Values - MXN
|
||||
value_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMN/VALORIMPOMN/VALOREXPOMN
|
||||
value_commercial_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALOREXPOCOMMN
|
||||
value_updated_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORACTUALIZADOMN
|
||||
value_subitem_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORSUBPMN
|
||||
sub_import_value_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # SUBVALORIMPOMN
|
||||
value_returned_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORRETORNADOMN
|
||||
value_depreciated_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORDEPRECIADOMN
|
||||
customs_value_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORADUANASMN
|
||||
value_total_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALMN
|
||||
value_temp_material_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPTEMPMN
|
||||
value_def_material_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPDEFMN
|
||||
value_added_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORAGREMN
|
||||
value_national_packing_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUENACMN
|
||||
vat_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # IVAIMPOMN/IVAEXPOMN/VALORIVAMN
|
||||
vat_used_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORIVAMNUSADO
|
||||
advalorem_line_mxn: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # ADVALORMNLINEAPED
|
||||
|
||||
# Values - USD
|
||||
value_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # VALORME/VALORIMPOME/VALOREXPOME
|
||||
value_commercial_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALOREXPOCOMME
|
||||
value_updated_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORACTUALIZADOME
|
||||
value_subitem_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORSUBPME
|
||||
sub_import_value_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # SUBVALORIMPOME
|
||||
value_returned_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORRETORNADOME
|
||||
value_depreciated_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORDEPRECIADOME
|
||||
customs_value_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORADUANASME
|
||||
value_auxiliary_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORIMPOAUXILIARME / VALOREXPORAUXILIARME
|
||||
value_total_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALME
|
||||
value_temp_material_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPTEMPME
|
||||
value_def_material_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPDEFME
|
||||
value_added_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORAGREME
|
||||
value_national_packing_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUENACME
|
||||
value_us_packing_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUEUSME
|
||||
vat_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # IVAIMPOME/IVAEXPOME/VALORIVAME
|
||||
vat_used_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORIVAMEUSADO
|
||||
value_non_originating_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORNOORIGINARIOME
|
||||
value_originating_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORORIGINARIOME
|
||||
igi_amount_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # MONTOIGIME
|
||||
exempt_amount_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # MONTOEXCENTOME
|
||||
total_commercial_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALCOMERCIAL
|
||||
advalorem_line_usd: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # ADVALORMELINEAPED
|
||||
|
||||
# Values - MC
|
||||
value_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(29, 8)) # VALORIMPOMC/VALOREXPOMC
|
||||
sub_import_value_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # SUBVALORIMPOMC
|
||||
vat_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # IVAIMPOMC/IVAEXPOMC
|
||||
value_added_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORAGREMC
|
||||
value_national_packing_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALEMPAQUENACMC
|
||||
value_total_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORTOTALMC
|
||||
value_temp_material_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPTEMPMC
|
||||
value_def_material_mc: Mapped[Optional[Decimal]] = mapped_column(Numeric(23, 8)) # VALORMPDEFMC
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineQuantity(Base):
|
||||
"""
|
||||
Quantity details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_quantities"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Quantities
|
||||
quantity: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTIMPO / CANTEXPO / CANTIMPODEF
|
||||
alternate_quantity: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTALTERNA
|
||||
quantity_uma: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTIMPOUMA / CANTEXPOUMA
|
||||
auxiliary_quantity: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTIMPOAUXILIAR / CANTEXPOAUXILIAR
|
||||
|
||||
# Quantities - Special (SCAF specific)
|
||||
quantity_temp_export: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTEXPOTEMP
|
||||
quantity_existence: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTEXISTENCIA
|
||||
quantity_returned: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTRETORNADA
|
||||
quantity_returned_temp: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # CANTRETORNADATEMP
|
||||
serial_count: Mapped[Optional[int]] = mapped_column(Integer) # CANT_SERIES/CANT_SERIESDEF
|
||||
|
||||
# Weight
|
||||
weight_unit: Mapped[Optional[str]] = mapped_column(String(3)) # 'KG' o 'LB'
|
||||
net_weight: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # PESONETO
|
||||
gross_weight: Mapped[Optional[Decimal]] = mapped_column(Numeric(19, 8)) # PESOBRUTO
|
||||
|
||||
# Packaging
|
||||
package_key: Mapped[Optional[str]] = mapped_column(String(5)) # CLAVEBULTOS
|
||||
package_quantity: Mapped[Optional[int]] = mapped_column(Integer) # CANTBULTOS
|
||||
package_description: Mapped[Optional[str]] = mapped_column(String(40)) # DESCBULTOS
|
||||
container_quantity: Mapped[Optional[int]] = mapped_column(SmallInteger) # CANTBULCONT
|
||||
container_description: Mapped[Optional[str]] = mapped_column(String(40)) # DESCCONTENEDOR
|
||||
box_count: Mapped[Optional[str]] = mapped_column(String(30)) # NOCAJAS
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineCustoms(Base):
|
||||
"""
|
||||
Customs details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_customs"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Tariff/Customs Classifications
|
||||
fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCION / FRACCIONIMPO / FRACCIONEXPO
|
||||
fraction_type: Mapped[Optional[str]] = mapped_column(String(7)) # TIPOFRACCION / TIPOFRACCIONIMPO / TIPOFRACCIONEXPO
|
||||
american_fraction: Mapped[Optional[str]] = mapped_column(String(16)) # FRACCIONAMERICANA
|
||||
alternate_fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCIONALTERNA
|
||||
reference_fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCIONREFERENCIA
|
||||
octave_fraction: Mapped[Optional[str]] = mapped_column(String(10)) # FRACCIONROCTAVA
|
||||
tlcan_fraction: Mapped[Optional[str]] = mapped_column(String(13)) # FRACCIONTLCAN
|
||||
extra_american_fraction: Mapped[Optional[str]] = mapped_column(String(16)) # FRACAMESELEXTRA
|
||||
garment_fraction: Mapped[Optional[str]] = mapped_column(String(19)) # FRACCIONDELAPRENDA/FRACCIONDELAPARTIDA
|
||||
|
||||
# Ad Valorem
|
||||
advalorem: Mapped[Optional[str]] = mapped_column(String(10)) # ADVIMPO / ADVEXPO
|
||||
advalorem_numeric: Mapped[Optional[Decimal]] = mapped_column(Numeric(7, 2)) # ADVIMPONUM / ADVEXPONUM
|
||||
advalorem_american: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2)) # ADVAME
|
||||
advalorem_tlcan: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2)) # ADVTLCAN
|
||||
|
||||
# Rates
|
||||
rate: Mapped[Optional[str]] = mapped_column(String(10)) # TASAIM / TASAEX
|
||||
depreciation_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2)) # TASADEPRECIA
|
||||
|
||||
# Origin/Destination
|
||||
origin_country: Mapped[Optional[str]] = mapped_column(String(3)) # PAISORIGEN
|
||||
destination_country: Mapped[Optional[str]] = mapped_column(String(3)) # PAISDESTINO
|
||||
optional_country: Mapped[Optional[str]] = mapped_column(String(3)) # PAISOPCIONAL
|
||||
origin_procedure: Mapped[Optional[str]] = mapped_column(String(3)) # PROCEDENCIA
|
||||
scrap_procedure: Mapped[Optional[str]] = mapped_column(String(3)) # PROCSCRAP
|
||||
|
||||
# Sector
|
||||
sector: Mapped[Optional[str]] = mapped_column(String(8)) # SECTOR
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineDescription(Base):
|
||||
"""
|
||||
Description details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_descriptions"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
# Descriptions
|
||||
description_spanish: Mapped[Optional[str]] = mapped_column(String(4999)) # DESCRIPCIONE
|
||||
description_english: Mapped[Optional[str]] = mapped_column(String(4999)) # DESCRIPCIONI
|
||||
extra_description: Mapped[Optional[str]] = mapped_column(Text) # DESCRIPCIONEEXTRA
|
||||
part_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONPARTE
|
||||
class_description: Mapped[Optional[str]] = mapped_column(String(500)) # DESCRIPCIONCLASE
|
||||
|
||||
# Product attributes
|
||||
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA
|
||||
model: Mapped[Optional[str]] = mapped_column(String(50)) # MODELO
|
||||
has_serial: Mapped[Optional[bool]] = mapped_column(Boolean) # LLEVASERIE
|
||||
|
||||
# Additional information
|
||||
additional_info_spanish: Mapped[Optional[str]] = mapped_column(String(1000)) # INFOADICIONESP
|
||||
additional_info_english: Mapped[Optional[str]] = mapped_column(String(1000)) # INFOADICIONING
|
||||
|
||||
# Lot and entry tracking
|
||||
lot: Mapped[Optional[str]] = mapped_column(String(254)) # LOTE
|
||||
entry_number: Mapped[Optional[str]] = mapped_column(String(50)) # NUMENTRADA/NUMERODEENTRADA
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
class LineReference(Base):
|
||||
"""
|
||||
Reference details for line items
|
||||
Consolidates all line-level data from Q and S tables
|
||||
"""
|
||||
__tablename__ = "line_references"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id"))
|
||||
|
||||
serie_id: Mapped[Optional[int]] = mapped_column(ForeignKey("a76.item_line_series.id")) # SERIEPARTIDA
|
||||
|
||||
# Customer/Vendor
|
||||
customer_invoice: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # CLIENTEFACTURAR
|
||||
assigned_client: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # CLIENTEASIGNADO
|
||||
supplier: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # PROVEEDOR
|
||||
requisitioner: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # REQUISITOR
|
||||
sent_to: Mapped[Optional[str]] = mapped_column(ForeignKey("a76.clients_and_providers.id")) # ENVIADOA
|
||||
|
||||
# PED line reference
|
||||
ped_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEAPED
|
||||
ro_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEARO
|
||||
|
||||
# Relationship
|
||||
item_line: Mapped["LineItem"] = relationship()
|
||||
|
||||
# ============================================================================
|
||||
# SUPPORTING TABLES
|
||||
# ============================================================================
|
||||
|
||||
class PackingList(Base):
|
||||
"""
|
||||
Packing list items
|
||||
From: SPartidasPackingList
|
||||
"""
|
||||
__tablename__ = "packing_lists"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
item_line_id: Mapped[int] = mapped_column(Integer) # LINEA
|
||||
packing_list_number: Mapped[Optional[str]] = mapped_column(String(100)) # NUMPACKINGLIST
|
||||
|
||||
|
||||
class RepairPart(Base):
|
||||
"""
|
||||
Repair parts (orphan table without primary key in original)
|
||||
From: SPartidasRep
|
||||
"""
|
||||
__tablename__ = "repair_parts"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
import_line: Mapped[int] = mapped_column(Integer) # LINEAIMPO
|
||||
|
||||
|
||||
class CTMShipment(Base):
|
||||
"""
|
||||
CTM Shipment lines (temporary manufacturing)
|
||||
From: SPartidasEnviaCTM
|
||||
"""
|
||||
__tablename__ = "ctm_shipments"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
shipment_line: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEAENVIO
|
||||
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA
|
||||
model: Mapped[Optional[str]] = mapped_column(String(50)) # MODELO
|
||||
serial_numbers: Mapped[Optional[str]] = mapped_column(String(50)) # SERIES
|
||||
|
||||
|
||||
class CTMReceipt(Base):
|
||||
"""
|
||||
CTM Receipt lines (temporary manufacturing)
|
||||
From: SPartidasReciboCTM
|
||||
"""
|
||||
__tablename__ = "ctm_receipts"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
receipt_line: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEARECIBO
|
||||
|
||||
option: Mapped[Optional[str]] = mapped_column(String(3)) # OPCION
|
||||
exit_invoice: Mapped[Optional[str]] = mapped_column(String(19)) # FACTURASALIDA
|
||||
|
||||
|
||||
class SubassemblyEntry(Base):
|
||||
"""
|
||||
Subassembly/Submanufacturing Entry lines
|
||||
From: SPartidasEntradaSM
|
||||
"""
|
||||
__tablename__ = "subassembly_entries"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
remission_line: Mapped[int] = mapped_column(Integer) # LINEAREMISION
|
||||
exit_invoice: Mapped[Optional[str]] = mapped_column(String(15)) # FACTURASALIDA
|
||||
exit_line: Mapped[Optional[int]] = mapped_column(Integer) # LINEASALIDA
|
||||
|
||||
|
||||
class SubassemblyExit(Base):
|
||||
"""
|
||||
Subassembly/Submanufacturing Exit lines
|
||||
From: SPartidasSalidaSM
|
||||
"""
|
||||
__tablename__ = "subassembly_exits"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
exit_line: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEASALIDA
|
||||
|
||||
|
||||
class ImpositionPart(Base):
|
||||
"""
|
||||
Imposition parts (orphan table without primary key constraint)
|
||||
From: SPartidasImposion
|
||||
"""
|
||||
__tablename__ = "imposition_parts"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
import_line: Mapped[int] = mapped_column(Integer) # LINEAIMPO
|
||||
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# INDEXES AND CONSTRAINTS
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
Recommended indexes for optimal query performance:
|
||||
|
||||
CREATE INDEX idx_items_consecutive ON items(consecutive);
|
||||
CREATE INDEX idx_items_invoice ON items(invoice_number);
|
||||
CREATE INDEX idx_items_type_system ON items(item_type, system_origin);
|
||||
CREATE INDEX idx_items_dates ON items(invoice_date, depreciation_date);
|
||||
|
||||
CREATE INDEX idx_lines_item ON item_lines(item_id);
|
||||
CREATE INDEX idx_lines_part ON item_lines(part_number);
|
||||
CREATE INDEX idx_lines_class ON item_lines(class_code);
|
||||
CREATE INDEX idx_lines_invoice_refs ON item_lines(import_invoice, export_invoice);
|
||||
CREATE INDEX idx_lines_fractions ON item_lines(import_fraction, export_fraction);
|
||||
|
||||
CREATE INDEX idx_packing_consecutive ON packing_lists(consecutive);
|
||||
CREATE INDEX idx_packing_part ON packing_lists(part_number);
|
||||
|
||||
CREATE INDEX idx_repair_invoice ON repair_parts(import_invoice, import_line);
|
||||
CREATE INDEX idx_ctm_ship_consec ON ctm_shipments(consecutive);
|
||||
CREATE INDEX idx_ctm_rcpt_consec ON ctm_receipts(consecutive);
|
||||
CREATE INDEX idx_sub_entry_consec ON subassembly_entries(consecutive);
|
||||
CREATE INDEX idx_sub_exit_consec ON subassembly_exits(consecutive);
|
||||
CREATE INDEX idx_imposition_consec ON imposition_parts(consecutive);
|
||||
"""
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# MIGRATION NOTES
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
MIGRATION STRATEGY FROM ORIGINAL TABLES TO NORMALIZED SCHEMA:
|
||||
|
||||
1. DOCUMENT MAPPING:
|
||||
- QEqeMaq (Equipment Import Temp) → items (type='EQUIPMENT_IMPORT_TEMP', system='SCAF')
|
||||
- QEqeMaqRep (Equipment Repair Export) → items (type='EQUIPMENT_REPAIR_EXPORT', system='SCAF')
|
||||
- QEqiDef (Equipment Import Definitive) → items (type='EQUIPMENT_IMPORT_DEF', system='SCAF')
|
||||
- QEqiMaq (Equipment Machinery) → items (type='EQUIPMENT_MACHINERY', system='SCAF')
|
||||
- QEqiMaqRep (Equipment Machinery Repair) → items (type='EQUIPMENT_REPAIR_IMPORT', system='SCAF')
|
||||
- SPartidasCM (Common Commerce) → items (type='COMMON_COMMERCE', system='SCAII')
|
||||
- SPartidasExpo (Export) → items (type='EXPORT', system='SCAII')
|
||||
- SPartidasImpo (Import) → items (type='IMPORT', system='SCAII')
|
||||
|
||||
2. LINE MAPPING:
|
||||
All line items from Q* and SPartidas* tables map to item_lines with appropriate
|
||||
field mapping based on the original column names (preserved as comments).
|
||||
|
||||
3. FIELD CONSOLIDATION RULES:
|
||||
- Costs: Unified under unit_cost_* with currency suffix (usd/mxn/mc)
|
||||
- Values: Unified under value_* with currency suffix
|
||||
- Quantities: Unified under quantity_* with specific purpose suffixes
|
||||
- Descriptions: Consolidated into description_spanish/english/extra
|
||||
- Fractions: All fraction fields preserved with clear naming
|
||||
|
||||
4. DATA INTEGRITY:
|
||||
- Original CONSECUTIVO + LINE number preserved for traceability
|
||||
- Foreign key relationships established via item_id
|
||||
- All original fields retained to prevent data loss
|
||||
|
||||
5. SPECIAL TABLES:
|
||||
- PackingList, RepairPart, CTM*, Subassembly*, ImpositionPart remain separate
|
||||
as they serve specific purposes and don't fit the main item/line pattern
|
||||
|
||||
6. BENEFITS:
|
||||
- Eliminates redundancy across 13 original tables
|
||||
- Unified query interface for all operations
|
||||
- Maintains full audit trail with original field names
|
||||
- Enables cross-system reporting (SCAF + SCAII)
|
||||
- Simplifies maintenance with single schema
|
||||
|
||||
7. QUERYING EXAMPLES:
|
||||
```python
|
||||
# Get all imports (both systems)
|
||||
session.query(Item).filter(
|
||||
Item.item_type.in_(['IMPORT', 'EQUIPMENT_IMPORT_TEMP', 'EQUIPMENT_IMPORT_DEF'])
|
||||
)
|
||||
|
||||
# Get all lines for a specific part across all items
|
||||
session.query(LineItem).filter(
|
||||
LineItem.part_number == 'ABC123'
|
||||
)
|
||||
|
||||
# Get SCAF equipment with depreciation
|
||||
session.query(Item).join(LineItem).filter(
|
||||
Item.system_origin == 'SCAF',
|
||||
LineItem.value_depreciated_usd.isnot(None)
|
||||
)
|
||||
```
|
||||
"""
|
||||
23
backend/api/v1/modules/a76/items/series/models.py
Normal file
23
backend/api/v1/modules/a76/items/series/models.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from typing import Optional
|
||||
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, Numeric, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from core.database import Base
|
||||
|
||||
class Serie(Base):
|
||||
__tablename__ = "item_line_series"
|
||||
__table_args__ = {
|
||||
"schema": "a76",
|
||||
}
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
line_item_id: Mapped[int] = mapped_column(ForeignKey("a76.item_lines.id")) # LINEAIMPO / LINEAEXPO
|
||||
row: Mapped[int] = mapped_column(Integer) # RENGLON
|
||||
serial_numbers: Mapped[Optional[str]] = mapped_column(String(50)) # SERIEEXPO
|
||||
model: Mapped[Optional[str]] = mapped_column(String(50)) # MODELOEXPO
|
||||
sub_model: Mapped[Optional[str]] = mapped_column(String(50)) # SUBMODELOEXPO
|
||||
brand: Mapped[Optional[str]] = mapped_column(String(50)) # MARCA
|
||||
expo_brad: Mapped[Optional[str]] = mapped_column(String(50)) # MARCAEXPO
|
||||
number_id: Mapped[Optional[str]] = mapped_column(String(25)) # NUMIDEXPO
|
||||
|
||||
|
||||
|
||||
@@ -9,12 +9,10 @@ from typing import TYPE_CHECKING, Optional
|
||||
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
|
||||
from core.database import Base
|
||||
from sqlalchemy import (
|
||||
ForeignKey,
|
||||
ForeignKeyConstraint,
|
||||
Integer,
|
||||
Numeric,
|
||||
PrimaryKeyConstraint,
|
||||
SmallInteger,
|
||||
String,
|
||||
UniqueConstraint,
|
||||
Boolean,
|
||||
@@ -57,7 +55,7 @@ class Part(Base, TenantScopedMixin, TimestampMixin):
|
||||
|
||||
# Unique constraint compuesta
|
||||
client_id: Mapped[int] = mapped_column(Integer)
|
||||
part_number: Mapped[str] = mapped_column(String(49))
|
||||
part_number: Mapped[str] = mapped_column(String(50))
|
||||
|
||||
# Basic information
|
||||
fraction: Mapped[Optional[str]] = mapped_column(String(10))
|
||||
|
||||
Reference in New Issue
Block a user