mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-04-25 01:58:54 +02:00
feat(monthly-view): add percentage bar
This commit is contained in:
@@ -13,7 +13,10 @@ from apps.monthly_overview.utils.daily_spending_allowance import (
|
|||||||
)
|
)
|
||||||
from apps.transactions.filters import TransactionsFilter
|
from apps.transactions.filters import TransactionsFilter
|
||||||
from apps.transactions.models import Transaction
|
from apps.transactions.models import Transaction
|
||||||
from apps.transactions.utils.calculations import calculate_currency_totals
|
from apps.transactions.utils.calculations import (
|
||||||
|
calculate_currency_totals,
|
||||||
|
calculate_percentage_distribution,
|
||||||
|
)
|
||||||
from apps.transactions.utils.default_ordering import default_order
|
from apps.transactions.utils.default_ordering import default_order
|
||||||
|
|
||||||
|
|
||||||
@@ -98,6 +101,7 @@ def monthly_summary(request, month: int, year: int):
|
|||||||
).exclude(Q(category__mute=True) & ~Q(category=None))
|
).exclude(Q(category__mute=True) & ~Q(category=None))
|
||||||
|
|
||||||
data = calculate_currency_totals(base_queryset, ignore_empty=True)
|
data = calculate_currency_totals(base_queryset, ignore_empty=True)
|
||||||
|
percentages = calculate_percentage_distribution(data)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"income_current": remove_falsey_entries(data, "income_current"),
|
"income_current": remove_falsey_entries(data, "income_current"),
|
||||||
@@ -110,6 +114,7 @@ def monthly_summary(request, month: int, year: int):
|
|||||||
"daily_spending_allowance": calculate_daily_allowance_currency(
|
"daily_spending_allowance": calculate_daily_allowance_currency(
|
||||||
currency_totals=data, month=month, year=year
|
currency_totals=data, month=month, year=year
|
||||||
),
|
),
|
||||||
|
"percentages": percentages,
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
|
|||||||
@@ -157,6 +157,94 @@ def calculate_currency_totals(transactions_queryset, ignore_empty=False):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_percentage_distribution(currency_totals):
|
||||||
|
"""
|
||||||
|
Calculate percentage distribution of financial metrics for each currency.
|
||||||
|
Returns a new dictionary with currency IDs as keys and percentage distributions.
|
||||||
|
"""
|
||||||
|
percentages = {}
|
||||||
|
|
||||||
|
for currency_id, data in currency_totals.items():
|
||||||
|
# Calculate total volume of transactions
|
||||||
|
total_volume = sum(
|
||||||
|
[
|
||||||
|
abs(data["income_current"]),
|
||||||
|
abs(data["income_projected"]),
|
||||||
|
abs(data["expense_current"]),
|
||||||
|
abs(data["expense_projected"]),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize percentages for this currency
|
||||||
|
percentages[currency_id] = {
|
||||||
|
"currency": data["currency"], # Keep currency info for reference
|
||||||
|
"percentages": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Calculate percentages if total_volume is not zero
|
||||||
|
if total_volume > 0:
|
||||||
|
percentages[currency_id]["percentages"] = {
|
||||||
|
"income_current": (abs(data["income_current"]) / total_volume) * 100,
|
||||||
|
"income_projected": (abs(data["income_projected"]) / total_volume)
|
||||||
|
* 100,
|
||||||
|
"expense_current": (abs(data["expense_current"]) / total_volume) * 100,
|
||||||
|
"expense_projected": (abs(data["expense_projected"]) / total_volume)
|
||||||
|
* 100,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
percentages[currency_id]["percentages"] = {
|
||||||
|
"income_current": 0,
|
||||||
|
"income_projected": 0,
|
||||||
|
"expense_current": 0,
|
||||||
|
"expense_projected": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
# If there's exchanged data, calculate percentages for that too
|
||||||
|
if "exchanged" in data:
|
||||||
|
exchanged_total = sum(
|
||||||
|
[
|
||||||
|
abs(data["exchanged"]["income_current"]),
|
||||||
|
abs(data["exchanged"]["income_projected"]),
|
||||||
|
abs(data["exchanged"]["expense_current"]),
|
||||||
|
abs(data["exchanged"]["expense_projected"]),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
percentages[currency_id]["exchanged"] = {
|
||||||
|
"currency": data["exchanged"]["currency"],
|
||||||
|
"percentages": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
if exchanged_total > 0:
|
||||||
|
percentages[currency_id]["exchanged"]["percentages"] = {
|
||||||
|
"income_current": (
|
||||||
|
abs(data["exchanged"]["income_current"]) / exchanged_total
|
||||||
|
)
|
||||||
|
* 100,
|
||||||
|
"income_projected": (
|
||||||
|
abs(data["exchanged"]["income_projected"]) / exchanged_total
|
||||||
|
)
|
||||||
|
* 100,
|
||||||
|
"expense_current": (
|
||||||
|
abs(data["exchanged"]["expense_current"]) / exchanged_total
|
||||||
|
)
|
||||||
|
* 100,
|
||||||
|
"expense_projected": (
|
||||||
|
abs(data["exchanged"]["expense_projected"]) / exchanged_total
|
||||||
|
)
|
||||||
|
* 100,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
percentages[currency_id]["exchanged"]["percentages"] = {
|
||||||
|
"income_current": 0,
|
||||||
|
"income_projected": 0,
|
||||||
|
"expense_current": 0,
|
||||||
|
"expense_projected": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
return percentages
|
||||||
|
|
||||||
|
|
||||||
def calculate_account_totals(transactions_queryset, ignore_empty=False):
|
def calculate_account_totals(transactions_queryset, ignore_empty=False):
|
||||||
# Prepare the aggregation expressions
|
# Prepare the aggregation expressions
|
||||||
account_totals = transactions_queryset.values(
|
account_totals = transactions_queryset.values(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load currency_display %}
|
{% load currency_display %}
|
||||||
|
|
||||||
<div class="row row-cols-1 g-4 mb-3">
|
<div class="row row-cols-1 g-4 mb-3">
|
||||||
{# Daily Spending#}
|
{# Daily Spending#}
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -281,3 +282,35 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% for p in percentages.values %}
|
||||||
|
<div class="progress-stacked mt-3">
|
||||||
|
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Income' %} ({{ p.percentages.income_projected|floatformat:2 }}%)" aria-valuenow="{{ p.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ p.percentages.income_projected|floatformat:0 }}%">
|
||||||
|
<div class="progress-bar progress-bar-striped !tw-bg-green-400"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top"
|
||||||
|
title="{% trans 'Projected Income' %} ({{ p.percentages.income_projected|floatformat:2 }}%)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Income' %} ({{ p.percentages.income_current|floatformat:2 }}%)" aria-valuenow="{{ p.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ p.percentages.income_current|floatformat:0 }}%">
|
||||||
|
<div class="progress-bar !tw-bg-green-400"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top"
|
||||||
|
title="{% trans 'Current Income' %} ({{ p.percentages.income_current|floatformat:2 }}%)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Projected Expenses' %} ({{ p.percentages.expense_projected|floatformat:2 }}%)" aria-valuenow="{{ p.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ p.percentages.expense_projected|floatformat:0 }}%">
|
||||||
|
<div class="progress-bar progress-bar-striped !tw-bg-red-400"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top"
|
||||||
|
title="{% trans 'Projected Expenses' %} ({{ p.percentages.expense_projected|floatformat:2 }}%)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress position-relative" role="progressbar" aria-label="{% trans 'Current Expenses' %} ({{ p.percentages.expense_current|floatformat:2 }}%)" aria-valuenow="{{ p.percentages.expense_projected|floatformat:0 }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ p.percentages.expense_current|floatformat:0 }}%">
|
||||||
|
<div class="progress-bar !tw-bg-red-400"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top"
|
||||||
|
title="{% trans 'Current Expenses' %} ({{ p.percentages.expense_current|floatformat:2 }}%)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|||||||
Reference in New Issue
Block a user