Merge pull request 'feature/migrations' (#228) from feature/migrations into development

Reviewed-on: ADUANASOFT/anexo76#228
This commit is contained in:
2026-03-18 22:04:19 +00:00
10 changed files with 4817 additions and 296 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,6 @@ from api.v1.modules.public.reference_data.pedimento_codes.seed import (
from api.v1.modules.public.reference_data.pedimento_regimens.seed import (
seed as pedimento_regimens_seed,
)
from api.v1.modules.a76.general_catalogs.sectors.seed import seed as sectors_seed
from api.v1.modules.public.reference_data.states.seed import seed as states_seed
from api.v1.modules.public.reference_data.transport_modes.seed import (
seed as transport_modes_seed,
@@ -89,14 +88,14 @@ from api.v1.modules.core.permissions.seed import (
from api.v1.modules.public.reference_data.license_exceptions.seed import seed_license_exceptions
from api.v1.modules.public.reference_data.agency_tariff_codes.seed import seed_agency_tariff_codes
from api.v1.modules.public.reference_data.identifiers.seed import seed_identifiers
from api.v1.modules.public.reference_data.carta_porte.seed import seed_carta_porte
from api.v1.modules.public.reference_data.carta_porte_codes.seed import seed_carta_porte
from sqlalchemy.orm import Session
# revision identifiers, used by Alembic.
revision: str = "7937209f9718"
down_revision: Union[str, Sequence[str], None] = None
down_revision: Union[str, Sequence[str], None] = "4ad64605fad2"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = "4ad64605fad2"
def upgrade() -> None:
@@ -299,9 +298,6 @@ def upgrade() -> None:
"""
)
# Sectors se siembran por compañía en _seed_company_data
# (a76.sectors requiere tenant_id/company_id — no aplica en seed global)
values_tm = ", ".join(
[
f"('{key}', '{name.replace(chr(39), chr(39)*2)}')"
@@ -544,8 +540,7 @@ def downgrade() -> None:
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("sectors", schema="a76")
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")

View File

@@ -0,0 +1,150 @@
# Importar modelos para Audit Log
from api.v1.modules.a76.pedmientos.models.pedimentos import Pedimentos
from api.v1.modules.a76.invoices.models import InvoiceHeader, InvoiceSalesDetails
from api.v1.modules.a76.audit_log.events import register_audit_listeners
# Core Modules
from api.v1.modules.a76.clients_and_providers.models import ClientProvider
from api.v1.modules.a76.customs_brokers.models import CustomsBroker
from api.v1.modules.a76.parts.models import Part
from api.v1.modules.a76.items.models import LineItem
from api.v1.modules.a76.general_catalogs.company.models import Company
# Reference Data
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.currency_types.models import CurrencyType
from api.v1.modules.public.reference_data.customs_sections.models import CustomsSection
from api.v1.modules.public.reference_data.customs_warehouses.models import (
CustomsWarehouse,
)
from api.v1.modules.public.reference_data.incoterms.models import Incoterm
from api.v1.modules.public.reference_data.invoice_types.models import InvoiceType
from api.v1.modules.public.reference_data.material_types.models import MaterialType
from api.v1.modules.public.reference_data.payment_methods.models import PaymentMethod
from api.v1.modules.public.reference_data.pedimento_transport_catalog.models import (
PedimentoTransportCatalog,
)
from api.v1.modules.public.reference_data.pedimento_codes.models import PedimentoCode
from api.v1.modules.public.reference_data.pedimento_regimens.models import (
RegimenPedimento,
)
from api.v1.modules.public.reference_data.states.models import State
from api.v1.modules.public.reference_data.transport_modes.models import TransportMode
from api.v1.modules.public.reference_data.transport_types.models import TransportType
from api.v1.modules.public.reference_data.valuation_methods.models import (
ValuationMethod,
)
from api.v1.modules.public.reference_data.license_exceptions.models import LicenseException
from api.v1.modules.public.reference_data.agency_tariff_codes.models import AgencyTariffCode
from api.v1.modules.public.reference_data.identifiers.models import IdentifierCatalog
from api.v1.modules.public.reference_data.carta_porte_codes.models import CartaPorte
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure
from api.v1.modules.a76.general_catalogs.exchange_rate.models import ExchangeRate
from api.v1.modules.a76.general_catalogs.identifiers.models import Identifier
from api.v1.modules.a76.classes.models import Class
from api.v1.modules.a76.general_catalogs.classification_concepts.models import (
ClassificationConcept,
)
from api.v1.modules.a76.general_catalogs.concepts.models import Concept
from api.v1.modules.a76.general_catalogs.customs_broker_concepts.models import (
CustomsBrokerConcept,
)
from api.v1.modules.a76.general_catalogs.depreciation_catalog.models import (
DepreciationCatalog,
)
from api.v1.modules.a76.general_catalogs.doda.models import Doda
from api.v1.modules.a76.general_catalogs.electronic_notices.models import (
ElectronicNotice,
)
from api.v1.modules.a76.general_catalogs.equivalencies.models import Equivalency
from api.v1.modules.a76.general_catalogs.error_catalogs.models import ErrorCatalog
from api.v1.modules.a76.general_catalogs.fda_catalog.models import FDACatalog
from api.v1.modules.a76.general_catalogs.inpc.models import INPC
from api.v1.modules.a76.general_catalogs.legends.models import Legend
from api.v1.modules.a76.general_catalogs.multi_currency_types.models import (
MultiCurrencyType,
)
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.a76.general_catalogs.ports.models import Port
from api.v1.modules.a76.general_catalogs.location.models import Location, FaLocationExt
from api.v1.modules.a76.general_catalogs.prevalidators.models import Prevalidator
from api.v1.modules.a76.general_catalogs.seal.models import Seal
from api.v1.modules.a76.general_catalogs.signatures.models import Signature
from api.v1.modules.a76.general_catalogs.fractions.tariff_fractions.models import (
TariffFraction,
)
from api.v1.modules.a76.general_catalogs.unit_conversions.models import UnitConversion
from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models import (
USTariffFraction,
)
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.a76.transportation.trailers.models import Trailer
from api.v1.modules.a76.transportation.transporters.models import Transporter
from api.v1.modules.a76.transportation.vehicles.models import Vehicle
# Registrar Listeners de Auditoría
def register_audit():
register_audit_listeners(
[
# Core Transactions
Pedimentos,
InvoiceHeader,
InvoiceSalesDetails,
LineItem,
# Sidebar Core Modules
ClientProvider,
CustomsBroker,
Part,
Company,
# Transportation Modules
Trailer,
Transporter,
Vehicle,
# Reference Data
Country,
CurrencyType,
CustomsSection,
CustomsWarehouse,
Incoterm,
InvoiceType,
MaterialType,
PaymentMethod,
PedimentoTransportCatalog,
PedimentoCode,
RegimenPedimento,
Sector,
State,
TransportMode,
TransportType,
ValuationMethod,
LicenseException,
AgencyTariffCode,
IdentifierCatalog,
CartaPorte,
UnitOfMeasure,
ExchangeRate,
Identifier,
Class,
ClassificationConcept,
Concept,
CustomsBrokerConcept,
DepreciationCatalog,
Doda,
ElectronicNotice,
Equivalency,
ErrorCatalog,
FDACatalog,
INPC,
Legend,
MultiCurrencyType,
Package,
Port,
Prevalidator,
Seal,
Signature,
TariffFraction,
UnitConversion,
USTariffFraction,
]
)

View File

@@ -4,7 +4,7 @@ from sqlalchemy.orm import Mapped, mapped_column
class CartaPorte(Base):
__tablename__ = "carta_porte"
__tablename__ = "carta_porte_codes"
__table_args__ = (
{"schema": "public", "extend_existing": True},
)

View File

@@ -39,10 +39,8 @@ def seed_carta_porte(db: Session):
if len(batch) >= batch_size:
db.bulk_save_objects(batch)
db.commit()
batch = []
print(f"Inserted {batch_size} records...")
batch = []
if batch:
db.bulk_save_objects(batch)
db.commit()
print(f"Finished seeding with {len(batch)} remaining records.")
db.commit()

View File

@@ -6,7 +6,7 @@ Agrega todos los módulos de la aplicación
from fastapi import APIRouter
from .agency_tariff_codes.routes import router as agency_tariff_codes_router
from .carta_porte.routes import router as carta_porte_router
from .carta_porte_codes.routes import router as carta_porte_router
from .code_pedimento_regimens.routes import router as code_pedimento_regimens_router
from .containers.routes import router as containers_router
from .countries.routes import router as countries_router
@@ -108,7 +108,7 @@ router.include_router(
router.include_router(
carta_porte_router,
prefix="/reference_data",
tags=["public / reference_data / carta_porte"],
tags=["public / reference_data / carta_porte_codes"],
)
router.include_router(
customs_sections_router,

View File

@@ -5,98 +5,18 @@ Backend API con FastAPI + Keycloak + SQLAlchemy
import logging
import subprocess
# Importar modelos para registrar con SQLAlchemy
# Reference Data (Dependencies)
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.currency_types.models import CurrencyType
from api.v1.modules.public.reference_data.customs_sections.models import CustomsSection
from api.v1.modules.public.reference_data.customs_warehouses.models import CustomsWarehouse
from api.v1.modules.public.reference_data.incoterms.models import Incoterm
from api.v1.modules.public.reference_data.invoice_types.models import InvoiceType
from api.v1.modules.public.reference_data.material_types.models import MaterialType
from api.v1.modules.public.reference_data.payment_methods.models import PaymentMethod
from api.v1.modules.public.reference_data.pedimento_transport_catalog.models import (
PedimentoTransportCatalog,
)
# Orden: PedimentoCode y RegimenPedimento antes de CodePedimentoRegimen para que
# SQLAlchemy resuelva los nombres en relationship() al configurar el mapper
from api.v1.modules.public.reference_data.pedimento_codes.models import PedimentoCode
from api.v1.modules.public.reference_data.pedimento_regimens.models import RegimenPedimento
from api.v1.modules.public.reference_data.code_pedimento_regimens.models import (
CodePedimentoRegimen,
)
from api.v1.modules.a76.general_catalogs.sectors.models import Sector
from api.v1.modules.public.reference_data.states.models import State
from api.v1.modules.public.reference_data.transport_modes.models import TransportMode
from api.v1.modules.public.reference_data.transport_types.models import TransportType
from api.v1.modules.public.reference_data.valuation_methods.models import ValuationMethod
from api.v1.modules.public.reference_data.license_exceptions.models import LicenseException
from api.v1.modules.public.reference_data.agency_tariff_codes.models import AgencyTariffCode
from api.v1.modules.public.reference_data.identifiers.models import IdentifierCatalog
from api.v1.modules.public.reference_data.carta_porte.models import CartaPorte
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure
from api.v1.modules.a76.general_catalogs.exchange_rate.models import ExchangeRate
from api.v1.modules.a76.general_catalogs.identifiers.models import Identifier
from api.v1.modules.a76.classes.models import Class
from api.v1.modules.a76.general_catalogs.classification_concepts.models import ClassificationConcept
from api.v1.modules.a76.general_catalogs.concepts.models import Concept
from api.v1.modules.a76.general_catalogs.customs_broker_concepts.models import CustomsBrokerConcept
from api.v1.modules.a76.general_catalogs.depreciation_catalog.models import DepreciationCatalog
from api.v1.modules.a76.general_catalogs.doda.models import Doda
from api.v1.modules.a76.general_catalogs.electronic_notices.models import ElectronicNotice
from api.v1.modules.a76.general_catalogs.equivalencies.models import Equivalency
from api.v1.modules.a76.general_catalogs.error_catalogs.models import ErrorCatalog
from api.v1.modules.a76.general_catalogs.fda_catalog.models import FDACatalog
from api.v1.modules.a76.general_catalogs.inpc.models import INPC
from api.v1.modules.a76.general_catalogs.legends.models import Legend
from api.v1.modules.a76.general_catalogs.multi_currency_types.models import MultiCurrencyType
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.a76.general_catalogs.ports.models import Port
from api.v1.modules.a76.general_catalogs.location.models import Location, FaLocationExt
from api.v1.modules.a76.general_catalogs.prevalidators.models import Prevalidator
from api.v1.modules.a76.general_catalogs.seal.models import Seal
from api.v1.modules.a76.general_catalogs.signatures.models import Signature
from api.v1.modules.a76.general_catalogs.fractions.tariff_fractions.models import (
TariffFraction,
)
from api.v1.modules.a76.general_catalogs.unit_conversions.models import UnitConversion
from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models import (
USTariffFraction,
)
# Core Modules & Reference Data (Dependencies)
from api.v1.modules.a76.clients_and_providers.models import ClientProvider
from api.v1.modules.a76.customs_brokers.models import CustomsBroker
from api.v1.modules.a76.general_catalogs.company.models import Company
# Transportation Modules
from api.v1.modules.a76.transportation.trailers.models import Trailer
from api.v1.modules.a76.transportation.transporters.models import Transporter
from api.v1.modules.a76.transportation.vehicles.models import Vehicle
# Core Modules & Transactional Models
from api.v1.modules.a76.items.models import LineItem
from api.v1.modules.a76.items.series.models import Serie
from api.v1.modules.a76.parts.models import Part
from api.v1.modules.a24.fa.fa_parts.models import FaPart
from api.v1.modules.a24.inv.inv_parts.models import InvPart
from api.v1.modules.a76.manifests.manifest.models import Manifest
from api.v1.modules.a76.manifests.concept_manifestation.models import ConceptManifestation
from api.v1.modules.a76.manifests.value_manifestation.models import ValueManifestation
# Transactional Primary Models
from api.v1.modules.a76.pedmientos.models.pedimentos import Pedimentos
from api.v1.modules.a76.invoices.models import InvoiceHeader, InvoiceSalesDetails
from api.v1.modules.a76.audit_log.events import register_audit_listeners
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pathlib import Path
from contextlib import asynccontextmanager
# Core Modules (Secondary)
import core.celery_app # Initialize Celery App
from api.v1.modules.a76.audit_log.middleware import UserContextMiddleware # Middleware de Contexto de Usuario (Audit Log)
from api.v1.modules.a76.audit_log.register import register_audit
from api.v1.router import router as api_v1_router
from core.config import settings
from core.database import init_db
from core.paths import layout_path
from core.error_handlers import register_exception_handlers
from core.middleware import (
@@ -104,26 +24,6 @@ from core.middleware import (
RequestLoggingMiddleware,
TenantMiddleware,
)
from fastapi import FastAPI, Request, status, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from pathlib import Path
# Importar modelos para registrar con SQLAlchemy
# IMPORTANT: Import FaLineItem BEFORE LineItem for relationship resolution
from api.v1.modules.a24.fa.fa_item_lines.models import FaLineItem
from api.v1.modules.a76.items.models import LineItem
from api.v1.modules.a76.items.series.models import Serie
from api.v1.modules.a76.parts.models import Part
from api.v1.modules.a24.fa.fa_parts.models import FaPart
from api.v1.modules.a24.inv.inv_parts.models import InvPart
from api.v1.modules.a76.manifests.manifest.models import Manifest
from api.v1.modules.a76.manifests.concept_manifestation.models import (
ConceptManifestation,
)
from api.v1.modules.a76.manifests.value_manifestation.models import ValueManifestation
# Configurar logging
logging.basicConfig(
@@ -131,7 +31,6 @@ logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
# Crear aplicación FastAPI
app = FastAPI(
title="Anexo76 API",
@@ -147,35 +46,14 @@ logger = logging.getLogger(__name__)
# Registrar manejadores de excepciones
register_exception_handlers(app)
def _cors_headers_for_request(request: Request):
"""Return CORS headers if request Origin is allowed (so error responses don't get blocked by browser)."""
origin = request.headers.get("origin")
if not origin:
return {}
allowed = settings.cors_origins_list
if origin in allowed:
return {
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Credentials": "true",
}
return {}
for k, v in _cors_headers_for_request(request).items():
response.headers[k] = v
return response
def run_migrations():
subprocess.run(["alembic", "upgrade", "head"], check=True)
# Inicializar la base de datos
@app.on_event("startup")
async def on_startup():
"""Evento de inicio de la aplicación"""
logger.info("Iniciando la aplicación Anexo76...")
init_db()
#init_db()
run_migrations()
logger.info("Base de datos inicializada correctamente.")
@@ -195,159 +73,16 @@ if settings.DEBUG:
app.add_middleware(LicenseValidationMiddleware)
app.add_middleware(TenantMiddleware)
# Middleware de Contexto de Usuario (Audit Log)
from api.v1.modules.a76.audit_log.middleware import UserContextMiddleware
app.add_middleware(UserContextMiddleware)
# Importar modelos para Audit Log
from api.v1.modules.a76.pedmientos.models.pedimentos import Pedimentos
from api.v1.modules.a76.invoices.models import InvoiceHeader, InvoiceSalesDetails
from api.v1.modules.a76.audit_log.events import register_audit_listeners
@asynccontextmanager
async def lifespan(app: FastAPI):
# Centraliza startup para evitar on_event() (deprecated en FastAPI)
await on_startup()
register_audit()
yield
# Core Modules
from api.v1.modules.a76.clients_and_providers.models import ClientProvider
from api.v1.modules.a76.customs_brokers.models import CustomsBroker
from api.v1.modules.a76.parts.models import Part
from api.v1.modules.a76.items.models import LineItem
from api.v1.modules.a76.general_catalogs.company.models import Company
# Reference Data
from api.v1.modules.public.reference_data.countries.models import Country
from api.v1.modules.public.reference_data.currency_types.models import CurrencyType
from api.v1.modules.public.reference_data.customs_sections.models import CustomsSection
from api.v1.modules.public.reference_data.customs_warehouses.models import (
CustomsWarehouse,
)
from api.v1.modules.public.reference_data.incoterms.models import Incoterm
from api.v1.modules.public.reference_data.invoice_types.models import InvoiceType
from api.v1.modules.public.reference_data.material_types.models import MaterialType
from api.v1.modules.public.reference_data.payment_methods.models import PaymentMethod
from api.v1.modules.public.reference_data.pedimento_transport_catalog.models import (
PedimentoTransportCatalog,
)
from api.v1.modules.public.reference_data.pedimento_codes.models import PedimentoCode
from api.v1.modules.public.reference_data.pedimento_regimens.models import (
RegimenPedimento,
)
from api.v1.modules.public.reference_data.states.models import State
from api.v1.modules.public.reference_data.transport_modes.models import TransportMode
from api.v1.modules.public.reference_data.transport_types.models import TransportType
from api.v1.modules.public.reference_data.valuation_methods.models import (
ValuationMethod,
)
from api.v1.modules.public.reference_data.license_exceptions.models import LicenseException
from api.v1.modules.public.reference_data.agency_tariff_codes.models import AgencyTariffCode
from api.v1.modules.public.reference_data.identifiers.models import IdentifierCatalog
from api.v1.modules.public.reference_data.carta_porte.models import CartaPorte
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure
from api.v1.modules.a76.general_catalogs.exchange_rate.models import ExchangeRate
from api.v1.modules.a76.general_catalogs.identifiers.models import Identifier
from api.v1.modules.a76.classes.models import Class
from api.v1.modules.a76.general_catalogs.classification_concepts.models import (
ClassificationConcept,
)
from api.v1.modules.a76.general_catalogs.concepts.models import Concept
from api.v1.modules.a76.general_catalogs.customs_broker_concepts.models import (
CustomsBrokerConcept,
)
from api.v1.modules.a76.general_catalogs.depreciation_catalog.models import (
DepreciationCatalog,
)
from api.v1.modules.a76.general_catalogs.doda.models import Doda
from api.v1.modules.a76.general_catalogs.electronic_notices.models import (
ElectronicNotice,
)
from api.v1.modules.a76.general_catalogs.equivalencies.models import Equivalency
from api.v1.modules.a76.general_catalogs.error_catalogs.models import ErrorCatalog
from api.v1.modules.a76.general_catalogs.fda_catalog.models import FDACatalog
from api.v1.modules.a76.general_catalogs.inpc.models import INPC
from api.v1.modules.a76.general_catalogs.legends.models import Legend
from api.v1.modules.a76.general_catalogs.multi_currency_types.models import (
MultiCurrencyType,
)
from api.v1.modules.a76.general_catalogs.packages.models import Package
from api.v1.modules.a76.general_catalogs.ports.models import Port
from api.v1.modules.a76.general_catalogs.location.models import Location, FaLocationExt
from api.v1.modules.a76.general_catalogs.prevalidators.models import Prevalidator
from api.v1.modules.a76.general_catalogs.seal.models import Seal
from api.v1.modules.a76.general_catalogs.signatures.models import Signature
from api.v1.modules.a76.general_catalogs.fractions.tariff_fractions.models import (
TariffFraction,
)
from api.v1.modules.a76.general_catalogs.unit_conversions.models import UnitConversion
from api.v1.modules.a76.general_catalogs.fractions.us_tariff_fractions.models import (
USTariffFraction,
)
# Registrar Listeners de Auditoría
@app.on_event("startup")
def register_audit():
register_audit_listeners(
[
# Core Transactions
Pedimentos,
InvoiceHeader,
InvoiceSalesDetails,
LineItem,
# Sidebar Core Modules
ClientProvider,
CustomsBroker,
Part,
Company,
# Transportation Modules
Trailer,
Transporter,
Vehicle,
# Reference Data
Country,
CurrencyType,
CustomsSection,
CustomsWarehouse,
Incoterm,
InvoiceType,
MaterialType,
PaymentMethod,
PedimentoTransportCatalog,
PedimentoCode,
RegimenPedimento,
Sector,
State,
TransportMode,
TransportType,
ValuationMethod,
LicenseException,
AgencyTariffCode,
IdentifierCatalog,
CartaPorte,
UnitOfMeasure,
ExchangeRate,
Identifier,
Class,
ClassificationConcept,
Concept,
CustomsBrokerConcept,
DepreciationCatalog,
Doda,
ElectronicNotice,
Equivalency,
ErrorCatalog,
FDACatalog,
INPC,
Legend,
MultiCurrencyType,
Package,
Port,
Prevalidator,
Seal,
Signature,
TariffFraction,
UnitConversion,
USTariffFraction,
]
)
app.router.lifespan_context = lifespan
# Crear directorio de uploads si no existe y montar archivos estáticos