From 310cc04a2bc220ee9e25573a95b4805932bde0c6 Mon Sep 17 00:00:00 2001
From: Matiss Janis Aboltins <matiss@mja.lv>
Date: Tue, 9 Apr 2024 07:06:04 +0100
Subject: [PATCH] :recycle: (bank-sync) unify the sync/reconciliation logic for
 internal & external sync (#2534)

---
 .../loot-core/src/client/actions/account.ts   |   20 -
 .../accounts/__snapshots__/sync.test.ts.snap  | 2503 -----------------
 .../loot-core/src/server/accounts/link.ts     |   50 +-
 .../src/server/accounts/sync.test.ts          |  284 +-
 .../loot-core/src/server/accounts/sync.ts     |  356 +--
 packages/loot-core/src/server/main.test.ts    |   58 -
 packages/loot-core/src/server/main.ts         |   65 +-
 .../loot-core/src/types/server-handlers.d.ts  |   14 -
 upcoming-release-notes/2534.md                |    6 +
 9 files changed, 66 insertions(+), 3290 deletions(-)
 create mode 100644 upcoming-release-notes/2534.md

diff --git a/packages/loot-core/src/client/actions/account.ts b/packages/loot-core/src/client/actions/account.ts
index f6448ce9e..0f31d3b4a 100644
--- a/packages/loot-core/src/client/actions/account.ts
+++ b/packages/loot-core/src/client/actions/account.ts
@@ -78,26 +78,6 @@ export function linkAccountSimpleFin(externalAccount, upgradingId) {
   };
 }
 
-// TODO: type correctly or remove (unused)
-export function connectAccounts(
-  institution,
-  publicToken,
-  accountIds,
-  offbudgetIds,
-) {
-  return async (dispatch: Dispatch) => {
-    const ids = await send('accounts-connect', {
-      institution,
-      publicToken,
-      accountIds,
-      offbudgetIds,
-    });
-    await dispatch(getPayees());
-    await dispatch(getAccounts());
-    return ids;
-  };
-}
-
 export function syncAccounts(id?: string) {
   return async (dispatch: Dispatch, getState: GetState) => {
     // Disallow two parallel sync operations
diff --git a/packages/loot-core/src/server/accounts/__snapshots__/sync.test.ts.snap b/packages/loot-core/src/server/accounts/__snapshots__/sync.test.ts.snap
index 53dec3886..0602bdc55 100644
--- a/packages/loot-core/src/server/accounts/__snapshots__/sync.test.ts.snap
+++ b/packages/loot-core/src/server/accounts/__snapshots__/sync.test.ts.snap
@@ -1,2508 +1,5 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`Account sync import never matches existing with financial ids 1`] = `
-Array [
-  Object {
-    "account": "one",
-    "amount": 8105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id18",
-    "imported_id": "5629ec0c-e559-49f4-9105-91d7b8b8738a",
-    "imported_payee": "Transaction 90",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id5",
-    "payee_name": "Transaction 90",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -473,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id22",
-    "imported_id": "45a2ad98-acbc-4120-a856-dec0839fa73c",
-    "imported_payee": "Transaction 54",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id9",
-    "payee_name": "Transaction 54",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1462,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id20",
-    "imported_id": "8791ca7e-5c19-4f23-bdf9-f60ee2a90081",
-    "imported_payee": "Transaction 79",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id7",
-    "payee_name": "Transaction 79",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4207,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id19",
-    "imported_id": "254ad9b3-23aa-4f70-b617-e126e054cc0e",
-    "imported_payee": "Transaction 3",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id6",
-    "payee_name": "Transaction 3",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5093,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id21",
-    "imported_id": "8e0ddc45-d545-4504-bed7-23c417a90f90",
-    "imported_payee": "Transaction 51",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id8",
-    "payee_name": "Transaction 51",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5938,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id23",
-    "imported_id": "00ab7e01-73f7-4da0-98f3-233f1dcc5b3e",
-    "imported_payee": "Transaction 68",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id10",
-    "payee_name": "Transaction 68",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 35884,
-    "category": "id2",
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id4",
-    "imported_id": null,
-    "imported_payee": null,
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id3",
-    "payee_name": "Starting Balance",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 1,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id25",
-    "imported_id": "6a764abf-69f4-47a6-94e1-638c7df0e245",
-    "imported_payee": "Transaction 64",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id12",
-    "payee_name": "Transaction 64",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3200,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id24",
-    "imported_id": "1b25b9df-8aa4-47c8-9792-75f4c38e351f",
-    "imported_payee": "Transaction 11",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id11",
-    "payee_name": "Transaction 11",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3342,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id28",
-    "imported_id": "f4b34ee3-6d5b-4625-bffc-057a72270140",
-    "imported_payee": "Transaction 48",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id15",
-    "payee_name": "Transaction 48",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3984,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id26",
-    "imported_id": "768b6d36-0ad7-47fb-a631-145170adc0b9",
-    "imported_payee": "Transaction 107",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id13",
-    "payee_name": "Transaction 107",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4524,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id30",
-    "imported_id": "f4e3a3f2-c20f-4667-8df6-6530bf5f4cb0",
-    "imported_payee": "Transaction 56",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id17",
-    "payee_name": "Transaction 56",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4881,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id27",
-    "imported_id": "ceb53daf-7318-4aee-a562-19a45654eaa7",
-    "imported_payee": "Transaction 28",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id14",
-    "payee_name": "Transaction 28",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5541,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id29",
-    "imported_id": "af2d6eba-f75e-4ee0-a9ad-5d9f8264797b",
-    "imported_payee": "Transaction 114",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id16",
-    "payee_name": "Transaction 114",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-]
-`;
-
-exports[`Account sync import never matches existing with financial ids 2`] = `
-"Snapshot Diff:
-- First value
-+ Second value
-
-@@ -68,10 +68,56 @@
-      \\"tombstone\\": 0,
-      \\"transfer_id\\": null,
-    },
-    Object {
-      \\"account\\": \\"one\\",
-+     \\"amount\\": -2947,
-+     \\"category\\": null,
-+     \\"cleared\\": 1,
-+     \\"date\\": 20171015,
-+     \\"error\\": null,
-+     \\"id\\": \\"one\\",
-+     \\"imported_id\\": \\"trans1\\",
-+     \\"imported_payee\\": null,
-+     \\"is_child\\": 0,
-+     \\"is_parent\\": 0,
-+     \\"notes\\": null,
-+     \\"parent_id\\": null,
-+     \\"payee\\": \\"id31\\",
-+     \\"payee_name\\": \\"foo\\",
-+     \\"reconciled\\": 0,
-+     \\"schedule\\": null,
-+     \\"sort_order\\": 123456789,
-+     \\"starting_balance_flag\\": 0,
-+     \\"tombstone\\": 0,
-+     \\"transfer_id\\": null,
-+   },
-+   Object {
-+     \\"account\\": \\"one\\",
-+     \\"amount\\": -2947,
-+     \\"category\\": null,
-+     \\"cleared\\": 1,
-+     \\"date\\": 20171015,
-+     \\"error\\": null,
-+     \\"id\\": \\"two\\",
-+     \\"imported_id\\": \\"trans2\\",
-+     \\"imported_payee\\": null,
-+     \\"is_child\\": 0,
-+     \\"is_parent\\": 0,
-+     \\"notes\\": null,
-+     \\"parent_id\\": null,
-+     \\"payee\\": \\"id32\\",
-+     \\"payee_name\\": \\"bar\\",
-+     \\"reconciled\\": 0,
-+     \\"schedule\\": null,
-+     \\"sort_order\\": 123456789,
-+     \\"starting_balance_flag\\": 0,
-+     \\"tombstone\\": 0,
-+     \\"transfer_id\\": null,
-+   },
-+   Object {
-+     \\"account\\": \\"one\\",
-      \\"amount\\": -4207,
-      \\"category\\": null,
-      \\"cleared\\": 1,
-      \\"date\\": 20171015,
-      \\"error\\": null,"
-`;
-
-exports[`Account sync import never matches existing with financial ids 3`] = `
-"Snapshot Diff:
-- First value
-+ Second value
-
-@@ -1,114 +1,160 @@
-  Array [
-    Object {
-      \\"account\\": \\"one\\",
--     \\"amount\\": 8105,
-+     \\"amount\\": -1865,
-+     \\"category\\": null,
-+     \\"cleared\\": 1,
-+     \\"date\\": 20171017,
-+     \\"error\\": null,
-+     \\"id\\": \\"id36\\",
-+     \\"imported_id\\": \\"622f7b61-a6be-4ce5-bd2f-50eb14c12f42\\",
-+     \\"imported_payee\\": \\"Transaction 53\\",
-+     \\"is_child\\": 0,
-+     \\"is_parent\\": 0,
-+     \\"notes\\": null,
-+     \\"parent_id\\": null,
-+     \\"payee\\": \\"id34\\",
-+     \\"payee_name\\": \\"Transaction 53\\",
-+     \\"reconciled\\": 0,
-+     \\"schedule\\": null,
-+     \\"sort_order\\": 123456789,
-+     \\"starting_balance_flag\\": 0,
-+     \\"tombstone\\": 0,
-+     \\"transfer_id\\": null,
-+   },
-+   Object {
-+     \\"account\\": \\"one\\",
-+     \\"amount\\": -2947,
-      \\"category\\": null,
-      \\"cleared\\": 1,
--     \\"date\\": 20171015,
-+     \\"date\\": 20171017,
-      \\"error\\": null,
--     \\"id\\": \\"id18\\",
--     \\"imported_id\\": \\"5629ec0c-e559-49f4-9105-91d7b8b8738a\\",
--     \\"imported_payee\\": \\"Transaction 90\\",
-+     \\"id\\": \\"one\\",
-+     \\"imported_id\\": \\"3591ad03-b705-42e0-945d-402a70371c49\\",
-+     \\"imported_payee\\": \\"foo\\",
-      \\"is_child\\": 0,
-      \\"is_parent\\": 0,
-      \\"notes\\": null,
-      \\"parent_id\\": null,
--     \\"payee\\": \\"id5\\",
--     \\"payee_name\\": \\"Transaction 90\\",
-+     \\"payee\\": \\"id31\\",
-+     \\"payee_name\\": \\"foo\\",
-      \\"reconciled\\": 0,
-      \\"schedule\\": null,
-      \\"sort_order\\": 123456789,
-      \\"starting_balance_flag\\": 0,
-      \\"tombstone\\": 0,
-      \\"transfer_id\\": null,
-    },
-    Object {
-      \\"account\\": \\"one\\",
--     \\"amount\\": -473,
-+     \\"amount\\": -2947,
-      \\"category\\": null,
-      \\"cleared\\": 1,
--     \\"date\\": 20171015,
-+     \\"date\\": 20171017,
-      \\"error\\": null,
--     \\"id\\": \\"id22\\",
--     \\"imported_id\\": \\"45a2ad98-acbc-4120-a856-dec0839fa73c\\",
--     \\"imported_payee\\": \\"Transaction 54\\",
-+     \\"id\\": \\"two\\",
-+     \\"imported_id\\": \\"01a3a594-a381-49d1-bcf8-331a3c410900\\",
-+     \\"imported_payee\\": \\"bar\\",
-      \\"is_child\\": 0,
-      \\"is_parent\\": 0,
-      \\"notes\\": null,
-      \\"parent_id\\": null,
--     \\"payee\\": \\"id9\\",
--     \\"payee_name\\": \\"Transaction 54\\",
-+     \\"payee\\": \\"id32\\",
-+     \\"payee_name\\": \\"bar\\",
-      \\"reconciled\\": 0,
-      \\"schedule\\": null,
-      \\"sort_order\\": 123456789,
-      \\"starting_balance_flag\\": 0,
-      \\"tombstone\\": 0,
-      \\"transfer_id\\": null,
-    },
-    Object {
-      \\"account\\": \\"one\\",
--     \\"amount\\": -1462,
-+     \\"amount\\": -2407,
-+     \\"category\\": null,
-+     \\"cleared\\": 1,
-+     \\"date\\": 20171016,
-+     \\"error\\": null,
-+     \\"id\\": \\"id35\\",
-+     \\"imported_id\\": \\"753911ce-7b09-4cb3-8447-ac6eb74e727e\\",
-+     \\"imported_payee\\": \\"Transaction 32\\",
-+     \\"is_child\\": 0,
-+     \\"is_parent\\": 0,
-+     \\"notes\\": null,
-+     \\"parent_id\\": null,
-+     \\"payee\\": \\"id33\\",
-+     \\"payee_name\\": \\"Transaction 32\\",
-+     \\"reconciled\\": 0,
-+     \\"schedule\\": null,
-+     \\"sort_order\\": 123456789,
-+     \\"starting_balance_flag\\": 0,
-+     \\"tombstone\\": 0,
-+     \\"transfer_id\\": null,
-+   },
-+   Object {
-+     \\"account\\": \\"one\\",
-+     \\"amount\\": 8105,
-      \\"category\\": null,
-      \\"cleared\\": 1,
-      \\"date\\": 20171015,
-      \\"error\\": null,
--     \\"id\\": \\"id20\\",
--     \\"imported_id\\": \\"8791ca7e-5c19-4f23-bdf9-f60ee2a90081\\",
--     \\"imported_payee\\": \\"Transaction 79\\",
-+     \\"id\\": \\"id18\\",
-+     \\"imported_id\\": \\"5629ec0c-e559-49f4-9105-91d7b8b8738a\\",
-+     \\"imported_payee\\": \\"Transaction 90\\",
-      \\"is_child\\": 0,
-      \\"is_parent\\": 0,
-      \\"notes\\": null,
-      \\"parent_id\\": null,
--     \\"payee\\": \\"id7\\",
--     \\"payee_name\\": \\"Transaction 79\\",
-+     \\"payee\\": \\"id5\\",
-+     \\"payee_name\\": \\"Transaction 90\\",
-      \\"reconciled\\": 0,
-      \\"schedule\\": null,
-      \\"sort_order\\": 123456789,
-      \\"starting_balance_flag\\": 0,
-      \\"tombstone\\": 0,
-      \\"transfer_id\\": null,
-    },
-    Object {
-      \\"account\\": \\"one\\",
--     \\"amount\\": -2947,
-+     \\"amount\\": -473,
-      \\"category\\": null,
-      \\"cleared\\": 1,
-      \\"date\\": 20171015,
-      \\"error\\": null,
--     \\"id\\": \\"one\\",
--     \\"imported_id\\": \\"trans1\\",
--     \\"imported_payee\\": null,
-+     \\"id\\": \\"id22\\",
-+     \\"imported_id\\": \\"45a2ad98-acbc-4120-a856-dec0839fa73c\\",
-+     \\"imported_payee\\": \\"Transaction 54\\",
-      \\"is_child\\": 0,
-      \\"is_parent\\": 0,
-      \\"notes\\": null,
-      \\"parent_id\\": null,
--     \\"payee\\": \\"id31\\",
--     \\"payee_name\\": \\"foo\\",
-+     \\"payee\\": \\"id9\\",
-+     \\"payee_name\\": \\"Transaction 54\\",
-      \\"reconciled\\": 0,
-      \\"schedule\\": null,
-      \\"sort_order\\": 123456789,
-      \\"starting_balance_flag\\": 0,
-      \\"tombstone\\": 0,
-      \\"transfer_id\\": null,
-    },
-    Object {
-      \\"account\\": \\"one\\",
--     \\"amount\\": -2947,
-+     \\"amount\\": -1462,
-      \\"category\\": null,
-      \\"cleared\\": 1,
-      \\"date\\": 20171015,
-      \\"error\\": null,
--     \\"id\\": \\"two\\",
--     \\"imported_id\\": \\"trans2\\",
--     \\"imported_payee\\": null,
-+     \\"id\\": \\"id20\\",
-+     \\"imported_id\\": \\"8791ca7e-5c19-4f23-bdf9-f60ee2a90081\\",
-+     \\"imported_payee\\": \\"Transaction 79\\",
-      \\"is_child\\": 0,
-      \\"is_parent\\": 0,
-      \\"notes\\": null,
-      \\"parent_id\\": null,
--     \\"payee\\": \\"id32\\",
--     \\"payee_name\\": \\"bar\\",
-+     \\"payee\\": \\"id7\\",
-+     \\"payee_name\\": \\"Transaction 79\\",
-      \\"reconciled\\": 0,
-      \\"schedule\\": null,
-      \\"sort_order\\": 123456789,
-      \\"starting_balance_flag\\": 0,
-      \\"tombstone\\": 0,"
-`;
-
-exports[`Account sync import updates transfers when matched 1`] = `
-Array [
-  Object {
-    "account": "one",
-    "amount": 8105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id18",
-    "imported_id": "5629ec0c-e559-49f4-9105-91d7b8b8738a",
-    "imported_payee": "Transaction 90",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id5",
-    "payee_name": "Transaction 90",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -473,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id22",
-    "imported_id": "45a2ad98-acbc-4120-a856-dec0839fa73c",
-    "imported_payee": "Transaction 54",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id9",
-    "payee_name": "Transaction 54",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1462,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id20",
-    "imported_id": "8791ca7e-5c19-4f23-bdf9-f60ee2a90081",
-    "imported_payee": "Transaction 79",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id7",
-    "payee_name": "Transaction 79",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4207,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id19",
-    "imported_id": "254ad9b3-23aa-4f70-b617-e126e054cc0e",
-    "imported_payee": "Transaction 3",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id6",
-    "payee_name": "Transaction 3",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5093,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id21",
-    "imported_id": "8e0ddc45-d545-4504-bed7-23c417a90f90",
-    "imported_payee": "Transaction 51",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id8",
-    "payee_name": "Transaction 51",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5938,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id23",
-    "imported_id": "00ab7e01-73f7-4da0-98f3-233f1dcc5b3e",
-    "imported_payee": "Transaction 68",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id10",
-    "payee_name": "Transaction 68",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 35884,
-    "category": "id2",
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id4",
-    "imported_id": null,
-    "imported_payee": null,
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id3",
-    "payee_name": "Starting Balance",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 1,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id25",
-    "imported_id": "6a764abf-69f4-47a6-94e1-638c7df0e245",
-    "imported_payee": "Transaction 64",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id12",
-    "payee_name": "Transaction 64",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3200,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id24",
-    "imported_id": "1b25b9df-8aa4-47c8-9792-75f4c38e351f",
-    "imported_payee": "Transaction 11",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id11",
-    "payee_name": "Transaction 11",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3342,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id28",
-    "imported_id": "f4b34ee3-6d5b-4625-bffc-057a72270140",
-    "imported_payee": "Transaction 48",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id15",
-    "payee_name": "Transaction 48",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3984,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id26",
-    "imported_id": "768b6d36-0ad7-47fb-a631-145170adc0b9",
-    "imported_payee": "Transaction 107",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id13",
-    "payee_name": "Transaction 107",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4524,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id30",
-    "imported_id": "f4e3a3f2-c20f-4667-8df6-6530bf5f4cb0",
-    "imported_payee": "Transaction 56",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id17",
-    "payee_name": "Transaction 56",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4881,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id27",
-    "imported_id": "ceb53daf-7318-4aee-a562-19a45654eaa7",
-    "imported_payee": "Transaction 28",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id14",
-    "payee_name": "Transaction 28",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5541,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id29",
-    "imported_id": "af2d6eba-f75e-4ee0-a9ad-5d9f8264797b",
-    "imported_payee": "Transaction 114",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id16",
-    "payee_name": "Transaction 114",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-]
-`;
-
-exports[`Account sync import updates transfers when matched 2`] = `
-"Snapshot Diff:
-- First value
-+ Second value
-
-@@ -21,10 +21,33 @@
-      \\"starting_balance_flag\\": 0,
-      \\"tombstone\\": 0,
-      \\"transfer_id\\": null,
-    },
-    Object {
-+     \\"account\\": \\"two\\",
-+     \\"amount\\": 2948,
-+     \\"category\\": null,
-+     \\"cleared\\": 1,
-+     \\"date\\": 20171015,
-+     \\"error\\": null,
-+     \\"id\\": \\"one\\",
-+     \\"imported_id\\": null,
-+     \\"imported_payee\\": null,
-+     \\"is_child\\": 0,
-+     \\"is_parent\\": 0,
-+     \\"notes\\": null,
-+     \\"parent_id\\": null,
-+     \\"payee\\": \\"transfer-one\\",
-+     \\"payee_name\\": \\"\\",
-+     \\"reconciled\\": 0,
-+     \\"schedule\\": null,
-+     \\"sort_order\\": 123456789,
-+     \\"starting_balance_flag\\": 0,
-+     \\"tombstone\\": 0,
-+     \\"transfer_id\\": \\"id31\\",
-+   },
-+   Object {
-      \\"account\\": \\"one\\",
-      \\"amount\\": -473,
-      \\"category\\": null,
-      \\"cleared\\": 1,
-      \\"date\\": 20171015,
-@@ -65,10 +88,33 @@
-      \\"schedule\\": null,
-      \\"sort_order\\": 123456789,
-      \\"starting_balance_flag\\": 0,
-      \\"tombstone\\": 0,
-      \\"transfer_id\\": null,
-+   },
-+   Object {
-+     \\"account\\": \\"one\\",
-+     \\"amount\\": -2948,
-+     \\"category\\": null,
-+     \\"cleared\\": 0,
-+     \\"date\\": 20171015,
-+     \\"error\\": null,
-+     \\"id\\": \\"id31\\",
-+     \\"imported_id\\": null,
-+     \\"imported_payee\\": null,
-+     \\"is_child\\": 0,
-+     \\"is_parent\\": 0,
-+     \\"notes\\": null,
-+     \\"parent_id\\": null,
-+     \\"payee\\": \\"transfer-two\\",
-+     \\"payee_name\\": \\"\\",
-+     \\"reconciled\\": 0,
-+     \\"schedule\\": null,
-+     \\"sort_order\\": 123456789,
-+     \\"starting_balance_flag\\": 0,
-+     \\"tombstone\\": 0,
-+     \\"transfer_id\\": \\"one\\",
-    },
-    Object {
-      \\"account\\": \\"one\\",
-      \\"amount\\": -4207,
-      \\"category\\": null,"
-`;
-
-exports[`Account sync import updates transfers when matched 3`] = `
-Array [
-  Object {
-    "account": "two",
-    "amount": 2948,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "one",
-    "imported_id": null,
-    "imported_payee": null,
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "transfer-one",
-    "payee_name": "",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": "id31",
-  },
-  Object {
-    "account": "one",
-    "amount": -1865,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id38",
-    "imported_id": "622f7b61-a6be-4ce5-bd2f-50eb14c12f42",
-    "imported_payee": "Transaction 53",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id35",
-    "payee_name": "Transaction 53",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -2948,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id31",
-    "imported_id": "3591ad03-b705-42e0-945d-402a70371c49",
-    "imported_payee": "#001 fenn st Macy’s 33333 EMX",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "transfer-two",
-    "payee_name": "",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": "one",
-  },
-  Object {
-    "account": "one",
-    "amount": -4911,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id37",
-    "imported_id": "01a3a594-a381-49d1-bcf8-331a3c410900",
-    "imported_payee": "Transaction 78",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id34",
-    "payee_name": "Transaction 78",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -2407,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id36",
-    "imported_id": "753911ce-7b09-4cb3-8447-ac6eb74e727e",
-    "imported_payee": "Transaction 32",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id32",
-    "payee_name": "Transaction 32",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 8105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id18",
-    "imported_id": "5629ec0c-e559-49f4-9105-91d7b8b8738a",
-    "imported_payee": "Transaction 90",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id5",
-    "payee_name": "Transaction 90",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -473,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id22",
-    "imported_id": "45a2ad98-acbc-4120-a856-dec0839fa73c",
-    "imported_payee": "Transaction 54",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id9",
-    "payee_name": "Transaction 54",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1462,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id20",
-    "imported_id": "8791ca7e-5c19-4f23-bdf9-f60ee2a90081",
-    "imported_payee": "Transaction 79",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id7",
-    "payee_name": "Transaction 79",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4207,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id19",
-    "imported_id": "254ad9b3-23aa-4f70-b617-e126e054cc0e",
-    "imported_payee": "Transaction 3",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id6",
-    "payee_name": "Transaction 3",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5093,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id21",
-    "imported_id": "8e0ddc45-d545-4504-bed7-23c417a90f90",
-    "imported_payee": "Transaction 51",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id8",
-    "payee_name": "Transaction 51",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5938,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id23",
-    "imported_id": "00ab7e01-73f7-4da0-98f3-233f1dcc5b3e",
-    "imported_payee": "Transaction 68",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id10",
-    "payee_name": "Transaction 68",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 35884,
-    "category": "id2",
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id4",
-    "imported_id": null,
-    "imported_payee": null,
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id3",
-    "payee_name": "Starting Balance",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 1,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id25",
-    "imported_id": "6a764abf-69f4-47a6-94e1-638c7df0e245",
-    "imported_payee": "Transaction 64",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id12",
-    "payee_name": "Transaction 64",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3200,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id24",
-    "imported_id": "1b25b9df-8aa4-47c8-9792-75f4c38e351f",
-    "imported_payee": "Transaction 11",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id11",
-    "payee_name": "Transaction 11",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3342,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id28",
-    "imported_id": "f4b34ee3-6d5b-4625-bffc-057a72270140",
-    "imported_payee": "Transaction 48",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id15",
-    "payee_name": "Transaction 48",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3984,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id26",
-    "imported_id": "768b6d36-0ad7-47fb-a631-145170adc0b9",
-    "imported_payee": "Transaction 107",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id13",
-    "payee_name": "Transaction 107",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4524,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id30",
-    "imported_id": "f4e3a3f2-c20f-4667-8df6-6530bf5f4cb0",
-    "imported_payee": "Transaction 56",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id17",
-    "payee_name": "Transaction 56",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4881,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id27",
-    "imported_id": "ceb53daf-7318-4aee-a562-19a45654eaa7",
-    "imported_payee": "Transaction 28",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id14",
-    "payee_name": "Transaction 28",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5541,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id29",
-    "imported_id": "af2d6eba-f75e-4ee0-a9ad-5d9f8264797b",
-    "imported_payee": "Transaction 114",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id16",
-    "payee_name": "Transaction 114",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-]
-`;
-
-exports[`Account sync imports transactions for current day and adds latest 1`] = `
-Array [
-  Object {
-    "account": "one",
-    "amount": 8105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id18",
-    "imported_id": "5629ec0c-e559-49f4-9105-91d7b8b8738a",
-    "imported_payee": "Transaction 90",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id5",
-    "payee_name": "Transaction 90",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -473,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id22",
-    "imported_id": "45a2ad98-acbc-4120-a856-dec0839fa73c",
-    "imported_payee": "Transaction 54",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id9",
-    "payee_name": "Transaction 54",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1462,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id20",
-    "imported_id": "8791ca7e-5c19-4f23-bdf9-f60ee2a90081",
-    "imported_payee": "Transaction 79",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id7",
-    "payee_name": "Transaction 79",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4207,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id19",
-    "imported_id": "254ad9b3-23aa-4f70-b617-e126e054cc0e",
-    "imported_payee": "Transaction 3",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id6",
-    "payee_name": "Transaction 3",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5093,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id21",
-    "imported_id": "8e0ddc45-d545-4504-bed7-23c417a90f90",
-    "imported_payee": "Transaction 51",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id8",
-    "payee_name": "Transaction 51",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5938,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id23",
-    "imported_id": "00ab7e01-73f7-4da0-98f3-233f1dcc5b3e",
-    "imported_payee": "Transaction 68",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id10",
-    "payee_name": "Transaction 68",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 35884,
-    "category": "id2",
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id4",
-    "imported_id": null,
-    "imported_payee": null,
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id3",
-    "payee_name": "Starting Balance",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 1,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id25",
-    "imported_id": "6a764abf-69f4-47a6-94e1-638c7df0e245",
-    "imported_payee": "Transaction 64",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id12",
-    "payee_name": "Transaction 64",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3200,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id24",
-    "imported_id": "1b25b9df-8aa4-47c8-9792-75f4c38e351f",
-    "imported_payee": "Transaction 11",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id11",
-    "payee_name": "Transaction 11",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3342,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id28",
-    "imported_id": "f4b34ee3-6d5b-4625-bffc-057a72270140",
-    "imported_payee": "Transaction 48",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id15",
-    "payee_name": "Transaction 48",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3984,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id26",
-    "imported_id": "768b6d36-0ad7-47fb-a631-145170adc0b9",
-    "imported_payee": "Transaction 107",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id13",
-    "payee_name": "Transaction 107",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4524,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id30",
-    "imported_id": "f4e3a3f2-c20f-4667-8df6-6530bf5f4cb0",
-    "imported_payee": "Transaction 56",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id17",
-    "payee_name": "Transaction 56",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4881,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id27",
-    "imported_id": "ceb53daf-7318-4aee-a562-19a45654eaa7",
-    "imported_payee": "Transaction 28",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id14",
-    "payee_name": "Transaction 28",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5541,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id29",
-    "imported_id": "af2d6eba-f75e-4ee0-a9ad-5d9f8264797b",
-    "imported_payee": "Transaction 114",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id16",
-    "payee_name": "Transaction 114",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-]
-`;
-
-exports[`Account sync imports transactions for current day and adds latest 2`] = `
-Array [
-  Object {
-    "account": "one",
-    "amount": -434,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id58",
-    "imported_id": "b89c446a-c425-4ce2-b3b9-251b3fbe1568",
-    "imported_payee": "Transaction 118",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id40",
-    "payee_name": "Transaction 118",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1865,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id51",
-    "imported_id": "622f7b61-a6be-4ce5-bd2f-50eb14c12f42",
-    "imported_payee": "Transaction 53",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id33",
-    "payee_name": "Transaction 53",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -2147,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id49",
-    "imported_id": "3591ad03-b705-42e0-945d-402a70371c49",
-    "imported_payee": "Transaction 13",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id31",
-    "payee_name": "Transaction 13",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -2947,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id54",
-    "imported_id": "d5ec5f37-2ac1-4b8d-b020-8eda39d4f61a",
-    "imported_payee": "Transaction 96",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id36",
-    "payee_name": "Transaction 96",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -2947,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id55",
-    "imported_id": "d5ec5f37-2ac1-4b8d-b020-8eda39d4f61a2",
-    "imported_payee": "Transaction Bazillion",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id37",
-    "payee_name": "Transaction Bazillion",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3170,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id59",
-    "imported_id": "aa69713d-f3ea-4914-a4fd-f04fcad242ba",
-    "imported_payee": "Transaction 89",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id41",
-    "payee_name": "Transaction 89",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3339,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id57",
-    "imported_id": "ade5fc3c-cce6-435e-9634-9e03c7876373",
-    "imported_payee": "Transaction 65",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id39",
-    "payee_name": "Transaction 65",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4911,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id50",
-    "imported_id": "01a3a594-a381-49d1-bcf8-331a3c410900",
-    "imported_payee": "Transaction 78",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id32",
-    "payee_name": "Transaction 78",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5391,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id56",
-    "imported_id": "8083e915-7eb0-4226-9514-2574e39ed333",
-    "imported_payee": "Transaction 49",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id38",
-    "payee_name": "Transaction 49",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5709,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id53",
-    "imported_id": "7f438a75-1ba3-40a0-a25b-689c8e720e31",
-    "imported_payee": "Transaction 100",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id35",
-    "payee_name": "Transaction 100",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5730,
-    "category": null,
-    "cleared": 1,
-    "date": 20171017,
-    "error": null,
-    "id": "id52",
-    "imported_id": "7b5a9df8-ca05-411b-82f9-4261b2df5b8c",
-    "imported_payee": "Transaction 115",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id34",
-    "payee_name": "Transaction 115",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 9675,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id63",
-    "imported_id": "4a907027-bed2-4f5d-ac67-b78fb14cead9",
-    "imported_payee": "Transaction 67",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id45",
-    "payee_name": "Transaction 67",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -2407,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id60",
-    "imported_id": "753911ce-7b09-4cb3-8447-ac6eb74e727e",
-    "imported_payee": "Transaction 32",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id42",
-    "payee_name": "Transaction 32",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3006,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id65",
-    "imported_id": "14ea70a2-511f-4797-92ae-81772acedf86",
-    "imported_payee": "Transaction 20",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id47",
-    "payee_name": "Transaction 20",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3935,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id64",
-    "imported_id": "5568650a-db53-43ce-9812-2755e8c7ca62",
-    "imported_payee": "Transaction 14",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id46",
-    "payee_name": "Transaction 14",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3987,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id62",
-    "imported_id": "831051b1-5d93-4df8-ab04-dd69615cd001",
-    "imported_payee": "Transaction 6",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id44",
-    "payee_name": "Transaction 6",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4837,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id61",
-    "imported_id": "e1f42f2d-ab97-468c-a859-df571e858896",
-    "imported_payee": "Transaction 119",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id43",
-    "payee_name": "Transaction 119",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4936,
-    "category": null,
-    "cleared": 1,
-    "date": 20171016,
-    "error": null,
-    "id": "id66",
-    "imported_id": "86c867c2-6d44-4556-84e7-015226144a7d",
-    "imported_payee": "Transaction 21",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id48",
-    "payee_name": "Transaction 21",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 8105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id18",
-    "imported_id": "5629ec0c-e559-49f4-9105-91d7b8b8738a",
-    "imported_payee": "Transaction 90",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id5",
-    "payee_name": "Transaction 90",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -473,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id22",
-    "imported_id": "45a2ad98-acbc-4120-a856-dec0839fa73c",
-    "imported_payee": "Transaction 54",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id9",
-    "payee_name": "Transaction 54",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1462,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id20",
-    "imported_id": "8791ca7e-5c19-4f23-bdf9-f60ee2a90081",
-    "imported_payee": "Transaction 79",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id7",
-    "payee_name": "Transaction 79",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4207,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id19",
-    "imported_id": "254ad9b3-23aa-4f70-b617-e126e054cc0e",
-    "imported_payee": "Transaction 3",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id6",
-    "payee_name": "Transaction 3",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5093,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id21",
-    "imported_id": "8e0ddc45-d545-4504-bed7-23c417a90f90",
-    "imported_payee": "Transaction 51",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id8",
-    "payee_name": "Transaction 51",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5938,
-    "category": null,
-    "cleared": 1,
-    "date": 20171015,
-    "error": null,
-    "id": "id23",
-    "imported_id": "00ab7e01-73f7-4da0-98f3-233f1dcc5b3e",
-    "imported_payee": "Transaction 68",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id10",
-    "payee_name": "Transaction 68",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": 35884,
-    "category": "id2",
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id4",
-    "imported_id": null,
-    "imported_payee": null,
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id3",
-    "payee_name": "Starting Balance",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 1,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -1105,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id25",
-    "imported_id": "6a764abf-69f4-47a6-94e1-638c7df0e245",
-    "imported_payee": "Transaction 64",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id12",
-    "payee_name": "Transaction 64",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3200,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id24",
-    "imported_id": "1b25b9df-8aa4-47c8-9792-75f4c38e351f",
-    "imported_payee": "Transaction 11",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id11",
-    "payee_name": "Transaction 11",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3342,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id28",
-    "imported_id": "f4b34ee3-6d5b-4625-bffc-057a72270140",
-    "imported_payee": "Transaction 48",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id15",
-    "payee_name": "Transaction 48",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -3984,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id26",
-    "imported_id": "768b6d36-0ad7-47fb-a631-145170adc0b9",
-    "imported_payee": "Transaction 107",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id13",
-    "payee_name": "Transaction 107",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4524,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id30",
-    "imported_id": "f4e3a3f2-c20f-4667-8df6-6530bf5f4cb0",
-    "imported_payee": "Transaction 56",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id17",
-    "payee_name": "Transaction 56",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -4881,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id27",
-    "imported_id": "ceb53daf-7318-4aee-a562-19a45654eaa7",
-    "imported_payee": "Transaction 28",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id14",
-    "payee_name": "Transaction 28",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-  Object {
-    "account": "one",
-    "amount": -5541,
-    "category": null,
-    "cleared": 1,
-    "date": 20171014,
-    "error": null,
-    "id": "id29",
-    "imported_id": "af2d6eba-f75e-4ee0-a9ad-5d9f8264797b",
-    "imported_payee": "Transaction 114",
-    "is_child": 0,
-    "is_parent": 0,
-    "notes": null,
-    "parent_id": null,
-    "payee": "id16",
-    "payee_name": "Transaction 114",
-    "reconciled": 0,
-    "schedule": null,
-    "sort_order": 123456789,
-    "starting_balance_flag": 0,
-    "tombstone": 0,
-    "transfer_id": null,
-  },
-]
-`;
-
 exports[`Account sync reconcile handles transactions with undefined fields 1`] = `
 Array [
   Object {
diff --git a/packages/loot-core/src/server/accounts/link.ts b/packages/loot-core/src/server/accounts/link.ts
index ff2618af8..2f7282c5c 100644
--- a/packages/loot-core/src/server/accounts/link.ts
+++ b/packages/loot-core/src/server/accounts/link.ts
@@ -63,48 +63,6 @@ export async function findOrCreateBank(institution, requisitionId) {
   return bankData;
 }
 
-export async function addAccounts(bankId, accountIds, offbudgetIds = []) {
-  const [[, userId], [, userKey]] = await asyncStorage.multiGet([
-    'user-id',
-    'user-key',
-  ]);
-
-  // Get all the available accounts
-  let accounts = await bankSync.getAccounts(userId, userKey, bankId);
-
-  // Only add the selected accounts
-  accounts = accounts.filter(acct => accountIds.includes(acct.account_id));
-
-  return Promise.all(
-    accounts.map(async acct => {
-      const id = await runMutator(async () => {
-        const id = await db.insertAccount({
-          account_id: acct.account_id,
-          name: acct.name,
-          official_name: acct.official_name,
-          balance_current: amountToInteger(acct.balances.current),
-          mask: acct.mask,
-          bank: bankId,
-          offbudget: offbudgetIds.includes(acct.account_id) ? 1 : 0,
-        });
-
-        // Create a transfer payee
-        await db.insertPayee({
-          name: '',
-          transfer_acct: id,
-        });
-
-        return id;
-      });
-
-      // Do an initial sync
-      await bankSync.syncAccount(userId, userKey, id, acct.account_id, bankId);
-
-      return id;
-    }),
-  );
-}
-
 export async function addGoCardlessAccounts(
   bankId,
   accountIds,
@@ -144,13 +102,7 @@ export async function addGoCardlessAccounts(
       });
 
       // Do an initial sync
-      await bankSync.syncExternalAccount(
-        userId,
-        userKey,
-        id,
-        acct.account_id,
-        bankId,
-      );
+      await bankSync.syncAccount(userId, userKey, id, acct.account_id, bankId);
 
       return id;
     }),
diff --git a/packages/loot-core/src/server/accounts/sync.test.ts b/packages/loot-core/src/server/accounts/sync.test.ts
index e6aaae936..0c8c9e8e1 100644
--- a/packages/loot-core/src/server/accounts/sync.test.ts
+++ b/packages/loot-core/src/server/accounts/sync.test.ts
@@ -1,24 +1,12 @@
 // @ts-strict-ignore
-import snapshotDiff from 'snapshot-diff';
-
 import * as monthUtils from '../../shared/months';
 import * as db from '../db';
 import { loadMappings } from '../db/mappings';
 import { post } from '../post';
 import { getServer } from '../server-config';
-import * as mockSyncServer from '../tests/mockSyncServer';
-
-import {
-  syncAccount,
-  reconcileTransactions,
-  addTransactions,
-  fromPlaid,
-} from './sync';
-import { loadRules, insertRule } from './transaction-rules';
-import * as transfer from './transfer';
 
-const papaJohns = 'Papa Johns east side';
-const lowes = 'Lowe’s Store';
+import { reconcileTransactions, addTransactions } from './sync';
+import { loadRules, insertRule } from './transaction-rules';
 
 jest.mock('../../shared/months', () => ({
   ...jest.requireActual('../../shared/months'),
@@ -27,7 +15,6 @@ jest.mock('../../shared/months', () => ({
 }));
 
 beforeEach(async () => {
-  mockSyncServer.reset();
   jest.resetAllMocks();
   (monthUtils.currentDay as jest.Mock).mockReturnValue('2017-10-15');
   (monthUtils.currentMonth as jest.Mock).mockReturnValue('2017-10');
@@ -46,37 +33,6 @@ function getAllTransactions() {
   );
 }
 
-function expectSnapshotWithDiffer(initialValue) {
-  let currentValue = initialValue;
-  expect(initialValue).toMatchSnapshot();
-  return {
-    expectToMatchDiff: value => {
-      expect(snapshotDiff(currentValue, value)).toMatchSnapshot();
-      currentValue = value;
-    },
-  };
-}
-
-function prepMockTransactions() {
-  let mockTransactions;
-  mockSyncServer.filterMockData(data => {
-    const account_id = data.accounts[0].account_id;
-    const transactions = data.transactions[account_id].filter(t => !t.pending);
-
-    mockTransactions = [
-      ...transactions.filter(t => t.date <= '2017-10-15'),
-      ...transactions.filter(t => t.date === '2017-10-16').slice(0, 1),
-      ...transactions.filter(t => t.date === '2017-10-17').slice(0, 3),
-    ];
-
-    return {
-      accounts: data.accounts,
-      transactions: { [account_id]: mockTransactions },
-    };
-  });
-  return mockTransactions;
-}
-
 async function prepareDatabase() {
   await db.insertCategoryGroup({ id: 'group1', name: 'group1', is_income: 1 });
   await db.insertCategory({
@@ -136,229 +92,6 @@ describe('Account sync', () => {
     );
   });
 
-  test('reconcile matches single transaction', async () => {
-    const mockTransactions = prepMockTransactions();
-    const { id, account_id } = await prepareDatabase();
-
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-
-    // The payee can be anything, all that matters is the amount is the same
-    const mockTransaction = mockTransactions.find(t => t.date === '2017-10-17');
-    mockTransaction.amount = 29.47;
-
-    const payeeId = await db.insertPayee({ name: 'macy' });
-    await db.insertTransaction({
-      id: 'one',
-      account: id,
-      amount: -2947,
-      date: '2017-10-15',
-      payee: payeeId,
-    });
-
-    const { added, updated } = await reconcileTransactions(
-      id,
-      mockTransactions.filter(t => t.date >= '2017-10-15').map(fromPlaid),
-    );
-
-    expect(added.length).toBe(3);
-    expect(updated.length).toBe(1);
-
-    const transactions = await getAllTransactions();
-    const transaction = transactions.find(t => t.amount === -2947);
-    expect(transaction.id).toBe(updated[0]);
-
-    // The payee has not been updated - it's still the payee that the original transaction had
-    const payees = await getAllPayees();
-    expect(payees.length).toBe(18);
-    expect(transaction.payee).toBe(payeeId);
-  });
-
-  test('reconcile matches multiple transactions', async () => {
-    const mockTransactions = prepMockTransactions();
-    const { id, account_id } = await prepareDatabase();
-
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-
-    // These should all match, but note that the one with the payee
-    // `macy` should match with the imported one with the same payee
-    // name. This should happen even though other transactions with
-    // the same amount are imported first, i.e. high fidelity matches
-    // always win
-    const mocked = mockTransactions.filter(t => t.date === '2017-10-17');
-    mocked[0].name = papaJohns;
-    mocked[0].amount = 29.47;
-    mocked[1].name = 'Lowe’s Store';
-    mocked[1].amount = 29.47;
-    mocked[2].name = 'macy';
-    mocked[2].amount = 29.47;
-
-    // Make sure that it macy is correctly matched from a different
-    // day first, and then the other two are matched based on amount.
-    // And it should never match the same transactions twice
-    await db.insertTransaction({
-      id: 'one',
-      account: id,
-      amount: -2947,
-      date: '2017-10-15',
-      payee: await db.insertPayee({ name: 'papa johns' }),
-    });
-    await db.insertTransaction({
-      id: 'two',
-      account: id,
-      amount: -2947,
-      date: '2017-10-17',
-      payee: await db.insertPayee({ name: 'lowes' }),
-    });
-    await db.insertTransaction({
-      id: 'three',
-      account: id,
-      amount: -2947,
-      date: '2017-10-17',
-      payee: await db.insertPayee({ name: 'macy' }),
-    });
-
-    const { added, updated } = await reconcileTransactions(
-      id,
-      mockTransactions.filter(t => t.date >= '2017-10-15').map(fromPlaid),
-    );
-
-    const transactions = await getAllTransactions();
-    expect(updated.length).toBe(3);
-    expect(added.length).toBe(1);
-
-    expect(transactions.find(t => t.id === 'one').imported_id).toBe(
-      mocked[1].transaction_id,
-    );
-    expect(transactions.find(t => t.id === 'two').imported_id).toBe(
-      mocked[0].transaction_id,
-    );
-    expect(transactions.find(t => t.id === 'three').imported_id).toBe(
-      mocked[2].transaction_id,
-    );
-  });
-
-  test('reconcile matches multiple transactions (imported_id wins)', async () => {
-    const mockTransactions = prepMockTransactions();
-    const { id, account_id } = await prepareDatabase();
-
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-
-    const mocked = mockTransactions.filter(t => t.date === '2017-10-17');
-    mocked[0].name = papaJohns;
-    mocked[0].amount = 29.47;
-    mocked[1].name = lowes;
-    mocked[1].amount = 29.47;
-    mocked[1].transaction_id = 'imported1';
-
-    // Technically, the amount doesn't even matter. The
-    // imported_id will always match no matter what
-    await db.insertTransaction({
-      id: 'one',
-      account: id,
-      amount: -3000,
-      date: '2017-10-15',
-      imported_id: 'imported1',
-      payee: await db.insertPayee({ name: 'papa johns' }),
-    });
-    await db.insertTransaction({
-      id: 'two',
-      account: id,
-      amount: -2947,
-      date: '2017-10-17',
-      payee: await db.insertPayee({ name: 'lowes' }),
-    });
-
-    const { added, updated } = await reconcileTransactions(
-      id,
-      mockTransactions.filter(t => t.date >= '2017-10-15').map(fromPlaid),
-    );
-
-    const transactions = await getAllTransactions();
-    expect(updated).toEqual(['two', 'one']);
-    expect(added.length).toBe(2);
-
-    // Make sure lowes, which has the imported_id, is the one that
-    // got matched with the same imported_id
-    expect(transactions.find(t => t.id === 'one').imported_payee).toBe(lowes);
-  });
-
-  test('import never matches existing with financial ids', async () => {
-    let mockTransactions = prepMockTransactions();
-    const { id, account_id } = await prepareDatabase();
-
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-    const differ = expectSnapshotWithDiffer(await getAllTransactions());
-
-    mockTransactions = mockTransactions.filter(t => t.date === '2017-10-17');
-    mockTransactions[0].name = 'foo';
-    mockTransactions[0].amount = 29.47;
-    mockTransactions[1].name = 'bar';
-    mockTransactions[1].amount = 29.47;
-
-    // Make sure, no matter what, it never tries to match with an
-    // existing transaction that already has a financial id
-    await db.insertTransaction({
-      id: 'one',
-      account: id,
-      amount: -2947,
-      date: '2017-10-15',
-      payee: await db.insertPayee({ name: 'foo' }),
-      imported_id: 'trans1',
-    });
-
-    await db.insertTransaction({
-      id: 'two',
-      account: id,
-      amount: -2947,
-      date: '2017-10-15',
-      payee: await db.insertPayee({ name: 'bar' }),
-      imported_id: 'trans2',
-    });
-
-    differ.expectToMatchDiff(await getAllTransactions());
-
-    (monthUtils.currentDay as jest.Mock).mockReturnValue('2017-10-17');
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-
-    differ.expectToMatchDiff(await getAllTransactions());
-  });
-
-  test('import updates transfers when matched', async () => {
-    const mockTransactions = prepMockTransactions();
-    const { id, account_id } = await prepareDatabase();
-    await db.insertAccount({ id: 'two', name: 'two' });
-    await db.insertPayee({
-      id: 'transfer-two',
-      name: '',
-      transfer_acct: 'two',
-    });
-
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-    const differ = expectSnapshotWithDiffer(await getAllTransactions());
-
-    const mockTransaction = mockTransactions.find(t => t.date === '2017-10-17');
-    mockTransaction.name = '#001 fenn st Macy’s 33333 EMX';
-    mockTransaction.amount = 29.48;
-
-    const transactionId = await db.insertTransaction({
-      id: 'one',
-      account: 'two',
-      amount: 2948,
-      date: '2017-10-15',
-      payee: 'transfer-' + id,
-    });
-    await transfer.onInsert(await db.getTransaction(transactionId));
-
-    differ.expectToMatchDiff(await getAllTransactions());
-
-    (monthUtils.currentDay as jest.Mock).mockReturnValue('2017-10-17');
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-
-    // Don't use `differ.expectToMatchDiff` because there's too many
-    // changes that look too confusing
-    expect(await getAllTransactions()).toMatchSnapshot();
-  });
-
   test('reconcile handles transactions with undefined fields', async () => {
     const { id: acctId } = await prepareDatabase();
 
@@ -609,17 +342,4 @@ describe('Account sync', () => {
       'bakkerij-renamed',
     ]);
   });
-
-  test('imports transactions for current day and adds latest', async () => {
-    const { id, account_id } = await prepareDatabase();
-
-    expect((await getAllTransactions()).length).toBe(0);
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-    expect(await getAllTransactions()).toMatchSnapshot();
-
-    (monthUtils.currentDay as jest.Mock).mockReturnValue('2017-10-17');
-
-    await syncAccount('userId', 'userKey', id, account_id, 'bank');
-    expect(await getAllTransactions()).toMatchSnapshot();
-  });
 });
diff --git a/packages/loot-core/src/server/accounts/sync.ts b/packages/loot-core/src/server/accounts/sync.ts
index 494759b72..03bd3fb9d 100644
--- a/packages/loot-core/src/server/accounts/sync.ts
+++ b/packages/loot-core/src/server/accounts/sync.ts
@@ -328,7 +328,7 @@ async function normalizeTransactions(
   return { normalized, payeesToCreate };
 }
 
-async function normalizeExternalTransactions(transactions, acctId) {
+async function normalizeBankSyncTransactions(transactions, acctId) {
   const payeesToCreate = new Map();
 
   const normalized = [];
@@ -437,14 +437,22 @@ async function createNewPayees(payeesToCreate, addsAndUpdates) {
   });
 }
 
-export async function reconcileExternalTransactions(acctId, transactions) {
+export async function reconcileTransactions(
+  acctId,
+  transactions,
+  isBankSyncAccount = false,
+) {
   console.log('Performing transaction reconciliation');
 
   const hasMatched = new Set();
   const updated = [];
   const added = [];
 
-  const { normalized, payeesToCreate } = await normalizeExternalTransactions(
+  const transactionNormalization = isBankSyncAccount
+    ? normalizeBankSyncTransactions
+    : normalizeTransactions;
+
+  const { normalized, payeesToCreate } = await transactionNormalization(
     transactions,
     acctId,
   );
@@ -575,6 +583,7 @@ export async function reconcileExternalTransactions(acctId, transactions) {
 
       // Update the transaction
       const updates = {
+        ...(isBankSyncAccount ? {} : { date: trans.date }),
         imported_id: trans.imported_id || null,
         payee: existing.payee || trans.payee || null,
         category: existing.category || trans.category || null,
@@ -630,190 +639,6 @@ export async function reconcileExternalTransactions(acctId, transactions) {
   };
 }
 
-export async function reconcileTransactions(acctId, transactions) {
-  const hasMatched = new Set();
-  const updated = [];
-  const added = [];
-
-  const { normalized, payeesToCreate } = await normalizeTransactions(
-    transactions,
-    acctId,
-  );
-
-  // The first pass runs the rules, and preps data for fuzzy matching
-  const transactionsStep1 = [];
-  for (const {
-    payee_name,
-    trans: originalTrans,
-    subtransactions,
-  } of normalized) {
-    // Run the rules
-    const trans = runRules(originalTrans);
-
-    let match = null;
-    let fuzzyDataset = null;
-
-    // First, match with an existing transaction's imported_id. This
-    // is the highest fidelity match and should always be attempted
-    // first.
-    if (trans.imported_id) {
-      match = await db.first(
-        'SELECT * FROM v_transactions WHERE imported_id = ? AND account = ?',
-        [trans.imported_id, acctId],
-      );
-
-      if (match) {
-        hasMatched.add(match.id);
-      }
-    }
-
-    // If it didn't match, query data needed for fuzzy matching
-    if (!match) {
-      // Look 7 days ahead and 7 days back when fuzzy matching. This
-      // needs to select all fields that need to be read from the
-      // matched transaction. See the final pass below for the needed
-      // 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 = ?`,
-        [
-          db.toDateRepr(monthUtils.subDays(trans.date, 7)),
-          db.toDateRepr(monthUtils.addDays(trans.date, 7)),
-          trans.amount || 0,
-          acctId,
-        ],
-      );
-
-      // Sort the matched transactions according to the distance from the original
-      // transactions date. i.e. if the original transaction is in 21-02-2024 and
-      // the matched transactions are: 20-02-2024, 21-02-2024, 29-02-2024 then
-      // the resulting data-set should be: 21-02-2024, 20-02-2024, 29-02-2024.
-      fuzzyDataset = fuzzyDataset.sort((a, b) => {
-        const aDistance = Math.abs(
-          dateFns.differenceInMilliseconds(
-            dateFns.parseISO(trans.date),
-            dateFns.parseISO(db.fromDateRepr(a.date)),
-          ),
-        );
-        const bDistance = Math.abs(
-          dateFns.differenceInMilliseconds(
-            dateFns.parseISO(trans.date),
-            dateFns.parseISO(db.fromDateRepr(b.date)),
-          ),
-        );
-        return aDistance > bDistance ? 1 : -1;
-      });
-    }
-
-    transactionsStep1.push({
-      payee_name,
-      trans,
-      subtransactions: trans.subtransactions || subtransactions,
-      match,
-      fuzzyDataset,
-    });
-  }
-
-  // Next, do the fuzzy matching. This first pass matches based on the
-  // payee id. We do this in multiple passes so that higher fidelity
-  // matching always happens first, i.e. a transaction should match
-  // match with low fidelity if a later transaction is going to match
-  // the same one with high fidelity.
-  const transactionsStep2 = transactionsStep1.map(data => {
-    if (!data.match && data.fuzzyDataset) {
-      // Try to find one where the payees match.
-      const match = data.fuzzyDataset.find(
-        row => !hasMatched.has(row.id) && data.trans.payee === row.payee,
-      );
-
-      if (match) {
-        hasMatched.add(match.id);
-        return { ...data, match };
-      }
-    }
-    return data;
-  });
-
-  // The final fuzzy matching pass. This is the lowest fidelity
-  // matching: it just find the first transaction that hasn't been
-  // matched yet. Remember the dataset only contains transactions
-  // around the same date with the same amount.
-  const transactionsStep3 = transactionsStep2.map(data => {
-    if (!data.match && data.fuzzyDataset) {
-      const match = data.fuzzyDataset.find(row => !hasMatched.has(row.id));
-      if (match) {
-        hasMatched.add(match.id);
-        return { ...data, match };
-      }
-    }
-    return data;
-  });
-
-  // Finally, generate & commit the changes
-  for (const { trans, subtransactions, match } of transactionsStep3) {
-    if (match) {
-      // Skip updating already reconciled (locked) transactions
-      if (match.reconciled) {
-        continue;
-      }
-
-      // TODO: change the above sql query to use aql
-      const existing = {
-        ...match,
-        cleared: match.cleared === 1,
-        date: db.fromDateRepr(match.date),
-      };
-
-      // Update the transaction
-      const updates = {
-        date: trans.date,
-        imported_id: trans.imported_id || null,
-        payee: existing.payee || trans.payee || null,
-        category: existing.category || trans.category || null,
-        imported_payee: trans.imported_payee || null,
-        notes: existing.notes || trans.notes || null,
-        cleared: trans.cleared != null ? trans.cleared : true,
-      };
-
-      if (hasFieldsChanged(existing, updates, Object.keys(updates))) {
-        updated.push({ id: existing.id, ...updates });
-      }
-
-      if (existing.is_parent && existing.cleared !== updates.cleared) {
-        const children = await db.all(
-          'SELECT id FROM v_transactions WHERE parent_id = ?',
-          [existing.id],
-        );
-        for (const child of children) {
-          updated.push({ id: child.id, cleared: updates.cleared });
-        }
-      }
-    } else {
-      // Insert a new transaction
-      const finalTransaction = {
-        ...trans,
-        id: uuidv4(),
-        category: trans.category || null,
-        cleared: trans.cleared != null ? trans.cleared : true,
-      };
-
-      if (subtransactions && subtransactions.length > 0) {
-        added.push(...makeSplitTransaction(finalTransaction, subtransactions));
-      } else {
-        added.push(finalTransaction);
-      }
-    }
-  }
-
-  await createNewPayees(payeesToCreate, [...added, ...updated]);
-  await batchUpdateTransactions({ added, updated });
-
-  return {
-    added: added.map(trans => trans.id),
-    updated: updated.map(trans => trans.id),
-  };
-}
-
 // This is similar to `reconcileTransactions` except much simpler: it
 // does not try to match any transactions. It just adds them
 export async function addTransactions(
@@ -872,7 +697,13 @@ export async function addTransactions(
   return newTransactions;
 }
 
-export async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
+export async function syncAccount(
+  userId: string,
+  userKey: string,
+  id: string,
+  acctId: string,
+  bankId: string,
+) {
   // TODO: Handle the case where transactions exist in the future
   // (that will make start date after end date)
   const latestTransaction = await db.first(
@@ -887,9 +718,8 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
       'SELECT date FROM v_transactions WHERE account = ? ORDER BY date ASC LIMIT 1',
       [id],
     );
-    const startingDate = monthUtils.parseDate(
-      db.fromDateRepr(startingTransaction.date),
-    );
+    const startingDate = db.fromDateRepr(startingTransaction.date);
+    // assert(startingTransaction)
 
     const startDate = monthUtils.dayFromDate(
       dateFns.max([
@@ -898,7 +728,7 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
         monthUtils.parseDate(monthUtils.subDays(monthUtils.currentDay(), 90)),
 
         // Never download transactions before the starting date.
-        startingDate,
+        monthUtils.parseDate(startingDate),
       ]),
     );
 
@@ -914,6 +744,31 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
         bankId,
         startDate,
       );
+    } else {
+      // Get all transactions since the latest transaction, plus any 5
+      // days before the latest transaction. This gives us a chance to
+      // resolve any transactions that were entered manually.
+      //
+      // TODO: What this really should do is query the last imported_id
+      // and since then
+      let date = monthUtils.subDays(
+        db.fromDateRepr(latestTransaction.date),
+        31,
+      );
+
+      // Never download transactions before the starting date. This was
+      // when the account was added to the system.
+      if (date < startingDate) {
+        date = startingDate;
+      }
+
+      download = await downloadTransactions(
+        userId,
+        userKey,
+        acctId,
+        bankId,
+        date,
+      );
     }
 
     const { transactions: originalTransactions, accountBalance } = download;
@@ -928,16 +783,16 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
     }));
 
     return runMutator(async () => {
-      const result = await reconcileExternalTransactions(id, transactions);
+      const result = await reconcileTransactions(id, transactions, true);
       await updateAccountBalance(id, accountBalance);
       return result;
     });
   } else {
+    let download;
+
     // Otherwise, download transaction for the past 90 days
     const startingDay = monthUtils.subDays(monthUtils.currentDay(), 90);
 
-    let download;
-
     if (acctRow.account_sync_source === 'simpleFin') {
       download = await downloadSimpleFinTransactions(acctId, startingDay);
     } else if (acctRow.account_sync_source === 'goCardless') {
@@ -950,12 +805,11 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
       );
     }
 
-    const { transactions, startingBalance } = download;
-
-    let balanceToUse = startingBalance;
+    const { transactions } = download;
+    let balanceToUse = download.startingBalance;
 
     if (acctRow.account_sync_source === 'simpleFin') {
-      const currentBalance = startingBalance;
+      const currentBalance = download.startingBalance;
       const previousBalance = transactions.reduce((total, trans) => {
         return (
           total - parseInt(trans.transactionAmount.amount.replace('.', ''))
@@ -984,109 +838,7 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) {
         starting_balance_flag: true,
       });
 
-      const result = await reconcileExternalTransactions(id, transactions);
-      return {
-        ...result,
-        added: [initialId, ...result.added],
-      };
-    });
-  }
-}
-
-export async function syncAccount(userId, userKey, id, acctId, bankId) {
-  // TODO: Handle the case where transactions exist in the future
-  // (that will make start date after end date)
-  const latestTransaction = await db.first(
-    'SELECT * FROM v_transactions WHERE account = ? ORDER BY date DESC LIMIT 1',
-    [id],
-  );
-
-  if (latestTransaction) {
-    const startingTransaction = await db.first(
-      'SELECT date FROM v_transactions WHERE account = ? ORDER BY date ASC LIMIT 1',
-      [id],
-    );
-    const startingDate = db.fromDateRepr(startingTransaction.date);
-    // assert(startingTransaction)
-
-    // Get all transactions since the latest transaction, plus any 5
-    // days before the latest transaction. This gives us a chance to
-    // resolve any transactions that were entered manually.
-    //
-    // TODO: What this really should do is query the last imported_id
-    // and since then
-    let date = monthUtils.subDays(db.fromDateRepr(latestTransaction.date), 31);
-
-    // Never download transactions before the starting date. This was
-    // when the account was added to the system.
-    if (date < startingDate) {
-      date = startingDate;
-    }
-
-    const { transactions: originalTransactions, accountBalance } =
-      await downloadTransactions(userId, userKey, acctId, bankId, date);
-    if (originalTransactions.length === 0) {
-      return { added: [], updated: [] };
-    }
-
-    const transactions = originalTransactions.map(trans => ({
-      ...trans,
-      account: id,
-    }));
-
-    return runMutator(async () => {
-      const result = await reconcileTransactions(id, transactions);
-      await updateAccountBalance(id, accountBalance);
-      return result;
-    });
-  } else {
-    const acctRow = await db.select('accounts', id);
-
-    // Otherwise, download transaction for the last few days if it's an
-    // on-budget account, or for the past 30 days if off-budget
-    const startingDay = monthUtils.subDays(
-      monthUtils.currentDay(),
-      acctRow.offbudget === 0 ? 1 : 30,
-    );
-
-    const { transactions } = await downloadTransactions(
-      userId,
-      userKey,
-      acctId,
-      bankId,
-      dateFns.format(dateFns.parseISO(startingDay), 'yyyy-MM-dd'),
-    );
-
-    // We need to add a transaction that represents the starting
-    // balance for everything to balance out. In order to get balance
-    // before the first imported transaction, we need to get the
-    // current balance from the accounts table and subtract all the
-    // imported transactions.
-    const currentBalance = acctRow.balance_current;
-
-    const previousBalance = transactions.reduce((total, trans) => {
-      return total - trans.amount;
-    }, currentBalance);
-
-    const oldestDate =
-      transactions.length > 0
-        ? transactions[transactions.length - 1].date
-        : monthUtils.currentDay();
-
-    const payee = await getStartingBalancePayee();
-
-    return runMutator(async () => {
-      const initialId = await db.insertTransaction({
-        account: id,
-        amount: previousBalance,
-        category: acctRow.offbudget === 0 ? payee.category : null,
-        payee: payee.id,
-        date: oldestDate,
-        cleared: true,
-        starting_balance_flag: true,
-      });
-
-      const result = await reconcileTransactions(id, transactions);
+      const result = await reconcileTransactions(id, transactions, true);
       return {
         ...result,
         added: [initialId, ...result.added],
diff --git a/packages/loot-core/src/server/main.test.ts b/packages/loot-core/src/server/main.test.ts
index 4625011bc..ea4d87130 100644
--- a/packages/loot-core/src/server/main.test.ts
+++ b/packages/loot-core/src/server/main.test.ts
@@ -16,7 +16,6 @@ import {
   disableGlobalMutations,
   enableGlobalMutations,
 } from './mutators';
-import { post } from './post';
 import * as prefs from './prefs';
 import * as sheet from './sheet';
 
@@ -103,63 +102,6 @@ describe('Budgets', () => {
 });
 
 describe('Accounts', () => {
-  test('create accounts with correct starting balance', async () => {
-    prefs.loadPrefs();
-    prefs.savePrefs({ groupId: 'group' });
-
-    await runMutator(async () => {
-      // An income category is required because the starting balance is
-      // categorized to it. Create one now.
-      await db.insertCategoryGroup({
-        id: 'group1',
-        name: 'income',
-        is_income: 1,
-      });
-      await db.insertCategory({
-        name: 'income',
-        cat_group: 'group1',
-        is_income: 1,
-      });
-    });
-
-    // Get accounts from the server. This isn't the normal API call,
-    // we know that the mock server just returns hardcoded accounts
-    const { accounts } = await post('/plaid/accounts', {});
-
-    // Create the accounts for the bank (bank is generally ignored in tests)
-    await runHandler(handlers['accounts-connect'], {
-      institution: { institution_id: 1, name: 'Jamesy Bank' },
-      publicToken: 'foo',
-      accountIds: accounts.map(acct => acct.account_id),
-    });
-
-    // Import transactions for all accounts
-    await runHandler(handlers['accounts-sync'], {});
-
-    // Go through each account and make sure the starting balance was
-    // created correctly
-    const res = await db.all('SELECT * FROM accounts');
-    for (const account of res) {
-      const sum = await db.first(
-        'SELECT sum(amount) as sum FROM transactions WHERE acct = ? AND starting_balance_flag = 0',
-        [account.id],
-      );
-      const starting = await db.first(
-        'SELECT * FROM transactions WHERE acct = ? AND starting_balance_flag = 1',
-        [account.id],
-      );
-      expect(account.balance_current - sum.sum).toBe(starting.amount);
-
-      // Also ensure that the starting balance has the earliest date
-      // possible
-      const earliestTrans = await db.first(
-        'SELECT p.name as payee_name FROM transactions t LEFT JOIN payees p ON p.id = t.description WHERE acct = ? ORDER BY date LIMIT 1',
-        [account.id],
-      );
-      expect(earliestTrans.payee_name).toBe('Starting Balance');
-    }
-  });
-
   test('Transfers are properly updated', async () => {
     await runMutator(async () => {
       await db.insertAccount({ id: 'one', name: 'one' });
diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts
index 0cc70892d..c0ca4ec8e 100644
--- a/packages/loot-core/src/server/main.ts
+++ b/packages/loot-core/src/server/main.ts
@@ -610,54 +610,6 @@ handlers['account-properties'] = async function ({ id }) {
   return { balance: balance || 0, numTransactions: count };
 };
 
-handlers['accounts-link'] = async function ({
-  institution,
-  publicToken,
-  accountId,
-  upgradingId,
-}) {
-  const bankId = await link.handoffPublicToken(institution, publicToken);
-
-  const [[, userId], [, userKey]] = await asyncStorage.multiGet([
-    'user-id',
-    'user-key',
-  ]);
-
-  // Get all the available accounts and find the selected one
-  const accounts = await bankSync.getGoCardlessAccounts(
-    userId,
-    userKey,
-    bankId,
-  );
-  const account = accounts.find(acct => acct.account_id === accountId);
-
-  await db.update('accounts', {
-    id: upgradingId,
-    account_id: account.account_id,
-    official_name: account.official_name,
-    balance_current: amountToInteger(account.balances.current),
-    balance_available: amountToInteger(account.balances.available),
-    balance_limit: amountToInteger(account.balances.limit),
-    mask: account.mask,
-    bank: bankId,
-  });
-
-  await bankSync.syncAccount(
-    userId,
-    userKey,
-    upgradingId,
-    account.account_id,
-    bankId,
-  );
-
-  connection.send('sync-event', {
-    type: 'success',
-    tables: ['transactions'],
-  });
-
-  return 'ok';
-};
-
 handlers['gocardless-accounts-link'] = async function ({
   requisitionId,
   account,
@@ -694,7 +646,7 @@ handlers['gocardless-accounts-link'] = async function ({
     });
   }
 
-  await bankSync.syncExternalAccount(
+  await bankSync.syncAccount(
     undefined,
     undefined,
     id,
@@ -752,7 +704,7 @@ handlers['simplefin-accounts-link'] = async function ({
     });
   }
 
-  await bankSync.syncExternalAccount(
+  await bankSync.syncAccount(
     undefined,
     undefined,
     id,
@@ -768,17 +720,6 @@ handlers['simplefin-accounts-link'] = async function ({
   return 'ok';
 };
 
-handlers['accounts-connect'] = async function ({
-  institution,
-  publicToken,
-  accountIds,
-  offbudgetIds,
-}) {
-  const bankId = await link.handoffPublicToken(institution, publicToken);
-  const ids = await link.addAccounts(bankId, accountIds, offbudgetIds);
-  return ids;
-};
-
 handlers['gocardless-accounts-connect'] = async function ({
   institution,
   publicToken,
@@ -1288,7 +1229,7 @@ handlers['gocardless-accounts-sync'] = async function ({ id }) {
     if (acct.bankId) {
       try {
         console.group('Bank Sync operation');
-        const res = await bankSync.syncExternalAccount(
+        const res = await bankSync.syncAccount(
           userId,
           userKey,
           acct.id,
diff --git a/packages/loot-core/src/types/server-handlers.d.ts b/packages/loot-core/src/types/server-handlers.d.ts
index eff46e2f6..476bbeaa9 100644
--- a/packages/loot-core/src/types/server-handlers.d.ts
+++ b/packages/loot-core/src/types/server-handlers.d.ts
@@ -149,13 +149,6 @@ export interface ServerHandlers {
     id;
   }) => Promise<{ balance: number; numTransactions: number }>;
 
-  'accounts-link': (arg: {
-    institution;
-    publicToken;
-    accountId;
-    upgradingId;
-  }) => Promise<'ok'>;
-
   'gocardless-accounts-link': (arg: {
     requisitionId;
     account;
@@ -167,13 +160,6 @@ export interface ServerHandlers {
     upgradingId;
   }) => Promise<'ok'>;
 
-  'accounts-connect': (arg: {
-    institution;
-    publicToken;
-    accountIds;
-    offbudgetIds?;
-  }) => Promise<unknown>;
-
   'gocardless-accounts-connect': (arg: {
     institution;
     publicToken;
diff --git a/upcoming-release-notes/2534.md b/upcoming-release-notes/2534.md
new file mode 100644
index 000000000..6101f9b69
--- /dev/null
+++ b/upcoming-release-notes/2534.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [MatissJanis]
+---
+
+Removing code duplication in bank-sync logic
-- 
GitLab