Se agregaron los moduloes de api_v2
This commit is contained in:
69
api/api_v2/modules/partidas/controllers.py
Normal file
69
api/api_v2/modules/partidas/controllers.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from controllers.RESTController import APIRESTController
|
||||
from controllers.SOAPController import VUCEMController
|
||||
from typing import List, Dict, Any
|
||||
import xml.etree.ElementTree as ET
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Dict
|
||||
|
||||
class PartidaRestController(APIRESTController):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
async def put_partida(self, partida_id: str, data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Método para actualizar un documento digitalizado en la API.
|
||||
|
||||
Args:
|
||||
edocument_id: UUID del documento a actualizar
|
||||
data: Diccionario con los datos a actualizar
|
||||
"""
|
||||
return await self._make_request_async('PUT', f'customs/partidas/{partida_id}/', data=data)
|
||||
|
||||
class PartidaVUController(VUCEMController):
|
||||
def __init__(self):
|
||||
super().__init__() # Implementación específica para Coves VU
|
||||
|
||||
def generate_partidas_template(self, username: str, password: str, aduana: str, patente: str, pedimento: str, numero_operacion: str, partida: str) -> str:
|
||||
"""
|
||||
Genera el template SOAP para consultar partidas de un pedimento
|
||||
|
||||
Args:
|
||||
username: Usuario de VUCEM
|
||||
password: Contraseña de VUCEM
|
||||
aduana: Código de aduana
|
||||
patente: Número de patente
|
||||
pedimento: Número de pedimento
|
||||
|
||||
Returns:
|
||||
str: Template SOAP XML completo
|
||||
"""
|
||||
soap_template = f'''
|
||||
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="http://www.ventanillaunica.gob.mx/pedimentos/ws/oxml/consultarpartida" xmlns:com="http://www.ventanillaunica.gob.mx/pedimentos/ws/oxml/comunes">
|
||||
<soapenv:Header>
|
||||
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
||||
<wsse:UsernameToken>
|
||||
<wsse:Username>{username}</wsse:Username>
|
||||
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">{password.strip()}</wsse:Password>
|
||||
</wsse:UsernameToken>
|
||||
</wsse:Security>
|
||||
</soapenv:Header>
|
||||
<soapenv:Body>
|
||||
<con:consultarPartidaPeticion>
|
||||
<con:peticion>
|
||||
<com:aduana>{aduana}</com:aduana>
|
||||
<com:patente>{patente}</com:patente>
|
||||
<com:pedimento>{pedimento}</com:pedimento>
|
||||
<con:numeroOperacion>{numero_operacion}</con:numeroOperacion>
|
||||
<con:numeroPartida>{partida}</con:numeroPartida>
|
||||
</con:peticion>
|
||||
</con:consultarPartidaPeticion>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
'''
|
||||
|
||||
return soap_template
|
||||
|
||||
partida_rest_controller = PartidaRestController()
|
||||
partida_vu_controller = PartidaVUController()
|
||||
|
||||
|
||||
43
api/api_v2/modules/partidas/routers.py
Normal file
43
api/api_v2/modules/partidas/routers.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
|
||||
|
||||
from api.api_v2.modules.authentication.services import get_current_user
|
||||
from .schemas import PartidaRequestSchema, PartidaListSchema
|
||||
from .tasks import process_partida_request
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("/services/partida/", response_model=Dict[str, Any])
|
||||
async def obtener_partida(partida_request: PartidaRequestSchema):
|
||||
"""
|
||||
Endpoint para obtener la información de una partida específica.
|
||||
"""
|
||||
|
||||
acuse_dict = partida_request.model_dump()
|
||||
# Ejecuta la tarea de Celery de forma asíncrona
|
||||
task = process_partida_request.delay(acuse_dict)
|
||||
# Puedes devolver el ID de la tarea para consultar el estado después
|
||||
return {"task_id": task.id, "status": "submitted"}
|
||||
|
||||
@router.post("/services/all/partidas/", response_model=Dict[str, Any])
|
||||
async def obtener_partidas(partidas_request: PartidaListSchema):
|
||||
"""
|
||||
Endpoint para iniciar la descarga masiva de partidas.
|
||||
"""
|
||||
task_ids = []
|
||||
partida_request_dict = partidas_request.model_dump()
|
||||
# Para cada partida en la lista, dispara una tarea Celery
|
||||
for partida in partida_request_dict.get('partidas', []):
|
||||
# Crea un nuevo diccionario de datos para cada tarea
|
||||
partida_dict = {
|
||||
"partida": partida,
|
||||
"pedimento": partida_request_dict.get('pedimento'),
|
||||
"credencial": partida_request_dict.get('credencial')
|
||||
}
|
||||
task = process_partida_request.delay(partida_dict)
|
||||
task_ids.append(task.id)
|
||||
|
||||
return {"task_ids": task_ids, "status": "submitted", "total": len(task_ids)}
|
||||
20
api/api_v2/modules/partidas/schemas.py
Normal file
20
api/api_v2/modules/partidas/schemas.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from schemas.CredencialSchema import CredencialBaseSchema
|
||||
from api.api_v2.modules.pedimentos.schemas import PedimentoBaseSchema
|
||||
|
||||
class PartidaBaseSchema(BaseModel):
|
||||
id: int
|
||||
numero: int
|
||||
|
||||
class PartidaRequestSchema(BaseModel):
|
||||
partida: PartidaBaseSchema
|
||||
pedimento: PedimentoBaseSchema
|
||||
credencial: CredencialBaseSchema
|
||||
|
||||
class PartidaListSchema(BaseModel):
|
||||
partidas: list[PartidaBaseSchema] = Field(..., description="Lista de partidas")
|
||||
pedimento: PedimentoBaseSchema
|
||||
credencial: CredencialBaseSchema
|
||||
|
||||
|
||||
122
api/api_v2/modules/partidas/services.py
Normal file
122
api/api_v2/modules/partidas/services.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import base64
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
from fastapi import HTTPException
|
||||
from controllers.RESTController import rest_controller
|
||||
from controllers.SOAPController import soap_controller
|
||||
from cryptography.hazmat.primitives import serialization, hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from cryptography.hazmat.primitives.serialization import load_der_private_key
|
||||
import tempfile
|
||||
|
||||
from utils.helpers import soap_error
|
||||
from .controllers import partida_rest_controller, partida_vu_controller
|
||||
|
||||
# Logger para el módulo
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Logica de negocio para consumir el servicio SOAP de VUCEM y procesar la respuesta
|
||||
async def consume_ws_get_partida(**kwargs):
|
||||
"""
|
||||
Consume el servicio SOAP para obtener un partida y procesar la respuesta.
|
||||
|
||||
Args:
|
||||
**kwargs: Debe contener 'credencial', 'pedimento' y 'partida'
|
||||
|
||||
Returns:
|
||||
Dict serializable con 'documento' y 'partida_put_response'
|
||||
Raises:
|
||||
Exception: Si hay errores en el procesamiento
|
||||
"""
|
||||
try:
|
||||
logger.info("Iniciando procesamiento de partidas")
|
||||
credenciales = kwargs.get('credencial')
|
||||
username = credenciales.get('user')
|
||||
pedimento_app = kwargs.get('pedimento', {}).get('pedimento_app', 'N/A')
|
||||
partida = kwargs.get('partida', {})
|
||||
|
||||
if not credenciales or not username or not partida:
|
||||
raise Exception("Credenciales o Partida no proporcionados correctamente")
|
||||
|
||||
logger.info(f"Procesando Partida: {partida} para usuario: {username}")
|
||||
|
||||
# Generar template SOAP
|
||||
|
||||
soap_xml = partida_vu_controller.generate_partidas_template(
|
||||
username=username,
|
||||
password=credenciales.get('password'),
|
||||
aduana=kwargs.get('pedimento', {}).get('aduana', 'N/A'),
|
||||
patente=kwargs.get('pedimento', {}).get('patente', 'N/A'),
|
||||
pedimento=kwargs.get('pedimento', {}).get('pedimento', 'N/A'),
|
||||
numero_operacion=kwargs.get('pedimento', {}).get('numero_operacion', ''),
|
||||
partida=partida.get('numero', '')
|
||||
)
|
||||
|
||||
soap_headers = {
|
||||
'Content-Type': 'text/xml; charset=utf-8'
|
||||
}
|
||||
|
||||
logger.info("Enviando petición SOAP a VUCEM")
|
||||
soap_response = await partida_vu_controller.make_request_async(
|
||||
"/ventanilla-ws-pedimentos/ConsultarPartidaService",
|
||||
data=soap_xml,
|
||||
headers=soap_headers
|
||||
)
|
||||
|
||||
|
||||
if not soap_response:
|
||||
raise Exception("No se recibió respuesta del servicio SOAP")
|
||||
|
||||
if soap_error(soap_response):
|
||||
raise Exception("Error en la respuesta del servicio SOAP")
|
||||
|
||||
logger.info("Respuesta SOAP exitosa, enviando documento")
|
||||
|
||||
# Enviar documento
|
||||
_file_name = f"vu_PT_{pedimento_app}_{partida.get('numero', '')}.xml"
|
||||
document_response = await partida_rest_controller.post_document(
|
||||
soap_response=soap_response,
|
||||
organizacion=kwargs.get('pedimento').get('organizacion'),
|
||||
pedimento=kwargs.get('pedimento').get('id'),
|
||||
file_name=_file_name,
|
||||
document_type=1,
|
||||
)
|
||||
|
||||
logger.info("Documento enviado, actualizando status de Partida")
|
||||
|
||||
# Actualizar status del partida
|
||||
partida_status_response = await change_partida_status(
|
||||
partida=kwargs.get('partida'),
|
||||
status=True,
|
||||
pedimento=kwargs.get('pedimento')
|
||||
)
|
||||
|
||||
logger.info(f"Partida {partida.get('numero', '')} procesado exitosamente")
|
||||
|
||||
# Asegurar que la respuesta sea serializable
|
||||
result = {
|
||||
"documento": document_response if document_response else None,
|
||||
"partida_update_response": partida_status_response if partida_status_response else None
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error procesando la partida: {str(e)}", exc_info=True)
|
||||
# Asegurar que no se retornen datos binarios en el error
|
||||
raise Exception(f"Error interno al procesar la partida: {str(e)}")
|
||||
|
||||
async def change_partida_status(partida: dict, status: bool, pedimento: dict):
|
||||
data = {
|
||||
"id": partida.get("id"),
|
||||
"numero_partida": partida.get("numero"),
|
||||
"descargado": status,
|
||||
"pedimento": pedimento.get("id"),
|
||||
"organizacion": pedimento.get("organizacion"),
|
||||
}
|
||||
print(data)
|
||||
response = await partida_rest_controller.put_partida(partida_id=partida.get("id"), data=data)
|
||||
|
||||
return response
|
||||
@@ -0,0 +1,26 @@
|
||||
from celery import Celery
|
||||
from celery_app import celery_app
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Dict, Any
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from .services import consume_ws_get_partida
|
||||
|
||||
|
||||
@celery_app.task
|
||||
def process_partida_request(partida_request: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Tarea de Celery para procesar la solicitud de partida.
|
||||
|
||||
Args:
|
||||
partida_request: Diccionario con los datos de la solicitud de partida.
|
||||
|
||||
Returns:
|
||||
Diccionario con la respuesta de la partida.
|
||||
"""
|
||||
loop = asyncio.get_event_loop()
|
||||
partida_response = loop.run_until_complete(consume_ws_get_partida(**partida_request))
|
||||
|
||||
return {"status": "processed", "data": partida_response}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user