take events since the last balance into account when calculating the graph
This commit is contained in:
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user