Actions

Python: ATM

From Rabbi Blog

I'm auditing part 1 of a Programming class in Python as I have to take part 2 next semester (I have an old transfer credit that covered Programming 1, alas the last time I did programming in school for school, it was in C and C++). I don't think I've ever done anything from start to finish in Python outside of print ("Hello world!"), though I've looked at the code of others a lot. My PERL programming comes in handy with this, but I'm still new at it.

It's a seven week course and one of the semester projects is to build an ATM prototype. I was out week one and I picked up the course notes a week ago (week 2). Tomorrow starts week 3.

To get through the project I had to figure out

  • How Python works with lists
    • This wasn't called for in the project, but it made things so much easier for the account setup.
  • console output
    • Why all the () stuff?
  • if, elsif, else
    • elif???
  • casting types
    • int\float, etc - I still have some basic trouble with this, mostly around remembering what I was hoping to do
  • format output in columns
    • not called for, I just don't like ugly columns
  • functions
    • I actually like Python's handling of functions, though I didn't look into passing information in an out, nor did I look into local vs global variables.
  • Loops
    • Made sense!

Here's my first iteration of the semester project, four days after I started it in IDLE:

#################################################################################
## /---------------------------------------------------------------------------\*
## |  Program: ATM
## |  Version: 0.0.1
## |  Language: 3.7.4
## | 
## |  Description: ATM Project Iteration #1
## | 
## |  Course: IT 261-1
## |  Author: Mike Beane
## \---------------------------------------------------------------------------/*
## Changelog
## Date				Description
## -----			-------------
## 9/11/2019                    Program Setup - Created Lists
##                              Basic account input created and sanity test
## 9/12/2019                    Added PIN check (simple)
## 9/13/2019                    Added WHILE LOOP screen clear: cls()
## 9/14/2019                    Added Account # loop and testing to see if the
##                                  value is in the list or not or input is
##                                  valid by length.
##                              Added help() to list account variables (this
##                                  is more for you than for me, it would NOT
##                                  exist in a real program.  Instead there
##                                  would be Post-IT notes for this information.
##                              Updated PIN check (advanced and now with fail!)
##                              Created functions for repetitive things
##                              Added Deposit (simple) - needs sanity checks
## 9/15/2019                    Updated Deposit checks
##                              Added Withdrawal routine and checks
#################################################################################
# Variables
debug = 1
PIN_Max_Attempts=3
#################################################################################
## System Variables - Do Not Edit Below This Line ###############################
#################################################################################
## Function - Clear Screen cludge
def cls():
    i = 0
    while i < 39:               # Default window size seems to be 40 lines
        print (" ")             # Avoiding making sys() calls and just 
        i += 1                  # Carriage returning the screen clear
        
## Function - Output Account Lists if "?" is used in the Account input section
def help():
    cls()
    print ("--------------------------------------------------------")
    print ("|***************** Help: Account Info *****************|")
    print ("--------------------------------------------------------")
    print ("Account Pin  Name ")
    print ("--------------------------------------------------------")
    i=0
    while i < len(ACCOUNTS):
        print (""+ACCOUNTS[i]+" "+PINS[i]+" "+USERS[i])
        i += 1
    print (" ")
    print (" ")
    print ("** Realistically this wouldn't be here **")
    print ("--------------------------------------------------------")

def header():
    cls()
    print ("--------------------------------------------------------")
    print (" Name                           Account ")
    print ("--------------------------------------------------------")
    print (" "+USERS[ACCOUNT_POSITION]+"                  "+USER_ACCOUNT)
    print ("--------------------------------------------------------")

def main_menu():
    print ("--------------------------------------------------------")
    print ("Options:  ")
    print ("         1. Fund Balance Inquiry")
    print ("         2. Deposit")
    print ("         3. Withdraw ")
    print ("         4. Quit")
    print ("--------------------------------------------------------")

def balance_display():
    print ("--------------------------------------------------------")
    print ("Balance:  ")
    print ("            Checking: $"+ str(BALANCE_Checking))
    print ("         Savings [1]: $"+ str(BALANCE_Savings_1))
    print ("         Savings [2]: $"+ str(BALANCE_Savings_2))
    print ("--------------------------------------------------------")

def ledger():
    table_data = [
    # https://docs.python.org/2.7/library/string.html#format-specification-mini-language
    # https://stackoverflow.com/questions/9989334/create-nice-column-output-in-python
    [' ', 'STARTING','TOTAL','TOTAL','ENDING'],
    ['TYPE', 'BALANCE','DEPOSITS','WITHDRAWLS','BALANCE'],
    ['----------','----------','----------','----------','----------'],
    ['Checking', str(STARTING_BALANCE_CHECKING), DEPOSIT_TALLY_CHECKING, WITHDRAWAL_TALLY_CHECKING, BALANCE_Checking],
    ['Savings[1]', str(STARTING_BALANCE_Savings_1), DEPOSIT_TALLY_SAVINGS_1, WITHDRAWAL_TALLY_SAVINGS_1, BALANCE_Savings_1],
    ['Savings[2]', str(STARTING_BALANCE_Savings_2), DEPOSIT_TALLY_SAVINGS_2, WITHDRAWAL_TALLY_SAVINGS_2, BALANCE_Savings_2],
    ['----------','----------','----------','----------','----------'],
    ['TOTALS','',DEPOSIT_TALLY_CHECKING+DEPOSIT_TALLY_SAVINGS_1+DEPOSIT_TALLY_SAVINGS_2,WITHDRAWAL_TALLY_CHECKING+WITHDRAWAL_TALLY_SAVINGS_1+WITHDRAWAL_TALLY_SAVINGS_2,'',]
    ]
    for row in table_data:
        print("{: >10} {: >10} {: >10} {: >10} {: >10}".format(*row))

def startup():
    cls()
    print ("--------------------------------------------------------")
    print ("--------------------------------------------------------")
    print ("-------A.T.M.-------------------------------------------")
    print ("---------NOTE: All Input Via Numeric Keypad-------------")
    print ("--------------------------------------------------------")
    print ("|************|                            |************|")
    print ("|************|    [ 7 ]  [ 8 ]  [ 9 ]     |************|")
    print ("|************|                            |************|")
    print ("|************|    [ 4 ]  [ 5 ]  [ 6 ]     |************|")
    print ("|************|                            |************|")
    print ("|************|    [ 1 ]  [ 2 ]  [ 3 ]     |************|")
    print ("|************|                            |************|")
    print ("|************|    [ 0 ]  [ . ]  [ ENTER ] |************|")
    print ("|************|                            |************|")
    print ("--------------------------------------------------------")


#################################################################################
## List Setup - User Accounts,Pins,Names
## Usage:
##          List position dictates linkage between UA->Pin->Name
##          Example:    Entering 7654321 will match at position 3 below
##                      and will correspond with PIN 4567 and USER Hank Simpson
#################################################################################
## Ref: https://www.w3schools.com/python/python_arrays.asp
#### Python doesn't do Arrays
#### It does Lists. Let's do Lists
#################################################################################
ACCOUNTS = ["1234567","8675309","6666666","7654321","5551212"]
PINS = ["1234","2345","3456","4567","5678"]
USERS = ["Brock Shumway","Gale Winds","Gustavo Adolpho","Hank Simpsons","Hector Lizondo"]
TOTAL_ACCOUNTS = len(ACCOUNTS)
TOTAL_PINS = len(PINS)
TOTAL_USERS = len(USERS)

#################################################################################
STARTING_BALANCE_CHECKING = 500
STARTING_BALANCE_Savings_1 = 1500
STARTING_BALANCE_Savings_2 = 5000

BALANCE_Checking = STARTING_BALANCE_CHECKING
BALANCE_Savings_1 = STARTING_BALANCE_Savings_1
BALANCE_Savings_2 = STARTING_BALANCE_Savings_2

DEPOSIT_TALLY_CHECKING = 0
DEPOSIT_TALLY_SAVINGS_1 = 0
DEPOSIT_TALLY_SAVINGS_2 = 0

WITHDRAWAL_TALLY_CHECKING = 0
WITHDRAWAL_TALLY_SAVINGS_1 = 0
WITHDRAWAL_TALLY_SAVINGS_2 = 0

DEPOSIT_AMOUNT = 0




#################################################################################    
## User Input: Account
#### http://introtopython.org/while_input.html
#################################################################################
cls()
#print ("#####")
startup()
WHILE_ACCOUNT_INPUT=0

while WHILE_ACCOUNT_INPUT == 0:
    USER_ACCOUNT = input("Please enter your seven digit Account Number or 0 to exit: ")
    # https://snakify.org/en/lessons/if_then_else_conditions/
    if USER_ACCOUNT == '0':
        print ("You entered 0, exiting program.")
        quit()
    elif len(USER_ACCOUNT) < 7:
        if USER_ACCOUNT == "?":
           help()
        else:
           print ("The entered string was too short: " + str(len(USER_ACCOUNT)))
    elif len(USER_ACCOUNT) > 7:
        print ("The entered string was too long: " + str(len(USER_ACCOUNT)))
    else:
        print ("The entered string was correct: " + str(len(USER_ACCOUNT)))
        #########################################################
        ### Length was correct, but is it a valid account?
        ### Check 'ACCOUNTS' list to see if typed in value exists
        ### We really don't care if the user put in alpha
        ### characters, it will fail the lookup.
        #########################################################
        if USER_ACCOUNT not in ACCOUNTS:
            print ("Account not found")
        else:
            WHILE_ACCOUNT_INPUT=1

#####################################################
## We have some valid input -> Find the position
#####################################################
            
ACCOUNT_POSITION = ACCOUNTS.index(USER_ACCOUNT)

####################################################
## debug to dump out known elements to screen
####################################################

if debug == 0:
    print ("Debugging Enabled")
    print ("Total Accounts: " + str(TOTAL_ACCOUNTS))
    print ("Total Pins: " + str(TOTAL_PINS))
    print ("Total Users: " + str(TOTAL_USERS))
    
    print ("Entered Account: " +USER_ACCOUNT)
    print ("Account Position: " + str(ACCOUNT_POSITION))
    print ("Pin at Pos " + str(ACCOUNT_POSITION) + ": " + PINS[ACCOUNT_POSITION])
    print ("User at Pos " + str(ACCOUNT_POSITION) + ": " + USERS[ACCOUNT_POSITION])

cls()

####################################################
# PIN Check
####################################################
While_PIN_Input=0
PIN_Input_Fail=0

while While_PIN_Input==0:
    print ("Account: " +USER_ACCOUNT)
    User_PIN = input("Please enter your four digit PIN Number or 0 to exit: ")
    # https://snakify.org/en/lessons/if_then_else_conditions/
    if User_PIN == '0':
        print ("You entered 0, exiting program.")
        quit()
    elif len(User_PIN) < 4:
        if User_PIN == "?":
           help()
        else:
           print ("The entered string was too short: " + str(len(User_PIN)))
    elif len(User_PIN) > 4:
        print ("The entered string was too long: " + str(len(User_PIN)))
    else:
        print ("The entered string was correct: " + str(len(User_PIN)))
        #########################################################
        ### Length was correct, but is it a valid match for ?
        ### Check 'accounts' list to see if typed in value exists
        ### We really don't care if the user put in alpha
        ### characters, it will fail the lookup.
        #########################################################
        if User_PIN == PINS[ACCOUNT_POSITION]:
            While_PIN_Input=1
        else:
            PIN_Input_Fail=PIN_Input_Fail+1
            if PIN_Input_Fail == PIN_Max_Attempts:
                cls()
                print ("*****************************************************************")
                print ("You have failed to enter a correct PIN.  Please contact the bank.")
                print ("*****************************************************************")
                EXIT = input("Press ENTER to exit")
                quit()
            else:       
                print ("Incorrect PIN.  Attempt "+str(PIN_Input_Fail)+" of "+str(PIN_Max_Attempts))
                
############################################################
## If you are here, you are logged in
############################################################


############################################################
# Two level while
## Level 1: main_menu area
#### Level 2: each individual option
############################################################

WHILE_MAIN_MENU = 0
while WHILE_MAIN_MENU == 0:
    cls()
    header()
    main_menu()
    main_menu_input = input ("Enter your choice: ")
    print (main_menu_input)
    if main_menu_input == '4':
        print ("Selected Exit...")
        WHILE_MAIN_MENU = 1
    elif main_menu_input == '1':
        print ("Selected Balance Inquiry...")
        cls()
        header()
        balance_display()
        EXIT = input("Press ENTER to return to Main Menu... ")
    elif main_menu_input == '?':
        print ("Selected Ledger Inquiry...")
        cls()
        header()
        ledger()
        EXIT = input("Press ENTER to return to Main Menu... ")
    elif main_menu_input == '2':
    ################################### DEPOSITS START #####################################
        print ("Selected Deposits...")
        WHILE_DEPOSITS_MENU = 0
        while WHILE_DEPOSITS_MENU == 0:
            cls()
            header()
            ########################### How much to deposit?
            print ("How much would you like to deposit?") 
            DEPOSIT_AMOUNT = input ("[0 to return, max deposit is $1000]: ")
            if DEPOSIT_AMOUNT == '0':
                print ("!")
                WHILE_DEPOSITS_MENU=1
            elif float(DEPOSIT_AMOUNT) > 1000:
                BAD_ENTRY = input ("Max entry is $1000. Press ENTER to continue")
                print ("!22")
                WHILE_DEPOSITS_MENU=1
            else:
                ################################################
                ## **** !!!!!!!! NEED TO ADD A TALLY SYSTEM FOR DEPOSITS
                ## DONE !!!!!!!! NEED TO ADD A 0 <> 1000 CHECK
                ################################################
                print (" 1. Checking")
                print (" 2. Savings [1]")
                print (" 3. Savings [2]")
                print (" 4. Return to Menu [2]")
                ################################################
                DEPOSIT_SELECTION = input ("Which acount would you like to make a deposit into? ")
                if DEPOSIT_SELECTION == '4':
                    WHILE_DEPOSITS_MENU = 1
                elif DEPOSIT_SELECTION == '1':
                    BALANCE_Checking=float(DEPOSIT_AMOUNT) + float(BALANCE_Checking)
                    DEPOSIT_TALLY_CHECKING = float(DEPOSIT_TALLY_CHECKING) + float(DEPOSIT_AMOUNT)
                    DEPOSIT_AMOUNT = 0
                    WHILE_DEPOSITS_MENU = 1
                elif DEPOSIT_SELECTION == '2':
                    BALANCE_Savings_1=float(DEPOSIT_AMOUNT) + float(BALANCE_Savings_1)
                    DEPOSIT_TALLY_SAVINGS_1 = float(DEPOSIT_TALLY_SAVINGS_1) + float(DEPOSIT_AMOUNT)
                    DEPOSIT_AMOUNT = 0
                    WHILE_DEPOSITS_MENU = 1
                elif DEPOSIT_SELECTION == '3':
                    BALANCE_Savings_2=float(DEPOSIT_AMOUNT) + float(BALANCE_Savings_2)
                    DEPOSIT_TALLY_SAVINGS_2 = float(DEPOSIT_TALLY_SAVINGS_2) + float(DEPOSIT_AMOUNT)
                    DEPOSIT_AMOUNT = 0
                    WHILE_DEPOSITS_MENU = 1
    ################################### DEPOSITS END #####################################

    elif main_menu_input == '3':
    ################################### WITHDRAWALS START #####################################
        print ("Selected Deposits...")
        WHILE_WITHDRAWALS_MENU = 0
        while WHILE_WITHDRAWALS_MENU == 0:
            cls()
            header()
            ########################### How much to withdraw? ###############################
            # Withdraw amounts can only be $20, $40, $60, $80, or $100.
            # Cannot withdraw more money than what exists in the account.
            # Total withdraws from a single account cannot exceed $300.
            # Total withdraws from ALL accounts cannot exceed $750.
            #################################################################################
            WITHDRAWAL_AMOUNT = 0  #Reset
            ##################################################################################
            ######### Total withdraws from ALL accounts cannot exceed $750.
            ######### Let's just check it as it comes into the menu, if you don't have the $,
            ######### don't waste time going through the tree
            ##################################################################################
            if WITHDRAWAL_TALLY_CHECKING+WITHDRAWAL_TALLY_SAVINGS_1+WITHDRAWAL_TALLY_SAVINGS_2+20 > 750:
                print ("Any more transactions will exceed your daily withdrawal limit.")
                EXIT = input("Press ENTER to return to Main Menu... ")
                WHILE_WITHDRAWALS_MENU=1
            else:            
                print ("------------------------------------") 
                print (" 1. $20      4. $80")
                print (" 2. $40      5. $100")
                print (" 3. $60      0. Return to Menu")
                print ("------------------------------------") 
                WITHDRAWAL_AMOUNT_SELECTION = input ("How much would you like to withdraw? ")

                if WITHDRAWAL_AMOUNT_SELECTION == '0':
                    print ("!")
                    WHILE_WITHDRAWALS_MENU=1
                elif WITHDRAWAL_AMOUNT_SELECTION == '1':
                    WITHDRAWAL_AMOUNT = 20
                elif WITHDRAWAL_AMOUNT_SELECTION == '2':
                    WITHDRAWAL_AMOUNT = 40
                elif WITHDRAWAL_AMOUNT_SELECTION == '3':
                    WITHDRAWAL_AMOUNT = 60
                elif WITHDRAWAL_AMOUNT_SELECTION == '4':
                    WITHDRAWAL_AMOUNT = 80
                elif WITHDRAWAL_AMOUNT_SELECTION == '5':
                    WITHDRAWAL_AMOUNT = 100
                else:
                    WHILE_WITHDRAWALS_MENU=1
            if WHILE_WITHDRAWALS_MENU == 0:
                ######### Total withdraws from ALL accounts cannot exceed $750.
                if WITHDRAWAL_TALLY_CHECKING+WITHDRAWAL_TALLY_SAVINGS_1+WITHDRAWAL_TALLY_SAVINGS_2+WITHDRAWAL_AMOUNT > 750:
                    print ("This transaction will exceed your daily withdrawal limit.")
                    EXIT = input("Press ENTER to return to Main Menu... ")
                    WHILE_WITHDRAWALS_MENU=1
                  
if WHILE_WITHDRAWALS_MENU == 0:    
                ##### WHICH ACCOUNT? ######
                print ("------------------------------------") 
                print (" 1: CHECKING ")
                print (" 2: SAVINGS[1]")
                print (" 3: SAVINGS[2]")
                print (" ")
                print (" 0: Return to Menu")
                print ("------------------------------------") 
                WITHDRAWAL_SELECTION = input ("Which account would you like to make a withdrawal from? ")
                if WITHDRAWAL_SELECTION == '0':
                    print ("!")
                    WHILE_WITHDRAWALS_MENU=1
                # Cannot withdraw more money than what exists in the account.
                # Total withdraws from a single account cannot exceed $300.
                elif WITHDRAWAL_SELECTION == '1':
                    print ("CHECKING")
                    if WITHDRAWAL_AMOUNT + WITHDRAWAL_TALLY_CHECKING > 300:
                        print ("You have exceeded your daily individual account withdrawal limit.")
                        EXIT = input("Press ENTER to return to Main Menu... ")
                        WHILE_WITHDRAWALS_MENU=1
                    elif BALANCE_Checking - WITHDRAWAL_AMOUNT < 0:
                        print ("Insufficient funds..")
                        EXIT = input("Press ENTER to return to Main Menu... ")
                        WHILE_WITHDRAWALS_MENU=1
                    else:
                        WITHDRAWAL_TALLY_CHECKING = WITHDRAWAL_TALLY_CHECKING+WITHDRAWAL_AMOUNT
                        BALANCE_Checking = BALANCE_Checking-WITHDRAWAL_AMOUNT
                elif WITHDRAWAL_SELECTION == '2':
                    print ("SAVINGS[1]")
                    if WITHDRAWAL_AMOUNT + WITHDRAWAL_TALLY_SAVINGS_1 > 300:
                        print ("You have exceeded your daily individual account withdrawal limit.")
                        EXIT = input("Press ENTER to return to Main Menu... ")
                        WHILE_WITHDRAWALS_MENU=1
                    elif BALANCE_Savings_1 - WITHDRAWAL_AMOUNT < 0:
                        print ("Insufficient funds..")
                        EXIT = input("Press ENTER to return to Main Menu... ")
                        WHILE_WITHDRAWALS_MENU=1
                    else:
                        WITHDRAWAL_TALLY_SAVINGS_1 = WITHDRAWAL_TALLY_SAVINGS_1+WITHDRAWAL_AMOUNT
                        BALANCE_Savings_1 = BALANCE_Savings_1-WITHDRAWAL_AMOUNT
                elif WITHDRAWAL_SELECTION == '3':
                    print ("SAVINGS[1]")
                    if WITHDRAWAL_AMOUNT + WITHDRAWAL_TALLY_SAVINGS_2 > 300:
                        print ("You have exceeded your daily individual account withdrawal limit.")
                        EXIT = input("Press ENTER to return to Main Menu... ")
                        WHILE_WITHDRAWALS_MENU=1
                    elif BALANCE_Savings_2 - WITHDRAWAL_AMOUNT < 0:
                        print ("Insufficient funds..")
                        EXIT = input("Press ENTER to return to Main Menu... ")
                        WHILE_WITHDRAWALS_MENU=1
                    else:
                        WITHDRAWAL_TALLY_SAVINGS_2 = WITHDRAWAL_TALLY_SAVINGS_2+WITHDRAWAL_AMOUNT
                        BALANCE_Savings_2 = BALANCE_Savings_2-WITHDRAWAL_AMOUNT
                else:
                    WHILE_WITHDRAWALS_MENU=1


           
#### If you're here, you exited the main_menu
cls()
ledger()
print ("")
print ("Thank you and have a good day.")