mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-07-09 22:32:50 +02:00
Merge pull request #353
feat(insights:category-overview): add "No entity" totals
This commit is contained in:
@@ -12,7 +12,10 @@ from apps.currencies.utils.convert import convert
|
|||||||
def get_categories_totals(
|
def get_categories_totals(
|
||||||
transactions_queryset, ignore_empty=False, show_entities=False
|
transactions_queryset, ignore_empty=False, show_entities=False
|
||||||
):
|
):
|
||||||
# First get the category totals as before
|
# Step 1: Aggregate transaction data by category and currency.
|
||||||
|
# This query calculates the total current and projected income/expense for each
|
||||||
|
# category by grouping transactions and summing up their amounts based on their
|
||||||
|
# type (income/expense) and payment status (paid/unpaid).
|
||||||
category_currency_metrics = (
|
category_currency_metrics = (
|
||||||
transactions_queryset.values(
|
transactions_queryset.values(
|
||||||
"category",
|
"category",
|
||||||
@@ -76,7 +79,10 @@ def get_categories_totals(
|
|||||||
.order_by("category__name")
|
.order_by("category__name")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get tag totals within each category with currency details
|
# Step 2: Aggregate transaction data by tag, category, and currency.
|
||||||
|
# This is similar to the category metrics but adds tags to the grouping,
|
||||||
|
# allowing for a breakdown of totals by tag within each category. It also
|
||||||
|
# handles untagged transactions, where the 'tags' field is None.
|
||||||
tag_metrics = transactions_queryset.values(
|
tag_metrics = transactions_queryset.values(
|
||||||
"category",
|
"category",
|
||||||
"tags",
|
"tags",
|
||||||
@@ -131,10 +137,12 @@ def get_categories_totals(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Process the results to structure by category
|
# Step 3: Initialize the main dictionary to structure the final results.
|
||||||
|
# The data will be organized hierarchically: category -> currency -> tags -> entities.
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
# Process category totals first
|
# Step 4: Process the aggregated category metrics to build the initial result structure.
|
||||||
|
# This loop iterates through each category's metrics and populates the `result` dict.
|
||||||
for metric in category_currency_metrics:
|
for metric in category_currency_metrics:
|
||||||
# Skip empty categories if ignore_empty is True
|
# Skip empty categories if ignore_empty is True
|
||||||
if ignore_empty and all(
|
if ignore_empty and all(
|
||||||
@@ -185,7 +193,7 @@ def get_categories_totals(
|
|||||||
"total_final": total_final,
|
"total_final": total_final,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add exchanged values if exchange_currency exists
|
# Step 4a: Handle currency conversion for category totals if an exchange currency is defined.
|
||||||
if metric["account__currency__exchange_currency"]:
|
if metric["account__currency__exchange_currency"]:
|
||||||
from_currency = Currency.objects.get(id=currency_id)
|
from_currency = Currency.objects.get(id=currency_id)
|
||||||
exchange_currency = Currency.objects.get(
|
exchange_currency = Currency.objects.get(
|
||||||
@@ -224,7 +232,7 @@ def get_categories_totals(
|
|||||||
|
|
||||||
result[category_id]["currencies"][currency_id] = currency_data
|
result[category_id]["currencies"][currency_id] = currency_data
|
||||||
|
|
||||||
# Process tag totals and add them to the result, including untagged
|
# Step 5: Process the aggregated tag metrics and integrate them into the result structure.
|
||||||
for tag_metric in tag_metrics:
|
for tag_metric in tag_metrics:
|
||||||
category_id = tag_metric["category"]
|
category_id = tag_metric["category"]
|
||||||
tag_id = tag_metric["tags"] # Will be None for untagged transactions
|
tag_id = tag_metric["tags"] # Will be None for untagged transactions
|
||||||
@@ -281,7 +289,7 @@ def get_categories_totals(
|
|||||||
"total_final": tag_total_final,
|
"total_final": tag_total_final,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add exchange currency support for tags
|
# Step 5a: Handle currency conversion for tag totals.
|
||||||
if tag_metric["account__currency__exchange_currency"]:
|
if tag_metric["account__currency__exchange_currency"]:
|
||||||
from_currency = Currency.objects.get(id=currency_id)
|
from_currency = Currency.objects.get(id=currency_id)
|
||||||
exchange_currency = Currency.objects.get(
|
exchange_currency = Currency.objects.get(
|
||||||
@@ -322,6 +330,7 @@ def get_categories_totals(
|
|||||||
currency_id
|
currency_id
|
||||||
] = tag_currency_data
|
] = tag_currency_data
|
||||||
|
|
||||||
|
# Step 6: If requested, aggregate and process entity-level data.
|
||||||
if show_entities:
|
if show_entities:
|
||||||
entity_metrics = transactions_queryset.values(
|
entity_metrics = transactions_queryset.values(
|
||||||
"category",
|
"category",
|
||||||
@@ -389,14 +398,15 @@ def get_categories_totals(
|
|||||||
tag_id = entity_metric["tags"]
|
tag_id = entity_metric["tags"]
|
||||||
entity_id = entity_metric["entities"]
|
entity_id = entity_metric["entities"]
|
||||||
|
|
||||||
if not entity_id:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if category_id in result:
|
if category_id in result:
|
||||||
tag_key = tag_id if tag_id is not None else "untagged"
|
tag_key = tag_id if tag_id is not None else "untagged"
|
||||||
if tag_key in result[category_id]["tags"]:
|
if tag_key in result[category_id]["tags"]:
|
||||||
entity_key = entity_id
|
entity_key = entity_id if entity_id is not None else "no_entity"
|
||||||
entity_name = entity_metric["entities__name"]
|
entity_name = (
|
||||||
|
entity_metric["entities__name"]
|
||||||
|
if entity_id is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
if "entities" not in result[category_id]["tags"][tag_key]:
|
if "entities" not in result[category_id]["tags"][tag_key]:
|
||||||
result[category_id]["tags"][tag_key]["entities"] = {}
|
result[category_id]["tags"][tag_key]["entities"] = {}
|
||||||
|
|||||||
@@ -268,95 +268,97 @@
|
|||||||
<!-- Entity rows -->
|
<!-- Entity rows -->
|
||||||
{% if show_entities %}
|
{% if show_entities %}
|
||||||
{% for entity_id, entity in tag.entities.items %}
|
{% for entity_id, entity in tag.entities.items %}
|
||||||
<tr class="table-row-nested-2">
|
{% if entity.name or not entity.name and tag.entities.values|length > 1 %}
|
||||||
<td class="ps-5">
|
<tr class="table-row-nested-2">
|
||||||
<i class="fa-solid fa-user-group fa-fw me-2 text-muted"></i>{{ entity.name }}
|
<td class="ps-5">
|
||||||
</td>
|
<i class="fa-solid fa-user-group fa-fw me-2 text-muted"></i>{% if entity.name %}{{ entity.name }}{% else %}{% trans 'No entity' %}{% endif %}
|
||||||
<td>
|
</td>
|
||||||
{% for currency in entity.currencies.values %}
|
<td>
|
||||||
{% if showing == 'current' and currency.income_current != 0 %}
|
{% for currency in entity.currencies.values %}
|
||||||
<c-amount.display
|
{% if showing == 'current' and currency.income_current != 0 %}
|
||||||
:amount="currency.income_current"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.income_current"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="green"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% elif showing == 'projected' and currency.income_projected != 0 %}
|
color="green"></c-amount.display>
|
||||||
<c-amount.display
|
{% elif showing == 'projected' and currency.income_projected != 0 %}
|
||||||
:amount="currency.income_projected"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.income_projected"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="green"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% elif showing == 'final' and currency.total_income != 0 %}
|
color="green"></c-amount.display>
|
||||||
<c-amount.display
|
{% elif showing == 'final' and currency.total_income != 0 %}
|
||||||
:amount="currency.total_income"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.total_income"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="green"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% else %}
|
color="green"></c-amount.display>
|
||||||
<div>-</div>
|
{% else %}
|
||||||
{% endif %}
|
<div>-</div>
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
</td>
|
{% endfor %}
|
||||||
<td>
|
</td>
|
||||||
{% for currency in entity.currencies.values %}
|
<td>
|
||||||
{% if showing == 'current' and currency.expense_current != 0 %}
|
{% for currency in entity.currencies.values %}
|
||||||
<c-amount.display
|
{% if showing == 'current' and currency.expense_current != 0 %}
|
||||||
:amount="currency.expense_current"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.expense_current"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="red"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% elif showing == 'projected' and currency.expense_projected != 0 %}
|
color="red"></c-amount.display>
|
||||||
<c-amount.display
|
{% elif showing == 'projected' and currency.expense_projected != 0 %}
|
||||||
:amount="currency.expense_projected"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.expense_projected"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="red"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% elif showing == 'final' and currency.total_expense != 0 %}
|
color="red"></c-amount.display>
|
||||||
<c-amount.display
|
{% elif showing == 'final' and currency.total_expense != 0 %}
|
||||||
:amount="currency.total_expense"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.total_expense"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="red"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% else %}
|
color="red"></c-amount.display>
|
||||||
<div>-</div>
|
{% else %}
|
||||||
{% endif %}
|
<div>-</div>
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
</td>
|
{% endfor %}
|
||||||
<td>
|
</td>
|
||||||
{% for currency in entity.currencies.values %}
|
<td>
|
||||||
{% if showing == 'current' and currency.total_current != 0 %}
|
{% for currency in entity.currencies.values %}
|
||||||
<c-amount.display
|
{% if showing == 'current' and currency.total_current != 0 %}
|
||||||
:amount="currency.total_current"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.total_current"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% elif showing == 'projected' and currency.total_projected != 0 %}
|
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
||||||
<c-amount.display
|
{% elif showing == 'projected' and currency.total_projected != 0 %}
|
||||||
:amount="currency.total_projected"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.total_projected"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% elif showing == 'final' and currency.total_final != 0 %}
|
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
||||||
<c-amount.display
|
{% elif showing == 'final' and currency.total_final != 0 %}
|
||||||
:amount="currency.total_final"
|
<c-amount.display
|
||||||
:prefix="currency.currency.prefix"
|
:amount="currency.total_final"
|
||||||
:suffix="currency.currency.suffix"
|
:prefix="currency.currency.prefix"
|
||||||
:decimal_places="currency.currency.decimal_places"
|
:suffix="currency.currency.suffix"
|
||||||
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
:decimal_places="currency.currency.decimal_places"
|
||||||
{% else %}
|
color="{% if currency.total_final < 0 %}red{% else %}green{% endif %}"></c-amount.display>
|
||||||
<div>-</div>
|
{% else %}
|
||||||
{% endif %}
|
<div>-</div>
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
</td>
|
{% endfor %}
|
||||||
</tr>
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user