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/lib/hamcrest-core-1.3.jar b/lib/hamcrest-core-1.3.jar new file mode 100644 index 0000000..9d5fe16 Binary files /dev/null and b/lib/hamcrest-core-1.3.jar differ diff --git a/lib/junit-4.12.jar b/lib/junit-4.12.jar new file mode 100644 index 0000000..3a7fc26 Binary files /dev/null and b/lib/junit-4.12.jar differ diff --git a/lib/junit-jupiter-api-5.0.0.jar b/lib/junit-jupiter-api-5.0.0.jar new file mode 100644 index 0000000..5e0d9ce Binary files /dev/null and b/lib/junit-jupiter-api-5.0.0.jar differ diff --git a/lib/opentest4j-1.0.0.jar b/lib/opentest4j-1.0.0.jar new file mode 100644 index 0000000..1b5f425 Binary files /dev/null and b/lib/opentest4j-1.0.0.jar differ diff --git a/oop-workshop.iml b/oop-workshop.iml index f6a7637..bcddc85 100644 --- a/oop-workshop.iml +++ b/oop-workshop.iml @@ -21,5 +21,25 @@ + + + + + + + + + + + + + + + + + + + + \ 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..3866380 100644 --- a/src/checkout/Category.java +++ b/src/checkout/Category.java @@ -1,5 +1,8 @@ package checkout; public enum Category { - MILK + MILK, + MEET, + FRUIT, + VEGETABLE } diff --git a/src/checkout/Check.java b/src/checkout/Check.java index 31436e5..3ea7f9e 100644 --- a/src/checkout/Check.java +++ b/src/checkout/Check.java @@ -1,18 +1,21 @@ 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 LocalDate dateOfCheck = LocalDate.now(); public int getTotalCost() { int totalCost = 0; for (Product product : this.products) { totalCost += product.price; } - return totalCost; + return (this.discount > 0) ? totalCost - (totalCost * discount / 100) : totalCost; } void addProduct(Product product) { @@ -23,14 +26,26 @@ public int getTotalPoints() { return getTotalCost() + points; } - void addPoints(int points) { + public void addPoints(int points) { this.points += points; } - int getCostByCategory(Category category) { + public int getCostByCategory(Category category) { return products.stream() .filter(p -> p.category == category) .mapToInt(p -> p.price) .reduce(0, (a, b) -> a + b); } + + public List getProducts() { + return this.products; + } + + public void setDiscount(int discount) { + this.discount = discount; + } + + LocalDate getDateOfCheck() { + return this.dateOfCheck; + } } diff --git a/src/checkout/CheckoutService.java b/src/checkout/CheckoutService.java index 3ac7cbb..f764561 100644 --- a/src/checkout/CheckoutService.java +++ b/src/checkout/CheckoutService.java @@ -1,9 +1,15 @@ package checkout; +import com.sun.javaws.exceptions.OfflineLaunchException; + +import java.util.ArrayList; + public class CheckoutService { private Check check; + private ArrayList currentOffers = new ArrayList<>(); + public void openCheck() { check = new Check(); } @@ -16,23 +22,20 @@ public void addProduct(Product product) { } public Check closeCheck() { + if (currentOffers.size() >= 1) { + this.currentOffers.forEach(item -> { + if (item.isOfferValid(check)) + item.applyOffer(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); - } - } + this.currentOffers.add(offer); } + + } 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/Offer.java b/src/checkout/Offer.java index f2c67fe..e3bc65b 100644 --- a/src/checkout/Offer.java +++ b/src/checkout/Offer.java @@ -1,5 +1,32 @@ package checkout; -public abstract class Offer { - public abstract void apply(Check check); -} +import checkout.offer_interfaces.Condition; +import checkout.offer_interfaces.Reward; +import java.time.LocalDate; + +public class Offer { + + private LocalDate expiresDate; + private Reward reward; + private Condition condition; + + public Offer(LocalDate expireDate, Reward rewardType) { + this(expireDate, rewardType, null ); + } + + public Offer(LocalDate expireDate, Reward rewardType, Condition conditionType) { + this.expiresDate = expireDate; + this.reward = rewardType; + this.condition = conditionType; + } + + void applyOffer(Check check) { + if (this.expiresDate.isAfter(check.getDateOfCheck())) + reward.applyReward(check); + } + + boolean isOfferValid(Check check) { + return (condition == null) || condition.checkCondition(check); + } + +} \ No newline at end of file diff --git a/src/checkout/offer_conditions/ByCategory.java b/src/checkout/offer_conditions/ByCategory.java new file mode 100644 index 0000000..cd4463a --- /dev/null +++ b/src/checkout/offer_conditions/ByCategory.java @@ -0,0 +1,26 @@ +package checkout.offer_conditions; + +import checkout.Category; +import checkout.Check; +import checkout.offer_interfaces.Condition; + +public class ByCategory implements Condition { + + private Category requiredCategory; + private int requiredAmount; + + public ByCategory(Category requiredCategory, int requiredAmount) { + this.requiredCategory = requiredCategory; + this.requiredAmount = requiredAmount; + } + + public ByCategory(Category requiredCategory) { + this.requiredCategory = requiredCategory; + this.requiredAmount = 0; + } + + @Override + public boolean checkCondition(Check check) { + return (this.requiredAmount < check.getCostByCategory(this.requiredCategory)); + } +} diff --git a/src/checkout/offer_conditions/ByTotalCost.java b/src/checkout/offer_conditions/ByTotalCost.java new file mode 100644 index 0000000..4ef28e7 --- /dev/null +++ b/src/checkout/offer_conditions/ByTotalCost.java @@ -0,0 +1,20 @@ +package checkout.offer_conditions; + +import checkout.Check; +import checkout.offer_interfaces.Condition; + +public class ByTotalCost implements Condition { + + private int requiredAmount; + + public ByTotalCost(int requiredAmount) { + this.requiredAmount = requiredAmount; + } + + @Override + public boolean checkCondition(Check check) { + return this.requiredAmount < check.getTotalCost(); + } + +} + diff --git a/src/checkout/offer_interfaces/Condition.java b/src/checkout/offer_interfaces/Condition.java new file mode 100644 index 0000000..9530966 --- /dev/null +++ b/src/checkout/offer_interfaces/Condition.java @@ -0,0 +1,7 @@ +package checkout.offer_interfaces; + +import checkout.Check; + +public interface Condition { + boolean checkCondition(Check check); +} diff --git a/src/checkout/offer_interfaces/Reward.java b/src/checkout/offer_interfaces/Reward.java new file mode 100644 index 0000000..d07805a --- /dev/null +++ b/src/checkout/offer_interfaces/Reward.java @@ -0,0 +1,7 @@ +package checkout.offer_interfaces; + +import checkout.Check; + +public interface Reward { + void applyReward(Check check); +} diff --git a/src/checkout/offer_rewards/DiscountReward.java b/src/checkout/offer_rewards/DiscountReward.java new file mode 100644 index 0000000..48ad09f --- /dev/null +++ b/src/checkout/offer_rewards/DiscountReward.java @@ -0,0 +1,20 @@ +package checkout.offer_rewards; + +import checkout.Check; +import checkout.offer_interfaces.Reward; + +public class DiscountReward implements Reward { + + private int discount; + + public DiscountReward(int discount) { + this.discount = discount; + } + + @Override + public void applyReward(Check check) { + check.setDiscount(this.discount); + check.getTotalCost(); + } + +} diff --git a/src/checkout/offer_rewards/FactorByCategoryReward.java b/src/checkout/offer_rewards/FactorByCategoryReward.java new file mode 100644 index 0000000..9ff4b7b --- /dev/null +++ b/src/checkout/offer_rewards/FactorByCategoryReward.java @@ -0,0 +1,23 @@ +package checkout.offer_rewards; + +import checkout.Category; +import checkout.Check; +import checkout.offer_interfaces.Reward; + +public class FactorByCategoryReward implements Reward { + + final Category category; + final int factor; + + public FactorByCategoryReward(Category category, int factor) { + this.category = category; + this.factor = factor; + } + + @Override + public void applyReward(Check check) { + int points = check.getCostByCategory(category); + check.addPoints(points * (factor - 1)); + } + +} diff --git a/src/checkout/offer_rewards/FlatReward.java b/src/checkout/offer_rewards/FlatReward.java new file mode 100644 index 0000000..89c2f68 --- /dev/null +++ b/src/checkout/offer_rewards/FlatReward.java @@ -0,0 +1,19 @@ +package checkout.offer_rewards; + +import checkout.Check; +import checkout.offer_interfaces.Reward; + +public class FlatReward implements Reward { + + private int aditionalPoints; + + public FlatReward(int points) { + this.aditionalPoints = points; + } + + @Override + public void applyReward(Check check) { + check.addPoints(this.aditionalPoints); + } + +} diff --git a/test/CheckoutServiceTest.java b/test/CheckoutServiceTest.java index a34315e..6a27bf8 100644 --- a/test/CheckoutServiceTest.java +++ b/test/CheckoutServiceTest.java @@ -1,15 +1,25 @@ import checkout.*; +import checkout.offer_conditions.ByCategory; +import checkout.offer_conditions.ByTotalCost; +import checkout.offer_rewards.DiscountReward; +import checkout.offer_rewards.FactorByCategoryReward; +import checkout.offer_rewards.FlatReward; +import com.sun.javaws.exceptions.OfflineLaunchException; 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; -public class CheckoutServiceTest { +class CheckoutServiceTest { private Product milk_7; private CheckoutService checkoutService; private Product bred_3; + private Offer specialOffer; + private LocalDate futureDate; @BeforeEach void setUp() { @@ -18,6 +28,8 @@ void setUp() { milk_7 = new Product(7, "Milk", Category.MILK); bred_3 = new Product(3, "Bred"); + + futureDate = LocalDate.now().plusYears(1); } @Test @@ -58,35 +70,148 @@ void closeCheck__calcTotalPoints() { } @Test - void useOffer__addOfferPoints() { + void userOffer__useOfferWhileBuying__FlatReward() { + checkoutService.addProduct(milk_7); + specialOffer = new Offer(futureDate, + new FlatReward(10), + new ByTotalCost(15)); + checkoutService.addProduct(milk_7); + checkoutService.addProduct(bred_3); + checkoutService.useOffer(specialOffer); + + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalPoints(), is(27)); + } + + @Test + void useOffer__FlatOfferReward() { checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); - checkoutService.useOffer(new AnyGoodsOffer(6, 2)); + specialOffer = new Offer(futureDate, new FlatReward( 2)); + + checkoutService.useOffer(specialOffer); Check check = checkoutService.closeCheck(); assertThat(check.getTotalPoints(), is(12)); } @Test - void useOffer__whenCostLessThanRequired__doNothing() { + void userOffer__FlatOfferReward__ByTotalCost() { + checkoutService.addProduct(milk_7); + + specialOffer = new Offer(futureDate, new FlatReward(10), new ByTotalCost(5)); + checkoutService.useOffer(specialOffer); + + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalPoints(), is(17)); + } + + @Test + void userOffer__FlatOfferReward__ByCategory() { + checkoutService.addProduct(milk_7); + + specialOffer = new Offer(futureDate, new FlatReward(10), new ByCategory(Category.MILK)); + checkoutService.useOffer(specialOffer); + + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalPoints(), is(17)); + } + + @Test + void userOffer__FactorByCategoryReward__ByCategory() { + checkoutService.addProduct(milk_7); + checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); - checkoutService.useOffer(new AnyGoodsOffer(6, 2)); + specialOffer = new Offer(futureDate, + new FactorByCategoryReward(Category.MILK, 2), + new ByCategory(Category.MILK, 10)); + checkoutService.useOffer(specialOffer); + Check check = checkoutService.closeCheck(); - assertThat(check.getTotalPoints(), is(3)); + assertThat(check.getTotalPoints(), is(31)); } @Test - void useOffer__factorByCategory() { + void userOffer__FactorByCategoryReward__ByTotalAmount() { checkoutService.addProduct(milk_7); checkoutService.addProduct(milk_7); checkoutService.addProduct(bred_3); - checkoutService.useOffer(new FactorByCategoryOffer(Category.MILK, 2)); + specialOffer = new Offer(futureDate, + new FactorByCategoryReward(Category.MILK, 2), + new ByTotalCost(10)); + checkoutService.useOffer(specialOffer); + Check check = checkoutService.closeCheck(); assertThat(check.getTotalPoints(), is(31)); } -} + + @Test + void userOffer__DiscountReward__ByCategory() { + Product beef_100 = new Product(100, "beef", Category.MEET); + checkoutService.addProduct(beef_100); + + specialOffer = new Offer(futureDate, new DiscountReward(20), new ByCategory(Category.MEET)); + checkoutService.useOffer(specialOffer); + + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalCost(), is(80)); + } + + @Test + void userOffer__checkExpirationDate__Expired() { + checkoutService.addProduct(milk_7); + checkoutService.addProduct(milk_7); + checkoutService.addProduct(bred_3); + + specialOffer = new Offer(LocalDate.now().minusYears(1), + new FactorByCategoryReward(Category.MILK, 2), + new ByTotalCost(10)); + + checkoutService.useOffer(specialOffer); + + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalPoints(), is(17)); + } + + @Test + void userOffer__useSeveralOffers__secondWorks() { + checkoutService.addProduct(milk_7); + + specialOffer = new Offer(futureDate, new FlatReward(10), new ByCategory(Category.MILK)); + checkoutService.useOffer(specialOffer); + + Offer offerTwo = new Offer(futureDate, new FlatReward(10), new ByTotalCost(6)); + checkoutService.useOffer(offerTwo); + + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalPoints(), is(27)); + } + + @Test + void userOffer__useSeveralOffers__secondDoesNotWorks() { + checkoutService.addProduct(milk_7); + + specialOffer = new Offer(futureDate, new FlatReward(10), new ByCategory(Category.MILK)); + checkoutService.useOffer(specialOffer); + + Offer offerTwo = new Offer(futureDate, new FlatReward(10), new ByTotalCost(26)); + checkoutService.useOffer(offerTwo); + + Check check = checkoutService.closeCheck(); + + assertThat(check.getTotalPoints(), is(17)); + } + + +} \ No newline at end of file