- Updated multiple DTO classes across various modules to replace the `Config` class with `model_config = ConfigDict(from_attributes=True)`. - This change enhances consistency in attribute handling and aligns with the latest Pydantic practices. - Adjusted error handling in core modules to change status codes from `HTTP_422_UNPROCESSABLE_ENTITY` to `HTTP_422_UNPROCESSABLE_CONTENT` for improved clarity in validation responses.
SITAR API Module
Módulo reorganizado para integración con la API externa de SITAR (Sistema de Información de Aranceles).
Estructura
Cada recurso ahora tiene su propia carpeta con separación de responsabilidades:
backend/api/v1/modules/sitar/
├── common/ # Servicio base compartido
│ ├── __init__.py
│ └── base_service.py # SitarAPIBaseService con autenticación
├── tlcs/ # TLCS (Tratados de Libre Comercio)
│ ├── __init__.py
│ ├── schemas.py # TLCSResponse
│ ├── service.py # TLCSService
│ └── router.py # Endpoints FastAPI
├── fracciones/ # Fracciones arancelarias mexicanas
├── fracciones_usa/ # Fracciones USA
├── regulaciones/ # Regulaciones y restricciones
├── prosec/ # PROSEC
├── precios_estimados/ # Precios estimados
├── fundamentos_tlc/ # Fundamentos TLC
├── aladi2/ # ALADI2
├── cuotas2/ # Cuotas compensatorias
├── cupos/ # Cupos de importación
├── fracciones_anteriores/ # Historial de fracciones
├── informacion_general/ # Información general
├── ieps/ # IEPS
├── noms/ # Normas Oficiales Mexicanas
├── rcg2/ # Reglas de Carácter General
├── reit/ # REIT
├── requisito_previo/ # Requisitos previos
├── vehiculos_marcas/ # Marcas de vehículos
├── vehiculos_modelos/ # Modelos de vehículos
├── __init__.py # Exporta todos los servicios
└── main_router.py # Router principal con todos los endpoints
Uso del Servicio
Desde cualquier parte del código
Cada recurso tiene su propio servicio singleton que maneja automáticamente la autenticación:
from api.v1.modules.sitar.tlcs import TLCSService
from api.v1.modules.sitar.fracciones import FraccionesService
# Obtener instancia singleton
tlcs_service = TLCSService.get_instance()
# Buscar TLCS (async)
tlcs_data = await tlcs_service.search(
fraccion="84716001",
pais="USA",
limit=100
)
# Procesar resultados
for tlcs in tlcs_data:
print(f"Tasa: {tlcs.TASATXT}, País: {tlcs.PAIS}")
Desde código síncrono
Si estás en contexto síncrono, usa asyncio.run():
import asyncio
from api.v1.modules.sitar.tlcs import TLCSService
tlcs_service = TLCSService.get_instance()
tlcs_data = asyncio.run(tlcs_service.search(fraccion="84716001", pais="USA"))
Métodos Disponibles
TLCS (Tratados de Libre Comercio)
search_tlcs(fraccion, pais, nico, skip, limit)- Buscar TLCSget_tlcs_by_id(sysid, fraccion)- Obtener TLCS por ID
Fracciones Arancelarias
search_fracciones(fraccion, nico, skip, limit)- Buscar fracciones mexicanasget_fraccion_by_id(sysid)- Obtener fracción por IDsearch_fracciones_usa(fraccion, skip, limit)- Buscar fracciones USAget_fraccion_usa_by_id(consecutivo)- Obtener fracción USA por IDsearch_fracciones_anteriores(fraccion_actual, fraccion_anterior, skip, limit)- Buscar historial de fraccionesget_fracciones_anteriores_by_id(sysid)- Obtener historial por ID
Regulaciones y Restricciones
search_regulaciones(fraccion, nico, skip, limit)- Buscar regulacionesget_regulacion_by_id(sysid)- Obtener regulación por IDsearch_noms(fraccion, pais, nico, skip, limit)- Buscar Normas Oficiales Mexicanasget_noms_by_id(sysid)- Obtener NOM por IDsearch_requisito_previo(fraccion, nico, skip, limit)- Buscar requisitos previosget_requisito_previo_by_id(sysid)- Obtener requisito previo por ID
PROSEC y Programas de Promoción
search_prosec(fraccion, nico, skip, limit)- Buscar PROSECget_prosec_by_id(sysid)- Obtener PROSEC por IDsearch_reit(fraccion, nico, skip, limit)- Buscar REITget_reit_by_id(sysid)- Obtener REIT por ID
Precios e Impuestos
search_precios_estimados(fraccion, nico, skip, limit)- Buscar precios estimadosget_precio_estimado_by_id(sysid)- Obtener precio estimado por IDsearch_ieps(fraccion, nico, skip, limit)- Buscar IEPSget_ieps_by_id(consecutivo)- Obtener IEPS por ID
Fundamentos y Acuerdos
search_fundamentos_tlc(fraccion, nico, tipat_only, skip, limit)- Buscar fundamentos TLCget_fundamento_tlc_by_id(sysid)- Obtener fundamento por IDsearch_aladi2(fraccion, pais, nico, skip, limit)- Buscar ALADI2get_aladi2_by_id(sysid)- Obtener ALADI2 por ID
Cuotas y Cupos
search_cuotas2(fraccion, pais, nico, skip, limit)- Buscar cuotas compensatoriasget_cuotas2_by_id(sysid)- Obtener cuota por IDsearch_cupos(fraccion, nico, skip, limit)- Buscar cupos de importaciónget_cupos_by_id(sysid)- Obtener cupo por ID
Reglas de Carácter General
search_rcg2(fraccion, nico, skip, limit)- Buscar RCG2get_rcg2_by_id(sysid)- Obtener RCG2 por ID
Información General
search_informacion_general(fraccion, nico, skip, limit)- Buscar información generalget_informacion_general_by_id(sysid)- Obtener información general por ID
Vehículos
search_vehiculos_marcas(fraccion, marca, skip, limit)- Buscar marcas de vehículosget_vehiculos_marcas_by_id(sysid)- Obtener marca por IDsearch_vehiculos_modelos(fraccion, marca, modelo, skip, limit)- Buscar modelos de vehículosget_vehiculos_modelos_by_id(sysid)- Obtener modelo por ID
Configuración
Requiere las siguientes variables de entorno:
SITAR_API_URL=https://api.sitar.example.com
SITAR_API_USER=your_username
SITAR_API_PASSWORD=your_password
Servicios Disponibles
Cada módulo sigue el mismo patrón con métodos search() y get_by_id():
TLCS - TLCSService
from api.v1.modules.sitar.tlcs import TLCSService
service = TLCSService.get_instance()
await service.search(fraccion="84716001", pais="USA", nico=None, skip=0, limit=100)
await service.get_by_id(sysid=123, fraccion="84716001")
Fracciones - FraccionesService
from api.v1.modules.sitar.fracciones import FraccionesService
service = FraccionesService.get_instance()
await service.search(fraccion="84716001", nico=None, skip=0, limit=100)
await service.get_by_id(sysid=123)
Fracciones USA - FraccionesUSAService
from api.v1.modules.sitar.fracciones_usa import FraccionesUSAService
service = FraccionesUSAService.get_instance()
await service.search(fraccion="84716001", skip=0, limit=100)
await service.get_by_id(consecutivo=123)
Otros servicios disponibles:
- RegulacionesService - Regulaciones y restricciones
- ProsecService - PROSEC (Programa de Promoción Sectorial)
- PreciosEstimadosService - Precios estimados
- FundamentosTLCService - Fundamentos de tratados de libre comercio
- Aladi2Service - ALADI2 (Asociación Latinoamericana de Integración)
- Cuotas2Service - Cuotas compensatorias
- CuposService - Cupos de importación
- FraccionesAnterioresService - Historial de fracciones
- InformacionGeneralService - Información general de fracciones
- IepsService - IEPS (Impuesto Especial sobre Producción y Servicios)
- NomsService - Normas Oficiales Mexicanas
- Rcg2Service - Reglas de Carácter General
- ReitService - Registro de Empresas de Industria Terminal
- RequisitoPrevioService - Requisitos previos
- VehiculosMarcasService - Marcas de vehículos
- VehiculosModelosService - Modelos de vehículos
```python
from fastapi import APIRouter, HTTPException
from api.v1.modules.sitar.tlcs import TLCSService
router = APIRouter()
@router.get("/tariff/{fraccion}")
async def get_tariff_info(fraccion: str, country: str = "USA"):
"""Endpoint que consulta información arancelaria"""
try:
tlcs_service = TLCSService.get_instance()
data = await tlcs_service.search(fraccion=fraccion, pais=country)
return {"success": True, "data": data}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
Arquitectura
Servicio Base Compartido
Todos los servicios heredan de SitarAPIBaseService que maneja:
- Autenticación con token caching
- Renovación automática de tokens
- Manejo de errores HTTP
- Timeout configurable
Singleton Pattern
Cada servicio usa el patrón singleton para:
- Compartir la conexión HTTP
- Reutilizar tokens de autenticación
- Evitar múltiples instancias
Separación de Responsabilidades
- schemas.py: Modelos Pydantic para validación de datos
- service.py: Lógica de negocio y llamadas a API
- router.py: Endpoints FastAPI (opcional)
- init.py: Exportaciones públicas
Notas Importantes
- Autenticación: El token se cachea y renueva automáticamente
- Timeouts: Configurado a 10 segundos por defecto
- Límites: Máximo 1000 registros por consulta
- Errores: Todos los servicios lanzan excepciones httpx en caso de error
- Async/Sync: Los servicios son async, usa
asyncio.run()en código síncrono
Esto expondrá endpoints como:
- `GET /api/v1/sitar/tlcs/` - Buscar TLCS
- `GET /api/v1/sitar/fracciones/` - Buscar fracciones
- etc.
## Ejemplo Completo
```python
from api.v1.modules.sitar import SitarAPIService
async def get_tariff_info(fraccion: str, country: str):
"""Obtener información arancelaria completa"""
sitar = SitarAPIService.get_instance()
try:
# Buscar TLCS
tlcs = await sitar.search_tlcs(fraccion=fraccion, pais=country)
if tlcs:
first_tlcs = tlcs[0]
return {
"rate": first_tlcs.TASATXT,
"adv_impo": float(first_tlcs.TASA1NUM or 0.0),
"country": first_tlcs.PAIS
}
# Si no hay TLCS, buscar fracción general
fracciones = await sitar.search_fracciones(fraccion=fraccion)
if fracciones:
first_frac = fracciones[0]
return {
"rate": first_frac.ADVIMPOTXT,
"adv_impo": float(first_frac.ADVIMPONUM or 0.0),
"description": first_frac.DESCRIPCION
}
return None
except Exception as e:
print(f"Error: {e}")
return None
Manejo de Errores
El servicio lanza excepciones httpx.HTTPError en caso de error:
import httpx
try:
tlcs = await sitar.search_tlcs(fraccion="invalid")
except httpx.HTTPStatusError as e:
print(f"HTTP Error: {e.response.status_code}")
except httpx.RequestError as e:
print(f"Request Error: {e}")
except Exception as e:
print(f"General Error: {e}")