Merge development

This commit is contained in:
hreyes
2026-02-23 13:12:49 -06:00
127 changed files with 17080 additions and 9433 deletions

View File

@@ -8,6 +8,10 @@ from api.v1.modules.public.reference_data.code_pedimento_regimens.models import
CodePedimentoRegimen,
)
# Import models in correct order for SQLAlchemy relationship resolution
# CRITICAL: FaLineItem must be imported BEFORE LineItem
from api.v1.modules.a24.fa.fa_item_lines.models import FaLineItem # noqa: F401
from api.v1.modules.a76.items.models import LineItem # noqa: F401
valkey_url = os.getenv("VALKEY_URL", "redis://valkey:6379/0")
@@ -21,7 +25,10 @@ celery_app = Celery(
"api.v1.modules.a76.reports.importacion.packing_list.task",
"api.v1.modules.a76.reports.exportacion.aviso_consolidado.task",
"api.v1.modules.a76.reports.exportacion.descargo.task",
"api.v1.modules.a76.imports.tasks"
"api.v1.modules.a76.imports.tasks",
"api.v1.modules.a76.reports.exportacion.transmission.MAINX30.task",
"api.v1.modules.a76.reports.importacion.transmission.temporal.MAINX30.task",
"api.v1.modules.a76.reports.importacion.transmission.definitive.MAINX30.task"
] # Ruta al módulo donde están las tareas
)
@@ -36,4 +43,4 @@ celery_app.conf.update(
)
if __name__ == "__main__":
celery_app.start()
celery_app.start()

View File

@@ -5,7 +5,7 @@ Manejadores globales de excepciones para FastAPI
import logging
from typing import Any, Dict
from fastapi import Request, status
from fastapi import Request, status, HTTPException
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
@@ -162,6 +162,23 @@ async def sqlalchemy_error_handler(
return response
async def http_exception_handler(
request: Request,
exc: HTTPException,
) -> JSONResponse:
"""
Manejador para HTTPException de FastAPI
"""
return JSONResponse(
status_code=exc.status_code,
content={
"error": "HTTP_ERROR",
"message": exc.detail,
"status_code": exc.status_code,
},
)
async def general_exception_handler(
request: Request,
exc: Exception,
@@ -199,6 +216,7 @@ def register_exception_handlers(app) -> None:
app: Instancia de FastAPI
"""
app.add_exception_handler(BaseAPIException, base_exception_handler)
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(RequestValidationError, validation_exception_handler)
app.add_exception_handler(IntegrityError, integrity_error_handler)
app.add_exception_handler(SQLAlchemyError, sqlalchemy_error_handler)

View File

@@ -1,7 +1,8 @@
import logging
import time
from typing import Callable
from fastapi import HTTPException, Request, Response
from fastapi import Request, Response
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from .config import settings
from .database import CoreSessionLocal
@@ -34,9 +35,13 @@ class TenantMiddleware(BaseHTTPMiddleware):
# 4. Validación estricta de Token (solo para lo que no es público ni OPTIONS)
auth_header = request.headers.get("Authorization")
if not auth_header or not auth_header.startswith("Bearer "):
raise HTTPException(
status_code=401,
detail="Missing or invalid authorization header"
return JSONResponse(
status_code=401,
content={
"error": "HTTP_ERROR",
"message": "Missing or invalid authorization header",
"status_code": 401,
}
)
token = auth_header.split(" ")[1]
@@ -48,7 +53,14 @@ class TenantMiddleware(BaseHTTPMiddleware):
request.state.user_info = user_info
except Exception as e:
logger.error(f"❌ Tenant validation error: {str(e)}")
raise HTTPException(status_code=401, detail="Invalid authentication")
return JSONResponse(
status_code=401,
content={
"error": "HTTP_ERROR",
"message": "Invalid authentication",
"status_code": 401,
}
)
# 5. Continuar con la petición real
return await call_next(request)
@@ -104,19 +116,28 @@ class LicenseValidationMiddleware(BaseHTTPMiddleware):
license_info = license_service.validate_license(tenant_id)
if not license_info["is_valid"]:
raise HTTPException(
return JSONResponse(
status_code=402,
detail=f"License validation failed: {license_info['reason']}",
content={
"error": "HTTP_ERROR",
"message": f"License validation failed: {license_info['reason']}",
"status_code": 402,
}
)
# Agregar info de licencia al request state
request.state.license_info = license_info
except HTTPException:
raise
except Exception as e:
logger.error(f"License validation error: {str(e)}")
raise HTTPException(status_code=500, detail="License validation error")
return JSONResponse(
status_code=500,
content={
"error": "HTTP_ERROR",
"message": "License validation error",
"status_code": 500,
}
)
finally:
db.close()