Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ import {
isPayer as isPayerReportUtils,
isPolicyExpenseChat as isPolicyExpenseChatReportUtil,
isReportApproved,
isReportManager,
isSelfDM,
isSettled,
isTrackExpenseReport,
Expand Down Expand Up @@ -8192,6 +8193,16 @@ function canApproveIOU(
return reportTransactions.length > 0 && isCurrentUserManager && !isOpenExpenseReport && !isApproved && !iouSettled && !isArchivedExpenseReport && !isPayAtEndExpenseReport;
}

function canUnapproveIOU(iouReport: OnyxEntry<OnyxTypes.Report>, policy: OnyxEntry<OnyxTypes.Policy>) {
return (
isExpenseReport(iouReport) &&
(isReportManager(iouReport) || isPolicyAdmin(policy)) &&
isReportApproved({report: iouReport}) &&
!isSubmitAndClose(policy) &&
!iouReport?.isWaitingOnBankAccount
);
}

function canIOUBePaid(
iouReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report> | SearchReport,
chatReport: OnyxTypes.OnyxInputOrEntry<OnyxTypes.Report> | SearchReport,
Expand Down Expand Up @@ -8263,6 +8274,10 @@ function canIOUBePaid(
);
}

function canCancelPayment(iouReport: OnyxEntry<OnyxTypes.Report>, session: OnyxEntry<OnyxTypes.Session>) {
return isPayerReportUtils(session, iouReport) && (isSettled(iouReport) || iouReport?.isWaitingOnBankAccount) && isExpenseReport(iouReport);
}

function canSubmitReport(
report: OnyxEntry<OnyxTypes.Report> | SearchReport,
policy: OnyxEntry<OnyxTypes.Policy> | SearchPolicy,
Expand Down Expand Up @@ -8791,6 +8806,7 @@ function cancelPayment(expenseReport: OnyxEntry<OnyxTypes.Report>, chatReport: O
key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
value: {
...expenseReport,
isWaitingOnBankAccount: false,
lastVisibleActionCreated: optimisticReportAction?.created,
lastMessageText: getReportActionText(optimisticReportAction),
lastMessageHtml: getReportActionHtml(optimisticReportAction),
Expand Down Expand Up @@ -8833,6 +8849,7 @@ function cancelPayment(expenseReport: OnyxEntry<OnyxTypes.Report>, chatReport: O
key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
value: {
statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED,
isWaitingOnBankAccount: expenseReport.isWaitingOnBankAccount,
},
},
];
Expand Down Expand Up @@ -9966,8 +9983,10 @@ export {
getNextApproverAccountID,
approveMoneyRequest,
canApproveIOU,
canUnapproveIOU,
cancelPayment,
canIOUBePaid,
canCancelPayment,
cleanUpMoneyRequest,
clearMoneyRequest,
completeSplitBill,
Expand Down
19 changes: 5 additions & 14 deletions src/pages/ReportDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -97,7 +93,9 @@ import {
} from '@libs/ReportUtils';
import StringUtils from '@libs/StringUtils';
import {
canCancelPayment,
cancelPayment as cancelPaymentAction,
canUnapproveIOU,
deleteMoneyRequest,
deleteTrackExpense,
getNavigationUrlAfterTrackExpenseDelete,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 : '';
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -636,7 +628,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta
isPolicyAdmin,
isSingleTransactionView,
isExpenseReport,
canUnapproveRequest,
isDebugModeEnabled,
shouldShowGoToWorkspace,
activeChatMembers.length,
Expand Down
32 changes: 32 additions & 0 deletions tests/actions/IOUTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();
});
});
});