Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1 refactoring #39

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ name := "abc-bank-scala"

version := "1.0"

scalaVersion := "2.11.0"
scalaVersion := "2.11.8"

libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.1.6" % "test"
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.1.6" % "test"
66 changes: 35 additions & 31 deletions src/main/scala/com/abc/Account.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,47 @@ package com.abc

import scala.collection.mutable.ListBuffer

object Account {
final val CHECKING: Int = 0
final val SAVINGS: Int = 1
final val MAXI_SAVINGS: Int = 2
//TODO add logging and monadify the code

sealed trait CurrencyTransaction {
val amount:Double = 0
}
/** Deposit given amount; it is acceptable to deposit a negative amount: this results in a withdrawal */
case class Deposit(override val amount:Double) extends CurrencyTransaction
/** Withdraw given amount; it is acceptable to withdraw a negative amount: this results in a deposit */
case class Withdraw(value:Double) extends CurrencyTransaction {
override val amount = -value
}

class Account(val accountType: Int, var transactions: ListBuffer[Transaction] = ListBuffer()) {
trait Account {
var transactions: ListBuffer[Transaction] = ListBuffer()
val accountType:Option[String] = None

def deposit(amount: Double) {
if (amount <= 0)
throw new IllegalArgumentException("amount must be greater than zero")
else
transactions += Transaction(amount)
}
def performTransaction(currencyTransaction: CurrencyTransaction):ListBuffer[Transaction] = transactions += Transaction(currencyTransaction.amount)
def interestEarned: Double
def sumTransactions: Double = transactions.map(_.amount).sum
}

def withdraw(amount: Double) {
if (amount <= 0)
throw new IllegalArgumentException("amount must be greater than zero")
else
transactions += Transaction(-amount)
}
class CheckingAccount extends Account {
override val accountType = Some("Checking Account\n")
def interestEarned: Double = sumTransactions* 0.001
}

class SavingsAccount extends Account {
override val accountType = Some("Savings Account\n")
def interestEarned: Double = {
val amount: Double = sumTransactions()
accountType match {
case Account.SAVINGS =>
if (amount <= 1000) amount * 0.001
else 1 + (amount - 1000) * 0.002
case Account.MAXI_SAVINGS =>
if (amount <= 1000) return amount * 0.02
if (amount <= 2000) return 20 + (amount - 1000) * 0.05
70 + (amount - 2000) * 0.1
case _ =>
amount * 0.001
}
val amount: Double = sumTransactions
if (amount <= 1000) amount * 0.001
else 1 + (amount - 1000) * 0.002
}
}

def sumTransactions(checkAllTransactions: Boolean = true): Double = transactions.map(_.amount).sum

class MaxiSavingsAccount extends Account {
override val accountType = Some("Maxi Savings Account\n")
def interestEarned: Double = {
val amount: Double = sumTransactions
if (amount <= 1000) return amount * 0.02
if (amount <= 2000) return 20 + (amount - 1000) * 0.05
70 + (amount - 2000) * 0.1
}
}
35 changes: 5 additions & 30 deletions src/main/scala/com/abc/Bank.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,15 @@ import scala.collection.mutable.ListBuffer
class Bank {
var customers = new ListBuffer[Customer]

def addCustomer(customer: Customer) {
customers += customer
}

def customerSummary: String = {
var summary: String = "Customer Summary"
for (customer <- customers)
summary = summary + "\n - " + customer.name + " (" + format(customer.numberOfAccounts, "account") + ")"
summary
}
def addCustomer(customer: Customer): ListBuffer[Customer] = customers += customer
def customerSummary: String = customers.map(c=>c.name + " (" + format(c.numberOfAccounts, "account") + ")").mkString("\n - ")

private def format(number: Int, word: String): String = {
private[this] def format(number: Int, word: String): String = {
number + " " + (if (number == 1) word else word + "s")
}

def totalInterestPaid: Double = {
var total: Double = 0
for (c <- customers) total += c.totalInterestEarned
return total
}

def getFirstCustomer: String = {
try {
customers = null
customers(0).name
}
catch {
case e: Exception => {
e.printStackTrace
return "Error"
}
}
}

def totalInterestPaid: Double = customers.map(_.totalInterestEarned).sum
def getFirstCustomer: Option[String] = customers.headOption.map(_.name)
}


31 changes: 7 additions & 24 deletions src/main/scala/com/abc/Customer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,36 @@ package com.abc

import scala.collection.mutable.ListBuffer

class Customer(val name: String, var accounts: ListBuffer[Account] = ListBuffer()) {

case class Customer(name: String, accounts: ListBuffer[Account] = ListBuffer()) {
def openAccount(account: Account): Customer = {
accounts += account
this
}

def numberOfAccounts: Int = accounts.size

def totalInterestEarned: Double = accounts.map(_.interestEarned).sum

/**
* This method gets a statement
*/
def getStatement: String = {
//JIRA-123 Change by Joe Bloggs 29/7/1988 start
var statement: String = null //reset statement to null here
//JIRA-123 Change by Joe Bloggs 29/7/1988 end
val totalAcrossAllAccounts = accounts.map(_.sumTransactions()).sum
statement = f"Statement for $name\n" +
val totalAcrossAllAccounts = accounts.map(_.sumTransactions).sum
f"Statement for $name\n" +
accounts.map(statementForAccount).mkString("\n", "\n\n", "\n") +
s"\nTotal In All Accounts ${toDollars(totalAcrossAllAccounts)}"
statement
}

private def statementForAccount(a: Account): String = {
val accountType = a.accountType match {
case Account.CHECKING =>
"Checking Account\n"
case Account.SAVINGS =>
"Savings Account\n"
case Account.MAXI_SAVINGS =>
"Maxi Savings Account\n"
}
private[this] def statementForAccount(a: Account): String = {
val transactionSummary = a.transactions.map(t => withdrawalOrDepositText(t) + " " + toDollars(t.amount.abs))
.mkString(" ", "\n ", "\n")
val totalSummary = s"Total ${toDollars(a.transactions.map(_.amount).sum)}"
accountType + transactionSummary + totalSummary
a.accountType.getOrElse("Unknown Account Type\n") + transactionSummary + totalSummary
}

private def withdrawalOrDepositText(t: Transaction) =
private[this] def withdrawalOrDepositText(t: Transaction) =
t.amount match {
case a if a < 0 => "withdrawal"
case a if a > 0 => "deposit"
case _ => "N/A"
}

private def toDollars(number: Double): String = f"$$$number%.2f"
private[this] def toDollars(number: Double): String = f"$$$number%.2f"
}

20 changes: 0 additions & 20 deletions src/main/scala/com/abc/DateProvider.scala

This file was deleted.

4 changes: 1 addition & 3 deletions src/main/scala/com/abc/Transaction.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
package com.abc

case class Transaction(var amount: Double) {
val transactionDate = DateProvider.getInstance.now
}
case class Transaction(amount: Double)

14 changes: 7 additions & 7 deletions src/test/scala/com/abc/BankTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,33 @@ class BankTest extends FlatSpec with Matchers {

"Bank" should "customer summary" in {
val bank: Bank = new Bank
var john: Customer = new Customer("John").openAccount(new Account(Account.CHECKING))
val john: Customer = new Customer("John").openAccount(new CheckingAccount)
bank.addCustomer(john)
bank.customerSummary should be("Customer Summary\n - John (1 account)")
}

it should "checking account" in {
val bank: Bank = new Bank
val checkingAccount: Account = new Account(Account.CHECKING)
val checkingAccount: Account = new CheckingAccount
val bill: Customer = new Customer("Bill").openAccount(checkingAccount)
bank.addCustomer(bill)
checkingAccount.deposit(100.0)
checkingAccount.performTransaction(Deposit(100.0))
bank.totalInterestPaid should be(0.1)
}

it should "savings account" in {
val bank: Bank = new Bank
val checkingAccount: Account = new Account(Account.SAVINGS)
val checkingAccount: Account = new SavingsAccount
bank.addCustomer(new Customer("Bill").openAccount(checkingAccount))
checkingAccount.deposit(1500.0)
checkingAccount.performTransaction(Deposit(1500.0))
bank.totalInterestPaid should be(2.0)
}

it should "maxi savings account" in {
val bank: Bank = new Bank
val checkingAccount: Account = new Account(Account.MAXI_SAVINGS)
val checkingAccount: Account = new MaxiSavingsAccount
bank.addCustomer(new Customer("Bill").openAccount(checkingAccount))
checkingAccount.deposit(3000.0)
checkingAccount.performTransaction(Deposit(3000.0))
bank.totalInterestPaid should be(170.0)
}

Expand Down
32 changes: 22 additions & 10 deletions src/test/scala/com/abc/CustomerTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,44 @@ import org.scalatest.{Matchers, FlatSpec}

class CustomerTest extends FlatSpec with Matchers {
"Customer" should "statement" in {
val checkingAccount: Account = new Account(Account.CHECKING)
val savingsAccount: Account = new Account(Account.SAVINGS)
val checkingAccount: Account = new CheckingAccount
val savingsAccount: Account = new SavingsAccount
val henry: Customer = new Customer("Henry").openAccount(checkingAccount).openAccount(savingsAccount)
checkingAccount.deposit(100.0)
savingsAccount.deposit(4000.0)
savingsAccount.withdraw(200.0)
checkingAccount.performTransaction(Deposit(100.0))
savingsAccount.performTransaction(Deposit(4000.0))
savingsAccount.performTransaction(Withdraw(200.0))
henry.getStatement should be("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" +
"\nTotal In All Accounts $3900.00")
}

it should "testOneAccount" in {
val oscar: Customer = new Customer("Oscar").openAccount(new Account(Account.SAVINGS))
val oscar: Customer = new Customer("Oscar").openAccount(new SavingsAccount)
oscar.numberOfAccounts should be(1)
}

it should "testTwoAccount" in {
val oscar: Customer = new Customer("Oscar").openAccount(new Account(Account.SAVINGS))
oscar.openAccount(new Account(Account.CHECKING))
val oscar: Customer = new Customer("Oscar").openAccount(new SavingsAccount).openAccount(new CheckingAccount)
oscar.numberOfAccounts should be(2)
}

ignore should "testThreeAcounts" in {
val oscar: Customer = new Customer("Oscar").openAccount(new Account(Account.SAVINGS))
oscar.openAccount(new Account(Account.CHECKING))
val oscar: Customer = new Customer("Oscar").openAccount(new SavingsAccount).openAccount(new CheckingAccount).openAccount(new CheckingAccount)
oscar.numberOfAccounts should be(3)
}

"Customer" should "be able to deposit a negative amount" in {
val checkingAccount: Account = new CheckingAccount
val savingsAccount: Account = new SavingsAccount
val henry: Customer = new Customer("Henry").openAccount(checkingAccount).openAccount(savingsAccount)
checkingAccount.performTransaction(Deposit(-100.0))
savingsAccount.performTransaction(Deposit(4000.0))
savingsAccount.performTransaction(Withdraw(200.0))
henry.getStatement should be("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" +
"\nTotal In All Accounts $3900.00")
}

}
4 changes: 0 additions & 4 deletions src/test/scala/com/abc/TransactionTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,4 @@ package com.abc
import org.scalatest.{FlatSpec, Matchers}

class TransactionTest extends FlatSpec with Matchers {
"Transaction" should "type" in {
val t = new Transaction(5)
t.isInstanceOf[Transaction] should be(true)
}
}