From f61704ccc61ab2d024e531eb6c4504346ff17d51 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Sat, 6 Sep 2003 15:02:21 +0000 Subject: [PATCH] merege from the cap-gains3 branch: remove some obsolete functions wrap amount/value geters so that gains can be auto-computed git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@9248 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/engine/Account.c | 29 ++-- src/engine/Scrub.c | 17 +- src/engine/TransLog.c | 54 ++++--- src/engine/Transaction.c | 288 ++++++++++++++++------------------ src/engine/Transaction.h | 42 ++--- src/engine/TransactionP.h | 39 +++-- src/engine/cap-gains.c | 63 +++++++- src/engine/gw-engine-spec.scm | 8 - 8 files changed, 285 insertions(+), 255 deletions(-) diff --git a/src/engine/Account.c b/src/engine/Account.c index a912709dcc..9605650055 100644 --- a/src/engine/Account.c +++ b/src/engine/Account.c @@ -1038,6 +1038,7 @@ void xaccAccountInsertSplit (Account *acc, Split *split) { Transaction *trans; + gnc_numeric old_amt; if (!acc) return; if (!split) return; @@ -1047,6 +1048,7 @@ xaccAccountInsertSplit (Account *acc, Split *split) g_return_if_fail (acc->book == split->book); trans = xaccSplitGetParent (split); + old_amt = xaccSplitGetAmount (split); xaccAccountBeginEdit(acc); xaccTransBeginEdit(trans); @@ -1054,13 +1056,6 @@ xaccAccountInsertSplit (Account *acc, Split *split) acc->balance_dirty = TRUE; acc->sort_dirty = TRUE; - /* Convert the split to the new account's denominator */ - /* If the denominator can't be exactly converted, it's an error */ - /* FIXME : need to enforce ordering of insertion/value */ - split->amount = gnc_numeric_convert(split->amount, - xaccAccountGetCommoditySCU(acc), - GNC_RND_ROUND); - /* If this split belongs to another account, remove it from there * first. We don't want to ever leave the system in an inconsistent * state. Note that it might belong to the current account if we're @@ -1090,10 +1085,11 @@ xaccAccountInsertSplit (Account *acc, Split *split) } mark_account (acc); - if (split->parent) - gnc_engine_generate_event (&split->parent->guid, GNC_ID_TRANS, GNC_EVENT_MODIFY); } + /* Setting the amount casues a conversion to the new account's + * denominator AKA 'SCU Smallest Currency Unit'. */ + xaccSplitSetAmount(split, old_amt); xaccTransCommitEdit(trans); xaccAccountCommitEdit(acc); LEAVE ("(acc=%p, split=%p)", acc, split); @@ -1197,16 +1193,17 @@ xaccAccountRecomputeBalance (Account * acc) for(lp = acc->splits; lp; lp = lp->next) { Split *split = (Split *) lp->data; + gnc_numeric amt = xaccSplitGetAmount (split); - balance = gnc_numeric_add_fixed(balance, split->amount); + balance = gnc_numeric_add_fixed(balance, amt); if (NREC != split->reconciled) - cleared_balance = gnc_numeric_add_fixed(cleared_balance, split->amount); + cleared_balance = gnc_numeric_add_fixed(cleared_balance, amt); if (YREC == split->reconciled || FREC == split->reconciled) { reconciled_balance = - gnc_numeric_add_fixed(reconciled_balance, split->amount); + gnc_numeric_add_fixed(reconciled_balance, amt); } split->balance = balance; @@ -1459,7 +1456,7 @@ xaccAccountSetNotes (Account *acc, const char *str) xaccAccountCommitEdit(acc); } -/* FIXME : is this the right way to do this? */ +/* FIXME : is this the right way to do this? Uhh, I think so ?? */ static void update_split_commodity(Account * acc) { @@ -1474,11 +1471,11 @@ update_split_commodity(Account * acc) { Split *s = (Split *) lp->data; Transaction *trans = xaccSplitGetParent (s); + gnc_numeric amt; + amt = xaccSplitGetAmount (s); xaccTransBeginEdit (trans); - s->amount = gnc_numeric_convert(s->amount, - xaccAccountGetCommoditySCU(acc), - GNC_RND_ROUND); + xaccSplitSetAmount (s, amt); xaccTransCommitEdit (trans); } diff --git a/src/engine/Scrub.c b/src/engine/Scrub.c index 6fb3c3c139..43dcae7107 100644 --- a/src/engine/Scrub.c +++ b/src/engine/Scrub.c @@ -250,9 +250,9 @@ xaccSplitScrub (Split *split) PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\"" " old amount %s %s, new amount %s", trans->description, split->memo, - gnc_numeric_to_string (split->amount), + gnc_numeric_to_string (xaccSplitGetAmount(split)), gnc_commodity_get_mnemonic (currency), - gnc_numeric_to_string (split->value)); + gnc_numeric_to_string (xaccSplitGetValue(split))); xaccTransBeginEdit (trans); xaccSplitSetAmount (split, value); @@ -491,14 +491,15 @@ xaccTransScrubCurrency (Transaction *trans) PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\"" " old amount %s %s, new amount %s", trans->description, sp->memo, - gnc_numeric_to_string (sp->amount), + gnc_numeric_to_string (xaccSplitGetAmount(sp)), gnc_commodity_get_mnemonic (currency), - gnc_numeric_to_string (sp->value)); + gnc_numeric_to_string (xaccSplitGetValue(sp))); xaccTransBeginEdit (trans); - xaccSplitSetAmount (sp, sp->value); + xaccSplitSetAmount (sp, xaccSplitGetValue(sp)); xaccTransCommitEdit (trans); } - /*else { + /*else + { PINFO ("Ok: Split '%s' Amount %s %s, value %s %s", xaccSplitGetMemo (sp), gnc_numeric_to_string (amount), @@ -603,7 +604,7 @@ move_quote_source (Account *account, gpointer data) tz = dxaccAccountGetQuoteTZ(account); PINFO("to %8s from %s", gnc_commodity_get_mnemonic(com), - xaccAccountGetName(account)); + xaccAccountGetName(account)); gnc_commodity_set_quote_flag(com, TRUE); quote_source = gnc_quote_source_lookup_by_internal(source); if (!quote_source) @@ -633,7 +634,7 @@ xaccGroupScrubQuoteSources (AccountGroup *group, gnc_commodity_table *table) xaccAccountGroupBeginEdit (group); xaccGroupForEachAccount (group, move_quote_source, - GINT_TO_POINTER(new_style), TRUE); + GINT_TO_POINTER(new_style), TRUE); xaccAccountGroupCommitEdit (group); LEAVE("Migration done"); } diff --git a/src/engine/TransLog.c b/src/engine/TransLog.c index 21d830181a..44fcb654bb 100644 --- a/src/engine/TransLog.c +++ b/src/engine/TransLog.c @@ -141,11 +141,11 @@ xaccOpenLog (void) g_free (timestamp); /* use tab-separated fields */ - fprintf (trans_log, "mod trans_guid split_guid time_now " \ - "date_entered date_posted " \ - "acc_guid acc_name num description " \ - "notes memo action reconciled " \ - "amount value date_reconciled\n"); + fprintf (trans_log, "mod trans_guid split_guid time_now " \ + "date_entered date_posted " \ + "acc_guid acc_name num description " \ + "notes memo action reconciled " \ + "amount value date_reconciled\n"); fprintf (trans_log, "-----------------\n"); } @@ -190,23 +190,31 @@ xaccTransWriteLog (Transaction *trans, char flag) trans_notes = xaccTransGetNotes(trans); fprintf (trans_log, "===== START\n"); - for (node = trans->splits; node; node = node->next) { + for (node = trans->splits; node; node = node->next) + { Split *split = node->data; const char * accname = ""; char acc_guid_str[GUID_ENCODING_LENGTH+1]; + gnc_numeric amt,val; - if (xaccSplitGetAccount(split)){ + if (xaccSplitGetAccount(split)) + { accname = xaccAccountGetName (xaccSplitGetAccount(split)); - guid_to_string_buff(xaccAccountGetGUID(xaccSplitGetAccount(split)), - acc_guid_str); - } else { - acc_guid_str[0] = '\0'; + guid_to_string_buff(xaccAccountGetGUID(xaccSplitGetAccount(split)), + acc_guid_str); + } + else + { + acc_guid_str[0] = '\0'; } - timespecFromTime_t(&ts,split->date_reconciled.tv_sec); - gnc_timespec_to_iso8601_buff (ts, drecn); + timespecFromTime_t(&ts,split->date_reconciled.tv_sec); + gnc_timespec_to_iso8601_buff (ts, drecn); guid_to_string_buff (xaccSplitGetGUID(split), split_guid_str); + amt = xaccSplitGetAmount (split); + val = xaccSplitGetValue (split); + /* use tab-separated fields */ fprintf (trans_log, "%c\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t" @@ -216,7 +224,7 @@ xaccTransWriteLog (Transaction *trans, char flag) dnow ? dnow : "", dent ? dent : "", dpost ? dpost : "", - acc_guid_str, + acc_guid_str, accname ? accname : "", trans->num ? trans->num : "", trans->description ? trans->description : "", @@ -224,10 +232,10 @@ xaccTransWriteLog (Transaction *trans, char flag) split->memo ? split->memo : "", split->action ? split->action : "", split->reconciled, - (long long int) gnc_numeric_num(split->amount), - (long long int) gnc_numeric_denom(split->amount), - (long long int) gnc_numeric_num(split->value), - (long long int) gnc_numeric_denom(split->value), + (long long int) gnc_numeric_num(amt), + (long long int) gnc_numeric_denom(amt), + (long long int) gnc_numeric_num(val), + (long long int) gnc_numeric_denom(val), drecn ? drecn : ""); } @@ -248,12 +256,13 @@ xaccTransWriteLog (Transaction *trans, char flag) */ char * -xaccSplitAsString(Split *split, const char prefix[]) { +xaccSplitAsString(Split *split, const char prefix[]) +{ char *result = NULL; size_t result_size; FILE *stream = open_memstream(&result, &result_size); const char *split_memo = xaccSplitGetMemo(split); - const double split_value = DxaccSplitGetValue(split); + const double split_value = gnc_numeric_to_double(xaccSplitGetValue(split)); Account *split_dest = xaccSplitGetAccount(split); const char *dest_name = split_dest ? xaccAccountGetName(split_dest) : NULL; @@ -287,7 +296,8 @@ xaccTransGetDateStr (Transaction *trans) } char * -xaccTransAsString(Transaction *txn, const char prefix[]) { +xaccTransAsString(Transaction *txn, const char prefix[]) +{ char *result = NULL; size_t result_size; FILE *stream = open_memstream(&result, &result_size); @@ -295,7 +305,7 @@ xaccTransAsString(Transaction *txn, const char prefix[]) { const char *num = xaccTransGetNum(txn); const char *desc = xaccTransGetDescription(txn); const char *memo = xaccSplitGetMemo(xaccTransGetSplit(txn, 0)); - const double total = DxaccSplitGetValue(xaccTransGetSplit(txn, 0)); + const double total = gnc_numeric_to_double(xaccSplitGetValue(xaccTransGetSplit(txn, 0))); g_return_val_if_fail (stream, NULL); diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index 6a9c56beee..1003b56ca8 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -230,6 +230,9 @@ xaccSplitClone (Split *s) split->reconciled_balance = s->reconciled_balance; split->idata = 0; + split->gains = GAINS_STATUS_UNKNOWN; + split->gains_split = NULL; + qof_entity_guid_new(s->book->entity_table, &split->guid); qof_entity_store(s->book->entity_table, split, &split->guid, GNC_ID_SPLIT); @@ -395,13 +398,13 @@ xaccSplitEqual(const Split *sa, const Split *sb, return FALSE; } - if (!gnc_numeric_eq(sa->amount, sb->amount)) + if (!gnc_numeric_eq(xaccSplitGetAmount (sa), xaccSplitGetAmount (sb))) { char *str_a; char *str_b; - str_a = gnc_numeric_to_string (sa->amount); - str_b = gnc_numeric_to_string (sb->amount); + str_a = gnc_numeric_to_string (xaccSplitGetAmount (sa)); + str_b = gnc_numeric_to_string (xaccSplitGetAmount (sb)); PWARN ("amounts differ: %s vs %s", str_a, str_b); @@ -411,13 +414,13 @@ xaccSplitEqual(const Split *sa, const Split *sb, return FALSE; } - if (!gnc_numeric_eq(sa->value, sb->value)) + if (!gnc_numeric_eq(xaccSplitGetValue (sa), xaccSplitGetValue (sb))) { char *str_a; char *str_b; - str_a = gnc_numeric_to_string (sa->value); - str_b = gnc_numeric_to_string (sb->value); + str_a = gnc_numeric_to_string (xaccSplitGetValue (sa)); + str_b = gnc_numeric_to_string (xaccSplitGetValue (sb)); PWARN ("values differ: %s vs %s", str_a, str_b); @@ -524,14 +527,14 @@ xaccConfigGetForceDoubleEntry (void) /********************************************************************\ \********************************************************************/ -/* routines for marking splits dirty, and for sending out change +/* Routines for marking splits dirty, and for sending out change * events. Note that we can't just mark-n-generate-event in one * step, since sometimes we need to mark things up before its suitable * to send out a change event. */ -static void -DetermineGainStatus (Split *split) +void +xaccSplitDetermineGainStatus (Split *split) { Split *other; KvpValue *val; @@ -541,7 +544,7 @@ DetermineGainStatus (Split *split) other = xaccSplitGetCapGainsSplit (split); if (other) { - split->gains = GAINS_STATUS_VDIRTY | GAINS_STATUS_DATE_DIRTY; + split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY; split->gains_split = other; return; } @@ -560,20 +563,24 @@ DetermineGainStatus (Split *split) split->gains_split = other; return; } - split->gains = GAINS_STATUS_VDIRTY | GAINS_STATUS_DATE_DIRTY; + split->gains = GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY; } #define CHECK_GAINS_STATUS(s) \ - if (GAINS_STATUS_UNKNOWN == s->gains) DetermineGainStatus(s); + if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus(s); -#define SET_GAINS_VDIRTY(s) { \ - if (GAINS_STATUS_GAINS != s->gains) { \ - s->gains |= GAINS_STATUS_VDIRTY; \ +#define SET_GAINS_DIRTY(s,flg) { \ + if (FALSE == (GAINS_STATUS_GAINS & s->gains)) { \ + s->gains |= flg;; \ } else { \ - if (s->gains_split) s->gains_split->gains |= GAINS_STATUS_VDIRTY; \ + if (s->gains_split) s->gains_split->gains |= flg; \ } \ } +#define SET_GAINS_ADIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_ADIRTY); +#define SET_GAINS_A_VDIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_A_VDIRTY); +#define SET_GAINS_VDIRTY(s) SET_GAINS_DIRTY(s,GAINS_STATUS_VDIRTY); + G_INLINE_FUNC void mark_split (Split *s); G_INLINE_FUNC void mark_split (Split *s) { @@ -730,7 +737,7 @@ DxaccSplitSetSharePriceAndAmount (Split *s, double price, double amt) s->value = double_to_gnc_numeric(price * amt, get_currency_denom(s), GNC_RND_ROUND); - SET_GAINS_VDIRTY(s); + SET_GAINS_A_VDIRTY(s); mark_split (s); /* gen_event (s); No! only in TransCommit() ! */ } @@ -746,27 +753,19 @@ xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, s->value = gnc_numeric_mul(s->amount, price, get_currency_denom(s), GNC_RND_ROUND); - SET_GAINS_VDIRTY(s); + SET_GAINS_A_VDIRTY(s); mark_split (s); /* gen_event (s); No! only in TransCommit() ! */ } -void -DxaccSplitSetSharePrice (Split *s, double amt) -{ - xaccSplitSetSharePrice - (s, double_to_gnc_numeric(amt, GNC_DENOM_AUTO, - GNC_DENOM_SIGFIGS(PRICE_SIGFIGS) | - GNC_RND_ROUND)); -} - void xaccSplitSetSharePrice (Split *s, gnc_numeric price) { if (!s) return; check_open (s->parent); - s->value = gnc_numeric_mul(s->amount, price, get_currency_denom(s), + s->value = gnc_numeric_mul(xaccSplitGetAmount(s), + price, get_currency_denom(s), GNC_RND_ROUND); SET_GAINS_VDIRTY(s); @@ -777,15 +776,18 @@ xaccSplitSetSharePrice (Split *s, gnc_numeric price) void DxaccSplitSetShareAmount (Split *s, double damt) { - gnc_numeric old_price; + gnc_numeric old_price, old_amt; int commodity_denom = get_commodity_denom(s); gnc_numeric amt = double_to_gnc_numeric(damt, commodity_denom, GNC_RND_ROUND); if (!s) return; check_open (s->parent); - if(!gnc_numeric_zero_p(s->amount)) { - old_price = gnc_numeric_div(s->value, s->amount, GNC_DENOM_AUTO, + old_amt = xaccSplitGetAmount (s); + if(!gnc_numeric_zero_p(old_amt)) + { + old_price = gnc_numeric_div(xaccSplitGetValue (s), + old_amt, GNC_DENOM_AUTO, GNC_DENOM_REDUCE); } else { @@ -797,26 +799,11 @@ DxaccSplitSetShareAmount (Split *s, double damt) s->value = gnc_numeric_mul(s->amount, old_price, get_currency_denom(s), GNC_RND_ROUND); - SET_GAINS_VDIRTY(s); + SET_GAINS_A_VDIRTY(s); mark_split (s); /* gen_event (s); No! only in TransCommit() ! */ } -void -DxaccSplitSetAmount (Split *s, double damt) -{ - gnc_numeric amt = double_to_gnc_numeric(damt, - get_currency_denom(s), - GNC_RND_ROUND); - if (!s) return; - check_open (s->parent); - - s->amount = gnc_numeric_convert(amt, get_commodity_denom(s), GNC_RND_ROUND); - - SET_GAINS_VDIRTY(s); - mark_split (s); - /* gen_event (s); No! only in TransCommit() ! */ -} void xaccSplitSetAmount (Split *s, gnc_numeric amt) @@ -826,44 +813,11 @@ xaccSplitSetAmount (Split *s, gnc_numeric amt) s->amount = gnc_numeric_convert(amt, get_commodity_denom(s), GNC_RND_ROUND); - SET_GAINS_VDIRTY(s); + SET_GAINS_ADIRTY(s); mark_split (s); /* gen_event (s); No! only in TransCommit() ! */ } -void -DxaccSplitSetValue (Split *s, double damt) -{ - int currency_denom = get_currency_denom(s); - gnc_numeric amt = double_to_gnc_numeric(damt, - currency_denom, - GNC_RND_ROUND); - gnc_numeric old_price; - if (!s) return; - check_open (s->parent); - - if(!gnc_numeric_zero_p(s->amount)) - { - old_price = gnc_numeric_div(s->value, s->amount, GNC_DENOM_AUTO, - GNC_DENOM_REDUCE); - } - else - { - old_price = gnc_numeric_create(1, 1); - } - - s->value = gnc_numeric_convert(amt, currency_denom, GNC_RND_NEVER); - - if(!gnc_numeric_zero_p(old_price)) - { - s->amount = gnc_numeric_div(s->value, old_price, currency_denom, - GNC_RND_ROUND); - } - - SET_GAINS_VDIRTY(s); - mark_split (s); - /* gen_event (s); No! only in TransCommit() ! */ -} void xaccSplitSetValue (Split *s, gnc_numeric amt) @@ -1008,7 +962,7 @@ xaccTransSortSplits (Transaction *trans) /* first debits */ for (node = trans->splits; node; node = node->next) { split = node->data; - if (gnc_numeric_negative_p (split->value)) + if (gnc_numeric_negative_p (xaccSplitGetValue(split))) continue; new_list = g_list_append(new_list, split); } @@ -1016,7 +970,7 @@ xaccTransSortSplits (Transaction *trans) /* then credits */ for (node = trans->splits; node; node = node->next) { split = node->data; - if (!gnc_numeric_negative_p (split->value)) + if (!gnc_numeric_negative_p (xaccSplitGetValue(split))) continue; new_list = g_list_append(new_list, split); } @@ -1409,16 +1363,6 @@ xaccTransLookupDirect (GUID guid, QofBook *book) /********************************************************************\ \********************************************************************/ -void -DxaccSplitSetBaseValue (Split *s, double value, - const gnc_commodity * base_currency) -{ - xaccSplitSetBaseValue(s, - double_to_gnc_numeric(value, get_currency_denom(s), - GNC_RND_ROUND), - base_currency); -} - void xaccSplitSetBaseValue (Split *s, gnc_numeric value, const gnc_commodity * base_currency) @@ -1444,6 +1388,7 @@ xaccSplitSetBaseValue (Split *s, gnc_numeric value, { s->value = value; s->amount = value; + SET_GAINS_A_VDIRTY(s); } mark_split (s); /* gen_event (s); No! only in TransCommit() ! */ @@ -1483,6 +1428,7 @@ xaccSplitSetBaseValue (Split *s, gnc_numeric value, return; } + SET_GAINS_A_VDIRTY(s); mark_split (s); /* gen_event (s); No! only in TransCommit() ! */ } @@ -1509,7 +1455,7 @@ xaccSplitGetBaseValue (const Split *s, g_return_val_if_fail (s->acc, gnc_numeric_zero ()); } else { - return s->value; + return xaccSplitGetValue((Split *)s); } } @@ -1518,16 +1464,20 @@ xaccSplitGetBaseValue (const Split *s, /* be more precise -- the value depends on the currency we want it * expressed in. */ - if (gnc_commodity_equiv(currency, base_currency)) { - value = s->value; + if (gnc_commodity_equiv(currency, base_currency)) + { + value = xaccSplitGetValue(s); } - else if (gnc_commodity_equiv(commodity, base_currency)) { - value = s->amount; + else if (gnc_commodity_equiv(commodity, base_currency)) + { + value = xaccSplitGetAmount (s); } - else if ((NULL == base_currency) && (0 == force_double_entry)) { - value = s->value; + else if ((NULL == base_currency) && (0 == force_double_entry)) + { + value = xaccSplitGetValue(s); } - else { + else + { PERR ("inappropriate base currency %s " "given split currency=%s and commodity=%s\n", gnc_commodity_get_printname(base_currency), @@ -1570,13 +1520,13 @@ xaccSplitsComputeValue (GList *splits, Split * skip_me, } else { - value = gnc_numeric_add(value, s->value, + value = gnc_numeric_add(value, xaccSplitGetValue(s), GNC_DENOM_AUTO, GNC_DENOM_LCD); } } else if ((NULL == base_currency) && (0 == force_double_entry)) { - value = gnc_numeric_add(value, s->value, + value = gnc_numeric_add(value, xaccSplitGetValue(s), GNC_DENOM_AUTO, GNC_DENOM_LCD); } else @@ -1593,12 +1543,12 @@ xaccSplitsComputeValue (GList *splits, Split * skip_me, * doesn't mean the denominators are the same! */ if (base_currency && gnc_commodity_equiv(currency, base_currency)) { - value = gnc_numeric_add(value, s->value, + value = gnc_numeric_add(value, xaccSplitGetValue(s), GNC_DENOM_AUTO, GNC_DENOM_LCD); } else if (base_currency && gnc_commodity_equiv(commodity, base_currency)) { - value = gnc_numeric_add(value, s->amount, + value = gnc_numeric_add(value, xaccSplitGetAmount(s), GNC_DENOM_AUTO, GNC_DENOM_LCD); } else { @@ -1787,18 +1737,26 @@ void xaccTransSetCurrency (Transaction *trans, gnc_commodity *curr) { GList *splits; - gint fraction; + gint fraction, old_fraction; if (!trans || !curr) return; + if (trans->common_currency == curr) return; /* No-op for common case */ check_open (trans); + old_fraction = gnc_commodity_get_fraction (trans->common_currency); trans->common_currency = curr; fraction = gnc_commodity_get_fraction (curr); - for (splits = trans->splits; splits; splits = splits->next) + /* avoid needless crud if fraction didn't change */ + if (fraction != old_fraction) { - Split *s = splits->data; - s->value = gnc_numeric_convert(s->value, fraction, GNC_RND_ROUND); + for (splits = trans->splits; splits; splits = splits->next) + { + Split *s = splits->data; + s->value = gnc_numeric_convert(xaccSplitGetValue(s), + fraction, GNC_RND_ROUND); + SET_GAINS_VDIRTY(s); + } } mark_trans (trans); @@ -1858,7 +1816,7 @@ destroy_gains (Transaction *trans) for (node = trans->splits; node; node = node->next) { Split *s = node->data; - if (GAINS_STATUS_UNKNOWN == s->gains) DetermineGainStatus(s); + if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus(s); if (s->gains_split && (GAINS_STATUS_GAINS & s->gains_split->gains)) { Transaction *t = s->gains_split->parent; @@ -1962,15 +1920,16 @@ xaccTransCommitEdit (Transaction *trans) */ if ((1 == force_double_entry) && (NULL == g_list_nth(trans->splits, 1)) && - (!gnc_numeric_zero_p(split->amount))) + (!gnc_numeric_zero_p(xaccSplitGetAmount(split)))) { Split * s = xaccMallocSplit(trans->book); xaccTransAppendSplit (trans, s); xaccAccountInsertSplit (s->acc, s); - s->amount = gnc_numeric_neg(split->amount); - s->value = gnc_numeric_neg(split->value); + s->amount = gnc_numeric_neg(xaccSplitGetAmount(split)); + s->value = gnc_numeric_neg(xaccSplitGetValue(split)); xaccSplitSetMemo (s, split->memo); xaccSplitSetAction (s, split->action); + SET_GAINS_A_VDIRTY(s); } } @@ -2156,6 +2115,7 @@ xaccTransRollbackEdit (Transaction *trans) s->reconciled = so->reconciled; s->amount = so->amount; s->value = so->value; + SET_GAINS_A_VDIRTY(s); s->date_reconciled = so->date_reconciled; @@ -2395,26 +2355,28 @@ xaccTransAppendSplit (Transaction *trans, Split *split) g_return_if_fail (trans->book == split->book); check_open (trans); - /* first, make sure that the split isn't already inserted + /* First, make sure that the split isn't already inserted * elsewhere. If so, then remove it. */ oldtrans = split->parent; if (oldtrans) xaccTransRemoveSplit (oldtrans, split); - /* now, insert the split into the array */ + /* Now, insert the split into the array */ split->parent = trans; trans->splits = g_list_append (trans->splits, split); - /* convert the split to the new transaction's commodity denominator */ - /* if the denominator can't be exactly converted, it's an error */ + /* Convert the split to the new transaction's commodity denominator */ + /* If the denominator can't be exactly converted, it's an error */ if (trans->common_currency) { int fraction = gnc_commodity_get_fraction (trans->common_currency); gnc_numeric new_value; - new_value = gnc_numeric_convert(split->value, fraction, GNC_RND_ROUND); + new_value = gnc_numeric_convert(xaccSplitGetValue(split), + fraction, GNC_RND_ROUND); if (gnc_numeric_check (new_value) == GNC_ERROR_OK) split->value = new_value; + SET_GAINS_VDIRTY(split); } } @@ -2494,11 +2456,11 @@ xaccSplitDateOrder (const Split *sa, const Split *sb) if ((sa->reconciled) > (sb->reconciled)) return +1; /* compare amounts */ - comp = gnc_numeric_compare(sa->amount, sb->amount); + comp = gnc_numeric_compare(xaccSplitGetAmount(sa), xaccSplitGetAmount (sb)); if(comp < 0) return -1; if(comp > 0) return +1; - comp = gnc_numeric_compare(sa->value, sb->value); + comp = gnc_numeric_compare(xaccSplitGetValue(sa), xaccSplitGetValue (sb)); if(comp < 0) return -1; if(comp > 0) return +1; @@ -2555,6 +2517,7 @@ xaccTransOrder (const Transaction *ta, const Transaction *tb) return 0; } + static gboolean get_corr_account_split(const Split *sa, Split **retval) { @@ -2569,7 +2532,7 @@ get_corr_account_split(const Split *sa, Split **retval) g_return_val_if_fail(sa, TRUE); ta = sa->parent; - sa_value = sa->value; + sa_value = xaccSplitGetValue (sa); sa_value_positive = gnc_numeric_positive_p(sa_value); for (split_list = ta->splits; @@ -2578,7 +2541,7 @@ get_corr_account_split(const Split *sa, Split **retval) current_split = split_list->data; if(current_split != sa) { - current_value = current_split->value; + current_value = xaccSplitGetValue (current_split); current_value_positive = gnc_numeric_positive_p(current_value); if((sa_value_positive && !current_value_positive) || (!sa_value_positive && current_value_positive)) @@ -2940,7 +2903,7 @@ restart_search: for (node = trans->splits; node; node=node->next) { Split *s = node->data; - if (GAINS_STATUS_UNKNOWN == s->gains) DetermineGainStatus(s); + if (GAINS_STATUS_UNKNOWN == s->gains) xaccSplitDetermineGainStatus(s); if ((GAINS_STATUS_GAINS & s->gains) && s->gains_split && @@ -3255,43 +3218,49 @@ xaccSplitGetReconcile (const Split *split) return (split->reconciled); } -double -DxaccSplitGetShareAmount (const Split * split) -{ - if (!split) return 0.0; - return gnc_numeric_to_double(split->amount); -} - -double -DxaccSplitGetValue (const Split * split) -{ - if (!split) return 0.0; - return gnc_numeric_to_double(split->value); -} - -double -DxaccSplitGetSharePrice (const Split * split) -{ - return gnc_numeric_to_double(xaccSplitGetSharePrice(split)); -} gnc_numeric -xaccSplitGetAmount (const Split * split) +xaccSplitGetAmount (const Split * cs) { + Split *split = (Split *) cs; if (!split) return gnc_numeric_zero(); + + /* The value of cap-gains splits is slave to the + * transaction that's actually causing the gains. +XXX implementation not finished!! + */ + + CHECK_GAINS_STATUS(split); return split->amount; } gnc_numeric -xaccSplitGetValue (const Split * split) +xaccSplitGetValue (const Split * cs) { + Split *split = (Split *) cs; if (!split) return gnc_numeric_zero(); + + /* The value of cap-gains splits is slave to the + * transaction that's actually causing the gains. + +XXX this test is wrong, it also needs to check for changed amount +which will should casue lot to recomputed! + */ + CHECK_GAINS_STATUS(split); + if ((split->gains & GAINS_STATUS_GAINS) && + split->gains_split && + (split->gains_split->gains & GAINS_STATUS_VDIRTY)) + { + xaccSplitComputeCapGains (split, NULL); + split->gains_split->gains |= ~GAINS_STATUS_VDIRTY; + } return split->value; } gnc_numeric xaccSplitGetSharePrice (const Split * split) { + gnc_numeric amt, val; if(!split) { return gnc_numeric_create(1, 1); @@ -3302,16 +3271,17 @@ xaccSplitGetSharePrice (const Split * split) * otherwise return value/amount */ - if(gnc_numeric_zero_p(split->amount)) + amt = xaccSplitGetAmount(split); + val = xaccSplitGetValue(split); + if(gnc_numeric_zero_p(amt)) { - if(gnc_numeric_zero_p(split->value)) + if(gnc_numeric_zero_p(val)) { return gnc_numeric_create(1, 1); } return gnc_numeric_create(0, 1); } - return gnc_numeric_div(split->value, - split->amount, + return gnc_numeric_div(val, amt, GNC_DENOM_AUTO, GNC_DENOM_SIGFIGS(PRICE_SIGFIGS) | GNC_RND_ROUND); @@ -3347,6 +3317,7 @@ xaccSplitMakeStockSplit(Split *s) s->value = gnc_numeric_zero(); kvp_frame_set_str(s->kvp_data, "split-type", "stock-split"); + SET_GAINS_VDIRTY(s); mark_split(s); /* gen_event (s); No! only in TransCommit() ! */ } @@ -3500,8 +3471,10 @@ xaccTransVoid(Transaction *transaction, Split * split = split_list->data; frame = split->kvp_data; - kvp_frame_set_gnc_numeric(frame, void_former_amt_str, split->amount); - kvp_frame_set_gnc_numeric(frame, void_former_val_str, split->value); + kvp_frame_set_gnc_numeric(frame, void_former_amt_str, + xaccSplitGetAmount(split)); + kvp_frame_set_gnc_numeric(frame, void_former_val_str, + xaccSplitGetValue(split)); xaccSplitSetAmount (split, zero); xaccSplitSetValue (split, zero); @@ -3645,8 +3618,9 @@ xaccTransReverse (Transaction *trans) split_list = g_list_next(split_list)) { split = split_list->data; - split->amount = gnc_numeric_neg(split->amount); - split->value = gnc_numeric_neg(split->value); + split->amount = gnc_numeric_neg(xaccSplitGetAmount(split)); + split->value = gnc_numeric_neg(xaccSplitGetValue(split)); + SET_GAINS_A_VDIRTY(split); split->reconciled = NREC; xaccSplitSetDateReconciledSecs (split, 0); } @@ -3710,6 +3684,13 @@ static gpointer split_account_guid_getter (gpointer obj) return ((gpointer)xaccAccountGetGUID (acc)); } +static double /* internal use only */ +DxaccSplitGetShareAmount (const Split * split) +{ + if (!split) return 0.0; + return gnc_numeric_to_double(xaccSplitGetAmount(split)); +} + static gpointer no_op (gpointer obj) { return obj; @@ -3721,6 +3702,9 @@ gboolean xaccSplitRegister (void) { SPLIT_KVP, QOF_QUERYCORE_KVP, (QofAccessFunc)xaccSplitGetSlots }, { SPLIT_DATE_RECONCILED, QOF_QUERYCORE_DATE, (QofAccessFunc)xaccSplitRetDateReconciledTS }, + + /* d-* are depricated query params, should not be used in new + * queries, should be removed from old queries. */ { "d-share-amount", QOF_QUERYCORE_DOUBLE, (QofAccessFunc)DxaccSplitGetShareAmount }, { "d-share-int64", QOF_QUERYCORE_INT64, (QofAccessFunc)xaccSplitGetGUID }, diff --git a/src/engine/Transaction.h b/src/engine/Transaction.h index f74af7c78c..0aa918990a 100644 --- a/src/engine/Transaction.h +++ b/src/engine/Transaction.h @@ -538,9 +538,8 @@ Timespec xaccSplitRetDateReconciledTS (const Split *split); */ /*@{*/ -/** The xaccSplitSetAmount() (formerly xaccSplitSetShareAmount) method - * sets the amount in the account's commodity that the split should - * have. +/** The xaccSplitSetAmount() method sets the amount in the account's + * commodity that the split should have. * * The following four setter functions set the prices and amounts. * All of the routines always maintain balance: that is, invoking any @@ -559,7 +558,10 @@ Timespec xaccSplitRetDateReconciledTS (const Split *split); */ void xaccSplitSetAmount (Split *split, gnc_numeric amount); -/** Returns the amount of the split in the account's commodity. */ +/** Returns the amount of the split in the account's commodity. + * Note that for cap-gains splits, this is slaved to the transaction + * that is causing the gains to occur. + */ gnc_numeric xaccSplitGetAmount (const Split * split); /** The xaccSplitSetValue() method sets the value of this split in the @@ -570,7 +572,10 @@ gnc_numeric xaccSplitGetAmount (const Split * split); */ void xaccSplitSetValue (Split *split, gnc_numeric value); -/** Returns the value of this split in the transaction's commodity. */ +/** Returns the value of this split in the transaction's commodity. + * Note that for cap-gains splits, this is slaved to the transaction + * that is causing the gains to occur. +*/ gnc_numeric xaccSplitGetValue (const Split * split); /** The xaccSplitSetSharePriceAndAmount() method will simultaneously @@ -766,36 +771,9 @@ const char * xaccSplitGetCorrAccountCode(const Split *sa); * split. DEPRECATED - set the value and amount instead. */ void xaccSplitSetSharePrice (Split *split, gnc_numeric price); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -void DxaccSplitSetAmount (Split *s, double damt); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. - * - * WARNING: The xaccSplitSetValue and DxaccSplitSetValue do NOT have the same - * behavior. The later divides the value given by the current value and set's - * the result as the new split value. Is that a but or just strange undocumented - * feature? Benoit Grégoire 2002-6-12 */ -void DxaccSplitSetValue (Split *split, double value); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -double DxaccSplitGetValue (const Split * split); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -void DxaccSplitSetSharePriceAndAmount (Split *split, double price, - double amount); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -void DxaccSplitSetShareAmount (Split *split, double amount); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -double DxaccSplitGetShareAmount (const Split * split); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -void DxaccSplitSetSharePrice (Split *split, double price); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -double DxaccSplitGetSharePrice (const Split * split); -/** @deprecated Don't use doubles anymore, only use gnc_numerics. */ -void DxaccSplitSetBaseValue (Split *split, double value, - const gnc_commodity * base_currency); /*@}*/ - - /********************************************************************\ * Miscellaneous utility routines. \********************************************************************/ diff --git a/src/engine/TransactionP.h b/src/engine/TransactionP.h index cf40c08534..522e81c79b 100644 --- a/src/engine/TransactionP.h +++ b/src/engine/TransactionP.h @@ -84,7 +84,9 @@ #define GAINS_STATUS_AMNT_DIRTY 0x20 #define GAINS_STATUS_VALU_DIRTY 0x40 #define GAINS_STATUS_LOT_DIRTY 0x80 -#define GAINS_STATUS_VDIRTY (GAINS_STATUS_AMNT_DIRTY|GAINS_STATUS_VALU_DIRTY|GAINS_STATUS_LOT_DIRTY) +#define GAINS_STATUS_ADIRTY (GAINS_STATUS_AMNT_DIRTY|GAINS_STATUS_LOT_DIRTY) +#define GAINS_STATUS_VDIRTY (GAINS_STATUS_VALU_DIRTY) +#define GAINS_STATUS_A_VDIRTY (GAINS_STATUS_AMNT_DIRTY|GAINS_STATUS_VALU_DIRTY|GAINS_STATUS_LOT_DIRTY) struct split_s { @@ -248,7 +250,7 @@ void xaccFreeSplit (Split *split); /* frees memory */ */ Transaction * xaccDupeTransaction (Transaction *t); -/* compute the value of a list of splits in the given currency, +/* Compute the value of a list of splits in the given currency, * excluding the skip_me split. */ gnc_numeric xaccSplitsComputeValue (GList *splits, Split * skip_me, const gnc_commodity * base_currency); @@ -261,13 +263,6 @@ gnc_numeric xaccSplitsComputeValue (GList *splits, Split * skip_me, void xaccTransSetVersion (Transaction*, gint32); gint32 xaccTransGetVersion (const Transaction*); -/* The xaccTransFindCommonCurrency () method returns a gnc_commodity - * indicating a currency denomination that all of the splits in this - * transaction have in common, using the old currency/security fields - * of the split accounts. */ -gnc_commodity * xaccTransFindOldCommonCurrency (Transaction *trans, - QofBook *book); - /* Code to register Split and Transaction types with the engine */ gboolean xaccSplitRegister (void); gboolean xaccTransRegister (void); @@ -279,4 +274,30 @@ gboolean xaccTransRegister (void); */ QofBackend * xaccTransactionGetBackend (Transaction *trans); +/* The xaccSplitDetermineGainStatus() routine will analyze the + * the split, and try to set the internal status flags + * appropriately for the split. These flags indicate if the split + * represents cap gains, and if the gains value/amount needs to be + * recomputed. + */ +void xaccSplitDetermineGainStatus (Split *split); + +/* ---------------------------------------------------------------- */ +/* Depricated routines */ +void DxaccSplitSetSharePriceAndAmount (Split *split, + double price, + double amount); +void DxaccSplitSetShareAmount (Split *split, double amount); + +/* The deprecated xaccTransFindCommonCurrency () method returns + * a gnc_commodity indicating a currency denomination that all + * of the splits in this transaction have in common, using the + * old currency/security fields of the split accounts. DO NOT + * USE THIS ROUTINE! */ +gnc_commodity * xaccTransFindOldCommonCurrency (Transaction *trans, + QofBook *book); + +/*@}*/ + + #endif /* XACC_TRANSACTION_P_H */ diff --git a/src/engine/cap-gains.c b/src/engine/cap-gains.c index ae9451304a..c59d0f1b53 100644 --- a/src/engine/cap-gains.c +++ b/src/engine/cap-gains.c @@ -55,6 +55,9 @@ ToDo List: then the peers need to be reunified first! And that implies that gain transactions need to be 'reunified' too. + o XXX Need to create a data-integrity scrubber, tht makes sure that + the various flags, and pointers & etc. match. See sections marked + with XXX below for things that might go wrong. */ #include "config.h" @@ -506,19 +509,51 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc) ENTER ("split=%p lot=%s", split, kvp_frame_get_string (gnc_lot_get_slots (lot), "/title")); - /* Make sure this isn't a cap-gains split itself; ignore these. */ + /* Make sure the status flags and pointers are initialized */ + if (GAINS_STATUS_UNKNOWN == split->gains) xaccSplitDetermineGainStatus(split); + if (GAINS_STATUS_GAINS & split->gains) + { + /* If this is the split that records the gains, then work with + * the split that generates the gains. + */ + /* split = xaccSplitGetCapGainsSplit (split); */ + split = split->gains_split; + + /* This should never be NULL, and if it is, and its matching + * parent can't be found, then its a bug, and we should be + * discarding this split. But ... for now .. return. + * XXX move appropriate actions to a 'scrub' routine' + */ + if (!split) + { + PERR ("Bad gains-split pointer! .. trying to recover."); + split->gains_split = xaccSplitGetCapGainsSplit (split); + split = split->gains_split; + if (!split) return; +#if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER + xaccTransDestroy (trans); +#endif + } + } + + if ((FALSE == (split->gains & GAINS_STATUS_A_VDIRTY)) && + (split->gains_split) && + (FALSE == (split->gains_split->gains & GAINS_STATUS_A_VDIRTY))) return; + + /* Yow! 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; opening_split = gnc_lot_get_earliest_split(lot); if (split == opening_split) { - /* Check to make sure this split doesn't have a cap-gain - * transaction associated with it. If it does, that's - * wrong, and we ruthlessly destroy it. + /* Check to make sure that this opening split doesn't + * have a cap-gain transaction associated with it. + * If it does, that's wrong, and we ruthlessly destroy it. * XXX Don't do this, it leads to infinite loops. * We need to scrub out errors like this elsewhere! */ -#if MOVE_THIS_ELSEWHERE +#if MOVE_THIS_TO_A_DATA_INTEGRITY_SCRUBBER if (xaccSplitGetCapGainsSplit (split)) { Split *gains_split = xaccSplitGetCapGainsSplit(split); @@ -695,10 +730,22 @@ xaccSplitGetCapGains(Split * split) { if (!split) return gnc_numeric_zero(); - /* XXX Do *not! recomp gains every time; use a 'dirty' flag instead */ - xaccSplitComputeCapGains (split, NULL); + if (GAINS_STATUS_UNKNOWN == split->gains) xaccSplitDetermineGainStatus(split); + if ((split->gains & GAINS_STATUS_A_VDIRTY) || + (split->gains_split && (split->gains_split->gains & GAINS_STATUS_A_VDIRTY))) + { + xaccSplitComputeCapGains (split, NULL); + } + + /* If this is the source split, get the gains from the one + * that records the gains. If this already is the gains split, + * its a no-op. */ + if (!(GAINS_STATUS_GAINS & split->gains)) + { + /* split = xaccSplitGetCapGainsSplit (split); */ + split = split->gains_split; + } - split = xaccSplitGetCapGainsSplit (split); if (!split) return gnc_numeric_zero(); return split->value; diff --git a/src/engine/gw-engine-spec.scm b/src/engine/gw-engine-spec.scm index f309ede004..958f44f918 100644 --- a/src/engine/gw-engine-spec.scm +++ b/src/engine/gw-engine-spec.scm @@ -1669,14 +1669,6 @@ of having a parent transaction with which one is working...") '(( s) ( value)) "Set reconcile state for split entry") -(gw:wrap-function - ws - 'd-gnc:split-set-share-price - ' - "DxaccSplitSetSharePrice" - '(( s) ( value)) - "Set share price for split entry") - (gw:wrap-function ws 'gnc:split-set-share-price