From 28c68940214cf80d0a638ffb39794879b05fce21 Mon Sep 17 00:00:00 2001 From: Aidan Harbison <aharbis@users.noreply.github.com> Date: Fri, 24 Mar 2023 13:57:50 -0400 Subject: [PATCH] transaction-import: treat (amount) as -amount (#808) - When parsing an amount string, consider surrounding parentheses to mean the amount is negative. - Ensures all input to `parseFloat()` is sanitized. Closes: #807 --- packages/loot-core/src/shared/util.js | 16 ++++++++++++---- packages/loot-core/src/shared/util.test.js | 5 +++++ upcoming-release-notes/808.md | 6 ++++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 upcoming-release-notes/808.md diff --git a/packages/loot-core/src/shared/util.js b/packages/loot-core/src/shared/util.js index 1101c4212..484ccb321 100644 --- a/packages/loot-core/src/shared/util.js +++ b/packages/loot-core/src/shared/util.js @@ -377,15 +377,23 @@ export function looselyParseAmount(amount) { return isNaN(v) ? null : v; } + function extractNumbers(v) { + return v.replace(/[^0-9-]/g, ''); + } + + if (amount.startsWith('(') && amount.endsWith(')')) { + amount = amount.replace('(', '-').replace(')', ''); + } + let m = amount.match(/[.,][^.,]*$/); if (!m || m.index === 0) { - return safeNumber(parseFloat(amount)); + return safeNumber(parseFloat(extractNumbers(amount))); } - let left = amount.slice(0, m.index); - let right = amount.slice(m.index + 1); + let left = extractNumbers(amount.slice(0, m.index)); + let right = extractNumbers(amount.slice(m.index + 1)); - return safeNumber(parseFloat(left.replace(/[^0-9-]/g, '') + '.' + right)); + return safeNumber(parseFloat(left + '.' + right)); } export function semverToNumber(str) { diff --git a/packages/loot-core/src/shared/util.test.js b/packages/loot-core/src/shared/util.test.js index ebd52e0c0..afe3b3d7c 100644 --- a/packages/loot-core/src/shared/util.test.js +++ b/packages/loot-core/src/shared/util.test.js @@ -22,6 +22,11 @@ describe('utility functions', () => { expect(looselyParseAmount('-3,45')).toBe(-3.45); }); + test('looseParseAmount works with parentheses (negative)', () => { + expect(looselyParseAmount('(3.45)')).toBe(-3.45); + expect(looselyParseAmount('(3)')).toBe(-3); + }); + test('looseParseAmount ignores non-numeric characters', () => { // This is strange behavior because it does not work for just // `3_45_23` (it needs a decimal amount). This function should be diff --git a/upcoming-release-notes/808.md b/upcoming-release-notes/808.md new file mode 100644 index 000000000..9009e101d --- /dev/null +++ b/upcoming-release-notes/808.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [aharbis] +--- + +Import transactions with negative amounts represented as `(amount)` -- GitLab