Ejemplo n.º 1
0
// Amount with Symbol or not
static gchar*
add_amount (gchar *so_far, Split *split, gboolean t_void, gboolean symbol, gint line_type, CsvExportInfo *info)
{
    const gchar *amt;
    gchar       *conv;
    gchar       *result;

    if (line_type == TRANS_COMPLEX)
        result = g_strconcat (so_far, "", info->mid_sep, NULL);
    else
    {
        if (symbol)
        {
            if (t_void)
                amt = xaccPrintAmount (gnc_numeric_zero(), gnc_split_amount_print_info (split, TRUE));
            else
                amt = xaccPrintAmount (xaccSplitGetAmount (split), gnc_split_amount_print_info (split, TRUE));
        }
        else
        {
            if (t_void)
                amt = xaccPrintAmount (xaccSplitVoidFormerAmount (split), gnc_split_amount_print_info (split, FALSE));
            else
                amt = xaccPrintAmount (xaccSplitGetAmount (split), gnc_split_amount_print_info (split, FALSE));
        }
        conv = csv_txn_test_field_string (info, amt);
        result = g_strconcat (so_far, conv, info->mid_sep, NULL);
        g_free (conv);
    }
    g_free (so_far);
    return result;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
static gboolean
spl_account_handler(xmlNodePtr node, gpointer data)
{
    struct split_pdata *pdata = data;
    GncGUID *id = dom_tree_to_guid(node);
    Account *account;

    g_return_val_if_fail(id, FALSE);

    account = xaccAccountLookup (id, pdata->book);
    if (!account && gnc_transaction_xml_v2_testing &&
            !guid_equal (id, guid_null ()))
    {
        account = xaccMallocAccount (pdata->book);
        xaccAccountSetGUID (account, id);
        xaccAccountSetCommoditySCU (account,
                                    xaccSplitGetAmount (pdata->split).denom);
    }

    xaccAccountInsertSplit (account, pdata->split);

    g_free(id);

    return TRUE;
}
Ejemplo n.º 4
0
/* Set the value for the given input amount */
void
gnc_tree_util_set_value_for_amount (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input)
{
    gnc_numeric  split_rate;
    gnc_numeric  amount;
    gnc_numeric  value, new_value;
    int denom;

    ENTER("trans %p and split %p and input is %s", trans, split, gnc_numeric_to_string (input));

    if (gnc_numeric_zero_p (input))
    {
        xaccSplitSetValue (split, input);
        xaccSplitSetAmount (split, input);
        LEAVE("zero");
        return;
    }

    amount = xaccSplitGetAmount (split);
    value = xaccSplitGetValue (split);

    denom = gtu_sr_get_value_denom (split);

    split_rate = gnc_numeric_div (value, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
    if (gnc_numeric_check (split_rate) != GNC_ERROR_OK)
        split_rate = gnc_numeric_create (100,100);

    new_value = gnc_numeric_mul (input, split_rate, denom, GNC_HOW_RND_ROUND_HALF_UP);

    xaccSplitSetValue (split, new_value);
    xaccSplitSetAmount (split, input);

    LEAVE("");
}
Ejemplo n.º 5
0
/********************************************************************\
 * gnc_reconcile_view_reconciled_balance                            *
 *   returns the reconciled balance of the view                     *
 *                                                                  *
 * Args: view - view to get reconciled balance of                   *
 * Returns: reconciled balance (gnc_numeric)                        *
\********************************************************************/
static void
grv_balance_hash_helper (gpointer key, gpointer value, gpointer user_data)
{
    Split *split = key;
    gnc_numeric *total = user_data;

    *total = gnc_numeric_add_fixed (*total, xaccSplitGetAmount (split));
}
Ejemplo n.º 6
0
static void
merge_splits (Split *sa, Split *sb)
{
    Account *act;
    Transaction *txn;
    gnc_numeric amt, val;

    act = xaccSplitGetAccount (sb);
    xaccAccountBeginEdit (act);

    txn = sa->parent;
    xaccTransBeginEdit (txn);

    /* Remove the guid of sb from the 'gemini' of sa */
    remove_guids (sa, sb);

    /* Add amount of sb into sa, ditto for value. */
    amt = xaccSplitGetAmount (sa);
    amt = gnc_numeric_add_fixed (amt, xaccSplitGetAmount (sb));
    xaccSplitSetAmount (sa, amt);

    val = xaccSplitGetValue (sa);
    val = gnc_numeric_add_fixed (val, xaccSplitGetValue (sb));
    xaccSplitSetValue (sa, val);

    /* Set reconcile to no; after this much violence,
     * no way its reconciled. */
    xaccSplitSetReconcile (sa, NREC);

    /* If sb has associated gains splits, trash them. */
    if ((sb->gains_split) &&
            (sb->gains_split->gains & GAINS_STATUS_GAINS))
    {
        Transaction *t = sb->gains_split->parent;
        xaccTransBeginEdit (t);
        xaccTransDestroy (t);
        xaccTransCommitEdit (t);
    }

    /* Finally, delete sb */
    xaccSplitDestroy(sb);

    xaccTransCommitEdit (txn);
    xaccAccountCommitEdit (act);
}
Ejemplo n.º 7
0
/** 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);
}
Ejemplo n.º 8
0
/* Get the rate */
gnc_numeric
gnc_tree_util_get_rate_for (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gboolean is_blank)
{
    gnc_numeric num;

    ENTER("trans %p and split %p is_blank %d", trans, split, is_blank);

    num = gnc_tree_util_split_reg_get_value_for (view, trans, split, is_blank);
//FIXME Not sure about this...
    if (xaccTransUseTradingAccounts (trans))
        num = gnc_numeric_div (num, xaccSplitGetValue (split), GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
    else
        num = gnc_numeric_div (xaccSplitGetAmount (split), num, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);

    LEAVE("split %p and return num is %s", split, gnc_numeric_to_string (num));
    return num;
}
Ejemplo n.º 9
0
static void
test_transaction(void)
{
    int i;

    for (i = 0; i < 50; i++)
    {
        Transaction *ran_trn;
        Account *root;
        xmlNodePtr test_node;
        gnc_commodity *com, *new_com;
        gchar *compare_msg;
        gchar *filename1;
        int fd;

        /* The next line exists for its side effect of creating the
         * account tree. */
        root = get_random_account_tree(book);
        ran_trn = get_random_transaction(book);
        new_com = get_random_commodity( book );
        if (!ran_trn)
        {
            failure_args("transaction_xml", __FILE__, __LINE__,
                         "get_random_transaction returned NULL");
            return;
        }

        {
            /* xaccAccountInsertSplit can reorder the splits. */
            GList * list = g_list_copy(xaccTransGetSplitList (ran_trn));
            GList * node = list;
            for ( ; node; node = node->next)
            {
                Split * s = node->data;
                Account * a = xaccMallocAccount(book);

                xaccAccountBeginEdit (a);
                xaccAccountSetCommodity( a, new_com );
                xaccAccountSetCommoditySCU (a, xaccSplitGetAmount (s).denom);
                xaccAccountInsertSplit (a, s);
                xaccAccountCommitEdit (a);
            }
            g_list_free(list);
        }

        com = xaccTransGetCurrency (ran_trn);

        test_node = gnc_transaction_dom_tree_create(ran_trn);
        if (!test_node)
        {
            failure_args("transaction_xml", __FILE__, __LINE__,
                         "gnc_transaction_dom_tree_create returned NULL");
            really_get_rid_of_transaction(ran_trn);
            continue;
        }

        if ((compare_msg = node_and_transaction_equal(test_node, ran_trn)) !=
                NULL)
        {
            failure_args("transaction_xml", __FILE__, __LINE__,
                         "node and transaction were not equal: %s",
                         compare_msg);
            xmlElemDump(stdout, NULL, test_node);
            printf("\n");
            fflush(stdout);
            xmlFreeNode(test_node);
            really_get_rid_of_transaction(ran_trn);
            continue;
        }
        else
        {
            success_args("transaction_xml", __FILE__, __LINE__, "%d", i );
        }

        filename1 = g_strdup_printf("test_file_XXXXXX");

        fd = g_mkstemp(filename1);

        write_dom_node_to_file(test_node, fd);

        close(fd);

        {
            GList * node = xaccTransGetSplitList (ran_trn);
            for ( ; node; node = node->next)
            {
                Split * s = node->data;
                Account * a1 = xaccSplitGetAccount(s);
                Account * a2 = xaccMallocAccount(book);

                xaccAccountBeginEdit (a2);
                xaccAccountSetCommoditySCU (a2, xaccAccountGetCommoditySCU (a1));
                xaccAccountSetGUID (a2, xaccAccountGetGUID (a1));
                xaccAccountCommitEdit (a2);
            }
        }

        {
            sixtp *parser;
            tran_data data;

            data.trn = ran_trn;
            data.com = com;
            data.value = i;

            g_print(" There will follow a bunch of CRIT scrub errors about the account not having a commodity. There isn't an account in the XML, so of course not. Ignore the errors\n");
            parser = gnc_transaction_sixtp_parser_create();

            if (!gnc_xml_parse_file(parser, filename1, test_add_transaction,
                                    (gpointer)&data, book))
            {
                failure_args("gnc_xml_parse_file returned FALSE",
                             __FILE__, __LINE__, "%d", i);
            }
            else
                really_get_rid_of_transaction (data.new_trn);

            /* no handling of circular data structures.  We'll do that later */
            /* sixtp_destroy(parser); */
        }

        g_unlink(filename1);
        g_free(filename1);
        really_get_rid_of_transaction(ran_trn);
        xmlFreeNode(test_node);
    }
}
Ejemplo n.º 10
0
void
gnc_autoclear_window_ok_cb (GtkWidget *widget,
                            AutoClearWindow *data)
{
    GList *node, *nc_list = 0, *toclear_list = 0;
    gnc_numeric toclear_value;
    GHashTable *sack;

    gtk_label_set_text(data->status_label, _("Searching for splits to clear ..."));

    /* Value we have to reach */
    toclear_value = gnc_amount_edit_get_amount(data->end_value);
    toclear_value = gnc_numeric_convert(toclear_value, xaccAccountGetCommoditySCU(data->account), GNC_HOW_RND_NEVER);

    /* Extract which splits are not cleared and compute the amount we have to clear */
    for (node = xaccAccountGetSplitList(data->account); node; node = node->next)
    {
        Split *split = (Split *)node->data;
        char recn;
        gnc_numeric value;

        recn = xaccSplitGetReconcile (split);
        value = xaccSplitGetAmount (split);

        if (recn == NREC)
            nc_list = g_list_append(nc_list, split);
        else
            toclear_value = gnc_numeric_sub_fixed(toclear_value, value);
    }

    /* Pretty print information */
    PINFO("Amount to clear: %s\n", gnc_numeric_to_string(toclear_value));
    PINFO("Available splits:\n");
    for (node = nc_list; node; node = node->next)
    {
        Split *split = (Split *)node->data;
        gnc_numeric value = xaccSplitGetAmount (split);
        PINFO("  %s\n", gnc_numeric_to_string(value));
    }

    /* Run knapsack */
    /* Entries in the hash table are:
     *  - key   = amount to which we know how to clear (freed by GHashTable)
     *  - value = last split we used to clear this amount (not managed by GHashTable)
     */
    PINFO("Knapsacking ...\n");
    sack = g_hash_table_new_full (ght_gnc_numeric_hash, ght_gnc_numeric_equal, g_free, NULL);
    for (node = nc_list; node; node = node->next)
    {
        Split *split = (Split *)node->data;
        gnc_numeric split_value = xaccSplitGetAmount(split);

        GList *node;
        struct _sack_foreach_data_t data[1];
        data->split_value = split_value;
        data->reachable_list = 0;

        PINFO("  Split value: %s\n", gnc_numeric_to_string(split_value));

        /* For each value in the sack, compute a new reachable value */
        g_hash_table_foreach (sack, sack_foreach_func, data);

        /* Add the value of the split itself to the reachable_list */
        data->reachable_list = g_list_append(data->reachable_list, g_memdup(&split_value, sizeof(gnc_numeric)));

        /* Add everything to the sack, looking out for duplicates */
        for (node = data->reachable_list; node; node = node->next)
        {
            gnc_numeric *reachable_value = node->data;
            Split *toinsert_split = split;

            PINFO("    Reachable value: %s ", gnc_numeric_to_string(*reachable_value));

            /* Check if it already exists */
            if (g_hash_table_lookup_extended(sack, reachable_value, NULL, NULL))
            {
                /* If yes, we are in trouble, we reached an amount using two solutions */
                toinsert_split = NULL;
                PINFO("dup");
            }
            g_hash_table_insert (sack, reachable_value, toinsert_split);
            PINFO("\n");
        }
        g_list_free(data->reachable_list);
    }

    /* Check solution */
    PINFO("Rebuilding solution ...\n");
    while (!gnc_numeric_zero_p(toclear_value))
    {
        gpointer psplit = NULL;

        PINFO("  Left to clear: %s\n", gnc_numeric_to_string(toclear_value));
        if (g_hash_table_lookup_extended(sack, &toclear_value, NULL, &psplit))
        {
            if (psplit != NULL)
            {
                /* Cast the gpointer to the kind of pointer we actually need */
                Split *split = (Split *)psplit;
                toclear_list = g_list_prepend(toclear_list, split);
                toclear_value = gnc_numeric_sub_fixed(toclear_value,
                                                      xaccSplitGetAmount(split));
                PINFO("    Cleared: %s -> %s\n",
                      gnc_numeric_to_string(xaccSplitGetAmount(split)),
                      gnc_numeric_to_string(toclear_value));
            }
            else
            {
                /* We couldn't reconstruct the solution */
                PINFO("    Solution not unique.\n");
                gtk_label_set_text(data->status_label, _("Cannot uniquely clear splits. Found multiple possibilities."));
                return;
            }
        }
        else
        {
            PINFO("    No solution found.\n");
            gtk_label_set_text(data->status_label, _("The selected amount cannot be cleared."));
            return;
        }
    }
    g_hash_table_destroy (sack);

    /* Show solution */
    PINFO("Clearing splits:\n");
    for (node = toclear_list; node; node = node->next)
    {
        Split *split = node->data;
        char recn;
        gnc_numeric value;

        recn = xaccSplitGetReconcile (split);
        value = xaccSplitGetAmount (split);

        PINFO("  %c %s\n", recn, gnc_numeric_to_string(value));

        xaccSplitSetReconcile (split, CREC);
    }
    if (toclear_list == 0)
        PINFO("  None\n");

    /* Free lists */
    g_list_free(nc_list);
    g_list_free(toclear_list);

    /* Close window */
    gtk_widget_destroy(data->window);
    g_free(data);
}
Ejemplo n.º 11
0
gboolean
gnc_tree_util_split_reg_get_debcred_entry (GncTreeViewSplitReg *view,
                                      Transaction *trans, Split *split,
                                      gboolean is_blank, gnc_numeric *ret_num,
                                      GNCPrintAmountInfo *ret_print_info)

{
    GncTreeModelSplitReg *model;
    gnc_commodity *currency;

    model = gnc_tree_view_split_reg_get_model_from_view (view);

    currency = xaccTransGetCurrency (trans);
    if (!currency)
        currency = gnc_default_currency ();

    if (is_blank)
    {
        gnc_numeric imbalance;
        Account *acc;

        imbalance = xaccTransGetImbalanceValue (trans);

        if (gnc_numeric_zero_p (imbalance))
            return FALSE;

        if (xaccTransUseTradingAccounts (trans))
        {
            MonetaryList *imbal_list;
            gnc_monetary *imbal_mon;
            imbal_list = xaccTransGetImbalance (trans);

            if (!imbal_list)
            {
                /* No commodity imbalance, there shouldn't be a value imablance. */
                return FALSE;
            }

            if (imbal_list->next)
            {
                /* Multiple currency imbalance. */
                gnc_monetary_list_free (imbal_list);
                return FALSE;
            }

            imbal_mon = imbal_list->data;
            if (!gnc_commodity_equal (gnc_monetary_commodity (*imbal_mon), currency))
            {
                /* Imbalance is in wrong currency */
                gnc_monetary_list_free (imbal_list);
                return FALSE;
            }

            if (!gnc_numeric_equal (gnc_monetary_value (*imbal_mon), imbalance))
            {
                /* Value and commodity imbalances differ */
                gnc_monetary_list_free (imbal_list);
                return FALSE;
            }

            /* Done with the imbalance list */
            gnc_monetary_list_free (imbal_list);
        }

        imbalance = gnc_numeric_neg (imbalance);

        acc = gnc_tree_model_split_reg_get_anchor (model);

        if (gnc_tree_util_split_reg_needs_conv_rate (view, trans, acc))
        {
            imbalance = gnc_numeric_mul (imbalance,
                                         xaccTransGetAccountConvRate (trans, acc),
                                         gnc_commodity_get_fraction (currency),
                                         GNC_HOW_RND_ROUND_HALF_UP);
        }
        else
        {
            imbalance = gnc_numeric_convert (imbalance,
                                             gnc_commodity_get_fraction (currency),
                                             GNC_HOW_RND_ROUND_HALF_UP);
        }

        *ret_num = imbalance;
        *ret_print_info = gnc_account_print_info (acc, FALSE);
         return TRUE;
    }

    {
        gnc_numeric amount;
        gnc_commodity *split_commodity;
        GNCPrintAmountInfo print_info;
        Account *account;
        gnc_commodity *commodity;

        account = gnc_tree_model_split_reg_get_anchor (model);

        commodity = xaccAccountGetCommodity (account);
        split_commodity = xaccAccountGetCommodity (xaccSplitGetAccount (split));

        if (xaccTransUseTradingAccounts (trans))
        {
            gboolean use_symbol, is_current = FALSE;
            Split *current_split = gnc_tree_view_split_reg_get_current_split (view);
            RowDepth depth = gnc_tree_view_reg_get_selected_row_depth (view);

            if ((split == current_split) && (depth == SPLIT3))
                is_current = TRUE;

            if (model->type == STOCK_REGISTER2 ||
                    model->type == CURRENCY_REGISTER2 ||
                    model->type == PORTFOLIO_LEDGER2)
            {
                gnc_commodity *amount_commodity;
                /* security register.  If this split has price and shares columns,
                   use the value, otherwise use the amount.  */
                if (gtu_sr_use_security (view))
                {
                    amount = xaccSplitGetValue (split);
                    amount_commodity = currency;
                }
                else
                {
                    amount = xaccSplitGetAmount (split);
                    amount_commodity = split_commodity;
                }
                /* Show the currency if it is not the default currency */
                if (is_current ||
                        gnc_commodity_equiv (amount_commodity, gnc_default_currency ()))
                    use_symbol = FALSE;
                else
                    use_symbol = TRUE;
                print_info = gnc_commodity_print_info (amount_commodity, use_symbol);
            }
            else
            {
                /* non-security register, always use the split amount. */
                amount = xaccSplitGetAmount (split);
                if (is_current ||
                        gnc_commodity_equiv (split_commodity, commodity))
                    use_symbol = FALSE;
                else
                    use_symbol = TRUE;
                print_info = gnc_commodity_print_info (split_commodity, use_symbol);
            }
        }
        else
        {
            /* If this account is not a stock/mutual/currency account, and
            * currency != the account commodity, then use the SplitAmount
            * instead of the SplitValue.
            */
            switch (model->type)
            {
            case STOCK_REGISTER2:
            case CURRENCY_REGISTER2:
            case PORTFOLIO_LEDGER2:
                amount = xaccSplitGetValue (split);
                print_info = gnc_commodity_print_info (currency, FALSE);
                break;

            default:
                if (commodity && !gnc_commodity_equal (commodity, currency))
                    /* Convert this to the "local" value */
                    amount = xaccSplitConvertAmount (split, account);
                else
                    amount = xaccSplitGetValue (split);
                print_info = gnc_account_print_info (account, FALSE);
                break;
            }
        }

        if (gnc_numeric_zero_p (amount))
            return FALSE;

        *ret_num = amount;
        *ret_print_info = print_info;
         return TRUE;
    }
}
Ejemplo n.º 12
0
static void
downloaded_transaction_changed_cb (GtkTreeSelection *selection,
                                   GNCImportMatchPicker *matcher)
{
    GNCImportMatchInfo * match_info;
    GtkTreeModel *dl_model;
    GtkListStore *match_store;
    GtkTreeIter iter;
    GList * list_element;
    gchar *text;
    const gchar *ro_text;
    /*DEBUG("row: %d%s%d",row,", column: ",column);*/

    /* Get the transaction info from the "downloaded" model.  */
    if (!gtk_tree_selection_get_selected(selection, &dl_model, &iter))
    {
        matcher->selected_trans_info = NULL;
        return;
    }
    gtk_tree_model_get(dl_model, &iter,
                       DOWNLOADED_COL_INFO_PTR, &matcher->selected_trans_info,
                       -1);

    /* Now rewrite the "match" model based on that trans. */
    match_store = GTK_LIST_STORE(gtk_tree_view_get_model(matcher->match_view));
    gtk_list_store_clear(match_store);
    list_element = g_list_first (gnc_import_TransInfo_get_match_list
                                 (matcher->selected_trans_info));
    while (list_element != NULL)
    {
        match_info = list_element->data;

        gtk_list_store_append(match_store, &iter);

        /* Print fields. */

        /* Probability */
        text = g_strdup_printf("%d", gnc_import_MatchInfo_get_probability (match_info));
        gtk_list_store_set(match_store, &iter, MATCHER_COL_CONFIDENCE, text, -1);
        g_free(text);

        /* Date */
        text =
            qof_print_date
            ( xaccTransGetDate
              ( xaccSplitGetParent
                ( gnc_import_MatchInfo_get_split(match_info) ) ));
        gtk_list_store_set(match_store, &iter, MATCHER_COL_DATE, text, -1);
        g_free(text);

        /* Amount */
        ro_text =
            xaccPrintAmount( xaccSplitGetAmount ( gnc_import_MatchInfo_get_split(match_info)  ),
                             gnc_split_amount_print_info(gnc_import_MatchInfo_get_split(match_info), TRUE)
                           );
        gtk_list_store_set(match_store, &iter, MATCHER_COL_AMOUNT, ro_text, -1);

        /*Description*/
        ro_text = xaccTransGetDescription
                  ( xaccSplitGetParent( gnc_import_MatchInfo_get_split(match_info)) );
        gtk_list_store_set(match_store, &iter, MATCHER_COL_DESCRIPTION, ro_text, -1);

        /*Split memo*/
        ro_text = xaccSplitGetMemo(gnc_import_MatchInfo_get_split(match_info) );
        gtk_list_store_set(match_store, &iter, MATCHER_COL_MEMO, ro_text, -1);

        gtk_list_store_set(match_store, &iter, MATCHER_COL_INFO_PTR, match_info, -1);
        if (gnc_import_MatchInfo_get_probability(match_info) != 0)
        {
            if (SHOW_NUMERIC_SCORE == TRUE)
            {
                gtk_list_store_set(match_store, &iter,
                                   MATCHER_COL_CONFIDENCE_PIXBUF,
                                   gen_probability_pixbuf(gnc_import_MatchInfo_get_probability(match_info),
                                           matcher->user_settings,
                                           GTK_WIDGET(matcher->match_view)),
                                   -1);
            }
            else
            {
                gtk_list_store_set(match_store, &iter,
                                   MATCHER_COL_CONFIDENCE_PIXBUF,
                                   gen_probability_pixbuf(gnc_import_MatchInfo_get_probability(match_info),
                                           matcher->user_settings,
                                           GTK_WIDGET(matcher->match_view)),
                                   -1);
            }
        }

        if (match_info ==
                gnc_import_TransInfo_get_selected_match (matcher->selected_trans_info))
        {
            GtkTreeSelection *selection;

            selection = gtk_tree_view_get_selection(matcher->match_view);
            gtk_tree_selection_select_iter(selection, &iter);
        }

        list_element = g_list_next(list_element);
    }
}
Ejemplo n.º 13
0
 Numeric getAmount() const { return xaccSplitGetAmount(get()); }
Ejemplo n.º 14
0
void
xaccTransWriteLog (Transaction *trans, char flag)
{
    GList *node;
    char trans_guid_str[GUID_ENCODING_LENGTH + 1];
    char split_guid_str[GUID_ENCODING_LENGTH + 1];
    const char *trans_notes;
    char dnow[100], dent[100], dpost[100], drecn[100];
    Timespec ts;

    if (!gen_logs) return;
    if (!trans_log) return;

    timespecFromTime_t(&ts, time(NULL));
    gnc_timespec_to_iso8601_buff (ts, dnow);

    timespecFromTime_t(&ts, trans->date_entered.tv_sec);
    gnc_timespec_to_iso8601_buff (ts, dent);

    timespecFromTime_t(&ts, trans->date_posted.tv_sec);
    gnc_timespec_to_iso8601_buff (ts, dpost);

    guid_to_string_buff (xaccTransGetGUID(trans), trans_guid_str);
    trans_notes = xaccTransGetNotes(trans);
    fprintf (trans_log, "===== START\n");

    for (node = trans->splits; node; node = node->next)
    {
        Split *split = node->data;
        const char * accname = "";
        char acc_guid_str[GUID_ENCODING_LENGTH + 1];
        gnc_numeric amt, val;

        if (xaccSplitGetAccount(split))
        {
            accname = xaccAccountGetName (xaccSplitGetAccount(split));
            guid_to_string_buff(xaccAccountGetGUID(xaccSplitGetAccount(split)),
                                acc_guid_str);
        }
        else
        {
            acc_guid_str[0] = '\0';
        }

        timespecFromTime_t(&ts, split->date_reconciled.tv_sec);
        gnc_timespec_to_iso8601_buff (ts, drecn);

        guid_to_string_buff (xaccSplitGetGUID(split), split_guid_str);
        amt = xaccSplitGetAmount (split);
        val = xaccSplitGetValue (split);

        /* use tab-separated fields */
        fprintf (trans_log,
                 "%c\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t"
                 "%s\t%s\t%s\t%s\t%c\t%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT "\t%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT "\t%s\n",
                 flag,
                 trans_guid_str, split_guid_str,  /* trans+split make up unique id */
                 /* Note that the next three strings always exist,
                 		* so we don't need to test them. */
                 dnow,
                 dent,
                 dpost,
                 acc_guid_str,
                 accname ? accname : "",
                 trans->num ? trans->num : "",
                 trans->description ? trans->description : "",
                 trans_notes ? trans_notes : "",
                 split->memo ? split->memo : "",
                 split->action ? split->action : "",
                 split->reconciled,
                 gnc_numeric_num(amt),
                 gnc_numeric_denom(amt),
                 gnc_numeric_num(val),
                 gnc_numeric_denom(val),
                 /* The next string always exists. No need to test it. */
                 drecn);
    }

    fprintf (trans_log, "===== END\n");

    /* get data out to the disk */
    fflush (trans_log);
}
Ejemplo n.º 15
0
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);
}
Ejemplo n.º 16
0
static xmlNodePtr
split_to_dom_tree(const gchar *tag, Split *spl)
{
    xmlNodePtr ret;

    ret = xmlNewNode(NULL, BAD_CAST tag);

    xmlAddChild(ret, guid_to_dom_tree("split:id", xaccSplitGetGUID(spl)));

    {
        char *memo = g_strdup (xaccSplitGetMemo(spl));

        if (memo && g_strcmp0(memo, "") != 0)
        {
            xmlNewTextChild(ret, NULL, BAD_CAST "split:memo",
			    checked_char_cast (memo));
        }
	g_free (memo);
    }

    {
        char *action = g_strdup (xaccSplitGetAction(spl));

        if (action && g_strcmp0(action, "") != 0)
        {
            xmlNewTextChild(ret, NULL, BAD_CAST "split:action",
			    checked_char_cast (action));
        }
	g_free (action);
    }

    {
        char tmp[2];

        tmp[0] = xaccSplitGetReconcile(spl);
        tmp[1] = '\0';

        xmlNewTextChild(ret, NULL, BAD_CAST "split:reconciled-state",
			BAD_CAST tmp);
    }

    add_timespec(ret, "split:reconcile-date",
                 xaccSplitRetDateReconciledTS(spl), FALSE);

    add_gnc_num(ret, "split:value", xaccSplitGetValue(spl));

    add_gnc_num(ret, "split:quantity", xaccSplitGetAmount(spl));

    {
        Account * account = xaccSplitGetAccount (spl);

        xmlAddChild (ret, guid_to_dom_tree("split:account",
                                           xaccAccountGetGUID (account)));
    }
    {
        GNCLot * lot = xaccSplitGetLot (spl);

        if (lot)
        {
            xmlAddChild (ret, guid_to_dom_tree("split:lot",
                                               gnc_lot_get_guid(lot)));
        }
    }
    {
        xmlNodePtr kvpnode = kvp_frame_to_dom_tree("split:slots",
                             xaccSplitGetSlots(spl));
        if (kvpnode)
        {
            xmlAddChild(ret, kvpnode);
        }
    }

    return ret;
}
Ejemplo n.º 17
0
static void
gnc_transaction_balance_trading (Transaction *trans, Account *root)
{
    MonetaryList *imbal_list;
    MonetaryList *imbalance_commod;
    Split *balance_split = NULL;

    /* If the transaction is balanced, nothing more to do */
    imbal_list = xaccTransGetImbalance (trans);
    if (!imbal_list)
    {
        LEAVE("transaction is balanced");
        return;
    }

    PINFO ("Currency unbalanced transaction");

    for (imbalance_commod = imbal_list; imbalance_commod;
         imbalance_commod = imbalance_commod->next)
    {
        gnc_monetary *imbal_mon = imbalance_commod->data;
        gnc_commodity *commodity;
        gnc_numeric old_amount, new_amount;
        gnc_numeric old_value, new_value, val_imbalance;
        Account *account = NULL;
        const gnc_commodity *txn_curr = xaccTransGetCurrency (trans);

        commodity = gnc_monetary_commodity (*imbal_mon);

        balance_split = get_trading_split(trans, root, commodity);
        if (!balance_split)
        {
            /* Error already logged */
            gnc_monetary_list_free(imbal_list);
            LEAVE("");
            return;
        }

        account = xaccSplitGetAccount(balance_split);

        if (! gnc_commodity_equal (txn_curr, commodity))
        {
            val_imbalance = gnc_transaction_get_commodity_imbalance (trans, commodity);
        }

        xaccTransBeginEdit (trans);

        old_amount = xaccSplitGetAmount (balance_split);
        new_amount = gnc_numeric_sub (old_amount, gnc_monetary_value(*imbal_mon),
                                      gnc_commodity_get_fraction(commodity),
                                      GNC_HOW_RND_ROUND_HALF_UP);

        xaccSplitSetAmount (balance_split, new_amount);

        if (gnc_commodity_equal (txn_curr, commodity))
        {
            /* Imbalance commodity is the transaction currency, value in the
               split must be the same as the amount */
            xaccSplitSetValue (balance_split, new_amount);
        }
        else
        {
            old_value = xaccSplitGetValue (balance_split);
            new_value = gnc_numeric_sub (old_value, val_imbalance,
                                         gnc_commodity_get_fraction(txn_curr),
                                         GNC_HOW_RND_ROUND_HALF_UP);

            xaccSplitSetValue (balance_split, new_value);
        }

        xaccSplitScrub (balance_split);
        xaccTransCommitEdit (trans);
    }

    gnc_monetary_list_free(imbal_list);
}
Ejemplo n.º 18
0
void
xaccScrubSubSplitPrice (Split *split, int maxmult, int maxamtscu)
{
    gnc_numeric src_amt, src_val;
    SplitList *node;

    if (FALSE == is_subsplit (split)) return;

    ENTER (" ");
    /* Get 'price' of the indicated split */
    src_amt = xaccSplitGetAmount (split);
    src_val = xaccSplitGetValue (split);

    /* Loop over splits, adjust each so that it has the same
     * ratio (i.e. price).  Change the value to get things
     * right; do not change the amount */
    for (node = split->parent->splits; node; node = node->next)
    {
        Split *s = node->data;
        Transaction *txn = s->parent;
        gnc_numeric dst_amt, dst_val, target_val;
        gnc_numeric frac, delta;
        int scu;

        /* Skip the reference split */
        if (s == split) continue;

        scu = gnc_commodity_get_fraction (txn->common_currency);

        dst_amt = xaccSplitGetAmount (s);
        dst_val = xaccSplitGetValue (s);
        frac = gnc_numeric_div (dst_amt, src_amt,
                                GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
        target_val = gnc_numeric_mul (frac, src_val,
                                      scu, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
        if (gnc_numeric_check (target_val))
        {
            PERR ("Numeric overflow of value\n"
                  "\tAcct=%s txn=%s\n"
                  "\tdst_amt=%s src_val=%s src_amt=%s\n",
                  xaccAccountGetName (s->acc),
                  xaccTransGetDescription(txn),
                  gnc_num_dbg_to_string(dst_amt),
                  gnc_num_dbg_to_string(src_val),
                  gnc_num_dbg_to_string(src_amt));
            continue;
        }

        /* If the required price changes are 'small', do nothing.
         * That is a case that the user will have to deal with
         * manually.  This routine is really intended only for
         * a gross level of synchronization.
         */
        delta = gnc_numeric_sub_fixed (target_val, dst_val);
        delta = gnc_numeric_abs (delta);
        if (maxmult * delta.num  < delta.denom) continue;

        /* If the amount is small, pass on that too */
        if ((-maxamtscu < dst_amt.num) && (dst_amt.num < maxamtscu)) continue;

        /* Make the actual adjustment */
        xaccTransBeginEdit (txn);
        xaccSplitSetValue (s, target_val);
        xaccTransCommitEdit (txn);
    }
    LEAVE (" ");
}
Ejemplo n.º 19
0
void
xaccTransScrubImbalance (Transaction *trans, Account *root,
                         Account *account)
{
    const gnc_commodity *currency;

    if (!trans) return;

    ENTER ("()");

    /* Must look for orphan splits even if there is no imbalance. */
    xaccTransScrubSplits (trans);

    /* Return immediately if things are balanced. */
    if (xaccTransIsBalanced (trans))
    {
        LEAVE ("transaction is balanced");
        return;
    }

    currency = xaccTransGetCurrency (trans);

    if (! xaccTransUseTradingAccounts (trans))
    {
        gnc_numeric imbalance;

        /* Make the value sum to zero */
        imbalance = xaccTransGetImbalanceValue (trans);
        if (! gnc_numeric_zero_p (imbalance))
        {
            PINFO ("Value unbalanced transaction");

            add_balance_split (trans, imbalance, root, account);
        }
    }
    else
    {
        MonetaryList *imbal_list;
        MonetaryList *imbalance_commod;
        GList *splits;
        gnc_numeric imbalance;
        Split *balance_split = NULL;

        /* If there are existing trading splits, adjust the price or exchange
           rate in each of them to agree with the non-trading splits for the
           same commodity.  If there are multiple non-trading splits for the
           same commodity in the transaction this will use the exchange rate in
           the last such split.  This shouldn't happen, and if it does then there's
           not much we can do about it anyway.

           While we're at it, compute the value imbalance ignoring existing
           trading splits. */

        imbalance = gnc_numeric_zero();

        for (splits = trans->splits; splits; splits = splits->next)
        {
            Split *split = splits->data;
            gnc_numeric value, amount;
            gnc_commodity *commodity;

            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(currency),
                                             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);
                }
            }
        }

        /* Balance the value, ignoring existing trading splits */
        if (! gnc_numeric_zero_p (imbalance))
        {
            PINFO ("Value unbalanced transaction");

            add_balance_split (trans, imbalance, root, account);
        }

        /* If the transaction is balanced, nothing more to do */
        imbal_list = xaccTransGetImbalance (trans);
        if (!imbal_list)
        {
            LEAVE("transaction is balanced");
            return;
        }

        PINFO ("Currency unbalanced transaction");

        for (imbalance_commod = imbal_list; imbalance_commod;
                imbalance_commod = imbalance_commod->next)
        {
            gnc_monetary *imbal_mon = imbalance_commod->data;
            gnc_commodity *commodity;
            gnc_numeric old_amount, new_amount;
            gnc_numeric old_value, new_value, val_imbalance;
            GList *splits;

            commodity = gnc_monetary_commodity (*imbal_mon);

            balance_split = get_trading_split(trans, root, commodity);
            if (!balance_split)
            {
                /* Error already logged */
                gnc_monetary_list_free(imbal_list);
                LEAVE("");
                return;
            }

            account = xaccSplitGetAccount(balance_split);

            if (! gnc_commodity_equal (currency, commodity))
            {
                /* Find the value imbalance in this commodity */
                val_imbalance = gnc_numeric_zero();
                for (splits = trans->splits; splits; splits = splits->next)
                {
                    Split *split = splits->data;
                    if (xaccTransStillHasSplit (trans, split) &&
                            gnc_commodity_equal (commodity,
                                                 xaccAccountGetCommodity(xaccSplitGetAccount(split))))
                        val_imbalance = gnc_numeric_add (val_imbalance, xaccSplitGetValue (split),
                                                         GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
                }
            }

            xaccTransBeginEdit (trans);

            old_amount = xaccSplitGetAmount (balance_split);
            new_amount = gnc_numeric_sub (old_amount, gnc_monetary_value(*imbal_mon),
                                          gnc_commodity_get_fraction(commodity),
                                          GNC_HOW_RND_ROUND_HALF_UP);

            xaccSplitSetAmount (balance_split, new_amount);

            if (gnc_commodity_equal (currency, commodity))
            {
                /* Imbalance commodity is the transaction currency, value in the
                   split must be the same as the amount */
                xaccSplitSetValue (balance_split, new_amount);
            }
            else
            {
                old_value = xaccSplitGetValue (balance_split);
                new_value = gnc_numeric_sub (old_value, val_imbalance,
                                             gnc_commodity_get_fraction(currency),
                                             GNC_HOW_RND_ROUND_HALF_UP);

                xaccSplitSetValue (balance_split, new_value);
            }

            xaccSplitScrub (balance_split);
            xaccTransCommitEdit (trans);
        }

        gnc_monetary_list_free(imbal_list);

        if (!gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
        {
            /* This is probably because there are splits with zero amount
               and non-zero value.  These are usually realized gain/loss
               splits.  Add a reversing split for each of them to balance
               the value. */

            /* Copy the split list so we don't see the splits we're adding */
            GList *splits_dup = g_list_copy(trans->splits);
            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;

                    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 */
                        gnc_monetary_list_free(imbal_list);
                        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(currency),
                                                 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);

            if (!gnc_numeric_zero_p(xaccTransGetImbalanceValue(trans)))
                PERR("Balancing currencies unbalanced value");
        }
    }
    LEAVE ("()");
}
Ejemplo n.º 20
0
static void
downloaded_transaction_append(GNCImportMatchPicker * matcher,
                              GNCImportTransInfo * transaction_info)
{
    GtkListStore *store;
    GtkTreeIter iter;
    GtkTreeSelection *selection;
    Transaction *trans;
    Split *split;
    gchar *text;
    const gchar *ro_text;
    gboolean found = FALSE;
    GNCImportTransInfo *local_info;

    g_assert(matcher);
    g_assert(transaction_info);

    /*DEBUG("Begin");*/

    /* Has the transaction already been added? */
    store = GTK_LIST_STORE(gtk_tree_view_get_model(matcher->downloaded_view));
    if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
    {
        do
        {
            gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
                               DOWNLOADED_COL_INFO_PTR, &local_info,
                               -1);
            if (local_info == transaction_info)
            {
                found = TRUE;
                break;
            }
        }
        while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
    }
    if (!found)
        gtk_list_store_append(store, &iter);

    split = gnc_import_TransInfo_get_fsplit(transaction_info);
    trans = gnc_import_TransInfo_get_trans(transaction_info);

    /*Account*/
    ro_text = xaccAccountGetName(xaccSplitGetAccount(split));
    gtk_list_store_set(store, &iter, DOWNLOADED_COL_ACCOUNT, ro_text, -1);

    /*Date*/
    text = qof_print_date(xaccTransGetDate(trans));
    gtk_list_store_set(store, &iter, DOWNLOADED_COL_DATE, text, -1);
    g_free(text);

    /*Amount*/
    ro_text = xaccPrintAmount(xaccSplitGetAmount(split),
                              gnc_split_amount_print_info(split, TRUE));
    gtk_list_store_set(store, &iter, DOWNLOADED_COL_AMOUNT, ro_text, -1);

    /*Description*/
    ro_text = xaccTransGetDescription(trans);
    gtk_list_store_set(store, &iter, DOWNLOADED_COL_DESCRIPTION, ro_text, -1);

    /*Memo*/
    ro_text = xaccSplitGetMemo(split);
    gtk_list_store_set(store, &iter, DOWNLOADED_COL_MEMO, ro_text, -1);

    /*Imbalance*/
    /* Assume that the importer won't create a transaction that involves two or more
       currencies and no non-currency commodity.  In that case can use the simpler
       value imbalance check. */
    ro_text = xaccPrintAmount(xaccTransGetImbalanceValue(trans),
                              gnc_default_print_info(TRUE));
    gtk_list_store_set(store, &iter, DOWNLOADED_COL_BALANCED, ro_text, -1);

    gtk_list_store_set(store, &iter, DOWNLOADED_COL_INFO_PTR,
                       transaction_info, -1);

    selection = gtk_tree_view_get_selection(matcher->downloaded_view);
    gtk_tree_selection_select_iter(selection, &iter);
}
Ejemplo n.º 21
0
static void
gnc_split_register_save_cells (gpointer save_data,
                               gpointer user_data)
{
    SRSaveData *sd = save_data;
    SplitRegister *reg = user_data;
    Split *other_split;
    gnc_commodity *txn_cur;
    gnc_numeric rate = gnc_numeric_zero();

    g_return_if_fail (sd != NULL);

    if (!sd->do_scrub)
        return;

    other_split = xaccSplitGetOtherSplit (sd->split);
    txn_cur = xaccTransGetCurrency (sd->trans);

    xaccSplitScrub (sd->split);

    rate = gnc_split_register_get_rate_cell (reg, RATE_CELL);

    if (other_split && !sd->reg_expanded)
    {
        gnc_numeric amount, value = xaccSplitGetValue (sd->split);
        Account *acc;
        gboolean split_needs_amount;

        split_needs_amount = gnc_split_register_split_needs_amount(reg, sd->split);

        /* We are changing the rate on the current split, but it was not
         * handled in the debcred handler, so we need to do it here.
         */
        if (!sd->handled_dc && split_needs_amount && !gnc_numeric_zero_p (rate))
        {
            gnc_numeric amount = xaccSplitGetAmount (sd->split);
            value = gnc_numeric_div(
                        amount, rate, gnc_commodity_get_fraction(txn_cur), GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetValue (sd->split, value);

            /* XXX: do we need to set the amount on the other split? */
        }

        /* Now reverse the value for the other split */
        value = gnc_numeric_neg (value);

        if (gnc_split_register_split_needs_amount (reg, other_split))
        {
            acc = xaccSplitGetAccount (other_split);

            /* If we don't have an exchange rate then figure it out.  Or, if
             * BOTH splits require an amount, then most likely we're in the
             * strange case of having a transaction currency different than
             * _both_ accounts -- so grab the other exchange rate.
             */
            if (gnc_numeric_zero_p (rate) || split_needs_amount)
                rate = xaccTransGetAccountConvRate(xaccSplitGetParent (other_split),
                                                   acc);

            amount = gnc_numeric_mul (value, rate, xaccAccountGetCommoditySCU (acc),
                                      GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetAmount (other_split, amount);

        }

        xaccSplitSetValue (other_split, value);

        xaccSplitScrub (other_split);
    }
    else if (gnc_split_register_split_needs_amount (reg, sd->split) &&
             ! gnc_numeric_zero_p (rate))
    {
        /* this is either a multi-split or expanded transaction, so only
         * deal with this split...  In particular we need to reset the
         * Value if the conv-rate changed.
         *
         * If we handled the debcred then no need to do anything there --
         * the debcred handler did all the computation.  If NOT, then the
         * convrate changed -- reset the value from the amount.
         */
        if (!sd->handled_dc)
        {
            gnc_split_register_save_amount_values (sd, reg);
#if 0
            gnc_numeric value, amount;

            amount = xaccSplitGetAmount (sd->split);
            value = gnc_numeric_div (amount, rate, gnc_commodity_get_fraction (txn_cur),
                                     GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetValue (sd->split, value);
#endif
        }
    }
}
Ejemplo n.º 22
0
/*******************************************************
 * account_splits
 *
 * gather the splits / transactions for an account and
 * send them to a file
 *******************************************************/
static
void account_splits (CsvExportInfo *info, Account *acc, FILE *fh )
{
    Query   *q;
    GSList  *p1, *p2;
    GList   *splits;
    QofBook *book;

    gchar   *end_sep;
    gchar   *mid_sep;

    q = qof_query_create_for(GNC_ID_SPLIT);
    book = gnc_get_current_book();
    qof_query_set_book (q, book);

    /* Set up separators */
    if (info->use_quotes)
    {
        end_sep = "\"";
        mid_sep = g_strconcat ( "\"", info->separator_str, "\"", NULL);
    }
    else
    {
        end_sep = "";
        mid_sep = g_strconcat ( info->separator_str, NULL);
    }

    /* Sort by transaction date */
    p1 = g_slist_prepend (NULL, TRANS_DATE_POSTED);
    p1 = g_slist_prepend (p1, SPLIT_TRANS);
    p2 = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
    qof_query_set_sort_order (q, p1, p2, NULL);

    xaccQueryAddSingleAccountMatch (q, acc, QOF_QUERY_AND);
    xaccQueryAddDateMatchTT (q, TRUE, info->csvd.start_time, TRUE, info->csvd.end_time, QOF_QUERY_AND);

    /* Run the query */
    for (splits = qof_query_run(q); splits; splits = splits->next)
    {
        Split       *split;
        Transaction *trans;
        SplitList   *s_list;
        GList       *node;
        Split       *t_split;
        int          nSplits;
        int          cnt;
        gchar       *part1;
        gchar       *part2;
        gchar       *date;
        const gchar *currentSel;
        const gchar *split_amount;

        split = splits->data;
        trans = xaccSplitGetParent(split);
        nSplits = xaccTransCountSplits(trans);
        s_list = xaccTransGetSplitList(trans);

        /* Date */
        date = qof_print_date ( xaccTransGetDate(trans));
        part1 = g_strconcat ( end_sep, date, mid_sep, NULL);
        g_free(date);
        /* Name */
        currentSel = xaccAccountGetName(acc);
        part2 = g_strconcat ( part1, currentSel, mid_sep, NULL);
        g_free(part1);
        /* Number */
        currentSel = gnc_get_num_action(trans, NULL);
        part1 = g_strconcat ( part2, currentSel, mid_sep, NULL);
        g_free(part2);
        /* Description */
        currentSel = xaccTransGetDescription(trans);
        part2 = g_strconcat ( part1, currentSel, mid_sep, NULL);
        g_free(part1);
        /* Notes */
        currentSel = xaccTransGetNotes(trans);
        if (currentSel == NULL)
            part1 = g_strconcat ( part2, mid_sep, NULL);
        else
            part1 = g_strconcat ( part2, currentSel, mid_sep, NULL);
        g_free(part2);
        /* Memo */
        currentSel = xaccSplitGetMemo(split);
        part2 = g_strconcat ( part1, currentSel, mid_sep, NULL);
        g_free(part1);
        /* Category */
        currentSel = xaccSplitGetCorrAccountName(split);
        part1 = g_strconcat ( part2, currentSel, mid_sep, "T", mid_sep, NULL);
        g_free(part2);
        /* Action */
        currentSel =  gnc_get_num_action(NULL, split);
        part2 = g_strconcat ( part1, currentSel, mid_sep, NULL);
        g_free(part1);
        /* Reconcile */
        switch (xaccSplitGetReconcile (split))
        {
        case NREC:
            currentSel = "N";
            break;
        case CREC:
            currentSel = "C";
            break;
        case YREC:
            currentSel = "Y";
            break;
        case FREC:
            currentSel = "F";
            break;
        case VREC:
            currentSel = "V";
            break;
        default:
            currentSel = "N";
        }
        part1 = g_strconcat ( part2, currentSel, mid_sep, NULL);
        g_free(part2);
        /* To with Symbol */
        split_amount = xaccPrintAmount(xaccSplitGetAmount(split), gnc_split_amount_print_info(split, TRUE));
        part2 = g_strconcat ( part1, split_amount, mid_sep, NULL);
        g_free(part1);

        /* From with Symbol */
        part1 = g_strconcat ( part2, "", mid_sep, NULL);
        g_free(part2);

        /* To Number Only */
        split_amount = xaccPrintAmount(xaccSplitGetAmount(split), gnc_split_amount_print_info(split, FALSE));
        part2 = g_strconcat ( part1, split_amount, mid_sep, NULL);
        g_free(part1);

        /* From Number Only */
        part1 = g_strconcat ( part2, "", mid_sep, "", mid_sep, "", end_sep, "\n", NULL);
        g_free(part2);

        /* Write to file */
        if (!write_line_to_file(fh, part1))
        {
            info->failed = TRUE;
            break;
        }
        g_free(part1);

        /* Loop through the list of splits for the Transcation */
        node = s_list;
        cnt = 0;
        while ( (cnt < nSplits) && (info->failed == FALSE))
        {
            t_split = node->data;

            /* Start of line */
            part1 = g_strconcat ( end_sep, mid_sep, mid_sep, mid_sep, mid_sep, mid_sep, NULL);

            /* Memo */
            currentSel = xaccSplitGetMemo(t_split);
            part2 = g_strconcat ( part1, currentSel, mid_sep, NULL);
            g_free(part1);

            /* Account */
            currentSel = xaccAccountGetName( xaccSplitGetAccount(t_split));
            part1 = g_strconcat ( part2, currentSel, mid_sep, "S", mid_sep, NULL);
            g_free(part2);

            /* Action */
            currentSel = gnc_get_num_action(NULL, t_split);
            part2 = g_strconcat ( part1, currentSel, mid_sep, NULL);
            g_free(part1);

            /* Reconcile */
            switch (xaccSplitGetReconcile (split))
            {
            case NREC:
                currentSel = "N";
                break;
            case CREC:
                currentSel = "C";
                break;
            case YREC:
                currentSel = "Y";
                break;
            case FREC:
                currentSel = "F";
                break;
            case VREC:
                currentSel = "V";
                break;
            default:
                currentSel = "N";
            }
            part1 = g_strconcat ( part2, currentSel, mid_sep, NULL);
            g_free(part2);

            /* From / To with Symbol */
            split_amount = xaccPrintAmount(xaccSplitGetAmount(t_split), gnc_split_amount_print_info(t_split, TRUE));
            if (xaccSplitGetAccount(t_split) == acc)
                part2 = g_strconcat ( part1,  split_amount, mid_sep, mid_sep, NULL);
            else
                part2 = g_strconcat ( part1, mid_sep, split_amount, mid_sep, NULL);
            g_free(part1);

            /* From / To Numbers only */
            split_amount = xaccPrintAmount(xaccSplitGetAmount(t_split), gnc_split_amount_print_info(t_split, FALSE));
            if (xaccSplitGetAccount(t_split) == acc)
                part1 = g_strconcat ( part2,  split_amount, mid_sep, mid_sep, NULL);
            else
                part1 = g_strconcat ( part2, mid_sep, split_amount, mid_sep, NULL);
            g_free(part2);

            /* From / To - Share Price / Conversion factor */
            split_amount = xaccPrintAmount(xaccSplitGetSharePrice(t_split), gnc_split_amount_print_info(t_split, FALSE));
            if (xaccSplitGetAccount(t_split) == acc)
                part2 = g_strconcat ( part1,  split_amount, mid_sep, end_sep, "\n", NULL);
            else
                part2 = g_strconcat ( part1, mid_sep, split_amount, end_sep, "\n", NULL);
            g_free(part1);

            if (!write_line_to_file(fh, part2))
                info->failed = TRUE;

            g_free(part2);
            cnt++;
            node = node->next;
        }
    }
    g_free(mid_sep);
    qof_query_destroy (q);
    g_list_free( splits );
}
Ejemplo n.º 23
0
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));
              }*/
        }
    }

}
Ejemplo n.º 24
0
/* Takes the input with column and sets the price / amount / value so they are consistent */
void
gnc_tree_util_set_number_for_input (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input, gint viewcol)
{
    GncTreeModelSplitReg *model;
    gnc_numeric  price;
    gnc_numeric  amount;
    gnc_numeric  value;

    gboolean price_changed = FALSE;   // Price of each share
    gboolean value_changed = FALSE;   // Total value of shares
    gboolean amount_changed = FALSE;  // No of shares

    gboolean recalc_amount = FALSE;
    gboolean recalc_price = FALSE;
    gboolean recalc_value = FALSE;
    gboolean expanded = FALSE;
    int denom;
    Account *account = NULL;

    ENTER("trans %p and split %p and input is %s and viewcol is %d", trans, split, gnc_numeric_to_string (input), viewcol);

    model = gnc_tree_view_split_reg_get_model_from_view (view);

    /* Check for sub account view */
    if (!gnc_tree_model_split_reg_get_sub_account (model))
        account = gnc_tree_model_split_reg_get_anchor (model);

    expanded = gnc_tree_view_split_reg_trans_expanded (view, trans);

    if (!account)
        account = xaccSplitGetAccount (split);

    if (!xaccAccountIsPriced (account))
        return;

    /* If we are using commodity trading accounts then the value may
       not really be the value.  Punt if so. */
    if (xaccTransUseTradingAccounts (xaccSplitGetParent (split)))
    {
        gnc_commodity *acc_commodity;
        acc_commodity = xaccAccountGetCommodity (account);
        if (!(xaccAccountIsPriced (account) || !gnc_commodity_is_iso (acc_commodity)))
            return;
    }

    if (gnc_numeric_zero_p (input))
    {
        xaccSplitSetValue (split, input);
        xaccSplitSetAmount (split, input);
        LEAVE("zero");
        return;
    }

    amount = xaccSplitGetAmount (split);
    value = xaccSplitGetValue (split);

    if (viewcol == COL_AMTVAL && !expanded)
    {
        value_changed = TRUE;
        if (gnc_numeric_zero_p (amount))
        {
            xaccSplitSetValue (split, input);
            xaccSplitSetAmount (split, input);
            LEAVE("");
            return;
        }
    }
    else if (viewcol == COL_AMTVAL && expanded)
    {
        amount_changed = TRUE;
        if (gnc_numeric_zero_p (value))
        {
            xaccSplitSetValue (split, input);
            xaccSplitSetAmount (split, input);
            LEAVE("");
            return;
        }
    }

    if (viewcol == COL_PRICE)
    {
        price_changed = TRUE;
        if (gnc_numeric_zero_p (value))
        {
            amount = gnc_numeric_create (1,1);
            value = gnc_numeric_mul (input, amount, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND);
            xaccSplitSetValue (split, input);
            xaccSplitSetAmount (split, amount);
            LEAVE("");
            return;
        }
    }

    if ((viewcol == COL_CREDIT || viewcol == COL_DEBIT) && !expanded)
    {
        amount_changed = TRUE;
        if (gnc_numeric_zero_p (value))
        {
            xaccSplitSetValue (split, input);
            xaccSplitSetAmount (split, input);
            LEAVE("");
            return;
        }
    }
    else if ((viewcol == COL_CREDIT || viewcol == COL_DEBIT) && expanded)
    {
        value_changed = TRUE;
        if (gnc_numeric_zero_p (value))
        {
            xaccSplitSetValue (split, input);
            xaccSplitSetAmount (split, input);
            LEAVE("");
            return;
        }
    }

    DEBUG("value_changed %d, price_changed %d, amount_changed %d", value_changed, price_changed, amount_changed);

    {
        int choice;
        int default_value;
        GList *node;
        GList *radio_list = NULL;
        const char *title = _("Recalculate Transaction");
        const char *message = _("The values entered for this transaction "
                                "are inconsistent. Which value would you "
                                "like to have recalculated?");

        if (amount_changed)
            radio_list = g_list_append (radio_list,
                                        g_strdup_printf ("%s (%s)",
                                                _("_Shares"), _("Changed")));
        else
            radio_list = g_list_append (radio_list, g_strdup (_("_Shares")));

        if (price_changed)
            radio_list = g_list_append (radio_list,
                                        g_strdup_printf ("%s (%s)",
                                                _("_Price"), _("Changed")));
        else
            radio_list = g_list_append (radio_list, g_strdup (_("_Price")));

        if (value_changed)
            radio_list = g_list_append (radio_list,
                                        g_strdup_printf ("%s (%s)",
                                                _("_Value"), _("Changed")));
        else
            radio_list = g_list_append (radio_list, g_strdup (_("_Value")));

        if(expanded)
        {
            if (price_changed)
                default_value = 2;  /* change the value */
            else
                default_value = 1;  /* change the price */
        }
        else
        {
            if (price_changed)
                default_value = 0;  /* change the amount / shares */
            else
                default_value = 1;  /* change the price */
        }
        choice = gnc_choose_radio_option_dialog
                 (gnc_tree_view_split_reg_get_parent (view),
                  title,
                  message,
                  _("_Recalculate"),
                  default_value,
                  radio_list);

        for (node = radio_list; node; node = node->next)
            g_free (node->data);

        g_list_free (radio_list);

        switch (choice)
        {
        case 0: /* Modify number of shares */
            recalc_amount = TRUE;
            break;
        case 1: /* Modify the share price */
            recalc_price = TRUE;
            break;
        case 2: /* Modify total value */
            recalc_value = TRUE;
            break;
        default: /* Cancel */
            LEAVE(" " );
            return;
        }
    }

    DEBUG("recalc_value %d, recalc_price %d, recalc_amount %d", recalc_value, recalc_price, recalc_amount);

    if (recalc_amount)
    {
        denom = gtu_sr_get_amount_denom (split);

        if (amount_changed)
        {
            LEAVE("");
            return;
        }

        if (price_changed)
            price = input;
        else
            price = gnc_numeric_div (value, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);

        if (value_changed)
        {
            xaccSplitSetValue (split, input);
            amount = gnc_numeric_div (input, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetAmount (split, amount);
        }
        else
        {
            amount = gnc_numeric_div (value, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetAmount (split, amount);
        }
    }

    if (recalc_price)
    {
        if (price_changed)
        {
            LEAVE("");
            return;
        }

        if (amount_changed)
        {
            xaccSplitSetAmount (split, input);
            xaccSplitSetValue (split, value);
        }

        if (value_changed)
        {
            xaccSplitSetValue (split, input);
            xaccSplitSetAmount (split, amount);
        }
    }

    if (recalc_value)
    {
        denom = gtu_sr_get_value_denom (split);

        if (value_changed)
        {
            LEAVE("");
            return;
        }

        if (price_changed)
            price = input;
        else
            price = gnc_numeric_div (value, amount, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);

        if (amount_changed)
        {
            xaccSplitSetAmount (split, input);
            value = gnc_numeric_mul (input, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetValue (split, value);
        }
        else
        {
            value = gnc_numeric_mul (amount, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
            xaccSplitSetValue (split, value);
        }
    }

    /* If the number of splits is two, change other split to balance */
    if (!gnc_tree_util_split_reg_is_multi (split) && expanded)
    {
        Split *osplit;
        gnc_commodity *osplit_com;

        osplit = xaccSplitGetOtherSplit (split);

        value = xaccSplitGetValue (split);

        osplit_com = xaccAccountGetCommodity (xaccSplitGetAccount (osplit));

        if (gnc_commodity_is_currency (osplit_com))
        {
            xaccSplitSetValue (osplit, gnc_numeric_neg (value));
            xaccSplitSetAmount (osplit, gnc_numeric_neg (value));
        }
    }
    LEAVE("");
}
static const char*
equals_node_val_vs_split_internal (xmlNodePtr node, Split* spl)
{
    xmlNodePtr mark;

    for (mark = node->children; mark != NULL; mark = mark->next)
    {
        if (g_strcmp0 ((char*)mark->name, "split:id") == 0)
        {
            GncGUID* id = dom_tree_to_guid (mark);

            if (!guid_equal (id, xaccSplitGetGUID (spl)))
            {
                g_free (id);
                return "ids differ";
            }
            g_free (id);
        }
        else if (g_strcmp0 ((char*)mark->name, "split:memo") == 0)
        {
            char* memo = dom_tree_to_text (mark);

            if (g_strcmp0 (memo, xaccSplitGetMemo (spl)) != 0)
            {
                g_free (memo);
                return "memos differ";
            }
            g_free (memo);
        }
        else if (g_strcmp0 ((char*)mark->name, "split:reconciled-state") == 0)
        {
            char* rs = dom_tree_to_text (mark);

            if (rs[0] != xaccSplitGetReconcile (spl))
            {
                g_free (rs);
                return "states differ";
            }
            g_free (rs);
        }
        else if (g_strcmp0 ((char*)mark->name, "split:value") == 0)
        {
            gnc_numeric* num = dom_tree_to_gnc_numeric (mark);
            gnc_numeric val = xaccSplitGetValue (spl);

            if (!gnc_numeric_equal (*num, val))
            {
                g_free (num);
                return g_strdup_printf ("values differ: %" G_GINT64_FORMAT "/%"
                                        G_GINT64_FORMAT " v %" G_GINT64_FORMAT
                                        "/%" G_GINT64_FORMAT,
                                        (*num).num, (*num).denom,
                                        val.num, val.denom);
            }
            g_free (num);
        }
        else if (g_strcmp0 ((char*)mark->name, "split:quantity") == 0)
        {
            gnc_numeric* num = dom_tree_to_gnc_numeric (mark);
            gnc_numeric val = xaccSplitGetAmount (spl);

            if (!gnc_numeric_equal (*num, val))
            {
                return g_strdup_printf ("quantities differ under _equal: %"
                                        G_GINT64_FORMAT "/%" G_GINT64_FORMAT
                                        " v %" G_GINT64_FORMAT "/%"
                                        G_GINT64_FORMAT,
                                        (*num).num, (*num).denom,
                                        val.num, val.denom);
            }
            if (!gnc_numeric_equal (*num, val))
            {
                g_free (num);
                return g_strdup_printf ("quantities differ: %" G_GINT64_FORMAT
                                        "/%" G_GINT64_FORMAT " v %"
                                        G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
                                        (*num).num, (*num).denom,
                                        val.num, val.denom);
            }
            g_free (num);
        }
        else if (g_strcmp0 ((char*)mark->name, "split:account") == 0)
        {
            GncGUID* id = dom_tree_to_guid (mark);
            Account* account = xaccSplitGetAccount (spl);

            if (!guid_equal (id, xaccAccountGetGUID (account)))
            {
                g_free (id);
                return "accounts differ";
            }
            g_free (id);
        }
    }
    return NULL;
}
static void
refresh_model_row (GNCImportMainMatcher *gui,
                   GtkTreeModel *model,
                   GtkTreeIter *iter,
                   GNCImportTransInfo *info)
{
    GtkListStore *store;
    GtkTreeSelection *selection;
    gchar *tmp, *imbalance, *text, *color;
    const gchar *ro_text;
    Split *split;
    g_assert (gui);
    g_assert (model);
    g_assert (info);
    /*DEBUG("Begin");*/

    store = GTK_LIST_STORE(model);
    gtk_list_store_set(store, iter, DOWNLOADED_COL_DATA, info, -1);

    /*Account:*/
    split = gnc_import_TransInfo_get_fsplit (info);
    g_assert(split); // Must not be NULL
    ro_text = xaccAccountGetName(xaccSplitGetAccount(split));
    gtk_list_store_set(store, iter, DOWNLOADED_COL_ACCOUNT, ro_text, -1);

    /*Date*/
    text = qof_print_date ( xaccTransGetDate( gnc_import_TransInfo_get_trans(info) ) );
    gtk_list_store_set(store, iter, DOWNLOADED_COL_DATE, text, -1);
    g_free(text);

    /*Amount*/
    ro_text = xaccPrintAmount
              (xaccSplitGetAmount (split),
               gnc_split_amount_print_info(split, TRUE)
              );
    gtk_list_store_set(store, iter, DOWNLOADED_COL_AMOUNT, ro_text, -1);

    /*Description*/
    ro_text = xaccTransGetDescription(gnc_import_TransInfo_get_trans(info) );
    gtk_list_store_set(store, iter, DOWNLOADED_COL_DESCRIPTION, ro_text, -1);

    /*Memo*/
    ro_text = xaccSplitGetMemo(split);
    gtk_list_store_set(store, iter, DOWNLOADED_COL_MEMO, ro_text, -1);

    /*Actions*/

    /* Action informations */
    ro_text = text = color = NULL;
    switch (gnc_import_TransInfo_get_action(info))
    {
    case GNCImport_ADD:
        if (gnc_import_TransInfo_is_balanced(info) == TRUE)
        {
            ro_text = _("New, already balanced");
            color = COLOR_GREEN;
        }
        else
        {
            /* Assume that importers won't create transactions in two or more
               currencies so we can use xaccTransGetImbalanceValue */
            imbalance =
                g_strdup
                (xaccPrintAmount
                 (gnc_numeric_neg(xaccTransGetImbalanceValue
                                  (gnc_import_TransInfo_get_trans(info) )),
                  gnc_commodity_print_info
                  (xaccTransGetCurrency(gnc_import_TransInfo_get_trans (info)),
                   TRUE) ));
            if (gnc_import_TransInfo_get_destacc (info) != NULL)
            {
                color = COLOR_GREEN;
                tmp = gnc_account_get_full_name
                      (gnc_import_TransInfo_get_destacc (info));
                if (gnc_import_TransInfo_get_destacc_selected_manually(info)
                        == TRUE)
                {
                    text =
                        /* Translators: %1$s is the amount to be
                           transferred. %2$s is the destination account. */
                        g_strdup_printf(_("New, transfer %s to (manual) \"%s\""),
                                        imbalance, tmp);
                }
                else
                {
                    text =
                        /* Translators: %1$s is the amount to be
                           transferred. %2$s is the destination account. */
                        g_strdup_printf(_("New, transfer %s to (auto) \"%s\""),
                                        imbalance, tmp);
                }
                g_free (tmp);

            }
            else
            {
                color = COLOR_YELLOW;
                text =
                    /* Translators: %s is the amount to be transferred. */
                    g_strdup_printf(_("New, UNBALANCED (need acct to transfer %s)!"),
                                    imbalance);
            }
            g_free (imbalance);
        }
        break;
    case GNCImport_CLEAR:
        if (gnc_import_TransInfo_get_selected_match(info))
        {
            color = COLOR_GREEN;
            if (gnc_import_TransInfo_get_match_selected_manually(info) == TRUE)
            {
                ro_text = _("Reconcile (manual) match");
            }
            else
            {
                ro_text = _("Reconcile (auto) match");
            }
        }
        else
        {
            color = COLOR_RED;
            ro_text = _("Match missing!");
        }
        break;
    case GNCImport_UPDATE:
        if (gnc_import_TransInfo_get_selected_match(info))
        {
            color = COLOR_GREEN;
            if (gnc_import_TransInfo_get_match_selected_manually(info) == TRUE)
            {
                ro_text = _("Update and reconcile (manual) match");
            }
            else
            {
                ro_text = _("Update and reconcile (auto) match");
            }
        }
        else
        {
            color = COLOR_RED;
            ro_text = _("Match missing!");
        }
        break;
    case GNCImport_SKIP:
        color = COLOR_RED;
        ro_text = _("Do not import (no action selected)");
        break;
    default:
        color = "white";
        ro_text = "WRITEME, this is an unknown action";
        break;
    }

    gtk_list_store_set(store, iter,
                       DOWNLOADED_COL_COLOR, color,
                       DOWNLOADED_COL_ACTION_INFO, ro_text ? ro_text : text,
                       -1);
    if (text)
        g_free(text);

    /* Set the pixmaps */
    gtk_list_store_set(store, iter,
                       DOWNLOADED_COL_ACTION_ADD,
                       gnc_import_TransInfo_get_action(info) == GNCImport_ADD,
                       -1);
    if (gnc_import_TransInfo_get_action(info) == GNCImport_SKIP)
    {
        /*Show the best match's confidence pixmap in the info column*/
        gtk_list_store_set(store, iter,
                           DOWNLOADED_COL_ACTION_PIXBUF,
                           gen_probability_pixbuf( gnc_import_MatchInfo_get_probability
                                   ( gnc_import_TransInfo_get_selected_match (info)),
                                   gui->user_settings,
                                   GTK_WIDGET(gui->view)),
                           -1);
    }

    gtk_list_store_set(store, iter,
                       DOWNLOADED_COL_ACTION_CLEAR,
                       gnc_import_TransInfo_get_action(info) == GNCImport_CLEAR,
                       -1);
    if (gnc_import_TransInfo_get_action(info) == GNCImport_CLEAR)
    {
        /*Show the best match's confidence pixmap in the info column*/
        gtk_list_store_set(store, iter,
                           DOWNLOADED_COL_ACTION_PIXBUF,
                           gen_probability_pixbuf( gnc_import_MatchInfo_get_probability
                                   ( gnc_import_TransInfo_get_selected_match (info)),
                                   gui->user_settings,
                                   GTK_WIDGET(gui->view)),
                           -1);
    }

    gtk_list_store_set(store, iter,
                       DOWNLOADED_COL_ACTION_UPDATE,
                       gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE,
                       -1);
    if (gnc_import_TransInfo_get_action(info) == GNCImport_UPDATE)
    {
        /*Show the best match's confidence pixmap in the info column*/
        gtk_list_store_set(store, iter,
                           DOWNLOADED_COL_ACTION_PIXBUF,
                           gen_probability_pixbuf( gnc_import_MatchInfo_get_probability
                                   ( gnc_import_TransInfo_get_selected_match (info)),
                                   gui->user_settings,
                                   GTK_WIDGET(gui->view)),
                           -1);
    }

    selection = gtk_tree_view_get_selection(gui->view);
    gtk_tree_selection_unselect_all(selection);
}
static void
test_transaction (void)
{
    int i;

    for (i = 0; i < 50; i++)
    {
        Transaction* ran_trn;
        xmlNodePtr test_node;
        gnc_commodity* com, *new_com;
        gchar* filename1;
        int fd;

        /* The next line exists for its side effect of creating the
         * account tree. */
        get_random_account_tree (book);
        ran_trn = get_random_transaction (book);
        new_com = get_random_commodity (book);
        if (!ran_trn)
        {
            failure_args ("transaction_xml", __FILE__, __LINE__,
                          "get_random_transaction returned NULL");
            return;
        }

        {
            /* xaccAccountInsertSplit can reorder the splits. */
            GList* list = g_list_copy (xaccTransGetSplitList (ran_trn));
            GList* node = list;
            for (; node; node = node->next)
            {
                Split* s = static_cast<decltype (s)> (node->data);
                Account* a = xaccMallocAccount (book);

                xaccAccountBeginEdit (a);
                xaccAccountSetCommodity (a, new_com);
                xaccAccountSetCommoditySCU (a, xaccSplitGetAmount (s).denom);
                xaccAccountInsertSplit (a, s);
                xaccAccountCommitEdit (a);
            }
            g_list_free (list);
        }

        com = xaccTransGetCurrency (ran_trn);

        test_node = gnc_transaction_dom_tree_create (ran_trn);
        if (!test_node)
        {
            failure_args ("transaction_xml", __FILE__, __LINE__,
                          "gnc_transaction_dom_tree_create returned NULL");
            really_get_rid_of_transaction (ran_trn);
            continue;
        }
        auto compare_msg = node_and_transaction_equal (test_node, ran_trn);
        if (compare_msg != nullptr)
        {
            failure_args ("transaction_xml", __FILE__, __LINE__,
                          "node and transaction were not equal: %s",
                          compare_msg);
            xmlElemDump (stdout, NULL, test_node);
            printf ("\n");
            fflush (stdout);
            xmlFreeNode (test_node);
            really_get_rid_of_transaction (ran_trn);
            continue;
        }
        else
        {
            success_args ("transaction_xml", __FILE__, __LINE__, "%d", i);
        }

        filename1 = g_strdup_printf ("test_file_XXXXXX");

        fd = g_mkstemp (filename1);

        write_dom_node_to_file (test_node, fd);

        close (fd);

        {
            GList* node = xaccTransGetSplitList (ran_trn);
            for (; node; node = node->next)
            {
                Split* s = static_cast<decltype (s)> (node->data);
                Account* a1 = xaccSplitGetAccount (s);
                Account* a2 = xaccMallocAccount (book);

                xaccAccountBeginEdit (a2);
                xaccAccountSetCommoditySCU (a2, xaccAccountGetCommoditySCU (a1));
                xaccAccountSetGUID (a2, xaccAccountGetGUID (a1));
                xaccAccountCommitEdit (a2);
            }
        }

        {
            sixtp* parser;
            tran_data data;

            const char* msg =
                "[xaccAccountScrubCommodity()] Account \"\" does not have a commodity!";
            const char* logdomain = "gnc.engine.scrub";
            GLogLevelFlags loglevel = static_cast<decltype (loglevel)>
                                      (G_LOG_LEVEL_CRITICAL);
            TestErrorStruct check = { loglevel, const_cast<char*> (logdomain),
                                      const_cast<char*> (msg)
                                    };
            g_log_set_handler (logdomain, loglevel,
                               (GLogFunc)test_checked_handler, &check);
            data.trn = ran_trn;
            data.com = com;
            data.value = i;
            parser = gnc_transaction_sixtp_parser_create ();

            if (!gnc_xml_parse_file (parser, filename1, test_add_transaction,
                                     (gpointer)&data, book))
            {
                failure_args ("gnc_xml_parse_file returned FALSE",
                              __FILE__, __LINE__, "%d", i);
            }
            else
                really_get_rid_of_transaction (data.new_trn);
        }
        /* no handling of circular data structures.  We'll do that later */
        /* sixtp_destroy(parser); */


        g_unlink (filename1);
        g_free (filename1);
        really_get_rid_of_transaction (ran_trn);
        xmlFreeNode (test_node);
    }
}
static xmlNodePtr
split_to_dom_tree (const gchar* tag, Split* spl)
{
    xmlNodePtr ret;

    ret = xmlNewNode (NULL, BAD_CAST tag);

    xmlAddChild (ret, guid_to_dom_tree ("split:id", xaccSplitGetGUID (spl)));

    {
        char* memo = g_strdup (xaccSplitGetMemo (spl));

        if (memo && g_strcmp0 (memo, "") != 0)
        {
            xmlNewTextChild (ret, NULL, BAD_CAST "split:memo",
                             checked_char_cast (memo));
        }
        g_free (memo);
    }

    {
        char* action = g_strdup (xaccSplitGetAction (spl));

        if (action && g_strcmp0 (action, "") != 0)
        {
            xmlNewTextChild (ret, NULL, BAD_CAST "split:action",
                             checked_char_cast (action));
        }
        g_free (action);
    }

    {
        char tmp[2];

        tmp[0] = xaccSplitGetReconcile (spl);
        tmp[1] = '\0';

        xmlNewTextChild (ret, NULL, BAD_CAST "split:reconciled-state",
                         BAD_CAST tmp);
    }

    add_timespec (ret, "split:reconcile-date",
                  xaccSplitRetDateReconciledTS (spl), FALSE);

    add_gnc_num (ret, "split:value", xaccSplitGetValue (spl));

    add_gnc_num (ret, "split:quantity", xaccSplitGetAmount (spl));

    {
        Account* account = xaccSplitGetAccount (spl);

        xmlAddChild (ret, guid_to_dom_tree ("split:account",
                                            xaccAccountGetGUID (account)));
    }
    {
        GNCLot* lot = xaccSplitGetLot (spl);

        if (lot)
        {
            xmlAddChild (ret, guid_to_dom_tree ("split:lot",
                                                gnc_lot_get_guid (lot)));
        }
    }
    /* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
    xmlAddChild (ret, qof_instance_slots_to_dom_tree ("split:slots",
                                                      QOF_INSTANCE (spl)));
    return ret;
}