diff --git a/MEDIA_CLEANUP_GUIDE.md b/MEDIA_CLEANUP_GUIDE.md index bb530b7..0a528a6 100644 --- a/MEDIA_CLEANUP_GUIDE.md +++ b/MEDIA_CLEANUP_GUIDE.md @@ -43,25 +43,25 @@ python manage.py cleanup_media_fast [opciones] ### 1. Análisis Inicial (Siempre hacer primero) ```bash # Escaneo rápido para obtener una estimación -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --dry-run --verbose" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --dry-run --verbose" # O escaneo completo para números exactos (puede tomar tiempo) -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --dry-run --verbose" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --dry-run --verbose" ``` ### 2. Limpieza por Lotes (Recomendado para grandes volúmenes) ```bash # Limpiar muestra de 10,000 archivos -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --verbose" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --verbose" # Limpiar hasta 5,000 archivos específicos -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --limit 5000 --verbose" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --limit 5000 --verbose" ``` ### 3. Limpieza Completa ```bash # Eliminar todos los archivos huérfanos (CUIDADO: puede tomar mucho tiempo) -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --verbose" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --verbose" ``` ## Ejemplos de Salida @@ -96,28 +96,28 @@ Eliminados 2763 archivos huérfanos (51.32 MB) ### Caso 1: Primera vez ejecutando el comando ```bash # 1. Hacer análisis inicial -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --dry-run" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --dry-run" # 2. Si hay pocos archivos (<5000), eliminar todos -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan" # 3. Si hay muchos archivos, eliminar por lotes -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --limit 10000" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --limit 10000" ``` ### Caso 2: Mantenimiento regular ```bash # Escaneo rápido y limpieza -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan" ``` ### Caso 3: Limpieza masiva después de migración de datos ```bash # 1. Análisis completo primero -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --dry-run" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --dry-run" # 2. Limpieza por lotes grandes -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --limit 50000" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --limit 50000" ``` ## Consideraciones de Seguridad @@ -126,10 +126,10 @@ docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_med Siempre haz un backup de tu directorio `/media/` antes de ejecutar eliminaciones masivas: ```bash # Backup del directorio media -docker exec EFC_backend_dev tar -czf /tmp/media_backup.tar.gz /app/media/ +docker exec backend tar -czf /tmp/media_backup.tar.gz /app/media/ # Copiar backup al host -docker cp EFC_backend_dev:/tmp/media_backup.tar.gz ./media_backup_$(date +%Y%m%d_%H%M%S).tar.gz +docker cp backend:/tmp/media_backup.tar.gz ./media_backup_$(date +%Y%m%d_%H%M%S).tar.gz ``` ### ✅ Buenas Prácticas @@ -149,19 +149,19 @@ docker cp EFC_backend_dev:/tmp/media_backup.tar.gz ./media_backup_$(date +%Y%m%d ### Error: "Too many open files" ```bash # Aumentar límite de archivos abiertos -docker exec -it EFC_backend_dev bash -c "ulimit -n 65536 && cd /app && python manage.py cleanup_media_fast --quick-scan" +docker exec -it backend bash -c "ulimit -n 65536 && cd /app && python manage.py cleanup_media_fast --quick-scan" ``` ### Proceso muy lento ```bash # Usar modo quick-scan en lugar de escaneo completo -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --dry-run" +docker exec -it backend bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan --dry-run" ``` ### Verificar que el comando existe ```bash # Listar comandos disponibles -docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py help" +docker exec -it backend bash -c "cd /app && python manage.py help" ``` ## Automatización @@ -169,7 +169,7 @@ docker exec -it EFC_backend_dev bash -c "cd /app && python manage.py help" Para automatizar la limpieza regular, puedes crear un cron job: ```bash # Ejecutar limpieza semanal los domingos a las 2 AM -0 2 * * 0 docker exec EFC_backend_dev bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan" >> /var/log/media_cleanup.log 2>&1 +0 2 * * 0 docker exec backend bash -c "cd /app && python manage.py cleanup_media_fast --quick-scan" >> /var/log/media_cleanup.log 2>&1 ``` ## Monitoreo @@ -177,8 +177,8 @@ Para automatizar la limpieza regular, puedes crear un cron job: Para monitorear el efecto de la limpieza: ```bash # Antes de limpiar -docker exec EFC_backend_dev du -sh /app/media/ +docker exec backend du -sh /app/media/ # Después de limpiar (verificar el cambio) -docker exec EFC_backend_dev du -sh /app/media/ +docker exec backend du -sh /app/media/ ``` \ No newline at end of file diff --git a/api/customs/tasks/auditoria.py b/api/customs/tasks/auditoria.py index 0ba713f..446471e 100644 --- a/api/customs/tasks/auditoria.py +++ b/api/customs/tasks/auditoria.py @@ -44,15 +44,17 @@ def auditar_procesamiento_remesas(organizacion_id): def auditar_partidas(organizacion_id): pedimentos = Pedimento.objects.filter(organizacion_id=organizacion_id) for pedimento in pedimentos: - partidas_descargadas = pedimento.documents.filter(document_type=1) + # 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 = [] + 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 + 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 @@ -87,30 +89,73 @@ def auditar_acuse_edocuments(organizacion_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)") - if pedimento.numero_partidas > pedimento.partidas.count(): - for i in range(1, pedimento.numero_partidas + 1): - from api.customs.models import Partida - Partida.objects.get_or_create( - pedimento=pedimento, - numero_partida=i, - organizacion_id=organizacion_id - ) + 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 - if pedimento.numero_partidas > pedimento.partidas.count(): - for i in range(1, pedimento.numero_partidas + 1): - from api.customs.models import Partida - Partida.objects.get_or_create( - pedimento=pedimento, - numero_partida=i, - organizacion_id=pedimento.organizacion_id - ) \ No newline at end of file + 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}") \ No newline at end of file