diff --git a/packages/loot-core/src/server/accounts/sync.test.ts b/packages/loot-core/src/server/accounts/sync.test.ts index 1ea00a4d0a59605f4a08428a8e43e7c1abb8f487..13a9160a87669408ee286a2013efcbe7e858029e 100644 --- a/packages/loot-core/src/server/accounts/sync.test.ts +++ b/packages/loot-core/src/server/accounts/sync.test.ts @@ -342,4 +342,108 @@ describe('Account sync', () => { 'bakkerij-renamed', ]); }); + + test('reconcile does not merge transactions with different ‘imported_id’ values', async () => { + const { id } = await prepareDatabase(); + + let payees = await getAllPayees(); + expect(payees.length).toBe(0); + + // Add first transaction + await reconcileTransactions(id, [ + { + date: '2024-04-05', + amount: -1239, + imported_payee: 'Acme Inc.', + payee_name: 'Acme Inc.', + imported_id: 'b85cdd57-5a1c-4ca5-bd54-12e5b56fa02c', + notes: 'TEST TRANSACTION', + cleared: true, + }, + ]); + + payees = await getAllPayees(); + expect(payees.length).toBe(1); + + let transactions = await getAllTransactions(); + expect(transactions.length).toBe(1); + + // Add second transaction + await reconcileTransactions(id, [ + { + date: '2024-04-06', + amount: -1239, + imported_payee: 'Acme Inc.', + payee_name: 'Acme Inc.', + imported_id: 'ca1589b2-7bc3-4587-a157-476170b383a7', + notes: 'TEST TRANSACTION', + cleared: true, + }, + ]); + + payees = await getAllPayees(); + expect(payees.length).toBe(1); + + transactions = await getAllTransactions(); + expect(transactions.length).toBe(2); + + expect( + transactions.find( + t => t.imported_id === 'b85cdd57-5a1c-4ca5-bd54-12e5b56fa02c', + ).amount, + ).toBe(-1239); + expect( + transactions.find( + t => t.imported_id === 'ca1589b2-7bc3-4587-a157-476170b383a7', + ).amount, + ).toBe(-1239); + }); + + test( + 'given an imported tx with no imported_id, ' + + 'when an existing transaction that has an imported_id and matches amount and is within 7 days of imported tx,' + + 'then imported tx should reconcile with existing transaction from fuzzy match', + async () => { + const { id } = await prepareDatabase(); + + let payees = await getAllPayees(); + expect(payees.length).toBe(0); + + const existingTx = { + date: '2024-04-05', + amount: -1239, + imported_payee: 'Acme Inc.', + payee_name: 'Acme Inc.', + imported_id: 'b85cdd57-5a1c-4ca5-bd54-12e5b56fa02c', + notes: 'TEST TRANSACTION', + cleared: true, + }; + + // Add transaction to represent existing transaction with imoprted_id + await reconcileTransactions(id, [existingTx]); + + payees = await getAllPayees(); + expect(payees.length).toBe(1); + + let transactions = await getAllTransactions(); + expect(transactions.length).toBe(1); + + // Import transaction similar to existing but with different date and no imported_id + await reconcileTransactions(id, [ + { + ...existingTx, + date: '2024-04-06', + imported_id: null, + }, + ]); + + payees = await getAllPayees(); + expect(payees.length).toBe(1); + + transactions = await getAllTransactions(); + expect(transactions.length).toBe(1); + + expect(transactions[0].amount).toBe(-1239); + }, + ); }); diff --git a/packages/loot-core/src/server/accounts/sync.ts b/packages/loot-core/src/server/accounts/sync.ts index 39f48bcdbf357dfb52962285987b7cf18e8fc75f..2b96092040baec638a061cc38aea23aac5230ebd 100644 --- a/packages/loot-core/src/server/accounts/sync.ts +++ b/packages/loot-core/src/server/accounts/sync.ts @@ -399,8 +399,15 @@ export async function reconcileTransactions( // fields. fuzzyDataset = await db.all( `SELECT id, is_parent, date, imported_id, payee, category, notes, reconciled FROM v_transactions - WHERE date >= ? AND date <= ? AND amount = ? AND account = ?`, + WHERE + -- If both ids are set, and we didn't match earlier then skip dedup + ( imported_id IS NULL OR ? IS NULL ) + -- Look 7 days ahead, 7 days behind + AND date >= ? AND date <= ? AND amount = ? + AND account = ? + `, [ + trans.imported_id || null, db.toDateRepr(monthUtils.subDays(trans.date, 7)), db.toDateRepr(monthUtils.addDays(trans.date, 7)), trans.amount || 0, diff --git a/upcoming-release-notes/2770.md b/upcoming-release-notes/2770.md new file mode 100644 index 0000000000000000000000000000000000000000..3681a1e521dec7f682c40e3b408ba158e6889401 --- /dev/null +++ b/upcoming-release-notes/2770.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [ttlgeek, strazto, pmoon00] +--- + +Prevent transaction deduplication for imported transactions