1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | var 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 |
|
21 | var round = function round(v) {
|
22 | return Math.round(v);
|
23 | };
|
24 |
|
25 | var pow = function pow(p) {
|
26 | return Math.pow(10, p);
|
27 | };
|
28 |
|
29 | var rounding = function rounding(value, increment) {
|
30 | return round(value / increment) * increment;
|
31 | };
|
32 |
|
33 | var groupRegex = /(\d)(?=(\d{3})+\b)/g;
|
34 | var vedicRegex = /(\d)(?=(\d\d)+\d\b)/g;
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | function 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;
|
53 |
|
54 | settings.increment = settings.increment || 1 / precision;
|
55 |
|
56 |
|
57 | if (settings.useVedic) {
|
58 | settings.groups = vedicRegex;
|
59 | } else {
|
60 | settings.groups = groupRegex;
|
61 | }
|
62 |
|
63 |
|
64 | this.s = settings;
|
65 | this.p = precision;
|
66 | }
|
67 |
|
68 | function 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')
|
89 | .replace(regex, '')
|
90 | .replace(decimalString, '.');
|
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;
|
103 |
|
104 | v = v.toFixed(4);
|
105 | }
|
106 |
|
107 | return useRounding ? round(v) : v;
|
108 | }
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | function 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 |
|
129 | currency.prototype = {
|
130 | |
131 |
|
132 |
|
133 |
|
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 |
|
144 |
|
145 |
|
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 |
|
156 |
|
157 |
|
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 |
|
167 |
|
168 |
|
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 |
|
178 |
|
179 |
|
180 |
|
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);
|
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 |
|
203 |
|
204 |
|
205 | dollars: function dollars() {
|
206 | return ~~this.value;
|
207 | },
|
208 |
|
209 | |
210 |
|
211 |
|
212 |
|
213 | cents: function cents() {
|
214 | var intValue = this.intValue,
|
215 | _precision = this.p;
|
216 | return ~~(intValue % _precision);
|
217 | },
|
218 |
|
219 | |
220 |
|
221 |
|
222 |
|
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 |
|
236 |
|
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 |
|
247 |
|
248 |
|
249 | toJSON: function toJSON() {
|
250 | return this.value;
|
251 | }
|
252 | };
|
253 |
|
254 | export default currency;
|