Разделы и статьи

MoneyToTextEx

Описание настроек MoneyToTextEx
 
Настройка предназначена для вывода числительных прописью в печатных формах на определённом языке.
1

2
Название – краткое название функции.
Наименование – полное название функции.
Синтаксис функции — параметры вызова функции.
Описание – краткое описание функции.
Язык – язык локализации, для которого будет работать функция, т.е. на каком языке запущено и используется само ПО.
Исходный код – текст скрипта.
Текущая версия – номер текущей версии.
 
Внимание! Описанный далее код функции является примером реализации для русского языка. Для других языков он может быть изменён в соответствии с особенностями самого языка
(например, отсутствие падежей, родов числительных в английском языке).

3
Вспомогательная функция округления с заданной точностью

function RoundDouble(AValue: Double; FracLen: Integer): Double;

var

 D10: array[0..10] of Double;

begin

 D10[0]  := 1;

 D10[1]  := 10;

 D10[2]  := 100;

 D10[3]  := 1000;

 D10[4]  := 10000;

 D10[5]  := 100000;

 D10[6]  := 1000000;

 D10[7]  := 10000000;

 D10[8]  := 100000000;

 D10[9]  := 1000000000;

 D10[10] := 10000000000.0;

 Result := (Round(AValue * D10[FracLen] + 1 / D10[FracLen + 1])) / D10[FracLen];

end;

Вспомогательная функция округления до второго знака после запятой

function RoundMoney(ASum: Double): Double;

begin

 Result := RoundDouble(ASum, 2)

end;

Вспомогательная функция копирования части строки

function RightStr(S: string; N: Integer): string;

begin

 if (N <= 0) then

   N := Length(S) + N;

 Result := Copy(S, Length(S) - N + 1, N);

end;

Вспомогательная функция копирования части строки и подстановки заданного символа слева

function PadLCh(S: string; C: Char; N: Byte; ExactLen: Boolean = True): string;

begin

 if ExactLen then

   Result := RightStr(S,N)

 else

   Result := S;

 while Length(Result) < N do

   Result := C + Result;

end;

Основная функция преобразования денежной суммы в сумму прописью

Входные параметры:

Sum — число для преобразования

Param_Language — язык локализации

Currency — код валюты

function MoneyToTextEx (Sum: Double; Param_Language: string; Currency: string): string;

var

 aOnes, aTeens, aTens, aHundreds, aTrios, aTrioFemale, aTrioPostfixes, aUnits,

   aUnitPostfixes, aUnitFemale, aPostfixes, aPostfix: Variant;

КЛАССЫ ЧИСЕЛ

Первый класс (класс единиц) – сотни, десятки, единицы

Второй класс (класс тысяч) – сотни тысяч, десятки тысяч, единицы тысяч

Третий класс (класс миллионов) – сотни миллионов, десятки миллионов, единицы миллионов

… и т.д.

Функция преобразования трехзначного числа в строку с добавлением класса чисел или значения валюты

 function TrioToText(Trio: Integer; TrioNo: Integer): string;

 var

   i1, i2, i3, PostfixNo: Integer;

   Female: Boolean;

 begin

   Result := '';

   if( Trio = 0) then

     if TrioNo > 0 then Exit; - если число [0] и «не копейки», то выходим из функции («ноль миллионов», «ноль тысяч» не пишем)

   i1 := (Trio mod 10); - выделяем единицы

   i2 := (Trio div 10) mod 10; - выделяем десятки

   i3 := (Trio div 100) mod 10; - выделяем сотни

   if (TrioNo > -1) then - если «не копейки»

   begin

     Result := aHundreds[i3]; - берем сотню из массива сотен

     if (i2 = 1) then – если второй десяток сотни (десять, одиннадцать...)

        Result := Trim(Result + ' ' + aTeens[i1]) - то берем из массива второго десятка по значению единиц

     else - если не второй десяток сотни (т.е. двадцать..., тридцать...,..)

     begin

       Result := Trim(Result + ' ' + aTens[i2]); - берем из массива десятков по значению десятка

       if (i1 in [1, 2]) then – если единица 1 или 2 (в русском языке «один» и «два» для женского рода это - «одна» и «две», остальные единицы идентичны для М и Ж: «три», «четыре»... «десять»)

       begin

         if (TrioNo > 0) then - если класс числа более первого (тысячи, миллионы, миллиарды и т.д.)

           Female := aTrioFemale[TrioNo] - берем признак женского рода в заданном массиве женских родов для классов чисел более первого (тысячи, миллионы, миллиарды и т.д.), т.е. если сюда пришел второй класс, в русском языке «тысяча» женского рода.

         else

           Female := aUnitFemale[1 – TrioNo] - если первый класс или «копейки», смотрим значение женского рода в массиве женских родов, заданном для конкретной валюты (рубль мужского рода, копейка женского рода; доллар мужского рода, цент мужского рода)

       end

       else

         Female := False; - если единица не 1 или 2, то мужской род («три», «четыре»...)

       if not Female then

         Result := Trim(Result + ' ' +  aOnes[i1]) - если мужской род, то берем единицу из массива единиц напрямую (индекс совпадает со значением)

       else

         Result := Trim(Result + ' ' + aOnes[9 + i1]); - если женский род, то берем единицу из массива единиц с инкрементом (для русского языка это будет 1 или 2, соответственно 9+1 = 10, в массиве единиц с индексом 10 идет женский род «одна»)

     end;

   end

   else - если «копейки»

     Result := PadLCh(IntToStr(Trio), '0', 2); - если «копейки», то сумму прописью не пишем, а к однозначному числу добавляем ноль слева (было 5, стало 05; было 55, стало 55)

После выполнения вышеуказанной части кода процедуры мы получаем одно-, двух- или трехзначное число прописью (451 = «четыреста пятьдесят один» для мужского рода класса чисел или «четыреста пятьдесят одна» для женского рода класса чисел).

   if (TrioNo > 0) then - если класс числа более первого (тысячи, миллионы, миллиарды и тд)

     Result := Trim(Result + ' ' + aTrios[TrioNo]) - берем значение из массива классов чисел напрямую

   else

     Result := Trim(Result + ' ' + aUnits[1 – TrioNo]); - если класс менее первого, то берем значение из массива валюты («рубл», «копе»)

После выполнения вышеуказанной части кода процедуры мы получаем число прописью + либо корень названия класса чисел, либо корень названия валюты («четыреста пятьдесят одна тысяч» либо «четыреста пятьдесят один рубл»).

   PostfixNo := 1; - по умолчанию берём индекс массива окончаний 1 (тысячА/копеЙКА/рублЬ/миллион)

   if (Param_Language = 'Russian') then

   begin

     PostfixNo := 3; - если язык русский по умолчанию, берём индекс массива окончаний 3 (рублЕЙ/копеЕК/миллионОВ/тысяч)

     if not (i2 = 1) then - если не второй десяток сотни, то определяем индекс массива окончаний

     begin - смотрим на единицы

       if (i1 = 1) then - если единица равна 1

         PostfixNo := 1 - берем индекс массива окончаний 1 (тысячА/копеЙКА/рублЬ/миллион)

       else

       if (i1 in [2, 3, 4]) then - если единица равна 2 или 3 или 4

         PostfixNo := 2; - берём индекс массива окончаний 2 (тысячИ/копеЙКИ/рублЯ/миллионА)

     end;

   end

   else

Для других языков

   if (Param_Language = 'Lithuanian') then

   begin

     PostfixNo := 3;

     if not (i2 = 1) then

     begin

       if (i1 = 1) then

         PostfixNo := 1

       else

       if (i1 in [2..9]) then

         PostfixNo := 2;

     end;

   end;

После определения индекса подставляем окончание.

   if (TrioNo > 0) then - для классов чисел

   begin

     aPostfix := aPostfixes[aTrioPostfixes[TrioNo]]; - определяем массив окончаний соответствующего класса чисел

     Result := Result + aPostfix[PostfixNo]; - добавляем окончание по определенному ранее индексу из соответствующего массива

   end

   else - для валют

   begin

     aPostfix := aPostfixes[aUnitPostfixes[1 – TrioNo]]; - определяем массив окончаний соответствующего значения валюты («рубл»/«копе»)

     Result := Result + aPostfix[PostfixNo];- добавляем окончание по определенному ранее индексу из соответствующего массива

   end;

 end;

Тело основной функции преобразования денежной суммы в сумму прописью

var

 I: Int64;

 F: Integer;

begin

 Result := '';

Создаем массивы и заполняем их соответствующими значениями на языке локализации, для которого будет работать функция.

Массив первого десятка сотни (единиц)

 aOnes := VarArrayCreate([0,11], varVariant);

 aOnes[0]  := '';

 aOnes[1]  := 'один';

 aOnes[2]  := 'два';

 aOnes[3]  := 'три';

 aOnes[4]  := 'четыре';

 aOnes[5]  := 'пять';

 aOnes[6]  := 'шесть';

 aOnes[7]  := 'семь';

 aOnes[8]  := 'восемь';

 aOnes[9]  := 'девять';

 aOnes[10] := 'одна';

 aOnes[11] := 'две';

Массив второго десятка сотни:

 aTeens := VarArrayCreate([0,9], varVariant);

 aTeens[0] := 'десять';

 aTeens[1] := 'одиннадцать';

 aTeens[2] := 'двенадцать';

 aTeens[3] := 'тринадцать';

 aTeens[4] := 'четырнадцать';

 aTeens[5] := 'пятнадцать';

 aTeens[6] := 'шестнадцать';

 aTeens[7] := 'семнадцать';

 aTeens[8] := 'восемнадцать';

 aTeens[9] := 'девятнадцать';

Массив десятков:

 aTens := VarArrayCreate([0,9], varVariant);

 aTens[0] := '';

 aTens[1] := 'десять';

 aTens[2] := 'двадцать';

 aTens[3] := 'тридцать';

 aTens[4] := 'сорок';

 aTens[5] := 'пятьдесят';

 aTens[6] := 'шестьдесят';

 aTens[7] := 'семьдесят';

 aTens[8] := 'восемьдесят';

 aTens[9] := 'девяносто';

Массив сотен:

 aHundreds := VarArrayCreate([0,9], varVariant);

 aHundreds[0] := '';

 aHundreds[1] := 'сто';

 aHundreds[2] := 'двести';

 aHundreds[3] := 'триста';

 aHundreds[4] := 'четыреста';

 aHundreds[5] := 'пятьсот';

 aHundreds[6] := 'шестьсот';

 aHundreds[7] := 'семьсот';

 aHundreds[8] := 'восемьсот';

 aHundreds[9] := 'девятьсот';

Массив классов чисел:

 aTrios := VarArrayCreate([0,4], varVariant);

 aTrios[0] := '';

 aTrios[1] := 'тысяч';

 aTrios[2] := 'миллион';

 aTrios[3] := 'миллиард';

 aTrios[4] := 'триллион';

Массив признаков женского рода для классов чисел:

 aTrioFemale := VarArrayCreate([1,4], varVariant);

 aTrioFemale[1] := True;

 aTrioFemale[2] := False;

 aTrioFemale[3] := False;

 aTrioFemale[4] := False;

Множество массивов окончаний как для классов чисел, так и для каждого значения всех используемых видов валют (идентичные по значениям массивы для разных валют или классов делать не нужно, главное правильно их определить для валют и классов).

 aPostfixes := VarArrayCreate([1,8], varVariant);

 aPostfix := VarArrayCreate([1,3], varVariant);

 aPostfix[1] := 'а';

 aPostfix[2] := 'и';

 aPostfix[3] := '';

 aPostfixes[1] := aPostfix;

 aPostfix := VarArrayCreate([1,3], varVariant);

 aPostfix[1] := '';

 aPostfix[2] := 'а';

 aPostfix[3] := 'ов';

 aPostfixes[2] := aPostfix;

 aPostfix := VarArrayCreate([1,3], varVariant);

 aPostfix[1] := 'ь';

 aPostfix[2] := 'я';

 aPostfix[3] := 'ей';

 aPostfixes[3] := aPostfix;

 aPostfix := VarArrayCreate([1,3], varVariant);

 aPostfix[1] := 'йка';

 aPostfix[2] := 'йки';

 aPostfix[3] := 'ек';

 aPostfixes[4] := aPostfix;

 aPostfix := VarArrayCreate([1,3], varVariant);

 aPostfix[1] := 'ка';

 aPostfix[2] := 'ка';

 aPostfix[3] := 'ок';

 aPostfixes[5] := aPostfix;

 aPostfix := VarArrayCreate([1,3], varVariant);

 aPostfix[1] := '';

 aPostfix[2] := '';

 aPostfix[3] := '';

 aPostfixes[6] := aPostfix;

Массив соответствий классов чисел и их окончаний

 aTrioPostfixes := VarArrayCreate([1,4], varVariant);

 aTrioPostfixes[1] := 1; - для «тысяч» массив из массива массивов aPostfixes с индексом 1 ( ['а','и',''])

 aTrioPostfixes[2] := 2; - для «миллион» массив из массива массивов aPostfixes с индексом 2 ['','а','ов']

 aTrioPostfixes[3] := 2; - для «миллард» массив из массива массивов aPostfixes с индексом 2 ['','а','ов']

 aTrioPostfixes[4] := 2; - для «триллион» массив из массива массивов aPostfixes с индексом 2 ['','а','ов']

 aUnits := VarArrayCreate([1,2], varVariant); - массив корней значений валют (рубл, копе)

 aUnitPostfixes := VarArrayCreate([1,2], varVariant); - массив соответствий корней значений валют и их окончаний

 aUnitFemale := VarArrayCreate([1,2], varVariant); - массив признаков женского рода значений валют (рубль мужского рода, копейка женского рода; доллар мужского рода, цент мужского рода)

Заполняем массивы для необходимых типов валют.

 if (Currency = 'USD')  or (Currency = '') then

 begin

   aUnits[1] := 'доллар';

   aUnits[2] := 'цент';

   aUnitPostfixes[1] := 2;

   aUnitPostfixes[2] := 2;

   aUnitFemale[1] := False;

   aUnitFemale[2] := False;

 end

 else        

 if (Currency = 'RUB') or (Currency = 'RUR')   then

 begin

   aUnits[1] := 'рубл';

   aUnits[2] := 'копе';

   aUnitPostfixes[1] := 3;

   aUnitPostfixes[2] := 4;

   aUnitFemale[1] := False;

   aUnitFemale[2] := True;

   end

 else        

 if Currency = 'KGS' then

 begin

   aUnits[1] := 'сом';

   aUnits[2] := 'тыйын';

   aUnitPostfixes[1] := 6;

   aUnitPostfixes[2] := 6;

   aUnitFemale[1] := False;

   aUnitFemale[2] := False;

 end

 else        

 if Currency = 'KZT' then

 begin

   aUnits[1] := 'тенге';

   aUnits[2] := 'тиын';

   aUnitPostfixes[1] := 6;

   aUnitPostfixes[2] := 6;

   aUnitFemale[1] := False;

   aUnitFemale[2] := False;

 end

 else        

 if Currency = 'EUR' then

 begin

   aUnits[1] := 'евро';

   aUnits[2] := 'цент';

   aUnitPostfixes[1] := 6;

   aUnitPostfixes[2] := 2;

   aUnitFemale[1] := False;

   aUnitFemale[2] := False;

 end;

 Sum := RoundMoney(Abs(Sum)); - округляем исходное число

 I := Trunc(Sum); - выделяем целую часть(рубли, доллары...)

 F := Round(Sum * 100) mod 100; - выделяем дробную часть (копейки, центы...)

 Result := Trim(Result + ' ' + TrioToText((I div 1000000000) mod 1000, 3)); - выделяем и преобразовываем в пропись миллиарды

 Result := Trim(Result + ' ' + TrioToText((I div 1000000) mod 1000, 2));- выделяем и преобразовываем в пропись миллионы

 Result := Trim(Result + ' ' + TrioToText((I div 1000) mod 1000, 1));- выделяем и преобразовываем в пропись тысячи

 Result := Trim(Result + ' ' + TrioToText(I mod 1000, 0));- выделяем и преобразовываем в пропись сотни

 Result := Trim(Result + ' ' + TrioToText(F , -1)); - преобразовываем в пропись дробную часть

 Result[1] := UpperCase(Result[1])[1]; - результат пишем с большой буквы

end;

begin

end
 
После перевода результат можно проверить через кнопку 4.

5
Sum – число для преобразования.

Param_Language – язык локализации.
Currency – код валюты.

 
Пример 1

Программа используется на русском языке, но числительные прописью должны отображаться на другом языке (вместо «рубль» и «копейка», например, «тугрик» и «тугрятик»).

1.Shelter v.2 \ Настройки \ Справочники \ Услуги и оплаты \ Валюты: заменить Рубли на Тугрики.
*В коде важен регистр букв!

6

2.Shelter v.2 \ Настройки \ Настройки отчётов \ Внешние функции: открыть внешнюю функцию для программы на русском языке (по умолчанию это - №1).

7

3.Внести изменения в исходный код:

8

Найти раздел, например, KZT. Скопировать данные из него и вставить следующим разделом ниже.
Внести изменения: KZT -> TUG, тенге -> тугрик, тиын -> тугрятик, массив для окончаний указать 7 для обоих aUnits (базово всего 6, т.е. нужно будет добавить новый).

else        

 if Currency = 'TUG' then

 begin

   aUnits[1] := 'тугрик';

   aUnits[2] := 'тугрятик';

   aUnitPostfixes[1] := 7;

   aUnitPostfixes[2] := 7;

   aUnitFemale[1] := False;

   aUnitFemale[2] := False;

 end

В разделе массивов окончаний создать новый (в нашем примере - 7) и внести изменения по окончаниям и номеру массива.

aPostfix := VarArrayCreate([1,3], varVariant);

 aPostfix[1] := '';

 aPostfix[2] := 'а';

 aPostfix[3] := 'ов';

 aPostfixes[7] := aPostfix;

*Если массив с такими значениями уже присутствует (например, массив 2 имеет те же окончания, что мы создали в массиве 7), то можно новый не создавать, а установить:

aUnitPostfixes[1] := 2;

aUnitPostfixes[2] := 2;

Найти запись массива массивов окончаний и установить максимально 7, вместо 6.

aPostfixes := VarArrayCreate([1,7], varVariant);

4.Произвести проверку результата изменений через кнопку [Проверить]:
Sum – числительное с десятыми или сотыми (разделитель – точка!).
Param_Language – Russian (язык программы, для которого настроена валюта).
Currency – TUG (валюта, в которой нужно числительное изобразить прописью).

[Сохранить] -> Получить результат.

9