diff --git a/financeplanner/calc.py b/financeplanner/calc.py new file mode 100644 index 0000000..ac2e85e --- /dev/null +++ b/financeplanner/calc.py @@ -0,0 +1,80 @@ +from dateutil.relativedelta import relativedelta +from django.db.models import Q + +from financeplanner.utils import current_date + + +class ActualTransaction: + + def __init__(self, date, subject, amount): + self.date = date + self.subject = subject + self.amount = amount + + +class Statistics: + + def __init__(self, user): + self.user = user + self.today = current_date() + self.start = self.today - relativedelta(months=6) + self.end = self.today + relativedelta(months=6) + self.calc_start = self.start + self.balances = [] + self.transactions = [] + self.actual_transactions = [] + + def _fetch_relevant_balances(self): + balances = [] + balances_until_start = self.user.balances.filter(date__lte=self.start) + if balances_until_start.exists(): + balances = [balances_until_start.latest("date")] + other_balances = self.user.balances.filter(date__gt=self.start, date__lte=self.end).order_by("date") + self.balances = balances + list(other_balances) + if self.balances: + self.calc_start = self.balances[0].date + + def _fetch_relevant_transactions(self): + one_time_in_range = Q( + booking_date__gte=self.calc_start, + booking_date__lte=self.end, + recurring_months__isnull=True, + ) + endlessly_recurring = Q( + booking_date__lte=self.end, + recurring_months__isnull=False, + not_recurring_after__isnull=True, + ) + recurring_and_ending_in_range = Q( + booking_date__lte=self.end, + recurring_months__isnull=False, + not_recurring_after__gte=self.calc_start, + ) + transactions = self.user.transactions.filter( + one_time_in_range | endlessly_recurring | recurring_and_ending_in_range + ).order_by("booking_date") + self.transactions = list(transactions) + + def _calculate_actual_transactions(self): + actual_transaction = [] + for trans in self.transactions: + if trans.recurring_months: + iter_date = trans.booking_date + iter_step = 1 + limit = min(trans.not_recurring_after, self.end) if trans.not_recurring_after else self.end + while iter_date < limit: + if iter_date >= self.calc_start: + actual_transaction.append(ActualTransaction( + date=iter_date, + subject=f"{trans.subject} #{iter_step}", + amount=trans.amount, + )) + iter_date += relativedelta(months=trans.recurring_months) + iter_step += 1 + else: + actual_transaction.append(ActualTransaction( + date=trans.booking_date, + subject=trans.subject, + amount=trans.amount, + )) + self.actual_transactions = actual_transaction