Beispiel #1
0
GNCLot *
gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction *txn,
                          Account *posted_acc, Account *xfer_acc,
                          gnc_numeric amount, gnc_numeric exch, Timespec date,
                          const char *memo, const char *num)
{
    QofBook *book;
    Split *split;
    const char *name;
    gnc_commodity *commodity;
    Split *xfer_split = NULL;
    GNCLot *payment_lot;

    /* Verify our arguments */
    if (!owner || !posted_acc || !xfer_acc) return NULL;
    g_return_val_if_fail (owner->owner.undefined != NULL, NULL);

    /* Compute the ancillary data */
    book = gnc_account_get_book (posted_acc);
    name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
    commodity = gncOwnerGetCurrency (owner);
//    reverse = use_reversed_payment_amounts(owner);

    if (txn)
    {
        /* Pre-existing transaction was specified. We completely clear it,
         * except for the split in the transfer account, unless the
         * transaction can't be reused (wrong currency, wrong transfer account).
         * In that case, the transaction is simply removed and an new
         * one created. */

        xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);

        if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
        {
            g_message("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
            xfer_split = NULL;
        }

        if (!xfer_split)
        {
            g_message("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");

            xaccTransBeginEdit (txn);
            xaccTransDestroy (txn);
            xaccTransCommitEdit (txn);

            txn = NULL;
        }
        else
        {
            int i = 0;
            xaccTransBeginEdit (txn);
            while (i < xaccTransCountSplits(txn))
            {
                Split *split = xaccTransGetSplit (txn, i);
                if (split == xfer_split)
                {
                    gnc_set_num_action (NULL, split, num, _("Payment"));
                    ++i;
                }
                else
                {
                    xaccSplitDestroy(split);
                }
            }
            /* Note: don't commit transaction now - that would insert an imbalance split.*/
        }
    }

    /* Create the transaction if we don't have one yet */
    if (!txn)
    {
        txn = xaccMallocTransaction (book);
        xaccTransBeginEdit (txn);
    }

    /* Insert a split for the transfer account if we don't have one yet */
    if (!xfer_split)
    {

        /* Set up the transaction */
        xaccTransSetDescription (txn, name ? name : "");
        /* set per book option */
        xaccTransSetCurrency (txn, commodity);
        xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
        xaccTransSetDatePostedTS (txn, &date);


        /* The split for the transfer account */
        split = xaccMallocSplit (book);
        xaccSplitSetMemo (split, memo);
        /* set per book option */
        gnc_set_num_action (NULL, split, num, _("Payment"));
        xaccAccountBeginEdit (xfer_acc);
        xaccAccountInsertSplit (xfer_acc, split);
        xaccAccountCommitEdit (xfer_acc);
        xaccTransAppendSplit (txn, split);

        if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
        {
            xaccSplitSetBaseValue (split, amount, commodity);
        }
        else
        {
            /* Need to value the payment in terms of the owner commodity */
            gnc_numeric payment_value = gnc_numeric_mul(amount,
                                        exch, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);

            xaccSplitSetAmount(split, amount);
            xaccSplitSetValue(split, payment_value);
        }
    }

    /* Add a split in the post account */
    split = xaccMallocSplit (book);
    xaccSplitSetMemo (split, memo);
    /* set per book option */
    gnc_set_num_action (NULL, split, num, _("Payment"));
    xaccAccountBeginEdit (posted_acc);
    xaccAccountInsertSplit (posted_acc, split);
    xaccAccountCommitEdit (posted_acc);
    xaccTransAppendSplit (txn, split);
    xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity);

    /* Create a new lot for the payment */
    payment_lot = gnc_lot_new (book);
    gncOwnerAttachToLot (owner, payment_lot);
    gnc_lot_add_split (payment_lot, split);

    /* Mark the transaction as a payment */
    gnc_set_num_action (txn, NULL, num, _("Payment"));
    xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);

    /* Commit this new transaction */
    xaccTransCommitEdit (txn);

    return payment_lot;
}
Beispiel #2
0
void
gnc_stock_split_assistant_finish (GtkAssistant *assistant,
                                  gpointer user_data)
{
    StockSplitInfo *info = user_data;
    GList *account_commits;
    GList *node;

    gnc_numeric amount;
    Transaction *trans;
    Account *account;
    Split *split;
    time64 date;

    account = info->acct;
    g_return_if_fail (account != NULL);

    amount = gnc_amount_edit_get_amount
             (GNC_AMOUNT_EDIT (info->distribution_edit));
    g_return_if_fail (!gnc_numeric_zero_p (amount));

    gnc_suspend_gui_refresh ();

    trans = xaccMallocTransaction (gnc_get_current_book ());

    xaccTransBeginEdit (trans);

    xaccTransSetCurrency (trans, gnc_default_currency ());

    date = gnc_date_edit_get_date (GNC_DATE_EDIT (info->date_edit));
    xaccTransSetDatePostedSecsNormalized (trans, date);

    {
        const char *description;

        description = gtk_entry_get_text (GTK_ENTRY (info->description_entry));
        xaccTransSetDescription (trans, description);
    }

    split = xaccMallocSplit (gnc_get_current_book ());

    xaccAccountBeginEdit (account);
    account_commits = g_list_prepend (NULL, account);

    xaccTransAppendSplit (trans, split);

    xaccAccountInsertSplit (account, split);

    xaccSplitSetAmount (split, amount);
    xaccSplitMakeStockSplit (split);
    /* Set split-action with gnc_set_num_action which is the same as
     * xaccSplitSetAction with these arguments */
    /* Translators: This string has a disambiguation prefix */
    gnc_set_num_action (NULL, split, NULL, Q_("Action Column|Split"));

    amount = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (info->price_edit));
    if (gnc_numeric_positive_p (amount))
    {
        QofBook *book;
        GNCPrice *price;
        GNCPriceDB *pdb;
        GNCCurrencyEdit *ce;
        Timespec ts;

        ce = GNC_CURRENCY_EDIT (info->price_currency_edit);

        ts.tv_sec = date;
        ts.tv_nsec = 0;

        price = gnc_price_create (gnc_get_current_book ());

        gnc_price_begin_edit (price);
        gnc_price_set_commodity (price, xaccAccountGetCommodity (account));
        gnc_price_set_currency (price, gnc_currency_edit_get_currency (ce));
        gnc_price_set_time (price, ts);
        gnc_price_set_source (price, "user:stock-split");
        gnc_price_set_typestr (price, "unknown");
        gnc_price_set_value (price, amount);
        gnc_price_commit_edit (price);

        book = gnc_get_current_book ();
        pdb = gnc_pricedb_get_db (book);

        if (!gnc_pricedb_add_price (pdb, price))
            gnc_error_dialog (info->window, "%s", _("Error adding price."));

        gnc_price_unref (price);
    }

    amount = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (info->cash_edit));
    if (gnc_numeric_positive_p (amount))
    {
        const char *memo;

        memo = gtk_entry_get_text (GTK_ENTRY (info->memo_entry));

        /* asset split */
        account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(info->asset_tree));

        split = xaccMallocSplit (gnc_get_current_book ());

        xaccAccountBeginEdit (account);
        account_commits = g_list_prepend (account_commits, account);

        xaccAccountInsertSplit (account, split);

        xaccTransAppendSplit (trans, split);

        xaccSplitSetAmount (split, amount);
        xaccSplitSetValue (split, amount);

        xaccSplitSetMemo (split, memo);


        /* income split */
        account = gnc_tree_view_account_get_selected_account (GNC_TREE_VIEW_ACCOUNT(info->income_tree));

        split = xaccMallocSplit (gnc_get_current_book ());

        xaccAccountBeginEdit (account);
        account_commits = g_list_prepend (account_commits, account);

        xaccAccountInsertSplit (account, split);

        xaccTransAppendSplit (trans, split);

        xaccSplitSetAmount (split, gnc_numeric_neg (amount));
        xaccSplitSetValue (split, gnc_numeric_neg (amount));

        xaccSplitSetMemo (split, memo);
    }

    xaccTransCommitEdit (trans);

    for (node = account_commits; node; node = node->next)
        xaccAccountCommitEdit (node->data);
    g_list_free (account_commits);

    gnc_resume_gui_refresh ();

    gnc_close_gui_component_by_data (ASSISTANT_STOCK_SPLIT_CM_CLASS, info);
}
/* File pointer must already be at the begining of a record */
static void  process_trans_record(  FILE *log_file)
{
    char read_buf[2048];
    char *read_retval;
    char * trans_ro = NULL;
    const char * record_end_str = "===== END";
    int first_record = TRUE;
    int record_ended = FALSE;
    int split_num = 0;
    split_record record;
    Transaction * trans = NULL;
    Split * split = NULL;
    Account * acct = NULL;
    QofBook * book = gnc_get_current_book();

    DEBUG("process_trans_record(): Begin...\n");

    while ( record_ended == FALSE)
    {
        read_retval = fgets(read_buf, sizeof(read_buf), log_file);
        if (read_retval != NULL && strncmp(record_end_str, read_buf, strlen(record_end_str)) != 0) /* If we are not at the end of the record */
        {
            split_num++;
            /*DEBUG("process_trans_record(): Line read: %s%s",read_buf ,"\n");*/
            record = interpret_split_record( read_buf);
            dump_split_record( record);
            if (record.log_action_present)
            {
                switch (record.log_action)
                {
                case split_record::LOG_BEGIN_EDIT:
                    DEBUG("process_trans_record():Ignoring log action: LOG_BEGIN_EDIT"); /*Do nothing, there is no point*/
                    break;
                case split_record::LOG_ROLLBACK:
                    DEBUG("process_trans_record():Ignoring log action: LOG_ROLLBACK");/*Do nothing, since we didn't do the begin_edit either*/
                    break;
                case split_record::LOG_DELETE:
                    DEBUG("process_trans_record(): Playing back LOG_DELETE");
                    if ((trans = xaccTransLookup (&(record.trans_guid), book)) != NULL
                            && first_record == TRUE)
                    {
                        first_record = FALSE;
                        if (xaccTransGetReadOnly(trans))
                        {
                            PWARN("Destroying a read only transaction.");
                            xaccTransClearReadOnly(trans);
                        }
                        xaccTransBeginEdit(trans);
                        xaccTransDestroy(trans);
                    }
                    else if (first_record == TRUE)
                    {
                        PERR("The transaction to delete was not found!");
                    }
                    else
                        xaccTransDestroy(trans);
                    break;
                case split_record::LOG_COMMIT:
                    DEBUG("process_trans_record(): Playing back LOG_COMMIT");
                    if (record.trans_guid_present == TRUE
                            && first_record == TRUE)
                    {
                        trans = xaccTransLookupDirect (record.trans_guid, book);
                        if (trans != NULL)
                        {
                            DEBUG("process_trans_record(): Transaction to be edited was found");
                            xaccTransBeginEdit(trans);
                            trans_ro = g_strdup(xaccTransGetReadOnly(trans));
                            if (trans_ro)
                            {
                                PWARN("Replaying a read only transaction.");
                                xaccTransClearReadOnly(trans);
                            }
                        }
                        else
                        {
                            DEBUG("process_trans_record(): Creating a new transaction");
                            trans = xaccMallocTransaction (book);
                            xaccTransBeginEdit(trans);
                        }

                        xaccTransSetGUID (trans, &(record.trans_guid));
                        /*Fill the transaction info*/
                        if (record.date_entered_present)
                        {
                            xaccTransSetDateEnteredTS(trans, &(record.date_entered));
                        }
                        if (record.date_posted_present)
                        {
                            xaccTransSetDatePostedTS(trans, &(record.date_posted));
                        }
                        if (record.trans_num_present)
                        {
                            xaccTransSetNum(trans, record.trans_num);
                        }
                        if (record.trans_descr_present)
                        {
                            xaccTransSetDescription(trans, record.trans_descr);
                        }
                        if (record.trans_notes_present)
                        {
                            xaccTransSetNotes(trans, record.trans_notes);
                        }
                    }
                    if (record.split_guid_present == TRUE) /*Fill the split info*/
                    {
                        gboolean is_new_split;

                        split = xaccSplitLookupDirect (record.split_guid, book);
                        if (split != NULL)
                        {
                            DEBUG("process_trans_record(): Split to be edited was found");
                            is_new_split = FALSE;
                        }
                        else
                        {
                            DEBUG("process_trans_record(): Creating a new split");
                            split = xaccMallocSplit(book);
                            is_new_split = TRUE;
                        }
                        xaccSplitSetGUID (split, &(record.split_guid));
                        if (record.acc_guid_present)
                        {
                            acct = xaccAccountLookupDirect(record.acc_guid, book);
                            xaccAccountInsertSplit(acct, split);
                        }
                        if (is_new_split)
                            xaccTransAppendSplit(trans, split);

                        if (record.split_memo_present)
                        {
                            xaccSplitSetMemo(split, record.split_memo);
                        }
                        if (record.split_action_present)
                        {
                            xaccSplitSetAction(split, record.split_action);
                        }
                        if (record.date_reconciled_present)
                        {
                            xaccSplitSetDateReconciledTS (split, &(record.date_reconciled));
                        }
                        if (record.split_reconcile_present)
                        {
                            xaccSplitSetReconcile(split, record.split_reconcile);
                        }

                        if (record.amount_present)
                        {
                            xaccSplitSetAmount(split, record.amount);
                        }
                        if (record.value_present)
                        {
                            xaccSplitSetValue(split, record.value);
                        }
                    }
                    first_record = FALSE;
                    break;
                }
            }
            else
            {
                PERR("Corrupted record");
            }
        }
        else /* The record ended */
        {
            record_ended = TRUE;
            DEBUG("process_trans_record(): Record ended\n");
            if (trans != NULL) /*If we played with a transaction, commit it here*/
            {
                xaccTransScrubCurrencyFromSplits(trans);
                xaccTransSetReadOnly(trans, trans_ro);
                xaccTransCommitEdit(trans);
                g_free(trans_ro);
            }
        }
    }
}
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);
            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);
            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);
            xaccSplitSetValue (sd->split, value);
#endif
        }
    }
}
static void
gnc_split_register_save_amount_values (SRSaveData *sd, SplitRegister *reg)
{
    Account *acc;
    gnc_numeric new_amount, convrate, amtconv, value;
    gnc_commodity *curr, *reg_com, *xfer_com;
    Account *xfer_acc;

    new_amount = gnc_split_register_debcred_cell_value (reg);
    acc = gnc_split_register_get_default_account (reg);

    xfer_acc = xaccSplitGetAccount (sd->split);
    xfer_com = xaccAccountGetCommodity (xfer_acc);
    reg_com = xaccAccountGetCommodity (acc);
    curr = xaccTransGetCurrency (sd->trans);

    /* First, compute the conversion rate to convert the value to the
      * amount.
      */
    amtconv = convrate = gnc_split_register_get_rate_cell (reg, RATE_CELL);
    if (gnc_split_register_needs_conv_rate (reg, sd->trans, acc))
    {

        /* If we are in an expanded register and the xfer_acc->comm !=
        * reg_acc->comm then we need to compute the convrate here.
        * Otherwise, we _can_ use the rate_cell!
        */
        if (sd->reg_expanded && ! gnc_commodity_equal (reg_com, xfer_com))
            amtconv = xaccTransGetAccountConvRate(sd->trans, acc);
    }

    if (xaccTransUseTradingAccounts (sd->trans))
    {
        /* Using currency accounts, the amount is probably really the
           amount and not the value. */
        gboolean is_amount;
        if (reg->type == STOCK_REGISTER ||
                reg->type == CURRENCY_REGISTER ||
                reg->type == PORTFOLIO_LEDGER)
        {
            if (xaccAccountIsPriced(xfer_acc) ||
                    !gnc_commodity_is_iso(xaccAccountGetCommodity(xfer_acc)))
                is_amount = FALSE;
            else
                is_amount = TRUE;
        }
        else
        {
            is_amount = TRUE;
        }

        if (is_amount)
        {
            xaccSplitSetAmount(sd->split, new_amount);
            if (gnc_split_register_split_needs_amount (reg, sd->split))
            {
                value = gnc_numeric_div(new_amount, amtconv,
                                        gnc_commodity_get_fraction(curr),
                                        GNC_HOW_RND_ROUND);
                xaccSplitSetValue(sd->split, value);
            }
            else
                xaccSplitSetValue(sd->split, new_amount);
        }
        else
        {
            xaccSplitSetValue(sd->split, new_amount);
        }

        return;
    }

    /* How to interpret new_amount depends on our view of this
     * transaction.  If we're sitting in an account with the same
     * commodity as the transaction, then we can set the Value and then
     * compute the amount.  Otherwise we are setting the "converted
     * value".  This means we need to convert new_amount to the actual
     * 'value' by dividing by the convrate in order to set the value.
     */

    /* Now compute/set the split value.  Amount is in the register
     * currency but we need to convert to the txn currency.
     */
    if (gnc_split_register_needs_conv_rate (reg, sd->trans, acc))
    {

        /* convert the amount to the Value ... */
        value = gnc_numeric_div (new_amount, amtconv,
                                 gnc_commodity_get_fraction (curr),
                                 GNC_HOW_RND_ROUND);
        xaccSplitSetValue (sd->split, value);
    }
    else
        xaccSplitSetValue (sd->split, new_amount);

    /* Now re-compute the Amount from the Value.  We may need to convert
     * from the Value back to the amount here using the convrate from
     * earlier.
     */
    value = xaccSplitGetValue (sd->split);

    if (gnc_split_register_split_needs_amount (reg, sd->split))
    {
        acc = xaccSplitGetAccount (sd->split);
        new_amount = gnc_numeric_mul (value, convrate,
                                      xaccAccountGetCommoditySCU (acc),
                                      GNC_HOW_RND_ROUND);
        xaccSplitSetAmount (sd->split, new_amount);
    }
}
Beispiel #6
0
int ofx_proc_transaction_cb(struct OfxTransactionData data, void * transaction_user_data)
{
    char dest_string[255];
    time64 current_time = gnc_time (NULL);
    Account *account;
    Account *investment_account = NULL;
    Account *income_account = NULL;
    gchar *investment_account_text, *investment_account_onlineid;
    gnc_commodity *currency = NULL;
    gnc_commodity *investment_commodity = NULL;
    gnc_numeric gnc_amount, gnc_units;
    QofBook *book;
    Transaction *transaction;
    Split *split;
    gchar *notes, *tmp;

    g_assert(gnc_ofx_importer_gui);

    if (!data.account_id_valid)
    {
        PERR("account ID for this transaction is unavailable!");
        return 0;
    }

    account = gnc_import_select_account(gnc_gen_trans_list_widget(gnc_ofx_importer_gui),
                                        data.account_id, 0, NULL, NULL,
                                        ACCT_TYPE_NONE, NULL, NULL);
    if (account == NULL)
    {
        PERR("Unable to find account for id %s", data.account_id);
        return 0;
    }
    /***** Validate the input strings to ensure utf8 *****/
    if (data.name_valid)
        gnc_utf8_strip_invalid(data.name);
    if (data.memo_valid)
        gnc_utf8_strip_invalid(data.memo);
    if (data.check_number_valid)
        gnc_utf8_strip_invalid(data.check_number);
    if (data.reference_number_valid)
        gnc_utf8_strip_invalid(data.reference_number);

    /***** Create the transaction and setup transaction data *******/
    book = gnc_account_get_book(account);
    transaction = xaccMallocTransaction(book);
    xaccTransBeginEdit(transaction);

    /* Note: Unfortunately libofx <= 0.9.5 will not report a missing
     * date field as an invalid one. Instead, it will report it as
     * valid and return a completely bogus date. Starting with
     * libofx-0.9.6 (not yet released as of 2012-09-09), it will still
     * be reported as valid but at least the date integer itself is
     * just plain zero. */
    if (data.date_posted_valid && (data.date_posted != 0))
    {
        /* The hopeful case: We have a posted_date */
        xaccTransSetDatePostedSecsNormalized(transaction, data.date_posted);
    } else if (data.date_initiated_valid && (data.date_initiated != 0))
    {
        /* No posted date? Maybe we have an initiated_date */
        xaccTransSetDatePostedSecsNormalized(transaction, data.date_initiated);
    }
    else
    {
        /* Uh no, no valid date. As a workaround use today's date */
        xaccTransSetDatePostedSecsNormalized(transaction, current_time);
    }

    xaccTransSetDateEnteredSecs(transaction, current_time);

    /* Put transaction name in Description, or memo if name unavailable */
    if (data.name_valid)
    {
        xaccTransSetDescription(transaction, data.name);
    }
    else if (data.memo_valid)
    {
        xaccTransSetDescription(transaction, data.memo);
    }

    /* Put everything else in the Notes field */
    notes = g_strdup_printf("OFX ext. info: ");

    if (data.transactiontype_valid)
    {
        tmp = notes;
        notes = g_strdup_printf("%s%s%s", tmp, "|Trans type:",
                                gnc_ofx_ttype_to_string(data.transactiontype));
        g_free(tmp);
    }

    if (data.invtransactiontype_valid)
    {
        tmp = notes;
        notes = g_strdup_printf("%s%s%s", tmp, "|Investment Trans type:",
                                gnc_ofx_invttype_to_str(data.invtransactiontype));
        g_free(tmp);
    }
    if (data.memo_valid && data.name_valid) /* Copy only if memo wasn't put in Description */
    {
        tmp = notes;
        notes = g_strdup_printf("%s%s%s", tmp, "|Memo:", data.memo);
        g_free(tmp);
    }
    if (data.date_funds_available_valid)
    {
        Timespec ts;
        timespecFromTime64(&ts, data.date_funds_available);
        gnc_timespec_to_iso8601_buff (ts, dest_string);
        tmp = notes;
        notes = g_strdup_printf("%s%s%s", tmp, "|Date funds available:", dest_string);
        g_free(tmp);
    }
    if (data.server_transaction_id_valid)
    {
        tmp = notes;
        notes = g_strdup_printf("%s%s%s", tmp, "|Server trans ID (conf. number):", data.server_transaction_id);
        g_free(tmp);
    }
    if (data.standard_industrial_code_valid)
    {
        tmp = notes;
        notes = g_strdup_printf("%s%s%ld", tmp, "|Standard Industrial Code:", data.standard_industrial_code);
        g_free(tmp);

    }
    if (data.payee_id_valid)
    {
        tmp = notes;
        notes = g_strdup_printf("%s%s%s", tmp, "|Payee ID:", data.payee_id);
        g_free(tmp);
    }

    //PERR("WRITEME: GnuCash ofx_proc_transaction():Add PAYEE and ADRESS here once supported by libofx! Notes=%s\n", notes);

    /* Ideally, gnucash should process the corrected transactions */
    if (data.fi_id_corrected_valid)
    {
        PERR("WRITEME: GnuCash ofx_proc_transaction(): WARNING: This transaction corrected a previous transaction, but we created a new one instead!\n");
        tmp = notes;
        notes = g_strdup_printf("%s%s%s%s", tmp, "|This corrects transaction #", data.fi_id_corrected, "but GnuCash didn't process the correction!");
        g_free(tmp);
    }
    xaccTransSetNotes(transaction, notes);
    g_free(notes);

    if (data.account_ptr && data.account_ptr->currency_valid)
    {
        DEBUG("Currency from libofx: %s", data.account_ptr->currency);
        currency = gnc_commodity_table_lookup( gnc_get_current_commodities (),
                                               GNC_COMMODITY_NS_CURRENCY,
                                               data.account_ptr->currency);
    }
    else
    {
        DEBUG("Currency from libofx unavailable, defaulting to account's default");
        currency = xaccAccountGetCommodity(account);
    }

    xaccTransSetCurrency(transaction, currency);
    if (data.amount_valid)
    {
        if (!data.invtransactiontype_valid)
        {
            /***** Process a normal transaction ******/
            DEBUG("Adding split; Ordinary banking transaction, money flows from or into the source account");
            split = xaccMallocSplit(book);
            xaccTransAppendSplit(transaction, split);
            xaccAccountInsertSplit(account, split);

            gnc_amount = gnc_ofx_numeric_from_double_txn(data.amount, transaction);
            xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));

            /* set tran-num and/or split-action per book option */
            if (data.check_number_valid)
            {
                gnc_set_num_action(transaction, split, data.check_number, NULL);
            }
            else if (data.reference_number_valid)
            {
                gnc_set_num_action(transaction, split, data.reference_number, NULL);
            }
            /* Also put the ofx transaction's memo in the
             * split's memo field */
            if (data.memo_valid)
            {
                xaccSplitSetMemo(split, data.memo);
            }
            if (data.fi_id_valid)
            {
                gnc_import_set_split_online_id(split, data.fi_id);
            }
        }

        else if (data.unique_id_valid
                 && data.security_data_valid
                 && data.security_data_ptr != NULL
                 && data.security_data_ptr->secname_valid)
        {
            gboolean choosing_account = TRUE;
            /********* Process an investment transaction **********/
            /* Note that the ACCT_TYPE_STOCK account type
               should be replaced with something derived from
               data.invtranstype*/

            // We have an investment transaction. First select the correct commodity.
            investment_commodity = gnc_import_select_commodity(data.unique_id,
                                   FALSE,
                                   NULL,
                                   NULL);
            if (investment_commodity != NULL)
            {
                // As we now have the commodity, select the account with that commodity.

                investment_account_text = g_strdup_printf( /* This string is a default account
                                                              name. It MUST NOT contain the
                                                              character ':' anywhere in it or
                                                              in any translations.  */
                                              _("Stock account for security \"%s\""),
                                              data.security_data_ptr->secname);

                investment_account_onlineid = g_strdup_printf( "%s%s", data.account_id, data.unique_id);
                investment_account = gnc_import_select_account(NULL,
                                                               investment_account_onlineid,
                                                               1,
                                                               investment_account_text,
                                                               investment_commodity,
                                                               ACCT_TYPE_STOCK,
                                                               NULL,
                                                               NULL);

                // but use it only if that's really the right commodity
                if (investment_account
                        && xaccAccountGetCommodity(investment_account) != investment_commodity)
                    investment_account = NULL;

                // Loop until we either have an account, or the user pressed Cancel
                while (!investment_account && choosing_account)
                {
                    // No account with correct commodity automatically found.

                    // But are we in auto-create mode and already know a parent?
                    if (auto_create_commodity && ofx_parent_account)
                    {
                        // Yes, so use that as parent when auto-creating the new account below.
                        investment_account = ofx_parent_account;
                    }
                    else
                    {
                        // Let the user choose an account
                        investment_account = gnc_import_select_account(
                                                 gnc_gen_trans_list_widget(gnc_ofx_importer_gui),
                                                 data.unique_id,
                                                 TRUE,
                                                 investment_account_text,
                                                 investment_commodity,
                                                 ACCT_TYPE_STOCK,
                                                 NULL,
                                                 &choosing_account);
                    }
                    // Does the chosen account have the right commodity?
                    if (investment_account && xaccAccountGetCommodity(investment_account) != investment_commodity)
                    {
                        if (auto_create_commodity
                                && xaccAccountTypesCompatible(xaccAccountGetType(investment_account),
                                                              ACCT_TYPE_STOCK))
                        {
                            // The user chose an account, but it does
                            // not have the right commodity. Also,
                            // auto-creation is on. Hence, we create a
                            // new child account of the selected one,
                            // and this one will have the right
                            // commodity.
                            Account *parent_account = investment_account;
                            investment_account =
                                gnc_ofx_new_account(investment_account_text,
                                                    investment_commodity,
                                                    parent_account,
                                                    ACCT_TYPE_STOCK);
                            if (investment_account)
                            {
                                gnc_import_set_acc_online_id(investment_account, data.unique_id);
                                choosing_account = FALSE;
                                ofx_parent_account = parent_account;
                            }
                            else
                            {
                                ofx_parent_account = NULL;
                            }
                        }
                        else
                        {
                            // No account with matching commodity. Ask the user
                            // whether to continue or abort.
                            choosing_account =
                                gnc_verify_dialog(
                                    gnc_gen_trans_list_widget(gnc_ofx_importer_gui), TRUE,
                                    "The chosen account \"%s\" does not have the correct "
                                    "currency/security \"%s\" (it has \"%s\" instead). "
                                    "This account cannot be used. "
                                    "Do you want to choose again?",
                                    xaccAccountGetName(investment_account),
                                    gnc_commodity_get_fullname(investment_commodity),
                                    gnc_commodity_get_fullname(xaccAccountGetCommodity(investment_account)));
                            // We must also delete the online_id that was set in gnc_import_select_account()
                            gnc_import_set_acc_online_id(investment_account, "");
                            investment_account = NULL;
                        }
                    }
                }
                if (!investment_account)
                {
                    PERR("No investment account found for text: %s\n", investment_account_text);
                }
                g_free (investment_account_text);
                g_free (investment_account_onlineid);
                investment_account_text = NULL;

                if (investment_account != NULL &&
                        data.unitprice_valid &&
                        data.units_valid &&
                        ( data.invtransactiontype != OFX_INCOME ) )
                {
                    DEBUG("Adding investment split; Money flows from or into the stock account");
                    split = xaccMallocSplit(book);
                    xaccTransAppendSplit(transaction, split);
                    xaccAccountInsertSplit(investment_account, split);

                    gnc_amount = gnc_ofx_numeric_from_double (ofx_get_investment_amount(&data),
                                 investment_commodity);
                    gnc_units = gnc_ofx_numeric_from_double (data.units, investment_commodity);
                    xaccSplitSetAmount(split, gnc_units);
                    xaccSplitSetValue(split, gnc_amount);

                    /* set tran-num and/or split-action per book option */
                    if (data.check_number_valid)
                    {
                        gnc_set_num_action(transaction, split, data.check_number, NULL);
                    }
                    else if (data.reference_number_valid)
                    {
                        gnc_set_num_action(transaction, split,
                                                data.reference_number, NULL);
                    }
                    if (data.security_data_ptr->memo_valid)
                    {
                        xaccSplitSetMemo(split, data.security_data_ptr->memo);
                    }
                    if (data.fi_id_valid)
                    {
                        gnc_import_set_split_online_id(split, data.fi_id);
                    }
                }
                else
                {
                    if (investment_account)
                        PERR("The investment account, units or unitprice was not found for the investment transaction");
                }
            }
            else
            {
                PERR("Commodity not found for the investment transaction");
            }

            if (data.invtransactiontype_valid && investment_account)
            {
                if (data.invtransactiontype == OFX_REINVEST
                        || data.invtransactiontype == OFX_INCOME)
                {
                    DEBUG("Now let's find an account for the destination split");

                    income_account = gnc_ofx_kvp_get_assoc_account(investment_account);

                    if (income_account == NULL)
                    {
                        DEBUG("Couldn't find an associated income account");
                        investment_account_text = g_strdup_printf( /* This string is a default account
                                                                      name. It MUST NOT contain the
                                                                      character ':' anywhere in it or
                                                                      in any translations.  */
                                                      _("Income account for security \"%s\""),
                                                      data.security_data_ptr->secname);
                        income_account = gnc_import_select_account(
                                             gnc_gen_trans_list_widget(gnc_ofx_importer_gui),
                                             NULL,
                                             1,
                                             investment_account_text,
                                             currency,
                                             ACCT_TYPE_INCOME,
                                             NULL,
                                             NULL);
                        gnc_ofx_kvp_set_assoc_account(investment_account,
                                                      income_account);
                        DEBUG("KVP written");

                    }
                    else
                    {
                        DEBUG("Found at least one associated income account");
                    }
                }
                if (income_account != NULL &&
                        data.invtransactiontype == OFX_REINVEST)
                {
                    DEBUG("Adding investment split; Money flows from the income account");
                    split = xaccMallocSplit(book);
                    xaccTransAppendSplit(transaction, split);
                    xaccAccountInsertSplit(income_account, split);

                    gnc_amount = gnc_ofx_numeric_from_double_txn (data.amount, transaction);
                    xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));

                    // Set split memo from ofx transaction name or memo
                    gnc_ofx_set_split_memo(&data, split);
                }
                if (income_account != NULL &&
                        data.invtransactiontype == OFX_INCOME)
                {
                    DEBUG("Adding investment split; Money flows from the income account");
                    split = xaccMallocSplit(book);
                    xaccTransAppendSplit(transaction, split);
                    xaccAccountInsertSplit(income_account, split);

                    gnc_amount = gnc_ofx_numeric_from_double_txn (-data.amount,/*OFX_INCOME amounts come in as positive numbers*/
                                 transaction);
                    xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));

                    // Set split memo from ofx transaction name or memo
                    gnc_ofx_set_split_memo(&data, split);
                }
            }

            if (data.invtransactiontype_valid
                    && data.invtransactiontype != OFX_REINVEST)
            {
                DEBUG("Adding investment split; Money flows from or to the cash account");
                split = xaccMallocSplit(book);
                xaccTransAppendSplit(transaction, split);
                xaccAccountInsertSplit(account, split);

                gnc_amount = gnc_ofx_numeric_from_double_txn(
                                 -ofx_get_investment_amount(&data), transaction);
                xaccSplitSetBaseValue(split, gnc_amount,
                                      xaccTransGetCurrency(transaction));

                // Set split memo from ofx transaction name or memo
                gnc_ofx_set_split_memo(&data, split);
            }
        }

        /* Send transaction to importer GUI. */
        if (xaccTransCountSplits(transaction) > 0)
        {
            DEBUG("%d splits sent to the importer gui", xaccTransCountSplits(transaction));
            gnc_gen_trans_list_add_trans (gnc_ofx_importer_gui, transaction);
        }
        else
        {
            PERR("No splits in transaction (missing account?), ignoring.");
            xaccTransDestroy(transaction);
            xaccTransCommitEdit(transaction);
        }
    }
    else
    {
        PERR("The transaction doesn't have a valid amount");
        xaccTransDestroy(transaction);
        xaccTransCommitEdit(transaction);
    }

    return 0;
}//end ofx_proc_transaction()