@@ -89,7 +89,7 @@ import DateUtils from '@src/libs/DateUtils';
8989import ONYXKEYS from '@src/ONYXKEYS';
9090import ROUTES from '@src/ROUTES';
9191import type {OriginalMessageIOU, PersonalDetailsList, Policy, PolicyTagLists, RecentlyUsedTags, Report, ReportNameValuePairs, SearchResults} from '@src/types/onyx';
92- import type {Accountant, Attendee} from '@src/types/onyx/IOU';
92+ import type {Accountant, Attendee, SplitExpense } from '@src/types/onyx/IOU';
9393import type {CurrentUserPersonalDetails} from '@src/types/onyx/PersonalDetails';
9494import type {Participant, ReportCollectionDataSet} from '@src/types/onyx/Report';
9595import type ReportAction from '@src/types/onyx/ReportAction';
@@ -11765,4 +11765,286 @@ describe('actions/IOU', () => {
1176511765 expect(result).toBe(reportCreatedTimestamp);
1176611766 });
1176711767 });
11768+
11769+ describe('Report Totals Calculation for Split Expenses', () => {
11770+ function calculateReportTotalsForSplitExpenses(
11771+ expenseReport: Report | undefined,
11772+ splitExpenses: SplitExpense[],
11773+ allReportsList: Record<string, Report> | undefined,
11774+ changesInReportTotal: number,
11775+ ): Map<string, number> {
11776+ const reportTotals = new Map<string, number>();
11777+ const expenseReportID = expenseReport?.reportID;
11778+
11779+ if (expenseReportID) {
11780+ const expenseReportKey = `${ONYXKEYS.COLLECTION.REPORT}${expenseReportID}`;
11781+ const expenseReportTotal = allReportsList?.[expenseReportKey]?.total ?? expenseReport?.total ?? 0;
11782+ reportTotals.set(expenseReportID, expenseReportTotal - changesInReportTotal);
11783+ }
11784+
11785+ for (const expense of splitExpenses) {
11786+ const splitExpenseReportID = expense.reportID;
11787+ if (!splitExpenseReportID || reportTotals.has(splitExpenseReportID)) {
11788+ continue;
11789+ }
11790+
11791+ const splitExpenseReport = allReportsList?.[`${ONYXKEYS.COLLECTION.REPORT}${splitExpenseReportID}`];
11792+ reportTotals.set(splitExpenseReportID, splitExpenseReport?.total ?? 0);
11793+ }
11794+
11795+ return reportTotals;
11796+ }
11797+
11798+ it('should calculate expense report total minus changes when expense report ID exists', () => {
11799+ const expenseReport: Report = {
11800+ reportID: 'report1',
11801+ total: 10000,
11802+ } as Report;
11803+
11804+ const splitExpenses: SplitExpense[] = [];
11805+ const allReportsList = {
11806+ [`${ONYXKEYS.COLLECTION.REPORT}report1`]: {
11807+ reportID: 'report1',
11808+ total: 10000,
11809+ } as Report,
11810+ };
11811+ const changesInReportTotal = 2000;
11812+
11813+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
11814+
11815+ expect(result.size).toBe(1);
11816+ expect(result.get('report1')).toBe(8000); // 10000 - 2000
11817+ });
11818+
11819+ it('should use expense report total directly when not in allReportsList', () => {
11820+ const expenseReport: Report = {
11821+ reportID: 'report1',
11822+ total: 15000,
11823+ } as Report;
11824+
11825+ const splitExpenses: SplitExpense[] = [];
11826+ const allReportsList = {}; // Empty, so should fall back to expenseReport.total
11827+ const changesInReportTotal = 3000;
11828+
11829+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
11830+
11831+ expect(result.size).toBe(1);
11832+ expect(result.get('report1')).toBe(12000); // 15000 - 3000
11833+ });
11834+
11835+ it('should use allReportsList total when it differs from expense report total', () => {
11836+ const expenseReport: Report = {
11837+ reportID: 'report1',
11838+ total: 10000,
11839+ } as Report;
11840+
11841+ const splitExpenses: SplitExpense[] = [];
11842+ const allReportsList = {
11843+ [`${ONYXKEYS.COLLECTION.REPORT}report1`]: {
11844+ reportID: 'report1',
11845+ total: 12000, // Different from expenseReport.total
11846+ } as Report,
11847+ };
11848+ const changesInReportTotal = 2000;
11849+
11850+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
11851+
11852+ expect(result.size).toBe(1);
11853+ expect(result.get('report1')).toBe(10000); // 12000 - 2000 (uses allReportsList value)
11854+ });
11855+
11856+ it('should add split expenses from different reports to the map', () => {
11857+ const expenseReport: Report = {
11858+ reportID: 'mainReport',
11859+ total: 10000,
11860+ } as Report;
11861+
11862+ const splitExpenses: SplitExpense[] = [
11863+ {
11864+ reportID: 'splitReport1',
11865+ amount: 2000,
11866+ } as SplitExpense,
11867+ {
11868+ reportID: 'splitReport2',
11869+ amount: 3000,
11870+ } as SplitExpense,
11871+ ];
11872+
11873+ const allReportsList = {
11874+ [`${ONYXKEYS.COLLECTION.REPORT}mainReport`]: {
11875+ reportID: 'mainReport',
11876+ total: 10000,
11877+ } as Report,
11878+ [`${ONYXKEYS.COLLECTION.REPORT}splitReport1`]: {
11879+ reportID: 'splitReport1',
11880+ total: 5000,
11881+ } as Report,
11882+ [`${ONYXKEYS.COLLECTION.REPORT}splitReport2`]: {
11883+ reportID: 'splitReport2',
11884+ total: 7000,
11885+ } as Report,
11886+ };
11887+ const changesInReportTotal = 1000;
11888+
11889+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
11890+
11891+ expect(result.size).toBe(3);
11892+ expect(result.get('mainReport')).toBe(9000); // 10000 - 1000
11893+ expect(result.get('splitReport1')).toBe(5000);
11894+ expect(result.get('splitReport2')).toBe(7000);
11895+ });
11896+
11897+ it('should skip split expenses without reportID', () => {
11898+ const expenseReport: Report = {
11899+ reportID: 'mainReport',
11900+ total: 10000,
11901+ } as Report;
11902+
11903+ const splitExpenses: SplitExpense[] = [
11904+ {
11905+ reportID: undefined,
11906+ amount: 2000,
11907+ } as SplitExpense,
11908+ {
11909+ reportID: 'splitReport1',
11910+ amount: 3000,
11911+ } as SplitExpense,
11912+ ];
11913+
11914+ const allReportsList = {
11915+ [`${ONYXKEYS.COLLECTION.REPORT}mainReport`]: {
11916+ reportID: 'mainReport',
11917+ total: 10000,
11918+ } as Report,
11919+ [`${ONYXKEYS.COLLECTION.REPORT}splitReport1`]: {
11920+ reportID: 'splitReport1',
11921+ total: 5000,
11922+ } as Report,
11923+ };
11924+ const changesInReportTotal = 1000;
11925+
11926+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
11927+
11928+ expect(result.size).toBe(2); // Only mainReport and splitReport1
11929+ expect(result.get('mainReport')).toBe(9000);
11930+ expect(result.get('splitReport1')).toBe(5000);
11931+ });
11932+
11933+ it('should skip split expenses that are already in reportTotals', () => {
11934+ const expenseReport: Report = {
11935+ reportID: 'mainReport',
11936+ total: 10000,
11937+ } as Report;
11938+
11939+ // Two split expenses with the same reportID
11940+ const splitExpenses: SplitExpense[] = [
11941+ {
11942+ reportID: 'splitReport1',
11943+ amount: 2000,
11944+ } as SplitExpense,
11945+ {
11946+ reportID: 'splitReport1', // Duplicate reportID
11947+ amount: 3000,
11948+ } as SplitExpense,
11949+ {
11950+ reportID: 'splitReport2',
11951+ amount: 1500,
11952+ } as SplitExpense,
11953+ ];
11954+
11955+ const allReportsList = {
11956+ [`${ONYXKEYS.COLLECTION.REPORT}mainReport`]: {
11957+ reportID: 'mainReport',
11958+ total: 10000,
11959+ } as Report,
11960+ [`${ONYXKEYS.COLLECTION.REPORT}splitReport1`]: {
11961+ reportID: 'splitReport1',
11962+ total: 5000,
11963+ } as Report,
11964+ [`${ONYXKEYS.COLLECTION.REPORT}splitReport2`]: {
11965+ reportID: 'splitReport2',
11966+ total: 3000,
11967+ } as Report,
11968+ };
11969+ const changesInReportTotal = 1000;
11970+
11971+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
11972+
11973+ expect(result.size).toBe(3);
11974+ expect(result.get('mainReport')).toBe(9000);
11975+ expect(result.get('splitReport1')).toBe(5000); // Should only be added once
11976+ expect(result.get('splitReport2')).toBe(3000);
11977+ });
11978+
11979+ it('should default split expense report total to 0 when not found in allReportsList', () => {
11980+ const expenseReport: Report = {
11981+ reportID: 'mainReport',
11982+ total: 10000,
11983+ } as Report;
11984+
11985+ const splitExpenses: SplitExpense[] = [
11986+ {
11987+ reportID: 'splitReport1',
11988+ amount: 2000,
11989+ } as SplitExpense,
11990+ ];
11991+
11992+ const allReportsList = {
11993+ [`${ONYXKEYS.COLLECTION.REPORT}mainReport`]: {
11994+ reportID: 'mainReport',
11995+ total: 10000,
11996+ } as Report,
11997+ // splitReport1 is NOT in allReportsList
11998+ };
11999+ const changesInReportTotal = 1000;
12000+
12001+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
12002+
12003+ expect(result.size).toBe(2);
12004+ expect(result.get('mainReport')).toBe(9000);
12005+ expect(result.get('splitReport1')).toBe(0); // Defaults to 0
12006+ });
12007+
12008+ it('should handle empty split expenses array', () => {
12009+ const expenseReport: Report = {
12010+ reportID: 'mainReport',
12011+ total: 10000,
12012+ } as Report;
12013+
12014+ const splitExpenses: SplitExpense[] = [];
12015+ const allReportsList = {
12016+ [`${ONYXKEYS.COLLECTION.REPORT}mainReport`]: {
12017+ reportID: 'mainReport',
12018+ total: 10000,
12019+ } as Report,
12020+ };
12021+ const changesInReportTotal = 2000;
12022+
12023+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
12024+
12025+ expect(result.size).toBe(1);
12026+ expect(result.get('mainReport')).toBe(8000);
12027+ });
12028+
12029+ it('should handle negative changesInReportTotal', () => {
12030+ const expenseReport: Report = {
12031+ reportID: 'mainReport',
12032+ total: 10000,
12033+ } as Report;
12034+
12035+ const splitExpenses: SplitExpense[] = [];
12036+ const allReportsList = {
12037+ [`${ONYXKEYS.COLLECTION.REPORT}mainReport`]: {
12038+ reportID: 'mainReport',
12039+ total: 10000,
12040+ } as Report,
12041+ };
12042+ const changesInReportTotal = -2000; // Negative change
12043+
12044+ const result = calculateReportTotalsForSplitExpenses(expenseReport, splitExpenses, allReportsList, changesInReportTotal);
12045+
12046+ expect(result.size).toBe(1);
12047+ expect(result.get('mainReport')).toBe(12000); // 10000 - (-2000) = 12000
12048+ });
12049+ });
1176812050});
0 commit comments