Mike Alexander's patch to fix lot date calculation, and to include all

splits when computing capital gain's instead of just the opening lot.
Scrub lots when scrubbing everything else.  Some MacOs X fixes.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13872 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
David Hampton 2006-04-28 21:11:01 +00:00
parent 3cb46f0897
commit 4a5f6e30ca
9 changed files with 109 additions and 19 deletions

View File

@ -91,6 +91,7 @@ Other Contributors:
----------------
(In alphabetical order)
Mike Alexander <mta@umich.edu> Cap gains, lot and MacOS fixes.
Andrew Arensburger <arensb@cfar.umd.edu> for FreeBSD & other patches
Matt Armstrong <matt_armstrong@bigfoot.com> for misc fixes
A. Alper Atici <alper_atici@yahoo.com> Turkish translation

View File

@ -1,5 +1,15 @@
2006-04-28 David Hampton <hampton@employees.org>
* src/gnome/window-reconcile.c:
* src/gnome/gnc-plugin-page-account-tree.c:
* src/engine/gnc-lot.[ch]:
* src/engine/Transaction.c:
* src/engine/Scrub2.c:
* src/engine/cap-gains.c: Mike Alexander's patch to fix lot date
calculation, and to include all splits when computing capital
gain's instead of just the opening lot. Scrub lots when scrubbing
everything else. Some MacOs X fixes.
* src/gnome/gnc-plugin-basic-commands.c: Finishing all pending
transactions before new and open commands, not just save commands.
Fixes #334090.

View File

@ -413,6 +413,7 @@ restart:
Split *s = node->data;
if (xaccSplitGetLot (s) != lot) continue;
if (s == split) continue;
if (s->inst.do_free) continue;
/* OK, this split is in the same lot (and thus same account)
* as the indicated split. It must be a subsplit (although

View File

@ -1014,6 +1014,8 @@ xaccTransCommitEdit (Transaction *trans)
*/
if (!(trans->inst.do_free) && scrub_data &&
!qof_book_shutting_down(xaccTransGetBook(trans))) {
/* If scrubbing gains recurses through here, don't call it again. */
scrub_data = 0;
/* The total value of the transaction should sum to zero.
* Call the trans scrub routine to fix it. Indirectly, this
* routine also performs a number of other transaction fixes too.
@ -1021,6 +1023,8 @@ xaccTransCommitEdit (Transaction *trans)
xaccTransScrubImbalance (trans, NULL, NULL);
/* Get the cap gains into a consistent state as well. */
xaccTransScrubGains (trans, NULL);
/* Allow scrubbing in transaction commit again */
scrub_data = 1;
}
/* Record the time of last modification */

View File

@ -86,6 +86,9 @@ xaccAccountHasTrades (Account *acc)
if (!acc) return FALSE;
if (xaccAccountIsPriced (acc))
return TRUE;
acc_comm = acc->commodity;
for (node=acc->splits; node; node=node->next)
@ -158,7 +161,7 @@ finder_helper (GNCLot *lot, gpointer user_data)
static inline GNCLot *
xaccAccountFindOpenLot (Account *acc, gnc_numeric sign,
gnc_commodity *currency,
gint64 guess,
guint64 guess,
gboolean (*date_pred)(Timespec, Timespec))
{
struct find_lot_s es;
@ -184,7 +187,7 @@ xaccAccountFindEarliestOpenLot (Account *acc, gnc_numeric sign,
ENTER (" sign=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, sign.num, sign.denom);
lot = xaccAccountFindOpenLot (acc, sign, currency,
G_GINT64_CONSTANT(2^31) * G_GINT64_CONSTANT(2^31), earliest_pred);
G_MAXUINT64, earliest_pred);
LEAVE ("found lot=%p %s baln=%s", lot, gnc_lot_get_title (lot),
gnc_num_dbg_to_string(gnc_lot_get_balance(lot)));
return lot;
@ -199,8 +202,7 @@ xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign,
sign.num, sign.denom);
lot = xaccAccountFindOpenLot (acc, sign, currency,
G_GINT64_CONSTANT(-2^31) * G_GINT64_CONSTANT(2^31),
latest_pred);
0, latest_pred);
LEAVE ("found lot=%p %s", lot, gnc_lot_get_title (lot));
return lot;
}
@ -588,12 +590,17 @@ xaccSplitAssign (Split *split)
GNCPolicy *pcy;
if (!split) return FALSE;
/* If this split already belongs to a lot or the account doesn't
* have lots, we are done.
*/
if (split->lot) return FALSE;
acc = split->acc;
if (!xaccAccountHasTrades (acc))
return FALSE;
ENTER ("(split=%p)", split);
/* If this split already belongs to a lot, we are done. */
if (split->lot) return FALSE;
acc = split->acc;
pcy = acc->policy;
xaccAccountBeginEdit (acc);
@ -657,6 +664,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
gnc_numeric value = zero;
gnc_numeric frac;
gnc_numeric opening_amount, opening_value;
gnc_numeric lot_amount, lot_value;
gnc_commodity *opening_currency;
if (!split) return;
@ -705,9 +713,15 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
return;
}
if (safe_strcmp ("stock-split", xaccSplitGetType (split)) == 0)
{
LEAVE ("Stock split split, returning.");
return;
}
if (GAINS_STATUS_GAINS & split->gains)
{
Split *s;
Split *s;
PINFO ("split is a gains recording split, switch over");
/* If this is the split that records the gains, then work with
* the split that generates the gains.
@ -730,7 +744,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
xaccTransDestroy (trans);
#endif
}
split = s;
split = s;
}
/* Note: if the value of the 'opening' split(s) has changed,
@ -826,19 +840,23 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
return;
}
/* The cap gains is the difference between the value of the
* opening split, and the current split, pro-rated for an equal
/* The cap gains is the difference between the basis prior to the
* current split, and the current split, pro-rated for an equal
* amount of shares.
* i.e. purchase_price = opening_value / opening_amount
* cost_basis = purchase_price * current_amount
* cap_gain = current_value - cost_basis
* i.e. purchase_price = lot_value / lot_amount
* cost_basis = purchase_price * current_split_amount
* cap_gain = current_split_value - cost_basis
*/
frac = gnc_numeric_div (split->amount, opening_amount,
gnc_lot_get_balance_before (lot, split, &lot_amount, &lot_value);
/* Fraction of the lot that this split represents: */
frac = gnc_numeric_div (split->amount, lot_amount,
GNC_DENOM_AUTO,
GNC_HOW_DENOM_REDUCE);
value = gnc_numeric_mul (frac, opening_value,
/* Basis for this split: */
value = gnc_numeric_mul (frac, lot_value,
gnc_numeric_denom(opening_value),
GNC_HOW_DENOM_EXACT|GNC_HOW_RND_ROUND);
/* Capital gain for this split: */
value = gnc_numeric_sub (value, split->value,
GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
PINFO ("Open amt=%s val=%s; split amt=%s val=%s; gains=%s\n",
@ -1124,7 +1142,10 @@ restart:
{
gboolean altered = FALSE;
split->gains |= ~GAINS_STATUS_ADIRTY;
if (split->lot) altered = xaccScrubLot (split->lot);
if (split->lot)
altered = xaccScrubLot (split->lot);
else
altered = xaccSplitAssign (split);
if (altered) goto restart;
}
}

View File

@ -225,6 +225,40 @@ gnc_lot_get_balance (GNCLot *lot)
/* ============================================================= */
void
gnc_lot_get_balance_before (GNCLot *lot, Split *split,
gnc_numeric *amount, gnc_numeric *value)
{
GList *node;
gnc_numeric zero = gnc_numeric_zero();
gnc_numeric amt = zero;
gnc_numeric val = zero;
if (lot && lot->splits)
{
for (node = lot->splits; node; node = node->next)
{
Split *s = node->data;
Transaction *ta, *tb;
ta = xaccSplitGetParent (s);
tb = xaccSplitGetParent (split);
if ((ta == tb && s != split) ||
xaccTransOrder (ta, tb) < 0)
{
gnc_numeric tmpval = xaccSplitGetAmount (s);
amt = gnc_numeric_add_fixed (amt, tmpval);
tmpval = xaccSplitGetValue (s);
val = gnc_numeric_add_fixed (val, tmpval);
}
}
}
*amount = amt;
*value = val;
}
/* ============================================================= */
void
gnc_lot_add_split (GNCLot *lot, Split *split)
{
@ -294,7 +328,7 @@ gnc_lot_get_earliest_split (GNCLot *lot)
Timespec ts;
Split *earliest = NULL;
ts.tv_sec = ((long long) LONG_MAX);
ts.tv_sec = ((long long) ULONG_MAX);
ts.tv_nsec = 0;
if (!lot) return NULL;
@ -323,7 +357,7 @@ gnc_lot_get_latest_split (GNCLot *lot)
Timespec ts;
Split *latest = NULL;
ts.tv_sec = -((long long) LONG_MAX);
ts.tv_sec = 0;
ts.tv_nsec = 0;
if (!lot) return NULL;

View File

@ -97,6 +97,13 @@ Account * gnc_lot_get_account (GNCLot *);
* of the account. */
gnc_numeric gnc_lot_get_balance (GNCLot *);
/** The gnc_lot_get_balance_before routines computes both the balance and
* value in the lot considering only splits in transactions prior to the
* one containing the given split or other splits in the same transaction.
* The first return value is the amount and the second is the value. */
void gnc_lot_get_balance_before (GNCLot *, Split *,
gnc_numeric *, gnc_numeric *);
/** The gnc_lot_is_closed() routine returns a boolean flag: is this
* lot closed? A lot is closed if its balance is zero. This
* routine is faster than using gnc_lot_get_balance() because

View File

@ -43,6 +43,7 @@
#include "gnc-plugin-page-register.h"
#include "Scrub.h"
#include "Scrub3.h"
#include "Transaction.h"
#include "dialog-account.h"
#include "dialog-transfer.h"
@ -1198,6 +1199,8 @@ gnc_plugin_page_account_tree_cmd_scrub (GtkAction *action, GncPluginPageAccountT
xaccAccountScrubOrphans (account);
xaccAccountScrubImbalance (account);
xaccAccountScrubLots (account);
gnc_resume_gui_refresh ();
}
@ -1213,6 +1216,8 @@ gnc_plugin_page_account_tree_cmd_scrub_sub (GtkAction *action, GncPluginPageAcco
xaccAccountTreeScrubOrphans (account);
xaccAccountTreeScrubImbalance (account);
xaccAccountTreeScrubLots (account);
gnc_resume_gui_refresh ();
}
@ -1225,6 +1230,10 @@ gnc_plugin_page_account_tree_cmd_scrub_all (GtkAction *action, GncPluginPageAcco
xaccGroupScrubOrphans (group);
xaccGroupScrubImbalance (group);
xaccGroupScrubLots (group);
gnc_resume_gui_refresh ();
}
/** @} */

View File

@ -37,6 +37,7 @@
#include <glib/gi18n.h>
#include "Scrub.h"
#include "Scrub3.h"
#include "dialog-account.h"
#include "dialog-transfer.h"
#include "dialog-utils.h"
@ -1229,6 +1230,8 @@ gnc_recn_scrub_cb(GtkAction *action, gpointer data)
xaccAccountTreeScrubOrphans (account);
xaccAccountTreeScrubImbalance (account);
xaccAccountTreeScrubLots (account);
gnc_resume_gui_refresh ();
}