estimate.py

#
import time
import helper
import logging
from telebot import types
#

Documentation of estimate.py

#

run(message, bot): This is the main function used to implement the estimate feature. It takes 2 arguments for processing - message which is the message from the user, and bot which is the telegram bot object from the main code.py function.

def run(message, bot):
#
    helper.read_json()
    chat_id = message.chat.id
    history = helper.getUserHistory(chat_id)
    if history is None:
        bot.send_message(
            chat_id, "Oops! Looks like you do not have any spending records!")
    else:
        markup = types.ReplyKeyboardMarkup(one_time_keyboard=True)
        markup.row_width = 2
        for mode in helper.getSpendEstimateOptions():
            markup.add(mode)
#

markup.add(‘Day’, ‘Month’)

        msg = bot.reply_to(
            message, 'Please select the period to estimate',
            reply_markup=markup)
        bot.register_next_step_handler(msg, estimate_total, bot)
#

estimate_total(message, bot): It takes 2 arguments for processing - message which is the message from the user, and bot which is the telegram bot object from the run(message, bot): function in the same file. This function loads the user’s data using the helper file’s getUserHistory(chat_id) method. After this, depending on the option user has chosen on the UI, it calls the calculate_estimate(queryResult, days_to_estimate): to process the queried data to return to the user after which it finally passes the data to the UI for the user to view.

def estimate_total(message, bot):
#
    try:
        chat_id = message.chat.id
        DayWeekMonth = message.text

        if DayWeekMonth not in helper.getSpendEstimateOptions():
            raise Exception(
                "Sorry I can't show an estimate for \"{}\"!".format(
                    DayWeekMonth))

        history = helper.getUserHistory(chat_id)
        if history is None:
            raise Exception(
                "Oops! Looks like you do not have any spending records!")

        bot.send_message(chat_id, "Hold on! Calculating...")
#

show the bot “typing” (max. 5 secs)

        bot.send_chat_action(chat_id, 'typing')
        time.sleep(0.5)

        total_text = ""
        days_to_estimate = 0
        if DayWeekMonth == 'Next day':
            days_to_estimate = 1
        elif DayWeekMonth == 'Next month':
            days_to_estimate = 30
#

query all that contains today’s date query all that contains all history

        queryResult = [value for index, value in enumerate(history)]

        total_text = calculate_estimate(queryResult, days_to_estimate)

        spending_text = ""
        if len(total_text) == 0:
            spending_text = "You have no estimate for {}!".format(DayWeekMonth)
        else:
            spending_text = "Here are your estimated spendings"
            spending_text += " for the " + DayWeekMonth.lower()
            spending_text += ":\nCATEGORIES,AMOUNT \n----------------------\n"
            spending_text += total_text

        bot.send_message(chat_id, spending_text)
    except Exception as e:
        logging.exception(str(e))
        bot.reply_to(message, str(e))
#

calculate_estimate(queryResult, days_to_estimate): Takes 2 arguments for processing - queryResult which is the query result from the estimate total function in the same file. It parses the query result and turns it into a form suitable for display on the UI by the user. days_to_estimate is a variable that tells the function to calculate the estimate for a specified period like a day or month.

def calculate_estimate(queryResult, days_to_estimate):
#
    total_dict = {}
    days_data_available = {}
    for row in queryResult:
#

date,cat,money

        s = row.split(',')
#

cat

        cat = s[1]
        date_str = s[0][0:11]
        if cat in total_dict:
#

round up to 2 decimal

            total_dict[cat] = round(total_dict[cat] + float(s[2]), 2)
        else:
            total_dict[cat] = float(s[2])
        if date_str not in days_data_available:
            days_data_available[date_str] = True

    total_text = ""
    for key, value in total_dict.items():
        category_count = len(days_data_available)
        daily_avg = value / category_count
        estimated_avg = round(daily_avg * days_to_estimate, 2)
        total_text += str(key) + " $" + str(estimated_avg) + "\n"
    return total_text