From d181deb4f87f38c178c7f12a4c5e6c2b24c50f00 Mon Sep 17 00:00:00 2001 From: Yafiaha Date: Wed, 6 Nov 2024 09:35:23 -0500 Subject: [PATCH 1/2] Feat : Lesson-17 SavingsAccount & BusinessCheckingAccount --- .../bank/BusinessCheckingAccount.java | 16 +++ .../lesson17/bank/Customer.java | 9 +- .../lesson17/bank/CustomerType.java | 6 + .../lesson17/bank/SavingsAccount.java | 106 ++++++++++++++++++ .../lesson17/bank/BankAtmTest.java | 6 +- .../lesson17/bank/CheckingAccountTest.java | 4 +- .../lesson17/bank/SavingsAccountTest.java | 106 ++++++++++++++++++ 7 files changed, 247 insertions(+), 6 deletions(-) create mode 100644 lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BusinessCheckingAccount.java create mode 100644 lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CustomerType.java create mode 100644 lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java create mode 100644 lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BusinessCheckingAccount.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BusinessCheckingAccount.java new file mode 100644 index 000000000..8d109fd6a --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BusinessCheckingAccount.java @@ -0,0 +1,16 @@ +package com.codedifferently.lesson17.bank; + +import java.util.Set; + +public class BusinessCheckingAccount extends CheckingAccount { + + public BusinessCheckingAccount( + String accountNumber, Set owners, double initialBalance) { + super(accountNumber, owners, initialBalance); // Call to Account's constructor + + if (owners.stream().noneMatch(Customer::isBusiness)) { + throw new IllegalArgumentException( + "A BusinessCheckingAccount must have at least one business owner."); + } + } +} diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Customer.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Customer.java index af0847134..4586d851c 100644 --- a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Customer.java +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Customer.java @@ -9,6 +9,7 @@ public class Customer { private final UUID id; private final String name; + private final CustomerType type; private final Set accounts = new HashSet<>(); /** @@ -17,9 +18,10 @@ public class Customer { * @param id The ID of the customer. * @param name The name of the customer. */ - public Customer(UUID id, String name) { + public Customer(UUID id, String name, CustomerType type) { this.id = id; this.name = name; + this.type = type; } /** @@ -58,6 +60,11 @@ public Set getAccounts() { return accounts; } + // make sure if the custumer is using a business account + public boolean isBusiness() { + return type == CustomerType.BUSINESS; + } + @Override public int hashCode() { return id.hashCode(); diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CustomerType.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CustomerType.java new file mode 100644 index 000000000..30f05a33c --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/CustomerType.java @@ -0,0 +1,6 @@ +package com.codedifferently.lesson17.bank; + +public enum CustomerType { + INDIVIDUAL, + BUSINESS +} diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java new file mode 100644 index 000000000..d836af3ca --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java @@ -0,0 +1,106 @@ +package com.codedifferently.lesson17.bank; + +import com.codedifferently.lesson17.bank.exceptions.InsufficientFundsException; +import java.util.Set; + +// represent a savings account +public class SavingsAccount { + + private final Set owners; + private final String accountNumber; + private double balance; + private boolean isActive; + + // consturcter of saving account + public SavingsAccount(String accountNumber, Set owners, double initialBalance) { + this.accountNumber = accountNumber; + this.owners = owners; + this.balance = initialBalance; + isActive = true; + } + + // getters & setters + public String getAccountNumber() { + return accountNumber; + } + + public Set getOwners() { + return owners; + } + + public double getBalance() { + return balance; + } + + public boolean isClosed() { + return !isActive; + } + + /** + * Deposits funds into the account. + * + * @param amount The amount to deposit. + */ + public void deposit(double amount) throws IllegalStateException { + if (isClosed()) { + throw new IllegalStateException("Cannot deposit to a closed account"); + } + if (amount <= 0) { + throw new IllegalArgumentException("Deposit amount must be positive"); + } + balance += amount; + } + + /** + * Withdraws funds from the account. + * + * @param amount + * @throws InsufficientFundsException + */ + public void withdraw(double amount) throws InsufficientFundsException { + if (isClosed()) { + throw new IllegalStateException("Cannot withdraw from a closed account"); + } + if (amount <= 0) { + throw new IllegalStateException("Withdrawal amount must be positive"); + } + if (balance < amount) { + throw new InsufficientFundsException("Account does not have enough funds for withdrawal"); + } + balance -= amount; + } + + /** Closes the account. */ + public void closeAccount() throws IllegalStateException { + if (balance > 0) { + throw new IllegalStateException("Cannot close account with a positive balance"); + } + isActive = false; + } + + @Override + public int hashCode() { + return accountNumber.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SavingsAccount other) { + return accountNumber.equals(other.accountNumber); + } + return false; + } + + @Override + public String toString() { + return "SavingsAccount{" + + "accountNumber='" + + accountNumber + + '\'' + + ", balance=" + + balance + + ", isActive=" + + isActive + + '}'; + } +} diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java index fa4a913a2..4953d17c3 100644 --- a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java @@ -21,8 +21,8 @@ class BankAtmTest { @BeforeEach void setUp() { classUnderTest = new BankAtm(); - customer1 = new Customer(UUID.randomUUID(), "John Doe"); - customer2 = new Customer(UUID.randomUUID(), "Jane Smith"); + customer1 = new Customer(UUID.randomUUID(), "John Doe", CustomerType.INDIVIDUAL); + customer2 = new Customer(UUID.randomUUID(), "Jane Smith", CustomerType.INDIVIDUAL); account1 = new CheckingAccount("123456789", Set.of(customer1), 100.0); account2 = new CheckingAccount("987654321", Set.of(customer1, customer2), 200.0); customer1.addAccount(account1); @@ -35,7 +35,7 @@ void setUp() { @Test void testAddAccount() { // Arrange - Customer customer3 = new Customer(UUID.randomUUID(), "Alice Johnson"); + Customer customer3 = new Customer(UUID.randomUUID(), "Alice Johnson", CustomerType.INDIVIDUAL); CheckingAccount account3 = new CheckingAccount("555555555", Set.of(customer3), 300.0); customer3.addAccount(account3); diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckingAccountTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckingAccountTest.java index f155d8e5b..3b6f00af4 100644 --- a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckingAccountTest.java +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckingAccountTest.java @@ -20,8 +20,8 @@ class CheckingAccountTest { @BeforeEach void setUp() { owners = new HashSet<>(); - owners.add(new Customer(UUID.randomUUID(), "John Doe")); - owners.add(new Customer(UUID.randomUUID(), "Jane Smith")); + owners.add(new Customer(UUID.randomUUID(), "John Doe", CustomerType.INDIVIDUAL)); + owners.add(new Customer(UUID.randomUUID(), "Jane Smith", CustomerType.INDIVIDUAL)); classUnderTest = new CheckingAccount("123456789", owners, 100.0); } diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java new file mode 100644 index 000000000..46ddf1bf5 --- /dev/null +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java @@ -0,0 +1,106 @@ +package com.codedifferently.lesson17.bank; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.codedifferently.lesson17.bank.exceptions.InsufficientFundsException; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SavingsAccountTest { + + private SavingsAccount classUnderTest; + private Set owners; + + @BeforeEach + void setUp() { + owners = new HashSet<>(); + owners.add(new Customer(UUID.randomUUID(), "John Doe", CustomerType.INDIVIDUAL)); + owners.add(new Customer(UUID.randomUUID(), "Jane Smith", CustomerType.INDIVIDUAL)); + classUnderTest = new SavingsAccount("123456789", owners, 100.0); + } + + @Test + void getAccountNumber() { + assertEquals("123456789", classUnderTest.getAccountNumber()); + } + + @Test + void getOwners() { + assertEquals(owners, classUnderTest.getOwners()); + } + + @Test + void deposit() { + classUnderTest.deposit(50.0); + assertEquals(150.0, classUnderTest.getBalance()); + } + + @Test + void deposit_withNegativeAmount() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> classUnderTest.deposit(-50.0)); + } + + @Test + void withdraw() { + classUnderTest.withdraw(50.0); + assertEquals(50.0, classUnderTest.getBalance()); + } + + @Test + void withdraw_withNegativeAmount() { + assertThatExceptionOfType(IllegalStateException.class) + .isThrownBy(() -> classUnderTest.withdraw(-50.0)) + .withMessage("Withdrawal amount must be positive"); + } + + @Test + void withdraw_withInsufficientBalance() { + assertThatExceptionOfType(InsufficientFundsException.class) + .isThrownBy(() -> classUnderTest.withdraw(150.0)) + .withMessage("Account does not have enough funds for withdrawal"); + } + + @Test + void getBalance() { + assertEquals(100.0, classUnderTest.getBalance()); + } + + @Test + void closeAccount_withPositiveBalance() { + assertThatExceptionOfType(IllegalStateException.class) + .isThrownBy(() -> classUnderTest.closeAccount()); + } + + @Test + void isClosed() { + assertFalse(classUnderTest.isClosed()); + classUnderTest.withdraw(100); + classUnderTest.closeAccount(); + assertTrue(classUnderTest.isClosed()); + } + + @Test + void equals() { + SavingsAccount otherAccount = new SavingsAccount("123456789", owners, 200.0); + assertEquals(classUnderTest, otherAccount); + } + + @Test + void hashCodeTest() { + SavingsAccount otherAccount = new SavingsAccount("123456789", owners, 200.0); + assertEquals(classUnderTest.hashCode(), otherAccount.hashCode()); + } + + @Test + void toStringTest() { + String expected = "SavingsAccount{accountNumber='123456789', balance=100.0, isActive=true}"; + assertEquals(expected, classUnderTest.toString()); + } +} From f3c2ca6b4fef1a72bbf614231f3e7e603ff72fb1 Mon Sep 17 00:00:00 2001 From: Yafiaha Date: Wed, 6 Nov 2024 09:35:54 -0500 Subject: [PATCH 2/2] Feat: BankATM & BankAtmTest --- .../lesson17/bank/BankAtm.java | 20 +++++++++----- .../lesson17/bank/BankAtmTest.java | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BankAtm.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BankAtm.java index 8cbcd3cc0..df46cdfc5 100644 --- a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BankAtm.java +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BankAtm.java @@ -18,13 +18,21 @@ public class BankAtm { * @param account The account to add. */ public void addAccount(CheckingAccount account) { + if (account instanceof BusinessCheckingAccount) { + Set owners = account.getOwners(); + + // Ensure at least one owner is a business + if (owners.stream().noneMatch(Customer::isBusiness)) { + throw new IllegalArgumentException( + "A BusinessCheckingAccount must have at least one business owner."); + } + } + + // Add the account to accountByNumber accountByNumber.put(account.getAccountNumber(), account); - account - .getOwners() - .forEach( - owner -> { - customerById.put(owner.getId(), owner); - }); + + // Add each owner to customerById + account.getOwners().forEach(owner -> customerById.put(owner.getId(), owner)); } /** diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java index 4953d17c3..d5bdd7c2f 100644 --- a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BankAtmTest.java @@ -107,4 +107,31 @@ void testWithdrawFunds_AccountNotFound() { .isThrownBy(() -> classUnderTest.withdrawFunds(nonExistingAccountNumber, 50.0)) .withMessage("Account not found"); } + + @Test + void testAddBusinessCheckingAccount_WithBusinessOwner() { + // Arrange + Customer businessCustomer = new Customer(UUID.randomUUID(), "TechCorp", CustomerType.BUSINESS); + Set owners = Set.of(businessCustomer); + + // Act + BusinessCheckingAccount businessAccount = + new BusinessCheckingAccount("BUS123456", owners, 500.0); + + // Assert + assertThat(businessAccount.getOwners()).contains(businessCustomer); + } + + @Test + void testAddBusinessCheckingAccount_WithoutBusinessOwner() { + // Arrange + Customer individualCustomer = + new Customer(UUID.randomUUID(), "John Doe", CustomerType.INDIVIDUAL); + Set owners = Set.of(individualCustomer); + + // Act & Assert + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new BusinessCheckingAccount("BUS987654", owners, 1000.0)) + .withMessage("A BusinessCheckingAccount must have at least one business owner."); + } }