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> *
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. *
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. *
17
* You should have received a copy of the GNU General Public License*
18
* along with this program; if not, contact: *
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 *
24
\********************************************************************/
29
#include <glib/gi18n.h>
35
#include "Transaction.h"
36
#include "TransactionP.h"
37
#include "gnc-event.h"
38
#include "gnc-glib-utils.h"
40
#include "gnc-lot-p.h"
41
#include "gnc-pricedb.h"
43
#define GNC_ID_ROOT_ACCOUNT "RootAccount"
45
static QofLogModule log_module = GNC_MOD_ACCOUNT;
47
/* The Canonical Account Separator. Pre-Initialized. */
48
static gchar account_separator[8] = ".";
49
gunichar account_uc_separator = ':';
70
PROP_START_CLEARED_BALANCE,
71
PROP_START_RECONCILED_BALANCE,
73
PROP_END_CLEARED_BALANCE,
74
PROP_END_RECONCILED_BALANCE,
83
typedef struct AccountPrivate
85
/* The accountName is an arbitrary string assigned by the user.
86
* It is intended to a short, 5 to 30 character long string that
87
* is displayed by the GUI as the account mnemonic.
91
/* The accountCode is an arbitrary string assigned by the user.
92
* It is intended to be reporting code that is a synonym for the
93
* accountName. Typically, it will be a numeric value that follows
94
* the numbering assignments commonly used by accountants, such
95
* as 100, 200 or 600 for top-level accounts, and 101, 102.. etc.
96
* for detail accounts.
100
/* The description is an arbitrary string assigned by the user.
101
* It is intended to be a longer, 1-5 sentence description of what
102
* this account is all about.
106
/* The type field is the account type, picked from the enumerated
107
* list that includes ACCT_TYPE_BANK, ACCT_TYPE_STOCK,
108
* ACCT_TYPE_CREDIT, ACCT_TYPE_INCOME, etc. Its intended use is to
109
* be a hint to the GUI as to how to display and format the
115
* The commodity field denotes the kind of 'stuff' stored
116
* in this account. The 'amount' field of a split indicates
117
* how much of the 'stuff' there is.
119
gnc_commodity * commodity;
121
gboolean non_standard_scu;
123
/* The parent and children pointers are used to implement an account
124
* hierarchy, of accounts that have sub-accounts ("detail accounts").
126
Account *parent; /* back-pointer to parent */
127
GList *children; /* list of sub-accounts */
129
/* protected data - should only be set by backends */
130
gnc_numeric starting_balance;
131
gnc_numeric starting_cleared_balance;
132
gnc_numeric starting_reconciled_balance;
134
/* cached parameters */
136
gnc_numeric cleared_balance;
137
gnc_numeric reconciled_balance;
139
gboolean balance_dirty; /* balances in splits incorrect */
141
GList *splits; /* list of split pointers */
142
gboolean sort_dirty; /* sort order of splits is bad */
144
LotList *lots; /* list of lot pointers */
145
GNCPolicy *policy; /* Cached pointer to policy method */
147
/* The "mark" flag can be used by the user to mark this account
148
* in any way desired. Handy for specialty traversals of the
153
#define GET_PRIVATE(o) \
154
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_ACCOUNT, AccountPrivate))
156
/********************************************************************\
157
* Because I can't use C++ for this project, doesn't mean that I *
158
* can't pretend to! These functions perform actions on the *
159
* account data structure, in order to encapsulate the knowledge *
160
* of the internals of the Account in one file. *
161
\********************************************************************/
163
static void xaccAccountBringUpToDate (Account *acc);
166
/********************************************************************\
167
* gnc_get_account_separator *
168
* returns the current account separator character *
171
* Returns: account separator character *
172
\*******************************************************************/
174
gnc_get_account_separator_string (void)
176
return account_separator;
180
gnc_get_account_separator (void)
182
return account_uc_separator;
186
gnc_set_account_separator (const gchar *separator)
191
uc = g_utf8_get_char_validated(separator, -1);
192
if ((uc == (gunichar)-2) || (uc == (gunichar)-1) || g_unichar_isalnum(uc)) {
193
account_uc_separator = ':';
194
strcpy(account_separator, ":");
198
account_uc_separator = uc;
199
count = g_unichar_to_utf8(uc, account_separator);
200
account_separator[count] = '\0';
203
/********************************************************************\
204
\********************************************************************/
206
G_INLINE_FUNC void mark_account (Account *acc);
208
mark_account (Account *acc)
210
qof_instance_set_dirty(&acc->inst);
213
/********************************************************************\
214
\********************************************************************/
216
/* GObject Initialization */
217
G_DEFINE_TYPE(Account, gnc_account, QOF_TYPE_INSTANCE)
220
gnc_account_init(Account* acc)
222
AccountPrivate *priv;
224
priv = GET_PRIVATE(acc);
226
priv->children = NULL;
228
priv->accountName = CACHE_INSERT("");
229
priv->accountCode = CACHE_INSERT("");
230
priv->description = CACHE_INSERT("");
232
priv->type = ACCT_TYPE_NONE;
236
priv->policy = xaccGetFIFOPolicy();
239
priv->commodity = NULL;
240
priv->commodity_scu = 0;
241
priv->non_standard_scu = FALSE;
243
priv->balance = gnc_numeric_zero();
244
priv->cleared_balance = gnc_numeric_zero();
245
priv->reconciled_balance = gnc_numeric_zero();
246
priv->starting_balance = gnc_numeric_zero();
247
priv->starting_cleared_balance = gnc_numeric_zero();
248
priv->starting_reconciled_balance = gnc_numeric_zero();
249
priv->balance_dirty = FALSE;
252
priv->sort_dirty = FALSE;
256
gnc_account_dispose (GObject *acctp)
258
G_OBJECT_CLASS(gnc_account_parent_class)->dispose(acctp);
262
gnc_account_finalize(GObject* acctp)
264
G_OBJECT_CLASS(gnc_account_parent_class)->finalize(acctp);
268
gnc_account_get_property (GObject *object,
274
AccountPrivate *priv;
276
g_return_if_fail(GNC_IS_ACCOUNT(object));
278
account = GNC_ACCOUNT(object);
279
priv = GET_PRIVATE(account);
282
g_value_set_string(value, priv->accountName);
285
g_value_take_string(value, xaccAccountGetFullName(account));
288
g_value_set_string(value, priv->accountCode);
290
case PROP_DESCRIPTION:
291
g_value_set_string(value, priv->description);
294
g_value_set_string(value, xaccAccountGetNotes(account));
297
// NEED TO BE CONVERTED TO A G_TYPE_ENUM
298
g_value_set_int(value, priv->type);
301
g_value_set_object(value, priv->commodity);
303
case PROP_COMMODITY_SCU:
304
g_value_set_int(value, priv->commodity_scu);
306
case PROP_NON_STD_SCU:
307
g_value_set_boolean(value, priv->non_standard_scu);
309
case PROP_SORT_DIRTY:
310
g_value_set_boolean(value, priv->sort_dirty);
312
case PROP_BALANCE_DIRTY:
313
g_value_set_boolean(value, priv->balance_dirty);
315
case PROP_START_BALANCE:
316
g_value_set_boxed(value, &priv->starting_balance);
318
case PROP_START_CLEARED_BALANCE:
319
g_value_set_boxed(value, &priv->starting_cleared_balance);
321
case PROP_START_RECONCILED_BALANCE:
322
g_value_set_boxed(value, &priv->starting_reconciled_balance);
324
case PROP_END_BALANCE:
325
g_value_set_boxed(value, &priv->balance);
327
case PROP_END_CLEARED_BALANCE:
328
g_value_set_boxed(value, &priv->cleared_balance);
330
case PROP_END_RECONCILED_BALANCE:
331
g_value_set_boxed(value, &priv->reconciled_balance);
334
/* MAKE THIS A BOXED VALUE */
335
g_value_set_pointer(value, priv->policy);
338
g_value_set_int(value, priv->mark);
340
case PROP_TAX_RELATED:
341
g_value_set_boolean(value, xaccAccountGetTaxRelated(account));
344
g_value_set_string(value, xaccAccountGetTaxUSCode(account));
346
case PROP_TAX_SOURCE:
347
g_value_set_string(value,
348
xaccAccountGetTaxUSPayerNameSource(account));
351
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
357
gnc_account_set_property (GObject *object,
365
g_return_if_fail(GNC_IS_ACCOUNT(object));
367
account = GNC_ACCOUNT(object);
371
xaccAccountSetName(account, g_value_get_string(value));
374
xaccAccountSetCode(account, g_value_get_string(value));
376
case PROP_DESCRIPTION:
377
xaccAccountSetDescription(account, g_value_get_string(value));
380
xaccAccountSetNotes(account, g_value_get_string(value));
383
// NEED TO BE CONVERTED TO A G_TYPE_ENUM
384
xaccAccountSetType(account, g_value_get_int(value));
387
xaccAccountSetCommodity(account, g_value_get_object(value));
389
case PROP_COMMODITY_SCU:
390
xaccAccountSetCommoditySCU(account, g_value_get_int(value));
392
case PROP_SORT_DIRTY:
393
gnc_account_set_sort_dirty(account);
395
case PROP_BALANCE_DIRTY:
396
gnc_account_set_balance_dirty(account);
398
case PROP_START_BALANCE:
399
number = g_value_get_boxed(value);
400
gnc_account_set_start_balance(account, *number);
402
case PROP_START_CLEARED_BALANCE:
403
number = g_value_get_boxed(value);
404
gnc_account_set_start_cleared_balance(account, *number);
406
case PROP_START_RECONCILED_BALANCE:
407
number = g_value_get_boxed(value);
408
gnc_account_set_start_reconciled_balance(account, *number);
411
gnc_account_set_policy(account, g_value_get_pointer(value));
414
xaccAccountSetMark(account, g_value_get_int(value));
416
case PROP_TAX_RELATED:
417
xaccAccountSetTaxRelated(account, g_value_get_boolean(value));
420
xaccAccountSetTaxUSCode(account, g_value_get_string(value));
422
case PROP_TAX_SOURCE:
423
xaccAccountSetTaxUSPayerNameSource(account,
424
g_value_get_string(value));
426
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
434
gnc_account_class_init (AccountClass *klass)
436
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
438
gobject_class->dispose = gnc_account_dispose;
439
gobject_class->finalize = gnc_account_finalize;
440
gobject_class->set_property = gnc_account_set_property;
441
gobject_class->get_property = gnc_account_get_property;
443
g_type_class_add_private(klass, sizeof(AccountPrivate));
445
g_object_class_install_property
448
g_param_spec_string ("name",
450
"The accountName is an arbitrary string "
451
"assigned by the user. It is intended to "
452
"a short, 5 to 30 character long string "
453
"that is displayed by the GUI as the "
454
"account mnemonic. Account names may be "
455
"repeasted. but no two accounts that share "
456
"a parent may have the same name.",
460
g_object_class_install_property
463
g_param_spec_string ("fullname",
465
"The name of the account concatenated with "
466
"all its parent account names to indicate "
471
g_object_class_install_property
474
g_param_spec_string ("code",
476
"The account code is an arbitrary string "
477
"assigned by the user. It is intended to "
478
"be reporting code that is a synonym for "
483
g_object_class_install_property
486
g_param_spec_string ("description",
487
"Account Description",
488
"The account description is an arbitrary "
489
"string assigned by the user. It is intended "
490
"to be a longer, 1-5 sentence description of "
491
"what this account is all about.",
495
g_object_class_install_property
498
g_param_spec_string ("notes",
500
"The account notes is an arbitrary provided "
501
"for the user to attach any orther text that "
502
"they would like to associate with the account.",
506
g_object_class_install_property
509
g_param_spec_int ("type",
511
"The account type, picked from the enumerated list "
512
"that includes ACCT_TYPE_BANK, ACCT_TYPE_STOCK, "
513
"ACCT_TYPE_CREDIT, ACCT_TYPE_INCOME, etc.",
515
NUM_ACCOUNT_TYPES - 1,
519
g_object_class_install_property
522
g_param_spec_object ("commodity",
524
"The commodity field denotes the kind of "
525
"'stuff' stored in this account, whether "
526
"it is USD, gold, stock, etc.",
530
g_object_class_install_property
533
g_param_spec_int ("commodity-scu",
535
"The smallest fraction of the commodity that is "
536
"tracked. This number is used as the denominator "
537
"value in 1/x, so a value of 100 says that the "
538
"commodity can be divided into hundreths. E.G."
539
"1 USD can be divided into 100 cents.",
545
g_object_class_install_property
548
g_param_spec_boolean ("non-std-scu",
550
"TRUE id the account SCU doesn't match "
551
"the commodity SCU. This indicates a case "
552
"where the two were accidentally set to "
553
"mismatched values in older versions of "
558
g_object_class_install_property
561
g_param_spec_boolean("sort-dirty",
563
"TRUE if the splits in the account needs to be "
564
"resorted. This flag is set by the accounts "
565
"code for certain internal modifications, or "
566
"when external code calls the engine to say a "
567
"split has been modified in a way that may "
568
"affect the sort order of the account. Note: "
569
"This value can only be set to TRUE.",
573
g_object_class_install_property
576
g_param_spec_boolean("balance-dirty",
578
"TRUE if the running balances in the account "
579
"needs to be recalculated. This flag is set "
580
"by the accounts code for certain internal "
581
"modifications, or when external code calls "
582
"the engine to say a split has been modified. "
583
"Note: This value can only be set to TRUE.",
587
g_object_class_install_property
590
g_param_spec_boxed("start-balance",
592
"The starting balance for the account. This "
593
"parameter is intended for use with backends that "
594
"do not return the complete list of splits for an "
595
"account, but rather return a partial list. In "
596
"such a case, the backend will typically return "
597
"all of the splits after some certain date, and "
598
"the 'starting balance' will represent the "
599
"summation of the splits up to that date.",
603
g_object_class_install_property
605
PROP_START_CLEARED_BALANCE,
606
g_param_spec_boxed("start-cleared-balance",
607
"Starting Cleared Balance",
608
"The starting cleared balance for the account. "
609
"This parameter is intended for use with backends "
610
"that do not return the complete list of splits "
611
"for an account, but rather return a partial "
612
"list. In such a case, the backend will "
613
"typically return all of the splits after "
614
"some certain date, and the 'starting cleared "
615
"balance' will represent the summation of the "
616
"splits up to that date.",
620
g_object_class_install_property
622
PROP_START_RECONCILED_BALANCE,
623
g_param_spec_boxed("start-reconciled-balance",
624
"Starting Reconciled Balance",
625
"The starting reconciled balance for the "
626
"account. This parameter is intended for use "
627
"with backends that do not return the complete "
628
"list of splits for an account, but rather return "
629
"a partial list. In such a case, the backend "
630
"will typically return all of the splits after "
631
"some certain date, and the 'starting recontiled "
632
"balance' will represent the summation of the "
633
"splits up to that date.",
637
g_object_class_install_property
640
g_param_spec_boxed("end-balance",
641
"Ending Account Balance",
642
"This is the current ending balance for the "
643
"account. It is computed from the sum of the "
644
"starting balance and all splits in the account.",
648
g_object_class_install_property
650
PROP_END_CLEARED_BALANCE,
651
g_param_spec_boxed("end-cleared-balance",
652
"Ending Account Cleared Balance",
653
"This is the current ending cleared balance for "
654
"the account. It is computed from the sum of the "
655
"starting balance and all cleared splits in the "
660
g_object_class_install_property
662
PROP_END_RECONCILED_BALANCE,
663
g_param_spec_boxed("end-reconciled-balance",
664
"Ending Account Reconciled Balance",
665
"This is the current ending reconciled balance "
666
"for the account. It is computed from the sum of "
667
"the starting balance and all reconciled splits "
672
g_object_class_install_property
675
g_param_spec_pointer ("policy",
677
"The account lots policy.",
680
g_object_class_install_property
683
g_param_spec_int ("acct-mark",
691
g_object_class_install_property
694
g_param_spec_boolean ("tax-related",
696
"Whether the account maps to an entry on an "
697
"income tax document.",
701
g_object_class_install_property
704
g_param_spec_string ("tax-code",
706
"This is the code for mapping an account to a "
707
"specific entry on a taxable document. In the "
708
"United States it is used to transfer totals "
709
"into tax preparation software.",
713
g_object_class_install_property
716
g_param_spec_string ("tax-source",
718
"This is an unknown tax related field.",
724
xaccInitAccount (Account * acc, QofBook *book)
726
ENTER ("book=%p\n", book);
727
qof_instance_init_data (&acc->inst, GNC_ID_ACCOUNT, book);
729
LEAVE ("account=%p\n", acc);
732
/********************************************************************\
733
\********************************************************************/
736
gnc_account_get_book(const Account *account)
738
return qof_instance_get_book(QOF_INSTANCE(account));
741
/********************************************************************\
742
\********************************************************************/
745
gnc_coll_get_root_account (QofCollection *col)
747
if (!col) return NULL;
748
return qof_collection_get_data (col);
752
gnc_coll_set_root_account (QofCollection *col, Account *root)
754
AccountPrivate *rpriv;
758
old_root = gnc_coll_get_root_account (col);
759
if (old_root == root) return;
761
/* If the new root is already linked into the tree somewhere, then
762
* remove it from its current position before adding it at the
764
rpriv = GET_PRIVATE(root);
766
xaccAccountBeginEdit(root);
767
gnc_account_remove_child(rpriv->parent, root);
768
xaccAccountCommitEdit(root);
771
qof_collection_set_data (col, root);
774
xaccAccountBeginEdit (old_root);
775
xaccAccountDestroy (old_root);
780
gnc_book_get_root_account (QofBook *book)
785
if (!book) return NULL;
786
col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
787
root = gnc_coll_get_root_account (col);
789
root = gnc_account_create_root(book);
794
gnc_book_set_root_account (QofBook *book, Account *root)
799
if (root && gnc_account_get_book(root) != book)
801
PERR ("cannot mix and match books freely!");
805
col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
806
gnc_coll_set_root_account (col, root);
809
/********************************************************************\
810
\********************************************************************/
813
xaccMallocAccount (QofBook *book)
817
g_return_val_if_fail (book, NULL);
819
acc = g_object_new (GNC_TYPE_ACCOUNT, NULL);
820
xaccInitAccount (acc, book);
821
qof_event_gen (&acc->inst, QOF_EVENT_CREATE, NULL);
827
gnc_account_create_root (QofBook *book)
830
AccountPrivate *rpriv;
832
root = xaccMallocAccount(book);
833
rpriv = GET_PRIVATE(root);
834
xaccAccountBeginEdit(root);
835
rpriv->type = ACCT_TYPE_ROOT;
836
CACHE_REPLACE(rpriv->accountName, "Root Account");
837
xaccAccountCommitEdit(root);
838
gnc_book_set_root_account(book, root);
843
xaccCloneAccountCommon(const Account *from, QofBook *book)
846
AccountPrivate *from_priv, *priv;
848
g_return_val_if_fail(GNC_IS_ACCOUNT(from), NULL);
849
g_return_val_if_fail(QOF_IS_BOOK(book), NULL);
852
ret = g_object_new (GNC_TYPE_ACCOUNT, NULL);
853
g_return_val_if_fail (ret, NULL);
855
from_priv = GET_PRIVATE(from);
856
priv = GET_PRIVATE(ret);
857
xaccInitAccount (ret, book);
859
/* Do not Begin/CommitEdit() here; give the caller
860
* a chance to fix things up, and let them do it.
861
* Also let caller issue the generate_event (EVENT_CREATE) */
862
priv->type = from_priv->type;
864
priv->accountName = CACHE_INSERT(from_priv->accountName);
865
priv->accountCode = CACHE_INSERT(from_priv->accountCode);
866
priv->description = CACHE_INSERT(from_priv->description);
868
kvp_frame_delete(ret->inst.kvp_data);
869
ret->inst.kvp_data = kvp_frame_copy(from->inst.kvp_data);
871
/* The new book should contain a commodity that matches
872
* the one in the old book. Find it, use it. */
873
priv->commodity = gnc_commodity_obtain_twin(from_priv->commodity, book);
875
priv->commodity_scu = from_priv->commodity_scu;
876
priv->non_standard_scu = from_priv->non_standard_scu;
883
xaccCloneAccount (const Account *from, QofBook *book)
885
Account *ret = xaccCloneAccountCommon(from, book);
886
qof_instance_gemini (&ret->inst, (QofInstance *) &from->inst);
888
(Account*) qof_instance_lookup_twin (QOF_INSTANCE(from), book));
893
xaccCloneAccountSimple (const Account *from, QofBook *book)
895
Account *ret = xaccCloneAccountCommon(from, book);
896
qof_instance_set_dirty(&ret->inst);
900
/********************************************************************\
901
\********************************************************************/
904
xaccFreeOneChildAccount (Account *acc, gpointer dummy)
906
/* FIXME: this code is kind of hacky. actually, all this code
907
* seems to assume that the account edit levels are all 1. */
908
if (qof_instance_get_editlevel(acc) == 0)
909
xaccAccountBeginEdit(acc);
910
xaccAccountDestroy(acc);
914
xaccFreeAccountChildren (Account *acc)
916
AccountPrivate *priv;
919
/* Copy the list since it will be modified */
920
priv = GET_PRIVATE(acc);
921
children = g_list_copy(priv->children);
922
g_list_foreach(children, (GFunc)xaccFreeOneChildAccount, NULL);
923
g_list_free(children);
925
/* The foreach should have removed all the children already. */
927
g_list_free(priv->children);
928
priv->children = NULL;
931
/* The xaccFreeAccount() routine releases memory associated with the
932
* account. It should never be called directly from user code;
933
* instead, the xaccAccountDestroy() routine should be used (because
934
* xaccAccountDestroy() has the correct commit semantics). */
936
xaccFreeAccount (Account *acc)
938
AccountPrivate *priv;
941
g_return_if_fail(GNC_IS_ACCOUNT(acc));
943
priv = GET_PRIVATE(acc);
944
qof_event_gen (&acc->inst, QOF_EVENT_DESTROY, NULL);
948
PERR (" instead of calling xaccFreeAccount(), please call \n"
949
" xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
951
/* First, recursively free children */
952
xaccFreeAccountChildren(acc);
955
/* remove lots -- although these should be gone by now. */
958
PERR (" instead of calling xaccFreeAccount(), please call \n"
959
" xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
961
for (lp=priv->lots; lp; lp=lp->next)
963
GNCLot *lot = lp->data;
964
gnc_lot_destroy (lot);
966
g_list_free (priv->lots);
970
/* Next, clean up the splits */
971
/* NB there shouldn't be any splits by now ... they should
972
* have been all been freed by CommitEdit(). We can remove this
973
* check once we know the warning isn't occurring any more. */
977
PERR (" instead of calling xaccFreeAccount(), please call \n"
978
" xaccAccountBeginEdit(); xaccAccountDestroy(); \n");
980
qof_instance_reset_editlevel(acc);
982
slist = g_list_copy(priv->splits);
983
for (lp = slist; lp; lp = lp->next) {
984
Split *s = (Split *) lp->data;
985
g_assert(xaccSplitGetAccount(s) == acc);
986
xaccSplitDestroy (s);
989
g_assert(priv->splits == NULL);
992
CACHE_REPLACE(priv->accountName, NULL);
993
CACHE_REPLACE(priv->accountCode, NULL);
994
CACHE_REPLACE(priv->description, NULL);
996
/* zero out values, just in case stray
997
* pointers are pointing here. */
1000
priv->children = NULL;
1002
priv->balance = gnc_numeric_zero();
1003
priv->cleared_balance = gnc_numeric_zero();
1004
priv->reconciled_balance = gnc_numeric_zero();
1006
priv->type = ACCT_TYPE_NONE;
1007
priv->commodity = NULL;
1009
priv->balance_dirty = FALSE;
1010
priv->sort_dirty = FALSE;
1012
/* qof_instance_release (&acc->inst); */
1013
g_object_unref(acc);
1016
/********************************************************************\
1017
* transactional routines
1018
\********************************************************************/
1021
xaccAccountBeginEdit (Account *acc)
1023
g_return_if_fail(acc);
1024
qof_begin_edit(&acc->inst);
1027
static void on_done(QofInstance *inst)
1029
/* old event style */
1030
qof_event_gen (inst, QOF_EVENT_MODIFY, NULL);
1033
static void on_err (QofInstance *inst, QofBackendError errcode)
1035
PERR("commit error: %d", errcode);
1038
static void acc_free (QofInstance *inst)
1040
AccountPrivate *priv;
1041
Account *acc = (Account *) inst;
1043
priv = GET_PRIVATE(acc);
1045
gnc_account_remove_child(priv->parent, acc);
1046
xaccFreeAccount(acc);
1050
destroy_pending_splits_for_account(QofInstance *ent, gpointer acc)
1052
Transaction *trans = (Transaction *) ent;
1055
if (xaccTransIsOpen(trans))
1056
while ((split = xaccTransFindSplitByAccount(trans, acc)))
1057
xaccSplitDestroy(split);
1061
xaccAccountCommitEdit (Account *acc)
1063
AccountPrivate *priv;
1066
g_return_if_fail(acc);
1067
if (!qof_commit_edit(&acc->inst)) return;
1069
/* If marked for deletion, get rid of subaccounts first,
1070
* and then the splits ... */
1071
priv = GET_PRIVATE(acc);
1072
if (qof_instance_get_destroying(acc))
1077
qof_instance_increase_editlevel(acc);
1079
/* First, recursively free children */
1080
xaccFreeAccountChildren(acc);
1082
PINFO ("freeing splits for account %p (%s)",
1083
acc, priv->accountName ? priv->accountName : "(null)");
1085
slist = g_list_copy(priv->splits);
1086
for (lp = slist; lp; lp = lp->next)
1088
Split *s = lp->data;
1089
xaccSplitDestroy (s);
1092
/* It turns out there's a case where this assertion does not hold:
1093
When the user tries to delete an Imbalance account, while also
1094
deleting all the splits in it. The splits will just get
1095
recreated and put right back into the same account!
1097
g_assert(priv->splits == NULL || qof_book_shutting_down(acc->inst.book));
1100
book = qof_instance_get_book(acc);
1101
if (!qof_book_shutting_down(book)) {
1102
col = qof_book_get_collection(book, GNC_ID_TRANS);
1103
qof_collection_foreach(col, destroy_pending_splits_for_account, acc);
1106
/* the lots should be empty by now */
1107
for (lp = priv->lots; lp; lp = lp->next)
1109
GNCLot *lot = lp->data;
1110
gnc_lot_destroy (lot);
1112
g_list_free(priv->lots);
1115
qof_instance_set_dirty(&acc->inst);
1116
qof_instance_decrease_editlevel(acc);
1120
xaccAccountBringUpToDate(acc);
1123
qof_commit_edit_part2(&acc->inst, on_err, on_done, acc_free);
1127
xaccAccountDestroy (Account *acc)
1129
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1131
qof_instance_set_destroying(acc, TRUE);
1133
xaccAccountCommitEdit (acc);
1136
/********************************************************************\
1137
\********************************************************************/
1140
xaccAcctChildrenEqual(const GList *na,
1142
gboolean check_guids)
1144
if ((!na && nb) || (na && !nb))
1146
PWARN ("only one has accounts");
1152
Account *aa = na->data;
1153
Account *ab = nb->data;
1155
if (!xaccAccountEqual(aa, ab, check_guids))
1157
char sa[GUID_ENCODING_LENGTH + 1];
1158
char sb[GUID_ENCODING_LENGTH + 1];
1160
guid_to_string_buff (xaccAccountGetGUID (aa), sa);
1161
guid_to_string_buff (xaccAccountGetGUID (ab), sb);
1163
PWARN ("accounts %s and %s differ", sa, sb);
1174
PWARN ("different numbers of accounts");
1182
xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
1184
AccountPrivate *priv_aa, *priv_ab;
1186
if(!aa && !ab) return TRUE;
1188
g_return_val_if_fail(GNC_IS_ACCOUNT(aa), FALSE);
1189
g_return_val_if_fail(GNC_IS_ACCOUNT(ab), FALSE);
1191
priv_aa = GET_PRIVATE(aa);
1192
priv_ab = GET_PRIVATE(ab);
1193
if (priv_aa->type != priv_ab->type)
1195
PWARN ("types differ: %d vs %d", priv_aa->type, priv_ab->type);
1199
if (safe_strcmp(priv_aa->accountName, priv_ab->accountName) != 0)
1201
PWARN ("names differ: %s vs %s", priv_aa->accountName, priv_ab->accountName);
1205
if (safe_strcmp(priv_aa->accountCode, priv_ab->accountCode) != 0)
1207
PWARN ("codes differ: %s vs %s", priv_aa->accountCode, priv_ab->accountCode);
1211
if (safe_strcmp(priv_aa->description, priv_ab->description) != 0)
1213
PWARN ("descriptions differ: %s vs %s", priv_aa->description, priv_ab->description);
1217
if (!gnc_commodity_equal(priv_aa->commodity, priv_ab->commodity))
1219
PWARN ("commodities differ");
1224
if(qof_instance_guid_compare(aa, ab) != 0)
1226
PWARN ("GUIDs differ");
1231
if (kvp_frame_compare(aa->inst.kvp_data, ab->inst.kvp_data) != 0)
1236
frame_a = kvp_frame_to_string (aa->inst.kvp_data);
1237
frame_b = kvp_frame_to_string (ab->inst.kvp_data);
1239
PWARN ("kvp frames differ:\n%s\n\nvs\n\n%s", frame_a, frame_b);
1247
if (!gnc_numeric_equal(priv_aa->starting_balance, priv_ab->starting_balance))
1252
str_a = gnc_numeric_to_string(priv_aa->starting_balance);
1253
str_b = gnc_numeric_to_string(priv_ab->starting_balance);
1255
PWARN ("starting balances differ: %s vs %s", str_a, str_b);
1263
if (!gnc_numeric_equal(priv_aa->starting_cleared_balance,
1264
priv_ab->starting_cleared_balance))
1269
str_a = gnc_numeric_to_string(priv_aa->starting_cleared_balance);
1270
str_b = gnc_numeric_to_string(priv_ab->starting_cleared_balance);
1272
PWARN ("starting cleared balances differ: %s vs %s", str_a, str_b);
1280
if (!gnc_numeric_equal(priv_aa->starting_reconciled_balance,
1281
priv_ab->starting_reconciled_balance))
1286
str_a = gnc_numeric_to_string(priv_aa->starting_reconciled_balance);
1287
str_b = gnc_numeric_to_string(priv_ab->starting_reconciled_balance);
1289
PWARN ("starting reconciled balances differ: %s vs %s", str_a, str_b);
1297
if (!gnc_numeric_equal(priv_aa->balance, priv_ab->balance))
1302
str_a = gnc_numeric_to_string(priv_aa->balance);
1303
str_b = gnc_numeric_to_string(priv_ab->balance);
1305
PWARN ("balances differ: %s vs %s", str_a, str_b);
1313
if (!gnc_numeric_equal(priv_aa->cleared_balance, priv_ab->cleared_balance))
1318
str_a = gnc_numeric_to_string(priv_aa->cleared_balance);
1319
str_b = gnc_numeric_to_string(priv_ab->cleared_balance);
1321
PWARN ("cleared balances differ: %s vs %s", str_a, str_b);
1329
if (!gnc_numeric_equal(priv_aa->reconciled_balance, priv_ab->reconciled_balance))
1334
str_a = gnc_numeric_to_string(priv_aa->reconciled_balance);
1335
str_b = gnc_numeric_to_string(priv_ab->reconciled_balance);
1337
PWARN ("reconciled balances differ: %s vs %s", str_a, str_b);
1345
/* no parent; always compare downwards. */
1348
GList *la = priv_aa->splits;
1349
GList *lb = priv_ab->splits;
1351
if ((la && !lb) || (!la && lb))
1353
PWARN ("only one has splits");
1359
/* presume that the splits are in the same order */
1362
Split *sa = (Split *) la->data;
1363
Split *sb = (Split *) lb->data;
1365
if (!xaccSplitEqual(sa, sb, check_guids, TRUE, FALSE))
1367
PWARN ("splits differ");
1375
if ((la != NULL) || (lb != NULL))
1377
PWARN ("number of splits differs");
1383
if (!xaccAcctChildrenEqual(priv_aa->children, priv_ab->children, check_guids))
1385
PWARN ("children differ");
1392
/********************************************************************\
1393
\********************************************************************/
1396
gnc_account_get_sort_dirty (Account *acc)
1398
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
1399
return GET_PRIVATE(acc)->sort_dirty;
1403
gnc_account_set_sort_dirty (Account *acc)
1405
AccountPrivate *priv;
1407
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1409
if (qof_instance_get_destroying(acc))
1412
priv = GET_PRIVATE(acc);
1413
priv->sort_dirty = TRUE;
1417
gnc_account_get_balance_dirty (Account *acc)
1419
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
1420
return GET_PRIVATE(acc)->balance_dirty;
1424
gnc_account_set_balance_dirty (Account *acc)
1426
AccountPrivate *priv;
1428
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1430
if (qof_instance_get_destroying(acc))
1433
priv = GET_PRIVATE(acc);
1434
priv->balance_dirty = TRUE;
1437
/********************************************************************\
1438
\********************************************************************/
1441
gnc_account_find_split (Account *acc, Split *s)
1443
AccountPrivate *priv;
1446
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
1447
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
1449
priv = GET_PRIVATE(acc);
1450
node = g_list_find(priv->splits, s);
1451
return node ? TRUE : FALSE;
1455
gnc_account_insert_split (Account *acc, Split *s)
1457
AccountPrivate *priv;
1460
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
1461
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
1463
priv = GET_PRIVATE(acc);
1464
node = g_list_find(priv->splits, s);
1468
if (qof_instance_get_editlevel(acc) == 0) {
1469
priv->splits = g_list_insert_sorted(priv->splits, s,
1470
(GCompareFunc)xaccSplitOrder);
1472
priv->splits = g_list_prepend(priv->splits, s);
1473
priv->sort_dirty = TRUE;
1476
//FIXME: find better event
1477
qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL);
1478
/* Also send an event based on the account */
1479
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_ADDED, s);
1481
priv->balance_dirty = TRUE;
1482
// DRH: Should the below be added? It is present in the delete path.
1483
// xaccAccountRecomputeBalance(acc);
1488
gnc_account_remove_split (Account *acc, Split *s)
1490
AccountPrivate *priv;
1493
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
1494
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
1496
priv = GET_PRIVATE(acc);
1497
node = g_list_find(priv->splits, s);
1501
priv->splits = g_list_delete_link(priv->splits, node);
1502
//FIXME: find better event type
1503
qof_event_gen(&acc->inst, QOF_EVENT_MODIFY, NULL);
1504
// And send the account-based event, too
1505
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_REMOVED, s);
1507
priv->balance_dirty = TRUE;
1508
xaccAccountRecomputeBalance(acc);
1513
xaccAccountSortSplits (Account *acc, gboolean force)
1515
AccountPrivate *priv;
1517
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1519
priv = GET_PRIVATE(acc);
1520
if (!priv->sort_dirty || (!force && qof_instance_get_editlevel(acc) > 0))
1522
priv->splits = g_list_sort(priv->splits, (GCompareFunc)xaccSplitOrder);
1523
priv->sort_dirty = FALSE;
1524
priv->balance_dirty = TRUE;
1528
xaccAccountBringUpToDate(Account *acc)
1532
/* if a re-sort happens here, then everything will update, so the
1533
cost basis and balance calls are no-ops */
1534
xaccAccountSortSplits(acc, FALSE);
1535
xaccAccountRecomputeBalance(acc);
1538
/********************************************************************\
1539
\********************************************************************/
1542
xaccAccountSetGUID (Account *acc, const GUID *guid)
1544
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1545
g_return_if_fail(guid);
1547
/* XXX this looks fishy and weird to me ... */
1548
PINFO("acct=%p", acc);
1549
xaccAccountBeginEdit (acc);
1550
qof_instance_set_guid (&acc->inst, guid);
1551
qof_instance_set_dirty(&acc->inst);
1552
xaccAccountCommitEdit (acc);
1555
/********************************************************************\
1556
\********************************************************************/
1559
xaccAccountLookup (const GUID *guid, QofBook *book)
1562
if (!guid || !book) return NULL;
1563
col = qof_book_get_collection (book, GNC_ID_ACCOUNT);
1564
return (Account *) qof_collection_lookup_entity (col, guid);
1567
/********************************************************************\
1568
\********************************************************************/
1571
xaccAccountGetMark (const Account *acc)
1573
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
1575
return GET_PRIVATE(acc)->mark;
1579
xaccAccountSetMark (Account *acc, short m)
1581
AccountPrivate *priv;
1583
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1585
priv = GET_PRIVATE(acc);
1590
xaccClearMark (Account *acc, short val)
1594
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1596
root = gnc_account_get_root(acc);
1597
xaccClearMarkDown(root ? root : acc, val);
1601
xaccClearMarkDown (Account *acc, short val)
1603
AccountPrivate *priv;
1606
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1608
priv = GET_PRIVATE(acc);
1610
for (node = priv->children; node; node = node->next) {
1611
xaccClearMarkDown(node->data, val);
1615
/********************************************************************\
1616
\********************************************************************/
1619
gnc_account_get_policy (Account *acc)
1621
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
1623
return GET_PRIVATE(acc)->policy;
1627
gnc_account_set_policy (Account *acc, GNCPolicy *policy)
1629
AccountPrivate *priv;
1631
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1633
priv = GET_PRIVATE(acc);
1634
priv->policy = policy ? policy : xaccGetFIFOPolicy();
1637
/********************************************************************\
1638
\********************************************************************/
1641
xaccAccountRemoveLot (Account *acc, GNCLot *lot)
1643
AccountPrivate *priv;
1645
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1646
g_return_if_fail(GNC_IS_LOT(lot));
1648
priv = GET_PRIVATE(acc);
1649
g_return_if_fail(priv->lots);
1651
ENTER ("(acc=%p, lot=%p)", acc, lot);
1652
priv->lots = g_list_remove(priv->lots, lot);
1653
LEAVE ("(acc=%p, lot=%p)", acc, lot);
1657
xaccAccountInsertLot (Account *acc, GNCLot *lot)
1659
AccountPrivate *priv, *opriv;
1660
Account * old_acc = NULL;
1663
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1664
g_return_if_fail(GNC_IS_LOT(lot));
1667
if (lot->account == acc)
1670
ENTER ("(acc=%p, lot=%p)", acc, lot);
1672
/* pull it out of the old account */
1674
old_acc = lot->account;
1675
opriv = GET_PRIVATE(old_acc);
1676
opriv->lots = g_list_remove(opriv->lots, lot);
1679
priv = GET_PRIVATE(acc);
1680
priv->lots = g_list_prepend(priv->lots, lot);
1683
/* Don't move the splits to the new account. The caller will do this
1684
* if appropriate, and doing it here will not work if we are being
1685
* called from gnc_book_close_period since xaccAccountInsertSplit
1686
* will try to balance capital gains and things aren't ready for that. */
1688
LEAVE ("(acc=%p, lot=%p)", acc, lot);
1691
/********************************************************************\
1692
\********************************************************************/
1694
xaccPreSplitMove (Split *split, gpointer dummy)
1696
xaccTransBeginEdit (xaccSplitGetParent (split));
1700
xaccPostSplitMove (Split *split, Account *accto)
1704
xaccSplitSetAccount(split, accto);
1705
xaccSplitSetAmount(split, split->amount);
1706
trans = xaccSplitGetParent (split);
1707
xaccTransCommitEdit (trans);
1711
xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
1713
AccountPrivate *from_priv, *to_priv;
1716
g_return_if_fail(GNC_IS_ACCOUNT(accfrom));
1717
g_return_if_fail(GNC_IS_ACCOUNT(accto));
1720
from_priv = GET_PRIVATE(accfrom);
1721
to_priv = GET_PRIVATE(accto);
1722
if (!from_priv->splits || accfrom == accto)
1725
/* check for book mix-up */
1726
g_return_if_fail (qof_instance_books_equal(accfrom, accto));
1727
ENTER ("(accfrom=%p, accto=%p)", accfrom, accto);
1729
xaccAccountBeginEdit(accfrom);
1730
xaccAccountBeginEdit(accto);
1731
/* Begin editing both accounts and all transactions in accfrom. */
1732
g_list_foreach(from_priv->splits, (GFunc)xaccPreSplitMove, NULL);
1734
/* Concatenate accfrom's lists of splits and lots to accto's lists. */
1735
//to_priv->splits = g_list_concat(to_priv->splits, from_priv->splits);
1736
//to_priv->lots = g_list_concat(to_priv->lots, from_priv->lots);
1738
/* Set appropriate flags. */
1739
//from_priv->balance_dirty = TRUE;
1740
//from_priv->sort_dirty = FALSE;
1741
//to_priv->balance_dirty = TRUE;
1742
//to_priv->sort_dirty = TRUE;
1745
* Change each split's account back pointer to accto.
1746
* Convert each split's amount to accto's commodity.
1747
* Commit to editing each transaction.
1749
g_list_foreach(from_priv->splits, (GFunc)xaccPostSplitMove, (gpointer)accto);
1751
/* Finally empty accfrom. */
1752
g_assert(from_priv->splits == NULL);
1753
g_assert(from_priv->lots == NULL);
1754
xaccAccountCommitEdit(accfrom);
1755
xaccAccountCommitEdit(accto);
1757
LEAVE ("(accfrom=%p, accto=%p)", accfrom, accto);
1761
/********************************************************************\
1762
* xaccAccountRecomputeBalance *
1763
* recomputes the partial balances and the current balance for *
1766
* The way the computation is done depends on whether the partial *
1767
* balances are for a monetary account (bank, cash, etc.) or a *
1768
* certificate account (stock portfolio, mutual fund). For bank *
1769
* accounts, the invariant amount is the dollar amount. For share *
1770
* accounts, the invariant amount is the number of shares. For *
1771
* share accounts, the share price fluctuates, and the current *
1772
* value of such an account is the number of shares times the *
1773
* current share price. *
1775
* Part of the complexity of this computation stems from the fact *
1776
* xacc uses a double-entry system, meaning that one transaction *
1777
* appears in two accounts: one account is debited, and the other *
1778
* is credited. When the transaction represents a sale of shares, *
1779
* or a purchase of shares, some care must be taken to compute *
1780
* balances correctly. For a sale of shares, the stock account must*
1781
* be debited in shares, but the bank account must be credited *
1782
* in dollars. Thus, two different mechanisms must be used to *
1783
* compute balances, depending on account type. *
1785
* Args: account -- the account for which to recompute balances *
1787
\********************************************************************/
1790
xaccAccountRecomputeBalance (Account * acc)
1792
AccountPrivate *priv;
1793
gnc_numeric balance;
1794
gnc_numeric cleared_balance;
1795
gnc_numeric reconciled_balance;
1796
Split *last_split = NULL;
1799
if (NULL == acc) return;
1801
priv = GET_PRIVATE(acc);
1802
if (qof_instance_get_editlevel(acc) > 0) return;
1803
if (!priv->balance_dirty) return;
1804
if (qof_instance_get_destroying(acc)) return;
1805
if (qof_book_shutting_down(qof_instance_get_book(acc))) return;
1807
balance = priv->starting_balance;
1808
cleared_balance = priv->starting_cleared_balance;
1809
reconciled_balance = priv->starting_reconciled_balance;
1811
PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
1812
priv->accountName, balance.num, balance.denom);
1813
for(lp = priv->splits; lp; lp = lp->next)
1815
Split *split = (Split *) lp->data;
1816
gnc_numeric amt = xaccSplitGetAmount (split);
1818
balance = gnc_numeric_add_fixed(balance, amt);
1820
if (NREC != split->reconciled)
1822
cleared_balance = gnc_numeric_add_fixed(cleared_balance, amt);
1825
if (YREC == split->reconciled ||
1826
FREC == split->reconciled)
1828
reconciled_balance =
1829
gnc_numeric_add_fixed(reconciled_balance, amt);
1832
split->balance = balance;
1833
split->cleared_balance = cleared_balance;
1834
split->reconciled_balance = reconciled_balance;
1839
priv->balance = balance;
1840
priv->cleared_balance = cleared_balance;
1841
priv->reconciled_balance = reconciled_balance;
1842
priv->balance_dirty = FALSE;
1845
/********************************************************************\
1846
\********************************************************************/
1848
/* The sort order is used to implicitly define an
1849
* order for report generation */
1851
static int typeorder[NUM_ACCOUNT_TYPES] = {
1852
ACCT_TYPE_BANK, ACCT_TYPE_STOCK, ACCT_TYPE_MUTUAL, ACCT_TYPE_CURRENCY,
1853
ACCT_TYPE_CASH, ACCT_TYPE_ASSET, ACCT_TYPE_RECEIVABLE,
1854
ACCT_TYPE_CREDIT, ACCT_TYPE_LIABILITY, ACCT_TYPE_PAYABLE,
1855
ACCT_TYPE_INCOME, ACCT_TYPE_EXPENSE, ACCT_TYPE_EQUITY };
1857
static int revorder[NUM_ACCOUNT_TYPES] = {
1858
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
1862
xaccAccountOrder (const Account *aa, const Account *ab)
1864
AccountPrivate *priv_aa, *priv_ab;
1866
char *endptr = NULL;
1870
if ( aa && !ab ) return -1;
1871
if ( !aa && ab ) return +1;
1872
if ( !aa && !ab ) return 0;
1874
priv_aa = GET_PRIVATE(aa);
1875
priv_ab = GET_PRIVATE(ab);
1877
/* sort on accountCode strings */
1878
da = priv_aa->accountCode;
1879
db = priv_ab->accountCode;
1881
/* If accountCodes are both base 36 integers do an integer sort */
1882
la = strtoul (da, &endptr, 36);
1883
if((*da != '\0') && (*endptr == '\0')) {
1884
lb = strtoul (db, &endptr, 36);
1885
if((*db != '\0') && (*endptr == '\0')) {
1886
if (la < lb) return -1;
1887
if (la > lb) return +1;
1891
/* Otherwise do a string sort */
1892
result = safe_strcmp (da, db);
1896
/* if acccount-type-order array not initialized, initialize it */
1897
/* this will happen at most once during program invocation */
1898
if (-1 == revorder[0]) {
1900
for (i=0; i<NUM_ACCOUNT_TYPES; i++) {
1901
revorder [typeorder[i]] = i;
1905
/* otherwise, sort on account type */
1910
if (ta < tb) return -1;
1911
if (ta > tb) return +1;
1913
/* otherwise, sort on accountName strings */
1914
da = priv_aa->accountName;
1915
db = priv_ab->accountName;
1916
result = safe_utf8_collate(da, db);
1920
/* guarantee a stable sort */
1921
return qof_instance_guid_compare(aa, ab);
1925
qof_xaccAccountOrder (const Account **aa, const Account **ab)
1927
return xaccAccountOrder(*aa, *ab);
1930
/********************************************************************\
1931
\********************************************************************/
1934
xaccAccountSetType (Account *acc, GNCAccountType tip)
1936
AccountPrivate *priv;
1939
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1940
g_return_if_fail(tip < NUM_ACCOUNT_TYPES);
1943
priv = GET_PRIVATE(acc);
1944
if (priv->type == tip)
1947
xaccAccountBeginEdit(acc);
1949
priv->balance_dirty = TRUE; /* new type may affect balance computation */
1951
xaccAccountCommitEdit(acc);
1955
xaccAccountSetName (Account *acc, const char *str)
1957
AccountPrivate *priv;
1960
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1961
g_return_if_fail(str);
1964
priv = GET_PRIVATE(acc);
1965
if (str == priv->accountName)
1968
xaccAccountBeginEdit(acc);
1969
CACHE_REPLACE(priv->accountName, str);
1971
xaccAccountCommitEdit(acc);
1975
xaccAccountSetCode (Account *acc, const char *str)
1977
AccountPrivate *priv;
1980
g_return_if_fail(GNC_IS_ACCOUNT(acc));
1983
priv = GET_PRIVATE(acc);
1984
if (str == priv->accountCode)
1987
xaccAccountBeginEdit(acc);
1988
CACHE_REPLACE(priv->accountCode, str ? str : "");
1990
xaccAccountCommitEdit(acc);
1994
xaccAccountSetDescription (Account *acc, const char *str)
1996
AccountPrivate *priv;
1999
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2002
priv = GET_PRIVATE(acc);
2003
if (str == priv->description)
2006
xaccAccountBeginEdit(acc);
2007
CACHE_REPLACE(priv->description, str ? str : "");
2009
xaccAccountCommitEdit(acc);
2013
qofAccountSetParent (Account *acc, QofInstance *parent)
2015
Account *parent_acc;
2017
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2018
g_return_if_fail(GNC_IS_ACCOUNT(parent));
2020
parent_acc = GNC_ACCOUNT(parent);
2021
xaccAccountBeginEdit(acc);
2022
xaccAccountBeginEdit(parent_acc);
2023
gnc_account_append_child(parent_acc, acc);
2024
mark_account (parent_acc);
2026
xaccAccountCommitEdit(acc);
2027
xaccAccountCommitEdit(parent_acc);
2031
xaccAccountSetNotes (Account *acc, const char *str)
2033
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2035
xaccAccountBeginEdit(acc);
2037
gchar *tmp = g_strstrip(g_strdup(str));
2038
kvp_frame_set_slot_nc(acc->inst.kvp_data, "notes",
2039
strlen(tmp) ? kvp_value_new_string(tmp) : NULL);
2042
kvp_frame_set_slot_nc(acc->inst.kvp_data, "notes", NULL);
2045
xaccAccountCommitEdit(acc);
2049
xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
2051
AccountPrivate *priv;
2055
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2056
g_return_if_fail(GNC_IS_COMMODITY(com));
2059
priv = GET_PRIVATE(acc);
2060
if (com == priv->commodity)
2063
xaccAccountBeginEdit(acc);
2064
priv->commodity = com;
2065
priv->commodity_scu = gnc_commodity_get_fraction(com);
2066
priv->non_standard_scu = FALSE;
2068
/* iterate over splits */
2069
for (lp = priv->splits; lp; lp = lp->next)
2071
Split *s = (Split *) lp->data;
2072
Transaction *trans = xaccSplitGetParent (s);
2074
xaccTransBeginEdit (trans);
2075
xaccSplitSetAmount (s, xaccSplitGetAmount(s));
2076
xaccTransCommitEdit (trans);
2079
priv->sort_dirty = TRUE; /* Not needed. */
2080
priv->balance_dirty = TRUE;
2083
if (gnc_commodity_is_iso(com)) {
2084
/* compatability hack - Gnucash 1.8 gets currency quotes when a
2085
non-default currency is assigned to an account. */
2086
gnc_commodity_begin_edit(com);
2087
gnc_commodity_set_quote_flag(com, TRUE);
2088
gnc_commodity_set_quote_source(com,
2089
gnc_commodity_get_default_quote_source(com));
2090
gnc_commodity_commit_edit(com);
2092
xaccAccountCommitEdit(acc);
2096
* Set the account scu and then check to see if it is the same as the
2097
* commodity scu. This function is called when parsing the data file
2098
* and is designed to catch cases where the two were accidentally set
2099
* to mismatched values in the past.
2102
xaccAccountSetCommoditySCU (Account *acc, int scu)
2104
AccountPrivate *priv;
2106
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2108
priv = GET_PRIVATE(acc);
2109
xaccAccountBeginEdit(acc);
2110
priv->commodity_scu = scu;
2111
if (scu != gnc_commodity_get_fraction(priv->commodity))
2112
priv->non_standard_scu = TRUE;
2114
xaccAccountCommitEdit(acc);
2118
xaccAccountGetCommoditySCUi (const Account * acc)
2120
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
2121
return GET_PRIVATE(acc)->commodity_scu;
2125
xaccAccountGetCommoditySCU (const Account * acc)
2127
AccountPrivate *priv;
2129
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
2131
priv = GET_PRIVATE(acc);
2132
if (priv->non_standard_scu || !priv->commodity)
2133
return priv->commodity_scu;
2134
return gnc_commodity_get_fraction(priv->commodity);
2138
xaccAccountSetNonStdSCU (Account *acc, gboolean flag)
2140
AccountPrivate *priv;
2142
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2144
priv = GET_PRIVATE(acc);
2145
if (priv->non_standard_scu == flag)
2147
xaccAccountBeginEdit(acc);
2148
priv->non_standard_scu = flag;
2150
xaccAccountCommitEdit(acc);
2154
xaccAccountGetNonStdSCU (const Account * acc)
2156
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
2157
return GET_PRIVATE(acc)->non_standard_scu;
2160
/********************************************************************\
2161
\********************************************************************/
2162
/* below follow the old, deprecated currency/security routines. */
2165
DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency)
2169
gnc_commodity *commodity;
2171
if ((!acc) || (!currency)) return;
2173
xaccAccountBeginEdit(acc);
2174
string = gnc_commodity_get_unique_name (currency);
2175
kvp_frame_set_slot_nc(acc->inst.kvp_data, "old-currency",
2176
kvp_value_new_string(string));
2178
xaccAccountCommitEdit(acc);
2180
commodity = DxaccAccountGetCurrency (acc);
2183
book = qof_instance_get_book(acc);
2184
gnc_commodity_table_insert (gnc_commodity_table_get_table (book), currency);
2188
/********************************************************************\
2189
\********************************************************************/
2192
gnc_account_append_child (Account *new_parent, Account *child)
2194
AccountPrivate *ppriv, *cpriv;
2195
Account *old_parent;
2199
g_assert(GNC_IS_ACCOUNT(new_parent));
2200
g_assert(GNC_IS_ACCOUNT(child));
2203
ppriv = GET_PRIVATE(new_parent);
2204
cpriv = GET_PRIVATE(child);
2205
old_parent = cpriv->parent;
2206
if (old_parent == new_parent)
2209
// xaccAccountBeginEdit(new_parent);
2210
xaccAccountBeginEdit(child);
2212
gnc_account_remove_child(old_parent, child);
2214
if (!qof_instance_books_equal(old_parent, new_parent)) {
2215
/* hack alert -- this implementation is not exactly correct.
2216
* If the entity tables are not identical, then the 'from' book
2217
* may have a different backend than the 'to' book. This means
2218
* that we should get the 'from' backend to destroy this account,
2219
* and the 'to' backend to save it. Right now, this is broken.
2221
* A 'correct' implementation similar to this is in Period.c
2222
* except its for transactions ...
2224
* Note also, we need to reparent the children to the new book as well.
2226
PWARN ("reparenting accounts across books is not correctly supported\n");
2228
qof_event_gen (&child->inst, QOF_EVENT_DESTROY, NULL);
2229
col = qof_book_get_collection (qof_instance_get_book(new_parent),
2231
qof_collection_insert_entity (col, &child->inst);
2232
qof_event_gen (&child->inst, QOF_EVENT_CREATE, NULL);
2235
cpriv->parent = new_parent;
2236
ppriv->children = g_list_append(ppriv->children, child);
2237
qof_instance_set_dirty(&new_parent->inst);
2238
qof_instance_set_dirty(&child->inst);
2240
/* Send events data. Warning: The call to commit_edit is also gpoing
2241
* to send a MODIFY event. If the gtktreemodelfilter code gets the
2242
* MODIFY before it gets the ADD, it gets very confused and thinks
2243
* that two nodes have been added. */
2244
qof_event_gen (&child->inst, QOF_EVENT_ADD, NULL);
2245
// qof_event_gen (&new_parent->inst, QOF_EVENT_MODIFY, NULL);
2247
xaccAccountCommitEdit (child);
2248
// xaccAccountCommitEdit(new_parent);
2252
gnc_account_remove_child (Account *parent, Account *child)
2254
AccountPrivate *ppriv, *cpriv;
2259
/* Note this routine might be called on accounts which
2260
* are not yet parented. */
2261
if (!parent) return;
2263
ppriv = GET_PRIVATE(parent);
2264
cpriv = GET_PRIVATE(child);
2266
if (cpriv->parent != parent)
2268
PERR ("account not a child of parent");
2272
/* Gather event data */
2274
ed.idx = g_list_index(ppriv->children, child);
2276
ppriv->children = g_list_remove(ppriv->children, child);
2278
/* Now send the event. */
2279
qof_event_gen(&child->inst, QOF_EVENT_REMOVE, &ed);
2281
/* clear the account's parent pointer after REMOVE event generation. */
2282
cpriv->parent = NULL;
2284
qof_event_gen (&parent->inst, QOF_EVENT_MODIFY, NULL);
2288
gnc_account_get_parent (const Account *acc)
2290
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2291
return GET_PRIVATE(acc)->parent;
2295
gnc_account_get_root (Account *acc)
2297
AccountPrivate *priv;
2299
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2301
priv = GET_PRIVATE(acc);
2302
while (priv->parent) {
2304
priv = GET_PRIVATE(acc);
2311
gnc_account_is_root (const Account *account)
2313
g_return_val_if_fail(GNC_IS_ACCOUNT(account), FALSE);
2314
return (GET_PRIVATE(account)->parent == NULL);
2318
gnc_account_get_children (const Account *account)
2320
g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
2321
return g_list_copy(GET_PRIVATE(account)->children);
2325
gnc_account_get_children_sorted (const Account *account)
2327
AccountPrivate *priv;
2330
g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
2333
priv = GET_PRIVATE(account);
2334
if (!priv->children)
2336
return g_list_sort(g_list_copy(priv->children), (GCompareFunc)xaccAccountOrder);
2340
gnc_account_n_children (const Account *account)
2342
g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
2343
return g_list_length(GET_PRIVATE(account)->children);
2347
gnc_account_child_index (const Account *parent, const Account *child)
2349
g_return_val_if_fail(GNC_IS_ACCOUNT(parent), -1);
2350
g_return_val_if_fail(GNC_IS_ACCOUNT(child), -1);
2351
return g_list_index(GET_PRIVATE(parent)->children, child);
2355
gnc_account_nth_child (const Account *parent, gint num)
2357
g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
2358
return g_list_nth_data(GET_PRIVATE(parent)->children, num);
2362
gnc_account_n_descendants (const Account *account)
2364
AccountPrivate *priv;
2368
g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
2370
priv = GET_PRIVATE(account);
2371
for (node = priv->children; node; node = g_list_next(node)) {
2372
count += gnc_account_n_descendants(node->data) + 1;
2378
gnc_account_get_current_depth (const Account *account)
2380
AccountPrivate *priv;
2383
g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
2385
priv = GET_PRIVATE(account);
2386
while (priv->parent && (priv->type != ACCT_TYPE_ROOT)) {
2387
account = priv->parent;
2388
priv = GET_PRIVATE(account);
2396
gnc_account_get_tree_depth (const Account *account)
2398
AccountPrivate *priv;
2400
gint depth = 0, child_depth;
2402
g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0);
2404
priv = GET_PRIVATE(account);
2405
if (!priv->children)
2408
for (node = priv->children; node; node = g_list_next(node)) {
2409
child_depth = gnc_account_get_tree_depth(node->data);
2410
depth = MAX(depth, child_depth);
2416
gnc_account_get_descendants (const Account *account)
2418
AccountPrivate *priv;
2419
GList *child, *descendants;
2421
g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
2423
priv = GET_PRIVATE(account);
2424
if (!priv->children)
2428
for (child = priv->children; child; child = g_list_next(child)) {
2429
descendants = g_list_append(descendants, child->data);
2430
descendants = g_list_concat(descendants,
2431
gnc_account_get_descendants(child->data));
2437
gnc_account_get_descendants_sorted (const Account *account)
2439
AccountPrivate *priv;
2440
GList *child, *children, *descendants;
2443
g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL);
2446
priv = GET_PRIVATE(account);
2447
if (!priv->children)
2451
children = g_list_sort(g_list_copy(priv->children), (GCompareFunc)xaccAccountOrder);
2452
for (child = children; child; child = g_list_next(child)) {
2453
descendants = g_list_append(descendants, child->data);
2454
descendants = g_list_concat(descendants,
2455
gnc_account_get_descendants(child->data));
2457
g_list_free(children);
2462
gnc_account_lookup_by_name (const Account *parent, const char * name)
2464
AccountPrivate *cpriv, *ppriv;
2465
Account *child, *result;
2468
g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
2469
g_return_val_if_fail(name, NULL);
2471
/* first, look for accounts hanging off the current node */
2472
ppriv = GET_PRIVATE(parent);
2473
for (node = ppriv->children; node; node = node->next)
2476
cpriv = GET_PRIVATE(child);
2477
if (safe_strcmp(cpriv->accountName, name) == 0)
2481
/* if we are still here, then we haven't found the account yet.
2482
* Recursively search each of the child accounts next */
2483
for (node = ppriv->children; node; node = node->next)
2486
result = gnc_account_lookup_by_name (child, name);
2494
/********************************************************************\
2495
* Fetch an account, given its full name *
2496
\********************************************************************/
2499
gnc_account_lookup_by_full_name_helper (const Account *parent,
2502
const AccountPrivate *priv, *ppriv;
2506
g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
2507
g_return_val_if_fail(names, NULL);
2509
/* Look for the first name in the children. */
2510
ppriv = GET_PRIVATE(parent);
2511
for (node = ppriv->children; node; node = node->next) {
2512
Account *account = node->data;
2514
priv = GET_PRIVATE(account);
2515
if (safe_strcmp(priv->accountName, names[0]) == 0) {
2516
/* We found an account. If the next entry is NULL, there is
2517
* nothing left in the name, so just return the account. */
2518
if (names[1] == NULL)
2521
/* No children? We're done. */
2522
if (!priv->children)
2525
/* There's stuff left to search for. Search recursively. */
2526
found = gnc_account_lookup_by_full_name_helper(account, &names[1]);
2527
if (found != NULL) {
2538
gnc_account_lookup_by_full_name (const Account *any_acc,
2541
const AccountPrivate *rpriv;
2542
const Account *root;
2546
g_return_val_if_fail(GNC_IS_ACCOUNT(any_acc), NULL);
2547
g_return_val_if_fail(name, NULL);
2550
rpriv = GET_PRIVATE(root);
2551
while (rpriv->parent) {
2552
root = rpriv->parent;
2553
rpriv = GET_PRIVATE(root);
2555
names = g_strsplit(name, gnc_get_account_separator_string(), -1);
2556
found = gnc_account_lookup_by_full_name_helper(root, names);
2562
gnc_account_foreach_child (const Account *acc,
2566
const AccountPrivate *priv;
2569
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2570
g_return_if_fail(thunk);
2572
priv = GET_PRIVATE(acc);
2573
for (node = priv->children; node; node = node->next) {
2574
thunk (node->data, user_data);
2579
gnc_account_foreach_child_until (const Account *acc,
2583
const AccountPrivate *priv;
2587
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2588
g_return_val_if_fail(thunk, NULL);
2590
priv = GET_PRIVATE(acc);
2591
for (node = priv->children; node; node = node->next) {
2592
result = thunk (node->data, user_data);
2601
gnc_account_foreach_descendant (const Account *acc,
2605
const AccountPrivate *priv;
2609
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2610
g_return_if_fail(thunk);
2612
priv = GET_PRIVATE(acc);
2613
for (node = priv->children; node; node = node->next) {
2615
thunk(child, user_data);
2616
gnc_account_foreach_descendant(child, thunk, user_data);
2621
gnc_account_foreach_descendant_until (const Account *acc,
2625
const AccountPrivate *priv;
2630
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2631
g_return_val_if_fail(thunk, NULL);
2633
priv = GET_PRIVATE(acc);
2634
for (node = priv->children; node; node = node->next) {
2636
result = thunk(child, user_data);
2640
result = gnc_account_foreach_descendant_until(child, thunk, user_data);
2650
xaccAccountGetType (const Account *acc)
2652
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), ACCT_TYPE_NONE);
2653
return GET_PRIVATE(acc)->type;
2657
qofAccountGetTypeString (const Account *acc)
2659
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2660
return xaccAccountTypeEnumAsString(GET_PRIVATE(acc)->type);
2664
qofAccountSetType (Account *acc, const char *type_string)
2666
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2667
g_return_if_fail(type_string);
2668
xaccAccountSetType(acc, xaccAccountStringToEnum(type_string));
2672
xaccAccountGetName (const Account *acc)
2674
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2675
return GET_PRIVATE(acc)->accountName;
2679
xaccAccountGetFullName(const Account *account)
2681
AccountPrivate *priv;
2687
/* So much for hardening the API. Too many callers to this function don't
2688
* bother to check if they have a non-NULL pointer before calling. */
2689
if (NULL == account)
2690
return g_strdup("");
2693
g_return_val_if_fail(GNC_IS_ACCOUNT(account), g_strdup(""));
2696
priv = GET_PRIVATE(account);
2698
return g_strdup("");
2700
/* Figure out how much space is needed by counting the nodes up to
2703
for (a = account; a; a = priv->parent) {
2704
priv = GET_PRIVATE(a);
2708
/* Get all the pointers in the right order. The root node "entry"
2709
* becomes the terminating NULL pointer for the array of strings. */
2710
names = g_malloc(level * sizeof(gchar *));
2711
names[--level] = NULL;
2712
for (a = account; level > 0; a = priv->parent) {
2713
priv = GET_PRIVATE(a);
2714
names[--level] = priv->accountName;
2717
/* Build the full name */
2718
fullname = g_strjoinv(account_separator, names);
2725
xaccAccountGetCode (const Account *acc)
2727
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2728
return GET_PRIVATE(acc)->accountCode;
2732
xaccAccountGetDescription (const Account *acc)
2734
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2735
return GET_PRIVATE(acc)->description;
2739
xaccAccountGetNotes (const Account *acc)
2741
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
2742
return acc ? kvp_frame_get_string(acc->inst.kvp_data, "notes") : NULL;
2746
DxaccAccountGetCurrency (const Account *acc)
2750
gnc_commodity_table *table;
2752
if (!acc) return NULL;
2754
v = kvp_frame_get_slot(acc->inst.kvp_data, "old-currency");
2755
if (!v) return NULL;
2757
s = kvp_value_get_string (v);
2758
if (!s) return NULL;
2760
table = gnc_commodity_table_get_table (qof_instance_get_book(acc));
2762
return gnc_commodity_table_lookup_unique (table, s);
2766
xaccAccountGetCommodity (const Account *acc)
2768
if (!GNC_IS_ACCOUNT(acc))
2770
return GET_PRIVATE(acc)->commodity;
2773
/********************************************************************\
2774
\********************************************************************/
2777
gnc_account_get_start_balance (Account *acc)
2779
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2781
return GET_PRIVATE(acc)->starting_balance;
2785
gnc_account_set_start_balance (Account *acc, const gnc_numeric start_baln)
2787
AccountPrivate *priv;
2789
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2791
priv = GET_PRIVATE(acc);
2792
priv->starting_balance = start_baln;
2793
priv->balance_dirty = TRUE;
2797
gnc_account_get_start_cleared_balance (Account *acc)
2799
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2801
return GET_PRIVATE(acc)->starting_cleared_balance;
2805
gnc_account_set_start_cleared_balance (Account *acc,
2806
const gnc_numeric start_baln)
2808
AccountPrivate *priv;
2810
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2812
priv = GET_PRIVATE(acc);
2813
priv->starting_balance = start_baln;
2814
priv->balance_dirty = TRUE;
2818
gnc_account_get_start_reconciled_balance (Account *acc)
2820
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2822
return GET_PRIVATE(acc)->starting_reconciled_balance;
2826
gnc_account_set_start_reconciled_balance (Account *acc,
2827
const gnc_numeric start_baln)
2829
AccountPrivate *priv;
2831
g_return_if_fail(GNC_IS_ACCOUNT(acc));
2833
priv = GET_PRIVATE(acc);
2834
priv->starting_balance = start_baln;
2835
priv->balance_dirty = TRUE;
2839
xaccAccountGetBalance (const Account *acc)
2841
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2842
return GET_PRIVATE(acc)->balance;
2846
xaccAccountGetClearedBalance (const Account *acc)
2848
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2849
return GET_PRIVATE(acc)->cleared_balance;
2853
xaccAccountGetReconciledBalance (const Account *acc)
2855
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2856
return GET_PRIVATE(acc)->reconciled_balance;
2860
xaccAccountGetProjectedMinimumBalance (const Account *acc)
2862
AccountPrivate *priv;
2865
gnc_numeric lowest = gnc_numeric_zero ();
2866
int seen_a_transaction = 0;
2868
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2870
priv = GET_PRIVATE(acc);
2871
today = gnc_timet_get_today_end();
2872
for (node = g_list_last(priv->splits); node; node = node->prev)
2874
Split *split = node->data;
2876
if (!seen_a_transaction)
2878
lowest = xaccSplitGetBalance (split);
2879
seen_a_transaction = 1;
2880
} else if (gnc_numeric_compare(xaccSplitGetBalance (split), lowest) < 0) {
2881
lowest = xaccSplitGetBalance (split);
2884
if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
2892
/********************************************************************\
2893
\********************************************************************/
2896
xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
2898
/* Ideally this could use xaccAccountForEachSplit, but
2899
* it doesn't exist yet and I'm uncertain of exactly how
2900
* it would work at this time, since it differs from
2901
* xaccAccountForEachTransaction by using gpointer return
2902
* values rather than gints.
2904
AccountPrivate *priv;
2906
Timespec ts, trans_ts;
2907
gboolean found = FALSE;
2908
gnc_numeric balance;
2910
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2912
xaccAccountSortSplits (acc, TRUE); /* just in case, normally a noop */
2913
xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */
2915
priv = GET_PRIVATE(acc);
2916
balance = priv->balance;
2918
/* Since transaction post times are stored as a Timespec,
2919
* convert date into a Timespec as well rather than converting
2920
* each transaction's Timespec into a time_t.
2922
* FIXME: CAS: I think this comment is a bogus justification for
2923
* using xaccTransGetDatePostedTS. There's no benefit to using
2924
* Timespec when the input argument is time_t, and it's hard to
2925
* imagine that casting long long to long and comparing two longs is
2926
* worse than comparing two long longs every time. IMO,
2927
* xaccAccountGetPresentBalance gets this right, and its algorithm
2928
* should be used here.
2934
while( lp && !found )
2936
xaccTransGetDatePostedTS( xaccSplitGetParent( (Split *)lp->data ),
2938
if( timespec_cmp( &trans_ts, &ts ) >= 0 )
2946
/* Since lp is now pointing to a split which was past the reconcile
2947
* date, get the running balance of the previous split.
2949
balance = xaccSplitGetBalance( (Split *)lp->prev->data );
2952
/* AsOf date must be before any entries, return zero. */
2953
balance = gnc_numeric_zero();
2957
/* Otherwise there were no splits posted after the given date,
2958
* so the latest account balance should be good enough.
2965
* Originally gsr_account_present_balance in gnc-split-reg.c
2967
* How does this routine compare to xaccAccountGetBalanceAsOfDate just
2968
* above? These two routines should eventually be collapsed into one.
2969
* Perhaps the startup logic from that one, and the logic from this
2970
* one that walks from the tail of the split list.
2973
xaccAccountGetPresentBalance (const Account *acc)
2975
AccountPrivate *priv;
2979
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
2981
priv = GET_PRIVATE(acc);
2982
today = gnc_timet_get_today_end();
2983
for (node = g_list_last(priv->splits); node; node = node->prev)
2985
Split *split = node->data;
2987
if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
2988
return xaccSplitGetBalance (split);
2991
return gnc_numeric_zero ();
2995
/********************************************************************\
2996
\********************************************************************/
2997
/* XXX TODO: These 'GetBal' routines should be moved to some
2998
* utility area outside of the core account engine area.
3002
* Convert a balance from one currency to another.
3005
xaccAccountConvertBalanceToCurrency(const Account *acc, /* for book */
3006
gnc_numeric balance,
3007
const gnc_commodity *balance_currency,
3008
const gnc_commodity *new_currency)
3013
if (gnc_numeric_zero_p (balance) ||
3014
gnc_commodity_equiv (balance_currency, new_currency))
3017
book = gnc_account_get_book (acc);
3018
pdb = gnc_pricedb_get_db (book);
3020
balance = gnc_pricedb_convert_balance_latest_price(
3021
pdb, balance, balance_currency, new_currency);
3027
* Convert a balance from one currency to another with price of
3031
xaccAccountConvertBalanceToCurrencyAsOfDate(const Account *acc, /* for book */
3032
gnc_numeric balance,
3033
gnc_commodity *balance_currency,
3034
gnc_commodity *new_currency,
3041
if (gnc_numeric_zero_p (balance) ||
3042
gnc_commodity_equiv (balance_currency, new_currency))
3045
book = gnc_account_get_book (acc);
3046
pdb = gnc_book_get_pricedb (book);
3051
balance = gnc_pricedb_convert_balance_nearest_price(
3052
pdb, balance, balance_currency, new_currency, ts);
3058
* Given an account and a GetBalanceFn pointer, extract the requested
3059
* balance from the account and then convert it to the desired
3063
xaccAccountGetXxxBalanceInCurrency (const Account *acc,
3064
xaccGetBalanceFn fn,
3065
const gnc_commodity *report_currency)
3067
AccountPrivate *priv;
3068
gnc_numeric balance;
3070
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3071
g_return_val_if_fail(fn, gnc_numeric_zero());
3072
g_return_val_if_fail(GNC_IS_COMMODITY(report_currency), gnc_numeric_zero());
3074
priv = GET_PRIVATE(acc);
3076
balance = xaccAccountConvertBalanceToCurrency(acc, balance,
3083
xaccAccountGetXxxBalanceAsOfDateInCurrency(Account *acc, time_t date,
3084
xaccGetBalanceAsOfDateFn fn,
3085
const gnc_commodity *report_commodity)
3087
AccountPrivate *priv;
3089
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
3090
g_return_val_if_fail(fn, gnc_numeric_zero());
3091
g_return_val_if_fail(GNC_IS_COMMODITY(report_commodity), gnc_numeric_zero());
3093
priv = GET_PRIVATE(acc);
3094
return xaccAccountConvertBalanceToCurrency(
3095
acc, fn(acc, date), priv->commodity, report_commodity);
3099
* Data structure used to pass various arguments into the following fn.
3103
const gnc_commodity *currency;
3104
gnc_numeric balance;
3105
xaccGetBalanceFn fn;
3106
xaccGetBalanceAsOfDateFn asOfDateFn;
3112
* A helper function for iterating over all the accounts in a list or
3113
* tree. This function is called once per account, and sums up the
3114
* values of all these accounts.
3117
xaccAccountBalanceHelper (Account *acc, gpointer data)
3119
CurrencyBalance *cb = data;
3120
gnc_numeric balance;
3122
if (!cb->fn || !cb->currency)
3124
balance = xaccAccountGetXxxBalanceInCurrency (acc, cb->fn, cb->currency);
3125
cb->balance = gnc_numeric_add (cb->balance, balance,
3126
gnc_commodity_get_fraction (cb->currency),
3131
xaccAccountBalanceAsOfDateHelper (Account *acc, gpointer data)
3133
CurrencyBalance *cb = data;
3134
gnc_numeric balance;
3136
g_return_if_fail (cb->asOfDateFn && cb->currency);
3138
balance = xaccAccountGetXxxBalanceAsOfDateInCurrency (
3139
acc, cb->date, cb->asOfDateFn, cb->currency);
3140
cb->balance = gnc_numeric_add (cb->balance, balance,
3141
gnc_commodity_get_fraction (cb->currency),
3148
* Common function that iterates recursively over all accounts below
3149
* the specified account. It uses xaccAccountBalanceHelper to sum up
3150
* the balances of all its children, and uses the specified function
3151
* 'fn' for extracting the balance. This function may extract the
3152
* current value, the reconciled value, etc.
3154
* If 'report_commodity' is NULL, just use the account's commodity.
3155
* If 'include_children' is FALSE, this function doesn't recurse at all.
3158
xaccAccountGetXxxBalanceInCurrencyRecursive (const Account *acc,
3159
xaccGetBalanceFn fn,
3160
const gnc_commodity *report_commodity,
3161
gboolean include_children)
3163
gnc_numeric balance;
3165
if (!acc) return gnc_numeric_zero ();
3166
if (!report_commodity)
3167
report_commodity = xaccAccountGetCommodity (acc);
3168
if (!report_commodity)
3169
return gnc_numeric_zero();
3171
balance = xaccAccountGetXxxBalanceInCurrency (acc, fn, report_commodity);
3173
/* If needed, sum up the children converting to the *requested*
3175
if (include_children) {
3176
CurrencyBalance cb = { report_commodity, balance, fn, NULL, 0 };
3178
gnc_account_foreach_descendant (acc, xaccAccountBalanceHelper, &cb);
3179
balance = cb.balance;
3186
xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3187
Account *acc, time_t date, xaccGetBalanceAsOfDateFn fn,
3188
gnc_commodity *report_commodity, gboolean include_children)
3190
gnc_numeric balance;
3192
g_return_val_if_fail(acc, gnc_numeric_zero());
3193
if (!report_commodity)
3194
report_commodity = xaccAccountGetCommodity (acc);
3195
if (!report_commodity)
3196
return gnc_numeric_zero();
3198
balance = xaccAccountGetXxxBalanceAsOfDateInCurrency(
3199
acc, date, fn, report_commodity);
3201
/* If needed, sum up the children converting to the *requested*
3203
if (include_children) {
3204
CurrencyBalance cb = { report_commodity, balance, NULL, fn, date };
3206
gnc_account_foreach_descendant (acc, xaccAccountBalanceAsOfDateHelper, &cb);
3207
balance = cb.balance;
3214
xaccAccountGetBalanceInCurrency (const Account *acc,
3215
const gnc_commodity *report_commodity,
3216
gboolean include_children)
3219
rc = xaccAccountGetXxxBalanceInCurrencyRecursive (
3220
acc, xaccAccountGetBalance, report_commodity, include_children);
3221
PINFO(" baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, rc.num, rc.denom);
3227
xaccAccountGetClearedBalanceInCurrency (const Account *acc,
3228
const gnc_commodity *report_commodity,
3229
gboolean include_children)
3231
return xaccAccountGetXxxBalanceInCurrencyRecursive (
3232
acc, xaccAccountGetClearedBalance, report_commodity,
3238
xaccAccountGetReconciledBalanceInCurrency (const Account *acc,
3239
const gnc_commodity *report_commodity,
3240
gboolean include_children)
3242
return xaccAccountGetXxxBalanceInCurrencyRecursive (
3243
acc, xaccAccountGetReconciledBalance, report_commodity,
3248
xaccAccountGetPresentBalanceInCurrency (const Account *acc,
3249
const gnc_commodity *report_commodity,
3250
gboolean include_children)
3252
return xaccAccountGetXxxBalanceInCurrencyRecursive (
3253
acc, xaccAccountGetPresentBalance, report_commodity,
3258
xaccAccountGetProjectedMinimumBalanceInCurrency (
3260
const gnc_commodity *report_commodity,
3261
gboolean include_children)
3263
return xaccAccountGetXxxBalanceInCurrencyRecursive (
3264
acc, xaccAccountGetProjectedMinimumBalance, report_commodity,
3269
xaccAccountGetBalanceAsOfDateInCurrency(
3270
Account *acc, time_t date, gnc_commodity *report_commodity,
3271
gboolean include_children)
3273
return xaccAccountGetXxxBalanceAsOfDateInCurrencyRecursive (
3274
acc, date, xaccAccountGetBalanceAsOfDate, report_commodity,
3279
xaccAccountGetBalanceChangeForPeriod (Account *acc, time_t t1, time_t t2, gboolean recurse)
3283
b1 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t1, NULL, recurse);
3284
b2 = xaccAccountGetBalanceAsOfDateInCurrency(acc, t2, NULL, recurse);
3285
return gnc_numeric_sub(b2, b1, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
3289
/********************************************************************\
3290
\********************************************************************/
3292
/* THIS API NEEDS TO CHANGE.
3294
* This code exposes the internal structure of the account object to
3295
* external callers by returning the actual list used by the object.
3296
* It should instead return a copy of the split list that the caller
3297
* is required to free. That change would provide the freedom of
3298
* allowing the internal organization to change data structures if
3299
* necessary for whatever reason, while leaving the external API
3302
xaccAccountGetSplitList (const Account *acc)
3304
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
3305
return GET_PRIVATE(acc)->splits;
3309
xaccAccountGetLotList (const Account *acc)
3311
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
3312
return g_list_copy(GET_PRIVATE(acc)->lots);
3316
xaccAccountFindOpenLots (const Account *acc,
3317
gboolean (*match_func)(GNCLot *lot,
3318
gpointer user_data),
3319
gpointer user_data, GCompareFunc sort_func)
3321
AccountPrivate *priv;
3323
GList *retval = NULL;
3325
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
3327
priv = GET_PRIVATE(acc);
3328
for (lot_list = priv->lots; lot_list; lot_list = lot_list->next) {
3329
GNCLot *lot = lot_list->data;
3331
/* If this lot is closed, then ignore it */
3332
if (gnc_lot_is_closed (lot))
3335
if (match_func && !(match_func)(lot, user_data))
3338
/* Ok, this is a valid lot. Add it to our list of lots */
3340
retval = g_list_insert_sorted (retval, lot, sort_func);
3342
retval = g_list_prepend (retval, lot);
3349
xaccAccountForEachLot(const Account *acc,
3350
gpointer (*proc)(GNCLot *lot, void *data), void *data)
3352
AccountPrivate *priv;
3354
gpointer result = NULL;
3356
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
3357
g_return_val_if_fail(proc, NULL);
3359
priv = GET_PRIVATE(acc);
3360
for (node = priv->lots; node; node = node->next)
3361
if ((result = proc((GNCLot *)node->data, data)))
3367
/********************************************************************\
3368
\********************************************************************/
3370
/* These functions use interchange gint64 and gboolean. Is that right? */
3372
xaccAccountGetTaxRelated (const Account *acc)
3374
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
3375
return kvp_frame_get_gint64(acc->inst.kvp_data, "tax-related");
3379
xaccAccountSetTaxRelated (Account *acc, gboolean tax_related)
3381
KvpValue *new_value;
3383
g_return_if_fail(GNC_IS_ACCOUNT(acc));
3386
new_value = kvp_value_new_gint64 (tax_related);
3390
xaccAccountBeginEdit (acc);
3391
kvp_frame_set_slot_nc(acc->inst.kvp_data, "tax-related", new_value);
3393
xaccAccountCommitEdit (acc);
3397
xaccAccountGetTaxUSCode (const Account *acc)
3399
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
3400
return kvp_frame_get_string(acc->inst.kvp_data, "tax-US/code");
3404
xaccAccountSetTaxUSCode (Account *acc, const char *code)
3406
g_return_if_fail(GNC_IS_ACCOUNT(acc));
3408
xaccAccountBeginEdit (acc);
3409
kvp_frame_set_string (acc->inst.kvp_data, "/tax-US/code", code);
3411
xaccAccountCommitEdit (acc);
3415
xaccAccountGetTaxUSPayerNameSource (const Account *acc)
3417
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
3418
return kvp_frame_get_string(acc->inst.kvp_data,
3419
"tax-US/payer-name-source");
3423
xaccAccountSetTaxUSPayerNameSource (Account *acc, const char *source)
3425
g_return_if_fail(GNC_IS_ACCOUNT(acc));
3427
xaccAccountBeginEdit (acc);
3428
kvp_frame_set_string (acc->inst.kvp_data,
3429
"/tax-US/payer-name-source", source);
3431
xaccAccountCommitEdit (acc);
3434
/********************************************************************\
3435
\********************************************************************/
3438
xaccAccountGetPlaceholder (const Account *acc)
3442
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
3444
str = kvp_frame_get_string(acc->inst.kvp_data, "placeholder");
3445
return (str && !strcmp(str, "true"));
3449
xaccAccountSetPlaceholder (Account *acc, gboolean val)
3451
g_return_if_fail(GNC_IS_ACCOUNT(acc));
3453
xaccAccountBeginEdit (acc);
3454
kvp_frame_set_string (acc->inst.kvp_data,
3455
"placeholder", val ? "true" : NULL);
3457
xaccAccountCommitEdit (acc);
3461
xaccAccountGetDescendantPlaceholder (const Account *acc)
3463
GList *descendants, *node;
3464
GNCPlaceholderType ret = PLACEHOLDER_NONE;
3466
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), PLACEHOLDER_NONE);
3467
if (xaccAccountGetPlaceholder(acc)) return PLACEHOLDER_THIS;
3469
descendants = gnc_account_get_descendants(acc);
3470
for (node = descendants; node; node = node->next)
3471
if (xaccAccountGetPlaceholder((Account *) node->data)) {
3472
ret = PLACEHOLDER_CHILD;
3476
g_list_free(descendants);
3480
/********************************************************************\
3481
\********************************************************************/
3484
xaccAccountGetHidden (const Account *acc)
3488
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
3490
str = kvp_frame_get_string(acc->inst.kvp_data, "hidden");
3491
return (str && !strcmp(str, "true"));
3495
xaccAccountSetHidden (Account *acc, gboolean val)
3497
g_return_if_fail(GNC_IS_ACCOUNT(acc));
3499
xaccAccountBeginEdit (acc);
3500
kvp_frame_set_string (acc->inst.kvp_data, "hidden",
3501
val ? "true" : NULL);
3503
xaccAccountCommitEdit (acc);
3507
xaccAccountIsHidden (const Account *acc)
3509
AccountPrivate *priv;
3511
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
3513
if (xaccAccountGetHidden(acc))
3515
priv = GET_PRIVATE(acc);
3516
while ((acc = priv->parent) != NULL) {
3517
priv = GET_PRIVATE(acc);
3518
if (xaccAccountGetHidden(acc))
3524
/********************************************************************\
3525
\********************************************************************/
3528
xaccAccountHasAncestor (const Account *acc, const Account * ancestor)
3530
const Account *parent;
3532
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
3533
g_return_val_if_fail(GNC_IS_ACCOUNT(ancestor), FALSE);
3536
while (parent && parent != ancestor)
3537
parent = GET_PRIVATE(parent)->parent;
3539
return (parent == ancestor);
3542
/********************************************************************\
3543
\********************************************************************/
3545
/* You must edit the functions in this block in tandem. KEEP THEM IN
3548
#define GNC_RETURN_ENUM_AS_STRING(x) case (ACCT_TYPE_ ## x): return #x;
3551
xaccAccountTypeEnumAsString(GNCAccountType type)
3555
GNC_RETURN_ENUM_AS_STRING(NONE);
3556
GNC_RETURN_ENUM_AS_STRING(BANK);
3557
GNC_RETURN_ENUM_AS_STRING(CASH);
3558
GNC_RETURN_ENUM_AS_STRING(CREDIT);
3559
GNC_RETURN_ENUM_AS_STRING(ASSET);
3560
GNC_RETURN_ENUM_AS_STRING(LIABILITY);
3561
GNC_RETURN_ENUM_AS_STRING(STOCK);
3562
GNC_RETURN_ENUM_AS_STRING(MUTUAL);
3563
GNC_RETURN_ENUM_AS_STRING(CURRENCY);
3564
GNC_RETURN_ENUM_AS_STRING(INCOME);
3565
GNC_RETURN_ENUM_AS_STRING(EXPENSE);
3566
GNC_RETURN_ENUM_AS_STRING(EQUITY);
3567
GNC_RETURN_ENUM_AS_STRING(RECEIVABLE);
3568
GNC_RETURN_ENUM_AS_STRING(PAYABLE);
3569
GNC_RETURN_ENUM_AS_STRING(ROOT);
3570
GNC_RETURN_ENUM_AS_STRING(CHECKING);
3571
GNC_RETURN_ENUM_AS_STRING(SAVINGS);
3572
GNC_RETURN_ENUM_AS_STRING(MONEYMRKT);
3573
GNC_RETURN_ENUM_AS_STRING(CREDITLINE);
3575
PERR ("asked to translate unknown account type %d.\n", type);
3581
#undef GNC_RETURN_ENUM_AS_STRING
3583
#define GNC_RETURN_ON_MATCH(x) \
3584
if(safe_strcmp(#x, (str)) == 0) { *type = ACCT_TYPE_ ## x; return(TRUE); }
3587
xaccAccountStringToType(const char* str, GNCAccountType *type)
3590
GNC_RETURN_ON_MATCH(NONE);
3591
GNC_RETURN_ON_MATCH(BANK);
3592
GNC_RETURN_ON_MATCH(CASH);
3593
GNC_RETURN_ON_MATCH(CREDIT);
3594
GNC_RETURN_ON_MATCH(ASSET);
3595
GNC_RETURN_ON_MATCH(LIABILITY);
3596
GNC_RETURN_ON_MATCH(STOCK);
3597
GNC_RETURN_ON_MATCH(MUTUAL);
3598
GNC_RETURN_ON_MATCH(CURRENCY);
3599
GNC_RETURN_ON_MATCH(INCOME);
3600
GNC_RETURN_ON_MATCH(EXPENSE);
3601
GNC_RETURN_ON_MATCH(EQUITY);
3602
GNC_RETURN_ON_MATCH(RECEIVABLE);
3603
GNC_RETURN_ON_MATCH(PAYABLE);
3604
GNC_RETURN_ON_MATCH(ROOT);
3605
GNC_RETURN_ON_MATCH(CHECKING);
3606
GNC_RETURN_ON_MATCH(SAVINGS);
3607
GNC_RETURN_ON_MATCH(MONEYMRKT);
3608
GNC_RETURN_ON_MATCH(CREDITLINE);
3610
PERR("asked to translate unknown account type string %s.\n",
3611
str ? str : "(null)");
3616
#undef GNC_RETURN_ON_MATCH
3618
/* impedance mismatch is a source of loss */
3620
xaccAccountStringToEnum(const char* str)
3622
GNCAccountType type;
3624
rc = xaccAccountStringToType(str, &type);
3625
if (FALSE == rc) return ACCT_TYPE_INVALID;
3629
/********************************************************************\
3630
\********************************************************************/
3633
account_type_name[NUM_ACCOUNT_TYPES] = {
3656
xaccAccountGetTypeStr(GNCAccountType type) {
3657
if (type < 0 || NUM_ACCOUNT_TYPES <= type ) return "";
3658
return _(account_type_name [type]);
3662
xaccAccountGetTypeFromStr (const gchar *str)
3666
for (type = 0; type < NUM_ACCOUNT_TYPES; type++)
3668
if (!safe_strcmp (str, _(account_type_name [type])))
3672
PERR("asked to translate unknown account type string %s.\n",
3673
str ? str : "(null)");
3675
return ACCT_TYPE_INVALID;
3679
/********************************************************************\
3680
\********************************************************************/
3683
xaccParentAccountTypesCompatibleWith (GNCAccountType type)
3686
case ACCT_TYPE_BANK:
3687
case ACCT_TYPE_CASH:
3688
case ACCT_TYPE_ASSET:
3689
case ACCT_TYPE_STOCK:
3690
case ACCT_TYPE_MUTUAL:
3691
case ACCT_TYPE_CURRENCY:
3692
case ACCT_TYPE_CREDIT:
3693
case ACCT_TYPE_LIABILITY:
3694
case ACCT_TYPE_RECEIVABLE:
3695
case ACCT_TYPE_PAYABLE:
3697
(1 << ACCT_TYPE_BANK) |
3698
(1 << ACCT_TYPE_CASH) |
3699
(1 << ACCT_TYPE_ASSET) |
3700
(1 << ACCT_TYPE_STOCK) |
3701
(1 << ACCT_TYPE_MUTUAL) |
3702
(1 << ACCT_TYPE_CURRENCY) |
3703
(1 << ACCT_TYPE_CREDIT) |
3704
(1 << ACCT_TYPE_LIABILITY) |
3705
(1 << ACCT_TYPE_RECEIVABLE) |
3706
(1 << ACCT_TYPE_PAYABLE) |
3707
(1 << ACCT_TYPE_ROOT);
3708
case ACCT_TYPE_INCOME:
3709
case ACCT_TYPE_EXPENSE:
3711
(1 << ACCT_TYPE_INCOME) |
3712
(1 << ACCT_TYPE_EXPENSE) |
3713
(1 << ACCT_TYPE_ROOT);
3714
case ACCT_TYPE_EQUITY:
3716
(1 << ACCT_TYPE_EQUITY) |
3717
(1 << ACCT_TYPE_ROOT);
3719
PERR("bad account type: %d", type);
3725
xaccAccountTypesCompatible (GNCAccountType parent_type,
3726
GNCAccountType child_type)
3728
return ((xaccParentAccountTypesCompatibleWith (parent_type) &
3734
xaccAccountTypesValid(void)
3736
guint32 mask = (1 << NUM_ACCOUNT_TYPES) - 1;
3737
mask &= ~((1 << ACCT_TYPE_CURRENCY) | /* DEPRECATED */
3738
(1 << ACCT_TYPE_ROOT)); /* ROOT */
3744
xaccAccountIsPriced(const Account *acc)
3746
AccountPrivate *priv;
3748
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
3750
priv = GET_PRIVATE(acc);
3751
return (priv->type == ACCT_TYPE_STOCK || priv->type == ACCT_TYPE_MUTUAL ||
3752
priv->type == ACCT_TYPE_CURRENCY);
3755
/********************************************************************\
3756
\********************************************************************/
3759
xaccAccountGetReconcileLastDate (const Account *acc, time_t *last_date)
3763
if (!acc) return FALSE;
3765
v = kvp_frame_get_value(acc->inst.kvp_data, "reconcile-info/last-date");
3767
if (!v || kvp_value_get_type(v) != KVP_TYPE_GINT64)
3771
*last_date = kvp_value_get_gint64(v);
3776
/********************************************************************\
3777
\********************************************************************/
3780
xaccAccountSetReconcileLastDate (Account *acc, time_t last_date)
3784
xaccAccountBeginEdit (acc);
3785
kvp_frame_set_gint64 (acc->inst.kvp_data,
3786
"/reconcile-info/last-date", last_date);
3788
xaccAccountCommitEdit (acc);
3791
/********************************************************************\
3792
\********************************************************************/
3795
xaccAccountGetReconcileLastInterval (const Account *acc,
3796
int *months, int *days)
3800
if (!acc) return FALSE;
3802
v1 = kvp_frame_get_value(acc->inst.kvp_data,
3803
"reconcile-info/last-interval/months");
3804
v2 = kvp_frame_get_value(acc->inst.kvp_data,
3805
"reconcile-info/last-interval/days");
3806
if (!v1 || (kvp_value_get_type (v1) != KVP_TYPE_GINT64) ||
3807
!v2 || (kvp_value_get_type (v2) != KVP_TYPE_GINT64))
3811
*months = kvp_value_get_gint64 (v1);
3813
*days = kvp_value_get_gint64 (v2);
3817
/********************************************************************\
3818
\********************************************************************/
3821
xaccAccountSetReconcileLastInterval (Account *acc, int months, int days)
3826
xaccAccountBeginEdit (acc);
3828
frame = kvp_frame_get_frame_slash (acc->inst.kvp_data,
3829
"/reconcile-info/last-interval");
3832
kvp_frame_set_gint64 (frame, "months", months);
3833
kvp_frame_set_gint64 (frame, "days", days);
3836
xaccAccountCommitEdit (acc);
3839
/********************************************************************\
3840
\********************************************************************/
3843
xaccAccountGetReconcilePostponeDate (const Account *acc, time_t *postpone_date)
3847
if (!acc) return FALSE;
3849
v = kvp_frame_get_value(acc->inst.kvp_data, "reconcile-info/postpone/date");
3850
if (!v || kvp_value_get_type (v) != KVP_TYPE_GINT64)
3854
*postpone_date = kvp_value_get_gint64 (v);
3859
/********************************************************************\
3860
\********************************************************************/
3863
xaccAccountSetReconcilePostponeDate (Account *acc, time_t postpone_date)
3867
xaccAccountBeginEdit (acc);
3869
/* XXX this should be using timespecs, not gints !! */
3870
kvp_frame_set_gint64 (acc->inst.kvp_data,
3871
"reconcile-info/postpone/date", postpone_date);
3873
xaccAccountCommitEdit (acc);
3876
/********************************************************************\
3877
\********************************************************************/
3880
xaccAccountGetReconcilePostponeBalance (const Account *acc,
3881
gnc_numeric *balance)
3885
if (!acc) return FALSE;
3887
v = kvp_frame_get_value(acc->inst.kvp_data,
3888
"reconcile-info/postpone/balance");
3889
if (!v || kvp_value_get_type (v) != KVP_TYPE_NUMERIC)
3893
*balance = kvp_value_get_numeric (v);
3898
/********************************************************************\
3899
\********************************************************************/
3902
xaccAccountSetReconcilePostponeBalance (Account *acc, gnc_numeric balance)
3906
xaccAccountBeginEdit (acc);
3907
kvp_frame_set_gnc_numeric (acc->inst.kvp_data,
3908
"/reconcile-info/postpone/balance", balance);
3910
xaccAccountCommitEdit (acc);
3913
/********************************************************************\
3915
\********************************************************************/
3918
xaccAccountClearReconcilePostpone (Account *acc)
3922
xaccAccountBeginEdit (acc);
3923
kvp_frame_set_value (acc->inst.kvp_data, "reconcile-info/postpone", NULL);
3925
xaccAccountCommitEdit (acc);
3928
/********************************************************************\
3929
\********************************************************************/
3931
/* xaccAccountGetAutoInterestXfer: determine whether the auto interest
3932
* xfer option is enabled for this account, and return that value.
3933
* If it is not defined for the account, return the default value.
3936
xaccAccountGetAutoInterestXfer (const Account *acc, gboolean default_value)
3938
const char *str = NULL;
3939
if (!acc) return default_value;
3941
str = kvp_frame_get_string(acc->inst.kvp_data,
3942
"reconcile-info/auto-interest-transfer");
3943
return str ? !strcmp(str, "true") : default_value;
3946
/********************************************************************\
3947
\********************************************************************/
3950
xaccAccountSetAutoInterestXfer (Account *acc, gboolean option)
3954
xaccAccountBeginEdit (acc);
3955
/* FIXME: need KVP_TYPE_BOOLEAN for this someday */
3956
kvp_frame_set_string (acc->inst.kvp_data,
3957
"/reconcile-info/auto-interest-transfer",
3958
(option ? "true" : "false"));
3960
xaccAccountCommitEdit (acc);
3963
/********************************************************************\
3964
\********************************************************************/
3967
xaccAccountGetLastNum (const Account *acc)
3969
return acc ? kvp_frame_get_string(acc->inst.kvp_data, "last-num") : NULL;
3972
/********************************************************************\
3973
\********************************************************************/
3976
xaccAccountSetLastNum (Account *acc, const char *num)
3980
xaccAccountBeginEdit (acc);
3981
kvp_frame_set_string(acc->inst.kvp_data, "last-num", num);
3983
xaccAccountCommitEdit (acc);
3986
/********************************************************************\
3987
\********************************************************************/
3990
dxaccAccountSetPriceSrc(Account *acc, const char *src)
3994
xaccAccountBeginEdit(acc);
3995
if (xaccAccountIsPriced(acc)) {
3996
kvp_frame_set_slot_nc(acc->inst.kvp_data,
3998
src ? kvp_value_new_string(src) : NULL);
4002
qof_instance_set_dirty(&acc->inst);
4003
xaccAccountCommitEdit(acc);
4006
/********************************************************************\
4007
\********************************************************************/
4010
dxaccAccountGetPriceSrc(const Account *acc)
4012
if(!acc) return NULL;
4014
if (xaccAccountIsPriced(acc)) {
4015
KvpValue *value = kvp_frame_get_slot(acc->inst.kvp_data,
4016
"old-price-source");
4017
if (value) return (kvp_value_get_string(value));
4022
/********************************************************************\
4023
\********************************************************************/
4026
dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
4030
xaccAccountBeginEdit(acc);
4031
if (xaccAccountIsPriced(acc)) {
4032
kvp_frame_set_slot_nc(acc->inst.kvp_data,
4034
tz ? kvp_value_new_string(tz) : NULL);
4037
qof_instance_set_dirty(&acc->inst);
4038
xaccAccountCommitEdit(acc);
4041
/********************************************************************\
4042
\********************************************************************/
4045
dxaccAccountGetQuoteTZ(const Account *acc)
4047
if (!acc) return NULL;
4049
if (xaccAccountIsPriced(acc)) {
4050
KvpValue *value = kvp_frame_get_slot(acc->inst.kvp_data, "old-quote-tz");
4051
if(value) return (kvp_value_get_string(value));
4056
/********************************************************************\
4057
\********************************************************************/
4060
xaccAccountSetReconcileChildrenStatus(Account *acc, gboolean status)
4064
xaccAccountBeginEdit (acc);
4066
/* XXX FIXME: someday this should use KVP_TYPE_BOOLEAN */
4067
kvp_frame_set_gint64 (acc->inst.kvp_data,
4068
"/reconcile-info/include-children", status);
4070
xaccAccountCommitEdit (acc);
4073
/********************************************************************\
4074
\********************************************************************/
4077
xaccAccountGetReconcileChildrenStatus(const Account *acc)
4079
/* access the account's kvp-data for status and return that, if no value
4080
* is found then we can assume not to include the children, that being
4081
* the default behaviour
4083
return acc ? kvp_frame_get_gint64(acc->inst.kvp_data,
4084
"reconcile-info/include-children") : FALSE;
4087
/********************************************************************\
4088
\********************************************************************/
4090
/* The caller of this function can get back one or both of the
4091
* matching split and transaction pointers, depending on whether
4092
* a valid pointer to the location to store those pointers is
4096
finder_help_function(const Account *acc, const char *description,
4097
Split **split, Transaction **trans )
4099
AccountPrivate *priv;
4102
/* First, make sure we set the data to NULL BEFORE we start */
4103
if (split) *split = NULL;
4104
if (trans) *trans = NULL;
4106
/* Then see if we have any work to do */
4107
if (acc == NULL) return;
4109
/* Why is this loop iterated backwards ?? Presumably because the split
4110
* list is in date order, and the most recent matches should be
4112
priv = GET_PRIVATE(acc);
4113
for (slp = g_list_last(priv->splits); slp; slp = slp->prev) {
4114
Split *lsplit = slp->data;
4115
Transaction *ltrans = xaccSplitGetParent(lsplit);
4117
if (safe_strcmp (description, xaccTransGetDescription (ltrans)) == 0)
4119
if (split) *split = lsplit;
4120
if (trans) *trans = ltrans;
4127
xaccAccountFindSplitByDesc(const Account *acc, const char *description)
4131
/* Get the split which has a transaction matching the description. */
4132
finder_help_function(acc, description, &split, NULL);
4136
/* This routine is for finding a matching transaction in an account by
4137
* matching on the description field. [CAS: The rest of this comment
4138
* seems to belong somewhere else.] This routine is used for
4139
* auto-filling in registers with a default leading account. The
4140
* dest_trans is a transaction used for currency checking. */
4142
xaccAccountFindTransByDesc(const Account *acc, const char *description)
4146
/* Get the transation matching the description. */
4147
finder_help_function(acc, description, NULL, &trans);
4151
/* ================================================================ */
4152
/* Concatenation, Mergeing functions */
4155
gnc_account_join_children (Account *to_parent, Account *from_parent)
4157
AccountPrivate *from_priv;
4158
GList *children, *node;
4161
g_return_if_fail(GNC_IS_ACCOUNT(to_parent));
4162
g_return_if_fail(GNC_IS_ACCOUNT(from_parent));
4165
from_priv = GET_PRIVATE(from_parent);
4166
if (!from_priv->children)
4170
children = g_list_copy(from_priv->children);
4171
for (node = children; node; node = g_list_next(node))
4172
gnc_account_append_child(to_parent, node->data);
4173
g_list_free(children);
4178
gnc_account_copy_children (Account *to, Account *from)
4180
AccountPrivate *to_priv, *from_priv;
4185
g_return_if_fail(GNC_IS_ACCOUNT(to));
4186
g_return_if_fail(GNC_IS_ACCOUNT(from));
4189
to_priv = GET_PRIVATE(to);
4190
from_priv = GET_PRIVATE(from);
4191
if (!from_priv->children)
4194
to_book = gnc_account_get_book(to);
4195
if (!to_book) return;
4198
xaccAccountBeginEdit(to);
4199
xaccAccountBeginEdit(from);
4200
for (node = from_priv->children; node; node=node->next)
4202
Account *to_acc, *from_acc = node->data;
4204
/* This will copy the basic data and the KVP. It will
4205
* not copy any splits/transactions. It will gemini. */
4206
to_acc = xaccCloneAccount (from_acc, to_book);
4208
xaccAccountBeginEdit (to_acc);
4209
to_priv->children = g_list_append(to_priv->children, to_acc);
4211
GET_PRIVATE(to_acc)->parent = to;
4212
qof_instance_set_dirty(&to_acc->inst);
4214
/* Copy child accounts too. */
4215
if (GET_PRIVATE(from_acc)->children)
4217
gnc_account_copy_children(to_acc, from_acc);
4219
xaccAccountCommitEdit (to_acc);
4220
qof_event_gen (&to_acc->inst, QOF_EVENT_CREATE, NULL);
4221
/* DRH - Should this send ADD/REMOVE events */
4223
xaccAccountCommitEdit(from);
4224
xaccAccountCommitEdit(to);
4228
/********************************************************************\
4229
\********************************************************************/
4232
gnc_account_merge_children (Account *parent)
4234
AccountPrivate *ppriv, *priv_a, *priv_b;
4235
GList *node_a, *node_b, *work, *worker;
4237
g_return_if_fail(GNC_IS_ACCOUNT(parent));
4239
ppriv = GET_PRIVATE(parent);
4240
for (node_a = ppriv->children; node_a; node_a = node_a->next)
4242
Account *acc_a = node_a->data;
4244
priv_a = GET_PRIVATE(acc_a);
4245
for (node_b = node_a->next; node_b; node_b = g_list_next(node_b))
4247
Account *acc_b = node_b->data;
4249
priv_b = GET_PRIVATE(acc_b);
4250
if (0 != safe_strcmp(priv_a->accountName, priv_b->accountName))
4252
if (0 != safe_strcmp(priv_a->accountCode, priv_b->accountCode))
4254
if (0 != safe_strcmp(priv_a->description, priv_b->description))
4256
if (!gnc_commodity_equiv(priv_a->commodity, priv_b->commodity))
4258
if (0 != safe_strcmp(xaccAccountGetNotes(acc_a),
4259
xaccAccountGetNotes(acc_b)))
4261
if (priv_a->type != priv_b->type)
4264
/* consolidate children */
4265
if (priv_b->children) {
4266
work = g_list_copy(priv_b->children);
4267
for (worker = work; worker; worker = g_list_next(worker))
4268
gnc_account_append_child (acc_a, (Account *)worker->data);
4271
qof_event_gen (&acc_a->inst, QOF_EVENT_MODIFY, NULL);
4272
qof_event_gen (&acc_b->inst, QOF_EVENT_MODIFY, NULL);
4275
/* recurse to do the children's children */
4276
gnc_account_merge_children (acc_a);
4278
/* consolidate transactions */
4279
while (priv_b->splits)
4280
xaccSplitSetAccount (priv_b->splits->data, acc_a);
4282
/* move back one before removal. next iteration around the loop
4283
* will get the node after node_b */
4284
node_b = g_list_previous(node_b);
4286
/* The destroy function will remove from list -- node_a is ok,
4287
* it's before node_b */
4288
xaccAccountBeginEdit (acc_b);
4289
xaccAccountDestroy (acc_b);
4294
/* ================================================================ */
4295
/* Transaction Traversal functions */
4299
xaccSplitsBeginStagedTransactionTraversals (GList *splits)
4303
for (lp = splits; lp; lp = lp->next)
4305
Split *s = lp->data;
4306
Transaction *trans = s->parent;
4313
/* original function */
4315
xaccAccountBeginStagedTransactionTraversals (const Account *account)
4317
AccountPrivate *priv;
4321
priv = GET_PRIVATE(account);
4322
xaccSplitsBeginStagedTransactionTraversals(priv->splits);
4326
xaccTransactionTraverse (Transaction *trans, int stage)
4328
if (trans == NULL) return FALSE;
4330
if (trans->marker < stage)
4332
trans->marker = stage;
4340
xaccSplitTransactionTraverse (Split *split, int stage)
4342
if (split == NULL) return FALSE;
4344
return xaccTransactionTraverse (split->parent, stage);
4347
static void do_one_split (Split *s, gpointer data)
4349
Transaction *trans = s->parent;
4353
static void do_one_account (Account *account, gpointer data)
4355
AccountPrivate *priv = GET_PRIVATE(account);
4356
g_list_foreach(priv->splits, (GFunc)do_one_split, NULL);
4359
/* Replacement for xaccGroupBeginStagedTransactionTraversals */
4361
gnc_account_tree_begin_staged_transaction_traversals (Account *account)
4365
descendants = gnc_account_get_descendants(account);
4366
g_list_foreach(descendants, (GFunc)do_one_account, NULL);
4367
g_list_free(descendants);
4371
xaccAccountStagedTransactionTraversal (const Account *acc,
4373
TransactionCallback thunk,
4376
AccountPrivate *priv;
4384
priv = GET_PRIVATE(acc);
4385
for(split_p = priv->splits; split_p; split_p = g_list_next(split_p)) {
4388
if (trans && (trans->marker < stage)) {
4389
trans->marker = stage;
4391
retval = thunk(trans, cb_data);
4392
if (retval) return retval;
4401
gnc_account_tree_staged_transaction_traversal (const Account *acc,
4403
TransactionCallback thunk,
4406
const AccountPrivate *priv;
4407
GList *acc_p, *split_p;
4414
/* depth first traversal */
4415
priv = GET_PRIVATE(acc);
4416
for (acc_p = priv->children; acc_p; acc_p = g_list_next(acc_p)) {
4417
retval = gnc_account_tree_staged_transaction_traversal(acc_p->data, stage,
4419
if (retval) return retval;
4422
/* Now this account */
4423
for(split_p = priv->splits; split_p; split_p = g_list_next(split_p)) {
4426
if (trans && (trans->marker < stage)) {
4427
trans->marker = stage;
4429
retval = thunk(trans, cb_data);
4430
if (retval) return retval;
4438
/********************************************************************\
4439
\********************************************************************/
4442
xaccAccountTreeForEachTransaction (Account *acc,
4443
int (*proc)(Transaction *t, void *data),
4446
if (!acc || !proc) return 0;
4448
gnc_account_tree_begin_staged_transaction_traversals (acc);
4449
return gnc_account_tree_staged_transaction_traversal (acc, 42, proc, data);
4454
xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
4457
if (!acc || !proc) return 0;
4458
xaccAccountBeginStagedTransactionTraversals (acc);
4459
return xaccAccountStagedTransactionTraversal(acc, 42, proc, data);
4462
/* ================================================================ */
4463
/* QofObject function implementation and registration */
4465
static QofObject account_object_def = {
4466
interface_version: QOF_OBJECT_VERSION,
4467
e_type: GNC_ID_ACCOUNT,
4468
type_label: "Account",
4469
create: (gpointer)xaccMallocAccount,
4472
is_dirty: qof_collection_is_dirty,
4473
mark_clean: qof_collection_mark_clean,
4474
foreach: qof_collection_foreach,
4475
printable: (const char* (*)(gpointer)) xaccAccountGetName,
4476
version_cmp: (int (*)(gpointer,gpointer)) qof_instance_version_cmp,
4479
gboolean xaccAccountRegister (void)
4481
static QofParam params[] = {
4482
{ ACCOUNT_NAME_, QOF_TYPE_STRING,
4483
(QofAccessFunc) xaccAccountGetName,
4484
(QofSetterFunc) xaccAccountSetName },
4485
{ ACCOUNT_CODE_, QOF_TYPE_STRING,
4486
(QofAccessFunc) xaccAccountGetCode,
4487
(QofSetterFunc) xaccAccountSetCode },
4488
{ ACCOUNT_DESCRIPTION_, QOF_TYPE_STRING,
4489
(QofAccessFunc) xaccAccountGetDescription,
4490
(QofSetterFunc) xaccAccountSetDescription },
4491
{ ACCOUNT_NOTES_, QOF_TYPE_STRING,
4492
(QofAccessFunc) xaccAccountGetNotes,
4493
(QofSetterFunc) xaccAccountSetNotes },
4494
{ ACCOUNT_PRESENT_, QOF_TYPE_NUMERIC,
4495
(QofAccessFunc) xaccAccountGetPresentBalance, NULL },
4496
{ ACCOUNT_BALANCE_, QOF_TYPE_NUMERIC,
4497
(QofAccessFunc) xaccAccountGetBalance, NULL },
4498
{ ACCOUNT_CLEARED_, QOF_TYPE_NUMERIC,
4499
(QofAccessFunc) xaccAccountGetClearedBalance, NULL },
4500
{ ACCOUNT_RECONCILED_, QOF_TYPE_NUMERIC,
4501
(QofAccessFunc) xaccAccountGetReconciledBalance, NULL },
4502
{ ACCOUNT_TYPE_, QOF_TYPE_STRING,
4503
(QofAccessFunc) qofAccountGetTypeString,
4504
(QofSetterFunc) qofAccountSetType },
4505
{ ACCOUNT_FUTURE_MINIMUM_, QOF_TYPE_NUMERIC,
4506
(QofAccessFunc) xaccAccountGetProjectedMinimumBalance, NULL },
4507
{ ACCOUNT_TAX_RELATED, QOF_TYPE_BOOLEAN,
4508
(QofAccessFunc) xaccAccountGetTaxRelated,
4509
(QofSetterFunc) xaccAccountSetTaxRelated },
4510
{ ACCOUNT_SCU, QOF_TYPE_INT32,
4511
(QofAccessFunc) xaccAccountGetCommoditySCU,
4512
(QofSetterFunc) xaccAccountSetCommoditySCU },
4513
{ ACCOUNT_NSCU, QOF_TYPE_BOOLEAN,
4514
(QofAccessFunc) xaccAccountGetNonStdSCU,
4515
(QofSetterFunc) xaccAccountSetNonStdSCU },
4516
{ ACCOUNT_PARENT, GNC_ID_ACCOUNT,
4517
(QofAccessFunc) gnc_account_get_parent,
4518
(QofSetterFunc) qofAccountSetParent },
4519
{ QOF_PARAM_BOOK, QOF_ID_BOOK,
4520
(QofAccessFunc) qof_instance_get_book, NULL },
4521
{ QOF_PARAM_GUID, QOF_TYPE_GUID,
4522
(QofAccessFunc) qof_instance_get_guid, NULL },
4523
{ ACCOUNT_KVP, QOF_TYPE_KVP,
4524
(QofAccessFunc) qof_instance_get_slots, NULL },
4528
qof_class_register (GNC_ID_ACCOUNT, (QofSortFunc) qof_xaccAccountOrder, params);
4530
return qof_object_register (&account_object_def);
4533
/* ======================= END OF FILE =========================== */
4537
// indent-tabs-mode: nil
4538
// c-block-comment-prefix: "* "
4539
// eval: (c-add-style "gnc" '("k&r" (c-basic-offset . 4) (c-offsets-alist (case-label . +))) t)