Money
Специальный класс-обёртка для семантически-корректной работы с денежными суммами.
Хранит информацию о валюте и сумме с точностью, соответствующей минимальной единицей валюты. Предоставляет методы
для операций с денежными суммами с "правильной" точностью и без проблем, связанных с хранением дробных значений в
переменных с плавающей запятой.
Экземплярами класса Money представлены runtime-значения полей heap-таблиц, объявленных через
Heap. Money.
Класс Money может быть использован для удобной работы с денежными суммами вне контекста хипа.
Применение / сигнатура
import { Money } from '@app/heap'
const moneyVal = new Money(amount, currency)
Свойства и методы
-
constructor(amount: number, currency: Currency)
constructor(moneyLike: { amount: number, currency: Currency })
constructor(money: Money)
constructor(serialized: [amount: number, currency: Currency])
Конструктор класса. Принимает на вход как другой экземплярMoney, так и другие форматы.-
amount:
number
сумма в указанной валюте. -
currency:
Currency
стрёхбуквенный международный код валюты (ISO 4217).
Сумма может быть передана с любой точностью, но всегда округляется до количества знаков после запятой,
указанного в стандарте ISO 4217 для выбранной валюты (используется метаинформация о валюте из встроенной в JS
подсистемы Intl.
Округление производится по правилу
"half away from zero". -
-
amount:
number
Количество (сумма) валюты, хранящееся в данном экземпляре. Хранится в виде дробного числа с точностью,
соответствующей требованиям валюты по стандарту ISO 4217 (для большинства валют - это 2 знака). -
currency:
Currency
Строка с трёхбуквенным международным кодом валюты (ISO 4217).
Арифметические операции
-
add(summand: Money):
Money
Операция сложения. Прибавляет переданную денежную сумму к текущей и возвращает результат в виде нового
экземпляра Money.- При попытке сложить две разные валюты будет брошено исключение.
- Операция производится с целочисленными значениями и не подвержена проблемам, связанным с операциями над
числами с плавающей запятой. - Результат округляется в соответствии с правилами для валюты, описанными выше.
- summand:
Money
Слагаемое - денежная сумма, которая должна быть прибавлена к текущей.
-
substract(subtracted: Money):
Money
Операция вычитания. Вычитает переданную денежную сумму из текущей и возвращает результат в виде нового
экземпляра Money.- При попытке вычесть валюту, отличную от уменьшаемого, будет брошено исключение.
- Операция производится с целочисленными значениями и не подвержена проблемам, связанным с операциями над
числами с плавающей запятой. - Результат округляется в соответствии с правилами для валюты, описанными выше.
- subtracted:
Money
Вычитаемое - денежная сумма, на которую нужно уменьшить текущую.
-
multiply(multiplier: number):
Money
Операция умножения. Умножает текущую сумму на заданный множитель и возвращает результат в виде нового
экземпляра Money с исходной валютой.- Операция производится с целочисленными значениями и не подвержена проблемам, связанным с операциями над
числами с плавающей запятой. - Результат округляется в соответствии с правилами для валюты, описанными выше.
- multiplier:
number
Множитель - любое дробное или целое число.
- Операция производится с целочисленными значениями и не подвержена проблемам, связанным с операциями над
-
divide(divider: number):
Money
Операция деления. Делит текущую сумму на заданный делитель и возвращает результат в виде нового экземпляра
Money с исходной валютой.- Операция производится с целочисленными значениями и не подвержена проблемам, связанным с операциями над
числами с плавающей запятой. - Результат округляется в соответствии с правилами для валюты, описанными выше.
- divider:
number
Делитель - любое дробное или целое число, кроме нуля.
- Операция производится с целочисленными значениями и не подвержена проблемам, связанным с операциями над
Другие методы
-
format(ctx: app. Ctx, options?: MoneyFormatOptions):
string
Возвращает строку с денежной суммой, отформатированной с помощью
[Number.toLocaleString()](Правила локализации (по правилам какой страны/языка форматировать валюту) берутся из переданного контекста.
-
ctx: app. Ctx
Контекст запроса, из которого метод "узнаёт" - какой код локали (в форматеen-US) использовать
в конструктореIntl.NumberFormat. -
options:
{style,
currencyDisplay,
signDisplay,
currencySign,
useGrouping,
minimumIntegerDigits,
minimumFractionDigits,
maximumFractionDigits,
minimumSignificantDigits,
maximumSignificantDigits}
Параметры форматирования. Поддерживаются почти все параметры Intl.NumberFormat.
Параметрcurrencyне поддерживается, поскольку всегда подставляется автоматически из валюты,
хранящейся в экземпляре Money.-
style:
'currency' | 'decimal'(по умолчанию'currency')
Выводить в виде обычного числа или числа с валютой. -
currencyDisplay:
'symbol' | 'code' | 'name' | 'narrowSymbol'
(по умолчанию'symbol')
Как выводить знак валюты, еслиstyle=currency:'symbol'- локализованный символ валюты ($, €, ₽)'code'- трёхбуквенный международный код (USD, EUR, RUB)'name'- локализованное название валюты (dollar, euro, рубль)'narrowSymbol'- сокращённый символ валюты - имеет смысл для некоторых валют, которые могут иметь
один и тот же символ - например в локалиen-AUавстралийский и американский доллары будут выводиться
по-разному ($ и USD) дляsymbolи одинаково ($ и $) дляnarrowSymbol. Также в некоторых локалях
по умолчанию используется международный код для иностранных валют,narrowSymbolфорсирует использование
короткого символа.
-
signDisplay:
'always' | 'auto' | 'exceptZero' | 'never'
(по умолчанию'auto')
Когда выводить знак числового значения.'always'- всегда (для нуля+)'auto'- только для положительных значений'exceptZero'- для всего кроме нуля'never'- не показывать знак
-
currencySign:
'standard' | 'accounting'(по умолчанию'standard')
Каким образом форматировать отрицательные значения.'standard'- использовать знак минус (-)'accounting'- во многих локалях в этом режиме отрицательные значения выводятся в круглых скобках
без знака минус (например в en-US(₽1,234.00))
-
useGrouping:
'auto' | true | false(по умолчанию'auto')
Использовать ли разделитель тысячных разрядов.'auto'- в соответствие с настройками локалиtrue- всегдаfalse- никогда
-
minimumIntegerDigits:
number(по умолчанию1)
Минимальное количество выводимых цифр (от 1 до 21) в целочисленной части выводимой суммы. Если количество
значимых знаков меньше этого числа, то оно "добивается" нулями слева до нужного количества.Свойство игнорируется, если явно заданы minimumSignificantDigits или
maximumSignificantDigits. -
minimumFractionDigits:
number
(по умолчанию - количество дробных знаков для валюты из ISO 4217)
Минимальное количество выводимых цифр (от 0 до 20) в дробной части выводимой суммы. Если количество
значимых знаков меньше этого числа, то оно "добивается" нулями справа до нужного количества.Свойство игнорируется, если явно заданы minimumSignificantDigits или
maximumSignificantDigits. -
maximumFractionDigits:
number
(по умолчаниюmax(minimumFractionDigits, количество дробных знаков для валюты из ISO 4217))
Максимальное количество выводимых цифр (от 0 до 20) в дробной части выводимой суммы. Если количество
значимых знаков больше этого числа, то оно округляется по правилу half-away-from-zero.Не может быть меньше, чем minimumFractionDigits.
Свойство игнорируется, если явно заданы minimumSignificantDigits или
maximumSignificantDigits. -
minimumSignificantDigits:
number(по умолчанию1)
Минимальное количество выводимых цифр (от 1 до 21) в общем в целочисленной и в дробной части выводимой
суммы. Если общее количество значимых знаков меньше этого числа, то оно "добивается" нулями в дробной
части справа до нужного количества.Использование этого свойства отлючает действие minimumIntegerDigits,
minimumFractionDigits и maximumFractionDigits. -
maximumSignificantDigits:
number(по умолчанию21)
Максимальное количество выводимых цифр (от 1 до 21) в общем в целочисленной и в дробной части выводимой суммы.
Если общее количество значимых знаков больше этого числа, то оно округляется по правилу half-away-from-zero,
таким образом, чтобы количество значимых цифр начиная от старшего разряда до последней ненулевой цифры
не превышало заданного значения. Округление действует не только для дробной части, но и для целочисленной:
например сумма 1251 с maximumSignificantDigits=2 превратится в 1300.Не может быть меньше, чем minimumSignificantDigits.
Использование этого свойства отлючает действие minimumIntegerDigits,
minimumFractionDigits и
maximumFractionDigits.
-
-
Примеры
Добавление бонуса, начисление процентов и вывод результата
const Balances = Heap.Table('balances', {
amount: Heap.Money(),
})
async function addBonusPlus10Percent(
ctx: app.Ctx, balanceId: string, bonus: Money,
): Promise<typeof Balances.T> {
const balance = await Balances.getById(ctx, balanceId)
return Balances.update({
id: balance.id,
amount: balance.amount.add(bonus).multiply(1.1),
})
}
const balanceWithBonus = await addBonusPlus10Percent(
ctx, req.params.id, new Money(req.params.bonus, 'USD'),
)
ctx.console.log('new balance', balanceWithBonus.amount.format(ctx, {
currencyDisplay: 'narrowSymbol',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})
