Files
WYGIWYH/app/apps/yearly_overview/views.py
2024-10-24 00:46:50 -03:00

176 lines
5.5 KiB
Python

from datetime import date
from decimal import Decimal
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.utils import timezone
from django.db.models import Sum, F, Q, Value, CharField, DecimalField
from django.db.models.functions import TruncMonth, Coalesce
from django.db.models.expressions import Case, When
from django.db.models.functions import Concat
from apps.transactions.models import Transaction
@login_required
def index(request):
now = timezone.localdate(timezone.now())
return redirect(to="yearly_overview", year=now.year)
def yearly_overview(request, year: int):
next_year = year + 1
previous_year = year - 1
transactions = Transaction.objects.filter(reference_date__year=year)
monthly_data = (
transactions.annotate(month=TruncMonth("reference_date"))
.values(
"month",
"account__currency__code",
"account__currency__prefix",
"account__currency__suffix",
"account__currency__decimal_places",
)
.annotate(
income_paid=Coalesce(
Sum(
Case(
When(
type=Transaction.Type.INCOME, is_paid=True, then=F("amount")
),
default=Value(Decimal("0")),
output_field=DecimalField(),
)
),
Value(Decimal("0")),
output_field=DecimalField(),
),
expense_paid=Coalesce(
Sum(
Case(
When(
type=Transaction.Type.EXPENSE,
is_paid=True,
then=F("amount"),
),
default=Value(Decimal("0")),
output_field=DecimalField(),
)
),
Value(Decimal("0")),
output_field=DecimalField(),
),
income_unpaid=Coalesce(
Sum(
Case(
When(
type=Transaction.Type.INCOME,
is_paid=False,
then=F("amount"),
),
default=Value(Decimal("0")),
output_field=DecimalField(),
)
),
Value(Decimal("0")),
output_field=DecimalField(),
),
expense_unpaid=Coalesce(
Sum(
Case(
When(
type=Transaction.Type.EXPENSE,
is_paid=False,
then=F("amount"),
),
default=Value(Decimal("0")),
output_field=DecimalField(),
)
),
Value(Decimal("0")),
output_field=DecimalField(),
),
)
.annotate(
balance_unpaid=F("income_unpaid") - F("expense_unpaid"),
balance_paid=F("income_paid") - F("expense_paid"),
balance_total=F("income_paid")
+ F("income_unpaid")
- F("expense_paid")
- F("expense_unpaid"),
)
.order_by("month", "account__currency__code")
)
# Create a list of all months in the year
all_months = [date(year, month, 1) for month in range(1, 13)]
# Create a dictionary to store the final result
result = {
month: {
"income_paid": [],
"expense_paid": [],
"income_unpaid": [],
"expense_unpaid": [],
"balance_unpaid": [],
"balance_paid": [],
"balance_total": [],
}
for month in all_months
}
# Fill in the data
for entry in monthly_data:
month = entry["month"]
currency_code = entry["account__currency__code"]
prefix = entry["account__currency__prefix"]
suffix = entry["account__currency__suffix"]
decimal_places = entry["account__currency__decimal_places"]
for field in [
"income_paid",
"expense_paid",
"income_unpaid",
"expense_unpaid",
"balance_unpaid",
"balance_paid",
"balance_total",
]:
if entry[field] != 0:
result[month][field].append(
{
"code": currency_code,
"prefix": prefix,
"suffix": suffix,
"decimal_places": decimal_places,
"amount": entry[field],
}
)
# Fill in missing months with empty lists
for month in all_months:
if not any(result[month].values()):
result[month] = {
"income_paid": [],
"expense_paid": [],
"income_unpaid": [],
"expense_unpaid": [],
"balance_unpaid": [],
"balance_paid": [],
"balance_total": [],
}
return render(
request,
"yearly_overview/pages/overview.html",
context={
"year": year,
"next_year": next_year,
"previous_year": previous_year,
"totals": result,
},
)