[$250] Invoice-Wrong recipient when selecting an email address after selecting an Invoice room
If you havenβt already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!
Version Number: v9.2.21-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: Found when working on https://github.com/Expensify/App/pull/71648 Email or phone of affected tester (no customers): [email protected] Issue reported by: Applause Internal Team Device used: Windows 11/ Chrome, Samsung S23FE/ Android 15, iPhone 13 Mini/ iOS 18.5 App Component: Other
Action Performed:
Preconditions: Have a workspace with the Invoices feature enabled. Have at least one Invoice room.
- Go to staging.new.expensify.com
- Open FAB > Send invoice
- Enter amount > Next
- Select an Invoice room from Recents
- In the "To" field, click on the right caret icon
- Enter an email address that is not included in any Invoice room with the current user 7 Send the invoice
Expected Result:
The app creates the invoice thread in a new Invoice room with the email address entered in step 6.
Actual Result:
The app creates the invoice thread in the Invoice room selected in step 4.
Workaround:
Unknown
Platforms:
- [x] Android: App
- [x] Android: mWeb Chrome
- [x] iOS: App
- [x] iOS: mWeb Safari
- [x] iOS: mWeb Chrome
- [x] Windows: Chrome
- [x] MacOS: Chrome / Safari
- [ ] MacOS: Desktop
Screenshots/Videos
https://github.com/user-attachments/assets/a778754b-769f-44d2-80d3-04a42a96b49d
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~021973664764145064677
- Upwork Job ID: 1973664764145064677
- Last Price Increase: 2025-12-25
Issue Owner
Current Issue Owner: @DylanDylann
Triggered auto assignment to @dylanexpensify (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.
Proposal
Please re-state the problem that we are trying to solve in this issue.
Invoice-Wrong recipient when selecting an email address after selecting an Invoice room
What is the root cause of that problem?
Invoice room selection logic prioritizes a pre-selected report over checking if the current transaction participants have changed
https://github.com/Expensify/App/blob/f3984ef514f3293ab0c843ead97223a6f1a3678c/src/pages/iou/request/step/IOURequestStepConfirmation.tsx#L869-L884
reportis the invoice room selected from recentsexistingInvoiceReportis determined by theuseParticipantsInvoiceReporthook based on current transaction participants
The issue occurs because when a user selects an invoice room and then changes the email address, the transaction participants are updated but it still uses the originally selected report instead of checking if it matches the new recipient
What changes do you think we should make in order to solve the problem?
We can check if the selected report matches the current transaction participants before using it
const doesReportMatchCurrentReceiver = report?.invoiceReceiver && 'accountID' in report.invoiceReceiver && report.invoiceReceiver.accountID === receiverAccountID;
// Or check for policyID as well
const doesReportMatchCurrentReceiver =
report?.invoiceReceiver &&
(('accountID' in report.invoiceReceiver && report.invoiceReceiver.accountID === receiverAccountID) ||
('policyID' in report.invoiceReceiver &&
receiverParticipant &&
'policyID' in receiverParticipant &&
report.invoiceReceiver.policyID === receiverParticipant.policyID)) &&
report.invoiceReceiver.type === receiverType;
Then use it here
const invoiceChatReport = doesReportMatchCurrentReceiver && report?.reportID ? report : existingInvoiceReport;
https://github.com/Expensify/App/blob/f3984ef514f3293ab0c843ead97223a6f1a3678c/src/pages/iou/request/step/IOURequestStepConfirmation.tsx#L870
What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?
None
What alternative solutions did you explore? (Optional)
None
Proposal
Please re-state the problem that we are trying to solve in this issue.
Wrong recipient when selecting an email address after selecting an Invoice room
What is the root cause of that problem?
The existingInvoiceReport is calculated by useParticipantsInvoiceReport based on current transaction participants (recipient B)
https://github.com/Expensify/App/blob/7a216023f2371a3c26c8a31112966a0ca8a55c0e/src/pages/iou/request/step/IOURequestStepConfirmation.tsx#L177
But the original report from route parameter (for recipient A)
When no existing invoice report exists for the new recipient B, the logic fell back to the original report for recipient A
So instead of creating a new report, the code fell back to the stale original report --> This caused the invoice to be created in the wrong room
What changes do you think we should make in order to solve the problem?
For useParticipantsInvoiceReport, we need the correct receiverID based on receiver type to calculate existingInvoiceReport in useParticipantsInvoiceReport
let receiverID: string | number | undefined = receiverAccountID;
if (receiverType === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS && receiverParticipant && 'policyID' in receiverParticipant) {
receiverID = receiverParticipant.policyID;
}
const existingInvoiceReport = useParticipantsInvoiceReport(receiverID, receiverType, senderWorkspaceID);
https://github.com/Expensify/App/blob/7a216023f2371a3c26c8a31112966a0ca8a55c0e/src/pages/iou/request/step/IOURequestStepConfirmation.tsx#L177
Update here to fallback to existingInvoiceReport if exists
const invoiceChatReport = existingInvoiceReport;
https://github.com/Expensify/App/blob/7a216023f2371a3c26c8a31112966a0ca8a55c0e/src/pages/iou/request/step/IOURequestStepConfirmation.tsx#L865
What alternative solutions did you explore? (Optional)
Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.
Job added to Upwork: https://www.upwork.com/jobs/~021973664764145064677
Triggered auto assignment to Contributor-plus team member for initial proposal review - @DylanDylann (External)
π« Duplicated proposal withdrawn by π€ ProposalPolice.
β οΈ @huult Your proposal is a duplicate of an already existing proposal and has been automatically withdrawn to prevent spam. Please review the existing proposals before submitting a new one.
Proposal
Please re-state the problem that we are trying to solve in this issue.
Invoice drafts created from the FAB could not be addressed to a new recipient if the user previously picked an existing invoice room. Entering a new email in the confirmation step still re-used the earlier room, so the invoice was sent to the wrong conversation.
What is the root cause of that problem?
The confirmation step and the invoicing action both prioritized an existing invoice room whenever a report was available on the route. In getSendInvoiceInformation, the receiver was picked only when a participant had a persisted accountID, otherwise the logic fell back to the existing room
https://github.com/Expensify/App/blob/b76a7405c94919fc6269506d9489decaffa572e5/src/libs/actions/IOU.ts#L3204-L3218
Similarly, the confirmation page derived the receiver directly from report?.invoiceReceiver when no accountID was present, ignoring a newly entered login
https://github.com/Expensify/App/blob/b76a7405c94919fc6269506d9489decaffa572e5/src/pages/iou/request/step/IOURequestStepConfirmation.tsx#L174-L179
As a result the old room stayed selected even after typing a different email.
What changes do you think we should make in order to solve the problem?
Update both the confirmation screen and the invoicing action to prefer the participant supplied by the current transaction (including those identified only by login) and only reuse the existing invoice room when that participant truly represents the same room.
// src/pages/iou/request/step/IOURequestStepConfirmation.tsx
const receiverParticipantFromTransaction = transaction?.participants?.find(
(participant) => !participant?.isSender && (!!participant?.accountID || !!participant?.login),
);
const receiverParticipant: Participant | InvoiceReceiver | undefined = receiverParticipantFromTransaction ?? report?.invoiceReceiver;
// src/libs/actions/IOU.ts
const receiverParticipantFromTransaction = participants?.find(
(participant) => !participant?.isSender && (!!participant?.accountID || !!participant?.login),
);
const shouldUseExistingInvoiceChat = !receiverParticipantFromTransaction || !!receiverParticipantFromTransaction.reportID;
const invoiceChatReportToUse = shouldUseExistingInvoiceChat ? invoiceChatReport : undefined;
const receiverParticipantFromReport = invoiceChatReportToUse?.invoiceReceiver;
const receiverParticipant: Participant | InvoiceReceiver | undefined = receiverParticipantFromTransaction ?? receiverParticipantFromReport;
...
const parameters: SendInvoiceParams = {
...,
...(receiverInvoiceRoomID ? {receiverInvoiceRoomID} : {receiverEmail: receiver.login ?? ''}),
};
These updates ensure a new invoice room is generated when the user types an email that does not yet belong to an existing room, while still preserving the previous behavior when the selected participant already references a room.
What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?
- Unit test for the confirmation step selector ensuring it returns the new participant when present and only falls back to
report?.invoiceReceiverwhen transaction data lacks a receiver.
Hi everyone, I think we should fix this issue from the RCA that reportID from the route isn't updated, when the user selects another option --> In IOURequestStepConfirmation, reportReal will be wrong --> report will be wrong --> invoiceChatReport will be wrong
You guys can see how we handle this problem in another place to suggest ideas
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
Looking for proposals
@dylanexpensify @DylanDylann this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
@DylanDylann Eep! 4 days overdue now. Issues have feelings too...
@DylanDylann 6 days overdue. This is scarier than being forced to listen to Vogon poetry!
@dylanexpensify Should we consider doubling the price?
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
@DylanDylann Eep! 4 days overdue now. Issues have feelings too...
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
@dylanexpensify @DylanDylann this issue is now 4 weeks old, please consider:
- Finding a contributor to fix the bug
- Closing the issue if BZ has been unable to add the issue to a VIP or Wave project
- If you have any questions, don't hesitate to start a discussion in #expensify-open-source
Thanks!
@DylanDylann 6 days overdue. This is scarier than being forced to listen to Vogon poetry!
@DylanDylann 10 days overdue. Is anyone even seeing these? Hello?
@DylanDylann 12 days overdue. Walking. Toward. The. Light...
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
Looking for proposals
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
π£ It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? πΈ
This issue has not been updated in over 14 days. @dylanexpensify, @DylanDylann eroding to Weekly issue.
Issue not reproducible during KI retests. (First week)