From 2faa2d40b36d86ba5de27555081b4b9789ee6b63 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Fri, 8 Jan 1999 07:22:42 +0000 Subject: [PATCH] compute cost basis correctly git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@1584 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/engine/Account.c | 53 ++++++++++++++++++++++++++++++++++++---- src/engine/AccountP.h | 18 +++++++++++--- src/engine/Transaction.c | 3 ++- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/engine/Account.c b/src/engine/Account.c index 1c9c8290f4..b5a11c733c 100644 --- a/src/engine/Account.c +++ b/src/engine/Account.c @@ -34,6 +34,7 @@ #include "GroupP.h" #include "date.h" #include "messages.h" +#include "Queue.h" #include "Transaction.h" #include "TransactionP.h" #include "util.h" @@ -203,7 +204,7 @@ void xaccAccountCommitEdit (Account *acc) { if (!acc) return; - acc->changed = 1; + acc->changed |= ACC_INVALIDATE_ALL; acc->open = 0; } @@ -263,7 +264,7 @@ disable for now till we figure out what the right thing is. */ /* mark the account as having changed */ - acc -> changed = TRUE; + acc -> changed |= ACC_INVALIDATE_ALL; /* if this split belongs to another acount, remove it from * there first. We don't want to ever leave the system @@ -357,7 +358,7 @@ xaccAccountRemoveSplit ( Account *acc, Split *split ) CHECK (acc); /* mark the account as having changed */ - acc -> changed = TRUE; + acc -> changed |= ACC_INVALIDATE_ALL; for( i=0,j=0; jnumSplits; i++,j++ ) { acc->splits[i] = acc->splits[j]; @@ -416,7 +417,8 @@ xaccAccountRecomputeBalance( Account * acc ) Split *split, *last_split = NULL; if( NULL == acc ) return; - if (FALSE == acc->changed) return; + if (0x0 == (ACC_INVALID_BALN & acc->changed)) return; + acc->changed &= ~ACC_INVALID_BALN; split = acc->splits[0]; while (split) { @@ -453,7 +455,8 @@ xaccAccountRecomputeBalance( Account * acc ) split -> cleared_balance = dcleared_balance; split -> reconciled_balance = dreconciled_balance; } - split -> cost_basis = dbalance; + /* invalidate the cost basis; this has to be computed with other routine */ + split -> cost_basis = 0.0; last_split = split; i++; @@ -479,6 +482,46 @@ xaccAccountRecomputeBalance( Account * acc ) return; } +/********************************************************************\ +\********************************************************************/ + +void +xaccAccountRecomputeCostBasis( Account * acc ) +{ + int i = 0; + double amt = 0.0; + Split *split = NULL; + Queue *q; + + if( NULL == acc ) return; + if (0x0 == (ACC_INVALID_COSTB & acc->changed)) return; + acc->changed &= ~ACC_INVALID_COSTB; + + /* create the FIFO queue */ + q = xaccMallocQueue (); + + /* loop over all splits in this account */ + split = acc->splits[0]; + while (split) { + + /* positive amounts are a purchase, negative are a sale. + * Use FIFO accounting: purchase to head, sale from tail. */ + amt = split->damount; + if (0.0 < amt) { + xaccQueuePushHead (q, split); + } else + if (0.0 > amt) { + xaccQueuePopTailShares (q, amt); + } + split->cost_basis = xaccQueueGetValue (q); + + i++; + split = acc->splits[i]; + } + + xaccFreeQueue (q); +} + /********************************************************************\ * xaccCheckDateOrder * * check this split to see if the date is in correct order * diff --git a/src/engine/AccountP.h b/src/engine/AccountP.h index 4d302c94df..28a937f451 100644 --- a/src/engine/AccountP.h +++ b/src/engine/AccountP.h @@ -18,7 +18,7 @@ /********************************************************************\ * Account.h -- the Account data structure * * Copyright (C) 1997 Robin D. Clark * - * Copyright (C) 1997, 1998 Linas Vepstas * + * Copyright (C) 1997, 1998, 1999 Linas Vepstas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -129,8 +129,9 @@ struct _account { int numSplits; /* length of splits array below */ Split **splits; /* ptr to array of ptrs to splits */ - /* the "changed" flag helps the gui keep track of - * changes to this account */ + /* The "changed" flag is used to invalidate cached values in this structure. + * currently, the balances and the cost basis are cached. + */ short changed; /* the "open" flag indicates if the account has been @@ -138,6 +139,11 @@ struct _account { short open; }; +/* bitfields for the changed flag */ +#define ACC_INVALID_BALN 0x1 +#define ACC_INVALID_COSTB 0x2 +#define ACC_INVALIDATE_ALL 0x3 + /* bitflields for the open flag */ #define ACC_BEGIN_EDIT 0x1 #define ACC_DEFER_REBALANCE 0x2 @@ -160,6 +166,12 @@ void xaccAccountRemoveSplit (Account *, Split *); void xaccAccountRecomputeBalance (Account *); void xaccAccountRecomputeBalances (Account **); +/* + * recomputes the cost basis + */ +void xaccAccountRecomputeCostBasis (Account *); + + /** GLOBALS *********************************************************/ extern int next_free_unique_account_id; diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index f8a3bc080d..6d73bf7a1b 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -203,7 +203,7 @@ xaccConfigGetForceDoubleEntry (void) #define MARK_SPLIT(split) { \ Account *acc = (Account *) ((split)->acc); \ - if (acc) acc->changed = 1; \ + if (acc) acc->changed |= ACC_INVALIDATE_ALL; \ } static void @@ -308,6 +308,7 @@ double xaccSplitGetShareBalance (Split *s) double xaccSplitGetCostBasis (Split *s) { if (!s) return 0.0; + xaccAccountRecomputeCostBasis (s->acc); return s->cost_basis; }