2711 lines
107 KiB
Python
2711 lines
107 KiB
Python
import os
|
|
from rest_framework.decorators import api_view, permission_classes
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework import status
|
|
from drf_yasg.utils import swagger_auto_schema
|
|
from drf_yasg import openapi
|
|
from core.permissions import require_permission
|
|
from .tasks.auditoria import (
|
|
crear_partidas,
|
|
auditar_coves,
|
|
auditar_acuse_cove,
|
|
auditar_edocuments,
|
|
auditar_acuse,
|
|
auditar_remesas,
|
|
auditar_integridad_partidas,
|
|
auditar_integridad_partidas_por_pedimento,
|
|
auditar_integridad_edocuments,
|
|
auditar_integridad_edocuments_por_pedimento,
|
|
auditar_integridad_coves,
|
|
auditar_integridad_coves_por_pedimento,
|
|
auditar_integridad_remesa,
|
|
auditar_integridad_remesa_por_pedimento,
|
|
corregir_integridad_partidas,
|
|
corregir_integridad_edocuments,
|
|
corregir_integridad_coves,
|
|
corregir_integridad_remesa,
|
|
_corregir_integridad_partidas_pedimento,
|
|
_corregir_integridad_edocuments_pedimento,
|
|
_corregir_integridad_coves_pedimento,
|
|
_corregir_integridad_remesa_pedimento,
|
|
)
|
|
from .tasks.internal_services import auditar_pedimentos
|
|
from .tasks.microservice_v2 import procesar_pedimentos_completos, procesar_pedimento_completo_individual
|
|
from .tasks.auto_corregir import auto_corregir_pedamentos_task, auditar_pedamentos_incompletos_task
|
|
from api.customs.models import Pedimento
|
|
from api.organization.models import Organizacion
|
|
from api.record.models import Document
|
|
from .tasks.auditoria_xml import extraer_info_pedimento_xml
|
|
import tempfile
|
|
import os
|
|
from api.utils.storage_service import storage_service
|
|
import logging
|
|
import uuid
|
|
|
|
_ERROR_DOCUMENT_TYPES = [10, 14, 16, 18, 20, 22, 24, 26]
|
|
|
|
logger = logging.getLogger('api.customs.views_auditor')
|
|
|
|
def get_document_content(documento):
|
|
"""
|
|
Obtiene el contenido de un documento (MinIO o local).
|
|
Retorna el contenido como string o bytes.
|
|
"""
|
|
ruta = str(documento.archivo)
|
|
|
|
with tempfile.NamedTemporaryFile(delete=False) as tmp:
|
|
tmp_path = tmp.name
|
|
|
|
try:
|
|
success = storage_service.download_file(ruta, tmp_path)
|
|
if not success:
|
|
return None
|
|
|
|
with open(tmp_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
content = f.read()
|
|
|
|
return content
|
|
finally:
|
|
if os.path.exists(tmp_path):
|
|
os.unlink(tmp_path)
|
|
|
|
def get_document_path(documento):
|
|
"""
|
|
Obtiene la ruta temporal de un documento para lectura.
|
|
Retorna la ruta del archivo temporal descargado.
|
|
"""
|
|
ruta = str(documento.archivo)
|
|
|
|
tmp = tempfile.NamedTemporaryFile(delete=False)
|
|
tmp_path = tmp.name
|
|
tmp.close()
|
|
|
|
success = storage_service.download_file(ruta, tmp_path)
|
|
if not success:
|
|
return None
|
|
|
|
return tmp_path
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea partidas faltantes para todos los pedimentos de una organización e informa cuáles están descargadas",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID de la organización')
|
|
},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def crear_partidas_organizacion(request):
|
|
organizacion_id = request.data.get('organizacion_id')
|
|
|
|
if not organizacion_id:
|
|
return Response({'error': 'Debe proporcionar organizacion_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(user.organizacion.id) != organizacion_id:
|
|
return Response({'error': 'No tiene permisos para esta organización'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
task = crear_partidas.delay(organizacion_id, user_id=str(user.id))
|
|
|
|
return Response({
|
|
'organizacion_id': organizacion_id,
|
|
'auditoria': 'partidas',
|
|
'task_id': task.id,
|
|
'mensaje': f'Creación de partidas iniciada. Consulta el resultado en GET /api/tasks/status/{task.id}/',
|
|
}, status=status.HTTP_202_ACCEPTED)
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea partidas faltantes para un pedimento e informa cuáles están descargadas",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento')
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Resultado de creación y estado de descarga de partidas'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def crear_partidas_pedimento(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.prefetch_related('partidas').select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
if not pedimento.numero_partidas or pedimento.numero_partidas <= 0:
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'pedimento': pedimento.pedimento,
|
|
'estado': 'sin_datos',
|
|
'mensaje': f'El pedimento no tiene número de partidas definido (numero_partidas={pedimento.numero_partidas})',
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
# Crear partidas faltantes (get_or_create por número)
|
|
from api.customs.models import Partida
|
|
partidas_creadas = 0
|
|
for i in range(1, pedimento.numero_partidas + 1):
|
|
_, created = Partida.objects.get_or_create(
|
|
pedimento=pedimento,
|
|
numero_partida=i,
|
|
defaults={'organizacion_id': pedimento.organizacion_id}
|
|
)
|
|
if created:
|
|
partidas_creadas += 1
|
|
|
|
# Evaluar estado de descarga sobre el conjunto completo
|
|
partidas = list(pedimento.partidas.order_by('numero_partida'))
|
|
total = len(partidas)
|
|
descargadas = [p.numero_partida for p in partidas if p.descargado]
|
|
no_descargadas = [p.numero_partida for p in partidas if not p.descargado]
|
|
|
|
if not no_descargadas:
|
|
estado = 'completado'
|
|
mensaje = f'Todas las partidas están descargadas ({total}/{total})'
|
|
else:
|
|
estado = 'en_proceso'
|
|
mensaje = f'{len(no_descargadas)} de {total} partidas pendientes de descarga'
|
|
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'pedimento': pedimento.pedimento,
|
|
'estado': estado,
|
|
'mensaje': mensaje,
|
|
'resumen': {
|
|
'total_partidas': total,
|
|
'partidas_creadas_ahora': partidas_creadas,
|
|
'descargadas': len(descargadas),
|
|
'no_descargadas': len(no_descargadas),
|
|
},
|
|
'no_descargadas': no_descargadas,
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita todos los pedimentos de una organización",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID de la organización')
|
|
},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Tarea de auditoría iniciada correctamente'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_pedimentos_endpoint(request):
|
|
"""
|
|
Inicia una tarea de auditoría para todos los pedimentos de una organización.
|
|
Verifica todos los documentos y datos asociados a los pedimentos.
|
|
"""
|
|
organizacion_id = request.data.get('organizacion_id')
|
|
|
|
if not organizacion_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar organizacion_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos
|
|
user = request.user
|
|
if not user.is_superuser and str(user.organizacion.id) != organizacion_id:
|
|
return Response(
|
|
{'error': 'No tiene permisos para esta organización'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
|
|
# Ejecutar la tarea de auditoría
|
|
task = auditar_pedimentos.delay(organizacion_id, user_id=str(user.id))
|
|
message = f"Auditoría iniciada para la organización {organizacion_id}"
|
|
|
|
return Response({
|
|
'message': message,
|
|
'task_id': task.id
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de procesamiento de remesa de un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento a auditar')
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Estado de procesamiento de remesa del pedimento'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_procesamiento_remesa_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').prefetch_related('coves').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
if not pedimento.remesas:
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'pedimento': pedimento.pedimento,
|
|
'tiene_remesas': False,
|
|
'estado': 'completado',
|
|
'mensaje': 'El pedimento no tiene remesas para procesar',
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
tiene_documento_remesa = pedimento.documents.filter(document_type=3).exists()
|
|
coves = list(pedimento.coves.all())
|
|
total_coves = len(coves)
|
|
|
|
if not tiene_documento_remesa:
|
|
estado = 'en_proceso'
|
|
mensaje = 'Documento XML de remesa aún no descargado'
|
|
elif total_coves == 0:
|
|
estado = 'en_proceso'
|
|
mensaje = 'Documento de remesa disponible pero no se han creado COVEs'
|
|
else:
|
|
estado = 'completado'
|
|
mensaje = f'Remesa procesada — {total_coves} COVE(s) registrados'
|
|
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'pedimento': pedimento.pedimento,
|
|
'tiene_remesas': True,
|
|
'estado': estado,
|
|
'mensaje': mensaje,
|
|
'resumen': {
|
|
'tiene_documento_remesa': tiene_documento_remesa,
|
|
'total_coves_registrados': total_coves,
|
|
},
|
|
'coves': [c.numero_cove for c in coves],
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
|
|
def _lanzar_auditoria_organizacion(request, task_fn, label):
|
|
"""Helper compartido para los endpoints de auditoría masiva por organización."""
|
|
organizacion_id = request.data.get('organizacion_id')
|
|
if not organizacion_id:
|
|
return Response({'error': 'Debe proporcionar organizacion_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(user.organizacion.id) != organizacion_id:
|
|
return Response({'error': 'No tiene permisos para esta organización'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
task = task_fn.delay(organizacion_id, user_id=str(user.id))
|
|
return Response({
|
|
'organizacion_id': organizacion_id,
|
|
'auditoria': label,
|
|
'task_id': task.id,
|
|
'mensaje': f'Auditoría de {label} iniciada. Usa el stream SSE para seguimiento en tiempo real.',
|
|
}, status=status.HTTP_202_ACCEPTED)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de COVEs de todos los pedimentos de una organización",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_coves_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_coves, 'COVEs')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de acuses de COVE de todos los pedimentos de una organización",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_acuse_cove_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_acuse_cove, 'acuses de COVE')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de EDocuments de todos los pedimentos de una organización",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_edocuments_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_edocuments, 'EDocuments')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de acuses de EDocument de todos los pedimentos de una organización",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_acuse_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_acuse, 'acuses de EDocument')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de remesas de todos los pedimentos de una organización",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_remesas_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_remesas, 'remesas')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de COVEs de un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento')
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Estado de descarga de COVEs del pedimento'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_cove_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').prefetch_related('coves').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
coves = list(pedimento.coves.all())
|
|
total = len(coves)
|
|
descargados = sum(1 for c in coves if c.cove_descargado)
|
|
pendientes = [c.numero_cove for c in coves if not c.cove_descargado]
|
|
|
|
if total == 0:
|
|
nuevo_estado = 3
|
|
mensaje = 'El pedimento no tiene COVEs registrados'
|
|
elif descargados == total:
|
|
nuevo_estado = 3
|
|
mensaje = 'Todos los COVEs están descargados'
|
|
else:
|
|
nuevo_estado = 4
|
|
mensaje = f'{total - descargados} de {total} COVEs pendientes de descarga'
|
|
|
|
from api.customs.tasks.auditoria import modificar_estado_procesamiento
|
|
modificar_estado_procesamiento(pedimento, servicio_id=8, nuevo_estado=nuevo_estado)
|
|
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'estado': 'completado' if nuevo_estado == 3 else 'en_proceso',
|
|
'mensaje': mensaje,
|
|
'resumen': {
|
|
'total_coves': total,
|
|
'coves_descargados': descargados,
|
|
},
|
|
'pendientes': pendientes,
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de acuses de COVE de un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento')
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Estado de descarga de acuses de COVE del pedimento'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_acuse_cove_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').prefetch_related('coves').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
coves = list(pedimento.coves.all())
|
|
total = len(coves)
|
|
descargados = sum(1 for c in coves if c.acuse_cove_descargado)
|
|
pendientes = [c.numero_cove for c in coves if not c.acuse_cove_descargado]
|
|
|
|
if total == 0:
|
|
nuevo_estado = 3
|
|
mensaje = 'El pedimento no tiene COVEs registrados, no hay acuses que auditar'
|
|
elif descargados == total:
|
|
nuevo_estado = 3
|
|
mensaje = 'Todos los acuses de COVE están descargados'
|
|
else:
|
|
nuevo_estado = 4
|
|
mensaje = f'{total - descargados} de {total} acuses de COVE pendientes de descarga'
|
|
|
|
from api.customs.tasks.auditoria import modificar_estado_procesamiento
|
|
modificar_estado_procesamiento(pedimento, servicio_id=9, nuevo_estado=nuevo_estado)
|
|
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'estado': 'completado' if nuevo_estado == 3 else 'en_proceso',
|
|
'mensaje': mensaje,
|
|
'resumen': {
|
|
'total_coves': total,
|
|
'acuses_descargados': descargados,
|
|
},
|
|
'pendientes': pendientes,
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de EDocuments de un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento')
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Estado de descarga de EDocuments del pedimento'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_edocument_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').prefetch_related('documentos').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
edocuments = list(pedimento.documentos.all())
|
|
total = len(edocuments)
|
|
descargados = sum(1 for d in edocuments if d.edocument_descargado)
|
|
pendientes = [d.numero_edocument for d in edocuments if not d.edocument_descargado]
|
|
|
|
if total == 0:
|
|
nuevo_estado = 3
|
|
mensaje = 'El pedimento no tiene EDocuments registrados'
|
|
elif descargados == total:
|
|
nuevo_estado = 3
|
|
mensaje = 'Todos los EDocuments están descargados'
|
|
else:
|
|
nuevo_estado = 4
|
|
mensaje = f'{total - descargados} de {total} EDocuments pendientes de descarga'
|
|
|
|
from api.customs.tasks.auditoria import modificar_estado_procesamiento
|
|
modificar_estado_procesamiento(pedimento, servicio_id=7, nuevo_estado=nuevo_estado)
|
|
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'estado': 'completado' if nuevo_estado == 3 else 'en_proceso',
|
|
'mensaje': mensaje,
|
|
'resumen': {
|
|
'total_edocuments': total,
|
|
'edocuments_descargados': descargados,
|
|
},
|
|
'pendientes': pendientes,
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita el estado de descarga de acuses de EDocument de un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento')
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Estado de descarga de acuses de EDocument del pedimento'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_acuse_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').prefetch_related('documentos').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
edocuments = list(pedimento.documentos.all())
|
|
total = len(edocuments)
|
|
descargados = sum(1 for d in edocuments if d.acuse_descargado)
|
|
pendientes = [d.numero_edocument for d in edocuments if not d.acuse_descargado]
|
|
|
|
if total == 0:
|
|
nuevo_estado = 3
|
|
mensaje = 'El pedimento no tiene EDocuments registrados, no hay acuses que auditar'
|
|
elif descargados == total:
|
|
nuevo_estado = 3
|
|
mensaje = 'Todos los acuses de EDocument están descargados'
|
|
else:
|
|
nuevo_estado = 4
|
|
mensaje = f'{total - descargados} de {total} acuses de EDocument pendientes de descarga'
|
|
|
|
from api.customs.tasks.auditoria import modificar_estado_procesamiento
|
|
modificar_estado_procesamiento(pedimento, servicio_id=6, nuevo_estado=nuevo_estado)
|
|
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'estado': 'completado' if nuevo_estado == 3 else 'en_proceso',
|
|
'mensaje': mensaje,
|
|
'resumen': {
|
|
'total_edocuments': total,
|
|
'acuses_descargados': descargados,
|
|
},
|
|
'pendientes': pendientes,
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
### Procesamiento de pedimentos ###
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Procesamiento de todos los pedimentos de todas las organizaciones",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={}
|
|
),
|
|
responses={
|
|
200: openapi.Response('Tarea de procesamiento iniciada correctamente'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('No se encontraron organizaciones')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditor_procesar_pedimentos_organizacion(request):
|
|
"""
|
|
Inicia una tarea de procesamiento para todos los pedimentos de todas las organizaciones.
|
|
Solo usuarios administradores pueden ejecutar esta función.
|
|
"""
|
|
# Validar permisos (solo superusuarios pueden procesar todas las organizaciones)
|
|
user = request.user
|
|
if not user.is_superuser:
|
|
return Response(
|
|
{'error': 'Solo los superusuarios pueden procesar todas las organizaciones'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
|
|
organizaciones = Organizacion.objects.all()
|
|
if not organizaciones.exists():
|
|
return Response(
|
|
{'error': 'No se encontraron organizaciones'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
# Lista para recopilar todos los task_ids y detalles
|
|
tasks_iniciadas = []
|
|
|
|
for organizacion in organizaciones:
|
|
organizacion_id = str(organizacion.id)
|
|
print(f"Procesando organización: {organizacion_id} - {organizacion.nombre}")
|
|
# Ejecutar la tarea de procesamiento
|
|
task = procesar_pedimentos_completos.delay(organizacion_id)
|
|
|
|
# Agregar información de la tarea a la lista
|
|
tasks_iniciadas.append({
|
|
'organizacion_id': organizacion_id,
|
|
'organizacion_nombre': organizacion.nombre,
|
|
'task_id': task.id
|
|
})
|
|
|
|
# Crear mensaje general y lista de task_ids
|
|
total_organizaciones = len(tasks_iniciadas)
|
|
task_ids = [task['task_id'] for task in tasks_iniciadas]
|
|
|
|
message = f"Procesamiento de pedimentos iniciado para {total_organizaciones} organización(es)"
|
|
|
|
return Response({
|
|
'message': message,
|
|
'total_organizaciones': total_organizaciones,
|
|
'task_ids': task_ids,
|
|
'tasks_detalle': tasks_iniciadas
|
|
}, status=status.HTTP_200_OK)
|
|
### Fin Procesamiento de pedimentos ###
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_peticion_respuesta_pedimento_completo(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones y respuestas asociadas a un pedimento.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
vista_auditar = request.data.get('vista', 'desconocido') # 'completa' o 'resumen'
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
tipo_documento_peticion = None
|
|
tipo_documento_respuesta = None
|
|
vista = 'desconocido'
|
|
|
|
if vista_auditar == 'pc':
|
|
tipo_documento_peticion = 13
|
|
tipo_documento_respuesta = 14
|
|
vista = 'Pedimento Completo'
|
|
elif vista_auditar == 'rm':
|
|
tipo_documento_peticion = 15
|
|
tipo_documento_respuesta = 16
|
|
vista = 'Remesa'
|
|
elif vista_auditar == 'pt':
|
|
tipo_documento_peticion = 17
|
|
tipo_documento_respuesta = 18
|
|
vista = 'Partidas'
|
|
elif vista_auditar == 'cove':
|
|
tipo_documento_peticion = 19
|
|
tipo_documento_respuesta = 20
|
|
vista = 'COVEs'
|
|
elif vista_auditar == 'edoc':
|
|
tipo_documento_peticion = 21
|
|
tipo_documento_respuesta = 22
|
|
vista = 'Edocuments'
|
|
elif vista_auditar == 'ac_cove':
|
|
tipo_documento_peticion = 23
|
|
tipo_documento_respuesta = 24
|
|
vista = 'Acuses COVEs'
|
|
elif vista_auditar == 'ac':
|
|
tipo_documento_peticion = 25
|
|
tipo_documento_respuesta = 26
|
|
vista = 'Acuses'
|
|
|
|
if not tipo_documento_peticion and not tipo_documento_respuesta:
|
|
return Response(
|
|
{'error': 'Tipo de vista no reconocido para auditoría de pedimento'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
#archivo__icontains= f"VU_PT_{pedimento_app}_REQUEST.xml",
|
|
document_type= tipo_documento_peticion, # Tipo de documento para petición de partidas
|
|
organizacion=pedimento.organizacion,
|
|
)
|
|
|
|
documentos_respuesta = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
#archivo__icontains= f"VU_PT_{pedimento_app}_REQUEST.xml",
|
|
document_type= tipo_documento_respuesta, # Tipo de documento para respuesta de partidas
|
|
organizacion=pedimento.organizacion,
|
|
)
|
|
|
|
if not documentos_peticion and not documentos_respuesta:
|
|
return Response(
|
|
{'error': f'Registro de documentos de petición y respuesta de {vista} no encontrado(s)'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
# Crear lista con todos los documentos encontrados
|
|
documentos_lista_peticiones = []
|
|
for documento in documentos_peticion:
|
|
|
|
nombre_archivo = os.path.basename(documento.archivo.name)
|
|
ruta_temporal = get_document_path(documento)
|
|
documentos_lista_peticiones.append({
|
|
'id': str(documento.id),
|
|
'archivo': ruta_temporal,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documento.extension,
|
|
'size': documento.size,
|
|
'tipo': documento.document_type.descripcion if documento.document_type else 'Desconocido',
|
|
'creado_en': documento.created_at,
|
|
'actualizado_en': documento.updated_at
|
|
})
|
|
|
|
# Crear lista vacía para respuestas (por si se requiere en el futuro)
|
|
documentos_lista_respuestas = []
|
|
for documento in documentos_respuesta:
|
|
|
|
nombre_archivo = os.path.basename(documento.archivo.name)
|
|
|
|
documentos_lista_respuestas.append({
|
|
'id': str(documento.id),
|
|
'archivo': documento.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documento.extension,
|
|
'size': documento.size,
|
|
'tipo': documento.document_type.descripcion if documento.document_type else 'Desconocido',
|
|
'creado_en': documento.created_at,
|
|
'actualizado_en': documento.updated_at
|
|
})
|
|
|
|
# return Response({
|
|
# 'id': pedimento.id,
|
|
# 'pedimento_app': pedimento_app,
|
|
# 'contribuyente': getattr(pedimento.contribuyente, 'rfc', None),
|
|
# 'organizacion': getattr(pedimento.organizacion, 'nombre', None),
|
|
# 'creado': pedimento.created_at
|
|
# }, status=status.HTTP_200_OK)
|
|
return Response({
|
|
'id': str(pedimento.id),
|
|
'pedimento_id': str(pedimento.id),
|
|
'pedimento': pedimento.pedimento,
|
|
'pedimento_app': pedimento_app,
|
|
'contribuyente': getattr(pedimento.contribuyente, 'rfc', None),
|
|
'organizacion': getattr(pedimento.organizacion, 'nombre', None),
|
|
'creado': pedimento.created_at,
|
|
'total_documentos_peticiones': len(documentos_lista_peticiones),
|
|
'total_documentos_respuestas': len(documentos_lista_respuestas),
|
|
'documentos_peticiones': documentos_lista_peticiones,
|
|
'documentos_respuestas': documentos_lista_respuestas
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_peticion_pedimento_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones y respuestas asociadas a un pedimento.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_PC_{pedimento_app}_REQUEST.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de petición no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticament
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_respuesta_pedimento_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las respuestas asociadas a un pedimento.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_PC_{pedimento_app}_ERROR.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de respuesta no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticamente
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_peticion_remesa_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_RM_{pedimento_app}_REQUEST.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de petición de remesa no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticament
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_respuesta_remesa_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las respuestas asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_RM_{pedimento_app}_ERROR.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de respuesta de remesa no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticamente
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_peticion_partidas_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
#archivo__icontains= f"VU_PT_{pedimento_app}_REQUEST.xml",
|
|
document_type= 17, # Tipo de documento para petición de partidas
|
|
organizacion=pedimento.organizacion,
|
|
)
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de petición de partidas no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
# Crear lista con todos los documentos encontrados
|
|
documentos_lista = []
|
|
|
|
for documento in documentos_peticion:
|
|
|
|
nombre_archivo = os.path.basename(documento.archivo.name)
|
|
|
|
documentos_lista.append({
|
|
'id': str(documento.id),
|
|
'archivo': documento.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documento.extension,
|
|
'size': documento.size,
|
|
'tipo': documento.document_type.descripcion if documento.document_type else 'Desconocido',
|
|
'creado_en': documento.created_at,
|
|
'actualizado_en': documento.updated_at
|
|
})
|
|
|
|
# nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
|
|
# return Response({
|
|
# 'id': documentos_peticion.id,
|
|
# 'archivo': documentos_peticion.archivo.path,
|
|
# 'archivo_original': nombre_archivo,
|
|
# 'extension': documentos_peticion.extension,
|
|
# 'size': documentos_peticion.size,
|
|
# 'tipo': documentos_peticion.document_type.descripcion # O detectar automáticament
|
|
|
|
# }, status=status.HTTP_200_OK)
|
|
return Response({
|
|
'pedimento_id': str(pedimento.id),
|
|
'pedimento': pedimento.pedimento,
|
|
'pedimento_app': pedimento.pedimento_app,
|
|
'total_documentos': len(documentos_lista),
|
|
'documentos': documentos_lista
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_respuesta_partidas_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las respuestas asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_PT_{pedimento_app}_ERROR.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de respuesta de partidas no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticamente
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_peticion_acuse_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_AC_{pedimento_app}_REQUEST.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de petición de acuse no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticament
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_respuesta_acuse_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las respuestas asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_AC_{pedimento_app}_ERROR.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de respuesta de acuse no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticamente
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_peticion_cove_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_COVE_{pedimento_app}_REQUEST.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de petición de cove no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticament
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_respuesta_cove_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las respuestas asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_COVE_{pedimento_app}_ERROR.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de respuesta de cove no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticamente
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_peticion_acuse_cove_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_AC_COVE_{pedimento_app}_REQUEST.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de petición de acuse cove no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticament
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_respuesta_acuse_cove_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las respuestas asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_AC_COVE_{pedimento_app}_ERROR.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de respuesta de acuse cove no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticamente
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_peticion_edocument_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las peticiones asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_ED_{pedimento_app}_REQUEST.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de petición de e-document no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticament
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditor_obtener_respuesta_edocument_vu(request):
|
|
"""
|
|
Backend endpoint para obtener las respuestas asociadas a una remesa.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Validar permisos y existencia del pedimento
|
|
try:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
pedimento_app = pedimento.pedimento_app
|
|
|
|
documentos_peticion = Document.objects.filter(
|
|
pedimento=pedimento,
|
|
archivo__icontains= f"VU_ED_{pedimento_app}_ERROR.xml",
|
|
organizacion=pedimento.organizacion,
|
|
).first()
|
|
|
|
if not documentos_peticion:
|
|
return Response(
|
|
{'error': 'Documento de respuesta de e-document no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
nombre_archivo = os.path.basename(documentos_peticion.archivo.name)
|
|
return Response({
|
|
'id': documentos_peticion.id,
|
|
'archivo': documentos_peticion.archivo.path,
|
|
'archivo_original': nombre_archivo,
|
|
'extension': documentos_peticion.extension,
|
|
'size': documentos_peticion.size,
|
|
'tipo': documentos_peticion.document_type.descripcion # O detectar automáticamente
|
|
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita un pedimento específico verificando su XML y extrayendo información",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento')
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Auditoría completada'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado')
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_pedimento_endpoint(request):
|
|
"""
|
|
Audita el pedimento completo (PC): ¿está descargado? ¿se puede procesar?
|
|
Incluye diagnóstico de campos y errores detectados por tipo de documento.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related(
|
|
'organizacion', 'contribuyente'
|
|
).get(id=pedimento_id)
|
|
user = request.user
|
|
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response(
|
|
{'error': 'No tiene permisos para este pedimento'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
|
|
# PC descargado (type 2)
|
|
pc_descargado = pedimento.documents.filter(
|
|
document_type_id=2,
|
|
organizacion=pedimento.organizacion
|
|
).exists()
|
|
|
|
# Fuente de carga
|
|
fuente = 'datastage' if pedimento.consultar_vucem else 'manual'
|
|
|
|
# Diagnóstico de campos
|
|
aduana = pedimento.aduana or ''
|
|
patente = pedimento.patente or ''
|
|
numero_pedimento = pedimento.pedimento or ''
|
|
|
|
aduana_valida = bool(aduana) and aduana.isdigit() and 2 <= len(aduana) <= 3
|
|
patente_valida = bool(patente) and patente.isdigit() and len(patente) == 4
|
|
pedimento_valido = bool(numero_pedimento) and numero_pedimento.isdigit() and len(numero_pedimento) >= 7
|
|
numero_operacion_presente = bool(pedimento.numero_operacion)
|
|
|
|
from api.vucem.models import CredencialesImportador
|
|
tiene_contribuyente = pedimento.contribuyente is not None
|
|
tiene_credenciales = False
|
|
credenciales_detalle = None
|
|
if tiene_contribuyente:
|
|
credencial = CredencialesImportador.objects.filter(rfc=pedimento.contribuyente).first()
|
|
tiene_credenciales = bool(credencial and credencial.vucem)
|
|
if credencial and not credencial.vucem:
|
|
credenciales_detalle = 'Credencial encontrada pero sin cuenta VUCEM asociada'
|
|
elif not credencial:
|
|
credenciales_detalle = f'Sin credenciales VUCEM para RFC {pedimento.contribuyente.rfc}'
|
|
|
|
razones = []
|
|
if not aduana_valida:
|
|
razones.append(f'Aduana inválida o ausente (valor: "{aduana}")')
|
|
if not patente_valida:
|
|
razones.append(f'Patente inválida o ausente (valor: "{patente}")')
|
|
if not pedimento_valido:
|
|
razones.append(f'Número de pedimento inválido (valor: "{numero_pedimento}")')
|
|
if not tiene_contribuyente:
|
|
razones.append('Sin contribuyente asignado')
|
|
elif not tiene_credenciales:
|
|
razones.append(credenciales_detalle or 'Sin credenciales VUCEM')
|
|
|
|
puede_procesar = len(razones) == 0
|
|
|
|
datos = {
|
|
'aduana': aduana or None,
|
|
'patente': patente or None,
|
|
'numero_pedimento': numero_pedimento or None,
|
|
'numero_operacion': pedimento.numero_operacion,
|
|
'contribuyente_rfc': pedimento.contribuyente.rfc if pedimento.contribuyente else None,
|
|
'contribuyente_nombre': str(pedimento.contribuyente) if pedimento.contribuyente else None,
|
|
}
|
|
|
|
validacion = {
|
|
'aduana_valida': aduana_valida,
|
|
'patente_valida': patente_valida,
|
|
'pedimento_valido': pedimento_valido,
|
|
'numero_operacion_presente': numero_operacion_presente,
|
|
'tiene_contribuyente': tiene_contribuyente,
|
|
'tiene_credenciales_vucem': tiene_credenciales,
|
|
}
|
|
|
|
# Errores por tipo de documento
|
|
docs_error = (
|
|
Document.objects
|
|
.filter(
|
|
pedimento=pedimento,
|
|
organizacion=pedimento.organizacion,
|
|
document_type_id__in=_ERROR_DOCUMENT_TYPES,
|
|
)
|
|
.select_related('document_type')
|
|
.order_by('document_type_id')
|
|
)
|
|
errores_detectados = [
|
|
{
|
|
'documento_id': str(doc.id),
|
|
'nombre_archivo': os.path.basename(str(doc.archivo)),
|
|
'tipo_error': doc.document_type.descripcion if doc.document_type else 'Error desconocido',
|
|
'tipo_id': doc.document_type_id,
|
|
}
|
|
for doc in docs_error
|
|
]
|
|
|
|
# XML del PC si existe
|
|
informacion_xml = None
|
|
doc_pc = pedimento.documents.filter(
|
|
document_type_id=2,
|
|
organizacion=pedimento.organizacion,
|
|
archivo__endswith='.xml',
|
|
).first()
|
|
if doc_pc:
|
|
xml_content = get_document_content(doc_pc)
|
|
if xml_content:
|
|
info_pedimento = extraer_info_pedimento_xml(xml_content)
|
|
if info_pedimento:
|
|
informacion_xml = info_pedimento
|
|
actualizar_info_pedimento(pedimento, info_pedimento)
|
|
|
|
hay_pendientes = not pc_descargado
|
|
hay_errores = bool(errores_detectados)
|
|
|
|
if hay_errores:
|
|
estado = 'CON_ERRORES'
|
|
elif hay_pendientes:
|
|
estado = 'PENDIENTE'
|
|
else:
|
|
estado = 'COMPLETO'
|
|
|
|
return Response({
|
|
'pedimento_id': str(pedimento_id),
|
|
'pedimento': pedimento.pedimento,
|
|
'pedimento_app': pedimento.pedimento_app,
|
|
'estado': estado,
|
|
'hay_pendientes': hay_pendientes,
|
|
'hay_errores': hay_errores,
|
|
'pc_descargado': pc_descargado,
|
|
'puede_procesar': puede_procesar,
|
|
'razones_no_puede_procesar': razones,
|
|
'fuente': fuente,
|
|
'datos': datos,
|
|
'validacion': validacion,
|
|
'errores_detectados': errores_detectados,
|
|
'informacion_xml': informacion_xml,
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
except Pedimento.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Pedimento no encontrado'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
except Exception as e:
|
|
return Response(
|
|
{'error': f'Error en la auditoría: {str(e)}'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Procesa el pedimento completo (tipo 2) de un pedimento específico llamando al microservicio VUCEM.",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID del pedimento'),
|
|
},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Procesamiento encolado — usar task_id para consultar resultado'),
|
|
200: openapi.Response('El pedimento ya tiene su documento completo descargado'),
|
|
400: openapi.Response('Error en los parámetros o prerequisitos faltantes'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def procesar_pedimento_completo_endpoint(request):
|
|
"""
|
|
Diagnostica el pedimento completo y, si todo está en orden y aún no se ha
|
|
descargado, encola la tarea de procesamiento.
|
|
|
|
Siempre devuelve diagnóstico completo: validación de campos, fuente, estado
|
|
del PC y razones por las que no se puede procesar si aplica.
|
|
"""
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
|
|
if not pedimento_id:
|
|
return Response(
|
|
{'error': 'Debe proporcionar pedimento_id'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related(
|
|
'organizacion', 'contribuyente', 'tipo_operacion'
|
|
).get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
# --- Diagnóstico de campos ---
|
|
aduana = pedimento.aduana or ''
|
|
patente = pedimento.patente or ''
|
|
numero_pedimento = pedimento.pedimento or ''
|
|
|
|
aduana_valida = bool(aduana) and aduana.isdigit() and 2 <= len(aduana) <= 3
|
|
patente_valida = bool(patente) and patente.isdigit() and len(patente) == 4
|
|
pedimento_valido = bool(numero_pedimento) and numero_pedimento.isdigit() and len(numero_pedimento) >= 7
|
|
numero_operacion_presente = bool(pedimento.numero_operacion)
|
|
|
|
# --- Fuente de carga ---
|
|
# consultar_vucem=True indica que fue originado desde datastage
|
|
fuente = 'datastage' if pedimento.consultar_vucem else 'manual'
|
|
|
|
# --- Estado del PC ---
|
|
pc_descargado = pedimento.documents.filter(
|
|
document_type_id=2,
|
|
organizacion=pedimento.organizacion
|
|
).exists()
|
|
|
|
# --- Credenciales VUCEM ---
|
|
from api.vucem.models import CredencialesImportador
|
|
tiene_contribuyente = pedimento.contribuyente is not None
|
|
tiene_credenciales = False
|
|
credenciales_detalle = None
|
|
if tiene_contribuyente:
|
|
credencial = CredencialesImportador.objects.filter(rfc=pedimento.contribuyente).first()
|
|
tiene_credenciales = bool(credencial and credencial.vucem)
|
|
if credencial and not credencial.vucem:
|
|
credenciales_detalle = 'Credencial encontrada pero sin cuenta VUCEM asociada'
|
|
elif not credencial:
|
|
credenciales_detalle = f'Sin credenciales VUCEM para RFC {pedimento.contribuyente.rfc}'
|
|
|
|
# --- Puede procesar ---
|
|
razones = []
|
|
if not aduana_valida:
|
|
razones.append(f'Aduana inválida o ausente (valor: "{aduana}")')
|
|
if not patente_valida:
|
|
razones.append(f'Patente inválida o ausente (valor: "{patente}")')
|
|
if not pedimento_valido:
|
|
razones.append(f'Número de pedimento inválido (valor: "{numero_pedimento}")')
|
|
if not tiene_contribuyente:
|
|
razones.append('Sin contribuyente asignado')
|
|
elif not tiene_credenciales:
|
|
razones.append(credenciales_detalle or 'Sin credenciales VUCEM')
|
|
|
|
puede_procesar = len(razones) == 0
|
|
|
|
datos = {
|
|
'aduana': aduana or None,
|
|
'patente': patente or None,
|
|
'numero_pedimento': numero_pedimento or None,
|
|
'numero_operacion': pedimento.numero_operacion,
|
|
'regimen': pedimento.regimen,
|
|
'clave_pedimento': pedimento.clave_pedimento,
|
|
'fecha_pago': str(pedimento.fecha_pago) if pedimento.fecha_pago else None,
|
|
'contribuyente_rfc': pedimento.contribuyente.rfc if pedimento.contribuyente else None,
|
|
'contribuyente_nombre': str(pedimento.contribuyente) if pedimento.contribuyente else None,
|
|
'remesas': pedimento.remesas,
|
|
'numero_partidas': pedimento.numero_partidas,
|
|
}
|
|
|
|
validacion = {
|
|
'aduana_valida': aduana_valida,
|
|
'patente_valida': patente_valida,
|
|
'pedimento_valido': pedimento_valido,
|
|
'numero_operacion_presente': numero_operacion_presente,
|
|
'tiene_contribuyente': tiene_contribuyente,
|
|
'tiene_credenciales_vucem': tiene_credenciales,
|
|
'puede_procesar': puede_procesar,
|
|
'razones_no_puede_procesar': razones,
|
|
}
|
|
|
|
base_response = {
|
|
'pedimento_id': str(pedimento_id),
|
|
'pedimento': pedimento.pedimento,
|
|
'pedimento_app': pedimento.pedimento_app,
|
|
'fuente': fuente,
|
|
'datos': datos,
|
|
'validacion': validacion,
|
|
'pc_descargado': pc_descargado,
|
|
}
|
|
|
|
force = bool(request.data.get('force', False))
|
|
|
|
# Ya descargado — solo bloquear si no es forzado
|
|
if pc_descargado and not force:
|
|
return Response({
|
|
**base_response,
|
|
'estado': 'ya_descargado',
|
|
'mensaje': 'El pedimento completo ya fue descargado. Usa force=true para reprocesar remesas, partidas y documentos derivados.',
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
# No puede procesar — devolver diagnóstico con razones
|
|
if not puede_procesar:
|
|
return Response({
|
|
**base_response,
|
|
'estado': 'no_puede_procesar',
|
|
'mensaje': 'El pedimento no cumple los requisitos para procesar',
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
# Todo en orden — encolar
|
|
task = procesar_pedimento_completo_individual.delay(str(pedimento_id), force=force)
|
|
logger.info(f"Procesamiento PC encolado: {pedimento.pedimento} (task={task.id})")
|
|
|
|
return Response({
|
|
**base_response,
|
|
'estado': 'encolado',
|
|
'task_id': task.id,
|
|
'mensaje': f'Procesamiento encolado para {pedimento.pedimento_app}',
|
|
}, status=status.HTTP_202_ACCEPTED)
|
|
|
|
|
|
def actualizar_info_pedimento(pedimento, info_xml):
|
|
"""
|
|
Actualiza la información del pedimento con los datos extraídos del XML.
|
|
"""
|
|
try:
|
|
actualizado = False
|
|
|
|
# Actualizar información del pedimento si está en el XML y no está ya llena
|
|
if 'numero_operacion' in info_xml and not pedimento.numero_operacion:
|
|
pedimento.numero_operacion = info_xml['numero_operacion']
|
|
actualizado = True
|
|
|
|
# Número de partidas
|
|
if 'numero_partidas' in info_xml and not pedimento.numero_partidas:
|
|
pedimento.numero_partidas = info_xml['numero_partidas']
|
|
actualizado = True
|
|
|
|
# Clave del pedimento
|
|
if 'clave_pedimento' in info_xml and not pedimento.clave_pedimento:
|
|
pedimento.clave_pedimento = info_xml['clave_pedimento']
|
|
actualizado = True
|
|
|
|
# Aduana (patente)
|
|
if 'aduana_clave' in info_xml and not pedimento.aduana:
|
|
pedimento.aduana = info_xml['aduana_clave']
|
|
actualizado = True
|
|
|
|
# RFC Agente Aduanal
|
|
if 'rfc_agente_aduanal' in info_xml and not pedimento.agente_aduanal:
|
|
pedimento.agente_aduanal = info_xml['rfc_agente_aduanal']
|
|
actualizado = True
|
|
|
|
# CURP Apoderado
|
|
if 'curp_apoderado' in info_xml and not pedimento.curp_apoderado:
|
|
pedimento.curp_apoderado = info_xml['curp_apoderado']
|
|
actualizado = True
|
|
|
|
# Fecha de pago
|
|
if 'fecha_pago' in info_xml and not pedimento.fecha_pago:
|
|
try:
|
|
# Convertir formato de fecha (ej: "2024-02-15-06:00")
|
|
fecha_str = info_xml['fecha_pago']
|
|
# Extraer solo la parte de la fecha (antes del primer '-')
|
|
fecha_parts = fecha_str.split('-')
|
|
if len(fecha_parts) >= 3:
|
|
fecha_simple = f"{fecha_parts[0]}-{fecha_parts[1]}-{fecha_parts[2]}"
|
|
from datetime import datetime
|
|
fecha_obj = datetime.strptime(fecha_simple, '%Y-%m-%d').date()
|
|
pedimento.fecha_pago = fecha_obj
|
|
actualizado = True
|
|
except (ValueError, TypeError, IndexError):
|
|
pass
|
|
|
|
# Importe total (valor en dólares)
|
|
if 'valor_dolares' in info_xml and not pedimento.importe_total:
|
|
try:
|
|
pedimento.importe_total = float(info_xml['valor_dolares'])
|
|
actualizado = True
|
|
except (ValueError, TypeError):
|
|
pass
|
|
|
|
if 'contribuyente_rfc' in info_xml and not pedimento.contribuyente:
|
|
try:
|
|
# Buscar o crear el importador
|
|
from api.customs.models import Importador
|
|
importador, created = Importador.objects.get_or_create(
|
|
rfc=info_xml['contribuyente_rfc'],
|
|
organizacion=pedimento.organizacion,
|
|
defaults={'nombre': info_xml.get('contribuyente_nombre', '')}
|
|
)
|
|
pedimento.contribuyente = importador
|
|
actualizado = True
|
|
except Exception:
|
|
pass
|
|
|
|
if 'tipo_operacion' in info_xml and not pedimento.tipo_operacion:
|
|
try:
|
|
from api.customs.models import TipoOperacion
|
|
tipo_op_obj, created = TipoOperacion.objects.get_or_create(
|
|
tipo=info_xml['tipo_operacion'],
|
|
defaults={'descripcion': info_xml['tipo_operacion_descripcion'][:100]} # Limitar a 100 caracteres
|
|
)
|
|
pedimento.tipo_operacion = tipo_op_obj
|
|
actualizado = True
|
|
except Exception:
|
|
pass
|
|
|
|
if actualizado:
|
|
pedimento.save()
|
|
return True
|
|
|
|
return False
|
|
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# Auto-corrección de pedimentos incompletos
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description=(
|
|
"Encola una tarea Celery que analiza los XMLs de pedimentos con "
|
|
"consultar_vucem=False, extrae datos del pedimento completo VUCEM y "
|
|
"auto-corrige los campos faltantes (numero_operacion, aduana, "
|
|
"clave_pedimento, regimen, contribuyente). El documento se reclasifica "
|
|
"a tipo 2 (Pedimento Completo) y se activa consultar_vucem=True."
|
|
),
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
required=['organizacion_id'],
|
|
properties={
|
|
'organizacion_id': openapi.Schema(
|
|
type=openapi.TYPE_STRING,
|
|
description='UUID de la organización a procesar',
|
|
),
|
|
},
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea encolada correctamente'),
|
|
400: openapi.Response('organizacion_id faltante'),
|
|
404: openapi.Response('Organización no encontrada'),
|
|
},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auto_corregir_pedamentos_endpoint(request):
|
|
organizacion_id = request.data.get('organizacion_id')
|
|
if not organizacion_id:
|
|
return Response(
|
|
{'error': 'organizacion_id es requerido'},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
|
|
try:
|
|
Organizacion.objects.get(id=organizacion_id)
|
|
except Organizacion.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Organización no encontrada'},
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
|
|
task = auto_corregir_pedamentos_task.delay(str(organizacion_id))
|
|
logger.info(
|
|
f"[auto_corregir] tarea encolada — org={organizacion_id} task={task.id}"
|
|
)
|
|
|
|
return Response(
|
|
{
|
|
'task_id': task.id,
|
|
'organizacion': str(organizacion_id),
|
|
'mensaje': (
|
|
'Tarea encolada. Se analizarán los pedimentos con '
|
|
'consultar_vucem=False de la organización.'
|
|
),
|
|
},
|
|
status=status.HTTP_202_ACCEPTED,
|
|
)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description=(
|
|
"Análisis de solo lectura: detecta pedimentos con consultar_vucem=False "
|
|
"que podrían corregirse automáticamente. No modifica BD ni storage. "
|
|
"Retorna el listado de pedimentos corregibles, los campos que cambiarían "
|
|
"y el nuevo nombre de documento que se asignaría."
|
|
),
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
required=['organizacion_id'],
|
|
properties={
|
|
'organizacion_id': openapi.Schema(
|
|
type=openapi.TYPE_STRING,
|
|
description='UUID de la organización a analizar',
|
|
),
|
|
},
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea de análisis encolada correctamente'),
|
|
400: openapi.Response('organizacion_id faltante'),
|
|
404: openapi.Response('Organización no encontrada'),
|
|
},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_pedamentos_incompletos_endpoint(request):
|
|
organizacion_id = request.data.get('organizacion_id')
|
|
if not organizacion_id:
|
|
return Response(
|
|
{'error': 'organizacion_id es requerido'},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
|
|
try:
|
|
Organizacion.objects.get(id=organizacion_id)
|
|
except Organizacion.DoesNotExist:
|
|
return Response(
|
|
{'error': 'Organización no encontrada'},
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
|
|
task = auditar_pedamentos_incompletos_task.delay(str(organizacion_id))
|
|
logger.info(
|
|
f"[auditar_incompletos] tarea encolada — org={organizacion_id} task={task.id}"
|
|
)
|
|
|
|
return Response(
|
|
{
|
|
'task_id': task.id,
|
|
'organizacion': str(organizacion_id),
|
|
'mensaje': (
|
|
'Tarea de análisis encolada. Se reportarán los pedimentos con '
|
|
'consultar_vucem=False que podrían corregirse automáticamente, '
|
|
'sin modificar nada.'
|
|
),
|
|
},
|
|
status=status.HTTP_202_ACCEPTED,
|
|
)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Analiza un pedimento específico para auto-corrección (solo lectura, sin modificar BD). Acepta pedimento_id (UUID) o pedimento_app.",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='UUID del pedimento'),
|
|
'pedimento_app': openapi.Schema(type=openapi.TYPE_STRING, description='Número de pedimento (ej: 21-80-3452-1004463)'),
|
|
},
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea de análisis encolada'),
|
|
400: openapi.Response('Parámetro faltante'),
|
|
404: openapi.Response('Pedimento no encontrado'),
|
|
},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_pedamento_incompleto_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
pedimento_app = request.data.get('pedimento_app')
|
|
if not pedimento_id and not pedimento_app:
|
|
return Response({'error': 'pedimento_id o pedimento_app es requerido'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
if pedimento_id:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
else:
|
|
pedimento = Pedimento.objects.get(pedimento_app=pedimento_app)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
task = auditar_pedamentos_incompletos_task.delay(str(pedimento.organizacion_id), str(pedimento.id))
|
|
logger.info(f"[auditar_incompletos] individual — ped={pedimento.pedimento_app} task={task.id}")
|
|
|
|
return Response(
|
|
{
|
|
'task_id': task.id,
|
|
'pedimento_id': str(pedimento.id),
|
|
'pedimento': pedimento.pedimento_app,
|
|
'mensaje': 'Análisis individual encolado. Sin modificar nada.',
|
|
},
|
|
status=status.HTTP_202_ACCEPTED,
|
|
)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Auto-corrige un pedimento específico: extrae campos del XML y actualiza BD + storage. Acepta pedimento_id (UUID) o pedimento_app.",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={
|
|
'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING, description='UUID del pedimento'),
|
|
'pedimento_app': openapi.Schema(type=openapi.TYPE_STRING, description='Número de pedimento (ej: 21-80-3452-1004463)'),
|
|
},
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea de corrección encolada'),
|
|
400: openapi.Response('Parámetro faltante'),
|
|
404: openapi.Response('Pedimento no encontrado'),
|
|
},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auto_corregir_pedamento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
pedimento_app = request.data.get('pedimento_app')
|
|
if not pedimento_id and not pedimento_app:
|
|
return Response({'error': 'pedimento_id o pedimento_app es requerido'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
if pedimento_id:
|
|
pedimento = Pedimento.objects.get(id=pedimento_id)
|
|
else:
|
|
pedimento = Pedimento.objects.get(pedimento_app=pedimento_app)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
task = auto_corregir_pedamentos_task.delay(str(pedimento.organizacion_id), str(pedimento.id))
|
|
logger.info(f"[auto_corregir] individual — ped={pedimento.pedimento_app} task={task.id}")
|
|
|
|
return Response(
|
|
{
|
|
'task_id': task.id,
|
|
'pedimento_id': str(pedimento.id),
|
|
'pedimento': pedimento.pedimento_app,
|
|
'mensaje': 'Corrección individual encolada.',
|
|
},
|
|
status=status.HTTP_202_ACCEPTED,
|
|
)
|
|
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# Endpoints de auditorías de integridad
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de partidas: compara numero_partidas del XML vs partidas registradas en DB (solo lectura, no crea registros)",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_integridad_partidas_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_integridad_partidas, 'integridad de partidas')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de partidas para un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Resultado de integridad de partidas del pedimento'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_integridad_partidas_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
resultado = auditar_integridad_partidas_por_pedimento(pedimento_id)
|
|
return Response(resultado, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de edocuments: compara lista del XML del pedimento completo vs EDocuments registrados en DB",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={
|
|
202: openapi.Response('Tarea iniciada — usar task_id para consultar resultado'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_integridad_edocuments_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_integridad_edocuments, 'integridad de edocuments')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de edocuments para un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={
|
|
200: openapi.Response('Resultado de integridad de edocuments del pedimento'),
|
|
400: openapi.Response('Error en los parámetros'),
|
|
403: openapi.Response('No tiene permisos suficientes'),
|
|
404: openapi.Response('Pedimento no encontrado'),
|
|
}
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_integridad_edocuments_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
resultado = auditar_integridad_edocuments_por_pedimento(pedimento_id)
|
|
return Response(resultado, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de COVEs del PC XML contra los registrados en DB (nivel organización)",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={202: openapi.Response('Tarea iniciada'), 400: 'Error en parámetros', 403: 'Sin permisos'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_integridad_coves_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_integridad_coves, 'integridad de COVEs')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de COVEs del PC XML para un pedimento específico",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={200: 'Resultado', 400: 'Error en parámetros', 403: 'Sin permisos', 404: 'No encontrado'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_integridad_coves_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
resultado = auditar_integridad_coves_por_pedimento(pedimento_id)
|
|
return Response(resultado, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de COVEs del XML de remesa contra los registrados en DB (nivel organización)",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={202: openapi.Response('Tarea iniciada'), 400: 'Error en parámetros', 403: 'Sin permisos'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def auditar_integridad_remesa_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, auditar_integridad_remesa, 'integridad de remesas')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Audita integridad de COVEs del XML de remesa para un pedimento específico. Deduce si es consolidado desde el identificador PC del pedimento completo; si falta el documento de remesa, dispara la consulta a VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={200: 'Resultado', 400: 'Error en parámetros', 403: 'Sin permisos', 404: 'No encontrado'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.view')])
|
|
def auditar_integridad_remesa_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
resultado = auditar_integridad_remesa_por_pedimento(pedimento_id)
|
|
return Response(resultado, status=status.HTTP_200_OK)
|
|
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# Endpoints de CORRECCIÓN de integridad
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea Partidas faltantes en toda la organización y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={202: openapi.Response('Tarea iniciada'), 400: 'Error en parámetros', 403: 'Sin permisos'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_partidas_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, corregir_integridad_partidas, 'corrección de partidas')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea Partidas faltantes para un pedimento específico y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={200: 'Resultado', 400: 'Error en parámetros', 403: 'Sin permisos', 404: 'No encontrado'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_partidas_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
resultado = _corregir_integridad_partidas_pedimento(pedimento)
|
|
return Response(resultado, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea EDocuments faltantes en toda la organización desde el XML del pedimento completo y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={202: openapi.Response('Tarea iniciada'), 400: 'Error en parámetros', 403: 'Sin permisos'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_edocuments_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, corregir_integridad_edocuments, 'corrección de edocuments')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea EDocuments faltantes para un pedimento específico y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={200: 'Resultado', 400: 'Error en parámetros', 403: 'Sin permisos', 404: 'No encontrado'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_edocuments_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
resultado = _corregir_integridad_edocuments_pedimento(pedimento)
|
|
return Response(resultado, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea COVEs faltantes del PC XML en toda la organización y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={202: openapi.Response('Tarea iniciada'), 400: 'Error en parámetros', 403: 'Sin permisos'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_coves_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, corregir_integridad_coves, 'corrección de COVEs')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea COVEs faltantes del PC XML para un pedimento específico y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={200: 'Resultado', 400: 'Error en parámetros', 403: 'Sin permisos', 404: 'No encontrado'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_coves_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
resultado = _corregir_integridad_coves_pedimento(pedimento)
|
|
return Response(resultado, status=status.HTTP_200_OK)
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea COVEs faltantes del XML de remesa en toda la organización y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'organizacion_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['organizacion_id']
|
|
),
|
|
responses={202: openapi.Response('Tarea iniciada'), 400: 'Error en parámetros', 403: 'Sin permisos'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_remesa_endpoint(request):
|
|
return _lanzar_auditoria_organizacion(request, corregir_integridad_remesa, 'corrección de remesas')
|
|
|
|
|
|
@swagger_auto_schema(
|
|
method='post',
|
|
operation_description="Crea COVEs faltantes del XML de remesa para un pedimento específico y dispara procesamiento VUCEM",
|
|
request_body=openapi.Schema(
|
|
type=openapi.TYPE_OBJECT,
|
|
properties={'pedimento_id': openapi.Schema(type=openapi.TYPE_STRING)},
|
|
required=['pedimento_id']
|
|
),
|
|
responses={200: 'Resultado', 400: 'Error en parámetros', 403: 'Sin permisos', 404: 'No encontrado'},
|
|
)
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated, require_permission('auditoria.process')])
|
|
def corregir_integridad_remesa_pedimento_endpoint(request):
|
|
pedimento_id = request.data.get('pedimento_id')
|
|
if not pedimento_id:
|
|
return Response({'error': 'Debe proporcionar pedimento_id'}, status=status.HTTP_400_BAD_REQUEST)
|
|
try:
|
|
pedimento = Pedimento.objects.select_related('organizacion').get(id=pedimento_id)
|
|
except Pedimento.DoesNotExist:
|
|
return Response({'error': 'Pedimento no encontrado'}, status=status.HTTP_404_NOT_FOUND)
|
|
user = request.user
|
|
if not user.is_superuser and str(pedimento.organizacion.id) != str(user.organizacion.id):
|
|
return Response({'error': 'No tiene permisos para este pedimento'}, status=status.HTTP_403_FORBIDDEN)
|
|
resultado = _corregir_integridad_remesa_pedimento(pedimento)
|
|
return Response(resultado, status=status.HTTP_200_OK) |