diff --git a/.idea/misc.xml b/.idea/misc.xml
index c9209a5..c08f7b9 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,7 +3,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/src/checkout/AnyGoodsOffer.java b/src/checkout/AnyGoodsOffer.java
deleted file mode 100644
index 8b11348..0000000
--- a/src/checkout/AnyGoodsOffer.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package checkout;
-
-public class AnyGoodsOffer extends Offer {
- public final int totalCost;
- public final int points;
-
- public AnyGoodsOffer(int totalCost, int points) {
- this.totalCost = totalCost;
- this.points = points;
- }
-
- @Override
- public void apply(Check check) {
-
- }
-}
diff --git a/src/checkout/Brand.java b/src/checkout/Brand.java
new file mode 100644
index 0000000..323e73c
--- /dev/null
+++ b/src/checkout/Brand.java
@@ -0,0 +1,5 @@
+package checkout;
+
+public enum Brand {
+ VOLOSHKOVE_POLE
+}
diff --git a/src/checkout/ByBrand.java b/src/checkout/ByBrand.java
new file mode 100644
index 0000000..3a5bb52
--- /dev/null
+++ b/src/checkout/ByBrand.java
@@ -0,0 +1,22 @@
+package checkout;
+
+public class ByBrand implements Condition {
+ Brand brand;
+
+ public ByBrand(Brand brand) {
+ setBrand(brand);
+ }
+
+ @Override
+ public boolean checkCondition(Check check) {
+ boolean marker = false;
+ for (Product p : check.getProducts()) {
+ if (p.brand == brand) marker = true;
+ }
+ return marker;
+ }
+
+ public void setBrand(Brand brand) {
+ this.brand = brand;
+ }
+}
diff --git a/src/checkout/ByCategory.java b/src/checkout/ByCategory.java
new file mode 100644
index 0000000..c773fa7
--- /dev/null
+++ b/src/checkout/ByCategory.java
@@ -0,0 +1,22 @@
+package checkout;
+
+public class ByCategory implements Condition {
+ Category category;
+
+ public ByCategory(Category category) {
+ setCategory(category);
+ }
+
+ @Override
+ public boolean checkCondition(Check check) {
+ boolean marker = false;
+ for(Product p : check.getProducts()) {
+ if (p.category == category) marker = true;
+ }
+ return marker;
+ }
+
+ public void setCategory(Category category) {
+ this.category = category;
+ }
+}
diff --git a/src/checkout/Check.java b/src/checkout/Check.java
index 31436e5..b6990b7 100644
--- a/src/checkout/Check.java
+++ b/src/checkout/Check.java
@@ -1,11 +1,14 @@
package checkout;
+import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
public class Check {
private List products = new ArrayList<>();
private int points = 0;
+ private int discount = 0;
+ private static LocalDate todayDate = LocalDate.now();
public int getTotalCost() {
int totalCost = 0;
@@ -15,6 +18,10 @@ public int getTotalCost() {
return totalCost;
}
+ public int getTotalCostWithDiscount() {
+ return getTotalCost() - discount/10;
+ }
+
void addProduct(Product product) {
products.add(product);
}
@@ -33,4 +40,23 @@ int getCostByCategory(Category category) {
.mapToInt(p -> p.price)
.reduce(0, (a, b) -> a + b);
}
+
+ public int getPointsForBrand(Brand brand) {
+ return products.stream()
+ .filter(p -> p.brand == brand)
+ .mapToInt(p -> p.price)
+ .reduce(0, (a,b)-> a+b);
+ }
+
+ public void addDiscount(int discount) {
+ this.discount = discount;
+ }
+
+ public List getProducts() {
+ return products;
+ }
+
+ public static LocalDate getTodayDate() {
+ return todayDate;
+ }
}
diff --git a/src/checkout/CheckoutService.java b/src/checkout/CheckoutService.java
index 3ac7cbb..c525a22 100644
--- a/src/checkout/CheckoutService.java
+++ b/src/checkout/CheckoutService.java
@@ -1,10 +1,15 @@
package checkout;
+import java.util.ArrayList;
+import java.util.List;
+
public class CheckoutService {
private Check check;
+ private List offers = new ArrayList<>();
public void openCheck() {
+ offers = new ArrayList<>();
check = new Check();
}
@@ -16,23 +21,19 @@ public void addProduct(Product product) {
}
public Check closeCheck() {
+ useAllOffer();
Check closedCheck = check;
check = null;
return closedCheck;
}
+ private void useAllOffer() {
+ if(this.offers.size()!=0) this.offers.forEach(offer ->
+ offer.apply(check));
+ }
+
public void useOffer(Offer offer) {
- offer.apply(check);
- if (offer instanceof FactorByCategoryOffer) {
- FactorByCategoryOffer fbOffer = (FactorByCategoryOffer) offer;
- int points = check.getCostByCategory(fbOffer.category);
- check.addPoints(points * (fbOffer.factor - 1));
- } else {
- if (offer instanceof AnyGoodsOffer) {
- AnyGoodsOffer agOffer = (AnyGoodsOffer) offer;
- if (agOffer.totalCost <= check.getTotalCost())
- check.addPoints(agOffer.points);
- }
- }
+ if(check != null)
+ this.offers.add(offer);
}
}
diff --git a/src/checkout/Condition.java b/src/checkout/Condition.java
new file mode 100644
index 0000000..a47c266
--- /dev/null
+++ b/src/checkout/Condition.java
@@ -0,0 +1,5 @@
+package checkout;
+
+public interface Condition {
+ boolean checkCondition(Check check);
+}
diff --git a/src/checkout/DiscountByBrand.java b/src/checkout/DiscountByBrand.java
new file mode 100644
index 0000000..d6a686a
--- /dev/null
+++ b/src/checkout/DiscountByBrand.java
@@ -0,0 +1,25 @@
+package checkout;
+
+public class DiscountByBrand implements Reward {
+ private double discount;
+ private Brand brand;
+
+ public DiscountByBrand(double discount, Brand brand) {
+ setBrand(brand);
+ setDiscount(discount);
+ }
+
+ @Override
+ public void apply(Check check) {
+ Double points = check.getPointsForBrand(brand) * discount * 10;
+ check.addDiscount(points.intValue());
+ }
+
+ public void setBrand(Brand brand) {
+ this.brand = brand;
+ }
+
+ public void setDiscount(double discount) {
+ this.discount = discount;
+ }
+}
diff --git a/src/checkout/FactorByCategoryOffer.java b/src/checkout/FactorByCategoryOffer.java
deleted file mode 100644
index fee57f0..0000000
--- a/src/checkout/FactorByCategoryOffer.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package checkout;
-
-public class FactorByCategoryOffer extends Offer {
- final Category category;
- final int factor;
-
- public FactorByCategoryOffer(Category category, int factor) {
- this.category = category;
- this.factor = factor;
- }
-
- @Override
- public void apply(Check check) {
-
- }
-}
diff --git a/src/checkout/FactorRewardByCategory.java b/src/checkout/FactorRewardByCategory.java
new file mode 100644
index 0000000..7a5b91e
--- /dev/null
+++ b/src/checkout/FactorRewardByCategory.java
@@ -0,0 +1,25 @@
+package checkout;
+
+public class FactorRewardByCategory implements Reward {
+ private int factor;
+ Category category;
+
+ public FactorRewardByCategory(int factor, Category category) {
+ setCategory(category);
+ setFactor(factor);
+ }
+
+ @Override
+ public void apply(Check check) {
+ int points = check.getCostByCategory(category);
+ check.addPoints(points * (factor-1));
+ }
+
+ public void setFactor(int factor) {
+ this.factor = factor;
+ }
+
+ public void setCategory(Category category) {
+ this.category = category;
+ }
+}
diff --git a/src/checkout/FlatReward.java b/src/checkout/FlatReward.java
new file mode 100644
index 0000000..617facf
--- /dev/null
+++ b/src/checkout/FlatReward.java
@@ -0,0 +1,18 @@
+package checkout;
+
+public class FlatReward implements Reward {
+ private int reward;
+
+ public FlatReward (int reward) {
+ setReward(reward);
+ }
+
+ @Override
+ public void apply(Check check) {
+ check.addPoints(reward);
+ }
+
+ public void setReward(int reward) {
+ this.reward = reward;
+ }
+}
diff --git a/src/checkout/Offer.java b/src/checkout/Offer.java
index f2c67fe..506dbdf 100644
--- a/src/checkout/Offer.java
+++ b/src/checkout/Offer.java
@@ -1,5 +1,23 @@
package checkout;
-public abstract class Offer {
- public abstract void apply(Check check);
+import java.time.LocalDate;
+
+public class Offer {
+ Reward reward;
+ Condition condition;
+ private LocalDate expirationDate;
+
+ public Offer(Reward reward , Condition condition, LocalDate expirationDate) {
+ this.condition = condition;
+ this.reward = reward;
+ this.expirationDate = expirationDate;
+ }
+
+ public void apply(Check check) {
+ if(condition.checkCondition(check) && isOfferAvailable(check.getTodayDate())) reward.apply(check);
+ }
+
+ public boolean isOfferAvailable(LocalDate todayDate) {
+ return (expirationDate.isAfter(todayDate));
+ }
}
diff --git a/src/checkout/Product.java b/src/checkout/Product.java
index f03a6e8..fbfc6e1 100644
--- a/src/checkout/Product.java
+++ b/src/checkout/Product.java
@@ -4,11 +4,17 @@ public class Product {
final int price;
final String name;
Category category;
+ Brand brand;
- public Product(int price, String name, Category category) {
+ public Product(int price, String name, Category category, Brand brand) {
this.price = price;
this.name = name;
this.category = category;
+ this.brand = brand;
+ }
+
+ public Product(int price, String name, Category category) {
+ this(price, name, category, null);
}
public Product(int price, String name) {
diff --git a/src/checkout/Reward.java b/src/checkout/Reward.java
new file mode 100644
index 0000000..2e885a0
--- /dev/null
+++ b/src/checkout/Reward.java
@@ -0,0 +1,6 @@
+package checkout;
+
+public interface Reward {
+
+ void apply(Check check);
+}
diff --git a/src/checkout/TotalCost.java b/src/checkout/TotalCost.java
new file mode 100644
index 0000000..659eed5
--- /dev/null
+++ b/src/checkout/TotalCost.java
@@ -0,0 +1,18 @@
+package checkout;
+
+public class TotalCost implements Condition {
+ int totalCost;
+
+ public TotalCost(int totalCost){
+ setTotalCost(totalCost);
+ }
+
+ @Override
+ public boolean checkCondition(Check check) {
+ return (totalCost <= check.getTotalCost());
+ }
+
+ public void setTotalCost(int totalCost) {
+ this.totalCost = totalCost;
+ }
+}
diff --git a/test/CheckoutServiceTest.java b/test/CheckoutServiceTest.java
index a34315e..d343b01 100644
--- a/test/CheckoutServiceTest.java
+++ b/test/CheckoutServiceTest.java
@@ -1,7 +1,7 @@
import checkout.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-
+import java.time.LocalDate;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@@ -10,6 +10,7 @@ public class CheckoutServiceTest {
private Product milk_7;
private CheckoutService checkoutService;
private Product bred_3;
+ private Product milk_7_WithBrand;
@BeforeEach
void setUp() {
@@ -18,6 +19,7 @@ void setUp() {
milk_7 = new Product(7, "Milk", Category.MILK);
bred_3 = new Product(3, "Bred");
+ milk_7_WithBrand = new Product(7, "Milk", Category.MILK, Brand.VOLOSHKOVE_POLE);
}
@Test
@@ -42,7 +44,6 @@ void addProduct__whenCheckIsClosed__opensNewCheck() {
checkoutService.addProduct(milk_7);
Check milkCheck = checkoutService.closeCheck();
assertThat(milkCheck.getTotalCost(), is(7));
-
checkoutService.addProduct(bred_3);
Check bredCheck = checkoutService.closeCheck();
assertThat(bredCheck.getTotalCost(), is(3));
@@ -53,40 +54,97 @@ void closeCheck__calcTotalPoints() {
checkoutService.addProduct(milk_7);
checkoutService.addProduct(bred_3);
Check check = checkoutService.closeCheck();
-
assertThat(check.getTotalPoints(), is(10));
}
@Test
- void useOffer__addOfferPoints() {
+ void useOffer__whenCheckClose() {
+ checkoutService.useOffer(new Offer(new FlatReward(20), new TotalCost(10), LocalDate.now().plusDays(1)));
+ checkoutService.useOffer(new Offer(new FactorRewardByCategory(2, Category.MILK),
+ new ByCategory(Category.MILK), LocalDate.now().plusDays(1)));
+ checkoutService.addProduct(milk_7);
+ checkoutService.addProduct((bred_3));
checkoutService.addProduct(milk_7);
- checkoutService.addProduct(bred_3);
-
- checkoutService.useOffer(new AnyGoodsOffer(6, 2));
Check check = checkoutService.closeCheck();
+ assertThat(check.getTotalPoints(), is(51));
+ }
- assertThat(check.getTotalPoints(), is(12));
+ @Test
+ void isOfferAvailable__ifTimeForOffersEnded__doNothing() {
+ checkoutService.addProduct(milk_7);
+ checkoutService.addProduct(milk_7);
+ checkoutService.addProduct((bred_3));
+ Offer offer = new Offer(new FlatReward(20), new TotalCost(10),
+ LocalDate.now().minusDays(1));
+ checkoutService.useOffer(offer);
+ Check check = checkoutService.closeCheck();
+ assertThat(check.getTotalPoints(), is(17));
}
+ @Test
+ void useOffer__addOfferPoints() {
+ checkoutService.addProduct(milk_7_WithBrand);
+ checkoutService.addProduct(milk_7_WithBrand);
+ Offer offer = new Offer(new FlatReward(20), new TotalCost(10),
+ LocalDate.now().plusDays(1));
+ checkoutService.useOffer(offer);
+ Check check = checkoutService.closeCheck();
+ assertThat(check.getTotalPoints(), is(34));
+ }
@Test
void useOffer__whenCostLessThanRequired__doNothing() {
checkoutService.addProduct(bred_3);
-
- checkoutService.useOffer(new AnyGoodsOffer(6, 2));
+ checkoutService.addProduct(bred_3);
+ checkoutService.addProduct(bred_3);
+ Offer offer = new Offer(new FlatReward(20), new TotalCost(10),
+ LocalDate.now().plusDays(1));
+ checkoutService.useOffer(offer);
Check check = checkoutService.closeCheck();
-
- assertThat(check.getTotalPoints(), is(3));
+ assertThat(check.getTotalPoints(), is(9));
}
@Test
void useOffer__factorByCategory() {
- checkoutService.addProduct(milk_7);
- checkoutService.addProduct(milk_7);
+ checkoutService.addProduct(milk_7_WithBrand);
+ checkoutService.addProduct(milk_7_WithBrand);
+ Offer offer = new Offer(new FactorRewardByCategory(2, Category.MILK),
+ new ByCategory(Category.MILK), LocalDate.now().plusDays(1));
+ checkoutService.useOffer(offer);
+ Check check = checkoutService.closeCheck();
+ assertThat(check.getTotalPoints(), is(28));
+ }
+
+ @Test
+ void useOffer__whenCategoryAbsent__doNothing() {
+ checkoutService.addProduct(bred_3);
checkoutService.addProduct(bred_3);
+ Offer offer = new Offer(new FactorRewardByCategory(2, Category.MILK),
+ new ByCategory(Category.MILK), LocalDate.now().plusDays(1));
+ checkoutService.useOffer(offer);
+ Check check = checkoutService.closeCheck();
+ assertThat(check.getTotalPoints(), is(6));
+ }
- checkoutService.useOffer(new FactorByCategoryOffer(Category.MILK, 2));
+ @Test
+ void useOffer__discountByBrand() {
+ checkoutService.addProduct(milk_7_WithBrand);
+ checkoutService.addProduct(milk_7_WithBrand);
+ Offer offer = new Offer(new DiscountByBrand(0.5, Brand.VOLOSHKOVE_POLE),
+ new ByBrand(Brand.VOLOSHKOVE_POLE), LocalDate.now().plusDays(1));
+ checkoutService.useOffer(offer);
+ Check check = checkoutService.closeCheck();
+ assertThat(check.getTotalCostWithDiscount(), is(7));
+ }
+
+ @Test
+ void useOffer__whenBrandAbsent__doNothing() {
+ checkoutService.addProduct(bred_3);
+ checkoutService.addProduct(milk_7);
+ Offer offer = new Offer(new DiscountByBrand(0.5, Brand.VOLOSHKOVE_POLE),
+ new ByBrand(Brand.VOLOSHKOVE_POLE), LocalDate.now().plusDays(1));
+ checkoutService.useOffer(offer);
Check check = checkoutService.closeCheck();
+ assertThat(check.getTotalCostWithDiscount(), is(10));
- assertThat(check.getTotalPoints(), is(31));
}
}