UNPKG

6.63 kBJavaScriptView Raw
1/*!
2 * currency.js - v2.0.4
3 * http://scurker.github.io/currency.js
4 *
5 * Copyright (c) 2021 Jason Wilson
6 * Released under MIT license
7 */
8
9var defaults = {
10 symbol: '$',
11 separator: ',',
12 decimal: '.',
13 errorOnInvalid: false,
14 precision: 2,
15 pattern: '!#',
16 negativePattern: '-!#',
17 format: format,
18 fromCents: false
19};
20
21var round = function round(v) {
22 return Math.round(v);
23};
24
25var pow = function pow(p) {
26 return Math.pow(10, p);
27};
28
29var rounding = function rounding(value, increment) {
30 return round(value / increment) * increment;
31};
32
33var groupRegex = /(\d)(?=(\d{3})+\b)/g;
34var vedicRegex = /(\d)(?=(\d\d)+\d\b)/g;
35/**
36 * Create a new instance of currency.js
37 * @param {number|string|currency} value
38 * @param {object} [opts]
39 */
40
41function currency(value, opts) {
42 var that = this;
43
44 if (!(that instanceof currency)) {
45 return new currency(value, opts);
46 }
47
48 var settings = Object.assign({}, defaults, opts),
49 precision = pow(settings.precision),
50 v = parse(value, settings);
51 that.intValue = v;
52 that.value = v / precision; // Set default incremental value
53
54 settings.increment = settings.increment || 1 / precision; // Support vedic numbering systems
55 // see: https://en.wikipedia.org/wiki/Indian_numbering_system
56
57 if (settings.useVedic) {
58 settings.groups = vedicRegex;
59 } else {
60 settings.groups = groupRegex;
61 } // Intended for internal usage only - subject to change
62
63
64 this.s = settings;
65 this.p = precision;
66}
67
68function parse(value, opts) {
69 var useRounding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
70 var v = 0,
71 decimal = opts.decimal,
72 errorOnInvalid = opts.errorOnInvalid,
73 decimals = opts.precision,
74 fromCents = opts.fromCents,
75 precision = pow(decimals),
76 isNumber = typeof value === 'number',
77 isCurrency = value instanceof currency;
78
79 if (isCurrency && fromCents) {
80 return value.intValue;
81 }
82
83 if (isNumber || isCurrency) {
84 v = isCurrency ? value.value : value;
85 } else if (typeof value === 'string') {
86 var regex = new RegExp('[^-\\d' + decimal + ']', 'g'),
87 decimalString = new RegExp('\\' + decimal, 'g');
88 v = value.replace(/\((.*)\)/, '-$1') // allow negative e.g. (1.99)
89 .replace(regex, '') // replace any non numeric values
90 .replace(decimalString, '.'); // convert any decimal values
91
92 v = v || 0;
93 } else {
94 if (errorOnInvalid) {
95 throw Error('Invalid Input');
96 }
97
98 v = 0;
99 }
100
101 if (!fromCents) {
102 v *= precision; // scale number to integer value
103
104 v = v.toFixed(4); // Handle additional decimal for proper rounding.
105 }
106
107 return useRounding ? round(v) : v;
108}
109/**
110 * Formats a currency object
111 * @param currency
112 * @param {object} [opts]
113 */
114
115
116function format(currency, settings) {
117 var pattern = settings.pattern,
118 negativePattern = settings.negativePattern,
119 symbol = settings.symbol,
120 separator = settings.separator,
121 decimal = settings.decimal,
122 groups = settings.groups,
123 split = ('' + currency).replace(/^-/, '').split('.'),
124 dollars = split[0],
125 cents = split[1];
126 return (currency.value >= 0 ? pattern : negativePattern).replace('!', symbol).replace('#', dollars.replace(groups, '$1' + separator) + (cents ? decimal + cents : ''));
127}
128
129currency.prototype = {
130 /**
131 * Adds values together.
132 * @param {number} number
133 * @returns {currency}
134 */
135 add: function add(number) {
136 var intValue = this.intValue,
137 _settings = this.s,
138 _precision = this.p;
139 return currency((intValue += parse(number, _settings)) / (_settings.fromCents ? 1 : _precision), _settings);
140 },
141
142 /**
143 * Subtracts value.
144 * @param {number} number
145 * @returns {currency}
146 */
147 subtract: function subtract(number) {
148 var intValue = this.intValue,
149 _settings = this.s,
150 _precision = this.p;
151 return currency((intValue -= parse(number, _settings)) / (_settings.fromCents ? 1 : _precision), _settings);
152 },
153
154 /**
155 * Multiplies values.
156 * @param {number} number
157 * @returns {currency}
158 */
159 multiply: function multiply(number) {
160 var intValue = this.intValue,
161 _settings = this.s;
162 return currency((intValue *= number) / (_settings.fromCents ? 1 : pow(_settings.precision)), _settings);
163 },
164
165 /**
166 * Divides value.
167 * @param {number} number
168 * @returns {currency}
169 */
170 divide: function divide(number) {
171 var intValue = this.intValue,
172 _settings = this.s;
173 return currency(intValue /= parse(number, _settings, false), _settings);
174 },
175
176 /**
177 * Takes the currency amount and distributes the values evenly. Any extra pennies
178 * left over from the distribution will be stacked onto the first set of entries.
179 * @param {number} count
180 * @returns {array}
181 */
182 distribute: function distribute(count) {
183 var intValue = this.intValue,
184 _precision = this.p,
185 _settings = this.s,
186 distribution = [],
187 split = Math[intValue >= 0 ? 'floor' : 'ceil'](intValue / count),
188 pennies = Math.abs(intValue - split * count),
189 precision = _settings.fromCents ? 1 : _precision;
190
191 for (; count !== 0; count--) {
192 var item = currency(split / precision, _settings); // Add any left over pennies
193
194 pennies-- > 0 && (item = item[intValue >= 0 ? 'add' : 'subtract'](1 / precision));
195 distribution.push(item);
196 }
197
198 return distribution;
199 },
200
201 /**
202 * Returns the dollar value.
203 * @returns {number}
204 */
205 dollars: function dollars() {
206 return ~~this.value;
207 },
208
209 /**
210 * Returns the cent value.
211 * @returns {number}
212 */
213 cents: function cents() {
214 var intValue = this.intValue,
215 _precision = this.p;
216 return ~~(intValue % _precision);
217 },
218
219 /**
220 * Formats the value as a string according to the formatting settings.
221 * @param {boolean} useSymbol - format with currency symbol
222 * @returns {string}
223 */
224 format: function format(options) {
225 var _settings = this.s;
226
227 if (typeof options === 'function') {
228 return options(this, _settings);
229 }
230
231 return _settings.format(this, Object.assign({}, _settings, options));
232 },
233
234 /**
235 * Formats the value as a string according to the formatting settings.
236 * @returns {string}
237 */
238 toString: function toString() {
239 var intValue = this.intValue,
240 _precision = this.p,
241 _settings = this.s;
242 return rounding(intValue / _precision, _settings.increment).toFixed(_settings.precision);
243 },
244
245 /**
246 * Value for JSON serialization.
247 * @returns {float}
248 */
249 toJSON: function toJSON() {
250 return this.value;
251 }
252};
253
254export default currency;