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 std::vector<const Account*>
3246 gnc_account_get_all_parents (const Account *account)
3247 {
3248  std::vector<const Account*> rv;
3249  for (auto a = account; !gnc_account_is_root (a); a = gnc_account_get_parent (a))
3250  rv.push_back (a);
3251  return rv;
3252 }
3253 
3254 gchar *
3256 {
3257  /* So much for hardening the API. Too many callers to this function don't
3258  * bother to check if they have a non-nullptr pointer before calling. */
3259  if (nullptr == account)
3260  return g_strdup("");
3261 
3262  /* errors */
3263  g_return_val_if_fail(GNC_IS_ACCOUNT(account), g_strdup(""));
3264 
3265  auto path{gnc_account_get_all_parents (account)};
3266  auto seps_size{path.empty() ? 0 : strlen (account_separator) * (path.size() - 1)};
3267  auto alloc_size{std::accumulate (path.begin(), path.end(), seps_size,
3268  [](auto sum, auto acc)
3269  { return sum + strlen (xaccAccountGetName (acc)); })};
3270  auto rv = g_new (char, alloc_size + 1);
3271  auto p = rv;
3272 
3273  std::for_each (path.rbegin(), path.rend(),
3274  [&p, rv](auto a)
3275  {
3276  if (p != rv)
3277  p = stpcpy (p, account_separator);
3278  p = stpcpy (p, xaccAccountGetName (a));
3279  });
3280  *p = '\0';
3281 
3282  return rv;
3283 }
3284 
3285 const char *
3287 {
3288  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3289  return GET_PRIVATE(acc)->accountCode;
3290 }
3291 
3292 const char *
3294 {
3295  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3296  return GET_PRIVATE(acc)->description;
3297 }
3298 
3299 const char *
3301 {
3302  return get_kvp_string_path (acc, {"color"});
3303 }
3304 
3305 const char *
3307 {
3308  return get_kvp_string_path (acc, {"filter"});
3309 }
3310 
3311 const char *
3313 {
3314  return get_kvp_string_path (acc, {"sort-order"});
3315 }
3316 
3317 gboolean
3319 {
3320  return get_kvp_boolean_path (acc, {"sort-reversed"});
3321 }
3322 
3323 const char *
3325 {
3326  return get_kvp_string_path (acc, {"notes"});
3327 }
3328 
3329 Account*
3330 xaccAccountGetAssociatedAccount (const Account *acc, const char *tag)
3331 {
3332  g_return_val_if_fail (tag && *tag, nullptr);
3333 
3334  return get_kvp_account_path (acc, {"associated-account", tag});
3335 }
3336 
3337 
3338 gnc_commodity *
3340 {
3341  if (auto s = get_kvp_string_path (acc, {"old-currency"}))
3342  {
3344  return gnc_commodity_table_lookup_unique (table, s);
3345  }
3346 
3347  return nullptr;
3348 }
3349 
3350 gnc_commodity *
3352 {
3353  if (!GNC_IS_ACCOUNT(acc))
3354  return nullptr;
3355  return GET_PRIVATE(acc)->commodity;
3356 }
3357 
3358 gnc_commodity * gnc_account_get_currency_or_parent(const Account* account)
3359 {
3360  g_return_val_if_fail (GNC_IS_ACCOUNT (account), nullptr);
3361 
3362  for (auto acc = account; acc; acc = gnc_account_get_parent (acc))
3363  if (auto comm = xaccAccountGetCommodity (acc); gnc_commodity_is_currency (comm))
3364  return comm;
3365 
3366  return nullptr; // no suitable commodity found.
3367 }
3368 
3369 /********************************************************************\
3370 \********************************************************************/
3371 void
3372 gnc_account_set_start_balance (Account *acc, const gnc_numeric start_baln)
3373 {
3374  AccountPrivate *priv;
3375 
3376  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3377 
3378  priv = GET_PRIVATE(acc);
3379  priv->starting_balance = start_baln;
3380  priv->balance_dirty = TRUE;
3381 }
3382 
3383 void
3385  const gnc_numeric start_baln)
3386 {
3387  AccountPrivate *priv;
3388 
3389  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3390 
3391  priv = GET_PRIVATE(acc);
3392  priv->starting_cleared_balance = start_baln;
3393  priv->balance_dirty = TRUE;
3394 }
3395 
3396 void
3398  const gnc_numeric start_baln)
3399 {
3400  AccountPrivate *priv;
3401 
3402  g_return_if_fail(GNC_IS_ACCOUNT(acc));
3403 
3404  priv = GET_PRIVATE(acc);
3405  priv->starting_reconciled_balance = start_baln;
3406  priv->balance_dirty = TRUE;
3407 }
3408 
3409 gnc_numeric
3411 {
3412  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3413  return GET_PRIVATE(acc)->balance;
3414 }
3415 
3416 gnc_numeric
3418 {
3419  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3420  return GET_PRIVATE(acc)->cleared_balance;
3421 }
3422 
3423 gnc_numeric
3425 {
3426  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3427  return GET_PRIVATE(acc)->reconciled_balance;
3428 }
3429 
3430 gnc_numeric
3431 xaccAccountGetProjectedMinimumBalance (const Account *acc)
3432 {
3433  auto today{gnc_time64_get_today_end()};
3434  std::optional<gnc_numeric> minimum;
3435 
3436  auto before_today_end = [&minimum, today](const Split *s) -> bool
3437  {
3438  auto bal{xaccSplitGetBalance(s)};
3439  if (!minimum || gnc_numeric_compare (bal, *minimum) < 0)
3440  minimum = bal;
3441  return (xaccTransGetDate(xaccSplitGetParent(s)) < today);
3442  };
3443  // scan to find today's split, but we're really interested in the
3444  // minimum balance
3445  [[maybe_unused]] auto todays_split = gnc_account_find_split (acc, before_today_end, true);
3446  return minimum ? *minimum : gnc_numeric_zero();
3447 }
3448 
3449 
3450 /********************************************************************\
3451 \********************************************************************/
3452 
3453 static gnc_numeric
3454 GetBalanceAsOfDate (Account *acc, time64 date, std::function<gnc_numeric(Split*)> split_to_numeric)
3455 {
3456  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3457 
3458  xaccAccountSortSplits (acc, TRUE); /* just in case, normally a noop */
3459  xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */
3460 
3461  auto is_before_date = [date](auto s) -> bool
3462  { return xaccTransGetDate(xaccSplitGetParent(s)) < date; };
3463 
3464  auto latest_split{gnc_account_find_split (acc, is_before_date, true)};
3465  return latest_split ? split_to_numeric (latest_split) : gnc_numeric_zero();
3466 }
3467 
3468 gnc_numeric
3470 {
3471  return GetBalanceAsOfDate (acc, date, xaccSplitGetBalance);
3472 }
3473 
3474 static gnc_numeric
3475 xaccAccountGetNoclosingBalanceAsOfDate (Account *acc, time64 date)
3476 {
3477  return GetBalanceAsOfDate (acc, date, xaccSplitGetNoclosingBalance);
3478 }
3479 
3480 gnc_numeric
3482 {
3483  return GetBalanceAsOfDate (acc, date, xaccSplitGetReconciledBalance);
3484 }
3485 
3486 /*
3487  * Originally gsr_account_present_balance in gnc-split-reg.c
3488  */
3489 gnc_numeric
3490 xaccAccountGetPresentBalance (const Account *acc)
3491 {
3492  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3493 
3494  return xaccAccountGetBalanceAsOfDate (GNC_ACCOUNT (acc),
3496 }
3497 
3498 
3499 /********************************************************************\
3500 \********************************************************************/
3501 /* XXX TODO: These 'GetBal' routines should be moved to some
3502  * utility area outside of the core account engine area.
3503  */
3504 
3505 /*
3506  * Convert a balance from one currency to another.
3507  */
3508 gnc_numeric
3509 xaccAccountConvertBalanceToCurrency(const Account *acc, /* for book */
3510  gnc_numeric balance,
3511  const gnc_commodity *balance_currency,
3512  const gnc_commodity *new_currency)
3513 {
3514  QofBook *book;
3515  GNCPriceDB *pdb;
3516 
3517  if (gnc_numeric_zero_p (balance) ||
3518  gnc_commodity_equiv (balance_currency, new_currency))
3519  return balance;
3520 
3521  book = gnc_account_get_book (acc);
3522  pdb = gnc_pricedb_get_db (book);
3523 
3525  pdb, balance, balance_currency, new_currency);
3526 
3527  return balance;
3528 }
3529 
3530 /*
3531  * Convert a balance from one currency to another with price of
3532  * a given date.
3533  */
3534 gnc_numeric
3535 xaccAccountConvertBalanceToCurrencyAsOfDate(const Account *acc, /* for book */
3536  gnc_numeric balance,
3537  const gnc_commodity *balance_currency,
3538  const gnc_commodity *new_currency,
3539  time64 date)
3540 {
3541  QofBook *book;
3542  GNCPriceDB *pdb;
3543 
3544  if (gnc_numeric_zero_p (balance) ||
3545  gnc_commodity_equiv (balance_currency, new_currency))
3546  return balance;
3547 
3548  book = gnc_account_get_book (acc);
3549  pdb = gnc_pricedb_get_db (book);
3550 
3552  pdb, balance, balance_currency, new_currency, date);
3553 
3554  return balance;
3555 }
3556 
3557 /*
3558  * Given an account and a GetBalanceFn pointer, extract the requested
3559  * balance from the account and then convert it to the desired
3560  * currency.
3561  */
3562 static gnc_numeric
3563 xaccAccountGetXxxBalanceInCurrency (const Account *acc,
3564  xaccGetBalanceFn fn,
3565  const gnc_commodity *report_currency)
3566 {
3567  AccountPrivate *priv;
3568  gnc_numeric balance;
3569 
3570  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3571  g_return_val_if_fail(fn, gnc_numeric_zero());
3572  g_return_val_if_fail(GNC_IS_COMMODITY(report_currency), gnc_numeric_zero());
3573 
3574  priv = GET_PRIVATE(acc);
3575  balance = fn(acc);
3576  balance = xaccAccountConvertBalanceToCurrency(acc, balance,
3577  priv->commodity,
3578  report_currency);
3579  return balance;
3580 }
3581 
3582 static gnc_numeric
3583 xaccAccountGetXxxBalanceAsOfDateInCurrency(Account *acc, time64 date,
3584  xaccGetBalanceAsOfDateFn fn,
3585  const gnc_commodity *report_commodity)
3586 {
3587  AccountPrivate *priv;
3588 
3589  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3590  g_return_val_if_fail(fn, gnc_numeric_zero());
3591  g_return_val_if_fail(GNC_IS_COMMODITY(report_commodity), gnc_numeric_zero());
3592 
3593  priv = GET_PRIVATE(acc);
3594  return xaccAccountConvertBalanceToCurrencyAsOfDate(
3595  acc, fn(acc, date), priv->commodity, report_commodity, date);
3596 }
3597 
3598 /*
3599  * Data structure used to pass various arguments into the following fn.
3600  */
3601 typedef struct
3602 {
3603  const gnc_commodity *currency;
3604  gnc_numeric balance;
3605  xaccGetBalanceFn fn;
3606  xaccGetBalanceAsOfDateFn asOfDateFn;
3607  time64 date;
3608 } CurrencyBalance;
3609 
3610 
3611 /*
3612  * A helper function for iterating over all the accounts in a list or
3613  * tree. This function is called once per account, and sums up the
3614  * values of all these accounts.
3615  */
3616 static void
3617 xaccAccountBalanceHelper (Account *acc, gpointer data)
3618 {
3619  CurrencyBalance *cb = static_cast<CurrencyBalance*>(data);
3620  gnc_numeric balance;
3621 
3622  if (!cb->fn || !cb->currency)
3623  return;
3624  balance = xaccAccountGetXxxBalanceInCurrency (acc, cb->fn, cb->currency);
3625  cb->balance = gnc_numeric_add (cb->balance, balance,
3626  gnc_commodity_get_fraction (cb->currency),
3628 }
3629 
3630 static void
3631 xaccAccountBalanceAsOfDateHelper (Account *acc, gpointer data)
3632 {
3633  CurrencyBalance *cb = static_cast<CurrencyBalance*>(data);
3634  gnc_numeric balance;
3635 
3636  g_return_if_fail (cb->asOfDateFn && cb->currency);
3637 
3638  balance = xaccAccountGetXxxBalanceAsOfDateInCurrency (
3639  acc, cb->date, cb->asOfDateFn, cb->currency);
3640  cb->balance = gnc_numeric_add (cb->balance, balance,
3641  gnc_commodity_get_fraction (cb->currency),
3643 }
3644 
3645 
3646 
3647 /*
3648  * Common function that iterates recursively over all accounts below
3649  * the specified account. It uses xaccAccountBalanceHelper to sum up
3650  * the balances of all its children, and uses the specified function
3651  * 'fn' for extracting the balance. This function may extract the
3652  * current value, the reconciled value, etc.
3653  *
3654  * If 'report_commodity' is nullptr, just use the account's commodity.
3655  * If 'include_children' is FALSE, this function doesn't recurse at all.
3656  */
3657 static gnc_numeric
3658 xaccAccountGetXxxBalanceInCurrencyRecursive (const Account *acc,
3659  xaccGetBalanceFn fn,
3660  const gnc_commodity *report_commodity,
3661  gboolean include_children)
3662 {
3663  gnc_numeric balance;
3664 
3665  if (!acc) return gnc_numeric_zero ();
3666  if (!report_commodity)
3667  report_commodity = xaccAccountGetCommodity (acc);
3668  if (!report_commodity)
3669  return gnc_numeric_zero();
3670 
3671  balance = xaccAccountGetXxxBalanceInCurrency (acc, fn, report_commodity);
3672 
3673  /* If needed, sum up the children converting to the *requested*
3674  commodity. */
3675  if (include_children)
3676  {
3677 #ifdef _MSC_VER
3678  /* MSVC compiler: Somehow, the struct initialization containing a
3679  gnc_numeric doesn't work. As an exception, we hand-initialize
3680  that member afterwards. */
3681  CurrencyBalance cb = { report_commodity, { 0 }, fn, nullptr, 0 };
3682  cb.balance = balance;
3683 #else
3684  CurrencyBalance cb = { report_commodity, balance, fn, nullptr, 0 };
3685 #endif
3686 
3687  gnc_account_foreach_descendant (acc, xaccAccountBalanceHelper, &cb);
3688  balance = cb.balance;
3689  }
3690 
3691  return balance;
3692 }
3693 
3694 static gnc_numeric
3695 xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3696  Account *acc, time64 date, xaccGetBalanceAsOfDateFn fn,
3697  const gnc_commodity *report_commodity, gboolean include_children)
3698 {
3699  gnc_numeric balance;
3700 
3701  g_return_val_if_fail(acc, gnc_numeric_zero());
3702  if (!report_commodity)
3703  report_commodity = xaccAccountGetCommodity (acc);
3704  if (!report_commodity)
3705  return gnc_numeric_zero();
3706 
3707  balance = xaccAccountGetXxxBalanceAsOfDateInCurrency(
3708  acc, date, fn, report_commodity);
3709 
3710  /* If needed, sum up the children converting to the *requested*
3711  commodity. */
3712  if (include_children)
3713  {
3714 #ifdef _MSC_VER
3715  /* MSVC compiler: Somehow, the struct initialization containing a
3716  gnc_numeric doesn't work. As an exception, we hand-initialize
3717  that member afterwards. */
3718  CurrencyBalance cb = { report_commodity, 0, nullptr, fn, date };
3719  cb.balance = balance;
3720 #else
3721  CurrencyBalance cb = { report_commodity, balance, nullptr, fn, date };
3722 #endif
3723 
3724  gnc_account_foreach_descendant (acc, xaccAccountBalanceAsOfDateHelper, &cb);
3725  balance = cb.balance;
3726  }
3727 
3728  return balance;
3729 }
3730 
3731 gnc_numeric
3732 xaccAccountGetBalanceInCurrency (const Account *acc,
3733  const gnc_commodity *report_commodity,
3734  gboolean include_children)
3735 {
3736  gnc_numeric rc;
3737  rc = xaccAccountGetXxxBalanceInCurrencyRecursive (
3738  acc, xaccAccountGetBalance, report_commodity, include_children);
3739  PINFO(" baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, rc.num, rc.denom);
3740  return rc;
3741 }
3742 
3743 
3744 gnc_numeric
3745 xaccAccountGetClearedBalanceInCurrency (const Account *acc,
3746  const gnc_commodity *report_commodity,
3747  gboolean include_children)
3748 {
3749  return xaccAccountGetXxxBalanceInCurrencyRecursive (
3750  acc, xaccAccountGetClearedBalance, report_commodity,
3751  include_children);
3752 }
3753 
3754 gnc_numeric
3755 xaccAccountGetReconciledBalanceInCurrency (const Account *acc,
3756  const gnc_commodity *report_commodity,
3757  gboolean include_children)
3758 {
3759  return xaccAccountGetXxxBalanceInCurrencyRecursive (
3760  acc, xaccAccountGetReconciledBalance, report_commodity,
3761  include_children);
3762 }
3763 
3764 gnc_numeric
3765 xaccAccountGetPresentBalanceInCurrency (const Account *acc,
3766  const gnc_commodity *report_commodity,
3767  gboolean include_children)
3768 {
3769  return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3771  report_commodity,
3772  include_children);
3773 }
3774 
3775 gnc_numeric
3776 xaccAccountGetProjectedMinimumBalanceInCurrency (
3777  const Account *acc,
3778  const gnc_commodity *report_commodity,
3779  gboolean include_children)
3780 {
3781  return xaccAccountGetXxxBalanceInCurrencyRecursive (
3782  acc, xaccAccountGetProjectedMinimumBalance, report_commodity,
3783  include_children);
3784 }
3785 
3786 gnc_numeric
3788  Account *acc, time64 date, gnc_commodity *report_commodity,
3789  gboolean include_children)
3790 {
3791  return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3792  acc, date, xaccAccountGetBalanceAsOfDate, report_commodity,
3793  include_children);
3794 }
3795 
3796 gnc_numeric
3798  Account *acc, time64 date, gnc_commodity *report_commodity,
3799  gboolean include_children)
3800 {
3801  return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive
3802  (acc, date, xaccAccountGetNoclosingBalanceAsOfDate,
3803  report_commodity, include_children);
3804 }
3805 
3806 gnc_numeric
3807 xaccAccountGetBalanceChangeForPeriod (Account *acc, time64 t1, time64 t2,
3808  gboolean recurse)
3809 {
3810  gnc_numeric b1, b2;
3811 
3812  b1 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t1, nullptr, recurse);
3813  b2 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t2, nullptr, recurse);
3815 }
3816 
3817 gnc_numeric
3818 xaccAccountGetNoclosingBalanceChangeForPeriod (Account *acc, time64 t1,
3819  time64 t2, gboolean recurse)
3820 {
3821  gnc_numeric b1, b2;
3822 
3823  b1 = xaccAccountGetNoclosingBalanceAsOfDateInCurrency(acc, t1, nullptr, recurse);
3824  b2 = xaccAccountGetNoclosingBalanceAsOfDateInCurrency(acc, t2, nullptr, recurse);
3826 }
3827 
3828 typedef struct
3829 {
3830  const gnc_commodity *currency;
3831  gnc_numeric balanceChange;
3832  time64 t1;
3833  time64 t2;
3835 
3836 static void
3837 xaccAccountBalanceChangeHelper (Account *acc, gpointer data)
3838 {
3839  CurrencyBalanceChange *cbdiff = static_cast<CurrencyBalanceChange*>(data);
3840 
3841  gnc_numeric b1, b2;
3842  b1 = GetBalanceAsOfDate(acc, cbdiff->t1, xaccSplitGetNoclosingBalance);
3843  b2 = GetBalanceAsOfDate(acc, cbdiff->t2, xaccSplitGetNoclosingBalance);
3844  gnc_numeric balanceChange = gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
3845  gnc_numeric balanceChange_conv = xaccAccountConvertBalanceToCurrencyAsOfDate(acc, balanceChange, xaccAccountGetCommodity(acc), cbdiff->currency, cbdiff->t2);
3846  cbdiff->balanceChange = gnc_numeric_add (cbdiff->balanceChange, balanceChange_conv,
3847  gnc_commodity_get_fraction (cbdiff->currency),
3849 }
3850 
3851 gnc_numeric
3852 xaccAccountGetNoclosingBalanceChangeInCurrencyForPeriod (Account *acc, time64 t1,
3853  time64 t2, gboolean recurse)
3854 {
3855 
3856 
3857  gnc_numeric b1, b2;
3858  b1 = GetBalanceAsOfDate(acc, t1, xaccSplitGetNoclosingBalance);
3859  b2 = GetBalanceAsOfDate(acc, t2, xaccSplitGetNoclosingBalance);
3860  gnc_numeric balanceChange = gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
3861 
3862  gnc_commodity *report_commodity = xaccAccountGetCommodity(acc);
3863  CurrencyBalanceChange cbdiff = { report_commodity, balanceChange, t1, t2 };
3864 
3865  if(recurse)
3866  {
3867  gnc_account_foreach_descendant (acc, xaccAccountBalanceChangeHelper, &cbdiff);
3868  balanceChange = cbdiff.balanceChange;
3869  }
3870  return balanceChange;
3871 }
3872 
3873 /********************************************************************\
3874 \********************************************************************/
3875 
3876 const SplitsVec&
3877 xaccAccountGetSplits (const Account *account)
3878 {
3879  static const SplitsVec empty;
3880  g_return_val_if_fail (GNC_IS_ACCOUNT(account), empty);
3881  return GET_PRIVATE(account)->splits;
3882 }
3883 
3884 SplitList *
3886 {
3887  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3888  auto priv{GET_PRIVATE(acc)};
3889  return std::accumulate (priv->splits.rbegin(), priv->splits.rend(),
3890  static_cast<GList*>(nullptr), g_list_prepend);
3891 }
3892 
3893 size_t
3894 xaccAccountGetSplitsSize (const Account *account)
3895 {
3896  g_return_val_if_fail (GNC_IS_ACCOUNT(account), 0);
3897  return GNC_IS_ACCOUNT(account) ? GET_PRIVATE(account)->splits.size() : 0;
3898 }
3899 
3900 gboolean gnc_account_and_descendants_empty (Account *acc)
3901 {
3902  g_return_val_if_fail (GNC_IS_ACCOUNT (acc), FALSE);
3903  auto priv = GET_PRIVATE (acc);
3904  if (!priv->splits.empty()) return FALSE;
3905  return std::all_of (priv->children.begin(), priv->children.end(),
3906  gnc_account_and_descendants_empty);
3907 }
3908 
3909 LotList *
3911 {
3912  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3913  return g_list_copy(GET_PRIVATE(acc)->lots);
3914 }
3915 
3916 LotList *
3918  gboolean (*match_func)(GNCLot *lot,
3919  gpointer user_data),
3920  gpointer user_data, GCompareFunc sort_func)
3921 {
3922  AccountPrivate *priv;
3923  GList *lot_list;
3924  GList *retval = nullptr;
3925 
3926  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3927 
3928  priv = GET_PRIVATE(acc);
3929  for (lot_list = priv->lots; lot_list; lot_list = lot_list->next)
3930  {
3931  GNCLot *lot = static_cast<GNCLot*>(lot_list->data);
3932 
3933  /* If this lot is closed, then ignore it */
3934  if (gnc_lot_is_closed (lot))
3935  continue;
3936 
3937  if (match_func && !(match_func)(lot, user_data))
3938  continue;
3939 
3940  /* Ok, this is a valid lot. Add it to our list of lots */
3941  retval = g_list_prepend (retval, lot);
3942  }
3943 
3944  if (sort_func)
3945  retval = g_list_sort (retval, sort_func);
3946 
3947  return retval;
3948 }
3949 
3950 gpointer
3951 xaccAccountForEachLot(const Account *acc,
3952  gpointer (*proc)(GNCLot *lot, void *data), void *data)
3953 {
3954  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), nullptr);
3955  g_return_val_if_fail(proc, nullptr);
3956 
3957  for (auto node = GET_PRIVATE(acc)->lots; node; node = node->next)
3958  if (auto result = proc(GNC_LOT(node->data), data))
3959  return result;
3960 
3961  return nullptr;
3962 }
3963 
3964 
3965 /********************************************************************\
3966 \********************************************************************/
3967 
3968 /* These functions use interchange gint64 and gboolean. Is that right? */
3969 gboolean
3971 {
3972  return get_kvp_boolean_path(acc, {"tax-related"});
3973 }
3974 
3975 void
3976 xaccAccountSetTaxRelated (Account *acc, gboolean tax_related)
3977 {
3978  set_kvp_boolean_path(acc, {"tax-related"}, tax_related);
3979 }
3980 
3981 const char *
3983 {
3984  return get_kvp_string_path (acc, {"tax-US", "code"});
3985 }
3986 
3987 void
3988 xaccAccountSetTaxUSCode (Account *acc, const char *code)
3989 {
3990  set_kvp_string_path (acc, {"tax-US", "code"}, code);
3991 }
3992 
3993 const char *
3995 {
3996  return get_kvp_string_path (acc, {"tax-US", "payer-name-source"});
3997 }
3998 
3999 void
4001 {
4002  set_kvp_string_path (acc, {"tax-US", "payer-name-source"}, source);
4003 }
4004 
4005 gint64
4007 {
4008  auto copy_number = get_kvp_int64_path (acc, {"tax-US", "copy-number"});
4009  return copy_number ? *copy_number : 1;
4010 }
4011 
4012 void
4013 xaccAccountSetTaxUSCopyNumber (Account *acc, gint64 copy_number)
4014 {
4015  set_kvp_int64_path (acc, {"tax-US", "copy-number"}, copy_number);
4016 }
4017 
4018 /*********************************************************************\
4019 \ ********************************************************************/
4020 
4021 
4023 {
4024  if (gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS))
4025  return _(dflt_acct_debit_str);
4026 
4027  auto result = gnc_acct_debit_strs.find(acct_type);
4028  if (result != gnc_acct_debit_strs.end())
4029  return _(result->second);
4030  else
4031  return _(dflt_acct_debit_str);
4032 }
4033 
4035 {
4036  if (gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS))
4037  return _(dflt_acct_credit_str);
4038 
4039  auto result = gnc_acct_credit_strs.find(acct_type);
4040  if (result != gnc_acct_credit_strs.end())
4041  return _(result->second);
4042  else
4043  return _(dflt_acct_credit_str);
4044 }
4045 
4046 /********************************************************************\
4047 \********************************************************************/
4048 
4049 gboolean
4051 {
4052  return get_kvp_boolean_path(acc, {"placeholder"});
4053 }
4054 
4055 void
4057 {
4058  set_kvp_boolean_path(acc, {"placeholder"}, val);
4059 }
4060 
4061 gboolean
4063 {
4064  return get_kvp_boolean_path(acc, {"import-append-text"});
4065 }
4066 
4067 void
4068 xaccAccountSetAppendText (Account *acc, gboolean val)
4069 {
4070  set_kvp_boolean_path(acc, {"import-append-text"}, val);
4071 }
4072 
4073 gboolean
4075 {
4076  g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false);
4077  if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
4078  return false;
4079 
4080  return !g_strcmp0 (get_kvp_string_path (acc, {"equity-type"}), "opening-balance");
4081 }
4082 
4083 void
4085 {
4086  g_return_if_fail (GNC_IS_ACCOUNT(acc));
4087  if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
4088  return;
4089  set_kvp_string_path(acc, {"equity-type"}, val ? "opening-balance" : nullptr);
4090 }
4091 
4094 {
4095  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), PLACEHOLDER_NONE);
4096  if (xaccAccountGetPlaceholder(acc)) return PLACEHOLDER_THIS;
4097 
4098  return gnc_account_foreach_descendant_until (acc, (AccountCb2)xaccAccountGetPlaceholder, nullptr)
4099  ? PLACEHOLDER_CHILD : PLACEHOLDER_NONE;
4100 }
4101 
4102 /********************************************************************\
4103  \********************************************************************/
4104 
4105 gboolean
4107 {
4108  return get_kvp_boolean_path (acc, {KEY_RECONCILE_INFO, "auto-interest-transfer"});
4109 }
4110 
4111 void
4113 {
4114  set_kvp_boolean_path (acc, {KEY_RECONCILE_INFO, "auto-interest-transfer"}, val);
4115 }
4116 
4117 /********************************************************************\
4118 \********************************************************************/
4119 
4120 gboolean
4122 {
4123  return get_kvp_boolean_path (acc, {"hidden"});
4124 }
4125 
4126 void
4127 xaccAccountSetHidden (Account *acc, gboolean val)
4128 {
4129  set_kvp_boolean_path (acc, {"hidden"}, val);
4130 }
4131 
4132 gboolean
4134 {
4135  AccountPrivate *priv;
4136 
4137  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4138 
4139  if (xaccAccountGetHidden(acc))
4140  return TRUE;
4141  priv = GET_PRIVATE(acc);
4142  while ((acc = priv->parent) != nullptr)
4143  {
4144  priv = GET_PRIVATE(acc);
4145  if (xaccAccountGetHidden(acc))
4146  return TRUE;
4147  }
4148  return FALSE;
4149 }
4150 
4151 /********************************************************************\
4152 \********************************************************************/
4153 
4154 gboolean
4155 xaccAccountHasAncestor (const Account *acc, const Account * ancestor)
4156 {
4157  const Account *parent;
4158 
4159  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4160  g_return_val_if_fail(GNC_IS_ACCOUNT(ancestor), FALSE);
4161 
4162  parent = acc;
4163  while (parent && parent != ancestor)
4164  parent = GET_PRIVATE(parent)->parent;
4165 
4166  return (parent == ancestor);
4167 }
4168 
4169 /********************************************************************\
4170 \********************************************************************/
4171 
4172 /* You must edit the functions in this block in tandem. KEEP THEM IN
4173  SYNC! */
4174 
4175 #define GNC_RETURN_ENUM_AS_STRING(x) case (ACCT_TYPE_ ## x): return #x;
4176 
4177 const char *
4179 {
4180  switch (type)
4181  {
4182  GNC_RETURN_ENUM_AS_STRING(NONE);
4183  GNC_RETURN_ENUM_AS_STRING(BANK);
4184  GNC_RETURN_ENUM_AS_STRING(CASH);
4185  GNC_RETURN_ENUM_AS_STRING(CREDIT);
4186  GNC_RETURN_ENUM_AS_STRING(ASSET);
4187  GNC_RETURN_ENUM_AS_STRING(LIABILITY);
4188  GNC_RETURN_ENUM_AS_STRING(STOCK);
4189  GNC_RETURN_ENUM_AS_STRING(MUTUAL);
4190  GNC_RETURN_ENUM_AS_STRING(CURRENCY);
4191  GNC_RETURN_ENUM_AS_STRING(INCOME);
4192  GNC_RETURN_ENUM_AS_STRING(EXPENSE);
4193  GNC_RETURN_ENUM_AS_STRING(EQUITY);
4194  GNC_RETURN_ENUM_AS_STRING(RECEIVABLE);
4195  GNC_RETURN_ENUM_AS_STRING(PAYABLE);
4196  GNC_RETURN_ENUM_AS_STRING(ROOT);
4197  GNC_RETURN_ENUM_AS_STRING(TRADING);
4198  GNC_RETURN_ENUM_AS_STRING(CHECKING);
4199  GNC_RETURN_ENUM_AS_STRING(SAVINGS);
4200  GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
4201  GNC_RETURN_ENUM_AS_STRING(CREDITLINE);
4202  default:
4203  PERR ("asked to translate unknown account type %d.\n", type);
4204  break;
4205  }
4206  return(nullptr);
4207 }
4208 
4209 #undef GNC_RETURN_ENUM_AS_STRING
4210 
4211 #define GNC_RETURN_ON_MATCH(x) \
4212  if(g_strcmp0(#x, (str)) == 0) { *type = ACCT_TYPE_ ## x; return(TRUE); }
4213 
4214 gboolean
4216 {
4217 
4218  GNC_RETURN_ON_MATCH(NONE);
4219  GNC_RETURN_ON_MATCH(BANK);
4220  GNC_RETURN_ON_MATCH(CASH);
4221  GNC_RETURN_ON_MATCH(CREDIT);
4222  GNC_RETURN_ON_MATCH(ASSET);
4223  GNC_RETURN_ON_MATCH(LIABILITY);
4224  GNC_RETURN_ON_MATCH(STOCK);
4225  GNC_RETURN_ON_MATCH(MUTUAL);
4226  GNC_RETURN_ON_MATCH(CURRENCY);
4227  GNC_RETURN_ON_MATCH(INCOME);
4228  GNC_RETURN_ON_MATCH(EXPENSE);
4229  GNC_RETURN_ON_MATCH(EQUITY);
4230  GNC_RETURN_ON_MATCH(RECEIVABLE);
4231  GNC_RETURN_ON_MATCH(PAYABLE);
4232  GNC_RETURN_ON_MATCH(ROOT);
4233  GNC_RETURN_ON_MATCH(TRADING);
4234  GNC_RETURN_ON_MATCH(CHECKING);
4235  GNC_RETURN_ON_MATCH(SAVINGS);
4236  GNC_RETURN_ON_MATCH(MONEYMRKT);
4237  GNC_RETURN_ON_MATCH(CREDITLINE);
4238 
4239  PERR("asked to translate unknown account type string %s.\n",
4240  str ? str : "(null)");
4241 
4242  return(FALSE);
4243 }
4244 
4245 #undef GNC_RETURN_ON_MATCH
4246 
4247 /* impedance mismatch is a source of loss */
4249 xaccAccountStringToEnum(const char* str)
4250 {
4251  GNCAccountType type;
4252  gboolean rc;
4253  rc = xaccAccountStringToType(str, &type);
4254  if (FALSE == rc) return ACCT_TYPE_INVALID;
4255  return type;
4256 }
4257 
4258 /********************************************************************\
4259 \********************************************************************/
4260 
4261 static char const *
4262 account_type_name[NUM_ACCOUNT_TYPES] =
4263 {
4264  N_("Bank"),
4265  N_("Cash"),
4266  N_("Asset"),
4267  N_("Credit Card"),
4268  N_("Liability"),
4269  N_("Stock"),
4270  N_("Mutual Fund"),
4271  N_("Currency"),
4272  N_("Income"),
4273  N_("Expense"),
4274  N_("Equity"),
4275  N_("A/Receivable"),
4276  N_("A/Payable"),
4277  N_("Root"),
4278  N_("Trading")
4279  /*
4280  N_("Checking"),
4281  N_("Savings"),
4282  N_("Money Market"),
4283  N_("Credit Line")
4284  */
4285 };
4286 
4287 const char *
4289 {
4290  if (type < 0 || NUM_ACCOUNT_TYPES <= type ) return "";
4291  return _(account_type_name [type]);
4292 }
4293 
4294 /********************************************************************\
4295 \********************************************************************/
4296 
4297 guint32
4299 {
4300  switch (type)
4301  {
4302  case ACCT_TYPE_BANK:
4303  case ACCT_TYPE_CASH:
4304  case ACCT_TYPE_ASSET:
4305  case ACCT_TYPE_CREDIT:
4306  case ACCT_TYPE_LIABILITY:
4307  case ACCT_TYPE_INCOME:
4308  case ACCT_TYPE_EXPENSE:
4309  case ACCT_TYPE_EQUITY:
4310  return
4311  (1 << ACCT_TYPE_BANK) |
4312  (1 << ACCT_TYPE_CASH) |
4313  (1 << ACCT_TYPE_ASSET) |
4314  (1 << ACCT_TYPE_CREDIT) |
4315  (1 << ACCT_TYPE_LIABILITY) |
4316  (1 << ACCT_TYPE_INCOME) |
4317  (1 << ACCT_TYPE_EXPENSE) |
4318  (1 << ACCT_TYPE_EQUITY);
4319  case ACCT_TYPE_STOCK:
4320  case ACCT_TYPE_MUTUAL:
4321  case ACCT_TYPE_CURRENCY:
4322  return
4323  (1 << ACCT_TYPE_STOCK) |
4324  (1 << ACCT_TYPE_MUTUAL) |
4325  (1 << ACCT_TYPE_CURRENCY);
4326  case ACCT_TYPE_RECEIVABLE:
4327  return (1 << ACCT_TYPE_RECEIVABLE);
4328  case ACCT_TYPE_PAYABLE:
4329  return (1 << ACCT_TYPE_PAYABLE);
4330  case ACCT_TYPE_TRADING:
4331  return (1 << ACCT_TYPE_TRADING);
4332  default:
4333  PERR("bad account type: %d", type);
4334  return 0;
4335  }
4336 }
4337 guint32
4339 {
4340  switch (type)
4341  {
4342  case ACCT_TYPE_BANK:
4343  case ACCT_TYPE_CASH:
4344  case ACCT_TYPE_ASSET:
4345  case ACCT_TYPE_STOCK:
4346  case ACCT_TYPE_MUTUAL:
4347  case ACCT_TYPE_CURRENCY:
4348  case ACCT_TYPE_CREDIT:
4349  case ACCT_TYPE_LIABILITY:
4350  case ACCT_TYPE_RECEIVABLE:
4351  case ACCT_TYPE_PAYABLE:
4352  return
4353  (1 << ACCT_TYPE_BANK) |
4354  (1 << ACCT_TYPE_CASH) |
4355  (1 << ACCT_TYPE_ASSET) |
4356  (1 << ACCT_TYPE_STOCK) |
4357  (1 << ACCT_TYPE_MUTUAL) |
4358  (1 << ACCT_TYPE_CURRENCY) |
4359  (1 << ACCT_TYPE_CREDIT) |
4360  (1 << ACCT_TYPE_LIABILITY) |
4361  (1 << ACCT_TYPE_RECEIVABLE) |
4362  (1 << ACCT_TYPE_PAYABLE) |
4363  (1 << ACCT_TYPE_ROOT);
4364  case ACCT_TYPE_INCOME:
4365  case ACCT_TYPE_EXPENSE:
4366  return
4367  (1 << ACCT_TYPE_INCOME) |
4368  (1 << ACCT_TYPE_EXPENSE) |
4369  (1 << ACCT_TYPE_ROOT);
4370  case ACCT_TYPE_EQUITY:
4371  return
4372  (1 << ACCT_TYPE_EQUITY) |
4373  (1 << ACCT_TYPE_ROOT);
4374  case ACCT_TYPE_TRADING:
4375  return
4376  (1 << ACCT_TYPE_TRADING) |
4377  (1 << ACCT_TYPE_ROOT);
4378  default:
4379  PERR("bad account type: %d", type);
4380  return 0;
4381  }
4382 }
4383 
4384 gboolean
4386  GNCAccountType child_type)
4387 {
4388  /* ACCT_TYPE_NONE isn't compatible with anything, even ACCT_TYPE_NONE. */
4389  if (parent_type == ACCT_TYPE_NONE || child_type == ACCT_TYPE_NONE)
4390  return FALSE;
4391 
4392  /* ACCT_TYPE_ROOT can't have a parent account, and asking will raise
4393  * an error. */
4394  if (child_type == ACCT_TYPE_ROOT)
4395  return FALSE;
4396 
4397  return ((xaccParentAccountTypesCompatibleWith (child_type) &
4398  (1 << parent_type))
4399  != 0);
4400 }
4401 
4402 guint32
4404 {
4405  guint32 mask = (1 << NUM_ACCOUNT_TYPES) - 1;
4406  mask &= ~((1 << ACCT_TYPE_CURRENCY) | /* DEPRECATED */
4407  (1 << ACCT_TYPE_ROOT)); /* ROOT */
4408 
4409  return mask;
4410 }
4411 
4413 {
4414  switch (t)
4415  {
4416  case ACCT_TYPE_RECEIVABLE:
4417  case ACCT_TYPE_PAYABLE:
4418  return FALSE;
4419  default:
4422  }
4423 }
4424 
4427 {
4428  switch (t)
4429  {
4430  case ACCT_TYPE_BANK:
4431  case ACCT_TYPE_STOCK:
4432  case ACCT_TYPE_MONEYMRKT:
4433  case ACCT_TYPE_CHECKING:
4434  case ACCT_TYPE_SAVINGS:
4435  case ACCT_TYPE_MUTUAL:
4436  case ACCT_TYPE_CURRENCY:
4437  case ACCT_TYPE_CASH:
4438  case ACCT_TYPE_ASSET:
4439  case ACCT_TYPE_RECEIVABLE:
4440  return ACCT_TYPE_ASSET;
4441  case ACCT_TYPE_CREDIT:
4442  case ACCT_TYPE_LIABILITY:
4443  case ACCT_TYPE_PAYABLE:
4444  case ACCT_TYPE_CREDITLINE:
4445  return ACCT_TYPE_LIABILITY;
4446  case ACCT_TYPE_INCOME:
4447  return ACCT_TYPE_INCOME;
4448  case ACCT_TYPE_EXPENSE:
4449  return ACCT_TYPE_EXPENSE;
4450  case ACCT_TYPE_EQUITY:
4451  return ACCT_TYPE_EQUITY;
4452  case ACCT_TYPE_TRADING:
4453  default:
4454  return ACCT_TYPE_NONE;
4455  }
4456 }
4457 
4459 {
4460  switch (t)
4461  {
4462  case ACCT_TYPE_RECEIVABLE:
4463  case ACCT_TYPE_PAYABLE:
4464  return TRUE;
4465  default:
4466  return FALSE;
4467  }
4468 }
4469 
4471 {
4472  switch (t)
4473  {
4474  case ACCT_TYPE_EQUITY:
4475  return TRUE;
4476  default:
4477  return FALSE;
4478  }
4479 }
4480 
4481 gboolean
4483 {
4484  AccountPrivate *priv;
4485 
4486  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4487 
4488  priv = GET_PRIVATE(acc);
4489  return (priv->type == ACCT_TYPE_STOCK || priv->type == ACCT_TYPE_MUTUAL ||
4490  priv->type == ACCT_TYPE_CURRENCY);
4491 }
4492 
4493 /********************************************************************\
4494 \********************************************************************/
4495 
4496 gboolean
4498 {
4499  gboolean retval = FALSE;
4500  auto date = get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-date"});
4501 
4502  if (date)
4503  {
4504  if (last_date)
4505  *last_date = *date;
4506  retval = TRUE;
4507  }
4508  return retval;
4509 }
4510 
4511 /********************************************************************\
4512 \********************************************************************/
4513 
4514 void
4516 {
4517  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-date"}, last_date);
4518 }
4519 
4520 /********************************************************************\
4521 \********************************************************************/
4522 
4523 gboolean
4525  int *months, int *days)
4526 {
4527  if (!acc) return FALSE;
4528  auto m{get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "months"})};
4529  auto d{get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "days"})};
4530  if (m && d)
4531  {
4532  if (months)
4533  *months = *m;
4534  if (days)
4535  *days = *d;
4536  return true;
4537  }
4538  return false;
4539 }
4540 
4541 /********************************************************************\
4542 \********************************************************************/
4543 
4544 void
4545 xaccAccountSetReconcileLastInterval (Account *acc, int months, int days)
4546 {
4547  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "months"}, months);
4548  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, "last-interval", "days"}, days);
4549 }
4550 
4551 /********************************************************************\
4552 \********************************************************************/
4553 
4554 gboolean
4556 {
4557  if (auto date = get_kvp_int64_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "date"}))
4558  {
4559  if (postpone_date)
4560  *postpone_date = *date;
4561  return true;
4562  }
4563  return false;
4564 }
4565 
4566 /********************************************************************\
4567 \********************************************************************/
4568 
4569 void
4571 {
4572  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "date"}, postpone_date);
4573 }
4574 
4575 /********************************************************************\
4576 \********************************************************************/
4577 
4578 gboolean
4580  gnc_numeric *balance)
4581 {
4582  if (auto bal = get_kvp_gnc_numeric_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"}))
4583  {
4584  if (balance)
4585  *balance = *bal;
4586  return true;
4587  }
4588  return false;
4589 }
4590 
4591 /********************************************************************\
4592 \********************************************************************/
4593 
4594 void
4596 {
4597  set_kvp_gnc_numeric_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"}, balance);
4598 }
4599 
4600 /********************************************************************\
4601 
4602 \********************************************************************/
4603 
4604 void
4606 {
4607  set_kvp_gnc_numeric_path (acc, {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"}, {});
4608 }
4609 
4610 /********************************************************************\
4611 \********************************************************************/
4612 
4613 const char *
4615 {
4616  return get_kvp_string_path (acc, {"last-num"});
4617 }
4618 
4619 /********************************************************************\
4620 \********************************************************************/
4621 
4622 void
4623 xaccAccountSetLastNum (Account *acc, const char *num)
4624 {
4625  set_kvp_string_path (acc, {"last-num"}, num);
4626 }
4627 
4628 
4629 /********************************************************************\
4630 \********************************************************************/
4631 
4632 static bool
4633 get_balance_limit (const Account* acc, const std::string& key, gnc_numeric* balance)
4634 {
4635  auto limit = get_kvp_gnc_numeric_path (acc, {KEY_BALANCE_LIMIT, key});
4636  if (limit)
4637  *balance = gnc_numeric_create (limit->num, limit->denom);
4638  return limit.has_value();
4639 }
4640 
4641 static void
4642 set_balance_limit (Account *acc, const std::string& key, std::optional<gnc_numeric> balance)
4643 {
4644  if (balance && gnc_numeric_check (*balance))
4645  return;
4646  set_kvp_gnc_numeric_path (acc, {KEY_BALANCE_LIMIT, key}, balance);
4647 }
4648 
4649 gboolean
4651  gnc_numeric *balance)
4652 {
4653  return get_balance_limit (acc, KEY_BALANCE_HIGHER_LIMIT_VALUE, balance);
4654 }
4655 
4656 gboolean
4658  gnc_numeric *balance)
4659 {
4660  return get_balance_limit (acc, KEY_BALANCE_LOWER_LIMIT_VALUE, balance);
4661 }
4662 
4663 void
4664 xaccAccountSetHigherBalanceLimit (Account *acc, gnc_numeric balance)
4665 {
4666  set_balance_limit (acc, KEY_BALANCE_HIGHER_LIMIT_VALUE, balance);
4667 }
4668 
4669 void
4670 xaccAccountSetLowerBalanceLimit (Account *acc, gnc_numeric balance)
4671 {
4672  set_balance_limit (acc, KEY_BALANCE_LOWER_LIMIT_VALUE, balance);
4673 }
4674 
4675 void
4677 {
4678  set_balance_limit (acc, KEY_BALANCE_HIGHER_LIMIT_VALUE, {});
4679 }
4680 
4681 void
4683 {
4684  set_balance_limit (acc, KEY_BALANCE_LOWER_LIMIT_VALUE, {});
4685 }
4686 
4687 gboolean
4689 {
4690  return get_kvp_boolean_path (acc, {KEY_BALANCE_LIMIT, KEY_BALANCE_INCLUDE_SUB_ACCTS});
4691 }
4692 
4693 void
4695 {
4696  set_kvp_boolean_path (acc, {KEY_BALANCE_LIMIT, KEY_BALANCE_INCLUDE_SUB_ACCTS}, inc_sub);
4697 }
4698 
4699 /********************************************************************\
4700 \********************************************************************/
4701 
4702 static Account *
4703 GetOrMakeOrphanAccount (Account *root, gnc_commodity * currency)
4704 {
4705  char * accname;
4706  Account * acc;
4707 
4708  g_return_val_if_fail (root, nullptr);
4709 
4710  /* build the account name */
4711  if (!currency)
4712  {
4713  PERR ("No currency specified!");
4714  return nullptr;
4715  }
4716 
4717  accname = g_strconcat (_("Orphaned Gains"), "-",
4718  gnc_commodity_get_mnemonic (currency), nullptr);
4719 
4720  /* See if we've got one of these going already ... */
4721  acc = gnc_account_lookup_by_name(root, accname);
4722 
4723  if (acc == nullptr)
4724  {
4725  /* Guess not. We'll have to build one. */
4726  acc = xaccMallocAccount (gnc_account_get_book(root));
4727  xaccAccountBeginEdit (acc);
4728  xaccAccountSetName (acc, accname);
4729  xaccAccountSetCommodity (acc, currency);
4731  xaccAccountSetDescription (acc, _("Realized Gain/Loss"));
4732  xaccAccountSetNotes (acc,
4733  _("Realized Gains or Losses from "
4734  "Commodity or Trading Accounts "
4735  "that haven't been recorded elsewhere."));
4736 
4737  /* Hang the account off the root. */
4738  gnc_account_append_child (root, acc);
4739  xaccAccountCommitEdit (acc);
4740  }
4741 
4742  g_free (accname);
4743 
4744  return acc;
4745 }
4746 
4747 Account *
4748 xaccAccountGainsAccount (Account *acc, gnc_commodity *curr)
4749 {
4750  Path path {KEY_LOT_MGMT, "gains-acct", gnc_commodity_get_unique_name (curr)};
4751  auto gains_account = get_kvp_account_path (acc, path);
4752 
4753  if (gains_account == nullptr) /* No gains account for this currency */
4754  {
4755  gains_account = GetOrMakeOrphanAccount (gnc_account_get_root (acc), curr);
4756  set_kvp_account_path (acc, path, gains_account);
4757  }
4758 
4759  return gains_account;
4760 }
4761 
4762 /********************************************************************\
4763 \********************************************************************/
4764 
4765 void
4766 dxaccAccountSetPriceSrc(Account *acc, const char *src)
4767 {
4768  if (!acc) return;
4769 
4770  if (xaccAccountIsPriced(acc))
4771  set_kvp_string_path (acc, {"old-price-source"}, src);
4772 }
4773 
4774 /********************************************************************\
4775 \********************************************************************/
4776 
4777 const char*
4779 {
4780  static char *source = nullptr;
4781  if (!acc) return nullptr;
4782 
4783  if (!xaccAccountIsPriced(acc)) return nullptr;
4784 
4785  g_free (source);
4786 
4787  return get_kvp_string_path (acc, {"old-price-source"});
4788 }
4789 
4790 /********************************************************************\
4791 \********************************************************************/
4792 
4793 void
4794 dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
4795 {
4796  if (!acc) return;
4797  if (!xaccAccountIsPriced(acc)) return;
4798  set_kvp_string_path (acc, {"old-quote-tz"}, tz);
4799 }
4800 
4801 /********************************************************************\
4802 \********************************************************************/
4803 
4804 const char*
4806 {
4807  if (!acc) return nullptr;
4808  if (!xaccAccountIsPriced(acc)) return nullptr;
4809  return get_kvp_string_path (acc, {"old-quote-tz"});
4810 }
4811 
4812 /********************************************************************\
4813 \********************************************************************/
4814 
4815 void
4817 {
4818  /* Would have been nice to use G_TYPE_BOOLEAN, but the other
4819  * boolean kvps save the value as "true" or "false" and that would
4820  * be file-incompatible with this.
4821  */
4822  set_kvp_int64_path (acc, {KEY_RECONCILE_INFO, KEY_INCLUDE_CHILDREN}, status);
4823 }
4824 
4825 /********************************************************************\
4826 \********************************************************************/
4827 
4828 gboolean
4830 {
4831  /* access the account's kvp-data for status and return that, if no value
4832  * is found then we can assume not to include the children, that being
4833  * the default behaviour
4834  */
4835  return get_kvp_boolean_path (acc, {KEY_RECONCILE_INFO, KEY_INCLUDE_CHILDREN});
4836 }
4837 
4838 /********************************************************************\
4839 \********************************************************************/
4840 
4841 Split *
4842 xaccAccountFindSplitByDesc(const Account *acc, const char *description)
4843 {
4844  auto has_description = [description](const Split* s) -> bool
4845  { return !g_strcmp0 (description, xaccTransGetDescription (xaccSplitGetParent (s))); };
4846  return gnc_account_find_split (acc, has_description, true);
4847 }
4848 
4849 /* This routine is for finding a matching transaction in an account by
4850  * matching on the description field. [CAS: The rest of this comment
4851  * seems to belong somewhere else.] This routine is used for
4852  * auto-filling in registers with a default leading account. The
4853  * dest_trans is a transaction used for currency checking. */
4854 Transaction *
4855 xaccAccountFindTransByDesc(const Account *acc, const char *description)
4856 {
4857  auto split = xaccAccountFindSplitByDesc (acc, description);
4858  return split ? xaccSplitGetParent (split) : nullptr;
4859 }
4860 
4861 /* ================================================================ */
4862 /* Concatenation, Merging functions */
4863 
4864 void
4865 gnc_account_join_children (Account *to_parent, Account *from_parent)
4866 {
4867 
4868  /* errors */
4869  g_return_if_fail(GNC_IS_ACCOUNT(to_parent));
4870  g_return_if_fail(GNC_IS_ACCOUNT(from_parent));
4871 
4872  /* optimizations */
4873  auto from_priv = GET_PRIVATE(from_parent);
4874  if (from_priv->children.empty())
4875  return;
4876 
4877  ENTER (" ");
4878  auto children = from_priv->children;
4879  for (auto child : children)
4880  gnc_account_append_child(to_parent, child);
4881  LEAVE (" ");
4882 }
4883 /********************************************************************\
4884 \********************************************************************/
4885 
4886 void
4888 {
4889  g_return_if_fail(GNC_IS_ACCOUNT(parent));
4890 
4891  auto ppriv = GET_PRIVATE(parent);
4892  for (auto it_a = ppriv->children.begin(); it_a != ppriv->children.end(); it_a++)
4893  {
4894  auto acc_a = *it_a;
4895  auto priv_a = GET_PRIVATE(acc_a);
4896  for (auto it_b = std::next(it_a); it_b != ppriv->children.end(); it_b++)
4897  {
4898  auto acc_b = *it_b;
4899  auto priv_b = GET_PRIVATE(acc_b);
4900  if (0 != null_strcmp(priv_a->accountName, priv_b->accountName))
4901  continue;
4902  if (0 != null_strcmp(priv_a->accountCode, priv_b->accountCode))
4903  continue;
4904  if (0 != null_strcmp(priv_a->description, priv_b->description))
4905  continue;
4906  if (0 != null_strcmp(xaccAccountGetColor(acc_a),
4907  xaccAccountGetColor(acc_b)))
4908  continue;
4909  if (!gnc_commodity_equiv(priv_a->commodity, priv_b->commodity))
4910  continue;
4911  if (0 != null_strcmp(xaccAccountGetNotes(acc_a),
4912  xaccAccountGetNotes(acc_b)))
4913  continue;
4914  if (priv_a->type != priv_b->type)
4915  continue;
4916 
4917  /* consolidate children */
4918  if (!priv_b->children.empty())
4919  {
4920  auto work = priv_b->children;
4921  for (auto w : work)
4922  gnc_account_append_child (acc_a, w);
4923 
4924  qof_event_gen (&acc_a->inst, QOF_EVENT_MODIFY, nullptr);
4925  qof_event_gen (&acc_b->inst, QOF_EVENT_MODIFY, nullptr);
4926  }
4927 
4928  /* recurse to do the children's children */
4930 
4931  /* consolidate transactions */
4932  while (!priv_b->splits.empty())
4933  xaccSplitSetAccount (priv_b->splits.front(), acc_a);
4934 
4935  /* move back one before removal. next iteration around the loop
4936  * will get the node after node_b */
4937  it_b--;
4938 
4939  /* The destroy function will remove from list -- node_a is ok,
4940  * it's before node_b */
4941  xaccAccountBeginEdit (acc_b);
4942  xaccAccountDestroy (acc_b);
4943  }
4944  }
4945 }
4946 
4947 /* ================================================================ */
4948 /* Transaction Traversal functions */
4949 
4950 
4951 static void
4952 xaccSplitsBeginStagedTransactionTraversals (SplitsVec& splits)
4953 {
4954  for (auto s : splits)
4955  {
4956  Transaction *trans = s->parent;
4957 
4958  if (trans)
4959  trans->marker = 0;
4960  }
4961 }
4962 
4963 /* original function */
4964 void
4966 {
4967  if (!account)
4968  return;
4969  xaccSplitsBeginStagedTransactionTraversals(GET_PRIVATE (account)->splits);
4970 }
4971 
4972 gboolean
4973 xaccTransactionTraverse (Transaction *trans, int stage)
4974 {
4975  if (trans == nullptr) return FALSE;
4976 
4977  if (trans->marker < stage)
4978  {
4979  trans->marker = stage;
4980  return TRUE;
4981  }
4982 
4983  return FALSE;
4984 }
4985 
4986 /* Replacement for xaccGroupBeginStagedTransactionTraversals */
4987 void
4989 {
4990  auto do_one_account = [](auto acc)
4991  { gnc_account_foreach_split (acc, [](auto s){ s->parent->marker = 0; }, false); };
4992  gnc_account_foreach_descendant (account, do_one_account);
4993 }
4994 
4995 int
4997  unsigned int stage,
4998  TransactionCallback thunk,
4999  void *cb_data)
5000 {
5001  if (!acc) return 0;
5002 
5003  // iterate on copy of splits. some callers modify the splitsvec.
5004  auto splits = GET_PRIVATE(acc)->splits;
5005  for (auto s : splits)
5006  {
5007  auto trans = s->parent;
5008  if (trans && (trans->marker < stage))
5009  {
5010  trans->marker = stage;
5011  if (thunk)
5012  {
5013  auto retval = thunk(trans, cb_data);
5014  if (retval) return retval;
5015  }
5016  }
5017  }
5018 
5019  return 0;
5020 }
5021 
5022 int
5024  unsigned int stage,
5025  TransactionCallback thunk,
5026  void *cb_data)
5027 {
5028  const AccountPrivate *priv;
5029  Transaction *trans;
5030  int retval;
5031 
5032  if (!acc) return 0;
5033 
5034  /* depth first traversal */
5035  priv = GET_PRIVATE(acc);
5036  for (auto acc_p : priv->children)
5037  {
5038  retval = gnc_account_tree_staged_transaction_traversal(acc_p, stage, thunk, cb_data);
5039  if (retval) return retval;
5040  }
5041 
5042  /* Now this account */
5043  for (auto s : priv->splits)
5044  {
5045  trans = s->parent;
5046  if (trans && (trans->marker < stage))
5047  {
5048  trans->marker = stage;
5049  if (thunk)
5050  {
5051  retval = thunk(trans, cb_data);
5052  if (retval) return retval;
5053  }
5054  }
5055  }
5056 
5057  return 0;
5058 }
5059 
5060 /********************************************************************\
5061 \********************************************************************/
5062 
5063 int
5065  int (*proc)(Transaction *t, void *data),
5066  void *data)
5067 {
5068  if (!acc || !proc) return 0;
5069 
5071  return gnc_account_tree_staged_transaction_traversal (acc, 42, proc, data);
5072 }
5073 
5074 
5075 gint
5076 xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
5077  void *data)
5078 {
5079  if (!acc || !proc) return 0;
5081  return xaccAccountStagedTransactionTraversal(acc, 42, proc, data);
5082 }
5083 
5084 /* ================================================================ */
5085 /* The following functions are used by
5086  * src/import-export/import-backend.c to manipulate the contra-account
5087  * matching data. See src/import-export/import-backend.c for explanations.
5088  */
5089 
5090 #define IMAP_FRAME "import-map"
5091 #define IMAP_FRAME_BAYES "import-map-bayes"
5092 
5093 /* Look up an Account in the map */
5094 Account*
5095 gnc_account_imap_find_account (Account *acc,
5096  const char *category,
5097  const char *key)
5098 {
5099  if (!acc || !key) return nullptr;
5100  std::vector<std::string> path {IMAP_FRAME};
5101  if (category)
5102  path.push_back (category);
5103  path.push_back (key);
5104  return get_kvp_account_path (acc, path);
5105 }
5106 
5107 Account*
5108 gnc_account_imap_find_any (QofBook *book, const char* category, const char *key)
5109 {
5110  Account *account = nullptr;
5111 
5112  /* Get list of Accounts */
5113  auto root = gnc_book_get_root_account (book);
5114  auto accts = gnc_account_get_descendants_sorted (root);
5115 
5116  /* Go through list of accounts */
5117  for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
5118  {
5119  auto tmp_acc = static_cast<Account*> (ptr->data);
5120 
5121  if (gnc_account_imap_find_account (tmp_acc, category, key))
5122  {
5123  account = tmp_acc;
5124  break;
5125  }
5126  }
5127  g_list_free (accts);
5128 
5129 return account;
5130 }
5131 
5132 /* Store an Account in the map */
5133 void
5134 gnc_account_imap_add_account (Account *acc,
5135  const char *category,
5136  const char *key,
5137  Account *added_acc)
5138 {
5139  if (!acc || !key || !added_acc || !*key) return;
5140 
5141  auto path = category ? Path{IMAP_FRAME, category, key} : Path{IMAP_FRAME, key};
5142 
5143  set_kvp_account_path (acc, path, added_acc);
5144 }
5145 
5146 /* Remove a reference to an Account in the map */
5147 void
5148 gnc_account_imap_delete_account (Account *acc,
5149  const char *category,
5150  const char *key)
5151 {
5152  if (!acc || !key) return;
5153 
5154  auto path = category ? Path{IMAP_FRAME, category, key} : Path{IMAP_FRAME, key};
5155  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
5156  {
5157  qof_instance_slot_path_delete (QOF_INSTANCE (acc), path);
5158  if (category)
5159  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (acc), {IMAP_FRAME, category});
5160  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (acc), {IMAP_FRAME});
5161  }
5162  qof_instance_set_dirty (QOF_INSTANCE (acc));
5163 }
5164 
5165 /*--------------------------------------------------------------------------
5166  Below here is the bayes transaction to account matching system
5167 --------------------------------------------------------------------------*/
5168 
5169 
5175 {
5176  double product; /* product of probabilities */
5177  double product_difference; /* product of (1-probabilities) */
5178 };
5179 
5181 {
5182  std::string account_guid;
5183  int64_t token_count;
5184 };
5185 
5190 {
5191  std::vector<AccountTokenCount> accounts;
5192  int64_t total_count;
5193 };
5194 
5199 {
5200  std::string account_guid;
5201  int32_t probability;
5202 };
5203 
5204 static void
5205 build_token_info(char const * suffix, KvpValue * value, TokenAccountsInfo & tokenInfo)
5206 {
5207  if (strlen(suffix) == GUID_ENCODING_LENGTH)
5208  {
5209  tokenInfo.total_count += value->get<int64_t>();
5210  /*By convention, the key ends with the account GUID.*/
5211  tokenInfo.accounts.emplace_back(AccountTokenCount{std::string{suffix}, value->get<int64_t>()});
5212  }
5213 }
5214 
5218 static constexpr int probability_factor = 100000;
5219 
5220 static FinalProbabilityVec
5221 build_probabilities(ProbabilityVec const & first_pass)
5222 {
5223  FinalProbabilityVec ret;
5224  for (auto const & first_pass_prob : first_pass)
5225  {
5226  auto const & account_probability = first_pass_prob.second;
5227  /* P(AB) = A*B / [A*B + (1-A)*(1-B)]
5228  * NOTE: so we only keep track of a running product(A*B*C...)
5229  * and product difference ((1-A)(1-B)...)
5230  */
5231  int32_t probability = (account_probability.product /
5232  (account_probability.product + account_probability.product_difference)) * probability_factor;
5233  ret.push_back({first_pass_prob.first, probability});
5234  }
5235  return ret;
5236 }
5237 
5238 static AccountInfo
5239 highest_probability(FinalProbabilityVec const & probabilities)
5240 {
5241  AccountInfo ret {"", std::numeric_limits<int32_t>::min()};
5242  for (auto const & prob : probabilities)
5243  if (prob.second > ret.probability)
5244  ret = AccountInfo {prob.first, prob.second};
5245  return ret;
5246 }
5247 
5248 static ProbabilityVec
5249 get_first_pass_probabilities(Account* acc, GList * tokens)
5250 {
5251  ProbabilityVec ret;
5252  /* find the probability for each account that contains any of the tokens
5253  * in the input tokens list. */
5254  for (auto current_token = tokens; current_token; current_token = current_token->next)
5255  {
5256  TokenAccountsInfo tokenInfo{};
5257  auto path = std::string{IMAP_FRAME_BAYES "/"} + static_cast <char const *> (current_token->data) + "/";
5258  qof_instance_foreach_slot_prefix (QOF_INSTANCE (acc), path, &build_token_info, tokenInfo);
5259  for (auto const & current_account_token : tokenInfo.accounts)
5260  {
5261  auto item = std::find_if(ret.begin(), ret.end(), [&current_account_token]
5262  (std::pair<std::string, AccountProbability> const & a) {
5263  return current_account_token.account_guid == a.first;
5264  });
5265  if (item != ret.end())
5266  {/* This account is already in the map */
5267  item->second.product = ((double)current_account_token.token_count /
5268  (double)tokenInfo.total_count) * item->second.product;
5269  item->second.product_difference = ((double)1 - ((double)current_account_token.token_count /
5270  (double)tokenInfo.total_count)) * item->second.product_difference;
5271  }
5272  else
5273  {
5274  /* add a new entry */
5275  AccountProbability new_probability;
5276  new_probability.product = ((double)current_account_token.token_count /
5277  (double)tokenInfo.total_count);
5278  new_probability.product_difference = 1 - (new_probability.product);
5279  ret.push_back({current_account_token.account_guid, std::move(new_probability)});
5280  }
5281  } /* for all accounts in tokenInfo */
5282  }
5283  return ret;
5284 }
5285 
5286 static std::string
5287 look_for_old_separator_descendants (Account *root, std::string const & full_name, const gchar *separator)
5288 {
5289  GList *top_accounts, *ptr;
5290  gint found_len = 0;
5291  gchar found_sep;
5292  top_accounts = gnc_account_get_descendants (root);
5293  PINFO("Incoming full_name is '%s', current separator is '%s'", full_name.c_str (), separator);
5294  /* Go through list of top level accounts */
5295  for (ptr = top_accounts; ptr; ptr = g_list_next (ptr))
5296  {
5297  const gchar *name = xaccAccountGetName (static_cast <Account const *> (ptr->data));
5298  // we are looking for the longest top level account that matches
5299  if (g_str_has_prefix (full_name.c_str (), name))
5300  {
5301  gint name_len = strlen (name);
5302  const gchar old_sep = full_name[name_len];
5303  if (!g_ascii_isalnum (old_sep)) // test for non alpha numeric
5304  {
5305  if (name_len > found_len)
5306  {
5307  found_sep = full_name[name_len];
5308  found_len = name_len;
5309  }
5310  }
5311  }
5312  }
5313  g_list_free (top_accounts); // Free the List
5314  std::string new_name {full_name};
5315  if (found_len > 1)
5316  std::replace (new_name.begin (), new_name.end (), found_sep, *separator);
5317  PINFO ("Return full_name is '%s'", new_name.c_str ());
5318  return new_name;
5319 }
5320 
5321 static std::string
5322 get_guid_from_account_name (Account * root, std::string const & name)
5323 {
5324  auto map_account = gnc_account_lookup_by_full_name (root, name.c_str ());
5325  if (!map_account)
5326  {
5327  auto temp_account_name = look_for_old_separator_descendants (root, name,
5329  map_account = gnc_account_lookup_by_full_name (root, temp_account_name.c_str ());
5330  }
5331  auto temp_guid = gnc::GUID {*xaccAccountGetGUID (map_account)};
5332  return temp_guid.to_string ();
5333 }
5334 
5335 static FlatKvpEntry
5336 convert_entry (KvpEntry entry, Account* root)
5337 {
5338  /*We need to make a copy here.*/
5339  auto account_name = entry.first.back();
5340  if (!gnc::GUID::is_valid_guid (account_name))
5341  {
5342  /* Earlier version stored the account name in the import map, and
5343  * there were early beta versions of 2.7 that stored a GUID.
5344  * If there is no GUID, we assume it's an account name. */
5345  /* Take off the account name and replace it with the GUID */
5346  entry.first.pop_back();
5347  auto guid_str = get_guid_from_account_name (root, account_name);
5348  entry.first.emplace_back (guid_str);
5349  }
5350  std::string new_key {std::accumulate (entry.first.begin(), entry.first.end(), std::string {})};
5351  new_key = IMAP_FRAME_BAYES + new_key;
5352  return {new_key, entry.second};
5353 }
5354 
5355 static std::vector<FlatKvpEntry>
5356 get_flat_imap (Account * acc)
5357 {
5358  auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
5359  auto slot = frame->get_slot ({IMAP_FRAME_BAYES});
5360  if (!slot)
5361  return {};
5362  auto imap_frame = slot->get<KvpFrame*> ();
5363  auto flat_kvp = imap_frame->flatten_kvp ();
5364  auto root = gnc_account_get_root (acc);
5365  std::vector <FlatKvpEntry> ret;
5366  for (auto const & flat_entry : flat_kvp)
5367  {
5368  auto converted_entry = convert_entry (flat_entry, root);
5369  /*If the entry was invalid, we don't perpetuate it.*/
5370  if (converted_entry.first.size())
5371  ret.emplace_back (converted_entry);
5372  }
5373  return ret;
5374 }
5375 
5376 static bool
5377 convert_imap_account_bayes_to_flat (Account *acc)
5378 {
5379  auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
5380  if (!frame->get_keys().size())
5381  return false;
5382  auto flat_imap = get_flat_imap(acc);
5383  if (!flat_imap.size ())
5384  return false;
5385  xaccAccountBeginEdit(acc);
5386  frame->set({IMAP_FRAME_BAYES}, nullptr);
5387  std::for_each(flat_imap.begin(), flat_imap.end(),
5388  [&frame] (FlatKvpEntry const & entry) {
5389  frame->set({entry.first.c_str()}, entry.second);
5390  });
5391  qof_instance_set_dirty (QOF_INSTANCE (acc));
5392  xaccAccountCommitEdit(acc);
5393  return true;
5394 }
5395 
5396 /*
5397  * Checks for import map data and converts them when found.
5398  */
5399 static bool
5400 imap_convert_bayes_to_flat (QofBook * book)
5401 {
5402  auto root = gnc_book_get_root_account (book);
5403  auto accts = gnc_account_get_descendants_sorted (root);
5404  bool ret = false;
5405  for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
5406  {
5407  Account *acc = static_cast <Account*> (ptr->data);
5408  if (convert_imap_account_bayes_to_flat (acc))
5409  {
5410  ret = true;
5411  gnc_features_set_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN);
5412  }
5413  }
5414  g_list_free (accts);
5415  return ret;
5416 }
5417 
5418 void
5420 {
5421  imap_convert_bayes_to_flat_run = false;
5422 }
5423 
5424 /*
5425  * Here we check to see the state of import map data.
5426  *
5427  * If the GUID_FLAT_BAYESIAN feature flag is set, everything
5428  * should be fine.
5429  *
5430  * If it is not set, there are two possibilities: import data
5431  * are present from a previous version or not. If they are,
5432  * they are converted, and the feature flag set. If there are
5433  * no previous data, nothing is done.
5434  */
5435 static void
5436 check_import_map_data (QofBook *book)
5437 {
5438  if (gnc_features_check_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN) ||
5439  imap_convert_bayes_to_flat_run)
5440  return;
5441 
5442  /* This function will set GNC_FEATURE_GUID_FLAT_BAYESIAN if necessary.*/
5443  imap_convert_bayes_to_flat (book);
5444  imap_convert_bayes_to_flat_run = true;
5445 }
5446 
5447 static constexpr double threshold = .90 * probability_factor; /* 90% */
5448 
5450 Account*
5452 {
5453  if (!acc)
5454  return nullptr;
5455  auto book = gnc_account_get_book(acc);
5456  check_import_map_data (book);
5457  auto first_pass = get_first_pass_probabilities(acc, tokens);
5458  if (!first_pass.size())
5459  return nullptr;
5460  auto final_probabilities = build_probabilities(first_pass);
5461  if (!final_probabilities.size())
5462  return nullptr;
5463  auto best = highest_probability(final_probabilities);
5464  if (best.account_guid == "")
5465  return nullptr;
5466  if (best.probability < threshold)
5467  return nullptr;
5468  gnc::GUID guid;
5469  try {
5470  guid = gnc::GUID::from_string(best.account_guid);
5471  } catch (gnc::guid_syntax_exception&) {
5472  return nullptr;
5473  }
5474  auto account = xaccAccountLookup (reinterpret_cast<GncGUID*>(&guid), book);
5475  return account;
5476 }
5477 
5478 static void
5479 change_imap_entry (Account *acc, std::string const & path, int64_t token_count)
5480 {
5481  PINFO("Source Account is '%s', Count is '%" G_GINT64_FORMAT "'",
5482  xaccAccountGetName (acc), token_count);
5483 
5484  // check for existing guid entry
5485  if (auto existing_token_count = get_kvp_int64_path (acc, {path}))
5486  {
5487  PINFO("found existing value of '%" G_GINT64_FORMAT "'", *existing_token_count);
5488  token_count += *existing_token_count;
5489  }
5490 
5491  // Add or Update the entry based on guid
5492  set_kvp_int64_path (acc, {path}, token_count);
5493 }
5494 
5496 void
5498  GList *tokens,
5499  Account *added_acc)
5500 {
5501  GList *current_token;
5502  gint64 token_count;
5503  char *account_fullname;
5504  char *guid_string;
5505 
5506  ENTER(" ");
5507  if (!acc)
5508  {
5509  LEAVE(" ");
5510  return;
5511  }
5512  check_import_map_data (gnc_account_get_book(acc));
5513 
5514  g_return_if_fail (added_acc != nullptr);
5515  account_fullname = gnc_account_get_full_name(added_acc);
5516  xaccAccountBeginEdit (acc);
5517 
5518  PINFO("account name: '%s'", account_fullname);
5519 
5520  guid_string = guid_to_string (xaccAccountGetGUID (added_acc));
5521 
5522  /* process each token in the list */
5523  for (current_token = g_list_first(tokens); current_token;
5524  current_token = current_token->next)
5525  {
5526  char* token = static_cast<char*>(current_token->data);
5527  /* Jump to next iteration if the pointer is not valid or if the
5528  string is empty. In HBCI import we almost always get an empty
5529  string, which doesn't work in the kvp loopkup later. So we
5530  skip this case here. */
5531  if (!token || !token[0])
5532  continue;
5533  /* start off with one token for this account */
5534  token_count = 1;
5535  PINFO("adding token '%s'", token);
5536  auto path = std::string {IMAP_FRAME_BAYES} + '/' + token + '/' + guid_string;
5537  /* change the imap entry for the account */
5538  change_imap_entry (acc, path, token_count);
5539  }
5540  /* free up the account fullname and guid string */
5541  xaccAccountCommitEdit (acc);
5542  gnc_features_set_used (gnc_account_get_book(acc), GNC_FEATURE_GUID_FLAT_BAYESIAN);
5543  g_free (account_fullname);
5544  g_free (guid_string);
5545  LEAVE(" ");
5546 }
5547 
5548 /*******************************************************************************/
5549 
5550 static void
5551 build_non_bayes (const char *key, const GValue *value, gpointer user_data)
5552 {
5553  if (!G_VALUE_HOLDS_BOXED (value))
5554  return;
5555  QofBook *book;
5556  GncGUID *guid = nullptr;
5557  gchar *guid_string = nullptr;
5558  auto imapInfo = (GncImapInfo*)user_data;
5559  // Get the book
5560  book = qof_instance_get_book (imapInfo->source_account);
5561 
5562  guid = (GncGUID*)g_value_get_boxed (value);
5563  guid_string = guid_to_string (guid);
5564 
5565  PINFO("build_non_bayes: match string '%s', match account guid: '%s'",
5566  (char*)key, guid_string);
5567 
5568  auto imapInfo_node = static_cast <GncImapInfo*> (g_malloc(sizeof(GncImapInfo)));
5569 
5570  imapInfo_node->source_account = imapInfo->source_account;
5571  imapInfo_node->map_account = xaccAccountLookup (guid, book);
5572  imapInfo_node->head = g_strdup (imapInfo->head);
5573  imapInfo_node->match_string = g_strdup (key);
5574  imapInfo_node->category = g_strdup (imapInfo->category);
5575  imapInfo_node->count = g_strdup (" ");
5576 
5577  imapInfo->list = g_list_prepend (imapInfo->list, imapInfo_node);
5578 
5579  g_free (guid_string);
5580 }
5581 
5582 static void
5583 build_bayes (const char *suffix, KvpValue * value, GncImapInfo & imapInfo)
5584 {
5585  size_t guid_start = strlen(suffix) - GUID_ENCODING_LENGTH;
5586  std::string account_guid {&suffix[guid_start]};
5587  GncGUID guid;
5588  try
5589  {
5590  guid = gnc::GUID::from_string (account_guid);
5591  }
5592  catch (const gnc::guid_syntax_exception& err)
5593  {
5594  PWARN("Invalid GUID string from %s%s", IMAP_FRAME_BAYES, suffix);
5595  }
5596  auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
5597  auto imap_node = static_cast <GncImapInfo*> (g_malloc (sizeof (GncImapInfo)));
5598  auto count = value->get <int64_t> ();
5599  imap_node->source_account = imapInfo.source_account;
5600  imap_node->map_account = map_account;
5601  imap_node->head = g_strdup_printf ("%s%s", IMAP_FRAME_BAYES, suffix);
5602  imap_node->match_string = g_strndup (&suffix[1], guid_start - 2);
5603  imap_node->category = g_strdup(" ");
5604  imap_node->count = g_strdup_printf ("%" G_GINT64_FORMAT, count);
5605  imapInfo.list = g_list_prepend (imapInfo.list, imap_node);
5606 }
5607 
5609 {
5610  g_free (imapInfo->head);
5611  g_free (imapInfo->category);
5612  g_free (imapInfo->match_string);
5613  g_free (imapInfo->count);
5614  g_free (imapInfo);
5615 }
5616 
5617 GList *
5619 {
5620  check_import_map_data (gnc_account_get_book (acc));
5621  /* A dummy object which is used to hold the specified account, and the list
5622  * of data about which we care. */
5623  GncImapInfo imapInfo {acc, nullptr};
5624  qof_instance_foreach_slot_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES, &build_bayes, imapInfo);
5625  return g_list_reverse(imapInfo.list);
5626 }
5627 
5628 GList *
5629 gnc_account_imap_get_info (Account *acc, const char *category)
5630 {
5631  GList *list = nullptr;
5632 
5633  GncImapInfo imapInfo;
5634 
5635  std::vector<std::string> path {IMAP_FRAME};
5636  if (category)
5637  path.emplace_back (category);
5638 
5639  imapInfo.source_account = acc;
5640  imapInfo.list = list;
5641 
5642  imapInfo.head = g_strdup (IMAP_FRAME);
5643  imapInfo.category = g_strdup (category);
5644 
5645  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
5646  {
5647  qof_instance_foreach_slot (QOF_INSTANCE(acc), IMAP_FRAME, category,
5648  build_non_bayes, &imapInfo);
5649  }
5650  g_free (imapInfo.head);
5651  g_free (imapInfo.category);
5652  return g_list_reverse(imapInfo.list);
5653 }
5654 
5655 /*******************************************************************************/
5656 
5657 gchar *
5658 gnc_account_get_map_entry (Account *acc, const char *head, const char *category)
5659 {
5660  return g_strdup (category ?
5661  get_kvp_string_path (acc, {head, category}) :
5662  get_kvp_string_path (acc, {head}));
5663 }
5664 
5665 
5666 void
5667 gnc_account_delete_map_entry (Account *acc, char *head, char *category,
5668  char *match_string, gboolean empty)
5669 {
5670  if (acc != nullptr)
5671  {
5672  std::vector<std::string> path {head};
5673  if (category)
5674  path.emplace_back (category);
5675  if (match_string)
5676  path.emplace_back (match_string);
5677 
5678  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
5679  {
5680  xaccAccountBeginEdit (acc);
5681  if (empty)
5682  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), path);
5683  else
5684  qof_instance_slot_path_delete (QOF_INSTANCE(acc), path);
5685  PINFO("Account is '%s', head is '%s', category is '%s', match_string is'%s'",
5686  xaccAccountGetName (acc), head, category, match_string);
5687  qof_instance_set_dirty (QOF_INSTANCE(acc));
5688  xaccAccountCommitEdit (acc);
5689  }
5690  }
5691 }
5692 
5693 void
5695 {
5696  if (acc != nullptr)
5697  {
5698  auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES);
5699  if (!slots.size()) return;
5700  xaccAccountBeginEdit (acc);
5701  for (auto const & entry : slots)
5702  {
5703  qof_instance_slot_path_delete (QOF_INSTANCE (acc), {entry.first});
5704  }
5705  qof_instance_set_dirty (QOF_INSTANCE(acc));
5706  xaccAccountCommitEdit (acc);
5707  }
5708 }
5709 
5710 /* ================================================================ */
5711 /* QofObject function implementation and registration */
5712 
5713 static void
5714 destroy_all_child_accounts (Account *acc, gpointer data)
5715 {
5716  xaccAccountBeginEdit (acc);
5717  xaccAccountDestroy (acc);
5718 }
5719 
5720 static void
5721 gnc_account_book_end(QofBook* book)
5722 {
5723  Account *root_account = gnc_book_get_root_account (book);
5724  GList *accounts;
5725 
5726  if (!root_account)
5727  return;
5728 
5729  accounts = gnc_account_get_descendants (root_account);
5730 
5731  if (accounts)
5732  {
5733  accounts = g_list_reverse (accounts);
5734  g_list_foreach (accounts, (GFunc)destroy_all_child_accounts, nullptr);
5735  g_list_free (accounts);
5736  }
5737  xaccAccountBeginEdit (root_account);
5738  xaccAccountDestroy (root_account);
5739 }
5740 
5741 #ifdef _MSC_VER
5742 /* MSVC compiler doesn't have C99 "designated initializers"
5743  * so we wrap them in a macro that is empty on MSVC. */
5744 # define DI(x) /* */
5745 #else
5746 # define DI(x) x
5747 #endif
5748 static QofObject account_object_def =
5749 {
5750  DI(.interface_version = ) QOF_OBJECT_VERSION,
5751  DI(.e_type = ) GNC_ID_ACCOUNT,
5752  DI(.type_label = ) "Account",
5753  DI(.create = ) (void*(*)(QofBook*)) xaccMallocAccount,
5754  DI(.book_begin = ) nullptr,
5755  DI(.book_end = ) gnc_account_book_end,
5756  DI(.is_dirty = ) qof_collection_is_dirty,
5757  DI(.mark_clean = ) qof_collection_mark_clean,
5758  DI(.foreach = ) qof_collection_foreach,
5759  DI(.printable = ) (const char * (*)(gpointer)) xaccAccountGetName,
5760  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
5761 };
5762 
5763 gboolean xaccAccountRegister (void)
5764 {
5765  static QofParam params[] =
5766  {
5767  {
5768  ACCOUNT_NAME_, QOF_TYPE_STRING,
5771  },
5772  {
5773  ACCOUNT_CODE_, QOF_TYPE_STRING,
5776  },
5777  {
5778  ACCOUNT_DESCRIPTION_, QOF_TYPE_STRING,
5781  },
5782  {
5783  ACCOUNT_COLOR_, QOF_TYPE_STRING,
5786  },
5787  {
5788  ACCOUNT_FILTER_, QOF_TYPE_STRING,
5791  },
5792  {
5793  ACCOUNT_SORT_ORDER_, QOF_TYPE_STRING,
5796  },
5797  {
5798  ACCOUNT_SORT_REVERSED_, QOF_TYPE_BOOLEAN,
5801  },
5802  {
5803  ACCOUNT_NOTES_, QOF_TYPE_STRING,
5806  },
5807  {
5808  ACCOUNT_PRESENT_, QOF_TYPE_NUMERIC,
5809  (QofAccessFunc) xaccAccountGetPresentBalance, nullptr
5810  },
5811  {
5812  ACCOUNT_BALANCE_, QOF_TYPE_NUMERIC,
5814  },
5815  {
5816  ACCOUNT_CLEARED_, QOF_TYPE_NUMERIC,
5818  },
5819  {
5820  ACCOUNT_RECONCILED_, QOF_TYPE_NUMERIC,
5822  },
5823  {
5824  ACCOUNT_TYPE_, QOF_TYPE_STRING,
5825  (QofAccessFunc) qofAccountGetTypeString,
5826  (QofSetterFunc) qofAccountSetType
5827  },
5828  {
5829  ACCOUNT_FUTURE_MINIMUM_, QOF_TYPE_NUMERIC,
5830  (QofAccessFunc) xaccAccountGetProjectedMinimumBalance, nullptr
5831  },
5832  {
5833  ACCOUNT_TAX_RELATED, QOF_TYPE_BOOLEAN,
5836  },
5837  {
5838  ACCOUNT_OPENING_BALANCE_, QOF_TYPE_BOOLEAN,
5841  },
5842  {
5843  ACCOUNT_SCU, QOF_TYPE_INT32,
5846  },
5847  {
5848  ACCOUNT_NSCU, QOF_TYPE_BOOLEAN,
5851  },
5852  {
5853  ACCOUNT_PARENT, GNC_ID_ACCOUNT,
5855  (QofSetterFunc) qofAccountSetParent
5856  },
5857  {
5858  QOF_PARAM_BOOK, QOF_ID_BOOK,
5860  },
5861  {
5862  QOF_PARAM_GUID, QOF_TYPE_GUID,
5864  },
5865  { nullptr },
5866  };
5867 
5868  qof_class_register (GNC_ID_ACCOUNT, (QofSortFunc) qof_xaccAccountOrder, params);
5869 
5870  return qof_object_register (&account_object_def);
5871 }
5872 
5873 /* ======================= UNIT TESTING ACCESS =======================
5874  * The following functions are for unit testing use only.
5875  */
5876 static AccountPrivate*
5877 utest_account_get_private (Account *acc)
5878 {
5879  return GET_PRIVATE (acc);
5880 }
5881 
5883 _utest_account_fill_functions(void)
5884 {
5885  AccountTestFunctions* func = g_new(AccountTestFunctions, 1);
5886 
5887  func->get_private = utest_account_get_private;
5888  func->coll_get_root_account = gnc_coll_get_root_account;
5889  func->xaccFreeAccountChildren = xaccFreeAccountChildren;
5890  func->xaccFreeAccount = xaccFreeAccount;
5891  func->qofAccountSetParent = qofAccountSetParent;
5892  func->gnc_account_lookup_by_full_name_helper =
5893  gnc_account_lookup_by_full_name_helper;
5894 
5895  return func;
5896 }
5897 /* ======================= 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:5076
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:1502
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:5023
gboolean xaccAccountGetAutoInterest(const Account *acc)
Get the "auto interest" flag for an account.
Definition: Account.cpp:4106
holds an account guid and its corresponding integer probability the integer probability is some facto...
Definition: Account.cpp:5198
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4614
GNCAccountType xaccAccountTypeGetFundamental(GNCAccountType t)
Convenience function to return the fundamental type asset/liability/income/expense/equity given an ac...
Definition: Account.cpp:4426
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:5658
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:3318
guint32 xaccAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of account types compatible with a given type.
Definition: Account.cpp:4298
void gnc_account_imap_info_destroy(GncImapInfo *imapInfo)
Clean destructor for the imap_info structure of Bayesian mappings.
Definition: Account.cpp:5608
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:4006
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:3885
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:3339
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:4482
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:5667
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:3306
gnc_numeric xaccSplitGetReconciledBalance(const Split *s)
Returns the reconciled-balance of this split.
Definition: Split.cpp:1315
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3217
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1472
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:3286
gboolean xaccAccountGetAppendText(const Account *acc)
Get the "import-append-text" flag for an account.
Definition: Account.cpp:4062
void xaccAccountSetReconcileLastDate(Account *acc, time64 last_date)
DOCUMENT ME!
Definition: Account.cpp:4515
STRUCTS.
total_count and the token_count for a given account let us calculate the probability of a given accou...
Definition: Account.cpp:5189
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:3976
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:4545
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:3787
guint32 xaccAccountTypesValid(void)
Returns the bitmask of the account type enums that are valid.
Definition: Account.cpp:4403
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:4178
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:4664
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:4022
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:5497
gnc_numeric xaccSplitGetBalance(const Split *s)
Returns the running balance up to and including the indicated split.
Definition: Split.cpp:1297
#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:4623
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:3417
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:4555
intermediate values used to calculate the bayes probability of a given account where p(AB) = (a*b)/[a...
Definition: Account.cpp:5174
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:4657
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:4133
gboolean xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_guids, gboolean check_balances, gboolean check_txn_splits)
Equality.
Definition: Split.cpp:802
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:3300
Split * xaccAccountFindSplitByDesc(const Account *acc, const char *description)
Returns a pointer to the split, not a copy.
Definition: Account.cpp:4842
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:4412
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:4249
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:3255
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:3481
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4056
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:4385
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:3797
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:4682
gboolean xaccTransactionTraverse(Transaction *trans, int stage)
xaccTransactionTraverse() checks the stage of the given transaction.
Definition: Account.cpp:4973
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:4855
void xaccAccountSetIncludeSubAccountBalances(Account *acc, gboolean inc_sub)
Set whether to include balances of sub accounts.
Definition: Account.cpp:4694
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:4988
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:4766
#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:4965
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:4093
const char * xaccAccountGetDescription(const Account *acc)
Get the account&#39;s description.
Definition: Account.cpp:3293
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:3397
void gnc_account_delete_all_bayes_maps(Account *acc)
Delete all bayes entries for Account.
Definition: Account.cpp:5694
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:4805
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:4605
const char * xaccAccountGetTaxUSPayerNameSource(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:3994
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:1303
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:5419
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:3910
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:5618
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:5629
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:4570
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:3982
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4458
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:4215
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:4084
void xaccAccountSetReconcilePostponeBalance(Account *acc, gnc_numeric balance)
DOCUMENT ME!
Definition: Account.cpp:4595
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:3970
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:3384
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:3424
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:4865
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:3469
gnc_numeric xaccAccountGetBalance(const Account *acc)
Get the current balance of the account, which may include future splits.
Definition: Account.cpp:3410
gboolean xaccAccountGetReconcileLastDate(const Account *acc, time64 *last_date)
DOCUMENT ME!
Definition: Account.cpp:4497
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:4794
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:3358
Account * xaccAccountGetAssociatedAccount(const Account *acc, const char *tag)
Get the account&#39;s associated account e.g.
Definition: Account.cpp:3330
gboolean xaccAccountGetHidden(const Account *acc)
Get the "hidden" flag for an account.
Definition: Account.cpp:4121
void xaccAccountSetAppendText(Account *acc, gboolean val)
Set the "import-append-text" flag for an account.
Definition: Account.cpp:4068
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:4112
void xaccAccountSetTaxUSCode(Account *acc, const char *code)
DOCUMENT ME!
Definition: Account.cpp:3988
GNCPlaceholderType
DOCUMENT ME!
Definition: Account.h:1261
gboolean xaccAccountGetIsOpeningBalance(const Account *acc)
Get the "opening-balance" flag for an account.
Definition: Account.cpp:4074
guint32 xaccParentAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of parent account types compatible with a given type.
Definition: Account.cpp:4338
gboolean xaccAccountGetReconcileChildrenStatus(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4829
gboolean xaccAccountGetReconcileLastInterval(const Account *acc, int *months, int *days)
DOCUMENT ME!
Definition: Account.cpp:4524
gboolean xaccAccountGetIncludeSubAccountBalances(const Account *acc)
Get whether to include balances of sub accounts.
Definition: Account.cpp:4688
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:4778
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:4034
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:4127
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:4155
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:3351
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:4050
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:4748
void xaccAccountSetLowerBalanceLimit(Account *acc, gnc_numeric balance)
Set the lower balance limit for the account.
Definition: Account.cpp:4670
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:4650
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:4000
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:3372
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:3917
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:4676
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:4288
#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:3312
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:4996
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:4887
gboolean xaccAccountIsEquityType(GNCAccountType t)
Convenience function to check if the account is a valid Equity type.
Definition: Account.cpp:4470
void xaccAccountSetReconcileChildrenStatus(Account *acc, gboolean status)
DOCUMENT ME!
Definition: Account.cpp:4816
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:3324
gboolean xaccAccountGetReconcilePostponeBalance(const Account *acc, gnc_numeric *balance)
DOCUMENT ME!
Definition: Account.cpp:4579
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:5451
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:4013