Skip to content
Open
68 changes: 68 additions & 0 deletions domain-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Domain Model

## Simplified user stories

- [x] Must be able to add bagel to basket
- [x] Must be able to remove bagel from basket
- [x] Must be able to check if basket is full
- [x] Must be able to change basket capacity
- [x] Must be able to check if item exists in basket
- [x] Warn when user removes non-existent item from basket
- [x] Must be able to check total cost of items in basket
- [x] Must be able to check cost of bagel before adding to basket
- [x] Must be able to choose fillings for bagel
- [x] Must be able to check cost of filling before adding to bagel order
- [x] Must be able to add coffee to basket
- [x] Must be able to check cost of coffee before adding to basket
- [x] Must be able to add promotion to product


## Methods

### Product (Bagel, coffee, etc.)

| Function Name | Parameters | Behavior | Returns |
|----------------|--------------------------|--------------------------------|--------------|
| GetCost | double cost | | |
| SetCost | double newCost | | |
| AddPromo | int amount, double price | Add a new promotion on product | void |

### Basket

| Function Name | Parameters | Behavior | Returns |
|--------------------------|------------------------|-------------------------------------------------|---------|
| Basket | int? capacity | Constructor, sets capacity to cart | void |
| Add | string SKU, int amount | Adds product to basket | void |
| Remove | string SKU, int amount | | void |
| SetCapacity | int newCapacity | Sets the new capacity of a basket | void |
| [private] CheckDiscounts | | | |
| [private] CheckCapacity | | Checks whether the basket can fit more products | bool |
| GetTotal | | Sets the new capacity of a basket | double |
| Order | | Submits the bagel order | void |
| [override] ToString | | Generates a string representation of cart | string |

### BasketItem
- Product
- Amount

### Inventory

| Function Name | Parameters | Behavior | Returns |
|---------------|-----------------------------|-----------------------------------|---------|
| Add | Product product, int amount | | |
| Remove | Product product, int amount | | |
| GetProduct | string SKU | Get product by SKU | Product |
| GetStock | | Get stock of the specific product | int |

### Order

| Function Name | Parameters | Behavior | Returns |
|---------------------|-----------------|---------------------------------------------------|---------|
| Order | List<OrderLine> | Constructor | void |
| [override] ToString | | Generate string representation of order (receipt) | string |

### OrderLine
- Product
- Amount
- Price
- Discount
183 changes: 183 additions & 0 deletions exercise.main/Basket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
namespace exercise.main;

public class Basket
{
private int _capacity;
private List<BasketItem> _items;

private readonly IInventory _inventory;

public Basket(IInventory inventory, int capacity = 10)
{
_capacity = capacity;
_items = new List<BasketItem>();
_inventory = inventory;
}
public void Add(string SKU, int quantity)
{
// Do not allow overfilled bagel basket!
if (GetNumberOfItems() + quantity > _capacity)
{
throw new Exception("Basket is full");
}

var item = Get(SKU);

if (ReferenceEquals(item, null))
{
_items.Add(new BasketItem(SKU, quantity));
return;
}

item.Quantity = quantity;
}

public void Remove(string SKU, int quantity)
{
var item = Get(SKU);
// Check if nullable item is null or empty

if (!ReferenceEquals(item, null))
{
Get(SKU).Quantity -= quantity;
}
}

public BasketItem? Get(string SKU)
{
return _items.FirstOrDefault(x => x.SKU == SKU);
}

public void SetCapacity(int capacity)
{
_capacity = capacity;
}

public int GetCapacity()
{
return _capacity;
}

private int GetNumberOfItems()
{
var numItems = 0;

foreach (var item in _items)
{
numItems += item.Quantity;
}

return numItems;
}

public double GetTotal()
{
double total = 0;

foreach (var item in _items)
{
var price = _inventory.GetProduct(item.SKU).GetPrice();

total += price * item.Quantity;
}

return total;
}

public Order Order()
{
Order order = new Order();
Dictionary<string, double> discounts = CheckDiscounts();

foreach (var item in _items)
{
var product = _inventory.GetProduct(item.SKU);
order.Add(product, item.Quantity);
}

foreach (var discount in discounts)
{
order.AddModifier(discount.Key, 0, discount.Value * -1);
}

return order;
}

public override string ToString()
{
throw new NotImplementedException();
}

private Dictionary<string, double> CheckDiscounts()
{
var discounts = new Dictionary<string, double>();
var numBagels = 0;
var numCoffees = 0;
var discount = 0.0;

foreach (var basketItem in _items)
{
if (basketItem.SKU.StartsWith("BGL"))
{
numBagels += basketItem.Quantity;
}

if (basketItem.SKU.StartsWith("COF"))
{
numCoffees += basketItem.Quantity;
}
}

// Apply the 12 for 3.99 offer
var twelves = numBagels / 12;
discount = twelves * (12 * 0.49 - 3.99);
numBagels %= 12;
// Discount is only applied when more than 0
if (discount > 0)
{
discounts.Add("12 for 3.99", discount);
}

// Apply the 6 for 2.49 offer
var sixes = numBagels / 6;
discount = sixes * (6 * 0.49 - 2.49);
numBagels %= 6;
if (discount > 0)
{
discounts.Add("6 for 2.49", discount);
}

// Coffee deal. Not to be combined with other deals
var qualifyingMealDeals = Math.Min(numBagels, numCoffees);
discount = qualifyingMealDeals * 0.5;
if (discount > 0)
{
discounts.Add("Coffee and Bagel", discount);
}

return discounts;
}

private bool CheckCapacity(int numNewItems)
{
throw new NotImplementedException();
}

private BasketItem? Contains(string SKU)
{
return Contains(SKU, []);
}

private BasketItem? Contains(string SKU, List<string> modifiers)
{
modifiers.Sort();
try
{
return _items.First(x => x.SKU == SKU && x.Modifiers.SequenceEqual(modifiers));
}
catch
{
return null;
}
}
}
15 changes: 15 additions & 0 deletions exercise.main/BasketItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace exercise.main;

public class BasketItem
{
public string SKU { get; set; }
public int Quantity { get; set; }
public List<string> Modifiers { get; set; }

public BasketItem(string sku, int quantity)
{
SKU = sku;
Quantity = quantity;
Modifiers = new List<string>();
}
}
65 changes: 65 additions & 0 deletions exercise.main/Inventory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Collections;

namespace exercise.main;

public class Inventory : IInventory, IEnumerable<KeyValuePair<Product, int>>
{
private Dictionary<Product, int> _products;

public Inventory()
{
_products = new Dictionary<Product, int>();
}

public IEnumerator<KeyValuePair<Product, int>> GetEnumerator()
{
return _products.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

public void AddProduct(Product product, int quantity)
{
_products.Add(product, quantity);
}

public void RemoveProduct(Product product, int quantity)
{
throw new NotImplementedException();
}

public void SetStock(Product product, int quantity)
{
throw new NotImplementedException();
}

public int GetStock(Product product)
{
throw new NotImplementedException();
}

public Product GetProduct(string sku)
{
try
{

return _products.First(p => p.Key.Sku == sku).Key;
}
catch (Exception e)
{
throw new Exception("Product not found", e);
}
}
}

public interface IInventory
{
void AddProduct(Product product, int quantity);
void RemoveProduct(Product product, int quantity);
void SetStock(Product product, int quantity);
int GetStock(Product product);
Product GetProduct(string sku);
}
Loading