mirror of
https://github.com/Gnucash/gnucash.git
synced 2026-10-24 23:27:39 -05:00
Merge Sherlock's 'stock-splits' into stable.
This commit is contained in:
commit
b766c126ee
18 files changed
+694
-389
No files matched your search
+278
-258
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.38.2 -->
|
||||
<!-- Generated with glade 3.40.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<object class="GtkDialog" id="lot_viewer_dialog">
|
||||
@@ -107,6 +107,22 @@
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="show_adjusted_amounts_checkbutton">
|
||||
<property name="label" translatable="yes">Show stock split adjusted amounts</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned" id="lot_vpaned">
|
||||
<property name="visible">True</property>
|
||||
@@ -191,13 +207,13 @@
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">_Title</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="mnemonic-widget">lot_title_entry</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
@@ -224,12 +240,12 @@
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">_Lots in This Account</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">lot_view</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
@@ -242,8 +258,6 @@
|
||||
<property name="can-focus">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hscrollbar-policy">always</property>
|
||||
<property name="vscrollbar-policy">always</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="lot_view">
|
||||
@@ -308,12 +322,12 @@
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Splits _free</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">split_free_view</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
@@ -366,12 +380,12 @@
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Splits _in lot</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
<property name="use-markup">True</property>
|
||||
<property name="use-underline">True</property>
|
||||
<property name="mnemonic-widget">split_in_lot_view</property>
|
||||
<style>
|
||||
<class name="gnc-class-strong"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
|
||||
@@ -82,6 +82,12 @@ gnc_numeric gnc_float_split_get_value (const FloatingSplit *fs)
|
||||
return fs->m_value;
|
||||
}
|
||||
|
||||
gboolean gnc_float_split_get_stock_split (const FloatingSplit *fs)
|
||||
{
|
||||
g_return_val_if_fail (fs, FALSE);
|
||||
return fs->m_stock_split;
|
||||
}
|
||||
|
||||
|
||||
/* modifiers */
|
||||
void gnc_float_split_set_split(FloatingSplit *fs, Split *split)
|
||||
@@ -129,17 +135,21 @@ void gnc_float_split_set_reconcile_date (FloatingSplit *fs, time64 reconcile_dat
|
||||
void gnc_float_split_set_amount (FloatingSplit *fs, const gnc_numeric amount)
|
||||
{
|
||||
g_return_if_fail (fs);
|
||||
|
||||
fs->m_amount = amount;
|
||||
}
|
||||
|
||||
void gnc_float_split_set_value (FloatingSplit *fs, const gnc_numeric value)
|
||||
{
|
||||
g_return_if_fail (fs);
|
||||
|
||||
fs->m_value = value;
|
||||
}
|
||||
|
||||
void gnc_float_split_set_stock_split (FloatingSplit *fs, gboolean stock_split)
|
||||
{
|
||||
g_return_if_fail (fs);
|
||||
fs->m_stock_split = stock_split;
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_float_template_sx_data_free (FloatingTemplateSxData *ftsd)
|
||||
{
|
||||
@@ -247,6 +257,7 @@ FloatingSplit *gnc_split_to_float_split (Split *split, gboolean is_template)
|
||||
fs->m_reconcile_date = xaccSplitGetDateReconciled (split);
|
||||
fs->m_amount = xaccSplitGetAmount (split);
|
||||
fs->m_value = xaccSplitGetValue (split);
|
||||
fs->m_stock_split = xaccSplitIsStockSplit (split);
|
||||
|
||||
if (is_template)
|
||||
fs->m_template_sx_data = gnc_split_to_float_template_sx_data (split);
|
||||
@@ -336,6 +347,8 @@ gnc_float_split_to_split (const FloatingSplit *fs, Split *split, Account *templa
|
||||
{
|
||||
xaccSplitSetAmount (split, fs->m_amount);
|
||||
xaccSplitSetValue (split, fs->m_value);
|
||||
if (fs->m_stock_split)
|
||||
xaccSplitMakeStockSplit(split);
|
||||
}
|
||||
|
||||
if (split_account)
|
||||
|
||||
@@ -55,6 +55,7 @@ typedef struct
|
||||
char m_reconcile_state;
|
||||
gnc_numeric m_value;
|
||||
gnc_numeric m_amount;
|
||||
gboolean m_stock_split;
|
||||
|
||||
FloatingTemplateSxData *m_template_sx_data;
|
||||
|
||||
@@ -83,6 +84,7 @@ char gnc_float_split_get_reconcile_state (const FloatingSplit *fs);
|
||||
time64 gnc_float_split_get_reconcile_date (const FloatingSplit *fs);
|
||||
gnc_numeric gnc_float_split_get_amount (const FloatingSplit *fs);
|
||||
gnc_numeric gnc_float_split_get_value (const FloatingSplit *fs);
|
||||
gboolean gnc_float_split_get_stock_split (const FloatingSplit *fs);
|
||||
|
||||
/* modifiers */
|
||||
void gnc_float_split_set_split (FloatingSplit *fs, Split *split);
|
||||
@@ -94,6 +96,7 @@ void gnc_float_split_set_reconcile_state (FloatingSplit *fs, char reconcile_stat
|
||||
void gnc_float_split_set_reconcile_date (FloatingSplit *fs, time64 reconcile_date);
|
||||
void gnc_float_split_set_amount (FloatingSplit *fs, gnc_numeric amount);
|
||||
void gnc_float_split_set_value (FloatingSplit *fs, gnc_numeric value);
|
||||
void gnc_float_split_set_stock_split (FloatingSplit *fs, gboolean stock_split);
|
||||
|
||||
FloatingSplit *gnc_split_to_float_split (Split *split, gboolean is_template);
|
||||
void gnc_float_split_to_split (const FloatingSplit *fs, Split *split, Account *template_account);
|
||||
|
||||
@@ -1546,7 +1546,7 @@ gnc_split_register_get_mxfrm_entry (VirtualLocation virt_loc,
|
||||
|
||||
if (s)
|
||||
name = g_strdup (SPLIT_TRANS_STR);
|
||||
else if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
|
||||
else if (xaccSplitIsStockSplit (split))
|
||||
name = g_strdup (STOCK_SPLIT_STR);
|
||||
else
|
||||
name = g_strdup ("");
|
||||
@@ -1588,7 +1588,7 @@ gnc_split_register_get_mxfrm_help (VirtualLocation virt_loc,
|
||||
if (s)
|
||||
help = _ ("This transaction has multiple splits; "
|
||||
"press the Split button to see them all");
|
||||
else if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
|
||||
else if (xaccSplitIsStockSplit (split))
|
||||
help = _ ("This transaction is a stock split; "
|
||||
"press the Split button to see details");
|
||||
else
|
||||
@@ -2080,7 +2080,7 @@ gnc_split_register_get_debcred_io_flags (VirtualLocation virt_loc,
|
||||
|
||||
split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
|
||||
|
||||
if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
|
||||
if (xaccSplitIsStockSplit (split))
|
||||
return XACC_CELL_ALLOW_NONE;
|
||||
|
||||
return XACC_CELL_ALLOW_ALL;
|
||||
|
||||
@@ -328,6 +328,7 @@ gnc_account_init(Account* acc)
|
||||
priv->starting_cleared_balance = gnc_numeric_zero();
|
||||
priv->starting_reconciled_balance = gnc_numeric_zero();
|
||||
priv->balance_dirty = FALSE;
|
||||
priv->has_stock_split = false;
|
||||
|
||||
new (&priv->children) AccountVec ();
|
||||
new (&priv->splits) SplitsVec ();
|
||||
@@ -1456,6 +1457,7 @@ xaccFreeAccount (Account *acc)
|
||||
priv->commodity = nullptr;
|
||||
|
||||
priv->balance_dirty = FALSE;
|
||||
priv->has_stock_split = false;
|
||||
priv->sort_dirty = FALSE;
|
||||
priv->splits.~SplitsVec();
|
||||
priv->children.~AccountVec();
|
||||
@@ -2137,30 +2139,26 @@ xaccAccountRemoveLot (Account *acc, GNCLot *lot)
|
||||
void
|
||||
xaccAccountInsertLot (Account *acc, GNCLot *lot)
|
||||
{
|
||||
AccountPrivate *priv, *opriv;
|
||||
Account * old_acc = nullptr;
|
||||
Account* lot_account;
|
||||
|
||||
/* errors */
|
||||
g_return_if_fail(GNC_IS_ACCOUNT(acc));
|
||||
g_return_if_fail(GNC_IS_LOT(lot));
|
||||
|
||||
/* optimizations */
|
||||
lot_account = gnc_lot_get_account(lot);
|
||||
if (lot_account == acc)
|
||||
auto lot_acc = gnc_lot_get_account(lot);
|
||||
if (lot_acc == acc)
|
||||
return;
|
||||
|
||||
ENTER ("(acc=%p, lot=%p)", acc, lot);
|
||||
|
||||
/* pull it out of the old account */
|
||||
if (lot_account)
|
||||
if (lot_acc)
|
||||
{
|
||||
old_acc = lot_account;
|
||||
opriv = GET_PRIVATE(old_acc);
|
||||
opriv->lots = g_list_remove(opriv->lots, lot);
|
||||
auto priv = GET_PRIVATE(lot_acc);
|
||||
priv->lots = g_list_remove(priv->lots, lot);
|
||||
qof_event_gen (&lot_acc->inst, QOF_EVENT_MODIFY, nullptr);
|
||||
}
|
||||
|
||||
priv = GET_PRIVATE(acc);
|
||||
auto priv = GET_PRIVATE(acc);
|
||||
priv->lots = g_list_prepend(priv->lots, lot);
|
||||
gnc_lot_set_account(lot, acc);
|
||||
|
||||
@@ -2276,32 +2274,52 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
|
||||
void
|
||||
xaccAccountRecomputeBalance (Account * acc)
|
||||
{
|
||||
AccountPrivate *priv;
|
||||
gnc_numeric balance;
|
||||
gnc_numeric noclosing_balance;
|
||||
gnc_numeric cleared_balance;
|
||||
gnc_numeric reconciled_balance;
|
||||
|
||||
if (nullptr == acc) return;
|
||||
|
||||
priv = GET_PRIVATE(acc);
|
||||
auto priv = GET_PRIVATE(acc);
|
||||
if (qof_instance_get_editlevel(acc) > 0) return;
|
||||
if (!priv->balance_dirty || priv->defer_bal_computation) return;
|
||||
if (qof_instance_get_destroying(acc)) return;
|
||||
if (qof_book_shutting_down(qof_instance_get_book(acc))) return;
|
||||
|
||||
balance = priv->starting_balance;
|
||||
noclosing_balance = priv->starting_noclosing_balance;
|
||||
cleared_balance = priv->starting_cleared_balance;
|
||||
reconciled_balance = priv->starting_reconciled_balance;
|
||||
auto balance = priv->starting_balance;
|
||||
auto noclosing_balance = priv->starting_noclosing_balance;
|
||||
auto cleared_balance = priv->starting_cleared_balance;
|
||||
auto reconciled_balance = priv->starting_reconciled_balance;
|
||||
auto has_stock_split = false;
|
||||
|
||||
PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
|
||||
priv->accountName, balance.num, balance.denom);
|
||||
for (auto split : priv->splits)
|
||||
{
|
||||
gnc_numeric amt = xaccSplitGetAmount (split);
|
||||
auto amt = xaccSplitGetAmount (split);
|
||||
|
||||
balance = gnc_numeric_add_fixed(balance, amt);
|
||||
if (xaccSplitIsStockSplit(split))
|
||||
{
|
||||
if (gnc_numeric_zero_p(balance))
|
||||
continue;
|
||||
auto new_balance = gnc_numeric_add_fixed(balance, amt);
|
||||
if (gnc_numeric_zero_p(new_balance))
|
||||
continue;
|
||||
auto ratio = gnc_numeric_div(new_balance, balance, GNC_DENOM_AUTO,
|
||||
GNC_HOW_DENOM_REDUCE);
|
||||
auto denom = xaccAccountGetCommoditySCU(acc);
|
||||
for (auto psplit : priv->splits)
|
||||
{
|
||||
if (psplit == split)
|
||||
break;
|
||||
xaccSplitSetAdjustedAmount(psplit,
|
||||
gnc_numeric_mul(xaccSplitGetAdjustedAmount(psplit), ratio, denom,
|
||||
GNC_HOW_RND_ROUND_HALF_UP));
|
||||
}
|
||||
balance = new_balance;
|
||||
has_stock_split = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
split->adjusted_amount = amt;
|
||||
balance = gnc_numeric_add_fixed(balance, amt);
|
||||
}
|
||||
|
||||
if (NREC != split->reconciled)
|
||||
{
|
||||
@@ -2330,6 +2348,7 @@ xaccAccountRecomputeBalance (Account * acc)
|
||||
priv->cleared_balance = cleared_balance;
|
||||
priv->reconciled_balance = reconciled_balance;
|
||||
priv->balance_dirty = FALSE;
|
||||
priv->has_stock_split = has_stock_split;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
@@ -3484,6 +3503,13 @@ xaccAccountGetProjectedMinimumBalance (const Account *acc)
|
||||
return minimum ? *minimum : gnc_numeric_zero();
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccAccountHasStockSplit (const Account *acc)
|
||||
{
|
||||
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), false);
|
||||
return GET_PRIVATE(acc)->has_stock_split;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
@@ -3935,7 +3961,8 @@ xaccAccountGetSplitsSize (const Account *account)
|
||||
return GNC_IS_ACCOUNT(account) ? GET_PRIVATE(account)->splits.size() : 0;
|
||||
}
|
||||
|
||||
gboolean gnc_account_and_descendants_empty (Account *acc)
|
||||
gboolean
|
||||
gnc_account_and_descendants_empty (Account *acc)
|
||||
{
|
||||
g_return_val_if_fail (GNC_IS_ACCOUNT (acc), FALSE);
|
||||
auto priv = GET_PRIVATE (acc);
|
||||
|
||||
@@ -648,6 +648,10 @@ typedef enum
|
||||
gnc_numeric xaccAccountGetBalanceChangeForPeriod (
|
||||
Account *acc, time64 date1, time64 date2, gboolean recurse);
|
||||
|
||||
/** Returns true if the account has a stock split,
|
||||
* otherwise false. */
|
||||
gboolean xaccAccountHasStockSplit (const Account *acc);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Account Children and Parents.
|
||||
|
||||
@@ -114,6 +114,7 @@ typedef struct AccountPrivate
|
||||
gnc_numeric reconciled_balance;
|
||||
|
||||
gboolean balance_dirty; /* balances in splits incorrect */
|
||||
gboolean has_stock_split; /* account includes a stock split */
|
||||
|
||||
std::vector<Split*> splits; /* list of split pointers */
|
||||
GHashTable* splits_hash;
|
||||
|
||||
@@ -68,6 +68,9 @@ restart_loop:
|
||||
{
|
||||
/* If already in lot, then no-op */
|
||||
if (split->lot) continue;
|
||||
|
||||
/* Skip stock splits */
|
||||
if (xaccSplitIsStockSplit(split)) continue;
|
||||
|
||||
/* Skip voided transactions */
|
||||
if (gnc_numeric_zero_p (split->amount) &&
|
||||
@@ -104,25 +107,33 @@ xaccLotFill (GNCLot *lot)
|
||||
/* If balance already zero, we have nothing to do. */
|
||||
if (gnc_lot_is_closed (lot))
|
||||
{
|
||||
LEAVE ("Lot Closed (lot=%s, acc=%s)", gnc_lot_get_title(lot),
|
||||
xaccAccountGetName(acc));
|
||||
return;
|
||||
LEAVE ("Lot Closed (lot=%s, acc=%s)", gnc_lot_get_title(lot),
|
||||
xaccAccountGetName(acc));
|
||||
return;
|
||||
}
|
||||
split = pcy->PolicyGetSplit (pcy, lot);
|
||||
if (!split)
|
||||
{
|
||||
LEAVE ("No Split (lot=%s, acc=%s)", gnc_lot_get_title(lot),
|
||||
xaccAccountGetName(acc));
|
||||
return; /* Handle the common case */
|
||||
LEAVE ("No Split (lot=%s, acc=%s)", gnc_lot_get_title(lot),
|
||||
xaccAccountGetName(acc));
|
||||
return; /* Handle the common case */
|
||||
}
|
||||
|
||||
/* Reject stock split transactions */
|
||||
if (xaccSplitIsStockSplit(split))
|
||||
{
|
||||
LEAVE ("Stock split transaction (lot=%s, acc=%s)",
|
||||
gnc_lot_get_title(lot), xaccAccountGetName(acc));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reject voided transactions */
|
||||
if (gnc_numeric_zero_p(split->amount) &&
|
||||
xaccTransGetVoidStatus(split->parent))
|
||||
{
|
||||
LEAVE ("Voided transaction (lot=%s, acc=%s)",
|
||||
gnc_lot_get_title(lot), xaccAccountGetName(acc));
|
||||
return;
|
||||
LEAVE ("Voided transaction (lot=%s, acc=%s)",
|
||||
gnc_lot_get_title(lot), xaccAccountGetName(acc));
|
||||
return;
|
||||
}
|
||||
|
||||
xaccAccountBeginEdit (acc);
|
||||
@@ -178,8 +189,8 @@ xaccLotScrubDoubleBalance (GNCLot *lot)
|
||||
/* We double-check only closed lots */
|
||||
if (FALSE == gnc_lot_is_closed (lot))
|
||||
{
|
||||
LEAVE ("lot=%s is closed", gnc_lot_get_title(lot));
|
||||
return;
|
||||
LEAVE ("lot=%s is closed", gnc_lot_get_title(lot));
|
||||
return;
|
||||
}
|
||||
|
||||
for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
|
||||
|
||||
+60
-13
@@ -128,6 +128,9 @@ gnc_split_init(Split* split)
|
||||
split->reconciled_balance = gnc_numeric_zero();
|
||||
split->noclosing_balance = gnc_numeric_zero();
|
||||
|
||||
split->adjusted_amount = gnc_numeric_zero();
|
||||
split->split_type = nullptr;
|
||||
|
||||
split->gains = GAINS_STATUS_UNKNOWN;
|
||||
split->gains_split = nullptr;
|
||||
}
|
||||
@@ -520,6 +523,9 @@ xaccSplitReinit(Split * split)
|
||||
split->reconciled_balance = gnc_numeric_zero();
|
||||
split->noclosing_balance = gnc_numeric_zero();
|
||||
|
||||
split->adjusted_amount = gnc_numeric_zero();
|
||||
split->split_type = nullptr;
|
||||
|
||||
qof_instance_set_idata(split, 0);
|
||||
|
||||
split->gains = GAINS_STATUS_UNKNOWN;
|
||||
@@ -604,6 +610,8 @@ xaccSplitCloneNoKvp (const Split *s)
|
||||
split->cleared_balance = s->cleared_balance;
|
||||
split->reconciled_balance = s->reconciled_balance;
|
||||
split->noclosing_balance = s->noclosing_balance;
|
||||
split->adjusted_amount = s->adjusted_amount;
|
||||
split->split_type = s->split_type;
|
||||
|
||||
split->gains = GAINS_STATUS_UNKNOWN;
|
||||
split->gains_split = nullptr;
|
||||
@@ -689,6 +697,8 @@ xaccSplitDump (const Split *split, const char *tag)
|
||||
printf(" RBalance: %s\n",
|
||||
gnc_numeric_to_string(split->reconciled_balance));
|
||||
printf(" NoClose: %s\n", gnc_numeric_to_string(split->noclosing_balance));
|
||||
printf(" AdjAmt: %s\n", gnc_numeric_to_string(split->adjusted_amount));
|
||||
printf(" Type: %s\n", split->split_type ? split->split_type : "(null)");
|
||||
printf(" idata: %x\n", qof_instance_get_idata(split));
|
||||
}
|
||||
#endif
|
||||
@@ -749,6 +759,13 @@ xaccFreeSplit (Split *split)
|
||||
split->acc = nullptr;
|
||||
split->orig_acc = nullptr;
|
||||
|
||||
split->balance = gnc_numeric_zero();
|
||||
split->cleared_balance = gnc_numeric_zero();
|
||||
split->reconciled_balance = gnc_numeric_zero();
|
||||
split->noclosing_balance = gnc_numeric_zero();
|
||||
split->adjusted_amount = gnc_numeric_zero();
|
||||
split->split_type = nullptr;
|
||||
|
||||
split->date_reconciled = 0;
|
||||
G_OBJECT_CLASS (QOF_INSTANCE_GET_CLASS (&split->inst))->dispose(G_OBJECT (split));
|
||||
|
||||
@@ -766,12 +783,11 @@ xaccFreeSplit (Split *split)
|
||||
void mark_split (Split *s)
|
||||
{
|
||||
if (s->acc)
|
||||
{
|
||||
g_object_set(s->acc, "sort-dirty", TRUE, "balance-dirty", TRUE, nullptr);
|
||||
}
|
||||
|
||||
/* set dirty flag on lot too. */
|
||||
if (s->lot) gnc_lot_set_closed_unknown(s->lot);
|
||||
if (s->lot)
|
||||
gnc_lot_set_closed_unknown(s->lot);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -915,6 +931,9 @@ xaccSplitEqual(const Split *sa, const Split *sb,
|
||||
if (!xaccSplitEqualCheckBal ("noclosing ", sa->noclosing_balance,
|
||||
sb->noclosing_balance))
|
||||
return FALSE;
|
||||
if (!xaccSplitEqualCheckBal ("adjusted ", sa->adjusted_amount,
|
||||
sb->adjusted_amount))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!xaccTransEqual(sa->parent, sb->parent, check_guids, check_txn_splits,
|
||||
@@ -1238,6 +1257,7 @@ xaccSplitSetAmount (Split *s, gnc_numeric amt)
|
||||
}
|
||||
else
|
||||
s->amount = amt;
|
||||
s->adjusted_amount = s->amount;
|
||||
|
||||
SET_GAINS_ADIRTY(s);
|
||||
mark_split (s);
|
||||
@@ -1316,6 +1336,21 @@ xaccSplitGetReconciledBalance (const Split *s)
|
||||
return s ? s->reconciled_balance : gnc_numeric_zero();
|
||||
}
|
||||
|
||||
gnc_numeric
|
||||
xaccSplitGetAdjustedAmount (const Split *s)
|
||||
{
|
||||
return s ? s->adjusted_amount : gnc_numeric_zero();
|
||||
}
|
||||
|
||||
void
|
||||
xaccSplitSetAdjustedAmount (Split *s, gnc_numeric amt)
|
||||
{
|
||||
if (!s) return;
|
||||
if (gnc_numeric_check (amt)) return;
|
||||
|
||||
s->adjusted_amount = amt;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSplitSetBaseValue (Split *s, gnc_numeric value,
|
||||
const gnc_commodity * base_currency)
|
||||
@@ -2001,20 +2036,25 @@ xaccSplitGetBook (const Split *split)
|
||||
}
|
||||
|
||||
const char *
|
||||
xaccSplitGetType(const Split *s)
|
||||
xaccSplitGetType(Split *s)
|
||||
{
|
||||
if (!s) return nullptr;
|
||||
|
||||
auto type{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(s), {"split-type"})};
|
||||
if (!s->split_type)
|
||||
{
|
||||
auto type{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE(s), {"split-type"})};
|
||||
|
||||
if (!type || !g_strcmp0 (*type, split_type_normal))
|
||||
return split_type_normal;
|
||||
|
||||
if (!g_strcmp0 (*type, split_type_stock_split))
|
||||
return split_type_stock_split;
|
||||
|
||||
PERR ("unexpected split-type %s, reset to normal.", *type);
|
||||
return split_type_normal;
|
||||
if (!type || !g_strcmp0 (*type, split_type_normal))
|
||||
s->split_type = split_type_normal;
|
||||
else if (!g_strcmp0 (*type, split_type_stock_split))
|
||||
s->split_type = split_type_stock_split;
|
||||
else
|
||||
{
|
||||
PERR ("unexpected split-type %s, reset to normal.", *type);
|
||||
s->split_type = split_type_normal;
|
||||
}
|
||||
}
|
||||
return s->split_type;
|
||||
}
|
||||
|
||||
/* reconfigure a split to be a stock split - after this, you shouldn't
|
||||
@@ -2025,6 +2065,7 @@ xaccSplitMakeStockSplit(Split *s)
|
||||
xaccTransBeginEdit (s->parent);
|
||||
|
||||
s->value = gnc_numeric_zero();
|
||||
s->split_type = split_type_stock_split;
|
||||
qof_instance_set_path_kvp<const char*> (QOF_INSTANCE(s), g_strdup(split_type_stock_split),
|
||||
{"split-type"});
|
||||
SET_GAINS_VDIRTY(s);
|
||||
@@ -2033,6 +2074,12 @@ xaccSplitMakeStockSplit(Split *s)
|
||||
xaccTransCommitEdit(s->parent);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xaccSplitIsStockSplit (Split *s)
|
||||
{
|
||||
return g_strcmp0(split_type_stock_split, xaccSplitGetType(s)) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
xaccSplitAddPeerSplit (Split *split, const Split *other_split,
|
||||
time64 timestamp)
|
||||
|
||||
@@ -345,6 +345,16 @@ gnc_numeric xaccSplitGetClearedBalance (const Split *split);
|
||||
*/
|
||||
gnc_numeric xaccSplitGetReconciledBalance (const Split *split);
|
||||
|
||||
/** Sets the stock split adjusted amount of a split.
|
||||
* @note The adjusted amount will be reset when the account is rebalanced.
|
||||
*/
|
||||
void xaccSplitSetAdjustedAmount (Split *split, gnc_numeric amount);
|
||||
|
||||
/** Returns the stock-split adjusted amount of the split in the account's commodity.
|
||||
*/
|
||||
gnc_numeric xaccSplitGetAdjustedAmount (const Split *split);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Split utility functions
|
||||
@@ -410,20 +420,18 @@ void xaccSplitMergePeerSplits (Split *split, const Split *other_split);
|
||||
*/
|
||||
Split * xaccSplitGetOtherSplit (const Split *split);
|
||||
|
||||
/** The xaccIsPeerSplit() is a convenience routine that returns TRUE
|
||||
* (a non-zero value) if the two splits share a common parent
|
||||
* transaction, else it returns FALSE (zero).
|
||||
*
|
||||
gboolean xaccIsPeerSplit (const Split *split_1, const Split *split_2);
|
||||
*/
|
||||
/** Returns the split type, which is either the string "normal", or
|
||||
* "stock-split" for a split from a stock split (pun intended? :-). */
|
||||
const char *xaccSplitGetType(const Split *s);
|
||||
* "stock-split" for a split from a stock split. */
|
||||
const char *xaccSplitGetType(Split *s);
|
||||
|
||||
/** Mark a split to be of type stock split - after this, you shouldn't
|
||||
modify the value anymore, just the amount. */
|
||||
void xaccSplitMakeStockSplit(Split *s);
|
||||
|
||||
/** Returns true if the split is of type stock split
|
||||
*/
|
||||
gboolean xaccSplitIsStockSplit(Split *s);
|
||||
|
||||
/**
|
||||
* The xaccSplitOrder(sa,sb) method is useful for sorting.
|
||||
* if sa and sb have different transactions, return their xaccTransOrder
|
||||
|
||||
@@ -115,7 +115,7 @@ struct split_s
|
||||
gnc_numeric value;
|
||||
gnc_numeric amount;
|
||||
|
||||
const gchar * split_type;
|
||||
const char *split_type;
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/* Below follow some 'temporary' fields */
|
||||
@@ -128,6 +128,9 @@ struct split_s
|
||||
gnc_numeric noclosing_balance;
|
||||
gnc_numeric cleared_balance;
|
||||
gnc_numeric reconciled_balance;
|
||||
|
||||
/* The stock-split adjusted amount */
|
||||
gnc_numeric adjusted_amount;
|
||||
};
|
||||
|
||||
struct _SplitClass
|
||||
|
||||
+184
-46
@@ -298,7 +298,7 @@ xaccSplitAssignToLot (Split *split, GNCLot *lot)
|
||||
* then we split the split into two pieces: one piece that will
|
||||
* bring the lot balance to zero, and another to be dealt with
|
||||
* later. */
|
||||
cmp = gnc_numeric_compare (gnc_numeric_abs(split->amount),
|
||||
cmp = gnc_numeric_compare (gnc_numeric_abs(xaccSplitGetAdjustedAmount (split)),
|
||||
gnc_numeric_abs(baln));
|
||||
|
||||
PINFO ("found open lot with baln=%s (%s)", gnc_num_dbg_to_string (baln),
|
||||
@@ -331,6 +331,16 @@ xaccSplitAssignToLot (Split *split, GNCLot *lot)
|
||||
trans = split->parent;
|
||||
xaccTransBeginEdit (trans);
|
||||
|
||||
/* Adjust split's view of the lot balance for stock splits */
|
||||
if (!gnc_numeric_equal (split->amount, xaccSplitGetAdjustedAmount (split)))
|
||||
{
|
||||
frac = gnc_numeric_div (split->amount, xaccSplitGetAdjustedAmount (split),
|
||||
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
|
||||
baln = gnc_numeric_mul (baln, frac,
|
||||
xaccAccountGetCommoditySCU(acc),
|
||||
GNC_HOW_RND_ROUND_HALF_UP);
|
||||
}
|
||||
|
||||
amt_tot = split->amount;
|
||||
amt_a = gnc_numeric_neg (baln);
|
||||
amt_b = gnc_numeric_sub_fixed (amt_tot, amt_a);
|
||||
@@ -476,48 +486,34 @@ xaccSplitAssign (Split *split)
|
||||
|
||||
/* ============================================================== */
|
||||
|
||||
Split *
|
||||
xaccSplitGetCapGainsSplit (const Split *split)
|
||||
static Split *
|
||||
find_split_by_type (const gchar *type, const Split *split)
|
||||
{
|
||||
GncGUID *gains_guid;
|
||||
Split *gains_split;
|
||||
GncGUID *type_guid = nullptr;
|
||||
|
||||
if (!split) return nullptr;
|
||||
|
||||
qof_instance_get (QOF_INSTANCE (split),
|
||||
"gains-split", &gains_guid,
|
||||
nullptr);
|
||||
if (!gains_guid) return nullptr;
|
||||
qof_instance_get (QOF_INSTANCE (split), type, &type_guid, nullptr);
|
||||
if (!type_guid) return nullptr;
|
||||
|
||||
/* Both splits will be in the same collection, so search there. */
|
||||
gains_split = (Split*) qof_collection_lookup_entity (
|
||||
qof_instance_get_collection(split), gains_guid);
|
||||
PINFO ("split=%p has gains-split=%p", split, gains_split);
|
||||
guid_free (gains_guid);
|
||||
return gains_split;
|
||||
auto *guid_split = (Split *) qof_collection_lookup_entity (qof_instance_get_collection (split), type_guid);
|
||||
PINFO ("split=%p has %s=%p", split, type, guid_split);
|
||||
guid_free (type_guid);
|
||||
return guid_split;
|
||||
}
|
||||
|
||||
/* ============================================================== */
|
||||
|
||||
Split *
|
||||
xaccSplitGetCapGainsSplit (const Split *split)
|
||||
{
|
||||
return find_split_by_type ("gains-split", split);
|
||||
}
|
||||
|
||||
Split *
|
||||
xaccSplitGetGainsSourceSplit (const Split *split)
|
||||
{
|
||||
GncGUID *source_guid;
|
||||
Split *source_split;
|
||||
|
||||
if (!split) return nullptr;
|
||||
|
||||
qof_instance_get (QOF_INSTANCE (split),
|
||||
"gains-source", &source_guid,
|
||||
nullptr);
|
||||
if (!source_guid) return nullptr;
|
||||
|
||||
/* Both splits will be in the same collection, so search there. */
|
||||
source_split = (Split*) qof_collection_lookup_entity(
|
||||
qof_instance_get_collection(split), source_guid);
|
||||
PINFO ("split=%p has source-split=%p", split, source_split);
|
||||
guid_free (source_guid);
|
||||
return source_split;
|
||||
return find_split_by_type ("gains-source", split);
|
||||
}
|
||||
|
||||
/* ============================================================== */
|
||||
@@ -581,7 +577,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_strcmp0 ("stock-split", xaccSplitGetType (split)) == 0)
|
||||
if (xaccSplitIsStockSplit (split))
|
||||
{
|
||||
LEAVE ("Stock split split, returning.");
|
||||
return;
|
||||
@@ -675,38 +671,38 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
|
||||
* cleans up the lot, before we get at it!
|
||||
*/
|
||||
if (0 > gnc_numeric_compare (gnc_numeric_abs(lot_amount),
|
||||
gnc_numeric_abs(split->amount)))
|
||||
gnc_numeric_abs(xaccSplitGetAdjustedAmount (split))))
|
||||
{
|
||||
GList *n;
|
||||
for (n = gnc_lot_get_split_list(lot); n; n = n->next)
|
||||
{
|
||||
Split *s = GNC_SPLIT(n->data);
|
||||
PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
|
||||
PINFO ("split adj amt=%s", gnc_num_dbg_to_string(xaccSplitGetAdjustedAmount (s)));
|
||||
}
|
||||
PERR ("Malformed Lot \"%s\"! (too thin!) "
|
||||
"opening amt=%s split amt=%s baln=%s",
|
||||
"opening amt=%s split adj amt=%s baln=%s",
|
||||
gnc_lot_get_title (lot),
|
||||
gnc_num_dbg_to_string (lot_amount),
|
||||
gnc_num_dbg_to_string (split->amount),
|
||||
gnc_num_dbg_to_string (xaccSplitGetAdjustedAmount (split)),
|
||||
gnc_num_dbg_to_string (gnc_lot_get_balance(lot)));
|
||||
return;
|
||||
}
|
||||
if ( (gnc_numeric_negative_p(lot_amount) ||
|
||||
gnc_numeric_positive_p(split->amount)) &&
|
||||
gnc_numeric_positive_p(xaccSplitGetAdjustedAmount (split))) &&
|
||||
(gnc_numeric_positive_p(lot_amount) ||
|
||||
gnc_numeric_negative_p(split->amount)))
|
||||
gnc_numeric_negative_p(xaccSplitGetAdjustedAmount (split))))
|
||||
{
|
||||
GList *n;
|
||||
for (n = gnc_lot_get_split_list(lot); n; n = n->next)
|
||||
{
|
||||
Split *s = GNC_SPLIT(n->data);
|
||||
PINFO ("split amt=%s", gnc_num_dbg_to_string(s->amount));
|
||||
PINFO ("split adj amt=%s", gnc_num_dbg_to_string(xaccSplitGetAdjustedAmount (s)));
|
||||
}
|
||||
PERR ("Malformed Lot \"%s\"! (too fat!) "
|
||||
"opening amt=%s split amt=%s baln=%s",
|
||||
"opening adj amt=%s split adj amt=%s baln=%s",
|
||||
gnc_lot_get_title (lot),
|
||||
gnc_num_dbg_to_string (lot_amount),
|
||||
gnc_num_dbg_to_string (split->amount),
|
||||
gnc_num_dbg_to_string (xaccSplitGetAdjustedAmount (split)),
|
||||
gnc_num_dbg_to_string (gnc_lot_get_balance(lot)));
|
||||
return;
|
||||
}
|
||||
@@ -719,7 +715,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
|
||||
* cap_gain = current_split_value - cost_basis
|
||||
*/
|
||||
/* Fraction of the lot that this split represents: */
|
||||
frac = gnc_numeric_div (split->amount, lot_amount,
|
||||
frac = gnc_numeric_div (xaccSplitGetAdjustedAmount (split), lot_amount,
|
||||
GNC_DENOM_AUTO,
|
||||
GNC_HOW_DENOM_REDUCE);
|
||||
/* Basis for this split: */
|
||||
@@ -729,10 +725,10 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
|
||||
/* 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",
|
||||
PINFO ("Open amt=%s val=%s; split adj amt=%s val=%s; gains=%s\n",
|
||||
gnc_num_dbg_to_string (lot_amount),
|
||||
gnc_num_dbg_to_string (lot_value),
|
||||
gnc_num_dbg_to_string (split->amount),
|
||||
gnc_num_dbg_to_string (xaccSplitGetAdjustedAmount (split)),
|
||||
gnc_num_dbg_to_string (split->value),
|
||||
gnc_num_dbg_to_string (value));
|
||||
if (gnc_numeric_check (value))
|
||||
@@ -744,7 +740,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
|
||||
xaccTransGetDescription(split->parent),
|
||||
gnc_num_dbg_to_string (lot_amount),
|
||||
gnc_num_dbg_to_string (lot_value),
|
||||
gnc_num_dbg_to_string (split->amount),
|
||||
gnc_num_dbg_to_string (xaccSplitGetAdjustedAmount (split)),
|
||||
gnc_num_dbg_to_string (split->value),
|
||||
gnc_num_dbg_to_string (value));
|
||||
return;
|
||||
@@ -752,7 +748,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
|
||||
|
||||
/* Are the cap gains zero? If not, add a balancing transaction.
|
||||
* As per design doc lots.txt: the transaction has two splits,
|
||||
* with equal & opposite values. The amt of one iz zero (so as
|
||||
* with equal & opposite values. The amt of one is zero (so as
|
||||
* not to upset the lot balance), the amt of the other is the same
|
||||
* as its value (its the realized gain/loss).
|
||||
*/
|
||||
@@ -896,6 +892,148 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
|
||||
|
||||
/* ============================================================== */
|
||||
|
||||
gnc_numeric
|
||||
xaccLotFreeSplitCapGain(Split *split, GNCLot *lot)
|
||||
{
|
||||
g_return_val_if_fail (split && lot && !split->lot, gnc_numeric_zero());
|
||||
|
||||
ENTER ("(split=%p lot=%s)", split, gnc_lot_get_title(lot));
|
||||
|
||||
auto pcy = gnc_account_get_policy (gnc_lot_get_account (lot));
|
||||
auto currency = split->parent->common_currency;
|
||||
|
||||
/* Not possible to have gains if the transaction currency and
|
||||
* account commodity are identical. */
|
||||
if (gnc_commodity_equal (currency,
|
||||
xaccAccountGetCommodity(split->acc)))
|
||||
{
|
||||
LEAVE ("Currency transfer, gains not possible, returning.");
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
|
||||
auto *esplit = gnc_lot_get_earliest_split (lot);
|
||||
if (!esplit)
|
||||
{
|
||||
LEAVE ("Lot is empty, returning.");
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
|
||||
if (xaccTransGetDate (xaccSplitGetParent (esplit)) >= xaccTransGetDate (xaccSplitGetParent (split)))
|
||||
{
|
||||
LEAVE ("Split is too early, returning.");
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
|
||||
if (xaccSplitIsStockSplit (split))
|
||||
{
|
||||
LEAVE ("Stock split split, returning.");
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
|
||||
/* If amount is zero, there's nothing to do! Amount-zero splits
|
||||
* may exist if users attempted to manually record gains. */
|
||||
if (gnc_numeric_zero_p (split->amount)) return gnc_numeric_zero();
|
||||
|
||||
/* If we got to here, then the gains really do need to be recomputed.
|
||||
* So start working things. */
|
||||
|
||||
/* Get the amount and value in this lot at the time of this transaction. */
|
||||
gnc_numeric lot_amount, lot_value;
|
||||
gnc_lot_get_balance_before (lot, split, &lot_amount, &lot_value);
|
||||
|
||||
gnc_numeric opening_amount, opening_value;
|
||||
gnc_commodity *opening_currency;
|
||||
pcy->PolicyGetLotOpening (pcy, lot, &opening_amount, &opening_value,
|
||||
&opening_currency);
|
||||
|
||||
/* Check to make sure the lot-opening currency and this split
|
||||
* use the same currency */
|
||||
if (FALSE == gnc_commodity_equiv (currency, opening_currency))
|
||||
{
|
||||
/* OK, the purchase and the sale were made in different currencies.
|
||||
* I don't know how to compute cap gains for that. This is not
|
||||
* an error. Just punt, silently.
|
||||
*/
|
||||
LEAVE ("Can't compute gains, mismatched commodities!");
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
|
||||
/* Opening amount should be larger (or equal) to current split,
|
||||
* and it should be of the opposite sign.
|
||||
* XXX This should really be a part of a scrub routine that
|
||||
* cleans up the lot, before we get at it!
|
||||
*/
|
||||
if (0 > gnc_numeric_compare (gnc_numeric_abs(lot_amount),
|
||||
gnc_numeric_abs(xaccSplitGetAdjustedAmount (split))))
|
||||
{
|
||||
for (auto *n = gnc_lot_get_split_list(lot); n; n = n->next)
|
||||
{
|
||||
auto *s = GNC_SPLIT(n->data);
|
||||
PINFO ("split adj amt=%s", gnc_num_dbg_to_string(xaccSplitGetAdjustedAmount (s)));
|
||||
}
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
if ( (gnc_numeric_negative_p(lot_amount) ||
|
||||
gnc_numeric_positive_p(xaccSplitGetAdjustedAmount (split))) &&
|
||||
(gnc_numeric_positive_p(lot_amount) ||
|
||||
gnc_numeric_negative_p(xaccSplitGetAdjustedAmount (split))))
|
||||
{
|
||||
for (auto *n = gnc_lot_get_split_list(lot); n; n = n->next)
|
||||
{
|
||||
auto *s = GNC_SPLIT(n->data);
|
||||
PINFO ("split adj amt=%s", gnc_num_dbg_to_string(xaccSplitGetAdjustedAmount (s)));
|
||||
}
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
|
||||
/* 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 = lot_value / lot_amount
|
||||
* cost_basis = purchase_price * current_split_amount
|
||||
* cap_gain = current_split_value - cost_basis
|
||||
*/
|
||||
/* Fraction of the lot that this split represents: */
|
||||
auto frac = gnc_numeric_div (xaccSplitGetAdjustedAmount (split), lot_amount,
|
||||
GNC_DENOM_AUTO,
|
||||
GNC_HOW_DENOM_REDUCE);
|
||||
/* Basis for this split: */
|
||||
auto value = gnc_numeric_mul (frac, lot_value,
|
||||
gnc_numeric_denom(opening_value),
|
||||
GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
|
||||
/* 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 adj amt=%s val=%s; gains=%s\n",
|
||||
gnc_num_dbg_to_string (lot_amount),
|
||||
gnc_num_dbg_to_string (lot_value),
|
||||
gnc_num_dbg_to_string (xaccSplitGetAdjustedAmount (split)),
|
||||
gnc_num_dbg_to_string (split->value),
|
||||
gnc_num_dbg_to_string (value));
|
||||
|
||||
if (gnc_numeric_check (value))
|
||||
{
|
||||
PERR ("Numeric overflow during gains calculation\n"
|
||||
"Acct=%s Txn=%s\n"
|
||||
"\tOpen amt=%s val=%s\n\tsplit amt=%s val=%s\n\tgains=%s\n",
|
||||
xaccAccountGetName(split->acc),
|
||||
xaccTransGetDescription(split->parent),
|
||||
gnc_num_dbg_to_string (lot_amount),
|
||||
gnc_num_dbg_to_string (lot_value),
|
||||
gnc_num_dbg_to_string (xaccSplitGetAdjustedAmount (split)),
|
||||
gnc_num_dbg_to_string (split->value),
|
||||
gnc_num_dbg_to_string (value));
|
||||
return gnc_numeric_zero();
|
||||
}
|
||||
|
||||
LEAVE ("(lot=%s)", gnc_lot_get_title(lot));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* ============================================================== */
|
||||
|
||||
gnc_numeric
|
||||
xaccSplitGetCapGains(Split * split)
|
||||
{
|
||||
|
||||
@@ -187,6 +187,20 @@ gboolean xaccSplitAssign (Split *split);
|
||||
*/
|
||||
Split * xaccSplitAssignToLot (Split *split, GNCLot *lot);
|
||||
|
||||
/** The xaccLotFreeSplitCapGain() method returns the value of capital gain
|
||||
* (if any) associated with the indicated split against the indicated
|
||||
* lot. In order for there to be any capital gain, a few things must
|
||||
* hold true about this split:
|
||||
* (1) It must have been involved in trading (for example,
|
||||
* by belonging to a stock or trading account)
|
||||
* (2) It must not be assigned to a lot.
|
||||
* (3) It cannot be the opening split of a lot; that
|
||||
* is, it must be a matching sale of an earlier purchase
|
||||
* (or vice versa).
|
||||
*/
|
||||
gnc_numeric xaccLotFreeSplitCapGain(Split *split, GNCLot *lot);
|
||||
|
||||
|
||||
/** The xaccSplitComputeCapGains() routine computes the cap gains
|
||||
* or losses for the indicated split. The gains are placed into
|
||||
* the 'gains_acct'. If the gains_acct is NULL, then the appropriate
|
||||
|
||||
@@ -505,7 +505,7 @@ gnc_lot_get_balance (GNCLot *lot)
|
||||
for (node = priv->splits; node; node = node->next)
|
||||
{
|
||||
Split *s = GNC_SPLIT(node->data);
|
||||
gnc_numeric amt = xaccSplitGetAmount (s);
|
||||
gnc_numeric amt = xaccSplitGetAdjustedAmount (s);
|
||||
baln = gnc_numeric_add_fixed (baln, amt);
|
||||
g_assert (gnc_numeric_check (baln) == GNC_ERROR_OK);
|
||||
}
|
||||
@@ -561,7 +561,7 @@ gnc_lot_get_balance_before (const GNCLot *lot, const Split *split,
|
||||
if ((ta == tb && source != target) ||
|
||||
xaccTransOrder (ta, tb) < 0)
|
||||
{
|
||||
gnc_numeric tmpval = xaccSplitGetAmount (s);
|
||||
gnc_numeric tmpval = xaccSplitGetAdjustedAmount (s);
|
||||
amt = gnc_numeric_add_fixed (amt, tmpval);
|
||||
tmpval = xaccSplitGetValue (s);
|
||||
val = gnc_numeric_add_fixed (val, tmpval);
|
||||
|
||||
@@ -119,7 +119,7 @@ static GNCLot *
|
||||
FIFOPolicyGetLot (GNCPolicy *pcy, Split *split)
|
||||
{
|
||||
if (!split) return nullptr;
|
||||
return xaccAccountFindEarliestOpenLot (split->acc, split->amount,
|
||||
return xaccAccountFindEarliestOpenLot (split->acc, xaccSplitGetAdjustedAmount (split),
|
||||
split->parent->common_currency);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ FIFOPolicyGetLotOpening (GNCPolicy *pcy,
|
||||
Split *opening_split;
|
||||
opening_split = gnc_lot_get_earliest_split(lot);
|
||||
|
||||
if (ret_amount) *ret_amount = opening_split->amount;
|
||||
if (ret_amount) *ret_amount = xaccSplitGetAdjustedAmount (opening_split);
|
||||
if (ret_value) *ret_value = opening_split->value;
|
||||
if (ret_currency) *ret_currency = opening_split->parent->common_currency;
|
||||
}
|
||||
|
||||
@@ -1565,7 +1565,7 @@ test_xaccAccountInsertRemoveLot (Fixture *fixture, gconstpointer pData)
|
||||
g_assert_cmpuint (g_list_length (p_priv->lots), == , 1);
|
||||
test_signal_assert_hits (sig1, 2);
|
||||
test_signal_assert_hits (sig4, 1);
|
||||
test_signal_assert_hits (sig2, 1);
|
||||
test_signal_assert_hits (sig2, 2);
|
||||
/* Check that removing the lot works */
|
||||
xaccAccountRemoveLot (parent, lot);
|
||||
/* The following test should fail, but it doesn't because of an
|
||||
@@ -1576,7 +1576,7 @@ test_xaccAccountInsertRemoveLot (Fixture *fixture, gconstpointer pData)
|
||||
g_assert_cmpuint (g_list_length (p_priv->lots), == , 0);
|
||||
test_signal_assert_hits (sig3, 1);
|
||||
test_signal_assert_hits (sig4, 2);
|
||||
test_signal_assert_hits (sig2, 1);
|
||||
test_signal_assert_hits (sig2, 2);
|
||||
/* Check that destroying the lot removes its reference */
|
||||
/* Because the lot's account pointer doesn't get nulled when the lot
|
||||
* is removed, we have to do that for the next test to work: */
|
||||
@@ -1635,7 +1635,7 @@ test_xaccAccountRecomputeBalance (Fixture *fixture, gconstpointer pData)
|
||||
rec_bal = gnc_numeric_add_fixed (rec_bal, p.amount);
|
||||
}
|
||||
g_assert_true (gnc_numeric_zero_p (priv->starting_balance));
|
||||
g_assert_true (gnc_numeric_zero_p (priv->balance));
|
||||
priv->cleared_balance = gnc_numeric_zero ();
|
||||
priv->balance_dirty = TRUE;
|
||||
xaccAccountRecomputeBalance (fixture->acct);
|
||||
g_assert_true (gnc_numeric_zero_p (priv->starting_balance));
|
||||
@@ -2375,6 +2375,7 @@ test_xaccAccountFindOpenLots (Fixture *fixture, gconstpointer pData)
|
||||
LotList* lots;
|
||||
|
||||
g_assert_true (acct);
|
||||
xaccAccountRecomputeBalance (acct);
|
||||
lots = xaccAccountFindOpenLots (acct, NULL, NULL, NULL);
|
||||
g_assert_true (g_list_length (lots) == 2);
|
||||
if (lots) g_list_free (lots);
|
||||
|
||||
@@ -91,6 +91,7 @@ setup (Fixture *fixture, gconstpointer pData)
|
||||
fixture->split->balance = amount;
|
||||
fixture->split->cleared_balance = amount;
|
||||
fixture->split->reconciled_balance = amount;
|
||||
fixture->split->adjusted_amount = amount;
|
||||
qof_instance_mark_clean (QOF_INSTANCE (fixture->split));
|
||||
qof_instance_mark_clean (QOF_INSTANCE (acc));
|
||||
qof_instance_mark_clean (QOF_INSTANCE (txn));
|
||||
|
||||
Reference in new issue
Block a user