-
{{ acc.name }}
-
Saldo actual: {{ acc.current_balance|floatformat:2 }} €
-
+
{{ acc.name }}
+
Saldo actual: {{ acc.current_balance|floatformat:2 }}€
@@ -160,7 +224,6 @@
-
diff --git a/expenses_manager/expenses/views.py b/expenses_manager/expenses/views.py
index 85ad52a..936c437 100644
--- a/expenses_manager/expenses/views.py
+++ b/expenses_manager/expenses/views.py
@@ -19,7 +19,7 @@ from django.db.models import Sum
from django.contrib.auth import login
from django.core.paginator import Paginator
from django.utils.ipv6 import is_valid_ipv6_address
-from django.db.models.functions import ExtractMonth, ExtractYear
+from django.db.models.functions import ExtractMonth, ExtractYear, ExtractDay
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, render, redirect
@@ -287,177 +287,176 @@ def expense_delete(request, pk):
@login_required
def dashboard(request):
- # ------------------
- # Filters
- # ------------------
- year = _get_int(request.GET.get("year"))
- month = _get_int(request.GET.get("month"))
- period = request.GET.get("period")
+ today = date.today()
+
+ period = request.GET.get("period", "")
account_id = _get_int(request.GET.get("account"))
compare_enabled = request.GET.get("compare") == "1"
-
- today = date.today()
- current_year = today.year
-
- accounts = Account.objects.filter(owner=request.user, active=True)
- selected_year = year or current_year
- selected_month = month
-
- # ------------------
- # Queryset base
- # -----------------
- expenses = Expense.objects.filter(owner=request.user)
-
- selected_account_obj = None
- if account_id:
- expenses = expenses.filter(account_id=account_id)
- selected_account_obj = accounts.filter(id=account_id).first()
-
+
+ # Time presets
if period == "this_month":
selected_year, selected_month = today.year, today.month
elif period == "last_month":
selected_year, selected_month = sub_months(today.year, today.month, 1)
elif period == "this_year":
selected_year, selected_month = today.year, None
-
+ else:
+ selected_year = _get_int(request.GET.get("year")) or _get_int(today.year)
+ selected_month = _get_int(request.GET.get("month"))
+ selected_month = _get_int(selected_month) if selected_month else None
+
+ # Accounts
+ accounts = Account.objects.filter(owner=request.user, active=True)
+ selected_account_obj = None
+ if account_id:
+ selected_account_obj = accounts.filter(id=account_id).first()
+
+ # Calculate the KPI
if selected_account_obj:
kpi_balance = selected_account_obj.current_balance()
else:
kpi_balance = sum(account.current_balance() for account in accounts)
-
+
+ # Filter by base expenses
+ expenses = Expense.objects.filter(owner=request.user)
+ if account_id:
+ expenses = expenses.filter(account_id=account_id)
+
expenses_filtered = expenses.filter(date__year=selected_year)
if selected_month:
expenses_filtered = expenses_filtered.filter(date__month=selected_month)
-
+
+ # Basic KPIs
total_amount = expenses_filtered.aggregate(total=Sum("amount"))["total"] or 0
expense_count = expenses_filtered.count()
category_count = expenses_filtered.values("category").distinct().count()
-
- # ------------------
- # Totals by category
- # -----------------
- by_category = (
+
+ # Total by category
+ by_category_qs = by_category = (
expenses_filtered.values("category__name")
.annotate(total=Sum("amount"))
- .order_by("category__name")
+ .order_by("-total")
)
-
- # ------------------
- # Totals by month
- # -----------------
-
- by_month_qs = (
- expenses_filtered.annotate(month=ExtractMonth("date"))
- .values("month")
- .annotate(total=Sum("amount"))
- )
-
- month_totals = {row["month"]: float(row["total"]) for row in by_month_qs}
- months = list(range(1, 13))
- by_month = [{"month": m, "total": month_totals.get(m, 0)}for m in months]
-
- # ------------------
- # Availables years
- # -----------------
-
+
+ CATEGORY_LIMIT = 10 # Top 10
+
+ by_category_chart = []
+ for index, row in enumerate(by_category_qs):
+ if index >= CATEGORY_LIMIT:
+ break
+
+ cat_name = row["category__name"] or "Sin categoría"
+ total_cat = float(row["total"])
+
+ by_category_chart.append({
+ "category__name": cat_name,
+ "total": total_cat
+ })
+
+ #Graphic
+ if selected_month:
+ by_day_qs = (
+ expenses_filtered.annotate(day=ExtractDay("date"))
+ .values("day")
+ .annotate(total=Sum("amount"))
+ )
+ day_totals = {row["day"]: float(row["total"]) for row in by_day_qs}
+
+ import calendar
+ num_days = calendar.monthrange(selected_year, selected_month)[1]
+
+ chart_labels = list(range(1, num_days + 1))
+ chart_totals = [day_totals.get(d, 0) for d in chart_labels]
+ chart_type = "day"
+ else:
+ by_month_qs = (
+ expenses_filtered.annotate(month=ExtractMonth("date"))
+ .values("month")
+ .annotate(total=Sum("amount"))
+ )
+ month_totals = {row["month"]: float(row["total"]) for row in by_month_qs}
+ chart_labels = ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"]
+ chart_totals = [month_totals.get(m, 0) for m in range(1, 13)]
+ chart_type = "month"
+
year_list = (
- expenses.annotate(year=ExtractYear("date"))
+ Expense.objects.filter(owner=request.user)
+ .annotate(year=ExtractYear("date"))
.values_list("year", flat=True)
.distinct()
- .order_by("year")
+ .order_by("-year")
)
-
- # ------------------
- # Chart
- # -----------------
- chart_labels = months
- chart_totals = [row["total"] for row in by_month]
-
- # ------------------
- # Compare period
- # -----------------
-
- previous_total = None
- kpi_difference = None
- percentage = None
- category_comparison = None
- kpi_trend = None
- kpi_difference_abs = None
-
+
+ # Comparison
+ previous_total = 0
+ kpi_difference = 0
+ percentage = 0
+ kpi_trend = "equal"
+ category_comparison = []
+
if compare_enabled:
previous_expenses = Expense.objects.filter(owner=request.user)
if account_id:
previous_expenses = previous_expenses.filter(account_id=account_id)
-
+
if selected_month:
prev_year, prev_month = sub_months(selected_year, selected_month, 1)
- previous_expenses = previous_expenses.filter(
- date__year=prev_year, date__month=prev_month
- )
+ previous_expenses = previous_expenses.filter(date__year=prev_year, date__month=prev_month)
else:
- # Anual compare
prev_year = selected_year - 1
previous_expenses = previous_expenses.filter(date__year=prev_year)
-
+
previous_total = previous_expenses.aggregate(total=Sum("amount"))["total"] or 0
kpi_difference = total_amount - previous_total
-
- if previous_total:
+
+ if previous_total > 0:
percentage = (kpi_difference / previous_total) * 100
-
- if kpi_difference is not None:
- if kpi_difference > 0:
- kpi_trend = "up"
- elif kpi_difference < 0:
- kpi_trend = "down"
- else:
- kpi_trend = "equal"
-
- kpi_difference_abs = abs(kpi_difference) if kpi_difference is not None else None
-
- # ------------------
- # Previous expenses by category
- # ------------------
-
+
+ if kpi_difference > 0:
+ kpi_trend = "up"
+ elif kpi_difference < 0:
+ kpi_trend = "down"
+
+ # Comparison by category
previous_by_category = previous_expenses.values("category__name").annotate(total=Sum("amount"))
-
- current_map = {row["category__name"]: row["total"] for row in by_category}
-
- previous_map = {row["category__name"]: row["total"] for row in previous_by_category}
- all_categories = set(current_map) | set(previous_map)
-
- category_comparison = []
- for category in all_categories:
- current_total = current_map.get(category, 0)
- previous_total_cat = previous_map.get(category, 0)
- difference = current_total - previous_total_cat
-
- category_comparison.append(
- {
- "category": category,
- "current": current_total,
- "previous": previous_total_cat,
- "difference": difference,
- "difference_abs": abs(difference),
- }
- )
-
- # ------------------
- # Previous expenses by category
- # ------------------
+ current_map = {row["category__name"]: float(row["total"]) for row in by_category}
+ previous_map = {row["category__name"]: float(row["total"]) for row in previous_by_category}
+
+ for cat in set(current_map) | set(previous_map):
+ cur_t = current_map.get(cat, 0)
+ prev_t = previous_map.get(cat, 0)
+ category_comparison.append({
+ "category": cat,
+ "current": cur_t,
+ "previous": prev_t,
+ "difference": cur_t - prev_t,
+ "difference_abs": abs(cur_t - prev_t)
+ })
+
+ # Anual evolution by accounts
accounts_charts = []
- for account in accounts:
- monthly_data = account.monthly_balance(selected_year)
- m_balance = [row["balance"] for row in monthly_data]
- accounts_charts.append(
- {
- "id": account.id,
- "name": account.name,
- "data": m_balance,
- "current_balance": account.current_balance(),
- }
- )
+ for acc in accounts:
+ try:
+ monthly_data = acc.monthly_balance(selected_year)
+ m_balance = [float(row["balance"]) for row in monthly_data]
+ except:
+ m_balance = [0] * 12
+
+ if selected_year == today.year:
+ current_month_index = today.month - 1
+
+ if current_month_index < len(m_balance):
+ m_balance[current_month_index] = float(acc.current_balance())
+ m_balance = m_balance[:today.month]
+
+ accounts_charts.append({
+ "id": acc.id,
+ "name": acc.name,
+ "data": m_balance,
+ "current_balance": acc.current_balance(),
+ })
+
# Goals
goals = Goal.objects.filter(owner=request.user)
@@ -468,11 +467,11 @@ def dashboard(request):
{
"active_menu": "dashboard",
"by_category": by_category,
- "by_month": by_month,
+ "by_category_chart": by_category_chart,
"chart_labels": chart_labels,
"chart_data": chart_totals,
"year_list": year_list,
- "months": months,
+ "months": list(range(1, 13)),
"selected_year": selected_year,
"selected_month": selected_month,
"kpi_total": total_amount,
@@ -481,7 +480,7 @@ def dashboard(request):
"compare_enabled": compare_enabled,
"kpi_previous_total": previous_total,
"kpi_difference": kpi_difference,
- "kpi_difference_abs": kpi_difference_abs,
+ "kpi_difference_abs": abs(kpi_difference),
"kpi_percentage": percentage,
"category_comparison": category_comparison,
"kpi_trend": kpi_trend,