From 1fffbaf856921906e195803726375765a2eacaa0 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 15 Jul 2018 13:20:21 -0700 Subject: [PATCH] Bug 794755 - Commodity Register displays fractional prices When printing numbers convert them to a new decimal denominator with rounding if the passed-in print info specifies that they should be forced and rounded. Make the default price settings forced and rounded. Pass the price currency to gnc_default_price_print_info and use the currency's fraction * 100 to determine the round-to denominator and the number of decimal places to display. --- gnucash/gnome-utils/gnc-tree-view-split-reg.c | 9 ++-- gnucash/gnome/assistant-loan.c | 4 +- gnucash/gnome/assistant-stock-split.c | 2 +- gnucash/gnome/dialog-price-editor.c | 2 +- .../ledger-core/split-register-model.c | 9 ++-- gnucash/register/ledger-core/split-register.c | 2 +- libgnucash/app-utils/gnc-ui-util.c | 48 ++++++++++++++++--- libgnucash/app-utils/gnc-ui-util.h | 2 +- 8 files changed, 56 insertions(+), 22 deletions(-) diff --git a/gnucash/gnome-utils/gnc-tree-view-split-reg.c b/gnucash/gnome-utils/gnc-tree-view-split-reg.c index a309cbe31f..c10d3afe5b 100644 --- a/gnucash/gnome-utils/gnc-tree-view-split-reg.c +++ b/gnucash/gnome-utils/gnc-tree-view-split-reg.c @@ -1805,12 +1805,9 @@ gtv_sr_cdf0 (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *s_mode } else { - GNCPrintAmountInfo print_info; - - print_info = gnc_default_price_print_info(); - print_info.min_decimal_places = 2; - - num = gnc_numeric_convert (gnc_tree_util_get_rate_for (view, trans, split, is_blank), 1000000, GNC_HOW_RND_ROUND_HALF_UP); + GNCPrintAmountInfo print_info = + gnc_default_price_print_info(xaccTransGetCurrency(trans)); + num = gnc_tree_util_get_rate_for (view, trans, split, is_blank); if (gnc_numeric_check (num) == GNC_ERROR_OK) s = xaccPrintAmount (num, print_info); diff --git a/gnucash/gnome/assistant-loan.c b/gnucash/gnome/assistant-loan.c index 26370f5c38..388af798e0 100644 --- a/gnucash/gnome/assistant-loan.c +++ b/gnucash/gnome/assistant-loan.c @@ -2213,7 +2213,7 @@ loan_rev_update_view( LoanAssistantData *ldd, GDate *start, GDate *end ) GtkListStore *store; GtkTreeIter iter; - pai = gnc_default_price_print_info(); + pai = gnc_default_price_print_info(NULL); pai.min_decimal_places = 2; store = GTK_LIST_STORE(gtk_tree_view_get_model( ldd->revView )); @@ -2522,7 +2522,7 @@ ld_setup_repayment_sx( LoanAssistantData *ldd, TTSplitInfo *fromSplit = NULL; TTSplitInfo *ttsi; TTInfo *toTxn = NULL; - GNCPrintAmountInfo pricePAI = gnc_default_price_print_info(); + GNCPrintAmountInfo pricePAI = gnc_default_price_print_info(NULL); #define AMTBUF_LEN 64 gchar amtBuf[AMTBUF_LEN]; gint GNCN_HOW = (GNC_HOW_DENOM_SIGFIGS(2) | GNC_HOW_RND_ROUND_HALF_UP); diff --git a/gnucash/gnome/assistant-stock-split.c b/gnucash/gnome/assistant-stock-split.c index c5c4f8e0d9..287a4375a4 100644 --- a/gnucash/gnome/assistant-stock-split.c +++ b/gnucash/gnome/assistant-stock-split.c @@ -630,7 +630,7 @@ gnc_stock_split_assistant_create (StockSplitInfo *info) amount = gnc_amount_edit_new (); gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (amount), - gnc_default_price_print_info ()); + gnc_default_price_print_info (gnc_default_currency())); g_signal_connect (amount, "changed", G_CALLBACK (gnc_stock_split_details_valid_cb), info); gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (amount), TRUE); diff --git a/gnucash/gnome/dialog-price-editor.c b/gnucash/gnome/dialog-price-editor.c index a787284f1b..5b474c6e07 100644 --- a/gnucash/gnome/dialog-price-editor.c +++ b/gnucash/gnome/dialog-price-editor.c @@ -461,7 +461,7 @@ gnc_price_pedit_dialog_create (GtkWidget *parent, pedit_dialog->price_edit = w; gtk_box_pack_start (GTK_BOX (box), w, TRUE, TRUE, 0); gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (w), TRUE); - print_info = gnc_default_price_print_info (); + print_info = gnc_default_price_print_info (gnc_currency_edit_get_currency (GNC_CURRENCY_EDIT (pedit_dialog->currency_edit))); gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (w), print_info); gtk_entry_set_activates_default(GTK_ENTRY(w), TRUE); gtk_widget_show (w); diff --git a/gnucash/register/ledger-core/split-register-model.c b/gnucash/register/ledger-core/split-register-model.c index 80fea427ca..bc65d38328 100644 --- a/gnucash/register/ledger-core/split-register-model.c +++ b/gnucash/register/ledger-core/split-register-model.c @@ -1201,6 +1201,7 @@ gnc_split_register_get_rate_entry (VirtualLocation virt_loc, Split *split, *osplit; Transaction *txn; gnc_numeric amount, value, convrate; + gnc_commodity *curr; SRInfo *info = gnc_split_register_get_info (reg); if (info->rate_reset == RATE_RESET_REQD && info->auto_complete) @@ -1216,7 +1217,7 @@ gnc_split_register_get_rate_entry (VirtualLocation virt_loc, */ osplit = xaccSplitGetOtherSplit (split); txn = gnc_split_register_get_trans (reg, virt_loc.vcell_loc); - + curr = xaccTransGetCurrency (xaccSplitGetParent (split)); if (!gnc_split_register_current_trans_expanded (reg) && osplit && !gnc_split_register_needs_conv_rate(reg, txn, xaccSplitGetAccount(split))) @@ -1232,7 +1233,7 @@ gnc_split_register_get_rate_entry (VirtualLocation virt_loc, convrate = gnc_numeric_div (amount, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); - return xaccPrintAmount (convrate, gnc_default_price_print_info ()); + return xaccPrintAmount (convrate, gnc_default_price_print_info (curr)); } static const char * @@ -1361,6 +1362,7 @@ gnc_split_register_get_price_entry (VirtualLocation virt_loc, { SplitRegister *reg = user_data; gnc_numeric price; + gnc_commodity *curr; Split *split; if (!gnc_split_register_use_security_cells (reg, virt_loc)) @@ -1369,10 +1371,11 @@ gnc_split_register_get_price_entry (VirtualLocation virt_loc, split = gnc_split_register_get_split (reg, virt_loc.vcell_loc); price = xaccSplitGetSharePrice (split); + curr = xaccTransGetCurrency (xaccSplitGetParent (split)); if (gnc_numeric_zero_p (price)) return NULL; - return xaccPrintAmount (price, gnc_default_price_print_info ()); + return xaccPrintAmount (price, gnc_default_price_print_info (curr)); } static char * diff --git a/gnucash/register/ledger-core/split-register.c b/gnucash/register/ledger-core/split-register.c index 5bbfdd0d68..f534f28e10 100644 --- a/gnucash/register/ledger-core/split-register.c +++ b/gnucash/register/ledger-core/split-register.c @@ -2648,7 +2648,7 @@ gnc_split_register_config_cells (SplitRegister *reg) gnc_price_cell_set_print_info ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL), - gnc_default_price_print_info ()); + gnc_default_price_print_info (gnc_default_currency ())); break; default: diff --git a/libgnucash/app-utils/gnc-ui-util.c b/libgnucash/app-utils/gnc-ui-util.c index 5fa6430842..30535c7b7a 100644 --- a/libgnucash/app-utils/gnc-ui-util.c +++ b/libgnucash/app-utils/gnc-ui-util.c @@ -80,6 +80,11 @@ static gboolean reverse_type[NUM_ACCOUNT_TYPES]; * as that will change any time the book changes. */ static gchar *user_default_currency = NULL; static gchar *user_report_currency = NULL; +const static int maximum_decimals = 15; +static const gint64 pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, + 10000000, 100000000, 1000000000, 10000000000, + 100000000000, 1000000000000, 10000000000000, + 100000000000000, 1000000000000000}; gchar *gnc_normalize_account_separator (const gchar* separator) { @@ -1317,17 +1322,31 @@ gnc_share_print_info_places (int decplaces) } GNCPrintAmountInfo -gnc_default_price_print_info (void) +gnc_default_price_print_info (const gnc_commodity *curr) { - static GNCPrintAmountInfo info; - static gboolean got_it = FALSE; + GNCPrintAmountInfo info; + info.commodity = curr; - if (!got_it) + if (info.commodity) { - info = gnc_default_print_info_helper (6); - got_it = TRUE; + int frac = gnc_commodity_get_fraction (curr); + guint8 decplaces = 2; + while (frac != 1 && (frac % 10) == 0 && (frac /= 10)) ++decplaces; + info.max_decimal_places = decplaces; + info.min_decimal_places = decplaces; + } + else + { + info.max_decimal_places = 6; + info.min_decimal_places = 0; } + info.use_separators = 1; + info.use_symbol = 0; + info.use_locale = 1; + info.monetary = 1; + info.force_fit = TRUE; + info.round = TRUE; return info; } @@ -1373,7 +1392,22 @@ PrintAmountInternal(char *buf, gnc_numeric val, const GNCPrintAmountInfo *info) /* Try to print as decimal. */ value_is_decimal = gnc_numeric_to_decimal(&val, NULL); - + if (!value_is_decimal && info->force_fit && info->round) + { + gint64 denom = pow10[maximum_decimals]; + /* if there's a commodity use 100x the commodity's fraction. N.B. This + * assumes that commodity fractions are multiples of 10, a reasonable + * assumption in 2018. Otherwise, if there's a reasonable + * max_decimal_places, use that. + */ + if (info->commodity) + denom = gnc_commodity_get_fraction(info->commodity) * 100; + else if (info->max_decimal_places && + info->max_decimal_places <= maximum_decimals) + denom = pow10[info->max_decimal_places]; + val = gnc_numeric_convert(val, denom, GNC_HOW_RND_ROUND_HALF_UP); + value_is_decimal = gnc_numeric_to_decimal(&val, NULL); + } /* Force at least auto_decimal_places zeros */ if (auto_decimal_enabled) { diff --git a/libgnucash/app-utils/gnc-ui-util.h b/libgnucash/app-utils/gnc-ui-util.h index 7161bca31e..884bdc6214 100644 --- a/libgnucash/app-utils/gnc-ui-util.h +++ b/libgnucash/app-utils/gnc-ui-util.h @@ -293,7 +293,7 @@ GNCPrintAmountInfo gnc_split_amount_print_info (Split *split, GNCPrintAmountInfo gnc_share_print_info_places (int decplaces); GNCPrintAmountInfo gnc_default_share_print_info (void); -GNCPrintAmountInfo gnc_default_price_print_info (void); +GNCPrintAmountInfo gnc_default_price_print_info (const gnc_commodity *curr); GNCPrintAmountInfo gnc_integral_print_info (void);