73 lines
2.5 KiB
C#
73 lines
2.5 KiB
C#
namespace Prices;
|
|
|
|
/// <summary>Turns a list price into what the customer actually pays.</summary>
|
|
public static class PriceCalculator
|
|
{
|
|
/// <summary>Applies a percentage discount to a price, e.g. 25 for a quarter off.</summary>
|
|
public static decimal ApplyDiscount(decimal price, decimal discountPercent)
|
|
{
|
|
if (price < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(price), "A price cannot be negative.");
|
|
}
|
|
|
|
if (discountPercent is < 0 or > 100)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(discountPercent), "A discount is between 0 and 100 percent.");
|
|
}
|
|
|
|
return price * (1m - discountPercent / 100m);
|
|
}
|
|
|
|
/// <summary>Rounds an amount to the nearest 0.05, rounding halves away from zero.</summary>
|
|
public static decimal RoundToFiveRappen(decimal amount)
|
|
{
|
|
return Math.Round(amount * 20m, MidpointRounding.AwayFromZero) / 20m;
|
|
}
|
|
|
|
/// <summary>Returns the quantity discount percent for a quantity: 0, 5 or 10.</summary>
|
|
public static int GetQuantityDiscountPercent(int quantity)
|
|
{
|
|
if (quantity < 1)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(quantity), "A quantity must be at least 1.");
|
|
}
|
|
|
|
return quantity switch
|
|
{
|
|
>= 50 => 10,
|
|
>= 10 => 5,
|
|
_ => 0,
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the total: percentage discount on the unit price first, then the quantity
|
|
/// discount on the total, then rounds the end amount to the nearest 0.05.
|
|
/// </summary>
|
|
public static decimal CalculateTotal(decimal unitPrice, int quantity, decimal discountPercent)
|
|
{
|
|
if (unitPrice < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(unitPrice), "A price cannot be negative.");
|
|
}
|
|
|
|
if (quantity < 1)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(quantity), "A quantity must be at least 1.");
|
|
}
|
|
|
|
if (discountPercent is < 0 or > 100)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(discountPercent), "A discount is between 0 and 100 percent.");
|
|
}
|
|
|
|
var discountedUnitPrice = ApplyDiscount(unitPrice, discountPercent);
|
|
var totalBeforeQuantityDiscount = discountedUnitPrice * quantity;
|
|
var quantityDiscountPercent = GetQuantityDiscountPercent(quantity);
|
|
var totalBeforeRounding = totalBeforeQuantityDiscount * (1m - quantityDiscountPercent / 100m);
|
|
|
|
return RoundToFiveRappen(totalBeforeRounding);
|
|
}
|
|
}
|