Skip to content

Commit 27ed226

Browse files
authored
Merge pull request Expensify#88363 from Expensify/claude-duplicateExpenseRestrictBillableActions
Add billing restriction guard to duplicate expense handlers
2 parents 1fc7d1d + 032cfc7 commit 27ed226

3 files changed

Lines changed: 37 additions & 3 deletions

File tree

src/components/MoneyRequestHeaderSecondaryActions.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
navigateToDetailsPage,
5353
rejectMoneyRequestReason,
5454
} from '@libs/ReportUtils';
55+
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
5556
import {
5657
getOriginalTransactionWithSplitInfo,
5758
hasCustomUnitOutOfPolicyViolation as hasCustomUnitOutOfPolicyViolationTransactionUtils,
@@ -139,6 +140,9 @@ function MoneyRequestHeaderSecondaryActions({reportID, onBackButtonPress}: Money
139140
const [recentWaypoints] = useOnyx(ONYXKEYS.NVP_RECENT_WAYPOINTS);
140141
const [shouldFailAllRequests] = useOnyx(ONYXKEYS.NETWORK, {selector: shouldFailAllRequestsSelector});
141142
const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE);
143+
const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END);
144+
const [userBillingGracePeriodEnds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END);
145+
const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED);
142146
const [isSelfTourViewed = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
143147
const [betas] = useOnyx(ONYXKEYS.BETAS);
144148
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
@@ -355,6 +359,12 @@ function MoneyRequestHeaderSecondaryActions({reportID, onBackButtonPress}: Money
355359
iconFill: isDuplicateActive ? undefined : theme.icon,
356360
value: CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.DUPLICATE,
357361
onSelected: () => {
362+
if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) {
363+
dropdownMenuRef.current?.setIsMenuVisible(false);
364+
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id));
365+
return;
366+
}
367+
358368
if (hasCustomUnitOutOfPolicyViolation) {
359369
showConfirmModal({
360370
title: translate('common.duplicateExpense'),

src/hooks/useExpenseActions.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,12 @@ function useExpenseActions({reportID, isReportInSearch = false, backTo, onDuplic
322322
iconFill: isDuplicateActive ? undefined : theme.icon,
323323
value: CONST.REPORT.SECONDARY_ACTIONS.DUPLICATE_EXPENSE,
324324
onSelected: () => {
325+
if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) {
326+
onDuplicateReset?.();
327+
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id));
328+
return;
329+
}
330+
325331
if (hasCustomUnitOutOfPolicyViolation) {
326332
showConfirmModal({
327333
title: translate('common.duplicateExpense'),
@@ -374,11 +380,18 @@ function useExpenseActions({reportID, isReportInSearch = false, backTo, onDuplic
374380
return;
375381
}
376382

383+
const isSourcePolicyValid = !!policy && isPolicyAccessible(policy, currentUserLogin ?? '');
384+
const targetPolicyForDuplicate = isSourcePolicyValid ? policy : defaultExpensePolicy;
385+
386+
if (targetPolicyForDuplicate && shouldRestrictUserBillableActions(targetPolicyForDuplicate.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) {
387+
onDuplicateReset?.();
388+
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(targetPolicyForDuplicate.id));
389+
return;
390+
}
391+
377392
temporarilyDisableDuplicateReportAction();
378393
wasDuplicateReportTriggeredRef.current = true;
379394

380-
const isSourcePolicyValid = !!policy && isPolicyAccessible(policy, currentUserLogin ?? '');
381-
const targetPolicyForDuplicate = isSourcePolicyValid ? policy : defaultExpensePolicy;
382395
const targetChatForDuplicate = isSourcePolicyValid ? chatReport : activePolicyExpenseChat;
383396
const activePolicyCategories = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${targetPolicyForDuplicate?.id}`] ?? {};
384397

src/hooks/useSearchBulkActions.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,13 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
11331133
icon: expensifyIcons.ExpenseCopy,
11341134
value: CONST.SEARCH.BULK_ACTION_TYPES.DUPLICATE,
11351135
shouldCloseModalOnSelect: true,
1136-
onSelected: invokeDuplicateHandler,
1136+
onSelected: () => {
1137+
if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) {
1138+
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id));
1139+
return;
1140+
}
1141+
invokeDuplicateHandler();
1142+
},
11371143
});
11381144
}
11391145

@@ -1477,6 +1483,10 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
14771483
value: CONST.SEARCH.BULK_ACTION_TYPES.DUPLICATE,
14781484
shouldCloseModalOnSelect: true,
14791485
onSelected: () => {
1486+
if (defaultExpensePolicy && shouldRestrictUserBillableActions(defaultExpensePolicy.id, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed)) {
1487+
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(defaultExpensePolicy.id));
1488+
return;
1489+
}
14801490
if (exceedsBulkDuplicateLimit) {
14811491
showConfirmModal({
14821492
title: translate('common.duplicateExpense'),
@@ -1598,6 +1608,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
15981608
allTransactions,
15991609
transactions,
16001610
isBetaEnabled,
1611+
defaultExpensePolicy,
16011612
]);
16021613

16031614
const handleOfflineModalClose = useCallback(() => {

0 commit comments

Comments
 (0)