static gint default_sort (gnc_commodity *comm_a, gnc_commodity *comm_b) { gint fraction_a, fraction_b, result; result = safe_utf8_collate (gnc_commodity_get_namespace (comm_a), gnc_commodity_get_namespace (comm_b)); if (result != 0) return result; result = safe_utf8_collate (gnc_commodity_get_mnemonic (comm_a), gnc_commodity_get_mnemonic (comm_b)); if (result != 0) return result; result = safe_utf8_collate (gnc_commodity_get_fullname (comm_a), gnc_commodity_get_fullname (comm_b)); if (result != 0) return result; result = safe_utf8_collate (gnc_commodity_get_cusip (comm_a), gnc_commodity_get_cusip (comm_b)); if (result != 0) return result; fraction_a = gnc_commodity_get_fraction (comm_a); fraction_b = gnc_commodity_get_fraction (comm_b); if (fraction_a < fraction_b) return -1; if (fraction_b < fraction_a) return 1; return 0; }
xmlNodePtr gnc_commodity_dom_tree_create(const gnc_commodity *com) { gnc_quote_source *source; const char *string; xmlNodePtr ret; gboolean currency = gnc_commodity_is_iso(com); xmlNodePtr slotsnode = qof_instance_slots_to_dom_tree(cmdty_slots, QOF_INSTANCE(com)); if (currency && !gnc_commodity_get_quote_flag(com) && !slotsnode) return NULL; ret = xmlNewNode(NULL, BAD_CAST gnc_commodity_string); xmlSetProp(ret, BAD_CAST "version", BAD_CAST commodity_version_string); xmlAddChild(ret, text_to_dom_tree(cmdty_namespace, gnc_commodity_get_namespace_compat(com))); xmlAddChild(ret, text_to_dom_tree(cmdty_id, gnc_commodity_get_mnemonic(com))); if (!currency) { if (gnc_commodity_get_fullname(com)) { xmlAddChild(ret, text_to_dom_tree(cmdty_name, gnc_commodity_get_fullname(com))); } if (gnc_commodity_get_cusip(com) && strlen(gnc_commodity_get_cusip(com)) > 0) { xmlAddChild(ret, text_to_dom_tree( cmdty_xcode, gnc_commodity_get_cusip(com))); } xmlAddChild(ret, int_to_dom_tree(cmdty_fraction, gnc_commodity_get_fraction(com))); } if (gnc_commodity_get_quote_flag(com)) { xmlNewChild(ret, NULL, BAD_CAST cmdty_get_quotes, NULL); source = gnc_commodity_get_quote_source(com); if (source) xmlAddChild(ret, text_to_dom_tree(cmdty_quote_source, gnc_quote_source_get_internal_name(source))); string = gnc_commodity_get_quote_tz(com); if (string) xmlAddChild(ret, text_to_dom_tree(cmdty_quote_tz, string)); } if (slotsnode) xmlAddChild(ret, slotsnode); return ret; }
/* Either sets the value and amount for split and returns TRUE, or does nothing and returns FALSE. */ static gboolean gtu_sr_handle_exchange_rate (GncTreeViewSplitReg *view, gnc_numeric amount, Transaction *trans, Split *split, gboolean force) { GncTreeModelSplitReg *model; XferDialog *xfer; gboolean rate_split_ok, rate_reg_ok; gnc_numeric rate_split, rate_reg, value; Account *reg_acc; gnc_commodity *xfer_comm = xaccAccountGetCommodity (xaccSplitGetAccount (split)); gnc_commodity *reg_comm = gnc_tree_view_split_reg_get_reg_commodity (view); gnc_commodity *trans_curr = xaccTransGetCurrency (trans); gboolean expanded; gboolean have_rate = TRUE; ENTER("handle_exchange_rate amount %s, trans %p and split %p force %d", gnc_numeric_to_string (amount), trans, split, force); model = gnc_tree_view_split_reg_get_model_from_view (view); reg_acc = gnc_tree_model_split_reg_get_anchor (model); /* Rate from trans-curr to split-comm */ rate_split_ok = xaccTransGetRateForCommodity (trans, xfer_comm, split, &rate_split); DEBUG("rate_split_ok %d and xfer_comm %s", rate_split_ok, gnc_commodity_get_fullname (xfer_comm)); /* Rate from trans-curr to reg-comm */ rate_reg_ok = xaccTransGetRateForCommodity (trans, reg_comm, split, &rate_reg); DEBUG("rate_reg_ok %d and reg_comm %s", rate_reg_ok, gnc_commodity_get_fullname (reg_comm)); /* Are we expanded */ expanded = gnc_tree_view_split_reg_trans_expanded (view, trans); if (gnc_commodity_equal (trans_curr, xfer_comm) && rate_split_ok) { xaccSplitSetAmount (split, amount); xaccSplitSetValue (split, amount); return TRUE; } if (rate_reg_ok && rate_split_ok && !force) { value = gnc_numeric_div (amount, rate_reg, gnc_commodity_get_fraction (trans_curr), GNC_HOW_DENOM_REDUCE); amount = gnc_numeric_mul (value, rate_split, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND); } else { if (!rate_split_ok) rate_split = gtu_sr_get_rate_from_db (reg_comm, xfer_comm); /* create the exchange-rate dialog */ xfer = gnc_xfer_dialog (NULL, NULL); gnc_xfer_dialog_is_exchange_dialog (xfer, &rate_split); /* fill in the dialog entries */ gnc_xfer_dialog_set_description (xfer, xaccTransGetDescription (trans)); gnc_xfer_dialog_set_memo (xfer, xaccSplitGetMemo (split)); /* Get per book option */ gnc_xfer_dialog_set_num (xfer, gnc_get_num_action (trans, split)); gnc_xfer_dialog_set_date (xfer, timespecToTime64 (xaccTransRetDatePostedTS (trans))); value = amount; if (gnc_xfer_dialog_run_exchange_dialog (xfer, &rate_split, value, reg_acc, trans, xfer_comm, expanded)) { if (!rate_split_ok) rate_split = gnc_numeric_create (1, 1); have_rate = FALSE; } else have_rate = TRUE; amount = gnc_numeric_mul (value, rate_split, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND); } xaccSplitSetAmount (split, amount); xaccSplitSetValue (split, value); LEAVE("handle_exchange_rate set split %p amt=%s; and val=%s", split, gnc_numeric_to_string (amount), gnc_numeric_to_string (value)); return have_rate; }
void xaccLotScrubDoubleBalance (GNCLot *lot) { gnc_commodity *currency = NULL; SplitList *snode; GList *node; gnc_numeric zero = gnc_numeric_zero(); gnc_numeric value = zero; if (!lot) return; ENTER ("lot=%s", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title")); for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next) { Split *s = snode->data; xaccSplitComputeCapGains (s, NULL); } /* We double-check only closed lots */ if (FALSE == gnc_lot_is_closed (lot)) return; for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next) { Split *s = snode->data; Transaction *trans = s->parent; /* Check to make sure all splits in the lot have a common currency */ if (NULL == currency) { currency = trans->common_currency; } if (FALSE == gnc_commodity_equiv (currency, trans->common_currency)) { /* This lot has mixed currencies. Can't double-balance. * Silently punt */ PWARN ("Lot with multiple currencies:\n" "\ttrans=%s curr=%s", xaccTransGetDescription(trans), gnc_commodity_get_fullname(trans->common_currency)); break; } /* Now, total up the values */ value = gnc_numeric_add (value, xaccSplitGetValue (s), GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT); PINFO ("Split=%p value=%s Accum Lot value=%s", s, gnc_num_dbg_to_string (s->value), gnc_num_dbg_to_string (value)); } if (FALSE == gnc_numeric_equal (value, zero)) { /* Unhandled error condition. Not sure what to do here, * Since the ComputeCapGains should have gotten it right. * I suppose there might be small rounding errors, a penny or two, * the ideal thing would to figure out why there's a rounding * error, and fix that. */ PERR ("Closed lot fails to double-balance !! lot value=%s", gnc_num_dbg_to_string (value)); for (node = gnc_lot_get_split_list(lot); node; node = node->next) { Split *s = node->data; PERR ("s=%p amt=%s val=%s", s, gnc_num_dbg_to_string(s->amount), gnc_num_dbg_to_string(s->value)); } } LEAVE ("lot=%s", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title")); }
static void gnc_tree_model_owner_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column, GValue *value) { GncTreeModelOwner *model = GNC_TREE_MODEL_OWNER (tree_model); GncOwner *owner; gboolean negative; /* used to set "deficit style" also known as red numbers */ gchar *string = NULL; g_return_if_fail (GNC_IS_TREE_MODEL_OWNER (model)); g_return_if_fail (iter != NULL); g_return_if_fail (iter->user_data != NULL); g_return_if_fail (iter->stamp == model->stamp); ENTER("model %p, iter %s, col %d", tree_model, iter_to_string(iter), column); owner = (GncOwner *) iter->user_data; switch (column) { case GNC_TREE_MODEL_OWNER_COL_NAME: g_value_init (value, G_TYPE_STRING); g_value_set_string (value, gncOwnerGetName (owner)); break; case GNC_TREE_MODEL_OWNER_COL_TYPE: g_value_init (value, G_TYPE_STRING); g_value_set_string (value, gncOwnerTypeToQofIdType (gncOwnerGetType (owner))); break; case GNC_TREE_MODEL_OWNER_COL_ID: g_value_init (value, G_TYPE_STRING); g_value_set_string (value, gncOwnerGetID (owner)); break; case GNC_TREE_MODEL_OWNER_COL_CURRENCY: g_value_init (value, G_TYPE_STRING); g_value_set_string (value, gnc_commodity_get_fullname(gncOwnerGetCurrency (owner))); break; case GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetName (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_ADDRESS_1: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetAddr1 (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_ADDRESS_2: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetAddr2 (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_ADDRESS_3: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetAddr3 (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_ADDRESS_4: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetAddr4 (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_PHONE: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetPhone (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_FAX: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetFax (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_EMAIL: g_value_init (value, G_TYPE_STRING); string = g_strdup (gncAddressGetEmail (gncOwnerGetAddr (owner))); if (string) g_value_take_string (value, string); else g_value_set_static_string (value, ""); break; case GNC_TREE_MODEL_OWNER_COL_BALANCE: g_value_init (value, G_TYPE_STRING); string = gnc_ui_owner_get_print_balance(owner, &negative); g_value_take_string (value, string); break; case GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT: g_value_init (value, G_TYPE_STRING); string = gnc_ui_owner_get_print_report_balance(owner, &negative); g_value_take_string (value, string); break; case GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE: g_value_init (value, G_TYPE_STRING); string = gnc_ui_owner_get_print_balance(owner, &negative); gnc_tree_model_owner_set_color(model, negative, value); g_free(string); break; case GNC_TREE_MODEL_OWNER_COL_NOTES: g_value_init (value, G_TYPE_STRING); switch (gncOwnerGetType (owner)) { case GNC_OWNER_NONE: case GNC_OWNER_UNDEFINED: case GNC_OWNER_EMPLOYEE: case GNC_OWNER_JOB: default: g_value_set_static_string (value, ""); break; case GNC_OWNER_VENDOR: g_value_set_string (value, gncVendorGetNotes (gncOwnerGetVendor (owner))); break; case GNC_OWNER_CUSTOMER: g_value_set_string (value, gncCustomerGetNotes (gncOwnerGetCustomer (owner))); break; } break; case GNC_TREE_MODEL_OWNER_COL_ACTIVE: g_value_init (value, G_TYPE_BOOLEAN); g_value_set_boolean (value, gncOwnerGetActive (owner)); break; default: g_assert_not_reached (); } LEAVE(" "); }
static const char* node_and_commodity_equal (xmlNodePtr node, const gnc_commodity* com) { xmlNodePtr mark; while (g_strcmp0 ((char*)node->name, "text") == 0) node = node->next; if (!check_dom_tree_version (node, "2.0.0")) { return "version wrong. Not 2.0.0 or not there"; } if (!node->name || g_strcmp0 ((char*)node->name, "gnc:commodity")) { return "Name of toplevel node is bad"; } for (mark = node->xmlChildrenNode; mark; mark = mark->next) { if (g_strcmp0 ((char*)mark->name, "text") == 0) { } else if (g_strcmp0 ((char*)mark->name, "cmdty:space") == 0) { if (!equals_node_val_vs_string ( mark, gnc_commodity_get_namespace_compat (com))) { return "namespaces differ"; } } else if (g_strcmp0 ((char*)mark->name, "cmdty:id") == 0) { if (!equals_node_val_vs_string ( mark, gnc_commodity_get_mnemonic (com))) { return "mnemonic differ"; } } else if (g_strcmp0 ((char*)mark->name, "cmdty:name") == 0) { if (!equals_node_val_vs_string ( mark, gnc_commodity_get_fullname (com))) { return "names differ"; } } else if (g_strcmp0 ((char*)mark->name, "cmdty:xcode") == 0) { if (!equals_node_val_vs_string ( mark, gnc_commodity_get_cusip (com))) { return "exchange codes differ"; } } else if (g_strcmp0 ((char*)mark->name, "cmdty:fraction") == 0) { gchar* txt; gint64 type; txt = dom_tree_to_text (mark); if (!txt) { return "couldn't get fraction string"; } else if (!string_to_gint64 (txt, &type)) { g_free (txt); return "couldn't convert fraction string to int"; } else if (type != gnc_commodity_get_fraction (com)) { g_free (txt); return "fractions differ"; } else { g_free (txt); } } else if (g_strcmp0 ((char*)mark->name, "cmdty:slots") == 0) { if (!equals_node_val_vs_kvp_frame (mark, gnc_commodity_get_kvp_frame (com))) return "slots differ"; } /* Legitimate tags which we don't yet have tests */ else if (g_strcmp0 ((char*)mark->name, "cmdty:get_quotes") == 0 || g_strcmp0 ((char*)mark->name, "cmdty:quote_source") == 0 || g_strcmp0 ((char*)mark->name, "cmdty:quote_tz") == 0) { continue; } else { return "unknown node"; } } return NULL; }
gnc_commodity * gnc_import_select_commodity(const char * cusip, gboolean ask_on_unknown, const char * default_fullname, const char * default_mnemonic) { const gnc_commodity_table * commodity_table = gnc_get_current_commodities (); gnc_commodity * retval = NULL; gnc_commodity * tmp_commodity = NULL; char * tmp_namespace = NULL; GList * commodity_list = NULL; GList * namespace_list = NULL; DEBUG("Default fullname received: %s", default_fullname ? default_fullname : "(null)"); DEBUG("Default mnemonic received: %s", default_mnemonic ? default_mnemonic : "(null)"); g_return_val_if_fail(cusip, NULL); DEBUG("Looking for commodity with exchange_code: %s", cusip); g_assert(commodity_table); namespace_list = gnc_commodity_table_get_namespaces(commodity_table); namespace_list = g_list_first(namespace_list); while ( namespace_list != NULL && retval == NULL) { tmp_namespace = namespace_list->data; DEBUG("Looking at namespace %s", tmp_namespace); commodity_list = gnc_commodity_table_get_commodities(commodity_table, tmp_namespace); commodity_list = g_list_first(commodity_list); while ( commodity_list != NULL && retval == NULL) { const char* tmp_cusip = NULL; tmp_commodity = commodity_list->data; DEBUG("Looking at commodity %s", gnc_commodity_get_fullname(tmp_commodity)); tmp_cusip = gnc_commodity_get_cusip(tmp_commodity); if (tmp_cusip != NULL && cusip != NULL) { int len = strlen(cusip) > strlen(tmp_cusip) ? strlen(cusip) : strlen(tmp_cusip); if (strncmp(tmp_cusip, cusip, len) == 0) { retval = tmp_commodity; DEBUG("Commodity %s%s", gnc_commodity_get_fullname(retval), " matches."); } } commodity_list = g_list_next(commodity_list); } namespace_list = g_list_next(namespace_list); } g_list_free(commodity_list); g_list_free(namespace_list); if (retval == NULL && ask_on_unknown != 0) { const gchar *message = _("Please select a commodity to match the following exchange " "specific code. Please note that the exchange code of the " "commodity you select will be overwritten."); retval = gnc_ui_select_commodity_modal_full(NULL, NULL, DIAG_COMM_ALL, message, cusip, default_fullname, default_mnemonic); } /* There seems to be a problem here - if the matched commodity does not have a cusip defined (gnc_commodity_get_cusip returns NULL) then it does not get overwritten - which is not consistent with the message - so Im adding it to do this. Looks like this is all that was needed to fix the cash value used as stock units problem for pre-defined commodities which didnt have the cusip defined! */ if (retval != NULL && gnc_commodity_get_cusip(retval) != NULL && cusip != NULL && (strncmp(gnc_commodity_get_cusip(retval), cusip, strlen(cusip)) != 0)) { gnc_commodity_set_cusip(retval, cusip); } else if (gnc_commodity_get_cusip(retval) == NULL && cusip != NULL) { gnc_commodity_set_cusip(retval, cusip); } return retval; };
/* * Create a new owner tree view for one type of owners. * This view will be based on a model that is common to all views of * the same set of books, but will have its own private filter on that * model. */ GtkTreeView * gnc_tree_view_owner_new (GncOwnerType owner_type) { GncTreeView *view; GtkTreeModel *model, *f_model, *s_model; const gchar *sample_type, *sample_currency; GncTreeViewOwnerPrivate *priv; GtkTreeViewColumn *tax_info_column; GtkCellRenderer *renderer; ENTER(" "); /* Create our view */ view = g_object_new (GNC_TYPE_TREE_VIEW_OWNER, "name", "owner_tree", NULL); priv = GNC_TREE_VIEW_OWNER_GET_PRIVATE(GNC_TREE_VIEW_OWNER (view)); /* Create/get a pointer to the existing model for this set of books. */ model = gnc_tree_model_owner_new (owner_type); /* Set up the view private filter layer on the common model. */ f_model = gtk_tree_model_filter_new (model, NULL); /* A GncTreeModelOwner is based on a GncTreeModel, which is a * GObject that provides a GtkTreeModel interface. */ g_object_unref(G_OBJECT(model)); /* Set up the view private sort layer on the common model. */ s_model = gtk_tree_model_sort_new_with_model(f_model); g_object_unref(G_OBJECT(f_model)); gnc_tree_view_set_model (view, s_model); g_object_unref(G_OBJECT(s_model)); /* Set default visibilities */ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view), FALSE); sample_type = gncOwnerTypeToQofIdType (GNC_OWNER_CUSTOMER); sample_currency = gnc_commodity_get_fullname(gnc_default_currency()); priv->name_column = gnc_tree_view_add_text_column(view, _("Owner Name"), GNC_OWNER_TREE_NAME_COL, NULL, "GnuCash Inc.", GNC_TREE_MODEL_OWNER_COL_NAME, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Type"), GNC_OWNER_TREE_TYPE_COL, NULL, sample_type, GNC_TREE_MODEL_OWNER_COL_TYPE, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); priv->id_column = gnc_tree_view_add_text_column(view, _("Owner ID"), GNC_OWNER_TREE_ID_COL, NULL, "1-123-1234", GNC_TREE_MODEL_OWNER_COL_ID, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Currency"), GNC_OWNER_TREE_CURRENCY_COL, NULL, sample_currency, GNC_TREE_MODEL_OWNER_COL_CURRENCY, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Address Name"), GNC_OWNER_TREE_ADDRESS_NAME_COL, NULL, "GnuCash Inc.", GNC_TREE_MODEL_OWNER_COL_ADDRESS_NAME, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Address 1"), GNC_OWNER_TREE_ADDRESS_1_COL, NULL, "Free Software Foundation", GNC_TREE_MODEL_OWNER_COL_ADDRESS_1, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Address 2"), GNC_OWNER_TREE_ADDRESS_2_COL, NULL, "51 Franklin Street, Fifth Floor", GNC_TREE_MODEL_OWNER_COL_ADDRESS_2, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Address 3"), GNC_OWNER_TREE_ADDRESS_3_COL, NULL, "Boston, MA 02110-1301", GNC_TREE_MODEL_OWNER_COL_ADDRESS_3, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Address 4"), GNC_OWNER_TREE_ADDRESS_4_COL, NULL, "USA", GNC_TREE_MODEL_OWNER_COL_ADDRESS_4, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Phone"), GNC_OWNER_TREE_PHONE_COL, NULL, "+1-617-542-5942", GNC_TREE_MODEL_OWNER_COL_PHONE, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("Fax"), GNC_OWNER_TREE_FAX_COL, NULL, "+1-617-542-2652", GNC_TREE_MODEL_OWNER_COL_FAX, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_text_column(view, _("E-mail"), GNC_OWNER_TREE_EMAIL_COL, NULL, "*****@*****.**", GNC_TREE_MODEL_OWNER_COL_EMAIL, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_numeric_column(view, _("Balance"), GNC_OWNER_TREE_BALANCE_COL, SAMPLE_OWNER_VALUE, GNC_TREE_MODEL_OWNER_COL_BALANCE, GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_balance_value); priv->balance_report_column = gnc_tree_view_add_numeric_column(view, _("Balance"), GNC_OWNER_TREE_BALANCE_REPORT_COL, SAMPLE_OWNER_VALUE, GNC_TREE_MODEL_OWNER_COL_BALANCE_REPORT, GNC_TREE_MODEL_OWNER_COL_COLOR_BALANCE, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_balance_value); priv->notes_column = gnc_tree_view_add_text_column(view, _("Notes"), GNC_OWNER_TREE_NOTES_COL, NULL, "Sample owner notes.", GNC_TREE_MODEL_OWNER_COL_NOTES, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_string); gnc_tree_view_add_toggle_column (view, _("Active"), /* Translators: This string has a context prefix; the translation must only contain the part after the | character. */ Q_("Column letter for 'Active'|A"), GNC_OWNER_TREE_ACTIVE_COL, GNC_TREE_MODEL_OWNER_COL_ACTIVE, GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, sort_by_boolean, gnc_tree_view_owner_active_toggled); /* Update column titles to use the currency name. */ gtvo_update_column_names(view); /* By default only the first column is visible. */ gnc_tree_view_configure_columns(view); gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (f_model), gnc_tree_view_owner_filter_helper, view, NULL); /* Default the sorting to owner name */ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(s_model), GNC_TREE_MODEL_OWNER_COL_NAME, GTK_SORT_ASCENDING); gtk_widget_show(GTK_WIDGET(view)); LEAVE("%p", view); return GTK_TREE_VIEW(view); }
int ofx_proc_transaction_cb(struct OfxTransactionData data, void * transaction_user_data) { char dest_string[255]; time64 current_time = gnc_time (NULL); Account *account; Account *investment_account = NULL; Account *income_account = NULL; gchar *investment_account_text, *investment_account_onlineid; gnc_commodity *currency = NULL; gnc_commodity *investment_commodity = NULL; gnc_numeric gnc_amount, gnc_units; QofBook *book; Transaction *transaction; Split *split; gchar *notes, *tmp; g_assert(gnc_ofx_importer_gui); if (!data.account_id_valid) { PERR("account ID for this transaction is unavailable!"); return 0; } account = gnc_import_select_account(gnc_gen_trans_list_widget(gnc_ofx_importer_gui), data.account_id, 0, NULL, NULL, ACCT_TYPE_NONE, NULL, NULL); if (account == NULL) { PERR("Unable to find account for id %s", data.account_id); return 0; } /***** Validate the input strings to ensure utf8 *****/ if (data.name_valid) gnc_utf8_strip_invalid(data.name); if (data.memo_valid) gnc_utf8_strip_invalid(data.memo); if (data.check_number_valid) gnc_utf8_strip_invalid(data.check_number); if (data.reference_number_valid) gnc_utf8_strip_invalid(data.reference_number); /***** Create the transaction and setup transaction data *******/ book = gnc_account_get_book(account); transaction = xaccMallocTransaction(book); xaccTransBeginEdit(transaction); /* Note: Unfortunately libofx <= 0.9.5 will not report a missing * date field as an invalid one. Instead, it will report it as * valid and return a completely bogus date. Starting with * libofx-0.9.6 (not yet released as of 2012-09-09), it will still * be reported as valid but at least the date integer itself is * just plain zero. */ if (data.date_posted_valid && (data.date_posted != 0)) { /* The hopeful case: We have a posted_date */ xaccTransSetDatePostedSecsNormalized(transaction, data.date_posted); } else if (data.date_initiated_valid && (data.date_initiated != 0)) { /* No posted date? Maybe we have an initiated_date */ xaccTransSetDatePostedSecsNormalized(transaction, data.date_initiated); } else { /* Uh no, no valid date. As a workaround use today's date */ xaccTransSetDatePostedSecsNormalized(transaction, current_time); } xaccTransSetDateEnteredSecs(transaction, current_time); /* Put transaction name in Description, or memo if name unavailable */ if (data.name_valid) { xaccTransSetDescription(transaction, data.name); } else if (data.memo_valid) { xaccTransSetDescription(transaction, data.memo); } /* Put everything else in the Notes field */ notes = g_strdup_printf("OFX ext. info: "); if (data.transactiontype_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Trans type:", gnc_ofx_ttype_to_string(data.transactiontype)); g_free(tmp); } if (data.invtransactiontype_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Investment Trans type:", gnc_ofx_invttype_to_str(data.invtransactiontype)); g_free(tmp); } if (data.memo_valid && data.name_valid) /* Copy only if memo wasn't put in Description */ { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Memo:", data.memo); g_free(tmp); } if (data.date_funds_available_valid) { Timespec ts; timespecFromTime64(&ts, data.date_funds_available); gnc_timespec_to_iso8601_buff (ts, dest_string); tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Date funds available:", dest_string); g_free(tmp); } if (data.server_transaction_id_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Server trans ID (conf. number):", data.server_transaction_id); g_free(tmp); } if (data.standard_industrial_code_valid) { tmp = notes; notes = g_strdup_printf("%s%s%ld", tmp, "|Standard Industrial Code:", data.standard_industrial_code); g_free(tmp); } if (data.payee_id_valid) { tmp = notes; notes = g_strdup_printf("%s%s%s", tmp, "|Payee ID:", data.payee_id); g_free(tmp); } //PERR("WRITEME: GnuCash ofx_proc_transaction():Add PAYEE and ADRESS here once supported by libofx! Notes=%s\n", notes); /* Ideally, gnucash should process the corrected transactions */ if (data.fi_id_corrected_valid) { PERR("WRITEME: GnuCash ofx_proc_transaction(): WARNING: This transaction corrected a previous transaction, but we created a new one instead!\n"); tmp = notes; notes = g_strdup_printf("%s%s%s%s", tmp, "|This corrects transaction #", data.fi_id_corrected, "but GnuCash didn't process the correction!"); g_free(tmp); } xaccTransSetNotes(transaction, notes); g_free(notes); if (data.account_ptr && data.account_ptr->currency_valid) { DEBUG("Currency from libofx: %s", data.account_ptr->currency); currency = gnc_commodity_table_lookup( gnc_get_current_commodities (), GNC_COMMODITY_NS_CURRENCY, data.account_ptr->currency); } else { DEBUG("Currency from libofx unavailable, defaulting to account's default"); currency = xaccAccountGetCommodity(account); } xaccTransSetCurrency(transaction, currency); if (data.amount_valid) { if (!data.invtransactiontype_valid) { /***** Process a normal transaction ******/ DEBUG("Adding split; Ordinary banking transaction, money flows from or into the source account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(account, split); gnc_amount = gnc_ofx_numeric_from_double_txn(data.amount, transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); /* set tran-num and/or split-action per book option */ if (data.check_number_valid) { gnc_set_num_action(transaction, split, data.check_number, NULL); } else if (data.reference_number_valid) { gnc_set_num_action(transaction, split, data.reference_number, NULL); } /* Also put the ofx transaction's memo in the * split's memo field */ if (data.memo_valid) { xaccSplitSetMemo(split, data.memo); } if (data.fi_id_valid) { gnc_import_set_split_online_id(split, data.fi_id); } } else if (data.unique_id_valid && data.security_data_valid && data.security_data_ptr != NULL && data.security_data_ptr->secname_valid) { gboolean choosing_account = TRUE; /********* Process an investment transaction **********/ /* Note that the ACCT_TYPE_STOCK account type should be replaced with something derived from data.invtranstype*/ // We have an investment transaction. First select the correct commodity. investment_commodity = gnc_import_select_commodity(data.unique_id, FALSE, NULL, NULL); if (investment_commodity != NULL) { // As we now have the commodity, select the account with that commodity. investment_account_text = g_strdup_printf( /* This string is a default account name. It MUST NOT contain the character ':' anywhere in it or in any translations. */ _("Stock account for security \"%s\""), data.security_data_ptr->secname); investment_account_onlineid = g_strdup_printf( "%s%s", data.account_id, data.unique_id); investment_account = gnc_import_select_account(NULL, investment_account_onlineid, 1, investment_account_text, investment_commodity, ACCT_TYPE_STOCK, NULL, NULL); // but use it only if that's really the right commodity if (investment_account && xaccAccountGetCommodity(investment_account) != investment_commodity) investment_account = NULL; // Loop until we either have an account, or the user pressed Cancel while (!investment_account && choosing_account) { // No account with correct commodity automatically found. // But are we in auto-create mode and already know a parent? if (auto_create_commodity && ofx_parent_account) { // Yes, so use that as parent when auto-creating the new account below. investment_account = ofx_parent_account; } else { // Let the user choose an account investment_account = gnc_import_select_account( gnc_gen_trans_list_widget(gnc_ofx_importer_gui), data.unique_id, TRUE, investment_account_text, investment_commodity, ACCT_TYPE_STOCK, NULL, &choosing_account); } // Does the chosen account have the right commodity? if (investment_account && xaccAccountGetCommodity(investment_account) != investment_commodity) { if (auto_create_commodity && xaccAccountTypesCompatible(xaccAccountGetType(investment_account), ACCT_TYPE_STOCK)) { // The user chose an account, but it does // not have the right commodity. Also, // auto-creation is on. Hence, we create a // new child account of the selected one, // and this one will have the right // commodity. Account *parent_account = investment_account; investment_account = gnc_ofx_new_account(investment_account_text, investment_commodity, parent_account, ACCT_TYPE_STOCK); if (investment_account) { gnc_import_set_acc_online_id(investment_account, data.unique_id); choosing_account = FALSE; ofx_parent_account = parent_account; } else { ofx_parent_account = NULL; } } else { // No account with matching commodity. Ask the user // whether to continue or abort. choosing_account = gnc_verify_dialog( gnc_gen_trans_list_widget(gnc_ofx_importer_gui), TRUE, "The chosen account \"%s\" does not have the correct " "currency/security \"%s\" (it has \"%s\" instead). " "This account cannot be used. " "Do you want to choose again?", xaccAccountGetName(investment_account), gnc_commodity_get_fullname(investment_commodity), gnc_commodity_get_fullname(xaccAccountGetCommodity(investment_account))); // We must also delete the online_id that was set in gnc_import_select_account() gnc_import_set_acc_online_id(investment_account, ""); investment_account = NULL; } } } if (!investment_account) { PERR("No investment account found for text: %s\n", investment_account_text); } g_free (investment_account_text); g_free (investment_account_onlineid); investment_account_text = NULL; if (investment_account != NULL && data.unitprice_valid && data.units_valid && ( data.invtransactiontype != OFX_INCOME ) ) { DEBUG("Adding investment split; Money flows from or into the stock account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(investment_account, split); gnc_amount = gnc_ofx_numeric_from_double (ofx_get_investment_amount(&data), investment_commodity); gnc_units = gnc_ofx_numeric_from_double (data.units, investment_commodity); xaccSplitSetAmount(split, gnc_units); xaccSplitSetValue(split, gnc_amount); /* set tran-num and/or split-action per book option */ if (data.check_number_valid) { gnc_set_num_action(transaction, split, data.check_number, NULL); } else if (data.reference_number_valid) { gnc_set_num_action(transaction, split, data.reference_number, NULL); } if (data.security_data_ptr->memo_valid) { xaccSplitSetMemo(split, data.security_data_ptr->memo); } if (data.fi_id_valid) { gnc_import_set_split_online_id(split, data.fi_id); } } else { if (investment_account) PERR("The investment account, units or unitprice was not found for the investment transaction"); } } else { PERR("Commodity not found for the investment transaction"); } if (data.invtransactiontype_valid && investment_account) { if (data.invtransactiontype == OFX_REINVEST || data.invtransactiontype == OFX_INCOME) { DEBUG("Now let's find an account for the destination split"); income_account = gnc_ofx_kvp_get_assoc_account(investment_account); if (income_account == NULL) { DEBUG("Couldn't find an associated income account"); investment_account_text = g_strdup_printf( /* This string is a default account name. It MUST NOT contain the character ':' anywhere in it or in any translations. */ _("Income account for security \"%s\""), data.security_data_ptr->secname); income_account = gnc_import_select_account( gnc_gen_trans_list_widget(gnc_ofx_importer_gui), NULL, 1, investment_account_text, currency, ACCT_TYPE_INCOME, NULL, NULL); gnc_ofx_kvp_set_assoc_account(investment_account, income_account); DEBUG("KVP written"); } else { DEBUG("Found at least one associated income account"); } } if (income_account != NULL && data.invtransactiontype == OFX_REINVEST) { DEBUG("Adding investment split; Money flows from the income account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(income_account, split); gnc_amount = gnc_ofx_numeric_from_double_txn (data.amount, transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); // Set split memo from ofx transaction name or memo gnc_ofx_set_split_memo(&data, split); } if (income_account != NULL && data.invtransactiontype == OFX_INCOME) { DEBUG("Adding investment split; Money flows from the income account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(income_account, split); gnc_amount = gnc_ofx_numeric_from_double_txn (-data.amount,/*OFX_INCOME amounts come in as positive numbers*/ transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); // Set split memo from ofx transaction name or memo gnc_ofx_set_split_memo(&data, split); } } if (data.invtransactiontype_valid && data.invtransactiontype != OFX_REINVEST) { DEBUG("Adding investment split; Money flows from or to the cash account"); split = xaccMallocSplit(book); xaccTransAppendSplit(transaction, split); xaccAccountInsertSplit(account, split); gnc_amount = gnc_ofx_numeric_from_double_txn( -ofx_get_investment_amount(&data), transaction); xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction)); // Set split memo from ofx transaction name or memo gnc_ofx_set_split_memo(&data, split); } } /* Send transaction to importer GUI. */ if (xaccTransCountSplits(transaction) > 0) { DEBUG("%d splits sent to the importer gui", xaccTransCountSplits(transaction)); gnc_gen_trans_list_add_trans (gnc_ofx_importer_gui, transaction); } else { PERR("No splits in transaction (missing account?), ignoring."); xaccTransDestroy(transaction); xaccTransCommitEdit(transaction); } } else { PERR("The transaction doesn't have a valid amount"); xaccTransDestroy(transaction); xaccTransCommitEdit(transaction); } return 0; }//end ofx_proc_transaction()