Просмотр исходного кода

Añado saldo inicial. Adapto informes para que tengan en cuenta el saldo inicial

Celestino Rey 1 год назад
Родитель
Сommit
5ad2c0fd08

+ 6 - 6
src/finanzas/forms.py

@@ -50,24 +50,24 @@ class CuentaForm(forms.ModelForm):
 
     class Meta:
         model = Cuenta
-        fields = ['nombre', 'tipo', 'saldo', 'favorita']
+        fields = ['nombre', 'tipo', 'saldo_inicial', 'favorita']
 
         widgets = {
             'nombre': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'El nombre de la cuenta'}),
             'tipo': forms.Select(attrs={'class': 'form-control'}),
-            'saldo': forms.TextInput(attrs={'class': 'form-control'}),
+            'saldo_inicial': forms.NumberInput(attrs={'class': 'form-control'}),
             'favorita': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
         }
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        if 'saldo' in self.initial:
-            self.initial['saldo'] = str(self.initial['saldo']).replace('.', ',')
+        if 'saldo_inicial' in self.initial:
+            self.initial['saldo_inicial'] = str(self.initial['saldo_inicial']).replace('.', ',')
         elif self.instance and self.instance.pk:
-            self.fields['saldo'].initial = str(self.instance.saldo).replace('.', ',')
+            self.fields['saldo_inicial'].initial = str(self.instance.saldo).replace('.', ',')
 
     def clean_saldo(self):
-        valor = self.cleaned_data['saldo'].replace(',', '.')
+        valor = self.cleaned_data['saldo_inicial'].replace(',', '.')
         try:
             return Decimal(valor)
         except InvalidOperation:

+ 5 - 1
src/finanzas/models.py

@@ -1,6 +1,6 @@
 from django.db import models
 from reymotausers.models import ReyMotaUser
-
+from decimal import Decimal
 
 class Cuenta(models.Model):
     TIPO_CUENTA_CHOICES = (
@@ -13,6 +13,10 @@ class Cuenta(models.Model):
     usuario = models.ForeignKey(ReyMotaUser, on_delete=models.CASCADE)
     favorita = models.BooleanField(default=False)
 
+    saldo_inicial = models.DecimalField(
+        max_digits=12, decimal_places=2, default=Decimal("0.00")
+    )
+
     def __str__(self):
         return f"{self.nombre} ({self.tipo})"
 

+ 41 - 5
src/finanzas/views.py

@@ -18,6 +18,8 @@ from django.http import HttpResponse
 from weasyprint import HTML
 import tempfile
 from django.utils.dateparse import parse_date
+from decimal import Decimal
+from django.db.models import Sum
 
 import logging
 import re
@@ -429,14 +431,14 @@ def api_ejecutar_recurrentes(request):
 
 @login_required
 def resumen_saldos_mensuales(request):
-    cuentas = Cuenta.objects.filter(usuario=request.user)
+    cuentas = Cuenta.objects.filter(usuario=request.user).order_by('nombre')
     movimientos = Movimiento.objects.filter(usuario=request.user).order_by('fecha')
 
     # Diccionario: {(cuenta_id, año, mes): saldo}
     saldos_mensuales = defaultdict(lambda: 0)
 
     # Diccionario para llevar el saldo acumulado
-    saldos_acumulados = {cuenta.id: 0 for cuenta in cuentas}
+    saldos_acumulados = {cuenta.id: float(cuenta.saldo_inicial) for cuenta in cuentas}
 
     # Obtener todos los meses presentes en movimientos
     meses_presentes = set()
@@ -494,6 +496,22 @@ def informe_cuenta(request):
         # 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))
+        
+        # Saldo antes del periodo
+        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),
@@ -501,7 +519,8 @@ def informe_cuenta(request):
         ).order_by('fecha')
 
         # Cálculo de saldos después de cada movimiento
-        saldo = 0
+        saldo = saldo_inicial
+
         movimientos_con_saldo = []
         for mov in movimientos:
             if mov.cuenta_origen == cuenta:
@@ -522,6 +541,7 @@ def informe_cuenta(request):
             'movimientos_con_saldo': movimientos_con_saldo,
             'fecha_inicio': fecha_inicio_str,
             'fecha_fin': fecha_fin_str,
+            'saldo_inicial': saldo_inicial,
         }
 
         return render(request, 'informe_cuenta.html', context)
@@ -551,12 +571,28 @@ def informe_cuenta_pdf(request):
     fecha_inicio_dt = timezone.make_aware(datetime.combine(fecha_inicio, time.min))
     fecha_fin_dt = timezone.make_aware(datetime.combine(fecha_fin, time.max))
 
+    # Saldo antes del periodo
+    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 = 0
+    saldo = saldo_inicial
     historial = []
 
     for mov in movimientos:
@@ -578,7 +614,7 @@ def informe_cuenta_pdf(request):
         })
 
     template = get_template('informe_cuenta_pdf.html')
-    html = template.render({'cuenta': cuenta, 'historial': historial})
+    html = template.render({'cuenta': cuenta, 'saldo_inicial': saldo_inicial, 'historial': historial})
 
     with tempfile.NamedTemporaryFile(delete=True) as output:
         HTML(string=html).write_pdf(output.name)

+ 4 - 3
src/templates/informe_cuenta.html

@@ -5,8 +5,11 @@
     {% include "_navigation.html" %}
     
     <h3 class="i-name">
-        Informe de cuenta: {{ cuenta.nombre }}  para el periodo del {{ fecha_inicio }} hasta {{ fecha_fin }}   
+        Informe de cuenta: {{ cuenta.nombre }}  
     </h3>
+    <h4 style="padding: 30px 30px 0 30px;">
+    Periodo del {{ fecha_inicio }} hasta {{ fecha_fin }} -  Saldo inicial: {{ saldo_inicial|floatformat:2 }} €
+    </h4>
 
     <div class="board"> 
         <div class="form-group">
@@ -28,8 +31,6 @@
             </form>
         </div>
 
-
-
         <table class="table table-striped">
             <thead>
                 <tr>

+ 3 - 0
src/templates/informe_cuenta_pdf.html

@@ -12,6 +12,9 @@
 </head>
 <body>
     <h2>Informe de cuenta: {{ cuenta.nombre }}</h2>
+    <h4>
+    Periodo del {{ fecha_inicio }} hasta {{ fecha_fin }} -  Saldo inicial: {{ saldo_inicial|floatformat:2 }} €
+    </h4>
     <table>
         <thead>
             <tr>