Add savings account flag and budget block model

This commit is contained in:
JKuijperM 2026-10-21 18:41:01 +02:00
parent 40b0c7ed7b
commit e64421b3df
2 changed files with 75 additions and 0 deletions

View File

@ -0,0 +1,34 @@
# Generated by Django 5.2.10 on 2026-10-18 14:51
import django.core.validators
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('expenses', '0018_category_expense_type'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='account',
name='is_savings',
field=models.BooleanField(default=False, help_text='Márcala si es una cuenta donde guardas dinero: los traspasos que entran en ella cuentan como ahorro en el reparto por bloques.', verbose_name='Cuenta de ahorro'),
),
migrations.CreateModel(
name='BudgetBlock',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('block', models.CharField(choices=[('fixed_essential', 'Fijo esencial'), ('fixed_discretionary', 'Fijo prescindible'), ('variable_essential', 'Variable esencial'), ('variable_discretionary', 'Variable prescindible'), ('saving', 'Ahorro')], max_length=30)),
('percentage', models.DecimalField(decimal_places=2, default=0, max_digits=5, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100)])),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='budget_blocks', to=settings.AUTH_USER_MODEL)),
],
options={
'unique_together': {('owner', 'block')},
},
),
]

View File

@ -1,6 +1,7 @@
from datetime import date
from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models, transaction
from django.conf import settings
from django.db.models import Q, Sum
@ -114,6 +115,14 @@ class Account(models.Model):
name = models.CharField(max_length=100)
initial_balance = models.DecimalField(max_digits=12, decimal_places=2, default=0)
active = models.BooleanField(default=True)
is_savings = models.BooleanField(
default=False,
verbose_name="Cuenta de ahorro",
help_text=(
"Márcala si es una cuenta donde guardas dinero: los traspasos que "
"entran en ella cuentan como ahorro en el reparto por bloques."
),
)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
@ -823,3 +832,35 @@ class Goal(models.Model):
def __str__(self):
return self.name
class BudgetBlock(models.Model):
"""Qué porcentaje del ingreso debería ir a un bloque.
Los bloques son los cuatro tipos de gasto de Category más el ahorro: lo que
el usuario clasificó en sus categorías es lo que ve aquí, sin un tercer eje.
Un único reparto por usuario, sin versionar por fecha: un histórico obliga
a decidir qué reparto aplica a cada mes, y eso se añade el día que haga
falta. Un bloque sin fila vale 0.
"""
BLOCK_SAVING = "saving"
BLOCK_CHOICES = Category.EXPENSE_TYPE_CHOICES + [(BLOCK_SAVING, "Ahorro")]
owner = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="budget_blocks"
)
block = models.CharField(max_length=30, choices=BLOCK_CHOICES)
percentage = models.DecimalField(
max_digits=5,
decimal_places=2,
default=0,
validators=[MinValueValidator(0), MaxValueValidator(100)],
)
class Meta:
unique_together = ("owner", "block")
def __str__(self):
return f"{self.get_block_display()}: {self.percentage} %"