29 #include <glib/gi18n.h> 36 #include <libofx/libofx.h> 44 #include "engine-helpers.h" 54 #include "dialog-utils.h" 55 #include "window-reconcile.h" 59 #include <unordered_map> 61 #define GNC_PREFS_GROUP "dialogs.import.ofx" 62 #define GNC_PREF_AUTO_COMMODITY "auto-create-commodity" 64 static QofLogModule log_module = GNC_MOD_IMPORT;
71 static gboolean auto_create_commodity = FALSE;
72 static Account *ofx_parent_account = NULL;
74 typedef struct OfxTransactionData OfxTransactionData;
77 typedef struct _ofx_info
80 GNCImportMainMatcher *gnc_ofx_importer_gui;
82 Account *last_investment_account;
84 gint num_trans_processed;
86 gboolean run_reconcile;
92 static void runMatcher(
ofx_info* info,
char * selected_filename, gboolean go_to_next_file);
101 static const char *PROP_OFX_INCOME_ACCOUNT =
"ofx-income-account";
104 get_associated_income_account(
const Account* investment_account)
108 g_assert(investment_account);
110 PROP_OFX_INCOME_ACCOUNT, &income_guid,
113 gnc_account_get_book(investment_account));
114 guid_free (income_guid);
119 set_associated_income_account(
Account* investment_account,
122 const GncGUID * income_acc_guid;
124 g_assert(investment_account);
125 g_assert(income_account);
130 PROP_OFX_INCOME_ACCOUNT, income_acc_guid,
135 int ofx_proc_statement_cb (
struct OfxStatementData data,
void * statement_user_data);
136 int ofx_proc_security_cb (
const struct OfxSecurityData data,
void * security_user_data);
137 int ofx_proc_transaction_cb (OfxTransactionData data,
void *user_data);
138 int ofx_proc_account_cb (
struct OfxAccountData data,
void * account_user_data);
139 static double ofx_get_investment_amount (
const OfxTransactionData* data);
141 static const gchar *gnc_ofx_ttype_to_string(TransactionType t)
146 return "Generic credit";
148 return "Generic debit";
150 return "Interest earned or paid (Note: Depends on signage of amount)";
156 return "Service charge";
160 return "ATM debit or credit (Note: Depends on signage of amount)";
162 return "Point of sale debit or credit (Note: Depends on signage of amount)";
168 return "Electronic payment";
170 return "Cash withdrawal";
172 return "Direct deposit";
173 case OFX_DIRECTDEBIT:
174 return "Merchant initiated debit";
176 return "Repeating payment/standing order";
180 return "Unknown transaction type";
184 static const gchar *gnc_ofx_invttype_to_str(InvTransactionType t)
189 return "BUYDEBT (Buy debt security)";
191 return "BUYMF (Buy mutual fund)";
193 return "BUYOPT (Buy option)";
195 return "BUYOTHER (Buy other security type)";
197 return "BUYSTOCK (Buy stock))";
199 return "CLOSUREOPT (Close a position for an option)";
201 return "INCOME (Investment income is realized as cash into the investment account)";
203 return "INVEXPENSE (Misc investment expense that is associated with a specific security)";
205 return "JRNLFUND (Journaling cash holdings between subaccounts within the same investment account)";
206 case OFX_MARGININTEREST:
207 return "MARGININTEREST (Margin interest expense)";
209 return "REINVEST (Reinvestment of income)";
211 return "RETOFCAP (Return of capital)";
213 return "SELLDEBT (Sell debt security. Used when debt is sold, called, or reached maturity)";
215 return "SELLMF (Sell mutual fund)";
217 return "SELLOPT (Sell option)";
219 return "SELLOTHER (Sell other type of security)";
221 return "SELLSTOCK (Sell stock)";
223 return "SPLIT (Stock or mutial fund split)";
225 return "TRANSFER (Transfer holdings in and out of the investment account)";
226 #ifdef HAVE_LIBOFX_VERSION_0_10 227 case OFX_INVBANKTRAN:
228 return "Transfer cash in and out of the investment account";
231 return "ERROR, this investment transaction type is unknown. This is a bug in ofxdump";
237 sanitize_string (gchar* str)
240 const int length = -1;
241 while (!g_utf8_validate (str, length, (
const gchar **)(&inval)))
246 int ofx_proc_security_cb(
const struct OfxSecurityData data,
void * security_user_data)
249 char* default_fullname = NULL;
250 char* default_mnemonic = NULL;
252 if (data.unique_id_valid)
256 if (data.secname_valid)
260 if (data.ticker_valid)
265 if (auto_create_commodity)
267 gnc_commodity *commodity =
275 QofBook *book = gnc_get_current_book();
276 gnc_quote_source *source;
277 gint source_selection = 0;
278 char *commodity_namespace = NULL;
281 if (data.unique_id_type_valid)
286 g_warning(
"Creating a new commodity, cusip=%s", cusip);
296 gnc_commodity_begin_edit(commodity);
300 gnc_commodity_commit_edit(commodity);
305 g_free (commodity_namespace);
318 g_free (default_mnemonic);
319 g_free (default_fullname);
323 static void gnc_ofx_set_split_memo(
const OfxTransactionData* data, Split *split)
330 if (data->name_valid)
334 else if (data->memo_valid)
339 static gnc_numeric gnc_ofx_numeric_from_double(
double value,
const gnc_commodity *commodity)
345 static gnc_numeric gnc_ofx_numeric_from_double_txn(
double value,
const Transaction* txn)
352 static Account *gnc_ofx_new_account(GtkWindow* parent,
354 const gnc_commodity * account_commodity,
359 GList * valid_types = NULL;
362 g_assert(account_commodity);
363 g_assert(parent_account);
369 g_list_prepend(valid_types,
370 GINT_TO_POINTER(new_account_default_type));
375 g_list_prepend(valid_types,
383 g_list_free(valid_types);
411 if (tzname[1][0] !=
' ' && !stm.tm_isdst)
414 if (daylight && !stm.tm_isdst)
422 set_transaction_dates(Transaction *transaction, OfxTransactionData *data)
433 if (data->date_posted_valid && (data->date_posted != 0))
436 data->date_posted = fix_ofx_bug_39 (data->date_posted);
439 else if (data->date_initiated_valid && (data->date_initiated != 0))
442 data->date_initiated = fix_ofx_bug_39 (data->date_initiated);
455 fill_transaction_description(Transaction *transaction, OfxTransactionData *data)
458 if (data->name_valid)
462 else if (data->memo_valid)
469 fill_transaction_notes(Transaction *transaction, OfxTransactionData *data)
472 char *notes = g_strdup_printf(
"OFX ext. info: ");
474 if (data->transactiontype_valid)
477 notes = g_strdup_printf(
"%s%s%s", tmp,
"|Trans type:",
478 gnc_ofx_ttype_to_string(data->transactiontype));
482 if (data->invtransactiontype_valid)
485 notes = g_strdup_printf(
"%s%s%s", tmp,
"|Investment Trans type:",
486 gnc_ofx_invttype_to_str(data->invtransactiontype));
489 if (data->memo_valid && data->name_valid)
492 notes = g_strdup_printf(
"%s%s%s", tmp,
"|Memo:", data->memo);
495 if (data->date_funds_available_valid)
498 time64 time = data->date_funds_available;
502 notes = g_strdup_printf(
"%s%s%s", tmp,
503 "|Date funds available:", dest_string);
506 if (data->server_transaction_id_valid)
509 notes = g_strdup_printf(
"%s%s%s", tmp,
510 "|Server trans ID (conf. number):",
511 sanitize_string (data->server_transaction_id));
514 if (data->standard_industrial_code_valid)
517 notes = g_strdup_printf(
"%s%s%ld", tmp,
518 "|Standard Industrial Code:",
519 data->standard_industrial_code);
523 if (data->payee_id_valid)
526 notes = g_strdup_printf(
"%s%s%s", tmp,
"|Payee ID:",
527 sanitize_string (data->payee_id));
533 if (data->fi_id_corrected_valid)
536 PERR(
"WRITEME: GnuCash ofx_proc_transaction(): WARNING: This transaction corrected a previous transaction, but we created a new one instead!\n");
537 notes = g_strdup_printf(
"%s%s%s%s", tmp,
538 "|This corrects transaction #",
539 sanitize_string (data->fi_id_corrected),
540 "but GnuCash didn't process the correction!");
549 process_bank_transaction(Transaction *transaction,
Account *import_account,
550 OfxTransactionData *data,
ofx_info *info)
553 gnc_numeric gnc_amount;
555 double amount = data->amount;
556 #ifdef HAVE_LIBOFX_VERSION_0_10 557 if (data->currency_ratio_valid && data->currency_ratio != 0)
558 amount *= data->currency_ratio;
561 DEBUG(
"Adding split; Ordinary banking transaction, money flows from or into the source account");
565 gnc_amount = gnc_ofx_numeric_from_double_txn(amount, transaction);
569 if (data->check_number_valid)
575 const char *num_value =
576 strcasecmp (data->check_number,
"null") == 0 ?
"" :
578 gnc_set_num_action(transaction, split, num_value, NULL);
580 else if (data->reference_number_valid)
582 const char *num_value =
583 strcasecmp (data->reference_number,
"null") == 0 ?
"" :
585 gnc_set_num_action(transaction, split, num_value, NULL);
589 if (data->memo_valid)
593 if (data->fi_id_valid)
595 gnc_import_set_split_online_id(split,
596 sanitize_string (data->fi_id));
602 gnc_commodity *commodity;
609 create_investment_subaccount(GtkWindow *parent,
Account* parent_acct,
614 gnc_ofx_new_account(parent,
619 if (investment_account)
621 gnc_import_set_acc_online_id(investment_account, inv_data->online_id);
622 inv_data->choosing = FALSE;
623 ofx_parent_account = parent_acct;
627 ofx_parent_account = NULL;
629 return investment_account;
633 continue_account_selection(GtkWidget* parent,
Account* account,
634 gnc_commodity* commodity)
636 gboolean keep_going =
638 GTK_WINDOW (parent), TRUE,
639 "The chosen account \"%s\" does not have the correct " 640 "currency/security \"%s\" (it has \"%s\" instead). " 641 "This account cannot be used. " 642 "Do you want to choose again?",
647 gnc_import_set_acc_online_id(account,
"");
652 choose_investment_account_helper(OfxTransactionData *data,
ofx_info *info,
655 Account *investment_account, *parent_account;
658 parent_account = info->last_investment_account;
660 parent_account = ofx_parent_account;
665 TRUE, inv_data->acct_text,
667 parent_account, &inv_data->choosing);
668 if (investment_account &&
673 if (!ofx_parent_account && parent_account &&
677 ofx_parent_account = parent_account;
679 info->last_investment_account = investment_account;
680 return investment_account;
684 if (auto_create_commodity && ofx_parent_account)
687 create_investment_subaccount(GTK_WINDOW(info->parent),
696 continue_account_selection(GTK_WIDGET(info->parent),
697 investment_account, inv_data->commodity);
698 investment_account = NULL;
701 return investment_account;
705 choose_investment_account(OfxTransactionData *data,
ofx_info *info,
706 gnc_commodity *commodity)
708 Account* investment_account = NULL;
716 inv_data.acct_text = g_strdup_printf(
717 _(
"Stock account for security \"%s\""),
718 sanitize_string (data->security_data_ptr->secname));
721 g_strdup_printf(
"%s%s", data->account_id, data->unique_id);
724 while (!investment_account && inv_data.choosing)
725 investment_account = choose_investment_account_helper(data, info,
727 if (!investment_account)
729 PERR(
"No investment account found for text: %s\n", inv_data.acct_text);
731 g_free (inv_data.acct_text);
732 g_free (inv_data.online_id);
734 return investment_account;
738 choose_income_account(
Account* investment_account, Transaction *transaction,
739 OfxTransactionData *data,
ofx_info *info)
741 Account *income_account = NULL;
742 DEBUG(
"Now let's find an account for the destination split");
744 get_associated_income_account(investment_account);
746 if (income_account == NULL)
748 char *income_account_text;
750 DEBUG(
"Couldn't find an associated income account");
754 income_account_text = g_strdup_printf(
755 _(
"Income account for security \"%s\""),
756 sanitize_string (data->security_data_ptr->secname));
759 income_account_text, currency,
761 info->last_income_account, NULL);
763 if (income_account != NULL)
765 info->last_income_account = income_account;
766 set_associated_income_account(investment_account,
768 DEBUG(
"KVP written");
773 DEBUG(
"Found at least one associated income account");
776 return income_account;
780 add_investment_split(Transaction* transaction,
Account* account,
781 OfxTransactionData *data)
784 QofBook *book = gnc_account_get_book(account);
785 gnc_numeric gnc_amount, gnc_units;
787 DEBUG(
"Adding investment split; Money flows from or into the stock account");
793 gnc_ofx_numeric_from_double_txn(ofx_get_investment_amount(data),
795 gnc_units = gnc_ofx_numeric_from_double (data->units, commodity);
800 if (data->check_number_valid)
802 gnc_set_num_action(transaction, split, data->check_number, NULL);
804 else if (data->reference_number_valid)
806 gnc_set_num_action(transaction, split,
807 data->reference_number, NULL);
809 if (data->security_data_ptr->memo_valid)
812 sanitize_string (data->security_data_ptr->memo));
814 if (data->fi_id_valid &&
818 gnc_import_set_split_online_id(split,
819 sanitize_string (data->fi_id));
824 add_currency_split(Transaction *transaction,
Account* account,
825 double amount, OfxTransactionData *data)
828 QofBook *book = gnc_account_get_book(account);
829 gnc_numeric gnc_amount;
834 gnc_amount = gnc_ofx_numeric_from_double_txn(amount, transaction);
838 gnc_ofx_set_split_memo(data, split);
839 if (data->fi_id_valid)
840 gnc_import_set_split_online_id (split, sanitize_string (data->fi_id));
849 process_investment_transaction(Transaction *transaction,
Account *import_account,
850 OfxTransactionData *data,
ofx_info *info)
852 Account *investment_account = NULL;
853 Account *income_account = NULL;
854 gnc_commodity *investment_commodity;
855 double amount = data->amount;
857 g_return_if_fail(data->invtransactiontype_valid);
863 if (data->invtransactiontype != OFX_REINVEST)
865 DEBUG(
"Adding investment cash split.");
866 add_currency_split(transaction, import_account,
867 -ofx_get_investment_amount(data), data);
872 if (!investment_commodity)
874 PERR(
"Commodity not found for the investment transaction");
877 investment_account = choose_investment_account(data, info,
878 investment_commodity);
880 if (!investment_account)
882 PERR(
"Failed to determine an investment asset account.");
886 if (data->invtransactiontype != OFX_INCOME)
888 if (data->unitprice_valid && data->units_valid)
889 add_investment_split(transaction, investment_account, data);
891 PERR(
"Unable to add investment split, unit price or units were invalid.");
894 if (!(data->invtransactiontype == OFX_REINVEST
895 || data->invtransactiontype == OFX_INCOME))
899 #ifdef HAVE_LIBOFX_VERSION_0_10 900 if (data->currency_ratio_valid && data->currency_ratio != 0)
901 amount *= data->currency_ratio;
903 income_account = choose_income_account(investment_account,
904 transaction, data, info);
905 g_return_if_fail(income_account);
907 DEBUG(
"Adding investment income split.");
908 if (data->invtransactiontype == OFX_REINVEST)
909 add_currency_split(transaction, income_account, amount, data);
911 add_currency_split(transaction, income_account, -amount, data);
914 int ofx_proc_transaction_cb(OfxTransactionData data,
void *user_data)
917 gnc_commodity *currency = NULL;
919 Transaction *transaction;
922 g_assert(info->parent);
924 if (!data.amount_valid)
926 PERR(
"The transaction doesn't have a valid amount");
930 if (!data.account_id_valid)
932 PERR(
"account ID for this transaction is unavailable!");
941 info->last_import_account, NULL);
942 if (import_account == NULL)
944 PERR(
"Unable to find account for id %s", data.account_id);
947 info->last_import_account = import_account;
953 if (data.check_number_valid)
955 if (data.reference_number_valid)
959 book = gnc_account_get_book(import_account);
963 set_transaction_dates(transaction, &data);
964 fill_transaction_description(transaction, &data);
965 fill_transaction_notes(transaction, &data);
967 if (data.account_ptr && data.account_ptr->currency_valid)
969 DEBUG(
"Currency from libofx: %s", data.account_ptr->currency);
970 currency = gnc_commodity_table_lookup( gnc_get_current_commodities (),
971 GNC_COMMODITY_NS_CURRENCY,
972 data.account_ptr->currency);
976 DEBUG(
"Currency from libofx unavailable, defaulting to account's default");
982 if (!data.invtransactiontype_valid
983 #ifdef HAVE_LIBOFX_VERSION_0_10
984 || data.invtransactiontype == OFX_INVBANKTRAN
987 process_bank_transaction(transaction, import_account, &data, info);
988 else if (data.unique_id_valid
989 && data.security_data_valid
990 && data.security_data_ptr != NULL
991 && data.security_data_ptr->secname_valid)
992 process_investment_transaction(transaction, import_account,
996 PERR(
"Unsupported OFX transaction type.");
1005 DEBUG(
"%d splits sent to the importer gui",
1007 info->trans_list = g_list_prepend (info->trans_list, transaction);
1011 PERR(
"No splits in transaction (missing account?), ignoring.");
1016 info->num_trans_processed += 1;
1021 int ofx_proc_statement_cb (
struct OfxStatementData data,
void * statement_user_data)
1024 struct OfxStatementData *statement = g_new (
struct OfxStatementData, 1);
1026 info->statement = g_list_prepend (info->statement, statement);
1031 int ofx_proc_account_cb(
struct OfxAccountData data,
void * account_user_data)
1033 gnc_commodity_table * commodity_table;
1034 gnc_commodity * default_commodity;
1036 gchar * account_description;
1037 GtkWidget * main_widget;
1041 gboolean new_book = gnc_is_new_book();
1045 const gchar * account_type_name = _(
"Unknown OFX account");
1047 if (data.account_id_valid)
1049 commodity_table = gnc_get_current_commodities ();
1050 if (data.currency_valid)
1052 DEBUG(
"Currency from libofx: %s", data.currency);
1053 default_commodity = gnc_commodity_table_lookup(commodity_table,
1054 GNC_COMMODITY_NS_CURRENCY,
1059 default_commodity = NULL;
1062 if (data.account_type_valid)
1064 switch (data.account_type)
1066 case OfxAccountData::OFX_CHECKING:
1068 account_type_name = _(
"Unknown OFX checking account");
1070 case OfxAccountData::OFX_SAVINGS:
1072 account_type_name = _(
"Unknown OFX savings account");
1074 case OfxAccountData::OFX_MONEYMRKT:
1076 account_type_name = _(
"Unknown OFX money market account");
1078 case OfxAccountData::OFX_CREDITLINE:
1080 account_type_name = _(
"Unknown OFX credit line account");
1082 case OfxAccountData::OFX_CMA:
1085 account_type_name = _(
"Unknown OFX CMA account");
1087 case OfxAccountData::OFX_CREDITCARD:
1089 account_type_name = _(
"Unknown OFX credit card account");
1091 case OfxAccountData::OFX_INVESTMENT:
1093 account_type_name = _(
"Unknown OFX investment account");
1096 PERR(
"WRITEME: ofx_proc_account() This is an unknown account type!");
1112 account_description = g_strdup_printf (
1124 if (gtk_widget_get_realized (main_widget))
1125 parent = main_widget;
1127 parent = GTK_WIDGET(gtk_window_get_transient_for (GTK_WINDOW(main_widget)));
1131 account_description, default_commodity,
1132 default_type, NULL, NULL);
1136 info->last_import_account = account;
1139 g_free(account_description);
1143 PERR(
"account online ID not available");
1149 double ofx_get_investment_amount(
const OfxTransactionData* data)
1151 double amount = data->amount;
1152 #ifdef HAVE_LIBOFX_VERSION_0_10 1153 if (data->invtransactiontype == OFX_INVBANKTRAN)
1155 if (data->currency_ratio_valid && data->currency_ratio != 0)
1156 amount *= data->currency_ratio;
1159 switch (data->invtransactiontype)
1166 return fabs(amount);
1172 return -1 * fabs(amount);
1180 gnc_file_ofx_import_process_file (
ofx_info* info);
1184 gnc_ofx_process_next_file (GtkDialog *dialog, gpointer user_data)
1188 g_list_free_full (info->statement, g_free);
1189 info->statement = NULL;
1192 info->file_list = g_slist_delete_link (info->file_list, info->file_list);
1193 if (info->file_list)
1194 gnc_file_ofx_import_process_file (info);
1203 gnc_ofx_on_match_click (GtkDialog *dialog, gint response_id, gpointer user_data)
1207 info->response = response_id;
1211 gnc_ofx_match_done (GtkDialog *dialog, gpointer user_data)
1218 if (info->response != GTK_RESPONSE_OK)
1221 if (info->trans_list)
1228 runMatcher (info, NULL,
true);
1232 if (info->run_reconcile && info->statement && info->statement->data)
1234 auto statement =
static_cast<struct OfxStatementData*
>(info->statement->data);
1237 statement->account_id,
1239 if (account && statement->ledger_balance_valid)
1245 RecnWindow* rec_window = recnWindowWithBalance (GTK_WIDGET (info->parent), account, value,
1246 statement->ledger_balance_date);
1249 g_signal_connect (G_OBJECT (gnc_ui_reconcile_window_get_window (rec_window)),
"destroy",
1250 G_CALLBACK (gnc_ofx_match_done), info);
1251 if (info->statement->next)
1252 info->statement = info->statement->next;
1255 g_list_free_full (g_list_first (info->statement), g_free);
1256 info->statement = NULL;
1263 if (info->statement && info->statement->next)
1265 info->statement = info->statement->next;
1266 gnc_ofx_match_done (dialog, user_data);
1271 g_list_free_full (g_list_first (info->statement), g_free);
1272 info->statement = NULL;
1275 gnc_ofx_process_next_file (NULL, info);
1281 reconcile_when_close_toggled_cb (GtkToggleButton *togglebutton,
ofx_info* info)
1283 info->run_reconcile = gtk_toggle_button_get_active (togglebutton);
1287 make_date_amount_key (
const Split* split)
1289 std::ostringstream ss;
1296 runMatcher (
ofx_info* info,
char * selected_filename, gboolean go_to_next_file)
1298 GtkWindow *parent = info->parent;
1299 GList* trans_list_remain = NULL;
1300 std::unordered_map <std::string,Account*> trans_map;
1306 info->num_trans_processed = 0;
1308 gnc_window_show_progress (_(
"Removing duplicate transactions…"), 100);
1315 for(GList* node = info->trans_list; node; node=node->next)
1317 auto trans =
static_cast<Transaction*
>(node->data);
1320 auto date_amount_key = make_date_amount_key (split);
1322 auto it = trans_map.find (date_amount_key);
1323 if (it != trans_map.end() && it->second != account)
1334 DEBUG (
"Potential transfer %s %s %s %s\n", name1, name2, amtstr, datestr);
1340 trans_list_remain = g_list_prepend (trans_list_remain, trans);
1344 trans_map[date_amount_key] = account;
1346 info->num_trans_processed ++;
1349 g_list_free (info->trans_list);
1350 info->trans_list = g_list_reverse (trans_list_remain);
1351 DEBUG(
"%d transactions remaining to process in file %s\n", g_list_length (info->trans_list),
1354 gnc_window_show_progress (
nullptr, -1);
1360 if (info->num_trans_processed)
1362 gnc_info_dialog (parent, _(
"While importing transactions from OFX file '%s' found %d previously imported transactions, no new transactions."),
1364 info->num_trans_processed);
1366 info->response = GTK_RESPONSE_OK;
1367 gnc_ofx_match_done (NULL, info);
1380 G_CALLBACK (gnc_ofx_match_done),
1386 G_CALLBACK (gnc_ofx_on_match_click),
1394 info->statement != NULL,
1395 info->run_reconcile);
1401 (info->gnc_ofx_importer_gui)),
1403 G_CALLBACK (reconcile_when_close_toggled_cb),
1410 gnc_file_ofx_import_process_file (
ofx_info* info)
1412 LibofxContextPtr libofx_context;
1413 char* filename = NULL;
1414 char * selected_filename = NULL;
1415 GtkWindow *parent = info->parent;
1417 if (info->file_list == NULL)
1420 filename =
static_cast<char*
>(info->file_list->data);
1421 libofx_context = libofx_get_new_context();
1424 selected_filename = g_win32_locale_filename_from_utf8 (filename);
1427 selected_filename = filename;
1429 DEBUG(
"Filename found: %s", selected_filename);
1432 info->num_trans_processed = 0;
1433 info->statement = NULL;
1436 ofx_set_statement_cb (libofx_context, ofx_proc_statement_cb, info);
1437 ofx_set_account_cb (libofx_context, ofx_proc_account_cb, info);
1438 ofx_set_transaction_cb (libofx_context, ofx_proc_transaction_cb, info);
1439 ofx_set_security_cb (libofx_context, ofx_proc_security_cb, info);
1444 libofx_proc_file (libofx_context, selected_filename, AUTODETECT);
1447 libofx_free_context(libofx_context);
1448 runMatcher(info, selected_filename,
true);
1449 g_free(selected_filename);
1455 extern int ofx_PARSER_msg;
1456 extern int ofx_DEBUG_msg;
1457 extern int ofx_WARNING_msg;
1458 extern int ofx_ERROR_msg;
1459 extern int ofx_INFO_msg;
1460 extern int ofx_STATUS_msg;
1461 GSList* selected_filenames = NULL;
1463 GList *filters = NULL;
1465 GtkFileFilter* filter = gtk_file_filter_new ();
1468 ofx_PARSER_msg =
false;
1469 ofx_DEBUG_msg =
false;
1470 ofx_WARNING_msg =
true;
1471 ofx_ERROR_msg =
true;
1472 ofx_INFO_msg =
true;
1473 ofx_STATUS_msg =
false;
1475 DEBUG(
"gnc_file_ofx_import(): Begin...\n");
1477 default_dir = gnc_get_default_directory(GNC_PREFS_GROUP);
1478 gtk_file_filter_set_name (filter, _(
"Open/Quicken Financial Exchange file (*.ofx, *.qfx)"));
1479 gtk_file_filter_add_pattern (filter,
"*.[oqOQ][fF][xX]");
1480 filters = g_list_prepend( filters, filter );
1482 selected_filenames = gnc_file_dialog_multi (parent,
1483 _(
"Select one or multiple OFX/QFX file(s) to process"),
1486 GNC_FILE_DIALOG_IMPORT);
1487 g_free(default_dir);
1489 if (selected_filenames)
1492 default_dir = g_path_get_dirname(static_cast<char*>(selected_filenames->data));
1493 gnc_set_default_directory(GNC_PREFS_GROUP, default_dir);
1494 g_free(default_dir);
1497 auto_create_commodity =
1500 DEBUG(
"Opening selected file(s)");
1503 info->num_trans_processed = 0;
1504 info->statement = NULL;
1505 info->last_investment_account = NULL;
1506 info->last_import_account = NULL;
1507 info->last_income_account = NULL;
1508 info->parent = parent;
1509 info->run_reconcile = FALSE;
1510 info->file_list = selected_filenames;
1511 info->trans_list = NULL;
1514 gnc_file_ofx_import_process_file (info);
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Add a new commodity to the commodity table.
Account * gnc_account_get_parent(const Account *acc)
This routine returns a pointer to the parent of the specified account.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Depending on the base_currency, set either the value or the amount of this split or both: If the base...
void gnc_gen_trans_list_show_reconcile_after_close_button(GNCImportMainMatcher *info, bool reconcile_after_close, bool active)
Show and set the reconcile after close check button.
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
gboolean gnc_account_is_root(const Account *account)
This routine indicates whether the specified account is the root node of an account tree...
This quote source pulls from a single specific web site.
This file contains the functions to present a gui to the user for creating a new account or editing a...
gnc_numeric double_to_gnc_numeric(double in, gint64 denom, gint how)
Convert a floating-point number to a gnc_numeric.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
void gnc_gen_trans_list_show_all(GNCImportMainMatcher *info)
Shows widgets.
gnc_commodity * gnc_import_select_commodity(const char *cusip, gboolean ask_on_unknown, const char *default_fullname, const char *default_mnemonic)
Must be called with a string containing a unique identifier for the commodity.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
utility functions for the GnuCash UI
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
#define DEBUG(format, args...)
Print a debugging message.
Functions that are supported by all types of windows.
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
#define GNC_PREFS_GROUP_IMPORT
The preferences used by the importer.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
Transaction matcher main window.
Account * gnc_import_select_account(GtkWidget *parent, const gchar *account_online_id_value, gboolean prompt_on_no_match, const gchar *account_human_description, const gnc_commodity *new_account_default_commodity, GNCAccountType new_account_default_type, Account *default_selection, gboolean *ok_pressed)
Must be called with a string containing a unique identifier for the account.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Ofx import module interface.
Generic and very flexible account matcher/picker.
gchar * gnc_numeric_to_string(gnc_numeric n)
Convert to string.
gnc_quote_source * gnc_quote_source_lookup_by_ti(QuoteSourceType type, gint index)
Given the type/index of a quote source, find the data structure identified by this pair...
#define PERR(format, args...)
Log a serious error.
void gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
Set the automatic price quote flag for the specified commodity, based on user input.
void gnc_gen_trans_list_add_trans(GNCImportMainMatcher *gui, Transaction *trans)
Add a newly imported Transaction to the Transaction Importer.
struct tm * gnc_localtime_r(const time64 *secs, struct tm *time)
fill out a time struct from a 64-bit time value adjusted for the current time zone.
void gnc_file_ofx_import(GtkWindow *parent)
The gnc_file_ofx_import() routine will pop up a standard file selection dialogue asking the user to p...
gnc_numeric gnc_numeric_reduce(gnc_numeric in)
Return input after reducing it by Greater Common Factor (GCF) elimination.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
bool gnc_gen_trans_list_empty(GNCImportMainMatcher *info)
Checks whether there are no transactions to match.
gboolean qof_log_check(QofLogModule domain, QofLogLevel level)
Check to see if the given log_module is configured to log at the given log_level. ...
Stock accounts will typically be shown in registers which show three columns: price, number of shares, and value.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
#define xaccAccountGetGUID(X)
char * qof_print_date(time64 secs)
Convenience; calls through to qof_print_date_dmy_buff().
void gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
Set the automatic price quote source for the specified commodity.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Account handling public routines.
GtkWidget * gnc_gen_trans_list_get_reconcile_after_close_button(GNCImportMainMatcher *info)
Returns the reconcile after close check button.
gboolean xaccAccountTypesCompatible(GNCAccountType parent_type, GNCAccountType child_type)
Return TRUE if accounts of type parent_type can have accounts of type child_type as children...
GtkWidget * gnc_gen_trans_list_widget(GNCImportMainMatcher *info)
Returns the widget of this dialog.
Income accounts are used to denote income.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Create a new commodity.
line of credit – don't use this for now, see NUM_ACCOUNT_TYPES
GNCImportMainMatcher * gnc_gen_trans_list_new(GtkWidget *parent, const gchar *heading, bool all_from_same_account, gint match_date_hardlimit, bool show_all)
Create a new generic transaction dialog window and return it.
The bank account type denotes a savings or checking account held at a bank.
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Retrieve the full name for the specified commodity.
void gnc_utf8_strip_invalid(gchar *str)
Strip any non-UTF-8 characters from a string.
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
asset (and liability) accounts indicate generic, generalized accounts that are none of the above...
All type declarations for the whole Gnucash engine.
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Split * xaccMallocSplit(QofBook *book)
Constructor.
Generic api to store and retrieve preferences.
gchar * gnc_utf8_strip_invalid_strdup(const gchar *str)
Returns a newly allocated copy of the given string but with any non-UTF-8 character stripped from it...
Account * gnc_ui_new_accounts_from_name_with_defaults(GtkWindow *parent, const char *name, GList *valid_types, const gnc_commodity *default_commodity, Account *parent_acct)
Display a modal window for creating a new account.
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
void gnc_gen_trans_list_delete(GNCImportMainMatcher *info)
Deletes the given object.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
bank account type – don't use this for now, see NUM_ACCOUNT_TYPES
Utility functions for writing import modules.
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
time64 gnc_time(time64 *tbuf)
get the current time
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
const char * xaccAccountGetName(const Account *acc)
Get the account's name.
A Generic commodity matcher/picker.
API for Transactions and Splits (journal entries)
The type used to store guids in C.
char * gnc_time64_to_iso8601_buff(time64 time, char *buff)
The gnc_time64_to_iso8601_buff() routine takes the input UTC time64 value and prints it as an ISO-860...
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
The Credit card account is used to denote credit (e.g.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...