gnucash master: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Sat Oct 29 10:26:20 EDT 2022


Updated	 via  https://github.com/Gnucash/gnucash/commit/fc94b41c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f2354d6b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1516bb18 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a078921a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/cf088f2a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f5099b3d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/093aa81e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8192deff (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8cb8f506 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d8417c3c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2774f8f8 (commit)
	from  https://github.com/Gnucash/gnucash/commit/4716af24 (commit)



commit fc94b41c814e6bcbf40818e4dcb3795cdd359803
Merge: 4716af24e f2354d6b2
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Oct 29 21:53:57 2022 +0800

    Merge branch 'maint'

diff --cc gnucash/gnome/dialog-report-style-sheet.cpp
index 732d49b6c,1a4d4afc1..472db0e7f
--- a/gnucash/gnome/dialog-report-style-sheet.cpp
+++ b/gnucash/gnome/dialog-report-style-sheet.cpp
@@@ -139,16 -132,16 +139,16 @@@ gnc_style_sheet_options_apply_cb (GncOp
  }
  
  static void
 -gnc_style_sheet_options_close_cb (GNCOptionWin * propertybox,
 +gnc_style_sheet_options_close_cb (GncOptionsDialog *opt_dialog,
                                    gpointer user_data)
  {
 -    ss_info * ssi = user_data;
 -    GtkTreeIter iter;
 +    auto ssi{static_cast<ss_info*>(user_data)};
  
-     if (gtk_tree_row_reference_valid (ssi->row_ref))
+     if (gnc_style_sheet_dialog && gtk_tree_row_reference_valid (ssi->row_ref))
      {
 -        StyleSheetDialog * ss = gnc_style_sheet_dialog;
 -        GtkTreePath *path = gtk_tree_row_reference_get_path (ssi->row_ref);
 +        auto ss = gnc_style_sheet_dialog;
 +        auto path = gtk_tree_row_reference_get_path (ssi->row_ref);
 +        GtkTreeIter iter;
          if (gtk_tree_model_get_iter (GTK_TREE_MODEL(ss->list_store), &iter, path))
              gtk_list_store_set (ss->list_store, &iter,
                                  COLUMN_DIALOG, NULL,
diff --cc libgnucash/app-utils/CMakeLists.txt
index ac9179994,0f007c8a8..86bcb48f8
--- a/libgnucash/app-utils/CMakeLists.txt
+++ b/libgnucash/app-utils/CMakeLists.txt
@@@ -6,33 -6,64 +6,31 @@@ include (GncFindLibm
  
  # Build the library
  
 -set (app_utils_noinst_HEADERS
 -  calculation/finvar.h
 -  calculation/finproto.h
 -  calculation/fin_spl_protos.h
 -  calculation/fin_static_proto.h
 -)
 -
  set (app_utils_HEADERS
    QuickFill.h
 -  business-options.h
    file-utils.h
 -  gfec.h
    gnc-basic-gobject.h
    gnc-account-merge.h
 -  gnc-accounting-period.h
    gnc-addr-quickfill.h
    gnc-entry-quickfill.h
-   gnc-euro.h
 -  gnc-exp-parser.h
    gnc-gsettings.h
    gnc-help-utils.h
 -  gnc-helpers.h
    gnc-prefs-utils.h
 -  gnc-state.h  
 -  gnc-sx-instance-model.h
 +  gnc-quotes.hpp
 +  gnc-state.h
    gnc-ui-util.h
    gnc-ui-balances.h
 -  option-util.h
 -)
 -
 -# Command to generate the swig-app-utils-guile.c wrapper file
 -gnc_add_swig_guile_command (swig-apputils-guile-c
 -    SWIG_APP_UTILS_GUILE_C swig-app-utils-guile.c
 -    ${CMAKE_CURRENT_SOURCE_DIR}/app-utils.i ""
 -)
 -
 -# Command to generate the swig-app-utils-python.c wrapper file
 -gnc_add_swig_python_command (swig-app-utils-python
 -    SWIG_APP_UTILS_PYTHON_C SWIG_APP_UTILS_PYTHON_PY
 -    swig-app-utils-python.c sw_app_utils.py
 -    ${CMAKE_CURRENT_SOURCE_DIR}/app-utils.i ""
  )
  
  set (app_utils_SOURCES
 -  calculation/expression_parser.c
 -  calculation/fin.c
 -  business-options.c
    QuickFill.c
    file-utils.c
 -  gfec.c
    gnc-account-merge.c
 -  gnc-accounting-period.c
    gnc-addr-quickfill.c
    gnc-entry-quickfill.c
-   gnc-euro.c
 -  gnc-exp-parser.c
    gnc-gsettings.cpp
 -  gnc-helpers.c
    gnc-prefs-utils.c
 -  gnc-sx-instance-model.c
 +  gnc-quotes.cpp
    gnc-state.c
    gnc-ui-util.c
    gnc-ui-balances.c
diff --cc po/POTFILES.in
index a7c6e5da0,51de233da..0b9bbd379
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@@ -510,12 -533,12 +510,11 @@@ libgnucash/app-utils/gfec.
  libgnucash/app-utils/gnc-account-merge.c
  libgnucash/app-utils/gnc-addr-quickfill.c
  libgnucash/app-utils/gnc-entry-quickfill.c
- libgnucash/app-utils/gnc-euro.c
  libgnucash/app-utils/gnc-exp-parser.c
  libgnucash/app-utils/gnc-gsettings.cpp
 -libgnucash/app-utils/gnc-helpers.c
  libgnucash/app-utils/gnc-help-utils.c
  libgnucash/app-utils/gnc-prefs-utils.c
 +libgnucash/app-utils/gnc-quotes.cpp
  libgnucash/app-utils/gnc-state.c
  libgnucash/app-utils/gnc-sx-instance-model.c
  libgnucash/app-utils/gnc-ui-balances.c

commit f2354d6b2af329c5cc849fc9d7908884c4b7fdc2
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Oct 29 13:47:33 2022 +0800

    [test-qofbook.c] add test for gnc_features_set_unused

diff --git a/libgnucash/engine/test/test-qofbook.c b/libgnucash/engine/test/test-qofbook.c
index a771c3d5e..4c6fe444e 100644
--- a/libgnucash/engine/test/test-qofbook.c
+++ b/libgnucash/engine/test/test-qofbook.c
@@ -782,6 +782,10 @@ test_book_features (Fixture *fixture, gconstpointer pData)
     g_assert_null (gnc_features_test_unknown (fixture->book));
     g_assert_true (gnc_features_check_used (fixture->book, "Credit Notes"));
 
+    gnc_features_set_unused (fixture->book, "Credit Notes");
+    g_assert_null (gnc_features_test_unknown (fixture->book));
+    g_assert_false (gnc_features_check_used (fixture->book, "Credit Notes"));
+
     /* cannot set an unknown feature: it bails out. */
     /* gnc_features_set_used (fixture->book, "Nanotech"); */
     /* g_assert_nonnull (gnc_features_test_unknown (fixture->book)); */

commit 1516bb18b070d6fbc0388791edb8cb1040ad0d6e
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Dec 2 22:12:29 2021 +0800

    [gnc-features.cpp] backport gnc_features_set_unused from master

diff --git a/libgnucash/engine/gnc-features.cpp b/libgnucash/engine/gnc-features.cpp
index 5e2823a3c..07d3e59fe 100644
--- a/libgnucash/engine/gnc-features.cpp
+++ b/libgnucash/engine/gnc-features.cpp
@@ -91,6 +91,23 @@ void gnc_features_set_used (QofBook *book, const gchar *feature)
     qof_book_set_feature (book, feature, iter->second.c_str());
 }
 
+
+void gnc_features_set_unused (QofBook *book, const gchar *feature)
+{
+    g_return_if_fail (book);
+    g_return_if_fail (feature);
+
+    /* Can't set an unknown feature */
+    auto iter = features_table.find (feature);
+    if (iter == features_table.end ())
+    {
+        PWARN("Tried to set unknown feature as unused.");
+        return;
+    }
+
+    qof_book_unset_feature (book, feature);
+}
+
 gboolean gnc_features_check_used (QofBook *book, const gchar * feature)
 {
     return qof_book_test_feature (book, feature);
diff --git a/libgnucash/engine/gnc-features.h b/libgnucash/engine/gnc-features.h
index 030c02531..b5960ac7a 100644
--- a/libgnucash/engine/gnc-features.h
+++ b/libgnucash/engine/gnc-features.h
@@ -67,6 +67,13 @@ extern "C" {
  */
 gchar *gnc_features_test_unknown (QofBook *book);
 
+/**
+ * Indicate that the current book does not use the given feature. This
+ * will allow older versions of GnuCash that don't support this
+ * feature to load this book.
+ */
+void gnc_features_set_unused (QofBook *book, const gchar *feature);
+
 /**
  * Indicate that the current book uses the given feature. This will prevent
  * older versions of GnuCash that don't support this feature to refuse to load

commit a078921a33e3ea1e2f3427565fe8d348205b3f6a
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Dec 2 22:12:12 2021 +0800

    [qofbook.cpp] backport qof_book_unset_feature from master

diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index cbed9cb2d..d963aa18c 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -1285,6 +1285,22 @@ qof_book_test_feature (QofBook *book, const char *feature)
     return (frame->get_slot({GNC_FEATURES, feature}) != nullptr);
 }
 
+void
+qof_book_unset_feature (QofBook *book, const gchar *key)
+{
+    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
+    auto feature_slot = frame->get_slot({GNC_FEATURES, key});
+    if (!feature_slot)
+    {
+        PWARN ("no feature %s. bail out.", key);
+        return;
+    }
+    qof_book_begin_edit (book);
+    delete frame->set_path({GNC_FEATURES, key}, nullptr);
+    qof_instance_set_dirty (QOF_INSTANCE (book));
+    qof_book_commit_edit (book);
+}
+
 void
 qof_book_load_options (QofBook *book, GNCOptionLoad load_cb, GNCOptionDB *odb)
 {
diff --git a/libgnucash/engine/qofbook.h b/libgnucash/engine/qofbook.h
index fbaf8a020..47104bbf4 100644
--- a/libgnucash/engine/qofbook.h
+++ b/libgnucash/engine/qofbook.h
@@ -382,6 +382,7 @@ void qof_book_option_frame_delete (QofBook *book, const char* opt_name);
 /** Access functions for reading and setting the used-features on this book.
  */
 GHashTable *qof_book_get_features (QofBook *book);
+void qof_book_unset_feature (QofBook *book, const gchar *key);
 void qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr);
 
 void qof_book_begin_edit(QofBook *book);

commit cf088f2a70f0dd21af0970cfbf1f11a338a54cbc
Merge: f5099b3d8 8cb8f5067
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Oct 28 15:27:28 2022 -0700

    Merge John Ralls's 'Bug798614' into maint.

diff --cc libgnucash/engine/CMakeLists.txt
index b9d11b877,33f9f3d2d..bf2b54463
--- a/libgnucash/engine/CMakeLists.txt
+++ b/libgnucash/engine/CMakeLists.txt
@@@ -145,8 -145,9 +146,9 @@@ set (engine_SOURCE
    gnc-date.cpp
    gnc-datetime.cpp
    gnc-engine.c
+   gnc-euro.c
    gnc-event.c
 -  gnc-features.c
 +  gnc-features.cpp
    gnc-hooks.c
    gnc-int128.cpp
    gnc-lot.c
diff --cc po/POTFILES.in
index 3d2a0e7b3,6795e6f2b..51de233da
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@@ -640,8 -639,9 +639,9 @@@ libgnucash/engine/gnc-datetime.cp
  libgnucash/engine/gncEmployee.c
  libgnucash/engine/gnc-engine.c
  libgnucash/engine/gncEntry.c
+ libgnucash/engine/gnc-euro.c
  libgnucash/engine/gnc-event.c
 -libgnucash/engine/gnc-features.c
 +libgnucash/engine/gnc-features.cpp
  libgnucash/engine/gnc-hooks.c
  libgnucash/engine/gncIDSearch.c
  libgnucash/engine/gnc-int128.cpp

commit f5099b3d87a693991dfb3160f848ad218254b760
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Oct 28 11:37:18 2022 -0700

    Bug 798649 - Crash when closing Edit Style Sheets dialog while...
    
    Style Sheet Properties dialog is still open.
    
    Because the style_sheet_dialog is already destroyed and nulled.

diff --git a/gnucash/gnome/dialog-report-style-sheet.c b/gnucash/gnome/dialog-report-style-sheet.c
index a4f8d7527..1a4d4afc1 100644
--- a/gnucash/gnome/dialog-report-style-sheet.c
+++ b/gnucash/gnome/dialog-report-style-sheet.c
@@ -138,7 +138,7 @@ gnc_style_sheet_options_close_cb (GNCOptionWin * propertybox,
     ss_info * ssi = user_data;
     GtkTreeIter iter;
 
-    if (gtk_tree_row_reference_valid (ssi->row_ref))
+    if (gnc_style_sheet_dialog && gtk_tree_row_reference_valid (ssi->row_ref))
     {
         StyleSheetDialog * ss = gnc_style_sheet_dialog;
         GtkTreePath *path = gtk_tree_row_reference_get_path (ssi->row_ref);

commit 093aa81ed1f4f638775212af4ee61d9e5d63fa07
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Fri Oct 28 21:57:15 2022 +0800

    [qofbook.cpp] deprecate qof_book_get_features

diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index da4e2c843..cbed9cb2d 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -1228,6 +1228,8 @@ qof_book_get_features (QofBook *book)
     GHashTable *features = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                   NULL, g_free);
 
+    PWARN ("qof_book_get_features is now deprecated.");
+
     auto slot = frame->get_slot({GNC_FEATURES});
     if (slot != nullptr)
     {

commit 8192deff37e4a5063ad62a90753bcd9a60b2f716
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue Oct 25 00:17:30 2022 +0800

    [gnc-features.cpp] convert to cpp
    
    - don't need to create/destroy GHashTable for each feature query
    - plugs leak: g_hash_table_unref (features_used) not always called properly
    - to check 1 feature, don't need to traverse whole GHashTable

diff --git a/libgnucash/engine/CMakeLists.txt b/libgnucash/engine/CMakeLists.txt
index 8dde8461b..b9d11b877 100644
--- a/libgnucash/engine/CMakeLists.txt
+++ b/libgnucash/engine/CMakeLists.txt
@@ -93,6 +93,7 @@ set (engine_HEADERS
   qof-backend.hpp
   qofbackend.h
   qofbook.h
+  qofbook.hpp
   qofbookslots.h
   qofchoice.h
   qofclass.h
@@ -145,7 +146,7 @@ set (engine_SOURCES
   gnc-datetime.cpp
   gnc-engine.c
   gnc-event.c
-  gnc-features.c
+  gnc-features.cpp
   gnc-hooks.c
   gnc-int128.cpp
   gnc-lot.c
diff --git a/libgnucash/engine/gnc-features.c b/libgnucash/engine/gnc-features.cpp
similarity index 53%
rename from libgnucash/engine/gnc-features.c
rename to libgnucash/engine/gnc-features.cpp
index f710677d2..5e2823a3c 100644
--- a/libgnucash/engine/gnc-features.c
+++ b/libgnucash/engine/gnc-features.cpp
@@ -19,28 +19,22 @@
  *                                                                  *
 \********************************************************************/
 
+#include <unordered_map>
+#include <string>
+#include <numeric>
+
 #include <config.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "qof.h"
-#include "gnc-features.h"
-#include "gnc-glib-utils.h"
+#include "qofbook.hpp"
 
-typedef struct
+extern "C"
 {
-    const gchar *key;
-    const gchar *desc;
-} gncFeature;
+#include "gnc-features.h"
+}
 
-static GHashTable *features_table = NULL;
-static gncFeature known_features[] =
+static const FeaturesTable features_table
 {
     { GNC_FEATURE_CREDIT_NOTES, "Customer and vendor credit notes (requires at least GnuCash 2.5.0)" },
     { GNC_FEATURE_NUM_FIELD_SOURCE, "User specifies source of 'num' field'; either transaction number or split action (requires at least GnuCash 2.5.0)" },
@@ -53,7 +47,6 @@ static gncFeature known_features[] =
     { GNC_FEATURE_BUDGET_UNREVERSED, "Store budget amounts unreversed (i.e. natural) signs (requires at least Gnucash 3.8)"},
     { GNC_FEATURE_BUDGET_SHOW_EXTRA_ACCOUNT_COLS, "Show extra account columns in the Budget View (requires at least Gnucash 3.8)"},
     { GNC_FEATURE_EQUITY_TYPE_OPENING_BALANCE, GNC_FEATURE_EQUITY_TYPE_OPENING_BALANCE " (requires at least Gnucash 4.3)" },
-    { NULL },
 };
 
 /* This static indicates the debugging module that this .o belongs to.  */
@@ -62,40 +55,11 @@ static QofLogModule log_module = G_LOG_DOMAIN;
 /********************************************************************\
 \********************************************************************/
 
-static void gnc_features_init ()
-{
-    gint i;
-
-    if (features_table)
-        return;
-
-    features_table = g_hash_table_new (g_str_hash, g_str_equal);
-    for (i = 0; known_features[i].key; i++)
-        g_hash_table_insert (features_table,
-                             g_strdup (known_features[i].key),
-                             g_strdup (known_features[i].desc));
-}
-
-static void gnc_features_test_one(gpointer pkey, gpointer value,
-                  gpointer data)
-{
-    const gchar *key = (const gchar*)pkey;
-    const gchar *feature_desc = (const gchar*)value;
-    GList **unknown_features;
-
-    g_assert(data);
-    unknown_features = (GList**) data;
-
-    /* Check if this feature is in the known features list. */
-    if (g_hash_table_lookup_extended (features_table, key, NULL, NULL))
-        return;
-
-    /* It is unknown, so add the description to the unknown features list: */
-    g_assert(feature_desc);
-
-    *unknown_features = g_list_prepend(*unknown_features,
-                       (gpointer)feature_desc);
-}
+static const char*
+header = N_("This Dataset contains features not supported "
+            "by this version of GnuCash. You must use a "
+            "newer version of GnuCash in order to support "
+            "the following features:");
 
 /* Check if the session requires features unknown to this version of GnuCash.
  *
@@ -104,78 +68,31 @@ static void gnc_features_test_one(gpointer pkey, gpointer value,
  */
 gchar *gnc_features_test_unknown (QofBook *book)
 {
-
-    GList* features_list = NULL;
-    GHashTable *features_used = qof_book_get_features (book);
-
-    /* Setup the known_features hash table */
-    gnc_features_init();
-
-    /* Iterate over the members of this frame for unknown features */
-    g_hash_table_foreach (features_used, &gnc_features_test_one,
-              &features_list);
-    if (features_list)
-    {
-        const char* sep = "\n* ";
-        const char* header = _("This Dataset contains features not supported "
-                               "by this version of GnuCash. You must use a "
-                               "newer version of GnuCash in order to support "
-                               "the following features:");
-
-        char *features_str = gnc_g_list_stringjoin (features_list, sep);
-        char *msg = g_strconcat (header, sep, features_str, NULL);
-        g_free (features_str);
-        g_list_free(features_list);
-        return msg;
-    }
-    g_hash_table_unref (features_used);
-    return NULL;
+    auto unknowns {qof_book_get_unknown_features (book, features_table)};
+    auto accum = [](const auto& a, const auto& b){ return a + "\n* " + b; };
+    return unknowns.empty() ? nullptr :
+        g_strdup (std::accumulate (unknowns.begin(), unknowns.end(),
+                                   std::string (_(header)), accum).c_str());
 }
 
 void gnc_features_set_used (QofBook *book, const gchar *feature)
 {
-    const gchar *description;
-
     g_return_if_fail (book);
     g_return_if_fail (feature);
 
-    gnc_features_init();
-
     /* Can't set an unknown feature */
-    description = g_hash_table_lookup (features_table, feature);
-    if (!description)
+    auto iter = features_table.find (feature);
+    if (iter == features_table.end ())
     {
         PWARN("Tried to set unknown feature as used.");
         return;
     }
 
-    qof_book_set_feature (book, feature, description);
-}
-
-struct CheckFeature
-{
-    gchar const * checked_feature;
-    gboolean found;
-};
-
-static void gnc_features_check_feature_cb (gpointer pkey, gpointer value,
-                  gpointer data)
-{
-    const gchar *key = (const gchar*)pkey;
-    struct CheckFeature * check_data = data;
-    g_assert(data);
-    if (!g_strcmp0 (key, check_data->checked_feature))
-        check_data->found = TRUE;
+    qof_book_set_feature (book, feature, iter->second.c_str());
 }
 
 gboolean gnc_features_check_used (QofBook *book, const gchar * feature)
 {
-    GHashTable *features_used = qof_book_get_features (book);
-    struct CheckFeature check_data = {feature, FALSE};
-    /* Setup the known_features hash table */
-    gnc_features_init();
-    g_hash_table_foreach (features_used, &gnc_features_check_feature_cb, &check_data);
-    g_hash_table_unref (features_used);
-    return check_data.found;
+    return qof_book_test_feature (book, feature);
 }
 
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index ab2b01231..da4e2c843 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -61,6 +61,8 @@ extern "C"
 // For GNC_ID_ROOT_ACCOUNT:
 #include "AccountP.h"
 
+#include "qofbook.hpp"
+
 static QofLogModule log_module = QOF_MOD_ENGINE;
 #define AB_KEY "hbci"
 #define AB_TEMPLATES "template-list"
@@ -1255,6 +1257,32 @@ qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
     }
 }
 
+std::vector<std::string>
+qof_book_get_unknown_features (QofBook *book, const FeaturesTable& features)
+{
+    std::vector<std::string> rv;
+    auto test_feature = [&](const KvpFrameImpl::map_type::value_type& feature)
+    {
+        if (features.find (feature.first) == features.end ())
+            rv.push_back (feature.second->get<const char*>());
+    };
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (book));
+    auto slot = frame->get_slot({GNC_FEATURES});
+    if (slot != nullptr)
+    {
+        frame = slot->get<KvpFrame*>();
+        std::for_each (frame->begin (), frame->end (), test_feature);
+    }
+    return rv;
+}
+
+bool
+qof_book_test_feature (QofBook *book, const char *feature)
+{
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (book));
+    return (frame->get_slot({GNC_FEATURES, feature}) != nullptr);
+}
+
 void
 qof_book_load_options (QofBook *book, GNCOptionLoad load_cb, GNCOptionDB *odb)
 {
diff --git a/libgnucash/engine/qofbook.hpp b/libgnucash/engine/qofbook.hpp
new file mode 100644
index 000000000..402de1711
--- /dev/null
+++ b/libgnucash/engine/qofbook.hpp
@@ -0,0 +1,36 @@
+/********************************************************************\
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+\********************************************************************/
+
+#ifndef __QOF_BOOK__HPP__
+#define __QOF_BOOK__HPP__
+
+#include <vector>
+#include <unordered_map>
+#include <string>
+
+#include "qof.h"
+
+using FeaturesTable = std::unordered_map<std::string,std::string>;
+
+std::vector<std::string>
+qof_book_get_unknown_features (QofBook *book, const FeaturesTable& features);
+bool qof_book_test_feature (QofBook*, const char*);
+
+#endif /* QOF_BOOK_HPP */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6c9be8e2c..3d2a0e7b3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -641,7 +641,7 @@ libgnucash/engine/gncEmployee.c
 libgnucash/engine/gnc-engine.c
 libgnucash/engine/gncEntry.c
 libgnucash/engine/gnc-event.c
-libgnucash/engine/gnc-features.c
+libgnucash/engine/gnc-features.cpp
 libgnucash/engine/gnc-hooks.c
 libgnucash/engine/gncIDSearch.c
 libgnucash/engine/gnc-int128.cpp

commit 8cb8f5067dbc7adfd920099de2b11aa1b92b7657
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Sep 11 16:36:52 2022 -0700

    Remove non-ISO4217 currency codes from gnc-euro table.
    
    They're not reachable because they don't have commodities associated with them.

diff --git a/libgnucash/engine/gnc-euro.c b/libgnucash/engine/gnc-euro.c
index 1a20e1459..411d6209f 100644
--- a/libgnucash/engine/gnc-euro.c
+++ b/libgnucash/engine/gnc-euro.c
@@ -43,35 +43,22 @@ static gnc_euro_rate_struct gnc_euro_rates[] =
 {
     { "ATS",  13.7603 },  /* austrian schilling */
     { "BEF",  40.3399 },  /* belgian franc */
-    { "BFR",  40.3399 },  /* belgian franc */
     { "CYP",  .585274 },  /* cyprus pound */
     { "DEM",  1.95583 },  /* german mark */
-    { "DM",   1.95583 },  /* german mark */
     { "EEK",  15.6466 },  /* Estonian Kroon */
-    { "ESC",  200.482 },  /* portuguese escudo */
     { "ESP",  166.386 },  /* spanish peseta */
     { "EUR",  1.00000 },  /* euro */
-    { "EURO", 1.00000 },  /* euro */
-    { "FF",   6.55957 },  /* french franc */
     { "FIM",  5.94573 },  /* finnmark */
-    { "FMK",  5.94573 },  /* finnmark */
     { "FRF",  6.55957 },  /* french franc */
     { "GRD",  340.750 },  /* greek drachma */
-    { "HFL",  2.20371 },  /* netherland gulden */
     { "HRK",  7.53450 },  /* Croatian kuna */
     { "IEP",  .787564 },  /* irish pound */
-    { "IRP",  .787564 },  /* irish pound */
     { "ITL",  1936.27 },  /* italian lira */
-    { "LFR",  40.3399 },  /* luxembourg franc */
-    { "LIT",  1936.27 },  /* italian lira */
     { "LUF",  40.3399 },  /* luxembourg franc */
     { "LVL",  .702804 },  /* latvian lats */
     { "MTL",  .429300 },  /* maltese lira */
     { "NLG",  2.20371 },  /* netherland gulden */
-    { "PTA",  166.386 },  /* spanish peseta */
     { "PTE",  200.482 },  /* portuguese escudo */
-    { "S",    13.7603 },  /* austrian schilling */
-    { "SCH",  13.7603 },  /* austrian schilling */
     { "SIT",  239.640 },  /* slovenian tolar */
     { "SKK",  30.1260 }   /* slovak koruna */
 };

commit d8417c3cfa235bf8ac46a0881c5e41f8fef54781
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Sep 11 16:29:57 2022 -0700

    Move gnc-euro.[ch] to engine and unit test it.

diff --git a/libgnucash/app-utils/CMakeLists.txt b/libgnucash/app-utils/CMakeLists.txt
index 9a511ed35..6a5714847 100644
--- a/libgnucash/app-utils/CMakeLists.txt
+++ b/libgnucash/app-utils/CMakeLists.txt
@@ -23,7 +23,6 @@ set (app_utils_HEADERS
   gnc-accounting-period.h
   gnc-addr-quickfill.h
   gnc-entry-quickfill.h
-  gnc-euro.h
   gnc-exp-parser.h
   gnc-gsettings.h
   gnc-help-utils.h
@@ -60,7 +59,6 @@ set (app_utils_SOURCES
   gnc-accounting-period.c
   gnc-addr-quickfill.c
   gnc-entry-quickfill.c
-  gnc-euro.c
   gnc-exp-parser.c
   gnc-gsettings.cpp
   gnc-helpers.c
diff --git a/libgnucash/engine/CMakeLists.txt b/libgnucash/engine/CMakeLists.txt
index 8dde8461b..33f9f3d2d 100644
--- a/libgnucash/engine/CMakeLists.txt
+++ b/libgnucash/engine/CMakeLists.txt
@@ -49,6 +49,7 @@ set (engine_HEADERS
   gnc-date.h
   gnc-datetime.hpp
   gnc-engine.h
+  gnc-euro.h
   gnc-event.h
   gnc-features.h
   gnc-hooks.h
@@ -144,6 +145,7 @@ set (engine_SOURCES
   gnc-date.cpp
   gnc-datetime.cpp
   gnc-engine.c
+  gnc-euro.c
   gnc-event.c
   gnc-features.c
   gnc-hooks.c
diff --git a/libgnucash/app-utils/gnc-euro.c b/libgnucash/engine/gnc-euro.c
similarity index 95%
rename from libgnucash/app-utils/gnc-euro.c
rename to libgnucash/engine/gnc-euro.c
index 86bf98e54..1a20e1459 100644
--- a/libgnucash/app-utils/gnc-euro.c
+++ b/libgnucash/engine/gnc-euro.c
@@ -27,8 +27,7 @@
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
-
-#include "gnc-ui-util.h"
+#include "gnc-session.h"
 
 /* local structs */
 typedef struct
@@ -39,7 +38,7 @@ typedef struct
 
 
 /* This array MUST be sorted ! */
-/* The rates are per EURO */
+/* The rates are per EURO and are converted to GncNumeric  */
 static gnc_euro_rate_struct gnc_euro_rates[] =
 {
     { "ATS",  13.7603 },  /* austrian schilling */
@@ -157,7 +156,8 @@ gnc_convert_to_euro(const gnc_commodity * currency, gnc_numeric value)
         rate = double_to_gnc_numeric (result->rate, 100000, GNC_HOW_RND_ROUND_HALF_UP);
 
         /* EC Regulation 1103/97 states we should use "Round half away from zero"
-         * See http://europa.eu/legislation_summaries/economic_and_monetary_affairs/institutional_and_economic_framework/l25025_en.htm */
+         * See https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A31997R1103&qid=1662917247821
+         */
         return gnc_numeric_div (value, rate, 100, GNC_HOW_RND_ROUND_HALF_UP);
     }
 }
@@ -227,9 +227,8 @@ gnc_euro_currency_get_rate (const gnc_commodity *currency)
 gnc_commodity *
 gnc_get_euro (void)
 {
-    gnc_commodity_table *table;
-
-    table = gnc_commodity_table_get_table (gnc_get_current_book ());
+    QofBook* book = qof_session_get_book (gnc_get_current_session ());
+    gnc_commodity_table *table = gnc_commodity_table_get_table (book);
 
     return gnc_commodity_table_lookup (table, GNC_COMMODITY_NS_CURRENCY, "EUR");
 }
diff --git a/libgnucash/app-utils/gnc-euro.h b/libgnucash/engine/gnc-euro.h
similarity index 100%
rename from libgnucash/app-utils/gnc-euro.h
rename to libgnucash/engine/gnc-euro.h
diff --git a/libgnucash/engine/test/CMakeLists.txt b/libgnucash/engine/test/CMakeLists.txt
index 8e44172ff..d1029bb6b 100644
--- a/libgnucash/engine/test/CMakeLists.txt
+++ b/libgnucash/engine/test/CMakeLists.txt
@@ -132,6 +132,9 @@ set(test_qofsession_SOURCES
 gnc_add_test(test-qofsession "${test_qofsession_SOURCES}"
   gtest_engine_INCLUDES gtest_old_engine_LIBS)
 
+gnc_add_test(test-gnc-euro  gtest-gnc-euro.cpp
+  gtest_engine_INCLUDES gtest_old_engine_LIBS)
+
 set(test_gnc_int128_SOURCES
   ${MODULEPATH}/gnc-int128.cpp
   gtest-gnc-int128.cpp)
@@ -197,6 +200,7 @@ gnc_add_test(test-qofquerycore "${test_qofquerycore_SOURCES}"
 
 set(test_engine_SOURCES_DIST
         dummy.cpp
+        gtest-gnc-euro.cpp
         gtest-gnc-int128.cpp
         gtest-gnc-rational.cpp
         gtest-gnc-numeric.cpp
diff --git a/libgnucash/engine/test/gtest-gnc-euro.cpp b/libgnucash/engine/test/gtest-gnc-euro.cpp
new file mode 100644
index 000000000..4777d09aa
--- /dev/null
+++ b/libgnucash/engine/test/gtest-gnc-euro.cpp
@@ -0,0 +1,228 @@
+/********************************************************************
+ * gtest-gnc-euro.cpp -- unit tests for Euro currency functions     *
+ * Copyright 2022 John Ralls <jralls at ceridwen.us>                   *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program is distributed in the hope that it will be useful,  *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
+ * GNU General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+\********************************************************************/
+
+#include <gtest/gtest.h>
+#include "../gnc-numeric.hpp"
+extern "C"
+{
+#include <config.h>
+#include "../gnc-euro.h"
+#include "../gnc-commodity.h"
+#include "../gnc-session.h"
+}
+
+class Currencies : public ::testing::Test
+{
+protected:
+    gnc_commodity_table* m_table;
+    Currencies() : m_table{gnc_commodity_table_new()}
+    {
+        QofBook* book = qof_session_get_book (gnc_get_current_session ());
+        qof_book_set_data (book, GNC_COMMODITY_TABLE, m_table);
+
+        if (!gnc_commodity_table_add_default_data(m_table, book))
+            exit(-1);
+    }
+
+    ~Currencies() { gnc_commodity_table_destroy(m_table); }
+};
+
+static const char* currency{"CURRENCY"};
+
+TEST_F(Currencies, is_euro_currency)
+{
+    auto usd = gnc_commodity_table_lookup(m_table, currency, "USD");
+    auto eur = gnc_commodity_table_lookup(m_table, currency, "EUR");
+    auto pte = gnc_commodity_table_lookup(m_table, currency, "PTE");
+
+    ASSERT_NE(eur, nullptr);
+    ASSERT_NE(usd, nullptr);
+    ASSERT_NE(pte, nullptr);
+
+    EXPECT_TRUE(gnc_is_euro_currency(pte));
+    EXPECT_TRUE(gnc_is_euro_currency(eur));
+    EXPECT_FALSE(gnc_is_euro_currency(usd));
+}
+
+TEST_F(Currencies, convert_to_euro)
+{
+    gnc_numeric value{314159, 100};
+    gnc_numeric cyp_eur_amount{536776, 100}; // calc gets 5367.76
+    auto cyp{gnc_commodity_table_lookup(m_table, currency, "CYP")};
+    ASSERT_NE(cyp, nullptr);
+    auto amount{gnc_convert_to_euro(cyp, value)};
+    EXPECT_EQ(cyp_eur_amount.num, amount.num);
+    EXPECT_EQ(cyp_eur_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(cyp_eur_amount, amount));
+
+    gnc_numeric grd_eur_amount{922, 100};
+    auto grd{gnc_commodity_table_lookup(m_table, currency, "GRD")};
+    amount = gnc_convert_to_euro(grd, value);
+    EXPECT_EQ(grd_eur_amount.num, amount.num);
+    EXPECT_EQ(grd_eur_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(grd_eur_amount, amount));
+
+    gnc_numeric itl_eur_amount{162, 100};
+    auto itl{gnc_commodity_table_lookup(m_table, currency, "ITL")};
+    amount = gnc_convert_to_euro(itl, value);
+    EXPECT_EQ(itl_eur_amount.num, amount.num);
+    EXPECT_EQ(itl_eur_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(itl_eur_amount, amount));
+
+    gnc_numeric nlg_eur_amount{142559, 100};
+    auto nlg{gnc_commodity_table_lookup(m_table, currency, "NLG")};
+    amount = gnc_convert_to_euro(nlg, value);
+    EXPECT_EQ(nlg_eur_amount.num, amount.num);
+    EXPECT_EQ(nlg_eur_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(nlg_eur_amount, amount));
+
+    auto eur{gnc_commodity_table_lookup(m_table, currency, "EUR")};
+    ASSERT_NE(eur, nullptr);
+    EXPECT_TRUE(gnc_numeric_equal(value,
+                               gnc_convert_to_euro(eur, value)));
+}
+
+TEST_F(Currencies, convert_from_euro)
+{
+    gnc_numeric value{314159, 100}; //.787564 * 3141.59 = 2472.20
+    gnc_numeric eur_iep_amount{247419, 100};
+    auto iep{gnc_commodity_table_lookup(m_table, currency, "IEP")};
+    ASSERT_NE(iep, nullptr);
+    auto amount{gnc_convert_from_euro(iep, value)};
+    EXPECT_EQ(eur_iep_amount.num, amount.num);
+    EXPECT_EQ(eur_iep_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(eur_iep_amount, amount));
+
+    gnc_numeric eur_itl_amount{6082966, 1};
+    auto itl{gnc_commodity_table_lookup(m_table, currency, "ITL")};
+    amount = gnc_convert_from_euro(itl, value);
+    EXPECT_EQ(eur_itl_amount.num, amount.num);
+    EXPECT_EQ(eur_itl_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(eur_itl_amount, amount));
+
+    gnc_numeric eur_fim_amount{1867905, 100};
+    auto fim{gnc_commodity_table_lookup(m_table, currency, "FIM")};
+    EXPECT_NE(fim, nullptr);
+    amount = gnc_convert_from_euro(fim, value);
+    EXPECT_EQ(eur_fim_amount.num, amount.num);
+    EXPECT_EQ(eur_fim_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(eur_fim_amount, amount));
+
+    gnc_numeric eur_dm_amount{614442, 100};
+    auto dm{gnc_commodity_table_lookup(m_table, currency, "DEM")};
+    EXPECT_NE(dm, nullptr);
+    amount = gnc_convert_from_euro(dm, value);
+    EXPECT_EQ(eur_dm_amount.num, amount.num);
+    EXPECT_EQ(eur_dm_amount.denom, amount.denom);
+    EXPECT_TRUE(gnc_numeric_equal(eur_dm_amount, amount));
+
+    auto eur{gnc_commodity_table_lookup(m_table, currency, "EUR")};
+    EXPECT_TRUE(gnc_numeric_equal(value,
+                               gnc_convert_from_euro(eur, value)));
+}
+
+TEST_F(Currencies, euro_currency_get_rate)
+{
+    auto ats{gnc_commodity_table_lookup(m_table, currency, "ATS")};
+    ASSERT_NE(ats, nullptr);
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{137603, 10000},
+                                  gnc_euro_currency_get_rate(ats)));
+
+    auto bef{gnc_commodity_table_lookup(m_table, currency, "BEF")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{403399, 10000},
+                                  gnc_euro_currency_get_rate(bef)));
+
+    auto cyp{gnc_commodity_table_lookup(m_table, currency, "CYP")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{585274, 1000000},
+                                  gnc_euro_currency_get_rate(cyp)));
+
+    auto dem{gnc_commodity_table_lookup(m_table, currency, "DEM")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{195583, 100000},
+                                  gnc_euro_currency_get_rate(dem)));
+
+    auto eek{gnc_commodity_table_lookup(m_table, currency, "EEK")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{156466, 10000},
+                                  gnc_euro_currency_get_rate(eek)));
+
+    auto esp{gnc_commodity_table_lookup(m_table, currency, "ESP")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{166386, 1000},
+                                  gnc_euro_currency_get_rate(esp)));
+
+    auto eur{gnc_commodity_table_lookup(m_table, currency, "EUR")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{100000, 100000},
+                                  gnc_euro_currency_get_rate(eur)));
+
+    auto fim{gnc_commodity_table_lookup(m_table, currency, "FIM")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{594573, 100000},
+                                  gnc_euro_currency_get_rate(fim)));
+
+
+    auto frf{gnc_commodity_table_lookup(m_table, currency, "FRF")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{655957, 100000},
+                                  gnc_euro_currency_get_rate(frf)));
+
+    auto grd{gnc_commodity_table_lookup(m_table, currency, "GRD")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{340750, 1000},
+                                  gnc_euro_currency_get_rate(grd)));
+
+
+    auto hrk{gnc_commodity_table_lookup(m_table, currency, "HRK")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{753450, 100000},
+                                  gnc_euro_currency_get_rate(hrk)));
+
+    auto iep{gnc_commodity_table_lookup(m_table, currency, "IEP")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{787564, 1000000},
+                                  gnc_euro_currency_get_rate(iep)));
+
+    auto itl{gnc_commodity_table_lookup(m_table, currency, "ITL")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{193627, 100},
+                                  gnc_euro_currency_get_rate(itl)));
+
+    auto luf{gnc_commodity_table_lookup(m_table, currency, "LUF")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{403399, 10000},
+                                  gnc_euro_currency_get_rate(luf)));
+
+    auto lvl{gnc_commodity_table_lookup(m_table, currency, "LVL")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{702804, 1000000},
+                                  gnc_euro_currency_get_rate(lvl)));
+
+    auto mtl{gnc_commodity_table_lookup(m_table, currency, "MTL")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{429300, 1000000},
+                                  gnc_euro_currency_get_rate(mtl)));
+
+    auto nlg{gnc_commodity_table_lookup(m_table, currency, "NLG")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{220371, 100000},
+                                  gnc_euro_currency_get_rate(nlg)));
+
+    auto pte{gnc_commodity_table_lookup(m_table, currency, "PTE")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{200482, 1000},
+                                  gnc_euro_currency_get_rate(pte)));
+
+    auto sit{gnc_commodity_table_lookup(m_table, currency, "SIT")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{239640, 1000},
+                                  gnc_euro_currency_get_rate(sit)));
+
+    auto skk{gnc_commodity_table_lookup(m_table, currency, "SKK")};
+    EXPECT_TRUE(gnc_numeric_equal(gnc_numeric{301260, 10000},
+                                  gnc_euro_currency_get_rate(skk)));
+
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6c9be8e2c..6795e6f2b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -534,7 +534,6 @@ libgnucash/app-utils/gnc-accounting-period.c
 libgnucash/app-utils/gnc-account-merge.c
 libgnucash/app-utils/gnc-addr-quickfill.c
 libgnucash/app-utils/gnc-entry-quickfill.c
-libgnucash/app-utils/gnc-euro.c
 libgnucash/app-utils/gnc-exp-parser.c
 libgnucash/app-utils/gnc-gsettings.cpp
 libgnucash/app-utils/gnc-helpers.c
@@ -640,6 +639,7 @@ libgnucash/engine/gnc-datetime.cpp
 libgnucash/engine/gncEmployee.c
 libgnucash/engine/gnc-engine.c
 libgnucash/engine/gncEntry.c
+libgnucash/engine/gnc-euro.c
 libgnucash/engine/gnc-event.c
 libgnucash/engine/gnc-features.c
 libgnucash/engine/gnc-hooks.c

commit 2774f8f88c7cb84b2ef3e2f2735bbca84f17a91a
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Sep 11 10:35:43 2022 -0700

    Bug 798614 - Croatia to join the Euro
    
    Add HRK to the conversion array.

diff --git a/libgnucash/app-utils/gnc-euro.c b/libgnucash/app-utils/gnc-euro.c
index b541100df..86bf98e54 100644
--- a/libgnucash/app-utils/gnc-euro.c
+++ b/libgnucash/app-utils/gnc-euro.c
@@ -59,6 +59,7 @@ static gnc_euro_rate_struct gnc_euro_rates[] =
     { "FRF",  6.55957 },  /* french franc */
     { "GRD",  340.750 },  /* greek drachma */
     { "HFL",  2.20371 },  /* netherland gulden */
+    { "HRK",  7.53450 },  /* Croatian kuna */
     { "IEP",  .787564 },  /* irish pound */
     { "IRP",  .787564 },  /* irish pound */
     { "ITL",  1936.27 },  /* italian lira */
diff --git a/libgnucash/engine/iso-4217-currencies.xml b/libgnucash/engine/iso-4217-currencies.xml
index 93c22311f..2aa62d136 100644
--- a/libgnucash/engine/iso-4217-currencies.xml
+++ b/libgnucash/engine/iso-4217-currencies.xml
@@ -1195,6 +1195,7 @@
   local-symbol="L"
 />
 <!-- "HRK" - "Croatian Kuna"
+     2023-01-01 "EUR" 7.53400
 -->
 <currency
   isocode="HRK"



Summary of changes:
 gnucash/gnome/dialog-report-style-sheet.cpp        |   2 +-
 libgnucash/app-utils/CMakeLists.txt                |   2 -
 libgnucash/engine/CMakeLists.txt                   |   5 +-
 libgnucash/{app-utils => engine}/gnc-euro.c        |  27 +--
 libgnucash/{app-utils => engine}/gnc-euro.h        |   0
 .../engine/{gnc-features.c => gnc-features.cpp}    | 141 +++----------
 libgnucash/engine/iso-4217-currencies.xml          |   1 +
 libgnucash/engine/qofbook.cpp                      |  51 +++--
 libgnucash/engine/qofbook.h                        |   2 +-
 libgnucash/engine/{gnc-session.h => qofbook.hpp}   |  17 +-
 libgnucash/engine/test/CMakeLists.txt              |   4 +
 libgnucash/engine/test/gtest-gnc-euro.cpp          | 228 +++++++++++++++++++++
 libgnucash/engine/test/test-qofbook.c              |   4 +
 po/POTFILES.in                                     |   4 +-
 14 files changed, 330 insertions(+), 158 deletions(-)
 rename libgnucash/{app-utils => engine}/gnc-euro.c (88%)
 rename libgnucash/{app-utils => engine}/gnc-euro.h (100%)
 rename libgnucash/engine/{gnc-features.c => gnc-features.cpp} (52%)
 copy libgnucash/engine/{gnc-session.h => qofbook.hpp} (78%)
 create mode 100644 libgnucash/engine/test/gtest-gnc-euro.cpp



More information about the gnucash-changes mailing list