From f906f0b11b40989f539cbbe9ddc4ea4465c23b49 Mon Sep 17 00:00:00 2001 From: David Hampton Date: Tue, 1 Apr 2003 04:05:32 +0000 Subject: [PATCH] Push gui independent functions into the engine. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@8146 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/app-utils/gnc-ui-util.c | 514 +++++++++++++----------------------- src/app-utils/gnc-ui-util.h | 70 ++++- src/engine/Account.c | 292 +++++++++++++++++++- src/engine/Account.h | 32 ++- src/gnome/gnc-split-reg.c | 100 +------ 5 files changed, 574 insertions(+), 434 deletions(-) diff --git a/src/app-utils/gnc-ui-util.c b/src/app-utils/gnc-ui-util.c index 9faff53417..530eb75217 100644 --- a/src/app-utils/gnc-ui-util.c +++ b/src/app-utils/gnc-ui-util.c @@ -291,255 +291,165 @@ gnc_get_current_commodities (void) return gnc_book_get_commodity_table (gnc_get_current_book ()); } -const char * -gnc_ui_account_get_field_name (AccountFieldCode field) +/* + * This is a wrapper routine around an xaccGetBalanceInCurrency + * function that handles additional needs of the gui. + * + * @param fn The underlying function in Account.c to call to retrieve + * a specific balance from the account. + * @param account The account to retrieve data about. + * @param recurse Include all sub-accounts of this account. + * @param negative An indication of whether or not the returned value + * is negative. This can be used by the caller to + * easily decode whether or not to color the output. + * @param commodity The commodity in which the account balance should + * be returned. If NULL, the value will be returned in + * the commodity of the account. This is normally used + * to specify a currency, which forces the conversion + * of things like stock account values from share + * values to an amount the requested currency. + */ +static gnc_numeric +gnc_ui_account_get_balance_internal (xaccGetBalanceInCurrencyFn fn, + Account *account, + gboolean recurse, + gboolean *negative, + gnc_commodity *commodity) { - g_return_val_if_fail ((field >= 0) && (field < NUM_ACCOUNT_FIELDS), NULL); + gnc_numeric balance; - switch (field) - { - case ACCOUNT_TYPE : - return _("Type"); - break; - case ACCOUNT_NAME : - return _("Account Name"); - break; - case ACCOUNT_CODE : - return _("Account Code"); - break; - case ACCOUNT_DESCRIPTION : - return _("Description"); - break; - case ACCOUNT_NOTES : - return _("Notes"); - break; - case ACCOUNT_COMMODITY : - return _("Commodity"); - break; - case ACCOUNT_BALANCE : - return _("Balance"); - break; - case ACCOUNT_BALANCE_REPORT : - return _("Balance"); - break; - case ACCOUNT_TOTAL : - return _("Total"); - break; - case ACCOUNT_TOTAL_REPORT : - return _("Total"); - break; - case ACCOUNT_TAX_INFO : - return _("Tax Info"); - default: - break; - } + balance = fn(account, commodity, recurse); - return NULL; + /* reverse sign if needed */ + if (gnc_reverse_balance (account)) + balance = gnc_numeric_neg (balance); + + /* Record whether the balance is negative. */ + if (negative) + *negative = gnc_numeric_negative_p(balance); + + return balance; +} + +/* + * This routine retrives the total balance in an account, possibly + * including all sub-accounts under the specified account. + */ +gnc_numeric +gnc_ui_account_get_balance (Account *account, gboolean recurse) +{ + return gnc_ui_account_get_balance_internal (xaccAccountGetBalanceInCurrency, + account, recurse, NULL, NULL); +} + +/* + * This routine retrives the reconciled balance in an account, + * possibly including all sub-accounts under the specified account. + */ +gnc_numeric +gnc_ui_account_get_reconciled_balance (Account *account, + gboolean recurse) +{ + return gnc_ui_account_get_balance_internal (xaccAccountGetReconciledBalanceInCurrency, + account, recurse, NULL, NULL); } -static gnc_numeric -gnc_account_get_balance_in_currency (Account *account, - gnc_commodity *currency) +/** + * Wrapper around gnc_ui_account_get_balance_internal that converts + * the resulting number to a character string. The number is + * formatted according to the specification of the account currency. + * + * @param fn The underlying function in Account.c to call to retrieve + * a specific balance from the account. + * @param account The account to retrieve data about. + * @param recurse Include all sub-accounts of this account. + * @param negative An indication of whether or not the returned value + * is negative. This can be used by the caller to + * easily decode whether or not to color the output. + */ +static gchar * +gnc_ui_account_get_print_balance (xaccGetBalanceInCurrencyFn fn, + Account *account, + gboolean recurse, + gboolean *negative) { - GNCBook *book; - GNCPriceDB *pdb; - GNCPrice *price; + GNCPrintAmountInfo print_info; gnc_numeric balance; - gnc_commodity *commodity; - if (!account || !currency) - return gnc_numeric_zero (); + balance = gnc_ui_account_get_balance_internal(fn, account, recurse, + negative, NULL); + print_info = gnc_account_print_info(account, TRUE); + return g_strdup(xaccPrintAmount(balance, print_info)); +} - balance = xaccAccountGetBalance (account); - commodity = xaccAccountGetCommodity (account); - if (gnc_numeric_zero_p (balance) || - gnc_commodity_equiv (currency, commodity)) - return balance; +/** + * Wrapper around gnc_ui_account_get_balance_internal that converts + * the resulting number to a character string. The number is + * formatted according to the specification of the default reporting + * currency. + * + * @param fn The underlying function in Account.c to call to retrieve + * a specific balance from the account. + * @param account The account to retrieve data about. + * @param recurse Include all sub-accounts of this account. + * @param negative An indication of whether or not the returned value + * is negative. This can be used by the caller to + * easily decode whether or not to color the output. + */ +static gchar * +gnc_ui_account_get_print_report_balance (xaccGetBalanceInCurrencyFn fn, + Account *account, + gboolean recurse, + gboolean *negative) +{ + GNCPrintAmountInfo print_info; + gnc_numeric balance; + gnc_commodity *report_commodity; - book = xaccGroupGetBook (xaccAccountGetRoot (account)); - g_return_val_if_fail (book != NULL, gnc_numeric_zero ()); - - pdb = gnc_book_get_pricedb (book); - - price = gnc_pricedb_lookup_latest (pdb, commodity, currency); - if (!price) - return gnc_numeric_zero (); - - balance = gnc_numeric_mul (balance, gnc_price_get_value (price), - gnc_commodity_get_fraction (currency), - GNC_RND_ROUND); - - gnc_price_unref (price); - - return balance; + report_commodity = gnc_default_report_currency(); + balance = gnc_ui_account_get_balance_internal(fn, account, recurse, + negative, report_commodity); + print_info = gnc_commodity_print_info(report_commodity, TRUE); + return g_strdup(xaccPrintAmount(balance, print_info)); } gnc_numeric -gnc_ui_convert_balance_to_currency(gnc_numeric balance, gnc_commodity *balance_currency, gnc_commodity *currency) -{ - GNCBook *book; - GNCPriceDB *pdb; - GNCPrice *price; - - if (gnc_numeric_zero_p (balance) || - gnc_commodity_equiv (currency, balance_currency)) - return balance; - - book = gnc_get_current_book (); - pdb = gnc_book_get_pricedb (book); - - price = gnc_pricedb_lookup_latest (pdb, balance_currency, currency); - - if (price) - { - balance = gnc_numeric_mul (balance, gnc_price_get_value (price), - gnc_commodity_get_fraction (currency), - GNC_RND_ROUND); - gnc_price_unref (price); - } - else - { - /* no direct price found, try if we find a price in another - currency and convert in two stages */ - GList *price_list = gnc_pricedb_lookup_latest_any_currency(pdb, balance_currency); - - if(price_list) - { - GList *list_helper = price_list; - gnc_numeric currency_price_value = gnc_numeric_zero(); - gnc_commodity *intermediate_currency; - GNCPrice *currency_price; - - do - { - price = (GNCPrice *)(list_helper->data); - - intermediate_currency = gnc_price_get_currency(price); - currency_price = gnc_pricedb_lookup_latest(pdb, intermediate_currency, currency); - if(currency_price) - { - currency_price_value = gnc_price_get_value(currency_price); - gnc_price_unref(currency_price); - } - else - { - currency_price = gnc_pricedb_lookup_latest(pdb, currency, intermediate_currency); - if(currency_price) - { - /* here we need the reciprocal */ - currency_price_value = gnc_numeric_div(gnc_numeric_create(1, 1), - gnc_price_get_value(currency_price), - gnc_commodity_get_fraction (currency), - GNC_RND_ROUND); - gnc_price_unref(currency_price); - } - } - - list_helper = list_helper->next; - } - while((list_helper != NULL) && (!gnc_numeric_zero_p(currency_price_value))); - - balance = gnc_numeric_mul (balance, currency_price_value, - gnc_commodity_get_fraction (currency), - GNC_RND_ROUND); - balance = gnc_numeric_mul (balance, gnc_price_get_value (price), - gnc_commodity_get_fraction (currency), - GNC_RND_ROUND); - - gnc_price_list_destroy(price_list); - } - else - { - balance = gnc_numeric_zero (); - } - } - - return balance; -} - -static gnc_numeric -gnc_account_get_reconciled_balance_in_currency (Account *account, - gnc_commodity *currency) +gnc_ui_account_get_balance_as_of_date (Account *account, time_t date, + gboolean include_children) { gnc_numeric balance; - gnc_commodity *balance_currency; - - if (!account || !currency) - return gnc_numeric_zero (); - - balance = xaccAccountGetReconciledBalance (account); - balance_currency = xaccAccountGetCommodity (account); - - return gnc_ui_convert_balance_to_currency (balance, balance_currency, - currency); -} - -typedef struct -{ gnc_commodity *currency; - gnc_numeric balance; -} CurrencyBalance; - - -static gpointer -balance_helper (Account *account, gpointer data) -{ - CurrencyBalance *cb = data; - gnc_numeric balance; - - if (!cb->currency) - return NULL; - - balance = gnc_account_get_balance_in_currency (account, cb->currency); - - cb->balance = gnc_numeric_add (cb->balance, balance, - gnc_commodity_get_fraction (cb->currency), - GNC_RND_ROUND); - - return NULL; -} - -static gpointer -reconciled_balance_helper (Account *account, gpointer data) -{ - CurrencyBalance *cb = data; - gnc_numeric balance; - - balance = gnc_account_get_reconciled_balance_in_currency (account, cb->currency); - - cb->balance = gnc_numeric_add (cb->balance, balance, - gnc_commodity_get_fraction (cb->currency), - GNC_RND_ROUND); - - return NULL; -} - -gnc_numeric -gnc_ui_account_get_balance (Account *account, gboolean include_children) -{ - gnc_numeric balance; - gnc_commodity *commodity; if (account == NULL) return gnc_numeric_zero (); - commodity = xaccAccountGetCommodity (account); - - balance = gnc_account_get_balance_in_currency (account, commodity); + currency = xaccAccountGetCommodity (account); + balance = xaccAccountGetBalanceAsOfDate (account, date); if (include_children) { - AccountGroup *children; - CurrencyBalance cb = { commodity, balance }; + AccountGroup *children_group; + GList *children, *node; - children = xaccAccountGetChildren (account); + children_group = xaccAccountGetChildren (account); + children = xaccGroupGetSubAccounts (children_group); - xaccGroupForEachAccount (children, balance_helper, &cb, TRUE); + for (node = children; node; node = node->next) + { + Account *child; + gnc_commodity *child_currency; + gnc_numeric child_balance; - balance = cb.balance; + child = node->data; + child_currency = xaccAccountGetCommodity (child); + child_balance = xaccAccountGetBalanceAsOfDate (child, date); + child_balance = xaccAccountConvertBalanceToCurrency (child, + child_balance, child_currency, currency); + balance = gnc_numeric_add_fixed (balance, child_balance); + } } /* reverse sign if needed */ @@ -549,7 +459,6 @@ gnc_ui_account_get_balance (Account *account, gboolean include_children) return balance; } - static char * gnc_ui_account_get_tax_info_string (Account *account) { @@ -631,88 +540,14 @@ gnc_ui_account_get_tax_info_string (Account *account) } -gnc_numeric -gnc_ui_account_get_reconciled_balance (Account *account, - gboolean include_children) -{ - gnc_numeric balance; - gnc_commodity *currency; - - if (account == NULL) - return gnc_numeric_zero (); - - currency = xaccAccountGetCommodity (account); - - balance = gnc_account_get_reconciled_balance_in_currency (account, currency); - - if (include_children) - { - AccountGroup *children; - CurrencyBalance cb = { currency, balance }; - - children = xaccAccountGetChildren (account); - - xaccGroupForEachAccount (children, reconciled_balance_helper, &cb, TRUE); - - balance = cb.balance; - } - - /* reverse sign if needed */ - if (gnc_reverse_balance (account)) - balance = gnc_numeric_neg (balance); - - return balance; -} - -gnc_numeric -gnc_ui_account_get_balance_as_of_date (Account *account, time_t date, - gboolean include_children) -{ - gnc_numeric balance; - gnc_commodity *currency; - - if (account == NULL) - return gnc_numeric_zero (); - - currency = xaccAccountGetCommodity (account); - balance = xaccAccountGetBalanceAsOfDate (account, date); - - if (include_children) - { - AccountGroup *children_group; - GList *children, *node; - - children_group = xaccAccountGetChildren (account); - children = xaccGroupGetSubAccounts (children_group); - - for (node = children; node; node = node->next) - { - Account *child; - gnc_commodity *child_currency; - gnc_numeric child_balance; - - child = node->data; - child_currency = xaccAccountGetCommodity (child); - child_balance = xaccAccountGetBalanceAsOfDate (child, date); - child_balance = gnc_ui_convert_balance_to_currency - (child_balance, child_currency, currency); - balance = gnc_numeric_add_fixed (balance, child_balance); - } - } - - /* reverse sign if needed */ - if (gnc_reverse_balance (account)) - balance = gnc_numeric_neg (balance); - - return balance; -} - char * gnc_ui_account_get_field_value_string (Account *account, - AccountFieldCode field) + AccountFieldCode field, + gboolean *negative) { g_return_val_if_fail ((field >= 0) && (field < NUM_ACCOUNT_FIELDS), NULL); + *negative = FALSE; if (account == NULL) return NULL; @@ -738,49 +573,66 @@ gnc_ui_account_get_field_value_string (Account *account, g_strdup (gnc_commodity_get_printname(xaccAccountGetCommodity(account))); - case ACCOUNT_BALANCE : - { - gnc_numeric balance = gnc_ui_account_get_balance(account, FALSE); + case ACCOUNT_PRESENT : + return + gnc_ui_account_get_print_balance(xaccAccountGetPresentBalanceInCurrency, + account, FALSE, negative); - return g_strdup - (xaccPrintAmount (balance, gnc_account_print_info (account, TRUE))); - } + case ACCOUNT_PRESENT_REPORT : + return + gnc_ui_account_get_print_report_balance(xaccAccountGetPresentBalanceInCurrency, + account, FALSE, negative); + + case ACCOUNT_BALANCE : + return + gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency, + account, FALSE, negative); case ACCOUNT_BALANCE_REPORT : - { - gnc_commodity * commodity = xaccAccountGetCommodity(account); - gnc_commodity * report_commodity = gnc_default_report_currency(); - gnc_numeric balance = gnc_ui_account_get_balance(account, FALSE); + return + gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency, + account, FALSE, negative); - gnc_numeric report_balance = gnc_ui_convert_balance_to_currency(balance, commodity, - report_commodity); + case ACCOUNT_CLEARED : + return + gnc_ui_account_get_print_balance(xaccAccountGetClearedBalanceInCurrency, + account, FALSE, negative); - return g_strdup - (xaccPrintAmount(report_balance, - gnc_commodity_print_info (report_commodity, TRUE))); - } + case ACCOUNT_CLEARED_REPORT : + return + gnc_ui_account_get_print_report_balance(xaccAccountGetClearedBalanceInCurrency, + account, FALSE, negative); + + case ACCOUNT_RECONCILED : + return + gnc_ui_account_get_print_balance(xaccAccountGetReconciledBalanceInCurrency, + account, FALSE, negative); + + case ACCOUNT_RECONCILED_REPORT : + return + gnc_ui_account_get_print_report_balance(xaccAccountGetReconciledBalanceInCurrency, + account, FALSE, negative); + + case ACCOUNT_FUTURE_MIN : + return + gnc_ui_account_get_print_balance(xaccAccountGetProjectedMinimumBalanceInCurrency, + account, FALSE, negative); + + case ACCOUNT_FUTURE_MIN_REPORT : + return + gnc_ui_account_get_print_report_balance(xaccAccountGetProjectedMinimumBalanceInCurrency, + account, FALSE, negative); case ACCOUNT_TOTAL : - { - gnc_numeric balance = gnc_ui_account_get_balance(account, TRUE); + return + gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency, + account, TRUE, negative); - return g_strdup - (xaccPrintAmount(balance, gnc_account_print_info (account, TRUE))); - } case ACCOUNT_TOTAL_REPORT : - { - gnc_commodity * commodity = xaccAccountGetCommodity(account); - gnc_commodity * report_commodity = gnc_default_report_currency(); - gnc_numeric balance = gnc_ui_account_get_balance(account, TRUE); - - gnc_numeric report_balance = gnc_ui_convert_balance_to_currency(balance, commodity, - report_commodity); - - return g_strdup - (xaccPrintAmount(report_balance, - gnc_commodity_print_info (report_commodity, TRUE))); - } + return + gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency, + account, TRUE, negative); case ACCOUNT_TAX_INFO: return gnc_ui_account_get_tax_info_string (account); diff --git a/src/app-utils/gnc-ui-util.h b/src/app-utils/gnc-ui-util.h index 86681871a8..7dc643af13 100644 --- a/src/app-utils/gnc-ui-util.h +++ b/src/app-utils/gnc-ui-util.h @@ -20,6 +20,13 @@ * Boston, MA 02111-1307, USA gnu@gnu.org * \********************************************************************/ +/** @addtogroup UI + @{ */ +/** @file gnc-ui-util.h + @brief utility functions for the GnuCash UI + @author Copyright (C) 2000 Dave Peticolas +*/ + #ifndef GNC_UI_UTIL_H #define GNC_UI_UTIL_H @@ -57,37 +64,75 @@ GNCBook * gnc_get_current_book (void); AccountGroup * gnc_get_current_group (void); gnc_commodity_table * gnc_get_current_commodities (void); +/* + * These values are order according to the way they should appear in + * the register. If you change this enum, you must also change the + * acct_tree_defaults data structure in gnc-account-tree.c. + */ typedef enum { - ACCOUNT_TYPE = 0, - ACCOUNT_NAME, + ACCOUNT_NAME = 0, + ACCOUNT_TYPE, + ACCOUNT_COMMODITY, ACCOUNT_CODE, ACCOUNT_DESCRIPTION, - ACCOUNT_NOTES, - ACCOUNT_COMMODITY, + ACCOUNT_PRESENT, + ACCOUNT_PRESENT_REPORT, ACCOUNT_BALANCE, /* with sign reversal */ ACCOUNT_BALANCE_REPORT, /* ACCOUNT_BALANCE in default report currency */ + ACCOUNT_CLEARED, + ACCOUNT_CLEARED_REPORT, + ACCOUNT_RECONCILED, + ACCOUNT_RECONCILED_REPORT, + ACCOUNT_FUTURE_MIN, + ACCOUNT_FUTURE_MIN_REPORT, ACCOUNT_TOTAL, /* balance + children's balance with sign reversal */ ACCOUNT_TOTAL_REPORT, /* ACCOUNT_TOTAL in default report currency */ + ACCOUNT_NOTES, ACCOUNT_TAX_INFO, NUM_ACCOUNT_FIELDS } AccountFieldCode; -const char * gnc_ui_account_get_field_name (AccountFieldCode field); - -/* Must g_free string when done */ +/** + * This routine retrives the content for any given field in the + * account tree data structure. The account specifies the "row" and + * the field parameter specifies the "column". In essence, this is + * one giant accessor routine for the Account object where all the + * results are string values. + * + * @param account The account to retrieve data about. + * @param field An indicator of which field in the account tree to return + * @param negative An indicator that the result was a negative numeric + * value. May be used by the caller for colorization of the + * returned string. + * @return The textual string representing the requested field. + * + * @note The caller must free the returned string when done with it. + */ char * gnc_ui_account_get_field_value_string (Account *account, - AccountFieldCode field); - -gnc_numeric gnc_ui_convert_balance_to_currency(gnc_numeric balance, - gnc_commodity *balance_currency, - gnc_commodity *currency); + AccountFieldCode field, + gboolean *negative); +/** + * This routine retrives the total balance in an account, possibly + * including all sub-accounts under the specified account. + * + * @param account The account to retrieve data about. + * @param include_children Include all sub-accounts of this account. + */ gnc_numeric gnc_ui_account_get_balance (Account *account, gboolean include_children); +/** + * This routine retrives the reconciled balance in an account, + * possibly including all sub-accounts under the specified account. + * + * @param account The account to retrieve data about. + * @param include_children Include all sub-accounts of this account. + */ gnc_numeric gnc_ui_account_get_reconciled_balance(Account *account, gboolean include_children); + gnc_numeric gnc_ui_account_get_balance_as_of_date (Account *account, time_t date, gboolean include_children); @@ -281,3 +326,4 @@ int iswlower (gint32 wc); #endif #endif +/** @} */ diff --git a/src/engine/Account.c b/src/engine/Account.c index 24c60911da..6fc21d9807 100644 --- a/src/engine/Account.c +++ b/src/engine/Account.c @@ -1182,7 +1182,7 @@ xaccAccountRecomputeBalance (Account * acc) balance = gnc_numeric_add_fixed(balance, split->amount); - if (NREC != split->reconciled) + if (CREC == split->reconciled) cleared_balance = gnc_numeric_add_fixed(cleared_balance, split->amount); if (YREC == split->reconciled || @@ -1855,6 +1855,38 @@ xaccAccountGetReconciledBalance (Account *acc) return acc->reconciled_balance; } +gnc_numeric +xaccAccountGetProjectedMinimumBalance (Account *account) +{ + GList *node; + time_t today; + gnc_numeric lowest = gnc_numeric_zero (); + int seen_a_transaction = 0; + + if (!account) + return gnc_numeric_zero (); + + today = gnc_timet_get_today_end(); + for (node = g_list_last (account->splits); node; node = node->prev) + { + Split *split = node->data; + + if (!seen_a_transaction) + { + lowest = xaccSplitGetBalance (split); + seen_a_transaction = 1; + } else if (gnc_numeric_compare(xaccSplitGetBalance (split), lowest) < 0) { + lowest = xaccSplitGetBalance (split); + } + + if (xaccTransGetDate (xaccSplitGetParent (split)) <= today) + return lowest; + } + + return lowest; +} + + /********************************************************************\ \********************************************************************/ @@ -1912,6 +1944,258 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date) return( balance ); } +/* + * Originally gsr_account_present_balance in gnc-split-reg.c + * + * How does this routine compare to xaccAccountGetBalanceAsOfDate just + * above? These two routines should eventually be collapsed into one. + * Perhaps the startup logic from that one, and the logic from this + * one that walks from the tail of the split list. + */ +gnc_numeric +xaccAccountGetPresentBalance (Account *account) +{ + GList *node; + time_t today; + + if (!account) + return gnc_numeric_zero (); + + today = gnc_timet_get_today_end(); + for (node = g_list_last (account->splits); node; node = node->prev) + { + Split *split = node->data; + + if (xaccTransGetDate (xaccSplitGetParent (split)) <= today) + return xaccSplitGetBalance (split); + } + + return gnc_numeric_zero (); +} + + +/********************************************************************\ +\********************************************************************/ + +/* + * Convert a balance from one currency to another. + */ +gnc_numeric +xaccAccountConvertBalanceToCurrency(Account *account, /* for book */ + gnc_numeric balance, + gnc_commodity *balance_currency, + gnc_commodity *new_currency) +{ + GNCBook *book; + GNCPriceDB *pdb; + GNCPrice *price, *currency_price; + GList *price_list, *list_helper; + gnc_numeric currency_price_value; + gnc_commodity *intermediate_currency; + + if (gnc_numeric_zero_p (balance) || + gnc_commodity_equiv (balance_currency, new_currency)) + return balance; + + book = xaccGroupGetBook (xaccAccountGetRoot (account)); + pdb = gnc_book_get_pricedb (book); + + /* Look for a direct price. */ + price = gnc_pricedb_lookup_latest (pdb, balance_currency, new_currency); + if (price) { + balance = gnc_numeric_mul (balance, gnc_price_get_value (price), + gnc_commodity_get_fraction (new_currency), + GNC_RND_ROUND); + gnc_price_unref (price); + return balance; + } + + /* + * no direct price found, try if we find a price in another currency + * and convert in two stages + */ + price_list = gnc_pricedb_lookup_latest_any_currency(pdb, balance_currency); + if (!price_list) { + balance = gnc_numeric_zero (); + return balance; + } + + list_helper = price_list; + currency_price_value = gnc_numeric_zero(); + + do { + price = (GNCPrice *)(list_helper->data); + + intermediate_currency = gnc_price_get_currency(price); + currency_price = gnc_pricedb_lookup_latest(pdb, intermediate_currency, + new_currency); + if(currency_price) { + currency_price_value = gnc_price_get_value(currency_price); + gnc_price_unref(currency_price); + } else { + currency_price = gnc_pricedb_lookup_latest(pdb, new_currency, + intermediate_currency); + if (currency_price) { + /* here we need the reciprocal */ + currency_price_value = gnc_numeric_div(gnc_numeric_create(1, 1), + gnc_price_get_value(currency_price), + gnc_commodity_get_fraction (new_currency), + GNC_RND_ROUND); + gnc_price_unref(currency_price); + } + } + + list_helper = list_helper->next; + } while((list_helper != NULL) && + (!gnc_numeric_zero_p(currency_price_value))); + + balance = gnc_numeric_mul (balance, currency_price_value, + gnc_commodity_get_fraction (new_currency), + GNC_RND_ROUND); + balance = gnc_numeric_mul (balance, gnc_price_get_value (price), + gnc_commodity_get_fraction (new_currency), + GNC_RND_ROUND); + + gnc_price_list_destroy(price_list); + return balance; +} + +/* + * Given an account and a GetBalanceFn pointer, extract the requested + * balance from the account and then convert it to the desired + * currency. + */ +static gnc_numeric +xaccAccountGetXxxBalanceInCurrency (Account *account, + xaccGetBalanceFn fn, + gnc_commodity *report_currency) +{ + gnc_numeric balance; + + if (!account || !fn || !report_currency) + return gnc_numeric_zero (); + balance = fn(account); + return xaccAccountConvertBalanceToCurrency(account, balance, + account->commodity, + report_currency); +} + +/* + * Data structure used to pass various arguments into the following fn. + */ +typedef struct +{ + gnc_commodity *currency; + gnc_numeric balance; + xaccGetBalanceFn fn; +} CurrencyBalance; + + +/* + * A helper function for iterating over all the accounts in a list or + * tree. This function is called once per account, and sums up the + * values of all these accounts. + */ +static gpointer +xaccAccountBalanceHelper (Account *account, gpointer data) +{ + CurrencyBalance *cb = data; + gnc_numeric balance; + + if (!cb->fn || !cb->currency) + return NULL; + balance = xaccAccountGetXxxBalanceInCurrency (account, cb->fn, cb->currency); + cb->balance = gnc_numeric_add (cb->balance, balance, + gnc_commodity_get_fraction (cb->currency), + GNC_RND_ROUND); + return NULL; +} + +/* + * Common function that iterates recursively over all accounts below + * the specified account. It uses the previous routine to sum up the + * balances of all its children, and uses the specified function for + * extracting the balance. This function may extract the current + * value, the reconciled value, etc. + */ +static gnc_numeric +xaccAccountGetXxxBalanceInCurrencyRecursive (Account *account, + xaccGetBalanceFn fn, + gnc_commodity *report_commodity, + gboolean include_children) +{ + gnc_numeric balance; + + if (account == NULL) + return gnc_numeric_zero (); + if (!report_commodity) + report_commodity = xaccAccountGetCommodity (account); + balance = xaccAccountGetXxxBalanceInCurrency (account, fn, report_commodity); + + /* If needed, sum up the children converting to *this* account's commodity. */ + if (include_children) + { + CurrencyBalance cb = { report_commodity, balance, fn }; + + xaccGroupForEachAccount (account->children, xaccAccountBalanceHelper, &cb, TRUE); + balance = cb.balance; + } + + return balance; +} + +gnc_numeric +xaccAccountGetBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children) +{ + return + xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetBalance, + report_commodity, include_children); +} + + +gnc_numeric +xaccAccountGetClearedBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children) +{ + return + xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetClearedBalance, + report_commodity, include_children); +} + + +gnc_numeric +xaccAccountGetReconciledBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children) +{ + return + xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetReconciledBalance, + report_commodity, include_children); +} + +gnc_numeric +xaccAccountGetPresentBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children) +{ + return + xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetPresentBalance, + report_commodity, include_children); +} + +gnc_numeric +xaccAccountGetProjectedMinimumBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children) +{ + return + xaccAccountGetXxxBalanceInCurrencyRecursive (account, xaccAccountGetProjectedMinimumBalance, + report_commodity, include_children); +} + /********************************************************************\ \********************************************************************/ @@ -2950,9 +3234,11 @@ gboolean xaccAccountRegister (void) { ACCOUNT_CODE_, QUERYCORE_STRING, (QueryAccess)xaccAccountGetCode }, { ACCOUNT_DESCRIPTION_, QUERYCORE_STRING, (QueryAccess)xaccAccountGetDescription }, { ACCOUNT_NOTES_, QUERYCORE_STRING, (QueryAccess)xaccAccountGetNotes }, + { ACCOUNT_PRESENT_, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetPresentBalance }, { ACCOUNT_BALANCE_, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetBalance }, - { ACCOUNT_CLEARED_BALANCE, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetClearedBalance }, - { ACCOUNT_RECONCILED_BALANCE, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetReconciledBalance }, + { ACCOUNT_CLEARED_, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetClearedBalance }, + { ACCOUNT_RECONCILED_, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetReconciledBalance }, + { ACCOUNT_FUTURE_MINIMUM_, QUERYCORE_NUMERIC, (QueryAccess)xaccAccountGetProjectedMinimumBalance }, { ACCOUNT_TAX_RELATED, QUERYCORE_BOOLEAN, (QueryAccess)xaccAccountGetTaxRelated }, { QUERY_PARAM_BOOK, GNC_ID_BOOK, (QueryAccess)xaccAccountGetBook }, { QUERY_PARAM_GUID, QUERYCORE_GUID, (QueryAccess)xaccAccountGetGUID }, diff --git a/src/engine/Account.h b/src/engine/Account.h index f53a66e8af..6581c778cd 100644 --- a/src/engine/Account.h +++ b/src/engine/Account.h @@ -34,6 +34,10 @@ #include "kvp_frame.h" +typedef gnc_numeric (*xaccGetBalanceFn)( Account *account ); +typedef gnc_numeric (*xaccGetBalanceInCurrencyFn) (Account *account, + gnc_commodity *report_commodity, + gboolean include_children); /** The account types are used to determine how the transaction data * in the account is displayed. These values can be safely changed @@ -311,8 +315,30 @@ gnc_numeric xaccAccountGetBalance (Account *account); gnc_numeric xaccAccountGetClearedBalance (Account *account); /** Get the current balance of the account, only including reconciled transactions */ gnc_numeric xaccAccountGetReconciledBalance (Account *account); +gnc_numeric xaccAccountGetPresentBalance (Account *account); +gnc_numeric xaccAccountGetProjectedMinimumBalance (Account *account); /** Get the balance of the account as of the date specified */ gnc_numeric xaccAccountGetBalanceAsOfDate (Account *account, time_t date); + +gnc_numeric xaccAccountConvertBalanceToCurrency(Account *account, /* for book */ + gnc_numeric balance, + gnc_commodity *balance_currency, + gnc_commodity *new_currency); +gnc_numeric xaccAccountGetBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children); +gnc_numeric xaccAccountGetClearedBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children); +gnc_numeric xaccAccountGetReconciledBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children); +gnc_numeric xaccAccountGetPresentBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children); +gnc_numeric xaccAccountGetProjectedMinimumBalanceInCurrency (Account *account, + gnc_commodity *report_commodity, + gboolean include_children); /*@}*/ @@ -689,8 +715,10 @@ const char * xaccAccountGetQuoteTZ (Account *account); #define ACCOUNT_DESCRIPTION_ "desc" #define ACCOUNT_NOTES_ "notes" #define ACCOUNT_BALANCE_ "balance" -#define ACCOUNT_CLEARED_BALANCE "cleared-balance" -#define ACCOUNT_RECONCILED_BALANCE "reconciled-balance" +#define ACCOUNT_CLEARED_ "cleared" +#define ACCOUNT_RECONCILED_ "reconciled" +#define ACCOUNT_PRESENT_ "present" +#define ACCOUNT_FUTURE_MINIMUM_ "future-minimum" #define ACCOUNT_TAX_RELATED "tax-related-p" /** @} */ diff --git a/src/gnome/gnc-split-reg.c b/src/gnome/gnc-split-reg.c index d2b0af4207..69fe228b11 100644 --- a/src/gnome/gnc-split-reg.c +++ b/src/gnome/gnc-split-reg.c @@ -92,8 +92,6 @@ static void gnc_split_reg_determine_read_only( GNCSplitReg *gsr ); static void gnc_split_reg_change_style (GNCSplitReg *gsr, SplitRegisterStyle style); static GNCPlaceholderType gnc_split_reg_get_placeholder( GNCSplitReg *gsr ); -static gnc_numeric gsr_account_present_balance( Account *account ); -static gnc_numeric gsr_account_projectedminimum_balance( Account *account ); static gncUIWidget gnc_split_reg_get_parent( GNCLedgerDisplay *ledger ); static void gsr_create_menus( GNCSplitReg *gsr ); @@ -106,13 +104,8 @@ static void gsr_setup_status_widgets( GNCSplitReg *gsr ); static GtkWidget* gsr_create_popup_menu( GNCSplitReg *gsr ); -/** - * Defines a function pointer def to get a gnc_numeric from an account. - **/ -typedef gnc_numeric (*AmountGetterFn)(Account*); - static void gsr_update_summary_label( GtkWidget *label, - AmountGetterFn getter, + xaccGetBalanceFn getter, Account *leader, GNCPrintAmountInfo print_info, gnc_commodity *cmdty, @@ -596,7 +589,7 @@ gnc_split_reg_raise( GNCSplitReg *gsr ) static void gsr_update_summary_label( GtkWidget *label, - AmountGetterFn getter, + xaccGetBalanceFn getter, Account *leader, GNCPrintAmountInfo print_info, gnc_commodity *cmdty, @@ -703,19 +696,19 @@ gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data) if ( gsr->createFlags & CREATE_SUMMARYBAR ) { gsr_update_summary_label( gsr->balance_label, - (AmountGetterFn)gsr_account_present_balance, + xaccAccountGetPresentBalance, leader, print_info, commodity, reverse, euro ); gsr_update_summary_label( gsr->cleared_label, - (AmountGetterFn)xaccAccountGetClearedBalance, + xaccAccountGetClearedBalance, leader, print_info, commodity, reverse, euro ); gsr_update_summary_label( gsr->reconciled_label, - (AmountGetterFn)xaccAccountGetReconciledBalance, + xaccAccountGetReconciledBalance, leader, print_info, commodity, reverse, euro ); gsr_update_summary_label( gsr->future_label, - (AmountGetterFn)xaccAccountGetBalance, + xaccAccountGetBalance, leader, print_info, commodity, reverse, euro ); gsr_update_summary_label( gsr->projectedminimum_label, - (AmountGetterFn)gsr_account_projectedminimum_balance, + xaccAccountGetProjectedMinimumBalance, leader, print_info, commodity, reverse, euro ); if (gsr->shares_label != NULL) @@ -759,12 +752,15 @@ gsr_redraw_all_cb (GnucashRegister *g_reg, gpointer data) if (reverse) amount = gnc_numeric_neg (amount); - currency_amount = gnc_ui_convert_balance_to_currency(amount, commodity, currency); - + currency_amount = + xaccAccountConvertBalanceToCurrency(leader, amount, + commodity, currency); xaccSPrintAmount (string, currency_amount, print_info); - default_currency_amount = gnc_ui_convert_balance_to_currency(amount, commodity, - default_currency); + default_currency_amount = + xaccAccountConvertBalanceToCurrency(leader, amount, + commodity, + default_currency); if(!gnc_numeric_zero_p(default_currency_amount)) { strcat( string, " / " ); @@ -2124,74 +2120,6 @@ gnc_toolbar_change_cb (void *data) gnc_split_reg_refresh_toolbar( gsr ); } -/** - * A utility function which retreives the present balance from an Account. - * This should move somewhere more general? - **/ -static -gnc_numeric -gsr_account_present_balance (Account *account) -{ - GList *list; - GList *node; - time_t today; - - if (!account) - return gnc_numeric_zero (); - - today = gnc_timet_get_today_end(); - list = xaccAccountGetSplitList (account); - for (node = g_list_last (list); node; node = node->prev) - { - Split *split = node->data; - - if (xaccTransGetDate (xaccSplitGetParent (split)) <= today) - return xaccSplitGetBalance (split); - } - - return gnc_numeric_zero (); -} - -/** - * A utility function which retreives the present balance from an Account. - * This should move somewhere more general? - **/ -static -gnc_numeric -gsr_account_projectedminimum_balance (Account *account) -{ - GList *list; - GList *node; - time_t today; - gnc_numeric lowest = gnc_numeric_zero (); - int seen_a_transaction = 0; - - if (!account) - return gnc_numeric_zero (); - - today = gnc_timet_get_today_end(); - list = xaccAccountGetSplitList (account); - for (node = g_list_last (list); node; node = node->prev) - { - Split *split = node->data; - - if (!seen_a_transaction) - { - lowest = xaccSplitGetBalance (split); - seen_a_transaction = 1; - } - - if ( gnc_numeric_compare(xaccSplitGetBalance (split), lowest) < 0 ) - lowest = xaccSplitGetBalance (split); - - if (xaccTransGetDate (xaccSplitGetParent (split)) <= today) - return lowest; - } - - return lowest; -} - - static gncUIWidget gnc_split_reg_get_parent( GNCLedgerDisplay *ledger )