mirror of
				https://github.com/Gnucash/gnucash.git
				synced 2025-02-25 18:55:30 -06:00 
			
		
		
		
	[gnc-pricedb.c][api] pull out composite pricedb price retriever
* tries direct price retrieval from pricedb. * if fails, tries intermediate currency.
This commit is contained in:
		@@ -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);
 | 
			
		||||
    price = gnc_pricedb_get_nearest_price (pdb, 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);
 | 
			
		||||
 | 
			
		||||
    return new_value;
 | 
			
		||||
    return gnc_numeric_mul
 | 
			
		||||
        (amount, price, gnc_commodity_get_fraction (new_currency),
 | 
			
		||||
         GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user