Compare commits

..

2 Commits

2 changed files with 18 additions and 9 deletions

View File

@ -3,9 +3,10 @@ from decimal import Decimal
from django.db import models
from django.conf import settings
from django.db.models import Sum
from functools import cached_property
from django.utils.text import slugify
from django.db.models.fields import related
from django.db.models.functions import ExtractMonth
from django.utils.text import slugify
class Category(models.Model):
@ -357,7 +358,15 @@ class Goal(models.Model):
return self.start_date
@cached_property
def progress(self):
"""Progreso del objetivo. Memoizado: se calcula una vez por instancia.
Ojo: es una cached_property, no un método. Se accede como `goal.progress`
(sin paréntesis), tanto en código como en plantillas. El valor se cachea
en la instancia la primera vez; si en la misma petición se modifican
gastos y se necesita recalcular, habría que crear una instancia nueva.
"""
if self.kind == self.KIND_SAVING:
# Provisional: saldo de la cuenta asociada. Cuando exista el
# módulo de inversiones, esta rama es lo único que hay que tocar.
@ -384,7 +393,7 @@ class Goal(models.Model):
def percentage(self):
if not self.target_amount:
return 0
return (self.progress() / self.target_amount) * 100
return (self.progress / self.target_amount) * 100
def bar_width(self):
return min(float(self.percentage()), 100)
@ -405,7 +414,7 @@ class Goal(models.Model):
"""True si es un presupuesto que ya se ha pasado del límite."""
return (
self.kind == self.KIND_BUDGET
and self.progress() > self.target_amount
and self.progress > self.target_amount
)
def __str__(self):

View File

@ -24,7 +24,7 @@ def test_payment_goal_sums_expenses_since_start_date(user, account, category):
include_subcategories=False, start_date=start, target_amount=Decimal("100"),
)
assert goal.progress() == Decimal("20")
assert goal.progress == Decimal("20")
def test_payment_goal_include_subcategories_true_includes_child_expenses(user, account, category):
@ -36,7 +36,7 @@ def test_payment_goal_include_subcategories_true_includes_child_expenses(user, a
include_subcategories=True, target_amount=Decimal("100"),
)
assert goal.progress() == Decimal("15")
assert goal.progress == Decimal("15")
def test_payment_goal_include_subcategories_false_excludes_child_expenses(user, account, category):
@ -48,7 +48,7 @@ def test_payment_goal_include_subcategories_false_excludes_child_expenses(user,
include_subcategories=False, target_amount=Decimal("100"),
)
assert goal.progress() == Decimal("0")
assert goal.progress == Decimal("0")
def test_budget_goal_period_month_counts_only_current_month(user, account, category):
@ -60,7 +60,7 @@ def test_budget_goal_period_month_counts_only_current_month(user, account, categ
period=Goal.PERIOD_MONTH, target_amount=Decimal("100"),
)
assert goal.progress() == Decimal("30")
assert goal.progress == Decimal("30")
def test_budget_goal_is_exceeded_true_over_target(user, account, category):
@ -92,7 +92,7 @@ def test_is_exceeded_always_false_for_non_budget_kind(user, account, category):
owner=user, name="Pago", kind=Goal.KIND_PAYMENT, category=category, target_amount=Decimal("10"),
)
assert goal.progress() > goal.target_amount
assert goal.progress > goal.target_amount
assert goal.is_exceeded() is False
@ -103,7 +103,7 @@ def test_saving_goal_progress_equals_account_balance(user):
owner=user, name="Ahorro", kind=Goal.KIND_SAVING, account=acc, target_amount=Decimal("1000"),
)
assert goal.progress() == acc.current_balance()
assert goal.progress == acc.current_balance()
def test_bar_width_caps_at_100_above_target(user):