|
|
@@ -394,7 +394,7 @@ def api_ejecutar_recurrentes(request):
|
|
|
|
|
|
# Usar token dedicado para la API de informes
|
|
|
if token_enviado != settings.RECURRENTES_API_TOKEN:
|
|
|
- logger_info.warning('api_informe_cuenta_pdf: intento no autorizado', extra={'ip': request.META.get('REMOTE_ADDR'), 'cuenta_id': request.GET.get('cuenta_id')})
|
|
|
+ logger_info.warning('api_ejecutar_recurrentes: intento no autorizado', extra={'ip': request.META.get('REMOTE_ADDR'), 'cuenta_id': request.GET.get('cuenta_id')})
|
|
|
return JsonResponse({'error': 'No autorizado'}, status=403)
|
|
|
|
|
|
procesar_transacciones_recurrentes(hoy=now().date())
|
|
|
@@ -448,7 +448,7 @@ def informe_cuenta(request):
|
|
|
cuenta_id = request.GET.get('cuenta_id')
|
|
|
cuenta = get_object_or_404(Cuenta, id=cuenta_id)
|
|
|
|
|
|
- logger_info.info('api_informe_cuenta_pdf: petición aceptada', extra={'ip': request.META.get('REMOTE_ADDR'), 'cuenta_id': cuenta_id, 'usuario': getattr(request, 'user', None)})
|
|
|
+# logger_info.info('api_informe_cuenta_pdf: petición aceptada', extra={'ip': request.META.get('REMOTE_ADDR'), 'cuenta_id': cuenta_id, 'usuario': getattr(request, 'user', None)})
|
|
|
|
|
|
form = FiltroInformeCuentaForm(request.GET or None)
|
|
|
|
|
|
@@ -598,104 +598,6 @@ def informe_cuenta_pdf(request):
|
|
|
template = get_template('informe_cuenta_pdf.html')
|
|
|
html = template.render({'cuenta': cuenta, 'saldo_inicial': saldo_inicial, 'fecha_inicio': fecha_inicio_str, 'fecha_fin': fecha_fin_str, 'historial': historial})
|
|
|
|
|
|
- with tempfile.NamedTemporaryFile(delete=True) as output:
|
|
|
- HTML(string=html).write_pdf(output.name)
|
|
|
-
|
|
|
- output.seek(0)
|
|
|
- data = output.read()
|
|
|
- response = HttpResponse(data, content_type='application/pdf')
|
|
|
- filename = f'informe_{cuenta.nombre}.pdf'
|
|
|
- response['Content-Disposition'] = f'filename={filename}'
|
|
|
-
|
|
|
- logger_info.info('api_informe_cuenta_pdf: PDF generado', extra={'cuenta_id': cuenta_id, 'filename': filename, 'size_bytes': len(data)})
|
|
|
- return response
|
|
|
-
|
|
|
-
|
|
|
-@csrf_exempt
|
|
|
-def api_informe_cuenta_pdf(request):
|
|
|
- """API endpoint para generar PDF del informe de una cuenta.
|
|
|
-
|
|
|
- Parámetros GET esperados:
|
|
|
- - cuenta_id: id de la cuenta
|
|
|
- - fecha_inicio: YYYY-MM-DD (opcional)
|
|
|
- - fecha_fin: YYYY-MM-DD (opcional)
|
|
|
- También acepta header `X-API-KEY` o parámetro `token` para autenticación.
|
|
|
- """
|
|
|
- token_enviado = request.headers.get('X-API-KEY') or request.GET.get('token')
|
|
|
-
|
|
|
- if token_enviado != settings.RECURRENTES_API_TOKEN:
|
|
|
- return JsonResponse({'error': 'No autorizado'}, status=403)
|
|
|
-
|
|
|
- cuenta_id = request.GET.get('cuenta_id')
|
|
|
- if not cuenta_id:
|
|
|
- return JsonResponse({'error': 'Falta parámetro cuenta_id'}, status=400)
|
|
|
-
|
|
|
- cuenta = get_object_or_404(Cuenta, id=cuenta_id)
|
|
|
-
|
|
|
- # obtener fechas desde GET o establecer por defecto (mes actual)
|
|
|
- hoy = timezone.localtime()
|
|
|
- primer_dia = hoy.replace(day=1)
|
|
|
-
|
|
|
- fecha_inicio_str = request.GET.get('fecha_inicio')
|
|
|
- fecha_fin_str = request.GET.get('fecha_fin')
|
|
|
-
|
|
|
- if fecha_inicio_str and fecha_fin_str:
|
|
|
- fecha_inicio = datetime.strptime(fecha_inicio_str, '%Y-%m-%d').date()
|
|
|
- fecha_fin = datetime.strptime(fecha_fin_str, '%Y-%m-%d').date()
|
|
|
- else:
|
|
|
- fecha_inicio = primer_dia
|
|
|
- fecha_fin = hoy
|
|
|
-
|
|
|
- # Convertir a datetime aware para evitar warnings
|
|
|
- fecha_inicio_dt = timezone.make_aware(datetime.combine(fecha_inicio, time.min))
|
|
|
- fecha_fin_dt = timezone.make_aware(datetime.combine(fecha_fin, time.max))
|
|
|
-
|
|
|
- movimientos_previos = Movimiento.objects.filter(
|
|
|
- fecha__lt=fecha_inicio_dt,
|
|
|
- ).filter(
|
|
|
- cuenta_origen=cuenta
|
|
|
- ).aggregate(total_origen=Sum('monto')) or {'total_origen': 0}
|
|
|
-
|
|
|
- entradas_previas = Movimiento.objects.filter(
|
|
|
- fecha__lt=fecha_inicio_dt,
|
|
|
- ).filter(
|
|
|
- cuenta_destino=cuenta
|
|
|
- ).aggregate(total_destino=Sum('monto')) or {'total_destino': 0}
|
|
|
-
|
|
|
- saldo_inicial = (entradas_previas['total_destino'] or 0) - (movimientos_previos['total_origen'] or 0)
|
|
|
- saldo_inicial = saldo_inicial + cuenta.saldo_inicial
|
|
|
-
|
|
|
- movimientos = Movimiento.objects.filter(
|
|
|
- Q(cuenta_origen=cuenta) | Q(cuenta_destino=cuenta),
|
|
|
- fecha__range=(fecha_inicio_dt, fecha_fin_dt)
|
|
|
- ).order_by('fecha')
|
|
|
-
|
|
|
- saldo = saldo_inicial
|
|
|
- historial = []
|
|
|
-
|
|
|
- for mov in movimientos:
|
|
|
- if mov.cuenta_origen == cuenta:
|
|
|
- saldo -= mov.monto
|
|
|
- tipo = 'Gasto'
|
|
|
- elif mov.cuenta_destino == cuenta:
|
|
|
- saldo += mov.monto
|
|
|
- tipo = 'Ingreso'
|
|
|
- else:
|
|
|
- tipo = 'Otro'
|
|
|
-
|
|
|
- historial.append({
|
|
|
- 'fecha': mov.fecha,
|
|
|
- 'desde': mov.cuenta_origen.nombre if mov.cuenta_origen else 'N/A',
|
|
|
- 'hasta': mov.cuenta_destino.nombre if mov.cuenta_destino else 'N/A',
|
|
|
- 'descripcion': mov.descripcion,
|
|
|
- 'monto': mov.monto,
|
|
|
- 'tipo': tipo,
|
|
|
- 'saldo_despues': saldo,
|
|
|
- })
|
|
|
-
|
|
|
- template = get_template('informe_cuenta_pdf.html')
|
|
|
- html = template.render({'cuenta': cuenta, 'saldo_inicial': saldo_inicial, 'fecha_inicio': fecha_inicio_str, 'fecha_fin': fecha_fin_str, 'historial': historial})
|
|
|
-
|
|
|
with tempfile.NamedTemporaryFile(delete=True) as output:
|
|
|
HTML(string=html).write_pdf(output.name)
|
|
|
|