mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-26 02:40:43 -06:00
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:
parent
3cb46f0897
commit
4a5f6e30ca
1
AUTHORS
1
AUTHORS
@ -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
|
||||
|
10
ChangeLog
10
ChangeLog
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user