Guard against empty personalDetails when formatting attendees#84300
Draft
Guard against empty personalDetails when formatting attendees#84300
Conversation
When currentUserPersonalDetails has no login and no accountID (e.g., data not yet loaded during app startup), formatCurrentUserToAttendee would create an attendee with all-empty fields. This ghost attendee then gets persisted server-side and can suppress category limit violations by inflating the attendee count in the per-person amount calculation. The fix strengthens the guard to check both login and accountID instead of just checking for a falsy currentUser object. Co-authored-by: Rocio Perez-Cano <pecanoro@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Explanation of Change
When
personalDetailshasn't fully loaded on the Android mobile app,formatCurrentUserToAttendeecreates a "ghost" attendee with all-empty fields (email: "", displayName: "", accountID: 0). This ghost attendee inflates the attendee count, which causesgetAmountViolationon the server to divide the expense amount by the number of attendees — effectively halving the per-person amount and preventing legitimate over-category-limit violations from being flagged.This PR strengthens the guard in
formatCurrentUserToAttendeeto check that the user object has at least a validloginoraccountIDbefore creating an attendee entry. If neither is present, the function returns early (same as theundefinedcase), preventing ghost attendees from being added to expenses.Fixed Issues
$ https://github.com/Expensify/Expensify/issues/606961
Tests
Unit tests added:
formatCurrentUserToAttendeereturnsundefinedwhencurrentUserisundefinedformatCurrentUserToAttendeereturnsundefinedwhencurrentUserhas no login and no accountID (the ghost attendee scenario)formatCurrentUserToAttendeereturns a valid attendee whencurrentUserhas a valid loginformatCurrentUserToAttendeereturns a valid attendee whencurrentUserhas a valid accountID but no loginOffline tests
No specific offline behavior changes — this fix prevents bad data from being created regardless of network state.
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
N/A - Logic-only change, no UI modifications
Android: mWeb Chrome
N/A - Logic-only change, no UI modifications
iOS: Native
N/A - Logic-only change, no UI modifications
iOS: mWeb Safari
N/A - Logic-only change, no UI modifications
MacOS: Chrome / Safari
N/A - Logic-only change, no UI modifications