GnuCash  4.8a-176-g88ecf8dd1
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 
3972 gboolean gnc_account_and_descendants_empty (Account *acc)
3973 {
3974  g_return_val_if_fail (GNC_IS_ACCOUNT (acc), FALSE);
3975  if (xaccAccountGetSplitList (acc)) return FALSE;
3976  auto empty = TRUE;
3977  auto *children = gnc_account_get_children (acc);
3978  for (auto *n = children; n && empty; n = n->next)
3979  {
3980  empty = gnc_account_and_descendants_empty ((Account*)n->data);
3981  }
3982  g_list_free (children);
3983  return empty;
3984 }
3985 
3986 LotList *
3988 {
3989  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
3990  return g_list_copy(GET_PRIVATE(acc)->lots);
3991 }
3992 
3993 LotList *
3995  gboolean (*match_func)(GNCLot *lot,
3996  gpointer user_data),
3997  gpointer user_data, GCompareFunc sort_func)
3998 {
3999  AccountPrivate *priv;
4000  GList *lot_list;
4001  GList *retval = NULL;
4002 
4003  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
4004 
4005  priv = GET_PRIVATE(acc);
4006  for (lot_list = priv->lots; lot_list; lot_list = lot_list->next)
4007  {
4008  GNCLot *lot = static_cast<GNCLot*>(lot_list->data);
4009 
4010  /* If this lot is closed, then ignore it */
4011  if (gnc_lot_is_closed (lot))
4012  continue;
4013 
4014  if (match_func && !(match_func)(lot, user_data))
4015  continue;
4016 
4017  /* Ok, this is a valid lot. Add it to our list of lots */
4018  retval = g_list_prepend (retval, lot);
4019  }
4020 
4021  if (sort_func)
4022  retval = g_list_sort (retval, sort_func);
4023 
4024  return retval;
4025 }
4026 
4027 gpointer
4028 xaccAccountForEachLot(const Account *acc,
4029  gpointer (*proc)(GNCLot *lot, void *data), void *data)
4030 {
4031  AccountPrivate *priv;
4032  LotList *node;
4033  gpointer result = NULL;
4034 
4035  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
4036  g_return_val_if_fail(proc, NULL);
4037 
4038  priv = GET_PRIVATE(acc);
4039  for (node = priv->lots; node; node = node->next)
4040  if ((result = proc((GNCLot *)node->data, data)))
4041  break;
4042 
4043  return result;
4044 }
4045 
4046 static void
4047 set_boolean_key (Account *acc, std::vector<std::string> const & path, gboolean option)
4048 {
4049  GValue v = G_VALUE_INIT;
4050  g_return_if_fail(GNC_IS_ACCOUNT(acc));
4051 
4052  g_value_init (&v, G_TYPE_BOOLEAN);
4053  g_value_set_boolean (&v, option);
4054  xaccAccountBeginEdit (acc);
4055  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, path);
4056  mark_account (acc);
4057  xaccAccountCommitEdit (acc);
4058  g_value_unset (&v);
4059 }
4060 
4061 static gboolean
4062 boolean_from_key (const Account *acc, std::vector<std::string> const & path)
4063 {
4064  GValue v = G_VALUE_INIT;
4065  gboolean retval = FALSE;
4066  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4067  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, path);
4068  if (G_VALUE_HOLDS_INT64 (&v))
4069  retval = (g_value_get_int64 (&v) != 0);
4070  if (G_VALUE_HOLDS_BOOLEAN (&v))
4071  retval = (g_value_get_boolean (&v));
4072  if (G_VALUE_HOLDS_STRING (&v))
4073  retval = !strcmp (g_value_get_string (&v), "true");
4074  g_value_unset (&v);
4075  return retval;
4076 }
4077 
4078 /********************************************************************\
4079 \********************************************************************/
4080 
4081 /* These functions use interchange gint64 and gboolean. Is that right? */
4082 gboolean
4084 {
4085  return boolean_from_key(acc, {"tax-related"});
4086 }
4087 
4088 void
4089 xaccAccountSetTaxRelated (Account *acc, gboolean tax_related)
4090 {
4091  set_boolean_key(acc, {"tax-related"}, tax_related);
4092 }
4093 
4094 const char *
4096 {
4097  auto priv = GET_PRIVATE (acc);
4098  if (priv->tax_us_code == is_unset)
4099  priv->tax_us_code = get_kvp_string_path (acc, {"tax-US", "code"});
4100  return priv->tax_us_code;
4101 }
4102 
4103 void
4104 xaccAccountSetTaxUSCode (Account *acc, const char *code)
4105 {
4106  auto priv = GET_PRIVATE (acc);
4107  if (priv->tax_us_code != is_unset)
4108  g_free (priv->tax_us_code);
4109  priv->tax_us_code = g_strdup (code);
4110  set_kvp_string_path (acc, {"tax-US", "code"}, priv->tax_us_code);
4111 }
4112 
4113 const char *
4115 {
4116  auto priv = GET_PRIVATE (acc);
4117  if (priv->tax_us_pns == is_unset)
4118  priv->tax_us_pns = get_kvp_string_path (acc, {"tax-US", "payer-name-source"});
4119  return priv->tax_us_pns;
4120  }
4121 
4122 void
4124 {
4125  auto priv = GET_PRIVATE (acc);
4126  if (priv->tax_us_pns != is_unset)
4127  g_free (priv->tax_us_pns);
4128  priv->tax_us_pns = g_strdup (source);
4129  set_kvp_string_path (acc, {"tax-US", "payer-name-source"}, priv->tax_us_pns);
4130 }
4131 
4132 gint64
4134 {
4135  gint64 copy_number = 0;
4136  GValue v = G_VALUE_INIT;
4137  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4138  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"tax-US", "copy-number"});
4139  if (G_VALUE_HOLDS_INT64 (&v))
4140  copy_number = g_value_get_int64 (&v);
4141 
4142  g_value_unset (&v);
4143  return (copy_number == 0) ? 1 : copy_number;
4144 }
4145 
4146 void
4147 xaccAccountSetTaxUSCopyNumber (Account *acc, gint64 copy_number)
4148 {
4149  g_return_if_fail(GNC_IS_ACCOUNT(acc));
4150  xaccAccountBeginEdit (acc);
4151  if (copy_number != 0)
4152  {
4153  GValue v = G_VALUE_INIT;
4154  g_value_init (&v, G_TYPE_INT64);
4155  g_value_set_int64 (&v, copy_number);
4156  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"tax-US", "copy-number"});
4157  g_value_unset (&v);
4158  }
4159  else
4160  {
4161  qof_instance_set_path_kvp (QOF_INSTANCE (acc), nullptr, {"tax-US", "copy-number"});
4162  }
4163  mark_account (acc);
4164  xaccAccountCommitEdit (acc);
4165 }
4166 
4167 /*********************************************************************\
4168 \ ********************************************************************/
4169 
4170 
4172 {
4173  if (gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS))
4174  return _(dflt_acct_debit_str);
4175 
4176  auto result = gnc_acct_debit_strs.find(acct_type);
4177  if (result != gnc_acct_debit_strs.end())
4178  return _(result->second);
4179  else
4180  return _(dflt_acct_debit_str);
4181 }
4182 
4184 {
4185  if (gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS))
4186  return _(dflt_acct_credit_str);
4187 
4188  auto result = gnc_acct_credit_strs.find(acct_type);
4189  if (result != gnc_acct_credit_strs.end())
4190  return _(result->second);
4191  else
4192  return _(dflt_acct_credit_str);
4193 }
4194 
4195 /********************************************************************\
4196 \********************************************************************/
4197 
4198 gboolean
4200 {
4201  return boolean_from_key(acc, {"placeholder"});
4202 }
4203 
4204 void
4206 {
4207  set_boolean_key(acc, {"placeholder"}, val);
4208 }
4209 
4210 gboolean
4212 {
4213  if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
4214  return false;
4215  auto priv = GET_PRIVATE(acc);
4216  if (priv->equity_type == TriState::Unset)
4217  {
4218  auto equity_type = get_kvp_string_tag (acc, "equity-type");
4219  priv->equity_type = g_strcmp0 (equity_type, "opening-balance") ?
4220  TriState::False : TriState::True;
4221  g_free (equity_type);
4222  }
4223  return (priv->equity_type == TriState::True);
4224 }
4225 
4226 void
4228 {
4229  if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
4230  return;
4231  auto priv = GET_PRIVATE (acc);
4232  priv->equity_type = val ? TriState::True : TriState::False;
4233  set_kvp_string_tag(acc, "equity-type", val ? "opening-balance" : nullptr);
4234 }
4235 
4238 {
4239  GList *descendants, *node;
4240  GNCPlaceholderType ret = PLACEHOLDER_NONE;
4241 
4242  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), PLACEHOLDER_NONE);
4243  if (xaccAccountGetPlaceholder(acc)) return PLACEHOLDER_THIS;
4244 
4245  descendants = gnc_account_get_descendants(acc);
4246  for (node = descendants; node; node = node->next)
4247  if (xaccAccountGetPlaceholder((Account *) node->data))
4248  {
4249  ret = PLACEHOLDER_CHILD;
4250  break;
4251  }
4252 
4253  g_list_free(descendants);
4254  return ret;
4255 }
4256 
4257 /********************************************************************\
4258  \********************************************************************/
4259 
4260 gboolean
4262 {
4263  return boolean_from_key (acc, {KEY_RECONCILE_INFO, "auto-interest-transfer"});
4264 }
4265 
4266 void
4268 {
4269  set_boolean_key (acc, {KEY_RECONCILE_INFO, "auto-interest-transfer"}, val);
4270 }
4271 
4272 /********************************************************************\
4273 \********************************************************************/
4274 
4275 gboolean
4277 {
4278  return boolean_from_key (acc, {"hidden"});
4279 }
4280 
4281 void
4282 xaccAccountSetHidden (Account *acc, gboolean val)
4283 {
4284  set_boolean_key (acc, {"hidden"}, val);
4285 }
4286 
4287 gboolean
4289 {
4290  AccountPrivate *priv;
4291 
4292  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4293 
4294  if (xaccAccountGetHidden(acc))
4295  return TRUE;
4296  priv = GET_PRIVATE(acc);
4297  while ((acc = priv->parent) != NULL)
4298  {
4299  priv = GET_PRIVATE(acc);
4300  if (xaccAccountGetHidden(acc))
4301  return TRUE;
4302  }
4303  return FALSE;
4304 }
4305 
4306 /********************************************************************\
4307 \********************************************************************/
4308 
4309 gboolean
4310 xaccAccountHasAncestor (const Account *acc, const Account * ancestor)
4311 {
4312  const Account *parent;
4313 
4314  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4315  g_return_val_if_fail(GNC_IS_ACCOUNT(ancestor), FALSE);
4316 
4317  parent = acc;
4318  while (parent && parent != ancestor)
4319  parent = GET_PRIVATE(parent)->parent;
4320 
4321  return (parent == ancestor);
4322 }
4323 
4324 /********************************************************************\
4325 \********************************************************************/
4326 
4327 /* You must edit the functions in this block in tandem. KEEP THEM IN
4328  SYNC! */
4329 
4330 #define GNC_RETURN_ENUM_AS_STRING(x) case (ACCT_TYPE_ ## x): return #x;
4331 
4332 const char *
4334 {
4335  switch (type)
4336  {
4337  GNC_RETURN_ENUM_AS_STRING(NONE);
4338  GNC_RETURN_ENUM_AS_STRING(BANK);
4339  GNC_RETURN_ENUM_AS_STRING(CASH);
4340  GNC_RETURN_ENUM_AS_STRING(CREDIT);
4341  GNC_RETURN_ENUM_AS_STRING(ASSET);
4342  GNC_RETURN_ENUM_AS_STRING(LIABILITY);
4343  GNC_RETURN_ENUM_AS_STRING(STOCK);
4344  GNC_RETURN_ENUM_AS_STRING(MUTUAL);
4345  GNC_RETURN_ENUM_AS_STRING(CURRENCY);
4346  GNC_RETURN_ENUM_AS_STRING(INCOME);
4347  GNC_RETURN_ENUM_AS_STRING(EXPENSE);
4348  GNC_RETURN_ENUM_AS_STRING(EQUITY);
4349  GNC_RETURN_ENUM_AS_STRING(RECEIVABLE);
4350  GNC_RETURN_ENUM_AS_STRING(PAYABLE);
4351  GNC_RETURN_ENUM_AS_STRING(ROOT);
4352  GNC_RETURN_ENUM_AS_STRING(TRADING);
4353  GNC_RETURN_ENUM_AS_STRING(CHECKING);
4354  GNC_RETURN_ENUM_AS_STRING(SAVINGS);
4355  GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
4356  GNC_RETURN_ENUM_AS_STRING(CREDITLINE);
4357  default:
4358  PERR ("asked to translate unknown account type %d.\n", type);
4359  break;
4360  }
4361  return(NULL);
4362 }
4363 
4364 #undef GNC_RETURN_ENUM_AS_STRING
4365 
4366 #define GNC_RETURN_ON_MATCH(x) \
4367  if(g_strcmp0(#x, (str)) == 0) { *type = ACCT_TYPE_ ## x; return(TRUE); }
4368 
4369 gboolean
4371 {
4372 
4373  GNC_RETURN_ON_MATCH(NONE);
4374  GNC_RETURN_ON_MATCH(BANK);
4375  GNC_RETURN_ON_MATCH(CASH);
4376  GNC_RETURN_ON_MATCH(CREDIT);
4377  GNC_RETURN_ON_MATCH(ASSET);
4378  GNC_RETURN_ON_MATCH(LIABILITY);
4379  GNC_RETURN_ON_MATCH(STOCK);
4380  GNC_RETURN_ON_MATCH(MUTUAL);
4381  GNC_RETURN_ON_MATCH(CURRENCY);
4382  GNC_RETURN_ON_MATCH(INCOME);
4383  GNC_RETURN_ON_MATCH(EXPENSE);
4384  GNC_RETURN_ON_MATCH(EQUITY);
4385  GNC_RETURN_ON_MATCH(RECEIVABLE);
4386  GNC_RETURN_ON_MATCH(PAYABLE);
4387  GNC_RETURN_ON_MATCH(ROOT);
4388  GNC_RETURN_ON_MATCH(TRADING);
4389  GNC_RETURN_ON_MATCH(CHECKING);
4390  GNC_RETURN_ON_MATCH(SAVINGS);
4391  GNC_RETURN_ON_MATCH(MONEYMRKT);
4392  GNC_RETURN_ON_MATCH(CREDITLINE);
4393 
4394  PERR("asked to translate unknown account type string %s.\n",
4395  str ? str : "(null)");
4396 
4397  return(FALSE);
4398 }
4399 
4400 #undef GNC_RETURN_ON_MATCH
4401 
4402 /* impedance mismatch is a source of loss */
4404 xaccAccountStringToEnum(const char* str)
4405 {
4406  GNCAccountType type;
4407  gboolean rc;
4408  rc = xaccAccountStringToType(str, &type);
4409  if (FALSE == rc) return ACCT_TYPE_INVALID;
4410  return type;
4411 }
4412 
4413 /********************************************************************\
4414 \********************************************************************/
4415 
4416 static char const *
4417 account_type_name[NUM_ACCOUNT_TYPES] =
4418 {
4419  N_("Bank"),
4420  N_("Cash"),
4421  N_("Asset"),
4422  N_("Credit Card"),
4423  N_("Liability"),
4424  N_("Stock"),
4425  N_("Mutual Fund"),
4426  N_("Currency"),
4427  N_("Income"),
4428  N_("Expense"),
4429  N_("Equity"),
4430  N_("A/Receivable"),
4431  N_("A/Payable"),
4432  N_("Root"),
4433  N_("Trading")
4434  /*
4435  N_("Checking"),
4436  N_("Savings"),
4437  N_("Money Market"),
4438  N_("Credit Line")
4439  */
4440 };
4441 
4442 const char *
4444 {
4445  if (type < 0 || NUM_ACCOUNT_TYPES <= type ) return "";
4446  return _(account_type_name [type]);
4447 }
4448 
4449 /********************************************************************\
4450 \********************************************************************/
4451 
4452 guint32
4454 {
4455  switch (type)
4456  {
4457  case ACCT_TYPE_BANK:
4458  case ACCT_TYPE_CASH:
4459  case ACCT_TYPE_ASSET:
4460  case ACCT_TYPE_CREDIT:
4461  case ACCT_TYPE_LIABILITY:
4462  case ACCT_TYPE_INCOME:
4463  case ACCT_TYPE_EXPENSE:
4464  case ACCT_TYPE_EQUITY:
4465  return
4466  (1 << ACCT_TYPE_BANK) |
4467  (1 << ACCT_TYPE_CASH) |
4468  (1 << ACCT_TYPE_ASSET) |
4469  (1 << ACCT_TYPE_CREDIT) |
4470  (1 << ACCT_TYPE_LIABILITY) |
4471  (1 << ACCT_TYPE_INCOME) |
4472  (1 << ACCT_TYPE_EXPENSE) |
4473  (1 << ACCT_TYPE_EQUITY);
4474  case ACCT_TYPE_STOCK:
4475  case ACCT_TYPE_MUTUAL:
4476  case ACCT_TYPE_CURRENCY:
4477  return
4478  (1 << ACCT_TYPE_STOCK) |
4479  (1 << ACCT_TYPE_MUTUAL) |
4480  (1 << ACCT_TYPE_CURRENCY);
4481  case ACCT_TYPE_RECEIVABLE:
4482  return (1 << ACCT_TYPE_RECEIVABLE);
4483  case ACCT_TYPE_PAYABLE:
4484  return (1 << ACCT_TYPE_PAYABLE);
4485  case ACCT_TYPE_TRADING:
4486  return (1 << ACCT_TYPE_TRADING);
4487  default:
4488  PERR("bad account type: %d", type);
4489  return 0;
4490  }
4491 }
4492 guint32
4494 {
4495  switch (type)
4496  {
4497  case ACCT_TYPE_BANK:
4498  case ACCT_TYPE_CASH:
4499  case ACCT_TYPE_ASSET:
4500  case ACCT_TYPE_STOCK:
4501  case ACCT_TYPE_MUTUAL:
4502  case ACCT_TYPE_CURRENCY:
4503  case ACCT_TYPE_CREDIT:
4504  case ACCT_TYPE_LIABILITY:
4505  case ACCT_TYPE_RECEIVABLE:
4506  case ACCT_TYPE_PAYABLE:
4507  return
4508  (1 << ACCT_TYPE_BANK) |
4509  (1 << ACCT_TYPE_CASH) |
4510  (1 << ACCT_TYPE_ASSET) |
4511  (1 << ACCT_TYPE_STOCK) |
4512  (1 << ACCT_TYPE_MUTUAL) |
4513  (1 << ACCT_TYPE_CURRENCY) |
4514  (1 << ACCT_TYPE_CREDIT) |
4515  (1 << ACCT_TYPE_LIABILITY) |
4516  (1 << ACCT_TYPE_RECEIVABLE) |
4517  (1 << ACCT_TYPE_PAYABLE) |
4518  (1 << ACCT_TYPE_ROOT);
4519  case ACCT_TYPE_INCOME:
4520  case ACCT_TYPE_EXPENSE:
4521  return
4522  (1 << ACCT_TYPE_INCOME) |
4523  (1 << ACCT_TYPE_EXPENSE) |
4524  (1 << ACCT_TYPE_ROOT);
4525  case ACCT_TYPE_EQUITY:
4526  return
4527  (1 << ACCT_TYPE_EQUITY) |
4528  (1 << ACCT_TYPE_ROOT);
4529  case ACCT_TYPE_TRADING:
4530  return
4531  (1 << ACCT_TYPE_TRADING) |
4532  (1 << ACCT_TYPE_ROOT);
4533  default:
4534  PERR("bad account type: %d", type);
4535  return 0;
4536  }
4537 }
4538 
4539 gboolean
4541  GNCAccountType child_type)
4542 {
4543  /* ACCT_TYPE_NONE isn't compatible with anything, even ACCT_TYPE_NONE. */
4544  if (parent_type == ACCT_TYPE_NONE || child_type == ACCT_TYPE_NONE)
4545  return FALSE;
4546 
4547  /* ACCT_TYPE_ROOT can't have a parent account, and asking will raise
4548  * an error. */
4549  if (child_type == ACCT_TYPE_ROOT)
4550  return FALSE;
4551 
4552  return ((xaccParentAccountTypesCompatibleWith (child_type) &
4553  (1 << parent_type))
4554  != 0);
4555 }
4556 
4557 guint32
4559 {
4560  guint32 mask = (1 << NUM_ACCOUNT_TYPES) - 1;
4561  mask &= ~((1 << ACCT_TYPE_CURRENCY) | /* DEPRECATED */
4562  (1 << ACCT_TYPE_ROOT)); /* ROOT */
4563 
4564  return mask;
4565 }
4566 
4568 {
4569  switch (t)
4570  {
4571  case ACCT_TYPE_RECEIVABLE:
4572  case ACCT_TYPE_PAYABLE:
4573  return FALSE;
4574  default:
4577  }
4578 }
4579 
4582 {
4583  switch (t)
4584  {
4585  case ACCT_TYPE_BANK:
4586  case ACCT_TYPE_STOCK:
4587  case ACCT_TYPE_MONEYMRKT:
4588  case ACCT_TYPE_CHECKING:
4589  case ACCT_TYPE_SAVINGS:
4590  case ACCT_TYPE_MUTUAL:
4591  case ACCT_TYPE_CURRENCY:
4592  case ACCT_TYPE_CASH:
4593  case ACCT_TYPE_ASSET:
4594  case ACCT_TYPE_RECEIVABLE:
4595  return ACCT_TYPE_ASSET;
4596  case ACCT_TYPE_CREDIT:
4597  case ACCT_TYPE_LIABILITY:
4598  case ACCT_TYPE_PAYABLE:
4599  case ACCT_TYPE_CREDITLINE:
4600  return ACCT_TYPE_LIABILITY;
4601  case ACCT_TYPE_INCOME:
4602  return ACCT_TYPE_INCOME;
4603  case ACCT_TYPE_EXPENSE:
4604  return ACCT_TYPE_EXPENSE;
4605  case ACCT_TYPE_EQUITY:
4606  return ACCT_TYPE_EQUITY;
4607  case ACCT_TYPE_TRADING:
4608  default:
4609  return ACCT_TYPE_NONE;
4610  }
4611 }
4612 
4614 {
4615  switch (t)
4616  {
4617  case ACCT_TYPE_RECEIVABLE:
4618  case ACCT_TYPE_PAYABLE:
4619  return TRUE;
4620  default:
4621  return FALSE;
4622  }
4623 }
4624 
4626 {
4627  switch (t)
4628  {
4629  case ACCT_TYPE_EQUITY:
4630  return TRUE;
4631  default:
4632  return FALSE;
4633  }
4634 }
4635 
4636 gboolean
4638 {
4639  AccountPrivate *priv;
4640 
4641  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4642 
4643  priv = GET_PRIVATE(acc);
4644  return (priv->type == ACCT_TYPE_STOCK || priv->type == ACCT_TYPE_MUTUAL ||
4645  priv->type == ACCT_TYPE_CURRENCY);
4646 }
4647 
4648 /********************************************************************\
4649 \********************************************************************/
4650 
4651 gboolean
4653 {
4654  gint64 date = 0;
4655  GValue v = G_VALUE_INIT;
4656  gboolean retval = FALSE;
4657  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4658  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {KEY_RECONCILE_INFO, "last-date"});
4659  if (G_VALUE_HOLDS_INT64 (&v))
4660  date = g_value_get_int64 (&v);
4661 
4662  g_value_unset (&v);
4663  if (date)
4664  {
4665  if (last_date)
4666  *last_date = date;
4667  retval = TRUE;
4668  }
4669  g_value_unset (&v);
4670  return retval;
4671 }
4672 
4673 /********************************************************************\
4674 \********************************************************************/
4675 
4676 void
4678 {
4679  GValue v = G_VALUE_INIT;
4680  g_return_if_fail(GNC_IS_ACCOUNT(acc));
4681 
4682  g_value_init (&v, G_TYPE_INT64);
4683  g_value_set_int64 (&v, last_date);
4684  xaccAccountBeginEdit (acc);
4685  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {KEY_RECONCILE_INFO, "last-date"});
4686  mark_account (acc);
4687  xaccAccountCommitEdit (acc);
4688  g_value_unset (&v);
4689 }
4690 
4691 /********************************************************************\
4692 \********************************************************************/
4693 
4694 gboolean
4696  int *months, int *days)
4697 {
4698  GValue v1 = G_VALUE_INIT, v2 = G_VALUE_INIT;
4699  int64_t m = 0, d = 0;
4700  gboolean retval = FALSE;
4701 
4702  if (!acc) return FALSE;
4703  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4704  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v1,
4705  {KEY_RECONCILE_INFO, "last-interval", "months"});
4706  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v2,
4707  {KEY_RECONCILE_INFO, "last-interval", "days"});
4708  if (G_VALUE_HOLDS_INT64 (&v1))
4709  m = g_value_get_int64 (&v1);
4710  if (G_VALUE_HOLDS_INT64 (&v2))
4711  d = g_value_get_int64 (&v2);
4712  if (m && d)
4713  {
4714  if (months)
4715  *months = m;
4716  if (days)
4717  *days = d;
4718  retval = TRUE;
4719  }
4720  g_value_unset (&v1);
4721  g_value_unset (&v2);
4722  return retval;
4723 }
4724 
4725 /********************************************************************\
4726 \********************************************************************/
4727 
4728 void
4729 xaccAccountSetReconcileLastInterval (Account *acc, int months, int days)
4730 {
4731  GValue v1 = G_VALUE_INIT, v2 = G_VALUE_INIT;
4732  g_return_if_fail(GNC_IS_ACCOUNT(acc));
4733 
4734  g_value_init (&v1, G_TYPE_INT64);
4735  g_value_set_int64 (&v1, months);
4736  g_value_init (&v2, G_TYPE_INT64);
4737  g_value_set_int64 (&v2, days);
4738  xaccAccountBeginEdit (acc);
4739  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v1,
4740  {KEY_RECONCILE_INFO, "last-interval", "months"});
4741  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v2,
4742  {KEY_RECONCILE_INFO, "last-interval", "days"});
4743  mark_account (acc);
4744  xaccAccountCommitEdit (acc);
4745  g_value_unset (&v1);
4746  g_value_unset (&v2);
4747 }
4748 
4749 /********************************************************************\
4750 \********************************************************************/
4751 
4752 gboolean
4754 {
4755  gint64 date = 0;
4756  gboolean retval = FALSE;
4757  GValue v = G_VALUE_INIT;
4758  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4759  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v,
4760  {KEY_RECONCILE_INFO, KEY_POSTPONE, "date"});
4761  if (G_VALUE_HOLDS_INT64 (&v))
4762  date = g_value_get_int64 (&v);
4763 
4764  if (date)
4765  {
4766  if (postpone_date)
4767  *postpone_date = date;
4768  retval = TRUE;
4769  }
4770  g_value_unset (&v);
4771  return retval;
4772 }
4773 
4774 /********************************************************************\
4775 \********************************************************************/
4776 
4777 void
4779 {
4780  GValue v = G_VALUE_INIT;
4781  g_return_if_fail(GNC_IS_ACCOUNT(acc));
4782 
4783  g_value_init (&v, G_TYPE_INT64);
4784  g_value_set_int64 (&v, postpone_date);
4785  xaccAccountBeginEdit (acc);
4786  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v,
4787  {KEY_RECONCILE_INFO, KEY_POSTPONE, "date"});
4788  mark_account (acc);
4789  xaccAccountCommitEdit (acc);
4790  g_value_unset (&v);
4791 }
4792 
4793 /********************************************************************\
4794 \********************************************************************/
4795 
4796 gboolean
4798  gnc_numeric *balance)
4799 {
4800  gnc_numeric bal = gnc_numeric_zero ();
4801  GValue v = G_VALUE_INIT;
4802  gboolean retval = FALSE;
4803  g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
4804  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v,
4805  {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"});
4806  if (G_VALUE_HOLDS_INT64 (&v))
4807  {
4808  bal = *(gnc_numeric*)g_value_get_boxed (&v);
4809  if (bal.denom)
4810  {
4811  if (balance)
4812  *balance = bal;
4813  retval = TRUE;
4814  }
4815  }
4816  g_value_unset (&v);
4817  return retval;
4818 }
4819 
4820 /********************************************************************\
4821 \********************************************************************/
4822 
4823 void
4825 {
4826  GValue v = G_VALUE_INIT;
4827  g_return_if_fail(GNC_IS_ACCOUNT(acc));
4828 
4829  g_value_init (&v, GNC_TYPE_NUMERIC);
4830  g_value_set_boxed (&v, &balance);
4831  xaccAccountBeginEdit (acc);
4832  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v,
4833  {KEY_RECONCILE_INFO, KEY_POSTPONE, "balance"});
4834  mark_account (acc);
4835  xaccAccountCommitEdit (acc);
4836  g_value_unset (&v);
4837 }
4838 
4839 /********************************************************************\
4840 
4841 \********************************************************************/
4842 
4843 void
4845 {
4846  if (!acc) return;
4847 
4848  xaccAccountBeginEdit (acc);
4849  qof_instance_set_path_kvp (QOF_INSTANCE(acc), nullptr, {KEY_RECONCILE_INFO, KEY_POSTPONE});
4850  mark_account (acc);
4851  xaccAccountCommitEdit (acc);
4852 }
4853 
4854 /********************************************************************\
4855 \********************************************************************/
4856 
4857 const char *
4859 {
4860  auto priv = GET_PRIVATE (acc);
4861  if (priv->last_num == is_unset)
4862  priv->last_num = get_kvp_string_tag (acc, "last-num");
4863  return priv->last_num;
4864 }
4865 
4866 /********************************************************************\
4867 \********************************************************************/
4868 
4869 void
4870 xaccAccountSetLastNum (Account *acc, const char *num)
4871 {
4872  auto priv = GET_PRIVATE (acc);
4873  if (priv->last_num != is_unset)
4874  g_free (priv->last_num);
4875  priv->last_num = g_strdup (num);
4876  set_kvp_string_tag (acc, "last-num", priv->last_num);
4877 }
4878 
4879 static Account *
4880 GetOrMakeOrphanAccount (Account *root, gnc_commodity * currency)
4881 {
4882  char * accname;
4883  Account * acc;
4884 
4885  g_return_val_if_fail (root, NULL);
4886 
4887  /* build the account name */
4888  if (!currency)
4889  {
4890  PERR ("No currency specified!");
4891  return NULL;
4892  }
4893 
4894  accname = g_strconcat (_("Orphaned Gains"), "-",
4895  gnc_commodity_get_mnemonic (currency), nullptr);
4896 
4897  /* See if we've got one of these going already ... */
4898  acc = gnc_account_lookup_by_name(root, accname);
4899 
4900  if (acc == NULL)
4901  {
4902  /* Guess not. We'll have to build one. */
4903  acc = xaccMallocAccount (gnc_account_get_book(root));
4904  xaccAccountBeginEdit (acc);
4905  xaccAccountSetName (acc, accname);
4906  xaccAccountSetCommodity (acc, currency);
4908  xaccAccountSetDescription (acc, _("Realized Gain/Loss"));
4909  xaccAccountSetNotes (acc,
4910  _("Realized Gains or Losses from "
4911  "Commodity or Trading Accounts "
4912  "that haven't been recorded elsewhere."));
4913 
4914  /* Hang the account off the root. */
4915  gnc_account_append_child (root, acc);
4916  xaccAccountCommitEdit (acc);
4917  }
4918 
4919  g_free (accname);
4920 
4921  return acc;
4922 }
4923 
4924 Account *
4925 xaccAccountGainsAccount (Account *acc, gnc_commodity *curr)
4926 {
4927  GValue v = G_VALUE_INIT;
4928  std::vector<std::string> path {KEY_LOT_MGMT, "gains-acct",
4930  GncGUID *guid = NULL;
4931  Account *gains_account;
4932 
4933  g_return_val_if_fail (acc != NULL, NULL);
4934  qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, path);
4935  if (G_VALUE_HOLDS_BOXED (&v))
4936  guid = (GncGUID*)g_value_get_boxed (&v);
4937  if (guid == NULL) /* No gains account for this currency */
4938  {
4939  gains_account = GetOrMakeOrphanAccount (gnc_account_get_root (acc),
4940  curr);
4941  guid = (GncGUID*)qof_instance_get_guid (QOF_INSTANCE (gains_account));
4942  xaccAccountBeginEdit (acc);
4943  {
4944  GValue vr = G_VALUE_INIT;
4945  g_value_init (&vr, GNC_TYPE_GUID);
4946  g_value_set_boxed (&vr, guid);
4947  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &vr, path);
4948  qof_instance_set_dirty (QOF_INSTANCE (acc));
4949  g_value_unset (&vr);
4950  }
4951  xaccAccountCommitEdit (acc);
4952  }
4953  else
4954  gains_account = xaccAccountLookup (guid,
4955  qof_instance_get_book(acc));
4956 
4957  g_value_unset (&v);
4958  return gains_account;
4959 }
4960 
4961 /********************************************************************\
4962 \********************************************************************/
4963 
4964 void
4965 dxaccAccountSetPriceSrc(Account *acc, const char *src)
4966 {
4967  if (!acc) return;
4968 
4969  if (xaccAccountIsPriced(acc))
4970  set_kvp_string_tag (acc, "old-price-source", src);
4971 }
4972 
4973 /********************************************************************\
4974 \********************************************************************/
4975 
4976 const char*
4978 {
4979  static char *source = nullptr;
4980  if (!acc) return NULL;
4981 
4982  if (!xaccAccountIsPriced(acc)) return NULL;
4983 
4984  g_free (source);
4985  source = get_kvp_string_tag (acc, "old-price-source");
4986  return source;
4987 }
4988 
4989 /********************************************************************\
4990 \********************************************************************/
4991 
4992 void
4993 dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
4994 {
4995  if (!acc) return;
4996  if (!xaccAccountIsPriced(acc)) return;
4997  set_kvp_string_tag (acc, "old-quote-tz", tz);
4998 }
4999 
5000 /********************************************************************\
5001 \********************************************************************/
5002 
5003 const char*
5005 {
5006  static char *quote_tz = nullptr;
5007  if (!acc) return NULL;
5008  if (!xaccAccountIsPriced(acc)) return NULL;
5009  g_free (quote_tz);
5010  quote_tz = get_kvp_string_tag (acc, "old-quote-tz");
5011  return quote_tz;
5012 }
5013 
5014 /********************************************************************\
5015 \********************************************************************/
5016 
5017 void
5019 {
5020  GValue v = G_VALUE_INIT;
5021  if (!acc) return;
5022 
5023  xaccAccountBeginEdit (acc);
5024  /* Would have been nice to use G_TYPE_BOOLEAN, but the other
5025  * boolean kvps save the value as "true" or "false" and that would
5026  * be file-incompatible with this.
5027  */
5028  g_value_init (&v, G_TYPE_INT64);
5029  g_value_set_int64 (&v, status);
5030  qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v,
5031  {KEY_RECONCILE_INFO, KEY_INCLUDE_CHILDREN});
5032  mark_account(acc);
5033  xaccAccountCommitEdit (acc);
5034  g_value_unset (&v);
5035 }
5036 
5037 /********************************************************************\
5038 \********************************************************************/
5039 
5040 gboolean
5042 {
5043  /* access the account's kvp-data for status and return that, if no value
5044  * is found then we can assume not to include the children, that being
5045  * the default behaviour
5046  */
5047  GValue v = G_VALUE_INIT;
5048  gboolean retval;
5049  if (!acc) return FALSE;
5050  qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v,
5051  {KEY_RECONCILE_INFO, KEY_INCLUDE_CHILDREN});
5052  retval = G_VALUE_HOLDS_INT64 (&v) ? g_value_get_int64 (&v) : FALSE;
5053  g_value_unset (&v);
5054  return retval;
5055 }
5056 
5057 /********************************************************************\
5058 \********************************************************************/
5059 
5060 /* The caller of this function can get back one or both of the
5061  * matching split and transaction pointers, depending on whether
5062  * a valid pointer to the location to store those pointers is
5063  * passed.
5064  */
5065 static void
5066 finder_help_function(const Account *acc, const char *description,
5067  Split **split, Transaction **trans )
5068 {
5069  AccountPrivate *priv;
5070  GList *slp;
5071 
5072  /* First, make sure we set the data to NULL BEFORE we start */
5073  if (split) *split = NULL;
5074  if (trans) *trans = NULL;
5075 
5076  /* Then see if we have any work to do */
5077  if (acc == NULL) return;
5078 
5079  /* Why is this loop iterated backwards ?? Presumably because the split
5080  * list is in date order, and the most recent matches should be
5081  * returned!? */
5082  priv = GET_PRIVATE(acc);
5083  for (slp = g_list_last(priv->splits); slp; slp = slp->prev)
5084  {
5085  Split *lsplit = static_cast<Split*>(slp->data);
5086  Transaction *ltrans = xaccSplitGetParent(lsplit);
5087 
5088  if (g_strcmp0 (description, xaccTransGetDescription (ltrans)) == 0)
5089  {
5090  if (split) *split = lsplit;
5091  if (trans) *trans = ltrans;
5092  return;
5093  }
5094  }
5095 }
5096 
5097 Split *
5098 xaccAccountFindSplitByDesc(const Account *acc, const char *description)
5099 {
5100  Split *split;
5101 
5102  /* Get the split which has a transaction matching the description. */
5103  finder_help_function(acc, description, &split, NULL);
5104  return split;
5105 }
5106 
5107 /* This routine is for finding a matching transaction in an account by
5108  * matching on the description field. [CAS: The rest of this comment
5109  * seems to belong somewhere else.] This routine is used for
5110  * auto-filling in registers with a default leading account. The
5111  * dest_trans is a transaction used for currency checking. */
5112 Transaction *
5113 xaccAccountFindTransByDesc(const Account *acc, const char *description)
5114 {
5115  Transaction *trans;
5116 
5117  /* Get the translation matching the description. */
5118  finder_help_function(acc, description, NULL, &trans);
5119  return trans;
5120 }
5121 
5122 /* ================================================================ */
5123 /* Concatenation, Merging functions */
5124 
5125 void
5126 gnc_account_join_children (Account *to_parent, Account *from_parent)
5127 {
5128  AccountPrivate *from_priv;
5129  GList *children, *node;
5130 
5131  /* errors */
5132  g_return_if_fail(GNC_IS_ACCOUNT(to_parent));
5133  g_return_if_fail(GNC_IS_ACCOUNT(from_parent));
5134 
5135  /* optimizations */
5136  from_priv = GET_PRIVATE(from_parent);
5137  if (!from_priv->children)
5138  return;
5139 
5140  ENTER (" ");
5141  children = g_list_copy(from_priv->children);
5142  for (node = children; node; node = g_list_next(node))
5143  gnc_account_append_child(to_parent, static_cast <Account*> (node->data));
5144  g_list_free(children);
5145  LEAVE (" ");
5146 }
5147 /********************************************************************\
5148 \********************************************************************/
5149 
5150 void
5152 {
5153  AccountPrivate *ppriv, *priv_a, *priv_b;
5154  GList *node_a, *node_b, *work, *worker;
5155 
5156  g_return_if_fail(GNC_IS_ACCOUNT(parent));
5157 
5158  ppriv = GET_PRIVATE(parent);
5159  for (node_a = ppriv->children; node_a; node_a = node_a->next)
5160  {
5161  Account *acc_a = static_cast <Account*> (node_a->data);
5162 
5163  priv_a = GET_PRIVATE(acc_a);
5164  for (node_b = node_a->next; node_b; node_b = g_list_next(node_b))
5165  {
5166  Account *acc_b = static_cast <Account*> (node_b->data);
5167 
5168  priv_b = GET_PRIVATE(acc_b);
5169  if (0 != null_strcmp(priv_a->accountName, priv_b->accountName))
5170  continue;
5171  if (0 != null_strcmp(priv_a->accountCode, priv_b->accountCode))
5172  continue;
5173  if (0 != null_strcmp(priv_a->description, priv_b->description))
5174  continue;
5175  if (0 != null_strcmp(xaccAccountGetColor(acc_a),
5176  xaccAccountGetColor(acc_b)))
5177  continue;
5178  if (!gnc_commodity_equiv(priv_a->commodity, priv_b->commodity))
5179  continue;
5180  if (0 != null_strcmp(xaccAccountGetNotes(acc_a),
5181  xaccAccountGetNotes(acc_b)))
5182  continue;
5183  if (priv_a->type != priv_b->type)
5184  continue;
5185 
5186  /* consolidate children */
5187  if (priv_b->children)
5188  {
5189  work = g_list_copy(priv_b->children);
5190  for (worker = work; worker; worker = g_list_next(worker))
5191  gnc_account_append_child (acc_a, (Account *)worker->data);
5192  g_list_free(work);
5193 
5194  qof_event_gen (&acc_a->inst, QOF_EVENT_MODIFY, NULL);
5195  qof_event_gen (&acc_b->inst, QOF_EVENT_MODIFY, NULL);
5196  }
5197 
5198  /* recurse to do the children's children */
5200 
5201  /* consolidate transactions */
5202  while (priv_b->splits)
5203  xaccSplitSetAccount (static_cast <Split*> (priv_b->splits->data), acc_a);
5204 
5205  /* move back one before removal. next iteration around the loop
5206  * will get the node after node_b */
5207  node_b = g_list_previous(node_b);
5208 
5209  /* The destroy function will remove from list -- node_a is ok,
5210  * it's before node_b */
5211  xaccAccountBeginEdit (acc_b);
5212  xaccAccountDestroy (acc_b);
5213  }
5214  }
5215 }
5216 
5217 /* ================================================================ */
5218 /* Transaction Traversal functions */
5219 
5220 
5221 void
5223 {
5224  GList *lp;
5225 
5226  for (lp = splits; lp; lp = lp->next)
5227  {
5228  Split *s = static_cast <Split*> (lp->data);
5229  Transaction *trans = s->parent;
5230 
5231  if (trans)
5232  trans->marker = 0;
5233  }
5234 }
5235 
5236 /* original function */
5237 void
5239 {
5240  AccountPrivate *priv;
5241 
5242  if (!account)
5243  return;
5244  priv = GET_PRIVATE(account);
5246 }
5247 
5248 gboolean
5249 xaccTransactionTraverse (Transaction *trans, int stage)
5250 {
5251  if (trans == NULL) return FALSE;
5252 
5253  if (trans->marker < stage)
5254  {
5255  trans->marker = stage;
5256  return TRUE;
5257  }
5258 
5259  return FALSE;
5260 }
5261 
5262 static void do_one_split (Split *s, gpointer data)
5263 {
5264  Transaction *trans = s->parent;
5265  trans->marker = 0;
5266 }
5267 
5268 static void do_one_account (Account *account, gpointer data)
5269 {
5270  AccountPrivate *priv = GET_PRIVATE(account);
5271  g_list_foreach(priv->splits, (GFunc)do_one_split, NULL);
5272 }
5273 
5274 /* Replacement for xaccGroupBeginStagedTransactionTraversals */
5275 void
5277 {
5278  GList *descendants;
5279 
5280  descendants = gnc_account_get_descendants(account);
5281  g_list_foreach(descendants, (GFunc)do_one_account, NULL);
5282  g_list_free(descendants);
5283 }
5284 
5285 int
5287  unsigned int stage,
5288  TransactionCallback thunk,
5289  void *cb_data)
5290 {
5291  AccountPrivate *priv;
5292  GList *split_p;
5293  GList *next;
5294  Transaction *trans;
5295  Split *s;
5296  int retval;
5297 
5298  if (!acc) return 0;
5299 
5300  priv = GET_PRIVATE(acc);
5301  for (split_p = priv->splits; split_p; split_p = next)
5302  {
5303  /* Get the next element in the split list now, just in case some
5304  * naughty thunk destroys the one we're using. This reduces, but
5305  * does not eliminate, the possibility of undefined results if
5306  * a thunk removes splits from this account. */
5307  next = g_list_next(split_p);
5308 
5309  s = static_cast <Split*> (split_p->data);
5310  trans = s->parent;
5311  if (trans && (trans->marker < stage))
5312  {
5313  trans->marker = stage;
5314  if (thunk)
5315  {
5316  retval = thunk(trans, cb_data);
5317  if (retval) return retval;
5318  }
5319  }
5320  }
5321 
5322  return 0;
5323 }
5324 
5325 int
5327  unsigned int stage,
5328  TransactionCallback thunk,
5329  void *cb_data)
5330 {
5331  const AccountPrivate *priv;
5332  GList *acc_p, *split_p;
5333  Transaction *trans;
5334  Split *s;
5335  int retval;
5336 
5337  if (!acc) return 0;
5338 
5339  /* depth first traversal */
5340  priv = GET_PRIVATE(acc);
5341  for (acc_p = priv->children; acc_p; acc_p = g_list_next(acc_p))
5342  {
5343  retval = gnc_account_tree_staged_transaction_traversal(static_cast <Account*> (acc_p->data),
5344  stage, thunk, cb_data);
5345  if (retval) return retval;
5346  }
5347 
5348  /* Now this account */
5349  for (split_p = priv->splits; split_p; split_p = g_list_next(split_p))
5350  {
5351  s = static_cast <Split*> (split_p->data);
5352  trans = s->parent;
5353  if (trans && (trans->marker < stage))
5354  {
5355  trans->marker = stage;
5356  if (thunk)
5357  {
5358  retval = thunk(trans, cb_data);
5359  if (retval) return retval;
5360  }
5361  }
5362  }
5363 
5364  return 0;
5365 }
5366 
5367 /********************************************************************\
5368 \********************************************************************/
5369 
5370 int
5372  int (*proc)(Transaction *t, void *data),
5373  void *data)
5374 {
5375  if (!acc || !proc) return 0;
5376 
5378  return gnc_account_tree_staged_transaction_traversal (acc, 42, proc, data);
5379 }
5380 
5381 
5382 gint
5383 xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
5384  void *data)
5385 {
5386  if (!acc || !proc) return 0;
5388  return xaccAccountStagedTransactionTraversal(acc, 42, proc, data);
5389 }
5390 
5391 /* ================================================================ */
5392 /* The following functions are used by
5393  * src/import-export/import-backend.c to manipulate the contra-account
5394  * matching data. See src/import-export/import-backend.c for explanations.
5395  */
5396 
5397 #define IMAP_FRAME "import-map"
5398 #define IMAP_FRAME_BAYES "import-map-bayes"
5399 
5400 /* Obtain an ImportMatchMap object from an Account or a Book */
5403 {
5404  GncImportMatchMap *imap;
5405 
5406  if (!acc) return NULL;
5407 
5408  imap = g_new0(GncImportMatchMap, 1);
5409 
5410  /* Cache the book for easy lookups; store the account/book for
5411  * marking dirtiness
5412  */
5413  imap->acc = acc;
5414  imap->book = gnc_account_get_book (acc);
5415 
5416  return imap;
5417 }
5418 
5419 /* Look up an Account in the map */
5420 Account*
5421 gnc_account_imap_find_account (GncImportMatchMap *imap,
5422  const char *category,
5423  const char *key)
5424 {
5425  GValue v = G_VALUE_INIT;
5426  GncGUID * guid = NULL;
5427  Account *retval;
5428  if (!imap || !key) return NULL;
5429  std::vector<std::string> path {IMAP_FRAME};
5430  if (category)
5431  path.push_back (category);
5432  path.push_back (key);
5433  qof_instance_get_path_kvp (QOF_INSTANCE (imap->acc), &v, path);
5434  if (G_VALUE_HOLDS_BOXED (&v))
5435  guid = (GncGUID*)g_value_get_boxed (&v);
5436  retval = xaccAccountLookup (guid, imap->book);
5437  g_value_unset (&v);
5438  return retval;
5439 }
5440 
5441 /* Store an Account in the map */
5442 void
5443 gnc_account_imap_add_account (GncImportMatchMap *imap,
5444  const char *category,
5445  const char *key,
5446  Account *acc)
5447 {
5448  GValue v = G_VALUE_INIT;
5449  if (!imap || !key || !acc || (strlen (key) == 0)) return;
5450  std::vector<std::string> path {IMAP_FRAME};
5451  if (category)
5452  path.emplace_back (category);
5453  path.emplace_back (key);
5454  g_value_init (&v, GNC_TYPE_GUID);
5455  g_value_set_boxed (&v, xaccAccountGetGUID (acc));
5456  xaccAccountBeginEdit (imap->acc);
5457  qof_instance_set_path_kvp (QOF_INSTANCE (imap->acc), &v, path);
5458  qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
5459  xaccAccountCommitEdit (imap->acc);
5460  g_value_unset (&v);
5461 }
5462 
5463 /* Remove a reference to an Account in the map */
5464 void
5465 gnc_account_imap_delete_account (GncImportMatchMap *imap,
5466  const char *category,
5467  const char *key)
5468 {
5469  if (!imap || !key) return;
5470  std::vector<std::string> path {IMAP_FRAME};
5471  if (category)
5472  path.emplace_back (category);
5473  path.emplace_back (key);
5474  xaccAccountBeginEdit (imap->acc);
5475  if (qof_instance_has_path_slot (QOF_INSTANCE (imap->acc), path))
5476  {
5477  qof_instance_slot_path_delete (QOF_INSTANCE (imap->acc), path);
5478  if (category)
5479  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (imap->acc), {IMAP_FRAME, category});
5480  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (imap->acc), {IMAP_FRAME});
5481  }
5482  qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
5483  xaccAccountCommitEdit (imap->acc);
5484 }
5485 
5486 /*--------------------------------------------------------------------------
5487  Below here is the bayes transaction to account matching system
5488 --------------------------------------------------------------------------*/
5489 
5490 
5496 {
5497  double product; /* product of probabilities */
5498  double product_difference; /* product of (1-probabilities) */
5499 };
5500 
5502 {
5503  std::string account_guid;
5504  int64_t token_count;
5505 };
5506 
5511 {
5512  std::vector<AccountTokenCount> accounts;
5513  int64_t total_count;
5514 };
5515 
5520 {
5521  std::string account_guid;
5522  int32_t probability;
5523 };
5524 
5525 static void
5526 build_token_info(char const * suffix, KvpValue * value, TokenAccountsInfo & tokenInfo)
5527 {
5528  if (strlen(suffix) == GUID_ENCODING_LENGTH)
5529  {
5530  tokenInfo.total_count += value->get<int64_t>();
5531  /*By convention, the key ends with the account GUID.*/
5532  tokenInfo.accounts.emplace_back(AccountTokenCount{std::string{suffix}, value->get<int64_t>()});
5533  }
5534 }
5535 
5539 static constexpr int probability_factor = 100000;
5540 
5541 static FinalProbabilityVec
5542 build_probabilities(ProbabilityVec const & first_pass)
5543 {
5544  FinalProbabilityVec ret;
5545  for (auto const & first_pass_prob : first_pass)
5546  {
5547  auto const & account_probability = first_pass_prob.second;
5548  /* P(AB) = A*B / [A*B + (1-A)*(1-B)]
5549  * NOTE: so we only keep track of a running product(A*B*C...)
5550  * and product difference ((1-A)(1-B)...)
5551  */
5552  int32_t probability = (account_probability.product /
5553  (account_probability.product + account_probability.product_difference)) * probability_factor;
5554  ret.push_back({first_pass_prob.first, probability});
5555  }
5556  return ret;
5557 }
5558 
5559 static AccountInfo
5560 highest_probability(FinalProbabilityVec const & probabilities)
5561 {
5562  AccountInfo ret {"", std::numeric_limits<int32_t>::min()};
5563  for (auto const & prob : probabilities)
5564  if (prob.second > ret.probability)
5565  ret = AccountInfo {prob.first, prob.second};
5566  return ret;
5567 }
5568 
5569 static ProbabilityVec
5570 get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
5571 {
5572  ProbabilityVec ret;
5573  /* find the probability for each account that contains any of the tokens
5574  * in the input tokens list. */
5575  for (auto current_token = tokens; current_token; current_token = current_token->next)
5576  {
5577  TokenAccountsInfo tokenInfo{};
5578  auto path = std::string{IMAP_FRAME_BAYES "/"} + static_cast <char const *> (current_token->data) + "/";
5579  qof_instance_foreach_slot_prefix (QOF_INSTANCE (imap->acc), path, &build_token_info, tokenInfo);
5580  for (auto const & current_account_token : tokenInfo.accounts)
5581  {
5582  auto item = std::find_if(ret.begin(), ret.end(), [&current_account_token]
5583  (std::pair<std::string, AccountProbability> const & a) {
5584  return current_account_token.account_guid == a.first;
5585  });
5586  if (item != ret.end())
5587  {/* This account is already in the map */
5588  item->second.product = ((double)current_account_token.token_count /
5589  (double)tokenInfo.total_count) * item->second.product;
5590  item->second.product_difference = ((double)1 - ((double)current_account_token.token_count /
5591  (double)tokenInfo.total_count)) * item->second.product_difference;
5592  }
5593  else
5594  {
5595  /* add a new entry */
5596  AccountProbability new_probability;
5597  new_probability.product = ((double)current_account_token.token_count /
5598  (double)tokenInfo.total_count);
5599  new_probability.product_difference = 1 - (new_probability.product);
5600  ret.push_back({current_account_token.account_guid, std::move(new_probability)});
5601  }
5602  } /* for all accounts in tokenInfo */
5603  }
5604  return ret;
5605 }
5606 
5607 static std::string
5608 look_for_old_separator_descendants (Account *root, std::string const & full_name, const gchar *separator)
5609 {
5610  GList *top_accounts, *ptr;
5611  gint found_len = 0;
5612  gchar found_sep;
5613  top_accounts = gnc_account_get_descendants (root);
5614  PINFO("Incoming full_name is '%s', current separator is '%s'", full_name.c_str (), separator);
5615  /* Go through list of top level accounts */
5616  for (ptr = top_accounts; ptr; ptr = g_list_next (ptr))
5617  {
5618  const gchar *name = xaccAccountGetName (static_cast <Account const *> (ptr->data));
5619  // we are looking for the longest top level account that matches
5620  if (g_str_has_prefix (full_name.c_str (), name))
5621  {
5622  gint name_len = strlen (name);
5623  const gchar old_sep = full_name[name_len];
5624  if (!g_ascii_isalnum (old_sep)) // test for non alpha numeric
5625  {
5626  if (name_len > found_len)
5627  {
5628  found_sep = full_name[name_len];
5629  found_len = name_len;
5630  }
5631  }
5632  }
5633  }
5634  g_list_free (top_accounts); // Free the List
5635  std::string new_name {full_name};
5636  if (found_len > 1)
5637  std::replace (new_name.begin (), new_name.end (), found_sep, *separator);
5638  PINFO ("Return full_name is '%s'", new_name.c_str ());
5639  return new_name;
5640 }
5641 
5642 static std::string
5643 get_guid_from_account_name (Account * root, std::string const & name)
5644 {
5645  auto map_account = gnc_account_lookup_by_full_name (root, name.c_str ());
5646  if (!map_account)
5647  {
5648  auto temp_account_name = look_for_old_separator_descendants (root, name,
5650  map_account = gnc_account_lookup_by_full_name (root, temp_account_name.c_str ());
5651  }
5652  auto temp_guid = gnc::GUID {*xaccAccountGetGUID (map_account)};
5653  return temp_guid.to_string ();
5654 }
5655 
5656 static FlatKvpEntry
5657 convert_entry (KvpEntry entry, Account* root)
5658 {
5659  /*We need to make a copy here.*/
5660  auto account_name = entry.first.back();
5661  if (!gnc::GUID::is_valid_guid (account_name))
5662  {
5663  /* Earlier version stored the account name in the import map, and
5664  * there were early beta versions of 2.7 that stored a GUID.
5665  * If there is no GUID, we assume it's an account name. */
5666  /* Take off the account name and replace it with the GUID */
5667  entry.first.pop_back();
5668  auto guid_str = get_guid_from_account_name (root, account_name);
5669  entry.first.emplace_back (guid_str);
5670  }
5671  std::string new_key {std::accumulate (entry.first.begin(), entry.first.end(), std::string {})};
5672  new_key = IMAP_FRAME_BAYES + new_key;
5673  return {new_key, entry.second};
5674 }
5675 
5676 static std::vector<FlatKvpEntry>
5677 get_flat_imap (Account * acc)
5678 {
5679  auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
5680  auto slot = frame->get_slot ({IMAP_FRAME_BAYES});
5681  if (!slot)
5682  return {};
5683  auto imap_frame = slot->get<KvpFrame*> ();
5684  auto flat_kvp = imap_frame->flatten_kvp ();
5685  auto root = gnc_account_get_root (acc);
5686  std::vector <FlatKvpEntry> ret;
5687  for (auto const & flat_entry : flat_kvp)
5688  {
5689  auto converted_entry = convert_entry (flat_entry, root);
5690  /*If the entry was invalid, we don't perpetuate it.*/
5691  if (converted_entry.first.size())
5692  ret.emplace_back (converted_entry);
5693  }
5694  return ret;
5695 }
5696 
5697 static bool
5698 convert_imap_account_bayes_to_flat (Account *acc)
5699 {
5700  auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
5701  if (!frame->get_keys().size())
5702  return false;
5703  auto flat_imap = get_flat_imap(acc);
5704  if (!flat_imap.size ())
5705  return false;
5706  xaccAccountBeginEdit(acc);
5707  frame->set({IMAP_FRAME_BAYES}, nullptr);
5708  std::for_each(flat_imap.begin(), flat_imap.end(),
5709  [&frame] (FlatKvpEntry const & entry) {
5710  frame->set({entry.first.c_str()}, entry.second);
5711  });
5712  qof_instance_set_dirty (QOF_INSTANCE (acc));
5713  xaccAccountCommitEdit(acc);
5714  return true;
5715 }
5716 
5717 /*
5718  * Checks for import map data and converts them when found.
5719  */
5720 static bool
5721 imap_convert_bayes_to_flat (QofBook * book)
5722 {
5723  auto root = gnc_book_get_root_account (book);
5724  auto accts = gnc_account_get_descendants_sorted (root);
5725  bool ret = false;
5726  for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
5727  {
5728  Account *acc = static_cast <Account*> (ptr->data);
5729  if (convert_imap_account_bayes_to_flat (acc))
5730  {
5731  ret = true;
5732  gnc_features_set_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN);
5733  }
5734  }
5735  g_list_free (accts);
5736  return ret;
5737 }
5738 
5739 void
5741 {
5742  imap_convert_bayes_to_flat_run = false;
5743 }
5744 
5745 /*
5746  * Here we check to see the state of import map data.
5747  *
5748  * If the GUID_FLAT_BAYESIAN feature flag is set, everything
5749  * should be fine.
5750  *
5751  * If it is not set, there are two possibilities: import data
5752  * are present from a previous version or not. If they are,
5753  * they are converted, and the feature flag set. If there are
5754  * no previous data, nothing is done.
5755  */
5756 static void
5757 check_import_map_data (QofBook *book)
5758 {
5759  if (gnc_features_check_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN) ||
5760  imap_convert_bayes_to_flat_run)
5761  return;
5762 
5763  /* This function will set GNC_FEATURE_GUID_FLAT_BAYESIAN if necessary.*/
5764  imap_convert_bayes_to_flat (book);
5765  imap_convert_bayes_to_flat_run = true;
5766 }
5767 
5768 static constexpr double threshold = .90 * probability_factor; /* 90% */
5769 
5771 Account*
5773 {
5774  if (!imap)
5775  return nullptr;
5776  check_import_map_data (imap->book);
5777  auto first_pass = get_first_pass_probabilities(imap, tokens);
5778  if (!first_pass.size())
5779  return nullptr;
5780  auto final_probabilities = build_probabilities(first_pass);
5781  if (!final_probabilities.size())
5782  return nullptr;
5783  auto best = highest_probability(final_probabilities);
5784  if (best.account_guid == "")
5785  return nullptr;
5786  if (best.probability < threshold)
5787  return nullptr;
5788  gnc::GUID guid;
5789  try {
5790  guid = gnc::GUID::from_string(best.account_guid);
5791  } catch (gnc::guid_syntax_exception&) {
5792  return nullptr;
5793  }
5794  auto account = xaccAccountLookup (reinterpret_cast<GncGUID*>(&guid), imap->book);
5795  return account;
5796 }
5797 
5798 static void
5799 change_imap_entry (GncImportMatchMap *imap, std::string const & path, int64_t token_count)
5800 {
5801  GValue value = G_VALUE_INIT;
5802 
5803  PINFO("Source Account is '%s', Count is '%" G_GINT64_FORMAT "'",
5804  xaccAccountGetName (imap->acc), token_count);
5805 
5806  // check for existing guid entry
5807  if (qof_instance_has_slot (QOF_INSTANCE(imap->acc), path.c_str ()))
5808  {
5809  int64_t existing_token_count = 0;
5810 
5811  // get the existing_token_count value
5812  qof_instance_get_path_kvp (QOF_INSTANCE (imap->acc), &value, {path});
5813 
5814  if (G_VALUE_HOLDS_INT64 (&value))
5815  existing_token_count = g_value_get_int64 (&value);
5816 
5817  PINFO("found existing value of '%" G_GINT64_FORMAT "'", existing_token_count);
5818 
5819  token_count = token_count + existing_token_count;
5820  }
5821 
5822  if (!G_IS_VALUE (&value))
5823  g_value_init (&value, G_TYPE_INT64);
5824 
5825  g_value_set_int64 (&value, token_count);
5826 
5827  // Add or Update the entry based on guid
5828  qof_instance_set_path_kvp (QOF_INSTANCE (imap->acc), &value, {path});
5829  gnc_features_set_used (imap->book, GNC_FEATURE_GUID_FLAT_BAYESIAN);
5830  g_value_unset (&value);
5831 }
5832 
5834 void
5836  GList *tokens,
5837  Account *acc)
5838 {
5839  GList *current_token;
5840  gint64 token_count;
5841  char *account_fullname;
5842  char *guid_string;
5843 
5844  ENTER(" ");
5845  if (!imap)
5846  {
5847  LEAVE(" ");
5848  return;
5849  }
5850  check_import_map_data (imap->book);
5851 
5852  g_return_if_fail (acc != NULL);
5853  account_fullname = gnc_account_get_full_name(acc);
5854  xaccAccountBeginEdit (imap->acc);
5855 
5856  PINFO("account name: '%s'", account_fullname);
5857 
5858  guid_string = guid_to_string (xaccAccountGetGUID (acc));
5859 
5860  /* process each token in the list */
5861  for (current_token = g_list_first(tokens); current_token;
5862  current_token = current_token->next)
5863  {
5864  /* Jump to next iteration if the pointer is not valid or if the
5865  string is empty. In HBCI import we almost always get an empty
5866  string, which doesn't work in the kvp loopkup later. So we
5867  skip this case here. */
5868  if (!current_token->data || (*((char*)current_token->data) == '\0'))
5869  continue;
5870  /* start off with one token for this account */
5871  token_count = 1;
5872  PINFO("adding token '%s'", (char*)current_token->data);
5873  auto path = std::string {IMAP_FRAME_BAYES} + '/' + static_cast<char*>(current_token->data) + '/' + guid_string;
5874  /* change the imap entry for the account */
5875  change_imap_entry (imap, path, token_count);
5876  }
5877  /* free up the account fullname and guid string */
5878  qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
5879  xaccAccountCommitEdit (imap->acc);
5880  g_free (account_fullname);
5881  g_free (guid_string);
5882  LEAVE(" ");
5883 }
5884 
5885 /*******************************************************************************/
5886 
5887 static void
5888 build_non_bayes (const char *key, const GValue *value, gpointer user_data)
5889 {
5890  if (!G_VALUE_HOLDS_BOXED (value))
5891  return;
5892  QofBook *book;
5893  GncGUID *guid = NULL;
5894  gchar *guid_string = NULL;
5895  auto imapInfo = (GncImapInfo*)user_data;
5896  // Get the book
5897  book = qof_instance_get_book (imapInfo->source_account);
5898 
5899  guid = (GncGUID*)g_value_get_boxed (value);
5900  guid_string = guid_to_string (guid);
5901 
5902  PINFO("build_non_bayes: match string '%s', match account guid: '%s'",
5903  (char*)key, guid_string);
5904 
5905  auto imapInfo_node = static_cast <GncImapInfo*> (g_malloc(sizeof(GncImapInfo)));
5906 
5907  imapInfo_node->source_account = imapInfo->source_account;
5908  imapInfo_node->map_account = xaccAccountLookup (guid, book);
5909  imapInfo_node->head = g_strdup (imapInfo->head);
5910  imapInfo_node->match_string = g_strdup (key);
5911  imapInfo_node->category = g_strdup (imapInfo->category);
5912  imapInfo_node->count = g_strdup (" ");
5913 
5914  imapInfo->list = g_list_prepend (imapInfo->list, imapInfo_node);
5915 
5916  g_free (guid_string);
5917 }
5918 
5919 static void
5920 build_bayes (const char *suffix, KvpValue * value, GncImapInfo & imapInfo)
5921 {
5922  size_t guid_start = strlen(suffix) - GUID_ENCODING_LENGTH;
5923  std::string account_guid {&suffix[guid_start]};
5924  GncGUID guid;
5925  try
5926  {
5927  guid = gnc::GUID::from_string (account_guid);
5928  }
5929  catch (const gnc::guid_syntax_exception& err)
5930  {
5931  PWARN("Invalid GUID string from %s%s", IMAP_FRAME_BAYES, suffix);
5932  }
5933  auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
5934  auto imap_node = static_cast <GncImapInfo*> (g_malloc (sizeof (GncImapInfo)));
5935  auto count = value->get <int64_t> ();
5936  imap_node->source_account = imapInfo.source_account;
5937  imap_node->map_account = map_account;
5938  imap_node->head = g_strdup_printf ("%s%s", IMAP_FRAME_BAYES, suffix);
5939  imap_node->match_string = g_strndup (&suffix[1], guid_start - 2);
5940  imap_node->category = g_strdup(" ");
5941  imap_node->count = g_strdup_printf ("%" G_GINT64_FORMAT, count);
5942  imapInfo.list = g_list_prepend (imapInfo.list, imap_node);
5943 }
5944 
5945 GList *
5947 {
5948  check_import_map_data (gnc_account_get_book (acc));
5949  /* A dummy object which is used to hold the specified account, and the list
5950  * of data about which we care. */
5951  GncImapInfo imapInfo {acc, nullptr};
5952  qof_instance_foreach_slot_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES, &build_bayes, imapInfo);
5953  return g_list_reverse(imapInfo.list);
5954 }
5955 
5956 GList *
5957 gnc_account_imap_get_info (Account *acc, const char *category)
5958 {
5959  GList *list = NULL;
5960 
5961  GncImapInfo imapInfo;
5962 
5963  std::vector<std::string> path {IMAP_FRAME};
5964  if (category)
5965  path.emplace_back (category);
5966 
5967  imapInfo.source_account = acc;
5968  imapInfo.list = list;
5969 
5970  imapInfo.head = g_strdup (IMAP_FRAME);
5971  imapInfo.category = g_strdup (category);
5972 
5973  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
5974  {
5975  qof_instance_foreach_slot (QOF_INSTANCE(acc), IMAP_FRAME, category,
5976  build_non_bayes, &imapInfo);
5977  }
5978  return g_list_reverse(imapInfo.list);
5979 }
5980 
5981 /*******************************************************************************/
5982 
5983 gchar *
5984 gnc_account_get_map_entry (Account *acc, const char *head, const char *category)
5985 {
5986  if (category)
5987  return get_kvp_string_path (acc, {head, category});
5988  else
5989  return get_kvp_string_path (acc, {head});
5990 }
5991 
5992 
5993 void
5994 gnc_account_delete_map_entry (Account *acc, char *head, char *category,
5995  char *match_string, gboolean empty)
5996 {
5997  if (acc != NULL)
5998  {
5999  std::vector<std::string> path {head};
6000  if (category)
6001  path.emplace_back (category);
6002  if (match_string)
6003  path.emplace_back (match_string);
6004 
6005  if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
6006  {
6007  xaccAccountBeginEdit (acc);
6008  if (empty)
6009  qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), path);
6010  else
6011  qof_instance_slot_path_delete (QOF_INSTANCE(acc), path);
6012  PINFO("Account is '%s', head is '%s', category is '%s', match_string is'%s'",
6013  xaccAccountGetName (acc), head, category, match_string);
6014  qof_instance_set_dirty (QOF_INSTANCE(acc));
6015  xaccAccountCommitEdit (acc);
6016  }
6017  }
6018 }
6019 
6020 void
6022 {
6023  if (acc != NULL)
6024  {
6025  auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES);
6026  if (!slots.size()) return;
6027  for (auto const & entry : slots)
6028  {
6029  qof_instance_slot_path_delete (QOF_INSTANCE (acc), {entry.first});
6030  }
6031  }
6032 }
6033 
6034 /* ================================================================ */
6035 /* QofObject function implementation and registration */
6036 
6037 static void
6038 gnc_account_book_end(QofBook* book)
6039 {
6040  Account *root_account = gnc_book_get_root_account(book);
6041  if (!root_account)
6042  return;
6043  xaccAccountBeginEdit(root_account);
6044  xaccAccountDestroy(root_account);
6045 }
6046 
6047 #ifdef _MSC_VER
6048 /* MSVC compiler doesn't have C99 "designated initializers"
6049  * so we wrap them in a macro that is empty on MSVC. */
6050 # define DI(x) /* */
6051 #else
6052 # define DI(x) x
6053 #endif
6054 static QofObject account_object_def =
6055 {
6056  DI(.interface_version = ) QOF_OBJECT_VERSION,
6057  DI(.e_type = ) GNC_ID_ACCOUNT,
6058  DI(.type_label = ) "Account",
6059  DI(.create = ) (void*(*)(QofBook*)) xaccMallocAccount,
6060  DI(.book_begin = ) NULL,
6061  DI(.book_end = ) gnc_account_book_end,
6062  DI(.is_dirty = ) qof_collection_is_dirty,
6063  DI(.mark_clean = ) qof_collection_mark_clean,
6064  DI(.foreach = ) qof_collection_foreach,
6065  DI(.printable = ) (const char * (*)(gpointer)) xaccAccountGetName,
6066  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
6067 };
6068 
6069 gboolean xaccAccountRegister (void)
6070 {
6071  static QofParam params[] =
6072  {
6073  {
6074  ACCOUNT_NAME_, QOF_TYPE_STRING,
6077  },
6078  {
6079  ACCOUNT_CODE_, QOF_TYPE_STRING,
6082  },
6083  {
6084  ACCOUNT_DESCRIPTION_, QOF_TYPE_STRING,
6087  },
6088  {
6089  ACCOUNT_COLOR_, QOF_TYPE_STRING,
6092  },
6093  {
6094  ACCOUNT_FILTER_, QOF_TYPE_STRING,
6097  },
6098  {
6099  ACCOUNT_SORT_ORDER_, QOF_TYPE_STRING,
6102  },
6103  {
6104  ACCOUNT_SORT_REVERSED_, QOF_TYPE_BOOLEAN,
6107  },
6108  {
6109  ACCOUNT_NOTES_, QOF_TYPE_STRING,
6112  },
6113  {
6114  ACCOUNT_PRESENT_, QOF_TYPE_NUMERIC,
6115  (QofAccessFunc) xaccAccountGetPresentBalance, NULL
6116  },
6117  {
6118  ACCOUNT_BALANCE_, QOF_TYPE_NUMERIC,
6120  },
6121  {
6122  ACCOUNT_CLEARED_, QOF_TYPE_NUMERIC,
6124  },
6125  {
6126  ACCOUNT_RECONCILED_, QOF_TYPE_NUMERIC,
6128  },
6129  {
6130  ACCOUNT_TYPE_, QOF_TYPE_STRING,
6131  (QofAccessFunc) qofAccountGetTypeString,
6132  (QofSetterFunc) qofAccountSetType
6133  },
6134  {
6135  ACCOUNT_FUTURE_MINIMUM_, QOF_TYPE_NUMERIC,
6136  (QofAccessFunc) xaccAccountGetProjectedMinimumBalance, NULL
6137  },
6138  {
6139  ACCOUNT_TAX_RELATED, QOF_TYPE_BOOLEAN,
6142  },
6143  {
6144  ACCOUNT_OPENING_BALANCE_, QOF_TYPE_BOOLEAN,
6147  },
6148  {
6149  ACCOUNT_SCU, QOF_TYPE_INT32,
6152  },
6153  {
6154  ACCOUNT_NSCU, QOF_TYPE_BOOLEAN,
6157  },
6158  {
6159  ACCOUNT_PARENT, GNC_ID_ACCOUNT,
6161  (QofSetterFunc) qofAccountSetParent
6162  },
6163  {
6164  QOF_PARAM_BOOK, QOF_ID_BOOK,
6166  },
6167  {
6168  QOF_PARAM_GUID, QOF_TYPE_GUID,
6170  },
6171  { NULL },
6172  };
6173 
6174  qof_class_register (GNC_ID_ACCOUNT, (QofSortFunc) qof_xaccAccountOrder, params);
6175 
6176  return qof_object_register (&account_object_def);
6177 }
6178 
6179 /* ======================= UNIT TESTING ACCESS =======================
6180  * The following functions are for unit testing use only.
6181  */
6182 static AccountPrivate*
6183 utest_account_get_private (Account *acc)
6184 {
6185  return GET_PRIVATE (acc);
6186 }
6187 
6189 _utest_account_fill_functions(void)
6190 {
6191  AccountTestFunctions* func = g_new(AccountTestFunctions, 1);
6192 
6193  func->get_private = utest_account_get_private;
6194  func->coll_get_root_account = gnc_coll_get_root_account;
6195  func->xaccFreeAccountChildren = xaccFreeAccountChildren;
6196  func->xaccFreeAccount = xaccFreeAccount;
6197  func->qofAccountSetParent = qofAccountSetParent;
6198  func->gnc_account_lookup_by_full_name_helper =
6199  gnc_account_lookup_by_full_name_helper;
6200 
6201  return func;
6202 }
6203 /* ======================= 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:5383
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:5326
gboolean xaccAccountGetAutoInterest(const Account *acc)
Get the "auto interest" flag for an account.
Definition: Account.cpp:4261
holds an account guid and its corresponding integer probability the integer probability is some facto...
Definition: Account.cpp:5519
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4858
GNCAccountType xaccAccountTypeGetFundamental(GNCAccountType t)
Convenience function to return the fundamental type asset/liability/income/expense/equity given an ac...
Definition: Account.cpp:4581
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:5984
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:4453
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:4133
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:4637
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:5994
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:4677
total_count and the token_count for a given account let us calculate the probability of a given accou...
Definition: Account.cpp:5510
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:4089
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:4729
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:4558
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:4333
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:4171
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:4870
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:5772
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:4753
intermediate values used to calculate the bayes probability of a given account where p(AB) = (a*b)/[a...
Definition: Account.cpp:5495
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:4288
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:5098
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:4567
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:4404
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:5835
void xaccAccountSetPlaceholder(Account *acc, gboolean val)
Set the "placeholder" flag for an account.
Definition: Account.cpp:4205
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:4540
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:5249
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:5113
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:5276
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:4965
#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:5238
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:4237
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:6021
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:5004
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:4844
const char * xaccAccountGetTaxUSPayerNameSource(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:4114
void xaccSplitsBeginStagedTransactionTraversals(GList *splits)
xaccSplitsBeginStagedTransactionTraversals() resets the traversal marker for each transaction which i...
Definition: Account.cpp:5222
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:5740
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:3987
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:5946
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:5957
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:4778
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:4095
gboolean xaccAccountIsAPARType(GNCAccountType t)
Convenience function to check if the account is a valid business account type (meaning an Accounts Pa...
Definition: Account.cpp:4613
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:4370
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:4227
void xaccAccountSetReconcilePostponeBalance(Account *acc, gnc_numeric balance)
DOCUMENT ME!
Definition: Account.cpp:4824
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:4083
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:5126
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:4652
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:4993
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:4276
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:5402
GLib helper routines.
Generic api to store and retrieve preferences.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
gboolean gnc_account_insert_split(Account *acc, Split *s)
Insert the given split from an account.
Definition: Account.cpp: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:4267
void xaccAccountSetTaxUSCode(Account *acc, const char *code)
DOCUMENT ME!
Definition: Account.cpp:4104
GNCPlaceholderType
DOCUMENT ME!
Definition: Account.h:1181
gboolean xaccAccountGetIsOpeningBalance(const Account *acc)
Get the "opening-balance" flag for an account.
Definition: Account.cpp:4211
guint32 xaccParentAccountTypesCompatibleWith(GNCAccountType type)
Return the bitmask of parent account types compatible with a given type.
Definition: Account.cpp:4493
gboolean xaccAccountGetReconcileChildrenStatus(const Account *acc)
DOCUMENT ME!
Definition: Account.cpp:5041
gboolean xaccAccountGetReconcileLastInterval(const Account *acc, int *months, int *days)
DOCUMENT ME!
Definition: Account.cpp:4695
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:4977
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:4183
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:4282
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:4310
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:4199
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
void xaccAccountSetSortReversed(Account *acc, gboolean sortreversed)
Set the account&#39;s Sort Order direction.
Definition: Account.cpp:2577
bank account type – don&#39;t use this for now, see NUM_ACCOUNT_TYPES
Definition: Account.h:172
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Account * xaccAccountGainsAccount(Account *acc, gnc_commodity *curr)
Retrieve the gains account used by this account for the indicated currency, creating and recording a ...
Definition: Account.cpp:4925
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
Retrieve the &#39;unique&#39; name for the specified commodity.
Account * gnc_account_nth_child(const Account *parent, gint num)
Return the n&#39;th child account of the specified parent account.
Definition: Account.cpp:2948
Account * xaccMallocAccount(QofBook *book)
Constructor.
Definition: Account.cpp:1209
gint gnc_account_child_index(const Account *parent, const Account *child)
Return the index of the specified child within the list of the parent&#39;s children. ...
Definition: Account.cpp:2940
QofCollection * qof_book