gnucash maint: Multiple changes pushed

Christopher Lam clam at code.gnucash.org
Mon Oct 26 12:00:44 EDT 2020


Updated	 via  https://github.com/Gnucash/gnucash/commit/92f27278 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1a4f27f6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/89c0baee (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4ff3355f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e7165507 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e833c8e1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2ecdd70e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4d63eb92 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/26e7eada (commit)
	from  https://github.com/Gnucash/gnucash/commit/b675e17e (commit)



commit 92f272786219adee04b7ce96bb15abc864cbb15e
Merge: b675e17e4 1a4f27f6b
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Oct 26 23:57:39 2020 +0800

    Merge branch 'maint-797982' into maint #802


commit 1a4f27f6b3b4d3ae2e9263396b32e684f434c96b
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Oct 21 22:45:06 2020 +0800

    [html-utilities.scm] deprecate gnc:html-make-exchangerates
    
    Because old exchange rates function used exchange-fn which converts 1
    commodity into domestic currency; new exchange rates uses price-fn
    which queries the gnc_numeric pricedb entry directly.

diff --git a/gnucash/report/html-utilities.scm b/gnucash/report/html-utilities.scm
index fb46b6a34..50629e01d 100644
--- a/gnucash/report/html-utilities.scm
+++ b/gnucash/report/html-utilities.scm
@@ -207,6 +207,8 @@
 ;; function 'exchange-fn' and the 'accounts' determine which
 ;; commodities to show. Returns a html-object, a <html-table>.
 (define (gnc:html-make-exchangerates common-commodity exchange-fn accounts)
+  (issue-deprecation-warning
+   "gnc:html-make-exchangerates is deprecated. use gnc:html-make-rates-table instead.")
   (let ((comm-list (gnc:accounts-get-commodities accounts common-commodity))
         (markup (lambda (c) (gnc:make-html-table-cell/markup "number-cell" c)))
         (table (gnc:make-html-table)))

commit 89c0baee9b6f6ae6c7c74730f9920a61157adb93
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Oct 19 22:29:59 2020 +0800

    Bug 797982 - exchange rates' decimal places
    
    use gnc:html-make-rates-table instead of gnc:html-make-exchangerates
    to show effective exchange rate or price used

diff --git a/gnucash/report/reports/standard/account-summary.scm b/gnucash/report/reports/standard/account-summary.scm
index 0ea163838..0ffb26641 100644
--- a/gnucash/report/reports/standard/account-summary.scm
+++ b/gnucash/report/reports/standard/account-summary.scm
@@ -315,6 +315,7 @@
                          (gnc:get-current-account-tree-depth)
                          depth-limit))
          ;; exchange rates calculation parameters
+         (price-fn (gnc:case-price-fn price-source report-commodity to-date))
          (exchange-fn (gnc:case-exchange-fn price-source report-commodity to-date)))
 
     (gnc:html-document-set-title!
@@ -441,8 +442,8 @@
           ;; add currency information
           (when show-rates?
             (gnc:html-document-add-object!
-             doc (gnc:html-make-exchangerates
-                  report-commodity exchange-fn
+             doc (gnc:html-make-rates-table
+                  report-commodity price-fn
                   (gnc:accounts-and-all-descendants accounts))))))
 
     (gnc:report-finished)
diff --git a/gnucash/report/reports/standard/balance-sheet.scm b/gnucash/report/reports/standard/balance-sheet.scm
index dddc7dfdc..6c1c32d76 100644
--- a/gnucash/report/reports/standard/balance-sheet.scm
+++ b/gnucash/report/reports/standard/balance-sheet.scm
@@ -343,6 +343,7 @@
          (tree-depth (if (eq? depth-limit 'all)
                          (gnc:get-current-account-tree-depth)
                          depth-limit))
+         (price-fn (gnc:case-price-fn price-source report-commodity reportdate))
          ;; exchange rates calculation parameters
          (exchange-fn
           (gnc:case-exchange-fn price-source report-commodity reportdate)))
@@ -550,7 +551,7 @@
           (gnc:report-percent-done 90)
           (when show-rates?
             (gnc:html-document-add-object!
-             doc (gnc:html-make-exchangerates report-commodity exchange-fn accounts)))
+             doc (gnc:html-make-rates-table report-commodity price-fn accounts)))
 
           (gnc:report-percent-done 100)))
 
diff --git a/gnucash/report/reports/standard/budget-balance-sheet.scm b/gnucash/report/reports/standard/budget-balance-sheet.scm
index d50a7a0d7..03df94ece 100644
--- a/gnucash/report/reports/standard/budget-balance-sheet.scm
+++ b/gnucash/report/reports/standard/budget-balance-sheet.scm
@@ -355,7 +355,8 @@
          ;; exchange rates calculation parameters
 	 (exchange-fn
 	  (gnc:case-exchange-fn price-source report-commodity date-t64))
-	 )
+
+         (price-fn (gnc:case-price-fn price-source report-commodity date-t64)))
     
     (define (add-subtotal-line table pos-label neg-label signed-balance)
       (let* ((neg? (and signed-balance neg-label
@@ -808,8 +809,7 @@
           (if show-rates?
               (gnc:html-document-add-object! 
                doc ;;(gnc:html-markup-p)
-               (gnc:html-make-exchangerates 
-                report-commodity exchange-fn accounts)))
+               (gnc:html-make-rates-table report-commodity price-fn accounts)))
 	  (gnc:report-percent-done 100)))))
     
     (gnc:report-finished)
diff --git a/gnucash/report/reports/standard/budget-income-statement.scm b/gnucash/report/reports/standard/budget-income-statement.scm
index 2e2978b56..e12e22e7e 100644
--- a/gnucash/report/reports/standard/budget-income-statement.scm
+++ b/gnucash/report/reports/standard/budget-income-statement.scm
@@ -401,7 +401,8 @@
          ;; exchange rates calculation parameters
 	 (exchange-fn
 	  (gnc:case-exchange-fn price-source report-commodity date-t64))
-	 )
+
+         (price-fn (gnc:case-price-fn price-source report-commodity date-t64)))
     
     (define (add-subtotal-line table pos-label neg-label signed-balance)
       (let* ((neg? (and signed-balance neg-label
@@ -595,7 +596,7 @@
         (gnc:report-percent-done 90)
         (when show-rates?
           (gnc:html-document-add-object!
-           doc (gnc:html-make-exchangerates report-commodity exchange-fn accounts)))
+           doc (gnc:html-make-rates-table report-commodity price-fn accounts)))
         (gnc:report-percent-done 100))))
     
     (gnc:report-finished)
diff --git a/gnucash/report/reports/standard/cash-flow.scm b/gnucash/report/reports/standard/cash-flow.scm
index 623f71998..2379e1885 100644
--- a/gnucash/report/reports/standard/cash-flow.scm
+++ b/gnucash/report/reports/standard/cash-flow.scm
@@ -149,6 +149,8 @@
          (exchange-fn (gnc:case-exchange-fn
                        price-source report-currency to-date-t64))
 
+         (price-fn (gnc:case-price-fn price-source report-currency to-date-t64))
+
          (doc (gnc:make-html-document))
          (table (gnc:make-html-table))
 
@@ -321,8 +323,8 @@
               (if show-rates?
                   (gnc:html-document-add-object!
                    doc ;;(gnc:html-markup-p
-                   (gnc:html-make-exchangerates
-                    report-currency exchange-fn accounts))))))
+                   (gnc:html-make-rates-table
+                    report-currency price-fn accounts))))))
 
         ;; error condition: no accounts specified
 
diff --git a/gnucash/report/reports/standard/equity-statement.scm b/gnucash/report/reports/standard/equity-statement.scm
index ce13efc1c..4b47cb179 100644
--- a/gnucash/report/reports/standard/equity-statement.scm
+++ b/gnucash/report/reports/standard/equity-statement.scm
@@ -280,7 +280,9 @@
 	 (end-exchange-fn
 	  (gnc:case-exchange-fn
 	   price-source report-commodity end-date))
-	 )
+
+         (start-price-fn (gnc:case-price-fn price-source report-commodity start-date))
+         (end-price-fn (gnc:case-price-fn price-source report-commodity end-date)))
 
     (define (unrealized-gains-at-date book-balance exchange-fn date)
       (define cost-fn
@@ -496,10 +498,10 @@
 		   (headers (list
 			     (qof-print-date start-date-printable)
 			     (qof-print-date end-date)))
-		   (then (gnc:html-make-exchangerates
-			  report-commodity start-exchange-fn accounts))
-		   (now (gnc:html-make-exchangerates
-                         report-commodity end-exchange-fn accounts)))
+		   (then (gnc:html-make-rates-table
+			  report-commodity start-price-fn accounts))
+		   (now (gnc:html-make-rates-table
+                         report-commodity end-price-fn accounts)))
 	      (gnc:html-table-set-col-headers! curr-tbl headers)
 	      (gnc:html-table-set-style!
 	       curr-tbl "table" 'attribute '("border" "1"))
diff --git a/gnucash/report/reports/standard/income-statement.scm b/gnucash/report/reports/standard/income-statement.scm
index 93988525d..ec9d8df4e 100644
--- a/gnucash/report/reports/standard/income-statement.scm
+++ b/gnucash/report/reports/standard/income-statement.scm
@@ -382,7 +382,7 @@
          ;; exchange rates calculation parameters
 	 (exchange-fn
 	  (gnc:case-exchange-fn price-source report-commodity end-date))
-	 )
+         (price-fn (gnc:case-price-fn price-source report-commodity end-date)))
 
     ;; Wrapper to call gnc:html-table-add-labeled-amount-line!
     ;; with the proper arguments.
@@ -561,8 +561,8 @@
           (gnc:report-percent-done 90)
           (when show-rates?
             (gnc:html-document-add-object!
-             doc (gnc:html-make-exchangerates
-                  report-commodity exchange-fn accounts)))
+             doc (gnc:html-make-rates-table
+                  report-commodity price-fn accounts)))
           (gnc:report-percent-done 100)))
 
     (gnc:report-finished)
diff --git a/gnucash/report/reports/standard/trial-balance.scm b/gnucash/report/reports/standard/trial-balance.scm
index 18b06f8ab..b305d70c5 100644
--- a/gnucash/report/reports/standard/trial-balance.scm
+++ b/gnucash/report/reports/standard/trial-balance.scm
@@ -401,6 +401,7 @@
          ;; exchange rates calculation parameters
          (exchange-fn
           (gnc:case-exchange-fn price-source report-commodity end-date))
+         (price-fn (gnc:case-price-fn price-source report-commodity end-date))
          (period-for (string-append " " (G_ "for Period"))))
 
     (gnc:html-document-set-title!
@@ -894,8 +895,8 @@
           (if show-rates?
               (gnc:html-document-add-object!
                doc
-               (gnc:html-make-exchangerates
-                report-commodity exchange-fn accounts)))
+               (gnc:html-make-rates-table
+                report-commodity price-fn accounts)))
           (gnc:report-percent-done 100)))
 
     (gnc:report-finished)

commit 4ff3355f02498308d4683906e2a23620b0b0414e
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue Oct 20 21:55:55 2020 +0800

    [html-style-info.scm] price-renderer does not convert to decimal
    
    so that it may obey global pref decimal vs fraction

diff --git a/gnucash/report/html-style-info.scm b/gnucash/report/html-style-info.scm
index 20f34e640..0c58671ec 100644
--- a/gnucash/report/html-style-info.scm
+++ b/gnucash/report/html-style-info.scm
@@ -167,12 +167,8 @@
   (xaccPrintAmount datum (gnc-default-print-info #f)))
 
 ;; renders a price to target currency
-(define (gnc:default-price-renderer currency amount)
-  (xaccPrintAmount
-   (gnc-numeric-convert
-    amount (min 10000 (* 100 (gnc-commodity-get-fraction currency)))
-    GNC-HOW-RND-ROUND)
-   (gnc-price-print-info currency #t)))
+(define (gnc:default-price-renderer currency price)
+  (xaccPrintAmount price (gnc-price-print-info currency #t)))
 
 (define (gnc:default-html-gnc-monetary-renderer datum params)
   (let* ((comm (gnc:gnc-monetary-commodity datum))

commit e7165507c8497bfbcf7d3b107ca4e9ed2912a9d3
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Tue Oct 20 10:03:48 2020 +0800

    [commodity-utils.scm][api] gnc:html-make-rates-table with price-fn
    
    better precision than gnc:html-make-exchangerates

diff --git a/gnucash/report/commodity-utilities.scm b/gnucash/report/commodity-utilities.scm
index c6c87efa2..e777a2a84 100644
--- a/gnucash/report/commodity-utilities.scm
+++ b/gnucash/report/commodity-utilities.scm
@@ -21,6 +21,7 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (use-modules (ice-9 match))
+(use-modules (srfi srfi-26))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Functions to get splits with interesting data from accounts.
@@ -764,6 +765,18 @@
          (gnc:exchange-by-pricedb-nearest
           foreign domestic to-date-tp))))))
 
+(define (gnc:case-price-fn source target-curr date)
+  (define pdb (gnc-pricedb-get-db (gnc-get-current-book)))
+  (case source
+    ((pricedb-nearest) (cut gnc-pricedb-get-nearest-price pdb <> target-curr date))
+    ((pricedb-latest)  (cut gnc-pricedb-get-latest-price pdb <> target-curr))
+    (else
+     (lambda (commodity)
+       (let* ((exchange-fn (gnc:case-exchange-fn source target-curr date))
+              (foreign-mon (gnc:make-gnc-monetary commodity 1))
+              (domestic-mon (exchange-fn foreign-mon target-curr)))
+         (gnc:gnc-monetary-amount domestic-mon))))))
+
 ;; Return a ready-to-use function. Which one to use is determined by
 ;; the value of 'source-option', whose possible values are set in
 ;; gnc:options-add-price-source!.
diff --git a/gnucash/report/html-utilities.scm b/gnucash/report/html-utilities.scm
index d536201e0..fb46b6a34 100644
--- a/gnucash/report/html-utilities.scm
+++ b/gnucash/report/html-utilities.scm
@@ -228,6 +228,30 @@
                             (G_ "Exchange rates"))))))
     table))
 
+;; Create a html-table of all prices. The report-currency is
+;; 'currency', The prices are given through the function 'price-fn'
+;; and the 'accounts' determine which commodities to show. Returns a
+;; html-object, a <html-table>. price-fn is easily obtained from
+;; gnc:case-price-fn
+(define (gnc:html-make-rates-table currency price-fn accounts)
+  (define (cell c) (gnc:make-html-table-cell/markup "number-cell" c))
+  (define table (gnc:make-html-table))
+  (let lp ((comm-list (gnc:accounts-get-commodities accounts currency)) (entries 0))
+    (match comm-list
+      (()
+       (unless (zero? entries)
+         (gnc:html-table-set-col-headers!
+          table (list (gnc:make-html-table-header-cell/size
+                       1 2 (if (= entries 1) (G_ "Exchange rate")
+                               (G_ "Exchange rates"))))))
+       table)
+      ((comm . rest)
+       (gnc:html-table-append-row!
+        table
+        (list (cell (gnc:make-gnc-monetary comm 1))
+              (cell (gnc:default-price-renderer currency (price-fn comm)))))
+       (lp rest (1+ entries))))))
+
 
 (define (gnc:html-make-generic-budget-warning report-title-string)
   (gnc:html-make-generic-simple-warning
diff --git a/gnucash/report/report.scm b/gnucash/report/report.scm
index 7791d969e..8444da85c 100644
--- a/gnucash/report/report.scm
+++ b/gnucash/report/report.scm
@@ -58,6 +58,7 @@
 (export gnc:exchange-by-pricealist-nearest)
 (export gnc:case-exchange-fn)
 (export gnc:case-exchange-time-fn)
+(export gnc:case-price-fn)
 (export gnc:sum-collector-commodity)
 
 ;; options-utilities.scm
@@ -104,6 +105,7 @@
 (export gnc:assign-colors)
 (export gnc:html-table-append-ruler!)
 (export gnc:html-make-exchangerates)
+(export gnc:html-make-rates-table)
 (export gnc:html-render-options-changed)
 (export gnc:html-make-generic-warning)
 (export gnc:html-make-no-account-warning)

commit e833c8e1aa6f55341692d81c9d87aa0ad53b393b
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Oct 26 20:48:52 2020 +0800

    [utest-gnc-pricedb.c] test: gnc_pricedb_get_[latest|nearest]_price

diff --git a/libgnucash/engine/test/utest-gnc-pricedb.c b/libgnucash/engine/test/utest-gnc-pricedb.c
index 0afeb86c1..daf34df4f 100644
--- a/libgnucash/engine/test/utest-gnc-pricedb.c
+++ b/libgnucash/engine/test/utest-gnc-pricedb.c
@@ -1248,6 +1248,84 @@ test_gnc_pricedb_convert_balance_nearest_price_t64 (PriceDBFixture *fixture, gco
     g_assert_cmpint(result.denom, ==, 100);
 
 }
+
+static void
+test_gnc_pricedb_get_latest_price (PriceDBFixture *fixture, gconstpointer pData)
+{
+    gnc_numeric result;
+
+    result = gnc_pricedb_get_latest_price (fixture->pricedb,
+                                           fixture->com->usd,
+                                           fixture->com->aud);
+    g_assert_cmpint(result.num, ==, 3587);
+    g_assert_cmpint(result.denom, ==, 3125);
+
+    result = gnc_pricedb_get_latest_price (fixture->pricedb,
+                                           fixture->com->usd,
+                                           fixture->com->gbp);
+    g_assert_cmpint(result.num, ==, 50000);
+    g_assert_cmpint(result.denom, ==, 78829);
+
+    result = gnc_pricedb_get_latest_price (fixture->pricedb,
+                                           fixture->com->usd,
+                                           fixture->com->eur);
+    g_assert_cmpint(result.num, ==, 63418);
+    g_assert_cmpint(result.denom, ==, 78829);
+
+    result = gnc_pricedb_get_latest_price (fixture->pricedb,
+                                           fixture->com->gbp,
+                                           fixture->com->dkk);
+    g_assert_cmpint(result.num, ==, 47194370497);
+    g_assert_cmpint(result.denom, ==, 5000000000);
+
+    result = gnc_pricedb_get_latest_price (fixture->pricedb,
+                                           fixture->com->amzn,
+                                           fixture->com->aud);
+    g_assert_cmpint(result.num, ==, 111738637);
+    g_assert_cmpint(result.denom, ==, 312500);
+}
+
+static void
+test_gnc_pricedb_get_nearest_price (PriceDBFixture *fixture, gconstpointer pData)
+{
+    time64 t = gnc_dmy2time64(15, 8, 2011);
+    gnc_numeric result;
+
+    result = gnc_pricedb_get_nearest_price (fixture->pricedb,
+                                            fixture->com->usd,
+                                            fixture->com->aud, t);
+    g_assert_cmpint(result.num, ==, 1250);
+    g_assert_cmpint(result.denom, ==, 1331);
+
+    result = gnc_pricedb_get_nearest_price (fixture->pricedb,
+                                            fixture->com->usd,
+                                            fixture->com->gbp,
+                                            t);
+    g_assert_cmpint(result.num, ==, 100000);
+    g_assert_cmpint(result.denom, ==, 161643);
+
+    result = gnc_pricedb_get_nearest_price (fixture->pricedb,
+                                            fixture->com->usd,
+                                            fixture->com->eur,
+                                            t);
+    g_assert_cmpint(result.num, ==, 37763);
+    g_assert_cmpint(result.denom, ==, 53881);
+
+    result = gnc_pricedb_get_nearest_price (fixture->pricedb,
+                                            fixture->com->gbp,
+                                            fixture->com->dkk,
+                                            t);
+    g_assert_cmpint(result.num, ==, 84450223707);
+    g_assert_cmpint(result.denom, ==, 10000000000);
+
+    result = gnc_pricedb_get_nearest_price (fixture->pricedb,
+                                            fixture->com->amzn,
+                                            fixture->com->aud,
+                                            t);
+    g_assert_cmpint(result.num, ==, 278150);
+    g_assert_cmpint(result.denom, ==, 1331);
+}
+
 /* pricedb_foreach_pricelist
 static void
 pricedb_foreach_pricelist(gpointer key, gpointer val, gpointer user_data)// Local: 0:1:0
@@ -1504,6 +1582,8 @@ test_suite_gnc_pricedb (void)
 // GNC_TEST_ADD (suitename, "indirect balance conversion", Fixture, NULL, setup, test_indirect_balance_conversion, teardown);
     GNC_TEST_ADD (suitename, "gnc pricedb convert balance latest price", PriceDBFixture, NULL, setup, test_gnc_pricedb_convert_balance_latest_price, teardown);
     GNC_TEST_ADD (suitename, "gnc pricedb convert balance nearest price", PriceDBFixture, NULL, setup, test_gnc_pricedb_convert_balance_nearest_price_t64, teardown);
+    GNC_TEST_ADD (suitename, "gnc pricedb get latest price", PriceDBFixture, NULL, setup, test_gnc_pricedb_get_latest_price, teardown);
+    GNC_TEST_ADD (suitename, "gnc pricedb get nearest price", PriceDBFixture, NULL, setup, test_gnc_pricedb_get_nearest_price, teardown);
 // GNC_TEST_ADD (suitename, "pricedb foreach pricelist", Fixture, NULL, setup, test_pricedb_foreach_pricelist, teardown);
 // GNC_TEST_ADD (suitename, "pricedb foreach currencies hash", Fixture, NULL, setup, test_pricedb_foreach_currencies_hash, teardown);
 // GNC_TEST_ADD (suitename, "unstable price traversal", Fixture, NULL, setup, test_unstable_price_traversal, teardown);

commit 2ecdd70e2412dac95d6b65eece136e718797252f
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Oct 19 20:08:44 2020 +0800

    [gnc-pricedb.c][api] pull out composite pricedb price retriever
    
    * tries direct price retrieval from pricedb.
    * if fails, tries intermediate currency.

diff --git a/libgnucash/engine/gnc-pricedb.c b/libgnucash/engine/gnc-pricedb.c
index 3b39788c1..481df22ad 100644
--- a/libgnucash/engine/gnc-pricedb.c
+++ b/libgnucash/engine/gnc-pricedb.c
@@ -2435,35 +2435,6 @@ gnc_pricedb_lookup_latest_before_t64 (GNCPriceDB *db,
     return current_price;
 }
 
-static gnc_numeric
-direct_balance_conversion (GNCPriceDB *db, gnc_numeric bal,
-                           const gnc_commodity *from, const gnc_commodity *to,
-                           time64 t)
-{
-    GNCPrice *price;
-    gnc_numeric retval = gnc_numeric_zero();
-    if (from == NULL || to == NULL)
-        return retval;
-    if (gnc_numeric_zero_p(bal))
-        return retval;
-    if (t != INT64_MAX)
-        price = gnc_pricedb_lookup_nearest_in_time64(db, from, to, t);
-    else
-        price = gnc_pricedb_lookup_latest(db, from, to);
-    if (price == NULL)
-        return retval;
-    if (gnc_price_get_commodity(price) == from)
-        retval = gnc_numeric_mul (bal, gnc_price_get_value (price),
-                                  gnc_commodity_get_fraction (to),
-                                  GNC_HOW_RND_ROUND);
-    else
-        retval = gnc_numeric_div (bal, gnc_price_get_value (price),
-                                  gnc_commodity_get_fraction (to),
-                                  GNC_HOW_RND_ROUND);
-    gnc_price_unref (price);
-    return retval;
-
-}
 
 typedef struct
 {
@@ -2601,72 +2572,35 @@ direct_price_conversion (GNCPriceDB *db, const gnc_commodity *from,
     return retval;
 }
 
-static gnc_numeric
-convert_balance(gnc_numeric bal, const gnc_commodity *from,
-                const gnc_commodity *to, PriceTuple tuple)
+gnc_numeric
+gnc_pricedb_get_nearest_price (GNCPriceDB *pdb,
+                               const gnc_commodity *orig_currency,
+                               const gnc_commodity *new_currency,
+                               const time64 t)
 {
-    gnc_commodity *from_com = gnc_price_get_commodity(tuple.from);
-    gnc_commodity *from_cur = gnc_price_get_currency(tuple.from);
-    gnc_commodity *to_com = gnc_price_get_commodity(tuple.to);
-    gnc_commodity *to_cur = gnc_price_get_currency(tuple.to);
-    gnc_numeric from_val = gnc_price_get_value(tuple.from);
-    gnc_numeric to_val = gnc_price_get_value(tuple.to);
-    int fraction = gnc_commodity_get_fraction(to);
+    gnc_numeric price;
 
-    int no_round = GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER;
-    if (from_cur == from && to_cur == to)
-        return gnc_numeric_div(gnc_numeric_mul(bal, to_val, GNC_DENOM_AUTO,
-                                               no_round),
-                               from_val, fraction, GNC_HOW_RND_ROUND);
-    if (from_com == from && to_com == to)
-        return gnc_numeric_div(gnc_numeric_mul(bal, from_val, GNC_DENOM_AUTO,
-                                               no_round),
-                               to_val, fraction, GNC_HOW_RND_ROUND);
-    if (from_cur == from)
-        return gnc_numeric_div(bal, gnc_numeric_mul(from_val, to_val,
-                                                    GNC_DENOM_AUTO, no_round),
-                               fraction, GNC_HOW_RND_ROUND);
-    return gnc_numeric_mul(bal, gnc_numeric_mul(from_val, to_val,
-                                                GNC_DENOM_AUTO, no_round),
-                           fraction, GNC_HOW_RND_ROUND);
+    if (gnc_commodity_equiv (orig_currency, new_currency))
+        return gnc_numeric_create (1, 1);
+
+    /* Look for a direct price. */
+    price = direct_price_conversion (pdb, orig_currency, new_currency, t);
+
+    /*
+     * no direct price found, try find a price in another currency
+     */
+    if (gnc_numeric_zero_p (price))
+        price = indirect_price_conversion (pdb, orig_currency, new_currency, t);
 
+    return gnc_numeric_reduce (price);
 }
-static gnc_numeric
-indirect_balance_conversion (GNCPriceDB *db, gnc_numeric bal,
-                             const gnc_commodity *from, const gnc_commodity *to,
-                             time64 t )
+
+gnc_numeric
+gnc_pricedb_get_latest_price (GNCPriceDB *pdb,
+                              const gnc_commodity *orig_currency,
+                              const gnc_commodity *new_currency)
 {
-    GList *from_prices = NULL, *to_prices = NULL;
-    PriceTuple tuple;
-    gnc_numeric zero = gnc_numeric_zero();
-    if (from == NULL || to == NULL)
-        return zero;
-    if (gnc_numeric_zero_p(bal))
-        return zero;
-    if (t == INT64_MAX)
-    {
-        from_prices = gnc_pricedb_lookup_latest_any_currency(db, from);
-        /* "to" is often the book currency which may have lots of prices,
-            so avoid getting them if they aren't needed. */
-        if (from_prices)
-            to_prices = gnc_pricedb_lookup_latest_any_currency(db, to);
-    }
-    else
-    {
-        from_prices = gnc_pricedb_lookup_nearest_in_time_any_currency_t64(db,
-                                                                      from, t);
-        if (from_prices)
-            to_prices = gnc_pricedb_lookup_nearest_in_time_any_currency_t64(db,
-                                                                    to, t);
-    }
-    if (from_prices == NULL || to_prices == NULL)
-        return zero;
-    tuple = extract_common_prices(from_prices, to_prices, from, to);
-    gnc_price_list_destroy(from_prices);
-    gnc_price_list_destroy(to_prices);
-    if (tuple.from)
-        return convert_balance(bal, from, to, tuple);
-    return zero;
+    return gnc_pricedb_get_nearest_price (pdb, orig_currency, new_currency, INT64_MAX);
 }
 
 static gnc_numeric convert_amount_at_date (GNCPriceDB *pdb,
@@ -2675,25 +2609,16 @@ static gnc_numeric convert_amount_at_date (GNCPriceDB *pdb,
                                            const gnc_commodity *new_currency,
                                            const time64 t)
 {
-    gnc_numeric new_value;
+    gnc_numeric price;
 
-    if (gnc_numeric_zero_p (amount) ||
-        gnc_commodity_equiv (orig_currency, new_currency))
+    if (gnc_numeric_zero_p (amount))
         return amount;
 
-    /* Look for a direct price. */
-    new_value = direct_balance_conversion
-        (pdb, amount, orig_currency, new_currency, t);
-
-    /*
-     * no direct price found, try if we find a price in another currency
-     * and convert in two stages
-     */
-    if (gnc_numeric_zero_p (new_value))
-        new_value = indirect_balance_conversion
-            (pdb, amount, orig_currency, new_currency, t);
+    price = gnc_pricedb_get_nearest_price (pdb, orig_currency, new_currency, t);
 
-    return new_value;
+    return gnc_numeric_mul
+        (amount, price, gnc_commodity_get_fraction (new_currency),
+         GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND);
 }
 
 /*
diff --git a/libgnucash/engine/gnc-pricedb.h b/libgnucash/engine/gnc-pricedb.h
index 6a8301f3c..5010476c3 100644
--- a/libgnucash/engine/gnc-pricedb.h
+++ b/libgnucash/engine/gnc-pricedb.h
@@ -559,6 +559,24 @@ PriceList * gnc_pricedb_lookup_latest_before_any_currency_t64(GNCPriceDB *db,
                                                               time64 t);
 
 
+/** @brief Retrieve the price one currency to another at specified date
+ * @param pdb The pricedb
+ * @param orig_currency The commodity in which the balance is currently
+ * expressed
+ * @param new_currency The commodity to which the balance should be converted
+ * @return A price, or gnc_numeric_zero if no price is available.
+ */
+
+gnc_numeric gnc_pricedb_get_nearest_price (GNCPriceDB *pdb,
+                                           const gnc_commodity *orig_currency,
+                                           const gnc_commodity *new_currency,
+                                           const time64 t);
+
+gnc_numeric gnc_pricedb_get_latest_price (GNCPriceDB *pdb,
+                                          const gnc_commodity *orig_currency,
+                                          const gnc_commodity *new_currency);
+
+
 /** @brief Convert a balance from one currency to another using the most recent
  * price between the two.
  * @param pdb The pricedb

commit 4d63eb922f4ae3794315dad36c9dafc0e9f752e3
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Oct 19 10:47:50 2020 +0800

    [gnc-pricedb.c] copy convert_amount to convert_price

diff --git a/libgnucash/engine/gnc-pricedb.c b/libgnucash/engine/gnc-pricedb.c
index 6887652d6..3b39788c1 100644
--- a/libgnucash/engine/gnc-pricedb.c
+++ b/libgnucash/engine/gnc-pricedb.c
@@ -2513,6 +2513,94 @@ extract_common_prices (PriceList *from_prices, PriceList *to_prices,
     return retval;
 }
 
+
+static gnc_numeric
+convert_price (const gnc_commodity *from, const gnc_commodity *to, PriceTuple tuple)
+{
+    gnc_commodity *from_com = gnc_price_get_commodity (tuple.from);
+    gnc_commodity *from_cur = gnc_price_get_currency (tuple.from);
+    gnc_commodity *to_com = gnc_price_get_commodity (tuple.to);
+    gnc_commodity *to_cur = gnc_price_get_currency (tuple.to);
+    gnc_numeric from_val = gnc_price_get_value (tuple.from);
+    gnc_numeric to_val = gnc_price_get_value (tuple.to);
+    gnc_numeric price;
+    int no_round = GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER;
+
+    price = gnc_numeric_div (to_val, from_val, GNC_DENOM_AUTO, no_round);
+
+    if (from_cur == from && to_cur == to)
+        return price;
+
+    if (from_com == from && to_com == to)
+        return gnc_numeric_invert (price);
+
+    price = gnc_numeric_mul (from_val, to_val, GNC_DENOM_AUTO, no_round);
+
+    if (from_cur == from)
+        return gnc_numeric_invert (price);
+
+    return price;
+}
+
+static gnc_numeric
+indirect_price_conversion (GNCPriceDB *db, const gnc_commodity *from,
+                           const gnc_commodity *to, time64 t)
+{
+    GList *from_prices = NULL, *to_prices = NULL;
+    PriceTuple tuple;
+    gnc_numeric zero = gnc_numeric_zero();
+    if (!from || !to)
+        return zero;
+    if (t == INT64_MAX)
+    {
+        from_prices = gnc_pricedb_lookup_latest_any_currency(db, from);
+        /* "to" is often the book currency which may have lots of prices,
+            so avoid getting them if they aren't needed. */
+        if (from_prices)
+            to_prices = gnc_pricedb_lookup_latest_any_currency(db, to);
+    }
+    else
+    {
+        from_prices = gnc_pricedb_lookup_nearest_in_time_any_currency_t64 (db, from, t);
+        if (from_prices)
+            to_prices = gnc_pricedb_lookup_nearest_in_time_any_currency_t64 (db, to, t);
+    }
+    if (!from_prices || !to_prices)
+        return zero;
+    tuple = extract_common_prices (from_prices, to_prices, from, to);
+    gnc_price_list_destroy (from_prices);
+    gnc_price_list_destroy (to_prices);
+    if (tuple.from)
+        return convert_price (from, to, tuple);
+    return zero;
+}
+
+
+static gnc_numeric
+direct_price_conversion (GNCPriceDB *db, const gnc_commodity *from,
+                         const gnc_commodity *to, time64 t)
+{
+    GNCPrice *price;
+    gnc_numeric retval = gnc_numeric_zero();
+
+    if (!from || !to) return retval;
+
+    if (t == INT64_MAX)
+        price = gnc_pricedb_lookup_latest(db, from, to);
+    else
+        price = gnc_pricedb_lookup_nearest_in_time64(db, from, to, t);
+
+    if (!price) return retval;
+
+    retval = gnc_price_get_value (price);
+
+    if (gnc_price_get_commodity (price) != from)
+        retval = gnc_numeric_invert (retval);
+
+    gnc_price_unref (price);
+    return retval;
+}
+
 static gnc_numeric
 convert_balance(gnc_numeric bal, const gnc_commodity *from,
                 const gnc_commodity *to, PriceTuple tuple)

commit 26e7eada37efa2a3b91509483e17e9c9ba544ec6
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Mon Oct 19 10:26:23 2020 +0800

    [gnc-pricedb.c] refactor amount converters, use common code

diff --git a/libgnucash/engine/gnc-pricedb.c b/libgnucash/engine/gnc-pricedb.c
index 94075ac03..6887652d6 100644
--- a/libgnucash/engine/gnc-pricedb.c
+++ b/libgnucash/engine/gnc-pricedb.c
@@ -2581,34 +2581,44 @@ indirect_balance_conversion (GNCPriceDB *db, gnc_numeric bal,
     return zero;
 }
 
-
-/*
- * Convert a balance from one currency to another.
- */
-gnc_numeric
-gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb,
-        gnc_numeric balance,
-        const gnc_commodity *balance_currency,
-        const gnc_commodity *new_currency)
+static gnc_numeric convert_amount_at_date (GNCPriceDB *pdb,
+                                           gnc_numeric amount,
+                                           const gnc_commodity *orig_currency,
+                                           const gnc_commodity *new_currency,
+                                           const time64 t)
 {
     gnc_numeric new_value;
 
-    if (gnc_numeric_zero_p (balance) ||
-            gnc_commodity_equiv (balance_currency, new_currency))
-        return balance;
+    if (gnc_numeric_zero_p (amount) ||
+        gnc_commodity_equiv (orig_currency, new_currency))
+        return amount;
 
     /* Look for a direct price. */
-    new_value = direct_balance_conversion(pdb, balance, balance_currency,
-                                          new_currency, INT64_MAX);
-    if (!gnc_numeric_zero_p(new_value))
-        return new_value;
+    new_value = direct_balance_conversion
+        (pdb, amount, orig_currency, new_currency, t);
 
     /*
      * no direct price found, try if we find a price in another currency
      * and convert in two stages
      */
-    return indirect_balance_conversion(pdb, balance, balance_currency,
-                                       new_currency, INT64_MAX);
+    if (gnc_numeric_zero_p (new_value))
+        new_value = indirect_balance_conversion
+            (pdb, amount, orig_currency, new_currency, t);
+
+    return new_value;
+}
+
+/*
+ * Convert a balance from one currency to another.
+ */
+gnc_numeric
+gnc_pricedb_convert_balance_latest_price (GNCPriceDB *pdb,
+                                          gnc_numeric balance,
+                                          const gnc_commodity *balance_currency,
+                                          const gnc_commodity *new_currency)
+{
+    return convert_amount_at_date
+        (pdb, balance, balance_currency, new_currency, INT64_MAX);
 }
 
 gnc_numeric
@@ -2618,24 +2628,8 @@ gnc_pricedb_convert_balance_nearest_price_t64(GNCPriceDB *pdb,
                                               const gnc_commodity *new_currency,
                                               time64 t)
 {
-    gnc_numeric new_value;
-
-    if (gnc_numeric_zero_p (balance) ||
-        gnc_commodity_equiv (balance_currency, new_currency))
-        return balance;
-
-    /* Look for a direct price. */
-    new_value = direct_balance_conversion(pdb, balance, balance_currency,
-                                          new_currency, t);
-    if (!gnc_numeric_zero_p(new_value))
-        return new_value;
-
-    /*
-     * no direct price found, try if we find a price in another currency
-     * and convert in two stages
-     */
-    return indirect_balance_conversion(pdb, balance, balance_currency,
-                                       new_currency, t);
+    return convert_amount_at_date
+        (pdb, balance, balance_currency, new_currency, t);
 }
 
 



Summary of changes:
 gnucash/report/commodity-utilities.scm             |  13 ++
 gnucash/report/html-style-info.scm                 |   8 +-
 gnucash/report/html-utilities.scm                  |  26 +++
 gnucash/report/report.scm                          |   2 +
 .../report/reports/standard/account-summary.scm    |   5 +-
 gnucash/report/reports/standard/balance-sheet.scm  |   3 +-
 .../reports/standard/budget-balance-sheet.scm      |   6 +-
 .../reports/standard/budget-income-statement.scm   |   5 +-
 gnucash/report/reports/standard/cash-flow.scm      |   6 +-
 .../report/reports/standard/equity-statement.scm   |  12 +-
 .../report/reports/standard/income-statement.scm   |   6 +-
 gnucash/report/reports/standard/trial-balance.scm  |   5 +-
 libgnucash/engine/gnc-pricedb.c                    | 215 +++++++++++----------
 libgnucash/engine/gnc-pricedb.h                    |  18 ++
 libgnucash/engine/test/utest-gnc-pricedb.c         |  80 ++++++++
 15 files changed, 280 insertions(+), 130 deletions(-)



More information about the gnucash-changes mailing list