Java Console Vending Machine App
-
application - holds the functionality for navigating menu options
-
exceptions - holds custom exceptions
-
io - holds user input and output for both Java console and files
- logs - holds functionality for creating timestamped logs
- report - holds functionality for reading and generating a persistent sales report CSV file
- ui - user input and output seperated into designated classes
-
models - contains a product model used for creating product objects from CSV file information
-
services - contains functionality for generating inventory list and completing user transactions
-
validators - contain functionality for checking the validity of user input
-
view - holds functionality for manipulating Java console display
After choosing to browse the vending machine (and thus start a new transaction), the available funds are displayed over the transaction menu. Adding money updates the funds available.
Inventory display includes item cost and current stock. The display is formatted such that product categories display evenly for easier visability.
for (Product product : productList) {
String id = product.getSlotID();
String name = product.getName() + "*";
String nameNoSpaces = name.replace(' ', '*');
String formattedName = String.format("%-20s", nameNoSpaces)
.replace(' ', '-')
.replace('*', ' ');
BigDecimal price = product.getPrice();
int quantity = product.getQuantity();
if (quantity == 0) UserOutput.displayProductSoldOut(id, formattedName, price);
else UserOutput.displayProductWithStock(id, formattedName, price, quantity);
}
Selecting a product prompts a dispensing loading bar and purchased item to display, updates current stock of item, and updates current funds. Item stock persists between transactions.
if (selection == null) throw new Exception("Selection is null");
else if (!Validator.isInStock(selection)) {
throw new InsufficientStockException("This item is out of stock", selection.getQuantity());
} else if (!Validator.hasEnoughMoney(selection, remainingFunds)) {
throw new InsufficientFundsException("Insufficient funds", getRemainingFunds(), selection.getPrice());
} else { // selected item found in menu, item is in stock, and user has enough money to purchase item
Inventory.updateInventory(selection, ITEM_QUANTITY_PER_SELECTION); // update inventory
updatePurchases(selection); // add item to list of user purchases for this transaction
spendMoney(selection); // subtract item cost from availabe funds
SalesReport.update(selection); // add purchase to sales report in memory
String type = selection.getType();
String name = selection.getName();
String id = selection.getSlotID();
BigDecimal price = selection.getPrice();
// use values from getter functions to create an entry in the transaction log
TransactionLog.createLogEntry(name + " " + id + " " + price + " " + remainingFunds);
// display loading bar, item purchased, and a purchase success message to the user
LoadingBar.displayLoadingBar();
userOutput.displayPurchaseSuccess(name);
userOutput.displayItemTypeReturnMessage(type);
}
Finishing the transaction promps a list of items purchased and change dispensed to display along with a thank you message
public Map<Product, Integer> finishTransaction() {
UserOutput.displaySummaryIntro();
getItemSummary(productsPurchased);
returnChange(remainingFunds);
// ...
}
public void getItemSummary(Map<Product, Integer> productsPurchased) {
for (Map.Entry<Product, Integer> product: productsPurchased.entrySet()) {
String productName = product.getKey().getName();
String amountPurchased = product.getValue().toString();
UserOutput.displayItemSummary(productName, amountPurchased);
}
}
public void returnChange(BigDecimal remainingFunds) {
int remaining = remainingFunds.multiply(new BigDecimal("100")).intValue();
// set constants QUARTER, DIME, NICKEL
int quartersReturned = remaining / QUARTER;
int lessQuarters = remaining % QUARTER;
int dimesReturned = lessQuarters / DIME;
int lessDimes = lessQuarters % DIME;
int nicklesReturned = lessDimes / NICKEL;
UserOutput.displayChange(quartersReturned, dimesReturned, nicklesReturned);
}
Program has custom exceptions for insufficient funds, invalid funds, invalid selection, and insufficient stock.
// if user enters $1, $5, $10, or $20 add money, otherwise throw Invalid Funds Exception
try {
transaction.addMoney(userFunds);
} catch (InvalidFundsException ex) {
// display error message for user and write exception to log file
}
try {
userOutput.displayEnterProduct();
String productSelection = userInput.getSelection();
transaction.purchaseItem(productSelection);
// if exception, display error message for user and write exception to log file
} catch (InvalidOptionException ex) { // ... if user does not enter a valid product code
} catch (InsufficientStockException ex) { // ... if user tries to purchase an item that's out of stock
} catch (InsufficientFundsException ex) { // ... if user does not have enough money to purchase item
} catch (Exception ex) { // generic exception
Logger.createLogEntry(ex.getMessage());
}
-
A hidden menu option displays a current sales report
-
An up-to-date sales report is written to a CSV file whenever the hidden menu option is called or the user selects the option to exit the program.
-
When the program is next run, the information from the CSV file is read and stored in memory until a new sales report is printed to overwrite the old file.
-
Another hidden menu option promps the vending machine to dispense all remaining products for free
public static void kickTheVendingMachine() { for (Product product : productList) product.setQuantity(0); }