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