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..25e481ded 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 @@ -58,17 +58,28 @@ public void depositFunds(String accountNumber, double amount) { */ public void depositFunds(String accountNumber, Check check) { CheckingAccount account = getAccountOrThrow(accountNumber); + if ((account instanceof SavingsAccount)) { + throw new IllegalArgumentException("Only checking accounts can make checks"); + } check.depositFunds(account); } /** - * Withdraws funds from an account. + * Withdraws funds from a specified account. * - * @param accountNumber - * @param amount + * @param accountNumber The unique identifier of the account. + * @param amount The amount to withdraw from the account. + * @throws IllegalArgumentException if the account is not found or if the withdrawal would result + * in a balance below $10,000 for a BusinessCheckingAccount. */ public void withdrawFunds(String accountNumber, double amount) { CheckingAccount account = getAccountOrThrow(accountNumber); + if ((account instanceof BusinessCheckingAccount)) { + if (account.getBalance() - amount < 10000) { + throw new IllegalArgumentException( + "Business checking account balance must remain greater than $10,000"); + } + } account.withdraw(amount); } 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..0f35bb23c --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/BusinessCheckingAccount.java @@ -0,0 +1,53 @@ +package com.codedifferently.lesson17.bank; + +import java.util.Set; + +public class BusinessCheckingAccount extends CheckingAccount { + + /** + * Creates a new BusinessCheckingAccount with the specified account number, owners, and initial + * balance. + * + *

This constructor ensures that the account meets the minimum requirements for a business + * checking account, including a minimum initial balance of $10,000 and at least one business + * owner in the provided set of owners. If these requirements are not met, an {@link + * IllegalArgumentException} is thrown. + * + * @param accountNumber The unique identifier for the account. + * @param owners A set of {@link Customer} objects representing the owners of the account. + * @param initialBalance The initial balance of the account, which must be at least $10,000. + * @throws IllegalArgumentException If the initial balance is less than $10,000 or if none of the + * owners meet the criteria to be considered a business owner. + */ + public BusinessCheckingAccount( + String accountNumber, Set owners, double initialBalance) { + super(accountNumber, owners, initialBalance); + + // Business Account Logic + if (initialBalance < 10000) { + throw new IllegalArgumentException("Business accounts require a minimum balance of $10,000."); + } + if (!hasBusinessOwner(owners)) { + throw new IllegalArgumentException( + "A business checking account must have at least one business owner."); + } + } + + /** + * Checks if at least one owner of the account is a business. + * + *

This method examines each owner in the "owners" set and returns true if any owner's name + * contains "INC" or "LLC" (case-insensitive), which are used as indicators of a business owning + * the account. + * + * @param owners The set of account owners to check. + * @return true if the account has at least one business owner; false otherwise. + */ + public boolean hasBusinessOwner(Set owners) { + return getOwners().stream() + .anyMatch( + owner -> + owner.getName().toUpperCase().contains("INC") + || owner.getName().toUpperCase().contains("LLC")); + } +} diff --git a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Check.java b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Check.java index 061fa4a5c..74814a69e 100644 --- a/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Check.java +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/Check.java @@ -16,8 +16,13 @@ public class Check { * @param checkNumber The check number. * @param amount The amount of the check. * @param account The account the check is drawn on. + * @throws IllegalArgumentException if the amount is negative or the account is not a + * `CheckingAccount` or `BusinessCheckingAccount` instance. */ public Check(String checkNumber, double amount, CheckingAccount account) { + if ((account instanceof SavingsAccount)) { + throw new IllegalArgumentException("Only checking accounts can make checks"); + } if (amount < 0) { throw new IllegalArgumentException("Check amount must be positive"); } 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..266f8fdc1 --- /dev/null +++ b/lesson_17/bank/bank_app/src/main/java/com/codedifferently/lesson17/bank/SavingsAccount.java @@ -0,0 +1,10 @@ +package com.codedifferently.lesson17.bank; + +import java.util.Set; + +public class SavingsAccount extends CheckingAccount { + + public SavingsAccount(String accountNumber, Set owners, double initialBalance) { + super(accountNumber, owners, initialBalance); + } +} 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..eb2774265 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 @@ -15,21 +15,26 @@ class BankAtmTest { private BankAtm classUnderTest; private CheckingAccount account1; private CheckingAccount account2; + private BusinessCheckingAccount account3; private Customer customer1; private Customer customer2; + private Customer customer3; @BeforeEach void setUp() { classUnderTest = new BankAtm(); customer1 = new Customer(UUID.randomUUID(), "John Doe"); customer2 = new Customer(UUID.randomUUID(), "Jane Smith"); + customer3 = new Customer(UUID.randomUUID(), "Doodle-Bob INC."); account1 = new CheckingAccount("123456789", Set.of(customer1), 100.0); account2 = new CheckingAccount("987654321", Set.of(customer1, customer2), 200.0); + account3 = new BusinessCheckingAccount("102938475", Set.of(customer3), 10000.0); customer1.addAccount(account1); customer1.addAccount(account2); customer2.addAccount(account2); classUnderTest.addAccount(account1); classUnderTest.addAccount(account2); + classUnderTest.addAccount(account3); } @Test @@ -107,4 +112,11 @@ void testWithdrawFunds_AccountNotFound() { .isThrownBy(() -> classUnderTest.withdrawFunds(nonExistingAccountNumber, 50.0)) .withMessage("Account not found"); } + + @Test + void testWithdrawFunds_BusinessAccountBalanceBelowMinimum() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> classUnderTest.withdrawFunds(account3.getAccountNumber(), 200.0)) + .withMessage("Business checking account balance must remain greater than $10,000"); + } } diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BusinessCheckingAccountTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BusinessCheckingAccountTest.java new file mode 100644 index 000000000..e3bc9e154 --- /dev/null +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/BusinessCheckingAccountTest.java @@ -0,0 +1,79 @@ +package com.codedifferently.lesson17.bank; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +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 BusinessCheckingAccountTest { + private Set owners; + + @BeforeEach + public void setUp() { + owners = new HashSet<>(); + } + + @Test + public void testBusinessCheckingAccount_HasBusinessOwner_WithIncInName() { + UUID id = UUID.randomUUID(); + Customer businesserOwner = new Customer(id, "Bob INC."); + + owners.add(businesserOwner); + + BusinessCheckingAccount account = new BusinessCheckingAccount("12345", owners, 15000); + assertNotNull(account); + assertEquals(15000, account.getBalance()); + assertEquals("12345", account.getAccountNumber()); + } + + @Test + public void testBusinessCheckingAccount_HasBusinessOwner_WithLlcInName() { + UUID id = UUID.randomUUID(); + Customer businesserOwner = new Customer(id, "Bob LLC."); + + owners.add(businesserOwner); + + BusinessCheckingAccount account = new BusinessCheckingAccount("12345", owners, 15000); + assertNotNull(account); + assertEquals(15000, account.getBalance()); + assertEquals("12345", account.getAccountNumber()); + } + + @Test + public void testBusinessCheckingAccount_WithoutBusinessOwner() { + UUID individualId = UUID.randomUUID(); + Customer individualOwner = + new Customer(individualId, "John Doe"); // Example customer without business designation + + owners.add(individualOwner); // Add the individual owner to the set + + assertThatThrownBy( + () -> { + new BusinessCheckingAccount("12345", owners, 15000); + }) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("A business checking account must have at least one business owner."); + } + + @Test + public void testBusinessCheckingAccount_BelowMinimumBalance() { + UUID businessId = UUID.randomUUID(); + Customer businessOwner = + new Customer(businessId, "ABC LLC"); // Create a customer with a valid business name + + owners.add(businessOwner); // Add the business owner to the set + + assertThatThrownBy( + () -> { + new BusinessCheckingAccount( + "12345", owners, 5000); // Attempt to create with a balance below 10,000 + }) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Business accounts require a minimum balance of $10,000."); + } +} diff --git a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckTest.java b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckTest.java index 6b62d39ba..280bc2176 100644 --- a/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckTest.java +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/CheckTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import com.codedifferently.lesson17.bank.exceptions.CheckVoidedException; import org.junit.jupiter.api.BeforeEach; @@ -49,6 +51,18 @@ void testConstructor_CantCreateCheckWithNegativeAmount() { .withMessage("Check amount must be positive"); } + @Test + void testConstructor_CantCreateCheckWithSavingsAccount() { + SavingsAccount savingsAccount = new SavingsAccount("12345", null, 500.0); + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> { + new Check("123", 100, savingsAccount); + }); + assertEquals("Only checking accounts can make checks", exception.getMessage()); + } + @Test void testHashCode() { // Arrange 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..81f0d7fec --- /dev/null +++ b/lesson_17/bank/bank_app/src/test/java/com/codedifferently/lesson17/bank/SavingsAccountTest.java @@ -0,0 +1,18 @@ +package com.codedifferently.lesson17.bank; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; + +public class SavingsAccountTest { + private SavingsAccount savingsAccount; + private Set owners; + + @BeforeEach + void setUp() { + owners = new HashSet<>(); + owners.add(new Customer(UUID.randomUUID(), "Bob Smith")); + savingsAccount = new SavingsAccount("12345", owners, 500); + } +}