gnucash maint: Multiple changes pushed

Geert Janssens gjanssens at code.gnucash.org
Sat Nov 12 05:07:29 EST 2016


Updated	 via  https://github.com/Gnucash/gnucash/commit/ecb43e7d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5b832c7f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/96c22f54 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/254b4fbc (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a9c624bf (commit)
	 via  https://github.com/Gnucash/gnucash/commit/396117ee (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d52f44a8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0bcd3030 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/673888de (commit)
	from  https://github.com/Gnucash/gnucash/commit/32c4d145 (commit)



commit ecb43e7d72941c32bc7bee3d3698029bfd643080
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Sat Nov 12 10:30:31 2016 +0100

    Bug 770364 - Sign of Value in Lots in Account window seems inconsistent
    
    Two parts to this bug:
    1. never reverse signs in the free splits list. Sign reversals don't
    make sense there.
    
    2. Sign reversal only makes sense for capital gains, not for business
    transactions. So only to the sign dance for non-business lots in the
    list of splits in the selected lot.

diff --git a/src/gnome/dialog-lot-viewer.c b/src/gnome/dialog-lot-viewer.c
index a4c64e4..2d6e2b5 100644
--- a/src/gnome/dialog-lot-viewer.c
+++ b/src/gnome/dialog-lot-viewer.c
@@ -485,8 +485,12 @@ gnc_split_viewer_fill (GNCLotViewer *lv, GtkListStore *store, SplitList *split_l
 {
     SplitList *node;
     GtkTreeIter iter;
-
+    gboolean is_business_lot = FALSE;
     gnc_numeric baln = gnc_numeric_zero();
+
+    if (lv->selected_lot)
+        is_business_lot = xaccAccountIsAPARType (xaccAccountGetType (gnc_lot_get_account (lv->selected_lot)));
+
     gtk_list_store_clear (lv->split_in_lot_store);
     for (node = split_list; node; node = node->next)
     {
@@ -501,8 +505,7 @@ gnc_split_viewer_fill (GNCLotViewer *lv, GtkListStore *store, SplitList *split_l
         gnc_numeric amnt, valu, gains;
 
         /* Do not show gains splits, however do show empty business splits */
-        if (!xaccAccountIsAPARType (xaccAccountGetType (xaccSplitGetAccount (split)))
-                && gnc_numeric_zero_p (xaccSplitGetAmount(split))) continue;
+        if (!is_business_lot && gnc_numeric_zero_p (xaccSplitGetAmount(split))) continue;
 
         gtk_list_store_append(store, &iter);
 
@@ -522,13 +525,13 @@ gnc_split_viewer_fill (GNCLotViewer *lv, GtkListStore *store, SplitList *split_l
                           gnc_account_print_info (lv->account, TRUE));
         gtk_list_store_set (store, &iter, SPLIT_COL_AMOUNT, amtbuff, -1);
 
-        /* Value. Invert the sign on the first, opening entry. */
+        /* Value.
+         * For non-business accounts which are part of a lot,
+         * invert the sign on the first. */
         currency = xaccTransGetCurrency (trans);
         valu = xaccSplitGetValue (split);
-        if (node != split_list)
-        {
-            valu = gnc_numeric_neg (valu);
-        }
+        if (lv->selected_lot && !is_business_lot && (node != split_list))
+                valu = gnc_numeric_neg (valu);
         xaccSPrintAmount (valbuff, valu,
                           gnc_commodity_print_info (currency, TRUE));
         gtk_list_store_set (store, &iter, SPLIT_COL_VALUE, valbuff, -1);

commit 5b832c7f9bec7e65077c139262e09070ada3e664
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Sat Nov 12 09:22:09 2016 +0100

    Use G_MAXINT64 instead of 0 to indicate an invalid date

diff --git a/src/gnome/dialog-lot-viewer.c b/src/gnome/dialog-lot-viewer.c
index 141da29..a4c64e4 100644
--- a/src/gnome/dialog-lot-viewer.c
+++ b/src/gnome/dialog-lot-viewer.c
@@ -393,7 +393,7 @@ gnc_lot_viewer_fill (GNCLotViewer *lv)
         }
         else
         {
-            gtk_list_store_set(store, &iter, LOT_COL_CLOSE, 0LL, -1);
+            gtk_list_store_set(store, &iter, LOT_COL_CLOSE, G_MAXINT64, -1);
         }
 
         /* Title */
@@ -800,7 +800,7 @@ static void print_date (GtkTreeViewColumn *tree_column,
     doc_date_time = (time64) g_value_get_int64 (&value);
     g_value_unset (&value);
 
-    if (doc_date_time) /* assumes 0 represents an invalid date/time */
+    if (doc_date_time != G_MAXINT64) /* assumes INT64_MAX represents an invalid date/time */
     {
         g_free (doc_date_str);
         doc_date_str = qof_print_date (doc_date_time);

commit 96c22f54a38420c7c3d2e981711e685edc63675c
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Fri Nov 11 21:32:30 2016 +0100

    Show empty business splits in lot viewer

diff --git a/src/gnome/dialog-lot-viewer.c b/src/gnome/dialog-lot-viewer.c
index 0bc919d..141da29 100644
--- a/src/gnome/dialog-lot-viewer.c
+++ b/src/gnome/dialog-lot-viewer.c
@@ -500,8 +500,9 @@ gnc_split_viewer_fill (GNCLotViewer *lv, GtkListStore *store, SplitList *split_l
         time64 date = xaccTransGetDate (trans);
         gnc_numeric amnt, valu, gains;
 
-        /* Do not show gains splits */
-        if (gnc_numeric_zero_p (xaccSplitGetAmount(split))) continue;
+        /* Do not show gains splits, however do show empty business splits */
+        if (!xaccAccountIsAPARType (xaccAccountGetType (xaccSplitGetAccount (split)))
+                && gnc_numeric_zero_p (xaccSplitGetAmount(split))) continue;
 
         gtk_list_store_append(store, &iter);
 

commit 254b4fbc2fcdf697096fe7fd6aed6c97618472a0
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Fri Nov 11 20:58:52 2016 +0100

    Check more splits while running check & repair on business accounts
    
    In addition, speed up the process a bit by already deleting empty splits as soon as they're encountered

diff --git a/src/engine/ScrubBusiness.c b/src/engine/ScrubBusiness.c
index 5212b5b..aa48ea3 100644
--- a/src/engine/ScrubBusiness.c
+++ b/src/engine/ScrubBusiness.c
@@ -200,7 +200,6 @@ scrub_start:
         if (!sl_split)
             continue; // next scrub lot split
 
-        // Only lot link transactions need to be scrubbed
         ll_txn = xaccSplitGetParent (sl_split);
 
         if (!ll_txn)
@@ -212,9 +211,19 @@ scrub_start:
             continue;
         }
 
-        if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
+        // Don't scrub invoice type transactions
+        if (xaccTransGetTxnType (ll_txn) == TXN_TYPE_INVOICE)
             continue; // next scrub lot split
 
+        // Empty splits can be removed immediately
+        if (gnc_numeric_zero_p (xaccSplitGetValue (sl_split)) ||
+                gnc_numeric_zero_p(xaccSplitGetValue (sl_split)))
+        {
+            xaccSplitDestroy (sl_split);
+            modified = TRUE;
+            goto scrub_start;
+        }
+
         // Iterate over all splits in the lot link transaction
         for (lts_iter = xaccTransGetSplitList (ll_txn); lts_iter; lts_iter = lts_iter->next)
         {
@@ -229,20 +238,22 @@ scrub_start:
             if (sl_split == ll_txn_split)
                 continue; // next lot link transaction split
 
+            // Skip empty other splits. They'll be scrubbed in the outer for loop later
+            if (gnc_numeric_zero_p (xaccSplitGetValue (ll_txn_split)) ||
+                    gnc_numeric_zero_p(xaccSplitGetValue (ll_txn_split)))
+                continue;
+
             // Only splits of opposite signed values can be scrubbed
             if (gnc_numeric_positive_p (xaccSplitGetValue (sl_split)) ==
                 gnc_numeric_positive_p (xaccSplitGetValue (ll_txn_split)))
                 continue; // next lot link transaction split
 
-            // Find linked lot via split
+            // We can only scrub if the other split is in a lot as well
+            // Link transactions always have their other split in another lot
+            // however ordinary payment transactions may not
             remote_lot = xaccSplitGetLot (ll_txn_split);
             if (!remote_lot)
-            {
-                // This is unexpected - write a warning message and skip this split
-                PWARN("Encountered a Lot Link transaction with a split that's not in any lot. "
-                      "This is unexpected! Skipping split %p from transaction %p.", ll_txn_split, ll_txn);
                 continue;
-            }
 
             sl_is_doc_lot = (gncInvoiceGetInvoiceFromLot (scrub_lot) != NULL);
             rl_is_doc_lot = (gncInvoiceGetInvoiceFromLot (remote_lot) != NULL);
@@ -550,10 +561,16 @@ gncScrubBusinessSplit (Split *split)
          */
         else if (gnc_numeric_zero_p (xaccSplitGetAmount(split)) && !gncInvoiceGetInvoiceFromTxn (txn))
         {
+            GNCLot *lot = xaccSplitGetLot (split);
             time64 pdate = xaccTransGetDate (txn);
             gchar *pdatestr = gnc_ctime (&pdate);
             PINFO ("Destroying empty split %p from transaction %s (%s)", split, pdatestr, xaccTransGetDescription(txn));
             xaccSplitDestroy (split);
+
+            // Also delete the lot containing this split if it was the last split in that lot
+            if (lot && (gnc_lot_count_splits (lot) == 0))
+                gnc_lot_destroy (lot);
+
             deleted_split = TRUE;
         }
 

commit a9c624bfad7d98cd95a39788b399914eea01ea7c
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Fri Nov 11 14:03:13 2016 +0100

    Business check & repair - correct lot invoice state
    
    There have been situations where a lot refered to an invoice while
    it doesn't actually contain splits for that invoice (any more).
    The new code corrects this by removing the invoice reference from the lot.
    Also if the lot and its splits don't agree on the invoice they belong to
    set the lot invoice to whatever the splits indicate.

diff --git a/src/engine/ScrubBusiness.c b/src/engine/ScrubBusiness.c
index 8ce5667..5212b5b 100644
--- a/src/engine/ScrubBusiness.c
+++ b/src/engine/ScrubBusiness.c
@@ -37,6 +37,7 @@
 #include "policy-p.h"
 #include "Account.h"
 #include "gncInvoice.h"
+#include "gncInvoiceP.h"
 #include "Scrub2.h"
 #include "ScrubBusiness.h"
 #include "Transaction.h"
@@ -46,6 +47,41 @@
 
 static QofLogModule log_module = G_LOG_DOMAIN;
 
+static void
+gncScrubInvoiceState (GNCLot *lot)
+{
+    SplitList *ls_iter = NULL;
+    Transaction *txn = NULL; // ll_txn = "Lot Link Transaction"
+    GncInvoice *invoice = NULL;
+    GncInvoice *lot_invoice = gncInvoiceGetInvoiceFromLot (lot);
+
+    for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
+    {
+        Split *split = ls_iter->data;
+        Transaction *txn = NULL; // ll_txn = "Lot Link Transaction"
+
+        if (!split)
+            continue; // next scrub lot split
+
+        txn = xaccSplitGetParent (split);
+        invoice = gncInvoiceGetInvoiceFromTxn (txn);
+        if (invoice)
+            break;
+
+    }
+
+    if (invoice != lot_invoice)
+    {
+        PINFO("Correcting lot invoice associaton. Old invoice: %p, new invoice %p", lot_invoice, invoice);
+        gncInvoiceDetachFromLot(lot);
+
+        if (invoice)
+            gncInvoiceAttachToLot (invoice, lot);
+        else
+            gncOwnerAttachToLot (gncInvoiceGetOwner(lot_invoice), lot);
+    }
+}
+
 // A helper function that takes two splits. If the splits are  of opposite sign
 // it reduces the biggest split to have the same value (but with opposite sign)
 // of the smaller split.
@@ -214,7 +250,7 @@ scrub_start:
             // Depending on the type of lots we're comparing, we need different actions
             // - Two document lots (an invoice and a credit note):
             //   Special treatment - look for all document lots linked via ll_txn
-            //   and update the memo to be of more use to the uses.
+            //   and update the memo to be of more use to the users.
             // - Two payment lots:
             //   (Part of) the link will be eliminated and instead (part of)
             //   one payment will be added to the other lot to keep the balance.
@@ -424,6 +460,13 @@ gncScrubBusinessLot (GNCLot *lot)
     if (acc)
         xaccAccountBeginEdit(acc);
 
+    /* Check invoice link consistency
+     * A lot should have both or neither of:
+     * - one split from an invoice transaction
+     * - an invoice-guid set
+     */
+    gncScrubInvoiceState (lot);
+
     // Scrub lot links.
     // They should only remain when two document lots are linked together
     xaccScrubMergeLotSubSplits (lot, FALSE);
diff --git a/src/engine/gncInvoice.c b/src/engine/gncInvoice.c
index 9b6c33f..222553f 100644
--- a/src/engine/gncInvoice.c
+++ b/src/engine/gncInvoice.c
@@ -1130,7 +1130,7 @@ qofInvoiceSetJob (GncInvoice *invoice, GncJob *job)
     invoice->job = job;
 }
 
-static void
+void
 gncInvoiceDetachFromLot (GNCLot *lot)
 {
     KvpFrame *kvp;
@@ -1143,7 +1143,7 @@ gncInvoiceDetachFromLot (GNCLot *lot)
     gnc_lot_commit_edit (lot);
 }
 
-static void
+void
 gncInvoiceAttachToLot (GncInvoice *invoice, GNCLot *lot)
 {
     KvpFrame *kvp;
@@ -1182,7 +1182,7 @@ GncInvoice * gncInvoiceGetInvoiceFromLot (GNCLot *lot)
     return gncInvoiceLookup(book, guid);
 }
 
-static void
+void
 gncInvoiceAttachToTxn (GncInvoice *invoice, Transaction *txn)
 {
     KvpFrame *kvp;
diff --git a/src/engine/gncInvoiceP.h b/src/engine/gncInvoiceP.h
index 537dc2e..5b4942a 100644
--- a/src/engine/gncInvoiceP.h
+++ b/src/engine/gncInvoiceP.h
@@ -41,5 +41,9 @@ void gncInvoiceSetPostedTxn (GncInvoice *invoice, Transaction *txn);
 void gncInvoiceSetPostedLot (GncInvoice *invoice, GNCLot *lot);
 //void gncInvoiceSetPaidTxn (GncInvoice *invoice, Transaction *txn);
 
+void gncInvoiceAttachToLot (GncInvoice *invoice, GNCLot *lot);
+void gncInvoiceDetachFromLot (GNCLot *lot);
+void gncInvoiceAttachToTxn (GncInvoice *invoice, Transaction *txn);
+
 #define gncInvoiceSetGUID(I,G) qof_instance_set_guid(QOF_INSTANCE(I),(G))
 #endif /* GNC_INVOICEP_H_ */

commit 396117eec9514f20916df858c9477857e6c92b9a
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Wed Nov 9 18:44:21 2016 +0100

    Various small improvements to check & repair on business accounts
    
    - don't attempt to merge splits that belong to an invoice transaction. These splits are managed by the business code.
    - lot link cleanup can leave empty splits, remove these as well

diff --git a/src/engine/Scrub2.c b/src/engine/Scrub2.c
index 10ee3f8..e6a60af 100644
--- a/src/engine/Scrub2.c
+++ b/src/engine/Scrub2.c
@@ -43,6 +43,7 @@
 #include "ScrubP.h"
 #include "cap-gains.h"
 #include "gnc-engine.h"
+#include "gncInvoice.h"
 #include "gnc-lot.h"
 #include "policy-p.h"
 
@@ -355,6 +356,11 @@ xaccScrubMergeSubSplits (Split *split, gboolean strict)
     if (strict && (FALSE == is_subsplit (split))) return FALSE;
 
     txn = split->parent;
+
+    // Don't mess with splits from an invoice transaction
+    // Those are the responsibility of the business code
+    if (gncInvoiceGetInvoiceFromTxn (txn)) return FALSE;
+
     lot = xaccSplitGetLot (split);
 
     ENTER ("(Lot=%s)", gnc_lot_get_title(lot));
@@ -366,6 +372,10 @@ restart:
         if (s == split) continue;
         if (qof_instance_get_destroying(s)) continue;
 
+        // Don't mess with splits from an invoice transaction
+        // Those are the responsibility of the business code
+        if (gncInvoiceGetInvoiceFromTxn (s->parent)) return FALSE;
+
         if (strict)
         {
             /* OK, this split is in the same lot (and thus same account)
@@ -386,9 +396,13 @@ restart:
         rc = TRUE;
         goto restart;
     }
-    if (gnc_numeric_zero_p (split->amount))
+    if (rc && gnc_numeric_zero_p (split->amount))
     {
+        time64 pdate = xaccTransGetDate (txn);
+        gchar *pdatestr = gnc_ctime (&pdate);
         PWARN ("Result of merge has zero amt!");
+        PWARN ("Transaction details - posted date %s - description %s", pdatestr, xaccTransGetDescription(txn));
+        g_free (pdatestr);
     }
     LEAVE (" splits merged=%d", rc);
     return rc;
diff --git a/src/engine/ScrubBusiness.c b/src/engine/ScrubBusiness.c
index cd69468..8ce5667 100644
--- a/src/engine/ScrubBusiness.c
+++ b/src/engine/ScrubBusiness.c
@@ -462,13 +462,14 @@ gncScrubBusinessLot (GNCLot *lot)
     return splits_deleted;
 }
 
-void
+gboolean
 gncScrubBusinessSplit (Split *split)
 {
     const gchar *memo = _("Please delete this transaction. Explanation at http://wiki.gnucash.org/wiki/Business_Features_Issues#Double_Posting");
     Transaction *txn;
+    gboolean deleted_split = FALSE;
 
-    if (!split) return;
+    if (!split) return FALSE;
     ENTER ("(split=%p)", split);
 
     txn = xaccSplitGetParent (split);
@@ -500,10 +501,23 @@ gncScrubBusinessSplit (Split *split)
                   txn_date);
             g_free (txn_date);
         }
+        /* Next delete any empty splits that aren't part of an invoice transaction
+         * Such splits may be the result of scrubbing the business lots, which can
+         * merge splits together while reducing superfluous lot links
+         */
+        else if (gnc_numeric_zero_p (xaccSplitGetAmount(split)) && !gncInvoiceGetInvoiceFromTxn (txn))
+        {
+            time64 pdate = xaccTransGetDate (txn);
+            gchar *pdatestr = gnc_ctime (&pdate);
+            PINFO ("Destroying empty split %p from transaction %s (%s)", split, pdatestr, xaccTransGetDescription(txn));
+            xaccSplitDestroy (split);
+            deleted_split = TRUE;
+        }
 
     }
 
     LEAVE ("(split=%p)", split);
+    return deleted_split;
 }
 
 /* ============================================================== */
@@ -563,7 +577,7 @@ gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc)
 {
     SplitList *splits, *node;
     gint split_count = 0;
-    gint curr_split_no = 0;
+    gint curr_split_no;
     const gchar *str;
     const char *message = _( "Checking business splits in account %s: %u of %u");
 
@@ -577,6 +591,8 @@ gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc)
     PINFO ("Cleaning up superfluous lot links in account %s \n", str);
     xaccAccountBeginEdit(acc);
 
+restart:
+    curr_split_no = 0;
     splits = xaccAccountGetSplitList(acc);
     split_count = g_list_length (splits);
     for (node = splits; node; node = node->next)
@@ -594,7 +610,10 @@ gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc)
         }
 
         if (split)
-            gncScrubBusinessSplit (split);
+            // If gncScrubBusinessSplit returns true, a split was deleted and hence
+            // The account split list has become invalid, so we need to start over
+            if (gncScrubBusinessSplit (split))
+                goto restart;
 
         PINFO("Finished processing split %d of %d",
               curr_split_no + 1, split_count);
diff --git a/src/engine/ScrubBusiness.h b/src/engine/ScrubBusiness.h
index e4be74f..0cfce50 100644
--- a/src/engine/ScrubBusiness.h
+++ b/src/engine/ScrubBusiness.h
@@ -57,7 +57,9 @@ gboolean gncScrubBusinessLot (GNCLot *lot);
 /** The gncScrubBusinessSplit() function will fix all issues found with
  *    the given split.
  *
- *    Currently this function only does one thing: check if the split is
+ *    Current checks are:
+ *
+ *    * check if the split is
  *    part of a transaction that was generated as the result of a doubly
  *    posted invoice/bill/credit note. Refer to
  *    https://bugzilla.gnome.org/show_bug.cgi?id=754209 to learn how this
@@ -66,8 +68,11 @@ gboolean gncScrubBusinessLot (GNCLot *lot);
  *    a warning is written to the trace file. Considering the user may
  *    already have added a correcting transaction we leave it up to the user
  *    to decide whether to also delete the transaction or not.
+ *
+ *    * remove empty splits, on condition they aren't part of an invoice transaction.
+ *    In this case the function returns true so the caller knows a split was removed.
  */
-void gncScrubBusinessSplit (Split *split);
+gboolean gncScrubBusinessSplit (Split *split);
 
 /** The gncScrubBusinessAccountLots() function will call
  *    gncScrubBusinessLot() on each lot in the given account.

commit d52f44a8c7055a1c91477abacfae5130de9cf569
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Sun Nov 6 17:11:30 2016 +0100

    When juggling business splits while scrubbing set both value and amount
    
    With only value there were several warnings in the log file during scrubbing

diff --git a/src/engine/gncOwner.c b/src/engine/gncOwner.c
index c55dd5c..e8e6295 100644
--- a/src/engine/gncOwner.c
+++ b/src/engine/gncOwner.c
@@ -971,10 +971,12 @@ gncOwnerReduceSplitTo (Split *split, gnc_numeric target_value)
     rem_val = gnc_numeric_sub (split_val, target_value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); // note: values are of opposite sign
     rem_split = xaccMallocSplit (xaccSplitGetBook (split));
     xaccSplitCopyOnto (split, rem_split);
+    xaccSplitSetAmount (rem_split, rem_val);
     xaccSplitSetValue (rem_split, rem_val);
 
     txn = xaccSplitGetParent (split);
     xaccTransBeginEdit (txn);
+    xaccSplitSetAmount (split, target_value);
     xaccSplitSetValue (split, target_value);
     xaccSplitSetParent (rem_split, txn);
     xaccTransCommitEdit (txn);

commit 0bcd30301e8ae747bff8bea53a19a432a0ed9d5e
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Sun Nov 6 17:10:30 2016 +0100

    Update progress bar while running Check & Repair
    
    Not complete - should still be added for check & repair invoked from a split register

diff --git a/src/engine/Scrub.c b/src/engine/Scrub.c
index 4146f9b..8588656 100644
--- a/src/engine/Scrub.c
+++ b/src/engine/Scrub.c
@@ -59,13 +59,13 @@ static QofLogModule log_module = G_LOG_DOMAIN;
 /* ================================================================ */
 
 void
-xaccAccountTreeScrubOrphans (Account *acc)
+xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
 {
     if (!acc) return;
 
-    xaccAccountScrubOrphans (acc);
+    xaccAccountScrubOrphans (acc, percentagefunc);
     gnc_account_foreach_descendant(acc,
-                                   (AccountCb)xaccAccountScrubOrphans, NULL);
+                                   (AccountCb)xaccAccountScrubOrphans, percentagefunc);
 }
 
 static void
@@ -99,24 +99,38 @@ TransScrubOrphansFast (Transaction *trans, Account *root)
 }
 
 void
-xaccAccountScrubOrphans (Account *acc)
+xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
 {
-    GList *node;
+    GList *node, *splits;
     const char *str;
+    const char *message = _( "Looking for orphans in account %s: %u of %u");
+    guint total_splits = 0;
+    guint current_split = 0;
 
     if (!acc) return;
 
     str = xaccAccountGetName (acc);
     str = str ? str : "(null)";
     PINFO ("Looking for orphans in account %s \n", str);
+    splits = xaccAccountGetSplitList(acc);
+    total_splits = g_list_length (splits);
 
-    for (node = xaccAccountGetSplitList(acc); node; node = node->next)
+    for (node = splits; node; node = node->next)
     {
         Split *split = node->data;
 
+        if (current_split % 100 == 0)
+        {
+            char *progress_msg = g_strdup_printf (message, str, current_split, total_splits);
+            (percentagefunc)(progress_msg, (100 * current_split) / total_splits);
+            g_free (progress_msg);
+        }
+
         TransScrubOrphansFast (xaccSplitGetParent (split),
                                gnc_account_get_root (acc));
+        current_split++;
     }
+    (percentagefunc)(NULL, -1.0);
 }
 
 
@@ -273,25 +287,26 @@ xaccSplitScrub (Split *split)
 /* ================================================================ */
 
 void
-xaccAccountTreeScrubImbalance (Account *acc)
+xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
 {
-    xaccAccountScrubImbalance (acc);
+    xaccAccountScrubImbalance (acc, percentagefunc);
     gnc_account_foreach_descendant(acc,
-                                   (AccountCb)xaccAccountScrubImbalance, NULL);
+                                   (AccountCb)xaccAccountScrubImbalance, percentagefunc);
 }
 
 void
-xaccAccountScrubImbalance (Account *acc)
+xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
 {
     GList *node, *splits;
     const char *str;
-    gint split_count = 0, curr_split_no = 1;
+    const char *message = _( "Looking for imbalances in account %s: %u of %u");
+    gint split_count = 0, curr_split_no = 0;
 
     if (!acc) return;
 
     str = xaccAccountGetName(acc);
     str = str ? str : "(null)";
-    PINFO ("Looking for imbalance in account %s \n", str);
+    PINFO ("Looking for imbalances in account %s \n", str);
 
     splits = xaccAccountGetSplitList(acc);
     split_count = g_list_length (splits);
@@ -301,16 +316,28 @@ xaccAccountScrubImbalance (Account *acc)
         Transaction *trans = xaccSplitGetParent(split);
 
         PINFO("Start processing split %d of %d",
-              curr_split_no, split_count);
+              curr_split_no + 1, split_count);
+
+        if (curr_split_no % 100 == 0)
+        {
+            char *progress_msg = g_strdup_printf (message, str, curr_split_no, split_count);
+            (percentagefunc)(progress_msg, (100 * curr_split_no) / split_count);
+            g_free (progress_msg);
+        }
+
+        TransScrubOrphansFast (xaccSplitGetParent (split),
+                               gnc_account_get_root (acc));
+        (percentagefunc)(NULL, 0.0);
 
         xaccTransScrubCurrency(trans);
 
         xaccTransScrubImbalance (trans, gnc_account_get_root (acc), NULL);
 
         PINFO("Finished processing split %d of %d",
-              curr_split_no, split_count);
+              curr_split_no + 1, split_count);
         curr_split_no++;
     }
+    (percentagefunc)(NULL, -1.0);
 }
 
 static Split *
diff --git a/src/engine/Scrub.h b/src/engine/Scrub.h
index efdad1b..d57fadf 100644
--- a/src/engine/Scrub.h
+++ b/src/engine/Scrub.h
@@ -77,12 +77,12 @@ void xaccTransScrubOrphans (Transaction *trans);
 /** The xaccAccountScrubOrphans() method performs this scrub only for the
  *    indicated account, and not for any of its children.
  */
-void xaccAccountScrubOrphans (Account *acc);
+void xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc);
 
 /** The xaccAccountTreeScrubOrphans() method performs this scrub for the
  *    indicated account and its children.
  */
-void xaccAccountTreeScrubOrphans (Account *acc);
+void xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc);
 
 /** The xaccSplitScrub method ensures that if this split has the same
  *   commodity and currency, then it will have the same amount and value.
@@ -108,8 +108,8 @@ void xaccAccountTreeScrubSplits (Account *account);
  */
 void xaccTransScrubImbalance (Transaction *trans, Account *root,
                               Account *parent);
-void xaccAccountScrubImbalance (Account *acc);
-void xaccAccountTreeScrubImbalance (Account *acc);
+void xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc);
+void xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc);
 
 /** The xaccTransScrubCurrency method fixes transactions without a
  * common_currency by looking for the most commonly used currency
diff --git a/src/engine/ScrubBusiness.c b/src/engine/ScrubBusiness.c
index f93619b..cd69468 100644
--- a/src/engine/ScrubBusiness.c
+++ b/src/engine/ScrubBusiness.c
@@ -509,12 +509,13 @@ gncScrubBusinessSplit (Split *split)
 /* ============================================================== */
 
 void
-gncScrubBusinessAccountLots (Account *acc)
+gncScrubBusinessAccountLots (Account *acc, QofPercentageFunc percentagefunc)
 {
     LotList *lots, *node;
     gint lot_count = 0;
-    gint curr_lot_no = 1;
+    gint curr_lot_no = 0;
     const gchar *str;
+    const char *message = _( "Checking business lots in account %s: %u of %u");
 
     if (!acc) return;
     if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
@@ -533,29 +534,38 @@ gncScrubBusinessAccountLots (Account *acc)
         GNCLot *lot = node->data;
 
         PINFO("Start processing lot %d of %d",
-              curr_lot_no, lot_count);
+              curr_lot_no + 1, lot_count);
+
+        if (curr_lot_no % 100 == 0)
+        {
+            char *progress_msg = g_strdup_printf (message, str, curr_lot_no, lot_count);
+            (percentagefunc)(progress_msg, (100 * curr_lot_no) / lot_count);
+            g_free (progress_msg);
+        }
 
         if (lot)
             gncScrubBusinessLot (lot);
 
         PINFO("Finished processing lot %d of %d",
-              curr_lot_no, lot_count);
+              curr_lot_no + 1, lot_count);
         curr_lot_no++;
     }
     g_list_free(lots);
     xaccAccountCommitEdit(acc);
+    (percentagefunc)(NULL, -1.0);
     LEAVE ("(acc=%s)", str);
 }
 
 /* ============================================================== */
 
 void
-gncScrubBusinessAccountSplits (Account *acc)
+gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc)
 {
     SplitList *splits, *node;
     gint split_count = 0;
-    gint curr_split_no = 1;
+    gint curr_split_no = 0;
     const gchar *str;
+    const char *message = _( "Checking business splits in account %s: %u of %u");
 
     if (!acc) return;
     if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
@@ -574,29 +584,37 @@ gncScrubBusinessAccountSplits (Account *acc)
         Split *split = node->data;
 
         PINFO("Start processing split %d of %d",
-              curr_split_no, split_count);
+              curr_split_no + 1, split_count);
+
+        if (curr_split_no % 100 == 0)
+        {
+            char *progress_msg = g_strdup_printf (message, str, curr_split_no, split_count);
+            (percentagefunc)(progress_msg, (100 * curr_split_no) / split_count);
+            g_free (progress_msg);
+        }
 
         if (split)
             gncScrubBusinessSplit (split);
 
         PINFO("Finished processing split %d of %d",
-              curr_split_no, split_count);
+              curr_split_no + 1, split_count);
         curr_split_no++;
     }
     xaccAccountCommitEdit(acc);
+    (percentagefunc)(NULL, -1.0);
     LEAVE ("(acc=%s)", str);
 }
 
 /* ============================================================== */
 
 void
-gncScrubBusinessAccount (Account *acc)
+gncScrubBusinessAccount (Account *acc, QofPercentageFunc percentagefunc)
 {
     if (!acc) return;
     if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
 
-    gncScrubBusinessAccountLots (acc);
-    gncScrubBusinessAccountSplits (acc);
+    gncScrubBusinessAccountLots (acc, percentagefunc);
+    gncScrubBusinessAccountSplits (acc, percentagefunc);
 }
 
 /* ============================================================== */
@@ -605,16 +623,16 @@ static void
 lot_scrub_cb (Account *acc, gpointer data)
 {
     if (FALSE == xaccAccountIsAPARType (xaccAccountGetType (acc))) return;
-    gncScrubBusinessAccount (acc);
+    gncScrubBusinessAccount (acc, data);
 }
 
 void
-gncScrubBusinessAccountTree (Account *acc)
+gncScrubBusinessAccountTree (Account *acc, QofPercentageFunc percentagefunc)
 {
     if (!acc) return;
 
-    gnc_account_foreach_descendant(acc, lot_scrub_cb, NULL);
-    gncScrubBusinessAccount (acc);
+    gnc_account_foreach_descendant(acc, lot_scrub_cb, percentagefunc);
+    gncScrubBusinessAccount (acc, percentagefunc);
 }
 
 /* ========================== END OF FILE  ========================= */
diff --git a/src/engine/ScrubBusiness.h b/src/engine/ScrubBusiness.h
index cbf31d5..e4be74f 100644
--- a/src/engine/ScrubBusiness.h
+++ b/src/engine/ScrubBusiness.h
@@ -76,12 +76,12 @@ void gncScrubBusinessSplit (Split *split);
  *    lot structure of every lot of a business account is in good
  *    order.
  */
-void gncScrubBusinessAccountLots (Account *acc);
+void gncScrubBusinessAccountLots (Account *acc, QofPercentageFunc percentagefunc);
 
 /** The gncScrubBusinessAccountSplits() function will call
  *    gncScrubBusinessSplit() on each split in the given account.
  */
-void gncScrubBusinessAccountSplits (Account *acc);
+void gncScrubBusinessAccountSplits (Account *acc, QofPercentageFunc percentagefunc);
 
 /** The gncScrubBusinessAccount() function will call
  *    all scrub functions relevant for a given account
@@ -91,13 +91,13 @@ void gncScrubBusinessAccountSplits (Account *acc);
  *    This routine is the primary routine for fixing all
  *    (known) issues in a business account.
  */
-void gncScrubBusinessAccount (Account *acc);
+void gncScrubBusinessAccount (Account *acc, QofPercentageFunc percentagefunc);
 
 /** The gncScrubBusinessAccountTreeLots() function will call
  *    gncScrubBusinessAccount() on the given account
  *    and its sub accounts.
  */
-void gncScrubBusinessAccountTree (Account *acc);
+void gncScrubBusinessAccountTree (Account *acc, QofPercentageFunc percentagefunc);
 
 /** @} */
 #endif /* GNC_SCRUBBUSINESS_H */
diff --git a/src/gnome/dialog-lot-viewer.c b/src/gnome/dialog-lot-viewer.c
index b5e44b3..0bc919d 100644
--- a/src/gnome/dialog-lot-viewer.c
+++ b/src/gnome/dialog-lot-viewer.c
@@ -48,6 +48,7 @@
 #include "gnc-component-manager.h"
 #include "gnc-prefs.h"
 #include "gnc-ui-util.h"
+#include "gnc-window.h"
 #include "misc-gnome-utils.h"
 #include "tree-view-utils.h"
 
@@ -762,7 +763,7 @@ lv_response_cb (GtkDialog *dialog, gint response, gpointer data)
     case RESPONSE_SCRUB_ACCOUNT:
         gnc_suspend_gui_refresh ();
         if (xaccAccountIsAPARType (xaccAccountGetType(lv->account)))
-            gncScrubBusinessAccountLots (lv->account);
+            gncScrubBusinessAccountLots (lv->account, gnc_window_show_progress);
         else
             xaccAccountScrubLots (lv->account);
         gnc_resume_gui_refresh ();
diff --git a/src/gnome/gnc-plugin-page-account-tree.c b/src/gnome/gnc-plugin-page-account-tree.c
index 7864e57..ce67bd6 100644
--- a/src/gnome/gnc-plugin-page-account-tree.c
+++ b/src/gnome/gnc-plugin-page-account-tree.c
@@ -63,6 +63,7 @@
 #include "gnc-tree-model-account-types.h"
 #include "gnc-ui.h"
 #include "gnc-ui-util.h"
+#include "gnc-window.h"
 #include "dialog-lot-viewer.h"
 #include "window-reconcile.h"
 #include "window-autoclear.h"
@@ -1561,19 +1562,23 @@ static void
 gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountTree *page)
 {
     Account *account = gnc_plugin_page_account_tree_get_current_account (page);
+    GncWindow *window;
 
     g_return_if_fail (account != NULL);
 
     gnc_suspend_gui_refresh ();
 
-    xaccAccountScrubOrphans (account);
-    xaccAccountScrubImbalance (account);
+    window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
+    gnc_window_set_progressbar_window (window);
+
+    xaccAccountScrubOrphans (account, gnc_window_show_progress);
+    xaccAccountScrubImbalance (account, gnc_window_show_progress);
 
     // XXX: Lots/capital gains scrubbing is disabled
     if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
         xaccAccountScrubLots(account);
 
-    gncScrubBusinessAccount(account);
+    gncScrubBusinessAccount(account, gnc_window_show_progress);
 
 
     gnc_resume_gui_refresh ();
@@ -1583,19 +1588,23 @@ static void
 gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAccountTree *page)
 {
     Account *account = gnc_plugin_page_account_tree_get_current_account (page);
+    GncWindow *window;
 
     g_return_if_fail (account != NULL);
 
     gnc_suspend_gui_refresh ();
 
-    xaccAccountTreeScrubOrphans (account);
-    xaccAccountTreeScrubImbalance (account);
+    window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
+    gnc_window_set_progressbar_window (window);
+
+    xaccAccountTreeScrubOrphans (account, gnc_window_show_progress);
+    xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
 
     // XXX: Lots/capital gains scrubbing is disabled
     if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
         xaccAccountTreeScrubLots(account);
 
-    gncScrubBusinessAccountTree(account);
+    gncScrubBusinessAccountTree(account, gnc_window_show_progress);
 
     gnc_resume_gui_refresh ();
 }
@@ -1604,16 +1613,20 @@ static void
 gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAccountTree *page)
 {
     Account *root = gnc_get_current_root_account ();
+    GncWindow *window;
 
     gnc_suspend_gui_refresh ();
 
-    xaccAccountTreeScrubOrphans (root);
-    xaccAccountTreeScrubImbalance (root);
+    window = GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window);
+    gnc_window_set_progressbar_window (window);
+
+    xaccAccountTreeScrubOrphans (root, gnc_window_show_progress);
+    xaccAccountTreeScrubImbalance (root, gnc_window_show_progress);
     // XXX: Lots/capital gains scrubbing is disabled
     if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
         xaccAccountTreeScrubLots(root);
 
-    gncScrubBusinessAccountTree(root);
+    gncScrubBusinessAccountTree(root, gnc_window_show_progress);
 
     gnc_resume_gui_refresh ();
 }
diff --git a/src/gnome/gnc-plugin-page-register.c b/src/gnome/gnc-plugin-page-register.c
index 88b03a5..0585617 100644
--- a/src/gnome/gnc-plugin-page-register.c
+++ b/src/gnome/gnc-plugin-page-register.c
@@ -3792,8 +3792,10 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction *action,
     GncPluginPageRegisterPrivate *priv;
     Query *query;
     Account *root;
+    GncWindow *window;
     GList *node, *splits;
-    gint split_count = 0, curr_split_no = 1;
+    gint split_count = 0, curr_split_no = 0;
+    const char *message = _( "Checking splits in current register: %u of %u");
 
     g_return_if_fail(GNC_IS_PLUGIN_PAGE_REGISTER(plugin_page));
 
@@ -3808,6 +3810,9 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction *action,
     }
 
     gnc_suspend_gui_refresh();
+    window = GNC_WINDOW(GNC_PLUGIN_PAGE (plugin_page)->window);
+    gnc_window_set_progressbar_window (window);
+
     root = gnc_get_current_root_account();
 
     splits = qof_query_run(query);
@@ -3818,9 +3823,17 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction *action,
         Split *split = node->data;
         Transaction *trans = xaccSplitGetParent(split);
 
+        if (!split) continue;
 
         PINFO("Start processing split %d of %d",
-              curr_split_no, split_count);
+              curr_split_no + 1, split_count);
+
+        if (curr_split_no % 100 == 0)
+        {
+            char *progress_msg = g_strdup_printf (message, curr_split_no, split_count);
+            gnc_window_show_progress (progress_msg, (100 * curr_split_no) / split_count);
+            g_free (progress_msg);
+        }
 
         xaccTransScrubOrphans(trans);
         xaccTransScrubImbalance(trans, root, NULL);
@@ -3833,10 +3846,11 @@ gnc_plugin_page_register_cmd_scrub_all (GtkAction *action,
         }
 
         PINFO("Finished processing split %d of %d",
-              curr_split_no, split_count);
+              curr_split_no + 1, split_count);
         curr_split_no++;
     }
 
+    gnc_window_show_progress (NULL, -1.0);
     gnc_resume_gui_refresh();
     LEAVE(" ");
 }
diff --git a/src/gnome/window-reconcile.c b/src/gnome/window-reconcile.c
index 6813161..c1fb12b 100644
--- a/src/gnome/window-reconcile.c
+++ b/src/gnome/window-reconcile.c
@@ -54,6 +54,7 @@
 #include "gnc-prefs.h"
 #include "gnc-ui.h"
 #include "gnc-ui-balances.h"
+#include "gnc-window.h"
 #include "guile-util.h"
 #include "reconcile-view.h"
 #include "window-reconcile.h"
@@ -1407,8 +1408,8 @@ gnc_recn_scrub_cb(GtkAction *action, gpointer data)
 
     gnc_suspend_gui_refresh ();
 
-    xaccAccountTreeScrubOrphans (account);
-    xaccAccountTreeScrubImbalance (account);
+    xaccAccountTreeScrubOrphans (account, gnc_window_show_progress);
+    xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
 
     // XXX: Lots are disabled.
     if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)
diff --git a/src/gnome/window-reconcile2.c b/src/gnome/window-reconcile2.c
index 4409b37..bcb121f 100644
--- a/src/gnome/window-reconcile2.c
+++ b/src/gnome/window-reconcile2.c
@@ -54,6 +54,7 @@
 #include "gnc-prefs.h"
 #include "gnc-ui.h"
 #include "gnc-ui-balances.h"
+#include "gnc-window.h"
 #include "guile-util.h"
 #include "reconcile-view.h"
 #include "window-reconcile2.h"
@@ -1370,8 +1371,8 @@ gnc_recn_scrub_cb (GtkAction *action, gpointer data)
 
     gnc_suspend_gui_refresh ();
 
-    xaccAccountTreeScrubOrphans (account);
-    xaccAccountTreeScrubImbalance (account);
+    xaccAccountTreeScrubOrphans (account, gnc_window_show_progress);
+    xaccAccountTreeScrubImbalance (account, gnc_window_show_progress);
 
     // XXX: Lots are disabled.
     if (g_getenv("GNC_AUTO_SCRUB_LOTS") != NULL)

commit 673888dee7c972d2ed8470ccc28c466162910a6d
Author: Geert Janssens <janssens-geert at telenet.be>
Date:   Wed Nov 9 18:41:05 2016 +0100

    Remove lot from account while deleting the lot
    
    There was no way the account was informed about the lot being deleted.
    This was resulting into invalid lot lists in an account while scrubbing.
    Which would bomb at later stages like when re-running check & repair or
    opening the lot viewer. Also saving would report a number of critical messages
    about invalid objects, but these didn't result in a segfault.

diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index ce780c4..3afb296 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -227,6 +227,9 @@ gnc_lot_free(GNCLot* lot)
     }
     g_list_free (priv->splits);
 
+    if (priv->account)
+        xaccAccountRemoveLot (priv->account, lot);
+
     priv->account = NULL;
     priv->is_closed = TRUE;
     /* qof_instance_release (&lot->inst); */



Summary of changes:
 src/engine/Scrub.c                       |  55 ++++++++---
 src/engine/Scrub.h                       |   8 +-
 src/engine/Scrub2.c                      |  16 +++-
 src/engine/ScrubBusiness.c               | 151 +++++++++++++++++++++++++------
 src/engine/ScrubBusiness.h               |  17 ++--
 src/engine/gnc-lot.c                     |   3 +
 src/engine/gncInvoice.c                  |   6 +-
 src/engine/gncInvoiceP.h                 |   4 +
 src/engine/gncOwner.c                    |   2 +
 src/gnome/dialog-lot-viewer.c            |  27 +++---
 src/gnome/gnc-plugin-page-account-tree.c |  31 +++++--
 src/gnome/gnc-plugin-page-register.c     |  20 +++-
 src/gnome/window-reconcile.c             |   5 +-
 src/gnome/window-reconcile2.c            |   5 +-
 14 files changed, 268 insertions(+), 82 deletions(-)



More information about the gnucash-changes mailing list