diff --git a/class-diagram.png b/class-diagram.png new file mode 100644 index 000000000..9fd6af458 Binary files /dev/null and b/class-diagram.png differ diff --git a/src/main/java/com/booleanuk/core/Account.java b/src/main/java/com/booleanuk/core/Account.java new file mode 100644 index 000000000..7a90a3c36 --- /dev/null +++ b/src/main/java/com/booleanuk/core/Account.java @@ -0,0 +1,73 @@ +package com.booleanuk.core; + +import java.util.ArrayList; +import java.util.List; + +public abstract class Account { + private float balance; + private ArrayList transactions = new ArrayList<>(); + + Transaction deposit(float amount) { + // amount must be greater than 0 + if (amount <= 0) { + return null; + } + + balance += amount; + Transaction transaction = new Transaction(amount, balance, true); + transactions.add(transaction); + + return transaction; + } + + Transaction withdraw(float amount) { + // amount must be greater than 0 and less than balance + if (amount <= 0 || amount > balance) { + return null; + } + + balance -= amount; + Transaction transaction = new Transaction(amount, balance, false); + transactions.add(transaction); + + return transaction; + } + + float getBalance() { + return balance; + } + + ArrayList getTransactions() { + return transactions; + } + + String statement() { + StringBuilder sb = new StringBuilder(); + + int cellWidth = 30; + // format String + String format = "| %-" + cellWidth + "s | %-" + cellWidth + "s | %-" + cellWidth + "s | %-" + cellWidth + + "s |%n"; + // add headers + sb.append(String.format(format, "Date", "Credit", "Debit", "Balance")); + + List descending = transactions.reversed(); + + for (Transaction t : descending) { + String time = t.getTime().toString(); + String amount = String.format("%.2f", t.getAmount()); + String balanceAfter = String.format("%.2f", t.getBalanceAfter()); + + // if deposit + if (t.getIsDeposit()) { + sb.append(String.format(format, time, amount, "", balanceAfter)); + } + // if withdraw + else { + sb.append(String.format(format, time, "", amount, balanceAfter)); + } + } + + return sb.toString(); + } +} diff --git a/src/main/java/com/booleanuk/core/CurrentAccount.java b/src/main/java/com/booleanuk/core/CurrentAccount.java new file mode 100644 index 000000000..727a0f600 --- /dev/null +++ b/src/main/java/com/booleanuk/core/CurrentAccount.java @@ -0,0 +1,4 @@ +package com.booleanuk.core; + +public class CurrentAccount extends Account { +} diff --git a/src/main/java/com/booleanuk/core/SavingsAccount.java b/src/main/java/com/booleanuk/core/SavingsAccount.java new file mode 100644 index 000000000..b9efb328e --- /dev/null +++ b/src/main/java/com/booleanuk/core/SavingsAccount.java @@ -0,0 +1,5 @@ +package com.booleanuk.core; + +public class SavingsAccount extends Account { + +} diff --git a/src/main/java/com/booleanuk/core/Transaction.java b/src/main/java/com/booleanuk/core/Transaction.java new file mode 100644 index 000000000..32dc3dac1 --- /dev/null +++ b/src/main/java/com/booleanuk/core/Transaction.java @@ -0,0 +1,33 @@ +package com.booleanuk.core; + +import java.time.LocalDateTime; + +public class Transaction { + private LocalDateTime time; + private float amount; + private float balanceAfter; + private boolean isDeposit; + + public Transaction(float amount, float balanceAfter, boolean isDeposit) { + this.time = LocalDateTime.now(); + this.amount = amount; + this.balanceAfter = balanceAfter; + this.isDeposit = isDeposit; + } + + LocalDateTime getTime() { + return time; + } + + float getAmount() { + return amount; + } + + float getBalanceAfter() { + return balanceAfter; + } + + boolean getIsDeposit() { + return isDeposit; + } +} diff --git a/src/main/java/com/booleanuk/extension/Account.java b/src/main/java/com/booleanuk/extension/Account.java new file mode 100644 index 000000000..6f49ae27d --- /dev/null +++ b/src/main/java/com/booleanuk/extension/Account.java @@ -0,0 +1,87 @@ +package com.booleanuk.extension; + +import java.util.ArrayList; +import java.util.List; + +public abstract class Account { + private ArrayList transactions = new ArrayList<>(); + private long accountNr; + + public Account(long accountNr) { + this.accountNr = accountNr; + } + + Transaction deposit(float amount) { + // amount must be greater than 0 + if (amount <= 0) { + return null; + } + + Transaction transaction = new Transaction(amount, getBalance() + amount, true); + transactions.add(transaction); + + return transaction; + } + + Transaction withdraw(float amount) { + // amount must be greater than 0 and less than getBalance() + if (amount <= 0 || amount > getBalance()) { + return null; + } + + Transaction transaction = new Transaction(amount, getBalance() - amount, false); + transactions.add(transaction); + + return transaction; + } + + float getBalance() { + float balance = 0f; + for (Transaction t : transactions) { + if (t.getIsDeposit()) { + balance += t.getAmount(); + } else { + balance -= t.getAmount(); + } + } + return balance; + } + + ArrayList getTransactions() { + return transactions; + } + + String statement() { + StringBuilder sb = new StringBuilder(); + + int cellWidth = 30; + // format String + String format = "| %-" + cellWidth + "s | %-" + cellWidth + "s | %-" + cellWidth + "s | %-" + cellWidth + + "s |%n"; + // add headers + sb.append(String.format(format, "Date", "Credit", "Debit", "Balance")); + + List descending = transactions.reversed(); + + for (Transaction t : descending) { + String time = t.getTime().toString(); + String amount = String.format("%.2f", t.getAmount()); + String balanceAfter = String.format("%.2f", t.getBalanceAfter()); + + // if deposit + if (t.getIsDeposit()) { + sb.append(String.format(format, time, amount, "", balanceAfter)); + } + // if withdraw + else { + sb.append(String.format(format, time, "", amount, balanceAfter)); + } + } + + return sb.toString(); + } + + long getAccountNr() { + return accountNr; + } +} diff --git a/src/main/java/com/booleanuk/extension/Bank.java b/src/main/java/com/booleanuk/extension/Bank.java new file mode 100644 index 000000000..630635bb4 --- /dev/null +++ b/src/main/java/com/booleanuk/extension/Bank.java @@ -0,0 +1,20 @@ +package com.booleanuk.extension; + +import java.util.HashMap; + +public class Bank { + private HashMap branches = new HashMap<>(); + private int nextBranchId = 1000; + + Branch newBranch() { + Branch branch = new Branch(nextBranchId); + branches.put(nextBranchId, branch); + nextBranchId++; + + return branch; + } + + HashMap getBranches() { + return branches; + } +} diff --git a/src/main/java/com/booleanuk/extension/Branch.java b/src/main/java/com/booleanuk/extension/Branch.java new file mode 100644 index 000000000..7c90d9161 --- /dev/null +++ b/src/main/java/com/booleanuk/extension/Branch.java @@ -0,0 +1,37 @@ +package com.booleanuk.extension; + +import java.util.HashMap; + +public class Branch { + private int nextAccountId = 10000000; + private HashMap accounts = new HashMap<>(); + private int branchId; + + public Branch(int branchId) { + this.branchId = branchId; + } + + int getId() { + return branchId; + } + + HashMap getAccounts() { + return accounts; + } + + CurrentAccount newCurrentAccount() { + long accountNr = Long.parseLong(String.valueOf(branchId) + String.valueOf(nextAccountId)); + nextAccountId++; + CurrentAccount acc = new CurrentAccount(accountNr); + accounts.put(accountNr, acc); + return acc; + } + + SavingsAccount newSavingsAccount() { + long accountNr = Long.parseLong(String.valueOf(branchId) + String.valueOf(nextAccountId)); + nextAccountId++; + SavingsAccount acc = new SavingsAccount(accountNr); + accounts.put(accountNr, acc); + return acc; + } +} diff --git a/src/main/java/com/booleanuk/extension/CurrentAccount.java b/src/main/java/com/booleanuk/extension/CurrentAccount.java new file mode 100644 index 000000000..c6fc00ebb --- /dev/null +++ b/src/main/java/com/booleanuk/extension/CurrentAccount.java @@ -0,0 +1,7 @@ +package com.booleanuk.extension; + +public class CurrentAccount extends Account { + public CurrentAccount(long accountNr) { + super(accountNr); + } +} diff --git a/src/main/java/com/booleanuk/extension/SavingsAccount.java b/src/main/java/com/booleanuk/extension/SavingsAccount.java new file mode 100644 index 000000000..8927edae9 --- /dev/null +++ b/src/main/java/com/booleanuk/extension/SavingsAccount.java @@ -0,0 +1,7 @@ +package com.booleanuk.extension; + +public class SavingsAccount extends Account { + public SavingsAccount(long accountNr) { + super(accountNr); + } +} diff --git a/src/main/java/com/booleanuk/extension/Transaction.java b/src/main/java/com/booleanuk/extension/Transaction.java new file mode 100644 index 000000000..9489ae306 --- /dev/null +++ b/src/main/java/com/booleanuk/extension/Transaction.java @@ -0,0 +1,33 @@ +package com.booleanuk.extension; + +import java.time.LocalDateTime; + +public class Transaction { + private LocalDateTime time; + private float amount; + private float balanceAfter; + private boolean isDeposit; + + public Transaction(float amount, float balanceAfter, boolean isDeposit) { + this.time = LocalDateTime.now(); + this.amount = amount; + this.balanceAfter = balanceAfter; + this.isDeposit = isDeposit; + } + + LocalDateTime getTime() { + return time; + } + + float getAmount() { + return amount; + } + + float getBalanceAfter() { + return balanceAfter; + } + + boolean getIsDeposit() { + return isDeposit; + } +} diff --git a/src/test/java/com/booleanuk/core/TestAccount.java b/src/test/java/com/booleanuk/core/TestAccount.java new file mode 100644 index 000000000..349fa1d48 --- /dev/null +++ b/src/test/java/com/booleanuk/core/TestAccount.java @@ -0,0 +1,98 @@ +package com.booleanuk.core; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; + +public class TestAccount { + @Test + void testDeposit() { + Account acc = new CurrentAccount(); + + Assertions.assertEquals(0f, acc.getBalance()); + Transaction tran = acc.deposit(2500.50f); + Assertions.assertEquals(2500.50f, acc.getBalance()); + + // check if transaction was created correctly + Assertions.assertTrue(tran.getTime() != null); + Assertions.assertEquals(2500.50f, tran.getAmount()); + Assertions.assertEquals(2500.50f, tran.getBalanceAfter()); + Assertions.assertTrue(tran.getIsDeposit()); + } + + @Test + void testInvalidDeposit() { + Account acc = new CurrentAccount(); + + Transaction tran = acc.deposit(-1000f); + Assertions.assertEquals(0f, acc.getBalance()); + + Assertions.assertTrue(tran == null); + } + + @Test + void testValidWithdraw() { + Account acc = new CurrentAccount(); + + Assertions.assertEquals(0f, acc.getBalance()); + acc.deposit(2500f); + Transaction tran = acc.withdraw(1000f); + Assertions.assertEquals(1500f, acc.getBalance()); + + // check if transaction was created correctly + Assertions.assertTrue(tran.getTime() != null); + Assertions.assertEquals(1000f, tran.getAmount()); + Assertions.assertEquals(1500f, tran.getBalanceAfter()); + Assertions.assertFalse(tran.getIsDeposit()); + } + + @Test + void testInvalidWithdraw() { + Account acc = new CurrentAccount(); + + acc.deposit(1000f); + Transaction tran = acc.withdraw(-1000f); + Assertions.assertTrue(tran == null); + + tran = acc.withdraw(1000.1f); + Assertions.assertTrue(tran == null); + + Assertions.assertEquals(1000f, acc.getBalance()); + } + + @Test + void testAccountStatement() { + Account acc = new CurrentAccount(); + + acc.deposit(1000f); + acc.deposit(2000f); + acc.withdraw(500f); + + String[] statement = acc.statement().split("\n"); + + String expected = "|Date|Credit|Debit|Balance|\n" + + "|14/01/2012||500.00|2500.00|\n" + + "|14/01/2012|2000.00||3000.00|\n" + + "|14/01/2012|1000.00||1000.00|\n"; + String[] expectedLines = expected.split("\n"); + + Assertions.assertEquals(expectedLines.length, statement.length); + + for (int i = 0; i < statement.length; i++) { + String line = statement[i]; + + String[] cells = line.strip().split("\\|"); + String[] expectedCells = expectedLines[i].strip().split("\\|"); + + Assertions.assertEquals(expectedCells.length, cells.length); + + // skip date cell + for (int n = 0; n < cells.length; n++) { + // if transaction line, skip date + if (i > 0 && n <= 1) { + continue; + } + Assertions.assertEquals(expectedCells[n].strip(), cells[n].strip()); + } + } + } +} diff --git a/src/test/java/com/booleanuk/extension/TestAccount.java b/src/test/java/com/booleanuk/extension/TestAccount.java new file mode 100644 index 000000000..2d1ed4508 --- /dev/null +++ b/src/test/java/com/booleanuk/extension/TestAccount.java @@ -0,0 +1,98 @@ +package com.booleanuk.extension; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; + +public class TestAccount { + @Test + void testDeposit() { + Account acc = new CurrentAccount(1); + + Assertions.assertEquals(0f, acc.getBalance()); + Transaction tran = acc.deposit(2500.50f); + Assertions.assertEquals(2500.50f, acc.getBalance()); + + // check if transaction was created correctly + Assertions.assertTrue(tran.getTime() != null); + Assertions.assertEquals(2500.50f, tran.getAmount()); + Assertions.assertEquals(2500.50f, tran.getBalanceAfter()); + Assertions.assertTrue(tran.getIsDeposit()); + } + + @Test + void testInvalidDeposit() { + Account acc = new CurrentAccount(1); + + Transaction tran = acc.deposit(-1000f); + Assertions.assertEquals(0f, acc.getBalance()); + + Assertions.assertTrue(tran == null); + } + + @Test + void testValidWithdraw() { + Account acc = new CurrentAccount(1); + + Assertions.assertEquals(0f, acc.getBalance()); + acc.deposit(2500f); + Transaction tran = acc.withdraw(1000f); + Assertions.assertEquals(1500f, acc.getBalance()); + + // check if transaction was created correctly + Assertions.assertTrue(tran.getTime() != null); + Assertions.assertEquals(1000f, tran.getAmount()); + Assertions.assertEquals(1500f, tran.getBalanceAfter()); + Assertions.assertFalse(tran.getIsDeposit()); + } + + @Test + void testInvalidWithdraw() { + Account acc = new CurrentAccount(1); + + acc.deposit(1000f); + Transaction tran = acc.withdraw(-1000f); + Assertions.assertTrue(tran == null); + + tran = acc.withdraw(1000.1f); + Assertions.assertTrue(tran == null); + + Assertions.assertEquals(1000f, acc.getBalance()); + } + + @Test + void testAccountStatement() { + Account acc = new CurrentAccount(1); + + acc.deposit(1000f); + acc.deposit(2000f); + acc.withdraw(500f); + + String[] statement = acc.statement().split("\n"); + + String expected = "|Date|Credit|Debit|Balance|\n" + + "|14/01/2012||500.00|2500.00|\n" + + "|14/01/2012|2000.00||3000.00|\n" + + "|14/01/2012|1000.00||1000.00|\n"; + String[] expectedLines = expected.split("\n"); + + Assertions.assertEquals(expectedLines.length, statement.length); + + for (int i = 0; i < statement.length; i++) { + String line = statement[i]; + + String[] cells = line.strip().split("\\|"); + String[] expectedCells = expectedLines[i].strip().split("\\|"); + + Assertions.assertEquals(expectedCells.length, cells.length); + + // skip date cell + for (int n = 0; n < cells.length; n++) { + // if transaction line, skip date + if (i > 0 && n <= 1) { + continue; + } + Assertions.assertEquals(expectedCells[n].strip(), cells[n].strip()); + } + } + } +} diff --git a/src/test/java/com/booleanuk/extension/TestBank.java b/src/test/java/com/booleanuk/extension/TestBank.java new file mode 100644 index 000000000..51305e14d --- /dev/null +++ b/src/test/java/com/booleanuk/extension/TestBank.java @@ -0,0 +1,19 @@ +package com.booleanuk.extension; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; + +public class TestBank { + @Test + void testNewBranch() { + Bank bank = new Bank(); + + Branch branch = bank.newBranch(); + Assertions.assertEquals(1000, branch.getId()); + Assertions.assertEquals(1, bank.getBranches().size()); // check if added to map + + branch = bank.newBranch(); + Assertions.assertEquals(1001, branch.getId()); + Assertions.assertEquals(2, bank.getBranches().size()); // check if added to map + } +} diff --git a/src/test/java/com/booleanuk/extension/TestBranch.java b/src/test/java/com/booleanuk/extension/TestBranch.java new file mode 100644 index 000000000..161c96f6e --- /dev/null +++ b/src/test/java/com/booleanuk/extension/TestBranch.java @@ -0,0 +1,28 @@ +package com.booleanuk.extension; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; + +public class TestBranch { + @Test + void testNewCurrentAccount() { + Bank bank = new Bank(); + Branch branch = bank.newBranch(); + + CurrentAccount acc = branch.newCurrentAccount(); + + Assertions.assertEquals(1, branch.getAccounts().size()); + Assertions.assertEquals(100010000000L, acc.getAccountNr()); + } + + @Test + void testNewSavingsAccount() { + Bank bank = new Bank(); + Branch branch = bank.newBranch(); + + SavingsAccount acc = branch.newSavingsAccount(); + + Assertions.assertEquals(1, branch.getAccounts().size()); + Assertions.assertEquals(100010000000L, acc.getAccountNr()); + } +}