Skip to content

Commit d51eca5

Browse files
authored
Merge pull request Expensify#88569 from paulnjs/paulnjs-fix/88375
2 parents 3ea444e + 8a5ae61 commit d51eca5

10 files changed

Lines changed: 50 additions & 23 deletions

File tree

src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import {sortPoliciesByName} from '@libs/PolicyUtils';
5050
import {getFilteredReportActionsForReportView, hasRequestFromCurrentAccount} from '@libs/ReportActionsUtils';
5151
import {getSecondaryReportActions} from '@libs/ReportSecondaryActionUtils';
5252
import {
53-
hasHeldExpenses as hasHeldExpensesReportUtils,
53+
hasHeldExpensesFromTransactions as hasHeldExpensesReportUtils,
5454
hasViolations as hasViolationsReportUtils,
5555
isAllowedToApproveExpenseReport,
5656
isInvoiceReport as isInvoiceReportUtil,
@@ -131,7 +131,7 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo
131131
const shouldCalculateTotals = useSearchShouldCalculateTotals(currentSearchKey, currentSearchQueryJSON?.hash, true);
132132

133133
const isInvoiceReport = isInvoiceReportUtil(moneyRequestReport);
134-
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(moneyRequestReport?.reportID);
134+
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(allTransactions);
135135
const existingB2BInvoiceReport = useParticipantsInvoiceReport(activePolicyID, CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, chatReport?.policyID);
136136

137137
const confirmPayment = ({paymentType: type, payAsBusiness, methodID, paymentMethod}: PaymentActionParams) => {

src/components/MoneyReportHeaderActions/MoneyReportHeaderSelectionDropdown.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ import {handleUnvalidatedAccount, selectPaymentType} from '@libs/PaymentUtils';
4646
import {sortPoliciesByName} from '@libs/PolicyUtils';
4747
import {hasRequestFromCurrentAccount} from '@libs/ReportActionsUtils';
4848
import {getSecondaryReportActions} from '@libs/ReportSecondaryActionUtils';
49-
import {hasHeldExpenses, hasUpdatedTotal, hasViolations as hasViolationsReportUtils, isInvoiceReport as isInvoiceReportUtil, isIOUReport as isIOUReportUtil} from '@libs/ReportUtils';
49+
import {
50+
hasHeldExpensesFromTransactions,
51+
hasUpdatedTotal,
52+
hasViolations as hasViolationsReportUtils,
53+
isInvoiceReport as isInvoiceReportUtil,
54+
isIOUReport as isIOUReportUtil,
55+
} from '@libs/ReportUtils';
5056
import shouldPopoverUseScrollView from '@libs/shouldPopoverUseScrollView';
5157
import {isTransactionPendingDelete} from '@libs/TransactionUtils';
5258
import {payInvoice, payMoneyRequest} from '@userActions/IOU/PayMoneyRequest';
@@ -114,9 +120,6 @@ function MoneyReportHeaderSelectionDropdown({reportID, primaryAction, isReportIn
114120
const existingB2BInvoiceReport = useParticipantsInvoiceReport(activePolicyID, CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, chatReport?.policyID);
115121
const isInvoiceReport = isInvoiceReportUtil(moneyRequestReport);
116122

117-
const isChatReportArchived = useReportIsArchived(chatReport?.reportID);
118-
const isAnyTransactionOnHold = hasHeldExpenses(moneyRequestReport?.reportID);
119-
120123
const {transactionThreadReportID, reportActions} = useTransactionThreadReport(reportID);
121124

122125
const {transactions: reportTransactions, violations} = useTransactionsAndViolationsForReport(moneyRequestReport?.reportID);
@@ -130,6 +133,9 @@ function MoneyReportHeaderSelectionDropdown({reportID, primaryAction, isReportIn
130133
const {accountID, email, login: currentUserLogin} = useCurrentUserPersonalDetails();
131134
const hasViolations = hasViolationsReportUtils(moneyRequestReport?.reportID, allTransactionViolations, accountID, email ?? '');
132135

136+
const isChatReportArchived = useReportIsArchived(chatReport?.reportID);
137+
const isAnyTransactionOnHold = hasHeldExpensesFromTransactions(transactions);
138+
133139
const {isDelegateAccessRestricted} = useDelegateNoAccessState();
134140
const {showDelegateNoAccessModal} = useDelegateNoAccessActions();
135141
const {isAccountLocked} = useLockedAccountState();

src/components/MoneyReportHeaderModals.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ function MoneyReportHeaderModals({reportID, children}: MoneyReportHeaderModalsPr
4545
const onlyShowPayElsewhere = !canIOUBePaid && canIOUBePaidAction(moneyRequestReport, chatReport, policy, bankAccountList, undefined, true);
4646
const shouldShowPayButton = canIOUBePaid || onlyShowPayElsewhere;
4747
const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount(moneyRequestReport, shouldShowPayButton);
48-
const hasOnlyHeldExpenses = hasOnlyHeldExpensesReportUtils(moneyRequestReport?.reportID);
48+
const hasOnlyHeldExpenses = hasOnlyHeldExpensesReportUtils(moneyRequestReport?.reportID, transactions);
4949
const transactionIDs = transactions.map((t) => t.transactionID);
5050

5151
// Imperative modals

src/components/MoneyReportHeaderPrimaryAction/PayPrimaryAction.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {generateDefaultWorkspaceName} from '@libs/actions/Policy/Policy';
1919
import {search} from '@libs/actions/Search';
2020
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
2121
import {getTotalAmountForIOUReportPreviewButton} from '@libs/MoneyRequestReportUtils';
22-
import {hasHeldExpenses as hasHeldExpensesReportUtils, hasUpdatedTotal, isAllowedToApproveExpenseReport, isInvoiceReport as isInvoiceReportUtil} from '@libs/ReportUtils';
22+
import {hasHeldExpensesFromTransactions as hasHeldExpensesReportUtils, hasUpdatedTotal, isAllowedToApproveExpenseReport, isInvoiceReport as isInvoiceReportUtil} from '@libs/ReportUtils';
2323
import {isExpensifyCardTransaction, isPending} from '@libs/TransactionUtils';
2424
import {payInvoice, payMoneyRequest} from '@userActions/IOU/PayMoneyRequest';
2525
import {canApproveIOU, canIOUBePaid as canIOUBePaidAction} from '@userActions/IOU/ReportWorkflow';
@@ -78,7 +78,7 @@ function PayPrimaryAction({reportID, chatReportID}: PayPrimaryActionProps) {
7878
const shouldDisableApproveButton = shouldShowApproveButton && !isAllowedToApproveExpenseReport(moneyRequestReport);
7979
const canAllowSettlement = hasUpdatedTotal(moneyRequestReport, policy);
8080
const totalAmount = getTotalAmountForIOUReportPreviewButton(moneyRequestReport, policy, CONST.REPORT.PRIMARY_ACTIONS.PAY, nonPendingDeleteTransactions);
81-
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(moneyRequestReport?.reportID);
81+
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(transactions);
8282

8383
const {currentSearchQueryJSON, currentSearchKey, currentSearchResults} = useSearchStateContext();
8484
const shouldCalculateTotals = useSearchShouldCalculateTotals(currentSearchKey, currentSearchQueryJSON?.hash, true);

src/components/ReportActionItem/MoneyRequestReportPreview/ApproveActionButton.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import useLocalize from '@hooks/useLocalize';
77
import useOnyx from '@hooks/useOnyx';
88
import usePermissions from '@hooks/usePermissions';
99
import usePolicy from '@hooks/usePolicy';
10-
import {hasHeldExpenses as hasHeldExpensesReportUtils, hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
10+
import useTransactionsAndViolationsForReport from '@hooks/useTransactionsAndViolationsForReport';
11+
import {hasHeldExpensesFromTransactions as hasHeldExpensesReportUtils, hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
1112
import {approveMoneyRequest} from '@userActions/IOU/ReportWorkflow';
1213
import CONST from '@src/CONST';
1314
import ONYXKEYS from '@src/ONYXKEYS';
@@ -44,10 +45,15 @@ function ApproveActionButton({iouReportID, startApprovedAnimation, onHoldMenuOpe
4445
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
4546
const hasViolations = hasViolationsReportUtils(iouReport?.reportID, transactionViolations, currentUserAccountID, currentUserEmail);
4647

48+
const {transactions: reportTransactions} = useTransactionsAndViolationsForReport(iouReport?.reportID);
49+
50+
const allTransactionValues = Object.values(reportTransactions);
51+
const transactions = allTransactionValues;
52+
4753
const confirmApproval = () => {
4854
if (isDelegateAccessRestricted) {
4955
showDelegateNoAccessModal();
50-
} else if (hasHeldExpensesReportUtils(iouReport?.reportID)) {
56+
} else if (hasHeldExpensesReportUtils(transactions)) {
5157
onHoldMenuOpen(CONST.IOU.REPORT_ACTION_TYPE.APPROVE, undefined, shouldShowPayButton);
5258
} else {
5359
approveMoneyRequest({

src/components/ReportActionItem/MoneyRequestReportPreview/PayActionButton.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ import usePolicy from '@hooks/usePolicy';
1616
import useReportTransactionsCollection from '@hooks/useReportTransactionsCollection';
1717
import {generateDefaultWorkspaceName} from '@libs/actions/Policy/Policy';
1818
import {getTotalAmountForIOUReportPreviewButton} from '@libs/MoneyRequestReportUtils';
19-
import {hasHeldExpenses as hasHeldExpensesReportUtils, hasUpdatedTotal, hasViolations as hasViolationsReportUtils, isInvoiceReport as isInvoiceReportUtils} from '@libs/ReportUtils';
19+
import {
20+
hasHeldExpensesFromTransactions as hasHeldExpensesReportUtils,
21+
hasUpdatedTotal,
22+
hasViolations as hasViolationsReportUtils,
23+
isInvoiceReport as isInvoiceReportUtils,
24+
} from '@libs/ReportUtils';
2025
import {payInvoice, payMoneyRequest} from '@userActions/IOU/PayMoneyRequest';
2126
import {approveMoneyRequest, canIOUBePaid as canIOUBePaidIOUActions} from '@userActions/IOU/ReportWorkflow';
2227
import CONST from '@src/CONST';
@@ -105,7 +110,7 @@ function PayActionButton({
105110
const confirmApproval = () => {
106111
if (isDelegateAccessRestricted) {
107112
showDelegateNoAccessModal();
108-
} else if (hasHeldExpensesReportUtils(iouReport?.reportID)) {
113+
} else if (hasHeldExpensesReportUtils(transactions)) {
109114
onHoldMenuOpen(CONST.IOU.REPORT_ACTION_TYPE.APPROVE, undefined, shouldShowPayButton);
110115
} else {
111116
approveMoneyRequest({
@@ -134,7 +139,7 @@ function PayActionButton({
134139
}
135140
if (isDelegateAccessRestricted) {
136141
showDelegateNoAccessModal();
137-
} else if (hasHeldExpensesReportUtils(iouReport?.reportID)) {
142+
} else if (hasHeldExpensesReportUtils(transactions)) {
138143
onHoldMenuOpen(CONST.IOU.REPORT_ACTION_TYPE.PAY, type, shouldShowPayButton);
139144
} else if (chatReport && iouReport) {
140145
if (isInvoiceReportUtils(iouReport)) {

src/hooks/useLifecycleActions.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {getFilteredReportActionsForReportView} from '@libs/ReportActionsUtils';
1313
import {
1414
getIntegrationNameFromExportMessage as getIntegrationNameFromExportMessageUtils,
1515
getNextApproverAccountID,
16-
hasHeldExpenses as hasHeldExpensesReportUtils,
16+
hasHeldExpensesFromTransactions as hasHeldExpensesReportUtils,
1717
hasViolations as hasViolationsReportUtils,
1818
isExported as isExportedUtils,
1919
isReportOwner,
@@ -125,7 +125,7 @@ function useLifecycleActions({reportID, startApprovedAnimation, startSubmittingA
125125
})
126126
: '';
127127

128-
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(moneyRequestReport?.reportID);
128+
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(transactions);
129129

130130
const hasAnyPendingRTERViolation = hasAnyPendingRTERViolationTransactionUtils(transactions, allTransactionViolations, email ?? '', accountID, moneyRequestReport, policy);
131131

src/hooks/useSelectionModeReportActions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {getSecondaryReportActions} from '@libs/ReportSecondaryActionUtils';
2929
import {
3030
getNextApproverAccountID,
3131
getNonHeldAndFullAmount,
32-
hasHeldExpenses as hasHeldExpensesReportUtils,
32+
hasHeldExpensesFromTransactions as hasHeldExpensesReportUtils,
3333
hasOnlyHeldExpenses as hasOnlyHeldExpensesReportUtils,
3434
hasUpdatedTotal,
3535
hasViolations as hasViolationsReportUtils,
@@ -153,7 +153,7 @@ function useSelectionModeReportActions({
153153
const shouldBlockSubmit = isBlockSubmitDueToStrictPolicyRules || isBlockSubmitDueToPreventSelfApproval;
154154

155155
const canAllowSettlement = hasUpdatedTotal(report, policy);
156-
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(report?.reportID, transactions);
156+
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(transactions);
157157
const isInvoiceReport = isInvoiceReportUtil(report);
158158

159159
const hasOnlyPendingTransactions = !!transactions && transactions.length > 0 && transactions.every((t) => isExpensifyCardTransaction(t) && isPending(t));

src/libs/ReportUtils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10873,13 +10873,22 @@ function getAllHeldTransactions(iouReportID?: string): Transaction[] {
1087310873

1087410874
/**
1087510875
* Check if Report has any held expenses
10876+
*
10877+
* @warning Use `hasHeldExpensesFromTransactions` instead.
1087610878
*/
1087710879
function hasHeldExpenses(iouReportID?: string, allReportTransactions?: Transaction[]): boolean {
1087810880
const iouReportTransactions = getReportTransactions(iouReportID);
1087910881
const transactions = allReportTransactions ?? iouReportTransactions;
1088010882
return transactions.some((transaction) => isOnHoldTransactionUtils(transaction));
1088110883
}
1088210884

10885+
/**
10886+
* Check if Report has any held expenses
10887+
*/
10888+
function hasHeldExpensesFromTransactions(allReportTransactions: Transaction[]): boolean {
10889+
return allReportTransactions.some((transaction) => isOnHoldTransactionUtils(transaction));
10890+
}
10891+
1088310892
/**
1088410893
* Check if all expenses in the Report are on hold
1088510894
*/
@@ -13728,6 +13737,7 @@ export {
1372813737
getTransactionSortValue,
1372913738
isSortableColumnName,
1373013739
getLinkedIOUTransaction,
13740+
hasHeldExpensesFromTransactions,
1373113741
};
1373213742

1373313743
export type {

tests/unit/hooks/useSelectionModeReportActions.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ jest.mock('@libs/ReportUtils', () => {
168168
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
169169
return {
170170
...actual,
171-
hasHeldExpenses: jest.fn(() => false),
171+
hasHeldExpensesFromTransactions: jest.fn(() => false),
172172
hasOnlyHeldExpenses: jest.fn(() => false),
173173
hasUpdatedTotal: jest.fn(() => true),
174174
hasViolations: jest.fn(() => false),
@@ -254,7 +254,7 @@ const PayMoneyRequestActions = require('@libs/actions/IOU/PayMoneyRequest') as R
254254
const usePaymentOptionsMock = require('@hooks/usePaymentOptions') as {default: jest.Mock};
255255

256256
function resetMocksToDefaults() {
257-
ReportUtils.hasHeldExpenses.mockReturnValue(false);
257+
ReportUtils.hasHeldExpensesFromTransactions.mockReturnValue(false);
258258
ReportUtils.hasOnlyHeldExpenses.mockReturnValue(false);
259259
ReportUtils.isReportOwner.mockReturnValue(false);
260260
ReportUtils.getNextApproverAccountID.mockReturnValue(0);
@@ -655,7 +655,7 @@ describe('useSelectionModeReportActions', () => {
655655
});
656656

657657
it('opens hold menu when there are held expenses during payment', () => {
658-
ReportUtils.hasHeldExpenses.mockReturnValue(true);
658+
ReportUtils.hasHeldExpensesFromTransactions.mockReturnValue(true);
659659

660660
const {result} = renderSelectionModeHook();
661661
act(() => {
@@ -694,7 +694,7 @@ describe('useSelectionModeReportActions', () => {
694694

695695
describe('confirmApproval branches', () => {
696696
it('opens hold menu when there are held expenses during approval', () => {
697-
ReportUtils.hasHeldExpenses.mockReturnValue(true);
697+
ReportUtils.hasHeldExpensesFromTransactions.mockReturnValue(true);
698698

699699
const {result} = renderSelectionModeHook();
700700
act(() => {
@@ -718,7 +718,7 @@ describe('useSelectionModeReportActions', () => {
718718

719719
describe('handleHoldMenuClose', () => {
720720
it('resets hold menu state', () => {
721-
ReportUtils.hasHeldExpenses.mockReturnValue(true);
721+
ReportUtils.hasHeldExpensesFromTransactions.mockReturnValue(true);
722722

723723
const {result} = renderSelectionModeHook();
724724

0 commit comments

Comments
 (0)