gnucash stable: Bug 799734 - mapped OFX income account not listed

Robert Fewell bobit at code.gnucash.org
Fri Mar 13 06:29:35 EDT 2026


Updated	 via  https://github.com/Gnucash/gnucash/commit/62af7f0d (commit)
	from  https://github.com/Gnucash/gnucash/commit/8538dcf9 (commit)



commit 62af7f0d6d479dffcaebfcecd4a8af13aa49fc88
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Mon Feb 16 16:50:58 2026 +0000

    Bug 799734 - mapped OFX income account not listed
    
    Change the Import Map Editor to look for the KVP slot
    "ofx/associated-income-account" so it can be listed. The account
    reference stored is a GUID so add a function to retrieve that so the
    existing gnc_account_delete_map_entry function can be used to remove it.

diff --git a/gnucash/gnome/dialog-imap-editor.c b/gnucash/gnome/dialog-imap-editor.c
index 581ef2c766..c20d5a7b4d 100644
--- a/gnucash/gnome/dialog-imap-editor.c
+++ b/gnucash/gnome/dialog-imap-editor.c
@@ -703,6 +703,97 @@ get_account_info_nbayes (ImapDialog *imap_dialog, GList *accts)
     }
 }
 
+static void
+add_online_entry_to_store (ImapDialog *imap_dialog, GtkTreeIter *toplevel,
+                           const gchar *based_on, GncImapInfo *imapInfo)
+{
+    // Add top level entry and pass iter to add_to_store
+    gtk_tree_store_append (GTK_TREE_STORE(imap_dialog->model), toplevel, NULL);
+    add_to_store (imap_dialog, toplevel, based_on, imapInfo);
+
+    imapInfo->map_account = NULL;
+}
+
+static void
+check_online_id (ImapDialog *imap_dialog, GtkTreeIter *toplevel, Account *acc, GncImapInfo *imapInfo)
+{
+    // Check for online_id
+    gchar *head = "online_id";
+    gchar *text = gnc_account_get_map_entry (acc, head, NULL);
+
+    if (!text)
+        return;
+
+    // Save source account
+    imapInfo->source_account = acc;
+    imapInfo->head = head;
+
+    if (text && *text)
+        imapInfo->map_account = imapInfo->source_account;
+
+    imapInfo->match_string = text;
+
+    add_online_entry_to_store (imap_dialog, toplevel, _("Online Id"), imapInfo);
+
+    g_free (text);
+}
+
+static void
+check_hbci (ImapDialog *imap_dialog, GtkTreeIter *toplevel, Account *acc, GncImapInfo *imapInfo)
+{
+    // Check for aqbanking hbci
+    gchar *head = "hbci";
+    gchar *hbci_account_id = gnc_account_get_map_entry (acc, head, "account-id");
+    gchar *hbci_bank_code = gnc_account_get_map_entry (acc, head, "bank-code");
+
+    if (!hbci_account_id || !hbci_bank_code)
+        return;
+
+    gchar *text = g_strconcat (hbci_bank_code, ",", hbci_account_id, NULL);
+
+    // Save source account
+    imapInfo->source_account = acc;
+    imapInfo->head = head;
+
+    if (text && *text)
+        imapInfo->map_account = imapInfo->source_account;
+
+    imapInfo->match_string = text;
+
+    add_online_entry_to_store (imap_dialog, toplevel, _("Online HBCI"), imapInfo);
+
+    g_free (hbci_account_id);
+    g_free (hbci_bank_code);
+    g_free (text);
+}
+
+static void
+check_ofx_account (ImapDialog *imap_dialog, GtkTreeIter *toplevel, Account *acc, GncImapInfo *imapInfo)
+{
+    // Check for ofx income account
+    gchar *head = "ofx/associated-income-account";
+    GncGUID *acct_guid = gnc_account_get_map_guid_entry (acc, head, NULL);
+
+    if (!acct_guid)
+        return;
+
+    gchar *text = guid_to_string (acct_guid);
+
+    // Save source account
+    imapInfo->source_account = acc;
+    imapInfo->head = head;
+
+    if (text && *text)
+        imapInfo->map_account = xaccAccountLookup (acct_guid, gnc_get_current_book ());
+
+    imapInfo->match_string = text;
+
+    add_online_entry_to_store (imap_dialog, toplevel, _("OFX Income Account"), imapInfo);
+
+    guid_free (acct_guid);
+    g_free (text);
+}
+
 static void
 get_account_info_online (ImapDialog *imap_dialog, GList *accts)
 {
@@ -711,65 +802,24 @@ get_account_info_online (ImapDialog *imap_dialog, GList *accts)
 
     GncImapInfo imapInfo;
 
+    imapInfo.map_account = NULL;
+    imapInfo.source_account = NULL;
+    imapInfo.category = " ";
+    imapInfo.count = " ";
+
     /* Go through list of accounts */
     for (ptr = accts; ptr; ptr = g_list_next (ptr))
     {
-        gchar  *hbci_account_id = NULL;
-        gchar  *hbci_bank_code = NULL;
-        gchar  *text = NULL;
         Account *acc = ptr->data;
 
         // Check for online_id
-        text = gnc_account_get_map_entry (acc, "online_id", NULL);
-
-        if (text != NULL)
-        {
-            // Save source account
-            imapInfo.source_account = acc;
-            imapInfo.head = "online_id";
-            imapInfo.category = " ";
-
-            if (g_strcmp0 (text, "") == 0)
-                imapInfo.map_account = NULL;
-            else
-                imapInfo.map_account = imapInfo.source_account;
-
-            imapInfo.match_string = text;
-            imapInfo.count = " ";
-
-            // Add top level entry and pass iter to add_to_store
-            gtk_tree_store_append (GTK_TREE_STORE(imap_dialog->model), &toplevel, NULL);
-            add_to_store (imap_dialog, &toplevel, _("Online Id"), &imapInfo);
-        }
-        g_free (text);
+        check_online_id (imap_dialog, &toplevel, acc, &imapInfo);
 
         // Check for aqbanking hbci
-        hbci_account_id = gnc_account_get_map_entry (acc, "hbci", "account-id");
-        hbci_bank_code = gnc_account_get_map_entry (acc, "hbci", "bank-code");
-        text = g_strconcat (hbci_bank_code, ",", hbci_account_id, NULL);
+        check_hbci (imap_dialog, &toplevel, acc, &imapInfo);
 
-        if ((hbci_account_id != NULL) || (hbci_bank_code != NULL))
-        {
-            // Save source account
-            imapInfo.source_account = acc;
-            imapInfo.head = "hbci";
-            imapInfo.category = " ";
-
-            if (g_strcmp0 (text, "") == 0)
-                imapInfo.map_account = NULL;
-            else
-                imapInfo.map_account = imapInfo.source_account;
-
-            imapInfo.match_string = text;
-            imapInfo.count = " ";
-
-            // Add top level entry and pass iter to add_to_store
-            gtk_tree_store_append (GTK_TREE_STORE(imap_dialog->model), &toplevel, NULL);
-            add_to_store (imap_dialog, &toplevel, _("Online HBCI"), &imapInfo);
-        }
-        g_free (hbci_account_id);
-        g_free (hbci_bank_code);
-        g_free (text);
+        // Check for ofx income account
+        check_ofx_account (imap_dialog, &toplevel, acc, &imapInfo);
     }
 }
 
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index e6ea9f640d..019c613a53 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -2583,6 +2583,13 @@ get_kvp_int64_path (const Account *acc, const Path& path)
     return qof_instance_get_path_kvp<int64_t> (QOF_INSTANCE(acc), path);
 }
 
+static GncGUID*
+get_kvp_guid_path (const Account *acc, const Path& path)
+{
+    auto val{qof_instance_get_path_kvp<GncGUID*> (QOF_INSTANCE(acc), path)};
+    return val ? guid_copy(*val) : nullptr;
+}
+
 void
 xaccAccountSetColor (Account *acc, const char *str)
 {
@@ -5688,6 +5695,13 @@ gnc_account_get_map_entry (Account *acc, const char *head, const char *category)
                      get_kvp_string_path (acc, {head}));
 }
 
+GncGUID *
+gnc_account_get_map_guid_entry (Account *acc, const char *head, const char *category)
+{
+    return category ?
+           get_kvp_guid_path (acc, {head, category}) :
+           get_kvp_guid_path (acc, {head});
+}
 
 void
 gnc_account_delete_map_entry (Account *acc, char *head, char *category,
diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h
index f748588735..0043d6a410 100644
--- a/libgnucash/engine/Account.h
+++ b/libgnucash/engine/Account.h
@@ -1648,6 +1648,11 @@ typedef enum
      */
     gchar *gnc_account_get_map_entry (Account *acc, const char *head, const char *category);
 
+    /** Returns the guid pointed to by head and category for the Account, free
+     *  the returned guid
+     */
+    GncGUID *gnc_account_get_map_guid_entry (Account *acc, const char *head, const char *category);
+
     /** Delete the entry for Account pointed to by head,category and match_string,
      *  if empty is TRUE then use delete if empty
      */
diff --git a/libgnucash/engine/test/utest-Account.cpp b/libgnucash/engine/test/utest-Account.cpp
index da8d240b63..fc52032ba1 100644
--- a/libgnucash/engine/test/utest-Account.cpp
+++ b/libgnucash/engine/test/utest-Account.cpp
@@ -1366,6 +1366,30 @@ test_gnc_account_get_map_entry (Fixture *fixture, gconstpointer pData)
     xaccAccountDestroy (account);
 }
 
+static void
+test_gnc_account_get_map_guid_entry (Fixture *fixture, gconstpointer pData)
+{
+    Account *account = xaccMallocAccount (gnc_account_get_book (fixture->acct));
+    const GncGUID *account_guid = xaccAccountGetGUID (account);
+
+    xaccAccountBeginEdit (fixture->acct);
+    qof_instance_set (QOF_INSTANCE(fixture->acct), "ofx-income-account", account_guid, nullptr);
+    xaccAccountCommitEdit (fixture->acct);
+
+    GncGUID *guid = gnc_account_get_map_guid_entry (fixture->acct, "ofx/associated-income-account", nullptr);
+    g_assert_true (guid_equal (account_guid, guid));
+    guid_free (guid);
+
+    gnc_account_delete_map_entry (fixture->acct, "ofx/associated-income-account", nullptr, nullptr, false);
+
+    guid = gnc_account_get_map_guid_entry (fixture->acct, "ofx/associated-income-account", nullptr);
+    g_assert_true (!guid);
+    guid_free (guid);
+
+    xaccAccountBeginEdit (account);
+    xaccAccountDestroy (account);
+}
+
 static void
 test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
 {
@@ -2869,6 +2893,7 @@ test_suite_account (void)
 // GNC_TEST_ADD (suitename, "xaccAccountEqual", Fixture, NULL, setup, test_xaccAccountEqual,  teardown );
     GNC_TEST_ADD (suitename, "gnc account kvp getters & setters", Fixture, NULL, setup, test_gnc_account_kvp_setters_getters,  teardown );
     GNC_TEST_ADD (suitename, "test_gnc_account_get_map_entry", Fixture, NULL, setup, test_gnc_account_get_map_entry,  teardown );
+    GNC_TEST_ADD (suitename, "test_gnc_account_get_map_guid_entry", Fixture, NULL, setup, test_gnc_account_get_map_guid_entry,  teardown );
     GNC_TEST_ADD (suitename, "gnc account insert & remove split", Fixture, NULL, setup, test_gnc_account_insert_remove_split,  teardown );
     GNC_TEST_ADD (suitename, "xaccAccount Insert and Remove Lot", Fixture, &good_data, setup, test_xaccAccountInsertRemoveLot,  teardown );
     GNC_TEST_ADD (suitename, "xaccAccountRecomputeBalance", Fixture, &some_data, setup, test_xaccAccountRecomputeBalance,  teardown );



Summary of changes:
 gnucash/gnome/dialog-imap-editor.c       | 150 ++++++++++++++++++++-----------
 libgnucash/engine/Account.cpp            |  14 +++
 libgnucash/engine/Account.h              |   5 ++
 libgnucash/engine/test/utest-Account.cpp |  25 ++++++
 4 files changed, 144 insertions(+), 50 deletions(-)



More information about the gnucash-changes mailing list