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