import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;
public class App {
private static final String AvailableFruitsHeader = "Available Fruits: ";
private static final String AvailableFruitsTemplate = "%s. %s (%s)";
private static final String EnterFruitCodeLabel = "Enter fruit code: ";
private static final String EnterQtyLabel = "Qty: ";
private static final String EnterDiscountLabel = "Discount: ";
private static final String FruitQtyTotalTemplate = "%s %s @ %s";
private static final String KeyValTemplate = "%s : %s";
private static final String VatLabel = "VAT(12%)";
private static final String TotalLabel = "Total";
private static final String CashLabel = "Cash: ";
private static final String ChangeLabel = "Change";
private static final String NextCustomerLabel = "Next Customer[y/n]: ";
private static final String InvalidInput = "Invalid input please try again!";
private static final String InvalidCashInput = "Invalid cash please try again!";
private static final BigDecimal twelvePercentVat = new BigDecimal("0.12");
public static void printer(String text, boolean newLine) {
if (newLine) {
System.out.println(text);
} else {
System.out.print(text);
}
}
public static void main(String[] args) {
// init scanner
final Scanner scanner = new Scanner(System.in);
// init fruits
final Fruit apple = new Fruit("Apple", new BigDecimal("15.75"), "a");
final Fruit banana = new Fruit("Banana", new BigDecimal("19.75"), "b");
final Fruit chico = new Fruit("Chico", new BigDecimal("5.95"), "c");
final Fruit durian = new Fruit("Durian", new BigDecimal("152.35"), "d");
// init list of fruit, initially empty
final List<Fruit> fruits = new ArrayList<>();
//add apple to list
fruits.add(apple);
//add banana to list
fruits.add(banana);
//add chico to list
fruits.add(chico);
//add durian to list
fruits.add(durian);
//initialize isNextCustomer true by default
boolean isNextCustomer = true;
// loop for customer
do {
//available fruits
printer(AvailableFruitsHeader, true);
//print all fruits
for (final Fruit fruit : fruits) {
printer(String.format(AvailableFruitsTemplate,
fruit.getCode(), fruit.getName(), fruit.getPrice()), true);
}
//enter fruit code
final String code = getInputText(scanner, EnterFruitCodeLabel);
// get fruit by entered code
final Fruit pickedFruit = getFruit(fruits, code);
// check if not null
if (pickedFruit != null) {
// enter quantity
final Long qty = getInputBigDecimal(scanner, EnterQtyLabel).longValue();
// compute sum by retrieved fruit(pickedFruit) price and entered quantity
final BigDecimal sum = computeSum(pickedFruit.getPrice(), qty);
final String fruitTotalTemplate = String.format(FruitQtyTotalTemplate,
pickedFruit.getName(),
pickedFruit.getPrice(),
qty);
// print(fruitTotalTemplate) <fruit name> <fruit price> @ <qty> : <sum>
printer(String.format(KeyValTemplate, fruitTotalTemplate, sum), true);
// enter discount
final BigDecimal discount = getInputBigDecimal(scanner, EnterDiscountLabel);
// compute vat
final BigDecimal computedVat = computeVat(sum);
// print VAT(12%) : <computed vat>
printer(String.format(KeyValTemplate, VatLabel, computedVat), true);
printer("==============================", true);
// compute total
final BigDecimal total = computTotal(sum, discount, computedVat);
// print Total : <total>
printer(String.format(KeyValTemplate, TotalLabel, total), true);
// validate if cash is sufficient
final BigDecimal cash = validatedCash(scanner, total);
// compute change
final BigDecimal change = computeChange(total, cash);
// print Change : <change>
printer(String.format(KeyValTemplate, ChangeLabel, change), true);
// validate if user has next customer
isNextCustomer = validatedContinue(scanner);
printer("******************************", true);
} else {
printer(InvalidInput, true);
}
} while (isNextCustomer);
printer("POS ended", true);
}
public static Fruit getFruit(final List<Fruit> fruits, final String code) {
Optional<Fruit> retrievedFruit = Optional.empty();
for (Fruit fruit : fruits) {
if (code.equals(fruit.getCode())) {
retrievedFruit = Optional.of(fruit);
break;
}
}
return retrievedFruit.orElse(null);
}
private static BigDecimal computeSum(final BigDecimal price,
final Long qty) {
return price.multiply(new BigDecimal(qty));
}
private static BigDecimal computeVat(final BigDecimal priceQtySum) {
return priceQtySum.multiply(twelvePercentVat);
}
private static BigDecimal computTotal(final BigDecimal priceQtySum,
final BigDecimal discount,
final BigDecimal computedVat) {
return priceQtySum.subtract(discount).add(computedVat);
}
private static BigDecimal computeChange(final BigDecimal total,
final BigDecimal cash) {
return cash.subtract(total);
}
private static Boolean isContinue(final String input) {
Boolean isContinue;
switch (input.toLowerCase()) {
case "y":
isContinue = true;
break;
case "n":
isContinue = false;
break;
default:
isContinue = null;
break;
}
return isContinue;
}
private static boolean validatedContinue(final Scanner scanner) {
// label and input
String option = getInputText(scanner, NextCustomerLabel);
// re-enter if option is null
while (isContinue(option) == null) {
printer(InvalidInput, true);
option = getInputText(scanner, NextCustomerLabel);
}
return isContinue(option);
}
private static BigDecimal validatedCash(final Scanner scanner,
final BigDecimal total) {
BigDecimal cash = getInputBigDecimal(scanner, App.CashLabel);
// re-enter cash if is below the total
while (cash.compareTo(total) < 0) {
printer("\n", false);
// print invalid cash input
printer(InvalidCashInput, true);
// label and input
cash = getInputBigDecimal(scanner, App.CashLabel);
}
return cash;
}
private static String getInputText(final Scanner scanner,
final String label) {
Optional<String> option = Optional.empty();
do {
try {
// input label
printer(label, false);
// input
option = Optional.ofNullable(scanner.nextLine());
} catch (NullPointerException ignored) {
printer("\n", false);
printer(InvalidInput, true);
}
// re enter if entered value was invalid
} while (!option.isPresent());
return option.orElse(null);
}
private static BigDecimal getInputBigDecimal(final Scanner scanner,
final String label) {
Optional<BigDecimal> option = Optional.empty();
do {
try {
// input label
printer(label, false);
// input
option = Optional.of(new BigDecimal(scanner.nextLine()));
} catch (NullPointerException | NumberFormatException ignored) {
printer("\n", false);
printer(InvalidInput, true);
}
// re enter if entered value was invalid
} while (!option.isPresent());
return option.orElse(null);
}
public static class Fruit {
private final String code;
private final String name;
private final BigDecimal price;
public Fruit(final String name, final BigDecimal price, final String code) {
this.code = code;
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public BigDecimal getPrice() {
return price;
}
public String getCode() {
return code;
}
}
}