from actual import Actual import os from dotenv import load_dotenv from actual.queries import get_budgets, get_categories, get_category, get_transactions from datetime import datetime from moneyed import Money, USD from moneyed.l10n import format_money import json import re import pprint load_dotenv() pp=pprint.PrettyPrinter(indent=4) TODAY = datetime.now() MONTH_DAY = TODAY.strftime("%Y%m") MONTHSTR = TODAY.strftime("%B") MONTHDAYDATE = datetime.strptime(MONTH_DAY, "%Y%m") ONBUDGETACCOUNTS = os.getenv('ONBUDGETACCOUNTS') def simple_track(actual): main_dict = {} main_list = [] budget = get_budgets(actual.session) for b in budget: if b.month == int(MONTH_DAY) and b.amount > 0: cats = get_categories(actual.session) for cat in cats: if cat.id == b.category_id: if cat.name == "Income": formatted_amount = str(b.amount)[:-2] + "." + str(b.amount)[-2:] expected_income = Money(formatted_amount, USD) main_dict[cat.name] = {"Expected Income": expected_income, "Actual Income": Money(0, USD), "Total Spent": Money(0, USD), "Amount Left Against Budget": Money(0, USD)} category_transcations(sesh=actual.session, main_list=main_dict, origin="simple") def main(actual): main_dict = {} main_list = [] budget = get_budgets(actual.session) for b in budget: if b.month == int(MONTH_DAY) and b.amount > 0: cats = get_categories(actual.session) for cat in cats: if cat.id == b.category_id: # if cat.name == "Kid's Activities": formatted_amount = str(b.amount)[:-2] + "." + str(b.amount)[-2:] budgeted_amount = Money(formatted_amount, USD) main_dict[cat.name] = {"budgeted_amount": budgeted_amount, "amount_spent": "", "amount_left": ""} # main_dict = {"category": cat.name, "month": MONTHSTR, "budgeted_amount": budgeted_amount, "amount_spent": "", "amount_left": ""} print(main_dict) category_transcations(sesh=actual.session, main_list=main_dict, origin="all_cats") def category_transcations(sesh, main_list, origin): if origin == "simple": this_monhth_income = get_transactions(sesh, category='Income', start_date=MONTHDAYDATE) income_sum = Money(0, USD) for ti in this_monhth_income: income = str(ti.amount)[:-2] + "." + str(ti.amount)[-2:] total_income = Money(income, USD) income_sum += total_income this_month_trans = get_transactions(sesh, account='onbudget', start_date=MONTHDAYDATE) curr_sum = Money(0, USD) count = 0 for ta in this_month_trans: if ta.category_id != '3c1699a5-522a-435e-86dc-93d900a14f0e' and ta.account.id in ONBUDGETACCOUNTS: tamount = str(ta.amount)[:-2] + "." + str(ta.amount)[-2:] total_sum = Money(tamount, USD) curr_sum += total_sum count += 1 amount_left = curr_sum + main_list['Income']['Expected Income'] main_list['Income']['Expected Income'] = main_list['Income']['Expected Income'] main_list['Income']['Actual Income'] = income_sum main_list['Income']['Amount Left Against Budget'] = amount_left main_list['Income']['Total Spent'] = curr_sum # print(f"curr_sum: {curr_sum} PLUS total_sum: {total_sum}") else: for keys, vals in main_list.items(): this_month_trans = get_transactions(sesh, category=keys, start_date=MONTHDAYDATE) curr_sum = Money(0, USD) for ta in this_month_trans: tamount = str(ta.amount)[:-2] + "." + str(ta.amount)[-2:] total_sum = Money(tamount, USD) curr_sum += total_sum # print(f"curr_sum: {curr_sum} PLUS total_sum: {total_sum}") amount_list = curr_sum + vals["budgeted_amount"] vals["budgeted_amount"] = vals['budgeted_amount'] vals["amount_spent"] = curr_sum vals["amount_left"] = amount_list # sorted_items = sorted(main_list.items(), key=lambda item: item[1]['amount_left']) # sorted_nested_dict = dict(sorted_items) # pp.pprint(sorted_nested_dict) # pp.pprint(sorted_key_val) # sorted_data = sorted(main_list, key=lambda x: main_list[x]['amount_left']) # pp.pprint(sorted_data) # sort_budgets_for_notification(sorted_data) if origin == "simple": x = format_dicts(main_list) simple_notifications(x) else: all_budgets_for_notifications(main_list) def simple_notifications(x): print(f"""Here's where you stand this month!\n {x}""") def all_budgets_for_notifications(sorted_data): negative_budget = {} no_budget_left = {} some_budget_left = {} final_tuple = () for categories, values in sorted_data.items(): # for budget_type, amount in values.items(): intmoney = values['amount_left'].amount if intmoney == 0: # no_budget_left.append((categories, values) ) no_budget_left[categories] = values elif intmoney < 0: # negative_budget.append((categories, values)) negative_budget[categories] = values else: # some_budget_left.append(( categories, values) ) some_budget_left[categories] = values final_tuple = (format_dicts(some_budget_left), format_dicts(negative_budget), format_dicts(no_budget_left)) print(f"""**This is an automated message!** Here's your spending status so far for this month.\nFirst, here are the categories where you've overspent:\n{final_tuple[1]}.\n\nHere is where you still have some budget left:\n{final_tuple[0]}.\n\nAnd finally, here is where you're exactly where you need to be. $0 left.\n {final_tuple[2]}""") def format_dicts(budgets_sorted): x = str(budgets_sorted)[10:] # y = re.search(r"(\'\w*\':)|(\'\w{1,9}\s\w{1,9})|(\d*.\d{2})", x).group() y = (x .replace("{'", "") .replace("}", "") .replace("Money('", "") .replace("'", "") .replace(", USD", "") .replace(")","") .replace("(","") .replace('"', '') ) z = re.sub(r"((([A-Z][a-z]*( | & )){1,2}[A-Z][a-z]*:)|([A-Z][a-z]*)|529 Contrib)", '\n\\1', y) t = re.sub(r", \n", '\n', z) h = re.sub(r'([a-z]*_[a-z]*)',lambda x: x[1].replace('_', ' ').capitalize(), t) p = re.sub(r'(\d{1,5}.\d{2})', '$\\1', h) o = re.sub(r'(\d{4,5})', lambda x: x[1][:-3]+','+x[1][-3:], p) return o # categies = str([x['category'] for x in negative_budget ])[1:-1].replace('"','').replace("'",'') # categies2 = str([x['category'] for x in some_budget_left ])[1:-1].replace('"','').replace("'",'') # categies3 = str([x['category'] for x in no_budget_left ])[1:-1].replace('"','').replace("'",'') # print(f"""Here's your spending status so far for this month. First, here are the categories where you've overspent:\n- {str(categies)}.\n\nHere is where you still have some budget left:\n- {str(categies2)}.\n\nAnd finally, here is where you're exactly where you need to be. $0 left.\n- {str(categies3)}""") if __name__ == "__main__": with Actual( base_url=os.getenv('BASEURL'), password=os.getenv('PASSWORD'), encryption_password=None, # Optional: Password for the file encryption. Will not use it if set to None. file=os.getenv('FILE') ) as actual: # main(actual) simple_track(actual)