Skip to content

Instantly share code, notes, and snippets.

@kpol
Last active April 15, 2019 02:28
Show Gist options
  • Select an option

  • Save kpol/b21a3be63e8af75763e08b98e74d7383 to your computer and use it in GitHub Desktop.

Select an option

Save kpol/b21a3be63e8af75763e08b98e74d7383 to your computer and use it in GitHub Desktop.
Kata09: Back to the Checkout
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