chore: resolve remaining merge conflicts in data-table-actions components

This commit is contained in:
2026-04-27 13:39:04 -05:00
325 changed files with 26584 additions and 10591 deletions

View File

@@ -0,0 +1,27 @@
"""add description to classification concept
Revision ID: 1f4ba75eaa35
Revises: f1a2b3c4d5e6
Create Date: 2026-04-21 20:55:04.259655
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '1f4ba75eaa35'
down_revision: Union[str, Sequence[str], None] = 'f1a2b3c4d5e6'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
op.add_column('classification_concepts', sa.Column('description', sa.String(length=255), nullable=True), schema='a76')
def downgrade() -> None:
"""Downgrade schema."""
op.drop_column('classification_concepts', 'description', schema='a76')

View File

@@ -20,6 +20,13 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# Requisito previo (antes estaba en scripts de initdb de Docker): extensiones y esquemas
# para tablas creadas debajo (schema=public/core/a76/…).
op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"')
op.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm")
for _schema in ("core", "a76", "a22", "a24", "a30"):
op.execute(f"CREATE SCHEMA IF NOT EXISTS {_schema}")
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('inv_aphis_catalog',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),

View File

@@ -0,0 +1,189 @@
"""company certification refactor + legacy ui fields
Revision ID: 6a7b8c9d0e1f
Revises: 1f4ba75eaa35
Create Date: 2026-04-23 11:10:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "6a7b8c9d0e1f"
down_revision: Union[str, Sequence[str], None] = "1f4ba75eaa35"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
SCHEMA = "a76"
TABLE = "company_certification"
def upgrade() -> None:
# Rename Annex 31 columns to Annex 30 names.
op.alter_column(TABLE, "annex31_certification_date", new_column_name="annex30_certification_date", schema=SCHEMA)
op.alter_column(TABLE, "annex31_certification_number", new_column_name="annex30_certification_number", schema=SCHEMA)
op.alter_column(TABLE, "annex31_modality", new_column_name="annex30_modality", schema=SCHEMA)
op.alter_column(TABLE, "annex31_company_type", new_column_name="annex30_company_type", schema=SCHEMA)
op.alter_column(TABLE, "annex31_renewal_date", new_column_name="annex30_renewal_date", schema=SCHEMA)
op.alter_column(TABLE, "annex31_final_certification_date", new_column_name="annex30_final_certification_date", schema=SCHEMA)
op.alter_column(
TABLE,
"annex30_modality",
existing_type=sa.String(length=50),
type_=sa.String(length=3),
schema=SCHEMA,
)
# Convert legacy integer dates (YYYYMMDD or 0) to DATE.
date_columns = [
"certified_company_start_date",
"certified_company_end_date",
"annex30_certification_date",
"annex30_renewal_date",
"annex30_final_certification_date",
]
for col in date_columns:
op.alter_column(
TABLE,
col,
existing_type=sa.Integer(),
type_=sa.Date(),
schema=SCHEMA,
postgresql_using=(
f"CASE "
f"WHEN {col} IS NULL OR {col} = 0 THEN NULL "
f"WHEN length({col}::text) = 8 THEN to_date({col}::text, 'YYYYMMDD') "
f"ELSE NULL END"
),
)
# Convert legacy S/N and 0/1 flags to native booleans.
op.alter_column(
TABLE,
"is_certified_company",
existing_type=sa.String(length=1),
type_=sa.Boolean(),
schema=SCHEMA,
postgresql_using=(
"CASE "
"WHEN is_certified_company IS NULL THEN NULL "
"WHEN upper(trim(is_certified_company)) IN ('S','SI','1','T','TRUE','Y','YES') THEN true "
"WHEN upper(trim(is_certified_company)) IN ('N','NO','0','F','FALSE') THEN false "
"ELSE NULL END"
),
)
op.alter_column(
TABLE,
"is_oea_company",
existing_type=sa.SmallInteger(),
type_=sa.Boolean(),
schema=SCHEMA,
postgresql_using="CASE WHEN is_oea_company IS NULL THEN NULL WHEN is_oea_company = 1 THEN true ELSE false END",
)
op.alter_column(
TABLE,
"neec_company",
existing_type=sa.Integer(),
type_=sa.Boolean(),
schema=SCHEMA,
postgresql_using="CASE WHEN neec_company IS NULL THEN NULL WHEN neec_company = 1 THEN true ELSE false END",
)
# Additional legacy UI fields.
op.add_column(
"company",
sa.Column("fiscal_deposit", sa.Boolean(), nullable=True, server_default=sa.text("false")),
schema=SCHEMA,
)
op.add_column(
"company",
sa.Column(
"generate_barcodes_with_fiel",
sa.Boolean(),
nullable=True,
server_default=sa.text("false"),
),
schema=SCHEMA,
)
op.add_column(
"company_certification",
sa.Column("is_seciit_company", sa.Boolean(), nullable=True, server_default=sa.text("false")),
schema=SCHEMA,
)
def downgrade() -> None:
# Remove additional legacy UI fields.
op.drop_column("company_certification", "is_seciit_company", schema=SCHEMA)
op.drop_column("company", "generate_barcodes_with_fiel", schema=SCHEMA)
op.drop_column("company", "fiscal_deposit", schema=SCHEMA)
# Restore booleans to legacy flag formats.
op.alter_column(
TABLE,
"is_certified_company",
existing_type=sa.Boolean(),
type_=sa.String(length=1),
schema=SCHEMA,
postgresql_using="CASE WHEN is_certified_company IS NULL THEN NULL WHEN is_certified_company THEN 'S' ELSE 'N' END",
)
op.alter_column(
TABLE,
"is_oea_company",
existing_type=sa.Boolean(),
type_=sa.SmallInteger(),
schema=SCHEMA,
postgresql_using="CASE WHEN is_oea_company IS NULL THEN NULL WHEN is_oea_company THEN 1 ELSE 0 END",
)
op.alter_column(
TABLE,
"neec_company",
existing_type=sa.Boolean(),
type_=sa.Integer(),
schema=SCHEMA,
postgresql_using="CASE WHEN neec_company IS NULL THEN NULL WHEN neec_company THEN 1 ELSE 0 END",
)
# Restore DATE columns to integer YYYYMMDD format.
date_columns = [
"certified_company_start_date",
"certified_company_end_date",
"annex30_certification_date",
"annex30_renewal_date",
"annex30_final_certification_date",
]
for col in date_columns:
op.alter_column(
TABLE,
col,
existing_type=sa.Date(),
type_=sa.Integer(),
schema=SCHEMA,
postgresql_using=f"CASE WHEN {col} IS NULL THEN NULL ELSE to_char({col}, 'YYYYMMDD')::integer END",
)
op.alter_column(
TABLE,
"annex30_modality",
existing_type=sa.String(length=3),
type_=sa.String(length=50),
schema=SCHEMA,
)
# Rename Annex 30 columns back to Annex 31.
op.alter_column(TABLE, "annex30_certification_date", new_column_name="annex31_certification_date", schema=SCHEMA)
op.alter_column(TABLE, "annex30_certification_number", new_column_name="annex31_certification_number", schema=SCHEMA)
op.alter_column(TABLE, "annex30_modality", new_column_name="annex31_modality", schema=SCHEMA)
op.alter_column(TABLE, "annex30_company_type", new_column_name="annex31_company_type", schema=SCHEMA)
op.alter_column(TABLE, "annex30_renewal_date", new_column_name="annex31_renewal_date", schema=SCHEMA)
op.alter_column(TABLE, "annex30_final_certification_date", new_column_name="annex31_final_certification_date", schema=SCHEMA)

View File

@@ -0,0 +1,49 @@
"""Add has_express_line to transporter; remove from company.
Revision ID: c8d9e0f1a2b3
Revises: 6a7b8c9d0e1f
Create Date: 2026-04-24
Upgrade: add transporter column first (NOT NULL + default), then drop company column.
Downgrade: restore company column, drop transporter column (schema only; data not restored).
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
revision: str = "c8d9e0f1a2b3"
down_revision: Union[str, Sequence[str], None] = "6a7b8c9d0e1f"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
SCHEMA = "a76"
def upgrade() -> None:
op.add_column(
"transporter",
sa.Column(
"has_express_line",
sa.Boolean(),
server_default=sa.text("false"),
nullable=False,
),
schema=SCHEMA,
)
op.drop_column("company", "has_express_line", schema=SCHEMA)
def downgrade() -> None:
op.add_column(
"company",
sa.Column(
"has_express_line",
sa.Boolean(),
server_default=sa.text("false"),
nullable=True,
),
schema=SCHEMA,
)
op.drop_column("transporter", "has_express_line", schema=SCHEMA)

View File

@@ -0,0 +1,302 @@
"""enable_rls_tenant_company
Habilita Row-Level Security en las tablas multi-tenant conforme al skill
`aduanasoft-dev-standards` (sección 10). Las políticas dependen de dos
GUCs que la aplicación establece por transacción con `SET LOCAL`:
- ``app.tenant_id`` (ID del tenant actual, obligatorio para aislamiento)
- ``app.company_id`` (ID de la compañía activa; opcional — si no está fijado
la política permite todas las compañías del tenant, útil para vistas de
selector de compañía / bootstrap de sesión)
Las funciones SQL viven en el esquema ``app`` y retornan ``NULL`` cuando la
GUC correspondiente está vacía, lo que hace que las comparaciones
``col = app.current_xxx_id()`` devuelvan 0 filas sin contexto (fail-closed
para ``tenant_id``).
Las tablas ``core.tenants`` y ``core.user_tenants`` NO quedan bajo RLS: son
necesarias para el bootstrap de la sesión (obtener tenant del JWT y listar
los tenants del usuario en el selector).
La migración instala ``FORCE ROW LEVEL SECURITY`` para que las políticas
apliquen también al owner — los superusuarios (p. ej. ``postgres`` en dev)
siguen haciendo bypass por diseño de PostgreSQL; en producción la API debe
conectarse con un rol sin BYPASSRLS.
Revision ID: d1a2b3c4e5f6
Revises: c8d9e0f1a2b3
Create Date: 2026-04-24 17:00:00.000000
"""
from typing import Sequence, Union
from alembic import op
revision: str = "d1a2b3c4e5f6"
down_revision: Union[str, Sequence[str], None] = "c8d9e0f1a2b3"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
TABLES_TENANT_ONLY: list[tuple[str, str]] = [
("a76", "company"),
("core", "license_usage"),
("core", "licenses"),
]
TABLES_TENANT_AND_COMPANY: list[tuple[str, str]] = [
("a24", "balance_movement"),
("a24", "discharge_detail"),
("a24", "discharge_header"),
("a24", "discharge_scrap"),
("a24", "fa_classes"),
("a24", "fa_item_lines"),
("a24", "fa_partes"),
("a24", "inv_aphis_characteristic"),
("a24", "inv_aphis_containers"),
("a24", "inv_aphis_entities"),
("a24", "inv_aphis_general"),
("a24", "inv_aphis_lpcos"),
("a24", "inv_aphis_routing"),
("a24", "inv_aphis_stype_pitems"),
("a24", "inv_bom"),
("a24", "inv_classes"),
("a24", "inv_parte_paises"),
("a24", "inv_partes"),
("a76", "app_settings"),
("a76", "audit_logs"),
("a76", "canadian_tariff_fractions"),
("a76", "classes"),
("a76", "classification_concepts"),
("a76", "clients_and_providers"),
("a76", "clients_and_providers_address"),
("a76", "clients_and_providers_programs"),
("a76", "concept_manifestations"),
("a76", "concepts"),
("a76", "country_rule_oct"),
("a76", "ctm_receipts"),
("a76", "customs_broker_concepts"),
("a76", "customs_brokers"),
("a76", "customs_brokers_personnel"),
("a76", "customs_brokers_vu"),
("a76", "depreciation_catalog"),
("a76", "document_types_digitization"),
("a76", "doda"),
("a76", "doda_american_pedimentos"),
("a76", "doda_container_seals"),
("a76", "doda_containers"),
("a76", "doda_pedimentos"),
("a76", "driver"),
("a76", "electronic_notices"),
("a76", "equivalencies"),
("a76", "equivalency_items"),
("a76", "error_catalogs"),
("a76", "error_classifications"),
("a76", "exchange_rate"),
("a76", "fa_location_ext"),
("a76", "fda_affirmation_codes"),
("a76", "fda_catalog"),
("a76", "fda_constituent_elements"),
("a76", "fda_lot_production"),
("a76", "fda_specifications"),
("a76", "fraction_rule_octave"),
("a76", "historical_tariff_fractions"),
("a76", "identifier_details"),
("a76", "identifiers"),
("a76", "inpc"),
("a76", "invoice_collections"),
("a76", "invoice_compliance_mx"),
("a76", "invoice_financials"),
("a76", "invoice_header"),
("a76", "invoice_logistics"),
("a76", "invoice_sales_details"),
("a76", "invoice_settings"),
("a76", "item_line_series"),
("a76", "item_lines"),
("a76", "item_presets"),
("a76", "legends"),
("a76", "location"),
("a76", "manifest_anexos"),
("a76", "manifest_drivers"),
("a76", "manifests"),
("a76", "multi_currency_types"),
("a76", "octave_balance"),
("a76", "packages"),
("a76", "packing_lists"),
("a76", "parts"),
("a76", "pedimento_config_additional"),
("a76", "pedimento_config_calculations"),
("a76", "pedimento_config_parameters"),
("a76", "pedimento_config_surcharges"),
("a76", "pedimento_config_update_rectification"),
("a76", "pedimento_config_updates"),
("a76", "pedimento_containers"),
("a76", "pedimento_contributions"),
("a76", "pedimento_customs_offices"),
("a76", "pedimento_dates"),
("a76", "pedimento_decrementables"),
("a76", "pedimento_guides"),
("a76", "pedimento_incrementables"),
("a76", "pedimento_indexes"),
("a76", "pedimento_packages"),
("a76", "pedimento_payments"),
("a76", "pedimento_rectification_destination"),
("a76", "pedimento_rectification_origin"),
("a76", "pedimento_seals"),
("a76", "pedimento_transport_carriers"),
("a76", "pedimento_transport_means"),
("a76", "pedimento_validation"),
("a76", "pedimentos"),
("a76", "permission_rule_oct"),
("a76", "permission_rule_octave"),
("a76", "ports"),
("a76", "prevalidators"),
("a76", "previous_fractions"),
("a76", "seal"),
("a76", "sectors"),
("a76", "signatures"),
("a76", "subassembly_entries"),
("a76", "trailer"),
("a76", "transporter"),
("a76", "unit_conversions"),
("a76", "units_of_measure"),
("a76", "units_of_measure_general"),
("a76", "us_tariff_fractions"),
("a76", "value_manifestations"),
("a76", "vehicle"),
("core", "company_roles"),
("core", "role_permissions"),
("core", "user_company_permissions"),
("core", "user_company_roles"),
("public", "warning_fractions"),
]
TABLES_COMPANY_ONLY: list[tuple[str, str]] = [
("a24", "inv_aphis_catalog"),
("a76", "company_address"),
("a76", "company_certification"),
("a76", "company_cfdi"),
("a76", "company_digital_certificate"),
("a76", "company_electronic_agent"),
("a76", "company_prevalidator"),
]
POLICY_TENANT_ONLY = "tenant_isolation"
POLICY_TENANT_COMPANY = "tenant_company_isolation"
POLICY_COMPANY_ONLY = "company_isolation"
def upgrade() -> None:
"""Habilita RLS con políticas de aislamiento por tenant_id / company_id."""
op.execute("CREATE SCHEMA IF NOT EXISTS app")
op.execute(
"""
CREATE OR REPLACE FUNCTION app.current_tenant_id() RETURNS INTEGER
LANGUAGE sql STABLE AS $$
SELECT NULLIF(current_setting('app.tenant_id', true), '')::INTEGER
$$
"""
)
op.execute(
"""
CREATE OR REPLACE FUNCTION app.current_company_id() RETURNS INTEGER
LANGUAGE sql STABLE AS $$
SELECT NULLIF(current_setting('app.company_id', true), '')::INTEGER
$$
"""
)
for schema, table in TABLES_TENANT_ONLY:
op.execute(f'ALTER TABLE "{schema}"."{table}" ENABLE ROW LEVEL SECURITY')
op.execute(f'ALTER TABLE "{schema}"."{table}" FORCE ROW LEVEL SECURITY')
op.execute(
f"""
CREATE POLICY {POLICY_TENANT_ONLY} ON "{schema}"."{table}"
USING (tenant_id = app.current_tenant_id())
WITH CHECK (tenant_id = app.current_tenant_id())
"""
)
for schema, table in TABLES_TENANT_AND_COMPANY:
op.execute(f'ALTER TABLE "{schema}"."{table}" ENABLE ROW LEVEL SECURITY')
op.execute(f'ALTER TABLE "{schema}"."{table}" FORCE ROW LEVEL SECURITY')
op.execute(
f"""
CREATE POLICY {POLICY_TENANT_COMPANY} ON "{schema}"."{table}"
USING (
tenant_id = app.current_tenant_id()
AND (
app.current_company_id() IS NULL
OR company_id = app.current_company_id()
)
)
WITH CHECK (
tenant_id = app.current_tenant_id()
AND (
app.current_company_id() IS NULL
OR company_id = app.current_company_id()
)
)
"""
)
for schema, table in TABLES_COMPANY_ONLY:
op.execute(f'ALTER TABLE "{schema}"."{table}" ENABLE ROW LEVEL SECURITY')
op.execute(f'ALTER TABLE "{schema}"."{table}" FORCE ROW LEVEL SECURITY')
op.execute(
f"""
CREATE POLICY {POLICY_COMPANY_ONLY} ON "{schema}"."{table}"
USING (
EXISTS (
SELECT 1 FROM a76.company c
WHERE c.id = "{schema}"."{table}".company_id
AND c.tenant_id = app.current_tenant_id()
)
AND (
app.current_company_id() IS NULL
OR company_id = app.current_company_id()
)
)
WITH CHECK (
EXISTS (
SELECT 1 FROM a76.company c
WHERE c.id = "{schema}"."{table}".company_id
AND c.tenant_id = app.current_tenant_id()
)
AND (
app.current_company_id() IS NULL
OR company_id = app.current_company_id()
)
)
"""
)
def downgrade() -> None:
"""Revierte: drop policies, deshabilita RLS y elimina helpers."""
for schema, table in TABLES_COMPANY_ONLY:
op.execute(
f'DROP POLICY IF EXISTS {POLICY_COMPANY_ONLY} ON "{schema}"."{table}"'
)
op.execute(f'ALTER TABLE "{schema}"."{table}" NO FORCE ROW LEVEL SECURITY')
op.execute(f'ALTER TABLE "{schema}"."{table}" DISABLE ROW LEVEL SECURITY')
for schema, table in TABLES_TENANT_AND_COMPANY:
op.execute(
f'DROP POLICY IF EXISTS {POLICY_TENANT_COMPANY} ON "{schema}"."{table}"'
)
op.execute(f'ALTER TABLE "{schema}"."{table}" NO FORCE ROW LEVEL SECURITY')
op.execute(f'ALTER TABLE "{schema}"."{table}" DISABLE ROW LEVEL SECURITY')
for schema, table in TABLES_TENANT_ONLY:
op.execute(
f'DROP POLICY IF EXISTS {POLICY_TENANT_ONLY} ON "{schema}"."{table}"'
)
op.execute(f'ALTER TABLE "{schema}"."{table}" NO FORCE ROW LEVEL SECURITY')
op.execute(f'ALTER TABLE "{schema}"."{table}" DISABLE ROW LEVEL SECURITY')
op.execute("DROP FUNCTION IF EXISTS app.current_company_id()")
op.execute("DROP FUNCTION IF EXISTS app.current_tenant_id()")
op.execute("DROP SCHEMA IF EXISTS app")

View File

@@ -0,0 +1,193 @@
"""create expediente_archivo table and seed document types digitization catalog
Revision ID: f1a2b3c4d5e6
Revises: f7a8b9c0d1e2
Create Date: 2026-04-20 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "f1a2b3c4d5e6"
down_revision = "f7a8b9c0d1e2"
branch_labels = None
depends_on = None
# ---------------------------------------------------------------------------
# Seed data
# ---------------------------------------------------------------------------
DOCUMENT_TYPES = [
("168", "Calca o fotografía digital del NIV del vehículo."),
("169", "Aviso."),
("170", "Factura."),
("171", "Documento con el que se acredite la propiedad de la mercancía."),
("172", "Contratos."),
("176", "Documentación relacionada con la garantía otorgada en términos de los artículos 84."),
("177", "Identificación Oficial."),
("179", "Comprobante de domicilio."),
("184", "Documento que ampara el avaluó de las mercancías."),
("185", "Documentos de adjudicación judicial de las mercancías."),
("187", "Solicitud de retiro de mercancías que causaron abandono."),
("189", "Actas."),
("192", "Escritos."),
("420", "Certificado de peso o volumen."),
("421", "Comprobante de la importación temporal de la embarcación debidamente formalizado."),
("422", "Comprobante expedido por donataria."),
("423", "Consulta en la que conste que el vehículo no se encuentra reportado como robado,"),
("424", "Clave Unica del Registro de Población."),
("425", "Declaración de internación o extracción de cantidades en efectivo y/o documentos p"),
("426", "Declaración de operaciones que no confieren origen en países no parte de acuerdo"),
("427", "Declaración en la que se señalen los motivos por los que efectúa la devolución de m"),
("428", "Documentación con información que permita la identificación, análisis y control en tér"),
("429", "Documentación que acredite que acepta y subsana la irregularidad."),
("430", "Documentación que ampare la importación temporal del vehículo de que se trate."),
("431", "Documentación que compruebe que la adquisición de las mercancías fue efectuada "),
("433", "Documento con base en el cual se determine la procedencia y el origen de las merca"),
("434", "Documento con que se acredite el reintegro del IVA, en caso de que el contribuyente "),
("435", "Documentos previstos en la regla 8.7., fracciones I a IV de la Resolución del TLCAN."),
("436", "El Documento que compruebe el cumplimiento de las regulaciones y restricciones no "),
("438", "Guía aérea, conocimiento de embarque o carta de porte."),
("439", "Hoja con los datos de la matrícula y nombre del barco, el lugar donde se localiza y se "),
("440", "Manifiesto de carga."),
("441", "Oficios emitidos por autoridad."),
("442", "Pedimentos."),
("443", "Programa IMMEX."),
("444", "Relación de candados."),
("445", "Relación de certificados de origen."),
]
# ---------------------------------------------------------------------------
# Upgrade / Downgrade
# ---------------------------------------------------------------------------
def upgrade() -> None:
# -- Table -----------------------------------------------------------------
op.create_table(
"expediente_archivo",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("e_document", sa.String(length=50), nullable=True),
sa.Column("num_operacion", sa.String(length=50), nullable=True),
sa.Column("tipo_documento", sa.String(length=10), nullable=True),
sa.Column("archivo_digitalizado_en", sa.String(length=500), nullable=True),
sa.Column("fecha_digitalizacion", sa.Date(), nullable=True),
sa.Column("agente_aduanal", sa.String(length=50), nullable=True),
sa.Column("pedimento", sa.String(length=21), nullable=True),
sa.Column("rfc_consulta", sa.String(length=13), nullable=True),
sa.Column("nombre_archivo", sa.String(length=255), nullable=True),
sa.Column("status", sa.String(length=20), nullable=True),
sa.Column("task_id", sa.String(length=255), nullable=True),
sa.Column("external_task_id", sa.String(length=255), nullable=True),
sa.Column("acuse_pdf_path", sa.String(length=500), nullable=True),
sa.Column("envio_xml_path", sa.String(length=500), nullable=True),
sa.Column("respuesta_xml_path", sa.String(length=500), nullable=True),
sa.Column("consulta_envio_xml_path", sa.String(length=500), nullable=True),
sa.Column("consulta_respuesta_xml_path", sa.String(length=500), nullable=True),
sa.Column("tenant_id", sa.Integer(), nullable=False),
sa.Column("company_id", sa.Integer(), nullable=False),
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
sa.Column("updated_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
sa.Column("deleted_at", sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(["company_id"], ["a76.company.id"]),
sa.ForeignKeyConstraint(["tenant_id"], ["core.tenants.id"]),
sa.PrimaryKeyConstraint("id", name="expediente_archivo_pkey"),
schema="a76",
)
op.create_index(
op.f("ix_a76_expediente_archivo_company_id"),
"expediente_archivo",
["company_id"],
unique=False,
schema="a76",
)
op.create_index(
op.f("ix_a76_expediente_archivo_tenant_id"),
"expediente_archivo",
["tenant_id"],
unique=False,
schema="a76",
)
op.create_index(
op.f("ix_a76_expediente_archivo_task_id"),
"expediente_archivo",
["task_id"],
unique=False,
schema="a76",
)
op.create_index(
op.f("ix_a76_expediente_archivo_external_task_id"),
"expediente_archivo",
["external_task_id"],
unique=False,
schema="a76",
)
# -- Seeds -----------------------------------------------------------------
bind = op.get_bind()
companies = (
bind.execute(sa.text("SELECT id, tenant_id FROM a76.company ORDER BY id"))
.mappings()
.all()
)
for company in companies:
for code, description in DOCUMENT_TYPES:
bind.execute(
sa.text(
"""
INSERT INTO a76.document_types_digitization
(tenant_id, company_id, code, description, active)
VALUES
(:tenant_id, :company_id, :code, :description, TRUE)
ON CONFLICT ON CONSTRAINT document_types_digitization_code_key
DO NOTHING
"""
),
{
"tenant_id": company["tenant_id"],
"company_id": company["id"],
"code": code,
"description": description,
},
)
def downgrade() -> None:
# -- Remove seeds ----------------------------------------------------------
bind = op.get_bind()
codes = [code for code, _ in DOCUMENT_TYPES]
placeholders = ", ".join(f":c{i}" for i in range(len(codes)))
params = {f"c{i}": code for i, code in enumerate(codes)}
bind.execute(
sa.text(
f"DELETE FROM a76.document_types_digitization WHERE code IN ({placeholders})"
),
params,
)
# -- Drop table ------------------------------------------------------------
op.drop_index(
op.f("ix_a76_expediente_archivo_external_task_id"),
table_name="expediente_archivo",
schema="a76",
)
op.drop_index(
op.f("ix_a76_expediente_archivo_task_id"),
table_name="expediente_archivo",
schema="a76",
)
op.drop_index(
op.f("ix_a76_expediente_archivo_tenant_id"),
table_name="expediente_archivo",
schema="a76",
)
op.drop_index(
op.f("ix_a76_expediente_archivo_company_id"),
table_name="expediente_archivo",
schema="a76",
)
op.drop_table("expediente_archivo", schema="a76")

View File

@@ -0,0 +1,39 @@
"""fix driver transporter_key length and validations
Revision ID: f7a8b9c0d1e2
Revises: e76_app_settings
Create Date: 2026-04-17 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "f7a8b9c0d1e2"
down_revision = "e76_app_settings"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.alter_column(
"driver",
"transporter_key",
schema="a76",
existing_type=sa.String(length=5),
type_=sa.String(length=30),
existing_nullable=False,
)
def downgrade() -> None:
op.alter_column(
"driver",
"transporter_key",
schema="a76",
existing_type=sa.String(length=30),
type_=sa.String(length=5),
existing_nullable=False,
)