diff --git a/src/COREEXERCISE.md b/src/COREEXERCISE.md new file mode 100644 index 000000000..c12c119e5 --- /dev/null +++ b/src/COREEXERCISE.md @@ -0,0 +1,50 @@ +# Bank exercise + +### Core excercise + +**User Stories** + +``` +As a customer, +So I can safely store and use my money, +I want to create a current account. + +As a customer, +So I can save for a rainy day, +I want to create a savings account. + +As a customer, +So I can keep a record of my finances, +I want to generate bank statements with transaction dates, amounts, and balance at the time of transaction. + +As a customer, +So I can use my account, +I want to deposit and withdraw funds. +``` +**Domain Models** + +| Classes | Members | Methods | Scenario | Outputs | +|------------|-------------------|-------------------|----------|---------| +| `Customer` | `properties` | `getters/setters` | | | +| | `Account account` | `createAccount` | | | + +| Classes | Members | Methods | Scenario | Outputs | +|-----------|-----------------------------------|---------------------------|-------------------------------|---------| +| `Account` | `List transactions` | `generateBankStatement()` | If there are any transactions | String | +| | | | If there are no transactions | String | + +| Classes | Members | Methods | Scenario | Outputs | +|-----------|---------------------|-------------|------------------------------|---------| +| `Account` | `BigDecimal amount` | `deposit()` | If amount is a valid int | String | +| | | | If amount is not a valid int | String | + +| Classes | Members | Methods | Scenario | Outputs | +|-----------|---------------------|--------------|-----------------------------------|---------| +| `Account` | `BigDecimal amount` | `withdraw()` | If amount is a valid int | String | +| | | | If amount is a valid int | String | +| | | | If amount is greater than balance | String | + + +| Classes | Members | Methods | Scenario | Outputs | +|---------------|--------------|--------------------|----------|---------| +| `Transaction` | `properties` | `getters/setters` | | | diff --git a/src/Diagram.png b/src/Diagram.png new file mode 100644 index 000000000..6897e18ae Binary files /dev/null and b/src/Diagram.png differ diff --git a/src/EXTENSION.md b/src/EXTENSION.md new file mode 100644 index 000000000..18fc682b7 --- /dev/null +++ b/src/EXTENSION.md @@ -0,0 +1,86 @@ +# Bank exercise + +### Core excercise + +**User Stories** + +``` +As a customer, +So I can safely store and use my money, +I want to create a current account. + +As a customer, +So I can save for a rainy day, +I want to create a savings account. + +As a customer, +So I can keep a record of my finances, +I want to generate bank statements with transaction dates, amounts, and balance at the time of transaction. + +As a customer, +So I can use my account, +I want to deposit and withdraw funds. + +As an engineer, +So I don't need to keep track of state, +I want account balances to be calculated based on transaction history instead of stored in memory. + +As a bank manager, +So I can expand, +I want accounts to be associated with specific branches. + +As a customer, +So I have an emergency fund, +I want to be able to request an overdraft on my account. + +As a bank manager, +So I can safeguard our funds, +I want to approve or reject overdraft requests. + +As a customer, +So I can stay up to date, +I want statements to be sent as messages to my phone. +``` +**Domain Models** + +| Classes | Members | Methods | Scenario | Outputs | +|------------|-------------------|----------------------|-------------------|---------| +| `Customer` | `properties` | `getters/setters` | | | +| | `Account account` | `createAccount` | | | +| | `Account account` | `requestOverdraft()` | if it is accepted | true | +| | | | if it is rejected | | + + +| Classes | Members | Methods | Scenario | Outputs | +|-----------|--------------------------------------|-----------------------|-------------------|---------| +| `Manager` | `properties` | `getters/setters` | | | +| | `Customer customer, Account account` | `decideOnOverdraft()` | if it is accepted | true | +| | | | if it is rejected | false | + +| Classes | Members | Methods | Scenario | Outputs | +|-----------|-----------------------------------|---------------------------|------------------------------|---------| +| `Account` | `List transactions` | `generateBankStatement()` | If there are any transactions | String | +| | | | If there are no transactions | String | +| | `double amount` | `deposit()` | If amount is a valid int | String | +| | | | If amount is not a valid int | String | +| | `List ` | `calculateBalance()` | if there are no transactions | String | +| | | | if there are transactions | String | + + +| Classes | Members | Methods | Scenario | Outputs | +|-----------|-----------------|--------------|--------------------------------------------------------------------|---------| +| `Account` | `double amount` | `withdraw()` | If amount is a valid int | String | +| | | | If amount is a valid int | String | +| | | | If amount is greater than balance and overdraft has been accepted | String | +| | | | if account is greater than balance and overdraft has been rejected | String | + + +| Classes | Members | Methods | Scenario | Outputs | +|---------------|--------------|--------------------|----------|---------| +| `Transaction` | `properties` | `getters/setters` | | | + + +| Classes | Members | Methods | Scenario | Outputs | +|----------|-------------------|-------------------|----------|---------| +| `Branch` | `properties` | `getters/setters` | | | + diff --git a/src/diagram-extension.png b/src/diagram-extension.png new file mode 100644 index 000000000..361c596dc Binary files /dev/null and b/src/diagram-extension.png differ diff --git a/src/main/java/com/booleanuk/core/dto/TransactionResult.java b/src/main/java/com/booleanuk/core/dto/TransactionResult.java new file mode 100644 index 000000000..97d952069 --- /dev/null +++ b/src/main/java/com/booleanuk/core/dto/TransactionResult.java @@ -0,0 +1,18 @@ +package com.booleanuk.core.dto; + +import java.math.BigDecimal; + +public class TransactionResult { + private boolean success; + private String message; + + public TransactionResult(boolean success, String message) { + this.success = success; + this.message = message; + } + + public boolean isSuccess() { return success; } + + public String getMessage() { return message; } + +} diff --git a/src/main/java/com/booleanuk/core/exceptions/InsufficientFundsException.java b/src/main/java/com/booleanuk/core/exceptions/InsufficientFundsException.java new file mode 100644 index 000000000..f80ed0cd9 --- /dev/null +++ b/src/main/java/com/booleanuk/core/exceptions/InsufficientFundsException.java @@ -0,0 +1,7 @@ +package com.booleanuk.core.exceptions; + +public class InsufficientFundsException extends Exception{ + public InsufficientFundsException(String message) { + super(message); + } +} diff --git a/src/main/java/com/booleanuk/core/exceptions/InvalidAmountException.java b/src/main/java/com/booleanuk/core/exceptions/InvalidAmountException.java new file mode 100644 index 000000000..06dbded58 --- /dev/null +++ b/src/main/java/com/booleanuk/core/exceptions/InvalidAmountException.java @@ -0,0 +1,7 @@ +package com.booleanuk.core.exceptions; + +public class InvalidAmountException extends Exception { + public InvalidAmountException(String message) { + super(message); + } +} diff --git a/src/main/java/com/booleanuk/core/models/Account.java b/src/main/java/com/booleanuk/core/models/Account.java new file mode 100644 index 000000000..6ce42473e --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/Account.java @@ -0,0 +1,114 @@ +package com.booleanuk.core.models; + +import com.booleanuk.core.dto.TransactionResult; +import com.booleanuk.core.exceptions.InsufficientFundsException; +import com.booleanuk.core.exceptions.InvalidAmountException; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class Account { + private Customer customer; + private int id; + private List transactions; + private int transactionCount = 1; + private boolean canBeOverdrafted = false; + private Branch branch; + private AccountType accountType; + + public Account(Customer customer, int id, AccountType accountType) { + this.customer = customer; + this.id = id; + this.accountType = accountType; + this.transactions = new ArrayList<>(); + } + public Account(Customer customer, int id, Branch branch, AccountType accountType) { + this.customer = customer; + this.id = id; + this.branch = branch; + this.accountType = accountType; + this.transactions = new ArrayList<>(); + } + public Account () {} + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public List getTransactions() { + return transactions; + } + + public void setTransactions(List transactions) { + this.transactions = transactions; + } + + public TransactionResult deposit(BigDecimal transAmount){ + if (transAmount.compareTo(BigDecimal.ZERO) >= 0) { + return new TransactionResult(false, "Amount must be more than 0"); + } + + Transaction trans = new Transaction(this.transactionCount, LocalDate.now(), transAmount, this, TransactionType.DEPOSIT); + this.transactionCount++; + this.transactions.add(trans); + return new TransactionResult(true, "Deposit successful"); + + + } + public TransactionResult withdraw(BigDecimal transAmount){ + + if (transAmount.compareTo(BigDecimal.ZERO) <=0) { + throw new InvalidAmountException("Amount must be more than 0"); + } + if (calculateBalance().compareTo(transAmount) <0 && !canBeOverdrafted) { + throw new InsufficientFundsException("Insufficient funds. Balance is at: " +calculateBalance().toString()); + } + + Transaction trans = new Transaction(this.transactionCount, LocalDate.now(), transAmount,this, TransactionType.WITHDRAWAL); + this.transactionCount++; + this.transactions.add(trans); + return new TransactionResult(true, transAmount.toString()+ " have been withdrawn from you account"); + } + public StringBuilder generateBankStatements() { + + StringBuilder returnString = new StringBuilder("date\t\t||\tcredit\t||\tdebit\t||\tbalance\n"); + BigDecimal currentBalance = new BigDecimal("0"); + + for (Transaction trans : transactions) { + currentBalance = currentBalance.add(trans.getTransAmount()); + if (trans.getType() == TransactionType.WITHDRAWAL) + returnString.append(trans.getDate().toString() + "\t||\t" + trans.getTransAmount().toString()+"\t\t||\t\t||\t"+currentBalance+"\n"); + + if (trans.getTransAmount().compareTo(BigDecimal.ZERO) >= 0) + returnString.append(trans.getDate().toString() + "\t||\t\t\t||\t" + trans.getTransAmount()+"\t||\t"+currentBalance+"\n"); + + + } + return returnString; + } + public boolean requestOverdraft() { + this.canBeOverdrafted = branch.getManager().decideOnOverdraft(this); + return this.canBeOverdrafted; + } + public BigDecimal calculateBalance() { + BigDecimal totalBalance = new BigDecimal("0"); + for (Transaction trans : transactions){ + totalBalance = totalBalance.add(trans.getTransAmount()); + } + return totalBalance; + } +} diff --git a/src/main/java/com/booleanuk/core/models/AccountsType.java b/src/main/java/com/booleanuk/core/models/AccountsType.java new file mode 100644 index 000000000..e3d797fd8 --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/AccountsType.java @@ -0,0 +1,5 @@ +package com.booleanuk.core.models; + +public enum AccountType { + SAVINGS, CURRENT +} diff --git a/src/main/java/com/booleanuk/core/models/Branch.java b/src/main/java/com/booleanuk/core/models/Branch.java new file mode 100644 index 000000000..d6bb0e3f6 --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/Branch.java @@ -0,0 +1,41 @@ +package com.booleanuk.core.models; + +import java.util.ArrayList; +import java.util.List; + +public class Branch { + private String name; + private Manager manager; + private List accounts; + + public Branch(String name, Manager manager) { + this.name = name; + this.manager = manager; + this.accounts = new ArrayList<>(); + } + public Branch() {} + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Manager getManager() { + return manager; + } + + public void setManager(Manager manager) { + this.manager = manager; + } + + public List getAccounts() { + return accounts; + } + + public void setAccounts(List accounts) { + this.accounts = accounts; + } +} diff --git a/src/main/java/com/booleanuk/core/models/Customer.java b/src/main/java/com/booleanuk/core/models/Customer.java new file mode 100644 index 000000000..01c04355b --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/Customer.java @@ -0,0 +1,22 @@ +package com.booleanuk.core.models; + +import java.util.ArrayList; +import java.util.List; + +public class Customer extends User { + + private List accounts; + + public Customer(String name, int id) { + super(name, id); + this.accounts = new ArrayList<>(); + } + + public Customer() {} + + public String createAccount( Account account) { + this.accounts.add(account); + return "Account "+account.getId()+" was added to " + super.getName(); + } + +} diff --git a/src/main/java/com/booleanuk/core/models/Manager.java b/src/main/java/com/booleanuk/core/models/Manager.java new file mode 100644 index 000000000..9260d456a --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/Manager.java @@ -0,0 +1,19 @@ +package com.booleanuk.core.models; + +public class Manager extends User { + private Branch branch; + + public Manager(String name, int id, Branch branch) { + super(name, id); + this.branch = branch; + } + + public Manager() { + } + public boolean decideOnOverdraft(Account a) { + if (a.getTransactions().size()>3) { + return true; + } else + return false; + } +} diff --git a/src/main/java/com/booleanuk/core/models/Transaction.java b/src/main/java/com/booleanuk/core/models/Transaction.java new file mode 100644 index 000000000..dd555972f --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/Transaction.java @@ -0,0 +1,60 @@ +package com.booleanuk.core.models; + +import java.math.BigDecimal; +import java.time.LocalDate; + +public class Transaction { + private int id; + private LocalDate date; + private BigDecimal transAmount; + private Account account; + private TransactionType type; + + public Transaction(int id, LocalDate date, BigDecimal transAmount, Account account, TransactionType transactionType) { + this.id = id; + this.date = date; + this.transAmount = transAmount; + this.account = account; + this.type = transactionType; + } + public Transaction() {} + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public BigDecimal getTransAmount() { + return transAmount; + } + + public void setTransAmount(BigDecimal transAmount) { + this.transAmount = transAmount; + } + public Account getAccount() { + return account; + } + + public void setAccount(Account account) { + this.account = account; + } + + public TransactionType getType() { + return type; + } + + public void setType(TransactionType type) { + this.type = type; + } +} diff --git a/src/main/java/com/booleanuk/core/models/TransactionType.java b/src/main/java/com/booleanuk/core/models/TransactionType.java new file mode 100644 index 000000000..268a8a801 --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/TransactionType.java @@ -0,0 +1,5 @@ +package com.booleanuk.core.models; + +public enum TransactionType { + DEPOSIT, WITHDRAWAL +} diff --git a/src/main/java/com/booleanuk/core/models/User.java b/src/main/java/com/booleanuk/core/models/User.java new file mode 100644 index 000000000..7b0ecb7d2 --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/User.java @@ -0,0 +1,28 @@ +package com.booleanuk.core.models; + +public abstract class User { + private String name; + private int id; + + public User(String name, int id) { + this.name = name; + this.id = id; + } + + public User() {} + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/booleanuk/core/models/main.java b/src/main/java/com/booleanuk/core/models/main.java new file mode 100644 index 000000000..b7c74ec15 --- /dev/null +++ b/src/main/java/com/booleanuk/core/models/main.java @@ -0,0 +1,7 @@ +package com.booleanuk.core.models; + +public class main { + public static void main(String[] args) { + System.out.println("date\t\t||\tcredit\t||\tdebit\t||\tbalance\n14/01/12\t||\t100\t\t||\t\t\t||\t1100"); + } +} diff --git a/src/test/java/com/booleanuk/core/AccountTest.java b/src/test/java/com/booleanuk/core/AccountTest.java new file mode 100644 index 000000000..dd936e78e --- /dev/null +++ b/src/test/java/com/booleanuk/core/AccountTest.java @@ -0,0 +1,118 @@ +package com.booleanuk.core; + +import com.booleanuk.core.models.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class AccountTest { +/* + @BeforeEach + @Test + public void shouldCreateAccount() { + Customer customer = new Customer("Hanna Håkansson", 1); + Account savings = new Account(customer, 1, branch, AccountType.SAVINGS); + Assertions.assertEquals("Account " + savings.getId()+ " was added to " + customer.getName(), customer.createAccount(savings)); + + } + + @Test + public void shouldDeposit() { + Customer customer = new Customer("Hanna Håkansson", 1); + Account savings = new SavingsAccount(customer, 1); + + double amount = 100; + Assertions.assertEquals(amount +" has been deposited to your account " + savings.getId() , savings.deposit(amount)); + } + @Test + public void shouldWithdrawWithSufficientFunds() { + Customer customer = new Customer("Hanna Håkansson", 1); + Branch branch = new Branch(); + Manager manager = new Manager("Giovanni Capilletti", 1, branch); + Account savings = new Account(customer, 1, branch, AccountType.SAVINGS); + + branch.setManager(manager); + branch.setName("Scranton"); + savings.deposit(1000); + double amount = 1000; + + Assertions.assertEquals(amount +" has been withdrawn from your account "+ savings.getId() , savings.withdraw(amount)); + + savings.deposit(1000); + savings.deposit(7000); + savings.deposit(12); + savings.requestOverdraft(); + + Assertions.assertEquals(1300000.0 +" has been withdrawn from your account "+ savings.getId() , savings.withdraw(1300000)); + + + } + @Test + public void shouldWithdrawWithOverdraft() { + Customer customer = new Customer("Hanna Håkansson", 1); + Branch branch = new Branch(); + Manager manager = new Manager("Giovanni Capilletti", 1, branch); + Account savings = new Account(customer, 1, branch, AccountType.SAVINGS); + + branch.setManager(manager); + branch.setName("Scranton"); + savings.deposit(1000); + double amount = 1000; + + savings.deposit(1000); + savings.deposit(7000); + savings.deposit(12); + savings.requestOverdraft(); + + Assertions.assertEquals(1300000.0 +" has been withdrawn from your account "+ savings.getId() , savings.withdraw(1300000)); + + + } + @Test + public void shouldNotWithdraw() { + Customer customer = new Customer("Hanna Håkansson", 1); + Branch branch = new Branch(); + Manager manager = new Manager("Giovanni Capilletti", 1, branch); + Account savings = new Account(customer, 1, branch, AccountType.SAVINGS); + + + branch.setManager(manager); + branch.setName("Scranton"); + + double amount = 11000; + + Assertions.assertEquals("There are not enough funds on your account.", savings.withdraw(amount)); + } + @Test + public void shouldGenerateBankStatements() { + Customer customer = new Customer("Hanna Håkansson", 1); + Branch branch = new Branch(); + Manager manager = new Manager("Giovanni Capilletti", 1, branch); + Account savings = new Account(customer, 1, branch, AccountType.SAVINGS); + + double amount = 1000; + savings.deposit(amount); + savings.withdraw(amount); + String string = "date\t\t||\tcredit\t||\tdebit\t||\tbalance\n2025-08-20\t||\t\t\t||\t1000.0\t||\t1000.0\n2025-08-20\t||\t1000.0\t\t||\t\t||\t0.0\n"; + + Assertions.assertEquals(string, savings.generateBankStatements()); + } + @Test + public void shouldCalculateBalance() { + Customer customer = new Customer("Hanna Håkansson", 1); + Branch branch = new Branch(); + Manager manager = new Manager("Giovanni Capilletti", 1, branch); + Account savings = new Account(customer, 1, branch, AccountType.SAVINGS); + + double amount = 100.0; + savings.deposit(amount); + savings.deposit(amount); + savings.deposit(amount); + savings.withdraw(amount); + Assertions.assertEquals(200.0, savings.calculateBalance()); + } +*/ + + + +}