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
7 changes: 2 additions & 5 deletions src/libs/IOUUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import createDynamicRoute from './Navigation/helpers/dynamicRoutesUtils/createDy
import Navigation from './Navigation/Navigation';
import {isGroupPolicy} from './PolicyUtils';
import {getOriginalMessage, isMoneyRequestAction} from './ReportActionsUtils';
import {generateReportID, getChatByParticipants, isProcessingReport, isReportOutstanding, isSelfDM} from './ReportUtils';
import {canAddTransaction, generateReportID, getChatByParticipants, isArchivedReport, isSelfDM} from './ReportUtils';
import {endSpan, getSpan, startSpan} from './telemetry/activeSpans';
import {getTagArrayFromName, hasRoute, isDistanceRequest} from './TransactionUtils';

Expand Down Expand Up @@ -570,20 +570,17 @@ function resolveReportForMoneyRequest({
transaction,
transactionReport,
routeReport,
policy,
reportNameValuePair,
}: {
transaction: OnyxEntry<Transaction>;
transactionReport: OnyxEntry<Report>;
routeReport: OnyxEntry<Report>;
policy: OnyxEntry<Policy>;
reportNameValuePair: OnyxInputOrEntry<ReportNameValuePairs>;
}): OnyxEntry<Report> {
if (transaction?.reportID === CONST.REPORT.UNREPORTED_REPORT_ID) {
return undefined;
}
const canUseTransactionReport =
!(isProcessingReport(transactionReport) && !policy?.harvesting?.enabled) && isReportOutstanding(transactionReport, policy?.id, reportNameValuePair, false);
const canUseTransactionReport = canAddTransaction(transactionReport, isArchivedReport(reportNameValuePair), false);
const shouldUseTransactionReport = !!transactionReport && (canUseTransactionReport || !routeReport);
if (shouldUseTransactionReport) {
return transactionReport;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Share/SubmitDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ function SubmitDetailsPage({
const [storedTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(existingTransactionID)}`);
const listOfParticipants = participants.filter((participant) => participant.selected);
const participant = listOfParticipants.at(0) ?? selectedParticipants.at(0);
const reportToSubmit = resolveReportForMoneyRequest({transaction, transactionReport, routeReport: report, policy, reportNameValuePair});
const reportToSubmit = resolveReportForMoneyRequest({transaction, transactionReport, routeReport: report, reportNameValuePair});
const postSubmitNavigationReportID = (isSelfDM(report) ? report : reportToSubmit)?.reportID ?? reportOrAccountID;
const isIouReport = isMoneyRequestReport(reportToSubmit);
const policyTagsForRequestMoney = useMoneyRequestPolicyTags({
Expand Down
4 changes: 1 addition & 3 deletions src/pages/iou/request/step/IOURequestStepConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ function IOURequestStepConfirmationContent({
const realPolicyID = selectedWorkspacePolicyID ?? getIOURequestPolicyID(initialTransaction, pickReportForPolicy(reportReal, participantReport));
const draftPolicyID = getIOURequestPolicyID(initialTransaction, reportDraft);
const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${draftPolicyID}`);
const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${realPolicyID}`);
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
const [reportNameValuePair] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${getNonEmptyStringOnyxID(transaction?.reportID)}`);

Expand All @@ -199,10 +198,9 @@ function IOURequestStepConfirmationContent({
transaction,
transactionReport,
routeReport: reportWithDraftFallback,
policy: policyReal,
reportNameValuePair,
}),
[transaction, transactionReport, reportWithDraftFallback, policyReal, reportNameValuePair],
[transaction, transactionReport, reportWithDraftFallback, reportNameValuePair],
);
const [reportDrafts] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT);

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/components/IOURequestStepConfirmationPageTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ describe('IOURequestStepConfirmationPageTest', () => {
harvesting: {enabled: false},
};

const isReportOutstandingSpy = jest.spyOn(require('@libs/ReportUtils'), 'isReportOutstanding').mockReturnValue(true);
const canAddTransactionSpy = jest.spyOn(require('@libs/ReportUtils'), 'canAddTransaction').mockReturnValue(true);

try {
await act(async () => {
Expand Down Expand Up @@ -1204,7 +1204,7 @@ describe('IOURequestStepConfirmationPageTest', () => {
const params = requestMoneyMock.mock.calls.at(0)?.at(0);
expect(params?.report?.reportID).toBe(transactionReportID);
} finally {
isReportOutstandingSpy.mockRestore();
canAddTransactionSpy.mockRestore();
}
});
});
Expand Down
31 changes: 17 additions & 14 deletions tests/unit/IOUUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,10 @@ describe('getExistingTransactionID', () => {
const policyForResolve: Policy = {...createRandomPolicy(1, CONST.POLICY.TYPE.TEAM, 'Resolve Test Policy'), id: 'resolve-policy'};
const nonArchivedReportNameValuePair: ReportNameValuePairs = {};

afterEach(() => {
jest.restoreAllMocks();
});

const makeOutstandingReport = (reportID: string): Report => ({
...createRandomReport(Number(reportID), undefined),
reportID,
Expand Down Expand Up @@ -949,49 +953,49 @@ describe('getExistingTransactionID', () => {
transaction,
transactionReport,
routeReport,
policy: policyForResolve,
reportNameValuePair: nonArchivedReportNameValuePair,
}),
).toBeUndefined();
});

it('returns the picked report when it is outstanding (user-selected report wins)', () => {
it('returns the picked report when canAddTransaction allows it (user-selected report wins)', () => {
const transaction = makeTransaction('500');
const transactionReport = makeOutstandingReport('500');
const routeReport = makeRouteReport('100');
jest.spyOn(ReportUtils, 'canAddTransaction').mockReturnValue(true);
expect(
IOUUtils.resolveReportForMoneyRequest({
transaction,
transactionReport,
routeReport,
policy: policyForResolve,
reportNameValuePair: nonArchivedReportNameValuePair,
})?.reportID,
).toBe('500');
});

it('returns undefined when the picked report is archived', () => {
it('returns undefined when canAddTransaction rejects the picked report (e.g. archived)', () => {
const transaction = makeTransaction('500');
const transactionReport = makeOutstandingReport('500');
const routeReport = makeRouteReport('100');
const reportNameValuePair: ReportNameValuePairs = {private_isArchived: testDate};
jest.spyOn(ReportUtils, 'canAddTransaction').mockReturnValue(false);

expect(IOUUtils.resolveReportForMoneyRequest({transaction, transactionReport, routeReport, policy: policyForResolve, reportNameValuePair})).toBeUndefined();
expect(IOUUtils.resolveReportForMoneyRequest({transaction, transactionReport, routeReport, reportNameValuePair})).toBeUndefined();
});

it('returns undefined when the picked report is non-outstanding and differs from the route (forces a new optimistic IOU)', () => {
it('returns undefined when canAddTransaction rejects the picked report and it differs from the route (forces a new optimistic IOU)', () => {
const transaction = makeTransaction('500');
const nonOutstandingPick: Report = {
...makeOutstandingReport('500'),
policyID: 'someOtherPolicy',
};
const routeReport = makeRouteReport('100');
jest.spyOn(ReportUtils, 'canAddTransaction').mockReturnValue(false);
expect(
IOUUtils.resolveReportForMoneyRequest({
transaction,
transactionReport: nonOutstandingPick,
routeReport,
policy: policyForResolve,
reportNameValuePair: nonArchivedReportNameValuePair,
}),
).toBeUndefined();
Expand All @@ -1006,7 +1010,6 @@ describe('getExistingTransactionID', () => {
transaction,
transactionReport,
routeReport,
policy: policyForResolve,
reportNameValuePair: nonArchivedReportNameValuePair,
})?.reportID,
).toBe('100');
Expand All @@ -1015,35 +1018,35 @@ describe('getExistingTransactionID', () => {
it('falls back to the transaction report when no route report exists (the !routeReport branch)', () => {
const transaction = makeTransaction('500');
const transactionReport = makeOutstandingReport('500');
jest.spyOn(ReportUtils, 'canAddTransaction').mockReturnValue(true);
expect(
IOUUtils.resolveReportForMoneyRequest({
transaction,
transactionReport,
routeReport: undefined,
policy: policyForResolve,
reportNameValuePair: nonArchivedReportNameValuePair,
})?.reportID,
).toBe('500');
});

it('returns undefined when the picked report is processing and policy harvesting is disabled', () => {
it('returns the picked submitted report when canAddTransaction allows it (harvesting disabled no longer blocks)', () => {
const transaction = makeTransaction('500');
const processingPick: Report = {
...makeOutstandingReport('500'),
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
};
const routeReport = makeRouteReport('100');
const harvestingDisabledPolicy: Policy = {...policyForResolve, harvesting: {enabled: false}};
jest.spyOn(ReportUtils, 'canAddTransaction').mockReturnValue(true);

expect(
IOUUtils.resolveReportForMoneyRequest({
transaction,
transactionReport: processingPick,
routeReport,
policy: harvestingDisabledPolicy,
reportNameValuePair: nonArchivedReportNameValuePair,
}),
).toBeUndefined();
})?.reportID,
).toBe('500');
});
});

Expand Down
Loading