Skip to content

Commit 8b4ae17

Browse files
authored
Merge pull request Expensify#65842 from thelullabyy/fix/64531-unexpected-error-displayed
2 parents 0717d3f + 56d4782 commit 8b4ae17

3 files changed

Lines changed: 43 additions & 15 deletions

File tree

src/libs/ReportUtils.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9678,14 +9678,22 @@ function getTripIDFromTransactionParentReportID(transactionParentReportID: strin
96789678
/**
96799679
* Checks if report contains actions with errors
96809680
*/
9681-
function hasActionsWithErrors(reportID: string | undefined): boolean {
9681+
function hasActionWithErrorsForTransaction(reportID: string | undefined, transaction: Transaction | undefined): boolean {
96829682
if (!reportID) {
96839683
return false;
96849684
}
96859685
const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {};
96869686
return Object.values(reportActions)
96879687
.filter(Boolean)
9688-
.some((action) => !isEmptyObject(action.errors));
9688+
.some((action) => {
9689+
if (isMoneyRequestAction(action) && getOriginalMessage(action)?.IOUTransactionID) {
9690+
if (getOriginalMessage(action)?.IOUTransactionID === transaction?.transactionID) {
9691+
return !isEmptyObject(action.errors);
9692+
}
9693+
return false;
9694+
}
9695+
return !isEmptyObject(action.errors);
9696+
});
96899697
}
96909698

96919699
function isNonAdminOrOwnerOfPolicyExpenseChat(report: OnyxInputOrEntry<Report>, policy: OnyxInputOrEntry<Policy>): boolean {
@@ -11272,7 +11280,7 @@ export {
1127211280
getInvoicesChatName,
1127311281
getPayeeName,
1127411282
getQuickActionDetails,
11275-
hasActionsWithErrors,
11283+
hasActionWithErrorsForTransaction,
1127611284
hasAutomatedExpensifyAccountIDs,
1127711285
hasExpensifyGuidesEmails,
1127811286
hasHeldExpenses,

src/libs/TransactionPreviewUtils.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,16 @@ import DateUtils from './DateUtils';
1313
import type {PlatformStackRouteProp} from './Navigation/PlatformStackNavigation/types';
1414
import type {TransactionDuplicateNavigatorParamList} from './Navigation/types';
1515
import {getOriginalMessage, isMessageDeleted, isMoneyRequestAction} from './ReportActionsUtils';
16-
import {hasActionsWithErrors, hasReceiptError, hasReportViolations, isPaidGroupPolicy, isPaidGroupPolicyExpenseReport, isReportApproved, isReportOwner, isSettled} from './ReportUtils';
16+
import {
17+
hasActionWithErrorsForTransaction,
18+
hasReceiptError,
19+
hasReportViolations,
20+
isPaidGroupPolicy,
21+
isPaidGroupPolicyExpenseReport,
22+
isReportApproved,
23+
isReportOwner,
24+
isSettled,
25+
} from './ReportUtils';
1726
import type {TransactionDetails} from './ReportUtils';
1827
import StringUtils from './StringUtils';
1928
import {
@@ -130,11 +139,17 @@ function getViolationTranslatePath(violations: OnyxTypes.TransactionViolations,
130139
* it returns an empty array. It identifies the latest error in each action and filters out duplicates to
131140
* ensure only unique error messages are returned.
132141
*/
133-
function getUniqueActionErrors(reportActions: OnyxTypes.ReportActions) {
142+
function getUniqueActionErrorsForTransaction(reportActions: OnyxTypes.ReportActions, transaction: OnyxTypes.Transaction | undefined) {
134143
const reportErrors = Object.values(reportActions).map((reportAction) => {
135144
const errors = reportAction.errors ?? {};
136145
const key = Object.keys(errors).sort().reverse().at(0) ?? '';
137146
const error = errors[key];
147+
if (isMoneyRequestAction(reportAction) && getOriginalMessage(reportAction)?.IOUTransactionID) {
148+
if (getOriginalMessage(reportAction)?.IOUTransactionID === transaction?.transactionID) {
149+
return typeof error === 'string' ? error : '';
150+
}
151+
return '';
152+
}
138153
return typeof error === 'string' ? error : '';
139154
});
140155

@@ -175,7 +190,7 @@ function getTransactionPreviewTextAndTranslationPaths({
175190
const isTransactionScanning = isScanning(transaction);
176191
const hasFieldErrors = hasMissingSmartscanFields(transaction);
177192
const hasViolationsOfTypeNotice = hasNoticeTypeViolation(transaction, violations, true) && isPaidGroupPolicy(iouReport);
178-
const hasActionWithErrors = hasActionsWithErrors(iouReport?.reportID);
193+
const hasActionWithErrors = hasActionWithErrorsForTransaction(iouReport?.reportID, transaction);
179194

180195
const {amount: requestAmount, currency: requestCurrency} = transactionDetails;
181196

@@ -211,7 +226,7 @@ function getTransactionPreviewTextAndTranslationPaths({
211226
}
212227

213228
if (RBRMessage === undefined && hasActionWithErrors && !!reportActions) {
214-
const actionsWithErrors = getUniqueActionErrors(reportActions);
229+
const actionsWithErrors = getUniqueActionErrorsForTransaction(reportActions, transaction);
215230
RBRMessage = actionsWithErrors.length > 1 ? {translationPath: 'violations.reviewRequired'} : {text: actionsWithErrors.at(0)};
216231
}
217232

@@ -334,7 +349,7 @@ function createTransactionPreviewConditionals({
334349
hasWarningTypeViolation(transaction, violations, true) ||
335350
hasViolation(transaction, violations, true);
336351
const hasErrorOrOnHold = hasFieldErrors || (!isFullySettled && !isFullyApproved && isTransactionOnHold);
337-
const hasReportViolationsOrActionErrors = (isReportOwner(iouReport) && hasReportViolations(iouReport?.reportID)) || hasActionsWithErrors(iouReport?.reportID);
352+
const hasReportViolationsOrActionErrors = (isReportOwner(iouReport) && hasReportViolations(iouReport?.reportID)) || hasActionWithErrorsForTransaction(iouReport?.reportID, transaction);
338353
const shouldShowRBR = hasAnyViolations || hasErrorOrOnHold || hasReportViolationsOrActionErrors || hasReceiptError(transaction);
339354

340355
// When there are no settled transactions in duplicates, show the "Keep this one" button
@@ -372,6 +387,6 @@ export {
372387
getTransactionPreviewTextAndTranslationPaths,
373388
createTransactionPreviewConditionals,
374389
getViolationTranslatePath,
375-
getUniqueActionErrors,
390+
getUniqueActionErrorsForTransaction,
376391
};
377392
export type {TranslationPathOrText};

tests/unit/TransactionPreviewUtils.test.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import Onyx from 'react-native-onyx';
22
import {convertAmountToDisplayString} from '@libs/CurrencyUtils';
33
import {buildOptimisticIOUReport, buildOptimisticIOUReportAction} from '@libs/ReportUtils';
4-
import {createTransactionPreviewConditionals, getTransactionPreviewTextAndTranslationPaths, getUniqueActionErrors, getViolationTranslatePath} from '@libs/TransactionPreviewUtils';
4+
import {
5+
createTransactionPreviewConditionals,
6+
getTransactionPreviewTextAndTranslationPaths,
7+
getUniqueActionErrorsForTransaction,
8+
getViolationTranslatePath,
9+
} from '@libs/TransactionPreviewUtils';
510
import {buildOptimisticTransaction} from '@libs/TransactionUtils';
611
import CONST from '@src/CONST';
712
import * as ReportUtils from '@src/libs/ReportUtils';
@@ -401,9 +406,9 @@ describe('TransactionPreviewUtils', () => {
401406
});
402407
});
403408

404-
describe('getUniqueActionErrors', () => {
409+
describe('getUniqueActionErrorsForTransaction', () => {
405410
test('returns an empty array if there are no actions', () => {
406-
expect(getUniqueActionErrors({})).toEqual([]);
411+
expect(getUniqueActionErrorsForTransaction({}, undefined)).toEqual([]);
407412
});
408413

409414
test('returns unique error messages from report actions', () => {
@@ -416,7 +421,7 @@ describe('TransactionPreviewUtils', () => {
416421
} as unknown as ReportActions;
417422

418423
const expectedErrors = ['Error B', 'Error C', 'Error D'];
419-
expect(getUniqueActionErrors(actions).sort()).toEqual(expectedErrors.sort());
424+
expect(getUniqueActionErrorsForTransaction(actions, undefined).sort()).toEqual(expectedErrors.sort());
420425
});
421426

422427
test('returns the latest error message if multiple errors exist under a single action', () => {
@@ -426,7 +431,7 @@ describe('TransactionPreviewUtils', () => {
426431
/* eslint-enable @typescript-eslint/naming-convention */
427432
} as unknown as ReportActions;
428433

429-
expect(getUniqueActionErrors(actions)).toEqual(['Error Z2']);
434+
expect(getUniqueActionErrorsForTransaction(actions, undefined)).toEqual(['Error Z2']);
430435
});
431436

432437
test('filters out non-string error messages', () => {
@@ -437,7 +442,7 @@ describe('TransactionPreviewUtils', () => {
437442
/* eslint-enable @typescript-eslint/naming-convention */
438443
} as unknown as ReportActions;
439444

440-
expect(getUniqueActionErrors(actions)).toEqual(['Error B', 'Error D']);
445+
expect(getUniqueActionErrorsForTransaction(actions, undefined)).toEqual(['Error B', 'Error D']);
441446
});
442447
});
443448
});

0 commit comments

Comments
 (0)