Иногда в разрабатываемых приложениях стоит задача представить данные на печатной форме или отчете. Особенно часто эта задача возникает в приложениях бухгалтерской направленности, где существуют формы строгой отчетности. Для решения таких задач используют генераторы отчетов: FastReport.Net, Crystal Reports и другие.
Кто хоть раз имел дело с бухгалтерией, наверняка знает, что на некоторых формах требуется выводить суммы или числа прописью в специально отведенных для этого полях. На самом деле, это далеко не тривиальная проблема.
В компании, где я работаю, используется FastReport.Net, поэтому именно на его примере посмотрим, как можно добиться нужного результата.
Как обычно, задачу можно решить несколькими способами.
Способ 1: Пишем свою функцию
Как ни странно, именно такой вариант решения я видел в приложениях, которые мне приходится поддерживать. Замечу, что этот способ подойдет тем, кто любит изобретать велосипеды :). Пишем на C# примерно следующее (нарыл в интернете):
////// Класс отображения суммы прописью. /// 3 варианта - рубли, доллары и просто для использования /// других любых единиц (вагоны, мешки и т.п.) /// -------------------------------------- /// Автор - Глеб Уфимцев (dnkvpb@nm.ru) /// public class NumByWords { public static string RurPhrase(decimal money) { return CurPhrase(money, "рубль", "рубля", "рублей", "копейка", "копейки", "копеек"); } public static string UsdPhrase(decimal money) { return CurPhrase(money, "доллар США", "доллара США", "долларов США", "цент", "цента", "центов"); } public static string NumPhrase(ulong Value, bool IsMale) { if (Value == 0UL) return "Ноль"; string[] Dek1 = { "", " од", " дв", " три", " четыре", " пять", " шесть", " семь", " восемь", " девять", " десять", " одиннадцать", " двенадцать", " тринадцать", " четырнадцать", " пятнадцать", " шестнадцать", " семнадцать", " восемнадцать", " девятнадцать" }; string[] Dek2 = { "", "", " двадцать", " тридцать", " сорок", " пятьдесят", " шестьдесят", " семьдесят", " восемьдесят", " девяносто" }; string[] Dek3 = { "", " сто", " двести", " триста", " четыреста", " пятьсот", " шестьсот", " семьсот", " восемьсот", " девятьсот" }; string[] Th = { "", "", " тысяч", " миллион", " миллиард", " триллион", " квадрилион", " квинтилион" }; string str = ""; for (byte th = 1; Value > 0; th++) { ushort gr = (ushort)(Value % 1000); Value = (Value - gr) / 1000; if (gr > 0) { byte d3 = (byte)((gr - gr % 100) / 100); byte d1 = (byte)(gr % 10); byte d2 = (byte)((gr - d3 * 100 - d1) / 10); if (d2 == 1) d1 += (byte)10; bool ismale = (th > 2) || ((th == 1) && IsMale); str = Dek3[d3] + Dek2[d2] + Dek1[d1] + EndDek1(d1, ismale) + Th[th] + EndTh(th, d1) + str; } } str = str.Substring(1, 1).ToUpper() + str.Substring(2); return str; } #region Private members private static string CurPhrase(decimal money, string word1, string word234, string wordmore, string sword1, string sword234, string swordmore) { money = decimal.Round(money, 2); decimal decintpart = decimal.Truncate(money); ulong intpart = decimal.ToUInt64(decintpart); string str = NumPhrase(intpart, true) + " "; byte endpart = (byte)(intpart % 100UL); if (endpart > 19) endpart = (byte)(endpart % 10); switch (endpart) { case 1: str += word1; break; case 2: case 3: case 4: str += word234; break; default: str += wordmore; break; } byte fracpart = decimal.ToByte((money - decintpart) * 100M); str += " " + ((fracpart < 10) ? "0" : "") + fracpart.ToString() + " "; if (fracpart > 19) fracpart = (byte)(fracpart % 10); switch (fracpart) { case 1: str += sword1; break; case 2: case 3: case 4: str += sword234; break; default: str += swordmore; break; }; return str; } private static string EndTh(byte ThNum, byte Dek) { bool In234 = ((Dek >= 2) && (Dek <= 4)); bool More4 = ((Dek > 4) || (Dek == 0)); if (((ThNum > 2) && In234) || ((ThNum == 2) && (Dek == 1))) return "а"; else if ((ThNum > 2) && More4) return "ов"; else if ((ThNum == 2) && In234) return "и"; else return ""; } private static string EndDek1(byte Dek, bool IsMale) { if ((Dek > 2) || (Dek == 0)) return ""; else if (Dek == 1) { if (IsMale) return "ин"; else return "на"; } else { if (IsMale) return "а"; else return "е"; } } #endregion }
Затем регистрируем этот класс в отчете:
Type ftype = typeof(NumByWords); MethodInfo mi = ftype.GetMethod("NumPhrase"); RegisteredObjects.AddFunction(mi, "NumPhrase");
Чтобы код выше заработал, нужно подключить:
using FastReport.Utils;
А теперь используем там, где нам это нужно:
NumPhrase(1987, true) = "Одна тысяча девятьсот восемьдесят семь рублей"
Способ 2: Используем встроенную в FastReport функцию
Да-да. Если заглянуть в документацию, среди функций конвертирования можно обнаружить функцию ToWordsRu. Это функция очень интересная и гибкая. Она имеет три перегрузки:
string ToWordsRu(object value) - конвертирует числовое значение value в сумму прописью на русском
ToWordsRu(1987.25) = "Одна тысяча девятьсот восемьдесят семь рублей 25 копеек"
string ToWordsRu(object value, string currencyName) - конвертирует числовое значение value в сумму прописью на русском. Используется валюта, заданная в параметре currencyName. Возможные значения этого параметра: "RUR", "UAH", "USD", "EUR".
ToWordsRu(1987.25, "EUR") = "Одна тысяча девятьсот восемьдесят евро 25 евроцентов"
string ToWordsRu(object value, bool male, string one, string two, string many) - конвертирует целочисленное значение value в число прописью на русском. В параметре male надо указать true, если существительное - мужского рода. В параметрах one, two и many задаются словоформы для чисел 1, 2 и 5.
// слово "страница" женского рода - параметр male = false ToWordsRu(124, false, "страница", "страницы", "страниц") = "Сто двадцать четыре страницы" // слово "лист" мужского рода - параметр male = true ToWordsRu(124, true, "лист", "листа", "листов") = "Сто двадцать четыре листа"
Если нужно просто вывести число прописью без каких-либо исчисляемых объектов, то можно сделать так:
ToWordsRu(124, true, "", "", "") = "Сто двадцать четыре"
Именно так стоит поступать при использовании, например, фиксированных бухгалтерских бланков, в которых нужно вписать только сумму прописью, а единицы уже предусмотрены самой формой ("итого:________________руб. ___ коп."). Кстати, здесь главное не забыть подставить целую часть числа, например, с помощью функции Truncate(decimal value):
ToWordsRu(Truncate(124.55), true, "", "", "") = "Сто двадцать четыре"
Как видно, во втором способе используются только встроенные возможности FastReport.Net. Тем не менее, если в разрабатываемом приложении необходимо выводить числа прописью не только в генерируемых отчетах, но и где-нибудь на форме, то придется воспользоваться кодом из первого способа.
Другие варианты решения задачи предлагайте в комментариях.
Здравствуйте, в программировании не силен, есть программа в ней отчеты формируются в Fastreport версия 4.15, в списке стандартных функций нет такой функции ToWordsRu
ОтветитьУдалитьКак можно ее туда добавить?
"Затем регистрируем этот класс в отчете:" - можно вот здесь поподробней?
ОтветитьУдалитьМожно ли этот класс в ReportViewer подключить?