diff --git a/financeplanner/calc.py b/financeplanner/calc.py
index 9af722b..9f0ab01 100644
--- a/financeplanner/calc.py
+++ b/financeplanner/calc.py
@@ -6,6 +6,10 @@ from django.db.models import Q
from financeplanner.utils import current_date
+days_per_year = Decimal("365.25")
+days_per_month = days_per_year / Decimal("12")
+days_per_week = Decimal("7")
+
def _floor_to_first_two_places(dec):
if dec < 100:
@@ -21,6 +25,9 @@ class ActualTransaction:
self.subject = subject
self.amount = amount
+ def __str__(self):
+ return f"ActualTransaction({self.date}, {self.subject}, {self.amount})"
+
class DailyStat:
def __init__(self, date, balance_amount, actual_transactions, resulting_amount):
@@ -32,6 +39,10 @@ class DailyStat:
self.color_class = ""
self.opacity_class = ""
+ def __str__(self):
+ return f"DailyStat({self.date}, {self.balance_amount}, " \
+ f"{len(self.actual_transactions)} a. transactions, {self.resulting_amount})"
+
def generate_graph_bar_attributes(self, amount_scale, today):
if self.resulting_amount is not None:
self.percentage = int((self.resulting_amount / amount_scale) * 100)
@@ -68,6 +79,9 @@ class Statistics:
self.avg_monthly_income = 0
self.avg_monthly_expenses = 0
self.avg_monthly_result = 0
+ self.avg_daily_irregular_expenses = 0
+ self.avg_weekly_irregular_expenses = 0
+ self.avg_monthly_irregular_expenses = 0
self._fetch_relevant_balances()
self._fetch_relevant_transactions()
@@ -150,7 +164,7 @@ class Statistics:
if transaction.date == iter_date:
actual_transactions.append(transaction)
if iter_amount is not None:
- iter_amount -= transaction.amount
+ iter_amount += transaction.amount
if iter_amount is not None:
self.daily_stats.append(DailyStat(
@@ -174,20 +188,38 @@ class Statistics:
def _calculate_analysis(self):
booked = Q(booking_date__lte=self.today)
- incoming = Q(amount__lt=0)
- outgoing = Q(amount__gt=0)
+ incoming = Q(amount__gt=0)
+ outgoing = Q(amount__lt=0)
recurring = Q(recurring_months__isnull=False) & (
Q(not_recurring_after__isnull=True) | Q(not_recurring_after__gte=self.today))
in_trans = self.user.transactions.filter(booked & incoming & recurring)
in_trans_per_month = [t.amount / t.recurring_months for t in in_trans]
- self.avg_monthly_income = -sum(in_trans_per_month)
+ self.avg_monthly_income = sum(in_trans_per_month)
out_trans = self.user.transactions.filter(booked & outgoing & recurring)
out_trans_per_month = [t.amount / t.recurring_months for t in out_trans]
self.avg_monthly_expenses = sum(out_trans_per_month)
- self.avg_monthly_result = self.avg_monthly_income - self.avg_monthly_expenses
+ self.avg_monthly_result = self.avg_monthly_income + self.avg_monthly_expenses
+
+ daily_irregular_expenses = []
+ if len(self.balances) > 1:
+ for i in range(1, len(self.balances)):
+ previous_balance = self.balances[i - 1]
+ current_balance = self.balances[i]
+ day_before = current_balance.date - relativedelta(days=1)
+ relevant_stats = [s for s in self.daily_stats if s.date == day_before]
+ if relevant_stats and day_before > previous_balance.date:
+ assert len(relevant_stats) == 1, \
+ f"daily stats should be unique per date, but here are {relevant_stats}"
+ amount_diff = current_balance.amount - relevant_stats[0].resulting_amount
+ time_diff = current_balance.date - previous_balance.date
+ daily_irregular_expenses.append(amount_diff / time_diff.days)
+ if daily_irregular_expenses:
+ self.avg_daily_irregular_expenses = sum(daily_irregular_expenses) / len(daily_irregular_expenses)
+ self.avg_weekly_irregular_expenses = self.avg_daily_irregular_expenses * days_per_week
+ self.avg_monthly_irregular_expenses = self.avg_daily_irregular_expenses * days_per_month
def get_daily_stats_in_range(self):
return [s for s in self.daily_stats if self.start <= s.date <= self.end]
diff --git a/financeplanner/templates/financeplanner/index.html b/financeplanner/templates/financeplanner/index.html
index 474d68e..f8c1044 100644
--- a/financeplanner/templates/financeplanner/index.html
+++ b/financeplanner/templates/financeplanner/index.html
@@ -44,36 +44,38 @@
Analysis
+
current average amounts per month:
- | current average monthly income |
+ income |
{{ avg_monthly_income|euro }} |
- | current average monthly expenses |
+ expenses |
{{ avg_monthly_expenses|euro }} |
- | current average monthly result |
+ result |
{{ avg_monthly_result|euro }} |
+
average irregular expenses based on the last half-a-year:
- | irregular expenses / month |
- 0 |
+ monthly |
+ {{ avg_monthly_irregular_expenses|euro }} |
- | irregular expenses / week |
- 0 |
+ weekly |
+ {{ avg_weekly_irregular_expenses|euro }} |
- | irregular expenses / day |
- 0 |
+ daily |
+ {{ avg_daily_irregular_expenses|euro }} |
diff --git a/financeplanner/views.py b/financeplanner/views.py
index 17a31c7..8461fe3 100644
--- a/financeplanner/views.py
+++ b/financeplanner/views.py
@@ -18,5 +18,8 @@ def index(request):
"avg_monthly_income": statistics.avg_monthly_income,
"avg_monthly_expenses": statistics.avg_monthly_expenses,
"avg_monthly_result": statistics.avg_monthly_result,
+ "avg_daily_irregular_expenses": statistics.avg_daily_irregular_expenses,
+ "avg_weekly_irregular_expenses": statistics.avg_weekly_irregular_expenses,
+ "avg_monthly_irregular_expenses": statistics.avg_monthly_irregular_expenses,
}
return render(request, "financeplanner/index.html", context)