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/oop-workshop.iml b/oop-workshop.iml index f6a7637..678d355 100644 --- a/oop-workshop.iml +++ b/oop-workshop.iml @@ -21,5 +21,27 @@ + + + + + + + + + + + + + + + + + + + + + + \ 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/Category.java b/src/checkout/Category.java index 0f1dff7..6345bb9 100644 --- a/src/checkout/Category.java +++ b/src/checkout/Category.java @@ -1,5 +1,6 @@ package checkout; public enum Category { - MILK + MILK, + BRED } diff --git a/src/checkout/Check.java b/src/checkout/Check.java index 31436e5..ff92263 100644 --- a/src/checkout/Check.java +++ b/src/checkout/Check.java @@ -2,16 +2,26 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; public class Check { private List products = new ArrayList<>(); + private List offers = new ArrayList<>(); private int points = 0; + private double discount = 0; - public int getTotalCost() { - int totalCost = 0; + public int getTotalPrice() { + int totalPrice = 0; for (Product product : this.products) { - totalCost += product.price; + totalPrice += product.price; } + return totalPrice; + } + + public double getTotalCost() { + double totalCost = 0; + totalCost += getTotalPrice(); + totalCost -= discount; return totalCost; } @@ -20,17 +30,31 @@ void addProduct(Product product) { } public int getTotalPoints() { - return getTotalCost() + points; + return getTotalPrice() + points; } void addPoints(int points) { this.points += points; } - int getCostByCategory(Category category) { + void useOffers(Check check) { + for (Offer offer : offers) { + offer.apply(check); + } + } + + void addOffer(Offer offer) { + offers.add(offer); + } + + int getSubCost(Predicate predicate) { return products.stream() - .filter(p -> p.category == category) + .filter(predicate) .mapToInt(p -> p.price) .reduce(0, (a, b) -> a + b); } + + void addDiscount(double discount) { + this.discount += discount; + } } diff --git a/src/checkout/CheckoutService.java b/src/checkout/CheckoutService.java index 3ac7cbb..d0b8bcb 100644 --- a/src/checkout/CheckoutService.java +++ b/src/checkout/CheckoutService.java @@ -16,23 +16,13 @@ public void addProduct(Product product) { } public Check closeCheck() { + check.useOffers(check); Check closedCheck = check; check = null; return closedCheck; } 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); - } - } + check.addOffer(offer); } } diff --git a/src/checkout/Condition.java b/src/checkout/Condition.java new file mode 100644 index 0000000..8d125ae --- /dev/null +++ b/src/checkout/Condition.java @@ -0,0 +1,7 @@ +package checkout; + +public interface Condition { + boolean checkCondition(Check check); + + int getCostForCondition(Check check); +} diff --git a/src/checkout/ConditionByCategory.java b/src/checkout/ConditionByCategory.java new file mode 100644 index 0000000..02a07bf --- /dev/null +++ b/src/checkout/ConditionByCategory.java @@ -0,0 +1,29 @@ +package checkout; + +import java.util.function.Predicate; + +public class ConditionByCategory implements Condition { + Category category; + int totalCost; + Predicate predicate = p -> p.category == category; + + public ConditionByCategory(Category category, int totalCost) { + this.category = category; + this.totalCost = totalCost; + } + + public ConditionByCategory(Category category) { + this.category = category; + this.totalCost = 0; + } + + @Override + public boolean checkCondition(Check check) { + return check.getSubCost(predicate) > totalCost; + } + + @Override + public int getCostForCondition(Check check) { + return check.getSubCost(predicate); + } +} diff --git a/src/checkout/ConditionByTradeMark.java b/src/checkout/ConditionByTradeMark.java new file mode 100644 index 0000000..ec691d4 --- /dev/null +++ b/src/checkout/ConditionByTradeMark.java @@ -0,0 +1,29 @@ +package checkout; + +import java.util.function.Predicate; + +public class ConditionByTradeMark implements Condition { + TradeMark tradeMark; + int totalCost; + Predicate productPredicate = p -> p.tradeMark == tradeMark; + + public ConditionByTradeMark(TradeMark tradeMark, int totalCost) { + this.tradeMark = tradeMark; + this.totalCost = totalCost; + } + + public ConditionByTradeMark(TradeMark tradeMark) { + this.tradeMark = tradeMark; + this.totalCost = 0; + } + + @Override + public boolean checkCondition(Check check) { + return check.getSubCost(productPredicate) > totalCost; + } + + @Override + public int getCostForCondition(Check check) { + return check.getSubCost(productPredicate); + } +} diff --git a/src/checkout/ConditionOfTotalCost.java b/src/checkout/ConditionOfTotalCost.java new file mode 100644 index 0000000..6ed409d --- /dev/null +++ b/src/checkout/ConditionOfTotalCost.java @@ -0,0 +1,17 @@ +package checkout; + +public class ConditionOfTotalCost implements Condition { + int totalCost; + + public ConditionOfTotalCost(int totalCost) { + this.totalCost = totalCost; + } + + public boolean checkCondition(Check check) { + return totalCost <= check.getTotalCost(); + } + + public int getCostForCondition(Check check) { + return check.getTotalPrice(); + } +} diff --git a/src/checkout/DiscountReward.java b/src/checkout/DiscountReward.java new file mode 100644 index 0000000..d8461ac --- /dev/null +++ b/src/checkout/DiscountReward.java @@ -0,0 +1,13 @@ +package checkout; + +public class DiscountReward implements Reward { + int discount; + + public DiscountReward(int discount) { + this.discount = discount; + } + + public void applyReward(Check check, int cost) { + check.addDiscount(cost * discount / 100.0); + } +} 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/FactorReward.java b/src/checkout/FactorReward.java new file mode 100644 index 0000000..c46db7b --- /dev/null +++ b/src/checkout/FactorReward.java @@ -0,0 +1,13 @@ +package checkout; + +public class FactorReward implements Reward { + int factor; + + public FactorReward(int factor) { + this.factor = factor; + } + + public void applyReward(Check check, int cost) { + check.addPoints(cost * (factor - 1)); + } +} diff --git a/src/checkout/FlatReward.java b/src/checkout/FlatReward.java new file mode 100644 index 0000000..9a80e2c --- /dev/null +++ b/src/checkout/FlatReward.java @@ -0,0 +1,14 @@ +package checkout; + +public class FlatReward implements Reward { + int flat; + + public FlatReward(int flat) { + this.flat = flat; + } + + public void applyReward(Check check, int cost) { + check.addPoints(flat); + } +} + diff --git a/src/checkout/Offer.java b/src/checkout/Offer.java index f2c67fe..7f7e726 100644 --- a/src/checkout/Offer.java +++ b/src/checkout/Offer.java @@ -1,5 +1,22 @@ package checkout; -public abstract class Offer { - public abstract void apply(Check check); +import java.time.LocalDate; + +public class Offer { + private LocalDate expiredDate; + private Reward reward; + private Condition condition; + private LocalDate todayDate = LocalDate.of(2019, 3, 6); + + public Offer(LocalDate expiredDate, Reward rewardType, Condition condition) { + this.expiredDate = expiredDate; + this.reward = rewardType; + this.condition = condition; + } + + public void apply(Check check) { + if (expiredDate.isAfter(todayDate) && condition.checkCondition(check)) { + reward.applyReward(check, condition.getCostForCondition(check)); + } + } } diff --git a/src/checkout/Product.java b/src/checkout/Product.java index f03a6e8..1d642a0 100644 --- a/src/checkout/Product.java +++ b/src/checkout/Product.java @@ -4,14 +4,16 @@ public class Product { final int price; final String name; Category category; + TradeMark tradeMark; - public Product(int price, String name, Category category) { + public Product(int price, String name, Category category, TradeMark tradeMark) { this.price = price; this.name = name; this.category = category; + this.tradeMark = tradeMark; } public Product(int price, String name) { - this(price, name, null); + this(price, name, null, null); } } diff --git a/src/checkout/Reward.java b/src/checkout/Reward.java new file mode 100644 index 0000000..d1b4c1f --- /dev/null +++ b/src/checkout/Reward.java @@ -0,0 +1,5 @@ +package checkout; + +public interface Reward { + void applyReward(Check check, int cost); +} diff --git a/src/checkout/TradeMark.java b/src/checkout/TradeMark.java new file mode 100644 index 0000000..96d70a0 --- /dev/null +++ b/src/checkout/TradeMark.java @@ -0,0 +1,7 @@ +package checkout; + +public enum TradeMark { + PEPSI, + ROSHEN, + LAYS +} diff --git a/test/CheckoutServiceTest.java b/test/CheckoutServiceTest.java index a34315e..eced323 100644 --- a/test/CheckoutServiceTest.java +++ b/test/CheckoutServiceTest.java @@ -2,6 +2,8 @@ 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,83 +12,101 @@ public class CheckoutServiceTest { private Product milk_7; private CheckoutService checkoutService; private Product bred_3; + private LocalDate expiredDate = LocalDate.of(2100, 4, 14); @BeforeEach void setUp() { checkoutService = new CheckoutService(); checkoutService.openCheck(); - milk_7 = new Product(7, "Milk", Category.MILK); - bred_3 = new Product(3, "Bred"); + milk_7 = new Product(7, "Milk", Category.MILK, TradeMark.PEPSI); + bred_3 = new Product(3, "Bred", Category.BRED, TradeMark.ROSHEN); } @Test - void closeCheck__withOneProduct() { + void useFactorReward_whenCostMoreThenRequired() { checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new FactorReward(3), new ConditionOfTotalCost(10))); Check check = checkoutService.closeCheck(); - assertThat(check.getTotalCost(), is(7)); + assertThat(check.getTotalPoints(), is(7)); } @Test - void closeCheck__withTwoProducts() { + void useFactorRewardAndConditionByCategory() { + checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new FactorReward(3), new ConditionByCategory(Category.MILK))); checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); Check check = checkoutService.closeCheck(); - assertThat(check.getTotalCost(), is(10)); + assertThat(check.getTotalPoints(), is(45)); } @Test - void addProduct__whenCheckIsClosed__opensNewCheck() { + void useFlatRewardAndConditionByCategory() { + checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new FlatReward(100), new ConditionByCategory(Category.MILK, 100))); 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)); + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalPoints(), is(17)); } @Test - void closeCheck__calcTotalPoints() { + void useFlatRewardAndConditionByOutlet() { + checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new FlatReward(30), new ConditionByTradeMark(TradeMark.ROSHEN))); checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); Check check = checkoutService.closeCheck(); - assertThat(check.getTotalPoints(), is(10)); + assertThat(check.getTotalPoints(), is(47)); } @Test - void useOffer__addOfferPoints() { + void useDiscountRewardAndConditionByOutlet() { + checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new DiscountReward(50), new ConditionByTradeMark(TradeMark.ROSHEN))); checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); - - checkoutService.useOffer(new AnyGoodsOffer(6, 2)); Check check = checkoutService.closeCheck(); - assertThat(check.getTotalPoints(), is(12)); + assertThat(check.getTotalCost(), is(15.5)); } @Test - void useOffer__whenCostLessThanRequired__doNothing() { + void useDiscountRewardAndConditionByOutlet__whenOutletNotFound() { + checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new DiscountReward(50), new ConditionByTradeMark(TradeMark.LAYS, 5))); + checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); - - checkoutService.useOffer(new AnyGoodsOffer(6, 2)); Check check = checkoutService.closeCheck(); - assertThat(check.getTotalPoints(), is(3)); + assertThat(check.getTotalCost(), is(17.0)); } @Test - void useOffer__factorByCategory() { + void useDiscountRewardAndConditionByTotalCost() { checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new DiscountReward(50), new ConditionOfTotalCost(7))); checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalCost(), is(8.5)); + } - checkoutService.useOffer(new FactorByCategoryOffer(Category.MILK, 2)); + @Test + void useDiscountRewardAndConditionByTotalCost__whenTotalCostLessThenRequire() { + checkoutService.addProduct(milk_7); + checkoutService.useOffer(new Offer(expiredDate, new DiscountReward(50), new ConditionOfTotalCost(50))); + checkoutService.addProduct(milk_7); + checkoutService.addProduct(bred_3); Check check = checkoutService.closeCheck(); - assertThat(check.getTotalPoints(), is(31)); + assertThat(check.getTotalCost(), is(17.0)); } } +