# Import required libraries import pandas as pd from datetime import datetime import matplotlib.pyplot as plt import getpass import calendar import sys # Program class stores the methods and attributes required to run the Smart Personal Finance Manager application. class Program: # try-except block: Stores login credientials in the user_data dataframe. try: user_data = pd.read_csv("user_data.csv") # pd.read_csv method: Creates a Pandas dataframe called user_data that stores the login credientials of users from the user_data.csv file if it exists. except: # If the user_data.csv file does not exist or if there is an issue with the file, the code below runs. user_data = pd.DataFrame(columns=["username", "password"]) # pd.DataFrame function: Creates a Pandas dataframe called user_data that stores the login credentials of users. Use the columns argument to create the columns for username and password. # __init__ function: Initializes the attributes for the username, password, CSV files, and CSV file names, setting these attributes to None to represent the absence of a value in these attributes. def __init__(self): self.username = None self.__password = None self.__transaction_data = None self.budget_data = None self.transaction_csv_name = None self.budget_csv_name = None self.start_menu() # Calls the start_menu method. # save_data method: Stores the transaction and budget data in the respective csv files using the to_csv function. def save_data(self): # Conditional statement: Saves the user's transaction and budget data if the user is logged in. if self.username != None: # Create variables for the transaction data and budget data CSV files using the username and by concatenating the username to the corresponding string for the file name. self.transaction_csv_name = self.username + "_transaction_data.csv" self.budget_csv_name = self.username + "_budget_data.csv" # to_csv method: Stores the user's new data from their current session in the respective CSV files, using the data in the transaction_data and budget_data dataframes. self.__transaction_data.to_csv(self.transaction_csv_name, index=False) self.budget_data.to_csv(self.budget_csv_name, index=False) # start_menu method: Provides the user options for creating an account or login. def start_menu(self): # Try-except block: Recieves the user input for the option as an integer. If an invalid input is given, the start_menu method is called again so that the user can enter a valid input. try: option = int(input("Welcome to the Smart Personal Finance Manager! Select 1 to create an account or 2 to login: ")) except: print("Invalid option. Please try again.") self.start_menu() # If-else statement: Compares the user input to the integer that corresponds to the selected option and calls the method for the given option. if option == 1: self.create_account() elif option == 2: self.login() # create_account method: Receives the user input for their username and password, adds the login credentials to the user_data dataframe and CSV, creates two new dataframes and CSV files for the user's transaction and budget data. def create_account(self): print("Welcome to the Smart Personal Finance Manager account creation page!") # Recieves the username from a user input and stores the username in the username variable as a string in lowercase. username = input("Enter your username: ").lower() # Recieves the password from a user input and stores the password in the password variable using the getpass method. password = getpass.getpass("Enter your password: ") # getpass method: Shows the user's password as star symbols (*). Source of getpass.getpass() method: https://www.geeksforgeeks.org/python/getpass-and-getuser-in-python-password-without-echo/ # Stores the user's login credentials in the new_data dateframe new_data = pd.DataFrame({"username": [username], "password": [password]}) # pd.concat method: Adds the new_data dataframe to the end of the user_data dataframe. Program.user_data = pd.concat([Program.user_data, new_data], ignore_index=True) # ignore_index argument: Relabels the indices in the user_data dataframe when new_data is added to simplify the index ranges. # to_csv method: Creates or updates the user_data.csv file Program.user_data.to_csv("user_data.csv", index=False) # Create variables for the transaction data and budget data CSV files using the username and by concatenating the username to the corresponding string for the file name. self.transaction_csv_name = username + "_transaction_data.csv" self.budget_csv_name = username + "_budget_data.csv" # pd.DataFrame: Create a Pandas dataframe called transaction_data that stores the user's income and expense transactions. Use the columns argument to create the columns for amount, transaction, category, date, and description. self.__transaction_data = pd.DataFrame(columns=["amount", "transaction", "category", "date", "description"]) # to_csv method: Creates a CSV file for the transaction data self.__transaction_data.to_csv(self.transaction_csv_name, index=False) # pd.DataFrame: Create a Pandas dataframe called budget_data that stores the user's budgets. Use the columns argument to create the columns for amount, category, date, and budget leftover. self.budget_data = pd.DataFrame(columns=["amount", "category", "date", "budget leftover"]) # to_csv method: Creates a CSV file for the budget data self.budget_data.to_csv(self.budget_csv_name, index=False) print("Your account has been created.") # Call the login method self.login() # login method: Recieves the user input for their username and password, checks if the login credentials are in the user_data csv, and permits the user to login and view the menu options if the credentials are valid. def login(self): print("Welcome to the Smart Personal Finance Manager login page!") # while loop: Runs the code below until a valid username and password pair are entered. while True: # Recieves the username from a user input and stores the username in the username variable as a string in lowercase. username = input("Enter your username: ").lower() # Recieves the password from a user input and stores the password in the password variable using the getpass method. password = getpass.getpass("Enter your password: ") # If-else statement: Checks if the username and password is in the CSV and permits the user to login if true by creating a username and password attribute for the instance. if username in Program.user_data["username"].values: # Use the values attribute to return the values in the username column. self.username = username # Store the username as an attribute. # Store the index of the username in the index variable, using the index method. Use the index of the username in the dataframe to store the corresponding pasword in the passowrd_check variable. index = Program.user_data.index[Program.user_data["username"] == username] # Store the password that matches the user's inputted password in the password_check variable. password_check = Program.user_data.loc[index, "password"] if password == password_check.item(): # Use the item method to return the element in the password_check variable. self.__password = password # Store the password as a private variable. try: # Store the budget_data and transaction_data CSV files for the user in the respecitve attributes. self.budget_data = pd.read_csv(username + "_budget_data.csv") self.__transaction_data = pd.read_csv(username + "_transaction_data.csv") self.__transaction_data["date"] = pd.to_datetime(self.__transaction_data["date"]) # Converts the date column in the transaction_data dataframe to datetime objects. except FileNotFoundError: # Creates new dataframes for budget_data and transaction_data if no CSV file is found. self.budget_data = pd.DataFrame(columns=["amount", "category", "date", "budget leftover"]) self.__transaction_data = pd.DataFrame(columns=["amount", "category", "date", "budget leftover"]) print("Login successful!") self.menu() # Call the menu method else: print("Your username or password is incorrect. Please try again.") # Prompts the user to enter their login credentials again if the username or password is invalid. # logout method: Saves the user's data from in the respective CSV files and calls the start_menu method. def logout(self): self.save_data() # Calls the save_data method to save the user's new data from their current session in the respective CSV files for transaction data and budget data. # Sets the username and password attributes to None, removing the user's login credentials. self.username = None self._password = None # Sets the transaction_data and budget_data attributes to none, removing the user's data. self.__transaction_data = None self.budget_data = None print("You have been logged out.") self.start_menu() # Calls the start menu. # menu method: Allows the user to select an option for the tasks they want to do on the Smart Personal Finance Manager app. def menu(self): # Print statements: Provide the user options as numbers for the tasks that the program can perform. print("Welcome to the main menu. Your options are:") print("1: Add a transaction") print("2: View transactions") print("3: Reports") print("4: Budgets") print("5: Logout") print("6: Exit") # Try-except block: Permits error exception, ensuring the user enters an integer as an input and stores a valid input in the option variable. If the user input is invalid, the menu method is called again. try: option = int(input("Please enter your option: ")) except: print("Invalid option. Please try again.") self.menu() # If-else statement: Calls the corresponding method for each number that represents an option and returns the user to the menu if the number they entered is invalid by calling the menu method. if option == 1: self.__transaction() elif option == 2: self.view_transaction() elif option == 3: self.reports() elif option == 4: self.budgets() elif option == 5: self.logout() elif option == 6: sys.exit() # Exits the program. else: print("Invalid option. Please try again.") self.menu() # budgets method: Provides the user the option to create a new budget or view their current budget. def budgets(self): # Try-except block: Permits error exception, ensuring the user enters an integer as an input and stores a valid input in the option variable. If the user input is invalid, the budgets method is called again. try: option = int(input("Select 1 to set a new budget or 2 to view your current budget: ")) except: print("Invalid option. Please try again.") self.budgets() # If-else statement: Calls the corresponding method for each number that represents an option and returns the user to the budgets menu if the number they entered is invalid by calling the budgets method. if option == 1: self.set_budget() elif option == 2: self.view_budget() else: print("Invalid option. Please try again") self.budgets() # transaction method: Provides the user the option to add an expense or income transaction. def __transaction(self): # Try-except block: Permits error exception, ensuring the user enters an integer as an input and stores a valid input in the option variable. If the user input is invalid, the transactions method is called again. try: option = int(input("Select 1 to add an expense transaction or 2 to add an income transaction: ")) except: print("Invalid option. Please try again.") self.__transaction() # If-else statement: Calls the corresponding method for each number that represents an option and returns the user to the transaction menu if the number they entered is invalid by calling the transaction method. if option == 1: self.__expense_transaction() elif option == 2: self.__income_transaction() else: print("Invalid option. Please try again") self.__transaction() # reports method: Provides the user options for the type of report they can generate. def reports(self): # Print statements: Provide the user options as numbers for the types of reports that the program can provide them. print("Select your report type.") print("1. Monthly summary") print("2. Yearly summary") print("3. Category Comparison") # Try-except block: Permits error exception, ensuring the user enters an integer as an input and stores a valid input in the option variable. If the user input is invalid, the reports method is called again. try: option = int(input("Please enter your option: ")) except: print("Invalid option. Please try again.") self.reports() # If-else statement: Calls the corresponding method for each number that represents an option and returns the user to the reports menu if the number they entered is invalid by calling the reports method. if option == 1: self.monthly_summary() elif option == 2: self.yearly_summary() elif option == 3: self.category_comparison() else: print("Invalid option. Please try again") self.reports() # monthly_summary method: Prints the summary of transactions and savings for the month that the user selects and visualizes the data in a graph. def monthly_summary(self): # While loop: Receives the user input for a month as a string in the month variable. Try-except block implements error handling for user inputs that are not strings. while True: try: month_num = int(input("Enter the month (1-12): ")) if 1 <= month_num <= 12: # Conditional statement: Checks if the user input is in the range (1-12) and breaks the loop if the user entered a valid input. break else: print("Invalid month. Please try again.") except: print("Invalid date. Please try again.") name_month = calendar.month_name[month_num] # month_name function: Returns the name of a month from the integer representing the month and stores the name in the name_month variable. # While loop: Runs the code below until a valid year is entered. while True: try: year_str = str(input("Enter the year (YYYY): ")) # Receives the user input for the year as a string and store the input in the year_str variable. year_dt = datetime.strptime(year_str, "%Y") # strptime function: Converts the year_str into a datetime object. break except: print("Invalid year. Please try again.") self.__transaction_data["date"] = pd.to_datetime(self.__transaction_data["date"]) # Converts the date column in the transaction_data dataframe to datetime objects filtered_df = self.__transaction_data[(self.__transaction_data["date"].dt.month == month_num) & (self.__transaction_data["date"].dt.year == year_dt.year)] # Filters the transaction dataframe by the user's inputted month and year. # Calculates the sum of the entries in the amount column that are income transactions using the sum function and stores the sum in the income variable. income = filtered_df.loc[filtered_df["transaction"] == "income", "amount"].sum() # Calculates the sum of the entries in the amount column that are expense transactions using the sum function and stores the sum in the expenses variable. expenses = filtered_df.loc[filtered_df["transaction"] == "expense", "amount"].sum() savings = income - expenses # Calculates the savings by finding the difference between income and expenses and stroes this value in the savings variable. # Print statements: Prints the total income, expenses, and savings for the selected month. print(f"Monthly Summary for {name_month} {year_dt.year}") print("Total income:", income) print("Total expenses:", expenses) print("Total savings:", savings) # monthrange function: Determines the number of days in a given month and year and stores the value in the num_days variable. num_days = calendar.monthrange(year_dt.year, month_num)[1] # Stores the days as a list of integers in the days variable. days = list(range(1, num_days + 1)) # Create empty lists to store the sum of income and expense transactions by day, respectively. income_by_day = [] expenses_by_day = [] # for loop: Iterates over the days in the days list. For each day, an income_sum and expenses_sum variable are created and appended to the income_by_day and expenses_by_day lists, respectively, by filtering the data by transaction type, day, month, and year. for i in days: income_sum = self.__transaction_data.loc[(self.__transaction_data["transaction"] == "income") & (self.__transaction_data["date"].dt.day == i) & (self.__transaction_data["date"].dt.month == month_num) & (self.__transaction_data["date"].dt.year == year.year)]["amount"].sum() income_by_day.append(income_sum) expenses_sum = self.__transaction_data.loc[(self.__transaction_data["transaction"] == "expense") & (self.__transaction_data["date"].dt.day == i) & (self.__transaction_data["date"].dt.month == month_num) & (self.__transaction_data["date"].dt.year == year.year)]["amount"].sum() expenses_by_day.append(expenses_sum) # Create a line graph using Matplotlib to show the income and expense transactions over time. plt.title("Transactions over Time") # Title the graph. plt.plot(days, income_by_day, label="Income") # Plot the income_by_day data by day and label the data "Income". plt.plot(days, expenses_by_day, label="Expenses") # Plot the expense_by_day data by day and label the data "Expenses". plt.xlabel("Month") # Label the x axis of the graph. plt.ylabel("Amount ($)") # Label the y axis of the graph. plt.legend() # Show the legend containing the labels for the income and expense data. plt.show() # Show the graph. self.menu() # Call the menu method. # yearly_summary method: Prints the summary of transactions and savings for the year that the user selects and visualizes the data in a graph. def yearly_summary(self): # While loop: Runs the code below until a valid year is entered. while True: try: year_str = str(input("Enter the year (YYYY): ")) # Receives the user input for the year as a string and store the input in the year_str variable. year_dt = datetime.strptime(year_str, "%Y") # strptime function: Convert the year_str into a datetime object. break except: print("Invalid year. Please try again.") self.__transaction_data["date"] = pd.to_datetime(self.__transaction_data["date"]) # Converts the date column in the transaction_data dataframe to datetime objects filtered_df = self.__transaction_data[(self.__transaction_data["date"].dt.year == year_dt.year)] # Filters the transaction dataframe by the user's inputted year. # Calculates the sum of the entries in the amount column that are income transactions using the sum function and stores the sum in the income variable. income = filtered_df.loc[filtered_df["transaction"] == "income", "amount"].sum() # Calculates the sum of the entries in the amount column that are expense transactions using the sum function and stores the sum in the expenses variable. expenses = filtered_df.loc[filtered_df["transaction"] == "expense", "amount"].sum() savings = income - expenses # Calculates the savings by finding the difference between income and expenses and stroes this value in the savings variable. # Print statements: Prints the total income, expenses, and savings for the selected year. print(f"Yearly Summary for {year_dt.year}") print("Total income:", income) print("Total expenses:", expenses) print("Total savings:", savings) date_list = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] # Stores the abbreviated month names in the date list. # Create empty lists to store the sum of income and expense transactions by month, respectively. income_by_month = [] expenses_by_month = [] # for loop: Iterates over the months in the range of 1-12. For each month, an income_sum and expenses_sum variable are created and appended to the income_by_month and expenses_by_month lists, respectively, by filtering the data by transaction type, month, and year. for month in range(12): income_sum = self.__transaction_data.loc[(self.__transaction_data["transaction"] == "income") & (self.__transaction_data["date"].dt.month == month + 1) & (self.__transaction_data["date"].dt.year == year_dt.year)]["amount"].sum() income_by_month.append(income_sum) expenses_sum = self.__transaction_data.loc[(self.__transaction_data["transaction"] == "expense") & (self.__transaction_data["date"].dt.month == month + 1) & (self.__transaction_data["date"].dt.year == year_dt.year)]["amount"].sum() expenses_by_month.append(expenses_sum) # Create a line graph using Matplotlib to show the income and expense transactions over time. plt.title("Transactions over Time") # Title the graph. plt.plot(date_list, income_by_month, label="Income") # Plot the income_by_month data and label the data "Income" plt.plot(date_list, expenses_by_month, label="Expenses") # Plot the expense_by_month data and label the data "Expenses" plt.xlabel("Month") # Label the x axis of the graph. plt.ylabel("Amount ($)") # Label the y axis of the graph. plt.legend() # Show the legend containing the labels for the income and expense data. plt.show() # Show the graph. self.menu() # Call the menu method. # category_comparison method: Prints the summary of the user's expenses by category and visualizes the data in a pie chart. def category_comparison(self): # For each category, use the get_category_expenses function to return the expenses of the category. utilities = self.get_category_expenses("utilities") transportation = self.get_category_expenses("transportation") food = self.get_category_expenses("food") other = self.get_category_expenses("other") # Print statements: Prints the total expenses per each category. print("Expenses by Category:") print("Utilities:", utilities) print("Transportation:", transportation) print("Food:", food) print("Other:", other) # Create a pie chart using Matplotlib to show the user's expenses by category pie_labels = ["Utilities", "Transportation", "Food", "Miscellaneous"] # pie_labels variable stores the names of each category in a list. data = [utilities, transportation, food, other] # data variable stores the sum of the expenses in each category as a list. # Conditional statement: Checks if there is data to plot in the pie chart. if sum(data) == 0: print("No expenses to display in the pie chart.") else: plt.title("Expenses by category") # Title the pie chart. plt.pie(data, labels = pie_labels, autopct="%1.0f%%") # Create a pie chart using the expenses by category data and use the pie_labels list for the labels of each datum. Use the autopct parameter to label the wedges. plt.show() # Show the pie chart. self.menu() # Call the menu method. # get_category_expenses method: Returns the amount of the expenses for a given category. The method takes category as an argument. def get_category_expenses(self, category): # Subtracts the budget total of the selected category from the total amount of expenses in the category. This amount is stored in the expenses variable. expenses = self.budget_data.loc[self.budget_data["category"] == category]["amount"].item() - self.budget_data.loc[self.budget_data["category"] == category]["budget leftover"].item() return expenses # Calling the get_category_expenses method will return the expenses variable (the expenses for the given category). # set_budget method: Prompts user to set their budget for the categories (utilities, transportation, food, and others) and uses the set_budget_entry method to enter each entry into the budget_data dataframe. def set_budget(self): print("Set your monthly budgets for the following categories:") # while loop: Runs the code below until a valid input is entered. while True: # try-except block: Stores the user's inputted budget in the utilities variable if a valid input is provided. Otherwise, the user is prompted to enter a valid input. try: utilities = float(input("Enter your monthly utilities budget: ")) self.set_budget_entry("utilities", utilities) break except: print("Invalid entry. Please try again.") # while loop: Runs the code below until a valid input is entered. while True: # try-except block: Stores the user's inputted budget in the transportation variable if a valid input is provided. Otherwise, the user is prompted to enter a valid input. try: transportation = float(input("Enter your monthly transportation budget: ")) self.set_budget_entry("transportation", transportation) break except: print("Invalid entry. Please try again.") # while loop: Runs the code below until a valid input is entered. while True: # try-except block: Stores the user's inputted budget in the food variable if a valid input is provided. Otherwise, the user is prompted to enter a valid input. try: food = float(input("Enter your monthly food budget: ")) self.set_budget_entry("food", food) break except: print("Invalid entry. Please try again.") # while loop: Runs the code below until a valid input is entered. while True: try: # try-except block: Stores the user's inputted budget in the others variable if a valid input is provided. Otherwise, the user is prompted to enter a valid input. others = float(input("Enter your monthly budget for miscellaneous expenses: ")) self.set_budget_entry("others", others) break except: print("Invalid entry. Please try again.") self.save_data() # Calls the save_data method. print("Your budgets have been set.") self.menu() # Calls the menu method after the budgets have been set. # set_budget_entry method: Adds a budget entry of a given amount for a specific category to the budget_data dataframe. def set_budget_entry(self, category, amount): # Stores the budget entry in the new_data dateframe. The amount variable is added to the amount column, the category variable is added to the category variable, the datetime.today() method returns the current date, and the amount is added to the budget leftover column. new_data = pd.DataFrame({"amount": [amount], "category": category, "date": datetime.today(), "budget leftover": [amount]}) # pd.concat method: Adds the new_data dataframe to the end of the budget_data dataframe. self.budget_data = pd.concat([self.budget_data, new_data], ignore_index=True) # income_transaction method: Receives user input for an income entry and stores the income transaction in the transaction_data dataframe. def __income_transaction(self): # while loop: Runs the code below until a valid date is entered. while True: # try-except block: Recieves the user input for amount of the income transaction as a float and stores the value in the amount variable. If an invalid input is given, the user is prompted to enter a valid input. try: amount = float(input("Enter the amount of the income: ")) break except: print("Invalid entry. Please try again.") # while loop: Runs the code below until a valid date is entered. while True: # try-except block: Recieves the user input for the date as a string and converts the data into a datetime object. If an invalid input is given, the user is prompted to enter a valid input. try: date_str = str(input("Enter the date of the expense in DD/MM/YYYY format: ")) datetime_object = datetime.strptime(date_str, "%d/%m/%Y") # datetime.strptime method: Converts the date from a string to a date-time format using the datetime library break except: print("Invalid date. Please try again.") description = str(input("Enter a description for the income: ")) # Prompts the user for a description using the input function and stores the input as a string in the description variable. # Stores the user's income transaction in the new_data dateframe. new_data = pd.DataFrame({"amount": [amount], "transaction": ["income"], "category": ["N/A"], "date": [datetime_object], "description": [description]}) # pd.concat method: Adds the new_data dataframe to the end of the transaction_data dataframe. self.__transaction_data = pd.concat([self.__transaction_data, new_data], ignore_index=True) self.save_data() # Calls the save_data method. print("Your income transaction has been recorded.") self.menu() # Calls the menu method after the income transaction has been recorded. # expense_transaction method: Receives user input for an expense entry and stores the expense transaction in the transaction_data dataframe. def __expense_transaction(self): # The user's input for their desired category is stored as a lowercase string in the category variable. category = input("Select the category of the expense: Utilities, transportation, food, or miscellaneous. ").lower() # Conditional statement: Checks if user's input in the category variable does not match any of the provided categories and calls the expense_transsaction method if it does not to permit the user to enter a valid input. if category not in ["utilities", "transportation", "food", "miscellaneous"]: print("Invalid category. Please try again.") self.__expense_transaction() # Calls the expense_transaction method. # while loop: Runs the code below until a valid date is entered. while True: # try-except block: Recieves the user input for amount of the expense transaction as a float and stores the value in the amount variable. If an invalid input is given, the user is prompted to enter a valid input. try: amount = float(input("Enter the amount of the expense: ")) break except: print("Invalid entry. Please try again.") # Conditional statement: Alerts the user when they are inputting a transaction that will exceed their budget. if amount > self.budget_data.loc[self.budget_data["category"] == category]["budget leftover"].item(): print(f"ALERT: You have exceeded your {category} budget of {self.budget_data.loc[self.budget_data["category"] == category, "amount"].item} for the month!") # while loop: Runs the code below until a valid date is entered. while True: # try-except block: Recieves the user input for the date as a string and converts the data into a datetime object. If an invalid input is given, the user is able to enter a valid input. try: date_str = str(input("Enter the date of the expense in DD/MM/YYYY format: ")) datetime_object = datetime.strptime(date_str, "%d/%m/%Y") # datetime.strptime method: Convert the date from a string to a date-time format using the datetime library break except: print("Invalid date. Please try again.") description = str(input("Enter a description for the expense: ")) # Prompts the user for a description using the input function and stores the input as a string in the description variable. # Stores the user's expense transaction in the new_data dateframe. new_data = pd.DataFrame({"amount": [amount], "transaction": ["expense"], "category": [category], "date": [datetime_object], "description": [description]}) # pd.concat method: Adds the new_data dataframe to the end of the transaction_data dataframe. self.__transaction_data = pd.concat([self.__transaction_data, new_data], ignore_index=True) # Subtracts the amount variable from the budget leftover column of the category inputted by the user. self.budget_data.loc[self.budget_data["category"] == category, "budget leftover"] -= amount print("Your expense transaction has been recorded.") try: self.alert(date, category) # Calls the alert method to check if the user is close to exceeding their budget. finally: self.save_data() # Calls the save_data method. self.menu() # Calls the menu method after the expense transaction has been recorded. # view_budget method: Prints the budget_data dataframe. def view_budget(self): # Conditional statement: Checks whether the budget_data dataframe has data and prints the dataframe if it contains data. if self.budget_data.empty: print("Budget has not been set.") else: print(self.budget_data.to_string(index=False)) # Prints the budget_data dataframe as a string and in a tabular format without showing the index using the to_string method. self.menu() # Calls the menu method after budget_data is printed. # view_transaction method: Prints the transaction_data dataframe, permitting the user to filter the transactions by date or category if wanted. def view_transaction(self): # Conditional statement: Checks if there is data in the transactions_data dataframe and permits the user to filter and print the data if the dataframe is not empty. if self.__transaction_data.empty: print("No transactions found.") else: # Recieves the user input and stores it in the option variable in lowercase letters. option = input("Would you like to filter the data (yes/no)?").lower() # if-else statement: Compares the user input, option, to the conditions for filtering the transaction_data dataframe and filters the dataframe according to the user's inputs. if option == "yes": filter = input("Filter by date or category?").lower() # Nested if-else statement: Permits the user to filter the transaction data by date or category. Uses try-except blocks for error handling of invalid inputs. if filter == "date": while True: try: date = str(input("Enter the date in DD/MM/YYYY format: ")) print(self.__transaction_data.loc[self.__transaction_data["date"] == date]) break except: print("Invalid date. Please try again.") elif filter == "category": while True: try: category = input("Enter the category: ").lower() print(self.__transaction_data.loc[self.__transaction_data["category"] == category]) break except: print("Invalid category. Please try again.") else: print("Invalid option. Please try again.") self.view_transaction() # Calls the view_transaction method if the user entered an invalid input. elif option == "no": print(self.__transaction_data.to_string(index=False)) # Prints the transaction_data dataframe as a string and in a tabular format without showing the index using the to_string method. else: print("Invalid option. Please try again.") self.view_transaction() # Calls the view_transaction method if the user entered an invalid input. self.menu() # Calls the menu method after the transaction data is printed. # alert method: Prints a message to the user if they are close to exceeding their budget. def alert(self, date, category): # For loop: Iterates over the categories in the list. for category in ["utilities", "transportation", "food", "miscellaneous"]: # Conditional statement: Checks if the budget leftover in a given category is greater than or equal to 75% of the amount in the same category and prints an alert that the user is close to exceeding their budget if true. if self.budget_data.loc[self.budget_data["category"] == category, "budget leftover"].item >= (0.75 * self.budget_data.loc[self.budget_data["category"] == category, "amount"].item): print(f"ALERT: You are close to exceeding your {category} budget of {self.budget_data.loc[self.budget_data["category"] == category, "amount"].item} for the month!") # Prints a message to the user, alerting them that they are close to exceeding their budget. current_user = Program() # Create an object of the Program class called current_user.