refactor: update alembic migrations and import models
- Added import for `alta_log_models` to `env.py` for autogeneration of tables outside of `models.py`. - Deleted several obsolete migration files, including those related to classification descriptions, initial data seeding, and legacy fields in the company certification schema. - Cleaned up migration history by removing unused migration scripts to streamline future updates.
This commit is contained in:
@@ -300,6 +300,9 @@ def import_models_from_dir(dir_path: str):
|
||||
modules_dir = os.path.join(BASE_DIR, "api", "v1", "modules")
|
||||
import_models_from_dir(modules_dir)
|
||||
|
||||
# Tablas declaradas fuera de models.py / carpeta models/ (autogenerate)
|
||||
import api.v1.modules.a76.general_catalogs.doda.alta_log_models # noqa: F401
|
||||
|
||||
|
||||
def run_migrations_offline() -> None:
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
"""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')
|
||||
@@ -1,189 +0,0 @@
|
||||
"""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)
|
||||
@@ -1,12 +1,10 @@
|
||||
"""seed_initial_data
|
||||
|
||||
Revision ID: 7937209f9718
|
||||
Revises:
|
||||
|
||||
Create Date: 2025-10-19 18:23:55.258800
|
||||
Revision ID: 8c9bad3da37f
|
||||
Revises: 9db46c604463
|
||||
Create Date: 2026-05-01 22:01:50.174319
|
||||
|
||||
"""
|
||||
|
||||
# pylint: disable=no-member
|
||||
|
||||
from typing import Sequence, Union
|
||||
@@ -87,44 +85,21 @@ from api.v1.modules.public.reference_data.carta_porte_codes.seed import seed_car
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "7937209f9718"
|
||||
down_revision: Union[str, Sequence[str], None] = "4ad64605fad2"
|
||||
revision: str = "8c9bad3da37f"
|
||||
down_revision: Union[str, Sequence[str], None] = "9db46c604463"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = "4ad64605fad2"
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
"""Catálogos de referencia y permisos base (datos)."""
|
||||
|
||||
def format_value(val):
|
||||
if val is None or str(val).strip() == "" or str(val).upper() == "NONE":
|
||||
return "NULL"
|
||||
return f"'{str(val).replace(chr(39), chr(39)*2)}'"
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS public.pedimento_transport_catalog (
|
||||
code VARCHAR(3) NOT NULL,
|
||||
transport_en VARCHAR(80) NOT NULL,
|
||||
transport_es VARCHAR(120) NOT NULL,
|
||||
payment_date_code VARCHAR(1) NOT NULL,
|
||||
CONSTRAINT pedimento_transport_catalog_pkey PRIMARY KEY (code),
|
||||
CONSTRAINT pedimento_transport_catalog_payment_date_code_chk
|
||||
CHECK (payment_date_code IN ('E','P'))
|
||||
);
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE IF EXISTS a76.pedimento_transport_means
|
||||
ALTER COLUMN entry_exit TYPE VARCHAR(3),
|
||||
ALTER COLUMN arrival TYPE VARCHAR(3),
|
||||
ALTER COLUMN departure TYPE VARCHAR(3);
|
||||
"""
|
||||
)
|
||||
|
||||
# --- SEEDS PUBLIC (Tablas base) ---
|
||||
# Seeds
|
||||
values_pc = ", ".join(
|
||||
[
|
||||
f"('{code}', '{desc.replace(chr(39), chr(39)*2)}')"
|
||||
@@ -364,8 +339,6 @@ def upgrade() -> None:
|
||||
)
|
||||
|
||||
# --- SEEDS A76 (Unidades de Medida) ---
|
||||
|
||||
# ACE
|
||||
val_ace = ", ".join(
|
||||
[f"({format_value(c)}, {format_value(d)})" for c, d in ace_seed]
|
||||
)
|
||||
@@ -373,7 +346,6 @@ def upgrade() -> None:
|
||||
f"INSERT INTO a76.unit_of_measure_ace (code, description) VALUES {val_ace} ON CONFLICT ON CONSTRAINT uq_uom_ace_code DO NOTHING;"
|
||||
)
|
||||
|
||||
# OMA
|
||||
val_oma = ", ".join(
|
||||
[f"({format_value(c)}, {format_value(d)})" for c, d in oma_seed]
|
||||
)
|
||||
@@ -381,7 +353,6 @@ def upgrade() -> None:
|
||||
f"INSERT INTO a76.unit_of_measure_oma (code, description) VALUES {val_oma} ON CONFLICT ON CONSTRAINT uq_uom_oma_code DO NOTHING;"
|
||||
)
|
||||
|
||||
# AME
|
||||
val_ame = ", ".join(
|
||||
[f"({format_value(c)}, {format_value(d)})" for c, d in ame_seed]
|
||||
)
|
||||
@@ -389,7 +360,6 @@ def upgrade() -> None:
|
||||
f"INSERT INTO a76.unit_of_measure_american (code, description) VALUES {val_ame} ON CONFLICT ON CONSTRAINT uq_uom_american_code DO NOTHING;"
|
||||
)
|
||||
|
||||
# ADUA (Customs) - seed_adua: (code, description, a76_unit_code)
|
||||
val_adua = ", ".join(
|
||||
[f"({format_value(code)}, {format_value(desc)}, {format_value(a76_code)})" for code, desc, a76_code in adua_seed]
|
||||
)
|
||||
@@ -397,7 +367,6 @@ def upgrade() -> None:
|
||||
f"INSERT INTO a76.unit_of_measure_customs (code, description, a76_unit_code) VALUES {val_adua} ON CONFLICT ON CONSTRAINT uq_uom_customs_code DO NOTHING;"
|
||||
)
|
||||
|
||||
# Recolectar códigos adicionales que faltan en los catálogos
|
||||
additional_customs = set()
|
||||
additional_american = set()
|
||||
additional_ace = set()
|
||||
@@ -418,10 +387,9 @@ def upgrade() -> None:
|
||||
if oma and oma.strip() and oma not in existing_oma:
|
||||
additional_oma.add((oma, f"Auto-generated from {code}"))
|
||||
|
||||
# Insertar códigos adicionales
|
||||
if additional_customs:
|
||||
val_add_customs = ", ".join(
|
||||
[f"({format_value(c)}, {format_value(d)}, {format_value(s)})" for c, d, s in additional_customs]
|
||||
[f"({format_value(c)}, {format_value(d)}, NULL)" for c, d in additional_customs]
|
||||
)
|
||||
op.execute(
|
||||
f"INSERT INTO a76.unit_of_measure_customs (code, description, a76_unit_code) VALUES {val_add_customs} ON CONFLICT ON CONSTRAINT uq_uom_customs_code DO NOTHING;"
|
||||
@@ -451,11 +419,7 @@ def upgrade() -> None:
|
||||
f"INSERT INTO a76.unit_of_measure_oma (code, description) VALUES {val_add_oma} ON CONFLICT ON CONSTRAINT uq_uom_oma_code DO NOTHING;"
|
||||
)
|
||||
|
||||
# TABLA MAESTRA UOM se genera ahora al crear una empresa
|
||||
|
||||
# --- SEEDS CORE (Permissions) ---
|
||||
|
||||
# Combinar todas las seeds de permisos desde el Registro V2
|
||||
all_permissions = registry.get_all()
|
||||
|
||||
values_permissions = ", ".join(
|
||||
@@ -474,7 +438,6 @@ def upgrade() -> None:
|
||||
"""
|
||||
)
|
||||
|
||||
# --- SEEDS PUBLIC (States) ---
|
||||
values_states = ", ".join(
|
||||
[
|
||||
f"('{m3_key}', '{description.replace(chr(39), chr(39)*2)}', {format_value(mex_key)})"
|
||||
@@ -489,7 +452,6 @@ def upgrade() -> None:
|
||||
"""
|
||||
)
|
||||
|
||||
# --- SEEDS A76 (Tariff Fractions - Fracciones Arancelarias Mexicanas) ---
|
||||
values_tariff_fractions = ", ".join(
|
||||
[
|
||||
f"({format_value(code)}, {format_value(fraction)}, {format_value(description)}, "
|
||||
@@ -505,9 +467,6 @@ def upgrade() -> None:
|
||||
"""
|
||||
)
|
||||
|
||||
# Historical Fractions se generan ahora al crear una empresa
|
||||
|
||||
# --- SEEDS NEW REFERENCE CATALOGS ---
|
||||
bind = op.get_bind()
|
||||
session = Session(bind=bind)
|
||||
seed_license_exceptions(session)
|
||||
@@ -517,44 +476,5 @@ def upgrade() -> None:
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE IF EXISTS a76.pedimento_transport_means
|
||||
ALTER COLUMN entry_exit TYPE VARCHAR(2),
|
||||
ALTER COLUMN arrival TYPE VARCHAR(2),
|
||||
ALTER COLUMN departure TYPE VARCHAR(2);
|
||||
"""
|
||||
)
|
||||
|
||||
op.drop_table("pedimento_transport_catalog", schema="public")
|
||||
op.drop_table("us_tariff_fractions", schema="a76")
|
||||
op.drop_table("historical_tariff_fractions", schema="a76")
|
||||
op.drop_table("canadian_tariff_fractions", schema="a76")
|
||||
op.drop_table("valuation_methods", schema="public")
|
||||
op.drop_table("transport_types", schema="public")
|
||||
op.drop_table("trailer_types", schema="public")
|
||||
op.drop_table("transport_modes", schema="public")
|
||||
op.drop_table("payment_methods", schema="public")
|
||||
op.drop_table("material_types", schema="public")
|
||||
op.drop_table("invoice_types", schema="public")
|
||||
op.drop_table("incoterms", schema="public")
|
||||
op.drop_table("customs_warehouses", schema="public")
|
||||
op.drop_table("customs_sections", schema="public")
|
||||
op.drop_table("currency_types", schema="public")
|
||||
op.drop_table("countries", schema="public")
|
||||
op.drop_table("containers", schema="public")
|
||||
op.drop_table("code_pedimento_regimens", schema="public")
|
||||
op.drop_table("pedimento_regimens", schema="public")
|
||||
op.drop_table("pedimento_codes", schema="public")
|
||||
op.drop_table("user_client_permissions", schema="core")
|
||||
op.drop_table("user_client_roles", schema="core")
|
||||
op.drop_table("role_permissions", schema="core")
|
||||
op.drop_table("client_roles", schema="core")
|
||||
op.drop_table("permissions", schema="core")
|
||||
op.drop_table("units_of_measure", schema="a76")
|
||||
op.drop_table("unit_of_measure_customs", schema="a76")
|
||||
op.drop_table("unit_of_measure_american", schema="a76")
|
||||
op.drop_table("unit_of_measure_oma", schema="a76")
|
||||
op.drop_table("unit_of_measure_ace", schema="a76")
|
||||
"""Los datos de catálogo no se revierten automáticamente."""
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +0,0 @@
|
||||
"""drop_legacy_return_counters
|
||||
|
||||
Revision ID: 9f3c2d1b7a11
|
||||
Revises: 4ad64605fad2
|
||||
Create Date: 2026-03-20 15:10:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "9f3c2d1b7a11"
|
||||
down_revision: Union[str, Sequence[str], None] = "7937209f9718"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Drop legacy quantity counters replaced by balance/discharge ledger."""
|
||||
op.drop_column("item_line_quantities", "quantity_returned_temp", schema="a76")
|
||||
op.drop_column("item_line_quantities", "quantity_returned", schema="a76")
|
||||
op.drop_column("item_line_quantities", "quantity_existence", schema="a76")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Restore legacy quantity counters."""
|
||||
op.add_column(
|
||||
"item_line_quantities",
|
||||
sa.Column("quantity_existence", sa.Numeric(precision=19, scale=8), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
op.add_column(
|
||||
"item_line_quantities",
|
||||
sa.Column("quantity_returned", sa.Numeric(precision=19, scale=8), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
op.add_column(
|
||||
"item_line_quantities",
|
||||
sa.Column("quantity_returned_temp", sa.Numeric(precision=19, scale=8), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
@@ -1,117 +0,0 @@
|
||||
"""create doda_alta_log table
|
||||
|
||||
Revision ID: a1b2c3d4e5f6
|
||||
Revises: d1a2b3c4e5f6
|
||||
Create Date: 2026-04-26 10:00:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "a1b2c3d4e5f6"
|
||||
down_revision = "d1a2b3c4e5f6"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"doda_alta_log",
|
||||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column("doda_id", sa.Integer(), nullable=True),
|
||||
sa.Column("variant", sa.String(length=10), nullable=True),
|
||||
sa.Column("responsible", sa.String(length=20), nullable=True),
|
||||
sa.Column("patent", sa.String(length=10), nullable=True),
|
||||
sa.Column("dispatch_customs", sa.String(length=10), nullable=True),
|
||||
sa.Column("operation_type", sa.String(length=5), nullable=True),
|
||||
sa.Column("integration_number", sa.String(length=50), nullable=True),
|
||||
sa.Column("task_id", sa.String(length=255), nullable=True),
|
||||
sa.Column("status", sa.String(length=30), nullable=True),
|
||||
sa.Column("message", sa.String(length=2000), nullable=True),
|
||||
sa.Column("result_json", sa.Text(), 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="doda_alta_log_pkey"),
|
||||
schema="a76",
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_a76_doda_alta_log_company_id"),
|
||||
"doda_alta_log",
|
||||
["company_id"],
|
||||
unique=False,
|
||||
schema="a76",
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_a76_doda_alta_log_tenant_id"),
|
||||
"doda_alta_log",
|
||||
["tenant_id"],
|
||||
unique=False,
|
||||
schema="a76",
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_a76_doda_alta_log_doda_id"),
|
||||
"doda_alta_log",
|
||||
["doda_id"],
|
||||
unique=False,
|
||||
schema="a76",
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_a76_doda_alta_log_task_id"),
|
||||
"doda_alta_log",
|
||||
["task_id"],
|
||||
unique=False,
|
||||
schema="a76",
|
||||
)
|
||||
|
||||
# Reporte PDF almacenado (S3) + invalidación por huella de contenido
|
||||
op.add_column(
|
||||
"doda",
|
||||
sa.Column("doda_report_pdf_path", sa.String(length=1000), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
op.add_column(
|
||||
"doda",
|
||||
sa.Column("doda_report_pdf_generated_at", sa.DateTime(), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
op.add_column(
|
||||
"doda",
|
||||
sa.Column("doda_report_source_fingerprint", sa.String(length=64), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("doda", "doda_report_source_fingerprint", schema="a76")
|
||||
op.drop_column("doda", "doda_report_pdf_generated_at", schema="a76")
|
||||
op.drop_column("doda", "doda_report_pdf_path", schema="a76")
|
||||
|
||||
op.drop_index(
|
||||
op.f("ix_a76_doda_alta_log_task_id"),
|
||||
table_name="doda_alta_log",
|
||||
schema="a76",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_a76_doda_alta_log_doda_id"),
|
||||
table_name="doda_alta_log",
|
||||
schema="a76",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_a76_doda_alta_log_tenant_id"),
|
||||
table_name="doda_alta_log",
|
||||
schema="a76",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_a76_doda_alta_log_company_id"),
|
||||
table_name="doda_alta_log",
|
||||
schema="a76",
|
||||
)
|
||||
op.drop_table("doda_alta_log", schema="a76")
|
||||
@@ -1,28 +0,0 @@
|
||||
"""drop client_id column from parts
|
||||
|
||||
Revision ID: b2c3d4e5f6a7
|
||||
Revises: a1b2c3d4e5f6
|
||||
Create Date: 2026-04-28 11:50:00.000000
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "b2c3d4e5f6a7"
|
||||
down_revision = "a1b2c3d4e5f6"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.drop_column("parts", "client_id", schema="a76")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.add_column(
|
||||
"parts",
|
||||
sa.Column("client_id", sa.Integer(), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
@@ -1,45 +0,0 @@
|
||||
"""iva_factor
|
||||
|
||||
Revision ID: bccb7f8986c7
|
||||
Revises: 9f3c2d1b7a11
|
||||
Create Date: 2026-03-23 09:44:02.275257
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'bccb7f8986c7'
|
||||
down_revision: Union[str, Sequence[str], None] = '9f3c2d1b7a11'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_index(op.f('ix_public_carta_porte_code'), table_name='carta_porte_codes')
|
||||
op.create_index(op.f('ix_public_carta_porte_codes_code'), 'carta_porte_codes', ['code'], unique=False, schema='public')
|
||||
op.alter_column('invoice_financials', 'iva_factor',
|
||||
existing_type=sa.VARCHAR(length=10),
|
||||
type_=sa.Numeric(precision=23, scale=8),
|
||||
postgresql_using='iva_factor::numeric(23,8)',
|
||||
existing_nullable=True,
|
||||
schema='a76')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('invoice_financials', 'iva_factor',
|
||||
existing_type=sa.Numeric(precision=23, scale=8),
|
||||
type_=sa.VARCHAR(length=10),
|
||||
existing_nullable=True,
|
||||
schema='a76')
|
||||
op.drop_index(op.f('ix_public_carta_porte_codes_code'), table_name='carta_porte_codes', schema='public')
|
||||
op.create_index(op.f('ix_public_carta_porte_code'), 'carta_porte_codes', ['code'], unique=False)
|
||||
# ### end Alembic commands ###
|
||||
@@ -1,142 +0,0 @@
|
||||
"""create_core_task_runs and backfill code_pedimento_regimens
|
||||
|
||||
Revision ID: c1a2b3d4e5f6
|
||||
Revises: bccb7f8986c7
|
||||
Create Date: 2026-03-24 11:30:00.000000
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
from api.v1.modules.public.reference_data.code_pedimento_regimens.seed import (
|
||||
seed as code_pedimento_regimens_seed_full,
|
||||
)
|
||||
from api.v1.modules.public.reference_data.pedimento_codes.seed import (
|
||||
seed as pedimento_codes_seed,
|
||||
)
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "c1a2b3d4e5f6"
|
||||
down_revision: Union[str, Sequence[str], None] = "bccb7f8986c7"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def _format_value(val: str | None) -> str:
|
||||
if val is None or str(val).strip() == "" or str(val).upper() == "NONE":
|
||||
return "NULL"
|
||||
return f"'{str(val).replace(chr(39), chr(39) * 2)}'"
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"task_runs",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("task_id", sa.String(length=255), nullable=False),
|
||||
sa.Column("tenant_id", sa.Integer(), nullable=False),
|
||||
sa.Column("company_id", sa.Integer(), nullable=True),
|
||||
sa.Column("requested_by_user", sa.String(length=255), nullable=True),
|
||||
sa.Column("task_name", sa.String(length=255), nullable=False),
|
||||
sa.Column("task_group", sa.String(length=100), nullable=False),
|
||||
sa.Column("task_origin", sa.String(length=255), nullable=True),
|
||||
sa.Column("status", sa.String(length=20), nullable=False),
|
||||
sa.Column("celery_state_raw", sa.String(length=30), nullable=False),
|
||||
sa.Column("progress_current", sa.Integer(), nullable=True),
|
||||
sa.Column("progress_total", sa.Integer(), nullable=True),
|
||||
sa.Column("progress_percent", sa.Float(), nullable=True),
|
||||
sa.Column("progress_message", sa.String(length=500), nullable=True),
|
||||
sa.Column("retries", sa.Integer(), nullable=True),
|
||||
sa.Column("exception_type", sa.String(length=255), nullable=True),
|
||||
sa.Column("exception_message", sa.Text(), nullable=True),
|
||||
sa.Column("traceback_excerpt", sa.Text(), nullable=True),
|
||||
sa.Column("result_summary", postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column("meta_payload", postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column("started_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False),
|
||||
sa.ForeignKeyConstraint(["company_id"], ["a76.company.id"]),
|
||||
sa.ForeignKeyConstraint(["tenant_id"], ["core.tenants.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
schema="core",
|
||||
)
|
||||
op.create_index("ix_core_task_runs_task_id", "task_runs", ["task_id"], unique=True, schema="core")
|
||||
op.create_index("ix_core_task_runs_tenant_updated", "task_runs", ["tenant_id", "updated_at"], unique=False, schema="core")
|
||||
op.create_index(
|
||||
"ix_core_task_runs_tenant_status_updated",
|
||||
"task_runs",
|
||||
["tenant_id", "status", "updated_at"],
|
||||
unique=False,
|
||||
schema="core",
|
||||
)
|
||||
op.create_index(
|
||||
"ix_core_task_runs_tenant_group_updated",
|
||||
"task_runs",
|
||||
["tenant_id", "task_group", "updated_at"],
|
||||
unique=False,
|
||||
schema="core",
|
||||
)
|
||||
op.create_index(
|
||||
"ix_core_task_runs_tenant_company_updated",
|
||||
"task_runs",
|
||||
["tenant_id", "company_id", "updated_at"],
|
||||
unique=False,
|
||||
schema="core",
|
||||
)
|
||||
|
||||
pedimento_desc_by_code = {code: desc for code, desc in pedimento_codes_seed}
|
||||
required_pedimento_codes = sorted(
|
||||
{pedimento_code for pedimento_code, _regimen_code, _type_code in code_pedimento_regimens_seed_full}
|
||||
)
|
||||
|
||||
values_missing_codes = ", ".join(
|
||||
[
|
||||
f"({_format_value(code)}, {_format_value(pedimento_desc_by_code.get(code, f'AUTO-GENERATED FOR FK ({code})'))})"
|
||||
for code in required_pedimento_codes
|
||||
]
|
||||
)
|
||||
op.execute(
|
||||
f"""
|
||||
INSERT INTO public.pedimento_codes (code, description)
|
||||
VALUES {values_missing_codes}
|
||||
ON CONFLICT (code) DO NOTHING;
|
||||
"""
|
||||
)
|
||||
|
||||
values_relations = ", ".join(
|
||||
[
|
||||
f"({_format_value(pedimento_code)}, {_format_value(regimen_code)}, {_format_value(type_code)})"
|
||||
for pedimento_code, regimen_code, type_code in code_pedimento_regimens_seed_full
|
||||
]
|
||||
)
|
||||
op.execute(
|
||||
f"""
|
||||
INSERT INTO public.code_pedimento_regimens (pedimento_code, regimen_code, type_code)
|
||||
SELECT src.pedimento_code, src.regimen_code, src.type_code
|
||||
FROM (VALUES {values_relations}) AS src(pedimento_code, regimen_code, type_code)
|
||||
JOIN public.pedimento_codes pc
|
||||
ON pc.code = src.pedimento_code
|
||||
JOIN public.pedimento_regimens pr
|
||||
ON pr.code = src.regimen_code
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.code_pedimento_regimens cpr
|
||||
WHERE cpr.pedimento_code = src.pedimento_code
|
||||
AND cpr.regimen_code = src.regimen_code
|
||||
AND COALESCE(cpr.type_code, '') = COALESCE(src.type_code, '')
|
||||
);
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index("ix_core_task_runs_tenant_company_updated", table_name="task_runs", schema="core")
|
||||
op.drop_index("ix_core_task_runs_tenant_group_updated", table_name="task_runs", schema="core")
|
||||
op.drop_index("ix_core_task_runs_tenant_status_updated", table_name="task_runs", schema="core")
|
||||
op.drop_index("ix_core_task_runs_tenant_updated", table_name="task_runs", schema="core")
|
||||
op.drop_index("ix_core_task_runs_task_id", table_name="task_runs", schema="core")
|
||||
op.drop_table("task_runs", schema="core")
|
||||
@@ -1,29 +0,0 @@
|
||||
"""add action column to doda_alta_log
|
||||
|
||||
Revision ID: c3d4e5f6a7b8
|
||||
Revises: b2c3d4e5f6a7
|
||||
Create Date: 2026-04-28 13:20:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "c3d4e5f6a7b8"
|
||||
down_revision = "b2c3d4e5f6a7"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column(
|
||||
"doda_alta_log",
|
||||
sa.Column("action", sa.String(length=20), nullable=True),
|
||||
schema="a76",
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("doda_alta_log", "action", schema="a76")
|
||||
@@ -1,49 +0,0 @@
|
||||
"""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)
|
||||
@@ -1,266 +0,0 @@
|
||||
"""Add surrogate int IDs for transport catalogs and invoice logistics.
|
||||
|
||||
Single consolidated migration for:
|
||||
- transporter_id, trailer_id, vehicle_id, driver_id
|
||||
- carrier_int_id, transport_int_id, trailer_int_id in invoice_logistics
|
||||
- backfill mappings from existing string keys/codes
|
||||
- FK constraints for the new invoice_logistics int references
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = "ca7d3c4e8b2a"
|
||||
down_revision: Union[str, Sequence[str], None] = "c1a2b3d4e5f6"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# transporter
|
||||
op.add_column("transporter", sa.Column("transporter_id", sa.BigInteger(), nullable=True), schema="a76")
|
||||
op.execute(
|
||||
"""
|
||||
WITH s AS (
|
||||
SELECT transporter_key, ROW_NUMBER() OVER (ORDER BY transporter_key) AS new_id
|
||||
FROM a76.transporter
|
||||
)
|
||||
UPDATE a76.transporter t
|
||||
SET transporter_id = s.new_id
|
||||
FROM s
|
||||
WHERE t.transporter_key = s.transporter_key
|
||||
"""
|
||||
)
|
||||
op.execute("CREATE SEQUENCE IF NOT EXISTS a76.transporter_transporter_id_seq")
|
||||
op.execute(
|
||||
"""
|
||||
SELECT setval(
|
||||
'a76.transporter_transporter_id_seq',
|
||||
COALESCE((SELECT MAX(transporter_id) FROM a76.transporter), 0) + 1,
|
||||
false
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE a76.transporter
|
||||
ALTER COLUMN transporter_id
|
||||
SET DEFAULT nextval('a76.transporter_transporter_id_seq')
|
||||
"""
|
||||
)
|
||||
op.execute("ALTER TABLE a76.transporter ALTER COLUMN transporter_id SET NOT NULL")
|
||||
op.create_unique_constraint("uq_a76_transporter_transporter_id", "transporter", ["transporter_id"], schema="a76")
|
||||
|
||||
# trailer
|
||||
op.add_column("trailer", sa.Column("trailer_id", sa.BigInteger(), nullable=True), schema="a76")
|
||||
op.execute(
|
||||
"""
|
||||
WITH s AS (
|
||||
SELECT trailer_number, ROW_NUMBER() OVER (ORDER BY trailer_number) AS new_id
|
||||
FROM a76.trailer
|
||||
)
|
||||
UPDATE a76.trailer t
|
||||
SET trailer_id = s.new_id
|
||||
FROM s
|
||||
WHERE t.trailer_number = s.trailer_number
|
||||
"""
|
||||
)
|
||||
op.execute("CREATE SEQUENCE IF NOT EXISTS a76.trailer_trailer_id_seq")
|
||||
op.execute(
|
||||
"""
|
||||
SELECT setval(
|
||||
'a76.trailer_trailer_id_seq',
|
||||
COALESCE((SELECT MAX(trailer_id) FROM a76.trailer), 0) + 1,
|
||||
false
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE a76.trailer
|
||||
ALTER COLUMN trailer_id
|
||||
SET DEFAULT nextval('a76.trailer_trailer_id_seq')
|
||||
"""
|
||||
)
|
||||
op.execute("ALTER TABLE a76.trailer ALTER COLUMN trailer_id SET NOT NULL")
|
||||
op.create_unique_constraint("uq_a76_trailer_trailer_id", "trailer", ["trailer_id"], schema="a76")
|
||||
|
||||
# vehicle
|
||||
op.add_column("vehicle", sa.Column("vehicle_id", sa.BigInteger(), nullable=True), schema="a76")
|
||||
op.execute(
|
||||
"""
|
||||
WITH s AS (
|
||||
SELECT vehicle_key, ROW_NUMBER() OVER (ORDER BY vehicle_key) AS new_id
|
||||
FROM a76.vehicle
|
||||
)
|
||||
UPDATE a76.vehicle v
|
||||
SET vehicle_id = s.new_id
|
||||
FROM s
|
||||
WHERE v.vehicle_key = s.vehicle_key
|
||||
"""
|
||||
)
|
||||
op.execute("CREATE SEQUENCE IF NOT EXISTS a76.vehicle_vehicle_id_seq")
|
||||
op.execute(
|
||||
"""
|
||||
SELECT setval(
|
||||
'a76.vehicle_vehicle_id_seq',
|
||||
COALESCE((SELECT MAX(vehicle_id) FROM a76.vehicle), 0) + 1,
|
||||
false
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE a76.vehicle
|
||||
ALTER COLUMN vehicle_id
|
||||
SET DEFAULT nextval('a76.vehicle_vehicle_id_seq')
|
||||
"""
|
||||
)
|
||||
op.execute("ALTER TABLE a76.vehicle ALTER COLUMN vehicle_id SET NOT NULL")
|
||||
op.create_unique_constraint("uq_a76_vehicle_vehicle_id", "vehicle", ["vehicle_id"], schema="a76")
|
||||
|
||||
# driver
|
||||
op.add_column("driver", sa.Column("driver_id", sa.BigInteger(), nullable=True), schema="a76")
|
||||
op.execute(
|
||||
"""
|
||||
WITH s AS (
|
||||
SELECT transporter_key, line, ROW_NUMBER() OVER (ORDER BY transporter_key, line) AS new_id
|
||||
FROM a76.driver
|
||||
)
|
||||
UPDATE a76.driver d
|
||||
SET driver_id = s.new_id
|
||||
FROM s
|
||||
WHERE d.transporter_key = s.transporter_key
|
||||
AND d.line = s.line
|
||||
"""
|
||||
)
|
||||
op.execute("CREATE SEQUENCE IF NOT EXISTS a76.driver_driver_id_seq")
|
||||
op.execute(
|
||||
"""
|
||||
SELECT setval(
|
||||
'a76.driver_driver_id_seq',
|
||||
COALESCE((SELECT MAX(driver_id) FROM a76.driver), 0) + 1,
|
||||
false
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE a76.driver
|
||||
ALTER COLUMN driver_id
|
||||
SET DEFAULT nextval('a76.driver_driver_id_seq')
|
||||
"""
|
||||
)
|
||||
op.execute("ALTER TABLE a76.driver ALTER COLUMN driver_id SET NOT NULL")
|
||||
op.create_unique_constraint("uq_a76_driver_driver_id", "driver", ["driver_id"], schema="a76")
|
||||
|
||||
# invoice_logistics int refs
|
||||
op.add_column("invoice_logistics", sa.Column("carrier_int_id", sa.BigInteger(), nullable=True), schema="a76")
|
||||
op.add_column("invoice_logistics", sa.Column("transport_int_id", sa.BigInteger(), nullable=True), schema="a76")
|
||||
op.add_column("invoice_logistics", sa.Column("trailer_int_id", sa.BigInteger(), nullable=True), schema="a76")
|
||||
|
||||
# ensure referenced codes exist
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO a76.transporter (transporter_key, tenant_id, company_id)
|
||||
SELECT DISTINCT ON (il.carrier_id) il.carrier_id, il.tenant_id, il.company_id
|
||||
FROM a76.invoice_logistics il
|
||||
WHERE il.carrier_id IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM a76.transporter t WHERE t.transporter_key = il.carrier_id
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO a76.vehicle (vehicle_key, tenant_id, company_id)
|
||||
SELECT DISTINCT ON (il.transport_id) il.transport_id, il.tenant_id, il.company_id
|
||||
FROM a76.invoice_logistics il
|
||||
WHERE il.transport_id IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM a76.vehicle v WHERE v.vehicle_key = il.transport_id
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO a76.trailer (trailer_number, tenant_id, company_id)
|
||||
SELECT DISTINCT ON (il.trailer_num) il.trailer_num, il.tenant_id, il.company_id
|
||||
FROM a76.invoice_logistics il
|
||||
WHERE il.trailer_num IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM a76.trailer tr WHERE tr.trailer_number = il.trailer_num
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
# backfill int refs
|
||||
op.execute(
|
||||
"""
|
||||
UPDATE a76.invoice_logistics il
|
||||
SET carrier_int_id = t.transporter_id
|
||||
FROM a76.transporter t
|
||||
WHERE il.carrier_id IS NOT NULL
|
||||
AND il.carrier_id = t.transporter_key
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
UPDATE a76.invoice_logistics il
|
||||
SET transport_int_id = v.vehicle_id
|
||||
FROM a76.vehicle v
|
||||
WHERE il.transport_id IS NOT NULL
|
||||
AND il.transport_id = v.vehicle_key
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
UPDATE a76.invoice_logistics il
|
||||
SET trailer_int_id = tr.trailer_id
|
||||
FROM a76.trailer tr
|
||||
WHERE il.trailer_num IS NOT NULL
|
||||
AND il.trailer_num = tr.trailer_number
|
||||
"""
|
||||
)
|
||||
|
||||
# FK constraints
|
||||
op.create_foreign_key(
|
||||
"fk_a76_invoice_logistics_carrier_int_id_transporter_id",
|
||||
"invoice_logistics",
|
||||
"transporter",
|
||||
["carrier_int_id"],
|
||||
["transporter_id"],
|
||||
source_schema="a76",
|
||||
referent_schema="a76",
|
||||
ondelete="SET NULL",
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"fk_a76_invoice_logistics_transport_int_id_vehicle_id",
|
||||
"invoice_logistics",
|
||||
"vehicle",
|
||||
["transport_int_id"],
|
||||
["vehicle_id"],
|
||||
source_schema="a76",
|
||||
referent_schema="a76",
|
||||
ondelete="SET NULL",
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"fk_a76_invoice_logistics_trailer_int_id_trailer_id",
|
||||
"invoice_logistics",
|
||||
"trailer",
|
||||
["trailer_int_id"],
|
||||
["trailer_id"],
|
||||
source_schema="a76",
|
||||
referent_schema="a76",
|
||||
ondelete="SET NULL",
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
pass
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
"""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")
|
||||
@@ -1,39 +0,0 @@
|
||||
"""extend company.logo for S3 keys
|
||||
|
||||
Revision ID: d4e5f6a7b8c9
|
||||
Revises: ca7d3c4e8b2a
|
||||
Create Date: 2026-04-02
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision: str = "d4e5f6a7b8c9"
|
||||
down_revision: Union[str, None] = "ca7d3c4e8b2a"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.alter_column(
|
||||
"company",
|
||||
"logo",
|
||||
existing_type=sa.String(length=255),
|
||||
type_=sa.String(length=512),
|
||||
existing_nullable=True,
|
||||
schema="a76",
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.alter_column(
|
||||
"company",
|
||||
"logo",
|
||||
existing_type=sa.String(length=512),
|
||||
type_=sa.String(length=255),
|
||||
existing_nullable=True,
|
||||
schema="a76",
|
||||
)
|
||||
@@ -1,40 +0,0 @@
|
||||
"""add_app_settings_table
|
||||
|
||||
Revision ID: e76_app_settings
|
||||
Revises: c1a2b3d4e5f6
|
||||
Create Date: 2026-03-27 16:10:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'e76_app_settings'
|
||||
down_revision = 'd4e5f6a7b8c9'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# Create a76.app_settings table
|
||||
op.create_table(
|
||||
'app_settings',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('tenant_id', sa.Integer(), nullable=True),
|
||||
sa.Column('company_id', sa.Integer(), nullable=True),
|
||||
sa.Column('settings', postgresql.JSONB(astext_type=sa.Text()), nullable=False, server_default='{}'),
|
||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
|
||||
sa.ForeignKeyConstraint(['company_id'], ['a76.company.id'], ),
|
||||
sa.ForeignKeyConstraint(['tenant_id'], ['core.tenants.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('tenant_id', 'company_id', name='uq_app_settings_tenant_company'),
|
||||
schema='a76'
|
||||
)
|
||||
op.create_index(op.f('ix_a76_app_settings_company_id'), 'app_settings', ['company_id'], unique=False, schema='a76')
|
||||
op.create_index(op.f('ix_a76_app_settings_tenant_id'), 'app_settings', ['tenant_id'], unique=False, schema='a76')
|
||||
|
||||
def downgrade():
|
||||
op.drop_index(op.f('ix_a76_app_settings_tenant_id'), table_name='app_settings', schema='a76')
|
||||
op.drop_index(op.f('ix_a76_app_settings_company_id'), table_name='app_settings', schema='a76')
|
||||
op.drop_table('app_settings', schema='a76')
|
||||
@@ -1,193 +0,0 @@
|
||||
"""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")
|
||||
@@ -1,39 +0,0 @@
|
||||
"""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,
|
||||
)
|
||||
@@ -1,53 +0,0 @@
|
||||
"""increase invoice_header who_processed and capture_user to 100 chars
|
||||
|
||||
Revision ID: g1b2c3d4e5f6
|
||||
Revises: f7a8b9c0d1e2
|
||||
Create Date: 2026-04-30 00:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'g1b2c3d4e5f6'
|
||||
down_revision = 'f7a8b9c0d1e2'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.alter_column(
|
||||
'invoice_header',
|
||||
'who_processed',
|
||||
existing_type=sa.String(length=20),
|
||||
type_=sa.String(length=100),
|
||||
existing_nullable=True,
|
||||
schema='a76',
|
||||
)
|
||||
op.alter_column(
|
||||
'invoice_header',
|
||||
'capture_user',
|
||||
existing_type=sa.String(length=20),
|
||||
type_=sa.String(length=100),
|
||||
existing_nullable=True,
|
||||
schema='a76',
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.alter_column(
|
||||
'invoice_header',
|
||||
'capture_user',
|
||||
existing_type=sa.String(length=100),
|
||||
type_=sa.String(length=20),
|
||||
existing_nullable=True,
|
||||
schema='a76',
|
||||
)
|
||||
op.alter_column(
|
||||
'invoice_header',
|
||||
'who_processed',
|
||||
existing_type=sa.String(length=100),
|
||||
type_=sa.String(length=20),
|
||||
existing_nullable=True,
|
||||
schema='a76',
|
||||
)
|
||||
@@ -1,26 +0,0 @@
|
||||
"""merge alembic heads for deployment
|
||||
|
||||
Revision ID: h1a2b3c4d5e6
|
||||
Revises: c3d4e5f6a7b8, g1b2c3d4e5f6
|
||||
Create Date: 2026-04-30 12:00:00.000000
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "h1a2b3c4d5e6"
|
||||
down_revision: Union[str, Sequence[str], None] = (
|
||||
"c3d4e5f6a7b8",
|
||||
"g1b2c3d4e5f6",
|
||||
)
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
pass
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
pass
|
||||
@@ -1,104 +0,0 @@
|
||||
"""Fix VARCHAR(20) truncation errors in audit_log and discharges
|
||||
|
||||
Revision ID: i7j8k9l0m1n2
|
||||
Revises: h1a2b3c4d5e6
|
||||
Create Date: 2026-04-30 13:00:00.000000
|
||||
|
||||
Issues fixed:
|
||||
- audit_log.system: String(20) → String(50)
|
||||
- audit_log.operation_type: String(20) → String(50)
|
||||
- discharges.cancelled_by: String(20) → String(100)
|
||||
- octave_balance.octave_permit: String(20) → String(100)
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'i7j8k9l0m1n2'
|
||||
down_revision = 'h1a2b3c4d5e6'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Fix audit_log.system
|
||||
op.alter_column(
|
||||
'audit_logs',
|
||||
'system',
|
||||
existing_type=sa.String(length=20),
|
||||
type_=sa.String(length=50),
|
||||
existing_nullable=False,
|
||||
schema='a76',
|
||||
)
|
||||
|
||||
# Fix audit_log.operation_type
|
||||
op.alter_column(
|
||||
'audit_logs',
|
||||
'operation_type',
|
||||
existing_type=sa.String(length=20),
|
||||
type_=sa.String(length=50),
|
||||
existing_nullable=True,
|
||||
schema='a76',
|
||||
)
|
||||
|
||||
# Fix discharges.cancelled_by
|
||||
op.alter_column(
|
||||
'discharge_header',
|
||||
'cancelled_by',
|
||||
existing_type=sa.String(length=20),
|
||||
type_=sa.String(length=100),
|
||||
existing_nullable=True,
|
||||
schema='a24',
|
||||
)
|
||||
|
||||
# Fix octave_balance.octave_permit
|
||||
op.alter_column(
|
||||
'octave_balance',
|
||||
'octave_permit',
|
||||
existing_type=sa.String(length=20),
|
||||
type_=sa.String(length=100),
|
||||
existing_nullable=False,
|
||||
schema='a76',
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# Revert octave_balance.octave_permit
|
||||
op.alter_column(
|
||||
'octave_balance',
|
||||
'octave_permit',
|
||||
existing_type=sa.String(length=100),
|
||||
type_=sa.String(length=20),
|
||||
existing_nullable=False,
|
||||
schema='a76',
|
||||
)
|
||||
|
||||
# Revert discharges.cancelled_by
|
||||
op.alter_column(
|
||||
'discharge_header',
|
||||
'cancelled_by',
|
||||
existing_type=sa.String(length=100),
|
||||
type_=sa.String(length=20),
|
||||
existing_nullable=True,
|
||||
schema='a24',
|
||||
)
|
||||
|
||||
# Revert audit_log.operation_type
|
||||
op.alter_column(
|
||||
'audit_logs',
|
||||
'operation_type',
|
||||
existing_type=sa.String(length=50),
|
||||
type_=sa.String(length=20),
|
||||
existing_nullable=True,
|
||||
schema='a76',
|
||||
)
|
||||
|
||||
# Revert audit_log.system
|
||||
op.alter_column(
|
||||
'audit_logs',
|
||||
'system',
|
||||
existing_type=sa.String(length=50),
|
||||
type_=sa.String(length=20),
|
||||
existing_nullable=False,
|
||||
schema='a76',
|
||||
)
|
||||
Reference in New Issue
Block a user