void xaccTransScrubOrphans (Transaction *trans) { SplitList *node; QofBook *book = NULL; Account *root = NULL; if (!trans) return; for (node = trans->splits; node; node = node->next) { Split *split = node->data; if (split->acc) { TransScrubOrphansFast (trans, gnc_account_get_root(split->acc)); return; } } /* If we got to here, then *none* of the splits belonged to an * account. Not a happy situation. We should dig an account * out of the book the transaction belongs to. * XXX we should probably *always* to this, instead of the above loop! */ PINFO ("Free Floating Transaction!"); book = xaccTransGetBook (trans); root = gnc_book_get_root_account (book); TransScrubOrphansFast (trans, root); }
/** 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))); }
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; }
/* Find the trading split for a commodity, but don't create any splits or accounts if they don't already exist. */ static Split * find_trading_split (Transaction *trans, Account *root, gnc_commodity *commodity) { Account *trading_account; Account *ns_account; Account *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; } } trading_account = gnc_account_lookup_by_name (root, _("Trading")); if (!trading_account) { return NULL; } ns_account = gnc_account_lookup_by_name (trading_account, gnc_commodity_get_namespace(commodity)); if (!ns_account) { return NULL; } account = gnc_account_lookup_by_name (ns_account, gnc_commodity_get_mnemonic(commodity)); if (!account) { return NULL; } return xaccTransFindSplitByAccount(trans, account); }
/* 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; }
static const char* node_and_transaction_equal (xmlNodePtr node, Transaction* trn) { 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:transaction")) { 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, "trn:id") == 0) { if (!equals_node_val_vs_guid (mark, xaccTransGetGUID (trn))) { return "ids differ"; } } /* This test will fail for many splits where the transaction has * splits in different commodities -- eg, buying or selling a * stock. jralls 2010-11-02 */ else if (g_strcmp0 ((char*)mark->name, "trn:currency") == 0) { #if 0 if (!equals_node_val_vs_commodity ( mark, xaccTransGetCurrency (trn), xaccTransGetBook (trn))) { return g_strdup ("currencies differ"); } #endif } else if (g_strcmp0 ((char*)mark->name, "trn:num") == 0) { if (!equals_node_val_vs_string (mark, xaccTransGetNum (trn))) { return "nums differ"; } } else if (g_strcmp0 ((char*)mark->name, "trn:date-posted") == 0) { if (!equals_node_val_vs_date (mark, xaccTransRetDatePostedTS (trn))) { return "posted dates differ"; } } else if (g_strcmp0 ((char*)mark->name, "trn:date-entered") == 0) { if (!equals_node_val_vs_date (mark, xaccTransRetDateEnteredTS (trn))) { return "entered dates differ"; } } else if (g_strcmp0 ((char*)mark->name, "trn:description") == 0) { if (!equals_node_val_vs_string (mark, xaccTransGetDescription (trn))) { return "descriptions differ"; } } else if (g_strcmp0 ((char*)mark->name, "trn:slots") == 0) { if (!equals_node_val_vs_kvp_frame (mark, qof_instance_get_slots (QOF_INSTANCE (trn)))) { return "slots differ"; } } else if (g_strcmp0 ((char*)mark->name, "trn:splits") == 0) { const char* msg = equals_node_val_vs_splits (mark, trn); if (msg != NULL) { return msg; } } else { return "unknown node"; } } return NULL; }