gnucash maint: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Tue Sep 15 15:07:10 EDT 2015


Updated	 via  https://github.com/Gnucash/gnucash/commit/bc9285bb (commit)
	 via  https://github.com/Gnucash/gnucash/commit/05bb4bd9 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/74d11b27 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/cfa5aa1c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4259255a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6b6920fd (commit)
	 via  https://github.com/Gnucash/gnucash/commit/585cc488 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d9a0f311 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7db7e0cf (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7d8b51e8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d52a0b60 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d4968d3b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/157c7e30 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/890cfe21 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/96471379 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d7fb92d0 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/93bb5c0f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ffe96b30 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/bfbb5087 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/86320a4d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c0683976 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e12c89b5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6b520778 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c7c97be6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/73233a5e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3a51c0d5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/06f70bad (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ea48ed88 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0b033281 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c6a67f4e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/407d61cb (commit)
	 via  https://github.com/Gnucash/gnucash/commit/47f91c02 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e1b4e45d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9a611a2a (commit)
	from  https://github.com/Gnucash/gnucash/commit/e921de8b (commit)



commit bc9285bbfbb80bb8a38b19fe70117b31874b151f
Merge: e921de8 05bb4bd
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 15 12:06:46 2015 -0700

    Merge branch 'single-price' into maint


commit 05bb4bd955f87ab2934f5dc80611c8757c395cfe
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 15 12:03:39 2015 -0700

    Prevent F::Q from updating PRICE_SOURCE_EDIT_DLG prices.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 6cb0899..4a3ed05 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1325,7 +1325,7 @@ gnc_xfer_dialog_set_fetch_sensitive (GtkWidget *fetch)
     if (gnc_quote_source_fq_installed ())
     {
         gtk_widget_set_sensitive (fetch, TRUE);
-        gtk_widget_set_tooltip_text (fetch, _("Retrieve the current online quote"));
+        gtk_widget_set_tooltip_text (fetch, _("Retrieve the current online quote. This will fail if there is a manually-created price for today."));
         return;
     }
     gtk_widget_set_sensitive (fetch, FALSE);
diff --git a/src/scm/price-quotes.scm b/src/scm/price-quotes.scm
index c078822..68c67bf 100644
--- a/src/scm/price-quotes.scm
+++ b/src/scm/price-quotes.scm
@@ -426,14 +426,16 @@
                   (if (not (null? saved-price))
                       (set! price (gnc-numeric-invert(price))))))
             (if (not (null? saved-price))
-              (begin
-                (gnc-price-begin-edit saved-price)
-                (gnc-price-set-time saved-price gnc-time)
+                (if (> (gnc-price-get-source saved-price) PRICE-SOURCE-FQ)
+                    (begin
+                      (gnc-price-begin-edit saved-price)
+                      (gnc-price-set-time saved-price gnc-time)
                       (gnc-price-set-source saved-price PRICE-SOURCE-FQ)
-                (gnc-price-set-typestr saved-price price-type)
-                (gnc-price-set-value saved-price price)
-                (gnc-price-commit-edit saved-price)
-                #f)
+                      (gnc-price-set-typestr saved-price price-type)
+                      (gnc-price-set-value saved-price price)
+                      (gnc-price-commit-edit saved-price)
+                      #f)
+                    #f)
               (let ((gnc-price (gnc-price-create book)))
                 (if (not gnc-price)
                     (string-append

commit 74d11b273616909de2c58aad0421d99e04fe9143
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Sep 12 12:09:46 2015 -0700

    Remove unnecessary and harmful price rounding.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 24fbb84..6cb0899 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -332,10 +332,7 @@ gnc_xfer_dialog_update_price (XferDialog *xferData)
     /* grab the price from the pricedb */
     price_value = gnc_price_get_value (pr.price);
     if (pr.reverse)
-    {
         price_value = gnc_numeric_invert (price_value);
-        price_value = round_price(pr.from, pr.to, price_value);
-    }
     gnc_price_unref(pr.price);
 
     /* and set the price entry */
@@ -1088,8 +1085,6 @@ gnc_xfer_to_amount_update_cb(GtkWidget *widget, GdkEventFocus *event,
 
     gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->to_amount_edit));
     price_value = gnc_xfer_dialog_compute_price_value(xferData);
-    price_value = round_price(xferData->from_commodity, xferData->to_commodity,
-                              price_value);
     gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit),
                                price_value);
     xferData->price_source = PRICE_SOURCE_XFER_DLG_VAL;
@@ -1581,7 +1576,6 @@ swap_commodities(gnc_commodity **from, gnc_commodity **to, gnc_numeric value)
     *to = *from;
     *from = tmp;
     value = gnc_numeric_invert(value);
-    value = round_price(*from, *to, value);
     return value;
 }
 
@@ -1861,8 +1855,7 @@ gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData)
     {
         gnc_numeric price_value = gnc_price_get_value(pr.price);
         if (pr.reverse)
-            price_value = round_price(pr.from, pr.to,
-                                      gnc_numeric_invert(price_value));
+            price_value = gnc_numeric_invert(price_value);
          _gnc_xfer_dialog_set_price_edit(xferData, price_value);
         gnc_price_unref (pr.price);
     }
@@ -2479,10 +2472,7 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
         gnc_xfer_dialog_select_to_currency(xfer, txn_cur);
         gnc_xfer_dialog_select_from_currency(xfer, xfer_com);
         if (!gnc_numeric_zero_p(*exch_rate))
-        {
             dialog_rate = gnc_numeric_invert(*exch_rate);
-            dialog_rate = round_price(xfer_com, txn_cur, *exch_rate);
-        }
         amount = gnc_numeric_neg(amount);
     }
     else

commit cfa5aa1cb24e59611ee46f1b36c27afdab8b8bcd
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Sep 12 12:04:34 2015 -0700

    Remove the preference for storing prices relative to the base currency.
    
    It interferes with the preference for storing the price in the direction
    in which the price is >1 for preserving sigfigs.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 4580217..24fbb84 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1602,12 +1602,6 @@ create_price(XferDialog *xferData, Timespec ts)
         return;
 
     value = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->price_edit));
-    /* Try to be consistent about how quotes are installed. */
-    if (from == gnc_default_currency() ||
-        ((to != gnc_default_currency()) &&
-         (strcmp (gnc_commodity_get_mnemonic(from),
-                  gnc_commodity_get_mnemonic(to)) < 0)))
-        swap_amount (&from, &to, &value, &from_amt, &to_amt);
 
 /* Normally we want to store currency rates such that the rate > 1 and commodity
  * prices in terms of a currency regardless of value. However, if we already

commit 4259255af1287794a7c5ea9c327ed1e56f381507
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Sep 12 12:02:28 2015 -0700

    Export the price-source enums to Guile and use them in price-quotes.scm.

diff --git a/src/engine/engine.i b/src/engine/engine.i
index 99a1039..6f51011 100644
--- a/src/engine/engine.i
+++ b/src/engine/engine.i
@@ -334,7 +334,7 @@ KvpValue * kvp_frame_get_slot_path_gslist (KvpFrame *frame, GSList *key_path);
     SET_ENUM("TRANS-DATE-POSTED");
     SET_ENUM("TRANS-DESCRIPTION");
     SET_ENUM("TRANS-NUM");
-    
+
     SET_ENUM("KVP-OPTION-PATH");
 
     SET_ENUM("OPTION-SECTION-ACCOUNTS");
@@ -355,6 +355,15 @@ KvpValue * kvp_frame_get_slot_path_gslist (KvpFrame *frame, GSList *key_path);
     SET_ENUM("GNC-HOW-RND-ROUND");
     SET_ENUM("GNC-HOW-RND-NEVER");
 
+    SET_ENUM("PRICE-SOURCE-EDIT-DLG");
+    SET_ENUM("PRICE-SOURCE-FQ");
+    SET_ENUM("PRICE-SOURCE-USER-PRICE");
+    SET_ENUM("PRICE-SOURCE-XFER-DLG-VAL");
+    SET_ENUM("PRICE-SOURCE-SPLIT-REG");
+    SET_ENUM("PRICE-SOURCE-STOCK-SPLIT");
+    SET_ENUM("PRICE-SOURCE-INVOICE");
+    SET_ENUM("PRICE-SOURCE-INVALID");
+
 #undef SET_ENUM
   }
 
diff --git a/src/scm/price-quotes.scm b/src/scm/price-quotes.scm
index e72fdae..c078822 100644
--- a/src/scm/price-quotes.scm
+++ b/src/scm/price-quotes.scm
@@ -429,7 +429,7 @@
               (begin
                 (gnc-price-begin-edit saved-price)
                 (gnc-price-set-time saved-price gnc-time)
-                (gnc-price-set-source-string saved-price "Finance::Quote")
+                      (gnc-price-set-source saved-price PRICE-SOURCE-FQ)
                 (gnc-price-set-typestr saved-price price-type)
                 (gnc-price-set-value saved-price price)
                 (gnc-price-commit-edit saved-price)
@@ -443,7 +443,7 @@
                       (gnc-price-set-commodity gnc-price commodity)
                       (gnc-price-set-currency gnc-price currency)
                       (gnc-price-set-time gnc-price gnc-time)
-                      (gnc-price-set-source-string gnc-price "Finance::Quote")
+                      (gnc-price-set-source gnc-price PRICE-SOURCE-FQ)
                       (gnc-price-set-typestr gnc-price price-type)
                       (gnc-price-set-value gnc-price price)
                       (gnc-price-commit-edit gnc-price)

commit 6b6920fd04621845d6c2042ed4ef18bbda3d2813
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Sep 9 15:25:06 2015 -0700

    Remove static function swap_amount(), not used.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index a42f68b..4580217 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1573,20 +1573,6 @@ create_transaction(XferDialog *xferData, Timespec *ts,
         xferData->transaction_cb(trans, xferData->transaction_user_data);
 }
 
-static void
-swap_amount (gnc_commodity **from, gnc_commodity **to, gnc_numeric *value,
-             gnc_numeric *from_amt, gnc_numeric *to_amt)
-{
-    gnc_commodity *tmp = *from;
-    gnc_numeric *tmp_amt = from_amt;
-    *from = *to;
-    *to = tmp;
-    from_amt = to_amt;
-    to_amt = tmp_amt;
-    *value = gnc_numeric_invert (*value);
-    *value = round_price(*from, *to, *value);
-}
-
 static gnc_numeric
 swap_commodities(gnc_commodity **from, gnc_commodity **to, gnc_numeric value)
 {

commit 585cc4883ffae9af2824bad9651aac808f48e83f
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Sep 9 15:06:56 2015 -0700

    Implement user-entered-price preference.
    
    Add user:price as a source and prefer values with lower PriceSource enum
    values over higher ones: In other words a price with a lower PriceSource
    value (e.g. user:price-editor) will overwrite one with a higher value (e.g.
    user:split-register) and not the other way around.

diff --git a/src/engine/gnc-pricedb.c b/src/engine/gnc-pricedb.c
index 8cb841b..bdc8e41 100644
--- a/src/engine/gnc-pricedb.c
+++ b/src/engine/gnc-pricedb.c
@@ -71,8 +71,12 @@ gnc_price_init(GNCPrice* price)
  */
 static const char* source_names[] =
 {
-    "user:price-editor", //sync with price_to_gui in dialog-price-editor.c
-    "Finance::Quote",    //sync with
+    /* sync with price_to_gui in dialog-price-editor.c */
+    "user:price-editor",
+    /* sync with commidity-tz-quote->price in price-quotes.scm */
+    "Finance::Quote",
+    "user:price",
+    /* String retained for backwards compatibility. */
     "user:xfer-dialog",
     "user:split-register",
     "user:stock-split",
@@ -1004,7 +1008,7 @@ insert_or_replace_price(GNCPriceDB *db, GNCPrice *p)
                                                   p->currency, p->tmspec);
     if (old_price == NULL)
         return TRUE;
-    if (p->source != PRICE_SOURCE_FQ)
+    if (p->source < old_price->source)
         return TRUE;
     return FALSE;
 
diff --git a/src/engine/gnc-pricedb.h b/src/engine/gnc-pricedb.h
index 00a4126..e3966b3 100644
--- a/src/engine/gnc-pricedb.h
+++ b/src/engine/gnc-pricedb.h
@@ -165,7 +165,8 @@ typedef enum
 {
     PRICE_SOURCE_EDIT_DLG,         // "user:price-editor"
     PRICE_SOURCE_FQ,               // "Finance::Quote"
-    PRICE_SOURCE_XFER_DLG,         // "user:xfer-dialog"
+    PRICE_SOURCE_USER_PRICE,       // "user:price"
+    PRICE_SOURCE_XFER_DLG_VAL,     // "user:xfer-dialog"
     PRICE_SOURCE_SPLIT_REG,        // "user:split-register"
     PRICE_SOURCE_STOCK_SPLIT,      // "user:stock-split"
     PRICE_SOURCE_INVOICE,          // "user:invoice-post"
@@ -174,7 +175,7 @@ typedef enum
 
 #define PRICE_TYPE_LAST "last"
 #define PRICE_TYPE_UNK "unknown"
-
+#define PRICE_TYPE_TRN "transaction"
 /* ------------------ */
 /** @name Constructors
     @{ */
diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index b7931ad..a42f68b 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -121,6 +121,8 @@ struct _xferDialog
      * creating a transaction)
      */
     gnc_numeric *exch_rate;
+    PriceSource price_source;
+    const char *price_type;
 
     /* Callback function to notify of the newly created Transaction */
     gnc_xfer_dialog_cb transaction_cb;
@@ -1058,6 +1060,9 @@ gnc_xfer_price_update_cb(GtkWidget *widget, GdkEventFocus *event,
     XferDialog *xferData = data;
 
     gnc_xfer_update_to_amount (xferData);
+    xferData->price_source = PRICE_SOURCE_USER_PRICE;
+    xferData->price_type = PRICE_TYPE_TRN;
+
 
     return FALSE;
 }
@@ -1087,6 +1092,8 @@ gnc_xfer_to_amount_update_cb(GtkWidget *widget, GdkEventFocus *event,
                               price_value);
     gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit),
                                price_value);
+    xferData->price_source = PRICE_SOURCE_XFER_DLG_VAL;
+    xferData->price_type = PRICE_TYPE_TRN;
     gnc_xfer_dialog_update_conv_info(xferData);
 
     return FALSE;
@@ -1635,9 +1642,9 @@ create_price(XferDialog *xferData, Timespec ts)
             gnc_price_unref (pr.price);
             return;
         }
-        if (gnc_price_get_source(pr.price) == PRICE_SOURCE_FQ)
+        if (gnc_price_get_source(pr.price) < xferData->price_source)
         {
-            PINFO("Existing price is from Finance::Quote, so won't supersede.");
+            PINFO("Existing price is preferred, so won't supersede.");
             gnc_price_unref (pr.price);
             return;
         }
@@ -1650,7 +1657,8 @@ create_price(XferDialog *xferData, Timespec ts)
         value = round_price(pr.from, pr.to, value);
         gnc_price_begin_edit (pr.price);
         gnc_price_set_time (pr.price, ts);
-        gnc_price_set_source (pr.price, PRICE_SOURCE_XFER_DLG);
+        gnc_price_set_source (pr.price, xferData->price_source);
+        gnc_price_set_typestr(pr.price, xferData->price_type);
         gnc_price_set_value (pr.price, value);
         gnc_price_commit_edit (pr.price);
         PINFO("Modified price: 1 %s = %f %s",
@@ -1683,7 +1691,8 @@ create_price(XferDialog *xferData, Timespec ts)
     gnc_price_set_commodity (price, from);
     gnc_price_set_currency (price, to);
     gnc_price_set_time (price, ts);
-    gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
+    gnc_price_set_source (price, xferData->price_source);
+    gnc_price_set_typestr (price, xferData->price_type);
     gnc_price_set_value (price, value);
     gnc_pricedb_add_price (xferData->pricedb, price);
     gnc_price_commit_edit (price);
diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c
index 1332bf1..3e4eb74 100644
--- a/src/register/ledger-core/split-register.c
+++ b/src/register/ledger-core/split-register.c
@@ -2044,7 +2044,8 @@ recalculate_value (Split *split, SplitRegister *reg,
 }
 
 static void
-record_price (SplitRegister *reg, Account *account, gnc_numeric value)
+record_price (SplitRegister *reg, Account *account, gnc_numeric value,
+              PriceSource source)
 {
     Transaction *trans = gnc_split_register_get_current_trans (reg);
     QofBook *book = qof_instance_get_book (QOF_INSTANCE (account));
@@ -2084,8 +2085,9 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
             gnc_price_unref (price);
             return;
         }
-        if (gnc_price_get_source(price) == PRICE_SOURCE_FQ)
+        if (gnc_price_get_source(price) < PRICE_SOURCE_XFER_DLG_VAL)
         {
+            /* Existing price is preferred over this one. */
             gnc_price_unref(price);
             return;
         }
@@ -2098,7 +2100,8 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
                                     GNC_HOW_RND_ROUND_HALF_UP);
         gnc_price_begin_edit (price);
         gnc_price_set_time (price, ts);
-        gnc_price_set_source (price, PRICE_SOURCE_SPLIT_REG);
+        gnc_price_set_source (price, source);
+        gnc_price_set_typestr (price, PRICE_TYPE_TRN);
         gnc_price_set_value (price, value);
         gnc_price_commit_edit (price);
         gnc_price_unref (price);
@@ -2112,7 +2115,8 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
     gnc_price_set_commodity (price, comm);
     gnc_price_set_currency (price, curr);
     gnc_price_set_time (price, ts);
-    gnc_price_set_source (price, PRICE_SOURCE_SPLIT_REG);
+    gnc_price_set_source (price, source);
+    gnc_price_set_typestr (price, PRICE_TYPE_TRN);
     gnc_price_set_value (price, value);
     gnc_pricedb_add_price (pricedb, price);
     gnc_price_commit_edit (price);
@@ -2135,6 +2139,7 @@ gnc_split_register_auto_calc (SplitRegister *reg, Split *split)
     Account *account;
     int denom;
     int choice;
+    PriceSource source = PRICE_SOURCE_USER_PRICE;
 
     if (STOCK_REGISTER    != reg->type &&
         CURRENCY_REGISTER != reg->type &&
@@ -2283,6 +2288,7 @@ gnc_split_register_auto_calc (SplitRegister *reg, Split *split)
     {
         recalculate_price (split, reg, value, amount);
         price_changed = TRUE;
+        source = PRICE_SOURCE_SPLIT_REG;
     }
     if (recalc_value)
         recalculate_value (split, reg, price, amount, shares_changed);
@@ -2293,7 +2299,7 @@ gnc_split_register_auto_calc (SplitRegister *reg, Split *split)
                 PRIC_CELL);
         price = gnc_price_cell_get_value (cell);
 	if (gnc_numeric_positive_p(price))
-	    record_price (reg, account, price);
+	    record_price (reg, account, price, source);
     }
     return TRUE;
 }

commit d9a0f311a4adac7968ed0a09646e1d1216bb8e7d
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Sep 9 11:22:52 2015 -0700

    Fold separate call of gnc_pricedb_lookup_latest() into lookup_price.
    
    Requires a 3-state enum instead of a boolean for the second arg to lookup_price.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 2bb173f..b7931ad 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -216,6 +216,13 @@ round_price(gnc_commodity *from, gnc_commodity *to, gnc_numeric value)
     return value;
 }
 
+typedef enum
+{
+    SAME_DAY,
+    NEAREST,
+    LATEST
+} PriceDate;
+
 typedef struct
 {
     GNCPrice *price;
@@ -240,7 +247,7 @@ price_request_from_xferData(PriceReq *pr, XferDialog *xd)
 }
 
 static gboolean
-lookup_price(PriceReq *pr, gboolean day_only)
+lookup_price(PriceReq *pr, PriceDate pd)
 {
     GNCPrice *prc = NULL;
     g_return_val_if_fail (pr != NULL, FALSE);
@@ -249,26 +256,37 @@ lookup_price(PriceReq *pr, gboolean day_only)
     g_return_val_if_fail (pr->to != NULL, FALSE);
 
     pr->reverse = FALSE;
-    if (day_only)
-    {
-        prc = gnc_pricedb_lookup_day (pr->pricedb, pr->from, pr->to, pr->ts);
-    if (!prc)
-    {
-            prc = gnc_pricedb_lookup_day (pr->pricedb, pr->to,
-                                          pr->from, pr->ts);
-            pr->reverse = TRUE;
-    }
-    }
-    else
+    switch (pd)
     {
-        prc = gnc_pricedb_lookup_nearest_in_time (pr->pricedb, pr->from,
-                                                  pr->to, pr->ts);
-    if (!prc)
-    {
-            prc = gnc_pricedb_lookup_nearest_in_time (pr->pricedb, pr->to,
-                                                      pr->from, pr->ts);
-            pr->reverse = TRUE;
-    }
+        default:
+        case SAME_DAY:
+            prc = gnc_pricedb_lookup_day (pr->pricedb, pr->from,
+                                          pr->to, pr->ts);
+            if (!prc)
+            {
+                prc = gnc_pricedb_lookup_day (pr->pricedb, pr->to,
+                                              pr->from, pr->ts);
+                pr->reverse = TRUE;
+            }
+        break;
+        case NEAREST:
+            prc = gnc_pricedb_lookup_nearest_in_time (pr->pricedb, pr->from,
+                                                      pr->to, pr->ts);
+            if (!prc)
+            {
+                prc = gnc_pricedb_lookup_nearest_in_time (pr->pricedb, pr->to,
+                                                          pr->from, pr->ts);
+                pr->reverse = TRUE;
+            }
+        break;
+        case LATEST:
+            prc = gnc_pricedb_lookup_latest (pr->pricedb, pr->from, pr->to);
+            if (!prc)
+            {
+                prc = gnc_pricedb_lookup_latest (pr->pricedb, pr->to, pr->from);
+                pr->reverse = TRUE;
+            }
+            break;
     }
     if (pr->reverse)
     {
@@ -305,8 +323,8 @@ gnc_xfer_dialog_update_price (XferDialog *xferData)
     if (!xferData->pricedb) return;
 
     price_request_from_xferData(&pr, xferData);
-    if (!lookup_price(&pr, TRUE))
-        if (!lookup_price(&pr, FALSE))
+    if (!lookup_price(&pr, SAME_DAY))
+        if (!lookup_price(&pr, NEAREST))
         return;
 
     /* grab the price from the pricedb */
@@ -1605,7 +1623,7 @@ create_price(XferDialog *xferData, Timespec ts)
  * shifts to be < 1. */
 
     price_request_from_xferData(&pr, xferData);
-    if (lookup_price(&pr, TRUE))
+    if (lookup_price(&pr, SAME_DAY))
     {
         price_value = gnc_price_get_value(pr.price);
         if (gnc_numeric_equal(pr.reverse ? gnc_numeric_invert(value) : value,
@@ -1810,14 +1828,11 @@ gnc_xfer_dialog_close_cb(GtkDialog *dialog, gpointer data)
 void
 gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData)
 {
-    gnc_numeric rate;
     GNCPrice *prc;
-    gnc_commodity *from = xferData->from_commodity;
-    gnc_commodity *to = xferData->to_commodity;
+    PriceReq pr;
     SCM quotes_func;
     SCM book_scm;
     SCM scm_window;
-    gboolean have_price = FALSE;
 
     g_return_if_fail (xferData);
 
@@ -1852,29 +1867,15 @@ gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData)
     gnc_unset_busy_cursor (NULL);
 
     /*the results should be in the price db now, but don't crash if not. */
-
-    prc = gnc_pricedb_lookup_latest(xferData->pricedb, from, to);
-    if (prc)
-    {
-        rate = gnc_price_get_value (prc);
-        _gnc_xfer_dialog_set_price_edit(xferData, rate);
-        gnc_price_unref (prc);
-        have_price = TRUE;
-    }
-
-    /* Lets try reversing the commodities */
-    if(!have_price)
+    price_request_from_xferData(&pr, xferData);
+    if (lookup_price(&pr, LATEST))
     {
-        prc = gnc_pricedb_lookup_latest (xferData->pricedb, to, from);
-        if (prc)
-        {
-/* FIXME: We probably want to swap the result price's to and from, not invert the price. */
-            rate = gnc_numeric_invert(gnc_price_get_value (prc));
-            rate = round_price(from, to, rate);
-            _gnc_xfer_dialog_set_price_edit(xferData, rate);
-            gnc_price_unref (prc);
-            have_price = TRUE;
-        }
+        gnc_numeric price_value = gnc_price_get_value(pr.price);
+        if (pr.reverse)
+            price_value = round_price(pr.from, pr.to,
+                                      gnc_numeric_invert(price_value));
+         _gnc_xfer_dialog_set_price_edit(xferData, price_value);
+        gnc_price_unref (pr.price);
     }
 
     LEAVE("quote retrieved");

commit 7db7e0cf7ab5b18de02df64992902f5d73bab7a3
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Sep 9 11:02:41 2015 -0700

    Recognize and handle reversed price quotes from gnc-fq-helper.
    
    Gnc-fq-helper will flip currency price quotes if the one requested is < 1
    or not available, which might mean that it's not representable in 4 digits
    to the right of the decimal.

diff --git a/src/scm/price-quotes.scm b/src/scm/price-quotes.scm
index fc81139..e72fdae 100644
--- a/src/scm/price-quotes.scm
+++ b/src/scm/price-quotes.scm
@@ -375,7 +375,15 @@
            (saved-price #f)
            (commodity-str (gnc-commodity-get-printname commodity))
            )
-
+      (if (equal? (gnc-commodity-get-printname currency) commodity-str)
+          (let* ((symbol (assq-ref quote-data 'symbol))
+                 (other-curr
+                  (and commodity-table
+                       (string? symbol)
+                       (gnc-commodity-table-lookup commodity-table "ISO4217"
+                                                   (string-upcase symbol)))))
+            (set! commodity other-curr))
+        )
       (or-map (lambda (price-sym)
                 (let ((p (assq-ref quote-data price-sym)))
                   (if p

commit 7d8b51e8db76608bd6a1b6b8de4fc92a8804b092
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Sep 3 16:22:14 2015 -0700

    Use an enum for internal representation of Price Sources.
    
    Strings are still used for storage and display.
    Purpose is to make multiple comparisons and conditional setting more
    convenient.

diff --git a/src/backend/sql/gnc-price-sql.c b/src/backend/sql/gnc-price-sql.c
index 8729c91..92a5176 100644
--- a/src/backend/sql/gnc-price-sql.c
+++ b/src/backend/sql/gnc-price-sql.c
@@ -203,7 +203,7 @@ write_price( GNCPrice* p, gpointer data )
     g_return_val_if_fail( p != NULL, FALSE );
     g_return_val_if_fail( data != NULL, FALSE );
 
-    if ( s->is_ok && strcmp(gnc_price_get_source(p), PRICE_SOURCE_INVOICE) != 0)
+    if ( s->is_ok && gnc_price_get_source(p) == PRICE_SOURCE_INVOICE)
     {
         s->is_ok = save_price( s->be, QOF_INSTANCE(p) );
     }
diff --git a/src/backend/xml/gnc-pricedb-xml-v2.c b/src/backend/xml/gnc-pricedb-xml-v2.c
index fad3ff4..710fa01 100644
--- a/src/backend/xml/gnc-pricedb-xml-v2.c
+++ b/src/backend/xml/gnc-pricedb-xml-v2.c
@@ -120,7 +120,7 @@ price_parse_xml_sub_node(GNCPrice *p, xmlNodePtr sub_node, QofBook *book)
     {
         char *text = dom_tree_to_text(sub_node);
         if (!text) return FALSE;
-        gnc_price_set_source(p, text);
+        gnc_price_set_source_string(p, text);
         g_free(text);
     }
     else if (g_strcmp0("price:type", (char*)sub_node->name) == 0)
@@ -440,7 +440,7 @@ gnc_price_to_dom_tree(const xmlChar *tag, GNCPrice *price)
     tmpnode = timespec_to_dom_tree("price:time", &timesp);
     if (!add_child_or_kill_parent(price_xml, tmpnode)) return NULL;
 
-    sourcestr = gnc_price_get_source(price);
+    sourcestr = gnc_price_get_source_string(price);
     if (sourcestr && (strlen(sourcestr) != 0))
     {
         tmpnode = text_to_dom_tree("price:source", sourcestr);
diff --git a/src/backend/xml/io-gncxml-v1.c b/src/backend/xml/io-gncxml-v1.c
index 099ccd6..2dff2d0 100644
--- a/src/backend/xml/io-gncxml-v1.c
+++ b/src/backend/xml/io-gncxml-v1.c
@@ -3112,7 +3112,7 @@ price_parse_xml_sub_node(GNCPrice *p, xmlNodePtr sub_node, QofBook *book)
     {
         char *text = dom_tree_to_text(sub_node);
         if (!text) return FALSE;
-        gnc_price_set_source(p, text);
+        gnc_price_set_source_string(p, text);
         g_free(text);
     }
     else if (g_strcmp0("price:type", (char*)sub_node->name) == 0)
diff --git a/src/engine/gnc-pricedb-p.h b/src/engine/gnc-pricedb-p.h
index d93747b..8d867da 100644
--- a/src/engine/gnc-pricedb-p.h
+++ b/src/engine/gnc-pricedb-p.h
@@ -39,7 +39,7 @@ struct gnc_price_s
     gnc_commodity *commodity;
     gnc_commodity *currency;
     Timespec tmspec;
-    char *source;
+    PriceSource source;
     char *type;
     gnc_numeric value;
 
diff --git a/src/engine/gnc-pricedb.c b/src/engine/gnc-pricedb.c
index 81febf1..8cb841b 100644
--- a/src/engine/gnc-pricedb.c
+++ b/src/engine/gnc-pricedb.c
@@ -58,9 +58,28 @@ gnc_price_init(GNCPrice* price)
     price->refcount = 1;
     price->value = gnc_numeric_zero();
     price->type = NULL;
-    price->source = NULL;
+    price->source = PRICE_SOURCE_INVALID;
 }
 
+/* Array of char constants for converting price-source enums. Be sure to keep in
+ * sync with the enum values in gnc-pricedb.h The string user:price-editor is
+ * explicitly used by price_to_gui() in dialog-price-editor.c and the string
+ * Finance::Quote is explicitly used by fq-results->commod-tz-quote-triples in
+ * price-quotes.scm. Take care to keep them in sync if you make changes. Beware
+ * that the strings are used to store the enum values in the backends so any
+ * changes will affect backward data compatibility.
+ */
+static const char* source_names[] =
+{
+    "user:price-editor", //sync with price_to_gui in dialog-price-editor.c
+    "Finance::Quote",    //sync with
+    "user:xfer-dialog",
+    "user:split-register",
+    "user:stock-split",
+    "user:invoice-post",
+    "invalid"
+};
+
 static void
 gnc_price_dispose(GObject *pricep)
 {
@@ -90,7 +109,7 @@ gnc_price_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec
     switch (prop_id)
     {
     case PROP_SOURCE:
-        g_value_set_string(value, price->source);
+        g_value_set_string(value, gnc_price_get_source_string(price));
         break;
     case PROP_TYPE:
         g_value_set_string(value, price->type);
@@ -126,7 +145,7 @@ gnc_price_set_property(GObject* object, guint prop_id, const GValue* value, GPar
     switch (prop_id)
     {
     case PROP_SOURCE:
-        gnc_price_set_source(price, g_value_get_string(value));
+        gnc_price_set_source_string(price, g_value_get_string(value));
         break;
     case PROP_TYPE:
         gnc_price_set_typestr(price, g_value_get_string(value));
@@ -188,10 +207,10 @@ gnc_price_class_init(GNCPriceClass *klass)
      PROP_SOURCE,
      g_param_spec_string ("source",
                           "Price source",
-                          "The price source is a string describing the "
-                          "source of a price quote.  It will be something "
-                          "like this: 'Finance::Quote', 'user:misc', "
-                          "'user:foo', etc.",
+                          "The price source is PriceSource enum describing how"
+                          " the price was created. This property works on the"
+                          " string values in source_names for SQL database"
+                          " compatibility.",
                           NULL,
                           G_PARAM_READWRITE));
 
@@ -252,7 +271,6 @@ gnc_price_destroy (GNCPrice *p)
     qof_event_gen (&p->inst, QOF_EVENT_DESTROY, NULL);
 
     if (p->type) CACHE_REMOVE(p->type);
-    if (p->source) CACHE_REMOVE(p->source);
 
     /* qof_instance_release (&p->inst); */
     g_object_unref(p);
@@ -439,23 +457,30 @@ gnc_price_set_time(GNCPrice *p, Timespec t)
 }
 
 void
-gnc_price_set_source(GNCPrice *p, const char *s)
+gnc_price_set_source(GNCPrice *p, PriceSource s)
 {
     if (!p) return;
-    if (g_strcmp0(p->source, s) != 0)
-    {
-        char *tmp;
-
-        gnc_price_begin_edit (p);
-        tmp = CACHE_INSERT((gpointer) s);
-        if (p->source) CACHE_REMOVE(p->source);
-        p->source = tmp;
-        gnc_price_set_dirty(p);
-        gnc_price_commit_edit (p);
-    }
+    gnc_price_begin_edit (p);
+    p->source = s;
+    gnc_price_set_dirty(p);
+    gnc_price_commit_edit(p);
 }
 
 void
+gnc_price_set_source_string(GNCPrice *p, const char* str)
+{
+    if (!p) return;
+    for (PriceSource s = PRICE_SOURCE_EDIT_DLG;
+         s < PRICE_SOURCE_INVALID; ++s)
+        if (strcmp(source_names[s], str) == 0)
+        {
+            gnc_price_set_source(p, s);
+            return;
+        }
+
+
+}
+void
 gnc_price_set_typestr(GNCPrice *p, const char* type)
 {
     if (!p) return;
@@ -518,13 +543,20 @@ gnc_price_get_time(const GNCPrice *p)
     return p->tmspec;
 }
 
-const char *
+PriceSource
 gnc_price_get_source(const GNCPrice *p)
 {
-    if (!p) return NULL;
+    if (!p) return PRICE_SOURCE_INVALID;
     return p->source;
 }
 
+const char*
+gnc_price_get_source_string(const GNCPrice *p)
+{
+    if (!p) return NULL;
+    return source_names[p->source];
+}
+
 const char *
 gnc_price_get_typestr(const GNCPrice *p)
 {
@@ -573,8 +605,7 @@ gnc_price_equal (const GNCPrice *p1, const GNCPrice *p2)
     if (!timespec_equal (&ts1, &ts2))
         return FALSE;
 
-    if (g_strcmp0 (gnc_price_get_source (p1),
-                   gnc_price_get_source (p2)) != 0)
+    if (gnc_price_get_source (p1) != gnc_price_get_source (p2))
         return FALSE;
 
     if (g_strcmp0 (gnc_price_get_typestr (p1),
@@ -973,11 +1004,11 @@ insert_or_replace_price(GNCPriceDB *db, GNCPrice *p)
                                                   p->currency, p->tmspec);
     if (old_price == NULL)
         return TRUE;
-    if (strcmp(p->source, "PRICE_SOURCE_FQ"))
+    if (p->source != PRICE_SOURCE_FQ)
         return TRUE;
     return FALSE;
-}
 
+}
 /* ==================================================================== */
 /* The add_price() function is a utility that only manages the
  * dual hash table instertion */
@@ -1210,7 +1241,7 @@ static gboolean
 check_one_price_date (GNCPrice *price, gpointer user_data)
 {
     remove_info *data = user_data;
-    const gchar *source;
+    PriceSource source;
     Timespec pt;
 
     ENTER("price %p (%s), data %p", price,
@@ -1219,7 +1250,7 @@ check_one_price_date (GNCPrice *price, gpointer user_data)
     if (!data->delete_user)
     {
         source = gnc_price_get_source (price);
-        if (g_strcmp0(source, "Finance::Quote") != 0)
+        if (source != PRICE_SOURCE_FQ)
         {
             LEAVE("Not an automatic quote");
             return TRUE;
@@ -2472,8 +2503,8 @@ gnc_price_print(GNCPrice *p, FILE *f, int indent)
     str = str ? str : "(null)";
     fprintf(f, "%s    <cmdty:ref-id>%s</cmdty:ref-id>\n", istr, str);
     fprintf(f, "%s  </pdb:currency>\n", istr);
-    str = gnc_price_get_source(p);
-    str = str ? str : "(null)";
+    str = source_names[gnc_price_get_source(p)];
+    str = str ? str : "invalid";
     fprintf(f, "%s  %s\n", istr, str);
     str = gnc_price_get_typestr(p);
     str = str ? str : "(null)";
diff --git a/src/engine/gnc-pricedb.h b/src/engine/gnc-pricedb.h
index ae65748..00a4126 100644
--- a/src/engine/gnc-pricedb.h
+++ b/src/engine/gnc-pricedb.h
@@ -156,6 +156,25 @@ GType gnc_pricedb_get_type(void);
 typedef struct gnc_price_lookup_s GNCPriceLookup;
 typedef GList PriceList;
 
+/** Price source enum. Be sure to keep in sync with the source_name array in
+ * gnc-pricedb.c. These are in preference order, so for example a quote with
+ * PRICE_SOURCE_EDIT_DLG will overwrite one with PRICE_SOURCE_FQ but not the
+ * other way around.
+ */
+typedef enum
+{
+    PRICE_SOURCE_EDIT_DLG,         // "user:price-editor"
+    PRICE_SOURCE_FQ,               // "Finance::Quote"
+    PRICE_SOURCE_XFER_DLG,         // "user:xfer-dialog"
+    PRICE_SOURCE_SPLIT_REG,        // "user:split-register"
+    PRICE_SOURCE_STOCK_SPLIT,      // "user:stock-split"
+    PRICE_SOURCE_INVOICE,          // "user:invoice-post"
+    PRICE_SOURCE_INVALID,
+} PriceSource;
+
+#define PRICE_TYPE_LAST "last"
+#define PRICE_TYPE_UNK "unknown"
+
 /* ------------------ */
 /** @name Constructors
     @{ */
@@ -202,33 +221,26 @@ void gnc_price_commit_edit (GNCPrice *p);
 void gnc_price_set_commodity(GNCPrice *p, gnc_commodity *c);
 void gnc_price_set_currency(GNCPrice *p, gnc_commodity *c);
 void gnc_price_set_time(GNCPrice *p, Timespec t);
-void gnc_price_set_source(GNCPrice *p, const char *source);
+void gnc_price_set_source(GNCPrice *p, PriceSource source);
+void gnc_price_set_source_string(GNCPrice *p, const char* s);
 void gnc_price_set_typestr(GNCPrice *p, const char* type);
 void gnc_price_set_value(GNCPrice *p, gnc_numeric value);
 /** @} */
 
-#define PRICE_SOURCE_FQ  "Finance::Quote"
-#define PRICE_SOURCE_INVOICE "user:invoice-post"
-#define PRICE_SOURCE_STOCK_SPLIT "user:stock-split"
-#define PRICE_SOURCE_XFER_DLG "user:xfer-dialog"
-#define PRICE_SOURCE_SPLIT_REG "user:split-register"
-#define PRICE_SOURCE_EDIT_DLG "user:price-editor"
-#define PRICE_TYPE_LAST "last"
-#define PRICE_TYPE_UNK "unknown"
-
 /* ------------------ */
 /** @name  Getters
     All of the getters return data that's internal
     to the GNCPrice, not copies, so don't free these values.
     @{ */
 
-GNCPrice *      gnc_price_lookup (const GncGUID *guid, QofBook *book);
+    GNCPrice *      gnc_price_lookup (const GncGUID *guid, QofBook *book);
 /*@ dependent @*/
 gnc_commodity * gnc_price_get_commodity(const GNCPrice *p);
 /*@ dependent @*/
 gnc_commodity * gnc_price_get_currency(const GNCPrice *p);
 Timespec        gnc_price_get_time(const GNCPrice *p);
-const char *    gnc_price_get_source(const GNCPrice *p);
+PriceSource     gnc_price_get_source(const GNCPrice *p);
+const char *    gnc_price_get_source_string(const GNCPrice *p);
 const char *    gnc_price_get_typestr(const GNCPrice *p);
 gnc_numeric     gnc_price_get_value(const GNCPrice *p);
 gboolean        gnc_price_equal(const GNCPrice *p1, const GNCPrice *p2);
diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index a9d9087..789a10b 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -656,6 +656,7 @@ void
 make_random_changes_to_price (QofBook *book, GNCPrice *p)
 {
     Timespec *ts;
+    PriceSource ps;
     char *string;
     gnc_commodity *c;
 
@@ -673,9 +674,9 @@ make_random_changes_to_price (QofBook *book, GNCPrice *p)
     gnc_price_set_time (p, *ts);
     g_free (ts);
 
-    string = get_random_string ();
-    gnc_price_set_source (p, string);
-    g_free (string);
+    ps = (PriceSource)get_random_int_in_range((int)PRICE_SOURCE_EDIT_DLG,
+                                              (int)PRICE_SOURCE_INVALID);
+    gnc_price_set_source (p, ps);
 
     string = get_random_string ();
     gnc_price_set_typestr (p, string);
diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 502e4ac..2bb173f 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1617,7 +1617,7 @@ create_price(XferDialog *xferData, Timespec ts)
             gnc_price_unref (pr.price);
             return;
         }
-        if (strcmp (gnc_price_get_source(pr.price), PRICE_SOURCE_FQ) == 0)
+        if (gnc_price_get_source(pr.price) == PRICE_SOURCE_FQ)
         {
             PINFO("Existing price is from Finance::Quote, so won't supersede.");
             gnc_price_unref (pr.price);
diff --git a/src/gnome-utils/gnc-tree-model-price.c b/src/gnome-utils/gnc-tree-model-price.c
index c62b749..20a4409 100644
--- a/src/gnome-utils/gnc-tree-model-price.c
+++ b/src/gnome-utils/gnc-tree-model-price.c
@@ -786,7 +786,7 @@ gnc_tree_model_price_get_value (GtkTreeModel *tree_model,
         break;
     case GNC_TREE_MODEL_PRICE_COL_SOURCE:
         g_value_init (value, G_TYPE_STRING);
-        g_value_set_string (value, gettext (gnc_price_get_source (price)));
+        g_value_set_string (value, gettext (gnc_price_get_source_string (price)));
         break;
     case GNC_TREE_MODEL_PRICE_COL_TYPE:
         g_value_init (value, G_TYPE_STRING);
diff --git a/src/gnome-utils/gnc-tree-view-price.c b/src/gnome-utils/gnc-tree-view-price.c
index 7f3113d..b0dc599 100644
--- a/src/gnome-utils/gnc-tree-view-price.c
+++ b/src/gnome-utils/gnc-tree-view-price.c
@@ -300,8 +300,7 @@ sort_by_source (GtkTreeModel *f_model,
         return sort_ns_or_cm (f_model, f_iter_a, f_iter_b);
 
     /* sort by source first */
-    result = safe_utf8_collate (gnc_price_get_source (price_a),
-                                gnc_price_get_source (price_b));
+    result = gnc_price_get_source (price_a) < gnc_price_get_source (price_b);
     if (result != 0)
         return result;
 
diff --git a/src/gnome/dialog-price-editor.c b/src/gnome/dialog-price-editor.c
index c7c5b9e..d395903 100644
--- a/src/gnome/dialog-price-editor.c
+++ b/src/gnome/dialog-price-editor.c
@@ -161,7 +161,7 @@ price_to_gui (PriceEditDialog *pedit_dialog)
 
         currency = gnc_price_get_currency (pedit_dialog->price);
         date = gnc_price_get_time (pedit_dialog->price);
-        source = gnc_price_get_source (pedit_dialog->price);
+        source = gnc_price_get_source_string (pedit_dialog->price);
         type = gnc_price_get_typestr (pedit_dialog->price);
         value = gnc_price_get_value (pedit_dialog->price);
     }
@@ -170,7 +170,7 @@ price_to_gui (PriceEditDialog *pedit_dialog)
         currency = gnc_default_currency ();
         date.tv_sec = gnc_time (NULL);
         date.tv_nsec = 0;
-        source = PRICE_SOURCE_EDIT_DLG;
+        source = "user:price-editor"; //Sync with source_names in gnc-pricedb.c
         type = "";
         value = gnc_numeric_zero ();
     }
@@ -237,7 +237,7 @@ gui_to_price (PriceEditDialog *pedit_dialog)
     gnc_price_set_commodity (pedit_dialog->price, commodity);
     gnc_price_set_currency (pedit_dialog->price, currency);
     gnc_price_set_time (pedit_dialog->price, date);
-    gnc_price_set_source (pedit_dialog->price, source);
+    gnc_price_set_source_string (pedit_dialog->price, source);
     gnc_price_set_typestr (pedit_dialog->price, type);
     gnc_price_set_value (pedit_dialog->price, value);
     gnc_price_commit_edit (pedit_dialog->price);
diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c
index 1b5dd47..1332bf1 100644
--- a/src/register/ledger-core/split-register.c
+++ b/src/register/ledger-core/split-register.c
@@ -2084,7 +2084,7 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
             gnc_price_unref (price);
             return;
         }
-        if (strcmp (gnc_price_get_source(price), PRICE_SOURCE_FQ) == 0)
+        if (gnc_price_get_source(price) == PRICE_SOURCE_FQ)
         {
             gnc_price_unref(price);
             return;
diff --git a/src/scm/price-quotes.scm b/src/scm/price-quotes.scm
index ecea984..fc81139 100644
--- a/src/scm/price-quotes.scm
+++ b/src/scm/price-quotes.scm
@@ -421,7 +421,7 @@
               (begin
                 (gnc-price-begin-edit saved-price)
                 (gnc-price-set-time saved-price gnc-time)
-                (gnc-price-set-source saved-price "Finance::Quote")
+                (gnc-price-set-source-string saved-price "Finance::Quote")
                 (gnc-price-set-typestr saved-price price-type)
                 (gnc-price-set-value saved-price price)
                 (gnc-price-commit-edit saved-price)
@@ -435,7 +435,7 @@
                       (gnc-price-set-commodity gnc-price commodity)
                       (gnc-price-set-currency gnc-price currency)
                       (gnc-price-set-time gnc-price gnc-time)
-                      (gnc-price-set-source gnc-price "Finance::Quote")
+                      (gnc-price-set-source-string gnc-price "Finance::Quote")
                       (gnc-price-set-typestr gnc-price price-type)
                       (gnc-price-set-value gnc-price price)
                       (gnc-price-commit-edit gnc-price)

commit d52a0b602c0af20faa40f344f2c5de1e99c1eaff
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Sep 3 16:16:33 2015 -0700

    Fix whitespace error.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 715245e..502e4ac 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1460,7 +1460,8 @@ check_accounts  (XferDialog* xferData, Account* from_account,
 
 static gboolean
 check_edit(XferDialog *xferData)
-{        if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->price_edit)))
+{
+    if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->price_edit)))
     {
         if (gtk_toggle_button_get_active
             (GTK_TOGGLE_BUTTON(xferData->price_radio)))

commit d4968d3bb40129c4e26a5f7b3b6de001b60dfc7b
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Sep 3 11:22:51 2015 -0700

    Extract function lookup_price in dialog_transfer.c

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index f0c2ff9..715245e 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -216,73 +216,107 @@ round_price(gnc_commodity *from, gnc_commodity *to, gnc_numeric value)
     return value;
 }
 
-/* (maybe) update the price from the pricedb. */
-static void
-gnc_xfer_dialog_update_price (XferDialog *xferData)
+typedef struct
 {
-    GNCPrice *prc;
-    gnc_numeric price_value;
-    Timespec date;
-    gnc_commodity *from = xferData->from_commodity;
-    gnc_commodity *to = xferData->to_commodity;
+    GNCPrice *price;
+    GNCPriceDB *pricedb;
+    gnc_commodity *from;
+    gnc_commodity *to;
+    Timespec ts;
     gboolean reverse;
+} PriceReq;
 
-    if (!xferData) return;
-    if (!xferData->from_commodity || ! xferData->to_commodity) return;
-    if (gnc_commodity_equal (xferData->from_commodity, xferData->to_commodity))
-        return;
-    if (!xferData->pricedb) return;
-
-    /* when do we update, and when do we NOT update? */
-
-    /* XXX: I'm ALWAYS going to update whenever we get called */
-
-    /* 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));
+static void
+price_request_from_xferData(PriceReq *pr, XferDialog *xd)
+{
+    g_return_if_fail (pr != NULL);
+    g_return_if_fail (xd != NULL);
+    pr->price = NULL;
+    pr->pricedb = xd->pricedb;
+    pr->from = xd->from_commodity;
+    pr->to = xd->to_commodity;
+    pr->ts = gnc_date_edit_get_date_ts (GNC_DATE_EDIT (xd->date_entry));
+    pr->reverse = FALSE;
+}
 
-    /* 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;
+static gboolean
+lookup_price(PriceReq *pr, gboolean day_only)
+{
+    GNCPrice *prc = NULL;
+    g_return_val_if_fail (pr != NULL, FALSE);
+    g_return_val_if_fail (pr->pricedb != NULL, FALSE);
+    g_return_val_if_fail (pr->from != NULL, FALSE);
+    g_return_val_if_fail (pr->to != NULL, FALSE);
 
+    pr->reverse = FALSE;
+    if (day_only)
+    {
+        prc = gnc_pricedb_lookup_day (pr->pricedb, pr->from, pr->to, pr->ts);
     if (!prc)
     {
-        /* Look for reverse price on same day */
-        prc = gnc_pricedb_lookup_day (xferData->pricedb, to, from, date);
-        reverse = TRUE;
+            prc = gnc_pricedb_lookup_day (pr->pricedb, pr->to,
+                                          pr->from, pr->ts);
+            pr->reverse = TRUE;
     }
-
+    }
+    else
+    {
+        prc = gnc_pricedb_lookup_nearest_in_time (pr->pricedb, pr->from,
+                                                  pr->to, pr->ts);
     if (!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;
+            prc = gnc_pricedb_lookup_nearest_in_time (pr->pricedb, pr->to,
+                                                      pr->from, pr->ts);
+            pr->reverse = TRUE;
     }
+    }
+    if (pr->reverse)
+    {
+        PINFO("Found reverse price: 1 %s = %f %s",
+              gnc_commodity_get_mnemonic(pr->to),
+              gnc_numeric_to_double(gnc_price_get_value(prc)),
+              gnc_commodity_get_mnemonic(pr->from));
 
-    if (!prc)
+    }
+    else
     {
-        prc = gnc_pricedb_lookup_nearest_in_time (xferData->pricedb, to,
-                                                  from, date);
-        reverse = TRUE;
+        PINFO("Found price: 1 %s = %f %s",
+              gnc_commodity_get_mnemonic(pr->from),
+              gnc_numeric_to_double(gnc_price_get_value(prc)),
+              gnc_commodity_get_mnemonic(pr->to));
     }
-
     if (!prc)
+        return FALSE;
+    pr->price = prc;
+    return TRUE;
+}
+
+/* (maybe) update the price from the pricedb. */
+static void
+gnc_xfer_dialog_update_price (XferDialog *xferData)
+{
+    PriceReq pr;
+    gnc_numeric price_value;
+
+    if (!xferData) return;
+    if (!xferData->from_commodity || ! xferData->to_commodity) return;
+    if (gnc_commodity_equal (xferData->from_commodity, xferData->to_commodity))
+        return;
+    if (!xferData->pricedb) return;
+
+    price_request_from_xferData(&pr, xferData);
+    if (!lookup_price(&pr, TRUE))
+        if (!lookup_price(&pr, FALSE))
         return;
 
     /* grab the price from the pricedb */
-    price_value = gnc_price_get_value (prc);
-    if (reverse)
+    price_value = gnc_price_get_value (pr.price);
+    if (pr.reverse)
     {
-        PINFO("Found reverse price: 1 %s = %f %s", gnc_commodity_get_mnemonic(to),
-              gnc_numeric_to_double(price_value), gnc_commodity_get_mnemonic(from));
         price_value = gnc_numeric_invert (price_value);
-        price_value = round_price(from, to, price_value);
-    }
-    else
-    {
-        PINFO("Found price: 1 %s = %f %s", gnc_commodity_get_mnemonic(from),
-              gnc_numeric_to_double(price_value), gnc_commodity_get_mnemonic(to));
+        price_value = round_price(pr.from, pr.to, price_value);
     }
+    gnc_price_unref(pr.price);
 
     /* and set the price entry */
     _gnc_xfer_dialog_set_price_edit(xferData, price_value);
@@ -1542,9 +1576,10 @@ swap_commodities(gnc_commodity **from, gnc_commodity **to, gnc_numeric value)
 static void
 create_price(XferDialog *xferData, Timespec ts)
 {
+    PriceReq pr;
+    GNCPrice *price = NULL;
     gnc_commodity *from = xferData->from_commodity;
     gnc_commodity *to = xferData->to_commodity;
-    GNCPrice *price;
     gnc_numeric price_value;
     gnc_numeric value;
     gnc_numeric from_amt, to_amt;
@@ -1561,52 +1596,49 @@ create_price(XferDialog *xferData, Timespec ts)
          (strcmp (gnc_commodity_get_mnemonic(from),
                   gnc_commodity_get_mnemonic(to)) < 0)))
         swap_amount (&from, &to, &value, &from_amt, &to_amt);
-    /* 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)
-    {
-        price = gnc_pricedb_lookup_day (xferData->pricedb, to, from, ts);
-        if (price)
-            swap = TRUE;
-    }
+
 /* Normally we want to store currency rates such that the rate > 1 and commodity
  * prices in terms of a currency regardless of value. However, if we already
  * have a price in either direction we want to continue using that direction for
  * the rest of the day so that we don't wind up with two prices if the rate
  * shifts to be < 1. */
 
-    if (price)
+    price_request_from_xferData(&pr, xferData);
+    if (lookup_price(&pr, TRUE))
     {
-        price_value = gnc_price_get_value(price);
-        if (gnc_numeric_equal(swap ? gnc_numeric_invert(value) : value,
+        price_value = gnc_price_get_value(pr.price);
+        if (gnc_numeric_equal(pr.reverse ? gnc_numeric_invert(value) : value,
                               price_value))
         {
-            PINFO("Found price for %s in %s", gnc_commodity_get_mnemonic(from),
-                  gnc_commodity_get_mnemonic(to));
-            gnc_price_unref (price);
+            PINFO("Found price for %s in %s",
+                  gnc_commodity_get_mnemonic(pr.from),
+                  gnc_commodity_get_mnemonic(pr.to));
+            gnc_price_unref (pr.price);
             return;
         }
-        if (strcmp (gnc_price_get_source(price), PRICE_SOURCE_FQ) == 0)
+        if (strcmp (gnc_price_get_source(pr.price), PRICE_SOURCE_FQ) == 0)
         {
             PINFO("Existing price is from Finance::Quote, so won't supersede.");
-            gnc_price_unref (price);
+            gnc_price_unref (pr.price);
             return;
         }
-        if (swap)
+        if (pr.reverse)
         {
             value = swap_commodities(&from, &to, value);
             xferData->from_commodity = from;
             xferData->to_commodity = to;
         }
-        value = round_price(from, to, value);
-        gnc_price_begin_edit (price);
-        gnc_price_set_time (price, ts);
-        gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
-        gnc_price_set_value (price, value);
-        gnc_price_commit_edit (price);
-        PINFO("Modified price: 1 %s = %f %s", gnc_commodity_get_mnemonic(from),
-              gnc_numeric_to_double(value), gnc_commodity_get_mnemonic(to));
-        gnc_price_unref (price);
+        value = round_price(pr.from, pr.to, value);
+        gnc_price_begin_edit (pr.price);
+        gnc_price_set_time (pr.price, ts);
+        gnc_price_set_source (pr.price, PRICE_SOURCE_XFER_DLG);
+        gnc_price_set_value (pr.price, value);
+        gnc_price_commit_edit (pr.price);
+        PINFO("Modified price: 1 %s = %f %s",
+              gnc_commodity_get_mnemonic(from),
+              gnc_numeric_to_double(value),
+              gnc_commodity_get_mnemonic(to));
+        gnc_price_unref (pr.price);
         return;
     }
     if (gnc_commodity_is_currency(from) && gnc_commodity_is_currency(to))

commit 157c7e30a53abe2e8f74ea61e02c497a306bf6ac
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 1 14:56:19 2015 -0700

    Invert the F::Q price if there's already one in the other direction.
    
    We don't want to create prices in both directions on the same day.

diff --git a/src/scm/price-quotes.scm b/src/scm/price-quotes.scm
index c6a2405..ecea984 100644
--- a/src/scm/price-quotes.scm
+++ b/src/scm/price-quotes.scm
@@ -1,17 +1,17 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; price-quotes.scm - manage sub-processes.
 ;;; Copyright 2001 Rob Browning <rlb at cs.utexas.edu>
-;;; 
-;;; This program is free software; you can redistribute it and/or    
-;;; modify it under the terms of the GNU General Public License as   
-;;; published by the Free Software Foundation; either version 2 of   
-;;; the License, or (at your option) any later version.              
-;;;                                                                  
-;;; This program is distributed in the hope that it will be useful,  
-;;; but WITHOUT ANY WARRANTY; without even the implied warranty of   
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    
-;;; GNU General Public License for more details.                     
-;;;                                                                  
+;;;
+;;; This program is free software; you can redistribute it and/or
+;;; modify it under the terms of the GNU General Public License as
+;;; published by the Free Software Foundation; either version 2 of
+;;; the License, or (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
 ;;; You should have received a copy of the GNU General Public License
 ;;; along with this program; if not, contact:
 ;;;
@@ -35,7 +35,7 @@
 
 (define (item-list->hash! lst hash
 			  getkey getval
-			  hashref hashset 
+			  hashref hashset
 			  list-duplicates?)
   ;; Takes a list of the form (item item item item) and returns a hash
   ;; formed by traversing the list, and getting the key and val from
@@ -58,7 +58,7 @@
 	  (if existing-val
 	      (hashset hash key (cons val existing-val))
 	      (hashset hash key (list val))))))
-  
+
   (for-each handle-item lst)
   hash)
 
@@ -205,7 +205,7 @@
     ;; a list of the corresponding commodities.  Also perform a bit of
     ;; optimization, merging calls for symbols to the same
     ;; Finance::Quote method.
-    ;; 
+    ;;
     ;; Returns a list of the info needed for a set of calls to
     ;; gnc-fq-helper.  Each item will of the list will be of the
     ;; form:
@@ -223,7 +223,7 @@
 	   (commodity-list #f)
 	   (currency-list (filter
 			   (lambda (a) (not (gnc-commodity-equiv (cadr a) (caddr a))))
-			   (call-with-values 
+			   (call-with-values
                                (lambda () (partition!
                                            (lambda (cmd)
                                              (not (string=? (car cmd) "currency")))
@@ -257,7 +257,7 @@
     ;;
     ;; ("yahoo" (commodity-1 currency-1 tz-1)
     ;;          (commodity-2 currency-2 tz-2) ...)
-    ;; 
+    ;;
     ;; ("yahoo" "IBM" "AMD" ...)
     ;;
 
@@ -411,6 +411,12 @@
             (set! saved-price (gnc-pricedb-lookup-day pricedb
                                                       commodity currency
                                                       gnc-time))
+            (if (null? saved-price)
+                (begin
+                  (set! saved-price (gnc-pricedb-lookup-day pricedb currency
+                                                            commodity gnc-time))
+                  (if (not (null? saved-price))
+                      (set! price (gnc-numeric-invert(price))))))
             (if (not (null? saved-price))
               (begin
                 (gnc-price-begin-edit saved-price)

commit 890cfe2186a452969cd2eeadaf065c04ef054d68
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 1 14:47:40 2015 -0700

    Handle currencies with one-directional quotes and quotes < 1 in F::Q.
    
    Some currencies quotes are one-directional, so check both directions if
    necessary. Quotes with values < 1 often have too few significant digits,
    so in that case use the other direction if available.

diff --git a/src/quotes/gnc-fq-dump b/src/quotes/gnc-fq-dump
index 2b1ab1e..771e2ae 100755
--- a/src/quotes/gnc-fq-dump
+++ b/src/quotes/gnc-fq-dump
@@ -166,6 +166,15 @@ if ($exchange eq "currency") {
   while ($#ARGV >= 0) {
     my $to = shift;
     my $result = $q->currency($from, $to);
+    unless (defined($result) && $result >= 1) {
+        my $inv_res = $q->currency($to, $from);
+        if (defined($inv_res)) {
+            my $tmp = $to;
+            $to = $from;
+            $from = $tmp;
+            $result = $inv_res;
+        }
+    }
     if (defined($result)) {
       printf "1 $from = $result $to\n";
     } else {
diff --git a/src/quotes/gnc-fq-helper.in b/src/quotes/gnc-fq-helper.in
index edb6220..6af1dee 100755
--- a/src/quotes/gnc-fq-helper.in
+++ b/src/quotes/gnc-fq-helper.in
@@ -350,6 +350,19 @@ while(<>) {
     last unless $to_currency;
 
     my $price = $quoter->currency($from_currency, $to_currency);
+    my $inv_price = undef;
+    #Sometimes price quotes are available in only one direction, and if the
+    #direction we asked for results in a quote < 1 we want the other direction
+    #if it's available to get more significant digits.
+    unless (defined($price) && $price > 1) {
+        $inv_price = $quoter->currency($to_currency, $from_currency);
+        if (defined($inv_price)) {
+            my $tmp = $to_currency;
+            $to_currency = $from_currency;
+            $from_currency = $tmp;
+            $price = $inv_price;
+        }
+    }
 
     $quote_data{$from_currency, "success"} = defined($price);
     $quote_data{$from_currency, "symbol"} = $from_currency;

commit 96471379f0d0f1fd8b5e6050a5f8e7d26fd7964c
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 1 12:44:25 2015 -0700

    Adjust split_register to match transfer dialog checking inverted prices.

diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c
index 3cf90cc..1b5dd47 100644
--- a/src/register/ledger-core/split-register.c
+++ b/src/register/ledger-core/split-register.c
@@ -2056,6 +2056,7 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
     int scu = gnc_commodity_get_fraction(curr);
     Timespec ts;
     BasicCell *cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
+    gboolean swap = FALSE;
 
     /* Only record the price for account types that don't have a
      * "rate" cell. They'll get handled later by
@@ -2065,24 +2066,20 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
         return;
     gnc_date_cell_get_date ((DateCell*)cell, &ts);
     price = gnc_pricedb_lookup_day (pricedb, comm, curr, ts);
-    if (price)
-    {
-        price_value = gnc_price_get_value(price);
-    }
-    else
+    if (!price)
     {
         price = gnc_pricedb_lookup_day (pricedb, curr, comm, ts);
         if (price)
-        {
 /* It might be better to raise an error here: We shouldn't be creating
  * currency->commodity prices.
  */
-            price_value = gnc_numeric_invert(gnc_price_get_value(price));
-        }
+            swap = TRUE;
     }
     if (price)
     {
-        if (gnc_numeric_equal(value, price_value))
+        price_value = gnc_price_get_value(price);
+        if (gnc_numeric_equal(swap ? gnc_numeric_invert(value) : value,
+                              price_value))
         {
             gnc_price_unref (price);
             return;
@@ -2092,16 +2089,13 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
             gnc_price_unref(price);
             return;
         }
-        if (!gnc_numeric_eq(price_value, gnc_price_get_value(price)))
+        if (swap)
         {
             value = gnc_numeric_invert(value);
             scu = gnc_commodity_get_fraction(comm);
-            value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
-                                        GNC_HOW_RND_ROUND_HALF_UP);
         }
-        else
-            value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
-                                        GNC_HOW_RND_ROUND_HALF_UP);
+        value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                    GNC_HOW_RND_ROUND_HALF_UP);
         gnc_price_begin_edit (price);
         gnc_price_set_time (price, ts);
         gnc_price_set_source (price, PRICE_SOURCE_SPLIT_REG);

commit d7fb92d03f9b043bb3f5259d4ff9d8a13bc4161e
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 1 12:39:12 2015 -0700

    Fix missing initialization of price_value.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index a7ecf9d..f0c2ff9 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1577,6 +1577,7 @@ create_price(XferDialog *xferData, Timespec ts)
 
     if (price)
     {
+        price_value = gnc_price_get_value(price);
         if (gnc_numeric_equal(swap ? gnc_numeric_invert(value) : value,
                               price_value))
         {

commit 93bb5c0fdd3c9ea1df7801228ea05bd0b989fd4c
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 1 12:17:12 2015 -0700

    Change CURRENCY_DENOM to 10000, matching what F::Q returns.

diff --git a/src/engine/gnc-pricedb.h b/src/engine/gnc-pricedb.h
index c7fe6d0..ae65748 100644
--- a/src/engine/gnc-pricedb.h
+++ b/src/engine/gnc-pricedb.h
@@ -250,7 +250,7 @@ void gnc_price_print(GNCPrice *db, FILE *f, int indent);
  * of the commodity with a fixed denominator of the pricing currency's
  * SCU * 10000.
  */
-#define CURRENCY_DENOM 1000
+#define CURRENCY_DENOM 10000
 #define COMMODITY_DENOM_MULT 10000
 
 /* ================================================================ */

commit ffe96b304412aa059c075b66812d3bcbf0712839
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 1 12:16:09 2015 -0700

    Extract function round_price(), consistently apply it.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index dd90e8b..a7ecf9d 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -190,6 +190,32 @@ gnc_xfer_dialog_compute_price_value (XferDialog *xferData)
     return(gnc_numeric_div(to_amt, from_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE));
 }
 
+/* Round a price value according to this policy:
+ * If both commodities are currencies, round to a fixed denominator.
+ * If only one is a currency, round to the currency's scu * a fixed factor.
+ * The fixed values are defined in gnc-pricedb.h
+ */
+static gnc_numeric
+round_price(gnc_commodity *from, gnc_commodity *to, gnc_numeric value)
+{
+    if (gnc_commodity_is_currency(from) && gnc_commodity_is_currency(to))
+        value = gnc_numeric_convert(value, CURRENCY_DENOM,
+                                    GNC_HOW_RND_ROUND_HALF_UP);
+    else if (gnc_commodity_is_currency(to))
+    {
+        int scu = gnc_commodity_get_fraction (to);
+        value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                    GNC_HOW_RND_ROUND_HALF_UP);
+    }
+    else if (gnc_commodity_is_currency(from))
+    {
+        int scu = gnc_commodity_get_fraction (from);
+        value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                    GNC_HOW_RND_ROUND_HALF_UP);
+    }
+    return value;
+}
+
 /* (maybe) update the price from the pricedb. */
 static void
 gnc_xfer_dialog_update_price (XferDialog *xferData)
@@ -249,7 +275,8 @@ gnc_xfer_dialog_update_price (XferDialog *xferData)
     {
         PINFO("Found reverse price: 1 %s = %f %s", gnc_commodity_get_mnemonic(to),
               gnc_numeric_to_double(price_value), gnc_commodity_get_mnemonic(from));
-        price_value = gnc_numeric_invert(price_value);
+        price_value = gnc_numeric_invert (price_value);
+        price_value = round_price(from, to, price_value);
     }
     else
     {
@@ -1001,17 +1028,11 @@ gnc_xfer_to_amount_update_cb(GtkWidget *widget, GdkEventFocus *event,
     XferDialog *xferData = data;
     gnc_numeric price_value;
     Account *account;
-    int scu;
 
-    account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_TO);
-    if (account == NULL)
-        account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_FROM);
-    scu = xaccAccountGetCommoditySCU(account);
     gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->to_amount_edit));
-
     price_value = gnc_xfer_dialog_compute_price_value(xferData);
-    price_value = gnc_numeric_convert (price_value, scu * COMMODITY_DENOM_MULT,
-                                       GNC_HOW_RND_ROUND_HALF_UP);
+    price_value = round_price(xferData->from_commodity, xferData->to_commodity,
+                              price_value);
     gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit),
                                price_value);
     gnc_xfer_dialog_update_conv_info(xferData);
@@ -1496,24 +1517,26 @@ static void
 swap_amount (gnc_commodity **from, gnc_commodity **to, gnc_numeric *value,
              gnc_numeric *from_amt, gnc_numeric *to_amt)
 {
-    gnc_commodity *tmp;
-    gnc_numeric *tmp_amt;
-    tmp = *from;
+    gnc_commodity *tmp = *from;
+    gnc_numeric *tmp_amt = from_amt;
     *from = *to;
     *to = tmp;
-    tmp_amt = from_amt;
     from_amt = to_amt;
     to_amt = tmp_amt;
     *value = gnc_numeric_invert (*value);
+    *value = round_price(*from, *to, *value);
 }
 
 static gnc_numeric
 swap_commodities(gnc_commodity **from, gnc_commodity **to, gnc_numeric value)
 {
     gnc_commodity *tmp = *to;
+
     *to = *from;
     *from = tmp;
-    return gnc_numeric_invert(value);
+    value = gnc_numeric_invert(value);
+    value = round_price(*from, *to, value);
+    return value;
 }
 
 static void
@@ -1546,6 +1569,11 @@ create_price(XferDialog *xferData, Timespec ts)
         if (price)
             swap = TRUE;
     }
+/* Normally we want to store currency rates such that the rate > 1 and commodity
+ * prices in terms of a currency regardless of value. However, if we already
+ * have a price in either direction we want to continue using that direction for
+ * the rest of the day so that we don't wind up with two prices if the rate
+ * shifts to be < 1. */
 
     if (price)
     {
@@ -1566,16 +1594,10 @@ create_price(XferDialog *xferData, Timespec ts)
         if (swap)
         {
             value = swap_commodities(&from, &to, value);
+            xferData->from_commodity = from;
+            xferData->to_commodity = to;
         }
-        if (gnc_commodity_is_currency(from) && gnc_commodity_is_currency(to))
-            value = gnc_numeric_convert(value, CURRENCY_DENOM,
-                                        GNC_HOW_RND_ROUND_HALF_UP);
-        else if (gnc_commodity_is_currency(to))
-        {
-            int scu = gnc_commodity_get_fraction (to);
-            value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
-                                        GNC_HOW_RND_ROUND_HALF_UP);
-        }
+        value = round_price(from, to, value);
         gnc_price_begin_edit (price);
         gnc_price_set_time (price, ts);
         gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
@@ -1814,6 +1836,7 @@ gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData)
         {
 /* FIXME: We probably want to swap the result price's to and from, not invert the price. */
             rate = gnc_numeric_invert(gnc_price_get_value (prc));
+            rate = round_price(from, to, rate);
             _gnc_xfer_dialog_set_price_edit(xferData, rate);
             gnc_price_unref (prc);
             have_price = TRUE;
@@ -2370,6 +2393,7 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
     gboolean swap_amounts = FALSE;
     gnc_commodity *txn_cur = xaccTransGetCurrency(txn);
     gnc_commodity *reg_com = xaccAccountGetCommodity(reg_acc);
+    gnc_numeric dialog_rate = *exch_rate;
 
     g_return_val_if_fail(txn_cur, TRUE);
 
@@ -2431,7 +2455,10 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
         gnc_xfer_dialog_select_to_currency(xfer, txn_cur);
         gnc_xfer_dialog_select_from_currency(xfer, xfer_com);
         if (!gnc_numeric_zero_p(*exch_rate))
-            *exch_rate = gnc_numeric_invert(*exch_rate);
+        {
+            dialog_rate = gnc_numeric_invert(*exch_rate);
+            dialog_rate = round_price(xfer_com, txn_cur, *exch_rate);
+        }
         amount = gnc_numeric_neg(amount);
     }
     else
@@ -2455,16 +2482,11 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
      */
 
     /* Set the exchange rate */
-    _gnc_xfer_dialog_set_price_edit(xfer, *exch_rate);
+    _gnc_xfer_dialog_set_price_edit(xfer, dialog_rate);
 
     /* and run it... */
     if (gnc_xfer_dialog_run_until_done(xfer) == FALSE)
         return TRUE;
 
-    /* If we swapped the amounts for the dialog, then make sure we swap
-     * it back now...
-     */
-    if (swap_amounts)
-        *exch_rate = gnc_numeric_invert(*exch_rate);
     return FALSE;
 }

commit bfbb50879901ac4f0ecde4065d5b662afa69568f
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Aug 31 13:40:21 2015 -0700

    Fix swap_amount so that it swaps the account pointers.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 2f4950c..dd90e8b 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1493,14 +1493,14 @@ create_transaction(XferDialog *xferData, Timespec *ts,
 }
 
 static void
-swap_amount (gnc_commodity *from, gnc_commodity *to, gnc_numeric *value,
+swap_amount (gnc_commodity **from, gnc_commodity **to, gnc_numeric *value,
              gnc_numeric *from_amt, gnc_numeric *to_amt)
 {
     gnc_commodity *tmp;
     gnc_numeric *tmp_amt;
-    tmp = from;
-    from = to;
-    to = tmp;
+    tmp = *from;
+    *from = *to;
+    *to = tmp;
     tmp_amt = from_amt;
     from_amt = to_amt;
     to_amt = tmp_amt;
@@ -1537,7 +1537,7 @@ create_price(XferDialog *xferData, Timespec ts)
         ((to != gnc_default_currency()) &&
          (strcmp (gnc_commodity_get_mnemonic(from),
                   gnc_commodity_get_mnemonic(to)) < 0)))
-        swap_amount (from, to, &value, &from_amt, &to_amt);
+        swap_amount (&from, &to, &value, &from_amt, &to_amt);
     /* 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)

commit 86320a4d11188bbc0b251060440dc693d502053c
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Aug 31 13:39:37 2015 -0700

    Fix gnc_numeric_invert to correctly handle negative values.

diff --git a/src/libqof/qof/gnc-numeric.c b/src/libqof/qof/gnc-numeric.c
index 97e416f..44c6400 100644
--- a/src/libqof/qof/gnc-numeric.c
+++ b/src/libqof/qof/gnc-numeric.c
@@ -1154,9 +1154,21 @@ gnc_numeric_invert(gnc_numeric num)
 {
     if (num.num == 0)
         return gnc_numeric_zero();
-    return gnc_numeric_create (num.denom, num.num);
+    if (num.denom > 0)
+    {
+        if (num.num < 0)
+            return gnc_numeric_create (-num.denom, -num.num);
+        return gnc_numeric_create (num.denom, num.num);
+    }
+    else /* Negative denominator means multiply instead of divide. */
+    {
+        int64_t mult = (num.num < 0 ? INT64_C(-1) : INT64_C(1));
+        qofint128 denom = mult128(-num.denom, mult * num.num);
+        if (denom.hi)
+            return gnc_numeric_error(GNC_ERROR_OVERFLOW);
+        return gnc_numeric_create (mult, denom.lo);
+    }
 }
-
 /* *******************************************************************
  *  double_to_gnc_numeric
  ********************************************************************/

commit c068397633569699b00cd3f4062f779f84f16faf
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Aug 30 11:36:54 2015 -0700

    Flip return values of check_edit() and check_accounts().
    
    It's easier to understand if they return FALSE on fail.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 79f6ba2..2f4950c 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1361,7 +1361,7 @@ check_accounts  (XferDialog* xferData, Account* from_account,
                                 "Otherwise, it will not be recorded.");
         gnc_error_dialog(xferData->dialog, "%s", message);
         LEAVE("bad account");
-        return TRUE;
+        return FALSE;
     }
 
     if (from_account == to_account)
@@ -1370,7 +1370,7 @@ check_accounts  (XferDialog* xferData, Account* from_account,
                                 "account!");
         gnc_error_dialog(xferData->dialog, "%s", message);
         LEAVE("same account");
-        return TRUE;
+        return FALSE;
     }
 
     if (xaccAccountGetPlaceholder(from_account) ||
@@ -1398,9 +1398,9 @@ check_accounts  (XferDialog* xferData, Account* from_account,
               "and making the \"amount\" negative.");
         gnc_error_dialog(xferData->dialog, "%s", message);
         LEAVE("non-currency");
-        return TRUE;
+        return FALSE;
     }
-    return FALSE;
+    return TRUE;
 }
 
 static gboolean
@@ -1412,7 +1412,7 @@ check_edit(XferDialog *xferData)
         {
             gnc_parse_error_dialog (xferData, _("You must enter a valid price."));
             LEAVE("invalid price");
-            return TRUE;
+            return FALSE;
         }
     }
 
@@ -1424,10 +1424,10 @@ check_edit(XferDialog *xferData)
             gnc_parse_error_dialog (xferData,
                                     _("You must enter a valid `to' amount."));
             LEAVE("invalid to amount");
-            return TRUE;
+            return FALSE;
         }
     }
-    return FALSE;
+    return TRUE;
 }
 
 static void
@@ -1647,7 +1647,7 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
     to_account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_TO);
 
     if (xferData->exch_rate == NULL &&
-        check_accounts(xferData, from_account, to_account))
+        !check_accounts(xferData, from_account, to_account))
         return;
 
     if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->amount_edit)))
@@ -1671,7 +1671,7 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
 
     if (!gnc_commodity_equiv(xferData->from_commodity, xferData->to_commodity))
     {
-        if (check_edit(xferData))
+        if (!check_edit(xferData))
             return;
         to_amount = gnc_amount_edit_get_amount
             (GNC_AMOUNT_EDIT(xferData->to_amount_edit));

commit e12c89b5cac50364e7234ce9be94cb0bf0819c59
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Aug 29 07:50:20 2015 -0700

    Move gnc_numeric_invert to be not-inline.
    
    The inline version crashed.

diff --git a/src/libqof/qof/gnc-numeric.c b/src/libqof/qof/gnc-numeric.c
index 693fdf9..97e416f 100644
--- a/src/libqof/qof/gnc-numeric.c
+++ b/src/libqof/qof/gnc-numeric.c
@@ -1149,6 +1149,13 @@ gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
     return TRUE;
 }
 
+gnc_numeric
+gnc_numeric_invert(gnc_numeric num)
+{
+    if (num.num == 0)
+        return gnc_numeric_zero();
+    return gnc_numeric_create (num.denom, num.num);
+}
 
 /* *******************************************************************
  *  double_to_gnc_numeric
diff --git a/src/libqof/qof/gnc-numeric.h b/src/libqof/qof/gnc-numeric.h
index b833753..89933c8 100644
--- a/src/libqof/qof/gnc-numeric.h
+++ b/src/libqof/qof/gnc-numeric.h
@@ -510,10 +510,7 @@ gboolean gnc_numeric_to_decimal(gnc_numeric * a,
  * @param num The number to be inverted
  * @return a gnc_numeric that is the inverse of num
  */
-inline gnc_numeric gnc_numeric_invert (gnc_numeric num)
-{
-    return gnc_numeric_create (num.num, num.denom);
-}
+gnc_numeric gnc_numeric_invert (gnc_numeric num);
 /** @} */
 
 /** @name GValue

commit 6b5207785a28c24ee887bc58a0af64318ba26640
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Aug 28 21:20:51 2015 +0100

    Create a rounding policy for prices in the pricedb.
    
    Currency-currency prices will be priced in the smaller currency so that
    the price > 1 and will be rounded to 3 digits after the decimal.
    Commodity-currency prices will be priced in the currency and rounded to
    the currency's scu * 10000.
    This affects only prices stored in the pricedb. Prices in splits will
    continue to be computed from value/amount.

diff --git a/src/engine/gnc-pricedb.h b/src/engine/gnc-pricedb.h
index befff2d..c7fe6d0 100644
--- a/src/engine/gnc-pricedb.h
+++ b/src/engine/gnc-pricedb.h
@@ -243,6 +243,15 @@ gboolean        gnc_price_equal(const GNCPrice *p1, const GNCPrice *p2);
 /** This simple function can be useful for debugging the price code */
 void gnc_price_print(GNCPrice *db, FILE *f, int indent);
 /** @} */
+/** @name Denominator Constants Price policy: In order to avoid rounding
+ * problems, currency prices (often called exchange rates) are saved in terms of
+ * the smaller currency, so that price > 1, with a fixed denominator of
+ * 1/1000. Commodity prices in currency are always expressed as value per unit
+ * of the commodity with a fixed denominator of the pricing currency's
+ * SCU * 10000.
+ */
+#define CURRENCY_DENOM 1000
+#define COMMODITY_DENOM_MULT 10000
 
 /* ================================================================ */
 /** @name GNCPrice lists
diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 0bfa185..79f6ba2 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -55,8 +55,6 @@
 #define DIALOG_TRANSFER_CM_CLASS "dialog-transfer"
 #define GNC_PREFS_GROUP "dialogs.transfer"
 
-#define PRECISION 1000000
-
 typedef enum
 {
     XFER_DIALOG_FROM,
@@ -1003,15 +1001,16 @@ gnc_xfer_to_amount_update_cb(GtkWidget *widget, GdkEventFocus *event,
     XferDialog *xferData = data;
     gnc_numeric price_value;
     Account *account;
+    int scu;
 
     account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_TO);
     if (account == NULL)
         account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_FROM);
-
+    scu = xaccAccountGetCommoditySCU(account);
     gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->to_amount_edit));
 
     price_value = gnc_xfer_dialog_compute_price_value(xferData);
-    price_value = gnc_numeric_convert (price_value, PRECISION,
+    price_value = gnc_numeric_convert (price_value, scu * COMMODITY_DENOM_MULT,
                                        GNC_HOW_RND_ROUND_HALF_UP);
     gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit),
                                price_value);
@@ -1507,6 +1506,16 @@ swap_amount (gnc_commodity *from, gnc_commodity *to, gnc_numeric *value,
     to_amt = tmp_amt;
     *value = gnc_numeric_invert (*value);
 }
+
+static gnc_numeric
+swap_commodities(gnc_commodity **from, gnc_commodity **to, gnc_numeric value)
+{
+    gnc_commodity *tmp = *to;
+    *to = *from;
+    *from = tmp;
+    return gnc_numeric_invert(value);
+}
+
 static void
 create_price(XferDialog *xferData, Timespec ts)
 {
@@ -1516,6 +1525,7 @@ create_price(XferDialog *xferData, Timespec ts)
     gnc_numeric price_value;
     gnc_numeric value;
     gnc_numeric from_amt, to_amt;
+    gboolean swap = FALSE;
 
 /* Bail in the unlikely event that both currencies have joined the Euro. */
     if (gnc_is_euro_currency (from) && gnc_is_euro_currency (to))
@@ -1530,21 +1540,17 @@ create_price(XferDialog *xferData, Timespec ts)
         swap_amount (from, to, &value, &from_amt, &to_amt);
     /* 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)
-    {
-        price_value = gnc_price_get_value(price);
-    }
-    else
+    if (!price)
     {
         price = gnc_pricedb_lookup_day (xferData->pricedb, to, from, ts);
         if (price)
-
-            price_value = gnc_numeric_invert(gnc_price_get_value(price));
+            swap = TRUE;
     }
 
     if (price)
     {
-        if (gnc_numeric_equal(value, price_value))
+        if (gnc_numeric_equal(swap ? gnc_numeric_invert(value) : value,
+                              price_value))
         {
             PINFO("Found price for %s in %s", gnc_commodity_get_mnemonic(from),
                   gnc_commodity_get_mnemonic(to));
@@ -1557,10 +1563,18 @@ create_price(XferDialog *xferData, Timespec ts)
             gnc_price_unref (price);
             return;
         }
-        if (!gnc_numeric_eq(price_value, gnc_price_get_value(price)))
+        if (swap)
         {
-            value = gnc_numeric_invert(value);
-            value = gnc_numeric_convert(value, PRECISION, GNC_HOW_DENOM_REDUCE);
+            value = swap_commodities(&from, &to, value);
+        }
+        if (gnc_commodity_is_currency(from) && gnc_commodity_is_currency(to))
+            value = gnc_numeric_convert(value, CURRENCY_DENOM,
+                                        GNC_HOW_RND_ROUND_HALF_UP);
+        else if (gnc_commodity_is_currency(to))
+        {
+            int scu = gnc_commodity_get_fraction (to);
+            value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                        GNC_HOW_RND_ROUND_HALF_UP);
         }
         gnc_price_begin_edit (price);
         gnc_price_set_time (price, ts);
@@ -1572,6 +1586,24 @@ create_price(XferDialog *xferData, Timespec ts)
         gnc_price_unref (price);
         return;
     }
+    if (gnc_commodity_is_currency(from) && gnc_commodity_is_currency(to))
+    {
+        if (value.num < value.denom)
+        {
+            value = swap_commodities(&from, &to, value);
+        }
+        value = gnc_numeric_convert(value, CURRENCY_DENOM,
+                                    GNC_HOW_RND_ROUND_HALF_UP);
+    }
+    else if (gnc_commodity_is_currency(from) || gnc_commodity_is_currency(to))
+    {
+        int scu;
+        if (gnc_commodity_is_currency(from))
+            value = swap_commodities(&from, &to, value);
+        scu = gnc_commodity_get_fraction (to);
+        value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                    GNC_HOW_RND_ROUND_HALF_UP);
+    }
     price = gnc_price_create (xferData->book);
     gnc_price_begin_edit (price);
     gnc_price_set_commodity (price, from);
diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c
index aef5c6f..3cf90cc 100644
--- a/src/register/ledger-core/split-register.c
+++ b/src/register/ledger-core/split-register.c
@@ -64,9 +64,9 @@ static QofLogModule log_module = GNC_MOD_LEDGER;
 static CursorClass copied_class = CURSOR_CLASS_NONE;
 static SCM copied_item = SCM_UNDEFINED;
 static GncGUID copied_leader_guid;
-static const int PRECISION = 1000000;
-
-
+/* A denominator representing number of digits to the right of the decimal point
+ * displayed in a price cell. */
+static int PRICE_CELL_DENOM = 1000000;
 /** static prototypes *****************************************************/
 
 static gboolean gnc_split_register_save_to_scm (SplitRegister *reg,
@@ -2053,6 +2053,7 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
     gnc_commodity *curr = xaccTransGetCurrency (trans);
     GNCPrice *price;
     gnc_numeric price_value;
+    int scu = gnc_commodity_get_fraction(curr);
     Timespec ts;
     BasicCell *cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
 
@@ -2073,10 +2074,10 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
         price = gnc_pricedb_lookup_day (pricedb, curr, comm, ts);
         if (price)
         {
-            price_value = gnc_numeric_div (gnc_numeric_create(1, 1),
-                                           gnc_price_get_value(price),
-                                           GNC_DENOM_AUTO,
-                                           GNC_HOW_DENOM_REDUCE);
+/* It might be better to raise an error here: We shouldn't be creating
+ * currency->commodity prices.
+ */
+            price_value = gnc_numeric_invert(gnc_price_get_value(price));
         }
     }
     if (price)
@@ -2092,9 +2093,15 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
             return;
         }
         if (!gnc_numeric_eq(price_value, gnc_price_get_value(price)))
-            value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
-                                           PRECISION, GNC_HOW_DENOM_REDUCE);
-
+        {
+            value = gnc_numeric_invert(value);
+            scu = gnc_commodity_get_fraction(comm);
+            value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                        GNC_HOW_RND_ROUND_HALF_UP);
+        }
+        else
+            value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                        GNC_HOW_RND_ROUND_HALF_UP);
         gnc_price_begin_edit (price);
         gnc_price_set_time (price, ts);
         gnc_price_set_source (price, PRICE_SOURCE_SPLIT_REG);
@@ -2104,6 +2111,8 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
         return;
     }
 
+    value = gnc_numeric_convert(value, scu * COMMODITY_DENOM_MULT,
+                                GNC_HOW_RND_ROUND_HALF_UP);
     price = gnc_price_create (book);
     gnc_price_begin_edit (price);
     gnc_price_set_commodity (price, comm);
@@ -2589,7 +2598,8 @@ gnc_split_register_config_cells (SplitRegister *reg)
     /* Use 6 decimal places for prices and "exchange rates"  */
     gnc_price_cell_set_fraction
     ((PriceCell *)
-     gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL), PRECISION);
+     gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
+     PRICE_CELL_DENOM);
 
     /* Initialize shares and share balance cells */
     gnc_price_cell_set_print_info

commit c7c97be684186bc4cfe90c9759cf838b4b6aaa74
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Aug 28 19:25:35 2015 +0100

    Rename _gnc_xfer_dialog_set_exchange_rate and use it consistently.
    
    _gnc_xfer_dialog_set_price_edit says what we're actually setting.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 30c0dc8..0bfa185 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -160,6 +160,7 @@ static Account *gnc_transfer_dialog_get_selected_account (XferDialog *dialog,
 static void gnc_transfer_dialog_set_selected_account (XferDialog *dialog,
                                                       Account *account,
                                                       XferDirection direction);
+static void _gnc_xfer_dialog_set_price_edit(XferDialog*, gnc_numeric);
 
 void gnc_xfer_description_insert_cb(GtkEditable *editable,
                                     const gchar *insert_text,
@@ -259,7 +260,7 @@ gnc_xfer_dialog_update_price (XferDialog *xferData)
     }
 
     /* and set the price entry */
-    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (xferData->price_edit), price_value);
+    _gnc_xfer_dialog_set_price_edit(xferData, price_value);
 
     /* And then update the to_amount */
     gnc_xfer_update_to_amount (xferData);
@@ -313,9 +314,7 @@ gnc_xfer_dialog_set_price_auto (XferDialog *xferData,
     if (!currency_active)
     {
         GtkEntry *entry;
-
-        gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit),
-                                   gnc_numeric_zero ());
+        _gnc_xfer_dialog_set_price_edit(xferData, gnc_numeric_zero());
         entry = GTK_ENTRY(gnc_amount_edit_gtk_entry
                           (GNC_AMOUNT_EDIT(xferData->price_edit)));
         gtk_entry_set_text(entry, "");
@@ -1338,16 +1337,16 @@ void gnc_xfer_dialog_set_date_sensitive(XferDialog *xferData,
 }
 
 void
-gnc_xfer_dialog_set_exchange_rate(XferDialog *xferData, gnc_numeric exchange_rate)
+_gnc_xfer_dialog_set_price_edit(XferDialog *xferData, gnc_numeric price_value)
 {
     if (xferData == NULL)
         return;
 
-    if (gnc_numeric_zero_p (exchange_rate))
+    if (gnc_numeric_zero_p (price_value))
         return;
 
     gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (xferData->price_edit),
-                                exchange_rate);
+                                price_value);
 
     gnc_xfer_update_to_amount (xferData);
 }
@@ -1770,7 +1769,7 @@ gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData)
     if (prc)
     {
         rate = gnc_price_get_value (prc);
-        gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit), rate);
+        _gnc_xfer_dialog_set_price_edit(xferData, rate);
         gnc_price_unref (prc);
         have_price = TRUE;
     }
@@ -1781,9 +1780,9 @@ gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData)
         prc = gnc_pricedb_lookup_latest (xferData->pricedb, to, from);
         if (prc)
         {
-            gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit), rate);
 /* FIXME: We probably want to swap the result price's to and from, not invert the price. */
             rate = gnc_numeric_invert(gnc_price_get_value (prc));
+            _gnc_xfer_dialog_set_price_edit(xferData, rate);
             gnc_price_unref (prc);
             have_price = TRUE;
         }
@@ -2424,7 +2423,7 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
      */
 
     /* Set the exchange rate */
-    gnc_xfer_dialog_set_exchange_rate(xfer, *exch_rate);
+    _gnc_xfer_dialog_set_price_edit(xfer, *exch_rate);
 
     /* and run it... */
     if (gnc_xfer_dialog_run_until_done(xfer) == FALSE)
@@ -2434,7 +2433,6 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
      * it back now...
      */
     if (swap_amounts)
-        *exch_rate = gnc_numeric_div(gnc_numeric_create(1, 1), *exch_rate,
-                                     GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+        *exch_rate = gnc_numeric_invert(*exch_rate);
     return FALSE;
 }

commit 73233a5e2e93f96f73ae60c314e58e1280bb9641
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Aug 28 19:21:37 2015 +0100

    Provide gnc_numeric_invert() convenience function.
    
    Clearer and faster than dividing into 1/1.

diff --git a/src/app-utils/gnc-sx-instance-model.c b/src/app-utils/gnc-sx-instance-model.c
index 560fe79..cc7dbbf 100644
--- a/src/app-utils/gnc-sx-instance-model.c
+++ b/src/app-utils/gnc-sx-instance-model.c
@@ -1170,9 +1170,9 @@ create_each_transaction_helper(Transaction *template_txn, void *user_data)
                   }
                   else
                   {
-                  exchange = gnc_numeric_div(gnc_numeric_create(1,1),
-                  gnc_price_get_value(price),
-                  1000, GNC_HOW_RND_ROUND_HALF_UP);
+                  exchange = gnc_numeric_invert(gnc_price_get_value(price));
+                  exchange = gnc_numeric_convert(exchange, 1000,
+                                                 GNC_HOW_RND_ROUND_HALF_UP);
                   }
                   }
                   else
@@ -1779,4 +1779,3 @@ GHashTable* gnc_sx_all_instantiate_cashflow_all(GDate range_start, GDate range_e
                                     result_map, NULL);
     return result_map;
 }
-
diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index aed2b3f..30c0dc8 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -250,8 +250,7 @@ gnc_xfer_dialog_update_price (XferDialog *xferData)
     {
         PINFO("Found reverse price: 1 %s = %f %s", gnc_commodity_get_mnemonic(to),
               gnc_numeric_to_double(price_value), gnc_commodity_get_mnemonic(from));
-        price_value = gnc_numeric_div (gnc_numeric_create (1, 1), price_value,
-                                 GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+        price_value = gnc_numeric_invert(price_value);
     }
     else
     {
@@ -910,8 +909,7 @@ gnc_xfer_dialog_update_conv_info (XferDialog *xferData)
         gtk_label_set_text(GTK_LABEL(xferData->conv_forward), string);
         g_free(string);
 
-        rate = gnc_numeric_div(gnc_numeric_create (1, 1), rate,
-                               GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+        rate = gnc_numeric_invert(rate);
         string = g_strdup_printf("1 %s = %f %s", to_mnemonic,
                                  gnc_numeric_to_double(rate), from_mnemonic);
         gtk_label_set_text(GTK_LABEL(xferData->conv_reverse), string);
@@ -1508,8 +1506,7 @@ swap_amount (gnc_commodity *from, gnc_commodity *to, gnc_numeric *value,
     tmp_amt = from_amt;
     from_amt = to_amt;
     to_amt = tmp_amt;
-    *value = gnc_numeric_div (gnc_numeric_create(1, 1), *value,
-                              GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+    *value = gnc_numeric_invert (*value);
 }
 static void
 create_price(XferDialog *xferData, Timespec ts)
@@ -1542,12 +1539,8 @@ create_price(XferDialog *xferData, Timespec ts)
     {
         price = gnc_pricedb_lookup_day (xferData->pricedb, to, from, ts);
         if (price)
-        {
-            price_value = gnc_numeric_div (gnc_numeric_create(1, 1),
-                                           gnc_price_get_value(price),
-                                           GNC_DENOM_AUTO,
-                                           GNC_HOW_DENOM_REDUCE);
-        }
+
+            price_value = gnc_numeric_invert(gnc_price_get_value(price));
     }
 
     if (price)
@@ -1566,9 +1559,10 @@ create_price(XferDialog *xferData, Timespec ts)
             return;
         }
         if (!gnc_numeric_eq(price_value, gnc_price_get_value(price)))
-            value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
-                                           PRECISION, GNC_HOW_DENOM_REDUCE);
-
+        {
+            value = gnc_numeric_invert(value);
+            value = gnc_numeric_convert(value, PRECISION, GNC_HOW_DENOM_REDUCE);
+        }
         gnc_price_begin_edit (price);
         gnc_price_set_time (price, ts);
         gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
@@ -1787,10 +1781,9 @@ gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData)
         prc = gnc_pricedb_lookup_latest (xferData->pricedb, to, from);
         if (prc)
         {
-            rate = gnc_numeric_div (gnc_numeric_create (1, 1), gnc_price_get_value (prc),
-                                    GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
-
             gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit), rate);
+/* FIXME: We probably want to swap the result price's to and from, not invert the price. */
+            rate = gnc_numeric_invert(gnc_price_get_value (prc));
             gnc_price_unref (prc);
             have_price = TRUE;
         }
@@ -2396,9 +2389,9 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
         gnc_numeric rate = xaccTransGetAccountConvRate(txn, reg_acc);
 
         /* XXX: should we tell the user we've done the conversion? */
-        amount = gnc_numeric_div(
-            amount, rate,
-            gnc_commodity_get_fraction(txn_cur), GNC_HOW_DENOM_REDUCE);
+        amount = gnc_numeric_div(amount, rate,
+                                 gnc_commodity_get_fraction(txn_cur),
+                                 GNC_HOW_DENOM_REDUCE);
     }
 
     /* enter the accounts */
@@ -2407,8 +2400,7 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
         gnc_xfer_dialog_select_to_currency(xfer, txn_cur);
         gnc_xfer_dialog_select_from_currency(xfer, xfer_com);
         if (!gnc_numeric_zero_p(*exch_rate))
-            *exch_rate = gnc_numeric_div(gnc_numeric_create(1, 1), *exch_rate,
-                                         GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+            *exch_rate = gnc_numeric_invert(*exch_rate);
         amount = gnc_numeric_neg(amount);
     }
     else
diff --git a/src/libqof/qof/gnc-numeric.h b/src/libqof/qof/gnc-numeric.h
index bcb70f1..b833753 100644
--- a/src/libqof/qof/gnc-numeric.h
+++ b/src/libqof/qof/gnc-numeric.h
@@ -504,6 +504,16 @@ gnc_numeric gnc_numeric_reduce(gnc_numeric n);
  ********************************************************************/
 gboolean gnc_numeric_to_decimal(gnc_numeric * a,
                                 guint8 * max_decimal_places);
+
+/** Invert a gnc_numeric.
+ * Much faster than dividing 1 by it.
+ * @param num The number to be inverted
+ * @return a gnc_numeric that is the inverse of num
+ */
+inline gnc_numeric gnc_numeric_invert (gnc_numeric num)
+{
+    return gnc_numeric_create (num.num, num.denom);
+}
 /** @} */
 
 /** @name GValue

commit 3a51c0d5c1ce654cf07a3eba22783411dfc5d128
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Aug 28 18:40:01 2015 +0100

    Use price_value when referring to a gnc_numeric.
    
    Price and prc are for gnc_price*.
    For clarity.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index c180283..aed2b3f 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -180,7 +180,7 @@ void gnc_xfer_dialog_close_cb(GtkDialog *dialog, gpointer data);
 /** Implementations **********************************************/
 
 static gnc_numeric
-gnc_xfer_dialog_compute_price (XferDialog *xferData)
+gnc_xfer_dialog_compute_price_value (XferDialog *xferData)
 {
     gnc_numeric from_amt, to_amt;
     g_return_val_if_fail (xferData != NULL, gnc_numeric_error (GNC_ERROR_ARG));
@@ -196,7 +196,7 @@ static void
 gnc_xfer_dialog_update_price (XferDialog *xferData)
 {
     GNCPrice *prc;
-    gnc_numeric price;
+    gnc_numeric price_value;
     Timespec date;
     gnc_commodity *from = xferData->from_commodity;
     gnc_commodity *to = xferData->to_commodity;
@@ -245,22 +245,22 @@ gnc_xfer_dialog_update_price (XferDialog *xferData)
         return;
 
     /* grab the price from the pricedb */
-    price = gnc_price_get_value (prc);
+    price_value = 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_numeric_to_double(price_value), gnc_commodity_get_mnemonic(from));
+        price_value = gnc_numeric_div (gnc_numeric_create (1, 1), price_value,
                                  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));
+              gnc_numeric_to_double(price_value), gnc_commodity_get_mnemonic(to));
     }
 
     /* and set the price entry */
-    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (xferData->price_edit), price);
+    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (xferData->price_edit), price_value);
 
     /* And then update the to_amount */
     gnc_xfer_update_to_amount (xferData);
@@ -309,7 +309,7 @@ gnc_xfer_dialog_set_price_auto (XferDialog *xferData,
 {
     gnc_numeric from_rate;
     gnc_numeric to_rate;
-    gnc_numeric price;
+    gnc_numeric price_value;
 
     if (!currency_active)
     {
@@ -339,9 +339,9 @@ gnc_xfer_dialog_set_price_auto (XferDialog *xferData,
     if (gnc_numeric_zero_p (from_rate) || gnc_numeric_zero_p (to_rate))
         gnc_xfer_dialog_update_price (xferData);
 
-    price = gnc_numeric_div (to_rate, from_rate, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+    price_value = gnc_numeric_div (to_rate, from_rate, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
 
-    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(xferData->price_edit), price);
+    gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT(xferData->price_edit), price_value);
 
     gnc_xfer_update_to_amount (xferData);
 }
@@ -938,7 +938,7 @@ static void
 gnc_xfer_update_to_amount (XferDialog *xferData)
 {
     GNCAmountEdit *amount_edit, *price_edit, *to_amount_edit;
-    gnc_numeric price, to_amount;
+    gnc_numeric price_value, to_amount;
     Account *account;
     int scu = 0;
 
@@ -961,11 +961,11 @@ gnc_xfer_update_to_amount (XferDialog *xferData)
 
     /* Determine the amount to transfer. */
     if (!gnc_amount_edit_evaluate(price_edit) ||
-        gnc_numeric_zero_p(price = gnc_amount_edit_get_amount(price_edit)))
+        gnc_numeric_zero_p(price_value = gnc_amount_edit_get_amount(price_edit)))
         to_amount = gnc_numeric_zero();
     else
         to_amount = gnc_numeric_mul(gnc_amount_edit_get_amount(amount_edit),
-                                    price, scu, GNC_HOW_RND_ROUND_HALF_UP);
+                                    price_value, scu, GNC_HOW_RND_ROUND_HALF_UP);
 
     /* Update the dialog. */
     gnc_amount_edit_set_amount(to_amount_edit, to_amount);
@@ -1004,7 +1004,7 @@ gnc_xfer_to_amount_update_cb(GtkWidget *widget, GdkEventFocus *event,
                              gpointer data)
 {
     XferDialog *xferData = data;
-    gnc_numeric price;
+    gnc_numeric price_value;
     Account *account;
 
     account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_TO);
@@ -1013,9 +1013,11 @@ gnc_xfer_to_amount_update_cb(GtkWidget *widget, GdkEventFocus *event,
 
     gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->to_amount_edit));
 
-    price = gnc_xfer_dialog_compute_price(xferData);
-    price = gnc_numeric_convert (price, PRECISION, GNC_HOW_RND_ROUND_HALF_UP);
-    gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit), price);
+    price_value = gnc_xfer_dialog_compute_price_value(xferData);
+    price_value = gnc_numeric_convert (price_value, PRECISION,
+                                       GNC_HOW_RND_ROUND_HALF_UP);
+    gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(xferData->price_edit),
+                               price_value);
     gnc_xfer_dialog_update_conv_info(xferData);
 
     return FALSE;
@@ -1656,7 +1658,7 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
 
     if (xferData->exch_rate)
     {
-        gnc_numeric price;
+        gnc_numeric price_value;
 
         /* If we've got the price-button set, then make sure we update the
          * to-amount before we use it.
@@ -1664,8 +1666,8 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xferData->price_radio)))
             gnc_xfer_update_to_amount(xferData);
 
-        price = gnc_xfer_dialog_compute_price(xferData);
-        *(xferData->exch_rate) = gnc_numeric_abs(price);
+        price_value = gnc_xfer_dialog_compute_price_value(xferData);
+        *(xferData->exch_rate) = gnc_numeric_abs(price_value);
     }
     else
         create_transaction (xferData, &ts, from_account, to_account,

commit 06f70bad61ea7205128b7aeb2ff49550b9139a60
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Aug 25 11:17:07 2015 +0100

    Price-quotes: Modify quotes on same day instead of creating new ones.
    
    We can use only one per day so no point in keeping a bunch of them.
    Finance::Quote prices always overwrite user prices.

diff --git a/src/scm/price-quotes.scm b/src/scm/price-quotes.scm
index 7daacd0..c6a2405 100644
--- a/src/scm/price-quotes.scm
+++ b/src/scm/price-quotes.scm
@@ -370,7 +370,11 @@
                  (string? currency-str)
                  (gnc-commodity-table-lookup commodity-table
                                              "ISO4217"
-                                             (string-upcase currency-str)))))
+                                             (string-upcase currency-str))))
+           (pricedb (gnc-pricedb-get-db book))
+           (saved-price #f)
+           (commodity-str (gnc-commodity-get-printname commodity))
+           )
 
       (or-map (lambda (price-sym)
                 (let ((p (assq-ref quote-data price-sym)))
@@ -403,27 +407,44 @@
       (if (not (and commodity currency gnc-time price price-type))
           (string-append
            currency-str ":" (gnc-commodity-get-mnemonic commodity))
-          (let ((gnc-price (gnc-price-create book)))
-            (if (not gnc-price)
-                (string-append
-                 currency-str ":" (gnc-commodity-get-mnemonic commodity))
-                (begin
-				  (gnc-price-begin-edit gnc-price)
-                  (gnc-price-set-commodity gnc-price commodity)
-                  (gnc-price-set-currency gnc-price currency)
-                  (gnc-price-set-time gnc-price gnc-time)
-                  (gnc-price-set-source gnc-price "Finance::Quote")
-                  (gnc-price-set-typestr gnc-price price-type)
-                  (gnc-price-set-value gnc-price price)
-				  (gnc-price-commit-edit gnc-price)
-                  gnc-price))))))
+          (begin
+            (set! saved-price (gnc-pricedb-lookup-day pricedb
+                                                      commodity currency
+                                                      gnc-time))
+            (if (not (null? saved-price))
+              (begin
+                (gnc-price-begin-edit saved-price)
+                (gnc-price-set-time saved-price gnc-time)
+                (gnc-price-set-source saved-price "Finance::Quote")
+                (gnc-price-set-typestr saved-price price-type)
+                (gnc-price-set-value saved-price price)
+                (gnc-price-commit-edit saved-price)
+                #f)
+              (let ((gnc-price (gnc-price-create book)))
+                (if (not gnc-price)
+                    (string-append
+                     currency-str ":" (gnc-commodity-get-mnemonic commodity))
+                    (begin
+                      (gnc-price-begin-edit gnc-price)
+                      (gnc-price-set-commodity gnc-price commodity)
+                      (gnc-price-set-currency gnc-price currency)
+                      (gnc-price-set-time gnc-price gnc-time)
+                      (gnc-price-set-source gnc-price "Finance::Quote")
+                      (gnc-price-set-typestr gnc-price price-type)
+                      (gnc-price-set-value gnc-price price)
+                      (gnc-price-commit-edit gnc-price)
+                      gnc-price)))))
+          )))
 
   (define (book-add-prices! book prices)
     (let ((pricedb (gnc-pricedb-get-db book)))
       (for-each
        (lambda (price)
-         (gnc-pricedb-add-price pricedb price)
-         (gnc-price-unref price))
+         (if price
+             (begin
+               (gnc-pricedb-add-price pricedb price)
+               (gnc-price-unref price)
+               #f)))
        prices)))
 
   ;; FIXME: uses of gnc:warn in here need to be cleaned up.  Right

commit ea48ed882b35f94aa716e91a8a82418a91fb687e
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Aug 23 12:17:23 2015 +0100

    Edit split-based prices instead of adding.
    
    For split-register and xfer-dialog generated prices if there's an existing
    non-FQ price for the day, change it. If there's an F::Q quote for the day,
    do nothing. Only add a price if there isn't one for the from/to
    combination.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index ebc0097..c180283 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -86,7 +86,7 @@ struct _xferDialog
     gnc_commodity *to_commodity;
 
     QuickFill *qf;     /* Quickfill on transfer descriptions,
-                           defaults to matching on the "From" account. */
+                          defaults to matching on the "From" account. */
 
     XferDirection quickfill;    /* direction match on the account instead. */
 
@@ -1548,26 +1548,46 @@ create_price(XferDialog *xferData, Timespec ts)
         }
     }
 
-    if (price && gnc_numeric_equal(value, price_value))
-    {
-        PINFO("Found price for %s in %s", gnc_commodity_get_mnemonic(from),
-              gnc_commodity_get_mnemonic(to));
-    }
-    else
+    if (price)
     {
-        price = gnc_price_create (xferData->book);
+        if (gnc_numeric_equal(value, price_value))
+        {
+            PINFO("Found price for %s in %s", gnc_commodity_get_mnemonic(from),
+                  gnc_commodity_get_mnemonic(to));
+            gnc_price_unref (price);
+            return;
+        }
+        if (strcmp (gnc_price_get_source(price), PRICE_SOURCE_FQ) == 0)
+        {
+            PINFO("Existing price is from Finance::Quote, so won't supersede.");
+            gnc_price_unref (price);
+            return;
+        }
+        if (!gnc_numeric_eq(price_value, gnc_price_get_value(price)))
+            value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
+                                           PRECISION, GNC_HOW_DENOM_REDUCE);
+
         gnc_price_begin_edit (price);
-        gnc_price_set_commodity (price, from);
-        gnc_price_set_currency (price, to);
         gnc_price_set_time (price, ts);
         gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
         gnc_price_set_value (price, value);
-        gnc_pricedb_add_price (xferData->pricedb, price);
         gnc_price_commit_edit (price);
-        PINFO("Created price: 1 %s = %f %s", gnc_commodity_get_mnemonic(from),
+        PINFO("Modified price: 1 %s = %f %s", gnc_commodity_get_mnemonic(from),
               gnc_numeric_to_double(value), gnc_commodity_get_mnemonic(to));
+        gnc_price_unref (price);
+        return;
     }
-
+    price = gnc_price_create (xferData->book);
+    gnc_price_begin_edit (price);
+    gnc_price_set_commodity (price, from);
+    gnc_price_set_currency (price, to);
+    gnc_price_set_time (price, ts);
+    gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
+    gnc_price_set_value (price, value);
+    gnc_pricedb_add_price (xferData->pricedb, price);
+    gnc_price_commit_edit (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);
 }
 
diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c
index 119a459..aef5c6f 100644
--- a/src/register/ledger-core/split-register.c
+++ b/src/register/ledger-core/split-register.c
@@ -64,6 +64,7 @@ static QofLogModule log_module = GNC_MOD_LEDGER;
 static CursorClass copied_class = CURSOR_CLASS_NONE;
 static SCM copied_item = SCM_UNDEFINED;
 static GncGUID copied_leader_guid;
+static const int PRECISION = 1000000;
 
 
 /** static prototypes *****************************************************/
@@ -2078,9 +2079,31 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
                                            GNC_HOW_DENOM_REDUCE);
         }
     }
-
-    if (price && gnc_numeric_equal(value, price_value))
+    if (price)
+    {
+        if (gnc_numeric_equal(value, price_value))
+        {
+            gnc_price_unref (price);
+            return;
+        }
+        if (strcmp (gnc_price_get_source(price), PRICE_SOURCE_FQ) == 0)
+        {
+            gnc_price_unref(price);
+            return;
+        }
+        if (!gnc_numeric_eq(price_value, gnc_price_get_value(price)))
+            value = gnc_numeric_div (gnc_numeric_create(1, 1), value,
+                                           PRECISION, GNC_HOW_DENOM_REDUCE);
+
+        gnc_price_begin_edit (price);
+        gnc_price_set_time (price, ts);
+        gnc_price_set_source (price, PRICE_SOURCE_SPLIT_REG);
+        gnc_price_set_value (price, value);
+        gnc_price_commit_edit (price);
+        gnc_price_unref (price);
         return;
+    }
+
     price = gnc_price_create (book);
     gnc_price_begin_edit (price);
     gnc_price_set_commodity (price, comm);
@@ -2566,7 +2589,7 @@ gnc_split_register_config_cells (SplitRegister *reg)
     /* Use 6 decimal places for prices and "exchange rates"  */
     gnc_price_cell_set_fraction
     ((PriceCell *)
-     gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL), 1000000);
+     gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL), PRECISION);
 
     /* Initialize shares and share balance cells */
     gnc_price_cell_set_print_info

commit 0b03328143b030871dfeaa034d151c3667878753
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Aug 23 11:44:24 2015 +0100

    Check for an existing price before adding one in split_reg.
    
    To make the behavior the same as in xfer_dialog.

diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c
index fc4f587..119a459 100644
--- a/src/register/ledger-core/split-register.c
+++ b/src/register/ledger-core/split-register.c
@@ -2051,8 +2051,9 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
     gnc_commodity *comm = xaccAccountGetCommodity (account);
     gnc_commodity *curr = xaccTransGetCurrency (trans);
     GNCPrice *price;
+    gnc_numeric price_value;
     Timespec ts;
-    BasicCell *cell;
+    BasicCell *cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
 
     /* Only record the price for account types that don't have a
      * "rate" cell. They'll get handled later by
@@ -2060,8 +2061,26 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
      */
     if (gnc_split_reg_has_rate_cell (reg->type))
         return;
-    cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
     gnc_date_cell_get_date ((DateCell*)cell, &ts);
+    price = gnc_pricedb_lookup_day (pricedb, comm, curr, ts);
+    if (price)
+    {
+        price_value = gnc_price_get_value(price);
+    }
+    else
+    {
+        price = gnc_pricedb_lookup_day (pricedb, curr, comm, ts);
+        if (price)
+        {
+            price_value = gnc_numeric_div (gnc_numeric_create(1, 1),
+                                           gnc_price_get_value(price),
+                                           GNC_DENOM_AUTO,
+                                           GNC_HOW_DENOM_REDUCE);
+        }
+    }
+
+    if (price && gnc_numeric_equal(value, price_value))
+        return;
     price = gnc_price_create (book);
     gnc_price_begin_edit (price);
     gnc_price_set_commodity (price, comm);

commit c6a67f4eac5f7e95b9637c2c163260fff3f7cc53
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Aug 23 11:06:14 2015 +0100

    In the transfer dialog use the price_edit value for the saved price.
    
    Instead of computing it separately and differently from to_amt and from_amt.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 08e6ab0..ebc0097 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1523,16 +1523,7 @@ create_price(XferDialog *xferData, Timespec ts)
     if (gnc_is_euro_currency (from) && gnc_is_euro_currency (to))
         return;
 
-    from_amt =
-        gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->amount_edit));
-    to_amt =
-        gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->to_amount_edit));
-
-    /* compute the price -- maybe we need to swap? */
-    value = gnc_numeric_div(to_amt, from_amt, GNC_DENOM_AUTO,
-                            GNC_HOW_DENOM_REDUCE);
-    value = gnc_numeric_abs (value);
-
+    value = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->price_edit));
     /* Try to be consistent about how quotes are installed. */
     if (from == gnc_default_currency() ||
         ((to != gnc_default_currency()) &&
@@ -1557,20 +1548,7 @@ create_price(XferDialog *xferData, Timespec ts)
         }
     }
 
-    /* See if we found a good enough price */
-    if (price)
-    {
-        int scu = gnc_commodity_get_fraction (to);
-        if (!gnc_numeric_equal (gnc_numeric_mul (from_amt, price_value,
-                                                 scu, GNC_HOW_RND_ROUND_HALF_UP),
-                                to_amt))
-        {
-            gnc_price_unref (price);
-            price = NULL;
-        }
-    }
-
-    if (price)
+    if (price && gnc_numeric_equal(value, price_value))
     {
         PINFO("Found price for %s in %s", gnc_commodity_get_mnemonic(from),
               gnc_commodity_get_mnemonic(to));

commit 407d61cbb64d3232bc56e74dbb1e95eff9cf5ef8
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Aug 22 10:48:24 2015 +0100

    Fix up whitespace in dialog-transfer.c.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 3715c7b..08e6ab0 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -69,61 +69,60 @@ static QofLogModule log_module = GNC_MOD_GUI;
 
 struct _xferDialog
 {
-    GtkWidget * dialog;
-
-    GtkWidget * amount_edit;
-    GtkWidget * date_entry;
-    GtkWidget * num_entry;
-    GtkWidget * description_entry;
-    GtkWidget * memo_entry;
-    GtkWidget * conv_forward;
-    GtkWidget * conv_reverse;
-
-    GtkWidget *	from_window;
+    GtkWidget *dialog;
+    GtkWidget *amount_edit;
+    GtkWidget *date_entry;
+    GtkWidget *num_entry;
+    GtkWidget *description_entry;
+    GtkWidget *memo_entry;
+    GtkWidget *conv_forward;
+    GtkWidget *conv_reverse;
+
+    GtkWidget *from_window;
     GtkTreeView * from_tree_view;
-    gnc_commodity *	from_commodity;
-    GtkWidget *	to_window;
-    GtkTreeView * to_tree_view;
-    gnc_commodity *	to_commodity;
+    gnc_commodity *from_commodity;
+    GtkWidget *to_window;
+    GtkTreeView *to_tree_view;
+    gnc_commodity *to_commodity;
 
-    QuickFill * qf;     /* Quickfill on transfer descriptions,
-                         defaults to matching on the "From" account. */
+    QuickFill *qf;     /* Quickfill on transfer descriptions,
+                           defaults to matching on the "From" account. */
 
-    XferDirection quickfill;	/* direction match on the account instead. */
+    XferDirection quickfill;    /* direction match on the account instead. */
 
     /* stored data for the description quickfill selection function */
     gint desc_start_selection;
     gint desc_end_selection;
     guint desc_selection_source_id;
 
-    GtkWidget * transferinfo_label;
+    GtkWidget *transferinfo_label;
 
-    GtkWidget * from_transfer_label;
-    GtkWidget * to_transfer_label;
+    GtkWidget *from_transfer_label;
+    GtkWidget *to_transfer_label;
 
-    GtkWidget * from_currency_label;
-    GtkWidget * to_currency_label;
+    GtkWidget *from_currency_label;
+    GtkWidget *to_currency_label;
 
-    GtkWidget * from_show_button;
-    GtkWidget * to_show_button;
+    GtkWidget *from_show_button;
+    GtkWidget *to_show_button;
 
-    GtkWidget * curr_xfer_table;
+    GtkWidget *curr_xfer_table;
 
-    GtkWidget * price_edit;
-    GtkWidget * to_amount_edit;
+    GtkWidget *price_edit;
+    GtkWidget *to_amount_edit;
 
-    GtkWidget * price_radio;
-    GtkWidget * amount_radio;
+    GtkWidget *price_radio;
+    GtkWidget *amount_radio;
 
-    GtkWidget * fetch_button;
+    GtkWidget *fetch_button;
 
-    QofBook *	book;
-    GNCPriceDB *	pricedb;
+    QofBook *book;
+    GNCPriceDB *pricedb;
 
     /* Where to store the "exchange_rate" at exit (in lieu of
      * creating a transaction)
      */
-    gnc_numeric * exch_rate;
+    gnc_numeric *exch_rate;
 
     /* Callback function to notify of the newly created Transaction */
     gnc_xfer_dialog_cb transaction_cb;
@@ -157,10 +156,10 @@ static void gnc_xfer_update_to_amount (XferDialog *xferData);
 static void gnc_xfer_dialog_update_conv_info(XferDialog *xferData);
 
 static Account *gnc_transfer_dialog_get_selected_account (XferDialog *dialog,
-        XferDirection direction);
+                                                          XferDirection direction);
 static void gnc_transfer_dialog_set_selected_account (XferDialog *dialog,
-        Account *account,
-        XferDirection direction);
+                                                      Account *account,
+                                                      XferDirection direction);
 
 void gnc_xfer_description_insert_cb(GtkEditable *editable,
                                     const gchar *insert_text,
@@ -168,11 +167,11 @@ void gnc_xfer_description_insert_cb(GtkEditable *editable,
                                     gint *start_pos,
                                     XferDialog *xferData);
 gboolean gnc_xfer_description_key_press_cb( GtkEntry *entry,
-        GdkEventKey *event,
-        XferDialog *xferData );
+                                            GdkEventKey *event,
+                                            XferDialog *xferData );
 void gnc_xfer_dialog_fetch (GtkButton *button, XferDialog *xferData);
 gboolean gnc_xfer_dialog_inc_exp_filter_func (Account *account,
-        gpointer data);
+                                              gpointer data);
 void price_amount_radio_toggled_cb(GtkToggleButton *togglebutton, gpointer data);
 
 void gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data);
@@ -231,14 +230,14 @@ gnc_xfer_dialog_update_price (XferDialog *xferData)
     {
         /* 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);
+                                                  to, date);
         reverse = FALSE;
     }
 
     if (!prc)
     {
         prc = gnc_pricedb_lookup_nearest_in_time (xferData->pricedb, to,
-                from, date);
+                                                  from, date);
         reverse = TRUE;
     }
 
@@ -328,7 +327,7 @@ gnc_xfer_dialog_set_price_auto (XferDialog *xferData,
     }
 
     if (!gnc_is_euro_currency (from_currency) ||
-            !gnc_is_euro_currency (to_currency))
+        !gnc_is_euro_currency (to_currency))
     {
         gnc_xfer_dialog_update_price (xferData);
         return;
@@ -363,8 +362,8 @@ gnc_xfer_dialog_curr_acct_activate(XferDialog *xferData)
 
     curr_active = (xferData->exch_rate ||
                    ((from_account != NULL) && (to_account != NULL)))
-                  && !gnc_commodity_equiv(xferData->from_commodity,
-                                          xferData->to_commodity);
+        && !gnc_commodity_equiv(xferData->from_commodity,
+                                xferData->to_commodity);
 
     gtk_widget_set_sensitive(xferData->curr_xfer_table, curr_active);
     gtk_widget_set_sensitive(xferData->price_edit,
@@ -441,7 +440,7 @@ gnc_xfer_dialog_reload_quickfill( XferDialog *xferData )
 
 static void
 gnc_xfer_dialog_from_tree_selection_changed_cb (GtkTreeSelection *selection,
-        gpointer data)
+                                                gpointer data)
 {
     XferDialog *xferData = data;
     GNCPrintAmountInfo print_info;
@@ -541,7 +540,7 @@ gnc_xfer_dialog_fill_tree_view(XferDialog *xferData,
 
     g_return_if_fail (xferData != NULL);
     use_accounting_labels = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL,
-                            GNC_PREF_ACCOUNTING_LABELS);
+                                               GNC_PREF_ACCOUNTING_LABELS);
 
     /* In "normal" mode (non accounting terms) the account where the
      * money comes from is displayed on the left side and the account
@@ -557,20 +556,20 @@ gnc_xfer_dialog_fill_tree_view(XferDialog *xferData,
     if (use_accounting_labels)
     {
         button = GTK_WIDGET(gtk_builder_get_object (builder,
-                            (direction == XFER_DIALOG_TO) ?
-                            "left_show_button" : "right_show_button"));
+                                                    (direction == XFER_DIALOG_TO) ?
+                                                    "left_show_button" : "right_show_button"));
         scroll_win = GTK_WIDGET(gtk_builder_get_object (builder,
-                                (direction == XFER_DIALOG_TO) ?
-                                "left_trans_window" : "right_trans_window"));
+                                                        (direction == XFER_DIALOG_TO) ?
+                                                        "left_trans_window" : "right_trans_window"));
     }
     else
     {
         button = GTK_WIDGET(gtk_builder_get_object (builder,
-                            (direction == XFER_DIALOG_TO) ?
-                            "right_show_button" : "left_show_button"));
+                                                    (direction == XFER_DIALOG_TO) ?
+                                                    "right_show_button" : "left_show_button"));
         scroll_win = GTK_WIDGET(gtk_builder_get_object (builder,
-                                (direction == XFER_DIALOG_TO) ?
-                                "right_trans_window" : "left_trans_window"));
+                                                        (direction == XFER_DIALOG_TO) ?
+                                                        "right_trans_window" : "left_trans_window"));
     }
 
 
@@ -686,7 +685,7 @@ gnc_xfer_dialog_quickfill( XferDialog *xferData )
      */
 
     if ( gnc_numeric_zero_p(
-                gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->amount_edit))))
+             gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->amount_edit))))
     {
         gnc_numeric amt;
         DEBUG("updating amount");
@@ -718,7 +717,7 @@ gnc_xfer_dialog_quickfill( XferDialog *xferData )
      * and select that account in the appropriate account tree.
      */
     if ( ( other = xaccSplitGetOtherSplit( split ) ) &&
-            ( other_acct = xaccSplitGetAccount( other ) ) )
+         ( other_acct = xaccSplitGetAccount( other ) ) )
     {
         GNCAccountType other_type;
         GtkWidget *other_button;
@@ -804,8 +803,8 @@ gnc_xfer_description_insert_cb(GtkEditable *editable,
     g_free(prefix);
 
     if ((match = gnc_quickfill_get_string_match(xferData->qf, new_text))
-            && (match_str = gnc_quickfill_string(match))
-            && ((match_str_len = strlen(match_str)) > new_text_len))
+        && (match_str = gnc_quickfill_string(match))
+        && ((match_str_len = strlen(match_str)) > new_text_len))
     {
         g_signal_handlers_block_matched (G_OBJECT (editable),
                                          G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, xferData);
@@ -829,7 +828,7 @@ gnc_xfer_description_insert_cb(GtkEditable *editable,
         xferData->desc_start_selection = *start_pos;
         xferData->desc_end_selection = -1;
         xferData->desc_selection_source_id = g_idle_add(idle_select_region,
-                                             xferData);
+                                                        xferData);
     }
     g_free(new_text);
 }
@@ -848,25 +847,25 @@ gnc_xfer_description_key_press_cb( GtkEntry *entry,
     ENTER(" ");
     switch ( event->keyval )
     {
-    case GDK_Return:
-    case GDK_KP_Enter:
-        gnc_xfer_dialog_quickfill( xferData );
-        /* NOT done with input, activate the default button of the dialog. */
-        break;
-
-    case GDK_Tab:
-    case GDK_ISO_Left_Tab:
-        if ( !( event->state & GDK_SHIFT_MASK) )    /* Complete on Tab,
-                                                  * but not Shift-Tab */
-        {
+        case GDK_Return:
+        case GDK_KP_Enter:
             gnc_xfer_dialog_quickfill( xferData );
-            /* NOT done with input, though, since we need to focus to the next
-             * field.  Unselect the current field, though.
-             */
-            gtk_editable_select_region( GTK_EDITABLE(xferData->description_entry),
-                                        0, 0 );
-        }
-        break;
+            /* NOT done with input, activate the default button of the dialog. */
+            break;
+
+        case GDK_Tab:
+        case GDK_ISO_Left_Tab:
+            if ( !( event->state & GDK_SHIFT_MASK) )    /* Complete on Tab,
+                                                         * but not Shift-Tab */
+            {
+                gnc_xfer_dialog_quickfill( xferData );
+                /* NOT done with input, though, since we need to focus to the next
+                 * field.  Unselect the current field, though.
+                 */
+                gtk_editable_select_region( GTK_EDITABLE(xferData->description_entry),
+                                            0, 0 );
+            }
+            break;
     }
 
     LEAVE("done=%d", done_with_input);
@@ -954,7 +953,7 @@ gnc_xfer_update_to_amount (XferDialog *xferData)
     account = gnc_transfer_dialog_get_selected_account(xferData, XFER_DIALOG_TO);
     if (account == NULL)
         account = gnc_transfer_dialog_get_selected_account(xferData,
-                  XFER_DIALOG_FROM);
+                                                           XFER_DIALOG_FROM);
     if (account != NULL)
         scu = xaccAccountGetCommoditySCU(account);
     else if (xferData->to_commodity != NULL)
@@ -962,7 +961,7 @@ gnc_xfer_update_to_amount (XferDialog *xferData)
 
     /* Determine the amount to transfer. */
     if (!gnc_amount_edit_evaluate(price_edit) ||
-            gnc_numeric_zero_p(price = gnc_amount_edit_get_amount(price_edit)))
+        gnc_numeric_zero_p(price = gnc_amount_edit_get_amount(price_edit)))
         to_amount = gnc_numeric_zero();
     else
         to_amount = gnc_numeric_mul(gnc_amount_edit_get_amount(amount_edit),
@@ -1099,18 +1098,18 @@ gnc_xfer_dialog_lock_account_tree(XferDialog *xferData,
 
     switch (direction)
     {
-    case XFER_DIALOG_FROM:
-        tree_view = xferData->from_tree_view;
-        scroll_win = xferData->from_window;
-        show_button = xferData->from_show_button;
-        break;
-    case XFER_DIALOG_TO:
-        tree_view = xferData->to_tree_view;
-        scroll_win = xferData->to_window;
-        show_button = xferData->to_show_button;
-        break;
-    default:
-        return;
+        case XFER_DIALOG_FROM:
+            tree_view = xferData->from_tree_view;
+            scroll_win = xferData->from_window;
+            show_button = xferData->from_show_button;
+            break;
+        case XFER_DIALOG_TO:
+            tree_view = xferData->to_tree_view;
+            scroll_win = xferData->to_window;
+            show_button = xferData->to_show_button;
+            break;
+        default:
+            return;
     }
 
     gtk_widget_set_sensitive( GTK_WIDGET(tree_view), FALSE );
@@ -1199,7 +1198,7 @@ gnc_xfer_dialog_is_exchange_dialog (XferDialog *xferData,
     g_return_if_fail(xferData);
     ENTER("xferData=%p, exch_rate=%p (%s)", xferData, exch_rate,
           exch_rate == NULL ? "NULL" : xaccPrintAmount(*exch_rate,
-                  gnc_default_print_info(FALSE)));
+                                                       gnc_default_print_info(FALSE)));
 
     gtk_widget_set_sensitive (xferData->amount_edit, FALSE);
     gtk_widget_set_sensitive (xferData->date_entry, FALSE);
@@ -1233,15 +1232,15 @@ gnc_xfer_dialog_set_amount(XferDialog *xferData, gnc_numeric amount)
         return;
 
     account = gnc_transfer_dialog_get_selected_account (xferData,
-              XFER_DIALOG_FROM);
+                                                        XFER_DIALOG_FROM);
     if (account == NULL)
         account = gnc_transfer_dialog_get_selected_account (xferData,
-                  XFER_DIALOG_TO);
+                                                            XFER_DIALOG_TO);
 
     gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (xferData->amount_edit), amount);
 }
 void gnc_xfer_dialog_set_amount_sensitive(XferDialog *xferData,
-        gboolean is_sensitive)
+                                          gboolean is_sensitive)
 {
     g_assert(xferData);
     gtk_widget_set_sensitive(gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT (xferData->amount_edit)), is_sensitive);
@@ -1252,9 +1251,9 @@ gnc_xfer_dialog_set_fetch_sensitive (GtkWidget *fetch)
 {
     if (gnc_quote_source_fq_installed ())
     {
-	gtk_widget_set_sensitive (fetch, TRUE);
-	gtk_widget_set_tooltip_text (fetch, _("Retrieve the current online quote"));
-	return;
+        gtk_widget_set_sensitive (fetch, TRUE);
+        gtk_widget_set_tooltip_text (fetch, _("Retrieve the current online quote"));
+        return;
     }
     gtk_widget_set_sensitive (fetch, FALSE);
     gtk_widget_set_tooltip_text (fetch, _("Finance::Quote must be installed to enable this button."));
@@ -1508,7 +1507,7 @@ swap_amount (gnc_commodity *from, gnc_commodity *to, gnc_numeric *value,
     from_amt = to_amt;
     to_amt = tmp_amt;
     *value = gnc_numeric_div (gnc_numeric_create(1, 1), *value,
-                             GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+                              GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
 }
 static void
 create_price(XferDialog *xferData, Timespec ts)
@@ -1808,7 +1807,7 @@ gnc_xfer_dialog_create(GtkWidget *parent, XferDialog *xferData)
     gboolean  use_accounting_labels;
 
     use_accounting_labels = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL,
-                            GNC_PREF_ACCOUNTING_LABELS);
+                                               GNC_PREF_ACCOUNTING_LABELS);
 
     ENTER(" ");
     builder = gtk_builder_new();
@@ -2129,7 +2128,7 @@ gnc_xfer_dialog_set_to_account_label( XferDialog *xferData,
 
 void
 gnc_xfer_dialog_set_from_show_button_active( XferDialog *xferData,
-        gboolean set_value )
+                                             gboolean set_value )
 {
     if ( xferData && xferData->from_show_button )
     {
@@ -2140,7 +2139,7 @@ gnc_xfer_dialog_set_from_show_button_active( XferDialog *xferData,
 
 void
 gnc_xfer_dialog_set_to_show_button_active( XferDialog *xferData,
-        gboolean set_value )
+                                           gboolean set_value )
 {
     if ( xferData && xferData->to_show_button )
     {
@@ -2151,16 +2150,16 @@ gnc_xfer_dialog_set_to_show_button_active( XferDialog *xferData,
 
 /* Add a button with a user-specified label and "clicked" callback */
 void gnc_xfer_dialog_add_user_specified_button( XferDialog *xferData,
-        const gchar *label,
-        GCallback callback,
-        gpointer user_data )
+                                                const gchar *label,
+                                                GCallback callback,
+                                                gpointer user_data )
 {
     if ( xferData && label && callback )
     {
         GtkBuilder *builder = g_object_get_data (G_OBJECT (xferData->dialog), "builder");
         GtkWidget *button   = gtk_button_new_with_label( label );
         GtkWidget *box      = GTK_WIDGET(gtk_builder_get_object (builder,
-                                         "transfermain-vbox" ));
+                                                                 "transfermain-vbox" ));
         gtk_box_pack_end( GTK_BOX(box), button, FALSE, FALSE, 0 );
         g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (callback), user_data);
         gtk_widget_show( button );
@@ -2168,7 +2167,7 @@ void gnc_xfer_dialog_add_user_specified_button( XferDialog *xferData,
 }
 
 void gnc_xfer_dialog_toggle_currency_table( XferDialog *xferData,
-        gboolean show_table )
+                                            gboolean show_table )
 {
     if (xferData && xferData->curr_xfer_table)
     {
@@ -2211,8 +2210,8 @@ gboolean gnc_xfer_dialog_run_until_done( XferDialog *xferData )
      * that's bad mojo whole gtk_dialog_run is still in control.
      */
     count = g_signal_handlers_disconnect_by_func(dialog,
-            gnc_xfer_dialog_response_cb,
-            xferData);
+                                                 gnc_xfer_dialog_response_cb,
+                                                 xferData);
     g_assert(count == 1);
 
     while ( TRUE )
@@ -2269,22 +2268,22 @@ gnc_xfer_dialog_quickfill_to_account(XferDialog *xferData,
 
 static Account *
 gnc_transfer_dialog_get_selected_account (XferDialog *dialog,
-        XferDirection direction)
+                                          XferDirection direction)
 {
     GtkTreeView *tree_view;
     Account *account;
 
     switch (direction)
     {
-    case XFER_DIALOG_FROM:
-        tree_view = dialog->from_tree_view;
-        break;
-    case XFER_DIALOG_TO:
-        tree_view = dialog->to_tree_view;
-        break;
-    default:
-        g_assert_not_reached ();
-        return NULL;
+        case XFER_DIALOG_FROM:
+            tree_view = dialog->from_tree_view;
+            break;
+        case XFER_DIALOG_TO:
+            tree_view = dialog->to_tree_view;
+            break;
+        default:
+            g_assert_not_reached ();
+            return NULL;
     }
 
     account = gnc_tree_view_account_get_selected_account  (GNC_TREE_VIEW_ACCOUNT (tree_view));
@@ -2293,8 +2292,8 @@ gnc_transfer_dialog_get_selected_account (XferDialog *dialog,
 
 static void
 gnc_transfer_dialog_set_selected_account (XferDialog *dialog,
-        Account *account,
-        XferDirection direction)
+                                          Account *account,
+                                          XferDirection direction)
 {
     GtkTreeView *tree_view;
     GtkCheckButton *show_button;
@@ -2305,17 +2304,17 @@ gnc_transfer_dialog_set_selected_account (XferDialog *dialog,
 
     switch (direction)
     {
-    case XFER_DIALOG_FROM:
-        tree_view = dialog->from_tree_view;
-        show_button = GTK_CHECK_BUTTON (dialog->from_show_button);
-        break;
-    case XFER_DIALOG_TO:
-        tree_view = dialog->to_tree_view;
-        show_button = GTK_CHECK_BUTTON (dialog->to_show_button);
-        break;
-    default:
-        g_assert_not_reached ();
-        return;
+        case XFER_DIALOG_FROM:
+            tree_view = dialog->from_tree_view;
+            show_button = GTK_CHECK_BUTTON (dialog->from_show_button);
+            break;
+        case XFER_DIALOG_TO:
+            tree_view = dialog->to_tree_view;
+            show_button = GTK_CHECK_BUTTON (dialog->to_show_button);
+            break;
+        default:
+            g_assert_not_reached ();
+            return;
     }
 
     type = xaccAccountGetType (account);
@@ -2324,7 +2323,7 @@ gnc_transfer_dialog_set_selected_account (XferDialog *dialog,
                                   (type == ACCT_TYPE_INCOME));
 
     gnc_tree_view_account_set_selected_account (GNC_TREE_VIEW_ACCOUNT (tree_view),
-            account);
+                                                account);
 }
 
 
@@ -2398,8 +2397,8 @@ gboolean gnc_xfer_dialog_run_exchange_dialog(
 
         /* XXX: should we tell the user we've done the conversion? */
         amount = gnc_numeric_div(
-                     amount, rate,
-                     gnc_commodity_get_fraction(txn_cur), GNC_HOW_DENOM_REDUCE);
+            amount, rate,
+            gnc_commodity_get_fraction(txn_cur), GNC_HOW_DENOM_REDUCE);
     }
 
     /* enter the accounts */

commit 47f91c022761a0f2d7c27caed0d3ab0cf81263d9
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Aug 22 10:44:00 2015 +0100

    Refactor gnc_xfer_dialog_response_cb with several extract-functions.

diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index 9a6215f..3715c7b 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1353,24 +1353,256 @@ gnc_xfer_dialog_set_exchange_rate(XferDialog *xferData, gnc_numeric exchange_rat
     gnc_xfer_update_to_amount (xferData);
 }
 
+static gboolean
+check_accounts  (XferDialog* xferData, Account* from_account,
+                 Account* to_account)
+{
+    if ((from_account == NULL) || (to_account == NULL))
+    {
+        const char *message = _("You must specify an account to transfer from, "
+                                "or to, or both, for this transaction. "
+                                "Otherwise, it will not be recorded.");
+        gnc_error_dialog(xferData->dialog, "%s", message);
+        LEAVE("bad account");
+        return TRUE;
+    }
+
+    if (from_account == to_account)
+    {
+        const char *message = _("You can't transfer from and to the same "
+                                "account!");
+        gnc_error_dialog(xferData->dialog, "%s", message);
+        LEAVE("same account");
+        return TRUE;
+    }
+
+    if (xaccAccountGetPlaceholder(from_account) ||
+        xaccAccountGetPlaceholder(to_account))
+    {
+        const char *placeholder_format =
+            _("The account %s does not allow transactions.");
+        char *name;
+
+        if (xaccAccountGetPlaceholder(from_account))
+            name = gnc_account_get_full_name(from_account);
+        else
+            name = gnc_account_get_full_name(to_account);
+        gnc_error_dialog(xferData->dialog, placeholder_format, name);
+        g_free(name);
+        LEAVE("placeholder");
+        return TRUE;
+    }
+
+    if (!gnc_commodity_is_iso (xferData->from_commodity))
+    {
+        const char *message =
+            _("You can't transfer from a non-currency account. "
+              "Try reversing the \"from\" and \"to\" accounts "
+              "and making the \"amount\" negative.");
+        gnc_error_dialog(xferData->dialog, "%s", message);
+        LEAVE("non-currency");
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static gboolean
+check_edit(XferDialog *xferData)
+{        if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->price_edit)))
+    {
+        if (gtk_toggle_button_get_active
+            (GTK_TOGGLE_BUTTON(xferData->price_radio)))
+        {
+            gnc_parse_error_dialog (xferData, _("You must enter a valid price."));
+            LEAVE("invalid price");
+            return TRUE;
+        }
+    }
+
+    if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->to_amount_edit)))
+    {
+        if (gtk_toggle_button_get_active
+            (GTK_TOGGLE_BUTTON(xferData->amount_radio)))
+        {
+            gnc_parse_error_dialog (xferData,
+                                    _("You must enter a valid `to' amount."));
+            LEAVE("invalid to amount");
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static void
+create_transaction(XferDialog *xferData, Timespec *ts,
+                   Account *from_account, Account* to_account,
+                   gnc_numeric amount, gnc_numeric to_amount)
+{
+    Transaction *trans;
+    Split *from_split;
+    Split *to_split;
+    const char *string;
+    /* Create the transaction */
+    trans = xaccMallocTransaction(xferData->book);
+
+    xaccTransBeginEdit(trans);
+
+    xaccTransSetCurrency(trans, xferData->from_commodity);
+    xaccTransSetDatePostedTS(trans, ts);
+
+    /* Trans-Num or Split-Action set with gnc_set_num_action below per book
+     * option */
+
+    string = gtk_entry_get_text(GTK_ENTRY(xferData->description_entry));
+    xaccTransSetDescription(trans, string);
+
+    /* create from split */
+    from_split = xaccMallocSplit(xferData->book);
+    xaccTransAppendSplit(trans, from_split);
+
+    /* create to split */
+    to_split = xaccMallocSplit(xferData->book);
+    xaccTransAppendSplit(trans, to_split);
+
+    xaccAccountBeginEdit(from_account);
+    xaccAccountInsertSplit(from_account, from_split);
+
+    xaccAccountBeginEdit(to_account);
+    xaccAccountInsertSplit(to_account, to_split);
+
+    xaccSplitSetBaseValue(from_split, gnc_numeric_neg (amount),
+                          xferData->from_commodity);
+    xaccSplitSetBaseValue(to_split, amount, xferData->from_commodity);
+    xaccSplitSetBaseValue(to_split, to_amount, xferData->to_commodity);
+
+    /* Set the transaction number or split action field based on book option*/
+    string = gtk_entry_get_text(GTK_ENTRY(xferData->num_entry));
+    gnc_set_num_action (trans, from_split, string, NULL);
+
+    /* Set the memo fields */
+    string = gtk_entry_get_text(GTK_ENTRY(xferData->memo_entry));
+    xaccSplitSetMemo(from_split, string);
+    xaccSplitSetMemo(to_split, string);
+
+    /* finish transaction */
+    xaccTransCommitEdit(trans);
+    xaccAccountCommitEdit(from_account);
+    xaccAccountCommitEdit(to_account);
+
+    /* If there is a registered callback handler that should be
+       notified of the newly created Transaction, call it now. */
+    if (xferData->transaction_cb)
+        xferData->transaction_cb(trans, xferData->transaction_user_data);
+}
+
+static void
+swap_amount (gnc_commodity *from, gnc_commodity *to, gnc_numeric *value,
+             gnc_numeric *from_amt, gnc_numeric *to_amt)
+{
+    gnc_commodity *tmp;
+    gnc_numeric *tmp_amt;
+    tmp = from;
+    from = to;
+    to = tmp;
+    tmp_amt = from_amt;
+    from_amt = to_amt;
+    to_amt = tmp_amt;
+    *value = gnc_numeric_div (gnc_numeric_create(1, 1), *value,
+                             GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
+}
+static void
+create_price(XferDialog *xferData, Timespec ts)
+{
+    gnc_commodity *from = xferData->from_commodity;
+    gnc_commodity *to = xferData->to_commodity;
+    GNCPrice *price;
+    gnc_numeric price_value;
+    gnc_numeric value;
+    gnc_numeric from_amt, to_amt;
+
+/* Bail in the unlikely event that both currencies have joined the Euro. */
+    if (gnc_is_euro_currency (from) && gnc_is_euro_currency (to))
+        return;
+
+    from_amt =
+        gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->amount_edit));
+    to_amt =
+        gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->to_amount_edit));
+
+    /* compute the price -- maybe we need to swap? */
+    value = gnc_numeric_div(to_amt, from_amt, GNC_DENOM_AUTO,
+                            GNC_HOW_DENOM_REDUCE);
+    value = gnc_numeric_abs (value);
+
+    /* Try to be consistent about how quotes are installed. */
+    if (from == gnc_default_currency() ||
+        ((to != gnc_default_currency()) &&
+         (strcmp (gnc_commodity_get_mnemonic(from),
+                  gnc_commodity_get_mnemonic(to)) < 0)))
+        swap_amount (from, to, &value, &from_amt, &to_amt);
+    /* 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)
+    {
+        price_value = gnc_price_get_value(price);
+    }
+    else
+    {
+        price = gnc_pricedb_lookup_day (xferData->pricedb, to, from, ts);
+        if (price)
+        {
+            price_value = gnc_numeric_div (gnc_numeric_create(1, 1),
+                                           gnc_price_get_value(price),
+                                           GNC_DENOM_AUTO,
+                                           GNC_HOW_DENOM_REDUCE);
+        }
+    }
+
+    /* See if we found a good enough price */
+    if (price)
+    {
+        int scu = gnc_commodity_get_fraction (to);
+        if (!gnc_numeric_equal (gnc_numeric_mul (from_amt, price_value,
+                                                 scu, GNC_HOW_RND_ROUND_HALF_UP),
+                                to_amt))
+        {
+            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));
+    }
+    else
+    {
+        price = gnc_price_create (xferData->book);
+        gnc_price_begin_edit (price);
+        gnc_price_set_commodity (price, from);
+        gnc_price_set_currency (price, to);
+        gnc_price_set_time (price, ts);
+        gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
+        gnc_price_set_value (price, value);
+        gnc_pricedb_add_price (xferData->pricedb, price);
+        gnc_price_commit_edit (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);
+}
+
 void
 gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
 {
     XferDialog *xferData = data;
     Account *to_account;
     Account *from_account;
-    gnc_commodity *from_commodity;
-    gnc_commodity *to_commodity;
     gnc_numeric amount, to_amount;
-    const char *string;
     Timespec ts;
 
-    gboolean curr_trans;
-
-    Transaction *trans;
-    Split *from_split;
-    Split *to_split;
-
     g_return_if_fail (xferData != NULL);
     ENTER(" ");
 
@@ -1390,54 +1622,9 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
     from_account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_FROM);
     to_account = gnc_transfer_dialog_get_selected_account (xferData, XFER_DIALOG_TO);
 
-    if (xferData->exch_rate == NULL)
-    {
-        if ((from_account == NULL) || (to_account == NULL))
-        {
-            const char *message = _("You must specify an account to transfer from, "
-                                    "or to, or both, for this transaction. "
-                                    "Otherwise, it will not be recorded.");
-            gnc_error_dialog(xferData->dialog, "%s", message);
-            LEAVE("bad account");
-            return;
-        }
-
-        if (from_account == to_account)
-        {
-            const char *message = _("You can't transfer from and to the same "
-                                    "account!");
-            gnc_error_dialog(xferData->dialog, "%s", message);
-            LEAVE("same account");
-            return;
-        }
-
-        if (xaccAccountGetPlaceholder(from_account) ||
-                xaccAccountGetPlaceholder(to_account))
-        {
-            const char *placeholder_format =
-                _("The account %s does not allow transactions.");
-            char *name;
-
-            if (xaccAccountGetPlaceholder(from_account))
-                name = gnc_account_get_full_name(from_account);
-            else
-                name = gnc_account_get_full_name(to_account);
-            gnc_error_dialog(xferData->dialog, placeholder_format, name);
-            g_free(name);
-            LEAVE("placeholder");
-            return;
-        }
-
-        if (!gnc_commodity_is_iso (xferData->from_commodity))
-        {
-            const char *message = _("You can't transfer from a non-currency account. "
-                                    "Try reversing the \"from\" and \"to\" accounts "
-                                    "and making the \"amount\" negative.");
-            gnc_error_dialog(xferData->dialog, "%s", message);
-            LEAVE("non-currency");
-            return;
-        }
-    }
+    if (xferData->exch_rate == NULL &&
+        check_accounts(xferData, from_account, to_account))
+        return;
 
     if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->amount_edit)))
     {
@@ -1446,11 +1633,6 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
         return;
     }
 
-    from_commodity = xferData->from_commodity;
-    to_commodity = xferData->to_commodity;
-
-    curr_trans = !gnc_commodity_equiv(from_commodity, to_commodity);
-
     amount = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->amount_edit));
 
     if (gnc_numeric_zero_p (amount))
@@ -1463,33 +1645,12 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
 
     ts = gnc_date_edit_get_date_ts(GNC_DATE_EDIT(xferData->date_entry));
 
-    if (curr_trans)
+    if (!gnc_commodity_equiv(xferData->from_commodity, xferData->to_commodity))
     {
-        if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->price_edit)))
-        {
-            if (gtk_toggle_button_get_active
-                    (GTK_TOGGLE_BUTTON(xferData->price_radio)))
-            {
-                gnc_parse_error_dialog (xferData, _("You must enter a valid price."));
-                LEAVE("invalid price");
-                return;
-            }
-        }
-
-        if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->to_amount_edit)))
-        {
-            if (gtk_toggle_button_get_active
-                    (GTK_TOGGLE_BUTTON(xferData->amount_radio)))
-            {
-                gnc_parse_error_dialog (xferData,
-                                        _("You must enter a valid `to' amount."));
-                LEAVE("invalid to amount");
-                return;
-            }
-        }
-
+        if (check_edit(xferData))
+            return;
         to_amount = gnc_amount_edit_get_amount
-                    (GNC_AMOUNT_EDIT(xferData->to_amount_edit));
+            (GNC_AMOUNT_EDIT(xferData->to_amount_edit));
     }
     else
         to_amount = amount;
@@ -1510,156 +1671,12 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
         *(xferData->exch_rate) = gnc_numeric_abs(price);
     }
     else
-    {
-        /* Create the transaction */
-        trans = xaccMallocTransaction(xferData->book);
-
-        xaccTransBeginEdit(trans);
-
-        xaccTransSetCurrency(trans, from_commodity);
-        xaccTransSetDatePostedTS(trans, &ts);
-
-        /* Trans-Num or Split-Action set with gnc_set_num_action below per book
-         * option */
-
-        string = gtk_entry_get_text(GTK_ENTRY(xferData->description_entry));
-        xaccTransSetDescription(trans, string);
-
-        /* create from split */
-        from_split = xaccMallocSplit(xferData->book);
-        xaccTransAppendSplit(trans, from_split);
-
-        /* create to split */
-        to_split = xaccMallocSplit(xferData->book);
-        xaccTransAppendSplit(trans, to_split);
-
-        xaccAccountBeginEdit(from_account);
-        xaccAccountInsertSplit(from_account, from_split);
-
-        xaccAccountBeginEdit(to_account);
-        xaccAccountInsertSplit(to_account, to_split);
-
-        xaccSplitSetBaseValue(from_split, gnc_numeric_neg (amount), from_commodity);
-        xaccSplitSetBaseValue(to_split, amount, from_commodity);
-        xaccSplitSetBaseValue(to_split, to_amount, to_commodity);
-
-        /* Set the transaction number or split action field based on book option*/
-        string = gtk_entry_get_text(GTK_ENTRY(xferData->num_entry));
-        gnc_set_num_action (trans, from_split, string, NULL);
-
-        /* Set the memo fields */
-        string = gtk_entry_get_text(GTK_ENTRY(xferData->memo_entry));
-        xaccSplitSetMemo(from_split, string);
-        xaccSplitSetMemo(to_split, string);
-
-        /* finish transaction */
-        xaccTransCommitEdit(trans);
-        xaccAccountCommitEdit(from_account);
-        xaccAccountCommitEdit(to_account);
-
-        /* If there is a registered callback handler that should be
-           notified of the newly created Transaction, call it now. */
-        if (xferData->transaction_cb)
-            xferData->transaction_cb(trans, xferData->transaction_user_data);
-    }
-
+        create_transaction (xferData, &ts, from_account, to_account,
+                            amount, to_amount);
     /* try to save this to the pricedb */
-    if (xferData->pricedb)
-    {
-        gnc_commodity *from = xferData->from_commodity;
-        gnc_commodity *to = xferData->to_commodity;
-
-        /* only continue if the currencies are DIFFERENT and are
-         * not both euroland currencies
-         */
-        if (!gnc_commodity_equal (from, to) &&
-                !(gnc_is_euro_currency (from) && gnc_is_euro_currency (to)))
-        {
-            GNCPrice *price;
-            gnc_numeric price_value;
-            gnc_numeric value;
-            gnc_commodity *tmp;
-            gnc_numeric from_amt, to_amt;
-            gnc_numeric tmp_amt;
-
-            from_amt = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->amount_edit));
-            to_amt = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->to_amount_edit));
-
-            /* compute the price -- maybe we need to swap? */
-
-            value = gnc_numeric_div(to_amt, from_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
-            value = gnc_numeric_abs (value);
-
-            /* Try to be consistent about how quotes are installed. */
-            if (from == gnc_default_currency() ||
-                    ((to != gnc_default_currency()) &&
-                     (strcmp (gnc_commodity_get_mnemonic(from),
-                              gnc_commodity_get_mnemonic(to)) < 0)))
-            {
-                tmp = from;
-                from = to;
-                to = tmp;
-                tmp_amt = from_amt;
-                from_amt = to_amt;
-                to_amt = tmp_amt;
-                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)
-            {
-                price_value = gnc_price_get_value(price);
-            }
-            else
-            {
-                price = gnc_pricedb_lookup_day (xferData->pricedb, to, from, ts);
-                if (price)
-                {
-                    price_value = gnc_numeric_div (gnc_numeric_create(1, 1),
-                                                   gnc_price_get_value(price),
-                                                   GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
-                }
-            }
-
-            /* See if we found a good enough price */
-            if (price)
-            {
-                int scu = gnc_commodity_get_fraction (to);
-                if (!gnc_numeric_equal (gnc_numeric_mul (from_amt, price_value,
-                                        scu, GNC_HOW_RND_ROUND_HALF_UP),
-                                        to_amt))
-                {
-                    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));
-            }
-            else
-            {
-                price = gnc_price_create (xferData->book);
-                gnc_price_begin_edit (price);
-                gnc_price_set_commodity (price, from);
-                gnc_price_set_currency (price, to);
-                gnc_price_set_time (price, ts);
-                gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
-                gnc_price_set_value (price, value);
-                gnc_pricedb_add_price (xferData->pricedb, price);
-                gnc_price_commit_edit (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);
-        }
-    }
-
+    if (xferData->pricedb && !gnc_commodity_equal (xferData->from_commodity,
+                                                   xferData->to_commodity))
+        create_price(xferData, ts);
     /* Refresh everything */
     gnc_resume_gui_refresh ();
 

commit e1b4e45de5f3ab357b17c135ee1881d99dbc8373
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Aug 22 09:17:49 2015 +0100

    Don't store prices of source invoice.
    
    They're intended to be temporary, for creating splits. They're also already
    stored from the transfer dialog.

diff --git a/src/backend/sql/gnc-price-sql.c b/src/backend/sql/gnc-price-sql.c
index d7e6b70..8729c91 100644
--- a/src/backend/sql/gnc-price-sql.c
+++ b/src/backend/sql/gnc-price-sql.c
@@ -203,7 +203,7 @@ write_price( GNCPrice* p, gpointer data )
     g_return_val_if_fail( p != NULL, FALSE );
     g_return_val_if_fail( data != NULL, FALSE );
 
-    if ( s->is_ok )
+    if ( s->is_ok && strcmp(gnc_price_get_source(p), PRICE_SOURCE_INVOICE) != 0)
     {
         s->is_ok = save_price( s->be, QOF_INSTANCE(p) );
     }

commit 9a611a2aca597be3aa95812f105e4d9b5d13e6ec
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Aug 21 15:54:58 2015 +0100

    Replace the price source and type strings with defines.

diff --git a/src/business/business-gnome/dialog-invoice.c b/src/business/business-gnome/dialog-invoice.c
index e840742..10c4d75 100644
--- a/src/business/business-gnome/dialog-invoice.c
+++ b/src/business/business-gnome/dialog-invoice.c
@@ -901,11 +901,8 @@ gnc_invoice_post(InvoiceWindow *iw, struct post_invoice_params *post_params)
             gnc_price_set_commodity (convprice, account_currency);
             gnc_price_set_currency (convprice, gncInvoiceGetCurrency (invoice));
             gnc_price_set_time (convprice, postdate);
-            gnc_price_set_source (convprice, "user:invoice-post");
-
-            /* Yes, magic strings are evil but I can't find any defined constants
-               for this..*/
-            gnc_price_set_typestr (convprice, "last");
+            gnc_price_set_source (convprice, PRICE_SOURCE_INVOICE);
+            gnc_price_set_typestr (convprice, PRICE_TYPE_LAST);
             gnc_price_set_value (convprice, exch_rate);
             gncInvoiceAddPrice(invoice, convprice);
             gnc_price_commit_edit (convprice);
@@ -1702,7 +1699,7 @@ gnc_invoice_update_window (InvoiceWindow *iw, GtkWidget *widget)
     }
 
     /* Set the type label */
-    gtk_label_set_text (GTK_LABEL(iw->type_label), iw->is_credit_note ? _("Credit Note") 
+    gtk_label_set_text (GTK_LABEL(iw->type_label), iw->is_credit_note ? _("Credit Note")
                         : gtk_label_get_text (GTK_LABEL(iw->type_label)));
 
     if (iw->owner_choice)
@@ -1820,14 +1817,14 @@ gnc_invoice_update_window (InvoiceWindow *iw, GtkWidget *widget)
             gtk_widget_hide (hide);
             hide = GTK_WIDGET (gtk_builder_get_object (iw->builder, "hide4"));
             gtk_widget_hide (hide);
-            
+
             show = GTK_WIDGET (gtk_builder_get_object (iw->builder, "posted_label"));
             gtk_widget_show (show);
             gtk_widget_show (iw->posted_date_hbox);
             show = GTK_WIDGET (gtk_builder_get_object (iw->builder, "acct_label"));
             gtk_widget_show (show);
             gtk_widget_show (acct_entry);
-            
+
             show = GTK_WIDGET (gtk_builder_get_object (iw->builder, "hide1"));
             gtk_widget_show (show);
             show = GTK_WIDGET (gtk_builder_get_object (iw->builder, "hide2"));
@@ -2347,17 +2344,17 @@ gnc_invoice_create_page (InvoiceWindow *iw, gpointer page)
         {
         case GNC_OWNER_VENDOR:
             gtk_label_set_text (GTK_LABEL(iw->info_label),  _("Bill Information"));
-            gtk_label_set_text (GTK_LABEL(iw->type_label),  _("Bill")); 
-            gtk_label_set_text (GTK_LABEL(iw->id_label),  _("Bill ID")); 
+            gtk_label_set_text (GTK_LABEL(iw->type_label),  _("Bill"));
+            gtk_label_set_text (GTK_LABEL(iw->id_label),  _("Bill ID"));
             break;
         case GNC_OWNER_EMPLOYEE:
             gtk_label_set_text (GTK_LABEL(iw->info_label),  _("Voucher Information"));
             gtk_label_set_text (GTK_LABEL(iw->type_label),  _("Voucher"));
-            gtk_label_set_text (GTK_LABEL(iw->id_label),  _("Voucher ID")); 
+            gtk_label_set_text (GTK_LABEL(iw->id_label),  _("Voucher ID"));
         default:
             break;
         }
-    
+
     entry_ledger = gnc_entry_ledger_new (iw->book, ledger_type);
 
     /* Save the ledger... */
@@ -2430,7 +2427,7 @@ gnc_invoice_window_new_invoice (InvoiceDialogType dialog_type, QofBook *bookp,
     const GncOwner *start_owner;
     GncBillTerm *owner_terms = NULL;
     GncOwnerType owner_type;
-    
+
     g_assert (dialog_type == NEW_INVOICE || dialog_type == MOD_INVOICE || dialog_type == DUP_INVOICE);
 
     if (invoice)
@@ -2513,20 +2510,20 @@ gnc_invoice_window_new_invoice (InvoiceDialogType dialog_type, QofBook *bookp,
     iw->id_label = GTK_WIDGET (gtk_builder_get_object (builder, "label14"));
     iw->info_label = GTK_WIDGET (gtk_builder_get_object (builder, "label1"));
     invoice_radio = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_invoice_type"));
-     
+
     iw->type_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_choice_hbox"));
     iw->type_choice = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_type_invoice"));
-    
+
     /* The default GUI lables are for invoices, so change them if it isn't. */
     owner_type = gncOwnerGetType (&iw->owner);
     switch(owner_type)
     {
         case GNC_OWNER_VENDOR:
             gtk_label_set_text (GTK_LABEL(iw->info_label),  _("Bill Information"));
-            gtk_label_set_text (GTK_LABEL(iw->type_label),  _("Bill")); 
+            gtk_label_set_text (GTK_LABEL(iw->type_label),  _("Bill"));
             gtk_button_set_label (GTK_BUTTON(invoice_radio),  _("Bill"));
             gtk_label_set_text (GTK_LABEL(iw->id_label),  _("Bill ID"));
-             
+
             break;
         case GNC_OWNER_EMPLOYEE:
             gtk_label_set_text (GTK_LABEL(iw->info_label),  _("Voucher Information"));
@@ -2536,7 +2533,7 @@ gnc_invoice_window_new_invoice (InvoiceDialogType dialog_type, QofBook *bookp,
         default:
         break;
     }
-    
+
     /* configure the type related widgets based on dialog type and invoice type */
     switch (dialog_type)
     {
@@ -3306,4 +3303,3 @@ gnc_invoice_remind_bills_due_cb (void)
 
     gnc_invoice_remind_bills_due();
 }
-
diff --git a/src/engine/gnc-pricedb.c b/src/engine/gnc-pricedb.c
index 54b7385..81febf1 100644
--- a/src/engine/gnc-pricedb.c
+++ b/src/engine/gnc-pricedb.c
@@ -966,6 +966,18 @@ gnc_pricedb_equal (GNCPriceDB *db1, GNCPriceDB *db2)
     return equal_data.equal;
 }
 
+static gboolean
+insert_or_replace_price(GNCPriceDB *db, GNCPrice *p)
+{
+    GNCPrice *old_price = gnc_pricedb_lookup_day (db, p->commodity,
+                                                  p->currency, p->tmspec);
+    if (old_price == NULL)
+        return TRUE;
+    if (strcmp(p->source, "PRICE_SOURCE_FQ"))
+        return TRUE;
+    return FALSE;
+}
+
 /* ==================================================================== */
 /* The add_price() function is a utility that only manages the
  * dual hash table instertion */
@@ -1030,6 +1042,12 @@ add_price(GNCPriceDB *db, GNCPrice *p)
         LEAVE (" no price list");
         return FALSE;
     }
+
+    if (!insert_or_replace_price(db, p))
+    {
+        LEAVE("A better price already exists");
+        return FALSE;
+    }
     g_hash_table_insert(currency_hash, currency, price_list);
     p->db = db;
     qof_event_gen (&p->inst, QOF_EVENT_ADD, NULL);
diff --git a/src/engine/gnc-pricedb.h b/src/engine/gnc-pricedb.h
index ce077a5..befff2d 100644
--- a/src/engine/gnc-pricedb.h
+++ b/src/engine/gnc-pricedb.h
@@ -207,6 +207,15 @@ void gnc_price_set_typestr(GNCPrice *p, const char* type);
 void gnc_price_set_value(GNCPrice *p, gnc_numeric value);
 /** @} */
 
+#define PRICE_SOURCE_FQ  "Finance::Quote"
+#define PRICE_SOURCE_INVOICE "user:invoice-post"
+#define PRICE_SOURCE_STOCK_SPLIT "user:stock-split"
+#define PRICE_SOURCE_XFER_DLG "user:xfer-dialog"
+#define PRICE_SOURCE_SPLIT_REG "user:split-register"
+#define PRICE_SOURCE_EDIT_DLG "user:price-editor"
+#define PRICE_TYPE_LAST "last"
+#define PRICE_TYPE_UNK "unknown"
+
 /* ------------------ */
 /** @name  Getters
     All of the getters return data that's internal
diff --git a/src/gnome-utils/dialog-transfer.c b/src/gnome-utils/dialog-transfer.c
index bd1cda6..9a6215f 100644
--- a/src/gnome-utils/dialog-transfer.c
+++ b/src/gnome-utils/dialog-transfer.c
@@ -1648,7 +1648,7 @@ gnc_xfer_dialog_response_cb (GtkDialog *dialog, gint response, gpointer data)
                 gnc_price_set_commodity (price, from);
                 gnc_price_set_currency (price, to);
                 gnc_price_set_time (price, ts);
-                gnc_price_set_source (price, "user:xfer-dialog");
+                gnc_price_set_source (price, PRICE_SOURCE_XFER_DLG);
                 gnc_price_set_value (price, value);
                 gnc_pricedb_add_price (xferData->pricedb, price);
                 gnc_price_commit_edit (price);
diff --git a/src/gnome/assistant-stock-split.c b/src/gnome/assistant-stock-split.c
index 8426ce1..f4b9cff 100644
--- a/src/gnome/assistant-stock-split.c
+++ b/src/gnome/assistant-stock-split.c
@@ -399,8 +399,8 @@ gnc_stock_split_assistant_finish (GtkAssistant *assistant,
         gnc_price_set_commodity (price, xaccAccountGetCommodity (account));
         gnc_price_set_currency (price, gnc_currency_edit_get_currency (ce));
         gnc_price_set_time (price, ts);
-        gnc_price_set_source (price, "user:stock-split");
-        gnc_price_set_typestr (price, "unknown");
+        gnc_price_set_source (price, PRICE_SOURCE_STOCK_SPLIT);
+        gnc_price_set_typestr (price, PRICE_TYPE_UNK);
         gnc_price_set_value (price, amount);
         gnc_price_commit_edit (price);
 
diff --git a/src/gnome/dialog-price-editor.c b/src/gnome/dialog-price-editor.c
index ac980dc..c7c5b9e 100644
--- a/src/gnome/dialog-price-editor.c
+++ b/src/gnome/dialog-price-editor.c
@@ -50,8 +50,6 @@
 
 #define DIALOG_PRICE_EDIT_CM_CLASS "dialog-price-edit"
 #define GNC_PREFS_GROUP "dialogs.price-editor"
-#define DIALOG_PRICE_EDIT_SOURCE "user:price-editor"
-
 
 /* This static indicates the debugging module that this .o belongs to.  */
 G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_GUI;
@@ -172,7 +170,7 @@ price_to_gui (PriceEditDialog *pedit_dialog)
         currency = gnc_default_currency ();
         date.tv_sec = gnc_time (NULL);
         date.tv_nsec = 0;
-        source = DIALOG_PRICE_EDIT_SOURCE;
+        source = PRICE_SOURCE_EDIT_DLG;
         type = "";
         value = gnc_numeric_zero ();
     }
@@ -553,7 +551,7 @@ gnc_price_edit_dialog (GtkWidget * parent,
             price = gnc_price_clone(price, pedit_dialog->book);
 //  } else {
 //      price = gnc_price_create (pedit_dialog->book);
-            gnc_price_set_source (price, DIALOG_PRICE_EDIT_SOURCE);
+            gnc_price_set_source (price, PRICE_SOURCE_EDIT_DLG);
         }
 
         pedit_dialog->is_new = TRUE;
diff --git a/src/register/ledger-core/split-register.c b/src/register/ledger-core/split-register.c
index 3531633..fc4f587 100644
--- a/src/register/ledger-core/split-register.c
+++ b/src/register/ledger-core/split-register.c
@@ -2067,7 +2067,7 @@ record_price (SplitRegister *reg, Account *account, gnc_numeric value)
     gnc_price_set_commodity (price, comm);
     gnc_price_set_currency (price, curr);
     gnc_price_set_time (price, ts);
-    gnc_price_set_source (price, "user:split-register");
+    gnc_price_set_source (price, PRICE_SOURCE_SPLIT_REG);
     gnc_price_set_value (price, value);
     gnc_pricedb_add_price (pricedb, price);
     gnc_price_commit_edit (price);



Summary of changes:
 src/app-utils/gnc-sx-instance-model.c        |    7 +-
 src/backend/sql/gnc-price-sql.c              |    2 +-
 src/backend/xml/gnc-pricedb-xml-v2.c         |    4 +-
 src/backend/xml/io-gncxml-v1.c               |    2 +-
 src/business/business-gnome/dialog-invoice.c |   34 +-
 src/engine/engine.i                          |   11 +-
 src/engine/gnc-pricedb-p.h                   |    2 +-
 src/engine/gnc-pricedb.c                     |  109 ++-
 src/engine/gnc-pricedb.h                     |   37 +-
 src/engine/test-core/test-engine-stuff.c     |    7 +-
 src/gnome-utils/dialog-transfer.c            | 1048 ++++++++++++++------------
 src/gnome-utils/gnc-tree-model-price.c       |    2 +-
 src/gnome-utils/gnc-tree-view-price.c        |    3 +-
 src/gnome/assistant-stock-split.c            |    4 +-
 src/gnome/dialog-price-editor.c              |   10 +-
 src/libqof/qof/gnc-numeric.c                 |   21 +-
 src/libqof/qof/gnc-numeric.h                 |    7 +
 src/quotes/gnc-fq-dump                       |    9 +
 src/quotes/gnc-fq-helper.in                  |   13 +
 src/register/ledger-core/split-register.c    |   68 +-
 src/scm/price-quotes.scm                     |  103 ++-
 21 files changed, 900 insertions(+), 603 deletions(-)



More information about the gnucash-changes mailing list