1
1

take events since the last balance into account when calculating the graph

This commit is contained in:
2020-02-18 17:47:17 +01:00
parent cdd358903b
commit f2d73b10bf

View File

@@ -10,29 +10,47 @@ from django.shortcuts import render
from financeplanner.utils import format_date from financeplanner.utils import format_date
def _get_relevant_balances(user, start, end): def _get_relevant_balances(user, range_start, range_end):
balances = user.balances.filter(date__range=(start, end)).order_by("date") balance_list = []
return list(balances) balances_until_start = user.balances.filter(date__lte=range_start)
if balances_until_start.exists():
balance_list = [balances_until_start.latest("date")]
other_balances = user.balances.filter(date__gt=range_start, date__lte=range_end).order_by("date")
return balance_list + list(other_balances)
def _get_relevant_transactions(user, start, end): def _get_relevant_transactions(user, calculation_start, range_end):
one_time_in_range = Q(
booking_date__gte=calculation_start,
booking_date__lte=range_end,
recurring_months__isnull=True,
)
endlessly_recurring = Q(
booking_date__lte=range_end,
recurring_months__isnull=False,
not_recurring_after__isnull=True,
)
recurring_and_ending_in_range = Q(
booking_date__lte=range_end,
recurring_months__isnull=False,
not_recurring_after__gte=calculation_start,
)
transactions = user.transactions.filter( transactions = user.transactions.filter(
Q(booking_date__range=(start, end)) | one_time_in_range | endlessly_recurring | recurring_and_ending_in_range
Q(booking_date__lte=end, recurring_months__isnull=False, not_recurring_after__gte=start)
).order_by("booking_date") ).order_by("booking_date")
return list(transactions) return list(transactions)
def _calculate_actual_transactions(start, end, transaction_list): def _calculate_actual_transactions(calculation_start, range_end, transaction_list):
result = [] result = []
for trans in transaction_list: for trans in transaction_list:
current_calc_trans = {} current_calc_trans = {}
if trans.recurring_months: if trans.recurring_months:
current_date = trans.booking_date current_date = trans.booking_date
step = 1 step = 1
limit = min(trans.not_recurring_after, end) if trans.not_recurring_after else end limit = min(trans.not_recurring_after, range_end) if trans.not_recurring_after else range_end
while current_date < limit: while current_date < limit:
if current_date >= start: if current_date >= calculation_start:
result.append(( result.append((
current_date, current_date,
f"{trans.subject} #{step}", f"{trans.subject} #{step}",
@@ -50,12 +68,12 @@ def _calculate_actual_transactions(start, end, transaction_list):
return result return result
def _calculate_daily_stats(start, end, balance_list, actual_transactions): def _calculate_daily_stats(calculation_start, range_end, balance_list, actual_transactions):
stats = {} stats = {}
current_date = start current_date = calculation_start
current_amount = None current_amount = None
while current_date < end: while current_date < range_end:
current_stats = { current_stats = {
"balance": None, "balance": None,
"transactions": [], "transactions": [],
@@ -87,6 +105,10 @@ def _calculate_daily_stats(start, end, balance_list, actual_transactions):
return stats return stats
def _trim_stats(stats, range_start):
return {date: stat for date, stat in stats.items() if date >= range_start}
def _floor_to_first_two_places(dec): def _floor_to_first_two_places(dec):
if dec < 100: if dec < 100:
return 100 return 100
@@ -103,7 +125,7 @@ def _calculate_scale(stats):
return _floor_to_first_two_places(max_amount * Decimal("1.3")) return _floor_to_first_two_places(max_amount * Decimal("1.3"))
def _build_graph_data(start, end, balance_list, actual_transactions): def _build_graph_data(range_start, range_end, calculation_start, balance_list, actual_transactions):
""" """
result has the format: result has the format:
{ {
@@ -125,7 +147,8 @@ def _build_graph_data(start, end, balance_list, actual_transactions):
} }
""" """
today = datetime.now().date() today = datetime.now().date()
stats = _calculate_daily_stats(start, end, balance_list, actual_transactions) stats = _calculate_daily_stats(calculation_start, range_end, balance_list, actual_transactions)
stats = _trim_stats(stats, range_start)
amount_limit = _calculate_scale(stats) amount_limit = _calculate_scale(stats)
for date in stats.keys(): for date in stats.keys():
amount = stats[date]["amount"] amount = stats[date]["amount"]
@@ -162,9 +185,10 @@ def index(request):
range_start = today - relativedelta(days=30) range_start = today - relativedelta(days=30)
range_end = today + relativedelta(days=50) range_end = today + relativedelta(days=50)
balance_list = _get_relevant_balances(user, range_start, range_end) balance_list = _get_relevant_balances(user, range_start, range_end)
transaction_list = _get_relevant_transactions(user, range_start, range_end) calculation_start = balance_list[0].date if balance_list else range_start
actual_transactions = _calculate_actual_transactions(range_start, range_end, transaction_list) transaction_list = _get_relevant_transactions(user, calculation_start, range_end)
graph_data = _build_graph_data(range_start, range_end, balance_list, actual_transactions) actual_transactions = _calculate_actual_transactions(calculation_start, range_end, transaction_list)
graph_data = _build_graph_data(range_start, range_end, calculation_start, balance_list, actual_transactions)
context = { context = {
"range_start": format_date(range_start), "range_start": format_date(range_start),
"range_end": format_date(range_end), "range_end": format_date(range_end),