More work on rebalancing.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3191 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas 2000-11-22 03:46:20 +00:00
parent c8a5c34c09
commit 737d33d7d8
11 changed files with 179 additions and 164 deletions

View File

@ -109,6 +109,7 @@
#include "FileDialog.h"
#include "MultiLedger.h"
#include "Refresh.h"
#include "Scrub.h"
#include "SplitLedger.h"
#include "global-options.h"
#include "gnc-engine-util.h"
@ -896,7 +897,7 @@ LedgerMoveCursor (Table *table, VirtualLocation *p_new_virt_loc)
/* This function determines if auto-completion is appropriate and,
* if so, performs it. This should only be called by LedgerTraverse. */
static void
static gboolean
LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
VirtualLocation *p_new_virt_loc)
{
@ -914,12 +915,12 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
/* auto-completion is only triggered by a tab out */
if (dir != GNC_TABLE_TRAVERSE_RIGHT)
return;
return FALSE;
split = xaccSRGetCurrentSplit(reg);
trans = xaccSRGetCurrentTrans(reg);
if (trans == NULL)
return;
return FALSE;
cursor_class = xaccSplitRegisterGetCurrentCursorClass(reg);
cell_type = xaccSplitRegisterGetCurrentCellType(reg);
@ -934,28 +935,28 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
/* there must be a blank transaction * */
if (blank_trans == NULL)
return;
return FALSE;
/* we must be on the blank split */
if (trans != blank_trans)
return;
return FALSE;
/* and leaving the description cell */
if (cell_type != DESC_CELL)
return;
return FALSE;
/* nothing but the date, num, and description should be changed */
if ((changed & ~(MOD_DATE | MOD_NUM | MOD_DESC)) != 0)
return;
return FALSE;
/* and the description should be changed */
if ((changed & MOD_DESC) == 0)
return;
return FALSE;
/* to a non-empty value */
desc = reg->descCell->cell.value;
if ((desc == NULL) || (*desc == '\0'))
return;
return FALSE;
/* find a transaction to auto-complete on */
if (info->default_source_account != NULL)
@ -968,7 +969,7 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
auto_trans = gnc_find_trans_in_reg_by_desc(reg, desc);
if (auto_trans == NULL)
return;
return FALSE;
xaccTransBeginEdit (trans, TRUE);
gnc_copy_trans_onto_trans (auto_trans, trans, FALSE, FALSE);
@ -1042,24 +1043,24 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
/* we must be on a blank split of a transaction */
if (split != NULL)
return;
return FALSE;
/* and leaving the memo cell */
if (cell_type != MEMO_CELL)
return;
return FALSE;
/* nothing but the action and memo should be changed */
if ((changed & ~(MOD_ACTN | MOD_MEMO)) != 0)
return;
/* nothing but the action memo, and amounts should be changed */
if ((changed & ~(MOD_ACTN | MOD_MEMO | MOD_AMNT)) != 0)
return FALSE;
/* and the memo should be changed */
if ((changed & MOD_MEMO) == 0)
return;
return FALSE;
/* to a non-empty value */
memo = reg->memoCell->cell.value;
if ((memo == NULL) || (*memo == '\0'))
return;
return FALSE;
/* if there is no price field, only auto-complete from splits with
* a unit share price. */
@ -1078,7 +1079,7 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
unit_price);
if (auto_split == NULL)
return;
return FALSE;
/* the auto-complete code below is taken from xaccSRGetEntryHandler */
@ -1095,11 +1096,14 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
xaccBasicCellSetChanged(&(reg->xfrmCell->cell), TRUE);
amount = xaccSplitGetValue (auto_split);
if (!(changed & MOD_AMNT))
{
amount = xaccSplitGetValue (auto_split);
xaccSetDebCredCellValue (reg->debitCell, reg->creditCell, amount);
xaccBasicCellSetChanged (&(reg->debitCell->cell), TRUE);
xaccBasicCellSetChanged (&(reg->creditCell->cell), TRUE);
xaccSetDebCredCellValue (reg->debitCell, reg->creditCell, amount);
xaccBasicCellSetChanged (&(reg->debitCell->cell), TRUE);
xaccBasicCellSetChanged (&(reg->creditCell->cell), TRUE);
}
/* and refresh the gui */
gnc_table_refresh_gui (reg->table);
@ -1117,6 +1121,8 @@ LedgerAutoCompletion(SplitRegister *reg, gncTableTraversalDir dir,
default:
break;
}
return TRUE;
}
/* ======================================================== */
@ -1162,12 +1168,8 @@ LedgerTraverse (Table *table,
* auto-complete. */
if (!gnc_table_virtual_cell_out_of_bounds (table, virt_loc.vcell_loc))
{
if (virt_cell_loc_equal (virt_loc.vcell_loc,
table->current_cursor_loc.vcell_loc))
{
LedgerAutoCompletion(reg, dir, p_new_virt_loc);
if (LedgerAutoCompletion(reg, dir, p_new_virt_loc))
return;
}
}
if (changed && (split == NULL) && (dir == GNC_TABLE_TRAVERSE_RIGHT))
@ -1310,7 +1312,7 @@ xaccSRGetTrans (SplitRegister *reg, VirtualCellLocation vcell_loc)
{
Split *split;
if (reg == NULL)
if (!reg || !reg->table)
return NULL;
split = sr_get_split (reg, vcell_loc);
@ -2900,7 +2902,7 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
{
gnc_numeric amount = xaccGetPriceCellValue(reg->sharesCell);
gnc_numeric price = xaccGetPriceCellValue(reg->priceCell);
DEBUG ("MOD_SHRS");
xaccSplitSetShareAmount (split, amount);
@ -2918,10 +2920,6 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
xaccSplitSetSharePrice (split, price);
}
/* The AMNT and NAMNT updates only differ by sign. Basically,
* the split cursors show minus the quants that the single,
* double and transaction cursors show, and so when updates
* happen, the extra minus sign must also be handled. */
if (MOD_AMNT & changed)
{
gnc_numeric new_amount;
@ -2934,10 +2932,12 @@ xaccSRSaveChangedCells (SplitRegister *reg, Transaction *trans, Split *split)
DEBUG ("MOD_AMNT");
/* FIXME : make sure amount gets updated? -- bg */
xaccSplitSetValue (split, new_amount);
}
if ((MOD_AMNT | MOD_PRIC | MOD_SHRS) & changed)
xaccSplitScrubImbalance (split);
return refresh_accounts;
}
@ -3028,19 +3028,53 @@ get_trans_total_balance (SplitRegister *reg, Transaction *trans)
/* ======================================================== */
const char *
xaccSRGetEntryHandler (gpointer vcell_data, short _cell_type,
gpointer user_data)
xaccSRGetEntryHandler (VirtualLocation virt_loc, short _cell_type,
gboolean *changed, gpointer user_data)
{
GUID *guid = vcell_data;
CellType cell_type = _cell_type;
SplitRegister *reg = user_data;
const char *value = "";
Transaction *trans;
Split *split;
split = xaccSplitLookup (guid);
if (changed)
*changed = FALSE;
split = sr_get_split (reg, virt_loc.vcell_loc);
if (split == NULL)
return value;
{
gnc_numeric imbalance;
trans = xaccSRGetTrans (reg, virt_loc.vcell_loc);
imbalance = xaccTransGetImbalance (trans);
if (gnc_numeric_zero_p (imbalance))
return value;
switch (cell_type)
{
case CRED_CELL:
case DEBT_CELL:
imbalance = gnc_numeric_neg (imbalance);
if (gnc_numeric_negative_p (imbalance) && (cell_type == DEBT_CELL))
return "";
if (gnc_numeric_positive_p (imbalance) && (cell_type == CRED_CELL))
return "";
if (changed)
*changed = TRUE;
imbalance = gnc_numeric_abs (imbalance);
return xaccPrintAmount (imbalance,
gnc_split_value_print_info (split, FALSE));
default:
return value;
}
}
trans = xaccSplitGetParent (split);
@ -3421,10 +3455,13 @@ xaccSRGetBGColorHandler (VirtualLocation virt_loc, gpointer user_data)
case CURSOR_TYPE_SPLIT:
{
Split *split = sr_get_split (reg, virt_loc.vcell_loc);
Transaction *trans = xaccSplitGetParent (split);
Transaction *trans;
gnc_numeric imbalance;
if (split && (split == xaccTransGetBalanceSplit (trans)))
trans = xaccSRGetTrans (reg, virt_loc.vcell_loc);
imbalance = xaccTransGetImbalance (trans);
if (!gnc_numeric_zero_p (imbalance))
return 0xffff00;
if (is_current)

View File

@ -203,7 +203,9 @@ void xaccSetSplitRegisterColors (SplitRegisterColors reg_colors);
void xaccSetSplitRegisterColorizeNegative (gboolean use_red);
/* Private function, for MultiLedger.c only */
const char * xaccSRGetEntryHandler (gpointer vcell_data, short _cell_type,
const char * xaccSRGetEntryHandler (VirtualLocation virt_loc,
short _cell_type,
gboolean *changed,
gpointer user_data);
guint32 xaccSRGetFGColorHandler (VirtualLocation virt_loc,
gpointer user_data);

View File

@ -440,10 +440,10 @@ xaccAccountInsertSplit ( Account *acc, Split *split ) {
{
Account *oldacc;
CHECK (acc);
acc->balance_dirty = TRUE;
acc->sort_dirty = TRUE;
/* convert the split to the new account's denominators */
/* if the denominator can't be exactly converted, it's an error */
/* FIXME : need to enforce ordering of insertion/value */
@ -462,7 +462,7 @@ xaccAccountInsertSplit ( Account *acc, Split *split ) {
oldacc = split->acc;
if (split->acc) xaccAccountRemoveSplit (split->acc, split);
split->acc = acc;
if(acc->editlevel == 1) {
acc->splits = g_list_insert_sorted(acc->splits, split, split_sort_func);
acc->sort_dirty = FALSE;

View File

@ -144,26 +144,20 @@ xaccAccountScrubImbalance (Account *acc)
void
xaccTransScrubImbalance (Transaction *trans)
{
Split *balance_split;
Split *balance_split = NULL;
gnc_numeric imbalance;
gboolean trans_was_open;
gboolean had_balance_split;
if (!trans)
return;
trans_was_open = xaccTransIsOpen (trans);
balance_split = xaccTransGetBalanceSplit (trans);
had_balance_split = balance_split != NULL;
if (!had_balance_split)
{
GList *node;
Account *account;
Account *peer = NULL;
for (node = trans->splits; node; node = node->next)
xaccSplitScrubImbalance (node->data);
imbalance = xaccTransGetImbalance (trans);
if (gnc_numeric_zero_p (imbalance))
return;
@ -192,34 +186,18 @@ xaccTransScrubImbalance (Transaction *trans)
xaccAccountInsertSplit (account, balance_split);
xaccAccountCommitEdit (account);
}
else
{
const gnc_commodity * currency = xaccTransFindCommonCurrency (trans);
imbalance = xaccSplitsComputeValue (trans->splits,
balance_split, currency);
if (gnc_numeric_zero_p (imbalance)) /* balances without balance split */
{
if (!trans_was_open)
xaccTransBeginEdit (trans, TRUE);
xaccSplitDestroy (balance_split);
xaccTransSetBalanceSplit (trans, NULL);
if (!trans_was_open)
xaccTransCommitEdit (trans);
return;
}
imbalance = xaccTransGetImbalance (trans);
}
PWARN ("unbalanced transaction: %s",
guid_to_string (xaccTransGetGUID (trans)));
{
const gnc_commodity *common_currency;
const gnc_commodity *commodity;
gboolean trans_was_open;
Account *account;
trans_was_open = xaccTransIsOpen (trans);
if (!trans_was_open)
xaccTransBeginEdit (trans, TRUE);
@ -235,30 +213,68 @@ xaccTransScrubImbalance (Transaction *trans)
xaccSplitSetValue (balance_split, new_value);
}
else
commodity = xaccAccountGetSecurity (account);
if (gnc_commodity_equiv (common_currency, commodity))
{
commodity = xaccAccountGetSecurity (account);
if (gnc_commodity_equiv (common_currency, commodity))
{
gnc_numeric new_share_amount = xaccSplitGetShareAmount (balance_split);
gnc_numeric new_share_amount = xaccSplitGetShareAmount (balance_split);
new_share_amount = gnc_numeric_sub_fixed (new_share_amount, imbalance);
new_share_amount = gnc_numeric_sub_fixed (new_share_amount, imbalance);
xaccSplitSetShareAmount (balance_split, new_share_amount);
}
xaccSplitSetShareAmount (balance_split, new_share_amount);
}
if (!had_balance_split)
{
xaccTransAppendSplit (trans, balance_split);
xaccTransSetBalanceSplit (trans, balance_split);
}
xaccTransAppendSplit (trans, balance_split);
if (!trans_was_open)
xaccTransCommitEdit (trans);
}
}
void xaccSplitScrubImbalance (Split *split)
{
Account *account;
Transaction *trans;
gboolean trans_was_open;
int scu;
if (!split)
return;
trans = xaccSplitGetParent (split);
if (!trans)
return;
account = xaccSplitGetAccount (split);
if (!account)
return;
if (!gnc_commodity_equiv (xaccAccountGetCurrency (account),
xaccAccountGetSecurity (account)))
return;
scu = MIN (xaccAccountGetCurrencySCU (account),
xaccAccountGetSecuritySCU (account));
if (gnc_numeric_same (xaccSplitGetShareAmount (split),
xaccSplitGetValue (split),
scu, GNC_RND_ROUND))
return;
PWARN ("split with mismatched values: %s",
guid_to_string (xaccSplitGetGUID (split)));
trans_was_open = xaccTransIsOpen (trans);
if (!trans_was_open)
xaccTransBeginEdit (trans, TRUE);
xaccSplitSetShareAmount (split, xaccSplitGetValue (split));
if (!trans_was_open)
xaccTransCommitEdit (trans);
}
/* ================================================================ */
static Account *

View File

@ -62,6 +62,7 @@ void xaccGroupScrubOrphans (AccountGroup *grp);
* is created to offset this amount and is added to an "imbalance"
* account.
*/
void xaccSplitScrubImbalance (Split *split);
void xaccTransScrubImbalance (Transaction *trans);
void xaccAccountScrubImbalance (Account *acc);
void xaccAccountTreeScrubImbalance (Account *acc);

View File

@ -369,7 +369,8 @@ xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price,
if (!s) return;
MARK_SPLIT(s);
s->damount = amt;
s->damount = gnc_numeric_convert(amt, get_security_denom(s), GNC_RND_ROUND);;
s->value = gnc_numeric_mul(s->damount, price,
get_currency_denom(s), GNC_RND_ROUND);
@ -424,9 +425,10 @@ DxaccSplitSetShareAmount (Split *s, double damt) {
void
xaccSplitSetShareAmount (Split *s, gnc_numeric amt) {
if(!s) return;
MARK_SPLIT(s);
s->damount = amt;
s->damount = gnc_numeric_convert(amt, get_security_denom(s), GNC_RND_ROUND);
xaccSplitRebalance (s);
}
@ -466,7 +468,7 @@ xaccSplitSetValue (Split *s, gnc_numeric amt) {
if(!s) return;
MARK_SPLIT(s);
s->value = amt;
s->value = gnc_numeric_convert(amt, get_currency_denom(s), GNC_RND_ROUND);;
xaccSplitRebalance (s);
}
@ -970,55 +972,13 @@ xaccSplitsComputeValue (GList *splits, Split * skip_me,
gnc_numeric
xaccTransGetImbalance (Transaction * trans)
{
const gnc_commodity * currency = xaccTransFindCommonCurrency (trans);
gnc_numeric imbal = xaccSplitsComputeValue (trans->splits, NULL, currency);
return imbal;
}
Split *
xaccTransGetBalanceSplit (Transaction *trans)
{
Split *split;
kvp_value *kvp;
GUID *guid;
const gnc_commodity * currency;
if (!trans)
return NULL;
return gnc_numeric_zero ();
kvp = kvp_frame_get_slot (xaccTransGetSlots (trans), "balance-split");
if (!kvp)
return NULL;
guid = kvp_value_get_guid (kvp);
if (!guid)
return NULL;
split = xaccSplitLookup (guid);
if (g_list_find (trans->splits, split))
return split;
xaccTransSetBalanceSplit (trans, NULL);
return NULL;
}
void
xaccTransSetBalanceSplit (Transaction *trans, Split *split)
{
kvp_value *new_value;
if (!trans)
return;
if (split)
new_value = kvp_value_new_guid (xaccSplitGetGUID (split));
else
new_value = NULL;
kvp_frame_set_slot(xaccTransGetSlots (trans), "balance-split", new_value);
if (new_value)
kvp_value_delete(new_value);
currency = xaccTransFindCommonCurrency (trans);
return xaccSplitsComputeValue (trans->splits, NULL, currency);
}
/********************************************************************\
@ -1128,6 +1088,8 @@ xaccTransFindCommonCurrency (Transaction *trans)
const gnc_commodity * ra, * rb;
Split *split;
if (!trans) return NULL;
if (trans->splits == NULL) return NULL;
split = trans->splits->data;
@ -1143,6 +1105,7 @@ xaccTransFindCommonCurrency (Transaction *trans)
const gnc_commodity *
xaccTransIsCommonCurrency (Transaction *trans, const gnc_commodity * ra)
{
if (!trans) return NULL;
return FindCommonCurrency (trans->splits, ra, NULL);
}
@ -1151,6 +1114,7 @@ xaccTransIsCommonExclSCurrency (Transaction *trans,
const gnc_commodity * ra,
Split *excl_split)
{
if (!trans) return NULL;
return FindCommonExclSCurrency (trans->splits, ra, NULL, excl_split);
}
@ -1166,6 +1130,8 @@ xaccTransIsCommonExclSCurrency (Transaction *trans,
static void
xaccTransRebalance (Transaction * trans)
{
return;
if (!trans || !trans->splits)
return;
@ -1179,6 +1145,13 @@ xaccSplitRebalance (Split *split)
gnc_numeric value;
const gnc_commodity * base_currency = NULL;
#if 0
if (split->acc &&
gnc_commodity_equiv (xaccAccountGetCurrency (split->acc),
xaccAccountGetSecurity (split->acc)))
split->damount = split->value;
#endif
/* let's see how we do without all this stuff */
return;

View File

@ -296,13 +296,6 @@ xaccTransIsCommonExclSCurrency (Transaction *trans,
*/
gnc_numeric xaccTransGetImbalance (Transaction * trans);
/* The xaccTransGetBalanceSplit method returns the 'balance' split of
* a transaction or NULL if there is no balance split. The balance
* split is an 'artificial' split created to make the transaction
* balance. This split is automatically managed by the rebalancing
* routines and is created and destroyed as needed. */
Split * xaccTransGetBalanceSplit (Transaction *trans);
/* ------------- splits --------------- */
Split * xaccMallocSplit (void);

View File

@ -197,7 +197,4 @@ void xaccFreeSplit (Split *split); /* frees memory */
gnc_numeric xaccSplitsComputeValue (GList *splits, Split * skip_me,
const gnc_commodity * base_currency);
/* Set the balance split of a transaction. */
void xaccTransSetBalanceSplit (Transaction *trans, Split *split);
#endif /* __XACC_TRANSACTION_P_H__ */

View File

@ -36,13 +36,6 @@ Please put the keys in alphabetical order.
--------------------------------------------------------------------------
Name: balance-split
Type: GUID
Entities: Transaction
Use: xaccTransGetBalanceSplit, xaccTransSetBalanceSplit
Store the GUID of the 'balance' split of a transaction.
This split, if present, ensures the transaction is balanced.
Name: memo
Type: string
Entities: Split

View File

@ -167,7 +167,8 @@ gnc_table_get_header_cell (Table *table)
/* ==================================================== */
static const char *
gnc_table_get_entry_internal (Table *table, VirtualLocation virt_loc)
gnc_table_get_entry_internal (Table *table, VirtualLocation virt_loc,
gboolean *changed)
{
VirtualCell *vcell;
CellBlockCell *cb_cell;
@ -184,7 +185,7 @@ gnc_table_get_entry_internal (Table *table, VirtualLocation virt_loc)
if (cb_cell->cell_type < 0)
return "";
return table->entry_handler (vcell->vcell_data, cb_cell->cell_type,
return table->entry_handler (virt_loc, cb_cell->cell_type, changed,
table->handler_user_data);
}
@ -216,7 +217,7 @@ gnc_table_get_entry (Table *table, VirtualLocation virt_loc)
return cb_cell->cell->value;
}
return table->entry_handler (vcell->vcell_data, cb_cell->cell_type,
return table->entry_handler (virt_loc, cb_cell->cell_type, NULL,
table->handler_user_data);
}
@ -602,12 +603,13 @@ gnc_table_move_cursor_internal (Table *table,
if (XACC_CELL_ALLOW_SHADOW & (cell->input_output))
{
const char *entry;
gboolean changed = FALSE;
entry = gnc_table_get_entry_internal (table, virt_loc);
entry = gnc_table_get_entry_internal (table, virt_loc, &changed);
xaccSetBasicCellValue (cell, entry);
cell->changed = 0;
cell->changed = changed ? GNC_CELL_CHANGED : 0;
}
}
}

View File

@ -150,8 +150,9 @@ typedef void (*TableSetHelpFunc) (Table *table,
typedef void (*TableDestroyFunc) (Table *table);
typedef const char * (*TableGetEntryHandler) (gpointer vcell_data,
typedef const char * (*TableGetEntryHandler) (VirtualLocation virt_loc,
short cell_type,
gboolean *changed,
gpointer user_data);
typedef guint32 (*TableGetFGColorHandler) (VirtualLocation virt_loc,