From 0f8c971730728205db10b5892e3a0086d282420a Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Thu, 11 Dec 2025 12:23:31 +0430 Subject: [PATCH 1/8] Recalculate report totals after moving expenses and hide Pay button when no payable items remain. --- src/libs/SearchUIUtils.ts | 2 +- src/libs/actions/Transaction.ts | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 06278f12c7247..fd6715af88d5d 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1578,7 +1578,7 @@ function getReportSections( } if (shouldShow) { - const reportPendingAction = reportItem?.pendingAction ?? reportItem?.pendingFields?.preview; + const reportPendingAction = reportItem?.pendingAction ?? reportItem?.pendingFields?.total ?? reportItem?.pendingFields?.createReport ?? reportItem?.pendingFields?.preview; const shouldShowBlankTo = !reportItem || isOpenExpenseReport(reportItem); const allActions = getActions(data, allViolations, key, currentSearch, currentUserEmail, actions); diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 614c3902de6a1..4d4dd209c9d58 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -946,14 +946,24 @@ function changeTransactionsReport( const oldReportTotal = oldReport?.total ?? 0; const updatedReportTotal = transactionAmount < 0 ? oldReportTotal - transactionAmount : oldReportTotal + transactionAmount; - if (oldReport && oldReport.currency === transactionCurrency) { - updatedReportTotals[oldReportID] = updatedReportTotals[oldReportID] ? updatedReportTotals[oldReportID] : updatedReportTotal; - updatedReportNonReimbursableTotals[oldReportID] = - (updatedReportNonReimbursableTotals[oldReportID] ? updatedReportNonReimbursableTotals[oldReportID] : (oldReport?.nonReimbursableTotal ?? 0)) + - (transaction?.reimbursable ? 0 : transactionAmount); - updatedReportUnheldNonReimbursableTotals[oldReportID] = - (updatedReportUnheldNonReimbursableTotals[oldReportID] ? updatedReportUnheldNonReimbursableTotals[oldReportID] : (oldReport?.unheldNonReimbursableTotal ?? 0)) + - (transaction?.reimbursable && !isOnHold(transaction) ? 0 : transactionAmount); + if (oldReport) { + const oldReportCurrency = oldReport.currency; + const remainingTransactions = getReportTransactions(oldReportID).filter( + (t) => !transactionIDs.includes(t.transactionID) && t.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + ); + + const willBeEmpty = remainingTransactions.length === 0; + + if (oldReportCurrency === transactionCurrency || willBeEmpty) { + const baseTotal = willBeEmpty ? 0 : (updatedReportTotals[oldReportID] ?? oldReportTotal); + updatedReportTotals[oldReportID] = baseTotal + (willBeEmpty ? 0 : transactionAmount); + + const baseNonReimb = willBeEmpty ? 0 : (updatedReportNonReimbursableTotals[oldReportID] ?? oldReport?.nonReimbursableTotal ?? 0); + updatedReportNonReimbursableTotals[oldReportID] = baseNonReimb + (willBeEmpty ? 0 : transaction?.reimbursable ? 0 : transactionAmount); + + const baseUnheld = willBeEmpty ? 0 : (updatedReportUnheldNonReimbursableTotals[oldReportID] ?? oldReport?.unheldNonReimbursableTotal ?? 0); + updatedReportUnheldNonReimbursableTotals[oldReportID] = baseUnheld + (willBeEmpty ? 0 : transaction?.reimbursable && !isOnHold(transaction) ? 0 : transactionAmount); + } } if (targetReportID) { From 9217fc4af2d21f5a00f635a84aa53b974b251128 Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Thu, 11 Dec 2025 12:24:50 +0430 Subject: [PATCH 2/8] removed unused variable --- src/libs/actions/Transaction.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 4d4dd209c9d58..867121bc9cfda 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -944,7 +944,6 @@ function changeTransactionsReport( const targetReportID = isUnreported ? selfDMReportID : reportID; const {amount: transactionAmount = 0, currency: transactionCurrency} = getTransactionDetails(transaction, undefined, undefined, allowNegative) ?? {}; const oldReportTotal = oldReport?.total ?? 0; - const updatedReportTotal = transactionAmount < 0 ? oldReportTotal - transactionAmount : oldReportTotal + transactionAmount; if (oldReport) { const oldReportCurrency = oldReport.currency; From ef5eeebe15cb37711becdc04f027380a7b04fd2b Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Thu, 11 Dec 2025 12:32:39 +0430 Subject: [PATCH 3/8] refine the code a little bit --- src/libs/actions/Transaction.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 867121bc9cfda..7fc363ca01b1e 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -955,13 +955,30 @@ function changeTransactionsReport( if (oldReportCurrency === transactionCurrency || willBeEmpty) { const baseTotal = willBeEmpty ? 0 : (updatedReportTotals[oldReportID] ?? oldReportTotal); - updatedReportTotals[oldReportID] = baseTotal + (willBeEmpty ? 0 : transactionAmount); const baseNonReimb = willBeEmpty ? 0 : (updatedReportNonReimbursableTotals[oldReportID] ?? oldReport?.nonReimbursableTotal ?? 0); - updatedReportNonReimbursableTotals[oldReportID] = baseNonReimb + (willBeEmpty ? 0 : transaction?.reimbursable ? 0 : transactionAmount); const baseUnheld = willBeEmpty ? 0 : (updatedReportUnheldNonReimbursableTotals[oldReportID] ?? oldReport?.unheldNonReimbursableTotal ?? 0); - updatedReportUnheldNonReimbursableTotals[oldReportID] = baseUnheld + (willBeEmpty ? 0 : transaction?.reimbursable && !isOnHold(transaction) ? 0 : transactionAmount); + + let addToTotal = 0; + let addToNonReimb = 0; + let addToUnheld = 0; + + if (!willBeEmpty) { + addToTotal = transactionAmount; + + if (!transaction?.reimbursable) { + addToNonReimb = transactionAmount; + + if (!isOnHold(transaction)) { + addToUnheld = transactionAmount; + } + } + } + + updatedReportTotals[oldReportID] = baseTotal + addToTotal; + updatedReportNonReimbursableTotals[oldReportID] = baseNonReimb + addToNonReimb; + updatedReportUnheldNonReimbursableTotals[oldReportID] = baseUnheld + addToUnheld; } } From c52a49a0569cbbff9f224b7ec2e2bf80aff5aeba Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Thu, 11 Dec 2025 13:22:17 +0430 Subject: [PATCH 4/8] applied bot suggested refinement --- src/libs/actions/Transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 7fc363ca01b1e..a9f99677f54e9 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -948,7 +948,7 @@ function changeTransactionsReport( if (oldReport) { const oldReportCurrency = oldReport.currency; const remainingTransactions = getReportTransactions(oldReportID).filter( - (t) => !transactionIDs.includes(t.transactionID) && t.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + (t) => t.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && !transactionIDs.includes(t.transactionID), ); const willBeEmpty = remainingTransactions.length === 0; From 29d9ac74557a64392a2014d2701e81fea0050068 Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Fri, 12 Dec 2025 15:49:00 +0430 Subject: [PATCH 5/8] refine unit tests --- tests/unit/TransactionTest.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/TransactionTest.ts b/tests/unit/TransactionTest.ts index 5a414da081628..25ad7dd5b9e76 100644 --- a/tests/unit/TransactionTest.ts +++ b/tests/unit/TransactionTest.ts @@ -551,7 +551,7 @@ describe('Transaction', () => { ...generateTransaction({ reportID: oldExpenseReport.reportID, }), - amount: -100, + amount: -200, reimbursable: false, }; const oldIOUAction: OnyxEntry> = { @@ -589,7 +589,7 @@ describe('Transaction', () => { expect(report?.nonReimbursableTotal).toBe(oldExpenseReport.nonReimbursableTotal - transaction.amount); }); - it('should not update the old report total when the currency is different', async () => { + it('should reset the old report total to 0 when no expenses remain, even if the currencies differ', async () => { const oldExpenseReport = { ...createRandomReport(1, undefined), total: -200, @@ -634,8 +634,8 @@ describe('Transaction', () => { }); }); - expect(report?.total).toBe(oldExpenseReport.total); - expect(report?.nonReimbursableTotal).toBe(oldExpenseReport.nonReimbursableTotal); + expect(report?.total).toBe(0); + expect(report?.nonReimbursableTotal).toBe(0); }); it('should show "waiting for you to submit expense" next step message when moving expense to a new report ', async () => { From 3bcb4cdd29723c8ba7a0ef25fd67b43b18f00908 Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Fri, 26 Dec 2025 21:25:34 +0430 Subject: [PATCH 6/8] grey out the values report rows and report titles Backend calculation --- .../MoneyRequestReportTransactionList.tsx | 14 +- src/libs/SearchUIUtils.ts | 11 + src/libs/actions/Transaction.ts | 194 ++++++++++++++++-- src/pages/AddUnreportedExpense.tsx | 17 +- src/pages/NewReportWorkspaceSelectionPage.tsx | 4 +- .../Search/SearchTransactionsChangeReport.tsx | 5 +- .../iou/request/step/IOURequestEditReport.tsx | 4 +- .../iou/request/step/IOURequestStepReport.tsx | 4 +- 8 files changed, 228 insertions(+), 25 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index 6def99bb55e14..b86d9e4406999 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -628,12 +628,14 @@ function MoneyRequestReportTransactionList({ )} - + + + ) { + if (!allSnapshots) { + return []; + } + + return Object.keys(allSnapshots || {}) as OnyxSnapshotKey[]; +} + export { getSuggestedSearches, getDefaultActionableSearchMenuItem, @@ -3434,6 +3444,7 @@ export { getSettlementStatus, getSettlementStatusBadgeProps, getTransactionFromTransactionListItem, + getSnapshotKeys, getSearchColumnTranslationKey, getTableMinWidth, getCustomColumns, diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 395e57af54a06..8d54db6462ffc 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -28,6 +28,7 @@ import { hasViolations as hasViolationsReportUtils, shouldEnableNegative, } from '@libs/ReportUtils'; +import {getSnapshotKeys} from '@libs/SearchUIUtils'; import {isManagedCardTransaction, isOnHold, waypointHasValidAddress} from '@libs/TransactionUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import CONST from '@src/CONST'; @@ -41,6 +42,7 @@ import type { ReportAction, ReportNextStepDeprecated, ReviewDuplicates, + SearchResults, Transaction, TransactionViolation, TransactionViolations, @@ -694,6 +696,7 @@ function changeTransactionsReport( isASAPSubmitBetaEnabled: boolean, accountID: number, email: string, + allSnapshots: OnyxCollection, newReport?: OnyxEntry, policy?: OnyxEntry, reportNextStep?: OnyxEntry, @@ -722,6 +725,7 @@ function changeTransactionsReport( | typeof ONYXKEYS.COLLECTION.TRANSACTION | typeof ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS | typeof ONYXKEYS.COLLECTION.NEXT_STEP + | typeof ONYXKEYS.COLLECTION.SNAPSHOT > > = []; const successData: Array< @@ -731,6 +735,7 @@ function changeTransactionsReport( | typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS | typeof ONYXKEYS.COLLECTION.TRANSACTION | typeof ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + | typeof ONYXKEYS.COLLECTION.SNAPSHOT > > = []; @@ -984,32 +989,112 @@ function changeTransactionsReport( const willBeEmpty = remainingTransactions.length === 0; - if (oldReportCurrency === transactionCurrency || willBeEmpty) { - const baseTotal = willBeEmpty ? 0 : (updatedReportTotals[oldReportID] ?? oldReportTotal); + if (willBeEmpty) { + updatedReportTotals[oldReportID] = 0; + updatedReportNonReimbursableTotals[oldReportID] = 0; + updatedReportUnheldNonReimbursableTotals[oldReportID] = 0; + } else if (oldReportCurrency === transactionCurrency) { + const baseTotal = updatedReportTotals[oldReportID] ?? oldReportTotal; - const baseNonReimb = willBeEmpty ? 0 : (updatedReportNonReimbursableTotals[oldReportID] ?? oldReport?.nonReimbursableTotal ?? 0); + const baseNonReimb = updatedReportNonReimbursableTotals[oldReportID] ?? oldReport?.nonReimbursableTotal ?? 0; - const baseUnheld = willBeEmpty ? 0 : (updatedReportUnheldNonReimbursableTotals[oldReportID] ?? oldReport?.unheldNonReimbursableTotal ?? 0); + const baseUnheld = updatedReportUnheldNonReimbursableTotals[oldReportID] ?? oldReport?.unheldNonReimbursableTotal ?? 0; - let addToTotal = 0; let addToNonReimb = 0; let addToUnheld = 0; - if (!willBeEmpty) { - addToTotal = transactionAmount; + if (!transaction?.reimbursable) { + addToNonReimb = transactionAmount; - if (!transaction?.reimbursable) { - addToNonReimb = transactionAmount; - - if (!isOnHold(transaction)) { - addToUnheld = transactionAmount; - } + if (!isOnHold(transaction)) { + addToUnheld = transactionAmount; } } - updatedReportTotals[oldReportID] = baseTotal + addToTotal; + updatedReportTotals[oldReportID] = baseTotal + transactionAmount; updatedReportNonReimbursableTotals[oldReportID] = baseNonReimb + addToNonReimb; updatedReportUnheldNonReimbursableTotals[oldReportID] = baseUnheld + addToUnheld; + } else { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${oldReport.reportID}`, + value: { + pendingFields: { + preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + total: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }); + + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${oldReport.reportID}`, + value: { + pendingFields: { + preview: null, + total: null, + }, + }, + }); + + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${oldReport.reportID}`, + value: { + pendingFields: { + preview: null, + total: null, + }, + }, + }); + + const allSnapshotKeys = getSnapshotKeys(allSnapshots); + + if (allSnapshotKeys?.length && allSnapshotKeys.length > 0) { + for (const key of allSnapshotKeys) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key, + value: { + data: { + [`${ONYXKEYS.COLLECTION.REPORT}${oldReport.reportID}`]: { + pendingFields: { + total: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }, + } as Partial, + }); + + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key, + value: { + data: { + [`${ONYXKEYS.COLLECTION.REPORT}${oldReport.reportID}`]: { + pendingFields: { + total: null, + }, + }, + }, + } as Partial, + }); + + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key, + value: { + data: { + [`${ONYXKEYS.COLLECTION.REPORT}${oldReport.reportID}`]: { + pendingFields: { + total: null, + }, + }, + }, + } as Partial, + }); + } + } } } @@ -1027,6 +1112,87 @@ function changeTransactionsReport( const currentUnheldNonReimbursableTotal = updatedReportUnheldNonReimbursableTotals[targetReportID] ?? targetReport?.unheldNonReimbursableTotal ?? 0; updatedReportUnheldNonReimbursableTotals[targetReportID] = currentUnheldNonReimbursableTotal - (transactionReimbursable && !isOnHold(transaction) ? 0 : transactionAmount); + } else { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetReportID}`, + value: { + pendingFields: { + preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + total: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }); + + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetReportID}`, + value: { + pendingFields: { + preview: null, + total: null, + }, + }, + }); + + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetReportID}`, + value: { + pendingFields: { + preview: null, + total: null, + }, + }, + }); + + const allSnapshotKeys = getSnapshotKeys(allSnapshots); + + if (allSnapshotKeys?.length && allSnapshotKeys.length > 0) { + for (const key of allSnapshotKeys) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key, + value: { + data: { + [`${ONYXKEYS.COLLECTION.REPORT}${targetReportID}`]: { + pendingFields: { + total: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }, + } as Partial, + }); + + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key, + value: { + data: { + [`${ONYXKEYS.COLLECTION.REPORT}${targetReportID}`]: { + pendingFields: { + total: null, + }, + }, + }, + } as Partial, + }); + + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key, + value: { + data: { + [`${ONYXKEYS.COLLECTION.REPORT}${targetReportID}`]: { + pendingFields: { + total: null, + }, + }, + }, + } as Partial, + }); + } + } } } diff --git a/src/pages/AddUnreportedExpense.tsx b/src/pages/AddUnreportedExpense.tsx index 35cfde53113f2..3bd616f29c925 100644 --- a/src/pages/AddUnreportedExpense.tsx +++ b/src/pages/AddUnreportedExpense.tsx @@ -61,6 +61,7 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) { const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT); const session = useSession(); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true}); + const [allSnapshots] = useOnyx(ONYXKEYS.COLLECTION.SNAPSHOT, {canBeMissing: true}); const shouldShowUnreportedTransactionsSkeletons = isLoadingUnreportedTransactions && hasMoreUnreportedTransactionsResults && !isOffline; const getUnreportedTransactions = useCallback( @@ -182,6 +183,7 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) { isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', + allSnapshots, reportToConfirm, policy, reportNextStep, @@ -190,7 +192,20 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) { } }); setErrorMessage(''); - }, [selectedIds, translate, report, isASAPSubmitBetaEnabled, session?.accountID, session?.email, transactionViolations, reportToConfirm, policy, reportNextStep, policyCategories]); + }, [ + selectedIds, + translate, + report, + isASAPSubmitBetaEnabled, + session?.accountID, + session?.email, + transactionViolations, + reportToConfirm, + policy, + reportNextStep, + policyCategories, + allSnapshots, + ]); const footerContent = useMemo(() => { return ( diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index 32b36476304e6..8149677226016 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -67,7 +67,7 @@ function NewReportWorkspaceSelectionPage({route}: NewReportWorkspaceSelectionPag const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, accountID ?? CONST.DEFAULT_NUMBER_ID, email ?? ''); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); const [hasDismissedEmptyReportsConfirmation] = useOnyx(ONYXKEYS.NVP_EMPTY_REPORTS_CONFIRMATION_DISMISSED, {canBeMissing: true}); - + const [allSnapshots] = useOnyx(ONYXKEYS.COLLECTION.SNAPSHOT, {canBeMissing: true}); const [policies, fetchStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); @@ -127,6 +127,7 @@ function NewReportWorkspaceSelectionPage({route}: NewReportWorkspaceSelectionPag isASAPSubmitBetaEnabled, currentUserPersonalDetails?.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserPersonalDetails?.email ?? '', + allSnapshots, optimisticReport, policies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`], reportNextStep, @@ -163,6 +164,7 @@ function NewReportWorkspaceSelectionPage({route}: NewReportWorkspaceSelectionPag policies, clearSelectedTransactions, backTo, + allSnapshots, ], ); diff --git a/src/pages/Search/SearchTransactionsChangeReport.tsx b/src/pages/Search/SearchTransactionsChangeReport.tsx index e4b7d587deff0..dc397b6973498 100644 --- a/src/pages/Search/SearchTransactionsChangeReport.tsx +++ b/src/pages/Search/SearchTransactionsChangeReport.tsx @@ -35,6 +35,7 @@ function SearchTransactionsChangeReport() { const hasPerDiemTransactions = useHasPerDiemTransactions(selectedTransactionsKeys); const {policyForMovingExpensesID, shouldSelectPolicy} = usePolicyForMovingExpenses(hasPerDiemTransactions); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true}); + const [allSnapshots] = useOnyx(ONYXKEYS.COLLECTION.SNAPSHOT, {canBeMissing: true}); const {isBetaEnabled} = usePermissions(); const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT); const session = useSession(); @@ -81,6 +82,7 @@ function SearchTransactionsChangeReport() { isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', + allSnapshots, optimisticReport, policyForMovingExpensesID ? allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyForMovingExpensesID}`] : undefined, reportNextStep, @@ -122,6 +124,7 @@ function SearchTransactionsChangeReport() { isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', + allSnapshots, destinationReport, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${item.policyID}`], reportNextStep, @@ -139,7 +142,7 @@ function SearchTransactionsChangeReport() { if (selectedTransactionsKeys.length === 0) { return; } - changeTransactionsReport(selectedTransactionsKeys, isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? ''); + changeTransactionsReport(selectedTransactionsKeys, isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', allSnapshots); clearSelectedTransactions(); Navigation.goBack(); }; diff --git a/src/pages/iou/request/step/IOURequestEditReport.tsx b/src/pages/iou/request/step/IOURequestEditReport.tsx index 80adc50d2331a..5c3949f757548 100644 --- a/src/pages/iou/request/step/IOURequestEditReport.tsx +++ b/src/pages/iou/request/step/IOURequestEditReport.tsx @@ -44,6 +44,7 @@ function IOURequestEditReport({route}: IOURequestEditReportProps) { const session = useSession(); const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const [allPolicyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}`, {canBeMissing: true}); + const [allSnapshots] = useOnyx(ONYXKEYS.COLLECTION.SNAPSHOT, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const hasPerDiemTransactions = useHasPerDiemTransactions(selectedTransactionIDs); @@ -66,6 +67,7 @@ function IOURequestEditReport({route}: IOURequestEditReportProps) { isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', + allSnapshots, newReport, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${item.policyID}`], reportNextStep, @@ -82,7 +84,7 @@ function IOURequestEditReport({route}: IOURequestEditReportProps) { if (!selectedReport || selectedTransactionIDs.length === 0) { return; } - changeTransactionsReport(selectedTransactionIDs, isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? ''); + changeTransactionsReport(selectedTransactionIDs, isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', allSnapshots); if (shouldTurnOffSelectionMode) { turnOffMobileSelectionMode(); } diff --git a/src/pages/iou/request/step/IOURequestStepReport.tsx b/src/pages/iou/request/step/IOURequestStepReport.tsx index 84bb5b6b0883a..cbf65b83f368d 100644 --- a/src/pages/iou/request/step/IOURequestStepReport.tsx +++ b/src/pages/iou/request/step/IOURequestStepReport.tsx @@ -48,6 +48,7 @@ function IOURequestStepReport({route, transaction}: IOURequestStepReportProps) { const selectedReportID = shouldUseTransactionReport ? transactionReport?.reportID : outstandingReportID; const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const [allPolicyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}`, {canBeMissing: true}); + const [allSnapshots] = useOnyx(ONYXKEYS.COLLECTION.SNAPSHOT, {canBeMissing: true}); const {removeTransaction, setSelectedTransactions} = useSearchContext(); const reportOrDraftReport = getReportOrDraftReport(reportIDFromRoute); const isEditing = action === CONST.IOU.ACTION.EDIT; @@ -129,6 +130,7 @@ function IOURequestStepReport({route, transaction}: IOURequestStepReportProps) { isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', + allSnapshots, report, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${item.policyID}`], undefined, @@ -169,7 +171,7 @@ function IOURequestStepReport({route, transaction}: IOURequestStepReportProps) { Navigation.dismissModal(); // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { - changeTransactionsReport([transaction.transactionID], isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? ''); + changeTransactionsReport([transaction.transactionID], isASAPSubmitBetaEnabled, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '', allSnapshots); removeTransaction(transaction.transactionID); }); }; From ec47602c1dc9ce0e8ab709bc2bb3d6bb735fe0e1 Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Sat, 27 Dec 2025 21:11:57 +0430 Subject: [PATCH 7/8] fixed type error --- tests/actions/IOUTest.ts | 2 +- tests/unit/TransactionTest.ts | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 8ec324d876600..f27c5278179a4 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -8458,7 +8458,7 @@ describe('actions/IOU', () => { expect(result.current.report).toBeDefined(); }); - changeTransactionsReport([transaction?.transactionID], false, CARLOS_ACCOUNT_ID, CARLOS_EMAIL, result.current.report); + changeTransactionsReport([transaction?.transactionID], false, CARLOS_ACCOUNT_ID, CARLOS_EMAIL, {}, result.current.report); let updatedTransaction: OnyxEntry; let updatedIOUReportActionOnSelfDMReport: OnyxEntry; diff --git a/tests/unit/TransactionTest.ts b/tests/unit/TransactionTest.ts index 7873412f90c76..ee02ed67bed09 100644 --- a/tests/unit/TransactionTest.ts +++ b/tests/unit/TransactionTest.ts @@ -116,7 +116,7 @@ describe('Transaction', () => { const report = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', report); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, report); await waitForBatchedUpdates(); const reportActions = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -153,7 +153,7 @@ describe('Transaction', () => { const report = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', report); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, report); await waitForBatchedUpdates(); const reportActions = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -203,7 +203,7 @@ describe('Transaction', () => { const report = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', report, undefined, mockReportNextStep); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, report, undefined, mockReportNextStep); await waitForBatchedUpdates(); expect(mockAPIWrite).toHaveBeenCalled(); @@ -255,7 +255,7 @@ describe('Transaction', () => { const report = await getReportFromUseOnyx(CONST.REPORT.UNREPORTED_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', report, undefined, mockReportNextStep); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, report, undefined, mockReportNextStep); await waitForBatchedUpdates(); expect(mockAPIWrite).toHaveBeenCalled(); @@ -295,7 +295,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${FAKE_OLD_REPORT_ID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); const report = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', report, undefined, undefined); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, report, undefined, undefined); await waitForBatchedUpdates(); expect(mockAPIWrite).toHaveBeenCalled(); @@ -348,7 +348,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${FAKE_OLD_REPORT_ID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); const report = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', report); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, report); await waitForBatchedUpdates(); try { @@ -393,7 +393,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${FAKE_OLD_REPORT_ID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); const report = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], true, CURRENT_USER_ID, 'test@example.com', report); + changeTransactionsReport([transaction.transactionID], true, CURRENT_USER_ID, 'test@example.com', {}, report); await waitForBatchedUpdates(); expect(mockAPIWrite).toHaveBeenCalled(); @@ -435,7 +435,7 @@ describe('Transaction', () => { const customEmail = 'custom@example.com'; const report = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, customAccountID, customEmail, report); + changeTransactionsReport([transaction.transactionID], false, customAccountID, customEmail, {}, report); await waitForBatchedUpdates(); expect(mockAPIWrite).toHaveBeenCalled(); @@ -482,7 +482,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, expenseReport); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${FAKE_SELF_DM_REPORT_ID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', expenseReport); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, expenseReport); await waitForBatchedUpdates(); const report = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -529,7 +529,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, expenseReport); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${FAKE_SELF_DM_REPORT_ID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', expenseReport); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, expenseReport); await waitForBatchedUpdates(); const report = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -577,7 +577,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldExpenseReport.reportID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); const fakeReport = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', fakeReport); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, fakeReport); await waitForBatchedUpdates(); const report = await new Promise>((resolve) => { @@ -626,7 +626,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldExpenseReport.reportID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); const fakeReport = await getReportFromUseOnyx(FAKE_NEW_REPORT_ID); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', fakeReport); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, fakeReport); await waitForBatchedUpdates(); const report = await new Promise>((resolve) => { @@ -666,7 +666,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, transaction); await Onyx.merge(`${ONYXKEYS.PERSONAL_DETAILS_LIST}`, userPersonalDetails); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@gmail.com', newOpenReport, policy, undefined, policyCategories); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@gmail.com', {}, newOpenReport, policy, undefined, policyCategories); await waitForBatchedUpdates(); From 6e97a3450122abc39c7467073e418f79aa6e271d Mon Sep 17 00:00:00 2001 From: Nabi Ebrahimi Date: Wed, 7 Jan 2026 12:55:28 +0430 Subject: [PATCH 8/8] fixed type error in unit tests --- tests/unit/TransactionTest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/TransactionTest.ts b/tests/unit/TransactionTest.ts index cf74c25cd809f..a4e77dc8b361b 100644 --- a/tests/unit/TransactionTest.ts +++ b/tests/unit/TransactionTest.ts @@ -583,7 +583,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${newExpenseReport.reportID}`, newExpenseReport); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldExpenseReport.reportID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', newExpenseReport); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, newExpenseReport); await waitForBatchedUpdates(); const report = await new Promise>((resolve) => { const connection = Onyx.connect({ @@ -636,7 +636,7 @@ describe('Transaction', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${newExpenseReport.reportID}`, newExpenseReport); await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldExpenseReport.reportID}`, {[oldIOUAction.reportActionID]: oldIOUAction}); - changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', newExpenseReport); + changeTransactionsReport([transaction.transactionID], false, CURRENT_USER_ID, 'test@example.com', {}, newExpenseReport); await waitForBatchedUpdates(); const report = await new Promise>((resolve) => { const connection = Onyx.connect({