/** Adds a split to a transaction. * @param trans The transaction to add a split to * @param account The split's account * @param amount The split's amount * @param rec_state The split's reconcile status * @param rec_date The split's reconcile date * @param price The split's conversion rate from account commodity to transaction commodity */ static void trans_add_split (Transaction* trans, Account* account, GncNumeric amount, const boost::optional<std::string>& action, const boost::optional<std::string>& memo, const boost::optional<char>& rec_state, const boost::optional<GncDate>& rec_date, const boost::optional<GncNumeric> price) { QofBook* book = xaccTransGetBook (trans); auto split = xaccMallocSplit (book); xaccSplitSetAccount (split, account); xaccSplitSetParent (split, trans); xaccSplitSetAmount (split, static_cast<gnc_numeric>(amount)); auto trans_curr = xaccTransGetCurrency(trans); auto acct_comm = xaccAccountGetCommodity(account); GncNumeric value; if (gnc_commodity_equiv(trans_curr, acct_comm)) value = amount; else if (price) value = amount * *price; else { auto time = xaccTransRetDatePosted (trans); /* Import data didn't specify price, let's lookup the nearest in time */ auto nprice = gnc_pricedb_lookup_nearest_in_time64(gnc_pricedb_get_db(book), acct_comm, trans_curr, time); if (nprice) { /* Found a usable price. Let's check if the conversion direction is right */ GncNumeric rate; if (gnc_commodity_equiv(gnc_price_get_currency(nprice), trans_curr)) rate = gnc_price_get_value(nprice); else rate = static_cast<GncNumeric>(gnc_price_get_value(nprice)).inv(); value = amount * rate; } else { PWARN("No price found, using a price of 1."); value = amount; } } xaccSplitSetValue (split, static_cast<gnc_numeric>(value)); if (memo) xaccSplitSetMemo (split, memo->c_str()); /* Note, this function assumes the num/action switch is done at a higher level * if needed by the book option */ if (action) xaccSplitSetAction (split, action->c_str()); if (rec_state && *rec_state != 'n') xaccSplitSetReconcile (split, *rec_state); if (rec_state && *rec_state == YREC && rec_date) xaccSplitSetDateReconciledSecs (split, static_cast<time64>(GncDateTime(*rec_date, DayPart::neutral))); }
/* * Given an owner, extract the open balance from the owner and then * convert it to the desired currency. */ gnc_numeric gncOwnerGetBalanceInCurrency (const GncOwner *owner, const gnc_commodity *report_currency) { gnc_numeric balance = gnc_numeric_zero (); GList *acct_list, *acct_node, *acct_types, *lot_list = NULL, *lot_node; QofBook *book; gnc_commodity *owner_currency; GNCPriceDB *pdb; g_return_val_if_fail (owner, gnc_numeric_zero ()); /* Get account list */ book = qof_instance_get_book (qofOwnerGetOwner (owner)); acct_list = gnc_account_get_descendants (gnc_book_get_root_account (book)); acct_types = gncOwnerGetAccountTypesList (owner); owner_currency = gncOwnerGetCurrency (owner); /* For each account */ for (acct_node = acct_list; acct_node; acct_node = acct_node->next) { Account *account = acct_node->data; /* Check if this account can have lots for the owner, otherwise skip to next */ if (g_list_index (acct_types, (gpointer)xaccAccountGetType (account)) == -1) continue; if (!gnc_commodity_equal (owner_currency, xaccAccountGetCommodity (account))) continue; /* Get a list of open lots for this owner and account */ lot_list = xaccAccountFindOpenLots (account, gncOwnerLotMatchOwnerFunc, (gpointer)owner, NULL); /* For each lot */ for (lot_node = lot_list; lot_node; lot_node = lot_node->next) { GNCLot *lot = lot_node->data; gnc_numeric lot_balance = gnc_lot_get_balance (lot); GncInvoice *invoice = gncInvoiceGetInvoiceFromLot(lot); if (invoice) balance = gnc_numeric_add (balance, lot_balance, gnc_commodity_get_fraction (owner_currency), GNC_HOW_RND_ROUND_HALF_UP); } } pdb = gnc_pricedb_get_db (book); if (report_currency) balance = gnc_pricedb_convert_balance_latest_price ( pdb, balance, owner_currency, report_currency); return balance; }
static gboolean test_add_pricedb (const char* tag, gpointer globaldata, gpointer data) { sixtp_gdv2* gdata = static_cast<decltype (gdata)> (globaldata); GNCPriceDB* db1 = static_cast<decltype (db1)> (data); GNCPriceDB* db2 = gnc_pricedb_get_db (gdata->book); do_test_args (gnc_pricedb_equal (db1, db2), "gnc_pricedb_sixtp_parser_create", __FILE__, __LINE__, "%d", iter); return TRUE; }
static gboolean write_prices (GncSqlBackend* be) { GNCPriceDB* priceDB; write_objects_t data; g_return_val_if_fail (be != NULL, FALSE); priceDB = gnc_pricedb_get_db (be->book); data.be = be; data.is_ok = TRUE; return gnc_pricedb_foreach_price (priceDB, write_price, &data, TRUE); }
/* Get the rate from the price db */ static gnc_numeric gtu_sr_get_rate_from_db (gnc_commodity *from, gnc_commodity *to) { GNCPrice *prc; gnc_numeric rate_split; gboolean have_rate = FALSE; QofBook *book = gnc_get_current_book (); /* Do we have a rate allready */ prc = gnc_pricedb_lookup_latest (gnc_pricedb_get_db (book), from, to); if (prc) { rate_split = gnc_price_get_value (prc); gnc_price_unref (prc); have_rate = TRUE; } /* Lets try reversing the commodities */ if (!have_rate) { prc = gnc_pricedb_lookup_latest (gnc_pricedb_get_db (book), to, from); if (prc) { rate_split = gnc_numeric_div (gnc_numeric_create (100, 100), gnc_price_get_value (prc), GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); gnc_price_unref (prc); have_rate = TRUE; } } /* No rate, set to 1/1 */ if (!have_rate) rate_split = gnc_numeric_create (100, 100); return rate_split; }
/* Get the rate from the price db */ static gnc_numeric gtu_sr_get_rate_from_db (gnc_commodity *from, gnc_commodity *to) { GNCPrice *prc; QofBook *book = gnc_get_current_book (); prc = gnc_pricedb_lookup_latest (gnc_pricedb_get_db (book), from, to); if (!prc) return gnc_numeric_create (100, 100); if (gnc_commodity_equiv(from, gnc_price_get_currency(prc))) return gnc_numeric_invert(gnc_price_get_value(prc)); return gnc_price_get_value(prc); }
xmlNodePtr gnc_book_dom_tree_create(QofBook *book) { xmlNodePtr ret; G_GNUC_UNUSED gboolean allow_incompat = TRUE; ret = xmlNewNode(NULL, BAD_CAST gnc_book_string); xmlSetProp(ret, BAD_CAST "version", BAD_CAST gnc_v2_book_version_string); xmlAddChild(ret, guid_to_dom_tree(book_id_string, qof_book_get_guid(book))); if (qof_instance_get_slots (QOF_INSTANCE (book))) { xmlNodePtr kvpnode = kvp_frame_to_dom_tree(book_slots_string, qof_instance_get_slots (QOF_INSTANCE (book))); if (kvpnode) xmlAddChild(ret, kvpnode); } #ifdef IMPLEMENT_BOOK_DOM_TREES_LATER /* theoretically, we should be adding all the below to the book * but in fact, there's enough brain damage in the code already * that we are only going to hand-edit the file at a higher layer. * And that's OK, since its probably a performance boost anyway. */ xmlAddChild(ret, gnc_commodity_dom_tree_create( gnc_commodity_table_get_table(book))); xmlAddChild(ret, gnc_pricedb_dom_tree_create(gnc_pricedb_get_db(book))); if (allow_incompat) { accnode = gnc_account_dom_tree_create(account, FALSE); xmlAddChild (ret, rootAccNode); } append_account_tree (ret, gnc_book_get_root(book)); xaccAccountTreeForEachTransaction (gnc_book_get_root_account(book), traverse_txns, ret); /* xxx FIXME hack alert how are we going to handle * gnc_book_get_template_group handled ??? */ xmlAddChild(ret, gnc_schedXaction_dom_tree_create( gnc_book_get_schedxactions(book))); #endif return ret; }
static gboolean pricedb_start_handler(GSList* sibling_data, gpointer parent_data, gpointer global_data, gpointer *data_for_children, gpointer *result, const gchar *tag, gchar **attrs) { gxpf_data *gdata = global_data; QofBook *book = gdata->bookdata; GNCPriceDB *db = gnc_pricedb_get_db(book); g_return_val_if_fail(db, FALSE); gnc_pricedb_set_bulk_update(db, TRUE); *result = db; return(TRUE); }
static void refresh_details_page (StockSplitInfo *info) { GNCPrintAmountInfo print_info; gnc_commodity *commodity, *currency; Account *account; QofBook *book; GNCPriceDB *db; GList *prices; account = info->acct; g_return_if_fail (account != NULL); print_info = gnc_account_print_info (account, FALSE); gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (info->distribution_edit), print_info); gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (info->distribution_edit), xaccAccountGetCommoditySCU (account)); commodity = xaccAccountGetCommodity (account); book = gnc_account_get_book (account); db = gnc_pricedb_get_db(book); prices = gnc_pricedb_lookup_latest_any_currency(db, commodity); if (prices) { /* Use the first existing price */ if (gnc_commodity_equiv (commodity, gnc_price_get_currency(prices->data))) currency = gnc_price_get_commodity(prices->data); else currency = gnc_price_get_currency(prices->data); } else { /* Take a wild guess. */ currency = gnc_default_currency (); } gnc_price_list_destroy(prices); gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT (info->price_currency_edit), currency); }
static void load_all_prices (GncSqlBackend* be) { GncSqlStatement* stmt; GncSqlResult* result; QofBook* pBook; GNCPriceDB* pPriceDB; g_return_if_fail (be != NULL); pBook = be->book; pPriceDB = gnc_pricedb_get_db (pBook); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); if (stmt != NULL) { result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); if (result != NULL) { GNCPrice* pPrice; GncSqlRow* row = gnc_sql_result_get_first_row (result); gchar* sql; gnc_pricedb_set_bulk_update (pPriceDB, TRUE); while (row != NULL) { pPrice = load_single_price (be, row); if (pPrice != NULL) { (void)gnc_pricedb_add_price (pPriceDB, pPrice); gnc_price_unref (pPrice); } row = gnc_sql_result_get_next_row (result); } gnc_sql_result_dispose (result); gnc_pricedb_set_bulk_update (pPriceDB, FALSE); sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", TABLE_NAME); gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)gnc_price_lookup); g_free (sql); } } }
void gnc_stock_split_assistant_finish (GtkAssistant *assistant, gpointer user_data) { StockSplitInfo *info = user_data; GList *account_commits; GList *node; gnc_numeric amount; Transaction *trans; Account *account; Split *split; time64 date; account = info->acct; g_return_if_fail (account != NULL); amount = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (info->distribution_edit)); g_return_if_fail (!gnc_numeric_zero_p (amount)); gnc_suspend_gui_refresh (); trans = xaccMallocTransaction (gnc_get_current_book ()); xaccTransBeginEdit (trans); xaccTransSetCurrency (trans, gnc_default_currency ()); date = gnc_date_edit_get_date (GNC_DATE_EDIT (info->date_edit)); xaccTransSetDatePostedSecsNormalized (trans, date); { const char *description; description = gtk_entry_get_text (GTK_ENTRY (info->description_entry)); xaccTransSetDescription (trans, description); } split = xaccMallocSplit (gnc_get_current_book ()); xaccAccountBeginEdit (account); account_commits = g_list_prepend (NULL, account); xaccTransAppendSplit (trans, split); xaccAccountInsertSplit (account, split); xaccSplitSetAmount (split, amount); xaccSplitMakeStockSplit (split); /* Set split-action with gnc_set_num_action which is the same as * xaccSplitSetAction with these arguments */ /* Translators: This string has a disambiguation prefix */ gnc_set_num_action (NULL, split, NULL, Q_("Action Column|Split")); amount = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (info->price_edit)); if (gnc_numeric_positive_p (amount)) { QofBook *book; GNCPrice *price; GNCPriceDB *pdb; GNCCurrencyEdit *ce; Timespec ts; ce = GNC_CURRENCY_EDIT (info->price_currency_edit); ts.tv_sec = date; ts.tv_nsec = 0; price = gnc_price_create (gnc_get_current_book ()); gnc_price_begin_edit (price); 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, PRICE_SOURCE_STOCK_SPLIT); gnc_price_set_typestr (price, PRICE_TYPE_UNK); gnc_price_set_value (price, amount); gnc_price_commit_edit (price); book = gnc_get_current_book (); pdb = gnc_pricedb_get_db (book); if (!gnc_pricedb_add_price (pdb, price)) gnc_error_dialog (info->window, "%s", _("Error adding price.")); } amount = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (info->cash_edit)); if (gnc_numeric_positive_p (amount)) { const char *memo; memo = gtk_entry_get_text (GTK_ENTRY (info->memo_entry)); /* asset split */ account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(info->asset_tree)); split = xaccMallocSplit (gnc_get_current_book ()); xaccAccountBeginEdit (account); account_commits = g_list_prepend (account_commits, account); xaccAccountInsertSplit (account, split); xaccTransAppendSplit (trans, split); xaccSplitSetAmount (split, amount); xaccSplitSetValue (split, amount); xaccSplitSetMemo (split, memo); /* income split */ account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(info->income_tree)); split = xaccMallocSplit (gnc_get_current_book ()); xaccAccountBeginEdit (account); account_commits = g_list_prepend (account_commits, account); xaccAccountInsertSplit (account, split); xaccTransAppendSplit (trans, split); xaccSplitSetAmount (split, gnc_numeric_neg (amount)); xaccSplitSetValue (split, gnc_numeric_neg (amount)); xaccSplitSetMemo (split, memo); } xaccTransCommitEdit (trans); for (node = account_commits; node; node = node->next) xaccAccountCommitEdit (node->data); g_list_free (account_commits); gnc_resume_gui_refresh (); gnc_close_gui_component_by_data (ASSISTANT_STOCK_SPLIT_CM_CLASS, info); }
/* * Create a new price tree view with (optional) top level root node. * This view will be based on a model that is common to all view of * the same set of books, but will have its own private filter on that * model. */ GtkTreeView * gnc_tree_view_price_new (QofBook *book, const gchar *first_property_name, ...) { GncTreeView *view; GtkTreeModel *model, *f_model, *s_model; GtkTreeViewColumn *col; GNCPriceDB *price_db; va_list var_args; const gchar *sample_text; gchar *sample_text2; ENTER(" "); /* Create/get a pointer to the existing model for this set of books. */ price_db = gnc_pricedb_get_db(book); model = gnc_tree_model_price_new (book, price_db); /* Set up the view private filter on the common model. */ f_model = gtk_tree_model_filter_new (model, NULL); g_object_unref(G_OBJECT(model)); s_model = gtk_tree_model_sort_new_with_model (f_model); g_object_unref(G_OBJECT(f_model)); /* Create our view */ view = g_object_new (GNC_TYPE_TREE_VIEW_PRICE, "name", "price_tree", NULL); gtk_tree_view_set_model (GTK_TREE_VIEW (view), s_model); g_object_unref(G_OBJECT(s_model)); DEBUG("model ref count is %d", G_OBJECT(model)->ref_count); DEBUG("f_model ref count is %d", G_OBJECT(f_model)->ref_count); DEBUG("s_model ref count is %d", G_OBJECT(s_model)->ref_count); sample_text = gnc_commodity_get_printname(gnc_default_currency()); sample_text2 = g_strdup_printf("%s%s", sample_text, sample_text); col = gnc_tree_view_add_text_column ( view, _("Security"), "security", NULL, sample_text2, GNC_TREE_MODEL_PRICE_COL_COMMODITY, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_name); g_free(sample_text2); col = gnc_tree_view_add_text_column ( view, _("Currency"), "currency", NULL, sample_text, GNC_TREE_MODEL_PRICE_COL_CURRENCY, GNC_TREE_MODEL_PRICE_COL_VISIBILITY, sort_by_name); g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1)); col = gnc_tree_view_add_text_column ( view, _("Date"), "date", NULL, "2005-05-20", GNC_TREE_MODEL_PRICE_COL_DATE, GNC_TREE_MODEL_PRICE_COL_VISIBILITY, sort_by_date); g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1)); col = gnc_tree_view_add_text_column ( view, _("Source"), "source", NULL, "Finance::Quote", GNC_TREE_MODEL_PRICE_COL_SOURCE, GNC_TREE_MODEL_PRICE_COL_VISIBILITY, sort_by_source); g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1)); col = gnc_tree_view_add_text_column ( view, _("Type"), "type", NULL, "last", GNC_TREE_MODEL_PRICE_COL_TYPE, GNC_TREE_MODEL_PRICE_COL_VISIBILITY, sort_by_type); g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1)); col = gnc_tree_view_add_numeric_column ( view, _("Price"), "price", "100.00000", GNC_TREE_MODEL_PRICE_COL_VALUE, GNC_TREE_VIEW_COLUMN_COLOR_NONE, GNC_TREE_MODEL_PRICE_COL_VISIBILITY, sort_by_value); g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1)); gnc_tree_view_configure_columns(view); /* Set properties */ va_start (var_args, first_property_name); g_object_set_valist (G_OBJECT(view), first_property_name, var_args); va_end (var_args); /* Sort on the commodity column by default. This allows for a consistent * sort if commodities are removed and re-added from the model. */ if (!gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(s_model), NULL, NULL)) { gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model), GNC_TREE_MODEL_PRICE_COL_COMMODITY, GTK_SORT_ASCENDING); } gtk_widget_show(GTK_WIDGET(view)); LEAVE(" %p", view); return GTK_TREE_VIEW(view); }
static void remove_clicked (CommoditiesDialog *cd) { GNCPriceDB *pdb; GList *prices; gboolean can_delete; gnc_commodity *commodity; GtkWidget *dialog; const gchar *message, *warning; gint response; commodity = gnc_tree_view_commodity_get_selected_commodity (cd->commodity_tree); if (commodity == NULL) return; AccountList_t accounts = gnc_account_get_descendants (gnc_book_get_root_account(cd->book)); can_delete = TRUE; for (AccountList_t::const_iterator node = accounts.begin(); node != accounts.end(); node++) { Account *account = *node; if (commodity == xaccAccountGetCommodity (account)) { can_delete = FALSE; break; } } /* FIXME check for transaction references */ if (!can_delete) { const char *message = _("That commodity is currently used by " "at least one of your accounts. You may " "not delete it."); gnc_warning_dialog (cd->dialog, "%s", message); return; } pdb = gnc_pricedb_get_db (cd->book); prices = gnc_pricedb_get_prices(pdb, commodity, NULL); if (prices) { message = _("This commodity has price quotes. Are " "you sure you want to delete the selected " "commodity and its price quotes?"); warning = "delete_commodity2"; } else { message = _("Are you sure you want to delete the " "selected commodity?"); warning = "delete_commodity"; } dialog = gtk_message_dialog_new(GTK_WINDOW(cd->dialog), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", _("Delete commodity?")); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", message); gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_DELETE, GTK_RESPONSE_OK, (gchar *)NULL); response = gnc_dialog_run(GTK_DIALOG(dialog), warning); gtk_widget_destroy(dialog); if (response == GTK_RESPONSE_OK) { gnc_commodity_table *ct; ct = gnc_commodity_table_get_table (cd->book); for (GList *node = prices; node; node = node->next) gnc_pricedb_remove_price(pdb, node->data); gnc_commodity_table_remove (ct, commodity); gnc_commodity_destroy (commodity); commodity = NULL; } gnc_price_list_destroy(prices); gnc_gui_refresh_all (); }
void GncPriceImport::create_price (std::vector<parse_line_t>::iterator& parsed_line) { StrVec line; std::string error_message; std::shared_ptr<GncImportPrice> price_props = nullptr; bool skip_line = false; std::tie(line, error_message, price_props, skip_line) = *parsed_line; if (skip_line) return; error_message.clear(); // Add a TO_CURRENCY property with the selected '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 a 'currency to' column *and* we didn't get a selected value either! // Note if you get here this suggests a bug in the code! error_message = _("No 'Currency to' column selected and no selected 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 FROM_COMMODITY property with the selected '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 a 'commodity from' column *and* we didn't get a selected value either! // Note if you get here this suggests a bug in the code! error_message = _("No 'Commodity from' column selected and no selected 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 { price_properties_verify_essentials (parsed_line); QofBook* book = gnc_get_current_book(); GNCPriceDB *pdb = gnc_pricedb_get_db (book); /* If all went well, add this price to the list. */ auto price_created = price_props->create_price (book, pdb, m_over_write); if (price_created == ADDED) m_prices_added++; else if (price_created == DUPLICATED) m_prices_duplicated++; else if (price_created == REPLACED) m_prices_replaced++; } catch (const std::invalid_argument& e) { error_message = e.what(); PINFO("User warning: %s", error_message.c_str()); } }