Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1eedd9d
Create initial class diagram
pudkipz Jan 15, 2025
58d3652
Create sanity check test for Transaction class
pudkipz Jan 15, 2025
54f713d
Create Transaction class
pudkipz Jan 15, 2025
99465ff
Create dummy tests and empty bank account classes
pudkipz Jan 15, 2025
8acc01d
Add test to verify attributes of new accounts
pudkipz Jan 15, 2025
c5939d0
Populate BankAccount with dummy methods and implement constructor
pudkipz Jan 15, 2025
433d477
Add test to verify withdrawing too much money
pudkipz Jan 15, 2025
b0d7b40
Add trivial implementation of withdraw method to pass test
pudkipz Jan 15, 2025
e5299d9
Add more dummy tests
pudkipz Jan 15, 2025
5b11bfd
Create test for depositing
pudkipz Jan 15, 2025
f8e1664
Implement deposit method to pass test
pudkipz Jan 15, 2025
1d3b815
Implement test for withdrawing valid amounts
pudkipz Jan 15, 2025
7f26d05
Fix return value of withdraw
pudkipz Jan 15, 2025
e6c51fb
Add test to verify that withdrawing decreases balance
pudkipz Jan 15, 2025
eac8985
Make sure withdraw withdraws money
pudkipz Jan 15, 2025
60283dc
Make sure withdraw doesn't remove money if there isn't enough
pudkipz Jan 15, 2025
ce89a13
Add test to verify that transactions are stored
pudkipz Jan 15, 2025
c4776cf
Store transactions in withdraw and deposit
pudkipz Jan 15, 2025
6043456
Create test for verifying correct transactions
pudkipz Jan 15, 2025
e482b07
Make sure transactions are created correctly
pudkipz Jan 15, 2025
52b246f
Create test for empty bank statements
pudkipz Jan 15, 2025
8976487
Implement generation of empty bank statements
pudkipz Jan 15, 2025
332e6c4
Add test for generating nonempty bank statements
pudkipz Jan 15, 2025
7a08dcf
Fix failing tests
pudkipz Jan 15, 2025
549bf54
Finalize class diagram
pudkipz Jan 15, 2025
ab92f09
Calculate balance through transaction history instead
pudkipz Jan 15, 2025
5588a50
Implement branch numbers and represent account and branch number with…
pudkipz Jan 15, 2025
ee5d641
Overload deposit and withdraw to support externally providing LocalDa…
pudkipz Jan 15, 2025
12937c3
Update bank statement test to use manual date time
pudkipz Jan 15, 2025
53d2a02
Add dummy methods for overdrafts in SavingsAccount
pudkipz Jan 15, 2025
3e92526
Add dummy methods and attributes for overdrafts
pudkipz Jan 15, 2025
d2996d7
Add test and implementation to verify that overdraft is valid
pudkipz Jan 15, 2025
b4d2b3b
Add dummy test for BankSystem
pudkipz Jan 15, 2025
1d5db77
Write tests for handling overdrafts and requests
pudkipz Jan 15, 2025
dfdeded
Fix handling of overdrafts and requests
pudkipz Jan 15, 2025
0076cbe
Finalize class diagram
pudkipz Jan 15, 2025
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
Binary file added bank_class_diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added bank_extension_class_diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 96 additions & 0 deletions src/main/java/com/booleanuk/core/BankAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.booleanuk.core;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public abstract class BankAccount {
private final String accountNumber;
private final String branchNumber;
private final List<Transaction> transactions;

public BankAccount(int branchNumber) {
Random random = new Random();
int randomAccountNumber = random.nextInt(99999999);
this.accountNumber = "0".repeat((int) (8 - Math.ceil(Math.log10(randomAccountNumber)))) + randomAccountNumber;
if (branchNumber > 999999) {
System.out.println("Invalid branch code (must be 6 digit number). Branch code will be set to 0.");
branchNumber = 0;
}
this.branchNumber = "0".repeat((int) (6 - Math.ceil(Math.log10(branchNumber)))) + branchNumber;
this.transactions = new ArrayList<>();
}

public BankAccount(String accountNumber, String branchNumber) {
// todo: make sure numbers are OK length
this.accountNumber = accountNumber;
this.branchNumber = branchNumber;
this.transactions = new ArrayList<>();
}

public boolean withdraw(double amount, LocalDateTime dateTime) {
double balance = this.getBalance();
if (amount <= balance) {
balance -= amount;
transactions.add(new Transaction(-amount, balance, dateTime));
}
return amount <= balance;
}

public boolean withdraw(double amount) {
return this.withdraw(amount, LocalDateTime.now());
}

// maybe can be void... or maybe consider overflow?
public boolean deposit(double amount, LocalDateTime dateTime) {
double balance = this.getBalance();
balance += amount;
transactions.add(new Transaction(amount, balance, dateTime));
return true;
}

public boolean deposit(double amount) {
return this.deposit(amount, LocalDateTime.now());
}

// TODO Fix formatting
public String generateBankStatement() {
StringBuilder sb = new StringBuilder();
sb.append("date\t||credit\t||debit\t||balance\n");

for (Transaction t : transactions.reversed()) {
sb.append(t.getDateTime().getDayOfMonth()).append("/")
.append(t.getDateTime().getMonthValue()).append("/")
.append(t.getDateTime().getYear()).append("||");
if (t.getAmount() > 0) {
sb.append(String.format("%.2f", Math.abs(t.getAmount()))).append("||\t");
} else {
sb.append("\t||").append(String.format("%.2f", Math.abs(t.getAmount())));
}
sb.append("||").append(String.format("%.2f", t.getCurrentBalance())).append("\n");
}

return sb.toString();
}

public String getAccountNumber() {
return accountNumber;
}

public double getBalance() {
double balance = 0;
for (Transaction t : transactions) {
balance += t.getAmount();
}
return balance;
}

public List<Transaction> getTransactions() {
return transactions;
}

public String getBranchNumber() {
return branchNumber;
}
}
41 changes: 41 additions & 0 deletions src/main/java/com/booleanuk/core/BankSystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.booleanuk.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BankSystem {
private List<OverdraftRequest> overdraftRequests;
private Map<String, SavingsAccount> savingsAccounts;
private Map<String, CurrentAccount> currentAccounts;

public BankSystem() {
overdraftRequests = new ArrayList<>();
savingsAccounts = new HashMap<>();
currentAccounts = new HashMap<>();
}

// maybe void?
public boolean approve(OverdraftRequest or) {
return savingsAccounts.get(or.accountNumber + or.branchNumber).setMaxOverdraft(or.getAmount());
}

public void addCurrentAccount(CurrentAccount b) {
currentAccounts.put(b.getAccountNumber() + b.getBranchNumber(), b);
}

public void addSavingsAccount(SavingsAccount b) {
savingsAccounts.put(b.getAccountNumber() + b.getBranchNumber(), b);
}

public Map<String, BankAccount> getBankAccounts() {
Map<String, BankAccount> bankAccounts = new HashMap<>(currentAccounts);
bankAccounts.putAll(savingsAccounts);
return bankAccounts;
}

public List<OverdraftRequest> getOverdraftRequests() {
return overdraftRequests;
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/booleanuk/core/CurrentAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.booleanuk.core;

public class CurrentAccount extends BankAccount {
public CurrentAccount() {
super(1);
}

public CurrentAccount(int branchNumber) {
super(branchNumber);
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/booleanuk/core/OverdraftRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.booleanuk.core;

public class OverdraftRequest {
String accountNumber;
String branchNumber;
double amount;

public OverdraftRequest(String accountNumber, String branchNumber, double amount) {
this.accountNumber = accountNumber;
this.branchNumber = branchNumber;
this.amount = amount;
}

public String getAccountNumber() {
return accountNumber;
}

public String getBranchNumber() {
return branchNumber;
}

public double getAmount() {
return amount;
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/booleanuk/core/SavingsAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.booleanuk.core;

import java.time.LocalDateTime;

public class SavingsAccount extends BankAccount {
private double maxOverdraft;

public SavingsAccount(String accountNumber, String branchNumber) {
super(accountNumber, branchNumber);
this.maxOverdraft = 0;
}

public SavingsAccount(int branchNumber) {
super(branchNumber);
this.maxOverdraft = 0;
}

@Override
public boolean withdraw(double amount, LocalDateTime dateTime) {
if (getBalance() - amount < - maxOverdraft) {
return false;
}
getTransactions().add(new Transaction(-amount, getBalance() - amount, dateTime));
return true;
}

@Override
public boolean withdraw(double amount) {
return this.withdraw(amount, LocalDateTime.now());
}

// probably won't be used, but useful in theory
public boolean hasOverdraft() {
return maxOverdraft > 0;
}

public double getMaxOverdraft() {
return maxOverdraft;
}

public boolean setMaxOverdraft(double maxOverdraft) {
if (maxOverdraft < 0) {
System.out.println("Cannot set negative overdraft.");
return false;
}
this.maxOverdraft = maxOverdraft;
return true;
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/booleanuk/core/Transaction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.booleanuk.core;

import java.time.LocalDateTime;

public class Transaction {
private final double amount;
private final double currentBalance;
private final LocalDateTime dateTime;

public Transaction(double amount, double currentBalance, LocalDateTime dateTime) {
this.amount = amount;
this.currentBalance = currentBalance;
this.dateTime = dateTime;
}

public double getAmount() {
return amount;
}

public double getCurrentBalance() {
return currentBalance;
}

public LocalDateTime getDateTime() {
return dateTime;
}
}
142 changes: 142 additions & 0 deletions src/test/java/com/booleanuk/core/TestBankAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package com.booleanuk.core;

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;

public class TestBankAccount {
@Test
public void newAccountInstancesAreValid() {
BankAccount currentAccount = new CurrentAccount(999999);
assertEquals(8, currentAccount.getAccountNumber().length());
assertEquals(6, currentAccount.getBranchNumber().length());
assertEquals(0, currentAccount.getBalance());
assertEquals(0, currentAccount.getTransactions().size());
}
@Test
public void withdrawTooMuchShouldFail() {
BankAccount currentAccount = new CurrentAccount();
double amount = 1000;
assertFalse(currentAccount.withdraw(amount));
}

@Test
public void canWithdrawWithinReason() {
BankAccount account = new CurrentAccount();
account.deposit(1000);
assertTrue(account.withdraw(500));
}

@Test
public void withdrawingRemovesMoney() {
BankAccount account = new CurrentAccount();
account.deposit(1000);
assertTrue(account.withdraw(500));
assertEquals(500, account.getBalance());
}
@Test
public void withdrawingRemovesMoneyOnlyIfValidAmount() {
BankAccount account = new CurrentAccount();
account.deposit(1000);
assertFalse(account.withdraw(2000));
assertEquals(1000, account.getBalance());
}

@Test
public void depositAddsTheRightAmount() {
BankAccount account = new CurrentAccount();
assertTrue(account.deposit(1000));
assertEquals(1000, account.getBalance());
}

@Test
public void transactionsAreStored() {
BankAccount account = new CurrentAccount();
assertTrue(account.deposit(1000));
assertTrue(account.withdraw(100));
assertEquals(2, account.getTransactions().size());
}

@Test
public void transactionsAreStoredCorrectly() {
BankAccount account = new CurrentAccount();
LocalDateTime ldt = LocalDateTime.now();
assertTrue(account.deposit(1000));
assertTrue(account.withdraw(100));
assertEquals(2, account.getTransactions().size());
LocalDateTime depTime = account.getTransactions().getFirst().getDateTime();
LocalDateTime wdrTime = account.getTransactions().getLast().getDateTime();
// deposit time correct within 1 s
assertEquals(ldt.toLocalDate(), depTime.toLocalDate());
assertEquals(ldt.getHour(), depTime.getHour());
assertEquals(ldt.getMinute(), depTime.getMinute());
assertEquals(ldt.getSecond(), depTime.getSecond());
// withdraw time correct within 1 s
assertEquals(ldt.toLocalDate(), wdrTime.toLocalDate());
assertEquals(ldt.getHour(), wdrTime.getHour());
assertEquals(ldt.getMinute(), wdrTime.getMinute());
assertEquals(ldt.getSecond(), wdrTime.getSecond());
// deposit amounts correct
Transaction dep = account.getTransactions().getFirst();
assertEquals(1000, dep.getAmount());
assertEquals(1000, dep.getCurrentBalance());
// withdraw amounts correct
Transaction wdr = account.getTransactions().getLast();
assertEquals(-100, wdr.getAmount());
assertEquals(900, wdr.getCurrentBalance());
}

@Test
public void generateStatementOnNoTransactions() {
BankAccount account = new CurrentAccount();
assertEquals(
"date||credit||debit||balance",
account.generateBankStatement().replaceAll("\\s+",""));
}

@Test
public void generateStatementOnSomeTransactions() {
BankAccount account = new CurrentAccount();
LocalDateTime ldt1 = LocalDateTime.of(2012, 1, 14, 13, 54);
LocalDateTime ldt2 = LocalDateTime.of(2012, 1, 13, 22, 18);
LocalDateTime ldt3 = LocalDateTime.of(2012, 1, 10, 11, 27);
account.deposit(1000, ldt3);
account.withdraw(100, ldt2);
account.withdraw(200, ldt1);
// System.out.println(account.generateBankStatement());

String sb = "date||credit||debit||balance" +
"14/1/2012" +
"||||200.00||700.00" +
"13/1/2012" +
"||||100.00||900.00" +
"10/1/2012" +
"||1000.00||||1000.00".replaceAll("\\s+","");

assertEquals(sb, account.generateBankStatement().replaceAll("\\s+",""));
}

@Test
public void overdraftNeedsToBePositive() {
SavingsAccount account = new SavingsAccount(523611);
assertFalse(account.setMaxOverdraft(-50));
}

@Test
public void cannotGoBeyondOverdraftLimit() {
SavingsAccount account = new SavingsAccount(123456);
account.deposit(100);
assertFalse(account.withdraw(200));
assertEquals(100, account.getBalance());
}

@Test
public void canHaveNegativeBalanceWithinOverdraft() {
SavingsAccount account = new SavingsAccount(123456);
account.deposit(100);
account.setMaxOverdraft(200);
assertTrue(account.withdraw(200));
assertEquals(-100, account.getBalance());
}
}
Loading
Loading