[gnc-sx-instance-model.c] refactor Scrub function

This scrubbing function calls xaccTransRollbackEdit which is
leaky. Instead of trying to fix xaccTransRollbackEdit which requires
superhuman skills, it's easiest to track the changes separately in a
GList, and use xaccTransBeginEdit/xaccTransCommitEdit only if
necessary.
This commit is contained in:
Christopher Lam 2022-07-27 21:38:31 +08:00
parent 7880f9b16f
commit 7c2a249511

View File

@ -88,41 +88,45 @@ static void _gnc_sx_instance_event_handler(QofInstance *ent, QofEventId event_ty
static gnc_commodity* get_transaction_currency(SxTxnCreationData *creation_data, SchedXaction *sx, Transaction *template_txn);
/* ------------------------------------------------------------ */
static gboolean
scrub_sx_split_numeric (Split* split, const char *debcred)
typedef struct
{
const gboolean is_credit = g_strcmp0 (debcred, "credit") == 0;
const char *formula = is_credit ?
"sx-credit-formula" : "sx-debit-formula";
const char *numeric = is_credit ?
"sx-credit-numeric" : "sx-debit-numeric";
const char *name;
gnc_numeric amount;
} ScrubItem;
static void
scrub_sx_split_numeric (Split* split, gboolean is_credit, GList **changes)
{
const char *formula = is_credit ? "sx-credit-formula" : "sx-debit-formula";
const char *numeric = is_credit ? "sx-credit-numeric" : "sx-debit-numeric";
char *formval;
gnc_numeric *numval = NULL;
GHashTable *parser_vars = g_hash_table_new (g_str_hash, g_str_equal);
char *error_loc;
gnc_numeric amount = gnc_numeric_zero ();
gboolean parse_result = FALSE;
gboolean num_val_changed = FALSE;
qof_instance_get (QOF_INSTANCE (split),
formula, &formval,
numeric, &numval,
NULL);
parse_result =
gnc_exp_parser_parse_separate_vars (formval, &amount,
&error_loc, parser_vars);
qof_instance_get (QOF_INSTANCE (split), formula, &formval,
numeric, &numval, NULL);
parse_result = gnc_exp_parser_parse_separate_vars (formval, &amount,
&error_loc, parser_vars);
if (!parse_result || g_hash_table_size (parser_vars) != 0)
amount = gnc_numeric_zero ();
g_hash_table_unref (parser_vars);
if (!numval || !gnc_numeric_eq (amount, *numval))
{
qof_instance_set (QOF_INSTANCE (split),
numeric, &amount,
NULL);
num_val_changed = TRUE;
ScrubItem *change = g_new (ScrubItem, 1);
change->name = numeric;
change->amount = amount;
*changes = g_list_prepend (*changes, change);
}
g_free (formval);
g_free (numval);
return num_val_changed;
}
/* Fixes error in pre-2.6.16 where the numeric slot wouldn't get changed if the
@ -133,14 +137,20 @@ gnc_sx_scrub_split_numerics (gpointer psplit, gpointer puser)
{
Split *split = GNC_SPLIT (psplit);
Transaction *trans = xaccSplitGetParent (split);
gboolean changed;
GList *changes = NULL;
scrub_sx_split_numeric (split, TRUE, &changes);
scrub_sx_split_numeric (split, FALSE, &changes);
if (!changes)
return;
xaccTransBeginEdit (trans);
changed = scrub_sx_split_numeric (split, "credit") +
scrub_sx_split_numeric (split, "debit");
if (!changed)
xaccTransRollbackEdit (trans);
else
xaccTransCommitEdit (trans);
for (GList *n = changes; n; n = n->next)
{
ScrubItem *change = n->data;
qof_instance_set (QOF_INSTANCE (split), change->name, &change->amount, NULL);
}
xaccTransCommitEdit (trans);
g_list_free_full (changes, g_free);
}
static void