Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions domain-modeling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
| Classes | Methods/Properties | Scenario | Outputs |
|:--------:|:--------------------:|:-------------------------:|:-----------------:|
| Customer | AddBagel | Space in basket | Success |
| Customer | AddBagel | Full Basket | Receive error |
| Customer | AddBagel | Bagel with custom filling | Success |
| Customer | RemoveBagel | Remove bagel from basket | Success |
| Customer | RemoveBagel | Has no bagel to remove | Receive Error |
| Customer | GetBagelPrice | Get price of bagel | Int |
| Customer | GetFillingPrices | Get price of each filling | Dict<string, int> |
| Manager | ChangeBasketCapacity | Adjust basket capacity | Success |
43 changes: 43 additions & 0 deletions exercise.main/Bagel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using exercise.tests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace exercise.main
{
public class Bagel : Product
{
private int MaxFillings = 10;
private Dictionary<string, Filling> fillings = new Dictionary<string,Filling>();

public Bagel(string sku, string variant, decimal price)
: base(sku, variant, price)
{
Name = "Bagel";
}

public Guid? AddFilling(Inventory inventory, string SKU)
{
if (!inventory.HasProduct(SKU)) return null;
Product potentialFilling = inventory.GetProduct(SKU);
Filling? filling = null;
if (potentialFilling == null || potentialFilling.GetName() != "Filling") return null;
else filling = potentialFilling as Filling;

if (filling == null || !inventory.HasProduct(filling.GetSKU())) return null;
if (fillings.Count >= MaxFillings) return null;

fillings.Add(filling.GetSKU(), filling);
return filling.GetId();
}

public decimal GetFillingPrice() { return fillings.Values.Sum(fillings => fillings.GetPrice()); }

public List<Filling> GetFillings()
{
return fillings.Values.ToList();
}
}
}
208 changes: 208 additions & 0 deletions exercise.main/Basket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
using exercise.tests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace exercise.main
{
public class Basket
{
private static int Capacity = 25;
private Dictionary<Guid, Product> products = new Dictionary<Guid, Product>();

public int GetCapacity() => Capacity;

public decimal GetBasketTotal(bool ApplyDiscount = false) {

if (ApplyDiscount) {
// first count number of each bagel SKU


Dictionary<string, int> SKUs = products.Values.GroupBy(product => product.GetSKU()).ToDictionary(group => group.Key, group => group.Count());
// Alternative but not that cool
// Dictionary<string, int> SKUs = new Dictionary<string, int>();
//foreach (var product in products.Values) {
// SKUs[product.GetSKU()] = SKUs.TryGetValue(product.GetSKU(), out var count) ? count + 1 : 1;
//}


Dictionary<string, int> bagelSKUs = SKUs.Where(sku => sku.Key.Contains("BGL")).ToDictionary();
int COFBs = products.Values.Where(product => product.GetSKU().Contains("COFB")).Count();


// check how many bagels that fit into the 6/12 discount. If any bagels left, check if any coffees
decimal BasketValue = 0;
foreach (var sku in bagelSKUs)
{
decimal n_12s = 0;
decimal n_6s = 0;
decimal noDiscount = 0;
int bagelCOFBCombo = 0;
if (sku.Value >= 12)
{
n_12s = Math.Floor(sku.Value / 12m);
decimal remainder = sku.Value % 12;
n_6s = remainder >= 6m ? 1 : 0;
noDiscount = remainder % 6;
}
else if (sku.Value >= 6)
{
n_6s++;
noDiscount = sku.Value % 6;
}
else noDiscount = sku.Value;

//iterate number of combos of coffee+bagel
for (; bagelCOFBCombo < Math.Min(COFBs, noDiscount); bagelCOFBCombo++) ;

COFBs -= bagelCOFBCombo;
BasketValue += n_12s * 3.99m + n_6s * 2.49m + noDiscount * GetProduct(sku.Key).GetPrice();

}

foreach (var product in products.Values)
{
// only add fillings
string sku = product.GetSKU();
if (sku.Contains("BGL")) BasketValue += (product as Bagel).GetFillingPrice();
else if (sku.Equals("COFB") && COFBs > 0)
{
COFBs -= 1;
BasketValue += product.GetPrice();
} else BasketValue += product.GetPrice();

}



return BasketValue;

// check for fillings
} else return products.Values.Sum(product => product.GetPrice());
}
public Guid? AddProduct(Inventory inventory, Product product)
{
if (!inventory.HasProduct(product.GetSKU())) return null;
else if (products.Count() == Capacity) return null;

products.Add(product.GetId(), product);

return product.GetId();
}


public Product GetProduct(Guid id) { return products[id]; }
public Product GetProduct(string SKU) {
return products.Values.FirstOrDefault(product => product.GetSKU() == SKU);
}


public List<Product> GetProducts() { return products.Values.ToList(); }

public bool RemoveProduct(Guid id)
{
// check if item is in basket
if (products.Values.Any(product => product.GetId().Equals(id)))
{
return products.Remove(id);
}
else return false;
}

public string GetReceipt()
{
string ReceiptSeperator = "\n------------------------------\n";
string Receipt = $" ~~~ Bob's Bagels ~~~\n\n {DateTime.Now}\n{ReceiptSeperator}\n";

Dictionary<string, int> SKUs = products.Values.GroupBy(product => product.GetSKU()).ToDictionary(group => group.Key, group => group.Count());

Dictionary<string, int> bagelSKUs = SKUs.Where(sku => sku.Key.Contains("BGL")).ToDictionary();
int COFBs = products.Values.Where(product => product.GetSKU().Contains("COFB")).Count();


// check how many bagels that fit into the 6/12 discount. If any bagels left, check if any coffees
decimal BasketValue = 0;
foreach (var sku in bagelSKUs)
{
decimal n_12s = 0;
decimal n_6s = 0;
decimal noDiscount = 0;
int bagelCOFBCombo = 0;
if (sku.Value >= 12)
{
n_12s = Math.Floor(sku.Value / 12m);
decimal remainder = sku.Value % 12;
n_6s = remainder >= 6m ? 1 : 0;
noDiscount = remainder % 6;
}
else if (sku.Value >= 6)
{
n_6s++;
noDiscount = sku.Value % 6;
}
else noDiscount = sku.Value;

//iterate number of combos of coffee+bagel
for (; bagelCOFBCombo < Math.Min(COFBs, noDiscount); bagelCOFBCombo++) ;

COFBs -= bagelCOFBCombo;


decimal discount = GetProduct(sku.Key).GetPrice() * sku.Value - (n_6s * 2.49m + n_12s * 3.99m);
Receipt += ""
BasketValue += n_12s * 3.99m + n_6s * 2.49m + noDiscount * GetProduct(sku.Key).GetPrice();

foreach (var product in products.Values.Where(product => (product.GetSKU() == sku.Key)))
{
BasketValue += (product as Bagel).GetFillingPrice();
List<Filling> fillings = (product as Bagel).GetFillings();
if (fillings.Count > 0)
{
foreach (var filling in fillings) {
Receipt += $" * {filling.GetVariant()} - £{filling.GetPrice()}\n";
}

}
}

}

foreach (var product in products.Values)
{
// only add fillings
string sku = product.GetSKU();
if (sku.Contains("BGL")) BasketValue += (product as Bagel).GetFillingPrice();
else if (sku.Equals("COFB") && COFBs > 0)
{
COFBs -= 1;
BasketValue += product.GetPrice();
}
else BasketValue += product.GetPrice();

}

// Original
foreach (var product in products.Values)
{
Receipt += $" {product.GetName()}, {product.GetVariant()} - £{product.GetPrice()}\n";
if (product is Bagel bagel)
{
List<Filling> fillings = bagel.GetFillings();
if (fillings.Count > 0)
{
foreach (var filling in fillings) Receipt += $" * {filling.GetVariant()} - £{filling.GetPrice()}\n";

}
}
}

Receipt += ReceiptSeperator;
Receipt += $"Total £{GetBasketTotal(true)}";
return Receipt;

}
}
}
20 changes: 20 additions & 0 deletions exercise.main/Coffee.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace exercise.main
{


public class Coffee : Product
{

public Coffee(string sku, string variant, decimal price)
: base(sku, variant, price)
{
Name = "Coffee";
}
}
}
14 changes: 14 additions & 0 deletions exercise.main/Filling.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using exercise.main;
using System.Xml.Linq;

namespace exercise.tests
{
public class Filling : Product
{
public Filling(string sku, string variant, decimal price)
: base(sku, variant, price)
{
Name = "Filling";
}
}
}
31 changes: 31 additions & 0 deletions exercise.main/IProduct.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace exercise.main
{
public class Product
{
protected Guid Id = Guid.NewGuid();
protected string SKU;
protected string Name;
protected string Variant;
protected decimal Price;

public Product(string sku, string variant, decimal price) //int stock
{
SKU = sku;
Variant = variant;
Price = price;
//Stock = stock;
}

public string GetSKU() { return SKU; }
public Guid GetId() { return Id; }
public string GetVariant() { return Variant; }
public decimal GetPrice() { return Price; }
public string GetName() { return Name; }
}
}
37 changes: 37 additions & 0 deletions exercise.main/Inventory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using exercise.tests;

namespace exercise.main
{
public class Inventory
{

private Dictionary<string, Product> products = new Dictionary<string, Product>();
public Inventory(bool StandardStock = true)
{
if (StandardStock) {
AddProduct(new Bagel("BGLO", "Onion", 0.49m));
AddProduct(new Bagel("BGLP", "Plain", 0.39m));
AddProduct(new Bagel("BGLE", "Everything", 0.49m));
AddProduct(new Bagel("BGLS", "Sesame", 0.49m));
AddProduct(new Coffee("COFB", "Black", 0.99m));
AddProduct(new Coffee("COFW", "White", 1.19m));
AddProduct(new Coffee("COFC", "Capuccino", 1.29m));
AddProduct(new Coffee("COFL", "Latte", 1.29m));
AddProduct(new Filling("FILB", "Bacon", 0.12m));
AddProduct(new Filling("FILE", "Egg", 0.12m));
AddProduct(new Filling("FILC", "Cheese", 0.12m));
AddProduct(new Filling("FILX", "Cream Cheese", 0.12m));
AddProduct(new Filling("FILS", "Smoked Salmon", 0.12m));
AddProduct(new Filling("FILH", "Ham", 0.12m));
}
}

public void AddProduct(Product product) { products.Add(product.GetSKU(), product); }
public bool RemoveProduct(string SKU) { return products.Remove(SKU); }

public List<Product> GetProducts() { return [.. products.Values]; }
public bool HasProduct(string SKU) { return products.Values.Any(product => (product.GetSKU() == SKU)); }

public Product GetProduct(string SKU) { return products[SKU]; }
}
}
2 changes: 1 addition & 1 deletion exercise.main/Program.cs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Console.WriteLine("Hello, World!");
5 changes: 5 additions & 0 deletions exercise.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "exercise.tests", "exercise.
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{825CCFE7-4F2E-4770-8393-FEB732F66EE4}"
ProjectSection(SolutionItems) = preProject
..\..\..\Downloads\BobsBagels.drawio.png = ..\..\..\Downloads\BobsBagels.drawio.png
domain-modeling.md = domain-modeling.md
extension1.md = extension1.md
extension2.md = extension2.md
extension3.md = extension3.md
Expand All @@ -34,4 +36,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B7C3F758-DF6B-4220-B2C9-8083957810CC}
EndGlobalSection
EndGlobal
Loading