helper.py

#
import re
import json
import os
from datetime import datetime

spend_categories = ['Food', 'Groceries', 'Utilities',
                    'Transport', 'Shopping', 'Miscellaneous']
choices = ['Date', 'Category', 'Cost']
spend_display_option = ['Day', 'Month']
spend_estimate_option = ['Next day', 'Next month']
update_options = {
    'continue': 'Continue',
    'exit': 'Exit'
}

budget_options = {
    'update': 'Add/Update',
    'view': 'View',
    'delete': 'Delete'
}

budget_types = {
    'overall': 'Overall Budget',
    'category': 'Category-Wise Budget'
}

data_format = {
    'data': [],
    'budget': {
        'overall': None,
        'category': None
    }
}
#

set of implemented commands and their description

commands = {
    'help': 'Display the list of commands.',
    'add': 'This option is for adding your expenses \
       \n 1. It will give you the list of categories to choose from. \
       \n 2. You will be prompted to enter the amount corresponding to your spending \
       \n 3.The message will be prompted to notify the addition of your expense with the amount,date, time and category ',
    'display': 'This option gives user a graphical representation(bar graph) of their expenditures \
        \n You will get an option to choose from day or month for better analysis of the expenses.',
    'estimate': 'This option gives you the estimate of expenditure for the next day/month. It calcuates based on your recorded spendings',
    'history': 'This option is to give you the detailed summary of your expenditure with Date, time ,category and amount. A quick lookup into your spendings',
    'delete': 'This option is to Clear/Erase all your records',
    'edit': 'This option helps you to go back and correct/update the missing details \
        \n 1. It will give you the list of your expenses you wish to edit \
        \n 2. It will let you change the specific field based on your requirements like amount/date/category',
    'budget': 'This option is to set/update/delete the budget. \
        \n 1. The Add/update category is to set the new budget or update the existing budget \
        \n 2. The view category gives the detail if budget is exceeding or in limit with the difference amount \
        \n 3. The delete category allows to delete the budget and start afresh!  '
}

dateFormat = '%d-%b-%Y'
timeFormat = '%H:%M'
monthFormat = '%b-%Y'
#

Documentation of helper.py

#

function to load .json expense record data

def read_json():
#

read_json(): Function to load .json expense record data

    try:
        if not os.path.exists('expense_record.json'):
            with open('expense_record.json', 'w') as json_file:
                json_file.write('{}')
            return json.dumps('{}')
        elif os.stat('expense_record.json').st_size != 0:
            with open('expense_record.json') as expense_record:
                expense_record_data = json.load(expense_record)
            return expense_record_data

    except FileNotFoundError:
        print("---------NO RECORDS FOUND---------")
#

write_json(user_list): Stores data into the datastore of the bot.

def write_json(user_list):
#
    try:
        with open('expense_record.json', 'w') as json_file:
            json.dump(user_list, json_file, ensure_ascii=False, indent=4)
    except FileNotFoundError:
        print('Sorry, the data file could not be found.')
#

validate_entered_amount(amount_entered): Takes 1 argument, amount_entered. It validates this amount’s format to see if it has been correctly entered by the user.

def validate_entered_amount(amount_entered):
#
    if amount_entered is None:
        return 0
    if re.match("^[1-9][0-9]{0,14}\\.[0-9]*$", amount_entered) or re.match("^[1-9][0-9]{0,14}$", amount_entered):
        amount = round(float(amount_entered), 2)
        if amount > 0:
            return str(amount)
    return 0
#

getUserHistory(chat_id): Takes 1 argument chat_id and uses this to get the relevant user’s historical data.

def getUserHistory(chat_id):
#
    data = getUserData(chat_id)
    if data is not None:
        return data['data']
    return None
#
def getUserData(chat_id):
    user_list = read_json()
    if user_list is None:
        return None
    if (str(chat_id) in user_list):
        return user_list[str(chat_id)]
    return None
#
def throw_exception(e, message, bot, logging):
    logging.exception(str(e))
    bot.reply_to(message, 'Oh no! ' + str(e))
#
def createNewUserRecord():
    return data_format
#
def getOverallBudget(chatId):
    data = getUserData(chatId)
    if data is None:
        return None
    return data['budget']['overall']
#
def getCategoryBudget(chatId):
    data = getUserData(chatId)
    if data is None:
        return None
    return data['budget']['category']
#
def getCategoryBudgetByCategory(chatId, cat):
    if not isCategoryBudgetByCategoryAvailable(chatId, cat):
        return None
    data = getCategoryBudget(chatId)
    return data[cat]
#
def canAddBudget(chatId):
    return (getOverallBudget(chatId) is None) and (getCategoryBudget(chatId) is None)
#
def isOverallBudgetAvailable(chatId):
    return getOverallBudget(chatId) is not None
#
def isCategoryBudgetAvailable(chatId):
    return getCategoryBudget(chatId) is not None
#
def isCategoryBudgetByCategoryAvailable(chatId, cat):
    data = getCategoryBudget(chatId)
    if data is None:
        return False
    return cat in data.keys()
#
def display_remaining_budget(message, bot, cat):
    chat_id = message.chat.id
    if isOverallBudgetAvailable(chat_id):
        display_remaining_overall_budget(message, bot)
    elif isCategoryBudgetByCategoryAvailable(chat_id, cat):
        display_remaining_category_budget(message, bot, cat)
#
def display_remaining_overall_budget(message, bot):
    print('here')
    chat_id = message.chat.id
    remaining_budget = calculateRemainingOverallBudget(chat_id)
    print("here", remaining_budget)
    if remaining_budget >= 0:
        msg = '\nRemaining Overall Budget is $' + str(remaining_budget)
    else:
        msg = '\nBudget Exceded!\nExpenditure exceeds the budget by $' + \
            str(remaining_budget)[1:]
    bot.send_message(chat_id, msg)
#
def calculateRemainingOverallBudget(chat_id):
    budget = getOverallBudget(chat_id)
    history = getUserHistory(chat_id)
    query = datetime.now().today().strftime(getMonthFormat())
    queryResult = [value for index, value in enumerate(
        history) if str(query) in value]

    return float(budget) - calculate_total_spendings(queryResult)
#
def calculate_total_spendings(queryResult):
    total = 0

    for row in queryResult:
        s = row.split(',')
        total = total + float(s[2])
    return total
#
def display_remaining_category_budget(message, bot, cat):
    chat_id = message.chat.id
    remaining_budget = calculateRemainingCategoryBudget(chat_id, cat)
    if remaining_budget >= 0:
        msg = '\nRemaining Budget for ' + cat + ' is $' + str(remaining_budget)
    else:
        msg = '\nBudget for ' + cat + \
            ' Exceded!\nExpenditure exceeds the budget by $' + \
            str(abs(remaining_budget))
    bot.send_message(chat_id, msg)
#
def calculateRemainingCategoryBudget(chat_id, cat):
    budget = getCategoryBudgetByCategory(chat_id, cat)
    history = getUserHistory(chat_id)
    query = datetime.now().today().strftime(getMonthFormat())
    queryResult = [value for index, value in enumerate(
        history) if str(query) in value]

    return float(budget) - calculate_total_spendings_for_category(queryResult, cat)
#
def calculate_total_spendings_for_category(queryResult, cat):
    total = 0

    for row in queryResult:
        s = row.split(',')
        if cat == s[1]:
            total = total + float(s[2])
    return total
#

getSpendCategories(): This functions returns the spend categories used in the bot. These are defined the same file.

def getSpendCategories():
#
    return spend_categories
#

getSpendDisplayOptions(): This functions returns the spend display options used in the bot. These are defined the same file.

def getSpendDisplayOptions():
#
    return spend_display_option
#
def getSpendEstimateOptions():
    return spend_estimate_option
#

getCommands(): This functions returns the command options used in the bot. These are defined the same file.

def getCommands():
#
    return commands
#

getCommands(): This functions returns the command options used in the bot. These are defined the same file.

def getDateFormat():
#
    return dateFormat
#

def getTimeFormat(): This functions returns the time format used in the bot.

def getTimeFormat():
#
    return timeFormat
#

def getMonthFormat(): This functions returns the month format used in the bot.

def getMonthFormat():
#
    return monthFormat
#
def getChoices():
    return choices
#
def getBudgetOptions():
    return budget_options
#
def getBudgetTypes():
    return budget_types
#
def getUpdateOptions():
    return update_options