Пример #1
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)
Пример #2
0
def change_budget_amounts(budg_data, budg_path):
    """
    Changes budget amounts selected by the user
    """
    done = False
    while not done:
        print(env.OUTPUT_SEP_STR)
        prompt = "Which budget month would you like to edit eh? (q) to abort: "
        dates = util.select_indices_of_list(prompt,
                                            list(budg_data.keys()),
                                            return_matches=True,
                                            abortchar='q')
        if dates is None:  # none type returned if user aborts
            return None

        for date in dates:
            print(f"--- Editing {date} ---")
            expenses = util.select_dict_keys_using_integer(
                budg_data[date],
                "Select the expenses you wish to change: ",
                print_children=False,
                quit_str='q',
                print_vals=True)
            if expenses is not None:  # quit if user says so.
                for exp in expenses:
                    amnt = util.get_float_input(
                        f"Enter the new amount for '{exp}': ",
                        force_pos=True,
                        roundto=2)
                    budg_data[date][exp] = amnt
            else:
                continue

        data_help.write_to_jsonFile(budg_path, budg_data)
Пример #3
0
def edit_expense_name(exp_db_data_filepath, df, exp_recbin_path, df_rec,
                      exp_data, budg_data, exp_stor_data, exp_path, budg_path,
                      exp_stor_data_path):
    """
    Edits an expense name across storesWithExpenses.json, Budgjet.json, expenses.json, and exp_db.csv
    """
    exps_to_edit = util.select_indices_of_list(
        "Which expense(s) would you like to edit?: ",
        exp_data[env.EXPENSE_DATA_KEY],
        abortchar='q',
        return_matches=True)
    if exps_to_edit is None:  # none type quits
        return None

    for exp_to_edit in exps_to_edit:
        if exp_to_edit != env.EXPENSE_MISC_STR:

            expense_new_name = util.select_item_not_in_list(
                f"Enter your new expense name for '{exp_to_edit}' 'q' to abort: ",
                exp_data[env.EXPENSE_DATA_KEY],
                ignorecase=False,
                abortchar='q')
            if expense_new_name is None:
                return None
            # edit the exp_stor_db
            print(f"--- Editing {env.EXP_STOR_DB_FNAME} --- ")
            for store in exp_stor_data.keys():
                if exp_to_edit in exp_stor_data[store]:
                    print(f"In {store}: ", end=" ")
                exp_stor_data[store] = util.replace_string_in_list(
                    exp_stor_data[store], exp_to_edit, expense_new_name)

            # Edit the budg_db
            print(f"\n--- Editing {env.BUDGET_FNAME} --- ")
            for date in budg_data.keys():
                budg_data[date] = data_help.modify_dict_key(
                    budg_data[date], exp_to_edit, expense_new_name)
            # Edit expenses.json
            print(f"--- Editing {env.EXP_FNAME} --- ")
            exp_data[env.EXPENSE_DATA_KEY] = util.replace_string_in_list(
                exp_data[env.EXPENSE_DATA_KEY], exp_to_edit, expense_new_name)
            # Edit exp_db.csv and (writes itself)
            print(f"--- Editing {env.OUT_EXP_DATA_TEMPL} --- ")
            edit_df_entries(df, exp_db_data_filepath, env.EXPENSE, exp_to_edit,
                            expense_new_name)
            print(f"--- Editing {env.OUT_EXPREC_DATA_TEMPL} --- ")
            edit_df_entries(df_rec, exp_recbin_path, env.EXPENSE, exp_to_edit,
                            expense_new_name)
            # Write changes
            data_help.write_to_jsonFile(budg_path, budg_data)
            data_help.write_to_jsonFile(exp_path, exp_data)
            data_help.write_to_jsonFile(exp_stor_data_path, exp_stor_data)

        else:
            print(
                f"'{env.EXPENSE_MISC_STR}' is a reserved expense category, and its name cannot be changed."
            )
Пример #4
0
def drop_rows(prompt, df):
    util.print_fulldf(df)
    rows = util.select_indices_of_list(prompt, list(
        df.index), abortchar='q', print_lst=False)
    if rows is not None:  # above returns none if user aborts
        df.drop(index=rows, inplace=True)
        return df
    else:
        return None
Пример #5
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)
Пример #6
0
def choose_months_in_dfs(df_exp, df_budg, df_inc, years):
    for year in years:
        months = data_help.extract_year_month(df_exp[year].index.to_series())
        months.sort()
        months_to_show = util.select_indices_of_list(
            f"Which months in {year} do you want to see? 'a' for all: ",
            list(months),
            return_matches=True,
            abortchar='q',
            ret_all_char='a')
        if months_to_show == None:
            return None, None, None, None
        dfs = data_help.drop_dt_indices_not_in_selection(
            months_to_show, months, [df_exp, df_budg, df_inc])

    return dfs[0], dfs[1], dfs[2], months_to_show
Пример #7
0
def edit_cell_in_dfcol(db_data_filepath: str,
                       df,
                       col_name,
                       opt_col=None,
                       opt_dict=None,
                       col_type=None):
    """
    Edits a single cell in the df based upon options provided in opt_dict
    params:
        db_data_filepath - the path to the dataframes csv data
        df - (DataFrame) object
        col_name - the column to set the new value of
        opt_col - the column to grab a key from to search opt_dict for the list of options. If none, user can edit cell manually with input
        opt_dict - the dictionary containing the pairs between keys and options for a key
        col_type - the columns type to check for on user inputs
    """
    index_list = df.index.tolist()
    util.print_fulldf(df)
    prompt = f"Select some indices from the above dataframe column '{col_name}' to edit: : "
    indices = util.select_indices_of_list(prompt,
                                          index_list,
                                          return_matches=True,
                                          abortchar='q',
                                          print_lst=False)
    if indices != None:
        for index in indices:
            if opt_col != None:
                opt_key = df.loc[index, opt_col]
                val = util.select_from_list(
                    opt_dict[opt_key],
                    f"Please select an option for cell [{index}] col '{col_name}' or (q) to quit: ",
                    abortchar='q',
                    ret_match=True)

            else:
                if col_type == 'float':
                    val = util.get_float_input(
                        f"Please input ({col_type}) for this entry at row [{index}] col [{col_name}]: ",
                        force_pos=False,
                        roundto=2)

            if val != None:  # nonetype aborts
                df.at[index, col_name] = val
                data_help.write_data(df, db_data_filepath)

            else:
                break
Пример #8
0
def search_store_relationships(storename, exp_stor_db, budg_db,
                               stor_exp_data_path, stor_db, stor_data_path):
    """
    Searches the store expense relationship (exp_stor_db) for an expense and if multiple exist, prompts the user to select one.
    params:
        storename - a store's name from the dataframe
        exp_stor_db - a python dict containing stores as keys, and arrays of expenses as values
        budg_db - expense budget dict database
        stor_exp_data_path - filepath to storesWithExpenses.json
        stor_db - the storename to store strings database
        stor_data_path - the path to stor_db
    returns: the selected expense string, and the modified exp_stor_db
    """
    exp_stor_dbKeys = exp_stor_db.keys()

    if storename not in exp_stor_dbKeys:
        storename, stor_db, exp_stor_db = select_store_for_purchase(
            storename, stor_data_path, stor_db, exp_stor_db,
            stor_exp_data_path)

    exps_fr_store = exp_stor_db[storename]

    if len(exps_fr_store) == 0:
        selected_exps = util.select_indices_of_list(
            f"No expenses for '{storename}'. Please select one or multiple to go with this store from now on.",
            list(budg_db.keys()),
            return_matches=True)
        if len(selected_exps) == 1:
            selected_exp = selected_exps[0]
        else:
            selected_exp = util.select_from_list(
                selected_exps,
                f"Please select which expense you want for this transaction at '{storename}': ",
                ret_match=True)
        exp_stor_db[storename] = selected_exps
        data_help.write_to_jsonFile(stor_exp_data_path, exp_stor_db)

    elif len(exps_fr_store) == 1:
        selected_exp = exps_fr_store[0]
    else:
        selected_exp = exps_fr_store[util.select_from_list(
            exps_fr_store,
            f"Please select an expense for this transaction at '{storename}': "
        )]

    return selected_exp, dict(exp_stor_db), stor_db, storename
Пример #9
0
def df_swap(prompt=None,
            df_to_move_from=None,
            df_to_move_to=None,
            df_to_move_from_path=None,
            df_to_move_to_path=None,
            rows=None,
            cross_check_df=None,
            cross_check_col=None,
            cross_check_df_path=None):
    """
    Performs a swap of data from one dataframe to another
    params
        prompt - the output to the user
        df_to_move_from - the dataframe to move rows from
        df_to_move_to - the dataframe to move the rows to
        rows - (default) None. If none, will prompt user, else will use the given rows to perform a swap.
        cross_check_df - perform a cross check on this dataframe for a value in cross_check_col and return matches
        cross_check_col - column to perform the cross check on
    """
    if rows is None:
        util.print_fulldf(df_to_move_from)
        rows = util.select_indices_of_list(prompt,
                                           list(df_to_move_from.index),
                                           abortchar='q',
                                           print_lst=False)
    if rows is not None:  # above returns none if user aborts
        if cross_check_df is not None:
            data_help.check_for_match_in_rows(rows, df_to_move_from,
                                              env.AMOUNT, cross_check_df,
                                              cross_check_col,
                                              cross_check_df_path,
                                              env.ADJUSTMENT)

        df_to_move_from, df_to_move_to = data_help.locate_and_move_data_between_dfs(
            df_to_move_from, rows, df_to_move_to, cross_check_col)
        data_help.write_data(df_to_move_to,
                             df_to_move_to_path,
                             sortby=env.DATE)
        data_help.write_data(df_to_move_from,
                             df_to_move_from_path,
                             sortby=env.DATE)
Пример #10
0
def add_expenses_to_store(exp_stor_data,
                          exp_stor_data_path,
                          exp_list: list,
                          force_add=False):
    """
    Adds an expense to a store within storesWithExpenses.json
    params:
        exp_stor_data : the dict object of storesWithExpenses.json
        exp_stor_data_keylist : the list of keys of exp_stor_data
        exp_list : the expense to add to the store selected by the user
        force_add : force the list of expenses into the store selection
    """
    stores = util.select_dict_keys_using_integer(
        exp_stor_data,
        "Select the store(s) you wish to add expense(s) to.",
        print_children=False,
        quit_str='q',
        print_aborting=False,
        print_vals=True)
    if stores != None:
        for store in stores:

            if not force_add:
                pair_prompt = f"Which expenses do you want to add to '{store}', separated by a space.. (q) to abort: "
                expenses = util.select_indices_of_list(pair_prompt,
                                                       exp_list,
                                                       return_matches=True,
                                                       abortchar='q')
            else:
                expenses = exp_list

            for expense in expenses:
                if expense not in exp_stor_data[store]:
                    exp_stor_data[store].append(expense)
                    print(f"Added '{expense}' to '{store}'")
                else:
                    print(
                        f"Ignoring addition! '{expense}' already is in '{store}'"
                    )

        data_help.write_to_jsonFile(exp_stor_data_path, exp_stor_data)
Пример #11
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
Пример #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
def edit_df_transaction_price(df_to_edit,
                              df_to_edit_path,
                              col_to_use,
                              df_to_move_reduction_to=None,
                              df_to_move_reduction_to_path=None,
                              df_with_reductions=None,
                              df_with_reductions_path=None,
                              reduction_col=None,
                              uuid_col=None,
                              df_reduct_uuid_col=None,
                              perform_swap=None):
    """
    params:
        df_to_edit - the dataframe to edit the price on
        col_to_use - the column across all dataframes to be using
        df_with_reductions - the dataframe carrying transaction values that can be inserted into df_to_edit
        df_to_move_reduction_to - the df that will take the reduction transaction from df_with_reductions
        reduction_col - the column to grab reduction value from
        restorable - whether the df is one which transactions can be restored from. e.g. a recycle bin
    """
    index_list = df_to_edit.index.tolist()
    util.print_fulldf(df_to_edit)
    prompt = f"Select some indices from the above dataframe column '{col_to_use}' to edit: : "
    indices = util.select_indices_of_list(prompt,
                                          index_list,
                                          return_matches=True,
                                          abortchar='q',
                                          print_lst=False)
    if indices is None:  # none type aborts
        return None

    for index in indices:
        reductions_index_list = df_with_reductions.index.tolist()
        util.print_fulldf(df_with_reductions)
        prompt = f"Which index contains the transaction you want? "
        reduction_indices = util.select_indices_of_list(prompt,
                                                        reductions_index_list,
                                                        abortchar='q',
                                                        return_matches=False,
                                                        print_lst=False)
        if reduction_indices is not None:  # none type aborts
            for reduction_index in reduction_indices:
                val = df_with_reductions.at[
                    reduction_index, reduction_col]  # get transaction val

                if df_to_edit.at[index,
                                 col_to_use] == np.nan:  # check for nan value
                    df_to_edit.at[index, col_to_use] = 0.0

                df_with_reductions.at[reduction_index,
                                      uuid_col] = df_to_edit.at[index,
                                                                uuid_col]
                df_to_edit.at[index,
                              col_to_use] = df_to_edit.at[index,
                                                          col_to_use] + val
            if perform_swap:
                df_swap(df_to_move_from=df_with_reductions,
                        df_to_move_to=df_to_move_reduction_to,
                        df_to_move_from_path=df_with_reductions_path,
                        df_to_move_to_path=df_to_move_reduction_to_path,
                        rows=reduction_indices)  # writes changes
            else:
                data_help.write_data(df_with_reductions,
                                     df_with_reductions_path,
                                     sortby=env.DATE)
        else:
            break

    data_help.write_data(df_to_edit, df_to_edit_path,
                         sortby=env.DATE)  # writes changes to the edited df.
Пример #14
0
def remove_exp_from_store(df_path, df, exp_recbin_path, df_rec, exp_stor_data,
                          exp_stor_data_path):
    """
    Removes an expense from exp_stor_data dict, replacing the reference with user selection or misc in the dataframe
    """
    prompt = "Select which store you wish to remove expense(s) from. (q) to abort."
    storenames = util.select_dict_keys_using_integer(exp_stor_data,
                                                     prompt,
                                                     print_children=False,
                                                     quit_str='q',
                                                     print_aborting=False,
                                                     print_vals=True)
    if storenames is None:
        return None

    for storename in storenames:
        removed_expenses = util.select_indices_of_list(
            "Select which expense(s) to remove. (q) to abort.",
            exp_stor_data[storename],
            return_matches=True,
            abortchar='q')
        if removed_expenses is None:
            return None

        print(f"--- Editing {env.EXP_STOR_DB_FNAME} --- ")
        for expense in removed_expenses:
            exp_stor_data[storename].remove(expense)
            print(f"Removed {expense} from {storename}.")

        if len(exp_stor_data[storename]
               ) == 0:  # if all was deleted, append misc into this store.
            print(
                f"You deleted all expenses from {storename}, I am adding {env.EXPENSE_MISC_STR} to preserve your data."
            )
            exp_stor_data[storename].append(env.EXPENSE_MISC_STR)
            new_exp = env.EXPENSE_MISC_STR

        print(
            f"--- Editing {env.OUT_EXP_DATA_TEMPL} & {env.OUT_EXPREC_DATA_TEMPL} --- "
        )
        for rem_exp in removed_expenses:
            if len(exp_stor_data[storename]) == 1:
                print(
                    f"Only expense left for '{storename}' is '{exp_stor_data[storename][0]}'. Replacing '{rem_exp}' with '{exp_stor_data[storename][0]}'."
                )
                new_exp = exp_stor_data[storename][0]
            else:

                new_exp = util.select_from_list(
                    exp_stor_data[storename],
                    f"Which expense do you want to use to replace '{rem_exp}' in '{storename}'? (q) to quit. ",
                    abortchar='q',
                    ret_match=True)
                if new_exp is None:  # user quits
                    return None

            edit_df_entries_given_columns(df, df_path, env.EXPENSE,
                                          env.FILT_STORENAME, storename,
                                          rem_exp, new_exp)
            edit_df_entries_given_columns(df_rec, exp_recbin_path, env.EXPENSE,
                                          env.FILT_STORENAME, storename,
                                          rem_exp, new_exp)

        data_help.write_to_jsonFile(exp_stor_data_path, exp_stor_data)
Пример #15
0
def remove_expense_from_dbs(exp_db_data_filepath, exp_recbin_path,
                            exp_stor_data, exp_data, budg_data, df, df_rec,
                            exp_stor_data_path, budg_path, exp_path):
    """
    Removes an expense from the storesWithExpenses.json, Budgjet.json, expenses.json
    """
    print(
        "Warning! Removing an expense is no small task. I will be pruning your store-expense database, your overall transactions, your expenses database and you budgets."
    )
    print(
        "This is irreversible, and will result in any reference to that expense being reverted to 'Misc'."
    )
    print(
        "Any budget amnt for that expense will be added to Misc to maintain balance in the force."
    )
    exps_to_rem = util.select_indices_of_list(
        "Which expense(s) would you like to go? ",
        exp_data[env.EXPENSE_DATA_KEY],
        abortchar='q',
        return_matches=True)
    if exps_to_rem is None:
        return None

    for exp_to_rem in exps_to_rem:
        if exp_to_rem != env.EXPENSE_MISC_STR:

            # delete from exp_stor db
            print(f"--- Editing {env.EXP_STOR_DB_FNAME} --- ")
            for store in exp_stor_data.keys():
                if exp_to_rem in exp_stor_data[store]:
                    exp_stor_data[store].remove(exp_to_rem)
                    print(f"Removed {exp_to_rem} from {store}.")

            # delete from expenses db
            print(f"--- Editing {env.EXP_FNAME} --- ")
            exp_data[env.EXPENSE_DATA_KEY].remove(exp_to_rem)
            print(f"Removed {exp_to_rem} from {env.EXP_FNAME}.")

            # remove from budget, adding amnt to Misc
            print(f"\n--- Editing {env.BUDGET_FNAME} --- ")
            for date in budg_data.keys():
                if exp_to_rem in budg_data[date].keys():
                    amnt_to_misc = budg_data[date][exp_to_rem]
                    budg_data[date][env.EXPENSE_MISC_STR] += amnt_to_misc
                    budg_data[date].pop(exp_to_rem)
                else:
                    print("No expense in this months budget.")

            print(f"--- Editing {env.OUT_EXP_DATA_TEMPL} --- ")
            edit_df_entries(df, exp_db_data_filepath, env.EXPENSE, exp_to_rem,
                            env.EXPENSE_MISC_STR)
            print(f"--- Editing {env.OUT_EXPREC_DATA_TEMPL} --- ")
            edit_df_entries(df_rec, exp_recbin_path, env.EXPENSE, exp_to_rem,
                            env.EXPENSE_MISC_STR)
            # write changes
            data_help.write_to_jsonFile(budg_path, budg_data)
            data_help.write_to_jsonFile(exp_path, exp_data)
            data_help.write_to_jsonFile(exp_stor_data_path, exp_stor_data)

        else:
            print(
                f"'{env.EXPENSE_MISC_STR}' is a reserved expense category, and it cannot be deleted."
            )