ITECH1400 Foundations of Programming - Simple Money Manager Application Assignment help and solution!!

Assignment Help  Simple Money Manager Application Assignment

ITECH1400 - Foundations of Programming

Assignment - Money Manager

!!Get the Best Assignment Help Service for ITECH1400 Foundations of Programming Assignment!!

Assignment Overview

You are tasked with creating an application that uses a GUI that simulates a simple money manager. This tool is used to track all spending of an individual.

Documentation

Source Code:

 

moneymanager.py

class MoneyManager():

    def __init__(self):

        '''Constructor to set user_number to -555, pin_number to an empty string,

           balance to 0.0, and transaction_list to an empty list.'''

self.user_number=-555

self.pin_number=""

self.balance=0.0

self.transaction_list=[]

    def add_entry(self, amount, entry_type):

        '''Function to add entry and amount to the tool. Raises an

           exception if it receives a value for amount that cannot be cast to float. Raises an exception

           if the entry_type is not valid - i.e. not food, rent, bills, entertainment or other'''

        try:

            if entry_type not in ["Bills", "Entertainment", "Food","Other", "Rent"]:

                raise Exception("Entry type is not in the list")

entry_amount_float=float(amount)

            if entry_amount_float>self.balance:

                raise Exception("Entry Amount is more than the user balance")         

self.balance = self.balance - entry_amount_float

self.transaction_list.append((entry_type,entry_amount_float))            

        except ValueError:

            raise Exception("Entry Amount conversion is unsuccessful")

 

    def deposit_funds(self, amount):

        '''Function to deposit an amount to the user balance. Raises an

           exception if it receives a value that cannot be cast to float. '''

        try:

deposit_amount_float=float(amount)

self.balance = self.balance + deposit_amount_float

self.transaction_list.append(("Deposit",deposit_amount_float))

        except ValueError:

            raise Exception("Deposit Amount conversion is unsuccessful")

 

    def get_transaction_string(self):

        '''Function to create and return a string of the transaction list. Each transaction

           consists of two lines - either the word "Deposit" or the entry type - food etc - on

           the first line, and then the amount deposited or entry amount on the next line.'''

data_string = ""

        for transaction_entry in self.transaction_list:

data_string += transaction_entry[0] + "\n"

data_string += str(transaction_entry[1]) + "\n"

        return data_string

 

    def save_to_file(self):

        '''Function to overwrite the user text file with the current user

           details. user number, pin number, and balance (in that

           precise order) are the first three lines - there are then two lines

           per transaction as outlined in the above 'get_transaction_string'

           function.'''

        filename=str(self.user_number) + ".txt"

        with open(filename, "w") as out_file:

out_file.write(str(self.user_number)+"\n")

out_file.write(self.pin_number+"\n")

out_file.write(str(self.balance)+"\n")

out_file.write(self.get_transaction_string())

testmoneymanager.py

import unittest

from moneymanager import MoneyManager

class TestMoneyManager(unittest.TestCase):

    def setUp(self):

        # Create a test BankAccount object

self.user = MoneyManager()

        # Provide it with some initial balance values       

self.user.balance = 1000.0

    def test_legal_deposit_works(self):

        # Your code here to test that depsositing money using the account's

        # 'deposit_funds' function adds the amount to the balance.

self.user.deposit_funds(400)

self.assertEqual(self.user.balance, 1400.0)

    def test_illegal_deposit_raises_exception(self):

        # Your code here to test that depositing an illegal value (like 'bananas'

        # or such - something which is NOT a float) results in an exception being

        # raised.

self.assertRaises(Exception, self.user.deposit_funds,'amount')

 

    def test_legal_entry(self):

        # Your code here to test that adding a new entry with a a legal amount subtracts the

        # funds from the balance.

self.user.add_entry(200.0,'Rent')

self.assertEqual(self.user.balance, 800.0)

    def test_illegal_entry_amount(self):

        # Your code here to test that withdrawing an illegal amount (like 'bananas'

        # or such - something which is NOT a float) raises a suitable exception.

self.assertRaises(Exception, self.user.add_entry,'amount','Other')

    def test_illegal_entry_type(self):

        # Your code here to test that adding an illegal entry type raises a

        # suitable exception.

self.assertRaises(Exception, self.user.add_entry,900.0,'Loan')

    def test_insufficient_funds_entry(self):

        # Your code here to test that you can only spend funds which are available.

        # For example, if you have a balance of 500.00 dollars then that is the maximum

        # that can be spent. If you tried to spend 600.00 then a suitable exception

        # should be raised and the withdrawal should NOT be applied to the user balance

        # or the user's transaction list.

self.assertRaises(Exception, self.user.add_entry,2000,'Entertainment')

# Run the unit tests in the above test case

unittest.main()      

main.py

import tkinter as tk

from tkinter import *

from tkinter import messagebox

from pylab import plot, show, xlabel, ylabel

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

from matplotlib.figure import Figure

from collections import defaultdict

from pprint import pprint

import matplotlib.pyplot as plt

from moneymanager import MoneyManager

win = tk.Tk()

#Set window size here to '500 x 660'

win.geometry('500x660')

#Set the window title to 'FedUni Money Manager'

win.winfo_toplevel().title("FedUni Money Manager")

#The user number and associated variable

user_number_var = tk.StringVar()

#This is set as a default for ease of testing

user_number_var.set('123456')

user_number_entry = tk.Entry(win, textvariable=user_number_var)

user_number_entry.focus_set()

#The pin number entry and associated variables

pin_number_var = tk.StringVar()

#This is set as a default for ease of testing

pin_number_var.set('7890')

#Modify the following to display a series of * rather than the pin ie **** not 1234

user_pin_entry = tk.Entry(win, text='PIN Number', textvariable=pin_number_var, show='*')

#set the user file by default to an empty string

user_file = ''

# The balance label and associated variable

balance_var = tk.StringVar()

balance_var.set('Balance: $0.00')

balance_label = tk.Label(win, textvariable=balance_var)

# The Entry widget to accept a numerical value to deposit or withdraw

#amount_var = tk.StringVar()

tkVar=StringVar(win)

amount_entry = tk.Entry(win)

entry_type=tk.Entry(win)

# The transaction text widget holds text of the transactions

transaction_text_widget = tk.Text(win, height=10, width=48)

# The money manager object we will work with

user = MoneyManager()

# ---------- Button Handlers for Login Screen ----------

def clear_pin_entry(event):

    '''Function to clear the PIN number entry when the Clear / Cancel button is clicked.'''   

    # Clear the pin number entry here

user_pin_entry.delete(0, tk.END)

def handle_pin_button(event):

    '''Function to add the number of the button clicked to the PIN number entry.'''   

    # Limit to 4 chars in length

pin_entry_length=len(user_pin_entry.get())

    if pin_entry_length<4:

        # Set the new pin number on the pin_number_var

user_pin_entry.insert(pin_entry_length,event.widget["text"])

pin_number_var = user_pin_entry.get()

def log_in(event):

    '''Function to log in to the banking system using a known user number and PIN.'''

    global user

    global pin_number_var

    global user_file

    global user_num_entry

    # Create the filename from the entered account number with '.txt' on the end

    filename = str(user_number_entry.get()) + ".txt"

 

    # Try to open the user file for reading

    try:

        # Open the user file for reading

user_file=open(filename, "r")

        # First line is user number

user.user_number=int(read_line_from_user_file())

        # Second line is PIN number, raise exception if the PIN entered doesn't match account PIN read

user.pin_number=read_line_from_user_file()

        if not (user_pin_entry.get() == user.pin_number):

            raise Exception("PIN entered does not match user PIN")

        # Read third - balance

user.balance = float(read_line_from_user_file())

        # Section to read account transactions from file - start an infinite 'do-while' loop here

        while True:

            # Attempt to read a line from the account file, break if we've hit the end of the file.

            line = read_line_from_user_file()

            if not line:

                break

trans_type=line

            # If we read a line then it's the transaction type, so read the next line which will be the transaction amount.

trans_amount=float(read_line_from_user_file())

            # and then create a tuple from both lines and add it to the account's transaction_list

user.transaction_list.append((trans_type,trans_amount))

        # Close the file now we're finished with it

user_file.close()

 

    # Catch exception if we couldn't open the file or PIN entered did not match account PIN

    except Exception as ex:

        # Show error messagebox and & reset MoneyManager object to default...

messagebox.showerror("Error", str(ex))

        user = MoneyManager()

        #  ...also clear PIN entry and change focus to account number entry

user_pin_entry.delete(0, tk.END)

user_number_entry.focus_set()

    # Got here without raising an exception? Then we can log in - so remove the widgets and display the user screen

    else:

remove_all_widgets()

create_user_screen()

# ---------- Button Handlers for User Screen ----------

def save_and_log_out():

    '''Function  to overwrite the user file with the current state of

       the user object (i.e. including any new transactions), remove

       all widgets and display the login screen.'''

    global user

    # Save the account with any new transactions

user.save_to_file()

    # Reset the money manager object

    user = MoneyManager()

    # Reset the account number and pin to blank

user_number_entry.delete(0, tk.END)

user_pin_entry.delete(0, tk.END)

    # Remove all widgets and display the login screen again

remove_all_widgets()

create_login_screen()

def perform_deposit():

    '''Function to add a deposit for the amount in the amount entry to the

       user's transaction list.'''

    global user   

    global amount_entry

    global balance_label

    global balance_var

    # Try to increase the account balance and append the deposit to the account file

    try:

        # Get the cash amount to deposit. Note: We check legality inside account's deposit method

deposit_amount=amount_entry.get()

        # Deposit funds

user.deposit_funds(deposit_amount)

 

        # Update the transaction widget with the new transaction by calling account.get_transaction_string()

        # Note: Configure the text widget to be state='normal' first, then delete contents, then instert new

        #       contents, and finally configure back to state='disabled' so it cannot be user edited.

transaction_text_widget.config(state='normal')

transaction_text_widget.delete(1.0,tk.END)

transaction_text_widget.insert(tk.INSERT, user.get_transaction_string())

transaction_text_widget.config(state='disabled')

        # Change the balance label to reflect the new balance

balance_var.set("Balance :$" + str(user.balance))

        # Clear the amount entry

amount_entry.delete(0, tk.END)

        # Update the spending graph

plot_spending_graph()

    # Catch and display exception as a 'showerror' messagebox with a title of 'Transaction Error' and the text of the exception

    except Exception as exception:

messagebox.showerror("Transaction Error", str(exception))

def perform_transaction():

    '''Function to add the entry the amount in the amount entry from the user balance and add an entry to the transaction list.'''

    global user   

    global amount_entry

    global balance_label

    global balance_var

    global entry_type

    # Try to decrease the account balance and append the deposit to the account file

    try:

        # Get the cash amount to use. Note: We check legality inside account's withdraw_funds method

spending_amount=amount_entry.get()

       # Get the type of entry that will be added ie rent etc

type_of_entry=tkVar.get()

        # Add entry to the manger

user.add_entry(spending_amount,type_of_entry)

        # Update the transaction widget with the new transaction by calling user.get_transaction_string()

        # Note: Configure the text widget to be state='normal' first, then delete contents, then instert new

        #       contents, and finally configure back to state='disabled' so it cannot be user edited.

transaction_text_widget.config(state='normal')

transaction_text_widget.delete(1.0,tk.END)

transaction_text_widget.insert(tk.INSERT, user.get_transaction_string())

transaction_text_widget.config(state='disabled')

        # Change the balance label to reflect the new balance

balance_var.set("Balance :$" + str(user.balance))

        # Clear the amount entry

amount_entry.delete(0, tk.END)

        # Update the graph

plot_spending_graph()

    # Catch and display any returned exception as a messagebox 'showerror'

    except Exception as exception:

messagebox.showerror("Tansaction Error", str(exception))

def remove_all_widgets():

    '''Function to remove all the widgets from the window.'''

    global win

    for widget in win.winfo_children():

widget.grid_remove()

def read_line_from_user_file():

    '''Function to read a line from the users file but not the last newline character.

       Note: The user_file must be open to read from for this function to succeed.'''

    global user_file

    return user_file.readline()[0:-1]

def plot_spending_graph():

    '''Function to plot the user spending here.'''

    # YOUR CODE to generate the x and y lists here which will be plotted

x_values= ["Bills", "Entertainment", "Food","Other", "Rent"]

y_values=[0.0]*5

    for index in range(len(x_values)):

        for transaction_entry in user.transaction_list:

            if x_values[index] == transaction_entry[0]:

y_values[index]+=transaction_entry[1]

    #Your code to display the graph on the screen here - do this last

    figure = Figure(figsize=(7,3), dpi=100)

figure.suptitle("Spending Graph")

sub_plot = figure.add_subplot(1,1,1)

sub_plot.bar(x_values, y_values, 0.6,color='brown')

sub_plot.grid()

figure_canvas = FigureCanvasTkAgg(figure, master=win)

figure_canvas.show()

figure_widget = figure_canvas.get_tk_widget()

figure_widget.grid(row=5, column=0, columnspan=5, sticky="nsew")

# ---------- UI Drawing Functions ----------

def create_login_screen():

    '''Function to create the login screen.'''   

    # ----- Row 0 -----

    # 'FedUni Money Manager' label here. Font size is 28.

tk.Label(win, text="FedUni Money Manager", font=("Times New Roman", 28)).grid(row=0, column=0, columnspan=3) 

    # ----- Row 1 -----

    # Acount Number / Pin label here

tk.Label(win, text="User Number/PIN").grid(row=1,column = 0)

    # Account number entry here

user_number_entry.grid(row=1, column=1, ipadx = 30, ipady = 20)

    # Account pin entry here

user_pin_entry.grid(row=1, column=2, ipadx = 30, ipady = 20)

    # ----- Row 2 -----

    # Buttons 1, 2 and 3 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.

    button_1 = tk.Button(win, text="1", width=23, height=8)

    button_1.grid(row=2, column=0)

    button_1.bind("<Button-1>", handle_pin_button)

 

 

    button_2 = tk.Button(win, text="2", width=23, height=8)

    button_2.grid(row=2, column=1)

    button_2.bind("<Button-1>", handle_pin_button)

 

 

    button_3 = tk.Button(win, text="3", width=23, height=8)

    button_3.grid(row=2, column=2)

    button_3.bind("<Button-1>", handle_pin_button)

 

    # ----- Row 3 -----

 

    # Buttons 4, 5 and 6 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.

    button_4 = tk.Button(win, text="4", width=23, height=8)

    button_4.grid(row=3, column=0)

    button_4.bind("<Button-1>", handle_pin_button)

 

 

    button_5 = tk.Button(win, text="5", width=23, height=8)

    button_5.grid(row=3, column=1)

    button_5.bind("<Button-1>", handle_pin_button)

 

 

    button_6 = tk.Button(win, text="6", width=23, height=8)

    button_6.grid(row=3, column=2)

    button_6.bind("<Button-1>", handle_pin_button)

 

 

    # ----- Row 4 -----

 

    # Buttons 7, 8 and 9 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.

    button_7 = tk.Button(win, text="7", width=23, height=8)

    button_7.grid(row=4, column=0)

    button_7.bind("<Button-1>", handle_pin_button)

 

 

    button_8 = tk.Button(win, text="8", width=23, height=8)

    button_8.grid(row=4, column=1)

    button_8.bind("<Button-1>", handle_pin_button)

 

 

    button_9 = tk.Button(win, text="9", width=23, height=8)

    button_9.grid(row=4, column=2)

    button_9.bind('<Button-1>', handle_pin_button)

 

 

    # ----- Row 5 -----

 

    # Cancel/Clear button here. 'bg' and 'activebackground' should be 'red'. But calls 'clear_pin_entry' function.

button_clear=tk .Button(win, text="Cancel/Clear", width=23, height=10, bg = "red", activebackground = "red")

button_clear.grid(row=5, column=0)

button_clear.bind("<Button-1>", clear_pin_entry)

 

 

    # Button 0 here

    button_0 = tk.Button(win, text="0", width=23, height=10)

    button_0.grid(row=5, column=1)

    button_0.bind("<Button-1>", handle_pin_button)

 

 

    # Login button here. 'bg' and 'activebackground' should be 'green'). Button calls 'log_in' function.

button_login=tk.Button(win, text="Login", width=23, height=10, bg = "green", activebackground = "green")

button_login.grid(row=5, column=2)

button_login.bind("<Button-1>", log_in)

 

 

    # ----- Set column & row weights -----

 

    # Set column and row weights. There are 5 columns and 6 rows (0..4 and 0..5 respectively)

win.grid_columnconfigure(0, weight=1)

win.grid_columnconfigure(1, weight=1)

win.grid_columnconfigure(2, weight=1)

win.grid_rowconfigure(0, weight=1)

win.grid_rowconfigure(1, weight=1)

win.grid_rowconfigure(2, weight=1)

win.grid_rowconfigure(3, weight=1)

win.grid_rowconfigure(4, weight=1)

win.grid_rowconfigure(5, weight=1)

 

 

 

def create_user_screen():

    '''Function to create the user screen.'''

    global amount_text

    global amount_label

    global transaction_text_widget

    global balance_var

 

    # ----- Row 0 -----

 

    # FedUni Banking label here. Font size should be 24.

tk.Label(win, text='FedUni Money Manager', font=("Times New Roman", 22)).grid(row=0, column=0, columnspan=5)

 

 

    # ----- Row 1 -----

 

    # Account number label here

tk.Label(win, text=("User Number:"+str(user.user_number))).grid(row=1, column=0)

 

    # Balance label here

balance_label.grid(row=1, column=2)

balance_var.set("Balance: $" + str(user.balance))

 

 

    # Log out button here

btn_log_out=tk.Button(win, text="Log Out", width=18, height = 3, command=save_and_log_out).grid(row=1, column=4)

 

    # ----- Row 2 -----

 

    # Amount label here

tk.Label(win, text="Amount($)").grid(row=2, column=0)

    # Amount entry here

amount_entry.grid(row=2, column=2, ipadx = 10, ipady = 10)

    # Deposit button here

btn_deposit=tk.Button(win, text="Deposit", width=18, height = 3, command=perform_deposit)

btn_deposit.grid(row=2, column=4)

 

    # NOTE: Bind Deposit and Withdraw buttons via the command attribute to the relevant deposit and withdraw

    #       functions in this file. If we "BIND" these buttons then the button being pressed keeps looking as

    #       if it is still pressed if an exception is raised during the deposit or withdraw operation, which is

    #       offputting.

 

 

    # ----- Row 3 -----

    # Entry type label here

entry_label=tk.Label(win, text="Entry Type")

entry_label.grid(row=3, column=0)

 

    # Entry drop list here

    options=["Food", "Rent", "Bills", "Entertainment", "Other"]

entry_type_options=tk.OptionMenu(win,tkVar,*options)

tkVar.set(options[0])

entry_type_options.grid(row=3, column=2)

 

    # Add entry button here

add_entry_btn=tk.Button(win, text='Add Entry', width=18, height = 3, command=perform_transaction)

add_entry_btn. grid(row=3, column=4)

 

    # ----- Row 4 -----

 

    # Declare scrollbar (text_scrollbar) here (BEFORE transaction text widget)

text_scrollbar = tk.Scrollbar(win)

 

    # Add transaction Text widget and configure to be in 'disabled' mode so it cannot be edited.

transaction_text_widget.grid(row = 4, column=0, columnspan=5)   

transaction_text_widget.config(state = 'disabled')

 

    # Note: Set the yscrollcommand to be 'text_scrollbar.set' here so that it actually scrolls the Text widget

transaction_text_widget['yscrollcommand'] = text_scrollbar.set

 

    # Note: When updating the transaction text widget it must be set back to 'normal mode' (i.e. state='normal') for it to be edited

transaction_text_widget.config(state='normal')

transaction_text_widget.delete(1.0,tk.END)

transaction_text_widget.insert(tk.INSERT, user.get_transaction_string())

transaction_text_widget.config(state='disabled')

 

    # Now add the scrollbar and set it to change with the yview of the text widget

text_scrollbar.grid(row =4, column = 5, ipady = 50)

text_scrollbar.configure(command = transaction_text_widget.yview)

 

    # ----- Row 5 - Graph -----

 

    # Call plot_interest_graph() here to display the graph

plot_spending_graph()

 

    # ----- Set column & row weights -----

 

    # Set column and row weights here - there are 6 rows and 5 columns (numbered 0 through 4 not 1 through 5!)

win.grid_columnconfigure(0, weight=1)

win.grid_columnconfigure(1, weight=1)

win.grid_columnconfigure(2, weight=1)

win.grid_columnconfigure(3, weight=1)

win.grid_columnconfigure(4, weight=1)   

 

win.grid_rowconfigure(0, weight=1)

win.grid_rowconfigure(1, weight=1)

win.grid_rowconfigure(2, weight=1)

win.grid_rowconfigure(3, weight=1)

win.grid_rowconfigure(4, weight=1)

win.grid_rowconfigure(5, weight=1)

 

# ---------- Display Login Screen & Start Main loop ----------

 

create_login_screen()

win.mainloop()

 

 

 

 

 

 

 

 

 

 

 

Output:

Money Manager Output.jpg

Money Manager Output1.jpg

Money Manager Output2.jpg

The assignment is broken up into the following main components:

1.) The ability to provide a login screen to prevent other people from viewing the information contained in the tool

2.) The ability to view the current balance funds, add purchases made and deposits into the balance

3.) The ability to save the transactions to a file so that you can log in, add transactions to the application, log out and then return to find all of the transactions still there - i.e. the data is persistent.

4.) The ability to display a graph of your spending broken down by type - i.e. food, bills, rent.

5.) A Test Case that ensures that your simple money manager works as required.

!!Avail High Quality ITECH1400 Foundations of Programming Assignment Help and Tutoring Services at Expertsminds!!



Most Matched Writing Services:-
Captcha

Get Academic Excellence with Best Skilled Tutor! Order Assignment Now! Submit Assignment