mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-04-19 23:31:27 +02:00
feat: improve calculations for net_worth
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user