diff --git a/src/libs/API/parameters/DismissViolationParams.ts b/src/libs/API/parameters/DismissViolationParams.ts index 9c5ba4d15661..4dcf72b482f6 100644 --- a/src/libs/API/parameters/DismissViolationParams.ts +++ b/src/libs/API/parameters/DismissViolationParams.ts @@ -1,7 +1,8 @@ type DismissViolationParams = { name: string; transactionIDList: string; - reportActionIDList: string; + reportActionIDList?: string; + reportID?: string; }; export default DismissViolationParams; diff --git a/src/libs/ReportPrimaryActionUtils.ts b/src/libs/ReportPrimaryActionUtils.ts index d9ce94303dc3..7d6e62c96964 100644 --- a/src/libs/ReportPrimaryActionUtils.ts +++ b/src/libs/ReportPrimaryActionUtils.ts @@ -254,7 +254,7 @@ function isRemoveHoldAction(report: Report, chatReport: OnyxEntry, repor } function isReviewDuplicatesAction(report: Report, reportTransactions: Transaction[]) { - const hasDuplicates = reportTransactions.some((transaction) => isDuplicate(transaction, true)); + const hasDuplicates = reportTransactions.some((transaction) => isDuplicate(transaction)); if (!hasDuplicates) { return false; diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index efc897040e6d..c8fccd791ee8 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -219,7 +219,7 @@ function isApproveAction(currentUserLogin: string, report: Report, reportTransac return false; } const isExpenseReport = isExpenseReportUtils(report); - const reportHasDuplicatedTransactions = reportTransactions.some((transaction) => isDuplicate(transaction, true)); + const reportHasDuplicatedTransactions = reportTransactions.some((transaction) => isDuplicate(transaction)); if (isExpenseReport && isProcessingReport && reportHasDuplicatedTransactions) { return true; diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 5bfa24ba34a8..63eb17b6d4a0 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1236,23 +1236,18 @@ function getRecentTransactions(transactions: Record, size = 2): /** * Check if transaction has duplicatedTransaction violation. * @param transactionID - the transaction to check - * @param checkDismissed - whether to check if the violation has already been dismissed as well */ -function isDuplicate(transaction: OnyxEntry, checkDismissed = false): boolean { +function isDuplicate(transaction: OnyxEntry): boolean { if (!transaction) { return false; } - const duplicateViolation = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`]?.find( + const duplicatedTransactionViolation = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`]?.find( (violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION, ); - const hasDuplicatedViolation = !!duplicateViolation; - if (!checkDismissed) { - return hasDuplicatedViolation; - } - - const didDismissedViolation = isViolationDismissed(transaction, duplicateViolation); + const hasDuplicatedTransactionViolation = !!duplicatedTransactionViolation; + const isDuplicatedTransactionViolationDismissed = isViolationDismissed(transaction, duplicatedTransactionViolation); - return hasDuplicatedViolation && !didDismissedViolation; + return hasDuplicatedTransactionViolation && !isDuplicatedTransactionViolationDismissed; } /** @@ -1307,7 +1302,7 @@ function hasDuplicateTransactions(iouReportID?: string, allReportTransactions?: const transactionsByIouReportID = getReportTransactions(iouReportID); const reportTransactions = allReportTransactions ?? transactionsByIouReportID; - return reportTransactions.length > 0 && reportTransactions.some((transaction) => isDuplicate(transaction, true)); + return reportTransactions.length > 0 && reportTransactions.some((transaction) => isDuplicate(transaction)); } /** diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 6d6e0c76f204..987e5aae0206 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -10012,7 +10012,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?: // Remove duplicates violations if we approve the report if (hasDuplicates) { - const transactions = getReportTransactions(expenseReport.reportID).filter((transaction) => isDuplicate(transaction, true)); + const transactions = getReportTransactions(expenseReport.reportID).filter((transaction) => isDuplicate(transaction)); if (!full) { transactions.filter((transaction) => !isOnHold(transaction)); } diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 00aa992f00d1..dc9db6e027a3 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -383,7 +383,13 @@ function updateWaypoints(transactionID: string, waypoints: WaypointCollection, i * Dismisses the duplicate transaction violation for the provided transactionIDs * and updates the transaction to include the dismissed violation in the comment. */ -function dismissDuplicateTransactionViolation(transactionIDs: string[], dismissedPersonalDetails: PersonalDetails) { +function dismissDuplicateTransactionViolation( + transactionIDs: string[], + dismissedPersonalDetails: PersonalDetails, + expenseReport: OnyxEntry, + policy: OnyxEntry, + isASAPSubmitBetaEnabled: boolean, +) { const currentTransactionViolations = transactionIDs.map((id) => ({transactionID: id, violations: allTransactionViolation?.[id] ?? []})); const currentTransactions = transactionIDs.map((id) => allTransactions?.[id]); const transactionsReportActions = currentTransactions.map((transaction) => getIOUActionForReportID(transaction.reportID, transaction.transactionID)); @@ -394,6 +400,33 @@ function dismissDuplicateTransactionViolation(transactionIDs: string[], dismisse const optimisticData: OnyxUpdate[] = []; const failureData: OnyxUpdate[] = []; + if (expenseReport) { + const hasOtherViolationsBesideDuplicates = currentTransactionViolations.some( + ({violations}) => violations.filter((violation) => violation.name !== CONST.VIOLATIONS.DUPLICATED_TRANSACTION).length, + ); + const optimisticNextStep = buildNextStepNew({ + report: expenseReport, + predictedNextStatus: expenseReport?.statusNum ?? CONST.REPORT.STATUS_NUM.OPEN, + shouldFixViolations: hasOtherViolationsBesideDuplicates, + policy, + currentUserAccountIDParam: dismissedPersonalDetails.accountID, + currentUserEmailParam: dismissedPersonalDetails.login ?? '', + hasViolations: hasOtherViolationsBesideDuplicates, + isASAPSubmitBetaEnabled, + }); + + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, + value: optimisticNextStep, + }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, + value: null, + }); + } + const optimisticReportActions: OnyxUpdate[] = transactionsReportActions.map((action, index) => { const optimisticDismissedViolationReportAction = optimisticDismissedViolationReportActions.at(index); return { @@ -484,6 +517,7 @@ function dismissDuplicateTransactionViolation(transactionIDs: string[], dismisse name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION, transactionIDList: transactionIDs.join(','), reportActionIDList: optimisticDismissedViolationReportActions.map(() => NumberUtils.rand64()).join(','), + reportID: expenseReport?.reportID, }; API.write(WRITE_COMMANDS.DISMISS_VIOLATION, params, { diff --git a/src/pages/TransactionDuplicate/Review.tsx b/src/pages/TransactionDuplicate/Review.tsx index 14febee13aeb..a5c6201d88a8 100644 --- a/src/pages/TransactionDuplicate/Review.tsx +++ b/src/pages/TransactionDuplicate/Review.tsx @@ -19,6 +19,7 @@ import {dismissDuplicateTransactionViolation} from '@libs/actions/Transaction'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {TransactionDuplicateNavigatorParamList} from '@libs/Navigation/types'; +import Permissions from '@libs/Permissions'; import {getLinkedTransactionID, getReportAction} from '@libs/ReportActionsUtils'; import {isReportIDApproved, isSettled} from '@libs/ReportUtils'; import CONST from '@src/CONST'; @@ -32,8 +33,12 @@ function TransactionDuplicateReview() { const {translate} = useLocalize(); const route = useRoute>(); const currentPersonalDetails = useCurrentUserPersonalDetails(); + const [allBetas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true}); + const isASAPSubmitBetaEnabled = Permissions.isBetaEnabled(CONST.BETAS.ASAP_SUBMIT, allBetas); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${route.params.threadReportID}`, {canBeMissing: true}); const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${route.params.threadReportID}`, {canBeMissing: true}); + const [expenseReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`, {canBeMissing: false}); + const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: false}); const reportAction = getReportAction(report?.parentReportID, report?.parentReportActionID); const transactionID = getLinkedTransactionID(reportAction); const transactionViolations = useTransactionViolations(transactionID); @@ -60,7 +65,7 @@ function TransactionDuplicateReview() { ); const keepAll = () => { - dismissDuplicateTransactionViolation(transactionIDs, currentPersonalDetails); + dismissDuplicateTransactionViolation(transactionIDs, currentPersonalDetails, expenseReport, policy, isASAPSubmitBetaEnabled); Navigation.goBack(); };