Expensify / App

Welcome to New Expensify: a complete re-imagination of financial collaboration, centered around chat. Help us build the next generation of Expensify by sharing feedback and contributing to the code.
https://new.expensify.com
MIT License
3.57k stars 2.91k forks source link

Some currency amount is rounded up/down when split bill #13565

Closed kavimuru closed 1 year ago

kavimuru commented 1 year ago

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Action Performed:

  1. Create a new group if you don't have one.
  2. Open the group and add a new split bill
  3. Change the currency to ALL
  4. Enter any amount that when divided among group members will be in decimal
  5. Press Next and observe the amount is rounded up/down
  6. Confirm the Split
  7. Look at the chat preview of the member you split bill with and observe the requested amount is also rounded
  8. Wait a few seconds (or open the chat in web) and the amount will be changed to the correct amount

Expected Result:

Amount is not rounded up/down

Actual Result:

Amount is rounded up/down

Workaround:

unknown

Platform:

Where is this issue occurring?

Version Number: 1.2.38-5 Reproducible in staging?: y Reproducible in production?: y Email or phone of affected tester (no customers): Logs: https://stackoverflow.com/c/expensify/questions/4856 Notes/Photos/Videos:

https://user-images.githubusercontent.com/43996225/207428947-3d50dac5-4543-4254-8fcd-4ea621639511.mp4

https://user-images.githubusercontent.com/43996225/207428976-01eb9be4-3399-4e15-8a5d-c205451534f3.mp4

Expensify/Expensify Issue URL: Issue reported by: @bernhardoj Slack conversation: https://expensify.slack.com/archives/C049HHMV9SM/p1670937919835729

View all open jobs on GitHub

melvin-bot[bot] commented 1 year ago

Triggered auto assignment to @abekkala (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details.

aldo-expensify commented 1 year ago

@luacmartins it looks like we have different rounding strategies in the front vs the server. I just wanted to confirm that the expected would have been 37.33 in the front instead of 33, right?

Also, I know you are working on a PR for split bill, is that PR going to fix this?

luacmartins commented 1 year ago

I just wanted to confirm that the expected would have been 37.33 in the front instead of 33, right?

Do you mean 37.33 instead of 37? I think that's correct and it should show 37.33.

Also, I know you are working on a PR for split bill, is that PR going to fix this?

My PR is not fixing this.

aldo-expensify commented 1 year ago

Do you mean 37.33 instead of 37?

yes :P

ok! thanks

abekkala commented 1 year ago

@aldo-expensify I see that you wanted this to be Internal. Based on this SO - should this also be Demolition?

aldo-expensify commented 1 year ago

Based on this SO - should this also be Demolition?

It is not really needed, I'll work in a solution. If you add demolition, it will be assigned to me anyway :P

luacmartins commented 1 year ago

I think that we merged the CME and Demolition teams into the engineering teams. Is that label still needed?

aldo-expensify commented 1 year ago

I think that we merged the CME and Demolition teams into the engineering teams

I think your are right about this (checked in Salt/www-whitelist)

Is that label still needed?

Shouldn't be

aldo-expensify commented 1 year ago

From this result:

image

It seems that ALL (Qindarka) is a currency that doesn't do "cents" (there are lots of currencies like this). Since the split has 33 "cents" of ALL, the front end rounds it to 0. I think this is correct. The problem is the backend not considering that this currency doesn't have "cents" and it should be rounding to the unit.

luacmartins commented 1 year ago

Nice find! I agree that this is an issue with the server then!

aldo-expensify commented 1 year ago

The backend stores the number of decimals for each currency here: https://github.com/Expensify/PHP-Libs/blob/main/src/CurrencyInfo.php

I'm thinking about running a small JS snipped like this:

const currencySymbols = ['AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BYR', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EEK', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'INR', 'IQD', 'IRR', 'ISK', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LTL', 'LVL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SRD', 'STD', 'STN', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEB', 'VEF', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMK', 'ZMW'];
const decimals = [0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001];
currencySymbols.map(currencySymbol => {
    let decimalPlaces = 0;
    let decimalPlacesTested = {};
    decimals.forEach((value, index) => {
        decimalPlacesTested[value] = Intl.NumberFormat('en', {style: 'currency', currency: currencySymbol}).format(value);
        if (decimalPlacesTested[value].indexOf(`${value}`) !== -1) {
            decimalPlaces = index + 1;
        }
    });
    return {
        currencySymbol,
        decimalPlaces,
        decimalPlacesTested,
    };
});
Results: ```json [ { "currencySymbol": "AED", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "AED 0.10", "0.01": "AED 0.01", "0.001": "AED 0.00", "0.0001": "AED 0.00", "0.00001": "AED 0.00", "0.000001": "AED 0.00" } }, { "currencySymbol": "AFN", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "AFN 0", "0.01": "AFN 0", "0.001": "AFN 0", "0.0001": "AFN 0", "0.00001": "AFN 0", "0.000001": "AFN 0" } }, { "currencySymbol": "ALL", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "ALL 0", "0.01": "ALL 0", "0.001": "ALL 0", "0.0001": "ALL 0", "0.00001": "ALL 0", "0.000001": "ALL 0" } }, { "currencySymbol": "AMD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "AMD 0.10", "0.01": "AMD 0.01", "0.001": "AMD 0.00", "0.0001": "AMD 0.00", "0.00001": "AMD 0.00", "0.000001": "AMD 0.00" } }, { "currencySymbol": "ANG", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "ANG 0.10", "0.01": "ANG 0.01", "0.001": "ANG 0.00", "0.0001": "ANG 0.00", "0.00001": "ANG 0.00", "0.000001": "ANG 0.00" } }, { "currencySymbol": "AOA", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "AOA 0.10", "0.01": "AOA 0.01", "0.001": "AOA 0.00", "0.0001": "AOA 0.00", "0.00001": "AOA 0.00", "0.000001": "AOA 0.00" } }, { "currencySymbol": "ARS", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "ARS 0.10", "0.01": "ARS 0.01", "0.001": "ARS 0.00", "0.0001": "ARS 0.00", "0.00001": "ARS 0.00", "0.000001": "ARS 0.00" } }, { "currencySymbol": "AUD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "A$0.10", "0.01": "A$0.01", "0.001": "A$0.00", "0.0001": "A$0.00", "0.00001": "A$0.00", "0.000001": "A$0.00" } }, { "currencySymbol": "AWG", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "AWG 0.10", "0.01": "AWG 0.01", "0.001": "AWG 0.00", "0.0001": "AWG 0.00", "0.00001": "AWG 0.00", "0.000001": "AWG 0.00" } }, { "currencySymbol": "AZN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "AZN 0.10", "0.01": "AZN 0.01", "0.001": "AZN 0.00", "0.0001": "AZN 0.00", "0.00001": "AZN 0.00", "0.000001": "AZN 0.00" } }, { "currencySymbol": "BAM", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BAM 0.10", "0.01": "BAM 0.01", "0.001": "BAM 0.00", "0.0001": "BAM 0.00", "0.00001": "BAM 0.00", "0.000001": "BAM 0.00" } }, { "currencySymbol": "BBD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BBD 0.10", "0.01": "BBD 0.01", "0.001": "BBD 0.00", "0.0001": "BBD 0.00", "0.00001": "BBD 0.00", "0.000001": "BBD 0.00" } }, { "currencySymbol": "BDT", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BDT 0.10", "0.01": "BDT 0.01", "0.001": "BDT 0.00", "0.0001": "BDT 0.00", "0.00001": "BDT 0.00", "0.000001": "BDT 0.00" } }, { "currencySymbol": "BGN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BGN 0.10", "0.01": "BGN 0.01", "0.001": "BGN 0.00", "0.0001": "BGN 0.00", "0.00001": "BGN 0.00", "0.000001": "BGN 0.00" } }, { "currencySymbol": "BHD", "decimalPlaces": 3, "decimalPlacesTested": { "0.1": "BHD 0.100", "0.01": "BHD 0.010", "0.001": "BHD 0.001", "0.0001": "BHD 0.000", "0.00001": "BHD 0.000", "0.000001": "BHD 0.000" } }, { "currencySymbol": "BIF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "BIF 0", "0.01": "BIF 0", "0.001": "BIF 0", "0.0001": "BIF 0", "0.00001": "BIF 0", "0.000001": "BIF 0" } }, { "currencySymbol": "BMD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BMD 0.10", "0.01": "BMD 0.01", "0.001": "BMD 0.00", "0.0001": "BMD 0.00", "0.00001": "BMD 0.00", "0.000001": "BMD 0.00" } }, { "currencySymbol": "BND", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BND 0.10", "0.01": "BND 0.01", "0.001": "BND 0.00", "0.0001": "BND 0.00", "0.00001": "BND 0.00", "0.000001": "BND 0.00" } }, { "currencySymbol": "BOB", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BOB 0.10", "0.01": "BOB 0.01", "0.001": "BOB 0.00", "0.0001": "BOB 0.00", "0.00001": "BOB 0.00", "0.000001": "BOB 0.00" } }, { "currencySymbol": "BRL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "R$0.10", "0.01": "R$0.01", "0.001": "R$0.00", "0.0001": "R$0.00", "0.00001": "R$0.00", "0.000001": "R$0.00" } }, { "currencySymbol": "BSD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BSD 0.10", "0.01": "BSD 0.01", "0.001": "BSD 0.00", "0.0001": "BSD 0.00", "0.00001": "BSD 0.00", "0.000001": "BSD 0.00" } }, { "currencySymbol": "BTN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BTN 0.10", "0.01": "BTN 0.01", "0.001": "BTN 0.00", "0.0001": "BTN 0.00", "0.00001": "BTN 0.00", "0.000001": "BTN 0.00" } }, { "currencySymbol": "BWP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BWP 0.10", "0.01": "BWP 0.01", "0.001": "BWP 0.00", "0.0001": "BWP 0.00", "0.00001": "BWP 0.00", "0.000001": "BWP 0.00" } }, { "currencySymbol": "BYN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BYN 0.10", "0.01": "BYN 0.01", "0.001": "BYN 0.00", "0.0001": "BYN 0.00", "0.00001": "BYN 0.00", "0.000001": "BYN 0.00" } }, { "currencySymbol": "BYR", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "BYR 0", "0.01": "BYR 0", "0.001": "BYR 0", "0.0001": "BYR 0", "0.00001": "BYR 0", "0.000001": "BYR 0" } }, { "currencySymbol": "BZD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "BZD 0.10", "0.01": "BZD 0.01", "0.001": "BZD 0.00", "0.0001": "BZD 0.00", "0.00001": "BZD 0.00", "0.000001": "BZD 0.00" } }, { "currencySymbol": "CAD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CA$0.10", "0.01": "CA$0.01", "0.001": "CA$0.00", "0.0001": "CA$0.00", "0.00001": "CA$0.00", "0.000001": "CA$0.00" } }, { "currencySymbol": "CDF", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CDF 0.10", "0.01": "CDF 0.01", "0.001": "CDF 0.00", "0.0001": "CDF 0.00", "0.00001": "CDF 0.00", "0.000001": "CDF 0.00" } }, { "currencySymbol": "CHF", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CHF 0.10", "0.01": "CHF 0.01", "0.001": "CHF 0.00", "0.0001": "CHF 0.00", "0.00001": "CHF 0.00", "0.000001": "CHF 0.00" } }, { "currencySymbol": "CLP", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "CLP 0", "0.01": "CLP 0", "0.001": "CLP 0", "0.0001": "CLP 0", "0.00001": "CLP 0", "0.000001": "CLP 0" } }, { "currencySymbol": "CNY", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CN¥0.10", "0.01": "CN¥0.01", "0.001": "CN¥0.00", "0.0001": "CN¥0.00", "0.00001": "CN¥0.00", "0.000001": "CN¥0.00" } }, { "currencySymbol": "COP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "COP 0.10", "0.01": "COP 0.01", "0.001": "COP 0.00", "0.0001": "COP 0.00", "0.00001": "COP 0.00", "0.000001": "COP 0.00" } }, { "currencySymbol": "CRC", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CRC 0.10", "0.01": "CRC 0.01", "0.001": "CRC 0.00", "0.0001": "CRC 0.00", "0.00001": "CRC 0.00", "0.000001": "CRC 0.00" } }, { "currencySymbol": "CUC", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CUC 0.10", "0.01": "CUC 0.01", "0.001": "CUC 0.00", "0.0001": "CUC 0.00", "0.00001": "CUC 0.00", "0.000001": "CUC 0.00" } }, { "currencySymbol": "CUP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CUP 0.10", "0.01": "CUP 0.01", "0.001": "CUP 0.00", "0.0001": "CUP 0.00", "0.00001": "CUP 0.00", "0.000001": "CUP 0.00" } }, { "currencySymbol": "CVE", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CVE 0.10", "0.01": "CVE 0.01", "0.001": "CVE 0.00", "0.0001": "CVE 0.00", "0.00001": "CVE 0.00", "0.000001": "CVE 0.00" } }, { "currencySymbol": "CZK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "CZK 0.10", "0.01": "CZK 0.01", "0.001": "CZK 0.00", "0.0001": "CZK 0.00", "0.00001": "CZK 0.00", "0.000001": "CZK 0.00" } }, { "currencySymbol": "DJF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "DJF 0", "0.01": "DJF 0", "0.001": "DJF 0", "0.0001": "DJF 0", "0.00001": "DJF 0", "0.000001": "DJF 0" } }, { "currencySymbol": "DKK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "DKK 0.10", "0.01": "DKK 0.01", "0.001": "DKK 0.00", "0.0001": "DKK 0.00", "0.00001": "DKK 0.00", "0.000001": "DKK 0.00" } }, { "currencySymbol": "DOP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "DOP 0.10", "0.01": "DOP 0.01", "0.001": "DOP 0.00", "0.0001": "DOP 0.00", "0.00001": "DOP 0.00", "0.000001": "DOP 0.00" } }, { "currencySymbol": "DZD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "DZD 0.10", "0.01": "DZD 0.01", "0.001": "DZD 0.00", "0.0001": "DZD 0.00", "0.00001": "DZD 0.00", "0.000001": "DZD 0.00" } }, { "currencySymbol": "EEK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "EEK 0.10", "0.01": "EEK 0.01", "0.001": "EEK 0.00", "0.0001": "EEK 0.00", "0.00001": "EEK 0.00", "0.000001": "EEK 0.00" } }, { "currencySymbol": "EGP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "EGP 0.10", "0.01": "EGP 0.01", "0.001": "EGP 0.00", "0.0001": "EGP 0.00", "0.00001": "EGP 0.00", "0.000001": "EGP 0.00" } }, { "currencySymbol": "ERN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "ERN 0.10", "0.01": "ERN 0.01", "0.001": "ERN 0.00", "0.0001": "ERN 0.00", "0.00001": "ERN 0.00", "0.000001": "ERN 0.00" } }, { "currencySymbol": "ETB", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "ETB 0.10", "0.01": "ETB 0.01", "0.001": "ETB 0.00", "0.0001": "ETB 0.00", "0.00001": "ETB 0.00", "0.000001": "ETB 0.00" } }, { "currencySymbol": "EUR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "€0.10", "0.01": "€0.01", "0.001": "€0.00", "0.0001": "€0.00", "0.00001": "€0.00", "0.000001": "€0.00" } }, { "currencySymbol": "FJD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "FJD 0.10", "0.01": "FJD 0.01", "0.001": "FJD 0.00", "0.0001": "FJD 0.00", "0.00001": "FJD 0.00", "0.000001": "FJD 0.00" } }, { "currencySymbol": "FKP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "FKP 0.10", "0.01": "FKP 0.01", "0.001": "FKP 0.00", "0.0001": "FKP 0.00", "0.00001": "FKP 0.00", "0.000001": "FKP 0.00" } }, { "currencySymbol": "GBP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "£0.10", "0.01": "£0.01", "0.001": "£0.00", "0.0001": "£0.00", "0.00001": "£0.00", "0.000001": "£0.00" } }, { "currencySymbol": "GEL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "GEL 0.10", "0.01": "GEL 0.01", "0.001": "GEL 0.00", "0.0001": "GEL 0.00", "0.00001": "GEL 0.00", "0.000001": "GEL 0.00" } }, { "currencySymbol": "GHS", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "GHS 0.10", "0.01": "GHS 0.01", "0.001": "GHS 0.00", "0.0001": "GHS 0.00", "0.00001": "GHS 0.00", "0.000001": "GHS 0.00" } }, { "currencySymbol": "GIP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "GIP 0.10", "0.01": "GIP 0.01", "0.001": "GIP 0.00", "0.0001": "GIP 0.00", "0.00001": "GIP 0.00", "0.000001": "GIP 0.00" } }, { "currencySymbol": "GMD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "GMD 0.10", "0.01": "GMD 0.01", "0.001": "GMD 0.00", "0.0001": "GMD 0.00", "0.00001": "GMD 0.00", "0.000001": "GMD 0.00" } }, { "currencySymbol": "GNF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "GNF 0", "0.01": "GNF 0", "0.001": "GNF 0", "0.0001": "GNF 0", "0.00001": "GNF 0", "0.000001": "GNF 0" } }, { "currencySymbol": "GTQ", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "GTQ 0.10", "0.01": "GTQ 0.01", "0.001": "GTQ 0.00", "0.0001": "GTQ 0.00", "0.00001": "GTQ 0.00", "0.000001": "GTQ 0.00" } }, { "currencySymbol": "GYD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "GYD 0.10", "0.01": "GYD 0.01", "0.001": "GYD 0.00", "0.0001": "GYD 0.00", "0.00001": "GYD 0.00", "0.000001": "GYD 0.00" } }, { "currencySymbol": "HKD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "HK$0.10", "0.01": "HK$0.01", "0.001": "HK$0.00", "0.0001": "HK$0.00", "0.00001": "HK$0.00", "0.000001": "HK$0.00" } }, { "currencySymbol": "HNL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "HNL 0.10", "0.01": "HNL 0.01", "0.001": "HNL 0.00", "0.0001": "HNL 0.00", "0.00001": "HNL 0.00", "0.000001": "HNL 0.00" } }, { "currencySymbol": "HRK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "HRK 0.10", "0.01": "HRK 0.01", "0.001": "HRK 0.00", "0.0001": "HRK 0.00", "0.00001": "HRK 0.00", "0.000001": "HRK 0.00" } }, { "currencySymbol": "HTG", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "HTG 0.10", "0.01": "HTG 0.01", "0.001": "HTG 0.00", "0.0001": "HTG 0.00", "0.00001": "HTG 0.00", "0.000001": "HTG 0.00" } }, { "currencySymbol": "HUF", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "HUF 0.10", "0.01": "HUF 0.01", "0.001": "HUF 0.00", "0.0001": "HUF 0.00", "0.00001": "HUF 0.00", "0.000001": "HUF 0.00" } }, { "currencySymbol": "IDR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "IDR 0.10", "0.01": "IDR 0.01", "0.001": "IDR 0.00", "0.0001": "IDR 0.00", "0.00001": "IDR 0.00", "0.000001": "IDR 0.00" } }, { "currencySymbol": "ILS", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "₪0.10", "0.01": "₪0.01", "0.001": "₪0.00", "0.0001": "₪0.00", "0.00001": "₪0.00", "0.000001": "₪0.00" } }, { "currencySymbol": "INR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "₹0.10", "0.01": "₹0.01", "0.001": "₹0.00", "0.0001": "₹0.00", "0.00001": "₹0.00", "0.000001": "₹0.00" } }, { "currencySymbol": "IQD", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "IQD 0", "0.01": "IQD 0", "0.001": "IQD 0", "0.0001": "IQD 0", "0.00001": "IQD 0", "0.000001": "IQD 0" } }, { "currencySymbol": "IRR", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "IRR 0", "0.01": "IRR 0", "0.001": "IRR 0", "0.0001": "IRR 0", "0.00001": "IRR 0", "0.000001": "IRR 0" } }, { "currencySymbol": "ISK", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "ISK 0", "0.01": "ISK 0", "0.001": "ISK 0", "0.0001": "ISK 0", "0.00001": "ISK 0", "0.000001": "ISK 0" } }, { "currencySymbol": "JMD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "JMD 0.10", "0.01": "JMD 0.01", "0.001": "JMD 0.00", "0.0001": "JMD 0.00", "0.00001": "JMD 0.00", "0.000001": "JMD 0.00" } }, { "currencySymbol": "JOD", "decimalPlaces": 3, "decimalPlacesTested": { "0.1": "JOD 0.100", "0.01": "JOD 0.010", "0.001": "JOD 0.001", "0.0001": "JOD 0.000", "0.00001": "JOD 0.000", "0.000001": "JOD 0.000" } }, { "currencySymbol": "JPY", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "¥0", "0.01": "¥0", "0.001": "¥0", "0.0001": "¥0", "0.00001": "¥0", "0.000001": "¥0" } }, { "currencySymbol": "KES", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "KES 0.10", "0.01": "KES 0.01", "0.001": "KES 0.00", "0.0001": "KES 0.00", "0.00001": "KES 0.00", "0.000001": "KES 0.00" } }, { "currencySymbol": "KGS", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "KGS 0.10", "0.01": "KGS 0.01", "0.001": "KGS 0.00", "0.0001": "KGS 0.00", "0.00001": "KGS 0.00", "0.000001": "KGS 0.00" } }, { "currencySymbol": "KHR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "KHR 0.10", "0.01": "KHR 0.01", "0.001": "KHR 0.00", "0.0001": "KHR 0.00", "0.00001": "KHR 0.00", "0.000001": "KHR 0.00" } }, { "currencySymbol": "KMF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "KMF 0", "0.01": "KMF 0", "0.001": "KMF 0", "0.0001": "KMF 0", "0.00001": "KMF 0", "0.000001": "KMF 0" } }, { "currencySymbol": "KPW", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "KPW 0", "0.01": "KPW 0", "0.001": "KPW 0", "0.0001": "KPW 0", "0.00001": "KPW 0", "0.000001": "KPW 0" } }, { "currencySymbol": "KRW", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "₩0", "0.01": "₩0", "0.001": "₩0", "0.0001": "₩0", "0.00001": "₩0", "0.000001": "₩0" } }, { "currencySymbol": "KWD", "decimalPlaces": 3, "decimalPlacesTested": { "0.1": "KWD 0.100", "0.01": "KWD 0.010", "0.001": "KWD 0.001", "0.0001": "KWD 0.000", "0.00001": "KWD 0.000", "0.000001": "KWD 0.000" } }, { "currencySymbol": "KYD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "KYD 0.10", "0.01": "KYD 0.01", "0.001": "KYD 0.00", "0.0001": "KYD 0.00", "0.00001": "KYD 0.00", "0.000001": "KYD 0.00" } }, { "currencySymbol": "KZT", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "KZT 0.10", "0.01": "KZT 0.01", "0.001": "KZT 0.00", "0.0001": "KZT 0.00", "0.00001": "KZT 0.00", "0.000001": "KZT 0.00" } }, { "currencySymbol": "LAK", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "LAK 0", "0.01": "LAK 0", "0.001": "LAK 0", "0.0001": "LAK 0", "0.00001": "LAK 0", "0.000001": "LAK 0" } }, { "currencySymbol": "LBP", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "LBP 0", "0.01": "LBP 0", "0.001": "LBP 0", "0.0001": "LBP 0", "0.00001": "LBP 0", "0.000001": "LBP 0" } }, { "currencySymbol": "LKR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "LKR 0.10", "0.01": "LKR 0.01", "0.001": "LKR 0.00", "0.0001": "LKR 0.00", "0.00001": "LKR 0.00", "0.000001": "LKR 0.00" } }, { "currencySymbol": "LRD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "LRD 0.10", "0.01": "LRD 0.01", "0.001": "LRD 0.00", "0.0001": "LRD 0.00", "0.00001": "LRD 0.00", "0.000001": "LRD 0.00" } }, { "currencySymbol": "LSL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "LSL 0.10", "0.01": "LSL 0.01", "0.001": "LSL 0.00", "0.0001": "LSL 0.00", "0.00001": "LSL 0.00", "0.000001": "LSL 0.00" } }, { "currencySymbol": "LTL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "LTL 0.10", "0.01": "LTL 0.01", "0.001": "LTL 0.00", "0.0001": "LTL 0.00", "0.00001": "LTL 0.00", "0.000001": "LTL 0.00" } }, { "currencySymbol": "LVL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "LVL 0.10", "0.01": "LVL 0.01", "0.001": "LVL 0.00", "0.0001": "LVL 0.00", "0.00001": "LVL 0.00", "0.000001": "LVL 0.00" } }, { "currencySymbol": "LYD", "decimalPlaces": 3, "decimalPlacesTested": { "0.1": "LYD 0.100", "0.01": "LYD 0.010", "0.001": "LYD 0.001", "0.0001": "LYD 0.000", "0.00001": "LYD 0.000", "0.000001": "LYD 0.000" } }, { "currencySymbol": "MAD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MAD 0.10", "0.01": "MAD 0.01", "0.001": "MAD 0.00", "0.0001": "MAD 0.00", "0.00001": "MAD 0.00", "0.000001": "MAD 0.00" } }, { "currencySymbol": "MDL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MDL 0.10", "0.01": "MDL 0.01", "0.001": "MDL 0.00", "0.0001": "MDL 0.00", "0.00001": "MDL 0.00", "0.000001": "MDL 0.00" } }, { "currencySymbol": "MGA", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "MGA 0", "0.01": "MGA 0", "0.001": "MGA 0", "0.0001": "MGA 0", "0.00001": "MGA 0", "0.000001": "MGA 0" } }, { "currencySymbol": "MKD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MKD 0.10", "0.01": "MKD 0.01", "0.001": "MKD 0.00", "0.0001": "MKD 0.00", "0.00001": "MKD 0.00", "0.000001": "MKD 0.00" } }, { "currencySymbol": "MMK", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "MMK 0", "0.01": "MMK 0", "0.001": "MMK 0", "0.0001": "MMK 0", "0.00001": "MMK 0", "0.000001": "MMK 0" } }, { "currencySymbol": "MNT", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MNT 0.10", "0.01": "MNT 0.01", "0.001": "MNT 0.00", "0.0001": "MNT 0.00", "0.00001": "MNT 0.00", "0.000001": "MNT 0.00" } }, { "currencySymbol": "MOP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MOP 0.10", "0.01": "MOP 0.01", "0.001": "MOP 0.00", "0.0001": "MOP 0.00", "0.00001": "MOP 0.00", "0.000001": "MOP 0.00" } }, { "currencySymbol": "MRO", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "MRO 0", "0.01": "MRO 0", "0.001": "MRO 0", "0.0001": "MRO 0", "0.00001": "MRO 0", "0.000001": "MRO 0" } }, { "currencySymbol": "MRU", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MRU 0.10", "0.01": "MRU 0.01", "0.001": "MRU 0.00", "0.0001": "MRU 0.00", "0.00001": "MRU 0.00", "0.000001": "MRU 0.00" } }, { "currencySymbol": "MUR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MUR 0.10", "0.01": "MUR 0.01", "0.001": "MUR 0.00", "0.0001": "MUR 0.00", "0.00001": "MUR 0.00", "0.000001": "MUR 0.00" } }, { "currencySymbol": "MVR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MVR 0.10", "0.01": "MVR 0.01", "0.001": "MVR 0.00", "0.0001": "MVR 0.00", "0.00001": "MVR 0.00", "0.000001": "MVR 0.00" } }, { "currencySymbol": "MWK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MWK 0.10", "0.01": "MWK 0.01", "0.001": "MWK 0.00", "0.0001": "MWK 0.00", "0.00001": "MWK 0.00", "0.000001": "MWK 0.00" } }, { "currencySymbol": "MXN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MX$0.10", "0.01": "MX$0.01", "0.001": "MX$0.00", "0.0001": "MX$0.00", "0.00001": "MX$0.00", "0.000001": "MX$0.00" } }, { "currencySymbol": "MYR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MYR 0.10", "0.01": "MYR 0.01", "0.001": "MYR 0.00", "0.0001": "MYR 0.00", "0.00001": "MYR 0.00", "0.000001": "MYR 0.00" } }, { "currencySymbol": "MZN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "MZN 0.10", "0.01": "MZN 0.01", "0.001": "MZN 0.00", "0.0001": "MZN 0.00", "0.00001": "MZN 0.00", "0.000001": "MZN 0.00" } }, { "currencySymbol": "NAD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "NAD 0.10", "0.01": "NAD 0.01", "0.001": "NAD 0.00", "0.0001": "NAD 0.00", "0.00001": "NAD 0.00", "0.000001": "NAD 0.00" } }, { "currencySymbol": "NGN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "NGN 0.10", "0.01": "NGN 0.01", "0.001": "NGN 0.00", "0.0001": "NGN 0.00", "0.00001": "NGN 0.00", "0.000001": "NGN 0.00" } }, { "currencySymbol": "NIO", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "NIO 0.10", "0.01": "NIO 0.01", "0.001": "NIO 0.00", "0.0001": "NIO 0.00", "0.00001": "NIO 0.00", "0.000001": "NIO 0.00" } }, { "currencySymbol": "NOK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "NOK 0.10", "0.01": "NOK 0.01", "0.001": "NOK 0.00", "0.0001": "NOK 0.00", "0.00001": "NOK 0.00", "0.000001": "NOK 0.00" } }, { "currencySymbol": "NPR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "NPR 0.10", "0.01": "NPR 0.01", "0.001": "NPR 0.00", "0.0001": "NPR 0.00", "0.00001": "NPR 0.00", "0.000001": "NPR 0.00" } }, { "currencySymbol": "NZD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "NZ$0.10", "0.01": "NZ$0.01", "0.001": "NZ$0.00", "0.0001": "NZ$0.00", "0.00001": "NZ$0.00", "0.000001": "NZ$0.00" } }, { "currencySymbol": "OMR", "decimalPlaces": 3, "decimalPlacesTested": { "0.1": "OMR 0.100", "0.01": "OMR 0.010", "0.001": "OMR 0.001", "0.0001": "OMR 0.000", "0.00001": "OMR 0.000", "0.000001": "OMR 0.000" } }, { "currencySymbol": "PAB", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "PAB 0.10", "0.01": "PAB 0.01", "0.001": "PAB 0.00", "0.0001": "PAB 0.00", "0.00001": "PAB 0.00", "0.000001": "PAB 0.00" } }, { "currencySymbol": "PEN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "PEN 0.10", "0.01": "PEN 0.01", "0.001": "PEN 0.00", "0.0001": "PEN 0.00", "0.00001": "PEN 0.00", "0.000001": "PEN 0.00" } }, { "currencySymbol": "PGK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "PGK 0.10", "0.01": "PGK 0.01", "0.001": "PGK 0.00", "0.0001": "PGK 0.00", "0.00001": "PGK 0.00", "0.000001": "PGK 0.00" } }, { "currencySymbol": "PHP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "₱0.10", "0.01": "₱0.01", "0.001": "₱0.00", "0.0001": "₱0.00", "0.00001": "₱0.00", "0.000001": "₱0.00" } }, { "currencySymbol": "PKR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "PKR 0.10", "0.01": "PKR 0.01", "0.001": "PKR 0.00", "0.0001": "PKR 0.00", "0.00001": "PKR 0.00", "0.000001": "PKR 0.00" } }, { "currencySymbol": "PLN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "PLN 0.10", "0.01": "PLN 0.01", "0.001": "PLN 0.00", "0.0001": "PLN 0.00", "0.00001": "PLN 0.00", "0.000001": "PLN 0.00" } }, { "currencySymbol": "PYG", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "PYG 0", "0.01": "PYG 0", "0.001": "PYG 0", "0.0001": "PYG 0", "0.00001": "PYG 0", "0.000001": "PYG 0" } }, { "currencySymbol": "QAR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "QAR 0.10", "0.01": "QAR 0.01", "0.001": "QAR 0.00", "0.0001": "QAR 0.00", "0.00001": "QAR 0.00", "0.000001": "QAR 0.00" } }, { "currencySymbol": "RON", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "RON 0.10", "0.01": "RON 0.01", "0.001": "RON 0.00", "0.0001": "RON 0.00", "0.00001": "RON 0.00", "0.000001": "RON 0.00" } }, { "currencySymbol": "RSD", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "RSD 0", "0.01": "RSD 0", "0.001": "RSD 0", "0.0001": "RSD 0", "0.00001": "RSD 0", "0.000001": "RSD 0" } }, { "currencySymbol": "RUB", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "RUB 0.10", "0.01": "RUB 0.01", "0.001": "RUB 0.00", "0.0001": "RUB 0.00", "0.00001": "RUB 0.00", "0.000001": "RUB 0.00" } }, { "currencySymbol": "RWF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "RWF 0", "0.01": "RWF 0", "0.001": "RWF 0", "0.0001": "RWF 0", "0.00001": "RWF 0", "0.000001": "RWF 0" } }, { "currencySymbol": "SAR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SAR 0.10", "0.01": "SAR 0.01", "0.001": "SAR 0.00", "0.0001": "SAR 0.00", "0.00001": "SAR 0.00", "0.000001": "SAR 0.00" } }, { "currencySymbol": "SBD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SBD 0.10", "0.01": "SBD 0.01", "0.001": "SBD 0.00", "0.0001": "SBD 0.00", "0.00001": "SBD 0.00", "0.000001": "SBD 0.00" } }, { "currencySymbol": "SCR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SCR 0.10", "0.01": "SCR 0.01", "0.001": "SCR 0.00", "0.0001": "SCR 0.00", "0.00001": "SCR 0.00", "0.000001": "SCR 0.00" } }, { "currencySymbol": "SDG", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SDG 0.10", "0.01": "SDG 0.01", "0.001": "SDG 0.00", "0.0001": "SDG 0.00", "0.00001": "SDG 0.00", "0.000001": "SDG 0.00" } }, { "currencySymbol": "SEK", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SEK 0.10", "0.01": "SEK 0.01", "0.001": "SEK 0.00", "0.0001": "SEK 0.00", "0.00001": "SEK 0.00", "0.000001": "SEK 0.00" } }, { "currencySymbol": "SGD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SGD 0.10", "0.01": "SGD 0.01", "0.001": "SGD 0.00", "0.0001": "SGD 0.00", "0.00001": "SGD 0.00", "0.000001": "SGD 0.00" } }, { "currencySymbol": "SHP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SHP 0.10", "0.01": "SHP 0.01", "0.001": "SHP 0.00", "0.0001": "SHP 0.00", "0.00001": "SHP 0.00", "0.000001": "SHP 0.00" } }, { "currencySymbol": "SLL", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "SLL 0", "0.01": "SLL 0", "0.001": "SLL 0", "0.0001": "SLL 0", "0.00001": "SLL 0", "0.000001": "SLL 0" } }, { "currencySymbol": "SOS", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "SOS 0", "0.01": "SOS 0", "0.001": "SOS 0", "0.0001": "SOS 0", "0.00001": "SOS 0", "0.000001": "SOS 0" } }, { "currencySymbol": "SRD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SRD 0.10", "0.01": "SRD 0.01", "0.001": "SRD 0.00", "0.0001": "SRD 0.00", "0.00001": "SRD 0.00", "0.000001": "SRD 0.00" } }, { "currencySymbol": "STD", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "STD 0", "0.01": "STD 0", "0.001": "STD 0", "0.0001": "STD 0", "0.00001": "STD 0", "0.000001": "STD 0" } }, { "currencySymbol": "STN", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "STN 0.10", "0.01": "STN 0.01", "0.001": "STN 0.00", "0.0001": "STN 0.00", "0.00001": "STN 0.00", "0.000001": "STN 0.00" } }, { "currencySymbol": "SVC", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SVC 0.10", "0.01": "SVC 0.01", "0.001": "SVC 0.00", "0.0001": "SVC 0.00", "0.00001": "SVC 0.00", "0.000001": "SVC 0.00" } }, { "currencySymbol": "SYP", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "SYP 0", "0.01": "SYP 0", "0.001": "SYP 0", "0.0001": "SYP 0", "0.00001": "SYP 0", "0.000001": "SYP 0" } }, { "currencySymbol": "SZL", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "SZL 0.10", "0.01": "SZL 0.01", "0.001": "SZL 0.00", "0.0001": "SZL 0.00", "0.00001": "SZL 0.00", "0.000001": "SZL 0.00" } }, { "currencySymbol": "THB", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "THB 0.10", "0.01": "THB 0.01", "0.001": "THB 0.00", "0.0001": "THB 0.00", "0.00001": "THB 0.00", "0.000001": "THB 0.00" } }, { "currencySymbol": "TJS", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "TJS 0.10", "0.01": "TJS 0.01", "0.001": "TJS 0.00", "0.0001": "TJS 0.00", "0.00001": "TJS 0.00", "0.000001": "TJS 0.00" } }, { "currencySymbol": "TMT", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "TMT 0.10", "0.01": "TMT 0.01", "0.001": "TMT 0.00", "0.0001": "TMT 0.00", "0.00001": "TMT 0.00", "0.000001": "TMT 0.00" } }, { "currencySymbol": "TND", "decimalPlaces": 3, "decimalPlacesTested": { "0.1": "TND 0.100", "0.01": "TND 0.010", "0.001": "TND 0.001", "0.0001": "TND 0.000", "0.00001": "TND 0.000", "0.000001": "TND 0.000" } }, { "currencySymbol": "TOP", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "TOP 0.10", "0.01": "TOP 0.01", "0.001": "TOP 0.00", "0.0001": "TOP 0.00", "0.00001": "TOP 0.00", "0.000001": "TOP 0.00" } }, { "currencySymbol": "TRY", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "TRY 0.10", "0.01": "TRY 0.01", "0.001": "TRY 0.00", "0.0001": "TRY 0.00", "0.00001": "TRY 0.00", "0.000001": "TRY 0.00" } }, { "currencySymbol": "TTD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "TTD 0.10", "0.01": "TTD 0.01", "0.001": "TTD 0.00", "0.0001": "TTD 0.00", "0.00001": "TTD 0.00", "0.000001": "TTD 0.00" } }, { "currencySymbol": "TWD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "NT$0.10", "0.01": "NT$0.01", "0.001": "NT$0.00", "0.0001": "NT$0.00", "0.00001": "NT$0.00", "0.000001": "NT$0.00" } }, { "currencySymbol": "TZS", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "TZS 0.10", "0.01": "TZS 0.01", "0.001": "TZS 0.00", "0.0001": "TZS 0.00", "0.00001": "TZS 0.00", "0.000001": "TZS 0.00" } }, { "currencySymbol": "UAH", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "UAH 0.10", "0.01": "UAH 0.01", "0.001": "UAH 0.00", "0.0001": "UAH 0.00", "0.00001": "UAH 0.00", "0.000001": "UAH 0.00" } }, { "currencySymbol": "UGX", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "UGX 0", "0.01": "UGX 0", "0.001": "UGX 0", "0.0001": "UGX 0", "0.00001": "UGX 0", "0.000001": "UGX 0" } }, { "currencySymbol": "USD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "$0.10", "0.01": "$0.01", "0.001": "$0.00", "0.0001": "$0.00", "0.00001": "$0.00", "0.000001": "$0.00" } }, { "currencySymbol": "UYU", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "UYU 0.10", "0.01": "UYU 0.01", "0.001": "UYU 0.00", "0.0001": "UYU 0.00", "0.00001": "UYU 0.00", "0.000001": "UYU 0.00" } }, { "currencySymbol": "UZS", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "UZS 0.10", "0.01": "UZS 0.01", "0.001": "UZS 0.00", "0.0001": "UZS 0.00", "0.00001": "UZS 0.00", "0.000001": "UZS 0.00" } }, { "currencySymbol": "VEB", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "VEB 0.10", "0.01": "VEB 0.01", "0.001": "VEB 0.00", "0.0001": "VEB 0.00", "0.00001": "VEB 0.00", "0.000001": "VEB 0.00" } }, { "currencySymbol": "VEF", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "VEF 0.10", "0.01": "VEF 0.01", "0.001": "VEF 0.00", "0.0001": "VEF 0.00", "0.00001": "VEF 0.00", "0.000001": "VEF 0.00" } }, { "currencySymbol": "VES", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "VES 0.10", "0.01": "VES 0.01", "0.001": "VES 0.00", "0.0001": "VES 0.00", "0.00001": "VES 0.00", "0.000001": "VES 0.00" } }, { "currencySymbol": "VND", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "₫0", "0.01": "₫0", "0.001": "₫0", "0.0001": "₫0", "0.00001": "₫0", "0.000001": "₫0" } }, { "currencySymbol": "VUV", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "VUV 0", "0.01": "VUV 0", "0.001": "VUV 0", "0.0001": "VUV 0", "0.00001": "VUV 0", "0.000001": "VUV 0" } }, { "currencySymbol": "WST", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "WST 0.10", "0.01": "WST 0.01", "0.001": "WST 0.00", "0.0001": "WST 0.00", "0.00001": "WST 0.00", "0.000001": "WST 0.00" } }, { "currencySymbol": "XAF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "FCFA 0", "0.01": "FCFA 0", "0.001": "FCFA 0", "0.0001": "FCFA 0", "0.00001": "FCFA 0", "0.000001": "FCFA 0" } }, { "currencySymbol": "XCD", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "EC$0.10", "0.01": "EC$0.01", "0.001": "EC$0.00", "0.0001": "EC$0.00", "0.00001": "EC$0.00", "0.000001": "EC$0.00" } }, { "currencySymbol": "XOF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "F CFA 0", "0.01": "F CFA 0", "0.001": "F CFA 0", "0.0001": "F CFA 0", "0.00001": "F CFA 0", "0.000001": "F CFA 0" } }, { "currencySymbol": "XPF", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "CFPF 0", "0.01": "CFPF 0", "0.001": "CFPF 0", "0.0001": "CFPF 0", "0.00001": "CFPF 0", "0.000001": "CFPF 0" } }, { "currencySymbol": "YER", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "YER 0", "0.01": "YER 0", "0.001": "YER 0", "0.0001": "YER 0", "0.00001": "YER 0", "0.000001": "YER 0" } }, { "currencySymbol": "ZAR", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "ZAR 0.10", "0.01": "ZAR 0.01", "0.001": "ZAR 0.00", "0.0001": "ZAR 0.00", "0.00001": "ZAR 0.00", "0.000001": "ZAR 0.00" } }, { "currencySymbol": "ZMK", "decimalPlaces": 0, "decimalPlacesTested": { "0.1": "ZMK 0", "0.01": "ZMK 0", "0.001": "ZMK 0", "0.0001": "ZMK 0", "0.00001": "ZMK 0", "0.000001": "ZMK 0" } }, { "currencySymbol": "ZMW", "decimalPlaces": 2, "decimalPlacesTested": { "0.1": "ZMW 0.10", "0.01": "ZMW 0.01", "0.001": "ZMW 0.00", "0.0001": "ZMW 0.00", "0.00001": "ZMW 0.00", "0.000001": "ZMW 0.00" } } ] ```
aldo-expensify commented 1 year ago

Hmm, the ISO4217 specifies the number for decimals (see https://en.wikipedia.org/wiki/ISO_4217), and it doesn't match with what Intl.NumberFormat('en', {style: 'currency', currency: currencySymbol}).format(value) produces. We use ISO4217 i nthe backend. I think we have two options:

  1. Add in PHP CurrencyInfo.php a new key iouDecimals that matches Intl.NumberFormat. A new key instead of updating decimals because I'm worried about breaking something 😬
  2. Do something in App to match the decimal places listed in ISO4217
aldo-expensify commented 1 year ago

Hmm, ok, I think we can do it in the App passing maximumFractionDigits: <decimalsAccordingToISO4217> in the options given to Intl.NumberFormat. For example:

Intl.NumberFormat('es', {style: 'currency', currency: 'ALL', maximumFractionDigits: 3}).format(0.001)
'0,001 ALL'
aldo-expensify commented 1 year ago

Some weird cases:

COP (Colombian Peso)

ALL (Albanian Lek)

I'll try to get some opinions in slack about:

aldo-expensify commented 1 year ago

Following the slack discussion...

It seems that the best solution for now is using the php NumberFormatter library in the backend because the results produced align very well with what Intl produces.

To compare the results between php NumberFormatter and js Intl, I ran the following snippets:

const currencySymbols = ['AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BYR', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EEK', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'INR', 'IQD', 'IRR', 'ISK', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LTL', 'LVL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SRD', 'STD', 'STN', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEB', 'VEF', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMK', 'ZMW'];
const decimals = [0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001];
currencySymbols.map(currencySymbol => {
    let decimalPlaces = 0;
    let decimalPlacesTested = {};
    decimals.forEach((value, index) => {
        const en = Intl.NumberFormat('en', {style: 'currency', currency: currencySymbol}).format(value);
        const es = Intl.NumberFormat('es', {style: 'currency', currency: currencySymbol}).format(value);
        decimalPlacesTested[value] = {en, es};
        if (en.indexOf(`${value}`) !== -1) {
            decimalPlaces = index + 1;
        }
    });
    return {
        currencySymbol,
        decimalPlaces,
        decimalPlacesTested,
    };
});
<?

$currencySymbols = ['AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN', 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL', 'BSD', 'BTN', 'BWP', 'BYN', 'BYR', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY', 'COP', 'CRC', 'CUC', 'CUP', 'CVE', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD', 'EEK', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF', 'IDR', 'ILS', 'INR', 'IQD', 'IRR', 'ISK', 'JMD', 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LTL', 'LVL', 'LYD', 'MAD', 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MRU', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON', 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SRD', 'STD', 'STN', 'SVC', 'SYP', 'SZL', 'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TWD', 'TZS', 'UAH', 'UGX', 'USD', 'UYU', 'UZS', 'VEB', 'VEF', 'VES', 'VND', 'VUV', 'WST', 'XAF', 'XCD', 'XOF', 'XPF', 'YER', 'ZAR', 'ZMK', 'ZMW'];
$decimals = [0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001];
$result = [];
foreach ($currencySymbols as $currencySymbol) {
    $decimalPlaces = 0;
    $decimalPlacesTested = [];
    foreach ($decimals as $index => $value) {
        $index2 = $index+1;
        $stringValue = sprintf("%.${index2}f", $value);
        $en = (new NumberFormatter("en", NumberFormatter::CURRENCY))->formatCurrency($value, $currencySymbol);
        $es = (new NumberFormatter("es", NumberFormatter::CURRENCY))->formatCurrency($value, $currencySymbol);
        $decimalPlacesTested[$stringValue] = ['en' => $en, 'es' => $es];
        if (strpos($en, $stringValue) !== false) {
            $decimalPlaces = $index2;
        }
    }
    $result[] = [
        "currencySymbol" => $currencySymbol,
        "decimalPlaces" => $decimalPlaces,
        "decimalPlacesTested" => $decimalPlacesTested,
    ];
}
file_put_contents("currencies-php.json", json_encode($result, JSON_UNESCAPED_UNICODE));

Put the results in two json files and compare them agains each other

There were differences in only 3 currency symbols:

locale php NumberFormatter js Intl
es CA$ CAD
en PHP
en CFA F CFA

The numbers of decimal places in both libraries matched

aldo-expensify commented 1 year ago

PR up: https://github.com/Expensify/Web-Expensify/pull/35845

deetergp commented 1 year ago

https://github.com/Expensify/Web-Expensify/pull/35845 was reverted here due to this deploy blocker.

abekkala commented 1 year ago

I'm now ooo and will need to reassign. It looks like PR 35845 for fix was all reviewed internally as well. So, I don't believe that there would be an contributor payment due with this one. But maybe @aldo-expensify can confirm.

Most likely just the BZ checklist for this one.

JmillsExpensify commented 1 year ago

Yeah, no C/C+ on this issue.

JmillsExpensify commented 1 year ago

That said, don't forget to compensate @bernhardoj for reporting.

lschurr commented 1 year ago

Are we just waiting to see if there are any regressions on this one? Shall I post the job to pay @bernhardoj for reporting?

lschurr commented 1 year ago

@bernhardoj - Could you apply to the job here? https://www.upwork.com/jobs/~01936a4e7a1ece5487

JmillsExpensify commented 1 year ago

Given that you're probably headed out on vacay after tomorrow, I'd go ahead and try to settle up before you leave. The PR is internal and we chose to fix it, so fair game to pay out on.

lschurr commented 1 year ago

Thanks @JmillsExpensify - I'll keep an eye on it. When @bernhardoj applies/accepts in Upwork, I'll pay!

aldo-expensify commented 1 year ago

About the resolution state of this bug:

aldo-expensify commented 1 year ago

Salt PR was salted.

New PR up redoing the change in the php API: https://github.com/Expensify/Web-Expensify/pull/35908

lschurr commented 1 year ago

Just noting from the BZ side that the payment was already made to the bug reporter.

lschurr commented 1 year ago

@aldo-expensify is this one resolved?

aldo-expensify commented 1 year ago

@aldo-expensify is this one resolved?

I believe so. The PR https://github.com/Expensify/Web-Expensify/pull/35908 is in production and was QAed.