Problem 1: Bank Account Revisited

We are going to rewrite the bank account closure problem we had a few assignments ago, only this time developing a formal class for a Bank User and Bank Account to use in our closure (recall previously we just had a nonlocal variable amount that we changed).

First we are going to define two types of bank accounts, run the code below:


In [3]:
from enum import Enum
class AccountType(Enum):
    SAVINGS = 1
    CHECKING = 2

An Enum stands for an enumeration, it's a convenient way for you to define lists of things. Typing:


In [4]:
AccountType.SAVINGS


Out[4]:
<AccountType.SAVINGS: 1>

returns a Python representation of an enumeration. You can compare these account types:


In [5]:
AccountType.SAVINGS == AccountType.SAVINGS


Out[5]:
True

In [4]:
AccountType.SAVINGS == AccountType.CHECKING


Out[4]:
False

To get a string representation of an Enum, you can use:


In [6]:
AccountType.SAVINGS.name


Out[6]:
'SAVINGS'

Create a BankAccount class with the following specification:

Constructor is BankAccount(self, owner, accountType) where owner is a string representing the name of the account owner and accountType is one of the AccountType enums

Methods withdraw(self, amount) and deposit(self, amount) to modify the account balance of the account

Override methods __str__ to write an informative string of the account owner and the type of account, and __len__ to return the balance of the account


In [6]:
class BankAccount:
    def __init__(self, owner, accountType):
        self.owner = owner
        self.accountType = accountType
        self.balance = 0
        
    def withdraw(self, amount):
        if self.balance >= amount and amount >= 0:
            self.balance -= amount
            return True
        else:
            return False
        
    def deposit(self, amount):
        if amount >= 0:
            self.balance += amount
            return True
        else:
            return False
        
    def __str__(self):
        return self.owner + "'s " + self.accountType.name + " Account"
    
    def __len__(self):
        return self.balance

Write some simple tests to make sure the BankAccount is working as expected.

Next, write a class BankUser with the following specification:

Constructor BankUser(self, owner) where owner is the name of the account.

Method addAccount(self, accountType) - to start, a user will have no accounts when the BankUser object is created. addAccount will add a new account to the user of the accountType specified. Only one savings/checking account per user, return appropriate error otherwise

Methods getBalance(self, accountType), deposit(self, accountType, amount), and withdraw(self, accountType, amount) for a specific AccountType.

Override __str__ to have an informative summary of user's accounts


In [3]:
class BankUser:
    def __init__(self, owner):
        self.owner = owner
        self.accounts = {}
        
    def addAccount(self, accountType):
        if accountType.name in self.accounts:
            return False
        else:
            self.accounts[accountType.name] = BankAccount(self.owner, accountType)
            return True
        
    def getBalance(self, accountType):
        return len(self.accounts[accountType.name]) if accountType.name in self.accounts else -1
        
    def deposit(self, accountType, amount):
        if accountType.name in self.accounts:
            return self.accounts[accountType.name].deposit(amount)
        else:
            return False
        
    def withdraw(self, accountType, amount):
        if accountType.name in self.accounts:
            return self.accounts[accountType.name].withdraw(amount)
        else:
            return False
        
    def __str__(self):
        s = self.owner + "'s Accounts:\n"
        for t, a in self.accounts.items():
            s += t + ": " + str(len(a)) + "\n"
        return s

Write some simple tests to make sure this is working. Think of edge scenarios a user might try to do.


In [4]:
b = BankUser("Charles Liu")
print(b.deposit(AccountType.SAVINGS, 100))
print(b.addAccount(AccountType.SAVINGS))
print(b.deposit(AccountType.SAVINGS, 50))


False
True
True

In [5]:
print(str(b))


Charles Liu's Accounts:
SAVINGS: 50

ATM Closure

Finally, we are going to rewrite a closure to use our bank account. We will make use of the input function which takes user input to decide what actions to take.

Write a closure called ATMSession(bankUser) which takes in a BankUser object. Return a method called Interface that when called, would provide the following interface:

First screen for user will look like:

Enter Option:

1)Exit

2)Create Account

3)Check Balance

4)Deposit

5)Withdraw

Pressing 1 will exit, any other option will show the options:

Enter Option:

1)Checking

2)Savings

If a deposit or withdraw was chosen, then there must be a third screen:

Enter Integer Amount, Cannot Be Negative:

This is to keep the code relatively simple, if you'd like you can also curate the options depending on the BankUser object (for example, if user has no accounts then only show the Create Account option), but this is up to you. In any case, you must handle any input from the user in a reasonable way that an actual bank would be okay with, and give the user a proper response to the action specified


In [6]:
def ATMSession(bankUser):
    def Interface():
        option = 0
        while option != 1:
            try:
                option = int(input('Enter Option:\n1)Exit\n2)Create Account\n3)Check Balance\n4)Deposit\n5)WithDraw\n\n'))
                if option > 1:
                    accountOption = 0
                    while accountOption != 1 and accountOption != 2:
                        accountOption = int(input('Select Account Type:\n1) Checking\n2) Savings\n'))
                        if accountOption != 1 and accountOption != 2:
                            print('Invalid Account Specified\n')
                    accountType = AccountType.SAVINGS if accountOption == 2 else AccountType.CHECKING
                    if option == 2:
                        if bankUser.addAccount(accountType):
                            print('Account Created\n')
                        else:
                            print('Account Already Exists\n')
                    elif option == 3:
                        balance = bankUser.getBalance(accountType)
                        if balance < 0:
                            print('Account Not Found\n')
                        else:
                            print('Balance:{}'.format(balance))
                    else:
                        amount = -1
                        while amount < 0:
                            amount = int(input('Enter integer amount, cannot be negative\n'))
                            if amount < 0:
                                print('Invalid Amount Entered\n')
                        bankFunc = bankUser.deposit if option == 4 else bankUser.withdraw
                        if bankFunc(accountType, amount):
                            print('Transaction was successful\n')
                        else:
                            balance = bankUser.getBalance(accountType)
                            if balance >= 0:
                                print('Insufficient Funds\n')
                            else:
                                print('No Account Found\n')
                            
                print(str(bankUser))
            except ValueError:
                print('Invalid Entry')
                option=1
    return Interface

In [7]:
interface = ATMSession(b)

In [8]:
interface()


Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

3
Select Account Type:
1) Checking
2) Savings
1
Account Not Found

Charles Liu's Accounts:
SAVINGS: 50

Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

3
Select Account Type:
1) Checking
2) Savings
2
Balance:50
Charles Liu's Accounts:
SAVINGS: 50

Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

4
Select Account Type:
1) Checking
2) Savings
1
Enter integer amount, cannot be negative
1000
No Account Found

Charles Liu's Accounts:
SAVINGS: 50

Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

4
Select Account Type:
1) Checking
2) Savings
2
Enter integer amount, cannot be negative
1000
Transaction was successful

Charles Liu's Accounts:
SAVINGS: 1050

Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

5
Select Account Type:
1) Checking
2) Savings
2
Enter integer amount, cannot be negative
10000
Insufficient Funds

Charles Liu's Accounts:
SAVINGS: 1050

Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

2
Select Account Type:
1) Checking
2) Savings
1
Account Created

Charles Liu's Accounts:
CHECKING: 0
SAVINGS: 1050

Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

4
Select Account Type:
1) Checking
2) Savings
1
Enter integer amount, cannot be negative
1000
Transaction was successful

Charles Liu's Accounts:
CHECKING: 1000
SAVINGS: 1050

Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)WithDraw

1
Charles Liu's Accounts:
CHECKING: 1000
SAVINGS: 1050