chore: resolve remaining merge conflicts in data-table-actions components
This commit is contained in:
@@ -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')
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
@@ -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,
|
||||
)
|
||||
Reference in New Issue
Block a user