mirror of
https://github.com/Gnucash/gnucash.git
synced 2026-08-04 02:13:29 -05:00
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:
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user