From 917d279fe774858642bf15a5aa38f93c3f369c4d Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Wed, 25 Feb 2026 15:00:40 +0100 Subject: [PATCH 1/8] add tests --- tests/actions/IOUTest/SplitTest.ts | 231 +++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index 0e95917164ee..948bd722a7ee 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -24,6 +24,7 @@ import { startSplitBill, updateSplitExpenseAmountField, updateSplitExpenseField, + updateSplitTransactions, updateSplitTransactionsFromSplitExpensesFlow, } from '@userActions/IOU/Split'; import CONST from '@src/CONST'; @@ -2565,6 +2566,236 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { }); }); +describe('updateSplitTransactions', () => { + it('should create split transactions and move original to SPLIT_REPORT_ID', async () => { + const amount = 10000; + let expenseReport: OnyxEntry; + let chatReport: OnyxEntry; + let originalTransactionID: string | undefined; + let firstIOU: ReportAction | undefined; + + const policyID = generatePolicyID(); + createWorkspace({ + policyOwnerEmail: CARLOS_EMAIL, + makeMeAdmin: true, + policyName: "Carlos's Workspace", + policyID, + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + currentUserAccountIDParam: CARLOS_ACCOUNT_ID, + currentUserEmailParam: CARLOS_EMAIL, + }); + setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + await waitForBatchedUpdates(); + + await getOnyxData({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (allReports) => { + chatReport = Object.values(allReports ?? {}).find((report) => report?.chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT); + }, + }); + + requestMoney({ + report: chatReport, + participantParams: { + payeeEmail: RORY_EMAIL, + payeeAccountID: RORY_ACCOUNT_ID, + participant: {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID, isPolicyExpenseChat: true, reportID: chatReport?.reportID}, + }, + transactionParams: {amount, attendees: [], currency: CONST.CURRENCY.USD, created: '', merchant: 'Test'}, + shouldGenerateTransactionThreadReport: true, + isASAPSubmitBetaEnabled: false, + currentUserAccountIDParam: RORY_ACCOUNT_ID, + currentUserEmailParam: RORY_EMAIL, + transactionViolations: {}, + policyRecentlyUsedCurrencies: [], + quickAction: undefined, + isSelfTourViewed: false, + betas: [CONST.BETAS.ALL], + personalDetails: {}, + }); + await waitForBatchedUpdates(); + + await getOnyxData({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (allReports) => { + expenseReport = Object.values(allReports ?? {}).find((report) => report?.type === CONST.REPORT.TYPE.EXPENSE); + }, + }); + await getOnyxData({ + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport?.reportID}`, + waitForCollectionCallback: false, + callback: (allReportsAction) => { + const iouActions = Object.values(allReportsAction ?? {}).filter((reportAction): reportAction is ReportAction => + isMoneyRequestAction(reportAction), + ); + firstIOU = iouActions?.at(0); + originalTransactionID = isMoneyRequestAction(firstIOU) ? getOriginalMessage(firstIOU)?.IOUTransactionID : undefined; + }, + }); + + const originalTransaction = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION}${originalTransactionID}`); + expect(originalTransaction?.reportID).not.toBe(CONST.REPORT.SPLIT_REPORT_ID); + + let allTransactions: OnyxCollection; + let allReports: OnyxCollection; + let allReportNameValuePairs: OnyxCollection; + await getOnyxData({key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, callback: (v) => (allTransactions = v)}); + await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (v) => (allReports = v)}); + await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); + + updateSplitTransactions({ + allTransactionsList: allTransactions, + allReportsList: allReports, + allReportNameValuePairsList: allReportNameValuePairs, + transactionData: { + reportID: originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID), + originalTransactionID: originalTransactionID ?? String(CONST.DEFAULT_NUMBER_ID), + splitExpenses: [ + {transactionID: 'split-1', amount: amount / 2, description: 'Split 1', created: DateUtils.getDBTime()}, + {transactionID: 'split-2', amount: amount / 2, description: 'Split 2', created: DateUtils.getDBTime()}, + ], + }, + searchContext: {currentSearchHash: -2}, + policyCategories: undefined, + policy: undefined, + policyRecentlyUsedCategories: [], + iouReport: expenseReport, + firstIOU, + isASAPSubmitBetaEnabled: false, + currentUserPersonalDetails, + transactionViolations: {}, + policyRecentlyUsedCurrencies: [], + quickAction: undefined, + iouReportNextStep: undefined, + betas: [CONST.BETAS.ALL], + }); + await waitForBatchedUpdates(); + + const updatedOriginal = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION}${originalTransactionID}`); + expect(updatedOriginal?.reportID).toBe(CONST.REPORT.SPLIT_REPORT_ID); + + const split1 = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION}split-1`); + const split2 = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION}split-2`); + expect(split1).toBeDefined(); + expect(split2).toBeDefined(); + }); + + it('should preserve category and tag in split transactions', async () => { + const amount = 10000; + const testCategory = 'Travel'; + const testTag = 'business-trip'; + let expenseReport: OnyxEntry; + let chatReport: OnyxEntry; + let originalTransactionID: string | undefined; + + const policyID = generatePolicyID(); + createWorkspace({ + policyOwnerEmail: CARLOS_EMAIL, + makeMeAdmin: true, + policyName: "Carlos's Workspace", + policyID, + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + currentUserAccountIDParam: CARLOS_ACCOUNT_ID, + currentUserEmailParam: CARLOS_EMAIL, + }); + setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); + await waitForBatchedUpdates(); + + await getOnyxData({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (allReports) => { + chatReport = Object.values(allReports ?? {}).find((report) => report?.chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT); + }, + }); + + requestMoney({ + report: chatReport, + participantParams: { + payeeEmail: RORY_EMAIL, + payeeAccountID: RORY_ACCOUNT_ID, + participant: {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID, isPolicyExpenseChat: true, reportID: chatReport?.reportID}, + }, + transactionParams: {amount, attendees: [], currency: CONST.CURRENCY.USD, created: '', merchant: 'Test', category: testCategory, tag: testTag}, + shouldGenerateTransactionThreadReport: true, + isASAPSubmitBetaEnabled: false, + currentUserAccountIDParam: RORY_ACCOUNT_ID, + currentUserEmailParam: RORY_EMAIL, + transactionViolations: {}, + policyRecentlyUsedCurrencies: [], + quickAction: undefined, + isSelfTourViewed: false, + betas: [CONST.BETAS.ALL], + personalDetails: {}, + }); + await waitForBatchedUpdates(); + + await getOnyxData({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (allReports) => { + expenseReport = Object.values(allReports ?? {}).find((report) => report?.type === CONST.REPORT.TYPE.EXPENSE); + }, + }); + await getOnyxData({ + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport?.reportID}`, + waitForCollectionCallback: false, + callback: (allReportsAction) => { + const iouActions = Object.values(allReportsAction ?? {}).filter((reportAction): reportAction is ReportAction => + isMoneyRequestAction(reportAction), + ); + originalTransactionID = isMoneyRequestAction(iouActions?.at(0)) ? getOriginalMessage(iouActions?.at(0))?.IOUTransactionID : undefined; + }, + }); + + const originalTransaction = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION}${originalTransactionID}`); + + let allTransactions: OnyxCollection; + let allReports: OnyxCollection; + let allReportNameValuePairs: OnyxCollection; + await getOnyxData({key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, callback: (v) => (allTransactions = v)}); + await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (v) => (allReports = v)}); + await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); + + updateSplitTransactions({ + allTransactionsList: allTransactions, + allReportsList: allReports, + allReportNameValuePairsList: allReportNameValuePairs, + transactionData: { + reportID: originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID), + originalTransactionID: originalTransactionID ?? String(CONST.DEFAULT_NUMBER_ID), + splitExpenses: [ + {transactionID: 'cat-tag-1', amount: amount / 2, description: 'Split 1', created: DateUtils.getDBTime(), category: testCategory, tags: [testTag]}, + {transactionID: 'cat-tag-2', amount: amount / 2, description: 'Split 2', created: DateUtils.getDBTime(), category: testCategory, tags: [testTag]}, + ], + }, + searchContext: {currentSearchHash: -2}, + policyCategories: undefined, + policy: undefined, + policyRecentlyUsedCategories: [], + iouReport: expenseReport, + firstIOU: undefined, + isASAPSubmitBetaEnabled: false, + currentUserPersonalDetails, + transactionViolations: {}, + policyRecentlyUsedCurrencies: [], + quickAction: undefined, + iouReportNextStep: undefined, + betas: [CONST.BETAS.ALL], + }); + await waitForBatchedUpdates(); + + const split1 = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION}cat-tag-1`); + const split2 = await getOnyxValue(`${ONYXKEYS.COLLECTION.TRANSACTION}cat-tag-2`); + expect(split1?.category).toBe(testCategory); + expect(split1?.tag).toBe(testTag); + expect(split2?.category).toBe(testCategory); + expect(split2?.tag).toBe(testTag); + }); +}); + describe('initSplitExpense', () => { it('should initialize split expense with correct transaction details', async () => { const transaction: Transaction = { From d85c4f960a8d976b389ec5f4c1757dfd3c5e0fdf Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Mon, 2 Mar 2026 08:24:52 +0100 Subject: [PATCH 2/8] moving to hook and updateSplitTransactionsFromSplitExpensesFlow --- src/hooks/useDeleteTransactions.ts | 3 +++ src/libs/actions/IOU/Split.ts | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hooks/useDeleteTransactions.ts b/src/hooks/useDeleteTransactions.ts index cfb7bc64a89c..df08dc886d8b 100644 --- a/src/hooks/useDeleteTransactions.ts +++ b/src/hooks/useDeleteTransactions.ts @@ -38,6 +38,7 @@ function useDeleteTransactions({report, reportActions, policy}: UseDeleteTransac const [policyRecentlyUsedCurrencies] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES); const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE); const [iouReportNextStep] = useOnyx(`${ONYXKEYS.COLLECTION.NEXT_STEP}${getNonEmptyStringOnyxID(report?.reportID)}`); + const [allPolicyTags] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS); const [betas] = useOnyx(ONYXKEYS.BETAS); const {isBetaEnabled} = usePermissions(); const archivedReportsIdSet = useArchivedReportsIdSet(); @@ -156,6 +157,7 @@ function useDeleteTransactions({report, reportActions, policy}: UseDeleteTransac quickAction, iouReportNextStep, betas, + allPolicyTags, }); } @@ -207,6 +209,7 @@ function useDeleteTransactions({report, reportActions, policy}: UseDeleteTransac reportActions, transactionViolations, betas, + allPolicyTags, ], ); diff --git a/src/libs/actions/IOU/Split.ts b/src/libs/actions/IOU/Split.ts index b0536bbd5a81..6fae15775cba 100644 --- a/src/libs/actions/IOU/Split.ts +++ b/src/libs/actions/IOU/Split.ts @@ -1043,7 +1043,8 @@ function updateSplitTransactions({ iouReportNextStep, isFromSplitExpensesFlow, betas, -}: UpdateSplitTransactionsParams) { + allPolicyTags, +}: UpdateSplitTransactionsParams & {allPolicyTags: OnyxCollection}) { const transactionReport = getReportOrDraftReport(transactionData?.reportID); const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); const expenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; @@ -1053,7 +1054,7 @@ function updateSplitTransactions({ const originalTransactionDetails = getTransactionDetails(originalTransaction); // TODO: remove `allPolicyTags` from this file [https://github.com/Expensify/App/issues/80401] // eslint-disable-next-line @typescript-eslint/no-deprecated - const policyTags = getPolicyTagsData(expenseReport?.policyID); + const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${expenseReport?.policyID}`] ?? {}; const participants = getMoneyRequestParticipantsFromReport(expenseReport, currentUserPersonalDetails.accountID); const splitExpenses = transactionData?.splitExpenses ?? []; @@ -1683,7 +1684,7 @@ function updateSplitTransactions({ } function updateSplitTransactionsFromSplitExpensesFlow(params: UpdateSplitTransactionsParams) { - updateSplitTransactions({...params, isFromSplitExpensesFlow: true}); + updateSplitTransactions({...params, isFromSplitExpensesFlow: true, allPolicyTags: getPolicyTags()}); const transactionReport = getReportOrDraftReport(params.transactionData?.reportID); const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); const expenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; From ac07e41a250f2f014efad7daa3929a91732c7fca Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Mon, 2 Mar 2026 08:32:29 +0100 Subject: [PATCH 3/8] update tests --- tests/actions/IOUTest/SplitTest.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index 948bd722a7ee..2820cbcaf94b 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -31,7 +31,7 @@ import CONST from '@src/CONST'; import IntlStore from '@src/languages/IntlStore'; import DateUtils from '@src/libs/DateUtils'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Policy, RecentlyUsedTags, Report, ReportNameValuePairs, SearchResults} from '@src/types/onyx'; +import type {Policy, PolicyTagLists, RecentlyUsedTags, Report, ReportNameValuePairs, SearchResults} from '@src/types/onyx'; import type {Participant as IOUParticipant, SplitExpense} from '@src/types/onyx/IOU'; import type {CurrentUserPersonalDetails} from '@src/types/onyx/PersonalDetails'; import type {Participant} from '@src/types/onyx/Report'; @@ -2645,6 +2645,15 @@ describe('updateSplitTransactions', () => { await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (v) => (allReports = v)}); await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); + let allPolicyTags: OnyxCollection; + await getOnyxData({ + waitForCollectionCallback: true, + key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}`, + callback: (tags) => { + allPolicyTags = tags; + }, + }); + updateSplitTransactions({ allTransactionsList: allTransactions, allReportsList: allReports, @@ -2670,6 +2679,7 @@ describe('updateSplitTransactions', () => { quickAction: undefined, iouReportNextStep: undefined, betas: [CONST.BETAS.ALL], + allPolicyTags, }); await waitForBatchedUpdates(); @@ -2759,6 +2769,15 @@ describe('updateSplitTransactions', () => { await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (v) => (allReports = v)}); await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); + let allPolicyTags: OnyxCollection; + await getOnyxData({ + waitForCollectionCallback: true, + key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}`, + callback: (tags) => { + allPolicyTags = tags; + }, + }); + updateSplitTransactions({ allTransactionsList: allTransactions, allReportsList: allReports, @@ -2784,6 +2803,7 @@ describe('updateSplitTransactions', () => { quickAction: undefined, iouReportNextStep: undefined, betas: [CONST.BETAS.ALL], + allPolicyTags, }); await waitForBatchedUpdates(); From 403a1d681be6e0026bdcac3d912897ceb58dbc9d Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Mon, 2 Mar 2026 13:21:44 +0100 Subject: [PATCH 4/8] fix tests --- tests/actions/IOUTest/SplitTest.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index 1fd1cddd2c13..b9e9472c9488 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -2598,6 +2598,7 @@ describe('updateSplitTransactions', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); @@ -2628,6 +2629,8 @@ describe('updateSplitTransactions', () => { isSelfTourViewed: false, betas: [CONST.BETAS.ALL], personalDetails: {}, + existingTransactionDraft: undefined, + draftTransactionIDs: [], }); await waitForBatchedUpdates(); @@ -2724,6 +2727,7 @@ describe('updateSplitTransactions', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); @@ -2754,6 +2758,8 @@ describe('updateSplitTransactions', () => { isSelfTourViewed: false, betas: [CONST.BETAS.ALL], personalDetails: {}, + existingTransactionDraft: undefined, + draftTransactionIDs: [], }); await waitForBatchedUpdates(); From a30bf439487da5a66a58f5e27220f4d688820de2 Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Thu, 5 Mar 2026 11:42:09 +0100 Subject: [PATCH 5/8] calculate policyTags before updateSplitTransactions --- src/hooks/useDeleteTransactions.ts | 11 +++++++++-- src/libs/actions/IOU/Split.ts | 11 +++++------ tests/actions/IOUTest/SplitTest.ts | 26 +++++++++++++++++--------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/hooks/useDeleteTransactions.ts b/src/hooks/useDeleteTransactions.ts index df08dc886d8b..c0a6cc2e44be 100644 --- a/src/hooks/useDeleteTransactions.ts +++ b/src/hooks/useDeleteTransactions.ts @@ -5,6 +5,7 @@ import {getIOUActionForTransactions} from '@libs/actions/IOU/Duplicate'; import {initSplitExpenseItemData, updateSplitTransactions} from '@libs/actions/IOU/Split'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import {getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils'; +import {getReportOrDraftReport} from '@libs/ReportUtils'; import {getChildTransactions, getOriginalTransactionWithSplitInfo} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -133,12 +134,18 @@ function useDeleteTransactions({report, reportActions, policy}: UseDeleteTransac return initSplitExpenseItemData(childTransaction, transactionReport); }); + const reportID = report?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); + const transactionReport = getReportOrDraftReport(reportID); + const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); + const expenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; + const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${expenseReport?.policyID}`] ?? {}; + updateSplitTransactions({ allTransactionsList: allTransactions, allReportsList: allReports, allReportNameValuePairsList: allReportNameValuePairs, transactionData: { - reportID: report?.reportID ?? String(CONST.DEFAULT_NUMBER_ID), + reportID, originalTransactionID: transactionID, splitExpenses: remainingSplitExpenses, }, @@ -157,7 +164,7 @@ function useDeleteTransactions({report, reportActions, policy}: UseDeleteTransac quickAction, iouReportNextStep, betas, - allPolicyTags, + policyTags, }); } diff --git a/src/libs/actions/IOU/Split.ts b/src/libs/actions/IOU/Split.ts index 9707fea3de75..77de9fce2561 100644 --- a/src/libs/actions/IOU/Split.ts +++ b/src/libs/actions/IOU/Split.ts @@ -1043,8 +1043,8 @@ function updateSplitTransactions({ iouReportNextStep, isFromSplitExpensesFlow, betas, - allPolicyTags, -}: UpdateSplitTransactionsParams & {allPolicyTags: OnyxCollection}) { + policyTags, +}: UpdateSplitTransactionsParams & {policyTags: OnyxTypes.PolicyTagLists}) { const transactionReport = getReportOrDraftReport(transactionData?.reportID); const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); const expenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; @@ -1052,9 +1052,6 @@ function updateSplitTransactions({ const originalTransactionID = transactionData?.originalTransactionID ?? CONST.IOU.OPTIMISTIC_TRANSACTION_ID; const originalTransaction = allTransactionsList?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${originalTransactionID}`]; const originalTransactionDetails = getTransactionDetails(originalTransaction); - // TODO: remove `allPolicyTags` from this file [https://github.com/Expensify/App/issues/80401] - // eslint-disable-next-line @typescript-eslint/no-deprecated - const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${expenseReport?.policyID}`] ?? {}; const participants = getMoneyRequestParticipantsFromReport(expenseReport, currentUserPersonalDetails.accountID); const splitExpenses = transactionData?.splitExpenses ?? []; @@ -1685,10 +1682,12 @@ function updateSplitTransactions({ } function updateSplitTransactionsFromSplitExpensesFlow(params: UpdateSplitTransactionsParams) { - updateSplitTransactions({...params, isFromSplitExpensesFlow: true, allPolicyTags: getPolicyTags()}); const transactionReport = getReportOrDraftReport(params.transactionData?.reportID); const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); const expenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; + const policyTags = getPolicyTags()?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${expenseReport?.policyID}`] ?? {}; + + updateSplitTransactions({...params, isFromSplitExpensesFlow: true, policyTags}); const isSearchPageTopmostFullScreenRoute = isSearchTopmostFullScreenRoute(); const transactionThreadReportID = params.firstIOU?.childReportID; const transactionThreadReportScreen = Navigation.getReportRouteByID(transactionThreadReportID); diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index f1aad394da38..1f040bc9ef59 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -10,7 +10,7 @@ import {createWorkspace, generatePolicyID, setWorkspaceApprovalMode} from '@libs import initSplitExpense from '@libs/actions/SplitExpenses'; import {rand64} from '@libs/NumberUtils'; import {getOriginalMessage, isActionOfType, isMoneyRequestAction} from '@libs/ReportActionsUtils'; -import {buildOptimisticIOUReportAction} from '@libs/ReportUtils'; +import {buildOptimisticIOUReportAction, getReportOrDraftReport} from '@libs/ReportUtils'; import { addSplitExpenseField, completeSplitBill, @@ -2663,12 +2663,16 @@ describe('updateSplitTransactions', () => { await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (v) => (allReports = v)}); await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); - let allPolicyTags: OnyxCollection; + const reportID = originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); + const transactionReport = getReportOrDraftReport(reportID); + const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); + const updateExpenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; + let policyTags: PolicyTagLists = {}; await getOnyxData({ waitForCollectionCallback: true, key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}`, callback: (tags) => { - allPolicyTags = tags; + policyTags = tags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${updateExpenseReport?.policyID}`] ?? {}; }, }); @@ -2677,7 +2681,7 @@ describe('updateSplitTransactions', () => { allReportsList: allReports, allReportNameValuePairsList: allReportNameValuePairs, transactionData: { - reportID: originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID), + reportID, originalTransactionID: originalTransactionID ?? String(CONST.DEFAULT_NUMBER_ID), splitExpenses: [ {transactionID: 'split-1', amount: amount / 2, description: 'Split 1', created: DateUtils.getDBTime()}, @@ -2697,7 +2701,7 @@ describe('updateSplitTransactions', () => { quickAction: undefined, iouReportNextStep: undefined, betas: [CONST.BETAS.ALL], - allPolicyTags, + policyTags, }); await waitForBatchedUpdates(); @@ -2790,12 +2794,16 @@ describe('updateSplitTransactions', () => { await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, callback: (v) => (allReports = v)}); await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); - let allPolicyTags: OnyxCollection; + const reportID = originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); + const transactionReport = getReportOrDraftReport(reportID); + const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); + const updateExpenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; + let policyTags: PolicyTagLists = {}; await getOnyxData({ waitForCollectionCallback: true, key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}`, callback: (tags) => { - allPolicyTags = tags; + policyTags = tags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${updateExpenseReport?.policyID}`] ?? {}; }, }); @@ -2804,7 +2812,7 @@ describe('updateSplitTransactions', () => { allReportsList: allReports, allReportNameValuePairsList: allReportNameValuePairs, transactionData: { - reportID: originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID), + reportID, originalTransactionID: originalTransactionID ?? String(CONST.DEFAULT_NUMBER_ID), splitExpenses: [ {transactionID: 'cat-tag-1', amount: amount / 2, description: 'Split 1', created: DateUtils.getDBTime(), category: testCategory, tags: [testTag]}, @@ -2824,7 +2832,7 @@ describe('updateSplitTransactions', () => { quickAction: undefined, iouReportNextStep: undefined, betas: [CONST.BETAS.ALL], - allPolicyTags, + policyTags, }); await waitForBatchedUpdates(); From 3139c568f4ebf7b392932a2ba9f2ca70fb4fb622 Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Thu, 5 Mar 2026 13:32:40 +0100 Subject: [PATCH 6/8] change prop calculation in deleteTransactions --- src/hooks/useDeleteTransactions.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hooks/useDeleteTransactions.ts b/src/hooks/useDeleteTransactions.ts index c0a6cc2e44be..b3bc40d8fd12 100644 --- a/src/hooks/useDeleteTransactions.ts +++ b/src/hooks/useDeleteTransactions.ts @@ -5,7 +5,6 @@ import {getIOUActionForTransactions} from '@libs/actions/IOU/Duplicate'; import {initSplitExpenseItemData, updateSplitTransactions} from '@libs/actions/IOU/Split'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import {getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils'; -import {getReportOrDraftReport} from '@libs/ReportUtils'; import {getChildTransactions, getOriginalTransactionWithSplitInfo} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -135,9 +134,8 @@ function useDeleteTransactions({report, reportActions, policy}: UseDeleteTransac }); const reportID = report?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); - const transactionReport = getReportOrDraftReport(reportID); - const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); - const expenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; + const parentTransactionReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const expenseReport = report?.type === CONST.REPORT.TYPE.EXPENSE ? report : parentTransactionReport; const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${expenseReport?.policyID}`] ?? {}; updateSplitTransactions({ From 847c4c3aeaadb5763ddde2f83a7e75f91892c1cb Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Fri, 6 Mar 2026 12:03:20 +0100 Subject: [PATCH 7/8] extract logic to getPolicyTags in tests --- tests/actions/IOUTest/SplitTest.ts | 41 ++++++++++++++---------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index 1f040bc9ef59..4d1c8d5938c7 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -130,6 +130,23 @@ const currentUserPersonalDetails: CurrentUserPersonalDetails = { avatar: 'https://example.com/avatar.jpg', }; +const getPolicyTags = async (reportID: string) => { + let allPolicyTags: OnyxCollection; + await getOnyxData({ + key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}`, + waitForCollectionCallback: true, + callback: (value) => { + allPolicyTags = value; + }, + }); + + const splitTransactionReport = getReportOrDraftReport(reportID); + const splitParentTransactionReport = getReportOrDraftReport(splitTransactionReport?.parentReportID); + const splitExpenseReport = splitTransactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? splitTransactionReport : splitParentTransactionReport; + const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${splitExpenseReport?.policyID}`] ?? {}; + return policyTags; +}; + let mockFetch: MockFetch; beforeAll(() => { @@ -2664,17 +2681,7 @@ describe('updateSplitTransactions', () => { await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); const reportID = originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); - const transactionReport = getReportOrDraftReport(reportID); - const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); - const updateExpenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; - let policyTags: PolicyTagLists = {}; - await getOnyxData({ - waitForCollectionCallback: true, - key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}`, - callback: (tags) => { - policyTags = tags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${updateExpenseReport?.policyID}`] ?? {}; - }, - }); + const policyTags = await getPolicyTags(reportID); updateSplitTransactions({ allTransactionsList: allTransactions, @@ -2795,17 +2802,7 @@ describe('updateSplitTransactions', () => { await getOnyxData({key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, waitForCollectionCallback: true, callback: (v) => (allReportNameValuePairs = v)}); const reportID = originalTransaction?.reportID ?? String(CONST.DEFAULT_NUMBER_ID); - const transactionReport = getReportOrDraftReport(reportID); - const parentTransactionReport = getReportOrDraftReport(transactionReport?.parentReportID); - const updateExpenseReport = transactionReport?.type === CONST.REPORT.TYPE.EXPENSE ? transactionReport : parentTransactionReport; - let policyTags: PolicyTagLists = {}; - await getOnyxData({ - waitForCollectionCallback: true, - key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}`, - callback: (tags) => { - policyTags = tags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${updateExpenseReport?.policyID}`] ?? {}; - }, - }); + const policyTags = await getPolicyTags(reportID); updateSplitTransactions({ allTransactionsList: allTransactions, From 07f9aa088255818d4cdf7a6ea4a6801fc2b817c4 Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Fri, 6 Mar 2026 20:32:48 +0100 Subject: [PATCH 8/8] remove getPolicyTagsData --- src/libs/actions/IOU/Split.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/libs/actions/IOU/Split.ts b/src/libs/actions/IOU/Split.ts index 9c52ea5e5687..32a4edc9bfd8 100644 --- a/src/libs/actions/IOU/Split.ts +++ b/src/libs/actions/IOU/Split.ts @@ -330,16 +330,6 @@ function splitBillAndOpenReport({ notifyNewAction(splitData.chatReportID, undefined, true); } -/** - * @deprecated This function uses Onyx.connect and should be replaced with useOnyx for reactive data access. - * TODO: remove `getPolicyTagsData` from this file [https://github.com/Expensify/App/issues/80401] - * All usages of this function should be replaced with useOnyx hook in React components. - */ -function getPolicyTagsData(policyID: string | undefined) { - const allPolicyTags = getPolicyTags(); - return allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}; -} - /** Used exclusively for starting a split expense request that contains a receipt, the split request will be completed once the receipt is scanned * or user enters details manually. *