GnuCash  5.6-150-g038405b370+
Account.cpp
1 /********************************************************************\
2  * Account.c -- Account data structure implementation *
3  * Copyright (C) 1997 Robin D. Clark *
4  * Copyright (C) 1997-2003 Linas Vepstas <linas@linas.org> *
5  * Copyright (C) 2007 David Hampton <hampton@employees.org> *
6  * *
7  * This program is free software; you can redistribute it and/or *
8  * modify it under the terms of the GNU General Public License as *
9  * published by the Free Software Foundation; either version 2 of *
10  * the License, or (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License*
18  * along with this program; if not, contact: *
19  * *
20  * Free Software Foundation Voice: +1-617-542-5942 *
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22  * Boston, MA 02110-1301, USA gnu@gnu.org *
23  * *
24 \********************************************************************/
25 
26 #include <config.h>
27 
28 #include "gnc-prefs.h"
29 
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <string.h>
35 
36 #include "AccountP.hpp"
37 #include "Account.hpp"
38 #include "Split.h"
39 #include "Transaction.h"
40 #include "TransactionP.hpp"
41 #include "gnc-event.h"
42 #include "gnc-glib-utils.h"
43 #include "gnc-lot.h"
44 #include "gnc-pricedb.h"
45 #include "qofinstance-p.h"
46 #include "gnc-features.h"
47 #include "guid.hpp"
48 
49 #include <numeric>
50 #include <map>
51 #include <unordered_set>
52 
53 static QofLogModule log_module = GNC_MOD_ACCOUNT;
54 
55 /* The Canonical Account Separator. Pre-Initialized. */
56 static gchar account_separator[8] = ".";
57 static gunichar account_uc_separator = ':';
58 
59 static bool imap_convert_bayes_to_flat_run = false;
60 
61 /* Predefined KVP paths */
62 static const std::string KEY_ASSOC_INCOME_ACCOUNT("ofx/associated-income-account");
63 static const std::string KEY_RECONCILE_INFO("reconcile-info");
64 static const std::string KEY_INCLUDE_CHILDREN("include-children");
65 static const std::string KEY_POSTPONE("postpone");
66 static const std::string KEY_LOT_MGMT("lot-mgmt");
67 static const std::string KEY_ONLINE_ID("online_id");
68 static const std::string KEY_IMP_APPEND_TEXT("import-append-text");
69 static const std::string AB_KEY("hbci");
70 static const std::string AB_ACCOUNT_ID("account-id");
71 static const std::string AB_ACCOUNT_UID("account-uid");
72 static const std::string AB_BANK_CODE("bank-code");
73 static const std::string AB_TRANS_RETRIEVAL("trans-retrieval");
74 
75 static const std::string KEY_BALANCE_LIMIT("balance-limit");
76 static const std::string KEY_BALANCE_HIGHER_LIMIT_VALUE("higher-value");
77 static const std::string KEY_BALANCE_LOWER_LIMIT_VALUE("lower-value");
78 static const std::string KEY_BALANCE_INCLUDE_SUB_ACCTS("inlude-sub-accts");
79 
80 using FinalProbabilityVec=std::vector<std::pair<std::string, int32_t>>;
81 using ProbabilityVec=std::vector<std::pair<std::string, struct AccountProbability>>;
82 using FlatKvpEntry=std::pair<std::string, KvpValue*>;
83 
84 enum
85 {
86  LAST_SIGNAL
87 };
88 
89 enum
90 {
91  PROP_0,
92  PROP_NAME, /* Table */
93  PROP_FULL_NAME, /* Constructed */
94  PROP_CODE, /* Table */
95  PROP_DESCRIPTION, /* Table */
96  PROP_COLOR, /* KVP */
97  PROP_NOTES, /* KVP */
98  PROP_TYPE, /* Table */
99 
100 // PROP_PARENT, /* Table, Not a property */
101  PROP_COMMODITY, /* Table */
102  PROP_COMMODITY_SCU, /* Table */
103  PROP_NON_STD_SCU, /* Table */
104  PROP_END_BALANCE, /* Constructed */
105  PROP_END_NOCLOSING_BALANCE, /* Constructed */
106  PROP_END_CLEARED_BALANCE, /* Constructed */
107  PROP_END_RECONCILED_BALANCE, /* Constructed */
108 
109  PROP_TAX_RELATED, /* KVP */
110  PROP_TAX_CODE, /* KVP */
111  PROP_TAX_SOURCE, /* KVP */
112  PROP_TAX_COPY_NUMBER, /* KVP */
113 
114  PROP_HIDDEN, /* Table slot exists, but in KVP in memory & xml */
115  PROP_PLACEHOLDER, /* Table slot exists, but in KVP in memory & xml */
116  PROP_AUTO_INTEREST,
117  PROP_FILTER, /* KVP */
118  PROP_SORT_ORDER, /* KVP */
119  PROP_SORT_REVERSED,
120 
121  PROP_LOT_NEXT_ID, /* KVP */
122  PROP_ONLINE_ACCOUNT, /* KVP */
123  PROP_IMP_APPEND_TEXT, /* KVP */
124  PROP_IS_OPENING_BALANCE, /* KVP */
125  PROP_OFX_INCOME_ACCOUNT, /* KVP */
126  PROP_AB_ACCOUNT_ID, /* KVP */
127  PROP_AB_ACCOUNT_UID, /* KVP */
128  PROP_AB_BANK_CODE, /* KVP */
129  PROP_AB_TRANS_RETRIEVAL, /* KVP */
130 
131  PROP_RUNTIME_0,
132  PROP_POLICY, /* Cached Value */
133  PROP_MARK, /* Runtime Value */
134  PROP_SORT_DIRTY, /* Runtime Value */
135  PROP_BALANCE_DIRTY, /* Runtime Value */
136  PROP_START_BALANCE, /* Runtime Value */
137  PROP_START_NOCLOSING_BALANCE, /* Runtime Value */
138  PROP_START_CLEARED_BALANCE, /* Runtime Value */
139  PROP_START_RECONCILED_BALANCE, /* Runtime Value */
140 };
141 
142 #define GET_PRIVATE(o) \
143  ((AccountPrivate*)gnc_account_get_instance_private((Account*)o))
144 
145 /* This map contains a set of strings representing the different column types. */
146 static const std::map<GNCAccountType, const char*> gnc_acct_debit_strs = {
147  { ACCT_TYPE_NONE, N_("Funds In") },
148  { ACCT_TYPE_BANK, N_("Deposit") },
149  { ACCT_TYPE_CASH, N_("Receive") },
150  { ACCT_TYPE_CREDIT, N_("Payment") },
151  { ACCT_TYPE_ASSET, N_("Increase") },
152  { ACCT_TYPE_LIABILITY, N_("Decrease") },
153  { ACCT_TYPE_STOCK, N_("Buy") },
154  { ACCT_TYPE_MUTUAL, N_("Buy") },
155  { ACCT_TYPE_CURRENCY, N_("Buy") },
156  { ACCT_TYPE_INCOME, N_("Charge") },
157  { ACCT_TYPE_EXPENSE, N_("Expense") },
158  { ACCT_TYPE_PAYABLE, N_("Payment") },
159  { ACCT_TYPE_RECEIVABLE, N_("Invoice") },
160  { ACCT_TYPE_TRADING, N_("Decrease") },
161  { ACCT_TYPE_EQUITY, N_("Decrease") },
162 };
163 static const char* dflt_acct_debit_str = N_("Debit");
164 
165 /* This map contains a set of strings representing the different column types. */
166 static const std::map<GNCAccountType, const char*> gnc_acct_credit_strs = {
167  { ACCT_TYPE_NONE, N_("Funds Out") },
168  { ACCT_TYPE_BANK, N_("Withdrawal") },
169  { ACCT_TYPE_CASH, N_("Spend") },
170  { ACCT_TYPE_CREDIT, N_("Charge") },
171  { ACCT_TYPE_ASSET, N_("Decrease") },
172  { ACCT_TYPE_LIABILITY, N_("Increase") },
173  { ACCT_TYPE_STOCK, N_("Sell") },
174  { ACCT_TYPE_MUTUAL, N_("Sell") },
175  { ACCT_TYPE_CURRENCY, N_("Sell") },
176  { ACCT_TYPE_INCOME, N_("Income") },
177  { ACCT_TYPE_EXPENSE, N_("Rebate") },
178  { ACCT_TYPE_PAYABLE, N_("Bill") },
179  { ACCT_TYPE_RECEIVABLE, N_("Payment") },
180  { ACCT_TYPE_TRADING, N_("Increase") },
181  { ACCT_TYPE_EQUITY, N_("Increase") },
182 };
183 static const char* dflt_acct_credit_str = N_("Credit");
184 
185 /********************************************************************\
186  * Because I can't use C++ for this project, doesn't mean that I *
187  * can't pretend to! These functions perform actions on the *
188  * account data structure, in order to encapsulate the knowledge *
189  * of the internals of the Account in one file. *
190 \********************************************************************/
191 
192 static void xaccAccountBringUpToDate (Account *acc);
193 
194 
195 /********************************************************************\
196  * gnc_get_account_separator *
197  * returns the current account separator character *
198  * *
199  * Args: none *
200  * Returns: account separator character *
201  \*******************************************************************/
202 const gchar *
204 {
205  return account_separator;
206 }
207 
208 gunichar
209 gnc_get_account_separator (void)
210 {
211  return account_uc_separator;
212 }
213 
214 void
215 gnc_set_account_separator (const gchar *separator)
216 {
217  gunichar uc;
218  gint count;
219 
220  uc = g_utf8_get_char_validated(separator, -1);
221  if ((uc == (gunichar) - 2) || (uc == (gunichar) - 1) || g_unichar_isalnum(uc))
222  {
223  account_uc_separator = ':';
224  strcpy(account_separator, ":");
225  return;
226  }
227 
228  account_uc_separator = uc;
229  count = g_unichar_to_utf8(uc, account_separator);
230  account_separator[count] = '\0';
231 }
232 
233 gchar *gnc_account_name_violations_errmsg (const gchar *separator, GList* invalid_account_names)
234 {
235  gchar *message = nullptr;
236 
237  if ( !invalid_account_names )
238  return nullptr;
239 
240  auto account_list {gnc_g_list_stringjoin (invalid_account_names, "\n")};
241 
242  /* Translators: The first %s will be the account separator character,
243  the second %s is a list of account names.
244  The resulting string will be displayed to the user if there are
245  account names containing the separator character. */
246  message = g_strdup_printf(
247  _("The separator character \"%s\" is used in one or more account names.\n\n"
248  "This will result in unexpected behaviour. "
249  "Either change the account names or choose another separator character.\n\n"
250  "Below you will find the list of invalid account names:\n"
251  "%s"), separator, account_list );
252  g_free ( account_list );
253  return message;
254 }
255 
257 {
258  GList *list;
259  const gchar *separator;
260 };
261 
262 static void
263 check_acct_name (Account *acct, gpointer user_data)
264 {
265  auto cb {static_cast<ViolationData*>(user_data)};
266  auto name {xaccAccountGetName (acct)};
267  if (g_strstr_len (name, -1, cb->separator))
268  cb->list = g_list_prepend (cb->list, g_strdup (name));
269 }
270 
271 GList *gnc_account_list_name_violations (QofBook *book, const gchar *separator)
272 {
273  g_return_val_if_fail (separator != nullptr, nullptr);
274  if (!book) return nullptr;
275  ViolationData cb = { nullptr, separator };
276  gnc_account_foreach_descendant (gnc_book_get_root_account (book),
277  (AccountCb)check_acct_name, &cb);
278  return cb.list;
279 }
280 
281 /********************************************************************\
282 \********************************************************************/
283 
284 static inline void mark_account (Account *acc);
285 void
286 mark_account (Account *acc)
287 {
288  qof_instance_set_dirty(&acc->inst);
289 }
290 
291 /********************************************************************\
292 \********************************************************************/
293 
294 /* GObject Initialization */
295 G_DEFINE_TYPE_WITH_PRIVATE(Account, gnc_account, QOF_TYPE_INSTANCE)
296 
297 static void
298 gnc_account_init(Account* acc)
299 {
300  AccountPrivate *priv;
301 
302  priv = GET_PRIVATE(acc);
303  priv->parent = nullptr;
304 
305  priv->accountName = qof_string_cache_insert("");
306  priv->accountCode = qof_string_cache_insert("");
307  priv->description = qof_string_cache_insert("");
308 
309  priv->type = ACCT_TYPE_NONE;
310 
311  priv->mark = 0;
312 
313  priv->policy = xaccGetFIFOPolicy();
314  priv->lots = nullptr;
315 
316  priv->commodity = nullptr;
317  priv->commodity_scu = 0;
318  priv->non_standard_scu = FALSE;
319 
320  priv->balance = gnc_numeric_zero();
321  priv->noclosing_balance = gnc_numeric_zero();
322  priv->cleared_balance = gnc_numeric_zero();
323  priv->reconciled_balance = gnc_numeric_zero();
324  priv->starting_balance = gnc_numeric_zero();
325  priv->starting_noclosing_balance = gnc_numeric_zero();
326  priv->starting_cleared_balance = gnc_numeric_zero();
327  priv->starting_reconciled_balance = gnc_numeric_zero();
328  priv->balance_dirty = FALSE;
329 
330  new (&priv->children) AccountVec ();
331  new (&priv->splits) SplitsVec ();
332  priv->splits_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
333  priv->sort_dirty = FALSE;
334 }
335 
336 static void
337 gnc_account_dispose (GObject *acctp)
338 {
339  G_OBJECT_CLASS(gnc_account_parent_class)->dispose(acctp);
340 }
341 
342 static void
343 gnc_account_finalize(GObject* acctp)
344 {
345  G_OBJECT_CLASS(gnc_account_parent_class)->finalize(acctp);
346 }
347 
348 /* Note that g_value_set_object() refs the object, as does
349  * g_object_get(). But g_object_get() only unrefs once when it disgorges
350  * the object, leaving an unbalanced ref, which leaks. So instead of
351  * using g_value_set_object(), use g_value_take_object() which doesn't
352  * ref the object when used in get_property().
353  */
354 static void
355 gnc_account_get_property (GObject *object,
356  guint prop_id,
357  GValue *value,
358  GParamSpec *pspec)
359 {
360  Account *account;
361  AccountPrivate *priv;
362 
363  g_return_if_fail(GNC_IS_ACCOUNT(object));
364 
365  account = GNC_ACCOUNT(object);
366  priv = GET_PRIVATE(account);
367  switch (prop_id)
368  {
369  case PROP_NAME:
370  g_value_set_string(value, priv->accountName);
371  break;
372  case PROP_FULL_NAME:
373  g_value_take_string(value, gnc_account_get_full_name(account));
374  break;
375  case PROP_CODE:
376  g_value_set_string(value, priv->accountCode);
377  break;
378  case PROP_DESCRIPTION:
379  g_value_set_string(value, priv->description);
380  break;
381  case PROP_COLOR:
382  g_value_set_string(value, xaccAccountGetColor(account));
383  break;
384  case PROP_NOTES:
385  g_value_set_string(value, xaccAccountGetNotes(account));
386  break;
387  case PROP_TYPE:
388  // NEED TO BE CONVERTED TO A G_TYPE_ENUM
389  g_value_set_int(value, priv->type);
390  break;
391  case PROP_COMMODITY:
392  g_value_take_object(value, priv->commodity);
393  break;
394  case PROP_COMMODITY_SCU:
395  g_value_set_int(value, priv->commodity_scu);
396  break;
397  case PROP_NON_STD_SCU:
398  g_value_set_boolean(value, priv->non_standard_scu);
399  break;
400  case PROP_SORT_DIRTY:
401  g_value_set_boolean(value, priv->sort_dirty);
402  break;
403  case PROP_BALANCE_DIRTY:
404  g_value_set_boolean(value, priv->balance_dirty);
405  break;
406  case PROP_START_BALANCE:
407  g_value_set_boxed(value, &priv->starting_balance);
408  break;
409  case PROP_START_NOCLOSING_BALANCE:
410  g_value_set_boxed(value, &priv->starting_noclosing_balance);
411  break;
412  case PROP_START_CLEARED_BALANCE:
413  g_value_set_boxed(value, &priv->starting_cleared_balance);
414  break;
415  case PROP_START_RECONCILED_BALANCE:
416  g_value_set_boxed(value, &priv->starting_reconciled_balance);
417  break;
418  case PROP_END_BALANCE:
419  g_value_set_boxed(value, &priv->balance);
420  break;
421  case PROP_END_NOCLOSING_BALANCE:
422  g_value_set_boxed(value, &priv->noclosing_balance);
423  break;
424  case PROP_END_CLEARED_BALANCE:
425  g_value_set_boxed(value, &priv->cleared_balance);
426  break;
427  case PROP_END_RECONCILED_BALANCE:
428  g_value_set_boxed(value, &priv->reconciled_balance);
429  break;
430  case PROP_POLICY:
431  /* MAKE THIS A BOXED VALUE */
432  g_value_set_pointer(value, priv->policy);
433  break;
434  case PROP_MARK:
435  g_value_set_int(value, priv->mark);
436  break;
437  case PROP_TAX_RELATED:
438  g_value_set_boolean(value, xaccAccountGetTaxRelated(account));
439  break;
440  case PROP_TAX_CODE:
441  g_value_set_string(value, xaccAccountGetTaxUSCode(account));
442  break;
443  case PROP_TAX_SOURCE:
444  g_value_set_string(value,
446  break;
447  case PROP_TAX_COPY_NUMBER:
448  g_value_set_int64(value,
450  break;
451  case PROP_HIDDEN:
452  g_value_set_boolean(value, xaccAccountGetHidden(account));
453  break;
454  case PROP_AUTO_INTEREST:
455  g_value_set_boolean (value, xaccAccountGetAutoInterest (account));
456  break;
457  case PROP_IS_OPENING_BALANCE:
458  g_value_set_boolean(value, xaccAccountGetIsOpeningBalance(account));
459  break;
460  case PROP_PLACEHOLDER:
461  g_value_set_boolean(value, xaccAccountGetPlaceholder(account));
462  break;
463  case PROP_FILTER:
464  g_value_set_string(value, xaccAccountGetFilter(account));
465  break;
466  case PROP_SORT_ORDER:
467  g_value_set_string(value, xaccAccountGetSortOrder(account));
468  break;
469  case PROP_SORT_REVERSED:
470  g_value_set_boolean(value, xaccAccountGetSortReversed(account));
471  break;
472  case PROP_LOT_NEXT_ID:
473  /* Pre-set the value in case the frame is empty */
474  g_value_set_int64 (value, 0);
475  qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {KEY_LOT_MGMT, "next-id"});
476  break;
477  case PROP_ONLINE_ACCOUNT:
478  qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {KEY_ONLINE_ID});
479  break;
480  case PROP_IMP_APPEND_TEXT:
481  g_value_set_boolean(value, xaccAccountGetAppendText(account));
482  break;
483  case PROP_OFX_INCOME_ACCOUNT:
484  qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {KEY_ASSOC_INCOME_ACCOUNT});
485  break;
486  case PROP_AB_ACCOUNT_ID:
487  qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_ID});
488  break;
489  case PROP_AB_ACCOUNT_UID:
490  qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_UID});
491  break;
492  case PROP_AB_BANK_CODE:
493  qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_BANK_CODE});
494  break;
495  case PROP_AB_TRANS_RETRIEVAL:
496  qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_TRANS_RETRIEVAL});
497  break;
498  default:
499  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
500  break;
501  }
502 }
503 
504 static void
505 gnc_account_set_property (GObject *object,
506  guint prop_id,
507  const GValue *value,
508  GParamSpec *pspec)
509 {
510  Account *account;
511  gnc_numeric *number;
512  g_return_if_fail(GNC_IS_ACCOUNT(object));
513  account = GNC_ACCOUNT(object);
514  if (prop_id < PROP_RUNTIME_0)
515  g_assert (qof_instance_get_editlevel(account));
516 
517  switch (prop_id)
518  {
519  case PROP_NAME:
520  xaccAccountSetName(account, g_value_get_string(value));
521  break;
522  case PROP_CODE:
523  xaccAccountSetCode(account, g_value_get_string(value));
524  break;
525  case PROP_DESCRIPTION:
526  xaccAccountSetDescription(account, g_value_get_string(value));
527  break;
528  case PROP_COLOR:
529  xaccAccountSetColor(account, g_value_get_string(value));
530  break;
531  case PROP_NOTES:
532  xaccAccountSetNotes(account, g_value_get_string(value));
533  break;
534  case PROP_TYPE:
535  // NEED TO BE CONVERTED TO A G_TYPE_ENUM
536  xaccAccountSetType(account, static_cast<GNCAccountType>(g_value_get_int(value)));
537  break;
538  case PROP_COMMODITY:
539  xaccAccountSetCommodity(account, static_cast<gnc_commodity*>(g_value_get_object(value)));
540  break;
541  case PROP_COMMODITY_SCU:
542  xaccAccountSetCommoditySCU(account, g_value_get_int(value));
543  break;
544  case PROP_NON_STD_SCU:
545  xaccAccountSetNonStdSCU(account, g_value_get_boolean(value));
546  break;
547  case PROP_SORT_DIRTY:
549  break;
550  case PROP_BALANCE_DIRTY:
552  break;
553  case PROP_START_BALANCE:
554  number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
555  gnc_account_set_start_balance(account, *number);
556  break;
557  case PROP_START_CLEARED_BALANCE:
558  number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
559  gnc_account_set_start_cleared_balance(account, *number);
560  break;
561  case PROP_START_RECONCILED_BALANCE:
562  number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
564  break;
565  case PROP_POLICY:
566  gnc_account_set_policy(account, static_cast<GNCPolicy*>(g_value_get_pointer(value)));
567  break;
568  case PROP_MARK:
569  xaccAccountSetMark(account, g_value_get_int(value));
570  break;
571  case PROP_TAX_RELATED:
572  xaccAccountSetTaxRelated(account, g_value_get_boolean(value));
573  break;
574  case PROP_TAX_CODE:
575  xaccAccountSetTaxUSCode(account, g_value_get_string(value));
576  break;
577  case PROP_TAX_SOURCE:
579  g_value_get_string(value));
580  break;
581  case PROP_TAX_COPY_NUMBER:
583  g_value_get_int64(value));
584  break;
585  case PROP_HIDDEN:
586  xaccAccountSetHidden(account, g_value_get_boolean(value));
587  break;
588  case PROP_AUTO_INTEREST:
589  xaccAccountSetAutoInterest (account, g_value_get_boolean (value));
590  break;
591  case PROP_IS_OPENING_BALANCE:
592  xaccAccountSetIsOpeningBalance (account, g_value_get_boolean (value));
593  break;
594  case PROP_PLACEHOLDER:
595  xaccAccountSetPlaceholder(account, g_value_get_boolean(value));
596  break;
597  case PROP_FILTER:
598  xaccAccountSetFilter(account, g_value_get_string(value));
599  break;
600  case PROP_SORT_ORDER:
601  xaccAccountSetSortOrder(account, g_value_get_string(value));
602  break;
603  case PROP_SORT_REVERSED:
604  xaccAccountSetSortReversed(account, g_value_get_boolean(value));
605  break;
606  case PROP_LOT_NEXT_ID:
607  qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {KEY_LOT_MGMT, "next-id"});
608  break;
609  case PROP_ONLINE_ACCOUNT:
610  qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {KEY_ONLINE_ID});
611  break;
612  case PROP_IMP_APPEND_TEXT:
613  xaccAccountSetAppendText(account, g_value_get_boolean(value));
614  break;
615  case PROP_OFX_INCOME_ACCOUNT:
616  qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {KEY_ASSOC_INCOME_ACCOUNT});
617  break;
618  case PROP_AB_ACCOUNT_ID:
619  qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_ID});
620  break;
621  case PROP_AB_ACCOUNT_UID:
622  qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_UID});
623  break;
624  case PROP_AB_BANK_CODE:
625  qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_BANK_CODE});
626  break;
627  case PROP_AB_TRANS_RETRIEVAL:
628  qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_TRANS_RETRIEVAL});
629  break;
630  default:
631  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
632  break;
633  }
634 }
635 
636 static void
637 gnc_account_class_init (AccountClass *klass)
638 {
639  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
640 
641  gobject_class->dispose = gnc_account_dispose;
642  gobject_class->finalize = gnc_account_finalize;
643  gobject_class->set_property = gnc_account_set_property;
644  gobject_class->get_property = gnc_account_get_property;
645 
646  g_object_class_install_property
647  (gobject_class,
648  PROP_NAME,
649  g_param_spec_string ("name",
650  "Account Name",
651  "The accountName is an arbitrary string "
652  "assigned by the user. It is intended to "
653  "a short, 5 to 30 character long string "
654  "that is displayed by the GUI as the "
655  "account mnemonic. Account names may be "
656  "repeated. but no two accounts that share "
657  "a parent may have the same name.",
658  nullptr,
659  static_cast<GParamFlags>(G_PARAM_READWRITE)));
660 
661  g_object_class_install_property
662  (gobject_class,
663  PROP_FULL_NAME,
664  g_param_spec_string ("fullname",
665  "Full Account Name",
666  "The name of the account concatenated with "
667  "all its parent account names to indicate "
668  "a unique account.",
669  nullptr,
670  static_cast<GParamFlags>(G_PARAM_READABLE)));
671 
672  g_object_class_install_property
673  (gobject_class,
674  PROP_CODE,
675  g_param_spec_string ("code",
676  "Account Code",
677  "The account code is an arbitrary string "
678  "assigned by the user. It is intended to "
679  "be reporting code that is a synonym for "
680  "the accountName.",
681  nullptr,
682  static_cast<GParamFlags>(G_PARAM_READWRITE)));
683 
684  g_object_class_install_property
685  (gobject_class,
686  PROP_DESCRIPTION,
687  g_param_spec_string ("description",
688  "Account Description",
689  "The account description is an arbitrary "
690  "string assigned by the user. It is intended "
691  "to be a longer, 1-5 sentence description of "
692  "what this account is all about.",
693  nullptr,
694  static_cast<GParamFlags>(G_PARAM_READWRITE)));
695 
696  g_object_class_install_property
697  (gobject_class,
698  PROP_COLOR,
699  g_param_spec_string ("color",
700  "Account Color",
701  "The account color is a color string assigned "
702  "by the user. It is intended to highlight the "
703  "account based on the users wishes.",
704  nullptr,
705  static_cast<GParamFlags>(G_PARAM_READWRITE)));
706 
707  g_object_class_install_property
708  (gobject_class,
709  PROP_NOTES,
710  g_param_spec_string ("notes",
711  "Account Notes",
712  "The account notes is an arbitrary provided "
713  "for the user to attach any other text that "
714  "they would like to associate with the account.",
715  nullptr,
716  static_cast<GParamFlags>(G_PARAM_READWRITE)));
717 
718  g_object_class_install_property
719  (gobject_class,
720  PROP_TYPE,
721  g_param_spec_int ("type",
722  "Account Type",
723  "The account type, picked from the enumerated list "
724  "that includes ACCT_TYPE_BANK, ACCT_TYPE_STOCK, "
725  "ACCT_TYPE_CREDIT, ACCT_TYPE_INCOME, etc.",
727  NUM_ACCOUNT_TYPES - 1,
729  static_cast<GParamFlags>(G_PARAM_READWRITE)));
730 
731  g_object_class_install_property
732  (gobject_class,
733  PROP_COMMODITY,
734  g_param_spec_object ("commodity",
735  "Commodity",
736  "The commodity field denotes the kind of "
737  "'stuff' stored in this account, whether "
738  "it is USD, gold, stock, etc.",
739  GNC_TYPE_COMMODITY,
740  static_cast<GParamFlags>(G_PARAM_READWRITE)));
741 
742  g_object_class_install_property
743  (gobject_class,
744  PROP_COMMODITY_SCU,
745  g_param_spec_int ("commodity-scu",
746  "Commodity SCU",
747  "The smallest fraction of the commodity that is "
748  "tracked. This number is used as the denominator "
749  "value in 1/x, so a value of 100 says that the "
750  "commodity can be divided into hundredths. E.G."
751  "1 USD can be divided into 100 cents.",
752  0,
753  G_MAXINT32,
755  static_cast<GParamFlags>(G_PARAM_READWRITE)));
756 
757  g_object_class_install_property
758  (gobject_class,
759  PROP_NON_STD_SCU,
760  g_param_spec_boolean ("non-std-scu",
761  "Non-std SCU",
762  "TRUE if the account SCU doesn't match "
763  "the commodity SCU. This indicates a case "
764  "where the two were accidentally set to "
765  "mismatched values in older versions of "
766  "GnuCash.",
767  FALSE,
768  static_cast<GParamFlags>(G_PARAM_READWRITE)));
769 
770  g_object_class_install_property
771  (gobject_class,
772  PROP_SORT_DIRTY,
773  g_param_spec_boolean("sort-dirty",
774  "Sort Dirty",
775  "TRUE if the splits in the account needs to be "
776  "resorted. This flag is set by the accounts "
777  "code for certain internal modifications, or "
778  "when external code calls the engine to say a "
779  "split has been modified in a way that may "
780  "affect the sort order of the account. Note: "
781  "This value can only be set to TRUE.",
782  FALSE,
783  static_cast<GParamFlags>(G_PARAM_READWRITE)));
784 
785  g_object_class_install_property
786  (gobject_class,
787  PROP_BALANCE_DIRTY,
788  g_param_spec_boolean("balance-dirty",
789  "Balance Dirty",
790  "TRUE if the running balances in the account "
791  "needs to be recalculated. This flag is set "
792  "by the accounts code for certain internal "
793  "modifications, or when external code calls "
794  "the engine to say a split has been modified. "
795  "Note: This value can only be set to TRUE.",
796  FALSE,
797  static_cast<GParamFlags>(G_PARAM_READWRITE)));
798 
799  g_object_class_install_property
800  (gobject_class,
801  PROP_START_BALANCE,
802  g_param_spec_boxed("start-balance",
803  "Starting Balance",
804  "The starting balance for the account. This "
805  "parameter is intended for use with backends that "
806  "do not return the complete list of splits for an "
807  "account, but rather return a partial list. In "
808  "such a case, the backend will typically return "
809  "all of the splits after some certain date, and "
810  "the 'starting balance' will represent the "
811  "summation of the splits up to that date.",
812  GNC_TYPE_NUMERIC,
813  static_cast<GParamFlags>(G_PARAM_READWRITE)));
814 
815  g_object_class_install_property
816  (gobject_class,
817  PROP_START_NOCLOSING_BALANCE,
818  g_param_spec_boxed("start-noclosing-balance",
819  "Starting No-closing Balance",
820  "The starting balance for the account, ignoring closing."
821  "This parameter is intended for use with backends "
822  "that do not return the complete list of splits "
823  "for an account, but rather return a partial "
824  "list. In such a case, the backend will "
825  "typically return all of the splits after "
826  "some certain date, and the 'starting noclosing "
827  "balance' will represent the summation of the "
828  "splits up to that date, ignoring closing splits.",
829  GNC_TYPE_NUMERIC,
830  static_cast<GParamFlags>(G_PARAM_READWRITE)));
831 
832  g_object_class_install_property
833  (gobject_class,
834  PROP_START_CLEARED_BALANCE,
835  g_param_spec_boxed("start-cleared-balance",
836  "Starting Cleared Balance",
837  "The starting cleared balance for the account. "
838  "This parameter is intended for use with backends "
839  "that do not return the complete list of splits "
840  "for an account, but rather return a partial "
841  "list. In such a case, the backend will "
842  "typically return all of the splits after "
843  "some certain date, and the 'starting cleared "
844  "balance' will represent the summation of the "
845  "splits up to that date.",
846  GNC_TYPE_NUMERIC,
847  static_cast<GParamFlags>(G_PARAM_READWRITE)));
848 
849  g_object_class_install_property
850  (gobject_class,
851  PROP_START_RECONCILED_BALANCE,
852  g_param_spec_boxed("start-reconciled-balance",
853  "Starting Reconciled Balance",
854  "The starting reconciled balance for the "
855  "account. This parameter is intended for use "
856  "with backends that do not return the complete "
857  "list of splits for an account, but rather return "
858  "a partial list. In such a case, the backend "
859  "will typically return all of the splits after "
860  "some certain date, and the 'starting reconciled "
861  "balance' will represent the summation of the "
862  "splits up to that date.",
863  GNC_TYPE_NUMERIC,
864  static_cast<GParamFlags>(G_PARAM_READWRITE)));
865 
866  g_object_class_install_property
867  (gobject_class,
868  PROP_END_BALANCE,
869  g_param_spec_boxed("end-balance",
870  "Ending Account Balance",
871  "This is the current ending balance for the "
872  "account. It is computed from the sum of the "
873  "starting balance and all splits in the account.",
874  GNC_TYPE_NUMERIC,
875  G_PARAM_READABLE));
876 
877  g_object_class_install_property
878  (gobject_class,
879  PROP_END_NOCLOSING_BALANCE,
880  g_param_spec_boxed("end-noclosing-balance",
881  "Ending Account Noclosing Balance",
882  "This is the current ending no-closing balance for "
883  "the account. It is computed from the sum of the "
884  "starting balance and all cleared splits in the "
885  "account.",
886  GNC_TYPE_NUMERIC,
887  G_PARAM_READABLE));
888 
889  g_object_class_install_property
890  (gobject_class,
891  PROP_END_CLEARED_BALANCE,
892  g_param_spec_boxed("end-cleared-balance",
893  "Ending Account Cleared Balance",
894  "This is the current ending cleared balance for "
895  "the account. It is computed from the sum of the "
896  "starting balance and all cleared splits in the "
897  "account.",
898  GNC_TYPE_NUMERIC,
899  G_PARAM_READABLE));
900 
901  g_object_class_install_property
902  (gobject_class,
903  PROP_END_RECONCILED_BALANCE,
904  g_param_spec_boxed("end-reconciled-balance",
905  "Ending Account Reconciled Balance",
906  "This is the current ending reconciled balance "
907  "for the account. It is computed from the sum of "
908  "the starting balance and all reconciled splits "
909  "in the account.",
910  GNC_TYPE_NUMERIC,
911  static_cast<GParamFlags>(G_PARAM_READABLE)));
912 
913  g_object_class_install_property
914  (gobject_class,
915  PROP_POLICY,
916  g_param_spec_pointer ("policy",
917  "Policy",
918  "The account lots policy.",
919  static_cast<GParamFlags>(G_PARAM_READWRITE)));
920 
921  g_object_class_install_property
922  (gobject_class,
923  PROP_MARK,
924  g_param_spec_int ("acct-mark",
925  "Account Mark",
926  "Ipsum Lorem",
927  0,
928  G_MAXINT16,
929  0,
930  static_cast<GParamFlags>(G_PARAM_READWRITE)));
931 
932  g_object_class_install_property
933  (gobject_class,
934  PROP_TAX_RELATED,
935  g_param_spec_boolean ("tax-related",
936  "Tax Related",
937  "Whether the account maps to an entry on an "
938  "income tax document.",
939  FALSE,
940  static_cast<GParamFlags>(G_PARAM_READWRITE)));
941 
942  g_object_class_install_property
943  (gobject_class,
944  PROP_IS_OPENING_BALANCE,
945  g_param_spec_boolean ("opening-balance",
946  "Opening Balance",
947  "Whether the account holds opening balances",
948  FALSE,
949  static_cast<GParamFlags>(G_PARAM_READWRITE)));
950 
951  g_object_class_install_property
952  (gobject_class,
953  PROP_TAX_CODE,
954  g_param_spec_string ("tax-code",
955  "Tax Code",
956  "This is the code for mapping an account to a "
957  "specific entry on a taxable document. In the "
958  "United States it is used to transfer totals "
959  "into tax preparation software.",
960  nullptr,
961  static_cast<GParamFlags>(G_PARAM_READWRITE)));
962 
963  g_object_class_install_property
964  (gobject_class,
965  PROP_TAX_SOURCE,
966  g_param_spec_string ("tax-source",
967  "Tax Source",
968  "This specifies where exported name comes from.",
969  nullptr,
970  static_cast<GParamFlags>(G_PARAM_READWRITE)));
971 
972  g_object_class_install_property
973  (gobject_class,
974  PROP_TAX_COPY_NUMBER,
975  g_param_spec_int64 ("tax-copy-number",
976  "Tax Copy Number",
977  "This specifies the copy number of the tax "
978  "form/schedule.",
979  (gint64)1,
980  G_MAXINT64,
981  (gint64)1,
982  static_cast<GParamFlags>(G_PARAM_READWRITE)));
983 
984  g_object_class_install_property
985  (gobject_class,
986  PROP_HIDDEN,
987  g_param_spec_boolean ("hidden",
988  "Hidden",
989  "Whether the account should be hidden in the "
990  "account tree.",
991  FALSE,
992  static_cast<GParamFlags>(G_PARAM_READWRITE)));
993 
994  g_object_class_install_property
995  (gobject_class,
996  PROP_AUTO_INTEREST,
997  g_param_spec_boolean ("auto-interest-transfer",
998  "Auto Interest",
999  "Whether an interest transfer should be automatically "
1000  "added before reconcile.",
1001  FALSE,
1002  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1003 
1004  g_object_class_install_property
1005  (gobject_class,
1006  PROP_PLACEHOLDER,
1007  g_param_spec_boolean ("placeholder",
1008  "Placeholder",
1009  "Whether the account is a placeholder account which does not "
1010  "allow transactions to be created, edited or deleted.",
1011  FALSE,
1012  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1013 
1014  g_object_class_install_property
1015  (gobject_class,
1016  PROP_FILTER,
1017  g_param_spec_string ("filter",
1018  "Account Filter",
1019  "The account filter is a value saved to allow "
1020  "filters to be recalled.",
1021  nullptr,
1022  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1023 
1024  g_object_class_install_property
1025  (gobject_class,
1026  PROP_SORT_ORDER,
1027  g_param_spec_string ("sort-order",
1028  "Account Sort Order",
1029  "The account sort order is a value saved to allow "
1030  "the sort order to be recalled.",
1031  nullptr,
1032  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1033 
1034  g_object_class_install_property
1035  (gobject_class,
1036  PROP_SORT_REVERSED,
1037  g_param_spec_boolean ("sort-reversed",
1038  "Account Sort Reversed",
1039  "Parameter to store whether the sort order is reversed or not.",
1040  FALSE,
1041  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1042 
1043  g_object_class_install_property
1044  (gobject_class,
1045  PROP_LOT_NEXT_ID,
1046  g_param_spec_int64 ("lot-next-id",
1047  "Lot Next ID",
1048  "Tracks the next id to use in gnc_lot_make_default.",
1049  (gint64)1,
1050  G_MAXINT64,
1051  (gint64)1,
1052  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1053 
1054  g_object_class_install_property
1055  (gobject_class,
1056  PROP_ONLINE_ACCOUNT,
1057  g_param_spec_string ("online-id",
1058  "Online Account ID",
1059  "The online account which corresponds to this "
1060  "account for OFX import",
1061  nullptr,
1062  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1063 
1064  g_object_class_install_property
1065  (gobject_class,
1066  PROP_IMP_APPEND_TEXT,
1067  g_param_spec_boolean ("import-append-text",
1068  "Import Append Text",
1069  "Saved state of Append checkbox for setting initial "
1070  "value next time this account is imported.",
1071  FALSE,
1072  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1073 
1074  g_object_class_install_property(
1075  gobject_class,
1076  PROP_OFX_INCOME_ACCOUNT,
1077  g_param_spec_boxed("ofx-income-account",
1078  "Associated income account",
1079  "Used by the OFX importer.",
1080  GNC_TYPE_GUID,
1081  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1082 
1083  g_object_class_install_property
1084  (gobject_class,
1085  PROP_AB_ACCOUNT_ID,
1086  g_param_spec_string ("ab-account-id",
1087  "AQBanking Account ID",
1088  "The AqBanking account which corresponds to this "
1089  "account for AQBanking import",
1090  nullptr,
1091  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1092  g_object_class_install_property
1093  (gobject_class,
1094  PROP_AB_BANK_CODE,
1095  g_param_spec_string ("ab-bank-code",
1096  "AQBanking Bank Code",
1097  "The online account which corresponds to this "
1098  "account for AQBanking import",
1099  nullptr,
1100  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1101 
1102  g_object_class_install_property
1103  (gobject_class,
1104  PROP_AB_ACCOUNT_UID,
1105  g_param_spec_int64 ("ab-account-uid",
1106  "AQBanking Account UID",
1107  "Tracks the next id to use in gnc_lot_make_default.",
1108  (gint64)1,
1109  G_MAXINT64,
1110  (gint64)1,
1111  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1112 
1113  g_object_class_install_property
1114  (gobject_class,
1115  PROP_AB_TRANS_RETRIEVAL,
1116  g_param_spec_boxed("ab-trans-retrieval",
1117  "AQBanking Last Transaction Retrieval",
1118  "The time of the last transaction retrieval for this "
1119  "account.",
1120  GNC_TYPE_TIME64,
1121  static_cast<GParamFlags>(G_PARAM_READWRITE)));
1122 
1123 }
1124 
1125 static void
1126 xaccInitAccount (Account * acc, QofBook *book)
1127 {
1128  ENTER ("book=%p\n", book);
1129  qof_instance_init_data (&acc->inst, GNC_ID_ACCOUNT, book);
1130 
1131  LEAVE ("account=%p\n", acc);
1132 }
1133 
1134 /********************************************************************\
1135 \********************************************************************/
1136 
1137 void
1138 gnc_account_foreach_split (const Account *acc, std::function<void(Split*)> func,
1139  bool reverse)
1140 {
1141  if (!GNC_IS_ACCOUNT (acc))
1142  return;
1143 
1144  auto& splits{GET_PRIVATE(acc)->splits};
1145  if (reverse)
1146  std::for_each(splits.rbegin(), splits.rend(), func);
1147  else
1148  std::for_each(splits.begin(), splits.end(), func);
1149 }
1150 
1151 void
1152 gnc_account_foreach_split_until_date (const Account *acc, time64 end_date,
1153  std::function<void(Split*)> f)
1154 {
1155  if (!GNC_IS_ACCOUNT (acc))
1156  return;
1157 
1158  auto after_date = [](time64 end_date, auto s) -> bool
1159  { return (xaccTransGetDate (xaccSplitGetParent (s)) > end_date); };
1160 
1161  auto& splits{GET_PRIVATE(acc)->splits};
1162  auto after_date_iter = std::upper_bound (splits.begin(), splits.end(), end_date, after_date);
1163  std::for_each (splits.begin(), after_date_iter, f);
1164 }
1165 
1166 
1167 Split*
1168 gnc_account_find_split (const Account *acc, std::function<bool(const Split*)> predicate,
1169  bool reverse)
1170 {
1171  if (!GNC_IS_ACCOUNT (acc))
1172  return nullptr;
1173 
1174  const auto& splits{GET_PRIVATE(acc)->splits};
1175  if (reverse)
1176  {
1177  auto latest = std::find_if(splits.rbegin(), splits.rend(), predicate);
1178  return (latest == splits.rend()) ? nullptr : *latest;
1179  }
1180  else
1181  {
1182  auto earliest = std::find_if(splits.begin(), splits.end(), predicate);
1183  return (earliest == splits.end()) ? nullptr : *earliest;
1184  }
1185 }
1186 
1187 /********************************************************************\
1188 \********************************************************************/
1189 
1190 QofBook *
1191 gnc_account_get_book(const Account *account)
1192 {
1193  if (!account) return nullptr;
1194  return qof_instance_get_book(QOF_INSTANCE(account));
1195 }
1196 
1197 /********************************************************************\
1198 \********************************************************************/
1199 
1200 static Account *
1201 gnc_coll_get_root_account (QofCollection *col)
1202 {
1203  if (!col) return nullptr;
1204  return static_cast<Account*>(qof_collection_get_data (col));
1205 }
1206 
1207 static void
1208 gnc_coll_set_root_account (QofCollection *col, Account *root)
1209 {
1210  AccountPrivate *rpriv;
1211  Account *old_root;
1212  if (!col) return;
1213 
1214  old_root = gnc_coll_get_root_account (col);
1215  if (old_root == root) return;
1216 
1217  /* If the new root is already linked into the tree somewhere, then
1218  * remove it from its current position before adding it at the
1219  * top. */
1220  rpriv = GET_PRIVATE(root);
1221  if (rpriv->parent)
1222  {
1223  xaccAccountBeginEdit(root);
1224  gnc_account_remove_child(rpriv->parent, root);
1225  xaccAccountCommitEdit(root);
1226  }
1227 
1228  qof_collection_set_data (col, root);
1229 
1230  if (old_root)
1231  {
1232  xaccAccountBeginEdit (old_root);
1233  xaccAccountDestroy (old_root);
1234  }
1235 }
1236 
1237 Account *
1238 gnc_book_get_root_account (QofBook *book)
1239 {
1240  QofCollection *col;
1241  Account *root;
1242 
1243  if (!book) return nullptr;
1244  col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
1245  root = gnc_coll_get_root_account (col);
1246  if (root == nullptr && !qof_book_shutting_down(book))
1247  root = gnc_account_create_root(book);
1248  return root;
1249 }
1250 
1251 void
1252 gnc_book_set_root_account (QofBook *book, Account *root)
1253 {
1254  QofCollection *col;
1255  if (!book) return;
1256 
1257  if (root && gnc_account_get_book(root) != book)
1258  {
1259  PERR ("cannot mix and match books freely!");
1260  return;
1261  }
1262 
1263  col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
1264  gnc_coll_set_root_account (col, root);
1265 }
1266 
1267 /********************************************************************\
1268 \********************************************************************/
1269 
1270 Account *
1271 xaccMallocAccount (QofBook *book)
1272 {
1273  Account *acc;
1274 
1275  g_return_val_if_fail (book, nullptr);
1276 
1277  acc = static_cast<Account*>(g_object_new (GNC_TYPE_ACCOUNT, nullptr));
1278  xaccInitAccount (acc, book);
1279  qof_event_gen (&acc->inst, QOF_EVENT_CREATE, nullptr);
1280 
1281  return acc;
1282 }
1283 
1284 Account *
1286 {
1287  Account *root;
1288  AccountPrivate *rpriv;
1289 
1290  root = xaccMallocAccount(book);
1291  rpriv = GET_PRIVATE(root);
1292  xaccAccountBeginEdit(root);
1293  rpriv->type = ACCT_TYPE_ROOT;
1294  rpriv->accountName = qof_string_cache_replace(rpriv->accountName, "Root Account");
1295  mark_account (root);
1296  xaccAccountCommitEdit(root);
1297  gnc_book_set_root_account(book, root);
1298  return root;
1299 }
1300 
1301 Account *
1302 xaccCloneAccount(const Account *from, QofBook *book)
1303 {
1304  Account *ret;
1305  AccountPrivate *from_priv, *priv;
1306 
1307  g_return_val_if_fail(GNC_IS_ACCOUNT(from), nullptr);
1308  g_return_val_if_fail(QOF_IS_BOOK(book), nullptr);
1309 
1310  ENTER (" ");
1311  ret = static_cast<Account*>(g_object_new (GNC_TYPE_ACCOUNT, nullptr));
1312  g_return_val_if_fail (ret, nullptr);
1313 
1314  from_priv = GET_PRIVATE(from);
1315  priv = GET_PRIVATE(ret);
1316  xaccInitAccount (ret, book);
1317 
1318  /* Do not Begin/CommitEdit() here; give the caller
1319  * a chance to fix things up, and let them do it.
1320  * Also let caller issue the generate_event (EVENT_CREATE) */
1321  priv->type = from_priv->type;
1322 
1323  priv->accountName = qof_string_cache_replace(priv->accountName, from_priv->accountName);
1324  priv->accountCode = qof_string_cache_replace(priv->accountCode, from_priv->accountCode);
1325  priv->description = qof_string_cache_replace(priv->description, from_priv->description);
1326 
1327  qof_instance_copy_kvp (QOF_INSTANCE (ret), QOF_INSTANCE (from));
1328 
1329  /* The new book should contain a commodity that matches
1330  * the one in the old book. Find it, use it. */
1331  priv->commodity = gnc_commodity_obtain_twin(from_priv->commodity, book);
1332  gnc_commodity_increment_usage_count(priv->commodity);
1333 
1334  priv->commodity_scu = from_priv->commodity_scu;
1335  priv->non_standard_scu = from_priv->non_standard_scu;
1336 
1337  qof_instance_set_dirty(&ret->inst);
1338  LEAVE (" ");
1339  return ret;
1340 }
1341 
1342 /********************************************************************\
1343 \********************************************************************/
1344 
1345 static void
1346 xaccFreeOneChildAccount (Account *acc)
1347 {
1348  /* FIXME: this code is kind of hacky. actually, all this code
1349  * seems to assume that the account edit levels are all 1. */
1350  if (qof_instance_get_editlevel(acc) == 0)
1351  xaccAccountBeginEdit(acc);
1352  xaccAccountDestroy(acc);
1353 }
1354 
1355 static void
1356 xaccFreeAccountChildren (Account *acc)
1357 {
1358  auto priv{GET_PRIVATE(acc)};
1359  /* Copy the list since it will be modified */
1360  auto children = priv->children;
1361  std::for_each (children.begin(), children.end(), xaccFreeOneChildAccount);
1362 
1363  /* The foreach should have removed all the children already. */
1364  priv->children.clear();
1365 }
1366 
1367 /* The xaccFreeAccount() routine releases memory associated with the
1368  * account. It should never be called directly from user code;
1369  * instead, the xaccAccountDestroy() routine should be used (because
1370  * xaccAccountDestroy() has the correct commit semantics). */
1371 static void
1372 xaccFreeAccount (Account *acc)
1373 {
1374  AccountPrivate *priv;
1375  GList *lp;
1376 
1377  g_return_if_fail(GNC_IS_ACCOUNT(acc));
1378 
1379  priv = GET_PRIVATE(acc);
1380  qof_event_gen (&acc->inst, QOF_EVENT_DESTROY, nullptr);
1381 
1382  /* Otherwise the lists below get munged while we're iterating
1383  * them, possibly crashing.
1384  */
1385  if (!qof_instance_get_destroying (acc))
1386  qof_instance_set_destroying(acc, TRUE);
1387 
1388  if (!priv->children.empty())
1389  {
1390  PERR (" instead of calling xaccFreeAccount(), please call\n"
1391  " xaccAccountBeginEdit(); xaccAccountDestroy();\n");
1392 
1393  /* First, recursively free children, also frees list */
1394  xaccFreeAccountChildren(acc);
1395  }
1396 
1397  /* remove lots -- although these should be gone by now. */
1398  if (priv->lots)
1399  {
1400  PERR (" instead of calling xaccFreeAccount(), please call\n"
1401  " xaccAccountBeginEdit(); xaccAccountDestroy();\n");
1402 
1403  for (lp = priv->lots; lp; lp = lp->next)
1404  {
1405  GNCLot *lot = static_cast<GNCLot*>(lp->data);
1406  gnc_lot_destroy (lot);
1407  }
1408  g_list_free (priv->lots);
1409  priv->lots = nullptr;
1410  }
1411 
1412  /* Next, clean up the splits */
1413  /* NB there shouldn't be any splits by now ... they should
1414  * have been all been freed by CommitEdit(). We can remove this
1415  * check once we know the warning isn't occurring any more. */
1416  if (!priv->splits.empty())
1417  {
1418  PERR (" instead of calling xaccFreeAccount(), please call\n"
1419  " xaccAccountBeginEdit(); xaccAccountDestroy();\n");
1420 
1421  qof_instance_reset_editlevel(acc);
1422 
1423  for (auto s : priv->splits)
1424  {
1425  g_assert(xaccSplitGetAccount(s) == acc);
1426  xaccSplitDestroy (s);
1427  }
1428 /* Nothing here (or in xaccAccountCommitEdit) nullptrs priv->splits, so this asserts every time.
1429  g_assert(priv->splits == nullptr);
1430 */
1431  }
1432 
1433  qof_string_cache_remove(priv->accountName);
1434  qof_string_cache_remove(priv->accountCode);
1435  qof_string_cache_remove(priv->description);
1436  priv->accountName = priv->accountCode = priv->description = nullptr;
1437 
1438  /* zero out values, just in case stray
1439  * pointers are pointing here. */
1440 
1441  priv->last_num = nullptr;
1442  priv->tax_us_code = nullptr;
1443  priv->tax_us_pns = nullptr;
1444  priv->color = nullptr;
1445  priv->sort_order = nullptr;
1446  priv->notes = nullptr;
1447  priv->filter = nullptr;
1448 
1449  priv->parent = nullptr;
1450 
1451  priv->balance = gnc_numeric_zero();
1452  priv->noclosing_balance = gnc_numeric_zero();
1453  priv->cleared_balance = gnc_numeric_zero();
1454  priv->reconciled_balance = gnc_numeric_zero();
1455 
1456  priv->type = ACCT_TYPE_NONE;
1457  gnc_commodity_decrement_usage_count(priv->commodity);
1458  priv->commodity = nullptr;
1459 
1460  priv->balance_dirty = FALSE;
1461  priv->sort_dirty = FALSE;
1462  priv->splits.~SplitsVec();
1463  priv->children.~AccountVec();
1464  g_hash_table_destroy (priv->splits_hash);
1465 
1466  /* qof_instance_release (&acc->inst); */
1467  g_object_unref(acc);
1468 }
1469 
1470 /********************************************************************\
1471  * transactional routines
1472 \********************************************************************/
1473 
1474 void
1476 {
1477  g_return_if_fail(acc);
1478  qof_begin_edit(&acc->inst);
1479 }
1480 
1481 static void on_done(QofInstance *inst)
1482 {
1483  /* old event style */
1484  qof_event_gen (inst, QOF_EVENT_MODIFY, nullptr);
1485 }
1486 
1487 static void on_err (QofInstance *inst, QofBackendError errcode)
1488 {
1489  PERR("commit error: %d", errcode);
1490  gnc_engine_signal_commit_error( errcode );
1491 }
1492 
1493 static void acc_free (QofInstance *inst)
1494 {
1495  AccountPrivate *priv;
1496  Account *acc = (Account *) inst;
1497 
1498  priv = GET_PRIVATE(acc);
1499  if (priv->parent)
1500  gnc_account_remove_child(priv->parent, acc);
1501  xaccFreeAccount(acc);
1502 }
1503 
1504 static void
1505 destroy_pending_splits_for_account(QofInstance *ent, gpointer acc)
1506 {
1507  Transaction *trans = (Transaction *) ent;
1508  Split *split;
1509 
1510  if (xaccTransIsOpen(trans))
1511  while ((split = xaccTransFindSplitByAccount(trans, static_cast<Account*>(acc))))
1512  xaccSplitDestroy(split);
1513 }
1514 
1515 void
1517 {
1518  AccountPrivate *priv;
1519  QofBook *book;
1520 
1521  g_return_if_fail(acc);
1522  if (!qof_commit_edit(&acc->inst)) return;
1523 
1524  /* If marked for deletion, get rid of subaccounts first,
1525  * and then the splits ... */
1526  priv = GET_PRIVATE(acc);
1527  if (qof_instance_get_destroying(acc))
1528  {
1529  QofCollection *col;
1530 
1531  qof_instance_increase_editlevel(acc);
1532 
1533  /* First, recursively free children */
1534  xaccFreeAccountChildren(acc);
1535 
1536  PINFO ("freeing splits for account %p (%s)",
1537  acc, priv->accountName ? priv->accountName : "(null)");
1538 
1539  book = qof_instance_get_book(acc);
1540 
1541  /* If book is shutting down, just clear the split list. The splits
1542  themselves will be destroyed by the transaction code */
1543  if (!qof_book_shutting_down(book))
1544  {
1545  // We need to delete in reverse order so that the vector's iterators aren't invalidated.
1546  for_each(priv->splits.rbegin(), priv->splits.rend(), [](Split *s) {
1547  xaccSplitDestroy (s); });
1548  }
1549  else
1550  {
1551  priv->splits.clear();
1552  g_hash_table_remove_all (priv->splits_hash);
1553  }
1554 
1555  /* It turns out there's a case where this assertion does not hold:
1556  When the user tries to delete an Imbalance account, while also
1557  deleting all the splits in it. The splits will just get
1558  recreated and put right back into the same account!
1559 
1560  g_assert(priv->splits == nullptr || qof_book_shutting_down(acc->inst.book));
1561  */
1562 
1563  if (!qof_book_shutting_down(book))
1564  {
1565  col = qof_book_get_collection(book, GNC_ID_TRANS);
1566  qof_collection_foreach(col, destroy_pending_splits_for_account, acc);
1567 
1568  /* the lots should be empty by now */
1569  for (auto lp = priv->lots; lp; lp = lp->next)
1570  {
1571  GNCLot *lot = static_cast<GNCLot*>(lp->data);
1572  gnc_lot_destroy (lot);
1573  }
1574  }
1575  g_list_free(priv->lots);
1576  priv->lots = nullptr;
1577 
1578  qof_instance_set_dirty(&acc->inst);
1579  qof_instance_decrease_editlevel(acc);
1580  }
1581  else
1582  {
1583  xaccAccountBringUpToDate(acc);
1584  }
1585 
1586  qof_commit_edit_part2(&acc->inst, on_err, on_done, acc_free);
1587 }
1588 
1589 void
1591 {
1592  g_return_if_fail(GNC_IS_ACCOUNT(acc));
1593 
1594  qof_instance_set_destroying(acc, TRUE);
1595 
1596  xaccAccountCommitEdit (acc);
1597 }
1598 
1599 /********************************************************************\
1600 \********************************************************************/
1601 
1602 static gboolean
1603 xaccAcctChildrenEqual(const AccountVec& na,
1604  const AccountVec& nb,
1605  gboolean check_guids)
1606 {
1607  if (na.size() != nb.size())
1608  {
1609  PINFO ("Accounts have different numbers of children");
1610  return (FALSE);
1611  }
1612 
1613  for (auto aa : na)
1614  {
1615  auto it_b = std::find_if (nb.begin(), nb.end(), [aa](auto ab) -> bool
1616  {
1617  if (!aa) return (!ab);
1618  if (!ab) return false;
1619  auto code_a{GET_PRIVATE(aa)->accountCode};
1620  auto code_b{GET_PRIVATE(ab)->accountCode};
1621  if ((code_a && *code_a) || (code_b && *code_b)) return !g_strcmp0 (code_a, code_b);
1622  return !g_strcmp0 (GET_PRIVATE(aa)->accountName, GET_PRIVATE(ab)->accountName);
1623  });
1624 
1625  if (it_b == nb.end())
1626  {
1627  PINFO ("Unable to find matching child account.");
1628  return FALSE;
1629  }
1630  else if (auto ab = *it_b; !xaccAccountEqual(aa, ab, check_guids))
1631  {
1632  char sa[GUID_ENCODING_LENGTH + 1];
1633  char sb[GUID_ENCODING_LENGTH + 1];
1634 
1637 
1638  PWARN ("accounts %s and %s differ", sa, sb);
1639 
1640  return(FALSE);
1641  }
1642  }
1643 
1644  return(TRUE);
1645 }
1646 
1647 gboolean
1648 xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
1649 {
1650  AccountPrivate *priv_aa, *priv_ab;
1651 
1652  if (!aa && !ab) return TRUE;
1653 
1654  g_return_val_if_fail(GNC_IS_ACCOUNT(aa), FALSE);
1655  g_return_val_if_fail(GNC_IS_ACCOUNT(ab), FALSE);
1656 
1657  priv_aa = GET_PRIVATE(aa);
1658  priv_ab = GET_PRIVATE(ab);
1659  if (priv_aa->type != priv_ab->type)
1660  {
1661  PWARN ("types differ: %d vs %d", priv_aa->type, priv_ab->type);
1662  return FALSE;
1663  }
1664 
1665  if (g_strcmp0(priv_aa->accountName, priv_ab->accountName) != 0)
1666  {
1667  PWARN ("names differ: %s vs %s", priv_aa->accountName, priv_ab->accountName);
1668  return FALSE;
1669  }
1670 
1671  if (g_strcmp0(priv_aa->accountCode, priv_ab->accountCode) != 0)
1672  {
1673  PWARN ("codes differ: %s vs %s", priv_aa->accountCode, priv_ab->accountCode);
1674  return FALSE;
1675  }
1676 
1677  if (g_strcmp0(priv_aa->description, priv_ab->description) != 0)
1678  {
1679  PWARN ("descriptions differ: %s vs %s", priv_aa->description, priv_ab->description);
1680  return FALSE;
1681  }
1682 
1683  if (!gnc_commodity_equal(priv_aa->commodity, priv_ab->commodity))
1684  {
1685  PWARN ("commodities differ");
1686  return FALSE;
1687  }
1688 
1689  if (check_guids)
1690  {
1691  if (qof_instance_guid_compare(aa, ab) != 0)
1692  {
1693  PWARN ("GUIDs differ");
1694  return FALSE;
1695  }
1696  }
1697 
1698  if (qof_instance_compare_kvp (QOF_INSTANCE (aa), QOF_INSTANCE (ab)) != 0)
1699  {
1700  char *frame_a;
1701  char *frame_b;
1702 
1703  frame_a = qof_instance_kvp_as_string (QOF_INSTANCE (aa));
1704  frame_b = qof_instance_kvp_as_string (QOF_INSTANCE (ab));
1705 
1706  PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
1707 
1708  g_free (frame_a);
1709  g_free (frame_b);
1710 
1711  return FALSE;
1712  }
1713 
1714  if (!gnc_numeric_equal(priv_aa->starting_balance, priv_ab->starting_balance))
1715  {
1716  char *str_a;
1717  char *str_b;
1718 
1719  str_a = gnc_numeric_to_string(priv_aa->starting_balance);
1720  str_b = gnc_numeric_to_string(priv_ab->starting_balance);
1721 
1722  PWARN ("starting balances differ: %s vs %s", str_a, str_b);
1723 
1724  g_free (str_a);
1725  g_free (str_b);
1726 
1727  return FALSE;
1728  }
1729 
1730  if (!gnc_numeric_equal(priv_aa->starting_noclosing_balance,
1731  priv_ab->starting_noclosing_balance))
1732  {
1733  char *str_a;
1734  char *str_b;
1735 
1736  str_a = gnc_numeric_to_string(priv_aa->starting_noclosing_balance);
1737  str_b = gnc_numeric_to_string(priv_ab->starting_noclosing_balance);
1738 
1739  PWARN ("starting noclosing balances differ: %s vs %s", str_a, str_b);
1740 
1741  g_free (str_a);
1742  g_free (str_b);
1743 
1744  return FALSE;
1745  }
1746  if (!gnc_numeric_equal(priv_aa->starting_cleared_balance,
1747  priv_ab->starting_cleared_balance))
1748  {
1749  char *str_a;
1750  char *str_b;
1751 
1752  str_a = gnc_numeric_to_string(priv_aa->starting_cleared_balance);
1753  str_b = gnc_numeric_to_string(priv_ab->starting_cleared_balance);
1754 
1755  PWARN ("starting cleared balances differ: %s vs %s", str_a, str_b);
1756 
1757  g_free (str_a);
1758  g_free (str_b);
1759 
1760  return FALSE;
1761  }
1762 
1763  if (!gnc_numeric_equal(priv_aa->starting_reconciled_balance,
1764  priv_ab->starting_reconciled_balance))
1765  {
1766  char *str_a;
1767  char *str_b;
1768 
1769  str_a = gnc_numeric_to_string(priv_aa->starting_reconciled_balance);
1770  str_b = gnc_numeric_to_string(priv_ab->starting_reconciled_balance);
1771 
1772  PWARN ("starting reconciled balances differ: %s vs %s", str_a, str_b);
1773 
1774  g_free (str_a);
1775  g_free (str_b);
1776 
1777  return FALSE;
1778  }
1779 
1780  if (!gnc_numeric_equal(priv_aa->balance, priv_ab->balance))
1781  {
1782  char *str_a;
1783  char *str_b;
1784 
1785  str_a = gnc_numeric_to_string(priv_aa->balance);
1786  str_b = gnc_numeric_to_string(priv_ab->balance);
1787 
1788  PWARN ("balances differ: %s vs %s", str_a, str_b);
1789 
1790  g_free (str_a);
1791  g_free (str_b);
1792 
1793  return FALSE;
1794  }
1795 
1796  if (!gnc_numeric_equal(priv_aa->noclosing_balance, priv_ab->noclosing_balance))
1797  {
1798  char *str_a;
1799  char *str_b;
1800 
1801  str_a = gnc_numeric_to_string(priv_aa->noclosing_balance);
1802  str_b = gnc_numeric_to_string(priv_ab->noclosing_balance);
1803 
1804  PWARN ("noclosing balances differ: %s vs %s", str_a, str_b);
1805 
1806  g_free (str_a);
1807  g_free (str_b);
1808 
1809  return FALSE;
1810  }
1811  if (!gnc_numeric_equal(priv_aa->cleared_balance, priv_ab->cleared_balance))
1812  {
1813  char *str_a;
1814  char *str_b;
1815 
1816  str_a = gnc_numeric_to_string(priv_aa->cleared_balance);
1817  str_b = gnc_numeric_to_string(priv_ab->cleared_balance);
1818 
1819  PWARN ("cleared balances differ: %s vs %s", str_a, str_b);
1820 
1821  g_free (str_a);
1822  g_free (str_b);
1823 
1824  return FALSE;
1825  }
1826 
1827  if (!gnc_numeric_equal(priv_aa->reconciled_balance, priv_ab->reconciled_balance))
1828  {
1829  char *str_a;
1830  char *str_b;
1831 
1832  str_a = gnc_numeric_to_string(priv_aa->reconciled_balance);
1833  str_b = gnc_numeric_to_string(priv_ab->reconciled_balance);
1834 
1835  PWARN ("reconciled balances differ: %s vs %s", str_a, str_b);
1836 
1837  g_free (str_a);
1838  g_free (str_b);
1839 
1840  return FALSE;
1841  }
1842 
1843  /* no parent; always compare downwards. */
1844 
1845  if (!std::equal (priv_aa->splits.begin(), priv_aa->splits.end(),
1846  priv_ab->splits.begin(), priv_ab->splits.end(),
1847  [check_guids](auto sa, auto sb)
1848  { return xaccSplitEqual(sa, sb, check_guids, true, false); }))
1849  {
1850  PWARN ("splits differ");
1851  return false;
1852  }
1853 
1854  if (!xaccAcctChildrenEqual(priv_aa->children, priv_ab->children, check_guids))
1855  {
1856  PWARN ("children differ");
1857  return FALSE;
1858  }
1859 
1860  return(TRUE);
1861 }
1862 
1863 /********************************************************************\
1864 \********************************************************************/
1865 void
1867 {
1868  AccountPrivate *priv;
1869 
1870  g_return_if_fail(GNC_IS_ACCOUNT(acc));
1871 
1872  if (qof_instance_get_destroying(acc))
1873  return;
1874 
1875  priv = GET_PRIVATE(acc);
1876  priv->sort_dirty = TRUE;
1877 }
1878 
1879 void
1881 {
1882  AccountPrivate *priv;
1883 
1884  g_return_if_fail(GNC_IS_ACCOUNT(acc));
1885 
1886  if (qof_instance_get_destroying(acc))
1887  return;
1888 
1889  priv = GET_PRIVATE(acc);
1890  priv->balance_dirty = TRUE;
1891 }
1892 
1894 {
1895  AccountPrivate *priv;
1896 
1897  g_return_if_fail (GNC_IS_ACCOUNT (acc));
1898 
1899  if (qof_instance_get_destroying (acc))
1900  return;
1901 
1902  priv = GET_PRIVATE (acc);
1903  priv->defer_bal_computation = defer;
1904 }
1905 
1907 {
1908  AccountPrivate *priv;
1909  if (!acc)
1910  return false;
1911  priv = GET_PRIVATE (acc);
1912  return priv->defer_bal_computation;
1913 }
1914 
1915 
1916 /********************************************************************\
1917 \********************************************************************/
1918 
1919 static bool split_cmp_less (const Split* a, const Split* b)
1920 {
1921  return xaccSplitOrder (a, b) < 0;
1922 }
1923 
1924 gboolean
1926 {
1927  AccountPrivate *priv;
1928 
1929  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
1930  g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
1931 
1932  priv = GET_PRIVATE(acc);
1933  if (!g_hash_table_add (priv->splits_hash, s))
1934  return false;
1935 
1936  priv->splits.push_back (s);
1937 
1938  if (qof_instance_get_editlevel(acc) == 0)
1939  std::sort (priv->splits.begin(), priv->splits.end(), split_cmp_less);
1940  else
1941  priv->sort_dirty = true;
1942 
1943  //FIXME: find better event
1944  qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, nullptr);
1945  /* Also send an event based on the account */
1946  qof_event_gen(&acc->inst, GNC_EVENT_ITEM_ADDED, s);
1947 
1948  priv->balance_dirty = TRUE;
1949 // DRH: Should the below be added? It is present in the delete path.
1950 // xaccAccountRecomputeBalance(acc);
1951  return TRUE;
1952 }
1953 
1954 gboolean
1956 {
1957  AccountPrivate *priv;
1958 
1959  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
1960  g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
1961 
1962  priv = GET_PRIVATE(acc);
1963 
1964  if (!g_hash_table_remove (priv->splits_hash, s))
1965  return false;
1966 
1967  // shortcut pruning the last element. this is the most common
1968  // remove_split operation during UI or book shutdown.
1969  if (s == priv->splits.back())
1970  priv->splits.pop_back();
1971  else
1972  priv->splits.erase (std::remove (priv->splits.begin(), priv->splits.end(), s),
1973  priv->splits.end());
1974 
1975  //FIXME: find better event type
1976  qof_event_gen(&acc->inst, QOF_EVENT_MODIFY, nullptr);
1977  // And send the account-based event, too
1978  qof_event_gen(&acc->inst, GNC_EVENT_ITEM_REMOVED, s);
1979 
1980  priv->balance_dirty = TRUE;
1982  return TRUE;
1983 }
1984 
1985 void
1986 xaccAccountSortSplits (Account *acc, gboolean force)
1987 {
1988  AccountPrivate *priv;
1989 
1990  g_return_if_fail(GNC_IS_ACCOUNT(acc));
1991 
1992  priv = GET_PRIVATE(acc);
1993  if (!priv->sort_dirty || (!force && qof_instance_get_editlevel(acc) > 0))
1994  return;
1995  std::sort (priv->splits.begin(), priv->splits.end(), split_cmp_less);
1996  priv->sort_dirty = FALSE;
1997  priv->balance_dirty = TRUE;
1998 }
1999 
2000 static void
2001 xaccAccountBringUpToDate(Account *acc)
2002 {
2003  if (!acc) return;
2004 
2005  /* if a re-sort happens here, then everything will update, so the
2006  cost basis and balance calls are no-ops */
2007  xaccAccountSortSplits(acc, FALSE);
2009 }
2010 
2011 /********************************************************************\
2012 \********************************************************************/
2013 
2014 void
2015 xaccAccountSetGUID (Account *acc, const GncGUID *guid)
2016 {
2017  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2018  g_return_if_fail(guid);
2019 
2020  /* XXX this looks fishy and weird to me ... */
2021  PINFO("acct=%p", acc);
2022  xaccAccountBeginEdit (acc);
2023  qof_instance_set_guid (&acc->inst, guid);
2024  qof_instance_set_dirty(&acc->inst);
2025  xaccAccountCommitEdit (acc);
2026 }
2027 
2028 /********************************************************************\
2029 \********************************************************************/
2030 
2031 Account *
2032 xaccAccountLookup (const GncGUID *guid, QofBook *book)
2033 {
2034  QofCollection *col;
2035  if (!guid || !book) return nullptr;
2036  col = qof_book_get_collection (book, GNC_ID_ACCOUNT);
2037  return (Account *) qof_collection_lookup_entity (col, guid);
2038 }
2039 
2040 /********************************************************************\
2041 \********************************************************************/
2042 
2043 void
2045 {
2046  AccountPrivate *priv;
2047 
2048  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2049 
2050  priv = GET_PRIVATE(acc);
2051  priv->mark = m;
2052 }
2053 
2054 void
2055 xaccClearMark (Account *acc, short val)
2056 {
2057  Account *root;
2058 
2059  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2060 
2061  root = gnc_account_get_root(acc);
2062  xaccClearMarkDown(root ? root : acc, val);
2063 }
2064 
2065 void
2066 xaccClearMarkDown (Account *acc, short val)
2067 {
2068  AccountPrivate *priv;
2069 
2070  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2071 
2072  priv = GET_PRIVATE(acc);
2073  priv->mark = val;
2074  std::for_each (priv->children.begin(), priv->children.end(),
2075  [val](auto acc){ xaccClearMarkDown(acc, val); });
2076 }
2077 
2078 /********************************************************************\
2079 \********************************************************************/
2080 
2081 GNCPolicy *
2083 {
2084  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
2085 
2086  return GET_PRIVATE(acc)->policy;
2087 }
2088 
2089 void
2090 gnc_account_set_policy (Account *acc, GNCPolicy *policy)
2091 {
2092  AccountPrivate *priv;
2093 
2094  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2095 
2096  priv = GET_PRIVATE(acc);
2097  priv->policy = policy ? policy : xaccGetFIFOPolicy();
2098 }
2099 
2100 /********************************************************************\
2101 \********************************************************************/
2102 
2103 void
2104 xaccAccountRemoveLot (Account *acc, GNCLot *lot)
2105 {
2106  AccountPrivate *priv;
2107 
2108  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2109  g_return_if_fail(GNC_IS_LOT(lot));
2110 
2111  priv = GET_PRIVATE(acc);
2112  g_return_if_fail(priv->lots);
2113 
2114  ENTER ("(acc=%p, lot=%p)", acc, lot);
2115  priv->lots = g_list_remove(priv->lots, lot);
2116  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_REMOVE, nullptr);
2117  qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, nullptr);
2118  LEAVE ("(acc=%p, lot=%p)", acc, lot);
2119 }
2120 
2121 void
2122 xaccAccountInsertLot (Account *acc, GNCLot *lot)
2123 {
2124  AccountPrivate *priv, *opriv;
2125  Account * old_acc = nullptr;
2126  Account* lot_account;
2127 
2128  /* errors */
2129  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2130  g_return_if_fail(GNC_IS_LOT(lot));
2131 
2132  /* optimizations */
2133  lot_account = gnc_lot_get_account(lot);
2134  if (lot_account == acc)
2135  return;
2136 
2137  ENTER ("(acc=%p, lot=%p)", acc, lot);
2138 
2139  /* pull it out of the old account */
2140  if (lot_account)
2141  {
2142  old_acc = lot_account;
2143  opriv = GET_PRIVATE(old_acc);
2144  opriv->lots = g_list_remove(opriv->lots, lot);
2145  }
2146 
2147  priv = GET_PRIVATE(acc);
2148  priv->lots = g_list_prepend(priv->lots, lot);
2149  gnc_lot_set_account(lot, acc);
2150 
2151  /* Don't move the splits to the new account. The caller will do this
2152  * if appropriate, and doing it here will not work if we are being
2153  * called from gnc_book_close_period since xaccAccountInsertSplit
2154  * will try to balance capital gains and things aren't ready for that. */
2155 
2156  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_ADD, nullptr);
2157  qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, nullptr);
2158 
2159  LEAVE ("(acc=%p, lot=%p)", acc, lot);
2160 }
2161 
2162 /********************************************************************\
2163 \********************************************************************/
2164 static void
2165 xaccPreSplitMove (Split *split)
2166 {
2168 }
2169 
2170 static void
2171 xaccPostSplitMove (Split *split, Account *accto)
2172 {
2173  Transaction *trans;
2174 
2175  xaccSplitSetAccount(split, accto);
2176  xaccSplitSetAmount(split, split->amount);
2177  trans = xaccSplitGetParent (split);
2178  xaccTransCommitEdit (trans);
2179 }
2180 
2181 void
2183 {
2184  AccountPrivate *from_priv;
2185 
2186  /* errors */
2187  g_return_if_fail(GNC_IS_ACCOUNT(accfrom));
2188  g_return_if_fail(GNC_IS_ACCOUNT(accto));
2189 
2190  /* optimizations */
2191  from_priv = GET_PRIVATE(accfrom);
2192  if (from_priv->splits.empty() || accfrom == accto)
2193  return;
2194 
2195  /* check for book mix-up */
2196  g_return_if_fail (qof_instance_books_equal(accfrom, accto));
2197  ENTER ("(accfrom=%p, accto=%p)", accfrom, accto);
2198 
2199  xaccAccountBeginEdit(accfrom);
2200  xaccAccountBeginEdit(accto);
2201  /* Begin editing both accounts and all transactions in accfrom. */
2202  std::for_each (from_priv->splits.begin(), from_priv->splits.end(), xaccPreSplitMove);
2203 
2204  /* Concatenate accfrom's lists of splits and lots to accto's lists. */
2205  //to_priv->splits = g_list_concat(to_priv->splits, from_priv->splits);
2206  //to_priv->lots = g_list_concat(to_priv->lots, from_priv->lots);
2207 
2208  /* Set appropriate flags. */
2209  //from_priv->balance_dirty = TRUE;
2210  //from_priv->sort_dirty = FALSE;
2211  //to_priv->balance_dirty = TRUE;
2212  //to_priv->sort_dirty = TRUE;
2213 
2214  /*
2215  * Change each split's account back pointer to accto.
2216  * Convert each split's amount to accto's commodity.
2217  * Commit to editing each transaction.
2218  */
2219  auto splits = from_priv->splits;
2220  std::for_each (splits.begin(), splits.end(), [accto](auto s){ xaccPostSplitMove (s, accto); });
2221 
2222  /* Finally empty accfrom. */
2223  g_assert(from_priv->splits.empty());
2224  g_assert(from_priv->lots == nullptr);
2225  xaccAccountCommitEdit(accfrom);
2226  xaccAccountCommitEdit(accto);
2227 
2228  LEAVE ("(accfrom=%p, accto=%p)", accfrom, accto);
2229 }
2230 
2231 
2232 /********************************************************************\
2233  * xaccAccountRecomputeBalance *
2234  * recomputes the partial balances and the current balance for *
2235  * this account. *
2236  * *
2237  * The way the computation is done depends on whether the partial *
2238  * balances are for a monetary account (bank, cash, etc.) or a *
2239  * certificate account (stock portfolio, mutual fund). For bank *
2240  * accounts, the invariant amount is the dollar amount. For share *
2241  * accounts, the invariant amount is the number of shares. For *
2242  * share accounts, the share price fluctuates, and the current *
2243  * value of such an account is the number of shares times the *
2244  * current share price. *
2245  * *
2246  * Part of the complexity of this computation stems from the fact *
2247  * xacc uses a double-entry system, meaning that one transaction *
2248  * appears in two accounts: one account is debited, and the other *
2249  * is credited. When the transaction represents a sale of shares, *
2250  * or a purchase of shares, some care must be taken to compute *
2251  * balances correctly. For a sale of shares, the stock account must*
2252  * be debited in shares, but the bank account must be credited *
2253  * in dollars. Thus, two different mechanisms must be used to *
2254  * compute balances, depending on account type. *
2255  * *
2256  * Args: account -- the account for which to recompute balances *
2257  * Return: void *
2258 \********************************************************************/
2259 
2260 void
2262 {
2263  AccountPrivate *priv;
2264  gnc_numeric balance;
2265  gnc_numeric noclosing_balance;
2266  gnc_numeric cleared_balance;
2267  gnc_numeric reconciled_balance;
2268 
2269  if (nullptr == acc) return;
2270 
2271  priv = GET_PRIVATE(acc);
2272  if (qof_instance_get_editlevel(acc) > 0) return;
2273  if (!priv->balance_dirty || priv->defer_bal_computation) return;
2274  if (qof_instance_get_destroying(acc)) return;
2276 
2277  balance = priv->starting_balance;
2278  noclosing_balance = priv->starting_noclosing_balance;
2279  cleared_balance = priv->starting_cleared_balance;
2280  reconciled_balance = priv->starting_reconciled_balance;
2281 
2282  PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
2283  priv->accountName, balance.num, balance.denom);
2284  for (auto split : priv->splits)
2285  {
2286  gnc_numeric amt = xaccSplitGetAmount (split);
2287 
2288  balance = gnc_numeric_add_fixed(balance, amt);
2289 
2290  if (NREC != split->reconciled)
2291  {
2292  cleared_balance = gnc_numeric_add_fixed(cleared_balance, amt);
2293  }
2294 
2295  if (YREC == split->reconciled ||
2296  FREC == split->reconciled)
2297  {
2298  reconciled_balance =
2299  gnc_numeric_add_fixed(reconciled_balance, amt);
2300  }
2301 
2302  if (!(xaccTransGetIsClosingTxn (split->parent)))
2303  noclosing_balance = gnc_numeric_add_fixed(noclosing_balance, amt);
2304 
2305  split->balance = balance;
2306  split->noclosing_balance = noclosing_balance;
2307  split->cleared_balance = cleared_balance;
2308  split->reconciled_balance = reconciled_balance;
2309 
2310  }
2311 
2312  priv->balance = balance;
2313  priv->noclosing_balance = noclosing_balance;
2314  priv->cleared_balance = cleared_balance;
2315  priv->reconciled_balance = reconciled_balance;
2316  priv->balance_dirty = FALSE;
2317 }
2318 
2319 /********************************************************************\
2320 \********************************************************************/
2321 
2322 /* The sort order is used to implicitly define an
2323  * order for report generation */
2324 
2325 static int typeorder[NUM_ACCOUNT_TYPES] =
2326 {
2331 };
2332 
2333 static int revorder[NUM_ACCOUNT_TYPES] =
2334 {
2335  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
2336 };
2337 
2338 
2339 int
2340 xaccAccountOrder (const Account *aa, const Account *ab)
2341 {
2342  AccountPrivate *priv_aa, *priv_ab;
2343  const char *da, *db;
2344  int ta, tb, result;
2345 
2346  if ( aa && !ab ) return -1;
2347  if ( !aa && ab ) return +1;
2348  if ( !aa && !ab ) return 0;
2349 
2350  priv_aa = GET_PRIVATE(aa);
2351  priv_ab = GET_PRIVATE(ab);
2352 
2353  /* sort on accountCode strings */
2354  da = priv_aa->accountCode;
2355  db = priv_ab->accountCode;
2356 
2357  /* Otherwise do a string sort */
2358  result = g_strcmp0 (da, db);
2359  if (result)
2360  return result;
2361 
2362  /* if account-type-order array not initialized, initialize it */
2363  /* this will happen at most once during program invocation */
2364  if (-1 == revorder[0])
2365  {
2366  int i;
2367  for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
2368  {
2369  revorder [typeorder[i]] = i;
2370  }
2371  }
2372 
2373  /* otherwise, sort on account type */
2374  ta = priv_aa->type;
2375  tb = priv_ab->type;
2376  ta = revorder[ta];
2377  tb = revorder[tb];
2378  if (ta < tb) return -1;
2379  if (ta > tb) return +1;
2380 
2381  /* otherwise, sort on accountName strings */
2382  da = priv_aa->accountName;
2383  db = priv_ab->accountName;
2384  result = safe_utf8_collate(da, db);
2385  if (result)
2386  return result;
2387 
2388  /* guarantee a stable sort */
2389  return qof_instance_guid_compare(aa, ab);
2390 }
2391 
2392 static int
2393 qof_xaccAccountOrder (const Account **aa, const Account **ab)
2394 {
2395  return xaccAccountOrder(*aa, *ab);
2396 }
2397 
2398 /********************************************************************\
2399 \********************************************************************/
2400 
2401 void
2403 {
2404  AccountPrivate *priv;
2405 
2406  /* errors */
2407  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2408  g_return_if_fail(tip < NUM_ACCOUNT_TYPES);
2409 
2410  /* optimizations */
2411  priv = GET_PRIVATE(acc);
2412  if (priv->type == tip)
2413  return;
2414 
2415  xaccAccountBeginEdit(acc);
2416  priv->type = tip;
2417  priv->balance_dirty = TRUE; /* new type may affect balance computation */
2418  mark_account(acc);
2419  xaccAccountCommitEdit(acc);
2420 }
2421 
2422 void
2423 xaccAccountSetName (Account *acc, const char *str)
2424 {
2425  AccountPrivate *priv;
2426 
2427  /* errors */
2428  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2429  g_return_if_fail(str);
2430 
2431  /* optimizations */
2432  priv = GET_PRIVATE(acc);
2433  if (g_strcmp0(str, priv->accountName) == 0)
2434  return;
2435 
2436  xaccAccountBeginEdit(acc);
2437  priv->accountName = qof_string_cache_replace(priv->accountName, str);
2438  mark_account (acc);
2439  xaccAccountCommitEdit(acc);
2440 }
2441 
2442 void
2443 xaccAccountSetCode (Account *acc, const char *str)
2444 {
2445  AccountPrivate *priv;
2446 
2447  /* errors */
2448  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2449 
2450  /* optimizations */
2451  priv = GET_PRIVATE(acc);
2452  if (g_strcmp0(str, priv->accountCode) == 0)
2453  return;
2454 
2455  xaccAccountBeginEdit(acc);
2456  priv->accountCode = qof_string_cache_replace(priv->accountCode, str ? str : "");
2457  mark_account (acc);
2458  xaccAccountCommitEdit(acc);
2459 }
2460 
2461 void
2462 xaccAccountSetDescription (Account *acc, const char *str)
2463 {
2464  AccountPrivate *priv;
2465 
2466  /* errors */
2467  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2468 
2469  /* optimizations */
2470  priv = GET_PRIVATE(acc);
2471  if (g_strcmp0(str, priv->description) == 0)
2472  return;
2473 
2474  xaccAccountBeginEdit(acc);
2475  priv->description = qof_string_cache_replace(priv->description, str ? str : "");
2476  mark_account (acc);
2477  xaccAccountCommitEdit(acc);
2478 }
2479 
2480 static void
2481 set_kvp_gnc_numeric_path (Account *acc, const std::vector<std::string>& path,
2482  std::optional<gnc_numeric> value)
2483 {
2484  xaccAccountBeginEdit(acc);
2485  qof_instance_set_path_kvp<gnc_numeric> (QOF_INSTANCE(acc), value, path);
2486  xaccAccountCommitEdit(acc);
2487 }
2488 
2489 static std::optional<gnc_numeric>
2490 get_kvp_gnc_numeric_path (const Account *acc, const Path& path)
2491 {
2492  return qof_instance_get_path_kvp<gnc_numeric> (QOF_INSTANCE(acc), path);
2493 }
2494 
2495 static void
2496 set_kvp_string_path (Account *acc, std::vector<std::string> const & path,
2497  const char *value)
2498 {
2499  std::optional<const char*> val;
2500  if (value && *value)
2501  val = g_strdup(value);
2502 
2503  xaccAccountBeginEdit(acc);
2504  qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(acc), val, path);
2505  xaccAccountCommitEdit(acc);
2506 }
2507 
2508 static const char*
2509 get_kvp_string_path (const Account *acc, const Path& path)
2510 {
2511  auto rv{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(acc), path)};
2512  return rv ? *rv : nullptr;
2513 }
2514 
2515 static void
2516 set_kvp_account_path (Account* acc, const Path& path, const Account* kvp_account)
2517 {
2518  std::optional<GncGUID*> val;
2519  if (kvp_account)
2520  val = guid_copy(xaccAccountGetGUID (kvp_account));
2521 
2522  xaccAccountBeginEdit(acc);
2523  qof_instance_set_path_kvp<GncGUID*> (QOF_INSTANCE(acc), val, path);
2524  xaccAccountCommitEdit(acc);
2525 }
2526 
2527 static Account*
2528 get_kvp_account_path (const Account *acc, const Path& path)
2529 {
2530  auto val{qof_instance_get_path_kvp<GncGUID*> (QOF_INSTANCE(acc), path)};
2531  return val ? xaccAccountLookup (*val, gnc_account_get_book (acc)) : nullptr;
2532 }
2533 
2534 static void
2535 set_kvp_boolean_path (Account *acc, const Path& path, gboolean option)
2536 {
2537  set_kvp_string_path (acc, path, option ? "true" : nullptr);
2538 }
2539 
2540 static gboolean
2541 get_kvp_boolean_path (const Account *acc, const Path& path)
2542 {
2543  auto slot{QOF_INSTANCE(acc)->kvp_data->get_slot(path)};
2544  if (!slot) return false;
2545  switch (slot->get_type())
2546  {
2547  case KvpValueImpl::Type::INT64:
2548  return slot->get<int64_t>() != 0;
2549  case KvpValueImpl::Type::STRING:
2550  return g_strcmp0 (slot->get<const char*>(), "true") == 0;
2551  default:
2552  return false;
2553  }
2554 }
2555 
2556 static void
2557 set_kvp_int64_path (Account *acc, const Path& path, std::optional<gint64> value)
2558 {
2559  xaccAccountBeginEdit(acc);
2560  qof_instance_set_path_kvp<int64_t> (QOF_INSTANCE(acc), value, path);
2561  xaccAccountCommitEdit(acc);
2562 }
2563 
2564 static const std::optional<gint64>
2565 get_kvp_int64_path (const Account *acc, const Path& path)
2566 {
2567  return qof_instance_get_path_kvp<int64_t> (QOF_INSTANCE(acc), path);
2568 }
2569 
2570 void
2571 xaccAccountSetColor (Account *acc, const char *str)
2572 {
2573  set_kvp_string_path (acc, {"color"}, str);
2574 }
2575 
2576 void
2577 xaccAccountSetFilter (Account *acc, const char *str)
2578 {
2579  set_kvp_string_path (acc, {"filter"}, str);
2580 }
2581 
2582 void
2583 xaccAccountSetSortOrder (Account *acc, const char *str)
2584 {
2585  set_kvp_string_path (acc, {"sort-order"}, str);
2586 }
2587 
2588 void
2589 xaccAccountSetSortReversed (Account *acc, gboolean sortreversed)
2590 {
2591  set_kvp_boolean_path (acc, {"sort-reversed"}, sortreversed);
2592 }
2593 
2594 static void
2595 qofAccountSetParent (Account *acc, QofInstance *parent)
2596 {
2597  Account *parent_acc;
2598 
2599  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2600  g_return_if_fail(GNC_IS_ACCOUNT(parent));
2601 
2602  parent_acc = GNC_ACCOUNT(parent);
2603  xaccAccountBeginEdit(acc);
2604  xaccAccountBeginEdit(parent_acc);
2605  gnc_account_append_child(parent_acc, acc);
2606  mark_account (parent_acc);
2607  mark_account (acc);
2608  xaccAccountCommitEdit(acc);
2609  xaccAccountCommitEdit(parent_acc);
2610 }
2611 
2612 void
2613 xaccAccountSetNotes (Account *acc, const char *str)
2614 {
2615  set_kvp_string_path (acc, {"notes"}, str);
2616 }
2617 
2618 
2619 void
2620 xaccAccountSetAssociatedAccount (Account *acc, const char *tag, const Account* assoc_acct)
2621 {
2622  g_return_if_fail (GNC_IS_ACCOUNT(acc));
2623  g_return_if_fail (tag && *tag);
2624 
2625  set_kvp_account_path (acc, {"associated-account", tag}, assoc_acct);
2626 }
2627 
2628 void
2629 xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
2630 {
2631  AccountPrivate *priv;
2632 
2633  /* errors */
2634  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2635  g_return_if_fail(GNC_IS_COMMODITY(com));
2636 
2637  /* optimizations */
2638  priv = GET_PRIVATE(acc);
2639  if (com == priv->commodity)
2640  return;
2641 
2642  xaccAccountBeginEdit(acc);
2643  gnc_commodity_decrement_usage_count(priv->commodity);
2644  priv->commodity = com;
2646  priv->commodity_scu = gnc_commodity_get_fraction(com);
2647  priv->non_standard_scu = FALSE;
2648 
2649  /* iterate over splits */
2650  for (auto s : priv->splits)
2651  {
2652  Transaction *trans = xaccSplitGetParent (s);
2653 
2654  xaccTransBeginEdit (trans);
2656  xaccTransCommitEdit (trans);
2657  }
2658 
2659  priv->sort_dirty = TRUE; /* Not needed. */
2660  priv->balance_dirty = TRUE;
2661  mark_account (acc);
2662 
2663  xaccAccountCommitEdit(acc);
2664 }
2665 
2666 /*
2667  * Set the account scu and then check to see if it is the same as the
2668  * commodity scu. This function is called when parsing the data file
2669  * and is designed to catch cases where the two were accidentally set
2670  * to mismatched values in the past.
2671  */
2672 void
2674 {
2675  AccountPrivate *priv;
2676 
2677  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2678 
2679  priv = GET_PRIVATE(acc);
2680  xaccAccountBeginEdit(acc);
2681  priv->commodity_scu = scu;
2682  if (scu != gnc_commodity_get_fraction(priv->commodity))
2683  priv->non_standard_scu = TRUE;
2684  mark_account(acc);
2685  xaccAccountCommitEdit(acc);
2686 }
2687 
2688 int
2690 {
2691  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
2692  return GET_PRIVATE(acc)->commodity_scu;
2693 }
2694 
2695 int
2697 {
2698  AccountPrivate *priv;
2699 
2700  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
2701 
2702  priv = GET_PRIVATE(acc);
2703  if (priv->non_standard_scu || !priv->commodity)
2704  return priv->commodity_scu;
2705  return gnc_commodity_get_fraction(priv->commodity);
2706 }
2707 
2708 void
2709 xaccAccountSetNonStdSCU (Account *acc, gboolean flag)
2710 {
2711  AccountPrivate *priv;
2712 
2713  g_return_if_fail(GNC_IS_ACCOUNT(acc));
2714 
2715  priv = GET_PRIVATE(acc);
2716  if (priv->non_standard_scu == flag)
2717  return;
2718  xaccAccountBeginEdit(acc);
2719  priv->non_standard_scu = flag;
2720  mark_account (acc);
2721  xaccAccountCommitEdit(acc);
2722 }
2723 
2724 gboolean
2726 {
2727  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
2728  return GET_PRIVATE(acc)->non_standard_scu;
2729 }
2730 
2731 /********************************************************************\
2732 \********************************************************************/
2733 /* below follow the old, deprecated currency/security routines. */
2734 
2735 void
2736 DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency)
2737 {
2738  if ((!acc) || (!currency)) return;
2739 
2740  auto s = gnc_commodity_get_unique_name (currency);
2741  set_kvp_string_path (acc, {"old-currency"}, s);
2742 
2743  auto book = qof_instance_get_book(acc);
2744  auto table = gnc_commodity_table_get_table (book);
2745  auto commodity = gnc_commodity_table_lookup_unique (table, s);
2746 
2747  if (!commodity)
2748  gnc_commodity_table_insert (table, currency);
2749 }
2750 
2751 /********************************************************************\
2752 \********************************************************************/
2753 
2754 void
2755 gnc_account_foreach_descendant (const Account *acc, std::function<void(Account*)> account_cb)
2756 {
2757  g_return_if_fail (GNC_IS_ACCOUNT(acc));
2758 
2759  // children must be a vector copy instead of reference because
2760  // some callers e.g. xaccAccountTreeScrubLots will modify the
2761  // children
2762  auto children = GET_PRIVATE(acc)->children;
2763  for (auto child : children)
2764  {
2765  account_cb (child);
2766  gnc_account_foreach_descendant (child, account_cb);
2767  }
2768 }
2769 
2770 static void
2771 account_foreach_descendant_sorted (const Account *acc, std::function<void(Account*)> account_cb)
2772 {
2773  g_return_if_fail (GNC_IS_ACCOUNT(acc));
2774 
2775  auto children = GET_PRIVATE(acc)->children;
2776  std::sort (children.begin(), children.end(),
2777  [](auto a, auto b) { return xaccAccountOrder (a, b) < 0; });
2778 
2779  for (auto child : children)
2780  {
2781  account_cb (child);
2782  account_foreach_descendant_sorted (child, account_cb);
2783  }
2784 }
2785 
2786 void
2788 {
2789  AccountPrivate *ppriv, *cpriv;
2790  Account *old_parent;
2791  QofCollection *col;
2792 
2793  /* errors */
2794  g_assert(GNC_IS_ACCOUNT(new_parent));
2795  g_assert(GNC_IS_ACCOUNT(child));
2796 
2797  /* optimizations */
2798  ppriv = GET_PRIVATE(new_parent);
2799  cpriv = GET_PRIVATE(child);
2800  old_parent = cpriv->parent;
2801  if (old_parent == new_parent)
2802  return;
2803 
2804  // xaccAccountBeginEdit(new_parent);
2805  xaccAccountBeginEdit(child);
2806  if (old_parent)
2807  {
2808  gnc_account_remove_child(old_parent, child);
2809 
2810  if (!qof_instance_books_equal(old_parent, new_parent))
2811  {
2812  /* hack alert -- this implementation is not exactly correct.
2813  * If the entity tables are not identical, then the 'from' book
2814  * may have a different backend than the 'to' book. This means
2815  * that we should get the 'from' backend to destroy this account,
2816  * and the 'to' backend to save it. Right now, this is broken.
2817  *
2818  * A 'correct' implementation similar to this is in Period.c
2819  * except its for transactions ...
2820  *
2821  * Note also, we need to reparent the children to the new book as well.
2822  */
2823  PWARN ("reparenting accounts across books is not correctly supported\n");
2824 
2825  qof_event_gen (&child->inst, QOF_EVENT_DESTROY, nullptr);
2827  GNC_ID_ACCOUNT);
2828  qof_collection_insert_entity (col, &child->inst);
2829  qof_event_gen (&child->inst, QOF_EVENT_CREATE, nullptr);
2830  }
2831  }
2832  cpriv->parent = new_parent;
2833  ppriv->children.push_back (child);
2834  qof_instance_set_dirty(&new_parent->inst);
2835  qof_instance_set_dirty(&child->inst);
2836 
2837  /* Send events data. Warning: The call to commit_edit is also going
2838  * to send a MODIFY event. If the gtktreemodelfilter code gets the
2839  * MODIFY before it gets the ADD, it gets very confused and thinks
2840  * that two nodes have been added. */
2841  qof_event_gen (&child->inst, QOF_EVENT_ADD, nullptr);
2842  // qof_event_gen (&new_parent->inst, QOF_EVENT_MODIFY, nullptr);
2843 
2844  xaccAccountCommitEdit (child);
2845  // xaccAccountCommitEdit(new_parent);
2846 }
2847 
2848 void
2850 {
2851  AccountPrivate *ppriv, *cpriv;
2852  GncEventData ed;
2853 
2854  if (!child) return;
2855 
2856  /* Note this routine might be called on accounts which
2857  * are not yet parented. */
2858  if (!parent) return;
2859 
2860  ppriv = GET_PRIVATE(parent);
2861  cpriv = GET_PRIVATE(child);
2862 
2863  if (cpriv->parent != parent)
2864  {
2865  PERR ("account not a child of parent");
2866  return;
2867  }
2868 
2869  /* Gather event data */
2870  ed.node = parent;
2871  ed.idx = gnc_account_child_index (parent, child);
2872 
2873  ppriv->children.erase (std::remove (ppriv->children.begin(), ppriv->children.end(), child),
2874  ppriv->children.end());
2875 
2876  /* Now send the event. */
2877  qof_event_gen(&child->inst, QOF_EVENT_REMOVE, &ed);
2878 
2879  /* clear the account's parent pointer after REMOVE event generation. */
2880  cpriv->parent = nullptr;
2881 
2882  qof_event_gen (&parent->inst, QOF_EVENT_MODIFY, nullptr);
2883 }
2884 
2885 Account *
2887 {
2888  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
2889  return GET_PRIVATE(acc)->parent;
2890 }
2891 
2892 Account *
2894 {
2895  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
2896 
2897  while (auto parent = gnc_account_get_parent (acc))
2898  acc = parent;
2899 
2900  return acc;
2901 }
2902 
2903 gboolean
2905 {
2906  g_return_val_if_fail(GNC_IS_ACCOUNT(account), FALSE);
2907  return (GET_PRIVATE(account)->parent == nullptr);
2908 }
2909 
2910 GList *
2912 {
2913  g_return_val_if_fail(GNC_IS_ACCOUNT(account), nullptr);
2914  auto& children = GET_PRIVATE(account)->children;
2915  return std::accumulate (children.rbegin(), children.rend(), static_cast<GList*>(nullptr),
2916  g_list_prepend);
2917 }
2918 
2919 GList *
2921 {
2922  g_return_val_if_fail(GNC_IS_ACCOUNT(account), nullptr);
2923  return g_list_sort(gnc_account_get_children (account), (GCompareFunc)xaccAccountOrder);
2924 }
2925 
2926 gint
2928 {
2929  g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
2930  return GET_PRIVATE(account)->children.size();
2931 }
2932 
2933 gint
2934 gnc_account_child_index (const Account *parent, const Account *child)
2935 {
2936  g_return_val_if_fail(GNC_IS_ACCOUNT(parent), -1);
2937  g_return_val_if_fail(GNC_IS_ACCOUNT(child), -1);
2938  auto& children = GET_PRIVATE(parent)->children;
2939  return std::distance (children.begin(), std::find (children.begin(), children.end(), child));
2940 }
2941 
2942 Account *
2943 gnc_account_nth_child (const Account *parent, gint num)
2944 {
2945  g_return_val_if_fail(GNC_IS_ACCOUNT(parent), nullptr);
2946  if ((size_t)num >= GET_PRIVATE(parent)->children.size())
2947  return nullptr;
2948  return static_cast<Account*>(GET_PRIVATE(parent)->children.at (num));
2949 }
2950 
2951 gint
2953 {
2954  int count {0};
2955  gnc_account_foreach_descendant (account, [&count](auto acc){ count++; });
2956  return count;
2957 }
2958 
2959 gint
2961 {
2962  AccountPrivate *priv;
2963  int depth = 0;
2964 
2965  g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
2966 
2967  priv = GET_PRIVATE(account);
2968  while (priv->parent && (priv->type != ACCT_TYPE_ROOT))
2969  {
2970  account = priv->parent;
2971  priv = GET_PRIVATE(account);
2972  depth++;
2973  }
2974 
2975  return depth;
2976 }
2977 
2978 gint
2980 {
2981  AccountPrivate *priv;
2982  g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
2983 
2984  priv = GET_PRIVATE(account);
2985  if (!priv->children.size())
2986  return 1;
2987 
2988  return 1 + std::accumulate (priv->children.begin(), priv->children.end(),
2989  0, [](auto a, auto b)
2990  { return std::max (a, gnc_account_get_tree_depth (b)); });
2991 }
2992 
2993 GList *
2995 {
2996  GList* list = nullptr;
2997  gnc_account_foreach_descendant (account, [&list](auto a){ list = g_list_prepend (list, a); });
2998  return g_list_reverse (list);
2999 }
3000 
3001 GList *
3003 {
3004  GList* list = nullptr;
3005  account_foreach_descendant_sorted (account, [&list](auto a){ list = g_list_prepend (list, a); });
3006  return g_list_reverse (list);
3007 }
3008 
3009 // because gnc_account_lookup_by_name and gnc_account_lookup_by_code
3010 // are described in Account.h searching breadth-first until 4.6, and
3011 // accidentally modified to search depth-first from 4.7
3012 // onwards. Restore breath-first searching in 4.11 onwards to match
3013 // previous behaviour and function description in Account.h
3014 static gpointer
3015 account_foreach_descendant_breadthfirst_until (const Account *acc,
3016  AccountCb2 thunk,
3017  gpointer user_data)
3018 {
3019  g_return_val_if_fail (GNC_IS_ACCOUNT(acc), nullptr);
3020  g_return_val_if_fail (thunk, nullptr);
3021 
3022  auto& children{GET_PRIVATE(acc)->children};
3023 
3024  for (auto acc : children)
3025  if (auto result = thunk (acc, user_data))
3026  return result;
3027 
3028  for (auto acc: children)
3029  if (auto result = account_foreach_descendant_breadthfirst_until (acc, thunk, user_data))
3030  return result;
3031 
3032  return nullptr;
3033 }
3034 
3035 static gpointer
3036 is_acct_name (Account *account, gpointer user_data)
3037 {
3038  auto name {static_cast<gchar*>(user_data)};
3039  return (g_strcmp0 (name, xaccAccountGetName (account)) ? nullptr : account);
3040 }
3041 
3042 Account *
3043 gnc_account_lookup_by_name (const Account *parent, const char * name)
3044 {
3045  return (Account*)account_foreach_descendant_breadthfirst_until (parent, is_acct_name, (char*)name);
3046 }
3047 
3048 static gpointer
3049 is_acct_code (Account *account, gpointer user_data)
3050 {
3051  auto name {static_cast<gchar*>(user_data)};
3052  return (g_strcmp0 (name, xaccAccountGetCode (account)) ? nullptr : account);
3053 }
3054 
3055 Account *
3056 gnc_account_lookup_by_code (const Account *parent, const char * code)
3057 {
3058  return (Account*)account_foreach_descendant_breadthfirst_until (parent, is_acct_code, (char*)code);
3059 }
3060 
3061 static gpointer
3062 is_opening_balance_account (Account* account, gpointer data)
3063 {
3064  gnc_commodity* commodity = GNC_COMMODITY(data);
3065  if (xaccAccountGetIsOpeningBalance(account) && gnc_commodity_equiv(commodity, xaccAccountGetCommodity(account)))
3066  return account;
3067  return nullptr;
3068 }
3069 
3070 Account*
3071 gnc_account_lookup_by_opening_balance (Account* account, gnc_commodity* commodity)
3072 {
3073  return (Account *)gnc_account_foreach_descendant_until (account, is_opening_balance_account, commodity);
3074 }
3075 
3076 /********************************************************************\
3077  * Fetch an account, given its full name *
3078 \********************************************************************/
3079 
3080 static Account *
3081 gnc_account_lookup_by_full_name_helper (const Account *parent,
3082  gchar **names)
3083 {
3084  g_return_val_if_fail(GNC_IS_ACCOUNT(parent), nullptr);
3085  g_return_val_if_fail(names, nullptr);
3086 
3087  /* Look for the first name in the children. */
3088  for (auto account : GET_PRIVATE(parent)->children)
3089  {
3090  auto priv = GET_PRIVATE(account);
3091  if (g_strcmp0(priv->accountName, names[0]) == 0)
3092  {
3093  /* We found an account. If the next entry is nullptr, there is
3094  * nothing left in the name, so just return the account. */
3095  if (names[1] == nullptr)
3096  return account;
3097 
3098  /* No children? We're done. */
3099  if (priv->children.empty())
3100  return nullptr;
3101 
3102  /* There's stuff left to search for. Search recursively. */
3103  if (auto found = gnc_account_lookup_by_full_name_helper(account, &names[1]))
3104  return found;
3105  }
3106  }
3107 
3108  return nullptr;
3109 }
3110 
3111 
3112 Account *
3114  const gchar *name)
3115 {
3116  const AccountPrivate *rpriv;
3117  const Account *root;
3118  Account *found;
3119  gchar **names;
3120 
3121  g_return_val_if_fail(GNC_IS_ACCOUNT(any_acc), nullptr);
3122  g_return_val_if_fail(name, nullptr);
3123 
3124  root = any_acc;
3125  rpriv = GET_PRIVATE(root);
3126  while (rpriv->parent)
3127  {
3128  root = rpriv->parent;
3129  rpriv = GET_PRIVATE(root);
3130  }
3131  names = g_strsplit(name, gnc_get_account_separator_string(), -1);
3132  found = gnc_account_lookup_by_full_name_helper(root, names);
3133  g_strfreev(names);
3134  return found;
3135 }
3136 
3137 GList*
3139  const char* name,
3140  GNCAccountType acctype,
3141  gnc_commodity* commodity)
3142 {
3143  GList *retval{};
3144  auto rpriv{GET_PRIVATE(root)};
3145  for (auto account : rpriv->children)
3146  {
3147  if (xaccAccountGetType (account) == acctype)
3148  {
3149  if (commodity &&
3151  commodity))
3152  continue;
3153 
3154  if (name && strcmp(name, xaccAccountGetName(account)))
3155  continue;
3156 
3157  retval = g_list_prepend(retval, account);
3158  }
3159  }
3160 
3161  if (!retval) // Recurse through the children
3162  for (auto account : rpriv->children)
3163  {
3164  auto result = gnc_account_lookup_by_type_and_commodity(account,
3165  name,
3166  acctype,
3167  commodity);
3168  if (result)
3169  retval = g_list_concat(result, retval);
3170  }
3171  return retval;
3172 }
3173 
3174 void
3176  AccountCb thunk,
3177  gpointer user_data)
3178 {
3179  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3180  g_return_if_fail(thunk);
3181  std::for_each (GET_PRIVATE(acc)->children.begin(), GET_PRIVATE(acc)->children.end(),
3182  [user_data, thunk](auto a){ thunk (a, user_data); });
3183 }
3184 
3185 void
3187  AccountCb thunk,
3188  gpointer user_data)
3189 {
3190  gnc_account_foreach_descendant (acc, [&](auto acc){ thunk (acc, user_data); });
3191 }
3192 
3193 gpointer
3195  AccountCb2 thunk,
3196  gpointer user_data)
3197 {
3198  gpointer result {nullptr};
3199 
3200  g_return_val_if_fail (GNC_IS_ACCOUNT(acc), nullptr);
3201  g_return_val_if_fail (thunk, nullptr);
3202 
3203  for (auto child : GET_PRIVATE(acc)->children)
3204  {
3205  result = thunk (child, user_data);
3206  if (result) break;
3207 
3208  result = gnc_account_foreach_descendant_until (child, thunk, user_data);
3209  if (result) break;
3210  }
3211 
3212  return result;
3213 }
3214 
3215 
3218 {
3219  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), ACCT_TYPE_NONE);
3220  return GET_PRIVATE(acc)->type;
3221 }
3222 
3223 static const char*
3224 qofAccountGetTypeString (const Account *acc)
3225 {
3226  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3227  return xaccAccountTypeEnumAsString(GET_PRIVATE(acc)->type);
3228 }
3229 
3230 static void
3231 qofAccountSetType (Account *acc, const char *type_string)
3232 {
3233  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3234  g_return_if_fail(type_string);
3235  xaccAccountSetType(acc, xaccAccountStringToEnum(type_string));
3236 }
3237 
3238 const char *
3240 {
3241  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3242  return GET_PRIVATE(acc)->accountName;
3243 }
3244 
3245 gchar *
3247 {
3248  AccountPrivate *priv;
3249  const Account *a;
3250  char *fullname;
3251  const gchar **names;
3252  int level;
3253 
3254  /* So much for hardening the API. Too many callers to this function don't
3255  * bother to check if they have a non-nullptr pointer before calling. */
3256  if (nullptr == account)
3257  return g_strdup("");
3258 
3259  /* errors */
3260  g_return_val_if_fail(GNC_IS_ACCOUNT(account), g_strdup(""));
3261 
3262  /* optimizations */
3263  priv = GET_PRIVATE(account);
3264  if (!priv->parent)
3265  return g_strdup("");
3266 
3267  /* Figure out how much space is needed by counting the nodes up to
3268  * the root. */
3269  level = 0;
3270  for (a = account; a; a = priv->parent)
3271  {
3272  priv = GET_PRIVATE(a);
3273  level++;
3274  }
3275 
3276  /* Get all the pointers in the right order. The root node "entry"
3277  * becomes the terminating nullptr pointer for the array of strings. */
3278  names = (const gchar **)g_malloc(level * sizeof(gchar *));
3279  names[--level] = nullptr;
3280  for (a = account; level > 0; a = priv->parent)
3281  {
3282  priv = GET_PRIVATE(a);
3283  names[--level] = priv->accountName;
3284  }
3285 
3286  /* Build the full name */
3287  fullname = g_strjoinv(account_separator, (gchar **)names);
3288  g_free(names);
3289 
3290  return fullname;
3291 }
3292 
3293 const char *
3295 {
3296  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3297  return GET_PRIVATE(acc)->accountCode;
3298 }
3299 
3300 const char *
3302 {
3303  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3304  return GET_PRIVATE(acc)->description;
3305 }
3306 
3307 const char *
3309 {
3310  return get_kvp_string_path (acc, {"color"});
3311 }
3312 
3313 const char *
3315 {
3316  return get_kvp_string_path (acc, {"filter"});
3317 }
3318 
3319 const char *
3321 {
3322  return get_kvp_string_path (acc, {"sort-order"});
3323 }
3324 
3325 gboolean
3327 {
3328  return get_kvp_boolean_path (acc, {"sort-reversed"});
3329 }
3330 
3331 const char *
3333 {
3334  return get_kvp_string_path (acc, {"notes"});
3335 }
3336 
3337 Account*
3338 xaccAccountGetAssociatedAccount (const Account *acc, const char *tag)
3339 {
3340  g_return_val_if_fail (tag && *tag, nullptr);
3341 
3342  return get_kvp_account_path (acc, {"associated-account", tag});
3343 }
3344 
3345 
3346 gnc_commodity *
3348 {
3349  if (auto s = get_kvp_string_path (acc, {"old-currency"}))
3350  {
3352  return gnc_commodity_table_lookup_unique (table, s);
3353  }
3354 
3355  return nullptr;
3356 }
3357 
3358 gnc_commodity *
3360 {
3361  if (!GNC_IS_ACCOUNT(acc))
3362  return nullptr;
3363  return GET_PRIVATE(acc)->commodity;
3364 }
3365 
3366 gnc_commodity * gnc_account_get_currency_or_parent(const Account* account)
3367 {
3368  g_return_val_if_fail (GNC_IS_ACCOUNT (account), nullptr);
3369 
3370  for (auto acc = account; acc; acc = gnc_account_get_parent (acc))
3371  if (auto comm = xaccAccountGetCommodity (acc); gnc_commodity_is_currency (comm))
3372  return comm;
3373 
3374  return nullptr; // no suitable commodity found.
3375 }
3376 
3377 /********************************************************************\
3378 \********************************************************************/
3379 void
3380 gnc_account_set_start_balance (Account *acc, const gnc_numeric start_baln)
3381 {
3382  AccountPrivate *priv;
3383 
3384  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3385 
3386  priv = GET_PRIVATE(acc);
3387  priv->starting_balance = start_baln;
3388  priv->balance_dirty = TRUE;
3389 }
3390 
3391 void
3393  const gnc_numeric start_baln)
3394 {
3395  AccountPrivate *priv;
3396 
3397  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3398 
3399  priv = GET_PRIVATE(acc);
3400  priv->starting_cleared_balance = start_baln;
3401  priv->balance_dirty = TRUE;
3402 }
3403 
3404 void
3406  const gnc_numeric start_baln)
3407 {
3408  AccountPrivate *priv;
3409 
3410  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3411 
3412  priv = GET_PRIVATE(acc);
3413  priv->starting_reconciled_balance = start_baln;
3414  priv->balance_dirty = TRUE;
3415 }
3416 
3417 gnc_numeric
3419 {
3420  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3421  return GET_PRIVATE(acc)->balance;
3422 }
3423 
3424 gnc_numeric
3426 {
3427  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3428  return GET_PRIVATE(acc)->cleared_balance;
3429 }
3430 
3431 gnc_numeric
3433 {
3434  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3435  return GET_PRIVATE(acc)->reconciled_balance;
3436 }
3437 
3438 gnc_numeric
3439 xaccAccountGetProjectedMinimumBalance (const Account *acc)
3440 {
3441  auto today{gnc_time64_get_today_end()};
3442  std::optional<gnc_numeric> minimum;
3443 
3444  auto before_today_end = [&minimum, today](const Split *s) -> bool
3445  {
3446  auto bal{xaccSplitGetBalance(s)};
3447  if (!minimum || gnc_numeric_compare (bal, *minimum) < 0)
3448  minimum = bal;
3449  return (xaccTransGetDate(xaccSplitGetParent(s)) < today);
3450  };
3451  // scan to find today's split, but we're really interested in the
3452  // minimum balance
3453  [[maybe_unused]] auto todays_split = gnc_account_find_split (acc, before_today_end, true);
3454  return minimum ? *minimum : gnc_numeric_zero();
3455 }
3456 
3457 
3458 /********************************************************************\
3459 \********************************************************************/
3460 
3461 static gnc_numeric
3462 GetBalanceAsOfDate (Account *acc, time64 date, std::function<gnc_numeric(Split*)> split_to_numeric)
3463 {
3464  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3465 
3466  xaccAccountSortSplits (acc, TRUE); /* just in case, normally a noop */
3467  xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */
3468 
3469  auto is_before_date = [date](auto s) -> bool
3470  { return xaccTransGetDate(xaccSplitGetParent(s)) < date; };
3471 
3472  auto latest_split{gnc_account_find_split (acc, is_before_date, true)};
3473  return latest_split ? split_to_numeric (latest_split) : gnc_numeric_zero();
3474 }
3475 
3476 gnc_numeric
3478 {
3479  return GetBalanceAsOfDate (acc, date, xaccSplitGetBalance);
3480 }
3481 
3482 static gnc_numeric
3483 xaccAccountGetNoclosingBalanceAsOfDate (Account *acc, time64 date)
3484 {
3485  return GetBalanceAsOfDate (acc, date, xaccSplitGetNoclosingBalance);
3486 }
3487 
3488 gnc_numeric
3490 {
3491  return GetBalanceAsOfDate (acc, date, xaccSplitGetReconciledBalance);
3492 }
3493 
3494 /*
3495  * Originally gsr_account_present_balance in gnc-split-reg.c
3496  */
3497 gnc_numeric
3498 xaccAccountGetPresentBalance (const Account *acc)
3499 {
3500  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3501 
3502  return xaccAccountGetBalanceAsOfDate (GNC_ACCOUNT (acc),
3504 }
3505 
3506 
3507 /********************************************************************\
3508 \********************************************************************/
3509 /* XXX TODO: These 'GetBal' routines should be moved to some
3510  * utility area outside of the core account engine area.
3511  */
3512 
3513 /*
3514  * Convert a balance from one currency to another.
3515  */
3516 gnc_numeric
3517 xaccAccountConvertBalanceToCurrency(const Account *acc, /* for book */
3518  gnc_numeric balance,
3519  const gnc_commodity *balance_currency,
3520  const gnc_commodity *new_currency)
3521 {
3522  QofBook *book;
3523  GNCPriceDB *pdb;
3524 
3525  if (gnc_numeric_zero_p (balance) ||
3526  gnc_commodity_equiv (balance_currency, new_currency))
3527  return balance;
3528 
3529  book = gnc_account_get_book (acc);
3530  pdb = gnc_pricedb_get_db (book);
3531 
3533  pdb, balance, balance_currency, new_currency);
3534 
3535  return balance;
3536 }
3537 
3538 /*
3539  * Convert a balance from one currency to another with price of
3540  * a given date.
3541  */
3542 gnc_numeric
3543 xaccAccountConvertBalanceToCurrencyAsOfDate(const Account *acc, /* for book */
3544  gnc_numeric balance,
3545  const gnc_commodity *balance_currency,
3546  const gnc_commodity *new_currency,
3547  time64 date)
3548 {
3549  QofBook *book;
3550  GNCPriceDB *pdb;
3551 
3552  if (gnc_numeric_zero_p (balance) ||
3553  gnc_commodity_equiv (balance_currency, new_currency))
3554  return balance;
3555 
3556  book = gnc_account_get_book (acc);
3557  pdb = gnc_pricedb_get_db (book);
3558 
3560  pdb, balance, balance_currency, new_currency, date);
3561 
3562  return balance;
3563 }
3564 
3565 /*
3566  * Given an account and a GetBalanceFn pointer, extract the requested
3567  * balance from the account and then convert it to the desired
3568  * currency.
3569  */
3570 static gnc_numeric
3571 xaccAccountGetXxxBalanceInCurrency (const Account *acc,
3572  xaccGetBalanceFn fn,
3573  const gnc_commodity *report_currency)
3574 {
3575  AccountPrivate *priv;
3576  gnc_numeric balance;
3577 
3578  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3579  g_return_val_if_fail(fn, gnc_numeric_zero());
3580  g_return_val_if_fail(GNC_IS_COMMODITY(report_currency), gnc_numeric_zero());
3581 
3582  priv = GET_PRIVATE(acc);
3583  balance = fn(acc);
3584  balance = xaccAccountConvertBalanceToCurrency(acc, balance,
3585  priv->commodity,
3586  report_currency);
3587  return balance;
3588 }
3589 
3590 static gnc_numeric
3591 xaccAccountGetXxxBalanceAsOfDateInCurrency(Account *acc, time64 date,
3592  xaccGetBalanceAsOfDateFn fn,
3593  const gnc_commodity *report_commodity)
3594 {
3595  AccountPrivate *priv;
3596 
3597  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3598  g_return_val_if_fail(fn, gnc_numeric_zero());
3599  g_return_val_if_fail(GNC_IS_COMMODITY(report_commodity), gnc_numeric_zero());
3600 
3601  priv = GET_PRIVATE(acc);
3602  return xaccAccountConvertBalanceToCurrencyAsOfDate(
3603  acc, fn(acc, date), priv->commodity, report_commodity, date);
3604 }
3605 
3606 /*
3607  * Data structure used to pass various arguments into the following fn.
3608  */
3609 typedef struct
3610 {
3611  const gnc_commodity *currency;
3612  gnc_numeric balance;
3613  xaccGetBalanceFn fn;
3614  xaccGetBalanceAsOfDateFn asOfDateFn;
3615  time64 date;
3616 } CurrencyBalance;
3617 
3618 
3619 /*
3620  * A helper function for iterating over all the accounts in a list or
3621  * tree. This function is called once per account, and sums up the
3622  * values of all these accounts.
3623  */
3624 static void
3625 xaccAccountBalanceHelper (Account *acc, gpointer data)
3626 {
3627  CurrencyBalance *cb = static_cast<CurrencyBalance*>(data);
3628  gnc_numeric balance;
3629 
3630  if (!cb->fn || !cb->currency)
3631  return;
3632  balance = xaccAccountGetXxxBalanceInCurrency (acc, cb->fn, cb->currency);
3633  cb->balance = gnc_numeric_add (cb->balance, balance,
3634  gnc_commodity_get_fraction (cb->currency),
3636 }
3637 
3638 static void
3639 xaccAccountBalanceAsOfDateHelper (Account *acc, gpointer data)
3640 {
3641  CurrencyBalance *cb = static_cast<CurrencyBalance*>(data);
3642  gnc_numeric balance;
3643 
3644  g_return_if_fail (cb->asOfDateFn && cb->currency);
3645 
3646  balance = xaccAccountGetXxxBalanceAsOfDateInCurrency (
3647  acc, cb->date, cb->asOfDateFn, cb->currency);
3648  cb->balance = gnc_numeric_add (cb->balance, balance,
3649  gnc_commodity_get_fraction (cb->currency),
3651 }
3652 
3653 
3654 
3655 /*
3656  * Common function that iterates recursively over all accounts below
3657  * the specified account. It uses xaccAccountBalanceHelper to sum up
3658  * the balances of all its children, and uses the specified function
3659  * 'fn' for extracting the balance. This function may extract the
3660  * current value, the reconciled value, etc.
3661  *
3662  * If 'report_commodity' is nullptr, just use the account's commodity.
3663  * If 'include_children' is FALSE, this function doesn't recurse at all.
3664  */
3665 static gnc_numeric
3666 xaccAccountGetXxxBalanceInCurrencyRecursive (const Account *acc,
3667  xaccGetBalanceFn fn,
3668  const gnc_commodity *report_commodity,
3669  gboolean include_children)
3670 {
3671  gnc_numeric balance;
3672 
3673  if (!acc) return gnc_numeric_zero ();
3674  if (!report_commodity)
3675  report_commodity = xaccAccountGetCommodity (acc);
3676  if (!report_commodity)
3677  return gnc_numeric_zero();
3678 
3679  balance = xaccAccountGetXxxBalanceInCurrency (acc, fn, report_commodity);
3680 
3681  /* If needed, sum up the children converting to the *requested*
3682  commodity. */
3683  if (include_children)
3684  {
3685 #ifdef _MSC_VER
3686  /* MSVC compiler: Somehow, the struct initialization containing a
3687  gnc_numeric doesn't work. As an exception, we hand-initialize
3688  that member afterwards. */
3689  CurrencyBalance cb = { report_commodity, { 0 }, fn, nullptr, 0 };
3690  cb.balance = balance;
3691 #else
3692  CurrencyBalance cb = { report_commodity, balance, fn, nullptr, 0 };
3693 #endif
3694 
3695  gnc_account_foreach_descendant (acc, xaccAccountBalanceHelper, &cb);
3696  balance = cb.balance;
3697  }
3698 
3699  return balance;
3700 }
3701 
3702 static gnc_numeric
3703 xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3704  Account *acc, time64 date, xaccGetBalanceAsOfDateFn fn,
3705  const gnc_commodity *report_commodity, gboolean include_children)
3706 {
3707  gnc_numeric balance;
3708 
3709  g_return_val_if_fail(acc, gnc_numeric_zero());
3710  if (!report_commodity)
3711  report_commodity = xaccAccountGetCommodity (acc);
3712  if (!report_commodity)
3713  return gnc_numeric_zero();
3714 
3715  balance = xaccAccountGetXxxBalanceAsOfDateInCurrency(
3716  acc, date, fn, report_commodity);
3717 
3718  /* If needed, sum up the children converting to the *requested*
3719  commodity. */
3720  if (include_children)
3721  {
3722 #ifdef _MSC_VER
3723  /* MSVC compiler: Somehow, the struct initialization containing a
3724  gnc_numeric doesn't work. As an exception, we hand-initialize
3725  that member afterwards. */
3726  CurrencyBalance cb = { report_commodity, 0, nullptr, fn, date };
3727  cb.balance = balance;
3728 #else
3729  CurrencyBalance cb = { report_commodity, balance, nullptr, fn, date };
3730 #endif
3731 
3732  gnc_account_foreach_descendant (acc, xaccAccountBalanceAsOfDateHelper, &cb);
3733  balance = cb.balance;
3734  }
3735 
3736  return balance;
3737 }
3738 
3739 gnc_numeric
3740 xaccAccountGetBalanceInCurrency (const Account *acc,
3741  const gnc_commodity *report_commodity,
3742  gboolean include_children)
3743 {
3744  gnc_numeric rc;
3745  rc = xaccAccountGetXxxBalanceInCurrencyRecursive (
3746  acc, xaccAccountGetBalance, report_commodity, include_children);
3747  PINFO(" baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, rc.num, rc.denom);
3748  return rc;
3749 }
3750 
3751 
3752 gnc_numeric
3753 xaccAccountGetClearedBalanceInCurrency (const Account *acc,
3754  const gnc_commodity *report_commodity,
3755  gboolean include_children)
3756 {
3757  return xaccAccountGetXxxBalanceInCurrencyRecursive (
3758  acc, xaccAccountGetClearedBalance, report_commodity,
3759  include_children);
3760 }
3761 
3762 gnc_numeric
3763 xaccAccountGetReconciledBalanceInCurrency (const Account *acc,
3764  const gnc_commodity *report_commodity,
3765  gboolean include_children)
3766 {
3767  return xaccAccountGetXxxBalanceInCurrencyRecursive (
3768  acc, xaccAccountGetReconciledBalance, report_commodity,
3769  include_children);
3770 }
3771 
3772 gnc_numeric
3773 xaccAccountGetPresentBalanceInCurrency (const Account *acc,
3774  const gnc_commodity *report_commodity,
3775  gboolean include_children)
3776 {
3777  return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3779  report_commodity,
3780  include_children);
3781 }
3782 
3783 gnc_numeric
3784 xaccAccountGetProjectedMinimumBalanceInCurrency (
3785  const Account *acc,
3786  const gnc_commodity *report_commodity,
3787  gboolean include_children)
3788 {
3789  return xaccAccountGetXxxBalanceInCurrencyRecursive (
3790  acc, xaccAccountGetProjectedMinimumBalance, report_commodity,
3791  include_children);
3792 }
3793 
3794 gnc_numeric
3796  Account *acc, time64 date, gnc_commodity *report_commodity,
3797  gboolean include_children)
3798 {
3799  return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3800  acc, date, xaccAccountGetBalanceAsOfDate, report_commodity,
3801  include_children);
3802 }
3803 
3804 gnc_numeric
3806  Account *acc, time64 date, gnc_commodity *report_commodity,
3807  gboolean include_children)
3808 {
3809  return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive
3810  (acc, date, xaccAccountGetNoclosingBalanceAsOfDate,
3811  report_commodity, include_children);
3812 }
3813 
3814 gnc_numeric
3815 xaccAccountGetBalanceChangeForPeriod (Account *acc, time64 t1, time64 t2,
3816  gboolean recurse)
3817 {
3818  gnc_numeric b1, b2;
3819 
3820  b1 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t1, nullptr, recurse);
3821  b2 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t2, nullptr, recurse);
3823 }
3824 
3825 gnc_numeric
3826 xaccAccountGetNoclosingBalanceChangeForPeriod (Account *acc, time64 t1,
3827  time64 t2, gboolean recurse)
3828 {
3829  gnc_numeric b1, b2;
3830 
3831  b1 = xaccAccountGetNoclosingBalanceAsOfDateInCurrency(acc, t1, nullptr, recurse);
3832  b2 = xaccAccountGetNoclosingBalanceAsOfDateInCurrency(acc, t2, nullptr, recurse);
3834 }
3835 
3836 typedef struct
3837 {
3838  const gnc_commodity *currency;
3839  gnc_numeric balanceChange;
3840  time64 t1;
3841  time64 t2;
3843 
3844 static void
3845 xaccAccountBalanceChangeHelper (Account *acc, gpointer data)
3846 {
3847  CurrencyBalanceChange *cbdiff = static_cast<CurrencyBalanceChange*>(data);
3848 
3849  gnc_numeric b1, b2;
3850  b1 = GetBalanceAsOfDate(acc, cbdiff->t1, xaccSplitGetNoclosingBalance);
3851  b2 = GetBalanceAsOfDate(acc, cbdiff->t2, xaccSplitGetNoclosingBalance);
3852  gnc_numeric balanceChange = gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
3853  gnc_numeric balanceChange_conv = xaccAccountConvertBalanceToCurrencyAsOfDate(acc, balanceChange, xaccAccountGetCommodity(acc), cbdiff->currency, cbdiff->t2);
3854  cbdiff->balanceChange = gnc_numeric_add (cbdiff->balanceChange, balanceChange_conv,
3855  gnc_commodity_get_fraction (cbdiff->currency),
3857 }
3858 
3859 gnc_numeric
3860 xaccAccountGetNoclosingBalanceChangeInCurrencyForPeriod (Account *acc, time64 t1,
3861  time64 t2, gboolean recurse)
3862 {
3863 
3864 
3865  gnc_numeric b1, b2;
3866  b1 = GetBalanceAsOfDate(acc, t1, xaccSplitGetNoclosingBalance);
3867  b2 = GetBalanceAsOfDate(acc, t2, xaccSplitGetNoclosingBalance);
3868  gnc_numeric balanceChange = gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
3869 
3870  gnc_commodity *report_commodity = xaccAccountGetCommodity(acc);
3871  CurrencyBalanceChange cbdiff = { report_commodity, balanceChange, t1, t2 };
3872 
3873  if(recurse)
3874  {
3875  gnc_account_foreach_descendant (acc, xaccAccountBalanceChangeHelper, &cbdiff);
3876  balanceChange = cbdiff.balanceChange;
3877  }
3878  return balanceChange;
3879 }
3880 
3881 /********************************************************************\
3882 \********************************************************************/
3883 
3884 const SplitsVec&
3885 xaccAccountGetSplits (const Account *account)
3886 {
3887  static const SplitsVec empty;
3888  g_return_val_if_fail (GNC_IS_ACCOUNT(account), empty);
3889  return GET_PRIVATE(account)->splits;
3890 }
3891 
3892 SplitList *
3894 {
3895  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3896  auto priv{GET_PRIVATE(acc)};
3897  return std::accumulate (priv->splits.rbegin(), priv->splits.rend(),
3898  static_cast<GList*>(nullptr), g_list_prepend);
3899 }
3900 
3901 size_t
3902 xaccAccountGetSplitsSize (const Account *account)
3903 {
3904  g_return_val_if_fail (GNC_IS_ACCOUNT(account), 0);
3905  return GNC_IS_ACCOUNT(account) ? GET_PRIVATE(account)->splits.size() : 0;
3906 }
3907 
3908 gboolean gnc_account_and_descendants_empty (Account *acc)
3909 {
3910  g_return_val_if_fail (GNC_IS_ACCOUNT (acc), FALSE);
3911  auto priv = GET_PRIVATE (acc);
3912  if (!priv->splits.empty()) return FALSE;
3913  return std::all_of (priv->children.begin(), priv->children.end(),
3914  gnc_account_and_descendants_empty);
3915 }
3916 
3917 LotList *
3919 {
3920  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3921  return g_list_copy(GET_PRIVATE(acc)->lots);
3922 }
3923 
3924 LotList *
3926  gboolean (*match_func)(GNCLot *lot,
3927  gpointer user_data),
3928  gpointer user_data, GCompareFunc sort_func)
3929 {
3930  AccountPrivate *priv;
3931  GList *lot_list;
3932  GList *retval = nullptr;
3933 
3934  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3935 
3936  priv = GET_PRIVATE(acc);
3937  for (lot_list = priv->lots; lot_list; lot_list = lot_list->next)
3938  {
3939  GNCLot *lot = static_cast<GNCLot*>(lot_list->data);
3940 
3941  /* If this lot is closed, then ignore it */
3942  if (gnc_lot_is_closed (lot))
3943  continue;
3944 
3945  if (match_func && !(match_func)(lot, user_data))
3946  continue;
3947 
3948  /* Ok, this is a valid lot. Add it to our list of lots */
3949  retval = g_list_prepend (retval, lot);
3950  }
3951 
3952  if (sort_func)
3953  retval = g_list_sort (retval, sort_func);
3954 
3955  return retval;
3956 }
3957 
3958 gpointer
3959 xaccAccountForEachLot(const Account *acc,
3960  gpointer (*proc)(GNCLot *lot, void *data), void *data)
3961 {
3962  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3963  g_return_val_if_fail(proc, nullptr);
3964 
3965  for (auto node = GET_PRIVATE(acc)->lots; node; node = node->next)
3966  if (auto result = proc(GNC_LOT(node->data), data))
3967  return result;
3968 
3969  return nullptr;
3970 }
3971 
3972 
3973 /********************************************************************\
3974 \********************************************************************/
3975 
3976 /* These functions use interchange gint64 and gboolean. Is that right? */
3977 gboolean
3979 {
3980  return get_kvp_boolean_path(acc, {"tax-related"});
3981 }
3982 
3983 void
3984 xaccAccountSetTaxRelated (Account *acc, gboolean tax_related)
3985 {
3986  set_kvp_boolean_path(acc, {"tax-related"}, tax_related);
3987 }
3988 
3989 const char *
3991 {
3992  return get_kvp_string_path (acc, {"tax-US", "code"});
3993 }
3994 
3995 void
3996 xaccAccountSetTaxUSCode (Account *acc, const char *code)
3997 {
3998  set_kvp_string_path (acc, {"tax-US", "code"}, code);
3999 }
4000 
4001 const char *
4003 {
4004  return get_kvp_string_path (acc, {"tax-US", "payer-name-source"});
4005 }
4006 
4007 void
4009 {
4010  set_kvp_string_path (acc, {"tax-US", "payer-name-source"}, source);
4011 }
4012 
4013 gint64
4015 {
4016  auto copy_number = get_kvp_int64_path (acc, {"tax-US", "copy-number"});
4017  return copy_number ? *copy_number : 1;
4018 }
4019 
4020 void
4021 xaccAccountSetTaxUSCopyNumber (Account *acc, gint64 copy_number)
4022 {
4023  set_kvp_int64_path (acc, {"tax-US", "copy-number"}, copy_number);
4024 }
4025 
4026 /*********************************************************************\
4027 \ ********************************************************************/
4028 
4029 
4031 {
4032  if (gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS))
4033  return _(dflt_acct_debit_str);
4034 
4035  auto result = gnc_acct_debit_strs.find(acct_type);
4036  if (result != gnc_acct_debit_strs.end())
4037  return _(result->second);
4038  else
4039  return _(dflt_acct_debit_str);
4040 }
4041 
4043 {
4044  if (gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS))
4045  return _(dflt_acct_credit_str);
4046 
4047  auto result = gnc_acct_credit_strs.find(acct_type);
4048  if (result != gnc_acct_credit_strs.end())
4049  return _(result->second);
4050  else
4051  return _(dflt_acct_credit_str);
4052 }
4053 
4054 /********************************************************************\
4055 \********************************************************************/
4056 
4057 gboolean
4059 {
4060  return get_kvp_boolean_path(acc, {"placeholder"});
4061 }
4062 
4063 void
4065 {
4066  set_kvp_boolean_path(acc, {"placeholder"}, val);
4067 }
4068 
4069 gboolean
4071 {
4072  return get_kvp_boolean_path(acc, {"import-append-text"});
4073 }
4074 
4075 void
4076 xaccAccountSetAppendText (Account *acc, gboolean val)
4077 {
4078  set_kvp_boolean_path(acc, {"import-append-text"}, val);
4079 }
4080 
4081 gboolean
4083 {
4084  g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false);
4085  if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
4086  return false;
4087 
4088  return !g_strcmp0 (get_kvp_string_path (acc, {"equity-type"}), "opening-balance");
4089 }
4090 
4091 void
4093 {
4094  g_return_if_fail (GNC_IS_ACCOUNT(acc));
4095  if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
4096  return;
4097  set_kvp_string_path(acc, {"equity-type"}, val ? "opening-balance" : nullptr);
4098 }
4099 
4102 {
4103  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), PLACEHOLDER_NONE);
4104  if (xaccAccountGetPlaceholder(acc)) return PLACEHOLDER_THIS;
4105 
4106  return gnc_account_foreach_descendant_until (acc, (AccountCb2)xaccAccountGetPlaceholder, nullptr)
4107  ? PLACEHOLDER_CHILD : PLACEHOLDER_NONE;
4108 }
4109 
4110 /********************************************************************\
4111  \********************************************************************/
4112 
4113 gboolean
4115 {
4116  return get_kvp_boolean_path (acc, {KEY_RECONCILE_INFO, "auto-interest-transfer"});
4117 }
4118 
4119 void
4121 {
4122  set_kvp_boolean_path (acc, {KEY_RECONCILE_INFO, "auto-interest-transfer"}, val);
4123 }
4124 
4125 /********************************************************************\
4126 \********************************************************************/
4127 
4128 gboolean
4130 {
4131  return get_kvp_boolean_path (acc, {"hidden"});
4132 }
4133 
4134 void
4135 xaccAccountSetHidden (Account *acc, gboolean val)
4136 {
4137  set_kvp_boolean_path (acc, {"hidden"}, val);
4138 }
4139 
4140 gboolean
4142 {
4143  AccountPrivate *priv;
4144 
4145  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4146 
4147  if (xaccAccountGetHidden(acc))
4148  return TRUE;
4149  priv = GET_PRIVATE(acc);
4150  while ((acc = priv->parent) != nullptr)
4151  {
4152  priv = GET_PRIVATE(acc);
4153  if (xaccAccountGetHidden(acc))
4154  return TRUE;
4155  }
4156  return FALSE;
4157 }
4158 
4159 /********************************************************************\
4160 \********************************************************************/
4161 
4162 gboolean
4163 xaccAccountHasAncestor (const Account *acc, const Account * ancestor)
4164 {
4165  const Account *parent;
4166 
4167  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4168  g_return_val_if_fail(GNC_IS_ACCOUNT(ancestor), FALSE);
4169 
4170  parent = acc;
4171  while (parent && parent != ancestor)
4172  parent = GET_PRIVATE(parent)->parent;
4173 
4174  return (parent == ancestor);
4175 }
4176 
4177 /********************************************************************\
4178 \********************************************************************/
4179 
4180 /* You must edit the functions in this block in tandem. KEEP THEM IN
4181  SYNC! */
4182 
4183 #define GNC_RETURN_ENUM_AS_STRING(x) case (ACCT_TYPE_ ## x): return #x;
4184 
4185 const char *
4187 {
4188  switch (type)
4189  {
4190  GNC_RETURN_ENUM_AS_STRING(NONE);
4191  GNC_RETURN_ENUM_AS_STRING(BANK);
4192  GNC_RETURN_ENUM_AS_STRING(CASH);
4193  GNC_RETURN_ENUM_AS_STRING(CREDIT);
4194  GNC_RETURN_ENUM_AS_STRING(ASSET);
4195  GNC_RETURN_ENUM_AS_STRING(LIABILITY);
4196  GNC_RETURN_ENUM_AS_STRING(STOCK);
4197  GNC_RETURN_ENUM_AS_STRING(MUTUAL);
4198  GNC_RETURN_ENUM_AS_STRING(CURRENCY);
4199  GNC_RETURN_ENUM_AS_STRING(INCOME);
4200  GNC_RETURN_ENUM_AS_STRING(EXPENSE);
4201  GNC_RETURN_ENUM_AS_STRING(EQUITY);
4202  GNC_RETURN_ENUM_AS_STRING(RECEIVABLE);
4203  GNC_RETURN_ENUM_AS_STRING(PAYABLE);
4204  GNC_RETURN_ENUM_AS_STRING(ROOT);
4205  GNC_RETURN_ENUM_AS_STRING(TRADING);
4206  GNC_RETURN_ENUM_AS_STRING(CHECKING);
4207  GNC_RETURN_ENUM_AS_STRING(SAVINGS);
4208  GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
4209  GNC_RETURN_ENUM_AS_STRING(CREDITLINE);
4210  default:
4211  PERR ("asked to translate unknown account type %d.\n", type);
4212  break;
4213  }
4214  return(nullptr);
4215 }
4216 
4217 #undef GNC_RETURN_ENUM_AS_STRING
4218 
4219 #define GNC_RETURN_ON_MATCH(x) \
4220  if(g_strcmp0(#x, (str)) == 0) { *type = ACCT_TYPE_ ## x; return(TRUE); }
4221 
4222 gboolean
4224 {
4225 
4226  GNC_RETURN_ON_MATCH(NONE);
4227  GNC_RETURN_ON_MATCH(BANK);
4228  GNC_RETURN_ON_MATCH(CASH);
4229  GNC_RETURN_ON_MATCH(CREDIT);
4230  GNC_RETURN_ON_MATCH(ASSET);
4231  GNC_RETURN_ON_MATCH(LIABILITY);
4232  GNC_RETURN_ON_MATCH(STOCK);
4233  GNC_RETURN_ON_MATCH(MUTUAL);
4234  GNC_RETURN_ON_MATCH(CURRENCY);
4235  GNC_RETURN_ON_MATCH(INCOME);
4236  GNC_RETURN_ON_MATCH(EXPENSE);
4237  GNC_RETURN_ON_MATCH(EQUITY);
4238  GNC_RETURN_ON_MATCH(RECEIVABLE);
4239  GNC_RETURN_ON_MATCH(PAYABLE);
4240  GNC_RETURN_ON_MATCH(ROOT);
4241  GNC_RETURN_ON_MATCH(TRADING);
4242  GNC_RETURN_ON_MATCH(CHECKING);
4243  GNC_RETURN_ON_MATCH(SAVINGS);
4244  GNC_RETURN_ON_MATCH(MONEYMRKT);
4245  GNC_RETURN_ON_MATCH(CREDITLINE);
4246 
4247  PERR("asked to translate unknown account type string %s.\n",
4248  str ? str : "(null)");
4249 
4250  return(FALSE);
4251 }
4252 
4253 #undef GNC_RETURN_ON_MATCH
4254 
4255 /* impedance mismatch is a source of loss */
4257 xaccAccountStringToEnum(const char* str)
4258 {
4259  GNCAccountType type;
4260  gboolean rc;
4261  rc = xaccAccountStringToType(str, &type);
4262  if (FALSE == rc) return ACCT_TYPE_INVALID;
4263  return type;
4264 }
4265 
4266 /********************************************************************\
4267 \********************************************************************/
4268 
4269 static char const *
4270 account_type_name[NUM_ACCOUNT_TYPES] =
4271 {
4272  N_("Bank"),
4273  N_("Cash"),
4274  N_("Asset"),
4275  N_("Credit Card"),
4276  N_("Liability"),
4277  N_("Stock"),
4278  N_("Mutual Fund"),
4279  N_("Currency"),
4280  N_("Income"),
4281  N_("Expense"),
4282  N_("Equity"),
4283  N_("A/Receivable"),
4284  N_("A/Payable"),
4285  N_("Root"),
4286  N_("Trading")
4287  /*
4288  N_("Checking"),
4289  N_("Savings"),
4290  N_("Money Market"),
4291  N_("Credit Line")
4292  */
4293 };
4294 
4295 const char *
4297 {
4298  if (type < 0 || NUM_ACCOUNT_TYPES <= type ) return "";
4299  return _(account_type_name [type]);
4300 }
4301 
4302 /********************************************************************\
4303 \********************************************************************/
4304 
4305 guint32
4307 {
4308  switch (type)
4309  {
4310  case ACCT_TYPE_BANK:
4311  case ACCT_TYPE_CASH:
4312  case ACCT_TYPE_ASSET:
4313  case ACCT_TYPE_CREDIT:
4314  case ACCT_TYPE_LIABILITY:
4315  case ACCT_TYPE_INCOME:
4316  case ACCT_TYPE_EXPENSE:
4317  case ACCT_TYPE_EQUITY:
4318  return
4319  (1 << ACCT_TYPE_BANK) |
4320  (1 << ACCT_TYPE_CASH) |
4321  (1 << ACCT_TYPE_ASSET) |
4322  (1 << ACCT_TYPE_CREDIT) |
4323  (1 << ACCT_TYPE_LIABILITY) |
4324  (1 << ACCT_TYPE_INCOME) |
4325  (1 << ACCT_TYPE_EXPENSE) |
4326  (1 << ACCT_TYPE_EQUITY);
4327  case ACCT_TYPE_STOCK:
4328  case ACCT_TYPE_MUTUAL:
4329  case ACCT_TYPE_CURRENCY:
4330  return
4331  (1 << ACCT_TYPE_STOCK) |
4332  (1 << ACCT_TYPE_MUTUAL) |
4333  (1 << ACCT_TYPE_CURRENCY);
4334  case ACCT_TYPE_RECEIVABLE:
4335  return (1 << ACCT_TYPE_RECEIVABLE);
4336  case ACCT_TYPE_PAYABLE:
4337  return (1 << ACCT_TYPE_PAYABLE);
4338  case ACCT_TYPE_TRADING:
4339  return (1 << ACCT_TYPE_TRADING);
4340  default:
4341  PERR("bad account type: %d", type);
4342  return 0;
4343  }
4344 }
4345 guint32
4347 {
4348  switch (type)
4349  {
4350  case ACCT_TYPE_BANK:
4351  case ACCT_TYPE_CASH:
4352  case ACCT_TYPE_ASSET:
4353  case ACCT_TYPE_STOCK:
4354  case ACCT_TYPE_MUTUAL:
4355  case ACCT_TYPE_CURRENCY:
4356  case ACCT_TYPE_CREDIT:
4357  case ACCT_TYPE_LIABILITY:
4358  case ACCT_TYPE_RECEIVABLE:
4359  case ACCT_TYPE_PAYABLE:
4360  return
4361  (1 << ACCT_TYPE_BANK) |
4362  (1 << ACCT_TYPE_CASH) |
4363  (1 << ACCT_TYPE_ASSET) |
4364  (1 << ACCT_TYPE_STOCK) |
4365  (1 << ACCT_TYPE_MUTUAL) |
4366  (1 << ACCT_TYPE_CURRENCY) |
4367  (1 << ACCT_TYPE_CREDIT) |
4368  (1 << ACCT_TYPE_LIABILITY) |
4369  (1 << ACCT_TYPE_RECEIVABLE) |
4370  (1 << ACCT_TYPE_PAYABLE) |
4371  (1 << ACCT_TYPE_ROOT);
4372  case ACCT_TYPE_INCOME:
4373  case ACCT_TYPE_EXPENSE:
4374  return
4375  (1 << ACCT_TYPE_INCOME) |
4376  (1 << ACCT_TYPE_EXPENSE) |
4377  (1 << ACCT_TYPE_ROOT);
4378  case ACCT_TYPE_EQUITY:
4379  return
4380  (1 << ACCT_TYPE_EQUITY) |
4381  (1 << ACCT_TYPE_ROOT);
4382  case ACCT_TYPE_TRADING:
4383  return
4384  (1 << ACCT_TYPE_TRADING) |
4385  (1 << ACCT_TYPE_ROOT);
4386  default:
4387  PERR("bad account type: %d", type);
4388  return 0;
4389  }
4390 }
4391 
4392 gboolean
4394  GNCAccountType child_type)
4395 {
4396  /* ACCT_TYPE_NONE isn't compatible with anything, even ACCT_TYPE_NONE. */
4397  if (parent_type == ACCT_TYPE_NONE || child_type == ACCT_TYPE_NONE)
4398  return FALSE;
4399 
4400  /* ACCT_TYPE_ROOT can't have a parent account, and asking will raise
4401  * an error. */
4402  if (child_type == ACCT_TYPE_ROOT)
4403  return FALSE;
4404 
4405  return ((xaccParentAccountTypesCompatibleWith (child_type) &
4406  (1 << parent_type))
4407  != 0);
4408 }
4409 
4410 guint32
4412 {
4413  guint32 mask = (1 << NUM_ACCOUNT_TYPES) - 1;
4414  mask &= ~((1 << ACCT_TYPE_CURRENCY) | /* DEPRECATED */
4415  (1 << ACCT_TYPE_ROOT)); /* ROOT */
4416 
4417  return mask;
4418 }
4419 
4421 {
4422  switch (t)
4423  {
4424  case ACCT_TYPE_RECEIVABLE:
4425  case ACCT_TYPE_PAYABLE:
4426  return FALSE;
4427  default:
4430  }
4431 }
4432 
4435 {
4436  switch (t)
4437  {
4438  case ACCT_TYPE_BANK:
4439  case ACCT_TYPE_STOCK:
4440  case ACCT_TYPE_MONEYMRKT:
4441  case ACCT_TYPE_CHECKING:
4442  case ACCT_TYPE_SAVINGS:
4443  case ACCT_TYPE_MUTUAL:
4444  case ACCT_TYPE_CURRENCY:
4445  case ACCT_TYPE_CASH:
4446  case ACCT_TYPE_ASSET:
4447  case ACCT_TYPE_RECEIVABLE:
4448  return ACCT_TYPE_ASSET;
4449  case ACCT_TYPE_CREDIT:
4450  case ACCT_TYPE_LIABILITY:
4451  case ACCT_TYPE_PAYABLE:
4452  case ACCT_TYPE_CREDITLINE:
4453  return ACCT_TYPE_LIABILITY;
4454  case ACCT_TYPE_INCOME:
4455  return ACCT_TYPE_INCOME;
4456  case ACCT_TYPE_EXPENSE:
4457  return ACCT_TYPE_EXPENSE;
4458  case ACCT_TYPE_EQUITY:
4459  return ACCT_TYPE_EQUITY;
4460  case ACCT_TYPE_TRADING:
4461  default:
4462  return ACCT_TYPE_NONE;
4463  }
4464 }
4465 
4467 {
4468  switch (t)
4469  {
4470  case ACCT_TYPE_RECEIVABLE:
4471  case ACCT_TYPE_PAYABLE:
4472  return TRUE;
4473  default:
4474  return FALSE;
4475  }
4476 }
4477 
4479 {
4480  switch (t)
4481  {
4482  case ACCT_TYPE_EQUITY:
4483  return TRUE;
4484  default:
4485  return FALSE;
4486  }
4487 }
4488 
4489 gboolean
4491 {
4492  AccountPrivate *priv;
4493 
4494  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4495 
4496  priv = GET_PRIVATE(acc);
4497  return (priv->type == ACCT_TYPE_STOCK || priv->type == ACCT_TYPE_MUTUAL ||
4498  priv->type == ACCT_TYPE_CURRENCY);
4499 }
4500 
4501 /********************************************************************\
4502 \********************************************************************/
4503 
4504 gboolean
4506 {
4507  gboolean retval = FALSE;
4508  auto date = get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-date"});
4509 
4510  if (date)
4511  {
4512  if (last_date)
4513  *last_date = *date;
4514  retval = TRUE;
4515  }
4516  return retval;
4517 }
4518 
4519 /********************************************************************\
4520 \********************************************************************/
4521 
4522 void
4524 {
4525  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-date"}, last_date);
4526 }
4527 
4528 /********************************************************************\
4529 \********************************************************************/
4530 
4531 gboolean
4533  int *months, int *days)
4534 {
4535  if (!acc) return FALSE;
4536  auto m{get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "months"})};
4537  auto d{get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "days"})};
4538  if (m && d)
4539  {
4540  if (months)
4541  *months = *m;
4542  if (days)
4543  *days = *d;
4544  return true;
4545  }
4546  return false;
4547 }
4548 
4549 /********************************************************************\
4550 \********************************************************************/
4551 
4552 void
4553 xaccAccountSetReconcileLastInterval (Account *acc, int months, int days)
4554 {
4555  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "months"}, months);
4556  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "days"}, days);
4557 }
4558 
4559 /********************************************************************\
4560 \********************************************************************/
4561 
4562 gboolean
4564 {
4565  if (auto date = get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "date"}))
4566  {
4567  if (postpone_date)
4568  *postpone_date = *date;
4569  return true;
4570  }
4571  return false;
4572 }
4573 
4574 /********************************************************************\
4575 \********************************************************************/
4576 
4577 void
4579 {
4580  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "date"}, postpone_date);
4581 }
4582 
4583 /********************************************************************\
4584 \********************************************************************/
4585 
4586 gboolean
4588  gnc_numeric *balance)
4589 {
4590  if (auto bal = get_kvp_gnc_numeric_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"}))
4591  {
4592  if (balance)
4593  *balance = *bal;
4594  return true;
4595  }
4596  return false;
4597 }
4598 
4599 /********************************************************************\
4600 \********************************************************************/
4601 
4602 void
4604 {
4605  set_kvp_gnc_numeric_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"}, balance);
4606 }
4607 
4608 /********************************************************************\
4609 
4610 \********************************************************************/
4611 
4612 void
4614 {
4615  set_kvp_gnc_numeric_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"}, {});
4616 }
4617 
4618 /********************************************************************\
4619 \********************************************************************/
4620 
4621 const char *
4623 {
4624  return get_kvp_string_path (acc, {"last-num"});
4625 }
4626 
4627 /********************************************************************\
4628 \********************************************************************/
4629 
4630 void
4631 xaccAccountSetLastNum (Account *acc, const char *num)
4632 {
4633  set_kvp_string_path (acc, {"last-num"}, num);
4634 }
4635 
4636 
4637 /********************************************************************\
4638 \********************************************************************/
4639 
4640 static bool
4641 get_balance_limit (const Account* acc, const std::string& key, gnc_numeric* balance)
4642 {
4643  auto limit = get_kvp_gnc_numeric_path (acc, {KEY_BALANCE_LIMIT, key});
4644  if (limit)
4645  *balance = gnc_numeric_create (limit->num, limit->denom);
4646  return limit.has_value();
4647 }
4648 
4649 static void
4650 set_balance_limit (Account *acc, const std::string& key, std::optional<gnc_numeric> balance)
4651 {
4652  if (balance && gnc_numeric_check (*balance))
4653  return;
4654  set_kvp_gnc_numeric_path (acc, {KEY_BALANCE_LIMIT, key}, balance);
4655 }
4656 
4657 gboolean
4659  gnc_numeric *balance)
4660 {
4661  return get_balance_limit (acc, KEY_BALANCE_HIGHER_LIMIT_VALUE, balance);
4662 }
4663 
4664 gboolean
4666  gnc_numeric *balance)
4667 {
4668  return get_balance_limit (acc, KEY_BALANCE_LOWER_LIMIT_VALUE, balance);
4669 }
4670 
4671 void
4672 xaccAccountSetHigherBalanceLimit (Account *acc, gnc_numeric balance)
4673 {
4674  set_balance_limit (acc, KEY_BALANCE_HIGHER_LIMIT_VALUE, balance);
4675 }
4676 
4677 void
4678 xaccAccountSetLowerBalanceLimit (Account *acc, gnc_numeric balance)
4679 {
4680  set_balance_limit (acc, KEY_BALANCE_LOWER_LIMIT_VALUE, balance);
4681 }
4682 
4683 void
4685 {
4686  set_balance_limit (acc, KEY_BALANCE_HIGHER_LIMIT_VALUE, {});
4687 }
4688 
4689 void
4691 {
4692  set_balance_limit (acc, KEY_BALANCE_LOWER_LIMIT_VALUE, {});
4693 }
4694 
4695 gboolean
4697 {
4698  return get_kvp_boolean_path (acc, {KEY_BALANCE_LIMIT, KEY_BALANCE_INCLUDE_SUB_ACCTS});
4699 }
4700 
4701 void
4703 {
4704  set_kvp_boolean_path (acc, {KEY_BALANCE_LIMIT, KEY_BALANCE_INCLUDE_SUB_ACCTS}, inc_sub);
4705 }
4706 
4707 /********************************************************************\
4708 \********************************************************************/
4709 
4710 static Account *
4711 GetOrMakeOrphanAccount (Account *root, gnc_commodity * currency)
4712 {
4713  char * accname;
4714  Account * acc;
4715 
4716  g_return_val_if_fail (root, nullptr);
4717 
4718  /* build the account name */
4719  if (!currency)
4720  {
4721  PERR ("No currency specified!");
4722  return nullptr;
4723  }
4724 
4725  accname = g_strconcat (_("Orphaned Gains"), "-",
4726  gnc_commodity_get_mnemonic (currency), nullptr);
4727 
4728  /* See if we've got one of these going already ... */
4729  acc = gnc_account_lookup_by_name(root, accname);
4730 
4731  if (acc == nullptr)
4732  {
4733  /* Guess not. We'll have to build one. */
4734  acc = xaccMallocAccount (gnc_account_get_book(root));
4735  xaccAccountBeginEdit (acc);
4736  xaccAccountSetName (acc, accname);
4737  xaccAccountSetCommodity (acc, currency);
4739  xaccAccountSetDescription (acc, _("Realized Gain/Loss"));
4740  xaccAccountSetNotes (acc,
4741  _("Realized Gains or Losses from "
4742  "Commodity or Trading Accounts "
4743  "that haven't been recorded elsewhere."));
4744 
4745  /* Hang the account off the root. */
4746  gnc_account_append_child (root, acc);
4747  xaccAccountCommitEdit (acc);
4748  }
4749 
4750  g_free (accname);
4751 
4752  return acc;
4753 }
4754 
4755 Account *
4756 xaccAccountGainsAccount (Account *acc, gnc_commodity *curr)
4757 {
4758  Path path {KEY_LOT_MGMT, "gains-acct", gnc_commodity_get_unique_name (curr)};
4759  auto gains_account = get_kvp_account_path (acc, path);
4760 
4761  if (gains_account == nullptr) /* No gains account for this currency */
4762  {
4763  gains_account = GetOrMakeOrphanAccount (gnc_account_get_root (acc), curr);
4764  set_kvp_account_path (acc, path, gains_account);
4765  }
4766 
4767  return gains_account;
4768 }
4769 
4770 /********************************************************************\
4771 \********************************************************************/
4772 
4773 void
4774 dxaccAccountSetPriceSrc(Account *acc, const char *src)
4775 {
4776  if (!acc) return;
4777 
4778  if (xaccAccountIsPriced(acc))
4779  set_kvp_string_path (acc, {"old-price-source"}, src);
4780 }
4781 
4782 /********************************************************************\
4783 \********************************************************************/
4784 
4785 const char*
4787 {
4788  static char *source = nullptr;
4789  if (!acc) return nullptr;
4790 
4791  if (!xaccAccountIsPriced(acc)) return nullptr;
4792 
4793  g_free (source);
4794 
4795  return get_kvp_string_path (acc, {"old-price-source"});
4796 }
4797 
4798 /********************************************************************\
4799 \********************************************************************/
4800 
4801 void
4802 dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
4803 {
4804  if (!acc) return;
4805  if (!xaccAccountIsPriced(acc)) return;
4806  set_kvp_string_path (acc, {"old-quote-tz"}, tz);
4807 }
4808 
4809 /********************************************************************\
4810 \********************************************************************/
4811 
4812 const char*
4814 {
4815  if (!acc) return nullptr;
4816  if (!xaccAccountIsPriced(acc)) return nullptr;
4817  return get_kvp_string_path (acc, {"old-quote-tz"});
4818 }
4819 
4820 /********************************************************************\
4821 \********************************************************************/
4822 
4823 void
4825 {
4826  /* Would have been nice to use G_TYPE_BOOLEAN, but the other
4827  * boolean kvps save the value as "true" or "false" and that would
4828  * be file-incompatible with this.
4829  */
4830  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, KEY_INCLUDE_CHILDREN}, status);
4831 }
4832 
4833 /********************************************************************\
4834 \********************************************************************/
4835 
4836 gboolean
4838 {
4839  /* access the account's kvp-data for status and return that, if no value
4840  * is found then we can assume not to include the children, that being
4841  * the default behaviour
4842  */
4843  return get_kvp_boolean_path (acc, {KEY_RECONCILE_INFO, KEY_INCLUDE_CHILDREN});
4844 }
4845 
4846 /********************************************************************\
4847 \********************************************************************/
4848 
4849 Split *
4850 xaccAccountFindSplitByDesc(const Account *acc, const char *description)
4851 {
4852  auto has_description = [description](const Split* s) -> bool
4853  { return !g_strcmp0 (description, xaccTransGetDescription (xaccSplitGetParent (s))); };
4854  return gnc_account_find_split (acc, has_description, true);
4855 }
4856 
4857 /* This routine is for finding a matching transaction in an account by
4858  * matching on the description field. [CAS: The rest of this comment
4859  * seems to belong somewhere else.] This routine is used for
4860  * auto-filling in registers with a default leading account. The
4861  * dest_trans is a transaction used for currency checking. */
4862 Transaction *
4863 xaccAccountFindTransByDesc(const Account *acc, const char *description)
4864 {
4865  auto split = xaccAccountFindSplitByDesc (acc, description);
4866  return split ? xaccSplitGetParent (split) : nullptr;
4867 }
4868 
4869 /* ================================================================ */
4870 /* Concatenation, Merging functions */
4871 
4872 void
4873 gnc_account_join_children (Account *to_parent, Account *from_parent)
4874 {
4875 
4876  /* errors */
4877  g_return_if_fail(GNC_IS_ACCOUNT(to_parent));
4878  g_return_if_fail(GNC_IS_ACCOUNT(from_parent));
4879 
4880  /* optimizations */
4881  auto from_priv = GET_PRIVATE(from_parent);
4882  if (from_priv->children.empty())
4883  return;
4884 
4885  ENTER (" ");
4886  auto children = from_priv->children;
4887  for (auto child : children)
4888  gnc_account_append_child(to_parent, child);
4889  LEAVE (" ");
4890 }
4891 /********************************************************************\
4892 \********************************************************************/
4893 
4894 void
4896 {
4897  g_return_if_fail(GNC_IS_ACCOUNT(parent));
4898 
4899  auto ppriv = GET_PRIVATE(parent);
4900  for (auto it_a = ppriv->children.begin(); it_a != ppriv->children.end(); it_a++)
4901  {
4902  auto acc_a = *it_a;
4903  auto priv_a = GET_PRIVATE(acc_a);
4904  for (auto it_b = std::next(it_a); it_b != ppriv->children.end(); it_b++)
4905  {
4906  auto acc_b = *it_b;
4907  auto priv_b = GET_PRIVATE(acc_b);
4908  if (0 != null_strcmp(priv_a->accountName, priv_b->accountName))
4909  continue;
4910  if (0 != null_strcmp(priv_a->accountCode, priv_b->accountCode))
4911  continue;
4912  if (0 != null_strcmp(priv_a->description, priv_b->description))
4913  continue;
4914  if (0 != null_strcmp(xaccAccountGetColor(acc_a),
4915  xaccAccountGetColor(acc_b)))
4916  continue;
4917  if (!gnc_commodity_equiv(priv_a->commodity, priv_b->commodity))
4918  continue;
4919  if (0 != null_strcmp(xaccAccountGetNotes(acc_a),
4920  xaccAccountGetNotes(acc_b)))
4921  continue;
4922  if (priv_a->type != priv_b->type)
4923  continue;
4924 
4925  /* consolidate children */
4926  if (!priv_b->children.empty())
4927  {
4928  auto work = priv_b->children;
4929  for (auto w : work)
4930  gnc_account_append_child (acc_a, w);
4931 
4932  qof_event_gen (&acc_a->inst, QOF_EVENT_MODIFY, nullptr);
4933  qof_event_gen (&acc_b->inst, QOF_EVENT_MODIFY, nullptr);
4934  }
4935 
4936  /* recurse to do the children's children */
4938 
4939  /* consolidate transactions */
4940  while (!priv_b->splits.empty())
4941  xaccSplitSetAccount (priv_b->splits.front(), acc_a);
4942 
4943  /* move back one before removal. next iteration around the loop
4944  * will get the node after node_b */
4945  it_b--;
4946 
4947  /* The destroy function will remove from list -- node_a is ok,
4948  * it's before node_b */
4949  xaccAccountBeginEdit (acc_b);
4950  xaccAccountDestroy (acc_b);
4951  }
4952  }
4953 }
4954 
4955 /* ================================================================ */
4956 /* Transaction Traversal functions */
4957 
4958 
4959 static void
4960 xaccSplitsBeginStagedTransactionTraversals (SplitsVec& splits)
4961 {
4962  for (auto s : splits)
4963  {
4964  Transaction *trans = s->parent;
4965 
4966  if (trans)
4967  trans->marker = 0;
4968  }
4969 }
4970 
4971 /* original function */
4972 void
4974 {
4975  if (!account)
4976  return;
4977  xaccSplitsBeginStagedTransactionTraversals(GET_PRIVATE (account)->splits);
4978 }
4979 
4980 gboolean
4981 xaccTransactionTraverse (Transaction *trans, int stage)
4982 {
4983  if (trans == nullptr) return FALSE;
4984 
4985  if (trans->marker < stage)
4986  {
4987  trans->marker = stage;
4988  return TRUE;
4989  }
4990 
4991  return FALSE;
4992 }
4993 
4994 /* Replacement for xaccGroupBeginStagedTransactionTraversals */
4995 void
4997 {
4998  auto do_one_account = [](auto acc)
4999  { gnc_account_foreach_split (acc, [](auto s){ s->parent->marker = 0; }, false); };
5000  gnc_account_foreach_descendant (account, do_one_account);
5001 }
5002 
5003 int
5005  unsigned int stage,
5006  TransactionCallback thunk,
5007  void *cb_data)
5008 {
5009  if (!acc) return 0;
5010 
5011  // iterate on copy of splits. some callers modify the splitsvec.
5012  auto splits = GET_PRIVATE(acc)->splits;
5013  for (auto s : splits)
5014  {
5015  auto trans = s->parent;
5016  if (trans && (trans->marker < stage))
5017  {
5018  trans->marker = stage;
5019  if (thunk)
5020  {
5021  auto retval = thunk(trans, cb_data);
5022  if (retval) return retval;
5023  }
5024  }
5025  }
5026 
5027  return 0;
5028 }
5029 
5030 int
5032  unsigned int stage,
5033  TransactionCallback thunk,
5034  void *cb_data)
5035 {
5036  const AccountPrivate *priv;
5037  Transaction *trans;
5038  int retval;
5039 
5040  if (!acc) return 0;
5041 
5042  /* depth first traversal */
5043  priv = GET_PRIVATE(acc);
5044  for (auto acc_p : priv->children)
5045  {
5046  retval = gnc_account_tree_staged_transaction_traversal(acc_p, stage, thunk, cb_data);
5047  if (retval) return retval;
5048  }
5049 
5050  /* Now this account */
5051  for (auto s : priv->splits)
5052  {
5053  trans = s->parent;
5054  if (trans && (trans->marker < stage))
5055  {
5056  trans->marker = stage;
5057  if (thunk)
5058  {
5059  retval = thunk(trans, cb_data);
5060  if (retval) return retval;
5061  }
5062  }
5063  }
5064 
5065  return 0;
5066 }
5067 
5068 /********************************************************************\
5069 \********************************************************************/
5070 
5071 int
5073  int (*proc)(Transaction *t, void *data),
5074  void *data)
5075 {
5076  if (!acc || !proc) return 0;
5077 
5079  return gnc_account_tree_staged_transaction_traversal (acc, 42, proc, data);
5080 }
5081 
5082 
5083 gint
5084 xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
5085  void *data)
5086 {
5087  if (!acc || !proc) return 0;
5089  return xaccAccountStagedTransactionTraversal(acc, 42, proc, data);
5090 }
5091 
5092 /* ================================================================ */
5093 /* The following functions are used by
5094  * src/import-export/import-backend.c to manipulate the contra-account
5095  * matching data. See src/import-export/import-backend.c for explanations.
5096  */
5097 
5098 #define IMAP_FRAME "import-map"
5099 #define IMAP_FRAME_BAYES "import-map-bayes"
5100 
5101 /* Look up an Account in the map */
5102 Account*
5103 gnc_account_imap_find_account (Account *acc,
5104  const char *category,
5105  const char *key)
5106 {
5107  if (!acc || !key) return nullptr;
5108  std::vector<std::string> path {IMAP_FRAME};
5109  if (category)
5110  path.push_back (category);
5111  path.push_back (key);
5112  return get_kvp_account_path (acc, path);
5113 }
5114 
5115 Account*
5116 gnc_account_imap_find_any (QofBook *book, const char* category, const char *key)
5117 {
5118  Account *account = nullptr;
5119 
5120  /* Get list of Accounts */
5121  auto root = gnc_book_get_root_account (book);
5122  auto accts = gnc_account_get_descendants_sorted (root);
5123 
5124  /* Go through list of accounts */
5125  for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
5126  {
5127  auto tmp_acc = static_cast<Account*> (ptr->data);
5128 
5129  if (gnc_account_imap_find_account (tmp_acc, category, key))
5130  {
5131  account = tmp_acc;
5132  break;
5133  }
5134  }
5135  g_list_free (accts);
5136 
5137 return account;
5138 }
5139 
5140 /* Store an Account in the map */
5141 void
5142 gnc_account_imap_add_account (Account *acc,
5143  const char *category,
5144  const char *key,
5145  Account *added_acc)
5146 {
5147  if (!acc || !key || !added_acc || !*key) return;
5148 
5149  auto path = category ? Path{IMAP_FRAME, category, key} : Path{IMAP_FRAME, key};
5150 
5151  set_kvp_account_path (acc, path, added_acc);
5152 }
5153 
5154 /* Remove a reference to an Account in the map */
5155 void
5156 gnc_account_imap_delete_account (Account *acc,
5157  const char *category,
5158  const char *key)
5159 {
5160  if (!acc || !key) return;
5161 
5162  auto path = category ? Path{IMAP_FRAME, category, key} : Path{IMAP_FRAME, key};
5163  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
5164  {
5165  qof_instance_slot_path_delete (QOF_INSTANCE (acc), path);
5166  if (category)
5167  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (acc), {IMAP_FRAME, category});
5168  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (acc), {IMAP_FRAME});
5169  }
5170  qof_instance_set_dirty (QOF_INSTANCE (acc));
5171 }
5172 
5173 /*--------------------------------------------------------------------------
5174  Below here is the bayes transaction to account matching system
5175 --------------------------------------------------------------------------*/
5176 
5177 
5183 {
5184  double product; /* product of probabilities */
5185  double product_difference; /* product of (1-probabilities) */
5186 };
5187 
5189 {
5190  std::string account_guid;
5191  int64_t token_count;
5192 };
5193 
5198 {
5199  std::vector<AccountTokenCount> accounts;
5200  int64_t total_count;
5201 };
5202 
5207 {
5208  std::string account_guid;
5209  int32_t probability;
5210 };
5211 
5212 static void
5213 build_token_info(char const * suffix, KvpValue * value, TokenAccountsInfo & tokenInfo)
5214 {
5215  if (strlen(suffix) == GUID_ENCODING_LENGTH)
5216  {
5217  tokenInfo.total_count += value->get<int64_t>();
5218  /*By convention, the key ends with the account GUID.*/
5219  tokenInfo.accounts.emplace_back(AccountTokenCount{std::string{suffix}, value->get<int64_t>()});
5220  }
5221 }
5222 
5226 static constexpr int probability_factor = 100000;
5227 
5228 static FinalProbabilityVec
5229 build_probabilities(ProbabilityVec const & first_pass)
5230 {
5231  FinalProbabilityVec ret;
5232  for (auto const & first_pass_prob : first_pass)
5233  {
5234  auto const & account_probability = first_pass_prob.second;
5235  /* P(AB) = A*B / [A*B + (1-A)*(1-B)]
5236  * NOTE: so we only keep track of a running product(A*B*C...)
5237  * and product difference ((1-A)(1-B)...)
5238  */
5239  int32_t probability = (account_probability.product /
5240  (account_probability.product + account_probability.product_difference)) * probability_factor;
5241  ret.push_back({first_pass_prob.first, probability});
5242  }
5243  return ret;
5244 }
5245 
5246 static AccountInfo
5247 highest_probability(FinalProbabilityVec const & probabilities)
5248 {
5249  AccountInfo ret {"", std::numeric_limits<int32_t>::min()};
5250  for (auto const & prob : probabilities)
5251  if (prob.second > ret.probability)
5252  ret = AccountInfo {prob.first, prob.second};
5253  return ret;
5254 }
5255 
5256 static ProbabilityVec
5257 get_first_pass_probabilities(Account* acc, GList * tokens)
5258 {
5259  ProbabilityVec ret;
5260  /* find the probability for each account that contains any of the tokens
5261  * in the input tokens list. */
5262  for (auto current_token = tokens; current_token; current_token = current_token->next)
5263  {
5264  TokenAccountsInfo tokenInfo{};
5265  auto path = std::string{IMAP_FRAME_BAYES "/"} + static_cast <char const *> (current_token->data) + "/";
5266  qof_instance_foreach_slot_prefix (QOF_INSTANCE (acc), path, &build_token_info, tokenInfo);
5267  for (auto const & current_account_token : tokenInfo.accounts)
5268  {
5269  auto item = std::find_if(ret.begin(), ret.end(), [&current_account_token]
5270  (std::pair<std::string, AccountProbability> const & a) {
5271  return current_account_token.account_guid == a.first;
5272  });
5273  if (item != ret.end())
5274  {/* This account is already in the map */
5275  item->second.product = ((double)current_account_token.token_count /
5276  (double)tokenInfo.total_count) * item->second.product;
5277  item->second.product_difference = ((double)1 - ((double)current_account_token.token_count /
5278  (double)tokenInfo.total_count)) * item->second.product_difference;
5279  }
5280  else
5281  {
5282  /* add a new entry */
5283  AccountProbability new_probability;
5284  new_probability.product = ((double)current_account_token.token_count /
5285  (double)tokenInfo.total_count);
5286  new_probability.product_difference = 1 - (new_probability.product);
5287  ret.push_back({current_account_token.account_guid, std::move(new_probability)});
5288  }
5289  } /* for all accounts in tokenInfo */
5290  }
5291  return ret;
5292 }
5293 
5294 static std::string
5295 look_for_old_separator_descendants (Account *root, std::string const & full_name, const gchar *separator)
5296 {
5297  GList *top_accounts, *ptr;
5298  gint found_len = 0;
5299  gchar found_sep;
5300  top_accounts = gnc_account_get_descendants (root);
5301  PINFO("Incoming full_name is '%s', current separator is '%s'", full_name.c_str (), separator);
5302  /* Go through list of top level accounts */
5303  for (ptr = top_accounts; ptr; ptr = g_list_next (ptr))
5304  {
5305  const gchar *name = xaccAccountGetName (static_cast <Account const *> (ptr->data));
5306  // we are looking for the longest top level account that matches
5307  if (g_str_has_prefix (full_name.c_str (), name))
5308  {
5309  gint name_len = strlen (name);
5310  const gchar old_sep = full_name[name_len];
5311  if (!g_ascii_isalnum (old_sep)) // test for non alpha numeric
5312  {
5313  if (name_len > found_len)
5314  {
5315  found_sep = full_name[name_len];
5316  found_len = name_len;
5317  }
5318  }
5319  }
5320  }
5321  g_list_free (top_accounts); // Free the List
5322  std::string new_name {full_name};
5323  if (found_len > 1)
5324  std::replace (new_name.begin (), new_name.end (), found_sep, *separator);
5325  PINFO ("Return full_name is '%s'", new_name.c_str ());
5326  return new_name;
5327 }
5328 
5329 static std::string
5330 get_guid_from_account_name (Account * root, std::string const & name)
5331 {
5332  auto map_account = gnc_account_lookup_by_full_name (root, name.c_str ());
5333  if (!map_account)
5334  {
5335  auto temp_account_name = look_for_old_separator_descendants (root, name,
5337  map_account = gnc_account_lookup_by_full_name (root, temp_account_name.c_str ());
5338  }
5339  auto temp_guid = gnc::GUID {*xaccAccountGetGUID (map_account)};
5340  return temp_guid.to_string ();
5341 }
5342 
5343 static FlatKvpEntry
5344 convert_entry (KvpEntry entry, Account* root)
5345 {
5346  /*We need to make a copy here.*/
5347  auto account_name = entry.first.back();
5348  if (!gnc::GUID::is_valid_guid (account_name))
5349  {
5350  /* Earlier version stored the account name in the import map, and
5351  * there were early beta versions of 2.7 that stored a GUID.
5352  * If there is no GUID, we assume it's an account name. */
5353  /* Take off the account name and replace it with the GUID */
5354  entry.first.pop_back();
5355  auto guid_str = get_guid_from_account_name (root, account_name);
5356  entry.first.emplace_back (guid_str);
5357  }
5358  std::string new_key {std::accumulate (entry.first.begin(), entry.first.end(), std::string {})};
5359  new_key = IMAP_FRAME_BAYES + new_key;
5360  return {new_key, entry.second};
5361 }
5362 
5363 static std::vector<FlatKvpEntry>
5364 get_flat_imap (Account * acc)
5365 {
5366  auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
5367  auto slot = frame->get_slot ({IMAP_FRAME_BAYES});
5368  if (!slot)
5369  return {};
5370  auto imap_frame = slot->get<KvpFrame*> ();
5371  auto flat_kvp = imap_frame->flatten_kvp ();
5372  auto root = gnc_account_get_root (acc);
5373  std::vector <FlatKvpEntry> ret;
5374  for (auto const & flat_entry : flat_kvp)
5375  {
5376  auto converted_entry = convert_entry (flat_entry, root);
5377  /*If the entry was invalid, we don't perpetuate it.*/
5378  if (converted_entry.first.size())
5379  ret.emplace_back (converted_entry);
5380  }
5381  return ret;
5382 }
5383 
5384 static bool
5385 convert_imap_account_bayes_to_flat (Account *acc)
5386 {
5387  auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
5388  if (!frame->get_keys().size())
5389  return false;
5390  auto flat_imap = get_flat_imap(acc);
5391  if (!flat_imap.size ())
5392  return false;
5393  xaccAccountBeginEdit(acc);
5394  frame->set({IMAP_FRAME_BAYES}, nullptr);
5395  std::for_each(flat_imap.begin(), flat_imap.end(),
5396  [&frame] (FlatKvpEntry const & entry) {
5397  frame->set({entry.first.c_str()}, entry.second);
5398  });
5399  qof_instance_set_dirty (QOF_INSTANCE (acc));
5400  xaccAccountCommitEdit(acc);
5401  return true;
5402 }
5403 
5404 /*
5405  * Checks for import map data and converts them when found.
5406  */
5407 static bool
5408 imap_convert_bayes_to_flat (QofBook * book)
5409 {
5410  auto root = gnc_book_get_root_account (book);
5411  auto accts = gnc_account_get_descendants_sorted (root);
5412  bool ret = false;
5413  for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
5414  {
5415  Account *acc = static_cast <Account*> (ptr->data);
5416  if (convert_imap_account_bayes_to_flat (acc))
5417  {
5418  ret = true;
5419  gnc_features_set_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN);
5420  }
5421  }
5422  g_list_free (accts);
5423  return ret;
5424 }
5425 
5426 void
5428 {
5429  imap_convert_bayes_to_flat_run = false;
5430 }
5431 
5432 /*
5433  * Here we check to see the state of import map data.
5434  *
5435  * If the GUID_FLAT_BAYESIAN feature flag is set, everything
5436  * should be fine.
5437  *
5438  * If it is not set, there are two possibilities: import data
5439  * are present from a previous version or not. If they are,
5440  * they are converted, and the feature flag set. If there are
5441  * no previous data, nothing is done.
5442  */
5443 static void
5444 check_import_map_data (QofBook *book)
5445 {
5446  if (gnc_features_check_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN) ||
5447  imap_convert_bayes_to_flat_run)
5448  return;
5449 
5450  /* This function will set GNC_FEATURE_GUID_FLAT_BAYESIAN if necessary.*/
5451  imap_convert_bayes_to_flat (book);
5452  imap_convert_bayes_to_flat_run = true;
5453 }
5454 
5455 static constexpr double threshold = .90 * probability_factor; /* 90% */
5456 
5458 Account*
5460 {
5461  if (!acc)
5462  return nullptr;
5463  auto book = gnc_account_get_book(acc);
5464  check_import_map_data (book);
5465  auto first_pass = get_first_pass_probabilities(acc, tokens);
5466  if (!first_pass.size())
5467  return nullptr;
5468  auto final_probabilities = build_probabilities(first_pass);
5469  if (!final_probabilities.size())
5470  return nullptr;
5471  auto best = highest_probability(final_probabilities);
5472  if (best.account_guid == "")
5473  return nullptr;
5474  if (best.probability < threshold)
5475  return nullptr;
5476  gnc::GUID guid;
5477  try {
5478  guid = gnc::GUID::from_string(best.account_guid);
5479  } catch (gnc::guid_syntax_exception&) {
5480  return nullptr;
5481  }
5482  auto account = xaccAccountLookup (reinterpret_cast<GncGUID*>(&guid), book);
5483  return account;
5484 }
5485 
5486 static void
5487 change_imap_entry (Account *acc, std::string const & path, int64_t token_count)
5488 {
5489  PINFO("Source Account is '%s', Count is '%" G_GINT64_FORMAT "'",
5490  xaccAccountGetName (acc), token_count);
5491 
5492  // check for existing guid entry
5493  if (auto existing_token_count = get_kvp_int64_path (acc, {path}))
5494  {
5495  PINFO("found existing value of '%" G_GINT64_FORMAT "'", *existing_token_count);
5496  token_count += *existing_token_count;
5497  }
5498 
5499  // Add or Update the entry based on guid
5500  set_kvp_int64_path (acc, {path}, token_count);
5501 }
5502 
5504 void
5506  GList *tokens,
5507  Account *added_acc)
5508 {
5509  GList *current_token;
5510  gint64 token_count;
5511  char *account_fullname;
5512  char *guid_string;
5513 
5514  ENTER(" ");
5515  if (!acc)
5516  {
5517  LEAVE(" ");
5518  return;
5519  }
5520  check_import_map_data (gnc_account_get_book(acc));
5521 
5522  g_return_if_fail (added_acc != nullptr);
5523  account_fullname = gnc_account_get_full_name(added_acc);
5524  xaccAccountBeginEdit (acc);
5525 
5526  PINFO("account name: '%s'", account_fullname);
5527 
5528  guid_string = guid_to_string (xaccAccountGetGUID (added_acc));
5529 
5530  /* process each token in the list */
5531  for (current_token = g_list_first(tokens); current_token;
5532  current_token = current_token->next)
5533  {
5534  char* token = static_cast<char*>(current_token->data);
5535  /* Jump to next iteration if the pointer is not valid or if the
5536  string is empty. In HBCI import we almost always get an empty
5537  string, which doesn't work in the kvp loopkup later. So we
5538  skip this case here. */
5539  if (!token || !token[0])
5540  continue;
5541  /* start off with one token for this account */
5542  token_count = 1;
5543  PINFO("adding token '%s'", token);
5544  auto path = std::string {IMAP_FRAME_BAYES} + '/' + token + '/' + guid_string;
5545  /* change the imap entry for the account */
5546  change_imap_entry (acc, path, token_count);
5547  }
5548  /* free up the account fullname and guid string */
5549  xaccAccountCommitEdit (acc);
5550  gnc_features_set_used (gnc_account_get_book(acc), GNC_FEATURE_GUID_FLAT_BAYESIAN);
5551  g_free (account_fullname);
5552  g_free (guid_string);
5553  LEAVE(" ");
5554 }
5555 
5556 /*******************************************************************************/
5557 
5558 static void
5559 build_non_bayes (const char *key, const GValue *value, gpointer user_data)
5560 {
5561  if (!G_VALUE_HOLDS_BOXED (value))
5562  return;
5563  QofBook *book;
5564  GncGUID *guid = nullptr;
5565  gchar *guid_string = nullptr;
5566  auto imapInfo = (GncImapInfo*)user_data;
5567  // Get the book
5568  book = qof_instance_get_book (imapInfo->source_account);
5569 
5570  guid = (GncGUID*)g_value_get_boxed (value);
5571  guid_string = guid_to_string (guid);
5572 
5573  PINFO("build_non_bayes: match string '%s', match account guid: '%s'",
5574  (char*)key, guid_string);
5575 
5576  auto imapInfo_node = static_cast <GncImapInfo*> (g_malloc(sizeof(GncImapInfo)));
5577 
5578  imapInfo_node->source_account = imapInfo->source_account;
5579  imapInfo_node->map_account = xaccAccountLookup (guid, book);
5580  imapInfo_node->head = g_strdup (imapInfo->head);
5581  imapInfo_node->match_string = g_strdup (key);
5582  imapInfo_node->category = g_strdup (imapInfo->category);
5583  imapInfo_node->count = g_strdup (" ");
5584 
5585  imapInfo->list = g_list_prepend (imapInfo->list, imapInfo_node);
5586 
5587  g_free (guid_string);
5588 }
5589 
5590 static void
5591 build_bayes (const char *suffix, KvpValue * value, GncImapInfo & imapInfo)
5592 {
5593  size_t guid_start = strlen(suffix) - GUID_ENCODING_LENGTH;
5594  std::string account_guid {&suffix[guid_start]};
5595  GncGUID guid;
5596  try
5597  {
5598  guid = gnc::GUID::from_string (account_guid);
5599  }
5600  catch (const gnc::guid_syntax_exception& err)
5601  {
5602  PWARN("Invalid GUID string from %s%s", IMAP_FRAME_BAYES, suffix);
5603  }
5604  auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
5605  auto imap_node = static_cast <GncImapInfo*> (g_malloc (sizeof (GncImapInfo)));
5606  auto count = value->get <int64_t> ();
5607  imap_node->source_account = imapInfo.source_account;
5608  imap_node->map_account = map_account;
5609  imap_node->head = g_strdup_printf ("%s%s", IMAP_FRAME_BAYES, suffix);
5610  imap_node->match_string = g_strndup (&suffix[1], guid_start - 2);
5611  imap_node->category = g_strdup(" ");
5612  imap_node->count = g_strdup_printf ("%" G_GINT64_FORMAT, count);
5613  imapInfo.list = g_list_prepend (imapInfo.list, imap_node);
5614 }
5615 
5617 {
5618  g_free (imapInfo->head);
5619  g_free (imapInfo->category);
5620  g_free (imapInfo->match_string);
5621  g_free (imapInfo->count);
5622  g_free (imapInfo);
5623 }
5624 
5625 GList *
5627 {
5628  check_import_map_data (gnc_account_get_book (acc));
5629  /* A dummy object which is used to hold the specified account, and the list
5630  * of data about which we care. */
5631  GncImapInfo imapInfo {acc, nullptr};
5632  qof_instance_foreach_slot_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES, &build_bayes, imapInfo);
5633  return g_list_reverse(imapInfo.list);
5634 }
5635 
5636 GList *
5637 gnc_account_imap_get_info (Account *acc, const char *category)
5638 {
5639  GList *list = nullptr;
5640 
5641  GncImapInfo imapInfo;
5642 
5643  std::vector<std::string> path {IMAP_FRAME};
5644  if (category)
5645  path.emplace_back (category);
5646 
5647  imapInfo.source_account = acc;
5648  imapInfo.list = list;
5649 
5650  imapInfo.head = g_strdup (IMAP_FRAME);
5651  imapInfo.category = g_strdup (category);
5652 
5653  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
5654  {
5655  qof_instance_foreach_slot (QOF_INSTANCE(acc), IMAP_FRAME, category,
5656  build_non_bayes, &imapInfo);
5657  }
5658  g_free (imapInfo.head);
5659  g_free (imapInfo.category);
5660  return g_list_reverse(imapInfo.list);
5661 }
5662 
5663 /*******************************************************************************/
5664 
5665 gchar *
5666 gnc_account_get_map_entry (Account *acc, const char *head, const char *category)
5667 {
5668  return g_strdup (category ?
5669  get_kvp_string_path (acc, {head, category}) :
5670  get_kvp_string_path (acc, {head}));
5671 }
5672 
5673 
5674 void
5675 gnc_account_delete_map_entry (Account *acc, char *head, char *category,
5676  char *match_string, gboolean empty)
5677 {
5678  if (acc != nullptr)
5679  {
5680  std::vector<std::string> path {head};
5681  if (category)
5682  path.emplace_back (category);
5683  if (match_string)
5684  path.emplace_back (match_string);
5685 
5686  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
5687  {
5688  xaccAccountBeginEdit (acc);
5689  if (empty)
5690  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), path);
5691  else
5692  qof_instance_slot_path_delete (QOF_INSTANCE(acc), path);
5693  PINFO("Account is '%s', head is '%s', category is '%s', match_string is'%s'",
5694  xaccAccountGetName (acc), head, category, match_string);
5695  qof_instance_set_dirty (QOF_INSTANCE(acc));
5696  xaccAccountCommitEdit (acc);
5697  }
5698  }
5699 }
5700 
5701 void
5703 {
5704  if (acc != nullptr)
5705  {
5706  auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES);
5707  if (!slots.size()) return;
5708  xaccAccountBeginEdit (acc);
5709  for (auto const & entry : slots)
5710  {
5711  qof_instance_slot_path_delete (QOF_INSTANCE (acc), {entry.first});
5712  }
5713  qof_instance_set_dirty (QOF_INSTANCE(acc));
5714  xaccAccountCommitEdit (acc);
5715  }
5716 }
5717 
5718 /* ================================================================ */
5719 /* QofObject function implementation and registration */
5720 
5721 static void
5722 destroy_all_child_accounts (Account *acc, gpointer data)
5723 {
5724  xaccAccountBeginEdit (acc);
5725  xaccAccountDestroy (acc);
5726 }
5727 
5728 static void
5729 gnc_account_book_end(QofBook* book)
5730 {
5731  Account *root_account = gnc_book_get_root_account (book);
5732  GList *accounts;
5733 
5734  if (!root_account)
5735  return;
5736 
5737  accounts = gnc_account_get_descendants (root_account);
5738 
5739  if (accounts)
5740  {
5741  accounts = g_list_reverse (accounts);
5742  g_list_foreach (accounts, (GFunc)destroy_all_child_accounts, nullptr);
5743  g_list_free (accounts);
5744  }
5745  xaccAccountBeginEdit (root_account);
5746  xaccAccountDestroy (root_account);
5747 }
5748 
5749 #ifdef _MSC_VER
5750 /* MSVC compiler doesn't have C99 "designated initializers"
5751  * so we wrap them in a macro that is empty on MSVC. */
5752 # define DI(x) /* */
5753 #else
5754 # define DI(x) x
5755 #endif
5756 static QofObject account_object_def =
5757 {
5758  DI(.interface_version = ) QOF_OBJECT_VERSION,
5759  DI(.e_type = ) GNC_ID_ACCOUNT,
5760  DI(.type_label = ) "Account",
5761  DI(.create = ) (void*(*)(QofBook*)) xaccMallocAccount,
5762  DI(.book_begin = ) nullptr,
5763  DI(.book_end = ) gnc_account_book_end,
5764  DI(.is_dirty = ) qof_collection_is_dirty,
5765  DI(.mark_clean = ) qof_collection_mark_clean,
5766  DI(.foreach = ) qof_collection_foreach,
5767  DI(.printable = ) (const char * (*)(gpointer)) xaccAccountGetName,
5768  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
5769 };
5770 
5771 gboolean xaccAccountRegister (void)
5772 {
5773  static QofParam params[] =
5774  {
5775  {
5776  ACCOUNT_NAME_, QOF_TYPE_STRING,
5779  },
5780  {
5781  ACCOUNT_CODE_, QOF_TYPE_STRING,
5784  },
5785  {
5786  ACCOUNT_DESCRIPTION_, QOF_TYPE_STRING,
5789  },
5790  {
5791  ACCOUNT_COLOR_, QOF_TYPE_STRING,
5794  },
5795  {
5796  ACCOUNT_FILTER_, QOF_TYPE_STRING,
5799  },
5800  {
5801  ACCOUNT_SORT_ORDER_, QOF_TYPE_STRING,
5804  },
5805  {
5806  ACCOUNT_SORT_REVERSED_, QOF_TYPE_BOOLEAN,
5809  },
5810  {
5811  ACCOUNT_NOTES_, QOF_TYPE_STRING,
5814  },
5815  {
5816  ACCOUNT_PRESENT_, QOF_TYPE_NUMERIC,
5817  (QofAccessFunc) xaccAccountGetPresentBalance, nullptr
5818  },
5819  {
5820  ACCOUNT_BALANCE_, QOF_TYPE_NUMERIC,
5822  },
5823  {
5824  ACCOUNT_CLEARED_, QOF_TYPE_NUMERIC,
5826  },
5827  {
5828  ACCOUNT_RECONCILED_, QOF_TYPE_NUMERIC,
5830  },
5831  {
5832  ACCOUNT_TYPE_, QOF_TYPE_STRING,
5833  (QofAccessFunc) qofAccountGetTypeString,
5834  (QofSetterFunc) qofAccountSetType
5835  },
5836  {
5837  ACCOUNT_FUTURE_MINIMUM_, QOF_TYPE_NUMERIC,
5838  (QofAccessFunc) xaccAccountGetProjectedMinimumBalance, nullptr
5839  },
5840  {
5841  ACCOUNT_TAX_RELATED, QOF_TYPE_BOOLEAN,
5844  },
5845  {
5846  ACCOUNT_OPENING_BALANCE_, QOF_TYPE_BOOLEAN,
5849  },
5850  {
5851  ACCOUNT_SCU, QOF_TYPE_INT32,
5854  },
5855  {
5856  ACCOUNT_NSCU, QOF_TYPE_BOOLEAN,
5859  },
5860  {
5861  ACCOUNT_PARENT, GNC_ID_ACCOUNT,
5863  (QofSetterFunc) qofAccountSetParent
5864  },
5865  {
5866  QOF_PARAM_BOOK, QOF_ID_BOOK,
5868  },
5869  {
5870  QOF_PARAM_GUID, QOF_TYPE_GUID,
5872  },
5873  { nullptr },
5874  };
5875 
5876  qof_class_register (GNC_ID_ACCOUNT, (QofSortFunc) qof_xaccAccountOrder, params);
5877 
5878  return qof_object_register (&account_object_def);
5879 }
5880 
5881 /* ======================= UNIT TESTING ACCESS =======================
5882  * The following functions are for unit testing use only.
5883  */
5884 static AccountPrivate*
5885 utest_account_get_private (Account *acc)
5886 {
5887  return GET_PRIVATE (acc);
5888 }
5889 
5891 _utest_account_fill_functions(void)
5892 {
5893  AccountTestFunctions* func = g_new(AccountTestFunctions, 1);
5894 
5895  func->get_private = utest_account_get_private;
5896  func->coll_get_root_account = gnc_coll_get_root_account;
5897  func->xaccFreeAccountChildren = xaccFreeAccountChildren;
5898  func->xaccFreeAccount = xaccFreeAccount;
5899  func->qofAccountSetParent = qofAccountSetParent;
5900  func->gnc_account_lookup_by_full_name_helper =
5901  gnc_account_lookup_by_full_name_helper;
5902 
5903  return func;
5904 }
5905 /* ======================= END OF FILE =========================== */
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Set the account&#39;s type.
Definition: Account.cpp:2402
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Add a new commodity to the commodity table.
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
Definition: Account.cpp:2886
void xaccAccountSetFilter(Account *acc, const char *str)
Set the account&#39;s Filter.
Definition: Account.cpp:2577
void xaccAccountSetSortOrder(Account *acc, const char *str)
Set the account&#39;s Sort Order.
Definition: Account.cpp:2583
gint xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc, void *data)
The xaccAccountForEachTransaction() routine will traverse all of the transactions in account and call...
Definition: Account.cpp:5084
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
Traverse all of the transactions in the given account group.
gint xaccSplitOrder(const Split *sa, const Split *sb)
The xaccSplitOrder(sa,sb) method is useful for sorting.
Definition: Split.cpp:1501
This is the private header for the account structure.
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Returns the commodity table associated with a book.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
int gnc_account_tree_staged_transaction_traversal(const Account *acc, unsigned int stage, TransactionCallback thunk, void *cb_data)
gnc_account_tree_staged_transaction_traversal() calls thunk on each transaction in the group whose cu...
Definition: Account.cpp:5031
gboolean xaccAccountGetAutoInterest(const Account *acc)
Get the "auto interest" flag for an account.
Definition: Account.cpp:4114
holds an account guid and its corresponding integer probability the integer probability is some facto...
Definition: Account.cpp:5206
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4622
GNCAccountType xaccAccountTypeGetFundamental(GNCAccountType t)
Convenience function to return the fundamental type asset/liability/income/expense/equity given an ac...
Definition: Account.cpp:4434
gchar * gnc_account_get_map_entry(Account *acc, const char *head, const char *category)
Returns the text string pointed to by head and category for the Account, free the returned text...
Definition: Account.cpp:5666
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...
GList LotList
GList of GNCLots.
Definition: gnc-engine.h:205
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
gboolean xaccAccountGetSortReversed(const Account *acc)
Get the account&#39;s Sort Order direction.
Definition: Account.cpp:3326
guint32 xaccAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of account types compatible with a given type.
Definition: Account.cpp:4306
void gnc_account_imap_info_destroy(GncImapInfo *imapInfo)
Clean destructor for the imap_info structure of Bayesian mappings.
Definition: Account.cpp:5616
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:2787
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
gpointer xaccAccountForEachLot(const Account *acc, gpointer(*proc)(GNCLot *lot, gpointer user_data), gpointer user_data)
The xaccAccountForEachLot() method will apply the function &#39;proc&#39; to each lot in the account...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
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:3002
gint gnc_account_n_descendants(const Account *account)
Return the number of descendants of the specified account.
Definition: Account.cpp:2952
gint64 xaccAccountGetTaxUSCopyNumber(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4014
gboolean gnc_account_is_root(const Account *account)
This routine indicates whether the specified account is the root node of an account tree...
Definition: Account.cpp:2904
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:3893
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
void xaccAccountSetAssociatedAccount(Account *acc, const char *tag, const Account *assoc_acct)
Set the account&#39;s associated account e.g.
Definition: Account.cpp:2620
gboolean xaccAccountGetNonStdSCU(const Account *acc)
Return boolean, indicating whether this account uses a non-standard SCU.
Definition: Account.cpp:2725
int xaccAccountGetCommoditySCUi(const Account *acc)
Return the &#39;internal&#39; SCU setting.
Definition: Account.cpp:2689
#define GNC_COMMODITY_MAX_FRACTION
Max fraction is 10^9 because 10^10 would require changing it to an int64_t.
const char * qof_string_cache_replace(char const *dst, char const *src)
Same as CACHE_REPLACE below, but safe to call from C++.
gchar * gnc_g_list_stringjoin(GList *list_of_strings, const gchar *sep)
Return a string joining a GList whose elements are gchar* strings.
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
Definition: Account.cpp:3347
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling &#39;func&#39; on each...
Definition: Account.cpp:3186
void xaccAccountSetNotes(Account *acc, const char *str)
Set the account&#39;s notes.
Definition: Account.cpp:2613
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4490
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:255
void gnc_account_delete_map_entry(Account *acc, char *head, char *category, char *match_string, gboolean empty)
Delete the entry for Account pointed to by head,category and match_string, if empty is TRUE then use ...
Definition: Account.cpp:5675
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
a simple price database for gnucash
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:212
Expense accounts are used to denote expenses.
Definition: Account.h:143
int safe_utf8_collate(const char *da, const char *db)
Collate two UTF-8 strings.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
const char * xaccAccountGetFilter(const Account *acc)
Get the account&#39;s filter.
Definition: Account.cpp:3314
gnc_numeric xaccSplitGetReconciledBalance(const Split *s)
Returns the reconciled-balance of this split.
Definition: Split.cpp:1314
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3217
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1471
void xaccAccountSetMark(Account *acc, short m)
Set a mark on the account.
Definition: Account.cpp:2044
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2696
const char * xaccAccountGetCode(const Account *acc)
Get the account&#39;s accounting code.
Definition: Account.cpp:3294
gboolean xaccAccountGetAppendText(const Account *acc)
Get the "import-append-text" flag for an account.
Definition: Account.cpp:4070
void xaccAccountSetReconcileLastDate(Account *acc, time64 last_date)
DOCUMENT ME!
Definition: Account.cpp:4523
STRUCTS.
total_count and the token_count for a given account let us calculate the probability of a given accou...
Definition: Account.cpp:5197
Account * gnc_account_create_root(QofBook *book)
Create a new root level account.
Definition: Account.cpp:1285
void gnc_commodity_decrement_usage_count(gnc_commodity *cm)
Decrement a commodity&#39;s internal counter that tracks how many accounts are using that commodity...
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition: guid.cpp:120
void xaccAccountSetTaxRelated(Account *acc, gboolean tax_related)
DOCUMENT ME!
Definition: Account.cpp:3984
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
All arguments are required to have the same denominator, that denominator is to be used in the output...
Definition: gnc-numeric.h:206
Mutual Fund accounts will typically be shown in registers which show three columns: price...
Definition: Account.h:125
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
void xaccAccountSortSplits(Account *acc, gboolean force)
The xaccAccountSortSplits() routine will resort the account&#39;s splits if the sort is dirty...
Definition: Account.cpp:1986
void xaccAccountSetCode(Account *acc, const char *str)
Set the account&#39;s accounting code.
Definition: Account.cpp:2443
gpointer gnc_account_foreach_descendant_until(const Account *acc, AccountCb2 thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling &#39;func&#39; on each...
Definition: Account.cpp:3194
void gnc_account_set_policy(Account *acc, GNCPolicy *policy)
Set the account&#39;s lot order policy.
Definition: Account.cpp:2090
void xaccAccountSetReconcileLastInterval(Account *acc, int months, int days)
DOCUMENT ME!
Definition: Account.cpp:4553
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
gboolean gnc_account_remove_split(Account *acc, Split *s)
Remove the given split from an account.
Definition: Account.cpp:1955
gnc_numeric xaccAccountGetBalanceAsOfDateInCurrency(Account *acc, time64 date, gnc_commodity *report_commodity, gboolean include_children)
This function gets the balance at the end of the given date in the desired commodity.
Definition: Account.cpp:3795
guint32 xaccAccountTypesValid(void)
Returns the bitmask of the account type enums that are valid.
Definition: Account.cpp:4411
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
const char * xaccAccountTypeEnumAsString(GNCAccountType type)
Conversion routines for the account types to/from strings that are used in persistent storage...
Definition: Account.cpp:4186
stop here; the following types just aren&#39;t ready for prime time
Definition: Account.h:161
GList * gnc_account_list_name_violations(QofBook *book, const gchar *separator)
Runs through all the accounts and returns a list of account names that contain the provided separator...
Definition: Account.cpp:271
void xaccAccountSetHigherBalanceLimit(Account *acc, gnc_numeric balance)
Set the higher balance limit for the account.
Definition: Account.cpp:4672
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2122
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
API for Transactions and Splits (journal entries)
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
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:223
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:63
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
void xaccAccountMoveAllSplits(Account *accfrom, Account *accto)
The xaccAccountMoveAllSplits() routine reassigns each of the splits in accfrom to accto...
Definition: Account.cpp:2182
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
void gnc_account_set_sort_dirty(Account *acc)
Tell the account believes that the splits may be incorrectly sorted and need to be resorted...
Definition: Account.cpp:1866
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gnc_numeric gnc_pricedb_convert_balance_nearest_before_price_t64(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency, time64 t)
Convert a balance from one currency to another using the price nearest to before the given time...
The cash account type is used to denote a shoe-box or pillowcase stuffed with * cash.
Definition: Account.h:110
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
Definition: Account.cpp:4030
void gnc_account_imap_add_account_bayes(Account *acc, GList *tokens, Account *added_acc)
Updates the imap for a given account using a list of tokens.
Definition: Account.cpp:5505
gnc_numeric xaccSplitGetBalance(const Split *s)
Returns the running balance up to and including the indicated split.
Definition: Split.cpp:1296
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:108
void xaccAccountSetLastNum(Account *acc, const char *num)
Set the last num field of an Account.
Definition: Account.cpp:4631
const char * qof_string_cache_insert(const char *key)
You can use this function with g_hash_table_insert(), for the key (or value), as long as you use the ...
gnc_numeric xaccAccountGetClearedBalance(const Account *acc)
Get the current balance of the account, only including cleared transactions.
Definition: Account.cpp:3425
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:185
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
gnc_numeric gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency)
Convert a balance from one currency to another using the most recent price between the two...
gboolean xaccAccountGetReconcilePostponeDate(const Account *acc, time64 *postpone_date)
DOCUMENT ME!
Definition: Account.cpp:4563
intermediate values used to calculate the bayes probability of a given account where p(AB) = (a*b)/[a...
Definition: Account.cpp:5182
Account used to record multiple commodity transactions.
Definition: Account.h:155
gboolean xaccAccountGetLowerBalanceLimit(const Account *acc, gnc_numeric *balance)
Get the lower balance limit for the account.
Definition: Account.cpp:4665
void xaccAccountDestroy(Account *acc)
The xaccAccountDestroy() routine can be used to get rid of an account.
Definition: Account.cpp:1590
gboolean xaccAccountIsHidden(const Account *acc)
Should this account be "hidden".
Definition: Account.cpp:4141
gboolean xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_guids, gboolean check_balances, gboolean check_txn_splits)
Equality.
Definition: Split.cpp:801
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
Definition: Account.cpp:3043
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
void gnc_account_remove_child(Account *parent, Account *child)
This function will remove the specified child account from the specified parent account.
Definition: Account.cpp:2849
int xaccAccountOrder(const Account *aa, const Account *ab)
The xaccAccountOrder() subroutine defines a sorting order on accounts.
Definition: Account.cpp:2340
Stock accounts will typically be shown in registers which show three columns: price, number of shares, and value.
Definition: Account.h:122
const char * xaccAccountGetColor(const Account *acc)
Get the account&#39;s color.
Definition: Account.cpp:3308
Split * xaccAccountFindSplitByDesc(const Account *acc, const char *description)
Returns a pointer to the split, not a copy.
Definition: Account.cpp:4850
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
#define xaccAccountGetGUID(X)
Definition: Account.h:248
gboolean xaccAccountIsAssetLiabType(GNCAccountType t)
Convenience function to check if the account is a valid Asset or Liability type, but not a business a...
Definition: Account.cpp:4420
void xaccClearMarkDown(Account *acc, short val)
The xaccClearMarkDown will clear the mark only in this and in sub-accounts.
Definition: Account.cpp:2066
GList SplitList
GList of Split.
Definition: gnc-engine.h:207
GNCAccountType xaccAccountStringToEnum(const char *str)
Conversion routines for the account types to/from strings that are used in persistent storage...
Definition: Account.cpp:4257
bank account type – don&#39;t use this for now, see NUM_ACCOUNT_TYPES
Definition: Account.h:165
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
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3246
gnc_numeric xaccAccountGetReconciledBalanceAsOfDate(Account *acc, time64 date)
Get the reconciled balance of the account at the end of the day of the date specified.
Definition: Account.cpp:3489
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4064
gboolean xaccAccountTypesCompatible(GNCAccountType parent_type, GNCAccountType child_type)
Return TRUE if accounts of type parent_type can have accounts of type child_type as children...
Definition: Account.cpp:4393
gnc_numeric xaccAccountGetNoclosingBalanceAsOfDateInCurrency(Account *acc, time64 date, gnc_commodity *report_commodity, gboolean include_children)
This function gets the balance at the end of the given date, ignoring closing entries, in the desired commodity.
Definition: Account.cpp:3805
gchar * gnc_account_name_violations_errmsg(const gchar *separator, GList *invalid_account_names)
Composes a translatable error message showing which account names clash with the current account sepa...
Definition: Account.cpp:233
void xaccAccountClearLowerBalanceLimit(Account *acc)
Clear the lower balance limit for the account.
Definition: Account.cpp:4690
gboolean xaccTransactionTraverse(Transaction *trans, int stage)
xaccTransactionTraverse() checks the stage of the given transaction.
Definition: Account.cpp:4981
void xaccAccountSetColor(Account *acc, const char *str)
Set the account&#39;s Color.
Definition: Account.cpp:2571
Transaction * xaccAccountFindTransByDesc(const Account *acc, const char *description)
Returns a pointer to the transaction, not a copy.
Definition: Account.cpp:4863
void xaccAccountSetIncludeSubAccountBalances(Account *acc, gboolean inc_sub)
Set whether to include balances of sub accounts.
Definition: Account.cpp:4702
void gnc_account_set_balance_dirty(Account *acc)
Tell the account that the running balances may be incorrect and need to be recomputed.
Definition: Account.cpp:1880
Income accounts are used to denote income.
Definition: Account.h:140
void gnc_account_foreach_child(const Account *acc, AccountCb thunk, gpointer user_data)
This method will traverse the immediate children of this accounts, calling &#39;func&#39; on each account...
Definition: Account.cpp:3175
Account public routines (C++ api)
#define YREC
The Split has been reconciled.
Definition: Split.h:74
Account * gnc_account_lookup_by_code(const Account *parent, const char *code)
The gnc_account_lookup_by_code() subroutine works like gnc_account_lookup_by_name, but uses the account code.
Definition: Account.cpp:3056
void gnc_account_tree_begin_staged_transaction_traversals(Account *account)
gnc_account_tree_begin_staged_transaction_traversals() resets the traversal marker inside every trans...
Definition: Account.cpp:4996
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:4774
#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 xaccAccountBeginStagedTransactionTraversals(const Account *account)
xaccAccountBeginStagedTransactionTraversals() resets the traversal marker for each transaction which ...
Definition: Account.cpp:4973
void gnc_commodity_increment_usage_count(gnc_commodity *cm)
Increment a commodity&#39;s internal counter that tracks how many accounts are using that commodity...
#define FREC
frozen into accounting period
Definition: Split.h:75
GNCPlaceholderType xaccAccountGetDescendantPlaceholder(const Account *acc)
Returns PLACEHOLDER_NONE if account is NULL or neither account nor any descendant of account is a pla...
Definition: Account.cpp:4101
const char * xaccAccountGetDescription(const Account *acc)
Get the account&#39;s description.
Definition: Account.cpp:3301
void gnc_account_set_start_reconciled_balance(Account *acc, const gnc_numeric start_baln)
This function will set the starting reconciled commodity balance for this account.
Definition: Account.cpp:3405
void gnc_account_delete_all_bayes_maps(Account *acc)
Delete all bayes entries for Account.
Definition: Account.cpp:5702
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:4813
line of credit – don&#39;t use this for now, see NUM_ACCOUNT_TYPES
Definition: Account.h:171
void xaccAccountClearReconcilePostpone(Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4613
const char * xaccAccountGetTaxUSPayerNameSource(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4002
gnc_numeric xaccSplitGetNoclosingBalance(const Split *s)
The noclosing-balance is the currency-denominated balance of all transactions except &#39;closing&#39; transa...
Definition: Split.cpp:1302
gint null_strcmp(const gchar *da, const gchar *db)
The null_strcmp compares strings a and b the same way that strcmp() does, except that either may be n...
Definition: qofutil.cpp:123
void gnc_account_reset_convert_bayes_to_flat(void)
Reset the flag that indicates the function imap_convert_bayes_to_flat has been run.
Definition: Account.cpp:5427
GList * gnc_account_get_children_sorted(const Account *account)
This routine returns a GList of all children accounts of the specified account, ordered by xaccAccoun...
Definition: Account.cpp:2920
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:107
LotList * xaccAccountGetLotList(const Account *acc)
The xaccAccountGetLotList() routine returns a list of all lots in this account.
Definition: Account.cpp:3918
void xaccAccountRecomputeBalance(Account *acc)
The following recompute the partial balances (stored with the transaction) and the total balance...
Definition: Account.cpp:2261
GList * gnc_account_imap_get_info_bayes(Account *acc)
Returns a GList of structure imap_info of all Bayesian mappings for required Account.
Definition: Account.cpp:5626
GList * gnc_account_imap_get_info(Account *acc, const char *category)
Returns a GList of structure imap_info of all Non Bayesian mappings for required Account.
Definition: Account.cpp:5637
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
Definition: Account.cpp:3113
gboolean gnc_account_get_defer_bal_computation(Account *acc)
Get the account&#39;s flag for deferred balance computation.
Definition: Account.cpp:1906
void xaccAccountSetReconcilePostponeDate(Account *acc, time64 postpone_date)
DOCUMENT ME!
Definition: Account.cpp:4578
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:178
A/P account type.
Definition: Account.h:151
const char * xaccAccountGetTaxUSCode(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:3990
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4466
void qof_collection_insert_entity(QofCollection *, QofInstance *)
Take entity, remove it from whatever collection its currently in, and place it in a new collection...
Definition: qofid.cpp:95
bank account type – don&#39;t use this for now, see NUM_ACCOUNT_TYPES
Definition: Account.h:167
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:261
gboolean xaccAccountStringToType(const char *str, GNCAccountType *type)
Conversion routines for the account types to/from strings that are used in persistent storage...
Definition: Account.cpp:4223
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Additional event handling code.
void xaccAccountSetIsOpeningBalance(Account *acc, gboolean val)
Set the "opening-balance" flag for an account.
Definition: Account.cpp:4092
void xaccAccountSetReconcilePostponeBalance(Account *acc, gnc_numeric balance)
DOCUMENT ME!
Definition: Account.cpp:4603
gboolean xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
Compare two accounts for equality - this is a deep compare.
Definition: Account.cpp:1648
gboolean xaccAccountGetTaxRelated(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:3978
void gnc_account_set_start_cleared_balance(Account *acc, const gnc_numeric start_baln)
This function will set the starting cleared commodity balance for this account.
Definition: Account.cpp:3392
Account * xaccCloneAccount(const Account *from, QofBook *book)
The xaccCloneAccount() routine makes a simple copy of the indicated account, placing it in the indica...
Definition: Account.cpp:1302
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gnc_numeric xaccAccountGetReconciledBalance(const Account *acc)
Get the current balance of the account, only including reconciled transactions.
Definition: Account.cpp:3432
asset (and liability) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:116
gint gnc_account_n_children(const Account *account)
Return the number of children of the specified account.
Definition: Account.cpp:2927
void gnc_account_join_children(Account *to_parent, Account *from_parent)
The gnc_account_join_children() subroutine will move (reparent) all child accounts from the from_pare...
Definition: Account.cpp:4873
gnc_numeric xaccAccountGetBalanceAsOfDate(Account *acc, time64 date)
Get the balance of the account at the end of the day before the date specified.
Definition: Account.cpp:3477
gnc_numeric xaccAccountGetBalance(const Account *acc)
Get the current balance of the account, which may include future splits.
Definition: Account.cpp:3418
gboolean xaccAccountGetReconcileLastDate(const Account *acc, time64 *last_date)
DOCUMENT ME!
Definition: Account.cpp:4505
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:4802
The currency account type indicates that the account is a currency trading account.
Definition: Account.h:129
void xaccAccountSetCommoditySCU(Account *acc, int scu)
Set the SCU for the account.
Definition: Account.cpp:2673
gboolean qof_instance_books_equal(gconstpointer ptr1, gconstpointer ptr2)
See if two QofInstances share the same book.
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:3366
Account * xaccAccountGetAssociatedAccount(const Account *acc, const char *tag)
Get the account&#39;s associated account e.g.
Definition: Account.cpp:3338
gboolean xaccAccountGetHidden(const Account *acc)
Get the "hidden" flag for an account.
Definition: Account.cpp:4129
void xaccAccountSetAppendText(Account *acc, gboolean val)
Set the "import-append-text" flag for an account.
Definition: Account.cpp:4076
GLib helper routines.
Generic api to store and retrieve preferences.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
gboolean gnc_account_insert_split(Account *acc, Split *s)
Insert the given split from an account.
Definition: Account.cpp:1925
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition: Account.cpp:2994
void xaccAccountSetAutoInterest(Account *acc, gboolean val)
Set the "auto interest" flag for an account.
Definition: Account.cpp:4120
void xaccAccountSetTaxUSCode(Account *acc, const char *code)
DOCUMENT ME!
Definition: Account.cpp:3996
GNCPlaceholderType
DOCUMENT ME!
Definition: Account.h:1261
gboolean xaccAccountGetIsOpeningBalance(const Account *acc)
Get the "opening-balance" flag for an account.
Definition: Account.cpp:4082
guint32 xaccParentAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of parent account types compatible with a given type.
Definition: Account.cpp:4346
gboolean xaccAccountGetReconcileChildrenStatus(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4837
gboolean xaccAccountGetReconcileLastInterval(const Account *acc, int *months, int *days)
DOCUMENT ME!
Definition: Account.cpp:4532
gboolean xaccAccountGetIncludeSubAccountBalances(const Account *acc)
Get whether to include balances of sub accounts.
Definition: Account.cpp:4696
Not a type.
Definition: Account.h:104
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:4786
liability (and asset) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:119
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Definition: Account.cpp:4042
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Definition: gnc-lot.cpp:367
GList * gnc_account_get_children(const Account *account)
This routine returns a GList of all children accounts of the specified account.
Definition: Account.cpp:2911
Split * gnc_account_find_split(const Account *acc, std::function< bool(const Split *)> predicate, bool reverse)
scans account split list (in forward or reverse order) until predicate split->bool returns true...
Definition: Account.cpp:1168
void xaccAccountSetHidden(Account *acc, gboolean val)
Set the "hidden" flag for an account.
Definition: Account.cpp:4135
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1475
gboolean xaccAccountHasAncestor(const Account *acc, const Account *ancestor)
Returns true if the account is &#39;ancestor&#39; or has &#39;ancestor&#39; as an ancestor.
Definition: Account.cpp:4163
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gchar * guid_to_string(const GncGUID *guid)
The guid_to_string() routine returns a null-terminated string encoding of the id. ...
Definition: guid.cpp:164
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3359
gboolean xaccTransGetIsClosingTxn(const Transaction *trans)
Returns whether this transaction is a "closing transaction".
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4058
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
Definition: gnc-date.cpp:1356
gint gnc_account_get_current_depth(const Account *account)
Return the number of levels of this account below the root account.
Definition: Account.cpp:2960
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
A/R account type.
Definition: Account.h:149
void xaccAccountSetSortReversed(Account *acc, gboolean sortreversed)
Set the account&#39;s Sort Order direction.
Definition: Account.cpp:2589
bank account type – don&#39;t use this for now, see NUM_ACCOUNT_TYPES
Definition: Account.h:169
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Account * xaccAccountGainsAccount(Account *acc, gnc_commodity *curr)
Retrieve the gains account used by this account for the indicated currency, creating and recording a ...
Definition: Account.cpp:4756
void xaccAccountSetLowerBalanceLimit(Account *acc, gnc_numeric balance)
Set the lower balance limit for the account.
Definition: Account.cpp:4678
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
Retrieve the &#39;unique&#39; name for the specified commodity.
gboolean xaccAccountGetHigherBalanceLimit(const Account *acc, gnc_numeric *balance)
Get the higher balance limit for the account.
Definition: Account.cpp:4658
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
Account * gnc_account_nth_child(const Account *parent, gint num)
Return the n&#39;th child account of the specified parent account.
Definition: Account.cpp:2943
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition: Account.cpp:1271
gint gnc_account_child_index(const Account *parent, const Account *child)
Return the index of the specified child within the list of the parent&#39;s children. ...
Definition: Account.cpp:2934
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:521
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void xaccAccountSetTaxUSPayerNameSource(Account *acc, const char *source)
DOCUMENT ME!
Definition: Account.cpp:4008
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition: gnc-lot.cpp:377
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:299
void xaccAccountSetDescription(Account *acc, const char *str)
Set the account&#39;s description.
Definition: Account.cpp:2462
void DxaccAccountSetCurrency(Account *acc, gnc_commodity *currency)
Definition: Account.cpp:2736
gpointer qof_collection_get_data(const QofCollection *col)
Store and retrieve arbitrary object-defined data.
Definition: qofid.cpp:289
void gnc_account_set_start_balance(Account *acc, const gnc_numeric start_baln)
This function will set the starting commodity balance for this account.
Definition: Account.cpp:3380
void xaccAccountSetNonStdSCU(Account *acc, gboolean flag)
Set the flag indicating that this account uses a non-standard SCU.
Definition: Account.cpp:2709
LotList * xaccAccountFindOpenLots(const Account *acc, gboolean(*match_func)(GNCLot *lot, gpointer user_data), gpointer user_data, GCompareFunc sort_func)
Find a list of open lots that match the match_func.
Definition: Account.cpp:3925
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:2893
Account * gnc_account_lookup_by_opening_balance(Account *account, gnc_commodity *commodity)
Find the opening balance account for the currency.
Definition: Account.cpp:3071
void xaccAccountClearHigherBalanceLimit(Account *acc)
Clear the higher balance limit for the account.
Definition: Account.cpp:4684
void gnc_account_set_defer_bal_computation(Account *acc, gboolean defer)
Set the defer balance flag.
Definition: Account.cpp:1893
gboolean qof_book_shutting_down(const QofBook *book)
Is the book shutting down?
Definition: qofbook.cpp:447
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3239
Equity account is used to balance the balance sheet.
Definition: Account.h:146
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
const char * xaccAccountGetTypeStr(GNCAccountType type)
The xaccAccountGetTypeStr() routine returns a string suitable for use in the GUI/Interface.
Definition: Account.cpp:4296
#define GNC_EVENT_ITEM_ADDED
These events are used when a split is added to an account.
Definition: gnc-event.h:45
const char * xaccAccountGetSortOrder(const Account *acc)
Get the account&#39;s Sort Order.
Definition: Account.cpp:3320
Not a type.
Definition: Account.h:105
#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)
The type used to store guids in C.
Definition: guid.h:75
int xaccAccountStagedTransactionTraversal(const Account *acc, unsigned int stage, TransactionCallback thunk, void *cb_data)
xaccAccountStagedTransactionTraversal() calls thunk on each transaction in account a whose current ma...
Definition: Account.cpp:5004
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1516
void xaccClearMark(Account *acc, short val)
Get the mark set by xaccAccountSetMark short xaccAccountGetMark (const Account *account);.
Definition: Account.cpp:2055
void xaccAccountSetName(Account *acc, const char *str)
Set the account&#39;s name.
Definition: Account.cpp:2423
The hidden root account of an account tree.
Definition: Account.h:153
gnc_commodity * gnc_commodity_obtain_twin(const gnc_commodity *from, QofBook *book)
Given the commodity &#39;findlike&#39;, this routine will find and return the equivalent commodity (commodity...
GNCPolicy * gnc_account_get_policy(Account *acc)
Get the account&#39;s lot order policy.
Definition: Account.cpp:2082
void qof_string_cache_remove(const char *key)
You can use this function as a destroy notifier for a GHashTable that uses common strings as keys (or...
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
void gnc_account_merge_children(Account *parent)
The gnc_account_merge_children() subroutine will go through an account, merging all child accounts th...
Definition: Account.cpp:4895
gboolean xaccAccountIsEquityType(GNCAccountType t)
Convenience function to check if the account is a valid Equity type.
Definition: Account.cpp:4478
void xaccAccountSetReconcileChildrenStatus(Account *acc, gboolean status)
DOCUMENT ME!
Definition: Account.cpp:4824
The Credit card account is used to denote credit (e.g.
Definition: Account.h:113
const gchar * gnc_get_account_separator_string(void)
Returns the account separation character chosen by the user.
Definition: Account.cpp:203
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Set the account&#39;s commodity.
Definition: Account.cpp:2629
#define NREC
not reconciled or cleared
Definition: Split.h:76
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:3138
const char * xaccAccountGetNotes(const Account *acc)
Get the account&#39;s notes.
Definition: Account.cpp:3332
gboolean xaccAccountGetReconcilePostponeBalance(const Account *acc, gnc_numeric *balance)
DOCUMENT ME!
Definition: Account.cpp:4587
gint gnc_account_get_tree_depth(const Account *account)
Return the number of levels of descendants accounts below the specified account.
Definition: Account.cpp:2979
GNCPolicy * xaccGetFIFOPolicy(void)
First-in, First-out Policy This policy will create FIFO Lots.
Definition: policy.cpp:155
Utility functions for file access.
Account * gnc_account_imap_find_account_bayes(Account *acc, GList *tokens)
Look up an Account in the map.
Definition: Account.cpp:5459
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2032
void xaccAccountSetTaxUSCopyNumber(Account *acc, gint64 copy_number)
DOCUMENT ME!
Definition: Account.cpp:4021