GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups 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 [email protected] *
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 <[email protected]>
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 
46 #include "Account.h"
47 #include "AccountP.h"
48 #include "Scrub.h"
49 #include "ScrubP.h"
50 #include "Transaction.h"
51 #include "TransactionP.h"
52 #include "gnc-commodity.h"
53 
54 #undef G_LOG_DOMAIN
55 #define G_LOG_DOMAIN "gnc.engine.scrub"
56 
57 static QofLogModule log_module = G_LOG_DOMAIN;
58 
59 /* ================================================================ */
60 
61 void
63 {
64  if (!acc) return;
65 
68  (AccountCb)xaccAccountScrubOrphans, NULL);
69 }
70 
71 static void
72 TransScrubOrphansFast (Transaction *trans, Account *root)
73 {
74  GList *node;
75  gchar *accname;
76 
77  if (!trans) return;
78  g_return_if_fail (root);
79 
80  for (node = trans->splits; node; node = node->next)
81  {
82  Split *split = node->data;
83  Account *orph;
84 
85  if (split->acc) continue;
86 
87  DEBUG ("Found an orphan \n");
88 
89  accname = g_strconcat (_("Orphan"), "-",
90  gnc_commodity_get_mnemonic (trans->common_currency),
91  NULL);
92  orph = xaccScrubUtilityGetOrMakeAccount (root, trans->common_currency,
93  accname, ACCT_TYPE_BANK, FALSE);
94  g_free (accname);
95  if (!orph) continue;
96 
97  xaccSplitSetAccount(split, orph);
98  }
99 }
100 
101 void
103 {
104  GList *node;
105  const char *str;
106 
107  if (!acc) return;
108 
109  str = xaccAccountGetName (acc);
110  str = str ? str : "(null)";
111  PINFO ("Looking for orphans in account %s \n", str);
112 
113  for (node = xaccAccountGetSplitList(acc); node; node = node->next)
114  {
115  Split *split = node->data;
116 
117  TransScrubOrphansFast (xaccSplitGetParent (split),
118  gnc_account_get_root (acc));
119  }
120 }
121 
122 
123 void
125 {
126  SplitList *node;
127  QofBook *book = NULL;
128  Account *root = NULL;
129 
130  if (!trans) return;
131 
132  for (node = trans->splits; node; node = node->next)
133  {
134  Split *split = node->data;
135 
136  if (split->acc)
137  {
138  TransScrubOrphansFast (trans, gnc_account_get_root(split->acc));
139  return;
140  }
141  }
142 
143  /* If we got to here, then *none* of the splits belonged to an
144  * account. Not a happy situation. We should dig an account
145  * out of the book the transaction belongs to.
146  * XXX we should probably *always* to this, instead of the above loop!
147  */
148  PINFO ("Free Floating Transaction!");
149  book = xaccTransGetBook (trans);
150  root = gnc_book_get_root_account (book);
151  TransScrubOrphansFast (trans, root);
152 }
153 
154 /* ================================================================ */
155 
156 void
157 xaccAccountTreeScrubSplits (Account *account)
158 {
159  if (!account) return;
160 
161  xaccAccountScrubSplits (account);
163  (AccountCb)xaccAccountScrubSplits, NULL);
164 }
165 
166 void
167 xaccAccountScrubSplits (Account *account)
168 {
169  GList *node;
170 
171  for (node = xaccAccountGetSplitList (account); node; node = node->next)
172  xaccSplitScrub (node->data);
173 }
174 
175 void
177 {
178  Account *account;
179  Transaction *trans;
180  gnc_numeric value, amount;
181  gnc_commodity *currency, *acc_commodity;
182  int scu;
183 
184  if (!split) return;
185  ENTER ("(split=%p)", split);
186 
187  trans = xaccSplitGetParent (split);
188  if (!trans)
189  {
190  LEAVE("no trans");
191  return;
192  }
193 
194  account = xaccSplitGetAccount (split);
195 
196  /* If there's no account, this split is an orphan.
197  * We need to fix that first, before proceeding.
198  */
199  if (!account)
200  {
201  xaccTransScrubOrphans (trans);
202  account = xaccSplitGetAccount (split);
203  }
204 
205  /* Grrr... the register gnc_split_register_load() line 203 of
206  * src/register/ledger-core/split-register-load.c will create
207  * free-floating bogus transactions. Ignore these for now ...
208  */
209  if (!account)
210  {
211  PINFO ("Free Floating Transaction!");
212  LEAVE ("no account");
213  return;
214  }
215 
216  /* Split amounts and values should be valid numbers */
217  value = xaccSplitGetValue (split);
218  if (gnc_numeric_check (value))
219  {
220  value = gnc_numeric_zero();
221  xaccSplitSetValue (split, value);
222  }
223 
224  amount = xaccSplitGetAmount (split);
225  if (gnc_numeric_check (amount))
226  {
227  amount = gnc_numeric_zero();
228  xaccSplitSetAmount (split, amount);
229  }
230 
231  currency = xaccTransGetCurrency (trans);
232 
233  /* If the account doesn't have a commodity,
234  * we should attempt to fix that first.
235  */
236  acc_commodity = xaccAccountGetCommodity(account);
237  if (!acc_commodity)
238  {
239  xaccAccountScrubCommodity (account);
240  }
241  if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency))
242  {
243  LEAVE ("(split=%p) inequiv currency", split);
244  return;
245  }
246 
247  scu = MIN (xaccAccountGetCommoditySCU (account),
248  gnc_commodity_get_fraction (currency));
249 
250  if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP))
251  {
252  LEAVE("(split=%p) different values", split);
253  return;
254  }
255 
256  /*
257  * This will be hit every time you answer yes to the dialog "The
258  * current transaction has changed. Would you like to record it.
259  */
260  PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
261  " old amount %s %s, new amount %s",
262  trans->description, split->memo,
264  gnc_commodity_get_mnemonic (currency),
266 
267  xaccTransBeginEdit (trans);
268  xaccSplitSetAmount (split, value);
269  xaccTransCommitEdit (trans);
270  LEAVE ("(split=%p)", split);
271 }
272 
273 /* ================================================================ */
274 
275 void
276 xaccAccountTreeScrubImbalance (Account *acc)
277 {
278  xaccAccountScrubImbalance (acc);
280  (AccountCb)xaccAccountScrubImbalance, NULL);
281 }
282 
283 void
284 xaccAccountScrubImbalance (Account *acc)
285 {
286  GList *node;
287  const char *str;
288 
289  if (!acc) return;
290 
291  str = xaccAccountGetName(acc);
292  str = str ? str : "(null)";
293  PINFO ("Looking for imbalance in account %s \n", str);
294 
295  for (node = xaccAccountGetSplitList(acc); node; node = node->next)
296  {
297  Split *split = node->data;
298  Transaction *trans = xaccSplitGetParent(split);
299 
300  xaccTransScrubCurrency(trans);
301 
302  xaccTransScrubImbalance (trans, gnc_account_get_root (acc), NULL);
303  }
304 }
305 
306 static Split *
307 get_balance_split (Transaction *trans, Account *root, Account *account,
308  gnc_commodity *commodity)
309 {
310  Split *balance_split;
311  gchar *accname;
312 
313  if (!account ||
314  !gnc_commodity_equiv (commodity, xaccAccountGetCommodity(account)))
315  {
316  if (!root)
317  {
318  root = gnc_book_get_root_account (xaccTransGetBook (trans));
319  if (NULL == root)
320  {
321  /* This can't occur, things should be in books */
322  PERR ("Bad data corruption, no root account in book");
323  return NULL;
324  }
325  }
326  accname = g_strconcat (_("Imbalance"), "-",
327  gnc_commodity_get_mnemonic (commodity), NULL);
328  account = xaccScrubUtilityGetOrMakeAccount (root, commodity,
329  accname, ACCT_TYPE_BANK, FALSE);
330  g_free (accname);
331  if (!account)
332  {
333  PERR ("Can't get balancing account");
334  return NULL;
335  }
336  }
337 
338  balance_split = xaccTransFindSplitByAccount(trans, account);
339 
340  /* Put split into account before setting split value */
341  if (!balance_split)
342  {
343  balance_split = xaccMallocSplit (qof_instance_get_book(trans));
344 
345  xaccTransBeginEdit (trans);
346  xaccSplitSetParent(balance_split, trans);
347  xaccSplitSetAccount(balance_split, account);
348  xaccTransCommitEdit (trans);
349  }
350 
351  return balance_split;
352 }
353 
354 /* Get the trading split for a given commodity, creating it (and the
355  necessary accounts) if it doesn't exist. */
356 static Split *
357 get_trading_split (Transaction *trans, Account *root,
358  gnc_commodity *commodity)
359 {
360  Split *balance_split;
361  Account *trading_account;
362  Account *ns_account;
363  Account *account;
364  gnc_commodity *default_currency = NULL;
365 
366  if (!root)
367  {
368  root = gnc_book_get_root_account (xaccTransGetBook (trans));
369  if (NULL == root)
370  {
371  /* This can't occur, things should be in books */
372  PERR ("Bad data corruption, no root account in book");
373  return NULL;
374  }
375  }
376 
377  /* Get the default currency. This is harder than it seems. It's not
378  possible to call gnc_default_currency() since it's a UI function. One
379  might think that the currency of the root account would do, but the root
380  account has no currency. Instead look for the Income placeholder account
381  and use its currency. */
382  default_currency = xaccAccountGetCommodity(gnc_account_lookup_by_name(root,
383  _("Income")));
384  if (! default_currency)
385  {
386  default_currency = commodity;
387  }
388 
389  trading_account = xaccScrubUtilityGetOrMakeAccount (root,
390  default_currency,
391  _("Trading"),
392  ACCT_TYPE_TRADING, TRUE);
393  if (!trading_account)
394  {
395  PERR ("Can't get trading account");
396  return NULL;
397  }
398 
399  ns_account = xaccScrubUtilityGetOrMakeAccount (trading_account,
400  default_currency,
401  gnc_commodity_get_namespace(commodity),
402  ACCT_TYPE_TRADING, TRUE);
403  if (!ns_account)
404  {
405  PERR ("Can't get namespace account");
406  return NULL;
407  }
408 
409  account = xaccScrubUtilityGetOrMakeAccount (ns_account, commodity,
410  gnc_commodity_get_mnemonic(commodity),
411  ACCT_TYPE_TRADING, FALSE);
412  if (!account)
413  {
414  PERR ("Can't get commodity account");
415  return NULL;
416  }
417 
418 
419  balance_split = xaccTransFindSplitByAccount(trans, account);
420 
421  /* Put split into account before setting split value */
422  if (!balance_split)
423  {
424  balance_split = xaccMallocSplit (qof_instance_get_book(trans));
425 
426  xaccTransBeginEdit (trans);
427  xaccSplitSetParent(balance_split, trans);
428  xaccSplitSetAccount(balance_split, account);
429  xaccTransCommitEdit (trans);
430  }
431 
432  return balance_split;
433 }
434 
435 /* Find the trading split for a commodity, but don't create any splits
436  or accounts if they don't already exist. */
437 static Split *
438 find_trading_split (Transaction *trans, Account *root,
439  gnc_commodity *commodity)
440 {
441  Account *trading_account;
442  Account *ns_account;
443  Account *account;
444 
445  if (!root)
446  {
447  root = gnc_book_get_root_account (xaccTransGetBook (trans));
448  if (NULL == root)
449  {
450  /* This can't occur, things should be in books */
451  PERR ("Bad data corruption, no root account in book");
452  return NULL;
453  }
454  }
455 
456  trading_account = gnc_account_lookup_by_name (root, _("Trading"));
457  if (!trading_account)
458  {
459  return NULL;
460  }
461 
462  ns_account = gnc_account_lookup_by_name (trading_account,
463  gnc_commodity_get_namespace(commodity));
464  if (!ns_account)
465  {
466  return NULL;
467  }
468 
469  account = gnc_account_lookup_by_name (ns_account,
470  gnc_commodity_get_mnemonic(commodity));
471  if (!account)
472  {
473  return NULL;
474  }
475 
476  return xaccTransFindSplitByAccount(trans, account);
477 }
478 
479 static void
480 add_balance_split (Transaction *trans, gnc_numeric imbalance,
481  Account *root, Account *account)
482 {
483  const gnc_commodity *commodity;
484  gnc_numeric old_value, new_value;
485  Split *balance_split;
486  gnc_commodity *currency = xaccTransGetCurrency (trans);
487 
488  balance_split = get_balance_split(trans, root, account, currency);
489  if (!balance_split)
490  {
491  /* Error already logged */
492  LEAVE("");
493  return;
494  }
495  account = xaccSplitGetAccount(balance_split);
496 
497  xaccTransBeginEdit (trans);
498 
499  old_value = xaccSplitGetValue (balance_split);
500 
501  /* Note: We have to round for the commodity's fraction, NOT any
502  * already existing denominator (bug #104343), because either one
503  * of the denominators might already be reduced. */
504  new_value = gnc_numeric_sub (old_value, imbalance,
505  gnc_commodity_get_fraction(currency),
507 
508  xaccSplitSetValue (balance_split, new_value);
509 
510  commodity = xaccAccountGetCommodity (account);
511  if (gnc_commodity_equiv (currency, commodity))
512  {
513  xaccSplitSetAmount (balance_split, new_value);
514  }
515 
516  xaccSplitScrub (balance_split);
517  xaccTransCommitEdit (trans);
518 }
519 
520 void
522  Account *account)
523 {
524  const gnc_commodity *currency;
525 
526  if (!trans) return;
527 
528  ENTER ("()");
529 
530  /* Must look for orphan splits even if there is no imbalance. */
531  xaccTransScrubSplits (trans);
532 
533  /* Return immediately if things are balanced. */
534  if (xaccTransIsBalanced (trans))
535  {
536  LEAVE ("transaction is balanced");
537  return;
538  }
539 
540  currency = xaccTransGetCurrency (trans);
541 
542  if (! xaccTransUseTradingAccounts (trans))
543  {
544  gnc_numeric imbalance;
545 
546  /* Make the value sum to zero */
547  imbalance = xaccTransGetImbalanceValue (trans);
548  if (! gnc_numeric_zero_p (imbalance))
549  {
550  PINFO ("Value unbalanced transaction");
551 
552  add_balance_split (trans, imbalance, root, account);
553  }
554  }
555  else
556  {
557  MonetaryList *imbal_list;
558  MonetaryList *imbalance_commod;
559  GList *splits;
560  gnc_numeric imbalance;
561  Split *balance_split = NULL;
562 
563  /* If there are existing trading splits, adjust the price or exchange
564  rate in each of them to agree with the non-trading splits for the
565  same commodity. If there are multiple non-trading splits for the
566  same commodity in the transaction this will use the exchange rate in
567  the last such split. This shouldn't happen, and if it does then there's
568  not much we can do about it anyway.
569 
570  While we're at it, compute the value imbalance ignoring existing
571  trading splits. */
572 
573  imbalance = gnc_numeric_zero();
574 
575  for (splits = trans->splits; splits; splits = splits->next)
576  {
577  Split *split = splits->data;
578  gnc_numeric value, amount;
579  gnc_commodity *commodity;
580 
581  if (! xaccTransStillHasSplit (trans, split)) continue;
582 
583  commodity = xaccAccountGetCommodity (xaccSplitGetAccount(split));
584  if (!commodity)
585  {
586  PERR("Split has no commodity");
587  continue;
588  }
589 
590  balance_split = find_trading_split (trans, root, commodity);
591 
592  if (balance_split != split)
593  /* this is not a trading split */
594  imbalance = gnc_numeric_add(imbalance, xaccSplitGetValue (split),
596 
597  /* Ignore splits where value or amount is zero */
598  value = xaccSplitGetValue (split);
599  amount = xaccSplitGetAmount (split);
600  if (gnc_numeric_zero_p(amount) || gnc_numeric_zero_p(value))
601  continue;
602 
603  if (balance_split && balance_split != split)
604  {
605  gnc_numeric convrate = gnc_numeric_div (amount, value,
607  gnc_numeric old_value, new_value;
608  old_value = xaccSplitGetValue(balance_split);
609  new_value = gnc_numeric_div (xaccSplitGetAmount(balance_split),
610  convrate,
611  gnc_commodity_get_fraction(currency),
613  if (! gnc_numeric_equal (old_value, new_value))
614  {
615  xaccTransBeginEdit (trans);
616  xaccSplitSetValue (balance_split, new_value);
617  xaccSplitScrub (balance_split);
618  xaccTransCommitEdit (trans);
619  }
620  }
621  }
622 
623  /* Balance the value, ignoring existing trading splits */
624  if (! gnc_numeric_zero_p (imbalance))
625  {
626  PINFO ("Value unbalanced transaction");
627 
628  add_balance_split (trans, imbalance, root, account);
629  }
630 
631  /* If the transaction is balanced, nothing more to do */
632  imbal_list = xaccTransGetImbalance (trans);
633  if (!imbal_list)
634  {
635  LEAVE("transaction is balanced");
636  return;
637  }
638 
639  PINFO ("Currency unbalanced transaction");
640 
641  for (imbalance_commod = imbal_list; imbalance_commod;
642  imbalance_commod = imbalance_commod->next)
643  {
644  gnc_monetary *imbal_mon = imbalance_commod->data;
645  gnc_commodity *commodity;
646  gnc_numeric old_amount, new_amount;
647  gnc_numeric old_value, new_value, val_imbalance;
648  GList *splits;
649 
650  commodity = gnc_monetary_commodity (*imbal_mon);
651 
652  balance_split = get_trading_split(trans, root, commodity);
653  if (!balance_split)
654  {
655  /* Error already logged */
656  gnc_monetary_list_free(imbal_list);
657  LEAVE("");
658  return;
659  }
660 
661  account = xaccSplitGetAccount(balance_split);
662 
663  if (! gnc_commodity_equal (currency, commodity))
664  {
665  /* Find the value imbalance in this commodity */
666  val_imbalance = gnc_numeric_zero();
667  for (splits = trans->splits; splits; splits = splits->next)
668  {
669  Split *split = splits->data;
670  if (xaccTransStillHasSplit (trans, split) &&
671  gnc_commodity_equal (commodity,
673  val_imbalance = gnc_numeric_add (val_imbalance, xaccSplitGetValue (split),
675  }
676  }
677 
678  xaccTransBeginEdit (trans);
679 
680  old_amount = xaccSplitGetAmount (balance_split);
681  new_amount = gnc_numeric_sub (old_amount, gnc_monetary_value(*imbal_mon),
682  gnc_commodity_get_fraction(commodity),
684 
685  xaccSplitSetAmount (balance_split, new_amount);
686 
687  if (gnc_commodity_equal (currency, commodity))
688  {
689  /* Imbalance commodity is the transaction currency, value in the
690  split must be the same as the amount */
691  xaccSplitSetValue (balance_split, new_amount);
692  }
693  else
694  {
695  old_value = xaccSplitGetValue (balance_split);
696  new_value = gnc_numeric_sub (old_value, val_imbalance,
697  gnc_commodity_get_fraction(currency),
699 
700  xaccSplitSetValue (balance_split, new_value);
701  }
702 
703  xaccSplitScrub (balance_split);
704  xaccTransCommitEdit (trans);
705  }
706 
707  gnc_monetary_list_free(imbal_list);
708 
710  {
711  /* This is probably because there are splits with zero amount
712  and non-zero value. These are usually realized gain/loss
713  splits. Add a reversing split for each of them to balance
714  the value. */
715 
716  /* Copy the split list so we don't see the splits we're adding */
717  GList *splits_dup = g_list_copy(trans->splits);
718  for (splits = splits_dup; splits; splits = splits->next)
719  {
720  Split *split = splits->data;
721  if (! xaccTransStillHasSplit(trans, split)) continue;
722  if (!gnc_numeric_zero_p(xaccSplitGetValue(split)) &&
724  {
725  gnc_commodity *commodity;
726  gnc_numeric old_value, new_value;
727 
728  commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split));
729  if (!commodity)
730  {
731  PERR("Split has no commodity");
732  continue;
733  }
734  balance_split = get_trading_split(trans, root, commodity);
735  if (!balance_split)
736  {
737  /* Error already logged */
738  gnc_monetary_list_free(imbal_list);
739  LEAVE("");
740  return;
741  }
742  account = xaccSplitGetAccount(balance_split);
743 
744  xaccTransBeginEdit (trans);
745 
746  old_value = xaccSplitGetValue (balance_split);
747  new_value = gnc_numeric_sub (old_value, xaccSplitGetValue(split),
748  gnc_commodity_get_fraction(currency),
750  xaccSplitSetValue (balance_split, new_value);
751 
752  /* Don't change the balance split's amount since the amount
753  is zero in the split we're working on */
754 
755  xaccSplitScrub (balance_split);
756  xaccTransCommitEdit (trans);
757  }
758  }
759 
760  g_list_free(splits_dup);
761 
763  PERR("Balancing currencies unbalanced value");
764  }
765  }
766  LEAVE ("()");
767 }
768 
769 /* ================================================================ */
770 /* The xaccTransFindCommonCurrency () method returns
771  * a gnc_commodity indicating a currency denomination that all
772  * of the splits in this transaction have in common, using the
773  * old/obsolete currency/security fields of the split accounts.
774  */
775 
776 static gnc_commodity *
777 FindCommonExclSCurrency (SplitList *splits,
778  gnc_commodity * ra, gnc_commodity * rb,
779  Split *excl_split)
780 {
781  GList *node;
782 
783  if (!splits) return NULL;
784 
785  for (node = splits; node; node = node->next)
786  {
787  Split *s = node->data;
788  gnc_commodity * sa, * sb;
789 
790  if (s == excl_split) continue;
791 
792  g_return_val_if_fail (s->acc, NULL);
793 
794  sa = DxaccAccountGetCurrency (s->acc);
795  sb = xaccAccountGetCommodity (s->acc);
796 
797  if (ra && rb)
798  {
799  int aa = !gnc_commodity_equiv(ra, sa);
800  int ab = !gnc_commodity_equiv(ra, sb);
801  int ba = !gnc_commodity_equiv(rb, sa);
802  int bb = !gnc_commodity_equiv(rb, sb);
803 
804  if ( (!aa) && bb) rb = NULL;
805  else if ( (!ab) && ba) rb = NULL;
806  else if ( (!ba) && ab) ra = NULL;
807  else if ( (!bb) && aa) ra = NULL;
808  else if ( aa && bb && ab && ba )
809  {
810  ra = NULL;
811  rb = NULL;
812  }
813 
814  if (!ra)
815  {
816  ra = rb;
817  rb = NULL;
818  }
819  }
820  else if (ra && !rb)
821  {
822  int aa = !gnc_commodity_equiv(ra, sa);
823  int ab = !gnc_commodity_equiv(ra, sb);
824  if ( aa && ab ) ra = NULL;
825  }
826  else if (!ra && rb)
827  {
828  int aa = !gnc_commodity_equiv(rb, sa);
829  int ab = !gnc_commodity_equiv(rb, sb);
830  ra = ( aa && ab ) ? NULL : rb;
831  }
832 
833  if ((!ra) && (!rb)) return NULL;
834  }
835 
836  return (ra);
837 }
838 
839 /* This is the wrapper for those calls (i.e. the older ones) which
840  * don't exclude one split from the splitlist when looking for a
841  * common currency.
842  */
843 static gnc_commodity *
844 FindCommonCurrency (GList *splits, gnc_commodity * ra, gnc_commodity * rb)
845 {
846  return FindCommonExclSCurrency(splits, ra, rb, NULL);
847 }
848 
849 static gnc_commodity *
850 xaccTransFindOldCommonCurrency (Transaction *trans, QofBook *book)
851 {
852  gnc_commodity *ra, *rb, *retval;
853  Split *split;
854 
855  if (!trans) return NULL;
856 
857  if (trans->splits == NULL) return NULL;
858 
859  g_return_val_if_fail (book, NULL);
860 
861  split = trans->splits->data;
862 
863  if (!split || NULL == split->acc) return NULL;
864 
865  ra = DxaccAccountGetCurrency (split->acc);
866  rb = xaccAccountGetCommodity (split->acc);
867 
868  retval = FindCommonCurrency (trans->splits, ra, rb);
869 
870  if (retval && !gnc_commodity_is_currency(retval))
871  retval = NULL;
872 
873  return retval;
874 }
875 
876 /* Test the currency of the splits and find the most common and return
877  * it, or NULL if there is no currency more common than the
878  * others -- or none at all.
879  */
880 typedef struct
881 {
882  gnc_commodity *commodity;
883  unsigned int count;
885 
886 static gint
887 commodity_equal (gconstpointer a, gconstpointer b)
888 {
889  CommodityCount *cc = (CommodityCount*)a;
890  gnc_commodity *com = (gnc_commodity*)b;
891  if ( cc == NULL || cc->commodity == NULL ||
892  !GNC_IS_COMMODITY( cc->commodity ) ) return -1;
893  if ( com == NULL || !GNC_IS_COMMODITY( com ) ) return 1;
894  if ( gnc_commodity_equal(cc->commodity, com) )
895  return 0;
896  return 1;
897 }
898 
899 static gint
900 commodity_compare( gconstpointer a, gconstpointer b)
901 {
902  CommodityCount *ca = (CommodityCount*)a, *cb = (CommodityCount*)b;
903  if (ca == NULL || ca->commodity == NULL ||
904  !GNC_IS_COMMODITY( ca->commodity ) )
905  {
906  if (cb == NULL || cb->commodity == NULL ||
907  !GNC_IS_COMMODITY( cb->commodity ) )
908  return 0;
909  return -1;
910  }
911  if (cb == NULL || cb->commodity == NULL ||
912  !GNC_IS_COMMODITY( cb->commodity ) )
913  return 1;
914  if (ca->count == cb->count)
915  return 0;
916  return ca->count > cb->count ? 1 : -1;
917 }
918 
919 /* Find the commodities in the account of each of the splits of a
920  * transaction, and rank them by how many splits in which they
921  * occur. Commodities which are currencies count more than those which
922  * aren't, because for simple buy and sell transactions it makes
923  * slightly more sense for the transaction commodity to be the
924  * currency -- to the extent that it makes sense for a transaction to
925  * have a currency at all. jralls, 2010-11-02 */
926 
927 static gnc_commodity *
928 xaccTransFindCommonCurrency (Transaction *trans, QofBook *book)
929 {
930  gnc_commodity *com_scratch;
931  GList *node = NULL;
932  GSList *comlist = NULL, *found = NULL;
933 
934  if (!trans) return NULL;
935 
936  if (trans->splits == NULL) return NULL;
937 
938  g_return_val_if_fail (book, NULL);
939 
940  /* Find the most commonly used currency among the splits. If a given split
941  is in a non-currency commodity, then look for an ancestor account in a
942  currency, but prefer currencies used directly in splits. Ignore trading
943  account splits in this whole process, they don't add any value to this algorithm. */
944  for (node = trans->splits; node; node = node->next)
945  {
946  Split *s = node->data;
947  unsigned int curr_weight;
948 
949  if (s == NULL || s->acc == NULL) continue;
950  if (xaccAccountGetType(s->acc) == ACCT_TYPE_TRADING) continue;
951  com_scratch = xaccAccountGetCommodity(s->acc);
952  if (com_scratch && gnc_commodity_is_currency(com_scratch))
953  {
954  curr_weight = 3;
955  }
956  else
957  {
958  com_scratch = gnc_account_get_currency_or_parent(s->acc);
959  if (com_scratch == NULL) continue;
960  curr_weight = 1;
961  }
962  if ( comlist )
963  {
964  found = g_slist_find_custom(comlist, com_scratch, commodity_equal);
965  }
966  if (comlist == NULL || found == NULL)
967  {
968  CommodityCount *count = g_slice_new0(CommodityCount);
969  count->commodity = com_scratch;
970  count->count = curr_weight;
971  comlist = g_slist_append(comlist, count);
972  }
973  else
974  {
975  CommodityCount *count = (CommodityCount*)(found->data);
976  count->count += curr_weight;
977  }
978  }
979  found = g_slist_sort( comlist, commodity_compare);
980 
981  if ( found && found->data && (((CommodityCount*)(found->data))->commodity != NULL))
982  {
983  return ((CommodityCount*)(found->data))->commodity;
984  }
985  /* We didn't find a currency in the current account structure, so try
986  * an old one. */
987  return xaccTransFindOldCommonCurrency( trans, book );
988 }
989 
990 /* ================================================================ */
991 
992 void
994 {
995  SplitList *node;
996  gnc_commodity *currency;
997 
998  if (!trans) return;
999 
1000  /* If there are any orphaned splits in a transaction, then the
1001  * this routine will fail. Therefore, we want to make sure that
1002  * there are no orphans (splits without parent account).
1003  */
1004  xaccTransScrubOrphans (trans);
1005 
1006  currency = xaccTransGetCurrency (trans);
1007  if (currency && gnc_commodity_is_currency(currency)) return;
1008 
1009  currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans));
1010  if (currency)
1011  {
1012  xaccTransBeginEdit (trans);
1013  xaccTransSetCurrency (trans, currency);
1014  xaccTransCommitEdit (trans);
1015  }
1016  else
1017  {
1018  if (NULL == trans->splits)
1019  {
1020  PWARN ("Transaction \"%s\" has no splits in it!", trans->description);
1021  }
1022  else
1023  {
1024  SplitList *node;
1025  char guid_str[GUID_ENCODING_LENGTH + 1];
1026  guid_to_string_buff(xaccTransGetGUID(trans), guid_str);
1027  PWARN ("no common transaction currency found for trans=\"%s\" (%s);",
1028  trans->description, guid_str);
1029 
1030  for (node = trans->splits; node; node = node->next)
1031  {
1032  Split *split = node->data;
1033  if (NULL == split->acc)
1034  {
1035  PWARN (" split=\"%s\" is not in any account!", split->memo);
1036  }
1037  else
1038  {
1039  gnc_commodity *currency = xaccAccountGetCommodity(split->acc);
1040  PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"",
1041  split->memo, xaccAccountGetName(split->acc),
1042  gnc_commodity_get_mnemonic(currency));
1043 
1044  xaccTransBeginEdit (trans);
1045  xaccTransSetCurrency (trans, currency);
1046  xaccTransCommitEdit (trans);
1047  return;
1048  }
1049  }
1050  }
1051  return;
1052  }
1053 
1054  for (node = trans->splits; node; node = node->next)
1055  {
1056  Split *sp = node->data;
1057 
1059  xaccSplitGetValue (sp)))
1060  {
1061  gnc_commodity *acc_currency;
1062 
1063  acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : NULL;
1064  if (acc_currency == currency)
1065  {
1066  /* This Split needs fixing: The transaction-currency equals
1067  * the account-currency/commodity, but the amount/values are
1068  * inequal i.e. they still correspond to the security
1069  * (amount) and the currency (value). In the new model, the
1070  * value is the amount in the account-commodity -- so it
1071  * needs to be set to equal the amount (since the
1072  * account-currency doesn't exist anymore).
1073  *
1074  * Note: Nevertheless we lose some information here. Namely,
1075  * the information that the 'amount' in 'account-old-security'
1076  * was worth 'value' in 'account-old-currency'. Maybe it would
1077  * be better to store that information in the price database?
1078  * But then, for old currency transactions there is still the
1079  * 'other' transaction, which is going to keep that
1080  * information. So I don't bother with that here. -- cstim,
1081  * 2002/11/20. */
1082 
1083  PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\""
1084  " old amount %s %s, new amount %s",
1085  trans->description, sp->memo,
1087  gnc_commodity_get_mnemonic (currency),
1089  xaccTransBeginEdit (trans);
1091  xaccTransCommitEdit (trans);
1092  }
1093  /*else
1094  {
1095  PINFO ("Ok: Split '%s' Amount %s %s, value %s %s",
1096  xaccSplitGetMemo (sp),
1097  gnc_num_dbg_to_string (amount),
1098  gnc_commodity_get_mnemonic (currency),
1099  gnc_num_dbg_to_string (value),
1100  gnc_commodity_get_mnemonic (acc_currency));
1101  }*/
1102  }
1103  }
1104 
1105 }
1106 
1107 /* ================================================================ */
1108 
1109 void
1111 {
1112  gnc_commodity *commodity;
1113 
1114  if (!account) return;
1115  if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return;
1116 
1117  commodity = xaccAccountGetCommodity (account);
1118  if (commodity) return;
1119 
1120  /* Use the 'obsolete' routines to try to figure out what the
1121  * account commodity should have been. */
1122  commodity = xaccAccountGetCommodity (account);
1123  if (commodity)
1124  {
1125  xaccAccountSetCommodity (account, commodity);
1126  return;
1127  }
1128 
1129  commodity = DxaccAccountGetCurrency (account);
1130  if (commodity)
1131  {
1132  xaccAccountSetCommodity (account, commodity);
1133  return;
1134  }
1135 
1136  PERR ("Account \"%s\" does not have a commodity!",
1137  xaccAccountGetName(account));
1138 }
1139 
1140 /* ================================================================ */
1141 
1142 /* EFFECTIVE FRIEND FUNCTION declared in qofinstance-p.h */
1143 extern void qof_instance_set_dirty (QofInstance*);
1144 
1145 static void
1146 xaccAccountDeleteOldData (Account *account)
1147 {
1148  if (!account) return;
1149  xaccAccountBeginEdit (account);
1150 
1151  kvp_frame_set_slot_nc (account->inst.kvp_data, "old-currency", NULL);
1152  kvp_frame_set_slot_nc (account->inst.kvp_data, "old-security", NULL);
1153  kvp_frame_set_slot_nc (account->inst.kvp_data, "old-currency-scu", NULL);
1154  kvp_frame_set_slot_nc (account->inst.kvp_data, "old-security-scu", NULL);
1155  qof_instance_set_dirty (QOF_INSTANCE (account));
1156  xaccAccountCommitEdit (account);
1157 }
1158 
1159 static int
1160 scrub_trans_currency_helper (Transaction *t, gpointer data)
1161 {
1163  return 0;
1164 }
1165 
1166 static void
1167 scrub_account_commodity_helper (Account *account, gpointer data)
1168 {
1169  xaccAccountScrubCommodity (account);
1170  xaccAccountDeleteOldData (account);
1171 }
1172 
1173 void
1175 {
1176  if (!acc) return;
1177 
1178  xaccAccountTreeForEachTransaction (acc, scrub_trans_currency_helper, NULL);
1179 
1180  scrub_account_commodity_helper (acc, NULL);
1181  gnc_account_foreach_descendant (acc, scrub_account_commodity_helper, NULL);
1182 }
1183 
1184 /* ================================================================ */
1185 
1186 static gboolean
1187 check_quote_source (gnc_commodity *com, gpointer data)
1188 {
1189  gboolean *commodity_has_quote_src = (gboolean *)data;
1190  if (com && !gnc_commodity_is_iso(com))
1191  *commodity_has_quote_src |= gnc_commodity_get_quote_flag(com);
1192  return TRUE;
1193 }
1194 
1195 static void
1196 move_quote_source (Account *account, gpointer data)
1197 {
1198  gnc_commodity *com;
1199  gnc_quote_source *quote_source;
1200  gboolean new_style = GPOINTER_TO_INT(data);
1201  const char *source, *tz;
1202 
1203  com = xaccAccountGetCommodity(account);
1204  if (!com)
1205  return;
1206 
1207  if (!new_style)
1208  {
1209  source = dxaccAccountGetPriceSrc(account);
1210  if (!source || !*source)
1211  return;
1212  tz = dxaccAccountGetQuoteTZ(account);
1213 
1214  PINFO("to %8s from %s", gnc_commodity_get_mnemonic(com),
1215  xaccAccountGetName(account));
1216  gnc_commodity_set_quote_flag(com, TRUE);
1217  quote_source = gnc_quote_source_lookup_by_internal(source);
1218  if (!quote_source)
1219  quote_source = gnc_quote_source_add_new(source, FALSE);
1220  gnc_commodity_set_quote_source(com, quote_source);
1221  gnc_commodity_set_quote_tz(com, tz);
1222  }
1223 
1224  dxaccAccountSetPriceSrc(account, NULL);
1225  dxaccAccountSetQuoteTZ(account, NULL);
1226  return;
1227 }
1228 
1229 
1230 void
1232 {
1233  gboolean new_style = FALSE;
1234  ENTER(" ");
1235 
1236  if (!root || !table)
1237  {
1238  LEAVE("Oops");
1239  return;
1240  }
1241 
1242  gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style);
1243 
1244  move_quote_source(root, GINT_TO_POINTER(new_style));
1245  gnc_account_foreach_descendant (root, move_quote_source,
1246  GINT_TO_POINTER(new_style));
1247  LEAVE("Migration done");
1248 }
1249 
1250 /* ================================================================ */
1251 
1252 void
1253 xaccAccountScrubKvp (Account *account)
1254 {
1255  const gchar *str;
1256  gchar *str2;
1257  KvpFrame *frame;
1258 
1259  if (!account) return;
1260 
1261  str = kvp_frame_get_string(account->inst.kvp_data, "notes");
1262  if (str)
1263  {
1264  str2 = g_strstrip(g_strdup(str));
1265  if (strlen(str2) == 0)
1266  kvp_frame_set_slot_nc (account->inst.kvp_data, "notes", NULL);
1267  g_free(str2);
1268  }
1269 
1270  str = kvp_frame_get_string(account->inst.kvp_data, "placeholder");
1271  if (str && strcmp(str, "false") == 0)
1272  kvp_frame_set_slot_nc (account->inst.kvp_data, "placeholder", NULL);
1273 
1274  frame = kvp_frame_get_frame(account->inst.kvp_data, "hbci");
1275  if (frame && kvp_frame_is_empty(frame))
1276  {
1277  kvp_frame_set_frame_nc(account->inst.kvp_data, "hbci", NULL);
1278  }
1279 }
1280 
1281 /* ================================================================ */
1282 
1283 Account *
1284 xaccScrubUtilityGetOrMakeAccount (Account *root, gnc_commodity * currency,
1285  const char *accname, GNCAccountType acctype,
1286  gboolean placeholder)
1287 {
1288  Account * acc;
1289 
1290  g_return_val_if_fail (root, NULL);
1291 
1292  /* build the account name */
1293  if (!currency)
1294  {
1295  PERR ("No currency specified!");
1296  return NULL;
1297  }
1298 
1299  /* See if we've got one of these going already ... */
1300  acc = gnc_account_lookup_by_name(root, accname);
1301 
1302  if (acc == NULL)
1303  {
1304  /* Guess not. We'll have to build one. */
1305  acc = xaccMallocAccount(gnc_account_get_book (root));
1306  xaccAccountBeginEdit (acc);
1307  xaccAccountSetName (acc, accname);
1308  xaccAccountSetCommodity (acc, currency);
1309  xaccAccountSetType (acc, acctype);
1310  xaccAccountSetPlaceholder (acc, placeholder);
1311 
1312  /* Hang the account off the root. */
1313  gnc_account_append_child (root, acc);
1314  xaccAccountCommitEdit (acc);
1315  }
1316 
1317  return acc;
1318 }
1319 
1320 /* ==================== END OF FILE ==================== */
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Definition: Account.c:2208
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
gboolean gnc_commodity_table_foreach_commodity(const gnc_commodity_table *table, gboolean(*f)(gnc_commodity *cm, gpointer user_data), gpointer user_data)
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
void xaccTransScrubCurrency(Transaction *trans)
Definition: Scrub.c:993
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
gchar * gnc_num_dbg_to_string(gnc_numeric n)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Definition: Transaction.c:1015
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3717
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
void xaccAccountTreeScrubCommodities(Account *acc)
Definition: Scrub.c:1174
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition: Account.c:3128
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
QofBook * qof_instance_get_book(gconstpointer)
gnc_quote_source * gnc_quote_source_add_new(const char *source_name, gboolean supported)
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Definition: qoflog.h:249
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
void xaccAccountScrubCommodity(Account *account)
Definition: Scrub.c:1110
gboolean gnc_commodity_get_quote_flag(const gnc_commodity *cm)
int xaccAccountGetCommoditySCU(const Account *acc)
Definition: Account.c:2458
gboolean kvp_frame_is_empty(const KvpFrame *frame)
void gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
#define DEBUG(format, args...)
Definition: qoflog.h:255
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean gnc_numeric_zero_p(gnc_numeric a)
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
void gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
gboolean xaccTransIsBalanced(const Transaction *trans)
Definition: Transaction.c:1124
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
Definition: Account.c:2803
#define PWARN(format, args...)
Definition: qoflog.h:243
convert single-entry accounts to clean double-entry
void gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
GList SplitList
Definition: gnc-engine.h:203
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
Account handling public routines.
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Definition: Account.c:3923
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
Definition: Transaction.c:1036
void dxaccAccountSetPriceSrc(Account *acc, const char *src)
Definition: Account.c:4569
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
void gnc_monetary_list_free(MonetaryList *list)
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Definition: Scrub.c:521
const char * dxaccAccountGetQuoteTZ(const Account *acc)
Definition: Account.c:4627
void xaccSplitScrub(Split *split)
Definition: Scrub.c:176
void xaccTransScrubSplits(Transaction *trans)
Definition: Transaction.c:2616
void kvp_frame_set_slot_nc(KvpFrame *frame, const gchar *key, KvpValue *value)
void xaccAccountScrubOrphans(Account *acc)
Definition: Scrub.c:102
void xaccTransScrubOrphans(Transaction *trans)
Definition: Scrub.c:124
#define xaccTransGetBook(X)
Definition: Transaction.h:753
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
void dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
Definition: Account.c:4607
GNCAccountType
Definition: Account.h:96
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Definition: Account.c:3155
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
#define xaccTransGetGUID(X)
Definition: Transaction.h:755
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gnc_quote_source * gnc_quote_source_lookup_by_internal(const char *name)
const char * dxaccAccountGetPriceSrc(const Account *acc)
Definition: Account.c:4590
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
Definition: Transaction.c:1052
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
#define LEAVE(format, args...)
Definition: qoflog.h:271
Account * xaccMallocAccount(QofBook *book)
Definition: Account.c:1083
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
void xaccAccountTreeScrubOrphans(Account *acc)
Definition: Scrub.c:62
KvpFrame * kvp_frame_get_frame(const KvpFrame *frame, const gchar *path)
Account * gnc_account_get_root(Account *acc)
Definition: Account.c:2630
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void xaccAccountTreeScrubQuoteSources(Account *root, gnc_commodity_table *table)
Definition: Scrub.c:1231
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void xaccAccountSetName(Account *acc, const char *str)
Definition: Account.c:2229
Commodity handling public routines.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
const gchar * QofLogModule
Definition: qofid.h:89
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987