void xaccAccountScrubCommodity (Account *account) { gnc_commodity *commodity; if (!account) return; if (xaccAccountGetType(account) == ACCT_TYPE_ROOT) return; commodity = xaccAccountGetCommodity (account); if (commodity) return; /* Use the 'obsolete' routines to try to figure out what the * account commodity should have been. */ commodity = xaccAccountGetCommodity (account); if (commodity) { xaccAccountSetCommodity (account, commodity); return; } commodity = DxaccAccountGetCurrency (account); if (commodity) { xaccAccountSetCommodity (account, commodity); return; } PERR ("Account \"%s\" does not have a commodity!", xaccAccountGetName(account)); }
static void move_quote_source (Account *account, gpointer data) { gnc_commodity *com; gnc_quote_source *quote_source; gboolean new_style = GPOINTER_TO_INT(data); const char *source, *tz; com = xaccAccountGetCommodity(account); if (!com) return; if (!new_style) { source = dxaccAccountGetPriceSrc(account); if (!source || !*source) return; tz = dxaccAccountGetQuoteTZ(account); PINFO("to %8s from %s", gnc_commodity_get_mnemonic(com), xaccAccountGetName(account)); gnc_commodity_set_quote_flag(com, TRUE); quote_source = gnc_quote_source_lookup_by_internal(source); if (!quote_source) quote_source = gnc_quote_source_add_new(source, FALSE); gnc_commodity_set_quote_source(com, quote_source); gnc_commodity_set_quote_tz(com, tz); } dxaccAccountSetPriceSrc(account, NULL); dxaccAccountSetQuoteTZ(account, NULL); return; }
static void calculate_selected_total_helper (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { gnc_numeric *subtotal = (gnc_numeric*) data; gnc_numeric cur_val; GValue value = { 0 }; GNCLot *lot; Account *acct; gnc_commodity *currency; gtk_tree_model_get_value (model, iter, 5, &value); lot = (GNCLot *) g_value_get_pointer (&value); g_value_unset (&value); /* Find the amount's currency to determine the required precision */ acct = gnc_lot_get_account (lot); currency = xaccAccountGetCommodity (acct); cur_val = gnc_lot_get_balance (lot); *subtotal = gnc_numeric_add (*subtotal, cur_val, gnc_commodity_get_fraction (currency), GNC_HOW_RND_ROUND_HALF_UP); }
/* Is current split a security account */ static gboolean gtu_sr_use_security (GncTreeViewSplitReg *view) { RowDepth depth; Account *account = NULL; Split *split; split = gnc_tree_view_split_reg_get_current_split (view); depth = gnc_tree_view_reg_get_selected_row_depth (view); if (!split) return TRUE; if (depth != SPLIT3) return TRUE; if (!account) account = xaccSplitGetAccount (split); if (!account) return TRUE; if (xaccTransUseTradingAccounts (xaccSplitGetParent (split))) { if (!gnc_commodity_is_iso (xaccAccountGetCommodity (account))) return TRUE; } return xaccAccountIsPriced (account); }
static gboolean test_add_account (const char* tag, gpointer globaldata, gpointer data) { Account* account = static_cast<decltype (account)> (data); act_data* gdata = (act_data*)globaldata; gnc_commodity* com; gnc_commodity* new_com; gnc_commodity_table* t; com = xaccAccountGetCommodity (account); t = gnc_commodity_table_get_table (sixbook); new_com = gnc_commodity_table_lookup (t, gnc_commodity_get_namespace (com), gnc_commodity_get_mnemonic (com)); if (new_com) { xaccAccountSetCommodity (account, new_com); } do_test_args (xaccAccountEqual ((Account*)account, (Account*) (gdata->act), TRUE), "gnc_account_sixtp_parser_create", __FILE__, __LINE__, "%d", gdata->value); return TRUE; }
static gnc_commodity * xaccTransFindOldCommonCurrency (Transaction *trans, QofBook *book) { gnc_commodity *ra, *rb, *retval; Split *split; if (!trans) return NULL; if (trans->splits == NULL) return NULL; g_return_val_if_fail (book, NULL); split = trans->splits->data; if (!split || NULL == split->acc) return NULL; ra = DxaccAccountGetCurrency (split->acc); rb = xaccAccountGetCommodity (split->acc); retval = FindCommonCurrency (trans->splits, ra, rb); if (retval && !gnc_commodity_is_currency(retval)) retval = NULL; return retval; }
/** 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 gnc_numeric gnc_transaction_adjust_trading_splits (Transaction* trans, Account *root) { GList* splits; gnc_numeric imbalance = gnc_numeric_zero(); for (splits = trans->splits; splits; splits = splits->next) { Split *split = splits->data; Split *balance_split = NULL; gnc_numeric value, amount; gnc_commodity *commodity, *txn_curr = xaccTransGetCurrency (trans); if (! xaccTransStillHasSplit (trans, split)) continue; commodity = xaccAccountGetCommodity (xaccSplitGetAccount(split)); if (!commodity) { PERR("Split has no commodity"); continue; } balance_split = find_trading_split (trans, root, commodity); if (balance_split != split) /* this is not a trading split */ imbalance = gnc_numeric_add(imbalance, xaccSplitGetValue (split), GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT); /* Ignore splits where value or amount is zero */ value = xaccSplitGetValue (split); amount = xaccSplitGetAmount (split); if (gnc_numeric_zero_p(amount) || gnc_numeric_zero_p(value)) continue; if (balance_split && balance_split != split) { gnc_numeric convrate = gnc_numeric_div (amount, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE); gnc_numeric old_value, new_value; old_value = xaccSplitGetValue(balance_split); new_value = gnc_numeric_div (xaccSplitGetAmount(balance_split), convrate, gnc_commodity_get_fraction(txn_curr), GNC_HOW_RND_ROUND_HALF_UP); if (! gnc_numeric_equal (old_value, new_value)) { xaccTransBeginEdit (trans); xaccSplitSetValue (balance_split, new_value); xaccSplitScrub (balance_split); xaccTransCommitEdit (trans); } } } return imbalance; }
/** Balance the transaction by adding more trading splits. This shouldn't * ordinarily be necessary. * @param trans the transaction to balance * @param root the root account */ static void gnc_transaction_balance_trading_more_splits (Transaction *trans, Account *root) { /* Copy the split list so we don't see the splits we're adding */ GList *splits_dup = g_list_copy(trans->splits), *splits = NULL; const gnc_commodity *txn_curr = xaccTransGetCurrency (trans); for (splits = splits_dup; splits; splits = splits->next) { Split *split = splits->data; if (! xaccTransStillHasSplit(trans, split)) continue; if (!gnc_numeric_zero_p(xaccSplitGetValue(split)) && gnc_numeric_zero_p(xaccSplitGetAmount(split))) { gnc_commodity *commodity; gnc_numeric old_value, new_value; Split *balance_split; Account *account = NULL; commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split)); if (!commodity) { PERR("Split has no commodity"); continue; } balance_split = get_trading_split(trans, root, commodity); if (!balance_split) { /* Error already logged */ LEAVE(""); return; } account = xaccSplitGetAccount(balance_split); xaccTransBeginEdit (trans); old_value = xaccSplitGetValue (balance_split); new_value = gnc_numeric_sub (old_value, xaccSplitGetValue(split), gnc_commodity_get_fraction(txn_curr), GNC_HOW_RND_ROUND_HALF_UP); xaccSplitSetValue (balance_split, new_value); /* Don't change the balance split's amount since the amount is zero in the split we're working on */ xaccSplitScrub (balance_split); xaccTransCommitEdit (trans); } } g_list_free(splits_dup); }
static gboolean tt_act_handler( xmlNodePtr node, gpointer data ) { gnc_template_xaction_data *txd = data; Account *acc; gnc_commodity *com; acc = dom_tree_to_account(node, txd->book); if ( acc == NULL ) { return FALSE; } else { xaccAccountBeginEdit (acc); /* Check for the lack of a commodity [signifying that the pre-7/11/2001-CIT-change SX template Account was parsed [but incorrectly]. */ if ( xaccAccountGetCommodity( acc ) == NULL ) { #if 1 gnc_commodity_table* table; table = gnc_commodity_table_get_table( txd->book ); com = gnc_commodity_table_lookup( table, "template", "template" ); #else /* FIXME: This should first look in the table of the book, maybe? The right thing happens [WRT file load/save] if we just _new all the time, but it doesn't seem right. This whole block should go away at some point, but the same concern still applies for SchedXaction.c:xaccSchedXactionInit... */ com = gnc_commodity_new( txd->book, "template", "template", "template", "template", 1 ); #endif xaccAccountSetCommodity( acc, com ); } txd->accts = g_list_append( txd->accts, acc ); } return TRUE; }
/** Create a transaction and splits from a pair of trans and split property objects. * Note: this function assumes all properties have been verified * to be valid and the required properties are available. * @param parsed_line The current line being parsed * @return On success, a shared pointer to a DraftTransaction object; on failure a nullptr */ std::shared_ptr<DraftTransaction> GncTxImport::trans_properties_to_trans (std::vector<parse_line_t>::iterator& parsed_line) { auto created_trans = false; std::string error_message; std::shared_ptr<GncPreTrans> trans_props; std::shared_ptr<GncPreSplit> split_props; std::tie(std::ignore, error_message, trans_props, split_props, std::ignore) = *parsed_line; auto account = split_props->get_account(); QofBook* book = gnc_account_get_book (account); gnc_commodity* currency = xaccAccountGetCommodity (account); auto trans = trans_props->create_trans (book, currency); if (trans) { /* We're about to continue with a new transaction * Time to do some closing actions on the previous one */ if (m_current_draft && m_current_draft->void_reason) { /* The import data specifies this transaction was voided. * So void the created transaction as well. * Attention: this assumes the imported transaction was balanced. * If not, this will cause an imbalance split to be added automatically! */ xaccTransCommitEdit (m_current_draft->trans); xaccTransVoid (m_current_draft->trans, m_current_draft->void_reason->c_str()); } m_current_draft = std::make_shared<DraftTransaction>(trans); m_current_draft->void_reason = trans_props->get_void_reason(); created_trans = true; } else if (m_settings.m_multi_split) // in multi_split mode create_trans will return a nullptr for all but the first split trans = m_current_draft->trans; else // in non-multi-split mode each line should be a transaction, so not having one here is an error throw std::invalid_argument ("Failed to create transaction from selected columns."); if (!trans) return nullptr; split_props->create_split(trans); /* Only return the draft transaction if we really created a new one * The return value will be added to a list for further processing, * we want each transaction to appear only once in that list. */ return created_trans ? m_current_draft : nullptr; }
SCM gnc_account_value_ptr_to_scm (GncAccountValue *av) { swig_type_info * account_type = get_acct_type(); gnc_commodity * com; gnc_numeric val; if (!av) return SCM_BOOL_F; com = xaccAccountGetCommodity (av->account); val = gnc_numeric_convert (av->value, gnc_commodity_get_fraction (com), GNC_HOW_RND_ROUND_HALF_UP); return scm_cons (SWIG_NewPointerObj(av->account, account_type, 0), gnc_numeric_to_scm (val)); }
static Split * get_balance_split (Transaction *trans, Account *root, Account *account, gnc_commodity *commodity) { Split *balance_split; gchar *accname; if (!account || !gnc_commodity_equiv (commodity, xaccAccountGetCommodity(account))) { if (!root) { root = gnc_book_get_root_account (xaccTransGetBook (trans)); if (NULL == root) { /* This can't occur, things should be in books */ PERR ("Bad data corruption, no root account in book"); return NULL; } } accname = g_strconcat (_("Imbalance"), "-", gnc_commodity_get_mnemonic (commodity), NULL); account = xaccScrubUtilityGetOrMakeAccount (root, commodity, accname, ACCT_TYPE_BANK, FALSE); g_free (accname); if (!account) { PERR ("Can't get balancing account"); return NULL; } } balance_split = xaccTransFindSplitByAccount(trans, account); /* Put split into account before setting split value */ if (!balance_split) { balance_split = xaccMallocSplit (qof_instance_get_book(trans)); xaccTransBeginEdit (trans); xaccSplitSetParent(balance_split, trans); xaccSplitSetAccount(balance_split, account); xaccTransCommitEdit (trans); } return balance_split; }
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); }
// Commodity Namespace static gchar* add_comm_namespace (gchar *so_far, Transaction *trans, Split *split, CsvExportInfo *info) { const gchar *comm_n; gchar *conv; gchar *result; if (split == NULL) comm_n = gnc_commodity_get_namespace (xaccTransGetCurrency (trans)); else comm_n = gnc_commodity_get_namespace (xaccAccountGetCommodity (xaccSplitGetAccount(split))); conv = csv_txn_test_field_string (info, comm_n); result = g_strconcat (so_far, conv, info->mid_sep, NULL); g_free (conv); g_free (so_far); return result; }
/* returns TRUE if you need to convert the split's value to the local * (account) display currency. Returns FALSE if you can just use the * split->value directly. */ gboolean gnc_tree_util_split_reg_needs_conv_rate (GncTreeViewSplitReg *view, Transaction *trans, Account *acc) { gnc_commodity *trans_cur, *acc_com; /* If there is not a RATE_CELL, then don't do anything */ if (!gnc_tree_util_split_reg_has_rate (view)) return FALSE; /* if txn->currency == acc->commodity, then return FALSE */ acc_com = xaccAccountGetCommodity (acc); trans_cur = xaccTransGetCurrency (trans); if (trans_cur && acc_com && gnc_commodity_equal (trans_cur, acc_com)) return FALSE; return TRUE; }
static gnc_numeric gnc_transaction_get_commodity_imbalance (Transaction *trans, gnc_commodity *commodity) { /* Find the value imbalance in this commodity */ gnc_numeric val_imbalance = gnc_numeric_zero(); GList *splits = NULL; for (splits = trans->splits; splits; splits = splits->next) { Split *split = splits->data; gnc_commodity *split_commodity = xaccAccountGetCommodity(xaccSplitGetAccount(split)); if (xaccTransStillHasSplit (trans, split) && gnc_commodity_equal (commodity, split_commodity)) val_imbalance = gnc_numeric_add (val_imbalance, xaccSplitGetValue (split), GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT); } return val_imbalance; }
void gnc_payment_leave_amount_cb (GtkWidget *widget, GdkEventFocus *event, PaymentWindow *pw) { gnc_numeric amount_deb, amount_cred, amount_tot; if (! pw->amount_credit_edit || ! pw->amount_debit_edit) return; /* If both credit and debit amount are entered, simplify it to either one */ amount_deb = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_debit_edit)); amount_cred = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (pw->amount_credit_edit)); amount_tot = gnc_numeric_sub (amount_cred, amount_deb, gnc_commodity_get_fraction (xaccAccountGetCommodity (pw->post_acct)), GNC_HOW_RND_ROUND_HALF_UP); gnc_ui_payment_window_set_amount (pw, amount_tot); /* Reflect if the payment could complete now */ gnc_payment_window_check_payment (pw); }
static void add_balance_split (Transaction *trans, gnc_numeric imbalance, Account *root, Account *account) { const gnc_commodity *commodity; gnc_numeric old_value, new_value; Split *balance_split; gnc_commodity *currency = xaccTransGetCurrency (trans); balance_split = get_balance_split(trans, root, account, currency); if (!balance_split) { /* Error already logged */ LEAVE(""); return; } account = xaccSplitGetAccount(balance_split); xaccTransBeginEdit (trans); old_value = xaccSplitGetValue (balance_split); /* Note: We have to round for the commodity's fraction, NOT any * already existing denominator (bug #104343), because either one * of the denominators might already be reduced. */ new_value = gnc_numeric_sub (old_value, imbalance, gnc_commodity_get_fraction(currency), GNC_HOW_RND_ROUND_HALF_UP); xaccSplitSetValue (balance_split, new_value); commodity = xaccAccountGetCommodity (account); if (gnc_commodity_equiv (currency, commodity)) { xaccSplitSetAmount (balance_split, new_value); } xaccSplitScrub (balance_split); xaccTransCommitEdit (trans); }
/* Do we need an exchange rate */ static gboolean gtu_sr_needs_exchange_rate (GncTreeViewSplitReg *view, Transaction *trans, Split *split) { gnc_commodity *split_com, *txn_curr, *reg_com; ENTER("gtu_sr_needs_exchange_rate - trans %p and split %p", trans, split); txn_curr = xaccTransGetCurrency (trans); split_com = xaccAccountGetCommodity (xaccSplitGetAccount (split)); if (split_com && txn_curr && !gnc_commodity_equiv (split_com, txn_curr)) { LEAVE("gtu_sr_needs_exchange_rate split_com to txn_curr return TRUE"); return TRUE; } reg_com = gnc_tree_view_split_reg_get_reg_commodity (view); if (split_com && reg_com && !gnc_commodity_equiv (split_com, reg_com)) { LEAVE("gtu_sr_needs_exchange_rate split_com and reg_com return TRUE"); return TRUE; } LEAVE("No Exchange rate needed"); return FALSE; }
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); }
/* Get the trading split for a given commodity, creating it (and the necessary accounts) if it doesn't exist. */ static Split * get_trading_split (Transaction *trans, Account *root, gnc_commodity *commodity) { Split *balance_split; Account *trading_account; Account *ns_account; Account *account; gnc_commodity *default_currency = NULL; if (!root) { root = gnc_book_get_root_account (xaccTransGetBook (trans)); if (NULL == root) { /* This can't occur, things should be in books */ PERR ("Bad data corruption, no root account in book"); return NULL; } } /* Get the default currency. This is harder than it seems. It's not possible to call gnc_default_currency() since it's a UI function. One might think that the currency of the root account would do, but the root account has no currency. Instead look for the Income placeholder account and use its currency. */ default_currency = xaccAccountGetCommodity(gnc_account_lookup_by_name(root, _("Income"))); if (! default_currency) { default_currency = commodity; } trading_account = xaccScrubUtilityGetOrMakeAccount (root, default_currency, _("Trading"), ACCT_TYPE_TRADING, TRUE); if (!trading_account) { PERR ("Can't get trading account"); return NULL; } ns_account = xaccScrubUtilityGetOrMakeAccount (trading_account, default_currency, gnc_commodity_get_namespace(commodity), ACCT_TYPE_TRADING, TRUE); if (!ns_account) { PERR ("Can't get namespace account"); return NULL; } account = xaccScrubUtilityGetOrMakeAccount (ns_account, commodity, gnc_commodity_get_mnemonic(commodity), ACCT_TYPE_TRADING, FALSE); if (!account) { PERR ("Can't get commodity account"); return NULL; } balance_split = xaccTransFindSplitByAccount(trans, account); /* Put split into account before setting split value */ if (!balance_split) { balance_split = xaccMallocSplit (qof_instance_get_book(trans)); xaccTransBeginEdit (trans); xaccSplitSetParent(balance_split, trans); xaccSplitSetAccount(balance_split, account); xaccTransCommitEdit (trans); } return balance_split; }
void xaccSplitScrub (Split *split) { Account *account; Transaction *trans; gnc_numeric value, amount; gnc_commodity *currency, *acc_commodity; int scu; if (!split) return; ENTER ("(split=%p)", split); trans = xaccSplitGetParent (split); if (!trans) { LEAVE("no trans"); return; } account = xaccSplitGetAccount (split); /* If there's no account, this split is an orphan. * We need to fix that first, before proceeding. */ if (!account) { xaccTransScrubOrphans (trans); account = xaccSplitGetAccount (split); } /* Grrr... the register gnc_split_register_load() line 203 of * src/register/ledger-core/split-register-load.c will create * free-floating bogus transactions. Ignore these for now ... */ if (!account) { PINFO ("Free Floating Transaction!"); LEAVE ("no account"); return; } /* Split amounts and values should be valid numbers */ value = xaccSplitGetValue (split); if (gnc_numeric_check (value)) { value = gnc_numeric_zero(); xaccSplitSetValue (split, value); } amount = xaccSplitGetAmount (split); if (gnc_numeric_check (amount)) { amount = gnc_numeric_zero(); xaccSplitSetAmount (split, amount); } currency = xaccTransGetCurrency (trans); /* If the account doesn't have a commodity, * we should attempt to fix that first. */ acc_commodity = xaccAccountGetCommodity(account); if (!acc_commodity) { xaccAccountScrubCommodity (account); } if (!acc_commodity || !gnc_commodity_equiv(acc_commodity, currency)) { LEAVE ("(split=%p) inequiv currency", split); return; } scu = MIN (xaccAccountGetCommoditySCU (account), gnc_commodity_get_fraction (currency)); if (gnc_numeric_same (amount, value, scu, GNC_HOW_RND_ROUND_HALF_UP)) { LEAVE("(split=%p) different values", split); return; } /* * This will be hit every time you answer yes to the dialog "The * current transaction has changed. Would you like to record it. */ PINFO ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\"" " old amount %s %s, new amount %s", trans->description, split->memo, gnc_num_dbg_to_string (xaccSplitGetAmount(split)), gnc_commodity_get_mnemonic (currency), gnc_num_dbg_to_string (xaccSplitGetValue(split))); xaccTransBeginEdit (trans); xaccSplitSetAmount (split, value); xaccTransCommitEdit (trans); LEAVE ("(split=%p)", split); }
static void gnc_split_register_save_amount_values (SRSaveData *sd, SplitRegister *reg) { Account *acc; gnc_numeric new_amount, convrate, amtconv, value; gnc_commodity *curr, *reg_com, *xfer_com; Account *xfer_acc; new_amount = gnc_split_register_debcred_cell_value (reg); acc = gnc_split_register_get_default_account (reg); xfer_acc = xaccSplitGetAccount (sd->split); xfer_com = xaccAccountGetCommodity (xfer_acc); reg_com = xaccAccountGetCommodity (acc); curr = xaccTransGetCurrency (sd->trans); /* First, compute the conversion rate to convert the value to the * amount. */ amtconv = convrate = gnc_split_register_get_rate_cell (reg, RATE_CELL); if (acc && gnc_split_register_needs_conv_rate (reg, sd->trans, acc)) { /* If we are in an expanded register and the xfer_acc->comm != * reg_acc->comm then we need to compute the convrate here. * Otherwise, we _can_ use the rate_cell! */ if (sd->reg_expanded && ! gnc_commodity_equal (reg_com, xfer_com)) amtconv = xaccTransGetAccountConvRate(sd->trans, acc); } if (xaccTransUseTradingAccounts (sd->trans)) { /* Using currency accounts, the amount is probably really the amount and not the value. */ gboolean is_amount; if (reg->type == STOCK_REGISTER || reg->type == CURRENCY_REGISTER || reg->type == PORTFOLIO_LEDGER) { if (xaccAccountIsPriced(xfer_acc) || !gnc_commodity_is_iso(xaccAccountGetCommodity(xfer_acc))) is_amount = FALSE; else is_amount = TRUE; } else { is_amount = TRUE; } if (is_amount) { xaccSplitSetAmount(sd->split, new_amount); if (gnc_split_register_split_needs_amount (reg, sd->split)) { value = gnc_numeric_div(new_amount, amtconv, gnc_commodity_get_fraction(curr), GNC_HOW_RND_ROUND_HALF_UP); xaccSplitSetValue(sd->split, value); } else xaccSplitSetValue(sd->split, new_amount); } else { xaccSplitSetValue(sd->split, new_amount); } return; } /* How to interpret new_amount depends on our view of this * transaction. If we're sitting in an account with the same * commodity as the transaction, then we can set the Value and then * compute the amount. Otherwise we are setting the "converted * value". This means we need to convert new_amount to the actual * 'value' by dividing by the convrate in order to set the value. */ /* Now compute/set the split value. Amount is in the register * currency but we need to convert to the txn currency. */ if (gnc_split_register_needs_conv_rate (reg, sd->trans, acc)) { /* convert the amount to the Value ... */ value = gnc_numeric_div (new_amount, amtconv, gnc_commodity_get_fraction (curr), GNC_HOW_RND_ROUND_HALF_UP); xaccSplitSetValue (sd->split, value); } else xaccSplitSetValue (sd->split, new_amount); /* Now re-compute the Amount from the Value. We may need to convert * from the Value back to the amount here using the convrate from * earlier. */ value = xaccSplitGetValue (sd->split); if (gnc_split_register_split_needs_amount (reg, sd->split)) { acc = xaccSplitGetAccount (sd->split); new_amount = gnc_numeric_mul (value, convrate, xaccAccountGetCommoditySCU (acc), GNC_HOW_RND_ROUND_HALF_UP); xaccSplitSetAmount (sd->split, new_amount); } }
static gnc_commodity * FindCommonExclSCurrency (SplitList *splits, gnc_commodity * ra, gnc_commodity * rb, Split *excl_split) { GList *node; if (!splits) return NULL; for (node = splits; node; node = node->next) { Split *s = node->data; gnc_commodity * sa, * sb; if (s == excl_split) continue; g_return_val_if_fail (s->acc, NULL); sa = DxaccAccountGetCurrency (s->acc); sb = xaccAccountGetCommodity (s->acc); if (ra && rb) { int aa = !gnc_commodity_equiv(ra, sa); int ab = !gnc_commodity_equiv(ra, sb); int ba = !gnc_commodity_equiv(rb, sa); int bb = !gnc_commodity_equiv(rb, sb); if ( (!aa) && bb) rb = NULL; else if ( (!ab) && ba) rb = NULL; else if ( (!ba) && ab) ra = NULL; else if ( (!bb) && aa) ra = NULL; else if ( aa && bb && ab && ba ) { ra = NULL; rb = NULL; } if (!ra) { ra = rb; rb = NULL; } } else if (ra && !rb) { int aa = !gnc_commodity_equiv(ra, sa); int ab = !gnc_commodity_equiv(ra, sb); if ( aa && ab ) ra = NULL; } else if (!ra && rb) { int aa = !gnc_commodity_equiv(rb, sa); int ab = !gnc_commodity_equiv(rb, sb); ra = ( aa && ab ) ? NULL : rb; } if ((!ra) && (!rb)) return NULL; } return (ra); }
void xaccTransScrubCurrency (Transaction *trans) { SplitList *node; gnc_commodity *currency; if (!trans) return; /* If there are any orphaned splits in a transaction, then the * this routine will fail. Therefore, we want to make sure that * there are no orphans (splits without parent account). */ xaccTransScrubOrphans (trans); currency = xaccTransGetCurrency (trans); if (currency && gnc_commodity_is_currency(currency)) return; currency = xaccTransFindCommonCurrency (trans, qof_instance_get_book(trans)); if (currency) { xaccTransBeginEdit (trans); xaccTransSetCurrency (trans, currency); xaccTransCommitEdit (trans); } else { if (NULL == trans->splits) { PWARN ("Transaction \"%s\" has no splits in it!", trans->description); } else { SplitList *node; char guid_str[GUID_ENCODING_LENGTH + 1]; guid_to_string_buff(xaccTransGetGUID(trans), guid_str); PWARN ("no common transaction currency found for trans=\"%s\" (%s);", trans->description, guid_str); for (node = trans->splits; node; node = node->next) { Split *split = node->data; if (NULL == split->acc) { PWARN (" split=\"%s\" is not in any account!", split->memo); } else { gnc_commodity *currency = xaccAccountGetCommodity(split->acc); PWARN ("setting to split=\"%s\" account=\"%s\" commodity=\"%s\"", split->memo, xaccAccountGetName(split->acc), gnc_commodity_get_mnemonic(currency)); xaccTransBeginEdit (trans); xaccTransSetCurrency (trans, currency); xaccTransCommitEdit (trans); return; } } } return; } for (node = trans->splits; node; node = node->next) { Split *sp = node->data; if (!gnc_numeric_equal(xaccSplitGetAmount (sp), xaccSplitGetValue (sp))) { gnc_commodity *acc_currency; acc_currency = sp->acc ? xaccAccountGetCommodity(sp->acc) : NULL; if (acc_currency == currency) { /* This Split needs fixing: The transaction-currency equals * the account-currency/commodity, but the amount/values are * inequal i.e. they still correspond to the security * (amount) and the currency (value). In the new model, the * value is the amount in the account-commodity -- so it * needs to be set to equal the amount (since the * account-currency doesn't exist anymore). * * Note: Nevertheless we lose some information here. Namely, * the information that the 'amount' in 'account-old-security' * was worth 'value' in 'account-old-currency'. Maybe it would * be better to store that information in the price database? * But then, for old currency transactions there is still the * 'other' transaction, which is going to keep that * information. So I don't bother with that here. -- cstim, * 2002/11/20. */ PWARN ("Adjusted split with mismatched values, desc=\"%s\" memo=\"%s\"" " old amount %s %s, new amount %s", trans->description, sp->memo, gnc_num_dbg_to_string (xaccSplitGetAmount(sp)), gnc_commodity_get_mnemonic (currency), gnc_num_dbg_to_string (xaccSplitGetValue(sp))); xaccTransBeginEdit (trans); xaccSplitSetAmount (sp, xaccSplitGetValue(sp)); xaccTransCommitEdit (trans); } /*else { PINFO ("Ok: Split '%s' Amount %s %s, value %s %s", xaccSplitGetMemo (sp), gnc_num_dbg_to_string (amount), gnc_commodity_get_mnemonic (currency), gnc_num_dbg_to_string (value), gnc_commodity_get_mnemonic (acc_currency)); }*/ } } }
static gnc_commodity * xaccTransFindCommonCurrency (Transaction *trans, QofBook *book) { gnc_commodity *com_scratch; GList *node = NULL; GSList *comlist = NULL, *found = NULL; if (!trans) return NULL; if (trans->splits == NULL) return NULL; g_return_val_if_fail (book, NULL); /* Find the most commonly used currency among the splits. If a given split is in a non-currency commodity, then look for an ancestor account in a currency, but prefer currencies used directly in splits. Ignore trading account splits in this whole process, they don't add any value to this algorithm. */ for (node = trans->splits; node; node = node->next) { Split *s = node->data; unsigned int curr_weight; if (s == NULL || s->acc == NULL) continue; if (xaccAccountGetType(s->acc) == ACCT_TYPE_TRADING) continue; com_scratch = xaccAccountGetCommodity(s->acc); if (com_scratch && gnc_commodity_is_currency(com_scratch)) { curr_weight = 3; } else { com_scratch = gnc_account_get_currency_or_parent(s->acc); if (com_scratch == NULL) continue; curr_weight = 1; } if ( comlist ) { found = g_slist_find_custom(comlist, com_scratch, commodity_equal); } if (comlist == NULL || found == NULL) { CommodityCount *count = g_slice_new0(CommodityCount); count->commodity = com_scratch; count->count = curr_weight; comlist = g_slist_append(comlist, count); } else { CommodityCount *count = (CommodityCount*)(found->data); count->count += curr_weight; } } found = g_slist_sort( comlist, commodity_compare); if ( found && found->data && (((CommodityCount*)(found->data))->commodity != NULL)) { return ((CommodityCount*)(found->data))->commodity; } /* We didn't find a currency in the current account structure, so try * an old one. */ return xaccTransFindOldCommonCurrency( trans, book ); }
/** Create a Transaction from a TransPropertyList. * @param list The list of properties * @param error Contains an error on failure * @return On success, a GncCsvTransLine; on failure, the trans pointer is NULL */ static GncCsvTransLine* trans_property_list_to_trans (TransPropertyList* list, gchar** error) { GncCsvTransLine* trans_line = g_new (GncCsvTransLine, 1); GList* properties_begin = list->properties; QofBook* book = gnc_account_get_book (list->account); gnc_commodity* currency = xaccAccountGetCommodity (list->account); gnc_numeric amount = double_to_gnc_numeric (0.0, xaccAccountGetCommoditySCU (list->account), GNC_HOW_RND_ROUND_HALF_UP); gchar *num = NULL; /* This flag is set to TRUE if we can use the "Deposit" or "Withdrawal" column. */ gboolean amount_set = FALSE; /* The balance is 0 by default. */ trans_line->balance_set = FALSE; trans_line->balance = amount; trans_line->num = NULL; /* We make the line_no -1 just to mark that it hasn't been set. We * may get rid of line_no soon anyway, so it's not particularly * important. */ trans_line->line_no = -1; /* Make sure this is a transaction with all the columns we need. */ if (!trans_property_list_verify_essentials (list, error)) { g_free(trans_line); return NULL; } trans_line->trans = xaccMallocTransaction (book); xaccTransBeginEdit (trans_line->trans); xaccTransSetCurrency (trans_line->trans, currency); /* Go through each of the properties and edit the transaction accordingly. */ list->properties = properties_begin; while (list->properties != NULL) { TransProperty* prop = (TransProperty*)(list->properties->data); switch (prop->type) { case GNC_CSV_DATE: xaccTransSetDatePostedSecsNormalized (trans_line->trans, *((time64*)(prop->value))); break; case GNC_CSV_DESCRIPTION: xaccTransSetDescription (trans_line->trans, (char*)(prop->value)); break; case GNC_CSV_NOTES: xaccTransSetNotes (trans_line->trans, (char*)(prop->value)); break; case GNC_CSV_NUM: /* the 'num' is saved and passed to 'trans_add_split' below where * 'gnc_set_num_action' is used to set tran-num and/or split-action * per book option */ num = g_strdup ((char*)(prop->value)); /* the 'num' is also saved and used in 'gnc_csv_parse_to_trans' when * it calls 'trans_add_split' after deleting the splits added below * when a balance is used by the user */ trans_line->num = g_strdup ((char*)(prop->value)); break; case GNC_CSV_DEPOSIT: /* Add deposits to the existing amount. */ if (prop->value != NULL) { amount = gnc_numeric_add (*((gnc_numeric*)(prop->value)), amount, xaccAccountGetCommoditySCU (list->account), GNC_HOW_RND_ROUND_HALF_UP); amount_set = TRUE; /* We will use the "Deposit" and "Withdrawal" columns in preference to "Balance". */ trans_line->balance_set = FALSE; } break; case GNC_CSV_WITHDRAWAL: /* Withdrawals are just negative deposits. */ if (prop->value != NULL) { amount = gnc_numeric_add (gnc_numeric_neg(*((gnc_numeric*)(prop->value))), amount, xaccAccountGetCommoditySCU (list->account), GNC_HOW_RND_ROUND_HALF_UP); amount_set = TRUE; /* We will use the "Deposit" and "Withdrawal" columns in preference to "Balance". */ trans_line->balance_set = FALSE; } break; case GNC_CSV_BALANCE: /* The balance gets stored in a separate field in trans_line. */ /* We will use the "Deposit" and "Withdrawal" columns in preference to "Balance". */ if (!amount_set && prop->value != NULL) { /* This gets put into the actual transaction at the end of gnc_csv_parse_to_trans. */ trans_line->balance = *((gnc_numeric*)(prop->value)); trans_line->balance_set = TRUE; } break; } list->properties = g_list_next (list->properties); } /* Add a split with the cumulative amount value. */ trans_add_split (trans_line->trans, list->account, book, amount, num); if (num) g_free (num); return trans_line; }
static int fill_account_list (StockSplitInfo *info, Account *selected_account) { GtkTreeRowReference *reference = NULL; GtkTreeView *view; GtkListStore *list; GtkTreeIter iter; GtkTreePath *path; GList *accounts; GList *node; gint rows = 0; gchar *full_name; view = GTK_TREE_VIEW(info->account_view); list = GTK_LIST_STORE(gtk_tree_view_get_model(view)); gtk_list_store_clear (list); accounts = gnc_account_get_descendants_sorted (gnc_get_current_root_account ()); for (node = accounts; node; node = node->next) { Account *account = node->data; GNCPrintAmountInfo print_info; const gnc_commodity *commodity; gnc_numeric balance; if (!xaccAccountIsPriced(account)) continue; balance = xaccAccountGetBalance (account); if (gnc_numeric_zero_p (balance)) continue; if (xaccAccountGetPlaceholder (account)) continue; commodity = xaccAccountGetCommodity (account); full_name = gnc_account_get_full_name (account); print_info = gnc_account_print_info (account, FALSE); gtk_list_store_append(list, &iter); gtk_list_store_set(list, &iter, SPLIT_COL_ACCOUNT, account, SPLIT_COL_FULLNAME, full_name, SPLIT_COL_MNEMONIC, gnc_commodity_get_mnemonic(commodity), SPLIT_COL_SHARES, xaccPrintAmount(balance, print_info), -1); if (account == selected_account) { path = gtk_tree_model_get_path(GTK_TREE_MODEL(list), &iter); reference = gtk_tree_row_reference_new(GTK_TREE_MODEL(list), path); gtk_tree_path_free(path); } g_free (full_name); rows++; } g_list_free(accounts); if (reference) { GtkTreeSelection* selection = gtk_tree_view_get_selection(view); path = gtk_tree_row_reference_get_path(reference); gtk_tree_row_reference_free(reference); if (path) { gtk_tree_selection_select_path(selection, path); gtk_tree_view_scroll_to_cell(view, path, NULL, TRUE, 0.5, 0.0); gtk_tree_path_free(path); } } return rows; }