Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added __init__.py
Empty file.
68 changes: 53 additions & 15 deletions abcbank/account.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,81 @@
from abcbank.transaction import Transaction
from datetime import datetime

CHECKING = 0
SAVINGS = 1
MAXI_SAVINGS = 2


class Account:

def __init__(self, accountType):
self.accountType = accountType
self.transactions = []
self.amount = 0.

def deposit(self, amount):
def deposit(self, amount, t=None):
t = datetime.now() if t is None else t
if (amount <= 0):
raise ValueError("amount must be greater than zero")
else:
self.transactions.append(Transaction(amount))
self.transactions.append(Transaction(amount, t))
self.amount += amount

def withdraw(self, amount):
def withdraw(self, amount, t=None):
t = datetime.now() if t is None else t
if (amount <= 0):
raise ValueError("amount must be greater than zero")
else:
self.transactions.append(Transaction(-amount))
self.transactions.append(Transaction(-amount, t))
self.amount -= amount

def interestEarned(self):
amount = self.sumTransactions()
if len(self.transactions) == 0:
return 0.
if len(self.transactions) == 1 and not self.transactions[0].withdraw:
t = self.transactions[0]
return self.interest(t.amount, t.age)
interest = 0.
last_amount = 0.
sorted_transactions = sorted(self.transactions,
key = lambda x: x.transactionDate)
for i, t in enumerate(sorted_transactions):
last_amount += t.amount
if i == 0:
continue
wd = self.withdrawalsInLastNDays(sorted_transactions[:i+1])
days_since_last_transaction = sorted_transactions[i-1].age - t.age
interest += self.interest(last_amount - t.amount,
days_since_last_transaction, wd)
wd = self.withdrawalsInLastNDays(sorted_transactions, current=True)
interest += self.interest(last_amount, t.age, wd)
return interest

def interest(self, amount, days, withdrawals=False):
if self.accountType == SAVINGS:
if (amount <= 1000):
return amount * 0.001
result = 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
result = 1 + (amount - 1000) * 0.002
elif self.accountType == MAXI_SAVINGS:
if withdrawals:
result = amount * 0.001
else:
return 70 + (amount - 2000) * 0.1
result = amount * 0.05
else:
return amount * 0.001
result = amount * 0.001
return result * float(days)/365

def withdrawalsInLastNDays(self, transactions, N=10, current=False):
last = 0 if current else transactions[-1].age
for i, t in enumerate(reversed(transactions)):
if not current and i == 0:
continue
if t.age - last > N:
return False
elif t.withdraw:
return True
return False

def sumTransactions(self, checkAllTransactions=True):
return sum([t.amount for t in self.transactions])
return sum([t.amount for t in self.transactions])
10 changes: 8 additions & 2 deletions abcbank/bank.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
class Bank:

def __init__(self):
self.customers = []

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") + ")"
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"
return "Error"
27 changes: 23 additions & 4 deletions abcbank/customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


class Customer:

def __init__(self, name):
self.name = name
self.accounts = []
Expand All @@ -21,11 +22,13 @@ 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([a.sumTransactions()
for a in self.accounts])
statement = "Statement for %s" % self.name
for account in self.accounts:
statement = statement + self.statementForAccount(account)
statement = statement + "\n\nTotal In All Accounts " + _toDollars(totalAcrossAllAccounts)
statement = statement + "\n\nTotal In All Accounts " +\
_toDollars(totalAcrossAllAccounts)
return statement

def statementForAccount(self, account):
Expand All @@ -36,10 +39,12 @@ def statementForAccount(self, account):
accountType = "\n\nSavings Account\n"
if account.accountType == MAXI_SAVINGS:
accountType = "\n\nMaxi Savings Account\n"
transactionSummary = [self.withdrawalOrDepositText(t) + " " + _toDollars(abs(t.amount))
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]))
totalSummary = "Total " + _toDollars(sum([t.amount for t in
account.transactions]))
return accountType + transactionSummary + totalSummary

def withdrawalOrDepositText(self, transaction):
Expand All @@ -50,6 +55,20 @@ def withdrawalOrDepositText(self, transaction):
else:
return "N/A"

def transfer(self, from_account, to_account, amount):
if amount <= 0:
raise ValueError('Incorrect amount, should be more than 0')
if from_account.amount < amount:
raise ValueError('Incorrect amount, should be more than '
'source account amount')
from_account.withdraw(amount)
try:
to_account.deposit(amount)
except:
from_account.deposit(amount)
raise
return True


def _toDollars(number):
return "${:1.2f}".format(number)
3 changes: 2 additions & 1 deletion abcbank/date_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


class DateProvider:

@staticmethod
def now():
return datetime.now()
return datetime.now()
11 changes: 9 additions & 2 deletions abcbank/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@


class Transaction:
def __init__(self, amount):

def __init__(self, amount, transaction_time=None):
self.amount = amount
self.transactionDate = datetime.now()
self.transactionDate = datetime.now() if transaction_time is None\
else transaction_time
self.withdraw = True if amount < 0 else False

@property
def age(self):
return (datetime.now() - self.transactionDate).days
23 changes: 23 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from tests import bank_tests, customer_tests, transaction_tests


def run():
print 'Running bank tests...'
b_tests = [getattr(bank_tests, obj) for obj in dir(bank_tests)
if 'test_' in obj]
for func in b_tests:
func()
print 'Running customer tests...'
c_tests = [getattr(customer_tests, obj) for obj in dir(customer_tests)
if 'test_' in obj]
for func in c_tests:
func()
print 'Running transactions tests...'
t_tests = [getattr(transaction_tests, obj)
for obj in dir(transaction_tests) if 'test_' in obj]
for func in t_tests:
func()
print 'Done'

if __name__ == '__main__':
run()
42 changes: 34 additions & 8 deletions tests/bank_tests.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from nose.tools import assert_equals
from nose.tools import assert_equals, assert_almost_equals
import datetime

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():
Expand All @@ -18,21 +19,46 @@ def test_checking_account():
checkingAccount = Account(CHECKING)
bill = Customer("Bill").openAccount(checkingAccount)
bank.addCustomer(bill)
checkingAccount.deposit(100.0)
year_behind = datetime.datetime.now() - datetime.timedelta(365)
checkingAccount.deposit(100.0, year_behind)
assert_equals(bank.totalInterestPaid(), 0.1)


def test_savings_account():
bank = Bank()
checkingAccount = Account(SAVINGS)
bank.addCustomer(Customer("Bill").openAccount(checkingAccount))
checkingAccount.deposit(1500.0)
year_behind = datetime.datetime.now() - datetime.timedelta(365)
checkingAccount.deposit(1500.0, year_behind)
assert_equals(bank.totalInterestPaid(), 2.0)


def test_maxi_savings_account():
bank = Bank()
checkingAccount = Account(MAXI_SAVINGS)
bank.addCustomer(Customer("Bill").openAccount(checkingAccount))
checkingAccount.deposit(3000.0)
assert_equals(bank.totalInterestPaid(), 170.0)
year_behind = datetime.datetime.now() - datetime.timedelta(365)
checkingAccount.deposit(3000.0, year_behind)
assert_equals(bank.totalInterestPaid(), 150.0)


def test_maxi_savings_account_without_withdrawals():
bank = Bank()
checkingAccount = Account(MAXI_SAVINGS)
bank.addCustomer(Customer("Bill").openAccount(checkingAccount))
year_behind = datetime.datetime.now() - datetime.timedelta(365)
eleven_days_behind = datetime.datetime.now() - datetime.timedelta(11)
checkingAccount.deposit(3000.0, year_behind)
checkingAccount.withdraw(1000.0, eleven_days_behind)
assert_almost_equals(bank.totalInterestPaid(), 148.49, places=2)


def test_maxi_savings_account_with_withdrawals():
bank = Bank()
checkingAccount = Account(MAXI_SAVINGS)
bank.addCustomer(Customer("Bill").openAccount(checkingAccount))
year_behind = datetime.datetime.now() - datetime.timedelta(365)
five_days_behind = datetime.datetime.now() - datetime.timedelta(5)
checkingAccount.deposit(3000.0, year_behind)
checkingAccount.withdraw(1000.0, five_days_behind)
assert_almost_equals(bank.totalInterestPaid(), 147.97, places=2)
64 changes: 57 additions & 7 deletions tests/customer_tests.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
from nose.tools import assert_equals, nottest
from nose.tools import assert_equals, assert_almost_equals
from datetime import datetime

from account import Account, CHECKING, SAVINGS
from customer import Customer
from abcbank.account import Account, CHECKING, SAVINGS, MAXI_SAVINGS
from abcbank.customer import Customer


def test_statement():
checkingAccount = Account(CHECKING)
savingsAccount = Account(SAVINGS)
henry = Customer("Henry").openAccount(checkingAccount).openAccount(savingsAccount)
henry = Customer("Henry").openAccount(checkingAccount).\
openAccount(savingsAccount)
checkingAccount.deposit(100.0)
savingsAccount.deposit(4000.0)
savingsAccount.withdraw(200.0)
assert_equals(henry.getStatement(),
"Statement for Henry" +
"\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\nSavings Account\n deposit $4000.00\n "
"withdrawal $200.00\nTotal $3800.00" +
"\n\nTotal In All Accounts $3900.00")


Expand All @@ -29,8 +32,55 @@ def test_twoAccounts():
assert_equals(oscar.numAccs(), 2)


@nottest
def test_threeAccounts():
oscar = Customer("Oscar").openAccount(Account(SAVINGS))
oscar.openAccount(Account(CHECKING))
assert_equals(oscar.numAccs(), 3)
oscar.openAccount(Account(MAXI_SAVINGS))
assert_equals(oscar.numAccs(), 3)


def test_withdrawals():
checkingAccount = Account(CHECKING)
oscar = Customer("Oscar").openAccount(checkingAccount)
checkingAccount.deposit(1000.0, datetime(2016, 4, 12))
checkingAccount.deposit(1000.0, datetime(2016, 4, 15))
checkingAccount.deposit(1000.0, datetime(2016, 4, 17))
assert_almost_equals(oscar.totalInterestEarned(), 0.17, places=2)
checkingAccount.withdraw(1000.0, datetime(2016, 4, 19))
assert_almost_equals(oscar.totalInterestEarned(), 0.12, places=2)


def test_transferAmountBelowZero():
checkingAccount = Account(CHECKING)
savingsAccount = Account(SAVINGS)
oscar = Customer("Oscar").openAccount(checkingAccount)
oscar.openAccount(savingsAccount)
try:
oscar.transfer(checkingAccount, savingsAccount, -1)
except ValueError as e:
result = str(e)
assert_equals(result, 'Incorrect amount, should be more than 0')


def test_transferNotEnoughFunds():
checkingAccount = Account(CHECKING)
savingsAccount = Account(SAVINGS)
oscar = Customer("Oscar").openAccount(checkingAccount)
oscar.openAccount(savingsAccount)
try:
oscar.transfer(savingsAccount, savingsAccount, 10)
except ValueError as e:
result = str(e)
assert_equals(result, 'Incorrect amount, should be more than '
'source account amount')


def test_transferAmount():
checkingAccount = Account(CHECKING)
savingsAccount = Account(SAVINGS)
oscar = Customer("Oscar").openAccount(checkingAccount)
oscar.openAccount(savingsAccount)
checkingAccount.deposit(100.0)
transfered = oscar.transfer(checkingAccount, savingsAccount, 10)
assert_equals(transfered, True)
assert_equals(savingsAccount.amount, 10.)
Loading