Andrew Sackville-West's changes to add the ability to lookup the

latest price before a specific date.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@13611 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
David Hampton 2006-03-12 22:18:28 +00:00
parent 872a2cafa8
commit c9bd69b302
4 changed files with 272 additions and 0 deletions

View File

@ -1,5 +1,10 @@
2006-03-12 David Hampton <hampton@employees.org> 2006-03-12 David Hampton <hampton@employees.org>
* src/engine/gnc-pricedb.[ch]:
* src/engine/gw-engine-spec.scm: Andrew Sackville-West's changes
to add the ability to lookup the latest price before a specific
date.
* src/register/register-gnome/gnucash-sheet.[ch]: * src/register/register-gnome/gnucash-sheet.[ch]:
* src/register/ledger-core/split-register.[ch]: * src/register/ledger-core/split-register.[ch]:
* src/register/ledger-core/split-register-control.c: * src/register/ledger-core/split-register-control.c:

View File

@ -1575,6 +1575,59 @@ gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
return result; return result;
} }
GNCPrice *
gnc_pricedb_lookup_latest_before (GNCPriceDB *db,
gnc_commodity *c,
gnc_commodity *currency,
Timespec t)
{
GList *price_list;
GNCPrice *current_price = NULL;
/* GNCPrice *next_price = NULL;
GNCPrice *result = NULL;*/
GList *item = NULL;
GHashTable *currency_hash;
QofBook *book;
QofBackend *be;
Timespec price_time;
if(!db || !c || !currency) return NULL;
ENTER ("db=%p commodity=%p currency=%p", db, c, currency);
book = qof_instance_get_book(&db->inst);
be = qof_book_get_backend(book);
#ifdef GNUCASH_MAJOR_VERSION
if (be && be->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_LATEST_BEFORE;
pl.prdb = db;
pl.commodity = c;
pl.currency = currency;
pl.date = t;
(be->price_lookup) (be, &pl);
}
#endif
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
if(!currency_hash) { LEAVE ("no currency hash"); return NULL; }
price_list = g_hash_table_lookup(currency_hash, currency);
if(!price_list) { LEAVE ("no price list"); return NULL; }
item = price_list;
do
{
price_time = gnc_price_get_time (item->data);
if (timespec_cmp(&price_time, &t) <= 0)
current_price = item->data;
item = item->next;
}
while (timespec_cmp(&price_time, &t) > 0 && item);
gnc_price_ref(current_price);
LEAVE (" ");
return current_price;
}
static void static void
lookup_nearest(gpointer key, gpointer val, gpointer user_data) lookup_nearest(gpointer key, gpointer val, gpointer user_data)
{ {
@ -1628,6 +1681,38 @@ lookup_nearest(gpointer key, gpointer val, gpointer user_data)
gnc_price_list_insert(return_list, result, FALSE); gnc_price_list_insert(return_list, result, FALSE);
} }
static void
lookup_latest_before(gpointer key, gpointer val, gpointer user_data)
{
//gnc_commodity *currency = (gnc_commodity *)key;
GList *price_list = (GList *)val;
GNCPrice *current_price = NULL;
/* GNCPrice *next_price = NULL;
GNCPrice *result = NULL;*/
GList *item = NULL;
GNCPriceLookupHelper *lookup_helper = (GNCPriceLookupHelper *)user_data;
GList **return_list = lookup_helper->return_list;
Timespec t = lookup_helper->time;
Timespec price_time;
if (price_list)
{
item = price_list;
do
{
price_time = gnc_price_get_time (item->data);
if (timespec_cmp(&price_time, &t) <= 0)
current_price = item->data;
item = item->next;
}
while (timespec_cmp(&price_time, &t) > 0 && item);
}
gnc_price_list_insert(return_list, current_price, FALSE);
}
GList * GList *
gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db, gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
const gnc_commodity *c, const gnc_commodity *c,
@ -1671,6 +1756,49 @@ gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
} }
GList *
gnc_pricedb_lookup_latest_before_any_currency(GNCPriceDB *db,
gnc_commodity *c,
Timespec t)
{
GList *result = NULL;
GHashTable *currency_hash;
GNCPriceLookupHelper lookup_helper;
QofBook *book;
QofBackend *be;
if(!db || !c) return NULL;
ENTER ("db=%p commodity=%p", db, c);
book = qof_instance_get_book(&db->inst);
be = qof_book_get_backend(book);
#ifdef GNUCASH_MAJOR_VERSION
if (be && be->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_LATEST_BEFORE;
pl.prdb = db;
pl.commodity = c;
pl.currency = NULL; /* can the backend handle this??? */
pl.date = t;
(be->price_lookup) (be, &pl);
}
#endif
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
if(!currency_hash) { LEAVE (" no currency hash"); return NULL; }
lookup_helper.return_list = &result;
lookup_helper.time = t;
g_hash_table_foreach(currency_hash, lookup_latest_before, &lookup_helper);
if(!result) { LEAVE (" "); return NULL; }
result = g_list_sort(result, compare_prices_by_date);
LEAVE (" ");
return result;
}
/* /*
* Convert a balance from one currency to another. * Convert a balance from one currency to another.
*/ */
@ -1817,6 +1945,7 @@ gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb,
balance = gnc_numeric_mul (balance, currency_price_value, balance = gnc_numeric_mul (balance, currency_price_value,
gnc_commodity_get_fraction (new_currency), gnc_commodity_get_fraction (new_currency),
GNC_HOW_RND_ROUND); GNC_HOW_RND_ROUND);
balance = gnc_numeric_mul (balance, gnc_price_get_value (price), balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
gnc_commodity_get_fraction (new_currency), gnc_commodity_get_fraction (new_currency),
GNC_HOW_RND_ROUND); GNC_HOW_RND_ROUND);
@ -1826,6 +1955,85 @@ gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb,
} }
gnc_numeric
gnc_pricedb_convert_balance_latest_before(GNCPriceDB *pdb,
gnc_numeric balance,
gnc_commodity *balance_currency,
gnc_commodity *new_currency,
Timespec t)
{
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;
/* Look for a direct price. */
price = gnc_pricedb_lookup_latest_before (pdb, balance_currency, new_currency, t);
if (price) {
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
gnc_commodity_get_fraction (new_currency),
GNC_HOW_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_before_any_currency(pdb, balance_currency, t);
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_before(pdb, intermediate_currency,
new_currency, t);
if(currency_price) {
currency_price_value = gnc_price_get_value(currency_price);
gnc_price_unref(currency_price);
} else {
currency_price = gnc_pricedb_lookup_nearest_in_time(pdb, new_currency,
intermediate_currency, t);
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_HOW_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_HOW_RND_ROUND);
balance = gnc_numeric_mul (balance, gnc_price_get_value (price),
gnc_commodity_get_fraction (new_currency),
GNC_HOW_RND_ROUND);
gnc_price_list_destroy(price_list);
return balance;
}
/* ==================================================================== */ /* ==================================================================== */
/* gnc_pricedb_foreach_price infrastructure /* gnc_pricedb_foreach_price infrastructure
*/ */

View File

@ -348,6 +348,20 @@ GNCPrice * gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
GList * gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db, GList * gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
const gnc_commodity *c, const gnc_commodity *c,
Timespec t); Timespec t);
/** gnc_pricedb_lookup_latest_before - return the latest price for the given commodity
in the given currency up to and including time t. */
GNCPrice * gnc_pricedb_lookup_latest_before(GNCPriceDB *db,
gnc_commodity *c,
gnc_commodity *currency,
Timespec t);
/** gnc_pricedb_lookup_latest_before_any_currency - return recent prices that
match the given commodity up to and including time t in any available currency. Prices
will be returned as a GNCPrice list (see above). */
GList * gnc_pricedb_lookup_latest_before_any_currency(GNCPriceDB *db,
gnc_commodity *c,
Timespec t);
/** gnc_pricedb_convert_balance_latest_price - Convert a balance /** gnc_pricedb_convert_balance_latest_price - Convert a balance
from one currency to another. */ from one currency to another. */
@ -366,6 +380,16 @@ gnc_pricedb_convert_balance_nearest_price(GNCPriceDB *pdb,
const gnc_commodity *new_currency, const gnc_commodity *new_currency,
Timespec t); Timespec t);
/** gnc_pricedb_convert_balance_latest_before - Convert a balance from one currency
to another using the lastest price prior to Timespec t. */
gnc_numeric
gnc_pricedb_convert_balance_latest_before(GNCPriceDB *pdb,
gnc_numeric balance,
gnc_commodity *balance_currency,
gnc_commodity *new_currency,
Timespec t);
/** gnc_pricedb_foreach_price - call f once for each price in db, until /** gnc_pricedb_foreach_price - call f once for each price in db, until
and unless f returns FALSE. If stable_order is not FALSE, make and unless f returns FALSE. If stable_order is not FALSE, make
sure the ordering of the traversal is stable (i.e. the same order sure the ordering of the traversal is stable (i.e. the same order

View File

@ -1300,6 +1300,27 @@ when no longer needed.")
(<gnc:commodity*> commodity) (<gnc:time-pair> t)) (<gnc:commodity*> commodity) (<gnc:time-pair> t))
"Returns the price(s) nearest to t in any currency available.") "Returns the price(s) nearest to t in any currency available.")
(gw:wrap-function
ws
'gnc:pricedb-lookup-latest-before
'<gnc:Price*>
"gnc_pricedb_lookup_latest_before"
'((<gnc:PriceDB*> db)
(<gnc:commodity*> commodity) (<gnc:commodity*> currency)
(<gnc:time-pair> t))
"Returns the latest price quote <= t. Unref price when finished with it.")
(gw:wrap-function
ws
'gnc:pricedb-lookup-latest-before-any-currency
'(gw:glist-of <gnc:Price*> caller-owned)
"gnc_pricedb_lookup_latest_before_any_currency"
'((<gnc:PriceDB*> db)
(<gnc:commodity*> commodity) (<gnc:time-pair> t))
"Returns the latest price quote(s) <= t in any currency available.")
(gw:wrap-function (gw:wrap-function
ws ws
'gnc:pricedb-get-prices 'gnc:pricedb-get-prices
@ -1352,6 +1373,20 @@ when no longer needed.")
"convert balance in commodity balance_commodity to new_currency using nearest price "convert balance in commodity balance_commodity to new_currency using nearest price
to time t.") to time t.")
(gw:wrap-function
ws
'gnc:pricedb-convert-balance-latest-before
'<gnc:numeric>
"gnc_pricedb_convert_balance_latest_before"
'((<gnc:PriceDB*> db)
(<gnc:numeric> balance)
(<gnc:commodity*> balance_commodity) (<gnc:commodity*> new_currency)
(<gnc:time-pair> t))
"convert balance in commodity balance_commodity to new_currency using latest price
prior to time t.")
;;=========== ;;===========
;; QofSession ;; QofSession