Skip to content

Commit 7f2fcd7

Browse files
authored
Merge pull request #78914 from ShridharGoel/issue78155
Show correct report total after offline split
2 parents 872382e + a460fab commit 7f2fcd7

File tree

2 files changed

+297
-4
lines changed

2 files changed

+297
-4
lines changed

src/libs/actions/IOU/index.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14005,11 +14005,22 @@ function updateSplitTransactions({
1400514005

1400614006
// The split transactions can be in different reports, so we need to calculate the total for each report.
1400714007
const reportTotals = new Map<string, number>();
14008+
const expenseReportID = expenseReport?.reportID;
14009+
14010+
if (expenseReportID) {
14011+
const expenseReportKey = `${ONYXKEYS.COLLECTION.REPORT}${expenseReportID}`;
14012+
const expenseReportTotal = allReportsList?.[expenseReportKey]?.total ?? expenseReport?.total ?? 0;
14013+
reportTotals.set(expenseReportID, expenseReportTotal - changesInReportTotal);
14014+
}
14015+
1400814016
for (const expense of splitExpenses) {
14009-
if (expense.reportID) {
14010-
const currentTotal = reportTotals.get(expense.reportID) ?? 0;
14011-
reportTotals.set(expense.reportID, currentTotal - (expense.amount ?? 0));
14017+
const splitExpenseReportID = expense.reportID;
14018+
if (!splitExpenseReportID || reportTotals.has(splitExpenseReportID)) {
14019+
continue;
1401214020
}
14021+
14022+
const splitExpenseReport = allReportsList?.[`${ONYXKEYS.COLLECTION.REPORT}${splitExpenseReportID}`];
14023+
reportTotals.set(splitExpenseReportID, splitExpenseReport?.total ?? 0);
1401314024
}
1401414025

1401514026
for (const [index, splitExpense] of splitExpenses.entries()) {

tests/actions/IOUTest.ts

Lines changed: 283 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ import DateUtils from '@src/libs/DateUtils';
8989
import ONYXKEYS from '@src/ONYXKEYS';
9090
import ROUTES from '@src/ROUTES';
9191
import 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';
9393
import type {CurrentUserPersonalDetails} from '@src/types/onyx/PersonalDetails';
9494
import type {Participant, ReportCollectionDataSet} from '@src/types/onyx/Report';
9595
import 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

Comments
 (0)