App: [HOLD for payment 2023-04-27] [$2000] Split - 'Split bill' incorrectly divides bills for some currencies
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:
- Open app and log in
- Click the FAB button and select Split Bill
- Select currency with a low exchange rate (for example, AFN or JPY)
- Enter an amount such that when divided by the number of attendees, fractional values are obtained. For example: 103 for 3 attendees, or 10 JPY between 4 attendees.
- Select attendees
- Check the amount for each attendee and sum these numbers
Expected Result:
- The amount obtained by summing up the numbers for each participant must be equal to the original amount that was entered in the BNP, even if this results in slightly different amounts for the different participants.
- We shouldn’t send “cents” to the backend if the unit doesn’t show “cents” in the UI. For example, if we split JPY, we should make sure we divide the amounts in integers.
10 JPY between 4 attendees should be split like 3, 3, 3 and 1 (remainder: 10 - 3 - 3 - 3), and the request to the backend should have the amounts 300, 300, 200 and 200. Each part that is not the remainder is just the Math.round(total / parts).
Actual Result:
The sum of divided bills does not equal the original number. Looks like the app divides with rounding and then discards all decimal places for currencies with low exchange rate like JPY. In our case we get 34x3 = 102 and not 103 as it should.
The request SplitBillAndOpenReport has decimal amounts in it:
Workaround:
Unknown
Platforms:
Which of our officially supported platforms is this issue occurring on?
- Android / native
- Android / Chrome
- iOS / native
- iOS / Safari
- MacOS / Chrome / Safari
- MacOS / Desktop
Version Number: 1.2.82.3
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from TestRail:
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Notes/Photos/Videos: Any additional supporting documentation
Expensify/Expensify Issue URL:
Issue reported by: Applause - Internal Team
Slack conversation:
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~013aa2514a7501c2d0
- Upwork Job ID: 1635977229585281024
- Last Price Increase: 2023-03-29
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 110 (94 by maintainers)
I think we landed here:
I think as soon as the backend PR is merged (no need to wait for deploy), @tienifr can update the PR to use the decimals in Onyx. I’m waiting because I don’t want to ask @tienifr to update the PR to use this and then, if it doesn’t get approved for some reason, @tienifr has to rollback.
Actually, currencyList is also stored in Onyx. However this data is provided by the back-end, specifically on OpenApp API response. Therefore, I believe we should go with @aldo-expensify’s suggestion on using
Intl.formatNumber.Lucky for me, the PR I’ve been working on already follows the second approach 😆😆 So I think it’s ready for your review!
it may be, but my intention is to keep the scope of this issue small and that current split logic can be discussed/fixed in an another issue. I had a small chat with @JmillsExpensify about this and splitting these tiny amounts into many participants is just an edge case we may not care about.
Here we are just dealing with the cents appearing in currencies that don’t support it.
Here’s summary for PR merge timeline:
There was weekend between Apr 13 - Apr 18 So I can say PR merged within 3 business days
No PRs caused regression. The issue existed from the beginning. Before, we treated all currencies same as USD which has 2 digits. So 1-3 items can be checked off. For regression test steps, we already have automated tests with good examples with edge cases so I don’t think it’s required.
@tienifr the backend PRs has been merged, but not deployed yet. Can you update your PR so it gets the decimal numbers from
currencyListin Onyx? 🙏I’ll remove the HOLD once the backend PR is deployed.
Either way, can we hold this until we get confirmation? Because PR cannot be merged until then and it affects timeline.
The currency list we send from the backend already contains a property call “decimals” for some of them. This property usually is
0or missing. If it is missing, we are supposed to assume that there are 2 decimals.This list is a bit outdated and there is a good number of currencies with 0 decimals that are missing
decimals: 0. I’m updating this in the backend. After this is updated, @tienifr you can use the currency list from onyx to figure out the number of decimals.ok I also suggest to do nothing in split logic. So leave negative value as is now for such extreme edge case. That being said, we can go with @tienifr’s solution Let’s make sure that we are not missing any currencies that don’t have 2 digits and also not exist in formatjs currency digits data
🎀 👀 🎀 C+ reviewed cc: @aldo-expensify
@aimane-chnaif here’s the demo video you requested for this case
https://user-images.githubusercontent.com/113963320/228623640-c9b846f0-b4a7-4e94-ac98-947743cc141d.mp4
@aimane-chnaif I think it was marked “do nothing” by another contributor rather than the team, so the solution hasn’t been made yet if it should be a GH issue 😁 Maybe @aldo-expensify can help decide here whether to fix it as part of this issue.
Agreed, I think we currently use Intl.NumberFormat to format currency? it would be ideal to use the same and not a 3rd party library so we don’t get inconsistencies where
Intldoesn’t use decimals from some currency and the 3rd party library does.Sorry, that was my mistake, it is not the intention to change how it works for USD. I’ll update my example to follow the same pattern. Splitting 10 JPY between 4 people should be 3, 3, 3 and 1 if that is more consistent with the current split in USD.
FYI the solution for that new split logic (aside from the above proposals, if we choose to implement it) will be:
Math.floor(10 / 4) = 2-> we get an array of [2, 2, 2, 2])10 % 4 = 2)A short snippet for the logic:
Compared to the current split logic that we have:
Math.round(10 / 4) = 3-> we get an array of [3, 3, 3, 3])This is the current behavior.
@aimane-chnaif friendly bump for reviewing proposals
I know that we can do cents when we split the amount equally, but I’m thinking that we shouldn’t split in cents if the currency doesn’t show cents in the UI. For example, for JPY, if we split 4 JPY between 3 people, the splits should be 1, 1 and 2, and not 1.33, 1.33 and 1.34.
Do you agree @aimane-chnaif @hayata-suenaga ?
reviewing proposals shortly