gnucash stable: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Sat Sep 16 08:51:00 EDT 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/d38bfe0e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5a8ee33f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/49c3c5dc (commit)
	 via  https://github.com/Gnucash/gnucash/commit/757c1cac (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0191b5f7 (commit)
	from  https://github.com/Gnucash/gnucash/commit/a81bc72f (commit)



commit d38bfe0e9d78f238af68775b0d6707b4239e02a6
Merge: a81bc72fb1 5a8ee33f06
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Sat Sep 16 20:50:17 2023 +0800

    Merge branch 'stable-autoclear' into stable #1769


commit 5a8ee33f064de69d2a7da537377dd76349d72046
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Thu Sep 14 22:30:48 2023 +0800

    [test-autoclear] plug memory leaks

diff --git a/gnucash/gnome-utils/test/test-autoclear.cpp b/gnucash/gnome-utils/test/test-autoclear.cpp
index 6a41b267ca..a13d92512e 100644
--- a/gnucash/gnome-utils/test/test-autoclear.cpp
+++ b/gnucash/gnome-utils/test/test-autoclear.cpp
@@ -145,12 +145,15 @@ TEST_P(AutoClearTest, DoesAutoClear) {
             xaccSplitSetReconcile(split, CREC);
         }
 
+        g_list_free (splits_to_clear);
+
         ASSERT_STREQ(err, t.expectedErr);
         if (t.expectedErr == NULL) {
             gnc_numeric c = xaccAccountGetClearedBalance(m_account);
             ASSERT_EQ(c.num, t.amount);
             ASSERT_EQ(c.denom, DENOM);
         }
+        g_free (err);
     }
 }
 

commit 49c3c5dc2ebffb9246062942ac20d37152c46caf
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Sep 13 07:20:39 2023 +0800

    [gnc-autoclear] Store gnc_numeric.num only in GHashTable
    
    no need for extra alloc

diff --git a/gnucash/gnome-utils/gnc-autoclear.c b/gnucash/gnome-utils/gnc-autoclear.c
index 05a370e525..b2c249d744 100644
--- a/gnucash/gnome-utils/gnc-autoclear.c
+++ b/gnucash/gnome-utils/gnc-autoclear.c
@@ -47,19 +47,6 @@ typedef enum
 
 #define log_module "autoclear"
 
-static gboolean
-numeric_equal (gnc_numeric *n1, gnc_numeric *n2)
-{
-    return gnc_numeric_equal (*n1, *n2);
-}
-
-static guint
-numeric_hash (gnc_numeric *n1)
-{
-    gdouble d1 = gnc_numeric_to_double (*n1);
-    return g_double_hash (&d1);
-}
-
 typedef struct
 {
     GList *worklist;
@@ -81,7 +68,7 @@ make_workitem (GHashTable *hash, gnc_numeric amount,
 {
     WorkItem *item = g_new0 (WorkItem, 1);
     item->reachable_amount = amount;
-    if (g_hash_table_lookup (hash, &amount) || splits == DUP_LIST)
+    if (g_hash_table_lookup (hash, GINT_TO_POINTER (amount.num)) || splits == DUP_LIST)
         item->list_of_splits = DUP_LIST;
     else
         item->list_of_splits = g_list_prepend (g_list_copy (splits), split);
@@ -89,19 +76,19 @@ make_workitem (GHashTable *hash, gnc_numeric amount,
 }
 
 static void
-sack_foreach_func (gnc_numeric *thisvalue, GList *splits, sack_data *data)
+sack_foreach_func (gint thisvalue_num, GList *splits, sack_data *data)
 {
     gnc_numeric itemval = xaccSplitGetAmount (data->split);
-    gnc_numeric new_value = gnc_numeric_add_fixed (*thisvalue, itemval);
+    gnc_numeric this_value = gnc_numeric_create (thisvalue_num, itemval.denom);
+    gnc_numeric new_value = gnc_numeric_add_fixed (this_value, itemval);
     WorkItem *item = make_workitem (data->sack, new_value, data->split, splits);
 
     data->worklist = g_list_prepend (data->worklist, item);
 }
 
 static void
-sack_free (gnc_numeric *thisvalue, GList *splits, sack_data *data)
+sack_free (gpointer thisvalue_num, GList *splits, sack_data *data)
 {
-    g_free (thisvalue);
     if (splits != DUP_LIST)
         g_list_free (splits);
 }
@@ -109,14 +96,14 @@ sack_free (gnc_numeric *thisvalue, GList *splits, sack_data *data)
 static void
 process_work (WorkItem *item, GHashTable *sack)
 {
-    GList *existing = g_hash_table_lookup (sack, &item->reachable_amount);
+    GList *existing = g_hash_table_lookup (sack, GINT_TO_POINTER(item->reachable_amount.num));
     if (existing && existing != DUP_LIST)
     {
         DEBUG ("removing existing for %6.2f\n",
                gnc_numeric_to_double (item->reachable_amount));
         g_list_free (existing);
     }
-    g_hash_table_insert (sack, &item->reachable_amount, item->list_of_splits);
+    g_hash_table_insert (sack, GINT_TO_POINTER(item->reachable_amount.num), item->list_of_splits);
 }
 
 gboolean
@@ -131,18 +118,23 @@ gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
     g_return_val_if_fail (GNC_IS_ACCOUNT (account), FALSE);
     g_return_val_if_fail (splits != NULL, FALSE);
 
-    sack = g_hash_table_new ((GHashFunc) numeric_hash, (GEqualFunc) numeric_equal);
+    sack = g_hash_table_new (NULL, NULL);
     DUP_LIST = g_list_prepend (NULL, NULL);
 
     /* Extract which splits are not cleared and compute the amount we have to clear */
     for (GList *node = xaccAccountGetSplitList (account); node; node = node->next)
     {
         Split *split = (Split *)node->data;
+        gnc_numeric amount = xaccSplitGetAmount (split);
 
+        if (amount.denom != toclear_value.denom)
+        {
+            g_set_error (error, autoclear_quark, AUTOCLEAR_NOP, "Split amount and toclear amount have different denoms");
+            goto skip_knapsack;
+        }
         if (xaccSplitGetReconcile (split) != NREC)
-            toclear_value = gnc_numeric_sub_fixed
-                (toclear_value, xaccSplitGetAmount (split));
-        else if (gnc_numeric_zero_p (xaccSplitGetAmount (split)))
+            toclear_value = gnc_numeric_sub_fixed (toclear_value, amount);
+        else if (gnc_numeric_zero_p (amount))
             DEBUG ("skipping zero-amount split %p", split);
         else if (end_date != INT64_MAX &&
                  xaccTransGetDate (xaccSplitGetParent (split)) > end_date)
@@ -179,7 +171,7 @@ gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
                          _("Too many uncleared splits"));
             goto skip_knapsack;
         }
-        else if (g_hash_table_lookup (sack, &toclear_value) == DUP_LIST)
+        else if (g_hash_table_lookup (sack, GINT_TO_POINTER(toclear_value.num)) == DUP_LIST)
         {
             g_set_error (error, autoclear_quark, AUTOCLEAR_MULTIPLE,
                          _("Cannot uniquely clear splits. Found multiple possibilities."));
@@ -187,7 +179,7 @@ gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
         }
     }
 
-    toclear_list = g_hash_table_lookup (sack, &toclear_value);
+    toclear_list = g_hash_table_lookup (sack, GINT_TO_POINTER(toclear_value.num));
 
     /* Check solution */
     if (!toclear_list)

commit 757c1cac3156ade45458333fabf677948bc04eaa
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Sep 13 07:02:12 2023 +0800

    [gnc-autoclear] [upgrade] add ability to clear same-amount splits

diff --git a/gnucash/gnome-utils/gnc-autoclear.c b/gnucash/gnome-utils/gnc-autoclear.c
index fbd5a2dffa..05a370e525 100644
--- a/gnucash/gnome-utils/gnc-autoclear.c
+++ b/gnucash/gnome-utils/gnc-autoclear.c
@@ -2,6 +2,7 @@
  * gnc-autoclear.c -- Knapsack algorithm functions                  *
  *                                                                  *
  * Copyright 2020 Cristian Klein <cristian at kleinlabs.eu>            *
+ * Modified  2021 Christopher Lam to clear same-amount splits       *
  *                                                                  *
  * This program is free software; you can redistribute it and/or    *
  * modify it under the terms of the GNU General Public License as   *
@@ -27,6 +28,7 @@
 
 #include "Account.h"
 #include "Split.h"
+#include "Transaction.h"
 #include "gncOwner.h"
 #include "qof.h"
 #include "gnc-autoclear.h"
@@ -43,36 +45,78 @@ typedef enum
 
 #define MAXIMUM_SACK_SIZE 1000000
 
+#define log_module "autoclear"
+
 static gboolean
-ght_gnc_numeric_equal(gconstpointer v1, gconstpointer v2)
+numeric_equal (gnc_numeric *n1, gnc_numeric *n2)
 {
-    gnc_numeric n1 = *(gnc_numeric *)v1, n2 = *(gnc_numeric *)v2;
-    return gnc_numeric_equal(n1, n2);
+    return gnc_numeric_equal (*n1, *n2);
 }
 
 static guint
-ght_gnc_numeric_hash(gconstpointer v1)
+numeric_hash (gnc_numeric *n1)
 {
-    gnc_numeric n1 = *(gnc_numeric *)v1;
-    gdouble d1 = gnc_numeric_to_double(n1);
+    gdouble d1 = gnc_numeric_to_double (*n1);
     return g_double_hash (&d1);
 }
 
-typedef struct _sack_foreach_data_t
+typedef struct
+{
+    GList *worklist;
+    GHashTable *sack;
+    Split *split;
+} sack_data;
+
+typedef struct
 {
-    gnc_numeric split_value;
-    GList *reachable_list;
-} *sack_foreach_data_t;
+    gnc_numeric reachable_amount;
+    GList *list_of_splits;
+} WorkItem;
+
+static GList *DUP_LIST;
+
+static WorkItem *
+make_workitem (GHashTable *hash, gnc_numeric amount,
+               Split *split, GList *splits)
+{
+    WorkItem *item = g_new0 (WorkItem, 1);
+    item->reachable_amount = amount;
+    if (g_hash_table_lookup (hash, &amount) || splits == DUP_LIST)
+        item->list_of_splits = DUP_LIST;
+    else
+        item->list_of_splits = g_list_prepend (g_list_copy (splits), split);
+    return item;
+}
+
+static void
+sack_foreach_func (gnc_numeric *thisvalue, GList *splits, sack_data *data)
+{
+    gnc_numeric itemval = xaccSplitGetAmount (data->split);
+    gnc_numeric new_value = gnc_numeric_add_fixed (*thisvalue, itemval);
+    WorkItem *item = make_workitem (data->sack, new_value, data->split, splits);
+
+    data->worklist = g_list_prepend (data->worklist, item);
+}
 
-static void sack_foreach_func(gpointer key, gpointer value, gpointer user_data)
+static void
+sack_free (gnc_numeric *thisvalue, GList *splits, sack_data *data)
 {
-    sack_foreach_data_t data = (sack_foreach_data_t) user_data;
-    gnc_numeric thisvalue = *(gnc_numeric *) key;
-    gnc_numeric reachable_value = gnc_numeric_add_fixed (thisvalue, data->split_value);
-    gnc_numeric* new_value = g_new(gnc_numeric, 1);
+    g_free (thisvalue);
+    if (splits != DUP_LIST)
+        g_list_free (splits);
+}
 
-    *new_value = reachable_value;
-    data->reachable_list = g_list_prepend(data->reachable_list, new_value);
+static void
+process_work (WorkItem *item, GHashTable *sack)
+{
+    GList *existing = g_hash_table_lookup (sack, &item->reachable_amount);
+    if (existing && existing != DUP_LIST)
+    {
+        DEBUG ("removing existing for %6.2f\n",
+               gnc_numeric_to_double (item->reachable_amount));
+        g_list_free (existing);
+    }
+    g_hash_table_insert (sack, &item->reachable_amount, item->list_of_splits);
 }
 
 gboolean
@@ -82,25 +126,29 @@ gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
 {
     GList *nc_list = NULL, *toclear_list = NULL;
     GHashTable *sack;
-    gboolean success = FALSE;
     GQuark autoclear_quark = g_quark_from_static_string ("autoclear");
-    guint sack_size = 0;
 
     g_return_val_if_fail (GNC_IS_ACCOUNT (account), FALSE);
+    g_return_val_if_fail (splits != NULL, FALSE);
 
-    sack = g_hash_table_new_full (ght_gnc_numeric_hash, ght_gnc_numeric_equal,
-                                  g_free, NULL);
+    sack = g_hash_table_new ((GHashFunc) numeric_hash, (GEqualFunc) numeric_equal);
+    DUP_LIST = g_list_prepend (NULL, NULL);
 
     /* Extract which splits are not cleared and compute the amount we have to clear */
     for (GList *node = xaccAccountGetSplitList (account); node; node = node->next)
     {
         Split *split = (Split *)node->data;
 
-        if (xaccSplitGetReconcile (split) == NREC)
-            nc_list = g_list_prepend (nc_list, split);
-        else
+        if (xaccSplitGetReconcile (split) != NREC)
             toclear_value = gnc_numeric_sub_fixed
                 (toclear_value, xaccSplitGetAmount (split));
+        else if (gnc_numeric_zero_p (xaccSplitGetAmount (split)))
+            DEBUG ("skipping zero-amount split %p", split);
+        else if (end_date != INT64_MAX &&
+                 xaccTransGetDate (xaccSplitGetParent (split)) > end_date)
+            DEBUG ("skipping split after statement_date %p", split);
+        else
+            nc_list = g_list_prepend (nc_list, split);
     }
 
     if (gnc_numeric_zero_p (toclear_value))
@@ -109,95 +157,55 @@ gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
                      _("Account is already at Auto-Clear Balance."));
         goto skip_knapsack;
     }
-
-    /* Run knapsack */
-    /* Entries in the hash table are:
-     *  - key   = amount to which we know how to clear (freed by GHashTable)
-     *  - value = last split we used to clear this amount (not managed by GHashTable)
-     */
-    for (GList *node = nc_list; node; node = node->next)
+    else if (!nc_list)
     {
-        Split *split = (Split *)node->data;
-        gnc_numeric split_value = xaccSplitGetAmount (split);
-        gnc_numeric *new_value = g_new(gnc_numeric, 1);
-
-        struct _sack_foreach_data_t s_data[1];
-        s_data->split_value = split_value;
-        s_data->reachable_list = NULL;
-
-        /* For each value in the sack, compute a new reachable value */
-        g_hash_table_foreach (sack, sack_foreach_func, s_data);
-
-        /* Add the value of the split itself to the reachable_list */
-        *new_value = split_value;
-        s_data->reachable_list = g_list_prepend
-            (s_data->reachable_list, new_value);
-
-        /* Add everything to the sack, looking out for duplicates */
-        for (GList *s_node = s_data->reachable_list; s_node; s_node = s_node->next)
-        {
-            gnc_numeric *reachable_value = s_node->data;
-
-            /* Check if it already exists */
-            if (g_hash_table_lookup_extended (sack, reachable_value, NULL, NULL))
-            {
-                /* If yes, we are in trouble, we reached an amount
-                   using two solutions */
-                g_hash_table_insert (sack, reachable_value, NULL);
-            }
-            else
-            {
-                g_hash_table_insert (sack, reachable_value, split);
-                sack_size++;
-
-                if (sack_size > MAXIMUM_SACK_SIZE)
-                {
-                    g_set_error (error, autoclear_quark, AUTOCLEAR_OVERLOAD,
-                                 _("Too many uncleared splits"));
-                    goto skip_knapsack;
-                }
-            }
-        }
-        g_list_free (s_data->reachable_list);
+        g_set_error (error, autoclear_quark, AUTOCLEAR_NOP,
+                     _("No uncleared splits found."));
+        goto skip_knapsack;
     }
 
-    /* Check solution */
-    while (!gnc_numeric_zero_p (toclear_value))
+    for (GList *node = nc_list; node; node = node->next)
     {
-        Split *split = NULL;
+        Split *split = (Split *)node->data;
+        WorkItem *item = make_workitem (sack, xaccSplitGetAmount (split), split, NULL);
+        sack_data s_data = { g_list_prepend (NULL, item), sack, split };
 
-        if (!g_hash_table_lookup_extended (sack, &toclear_value,
-                                           NULL, (gpointer) &split))
+        g_hash_table_foreach (sack, (GHFunc) sack_foreach_func, &s_data);
+        g_list_foreach (s_data.worklist, (GFunc) process_work, sack);
+        g_list_free_full (s_data.worklist, g_free);
+        if (g_hash_table_size (sack) > MAXIMUM_SACK_SIZE)
         {
-            g_set_error (error, autoclear_quark, AUTOCLEAR_UNABLE,
-                         _("The selected amount cannot be cleared."));
+            g_set_error (error, autoclear_quark, AUTOCLEAR_OVERLOAD,
+                         _("Too many uncleared splits"));
             goto skip_knapsack;
         }
-
-        if (!split)
+        else if (g_hash_table_lookup (sack, &toclear_value) == DUP_LIST)
         {
             g_set_error (error, autoclear_quark, AUTOCLEAR_MULTIPLE,
                          _("Cannot uniquely clear splits. Found multiple possibilities."));
             goto skip_knapsack;
         }
+    }
 
-        toclear_list = g_list_prepend (toclear_list, split);
-        toclear_value = gnc_numeric_sub_fixed (toclear_value,
-                                               xaccSplitGetAmount (split));
+    toclear_list = g_hash_table_lookup (sack, &toclear_value);
+
+    /* Check solution */
+    if (!toclear_list)
+    {
+        g_set_error (error, autoclear_quark, AUTOCLEAR_UNABLE,
+                     _("The selected amount cannot be cleared."));
+        goto skip_knapsack;
     }
-    success = TRUE;
+    else
+        /* copy GList because GHashTable value will be freed */
+        *splits = g_list_copy (toclear_list);
 
  skip_knapsack:
+    g_hash_table_foreach (sack, (GHFunc) sack_free, NULL);
     g_hash_table_destroy (sack);
     g_list_free (nc_list);
+    g_list_free (DUP_LIST);
 
-    if (!success)
-    {
-        g_list_free (toclear_list);
-        toclear_list = NULL;
-    }
-
-    *splits = toclear_list;
     return (toclear_list != NULL);
 }
 
@@ -209,8 +217,8 @@ gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
     GError *error = NULL;
     GList *splits = NULL;
 
-    gnc_autoclear_get_splits (account, toclear_value,
-                              &splits, &error);
+    gnc_autoclear_get_splits (account, toclear_value, INT64_MAX,
+                              &splits, &error, NULL);
 
     if (error)
     {
diff --git a/gnucash/gnome-utils/test/test-autoclear.cpp b/gnucash/gnome-utils/test/test-autoclear.cpp
index 288074e900..6a41b267ca 100644
--- a/gnucash/gnome-utils/test/test-autoclear.cpp
+++ b/gnucash/gnome-utils/test/test-autoclear.cpp
@@ -100,9 +100,8 @@ TestCase ambiguousTestCase = {
         { -10, "Cannot uniquely clear splits. Found multiple possibilities." },
         { -20, "Cannot uniquely clear splits. Found multiple possibilities." },
 
-        // Forbid auto-clear to be too smart. We expect the user to manually deal
-        // with such situations.
-        { -30, "Cannot uniquely clear splits. Found multiple possibilities." },
+        // -30 can be cleared by returning all three -10 splits
+        { -30, nullptr },
     },
 };
 

commit 0191b5f70b20eb8118775163bfbd408289d91333
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Fri Oct 29 22:28:09 2021 +0800

    [gnc-autoclear] use GError to signal errors

diff --git a/gnucash/gnome-utils/gnc-autoclear.c b/gnucash/gnome-utils/gnc-autoclear.c
index 34cb35b8ac..fbd5a2dffa 100644
--- a/gnucash/gnome-utils/gnc-autoclear.c
+++ b/gnucash/gnome-utils/gnc-autoclear.c
@@ -33,6 +33,14 @@
 
 /* the following functions are used in window-autoclear: */
 
+typedef enum
+{
+    AUTOCLEAR_OVERLOAD = 1,
+    AUTOCLEAR_UNABLE,
+    AUTOCLEAR_MULTIPLE,
+    AUTOCLEAR_NOP,
+} autoclear_error_type;
+
 #define MAXIMUM_SACK_SIZE 1000000
 
 static gboolean
@@ -67,16 +75,18 @@ static void sack_foreach_func(gpointer key, gpointer value, gpointer user_data)
     data->reachable_list = g_list_prepend(data->reachable_list, new_value);
 }
 
-GList *
-gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
-                                  gchar **errmsg)
+gboolean
+gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
+                          time64 end_date,
+                          GList **splits, GError **error, GtkLabel *label)
 {
     GList *nc_list = NULL, *toclear_list = NULL;
     GHashTable *sack;
-    gchar *msg = NULL;
+    gboolean success = FALSE;
+    GQuark autoclear_quark = g_quark_from_static_string ("autoclear");
     guint sack_size = 0;
 
-    g_return_val_if_fail (GNC_IS_ACCOUNT (account), NULL);
+    g_return_val_if_fail (GNC_IS_ACCOUNT (account), FALSE);
 
     sack = g_hash_table_new_full (ght_gnc_numeric_hash, ght_gnc_numeric_equal,
                                   g_free, NULL);
@@ -95,7 +105,8 @@ gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
 
     if (gnc_numeric_zero_p (toclear_value))
     {
-        msg = _("Account is already at Auto-Clear Balance.");
+        g_set_error (error, autoclear_quark, AUTOCLEAR_NOP,
+                     _("Account is already at Auto-Clear Balance."));
         goto skip_knapsack;
     }
 
@@ -141,7 +152,8 @@ gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
 
                 if (sack_size > MAXIMUM_SACK_SIZE)
                 {
-                    msg = _("Too many uncleared splits");
+                    g_set_error (error, autoclear_quark, AUTOCLEAR_OVERLOAD,
+                                 _("Too many uncleared splits"));
                     goto skip_knapsack;
                 }
             }
@@ -157,13 +169,15 @@ gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
         if (!g_hash_table_lookup_extended (sack, &toclear_value,
                                            NULL, (gpointer) &split))
         {
-            msg = _("The selected amount cannot be cleared.");
+            g_set_error (error, autoclear_quark, AUTOCLEAR_UNABLE,
+                         _("The selected amount cannot be cleared."));
             goto skip_knapsack;
         }
 
         if (!split)
         {
-            msg = _("Cannot uniquely clear splits. Found multiple possibilities.");
+            g_set_error (error, autoclear_quark, AUTOCLEAR_MULTIPLE,
+                         _("Cannot uniquely clear splits. Found multiple possibilities."));
             goto skip_knapsack;
         }
 
@@ -171,18 +185,40 @@ gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
         toclear_value = gnc_numeric_sub_fixed (toclear_value,
                                                xaccSplitGetAmount (split));
     }
+    success = TRUE;
 
  skip_knapsack:
     g_hash_table_destroy (sack);
     g_list_free (nc_list);
 
-    if (msg)
+    if (!success)
     {
-        *errmsg = g_strdup (msg);
         g_list_free (toclear_list);
+        toclear_list = NULL;
+    }
+
+    *splits = toclear_list;
+    return (toclear_list != NULL);
+}
+
+
+GList *
+gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
+                                  gchar **errmsg)
+{
+    GError *error = NULL;
+    GList *splits = NULL;
+
+    gnc_autoclear_get_splits (account, toclear_value,
+                              &splits, &error);
+
+    if (error)
+    {
+        *errmsg = g_strdup (error->message);
+        g_error_free (error);
         return NULL;
     }
 
     *errmsg = NULL;
-    return toclear_list;
+    return splits;
 }
diff --git a/gnucash/gnome-utils/gnc-autoclear.h b/gnucash/gnome-utils/gnc-autoclear.h
index ac9807d12e..1f53629748 100644
--- a/gnucash/gnome-utils/gnc-autoclear.h
+++ b/gnucash/gnome-utils/gnc-autoclear.h
@@ -25,6 +25,8 @@
 #define GNC_AUTOCLEAR_H
 
 #include <glib.h>
+#include <stdint.h>
+#include <gtk/gtk.h>
 #include <Account.h>
 
 #ifdef __cplusplus
@@ -40,6 +42,12 @@ extern "C" {
 GList * gnc_account_get_autoclear_splits (Account *account, gnc_numeric toclear_value,
                                           gchar **errmsg);
 
+/* same as above, but returns TRUE if successful, and FALSE if
+   unsuccessful and sets GError appropriately */
+gboolean gnc_autoclear_get_splits (Account *account, gnc_numeric toclear_value,
+                                   time64 end_date,
+                                   GList **splits, GError **error, GtkLabel *label);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gnucash/gnome/window-autoclear.c b/gnucash/gnome/window-autoclear.c
index 8434872191..7f9cc18cf1 100644
--- a/gnucash/gnome/window-autoclear.c
+++ b/gnucash/gnome/window-autoclear.c
@@ -124,18 +124,12 @@ gnc_autoclear_window_ok_cb (GtkWidget *widget,
 {
     GList *toclear_list = NULL;
     gnc_numeric toclear_value = gnc_numeric_error (GNC_ERROR_ARG);
-    gchar *errmsg = NULL;
     GError* error = NULL;
 
     g_return_if_fail (widget && data);
 
     /* test for valid value */
-    if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(data->end_value), &error))
-    {
-        errmsg = g_strdup (error->message);
-        g_error_free (error);
-    }
-    else
+    if (gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(data->end_value), &error))
     {
         toclear_value = gnc_amount_edit_get_amount(data->end_value);
 
@@ -145,19 +139,19 @@ gnc_autoclear_window_ok_cb (GtkWidget *widget,
         toclear_value = gnc_numeric_convert
             (toclear_value, xaccAccountGetCommoditySCU(data->account), GNC_HOW_RND_ROUND);
 
-        toclear_list = gnc_account_get_autoclear_splits
-            (data->account, toclear_value, &errmsg);
+        gnc_autoclear_get_splits (data->account, toclear_value, INT64_MAX,
+                                  &toclear_list, &error, data->status_label);
     }
 
-    if (errmsg)
+    if (error && error->message)
     {
         GtkWidget *entry = gnc_amount_edit_gtk_entry (GNC_AMOUNT_EDIT(data->end_value));
-        gtk_label_set_text (data->status_label, errmsg);
+        gtk_label_set_text (data->status_label, error->message);
         if (gnc_numeric_check (toclear_value) == 0)
             gnc_amount_edit_set_amount (data->end_value, toclear_value);
         gtk_widget_grab_focus (GTK_WIDGET(entry));
         gnc_amount_edit_select_region (GNC_AMOUNT_EDIT(data->end_value), 0, -1);
-        g_free (errmsg);
+        g_error_free (error);
     }
     else
     {



Summary of changes:
 gnucash/gnome-utils/gnc-autoclear.c         | 232 ++++++++++++++++------------
 gnucash/gnome-utils/gnc-autoclear.h         |   8 +
 gnucash/gnome-utils/test/test-autoclear.cpp |   8 +-
 gnucash/gnome/window-autoclear.c            |  18 +--
 4 files changed, 153 insertions(+), 113 deletions(-)



More information about the gnucash-changes mailing list