namespace Distribution.Features.Grn; /// /// GRN costing. Per line: gross = accepted qty x unit cost; discount = gross x disc%; /// VAT = (gross - discount) x VAT%; total = gross - discount + 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. /// public static class GrnPricing { public static decimal Round(decimal value) => Math.Round(value, 2, MidpointRounding.AwayFromZero); public static (decimal Gross, decimal Discount, decimal Vat, decimal Total) Line( int acceptedQty, decimal unitCost, decimal discountPercent, decimal vatPercent) { var gross = Round(acceptedQty * unitCost); var discount = Round(gross * discountPercent / 100m); var vat = Round((gross - discount) * vatPercent / 100m); return (gross, discount, vat, gross - discount + 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."); } }