From 6480b0a5a0a4eb2cc4bb4ec1087ba141a89b1346 Mon Sep 17 00:00:00 2001 From: Kevin Rosales Date: Tue, 7 Oct 2025 20:57:50 -0600 Subject: [PATCH] se agrego comando del auditor --- .../management/commands/AUDITOR_COMMAND.md | 122 +++++++++++++++++ api/customs/management/commands/auditor.py | 97 +++++++++++++ api/customs/tasks/auditoria.py | 128 +++++++++++------- api/customs/views.py | 2 - api/customs/views_auditor.py | 2 + 5 files changed, 301 insertions(+), 50 deletions(-) create mode 100644 api/customs/management/commands/AUDITOR_COMMAND.md create mode 100644 api/customs/management/commands/auditor.py diff --git a/api/customs/management/commands/AUDITOR_COMMAND.md b/api/customs/management/commands/AUDITOR_COMMAND.md new file mode 100644 index 0000000..4a02ba7 --- /dev/null +++ b/api/customs/management/commands/AUDITOR_COMMAND.md @@ -0,0 +1,122 @@ +# Comando de Auditoría de Pedimentos + +## 📝 Descripción +El comando `auditor` es una herramienta flexible para ejecutar tareas de auditoría y verificación de datos relacionados con pedimentos de una organización específica. Permite ejecutar todas las tareas o seleccionar específicamente cuáles ejecutar. + +## 🔍 Tareas Disponibles + +- **remesas**: Auditoría de remesas y procesamiento de COVEs +- **partidas**: Creación y validación de partidas faltantes +- **coves**: Auditoría de COVEs y su estado +- **acuse-cove**: Verificación de acuses de COVEs +- **edocs**: Auditoría de E-documents +- **acuses**: Verificación de acuses generales + +## 💻 Uso + +### Ver Tareas Disponibles +```bash +python manage.py auditor --list +``` + +### Ejecutar Todas las Tareas +```bash +python manage.py auditor +# o explícitamente +python manage.py auditor --tareas todas +``` + +### Ejecutar Tareas Específicas +```bash +# Ejecutar solo auditoría de remesas y COVEs +python manage.py auditor --tareas remesas coves + +# Ejecutar partidas y acuses +python manage.py auditor --tareas partidas acuses + +# Ejecutar E-documents y acuses de COVEs +python manage.py auditor --tareas edocs acuse-cove +``` + +### Ejecución en Docker +```bash +docker exec -it EFC_backend_dev python manage.py auditor [opciones] +``` + +### Ejemplos +```bash +# Listar tareas disponibles +python manage.py auditor --list + +# Auditar todo para una organización +python manage.py auditor 9d705e97-d3f2-4b6c-8d92-9f1af2b2d4b4 + +# Auditar solo remesas y COVEs +python manage.py auditor 9d705e97-d3f2-4b6c-8d92-9f1af2b2d4b4 --tareas remesas coves +``` + +## 📊 Monitoreo y Resultados + +### Indicadores de Estado +- ✓ Tarea iniciada correctamente +- ✗ Error en la ejecución + +### Información Mostrada +- ID de la organización +- Número total de pedimentos +- Task ID de cada tarea iniciada +- Tiempo total de ejecución +- Estado de cada tarea + +## ⚠️ Consideraciones Importantes + +### Requisitos Previos +- Acceso al servidor/contenedor +- Permisos de Django +- ID válido de organización +- Celery en ejecución + +### Recomendaciones +1. **Antes de Ejecutar** + - Realizar respaldo de datos + - Verificar disponibilidad de recursos + - Comprobar conexión con servicios + +2. **Durante la Ejecución** + - Monitorear logs de Celery + - Verificar uso de recursos + - No interrumpir el proceso + +3. **Después de la Ejecución** + - Verificar logs + - Validar resultados + - Documentar incidencias + +## 🔧 Solución de Problemas + +### Errores Comunes +1. **Organización no encontrada** + - Verificar ID de organización + - Confirmar existencia de pedimentos + +2. **Tareas no inician** + - Verificar estado de Celery + - Comprobar permisos + - Revisar conexiones + +3. **Errores de ejecución** + - Consultar logs detallados + - Verificar disponibilidad de servicios + - Comprobar estado de la base de datos + +## 📝 Notas Adicionales +- Las tareas se ejecutan de forma asíncrona +- El tiempo mostrado corresponde solo a la inicialización +- Las tareas continúan en segundo plano +- Se recomienda ejecutar en horarios de bajo tráfico + +## 🔍 Logs y Monitoreo +Para un seguimiento detallado, revisar: +- Logs de Celery +- Logs de Django +- Monitor de tareas de Celery \ No newline at end of file diff --git a/api/customs/management/commands/auditor.py b/api/customs/management/commands/auditor.py new file mode 100644 index 0000000..f512234 --- /dev/null +++ b/api/customs/management/commands/auditor.py @@ -0,0 +1,97 @@ +from django.core.management.base import BaseCommand +from api.customs.tasks.auditoria import ( + auditar_procesamiento_remesas, + auditar_coves, + auditar_acuse_cove, + auditar_edocuments, + auditar_acuse, + crear_partidas +) +from api.customs.models import Pedimento +from datetime import datetime + +class Command(BaseCommand): + help = 'Ejecuta tareas de auditoría para una organización' + + # Definir las tareas disponibles + TAREAS_DISPONIBLES = { + 'remesas': (auditar_procesamiento_remesas, "Auditoría de remesas"), + 'partidas': (crear_partidas, "Creación de partidas"), + 'coves': (auditar_coves, "Auditoría de COVEs"), + 'acuse-cove': (auditar_acuse_cove, "Auditoría de acuses de COVEs"), + 'edocs': (auditar_edocuments, "Auditoría de E-documents"), + 'acuses': (auditar_acuse, "Auditoría de acuses") + } + + def add_arguments(self, parser): + parser.add_argument( + 'organizacion_id', + type=str, + help='ID de la organización a auditar' + ) + parser.add_argument( + '--tareas', + nargs='+', + choices=['todas'] + list(self.TAREAS_DISPONIBLES.keys()), + default=['todas'], + help='Lista de tareas a ejecutar. Opciones: todas, ' + + ', '.join(self.TAREAS_DISPONIBLES.keys()) + ) + parser.add_argument( + '--list', + action='store_true', + help='Muestra la lista de tareas disponibles' + ) + + def handle(self, *args, **options): + organizacion_id = options['organizacion_id'] + start_time = datetime.now() + + # Verificar si la organización tiene pedimentos + pedimentos_count = Pedimento.objects.filter(organizacion_id=organizacion_id).count() + if not pedimentos_count: + self.stdout.write( + self.style.ERROR(f'No se encontraron pedimentos para la organización {organizacion_id}') + ) + return + + self.stdout.write(f'Iniciando auditoría para organización {organizacion_id}') + self.stdout.write(f'Total de pedimentos a procesar: {pedimentos_count}') + + # Si se solicita listar las tareas + if options['list']: + self.stdout.write('Tareas disponibles:') + for key, (_, desc) in self.TAREAS_DISPONIBLES.items(): + self.stdout.write(f' - {key}: {desc}') + return + + # Determinar qué tareas ejecutar + tareas_seleccionadas = [] + if 'todas' in options['tareas']: + tareas_seleccionadas = list(self.TAREAS_DISPONIBLES.values()) + else: + for tarea in options['tareas']: + if tarea in self.TAREAS_DISPONIBLES: + tareas_seleccionadas.append(self.TAREAS_DISPONIBLES[tarea]) + + self.stdout.write(f'Tareas seleccionadas: {len(tareas_seleccionadas)}') + for _, desc in tareas_seleccionadas: + self.stdout.write(f' - {desc}') + + # Ejecutar cada tarea + for tarea, descripcion in tareas_seleccionadas: + self.stdout.write(f'\nIniciando {descripcion}...') + try: + resultado = tarea.delay(organizacion_id) + self.stdout.write( + self.style.SUCCESS(f'✓ {descripcion} iniciada (Task ID: {resultado.id})') + ) + except Exception as e: + self.stdout.write( + self.style.ERROR(f'✗ Error en {descripcion}: {str(e)}') + ) + + tiempo_total = datetime.now() - start_time + self.stdout.write(self.style.SUCCESS( + f'\nProceso de auditoría completado en {tiempo_total}' + )) \ No newline at end of file diff --git a/api/customs/tasks/auditoria.py b/api/customs/tasks/auditoria.py index b2fb7b2..42a3558 100644 --- a/api/customs/tasks/auditoria.py +++ b/api/customs/tasks/auditoria.py @@ -16,6 +16,36 @@ def extraer_coves(pedimento): return xml_data +def modificar_estado_procesamiento(pedimento, servicio_id, nuevo_estado): + procesamiento = ProcesamientoPedimento.objects.filter( + pedimento=pedimento, + servicio_id=servicio_id, + organizacion=pedimento.organizacion + ).first() + if procesamiento: + procesamiento.estado_id = nuevo_estado + procesamiento.save() + return True + return False + +def auditor_descargas(pedimento, servicio, related_name, variable, mensaje): + pedimento_id = pedimento.id + docs = getattr(pedimento, related_name).all() + + all_docs = all(getattr(doc, variable) for doc in docs) + + if all_docs: + proceso = modificar_estado_procesamiento(pedimento, servicio_id=servicio, nuevo_estado=3) # Estado "completado" + print(f"✓ Pedimento {pedimento_id} tiene todos sus {mensaje} de edocument descargados.") + else: + proceso = modificar_estado_procesamiento(pedimento, servicio_id=servicio, nuevo_estado=4) # Estado "en progreso" + print(f"✗ Pedimento {pedimento_id} NO tiene todos sus {mensaje} de edocument descargados.") + if proceso: + print(f"✓ Proceso de auditoría para pedimento {pedimento_id} completado.") + else: + print(f"✗ No se encontró proceso de auditoría para pedimento {pedimento_id}.") + +## Auditar pedimentos @shared_task def auditar_procesamiento_remesas(organizacion_id): pedimentos = obtener_pedimentos(organizacion_id) @@ -103,53 +133,6 @@ def auditar_procesamiento_remesa_por_pedimento(pedimento_id): 'pedimento_id': str(pedimento_id) } - -@shared_task -def auditar_partidas(organizacion_id): - pedimentos = Pedimento.objects.filter(organizacion_id=organizacion_id) - for pedimento in pedimentos: - # Validar que numero_partidas no sea None y sea mayor que 0 - if pedimento.numero_partidas is not None and pedimento.numero_partidas > 0: - partidas_descargadas = pedimento.documents.filter(document_type=1) - - partidas = {str(documento.archivo).split('_')[-1].split('.')[0]: documento.archivo for documento in partidas_descargadas} - partidas_faltantes = [] - - for i in range(1, pedimento.numero_partidas + 1): - if str(i) not in partidas.keys(): - partidas_faltantes.append(i) - # crear servicio individual para cada partida faltante en microservicios - - -@shared_task -def auditar_coves(organizacion_id): - # crear servicio individual para cada cove faltante en microservicios - pass - -@shared_task -def auditar_edocuments(organizacion_id): - # crear servicio individual para cada Edocument faltante en microservicios - pass - -@shared_task -def auditar_acuse_coves(organizacion_id): - # crear servicio individual para cada cove faltante en microservicios - - pass - - - -@shared_task -def auditar_acuse_edocuments(organizacion_id): - # crear servicio individual para cada acuse de edocument faltante en microservicios - pedimentos = obtener_pedimentos(organizacion_id) - - for pedimento in pedimentos: - acuses_descargados = pedimento.documents.filter(document_type=4) - edocs = pedimento.documentos.all() - - - @shared_task def crear_partidas(organizacion_id): pedimentos = obtener_pedimentos(organizacion_id) @@ -222,4 +205,53 @@ def crear_partidas_por_pedimento(pedimento_id): else: print(f"Pedimento {pedimento_id} ya tiene todas sus partidas ({partidas_existentes}/{pedimento.numero_partidas})") else: - print(f"Error: Pedimento {pedimento_id} tiene numero_partidas inválido: {pedimento.numero_partidas}") \ No newline at end of file + print(f"Error: Pedimento {pedimento_id} tiene numero_partidas inválido: {pedimento.numero_partidas}") + +# Auditar coves +@shared_task +def auditar_coves(organizacion_id): + for pedimento in obtener_pedimentos(organizacion_id): + auditor_descargas( + pedimento, + servicio=8, + related_name='coves', + variable='acuse_descargado', + mensaje='COVE' + ) + +@shared_task +def auditar_acuse_cove(organizacion_id): + for pedimento in obtener_pedimentos(organizacion_id): + auditor_descargas( + pedimento, + servicio=9, + related_name='coves', + variable='acuse_cove_descargado', + mensaje='acuse de COVE' + ) + +# Revisa si el pedimento completo todos sus acuse coves + +# Auditar edocuments +@shared_task +def auditar_edocuments(organizacion_id): + for pedimento in obtener_pedimentos(organizacion_id): + auditor_descargas( + pedimento, + servicio=7, + related_name='documentos', + variable='edocument_descargado', + mensaje='EDocument' + ) + +@shared_task +def auditar_acuse(organizacion_id): + for pedimento in obtener_pedimentos(organizacion_id): + auditor_descargas( + pedimento, + servicio=6, + related_name='documentos', + variable='acuse_descargado', + mensaje='acuse' + ) + diff --git a/api/customs/views.py b/api/customs/views.py index 3bc0129..ab1bf73 100644 --- a/api/customs/views.py +++ b/api/customs/views.py @@ -260,8 +260,6 @@ class PartidaViewSet(viewsets.ModelViewSet): my_tags = ['Partidas'] - - class ViewSetTipoOperacion(LoggingMixin, viewsets.ModelViewSet): """ ViewSet for TipoOperacion model. diff --git a/api/customs/views_auditor.py b/api/customs/views_auditor.py index 0a12f00..980b2df 100644 --- a/api/customs/views_auditor.py +++ b/api/customs/views_auditor.py @@ -275,3 +275,5 @@ def auditar_procesamiento_remesas_endpoint(request): 'message': message, 'task_id': task.id }, status=status.HTTP_200_OK) + +