fix: networth doesn't load if there aren't any transactions

This commit is contained in:
Herculino Trotta
2024-10-17 13:04:41 -03:00
parent 255fe6f771
commit e9359a3dfd
2 changed files with 61 additions and 35 deletions

View File

@@ -10,6 +10,7 @@ from django.db.models import Sum, Min, Max, Case, When, F, Value, DecimalField
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
from django.db.models.functions import TruncMonth from django.db.models.functions import TruncMonth
from django.template.defaultfilters import date as date_filter from django.template.defaultfilters import date as date_filter
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from apps.accounts.models import Account from apps.accounts.models import Account
@@ -88,18 +89,12 @@ def calculate_account_net_worth():
def calculate_currency_net_worth(): def calculate_currency_net_worth():
# Calculate net worth and fetch currency details in a single query # Subquery to calculate balance for each account
net_worth_data = ( balance_subquery = (
Transaction.objects.filter(is_paid=True) Transaction.objects.filter(account=OuterRef("pk"), is_paid=True)
.values( .values("account")
"account__currency__name",
"account__currency__code",
"account__currency__prefix",
"account__currency__suffix",
"account__currency__decimal_places",
)
.annotate( .annotate(
amount=Sum( balance=Sum(
Case( Case(
When(type=Transaction.Type.INCOME, then=F("amount")), When(type=Transaction.Type.INCOME, then=F("amount")),
When(type=Transaction.Type.EXPENSE, then=-F("amount")), When(type=Transaction.Type.EXPENSE, then=-F("amount")),
@@ -108,19 +103,25 @@ def calculate_currency_net_worth():
) )
) )
) )
.values("balance")
) )
# Create the net worth dictionary from the query results # Main query to fetch all account data
accounts_data = Account.objects.annotate(
balance=Coalesce(Subquery(balance_subquery), Decimal("0"))
).select_related("currency")
net_worth = {} net_worth = {}
for item in net_worth_data: for item in accounts_data:
currency_name = item["account__currency__name"] currency_name = item.currency.name
net_worth[currency_name] = { net_worth[currency_name] = {
"amount": item["amount"] or Decimal("0"), "amount": net_worth.get(currency_name, {}).get("amount", Decimal("0"))
"code": item["account__currency__code"], + item.balance,
"code": item.currency.code,
"name": currency_name, "name": currency_name,
"prefix": item["account__currency__prefix"], "prefix": item.currency.prefix,
"suffix": item["account__currency__suffix"], "suffix": item.currency.suffix,
"decimal_places": item["account__currency__decimal_places"], "decimal_places": item.currency.decimal_places,
} }
return net_worth return net_worth
@@ -134,8 +135,15 @@ def calculate_historical_currency_net_worth():
) )
currencies = list(Currency.objects.values_list("name", flat=True)) currencies = list(Currency.objects.values_list("name", flat=True))
start_date = aggregates["min_date"].replace(day=1) if not aggregates.get("min_date"):
end_date = aggregates["max_date"].replace(day=1) start_date = timezone.localdate(timezone.now())
else:
start_date = aggregates["min_date"].replace(day=1)
if not aggregates.get("max_date"):
end_date = timezone.localdate(timezone.now()) + relativedelta(months=1)
else:
end_date = aggregates["max_date"].replace(day=1)
# Calculate cumulative balances for each account, currency, and month # Calculate cumulative balances for each account, currency, and month
cumulative_balances = ( cumulative_balances = (
@@ -184,7 +192,7 @@ def calculate_historical_currency_net_worth():
if balance_change != Decimal("0.00"): if balance_change != Decimal("0.00"):
totals_changed = True totals_changed = True
if totals_changed: if totals_changed or not historical_net_worth:
historical_net_worth[month_str] = running_totals.copy() historical_net_worth[month_str] = running_totals.copy()
last_recorded_totals = running_totals.copy() last_recorded_totals = running_totals.copy()
@@ -207,8 +215,16 @@ def calculate_historical_account_balance():
date_range = Transaction.objects.filter(is_paid=True).aggregate( date_range = Transaction.objects.filter(is_paid=True).aggregate(
min_date=Min("reference_date"), max_date=Max("reference_date") min_date=Min("reference_date"), max_date=Max("reference_date")
) )
start_date = date_range["min_date"].replace(day=1)
end_date = date_range["max_date"].replace(day=1) if not date_range.get("min_date"):
start_date = timezone.localdate(timezone.now())
else:
start_date = date_range["min_date"].replace(day=1)
if not date_range.get("max_date"):
end_date = timezone.localdate(timezone.now()) + relativedelta(months=1)
else:
end_date = date_range["max_date"].replace(day=1)
# Calculate balances for each account and month # Calculate balances for each account and month
balances = ( balances = (

View File

@@ -1,11 +1,7 @@
import json import json
from datetime import datetime
from dateutil.relativedelta import relativedelta
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.http import JsonResponse
from django.shortcuts import render from django.shortcuts import render
from django.utils import timezone
from apps.net_worth.utils.calculate_net_worth import ( from apps.net_worth.utils.calculate_net_worth import (
calculate_currency_net_worth, calculate_currency_net_worth,
@@ -13,7 +9,6 @@ from apps.net_worth.utils.calculate_net_worth import (
calculate_account_net_worth, calculate_account_net_worth,
calculate_historical_account_balance, calculate_historical_account_balance,
) )
from apps.currencies.models import Currency
# Create your views here. # Create your views here.
@@ -21,15 +16,24 @@ def net_worth_main(request):
currency_net_worth = calculate_currency_net_worth() currency_net_worth = calculate_currency_net_worth()
account_net_worth = calculate_account_net_worth() account_net_worth = calculate_account_net_worth()
historical_net_worth = calculate_historical_currency_net_worth() historical_currency_net_worth = calculate_historical_currency_net_worth()
labels = list(historical_net_worth.keys()) labels = (
currencies = list(historical_net_worth[labels[0]].keys()) list(historical_currency_net_worth.keys())
if historical_currency_net_worth
else []
)
currencies = (
list(historical_currency_net_worth[labels[0]].keys())
if historical_currency_net_worth
else []
)
datasets = [] datasets = []
for i, currency in enumerate(currencies): for i, currency in enumerate(currencies):
data = [ data = [
float(month_data[currency]) for month_data in historical_net_worth.values() float(month_data[currency])
for month_data in historical_currency_net_worth.values()
] ]
datasets.append( datasets.append(
{ {
@@ -47,8 +51,14 @@ def net_worth_main(request):
historical_account_balance = calculate_historical_account_balance() historical_account_balance = calculate_historical_account_balance()
labels = list(historical_account_balance.keys()) labels = (
accounts = list(historical_account_balance[labels[0]].keys()) list(historical_account_balance.keys()) if historical_account_balance else []
)
accounts = (
list(historical_account_balance[labels[0]].keys())
if historical_account_balance
else []
)
datasets = [] datasets = []
for i, account in enumerate(accounts): for i, account in enumerate(accounts):