예제 #1
0
def get_expenses_for_rows(df, stor_exp_data_path, stor_data_path, budg_path,
                          bankconfig):
    """
    Gets the expense data for stores, prompting the user when multiple expenses exist for a store
    params:
        df - pandas dataframe
        stor_exp_data_path - filepath to expensesDB
    """
    print(
        "\nIterating your transactions. If you want to quit halfway, type ctrl c to save!\n"
    )

    # initialize the objects for tracking changes
    exp_stor_db = data_help.read_jsonFile(stor_exp_data_path)
    stor_db = data_help.read_jsonFile(stor_data_path)
    budg_db = data_help.read_jsonFile(budg_path)
    try:
        for idx, row in df.iterrows():
            # iterate through only the data which has no expenses declared.
            if pd.isnull(row[env.EXPENSE]):
                # get relevant expenses for that month set by the user.
                month_end_date = util.get_month_from_timestamp(row[env.DATE],
                                                               start=False)
                if type(row[env.BANK_STORENAME]) is str:
                    match = bankconfig.regex_str.search(
                        row[env.BANK_STORENAME])

                    if match:

                        processed_text = util.process_text(match.group(0))
                        print(
                            f"Was able to filter - {row[env.BANK_STORENAME]} -> {processed_text}"
                        )
                        storename = processed_text

                    else:
                        print(f"Unable to filter - {row[env.BANK_STORENAME]}")
                        storename = row[env.BANK_STORENAME]

                else:  # default case use empty str
                    print("No storename exists for this transaction.")
                    storename = ""

                print(
                    "Curr Transaction:  %-10s | %-10s | %-10s | %-10s " %
                    (row[env.DATE], row[env.AMOUNT], storename, row[env.TYPE]))
                selected_exp, exp_stor_db, stor_db, storename = search_store_relationships(
                    storename, exp_stor_db, budg_db[month_end_date],
                    stor_exp_data_path, stor_db, stor_data_path)
                df.at[idx, env.FILT_STORENAME] = storename
                df.at[idx, env.EXPENSE] = selected_exp

    except KeyboardInterrupt:
        print(
            "\n\nQuitting to main menu. Your data inputs will be saved, and you can resume where you left off by restarting and selecting 'v' for view data!\n"
        )

    return df
예제 #2
0
def get_expenses(db_exp_data_fpaths: list,
                 db_inc_data_fpaths: list,
                 stor_pair_path: str,
                 stor_exp_data_path: str,
                 budg_path: str,
                 exp_path: str,
                 dont_print_cols=None,
                 bankconfig=None):
    """
    main method for the importing of expense data
    """
    bank_json = data_help.read_jsonFile(bankconfig.settings_path)
    exp_df = data_help.load_csvs(
        db_exp_data_fpaths,
        dtype=bankconfig.exp_dtypes,
        parse_dates=env.pdates_colname
    )  # only using on csv db for now. newest will be last? idk verify later.

    exp_df = data_help.drop_for_substring(
        exp_df, env.BANK_STORENAME, bankconfig.ignorable_transactions,
        "\nRemoving the below expense transactions as they are either an internal bank acct transfer, cash advance or credit payment."
    )
    dates = data_help.extract_months(exp_df[env.DATE], start=False)
    # check for any missing budgets either this month or any month in the data
    expManager.get_budgets(budg_path, exp_path, dates)
    exp_df = expManager.get_expenses_for_rows(exp_df, stor_exp_data_path,
                                              stor_pair_path, budg_path,
                                              bankconfig)
    print("\nFinished gathering your expense data: \n")
    util.print_fulldf(exp_df, dont_print_cols)
    data_help.write_data(exp_df, db_exp_data_fpaths[0])
예제 #3
0
def edit_settings(settings_path):
    """
    Main interface for editing settings for the app
    """
    done = False
    prompt = "Please select a setting to edit: "
    while not done:
        settings = data_help.read_jsonFile(settings_path)
        setting_sels = util.select_indices_of_list(prompt,
                                                   list(settings.keys()),
                                                   return_matches=True,
                                                   abortchar='q',
                                                   print_lst=True)
        if setting_sels is None:
            return None

        for setting in setting_sels:
            if setting == env.BANK_SELECTION_KEY:
                value = util.select_indices_of_list(
                    "Please select from the list: ",
                    settings[env.BANK_CHOICES_KEY],
                    return_matches=True,
                    abortchar='q')
            else:
                data_type = type(settings[setting])
                value = util.get_input_given_type(
                    f"Enter your '{data_type}' for {setting}={settings[setting]}. ",
                    data_type,
                    abortchar='q',
                    setting=settings[setting])
            if value is not None:  # none type returned upon quit
                settings[setting] = value
                done = True
                data_help.write_to_jsonFile(settings_path, settings)
예제 #4
0
def set_dict_keys_to_lowercase(dct_path):
    """
    Function I wrote just to run on the stores exp database to keep all stores lowercase.
    """
    dct = data_help.read_jsonFile(dct_path)
    for key in dct.keys():
        dct = data_help.modify_dict_key(dct, key, key.lower())
    data_help.write_to_jsonFile(dct_path, dct)
예제 #5
0
def get_budgets(budg_path, exp_path, dates=None):
    """
    Prompts user for budgeting options given a new month if no budget is present for that month
    """
    exp_budg = data_help.read_jsonFile(budg_path)
    exp_data = data_help.read_jsonFile(exp_path)
    if dates == None:
        dates = [util.get_current_month()]
    for date in dates:
        exp_budg_keys = exp_budg.keys()
        if date not in exp_budg_keys:  # check for current month to find exp categories
            print(
                f"I have detected some data with for the month {date} that has no budget set."
            )
            print(
                "Please set the budget for this month.. or delete the data and run the program again."
            )
            if len(exp_budg) != 0:
                user_in = util.get_user_input_for_chars(
                    "Would you like to the whole thing (w) or create new (n)? ",
                    ['w', 'n'])

                if user_in == 'w':
                    key = util.select_dict_key_using_integer(
                        exp_budg,
                        "Please select a budget to copy: ",
                        print_children=True,
                        print_vals=False,
                        print_child_vals=True)
                    exp_budg[date] = exp_budg[key]
                elif user_in == 'n':
                    exp_budg[date] = declare_new_budget(date, exp_data)
            else:
                exp_budg[date] = declare_new_budget(date, exp_data)

            print(f"Your budget is now saved for {date}.")

        else:
            print(f"Your monthly budget for {date} is: ")

        util.print_simple_dict(exp_budg[date], print_vals=True)

    data_help.write_to_jsonFile(budg_path, exp_budg)
    return
예제 #6
0
def store_editor(db_exp_data_fpaths,
                 db_exprec_data_fpath,
                 stor_pair_path,
                 exp_stor_data_path,
                 budg_path,
                 exp_path,
                 bankconfig=None):
    """
    Edits a store's name across all databases.
    params:
        db_exp_data_fpaths - filepaths to expense csv's
        stor_pair_path - filepath to store name database
        exp_stor_data_path - filepath to store-expense data base
        budg_path - filepath to budget database
    """

    done = False
    while not done:
        df = data_help.load_csvs(db_exp_data_fpaths,
                                 dtype=bankconfig.exp_dtypes,
                                 parse_dates=env.pdates_colname)
        df_rec = data_help.load_csv(db_exprec_data_fpath,
                                    dtype=bankconfig.exp_dtypes,
                                    parse_dates=env.pdates_colname)
        stor_data = data_help.read_jsonFile(stor_pair_path)
        exp_stor_data = data_help.read_jsonFile(exp_stor_data_path)
        exp_data = data_help.read_jsonFile(exp_path)
        budg_db = data_help.read_jsonFile(budg_path)

        prompt = "Would you like to: \n(a) - change storenames\n(b) - edit bank to database store relationships\n(q) - quit\ntype here: "
        user_in = util.get_user_input_for_chars(prompt, ['a', 'b', 'q'])

        if user_in == 'a':
            change_storename(db_exp_data_fpaths, df, db_exprec_data_fpath,
                             df_rec, exp_stor_data, stor_data, stor_pair_path,
                             exp_stor_data_path)
        elif user_in == 'b':
            change_storepair(db_exp_data_fpaths, df, db_exprec_data_fpath,
                             df_rec, exp_stor_data, stor_data, stor_pair_path,
                             exp_stor_data_path, exp_data, budg_db)
        elif user_in == 'q':
            done = True
    return
예제 #7
0
def choose_bank(json_path: str):
    """
    Prompt user for banks
    """
    settings_json = data_help.read_jsonFile(json_path)
    if env.BANK_SELECTION_KEY not in settings_json.keys():
        prompt = f"Please choose your bank(s) from the list of banks: "
        choices = util.select_indices_of_list(prompt,
                                              env.BANK_OPTIONS,
                                              return_matches=True)
        settings_json[env.BANK_SELECTION_KEY] = choices
        data_help.write_to_jsonFile(json_path, settings_json)
예제 #8
0
def initialize_settings(settings_path):
    settings = data_help.read_jsonFile(settings_path)
    for key in env.SETTINGS_TEMPL.keys():  # add keys in globvar
        if key not in settings.keys():
            settings[key] = env.SETTINGS_TEMPL[key]

    keys_to_rem = []
    for key in settings.keys():  # remove keys not in globvar
        if key not in env.SETTINGS_TEMPL.keys():
            keys_to_rem.append(key)

    for key in keys_to_rem:
        settings.pop(key)

    data_help.write_to_jsonFile(settings_path, settings)
예제 #9
0
def budget_editor(budg_path):
    """
    Allows user to play around with the budget database
    """
    done = False

    prompt = "Would you like to \n(a) - change budget amounts\n(q) - quit?\nType here: "
    while not done:
        budg_data = data_help.read_jsonFile(budg_path)
        print(env.OUTPUT_SEP_STR)
        user_in = util.get_user_input_for_chars(prompt, ['a', 'q'])
        if user_in == 'a':
            change_budget_amounts(budg_data, budg_path)
        elif user_in == 'q':
            done = True
예제 #10
0
def notes_editor(db_exp_data_fpaths,
                 db_inc_data_fpaths,
                 notes_path,
                 bankconfig=None):
    """
    Main menu for editing notes
    """
    done = False
    while not done:
        exp_df = data_help.load_csvs(db_exp_data_fpaths,
                                     dtype=bankconfig.exp_dtypes,
                                     parse_dates=env.pdates_colname)
        inc_df = data_help.load_csvs(db_inc_data_fpaths,
                                     dtype=bankconfig.inc_dtypes,
                                     parse_dates=env.pdates_colname)
        notes_dict = data_help.read_jsonFile(notes_path)

        exp_months = data_help.extract_months(exp_df[env.DATE], start=False)
        inc_months = data_help.extract_months(inc_df[env.DATE], start=False)
        months_in_data = util.add_set_to_set(exp_months, inc_months, sort=True)

        if notes_dict == {}:
            prompt = "You have not entered any notes yet. Which month(s) would you like to add notes for? "
            edit_prompt_base = "Please enter your note below for month "

        else:
            prompt = "Please select a month to edit : "
            edit_prompt_base = "Edit your note below for month "

        sel_months = util.select_indices_of_list(
            prompt,
            list_to_compare_to=months_in_data,
            return_matches=True,
            abortchar='q')

        if sel_months is not None:
            notes = edit_notes(edit_prompt_base, notes_dict, sel_months,
                               notes_path)

        else:
            done = True
예제 #11
0
def setup_expense_names(exp_path: str):
    """
    Gets a list of expense names from the user and saves them.
    """
    exp_list = data_help.read_jsonFile(exp_path)
    if len(exp_list) == 0:
        exp_list[env.EXPENSE_DATA_KEY] = util.format_input_to_list(
            "Please input your expense categories, I will add a Misc category since it is reserved. "
        )
        idxs_matched = util.check_lst_for_values(
            exp_list[env.EXPENSE_DATA_KEY], env.MISC_POS_VALUES)
        for idx in sorted(idxs_matched, reverse=True):
            print(
                f"Found {exp_list[env.EXPENSE_DATA_KEY][idx]} in your expenses. Removing since '{env.EXPENSE_MISC_STR}' is reserved as miscellaneous category."
            )
            del exp_list[env.EXPENSE_DATA_KEY][idx]
        exp_list[env.EXPENSE_DATA_KEY].append(env.EXPENSE_MISC_STR)
        data_help.write_to_jsonFile(exp_path, exp_list)

    if env.EXPENSES_SUBTRACTED_KEY not in exp_list.keys():
        exp_list[env.EXPENSES_SUBTRACTED_KEY] = []
        data_help.write_to_jsonFile(exp_path, exp_list)
예제 #12
0
def view_money_data(db_exp_data_fpaths,
                    db_inc_data_fpaths,
                    stor_pair_path,
                    stor_exp_data_path,
                    budg_path,
                    notes_path,
                    exp_path,
                    dont_print_cols=None,
                    bankconfig=None,
                    settings_path=None):
    """
    main method for the viewing of data
    params:
        exp_path - path to expenses.json
        dont_print_cols - ignore columns for output to CLI
    """
    df_exp = data_help.load_csvs(db_exp_data_fpaths,
                                 dtype=bankconfig.exp_dtypes,
                                 parse_dates=env.pdates_colname,
                                 index=env.DATE)
    df_inc = data_help.load_csvs(
        db_inc_data_fpaths,
        dtype=bankconfig.inc_dtypes,
        parse_dates=env.pdates_colname,
        index=env.DATE)  # TODO SHOW NET INCOME ON PLOTS
    df_exp = data_help.combine_and_drop(df_exp, env.AMOUNT, env.ADJUSTMENT,
                                        'subtract')

    df_inc = data_help.combine_and_drop(df_inc, env.AMOUNT, env.ADJUSTMENT,
                                        'subtract')
    exp_dict = data_help.read_jsonFile(exp_path)

    settings = data_help.read_jsonFile(settings_path)

    if df_inc.empty:  # set index to datetime if empty.
        df_inc.set_index(pd.to_datetime(df_inc.index), inplace=True)

    budg_db = data_help.read_jsonFile(budg_path)  # load the budget data
    df_budg = pd.DataFrame(budg_db)
    df_budg = df_budg.T  # transpose to make index date str
    df_budg.set_index(pd.to_datetime(df_budg.index),
                      inplace=True)  # set index to date time

    notes_dict = data_help.read_jsonFile(notes_path)

    years = data_help.extract_years(df_exp.index.to_series())
    years_to_show = util.select_indices_of_list(
        "Which of the above year(s) would you like to take a peak at, 'a' for all: ",
        years,
        return_matches=True,
        abortchar='q',
        ret_all_char='a')

    if years_to_show is None:  # select_indices_of_list returns None if user aborts
        return None

    dfs = data_help.drop_dt_indices_not_in_selection(years_to_show, years,
                                                     [df_exp, df_budg, df_inc])
    df_exp = dfs[0]
    df_budg = dfs[1]
    df_inc = dfs[2]
    if df_exp is None:  # quit condition
        return None

    freq, freq_desc = get_plotting_frequency()
    if freq == None:
        return None

    if freq == env.YEAR_FREQ:
        plot_for_date(years,
                      dont_print_cols,
                      exp_dict,
                      df_inc,
                      df_budg,
                      df_exp,
                      settings,
                      notes_dict,
                      freq=freq,
                      freq_desc=freq_desc)
    elif freq == env.MONTH_FREQ:
        df_exp, df_budg, df_inc, months = choose_months_in_dfs(
            df_exp, df_budg, df_inc, years_to_show)
        if df_exp is None:
            return None

        plot_for_date(years,
                      dont_print_cols,
                      exp_dict,
                      df_inc,
                      df_budg,
                      df_exp,
                      settings,
                      notes_dict,
                      freq=env.MONTH_FREQ,
                      freq_desc=freq_desc,
                      months=months)
    elif freq == 'b':

        df_exp_mnth, df_budg_mnth, df_inc_mnth, months = choose_months_in_dfs(
            df_exp, df_budg, df_inc, years_to_show)
        if df_exp_mnth is None:
            return None
        plot_for_date(years,
                      dont_print_cols,
                      exp_dict,
                      df_inc_mnth,
                      df_budg_mnth,
                      df_exp_mnth,
                      settings,
                      notes_dict,
                      freq=env.MONTH_FREQ,
                      freq_desc='month',
                      override_show=True,
                      months=months)
        plot_for_date(years,
                      dont_print_cols,
                      exp_dict,
                      df_inc,
                      df_budg,
                      df_exp,
                      settings,
                      notes_dict,
                      freq=env.YEAR_FREQ,
                      freq_desc='year')

    else:
        pass
예제 #13
0
    json_paths = [
        budg_path, stor_exp_data_path, stor_pair_path, exp_path, notes_path,
        settings_path
    ]

    initialize_dirs(list_of_dirs)
    initialize_dbs(json_paths)

    # check for expense list and setup if none are there.
    expManager.setup_expense_names(exp_path)
    # check for bank choice and setup if no choice is there.
    expManager.choose_bank(settings_path)
    # initialize settings
    initialize_settings(settings_path)

    settings = data_help.read_jsonFile(settings_path)

    bankconfig = util.get_bank_conf(settings, settings_path)

    initialize_csvs([exp_recbin_path, inc_recbin_path],
                    [bankconfig.exp_colnames, bankconfig.inc_colnames])
    print("--- --- --- --- --- --- --- --- --- --- --- --- ---")
    print("--- --- --- -- SHOW ME YOUR MONEY -- --- --- --- --")
    print(f"--- --- --- --- --- V. {env.VERSION} --- --- --- --- --- ---")
    print("WELCOME TO SHOW ME YOUR MONEYYYYY COME ON DOWN!")
    quit = False
    index = 0
    bankconfigreloaded = bankconfig
    while not quit:
        print("          ----|$$| MAIN MENU |$$|----         ")
        user_in = util.get_user_input_for_chars(
예제 #14
0
def expenses_editor(db_exp_data_fpaths,
                    exp_recbin_path,
                    stor_pair_path,
                    exp_stor_data_path,
                    budg_path,
                    exp_path,
                    bankconfig=None):
    """
    Edits an expense's name across all databases
    """
    done = False
    while not done:
        exp_data = data_help.read_jsonFile(exp_path)
        df_rec = data_help.load_csv(exp_recbin_path,
                                    dtype=bankconfig.exp_dtypes,
                                    parse_dates=env.pdates_colname)
        df = data_help.load_csvs(db_exp_data_fpaths,
                                 dtype=bankconfig.exp_dtypes,
                                 parse_dates=env.pdates_colname)
        stor_data = data_help.read_jsonFile(stor_pair_path)
        exp_stor_data = data_help.read_jsonFile(exp_stor_data_path)
        budg_data = data_help.read_jsonFile(budg_path)

        prompt = "\n".join(
            ("Would you like to:", "(a) - add an expense",
             "(b) - edit an expenses name", "(c) - pair expenses to stores",
             "(d) - delete an expense **CAUTION**",
             "(e) - edit an expense within your database",
             "(f) - unpair an expense from stores",
             "(g) - add expense to be subtracted in plot title",
             "(h) - remove expense to be subtracted in plot title",
             "(q) - quit editor", "type here: "))
        user_in = util.get_user_input_for_chars(
            prompt, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'q', 's'])

        if user_in == 'a':
            add_expense(exp_data, exp_stor_data, exp_path, exp_stor_data_path)
        elif user_in == 'b':  # TODO
            edit_expense_name(db_exp_data_fpaths[0], df, exp_recbin_path,
                              df_rec, exp_data, budg_data, exp_stor_data,
                              exp_path, budg_path, exp_stor_data_path)
        elif user_in == 'c':
            add_expenses_to_store(exp_stor_data, exp_stor_data_path,
                                  exp_data[env.EXPENSE_DATA_KEY])
        elif user_in == 'd':
            remove_expense_from_dbs(db_exp_data_fpaths[0], exp_recbin_path,
                                    exp_stor_data, exp_data, budg_data, df,
                                    df_rec, exp_stor_data_path, budg_path,
                                    exp_path)
        elif user_in == 'e':
            edit_cell_in_dfcol(db_exp_data_fpaths[0],
                               df,
                               col_name=env.EXPENSE,
                               opt_col=env.FILT_STORENAME,
                               opt_dict=exp_stor_data)
        elif user_in == 'f':
            remove_exp_from_store(db_exp_data_fpaths[0], df, exp_recbin_path,
                                  df_rec, exp_stor_data, exp_stor_data_path)
        elif user_in == 'g':
            prompt = "Which expense(s) would you like to be subtracted in the title to your plots? "
            util.edit_list_in_dict(prompt,
                                   exp_data[env.EXPENSE_DATA_KEY],
                                   exp_data,
                                   env.EXPENSES_SUBTRACTED_KEY,
                                   exp_path,
                                   add=True)
        elif user_in == 'h':
            prompt = "Which expense(s) would you like to remove? "
            util.edit_list_in_dict(prompt,
                                   exp_data[env.EXPENSES_SUBTRACTED_KEY],
                                   exp_data,
                                   env.EXPENSES_SUBTRACTED_KEY,
                                   exp_path,
                                   add=False)
        elif user_in == 'q':
            done = True
        elif user_in == 's':
            print("Ah so youre an alchemist then.")
            sync_expenses(exp_data, exp_stor_data, exp_path,
                          exp_stor_data_path)