|
GnuCash 2.4.99
|
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(¤t_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
1.7.4