GnuCash 2.4.99
gnc-ofx-import.c
00001 /*******************************************************************\
00002  * This program is free software; you can redistribute it and/or    *
00003  * modify it under the terms of the GNU General Public License as   *
00004  * published by the Free Software Foundation; either version 2 of   *
00005  * the License, or (at your option) any later version.              *
00006  *                                                                  *
00007  * This program is distributed in the hope that it will be useful,  *
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00010  * GNU General Public License for more details.                     *
00011  *                                                                  *
00012  * You should have received a copy of the GNU General Public License*
00013  * along with this program; if not, contact:                        *
00014  *                                                                  *
00015  * Free Software Foundation           Voice:  +1-617-542-5942       *
00016  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00017  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00018 \********************************************************************/
00026 #include "config.h"
00027 
00028 #include <gtk/gtk.h>
00029 #include <glib/gi18n.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <sys/time.h>
00033 #include <libguile.h>
00034 #include <math.h>
00035 
00036 #include <libofx/libofx.h>
00037 #include "import-account-matcher.h"
00038 #include "import-commodity-matcher.h"
00039 #include "import-utilities.h"
00040 #include "import-main-matcher.h"
00041 
00042 #include "Account.h"
00043 #include "Transaction.h"
00044 #include "gnc-ofx-import.h"
00045 #include "gnc-file.h"
00046 #include "gnc-engine.h"
00047 #include "gnc-ui-util.h"
00048 #include "gnc-glib-utils.h"
00049 #include "core-utils/gnc-gconf-utils.h"
00050 #include "gnome-utils/gnc-ui.h"
00051 #include "gnome-utils/dialog-account.h"
00052 
00053 #include "gnc-ofx-kvp.h"
00054 
00055 #define GCONF_SECTION "dialogs/import/ofx"
00056 
00057 static QofLogModule log_module = GNC_MOD_IMPORT;
00058 
00059 /********************************************************************\
00060  * gnc_file_ofx_import
00061  * Entry point
00062 \********************************************************************/
00063 
00064 /* CS: Store the reference to the created importer gui so that the
00065    ofx_proc_transaction_cb can use it. */
00066 GNCImportMainMatcher *gnc_ofx_importer_gui = NULL;
00067 static gboolean auto_create_commodity = FALSE;
00068 static Account *ofx_parent_account = NULL;
00069 
00070 GList *ofx_created_commodites = NULL;
00071 
00072 /*
00073 int ofx_proc_status_cb(struct OfxStatusData data)
00074 {
00075   return 0;
00076 }
00077 */
00078 
00079 int ofx_proc_security_cb(const struct OfxSecurityData data, void * security_user_data);
00080 int ofx_proc_transaction_cb(struct OfxTransactionData data, void * transaction_user_data);
00081 int ofx_proc_account_cb(struct OfxAccountData data, void * account_user_data);
00082 static double ofx_get_investment_amount(const struct OfxTransactionData* data);
00083 
00084 static const gchar *gnc_ofx_ttype_to_string(TransactionType t)
00085 {
00086     switch (t)
00087     {
00088     case OFX_CREDIT:
00089         return "Generic credit";
00090     case OFX_DEBIT:
00091         return "Generic debit";
00092     case OFX_INT:
00093         return "Interest earned or paid (Note: Depends on signage of amount)";
00094     case OFX_DIV:
00095         return "Dividend";
00096     case OFX_FEE:
00097         return "FI fee";
00098     case OFX_SRVCHG:
00099         return "Service charge";
00100     case OFX_DEP:
00101         return "Deposit";
00102     case OFX_ATM:
00103         return "ATM debit or credit (Note: Depends on signage of amount)";
00104     case OFX_POS:
00105         return "Point of sale debit or credit (Note: Depends on signage of amount)";
00106     case OFX_XFER:
00107         return "Transfer";
00108     case OFX_CHECK:
00109         return "Check";
00110     case OFX_PAYMENT:
00111         return "Electronic payment";
00112     case OFX_CASH:
00113         return "Cash withdrawal";
00114     case OFX_DIRECTDEP:
00115         return "Direct deposit";
00116     case OFX_DIRECTDEBIT:
00117         return "Merchant initiated debit";
00118     case OFX_REPEATPMT:
00119         return "Repeating payment/standing order";
00120     case OFX_OTHER:
00121         return "Other";
00122     default:
00123         return "Unknown transaction type";
00124     }
00125 }
00126 
00127 static const gchar *gnc_ofx_invttype_to_str(InvTransactionType t)
00128 {
00129     switch (t)
00130     {
00131     case OFX_BUYDEBT:
00132         return "BUYDEBT (Buy debt security)";
00133     case OFX_BUYMF:
00134         return "BUYMF (Buy mutual fund)";
00135     case OFX_BUYOPT:
00136         return "BUYOPT (Buy option)";
00137     case OFX_BUYOTHER:
00138         return "BUYOTHER (Buy other security type)";
00139     case OFX_BUYSTOCK:
00140         return "BUYSTOCK (Buy stock))";
00141     case OFX_CLOSUREOPT:
00142         return "CLOSUREOPT (Close a position for an option)";
00143     case OFX_INCOME:
00144         return "INCOME (Investment income is realized as cash into the investment account)";
00145     case OFX_INVEXPENSE:
00146         return "INVEXPENSE (Misc investment expense that is associated with a specific security)";
00147     case OFX_JRNLFUND:
00148         return "JRNLFUND (Journaling cash holdings between subaccounts within the same investment account)";
00149     case OFX_MARGININTEREST:
00150         return "MARGININTEREST (Margin interest expense)";
00151     case OFX_REINVEST:
00152         return "REINVEST (Reinvestment of income)";
00153     case OFX_RETOFCAP:
00154         return "RETOFCAP (Return of capital)";
00155     case OFX_SELLDEBT:
00156         return "SELLDEBT (Sell debt security.  Used when debt is sold, called, or reached maturity)";
00157     case OFX_SELLMF:
00158         return "SELLMF (Sell mutual fund)";
00159     case OFX_SELLOPT:
00160         return "SELLOPT (Sell option)";
00161     case OFX_SELLOTHER:
00162         return "SELLOTHER (Sell other type of security)";
00163     case OFX_SELLSTOCK:
00164         return "SELLSTOCK (Sell stock)";
00165     case OFX_SPLIT:
00166         return "SPLIT (Stock or mutial fund split)";
00167     case OFX_TRANSFER:
00168         return "TRANSFER (Transfer holdings in and out of the investment account)";
00169     default:
00170         return "ERROR, this investment transaction type is unknown.  This is a bug in ofxdump";
00171     }
00172 
00173 }
00174 
00175 
00176 int ofx_proc_security_cb(const struct OfxSecurityData data, void * security_user_data)
00177 {
00178     const char* cusip = NULL;
00179     const char* default_fullname = NULL;
00180     const char* default_mnemonic = NULL;
00181 
00182     if (data.unique_id_valid)
00183     {
00184         cusip = data.unique_id;
00185     }
00186     if (data.secname_valid)
00187     {
00188         default_fullname = data.secname;
00189     }
00190     if (data.ticker_valid)
00191     {
00192         default_mnemonic = data.ticker;
00193     }
00194 
00195     if (auto_create_commodity)
00196     {
00197         gnc_commodity *commodity =
00198             gnc_import_select_commodity(cusip,
00199                                         FALSE,
00200                                         default_fullname,
00201                                         default_mnemonic);
00202 
00203         if (!commodity)
00204         {
00205             QofBook *book = gnc_get_current_book();
00206             gnc_quote_source *source;
00207             gint source_selection = 0; // FIXME: This is just a wild guess
00208             const char *commodity_namespace = NULL;
00209             int fraction = 1;
00210 
00211             if (data.unique_id_type_valid)
00212             {
00213                 commodity_namespace = data.unique_id_type;
00214             }
00215 
00216             g_warning("Creating a new commodity, cusip=%s", cusip);
00217             /* Create the new commodity */
00218             commodity = gnc_commodity_new(book,
00219                                           default_fullname,
00220                                           commodity_namespace,
00221                                           default_mnemonic,
00222                                           cusip,
00223                                           fraction);
00224 
00225             /* Also set a single quote source */
00226             gnc_commodity_begin_edit(commodity);
00227             gnc_commodity_user_set_quote_flag (commodity, TRUE);
00228             source = gnc_quote_source_lookup_by_ti (SOURCE_SINGLE, source_selection);
00229             gnc_commodity_set_quote_source(commodity, source);
00230             gnc_commodity_commit_edit(commodity);
00231 
00232             /* Remember the commodity */
00233             gnc_commodity_table_insert(gnc_get_current_commodities(), commodity);
00234 
00235             /* Remember this new commodity for us as well */
00236             ofx_created_commodites = g_list_prepend(ofx_created_commodites, commodity);
00237         }
00238     }
00239     else
00240     {
00241         gnc_import_select_commodity(cusip,
00242                                     TRUE,
00243                                     default_fullname,
00244                                     default_mnemonic);
00245     }
00246     return 0;
00247 }
00248 
00249 static void gnc_ofx_set_split_memo(const struct OfxTransactionData* data, Split *split)
00250 {
00251     g_assert(data);
00252     g_assert(split);
00253     /* Also put the ofx transaction name in
00254      * the splits memo field, or ofx memo if
00255      * name is unavailable */
00256     if (data->name_valid)
00257     {
00258         xaccSplitSetMemo(split, data->name);
00259     }
00260     else if (data->memo_valid)
00261     {
00262         xaccSplitSetMemo(split, data->memo);
00263     }
00264 }
00265 static gnc_numeric gnc_ofx_numeric_from_double(double value, const gnc_commodity *commodity)
00266 {
00267     return double_to_gnc_numeric (value,
00268                                   gnc_commodity_get_fraction(commodity),
00269                                   GNC_HOW_RND_ROUND_HALF_UP);
00270 }
00271 static gnc_numeric gnc_ofx_numeric_from_double_txn(double value, const Transaction* txn)
00272 {
00273     return gnc_ofx_numeric_from_double(value, xaccTransGetCurrency(txn));
00274 }
00275 
00276 /* Opens the dialog to create a new account with given name, commodity, parent, type.
00277  * Returns the new account, or NULL if it couldn't be created.. */
00278 static Account *gnc_ofx_new_account(const char* name,
00279                                     const gnc_commodity * account_commodity,
00280                                     Account *parent_account,
00281                                     GNCAccountType new_account_default_type)
00282 {
00283     Account *result;
00284     GList * valid_types = NULL;
00285 
00286     g_assert(name);
00287     g_assert(account_commodity);
00288     g_assert(parent_account);
00289 
00290     if (new_account_default_type != ACCT_TYPE_NONE)
00291     {
00292         // Passing the types as gpointer
00293         valid_types =
00294             g_list_prepend(valid_types,
00295                            GINT_TO_POINTER(new_account_default_type));
00296         if (!xaccAccountTypesCompatible(xaccAccountGetType(parent_account), new_account_default_type))
00297         {
00298             // Need to add the parent's account type
00299             valid_types =
00300                 g_list_prepend(valid_types,
00301                                GINT_TO_POINTER(xaccAccountGetType(parent_account)));
00302         }
00303     }
00304     result = gnc_ui_new_accounts_from_name_with_defaults (name,
00305              valid_types,
00306              account_commodity,
00307              parent_account);
00308     g_list_free(valid_types);
00309     return result;
00310 }
00311 
00312 
00313 int ofx_proc_transaction_cb(struct OfxTransactionData data, void * transaction_user_data)
00314 {
00315     char dest_string[255];
00316     time_t current_time;
00317     Account *account;
00318     Account *investment_account = NULL;
00319     Account *income_account = NULL;
00320     gchar *investment_account_text;
00321     gnc_commodity *currency = NULL;
00322     gnc_commodity *investment_commodity = NULL;
00323     gnc_numeric gnc_amount, gnc_units;
00324     QofBook *book;
00325     Transaction *transaction;
00326     Split *split;
00327     gchar *notes, *tmp;
00328 
00329     g_assert(gnc_ofx_importer_gui);
00330 
00331     if (!data.account_id_valid)
00332     {
00333         PERR("account ID for this transaction is unavailable!");
00334         return 0;
00335     }
00336 
00337     account = gnc_import_select_account(gnc_gen_trans_list_widget(gnc_ofx_importer_gui),
00338                                         data.account_id, 0, NULL, NULL,
00339                                         ACCT_TYPE_NONE, NULL, NULL);
00340     if (account == NULL)
00341     {
00342         PERR("Unable to find account for id %s", data.account_id);
00343         return 0;
00344     }
00345     /***** Validate the input strings to ensure utf8 *****/
00346     if (data.name_valid)
00347         gnc_utf8_strip_invalid(data.name);
00348     if (data.memo_valid)
00349         gnc_utf8_strip_invalid(data.memo);
00350     if (data.check_number_valid)
00351         gnc_utf8_strip_invalid(data.check_number);
00352     if (data.reference_number_valid)
00353         gnc_utf8_strip_invalid(data.reference_number);
00354 
00355     /***** Create the transaction and setup transaction data *******/
00356     book = gnc_account_get_book(account);
00357     transaction = xaccMallocTransaction(book);
00358     xaccTransBeginEdit(transaction);
00359 
00360     if (data.date_initiated_valid)
00361     {
00362         xaccTransSetDatePostedSecs(transaction, data.date_initiated);
00363     }
00364     else if (data.date_posted_valid)
00365     {
00366         xaccTransSetDatePostedSecs(transaction, data.date_posted);
00367     }
00368 
00369     if (data.date_posted_valid)
00370     {
00371         xaccTransSetDatePostedSecs(transaction, data.date_posted);
00372     }
00373 
00374     current_time = time(NULL);
00375     xaccTransSetDateEnteredSecs(transaction, mktime(localtime(&current_time)));
00376 
00377     if (data.check_number_valid)
00378     {
00379         xaccTransSetNum(transaction, data.check_number);
00380     }
00381     else if (data.reference_number_valid)
00382     {
00383         xaccTransSetNum(transaction, data.reference_number);
00384     }
00385     /* Put transaction name in Description, or memo if name unavailable */
00386     if (data.name_valid)
00387     {
00388         xaccTransSetDescription(transaction, data.name);
00389     }
00390     else if (data.memo_valid)
00391     {
00392         xaccTransSetDescription(transaction, data.memo);
00393     }
00394 
00395     /* Put everything else in the Notes field */
00396     notes = g_strdup_printf("OFX ext. info: ");
00397 
00398     if (data.transactiontype_valid)
00399     {
00400         tmp = notes;
00401         notes = g_strdup_printf("%s%s%s", tmp, "|Trans type:",
00402                                 gnc_ofx_ttype_to_string(data.transactiontype));
00403         g_free(tmp);
00404     }
00405 
00406     if (data.invtransactiontype_valid)
00407     {
00408         tmp = notes;
00409         notes = g_strdup_printf("%s%s%s", tmp, "|Investment Trans type:",
00410                                 gnc_ofx_invttype_to_str(data.invtransactiontype));
00411         g_free(tmp);
00412     }
00413     if (data.memo_valid && data.name_valid) /* Copy only if memo wasn't put in Description */
00414     {
00415         tmp = notes;
00416         notes = g_strdup_printf("%s%s%s", tmp, "|Memo:", data.memo);
00417         g_free(tmp);
00418     }
00419     if (data.date_funds_available_valid)
00420     {
00421         Timespec ts;
00422         timespecFromTime_t(&ts, data.date_funds_available);
00423         gnc_timespec_to_iso8601_buff (ts, dest_string);
00424         tmp = notes;
00425         notes = g_strdup_printf("%s%s%s", tmp, "|Date funds available:", dest_string);
00426         g_free(tmp);
00427     }
00428     if (data.server_transaction_id_valid)
00429     {
00430         tmp = notes;
00431         notes = g_strdup_printf("%s%s%s", tmp, "|Server trans ID (conf. number):", data.server_transaction_id);
00432         g_free(tmp);
00433     }
00434     if (data.standard_industrial_code_valid)
00435     {
00436         tmp = notes;
00437         notes = g_strdup_printf("%s%s%ld", tmp, "|Standard Industrial Code:", data.standard_industrial_code);
00438         g_free(tmp);
00439 
00440     }
00441     if (data.payee_id_valid)
00442     {
00443         tmp = notes;
00444         notes = g_strdup_printf("%s%s%s", tmp, "|Payee ID:", data.payee_id);
00445         g_free(tmp);
00446     }
00447 
00448     //PERR("WRITEME: GnuCash ofx_proc_transaction():Add PAYEE and ADRESS here once supported by libofx! Notes=%s\n", notes);
00449 
00450     /* Ideally, gnucash should process the corrected transactions */
00451     if (data.fi_id_corrected_valid)
00452     {
00453         PERR("WRITEME: GnuCash ofx_proc_transaction(): WARNING: This transaction corrected a previous transaction, but we created a new one instead!\n");
00454         tmp = notes;
00455         notes = g_strdup_printf("%s%s%s%s", tmp, "|This corrects transaction #", data.fi_id_corrected, "but GnuCash didn't process the correction!");
00456         g_free(tmp);
00457     }
00458     xaccTransSetNotes(transaction, notes);
00459     g_free(notes);
00460 
00461     if (data.account_ptr && data.account_ptr->currency_valid)
00462     {
00463         DEBUG("Currency from libofx: %s", data.account_ptr->currency);
00464         currency = gnc_commodity_table_lookup( gnc_get_current_commodities (),
00465                                                GNC_COMMODITY_NS_CURRENCY,
00466                                                data.account_ptr->currency);
00467     }
00468     else
00469     {
00470         DEBUG("Currency from libofx unavailable, defaulting to account's default");
00471         currency = xaccAccountGetCommodity(account);
00472     }
00473 
00474     xaccTransSetCurrency(transaction, currency);
00475     if (data.amount_valid)
00476     {
00477         if (!data.invtransactiontype_valid)
00478         {
00479             /***** Process a normal transaction ******/
00480             DEBUG("Adding split; Ordinary banking transaction, money flows from or into the source account");
00481             split = xaccMallocSplit(book);
00482             xaccTransAppendSplit(transaction, split);
00483             xaccAccountInsertSplit(account, split);
00484 
00485             gnc_amount = gnc_ofx_numeric_from_double_txn(data.amount, transaction);
00486             xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));
00487 
00488             /* Also put the ofx transaction's memo in the
00489              * split's memo field */
00490             if (data.memo_valid)
00491             {
00492                 xaccSplitSetMemo(split, data.memo);
00493             }
00494             if (data.fi_id_valid)
00495             {
00496                 gnc_import_set_split_online_id(split, data.fi_id);
00497             }
00498         }
00499 
00500         else if (data.unique_id_valid
00501                  && data.security_data_valid
00502                  && data.security_data_ptr != NULL
00503                  && data.security_data_ptr->secname_valid)
00504         {
00505             gboolean choosing_account = TRUE;
00506             /********* Process an investment transaction **********/
00507             /* Note that the ACCT_TYPE_STOCK account type
00508                should be replaced with something derived from
00509                data.invtranstype*/
00510 
00511             // We have an investment transaction. First select the correct commodity.
00512             investment_commodity = gnc_import_select_commodity(data.unique_id,
00513                                    FALSE,
00514                                    NULL,
00515                                    NULL);
00516             if (investment_commodity != NULL)
00517             {
00518                 // As we now have the commodity, select the account with that commodity.
00519 
00520                 investment_account_text = g_strdup_printf( /* This string is a default account
00521                                                                   name. It MUST NOT contain the
00522                                                                   character ':' anywhere in it or
00523                                                                   in any translations.  */
00524                                               _("Stock account for security \"%s\""),
00525                                               data.security_data_ptr->secname);
00526 
00527                 // @FIXME: Add the automated selection or creation of account here!
00528 
00529                 // First check whether we can find the right investment_account without asking the user
00530                 investment_account = gnc_import_select_account(NULL,
00531                                      data.unique_id, FALSE, investment_account_text,
00532                                      investment_commodity, ACCT_TYPE_STOCK, NULL, NULL);
00533                 // but use it only if that's really the right commodity
00534                 if (investment_account
00535                         && xaccAccountGetCommodity(investment_account) != investment_commodity)
00536                     investment_account = NULL;
00537 
00538                 // Loop until we either have an account, or the user pressed Cancel
00539                 while (!investment_account && choosing_account)
00540                 {
00541                     // No account with correct commodity automatically found.
00542 
00543                     // But are we in auto-create mode and already know a parent?
00544                     if (auto_create_commodity && ofx_parent_account)
00545                     {
00546                         // Yes, so use that as parent when auto-creating the new account below.
00547                         investment_account = ofx_parent_account;
00548                     }
00549                     else
00550                     {
00551                         // Let the user choose an account
00552                         investment_account = gnc_import_select_account(
00553                                                  gnc_gen_trans_list_widget(gnc_ofx_importer_gui),
00554                                                  data.unique_id,
00555                                                  TRUE,
00556                                                  investment_account_text,
00557                                                  investment_commodity,
00558                                                  ACCT_TYPE_STOCK,
00559                                                  NULL,
00560                                                  &choosing_account);
00561                     }
00562                     // Does the chosen account have the right commodity?
00563                     if (investment_account && xaccAccountGetCommodity(investment_account) != investment_commodity)
00564                     {
00565                         if (auto_create_commodity
00566                                 && xaccAccountTypesCompatible(xaccAccountGetType(investment_account),
00567                                                               ACCT_TYPE_STOCK))
00568                         {
00569                             // The user chose an account, but it does
00570                             // not have the right commodity. Also,
00571                             // auto-creation is on. Hence, we create a
00572                             // new child account of the selected one,
00573                             // and this one will have the right
00574                             // commodity.
00575                             Account *parent_account = investment_account;
00576                             investment_account =
00577                                 gnc_ofx_new_account(investment_account_text,
00578                                                     investment_commodity,
00579                                                     parent_account,
00580                                                     ACCT_TYPE_STOCK);
00581                             if (investment_account)
00582                             {
00583                                 gnc_import_set_acc_online_id(investment_account, data.unique_id);
00584                                 choosing_account = FALSE;
00585                                 ofx_parent_account = parent_account;
00586                             }
00587                             else
00588                             {
00589                                 ofx_parent_account = NULL;
00590                             }
00591                         }
00592                         else
00593                         {
00594                             // No account with matching commodity. Ask the user
00595                             // whether to continue or abort.
00596                             choosing_account =
00597                                 gnc_verify_dialog(
00598                                     gnc_gen_trans_list_widget(gnc_ofx_importer_gui), TRUE,
00599                                     "The chosen account \"%s\" does not have the correct "
00600                                     "currency/security \"%s\" (it has \"%s\" instead). "
00601                                     "This account cannot be used. "
00602                                     "Do you want to choose again?",
00603                                     xaccAccountGetName(investment_account),
00604                                     gnc_commodity_get_fullname(investment_commodity),
00605                                     gnc_commodity_get_fullname(xaccAccountGetCommodity(investment_account)));
00606                             // We must also delete the online_id that was set in gnc_import_select_account()
00607                             gnc_import_set_acc_online_id(investment_account, "");
00608                             investment_account = NULL;
00609                         }
00610                     }
00611                 }
00612                 if (!investment_account)
00613                 {
00614                     PERR("No investment account found for text: %s\n", investment_account_text);
00615                 }
00616                 g_free (investment_account_text);
00617                 investment_account_text = NULL;
00618 
00619                 if (investment_account != NULL &&
00620                         data.unitprice_valid &&
00621                         data.units_valid &&
00622                         ( data.invtransactiontype != OFX_INCOME ) )
00623                 {
00624                     DEBUG("Adding investment split; Money flows from or into the stock account");
00625                     split = xaccMallocSplit(book);
00626                     xaccTransAppendSplit(transaction, split);
00627                     xaccAccountInsertSplit(investment_account, split);
00628 
00629                     gnc_amount = gnc_ofx_numeric_from_double (ofx_get_investment_amount(&data),
00630                                  investment_commodity);
00631                     gnc_units = gnc_ofx_numeric_from_double (data.units, investment_commodity);
00632                     xaccSplitSetAmount(split, gnc_units);
00633                     xaccSplitSetValue(split, gnc_amount);
00634 
00635                     if (data.security_data_ptr->memo_valid)
00636                     {
00637                         xaccSplitSetMemo(split, data.security_data_ptr->memo);
00638                     }
00639                     if (data.fi_id_valid)
00640                     {
00641                         gnc_import_set_split_online_id(split, data.fi_id);
00642                     }
00643                 }
00644                 else
00645                 {
00646                     if (investment_account)
00647                         PERR("The investment account, units or unitprice was not found for the investment transaction");
00648                 }
00649             }
00650             else
00651             {
00652                 PERR("Commodity not found for the investment transaction");
00653             }
00654 
00655             if (data.invtransactiontype_valid && investment_account)
00656             {
00657                 if (data.invtransactiontype == OFX_REINVEST
00658                         || data.invtransactiontype == OFX_INCOME)
00659                 {
00660                     DEBUG("Now let's find an account for the destination split");
00661 
00662                     income_account = gnc_ofx_kvp_get_assoc_account(investment_account);
00663 
00664                     if (income_account == NULL)
00665                     {
00666                         DEBUG("Couldn't find an associated income account");
00667                         investment_account_text = g_strdup_printf( /* This string is a default account
00668                                                                           name. It MUST NOT contain the
00669                                                                           character ':' anywhere in it or
00670                                                                           in any translations.  */
00671                                                       _("Income account for security \"%s\""),
00672                                                       data.security_data_ptr->secname);
00673                         income_account = gnc_import_select_account(
00674                                              gnc_gen_trans_list_widget(gnc_ofx_importer_gui),
00675                                              NULL,
00676                                              1,
00677                                              investment_account_text,
00678                                              currency,
00679                                              ACCT_TYPE_INCOME,
00680                                              NULL,
00681                                              NULL);
00682                         gnc_ofx_kvp_set_assoc_account(investment_account,
00683                                                       income_account);
00684                         DEBUG("KVP written");
00685 
00686                     }
00687                     else
00688                     {
00689                         DEBUG("Found at least one associated income account");
00690                     }
00691                 }
00692                 if (income_account != NULL &&
00693                         data.invtransactiontype == OFX_REINVEST)
00694                 {
00695                     DEBUG("Adding investment split; Money flows from the income account");
00696                     split = xaccMallocSplit(book);
00697                     xaccTransAppendSplit(transaction, split);
00698                     xaccAccountInsertSplit(income_account, split);
00699 
00700                     gnc_amount = gnc_ofx_numeric_from_double_txn (data.amount, transaction);
00701                     xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));
00702 
00703                     // Set split memo from ofx transaction name or memo
00704                     gnc_ofx_set_split_memo(&data, split);
00705                 }
00706                 if (income_account != NULL &&
00707                         data.invtransactiontype == OFX_INCOME)
00708                 {
00709                     DEBUG("Adding investment split; Money flows from the income account");
00710                     split = xaccMallocSplit(book);
00711                     xaccTransAppendSplit(transaction, split);
00712                     xaccAccountInsertSplit(income_account, split);
00713 
00714                     gnc_amount = gnc_ofx_numeric_from_double_txn (-data.amount,/*OFX_INCOME amounts come in as positive numbers*/
00715                                  transaction);
00716                     xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));
00717 
00718                     // Set split memo from ofx transaction name or memo
00719                     gnc_ofx_set_split_memo(&data, split);
00720                 }
00721             }
00722 
00723             if (data.invtransactiontype_valid
00724                     && data.invtransactiontype != OFX_REINVEST)
00725             {
00726                 DEBUG("Adding investment split; Money flows from or to the cash account");
00727                 split = xaccMallocSplit(book);
00728                 xaccTransAppendSplit(transaction, split);
00729                 xaccAccountInsertSplit(account, split);
00730 
00731                 gnc_amount = gnc_ofx_numeric_from_double_txn(
00732                                  -ofx_get_investment_amount(&data), transaction);
00733                 xaccSplitSetBaseValue(split, gnc_amount,
00734                                       xaccTransGetCurrency(transaction));
00735 
00736                 // Set split memo from ofx transaction name or memo
00737                 gnc_ofx_set_split_memo(&data, split);
00738             }
00739         }
00740 
00741         /* Send transaction to importer GUI. */
00742         if (xaccTransCountSplits(transaction) > 0)
00743         {
00744             DEBUG("%d splits sent to the importer gui", xaccTransCountSplits(transaction));
00745             gnc_gen_trans_list_add_trans (gnc_ofx_importer_gui, transaction);
00746         }
00747         else
00748         {
00749             PERR("No splits in transaction (missing account?), ignoring.");
00750             xaccTransDestroy(transaction);
00751             xaccTransCommitEdit(transaction);
00752         }
00753     }
00754     else
00755     {
00756         PERR("The transaction doesn't have a valid amount");
00757         xaccTransDestroy(transaction);
00758         xaccTransCommitEdit(transaction);
00759     }
00760 
00761     return 0;
00762 }//end ofx_proc_transaction()
00763 
00764 /*
00765 int ofx_proc_statement_cb(struct OfxStatementData data, void * statement_user_data)
00766 {
00767   return 0;
00768 }//end ofx_proc_statement()
00769 */
00770 
00771 int ofx_proc_account_cb(struct OfxAccountData data, void * account_user_data)
00772 {
00773     Account *selected_account;
00774     gnc_commodity_table * commodity_table;
00775     gnc_commodity * default_commodity;
00776     GNCAccountType default_type = ACCT_TYPE_NONE;
00777     gchar * account_description;
00778     const gchar * account_type_name = _("Unknown OFX account");
00779 
00780     if (data.account_id_valid)
00781     {
00782         commodity_table = gnc_get_current_commodities ();
00783         if (data.currency_valid)
00784         {
00785             DEBUG("Currency from libofx: %s", data.currency);
00786             default_commodity = gnc_commodity_table_lookup(commodity_table,
00787                                 GNC_COMMODITY_NS_CURRENCY,
00788                                 data.currency);
00789         }
00790         else
00791         {
00792             default_commodity = NULL;
00793         }
00794 
00795         if (data.account_type_valid)
00796         {
00797             switch (data.account_type)
00798             {
00799             case OFX_CHECKING :
00800                 default_type = ACCT_TYPE_BANK;
00801                 account_type_name = _("Unknown OFX checking account");
00802                 break;
00803             case OFX_SAVINGS :
00804                 default_type = ACCT_TYPE_BANK;
00805                 account_type_name = _("Unknown OFX savings account");
00806                 break;
00807             case OFX_MONEYMRKT :
00808                 default_type = ACCT_TYPE_MONEYMRKT;
00809                 account_type_name = _("Unknown OFX money market account");
00810                 break;
00811             case OFX_CREDITLINE :
00812                 default_type = ACCT_TYPE_CREDITLINE;
00813                 account_type_name = _("Unknown OFX credit line account");
00814                 break;
00815             case OFX_CMA :
00816                 default_type = ACCT_TYPE_NONE;
00817                 account_type_name = _("Unknown OFX CMA account");
00818                 break;
00819             case OFX_CREDITCARD :
00820                 default_type = ACCT_TYPE_CREDIT;
00821                 account_type_name = _("Unknown OFX credit card account");
00822                 break;
00823             case OFX_INVESTMENT :
00824                 default_type = ACCT_TYPE_BANK;
00825                 account_type_name = _("Unknown OFX investment account");
00826                 break;
00827             default:
00828                 PERR("WRITEME: ofx_proc_account() This is an unknown account type!");
00829             }
00830         }
00831 
00832         gnc_utf8_strip_invalid(data.account_name);
00833         account_description = g_strdup_printf( /* This string is a default account
00834                                               name. It MUST NOT contain the
00835                                               character ':' anywhere in it or
00836                                               in any translation.  */
00837                                   "%s \"%s\"",
00838                                   account_type_name,
00839                                   data.account_name);
00840         selected_account = gnc_import_select_account(NULL,
00841                            data.account_id, 1,
00842                            account_description, default_commodity,
00843                            default_type, NULL, NULL);
00844         g_free(account_description);
00845     }
00846     else
00847     {
00848         PERR("account online ID not available");
00849     }
00850 
00851     return 0;
00852 }
00853 
00854 double ofx_get_investment_amount(const struct OfxTransactionData* data)
00855 {
00856     g_assert(data);
00857     switch (data->invtransactiontype)
00858     {
00859     case OFX_BUYDEBT:
00860     case OFX_BUYMF:
00861     case OFX_BUYOPT:
00862     case OFX_BUYOTHER:
00863     case OFX_BUYSTOCK:
00864         return fabs(data->amount);
00865     case OFX_SELLDEBT:
00866     case OFX_SELLMF:
00867     case OFX_SELLOPT:
00868     case OFX_SELLOTHER:
00869     case OFX_SELLSTOCK:
00870         return -1 * fabs(data->amount);
00871     default:
00872         return -1 * data->amount;
00873     }
00874 }
00875 
00876 void gnc_file_ofx_import (void)
00877 {
00878     extern int ofx_PARSER_msg;
00879     extern int ofx_DEBUG_msg;
00880     extern int ofx_WARNING_msg;
00881     extern int ofx_ERROR_msg;
00882     extern int ofx_INFO_msg;
00883     extern int ofx_STATUS_msg;
00884     char *selected_filename;
00885     char *default_dir;
00886     LibofxContextPtr libofx_context = libofx_get_new_context();
00887 
00888     ofx_PARSER_msg = false;
00889     ofx_DEBUG_msg = false;
00890     ofx_WARNING_msg = true;
00891     ofx_ERROR_msg = true;
00892     ofx_INFO_msg = true;
00893     ofx_STATUS_msg = false;
00894 
00895     DEBUG("gnc_file_ofx_import(): Begin...\n");
00896 
00897     default_dir = gnc_get_default_directory(GCONF_SECTION);
00898     selected_filename = gnc_file_dialog(_("Select an OFX/QFX file to process"),
00899                                         NULL,
00900                                         default_dir,
00901                                         GNC_FILE_DIALOG_IMPORT);
00902     g_free(default_dir);
00903 
00904     if (selected_filename != NULL)
00905     {
00906 #ifdef G_OS_WIN32
00907         gchar *conv_name;
00908 #endif
00909 
00910         /* Remember the directory as the default. */
00911         default_dir = g_path_get_dirname(selected_filename);
00912         gnc_set_default_directory(GCONF_SECTION, default_dir);
00913         g_free(default_dir);
00914 
00915         /*strncpy(file,selected_filename, 255);*/
00916         DEBUG("Filename found: %s", selected_filename);
00917 
00918         /* Create the Generic transaction importer GUI. */
00919         gnc_ofx_importer_gui = gnc_gen_trans_list_new(NULL, NULL, FALSE, 42);
00920 
00921         /* Look up the needed gconf options */
00922         auto_create_commodity =
00923             gnc_gconf_get_bool(GCONF_IMPORT_SECTION, "auto_create_commodity", NULL);
00924 
00925         /* Initialize libofx */
00926 
00927         /*ofx_set_statement_cb(libofx_context, ofx_proc_statement_cb, 0);*/
00928         ofx_set_account_cb(libofx_context, ofx_proc_account_cb, 0);
00929         ofx_set_transaction_cb(libofx_context, ofx_proc_transaction_cb, 0);
00930         ofx_set_security_cb(libofx_context, ofx_proc_security_cb, 0);
00931         /*ofx_set_status_cb(libofx_context, ofx_proc_status_cb, 0);*/
00932 
00933 #ifdef G_OS_WIN32
00934         conv_name = g_win32_locale_filename_from_utf8(selected_filename);
00935         g_free(selected_filename);
00936         selected_filename = conv_name;
00937 #endif
00938 
00939         DEBUG("Opening selected file");
00940         libofx_proc_file(libofx_context, selected_filename, AUTODETECT);
00941         g_free(selected_filename);
00942     }
00943 
00944     if (ofx_created_commodites)
00945     {
00946         /* FIXME: Present some result window about the newly created
00947          * commodities */
00948         g_warning("Created %d new commodities during import", g_list_length(ofx_created_commodites));
00949         g_list_free(ofx_created_commodites);
00950         ofx_created_commodites = NULL;
00951     }
00952     else
00953     {
00954         //g_warning("No new commodities created");
00955     }
00956 }
00957 
00958 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines