r23071 - gnucash/trunk/src/business/business-gnome - Make it possible to post multiple invoices from the find dialog.

Mike Alexander mta at code.gnucash.org
Sat Jun 29 01:57:44 EDT 2013


Author: mta
Date: 2013-06-29 01:57:44 -0400 (Sat, 29 Jun 2013)
New Revision: 23071
Trac: http://svn.gnucash.org/trac/changeset/23071

Modified:
   gnucash/trunk/src/business/business-gnome/dialog-invoice.c
Log:
Make it possible to post multiple invoices from the find dialog.
GnuCash was crashing if you searched for all unposted invoices, selected two or
more of them, and posted them.  This was because the list of invoices to be posted
changed while it was being processed.  As part of fixing this the prompt for post date,
due date, etc. will only be given once, not once per invoice.

Modified: gnucash/trunk/src/business/business-gnome/dialog-invoice.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/dialog-invoice.c	2013-06-29 05:57:35 UTC (rev 23070)
+++ gnucash/trunk/src/business/business-gnome/dialog-invoice.c	2013-06-29 05:57:44 UTC (rev 23071)
@@ -664,51 +664,23 @@
     gnc_invoice_window_print_invoice(iw_get_invoice (iw));
 }
 
-void
-gnc_invoice_window_postCB (GtkWidget *unused_widget, gpointer data)
+static gboolean
+gnc_dialog_post_invoice(InvoiceWindow *iw, char *message,
+                        Timespec *ddue, Timespec *postdate,
+                        char **memo, Account **acc, gboolean *accumulate)
 {
-    InvoiceWindow *iw = data;
     GncInvoice *invoice;
-    char *message, *memo, *ddue_label, *post_label, *acct_label, *question_label;
-    Account *acc = NULL;
+    char *ddue_label, *post_label, *acct_label, *question_label;
     GList * acct_types = NULL;
     GList * acct_commodities = NULL;
-    Timespec ddue, postdate;
-    gboolean accumulate;
     QofInstance *owner_inst;
     KvpFrame *kvpf;
-    KvpValue *kvp_val;
-    const char *text;
     EntryList *entries, *entries_iter;
-    GncEntry* entry;
-    gboolean is_cust_doc;
-    gboolean is_cn;
-    gboolean show_dialog = TRUE;
-    gboolean post_ok = TRUE;
 
-    /* Make sure the invoice is ok */
-    if (!gnc_invoice_window_verify_ok (iw))
-        return;
-
     invoice = iw_get_invoice (iw);
     if (!invoice)
-        return;
-
-    /* Check that there is at least one Entry */
-    if (gncInvoiceGetEntries (invoice) == NULL)
-    {
-        gnc_error_dialog (iw_get_window(iw), "%s",
-                          _("The Invoice must have at least one Entry."));
-        return;
-    }
-
-    is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
-    is_cn = gncInvoiceGetIsCreditNote (invoice);
-
-    /* Ok, we can post this invoice.  Ask for verification, set the due date,
-     * post date, and posted account
-     */
-    message = _("Do you really want to post the invoice?");
+        return FALSE;
+        
     ddue_label = _("Due Date");
     post_label = _("Post Date");
     acct_label = _("Post to Account");
@@ -728,40 +700,110 @@
      * For Vendor Bills and Employee Vouchers
      * that would be the date of the most recent invoice entry.
      * Failing that, today is used as a fallback */
-    postdate = timespec_now();
+    *postdate = timespec_now();
 
     if (entries && ((gncInvoiceGetOwnerType (invoice) == GNC_OWNER_VENDOR) ||
                     (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_EMPLOYEE)))
     {
-        postdate = gncEntryGetDate ((GncEntry*)entries->data);
+        *postdate = gncEntryGetDate ((GncEntry*)entries->data);
         for (entries_iter = entries; entries_iter != NULL; entries_iter = g_list_next(entries_iter))
         {
             Timespec entrydate;
 
             entrydate = gncEntryGetDate ((GncEntry*)entries_iter->data);
-            if (timespec_cmp(&entrydate, &postdate) > 0)
-                postdate = entrydate;
+            if (timespec_cmp(&entrydate, postdate) > 0)
+                *postdate = entrydate;
         }
     }
 
     /* Get the due date and posted account */
-    ddue = postdate;
-    memo = NULL;
+    *ddue = *postdate;
+    *memo = NULL;
 
     owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
     kvpf = qof_instance_get_slots (owner_inst);
-    acc = xaccAccountLookup (kvp_frame_get_guid (kvpf, LAST_POSTED_TO_ACCT),
+    *acc = xaccAccountLookup (kvp_frame_get_guid (kvpf, LAST_POSTED_TO_ACCT),
                              iw->book);
 
     /* Get the default for the accumulate option */
-    accumulate = gnc_gconf_get_bool(GCONF_SECTION_INVOICE, "accumulate_splits", NULL);
+    *accumulate = gnc_gconf_get_bool(GCONF_SECTION_INVOICE, "accumulate_splits", NULL);
 
     if (!gnc_dialog_dates_acct_question_parented (iw_get_window(iw), message, ddue_label,
             post_label, acct_label, question_label, TRUE, TRUE,
             acct_types, acct_commodities, iw->book, iw->terms,
-            &ddue, &postdate, &memo, &acc, &accumulate))
+            ddue, postdate, memo, acc, accumulate))
+        return FALSE;
+    
+    return TRUE;
+}
+
+struct post_invoice_params 
+{
+    Timespec ddue;          /* Due date */
+    Timespec postdate;      /* Date posted */
+    char *memo;             /* Memo for posting transaction */
+    Account *acc;           /* Account to post to */
+    gboolean accumulate;    /* Whether to accumulate splits */
+};
+
+static void
+gnc_invoice_post(InvoiceWindow *iw, struct post_invoice_params *post_params)
+{
+    GncInvoice *invoice;
+    char *message, *memo;
+    Account *acc = NULL;
+    Timespec ddue, postdate;
+    gboolean accumulate;
+    QofInstance *owner_inst;
+    KvpFrame *kvpf;
+    KvpValue *kvp_val;
+    const char *text;
+    EntryList *entries, *entries_iter;
+    GncEntry* entry;
+    gboolean is_cust_doc;
+    gboolean is_cn;
+    gboolean show_dialog = TRUE;
+    gboolean post_ok = TRUE;
+
+    /* Make sure the invoice is ok */
+    if (!gnc_invoice_window_verify_ok (iw))
         return;
 
+    invoice = iw_get_invoice (iw);
+    if (!invoice)
+        return;
+
+    /* Check that there is at least one Entry */
+    if (gncInvoiceGetEntries (invoice) == NULL)
+    {
+        gnc_error_dialog (iw_get_window(iw), "%s",
+                          _("The Invoice must have at least one Entry."));
+        return;
+    }
+
+    is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
+    is_cn = gncInvoiceGetIsCreditNote (invoice);
+
+    /* Ok, we can post this invoice.  Ask for verification, set the due date,
+     * post date, and posted account
+     */
+    if (post_params)
+    {
+        ddue = post_params->ddue;
+        postdate = post_params->postdate;
+        // Dup it since it will free it below
+        memo = g_strdup (post_params->memo);
+        acc = post_params->acc;
+        accumulate = post_params->accumulate;
+    }
+    else
+    {
+        message = _("Do you really want to post the invoice?");
+        if (!gnc_dialog_post_invoice(iw, message,
+                                     &ddue, &postdate, &memo, &acc, &accumulate))
+            return;
+    }
+
     /* Yep, we're posting.  So, save the invoice...
      * Note that we can safely ignore the return value; we checked
      * the verify_ok earlier, so we know it's ok.
@@ -773,6 +815,9 @@
     /* Fill in the conversion prices with feedback from the user */
     text = _("One or more of the entries are for accounts different from the invoice/bill currency.  You will be asked a conversion rate for each.");
 
+    /* Get the invoice entries */
+    entries = gncInvoiceGetEntries (invoice);
+
     for (entries_iter = entries; entries_iter != NULL; entries_iter = g_list_next(entries_iter))
     {
         Account *this_acc;
@@ -874,6 +919,8 @@
 
 
     /* Save account as last used account in the kvp frame of the invoice owner */
+    owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
+    kvpf = qof_instance_get_slots (owner_inst);
     kvp_val = kvp_value_new_guid (qof_instance_get_guid (QOF_INSTANCE (acc)));;
     qof_begin_edit (owner_inst);
     kvp_frame_set_slot_nc (kvpf, LAST_POSTED_TO_ACCT, kvp_val);
@@ -908,6 +955,13 @@
 }
 
 void
+gnc_invoice_window_postCB (GtkWidget *unused_widget, gpointer data)
+{
+    InvoiceWindow *iw =data;
+    gnc_invoice_post(iw, NULL);
+}
+
+void
 gnc_invoice_window_unpostCB (GtkWidget *widget, gpointer data)
 {
     InvoiceWindow *iw = data;
@@ -2719,18 +2773,35 @@
 static void post_one_invoice_cb(gpointer data, gpointer user_data)
 {
     GncInvoice *invoice = data;
+    struct post_invoice_params *post_params = user_data;
     InvoiceWindow *iw = gnc_ui_invoice_edit(invoice);
-    gnc_invoice_window_ok_save (iw);
-    gnc_invoice_window_postCB(NULL, iw);
+    gnc_invoice_post(iw, post_params);
 }
 
 static void
 multi_post_invoice_cb (GList *invoice_list, gpointer user_data)
 {
+    struct post_invoice_params post_params;
+    InvoiceWindow *iw;
+    
     if (g_list_length(invoice_list) == 0)
         return;
+        
+    // Get the posting parameters for these invoices
+    iw = gnc_ui_invoice_edit(invoice_list->data);
+    if (!gnc_dialog_post_invoice(iw, _("Do you really want to post these invoices?"),
+                                 &post_params.ddue, &post_params.postdate,
+                                 &post_params.memo, &post_params.acc,
+                                 &post_params.accumulate))
+        return;
 
-    g_list_foreach(invoice_list, post_one_invoice_cb, user_data);
+    // Turn off GUI refresh for the duration.  This is more than just an
+    // optimization.  If the search that got us here is based on the "posted"
+    // status of an invoice, the updating the GUI will change the list we're
+    // working on which leads to bad things happening.
+    gnc_suspend_gui_refresh ();
+    g_list_foreach(invoice_list, post_one_invoice_cb, &post_params);
+    gnc_resume_gui_refresh ();
 }
 
 static void print_one_invoice_cb(gpointer data, gpointer user_data)



More information about the gnucash-changes mailing list