from datetime import datetime from decimal import Decimal from dateutil.relativedelta import relativedelta from django.core.management import BaseCommand from core.models import Subject from core.prediction import predict_transactions past_lookup_delta = relativedelta(weeks=2) future_lookup_delta = relativedelta(months=2) class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( "--start", default="0", help="the current balance to use as a starting point for prediction", ) def handle(self, *args, **options): start_balance = Decimal(options["start"]) today = datetime.now().date() past_lookup_bound = today - past_lookup_delta future_lookup_bound = today + future_lookup_delta transaction_dict = {} for subject in Subject.objects.all(): transactions = [] for tr in subject.transactions.order_by("booking_date"): if past_lookup_bound <= tr.booking_date <= future_lookup_bound: transactions.append(tr) predicted_transaction, prediction_info = predict_transactions(subject) if predicted_transaction: first_predicted_date = predicted_transaction[0].booking_date if first_predicted_date >= past_lookup_bound: # if two weeks after the first predicted transaction have passed, the subject is considered done for tr in predicted_transaction: if past_lookup_bound <= tr.booking_date <= future_lookup_bound: transactions.append(tr) transaction_dict[subject] = (transactions, prediction_info) future_transactions = [] for subject, prediction in transaction_dict.items(): transactions, info = prediction[0], prediction[1] print(f">>> {subject}") if info: rec_days, rec_months, day_of_month = \ info["recurring_days"], info["recurring_months"], info["day_of_month"] if rec_months and day_of_month: print(f"~~~ predicted transaction on day-of-month {day_of_month} every {rec_months} month(s)") elif rec_months: print(f"~~~ predicted transaction every {rec_months} month(s)") elif rec_days: print(f"~~~ predicted transaction every {rec_days} day(s)") else: print("~~~ no prediction possible") for tr in transactions: print(f" {tr.booking_date:%d.%m.%Y} | {tr.amount} € | {'stored' if tr.pk else 'predicted'}") if tr.booking_date > today: future_transactions.append(tr) print() current_balance = start_balance print(f"starting calculation with amount {current_balance} €") for tr in sorted(future_transactions, key=lambda t: t.booking_date): current_balance += tr.amount print( f"{tr.booking_date:%d.%m.%Y} | " f"{tr.subject.name:<18} | " f"{tr.amount:>8} € ==> " f"{current_balance:>8} €" )