Itech1400 Foundations Of Programming: Resembles Assessment Answers
You are tasked with creating an application that uses a GUI that simulates a simple banking interface similar to an ATM / online banking using the Python 3 programming language.
The assignment is broken up into five main components:
1.) The ability to provide an account number and a PIN (Personal Identification Number) to sign into a bank account,
2.) The ability to view the balance of the bank account and to deposit and withdraw virtual money into and out from the account,
3.) The ability to save transactions via file storage so that you can log in, deposit some money and then log out – and when you log back in that money is still there, and finally
4.) The ability to display a graph of projected earnings on the bank account via the compound interest accrued over a variable amount of time.
5.) A Test Case that ensures your BankAccount's deposit and withdraw functionality operates correctly.
Your report should consist of three Python scripts that implement this application as described in the following pages: bankaccount.py, main.py along with a testbankaccount.py which contains a small test case with a few simple unit tests than ensure that your bank accounts deposit_funds and withdraw_funds methods operate correctly.
You are provided with a 'stub' of each of these files which contain all the function declarations and comments which describe the role of the function and how it can be put together, but you will have to write the code for vast majority of the functions yourself. You are also provided with a stub of the bankaccounttestcase.py file.
Answer:
Introduction
This assignment involved developing a python application that resembles an ATM. Tkinter has been used to build the graphical user interface. All requirements and specification have been met and thorough testing has been done to ensure that the application functions as it expected. Error handling has been implemented whenever necessary to catch possible error.
Python Code With Changes.
main.py
….
#Creates a window
win = tk.Tk()
# Set window size to '440x640' pixels
win.geometry("440x640")
# Set window Title to 'FedUni Banking'
win.winfo_toplevel().title("FedUni Banking")
# The account number entry and associated variable
account_number_var = tk.StringVar()
account_number_entry = tk.Entry(win, textvariable=account_number_var)
# Let the account number have the cursor when the app begins
account_number_entry.focus_set()
# The pin number entry and associated variable.
# PIN numbers are shown as asterisks (i.e. **** not 1234)
pin_number_var = tk.StringVar()
account_pin_entry = tk.Entry(win, text='PIN Number', textvariable=pin_number_var, show='*')
# 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_entry = tk.Entry(win)
# The transaction text widget holds text of the accounts transactions
transaction_text_widget = tk.Text(win, height=10, width=48)
# The bank account object we will work with
account = BankAccount()
# ---------- 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
account_pin_entry.delete(0,'end')
def handle_pin_button(event):
'''Function to add the number of the button clicked to the PIN number entry via its associated variable.'''
try:
UserPIN = pin_number_var.get()
# Limit UserPIN to 4 characters
if len(UserPIN) > 3:
raise Exception("Your PIN should not be more than 4 characters")
# Set the new pin number on the pin_number_var
UserPIN = pin_number_var.get()
UserPIN = UserPIN + event.widget['text']
pin_number_var.set(UserPIN)
# Let the Pin textfield posess the focus
account_pin_entry.focus_set()
# Move the cursor the cursor to the end when a new char has been appended
account_pin_entry.icursor(4)
except Exception as e:
tk.messagebox.showwarning('Pin Error', e)
def read_acc_file(ExistingAccount):
with open(ExistingAccount, 'r') as account_file:
AccountDetails = account_file.read().splitlines()
return AccountDetails
def init_trans_list(AccountDetails):
transaction_list = []
for item in range(4, len(AccountDetails), 2):
transaction_tuple = (AccountDetails[item], AccountDetails[item + 1])
transaction_list.append(transaction_tuple)
return transaction_list
def log_in(event):
'''Function to log in to the banking system using a known account number and PIN.'''
global account
global pin_number_var
global account_num_entry
UserAccount = account_number_var.get()
if len(UserAccount) == 0:
# Reset account object
account.reset()
tk.messagebox.showerror(title="Account Error", message="Please provide an account to log in.")
return
pin_number = pin_number_var.get()
if len(pin_number) != 4:
tk.messagebox.showerror(title="Pin Too Short", message="Your Pin should be 4 digits in length.")
return
ExistingAccount = UserAccount + ".txt"
#Check if the account exists
if os.path.isfile(ExistingAccount):
# Try to open the account file for reading
# Open the account file for reading
AccountDetails = read_acc_file(ExistingAccount)
if (len(AccountDetails)) >= 6:
# First line is account number
# Second line is PIN number, raise exception if the PIN entered doesn't match account PIN read
if pin_number != AccountDetails[1]:
# Display an Pin Mistmatch Error.
tk.messagebox.showerror(title="Pin Mismatch", message="Pin Invalid. Please Retry.")
account.reset()
return
# Read third and fourth lines (balance and interest rate)
balance = AccountDetails[2]
interest_rate = AccountDetails[3]
# Attempt to read a line from the account file, break if we've hit the end of the file. If we read a
# line then it's the transaction type, so read the next line which will be the transaction amount.
# and then create a tuple from both lines and add it to the account's transaction_list
transaction_list = init_trans_list(AccountDetails)
else:
balance = 0.0
interest_rate = 12.0
transaction_list = []
else:
# Create a NEW account file now that the provided account does not exist
open(ExistingAccount, "w")
balance = 0.0
interest_rate = 12.0
transaction_list = []
account.account_number = UserAccount
account.pin_number = pin_number
account.balance = float(balance)
account.interest_rate = float(interest_rate)
account.transaction_list = transaction_list
balance_label["text"] = "Balance: $" + str(balance)
pin_number_var.set("")
remove_all_widgets()
create_account_screen()
# ---------- Button Handlers for Account Screen ----------
def save_and_log_out():
'''Function to overwrite the account file with the current state of
the account object (i.e. including any new transactions), remove
all widgets and display the login screen.'''
global account
# Save the account with any new transactions
account.save_to_file()
# Reset/Initialize the bank acount object
account = BankAccount()
# Reset the account number and pin
account_number_var.set("")
pin_number_var.set("")
# Remove all widgets and display the login screen again
#Takes the user back to the login screen
remove_all_widgets()
create_login_screen()
def perform_deposit():
'''Function to add a deposit for the amount in the amount entry to the
account's transaction list.'''
global account
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
UserDeposit = amount_entry.get()
# Deposit funds
account.deposit_funds(UserDeposit)
# 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(0.0, 'end')
transaction_text_widget.insert('end', account.get_transaction_string())
transaction_text_widget.config(state='disabled')
# Change the balance label to reflect the new balance
balance_var.set("Balance: $"+str(account.balance))
# Clear the amount entry
amount_entry.delete(0, 'end')
# Update the interest graph with our new balance
plot_interest_graph()
# Catch and display exception as a 'showerror' messagebox with a title of 'Transaction Error' and the text of the exception
except Exception as err:
tk.messagebox.showerror(title="Transaction Error", message=str(err))
def perform_withdrawal():
'''Function to withdraw the amount in the amount entry from the account balance and add an entry to the transaction list.'''
global account
global amount_entry
global balance_label
global balance_var
# Try to increase the account balance and append the deposit to the account file
try:
UserWithdrawal = amount_entry.get()
# Withdraw funds
account.withdraw_funds(UserWithdrawal)
# 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(0.0, 'end')
transaction_text_widget.insert('end', account.get_transaction_string())
transaction_text_widget.config(state='disabled')
# Change the balance label to reflect the new balance
balance_var.set("Balance: $"+str(account.balance))
# Clear the amount entry
amount_entry.delete(0, 'end')
# Update the interest graph with our new balance
plot_interest_graph()
# Catch and display any returned exception as a messagebox 'showerror'
except Exception as e:
tk.messagebox.showerror(title="Transaction Error", message=str(e))
# ---------- Utility functions ----------
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_account_file():
'''Function to read a line from the accounts file but not the last newline character.
Note: The account_file must be open to read from for this function to succeed.'''
global account_file
return account_file.readline()[0:-1]
def plot_interest_graph():
'''Function to plot the cumulative interest for the next 12 months here.'''
# Generate the x and y lists which will be plotted
value_add = account.balance * account.interest_rate / 12
x = [1,2,3,4,5,6,7,8,9,10,11,12]
y = [account.balance+value_add*1, account.balance+value_add*2, account.balance+value_add*3,
account.balance+value_add*4, account.balance+value_add*5, account.balance+value_add*6,
account.balance+value_add*7, account.balance+value_add*8, account.balance+value_add*9,
account.balance+value_add*10, account.balance+value_add*11, account.balance+value_add*12
]
# Code to add the plots to the window is a little bit fiddly so you are provided with it.
# Generates a list called 'x' and a list called 'y' and the graph will be plotted correctly.
figure = Figure(figsize=(5, 2), dpi=100)
figure.suptitle('Cumulative Interest 12 Months')
a = figure.add_subplot(111)
a.plot(x, y, marker='o')
a.grid()
canvas = FigureCanvasTkAgg(figure, master=win)
canvas.draw()
graph_widget = canvas.get_tk_widget()
graph_widget.grid(row=4, column=0, columnspan=5, sticky='nsew')
# ---------- UI Screen Drawing Functions ----------
def create_login_screen():
'''Function to create the login screen.'''
# ----- Row 0 -----
# 'FedUni Banking' label here. Font size is 32.
tk.Label(win, text="FedUni Banking", font="None 32 bold").grid(row=0, columnspan=5, sticky='nsew')
# ----- Row 1 -----
# Acount Number / Pin label here
tk.Label(win, text="Account Number/PIN", justify='left').grid(row=1, column=0, sticky='nsew')
# Account number entry here
account_number_entry.grid(row=1, column=1, columnspan=2, sticky='nsew')
# Account pin entry here
account_pin_entry.grid(row=1, column=3, columnspan=2, sticky='nsew')
# ----- Row 2 -----
# Buttons 1, 2 and 3 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.
Button_tmp = tk.Button(win, text="1")
Button_tmp.bind('<Button-1>',handle_pin_button)
Button_tmp.grid(row=2, column=0, sticky='nsew')
Button_tmp = tk.Button(win, text="2")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=2, column=1, columnspan=2, sticky='nsew')
Button_tmp = tk.Button(win, text="3")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=2, column=3, columnspan=2, sticky='nsew')
# ----- Row 3 -----
# Buttons 4, 5 and 6 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.
Button_tmp = tk.Button(win, text="4")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=3, column=0, sticky='nsew')
Button_tmp = tk.Button(win, text="5")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=3, column=1, columnspan=2, sticky='nsew')
Button_tmp = tk.Button(win, text="6")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=3, column=3, columnspan=2, sticky='nsew')
# ----- Row 4 -----
# Buttons 7, 8 and 9 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.
Button_tmp = tk.Button(win, text="7")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=4, column=0, sticky='nsew')
Button_tmp = tk.Button(win, text="8")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=4, column=1, columnspan=2, sticky='nsew')
Button_tmp = tk.Button(win, text="9")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=4, column=3, columnspan=2, sticky='nsew')
# ----- Row 5 -----
# Cancel/Clear button here. 'bg' and 'activebackground' should be 'red'. Button calls 'clear_pin_entry' function.
Button_tmp = tk.Button(win, text="Cancel/Clear", bg='red', activebackground='red')
Button_tmp.bind('<Button-1>', clear_pin_entry)
Button_tmp.grid(row=5, column=0, sticky='nsew')
# Button 0 here
Button_tmp = tk.Button(win, text="0")
Button_tmp.bind('<Button-1>', handle_pin_button)
Button_tmp.grid(row=5, column=1, columnspan=2, sticky='nsew')
# Login button here. 'bg' and 'activebackground' should be 'green'). Button calls 'log_in' function.
Button_tmp = tk.Button(win, text="Log In", bg='green', activebackground='green')
Button_tmp.bind('<Button-1>', log_in)
Button_tmp.grid(row=5, column=3, columnspan=2, sticky='nsew')
# ----- Set column & row weights -----
# Set column and row weights. There are 5 columns and 6 rows (0..4 and 0..5 respectively)
for i in range(5):
win.columnconfigure(i, weight=1)
for i in range(6):
win.rowconfigure(i, weight=1)
def create_account_screen():
'''Function to create the account screen.'''
global amount_text
global amount_label
global transaction_text_widget
global balance_var
# ----- Row 0 -----
# FedUni Banking label. Font size 24.
tk.Label(win, text="FedUni Banking", font='None 24 bold').grid(row=0, column=0, columnspan=5, sticky='nsew')
# ----- Row 1 -----
# Account number label
tk.Label(win, text="Account:"+str(account.account_number)).grid(row=1, column=0, sticky='nsew')
# Balance label
balance_label.grid(row=1, column=2, sticky='nsew')
balance_var.set("Balance: $"+str(account.balance))
# Log out button
Button_tmp = tk.Button(win, text="Log Out", command=save_and_log_out)
Button_tmp.grid(row=1, column=3, columnspan=2, sticky='nsew')
# ----- Row 2 -----
# Amount label
tk.Label(win, text="Amount($)").grid(row=2, column=0, sticky='nsew')
# Amount entry
amount_entry.grid(row=2, column=2, sticky='nsew')
# Deposit button
Button_tmp = tk.Button(win, text="Deposit", command=perform_deposit)
Button_tmp.grid(row=2, column=3, sticky='nsew')
# Withdraw button
Button_tmp = tk.Button(win, text="Withdraw", command=perform_withdrawal)
Button_tmp.grid(row=2, column=4, sticky='nsew')
# 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 -----
# Declare scrollbar (text_scrollbar) here (BEFORE transaction text widget)
for child in transaction_text_widget.winfo_children():
child.destroy()
scroll = tk.Scrollbar(transaction_text_widget)
# Add transaction Text widget and configure to be in 'disabled' mode so it cannot be edited.
# Note: Set the yscrollcommand to be 'text_scrollbar.set' here so that it actually scrolls the Text widget
# 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(yscrollcommand=scroll.set, state='normal')
transaction_text_widget.delete(0.0, 'end')
transaction_text_widget.insert('end', account.get_transaction_string())
transaction_text_widget.config(state='disabled')
transaction_text_widget.grid(row=3, columnspan=5, sticky='nsew')
# Now add the scrollbar and set it to change with the yview of the text widget
scroll.config(command=transaction_text_widget.yview)
scroll.pack(side='right', fill='y')
# ----- Row 4 - Graph -----
# Call plot_interest_graph() here to display the graph
plot_interest_graph()
# ----- Set column & row weights -----
# Set column and row weights here - there are 5 rows and 5 columns (numbered 0 through 4 not 1 through 5!)
for i in range(5):
win.columnconfigure(i, weight=1)
for i in range(5):
win.rowconfigure(i, weight=1)
# ---------- Display Login Screen & Start Main loop ----------
create_login_screen()
win.mainloop()
bankaccount.py
class BankAccount():
def __init__(self):
'''Constructor to set account_number to '0', pin_number to an empty string,
balance to 0.0, interest_rate to 0.0 and transaction_list to an empty list.'''
# initialize account number : int
self.account_number = 0
# initialize pin number : string
self.pin_number = ""
# initialize balance : float
self.balance = 0.0
# initialize interest rate : float
self.interest_rate = 0.0
# initialize transaction list : list. list of two-tuples
self.transaction_list = []
def deposit_funds(self, amount):
'''Function to deposit an amount to the account balance. Raises an
exception if it receives a value that cannot be cast to float.'''
try:
UserDeposit = float(amount)
assert UserDeposit >= 0
self.balance += UserDeposit
self.transaction_list.append(("Deposit",UserDeposit))
except AssertionError :
raise Exception("You cannot Deposit negative amount. Please retry.")
except Exception:
raise Exception("Amount not valid. Please Retry")
def withdraw_funds(self, amount):
'''Function to withdraw an amount from the account balance. Raises an
exception if it receives a value that cannot be cast to float. Raises
an exception if the amount to withdraw is greater than the available
funds in the account.'''
try:
UserWithdrawal = float(amount)
#Ensure that the amount to be withdrawn is not more than the one in the account.
assert UserWithdrawal <= self.balance
if UserWithdrawal < 0:
raise Exception("Amount to be withdrawn cannot be negative.")
self.balance -= UserWithdrawal
self.transaction_list.append(("Withdrawal",UserWithdrawal))
except AssertionError :
raise Exception("Amount entered is more than the one in your account")
except Exception:
raise Exception("Withdrawal amount is invalid. Try again with a positive numeric value.")
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 "Withdrawal" on
the first line, and then the amount deposited or withdrawn on the next line.'''
UserTransaction = ""
for Trans_item in self.transaction_list:
UserTransaction = UserTransaction + str(Trans_item[0]) +"n"+ str(Trans_item[1])+"n"
UserTransaction = UserTransaction[:-1]
return UserTransaction
def save_to_file(self):
'''Function to overwrite the account text file with the current account
details. Account number, pin number, balance and interest (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.'''
account_file = str(self.account_number) + ".txt"
with open(account_file,"w") as UserAccount:
UserAccount.write(str(self.account_number)+"n")
UserAccount.write(str(self.pin_number)+"n")
UserAccount.write(str(self.balance)+"n")
UserAccount.write(str(self.interest_rate))
if len(self.transaction_list) != 0:
UserAccount.write("n")
UserAccount.write(self.get_transaction_string())
testbankaccount.py
import unittest
from bankaccount import BankAccount
class TestBankAcount(unittest.TestCase):
def setUp(self):
# Create a test BankAccount object
self.account = BankAccount()
# Provide it with some property values
self.account.account_number = 1001
# Set Default PIN to 7890
self.account.pin_number = 7890
# Set balance to 1000
self.account.balance = 1000.0
def test_legal_deposit_works(self):
# Your code here to test that depositing money using the account's
# 'deposit_funds' function adds the amount to the balance.
self.account.deposit_funds(200)
# Ensure that our balance has been updated to include the 200 that we've deposited
assert (self.account.balance) == 1000 + 200
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.account.deposit_funds("Betty")
#Ensure that the balance has not changed after the illegal_deposit
assert (self.account.balance) == 1000
def test_legal_withdrawal(self):
# Your code here to test that withdrawing a legal amount subtracts the
# funds from the balance.
self.account.withdraw_funds(50)
#Ensure that the balance has been updated after a legal withdrawal
assert (self.account.balance) == 1000 - 50
def test_illegal_withdrawal(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.account.withdraw_funds("Money")
#Ensure that the balance has not changed after the illegal_withdrawal
assert (self.account.balance) == 1000
def test_insufficient_funds_withdrawal(self):
# Your code here to test that you can only withdraw funds which are available.
# For example, if you have a balance of 500.00 dollars then that is the maximum
# that can be withdrawn. If you tried to withdraw 600.00 then a suitable exception
# should be raised and the withdrawal should NOT be applied to the account balance
# or the account's transaction list.
self.account.withdraw_funds(2000)
#Ensure that the balance has not changed after the insufficient funds withdrawal attempt
assert (self.account.balance) == 1000
def test_save_to_file(self):
# Test the function of saving file
self.account.save_to_file()
# Run the unit tests in the above test case
unittest.main(verbosity=2)
Buy Itech1400 Foundations Of Programming: Resembles Assessment Answers Online
Talk to our expert to get the help with Itech1400 Foundations Of Programming: Resembles Assessment Answers to complete your assessment on time and boost your grades now
The main aim/motive of the management assignment help services is to get connect with a greater number of students, and effectively help, and support them in getting completing their assignments the students also get find this a wonderful opportunity where they could effectively learn more about their topics, as the experts also have the best team members with them in which all the members effectively support each other to get complete their diploma assignments. They complete the assessments of the students in an appropriate manner and deliver them back to the students before the due date of the assignment so that the students could timely submit this, and can score higher marks. The experts of the assignment help services at urgenthomework.com are so much skilled, capable, talented, and experienced in their field of programming homework help writing assignments, so, for this, they can effectively write the best economics assignment help services.