From df7ad223779703b3ea590233d07c529effaf8bb3 Mon Sep 17 00:00:00 2001
From: Matthew Booe <mirdaki@users.noreply.github.com>
Date: Thu, 16 May 2024 11:25:56 -0700
Subject: [PATCH] Fix amount filter to include both incoming and outgoing
 amounts (#2643)

* Update filter amount to filter incoming and outgoing transactions

* Add test and fix logic

* Added release note

* Update with linter fixes

* Update new ammount filter to apply to all ops

* Fix lint
---
 .../server/accounts/transaction-rules.test.ts | 52 +++++++++++++++++--
 .../src/server/accounts/transaction-rules.ts  | 25 +++++----
 upcoming-release-notes/2643.md                |  6 +++
 3 files changed, 69 insertions(+), 14 deletions(-)
 create mode 100644 upcoming-release-notes/2643.md

diff --git a/packages/loot-core/src/server/accounts/transaction-rules.test.ts b/packages/loot-core/src/server/accounts/transaction-rules.test.ts
index 367da4b57..d86140470 100644
--- a/packages/loot-core/src/server/accounts/transaction-rules.test.ts
+++ b/packages/loot-core/src/server/accounts/transaction-rules.test.ts
@@ -420,7 +420,23 @@ describe('Transaction rules', () => {
       account,
       payee: lowesId,
       notes: '',
-      amount: 124,
+      amount: 102,
+    });
+    await db.insertTransaction({
+      id: '6',
+      date: '2020-10-17',
+      account,
+      payee: krogerId,
+      notes: 'baz',
+      amount: -102,
+    });
+    await db.insertTransaction({
+      id: '7',
+      date: '2020-10-17',
+      account,
+      payee: krogerId,
+      notes: 'zaz',
+      amount: -101,
     });
 
     let transactions = await getMatchingTransactions([
@@ -438,6 +454,36 @@ describe('Transaction rules', () => {
     ]);
     expect(transactions.map(t => t.id)).toEqual(['1']);
 
+    transactions = await getMatchingTransactions([
+      { field: 'amount', op: 'is', value: 102 },
+    ]);
+    expect(transactions.map(t => t.id)).toEqual(['6', '5']);
+
+    transactions = await getMatchingTransactions([
+      { field: 'amount', op: 'isapprox', value: 102 },
+    ]);
+    expect(transactions.map(t => t.id)).toEqual(['6', '7', '4', '5']);
+
+    transactions = await getMatchingTransactions([
+      { field: 'amount', op: 'gt', value: 102 },
+    ]);
+    expect(transactions.map(t => t.id)).toEqual(['2', '3', '1']);
+
+    transactions = await getMatchingTransactions([
+      { field: 'amount', op: 'lt', value: 102 },
+    ]);
+    expect(transactions.map(t => t.id)).toEqual(['7', '4']);
+
+    transactions = await getMatchingTransactions([
+      { field: 'amount', op: 'gte', value: 102 },
+    ]);
+    expect(transactions.map(t => t.id)).toEqual(['6', '5', '2', '3', '1']);
+
+    transactions = await getMatchingTransactions([
+      { field: 'amount', op: 'lte', value: 102 },
+    ]);
+    expect(transactions.map(t => t.id)).toEqual(['6', '7', '4', '5']);
+
     transactions = await getMatchingTransactions([
       { field: 'notes', op: 'is', value: 'FooO' },
     ]);
@@ -461,7 +507,7 @@ describe('Transaction rules', () => {
     transactions = await getMatchingTransactions([
       { field: 'amount', op: 'gt', value: 300 },
     ]);
-    expect(transactions.map(t => t.id)).toEqual(['2', '1']);
+    expect(transactions.map(t => t.id)).toEqual(['2', '3', '1']);
 
     transactions = await getMatchingTransactions([
       { field: 'amount', op: 'gt', value: 400 },
@@ -490,7 +536,7 @@ describe('Transaction rules', () => {
     transactions = await getMatchingTransactions([
       { field: 'date', op: 'gt', value: '2020-10-10' },
     ]);
-    expect(transactions.map(t => t.id)).toEqual(['4', '5', '2', '3']);
+    expect(transactions.map(t => t.id)).toEqual(['6', '7', '4', '5', '2', '3']);
 
     // todo: isapprox
   });
diff --git a/packages/loot-core/src/server/accounts/transaction-rules.ts b/packages/loot-core/src/server/accounts/transaction-rules.ts
index 3119cdd69..144ae6670 100644
--- a/packages/loot-core/src/server/accounts/transaction-rules.ts
+++ b/packages/loot-core/src/server/accounts/transaction-rules.ts
@@ -335,22 +335,25 @@ export function conditionsToAQL(conditions, { recurDateBounds = 100 } = {}) {
 
     const apply = (field, op, value) => {
       if (type === 'number') {
+        const outflowQuery = {
+          $and: [
+            { amount: { $lt: 0 } },
+            { [field]: { $transform: '$neg', [op]: value } },
+          ],
+        };
+        const inflowQuery = {
+          $and: [{ amount: { $gt: 0 } }, { [field]: { [op]: value } }],
+        };
         if (options) {
           if (options.outflow) {
-            return {
-              $and: [
-                { amount: { $lt: 0 } },
-                { [field]: { $transform: '$neg', [op]: value } },
-              ],
-            };
+            return outflowQuery;
           } else if (options.inflow) {
-            return {
-              $and: [{ amount: { $gt: 0 } }, { [field]: { [op]: value } }],
-            };
+            return inflowQuery;
           }
         }
-
-        return { amount: { [op]: value } };
+        return {
+          $or: [outflowQuery, inflowQuery],
+        };
       } else if (type === 'string') {
         return { [field]: { $transform: '$lower', [op]: value } };
       } else if (type === 'date') {
diff --git a/upcoming-release-notes/2643.md b/upcoming-release-notes/2643.md
new file mode 100644
index 000000000..781e0c741
--- /dev/null
+++ b/upcoming-release-notes/2643.md
@@ -0,0 +1,6 @@
+---
+category: Bugfix
+authors: [mirdaki]
+---
+
+Fix amount filter to include both incoming and outgoing amounts.
-- 
GitLab