Часто для вывода в отчёте денежной суммы дробное число нужно оформить нужным образом, с разделением на нгултрумы и чертумы (или, скажем, рубли и копейки), также с пробелом или запятой между группами разрядов. Предлагается многофункциональная функция для осуществления такого форматирования.

function FormatFloat(Value, DecimalMark, ThousandSeparator, Prefix, Postfix, NoZero){
        DecimalMark = IsNull(DecimalMark, ',');
        ThousandSeparator = IsNull(ThousandSeparator, ' ');
        Prefix = IsNull(Prefix, '');
        Postfix = IsNull(Postfix, '');
        var Minus = (Math.abs(Value) != Value) ? ' - ' : '';
        Value = Math.abs(Value);
        var Result = '';
        var Cop = Math.round((Value - Math.floor(Value))*100);
        if (Cop.toString().length > 1 || !!NoZero) {
                Result = Result + DecimalMark + Cop.toString();
        } else {
                Result = Result + DecimalMark + '0' + Cop.toString();
        }
        var IsFirstIteration = true;
       
        while (true) {  
                var Thousand = Math.floor(Value) - Math.floor(Value / 1000) * 1000;
                if (IsFirstIteration) {
                        Result = Thousand + Result;
                        IsFirstIteration = false;
                } else {
                        Result = Thousand + ThousandSeparator + Result;        
                }
               
                Value = Math.floor(Value / 1000);
                if (Value == 0) {
                        return Prefix +Minus + Result + Postfix;
                } else {
                        if (Thousand 10) {
                                Result = '00' + Result;
                        } else
                                if (Thousand 100) {
                                        Result = '0' + Result;                         
                                }
                }
               
        }              
}

Параметры:

Value — исходное дробное число.
DecimalMark — десятичная запятая, точка или название валюты на её месте.
ThousandSeparator — пробел или запятая между единицами, тысячами, миллионами и т.д.
Prefix — название валюты перед числом.
Postfix — название валюты или разменной монеты после числа.
NoZero — если true, то 1 копейка, иначе — 01 копейка.

Примеры использования:

FormatFloat(-12345.67)//- 12 345,67
FormatFloat(1000003.62, ' руб. ', null, null, ' коп.')// 1 000 003 руб. 62 коп.

Также сходную задачу решает "коробочная" функция AmountToStr (скрипт scr_ConvertUtils), переводящая число в его написание словами. А если нужно ещё и склонять слово (1 копейка, 2 копейки,5 копеек), можно использовать соответствующий механизм.

Нравится

Поделиться

0 комментариев
Показать все комментарии

Здравствуй, читатель. Давно мы не встречались с тобой.
Хочу поведать тебе об одной ошибке, выявление причины которой у меня заняло немало времени и дабы не наступать на эти грабли снова, внимай же голосу моему.

Если ты по некой неосторожности датафилду с типом Float присвоишь значение NaN, то система тебе ничего не скажет плохого. Однако, когда ты скажешь датасету: "Post!", система встретит тебя ошибкой вида:

TSObjectLibrary.DBDataset: Error posting record. Original error message: The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter 20 (""): The supplied value is not a valid instance of data type float. Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision

Эта ошибка возникает на стороне клиента, так что в профайлере ты ничего не увидешь.

Если ты, читатель, думаешь, что получить значение NaN очень сложно, то это не так. Достаточно написать:

var a = Dataset.Values('Subject');
var b = Dataset.Values('Divisor');
if (b != 0) {
   Dataset.Values('Result') = a / b;
};

Уважаемый написавший сей код не затруднил себя проверить, что a и b неравны null и в итоге при некоторых обстоятельствах (когда второй операнд = null) получил NaN. (опытный читатель воскликнет, что надо было использовать ValAsFloat вместо Values).

Спасибо за внимание и до новых встреч в эфире.

Нравится

Поделиться

12 комментариев

"Встреча с неведомым" и как ее избежать))
по идее ругаться система должна была еще при попытке присвоения NaN в тот самый датафилд - может стоит добавить отработку данного события этаким хитрым образом на уровень самого объекта Dataset, чтобы не ловить потом хитрые сообщения?

Нифига не понятно, но стиль - прекрасен!

"Репко Артём" написал:(опытный читатель воскликнет, что надо было использовать ValAsFloat вместо Values).

Я так понимаю, ValAsFloat нужно только в первых двух строчках? ;).

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

"Лабьяк Олег Игоревич" написал:Я так понимаю, ValAsFloat нужно только в первых двух строчках? ;).

Да, в последней строчке необязательно, хотя и не помешает.

При использовании метода ValAsFloat() нужно быть уверенным что в DataField имеет тип Integer или Float.

"Кривонос Максим" написал:При использовании метода ValAsFloat() нужно быть уверенным что в DataField имеет тип Integer или Float.

Более того, нужно быть увереным, что переменная Dataset является объектом, реализующим интерфейс IDataset.

Артём, +1 ))).

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Я был не прав, тип DataField'a не обязательно должен быть Integer или Float, главное чтоб его значение было подходящим.

Воспроизвел ситуацию, но сообщение появилось немного другое:
TSObjectLibrary.DBDataset: Error posting record. Original error message: A floating point exception occurred in the user process. Current transaction is canceled

Кстати, для воспроизведения хватило бы написать:

Dataset.Values('Result') = NaN;

А в текущем примере если немного изменить, то ошибка бы не появилась:

var a = Dataset.Values('Subject');
var b = Dataset.Values('Divisor');
if (b) {
   Dataset.Values('Result') = a / b;
};

Думаю какую проверку нужно добавить в ядро. Если передают NaN конвертировать в null?

"Александр Кравчук" написал:Dataset.Values('Result') = NaN;

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

"Александр Кравчук" написал:Думаю какую проверку нужно добавить в ядро. Если передают NaN конвертировать в null?

Я бы лучше исключение генерировал. Вряд ли человек, написавший Dataset.Values('a') = 5 + a / b (где b равно null), ожидает в результате увидеть null в поле.

"Репко Артём" написал:Я бы лучше исключение генерировал.

Согласен, наверное так и сделаю.

Дякую Артем!
Ніколи не знаєш, коли така інформація стане корисною. І ось цей час настав.

Показать все комментарии