Valores extendidos para partes

This commit is contained in:
2026-03-17 16:57:03 -05:00
parent 5a619e8bc4
commit adfa82c707
29 changed files with 2661 additions and 29 deletions

View File

@@ -0,0 +1,17 @@
from .inv_aphis_general.dto import InvPartAphisGeneralDTO
from .inv_aphis_characteristic.dto import InvPartAphisCharacteristicDTO
from .inv_aphis_stype_pitems.dto import InvPartAphisStypePitemsDTO
from .inv_aphis_lpcos.dto import InvPartAphisLpcosDTO
from .inv_aphis_entities.dto import InvPartAphisEntitiesDTO
from .inv_aphis_containers.dto import InvPartAphisContainersDTO
from .inv_aphis_routing.dto import InvPartAphisRoutingDTO
__all__ = [
"InvPartAphisGeneralDTO",
"InvPartAphisCharacteristicDTO",
"InvPartAphisStypePitemsDTO",
"InvPartAphisLpcosDTO",
"InvPartAphisEntitiesDTO",
"InvPartAphisContainersDTO",
"InvPartAphisRoutingDTO"
]

View File

@@ -0,0 +1,15 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import date
class InvPartAphisCharacteristicDTO(BaseModel):
id: Optional[int] = None
aphis_general_id: Optional[int] = None
item_id: Optional[str] = None
number_from: Optional[str] = None
number_to: Optional[str] = None
category_type: Optional[str] = None
commodity_qua: Optional[str] = None
commodity_char_qua: Optional[str] = None
description: Optional[str] = None
category_code: Optional[str] = None

View File

@@ -0,0 +1,35 @@
from typing import TYPE_CHECKING, Optional, List
from datetime import date
from sqlalchemy import (
Integer, String, Date, Numeric, Boolean,
PrimaryKeyConstraint, ForeignKeyConstraint
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
if TYPE_CHECKING:
from api.v1.modules.a24.inv.inv_parts.models import InvPart
class InvPartAphisCharacteristic(Base, TenantScopedMixin, TimestampMixin):
"""Módulo: Item characteristic"""
__tablename__ = "inv_aphis_characteristic"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_characteristic_pkey"),
ForeignKeyConstraint(["aphis_general_id"], ["a24.inv_aphis_general.id"]),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
aphis_general_id: Mapped[int] = mapped_column(Integer, nullable=False)
# --- CAMPOS CARACTERISTICAS ---
item_id: Mapped[Optional[str]] = mapped_column(String(50))
number_from: Mapped[Optional[str]] = mapped_column(String(50))
number_to: Mapped[Optional[str]] = mapped_column(String(50))
category_type: Mapped[Optional[str]] = mapped_column(String(50))
commodity_qua: Mapped[Optional[str]] = mapped_column(String(50))
commodity_char_qua: Mapped[Optional[str]] = mapped_column(String(50))
description: Mapped[Optional[str]] = mapped_column(String(200))
category_code: Mapped[Optional[str]] = mapped_column(String(50))
aphis_general: Mapped["InvPartAphisGeneral"] = relationship(back_populates="characteristics")

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import date
class InvPartAphisContainersDTO(BaseModel):
id: Optional[int] = None
aphis_general_id: Optional[int] = None
container_number: Optional[str] = None
length: Optional[str] = None
type: Optional[str] = None

View File

@@ -0,0 +1,30 @@
from typing import TYPE_CHECKING, Optional, List
from datetime import date
from sqlalchemy import (
Integer, String, Date, Numeric, Boolean,
PrimaryKeyConstraint, ForeignKeyConstraint
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
if TYPE_CHECKING:
from api.v1.modules.a24.inv.inv_parts.models import InvPart
class InvPartAphisContainers(Base, TenantScopedMixin, TimestampMixin):
"""Módulo: containers"""
__tablename__ = "inv_aphis_containers"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_containers_pkey"),
ForeignKeyConstraint(["aphis_general_id"], ["a24.inv_aphis_general.id"]),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
aphis_general_id: Mapped[int] = mapped_column(Integer, nullable=False)
# --- CAMPOS CONTAINERS ---
container_number: Mapped[Optional[str]] = mapped_column(String(50))
length: Mapped[Optional[str]] = mapped_column(String(20))
type: Mapped[Optional[str]] = mapped_column(String(50))
aphis_general: Mapped["InvPartAphisGeneral"] = relationship(back_populates="containers")

View File

@@ -0,0 +1,11 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import date
class InvPartAphisEntitiesDTO(BaseModel):
id: Optional[int] = None
aphis_general_id: Optional[int] = None
consignee_key: Optional[str] = None
broker_key: Optional[str] = None
lpco_auth_party_key: Optional[str] = None
grower_key: Optional[str] = None

View File

@@ -0,0 +1,31 @@
from typing import TYPE_CHECKING, Optional, List
from datetime import date
from sqlalchemy import (
Integer, String, Date, Numeric, Boolean,
PrimaryKeyConstraint, ForeignKeyConstraint
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
if TYPE_CHECKING:
from api.v1.modules.a24.inv.inv_parts.models import InvPart
class InvPartAphisEntities(Base, TenantScopedMixin, TimestampMixin):
"""Módulo: entities"""
__tablename__ = "inv_aphis_entities"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_entities_pkey"),
ForeignKeyConstraint(["aphis_general_id"], ["a24.inv_aphis_general.id"]),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
aphis_general_id: Mapped[int] = mapped_column(Integer, nullable=False)
# --- CAMPOS ENTITIES ---
consignee_key: Mapped[Optional[str]] = mapped_column(String(50))
broker_key: Mapped[Optional[str]] = mapped_column(String(50))
lpco_auth_party_key: Mapped[Optional[str]] = mapped_column(String(50))
grower_key: Mapped[Optional[str]] = mapped_column(String(50))
aphis_general: Mapped["InvPartAphisGeneral"] = relationship(back_populates="entities")

View File

@@ -0,0 +1,54 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import date
from ..inv_aphis_characteristic.dto import InvPartAphisCharacteristicDTO
from ..inv_aphis_stype_pitems.dto import InvPartAphisStypePitemsDTO
from ..inv_aphis_lpcos.dto import InvPartAphisLpcosDTO
from ..inv_aphis_entities.dto import InvPartAphisEntitiesDTO
from ..inv_aphis_containers.dto import InvPartAphisContainersDTO
from ..inv_aphis_routing.dto import InvPartAphisRoutingDTO
# NOTA: Importar primero los sub-dtos para resolver dependencias
class InvPartAphisGeneralDTO(BaseModel):
id: Optional[int] = None
program_code: Optional[str] = None
processing_code: Optional[str] = None
aphis_type: Optional[str] = None
disclaimer: Optional[str] = None
electronic_image: Optional[str] = None
confidential: Optional[str] = None
global_product_id: Optional[str] = None
intended_use_code: Optional[str] = None
intended_use_description: Optional[str] = None
item_type: Optional[str] = None
product_code: Optional[str] = None
product_code_2: Optional[str] = None
product_code_3: Optional[str] = None
scientific_genus_name: Optional[str] = None
scientific_species_name: Optional[str] = None
scientific_sub_species_name: Optional[str] = None
common_name_specific: Optional[str] = None
common_name_general: Optional[str] = None
signed_doc: Optional[str] = None
signed_doc_date: Optional[date] = None
signed_doc_id: Optional[str] = None
invoice_number: Optional[str] = None
quantity_1: Optional[str] = None
quantity_2: Optional[str] = None
quantity_3: Optional[str] = None
inspection: Optional[str] = None
inspection_date: Optional[date] = None
inspection_loc_date: Optional[date] = None
inspection_location: Optional[str] = None
country_production: Optional[str] = None
country_source: Optional[str] = None
# Relaciones
characteristics: List[InvPartAphisCharacteristicDTO] = []
stype_pitems: List[InvPartAphisStypePitemsDTO] = []
lpcos: List[InvPartAphisLpcosDTO] = []
entities: List[InvPartAphisEntitiesDTO] = []
containers: List[InvPartAphisContainersDTO] = []
routing: List[InvPartAphisRoutingDTO] = []

View File

@@ -0,0 +1,72 @@
from typing import TYPE_CHECKING, Optional, List
from datetime import date
from sqlalchemy import (
Integer, String, Date, Numeric, Boolean,
PrimaryKeyConstraint, ForeignKeyConstraint
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
if TYPE_CHECKING:
from api.v1.modules.a24.inv.inv_parts.models import InvPart
class InvPartAphisGeneral(Base, TenantScopedMixin, TimestampMixin):
"""
Tabla principal de Aphis vinculada a la parte.
Pestaña: Información general de aphis
"""
__tablename__ = "inv_aphis_general"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_general_pkey"),
ForeignKeyConstraint(
["inv_part_id"], ["a24.inv_partes.id"], name="fk_aphis_general_inv_part"
),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
inv_part_id: Mapped[int] = mapped_column(Integer, nullable=False)
# --- 31 CAMPOS INICIALES ---
program_code: Mapped[Optional[str]] = mapped_column(String(10))
processing_code: Mapped[Optional[str]] = mapped_column(String(10))
aphis_type: Mapped[Optional[str]] = mapped_column(String(10))
disclaimer: Mapped[Optional[str]] = mapped_column(String(10))
electronic_image: Mapped[Optional[str]] = mapped_column(String(50))
confidential: Mapped[Optional[str]] = mapped_column(String(1))
global_product_id: Mapped[Optional[str]] = mapped_column(String(100))
intended_use_code: Mapped[Optional[str]] = mapped_column(String(10))
intended_use_description: Mapped[Optional[str]] = mapped_column(String(200))
item_type: Mapped[Optional[str]] = mapped_column(String(20))
product_code: Mapped[Optional[str]] = mapped_column(String(20))
product_code_2: Mapped[Optional[str]] = mapped_column(String(20))
product_code_3: Mapped[Optional[str]] = mapped_column(String(20))
scientific_genus_name: Mapped[Optional[str]] = mapped_column(String(100))
scientific_species_name: Mapped[Optional[str]] = mapped_column(String(100))
scientific_sub_species_name: Mapped[Optional[str]] = mapped_column(String(100))
common_name_specific: Mapped[Optional[str]] = mapped_column(String(200))
common_name_general: Mapped[Optional[str]] = mapped_column(String(200))
signed_doc: Mapped[Optional[str]] = mapped_column(String(100))
signed_doc_date: Mapped[Optional[date]] = mapped_column(Date)
signed_doc_id: Mapped[Optional[str]] = mapped_column(String(50))
invoice_number: Mapped[Optional[str]] = mapped_column(String(50))
quantity_1: Mapped[Optional[str]] = mapped_column(String(50))
quantity_2: Mapped[Optional[str]] = mapped_column(String(50))
quantity_3: Mapped[Optional[str]] = mapped_column(String(50))
inspection: Mapped[Optional[str]] = mapped_column(String(200))
inspection_date: Mapped[Optional[date]] = mapped_column(Date)
inspection_loc_date: Mapped[Optional[date]] = mapped_column(Date)
inspection_location: Mapped[Optional[str]] = mapped_column(String(200))
country_production: Mapped[Optional[str]] = mapped_column(String(3))
country_source: Mapped[Optional[str]] = mapped_column(String(3))
# Relaciones
inv_part: Mapped["InvPart"] = relationship("InvPart", back_populates="aphis_records")
characteristics: Mapped[List["InvPartAphisCharacteristic"]] = relationship(back_populates="aphis_general", cascade="all, delete-orphan")
stype_pitems: Mapped[List["InvPartAphisStypePitems"]] = relationship(back_populates="aphis_general", cascade="all, delete-orphan")
lpcos: Mapped[List["InvPartAphisLpcos"]] = relationship(back_populates="aphis_general", cascade="all, delete-orphan")
entities: Mapped[List["InvPartAphisEntities"]] = relationship(back_populates="aphis_general", cascade="all, delete-orphan")
containers: Mapped[List["InvPartAphisContainers"]] = relationship(back_populates="aphis_general", cascade="all, delete-orphan")
routing: Mapped[List["InvPartAphisRouting"]] = relationship(back_populates="aphis_general", cascade="all, delete-orphan")

View File

@@ -0,0 +1,18 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import date
class InvPartAphisLpcosDTO(BaseModel):
id: Optional[int] = None
aphis_general_id: Optional[int] = None
issuer: Optional[str] = None
issuer_loc_qua: Optional[str] = None
issuer_loc: Optional[str] = None
issuer_loc_desc: Optional[str] = None
uom: Optional[str] = None
txn_type: Optional[str] = None
type: Optional[str] = None
number: Optional[str] = None
date_qual: Optional[str] = None
date: Optional[date] = None
qty: Optional[str] = None

View File

@@ -0,0 +1,38 @@
from typing import TYPE_CHECKING, Optional, List
from datetime import date
from sqlalchemy import (
Integer, String, Date, Numeric, Boolean,
PrimaryKeyConstraint, ForeignKeyConstraint
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
if TYPE_CHECKING:
from api.v1.modules.a24.inv.inv_parts.models import InvPart
class InvPartAphisLpcos(Base, TenantScopedMixin, TimestampMixin):
"""Módulo: lpcos"""
__tablename__ = "inv_aphis_lpcos"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_lpcos_pkey"),
ForeignKeyConstraint(["aphis_general_id"], ["a24.inv_aphis_general.id"]),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
aphis_general_id: Mapped[int] = mapped_column(Integer, nullable=False)
# --- CAMPOS LPCO ---
issuer: Mapped[Optional[str]] = mapped_column(String(100))
issuer_loc_qua: Mapped[Optional[str]] = mapped_column(String(50))
issuer_loc: Mapped[Optional[str]] = mapped_column(String(50))
issuer_loc_desc: Mapped[Optional[str]] = mapped_column(String(200))
uom: Mapped[Optional[str]] = mapped_column(String(20))
txn_type: Mapped[Optional[str]] = mapped_column(String(50))
type: Mapped[Optional[str]] = mapped_column(String(50))
number: Mapped[Optional[str]] = mapped_column(String(50))
date_qual: Mapped[Optional[str]] = mapped_column(String(50))
date: Mapped[Optional[date]] = mapped_column(Date)
qty: Mapped[Optional[str]] = mapped_column(String(50))
aphis_general: Mapped["InvPartAphisGeneral"] = relationship(back_populates="lpcos")

View File

@@ -0,0 +1,10 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import date
class InvPartAphisRoutingDTO(BaseModel):
id: Optional[int] = None
aphis_general_id: Optional[int] = None
type: Optional[str] = None
country: Optional[str] = None
name: Optional[str] = None

View File

@@ -0,0 +1,30 @@
from typing import TYPE_CHECKING, Optional, List
from datetime import date
from sqlalchemy import (
Integer, String, Date, Numeric, Boolean,
PrimaryKeyConstraint, ForeignKeyConstraint
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
if TYPE_CHECKING:
from api.v1.modules.a24.inv.inv_parts.models import InvPart
class InvPartAphisRouting(Base, TenantScopedMixin, TimestampMixin):
"""Módulo: routing"""
__tablename__ = "inv_aphis_routing"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_routing_pkey"),
ForeignKeyConstraint(["aphis_general_id"], ["a24.inv_aphis_general.id"]),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
aphis_general_id: Mapped[int] = mapped_column(Integer, nullable=False)
# --- CAMPOS ROUTING ---
type: Mapped[Optional[str]] = mapped_column(String(50))
country: Mapped[Optional[str]] = mapped_column(String(50))
name: Mapped[Optional[str]] = mapped_column(String(100))
aphis_general: Mapped["InvPartAphisGeneral"] = relationship(back_populates="routing")

View File

@@ -0,0 +1,14 @@
from pydantic import BaseModel
from typing import Optional, List
from datetime import date
class InvPartAphisStypePitemsDTO(BaseModel):
id: Optional[int] = None
aphis_general_id: Optional[int] = None
source_type_code: Optional[str] = None
country_code: Optional[str] = None
geo_location: Optional[str] = None
processing_start: Optional[date] = None
processing_end: Optional[date] = None
processing_type: Optional[str] = None
processing_desc: Optional[str] = None

View File

@@ -0,0 +1,34 @@
from typing import TYPE_CHECKING, Optional, List
from datetime import date
from sqlalchemy import (
Integer, String, Date, Numeric, Boolean,
PrimaryKeyConstraint, ForeignKeyConstraint
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
if TYPE_CHECKING:
from api.v1.modules.a24.inv.inv_parts.models import InvPart
class InvPartAphisStypePitems(Base, TenantScopedMixin, TimestampMixin):
"""Módulo: stype_Pitems"""
__tablename__ = "inv_aphis_stype_pitems"
__table_args__ = (
PrimaryKeyConstraint("id", name="inv_aphis_stype_pitems_pkey"),
ForeignKeyConstraint(["aphis_general_id"], ["a24.inv_aphis_general.id"]),
{"schema": "a24", "extend_existing": True},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
aphis_general_id: Mapped[int] = mapped_column(Integer, nullable=False)
# --- CAMPOS STYPE PITEMS ---
source_type_code: Mapped[Optional[str]] = mapped_column(String(50))
country_code: Mapped[Optional[str]] = mapped_column(String(3))
geo_location: Mapped[Optional[str]] = mapped_column(String(100))
processing_start: Mapped[Optional[date]] = mapped_column(Date)
processing_end: Mapped[Optional[date]] = mapped_column(Date)
processing_type: Mapped[Optional[str]] = mapped_column(String(50))
processing_desc: Mapped[Optional[str]] = mapped_column(String(200))
aphis_general: Mapped["InvPartAphisGeneral"] = relationship(back_populates="stype_pitems")

View File

@@ -0,0 +1,17 @@
from .inv_aphis_general.models import InvPartAphisGeneral
from .inv_aphis_characteristic.models import InvPartAphisCharacteristic
from .inv_aphis_stype_pitems.models import InvPartAphisStypePitems
from .inv_aphis_lpcos.models import InvPartAphisLpcos
from .inv_aphis_entities.models import InvPartAphisEntities
from .inv_aphis_containers.models import InvPartAphisContainers
from .inv_aphis_routing.models import InvPartAphisRouting
__all__ = [
"InvPartAphisGeneral",
"InvPartAphisCharacteristic",
"InvPartAphisStypePitems",
"InvPartAphisLpcos",
"InvPartAphisEntities",
"InvPartAphisContainers",
"InvPartAphisRouting"
]

View File

@@ -2,7 +2,7 @@
Modelo ORM para datos específicos de Inventario y Manufactura (S-Partes) - Anexo 24
"""
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Optional, List
from decimal import Decimal
from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
@@ -18,10 +18,10 @@ from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
if TYPE_CHECKING:
from api.v1.modules.a76.parts.models import Part
# Importar los modelos Aphis para asegurar su registro en SQLAlchemy
import api.v1.modules.a24.inv.inv_aphis.models as aphis_models
class InvPart(Base, TenantScopedMixin, TimestampMixin):
"""
Tabla inv_partes: Extensión de Anexo 24 para Inventarios (SPartes).
@@ -135,10 +135,23 @@ class InvPart(Base, TenantScopedMixin, TimestampMixin):
origin_country: Mapped[Optional[str]] = mapped_column(String(3), default='MEX')
fraction_type: Mapped[Optional[str]] = mapped_column(String(10))
# --- NUEVOS CAMPOS EXTENSION ---
agency_code_definition: Mapped[Optional[str]] = mapped_column(String(50)) # Fila 7
carta_porte: Mapped[Optional[str]] = mapped_column(String(100)) # Fila 10
client_part_names: Mapped[Optional[list]] = mapped_column(JSONB, nullable=True, default=[]) # Fila 5
part_identifiers: Mapped[Optional[list]] = mapped_column(JSONB, nullable=True, default=[]) # Fila 9
substitute_parts: Mapped[Optional[list]] = mapped_column(JSONB, nullable=True, default=[]) # Pestaña Continuación
aphis_data: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True, default={}) # Sección Aphis en Continuación
# JSONB para almacenar clientes con restricción de no descarga
non_discharge_clients: Mapped[Optional[list]] = mapped_column(JSONB, nullable=True, default=[])
# --- RELACIÓN ---
aphis_records: Mapped[List["InvPartAphisGeneral"]] = relationship(
"InvPartAphisGeneral",
back_populates="inv_part",
cascade="all, delete-orphan"
)
# Usamos string "Part" para evitar problemas de carga
master_info: Mapped["Part"] = relationship("Part", back_populates="inv_data")