Add billing restriction guard to duplicate expense handlers#88363
Add billing restriction guard to duplicate expense handlers#88363
Conversation
…lers The duplicate expense flow never checks whether the target workspace has expired billing. This allows users to bypass the billing restriction by duplicating expenses into expired workspaces. Add the same shouldRestrictUserBillableActions guard that exists in the Add Expense handler to all duplicate expense entry points: - useExpenseActions: DUPLICATE_EXPENSE and DUPLICATE_REPORT handlers - MoneyRequestHeaderSecondaryActions: transaction-level DUPLICATE handler - useSearchBulkActions: bulk DUPLICATE handler (both contexts) Co-authored-by: Eugene Voloshchak <eVoloshchak@users.noreply.github.com>
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
|
@MelvinBot, bug: Screen.Recording.2026-04-23.at.21.13.29.mov |
|
@MelvinBot, fix the bug with the context not being closed when ROUTES.RESTRICTED_ACTION page is opened, which results in them overlapping |
The duplicate action handlers have shouldCloseModalOnSelect set to false, so the dropdown menu stays open when the billing restriction guard triggers navigation to ROUTES.RESTRICTED_ACTION, causing them to overlap. Co-authored-by: Eugene Voloshchak <eVoloshchak@users.noreply.github.com>
|
Fixed the context menu overlap bug. The duplicate action handlers have Added explicit menu close calls before navigation in all three affected handlers:
The search bulk action handlers ( |
The call sites were passing a Policy object as a 5th argument, but the current main branch signature expects only 4 arguments (with policyID string as the first). Removed the redundant 5th argument from all call sites to match the expected function signature. Co-authored-by: Eugene Voloshchak <eVoloshchak@users.noreply.github.com>
|
Fixed the failing typecheck: the |
|
@MelvinBot, This branch has conflicts that must be resolved, pull the latest main |
|
⏱️ Ran out of time before I could finish. This usually means the task was too complex or I got stuck exploring. Please try again with a more specific request or post in #melvinbot-ai. |
|
@MelvinBot, This branch has conflicts that must be resolved, pull the latest main |
Resolve conflicts in useExpenseActions.ts and useSearchBulkActions.ts by adopting main's updated shouldRestrictUserBillableActions signature. Co-authored-by: Eugene Voloshchak <eVoloshchak@users.noreply.github.com>
|
Merged latest |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-04-29.at.22.45.10.movAndroid: mWeb ChromeScreen.Recording.2026-04-29.at.22.42.53.moviOS: HybridAppScreen.Recording.2026-04-29.at.22.32.47.moviOS: mWeb SafariScreen.Recording.2026-04-29.at.22.37.05.movMacOS: Chrome / SafariScreen.Recording.2026-04-29.at.22.28.37.mov |
|
Preconditions:
Tests:
@MelvinBot, add the above tests to the checklist |
|
Updated the Tests and QA Steps sections in the PR description with the provided test steps. |
|
@MelvinBot, this is ready for review |
|
I wasn't able to mark this PR as ready for review due to a permissions issue. |
|
We did not find an internal engineer to review this PR, trying to assign a random engineer to #84368 as well as to this PR... Please reach out for help on Slack if no one gets assigned! |
|
@MelvinBot, how do I mark this as ready for review from console? |
|
Run |
|
@eVoloshchak conflicts |
|
@MelvinBot, This branch has conflicts that must be resolved, pull the latest main |
Co-authored-by: Eugene Voloshchak <eVoloshchak@users.noreply.github.com>
|
Merged latest main and resolved the conflict in |
|
MelvinBot has made 5 consecutive commits trying to fix CI failures. Automatic CI fix dispatches are now paused for this PR. Next steps: A human should review the recent commits and resolve the conflicting CI errors manually. |
Explanation of Change
The duplicate expense flow never checks whether the target workspace has expired billing. When a user duplicates an expense, the target workspace is selected via
useDefaultExpensePolicy→isPolicyAccessible, which only verifies the policy exists and the user has a role — it does not check billing/expiration status.This adds the same
shouldRestrictUserBillableActionsguard that already exists in the Add Expense handler to all duplicate expense entry points:useExpenseActions.ts:DUPLICATE_EXPENSEandDUPLICATE_REPORThandlersMoneyRequestHeaderSecondaryActions.tsx: Transaction-levelDUPLICATEhandleruseSearchBulkActions.ts: BulkDUPLICATEhandler (both deleted-transactions and normal contexts)When the target policy has restricted billable actions, the user is now navigated to
ROUTES.RESTRICTED_ACTIONinstead of proceeding with the duplication — consistent with the existing Add Expense behavior.Fixed Issues
$ #84368
PROPOSAL: #84368 (comment)
Tests
Preconditions:
MorebuttonDuplicate expenseOffline tests
// TODO: The human co-author must fill out the offline tests before marking this PR as "ready for review"
QA Steps
Preconditions:
MorebuttonDuplicate expensePR 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))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
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari