From f559c850a37fb875e72ceb264f902707903084a2 Mon Sep 17 00:00:00 2001 From: Derek Atkins Date: Sat, 7 Dec 2002 22:37:50 +0000 Subject: [PATCH] * src/register/ledger-core/split-register-control.c: - Don't grab the register account for multi-split txns. Just return NULL. - Better logic in the exchange-rate handler function for when to pop up the dialog, and what to put into it. - add an error dialog for corner cases where we want to force the user to expand the txn in order to get proper conversions. * src/register/ledger-core/split-register-model-save.c: - export "split_needs_amount()" for use elsewhere - fix the logic in handling debcred changes, in particular for multi-currency cases. Convert amount->value->amount properly. - handle the case where you change the exchange-rate manually (and do nothing else). - fix the logic in the save-split post-processing for what gets converted when. * src/register/ledger-core/split-register-p.h: - export the "split_needs_amount()" api for use in the register. FIXES bug #100489 git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@7648 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 24 ++++ .../ledger-core/split-register-control.c | 45 +++++-- .../ledger-core/split-register-model-save.c | 123 +++++++++++++----- src/register/ledger-core/split-register-p.h | 1 + 4 files changed, 148 insertions(+), 45 deletions(-) diff --git a/ChangeLog b/ChangeLog index f9a4c52908..1f615e8736 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2002-12-07 Derek Atkins + + * src/register/ledger-core/split-register-control.c: + - Don't grab the register account for multi-split txns. Just return NULL. + - Better logic in the exchange-rate handler function for when to + pop up the dialog, and what to put into it. + - add an error dialog for corner cases where we want to force + the user to expand the txn in order to get proper conversions. + + * src/register/ledger-core/split-register-model-save.c: + - export "split_needs_amount()" for use elsewhere + - fix the logic in handling debcred changes, in particular for + multi-currency cases. Convert amount->value->amount properly. + - handle the case where you change the exchange-rate manually + (and do nothing else). + - fix the logic in the save-split post-processing for what gets + converted when. + + * src/register/ledger-core/split-register-p.h: + - export the "split_needs_amount()" api for use in the register. + + FIXES bug #100489 + + 2002-12-7 Benoit Grégoire More Doxygenification. Created an Engine module, and a Deprecated list. Unfortunately, unless we turn on EXTRACT_ALL diff --git a/src/register/ledger-core/split-register-control.c b/src/register/ledger-core/split-register-control.c index 8074aa9230..96c820df86 100644 --- a/src/register/ledger-core/split-register-control.c +++ b/src/register/ledger-core/split-register-control.c @@ -961,8 +961,8 @@ gnc_split_register_traverse_check_stock_shares (SplitRegister *reg, const char * } static Account * -gnc_split_register_get_account_always (SplitRegister *reg, const char * cell_name, - gboolean force) +gnc_split_register_get_account_always (SplitRegister *reg, const char * cell_name) + { BasicCell *cell; const char *name; @@ -975,10 +975,7 @@ gnc_split_register_get_account_always (SplitRegister *reg, const char * cell_nam /* If 'name' is "-- Split Transaction --" then return NULL or the register acct */ if (!safe_strcmp (name, _("-- Split Transaction --"))) { - if (force) - return gnc_split_register_get_default_account (reg); - else - return NULL; + return NULL; } return gnc_split_register_get_account_by_name (reg, cell, name, &dummy); @@ -1021,15 +1018,15 @@ gboolean gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog) { Transaction *txn; - Split *osplit; + Split *split, *osplit; Account *xfer_acc, *reg_acc; gnc_commodity *txn_cur, *xfer_com, *reg_com; gnc_numeric amount, exch_rate; XferDialog *xfer; - gboolean used_mxfrm = FALSE; gboolean swap_amounts = FALSE; gboolean expanded = FALSE; PriceCell *rate_cell; + const char *message; /* Make sure we NEED this for this type of register */ rate_cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL); @@ -1045,12 +1042,21 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog) expanded = gnc_split_register_current_trans_expanded (reg); /* Grab the xfer account */ - xfer_acc = gnc_split_register_get_account_always (reg, XFRM_CELL, FALSE); - if (!xfer_acc) { - used_mxfrm = TRUE; - xfer_acc = gnc_split_register_get_account_always (reg, MXFRM_CELL, !expanded); + if (expanded) + xfer_acc = gnc_split_register_get_account_always (reg, XFRM_CELL); + else + xfer_acc = gnc_split_register_get_account_always (reg, MXFRM_CELL); + + message = + _("You need to expand the transaction in order to modify its exchange rates."); + + /* If this is an un-expanded, multi-split transaction, then warn the user */ + if (force_dialog && !expanded && ! xfer_acc) { + gnc_error_dialog (message); + return TRUE; } + /* No account -- don't run the dialog */ if (!xfer_acc) return FALSE; @@ -1064,8 +1070,8 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog) reg_com = xaccAccountGetCommodity (reg_acc); /* Is this a two-split txn? */ - osplit = gnc_split_register_get_current_split (reg); - osplit = xaccSplitGetOtherSplit (osplit); + split = gnc_split_register_get_current_split (reg); + osplit = xaccSplitGetOtherSplit (split); /* Check if the txn- and xfer- commodities are the same */ if (gnc_commodity_equal (txn_cur, xfer_com)) { @@ -1088,6 +1094,17 @@ gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog) return FALSE; } + /* If this is a non-expanded, two-split txn where BOTH splits need + * conversion rates, then require the user to actually expand the + * transaction in order to edit it. + */ + if (!expanded && osplit && + gnc_split_register_split_needs_amount (split) && + gnc_split_register_split_needs_amount (osplit)) { + gnc_error_dialog (message); + return TRUE; + } + /* Ok, we need to grab the exchange rate */ amount = gnc_split_register_debcred_cell_value (reg); diff --git a/src/register/ledger-core/split-register-model-save.c b/src/register/ledger-core/split-register-model-save.c index 381068a577..dcdf0482a3 100644 --- a/src/register/ledger-core/split-register-model-save.c +++ b/src/register/ledger-core/split-register-model-save.c @@ -370,7 +370,7 @@ gnc_split_register_get_rate_cell (SplitRegister *reg, const char *cell_name) return gnc_numeric_create (100,100); } -static gboolean +gboolean gnc_split_register_split_needs_amount (Split *split) { Transaction *txn = xaccSplitGetParent (split); @@ -387,7 +387,7 @@ gnc_split_register_save_debcred_cell (BasicCell * bcell, SRSaveData *sd = save_data; SplitRegister *reg = user_data; Account *acc; - gnc_numeric new_amount, convrate, oldconvrate, value; + gnc_numeric new_amount, convrate, amtconv, value; g_return_if_fail (gnc_basic_cell_has_name (bcell, DEBT_CELL) || gnc_basic_cell_has_name (bcell, CRED_CELL)); @@ -405,43 +405,53 @@ gnc_split_register_save_debcred_cell (BasicCell * bcell, * 'value' by dividing by the convrate in order to set the value. */ - /* First, compute the "old" conversion rate -- use the RATE_CELL if it - * exists -- if not, then compute from the old amount/value + /* First, compute the conversion rate to convert the value to the + * amount. Use the RATE_CELL (if it exists) -- if not, then assume + * it is 1. */ - oldconvrate = gnc_split_register_get_rate_cell (reg, RATE_CELL); - if (gnc_numeric_zero_p (oldconvrate)) { - convrate = xaccSplitGetAmount (sd->split); - value = xaccSplitGetValue (sd->split); + convrate = gnc_split_register_get_rate_cell (reg, RATE_CELL); + if (gnc_numeric_zero_p (convrate)) + convrate = gnc_numeric_create (100,100); - if (! gnc_numeric_zero_p (value)) - oldconvrate = gnc_numeric_div (convrate, value, GNC_DENOM_AUTO, GNC_DENOM_REDUCE); - else - oldconvrate = gnc_numeric_create (100,100); - } - - /* Now compute/set the split value */ + /* Now compute/set the split value. Amount is in the register + * currency but we need to convert to the txn currency. + */ acc = gnc_split_register_get_default_account (reg); if (gnc_split_register_needs_conv_rate (sd->trans, acc)) { - gnc_commodity *curr; + gnc_commodity *curr, *reg_com, *xfer_com; + Account *xfer_acc; + + xfer_acc = xaccSplitGetAccount (sd->split); + xfer_com = xaccAccountGetCommodity (xfer_acc); + reg_com = xaccAccountGetCommodity (acc); + + /* If we are in an expanded register and the xfer_acc->comm != + * reg_acc->comm then we need to compute the convrate here. + * Otherwise, we _can_ use the rate_cell! + */ + if (sd->reg_expanded && ! gnc_commodity_equal (reg_com, xfer_com)) + amtconv = gnc_split_register_get_conv_rate (sd->trans, acc); + else + amtconv = convrate; /* convert the amount to the Value ... */ - convrate = gnc_split_register_get_conv_rate (sd->trans, acc); curr = xaccTransGetCurrency (sd->trans); - value = gnc_numeric_div (new_amount, convrate, + value = gnc_numeric_div (new_amount, amtconv, gnc_commodity_get_fraction (curr), GNC_RND_ROUND); xaccSplitSetValue (sd->split, value); } else xaccSplitSetValue (sd->split, new_amount); - /* Now re-compute the Amount -- We may need to convert from the Value back - * to the amount here using the conversion in the rate-cell. + /* Now re-compute the Amount from the Value. We may need to convert + * from the Value back to the amount here using the convrate from + * earlier. */ value = xaccSplitGetValue (sd->split); if (gnc_split_register_split_needs_amount (sd->split)) { acc = xaccSplitGetAccount (sd->split); - new_amount = gnc_numeric_mul (value, oldconvrate, + new_amount = gnc_numeric_mul (value, convrate, xaccAccountGetCommoditySCU (acc), GNC_RND_ROUND); xaccSplitSetAmount (sd->split, new_amount); @@ -451,6 +461,17 @@ gnc_split_register_save_debcred_cell (BasicCell * bcell, sd->do_scrub = TRUE; } +static void +gnc_split_register_save_rate_cell (BasicCell * bcell, + gpointer save_data, + gpointer user_data) +{ + SRSaveData *sd = save_data; + + /* if the exchrate cell changed, then make sure to force a scrub */ + sd->do_scrub = TRUE; +} + static void gnc_split_register_save_cells (gpointer save_data, gpointer user_data) @@ -458,6 +479,7 @@ gnc_split_register_save_cells (gpointer save_data, SRSaveData *sd = save_data; SplitRegister *reg = user_data; Split *other_split; + gnc_commodity *txn_cur; gnc_numeric rate = gnc_numeric_zero(); g_return_if_fail (sd != NULL); @@ -466,6 +488,7 @@ gnc_split_register_save_cells (gpointer save_data, return; other_split = xaccSplitGetOtherSplit (sd->split); + txn_cur = xaccTransGetCurrency (sd->trans); xaccSplitScrub (sd->split); @@ -473,23 +496,47 @@ gnc_split_register_save_cells (gpointer save_data, if (other_split && !sd->reg_expanded) { - gnc_numeric value = xaccSplitGetValue (sd->split); + gnc_numeric amount, value = xaccSplitGetValue (sd->split); + Account *acc; + gboolean split_needs_amount; + split_needs_amount = gnc_split_register_split_needs_amount (sd->split); + + /* We are changing the rate on the current split, but it was not + * handled in the debcred handler, so we need to do it here. + */ + if (!sd->handled_dc && split_needs_amount && !gnc_numeric_zero_p (rate)) + { + gnc_numeric amount = xaccSplitGetAmount (sd->split); + value = gnc_numeric_div (amount, rate, gnc_commodity_get_fraction (txn_cur), + GNC_RND_ROUND); + xaccSplitSetValue (sd->split, value); + + /* XXX: do we need to set the amount on the other split? */ + } + + /* Now reverse the value for the other split */ value = gnc_numeric_neg (value); if (gnc_split_register_split_needs_amount (other_split)) { - Account *acc = xaccSplitGetAccount (other_split); - gnc_numeric amount; + acc = xaccSplitGetAccount (other_split); - if (gnc_numeric_zero_p (rate)) + /* If we don't have an exchange rate then figure it out. Or, if + * BOTH splits require an amount, then most likely we're in the + * strange case of having a transaction currency different than + * _both_ accounts -- so grab the other exchange rate. + */ + if (gnc_numeric_zero_p (rate) || split_needs_amount) rate = gnc_split_register_get_conv_rate (xaccSplitGetParent (other_split), acc); amount = gnc_numeric_mul (value, rate, xaccAccountGetCommoditySCU (acc), GNC_RND_ROUND); xaccSplitSetAmount (other_split, amount); + } + xaccSplitSetValue (other_split, value); xaccSplitScrub (other_split); @@ -497,13 +544,23 @@ gnc_split_register_save_cells (gpointer save_data, else if (gnc_split_register_split_needs_amount (sd->split) && ! gnc_numeric_zero_p (rate)) { - Account *acc = xaccSplitGetAccount (sd->split); - gnc_numeric value, amount; + /* this is either a multi-split or expanded transaction, so only + * deal with this split... In particular we need to reset the + * Value if the conv-rate changed. + * + * If we handled the debcred then no need to do anything there -- + * the debcred handler did all the computation. If NOT, then the + * convrate changed -- reset the value from the amount. + */ + if (!sd->handled_dc) + { + gnc_numeric value, amount; - value = xaccSplitGetValue (sd->split); - amount = gnc_numeric_mul (value, rate, xaccAccountGetCommoditySCU (acc), - GNC_RND_ROUND); - xaccSplitSetAmount (sd->split, amount); + amount = xaccSplitGetAmount (sd->split); + value = gnc_numeric_div (amount, rate, gnc_commodity_get_fraction (txn_cur), + GNC_RND_ROUND); + xaccSplitSetValue (sd->split, value); + } } } @@ -701,6 +758,10 @@ gnc_split_register_model_add_save_handlers (TableModel *model) gnc_split_register_save_debcred_cell, CRED_CELL); + gnc_table_model_set_save_handler (model, + gnc_split_register_save_rate_cell, + RATE_CELL); + gnc_table_model_set_post_save_handler (model, gnc_split_register_save_cells); } diff --git a/src/register/ledger-core/split-register-p.h b/src/register/ledger-core/split-register-p.h index c5c7b753fb..bd7e91af3f 100644 --- a/src/register/ledger-core/split-register-p.h +++ b/src/register/ledger-core/split-register-p.h @@ -163,6 +163,7 @@ gnc_numeric gnc_split_register_debcred_cell_value (SplitRegister *reg); /* Determine if we need to perform any conversion on the splits in this * transaction, and if so, what conversion we need */ +gboolean gnc_split_register_split_needs_amount (Split *split); gboolean gnc_split_register_needs_conv_rate (Transaction *txn, Account *acc); gnc_numeric gnc_split_register_get_conv_rate (Transaction *txn, Account *acc);