+1 678 648 4277 

Banking Application using Python Homework Solution


Bank Application Management

Problem Overview:

You will build a banking application that processes transactions. This banking application consists of three phases.

  1. The program will read in a string of transactions from a file into an in-memory queue. These transactions can open accounts, withdraw funds, deposit funds, transfer funds, or ask for the transactional history to be printed.
  2. The program will next read from the queue and process the transactions in order.
  3. When the queue has been depleted the program will print out all open accounts and balances in those accounts.

Details:

Input:

To test your program a file called BankTransIn.txt will be utilized. Your program should assume a file with this exact name. We will use different variants of this file for testing. Transactions of the format described below (see the section on transactions) will be contained in this file. There will be one transaction per line

Assume that the input is well-formed—that is, there are no syntax errors. That said, there may be errors in the transactions themselves. For instance, a transaction may try to withdraw more money than there is a fund or try to withdraw for a non-existent fund. See the section below entitled errors for details.

Client Accounts and Funds:

Each client account contains assets held in up to ten funds. A client account is represented by a first and last name (two strings) and a unique 4 digit identifier. A fifth digit can be added to the digit id to represent the individual fund within the account as enumerated below:

Bank 1

For instance, 23452 represents the Long-Term Bond fund for client account 2345. A client account is opened as a transaction (see below).

Transactions:

There are five types of transactions and each is identified by a character beginning the line.

O: Open a client account with the appropriate funds D: Deposit assets into a fund

W: Withdraw assets from a fund

T: Transfer assets between funds (can be funds owned by a single client or transfers between clients)

H: Display the history of all transactions for a client account or for a single fund.

Include errors in the output where appropriate.

After this character key, the account-fund number is given followed by relevant information for the transaction.

Examples:

Bank 2

Errors:

As noted above, assume the format (number and types of input items) are correct. However, the program should deal with all other types of errors. For instance, there could be a bad account number (for instance, one already used) or an amount which is too much to withdraw. Also, assume that each line will begin with an appropriate letter: O, W, D, H, or T.

Examples of errors that may occur:

W 65439 10000 (when the Value Stock Index of client 6543 has only $20) D 765435 76

 A transaction that would cause a balance to become negative should not occur and is an error. There is one exception to this rule: if you are withdrawing from a money market fund with insufficient dollars, and it can be covered with dollars from the other money market fund owned by the client account, the desired amount (only the partial amount needed to cover the withdrawal) is moved to that money market account. The two Bond accounts are handled similarly. No other types of accounts are handled in this manner.

Appropriate error messages should be printed out to the console. No other messages should be printed out during phase 1 or phase 2.

Output:

In Phase 3, each client account will be printed out with the amount held in each account. Please make sure to create an intuitive and readable output for this aspect of the program. This should be part of the design.

Data Structures:

One key aspect of this Lab exercise is the right class design for handling the problem. So in general there are no pre-defined classes or signature structures for the classes required. This is up to you to define. However, there are two data structures that are required.

First, you need to use a queue to read the transactions during phase 1. All transactions should be read before processing starts. You can use the queue found in the queue module if you like.

Second, the client accounts should be stored in a binary search tree (BSTree). You should design and code the BST. We have spent time in class on making progress on this.

Solution:

Account:

from Fund import * class Account: def __init__(self, client_id, lastname, firstname): self.lastname = lastname self.firstname = firstname self.client_id = client_id self.funds = [] for i in range(10): self.funds.append(Fund(i)) def deposit(self, fund_id, amount, action, success): if fund_id > 9 or fund_id < 0: return f"ERROR: Deposit for a non-existent fund" else: self.funds[fund_id].deposit(amount, action, success) def withdraw(self, fund_id, amount, action): if fund_id > 9 or fund_id < 0: return f"ERROR: Withdraw for a non-existent fund" if not self.funds[fund_id].withdraw(amount, action): return f"ERROR: Not enough funds to withdraw {amount} from " \ f"{self.firstname} {self.lastname} {self.funds[fund_id].name}" def __lt__(self, x): key = x if x is Account: key = x.client_id if self.client_id < key: return True else: return False def __le__(self, x): key = x if x is Account: key = x.client_id if self.client_id <= key: return True else: return False def __eq__(self, x): key = x if x is Account: key = x.client_id if self.client_id == key: return True else: return False def __ne__(self, x): key = x if x is Account: key = x.client_id if self.client_id != key: return True else: return False def __ge__(self, x): key = x if x is Account: key = x.client_id if self.client_id >= key: return True else: return False def __gt__(self, x): key = x if x is Account: key = x.client_id if self.client_id > key: return True else: return False def __str__(self): result = f"{self.firstname} {self.lastname} Account ID: {self.client_id}\n" for i in range(10): result += f" {self.funds[i]}\n" return result

Node:

class Node: def __init__(self, val=None): self.left = None self.right = None self.val = val def insert(self, val): if not self.val: self.val = val return if self.val == val: return elif val < self.val: if self.left: self.left.insert(val) return self.left = Node(val) return else: if self.right: self.right.insert(val) return self.right = Node(val) def search(self, key): if self.val is None: return None if key == self.val: return self.val if key < self.val: if self.left is None: return None return self.left.search(key) if self.right is None: return None return self.right.search(key) def __in_order(self, result): if self.left is not None: self.left.__in_order(result) # print(self.val) result.append(self.val) if self.right is not None: self.right.__in_order(result) def nodes(self): result = [] self.__in_order(result) return result

Bank Transaction:

from Account import * from Node import * # Build a banking application which processes transactions # Three Phases # 1) The program will read in a string of transactions from a file into an in-memory queue. # These transactions can open __accounts, withdraw funds, deposit funds, transfer funds, # or ask for the transactional history to be printed. # 2) The program will next read from the queue and process the transactions in order. # 3) When the queue has been depleted the program will print out all open __accounts and # balances in those __accounts. class BankTrans: def __init__(self): self.__accounts = Node() def open_account(self, client_id, last_name, first_name): client_id = int(client_id) if self.__exists(client_id): return f"ERROR: Account {client_id} is already open. Transaction refused." self.__accounts.insert(Account(client_id, last_name, first_name)) def deposit(self, client_id, fund_id, amount): self.__deposit(client_id, fund_id, amount, f"D {fund_id} {amount}", True) def __deposit(self, client_id, fund_id, amount, action, success): client_id = int(client_id) fund_id = int(fund_id) amount = int(amount) account = self.__accounts.search(client_id) if account is not None: return account.deposit(fund_id, amount, action, success) else: return f"ERROR: Account {client_id} not found. Deposit refused." def withdraw(self, client_id, fund_id, amount): self.__withdraw(client_id, fund_id, amount, f"W {fund_id} {amount}") def __withdraw(self, client_id, fund_id, amount, action): client_id = int(client_id) fund_id = int(fund_id) amount = int(amount) account = self.__accounts.search(client_id) if account is not None: return account.withdraw(fund_id, amount, action) else: return f"ERROR: Account {client_id} not found. Withdraw refused." def transfer(self, src, dst, amount): src_client_id = int(src[0:4]) src_fund_id = int(src[4]) dst_client_id = int(dst[0:4]) dst_fund_id = int(dst[4]) src_account = self.__accounts.search(src_client_id) if src_account is None: return f"ERROR: Account {src_client_id} not found. Transferal refused." dst_account = self.__accounts.search(dst_client_id) if dst_account is None: return f"ERROR: Account {dst_client_id} not found. Transferal refused." src_resp = self.__withdraw(src_client_id, src_fund_id, amount, f"T {src} {amount} {dst}") if src_resp is not None: success = False else: success = False dst_resp = self.__deposit(dst_client_id, dst_fund_id, amount, f"T {src} {amount} {dst}", success) if src_resp is not None and dst_resp is not None: return f"{src_resp}\n{dst_resp}" elif src_resp is not None: return f"{src_resp}" elif dst_resp is not None: return f"{dst_resp}" def __exists(self, client_id): client_id = int(client_id) if self.__accounts.search(client_id) is not None: return True else: return False def history(self, client_id, fund_ids): account: Account = self.__accounts.search(client_id) if account is not None: if len(fund_ids) == 1: fund_id = int(fund_ids[0]) result = f"Transaction History for {account.firstname} {account.lastname}" \ f" {account.funds[fund_id]}\n" \ f"{account.funds[fund_id].report()}" else: result = f"Transaction History for {account.firstname} {account.lastname} by fund.\n" for i in range(10): if account.funds[i].amount > 0: result += f"{account.funds[i]}\n" \ f"{account.funds[i].report()}" return result else: return f"ERROR: Account {client_id} not found. Transaction refused." def report_all(self): return self.__accounts.nodes() def main(): bank = BankTrans() fin = open("BankTransIn.txt", "r") fout = open("BankTransOut.txt", "w") for i in fin.readlines(): data = i.rstrip("\n").split() trans_type = data[0] # Assume that each line will begin with # an appropriate letter: O, W, D, H, or T if trans_type == 'O': # O: Open a client account with the appropriate funds last_name = data[1] first_name = data[2] client_id = data[3] response = bank.open_account(client_id, last_name, first_name) if response is not None: fout.write(response + "\n") elif trans_type == 'D': # D: Deposit assets into a fund client_id = data[1][0:4] fund_id = data[1][4] amount = data[2] response = bank.deposit(client_id, fund_id, amount) if response is not None: fout.write(response + "\n") elif trans_type == 'W': # W: Withdraw assets from a fund client_id = data[1][0:4] fund_id = data[1][4] amount = data[2] response = bank.withdraw(client_id, fund_id, amount) if response is not None: fout.write(response + "\n") elif trans_type == 'T': # T: Transfer assets between funds (can be funds owned # by a single client or transfers between clients) src = data[1] dst = data[3] amount = data[2] response = bank.transfer(src, dst, amount) if response is not None: fout.write(response + "\n") elif trans_type == 'H': # H: Display the history of all transactions for a client # account or for a single fund. if len(data[1]) == 4: client_id = int(data[1]) fund_ids = list(range(10)) else: client_id = int(data[1][0:4]) fund_ids = [data[1][4]] fout.write(bank.history(client_id, fund_ids) + "\n") else: # Include errors in the output where appropriate. fout.write("Error: Invalid Transaction Type\n") fout.write("\n") fout.write("Processing Done. Final Balances\n") for n in bank.report_all(): fout.write(f"{n}\n") fin.close() fout.close() if __name__ == "__main__": main()

Fund:

class Fund: def __init__(self, fund_type): self.__fund_name = {0: "Money Market", 1: "Prime Money Market", 2: "Long-Term Bond", 3: "Short-Term Bond", 4: "500 Index Fund", 5: "Capital Value Fund", 6: "Growth Equity Fund", 7: "Growth Index Fund", 8: "Value Fund", 9: "Value Stock Index"} self.fund_type = fund_type self.amount = 0 self.transaction = [] def deposit(self, amount, action, success): if success: self.amount += amount self.add_record(action, success) def withdraw(self, amount, action): if amount > self.amount: success = False else: self.amount -= amount success = True self.add_record(action, success) return success def add_record(self, action, success): status = "" if success else " (Failed)" self.transaction.append(f"{action}{status}") def name(self): return self.__fund_name[self.fund_type] def __str__(self): return f"{self.name()}: ${self.amount}" def report(self): result = "" for t in self.transaction: result += f" {t}\n" return result