diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index 3682b28943dc..8f74ac4ae6df 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -97,13 +97,18 @@ function calculateAmount(numberOfSplits: number, total: number, currency: string * Calculate a split amount in backend cents from a percentage of the original amount. * - Clamps percentage to [0, 100] * - Preserves decimal precision in percentage (supports 0.1 precision) - * - Uses absolute value of the total amount (cents) + * - Preserves the sign of the original amount (negative amounts stay negative) */ function calculateSplitAmountFromPercentage(totalInCents: number, percentage: number): number { const totalAbs = Math.abs(totalInCents); // Clamp percentage to [0, 100] without rounding to preserve decimal precision const clamped = Math.min(100, Math.max(0, percentage)); - return Math.round((totalAbs * clamped) / 100); + const amount = Math.round((totalAbs * clamped) / 100); + // Return 0 for zero amounts to avoid -0 + if (amount === 0) { + return 0; + } + return totalInCents < 0 ? -amount : amount; } /** diff --git a/tests/unit/IOUUtilsTest.ts b/tests/unit/IOUUtilsTest.ts index a4d64034e77b..1032d4ba8d54 100644 --- a/tests/unit/IOUUtilsTest.ts +++ b/tests/unit/IOUUtilsTest.ts @@ -185,10 +185,20 @@ describe('IOUUtils', () => { expect(IOUUtils.calculateSplitAmountFromPercentage(8900, 7.7)).toBe(685); }); - test('Clamps percentage between 0 and 100 and uses absolute total', () => { + test('Clamps percentage between 0 and 100', () => { expect(IOUUtils.calculateSplitAmountFromPercentage(20000, -10)).toBe(0); expect(IOUUtils.calculateSplitAmountFromPercentage(20000, 150)).toBe(20000); - expect(IOUUtils.calculateSplitAmountFromPercentage(-20000, 25)).toBe(5000); + }); + + test('Preserves negative sign for negative amounts (negative expense splits)', () => { + // When the original transaction is negative, split amounts should also be negative + expect(IOUUtils.calculateSplitAmountFromPercentage(-20000, 25)).toBe(-5000); + expect(IOUUtils.calculateSplitAmountFromPercentage(-20000, 50)).toBe(-10000); + expect(IOUUtils.calculateSplitAmountFromPercentage(-10000, 33.3)).toBe(-3330); + // Edge case: 0% results in 0 amount (not -0) + expect(IOUUtils.calculateSplitAmountFromPercentage(-20000, 0)).toBe(0); + // Full amount should also be negative + expect(IOUUtils.calculateSplitAmountFromPercentage(-20000, 100)).toBe(-20000); }); });