r22646 - gnucash/trunk/src - Improvements to exchange rate dialog.
Mike Alexander
mta at code.gnucash.org
Thu Dec 13 00:13:49 EST 2012
Author: mta
Date: 2012-12-13 00:13:49 -0500 (Thu, 13 Dec 2012)
New Revision: 22646
Trac: http://svn.gnucash.org/trac/changeset/22646
Modified:
gnucash/trunk/src/engine/gnc-pricedb.c
gnucash/trunk/src/engine/gnc-pricedb.h
gnucash/trunk/src/gnome-utils/dialog-transfer.c
Log:
Improvements to exchange rate dialog.
Use a price on the same day as the transaction as default if there is one.
Don't add a new price to the price DB if the nearest one on the same day
is equivalent to the one being added.
Modified: gnucash/trunk/src/engine/gnc-pricedb.c
===================================================================
--- gnucash/trunk/src/engine/gnc-pricedb.c 2012-12-13 05:13:42 UTC (rev 22645)
+++ gnucash/trunk/src/engine/gnc-pricedb.c 2012-12-13 05:13:49 UTC (rev 22646)
@@ -34,6 +34,9 @@
static gboolean add_price(GNCPriceDB *db, GNCPrice *p);
static gboolean remove_price(GNCPriceDB *db, GNCPrice *p, gboolean cleanup);
+static GNCPrice *lookup_nearest_in_time(GNCPriceDB *db, const gnc_commodity *c,
+ const gnc_commodity *currency,
+ Timespec t, gboolean sameday);
enum
{
@@ -1519,65 +1522,13 @@
}
-PriceList *
+GNCPrice *
gnc_pricedb_lookup_day(GNCPriceDB *db,
const gnc_commodity *c,
const gnc_commodity *currency,
Timespec t)
{
- GList *price_list;
- GList *result = NULL;
- GList *item = NULL;
- GHashTable *currency_hash;
- QofBook *book;
- QofBackend *be;
-
- 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);
- /* Convert to noon local time. */
- t = timespecCanonicalDayTime(t);
-#ifdef GNUCASH_MAJOR_VERSION
- if (be && be->price_lookup)
- {
- GNCPriceLookup pl;
- pl.type = LOOKUP_AT_TIME;
- 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;
- while (item)
- {
- GNCPrice *p = item->data;
- Timespec price_time = timespecCanonicalDayTime(gnc_price_get_time(p));
- if (timespec_equal(&price_time, &t))
- {
- result = g_list_prepend(result, p);
- gnc_price_ref(p);
- }
- item = item->next;
- }
- LEAVE (" ");
- return result;
+ return lookup_nearest_in_time(db, c, currency, t, TRUE);
}
#if 0 /* Not Used */
@@ -1687,11 +1638,12 @@
}
}
#endif
-GNCPrice *
-gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
- const gnc_commodity *c,
- const gnc_commodity *currency,
- Timespec t)
+static GNCPrice *
+lookup_nearest_in_time(GNCPriceDB *db,
+ const gnc_commodity *c,
+ const gnc_commodity *currency,
+ Timespec t,
+ gboolean sameday)
{
GList *price_list;
GNCPrice *current_price = NULL;
@@ -1752,14 +1704,27 @@
item = item->next;
}
- if (current_price)
+ if (current_price) /* How can this be null??? */
{
if (!next_price)
{
+ /* It's earlier than the last price on the list */
result = current_price;
+ if (sameday)
+ {
+ /* Must be on the same day. */
+ Timespec price_day;
+ Timespec t_day;
+ price_day = timespecCanonicalDayTime(gnc_price_get_time(current_price));
+ t_day = timespecCanonicalDayTime(t);
+ if (!timespec_equal(&price_day, &t_day))
+ result = NULL;
+ }
}
else
{
+ /* If the requested time is not earlier than the first price on the
+ list, then current_price and next_price will be the same. */
Timespec current_t = gnc_price_get_time(current_price);
Timespec next_t = gnc_price_get_time(next_price);
Timespec diff_current = timespec_diff(¤t_t, &t);
@@ -1767,16 +1732,43 @@
Timespec abs_current = timespec_abs(&diff_current);
Timespec abs_next = timespec_abs(&diff_next);
- /* Choose the price that is closest to the given time. In case of
- * a tie, prefer the older price since it actually existed at the
- * time. (This also fixes bug #541970.) */
- if (timespec_cmp(&abs_current, &abs_next) < 0)
+ if (sameday)
{
- result = current_price;
+ /* Result must be on same day, see if either of the two isn't */
+ Timespec t_day = timespecCanonicalDayTime(t);
+ Timespec current_day = timespecCanonicalDayTime(current_t);
+ Timespec next_day = timespecCanonicalDayTime(next_t);
+ if (timespec_equal(¤t_day, &t_day))
+ {
+ if (timespec_equal(&next_day, &t_day))
+ {
+ /* Both on same day, return nearest */
+ if (timespec_cmp(&abs_current, &abs_next) < 0)
+ result = current_price;
+ else
+ result = next_price;
+ }
+ else
+ /* current_price on same day, next_price not */
+ result = current_price;
+ }
+ else if (timespec_equal(&next_day, &t_day))
+ /* next_price on same day, current_price not */
+ result = next_price;
}
else
{
- result = next_price;
+ /* Choose the price that is closest to the given time. In case of
+ * a tie, prefer the older price since it actually existed at the
+ * time. (This also fixes bug #541970.) */
+ if (timespec_cmp(&abs_current, &abs_next) < 0)
+ {
+ result = current_price;
+ }
+ else
+ {
+ result = next_price;
+ }
}
}
}
@@ -1787,6 +1779,15 @@
}
GNCPrice *
+gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
+ const gnc_commodity *c,
+ const gnc_commodity *currency,
+ Timespec t)
+{
+ return lookup_nearest_in_time(db, c, currency, t, FALSE);
+}
+
+GNCPrice *
gnc_pricedb_lookup_latest_before (GNCPriceDB *db,
gnc_commodity *c,
gnc_commodity *currency,
Modified: gnucash/trunk/src/engine/gnc-pricedb.h
===================================================================
--- gnucash/trunk/src/engine/gnc-pricedb.h 2012-12-13 05:13:42 UTC (rev 22645)
+++ gnucash/trunk/src/engine/gnc-pricedb.h 2012-12-13 05:13:49 UTC (rev 22646)
@@ -346,13 +346,13 @@
const gnc_commodity *currency,
Timespec t);
-/** gnc_pricedb_lookup_day - return all prices that match the given
- commodity, currency, and timespec. Prices will be returned as a
- GNCPrice list (see above). */
-PriceList * gnc_pricedb_lookup_day(GNCPriceDB *db,
- const gnc_commodity *commodity,
- const gnc_commodity *currency,
- Timespec t);
+/** gnc_pricedb_lookup_day - return the price that matchex the given
+ commodity, currency, and timespec which is on the same day.
+ If no prices are on that day, returns a null value. */
+GNCPrice * gnc_pricedb_lookup_day(GNCPriceDB *db,
+ const gnc_commodity *commodity,
+ const gnc_commodity *currency,
+ Timespec t);
/** gnc_pricedb_lookup_nearest_in_time - return the price for the given
Modified: gnucash/trunk/src/gnome-utils/dialog-transfer.c
===================================================================
--- gnucash/trunk/src/gnome-utils/dialog-transfer.c 2012-12-13 05:13:42 UTC (rev 22645)
+++ gnucash/trunk/src/gnome-utils/dialog-transfer.c 2012-12-13 05:13:49 UTC (rev 22646)
@@ -198,6 +198,7 @@
Timespec date;
gnc_commodity *from = xferData->from_commodity;
gnc_commodity *to = xferData->to_commodity;
+ gboolean reverse;
if (!xferData) return;
if (!xferData->from_commodity || ! xferData->to_commodity) return;
@@ -209,30 +210,52 @@
/* XXX: I'm ALWAYS going to update whenever we get called */
- /* grab the price nearest to the DATE out of the pricedb */
+ /* grab the price on the same day or nearest to the DATE out of the pricedb */
date = gnc_date_edit_get_date_ts (GNC_DATE_EDIT (xferData->date_entry));
- prc = gnc_pricedb_lookup_nearest_in_time (xferData->pricedb,
- from, to, date);
-
- if (prc)
+
+ /* Look for a price on the same day or, failing that, closest in time. */
+ prc = gnc_pricedb_lookup_day (xferData->pricedb, from, to, date);
+ reverse = FALSE;
+
+ if (!prc)
{
- /* grab the price from the pricedb */
- price = gnc_price_get_value (prc);
- PINFO("Found price: 1 %s = %f %s", gnc_commodity_get_mnemonic(from),
- gnc_numeric_to_double(price), gnc_commodity_get_mnemonic(to));
+ /* Look for reverse price on same day */
+ prc = gnc_pricedb_lookup_day (xferData->pricedb, to, from, date);
+ reverse = TRUE;
}
- else
+
+ if (!prc)
{
- prc = gnc_pricedb_lookup_nearest_in_time (xferData->pricedb,
- to, from, date);
- if (!prc)
- return;
- price = gnc_price_get_value (prc);
+ /* Didn't find one on the same day, look for nearest in time */
+ prc = gnc_pricedb_lookup_nearest_in_time (xferData->pricedb, from,
+ to, date);
+ reverse = FALSE;
+ }
+
+ if (!prc)
+ {
+ prc = gnc_pricedb_lookup_nearest_in_time (xferData->pricedb, to,
+ from, date);
+ reverse = TRUE;
+ }
+
+ if (!prc)
+ return;
+
+ /* grab the price from the pricedb */
+ price = gnc_price_get_value (prc);
+ if (reverse)
+ {
PINFO("Found reverse price: 1 %s = %f %s", gnc_commodity_get_mnemonic(to),
gnc_numeric_to_double(price), gnc_commodity_get_mnemonic(from));
price = gnc_numeric_div (gnc_numeric_create (1, 1), price,
GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
}
+ else
+ {
+ PINFO("Found price: 1 %s = %f %s", gnc_commodity_get_mnemonic(from),
+ gnc_numeric_to_double(price), gnc_commodity_get_mnemonic(to));
+ }
/* and set the price entry */
gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (xferData->price_edit), price);
@@ -1519,59 +1542,75 @@
!(gnc_is_euro_currency (from) && gnc_is_euro_currency (to)))
{
GNCPrice *price;
- GList *prices;
+ gnc_numeric value;
+ gnc_commodity *tmp;
- /* First see if an entry exists at time ts */
- prices = gnc_pricedb_lookup_at_time (xferData->pricedb, from, to, ts);
- if (prices)
+ /* compute the price -- maybe we need to swap? */
+
+ value = gnc_xfer_dialog_compute_price(xferData);
+ value = gnc_numeric_abs (value);
+
+ /* Try to be consistent about how quotes are installed. */
+ if (from == gnc_default_currency())
{
- PINFO("Found price for %s in %s", gnc_commodity_get_mnemonic(from),
- gnc_commodity_get_mnemonic(to));
+ tmp = from;
+ from = to;
+ to = tmp;
+ value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
}
- else
+ else if ((to != gnc_default_currency()) &&
+ (strcmp (gnc_commodity_get_mnemonic(from),
+ gnc_commodity_get_mnemonic(to)) < 0))
{
- prices = gnc_pricedb_lookup_at_time (xferData->pricedb, to, from, ts);
- if (prices)
+ tmp = from;
+ from = to;
+ to = tmp;
+ value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ }
+
+ /* First see if the closest entry on the same day has an equivalent rate */
+ price = gnc_pricedb_lookup_day (xferData->pricedb, from, to, ts);
+ if (price)
+ {
+ gnc_numeric price_value = gnc_price_get_value(price);
+ if (!gnc_numeric_same (value, price_value,
+ MIN(gnc_numeric_denom(value),
+ gnc_numeric_denom(price_value)),
+ GNC_HOW_RND_ROUND_HALF_UP))
{
- PINFO("Found reverse price for %s in %s", gnc_commodity_get_mnemonic(to),
- gnc_commodity_get_mnemonic(from));
+ gnc_price_unref (price);
+ price = NULL;
}
+ if (price)
+ PINFO("Found price for %s in %s", gnc_commodity_get_mnemonic(from),
+ gnc_commodity_get_mnemonic(to));
}
-
- /* If so, do nothing (well, destroy the list). if not, create one. */
- if (prices)
- {
- gnc_price_list_destroy (prices);
- }
else
{
- gnc_commodity *tmp;
- gnc_numeric value;
-
- /* compute the price -- maybe we need to swap? */
- value = gnc_xfer_dialog_compute_price(xferData);
- value = gnc_numeric_abs (value);
-
- /* Try to be consistent about how quotes are installed. */
- if (from == gnc_default_currency())
+ price = gnc_pricedb_lookup_day (xferData->pricedb, to, from, ts);
+ if (price)
{
- tmp = from;
- from = to;
- to = tmp;
- value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
- GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ gnc_numeric price_value = gnc_numeric_div (gnc_numeric_create(1, 1),
+ gnc_price_get_value(price),
+ GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+ if (!gnc_numeric_same (value, price_value,
+ MIN(gnc_numeric_denom(value),
+ gnc_numeric_denom(price_value)),
+ GNC_HOW_RND_ROUND_HALF_UP))
+ {
+ gnc_price_unref (price);
+ price = NULL;
+ }
+ if (price)
+ PINFO("Found reverse price for %s in %s", gnc_commodity_get_mnemonic(to),
+ gnc_commodity_get_mnemonic(from));
}
- else if ((to != gnc_default_currency()) &&
- (strcmp (gnc_commodity_get_mnemonic(from),
- gnc_commodity_get_mnemonic(to)) < 0))
- {
- tmp = from;
- from = to;
- to = tmp;
- value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
- GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
- }
+ }
+ if (!price)
+ {
price = gnc_price_create (xferData->book);
gnc_price_begin_edit (price);
gnc_price_set_commodity (price, from);
@@ -1581,10 +1620,11 @@
gnc_price_set_value (price, value);
gnc_pricedb_add_price (xferData->pricedb, price);
gnc_price_commit_edit (price);
- gnc_price_unref (price);
PINFO("Created price: 1 %s = %f %s", gnc_commodity_get_mnemonic(from),
gnc_numeric_to_double(value), gnc_commodity_get_mnemonic(to));
}
+
+ gnc_price_unref (price);
}
}
More information about the gnucash-changes
mailing list