diff --git a/app/apps/net_worth/utils/calculate_net_worth.py b/app/apps/net_worth/utils/calculate_net_worth.py index c63ce50..6ab9bbf 100644 --- a/app/apps/net_worth/utils/calculate_net_worth.py +++ b/app/apps/net_worth/utils/calculate_net_worth.py @@ -19,133 +19,6 @@ from apps.currencies.utils.convert import convert from apps.transactions.models import Transaction -def calculate_account_net_worth(): - ungrouped_id = None # Special ID for ungrouped accounts - - # Subquery to calculate balance for each account - balance_subquery = ( - Transaction.objects.filter(account=OuterRef("pk"), is_paid=True) - .values("account") - .annotate( - balance=Sum( - Case( - When(type=Transaction.Type.INCOME, then=F("amount")), - When(type=Transaction.Type.EXPENSE, then=-F("amount")), - default=0, - output_field=DecimalField(), - ) - ) - ) - .values("balance") - ) - - # Main query to fetch all account data - accounts_data = ( - Account.objects.filter(is_archived=False) - .annotate(balance=Coalesce(Subquery(balance_subquery), Decimal("0"))) - .select_related("currency", "exchange_currency", "group") - ) - - account_net_worth = {ungrouped_id: {"name": _("Ungrouped"), "accounts": {}}} - - for account in accounts_data: - account_data = { - "name": account.name, - "balance": account.balance, - "currency": { - "code": account.currency.code, - "name": account.currency.name, - "prefix": account.currency.prefix, - "suffix": account.currency.suffix, - "decimal_places": account.currency.decimal_places, - }, - } - - if account.exchange_currency: - converted_amount, prefix, suffix, decimal_places = convert( - amount=account.balance, - from_currency=account.currency, - to_currency=account.exchange_currency, - ) - if converted_amount: - account_data["exchange"] = { - "amount": converted_amount, - "prefix": prefix, - "suffix": suffix, - "decimal_places": decimal_places, - } - - group_id = account.group.id if account.group else ungrouped_id - group_name = account.group.name if account.group else _("Ungrouped") - - if group_id not in account_net_worth: - account_net_worth[group_id] = {"name": group_name, "accounts": {}} - - account_net_worth[group_id]["accounts"][account.id] = account_data - - # Remove the "Ungrouped" category if it's empty - if not account_net_worth[ungrouped_id]["accounts"]: - del account_net_worth[ungrouped_id] - - return account_net_worth - - -def calculate_currency_net_worth(): - # Subquery to calculate balance for each currency - balance_subquery = ( - Transaction.objects.filter(account__currency=OuterRef("pk"), is_paid=True) - .values("account__currency") - .annotate( - balance=Sum( - Case( - When(type=Transaction.Type.INCOME, then=F("amount")), - When(type=Transaction.Type.EXPENSE, then=-F("amount")), - default=0, - output_field=DecimalField(), - ) - ) - ) - .values("balance") - ) - - # Fetch all currencies with their balances in a single query - currencies_data = Currency.objects.annotate( - balance=Coalesce(Subquery(balance_subquery), Decimal("0")) - ).select_related( - "exchange_currency" - ) # Optimize by pre-fetching exchange_currency - - net_worth = {} - for currency in currencies_data: - # Skip conversion if no exchange currency is set - exchanged_value = None - if currency.exchange_currency: - exchanged_amount, ex_prefix, ex_suffix, ex_decimal_places = convert( - amount=currency.balance, - from_currency=currency, - to_currency=currency.exchange_currency, - ) - exchanged_value = { - "amount": exchanged_amount, - "name": currency.exchange_currency.name, - "prefix": ex_prefix, - "suffix": ex_suffix, - "decimal_places": ex_decimal_places, - } - - net_worth[currency.name] = { - "amount": currency.balance, - "code": currency.code, - "name": currency.name, - "prefix": currency.prefix, - "suffix": currency.suffix, - "decimal_places": currency.decimal_places, - "exchanged": exchanged_value, - } - - return net_worth - - def calculate_historical_currency_net_worth(): # Get all currencies and date range in a single query aggregates = Transaction.objects.aggregate( diff --git a/app/apps/net_worth/views.py b/app/apps/net_worth/views.py index 27bd5d2..4aa5803 100644 --- a/app/apps/net_worth/views.py +++ b/app/apps/net_worth/views.py @@ -9,11 +9,24 @@ from apps.net_worth.utils.calculate_net_worth import ( calculate_account_net_worth, calculate_historical_account_balance, ) +from apps.transactions.models import Transaction +from apps.transactions.utils.calculations import ( + calculate_currency_totals, + calculate_account_totals, +) def net_worth_main(request): - currency_net_worth = calculate_currency_net_worth() - account_net_worth = calculate_account_net_worth() + transactions_queryset = Transaction.objects.filter(is_paid=True).order_by( + "account__group", + "account__name", + ) + currency_net_worth = calculate_currency_totals( + transactions_queryset=transactions_queryset + ) + account_net_worth = calculate_account_totals( + transactions_queryset=transactions_queryset + ) historical_currency_net_worth = calculate_historical_currency_net_worth() @@ -83,7 +96,7 @@ def net_worth_main(request): request, "net_worth/net_worth.html", { - "currency_net_worth": currency_net_worth.values(), + "currency_net_worth": currency_net_worth, "account_net_worth": account_net_worth, "chart_data_currency_json": chart_data_currency_json, "currencies": currencies, diff --git a/app/templates/net_worth/net_worth.html b/app/templates/net_worth/net_worth.html index dd9b8c8..58b02d9 100644 --- a/app/templates/net_worth/net_worth.html +++ b/app/templates/net_worth/net_worth.html @@ -21,29 +21,29 @@
{% translate 'By currency' %}
- {% for currency in currency_net_worth %} + {% for currency in currency_net_worth.values %}
-
{{ currency.name }}
+
{{ currency.currency.name }}
- {% if currency.exchanged and currency.exchanged.amount %} + {% if currency.exchanged and currency.exchanged.total_current %}
@@ -60,62 +60,63 @@
{% translate 'By account' %}
- {% for group_id, group_data in account_net_worth.items %} - {% if group_id %} + {% regroup account_net_worth.values by account.group as account_data %} + {% for data in account_data %} + {% if data.grouper %}
- {{ group_data.name }}
+ {{ data.grouper }}
- {% for account_id, account_data in group_data.accounts.items %} + {% for account in data.list %}
- {{ account_data.name }}
+ {{ account.account.name }}
+ :amount="account.total_final" + :prefix="account.currency.prefix" + :suffix="account.currency.suffix" + :decimal_places="account.currency.decimal_places" + color="{% if account.total_final > 0 %}green{% elif account.total_final < 0 %}red{% endif %}">
- {% if account_data.exchange %} + {% if account.exchanged and account.exchanged.total_final %} {% endif %} {% endfor %} {% else %} - {% for account_id, account_data in group_data.accounts.items %} + {% for account in data.list %}
-
{{ account_data.name }}
+
{{ account.account.name }}
+ :amount="account.total_final" + :prefix="account.currency.prefix" + :suffix="account.currency.suffix" + :decimal_places="account.currency.decimal_places" + color="{% if account.total_final > 0 %}green{% elif account.total_final < 0 %}red{% endif %}">
- {% if account_data.exchange %} + {% if account.exchanged and account.exchanged.total_final %} {% endif %}