Answer To: ITECH1400 – Foundations of Programming – SEM3/18 School of Science, Engineering and Information...
Ximi answered on Feb 05 2021
cfile_c_636845191878483184_36529_1/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.
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.
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.
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.
def test_illegal_entry_type(self):
# Your code here to test that adding an illegal entry type (like 'bananas'
# or such - something which is NOT a float) raises a suitable exception.
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.
# Run the unit tests in the above test case
unittest.main()
__MACOSX/cfile_c_636845191878483184_36529_1/._testmoneymanager.py
cfile_c_636845191878483184_36529_1/moneymanager.py
class MoneyManager():
def __init__(self, username, password, balance, transaction_list):
'''Constructor to set username to '', pin_number to an empty string,
balance to 0.0, and transaction_list to an empty list.'''
self.username = username
self.password = password
self.balance = balance
self.transaction_list = transaction_list
def add_entry(self, entry_type, amount):
'''Function to add and entry an 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'''
entries = ["food", "rent", "bills", "entertainment", "other"]
if entry_type.lower() not in entries:
raise ValueError("Cannot have this entry.")
if float(self.balance)-float(amount) < 0:
raise ValueError("Amount exceeds your balance")
self.transaction_list.append((entry_type, amount))
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. '''
self.transaction_list.append(("Deposit", amount))
self.balance = str(float(self.balance)+float(amount))
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.'''
string = ["\n{}\n{}".format(e, a) for e,a in self.transaction_list]
return 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 four lines - there are then two lines
per transaction as outlined in the above 'get_transaction_string'
function.'''
string = self.get_transaction_string()
with open(self.username+".txt", "w") as f:
f.write(self.username+"\n")
f.write(self.password+"\n")
f.write(self.balance)
for s in string:
f.write(s)
__MACOSX/cfile_c_636845191878483184_36529_1/._moneymanager.py
cfile_c_636845191878483184_36529_1/__pycache__/moneymanager.cpython-37.pyc
cfile_c_636845191878483184_36529_1/123456.txt
123456
7890
6500.0
Deposit
3000.0
Deposit
4000.0
Rent
2000.0
Deposit
1000
bills
1000
Deposit
1000
Deposit
1000
__MACOSX/cfile_c_636845191878483184_36529_1/._123456.txt
cfile_c_636845191878483184_36529_1/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 '540 x 640'
win.geometry("540x640")
#Set the window title to 'FedUni Money Manager'
win.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():
'''Function to clear the PIN number entry when the Clear / Cancel button is clicked.'''
# Clear the pin number entry here
user_number_entry.delete(first=0, last=END)
user_pin_entry.delete(first=0, last=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
# Set the new pin number on the pin_number_var
text = event.widget["text"]
if text in list(map(str, range(10))):
user_pin_entry.insert(END, text)
win.bind("", handle_pin_button)
def log_in():
'''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_number_entry
with open(user_number_entry.get()+".txt", "r") as f:
data = f.read().split('\n')
user = data[0]
password_ = data[1]
assert user_pin_entry.get() == password_, "Invalid password"
balance = data[2]
transaction_list = [(data[idx], data[idx+1]) for idx in range(3, len(data)-1, 2)]
user = MoneyManager(user_number_entry.get(), password_, balance, transaction_list)
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
user.save_to_file()
win.destroy()
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
# Get the cash amount to deposit. Note: We check legality inside account's deposit method
# Deposit funds
# 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.
# Change the balance label to reflect the new balance
# Clear the amount entry
# Update the interest graph with our new balance
# Catch and display exception as a 'showerror' messagebox with a title of 'Transaction Error' and the text of the 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
# Get the cash amount to use. Note: We check legality inside account's withdraw_funds method
# Get the type of entry that will be added ie rent etc
# Withdraw funds from the balance
# 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.
# Change the balance label to reflect the new balance
# Clear the amount entry
# Update the graph
# Catch and display any returned exception as a messagebox 'showerror'
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
#Your code to display the graph on the screen here - do this last
# ---------- UI Drawing Functions ----------
def create_login_screen():
'''Function to create the login screen.'''
Label(win, text='FedUni Money Manager',font=("Helvetica", 22)).grid(row=0, column=0, columnspan=3)
Label(win, text='Username/ PIN').grid(row=1, column=0)
user_number_entry.grid(row=1, column=1)
user_pin_entry.grid(row=1, column=2)
Button(text='1', width=10).grid(row=2,column=0)
Button(text='2', width=10).grid(row=2,column=1)
Button(text='3', width=10).grid(row=2,column=2)
Button(text='4', width=10).grid(row=3,column=0)
Button(text='5', width=10).grid(row=3,column=1)
Button(text='6', width=10).grid(row=3,column=2)
Button(text='7', width=10).grid(row=4,column=0)
Button(text='8', width=10).grid(row=4,column=1)
Button(text='9', width=10).grid(row=4,column=2)
Button(text='Cancel/Clear', width=10, command=clear_pin_entry, bg="red").grid(row=5,column=0)
Button(text='0', width=10).grid(row=5,column=1)
Button(text='Login', width=10,bg="green",command=log_in).grid(row=5,column=2)
def create_user_screen():
'''Function to create the user screen.'''
global amount_text
global amount_label
global transaction_text_widget
global balance_var
global win
win = tk.Tk()
win.geometry("500x600")
Label(win, text='FedUni Money Manager',font=("Helvetica", 22)).grid(row=0, column=0, columnspan=3)
Label(win, text="User Number: {}".format(user_number_entry)).grid(row=1, column=0)
Label(win, text="Balance: {}".format(user.balance)).grid(row=1, column=1)
Label(win, text="Amount ($)").grid(row=2, column=0)
amount_label = Entry(win, width=10,)
amount_label.grid(row=2, column=1)
Button(win, text='Log Out', width=10, command=save_and_log_out).grid(row=1,column=2)
Button(win,text='Deposit', width=10, \
command=lambda: user.deposit_funds(amount_label.get()))\
.grid(row=2,column=2)
lb = Listbox(win, height=5, selectmode=SINGLE)
entries = ["food", "rent", "bills", "entertainment", "other"]
for i in range(len(entries)):
lb.insert(i+1, entries[i])
lb.grid(row=3, column=1)
def get_items_list():
items = list(map(int, lb.curselection()))
item = lb.get(items[0])
return item
Button(win, text='Add Entry', width=10,\
command=lambda: user.add_entry(get_items_list(), amount_label.get()))\
.grid(row=3,column=2)
Label(win, text="Entry Type").grid(row=3, column=0)
textBox = Text(win, height=10, width=48,)
scrollb = Scrollbar(command=textBox.yview)
textBox['yscrollcommand'] = scrollb.set
textBox.grid(row=4, column=0, columnspan=3)
for idx in range(len(user.transaction_list)):
for e in user.transaction_list[idx]:
textBox.insert(INSERT, e+"\n")
#textBox.insert(INSERT, )
# ---------- Display Login Screen & Start Main loop ----------
create_login_screen()
win.mainloop()
__MACOSX/cfile_c_636845191878483184_36529_1/._main.py
__MACOSX/._cfile_c_636845191878483184_36529_1