From 2ecdd70e2412dac95d6b65eece136e718797252f Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Mon, 19 Oct 2020 20:08:44 +0800 Subject: [PATCH] [gnc-pricedb.c][api] pull out composite pricedb price retriever * tries direct price retrieval from pricedb. * if fails, tries intermediate currency. --- libgnucash/engine/gnc-pricedb.c | 135 +++++++------------------------- libgnucash/engine/gnc-pricedb.h | 18 +++++ 2 files changed, 48 insertions(+), 105 deletions(-) diff --git a/libgnucash/engine/gnc-pricedb.c b/libgnucash/engine/gnc-pricedb.c index 3b39788c17..481df22adc 100644 --- a/libgnucash/engine/gnc-pricedb.c +++ b/libgnucash/engine/gnc-pricedb.c @@ -2435,35 +2435,6 @@ gnc_pricedb_lookup_latest_before_t64 (GNCPriceDB *db, return current_price; } -static gnc_numeric -direct_balance_conversion (GNCPriceDB *db, gnc_numeric bal, - const gnc_commodity *from, const gnc_commodity *to, - time64 t) -{ - GNCPrice *price; - gnc_numeric retval = gnc_numeric_zero(); - if (from == NULL || to == NULL) - return retval; - if (gnc_numeric_zero_p(bal)) - return retval; - if (t != INT64_MAX) - price = gnc_pricedb_lookup_nearest_in_time64(db, from, to, t); - else - price = gnc_pricedb_lookup_latest(db, from, to); - if (price == NULL) - return retval; - if (gnc_price_get_commodity(price) == from) - retval = gnc_numeric_mul (bal, gnc_price_get_value (price), - gnc_commodity_get_fraction (to), - GNC_HOW_RND_ROUND); - else - retval = gnc_numeric_div (bal, gnc_price_get_value (price), - gnc_commodity_get_fraction (to), - GNC_HOW_RND_ROUND); - gnc_price_unref (price); - return retval; - -} typedef struct { @@ -2601,72 +2572,35 @@ direct_price_conversion (GNCPriceDB *db, const gnc_commodity *from, return retval; } -static gnc_numeric -convert_balance(gnc_numeric bal, const gnc_commodity *from, - const gnc_commodity *to, PriceTuple tuple) +gnc_numeric +gnc_pricedb_get_nearest_price (GNCPriceDB *pdb, + const gnc_commodity *orig_currency, + const gnc_commodity *new_currency, + const time64 t) { - gnc_commodity *from_com = gnc_price_get_commodity(tuple.from); - gnc_commodity *from_cur = gnc_price_get_currency(tuple.from); - gnc_commodity *to_com = gnc_price_get_commodity(tuple.to); - gnc_commodity *to_cur = gnc_price_get_currency(tuple.to); - gnc_numeric from_val = gnc_price_get_value(tuple.from); - gnc_numeric to_val = gnc_price_get_value(tuple.to); - int fraction = gnc_commodity_get_fraction(to); + gnc_numeric price; - int no_round = GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER; - if (from_cur == from && to_cur == to) - return gnc_numeric_div(gnc_numeric_mul(bal, to_val, GNC_DENOM_AUTO, - no_round), - from_val, fraction, GNC_HOW_RND_ROUND); - if (from_com == from && to_com == to) - return gnc_numeric_div(gnc_numeric_mul(bal, from_val, GNC_DENOM_AUTO, - no_round), - to_val, fraction, GNC_HOW_RND_ROUND); - if (from_cur == from) - return gnc_numeric_div(bal, gnc_numeric_mul(from_val, to_val, - GNC_DENOM_AUTO, no_round), - fraction, GNC_HOW_RND_ROUND); - return gnc_numeric_mul(bal, gnc_numeric_mul(from_val, to_val, - GNC_DENOM_AUTO, no_round), - fraction, GNC_HOW_RND_ROUND); + if (gnc_commodity_equiv (orig_currency, new_currency)) + return gnc_numeric_create (1, 1); + + /* Look for a direct price. */ + price = direct_price_conversion (pdb, orig_currency, new_currency, t); + + /* + * no direct price found, try find a price in another currency + */ + if (gnc_numeric_zero_p (price)) + price = indirect_price_conversion (pdb, orig_currency, new_currency, t); + return gnc_numeric_reduce (price); } -static gnc_numeric -indirect_balance_conversion (GNCPriceDB *db, gnc_numeric bal, - const gnc_commodity *from, const gnc_commodity *to, - time64 t ) + +gnc_numeric +gnc_pricedb_get_latest_price (GNCPriceDB *pdb, + const gnc_commodity *orig_currency, + const gnc_commodity *new_currency) { - GList *from_prices = NULL, *to_prices = NULL; - PriceTuple tuple; - gnc_numeric zero = gnc_numeric_zero(); - if (from == NULL || to == NULL) - return zero; - if (gnc_numeric_zero_p(bal)) - return zero; - if (t == INT64_MAX) - { - from_prices = gnc_pricedb_lookup_latest_any_currency(db, from); - /* "to" is often the book currency which may have lots of prices, - so avoid getting them if they aren't needed. */ - if (from_prices) - to_prices = gnc_pricedb_lookup_latest_any_currency(db, to); - } - else - { - from_prices = gnc_pricedb_lookup_nearest_in_time_any_currency_t64(db, - from, t); - if (from_prices) - to_prices = gnc_pricedb_lookup_nearest_in_time_any_currency_t64(db, - to, t); - } - if (from_prices == NULL || to_prices == NULL) - return zero; - tuple = extract_common_prices(from_prices, to_prices, from, to); - gnc_price_list_destroy(from_prices); - gnc_price_list_destroy(to_prices); - if (tuple.from) - return convert_balance(bal, from, to, tuple); - return zero; + return gnc_pricedb_get_nearest_price (pdb, orig_currency, new_currency, INT64_MAX); } static gnc_numeric convert_amount_at_date (GNCPriceDB *pdb, @@ -2675,25 +2609,16 @@ static gnc_numeric convert_amount_at_date (GNCPriceDB *pdb, const gnc_commodity *new_currency, const time64 t) { - gnc_numeric new_value; + gnc_numeric price; - if (gnc_numeric_zero_p (amount) || - gnc_commodity_equiv (orig_currency, new_currency)) + if (gnc_numeric_zero_p (amount)) return amount; - /* Look for a direct price. */ - new_value = direct_balance_conversion - (pdb, amount, orig_currency, new_currency, t); - - /* - * no direct price found, try if we find a price in another currency - * and convert in two stages - */ - if (gnc_numeric_zero_p (new_value)) - new_value = indirect_balance_conversion - (pdb, amount, orig_currency, new_currency, t); + price = gnc_pricedb_get_nearest_price (pdb, orig_currency, new_currency, t); - return new_value; + return gnc_numeric_mul + (amount, price, gnc_commodity_get_fraction (new_currency), + GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND); } /* diff --git a/libgnucash/engine/gnc-pricedb.h b/libgnucash/engine/gnc-pricedb.h index 6a8301f3c0..5010476c3e 100644 --- a/libgnucash/engine/gnc-pricedb.h +++ b/libgnucash/engine/gnc-pricedb.h @@ -559,6 +559,24 @@ PriceList * gnc_pricedb_lookup_latest_before_any_currency_t64(GNCPriceDB *db, time64 t); +/** @brief Retrieve the price one currency to another at specified date + * @param pdb The pricedb + * @param orig_currency The commodity in which the balance is currently + * expressed + * @param new_currency The commodity to which the balance should be converted + * @return A price, or gnc_numeric_zero if no price is available. + */ + +gnc_numeric gnc_pricedb_get_nearest_price (GNCPriceDB *pdb, + const gnc_commodity *orig_currency, + const gnc_commodity *new_currency, + const time64 t); + +gnc_numeric gnc_pricedb_get_latest_price (GNCPriceDB *pdb, + const gnc_commodity *orig_currency, + const gnc_commodity *new_currency); + + /** @brief Convert a balance from one currency to another using the most recent * price between the two. * @param pdb The pricedb