diff --git a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp index 6c4279a813..120367a58e 100644 --- a/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp +++ b/gnucash/import-export/csv-imp/assistant-csv-price-import.cpp @@ -90,6 +90,8 @@ public: void preview_update_encoding (const char* encoding); void preview_update_date_format (); void preview_update_currency_format (); + void preview_update_currency (); + void preview_update_commodity (); void preview_update_col_type (GtkComboBox* cbox); void preview_update_fw_columns (GtkTreeView* treeview, GdkEventButton* event); @@ -134,6 +136,8 @@ private: GtkWidget *csv_button; /**< The widget for the CSV button */ GtkWidget *fixed_button; /**< The widget for the Fixed Width button */ GtkWidget *over_write_cbutton; /**< The widget for Price Over Write */ + GtkWidget *commodity_selector; /**< The widget for commodity combo box */ + GtkWidget *currency_selector; /**< The widget for currency combo box */ GOCharmapSel *encselector; /**< The widget for selecting the encoding */ GtkWidget *separator_table; /**< Container for the separator checkboxes */ GtkCheckButton *sep_button[SEP_NUM_OF_TYPES]; /**< Checkbuttons for common separators */ @@ -321,6 +325,16 @@ static void csv_price_imp_preview_currency_fmt_sel_cb (GtkComboBox* format_selec info->preview_update_currency_format(); } +static void csv_price_imp_preview_currency_sel_cb (GtkComboBox* currency_selector, CsvImpPriceAssist* info) +{ + info->preview_update_currency(); +} + +static void csv_price_imp_preview_commodity_sel_cb (GtkComboBox* commodity_selector, CsvImpPriceAssist* info) +{ + info->preview_update_commodity(); +} + void csv_price_imp_preview_col_type_changed_cb (GtkComboBox* cbox, CsvImpPriceAssist* info) { info->preview_update_col_type (cbox); @@ -334,6 +348,126 @@ csv_price_imp_preview_treeview_clicked_cb (GtkTreeView* treeview, GdkEventButton return false; } +static +gnc_commodity *get_commodity_from_combo (GtkComboBox *combo) +{ + GtkTreeModel *model, *sort_model; + GtkTreeIter iter, siter; + gchar *string; + gnc_commodity *comm; + + if (!gtk_combo_box_get_active_iter (combo, &siter)) + return nullptr; + + sort_model = gtk_combo_box_get_model (combo); + model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT(sort_model)); + + gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT(sort_model), + &iter, &siter); + + gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &string, 2, &comm, -1); + + PINFO("Commodity string is %s", string); + + g_free (string); + return comm; +} + +static void +set_commodity_for_combo (GtkComboBox *combo, gnc_commodity *comm) +{ + GtkTreeModel *model, *sort_model; + GtkTreeIter iter, siter; + gnc_commodity *model_comm; + gboolean valid; + + sort_model = gtk_combo_box_get_model (combo); + model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT(sort_model)); + valid = gtk_tree_model_get_iter_first (model, &iter); + + while (valid) + { + gtk_tree_model_get (model, &iter, 2, &model_comm, -1); + if (model_comm == comm) + { + if (gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(sort_model), &siter, &iter)) + { + gtk_combo_box_set_active_iter (combo, &siter); + return; + } + } + /* Make iter point to the next row in the list store */ + valid = gtk_tree_model_iter_next (model, &iter); + } + // Not found, set it to first iter + valid = gtk_tree_model_get_iter_first (model, &iter); + if (gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT(sort_model), &siter, &iter)) + gtk_combo_box_set_active_iter (combo, &siter); +} + +static +GtkTreeModel *get_model (bool all_commodity) +{ + GtkTreeModel *store, *model; + const gnc_commodity_table *commodity_table = gnc_get_current_commodities (); + gnc_commodity *tmp_commodity = nullptr; + char *tmp_namespace = nullptr; + GList *commodity_list = nullptr; + GList *namespace_list = gnc_commodity_table_get_namespaces (commodity_table); + GtkTreeIter iter; + + store = GTK_TREE_MODEL(gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER)); + model = gtk_tree_model_sort_new_with_model (store); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + 0, GTK_SORT_ASCENDING); + + gtk_list_store_append (GTK_LIST_STORE(store), &iter); + gtk_list_store_set (GTK_LIST_STORE(store), &iter, 0, " ", 1, nullptr, -1); + + namespace_list = g_list_first (namespace_list); + while (namespace_list != nullptr) + { + tmp_namespace = (char*)namespace_list->data; + DEBUG("Looking at namespace %s", tmp_namespace); + + /* Hide the template entry */ + if (g_utf8_collate (tmp_namespace, "template" ) != 0) + { + if ((g_utf8_collate (tmp_namespace, GNC_COMMODITY_NS_CURRENCY ) == 0) || (all_commodity == true)) + { + commodity_list = gnc_commodity_table_get_commodities (commodity_table, tmp_namespace); + commodity_list = g_list_first (commodity_list); + while (commodity_list != nullptr) + { + gchar *name_str; + gchar *save_str; + gchar *settings_str; + tmp_commodity = (gnc_commodity*)commodity_list->data; + DEBUG("Looking at commodity %s", gnc_commodity_get_fullname (tmp_commodity)); + + name_str = g_strconcat (tmp_namespace, " : (", gnc_commodity_get_mnemonic (tmp_commodity), + ") ", gnc_commodity_get_fullname (tmp_commodity), nullptr); + + settings_str = g_strconcat (tmp_namespace, "::", gnc_commodity_get_mnemonic (tmp_commodity), nullptr); + DEBUG("Name string is %s, Save string is %s", name_str, settings_str); + + gtk_list_store_append (GTK_LIST_STORE(store), &iter); + gtk_list_store_set (GTK_LIST_STORE(store), &iter, 0, name_str, 1, settings_str, 2, tmp_commodity, -1); + + g_free (name_str); + g_free (settings_str); + commodity_list = g_list_next (commodity_list); + } + } + } + namespace_list = g_list_next (namespace_list); + } + g_list_free (commodity_list); + g_list_free (namespace_list); + + return model; +} + /******************************************************* * Assistant Constructor @@ -343,6 +477,8 @@ CsvImpPriceAssist::CsvImpPriceAssist () auto builder = gtk_builder_new(); gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "start_row_adj"); gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "end_row_adj"); + gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "liststore1"); + gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "liststore2"); gnc_builder_add_from_file (builder , "assistant-csv-price-import.glade", "CSV Price Assistant"); csv_imp_asst = GTK_ASSISTANT(gtk_builder_get_object (builder, "CSV Price Assistant")); @@ -453,6 +589,18 @@ CsvImpPriceAssist::CsvImpPriceAssist () gtk_container_add (encoding_container, GTK_WIDGET(encselector)); gtk_widget_show_all (GTK_WIDGET(encoding_container)); + /* Add commodity selection widget */ + commodity_selector = GTK_WIDGET(gtk_builder_get_object (builder, "commodity_cbox")); + gtk_combo_box_set_model (GTK_COMBO_BOX(commodity_selector), get_model (true)); + g_signal_connect(G_OBJECT(commodity_selector), "changed", + G_CALLBACK(csv_price_imp_preview_commodity_sel_cb), this); + + /* Add currency selection widget */ + currency_selector = GTK_WIDGET(gtk_builder_get_object (builder, "currency_cbox")); + gtk_combo_box_set_model (GTK_COMBO_BOX(currency_selector), get_model (false)); + g_signal_connect(G_OBJECT(currency_selector), "changed", + G_CALLBACK(csv_price_imp_preview_currency_sel_cb), this); + /* The instructions label and image */ instructions_label = GTK_LABEL(gtk_builder_get_object (builder, "instructions_label")); instructions_image = GTK_IMAGE(gtk_builder_get_object (builder, "instructions_image")); @@ -570,6 +718,9 @@ CsvImpPriceAssist::file_confirm_cb () preview_populate_settings_combo(); gtk_combo_box_set_active (settings_combo, 0); + // set over_write to false as default + price_imp->over_write (false); + auto num = gtk_assistant_get_current_page (csv_imp_asst); gtk_assistant_set_current_page (csv_imp_asst, num + 1); } @@ -951,6 +1102,22 @@ CsvImpPriceAssist::preview_update_currency_format () preview_refresh_table (); } +void +CsvImpPriceAssist::preview_update_currency () +{ + gnc_commodity *comm = get_commodity_from_combo (GTK_COMBO_BOX(currency_selector)); + price_imp->to_currency (comm); + preview_refresh_table (); +} + +void +CsvImpPriceAssist::preview_update_commodity () +{ + gnc_commodity *comm = get_commodity_from_combo (GTK_COMBO_BOX(commodity_selector)); + price_imp->from_commodity (comm); + preview_refresh_table (); +} + gboolean csv_imp_preview_queue_rebuild_table (CsvImpPriceAssist *assist) { @@ -1413,6 +1580,28 @@ void CsvImpPriceAssist::preview_refresh_table () for (uint32_t i = 0; i < ntcols; i++) preview_style_column (i, combostore); + auto column_types = price_imp->column_types_price(); + + // look for a commodity column, clear the commdoity combo + auto col_type_comm = std::find (column_types.begin(), + column_types.end(), GncPricePropType::FROM_COMMODITY); + if (col_type_comm != column_types.end()) + { + g_signal_handlers_block_by_func (commodity_selector, (gpointer) csv_price_imp_preview_commodity_sel_cb, this); + set_commodity_for_combo (GTK_COMBO_BOX(commodity_selector), nullptr); + g_signal_handlers_unblock_by_func (commodity_selector, (gpointer) csv_price_imp_preview_commodity_sel_cb, this); + } + + // look for a currency column, clear the currency combo + auto col_type_curr = std::find (column_types.begin(), + column_types.end(), GncPricePropType::TO_CURRENCY); + if (col_type_curr != column_types.end()) + { + g_signal_handlers_block_by_func (currency_selector, (gpointer) csv_price_imp_preview_currency_sel_cb, this); + set_commodity_for_combo (GTK_COMBO_BOX(currency_selector), nullptr); + g_signal_handlers_unblock_by_func (currency_selector, (gpointer) csv_price_imp_preview_currency_sel_cb, this); + } + /* Release our reference for the stores to allow proper memory management. */ g_object_unref (store); g_object_unref (combostore); @@ -1460,6 +1649,13 @@ CsvImpPriceAssist::preview_refresh () price_imp->currency_format()); go_charmap_sel_set_encoding (encselector, price_imp->encoding().c_str()); + // Set the commodity and currency combos + set_commodity_for_combo(GTK_COMBO_BOX(commodity_selector), + price_imp->from_commodity()); + + set_commodity_for_combo(GTK_COMBO_BOX(currency_selector), + price_imp->to_currency()); + // Handle separator checkboxes and custom field, only relevant if the file format is csv if (price_imp->file_format() == GncImpFileFormat::CSV) { @@ -1533,9 +1729,9 @@ CsvImpPriceAssist::assist_summary_page_prepare () auto text = std::string(""); text += _("The prices were imported from the file '") + m_file_name + "'."; text += _("\n\nThe number of Prices added was ") + std::to_string(price_imp->m_prices_added); - text += _(" and ") + std::to_string(price_imp->m_prices_duplicated); - text += _(" were duplicated."); - text += ""; + text += _(", duplicated was ") + std::to_string(price_imp->m_prices_duplicated); + text += _(" and replaced was ") + std::to_string(price_imp->m_prices_replaced); + text += "."; gtk_label_set_markup (GTK_LABEL(summary_label), text.c_str()); } diff --git a/gnucash/import-export/csv-imp/assistant-csv-price-import.glade b/gnucash/import-export/csv-imp/assistant-csv-price-import.glade index 705e8274aa..764b1967a2 100644 --- a/gnucash/import-export/csv-imp/assistant-csv-price-import.glade +++ b/gnucash/import-export/csv-imp/assistant-csv-price-import.glade @@ -7,6 +7,26 @@ 1 10 + + + + + + + + + + + + + + + + + + + + 1000 1 @@ -515,7 +535,7 @@ Select location and file name for the Import, then click 'OK'... True True False - Normally prices are not over written, select this to change that. + Normally prices are not over written, select this to change that. This setting is not saved. True @@ -804,6 +824,9 @@ For example GTK_FILL + + + False @@ -811,6 +834,125 @@ For example 0 + + + True + False + + + True + False + 0 + none + + + True + False + 5 + 5 + 5 + + + True + False + + + True + False + liststore1 + + + + 0 + + + + + False + False + 0 + + + + + + + + + True + False + <b>Commodity From</b> + True + + + + + False + False + 0 + + + + + True + False + 0 + none + + + True + False + 5 + 5 + 5 + + + True + False + + + True + False + liststore1 + + + + 0 + + + + + False + False + 0 + + + + + + + + + True + False + <b>Currency To</b> + True + + + + + False + False + 2 + + + + + False + False + 1 + + True @@ -860,7 +1002,7 @@ For example True True - 1 + 2 @@ -902,7 +1044,7 @@ For example False False 5 - 2 + 3 @@ -930,7 +1072,7 @@ For example False False - 3 + 4 diff --git a/gnucash/import-export/csv-imp/gnc-price-import.cpp b/gnucash/import-export/csv-imp/gnc-price-import.cpp index 5437237ef1..e7bb72a0e5 100644 --- a/gnucash/import-export/csv-imp/gnc-price-import.cpp +++ b/gnucash/import-export/csv-imp/gnc-price-import.cpp @@ -125,7 +125,6 @@ void GncPriceImport::file_format(GncImpFileFormat format) auto fwtok = dynamic_cast(m_tokenizer.get()); fwtok->columns (m_settings.m_column_widths); } - } GncImpFileFormat GncPriceImport::file_format() @@ -140,6 +139,50 @@ void GncPriceImport::over_write (bool over) bool GncPriceImport::over_write () { return m_over_write; } +/** Sets a from commodity. This is the commodity all import data relates to. + * When a from commodity is set, there can't be any from columns selected + * in the import data. + * @param from_commodity Pointer to a commodity or NULL. + */ +void GncPriceImport::from_commodity (gnc_commodity* from_commodity) +{ + m_settings.m_from_commodity = from_commodity; + + if (m_settings.m_from_commodity) + { + auto col_type = std::find (m_settings.m_column_types_price.begin(), + m_settings.m_column_types_price.end(), GncPricePropType::FROM_COMMODITY); + + if (col_type != m_settings.m_column_types_price.end()) + set_column_type_price (col_type -m_settings.m_column_types_price.begin(), + GncPricePropType::NONE); + } +} + +gnc_commodity *GncPriceImport::from_commodity () { return m_settings.m_from_commodity; } + +/** Sets a to currency. This is the to currency all import data relates to. + * When a to currency is set, there can't be any to currency columns selected + * in the import data. + * @param to_currency Pointer to a commodity or NULL. + */ +void GncPriceImport::to_currency (gnc_commodity* to_currency) +{ + m_settings.m_to_currency = to_currency; + + if (m_settings.m_to_currency) + { + auto col_type = std::find (m_settings.m_column_types_price.begin(), + m_settings.m_column_types_price.end(), GncPricePropType::TO_CURRENCY); + + if (col_type != m_settings.m_column_types_price.end()) + set_column_type_price (col_type -m_settings.m_column_types_price.begin(), + GncPricePropType::NONE); + } +} + +gnc_commodity *GncPriceImport::to_currency () { return m_settings.m_to_currency; } + void GncPriceImport::reset_formatted_column (std::vector& col_types) { for (auto col_type: col_types) @@ -241,6 +284,8 @@ void GncPriceImport::settings (const CsvTransSettings& settings) /* First apply file format as this may recreate the tokenizer */ file_format (settings.m_file_format); /* Only then apply the other settings */ + from_commodity (m_settings.m_from_commodity); + to_currency (m_settings.m_to_currency); m_settings = settings; encoding (m_settings.m_encoding); @@ -402,14 +447,19 @@ void GncPriceImport::verify_column_selections (ErrorListPrice& error_msg) /* Verify a Currency to column is selected. */ - if (!check_for_column_type(GncPricePropType::CURRENCY_TO)) - error_msg.add_error( _("Please select a Currency to column.")); + if (!check_for_column_type(GncPricePropType::TO_CURRENCY)) + { + if (!m_settings.m_to_currency) + error_msg.add_error( _("Please select a Currency to column or set a Currency in the Currency To field.")); + } - /* Verify at least one from column (symbol_from or currency_from) column is selected. + /* Verify a Commodity from column is selected. */ - if (!check_for_column_type(GncPricePropType::SYMBOL_FROM) && - !check_for_column_type(GncPricePropType::CURRENCY_FROM)) - error_msg.add_error( _("Please select a symbol or currency from column.")); + if (!check_for_column_type(GncPricePropType::FROM_COMMODITY)) + { + if (!m_settings.m_from_commodity) + error_msg.add_error( _("Please select a Commodity from column or set a Commodity in the Commodity From field.")); + } } @@ -497,6 +547,40 @@ void GncPriceImport::create_price (std::vector::iterator& parsed_l error_message.clear(); + // Add a CURRENCY_TO property with the default currency to if no currency to column was set by the user + auto line_to_currency = price_props->get_to_currency(); + if (!line_to_currency) + { + if (m_settings.m_to_currency) + price_props->set_to_currency(m_settings.m_to_currency); + else + { + // Oops - the user didn't select an Account column *and* we didn't get a default value either! + // Note if you get here this suggests a bug in the code! + error_message = _("No Currency to column selected and no default Currency specified either.\n" + "This should never happen. Please report this as a bug."); + PINFO("User warning: %s", error_message.c_str()); + throw std::invalid_argument(error_message); + } + } + + // Add a COMMODITY_FROM property with the default commodity from if no commodity from column was set by the user + auto line_from_commodity = price_props->get_from_commodity(); + if (!line_from_commodity) + { + if (m_settings.m_from_commodity) + price_props->set_from_commodity(m_settings.m_from_commodity); + else + { + // Oops - the user didn't select an Account column *and* we didn't get a default value either! + // Note if you get here this suggests a bug in the code! + error_message = _("No Commodity from column selected and no default Commodity specified either.\n" + "This should never happen. Please report this as a bug."); + PINFO("User warning: %s", error_message.c_str()); + throw std::invalid_argument(error_message); + } + } + /* If column parsing was successful, convert price properties into a price. */ try { @@ -507,11 +591,12 @@ void GncPriceImport::create_price (std::vector::iterator& parsed_l /* If all went well, add this price to the list. */ auto price_created = price_props->create_price (book, pdb, m_over_write); -//FIXME Need to look at this - if (price_created) + if (price_created == ADDED) m_prices_added++; - else + else if (price_created == DUPLICATED) m_prices_duplicated++; + else if (price_created == REPLACED) + m_prices_replaced++; } catch (const std::invalid_argument& e) { @@ -537,6 +622,7 @@ void GncPriceImport::create_prices () m_prices_added = 0; m_prices_duplicated = 0; + m_prices_replaced = 0; /* Iterate over all parsed lines */ for (auto parsed_lines_it = m_parsed_lines.begin(); @@ -550,8 +636,8 @@ void GncPriceImport::create_prices () /* Should not throw anymore, otherwise verify needs revision */ create_price (parsed_lines_it); } - PINFO("Number of lines is %d, added is %d, duplicates is %d", - (int)m_parsed_lines.size(), m_prices_added, m_prices_duplicated); + PINFO("Number of lines is %d, added %d, duplicated %d, replaced %d", + (int)m_parsed_lines.size(), m_prices_added, m_prices_duplicated, m_prices_replaced); } bool @@ -611,6 +697,14 @@ GncPriceImport::set_column_type_price (uint32_t position, GncPricePropType type, m_settings.m_column_types_price.at (position) = type; + // If the user has set a Commodity from column, we can't have a commodity from default set + if (type == GncPricePropType::FROM_COMMODITY) + from_commodity (nullptr); + + // If the user has set a Currency to column, we can't have a currency to default set + if (type == GncPricePropType::TO_CURRENCY) + to_currency (nullptr); + /* Update the preparsed data */ for (auto parsed_lines_it = m_parsed_lines.begin(); parsed_lines_it != m_parsed_lines.end(); diff --git a/gnucash/import-export/csv-imp/gnc-price-import.hpp b/gnucash/import-export/csv-imp/gnc-price-import.hpp index 60cdc27807..809464eaea 100644 --- a/gnucash/import-export/csv-imp/gnc-price-import.hpp +++ b/gnucash/import-export/csv-imp/gnc-price-import.hpp @@ -32,7 +32,7 @@ extern "C" { #include "config.h" - +#include "gnc-commodity.h" } #include @@ -85,6 +85,12 @@ public: void over_write (bool over); bool over_write (); + void from_commodity (gnc_commodity *from_commodity); + gnc_commodity *from_commodity (); + + void to_currency (gnc_commodity *to_currency); + gnc_commodity *to_currency (); + void currency_format (int currency_format); int currency_format (); @@ -131,6 +137,7 @@ public: price properties. */ int m_prices_added; int m_prices_duplicated; + int m_prices_replaced; private: /** A helper function used by create_prices. It will attempt diff --git a/gnucash/import-export/csv-imp/gnc-price-props.cpp b/gnucash/import-export/csv-imp/gnc-price-props.cpp index a39f178851..e6f983e525 100644 --- a/gnucash/import-export/csv-imp/gnc-price-props.cpp +++ b/gnucash/import-export/csv-imp/gnc-price-props.cpp @@ -32,8 +32,6 @@ extern "C" { #include "engine-helpers.h" #include "gnc-ui-util.h" -#include "gnc-pricedb.h" - } #include @@ -48,9 +46,8 @@ std::map gnc_price_col_type_strs = { { GncPricePropType::NONE, N_("None") }, { GncPricePropType::DATE, N_("Date") }, { GncPricePropType::AMOUNT, N_("Amount") }, - { GncPricePropType::CURRENCY_FROM, N_("Currency From") }, - { GncPricePropType::CURRENCY_TO, N_("Currency To") }, - { GncPricePropType::SYMBOL_FROM, N_("Symbol From") }, + { GncPricePropType::FROM_COMMODITY, N_("Commodity From") }, + { GncPricePropType::TO_CURRENCY, N_("Currency To") }, }; /* Regular expressions used to parse dates per date format */ @@ -243,6 +240,7 @@ gnc_commodity* parse_commodity_price_comm (const std::string& comm_str) return comm; } +//FIXME can we change above to do below gnc_commodity * parse_commodity_price_sym (const std::string& sym_str, bool is_currency) { if (sym_str.empty()) @@ -285,8 +283,8 @@ gnc_commodity * parse_commodity_price_sym (const std::string& sym_str, bool is_c throw std::invalid_argument (_("Value can't be parsed into a valid commodity.")); else { - if (gnc_commodity_is_currency (retval) != is_currency) - throw std::invalid_argument (_("Value parsed into an invalid commodity for column type.")); + if ((is_currency == true) && (gnc_commodity_is_currency (retval) != true)) + throw std::invalid_argument (_("Value parsed into an invalid currency for currency column type.")); else return retval; } @@ -312,25 +310,18 @@ void GncImportPrice::set (GncPricePropType prop_type, const std::string& value) m_amount = parse_amount_price (value, m_currency_format); // Will throw if parsing fails break; - case GncPricePropType::CURRENCY_FROM: - m_currency_from = boost::none; - comm = parse_commodity_price_sym (value, true); // Throws if parsing fails - if (comm) - m_currency_from = comm; - break; - - case GncPricePropType::CURRENCY_TO: - m_currency_to = boost::none; - comm = parse_commodity_price_sym (value, true); // Throws if parsing fails - if (comm) - m_currency_to = comm; - break; - - case GncPricePropType::SYMBOL_FROM: - m_symbol_from = boost::none; + case GncPricePropType::FROM_COMMODITY: + m_from_commodity = boost::none; comm = parse_commodity_price_sym (value, false); // Throws if parsing fails if (comm) - m_symbol_from = comm; + m_from_commodity = comm; + break; + + case GncPricePropType::TO_CURRENCY: + m_to_currency = boost::none; + comm = parse_commodity_price_sym (value, true); // Throws if parsing fails + if (comm) + m_to_currency = comm; break; default: @@ -378,15 +369,15 @@ std::string GncImportPrice::verify_essentials (void) return _("No date column."); else if (m_amount == boost::none) return _("No amount column."); - else if (m_currency_to == boost::none) + else if (m_to_currency == boost::none) return _("No Currency to column."); - else if ((m_symbol_from == boost::none) && (m_currency_from == boost::none)) - return _("No from column."); + else if (m_from_commodity == boost::none) + return _("No Commodity from column."); else return std::string(); } -bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over) +Result GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over) { /* Gently refuse to create the price if the basics are not set correctly * This should have been tested before calling this function though! @@ -395,47 +386,40 @@ bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over) if (!check.empty()) { PWARN ("Refusing to create price because essentials not set properly: %s", check.c_str()); - return false; + return FAILED; } Timespec date; timespecFromTime64 (&date, *m_date); date.tv_nsec = 0; -#ifdef skip -//FIXME Numeric needs changing, copied from old version... bool rev = false; - gnc_commodity *comm_from = nullptr; + auto amount = *m_amount; - if (m_currency_from != boost::none) // Currency Import + GNCPrice *old_price = gnc_pricedb_lookup_day (pdb, *m_from_commodity, *m_to_currency, date); + + if (gnc_commodity_is_currency (*m_from_commodity)) // Currency Import { // Check for currency in reverse direction. - GNCPrice *rev_price = gnc_pricedb_lookup_day (pdb, *m_currency_to, *m_currency_from, date); - if (rev_price != nullptr) - rev = true; - gnc_price_unref (rev_price); + if (old_price != nullptr) + { + // Check for price in reverse direction. + if (gnc_commodity_equiv (gnc_price_get_currency (old_price), *m_from_commodity)) + rev = true; + + DEBUG("Commodity from is a Currency"); + } // Check for price less than 1, reverse if so. - if (gnc_numeric_compare (*m_amount, gnc_numeric_create (1, 1)) != 1) + if (*m_amount < GncNumeric(1,1)) rev = true; - comm_from = *m_currency_from; - DEBUG("Commodity from is a Currency"); } - else - comm_from = *m_symbol_from; - DEBUG("Date is %s, Rev is %d, Commodity from is '%s', Currency is '%s', Amount is %s", gnc_print_date (date), - rev, gnc_commodity_get_fullname (comm_from), gnc_commodity_get_fullname (*m_currency_to), - gnc_num_dbg_to_string (*m_amount) ); + rev, gnc_commodity_get_fullname (*m_from_commodity), gnc_commodity_get_fullname (*m_to_currency), + amount.to_string().c_str()); - GNCPrice *old_price = nullptr; - - // Should the commodities be reversed - if (rev) - old_price = gnc_pricedb_lookup_day (pdb, *m_currency_to, comm_from, date); - else - old_price = gnc_pricedb_lookup_day (pdb, comm_from, *m_currency_to, date); + Result ret_val = ADDED; // Should old price be over writen if ((old_price != nullptr) && (over == true)) @@ -444,31 +428,29 @@ bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over) gnc_pricedb_remove_price (pdb, old_price); gnc_price_unref (old_price); old_price = nullptr; + ret_val = REPLACED; } -#endif - bool ret_val = true; -#ifdef skip + // Create the new price if (old_price == nullptr) { DEBUG("Create"); GNCPrice *price = gnc_price_create (book); gnc_price_begin_edit (price); - if (rev) { - gnc_price_set_commodity (price, *m_currency_to); - gnc_price_set_currency (price, comm_from); - *m_amount = gnc_numeric_convert (gnc_numeric_invert (*m_amount), - CURRENCY_DENOM, GNC_HOW_RND_ROUND_HALF_UP); - gnc_price_set_value (price, *m_amount); + amount = amount.inv(); //invert the amount + gnc_price_set_commodity (price, *m_to_currency); + gnc_price_set_currency (price, *m_from_commodity); } else { - gnc_price_set_commodity (price, comm_from); - gnc_price_set_currency (price, *m_currency_to); - gnc_price_set_value (price, *m_amount); + gnc_price_set_commodity (price, *m_from_commodity); + gnc_price_set_currency (price, *m_to_currency); } + auto amount_conv = amount.convert(CURRENCY_DENOM); + gnc_price_set_value (price, static_cast(amount_conv)); + gnc_price_set_time (price, date); gnc_price_set_source (price, PRICE_SOURCE_USER_PRICE); //FIXME Not sure which one gnc_price_set_source (price, PRICE_SOURCE_FQ); @@ -479,15 +461,15 @@ bool GncImportPrice::create_price (QofBook* book, GNCPriceDB *pdb, bool over) gnc_price_unref (price); - if (perr == false) + if (perr == false) throw std::invalid_argument (_("Failed to create price from selected columns.")); //FIXME Not sure about this, should this be a PWARN } else - -#endif - ret_val = false; - + { + gnc_price_unref (old_price); + ret_val = DUPLICATED; + } return ret_val; } diff --git a/gnucash/import-export/csv-imp/gnc-price-props.hpp b/gnucash/import-export/csv-imp/gnc-price-props.hpp index 57083e9a4b..a8550ea1e3 100644 --- a/gnucash/import-export/csv-imp/gnc-price-props.hpp +++ b/gnucash/import-export/csv-imp/gnc-price-props.hpp @@ -49,12 +49,13 @@ enum class GncPricePropType { NONE, DATE, AMOUNT, - CURRENCY_FROM, - CURRENCY_TO, - SYMBOL_FROM, - PRICE_PROPS = SYMBOL_FROM + FROM_COMMODITY, + TO_CURRENCY, + PRICE_PROPS = TO_CURRENCY }; +enum Result { FAILED, ADDED, DUPLICATED, REPLACED }; + /** Maps all column types to a string representation. * The actual definition is in gnc-price-props.cpp. * Attention: that definition should be adjusted for any @@ -91,7 +92,14 @@ public: void set_currency_format (int currency_format) { m_currency_format = currency_format ;} void reset (GncPricePropType prop_type); std::string verify_essentials (void); - bool create_price (QofBook* book, GNCPriceDB *pdb, bool over); + Result create_price (QofBook* book, GNCPriceDB *pdb, bool over); + + gnc_commodity* get_from_commodity () { if (m_from_commodity) return *m_from_commodity; else return nullptr; } + void set_from_commodity (gnc_commodity* comm) { if (comm) m_from_commodity = comm; else m_from_commodity = boost::none; } + + gnc_commodity* get_to_currency () { if (m_to_currency) return *m_to_currency; else return nullptr; } + void set_to_currency (gnc_commodity* curr) { if (curr) m_to_currency = curr; else m_to_currency = boost::none; } + std::string errors(); private: @@ -99,9 +107,8 @@ private: int m_currency_format; boost::optional m_date; boost::optional m_amount; - boost::optional m_currency_from; - boost::optional m_currency_to; - boost::optional m_symbol_from; + boost::optional m_from_commodity; + boost::optional m_to_currency; bool created = false; std::map m_errors;