You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Due for payment 2025-10-23] [$250] Expense - Report list is not filtered when moving per diem expense #70809
The report from Workspace B should not appear on the Report list because Workspace B does not have per diem rates.
Actual Result:
The report from Workspace B appears on the Report list when Workspace B does not have per diem rates, but the per diem expense cannot be moved to the report.
Please re-state the problem that we are trying to solve in this issue.
Expense - Report list is not filtered when moving per diem expense
What is the root cause of that problem?
We can't move per diem expense to different workspace as BE will return this response
"Heads up! You can't transfer Per Diem International expenses between workspaces, as the Per Diem International rates may differ on each workspace. Please select a report on the Ryan's Workspace workspace, or create a new expense in the desired workspace to continue."
When filtering available reports for moving expenses, there is no validation to ensure that per diem expenses can only be moved to the workspaces they were originally created in. The current logic shows ALL workspace reports when moving expenses, without checking if the expense being moved is a per diem expense that requires specific workspace compatibility
What changes do you think we should make in order to solve the problem?
We can check the original workspace of the per diem expense before showing the available reports by filtering it with per diem custom unit like we did here
const[allPolicies]=useOnyx(ONYXKEYS.COLLECTION.POLICY,{canBeMissing: true});const[allTransactions]=useOnyx(ONYXKEYS.COLLECTION.TRANSACTION,{canBeMissing: true});
...
// Per diem expense handlingconstmovingTransactions=useMemo(()=>{if(!transactionIDs||!allTransactions)return[];returntransactionIDs.map((id)=>allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${id}`]).filter(Boolean);},[transactionIDs,allTransactions]);constcurrentTransaction=movingTransactions.at(0);constisPerDiemExpense=isPerDiemRequest(currentTransaction);constperDiemWorkspacePolicyID=isPerDiemExpense ? selectedReport?.policyID : undefined;constperDiemCustomUnitID=isPerDiemExpense ? currentTransaction?.comment?.customUnit?.customUnitID : undefined;
Then we filter it on expenseReports section
constexpenseReports=useMemo(()=>{// Early return if no reports are available to prevent useless loopif(!outstandingReportsByPolicyID||isEmptyObject(outstandingReportsByPolicyID)){return[];}constpersonalPolicyID=getPersonalPolicy()?.id;if(!selectedPolicyID||selectedPolicyID===personalPolicyID||isSelfDM(selectedReport)){returnObject.values(allPoliciesID??{}).filter((policyID)=>personalPolicyID!==policyID).flatMap((policyID)=>{if(!policyID){return[];}// For per diem expenses, filter reports based on the original workspaceif(isPerDiemExpense){// If expense is still in workspace, use the workspace policy IDif(perDiemWorkspacePolicyID&&policyID!==perDiemWorkspacePolicyID){return[];}// If expense moved to self DM, match by custom unit ID to find original workspaceif(!perDiemWorkspacePolicyID&&perDiemCustomUnitID){constpolicy=allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];constworkspacePerDiemUnit=getPerDiemCustomUnit(policy);if(!workspacePerDiemUnit||workspacePerDiemUnit.customUnitID!==perDiemCustomUnitID){return[];}}}constreports=getOutstandingReportsForUser(policyID,reportOwnerAccountID,outstandingReportsByPolicyID?.[policyID??CONST.DEFAULT_NUMBER_ID]??{},reportNameValuePairs,isEditing,);returnreports;});}// For per diem expenses, ensure we only show reports from compatible workspaceif(isPerDiemExpense&&selectedPolicyID){// If expense is still in workspace, only show reports from that workspaceif(perDiemWorkspacePolicyID&&selectedPolicyID!==perDiemWorkspacePolicyID){return[];}// If expense moved to self DM, check if target workspace has compatible per diem ratesif(!perDiemWorkspacePolicyID&&perDiemCustomUnitID){constpolicy=allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${selectedPolicyID}`];constworkspacePerDiemUnit=getPerDiemCustomUnit(policy);if(!workspacePerDiemUnit||workspacePerDiemUnit.customUnitID!==perDiemCustomUnitID){return[];}}}returngetOutstandingReportsForUser(selectedPolicyID,reportOwnerAccountID,outstandingReportsByPolicyID?.[selectedPolicyID??CONST.DEFAULT_NUMBER_ID]??{},reportNameValuePairs,isEditing,);},[outstandingReportsByPolicyID,reportOwnerAccountID,allPoliciesID,reportNameValuePairs,selectedReport,selectedPolicyID,isEditing,isPerDiemExpense,perDiemWorkspacePolicyID,perDiemCustomUnitID,allPolicies,]);
Please re-state the problem that we are trying to solve in this issue.
When a user tries to move a per diem expense from one workspace to another, the system shows reports from all workspaces in the selection list, including workspaces that don't have per diem rates enabled.
What is the root cause of that problem?
The report selection logic in IOURequestEditReportCommon.tsx was not filtering out reports from workspaces that don't support per diem expenses.
What changes do you think we should make in order to solve the problem?
We should add another filter to check if transaction is per diem and workspaces supporting per diem expenses:
returnexpenseReports.sort((report1,report2)=>sortOutstandingReportsBySelected(report1,report2,selectedReportID,localeCompare)).filter((report)=>!debouncedSearchValue||report?.reportName?.toLowerCase().includes(debouncedSearchValue.toLowerCase())).filter((report): report is NonNullable<typeofreport>=>report!==undefined).filter((report)=>{// Filter out reports from workspaces that don't support per diem expensesif(isPerDiemRequest&&report?.policyID){constpolicy=allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`];returncanSubmitPerDiemExpenseFromWorkspace(policy);}returntrue;})...
And isPerDiemRequest is passed as props where we decide if transaction is per dim or not in
Please re-state the problem that we are trying to solve in this issue.
When a user tries to move a per diem expense from one workspace to another, the system shows reports from all workspaces in the selection list, including workspaces that don't have per diem rates enabled. This allows users to attempt moving per diem expenses to incompatible workspaces, which results in a backend error:
{
"code": 666,
"jsonCode": 666,
"type": "Expensify\\Libs\\Error\\ExpError",
"UUID": "1482DEDE-C9D4-4DD5-A00C-E6A62D988167",
"message": "Heads up! You can't transfer Per Diem International expenses between workspaces, as the Per Diem International rates may differ on each workspace. Please select a report on the W1 workspace, or create a new expense in the desired workspace to continue.",
"title": "",
"data": [],
"htmlMessage": "",
"onyxData": [],
"requestID": "982aa44b0cbf2646-LAX"
}
What is the root cause of that problem?
The report selection logic in IOURequestEditReportCommon.tsx does not filter reports based on per diem expense compatibility. The current reportOptions generation shows ALL available reports without checking if the expense being moved is a per diem expense that requires specific workspace compatibility.
The issue is that there's no validation to ensure per diem expenses can only be moved to workspaces with compatible per diem rates.
What changes do you think we should make in order to solve the problem?
We should add per diem compatibility filtering using an Onyx selector, following the existing pattern used in AddUnreportedExpense.tsx(pattern linked at bottom). This approach filters data at the source level, making it more efficient and following established architectural patterns in the codebase.
Add data access, create selector for filtering and apply selector to useOnyx:
const[allPolicies]=useOnyx(ONYXKEYS.COLLECTION.POLICY,{canBeMissing: true});const[allTransactions]=useOnyx(ONYXKEYS.COLLECTION.TRANSACTION,{canBeMissing: true});// Filter outstanding reports for per diem compatibilityconstgetFilteredOutstandingReports=useMemo(()=>{return(reports: any)=>{if(!reports||!transactionIDs?.length||!allTransactions||!allPolicies){returnreports;}// Check if any transaction is per diemconsthasPerDiemTransaction=transactionIDs.some((id)=>{consttransaction=allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${id}`];returnisPerDiemRequest(transaction);});if(!hasPerDiemTransaction){returnreports;}// Get per diem custom unit ID for compatibility checkconstperDiemTransaction=transactionIDs.map((id)=>allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${id}`]).find((transaction)=>isPerDiemRequest(transaction));constperDiemCustomUnitID=perDiemTransaction?.comment?.customUnit?.customUnitID;// Filter reports by per diem compatibilityconstfilteredReports: any={};Object.entries(reports).forEach(([policyID,policyReports])=>{constpolicy=allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];if(canSubmitPerDiemExpenseFromWorkspace(policy)){if(perDiemCustomUnitID){constworkspacePerDiemUnit=getPerDiemCustomUnit(policy);if(workspacePerDiemUnit?.customUnitID===perDiemCustomUnitID){filteredReports[policyID]=policyReports;}}else{filteredReports[policyID]=policyReports;}}});returnfilteredReports;};},[transactionIDs,allTransactions,allPolicies]);const[outstandingReportsByPolicyID]=useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID,{canBeMissing: true,selector: getFilteredOutstandingReports,});
changed the title [-]Expense - Report list is not filtered when moving per diem expense[/-][+][$250] Expense - Report list is not filtered when moving per diem expense[/+]on Sep 23, 2025
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: Not critical
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
Regression Test Proposal Template
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Link to issue:
Regression Test Proposal
Precondition:
Workspace A has imported per diem rates.
Workspace B does not have per diem rates.
Activity
melvin-bot commentedon Sep 18, 2025
Triggered auto assignment to @mallenexpensify (
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.ryntgh commentedon Sep 18, 2025
Proposal
Please re-state the problem that we are trying to solve in this issue.
Expense - Report list is not filtered when moving per diem expense
What is the root cause of that problem?
We can't move per diem expense to different workspace as BE will return this response
When filtering available reports for moving expenses, there is no validation to ensure that per diem expenses can only be moved to the workspaces they were originally created in. The current logic shows ALL workspace reports when moving expenses, without checking if the expense being moved is a per diem expense that requires specific workspace compatibility
App/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Lines 79 to 110 in c96ff29
What changes do you think we should make in order to solve the problem?
We can check the original workspace of the per diem expense before showing the available reports by filtering it with per diem custom unit like we did here
Then we filter it on
expenseReportssectionApp/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Lines 79 to 110 in c96ff29
Implementation can be improved during PR phase
What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?
N/A
What alternative solutions did you explore? (Optional)
N/A
mukhrr commentedon Sep 18, 2025
Proposal
Please re-state the problem that we are trying to solve in this issue.
When a user tries to move a per diem expense from one workspace to another, the system shows reports from all workspaces in the selection list, including workspaces that don't have per diem rates enabled.
What is the root cause of that problem?
The report selection logic in
IOURequestEditReportCommon.tsxwas not filtering out reports from workspaces that don't support per diem expenses.App/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Lines 85 to 102 in 1f58846
What changes do you think we should make in order to solve the problem?
We should add another filter to check if transaction is per diem and workspaces supporting per diem expenses:
And
isPerDiemRequestis passed as props where we decide if transaction is per dim or not inApp/src/pages/iou/request/step/IOURequestStepReport.tsx
Lines 161 to 172 in 1f58846
What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?
What alternative solutions did you explore? (Optional)
ganzz4 commentedon Sep 21, 2025
Proposal
Please re-state the problem that we are trying to solve in this issue.
When a user tries to move a per diem expense from one workspace to another, the system shows reports from all workspaces in the selection list, including workspaces that don't have per diem rates enabled. This allows users to attempt moving per diem expenses to incompatible workspaces, which results in a backend error:
What is the root cause of that problem?
The report selection logic in
IOURequestEditReportCommon.tsxdoes not filter reports based on per diem expense compatibility. The currentreportOptionsgeneration shows ALL available reports without checking if the expense being moved is a per diem expense that requires specific workspace compatibility.App/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Lines 119 to 141 in d41575d
The issue is that there's no validation to ensure per diem expenses can only be moved to workspaces with compatible per diem rates.
What changes do you think we should make in order to solve the problem?
We should add per diem compatibility filtering using an Onyx selector, following the existing pattern used in
AddUnreportedExpense.tsx(pattern linked at bottom). This approach filters data at the source level, making it more efficient and following established architectural patterns in the codebase.Required imports:
App/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Line 15 in d41575d
Add data access, create selector for filtering and apply selector to useOnyx:
Add after this:
App/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Line 68 in d41575d
And remove the old useOnyx call:
App/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Line 56 in d41575d
Update dependencies array:
App/src/pages/iou/request/step/IOURequestEditReportCommon.tsx
Line 141 in d41575d
This solution:
AddUnreportedExpense.tsxApp/src/pages/AddUnreportedExpense.tsx
Lines 59 to 84 in d41575d
What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?
N/A, UI issue
What alternative solutions did you explore? (Optional)
ganzz4 commentedon Sep 21, 2025
Note for Reviewers:
To test per diem expense filtering, enable unreported expenses first:
App/src/libs/Permissions.ts
Lines 18 to 23 in d41575d
This is required after PR #70663 to access the "Report" button for unreported per diem expenses.
melvin-bot commentedon Sep 23, 2025
Job added to Upwork: https://www.upwork.com/jobs/~021970622101408081191
[-]Expense - Report list is not filtered when moving per diem expense[/-][+][$250] Expense - Report list is not filtered when moving per diem expense[/+]melvin-bot commentedon Sep 23, 2025
Triggered auto assignment to Contributor-plus team member for initial proposal review - @rushatgabhane (
External)44 remaining items
mallenexpensify commentedon Oct 27, 2025
@mukhrr paid, summary is updated above
@rushatgabhane plz complete the BZ checklist.
mallenexpensify commentedon Oct 30, 2025
@rushatgabhane 👀 plz, need BZ checkilst to wrap this up.
rushatgabhane commentedon Oct 30, 2025
BugZero Checklist:
Bug classification
Source of bug:
Where bug was reported:
Who reported the bug:
[Contributor] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.
Link to comment: https://github.com/Expensify/App/pull/71866/files#r2479618488
[Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.
Link to discussion: Not critical
[Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.
Regression Test Proposal Template
[BugZero Assignee] Create a GH issue for creating/updating the regression test once above steps have been agreed upon.
Link to issue:
Regression Test Proposal
Precondition:
Workspace A has imported per diem rates.
Workspace B does not have per diem rates.
Test:
Do we agree 👍 or 👎
garrettmknight commentedon Nov 1, 2025
$250 approved for @rushatgabhane
melvin-bot commentedon Nov 4, 2025
@rushatgabhane Huh... This is 4 days overdue. Who can take care of this?
MarioExpensify commentedon Nov 5, 2025
@mallenexpensify can we close this?
mallenexpensify commentedon Nov 5, 2025
Yup! I created a test case, linked the test case in the OP too, in case that needs to be updated.
Thx