From 85ada9226c4df15c979e583ef0b6b1a682b19240 Mon Sep 17 00:00:00 2001 From: Andrew Schott Date: Sun, 8 Mar 2015 23:09:32 -0400 Subject: [PATCH] This for the coding Test --- abcbank/account.py | 111 ++++++++++++++++++++++++++++++++----- abcbank/bank.py | 8 +++ abcbank/config.json | 4 ++ abcbank/customer.py | 22 +++++--- tests/bank_tests.py | 13 ++--- tests/customer_tests.py | 46 ++++++++++----- tests/transaction_tests.py | 3 +- 7 files changed, 161 insertions(+), 46 deletions(-) create mode 100644 abcbank/config.json diff --git a/abcbank/account.py b/abcbank/account.py index e010009..2f8dafc 100644 --- a/abcbank/account.py +++ b/abcbank/account.py @@ -1,43 +1,124 @@ from abcbank.transaction import Transaction - +import json, os CHECKING = 0 SAVINGS = 1 MAXI_SAVINGS = 2 +full_path = os.path.realpath(__file__) +config = os.path.dirname(full_path) + "/config.json" -class Account: +class Account(object): def __init__(self, accountType): self.accountType = accountType + self.configPath = "" self.transactions = [] def deposit(self, amount): + #deposits an amount into a customer's account if (amount <= 0): raise ValueError("amount must be greater than zero") else: self.transactions.append(Transaction(amount)) def withdraw(self, amount): + #withdraws the amount specified from the customer's account if (amount <= 0): raise ValueError("amount must be greater than zero") else: self.transactions.append(Transaction(-amount)) + + def transfer(self, amount, toAcct): + #transfers the amount specified from one account to another. + #Once hooked into a database we can set a max for transfers based on account balances. + if (amount <= 0): + raise ValueError("amount must be greater than zero") + else: + self.transactions.append(Transaction(-amount)) + toAcct.transactions.append(Transaction(amount)) + - def interestEarned(self): + def interestEarned(self, duration=None): + #interest eared over a duration, duration is expressed as 1 being one year, + #This version utilizes a json config file so that it can be quickly referenced + #by many files and easily edited without effecting the rest of the system or + #requiring a recommit. + json_data = open(config) + data = json.load(json_data) + json_data.close() amount = self.sumTransactions() + #these allow for the use of duration and compound frequency without being required. + if duration is None: + duration = 1 + if self.accountType == SAVINGS: - if (amount <= 1000): - return amount * 0.001 + sb1=data["savings"][0]["breakpoint"] + sr1=data["savings"][0]["rate"] + sr2=data["savings"][1]["rate"] + sf =data["savings"][0]["frequency"] + freq = sf + if (amount <= sb1): + rate = sr1 + earned = self.interestEarnedTime(amount,rate,freq,duration) + self.result = self.twoPlaces(earned) else: - return 1 + (amount - 1000) * 0.002 - if self.accountType == MAXI_SAVINGS: - if (amount <= 1000): - return amount * 0.02 - elif (amount <= 2000): - return 20 + (amount - 1000) * 0.05 + rate = sr2 + sofar = self.interestEarnedTime(sb1,sr1,freq,duration) + sb2 = self.interestEarnedTime((amount-sb1),rate,freq,duration) + earned = sofar + sb2 + self.result = self.twoPlaces(earned) + + elif self.accountType == MAXI_SAVINGS: + mb1=data["maxi"][0]["breakpoint"] + mr1=data["maxi"][0]["rate"] + mb2=data["maxi"][1]["breakpoint"] + mr2=data["maxi"][1]["rate"] + mr3=data["maxi"][2]["rate"] + mf =data["maxi"][0]["frequency"] + freq = mf + if (amount <= mb1): + rate = mr1 + earned = self.interestEarnedTime(amount,rate,freq,duration) + self.result = self.twoPlaces(earned) + + elif (amount <= mb2): + rate = mr2 + principal = amount - mb1 + earned =(mr1*mb1) + self.interestEarnedTime(principal,rate,freq,duration) + self.result = self.twoPlaces(earned) + else: - return 70 + (amount - 2000) * 0.1 - else: - return amount * 0.001 + rate = mr3 + principal = amount - mb2 + c1 = self.interestEarnedTime(mb1,mr1,freq,duration) + c2 = self.interestEarnedTime((mb2-mb1),mr2,freq,duration) + res = self.interestEarnedTime(principal,rate,freq,duration) + earned = c1 + c2 + res + self.result = self.twoPlaces(earned) + + elif self.accountType == CHECKING: + cr1=data["checking"][0]["rate"] + cf =data["checking"][0]["frequency"] + freq = cf + rate = cr1 + earned = self.interestEarnedTime(amount,rate,freq,duration) + self.result = self.twoPlaces(earned) + + return self.result def sumTransactions(self, checkAllTransactions=True): - return sum([t.amount for t in self.transactions]) \ No newline at end of file + return sum([t.amount for t in self.transactions]) + + def twoPlaces(self,value): + #quick reusable funciton to round to 2 spots to make it easier to put in to a dollar value + return float("{0:.2f}".format(value)) + + def interestEarnedTime(self,principal, rate,times_per_year, years): + #this function is the formula for interest and it can be set up to account + #for duration as well as compound frequency + # (1 + r/n) + body = 1 + (rate / times_per_year) + # nt + exponent = times_per_year * years + # P(1 + r/n)^nt + return principal * pow(body, exponent) -principal + diff --git a/abcbank/bank.py b/abcbank/bank.py index 44711fe..5ef562c 100644 --- a/abcbank/bank.py +++ b/abcbank/bank.py @@ -4,19 +4,27 @@ def __init__(self): def addCustomer(self, customer): self.customers.append(customer) + def customerSummary(self): + #returns a summary of a customer's accounts summary = "Customer Summary" for customer in self.customers: summary = summary + "\n - " + customer.name + " (" + self._format(customer.numAccs(), "account") + ")" return summary + def _format(self, number, word): + #returns a formatted string with the proper sytax return str(number) + " " + (word if (number == 1) else word + "s") + def totalInterestPaid(self): + #returns the total interest paid by the bank to all customers requested total = 0 for c in self.customers: total += c.totalInterestEarned() return total + def getFirstCustomer(self): + #returns the first cutomer's name try: self.customers = None return self.customers[0].name diff --git a/abcbank/config.json b/abcbank/config.json new file mode 100644 index 0000000..45bb3f1 --- /dev/null +++ b/abcbank/config.json @@ -0,0 +1,4 @@ +{"maxi":[{"rate":0.02,"breakpoint":1000.00,"frequency":365},{"rate":0.05,"breakpoint":2000.00},{"rate":0.1,"breakpoint":0}], +"savings":[{"rate":0.001,"breakpoint":1000.00,"frequency":365},{"rate":0.002}], +"checking":[{"frequency":365,"rate":0.001}] +} \ No newline at end of file diff --git a/abcbank/customer.py b/abcbank/customer.py index 7cfd62a..bbd66ed 100644 --- a/abcbank/customer.py +++ b/abcbank/customer.py @@ -1,4 +1,4 @@ -from account import CHECKING, SAVINGS, MAXI_SAVINGS +from abcbank.account import CHECKING, SAVINGS, MAXI_SAVINGS class Customer: @@ -7,20 +7,20 @@ def __init__(self, name): self.accounts = [] def openAccount(self, account): + #opens an account for customer self.accounts.append(account) return self def numAccs(self): + #this returns the number of accounts return len(self.accounts) def totalInterestEarned(self): + #Returns the total interest earned across all acounts return sum([a.interestEarned() for a in self.accounts]) - - # This method gets a statement + def getStatement(self): - # JIRA-123 Change by Joe Bloggs 29/7/1988 start - statement = None # reset statement to null here - # JIRA-123 Change by Joe Bloggs 29/7/1988 end + # This method gets a statement totalAcrossAllAccounts = sum([a.sumTransactions() for a in self.accounts]) statement = "Statement for %s" % self.name for account in self.accounts: @@ -29,6 +29,7 @@ def getStatement(self): return statement def statementForAccount(self, account): + # This puts the statement in a human readable format. accountType = "\n\n\n" if account.accountType == CHECKING: accountType = "\n\nChecking Account\n" @@ -38,11 +39,13 @@ def statementForAccount(self, account): accountType = "\n\nMaxi Savings Account\n" transactionSummary = [self.withdrawalOrDepositText(t) + " " + _toDollars(abs(t.amount)) for t in account.transactions] - transactionSummary = " " + "\n ".join(transactionSummary) + "\n" - totalSummary = "Total " + _toDollars(sum([t.amount for t in account.transactions])) - return accountType + transactionSummary + totalSummary + joinedTransactionSummary = " " + "\n ".join(transactionSummary) + "\n" + self.balance = sum([t.amount for t in account.transactions]) + totalSummary = "Total " + _toDollars(self.balance) + return accountType + joinedTransactionSummary + totalSummary def withdrawalOrDepositText(self, transaction): + #returns proper text for if a transaction was a withdrawal or deposit if transaction.amount < 0: return "withdrawal" elif transaction.amount > 0: @@ -52,4 +55,5 @@ def withdrawalOrDepositText(self, transaction): def _toDollars(number): + #returns float value to dollars. return "${:1.2f}".format(number) diff --git a/tests/bank_tests.py b/tests/bank_tests.py index 6de98db..5d9fd73 100644 --- a/tests/bank_tests.py +++ b/tests/bank_tests.py @@ -1,8 +1,7 @@ from nose.tools import assert_equals - -from account import Account, CHECKING, MAXI_SAVINGS, SAVINGS -from bank import Bank -from customer import Customer +from abcbank.account import Account, CHECKING, MAXI_SAVINGS, SAVINGS +from abcbank.bank import Bank +from abcbank.customer import Customer def test_customer_summary(): @@ -25,7 +24,7 @@ def test_checking_account(): def test_savings_account(): bank = Bank() checkingAccount = Account(SAVINGS) - bank.addCustomer(Customer("Bill").openAccount(checkingAccount)) + bank.addCustomer(Customer("Andrew").openAccount(checkingAccount)) checkingAccount.deposit(1500.0) assert_equals(bank.totalInterestPaid(), 2.0) @@ -33,6 +32,6 @@ def test_savings_account(): def test_maxi_savings_account(): bank = Bank() checkingAccount = Account(MAXI_SAVINGS) - bank.addCustomer(Customer("Bill").openAccount(checkingAccount)) + bank.addCustomer(Customer("Gabriela").openAccount(checkingAccount)) checkingAccount.deposit(3000.0) - assert_equals(bank.totalInterestPaid(), 170.0) \ No newline at end of file + assert_equals(bank.totalInterestPaid(), 176.62) \ No newline at end of file diff --git a/tests/customer_tests.py b/tests/customer_tests.py index 0211a4f..fa81d22 100644 --- a/tests/customer_tests.py +++ b/tests/customer_tests.py @@ -1,13 +1,14 @@ -from nose.tools import assert_equals, nottest - -from account import Account, CHECKING, SAVINGS -from customer import Customer +from nose.tools import assert_equals +from abcbank.account import Account, CHECKING, SAVINGS, MAXI_SAVINGS +from abcbank.customer import Customer def test_statement(): + #statement test checkingAccount = Account(CHECKING) savingsAccount = Account(SAVINGS) - henry = Customer("Henry").openAccount(checkingAccount).openAccount(savingsAccount) + henry = Customer("Henry").openAccount(checkingAccount) + henry.openAccount(savingsAccount) checkingAccount.deposit(100.0) savingsAccount.deposit(4000.0) savingsAccount.withdraw(200.0) @@ -16,21 +17,40 @@ def test_statement(): "\n\nChecking Account\n deposit $100.00\nTotal $100.00" + "\n\nSavings Account\n deposit $4000.00\n withdrawal $200.00\nTotal $3800.00" + "\n\nTotal In All Accounts $3900.00") - + +def test_transfer(): + #transfer test + checkingAccount = Account(CHECKING) + savingsAccount = Account(SAVINGS) + andy = Customer("Andy").openAccount(checkingAccount) + andy.openAccount(savingsAccount) + savingsAccount.deposit(4000.0) + savingsAccount.transfer(200.0,checkingAccount) + assert_equals(andy.getStatement(), + "Statement for Andy" + + "\n\nChecking Account\n deposit $200.00\nTotal $200.00" + + "\n\nSavings Account\n deposit $4000.00\n withdrawal $200.00\nTotal $3800.00" + + "\n\nTotal In All Accounts $4000.00") def test_oneAccount(): + #single account test oscar = Customer("Oscar").openAccount(Account(SAVINGS)) assert_equals(oscar.numAccs(), 1) def test_twoAccounts(): - oscar = Customer("Oscar").openAccount(Account(SAVINGS)) - oscar.openAccount(Account(CHECKING)) - assert_equals(oscar.numAccs(), 2) + #two account test + jerry = Customer("Jerry").openAccount(Account(SAVINGS)) + jerry.openAccount(Account(CHECKING)) + assert_equals(jerry.numAccs(), 2) -@nottest def test_threeAccounts(): - oscar = Customer("Oscar").openAccount(Account(SAVINGS)) - oscar.openAccount(Account(CHECKING)) - assert_equals(oscar.numAccs(), 3) \ No newline at end of file + #two account test + steve = Customer("Steve").openAccount(Account(SAVINGS)) + steve.openAccount(Account(CHECKING)) + steve.openAccount(Account(MAXI_SAVINGS)) + assert_equals(steve.numAccs(), 3) + + + \ No newline at end of file diff --git a/tests/transaction_tests.py b/tests/transaction_tests.py index 62caa8a..aac0293 100644 --- a/tests/transaction_tests.py +++ b/tests/transaction_tests.py @@ -1,6 +1,5 @@ from nose.tools import assert_is_instance - -from transaction import Transaction +from abcbank.transaction import Transaction def test_type():