OOP bank account program in Python 3












1












$begingroup$


Python beginner here. Building an OOP bank account program with SQLite and starting to struggle a bit with its design. From a design standpoint I have a file (bank) which calls ATM. ATM simulates an ATM, and is the file which then calls bank_account or credit_card depending on the account data passed in from bank.



To initially setup an account I decided to put this into a different file, for example bank_account_setup or for credit_card, credit_card_setup. These would create_account, help setup pin etc so that the account is created and ready to use. Then the actual bank_account or credit_card contains other functions, like, deposit, withdraw, get_balance etc. Also, send_email is in another file



My question is basically around my design. Is there a way to structure this better? How about my setup files to create bank or credit card accounts? Is that a good or bad idea? Also, another issue I am having is that when I run bank I pass in account type to ATM. In ATM I then had to know what class I am using in advance and instantiate that inside ATM. Could I handle that dynamically? (Also, the code does work - just concerned with bad design).



Here's my calling file bank:



import atm

class BankAccount:

def __init__(self, name, social, account_number, balance, acctype):
self.name = name
self.social = social
self.account_number = account_number
self.balance = balance
self.acctype = acctype

if __name__ == '__main__':

obj1 = atm.ATM.main_menu( "Frank Smith", 135063522, 5544, 850, 'credit_card', 4400110022004400)


Here's ATM, which calls the other files:



import sqlite3, smtplib
import bank_account
import secrets
import send_email
import credit_card
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders

conn = sqlite3.connect('bank_account.db')
c = conn.cursor()

class ATM:

def get_pin(account_number, acctype, user_pin):
with conn:
db_pin = c.execute("SELECT pin from {} WHERE account_number=:account_number".format(acctype),
{'account_number':account_number})
db_pin = c.fetchone()
if db_pin is not None:
return(db_pin[0])
else:
print("db pin is None")
pass

def set_pin(account_number, acctype, input_code):
with conn:
get_code = ATM.get_user_code(account_number, acctype)
if get_code is None:
pass
print("You need to request an authorization code first before you set your pin")
else:
if get_code !=input_code:
print("Authorization code not valid")
else:
pin = input("Please set your 4 digit pin: ")
if len(pin) < 4 or len(pin) >4 or len(pin) == 4 and pin.isdigit()==False:
print("This is not a 4 digit pin")
else:
print("pin accepted")
c.execute("""UPDATE {} SET pin=:pin
WHERE account_number =:account_number""".format(acctype),
{'account_number':account_number, 'pin':pin})
print("Pin for account has been updated")


def main_menu(name, social, account_number, balance, acctype, card_no=None):

# obj1 = bank_account.BankAccount(name, social, account_number, balance, acctype)
# obj1 = credit_card.CreditCard(name, social, account_number, balance, acctype, card_no)
user_pin = int(input("nATM Home Screen. Please enter your pin code: "))
db_pin = ATM.get_pin(account_number, acctype, user_pin)
if user_pin != db_pin and db_pin != '':
print("No pin match")
elif db_pin is '':
print("Pin has not been set")
print("First request an authorization code and use that to set the pin")
else:
user_pin == db_pin
print("nPin accepted continue n ")
print("""""""ATM Menu, choose an option""""""")
print("n1 - Deposit funds")
print("2 - Withdraw funds")
print("3 - Check balance")
print("4 - Reset Pin")
print("5 - Exit")

while True:
try:
choice = int(input("Please enter a number: "))
except ValueError:
print("This is not a number")
if choice >= 1 and choice <=5:
if choice == 1:
amount = input("nPlease enter the deposit amount: ")
if amount != '' and amount.isdigit():
int(amount)
obj1.deposit( account_number, acctype, amount)
else:
print("Please enter a valid number")

elif choice == 2:
amount = input("Please enter the withdrawl amount: ")
if amount != '' and amount.isdigit():
int(amount)
obj1.withdraw(account_number, acctype, amount)
else:
print("Please enter a valid number")

elif choice ==3:
obj1.get_balance(account_number, acctype)

elif choice ==4:
new_pin = input("Please enter a new 4 digit pin: ")
if new_pin != '' and new_pin.isdigit():
int(new_pin)
obj1.set_reset_pin(account_number, acctype, new_pin)

elif choice ==5:
break

else:
print("Not a valid number")


A piece of bank_account_setup:



import sqlite3
import secrets
import getpass
import smtplib, sqlite3
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import send_email

conn = sqlite3.connect('bank_account.db')
c = conn.cursor()

class BankAccount:

def __init__(self, name, social, account_number, balance, acctype):
self.name = name
self.social = social
self.account_number = account_number
self.balance = balance
self.acctype = acctype

""" create different accounts based on account type passed in """
def create_account(self, name, social, account_number, balance, acctype, card_no=None, credit_score=None, credit_limit=None):
self.rate = None
with conn:
# account_found = BankAccount.get_account(self, account_number, acctype)
# if not account_found:
if acctype == 'bank_account':
c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :pin)".format(acctype),
{'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'pin':''})
print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

elif acctype == 'savings_account':
c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :rate)".format(acctype),
{'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'rate':''})
print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

elif acctype == 'credit_card':
c.execute("INSERT INTO credit_card VALUES (:name, :social, :account_number, :balance, :card_no,:credit_score, :credit_limit, :pin)",
{'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'card_no'
:card_no, 'credit_score':credit_score, 'credit_limit':credit_limit, 'pin':'' })
print("New account: {} has been created, acc # is: {}".format(acctype, account_number))
conn.commit()


Piece of bank_account:



import sqlite3
import secrets
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import send_email

conn = sqlite3.connect('bank_account.db')
c = conn.cursor()

class BankAccount:

def __init__(self, name, social, account_number, balance, acctype):
self.name = name
self.social = social
self.account_number = account_number
self.balance = balance
self.acctype = acctype


def get_balance(self, account_number, acctype):
with conn:
balance = c.execute("SELECT balance from {} WHERE account_number=:account_number".format(acctype),
{'account_number':account_number})
balance = c.fetchone()
print("The balance for account number: {} is ${}".format(account_number, balance[0]))
notif_set = BankAccount.get_notif(self, account_number, acctype)
if notif_set is None:
print("No notifications are set for this user")
else:
notif_balance = notif_set[4]
name = notif_set[0]
if notif_balance == 1:
notify = send_email.send_email(account_number, acctype, 'Balance', balance, balance, name)

return(balance[0])

""" Deposit funds into the account number + acctype for the account passed in """
def deposit(self, account_number, acctype, amount):
with conn:

""" Check acct exists before making deposit """
account_found = BankAccount.get_account(self, account_number, acctype)
if account_found:
existing_bal = account_found[3]
c.execute("""UPDATE {} SET balance=balance +:amount
WHERE account_number =:account_number""".format(acctype),
{'account_number':account_number, 'amount':amount})
new_bal = existing_bal + (int(amount))
print("${} has been deposited to account {} and the new balance is ${}".format(amount, account_number, existing_bal + (int(amount))))

# Check email configurations are turned on for deposits
notif_set = BankAccount.get_notif(self, account_number, acctype)
if notif_set is None:
print("No notifications are set for this user")
else:
notif_deposits = notif_set[5]
name = notif_set[0]
if notif_deposits == 1:
notify = send_email.send_email(account_number, acctype, 'Deposit', amount, new_bal, name)


Piece of credit_card:



from bank_account import BankAccount
import sqlite3

conn = sqlite3.connect('bank_account.db')
c = conn.cursor()

class CreditCard(BankAccount):
def __init__(self, name, social, account_number, balance, acctype, card_no, credit_score=None, credit_limit=None):
super().__init__(name, social, account_number, balance, acctype)
self.card_no = card_no
self.credit_score = credit_score
self.credit_limit = credit_limit

""" set credit limit, check if acct exists, then call get credit limit """
def set_credit_limit(self, account_number, acctype, credit_score):
with conn:
account_found = BankAccount.get_account(self, account_number, acctype)
if account_found:
credit_limit = CreditCard.set_credit_limit_helper(self, account_number, credit_score)
if credit_limit:
c.execute("""UPDATE credit_card SET credit_limit=:credit_limit
WHERE account_number =:account_number """,
{'account_number':account_number, 'credit_limit':credit_limit})
print("Account number {} credit limit is set to {}".format(account_number, credit_limit))
conn.commit()

def withdraw(self, account_number, acctype, amount):
with conn:
account_found = BankAccount.get_account(self, account_number, acctype)
if account_found:
balance = account_found[3]
credit_limit = CreditCard.get_credit_limit(self, account_number)
amount_left = credit_limit - (int(balance))

if balance - (int(amount)) < credit_limit:
print("Your balance is: {}, and your credit limit is: {}".format(balance, credit_limit))
print("The max you can withdraw is {}".format(amount_left))
else:
existing_bal = account_found[3]
c.execute("""UPDATE credit_card SET balance=balance -:amount
WHERE account_number =:account_number""",
{'account_number':account_number, 'amount':amount})
print("${} has been withdrawn from account {} and the new balance is ${}".format(amount, account_number, existing_bal - (int(amount))))

notif_set = BankAccount.get_notif(self, account_number, acctype)
if notif_set is None:
print("No notifications have been set for this acct")
else:
notif_withdraw = notif_set[7]
if notif_withdraw == 1:
notify = BankAccount.send_email(self,account_number, acctype, 'Withdraw', amount, existing_bal - amount)
conn.commit()









share|improve this question









New contributor




anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$

















    1












    $begingroup$


    Python beginner here. Building an OOP bank account program with SQLite and starting to struggle a bit with its design. From a design standpoint I have a file (bank) which calls ATM. ATM simulates an ATM, and is the file which then calls bank_account or credit_card depending on the account data passed in from bank.



    To initially setup an account I decided to put this into a different file, for example bank_account_setup or for credit_card, credit_card_setup. These would create_account, help setup pin etc so that the account is created and ready to use. Then the actual bank_account or credit_card contains other functions, like, deposit, withdraw, get_balance etc. Also, send_email is in another file



    My question is basically around my design. Is there a way to structure this better? How about my setup files to create bank or credit card accounts? Is that a good or bad idea? Also, another issue I am having is that when I run bank I pass in account type to ATM. In ATM I then had to know what class I am using in advance and instantiate that inside ATM. Could I handle that dynamically? (Also, the code does work - just concerned with bad design).



    Here's my calling file bank:



    import atm

    class BankAccount:

    def __init__(self, name, social, account_number, balance, acctype):
    self.name = name
    self.social = social
    self.account_number = account_number
    self.balance = balance
    self.acctype = acctype

    if __name__ == '__main__':

    obj1 = atm.ATM.main_menu( "Frank Smith", 135063522, 5544, 850, 'credit_card', 4400110022004400)


    Here's ATM, which calls the other files:



    import sqlite3, smtplib
    import bank_account
    import secrets
    import send_email
    import credit_card
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    from email import encoders

    conn = sqlite3.connect('bank_account.db')
    c = conn.cursor()

    class ATM:

    def get_pin(account_number, acctype, user_pin):
    with conn:
    db_pin = c.execute("SELECT pin from {} WHERE account_number=:account_number".format(acctype),
    {'account_number':account_number})
    db_pin = c.fetchone()
    if db_pin is not None:
    return(db_pin[0])
    else:
    print("db pin is None")
    pass

    def set_pin(account_number, acctype, input_code):
    with conn:
    get_code = ATM.get_user_code(account_number, acctype)
    if get_code is None:
    pass
    print("You need to request an authorization code first before you set your pin")
    else:
    if get_code !=input_code:
    print("Authorization code not valid")
    else:
    pin = input("Please set your 4 digit pin: ")
    if len(pin) < 4 or len(pin) >4 or len(pin) == 4 and pin.isdigit()==False:
    print("This is not a 4 digit pin")
    else:
    print("pin accepted")
    c.execute("""UPDATE {} SET pin=:pin
    WHERE account_number =:account_number""".format(acctype),
    {'account_number':account_number, 'pin':pin})
    print("Pin for account has been updated")


    def main_menu(name, social, account_number, balance, acctype, card_no=None):

    # obj1 = bank_account.BankAccount(name, social, account_number, balance, acctype)
    # obj1 = credit_card.CreditCard(name, social, account_number, balance, acctype, card_no)
    user_pin = int(input("nATM Home Screen. Please enter your pin code: "))
    db_pin = ATM.get_pin(account_number, acctype, user_pin)
    if user_pin != db_pin and db_pin != '':
    print("No pin match")
    elif db_pin is '':
    print("Pin has not been set")
    print("First request an authorization code and use that to set the pin")
    else:
    user_pin == db_pin
    print("nPin accepted continue n ")
    print("""""""ATM Menu, choose an option""""""")
    print("n1 - Deposit funds")
    print("2 - Withdraw funds")
    print("3 - Check balance")
    print("4 - Reset Pin")
    print("5 - Exit")

    while True:
    try:
    choice = int(input("Please enter a number: "))
    except ValueError:
    print("This is not a number")
    if choice >= 1 and choice <=5:
    if choice == 1:
    amount = input("nPlease enter the deposit amount: ")
    if amount != '' and amount.isdigit():
    int(amount)
    obj1.deposit( account_number, acctype, amount)
    else:
    print("Please enter a valid number")

    elif choice == 2:
    amount = input("Please enter the withdrawl amount: ")
    if amount != '' and amount.isdigit():
    int(amount)
    obj1.withdraw(account_number, acctype, amount)
    else:
    print("Please enter a valid number")

    elif choice ==3:
    obj1.get_balance(account_number, acctype)

    elif choice ==4:
    new_pin = input("Please enter a new 4 digit pin: ")
    if new_pin != '' and new_pin.isdigit():
    int(new_pin)
    obj1.set_reset_pin(account_number, acctype, new_pin)

    elif choice ==5:
    break

    else:
    print("Not a valid number")


    A piece of bank_account_setup:



    import sqlite3
    import secrets
    import getpass
    import smtplib, sqlite3
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    from email import encoders
    import send_email

    conn = sqlite3.connect('bank_account.db')
    c = conn.cursor()

    class BankAccount:

    def __init__(self, name, social, account_number, balance, acctype):
    self.name = name
    self.social = social
    self.account_number = account_number
    self.balance = balance
    self.acctype = acctype

    """ create different accounts based on account type passed in """
    def create_account(self, name, social, account_number, balance, acctype, card_no=None, credit_score=None, credit_limit=None):
    self.rate = None
    with conn:
    # account_found = BankAccount.get_account(self, account_number, acctype)
    # if not account_found:
    if acctype == 'bank_account':
    c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :pin)".format(acctype),
    {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'pin':''})
    print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

    elif acctype == 'savings_account':
    c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :rate)".format(acctype),
    {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'rate':''})
    print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

    elif acctype == 'credit_card':
    c.execute("INSERT INTO credit_card VALUES (:name, :social, :account_number, :balance, :card_no,:credit_score, :credit_limit, :pin)",
    {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'card_no'
    :card_no, 'credit_score':credit_score, 'credit_limit':credit_limit, 'pin':'' })
    print("New account: {} has been created, acc # is: {}".format(acctype, account_number))
    conn.commit()


    Piece of bank_account:



    import sqlite3
    import secrets
    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    from email import encoders
    import send_email

    conn = sqlite3.connect('bank_account.db')
    c = conn.cursor()

    class BankAccount:

    def __init__(self, name, social, account_number, balance, acctype):
    self.name = name
    self.social = social
    self.account_number = account_number
    self.balance = balance
    self.acctype = acctype


    def get_balance(self, account_number, acctype):
    with conn:
    balance = c.execute("SELECT balance from {} WHERE account_number=:account_number".format(acctype),
    {'account_number':account_number})
    balance = c.fetchone()
    print("The balance for account number: {} is ${}".format(account_number, balance[0]))
    notif_set = BankAccount.get_notif(self, account_number, acctype)
    if notif_set is None:
    print("No notifications are set for this user")
    else:
    notif_balance = notif_set[4]
    name = notif_set[0]
    if notif_balance == 1:
    notify = send_email.send_email(account_number, acctype, 'Balance', balance, balance, name)

    return(balance[0])

    """ Deposit funds into the account number + acctype for the account passed in """
    def deposit(self, account_number, acctype, amount):
    with conn:

    """ Check acct exists before making deposit """
    account_found = BankAccount.get_account(self, account_number, acctype)
    if account_found:
    existing_bal = account_found[3]
    c.execute("""UPDATE {} SET balance=balance +:amount
    WHERE account_number =:account_number""".format(acctype),
    {'account_number':account_number, 'amount':amount})
    new_bal = existing_bal + (int(amount))
    print("${} has been deposited to account {} and the new balance is ${}".format(amount, account_number, existing_bal + (int(amount))))

    # Check email configurations are turned on for deposits
    notif_set = BankAccount.get_notif(self, account_number, acctype)
    if notif_set is None:
    print("No notifications are set for this user")
    else:
    notif_deposits = notif_set[5]
    name = notif_set[0]
    if notif_deposits == 1:
    notify = send_email.send_email(account_number, acctype, 'Deposit', amount, new_bal, name)


    Piece of credit_card:



    from bank_account import BankAccount
    import sqlite3

    conn = sqlite3.connect('bank_account.db')
    c = conn.cursor()

    class CreditCard(BankAccount):
    def __init__(self, name, social, account_number, balance, acctype, card_no, credit_score=None, credit_limit=None):
    super().__init__(name, social, account_number, balance, acctype)
    self.card_no = card_no
    self.credit_score = credit_score
    self.credit_limit = credit_limit

    """ set credit limit, check if acct exists, then call get credit limit """
    def set_credit_limit(self, account_number, acctype, credit_score):
    with conn:
    account_found = BankAccount.get_account(self, account_number, acctype)
    if account_found:
    credit_limit = CreditCard.set_credit_limit_helper(self, account_number, credit_score)
    if credit_limit:
    c.execute("""UPDATE credit_card SET credit_limit=:credit_limit
    WHERE account_number =:account_number """,
    {'account_number':account_number, 'credit_limit':credit_limit})
    print("Account number {} credit limit is set to {}".format(account_number, credit_limit))
    conn.commit()

    def withdraw(self, account_number, acctype, amount):
    with conn:
    account_found = BankAccount.get_account(self, account_number, acctype)
    if account_found:
    balance = account_found[3]
    credit_limit = CreditCard.get_credit_limit(self, account_number)
    amount_left = credit_limit - (int(balance))

    if balance - (int(amount)) < credit_limit:
    print("Your balance is: {}, and your credit limit is: {}".format(balance, credit_limit))
    print("The max you can withdraw is {}".format(amount_left))
    else:
    existing_bal = account_found[3]
    c.execute("""UPDATE credit_card SET balance=balance -:amount
    WHERE account_number =:account_number""",
    {'account_number':account_number, 'amount':amount})
    print("${} has been withdrawn from account {} and the new balance is ${}".format(amount, account_number, existing_bal - (int(amount))))

    notif_set = BankAccount.get_notif(self, account_number, acctype)
    if notif_set is None:
    print("No notifications have been set for this acct")
    else:
    notif_withdraw = notif_set[7]
    if notif_withdraw == 1:
    notify = BankAccount.send_email(self,account_number, acctype, 'Withdraw', amount, existing_bal - amount)
    conn.commit()









    share|improve this question









    New contributor




    anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$















      1












      1








      1





      $begingroup$


      Python beginner here. Building an OOP bank account program with SQLite and starting to struggle a bit with its design. From a design standpoint I have a file (bank) which calls ATM. ATM simulates an ATM, and is the file which then calls bank_account or credit_card depending on the account data passed in from bank.



      To initially setup an account I decided to put this into a different file, for example bank_account_setup or for credit_card, credit_card_setup. These would create_account, help setup pin etc so that the account is created and ready to use. Then the actual bank_account or credit_card contains other functions, like, deposit, withdraw, get_balance etc. Also, send_email is in another file



      My question is basically around my design. Is there a way to structure this better? How about my setup files to create bank or credit card accounts? Is that a good or bad idea? Also, another issue I am having is that when I run bank I pass in account type to ATM. In ATM I then had to know what class I am using in advance and instantiate that inside ATM. Could I handle that dynamically? (Also, the code does work - just concerned with bad design).



      Here's my calling file bank:



      import atm

      class BankAccount:

      def __init__(self, name, social, account_number, balance, acctype):
      self.name = name
      self.social = social
      self.account_number = account_number
      self.balance = balance
      self.acctype = acctype

      if __name__ == '__main__':

      obj1 = atm.ATM.main_menu( "Frank Smith", 135063522, 5544, 850, 'credit_card', 4400110022004400)


      Here's ATM, which calls the other files:



      import sqlite3, smtplib
      import bank_account
      import secrets
      import send_email
      import credit_card
      from email.mime.text import MIMEText
      from email.mime.multipart import MIMEMultipart
      from email.mime.base import MIMEBase
      from email import encoders

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class ATM:

      def get_pin(account_number, acctype, user_pin):
      with conn:
      db_pin = c.execute("SELECT pin from {} WHERE account_number=:account_number".format(acctype),
      {'account_number':account_number})
      db_pin = c.fetchone()
      if db_pin is not None:
      return(db_pin[0])
      else:
      print("db pin is None")
      pass

      def set_pin(account_number, acctype, input_code):
      with conn:
      get_code = ATM.get_user_code(account_number, acctype)
      if get_code is None:
      pass
      print("You need to request an authorization code first before you set your pin")
      else:
      if get_code !=input_code:
      print("Authorization code not valid")
      else:
      pin = input("Please set your 4 digit pin: ")
      if len(pin) < 4 or len(pin) >4 or len(pin) == 4 and pin.isdigit()==False:
      print("This is not a 4 digit pin")
      else:
      print("pin accepted")
      c.execute("""UPDATE {} SET pin=:pin
      WHERE account_number =:account_number""".format(acctype),
      {'account_number':account_number, 'pin':pin})
      print("Pin for account has been updated")


      def main_menu(name, social, account_number, balance, acctype, card_no=None):

      # obj1 = bank_account.BankAccount(name, social, account_number, balance, acctype)
      # obj1 = credit_card.CreditCard(name, social, account_number, balance, acctype, card_no)
      user_pin = int(input("nATM Home Screen. Please enter your pin code: "))
      db_pin = ATM.get_pin(account_number, acctype, user_pin)
      if user_pin != db_pin and db_pin != '':
      print("No pin match")
      elif db_pin is '':
      print("Pin has not been set")
      print("First request an authorization code and use that to set the pin")
      else:
      user_pin == db_pin
      print("nPin accepted continue n ")
      print("""""""ATM Menu, choose an option""""""")
      print("n1 - Deposit funds")
      print("2 - Withdraw funds")
      print("3 - Check balance")
      print("4 - Reset Pin")
      print("5 - Exit")

      while True:
      try:
      choice = int(input("Please enter a number: "))
      except ValueError:
      print("This is not a number")
      if choice >= 1 and choice <=5:
      if choice == 1:
      amount = input("nPlease enter the deposit amount: ")
      if amount != '' and amount.isdigit():
      int(amount)
      obj1.deposit( account_number, acctype, amount)
      else:
      print("Please enter a valid number")

      elif choice == 2:
      amount = input("Please enter the withdrawl amount: ")
      if amount != '' and amount.isdigit():
      int(amount)
      obj1.withdraw(account_number, acctype, amount)
      else:
      print("Please enter a valid number")

      elif choice ==3:
      obj1.get_balance(account_number, acctype)

      elif choice ==4:
      new_pin = input("Please enter a new 4 digit pin: ")
      if new_pin != '' and new_pin.isdigit():
      int(new_pin)
      obj1.set_reset_pin(account_number, acctype, new_pin)

      elif choice ==5:
      break

      else:
      print("Not a valid number")


      A piece of bank_account_setup:



      import sqlite3
      import secrets
      import getpass
      import smtplib, sqlite3
      from email.mime.text import MIMEText
      from email.mime.multipart import MIMEMultipart
      from email.mime.base import MIMEBase
      from email import encoders
      import send_email

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class BankAccount:

      def __init__(self, name, social, account_number, balance, acctype):
      self.name = name
      self.social = social
      self.account_number = account_number
      self.balance = balance
      self.acctype = acctype

      """ create different accounts based on account type passed in """
      def create_account(self, name, social, account_number, balance, acctype, card_no=None, credit_score=None, credit_limit=None):
      self.rate = None
      with conn:
      # account_found = BankAccount.get_account(self, account_number, acctype)
      # if not account_found:
      if acctype == 'bank_account':
      c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :pin)".format(acctype),
      {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'pin':''})
      print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

      elif acctype == 'savings_account':
      c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :rate)".format(acctype),
      {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'rate':''})
      print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

      elif acctype == 'credit_card':
      c.execute("INSERT INTO credit_card VALUES (:name, :social, :account_number, :balance, :card_no,:credit_score, :credit_limit, :pin)",
      {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'card_no'
      :card_no, 'credit_score':credit_score, 'credit_limit':credit_limit, 'pin':'' })
      print("New account: {} has been created, acc # is: {}".format(acctype, account_number))
      conn.commit()


      Piece of bank_account:



      import sqlite3
      import secrets
      import smtplib
      from email.mime.text import MIMEText
      from email.mime.multipart import MIMEMultipart
      from email.mime.base import MIMEBase
      from email import encoders
      import send_email

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class BankAccount:

      def __init__(self, name, social, account_number, balance, acctype):
      self.name = name
      self.social = social
      self.account_number = account_number
      self.balance = balance
      self.acctype = acctype


      def get_balance(self, account_number, acctype):
      with conn:
      balance = c.execute("SELECT balance from {} WHERE account_number=:account_number".format(acctype),
      {'account_number':account_number})
      balance = c.fetchone()
      print("The balance for account number: {} is ${}".format(account_number, balance[0]))
      notif_set = BankAccount.get_notif(self, account_number, acctype)
      if notif_set is None:
      print("No notifications are set for this user")
      else:
      notif_balance = notif_set[4]
      name = notif_set[0]
      if notif_balance == 1:
      notify = send_email.send_email(account_number, acctype, 'Balance', balance, balance, name)

      return(balance[0])

      """ Deposit funds into the account number + acctype for the account passed in """
      def deposit(self, account_number, acctype, amount):
      with conn:

      """ Check acct exists before making deposit """
      account_found = BankAccount.get_account(self, account_number, acctype)
      if account_found:
      existing_bal = account_found[3]
      c.execute("""UPDATE {} SET balance=balance +:amount
      WHERE account_number =:account_number""".format(acctype),
      {'account_number':account_number, 'amount':amount})
      new_bal = existing_bal + (int(amount))
      print("${} has been deposited to account {} and the new balance is ${}".format(amount, account_number, existing_bal + (int(amount))))

      # Check email configurations are turned on for deposits
      notif_set = BankAccount.get_notif(self, account_number, acctype)
      if notif_set is None:
      print("No notifications are set for this user")
      else:
      notif_deposits = notif_set[5]
      name = notif_set[0]
      if notif_deposits == 1:
      notify = send_email.send_email(account_number, acctype, 'Deposit', amount, new_bal, name)


      Piece of credit_card:



      from bank_account import BankAccount
      import sqlite3

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class CreditCard(BankAccount):
      def __init__(self, name, social, account_number, balance, acctype, card_no, credit_score=None, credit_limit=None):
      super().__init__(name, social, account_number, balance, acctype)
      self.card_no = card_no
      self.credit_score = credit_score
      self.credit_limit = credit_limit

      """ set credit limit, check if acct exists, then call get credit limit """
      def set_credit_limit(self, account_number, acctype, credit_score):
      with conn:
      account_found = BankAccount.get_account(self, account_number, acctype)
      if account_found:
      credit_limit = CreditCard.set_credit_limit_helper(self, account_number, credit_score)
      if credit_limit:
      c.execute("""UPDATE credit_card SET credit_limit=:credit_limit
      WHERE account_number =:account_number """,
      {'account_number':account_number, 'credit_limit':credit_limit})
      print("Account number {} credit limit is set to {}".format(account_number, credit_limit))
      conn.commit()

      def withdraw(self, account_number, acctype, amount):
      with conn:
      account_found = BankAccount.get_account(self, account_number, acctype)
      if account_found:
      balance = account_found[3]
      credit_limit = CreditCard.get_credit_limit(self, account_number)
      amount_left = credit_limit - (int(balance))

      if balance - (int(amount)) < credit_limit:
      print("Your balance is: {}, and your credit limit is: {}".format(balance, credit_limit))
      print("The max you can withdraw is {}".format(amount_left))
      else:
      existing_bal = account_found[3]
      c.execute("""UPDATE credit_card SET balance=balance -:amount
      WHERE account_number =:account_number""",
      {'account_number':account_number, 'amount':amount})
      print("${} has been withdrawn from account {} and the new balance is ${}".format(amount, account_number, existing_bal - (int(amount))))

      notif_set = BankAccount.get_notif(self, account_number, acctype)
      if notif_set is None:
      print("No notifications have been set for this acct")
      else:
      notif_withdraw = notif_set[7]
      if notif_withdraw == 1:
      notify = BankAccount.send_email(self,account_number, acctype, 'Withdraw', amount, existing_bal - amount)
      conn.commit()









      share|improve this question









      New contributor




      anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      Python beginner here. Building an OOP bank account program with SQLite and starting to struggle a bit with its design. From a design standpoint I have a file (bank) which calls ATM. ATM simulates an ATM, and is the file which then calls bank_account or credit_card depending on the account data passed in from bank.



      To initially setup an account I decided to put this into a different file, for example bank_account_setup or for credit_card, credit_card_setup. These would create_account, help setup pin etc so that the account is created and ready to use. Then the actual bank_account or credit_card contains other functions, like, deposit, withdraw, get_balance etc. Also, send_email is in another file



      My question is basically around my design. Is there a way to structure this better? How about my setup files to create bank or credit card accounts? Is that a good or bad idea? Also, another issue I am having is that when I run bank I pass in account type to ATM. In ATM I then had to know what class I am using in advance and instantiate that inside ATM. Could I handle that dynamically? (Also, the code does work - just concerned with bad design).



      Here's my calling file bank:



      import atm

      class BankAccount:

      def __init__(self, name, social, account_number, balance, acctype):
      self.name = name
      self.social = social
      self.account_number = account_number
      self.balance = balance
      self.acctype = acctype

      if __name__ == '__main__':

      obj1 = atm.ATM.main_menu( "Frank Smith", 135063522, 5544, 850, 'credit_card', 4400110022004400)


      Here's ATM, which calls the other files:



      import sqlite3, smtplib
      import bank_account
      import secrets
      import send_email
      import credit_card
      from email.mime.text import MIMEText
      from email.mime.multipart import MIMEMultipart
      from email.mime.base import MIMEBase
      from email import encoders

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class ATM:

      def get_pin(account_number, acctype, user_pin):
      with conn:
      db_pin = c.execute("SELECT pin from {} WHERE account_number=:account_number".format(acctype),
      {'account_number':account_number})
      db_pin = c.fetchone()
      if db_pin is not None:
      return(db_pin[0])
      else:
      print("db pin is None")
      pass

      def set_pin(account_number, acctype, input_code):
      with conn:
      get_code = ATM.get_user_code(account_number, acctype)
      if get_code is None:
      pass
      print("You need to request an authorization code first before you set your pin")
      else:
      if get_code !=input_code:
      print("Authorization code not valid")
      else:
      pin = input("Please set your 4 digit pin: ")
      if len(pin) < 4 or len(pin) >4 or len(pin) == 4 and pin.isdigit()==False:
      print("This is not a 4 digit pin")
      else:
      print("pin accepted")
      c.execute("""UPDATE {} SET pin=:pin
      WHERE account_number =:account_number""".format(acctype),
      {'account_number':account_number, 'pin':pin})
      print("Pin for account has been updated")


      def main_menu(name, social, account_number, balance, acctype, card_no=None):

      # obj1 = bank_account.BankAccount(name, social, account_number, balance, acctype)
      # obj1 = credit_card.CreditCard(name, social, account_number, balance, acctype, card_no)
      user_pin = int(input("nATM Home Screen. Please enter your pin code: "))
      db_pin = ATM.get_pin(account_number, acctype, user_pin)
      if user_pin != db_pin and db_pin != '':
      print("No pin match")
      elif db_pin is '':
      print("Pin has not been set")
      print("First request an authorization code and use that to set the pin")
      else:
      user_pin == db_pin
      print("nPin accepted continue n ")
      print("""""""ATM Menu, choose an option""""""")
      print("n1 - Deposit funds")
      print("2 - Withdraw funds")
      print("3 - Check balance")
      print("4 - Reset Pin")
      print("5 - Exit")

      while True:
      try:
      choice = int(input("Please enter a number: "))
      except ValueError:
      print("This is not a number")
      if choice >= 1 and choice <=5:
      if choice == 1:
      amount = input("nPlease enter the deposit amount: ")
      if amount != '' and amount.isdigit():
      int(amount)
      obj1.deposit( account_number, acctype, amount)
      else:
      print("Please enter a valid number")

      elif choice == 2:
      amount = input("Please enter the withdrawl amount: ")
      if amount != '' and amount.isdigit():
      int(amount)
      obj1.withdraw(account_number, acctype, amount)
      else:
      print("Please enter a valid number")

      elif choice ==3:
      obj1.get_balance(account_number, acctype)

      elif choice ==4:
      new_pin = input("Please enter a new 4 digit pin: ")
      if new_pin != '' and new_pin.isdigit():
      int(new_pin)
      obj1.set_reset_pin(account_number, acctype, new_pin)

      elif choice ==5:
      break

      else:
      print("Not a valid number")


      A piece of bank_account_setup:



      import sqlite3
      import secrets
      import getpass
      import smtplib, sqlite3
      from email.mime.text import MIMEText
      from email.mime.multipart import MIMEMultipart
      from email.mime.base import MIMEBase
      from email import encoders
      import send_email

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class BankAccount:

      def __init__(self, name, social, account_number, balance, acctype):
      self.name = name
      self.social = social
      self.account_number = account_number
      self.balance = balance
      self.acctype = acctype

      """ create different accounts based on account type passed in """
      def create_account(self, name, social, account_number, balance, acctype, card_no=None, credit_score=None, credit_limit=None):
      self.rate = None
      with conn:
      # account_found = BankAccount.get_account(self, account_number, acctype)
      # if not account_found:
      if acctype == 'bank_account':
      c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :pin)".format(acctype),
      {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'pin':''})
      print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

      elif acctype == 'savings_account':
      c.execute("INSERT INTO {} VALUES (:name, :social, :account_number, :balance, :rate)".format(acctype),
      {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'rate':''})
      print("New account: {} has been created, acc # is: {}".format(acctype, account_number))

      elif acctype == 'credit_card':
      c.execute("INSERT INTO credit_card VALUES (:name, :social, :account_number, :balance, :card_no,:credit_score, :credit_limit, :pin)",
      {'name':name, 'social': social,'account_number': account_number, 'balance':balance, 'card_no'
      :card_no, 'credit_score':credit_score, 'credit_limit':credit_limit, 'pin':'' })
      print("New account: {} has been created, acc # is: {}".format(acctype, account_number))
      conn.commit()


      Piece of bank_account:



      import sqlite3
      import secrets
      import smtplib
      from email.mime.text import MIMEText
      from email.mime.multipart import MIMEMultipart
      from email.mime.base import MIMEBase
      from email import encoders
      import send_email

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class BankAccount:

      def __init__(self, name, social, account_number, balance, acctype):
      self.name = name
      self.social = social
      self.account_number = account_number
      self.balance = balance
      self.acctype = acctype


      def get_balance(self, account_number, acctype):
      with conn:
      balance = c.execute("SELECT balance from {} WHERE account_number=:account_number".format(acctype),
      {'account_number':account_number})
      balance = c.fetchone()
      print("The balance for account number: {} is ${}".format(account_number, balance[0]))
      notif_set = BankAccount.get_notif(self, account_number, acctype)
      if notif_set is None:
      print("No notifications are set for this user")
      else:
      notif_balance = notif_set[4]
      name = notif_set[0]
      if notif_balance == 1:
      notify = send_email.send_email(account_number, acctype, 'Balance', balance, balance, name)

      return(balance[0])

      """ Deposit funds into the account number + acctype for the account passed in """
      def deposit(self, account_number, acctype, amount):
      with conn:

      """ Check acct exists before making deposit """
      account_found = BankAccount.get_account(self, account_number, acctype)
      if account_found:
      existing_bal = account_found[3]
      c.execute("""UPDATE {} SET balance=balance +:amount
      WHERE account_number =:account_number""".format(acctype),
      {'account_number':account_number, 'amount':amount})
      new_bal = existing_bal + (int(amount))
      print("${} has been deposited to account {} and the new balance is ${}".format(amount, account_number, existing_bal + (int(amount))))

      # Check email configurations are turned on for deposits
      notif_set = BankAccount.get_notif(self, account_number, acctype)
      if notif_set is None:
      print("No notifications are set for this user")
      else:
      notif_deposits = notif_set[5]
      name = notif_set[0]
      if notif_deposits == 1:
      notify = send_email.send_email(account_number, acctype, 'Deposit', amount, new_bal, name)


      Piece of credit_card:



      from bank_account import BankAccount
      import sqlite3

      conn = sqlite3.connect('bank_account.db')
      c = conn.cursor()

      class CreditCard(BankAccount):
      def __init__(self, name, social, account_number, balance, acctype, card_no, credit_score=None, credit_limit=None):
      super().__init__(name, social, account_number, balance, acctype)
      self.card_no = card_no
      self.credit_score = credit_score
      self.credit_limit = credit_limit

      """ set credit limit, check if acct exists, then call get credit limit """
      def set_credit_limit(self, account_number, acctype, credit_score):
      with conn:
      account_found = BankAccount.get_account(self, account_number, acctype)
      if account_found:
      credit_limit = CreditCard.set_credit_limit_helper(self, account_number, credit_score)
      if credit_limit:
      c.execute("""UPDATE credit_card SET credit_limit=:credit_limit
      WHERE account_number =:account_number """,
      {'account_number':account_number, 'credit_limit':credit_limit})
      print("Account number {} credit limit is set to {}".format(account_number, credit_limit))
      conn.commit()

      def withdraw(self, account_number, acctype, amount):
      with conn:
      account_found = BankAccount.get_account(self, account_number, acctype)
      if account_found:
      balance = account_found[3]
      credit_limit = CreditCard.get_credit_limit(self, account_number)
      amount_left = credit_limit - (int(balance))

      if balance - (int(amount)) < credit_limit:
      print("Your balance is: {}, and your credit limit is: {}".format(balance, credit_limit))
      print("The max you can withdraw is {}".format(amount_left))
      else:
      existing_bal = account_found[3]
      c.execute("""UPDATE credit_card SET balance=balance -:amount
      WHERE account_number =:account_number""",
      {'account_number':account_number, 'amount':amount})
      print("${} has been withdrawn from account {} and the new balance is ${}".format(amount, account_number, existing_bal - (int(amount))))

      notif_set = BankAccount.get_notif(self, account_number, acctype)
      if notif_set is None:
      print("No notifications have been set for this acct")
      else:
      notif_withdraw = notif_set[7]
      if notif_withdraw == 1:
      notify = BankAccount.send_email(self,account_number, acctype, 'Withdraw', amount, existing_bal - amount)
      conn.commit()






      python object-oriented finance sqlite






      share|improve this question









      New contributor




      anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 3 mins ago









      200_success

      130k16153417




      130k16153417






      New contributor




      anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 2 hours ago









      anfieldanfield

      6




      6




      New contributor




      anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      anfield is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          anfield is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214886%2foop-bank-account-program-in-python-3%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          anfield is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          anfield is a new contributor. Be nice, and check out our Code of Conduct.













          anfield is a new contributor. Be nice, and check out our Code of Conduct.












          anfield is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214886%2foop-bank-account-program-in-python-3%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Список кардиналов, возведённых папой римским Каликстом III

          Deduzione

          Mysql.sock missing - “Can't connect to local MySQL server through socket”