From 4ca31fddab100d2ea753232d186041db357a3dca Mon Sep 17 00:00:00 2001 From: Deepak Date: Wed, 18 May 2016 23:14:02 -0400 Subject: [PATCH 01/10] fixed formatting & testcases importing errors --- abcbank/bank.py | 6 +++++- tests/bank_tests.py | 6 +++--- tests/customer_tests.py | 4 ++-- tests/transaction_tests.py | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/abcbank/bank.py b/abcbank/bank.py index 44711fe..e3f2d58 100644 --- a/abcbank/bank.py +++ b/abcbank/bank.py @@ -4,22 +4,26 @@ def __init__(self): def addCustomer(self, customer): self.customers.append(customer) + def customerSummary(self): 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): return str(number) + " " + (word if (number == 1) else word + "s") + def totalInterestPaid(self): total = 0 for c in self.customers: total += c.totalInterestEarned() return total + def getFirstCustomer(self): try: self.customers = None return self.customers[0].name except Exception as e: print(e) - return "Error" \ No newline at end of file + return "Error" diff --git a/tests/bank_tests.py b/tests/bank_tests.py index 6de98db..926ebf5 100644 --- a/tests/bank_tests.py +++ b/tests/bank_tests.py @@ -1,8 +1,8 @@ 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(): diff --git a/tests/customer_tests.py b/tests/customer_tests.py index 0211a4f..65acfcc 100644 --- a/tests/customer_tests.py +++ b/tests/customer_tests.py @@ -1,7 +1,7 @@ from nose.tools import assert_equals, nottest -from account import Account, CHECKING, SAVINGS -from customer import Customer +from abcbank.account import Account, CHECKING, SAVINGS +from abcbank.customer import Customer def test_statement(): diff --git a/tests/transaction_tests.py b/tests/transaction_tests.py index 62caa8a..e44b0c0 100644 --- a/tests/transaction_tests.py +++ b/tests/transaction_tests.py @@ -1,6 +1,6 @@ from nose.tools import assert_is_instance -from transaction import Transaction +from abcbank.transaction import Transaction def test_type(): From acbd5f17341025d636b72fb06ef371c37dd90394 Mon Sep 17 00:00:00 2001 From: Deepak Date: Wed, 18 May 2016 23:47:31 -0400 Subject: [PATCH 02/10] added available balance property to Account --- abcbank/account.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/abcbank/account.py b/abcbank/account.py index e010009..fb5ac46 100644 --- a/abcbank/account.py +++ b/abcbank/account.py @@ -9,18 +9,23 @@ class Account: def __init__(self, accountType): self.accountType = accountType self.transactions = [] + self.availableBalance = 0 def deposit(self, amount): if (amount <= 0): raise ValueError("amount must be greater than zero") else: self.transactions.append(Transaction(amount)) + self.availableBalance += amount def withdraw(self, amount): if (amount <= 0): raise ValueError("amount must be greater than zero") + elif (amount > self.availableBalance): + raise ValueError("amount greater than available balance") else: self.transactions.append(Transaction(-amount)) + self.availableBalance -= amount def interestEarned(self): amount = self.sumTransactions() From 7a5f6d04fb662f24c9204fc0bb4c48f54cc1afe7 Mon Sep 17 00:00:00 2001 From: Deepak Date: Wed, 18 May 2016 23:57:29 -0400 Subject: [PATCH 03/10] added unit test for Account --- tests/account_tests.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/account_tests.py diff --git a/tests/account_tests.py b/tests/account_tests.py new file mode 100644 index 0000000..04b31ce --- /dev/null +++ b/tests/account_tests.py @@ -0,0 +1,10 @@ +from nose.tools import assert_equal + +from abcbank.account import Account, CHECKING + +def test_accountBalance(): + testAccount = Account(CHECKING) + testAccount.deposit(1000) + assert_equal(testAccount.availableBalance, 1000, "Test available Balance") + testAccount.withdraw(500) + assert_equal(testAccount.availableBalance, 500, "Test available Balance after withdraw") From da7d730f6a487fbd4ec8bb45a78a7484c6b12c46 Mon Sep 17 00:00:00 2001 From: Deepak Date: Thu, 19 May 2016 01:35:56 -0400 Subject: [PATCH 04/10] Transfer Feature added --- abcbank/customer.py | 32 +++++++++++++++++++++++++------- tests/customer_tests.py | 10 ++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/abcbank/customer.py b/abcbank/customer.py index 7cfd62a..7fb562e 100644 --- a/abcbank/customer.py +++ b/abcbank/customer.py @@ -1,30 +1,48 @@ -from account import CHECKING, SAVINGS, MAXI_SAVINGS +from account import CHECKING, SAVINGS, MAXI_SAVINGS, Account +from transaction import Transaction class Customer: def __init__(self, name): self.name = name - self.accounts = [] + self.accounts = {} def openAccount(self, account): - self.accounts.append(account) + if isinstance(account, Account): + self.accounts[account.accountType] = account + elif isinstance(account, int): + self.accounts[account] = Account(account) + return self + + def transfer(self, fromAccount, toAccount, amount): + if fromAccount not in self.accounts or toAccount not in self.accounts: + return ValueError("Invalid Account") + _from = self.accounts[fromAccount] + _to = self.accounts[toAccount] + if _from.availableBalance < 0 or amount > _from.availableBalance: + return ValueError("Account does not have sufficient balance") + _from.availableBalance -= amount + _to.availableBalance += amount + _from.transactions.append(Transaction(-amount)) + _to.transactions.append(Transaction(amount)) return self def numAccs(self): return len(self.accounts) def totalInterestEarned(self): - return sum([a.interestEarned() for a in self.accounts]) + return sum([self.accounts[accountType].interestEarned() for accountType in self.accounts.keys()]) # 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 - totalAcrossAllAccounts = sum([a.sumTransactions() for a in self.accounts]) + totalAcrossAllAccounts = sum( + [self.accounts[accountType].sumTransactions() for accountType in self.accounts.keys()]) statement = "Statement for %s" % self.name - for account in self.accounts: - statement = statement + self.statementForAccount(account) + for accountType in self.accounts.keys(): + statement += self.statementForAccount(self.accounts[accountType]) statement = statement + "\n\nTotal In All Accounts " + _toDollars(totalAcrossAllAccounts) return statement diff --git a/tests/customer_tests.py b/tests/customer_tests.py index 65acfcc..9ea490e 100644 --- a/tests/customer_tests.py +++ b/tests/customer_tests.py @@ -29,6 +29,16 @@ def test_twoAccounts(): assert_equals(oscar.numAccs(), 2) +def test_transfer(): + bob = Customer("Bob").openAccount(CHECKING) + bob.openAccount(SAVINGS) + bob.accounts[CHECKING].deposit(500) + bob.transfer(CHECKING, SAVINGS, 100) + assert_equals(bob.accounts[CHECKING].availableBalance, 400) + assert_equals(bob.accounts[SAVINGS].availableBalance, 100) + bob.accounts[SAVINGS].deposit(400) + assert_equals(bob.accounts[SAVINGS].availableBalance, 500) + @nottest def test_threeAccounts(): oscar = Customer("Oscar").openAccount(Account(SAVINGS)) From bf84836ae91586b003ae7d2a26069cc26956178a Mon Sep 17 00:00:00 2001 From: Deepak Date: Thu, 19 May 2016 19:15:47 -0400 Subject: [PATCH 05/10] added DateUtils + modified MAXI-SAVING interest calculation + added unit tests --- abcbank/account.py | 59 +++++++++++++++++++++++++++++--------- abcbank/date_provider.py | 43 +++++++++++++++++++++++++-- abcbank/transaction.py | 17 +++++++++-- tests/account_tests.py | 18 ++++++++++++ tests/bank_tests.py | 4 ++- tests/dateprovider_test.py | 40 ++++++++++++++++++++++++++ tests/transaction_tests.py | 11 +++++-- 7 files changed, 170 insertions(+), 22 deletions(-) create mode 100644 tests/dateprovider_test.py diff --git a/abcbank/account.py b/abcbank/account.py index fb5ac46..1cb8c01 100644 --- a/abcbank/account.py +++ b/abcbank/account.py @@ -1,3 +1,4 @@ +from abcbank.date_provider import DateUtils from abcbank.transaction import Transaction CHECKING = 0 @@ -11,38 +12,70 @@ def __init__(self, accountType): self.transactions = [] self.availableBalance = 0 - def deposit(self, amount): - if (amount <= 0): + def deposit(self, amount, date_deposited=None): + if amount <= 0: raise ValueError("amount must be greater than zero") else: - self.transactions.append(Transaction(amount)) + if date_deposited: + try: + date = DateUtils.toDate(date_deposited) + self.transactions.append(Transaction(amount, date)) + except ValueError: + return ValueError("Incorrect date format") + else: + self.transactions.append(Transaction(amount)) self.availableBalance += amount def withdraw(self, amount): - if (amount <= 0): + if amount <= 0: raise ValueError("amount must be greater than zero") - elif (amount > self.availableBalance): + elif amount > self.availableBalance: raise ValueError("amount greater than available balance") else: self.transactions.append(Transaction(-amount)) self.availableBalance -= amount def interestEarned(self): - amount = self.sumTransactions() + amount = self.availableBalance if self.accountType == SAVINGS: - if (amount <= 1000): + if amount <= 1000: return amount * 0.001 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 + endDate = DateUtils.now() + startDate = DateUtils.add(endDate, -10) + _transactions = self.getTransaction(startDate, endDate) + withdrawn = 0 + for t in _transactions: + if t.amount < 0: + withdrawn = 1 + break + if withdrawn == 1: + return amount * (0.1 / 100.0) else: - return 70 + (amount - 2000) * 0.1 + return amount * (5 / 100.0) else: return amount * 0.001 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 getTransaction(self, startDate, endDate): + transaction_data = [] + try: + start_date = DateUtils.toDate(startDate) + end_date = DateUtils.toDate(endDate) + except ValueError: + return ValueError("Incorrect date format") + for transaction in self.transactions: + if DateUtils.isDateWithinRange(transaction.transactionDate, startDate, endDate): + transaction_data.append(transaction) + return transaction_data + + # @staticmethod + # def dailyInterest(P, r, days): + # I = P + # for x in range(days): + # I *= 1 + ((r / 100) / 365) + # return I diff --git a/abcbank/date_provider.py b/abcbank/date_provider.py index 33b64eb..10c9401 100644 --- a/abcbank/date_provider.py +++ b/abcbank/date_provider.py @@ -1,7 +1,44 @@ -from datetime import datetime +import datetime -class DateProvider: +class DateUtils: @staticmethod def now(): - return datetime.now() \ No newline at end of file + return datetime.datetime.now() + + @staticmethod + def add(date, days): + return (DateUtils.toDate(date) + datetime.timedelta(days=days)).strftime("%m/%d/%Y") + + @staticmethod + def toDate(date_str): + if isinstance(date_str,str): + return datetime.datetime.strptime(date_str, '%m/%d/%Y') + else: + return date_str + + @staticmethod + def find_no_days(date1_str, date2_str): + if isinstance(date1_str, str): + date1 = DateUtils.toDate(date1_str) + else: + date1 = date1_str + if isinstance(date2_str, str): + date2 = DateUtils.toDate(date2_str) + else: + date2 = date2_str + return (date2 - date1).days + + @staticmethod + def toString(date): + return date.strftime("%m/%d/%Y") + + @staticmethod + def isDateWithinRange(date, startDate, endDate): + if isinstance(date, str): + date = DateUtils.toDate(date) + if isinstance(startDate, str): + startDate = DateUtils.toDate(startDate) + if isinstance(endDate, str): + endDate = DateUtils.toDate(endDate) + return DateUtils.find_no_days(date, startDate) <= 0 <= DateUtils.find_no_days(date, endDate) diff --git a/abcbank/transaction.py b/abcbank/transaction.py index 8e5b5ad..9424484 100644 --- a/abcbank/transaction.py +++ b/abcbank/transaction.py @@ -1,7 +1,20 @@ from datetime import datetime +from date_provider import DateUtils class Transaction: - def __init__(self, amount): + def __init__(self, amount, date=None): self.amount = amount - self.transactionDate = datetime.now() \ No newline at end of file + if not date: + self.transactionDate = datetime.now() + else: + if isinstance(date, str): + self.transactionDate = DateUtils.toDate(date) + else: + self.transactionDate = date + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.amount == other.amount and DateUtils.toString(self.transactionDate) == DateUtils.toString( + other.transactionDate) + return False diff --git a/tests/account_tests.py b/tests/account_tests.py index 04b31ce..53a3008 100644 --- a/tests/account_tests.py +++ b/tests/account_tests.py @@ -1,6 +1,8 @@ from nose.tools import assert_equal from abcbank.account import Account, CHECKING +from abcbank.transaction import Transaction + def test_accountBalance(): testAccount = Account(CHECKING) @@ -8,3 +10,19 @@ def test_accountBalance(): assert_equal(testAccount.availableBalance, 1000, "Test available Balance") testAccount.withdraw(500) assert_equal(testAccount.availableBalance, 500, "Test available Balance after withdraw") + + +def test_checkDateFormat(): + assert_equal(Account(CHECKING).getTransaction("01-01-2016", "01-01-2016").message, "Incorrect date format") + + +def test_checkNoOfTransaction(): + test_acc = Account(CHECKING) + test_acc.deposit(500, "01/01/2016") + test_acc.deposit(500, "01/02/2016") + test_acc.deposit(500, "01/03/2016") + test_acc.deposit(500, "01/04/2016") + test_acc.deposit(500, "01/05/2016") + test_acc.deposit(500, "01/06/2016") + test_acc.deposit(500, "01/07/2016") + assert_equal(len(test_acc.getTransaction("01/02/2016", "01/04/2016")), 3) diff --git a/tests/bank_tests.py b/tests/bank_tests.py index 926ebf5..a9566c1 100644 --- a/tests/bank_tests.py +++ b/tests/bank_tests.py @@ -35,4 +35,6 @@ def test_maxi_savings_account(): checkingAccount = Account(MAXI_SAVINGS) bank.addCustomer(Customer("Bill").openAccount(checkingAccount)) checkingAccount.deposit(3000.0) - assert_equals(bank.totalInterestPaid(), 170.0) \ No newline at end of file + assert_equals(bank.totalInterestPaid(), 150.0) + checkingAccount.withdraw(1000.0) + assert_equals(bank.totalInterestPaid(), 2.0) diff --git a/tests/dateprovider_test.py b/tests/dateprovider_test.py new file mode 100644 index 0000000..ba6e9ad --- /dev/null +++ b/tests/dateprovider_test.py @@ -0,0 +1,40 @@ +from nose.tools import assert_equals + +from abcbank.date_provider import DateUtils + + +def test_findnodays(): + date1 = "01/01/2016" + date2 = "01/01/2017" + assert_equals(DateUtils.find_no_days(date1, date2), 366) + + +def test_add_date(): + date1 = "01/01/2016" + assert_equals(DateUtils.add(date1, 5), "01/06/2016") + +def test_isdateWithinRange(): + date ="01/04/2016" + startDate = "01/01/2016" + endDate = "01/06/2016" + assert_equals(DateUtils.isDateWithinRange(date,startDate,endDate),True) + + date = "01/04/2015" + startDate = "01/01/2016" + endDate = "01/06/2016" + assert_equals(DateUtils.isDateWithinRange(date, startDate, endDate), False) + + date = "01/04/2017" + startDate = "01/01/2016" + endDate = "01/06/2016" + assert_equals(DateUtils.isDateWithinRange(date, startDate, endDate), False) + + date = "01/01/2016" + startDate = "01/01/2016" + endDate = "01/06/2016" + assert_equals(DateUtils.isDateWithinRange(date, startDate, endDate), True) + + date = "01/06/2016" + startDate = "01/01/2016" + endDate = "01/06/2016" + assert_equals(DateUtils.isDateWithinRange(date, startDate, endDate), True) diff --git a/tests/transaction_tests.py b/tests/transaction_tests.py index e44b0c0..7a5c242 100644 --- a/tests/transaction_tests.py +++ b/tests/transaction_tests.py @@ -1,8 +1,13 @@ -from nose.tools import assert_is_instance - +from nose.tools import assert_is_instance, assert_equal from abcbank.transaction import Transaction def test_type(): t = Transaction(5) - assert_is_instance(t, Transaction, "correct type") \ No newline at end of file + assert_is_instance(t, Transaction, "correct type") + + +def test_TransactionEquality(): + T1 = Transaction(100, "01/01/2016") + T2 = Transaction(100, "01/01/2016") + assert_equal(T1, T2) From fd45a3582ac86bd726c1fb17d7ef0920d293f114 Mon Sep 17 00:00:00 2001 From: Deepak Date: Thu, 19 May 2016 19:20:32 -0400 Subject: [PATCH 06/10] removed unused imports --- tests/account_tests.py | 2 +- tests/dateprovider_test.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/account_tests.py b/tests/account_tests.py index 53a3008..105130a 100644 --- a/tests/account_tests.py +++ b/tests/account_tests.py @@ -1,7 +1,7 @@ from nose.tools import assert_equal from abcbank.account import Account, CHECKING -from abcbank.transaction import Transaction + def test_accountBalance(): diff --git a/tests/dateprovider_test.py b/tests/dateprovider_test.py index ba6e9ad..5e66810 100644 --- a/tests/dateprovider_test.py +++ b/tests/dateprovider_test.py @@ -13,11 +13,12 @@ def test_add_date(): date1 = "01/01/2016" assert_equals(DateUtils.add(date1, 5), "01/06/2016") + def test_isdateWithinRange(): - date ="01/04/2016" + date = "01/04/2016" startDate = "01/01/2016" endDate = "01/06/2016" - assert_equals(DateUtils.isDateWithinRange(date,startDate,endDate),True) + assert_equals(DateUtils.isDateWithinRange(date, startDate, endDate), True) date = "01/04/2015" startDate = "01/01/2016" From 1fa486756015c4e58f4c22c904b47d2a152d0534 Mon Sep 17 00:00:00 2001 From: Deepak Date: Thu, 19 May 2016 19:29:33 -0400 Subject: [PATCH 07/10] added unit test for customer --- abcbank/customer.py | 6 +++--- tests/customer_tests.py | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/abcbank/customer.py b/abcbank/customer.py index 7fb562e..945cd98 100644 --- a/abcbank/customer.py +++ b/abcbank/customer.py @@ -16,16 +16,16 @@ def openAccount(self, account): def transfer(self, fromAccount, toAccount, amount): if fromAccount not in self.accounts or toAccount not in self.accounts: - return ValueError("Invalid Account") + return "Invalid Account" _from = self.accounts[fromAccount] _to = self.accounts[toAccount] if _from.availableBalance < 0 or amount > _from.availableBalance: - return ValueError("Account does not have sufficient balance") + return "Account does not have sufficient balance" _from.availableBalance -= amount _to.availableBalance += amount _from.transactions.append(Transaction(-amount)) _to.transactions.append(Transaction(amount)) - return self + return "Transfer Succeeded" def numAccs(self): return len(self.accounts) diff --git a/tests/customer_tests.py b/tests/customer_tests.py index 9ea490e..f8cb34e 100644 --- a/tests/customer_tests.py +++ b/tests/customer_tests.py @@ -1,6 +1,6 @@ from nose.tools import assert_equals, nottest -from abcbank.account import Account, CHECKING, SAVINGS +from abcbank.account import Account, CHECKING, SAVINGS, MAXI_SAVINGS from abcbank.customer import Customer @@ -33,14 +33,21 @@ def test_transfer(): bob = Customer("Bob").openAccount(CHECKING) bob.openAccount(SAVINGS) bob.accounts[CHECKING].deposit(500) - bob.transfer(CHECKING, SAVINGS, 100) - assert_equals(bob.accounts[CHECKING].availableBalance, 400) - assert_equals(bob.accounts[SAVINGS].availableBalance, 100) + + status = bob.transfer(CHECKING, SAVINGS, 100) + assert_equals(status, "Transfer Succeeded", "Checking status of transfer") + assert_equals(bob.accounts[CHECKING].availableBalance, 400, "Checking balance after transfer") + assert_equals(bob.accounts[SAVINGS].availableBalance, 100, "Checking balance after transfer") + bob.accounts[SAVINGS].deposit(400) - assert_equals(bob.accounts[SAVINGS].availableBalance, 500) + assert_equals(bob.accounts[SAVINGS].availableBalance, 500, "Checking balance after deposit") + + status = bob.transfer(MAXI_SAVINGS, CHECKING, 100) + assert_equals(status, "Invalid Account") + @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 + assert_equals(oscar.numAccs(), 3) From ba9bedcca1fd0acb13e50c7f4b25b3fd1fb5a7ff Mon Sep 17 00:00:00 2001 From: Deepak Date: Thu, 19 May 2016 22:29:15 -0400 Subject: [PATCH 08/10] removed un-used test --- tests/customer_tests.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/customer_tests.py b/tests/customer_tests.py index f8cb34e..c16ba68 100644 --- a/tests/customer_tests.py +++ b/tests/customer_tests.py @@ -44,10 +44,3 @@ def test_transfer(): status = bob.transfer(MAXI_SAVINGS, CHECKING, 100) assert_equals(status, "Invalid Account") - - -@nottest -def test_threeAccounts(): - oscar = Customer("Oscar").openAccount(Account(SAVINGS)) - oscar.openAccount(Account(CHECKING)) - assert_equals(oscar.numAccs(), 3) From de73e74beb1887f822bae75b195e87d454a708a5 Mon Sep 17 00:00:00 2001 From: Deepak Date: Thu, 19 May 2016 23:04:13 -0400 Subject: [PATCH 09/10] added interest after x days feature --- abcbank/account.py | 36 ++++++++++++++++++++++++++++++------ tests/account_tests.py | 11 +++++++++-- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/abcbank/account.py b/abcbank/account.py index 1cb8c01..1d64c1d 100644 --- a/abcbank/account.py +++ b/abcbank/account.py @@ -58,6 +58,29 @@ def interestEarned(self): else: return amount * 0.001 + def interest_earned_after_x_days(self, days=1): + amount = self.availableBalance + if self.accountType == SAVINGS: + if amount <= 1000: + return Account.daily_interest(amount, 0.1, days) + else: + return Account.daily_interest(amount-1000, 0.2, days) + Account.daily_interest(1000, 0.1, days) + if self.accountType == MAXI_SAVINGS: + endDate = DateUtils.now() + startDate = DateUtils.add(endDate, -10) + _transactions = self.getTransaction(startDate, endDate) + withdrawn = 0 + for t in _transactions: + if t.amount < 0: + withdrawn = 1 + break + if withdrawn == 1: + return Account.daily_interest(amount, 0.1, days) + else: + return Account.daily_interest(amount, 5, days) + else: + return Account.daily_interest(amount, 0.1, days) + def sumTransactions(self, checkAllTransactions=True): return sum([t.amount for t in self.transactions]) @@ -73,9 +96,10 @@ def getTransaction(self, startDate, endDate): transaction_data.append(transaction) return transaction_data - # @staticmethod - # def dailyInterest(P, r, days): - # I = P - # for x in range(days): - # I *= 1 + ((r / 100) / 365) - # return I + @staticmethod + def daily_interest(P, r, days): + I = P + for x in range(days): + I *= 1 + ((r / 100.0) / 365.0) + return round(I,2) + diff --git a/tests/account_tests.py b/tests/account_tests.py index 105130a..eba9c0f 100644 --- a/tests/account_tests.py +++ b/tests/account_tests.py @@ -1,7 +1,6 @@ from nose.tools import assert_equal -from abcbank.account import Account, CHECKING - +from abcbank.account import Account, CHECKING, MAXI_SAVINGS def test_accountBalance(): @@ -26,3 +25,11 @@ def test_checkNoOfTransaction(): test_acc.deposit(500, "01/06/2016") test_acc.deposit(500, "01/07/2016") assert_equal(len(test_acc.getTransaction("01/02/2016", "01/04/2016")), 3) + + +def test_interest_after_x_days(): + test_acc = Account(MAXI_SAVINGS) + test_acc.deposit(3000, "01/01/2016") + assert_equal(test_acc.interest_earned_after_x_days(1), 3000.41) + assert_equal(test_acc.interest_earned_after_x_days(2), 3000.82) + assert_equal(test_acc.interest_earned_after_x_days(3), 3001.23) From d79cad4e8a0c09fb8186e59d9e69a36f7e51bcb0 Mon Sep 17 00:00:00 2001 From: Deepak Date: Fri, 20 May 2016 00:25:13 -0400 Subject: [PATCH 10/10] docstring added --- abcbank/account.py | 46 ++++++++++++++++++++++++++++++++++++++-- abcbank/bank.py | 11 ++++++++++ abcbank/customer.py | 18 ++++++++++++++++ abcbank/date_provider.py | 38 +++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/abcbank/account.py b/abcbank/account.py index 1d64c1d..fc31c37 100644 --- a/abcbank/account.py +++ b/abcbank/account.py @@ -13,6 +13,12 @@ def __init__(self, accountType): self.availableBalance = 0 def deposit(self, amount, date_deposited=None): + """ + + :param amount: amount to be deposited + :param date_deposited: optional param; date of deposit + :return: + """ if amount <= 0: raise ValueError("amount must be greater than zero") else: @@ -27,6 +33,11 @@ def deposit(self, amount, date_deposited=None): self.availableBalance += amount def withdraw(self, amount): + """ + + :param amount: amount to be withdrawn + :return: None + """ if amount <= 0: raise ValueError("amount must be greater than zero") elif amount > self.availableBalance: @@ -36,6 +47,11 @@ def withdraw(self, amount): self.availableBalance -= amount def interestEarned(self): + """ + calculate the interest annually + + :return: interest payout for the customer + """ amount = self.availableBalance if self.accountType == SAVINGS: if amount <= 1000: @@ -59,12 +75,18 @@ def interestEarned(self): return amount * 0.001 def interest_earned_after_x_days(self, days=1): + """ + Calculate the interest after x days + + :param days: + :return: return the Amount along with accrued interest + """ amount = self.availableBalance if self.accountType == SAVINGS: if amount <= 1000: return Account.daily_interest(amount, 0.1, days) else: - return Account.daily_interest(amount-1000, 0.2, days) + Account.daily_interest(1000, 0.1, days) + return Account.daily_interest(amount - 1000, 0.2, days) + Account.daily_interest(1000, 0.1, days) if self.accountType == MAXI_SAVINGS: endDate = DateUtils.now() startDate = DateUtils.add(endDate, -10) @@ -82,9 +104,21 @@ def interest_earned_after_x_days(self, days=1): return Account.daily_interest(amount, 0.1, days) def sumTransactions(self, checkAllTransactions=True): + """ + + :param checkAllTransactions: + :return: Return the sum of all transaction including debits and credits + """ return sum([t.amount for t in self.transactions]) def getTransaction(self, startDate, endDate): + """ + Get the Customer Transaction between any time frame + + :param startDate: Start Date + :param endDate: End Date + :return: List of Transaction between the start date and end date + """ transaction_data = [] try: start_date = DateUtils.toDate(startDate) @@ -98,8 +132,16 @@ def getTransaction(self, startDate, endDate): @staticmethod def daily_interest(P, r, days): + """ + Calculate the Daily/Continuous Interest + + :param P: Prinicipal Amount + :param r: Rate of Interest + :param days: No. of days upto which the interest is calculated + :return: Final amount with Interest accrued daily + """ I = P for x in range(days): I *= 1 + ((r / 100.0) / 365.0) - return round(I,2) + return round(I, 2) diff --git a/abcbank/bank.py b/abcbank/bank.py index e3f2d58..c644eda 100644 --- a/abcbank/bank.py +++ b/abcbank/bank.py @@ -3,6 +3,12 @@ def __init__(self): self.customers = [] def addCustomer(self, customer): + """ + Add a customer to the bank + + :param customer: Customer Name + :return: None + """ self.customers.append(customer) def customerSummary(self): @@ -15,6 +21,11 @@ def _format(self, number, word): return str(number) + " " + (word if (number == 1) else word + "s") def totalInterestPaid(self): + """ + Total Interest Paid for all customer for all acounts the customer possess + + :return: interest payout + """ total = 0 for c in self.customers: total += c.totalInterestEarned() diff --git a/abcbank/customer.py b/abcbank/customer.py index 945cd98..5faf69c 100644 --- a/abcbank/customer.py +++ b/abcbank/customer.py @@ -8,6 +8,12 @@ def __init__(self, name): self.accounts = {} def openAccount(self, account): + """ + Create/Open an account + + :param account: account type + :return: Customer object + """ if isinstance(account, Account): self.accounts[account.accountType] = account elif isinstance(account, int): @@ -15,6 +21,14 @@ def openAccount(self, account): return self def transfer(self, fromAccount, toAccount, amount): + """ + Transfer money between the customer accounts + + :param fromAccount: Account Type + :param toAccount: Account Type + :param amount: Amount to be transfered + :return: status of the transfer + """ if fromAccount not in self.accounts or toAccount not in self.accounts: return "Invalid Account" _from = self.accounts[fromAccount] @@ -28,6 +42,10 @@ def transfer(self, fromAccount, toAccount, amount): return "Transfer Succeeded" def numAccs(self): + """ + + :return: number of accounts the customer has opened + """ return len(self.accounts) def totalInterestEarned(self): diff --git a/abcbank/date_provider.py b/abcbank/date_provider.py index 10c9401..0b7de59 100644 --- a/abcbank/date_provider.py +++ b/abcbank/date_provider.py @@ -4,14 +4,31 @@ class DateUtils: @staticmethod def now(): + """ + + :return: Current date time + """ return datetime.datetime.now() @staticmethod def add(date, days): + """ + Add x days to the date + + :param date: date in string format + :param days: number of days to be added + :return: date in string format + """ return (DateUtils.toDate(date) + datetime.timedelta(days=days)).strftime("%m/%d/%Y") @staticmethod def toDate(date_str): + """ + Convert the date in string format to datetime format + + :param date_str: date in string format + :return: date in datetime format + """ if isinstance(date_str,str): return datetime.datetime.strptime(date_str, '%m/%d/%Y') else: @@ -19,6 +36,13 @@ def toDate(date_str): @staticmethod def find_no_days(date1_str, date2_str): + """ + Find no of days between 2 dates + + :param date1_str: date1 in string format + :param date2_str: date2 in string format + :return: no of day between 2 dates + """ if isinstance(date1_str, str): date1 = DateUtils.toDate(date1_str) else: @@ -31,10 +55,24 @@ def find_no_days(date1_str, date2_str): @staticmethod def toString(date): + """ + Return datetime object in string format + + :param date: datetime object + :return: datetime in string + """ return date.strftime("%m/%d/%Y") @staticmethod def isDateWithinRange(date, startDate, endDate): + """ + Checks if the given date is within the time frame + + :param date: + :param startDate: + :param endDate: + :return: boolean true/false + """ if isinstance(date, str): date = DateUtils.toDate(date) if isinstance(startDate, str):