import os from datetime import datetime from django.db import models from celery import shared_task, group from api.customs.models import ProcesamientoPedimento, Pedimento, Cove, EDocument from core.utils import xml_controller import requests from core.utils import xml_remesas_controller def obtener_pedimentos(organizacion_id): return Pedimento.objects.filter(organizacion_id=organizacion_id) def extraer_coves(pedimento): remesas = pedimento.documents.filter(document_type=3).first() with open(f'./media/{remesas.archivo}', 'r') as f: xml_content = f.read() xml_data = xml_remesas_controller.extract_remesas(xml_content) 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() # Si no hay documentos, marcar como completado if not docs.exists(): proceso = modificar_estado_procesamiento(pedimento, servicio_id=servicio, nuevo_estado=3) # Estado "completado" print(f"✓ Pedimento {pedimento_id} no tiene {mensaje}s para procesar.") else: 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} 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} 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_remesa_por_pedimento(pedimento_id): """ Audita el procesamiento de remesa para un pedimento específico. Args: pedimento_id: UUID del pedimento a auditar Returns: dict: Resultado de la auditoría con detalles del procesamiento """ try: pedimento = Pedimento.objects.get(id=pedimento_id) resultado = { 'pedimento_id': str(pedimento_id), 'pedimento_numero': pedimento.pedimento, 'tiene_remesas': pedimento.remesas, 'procesamiento_creado': False, 'coves_creados': [] } if not pedimento.remesas: resultado['mensaje'] = 'El pedimento no tiene remesas para procesar' return resultado # Verificar documento tipo remesa if not pedimento.documents.filter(document_type=3).exists(): # Crear procesamiento si no existe documento de remesa procesamiento, creado = ProcesamientoPedimento.objects.get_or_create( pedimento=pedimento, servicio_id=5, # ID del servicio de remesas organizacion=pedimento.organizacion_id ) resultado['procesamiento_creado'] = creado resultado['mensaje'] = 'Procesamiento de remesa creado - documento no encontrado' else: # Procesar XML de remesas xml_data = extraer_coves(pedimento) if xml_data: for remesa in xml_data: numero_cove = remesa.get('remesaSA') cove, creado = Cove.objects.get_or_create( pedimento=pedimento, numero_cove=numero_cove, organizacion=pedimento.organizacion_id ) if creado: resultado['coves_creados'].append(numero_cove) resultado['mensaje'] = f"Procesados {len(xml_data)} remesas, creados {len(resultado['coves_creados'])} COVEs nuevos" else: resultado['mensaje'] = 'No se encontraron datos de remesas en el XML' return resultado except Pedimento.DoesNotExist: return { 'error': f'Pedimento con ID {pedimento_id} no encontrado', 'pedimento_id': str(pedimento_id) } except Exception as e: return { 'error': f'Error procesando pedimento {pedimento_id}: {str(e)}', 'pedimento_id': str(pedimento_id) } @shared_task def crear_partidas(organizacion_id): pedimentos = obtener_pedimentos(organizacion_id) total_pedimentos = pedimentos.count() pedimentos_procesados = 0 total_partidas_agregadas = 0 print(f"Iniciando procesamiento de {total_pedimentos} pedimentos para organización {organizacion_id}") for pedimento in pedimentos: pedimentos_procesados += 1 partidas_agregadas_pedimento = 0 # 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_existentes = pedimento.partidas.count() if pedimento.numero_partidas > partidas_existentes: print(f"Procesando pedimento {pedimento.id} ({pedimentos_procesados}/{total_pedimentos}) - Partidas existentes: {partidas_existentes}, Requeridas: {pedimento.numero_partidas}") for i in range(1, pedimento.numero_partidas + 1): from api.customs.models import Partida partida, created = Partida.objects.get_or_create( pedimento=pedimento, numero_partida=i, organizacion_id=organizacion_id ) if created: partidas_agregadas_pedimento += 1 total_partidas_agregadas += 1 print(f" → Partidas agregadas para pedimento {pedimento.id}: {partidas_agregadas_pedimento}") else: print(f"Pedimento {pedimento.id} ya tiene todas sus partidas ({partidas_existentes}/{pedimento.numero_partidas})") else: print(f"Pedimento {pedimento.id} omitido - numero_partidas: {pedimento.numero_partidas} (inválido)") print(f"\n=== RESUMEN ===") print(f"Pedimentos procesados: {pedimentos_procesados}") print(f"Total de partidas agregadas: {total_partidas_agregadas}") print(f"Procesamiento completado para organización {organizacion_id}") @shared_task def crear_partidas_por_pedimento(pedimento_id): try: pedimento = Pedimento.objects.get(id=pedimento_id) except Pedimento.DoesNotExist: print(f"Error: Pedimento con ID {pedimento_id} no encontrado") return print(f"Procesando pedimento individual {pedimento_id}...") partidas_agregadas = 0 # 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_existentes = pedimento.partidas.count() if pedimento.numero_partidas > partidas_existentes: print(f"Pedimento {pedimento_id} - Partidas existentes: {partidas_existentes}, Requeridas: {pedimento.numero_partidas}") for i in range(1, pedimento.numero_partidas + 1): from api.customs.models import Partida partida, created = Partida.objects.get_or_create( pedimento=pedimento, numero_partida=i, organizacion_id=pedimento.organizacion_id ) if created: partidas_agregadas += 1 print(f"✓ Partidas agregadas para pedimento {pedimento_id}: {partidas_agregadas}") 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}") # 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='cove_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' ) @shared_task def auditar_cove_por_pedimento(pedimento_id): try: from api.customs.models import Pedimento pedimento = Pedimento.objects.get(id=pedimento_id) auditor_descargas( pedimento, servicio=8, related_name='coves', variable='cove_descargado', mensaje='COVE' ) return {'success': True, 'pedimento_id': str(pedimento_id)} except Exception as e: return {'success': False, 'error': str(e), 'pedimento_id': str(pedimento_id)} @shared_task def auditar_acuse_cove_por_pedimento(pedimento_id): try: from api.customs.models import Pedimento pedimento = Pedimento.objects.get(id=pedimento_id) auditor_descargas( pedimento, servicio=9, related_name='coves', variable='acuse_cove_descargado', mensaje='acuse de COVE' ) return {'success': True, 'pedimento_id': str(pedimento_id)} except Exception as e: return {'success': False, 'error': str(e), 'pedimento_id': str(pedimento_id)} @shared_task def auditar_edocument_por_pedimento(pedimento_id): try: from api.customs.models import Pedimento pedimento = Pedimento.objects.get(id=pedimento_id) auditor_descargas( pedimento, servicio=7, related_name='documentos', variable='edocument_descargado', mensaje='EDocument' ) return {'success': True, 'pedimento_id': str(pedimento_id)} except Exception as e: return {'success': False, 'error': str(e), 'pedimento_id': str(pedimento_id)} @shared_task def auditar_acuse_por_pedimento(pedimento_id): try: from api.customs.models import Pedimento pedimento = Pedimento.objects.get(id=pedimento_id) auditor_descargas( pedimento, servicio=6, related_name='documentos', variable='acuse_descargado', mensaje='acuse' ) return {'success': True, 'pedimento_id': str(pedimento_id)} except Exception as e: return {'success': False, 'error': str(e), 'pedimento_id': str(pedimento_id)} @shared_task def auditar_pedimento_por_id(pedimento_id): """ Tarea para auditar un pedimento específico verificando todos sus documentos y datos. """ try: pedimento = Pedimento.objects.get(id=pedimento_id) resultado = { 'pedimento_id': str(pedimento_id), 'pedimento': pedimento.pedimento, 'pedimento_app': pedimento.pedimento_app, 'organizacion': str(pedimento.organizacion.id), 'fecha_auditoria': datetime.now().isoformat(), 'estado_general': 'EN_PROGRESO', 'detalles': {} } # 1. Verificar documentos XML from api.record.models import Document documentos_xml = Document.objects.filter( pedimento=pedimento, archivo__endswith='.xml' ) resultado['detalles']['documentos_xml'] = { 'total': documentos_xml.count(), 'archivos': [] } for doc in documentos_xml: try: xml_info = { 'id': str(doc.id), 'nombre': os.path.basename(doc.archivo.name), 'tamanio': doc.size, 'extension': doc.extension, 'tipo': doc.document_type.descripcion if doc.document_type else 'Desconocido' } # Verificar si el archivo existe físicamente if os.path.exists(doc.archivo.path): xml_info['existe_fisicamente'] = True # Intentar leer el XML try: with open(doc.archivo.path, 'r', encoding='utf-8') as f: content = f.read() xml_info['es_xml_valido'] = ' 0, 'fecha_pago': bool(pedimento.fecha_pago) } resultado['detalles']['campos_pedimento'] = campos_revisados resultado['detalles']['campos_completos'] = sum(campos_revisados.values()) resultado['detalles']['campos_totales'] = len(campos_revisados) # 7. Determinar estado general campos_completos = resultado['detalles']['campos_completos'] total_campos = resultado['detalles']['campos_totales'] if documentos_xml.count() == 0: resultado['estado_general'] = 'SIN_XML' resultado['mensaje'] = 'No se encontraron documentos XML' elif campos_completos == total_campos: resultado['estado_general'] = 'COMPLETO' resultado['mensaje'] = 'Pedimento completamente procesado' elif campos_completos >= total_campos * 0.7: resultado['estado_general'] = 'PARCIAL' resultado['mensaje'] = 'Pedimento parcialmente procesado' else: resultado['estado_general'] = 'INCOMPLETO' resultado['mensaje'] = 'Pedimento con información incompleta' resultado['porcentaje_completitud'] = (campos_completos / total_campos) * 100 if total_campos > 0 else 0 # 8. Sugerencias sugerencias = [] if not pedimento.numero_operacion: sugerencias.append("Falta el número de operación") if not pedimento.numero_partidas: sugerencias.append("Falta el número de partidas") if pedimento.numero_partidas and pedimento.numero_partidas > pedimento.partidas.count(): sugerencias.append(f"Faltan partidas: {pedimento.numero_partidas - pedimento.partidas.count()} de {pedimento.numero_partidas}") if not pedimento.contribuyente: sugerencias.append("Falta el contribuyente asociado") resultado['sugerencias'] = sugerencias return resultado except Pedimento.DoesNotExist: return { 'error': f'Pedimento con ID {pedimento_id} no encontrado', 'pedimento_id': str(pedimento_id) } except Exception as e: return { 'error': f'Error auditar pedimento {pedimento_id}: {str(e)}', 'pedimento_id': str(pedimento_id) }