GnuCash  4.8a-132-gcdaeb421d+
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 
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
72 gnc_set_abort_scrub (gboolean abort)
73 {
74  abort_now = abort;
75 }
76 
77 gboolean
78 gnc_get_abort_scrub (void)
79 {
80  return abort_now;
81 }
82 
83 gboolean
85 {
86  return scrub_depth > 0;
87 }
88 
89 /* ================================================================ */
90 
91 void
93 {
94  if (!acc) return;
95 
96  if (abort_now)
97  (percentagefunc)(NULL, -1.0);
98 
99  scrub_depth ++;
100  xaccAccountScrubOrphans (acc, percentagefunc);
102  (AccountCb)xaccAccountScrubOrphans, percentagefunc);
103  scrub_depth--;
104 }
105 
106 static void
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
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
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
212 xaccAccountTreeScrubSplits (Account *account)
213 {
214  if (!account) return;
215 
216  xaccAccountScrubSplits (account);
218  (AccountCb)xaccAccountScrubSplits, NULL);
219 }
220 
221 void
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
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,
323  gnc_commodity_get_mnemonic (currency),
325 
326  xaccTransBeginEdit (trans);
327  xaccSplitSetAmount (split, value);
328  xaccTransCommitEdit (trans);
329  LEAVE ("(split=%p)", split);
330 }
331 
332 /* ================================================================ */
333 
334 void
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);
345  (AccountCb)xaccAccountScrubImbalance, percentagefunc);
346  scrub_depth--;
347 }
348 
349 void
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  */
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 *
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*
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 *
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"),
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),
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),
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
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),
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
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
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 =
614  if (xaccTransStillHasSplit (trans, split) &&
615  gnc_commodity_equal (commodity, split_commodity))
616  val_imbalance = gnc_numeric_add (val_imbalance,
617  xaccSplitGetValue (split),
620  }
621  return val_imbalance;
622 }
623 
624 /* GFunc wrapper for xaccSplitDestroy */
625 static void
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
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
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),
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),
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 
738 static void
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)) &&
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),
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 
793 void
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);
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);
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 *
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 *
921 FindCommonCurrency (GList *splits, gnc_commodity * ra, gnc_commodity * rb)
922 {
923  return FindCommonExclSCurrency(splits, ra, rb, NULL);
924 }
925 
926 static gnc_commodity *
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;
962 
963 static gint
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
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 *
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
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 
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,
1164  gnc_commodity_get_mnemonic (currency),
1166  xaccTransBeginEdit (trans);
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
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
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
1236 scrub_trans_currency_helper (Transaction *t, gpointer data)
1237 {
1239  return 0;
1240 }
1241 
1242 static void
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
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
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
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
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
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
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*
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*
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*
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 *
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 =
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
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 ==================== */
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Set the account&#39;s type.
Definition: Account.cpp:2407
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:1333
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:1070
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:2782
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:3025
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
Definition: Transaction.c:1033
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:3964
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:1252
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition: Account.cpp:3383
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:3202
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:84
#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:3236
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1470
void xaccAccountScrubCommodity(Account *account)
The xaccAccountScrubCommodity method fixed accounts without a commodity by using the old account curr...
Definition: Scrub.c:1187
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:2682
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.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:189
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:174
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.
Definition: Transaction.c:1142
void xaccTransScrubPostedDate(Transaction *trans)
Changes Transaction date_posted timestamps from 00:00 local to 11:00 UTC.
Definition: Scrub.c:1491
#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
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
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.
Definition: Transaction.c:1425
Account used to record multiple commodity transactions.
Definition: Account.h:158
#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:3327
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:72
convert single-entry accounts to clean double-entry
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:211
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:578
Account handling public routines.
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4226
void xaccAccountSetColor(Account *acc, const char *str)
Set the account&#39;s Color.
Definition: Account.cpp:2547
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:143
void xaccAccountTreeScrubOrphans(Account *acc, QofPercentageFunc percentagefunc)
The xaccAccountTreeScrubOrphans() method performs this scrub for the indicated account and its childr...
Definition: Scrub.c:92
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:4986
#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:794
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:5025
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:235
void xaccTransScrubSplits(Transaction *trans)
The xacc*ScrubSplits() calls xaccSplitScrub() on each split in the respective structure: transaction...
Definition: Transaction.c:2924
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:110
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:140
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1256
void xaccTransScrubOrphans(Transaction *trans)
The xaccTransScrubOrphans() method scrubs only the splits in the given transaction.
Definition: Scrub.c:178
#define xaccTransGetBook(X)
Definition: Transaction.h:783
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:5014
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Definition: Account.h:105
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:3412
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
#define xaccTransGetGUID(X)
Definition: Transaction.h:785
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)).
Definition: Transaction.c:2017
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:4998
GList * gnc_account_get_children(const Account *account)
This routine returns a GList of all children accounts of the specified account.
Definition: Account.cpp:2911
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:1430
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:3405
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1366
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 ...
Definition: Transaction.c:1070
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition: Account.cpp:1209
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
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:2887
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:1364
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3258
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:1310
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.
Definition: Transaction.c:2490
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
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:1471
void xaccAccountSetName(Account *acc, const char *str)
Set the account&#39;s name.
Definition: Account.cpp:2428
The hidden root account of an account tree.
Definition: Account.h:156
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:2613
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:3145