1 /********************************************************************\
2  * Scrub.c -- convert single-entry accounts into clean double-entry *
3  *                                                                  *
4  * This program is free software; you can redistribute it and/or    *
5  * modify it under the terms of the GNU General Public License as   *
6  * published by the Free Software Foundation; either version 2 of   *
7  * the License, or (at your option) any later version.              *
8  *                                                                  *
9  * This program is distributed in the hope that it will be useful,  *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
12  * GNU General Public License for more details.                     *
13  *                                                                  *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact:                        *
16  *                                                                  *
17  * Free Software Foundation           Voice:  +1-617-542-5942       *
18  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
19  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
20  *                                                                  *
21 \********************************************************************/
22 
23 /*
24  * FILE:
25  * Scrub.c
26  *
27  * FUNCTION:
28  * Provides a set of functions and utilities for scrubbing clean
29  * single-entry accounts so that they can be promoted into
30  * self-consistent, clean double-entry accounts.
31  *
32  * HISTORY:
33  * Created by Linas Vepstas December 1998
34  * Copyright (c) 1998-2000, 2003 Linas Vepstas <linas@linas.org>
35  * Copyright (c) 2002 Christian Stimming
36  * Copyright (c) 2006 David Hampton
37  */
38 
39 #include <config.h>
40 
41 #include <glib.h>
42 #include <glib/gi18n.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdint.h>
46 
47 #include "Account.h"
48 #include "AccountP.h"
49 #include "Scrub.h"
50 #include "Transaction.h"
51 #include "TransactionP.h"
52 #include "gnc-commodity.h"
53 #include "qofinstance-p.h"
54 #include "gnc-session.h"
55 
56 #undef G_LOG_DOMAIN
57 #define G_LOG_DOMAIN "gnc.engine.scrub"
58 
59 static QofLogModule log_module = G_LOG_DOMAIN;
60 static gboolean abort_now = FALSE;
61 static gint scrub_depth = 0;
62 
63 
64 static Account* xaccScrubUtilityGetOrMakeAccount (Account *root,
65                                                   gnc_commodity* currency,
66                                                   const char* accname,
67                                                   GNCAccountType acctype,
68                                                   gboolean placeholder,
69                                                   gboolean checkname);
70 
71 void
gnc_set_abort_scrub(gboolean abort)72 gnc_set_abort_scrub (gboolean abort)
73 {
74     abort_now = abort;
75 }
76 
77 gboolean
gnc_get_abort_scrub(void)78 gnc_get_abort_scrub (void)
79 {
80     return abort_now;
81 }
82 
83 gboolean
gnc_get_ongoing_scrub(void)84 gnc_get_ongoing_scrub (void)
85 {
86     return scrub_depth > 0;
87 }
88 
89 /* ================================================================ */
90 
91 void
xaccAccountTreeScrubOrphans(Account * acc,QofPercentageFunc percentagefunc)92 xaccAccountTreeScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
93 {
94     if (!acc) return;
95 
96     if (abort_now)
97         (percentagefunc)(NULL, -1.0);
98 
99     scrub_depth ++;
100     xaccAccountScrubOrphans (acc, percentagefunc);
101     gnc_account_foreach_descendant(acc,
102                                    (AccountCb)xaccAccountScrubOrphans, percentagefunc);
103     scrub_depth--;
104 }
105 
106 static void
TransScrubOrphansFast(Transaction * trans,Account * root)107 TransScrubOrphansFast (Transaction *trans, Account *root)
108 {
109     GList *node;
110     gchar *accname;
111 
112     if (!trans) return;
113     g_return_if_fail (root);
114     g_return_if_fail (trans->common_currency);
115 
116     for (node = trans->splits; node; node = node->next)
117     {
118         Split *split = node->data;
119         Account *orph;
120         if (abort_now) break;
121 
122         if (split->acc) continue;
123 
124         DEBUG ("Found an orphan\n");
125 
126         accname = g_strconcat (_("Orphan"), "-",
127                                gnc_commodity_get_mnemonic (trans->common_currency),
128                                NULL);
129         orph = xaccScrubUtilityGetOrMakeAccount (root, trans->common_currency,
130                                                  accname, ACCT_TYPE_BANK,
131                                                  FALSE, TRUE);
132         g_free (accname);
133         if (!orph) continue;
134 
135         xaccSplitSetAccount(split, orph);
136     }
137 }
138 
139 void
xaccAccountScrubOrphans(Account * acc,QofPercentageFunc percentagefunc)140 xaccAccountScrubOrphans (Account *acc, QofPercentageFunc percentagefunc)
141 {
142     GList *node, *splits;
143     const char *str;
144     const char *message = _( "Looking for orphans in account %s: %u of %u");
145     guint total_splits = 0;
146     guint current_split = 0;
147 
148     if (!acc) return;
149     scrub_depth++;
150 
151     str = xaccAccountGetName (acc);
152     str = str ? str : "(null)";
153     PINFO ("Looking for orphans in account %s\n", str);
154     splits = xaccAccountGetSplitList(acc);
155     total_splits = g_list_length (splits);
156 
157     for (node = splits; node; node = node->next)
158     {
159         Split *split = node->data;
160         if (current_split % 10 == 0)
161         {
162             char *progress_msg = g_strdup_printf (message, str, current_split, total_splits);
163             (percentagefunc)(progress_msg, (100 * current_split) / total_splits);
164             g_free (progress_msg);
165             if (abort_now) break;
166         }
167 
168         TransScrubOrphansFast (xaccSplitGetParent (split),
169                                gnc_account_get_root (acc));
170         current_split++;
171     }
172     (percentagefunc)(NULL, -1.0);
173     scrub_depth--;
174 }
175 
176 
177 void
xaccTransScrubOrphans(Transaction * trans)178 xaccTransScrubOrphans (Transaction *trans)
179 {
180     SplitList *node;
181     QofBook *book = NULL;
182     Account *root = NULL;
183 
184     if (!trans) return;
185 
186     for (node = trans->splits; node; node = node->next)
187     {
188         Split *split = node->data;
189         if (abort_now) break;
190 
191         if (split->acc)
192         {
193             TransScrubOrphansFast (trans, gnc_account_get_root(split->acc));
194             return;
195         }
196     }
197 
198     /* If we got to here, then *none* of the splits belonged to an
199      * account.  Not a happy situation.  We should dig an account
200      * out of the book the transaction belongs to.
201      * XXX we should probably *always* to this, instead of the above loop!
202      */
203     PINFO ("Free Floating Transaction!");
204     book = xaccTransGetBook (trans);
205     root = gnc_book_get_root_account (book);
206     TransScrubOrphansFast (trans, root);
207 }
208 
209 /* ================================================================ */
210 
211 void
xaccAccountTreeScrubSplits(Account * account)212 xaccAccountTreeScrubSplits (Account *account)
213 {
214     if (!account) return;
215 
216     xaccAccountScrubSplits (account);
217     gnc_account_foreach_descendant(account,
218                                    (AccountCb)xaccAccountScrubSplits, NULL);
219 }
220 
221 void
xaccAccountScrubSplits(Account * account)222 xaccAccountScrubSplits (Account *account)
223 {
224     GList *node;
225     scrub_depth++;
226     for (node = xaccAccountGetSplitList (account); node; node = node->next)
227     {
228         if (abort_now) break;
229         xaccSplitScrub (node->data);
230     }
231     scrub_depth--;
232 }
233 
234 void
xaccSplitScrub(Split * split)235 xaccSplitScrub (Split *split)
236 {
237     Account *account;
238     Transaction *trans;
239     gnc_numeric value, amount;
240     gnc_commodity *currency, *acc_commodity;
241     int scu;
242 
243     if (!split) return;
244     ENTER ("(split=%p)", split);
245 
246     trans = xaccSplitGetParent (split);
247     if (!trans)
248     {
249         LEAVE("no trans");
250         return;
251     }
252 
253     account = xaccSplitGetAccount (split);
254 
255     /* If there's no account, this split is an orphan.
256      * We need to fix that first, before proceeding.
257      */
258     if (!account)
259     {
260         xaccTransScrubOrphans (trans);
261         account = xaccSplitGetAccount (split);
262     }
263 
264     /* Grrr... the register gnc_split_register_load() line 203 of
265      *  src/register/ledger-core/split-register-load.c will create
266      * free-floating bogus transactions. Ignore these for now ...
267      */
268     if (!account)
269     {
270         PINFO ("Free Floating Transaction!");
271         LEAVE ("no account");
272         return;
273     }
274 
275     /* Split amounts and values should be valid numbers */
276     value = xaccSplitGetValue (split);
277     if (gnc_numeric_check (value))
278     {
279         value = gnc_numeric_zero();
280         xaccSplitSetValue (split, value);
281     }
282 
283     amount = xaccSplitGetAmount (split);
284     if (gnc_numeric_check (amount))
285     {
286         amount = gnc_numeric_zero();
287         xaccSplitSetAmount (split, amount);
288     }
289 
290     currency = xaccTransGetCurrency (trans);
291 
292     /* If the account doesn't have a commodity,
293      * we should attempt to fix that first.
294      */
295     acc_commodity = xaccAccountGetCommodity(account);
296     if (!acc_commodity)
297     {
298         xaccAccountScrubCommodity (account);
299     }
300     if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency))
301     {
302         LEAVE ("(split=%p) inequiv currency", split);
303         return;
304     }
305 
306     scu = MIN (xaccAccountGetCommoditySCU (account),
307                gnc_commodity_get_fraction (currency));
308 
309     if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP))
310     {
311         LEAVE("(split=%p) different values", split);
312         return;
313     }
314 
315     /*
316      * This will be hit every time you answer yes to the dialog "The
317      * current transaction has changed. Would you like to record it.
318      */
319     PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
320            " old amount %s %s, new amount %s",
321            trans->description, split->memo,
322            gnc_num_dbg_to_string (xaccSplitGetAmount(split)),
323            gnc_commodity_get_mnemonic (currency),
324            gnc_num_dbg_to_string (xaccSplitGetValue(split)));
325 
326     xaccTransBeginEdit (trans);
327     xaccSplitSetAmount (split, value);
328     xaccTransCommitEdit (trans);
329     LEAVE ("(split=%p)", split);
330 }
331 
332 /* ================================================================ */
333 
334 void
xaccAccountTreeScrubImbalance(Account * acc,QofPercentageFunc percentagefunc)335 xaccAccountTreeScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
336 {
337     if (!acc) return;
338 
339     if (abort_now)
340         (percentagefunc)(NULL, -1.0);
341 
342     scrub_depth++;
343     xaccAccountScrubImbalance (acc, percentagefunc);
344     gnc_account_foreach_descendant(acc,
345                                    (AccountCb)xaccAccountScrubImbalance, percentagefunc);
346     scrub_depth--;
347 }
348 
349 void
xaccAccountScrubImbalance(Account * acc,QofPercentageFunc percentagefunc)350 xaccAccountScrubImbalance (Account *acc, QofPercentageFunc percentagefunc)
351 {
352     GList *node, *splits;
353     const char *str;
354     const char *message = _( "Looking for imbalances in account %s: %u of %u");
355     gint split_count = 0, curr_split_no = 0;
356 
357     if (!acc) return;
358     /* If it's a trading account and an imbalanced transaction is
359      * found the trading splits will be replaced, invalidating the
360      * split list in mid-traversal, see
361      * https://bugs.gnucash.org/show_bug.cgi?id=798346. Also the
362      * transactions will get scrubbed at least twice from their "real"
363      * accounts anyway so doing so from the trading accounts is wasted
364      * effort.
365      */
366     if (xaccAccountGetType(acc) == ACCT_TYPE_TRADING)
367          return;
368 
369     scrub_depth++;
370 
371     str = xaccAccountGetName(acc);
372     str = str ? str : "(null)";
373     PINFO ("Looking for imbalances in account %s\n", str);
374 
375     splits = xaccAccountGetSplitList(acc);
376     split_count = g_list_length (splits);
377     for (node = splits; node; node = node->next)
378     {
379         Split *split = node->data;
380         Transaction *trans = xaccSplitGetParent(split);
381         if (abort_now) break;
382 
383         PINFO("Start processing split %d of %d",
384               curr_split_no + 1, split_count);
385 
386         if (curr_split_no % 10 == 0)
387         {
388             char *progress_msg = g_strdup_printf (message, str, curr_split_no, split_count);
389             (percentagefunc)(progress_msg, (100 * curr_split_no) / split_count);
390             g_free (progress_msg);
391         }
392 
393         TransScrubOrphansFast (xaccSplitGetParent (split),
394                                gnc_account_get_root (acc));
395 
396         xaccTransScrubCurrency(trans);
397 
398         xaccTransScrubImbalance (trans, gnc_account_get_root (acc), NULL);
399 
400         PINFO("Finished processing split %d of %d",
401               curr_split_no + 1, split_count);
402         curr_split_no++;
403     }
404     (percentagefunc)(NULL, -1.0);
405     scrub_depth--;
406 }
407 
408 static Split *
get_balance_split(Transaction * trans,Account * root,Account * account,gnc_commodity * commodity)409 get_balance_split (Transaction *trans, Account *root, Account *account,
410                    gnc_commodity *commodity)
411 {
412     Split *balance_split;
413     gchar *accname;
414 
415     if (!account ||
416         !gnc_commodity_equiv (commodity, xaccAccountGetCommodity(account)))
417     {
418         if (!root)
419         {
420             root = gnc_book_get_root_account (xaccTransGetBook (trans));
421             if (NULL == root)
422             {
423                 /* This can't occur, things should be in books */
424                 PERR ("Bad data corruption, no root account in book");
425                 return NULL;
426             }
427         }
428         accname = g_strconcat (_("Imbalance"), "-",
429                                gnc_commodity_get_mnemonic (commodity), NULL);
430         account = xaccScrubUtilityGetOrMakeAccount (root, commodity,
431                                                     accname, ACCT_TYPE_BANK,
432                                                     FALSE, TRUE);
433         g_free (accname);
434         if (!account)
435         {
436             PERR ("Can't get balancing account");
437             return NULL;
438         }
439     }
440 
441     balance_split = xaccTransFindSplitByAccount(trans, account);
442 
443     /* Put split into account before setting split value */
444     if (!balance_split)
445     {
446         balance_split = xaccMallocSplit (qof_instance_get_book(trans));
447 
448         xaccTransBeginEdit (trans);
449         xaccSplitSetParent(balance_split, trans);
450         xaccSplitSetAccount(balance_split, account);
451         xaccTransCommitEdit (trans);
452     }
453 
454     return balance_split;
455 }
456 
457 static gnc_commodity*
find_root_currency(void)458 find_root_currency(void)
459 {
460     QofSession *sess = gnc_get_current_session ();
461     Account *root = gnc_book_get_root_account (qof_session_get_book (sess));
462     gnc_commodity *root_currency = xaccAccountGetCommodity (root);
463 
464     /* Some older books may not have a currency set on the root
465      * account. In that case find the first top-level INCOME account
466      * and use its currency. */
467     if (!root_currency)
468     {
469          GList *children = gnc_account_get_children (root);
470          for (GList *node = children; node && !root_currency;
471               node = g_list_next (node))
472          {
473               Account *child = GNC_ACCOUNT (node->data);
474               if (xaccAccountGetType (child) == ACCT_TYPE_INCOME)
475                    root_currency = xaccAccountGetCommodity (child);
476          }
477          g_list_free (children);
478     }
479     return root_currency;
480 }
481 
482 /* Get the trading split for a given commodity, creating it (and the
483    necessary parent accounts) if it doesn't exist. */
484 static Split *
get_trading_split(Transaction * trans,Account * base,gnc_commodity * commodity)485 get_trading_split (Transaction *trans, Account *base,
486                    gnc_commodity *commodity)
487 {
488     Split *balance_split;
489     Account *trading_account;
490     Account *ns_account;
491     Account *account;
492     Account* root = gnc_book_get_root_account (xaccTransGetBook (trans));
493     gnc_commodity *root_currency = find_root_currency ();
494 
495     trading_account = xaccScrubUtilityGetOrMakeAccount (root,
496                                                         NULL,
497                                                         _("Trading"),
498                                                         ACCT_TYPE_TRADING,
499                                                         TRUE, FALSE);
500     if (!trading_account)
501     {
502         PERR ("Can't get trading account");
503         return NULL;
504     }
505 
506     ns_account = xaccScrubUtilityGetOrMakeAccount (trading_account,
507                                                    NULL,
508                                                    gnc_commodity_get_namespace(commodity),
509                                                    ACCT_TYPE_TRADING,
510                                                    TRUE, TRUE);
511     if (!ns_account)
512     {
513         PERR ("Can't get namespace account");
514         return NULL;
515     }
516 
517     account = xaccScrubUtilityGetOrMakeAccount (ns_account, commodity,
518                                                 gnc_commodity_get_mnemonic(commodity),
519                                                 ACCT_TYPE_TRADING,
520                                                 FALSE, FALSE);
521     if (!account)
522     {
523         PERR ("Can't get commodity account");
524         return NULL;
525     }
526 
527 
528     balance_split = xaccTransFindSplitByAccount(trans, account);
529 
530     /* Put split into account before setting split value */
531     if (!balance_split)
532     {
533         balance_split = xaccMallocSplit (qof_instance_get_book(trans));
534 
535         xaccTransBeginEdit (trans);
536         xaccSplitSetParent(balance_split, trans);
537         xaccSplitSetAccount(balance_split, account);
538         xaccTransCommitEdit (trans);
539     }
540 
541     return balance_split;
542 }
543 
544 static void
add_balance_split(Transaction * trans,gnc_numeric imbalance,Account * root,Account * account)545 add_balance_split (Transaction *trans, gnc_numeric imbalance,
546                    Account *root, Account *account)
547 {
548     const gnc_commodity *commodity;
549     gnc_numeric old_value, new_value;
550     Split *balance_split;
551     gnc_commodity *currency = xaccTransGetCurrency (trans);
552 
553     balance_split = get_balance_split(trans, root, account, currency);
554     if (!balance_split)
555     {
556         /* Error already logged */
557         LEAVE("");
558         return;
559     }
560     account = xaccSplitGetAccount(balance_split);
561 
562     xaccTransBeginEdit (trans);
563 
564     old_value = xaccSplitGetValue (balance_split);
565 
566     /* Note: We have to round for the commodity's fraction, NOT any
567      * already existing denominator (bug #104343), because either one
568      * of the denominators might already be reduced.  */
569     new_value = gnc_numeric_sub (old_value, imbalance,
570                                  gnc_commodity_get_fraction(currency),
571                                  GNC_HOW_RND_ROUND_HALF_UP);
572 
573     xaccSplitSetValue (balance_split, new_value);
574 
575     commodity = xaccAccountGetCommodity (account);
576     if (gnc_commodity_equiv (currency, commodity))
577     {
578         xaccSplitSetAmount (balance_split, new_value);
579     }
580 
581     xaccSplitScrub (balance_split);
582     xaccTransCommitEdit (trans);
583 }
584 
585 /* Balance a transaction without trading accounts. */
586 static void
gnc_transaction_balance_no_trading(Transaction * trans,Account * root,Account * account)587 gnc_transaction_balance_no_trading (Transaction *trans, Account *root,
588                                     Account *account)
589 {
590     gnc_numeric imbalance  = xaccTransGetImbalanceValue (trans);
591 
592     /* Make the value sum to zero */
593     if (! gnc_numeric_zero_p (imbalance))
594     {
595         PINFO ("Value unbalanced transaction");
596 
597         add_balance_split (trans, imbalance, root, account);
598     }
599 
600 }
601 
602 static gnc_numeric
gnc_transaction_get_commodity_imbalance(Transaction * trans,gnc_commodity * commodity)603 gnc_transaction_get_commodity_imbalance (Transaction *trans,
604                                          gnc_commodity *commodity)
605 {
606     /* Find the value imbalance in this commodity */
607     gnc_numeric val_imbalance = gnc_numeric_zero();
608     GList *splits = NULL;
609     for (splits = trans->splits; splits; splits = splits->next)
610     {
611         Split *split = splits->data;
612         gnc_commodity *split_commodity =
613             xaccAccountGetCommodity(xaccSplitGetAccount(split));
614         if (xaccTransStillHasSplit (trans, split) &&
615             gnc_commodity_equal (commodity, split_commodity))
616             val_imbalance = gnc_numeric_add (val_imbalance,
617                                              xaccSplitGetValue (split),
618                                              GNC_DENOM_AUTO,
619                                              GNC_HOW_DENOM_EXACT);
620     }
621     return val_imbalance;
622 }
623 
624 /* GFunc wrapper for xaccSplitDestroy */
625 static void
destroy_split(void * ptr)626 destroy_split (void* ptr)
627 {
628     Split *split = GNC_SPLIT (ptr);
629     if (split)
630         xaccSplitDestroy (split);
631 }
632 
633 /* Balancing transactions with trading accounts works best when
634  * starting with no trading splits.
635  */
636 static void
xaccTransClearTradingSplits(Transaction * trans)637 xaccTransClearTradingSplits (Transaction *trans)
638 {
639     GList *trading_splits = NULL;
640 
641     for (GList* node = trans->splits; node; node = node->next)
642     {
643          Split* split = GNC_SPLIT(node->data);
644          Account* acc = NULL;
645          if (!split)
646               continue;
647          acc = xaccSplitGetAccount(split);
648          if (acc && xaccAccountGetType(acc) == ACCT_TYPE_TRADING)
649             trading_splits = g_list_prepend (trading_splits, node->data);
650     }
651 
652     if (!trading_splits)
653         return;
654 
655     xaccTransBeginEdit (trans);
656     /* destroy_splits doesn't actually free the splits but this gets
657      * the list ifself freed.
658      */
659     g_list_free_full (trading_splits, destroy_split);
660     xaccTransCommitEdit (trans);
661 }
662 
663 static void
gnc_transaction_balance_trading(Transaction * trans,Account * root)664 gnc_transaction_balance_trading (Transaction *trans, Account *root)
665 {
666     MonetaryList *imbal_list;
667     MonetaryList *imbalance_commod;
668     Split *balance_split = NULL;
669 
670     /* If the transaction is balanced, nothing more to do */
671     imbal_list = xaccTransGetImbalance (trans);
672     if (!imbal_list)
673     {
674         LEAVE("transaction is balanced");
675         return;
676     }
677 
678     PINFO ("Currency unbalanced transaction");
679 
680     for (imbalance_commod = imbal_list; imbalance_commod;
681          imbalance_commod = imbalance_commod->next)
682     {
683         gnc_monetary *imbal_mon = imbalance_commod->data;
684         gnc_commodity *commodity;
685         gnc_numeric old_amount, new_amount;
686         const gnc_commodity *txn_curr = xaccTransGetCurrency (trans);
687 
688         commodity = gnc_monetary_commodity (*imbal_mon);
689 
690         balance_split = get_trading_split(trans, root, commodity);
691         if (!balance_split)
692         {
693             /* Error already logged */
694             gnc_monetary_list_free(imbal_list);
695             LEAVE("");
696             return;
697         }
698 
699         xaccTransBeginEdit (trans);
700 
701         old_amount = xaccSplitGetAmount (balance_split);
702         new_amount = gnc_numeric_sub (old_amount, gnc_monetary_value(*imbal_mon),
703                                       gnc_commodity_get_fraction(commodity),
704                                       GNC_HOW_RND_ROUND_HALF_UP);
705 
706         xaccSplitSetAmount (balance_split, new_amount);
707 
708         if (gnc_commodity_equal (txn_curr, commodity))
709         {
710             /* Imbalance commodity is the transaction currency, value in the
711                split must be the same as the amount */
712             xaccSplitSetValue (balance_split, new_amount);
713         }
714         else
715         {
716             gnc_numeric val_imbalance = gnc_transaction_get_commodity_imbalance (trans,            commodity);
717 
718             gnc_numeric old_value = xaccSplitGetValue (balance_split);
719             gnc_numeric new_value = gnc_numeric_sub (old_value, val_imbalance,
720                                          gnc_commodity_get_fraction(txn_curr),
721                                          GNC_HOW_RND_ROUND_HALF_UP);
722 
723             xaccSplitSetValue (balance_split, new_value);
724         }
725 
726         xaccSplitScrub (balance_split);
727         xaccTransCommitEdit (trans);
728     }
729 
730     gnc_monetary_list_free(imbal_list);
731 }
732 
733 /** Balance the transaction by adding more trading splits. This shouldn't
734  * ordinarily be necessary.
735  * @param trans the transaction to balance
736  * @param root the root account
737  */
738 static void
gnc_transaction_balance_trading_more_splits(Transaction * trans,Account * root)739 gnc_transaction_balance_trading_more_splits (Transaction *trans, Account *root)
740 {
741     /* Copy the split list so we don't see the splits we're adding */
742     GList *splits_dup = g_list_copy(trans->splits), *splits = NULL;
743     const gnc_commodity  *txn_curr = xaccTransGetCurrency (trans);
744     for (splits = splits_dup; splits; splits = splits->next)
745     {
746         Split *split = splits->data;
747         if (! xaccTransStillHasSplit(trans, split)) continue;
748         if (!gnc_numeric_zero_p(xaccSplitGetValue(split)) &&
749             gnc_numeric_zero_p(xaccSplitGetAmount(split)))
750         {
751             gnc_commodity *commodity;
752             gnc_numeric old_value, new_value;
753             Split *balance_split;
754 
755             commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split));
756             if (!commodity)
757             {
758                 PERR("Split has no commodity");
759                 continue;
760             }
761             balance_split = get_trading_split(trans, root, commodity);
762             if (!balance_split)
763             {
764                 /* Error already logged */
765                 LEAVE("");
766                 return;
767             }
768             xaccTransBeginEdit (trans);
769 
770             old_value = xaccSplitGetValue (balance_split);
771             new_value = gnc_numeric_sub (old_value, xaccSplitGetValue(split),
772                                          gnc_commodity_get_fraction(txn_curr),
773                                          GNC_HOW_RND_ROUND_HALF_UP);
774             xaccSplitSetValue (balance_split, new_value);
775 
776             /* Don't change the balance split's amount since the amount
777                is zero in the split we're working on */
778 
779             xaccSplitScrub (balance_split);
780             xaccTransCommitEdit (trans);
781         }
782     }
783 
784     g_list_free(splits_dup);
785 }
786 
787 /** Correct transaction imbalances.
788  * @param trans The Transaction
789  * @param root The (hidden) root account, for the book default currency.
790  * @param account The account whose currency in which to balance.
791  */
792 
793 void
xaccTransScrubImbalance(Transaction * trans,Account * root,Account * account)794 xaccTransScrubImbalance (Transaction *trans, Account *root,
795                          Account *account)
796 {
797     gnc_numeric imbalance;
798 
799     if (!trans) return;
800 
801     ENTER ("()");
802 
803     /* Must look for orphan splits even if there is no imbalance. */
804     xaccTransScrubSplits (trans);
805 
806     /* Return immediately if things are balanced. */
807     if (xaccTransIsBalanced (trans))
808     {
809         LEAVE ("transaction is balanced");
810         return;
811     }
812 
813     if (! xaccTransUseTradingAccounts (trans))
814     {
815         gnc_transaction_balance_no_trading (trans, root, account);
816         LEAVE ("transaction balanced, no managed trading accounts");
817         return;
818     }
819 
820     xaccTransClearTradingSplits (trans);
821     imbalance = xaccTransGetImbalanceValue (trans);
822     if (! gnc_numeric_zero_p (imbalance))
823     {
824         PINFO ("Value unbalanced transaction");
825 
826         add_balance_split (trans, imbalance, root, account);
827     }
828 
829     gnc_transaction_balance_trading (trans, root);
830     if (gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
831     {
832         LEAVE ("()");
833         return;
834     }
835     /* If the transaction is still not balanced, it's probably because there
836        are splits with zero amount and non-zero value.  These are usually
837        realized gain/loss splits.  Add a reversing split for each of them to
838        balance the value. */
839 
840     gnc_transaction_balance_trading_more_splits (trans, root);
841     if (!gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
842         PERR("Balancing currencies unbalanced value");
843 
844 }
845 
846 /* ================================================================ */
847 /* The xaccTransFindCommonCurrency () method returns
848  *    a gnc_commodity indicating a currency denomination that all
849  *    of the splits in this transaction have in common, using the
850  *    old/obsolete currency/security fields of the split accounts.
851  */
852 
853 static gnc_commodity *
FindCommonExclSCurrency(SplitList * splits,gnc_commodity * ra,gnc_commodity * rb,Split * excl_split)854 FindCommonExclSCurrency (SplitList *splits,
855                          gnc_commodity * ra, gnc_commodity * rb,
856                          Split *excl_split)
857 {
858     GList *node;
859 
860     if (!splits) return NULL;
861 
862     for (node = splits; node; node = node->next)
863     {
864         Split *s = node->data;
865         gnc_commodity * sa, * sb;
866 
867         if (s == excl_split) continue;
868 
869         g_return_val_if_fail (s->acc, NULL);
870 
871         sa = DxaccAccountGetCurrency (s->acc);
872         sb = xaccAccountGetCommodity (s->acc);
873 
874         if (ra && rb)
875         {
876             int aa = !gnc_commodity_equiv(ra, sa);
877             int ab = !gnc_commodity_equiv(ra, sb);
878             int ba = !gnc_commodity_equiv(rb, sa);
879             int bb = !gnc_commodity_equiv(rb, sb);
880 
881             if ( (!aa) && bb) rb = NULL;
882             else if ( (!ab) && ba) rb = NULL;
883             else if ( (!ba) && ab) ra = NULL;
884             else if ( (!bb) && aa) ra = NULL;
885             else if ( aa && bb && ab && ba )
886             {
887                 ra = NULL;
888                 rb = NULL;
889             }
890 
891             if (!ra)
892             {
893                 ra = rb;
894                 rb = NULL;
895             }
896         }
897         else if (ra && !rb)
898         {
899             int aa = !gnc_commodity_equiv(ra, sa);
900             int ab = !gnc_commodity_equiv(ra, sb);
901             if ( aa && ab ) ra = NULL;
902         }
903         else if (!ra && rb)
904         {
905             int aa = !gnc_commodity_equiv(rb, sa);
906             int ab = !gnc_commodity_equiv(rb, sb);
907             ra = ( aa && ab ) ? NULL : rb;
908         }
909 
910         if ((!ra) && (!rb)) return NULL;
911     }
912 
913     return (ra);
914 }
915 
916 /* This is the wrapper for those calls (i.e. the older ones) which
917  * don't exclude one split from the splitlist when looking for a
918  * common currency.
919  */
920 static gnc_commodity *
FindCommonCurrency(GList * splits,gnc_commodity * ra,gnc_commodity * rb)921 FindCommonCurrency (GList *splits, gnc_commodity * ra, gnc_commodity * rb)
922 {
923     return FindCommonExclSCurrency(splits, ra, rb, NULL);
924 }
925 
926 static gnc_commodity *
xaccTransFindOldCommonCurrency(Transaction * trans,QofBook * book)927 xaccTransFindOldCommonCurrency (Transaction *trans, QofBook *book)
928 {
929     gnc_commodity *ra, *rb, *retval;
930     Split *split;
931 
932     if (!trans) return NULL;
933 
934     if (trans->splits == NULL) return NULL;
935 
936     g_return_val_if_fail (book, NULL);
937 
938     split = trans->splits->data;
939 
940     if (!split || NULL == split->acc) return NULL;
941 
942     ra = DxaccAccountGetCurrency (split->acc);
943     rb = xaccAccountGetCommodity (split->acc);
944 
945     retval = FindCommonCurrency (trans->splits, ra, rb);
946 
947     if (retval && !gnc_commodity_is_currency(retval))
948         retval = NULL;
949 
950     return retval;
951 }
952 
953 /* Test the currency of the splits and find the most common and return
954  * it, or NULL if there is no currency more common than the
955  * others -- or none at all.
956  */
957 typedef struct
958 {
959     gnc_commodity *commodity;
960     unsigned int count;
961 } CommodityCount;
962 
963 static gint
commodity_equal(gconstpointer a,gconstpointer b)964 commodity_equal (gconstpointer a, gconstpointer b)
965 {
966     CommodityCount *cc = (CommodityCount*)a;
967     gnc_commodity *com = (gnc_commodity*)b;
968     if ( cc == NULL || cc->commodity == NULL ||
969          !GNC_IS_COMMODITY( cc->commodity ) ) return -1;
970     if ( com == NULL || !GNC_IS_COMMODITY( com ) ) return 1;
971     if ( gnc_commodity_equal(cc->commodity, com) )
972         return 0;
973     return 1;
974 }
975 
976 static gint
commodity_compare(gconstpointer a,gconstpointer b)977 commodity_compare( gconstpointer a, gconstpointer b)
978 {
979     CommodityCount *ca = (CommodityCount*)a, *cb = (CommodityCount*)b;
980     if (ca == NULL || ca->commodity == NULL ||
981         !GNC_IS_COMMODITY( ca->commodity ) )
982     {
983         if (cb == NULL || cb->commodity == NULL ||
984             !GNC_IS_COMMODITY( cb->commodity ) )
985             return 0;
986         return -1;
987     }
988     if (cb == NULL || cb->commodity == NULL ||
989         !GNC_IS_COMMODITY( cb->commodity ) )
990         return 1;
991     if (ca->count == cb->count)
992         return 0;
993     return ca->count > cb->count ? 1 : -1;
994 }
995 
996 /* Find the commodities in the account of each of the splits of a
997  * transaction, and rank them by how many splits in which they
998  * occur. Commodities which are currencies count more than those which
999  * aren't, because for simple buy and sell transactions it makes
1000  * slightly more sense for the transaction commodity to be the
1001  * currency -- to the extent that it makes sense for a transaction to
1002  * have a currency at all. jralls, 2010-11-02 */
1003 
1004 static gnc_commodity *
xaccTransFindCommonCurrency(Transaction * trans,QofBook * book)1005 xaccTransFindCommonCurrency (Transaction *trans, QofBook *book)
1006 {
1007     gnc_commodity *com_scratch;
1008     GList *node = NULL;
1009     GSList *comlist = NULL, *found = NULL;
1010 
1011     if (!trans) return NULL;
1012 
1013     if (trans->splits == NULL) return NULL;
1014 
1015     g_return_val_if_fail (book, NULL);
1016 
1017     /* Find the most commonly used currency among the splits.  If a given split
1018        is in a non-currency commodity, then look for an ancestor account in a
1019        currency, but prefer currencies used directly in splits.  Ignore trading
1020        account splits in this whole process, they don't add any value to this algorithm. */
1021     for (node = trans->splits; node; node = node->next)
1022     {
1023         Split *s = node->data;
1024         unsigned int curr_weight;
1025 
1026         if (s == NULL || s->acc == NULL) continue;
1027         if (xaccAccountGetType(s->acc) == ACCT_TYPE_TRADING) continue;
1028         com_scratch = xaccAccountGetCommodity(s->acc);
1029         if (com_scratch && gnc_commodity_is_currency(com_scratch))
1030         {
1031             curr_weight = 3;
1032         }
1033         else
1034         {
1035             com_scratch = gnc_account_get_currency_or_parent(s->acc);
1036             if (com_scratch == NULL) continue;
1037             curr_weight = 1;
1038         }
1039         if ( comlist )
1040         {
1041             found = g_slist_find_custom(comlist, com_scratch, commodity_equal);
1042         }
1043         if (comlist == NULL || found == NULL)
1044         {
1045             CommodityCount *count = g_slice_new0(CommodityCount);
1046             count->commodity = com_scratch;
1047             count->count = curr_weight;
1048             comlist = g_slist_append(comlist, count);
1049         }
1050         else
1051         {
1052             CommodityCount *count = (CommodityCount*)(found->data);
1053             count->count += curr_weight;
1054         }
1055     }
1056     found = g_slist_sort( comlist, commodity_compare);
1057 
1058     if ( found && found->data && (((CommodityCount*)(found->data))->commodity != NULL))
1059     {
1060         return ((CommodityCount*)(found->data))->commodity;
1061     }
1062     /* We didn't find a currency in the current account structure, so try
1063      * an old one. */
1064     return xaccTransFindOldCommonCurrency( trans, book );
1065 }
1066 
1067 /* ================================================================ */
1068 
1069 void
xaccTransScrubCurrency(Transaction * trans)1070 xaccTransScrubCurrency (Transaction *trans)
1071 {
1072     SplitList *node;
1073     gnc_commodity *currency;
1074 
1075     if (!trans) return;
1076 
1077     /* If there are any orphaned splits in a transaction, then the
1078      * this routine will fail.  Therefore, we want to make sure that
1079      * there are no orphans (splits without parent account).
1080      */
1081     xaccTransScrubOrphans (trans);
1082 
1083     currency = xaccTransGetCurrency (trans);
1084     if (currency && gnc_commodity_is_currency(currency)) return;
1085 
1086     currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
1087     if (currency)
1088     {
1089         xaccTransBeginEdit (trans);
1090         xaccTransSetCurrency (trans, currency);
1091         xaccTransCommitEdit (trans);
1092     }
1093     else
1094     {
1095         if (NULL == trans->splits)
1096         {
1097             PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
1098         }
1099         else
1100         {
1101             SplitList *node;
1102             char guid_str[GUID_ENCODING_LENGTH + 1];
1103             guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
1104             PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
1105                    trans->description, guid_str);
1106 
1107             for (node = trans->splits; node; node = node->next)
1108             {
1109                 Split *split = node->data;
1110                 if (NULL == split->acc)
1111                 {
1112                     PWARN (" split=\"%s\" is not in any account!", split->memo);
1113                 }
1114                 else
1115                 {
1116                     gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
1117                     PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
1118                            split->memo, xaccAccountGetName(split->acc),
1119                            gnc_commodity_get_mnemonic(currency));
1120 
1121                     xaccTransBeginEdit (trans);
1122                     xaccTransSetCurrency (trans, currency);
1123                     xaccTransCommitEdit (trans);
1124                     return;
1125                 }
1126             }
1127         }
1128         return;
1129     }
1130 
1131     for (node = trans->splits; node; node = node->next)
1132     {
1133         Split *sp = node->data;
1134 
1135         if (!gnc_numeric_equal(xaccSplitGetAmount (sp),
1136                                xaccSplitGetValue (sp)))
1137         {
1138             gnc_commodity *acc_currency;
1139 
1140             acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : NULL;
1141             if (acc_currency == currency)
1142             {
1143                 /* This Split needs fixing: The transaction-currency equals
1144                  * the account-currency/commodity, but the amount/values are
1145                  * inequal i.e. they still correspond to the security
1146                  * (amount) and the currency (value). In the new model, the
1147                  * value is the amount in the account-commodity -- so it
1148                  * needs to be set to equal the amount (since the
1149                  * account-currency doesn't exist anymore).
1150                  *
1151                  * Note: Nevertheless we lose some information here. Namely,
1152                  * the information that the 'amount' in 'account-old-security'
1153                  * was worth 'value' in 'account-old-currency'. Maybe it would
1154                  * be better to store that information in the price database?
1155                  * But then, for old currency transactions there is still the
1156                  * 'other' transaction, which is going to keep that
1157                  * information. So I don't bother with that here. -- cstim,
1158                  * 2002/11/20. */
1159 
1160                 PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
1161                        " old amount %s %s, new amount %s",
1162                        trans->description, sp->memo,
1163                        gnc_num_dbg_to_string (xaccSplitGetAmount(sp)),
1164                        gnc_commodity_get_mnemonic (currency),
1165                        gnc_num_dbg_to_string (xaccSplitGetValue(sp)));
1166                 xaccTransBeginEdit (trans);
1167                 xaccSplitSetAmount (sp, xaccSplitGetValue(sp));
1168                 xaccTransCommitEdit (trans);
1169             }
1170             /*else
1171               {
1172               PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
1173               xaccSplitGetMemo (sp),
1174               gnc_num_dbg_to_string (amount),
1175               gnc_commodity_get_mnemonic (currency),
1176               gnc_num_dbg_to_string (value),
1177               gnc_commodity_get_mnemonic (acc_currency));
1178               }*/
1179         }
1180     }
1181 
1182 }
1183 
1184 /* ================================================================ */
1185 
1186 void
xaccAccountScrubCommodity(Account * account)1187 xaccAccountScrubCommodity (Account *account)
1188 {
1189     gnc_commodity *commodity;
1190 
1191     if (!account) return;
1192     if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
1193 
1194     commodity = xaccAccountGetCommodity (account);
1195     if (commodity) return;
1196 
1197     /* Use the 'obsolete' routines to try to figure out what the
1198      * account commodity should have been. */
1199     commodity = xaccAccountGetCommodity (account);
1200     if (commodity)
1201     {
1202         xaccAccountSetCommodity (account, commodity);
1203         return;
1204     }
1205 
1206     commodity = DxaccAccountGetCurrency (account);
1207     if (commodity)
1208     {
1209         xaccAccountSetCommodity (account, commodity);
1210         return;
1211     }
1212 
1213     PERR ("Account \"%s\" does not have a commodity!",
1214           xaccAccountGetName(account));
1215 }
1216 
1217 /* ================================================================ */
1218 
1219 /* EFFECTIVE FRIEND FUNCTION declared in qofinstance-p.h */
1220 extern void qof_instance_set_dirty (QofInstance*);
1221 
1222 static void
xaccAccountDeleteOldData(Account * account)1223 xaccAccountDeleteOldData (Account *account)
1224 {
1225     if (!account) return;
1226     xaccAccountBeginEdit (account);
1227     qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency");
1228     qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-security");
1229     qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency-scu");
1230     qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-security-scu");
1231     qof_instance_set_dirty (QOF_INSTANCE (account));
1232     xaccAccountCommitEdit (account);
1233 }
1234 
1235 static int
scrub_trans_currency_helper(Transaction * t,gpointer data)1236 scrub_trans_currency_helper (Transaction *t, gpointer data)
1237 {
1238     xaccTransScrubCurrency (t);
1239     return 0;
1240 }
1241 
1242 static void
scrub_account_commodity_helper(Account * account,gpointer data)1243 scrub_account_commodity_helper (Account *account, gpointer data)
1244 {
1245     scrub_depth++;
1246     xaccAccountScrubCommodity (account);
1247     xaccAccountDeleteOldData (account);
1248     scrub_depth--;
1249 }
1250 
1251 void
xaccAccountTreeScrubCommodities(Account * acc)1252 xaccAccountTreeScrubCommodities (Account *acc)
1253 {
1254     if (!acc) return;
1255     scrub_depth++;
1256     xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, NULL);
1257 
1258     scrub_account_commodity_helper (acc, NULL);
1259     gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, NULL);
1260     scrub_depth--;
1261 }
1262 
1263 /* ================================================================ */
1264 
1265 static gboolean
check_quote_source(gnc_commodity * com,gpointer data)1266 check_quote_source (gnc_commodity *com, gpointer data)
1267 {
1268     gboolean *commodity_has_quote_src = (gboolean *)data;
1269     if (com && !gnc_commodity_is_iso(com))
1270         *commodity_has_quote_src |= gnc_commodity_get_quote_flag(com);
1271     return TRUE;
1272 }
1273 
1274 static void
move_quote_source(Account * account,gpointer data)1275 move_quote_source (Account *account, gpointer data)
1276 {
1277     gnc_commodity *com;
1278     gnc_quote_source *quote_source;
1279     gboolean new_style = GPOINTER_TO_INT(data);
1280     const char *source, *tz;
1281 
1282     com = xaccAccountGetCommodity(account);
1283     if (!com)
1284         return;
1285 
1286     if (!new_style)
1287     {
1288         source = dxaccAccountGetPriceSrc(account);
1289         if (!source || !*source)
1290             return;
1291         tz = dxaccAccountGetQuoteTZ(account);
1292 
1293         PINFO("to %8s from %s", gnc_commodity_get_mnemonic(com),
1294               xaccAccountGetName(account));
1295         gnc_commodity_set_quote_flag(com, TRUE);
1296         quote_source = gnc_quote_source_lookup_by_internal(source);
1297         if (!quote_source)
1298             quote_source = gnc_quote_source_add_new(source, FALSE);
1299         gnc_commodity_set_quote_source(com, quote_source);
1300         gnc_commodity_set_quote_tz(com, tz);
1301     }
1302 
1303     dxaccAccountSetPriceSrc(account, NULL);
1304     dxaccAccountSetQuoteTZ(account, NULL);
1305     return;
1306 }
1307 
1308 
1309 void
xaccAccountTreeScrubQuoteSources(Account * root,gnc_commodity_table * table)1310 xaccAccountTreeScrubQuoteSources (Account *root, gnc_commodity_table *table)
1311 {
1312     gboolean new_style = FALSE;
1313     ENTER(" ");
1314 
1315     if (!root || !table)
1316     {
1317         LEAVE("Oops");
1318         return;
1319     }
1320     scrub_depth++;
1321     gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
1322 
1323     move_quote_source(root, GINT_TO_POINTER(new_style));
1324     gnc_account_foreach_descendant (root, move_quote_source,
1325                                     GINT_TO_POINTER(new_style));
1326     LEAVE("Migration done");
1327     scrub_depth--;
1328 }
1329 
1330 /* ================================================================ */
1331 
1332 void
xaccAccountScrubKvp(Account * account)1333 xaccAccountScrubKvp (Account *account)
1334 {
1335     GValue v = G_VALUE_INIT;
1336     gchar *str2;
1337 
1338     if (!account) return;
1339     scrub_depth++;
1340 
1341     qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "notes");
1342     if (G_VALUE_HOLDS_STRING (&v))
1343     {
1344         str2 = g_strstrip(g_value_dup_string(&v));
1345         if (strlen(str2) == 0)
1346             qof_instance_slot_delete (QOF_INSTANCE (account), "notes");
1347         g_free(str2);
1348     }
1349 
1350     qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "placeholder");
1351     if ((G_VALUE_HOLDS_STRING (&v) &&
1352         strcmp(g_value_get_string (&v), "false") == 0) ||
1353         (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
1354         qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
1355 
1356     g_value_unset (&v);
1357     qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
1358     scrub_depth--;
1359 }
1360 
1361 /* ================================================================ */
1362 
1363 void
xaccAccountScrubColorNotSet(QofBook * book)1364 xaccAccountScrubColorNotSet (QofBook *book)
1365 {
1366     GValue value_s = G_VALUE_INIT;
1367     gboolean already_scrubbed;
1368 
1369     // get the run-once value
1370     qof_instance_get_kvp (QOF_INSTANCE (book), &value_s, 1, "remove-color-not-set-slots");
1371 
1372     already_scrubbed = (G_VALUE_HOLDS_STRING (&value_s) &&
1373                         !g_strcmp0 (g_value_get_string (&value_s), "true"));
1374     g_value_unset (&value_s);
1375 
1376     if (already_scrubbed)
1377         return;
1378     else
1379     {
1380         GValue value_b = G_VALUE_INIT;
1381         Account *root = gnc_book_get_root_account (book);
1382         GList *accts = gnc_account_get_descendants_sorted (root);
1383         GList *ptr;
1384 
1385         for (ptr = accts; ptr; ptr = g_list_next (ptr))
1386         {
1387             const gchar *color = xaccAccountGetColor (ptr->data);
1388 
1389             if (g_strcmp0 (color, "Not Set") == 0)
1390                 xaccAccountSetColor (ptr->data, "");
1391         }
1392         g_list_free (accts);
1393 
1394         g_value_init (&value_b, G_TYPE_BOOLEAN);
1395         g_value_set_boolean (&value_b, TRUE);
1396 
1397         // set the run-once value
1398         qof_instance_set_kvp (QOF_INSTANCE (book),  &value_b, 1, "remove-color-not-set-slots");
1399         g_value_unset (&value_b);
1400     }
1401 }
1402 
1403 /* ================================================================ */
1404 
1405 static Account*
construct_account(Account * root,gnc_commodity * currency,const char * accname,GNCAccountType acctype,gboolean placeholder)1406 construct_account (Account *root, gnc_commodity *currency, const char *accname,
1407                    GNCAccountType acctype, gboolean placeholder)
1408 {
1409     gnc_commodity* root_currency = find_root_currency ();
1410     Account *acc = xaccMallocAccount(gnc_account_get_book (root));
1411     xaccAccountBeginEdit (acc);
1412     if (accname && *accname)
1413          xaccAccountSetName (acc, accname);
1414     if (currency || root_currency)
1415          xaccAccountSetCommodity (acc, currency ? currency : root_currency);
1416     xaccAccountSetType (acc, acctype);
1417     xaccAccountSetPlaceholder (acc, placeholder);
1418 
1419     /* Hang the account off the root. */
1420     gnc_account_append_child (root, acc);
1421     xaccAccountCommitEdit (acc);
1422     return acc;
1423 }
1424 
1425 static Account*
find_root_currency_account_in_list(GList * acc_list)1426 find_root_currency_account_in_list (GList *acc_list)
1427 {
1428     gnc_commodity* root_currency = find_root_currency();
1429     for (GList *node = acc_list; node; node = g_list_next (node))
1430     {
1431         Account *acc = GNC_ACCOUNT (node->data);
1432         gnc_commodity *acc_commodity = NULL;
1433         if (G_UNLIKELY (!acc)) continue;
1434         acc_commodity = xaccAccountGetCommodity(acc);
1435         if (gnc_commodity_equiv (acc_commodity, root_currency))
1436             return acc;
1437     }
1438 
1439     return NULL;
1440 }
1441 
1442 static Account*
find_account_matching_name_in_list(GList * acc_list,const char * accname)1443 find_account_matching_name_in_list (GList *acc_list, const char* accname)
1444 {
1445     for (GList* node = acc_list; node; node = g_list_next(node))
1446     {
1447         Account *acc = GNC_ACCOUNT (node->data);
1448         if (G_UNLIKELY (!acc)) continue;
1449         if (g_strcmp0 (accname, xaccAccountGetName (acc)) == 0)
1450             return acc;
1451     }
1452     return NULL;
1453 }
1454 
1455 Account *
xaccScrubUtilityGetOrMakeAccount(Account * root,gnc_commodity * currency,const char * accname,GNCAccountType acctype,gboolean placeholder,gboolean checkname)1456 xaccScrubUtilityGetOrMakeAccount (Account *root, gnc_commodity * currency,
1457                                   const char *accname, GNCAccountType acctype,
1458                                   gboolean placeholder, gboolean checkname)
1459 {
1460     GList* acc_list;
1461     Account *acc = NULL;
1462 
1463     g_return_val_if_fail (root, NULL);
1464 
1465     acc_list =
1466         gnc_account_lookup_by_type_and_commodity (root,
1467                                                   checkname ? accname : NULL,
1468                                                   acctype, currency);
1469 
1470     if (!acc_list)
1471         return construct_account (root, currency, accname,
1472                                   acctype, placeholder);
1473 
1474     if (g_list_next(acc_list))
1475     {
1476         if (!currency)
1477             acc = find_root_currency_account_in_list (acc_list);
1478 
1479         if (!acc)
1480             acc = find_account_matching_name_in_list (acc_list, accname);
1481     }
1482 
1483     if (!acc)
1484         acc = GNC_ACCOUNT (acc_list->data);
1485 
1486     g_list_free (acc_list);
1487     return acc;
1488 }
1489 
1490 void
xaccTransScrubPostedDate(Transaction * trans)1491 xaccTransScrubPostedDate (Transaction *trans)
1492 {
1493     time64 orig = xaccTransGetDate(trans);
1494     if(orig == INT64_MAX)
1495     {
1496 	GDate date = xaccTransGetDatePostedGDate(trans);
1497 	time64 time = gdate_to_time64(date);
1498 	if(time != INT64_MAX)
1499 	{
1500 	    // xaccTransSetDatePostedSecs handles committing the change.
1501 	    xaccTransSetDatePostedSecs(trans, time);
1502 	}
1503     }
1504 }
1505 
1506 /* ==================== END OF FILE ==================== */
1507