Files
backend/api/reports/views_table.py
2025-10-20 21:14:31 -06:00

211 lines
8.7 KiB
Python

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from django.db.models import Value, CharField, Q, Exists, OuterRef, Subquery
from django.db.models.functions import Cast
from datetime import datetime, timedelta
from api.customs.models import Pedimento, Cove, EDocument, Partida
class CustomPagination(PageNumberPagination):
page_size = 50
page_size_query_param = 'page_size'
max_page_size = 1000
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def table_summary(request):
# ...existing code...
# Si se solicita CSV, generar archivo y devolverlo (después de definir pedimentos_filters)
my_tags = ['Reportes']
"""
Endpoint que devuelve un resumen tabulado de pedimentos y sus documentos asociados.
"""
org_id = request.query_params.get('organizacion_id')
if not org_id:
return Response({"error": "organizacion_id es requerido"}, status=400)
# Obtener filtros de query params
tipo_documento = request.query_params.get('tipo_documento')
rfc = request.query_params.get('contribuyente__rfc')
fecha_pago_gte = request.query_params.get('fecha_pago__gte')
fecha_pago_lte = request.query_params.get('fecha_pago__lte')
patente = request.query_params.get('patente')
aduana = request.query_params.get('aduana')
pedimento = request.query_params.get('pedimento')
pedimento_app = request.query_params.get('pedimento_app')
regimen = request.query_params.get('regimen')
tipo_operacion = request.query_params.get('tipo_operacion')
# Si no se proporcionan fechas, establecer un rango por defecto de los últimos 30 días
if not fecha_pago_gte and not fecha_pago_lte:
fecha_pago_lte = datetime.now().date()
fecha_pago_gte = fecha_pago_lte - timedelta(days=30)
# Construir filtros base para pedimentos
pedimentos_filters = Q()
pedimentos_filters &= Q(organizacion_id=org_id)
if fecha_pago_gte:
pedimentos_filters &= Q(fecha_pago__gte=fecha_pago_gte)
if fecha_pago_lte:
pedimentos_filters &= Q(fecha_pago__lte=fecha_pago_lte)
if rfc:
pedimentos_filters &= Q(contribuyente__rfc=rfc)
if patente:
pedimentos_filters &= Q(patente=patente)
if aduana:
pedimentos_filters &= Q(aduana=aduana)
if pedimento:
pedimentos_filters &= Q(pedimento=pedimento)
if pedimento_app:
pedimentos_filters &= Q(pedimento_app=pedimento_app)
if regimen:
pedimentos_filters &= Q(regimen=regimen)
if tipo_operacion:
pedimentos_filters &= Q(tipo_operacion_id=tipo_operacion)
# Si se solicita los últimos 100 registros actualizados
if request.query_params.get('ultimos') == '1':
pedimentos = Pedimento.objects.filter(pedimentos_filters).order_by('-updated_at')[:100]
else:
pedimentos = Pedimento.objects.filter(pedimentos_filters)
# Serializar pedimentos con documentos relacionados
results = []
for ped in pedimentos:
ped_dict = {
'aduana': ped.aduana,
'patente': ped.patente,
'regimen': ped.regimen,
'pedimento': ped.pedimento,
'pedimento_app': ped.pedimento_app,
'clave_pedimento': ped.clave_pedimento,
'tipo_operacion_id': ped.tipo_operacion_id,
'contribuyente_id': ped.contribuyente_id,
'documentos': []
}
# COVEs
for cove in Cove.objects.filter(pedimento=ped):
ped_dict['documentos'].append({
'tipo': 'COVE',
'numero': cove.numero_cove,
'estado': cove.cove_descargado,
'acuse_estado': cove.acuse_cove_descargado
})
# EDOCs
for edoc in EDocument.objects.filter(pedimento=ped):
ped_dict['documentos'].append({
'tipo': 'EDOC',
'numero': edoc.numero_edocument,
'estado': edoc.edocument_descargado,
'acuse_estado': edoc.acuse_descargado,
})
# PARTIDAS
for partida in Partida.objects.filter(pedimento=ped):
ped_dict['documentos'].append({
'tipo': 'PARTIDA',
'numero': partida.numero_partida,
'estado': partida.descargado
})
results.append(ped_dict)
if request.query_params.get('csv') == '1':
import csv
from django.http import HttpResponse
headers = [
'aduana', 'patente', 'regimen', 'pedimento', 'pedimento_app', 'clave_pedimento',
'tipo_operacion_id', 'contribuyente_id', 'tipo_documento', 'numero_documento', 'estado', 'acuse_estado'
]
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=table_summary.csv'
writer = csv.writer(response)
writer.writerow(headers)
# Llenar filas
if request.query_params.get('ultimos') == '1':
pedimentos = Pedimento.objects.filter(pedimentos_filters).order_by('-updated_at')[:100]
else:
pedimentos = Pedimento.objects.filter(pedimentos_filters)
for ped in pedimentos:
# COVEs
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
])
# EDOCs
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
])
# PARTIDAS
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, ''
])
return response
# Si se solicita Excel, generar archivo y devolverlo
if request.query_params.get('excel') == '1':
import openpyxl
from openpyxl.utils import get_column_letter
from django.http import HttpResponse
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Resumen"
# Encabezados
headers = [
'aduana', 'patente', 'regimen', 'pedimento', 'pedimento_app', 'clave_pedimento',
'tipo_operacion_id', 'contribuyente_id', 'tipo_documento', 'numero_documento', 'estado', 'acuse_estado'
]
ws.append(headers)
# Llenar filas
for ped in results:
for doc in ped['documentos']:
ws.append([
ped['aduana'], ped['patente'], ped['regimen'], ped['pedimento'], ped['pedimento_app'],
ped['clave_pedimento'], ped['tipo_operacion_id'], ped['contribuyente_id'],
doc.get('tipo'), doc.get('numero'), doc.get('estado'), doc.get('acuse_estado')
])
# Ajustar ancho de columnas
for i, col in enumerate(headers, 1):
ws.column_dimensions[get_column_letter(i)].width = max(12, len(col) + 2)
# Guardar en memoria y devolver como respuesta
from io import BytesIO
output = BytesIO()
wb.save(output)
output.seek(0)
response = HttpResponse(
output.read(),
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
response['Content-Disposition'] = 'attachment; filename=table_summary.xlsx'
return response
# Aplicar paginación manual sobre results
paginator = CustomPagination()
page = paginator.paginate_queryset(results, request)
return paginator.get_paginated_response({
"results": page,
"filtros_aplicados": {
"organizacion_id": org_id,
"tipo_documento": tipo_documento,
"contribuyente__rfc": rfc,
"fecha_pago__gte": fecha_pago_gte,
"fecha_pago__lte": fecha_pago_lte,
"patente": patente,
"aduana": aduana,
"pedimento": pedimento,
"pedimento_app": pedimento_app,
"regimen": regimen,
"tipo_operacion": tipo_operacion
}
})