Skip to content

feat: Implement Banking System Features and Tests #542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.codedifferently.lesson17.bank;

import java.util.ArrayList;
import java.util.List;

/**
* Records audit logs for account-related actions. This class maintains a list of log entries for
* tracking account additions.
*/
public class AuditLog {

// List to hold log entries
private final List<String> logEntries = new ArrayList<>();

/**
* Logs the addition of a new account by recording its account number.
*
* @param accountNumber The account number of the newly added account.
*/
public void logAccountAddition(String accountNumber) {
logEntries.add("Account added: " + accountNumber);
}

/**
* Retrieves all log entries recorded in the audit log.
*
* @return A new list containing all log entries.
*/
public List<String> getLogEntries() {
// Return a copy of the log entries to prevent external modification
return new ArrayList<>(logEntries);
}

/**
* Retrieves the last log entry recorded in the audit log.
*
* @return The most recent log entry as a String, or null if there are no entries.
*/
public String getLastEntry() {
// Check if the log is empty and return null if so
if (logEntries.isEmpty()) {
return null; // Or throw an exception if preferred
}
// Return the last log entry
return logEntries.get(logEntries.size() - 1);
}
}
Original file line number Diff line number Diff line change
@@ -1,88 +1,158 @@
package com.codedifferently.lesson17.bank;

import com.codedifferently.lesson17.bank.exceptions.AccountNotFoundException;
import java.util.Currency;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/** Represents a bank ATM. */
/**
* Represents a bank ATM that manages customer accounts and transactions. This class handles account
* management, deposits, withdrawals, and logging actions.
*/
public class BankAtm {

// Map to store customers by their unique ID
private final Map<UUID, Customer> customerById = new HashMap<>();

// Map to store checking accounts by their account number
private final Map<String, CheckingAccount> accountByNumber = new HashMap<>();

// Audit log to record account-related actions
private final AuditLog auditLog = new AuditLog();

/**
* Adds a checking account to the bank.
* Adds a checking account to the bank's records.
*
* @param account The account to add.
* @param account The CheckingAccount to add.
*/
public void addAccount(CheckingAccount account) {
// Add the account to the account map using its account number
accountByNumber.put(account.getAccountNumber(), account);

// Register each owner of the account in the customer map
account
.getOwners()
.forEach(
owner -> {
customerById.put(owner.getId(), owner);
});

// Log the account addition in the audit log
auditLog.logAccountAddition(account.getAccountNumber());
}

/**
* Finds all accounts owned by a customer.
* Finds all accounts owned by a specific customer.
*
* @param customerId The ID of the customer.
* @return The unique set of accounts owned by the customer.
* @param customerId The ID of the customer whose accounts are to be found.
* @return A unique set of CheckingAccounts owned by the customer, or an empty set if none are
* found.
*/
public Set<CheckingAccount> findAccountsByCustomerId(UUID customerId) {
return customerById.containsKey(customerId)
? customerById.get(customerId).getAccounts()
: Set.of();
: Set.of(); // Return an empty set if the customer does not exist
}

/**
* Deposits funds into an account.
* Deposits a specified amount of funds into an account.
*
* @param accountNumber The account number.
* @param amount The amount to deposit.
* @param accountNumber The account number to deposit into.
* @param amount The amount of money to deposit.
*/
public void depositFunds(String accountNumber, double amount) {
// Retrieve the account or throw an exception if not found
CheckingAccount account = getAccountOrThrow(accountNumber);
account.deposit(amount);
account.deposit(amount); // Deposit the amount into the account
}

/**
* Deposits funds into an account using a check.
*
* @param accountNumber The account number.
* @param check The check to deposit.
* @param accountNumber The account number to deposit into.
* @param check The Check object representing the check to be deposited.
*/
public void depositFunds(String accountNumber, Check check) {
// Retrieve the account or throw an exception if not found
CheckingAccount account = getAccountOrThrow(accountNumber);
check.depositFunds(account);
check.depositFunds(account); // Process the check and deposit funds into the account
}

/**
* Deposits funds into an account while converting from a specified currency.
*
* @param accountNumber The account number to deposit into.
* @param amount The amount to deposit.
* @param currency The currency of the deposit amount.
*/
public void depositFunds(String accountNumber, double amount, Currency currency) {
// Retrieve the account or throw an exception if not found
CheckingAccount account = getAccountOrThrow(accountNumber);

// Validate the provided currency
if (currency == null || !isValidCurrency(currency)) {
throw new IllegalArgumentException("Invalid currency provided");
}

// Convert the amount to the account's currency (assuming USD for this example)
Currency accountCurrency =
Currency.getInstance("USD"); // Replace with actual account currency if necessary
double convertedAmount = CurrencyConverter.convert(amount, currency, accountCurrency);

account.deposit(convertedAmount); // Deposit the converted amount into the account
}

/**
* Checks if the provided currency is valid.
*
* @param currency The currency to validate.
* @return true if the currency is valid; false otherwise.
*/
private boolean isValidCurrency(Currency currency) {
// Define valid currencies
return currency.getCurrencyCode().equals("USD")
|| currency.getCurrencyCode().equals("GBP")
|| currency.getCurrencyCode().equals("CAD")
|| currency.getCurrencyCode().equals("EUR");
}

/**
* Retrieves all entries from the audit log.
*
* @return A list of log entries recorded in the audit log.
*/
public List<String> getAuditLogEntries() {
return auditLog.getLogEntries(); // Return the audit log entries
}

/**
* Withdraws funds from an account.
* Withdraws a specified amount of funds from an account.
*
* @param accountNumber
* @param amount
* @param accountNumber The account number to withdraw from.
* @param amount The amount of money to withdraw.
*/
public void withdrawFunds(String accountNumber, double amount) {
// Retrieve the account or throw an exception if not found
CheckingAccount account = getAccountOrThrow(accountNumber);
account.withdraw(amount);
account.withdraw(amount); // Withdraw the specified amount from the account
}

/**
* Gets an account by its number or throws an exception if not found.
* Retrieves an account by its account number, throwing an exception if not found.
*
* @param accountNumber The account number.
* @return The account.
* @param accountNumber The account number to search for.
* @return The CheckingAccount associated with the given account number.
* @throws AccountNotFoundException if the account is not found or is closed.
*/
private CheckingAccount getAccountOrThrow(String accountNumber) {
CheckingAccount account = accountByNumber.get(accountNumber);
// Check if the account is found and is not closed
if (account == null || account.isClosed()) {
throw new AccountNotFoundException("Account not found");
}
return account;
return account; // Return the found account
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.codedifferently.lesson17.bank;

import java.util.Set;

/**
* Represents a business checking account, which is a specialized type of checking account. This
* account must have at least one owner designated as a business.
*/
public class BusinessCheckingAccount extends CheckingAccount {

/**
* Creates a new BusinessCheckingAccount with the specified account number, owners, and initial
* balance.
*
* @param accountNumber The account number for the business checking account.
* @param owners A set of Customer objects representing the owners of the account.
* @param initialBalance The initial balance to set for the account.
* @throws IllegalArgumentException if no owner is designated as a business.
*/
public BusinessCheckingAccount(
String accountNumber, Set<Customer> owners, double initialBalance) {
super(
accountNumber,
owners,
initialBalance); // Call the superclass constructor to initialize common fields

// Ensure that at least one owner is a business customer
if (!owners.stream().anyMatch(Customer::isBusiness)) {
throw new IllegalArgumentException("At least one owner must be a business");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,80 @@

import com.codedifferently.lesson17.bank.exceptions.CheckVoidedException;

/** Represents a check. */
/**
* Represents a check that can be deposited into a checking account. A check has a number, an
* amount, and is associated with a checking account.
*/
public class Check {

// The unique identifier for the check
private final String checkNumber;

// The amount specified on the check
private final double amount;

// The checking account that the check is drawn from
private final CheckingAccount account;

// Indicates whether the check has been voided
private boolean isVoided = false;

/**
* Creates a new check.
* Creates a new check with the specified check number, amount, and associated account.
*
* @param checkNumber The check number.
* @param amount The amount of the check.
* @param account The account the check is drawn on.
* @param amount The amount of the check (must be positive).
* @param account The checking account the check is drawn on.
* @throws IllegalArgumentException if the amount is negative.
*/
public Check(String checkNumber, double amount, CheckingAccount account) {
if (amount < 0) {
throw new IllegalArgumentException("Check amount must be positive");
throw new IllegalArgumentException(
"Check amount must be positive"); // Validate the check amount
}
this.checkNumber = checkNumber;
this.amount = amount;
this.account = account;
this.account = account; // Assign the associated checking account
}

/**
* Gets the voided status of the check.
*
* @return True if the check is voided, and false otherwise.
* @return True if the check is voided; false otherwise.
*/
public boolean getIsVoided() {
return isVoided;
return isVoided; // Return the voided status
}

/** Voids the check. */
/** Voids the check, preventing it from being deposited. */
public void voidCheck() {
isVoided = true;
isVoided = true; // Set the voided status to true
}

/**
* Deposits the check into an account.
* Deposits the check into the specified account.
*
* @param toAccount The account to deposit the check into.
* @throws CheckVoidedException if the check is voided.
*/
public void depositFunds(CheckingAccount toAccount) {
if (isVoided) {
throw new CheckVoidedException("Check is voided");
throw new CheckVoidedException("Check is voided"); // Check if the check is voided
}
account.withdraw(amount);
toAccount.deposit(amount);
voidCheck();
account.withdraw(amount); // Withdraw the amount from the original account
toAccount.deposit(amount); // Deposit the amount into the specified account
voidCheck(); // Void the check after successful deposit
}

@Override
public int hashCode() {
return checkNumber.hashCode();
return checkNumber.hashCode(); // Generate hash code based on the check number
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Check other) {
return checkNumber.equals(other.checkNumber);
return checkNumber.equals(other.checkNumber); // Check equality based on the check number
}
return false;
}
Expand All @@ -77,6 +90,6 @@ public String toString() {
+ amount
+ ", account="
+ account.getAccountNumber()
+ '}';
+ '}'; // Return a string representation of the check
}
}
Loading