Jul-12-2018, 01:45 AM
UPDATE ON PROGRAM
I wanted to post an update on my program, it's come a long way and I have learned a lot. I spent today and yesterday working on improving the code and implementing some changes and I'd like to post the new files here.
main.py
OUTPUTS
Login Screen
I hope to continue to improve this program. I want to start really learning GUI using Tkinter in python so I can move this to a nicer, more aesthetically pleasing interface.
I wanted to post an update on my program, it's come a long way and I have learned a lot. I spent today and yesterday working on improving the code and implementing some changes and I'd like to post the new files here.
main.py
import bankAccount import os from Account import Account def main(): while True: acct_num, pin = bankAccount.login() # Create User Account object user_account = Account(acct_num, pin) while True: os.system("CLS") user_menu = bankAccount.show_user_menu(user_account.get_name(), user_account.get_balance()) if user_menu == 'Deposit': user_account.make_deposit() if user_menu == 'Withdrawal': user_account.make_withdrawal() if user_menu == 'Transaction Log': user_account.get_trans_log() if user_menu == 'Logout': os.system("cls") break if __name__ == '__main__': main()Account Class File
import bankAccount import os from datetime import datetime # Project folder and relative file paths project_dir = bankAccount.project_dir file_path_list = bankAccount.file_path_list class Account: def __init__(self, acctNum, pin): # Initialize acct# and pin self.__acctNum = acctNum self.__pin = pin # Open account file acct_file_path = file_path_list[2] + self.__acctNum + "info.txt" acctFile = open(acct_file_path, 'r') # Set account information (Skip first two lines and last line) acctFile.readline() acctFile.readline() # Set account information self.__name = acctFile.readline().strip() self.__DOB = acctFile.readline().strip() self.__SSN = acctFile.readline().strip() self.__balance = acctFile.readline().strip() # Close the file acctFile.close() def make_withdrawal(self): # Clear the screen, show the bank header os.system("CLS") bankAccount.get_menu(0) # File location account_info_file = file_path_list[2] + self.__acctNum + "info.txt" transFile = file_path_list[1] + "transLog" # Print withdrawal UI print("WITHDRAWAL") print("----------") print("Current Balance: $" + self.__balance + '\n') # Ask user to enter an amount to withdrawal while True: try: amount = float(input("Enter an amount to withdrawal: $")) if amount > float(self.__balance): pass else: break except: print("Please enter a valid amount!") continue # PIN Comformation, this will loop 3 times(Or until the user enters the correct PIN) pinCom = bankAccount.check_pin(self.__pin) if pinCom: # Update the balance and input into info file self.__balance = str(float(self.__balance) - amount) bankAccount.update_balance(account_info_file, 5, self.__balance) print("\nTransaction Success!") os.system("PAUSE") else: # Run only if the PIN was incorrect print("\nTransaction Failed. PIN couldn't be confirmed") os.system("PAUSE") # Write to trans log file for the account initAmount = float(self.__balance) + amount transLog = open(transFile + self.__acctNum + ".txt", 'a') transLog.write('W\n' + str(initAmount) + "\n" + str(amount) + "\n" + str(datetime.now().replace(microsecond=0)) + "\n") transLog.close() def make_deposit(self): # Clear the screen os.system("CLS") # Bank Header bankAccount.get_menu(0) # File Location account_info_file = file_path_list[2] + self.__acctNum + "info.txt" transFile = file_path_list[1] + "transLog" # Print Deposit UI print("DEPOSIT") print("-------") print("Current Balance: $" + self.__balance) # Ask user to enter an amount to deposit while True: try: amount = float(input("Enter an amount to Deposit: $")) if amount > 1000 and self.__name != "ADMIN": pass else: break except: print("Please enter a valid amount under $1000") continue # PIN Comformation pinCom = bankAccount.check_pin(self.__pin) if pinCom: # Update the balance and input into info file self.__balance = str(float(self.__balance) + amount) bankAccount.update_balance(account_info_file, 5, self.__balance) print("\nTransaction Success!") os.system("PAUSE") else: print("\nTransaction Failed. PIN couldn't be confirmed") os.system("PAUSE") # Write to trans log file for the account initAmount = float(self.__balance) - amount transLog = open(transFile + self.__acctNum + ".txt", 'a') transLog.write('D\n' + str(initAmount) + "\n" + str(amount) + "\n" + str(datetime.now().replace(microsecond=0)) + "\n") transLog.close() def get_trans_log(self): os.system("CLS") # Open the transLog file for the current user transFolder = "C:/Users/bagpi/PycharmProjects/Bank Account SIM v3/Trans Logs/transLog" transFile = transFolder + self.__acctNum + ".txt" transLog = open(transFile, 'r') # Show transaction log header: print("Transaction Type Date Transaction Amount Balance After Transaction") print("--------------------------------------------------------------------------------------------------------------") # Read the transCode in the file transCode = transLog.readline().strip() # If transCode is blank, EOF is reached while transCode != '': # Get the balance before transaction, transaction amount, and date of transaction initBalance = float(transLog.readline().strip()) transAmount = float(transLog.readline().strip()) transDate = transLog.readline().strip() # Output data according to transaction code. if transCode == 'D': print(format("Deposit", '<26s'), format(transDate, '<30s'), format(transAmount, '<26.2f'), format(initBalance + transAmount, '<15.2f')) if transCode == 'W': print(format("Withdrawal", '<26s'), format(transDate, '<30s'), format(transAmount, '<26.2f'), format(initBalance - transAmount, '<15.2f')) # Read next transaction code transCode = transLog.readline().strip() # Print footer print("--------------------------------------------------------------------------------------------------------------") print("CURRENT BALANCE: $" + self.__balance) # Wait for user os.system("PAUSE") def get_name(self): return self.__name def get_dob(self): return self.__DOB def get_ssn(self): return self.__SSN def get_balance(self): return self.__balanceFunction Library
# FUNCTION LIST FOR BANK ACCOUNT SIM V2 import datetime import os import random import time from accountExceptions import NameInvalid from accountExceptions import PINInvalid from accountExceptions import SSNInvalid from accountExceptions import BalanceInvalid # File and Directory list project_dir = os.path.dirname(os.path.abspath(__file__)).split("\_Scripts")[0] file_path_list = [project_dir+'/Login_Info/acctNum.txt', project_dir+'/Trans Logs/', project_dir+'/Account_Information/account', project_dir+'/Login_Info/PIN.txt', project_dir+'/UI/'] def gen_acct_num(): # Get the account numbers text file path and trans log path acct_num_path = file_path_list[0] trans_log_path = file_path_list[1] # Open the acct_num_file in read mode and read the contents of the file to compare # This will be used to check if the generated acct # is already in the database of acct #'s acct_num_file = open(acct_num_path) acct_nums = [line.strip for line in acct_num_file] while True: generated_acct_num = str(random.randint(100000000000, 999999999999)) if generated_acct_num not in acct_nums: break # Once the file has been searched and the account # is generated, append the # account # to the database. acct_num_file = open(acct_num_path, 'a') acct_num_file.write(generated_acct_num + "\n") acct_num_file.close() # Create trans log file trans_log = open(f'{trans_log_path}transLog{generated_acct_num}.txt', 'w+') trans_log.close() # Return the account number return generated_acct_num def get_menu(menu_num): # Open file folder for UI, put all files into a list ui_path = file_path_list[4] ui_file_list = [] for i in range(4): ui_file = open(f'{ui_path}UI{str(i)}.txt', 'r') ui_file_list.append(ui_file) # 0 = Header, 1 = Login, 2 = User, 3 = Registration text = ui_file_list[menu_num].readline().strip() while text != '': print(text) text = ui_file_list[menu_num].readline().strip() def log_data(acct_num, pin, name, dob, ssn, balance): # Log PIN into PINS.txt pin_file_path = file_path_list[3] pin_file = open(pin_file_path, 'a') pin_file.write(pin+'\n') pin_file.close() # Create the path for the file folder log_file_path = file_path_list[2] # Create a file with the user's account # acct_file = open(f'{log_file_path}{acct_num}info.txt', 'w+') # Log data into file in correct order acct_file.write(acct_num + '\n') acct_file.write(pin + '\n') acct_file.write(name + '\n') acct_file.write(str(dob) + '\n') acct_file.write(ssn + '\n') acct_file.write(balance + '\n') # Close the file acct_file.close() def registration(): # Clear the screen os.system("CLS") # Print Bank Header get_menu(0) get_menu(3) # Get Users Name while True: try: name = input("Enter your full name:") if name.replace(' ', '').isalpha(): break else: raise NameInvalid except NameInvalid: print("ERROR: Name must be alphabetic\n") continue # Get Users DOB while True: try: temp_dob = input("Enter your date of birth[-m, -d, yyyy]:") m, d, y = [int(x) for x in temp_dob.split(",")] dob = datetime.date(y, m, d) break except ValueError: print("ERROR: DOB must be in valid m,d,yyyy format!\n") continue # Get Users SSN while True: try: ssn = input("Enter your SSN[xxxxxxxxx]:") if ssn.isdigit() and len(ssn) == 9: break else: raise SSNInvalid except SSNInvalid: print("ERROR: SSN must be numeric and EXACTLY 9-Digits\n") continue # Set User's PIN while True: try: pin = input("Create a Personal ID #:") if len(pin) != 4 or not pin.isdigit(): raise PINInvalid else: break except PINInvalid: print("ERROR: PIN must be EXACTLY 4-digits and must be numeric\n") continue # Set Users Balance while True: try: balance = input("Enter an initial balance:$") if float(balance) > 1000: raise BalanceInvalid else: break except BalanceInvalid: print("ERROR: Max initial balance is $1000\n") continue except ValueError: print("ERROR: Must be a valid value!\n") continue acct_num = gen_acct_num() # Get user Data log_data(acct_num, pin, name, dob, ssn, balance) # Tell User their acct# and PIN print('\n') print("Do NOT share this information with anyone!") print(f'ACCOUNT NUMBER: {acct_num}') print(f' PIN: {pin}') def check_login(acct_num, pin): # Open account numbers and PIN text files acctFile = file_path_list[0] pinFile = file_path_list[3] acctNums = open(acctFile, 'r') pins = open(pinFile, 'r') # Read line by line checking if acct num and pin match in the files readAcctNum = acctNums.readline().strip() readPIN = pins.readline().strip() acctList = [] pinList = [] # Get Account Numbers while readAcctNum != '': acctList.append(readAcctNum) readAcctNum = acctNums.readline().strip() # Get PINs while readPIN != '': pinList.append(readPIN) readPIN = pins.readline().strip() # Set a variable to check if valid. Check if acct number matches with PIN isValid = False for i in range(len(acctList)): if acctList[i] == acct_num: if pinList[i] == pin: isValid = True return isValid def login(): # Set variables to check for lockout and set lockout times tries = 0 lockoutNum = 0 timeoutDone = True # Show login menu get_menu(0) get_menu(1) # Login Loop while True: # Print a blank line print() # Check if the person is currently locked out or not if lockoutNum > 0 and not timeoutDone: # Set a lockout time based on the equation timeWait = 6 * lockoutNum / 2 # Tell the user that they've tried to enter in information too many times print("You've entered the wrong information too many times!") print("Please wait " + str(timeWait) + " seconds.") # Lockout, prevent from asking for the account # and PIN while timeWait != 0: time.sleep(1) timeWait -= 1 # Timeout is done timeoutDone = True # Clear the screen and take them back to login. os.system("CLS") get_menu(0) get_menu(1) continue # Ask the user for their Acct # userAcctNum = input("Acct #: ") # If they enter register instead, take them to registration portal if userAcctNum == "register": registration() os.system("PAUSE") os.system("CLS") get_menu(1) continue # If they enter quit, quit the program elif userAcctNum == "quit": quit() # Else, ask for their PIN else: userPIN = input("PIN: ") # Check if the user enters quit into PIN if userPIN == 'quit': quit() # If the information is correct, take them to user Main Menu isLogin = check_login(userAcctNum, userPIN) if isLogin: os.system("CLS") animation(3, "Login Success") os.system("CLS") break # If the information is incorrect, do some things... else: # If the user enters the wrong information 3 times in a row, lock the user out. tries += 1 if tries % 3 == 0: lockoutNum += 1 timeoutDone = False # Tell the user their info was incorrect, clear login screen. os.system("CLS") get_menu(0) print("\nLogin details incorrect! Try Again!\n") get_menu(1) continue # When done, return user information return userAcctNum, userPIN def update_balance(fileName, lineNum, balance): # read the lines in the file, creates a list lines = open(fileName, 'r').readlines() # Replace balance, Line number 5 lines[lineNum] = balance + '\n' # Rewrite file and close out = open(fileName, 'w') out.writelines(lines) out.close() def show_user_menu(name, balance): # Get Menu get_menu(0) print(f'Welcome back, {name}') print(f'CURRENT BALANCE: ${balance}') get_menu(2) # MAIN LOOP while True: # Ask user for choice userChoice = input("\nChoice: ") # Return users choice if userChoice == '1': return 'Withdrawal' if userChoice == '2': return 'Deposit' if userChoice == '3': return 'Transaction Log' if userChoice == '0': return 'Logout' if userChoice == 'quit': quit() else: # If option is not valid, clear screen and tell user. os.system("CLS") get_menu(0) print("NOT A VALID OPTION!") print() print(f'Welcome back, {name}') print(f'CURRENT BALANCE: ${balance}') get_menu(2) continue def animation(Time, message): # This is used to make the LOGIN SUCCESS look 'prettier' tempTime = 0 while Time > tempTime: dot = message + '' for i in range(3): dot += '.' print(dot) time.sleep(0.3) os.system("CLS") tempTime += 0.5 def check_pin(pin): # Set vars to chcek for correct PIN pinCheck = False tries = 0 # Loop while the user has not input 3 incorrect PINs while tries != 3: # Ask for user's PIN userPin = input("Please enter your comformation PIN: ") # If the PIN is correct, pinCheck = True. if userPin == pin: pinCheck = True break else: # Increment tries tries += 1 continue # Will return false unless PIN is correct return pinCheckError Classes
class Error(Exception): """Base Class for other exceptions""" pass class NameInvalid(Error): pass class PINInvalid(Error): pass class SSNInvalid(Error): pass class BalanceInvalid(Error): pass
OUTPUTS
Login Screen
Output:Welcome to Bank Account SIM v2 Made by: Dillon
***************************************************************
LOGIN PORTAL
************
Welcome to Bank SIM v2. Please log in down below.
If you are not registered, type 'register' in the ACCT#
field. Type 'quit' at any time to quit the program.
Acct #:
User Main Menu ScreenOutput:Welcome to Bank Account SIM v2 Made by: Dillon
***************************************************************
Welcome back, ADMIN
CURRENT BALANCE: $4600.0
Choose an option below
+---------------------+
|1. WITHDRAWAL |
|2. DEPOSIT |
|3. TRANSACTION LOG |
+---------------------+
|0. LOG OUT |
+---------------------+
Type 'quit' at any time to quit the program.
Choice:
Withdrawl and Deposit screensOutput:Welcome to Bank Account SIM v2 Made by: Dillon
***************************************************************
WITHDRAWAL
----------
Current Balance: $4600.0
Enter an amount to withdrawal: $100
Please enter your comformation PIN: 2356
Transaction Success!
Press any key to continue . . .
Output:Welcome to Bank Account SIM v2 Made by: Dillon
***************************************************************
DEPOSIT
-------
Current Balance: $4500.0
Enter an amount to Deposit: $100
Please enter your comformation PIN: 2356
Transaction Success!
Press any key to continue . . .
Transaction Log ScreenOutput:Transaction Type Date Transaction Amount Balance After Transaction
--------------------------------------------------------------------------------------------------------------
Withdrawal 2018-07-04 23:26:35 100.00 9250.00
Deposit 2018-07-04 23:27:00 2000.00 11250.00
Withdrawal 2018-07-04 23:27:04 100.00 11150.00
Withdrawal 2018-07-04 23:27:12 3000.00 8150.00
Withdrawal 2018-07-04 23:27:21 1000.00 7150.00
Deposit 2018-07-04 23:27:26 100.00 7250.00
Deposit 2018-07-04 23:27:32 500.00 7750.00
Withdrawal 2018-07-04 23:27:36 1000.00 6750.00
Withdrawal 2018-07-05 10:13:16 1000.00 5750.00
Withdrawal 2018-07-05 11:45:19 0.00 5750.00
Withdrawal 2018-07-05 13:40:44 200.00 5550.00
Withdrawal 2018-07-05 14:13:41 100.00 5450.00
Deposit 2018-07-05 14:14:36 100.00 5550.00
Withdrawal 2018-07-05 14:24:42 150.00 5400.00
Deposit 2018-07-05 14:24:50 150.00 5550.00
Deposit 2018-07-05 14:26:30 150.00 5700.00
Withdrawal 2018-07-05 19:18:32 100.00 5600.00
Deposit 2018-07-05 19:19:39 100.00 5700.00
Withdrawal 2018-07-05 19:20:53 100.00 5600.00
Deposit 2018-07-05 19:21:01 100.00 5700.00
Withdrawal 2018-07-05 20:26:52 100.00 5600.00
Deposit 2018-07-07 20:41:49 100.00 5700.00
Withdrawal 2018-07-07 20:42:11 1000.00 4700.00
Withdrawal 2018-07-11 17:21:48 100.00 4600.00
Withdrawal 2018-07-11 17:33:27 100.00 4500.00
Deposit 2018-07-11 17:34:13 100.00 4600.00
--------------------------------------------------------------------------------------------------------------
CURRENT BALANCE: $4600.0
Press any key to continue . . .
Registration PortalOutput:Welcome to Bank Account SIM v2 Made by: Dillon
***************************************************************
REGISTRATION PORTAL
-------------------
Enter your full name:John Smith
Enter your date of birth[-m, -d, yyyy]:1,1,1999
Enter your SSN[xxxxxxxxx]:123456789
Create a Personal ID #:2356
Enter an initial balance:$1000
Do NOT share this information with anyone!
ACCOUNT NUMBER: 724166601420
PIN: 2356
Press any key to continue . . .
I hope to continue to improve this program. I want to start really learning GUI using Tkinter in python so I can move this to a nicer, more aesthetically pleasing interface.