/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/
const math = require('utils/math');
const User = require('core/user');
const Utils = require('utils/utils');
/**
* Currency module provides utility methods for working with currencies.
*
* @module Utils/Currency
*/
module.exports = {
/**
* Gets the base currency id.
*
* @return {string} The base currency id.
*/
getBaseCurrencyId: function() {
return SUGAR.App.metadata.getBaseCurrencyId();
},
/**
* Gets the system's base currency.
*
* @return {Object} The base currency data.
*/
getBaseCurrency: function() {
var currId = SUGAR.App.metadata.getBaseCurrencyId(),
currencyObj = SUGAR.App.metadata.getCurrency(currId);
// add currency_id to returned data
currencyObj.currency_id = currId;
return currencyObj;
},
/**
* Returns a map of currency IDs to the result of applying the
* given Handlebars template to them.
*
* Example for the `template` param:
* ```
* getCurrenciesSelector(Handlebars.compile('{{symbol}} ({{iso}})'));
* ```
*
* @param {Function} template How to format the values returned.
* @return {Object} Map from currency IDs to formatted currency data.
*/
getCurrenciesSelector: function(template) {
var currencies = {};
_.each(SUGAR.App.metadata.getCurrencies(), function(currency, id) {
currencies[id] = template(currency);
});
return currencies;
},
/**
* Gets the symbol for the given currency ID.
*
* @param {string} currencyId Currency identifier.
* @return {string} The currency display symbol (e.g. "$").
*/
getCurrencySymbol: function (currencyId) {
var currency = SUGAR.App.metadata.getCurrency(currencyId);
return currency ? currency.symbol : '';
},
/**
* Formats a currency amount.
*
* @param {number} amount The amount to be formatted.
* @param {string} [currencyId] The currency id to be used. If not
* specified, the system default will be used.
* @param {number} [decimalPrecision=2] The number of digits for
* decimal precision.
* @param {string} [numberGroupingSeparator=','] The thousands separator.
* @param {string} [decimalSeparator='.'] The decimal separator (string
* between number and decimal digits).
* @param {string} [symbolSeparator=''] The string between the symbol and
* the amount.
* @return {string} The formatted currency amount.
*/
formatAmount: function(
amount,
currencyId,
decimalPrecision,
numberGroupingSeparator,
decimalSeparator,
symbolSeparator
) {
// we don't want to format non-numbers
if (!_.isFinite(amount)) {
return amount;
}
var currencySymbol;
var config = SUGAR.App.metadata.getConfig();
// default to base currency
currencyId = currencyId || this.getBaseCurrencyId();
symbolSeparator = symbolSeparator || '';
// use reasonable defaults if none exist
if (!_.isFinite(decimalPrecision)) {
if (_.isFinite(config.defaultCurrencySignificantDigits)) {
decimalPrecision = config.defaultCurrencySignificantDigits;
}
else {
decimalPrecision = 2;
}
}
decimalSeparator = decimalSeparator || config.defaultDecimalSeparator || '.';
// if the numberGroupingSeparator is truly undefined we need to get the defaults, if it's an empty string
// we need to use the empty string as it's a valid value.
numberGroupingSeparator = (!_.isUndefined(numberGroupingSeparator)) ?
numberGroupingSeparator : config.defaultNumberGroupingSeparator || ',';
currencySymbol = this.getCurrencySymbol(currencyId) || this.getCurrencySymbol(this.getBaseCurrencyId());
amount = Utils.formatNumber(
amount,
decimalPrecision,
decimalPrecision,
numberGroupingSeparator,
decimalSeparator
);
return currencySymbol + symbolSeparator + amount;
},
/**
* Formats a currency amount according to the current user's locale.
*
* @param {number} amount The amount to format.
* @param {string} [currencyId] The currency id to use. If not
* specified, the system default will be used.
* @param {string} [decimalPrecision] The number of decimal digits to use.
* If not specified, the user preference will be used.
* @return {string} formatted currency amount.
*/
formatAmountLocale: function (amount, currencyId, decimalPrecision) {
// get user preferred formatting
var decimalSeparator = User.getPreference('decimal_separator');
var numberGroupingSeparator = User.getPreference('number_grouping_separator');
var userDecimalPrecision = User.getPreference('decimal_precision');
decimalPrecision = (_.isFinite(decimalPrecision)) ? decimalPrecision : userDecimalPrecision;
return this.formatAmount(
amount,
currencyId,
decimalPrecision,
numberGroupingSeparator,
decimalSeparator
);
},
/**
* Unformats a currency amount.
*
* @param {string} amount The amount to unformat.
* @param {string} numberGroupingSeparator Thousands separator.
* @param {string} decimalSeparator The string between number and decimals.
* @param {boolean} [toFloat=false] If `true`, convert string to float
* value.
* @return {string} The unformatted currency amount.
*/
unformatAmount:function (amount, numberGroupingSeparator, decimalSeparator, toFloat) {
toFloat = toFloat || false;
// strip off currency symbol, or anything prefixed that is not a digit or separator
amount = amount.toString().replace(/^[^\d\.\,-]+/, '');
return Utils.unformatNumberString(
amount,
numberGroupingSeparator,
decimalSeparator,
toFloat
);
},
/**
* Unformats the currency amount according to the current user's locale.
*
* @param {string} amount Amount to unformat.
* @param {boolean} toFloat If `true`, convert string to float value.
* @return {string} The unformatted currency amount.
*/
unformatAmountLocale:function (amount, toFloat) {
var decimalSeparator,
numberGroupingSeparator,
config = SUGAR.App.metadata.getConfig();
// use user locale or reasonable defaults
decimalSeparator = User.getPreference('decimal_separator') || config.defaultDecimalSeparator || '.';
var userNumGroupingSeparator = User.getPreference('number_grouping_separator');
numberGroupingSeparator = userNumGroupingSeparator || config.defaultNumberGroupingSeparator || ',';
return this.unformatAmount(
amount,
numberGroupingSeparator,
decimalSeparator,
toFloat
);
},
/**
* Converts from one currency to another.
*
* @param {number|string} amount Base currency amount.
* @param {string} fromId Source currency id.
* @param {string} toId Target currency id.
* @return {string} The converted amount.
*/
convertAmount: function(amount, fromId, toId) {
var currency1;
var currency2;
if (fromId == toId) {
return math.round(amount, undefined, true);
}
currency1 = SUGAR.App.metadata.getCurrency(fromId);
currency2 = SUGAR.App.metadata.getCurrency(toId);
return this.convertWithRate(amount, currency1.conversion_rate, currency2.conversion_rate);
},
/**
* Converts a currency to the base currency.
*
* @param {number|string} amount The amount in the source currency.
* @param {string} fromId Source currency id.
* @return {string} The converted amount.
*/
convertToBase: function (amount, fromId) {
return this.convertAmount(amount, fromId, this.getBaseCurrencyId());
},
/**
* Converts from the base currency to another currency.
*
* @param {number|string} amount The amount in the base currency.
* @param {string} toId Target currency id.
* @return {string} The converted amount.
*/
convertFromBase:function (amount, toId) {
return this.convertAmount(amount, this.getBaseCurrencyId(), toId);
},
/**
* Converts a currency with given conversion rates.
*
* @param {number|string} amount The amount in the origin currency.
* @param {number} fromRate The origin conversion rate relative to the base
* currency.
* @param {number} toRate The target conversion rate relative to the base
* currency.
* @return {string} The converted amount.
*/
convertWithRate: function(amount, fromRate, toRate) {
fromRate = fromRate || 1.0;
toRate = toRate || 1.0;
return math.mul(math.div(amount, fromRate, undefined, true), toRate, undefined, true);
}
};