Last active
April 15, 2019 02:28
-
-
Save kpol/b21a3be63e8af75763e08b98e74d7383 to your computer and use it in GitHub Desktop.
Kata09: Back to the Checkout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| class Program | |
| { | |
| static void Main() | |
| { | |
| var product = new Product(1) { Price = 10 }; | |
| var product2 = new Product(2) { Price = 1 }; | |
| var orderItem = new OrderedItem { Product = product, Count = 10 }; | |
| var orderItem2 = new OrderedItem { Product = product2, Count = 2 }; | |
| var discountRule1 = new DiscountRule { Product = product, NumberOfProductsToApplyTheRule = 3, SpecialPrice = 25 }; | |
| var discountRule2 = new DiscountRule { Product = product, NumberOfProductsToApplyTheRule = 5, SpecialPrice = 40 }; | |
| var total = new DiscountEngine().Calculate(new[] { orderItem, orderItem2 }, | |
| new IPricingRule[] { discountRule1, discountRule2 }); | |
| Console.WriteLine(total); | |
| } | |
| public class Product : IEquatable<Product> | |
| { | |
| public Product(int id) | |
| { | |
| Id = id; | |
| } | |
| public int Id { get; } | |
| public string Name { get; set; } | |
| public decimal Price { get; set; } | |
| public bool Equals(Product other) | |
| { | |
| if (other == null) | |
| { | |
| return false; | |
| } | |
| return NonNullEquals(other); | |
| } | |
| public override bool Equals(object obj) | |
| { | |
| if (obj == null || obj.GetType() != GetType()) | |
| { | |
| return false; | |
| } | |
| return NonNullEquals((Product)obj); | |
| } | |
| public override int GetHashCode() | |
| { | |
| return Id.GetHashCode(); | |
| } | |
| private bool NonNullEquals(Product product) | |
| { | |
| return Id == product.Id; | |
| } | |
| } | |
| public class OrderedItem | |
| { | |
| public Product Product { get; set; } | |
| public int Count { get; set; } | |
| } | |
| public interface IPricingRule | |
| { | |
| Product Product { get; set; } | |
| int NumberOfProductsToApplyTheRule { get; set; } | |
| IPricingRuleResult Calculate(int numberOfItems); | |
| } | |
| public interface IPricingRuleResult | |
| { | |
| decimal TotalCost { get; } | |
| int NumberOfProducts { get; } | |
| } | |
| private class PricingRuleResult : IPricingRuleResult | |
| { | |
| public decimal TotalCost { get; set; } | |
| public int NumberOfProducts { get; set; } | |
| } | |
| public class DiscountRule : IPricingRule | |
| { | |
| public Product Product { get; set; } | |
| public int NumberOfProductsToApplyTheRule { get; set; } | |
| public decimal SpecialPrice { get; set; } | |
| public IPricingRuleResult Calculate(int numberOfItems) | |
| { | |
| if (numberOfItems < NumberOfProductsToApplyTheRule) | |
| { | |
| return new PricingRuleResult { NumberOfProducts = 0, TotalCost = 0 }; | |
| } | |
| var numberOfGroups = numberOfItems / NumberOfProductsToApplyTheRule; | |
| return new PricingRuleResult | |
| { | |
| NumberOfProducts = numberOfGroups * NumberOfProductsToApplyTheRule, | |
| TotalCost = numberOfGroups * SpecialPrice | |
| }; | |
| } | |
| } | |
| public class DiscountEngine | |
| { | |
| public decimal Calculate(IEnumerable<OrderedItem> products, IEnumerable<IPricingRule> rules) | |
| { | |
| var result = products.GroupJoin(rules, p => p.Product, r => r.Product, (p, r) => | |
| new | |
| { | |
| OrderItem = p, | |
| Rules = r.OrderByDescending(rule => rule.NumberOfProductsToApplyTheRule) | |
| } | |
| ); | |
| decimal total = 0; | |
| foreach (var orderItem in result) | |
| { | |
| var count = orderItem.OrderItem.Count; | |
| foreach (var pricingRule in orderItem.Rules) | |
| { | |
| if (count == 0) | |
| { | |
| break; | |
| } | |
| var calc = pricingRule.Calculate(count); | |
| total += calc.TotalCost; | |
| count -= calc.NumberOfProducts; | |
| } | |
| if (count != 0) | |
| { | |
| // applying default price | |
| total += count * orderItem.OrderItem.Product.Price; | |
| } | |
| } | |
| return total; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment