Move more account properties from the public data structure to a

private data structure, with access to them as properties of the
object.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@15921 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
David Hampton 2007-04-18 04:50:34 +00:00
parent 3c9babbcf2
commit c6a609b8f7
11 changed files with 722 additions and 221 deletions

View File

@ -451,6 +451,7 @@ gnc_numeric gnc_numeric_reduce(gnc_numeric in);
@{
*/
GType gnc_numeric_get_type( void );
#define GNC_NUMERIC (gnc_numeric_get_type ())
/** @} */

View File

@ -496,7 +496,11 @@ pgendAccountGetBalance (PGBackend *be, Account *acc, Timespec as_of_date)
cleared_baln = gnc_numeric_create (cl_b, deno);
reconciled_baln = gnc_numeric_create (rec_b, deno);
xaccAccountSetStartingBalance (acc, baln, cleared_baln, reconciled_baln);
g_object_set(acc,
"start-balance", &baln,
"start-cleared-balance", &cleared_baln,
"start-reconcoled-balance", &reconciled_baln,
NULL);
{
char buf[80];

View File

@ -128,27 +128,28 @@ typedef struct AccountPrivate
Account *parent; /* back-pointer to parent */
GList *children; /* list of sub-accounts */
// /* protected data, cached parameters */
// gnc_numeric starting_balance;
// gnc_numeric starting_cleared_balance;
// gnc_numeric starting_reconciled_balance;
//
// gnc_numeric balance;
// gnc_numeric cleared_balance;
// gnc_numeric reconciled_balance;
/* protected data - should only be set by backends */
gnc_numeric starting_balance;
gnc_numeric starting_cleared_balance;
gnc_numeric starting_reconciled_balance;
/* cached parameters */
gnc_numeric balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
gboolean balance_dirty; /* balances in splits incorrect */
/* version number, used for tracking multiuser updates */
gint32 version;
guint32 version_check; /* data aging timestamp */
// SplitList *splits; /* list of split pointers */
GList *splits; /* list of split pointers */
gboolean sort_dirty; /* sort order of splits is bad */
LotList *lots; /* list of lot pointers */
GNCPolicy *policy; /* Cached pointer to policy method */
// gboolean balance_dirty; /* balances in splits incorrect */
// gboolean sort_dirty; /* sort order of splits is bad */
/* The "mark" flag can be used by the user to mark this account
* in any way desired. Handy for specialty traversals of the
* account tree. */
@ -246,17 +247,17 @@ gnc_account_init(Account* acc)
// priv->commodity = NULL;
// priv->commodity_scu = 0;
// priv->non_standard_scu = FALSE;
//
// priv->balance = gnc_numeric_zero();
// priv->cleared_balance = gnc_numeric_zero();
// priv->reconciled_balance = gnc_numeric_zero();
//
// priv->starting_balance = gnc_numeric_zero();
// priv->starting_cleared_balance = gnc_numeric_zero();
// priv->starting_reconciled_balance = gnc_numeric_zero();
//
// priv->balance_dirty = FALSE;
// priv->sort_dirty = FALSE;
priv->balance = gnc_numeric_zero();
priv->cleared_balance = gnc_numeric_zero();
priv->reconciled_balance = gnc_numeric_zero();
priv->starting_balance = gnc_numeric_zero();
priv->starting_cleared_balance = gnc_numeric_zero();
priv->starting_reconciled_balance = gnc_numeric_zero();
priv->balance_dirty = FALSE;
priv->splits = NULL;
priv->sort_dirty = FALSE;
}
static void
@ -304,6 +305,30 @@ gnc_account_get_property (GObject *object,
// NEED TO BE CONVERTED TO A G_TYPE_ENUM
g_value_set_int(value, priv->type);
break;
case PROP_SORT_DIRTY:
g_value_set_boolean(value, priv->sort_dirty);
break;
case PROP_BALANCE_DIRTY:
g_value_set_boolean(value, priv->balance_dirty);
break;
case PROP_START_BALANCE:
g_value_set_boxed(value, &priv->starting_balance);
break;
case PROP_START_CLEARED_BALANCE:
g_value_set_boxed(value, &priv->starting_cleared_balance);
break;
case PROP_START_RECONCILED_BALANCE:
g_value_set_boxed(value, &priv->starting_reconciled_balance);
break;
case PROP_END_BALANCE:
g_value_set_boxed(value, &priv->balance);
break;
case PROP_END_CLEARED_BALANCE:
g_value_set_boxed(value, &priv->cleared_balance);
break;
case PROP_END_RECONCILED_BALANCE:
g_value_set_boxed(value, &priv->reconciled_balance);
break;
case PROP_ACCT_VERSION:
g_value_set_int(value, priv->version);
break;
@ -363,6 +388,24 @@ gnc_account_set_property (GObject *object,
// NEED TO BE CONVERTED TO A G_TYPE_ENUM
xaccAccountSetType(account, g_value_get_int(value));
break;
case PROP_SORT_DIRTY:
gnc_account_set_sort_dirty(account);
break;
case PROP_BALANCE_DIRTY:
gnc_account_set_balance_dirty(account);
break;
case PROP_START_BALANCE:
number = g_value_get_boxed(value);
gnc_account_set_start_balance(account, *number);
break;
case PROP_START_CLEARED_BALANCE:
number = g_value_get_boxed(value);
gnc_account_set_start_cleared_balance(account, *number);
break;
case PROP_START_RECONCILED_BALANCE:
number = g_value_get_boxed(value);
gnc_account_set_start_reconciled_balance(account, *number);
break;
case PROP_ACCT_VERSION:
xaccAccountSetVersion(account, g_value_get_int(value));
break;
@ -478,6 +521,120 @@ gnc_account_class_init (AccountClass *klass)
ACCT_TYPE_BANK,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_BALANCE_DIRTY,
g_param_spec_boolean("sort-dirty",
"Sort Dirty",
"TRUE if the splits in the account needs to be "
"resorted. This flag is set by the accounts "
"code for certain internal modifications, or "
"when external code calls the engine to say a "
"split has been modified in a way that may "
"affect the sort order of the account. Note: "
"This value can only be set to TRUE.",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_BALANCE_DIRTY,
g_param_spec_boolean("balance-dirty",
"Balance Dirty",
"TRUE if the running balances in the account "
"needs to be recalculated. This flag is set "
"by the accounts code for certain internal "
"modifications, or when external code calls "
"the engine to say a split has been modified. "
"Note: This value can only be set to TRUE.",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_START_BALANCE,
g_param_spec_boxed("start-balance",
"Starting Balance",
"The starting balance for the account. This "
"parameter is intended for use with backends that "
"do not return the complete list of splits for an "
"account, but rather return a partial list. In "
"such a case, the backend will typically return "
"all of the splits after some certain date, and "
"the 'starting balance' will represent the "
"summation of the splits up to that date.",
GNC_NUMERIC,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_START_CLEARED_BALANCE,
g_param_spec_boxed("start-cleared-balance",
"Starting Cleared Balance",
"The starting cleared balance for the account. "
"This parameter is intended for use with backends "
"that do not return the complete list of splits "
"for an account, but rather return a partial "
"list. In such a case, the backend will "
"typically return all of the splits after "
"some certain date, and the 'starting cleared "
"balance' will represent the summation of the "
"splits up to that date.",
GNC_NUMERIC,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_START_RECONCILED_BALANCE,
g_param_spec_boxed("start-reconciled-balance",
"Starting Reconciled Balance",
"The starting reconciled balance for the "
"account. This parameter is intended for use "
"with backends that do not return the complete "
"list of splits for an account, but rather return "
"a partial list. In such a case, the backend "
"will typically return all of the splits after "
"some certain date, and the 'starting recontiled "
"balance' will represent the summation of the "
"splits up to that date.",
GNC_NUMERIC,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_END_BALANCE,
g_param_spec_boxed("end-balance",
"Ending Account Balance",
"This is the current ending balance for the "
"account. It is computed from the sum of the "
"starting balance and all splits in the account.",
GNC_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_END_CLEARED_BALANCE,
g_param_spec_boxed("end-cleared-balance",
"Ending Account Cleared Balance",
"This is the current ending cleared balance for "
"the account. It is computed from the sum of the "
"starting balance and all cleared splits in the "
"account.",
GNC_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_END_RECONCILED_BALANCE,
g_param_spec_boxed("end-reconciled-balance",
"Ending Account Reconciled Balance",
"This is the current ending reconciled balance "
"for the account. It is computed from the sum of "
"the starting balance and all reconciled splits "
"in the account.",
GNC_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_ACCT_VERSION,
@ -557,25 +714,12 @@ xaccInitAccount (Account * acc, QofBook *book)
ENTER ("book=%p\n", book);
qof_instance_init_data (&acc->inst, GNC_ID_ACCOUNT, book);
acc->balance = gnc_numeric_zero();
acc->cleared_balance = gnc_numeric_zero();
acc->reconciled_balance = gnc_numeric_zero();
acc->starting_balance = gnc_numeric_zero();
acc->starting_cleared_balance = gnc_numeric_zero();
acc->starting_reconciled_balance = gnc_numeric_zero();
acc->idata = 0;
acc->commodity = NULL;
acc->commodity_scu = 0;
acc->non_standard_scu = FALSE;
acc->splits = NULL;
acc->balance_dirty = FALSE;
acc->sort_dirty = FALSE;
LEAVE ("account=%p\n", acc);
}
@ -818,7 +962,7 @@ xaccFreeAccount (Account *acc)
/* NB there shouldn't be any splits by now ... they should
* have been all been freed by CommitEdit(). We can remove this
* check once we know the warning isn't occurring any more. */
if (acc->splits)
if (priv->splits)
{
GList *slist;
PERR (" instead of calling xaccFreeAccount(), please call \n"
@ -826,14 +970,14 @@ xaccFreeAccount (Account *acc)
acc->inst.editlevel = 0;
slist = g_list_copy(acc->splits);
slist = g_list_copy(priv->splits);
for (lp = slist; lp; lp = lp->next) {
Split *s = (Split *) lp->data;
g_assert(xaccSplitGetAccount(s) == acc);
xaccSplitDestroy (s);
}
g_list_free(slist);
g_assert(acc->splits == NULL);
g_assert(priv->splits == NULL);
}
CACHE_REPLACE(priv->accountName, NULL);
@ -847,16 +991,16 @@ xaccFreeAccount (Account *acc)
priv->parent = NULL;
priv->children = NULL;
acc->balance = gnc_numeric_zero();
acc->cleared_balance = gnc_numeric_zero();
acc->reconciled_balance = gnc_numeric_zero();
priv->balance = gnc_numeric_zero();
priv->cleared_balance = gnc_numeric_zero();
priv->reconciled_balance = gnc_numeric_zero();
priv->type = ACCT_TYPE_NONE;
acc->commodity = NULL;
priv->version = 0;
acc->balance_dirty = FALSE;
acc->sort_dirty = FALSE;
priv->balance_dirty = FALSE;
priv->sort_dirty = FALSE;
/* qof_instance_release (&acc->inst); */
g_object_unref(acc);
@ -930,7 +1074,7 @@ xaccAccountCommitEdit (Account *acc)
PINFO ("freeing splits for account %p (%s)",
acc, priv->accountName ? priv->accountName : "(null)");
slist = g_list_copy(acc->splits);
slist = g_list_copy(priv->splits);
for (lp = slist; lp; lp = lp->next)
{
Split *s = lp->data;
@ -942,7 +1086,7 @@ xaccAccountCommitEdit (Account *acc)
deleting all the splits in it. The splits will just get
recreated and put right back into the same account!
g_assert(acc->splits == NULL || qof_book_shutting_down(acc->inst.book));
g_assert(priv->splits == NULL || qof_book_shutting_down(acc->inst.book));
*/
if (!qof_book_shutting_down(acc->inst.book)) {
@ -1143,13 +1287,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal (aa->starting_balance, ab->starting_balance))
if (!gnc_numeric_equal(priv_aa->starting_balance, priv_ab->starting_balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string (aa->starting_balance);
str_b = gnc_numeric_to_string (ab->starting_balance);
str_a = gnc_numeric_to_string(priv_aa->starting_balance);
str_b = gnc_numeric_to_string(priv_ab->starting_balance);
PWARN ("starting balances differ: %s vs %s", str_a, str_b);
@ -1159,14 +1303,14 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal (aa->starting_cleared_balance,
ab->starting_cleared_balance))
if (!gnc_numeric_equal(priv_aa->starting_cleared_balance,
priv_ab->starting_cleared_balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string (aa->starting_cleared_balance);
str_b = gnc_numeric_to_string (ab->starting_cleared_balance);
str_a = gnc_numeric_to_string(priv_aa->starting_cleared_balance);
str_b = gnc_numeric_to_string(priv_ab->starting_cleared_balance);
PWARN ("starting cleared balances differ: %s vs %s", str_a, str_b);
@ -1176,14 +1320,14 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal (aa->starting_reconciled_balance,
ab->starting_reconciled_balance))
if (!gnc_numeric_equal(priv_aa->starting_reconciled_balance,
priv_ab->starting_reconciled_balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string (aa->starting_reconciled_balance);
str_b = gnc_numeric_to_string (ab->starting_reconciled_balance);
str_a = gnc_numeric_to_string(priv_aa->starting_reconciled_balance);
str_b = gnc_numeric_to_string(priv_ab->starting_reconciled_balance);
PWARN ("starting reconciled balances differ: %s vs %s", str_a, str_b);
@ -1193,13 +1337,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal (aa->balance, ab->balance))
if (!gnc_numeric_equal(priv_aa->balance, priv_ab->balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string (aa->balance);
str_b = gnc_numeric_to_string (ab->balance);
str_a = gnc_numeric_to_string(priv_aa->balance);
str_b = gnc_numeric_to_string(priv_ab->balance);
PWARN ("balances differ: %s vs %s", str_a, str_b);
@ -1209,13 +1353,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal (aa->cleared_balance, ab->cleared_balance))
if (!gnc_numeric_equal(priv_aa->cleared_balance, priv_ab->cleared_balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string (aa->cleared_balance);
str_b = gnc_numeric_to_string (ab->cleared_balance);
str_a = gnc_numeric_to_string(priv_aa->cleared_balance);
str_b = gnc_numeric_to_string(priv_ab->cleared_balance);
PWARN ("cleared balances differ: %s vs %s", str_a, str_b);
@ -1225,13 +1369,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE;
}
if (!gnc_numeric_equal (aa->reconciled_balance, ab->reconciled_balance))
if (!gnc_numeric_equal(priv_aa->reconciled_balance, priv_ab->reconciled_balance))
{
char *str_a;
char *str_b;
str_a = gnc_numeric_to_string (aa->reconciled_balance);
str_b = gnc_numeric_to_string (ab->reconciled_balance);
str_a = gnc_numeric_to_string(priv_aa->reconciled_balance);
str_b = gnc_numeric_to_string(priv_ab->reconciled_balance);
PWARN ("reconciled balances differ: %s vs %s", str_a, str_b);
@ -1244,8 +1388,8 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
/* no parent; always compare downwards. */
{
GList *la = aa->splits;
GList *lb = ab->splits;
GList *la = priv_aa->splits;
GList *lb = priv_ab->splits;
if ((la && !lb) || (!la && lb))
{
@ -1290,14 +1434,137 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
/********************************************************************\
\********************************************************************/
gboolean
gnc_account_get_sort_dirty (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
return GET_PRIVATE(acc)->sort_dirty;
}
void
gnc_account_set_sort_dirty (Account *acc)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
if (acc->inst.do_free)
return;
priv = GET_PRIVATE(acc);
priv->sort_dirty = TRUE;
}
gboolean
gnc_account_get_balance_dirty (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
return GET_PRIVATE(acc)->balance_dirty;
}
void
gnc_account_set_balance_dirty (Account *acc)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
if (acc->inst.do_free)
return;
priv = GET_PRIVATE(acc);
priv->balance_dirty = TRUE;
}
/********************************************************************\
\********************************************************************/
gboolean
gnc_account_find_split (Account *acc, Split *s)
{
AccountPrivate *priv;
GList *node;
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
priv = GET_PRIVATE(acc);
node = g_list_find(priv->splits, s);
return node ? TRUE : FALSE;
}
gboolean
gnc_account_insert_split (Account *acc, Split *s)
{
AccountPrivate *priv;
GList *node;
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
priv = GET_PRIVATE(acc);
node = g_list_find(priv->splits, s);
if (node)
return FALSE;
if (acc->inst.editlevel == 0) {
priv->splits = g_list_insert_sorted(priv->splits, s,
(GCompareFunc)xaccSplitOrder);
} else {
priv->splits = g_list_prepend(priv->splits, s);
priv->sort_dirty = TRUE;
}
//FIXME: find better event
qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL);
/* Also send an event based on the account */
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_ADDED, s);
priv->balance_dirty = TRUE;
// DRH: Should the below be added? It is present in the delete path.
// xaccAccountRecomputeBalance(acc);
return TRUE;
}
gboolean
gnc_account_remove_split (Account *acc, Split *s)
{
AccountPrivate *priv;
GList *node;
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
priv = GET_PRIVATE(acc);
node = g_list_find(priv->splits, s);
if (NULL == node)
return FALSE;
priv->splits = g_list_delete_link(priv->splits, node);
//FIXME: find better event type
qof_event_gen(&acc->inst, QOF_EVENT_MODIFY, NULL);
// And send the account-based event, too
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_REMOVED, s);
priv->balance_dirty = TRUE;
xaccAccountRecomputeBalance(acc);
return TRUE;
}
void
xaccAccountSortSplits (Account *acc, gboolean force)
{
if (!acc || !acc->sort_dirty || (!force && acc->inst.editlevel > 0)) return;
AccountPrivate *priv;
acc->splits = g_list_sort(acc->splits, (GCompareFunc)xaccSplitOrder);
acc->sort_dirty = FALSE;
acc->balance_dirty = TRUE;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
priv = GET_PRIVATE(acc);
if (!priv->sort_dirty || (!force && acc->inst.editlevel > 0))
return;
priv->splits = g_list_sort(priv->splits, (GCompareFunc)xaccSplitOrder);
priv->sort_dirty = FALSE;
priv->balance_dirty = TRUE;
}
static void
@ -1494,7 +1761,7 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
/* optimizations */
from_priv = GET_PRIVATE(accfrom);
to_priv = GET_PRIVATE(accto);
if (!accfrom->splits || accfrom == accto)
if (!from_priv->splits || accfrom == accto)
return;
/* check for book mix-up */
@ -1504,27 +1771,27 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
xaccAccountBeginEdit(accfrom);
xaccAccountBeginEdit(accto);
/* Begin editing both accounts and all transactions in accfrom. */
g_list_foreach(accfrom->splits, (GFunc)xaccPreSplitMove, NULL);
g_list_foreach(from_priv->splits, (GFunc)xaccPreSplitMove, NULL);
/* Concatenate accfrom's lists of splits and lots to accto's lists. */
//accto->splits = g_list_concat(accto->splits, accfrom->splits);
//to_priv->splits = g_list_concat(to_priv->splits, from_priv->splits);
//to_priv->lots = g_list_concat(to_priv->lots, from_priv->lots);
/* Set appropriate flags. */
//accfrom->balance_dirty = TRUE;
//accfrom->sort_dirty = FALSE;
//accto->balance_dirty = TRUE;
//accto->sort_dirty = TRUE;
//from_priv->balance_dirty = TRUE;
//from_priv->sort_dirty = FALSE;
//to_priv->balance_dirty = TRUE;
//to_priv->sort_dirty = TRUE;
/*
* Change each split's account back pointer to accto.
* Convert each split's amount to accto's commodity.
* Commit to editing each transaction.
*/
g_list_foreach(accfrom->splits, (GFunc)xaccPostSplitMove, (gpointer)accto);
g_list_foreach(from_priv->splits, (GFunc)xaccPostSplitMove, (gpointer)accto);
/* Finally empty accfrom. */
g_assert(accfrom->splits == NULL);
g_assert(from_priv->splits == NULL);
g_assert(from_priv->lots == NULL);
xaccAccountCommitEdit(accfrom);
xaccAccountCommitEdit(accto);
@ -1575,17 +1842,17 @@ xaccAccountRecomputeBalance (Account * acc)
priv = GET_PRIVATE(acc);
if (acc->inst.editlevel > 0) return;
if (!acc->balance_dirty) return;
if (!priv->balance_dirty) return;
if (acc->inst.do_free) return;
if (qof_book_shutting_down(acc->inst.book)) return;
balance = acc->starting_balance;
cleared_balance = acc->starting_cleared_balance;
reconciled_balance = acc->starting_reconciled_balance;
balance = priv->starting_balance;
cleared_balance = priv->starting_cleared_balance;
reconciled_balance = priv->starting_reconciled_balance;
PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
priv->accountName, balance.num, balance.denom);
for(lp = acc->splits; lp; lp = lp->next)
for(lp = priv->splits; lp; lp = lp->next)
{
Split *split = (Split *) lp->data;
gnc_numeric amt = xaccSplitGetAmount (split);
@ -1611,30 +1878,10 @@ xaccAccountRecomputeBalance (Account * acc)
last_split = split;
}
acc->balance = balance;
acc->cleared_balance = cleared_balance;
acc->reconciled_balance = reconciled_balance;
acc->balance_dirty = FALSE;
}
/********************************************************************\
\********************************************************************/
void
xaccAccountSetStartingBalance(Account *acc,
const gnc_numeric start_baln,
const gnc_numeric start_cleared_baln,
const gnc_numeric start_reconciled_baln)
{
if (!acc) return;
acc->starting_balance = start_baln;
acc->starting_cleared_balance = start_cleared_baln;
acc->starting_reconciled_balance = start_reconciled_baln;
acc->balance_dirty = TRUE;
priv->balance = balance;
priv->cleared_balance = cleared_balance;
priv->reconciled_balance = reconciled_balance;
priv->balance_dirty = FALSE;
}
/********************************************************************\
@ -1741,7 +1988,7 @@ xaccAccountSetType (Account *acc, GNCAccountType tip)
xaccAccountBeginEdit(acc);
priv->type = tip;
acc->balance_dirty = TRUE; /* new type may affect balance computation */
priv->balance_dirty = TRUE; /* new type may affect balance computation */
mark_account(acc);
xaccAccountCommitEdit(acc);
}
@ -1841,9 +2088,11 @@ xaccAccountSetNotes (Account *acc, const char *str)
void
xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
{
AccountPrivate *priv;
GList *lp;
if (!acc || !com || com == acc->commodity) return;
priv = GET_PRIVATE(acc);
xaccAccountBeginEdit(acc);
acc->commodity = com;
@ -1851,7 +2100,7 @@ xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
acc->non_standard_scu = FALSE;
/* iterate over splits */
for (lp = acc->splits; lp; lp = lp->next)
for (lp = priv->splits; lp; lp = lp->next)
{
Split *s = (Split *) lp->data;
Transaction *trans = xaccSplitGetParent (s);
@ -1861,8 +2110,8 @@ xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
xaccTransCommitEdit (trans);
}
acc->sort_dirty = TRUE; /* Not needed. */
acc->balance_dirty = TRUE;
priv->sort_dirty = TRUE; /* Not needed. */
priv->balance_dirty = TRUE;
mark_account (acc);
if (gnc_commodity_is_iso(com)) {
@ -2531,27 +2780,96 @@ xaccAccountGetCommodity (const Account *acc)
return acc ? acc->commodity : NULL;
}
/********************************************************************\
\********************************************************************/
gnc_numeric
gnc_account_get_start_balance (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->starting_balance;
}
void
gnc_account_set_start_balance (Account *acc, const gnc_numeric start_baln)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
priv = GET_PRIVATE(acc);
priv->starting_balance = start_baln;
priv->balance_dirty = TRUE;
}
gnc_numeric
gnc_account_get_start_cleared_balance (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->starting_cleared_balance;
}
void
gnc_account_set_start_cleared_balance (Account *acc,
const gnc_numeric start_baln)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
priv = GET_PRIVATE(acc);
priv->starting_balance = start_baln;
priv->balance_dirty = TRUE;
}
gnc_numeric
gnc_account_get_start_reconciled_balance (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->starting_reconciled_balance;
}
void
gnc_account_set_start_reconciled_balance (Account *acc,
const gnc_numeric start_baln)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
priv = GET_PRIVATE(acc);
priv->starting_balance = start_baln;
priv->balance_dirty = TRUE;
}
gnc_numeric
xaccAccountGetBalance (const Account *acc)
{
return acc ? acc->balance : gnc_numeric_zero();
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->balance;
}
gnc_numeric
xaccAccountGetClearedBalance (const Account *acc)
{
return acc ? acc->cleared_balance : gnc_numeric_zero();
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->cleared_balance;
}
gnc_numeric
xaccAccountGetReconciledBalance (const Account *acc)
{
return acc ? acc->reconciled_balance : gnc_numeric_zero();
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->reconciled_balance;
}
gnc_numeric
xaccAccountGetProjectedMinimumBalance (const Account *acc)
{
AccountPrivate *priv;
GList *node;
time_t today;
gnc_numeric lowest = gnc_numeric_zero ();
@ -2559,8 +2877,9 @@ xaccAccountGetProjectedMinimumBalance (const Account *acc)
if (!acc) return gnc_numeric_zero ();
priv = GET_PRIVATE(acc);
today = gnc_timet_get_today_end();
for (node = g_list_last (acc->splits); node; node = node->prev)
for (node = g_list_last(priv->splits); node; node = node->prev)
{
Split *split = node->data;
@ -2592,6 +2911,7 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
* xaccAccountForEachTransaction by using gpointer return
* values rather than gints.
*/
AccountPrivate *priv;
GList *lp;
Timespec ts, trans_ts;
gboolean found = FALSE;
@ -2602,7 +2922,8 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
xaccAccountSortSplits (acc, TRUE); /* just in case, normally a noop */
xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */
balance = acc->balance;
priv = GET_PRIVATE(acc);
balance = priv->balance;
/* Since transaction post times are stored as a Timespec,
* convert date into a Timespec as well rather than converting
@ -2619,7 +2940,7 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
ts.tv_sec = date;
ts.tv_nsec = 0;
lp = acc->splits;
lp = priv->splits;
while( lp && !found )
{
xaccTransGetDatePostedTS( xaccSplitGetParent( (Split *)lp->data ),
@ -2661,13 +2982,15 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
gnc_numeric
xaccAccountGetPresentBalance (const Account *acc)
{
AccountPrivate *priv;
GList *node;
time_t today;
g_return_val_if_fail(acc, gnc_numeric_zero());
priv = GET_PRIVATE(acc);
today = gnc_timet_get_today_end();
for (node = g_list_last (acc->splits); node; node = node->prev)
for (node = g_list_last(priv->splits); node; node = node->prev)
{
Split *split = node->data;
@ -2961,11 +3284,20 @@ xaccAccountGetBalanceChangeForPeriod (Account *acc, time_t t1, time_t t2, gboole
/********************************************************************\
\********************************************************************/
/* THIS API NEEDS TO CHANGE.
*
* This code exposes the internal structure of the account object to
* external callers by returning the actual list used by the object.
* It should instead return a copy of the split list that the caller
* is required to free. That change would provide the freedom of
* allowing the internal organization to change data structures if
* necessary for whatever reason, while leaving the external API
* unchanged. */
SplitList *
xaccAccountGetSplitList (const Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
return acc->splits;
return GET_PRIVATE(acc)->splits;
}
LotList *
@ -3755,6 +4087,7 @@ static void
finder_help_function(const Account *acc, const char *description,
Split **split, Transaction **trans )
{
AccountPrivate *priv;
GList *slp;
/* First, make sure we set the data to NULL BEFORE we start */
@ -3767,7 +4100,8 @@ finder_help_function(const Account *acc, const char *description,
/* Why is this loop iterated backwards ?? Presumably because the split
* list is in date order, and the most recent matches should be
* returned!? */
for (slp = g_list_last (acc->splits); slp; slp = slp->prev) {
priv = GET_PRIVATE(acc);
for (slp = g_list_last(priv->splits); slp; slp = slp->prev) {
Split *lsplit = slp->data;
Transaction *ltrans = xaccSplitGetParent(lsplit);
@ -3933,8 +4267,8 @@ gnc_account_merge_children (Account *parent)
gnc_account_merge_children (acc_a);
/* consolidate transactions */
while (acc_b->splits)
xaccSplitSetAccount (acc_b->splits->data, acc_a);
while (priv_b->splits)
xaccSplitSetAccount (priv_b->splits->data, acc_a);
/* move back one before removal. next iteration around the loop
* will get the node after node_b */
@ -3971,8 +4305,12 @@ xaccSplitsBeginStagedTransactionTraversals (GList *splits)
void
xaccAccountBeginStagedTransactionTraversals (const Account *account)
{
if (account)
xaccSplitsBeginStagedTransactionTraversals (account->splits);
AccountPrivate *priv;
if (!account)
return;
priv = GET_PRIVATE(account);
xaccSplitsBeginStagedTransactionTraversals(priv->splits);
}
gboolean
@ -4005,7 +4343,8 @@ static void do_one_split (Split *s, gpointer data)
static void do_one_account (Account *account, gpointer data)
{
g_list_foreach(account->splits, (GFunc)do_one_split, NULL);
AccountPrivate *priv = GET_PRIVATE(account);
g_list_foreach(priv->splits, (GFunc)do_one_split, NULL);
}
/* Replacement for xaccGroupBeginStagedTransactionTraversals */
@ -4025,6 +4364,7 @@ xaccAccountStagedTransactionTraversal (const Account *acc,
TransactionCallback thunk,
void *cb_data)
{
AccountPrivate *priv;
GList *split_p;
Transaction *trans;
Split *s;
@ -4032,7 +4372,8 @@ xaccAccountStagedTransactionTraversal (const Account *acc,
if (!acc) return 0;
for(split_p = acc->splits; split_p; split_p = g_list_next(split_p)) {
priv = GET_PRIVATE(acc);
for(split_p = priv->splits; split_p; split_p = g_list_next(split_p)) {
s = split_p->data;
trans = s->parent;
if (trans && (trans->marker < stage)) {
@ -4070,7 +4411,7 @@ gnc_account_tree_staged_transaction_traversal (const Account *acc,
}
/* Now this account */
for(split_p = acc->splits; split_p; split_p = g_list_next(split_p)) {
for(split_p = priv->splits; split_p; split_p = g_list_next(split_p)) {
s = split_p->data;
trans = s->parent;
if (trans && (trans->marker < stage)) {

View File

@ -275,6 +275,80 @@ GNCAccountType xaccAccountGetType (const Account *account);
/** Is the account a stock, mutual fund or currency? */
gboolean xaccAccountIsPriced(const Account *acc);
/** This function will set the starting commodity balance for this
* account. This routine is intended for use with backends that do
* not return the complete list of splits for an account, but rather
* return a partial list. In such a case, the backend will typically
* return all of the splits after some certain date, and the
* 'starting balance' will represent the summation of the splits up
* to that date. */
void gnc_account_set_start_balance (Account *acc,
const gnc_numeric start_baln);
/** This function will set the starting cleared commodity balance for
* this account. This routine is intended for use with backends that
* do not return the complete list of splits for an account, but
* rather return a partial list. In such a case, the backend will
* typically return all of the splits after some certain date, and
* the 'starting balance' will represent the summation of the splits
* up to that date. */
void gnc_account_set_start_cleared_balance (Account *acc,
const gnc_numeric start_baln);
/** This function will set the starting reconciled commodity balance
* for this account. This routine is intended for use with backends
* that do not return the complete list of splits for an account, but
* rather return a partial list. In such a case, the backend will
* typically return all of the splits after some certain date, and
* the 'starting balance' will represent the summation of the splits
* up to that date. */
void gnc_account_set_start_reconciled_balance (Account *acc,
const gnc_numeric start_baln);
/** Tell the account that the running balances may be incorrect and
* need to be recomputed.
*
* @param acc Set the flag on this account. */
void gnc_account_set_balance_dirty (Account *acc);
/** Tell the account believes that the splits may be incorrectly
* sorted and need to be resorted.
*
* @param acc Set the flag on this account. */
void gnc_account_set_sort_dirty (Account *acc);
/** Find the given split in an account.
*
* @param acc The account whose splits are to be searched.
*
* @param s The split to be found.
*
* @result TRUE is the split is found in the accounts list of splits.
* FALSE otherwise. */
gboolean gnc_account_find_split (Account *acc, Split *s);
/** Insert the given split from an account.
*
* @param acc The account to which the split should be added.
*
* @param s The split to be added.
*
* @result TRUE is the split is successfully added to the set of
* splits in the account. FALSE if the addition fails for any reason
* (including that the split is already in the account). */
gboolean gnc_account_insert_split (Account *acc, Split *s);
/** Remove the given split from an account.
*
* @param acc The account from which the split should be removed.
*
* @param s The split to be removed.
*
* @result TRUE is the split is successfully removed from the set of
* splits in the account. FALSE if the removal fails for any
* reason. */
gboolean gnc_account_remove_split (Account *acc, Split *s);
/** Get the account's name */
const char * xaccAccountGetName (const Account *account);
/** Get the account's accounting code */
@ -292,6 +366,45 @@ GNCPolicy *gnc_account_get_policy (Account *account);
gint32 xaccAccountGetVersion (const Account* acc);
/** Get the account version_check number */
guint32 gnc_account_get_version_check (const Account *acc);
/** Retrieve the starting commodity balance for this account. */
gnc_numeric gnc_account_get_start_balance (Account *acc);
/** Retrieve the starting cleared commodity balance for this
* account. */
gnc_numeric gnc_account_get_start_cleared_balance (Account *acc);
/** Retrieve the starting reconciled commodity balance for this
* account. */
gnc_numeric gnc_account_get_start_reconciled_balance (Account *acc);
/** Get an indication of whether the account believes that the running
* balances may be incorrect and need to be recomputed.
*
* @param acc Retrieve the flag on this account.
*
* @return TRUE if the running account balances need to be recomputed.
* FALSE if they are correct. */
gboolean gnc_account_get_balance_dirty (Account *acc);
/** Get an indication of whether the account believes that the splits
* may be incorrectly sorted and need to be resorted.
*
* @param acc Retrieve the flag on this account.
*
* @return TRUE if the splits in the account need to be resorted.
* FALSE if the sort order is correct. */
gboolean gnc_account_get_sort_dirty (Account *acc);
/** The following recompute the partial balances (stored with the
* transaction) and the total balance, for this account
*/
void xaccAccountRecomputeBalance (Account *);
/** The xaccAccountSortSplits() routine will resort the account's
* splits if the sort is dirty. If 'force' is true, the account
* is sorted even if the editlevel is not zero.
*/
void xaccAccountSortSplits (Account *acc, gboolean force);
/** The xaccAccountGetFullName routine returns the fully qualified name
* of the account using the given separator char. The name must be
@ -864,7 +977,11 @@ guint32 xaccAccountTypesValid(void);
* data structure: do not delete it when done; treat it as a read-only
* structure. Note that some routines (such as xaccAccountRemoveSplit())
* modify this list directly, and could leave you with a corrupted
* pointer. */
* pointer.
* @note This should be changed so that the returned value is a copy
* of the list. No other part of the code should have access to the
* internal data structure used by this object.
*/
SplitList* xaccAccountGetSplitList (const Account *account);
/** The xaccAccountMoveAllSplits() routine reassigns each of the splits

View File

@ -65,58 +65,16 @@ struct account_s
int commodity_scu;
gboolean non_standard_scu;
/* protected data, cached parameters */
gnc_numeric starting_balance;
gnc_numeric starting_cleared_balance;
gnc_numeric starting_reconciled_balance;
gnc_numeric balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
SplitList *splits; /* list of split pointers */
gboolean balance_dirty; /* balances in splits incorrect */
gboolean sort_dirty; /* sort order of splits is bad */
/* -------------------------------------------------------------- */
/* Backend private expansion data */
guint32 idata; /* used by the sql backend for kvp management */
};
/* The xaccAccountSortSplits() routine will resort the account's
* splits if the sort is dirty. If 'force' is true, the account
* is sorted even if the editlevel is not zero.
*/
void xaccAccountSortSplits (Account *acc, gboolean force);
/* The following recompute the partial balances (stored with the
* transaction) and the total balance, for this account
*/
void xaccAccountRecomputeBalance (Account *);
/* Set the account's GUID. This should only be done when reading
* an account from a datafile, or some other external source. Never
* call this on an existing account! */
void xaccAccountSetGUID (Account *account, const GUID *guid);
/* The xaccAccountSetStartingBalance() routine will set the starting
* commodity balance for this account. This routine is intended for
* use with backends that do not return the complete list of splits
* for an account, but rather return a partial list. In such a case,
* the backend will typically return all of the splits after some
* certain date, and the 'starting balance' will represent the summation
* of the splits up to that date.
*
* This routine is in the private .h file because only backends are
* allowed to set the starting balance. This is *not* a user interface
* function.
*/
void xaccAccountSetStartingBalance(Account *account,
const gnc_numeric start_baln,
const gnc_numeric start_cleared_baln,
const gnc_numeric start_reconciled_baln);
/* Register Accounts with the engine */
gboolean xaccAccountRegister (void);

View File

@ -112,8 +112,7 @@ gnc_book_insert_trans_clobber (QofBook *book, Transaction *trans)
else
{
xaccAccountInsertSplit (twin, s);
twin->balance_dirty = TRUE;
twin->sort_dirty = TRUE;
g_object_set(twin, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
}
}
@ -179,8 +178,7 @@ gnc_book_insert_trans (QofBook *book, Transaction *trans)
if (s->acc != twin)
{
xaccAccountInsertSplit (twin, s);
twin->balance_dirty = TRUE;
twin->sort_dirty = TRUE;
g_object_set(twin, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
}
}
}

View File

@ -57,7 +57,7 @@ static QofLogModule log_module = GNC_MOD_LOT;
void
xaccAccountAssignLots (Account *acc)
{
SplitList *node;
SplitList *splits, *node;
if (!acc) return;
@ -65,7 +65,8 @@ xaccAccountAssignLots (Account *acc)
xaccAccountBeginEdit (acc);
restart_loop:
for (node=acc->splits; node; node=node->next)
splits = xaccAccountGetSplitList(acc);
for (node=splits; node; node=node->next)
{
Split * split = node->data;

View File

@ -296,17 +296,11 @@ xaccFreeSplit (Split *split)
g_object_unref(split);
}
static void mark_acc(Account *acc)
{
if (acc && !acc->inst.do_free) {
acc->balance_dirty = TRUE;
acc->sort_dirty = TRUE;
}
}
void mark_split (Split *s)
{
mark_acc(s->acc);
if (s->acc) {
g_object_set(s->acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
}
/* set dirty flag on lot too. */
if (s->lot) s->lot->is_closed = -1;
@ -526,41 +520,21 @@ xaccSplitCommitEdit(Split *s)
/* Possibly remove the split from the original account... */
if (orig_acc && (orig_acc != acc || s->inst.do_free)) {
GList *node = g_list_find (orig_acc->splits, s);
if (node) {
orig_acc->splits = g_list_delete_link (orig_acc->splits, node);
//FIXME: find better event type
qof_event_gen (&orig_acc->inst, QOF_EVENT_MODIFY, NULL);
// And send the account-based event, too
qof_event_gen(&orig_acc->inst, GNC_EVENT_ITEM_REMOVED, s);
} else PERR("Account lost track of moved or deleted split.");
orig_acc->balance_dirty = TRUE;
xaccAccountRecomputeBalance(orig_acc);
if (!gnc_account_remove_split(orig_acc, s)) {
PERR("Account lost track of moved or deleted split.");
}
}
/* ... and insert it into the new account if needed */
if (orig_acc != s->acc && !s->inst.do_free) {
if (!g_list_find(acc->splits, s)) {
if (acc->inst.editlevel == 0) {
acc->splits = g_list_insert_sorted(
acc->splits, s, (GCompareFunc)xaccSplitOrder);
} else {
acc->splits = g_list_prepend(acc->splits, s);
acc->sort_dirty = TRUE;
}
if (acc && (orig_acc != acc) && !s->inst.do_free) {
if (gnc_account_insert_split(acc, s)) {
/* If the split's lot belonged to some other account, we
leave it so. */
if (s->lot && (NULL == s->lot->account))
xaccAccountInsertLot (acc, s->lot);
//FIXME: find better event
qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL);
/* Also send an event based on the account */
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_ADDED, s);
} else PERR("Account grabbed split prematurely.");
acc->balance_dirty = TRUE;
} else {
PERR("Account grabbed split prematurely.");
}
xaccSplitSetAmount(s, xaccSplitGetAmount(s));
}
@ -585,8 +559,10 @@ xaccSplitCommitEdit(Split *s)
/* This is because Splits don't call qof_commit_edit(). */
qof_instance_set_dirty(QOF_INSTANCE(s->parent));
mark_acc(acc);
xaccAccountRecomputeBalance(acc);
if (acc) {
g_object_set(acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
xaccAccountRecomputeBalance(acc);
}
if (s->inst.do_free)
xaccFreeSplit(s);
}

View File

@ -79,7 +79,7 @@ gboolean
xaccAccountHasTrades (Account *acc)
{
gnc_commodity *acc_comm;
SplitList *node;
SplitList *splits, *node;
if (!acc) return FALSE;
@ -88,7 +88,8 @@ xaccAccountHasTrades (Account *acc)
acc_comm = acc->commodity;
for (node=acc->splits; node; node=node->next)
splits = xaccAccountGetSplitList(acc);
for (node=splits; node; node=node->next)
{
Split *s = node->data;
Transaction *t = s->parent;

View File

@ -31,6 +31,7 @@ TESTS = \
test-object \
test-commodities \
test-create-account \
test-account-object \
test-group-vs-book \
test-lots \
test-period \
@ -66,6 +67,7 @@ check_PROGRAMS = \
test-freq-spec \
test-recurrence \
test-guid \
test-account-object \
test-group-vs-book \
test-load-engine \
test-period \

View File

@ -0,0 +1,102 @@
/***************************************************************************
* test-account-object.c
*
* Copyright (C) 2007 David Hampton <hampton@employees.org>
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file test-account-object.c
* @brief Minimal test of reading/writing account parameters
* @author David Hampton <hampton@employees.org>
*/
#include "config.h"
#include <unistd.h>
#include <glib.h>
#include "qof.h"
#include "Account.h"
#include "cashobjects.h"
#include "test-stuff.h"
#include "test-engine-stuff.h"
static void
run_test (void)
{
QofSession *sess;
QofBook *book;
Account *acc;
gnc_numeric *start, *end, end2, delta, zero, five;
sess = get_random_session ();
book = qof_session_get_book (sess);
do_test ((NULL != book), "create random data");
acc = get_random_account(book);
/*****/
g_object_get(acc, "start-balance", &start, "end-balance", &end, NULL);
end2 = xaccAccountGetBalance(acc);
delta = gnc_numeric_sub(*end, *start, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
do_test (gnc_numeric_zero_p(*start), "start balance is zero");
do_test (gnc_numeric_zero_p(*end), "end balance is zero");
do_test (gnc_numeric_zero_p(delta), "delta is zero");
do_test (gnc_numeric_zero_p(end2), "end2 balance is zero");
/*****/
five = gnc_numeric_create(5, 1);
g_object_set(acc, "start-balance", &five, NULL);
xaccAccountRecomputeBalance(acc);
g_object_get(acc, "start-balance", &start, "end-balance", &end, NULL);
end2 = xaccAccountGetBalance(acc);
delta = gnc_numeric_sub(*end, five, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
do_test (gnc_numeric_zero_p(delta), "end balance matches");
delta = gnc_numeric_sub(end2, five, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
do_test (gnc_numeric_zero_p(delta), "end2 balance matches");
/*****/
qof_session_end (sess);
}
int
main (int argc, char **argv)
{
gint i;
qof_init();
if (!cashobjects_register())
exit(1);
/* Any tests that cause an error or warning to be printed
* automatically fail! */
g_log_set_always_fatal( G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING );
/* Set up a reproducible test-case */
srand(0);
/* Run the tests */
run_test ();
print_test_results();
qof_close();
return get_rv();
}