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
24 changes: 24 additions & 0 deletions DOMAINMODEL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

# Domain Model – Banking Application

| Class | Fields | Method | What it does | Return values |
|--------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|------------------------------------------------------------------------|-------------------------------|
| **Customer** | `customerId: String` <br> `accounts: Map<String, Account>` | `createCurrentAccount()` | Creates and stores a new CurrentAccount for this customer | `CurrentAccount` |
| | | `createSavingsAccount()` | Creates and stores a new SavingsAccount for this customer | `SavingsAccount` |
| | | `getAccount(accountId)` | Retrieves an Account from the customer’s accounts by ID | `Account` |
| | | `getAccountId()` | Returns the customer’s unique ID | `String` |
| | | `addAccount(account)` | Adds an Account to the customer’s collection | `void` |
| **Account (abstract)** | `accountId: String` <br> `customerId: String` <br> `balance: int` <br> `transactions: List<Transaction>` | `deposit(amount)` | Adds funds, updates balance, and records a Transaction | `void` |
| | | `withdraw(amount)` | Subtracts funds, updates balance, records a Transaction (checks funds) | `void` |
| | | `generateStatement()` | Processes transactions into a formatted bank statement | `String` |
| | | `getBalance()` | Returns the current balance | `int` |
| | | `getAccountId()` | Returns this account’s unique ID | `String` |
| | | `addTransaction(transaction)` | Adds a Transaction to the account’s ledger | `void` |
| | | `getTransactions()` | Returns the list of all Transactions for this account | `List<Transaction>` |
| **CurrentAccount** | *(inherits fields from Account)* | *(inherits all methods from Account)* | Same behavior as Account | Same as Account |
| **SavingsAccount** | *(inherits fields from Account)* | *(inherits all methods from Account)* | Same behavior as Account | Same as Account |
| **Transaction** |`accountId: String` <br> `date: LocalDate` <br> `amount: float` <br> `type: String (CREDIT/DEBIT)` <br> `balanceAtTime: float` | `getDate()` | Returns the transaction date | `LocalDate` |
| | | `getAmount()` | Returns the transaction amount | `float` |
| | | `getBalanceAtTime()` | Returns the balance after this transaction | `gloat` |
| | | `getType()` | Returns whether it was a CREDIT or DEBIT | `String` |
| | | `getAccountId()` | Returns acountId | `String` |
92 changes: 92 additions & 0 deletions src/main/java/com/booleanuk/core/Account.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.booleanuk.core;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

public abstract class Account {
private final String accountId;
private final String customerId;
private float balance;
private final List<Transaction> transactions;

public Account(String accountId, String customerId, float balance) {
this.accountId = accountId;
this.customerId = customerId;
this.balance = balance;
this.transactions = new ArrayList<>();

}

public void deposit(float amount) {
if (amount <= 0.0f) {
throw new IllegalArgumentException("deposit amount must be positive");
}
this.balance += amount;

this.transactions.add(new Transaction(
this.accountId, LocalDate.now(), amount,"CREDIT", this.balance
));
}

public void withdraw(float amount) {
if (amount <= 0.0f) {
throw new IllegalArgumentException("deposit amount must be positive");
}
this.balance -= amount;
this.transactions.add(new Transaction(
this.accountId,
LocalDate.now(),
amount,
"DEBIT",
this.balance
));
}

public String generateStatement() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy");
List<Transaction> transactions = new ArrayList<>(this.getTransactions());
transactions.sort((a, b) -> b.getDate().compareTo(a.getDate()));

StringBuilder sb = new StringBuilder();
sb.append("date || credit || debit || balance");

for (int i = 0; i < transactions.size(); i++) {
Transaction trans = transactions.get(i);
String date = trans.getDate().format(dtf);
String credit = "CREDIT".equals(trans.getType()) ? String.format("%.2f", trans.getAmount()) : " ";
String debit = "DEBIT".equals(trans.getType()) ? String.format("%.2f", trans.getAmount()) : " ";
String balance = String.format("%.2f", trans.getBalanceAtTime());


sb.append("\n")
.append(date).append(" || ")
.append(credit).append(" || ")
.append(debit).append(" || ")
.append(balance);
}

return sb.toString();

}


public float getBalance() {
return this.balance;
}

public String getAccountId() {
return this.accountId;
}

public void addTransaction(Transaction transaction) {
this.transactions.add(transaction);
}


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

}
8 changes: 8 additions & 0 deletions src/main/java/com/booleanuk/core/CurrentAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.booleanuk.core;

public class CurrentAccount extends Account {

public CurrentAccount(String accountId, String customerId) {
super(accountId, customerId, 0.0f);
}
}
43 changes: 43 additions & 0 deletions src/main/java/com/booleanuk/core/Customer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.booleanuk.core;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class Customer {
private String customerId;
private Map<String, Account> accounts;

public Customer(String customerId) {
this.customerId = customerId;
this.accounts = new HashMap<>();
}

public Account createCurrentAccount(){
String accountId = UUID.randomUUID().toString();
CurrentAccount newAccount = new CurrentAccount(accountId, this.customerId);
this.accounts.put(accountId, newAccount);
return newAccount;
}

public Account createSavingsAccount(){
String accountId = UUID.randomUUID().toString();
SavingsAccount newSavingsAccount = new SavingsAccount(accountId, this.customerId);
this.accounts.put(accountId, newSavingsAccount);
return newSavingsAccount;
}

public Account getAccount(String accountId){
return accounts.get(accountId);
}

public String getCustomerId() {
return this.customerId;
}
public void setCustomerId(String customerId) {}


public void addAccount(Account account){
accounts.put(account.getAccountId(), account);
}
}
41 changes: 41 additions & 0 deletions src/main/java/com/booleanuk/core/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.booleanuk.core;

import java.time.LocalDate;

public class Main {
public static void main(String[] args) {

// Create a customer
Customer customer = new Customer("C-001");
System.out.println("Customer ID: " + customer.getCustomerId());
// Create accounts via methods
Account current = customer.createCurrentAccount();
Account savings = customer.createSavingsAccount();

System.out.println("Created Current Account ID: " + current.getAccountId());
System.out.println("Created Savings Account ID: " + savings.getAccountId());

Account foundCurrent = customer.getAccount(current.getAccountId());
Account foundSavings = customer.getAccount(savings.getAccountId());

System.out.println("Found Current equals created? " + (foundCurrent == current));
System.out.println("Found Savings equals created? " + (foundSavings == savings));

Account external = new CurrentAccount("ACC-001", "C-001");
customer.addAccount(external);
System.out.println("Added external account with ID: " + external.getAccountId());
System.out.println("Lookup external: " + (customer.getAccount("ACC-001") == external));

Account account = new CurrentAccount("ACC-023", "C-1");

// Add the three example transactions
account.addTransaction(new Transaction("ACC-023", LocalDate.of(2012, 1, 10), 1000.0f, "CREDIT", 1000.0f));
account.addTransaction(new Transaction("ACC-023", LocalDate.of(2012, 1, 13), 2000.0f, "CREDIT", 3000.0f));
account.addTransaction(new Transaction("ACC-023", LocalDate.of(2012, 1, 14), 500.0f, "DEBIT", 2500.0f));

// Print the statement
System.out.println(account.generateStatement());
}


}
8 changes: 8 additions & 0 deletions src/main/java/com/booleanuk/core/SavingsAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.booleanuk.core;

public class SavingsAccount extends Account {
public SavingsAccount(String accountId, String customerId) {
super(accountId, customerId, 0.0f);

}
}
39 changes: 39 additions & 0 deletions src/main/java/com/booleanuk/core/Transaction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.booleanuk.core;

import java.time.LocalDate;

public class Transaction {
private String accountId;
private LocalDate date;
private float amount;
private String type;
private float balanceAtTime;

public Transaction(String accountId, LocalDate date, float amount, String type, float balanceAtTime) {
this.accountId = accountId;
this.date = date;
this.amount = amount;
this.type = type;
this.balanceAtTime = balanceAtTime;
}

public LocalDate getDate() {
return date;
}

public float getBalanceAtTime() {
return balanceAtTime;
}

public String getType() {
return type;
}

public float getAmount() {
return amount;
}

public String getAccountId() {
return accountId;
}
}
129 changes: 129 additions & 0 deletions src/test/java/com/booleanuk/core/AccountTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.booleanuk.core;

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

import java.time.LocalDate;

public class AccountTest {

@Test
public void testDepositForCurrentAccount() {
Account account = new CurrentAccount("ACC-001", "C-123");
float initialBalance = account.getBalance();
float depositAmount = 500.0f;

account.deposit(depositAmount);

Assertions.assertEquals(initialBalance + depositAmount, account.getBalance());

}
@Test
public void testDepositForSavingAccount() {
Account account = new CurrentAccount("ACC-001", "C-123");
float initialBalance = account.getBalance();
float depositAmount = 400.0f;
account.deposit(depositAmount);

Assertions.assertEquals(initialBalance + depositAmount, account.getBalance());
}


@Test
public void testMultipleDepositsBalance() {
Account account = new CurrentAccount("ACC-001", "C-123");

account.deposit(1000f);
account.deposit(2000f);

Assertions.assertEquals(3000f, account.getBalance());
Assertions.assertEquals(2, account.getTransactions().size());
}

@Test
public void testWithdrawForCurrentAccount() {
Account account = new CurrentAccount("ACC-001", "C-123");

account.deposit(500.0f);
float startingBalance = account.getBalance();

float withdrawAmount = 200.0f;
account.withdraw(withdrawAmount);

Assertions.assertEquals(startingBalance - withdrawAmount, account.getBalance());

}

@Test
public void testMultipleWithdrawals() {
Account account = new CurrentAccount("ACC-001", "C-123");
account.deposit(1000f);

account.withdraw(100f);
account.withdraw(200f);

Assertions.assertEquals(700f, account.getBalance(), 0.0001f);
Assertions.assertEquals(3, account.getTransactions().size());

Transaction last = account.getTransactions().get(2);
Assertions.assertEquals("DEBIT", last.getType());
Assertions.assertEquals(200f, last.getAmount(), 0.0001f);
}

@Test
public void testAddTransactionStoresTransaction() {
Account account = new CurrentAccount("ACC-100", "C-123");

Transaction tx = new Transaction("ACC-100", LocalDate.now(), 500, "CREDIT", 500);
account.addTransaction(tx);

Assertions.assertEquals(1, account.getTransactions().size());
Assertions.assertEquals(tx, account.getTransactions().get(0));
}

@Test
public void testGetTransactionsInitiallyEmpty() {
Account account = new CurrentAccount("ACC-101", "C-123");

Assertions.assertNotNull(account.getTransactions());
Assertions.assertTrue(account.getTransactions().isEmpty());

}

@Test
public void testGenerateStatementContainsHeader() {
Account account = new CurrentAccount("ACC-102", "C-123");

account.addTransaction(new Transaction("ACC-102", LocalDate.of(2012, 1, 10), 1000f, "CREDIT", 1000f));
account.addTransaction(new Transaction("ACC-102", LocalDate.of(2012, 1, 13), 2000f, "CREDIT", 3000f));
account.addTransaction(new Transaction("ACC-102", LocalDate.of(2012, 1, 14), 500f, "DEBIT", 2500f));

String statement = account.generateStatement();

Assertions.assertTrue(statement.contains("date || credit || debit || balance"));
Assertions.assertTrue(statement.contains("14/01/2012"));
Assertions.assertTrue(statement.contains("13/01/2012"));
Assertions.assertTrue(statement.contains("10/01/2012"));
}

@Test
public void testStatementMatchesAcceptanceCriteriaExact() {
Account account = new CurrentAccount("ACC-023", "C-1");

account.addTransaction(new Transaction("ACC-023", java.time.LocalDate.of(2012, 1, 10), 1000.0f, "CREDIT", 1000.0f));
account.addTransaction(new Transaction("ACC-023", java.time.LocalDate.of(2012, 1, 13), 2000.0f, "CREDIT", 3000.0f));
account.addTransaction(new Transaction("ACC-023", java.time.LocalDate.of(2012, 1, 14), 500.0f, "DEBIT", 2500.0f));

String expected = String.join("\n",
"date || credit || debit || balance",
"14/01/2012 || || 500.00 || 2500.00",
"13/01/2012 || 2000.00 || || 3000.00",
"10/01/2012 || 1000.00 || || 1000.00"
);

Assertions.assertEquals(expected, account.generateStatement());
}



}
Loading
Loading