Merge pull request 'add/tables' (#57) from add/tables into development
Reviewed-on: ADUANASOFT/anexo76#57
This commit is contained in:
@@ -1,7 +1,26 @@
|
||||
"""
|
||||
Módulo de Company
|
||||
"""
|
||||
|
||||
from .models import Company
|
||||
from .routes import router
|
||||
from .submodels import (
|
||||
CompanyAddress,
|
||||
CompanyCertification,
|
||||
CompanyDigitalCertificate,
|
||||
CompanyVU,
|
||||
CompanyElectronicAgent,
|
||||
CompanyPrevalidator,
|
||||
CompanyCFDI,
|
||||
)
|
||||
|
||||
__all__ = ["router"]
|
||||
__all__ = [
|
||||
"Company",
|
||||
"router",
|
||||
"CompanyAddress",
|
||||
"CompanyCertification",
|
||||
"CompanyDigitalCertificate",
|
||||
"CompanyVU",
|
||||
"CompanyElectronicAgent",
|
||||
"CompanyPrevalidator",
|
||||
"CompanyCFDI",
|
||||
]
|
||||
@@ -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, Boolean
|
||||
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[bool]] = mapped_column(Boolean, default=False)
|
||||
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"
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Submodelos de Company
|
||||
"""
|
||||
from .address import CompanyAddress
|
||||
from .certification import CompanyCertification
|
||||
from .digital_certificate import CompanyDigitalCertificate
|
||||
from .vu import CompanyVU
|
||||
from .electronic_agent import CompanyElectronicAgent
|
||||
from .prevalidator import CompanyPrevalidator
|
||||
from .cfdi import CompanyCFDI
|
||||
|
||||
__all__ = [
|
||||
"CompanyAddress",
|
||||
"CompanyCertification",
|
||||
"CompanyDigitalCertificate",
|
||||
"CompanyVU",
|
||||
"CompanyElectronicAgent",
|
||||
"CompanyPrevalidator",
|
||||
"CompanyCFDI",
|
||||
]
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -37,6 +37,61 @@ export function createColumns(onSuccess) {
|
||||
return renderSnippet(snippet, { val: row.original.name });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "streets",
|
||||
header: "Calles",
|
||||
cell: ({ row }) => {
|
||||
const snippet = createRawSnippet((getData) => {
|
||||
const { val } = getData();
|
||||
return { render: () => `<div class="max-w-[200px] truncate" title="${val || ''}">${val || '-'}</div>` };
|
||||
});
|
||||
return renderSnippet(snippet, { val: row.original.address?.streets });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "exterior_number",
|
||||
header: "Num Ext.",
|
||||
cell: ({ row }) => {
|
||||
const snippet = createRawSnippet((getData) => {
|
||||
const { val } = getData();
|
||||
return { render: () => `<div>${val || '-'}</div>` };
|
||||
});
|
||||
return renderSnippet(snippet, { val: row.original.address?.exterior_number });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "postal_code",
|
||||
header: "Código Postal",
|
||||
cell: ({ row }) => {
|
||||
const snippet = createRawSnippet((getData) => {
|
||||
const { val } = getData();
|
||||
return { render: () => `<code class="bg-muted px-1 py-0.5 rounded text-sm">${val || '-'}</code>` };
|
||||
});
|
||||
return renderSnippet(snippet, { val: row.original.address?.postal_code });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "neighborhood",
|
||||
header: "Colonia",
|
||||
cell: ({ row }) => {
|
||||
const snippet = createRawSnippet((getData) => {
|
||||
const { val } = getData();
|
||||
return { render: () => `<div class="max-w-[150px] truncate" title="${val || ''}">${val || '-'}</div>` };
|
||||
});
|
||||
return renderSnippet(snippet, { val: row.original.address?.neighborhood });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "city",
|
||||
header: "Ciudad",
|
||||
cell: ({ row }) => {
|
||||
const snippet = createRawSnippet((getData) => {
|
||||
const { val } = getData();
|
||||
return { render: () => `<div class="max-w-[150px] truncate" title="${val || ''}">${val || '-'}</div>` };
|
||||
});
|
||||
return renderSnippet(snippet, { val: row.original.address?.city });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "country",
|
||||
header: "País",
|
||||
|
||||
@@ -22,9 +22,22 @@ export function createColumns(onSuccess?: () => void): ColumnDef<CustomsBroker>[
|
||||
return renderSnippet(keySnippet, { key: row.original.broker_key });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "type",
|
||||
header: "Tipo",
|
||||
cell: ({ row }) => {
|
||||
const typeSnippet = createRawSnippet<[{ type: string | null | undefined }]>((getType) => {
|
||||
const { type } = getType();
|
||||
return {
|
||||
render: () => `<div class="max-w-[120px] truncate">${type || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(typeSnippet, { type: row.original.type });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Nombre",
|
||||
header: "Nombre Completo",
|
||||
cell: ({ row }) => {
|
||||
const nameSnippet = createRawSnippet<[{ name: string | null | undefined }]>((getName) => {
|
||||
const { name } = getName();
|
||||
@@ -36,16 +49,84 @@ export function createColumns(onSuccess?: () => void): ColumnDef<CustomsBroker>[
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "type",
|
||||
header: "Tipo",
|
||||
accessorKey: "address",
|
||||
header: "Dirección",
|
||||
cell: ({ row }) => {
|
||||
const typeSnippet = createRawSnippet<[{ type: string | null | undefined }]>((getType) => {
|
||||
const { type } = getType();
|
||||
const addressSnippet = createRawSnippet<[{ address: string | null | undefined }]>((getAddress) => {
|
||||
const { address } = getAddress();
|
||||
return {
|
||||
render: () => `<div class="max-w-[120px] truncate">${type || '-'}</div>`
|
||||
render: () => `<div class="max-w-[250px] truncate" title="${address || ''}">${address || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(typeSnippet, { type: row.original.type });
|
||||
return renderSnippet(addressSnippet, { address: row.original.address });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "postal_code",
|
||||
header: "Código Postal",
|
||||
cell: ({ row }) => {
|
||||
const postalSnippet = createRawSnippet<[{ postal: string | null | undefined }]>((getPostal) => {
|
||||
const { postal } = getPostal();
|
||||
return {
|
||||
render: () =>
|
||||
postal
|
||||
? `<code class="bg-muted px-1 py-0.5 rounded text-sm">${postal}</code>`
|
||||
: `<span class="text-muted-foreground">-</span>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(postalSnippet, { postal: row.original.postal_code });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "city",
|
||||
header: "Ciudad",
|
||||
cell: ({ row }) => {
|
||||
const citySnippet = createRawSnippet<[{ city: string | null | undefined }]>((getCity) => {
|
||||
const { city } = getCity();
|
||||
return {
|
||||
render: () => `<div class="max-w-[150px] truncate">${city || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(citySnippet, { city: row.original.city });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "state",
|
||||
header: "Estado",
|
||||
cell: ({ row }) => {
|
||||
const stateSnippet = createRawSnippet<[{ state: string | null | undefined }]>((getState) => {
|
||||
const { state } = getState();
|
||||
return {
|
||||
render: () => `<div class="max-w-[150px] truncate">${state || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(stateSnippet, { state: row.original.state });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "phone",
|
||||
header: "Teléfono",
|
||||
cell: ({ row }) => {
|
||||
const phoneSnippet = createRawSnippet<[{ phone: string | null | undefined }]>((getPhone) => {
|
||||
const { phone } = getPhone();
|
||||
return {
|
||||
render: () => `<div class="max-w-[140px] truncate text-sm">${phone || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(phoneSnippet, { phone: row.original.phone });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "fax",
|
||||
header: "Número Fax",
|
||||
cell: ({ row }) => {
|
||||
const faxSnippet = createRawSnippet<[{ fax: string | null | undefined }]>((getFax) => {
|
||||
const { fax } = getFax();
|
||||
return {
|
||||
render: () => `<div class="max-w-[140px] truncate text-sm">${fax || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(faxSnippet, { fax: row.original.fax });
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -90,32 +171,6 @@ export function createColumns(onSuccess?: () => void): ColumnDef<CustomsBroker>[
|
||||
return renderSnippet(emailSnippet, { email: row.original.email });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "phone",
|
||||
header: "Teléfono",
|
||||
cell: ({ row }) => {
|
||||
const phoneSnippet = createRawSnippet<[{ phone: string | null | undefined }]>((getPhone) => {
|
||||
const { phone } = getPhone();
|
||||
return {
|
||||
render: () => `<div class="max-w-[140px] truncate text-sm">${phone || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(phoneSnippet, { phone: row.original.phone });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "city",
|
||||
header: "Ciudad",
|
||||
cell: ({ row }) => {
|
||||
const citySnippet = createRawSnippet<[{ city: string | null | undefined }]>((getCity) => {
|
||||
const { city } = getCity();
|
||||
return {
|
||||
render: () => `<div class="max-w-[150px] truncate">${city || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(citySnippet, { city: row.original.city });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: "Acciones",
|
||||
|
||||
@@ -112,7 +112,25 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Part>[] {
|
||||
}
|
||||
},
|
||||
|
||||
// 7. FRACCION
|
||||
// 7. U.M. (Unidad de Medida)
|
||||
{
|
||||
accessorKey: "unit_of_measure",
|
||||
header: "U.M.",
|
||||
cell: ({ row }) => {
|
||||
const umSnippet = createRawSnippet<[{ um: string }]>((getUm) => {
|
||||
const { um } = getUm();
|
||||
return {
|
||||
render: () =>
|
||||
`<span class="inline-flex items-center rounded-sm bg-blue-50 dark:bg-blue-900 text-blue-700 dark:text-blue-300 px-1.5 py-0.5 text-[10px] font-bold ring-1 ring-inset ring-blue-700/10">
|
||||
${um}
|
||||
</span>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(umSnippet, { um: row.original.unit_of_measure });
|
||||
}
|
||||
},
|
||||
|
||||
// 8. FRACCION
|
||||
{
|
||||
accessorKey: "fraction",
|
||||
header: "Fracción",
|
||||
@@ -127,25 +145,22 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Part>[] {
|
||||
}
|
||||
},
|
||||
|
||||
// 8. UMT (Unidad de Medida)
|
||||
// 9. U.M.T. (del inv_data)
|
||||
{
|
||||
accessorKey: "unit_of_measure",
|
||||
header: "UMT",
|
||||
id: "stock_uom",
|
||||
header: "U.M.T.",
|
||||
cell: ({ row }) => {
|
||||
const umtSnippet = createRawSnippet<[{ um: string }]>((getUm) => {
|
||||
const { um } = getUm();
|
||||
const umtSnippet = createRawSnippet<[{ umt: string }]>((getUmt) => {
|
||||
const { umt } = getUmt();
|
||||
return {
|
||||
render: () =>
|
||||
`<span class="inline-flex items-center rounded-sm bg-blue-50 text-blue-700 px-1.5 py-0.5 text-[10px] font-bold ring-1 ring-inset ring-blue-700/10">
|
||||
${um}
|
||||
</span>`
|
||||
render: () => `<div class="text-xs font-mono">${umt || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(umtSnippet, { um: row.original.unit_of_measure });
|
||||
return renderSnippet(umtSnippet, { umt: row.original.inv_data?.stock_uom || '' });
|
||||
}
|
||||
},
|
||||
|
||||
// 9. COSTO
|
||||
// 10. COSTO
|
||||
{
|
||||
accessorKey: "unit_cost",
|
||||
header: "Costo",
|
||||
@@ -163,6 +178,78 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Part>[] {
|
||||
}
|
||||
},
|
||||
|
||||
// 11. MONEDA
|
||||
{
|
||||
accessorKey: "currency_key",
|
||||
header: "Moneda",
|
||||
cell: ({ row }) => {
|
||||
const currSnippet = createRawSnippet<[{ curr: string }]>((getCurr) => {
|
||||
const { curr } = getCurr();
|
||||
return {
|
||||
render: () => `<span class="inline-flex items-center rounded-sm bg-emerald-50 dark:bg-emerald-900 text-emerald-700 dark:text-emerald-300 px-1.5 py-0.5 text-[10px] font-bold">${curr || '-'}</span>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(currSnippet, { curr: row.original.currency_key || '' });
|
||||
}
|
||||
},
|
||||
|
||||
// 12. PESO UNITARIO
|
||||
{
|
||||
accessorKey: "unit_weight",
|
||||
header: "Peso Unitario",
|
||||
cell: ({ row }) => {
|
||||
const weightSnippet = createRawSnippet<[{ weight: number | null, type: string | null }]>((getWeight) => {
|
||||
const { weight, type } = getWeight();
|
||||
return {
|
||||
render: () => {
|
||||
if (weight === null || weight === undefined) return '-';
|
||||
return `<div class="text-xs font-mono">${weight.toFixed(4)} ${type || ''}</div>`;
|
||||
}
|
||||
};
|
||||
});
|
||||
return renderSnippet(weightSnippet, {
|
||||
weight: row.original.unit_weight,
|
||||
type: row.original.weight_type
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 13. U.M. EXIST (Stock UOM del inv_data)
|
||||
{
|
||||
id: "equivalent_uom",
|
||||
header: "U.M. Exist",
|
||||
cell: ({ row }) => {
|
||||
const eqUomSnippet = createRawSnippet<[{ uom: string }]>((getUom) => {
|
||||
const { uom } = getUom();
|
||||
return {
|
||||
render: () => `<div class="text-xs">${uom || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(eqUomSnippet, { uom: row.original.inv_data?.equivalent_uom || '' });
|
||||
}
|
||||
},
|
||||
|
||||
// 14. FECHA MODIFICACIÓN
|
||||
{
|
||||
accessorKey: "updated_at",
|
||||
header: "Fecha Modificación",
|
||||
cell: ({ row }) => {
|
||||
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
|
||||
const { date } = getDate();
|
||||
if (!date) return { render: () => '-' };
|
||||
const formatted = new Date(date).toLocaleDateString('es-MX', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
});
|
||||
return {
|
||||
render: () => `<div class="text-xs text-muted-foreground">${formatted}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(dateSnippet, { date: row.original.updated_at });
|
||||
}
|
||||
},
|
||||
|
||||
// ACCIONES
|
||||
{
|
||||
id: "actions",
|
||||
|
||||
@@ -117,6 +117,152 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Pedimento>[] {
|
||||
return renderSnippet(numberSnippet, { number: fullNumber });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_type",
|
||||
header: "Tipo",
|
||||
cell: ({ row }) => {
|
||||
const typeSnippet = createRawSnippet<[{ type?: string | null }]>((getType) => {
|
||||
const { type } = getType();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm">${type || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(typeSnippet, { type: row.original.pedimento_type });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_code",
|
||||
header: "Clave",
|
||||
cell: ({ row }) => {
|
||||
const codeSnippet = createRawSnippet<[{ code?: string | null }]>((getCode) => {
|
||||
const { code } = getCode();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm">${code || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(codeSnippet, { code: row.original.pedimento_code });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "regime",
|
||||
header: "Régimen",
|
||||
cell: ({ row }) => {
|
||||
const regimeSnippet = createRawSnippet<[{ regime?: string | null }]>((getRegime) => {
|
||||
const { regime } = getRegime();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm">${regime || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(regimeSnippet, { regime: row.original.regime });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_dates.start_date",
|
||||
header: "Fecha Inicio",
|
||||
cell: ({ row }) => {
|
||||
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
|
||||
const { date } = getDate();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm text-muted-foreground">${date}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.start_date) });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_dates.end_date",
|
||||
header: "Fecha Final",
|
||||
cell: ({ row }) => {
|
||||
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
|
||||
const { date } = getDate();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm text-muted-foreground">${date}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.end_date) });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_dates.payment_date",
|
||||
header: "Fecha de Pago",
|
||||
cell: ({ row }) => {
|
||||
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
|
||||
const { date } = getDate();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm text-muted-foreground">${date}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.payment_date) });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_config_update_rectification.pediment_rectifed_18",
|
||||
header: "Pedimento 18",
|
||||
cell: ({ row }) => {
|
||||
const ped18Snippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
|
||||
const { value } = getValue();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm">${value || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(ped18Snippet, { value: row.original.pedimento_config_update_rectification?.pediment_rectifed_18 });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_config_update_rectification.r1",
|
||||
header: "Pedimento R1",
|
||||
cell: ({ row }) => {
|
||||
const r1Snippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
|
||||
const { value } = getValue();
|
||||
return {
|
||||
render: () =>
|
||||
`<div class="text-sm">${value || '-'}</div>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(r1Snippet, { value: row.original.pedimento_config_update_rectification?.r1 });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_validation.electronic_signature",
|
||||
header: "Acuse Electrónico",
|
||||
cell: ({ row }) => {
|
||||
const ackSnippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
|
||||
const { value } = getValue();
|
||||
const hasValue = value && value !== '';
|
||||
return {
|
||||
render: () =>
|
||||
`<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${hasValue ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}">
|
||||
${hasValue ? 'Sí' : 'No'}
|
||||
</span>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(ackSnippet, { value: row.original.pedimento_validation?.electronic_signature });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "pedimento_payments.total_contributions",
|
||||
header: "¿Se pagó el impuesto?",
|
||||
cell: ({ row }) => {
|
||||
const paidSnippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
|
||||
const { value } = getValue();
|
||||
const isPaid = value && parseFloat(value) > 0;
|
||||
return {
|
||||
render: () =>
|
||||
`<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${isPaid ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}">
|
||||
${isPaid ? 'Sí' : 'No'}
|
||||
</span>`
|
||||
};
|
||||
});
|
||||
return renderSnippet(paidSnippet, { value: row.original.pedimento_payments?.total_contributions });
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "client_id",
|
||||
header: "Cliente",
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
<!-- Error Message -->
|
||||
{#if error}
|
||||
<Card.Root class="border-destructive">
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-destructive dark:border-red-800">
|
||||
<Card.Header>
|
||||
<Card.Title class="text-destructive">Error</Card.Title>
|
||||
<Card.Description>
|
||||
@@ -214,11 +214,10 @@
|
||||
{/if}
|
||||
|
||||
<!-- Data Table -->
|
||||
<Card.Root>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<Card.Title>Listado de Clientes y Proveedores</Card.Title>
|
||||
<Card.Description>
|
||||
Mostrando {allItems.length} de {totalItems} registros
|
||||
{#if companyStore.activeCompany}
|
||||
|
||||
@@ -130,8 +130,13 @@
|
||||
if (response.data) {
|
||||
if (Array.isArray(response.data)) {
|
||||
brokersList = response.data;
|
||||
} else if (response.data.items && Array.isArray(response.data.items)) {
|
||||
brokersList = response.data.items;
|
||||
} else if (typeof response.data === 'object' && 'items' in response.data) {
|
||||
const dataWithItems = response.data as { items?: CustomsBroker[] };
|
||||
if (Array.isArray(dataWithItems.items)) {
|
||||
brokersList = dataWithItems.items;
|
||||
} else {
|
||||
brokersList = [];
|
||||
}
|
||||
} else {
|
||||
console.error("⚠️ Estructura de datos inesperada:", response.data);
|
||||
brokersList = [];
|
||||
@@ -171,9 +176,8 @@
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Header>
|
||||
<Card.Title>Buscar Agente Aduanal</Card.Title>
|
||||
<Card.Description>
|
||||
Ingresa la clave del agente aduanal para buscarlo
|
||||
{#if companyStore.activeCompany}
|
||||
@@ -222,7 +226,7 @@
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -271,4 +275,12 @@
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
||||
<CreateDialog bind:open={showCreateDialog} onSuccess={handleSuccess} />
|
||||
<CreateDialog
|
||||
bind:open={showCreateDialog}
|
||||
companyId={companyStore.activeCompany?.id.toString() || ''}
|
||||
onSave={async (data) => {
|
||||
// El CreateDialog maneja la creación internamente
|
||||
// Después de guardar exitosamente, recargar los datos
|
||||
await handleSuccess();
|
||||
}}
|
||||
/>
|
||||
@@ -121,11 +121,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Búsqueda Rápida</Card.Title>
|
||||
<Card.Description>Ingresa el número de parte o descripción para filtrar.</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Content>
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-1 max-w-xl">
|
||||
@@ -155,7 +151,7 @@
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Header>
|
||||
<Card.Title>
|
||||
{#if isSearching}
|
||||
|
||||
@@ -392,11 +392,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Filtros -->
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Filtros</Card.Title>
|
||||
<Card.Description>Filtra las facturas por diferentes criterios (los filtros se aplican automáticamente)</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Content>
|
||||
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
|
||||
<div class="space-y-2">
|
||||
@@ -458,7 +454,7 @@
|
||||
|
||||
<!-- Error Message -->
|
||||
{#if error}
|
||||
<Card.Root class="border-destructive">
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-destructive dark:border-red-800">
|
||||
<Card.Header>
|
||||
<Card.Title class="text-destructive">Error</Card.Title>
|
||||
<Card.Description>{error}</Card.Description>
|
||||
@@ -467,7 +463,7 @@
|
||||
{/if}
|
||||
|
||||
<!-- Data Table -->
|
||||
<Card.Root>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
|
||||
@@ -267,18 +267,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Filtros -->
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Filtros</Card.Title>
|
||||
<Card.Description>Filtra los pedimentos por diferentes criterios</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Content>
|
||||
<form onsubmit={(e) => { e.preventDefault(); applyFilters(); }} class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="filter-status">Estado</Label>
|
||||
<select
|
||||
id="filter-status"
|
||||
bind:value={filters.status}
|
||||
onchange={applyFilters}
|
||||
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||
>
|
||||
{#each statusOptions as option}
|
||||
@@ -293,6 +290,7 @@
|
||||
id="filter-client"
|
||||
type="number"
|
||||
bind:value={filters.client_id}
|
||||
oninput={applyFilters}
|
||||
placeholder="Ej: 123"
|
||||
/>
|
||||
</div>
|
||||
@@ -302,27 +300,18 @@
|
||||
<Input
|
||||
id="filter-year"
|
||||
bind:value={filters.year}
|
||||
oninput={applyFilters}
|
||||
placeholder="Ej: 23"
|
||||
maxlength={2}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-end gap-2">
|
||||
<Button type="submit" disabled={loading} class="flex-1">
|
||||
<Filter class="mr-2" size={16} />
|
||||
Filtrar
|
||||
</Button>
|
||||
<Button type="button" variant="outline" onclick={clearFilters} disabled={loading}>
|
||||
<Trash2 size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<!-- Error Message -->
|
||||
{#if error}
|
||||
<Card.Root class="border-destructive">
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-destructive">
|
||||
<Card.Header>
|
||||
<Card.Title class="text-destructive">Error</Card.Title>
|
||||
<Card.Description>{error}</Card.Description>
|
||||
@@ -331,7 +320,7 @@
|
||||
{/if}
|
||||
|
||||
<!-- Data Table -->
|
||||
<Card.Root>
|
||||
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
|
||||
<Card.Header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user