UNPKG

bigmoney.js

Version:

Library for handling the money values. Based on big.js library for arbitrary-precision decimal arithmetic. Support multiple currencies.

246 lines (197 loc) 6.98 kB
/** * Library for handling money: * - mathematical operations * - work with different currencies * - formatted output * * @example Money(3300, 'USD').plus(99.01).convert('RUB').format() */ ;(function (root, undefined) { var Big = root.Big || require('big.js'); var settings = { base: "USD", rates: { //USD : 1, //this is base. Other rates relative to the USD //"RUB": 35.2448, //"EUR": 1/1.3485, //"JPY": 102.02 }, format: "%decimal %currency" }; function Money(val, currency, options) { if (!(this instanceof Money)) { return new Money(val, currency, options); } if (arguments.length === 2 && typeof currency === 'object') { options = currency; currency = undefined; } this.options = options || {}; this.val = Big(val); this.currency = currency || this.options.currency || Money.settings.base; } /** * wrap Big.js methods */ Money.prototype.abs = function () { return Money(this.val.abs.apply(this.val, arguments), this.currency, this.options); }; Money.prototype.cmp = function () { return this.val.cmp.apply(this.val, arguments); }; Money.prototype.div = function () { return Money(this.val.div.apply(this.val, arguments), this.currency, this.options); }; Money.prototype.eq = function () { return this.val.eq.apply(this.val, arguments); }; Money.prototype.gt = function () { return this.val.gt.apply(this.val, arguments); }; Money.prototype.gte = function () { return this.val.gte.apply(this.val, arguments); }; Money.prototype.lt = function () { return this.val.lt.apply(this.val, arguments); }; Money.prototype.lte = function () { return this.val.lte.apply(this.val, arguments); }; Money.prototype.minus = function () { return Money(this.val.minus.apply(this.val, arguments), this.currency, this.options); }; Money.prototype.mod = function () { return Money(this.val.mod.apply(this.val, arguments), this.currency, this.options); }; Money.prototype.plus = function () { return Money(this.val.plus.apply(this.val, arguments), this.currency, this.options); }; Money.prototype.pow = function () { return this.val.pow.apply(this.val, arguments); }; Money.prototype.round = function () { return Money(this.val.round.apply(this.val, arguments), this.currency, this.options); }; Money.prototype.sqrt = function () { return Money(this.val.sqrt.apply(this.val, arguments), this.currency, this.options); }; Money.prototype.times = function () { return Money(this.val.times.apply(this.val, arguments), this.currency, this.options); }; /** * Allocates amounts of money in an array so that you won't loose cents * @param ratios {Number} How many parts you want to divide the initial amount. * @returns {*} */ function sum(a, b) { return a + b; } function ones(len) { var arr = []; for (var i = 0; i < len; i++) { arr.push(1); } return arr; } Money.prototype.allocate = function(ratios) { if(typeof ratios === 'undefined') { return [this]; } else if(typeof ratios === 'number') { ratios = ones(ratios); } var amount = this, remainder = amount, total = ratios.reduce(sum), results = [], current = 0; ratios.forEach(function(ratio, index) { results.push(amount.times(ratio).div(total)); remainder = remainder.minus(results[index]); }); while(!remainder.eq(0)) { results[current] = results[current++].plus(0.01 * remainder.val.s); if(current >= results.length) { current = 0; } remainder = remainder.plus(0.01 * remainder.val.s * -1); } return results; }; /** * Convert to over currency * @param to {String} Destination currency. Default is a settings.base currency. * @returns {*} */ Money.prototype.convert = function (to) { to || (to = Money.settings.base); var rate, val, from = this.currency; if (from === to) return Money(this.val, to, this.options); if (from === Money.settings.base) { rate = Money.settings.rates[to]; if (rate === undefined) throw new Error('Unknown rate for "' + to + '" currency'); val = this.val.times(rate); return Money(val, to, this.options); } else if (to === Money.settings.base) { rate = Money.settings.rates[from]; if (rate === undefined) throw new Error('Unknown rate for "' + from + '" currency'); val = rate === 0 ? 0 : this.val.div(rate); return Money(val, to, this.options); } else { return (this.convert(Money.settings.base)).convert(to); } }; /** * Return value as number * @returns {Number} */ Money.prototype.valueOf = function () { return parseFloat(this.val.toFixed(2)); }; /** * Return value as string * @returns {string} */ Money.prototype.toString = function () { return this.val.toFixed(2); }; /** * Return formatted string * @returns {string} */ Money.prototype.format = function (formatTemplate) { return Money.formatter(this.valueOf(), this.currency, formatTemplate); }; Money.isValidCurrency = function (curr) { return typeof Money.settings.rates[curr] === 'number'; }; Money.settings = settings; Money.formatter = function(decimal, currency, formatTemplate) { formatTemplate || (formatTemplate = Money.settings.format); return formatTemplate.replace('%decimal', decimal).replace('%currency', currency); }; // EXPORT // Node and other CommonJS-like environments that support module.exports. if ( typeof module !== 'undefined' && module.exports ) { module.exports = Money; //AMD. } else if ( typeof define == 'function' && define.amd ) { define( function () { return Money }); //Browser. } else { Money.noConflict = (function(oldMoney) { return function() { // Reset the value of the root's `accounting` variable: root.Money = oldMoney; // Delete the noConflict method: Money.noConflict = undefined; // Return reference to the library to re-assign it: return Money; }; })(root.Money); root['Money'] = Money; } })(this);