|
@@ -345,151 +345,6 @@ def listar_categorias(request):
|
|
|
'fecha_inicio': fecha_inicio,
|
|
'fecha_inicio': fecha_inicio,
|
|
|
'fecha_fin': fecha_fin})
|
|
'fecha_fin': fecha_fin})
|
|
|
|
|
|
|
|
-@login_required
|
|
|
|
|
-def informe_categoria(request):
|
|
|
|
|
- categoria_id = request.GET.get('categoria_id')
|
|
|
|
|
-
|
|
|
|
|
- categoria = get_object_or_404(Categoria, id=categoria_id)
|
|
|
|
|
-
|
|
|
|
|
- form = FiltroInformeCuentaForm(request.GET or None)
|
|
|
|
|
-
|
|
|
|
|
- if form.is_valid():
|
|
|
|
|
- # 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 = Movimiento.objects.filter(
|
|
|
|
|
- fecha__lt=fecha_inicio_dt,
|
|
|
|
|
- ).filter(
|
|
|
|
|
- categoria=categoria
|
|
|
|
|
- ).aggregate(total=Sum('monto'))
|
|
|
|
|
-
|
|
|
|
|
- saldo_inicial = movimientos['total'] or 0
|
|
|
|
|
-
|
|
|
|
|
- logger.info(f"informe_categoria: categoría: {categoria.nombre} / fecha_inicio: {fecha_inicio_str} / fecha_fin: {fecha_fin_str} / saldo_inicial: {saldo_inicial}")
|
|
|
|
|
-
|
|
|
|
|
- movimientos_con_saldo = []
|
|
|
|
|
- saldo_acumulado = saldo_inicial
|
|
|
|
|
- for mov in movimientos:
|
|
|
|
|
- if mov.tipo == 'Ingreso':
|
|
|
|
|
- saldo_acumulado += mov.monto
|
|
|
|
|
- else:
|
|
|
|
|
- saldo_acumulado -= mov.monto
|
|
|
|
|
-
|
|
|
|
|
- movimientos_con_saldo.append({
|
|
|
|
|
- 'movimiento': mov,
|
|
|
|
|
- 'saldo_acumulado': saldo_acumulado
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- logger.info(f"informe_categoria: movimientos_con_saldo: {[{'id': m['movimiento'].id, 'saldo_acumulado': m['saldo_acumulado']} for m in movimientos_con_saldo]}")
|
|
|
|
|
-
|
|
|
|
|
- context = {
|
|
|
|
|
- 'categoria': categoria,
|
|
|
|
|
- 'movimientos_con_saldo': movimientos_con_saldo,
|
|
|
|
|
- 'fecha_inicio': fecha_inicio_str,
|
|
|
|
|
- 'fecha_fin': fecha_fin_str,
|
|
|
|
|
- 'saldo_inicial': saldo_inicial
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return render(request, 'informe_categoria.html', context)
|
|
|
|
|
-
|
|
|
|
|
-@login_required
|
|
|
|
|
-def informe_categoria_pdf(request):
|
|
|
|
|
- categoria_id = request.GET.get('categoria_id')
|
|
|
|
|
-
|
|
|
|
|
- categoria = get_object_or_404(Categoria, id=categoria_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 = Movimiento.objects.filter(
|
|
|
|
|
- categoria=categoria,
|
|
|
|
|
- usuario=request.user,
|
|
|
|
|
- fecha__range=(fecha_inicio_dt, fecha_fin_dt)
|
|
|
|
|
- ).order_by('fecha')
|
|
|
|
|
-
|
|
|
|
|
- template = get_template('informe_categoria_pdf.html')
|
|
|
|
|
- html = template.render({'categoria': categoria, 'fecha_inicio': fecha_inicio_str, 'fecha_fin': fecha_fin_str, 'movimientos': movimientos})
|
|
|
|
|
-
|
|
|
|
|
- with tempfile.NamedTemporaryFile(delete=True) as output:
|
|
|
|
|
- HTML(string=html).write_pdf(output.name)
|
|
|
|
|
-
|
|
|
|
|
- output.seek(0)
|
|
|
|
|
- response = HttpResponse(output.read(), content_type='application/pdf')
|
|
|
|
|
- response['Content-Disposition'] = f'filename=informe_{categoria.nombre}.pdf'
|
|
|
|
|
- return response
|
|
|
|
|
-
|
|
|
|
|
-@login_required
|
|
|
|
|
-def informe_categoria(request):
|
|
|
|
|
- categoria_id = request.GET.get('categoria_id')
|
|
|
|
|
-
|
|
|
|
|
- categoria = get_object_or_404(Categoria, id=categoria_id)
|
|
|
|
|
-
|
|
|
|
|
- form = FiltroInformeCuentaForm(request.GET or None)
|
|
|
|
|
-
|
|
|
|
|
- if form.is_valid():
|
|
|
|
|
- # 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 = Movimiento.objects.filter(
|
|
|
|
|
- categoria=categoria,
|
|
|
|
|
- usuario=request.user,
|
|
|
|
|
- fecha__range=(fecha_inicio_dt, fecha_fin_dt)
|
|
|
|
|
- ).order_by('fecha')
|
|
|
|
|
-
|
|
|
|
|
- context = {
|
|
|
|
|
- 'categoria': categoria,
|
|
|
|
|
- 'movimientos': movimientos,
|
|
|
|
|
- 'fecha_inicio': fecha_inicio_str,
|
|
|
|
|
- 'fecha_fin': fecha_fin_str,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return render(request, 'informe_categoria.html', context)
|
|
|
|
|
-
|
|
|
|
|
# API
|
|
# API
|
|
|
|
|
|
|
|
|
|
|
|
@@ -777,3 +632,106 @@ def informe_cuenta_pdf(request):
|
|
|
response = HttpResponse(output.read(), content_type='application/pdf')
|
|
response = HttpResponse(output.read(), content_type='application/pdf')
|
|
|
response['Content-Disposition'] = f'filename=informe_{cuenta.nombre}.pdf'
|
|
response['Content-Disposition'] = f'filename=informe_{cuenta.nombre}.pdf'
|
|
|
return response
|
|
return response
|
|
|
|
|
+
|
|
|
|
|
+@login_required
|
|
|
|
|
+def informe_categoria(request):
|
|
|
|
|
+ categoria_id = request.GET.get('categoria_id')
|
|
|
|
|
+
|
|
|
|
|
+ categoria = get_object_or_404(Categoria, id=categoria_id)
|
|
|
|
|
+
|
|
|
|
|
+ form = FiltroInformeCuentaForm(request.GET or None)
|
|
|
|
|
+
|
|
|
|
|
+ if form.is_valid():
|
|
|
|
|
+ # 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 = Movimiento.objects.filter(
|
|
|
|
|
+ fecha__lt=fecha_inicio_dt,
|
|
|
|
|
+ ).filter(
|
|
|
|
|
+ categoria=categoria
|
|
|
|
|
+ ).aggregate(total=Sum('monto'))
|
|
|
|
|
+
|
|
|
|
|
+ saldo_inicial = movimientos['total'] or 0
|
|
|
|
|
+
|
|
|
|
|
+ logger.info(f"informe_categoria: categoría: {categoria.nombre} / fecha_inicio: {fecha_inicio_str} / fecha_fin: {fecha_fin_str} / saldo_inicial: {saldo_inicial}")
|
|
|
|
|
+
|
|
|
|
|
+ movimientos_con_saldo = []
|
|
|
|
|
+ saldo_acumulado = saldo_inicial
|
|
|
|
|
+ for mov in movimientos:
|
|
|
|
|
+ if mov.tipo == 'Ingreso':
|
|
|
|
|
+ saldo_acumulado += mov.monto
|
|
|
|
|
+ else:
|
|
|
|
|
+ saldo_acumulado -= mov.monto
|
|
|
|
|
+
|
|
|
|
|
+ movimientos_con_saldo.append({
|
|
|
|
|
+ 'movimiento': mov,
|
|
|
|
|
+ 'saldo_acumulado': saldo_acumulado
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ logger.info(f"informe_categoria: movimientos_con_saldo: {[{'id': m['movimiento'].id, 'saldo_acumulado': m['saldo_acumulado']} for m in movimientos_con_saldo]}")
|
|
|
|
|
+
|
|
|
|
|
+ context = {
|
|
|
|
|
+ 'categoria': categoria,
|
|
|
|
|
+ 'movimientos_con_saldo': movimientos_con_saldo,
|
|
|
|
|
+ 'fecha_inicio': fecha_inicio_str,
|
|
|
|
|
+ 'fecha_fin': fecha_fin_str,
|
|
|
|
|
+ 'saldo_inicial': saldo_inicial
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return render(request, 'informe_categoria.html', context)
|
|
|
|
|
+
|
|
|
|
|
+@login_required
|
|
|
|
|
+def informe_categoria_pdf(request):
|
|
|
|
|
+ categoria_id = request.GET.get('categoria_id')
|
|
|
|
|
+
|
|
|
|
|
+ categoria = get_object_or_404(Categoria, id=categoria_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 = Movimiento.objects.filter(
|
|
|
|
|
+ categoria=categoria,
|
|
|
|
|
+ usuario=request.user,
|
|
|
|
|
+ fecha__range=(fecha_inicio_dt, fecha_fin_dt)
|
|
|
|
|
+ ).order_by('fecha')
|
|
|
|
|
+
|
|
|
|
|
+ template = get_template('informe_categoria_pdf.html')
|
|
|
|
|
+ html = template.render({'categoria': categoria, 'fecha_inicio': fecha_inicio_str, 'fecha_fin': fecha_fin_str, 'movimientos': movimientos})
|
|
|
|
|
+
|
|
|
|
|
+ with tempfile.NamedTemporaryFile(delete=True) as output:
|
|
|
|
|
+ HTML(string=html).write_pdf(output.name)
|
|
|
|
|
+
|
|
|
|
|
+ output.seek(0)
|
|
|
|
|
+ response = HttpResponse(output.read(), content_type='application/pdf')
|
|
|
|
|
+ response['Content-Disposition'] = f'filename=informe_{categoria.nombre}.pdf'
|
|
|
|
|
+ return response
|