38 lines
1.5 KiB
C#
38 lines
1.5 KiB
C#
namespace Distribution.Features.Grn;
|
|
|
|
public record LineAmounts(decimal Gross, decimal Discount, decimal Nbt, decimal Vat, decimal Total);
|
|
|
|
/// <summary>
|
|
/// GRN costing. Per line: gross = accepted qty x unit cost; discount = gross x disc%;
|
|
/// NBT = (gross - discount) x NBT%; VAT = (gross - discount + NBT) x VAT%;
|
|
/// total = gross - discount + NBT + VAT. Rejected units are never costed.
|
|
/// Each amount is rounded to 2 dp per line so the GRN totals equal the sum of what the lines show.
|
|
/// </summary>
|
|
public static class GrnPricing
|
|
{
|
|
public static decimal Round(decimal value) => Math.Round(value, 2, MidpointRounding.AwayFromZero);
|
|
|
|
public static LineAmounts Line(
|
|
int acceptedQty, decimal unitCost, decimal discountPercent, decimal nbtPercent, decimal vatPercent)
|
|
{
|
|
var gross = Round(acceptedQty * unitCost);
|
|
var discount = Round(gross * discountPercent / 100m);
|
|
var net = gross - discount;
|
|
var nbt = Round(net * nbtPercent / 100m);
|
|
var vat = Round((net + nbt) * vatPercent / 100m);
|
|
return new LineAmounts(gross, discount, nbt, vat, net + nbt + vat);
|
|
}
|
|
|
|
public static void ValidatePercent(decimal value, string label)
|
|
{
|
|
if (value < 0 || value > 100)
|
|
throw new InvalidOperationException($"{label} must be between 0 and 100.");
|
|
}
|
|
|
|
public static void ValidateCost(decimal value, string label)
|
|
{
|
|
if (value < 0)
|
|
throw new InvalidOperationException($"{label} cannot be negative.");
|
|
}
|
|
}
|