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