diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 4943bb2a36f6d..1f68b3e23c7cc 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -130,6 +130,7 @@ import { isPayer as isPayerReportUtils, isPolicyExpenseChat as isPolicyExpenseChatReportUtil, isReportApproved, + isReportManager, isSelfDM, isSettled, isTrackExpenseReport, @@ -8192,6 +8193,16 @@ function canApproveIOU( return reportTransactions.length > 0 && isCurrentUserManager && !isOpenExpenseReport && !isApproved && !iouSettled && !isArchivedExpenseReport && !isPayAtEndExpenseReport; } +function canUnapproveIOU(iouReport: OnyxEntry, policy: OnyxEntry) { + return ( + isExpenseReport(iouReport) && + (isReportManager(iouReport) || isPolicyAdmin(policy)) && + isReportApproved({report: iouReport}) && + !isSubmitAndClose(policy) && + !iouReport?.isWaitingOnBankAccount + ); +} + function canIOUBePaid( iouReport: OnyxTypes.OnyxInputOrEntry | SearchReport, chatReport: OnyxTypes.OnyxInputOrEntry | SearchReport, @@ -8263,6 +8274,10 @@ function canIOUBePaid( ); } +function canCancelPayment(iouReport: OnyxEntry, session: OnyxEntry) { + return isPayerReportUtils(session, iouReport) && (isSettled(iouReport) || iouReport?.isWaitingOnBankAccount) && isExpenseReport(iouReport); +} + function canSubmitReport( report: OnyxEntry | SearchReport, policy: OnyxEntry | SearchPolicy, @@ -8791,6 +8806,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { ...expenseReport, + isWaitingOnBankAccount: false, lastVisibleActionCreated: optimisticReportAction?.created, lastMessageText: getReportActionText(optimisticReportAction), lastMessageHtml: getReportActionHtml(optimisticReportAction), @@ -8833,6 +8849,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, + isWaitingOnBankAccount: expenseReport.isWaitingOnBankAccount, }, }, ]; @@ -9966,8 +9983,10 @@ export { getNextApproverAccountID, approveMoneyRequest, canApproveIOU, + canUnapproveIOU, cancelPayment, canIOUBePaid, + canCancelPayment, cleanUpMoneyRequest, clearMoneyRequest, completeSplitBill, diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index d5d8410636904..295c96e7edac2 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -36,7 +36,7 @@ import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types'; import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; -import {getConnectedIntegration, isPolicyAdmin as isPolicyAdminUtil, isPolicyEmployee as isPolicyEmployeeUtil, isSubmitAndClose, shouldShowPolicy} from '@libs/PolicyUtils'; +import {getConnectedIntegration, isPolicyAdmin as isPolicyAdminUtil, isPolicyEmployee as isPolicyEmployeeUtil, shouldShowPolicy} from '@libs/PolicyUtils'; import {getOneTransactionThreadReportID, getOriginalMessage, getTrackExpenseActionableWhisper, isDeletedAction, isMoneyRequestAction, isTrackExpenseAction} from '@libs/ReportActionsUtils'; import { canDeleteTransaction, @@ -74,16 +74,12 @@ import { isInvoiceRoom as isInvoiceRoomUtil, isMoneyRequestReport as isMoneyRequestReportUtil, isMoneyRequest as isMoneyRequestUtil, - isPayer as isPayerUtil, isPolicyExpenseChat as isPolicyExpenseChatUtil, isPublicRoom as isPublicRoomUtil, - isReportApproved as isReportApprovedUtil, isReportFieldDisabled, isReportFieldOfTypeTitle, - isReportManager as isReportManagerUtil, isRootGroupChat as isRootGroupChatUtil, isSelfDM as isSelfDMUtil, - isSettled as isSettledUtil, isSystemChat as isSystemChatUtil, isTaskReport as isTaskReportUtil, isThread as isThreadUtil, @@ -97,7 +93,9 @@ import { } from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import { + canCancelPayment, cancelPayment as cancelPaymentAction, + canUnapproveIOU, deleteMoneyRequest, deleteTrackExpense, getNavigationUrlAfterTrackExpenseDelete, @@ -298,8 +296,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; const shouldShowDeleteButton = shouldShowTaskDeleteButton || canDeleteRequest; - const canUnapproveRequest = isExpenseReportUtil(report) && (isReportManagerUtil(report) || isPolicyAdmin) && isReportApprovedUtil({report}) && !isSubmitAndClose(policy); - useEffect(() => { if (canDeleteRequest) { return; @@ -367,11 +363,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const shouldShowNotificationPref = !isMoneyRequestReport && !isHiddenForCurrentUser(report); const shouldShowWriteCapability = !isMoneyRequestReport; const shouldShowMenuItem = shouldShowNotificationPref || shouldShowWriteCapability || (!!report?.visibility && report.chatType !== CONST.REPORT.CHAT_TYPE.INVOICE); - - const isPayer = isPayerUtil(session, moneyRequestReport); - const isSettled = isSettledUtil(moneyRequestReport?.reportID); - - const shouldShowCancelPaymentButton = caseID === CASES.MONEY_REPORT && isPayer && isSettled && isExpenseReportUtil(moneyRequestReport); + const shouldShowCancelPaymentButton = caseID === CASES.MONEY_REPORT && canCancelPayment(moneyRequestReport, session); const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReport?.chatReportID}`); const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; @@ -555,7 +547,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta }); } - if (canUnapproveRequest) { + if (canUnapproveIOU(report, policy)) { items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.UNAPPROVE, icon: Expensicons.CircularArrowBackwards, @@ -636,7 +628,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta isPolicyAdmin, isSingleTransactionView, isExpenseReport, - canUnapproveRequest, isDebugModeEnabled, shouldShowGoToWorkspace, activeChatMembers.length, diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 11accbdae72b6..51e621909f600 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -4,7 +4,9 @@ import type {OnyxCollection, OnyxEntry, OnyxInputValue} from 'react-native-onyx' import Onyx from 'react-native-onyx'; import { canApproveIOU, + canCancelPayment, cancelPayment, + canUnapproveIOU, deleteMoneyRequest, payMoneyRequest, putOnHold, @@ -4736,4 +4738,34 @@ describe('actions/IOU', () => { expect(canApproveIOU(fakeReport, fakePolicy)).toBeTruthy(); }); }); + + describe('canUnapproveIOU', () => { + it('should return false if the report is waiting for a bank account', () => { + const fakeReport: Report = { + ...createRandomReport(1), + type: CONST.REPORT.TYPE.EXPENSE, + policyID: 'A', + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + isWaitingOnBankAccount: true, + managerID: RORY_ACCOUNT_ID, + }; + expect(canUnapproveIOU(fakeReport, undefined)).toBeFalsy(); + }); + }); + + describe('canCancelPayment', () => { + it('should return true if the report is waiting for a bank account', () => { + const fakeReport: Report = { + ...createRandomReport(1), + type: CONST.REPORT.TYPE.EXPENSE, + policyID: 'A', + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + isWaitingOnBankAccount: true, + managerID: RORY_ACCOUNT_ID, + }; + expect(canCancelPayment(fakeReport, {accountID: RORY_ACCOUNT_ID})).toBeTruthy(); + }); + }); });