feat(company): add submodels for Company including address, certification, digital certificate, electronic agent, prevalidator, and VU configurations

This commit is contained in:
Galindo97
2026-01-16 09:26:06 -06:00
parent 12f5164054
commit eb03237f44
10 changed files with 474 additions and 56 deletions

View File

@@ -1,7 +1,24 @@
"""
Módulo de Company
"""
from .models import Company
from .submodels import (
CompanyAddress,
CompanyCertification,
CompanyDigitalCertificate,
CompanyVU,
CompanyElectronicAgent,
CompanyPrevalidator,
CompanyCFDI,
)
from .routes import router
__all__ = ["router"]
__all__ = [
"Company",
"CompanyAddress",
"CompanyCertification",
"CompanyDigitalCertificate",
"CompanyVU",
"CompanyElectronicAgent",
"CompanyPrevalidator",
"CompanyCFDI",
]

View File

@@ -1,53 +1,57 @@
"""
Modelos ORM para gestión de empresa
Modelo principal de Company
"""
from typing import Optional
from api.v1.common.base_models import TimestampMixin
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, SmallInteger, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from sqlalchemy import (
Boolean,
ForeignKey,
ForeignKeyConstraint,
Integer,
PrimaryKeyConstraint,
SmallInteger,
String,
)
from sqlalchemy.orm import Mapped, mapped_column
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from .submodels.address import CompanyAddress
from .submodels.certification import CompanyCertification
from .submodels.digital_certificate import CompanyDigitalCertificate
from .submodels.ventanilla_unica import CompanyVU
from .submodels.electronic_agent import CompanyElectronicAgent
from .submodels.prevalidator import CompanyPrevalidator
from .submodels.cfdi import CompanyCFDI
class Company(Base, TimestampMixin):
"""
Modelo para la tabla Company - Información de la empresa
"""
__tablename__ = "company" #GEmpresa
__table_args__ = (
PrimaryKeyConstraint("id", name="company_pkey"),
{"schema": "a76"},
)
"""Información principal de la empresa"""
__tablename__ = "company"
__table_args__ = {"schema": "a76"}
# Primary key
id: Mapped[int] = mapped_column(Integer, primary_key=True)
tenant_id: Mapped[int] = mapped_column(Integer, ForeignKey("core.tenants.id"), nullable=False, index=True)
# Información básica de la empresa
name: Mapped[Optional[str]] = mapped_column(String(255))
tenant_id: Mapped[int] = mapped_column(
ForeignKey("core.tenants.id"),
nullable=False,
index=True
)
# Información básica
name: Mapped[Optional[str]] = mapped_column(String(256))
rfc: Mapped[Optional[str]] = mapped_column(String(30))
main_activity: Mapped[Optional[str]] = mapped_column(String(255))
# Información del programa
program: Mapped[Optional[str]] = mapped_column(String(10))
curp: Mapped[Optional[str]] = mapped_column(String(19))
main_activity: Mapped[Optional[str]] = mapped_column(String(80))
# Programa
program: Mapped[Optional[str]] = mapped_column(String(7))
program_number: Mapped[Optional[str]] = mapped_column(String(40))
prosec: Mapped[Optional[int]] = mapped_column(SmallInteger)
prosec_authorization: Mapped[Optional[str]] = mapped_column(String(20))
# Sectores
sector1: Mapped[Optional[str]] = mapped_column(String(150))
sector2: Mapped[Optional[str]] = mapped_column(String(150))
sector3: Mapped[Optional[str]] = mapped_column(String(5))
# Identificadores
manufacturer_id: Mapped[Optional[str]] = mapped_column(String(25))
broker_company: Mapped[Optional[str]] = mapped_column(String(10))
broker_company: Mapped[Optional[str]] = mapped_column(String(6))
# Responsable
responsible: Mapped[Optional[str]] = mapped_column(String(80))
responsible_name: Mapped[Optional[str]] = mapped_column(String(20))
@@ -55,24 +59,88 @@ class Company(Base, TimestampMixin):
responsible_mother_last_name: Mapped[Optional[str]] = mapped_column(String(20))
responsible_rfc: Mapped[Optional[str]] = mapped_column(String(30))
position: Mapped[Optional[str]] = mapped_column(String(30))
# Configuración
logo: Mapped[Optional[str]] = mapped_column(String(500))
has_express_line: Mapped[Optional[bool]] = mapped_column(Boolean)
# Configuración básica
logo: Mapped[Optional[str]] = mapped_column(String(255))
has_express_line: Mapped[Optional[str]] = mapped_column(String(2))
order_format_type: Mapped[Optional[str]] = mapped_column(String(19))
previous_code: Mapped[Optional[int]] = mapped_column(SmallInteger)
is_service_company: Mapped[Optional[bool]] = mapped_column(Boolean)
# Cliente y submaquila
is_service_company: Mapped[Optional[str]] = mapped_column(String(2))
client_name: Mapped[Optional[str]] = mapped_column(String(300))
subassembly_mode: Mapped[Optional[str]] = mapped_column(String(7))
# Información adicional
curp: Mapped[Optional[str]] = mapped_column(String(19))
# Configuraciones técnicas (flags)
previous_code: Mapped[Optional[int]] = mapped_column(SmallInteger)
active_labels: Mapped[Optional[int]] = mapped_column(SmallInteger)
active_fractions: Mapped[Optional[int]] = mapped_column(SmallInteger)
activate_caat: Mapped[Optional[int]] = mapped_column(SmallInteger)
trans_interface: Mapped[Optional[int]] = mapped_column(SmallInteger)
american_costs: Mapped[Optional[int]] = mapped_column(SmallInteger)
scaf_readonly: Mapped[Optional[int]] = mapped_column(SmallInteger)
parts_replacement: Mapped[Optional[int]] = mapped_column(SmallInteger)
activate_facmexame: Mapped[Optional[int]] = mapped_column(SmallInteger)
part_reference: Mapped[Optional[int]] = mapped_column(SmallInteger)
international_firm: Mapped[Optional[int]] = mapped_column(SmallInteger)
# Configuraciones simples
ftp_key: Mapped[Optional[str]] = mapped_column(String(10))
sifra_path: Mapped[Optional[str]] = mapped_column(String(255))
version_type: Mapped[Optional[str]] = mapped_column(String(20))
sql_language: Mapped[Optional[str]] = mapped_column(String(19))
balance_operation_mode: Mapped[Optional[str]] = mapped_column(String(50))
inter_db_name: Mapped[Optional[str]] = mapped_column(String(100))
ctpat_svi: Mapped[Optional[str]] = mapped_column(String(100))
trusted_exporter_number: Mapped[Optional[str]] = mapped_column(String(50))
prevalidator_key: Mapped[Optional[str]] = mapped_column(String(20))
seventh_amendment: Mapped[Optional[bool]] = mapped_column(
Boolean
) # FINALCONTADORAELECTRONICO renombrado
# ==================== RELACIONES CON SUBTABLAS ====================
addresses: Mapped[list["CompanyAddress"]] = relationship(
"CompanyAddress",
back_populates="company",
cascade="all, delete-orphan",
lazy="selectin"
)
certification: Mapped[Optional["CompanyCertification"]] = relationship(
"CompanyCertification",
back_populates="company",
uselist=False,
cascade="all, delete-orphan",
lazy="selectin"
)
digital_certificates: Mapped[list["CompanyDigitalCertificate"]] = relationship(
"CompanyDigitalCertificate",
back_populates="company",
cascade="all, delete-orphan",
lazy="selectin"
)
ventanilla_unica: Mapped[Optional["CompanyVU"]] = relationship(
"CompanyVU",
back_populates="company",
uselist=False,
cascade="all, delete-orphan",
lazy="selectin"
)
electronic_agent: Mapped[Optional["CompanyElectronicAgent"]] = relationship(
"CompanyElectronicAgent",
back_populates="company",
uselist=False,
cascade="all, delete-orphan",
lazy="selectin"
)
prevalidator: Mapped[Optional["CompanyPrevalidator"]] = relationship(
"CompanyPrevalidator",
back_populates="company",
uselist=False,
cascade="all, delete-orphan",
lazy="selectin"
)
cfdi: Mapped[Optional["CompanyCFDI"]] = relationship(
"CompanyCFDI",
back_populates="company",
uselist=False,
cascade="all, delete-orphan",
lazy="selectin"
)

View File

@@ -0,0 +1,20 @@
"""
Submodelos de Company
"""
from .address import CompanyAddress
from .certification import CompanyCertification
from .digital_certificate import CompanyDigitalCertificate
from .companyVU import CompanyVU
from .electronic_agent import CompanyElectronicAgent
from .prevalidator import CompanyPrevalidator
from .cfdi import CompanyCFDI
__all__ = [
"CompanyAddress",
"CompanyCertification",
"CompanyDigitalCertificate",
"CompanyVU",
"CompanyElectronicAgent",
"CompanyPrevalidator",
"CompanyCFDI",
]

View File

@@ -0,0 +1,46 @@
"""
Modelo de direcciones de empresa
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from ..models import Company
class CompanyAddress(Base, TimestampMixin):
"""Direcciones de la empresa (principal, industrial 1 y 2)"""
__tablename__ = "company_address"
__table_args__ = {"schema": "a76"}
id: Mapped[int] = mapped_column(Integer, primary_key=True)
company_id: Mapped[int] = mapped_column(
ForeignKey("a76.company.id", ondelete="CASCADE"),
nullable=False,
index=True
)
address_type: Mapped[str] = mapped_column(String(20)) # 'main', 'industrial', 'industrial2'
# Campos de dirección
street: Mapped[Optional[str]] = mapped_column(String(100))
exterior_number: Mapped[Optional[str]] = mapped_column(String(20))
interior_number: Mapped[Optional[str]] = mapped_column(String(20))
postal_code: Mapped[Optional[str]] = mapped_column(String(15))
neighborhood: Mapped[Optional[str]] = mapped_column(String(40))
city: Mapped[Optional[str]] = mapped_column(String(40))
municipality: Mapped[Optional[str]] = mapped_column(String(50))
state: Mapped[Optional[str]] = mapped_column(String(30))
country: Mapped[Optional[str]] = mapped_column(String(4))
phone: Mapped[Optional[str]] = mapped_column(String(30))
fax: Mapped[Optional[str]] = mapped_column(String(30))
email: Mapped[Optional[str]] = mapped_column(String(100))
# Relación inversa
company: Mapped["Company"] = relationship(
"Company",
back_populates="addresses"
)

View File

@@ -0,0 +1,52 @@
"""
Modelo de certificaciones de empresa
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, SmallInteger, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from ..models import Company
class CompanyCertification(Base, TimestampMixin):
"""Certificaciones de la empresa"""
__tablename__ = "company_certification"
__table_args__ = {"schema": "a76"}
id: Mapped[int] = mapped_column(Integer, primary_key=True)
company_id: Mapped[int] = mapped_column(
ForeignKey("a76.company.id", ondelete="CASCADE"),
nullable=False,
unique=True,
index=True
)
# Certificación general
is_certified_company: Mapped[Optional[str]] = mapped_column(String(1))
certified_company_registration: Mapped[Optional[str]] = mapped_column(String(40))
certified_company_start_date: Mapped[Optional[int]] = mapped_column(Integer)
certified_company_end_date: Mapped[Optional[int]] = mapped_column(Integer)
# Anexo 31
annex31_certification_date: Mapped[Optional[int]] = mapped_column(Integer)
annex31_certification_number: Mapped[Optional[str]] = mapped_column(String(50))
annex31_modality: Mapped[Optional[str]] = mapped_column(String(50))
annex31_company_type: Mapped[Optional[str]] = mapped_column(String(50))
annex31_renewal_date: Mapped[Optional[int]] = mapped_column(Integer)
annex31_final_certification_date: Mapped[Optional[int]] = mapped_column(Integer)
# Otras certificaciones
is_oea_company: Mapped[Optional[int]] = mapped_column(SmallInteger)
ctpat_svi: Mapped[Optional[str]] = mapped_column(String(100))
trusted_exporter_number: Mapped[Optional[str]] = mapped_column(String(50))
neec_company: Mapped[Optional[int]] = mapped_column(Integer)
# Relación inversa
company: Mapped["Company"] = relationship(
"Company",
back_populates="certification"
)

View File

@@ -0,0 +1,37 @@
"""
Modelo de configuración de CFDI (Facturación Electrónica)
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from ..models import Company
class CompanyCFDI(Base, TimestampMixin):
"""Configuración de Facturación Electrónica (CFDI)"""
__tablename__ = "company_cfdi"
__table_args__ = {"schema": "a76"}
id: Mapped[int] = mapped_column(Integer, primary_key=True)
company_id: Mapped[int] = mapped_column(
ForeignKey("a76.company.id", ondelete="CASCADE"),
nullable=False,
unique=True,
index=True
)
# Rutas de aplicaciones y archivos
xml_save_path: Mapped[Optional[str]] = mapped_column(String(5000))
cfdi_app_path: Mapped[Optional[str]] = mapped_column(String(5000))
pac_app_path: Mapped[Optional[str]] = mapped_column(String(5000))
# Relación inversa
company: Mapped["Company"] = relationship(
"Company",
back_populates="cfdi"
)

View File

@@ -0,0 +1,44 @@
"""
Modelo de certificados digitales (FIEL, CFDI, Cancelación)
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from ..models import Company
class CompanyDigitalCertificate(Base, TimestampMixin):
"""Certificados digitales (FIEL, CFDI)"""
__tablename__ = "company_digital_certificate"
__table_args__ = {"schema": "a76"}
id: Mapped[int] = mapped_column(Integer, primary_key=True)
company_id: Mapped[int] = mapped_column(
ForeignKey("a76.company.id", ondelete="CASCADE"),
nullable=False,
index=True
)
certificate_type: Mapped[str] = mapped_column(String(20)) # 'fiel', 'cfdi', 'cancellation'
# Rutas de archivos
cer_file_path: Mapped[Optional[str]] = mapped_column(String(5000))
key_file_path: Mapped[Optional[str]] = mapped_column(String(5000))
# Contraseñas y claves
password: Mapped[Optional[str]] = mapped_column(String(200))
access_key: Mapped[Optional[str]] = mapped_column(String(50))
# Fechas de expiración
cer_expiration_date: Mapped[Optional[int]] = mapped_column(Integer)
key_expiration_date: Mapped[Optional[int]] = mapped_column(Integer)
# Relación inversa
company: Mapped["Company"] = relationship(
"Company",
back_populates="digital_certificates"
)

View File

@@ -0,0 +1,46 @@
"""
Modelo de configuración del Agente Aduanal Electrónico
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from ..models import Company
class CompanyElectronicAgent(Base, TimestampMixin):
"""Configuración de Agente Aduanal Electrónico"""
__tablename__ = "company_electronic_agent"
__table_args__ = {"schema": "a76"}
id: Mapped[int] = mapped_column(Integer, primary_key=True)
company_id: Mapped[int] = mapped_column(
ForeignKey("a76.company.id", ondelete="CASCADE"),
nullable=False,
unique=True,
index=True
)
# Carpetas
input_folder: Mapped[Optional[str]] = mapped_column(String(1000))
output_folder: Mapped[Optional[str]] = mapped_column(String(1000))
# Máscaras y extensiones
send_mask: Mapped[Optional[str]] = mapped_column(String(20))
response_mask: Mapped[Optional[str]] = mapped_column(String(20))
response_extension: Mapped[Optional[str]] = mapped_column(String(20))
# Contadores
counter_start: Mapped[Optional[int]] = mapped_column(Integer)
counter_end: Mapped[Optional[int]] = mapped_column(Integer)
counter_next: Mapped[Optional[int]] = mapped_column(Integer)
# Relación inversa
company: Mapped["Company"] = relationship(
"Company",
back_populates="electronic_agent"
)

View File

@@ -0,0 +1,38 @@
"""
Modelo de configuración del Prevalidador Aduanal
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from ..models import Company
class CompanyPrevalidator(Base, TimestampMixin):
"""Configuración de Prevalidador Aduanal"""
__tablename__ = "company_prevalidator"
__table_args__ = {"schema": "a76"}
id: Mapped[int] = mapped_column(Integer, primary_key=True)
company_id: Mapped[int] = mapped_column(
ForeignKey("a76.company.id", ondelete="CASCADE"),
nullable=False,
unique=True,
index=True
)
# Información del prevalidador
customs: Mapped[Optional[str]] = mapped_column(String(20))
key: Mapped[Optional[str]] = mapped_column(String(20))
patent: Mapped[Optional[str]] = mapped_column(String(4))
description: Mapped[Optional[str]] = mapped_column(String(100))
# Relación inversa
company: Mapped["Company"] = relationship(
"Company",
back_populates="prevalidator"
)

View File

@@ -0,0 +1,50 @@
"""
Modelo de configuración de Ventanilla Única
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from api.v1.common.base_models import TimestampMixin
if TYPE_CHECKING:
from ..models import Company
class CompanyVU(Base, TimestampMixin):
"""Configuración de Ventanilla Única"""
__tablename__ = "CompanyVU"
__table_args__ = {"schema": "a76"}
id: Mapped[int] = mapped_column(Integer, primary_key=True)
company_id: Mapped[int] = mapped_column(
ForeignKey("a76.company.id", ondelete="CASCADE"),
nullable=False,
unique=True,
index=True
)
# Credenciales
webservice_user: Mapped[Optional[str]] = mapped_column(String(100))
webservice_password: Mapped[Optional[str]] = mapped_column(String(100))
email: Mapped[Optional[str]] = mapped_column(String(800))
# Configuración
figure_type: Mapped[Optional[str]] = mapped_column(String(29))
central_path: Mapped[Optional[str]] = mapped_column(String(1499))
xml_files_path: Mapped[Optional[str]] = mapped_column(String(1499))
# RFC y validación
query_rfc: Mapped[Optional[str]] = mapped_column(String(30))
validation_rfc: Mapped[Optional[str]] = mapped_column(String(30))
# Otras configuraciones
configuration_source: Mapped[Optional[str]] = mapped_column(String(30))
measurement_units: Mapped[Optional[str]] = mapped_column(String(3))
# Relación inversa
company: Mapped["Company"] = relationship(
"Company",
back_populates="ventanilla_unica"
)