Work on reconciling stock/mutual fund accounts.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2369 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas
2000-05-21 07:40:51 +00:00
parent c25afb2e8b
commit 7011321677
8 changed files with 150 additions and 74 deletions
+19 -2
View File
@@ -1,7 +1,24 @@
2000-05-21 Dave Peticolas <peticola@cs.ucdavis.edu>
* src/gnome/window-reconcile.c: use share balances when
reconciling stock, mutual fund, and currency accounts.
2000-05-20 Dave Peticolas <peticola@cs.ucdavis.edu>
* src/gnome/dialog-add.c (accWindow): if the window is closed as
a result of a window destroy, don't save the size or destroy the
* src/engine/Account.c (xaccAccountRecomputeBalance): added share,
cleared share, and reconciled share balance tracking, along with
api calls for getting them.
* src/engine/Transaction.c: add calls to get share cleared and
reconciled balance.
* src/engine/Query.c: use g_list_prepend and then reverse when
gathering splits. When pruning the list, prune from the beginning,
not the end, per the original semantics. Handle the case when
q->max_splits is 0.
* src/gnome/dialog-add.c (accWindow): if the window is closed as a
result of a gnome_dialog_close, don't save the size or destroy the
window, it's already gone.
* configure.in: remove check for readline. guile-config should
+66 -47
View File
@@ -77,12 +77,13 @@ xaccInitAccount (Account * acc)
acc->parent = NULL;
acc->children = NULL;
acc->balance = 0.0;
acc->balance = 0.0;
acc->cleared_balance = 0.0;
acc->reconciled_balance = 0.0;
acc->running_balance = 0.0;
acc->running_cleared_balance = 0.0;
acc->running_reconciled_balance = 0.0;
acc->share_balance = 0.0;
acc->share_cleared_balance = 0.0;
acc->share_reconciled_balance = 0.0;
acc->flags = 0;
acc->type = -1;
@@ -181,6 +182,10 @@ xaccFreeAccount( Account *acc )
acc->cleared_balance = 0.0;
acc->reconciled_balance = 0.0;
acc->share_balance = 0.0;
acc->share_cleared_balance = 0.0;
acc->share_reconciled_balance = 0.0;
acc->flags = 0;
acc->type = -1;
@@ -490,25 +495,25 @@ xaccAccountRemoveSplit ( Account *acc, Split *split )
* xaccAccountRecomputeBalance *
* recomputes the partial balances and the current balance for *
* this account. *
*
* The way the computation is done depends on whether the partial
* balances are for a monetary account (bank, cash, etc.) or a
* certificate account (stock portfolio, mutual fund). For bank
* accounts, the invariant amount is the dollar amount. For share
* accounts, the invariant amount is the number of shares. For
* share accounts, the share price fluctuates, and the current
* value of such an account is the number of shares times the current
* share price.
*
* Part of the complexity of this computatation stems from the fact
* xacc uses a double-entry system, meaning that one transaction
* appears in two accounts: one account is debited, and the other
* is credited. When the transaction represents a sale of shares,
* or a purchase of shares, some care must be taken to compute
* balances correctly. For a sale of shares, the stock account must
* be debited in shares, but the bank account must be credited
* in dollars. Thus, two different mechanisms must be used to
* compute balances, depending on account type.
* *
* The way the computation is done depends on whether the partial *
* balances are for a monetary account (bank, cash, etc.) or a *
* certificate account (stock portfolio, mutual fund). For bank *
* accounts, the invariant amount is the dollar amount. For share *
* accounts, the invariant amount is the number of shares. For *
* share accounts, the share price fluctuates, and the current *
* value of such an account is the number of shares times the *
* current share price. *
* *
* Part of the complexity of this computatation stems from the fact *
* xacc uses a double-entry system, meaning that one transaction *
* appears in two accounts: one account is debited, and the other *
* is credited. When the transaction represents a sale of shares, *
* or a purchase of shares, some care must be taken to compute *
* balances correctly. For a sale of shares, the stock account must*
* be debited in shares, but the bank account must be credited *
* in dollars. Thus, two different mechanisms must be used to *
* compute balances, depending on account type. *
* *
* Args: account -- the account for which to recompute balances *
* Return: void *
@@ -526,7 +531,7 @@ xaccAccountRecomputeBalance( Account * acc )
double share_reconciled_balance = 0.0;
double amt = 0.0;
Split *split, *last_split = NULL;
if( NULL == acc ) return;
if (0x0 == (ACC_INVALID_BALN & acc->changed)) return;
acc->changed &= ~ACC_INVALID_BALN;
@@ -557,7 +562,8 @@ xaccAccountRecomputeBalance( Account * acc )
split -> share_reconciled_balance = share_reconciled_balance;
split -> balance = split->share_price * share_balance;
split -> cleared_balance = split->share_price * share_cleared_balance;
split -> reconciled_balance = split->share_price * share_reconciled_balance;
split -> reconciled_balance = (split->share_price *
share_reconciled_balance);
} else {
split -> share_balance = dbalance;
split -> share_cleared_balance = dcleared_balance;
@@ -576,20 +582,31 @@ xaccAccountRecomputeBalance( Account * acc )
if ( (STOCK == acc->type) || ( MUTUAL == acc->type) ) {
if (last_split) {
acc -> share_balance = share_balance;
acc -> share_cleared_balance = share_cleared_balance;
acc -> share_reconciled_balance = share_reconciled_balance;
acc -> balance = share_balance * (last_split->share_price);
acc -> cleared_balance = share_cleared_balance * (last_split->share_price);
acc -> reconciled_balance = share_reconciled_balance * (last_split->share_price);
acc -> cleared_balance = (share_cleared_balance *
last_split->share_price);
acc -> reconciled_balance = (share_reconciled_balance *
last_split->share_price);
} else {
acc -> share_balance = 0.0;
acc -> share_cleared_balance = 0.0;
acc -> share_reconciled_balance = 0.0;
acc -> balance = 0.0;
acc -> cleared_balance = 0.0;
acc -> reconciled_balance = 0.0;
}
} else {
acc -> share_balance = dbalance;
acc -> share_cleared_balance = dcleared_balance;
acc -> share_reconciled_balance = dreconciled_balance;
acc -> balance = dbalance;
acc -> cleared_balance = dcleared_balance;
acc -> reconciled_balance = dreconciled_balance;
}
return;
}
@@ -863,25 +880,6 @@ xaccAccountRecomputeBalances( Account **list )
/********************************************************************\
\********************************************************************/
void
xaccZeroRunningBalances( Account **list )
{
Account * acc;
int nacc = 0;
if (!list) return;
acc = list[0];
while (acc) {
acc -> running_balance = 0.0;
acc -> running_cleared_balance = 0.0;
nacc++;
acc = list[nacc];
}
}
/********************************************************************\
\********************************************************************/
void
xaccMoveFarEnd (Split *split, Account *new_acc)
{
@@ -1319,6 +1317,27 @@ xaccAccountGetReconciledBalance (Account *acc)
return (acc->reconciled_balance);
}
double
xaccAccountGetShareBalance (Account *acc)
{
if (!acc) return 0.0;
return (acc->share_balance);
}
double
xaccAccountGetShareClearedBalance (Account *acc)
{
if (!acc) return 0.0;
return (acc->share_cleared_balance);
}
double
xaccAccountGetShareReconciledBalance (Account *acc)
{
if (!acc) return 0.0;
return (acc->share_reconciled_balance);
}
Split *
xaccAccountGetSplit (Account *acc, int i)
{
+3 -1
View File
@@ -94,7 +94,6 @@ int xaccCheckTransDateOrder (Transaction *);
* that an account appears in the account list.
*/
int xaccIsAccountInList (Account * acc, Account **list);
void xaccZeroRunningBalances (Account **list);
/* The xaccAccountOrder() subroutine defines a sorting order
* on accounts. It takes pointers to two accounts, and
@@ -165,6 +164,9 @@ AccInfo * xaccAccountGetAccInfo (Account *);
double xaccAccountGetBalance (Account *);
double xaccAccountGetClearedBalance (Account *);
double xaccAccountGetReconciledBalance (Account *);
double xaccAccountGetShareBalance (Account *);
double xaccAccountGetShareClearedBalance (Account *);
double xaccAccountGetShareReconciledBalance (Account *);
Split * xaccAccountGetSplit (Account *acc, int i);
Split ** xaccAccountGetSplitList (Account *acc);
int xaccAccountGetNumSplits (Account *acc);
+3 -3
View File
@@ -128,9 +128,9 @@ struct _account {
double cleared_balance;
double reconciled_balance;
double running_balance;
double running_cleared_balance;
double running_reconciled_balance;
double share_balance;
double share_cleared_balance;
double share_reconciled_balance;
int numSplits; /* length of splits array below */
Split **splits; /* ptr to array of ptrs to splits */
+17 -4
View File
@@ -745,7 +745,7 @@ xaccQueryGetSplits(Query * q) {
/* iterate over splits */
for(sptr = splits; *sptr; sptr++) {
if(xaccQueryCheckSplit(q, *sptr)) {
matching_splits = g_list_append(matching_splits, *sptr);
matching_splits = g_list_prepend(matching_splits, *sptr);
split_count++;
}
total_splits_checked++;
@@ -753,6 +753,13 @@ xaccQueryGetSplits(Query * q) {
}
}
/* There is no absolute need to reverse this list, since it's
* being sorted below. However, in the common case, we will be
* searching in a single account and returning in the account
* order, thus reversing will put us in the correct order we
* want and make the sorting go much faster. */
matching_splits = g_list_reverse(matching_splits);
/* now sort the matching splits based on the search criteria
* split_sort_query is an unforgivable use of static global data...
* I just can't figure out how else to do this sanely. */
@@ -762,9 +769,15 @@ xaccQueryGetSplits(Query * q) {
/* crop the list to limit the number of splits */
if((split_count > q->max_splits) && (q->max_splits > -1)) {
if(q->max_splits > 0) {
mptr = g_list_nth(matching_splits, q->max_splits - 1);
g_list_free(mptr->next);
mptr->next = NULL;
/* mptr is set to the first node of what will be the new list */
mptr = g_list_nth(matching_splits, split_count - q->max_splits);
mptr->prev = NULL;
g_list_free(matching_splits);
matching_splits = mptr;
}
else { /* q->max_splits == 0 */
g_list_free(matching_splits);
matching_splits = NULL;
}
split_count = q->max_splits;
}
+13 -2
View File
@@ -345,6 +345,18 @@ double xaccSplitGetShareBalance (Split *s)
return s->share_balance;
}
double xaccSplitGetShareClearedBalance (Split *s)
{
if (!s) return 0.0;
return s->share_cleared_balance;
}
double xaccSplitGetShareReconciledBalance (Split *s)
{
if (!s) return 0.0;
return s->share_reconciled_balance;
}
double xaccSplitGetCostBasis (Split *s)
{
if (!s) return 0.0;
@@ -1386,8 +1398,7 @@ xaccTransRemoveSplit (Transaction *trans, Split *split)
* occur on the same day that have all three of these values identical.
*
* Note that being able to establish this kind of absolute order is
* important for some of the ledger display functions. In particular,
* grep for "running_balance" in the code, and see the notes there.
* important for some of the ledger display functions.
*
* Yes, this kind of code dependency is ugly, but the alternatives seem
* ugly too.
+2
View File
@@ -400,6 +400,8 @@ double xaccSplitGetBalance (Split *);
double xaccSplitGetClearedBalance (Split *);
double xaccSplitGetReconciledBalance (Split *);
double xaccSplitGetShareBalance (Split *);
double xaccSplitGetShareClearedBalance (Split *);
double xaccSplitGetShareReconciledBalance (Split *);
double xaccSplitGetCostBasis (Split *);
double xaccSplitGetBaseValue (Split *s, const char *base_currency);
+27 -15
View File
@@ -62,6 +62,7 @@ struct _RecnWindow
Account *account; /* The account that we are reconciling */
double new_ending; /* The new ending balance */
time_t statement_date; /* The statement date */
gboolean use_shares; /* Use share balances */
GtkWidget *window; /* The reconcile window */
@@ -176,21 +177,21 @@ recnRecalculateBalance(RecnWindow *recnData)
double diff;
GNCPrintAmountFlags flags;
gboolean reverse_balance;
int account_type;
flags = PRTSYM | PRTSEP;
reverse_balance = gnc_reverse_balance(recnData->account);
account_type = xaccAccountGetType(recnData->account);
if ((account_type == STOCK ) || (account_type == MUTUAL) ||
(account_type == CURRENCY))
if (recnData->use_shares)
flags |= PRTSHR;
currency = xaccAccountGetCurrency(recnData->account);
/* update the starting balance */
starting = xaccAccountGetReconciledBalance(recnData->account);
if (recnData->use_shares)
starting = xaccAccountGetShareReconciledBalance(recnData->account);
else
starting = xaccAccountGetReconciledBalance(recnData->account);
if (reverse_balance)
starting = -starting;
amount = xaccPrintAmount(starting, flags, currency);
@@ -310,21 +311,23 @@ startRecnWindow(GtkWidget *parent, Account *account,
flags = PRTSYM | PRTSEP;
/* Get the previous ending balance. Use the published
* account interface for this, since the ending balance
* may have to be adjusted for stock price fluctuations. */
dendBalance = xaccAccountGetReconciledBalance(account);
account_type = xaccAccountGetType(account);
if ((account_type == STOCK) || (account_type == MUTUAL) ||
(account_type == CURRENCY))
{
flags |= PRTSHR;
dendBalance = xaccAccountGetShareReconciledBalance(account);
}
else
dendBalance = xaccAccountGetReconciledBalance(account);
if (gnc_reverse_balance(account))
{
dendBalance = -dendBalance;
*new_ending = -(*new_ending);
}
account_type = xaccAccountGetType(account);
if ((account_type == STOCK) || (account_type == MUTUAL) ||
(account_type == CURRENCY))
flags |= PRTSHR;
currency = xaccAccountGetCurrency(account);
amount = xaccPrintAmount(dendBalance, flags, currency);
@@ -1241,13 +1244,22 @@ recnWindow(GtkWidget *parent, Account *account)
GtkWidget *dock;
double new_ending;
time_t statement_date;
GNCAccountType type;
if (account == NULL)
return NULL;
FETCH_FROM_LIST(RecnWindow, recnList, account, account, recnData);
new_ending = xaccAccountGetBalance(account);
type = xaccAccountGetType(account);
recnData->use_shares = ((type == STOCK) || (type == MUTUAL) ||
(type == CURRENCY));
if (recnData->use_shares)
new_ending = xaccAccountGetShareBalance(account);
else
new_ending = xaccAccountGetBalance(account);
statement_date = time(NULL);
/* Popup a little window to prompt the user to enter the