T2026-05-030

This commit is contained in:
Dulce
2026-05-18 11:51:30 -06:00
parent 63f051c566
commit 3a636c14ae
9 changed files with 825 additions and 383 deletions

View File

@@ -6,6 +6,8 @@ from api.customs.models import ProcesamientoPedimento, Pedimento, Cove, EDocumen
from core.utils import xml_controller
import requests
from core.utils import xml_remesas_controller
import logging
logger = logging.getLogger(__name__)
def obtener_pedimentos(organizacion_id):
return Pedimento.objects.filter(organizacion_id=organizacion_id)
@@ -35,23 +37,31 @@ def auditor_descargas(pedimento, servicio, related_name, variable, mensaje):
pedimento_id = pedimento.id
docs = getattr(pedimento, related_name).all()
print(f"pedimento: {pedimento}, servicio: {servicio}, related_name: {related_name}, variable: {variable}, mensaje: {mensaje}")
logger.info(f"pedimento: {pedimento}, servicio: {servicio}, related_name: {related_name}, variable: {variable}, mensaje: {mensaje}")
# 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.")
logger.info(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.")
logger.info(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.")
logger.info(f"✗ Pedimento {pedimento_id} NO tiene todos sus {mensaje} descargados.")
if proceso:
print(f"✓ Proceso de auditoría para pedimento {pedimento_id} completado.")
logger.info(f"✓ Proceso de auditoría para pedimento {pedimento_id} completado.")
else:
print(f"✗ No se encontró proceso de auditoría para pedimento {pedimento_id}.")
logger.info(f"✗ No se encontró proceso de auditoría para pedimento {pedimento_id}.")
## Auditar pedimentos
@@ -121,44 +131,66 @@ def auditar_procesamiento_remesa_por_pedimento(pedimento_id):
@shared_task
def crear_partidas(organizacion_id):
from api.customs.models import Partida
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}")
completados = []
con_pendientes = []
sin_datos = []
errores = []
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)")
try:
if not pedimento.numero_partidas or pedimento.numero_partidas <= 0:
sin_datos.append({
'pedimento_id': str(pedimento.id),
'pedimento': pedimento.pedimento,
'razon': f'numero_partidas inválido ({pedimento.numero_partidas})',
})
continue
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}")
for i in range(1, pedimento.numero_partidas + 1):
Partida.objects.get_or_create(
pedimento=pedimento,
numero_partida=i,
defaults={'organizacion_id': organizacion_id}
)
partidas = list(pedimento.partidas.order_by('numero_partida'))
no_descargadas = [p.numero_partida for p in partidas if not p.descargado]
if not no_descargadas:
completados.append(str(pedimento.id))
else:
con_pendientes.append({
'pedimento_id': str(pedimento.id),
'pedimento': pedimento.pedimento,
'total_partidas': len(partidas),
'descargadas': len(partidas) - len(no_descargadas),
'no_descargadas': no_descargadas,
})
except Exception as e:
errores.append({
'pedimento_id': str(pedimento.id),
'pedimento': pedimento.pedimento,
'error': str(e),
})
logger.error(f"Error creando partidas para pedimento {pedimento.id}: {e}")
return {
'organizacion_id': str(organizacion_id),
'total_pedimentos': total_pedimentos,
'completados': len(completados),
'con_pendientes': len(con_pendientes),
'sin_datos': len(sin_datos),
'con_errores': len(errores),
'detalle_pendientes': con_pendientes,
'detalle_sin_datos': sin_datos,
'detalle_errores': errores,
}
@shared_task
def crear_partidas_por_pedimento(pedimento_id):
@@ -169,6 +201,7 @@ def crear_partidas_por_pedimento(pedimento_id):
return
print(f"Procesando pedimento individual {pedimento_id}...")
logger.info(f"Procesando pedimento individual {pedimento_id}...")
partidas_agregadas = 0
# Validar que numero_partidas no sea None y sea mayor que 0
@@ -176,6 +209,7 @@ def crear_partidas_por_pedimento(pedimento_id):
partidas_existentes = pedimento.partidas.count()
if pedimento.numero_partidas > partidas_existentes:
print(f"Pedimento {pedimento_id} - Partidas existentes: {partidas_existentes}, Requeridas: {pedimento.numero_partidas}")
logger.info(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
@@ -188,62 +222,165 @@ def crear_partidas_por_pedimento(pedimento_id):
partidas_agregadas += 1
print(f"✓ Partidas agregadas para pedimento {pedimento_id}: {partidas_agregadas}")
logger.info(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})")
logger.info(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}")
logger.info(f"Error: Pedimento {pedimento_id} tiene numero_partidas inválido: {pedimento.numero_partidas}")
# Auditar coves
def _auditar_organizacion(organizacion_id, servicio, related_name, variable, label):
"""
Itera todos los pedimentos de una organización auditando el campo `variable`
en la relación `related_name`. Retorna un resumen estructurado por pedimento.
"""
pedimentos = obtener_pedimentos(organizacion_id)
total_pedimentos = pedimentos.count()
completados = []
pendientes = []
errores = []
for pedimento in pedimentos:
try:
docs = list(getattr(pedimento, related_name).all())
total = len(docs)
faltantes = [
getattr(doc, 'numero_cove', None) or getattr(doc, 'numero_edocument', None)
for doc in docs if not getattr(doc, variable)
]
if total == 0 or len(faltantes) == 0:
nuevo_estado = 3
completados.append(str(pedimento.id))
else:
nuevo_estado = 4
pendientes.append({
'pedimento_id': str(pedimento.id),
'pedimento': pedimento.pedimento,
f'faltantes_{label}': faltantes,
'total': total,
'descargados': total - len(faltantes),
})
modificar_estado_procesamiento(pedimento, servicio_id=servicio, nuevo_estado=nuevo_estado)
except Exception as e:
errores.append({
'pedimento_id': str(pedimento.id),
'pedimento': pedimento.pedimento,
'error': str(e),
})
logger.error(f"Error auditando pedimento {pedimento.id} [{label}]: {e}")
return {
'organizacion_id': str(organizacion_id),
'auditoria': label,
'total_pedimentos': total_pedimentos,
'completados': len(completados),
'con_pendientes': len(pendientes),
'con_errores': len(errores),
'detalle_pendientes': pendientes,
'detalle_errores': errores,
}
@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'
)
return _auditar_organizacion(
organizacion_id,
servicio=8,
related_name='coves',
variable='cove_descargado',
label='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'
)
return _auditar_organizacion(
organizacion_id,
servicio=9,
related_name='coves',
variable='acuse_cove_descargado',
label='acuse_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'
)
return _auditar_organizacion(
organizacion_id,
servicio=7,
related_name='documentos',
variable='edocument_descargado',
label='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'
)
return _auditar_organizacion(
organizacion_id,
servicio=6,
related_name='documentos',
variable='acuse_descargado',
label='acuse',
)
@shared_task
def auditar_remesas(organizacion_id):
"""
Audita el estado de descarga de remesas para todos los pedimentos de una organización.
A diferencia de coves/edocuments, las remesas no tienen campo booleano propio —
se verifica la existencia de un documento de tipo 3 (Remesa) en el pedimento.
"""
pedimentos = obtener_pedimentos(organizacion_id)
total_pedimentos = pedimentos.count()
completados = []
pendientes = []
errores = []
for pedimento in pedimentos:
try:
if not pedimento.remesas:
# El pedimento no declara remesas — no aplica, marcar como completado
modificar_estado_procesamiento(pedimento, servicio_id=5, nuevo_estado=3)
completados.append(str(pedimento.id))
elif pedimento.documents.filter(document_type=3).exists():
# Documento de remesa ya descargado
modificar_estado_procesamiento(pedimento, servicio_id=5, nuevo_estado=3)
completados.append(str(pedimento.id))
else:
# Tiene remesas declaradas pero el documento aún no existe
modificar_estado_procesamiento(pedimento, servicio_id=5, nuevo_estado=4)
pendientes.append({
'pedimento_id': str(pedimento.id),
'pedimento': pedimento.pedimento,
})
except Exception as e:
errores.append({
'pedimento_id': str(pedimento.id),
'pedimento': pedimento.pedimento,
'error': str(e),
})
logger.error(f"Error auditando remesa de pedimento {pedimento.id}: {e}")
return {
'organizacion_id': str(organizacion_id),
'auditoria': 'remesa',
'total_pedimentos': total_pedimentos,
'completados': len(completados),
'con_pendientes': len(pendientes),
'con_errores': len(errores),
'detalle_pendientes': pendientes,
'detalle_errores': errores,
}
@shared_task
def auditar_cove_por_pedimento(pedimento_id):
try:
print(f"auditar_cove_por_pedimento >>>> {pedimento_id}")
logger.info(f"auditar_cove_por_pedimento >>>> {pedimento_id}")
from api.customs.models import Pedimento
pedimento = Pedimento.objects.get(id=pedimento_id)
auditor_descargas(