Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6d440a4
Initial commit
Sep 10, 2019
f8ef8da
Update .gitignore to ignore target directory
Sep 10, 2019
7a4e229
Calculate basket total
Sep 10, 2019
cecd1d1
Move classes into src folder
saqibarif Sep 12, 2019
55a2497
Convert Product into a class
saqibarif Sep 12, 2019
e71b446
Moved BasketTest into correct package
saqibarif Sep 13, 2019
f735725
Add console output
saqibarif Sep 13, 2019
34d4b40
Create percentage discount offer
saqibarif Sep 13, 2019
66506e1
Made PercentageDiscount not be specific to apples
saqibarif Sep 13, 2019
3b1d833
Remove unused imports
saqibarif Sep 13, 2019
a41a10d
Convert PercentageDiscount back to being apple-specific
saqibarif Sep 15, 2019
baf7e2e
Rename: PercentageDiscount -> TenPercentOffApplesOffer
saqibarif Sep 15, 2019
6c25df5
Add date range to apple offer
saqibarif Sep 16, 2019
fb7fc51
Minor refactors to TenPercentOffApplesOffer
saqibarif Sep 16, 2019
ebb3b6a
Create buy two soups get bread half price offer
saqibarif Sep 16, 2019
e6f3696
Remove white space
saqibarif Sep 16, 2019
f820966
Push duplicate code into new abstract offer class
saqibarif Sep 16, 2019
9ea42e8
Include offers in BasketRunner
saqibarif Sep 16, 2019
ea6f02b
Expand basket tests
saqibarif Sep 16, 2019
5144c35
Format prices and display discounts
saqibarif Sep 16, 2019
8ef3193
Improve loop varible name
saqibarif Sep 16, 2019
4716640
Extract duplicated date to variable
saqibarif Sep 16, 2019
f289fde
Remove ununsed import
saqibarif Sep 16, 2019
5953be1
Do not display basket again when quitting
saqibarif Sep 16, 2019
2d80e15
Simplify tests with custom matcher for BigDecimals
saqibarif Sep 16, 2019
a4d173b
Update pom to allow build of runnable jar with dependencies
saqibarif Sep 16, 2019
ee89455
Update README with instructions on how to run
saqibarif Sep 16, 2019
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.idea/
target/
*.iml
*.class
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Java Exercise

This is a simple exercise to allow you to demostrate your software engineering skillset. It's completly up to you how long you give yourself, stop when you're happy with the quality of your work, but we don't expect it to take too long.
This is a simple exercise to allow you to demonstrate your software engineering skillset. It's completely up to you how long you give yourself, stop when you're happy with the quality of your work, but we don't expect it to take too long.

## To Run
1. First build with `mvn clean install`.
2. Run with `java -jar /insert/path/to/your/maven/repository/henrys-groceries-1.0-SNAPSHOT-jar-with-dependencies.jar`.
3. Alternatively, just run `BasketRunner` class in your IDE.

## Instructions
1. Please fork this repository and work on your fork.
Expand All @@ -18,7 +23,7 @@ This is a simple exercise to allow you to demostrate your software engineering s

A local shop, Henry’s Grocery, has asked you to author an IT solution for them to price up a basket of shopping for their customers.

Henry’s Grocery, currently only stocks four items and has two promotions. These are as follows:
Henry’s Grocery currently only stocks four items and has two promotions. These are as follows:

### Stock Items

Expand Down
70 changes: 70 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.ford.henrysgroceries</groupId>
<artifactId>henrys-groceries</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>

<junit.version>4.11</junit.version>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.20.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.ford.henrysgroceries.BasketRunner</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
72 changes: 72 additions & 0 deletions src/main/java/com/ford/henrysgroceries/Basket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.ford.henrysgroceries;

import com.ford.henrysgroceries.offers.Offer;
import com.ford.henrysgroceries.products.Product;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.time.Clock;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Basket {

private List<Product> products;
private List<Offer> offers;
private Clock clock;

public Basket() {
products = new ArrayList<>();
offers = new ArrayList<>();
}

public Basket(List<Offer> offers) {
products = new ArrayList<>();
this.offers = offers;
}

public Basket(List<Offer> offers, Clock fixedClock, Product... products) {
this.products = Arrays.asList(products);
this.offers = offers;
clock = fixedClock;
}

public BigDecimal calculateTotal() {
offers.forEach(offer -> offer.apply(this, getDate()));

return products.stream()
.map(product -> product.hasDiscount() ? product.getDiscountPrice() : product.getPrice())
.reduce(BigDecimal.ZERO, BigDecimal::add);
}

private LocalDate getDate() {
return clock == null ? LocalDate.now() : LocalDate.now(clock);
}

public List<Product> getProducts() {
return products;
}

public void addProduct(Product product) {
this.products.add(product);
calculateTotal();
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder("Basket:\n");
products.forEach(product -> display(sb, product));
sb.append("Total: ").append(format(calculateTotal())).append("\n");
return sb.toString();
}

private StringBuilder display(StringBuilder sb, Product product) {
return sb.append(product.getName()).append(" ").append(format(product.getDisplayPrice())).append("\n");
}

private String format(BigDecimal price) {
return NumberFormat.getCurrencyInstance().format(price);
}
}
78 changes: 78 additions & 0 deletions src/main/java/com/ford/henrysgroceries/BasketRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.ford.henrysgroceries;

import com.ford.henrysgroceries.offers.BuyTwoSoupsGetBreadHalfPriceOffer;
import com.ford.henrysgroceries.offers.Offer;
import com.ford.henrysgroceries.offers.TenPercentOffApplesOffer;

import java.io.PrintStream;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

import static com.ford.henrysgroceries.products.ProductHelper.*;

public class BasketRunner {
private final Basket basket;

private final Scanner scanner;

private final PrintStream printStream;

public BasketRunner(Basket basket, Scanner scanner, PrintStream printStream) {
this.basket = basket;
this.scanner = scanner;
this.printStream = printStream;
}

public static void main(String[] args) {
LocalDate today = LocalDate.now();
Offer applesOffer = new TenPercentOffApplesOffer(today);
Offer breadOffer = new BuyTwoSoupsGetBreadHalfPriceOffer(today);
List<Offer> offers = Arrays.asList(applesOffer, breadOffer);
BasketRunner basketRunner = new BasketRunner(new Basket(offers), new Scanner(System.in), System.out);
basketRunner.run();
}

void run() {
boolean addMoreToBasket = true;

do {
printStream.print("Please enter the first letter of the product you wish to add to your basket: [S]oup, [B]read, [M]ilk, [A]pples or [Q]uit: ");
String input = scanner.nextLine().toUpperCase();

switch (input) {
case "S":
printStream.print("You added: Soup\n");
basket.addProduct(soup());
break;

case "B":
printStream.print("You added: Bread\n");
basket.addProduct(bread());
break;

case "M":
printStream.print("You added: Milk\n");
basket.addProduct(milk());
break;

case "A":
printStream.print("You added: Apples\n");
basket.addProduct(apples());
break;

case "Q":
printStream.print("\n");
addMoreToBasket = false;
break;

default:
printStream.print("Product not recognised\n");
}

if (addMoreToBasket)
printStream.println(basket);
} while (addMoreToBasket);
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/ford/henrysgroceries/offers/AbstractOffer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ford.henrysgroceries.offers;

import java.time.LocalDate;

public abstract class AbstractOffer implements Offer {
LocalDate start;
LocalDate end;

boolean notApplicable(LocalDate date) {
return date.isBefore(start) || date.isAfter(end);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.ford.henrysgroceries.offers;

import com.ford.henrysgroceries.Basket;
import com.ford.henrysgroceries.products.Product;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;

import static com.ford.henrysgroceries.products.ProductHelper.bread;
import static com.ford.henrysgroceries.products.ProductHelper.soup;

public class BuyTwoSoupsGetBreadHalfPriceOffer extends AbstractOffer {
public BuyTwoSoupsGetBreadHalfPriceOffer(LocalDate today) {
start = today.minusDays(1);
end = start.plusDays(7);
}

@Override
public Basket apply(Basket basket, LocalDate date) {
if (notApplicable(date))
return basket;

List<Product> products = basket.getProducts();
long numberOfSoup = products.stream()
.filter(product -> product.getName().equals(soup().getName()))
.count();

if (numberOfSoup < 2)
return basket;

long numberOfDiscountsToApply = numberOfSoup / 2;

for (Product product : products) {
if (product.getName().equals(bread().getName()) && numberOfDiscountsToApply > 0) {
product.setDiscountPrice(product.getPrice().divide(new BigDecimal(2)));
numberOfDiscountsToApply--;
}
}

return basket;
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/ford/henrysgroceries/offers/Offer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ford.henrysgroceries.offers;

import com.ford.henrysgroceries.Basket;

import java.time.LocalDate;

public interface Offer {

Basket apply(Basket basket, LocalDate date);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.ford.henrysgroceries.offers;

import com.ford.henrysgroceries.Basket;
import com.ford.henrysgroceries.products.Product;

import java.math.BigDecimal;
import java.time.LocalDate;

import static com.ford.henrysgroceries.products.ProductHelper.apples;
import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;

public class TenPercentOffApplesOffer extends AbstractOffer {

public TenPercentOffApplesOffer(LocalDate today) {
start = today.plusDays(3);
end = today.plusMonths(1).with(lastDayOfMonth());
}

@Override
public Basket apply(Basket basket, LocalDate date) {
if (notApplicable(date))
return basket;

basket.getProducts().stream()
.filter(product -> product.getName().equals(apples().getName()))
.forEach(product -> product.setDiscountPrice(setDiscountPrice(product)));
return basket;
}

private BigDecimal setDiscountPrice(Product product) {
BigDecimal price = product.getPrice();
BigDecimal percentage = new BigDecimal(10);
BigDecimal discount = price.divide(new BigDecimal("100.00")).multiply(percentage);
return price.subtract(discount);
}
}
Loading