76 lines
2.4 KiB
C#
76 lines
2.4 KiB
C#
namespace ROLAC.API.Services.Disbursement;
|
|
|
|
/// <summary>
|
|
/// Converts a monetary amount to the English words used on a check, e.g.
|
|
/// 1234.56 → "One Thousand Two Hundred Thirty-Four and 56/100 Dollars".
|
|
/// Pure and dependency-free so it is easily unit-tested.
|
|
/// </summary>
|
|
public static class AmountToWords
|
|
{
|
|
private static readonly string[] Ones =
|
|
[
|
|
"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine",
|
|
"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen",
|
|
"Seventeen", "Eighteen", "Nineteen",
|
|
];
|
|
|
|
private static readonly string[] Tens =
|
|
[
|
|
"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety",
|
|
];
|
|
|
|
// index 1.. → 10^(3*index)
|
|
private static readonly string[] Scales = ["", "Thousand", "Million", "Billion", "Trillion"];
|
|
|
|
public static string Convert(decimal amount)
|
|
{
|
|
if (amount < 0) amount = 0m;
|
|
// Round half-up to cents.
|
|
amount = Math.Round(amount, 2, MidpointRounding.AwayFromZero);
|
|
|
|
var dollars = (long)Math.Floor(amount);
|
|
var cents = (int)Math.Round((amount - dollars) * 100m, MidpointRounding.AwayFromZero);
|
|
|
|
var words = dollars == 0 ? "Zero" : ThreeDigitGroupsToWords(dollars);
|
|
return $"{words} and {cents:00}/100 Dollars";
|
|
}
|
|
|
|
private static string ThreeDigitGroupsToWords(long n)
|
|
{
|
|
// Split into groups of three digits, low to high.
|
|
var groups = new List<int>();
|
|
while (n > 0) { groups.Add((int)(n % 1000)); n /= 1000; }
|
|
|
|
var parts = new List<string>();
|
|
for (var i = groups.Count - 1; i >= 0; i--)
|
|
{
|
|
if (groups[i] == 0) continue;
|
|
var group = HundredsToWords(groups[i]);
|
|
var scale = Scales[i];
|
|
parts.Add(string.IsNullOrEmpty(scale) ? group : $"{group} {scale}");
|
|
}
|
|
return string.Join(" ", parts);
|
|
}
|
|
|
|
private static string HundredsToWords(int n)
|
|
{
|
|
var parts = new List<string>();
|
|
if (n >= 100)
|
|
{
|
|
parts.Add($"{Ones[n / 100]} Hundred");
|
|
n %= 100;
|
|
}
|
|
if (n >= 20)
|
|
{
|
|
var t = Tens[n / 10];
|
|
var o = n % 10;
|
|
parts.Add(o == 0 ? t : $"{t}-{Ones[o]}");
|
|
}
|
|
else if (n > 0)
|
|
{
|
|
parts.Add(Ones[n]);
|
|
}
|
|
return string.Join(" ", parts);
|
|
}
|
|
}
|