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
133 changes: 116 additions & 17 deletions abcbank/account.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,142 @@
from datetime import datetime

from abcbank.transaction import Transaction


CHECKING = 0
SAVINGS = 1
MAXI_SAVINGS = 2
DAYS_IN_YEAR = 365


class Account:
def __init__(self, accountType):
self.accountType = accountType
def __init__(self):
self.transactions = []

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

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

def _calculateInterest(self, checkAllTransactionsUpInToIndex=None, daysAccrued=365):
fractionOfYearAccrued = daysAccrued/DAYS_IN_YEAR
amount = self.sumTransactions(checkAllTransactionsUpInToIndex)
interestAmount = 0.01


def interestEarned(self):
amount = self.sumTransactions()
if self.accountType == SAVINGS:
if (amount <= 1000):
return amount * 0.001
interestAmount = 0.001
return amount * interestAmount * fractionOfYearAccrued
else:
return 1 + (amount - 1000) * 0.002
if self.accountType == MAXI_SAVINGS:
interestAmount = 0.002
return 1 + (amount - 1000) * interestAmount * fractionOfYearAccrued
elif self.accountType == MAXI_SAVINGS:
if (amount <= 1000):
return amount * 0.02
currTime = datetime.now()
interestAmount = 0.02
if abs(self.transactions[-1].transactionDate - currTime <= datetime.timedelta(days=10)):
interestAmount = 0.01
return amount * interestAmount * fractionOfYearAccrued
elif (amount <= 2000):
return 20 + (amount - 1000) * 0.05
interestAmount = 0.05
return 20 + (amount - 1000) * interestAmount * fractionOfYearAccrued
else:
return 70 + (amount - 2000) * 0.1
interestAmount = 0.1
return 70 + (amount - 2000) * interestAmount * fractionOfYearAccrued
else:
return amount * 0.001
return amount * interestAmount * fractionOfYearAccrued

def sumTransactions(self, checkAllTransactionsUpToIndex=None):
endIndex = checkAllTransactionsUpToIndex or len(self.transactions)
return sum([t.amount for t in self.transactions[0:endIndex]])

def interestEarned(self):
"""Calculate Accrued Interest (daily)"""

transactions = self.transactions
totalInterest = 0

for ind in range(1, len(transactions)):
prevTransaction = transactions[ind-1]
currTransaction = transactions[ind]
timeLagDays = (currTransaction.transactionDate - prevTransaction.transactionDate).days
totalInterest += self._calculateInterest(checkAllTransactionsUpInToIndex=ind, daysAccrued=timeLagDays)
totalInterest += self._calculateInterest(
daysAccrued=(datetime.now() - self.transactions[-1].transactionDate).days)
return totalInterest

@property
def accountDescription(self):
return 'Account'

class CheckingAccount(Account):
accountType = CHECKING

def _calculateInterest(self, checkAllTransactionsUpInToIndex=None, daysAccrued=365):
fractionOfYearAccrued = daysAccrued / DAYS_IN_YEAR
amount = self.sumTransactions(checkAllTransactionsUpInToIndex)
return amount * 0.001 * fractionOfYearAccrued

@property
def accountDescription(self):
return "Checking Account"
class SavingsAccount(Account):
accountType = SAVINGS

def _calculateInterest(self, checkAllTransactionsUpInToIndex=None, daysAccrued=365):
fractionOfYearAccrued = daysAccrued / DAYS_IN_YEAR
amount = self.sumTransactions(checkAllTransactionsUpInToIndex)

if (amount <= 1000):
interestAmount = 0.001
return amount * interestAmount * fractionOfYearAccrued
else:
interestAmount = 0.002
return 1 + (amount - 1000) * interestAmount * fractionOfYearAccrued

@property
def accountDescription(self):
return "Savings Account"


class MaxiSavings(Account):
accountType = MAXI_SAVINGS

def _calculateInterest(self, checkAllTransactionsUpInToIndex=None, daysAccrued=365):
fractionOfYearAccrued = daysAccrued / DAYS_IN_YEAR
amount = self.sumTransactions(checkAllTransactionsUpInToIndex)

if (amount <= 1000):
currTime = datetime.now()
interestAmount = 0.02
if abs(self.transactions[-1].transactionDate - currTime <= datetime.timedelta(days=10)):
interestAmount = 0.01
return amount * interestAmount * fractionOfYearAccrued
elif (amount <= 2000):
interestAmount = 0.05
return 20 + (amount - 1000) * interestAmount * fractionOfYearAccrued
else:
interestAmount = 0.1
return 70 + (amount - 2000) * interestAmount * fractionOfYearAccrued

@property
def accountDescription(self):
return "Maxi Savings Account"


def sumTransactions(self, checkAllTransactions=True):
return sum([t.amount for t in self.transactions])
def createBankAccount(accountType):
if accountType == CHECKING:
return CheckingAccount()
elif accountType == SAVINGS:
return SavingsAccount()
elif accountType == MAXI_SAVINGS:
return MaxiSavings()
raise ValueError("Account Type: {AccountType} is not supported".format(accountType))
19 changes: 7 additions & 12 deletions abcbank/bank.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,17 @@ 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
summary = ''.join(["\n - {} ({})".format(c.name, self._format(c.numAccs(), "account"))
for c in self.customers])
return "Customer Summary{summary}" .format(summary=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 total
39 changes: 13 additions & 26 deletions abcbank/customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,26 @@ def numAccs(self):
def totalInterestEarned(self):
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 returns a statement"""
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)
return statement
statements = ''.join([self.statementForAccount(account) for account in self.accounts])
totalValue = _toDollars(totalAcrossAllAccounts)

return "Statement for {name}{statements}\n\nTotal In All Accounts {totalValue}".format(name=self.name,
statements=statements,
totalValue=_toDollars(totalAcrossAllAccounts))

def statementForAccount(self, account):
accountType = "\n\n\n"
if account.accountType == CHECKING:
accountType = "\n\nChecking Account\n"
if account.accountType == SAVINGS:
accountType = "\n\nSavings Account\n"
if account.accountType == MAXI_SAVINGS:
accountType = "\n\nMaxi Savings Account\n"
transactionSummary = [self.withdrawalOrDepositText(t) + " " + _toDollars(abs(t.amount))
accountType = "\n\n{accountDescription}\n".format(accountDescription=account.accountDescription)
transactionSummary = [t.transactionDescription() + " " + _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

def withdrawalOrDepositText(self, transaction):
if transaction.amount < 0:
return "withdrawal"
elif transaction.amount > 0:
return "deposit"
else:
return "N/A"

return "{accountType}{transactionSummary}{totalSummary}".format(accountType=accountType,
transactionSummary=transactionSummary,
totalSummary=totalSummary)


def _toDollars(number):
Expand Down
7 changes: 0 additions & 7 deletions abcbank/date_provider.py

This file was deleted.

9 changes: 7 additions & 2 deletions abcbank/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@


class Transaction:
def __init__(self, amount):
def __init__(self, amount, transactionDate=None):
self.amount = amount
self.transactionDate = datetime.now()
self.transactionDate = transactionDate or datetime.now()

def transactionDescription(self):
if self.amount < 0:
return "withdrawal"
return "deposit"
37 changes: 25 additions & 12 deletions tests/bank_tests.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,51 @@
from nose.tools import assert_equals
import datetime

from account import Account, CHECKING, MAXI_SAVINGS, SAVINGS
from nose.tools import assert_equals, assert_almost_equals

from account import Account, CHECKING, MAXI_SAVINGS, SAVINGS, createBankAccount
from bank import Bank
from customer import Customer

ONE_YEAR_AGO = datetime.datetime.today() - datetime.timedelta(days=365)


def test_customer_summary():
bank = Bank()
john = Customer("John").openAccount(Account(CHECKING))
john = Customer("John").openAccount(createBankAccount(CHECKING))
bank.addCustomer(john)
assert_equals(bank.customerSummary(),
"Customer Summary\n - John (1 account)")


def test_checking_account():
bank = Bank()
checkingAccount = Account(CHECKING)
checkingAccount = createBankAccount(CHECKING)
bill = Customer("Bill").openAccount(checkingAccount)
bank.addCustomer(bill)
checkingAccount.deposit(100.0)
checkingAccount.deposit(100.0, ONE_YEAR_AGO)
assert_equals(bank.totalInterestPaid(), 0.1)


def test_savings_account():
def test_savings_account(self):
bank = Bank()
checkingAccount = Account(SAVINGS)
checkingAccount = createBankAccount(SAVINGS)
bank.addCustomer(Customer("Bill").openAccount(checkingAccount))
checkingAccount.deposit(1500.0)
checkingAccount.deposit(1500.0, ONE_YEAR_AGO)
assert_equals(bank.totalInterestPaid(), 2.0)


def test_maxi_savings_account():
def test_daily_accrued_interest(self):
bank = Bank()
checkingAccount = Account(MAXI_SAVINGS)
checkingAccount = createBankAccount(CHECKING)
bank.addCustomer(Customer("Bill").openAccount(checkingAccount))
checkingAccount.deposit(3000.0)
assert_equals(bank.totalInterestPaid(), 170.0)

two_years_ago = datetime.datetime.today() - datetime.timedelta(days=730)
checkingAccount.deposit(1000.0, transactionDate=two_years_ago)
assert_equals(checkingAccount.interestEarned(), 2.0)

checkingAccount.deposit(1000.0, transactionDate=ONE_YEAR_AGO)
assert_almost_equals(checkingAccount.interestEarned(), 3.0, places=2)

half_year_ago = datetime.datetime.today() - datetime.timedelta(days=182)
checkingAccount.deposit(1000.0, transactionDate=half_year_ago)
assert_almost_equals(checkingAccount.interestEarned(), 3.5, places=2)
16 changes: 8 additions & 8 deletions tests/customer_tests.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from nose.tools import assert_equals, nottest

from account import Account, CHECKING, SAVINGS
from account import Account, CHECKING, SAVINGS, createBankAccount
from customer import Customer


def test_statement():
checkingAccount = Account(CHECKING)
savingsAccount = Account(SAVINGS)
checkingAccount = createBankAccount(CHECKING)
savingsAccount = createBankAccount(SAVINGS)
henry = Customer("Henry").openAccount(checkingAccount).openAccount(savingsAccount)
checkingAccount.deposit(100.0)
savingsAccount.deposit(4000.0)
Expand All @@ -19,18 +19,18 @@ def test_statement():


def test_oneAccount():
oscar = Customer("Oscar").openAccount(Account(SAVINGS))
oscar = Customer("Oscar").openAccount(createBankAccount(SAVINGS))
assert_equals(oscar.numAccs(), 1)


def test_twoAccounts():
oscar = Customer("Oscar").openAccount(Account(SAVINGS))
oscar.openAccount(Account(CHECKING))
oscar = Customer("Oscar").openAccount(createBankAccount(SAVINGS))
oscar.openAccount(createBankAccount(CHECKING))
assert_equals(oscar.numAccs(), 2)


@nottest
def test_threeAccounts():
oscar = Customer("Oscar").openAccount(Account(SAVINGS))
oscar.openAccount(Account(CHECKING))
oscar = Customer("Oscar").openAccount(createBankAccount(SAVINGS))
oscar.openAccount(createBankAccount(CHECKING))
assert_equals(oscar.numAccs(), 3)
12 changes: 10 additions & 2 deletions tests/transaction_tests.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
from nose.tools import assert_is_instance
from nose.tools import assert_is_instance, assert_equals

from transaction import Transaction


def test_type():
t = Transaction(5)
assert_is_instance(t, Transaction, "correct type")
assert_is_instance(t, Transaction, "correct type")


def test_description():
t = Transaction(-4)
assert_equals(t.transactionDescription(), "withdrawal")

t = Transaction(5)
assert_equals(t.transactionDescription(), "deposit")