Skip to content

fix: Update duplicate detection to be treated as any other violation #58387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 27, 2025
10 changes: 9 additions & 1 deletion src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
import {
allHavePendingRTERViolation,
checkIfShouldShowMarkAsCashButton,
hasDuplicateTransactions,
isDuplicate as isDuplicateTransactionUtils,
isExpensifyCardTransaction,
isOnHold as isOnHoldTransactionUtils,
Expand Down Expand Up @@ -208,8 +209,10 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea

const shouldDisableSubmitButton = shouldShowSubmitButton && !isAllowedToSubmitDraftExpenseReport(moneyRequestReport);
const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE;

const hasDuplicates = hasDuplicateTransactions(moneyRequestReport?.reportID);
const shouldShowStatusBar =
hasAllPendingRTERViolations || shouldShowBrokenConnectionViolation || hasOnlyHeldExpenses || hasScanningReceipt || isPayAtEndExpense || hasOnlyPendingTransactions;
hasAllPendingRTERViolations || shouldShowBrokenConnectionViolation || hasOnlyHeldExpenses || hasScanningReceipt || isPayAtEndExpense || hasOnlyPendingTransactions || hasDuplicates;

// When prevent self-approval is enabled & the current user is submitter AND they're submitting to theirself, we need to show the optimistic next step
// We should always show this optimistic message for policies with preventSelfApproval
Expand Down Expand Up @@ -321,6 +324,11 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
if (hasOnlyHeldExpenses) {
return {icon: getStatusIcon(Expensicons.Stopwatch), description: translate('iou.expensesOnHold')};
}

if (hasDuplicates) {
return {icon: getStatusIcon(Expensicons.Stopwatch), description: translate('iou.duplicateTransaction')};
}

if (!!transaction?.transactionID && shouldShowBrokenConnectionViolation) {
return {
icon: getStatusIcon(Expensicons.Hourglass),
Expand Down
6 changes: 5 additions & 1 deletion src/components/MoneyRequestHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre

const getStatusBarProps: () => MoneyRequestHeaderStatusBarProps | undefined = () => {
if (isOnHold) {
return {icon: getStatusIcon(Expensicons.Stopwatch), description: isDuplicate ? translate('iou.expenseDuplicate') : translate('iou.expenseOnHold')};
return {icon: getStatusIcon(Expensicons.Stopwatch), description: translate('iou.expenseOnHold')};
}

if (isDuplicate) {
return {icon: getStatusIcon(Expensicons.Stopwatch), description: translate('iou.expenseDuplicate')};
}

if (isExpensifyCardTransaction(transaction) && isPending(transaction)) {
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ const translations = {
}),
receiptScanInProgress: 'Receipt scan in progress',
receiptScanInProgressDescription: 'Receipt scan in progress. Check back later or enter the details now.',
duplicateTransaction: 'Potential duplicate expenses identified. Review duplicates to enable submission.',
receiptIssuesFound: () => ({
one: 'Issue found',
other: 'Issues found',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,7 @@ const translations = {
}),
receiptScanInProgress: 'Escaneado de recibo en proceso',
receiptScanInProgressDescription: 'Escaneado de recibo en proceso. Vuelve a comprobarlo más tarde o introduce los detalles ahora.',
duplicateTransaction: 'Se han identificado posibles gastos duplicados. Revisa los duplicados para habilitar el envío.',
defaultRate: 'Tasa predeterminada',
receiptMissingDetails: 'Recibo con campos vacíos',
missingAmount: 'Falta importe',
Expand Down
12 changes: 10 additions & 2 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import type {IOUType} from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {OnyxInputOrEntry, Policy, RecentWaypoint, Report, ReviewDuplicates, TaxRate, TaxRates, Transaction, TransactionViolation, TransactionViolations} from '@src/types/onyx';
import type {Attendee} from '@src/types/onyx/IOU';
import type {SearchPolicy, SearchReport} from '@src/types/onyx/SearchResults';
import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults';
import type {Comment, Receipt, TransactionChanges, TransactionCustomUnit, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction';
import type DeepValueOf from '@src/types/utils/DeepValueOf';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
Expand Down Expand Up @@ -989,7 +989,7 @@ function isOnHold(transaction: OnyxEntry<Transaction>): boolean {
return false;
}

return !!transaction.comment?.hold || isDuplicate(transaction.transactionID, true);
return !!transaction.comment?.hold;
}

/**
Expand Down Expand Up @@ -1043,6 +1043,13 @@ function hasViolation(transaction: Transaction | undefined, transactionViolation
);
}

function hasDuplicateTransactions(iouReportID?: string, allReportTransactions?: SearchTransaction[]): boolean {
const transactionsByIouReportID = getReportTransactions(iouReportID);
const reportTransactions = allReportTransactions ?? transactionsByIouReportID;

return reportTransactions.length > 0 && reportTransactions.some((transaction) => isDuplicate(transaction?.transactionID, true));
}

/**
* Checks if any violations for the provided transaction are of type 'notice'
*/
Expand Down Expand Up @@ -1530,6 +1537,7 @@ export {
getRecentTransactions,
hasReservationList,
hasViolation,
hasDuplicateTransactions,
hasBrokenConnectionViolation,
shouldShowBrokenConnectionViolation,
shouldShowBrokenConnectionViolationForMultipleTransactions,
Expand Down
Loading