Assignment

Requirements:

Code is Object Oriented, class-based
• The input values are not“hard-coded;” Input values should be prompted
• Exceptions for bad inputs
• Correct output values
• The code should not be sloppy, extraneous or cumbersome

  • Should be well commented and explained

Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt. Import duty is an additional sales tax applicable on all imported goods at a rate of 5%, with no exemptions.

When I purchase items I receive a receipt which lists the name of all the items and their price (including tax), finishing with the total cost of the items, and the total amounts of sales taxes paid. The rounding rules for sales tax are that for a tax rate of n%, a shelf price of p contains (np/100 rounded up to the nearest 0.05) amount of sales tax.

Write an application that takes input for shopping baskets and returns receipts in the format shown below.

TEST DATA:

Input 1:

1 book at 12.49

1 book at 12.49

1 music CD at 14.99

1 chocolate bar at 0.85

Output 1:

Book:  24.98 (2 @ 12.49)

Music CD: 16.49

Chocolate bar: 0.85

Sales Taxes: 1.50

Total: 42.32 

Input 2:

1 imported box of chocolates at 10.00 1 imported bottle of perfume at 47.50

Output 2:

Imported box of chocolates: 10.50 Imported bottle of perfume: 54.65 Sales Taxes: 7.65

Total: 65.15 

Input 3:

1 imported bottle of perfume at 27.99 1 bottle of perfume at 18.99

1 packet of headache pills at 9.75

1 box of imported chocolates at 11.25 1 box of imported chocolates at 11.25

Output 3:

Imported bottle of perfume: 32.19 Bottle of perfume: 20.89

Packet of headache pills: 9.75

Imported box of chocolates: 23.70 (2 @ 11.85)

Sales Taxes: 7.30

Total: 86.53

 Solution 

Good.java 

package receipts;

importjava.text.DecimalFormat;

// Class representing good in the shop basket. Stores number of this good in the basket, price of one instance of this good.

public class Good {

// Keywords for determination if good is exempt or not

private static final String[] exemptKeyWords = {“food”, “book”, “medicine”, “chocolate”, “pill”};

// Format for outputting decimal numbers

private static DecimalFormatdf = new DecimalFormat(“0.00”);

// Instance private fields of class

private String name;

private double price;

privateint number;

privatebooleanisImported;

privatebooleanisExempt;

public Good(String name, double price, int number) throws IllegalArgumentException{

// Throwing exceptions if parameters are illegal

if (price <= 0.0) {

throw new IllegalArgumentException(“Price must be positive”);

}

if (number <= 0.0) {

throw new IllegalArgumentException(“Quantity must be positive integer”);

}

this.name = name;

this.price = price;

this.number = number;

isImported = false;

isExempt = false;

// Checking if good is imported or exempt

String lcName = name.toLowerCase();

if (lcName.contains(“imported”)) {

isImported = true;

}

// If name of good contains one of keywords, then good is exempt

for (String exemptKeyWord : exemptKeyWords) {

if (lcName.contains(exemptKeyWord)) {

isExempt = true;

break;

}

}

}

public Good(String name, double price) {

this(name, price, 1);

}

// Getter for name field

public String getName() {

return name;

}

// Adding more instances of the same good (increasing number field of the class).

// If prices differ, returns false.

publicbooleanaddQuantity(Good good) {

if (this.price != good.price) {

return false;

}

this.number += good.number;

return true;

}

// Checking if name of the current good matches given name

publicboolean equals(String name) {

returnthis.name.equals(name);

}

// Return overall sale tax for ‘number’ of goods

public double getTax() {

if (isExempt) {

return 0.0;

}

return number*Math.ceil((price*0.1)/0.05)*0.05;

}

// Return overall import tax for ‘number’ of goods

public double getImportTax() {

if (!isImported)

return 0.0;

return number*Math.ceil((price*0.05)/0.05)*0.05;

}

// Calculates overall price for ‘number’ of goods (including taxes)

public double getOverallPrice() {

return number*price + getTax() + getImportTax();

}

// Returns the string representation of good info.

public String toString() {

StringBufferbuf = new StringBuffer();

buf.append(name + “: ” + df.format(getOverallPrice()));

if (number > 1) {

buf.append(” (” + number + ” @ ” + df.format(getOverallPrice()/number) + “)”);

}

returnbuf.toString();

}

} 

Receipt.java 

package receipts;

importjava.text.DecimalFormat;

importjava.util.ArrayList;

importjava.util.InputMismatchException;

importjava.util.List;

importjava.util.NoSuchElementException;

importjava.util.Scanner;

// Class representing selected set of goods.

public class Receipt {

// Format for outputting decimal numbers

private static DecimalFormatdf = new DecimalFormat(“0.00”);

// List, containing all selected goods

private List<Good> basket;

private double totalPrice;

private double taxes;

public Receipt() {

basket = new ArrayList<>();

taxes = 0;

}

// Adding good to the basket. If no such kind of good was selected previously, than adding new good instance to the basket list.

// Otherwise, increasing number field in corresponding good instance.

public void addGood(Good good) throws IllegalArgumentException{

for (Good g : basket) {

if (g.equals(good.getName())) {

if (!g.addQuantity(good)) {

throw new IllegalArgumentException(“Two goods with the same name but different data are found.”);

}

return;

}

}

basket.add(good);

}

// This method outputs all necessary info

public void outputAll() {

for (Good g : basket) {

// Cumulating total overall cost and taxes

taxes += (g.getTax() + g.getImportTax());

totalPrice += g.getOverallPrice();

// Printing separate good info

System.out.println(g);

}

System.out.println(“Sales taxes: ” + df.format(taxes));

System.out.println(“Total price: ” + df.format(totalPrice));

}

// Main method. Reads items from console, until empty string is entered

public static void main(String[] args) {

Scanner scanner = new Scanner(System.in);

Receipt receipt = new Receipt();

// Reading from console

while(true) {

// If line is empty, then quit

String line = scanner.nextLine();

if (line.equals(“”)) {

break;

}

// Scanning entered line

Scanner lineScan = null;

try {

// Line must contain word “at”

int index = line.lastIndexOf(“at”);

if (index == -1) {

throw new IllegalArgumentException(“Illegal input format: no \’at\’ found.”);

}

// Reading price after word “at”. Can throw NumberFormatException

String priceLine = line.substring(index+2);

double price = Double.parseDouble(priceLine);

lineScan = new Scanner(line.substring(0, index));

// Reading item quantity in the beginning of the line. Can throw InputMismatchException

int number = lineScan.nextInt();

// Trying to read good name. NoSuchElementException can be thrown if name is empty.

String name = lineScan.next();

while (lineScan.hasNext()) {

name += (” ” + lineScan.next());

}

// Creating new item instance and putting it to the basket

receipt.addGood(new Good(format(name), price, number));

lineScan.close();

}

// Processing errors

catch(NumberFormatExceptionnfe) {

System.out.println(“Can not read price”);

}

catch (InputMismatchExceptionime) {

System.out.println(“Can not read quantity”);

lineScan.close();

}

catch (NoSuchElementExceptionnsee) {

System.out.println(“Good item name is empty”);

lineScan.close();

}

catch(IllegalArgumentExceptioniae) {

if (lineScan != null) {

lineScan.close();

}

System.out.println(iae.getMessage());

}

}

scanner.close();

// Printing results

receipt.outputAll();

}

// Formatting good name. First letter of it must be capital.

private static String format(String word) {

returnword.substring(0,1).toUpperCase() + word.substring(1);

}

}