apiv2
This commit is contained in:
@@ -2,17 +2,17 @@ from fastapi import APIRouter
|
||||
# En Python, no se pueden usar llaves {} para importar múltiples módulos.
|
||||
# Debes usar paréntesis () para hacer importaciones multilínea.
|
||||
|
||||
from api.api_v2.modules.acuses import router as acuses_router
|
||||
from api.api_v2.modules.coves import router as coves_router
|
||||
from api.api_v2.modules.edocs import router as edocs_router
|
||||
from api.api_v2.modules.partidas import router as partidas_router
|
||||
from api.api_v2.modules.pedimentos import router as pedimentos_router
|
||||
# from api.api_v2.modules.acuses import router as acuses_router
|
||||
from api.api_v2.modules.coves.router import router as coves_router
|
||||
# from api.api_v2.modules.edocs import router as edocs_router
|
||||
# from api.api_v2.modules.partidas import router as partidas_router
|
||||
# from api.api_v2.modules.pedimentos import router as pedimentos_router
|
||||
|
||||
api_router = APIRouter()
|
||||
|
||||
# Incluir routers de endpoints
|
||||
api_router.include_router(acuses_router, tags=["acuses"])
|
||||
# api_router.include_router(acuses_router, tags=["acuses"])
|
||||
api_router.include_router(coves_router, tags=["coves"])
|
||||
api_router.include_router(edocs_router, tags=["edocs"])
|
||||
api_router.include_router(partidas_router, tags=["partidas"])
|
||||
api_router.include_router(pedimentos_router, tags=["pedimentos"])
|
||||
# api_router.include_router(edocs_router, tags=["edocs"])
|
||||
# api_router.include_router(partidas_router, tags=["partidas"])
|
||||
# api_router.include_router(pedimentos_router, tags=["pedimentos"])
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from .schema import CoveBaseSchema
|
||||
from typing import List
|
||||
from uuid import UUID
|
||||
|
||||
router = APIRouter()
|
||||
# Aquí puedes definir tus endpoints relacionados con COVES usando el esquema CoveBaseSchema
|
||||
|
||||
@router.post("/cove/", response_model=CoveBaseSchema)
|
||||
async def create_cove(cove: CoveBaseSchema):
|
||||
# Lógica para crear un COVE
|
||||
return cove
|
||||
@@ -0,0 +1,12 @@
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
from api.api_v2.modules.pedimentos.schema import PedimentoBaseSchema
|
||||
from schemas.CredencialSchema import CredencialBaseSchema
|
||||
|
||||
class CoveBaseSchema(BaseModel):
|
||||
cove: str = Field(..., description="ID del COVE asociado")
|
||||
pedimento: PedimentoBaseSchema
|
||||
credenciales: CredencialBaseSchema
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import base64
|
||||
from http.client import HTTPException
|
||||
import os
|
||||
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
|
||||
|
||||
|
||||
def sign_chain_original(key_path: str, password: str, cadena_original: str) -> str:
|
||||
with open(key_path, 'rb') as key_file:
|
||||
private_key = load_der_private_key(
|
||||
key_file.read(),
|
||||
password=password.encode() if password else None
|
||||
)
|
||||
|
||||
signature = private_key.sign(
|
||||
cadena_original.encode(),
|
||||
padding.PKCS1v15(),
|
||||
hashes.SHA256()
|
||||
)
|
||||
|
||||
return base64.b64encode(signature).decode()
|
||||
|
||||
async def fetch_sign_and_cer(cadena_original: str, username: str, credenciales: dict, **kwargs):
|
||||
cer = await rest_controller.get_cer(credenciales['id'])
|
||||
if cer is None:
|
||||
raise HTTPException(status_code=500, detail="No se pudo obtener el certificado para firmar el COVE")
|
||||
certificado = base64.b64encode(cer).decode('utf-8')
|
||||
|
||||
# Obtener la key como binario y guardarla en un archivo temporal
|
||||
import tempfile
|
||||
key_bytes = await rest_controller.get_key(credenciales['id'])
|
||||
if key_bytes is None:
|
||||
raise HTTPException(status_code=500, detail="No se pudo obtener la llave privada para firmar el COVE")
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmp_key_file:
|
||||
tmp_key_file.write(key_bytes)
|
||||
tmp_key_path = tmp_key_file.name
|
||||
|
||||
# Usar la ruta temporal para firmar
|
||||
firma = sign_chain_original(tmp_key_path, credenciales['efirma'], cadena_original)
|
||||
return firma, certificado, tmp_key_path
|
||||
|
||||
async def consume_ws_get_cove(**kwargs):
|
||||
|
||||
# valdiar kwargs
|
||||
|
||||
# Cadena original que vas a firmar
|
||||
|
||||
try:
|
||||
cadena_original = f"|{username}|{cove['numero_cove']}|"
|
||||
firma, certificado, tmp_key_path = await fetch_sign_and_cer(cadena_original, username, credenciales, **kwargs)
|
||||
os.remove(tmp_key_path) # Eliminar el archivo temporal después de usarlo
|
||||
|
||||
soap_xml = soap_controller.generate_cove_template(
|
||||
username=username,
|
||||
password=credenciales['password'],
|
||||
certificado=certificado,
|
||||
firma=firma,
|
||||
cove=cove,
|
||||
)
|
||||
|
||||
soap_headers = {
|
||||
'Content-Type': 'text/xml; charset=utf-8',
|
||||
'SOAPAction': '',
|
||||
#'Accept-Encoding': 'gzip,deflate',
|
||||
}
|
||||
|
||||
soap_response = await soap_controller.make_request_async(
|
||||
"ventanilla/ConsultarEdocumentService?wsdl",
|
||||
data=soap_xml,
|
||||
headers=soap_headers
|
||||
)
|
||||
|
||||
if (soap_response) and (not soap_error(soap_response)):
|
||||
remesas = 1 if response_service['pedimento'].get('remesas', 0) else 0
|
||||
patente = response_service['pedimento'].get('patente', 'N/A')
|
||||
aduana = response_service['pedimento'].get('aduana', 'N/A')
|
||||
no_partidas = response_service['pedimento'].get('numero_partidas', 0)
|
||||
tipo_operacion = response_service['pedimento'].get('tipo_operacion', 'N/A')
|
||||
pedimento = response_service['pedimento'].get('pedimento', 'N/A')
|
||||
_file_name = f"vu_COVE_{remesas}{no_partidas}{tipo_operacion}_{aduana}_{patente}_{pedimento}_{cove['numero_cove']}.xml"
|
||||
|
||||
document_response = await rest_controller.post_document(
|
||||
soap_response=soap_response,
|
||||
organizacion=response_service['organizacion'],
|
||||
pedimento=response_service['pedimento']['id'],
|
||||
file_name=_file_name,
|
||||
document_type=8,
|
||||
)
|
||||
|
||||
return {
|
||||
"servicio": response_service,
|
||||
"documento": document_response
|
||||
}
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail="Error en la petición SOAP al servicio VUCEM")
|
||||
except HTTPException:
|
||||
# Re-lanzar HTTPExceptions sin modificar
|
||||
raise
|
||||
except Exception as e:
|
||||
import traceback
|
||||
raise HTTPException(status_code=500, detail=f"Error interno al procesar acuse cove: {str(e)}")
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class PedimentoBaseSchema(BaseModel):
|
||||
id: str
|
||||
pedimento: str
|
||||
pedimento_app: str
|
||||
aduana: str
|
||||
patente: str
|
||||
regimen: str
|
||||
organizacion: str
|
||||
clave_pedimento: str
|
||||
fecha_pago: Optional[str]
|
||||
fecha_inicio: Optional[str]
|
||||
fecha_fin: Optional[str]
|
||||
alerta: Optional[bool]
|
||||
agente_aduanal: Optional[str]
|
||||
curp_apoderado: Optional[str]
|
||||
importe_total: Optional[float]
|
||||
saldo_disponible: Optional[float]
|
||||
importe_pedimento: Optional[float]
|
||||
existe_expediente: Optional[bool]
|
||||
|
||||
2
main.py
2
main.py
@@ -2,6 +2,7 @@ import logging
|
||||
from fastapi import FastAPI
|
||||
from core.config import settings
|
||||
from api.api_v1.api import api_router
|
||||
from api.api_v2.api import api_router as api_v2_router
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
# Configuración inicial del logging (debe estar al inicio del archivo)
|
||||
@@ -55,6 +56,7 @@ def create_application() -> FastAPI:
|
||||
|
||||
# Incluir el router principal de la API
|
||||
application.include_router(api_router, prefix="/api/v1")
|
||||
application.include_router(api_v2_router, prefix="/api/v2")
|
||||
|
||||
return application
|
||||
|
||||
|
||||
15
schemas/CredencialSchema.py
Normal file
15
schemas/CredencialSchema.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from schemas.importadorSchema import ImportadorBaseSchema
|
||||
|
||||
class CredencialBaseSchema(BaseModel):
|
||||
importadores: ImportadorBaseSchema
|
||||
user: str = Field(..., description="Usuario de la credencial")
|
||||
password: str = Field(..., description="Contraseña de la credencial")
|
||||
efirma: str = Field(..., description="E-firma de la credencial")
|
||||
key: str = Field(..., description="Key de la credencial")
|
||||
cer: str = Field(..., description="Cer de la credencial")
|
||||
is_active: bool = Field(..., description="Indica si la credencial está activa")
|
||||
organizacion: UUID = Field(..., description="ID de la organización asociada")
|
||||
8
schemas/importadorSchema.py
Normal file
8
schemas/importadorSchema.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
class ImportadorBaseSchema(BaseModel):
|
||||
rfc: str = Field(..., description="RFC del importador")
|
||||
nombre: Optional[str] = Field(None, description="Nombre del importador")
|
||||
organizacion: UUID = Field(..., description="ID de la organización asociada")
|
||||
Reference in New Issue
Block a user