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'
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