gnucash maint: Bug 754856 - scheduled transaction <gnc.app-utils.sx> fails without warning.

John Ralls jralls at code.gnucash.org
Sun Jan 24 17:42:17 EST 2016


Updated	 via  https://github.com/Gnucash/gnucash/commit/2e8407ed (commit)
	from  https://github.com/Gnucash/gnucash/commit/1ecb1235 (commit)



commit 2e8407ed125566fe85781d97cd01c95c491522a3
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Jan 24 14:41:55 2016 -0800

    Bug 754856 - scheduled transaction <gnc.app-utils.sx> fails without warning.
    
    Add warnings, both when saving the SX and when running an instance from the
    Since Last Run dialog.

diff --git a/src/app-utils/gnc-sx-instance-model.c b/src/app-utils/gnc-sx-instance-model.c
index cf7472e..4265c0e 100644
--- a/src/app-utils/gnc-sx-instance-model.c
+++ b/src/app-utils/gnc-sx-instance-model.c
@@ -941,14 +941,14 @@ _get_template_split_account(const SchedXaction* sx, const Split *template_split,
                                       NULL);
     if (kvp_val == NULL)
     {
-        GString *err = g_string_new("");
-        g_string_printf(err, "Null account kvp value for SX [%s], cancelling creation.",
-                        xaccSchedXactionGetName(sx));
-        g_critical("%s", err->str);
+        gchar *err = g_strdup_printf("Null account kvp value for SX [%s], "
+                                       "cancelling creation.",
+                                       xaccSchedXactionGetName(sx));
+        g_critical("%s", err);
         if (creation_errors != NULL)
             *creation_errors = g_list_append(*creation_errors, err);
         else
-            g_string_free(err, TRUE);
+            g_free(err);
         return FALSE;
     }
     acct_guid = kvp_value_get_guid( kvp_val );
@@ -1247,7 +1247,7 @@ create_each_transaction_helper(Transaction *template_txn, void *user_data)
 
     if (err_flag)
     {
-        g_critical("new transaction creation sx [%s]",
+        g_critical("Error in SX transaction [%s], creation aborted.",
                    xaccSchedXactionGetName(sx));
         xaccTransDestroy(new_txn);
         xaccTransCommitEdit(new_txn);
diff --git a/src/gnome/dialog-sx-editor.c b/src/gnome/dialog-sx-editor.c
index 9e0a2d8..b5cf59a 100644
--- a/src/gnome/dialog-sx-editor.c
+++ b/src/gnome/dialog-sx-editor.c
@@ -643,6 +643,8 @@ gnc_sxed_split_check_account (GncSxEditorDialog *sxed, Split *s,
     KvpValue *v = kvp_frame_get_slot_path(f, GNC_SX_ID, GNC_SX_ACCOUNT, NULL);
     GncGUID *acct_guid = kvp_value_get_guid (v);
     acct = xaccAccountLookup( acct_guid, gnc_get_current_book ());
+    if (acct == NULL)
+        return FALSE;
     split_cmdty = xaccAccountGetCommodity(acct);
     split_amount = xaccSplitGetAmount(s);
     if (!gnc_numeric_zero_p(split_amount) && base_cmdty == NULL)
@@ -685,6 +687,100 @@ gnc_sxed_split_calculate_formula (GncSxEditorDialog *sxed, Split *s,
     return TRUE;
 }
 
+typedef struct
+{
+    GncSxEditorDialog *sxed;
+    GHashTable *txns;
+    GHashTable *vars;
+    txnCreditDebitSums *tcds;
+    gboolean multi_commodity;
+    gboolean err;
+} CheckTxnSplitData;
+
+static void
+split_error_warning_dialog (GtkWidget *parent, const gchar *title,
+                            gchar *message)
+{
+    GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0,
+                                                GTK_MESSAGE_ERROR,
+                                                GTK_BUTTONS_CLOSE,
+                                                "%s", title);
+    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                              "%s", message);
+    gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
+    g_signal_connect_swapped (dialog, "response",
+                              G_CALLBACK(gtk_widget_destroy), dialog);
+    gtk_dialog_run (GTK_DIALOG (dialog));
+
+}
+static gboolean
+check_transaction_splits (Transaction *txn, gpointer data)
+{
+    GList *splitList = xaccTransGetSplitList (txn);
+    CheckTxnSplitData *sd = (CheckTxnSplitData*)data;
+
+    for ( ; splitList; splitList = splitList->next )
+    {
+        gnc_commodity *base_cmdty = NULL;
+        txnCreditDebitSums *tcds;
+        Split *s = (Split*)splitList->data;
+
+        tcds = (txnCreditDebitSums*)g_hash_table_lookup (sd->txns,
+                                                         (gpointer)txn);
+        if (sd->tcds == NULL)
+        {
+            sd->tcds = tcds_new ();
+            g_hash_table_insert (sd->txns, (gpointer)txn, (gpointer)(sd->tcds));
+        }
+
+        if (!gnc_sxed_split_check_account (sd->sxed, s, base_cmdty,
+                                           &sd->multi_commodity))
+        {
+            gchar *message = g_strdup_printf
+                (_("Split with memo %s has an invalid account."),
+                 xaccSplitGetMemo (s));
+            split_error_warning_dialog (sd->sxed->dialog,
+                                        _("Invalid Account in Split"),
+                                        message);
+            g_free (message);
+            sd->err = TRUE;
+            return FALSE;
+        }
+
+        if (!gnc_sxed_split_calculate_formula (sd->sxed, s, sd->vars,
+                                               GNC_SX_CREDIT_FORMULA,
+                                               sd->tcds))
+        {
+            gchar *message = g_strdup_printf
+                (_("Split with memo %s has an unparseable Credit Formula."),
+                 xaccSplitGetMemo (s));
+            split_error_warning_dialog (sd->sxed->dialog,
+                                        _("Unparsable Formula in Split"),
+                                        message);
+            g_free (message);
+            sd->err = TRUE;
+            return FALSE;
+        }
+
+        if (!gnc_sxed_split_calculate_formula (sd->sxed, s, sd->vars,
+                                               GNC_SX_DEBIT_FORMULA,
+                                               sd->tcds))
+
+        {
+            gchar *message = g_strdup_printf
+                (_("Split with memo %s has an unparseable Debit Formula."),
+                 xaccSplitGetMemo (s));
+            split_error_warning_dialog (sd->sxed->dialog,
+                                        _("Unparsable Formula in Split"),
+                                        message);
+            g_free (message);
+            sd->err = TRUE;
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
 /*******************************************************************************
  * Checks to make sure that the SX is in a reasonable state to save.
  * @return true if checks out okay, false otherwise.
@@ -724,6 +820,8 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
                                   (GDestroyNotify)gnc_sx_variable_free);
     GHashTable *txns = g_hash_table_new_full (g_direct_hash, g_direct_equal,
                                               NULL, g_free);
+    CheckTxnSplitData sd = {sxed, txns, vars, NULL, FALSE, FALSE};
+
     /**
      * Plan:
      * . Do a first pass to get the variables.
@@ -751,38 +849,16 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
     for ( i = 0; i < numIters && !unbalanceable; i++ )
     {
         GList *splitList = xaccSchedXactionGetSplits (sxed->sx);
+        Account *tmpl_acct = gnc_sx_get_template_transaction_account (sxed->sx);
         gnc_sx_randomize_variables(vars);
         g_hash_table_foreach( txns, set_sums_to_zero, NULL );
 
         splitCount += g_list_length( splitList );
 
-        for ( ; splitList; splitList = splitList->next )
-        {
-            gnc_commodity *base_cmdty = NULL;
-            txnCreditDebitSums *tcds;
-            Split *s = (Split*)splitList->data;
-            Transaction *t = xaccSplitGetParent (s);
-
-            tcds = (txnCreditDebitSums*)g_hash_table_lookup (txns, (gpointer)t);
-            if (tcds == NULL)
-            {
-                tcds = tcds_new ();
-                g_hash_table_insert (txns, (gpointer)t, (gpointer)tcds);
-            }
-
-            if (!gnc_sxed_split_check_account (sxed, s, base_cmdty,
-                                               &multi_commodity))
-                return FALSE;
-
-            if (!gnc_sxed_split_calculate_formula (sxed, s, vars,
-                                                   GNC_SX_CREDIT_FORMULA,
-                                                   tcds))
-                return FALSE;
-            if (!gnc_sxed_split_calculate_formula (sxed, s, vars,
-                                                   GNC_SX_DEBIT_FORMULA,
-                                                   tcds))
-                return FALSE;
-        }
+        xaccAccountForEachTransaction(tmpl_acct, check_transaction_splits, &sd);
+
+        if (sd.err)
+            return FALSE;
 
         g_hash_table_foreach (txns, check_credit_debit_balance, &unbalanceable);
     }
@@ -807,7 +883,7 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
         return FALSE;
 
     if (!gnc_sxed_check_autocreate (sxed, ttVarCount,
-                                    splitCount, multi_commodity))
+                                    splitCount, sd.multi_commodity))
         return FALSE;
 
     if (!gnc_sxed_check_endpoint (sxed))
@@ -819,7 +895,7 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
 /******************************************************************************
  * Saves the contents of the SX.  This assumes that gnc_sxed_check_consistent
  * has returned true.
- *****************************************************************************/
+  *****************************************************************************/
 static void
 gnc_sxed_save_sx( GncSxEditorDialog *sxed )
 {
diff --git a/src/gnome/dialog-sx-since-last-run.c b/src/gnome/dialog-sx-since-last-run.c
index 3964e68..fe85a45 100644
--- a/src/gnome/dialog-sx-since-last-run.c
+++ b/src/gnome/dialog-sx-since-last-run.c
@@ -791,10 +791,39 @@ gnc_sx_slr_tree_model_adapter_new(GncSxInstanceModel *instances)
     return rtn;
 }
 
+static void
+creation_error_dialog (GList **creation_errors)
+{
+    GList *node = *creation_errors;
+    GtkWidget *dialog = NULL;
+    gchar *message = NULL;
+    if (*creation_errors == NULL) return;
+    for(; node != NULL; node = g_list_next (node))
+    {
+        const gchar *fmt = message == NULL ? "%s%s" : "%s\n%s";
+        gchar *new_msg = g_strdup_printf (fmt, message, node->data);
+        g_free (message);
+        message = new_msg;
+        g_free(node->data);
+    }
+    g_list_free (*creation_errors);
+    creation_errors = NULL;
+    dialog = gtk_message_dialog_new (NULL, 0,
+                                     GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+                                     "%s", _("Invalid Transactions"));
+    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                              "%s", message);
+    g_signal_connect_swapped (dialog, "response",
+                              G_CALLBACK(gtk_widget_destroy), dialog);
+    gtk_dialog_run (GTK_DIALOG (dialog));
+    g_free (message);
+}
+
 void
 gnc_sx_sxsincelast_book_opened(void)
 {
     GList *auto_created_txns = NULL;
+    GList *creation_errors = NULL;
     GncSxInstanceModel *inst_model;
     GncSxSummary summary;
 
@@ -810,7 +839,8 @@ gnc_sx_sxsincelast_book_opened(void)
     inst_model = gnc_sx_get_current_instances();
     gnc_sx_instance_model_summarize(inst_model, &summary);
     gnc_sx_summary_print(&summary);
-    gnc_sx_instance_model_effect_change(inst_model, TRUE, &auto_created_txns, NULL);
+    gnc_sx_instance_model_effect_change(inst_model, TRUE, &auto_created_txns,
+                                        &creation_errors);
 
     if (summary.need_dialog)
     {
@@ -837,6 +867,8 @@ gnc_sx_sxsincelast_book_opened(void)
     }
     g_list_free(auto_created_txns);
     g_object_unref(G_OBJECT(inst_model));
+    if (creation_errors)
+        creation_error_dialog(&creation_errors);
 }
 
 static void
@@ -1075,6 +1107,7 @@ dialog_destroy_cb(GtkWidget *object, GncSxSinceLastRunDialog *app_dialog)
 static void
 dialog_response_cb(GtkDialog *dialog, gint response_id, GncSxSinceLastRunDialog *app_dialog)
 {
+    GList* creation_errors = NULL;
     switch (response_id)
     {
     case GTK_RESPONSE_OK:
@@ -1108,8 +1141,11 @@ dialog_response_cb(GtkDialog *dialog, gint response_id, GncSxSinceLastRunDialog
         }
     }
     gnc_suspend_gui_refresh();
-    gnc_sx_slr_model_effect_change(app_dialog->editing_model, FALSE, &app_dialog->created_txns, NULL);
+    gnc_sx_slr_model_effect_change(app_dialog->editing_model, FALSE, &app_dialog->created_txns, &creation_errors);
     gnc_resume_gui_refresh();
+    if (creation_errors)
+        creation_error_dialog(&creation_errors);
+
     if (gtk_toggle_button_get_active(app_dialog->review_created_txns_toggle)
             && g_list_length(app_dialog->created_txns) > 0)
     {



Summary of changes:
 src/app-utils/gnc-sx-instance-model.c |  12 +--
 src/gnome/dialog-sx-editor.c          | 134 ++++++++++++++++++++++++++--------
 src/gnome/dialog-sx-since-last-run.c  |  40 +++++++++-
 3 files changed, 149 insertions(+), 37 deletions(-)



More information about the gnucash-changes mailing list