[Gnucash-changes] r13611 - gnucash/trunk - Andrew Sackville-West's changes to add the ability to lookup the

David Hampton hampton at cvs.gnucash.org
Sun Mar 12 17:18:28 EST 2006


Author: hampton
Date: 2006-03-12 17:18:28 -0500 (Sun, 12 Mar 2006)
New Revision: 13611
Trac: http://svn.gnucash.org/trac/changeset/13611

Modified:
   gnucash/trunk/ChangeLog
   gnucash/trunk/src/engine/gnc-pricedb.c
   gnucash/trunk/src/engine/gnc-pricedb.h
   gnucash/trunk/src/engine/gw-engine-spec.scm
Log:
Andrew Sackville-West's changes to add the ability to lookup the
latest price before a specific date.


Modified: gnucash/trunk/ChangeLog
===================================================================
--- gnucash/trunk/ChangeLog	2006-03-12 21:54:04 UTC (rev 13610)
+++ gnucash/trunk/ChangeLog	2006-03-12 22:18:28 UTC (rev 13611)
@@ -1,5 +1,10 @@
 2006-03-12  David Hampton  <hampton at 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/ledger-core/split-register.[ch]:
 	* src/register/ledger-core/split-register-control.c:

Modified: gnucash/trunk/src/engine/gnc-pricedb.c
===================================================================
--- gnucash/trunk/src/engine/gnc-pricedb.c	2006-03-12 21:54:04 UTC (rev 13610)
+++ gnucash/trunk/src/engine/gnc-pricedb.c	2006-03-12 22:18:28 UTC (rev 13611)
@@ -1575,6 +1575,59 @@
   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
 lookup_nearest(gpointer key, gpointer val, gpointer user_data)
 {
@@ -1628,6 +1681,38 @@
   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 *
 gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
                                                 const gnc_commodity *c,
@@ -1671,6 +1756,49 @@
 }
 
 
+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.
  */
@@ -1817,6 +1945,7 @@
   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);
@@ -1826,6 +1955,85 @@
 }
 
 
+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
  */

Modified: gnucash/trunk/src/engine/gnc-pricedb.h
===================================================================
--- gnucash/trunk/src/engine/gnc-pricedb.h	2006-03-12 21:54:04 UTC (rev 13610)
+++ gnucash/trunk/src/engine/gnc-pricedb.h	2006-03-12 22:18:28 UTC (rev 13611)
@@ -348,7 +348,21 @@
 GList      * gnc_pricedb_lookup_nearest_in_time_any_currency(GNCPriceDB *db,
  		                                             const gnc_commodity *c,
 		                                             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
     from one currency to another. */
 gnc_numeric
@@ -366,6 +380,16 @@
 				          const gnc_commodity *new_currency,
 					  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
      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

Modified: gnucash/trunk/src/engine/gw-engine-spec.scm
===================================================================
--- gnucash/trunk/src/engine/gw-engine-spec.scm	2006-03-12 21:54:04 UTC (rev 13610)
+++ gnucash/trunk/src/engine/gw-engine-spec.scm	2006-03-12 22:18:28 UTC (rev 13611)
@@ -1300,7 +1300,28 @@
    (<gnc:commodity*> commodity) (<gnc:time-pair> t))
  "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
  ws
  'gnc:pricedb-get-prices
  '(gw:glist-of <gnc:Price*> caller-owned)
@@ -1352,6 +1373,20 @@
  "convert balance in commodity balance_commodity to new_currency using nearest price
 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
 



More information about the gnucash-changes mailing list