@@ -164,9 +164,24 @@ export const createMoneyValue = (currencyCode, rawAmount) => {
164
164
const amountAsNumber = parseRawAmountToNumber ( rawAmount ) ;
165
165
if ( isNaN ( amountAsNumber ) ) return null ;
166
166
167
- const centAmount = amountAsNumber * 10 ** currency . fractionDigits ;
167
+ // The cent amount is rounded to the currencie's default number
168
+ // of fraction digits for prices with high precision.
169
+ //
170
+ // Additionally, JavaScript is sometimes incorrect when multiplying floats,
171
+ // e.g. 2.49 * 100 -> 249.00000000000003
172
+ // While inaccuracy from multiplying floating point numbers is a
173
+ // general problem in JS, we can avoid it by cutting off all
174
+ // decimals. This is possible since cents is the base unit, so we
175
+ // operate on integers anyways
176
+ // Also we should the round the value to ensure that we come close
177
+ // to the nearest decimal value
178
+ // ref: https://github.com/commercetools/merchant-center-frontend/pull/770
179
+ const centAmount = Math . trunc (
180
+ Math . round ( amountAsNumber * 10 ** currency . fractionDigits )
181
+ ) ;
182
+
168
183
const fractionDigitsOfAmount =
169
- // The input will always use a dot as the separator.
184
+ // The conversion to a string will always use a dot as the separator.
170
185
// That means we don't have to handle a comma.
171
186
String ( amountAsNumber ) . indexOf ( '.' ) === - 1
172
187
? 0
@@ -176,9 +191,7 @@ export const createMoneyValue = (currencyCode, rawAmount) => {
176
191
return {
177
192
type : 'highPrecision' ,
178
193
currencyCode,
179
- // For prices with high precision, the cent amount is rounded to the
180
- // currencies default number of fraction digits
181
- centAmount : parseFloat ( centAmount . toFixed ( 0 ) , 10 ) ,
194
+ centAmount,
182
195
preciseAmount : parseInt (
183
196
amountAsNumber * 10 ** fractionDigitsOfAmount ,
184
197
10
@@ -211,13 +224,13 @@ const formatAmount = (rawAmount, currencyCode, locale) => {
211
224
212
225
const amount = getAmountAsNumberFromMoneyValue ( moneyValue ) ;
213
226
227
+ const fractionDigits = moneyValue . preciseAmount
228
+ ? moneyValue . fractionDigits
229
+ : currencies [ moneyValue . currencyCode ] . fractionDigits ;
230
+
214
231
return isNaN ( amount )
215
232
? ''
216
- : amount . toLocaleString ( locale , {
217
- minimumFractionDigits : moneyValue . preciseAmount
218
- ? moneyValue . fractionDigits
219
- : currencies [ moneyValue . currencyCode ] . fractionDigits ,
220
- } ) ;
233
+ : amount . toLocaleString ( locale , { minimumFractionDigits : fractionDigits } ) ;
221
234
} ;
222
235
223
236
const getAmountStyles = props => {
0 commit comments