265 lines
12 KiB
Python
265 lines
12 KiB
Python
from celery import shared_task
|
|
from django.core.files.base import ContentFile
|
|
from django.utils import timezone
|
|
from api.reports.models import ReportDocument
|
|
from api.customs.models import Pedimento, Cove, EDocument, Partida
|
|
from django.db.models import Q, Exists, OuterRef
|
|
# from django.db.models import Q,
|
|
from api.record.models import Document
|
|
import csv
|
|
import os
|
|
from django.conf import settings
|
|
import logging
|
|
|
|
logger = logging.getLogger()
|
|
|
|
@shared_task
|
|
def generate_report_document(report_id):
|
|
try:
|
|
report = ReportDocument.objects.get(id=report_id)
|
|
report.status = 'processing'
|
|
report.save(update_fields=['status'])
|
|
filters = report.filters or {}
|
|
pedimentos_filters = Q()
|
|
if filters.get('organizacion_id'):
|
|
pedimentos_filters &= Q(organizacion_id=filters['organizacion_id'])
|
|
if filters.get('fecha_pago__gte'):
|
|
pedimentos_filters &= Q(fecha_pago__gte=filters['fecha_pago__gte'])
|
|
if filters.get('fecha_pago__lte'):
|
|
pedimentos_filters &= Q(fecha_pago__lte=filters['fecha_pago__lte'])
|
|
if filters.get('contribuyente__rfc'):
|
|
pedimentos_filters &= Q(contribuyente__rfc=filters['contribuyente__rfc'])
|
|
if filters.get('patente'):
|
|
pedimentos_filters &= Q(patente=filters['patente'])
|
|
if filters.get('aduana'):
|
|
pedimentos_filters &= Q(aduana=filters['aduana'])
|
|
if filters.get('pedimento'):
|
|
pedimentos_filters &= Q(pedimento=filters['pedimento'])
|
|
if filters.get('pedimento_app'):
|
|
pedimentos_filters &= Q(pedimento_app=filters['pedimento_app'])
|
|
if filters.get('regimen'):
|
|
pedimentos_filters &= Q(regimen=filters['regimen'])
|
|
if filters.get('tipo_operacion'):
|
|
pedimentos_filters &= Q(tipo_operacion_id=filters['tipo_operacion'])
|
|
# Consulta asíncrona de los modelos
|
|
pedimentos = Pedimento.objects.filter(pedimentos_filters)
|
|
filename = filters.get('filename')
|
|
if filename:
|
|
filename = f"{filename}.csv" if not filename.endswith('.csv') else filename
|
|
else:
|
|
filename = f"report_{report.id}_{timezone.now().strftime('%Y%m%d%H%M%S')}.csv"
|
|
file_path = os.path.join(settings.MEDIA_ROOT, 'reports', filename)
|
|
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
with open(file_path, 'w', newline='', encoding='utf-8') as f:
|
|
writer = csv.writer(f)
|
|
headers = [
|
|
'aduana', 'patente', 'regimen', 'pedimento', 'pedimento_app', 'clave_pedimento',
|
|
'tipo_operacion_id', 'contribuyente_id', 'tipo_documento', 'numero_documento', 'estado', 'acuse_estado'
|
|
]
|
|
writer.writerow(headers)
|
|
for ped in pedimentos:
|
|
for cove in Cove.objects.filter(pedimento=ped):
|
|
writer.writerow([
|
|
ped.aduana, ped.patente, ped.regimen, ped.pedimento, ped.pedimento_app,
|
|
ped.clave_pedimento, ped.tipo_operacion_id, ped.contribuyente_id,
|
|
'COVE', cove.numero_cove, cove.cove_descargado, cove.acuse_cove_descargado
|
|
])
|
|
for edoc in EDocument.objects.filter(pedimento=ped):
|
|
writer.writerow([
|
|
ped.aduana, ped.patente, ped.regimen, ped.pedimento, ped.pedimento_app,
|
|
ped.clave_pedimento, ped.tipo_operacion_id, ped.contribuyente_id,
|
|
'EDOC', edoc.numero_edocument, edoc.edocument_descargado, edoc.acuse_descargado
|
|
])
|
|
for partida in Partida.objects.filter(pedimento=ped):
|
|
writer.writerow([
|
|
ped.aduana, ped.patente, ped.regimen, ped.pedimento, ped.pedimento_app,
|
|
ped.clave_pedimento, ped.tipo_operacion_id, ped.contribuyente_id,
|
|
'PARTIDA', partida.numero_partida, partida.descargado, ''
|
|
])
|
|
# Guardar el archivo en el modelo
|
|
with open(file_path, 'rb') as f:
|
|
report.file.save(filename, ContentFile(f.read()), save=True)
|
|
report.status = 'ready'
|
|
report.finished_at = timezone.now()
|
|
report.save(update_fields=['status', 'file', 'finished_at'])
|
|
except Exception as e:
|
|
report.status = 'error'
|
|
report.error_message = str(e)
|
|
report.finished_at = timezone.now()
|
|
report.save(update_fields=['status', 'error_message', 'finished_at'])
|
|
|
|
@shared_task
|
|
def generate_report_control_pedimento(report_id):
|
|
try:
|
|
logger.info(f"🔴🔴🔴 INICIANDO TAREA para control de pedimento {report_id}")
|
|
report = ReportDocument.objects.get(id=report_id)
|
|
report.status = 'processing'
|
|
report.save(update_fields=['status'])
|
|
filters = report.filters or {}
|
|
logger.info(f"🔴🔴🔴 FILTROS: {filters}")
|
|
|
|
# Construir filtros
|
|
pedimentos_filters = {}
|
|
if filters.get('organizacion_id'):
|
|
pedimentos_filters['organizacion_id'] = filters['organizacion_id']
|
|
if filters.get('fecha_pago__gte'):
|
|
pedimentos_filters['fecha_pago__gte'] = filters['fecha_pago__gte']
|
|
if filters.get('fecha_pago__lte'):
|
|
pedimentos_filters['fecha_pago__lte'] = filters['fecha_pago__lte']
|
|
if filters.get('pedimento_app'):
|
|
pedimentos_filters['pedimento_app'] = filters['pedimento_app']
|
|
|
|
# pedimentos por organizacion
|
|
pedimentos_qs = Pedimento.objects.filter(**pedimentos_filters)
|
|
pedimentos_total = pedimentos_qs.count()
|
|
logger.info(f'🔴🔴🔴 PEDIMENTOS ENCONTRADOS: {pedimentos_total}')
|
|
|
|
pedimento_ids = list(pedimentos_qs.values_list('id', flat=True))
|
|
|
|
# inicializar totales
|
|
pedimentos_completos = 0
|
|
total_documentos = 0
|
|
documentos_sin_descargar = 0
|
|
|
|
# Para cada pedimento, verificar si está completo
|
|
for pedimento in pedimentos_qs:
|
|
# Contar documentos de este pedimento
|
|
docs_pedimento = 0
|
|
docs_pendientes_pedimento = 0
|
|
|
|
# COVES
|
|
coves_count = Cove.objects.filter(pedimento_id=pedimento.id).count()
|
|
coves_pendientes = Cove.objects.filter(pedimento_id=pedimento.id, cove_descargado=False).count()
|
|
docs_pedimento += coves_count
|
|
docs_pendientes_pedimento += coves_pendientes
|
|
|
|
# PARTIDAS
|
|
partidas_count = Partida.objects.filter(pedimento_id=pedimento.id).count()
|
|
partidas_pendientes = Partida.objects.filter(pedimento_id=pedimento.id, descargado=False).count()
|
|
docs_pedimento += partidas_count
|
|
docs_pendientes_pedimento += partidas_pendientes
|
|
|
|
# EDOCUMENTS
|
|
edocs_count = EDocument.objects.filter(pedimento_id=pedimento.id).count()
|
|
edocs_pendientes = EDocument.objects.filter(pedimento_id=pedimento.id, edocument_descargado=False).count()
|
|
docs_pedimento += edocs_count
|
|
docs_pendientes_pedimento += edocs_pendientes
|
|
|
|
# Acumular totales
|
|
total_documentos += docs_pedimento
|
|
documentos_sin_descargar += docs_pendientes_pedimento
|
|
|
|
# Si no tiene documentos pendientes, está completo
|
|
if docs_pendientes_pedimento == 0 and docs_pedimento > 0:
|
|
pedimentos_completos += 1
|
|
|
|
# 3. PORCENTAJE
|
|
porcentaje_faltantes = (documentos_sin_descargar / total_documentos * 100) if total_documentos > 0 else 0
|
|
|
|
# 4. GENERAR CSV CON DETALLES
|
|
filename = f"report_{report.id}_{timezone.now().strftime('%Y%m%d%H%M%S')}.csv"
|
|
file_path = os.path.join(settings.MEDIA_ROOT, 'reports', filename)
|
|
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
|
|
todas_las_filas = []
|
|
|
|
# Recopilar datos detallados - UNA FILA POR CADA DOCUMENTO
|
|
for pedimento in pedimentos_qs:
|
|
# DATOS BASE DEL PEDIMENTO (se repiten en cada fila)
|
|
datos_base_pedimento = [
|
|
pedimento.aduana or '',
|
|
pedimento.patente or '',
|
|
pedimento.regimen or '',
|
|
pedimento.pedimento or '', # No. Pedimento (7 dígitos)
|
|
pedimento.pedimento_app or '', # No. Pedimento App completo
|
|
pedimento.clave_pedimento or '',
|
|
pedimento.tipo_operacion.tipo if pedimento.tipo_operacion else '',
|
|
str(pedimento.contribuyente_id) if pedimento.contribuyente_id else ''
|
|
]
|
|
|
|
# COVES - Una fila por cada COVE
|
|
coves = Cove.objects.filter(pedimento_id=pedimento.id)
|
|
for cove in coves:
|
|
estado = 'VERDADERO' if cove.cove_descargado else 'FALSO'
|
|
fila = datos_base_pedimento + [
|
|
# str(cove.id), # Identificador de documento
|
|
cove.numero_cove,
|
|
'COVE', # Tipo de documento
|
|
estado
|
|
]
|
|
todas_las_filas.append(fila)
|
|
|
|
# PARTIDAS - Una fila por cada Partida
|
|
partidas = Partida.objects.filter(pedimento_id=pedimento.id)
|
|
for partida in partidas:
|
|
estado = 'VERDADERO' if partida.descargado else 'FALSO'
|
|
fila = datos_base_pedimento + [
|
|
# str(partida.id),
|
|
partida.numero_partida,
|
|
'PARTIDA', # Tipo de documento
|
|
estado
|
|
]
|
|
todas_las_filas.append(fila)
|
|
|
|
# EDOCUMENTS - Una fila por cada EDocument
|
|
edocuments = EDocument.objects.filter(pedimento_id=pedimento.id)
|
|
for edoc in edocuments:
|
|
estado = 'VERDADERO' if edoc.edocument_descargado else 'FALSO'
|
|
fila = datos_base_pedimento + [
|
|
# str(edoc.id),
|
|
edoc.numero_edocument,
|
|
'EDOCUMENT', # Tipo de documento
|
|
estado
|
|
]
|
|
todas_las_filas.append(fila)
|
|
|
|
# 5. ESCRIBIR ARCHIVO CSV
|
|
with open(file_path, 'w', newline='', encoding='utf-8') as f:
|
|
writer = csv.writer(f)
|
|
|
|
# SECCIÓN DE TOTALES
|
|
writer.writerow(['RESUMEN DEL REPORTE - CONTROL DE PEDIMENTOS'])
|
|
writer.writerow([])
|
|
writer.writerow(['TOTAL DE EXPEDIENTES:', pedimentos_total])
|
|
writer.writerow(['TOTAL DE EXPEDIENTES COMPLETOS:', pedimentos_completos])
|
|
writer.writerow(['TOTAL DE DOCUMENTOS:', total_documentos])
|
|
writer.writerow(['DOCUMENTOS SIN DESCARGAR:', documentos_sin_descargar])
|
|
writer.writerow(['PORCENTAJE DE DOCUMENTOS FALTANTES (%):', f"{porcentaje_faltantes:.2f}%"])
|
|
writer.writerow([])
|
|
writer.writerow([])
|
|
|
|
# ENCABEZADOS DE DATOS (según requerimiento)
|
|
headers = [
|
|
'ADUANA', 'PATENTE', 'REGIMEN', 'NO. PEDIMENTO', 'PEDIMENTO_APP',
|
|
'CLAVE_PEDIMENTO', 'TIPO_OPERACION', 'CONTRIBUYENTE_ID',
|
|
'IDENTIFICADOR_DOCUMENTO', 'TIPO_DOCUMENTO', 'ESTADO'
|
|
]
|
|
writer.writerow(headers)
|
|
|
|
# DATOS DETALLADOS
|
|
for fila in todas_las_filas:
|
|
writer.writerow(fila)
|
|
|
|
# 6. LOGS Y GUARDAR
|
|
logger.info(f"📊 REPORTE FINAL:")
|
|
logger.info(f" - Expedientes: {pedimentos_total}")
|
|
logger.info(f" - Expedientes completos: {pedimentos_completos}")
|
|
logger.info(f" - Total documentos: {total_documentos}")
|
|
logger.info(f" - Documentos sin descargar: {documentos_sin_descargar}")
|
|
logger.info(f" - Porcentaje faltantes: {porcentaje_faltantes:.2f}%")
|
|
|
|
with open(file_path, 'rb') as f:
|
|
report.file.save(filename, ContentFile(f.read()), save=True)
|
|
|
|
report.status = 'ready'
|
|
report.finished_at = timezone.now()
|
|
report.save(update_fields=['status', 'file', 'finished_at'])
|
|
|
|
logger.info(f"✅ REPORTE GENERADO EXITOSAMENTE: {filename}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"❌ ERROR en generate_report_control_pedimento: {str(e)}", exc_info=True)
|
|
report.status = 'error'
|
|
report.error_message = str(e)
|
|
report.finished_at = timezone.now()
|
|
report.save(update_fields=['status', 'error_message', 'finished_at']) |