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