GnuCash  4.8a-134-g214de30c7+
gnc-ofx-import.c
1 /*******************************************************************\
2  * This program is free software; you can redistribute it and/or *
3  * modify it under the terms of the GNU General Public License as *
4  * published by the Free Software Foundation; either version 2 of *
5  * the License, or (at your option) any later version. *
6  * *
7  * This program is distributed in the hope that it will be useful, *
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
10  * GNU General Public License for more details. *
11  * *
12  * You should have received a copy of the GNU General Public License*
13  * along with this program; if not, contact: *
14  * *
15  * Free Software Foundation Voice: +1-617-542-5942 *
16  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
17  * Boston, MA 02110-1301, USA gnu@gnu.org *
18 \********************************************************************/
26 #include <config.h>
27 
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/time.h>
33 #include <math.h>
34 
35 #include <libofx/libofx.h>
36 #include "import-account-matcher.h"
38 #include "import-utilities.h"
39 #include "import-main-matcher.h"
40 
41 #include "Account.h"
42 #include "Transaction.h"
43 #include "engine-helpers.h"
44 #include "gnc-ofx-import.h"
45 #include "gnc-file.h"
46 #include "gnc-engine.h"
47 #include "gnc-ui-util.h"
48 #include "gnc-glib-utils.h"
49 #include "gnc-prefs.h"
50 #include "gnc-ui.h"
51 #include "dialog-account.h"
52 #include "dialog-utils.h"
53 #include "window-reconcile.h"
54 
55 #define GNC_PREFS_GROUP "dialogs.import.ofx"
56 #define GNC_PREF_AUTO_COMMODITY "auto-create-commodity"
57 
58 static QofLogModule log_module = GNC_MOD_IMPORT;
59 
60 /********************************************************************\
61  * gnc_file_ofx_import
62  * Entry point
63 \********************************************************************/
64 
65 static gboolean auto_create_commodity = FALSE;
66 static Account *ofx_parent_account = NULL;
67 // Structure we use to gather information about statement balance/account etc.
68 typedef struct _ofx_info
69 {
70  GtkWindow* parent;
71  GNCImportMainMatcher *gnc_ofx_importer_gui;
72  Account *last_import_account;
73  Account *last_investment_account;
74  Account *last_income_account;
75  gint num_trans_processed; // Number of transactions processed
76  struct OfxStatementData* statement; // Statement, if any
77  gboolean run_reconcile; // If TRUE the reconcile window is opened after matching.
78  GSList* file_list; // List of OFX files to import
79  GList* trans_list; // We store the processed ofx transactions here
80  gint response; // Response sent by the match gui
81 } ofx_info ;
82 
83 static void runMatcher(ofx_info* info, char * selected_filename, gboolean go_to_next_file);
84 
85 /*
86 int ofx_proc_status_cb(struct OfxStatusData data)
87 {
88  return 0;
89 }
90 */
91 
92 static const char *PROP_OFX_INCOME_ACCOUNT = "ofx-income-account";
93 
94 static Account*
95 get_associated_income_account(const Account* investment_account)
96 {
97  GncGUID *income_guid = NULL;
98  Account *acct = NULL;
99  g_assert(investment_account);
100  qof_instance_get (QOF_INSTANCE (investment_account),
101  PROP_OFX_INCOME_ACCOUNT, &income_guid,
102  NULL);
103  acct = xaccAccountLookup (income_guid,
104  gnc_account_get_book(investment_account));
105  guid_free (income_guid);
106  return acct;
107 }
108 
109 static void
110 set_associated_income_account(Account* investment_account,
111  const Account *income_account)
112 {
113  const GncGUID * income_acc_guid;
114 
115  g_assert(investment_account);
116  g_assert(income_account);
117 
118  income_acc_guid = xaccAccountGetGUID(income_account);
119  xaccAccountBeginEdit(investment_account);
120  qof_instance_set (QOF_INSTANCE (investment_account),
121  PROP_OFX_INCOME_ACCOUNT, income_acc_guid,
122  NULL);
123  xaccAccountCommitEdit(investment_account);
124 }
125 
126 int ofx_proc_statement_cb (struct OfxStatementData data, void * statement_user_data);
127 int ofx_proc_security_cb (const struct OfxSecurityData data, void * security_user_data);
128 int ofx_proc_transaction_cb (struct OfxTransactionData data, void *user_data);
129 int ofx_proc_account_cb (struct OfxAccountData data, void * account_user_data);
130 static double ofx_get_investment_amount (const struct OfxTransactionData* data);
131 
132 static const gchar *gnc_ofx_ttype_to_string(TransactionType t)
133 {
134  switch (t)
135  {
136  case OFX_CREDIT:
137  return "Generic credit";
138  case OFX_DEBIT:
139  return "Generic debit";
140  case OFX_INT:
141  return "Interest earned or paid (Note: Depends on signage of amount)";
142  case OFX_DIV:
143  return "Dividend";
144  case OFX_FEE:
145  return "FI fee";
146  case OFX_SRVCHG:
147  return "Service charge";
148  case OFX_DEP:
149  return "Deposit";
150  case OFX_ATM:
151  return "ATM debit or credit (Note: Depends on signage of amount)";
152  case OFX_POS:
153  return "Point of sale debit or credit (Note: Depends on signage of amount)";
154  case OFX_XFER:
155  return "Transfer";
156  case OFX_CHECK:
157  return "Check";
158  case OFX_PAYMENT:
159  return "Electronic payment";
160  case OFX_CASH:
161  return "Cash withdrawal";
162  case OFX_DIRECTDEP:
163  return "Direct deposit";
164  case OFX_DIRECTDEBIT:
165  return "Merchant initiated debit";
166  case OFX_REPEATPMT:
167  return "Repeating payment/standing order";
168  case OFX_OTHER:
169  return "Other";
170  default:
171  return "Unknown transaction type";
172  }
173 }
174 
175 static const gchar *gnc_ofx_invttype_to_str(InvTransactionType t)
176 {
177  switch (t)
178  {
179  case OFX_BUYDEBT:
180  return "BUYDEBT (Buy debt security)";
181  case OFX_BUYMF:
182  return "BUYMF (Buy mutual fund)";
183  case OFX_BUYOPT:
184  return "BUYOPT (Buy option)";
185  case OFX_BUYOTHER:
186  return "BUYOTHER (Buy other security type)";
187  case OFX_BUYSTOCK:
188  return "BUYSTOCK (Buy stock))";
189  case OFX_CLOSUREOPT:
190  return "CLOSUREOPT (Close a position for an option)";
191  case OFX_INCOME:
192  return "INCOME (Investment income is realized as cash into the investment account)";
193  case OFX_INVEXPENSE:
194  return "INVEXPENSE (Misc investment expense that is associated with a specific security)";
195  case OFX_JRNLFUND:
196  return "JRNLFUND (Journaling cash holdings between subaccounts within the same investment account)";
197  case OFX_MARGININTEREST:
198  return "MARGININTEREST (Margin interest expense)";
199  case OFX_REINVEST:
200  return "REINVEST (Reinvestment of income)";
201  case OFX_RETOFCAP:
202  return "RETOFCAP (Return of capital)";
203  case OFX_SELLDEBT:
204  return "SELLDEBT (Sell debt security. Used when debt is sold, called, or reached maturity)";
205  case OFX_SELLMF:
206  return "SELLMF (Sell mutual fund)";
207  case OFX_SELLOPT:
208  return "SELLOPT (Sell option)";
209  case OFX_SELLOTHER:
210  return "SELLOTHER (Sell other type of security)";
211  case OFX_SELLSTOCK:
212  return "SELLSTOCK (Sell stock)";
213  case OFX_SPLIT:
214  return "SPLIT (Stock or mutial fund split)";
215  case OFX_TRANSFER:
216  return "TRANSFER (Transfer holdings in and out of the investment account)";
217 #ifdef HAVE_LIBOFX_VERSION_0_10
218  case OFX_INVBANKTRAN:
219  return "Transfer cash in and out of the investment account";
220 #endif
221  default:
222  return "ERROR, this investment transaction type is unknown. This is a bug in ofxdump";
223  }
224 
225 }
226 
227 static gchar*
228 sanitize_string (gchar* str)
229 {
230  gchar *inval;
231  const int length = -1; /*Assumes str is null-terminated */
232  while (!g_utf8_validate (str, length, (const gchar **)(&inval)))
233  *inval = '@';
234  return str;
235 }
236 
237 int ofx_proc_security_cb(const struct OfxSecurityData data, void * security_user_data)
238 {
239  char* cusip = NULL;
240  char* default_fullname = NULL;
241  char* default_mnemonic = NULL;
242 
243  ofx_info* info = (ofx_info*) security_user_data;
244 
245  if (data.unique_id_valid)
246  {
247  cusip = gnc_utf8_strip_invalid_strdup (data.unique_id);
248  }
249  if (data.secname_valid)
250  {
251  default_fullname = gnc_utf8_strip_invalid_strdup (data.secname);
252  }
253  if (data.ticker_valid)
254  {
255  default_mnemonic = gnc_utf8_strip_invalid_strdup (data.ticker);
256  }
257 
258  if (auto_create_commodity)
259  {
260  gnc_commodity *commodity =
262  FALSE,
263  default_fullname,
264  default_mnemonic);
265 
266  if (!commodity)
267  {
268  QofBook *book = gnc_get_current_book();
269  gnc_quote_source *source;
270  gint source_selection = 0; // FIXME: This is just a wild guess
271  char *commodity_namespace = NULL;
272  int fraction = 1;
273 
274  if (data.unique_id_type_valid)
275  {
276  commodity_namespace = gnc_utf8_strip_invalid_strdup (data.unique_id_type);
277  }
278 
279  g_warning("Creating a new commodity, cusip=%s", cusip);
280  /* Create the new commodity */
281  commodity = gnc_commodity_new(book,
282  default_fullname,
283  commodity_namespace,
284  default_mnemonic,
285  cusip,
286  fraction);
287 
288  /* Also set a single quote source */
289  gnc_commodity_begin_edit(commodity);
290  gnc_commodity_user_set_quote_flag (commodity, TRUE);
291  source = gnc_quote_source_lookup_by_ti (SOURCE_SINGLE, source_selection);
292  gnc_commodity_set_quote_source(commodity, source);
293  gnc_commodity_commit_edit(commodity);
294 
295  /* Remember the commodity */
296  gnc_commodity_table_insert(gnc_get_current_commodities(), commodity);
297 
298  g_free (commodity_namespace);
299 
300  }
301  }
302  else
303  {
305  TRUE,
306  default_fullname,
307  default_mnemonic);
308  }
309 
310  g_free (cusip);
311  g_free (default_mnemonic);
312  g_free (default_fullname);
313  return 0;
314 }
315 
316 static void gnc_ofx_set_split_memo(const struct OfxTransactionData* data, Split *split)
317 {
318  g_assert(data);
319  g_assert(split);
320  /* Also put the ofx transaction name in
321  * the splits memo field, or ofx memo if
322  * name is unavailable */
323  if (data->name_valid)
324  {
325  xaccSplitSetMemo(split, data->name);
326  }
327  else if (data->memo_valid)
328  {
329  xaccSplitSetMemo(split, data->memo);
330  }
331 }
332 static gnc_numeric gnc_ofx_numeric_from_double(double value, const gnc_commodity *commodity)
333 {
334  return double_to_gnc_numeric (value,
335  gnc_commodity_get_fraction(commodity),
337 }
338 static gnc_numeric gnc_ofx_numeric_from_double_txn(double value, const Transaction* txn)
339 {
340  return gnc_ofx_numeric_from_double(value, xaccTransGetCurrency(txn));
341 }
342 
343 /* Opens the dialog to create a new account with given name, commodity, parent, type.
344  * Returns the new account, or NULL if it couldn't be created.. */
345 static Account *gnc_ofx_new_account(GtkWindow* parent,
346  const char* name,
347  const gnc_commodity * account_commodity,
348  Account *parent_account,
349  GNCAccountType new_account_default_type)
350 {
351  Account *result;
352  GList * valid_types = NULL;
353 
354  g_assert(name);
355  g_assert(account_commodity);
356  g_assert(parent_account);
357 
358  if (new_account_default_type != ACCT_TYPE_NONE)
359  {
360  // Passing the types as gpointer
361  valid_types =
362  g_list_prepend(valid_types,
363  GINT_TO_POINTER(new_account_default_type));
364  if (!xaccAccountTypesCompatible(xaccAccountGetType(parent_account), new_account_default_type))
365  {
366  // Need to add the parent's account type
367  valid_types =
368  g_list_prepend(valid_types,
369  GINT_TO_POINTER(xaccAccountGetType(parent_account)));
370  }
371  }
372  result = gnc_ui_new_accounts_from_name_with_defaults (parent, name,
373  valid_types,
374  account_commodity,
375  parent_account);
376  g_list_free(valid_types);
377  return result;
378 }
379 /* LibOFX has a daylight time handling bug,
380  * https://sourceforge.net/p/libofx/bugs/39/, which causes it to adjust the
381  * timestamp for daylight time even when daylight time is not in
382  * effect. HAVE_OFX_BUG_39 reflects the result of checking for this bug during
383  * configuration, and fix_ofx_bug_39() corrects for it.
384  */
385 static time64
386 fix_ofx_bug_39 (time64 t)
387 {
388 #if HAVE_OFX_BUG_39
389  struct tm stm;
390 
391 #ifdef __FreeBSD__
392  time64 now;
393  /*
394  * FreeBSD has it's own libc implementation which differs from glibc. In particular:
395  * There is no daylight global
396  * tzname members are set to the string " " (three spaces) when not explicitly populated
397  *
398  * To check that the current timezone does not observe DST I check if tzname[1] starts with a space.
399  */
400  now = gnc_time (NULL);
401  gnc_localtime_r(&now, &stm);
402  tzset();
403 
404  if (tzname[1][0] != ' ' && !stm.tm_isdst)
405 #else
406  gnc_localtime_r(&t, &stm);
407  if (daylight && !stm.tm_isdst)
408 #endif
409  t += 3600;
410 #endif
411  return t;
412 }
413 
414 int ofx_proc_transaction_cb(struct OfxTransactionData data, void *user_data)
415 {
416  char dest_string[255];
417  time64 current_time = gnc_time (NULL);
418  Account *account;
419  Account *investment_account = NULL;
420  Account *income_account = NULL;
421  gchar *investment_account_text, *investment_account_onlineid;
422  gnc_commodity *currency = NULL;
423  gnc_commodity *investment_commodity = NULL;
424  gnc_numeric gnc_amount, gnc_units;
425  QofBook *book;
426  Transaction *transaction;
427  Split *split;
428  gchar *notes, *tmp;
429  ofx_info* info = (ofx_info*) user_data;
430  GtkWindow *parent = GTK_WINDOW (info->parent);
431 
432  g_assert(info->gnc_ofx_importer_gui);
433 
434  if (!data.account_id_valid)
435  {
436  PERR("account ID for this transaction is unavailable!");
437  return 0;
438  }
439  else
440  gnc_utf8_strip_invalid (data.account_id);
441 
442  account = gnc_import_select_account(gnc_gen_trans_list_widget(info->gnc_ofx_importer_gui),
443  data.account_id,
444  0, NULL, NULL, ACCT_TYPE_NONE,
445  info->last_import_account, NULL);
446  if (account == NULL)
447  {
448  PERR("Unable to find account for id %s", data.account_id);
449  return 0;
450  }
451  info->last_import_account = account;
452  /***** Validate the input strings to ensure utf8 *****/
453  if (data.name_valid)
454  gnc_utf8_strip_invalid(data.name);
455  if (data.memo_valid)
456  gnc_utf8_strip_invalid(data.memo);
457  if (data.check_number_valid)
458  gnc_utf8_strip_invalid(data.check_number);
459  if (data.reference_number_valid)
460  gnc_utf8_strip_invalid(data.reference_number);
461 
462  /***** Create the transaction and setup transaction data *******/
463  book = gnc_account_get_book(account);
464  transaction = xaccMallocTransaction(book);
465  xaccTransBeginEdit(transaction);
466 
467  /* Note: Unfortunately libofx <= 0.9.5 will not report a missing
468  * date field as an invalid one. Instead, it will report it as
469  * valid and return a completely bogus date. Starting with
470  * libofx-0.9.6 (not yet released as of 2012-09-09), it will still
471  * be reported as valid but at least the date integer itself is
472  * just plain zero. */
473  if (data.date_posted_valid && (data.date_posted != 0))
474  {
475  /* The hopeful case: We have a posted_date */
476  data.date_posted = fix_ofx_bug_39 (data.date_posted);
477  xaccTransSetDatePostedSecsNormalized(transaction, data.date_posted);
478  }
479  else if (data.date_initiated_valid && (data.date_initiated != 0))
480  {
481  /* No posted date? Maybe we have an initiated_date */
482  data.date_initiated = fix_ofx_bug_39 (data.date_initiated);
483  xaccTransSetDatePostedSecsNormalized(transaction, data.date_initiated);
484  }
485  else
486  {
487  /* Uh no, no valid date. As a workaround use today's date */
488  xaccTransSetDatePostedSecsNormalized(transaction, current_time);
489  }
490 
491  xaccTransSetDateEnteredSecs(transaction, current_time);
492 
493  /* Put transaction name in Description, or memo if name unavailable */
494  if (data.name_valid)
495  {
496  xaccTransSetDescription(transaction, data.name);
497  }
498  else if (data.memo_valid)
499  {
500  xaccTransSetDescription(transaction, data.memo);
501  }
502 
503  /* Put everything else in the Notes field */
504  notes = g_strdup_printf("OFX ext. info: ");
505 
506  if (data.transactiontype_valid)
507  {
508  tmp = notes;
509  notes = g_strdup_printf("%s%s%s", tmp, "|Trans type:",
510  gnc_ofx_ttype_to_string(data.transactiontype));
511  g_free(tmp);
512  }
513 
514  if (data.invtransactiontype_valid)
515  {
516  tmp = notes;
517  notes = g_strdup_printf("%s%s%s", tmp, "|Investment Trans type:",
518  gnc_ofx_invttype_to_str(data.invtransactiontype));
519  g_free(tmp);
520  }
521  if (data.memo_valid && data.name_valid) /* Copy only if memo wasn't put in Description */
522  {
523  tmp = notes;
524  notes = g_strdup_printf("%s%s%s", tmp, "|Memo:", data.memo);
525  g_free(tmp);
526  }
527  if (data.date_funds_available_valid)
528  {
529  time64 time = data.date_funds_available;
530  gnc_time64_to_iso8601_buff (time, dest_string);
531  tmp = notes;
532  notes = g_strdup_printf("%s%s%s", tmp,
533  "|Date funds available:", dest_string);
534  g_free(tmp);
535  }
536  if (data.server_transaction_id_valid)
537  {
538  tmp = notes;
539  notes = g_strdup_printf("%s%s%s", tmp,
540  "|Server trans ID (conf. number):",
541  sanitize_string (data.server_transaction_id));
542  g_free(tmp);
543  }
544  if (data.standard_industrial_code_valid)
545  {
546  tmp = notes;
547  notes = g_strdup_printf("%s%s%ld", tmp,
548  "|Standard Industrial Code:",
549  data.standard_industrial_code);
550  g_free(tmp);
551 
552  }
553  if (data.payee_id_valid)
554  {
555  tmp = notes;
556  notes = g_strdup_printf("%s%s%s", tmp, "|Payee ID:",
557  sanitize_string (data.payee_id));
558  g_free(tmp);
559  }
560 
561  //PERR("WRITEME: GnuCash ofx_proc_transaction():Add PAYEE and ADDRESS here once supported by libofx! Notes=%s\n", notes);
562 
563  /* Ideally, gnucash should process the corrected transactions */
564  if (data.fi_id_corrected_valid)
565  {
566  PERR("WRITEME: GnuCash ofx_proc_transaction(): WARNING: This transaction corrected a previous transaction, but we created a new one instead!\n");
567  tmp = notes;
568  notes = g_strdup_printf("%s%s%s%s", tmp,
569  "|This corrects transaction #",
570  sanitize_string (data.fi_id_corrected),
571  "but GnuCash didn't process the correction!");
572  g_free(tmp);
573  }
574  xaccTransSetNotes(transaction, notes);
575  g_free(notes);
576 
577  if (data.account_ptr && data.account_ptr->currency_valid)
578  {
579  DEBUG("Currency from libofx: %s", data.account_ptr->currency);
580  currency = gnc_commodity_table_lookup( gnc_get_current_commodities (),
581  GNC_COMMODITY_NS_CURRENCY,
582  data.account_ptr->currency);
583  }
584  else
585  {
586  DEBUG("Currency from libofx unavailable, defaulting to account's default");
587  currency = xaccAccountGetCommodity(account);
588  }
589 
590  xaccTransSetCurrency(transaction, currency);
591  if (data.amount_valid)
592  {
593  if (!data.invtransactiontype_valid
594 #ifdef HAVE_LIBOFX_VERSION_0_10
595  || data.invtransactiontype == OFX_INVBANKTRAN)
596 #else
597  )
598 #endif
599  {
600  double amount = data.amount;
601 #ifdef HAVE_LIBOFX_VERSION_0_10
602  if (data.currency_ratio_valid && data.currency_ratio != 0)
603  amount *= data.currency_ratio;
604 #endif
605  /***** Process a normal transaction ******/
606  DEBUG("Adding split; Ordinary banking transaction, money flows from or into the source account");
607  split = xaccMallocSplit(book);
608  xaccTransAppendSplit(transaction, split);
609  xaccAccountInsertSplit(account, split);
610  gnc_amount = gnc_ofx_numeric_from_double_txn(amount, transaction);
611  xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));
612 
613  /* set tran-num and/or split-action per book option */
614  if (data.check_number_valid)
615  {
616  gnc_set_num_action(transaction, split, data.check_number, NULL);
617  }
618  else if (data.reference_number_valid)
619  {
620  gnc_set_num_action(transaction, split, data.reference_number, NULL);
621  }
622  /* Also put the ofx transaction's memo in the
623  * split's memo field */
624  if (data.memo_valid)
625  {
626  xaccSplitSetMemo(split, data.memo);
627  }
628  if (data.fi_id_valid)
629  {
630  gnc_import_set_split_online_id(split,
631  sanitize_string (data.fi_id));
632  }
633  }
634 
635  else if (data.unique_id_valid
636  && data.security_data_valid
637  && data.security_data_ptr != NULL
638  && data.security_data_ptr->secname_valid)
639  {
640  gboolean choosing_account = TRUE;
641  gnc_utf8_strip_invalid (data.unique_id);
642  /********* Process an investment transaction **********/
643  /* Note that the ACCT_TYPE_STOCK account type
644  should be replaced with something derived from
645  data.invtranstype*/
646 
647  // We have an investment transaction. First select the correct commodity.
648  investment_commodity = gnc_import_select_commodity(data.unique_id,
649  FALSE,
650  NULL,
651  NULL);
652  if (investment_commodity != NULL)
653  {
654  // As we now have the commodity, select the account with that commodity.
655 
656  /* Translators: This string is a default account name. It MUST
657  * NOT contain the character ':' anywhere in it or in any
658  * translations. */
659  investment_account_text = g_strdup_printf(
660  _("Stock account for security \"%s\""),
661  sanitize_string (data.security_data_ptr->secname));
662 
663  investment_account_onlineid = g_strdup_printf( "%s%s",
664  data.account_id,
665  data.unique_id);
666  investment_account = gnc_import_select_account(
667  gnc_gen_trans_list_widget(info->gnc_ofx_importer_gui),
668  investment_account_onlineid,
669  1,
670  investment_account_text,
671  investment_commodity,
673  info->last_investment_account,
674  NULL);
675  if (investment_account)
676  info->last_investment_account = investment_account;
677 
678  // but use it only if that's really the right commodity
679  if (investment_account
680  && xaccAccountGetCommodity(investment_account) != investment_commodity)
681  investment_account = NULL;
682 
683  // Loop until we either have an account, or the user pressed Cancel
684  while (!investment_account && choosing_account)
685  {
686  // No account with correct commodity automatically found.
687 
688  // But are we in auto-create mode and already know a parent?
689  if (auto_create_commodity && ofx_parent_account)
690  {
691  // Yes, so use that as parent when auto-creating the new account below.
692  investment_account = ofx_parent_account;
693  }
694  else
695  {
696  // Let the user choose an account
697  investment_account = gnc_import_select_account(
698  gnc_gen_trans_list_widget(info->gnc_ofx_importer_gui),
699  data.unique_id,
700  TRUE,
701  investment_account_text,
702  investment_commodity,
704  info->last_investment_account,
705  &choosing_account);
706  if (investment_account)
707  info->last_investment_account = investment_account;
708  }
709  // Does the chosen account have the right commodity?
710  if (investment_account && xaccAccountGetCommodity(investment_account) != investment_commodity)
711  {
712  if (auto_create_commodity
713  && xaccAccountTypesCompatible(xaccAccountGetType(investment_account),
715  {
716  // The user chose an account, but it does
717  // not have the right commodity. Also,
718  // auto-creation is on. Hence, we create a
719  // new child account of the selected one,
720  // and this one will have the right
721  // commodity.
722  Account *parent_account = investment_account;
723  investment_account =
724  gnc_ofx_new_account(parent,
725  investment_account_text,
726  investment_commodity,
727  parent_account,
729  if (investment_account)
730  {
731  gnc_import_set_acc_online_id(investment_account, data.unique_id);
732  choosing_account = FALSE;
733  ofx_parent_account = parent_account;
734  }
735  else
736  {
737  ofx_parent_account = NULL;
738  }
739  }
740  else
741  {
742  // No account with matching commodity. Ask the user
743  // whether to continue or abort.
744  choosing_account =
745  gnc_verify_dialog(
746  GTK_WINDOW (gnc_gen_trans_list_widget(info->gnc_ofx_importer_gui)), TRUE,
747  "The chosen account \"%s\" does not have the correct "
748  "currency/security \"%s\" (it has \"%s\" instead). "
749  "This account cannot be used. "
750  "Do you want to choose again?",
751  xaccAccountGetName(investment_account),
752  gnc_commodity_get_fullname(investment_commodity),
754  // We must also delete the online_id that was set in gnc_import_select_account()
755  gnc_import_set_acc_online_id(investment_account, "");
756  investment_account = NULL;
757  }
758  }
759  }
760  if (!investment_account)
761  {
762  PERR("No investment account found for text: %s\n", investment_account_text);
763  }
764  g_free (investment_account_text);
765  g_free (investment_account_onlineid);
766  investment_account_text = NULL;
767 
768  if (investment_account != NULL &&
769  data.unitprice_valid &&
770  data.units_valid &&
771  ( data.invtransactiontype != OFX_INCOME ) )
772  {
773  DEBUG("Adding investment split; Money flows from or into the stock account");
774  split = xaccMallocSplit(book);
775  xaccTransAppendSplit(transaction, split);
776  xaccAccountInsertSplit(investment_account, split);
777 
778  gnc_amount = gnc_ofx_numeric_from_double_txn (ofx_get_investment_amount(&data),
779  transaction);
780  gnc_units = gnc_ofx_numeric_from_double (data.units, investment_commodity);
781  xaccSplitSetAmount(split, gnc_units);
782  xaccSplitSetValue(split, gnc_amount);
783 
784  /* set tran-num and/or split-action per book option */
785  if (data.check_number_valid)
786  {
787  gnc_set_num_action(transaction, split, data.check_number, NULL);
788  }
789  else if (data.reference_number_valid)
790  {
791  gnc_set_num_action(transaction, split,
792  data.reference_number, NULL);
793  }
794  if (data.security_data_ptr->memo_valid)
795  {
796  xaccSplitSetMemo(split,
797  sanitize_string (data.security_data_ptr->memo));
798  }
799  if (data.fi_id_valid)
800  {
801  gnc_import_set_split_online_id(split,
802  sanitize_string (data.fi_id));
803  }
804  }
805  else
806  {
807  if (investment_account)
808  PERR("The investment account, units or unitprice was not found for the investment transaction");
809  }
810  }
811  else
812  {
813  PERR("Commodity not found for the investment transaction");
814  }
815 
816  if (data.invtransactiontype_valid && investment_account)
817  {
818  double amount = data.amount;
819 #ifdef HAVE_LIBOFX_VERSION_0_10
820  if (data.currency_ratio_valid && data.currency_ratio != 0)
821  amount *= data.currency_ratio;
822 #endif
823  if (data.invtransactiontype == OFX_REINVEST
824  || data.invtransactiontype == OFX_INCOME)
825  {
826  DEBUG("Now let's find an account for the destination split");
827  income_account =
828  get_associated_income_account(investment_account);
829 
830  if (income_account == NULL)
831  {
832  DEBUG("Couldn't find an associated income account");
833  /* Translators: This string is a default account
834  * name. It MUST NOT contain the character ':' anywhere
835  * in it or in any translations. */
836  investment_account_text = g_strdup_printf(
837  _("Income account for security \"%s\""),
838  sanitize_string (data.security_data_ptr->secname));
839  income_account = gnc_import_select_account(
840  gnc_gen_trans_list_widget(info->gnc_ofx_importer_gui),
841  NULL,
842  1,
843  investment_account_text,
844  currency,
846  info->last_income_account,
847  NULL);
848  if (income_account != NULL)
849  {
850  info->last_income_account = income_account;
851  set_associated_income_account(investment_account,
852  income_account);
853  DEBUG("KVP written");
854  }
855 
856  }
857  else
858  {
859  DEBUG("Found at least one associated income account");
860  }
861  }
862  if (income_account != NULL &&
863  data.invtransactiontype == OFX_REINVEST)
864  {
865  DEBUG("Adding investment split; Money flows from the income account");
866  split = xaccMallocSplit(book);
867  xaccTransAppendSplit(transaction, split);
868  xaccAccountInsertSplit(income_account, split);
869  gnc_amount = gnc_ofx_numeric_from_double_txn(amount,
870  transaction);
871  xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));
872 
873  // Set split memo from ofx transaction name or memo
874  gnc_ofx_set_split_memo(&data, split);
875  }
876  if (income_account != NULL &&
877  data.invtransactiontype == OFX_INCOME)
878  {
879  DEBUG("Adding investment split; Money flows from the income account");
880  split = xaccMallocSplit(book);
881  xaccTransAppendSplit(transaction, split);
882  xaccAccountInsertSplit(income_account, split);
883  /*OFX_INCOME amounts come in as positive numbers*/
884  gnc_amount = gnc_ofx_numeric_from_double_txn (-amount,
885  transaction);
886 
887  xaccSplitSetBaseValue(split, gnc_amount, xaccTransGetCurrency(transaction));
888 
889  // Set split memo from ofx transaction name or memo
890  gnc_ofx_set_split_memo(&data, split);
891  }
892  }
893 
894  if (data.invtransactiontype_valid
895  && data.invtransactiontype != OFX_REINVEST)
896  {
897  DEBUG("Adding investment split; Money flows from or to the cash account");
898  split = xaccMallocSplit(book);
899  xaccTransAppendSplit(transaction, split);
900  xaccAccountInsertSplit(account, split);
901 
902  gnc_amount = gnc_ofx_numeric_from_double_txn(
903  -ofx_get_investment_amount(&data), transaction);
904  xaccSplitSetBaseValue(split, gnc_amount,
905  xaccTransGetCurrency(transaction));
906 
907  // Set split memo from ofx transaction name or memo
908  gnc_ofx_set_split_memo(&data, split);
909  }
910  }
911 
912  /* Send transaction to importer GUI. */
913  if (xaccTransCountSplits(transaction) > 0)
914  {
915  DEBUG("%d splits sent to the importer gui",
916  xaccTransCountSplits(transaction));
917  info->trans_list = g_list_prepend (info->trans_list, transaction);
918  }
919  else
920  {
921  PERR("No splits in transaction (missing account?), ignoring.");
922  xaccTransDestroy(transaction);
923  xaccTransCommitEdit(transaction);
924  }
925  }
926  else
927  {
928  PERR("The transaction doesn't have a valid amount");
929  xaccTransDestroy(transaction);
930  xaccTransCommitEdit(transaction);
931  }
932  info->num_trans_processed += 1;
933  return 0;
934 }//end ofx_proc_transaction()
935 
936 
937 int ofx_proc_statement_cb (struct OfxStatementData data, void * statement_user_data)
938 {
939  ofx_info* info = (ofx_info*) statement_user_data;
940  info->statement = g_new (struct OfxStatementData, 1);
941  *info->statement = data;
942  return 0;
943 }
944 
945 
946 int ofx_proc_account_cb(struct OfxAccountData data, void * account_user_data)
947 {
948  gnc_commodity_table * commodity_table;
949  gnc_commodity * default_commodity;
950  GNCAccountType default_type = ACCT_TYPE_NONE;
951  gchar * account_description;
952  GtkWidget * main_widget;
953  GtkWidget * parent;
954  /* In order to trigger a book options display on the creation of a new book,
955  * we need to detect when we are dealing with a new book. */
956  gboolean new_book = gnc_is_new_book();
957  ofx_info* info = (ofx_info*) account_user_data;
958  Account* account = NULL;
959 
960  const gchar * account_type_name = _("Unknown OFX account");
961 
962  if (data.account_id_valid)
963  {
964  commodity_table = gnc_get_current_commodities ();
965  if (data.currency_valid)
966  {
967  DEBUG("Currency from libofx: %s", data.currency);
968  default_commodity = gnc_commodity_table_lookup(commodity_table,
969  GNC_COMMODITY_NS_CURRENCY,
970  data.currency);
971  }
972  else
973  {
974  default_commodity = NULL;
975  }
976 
977  if (data.account_type_valid)
978  {
979  switch (data.account_type)
980  {
981  case OFX_CHECKING :
982  default_type = ACCT_TYPE_BANK;
983  account_type_name = _("Unknown OFX checking account");
984  break;
985  case OFX_SAVINGS :
986  default_type = ACCT_TYPE_BANK;
987  account_type_name = _("Unknown OFX savings account");
988  break;
989  case OFX_MONEYMRKT :
990  default_type = ACCT_TYPE_MONEYMRKT;
991  account_type_name = _("Unknown OFX money market account");
992  break;
993  case OFX_CREDITLINE :
994  default_type = ACCT_TYPE_CREDITLINE;
995  account_type_name = _("Unknown OFX credit line account");
996  break;
997  case OFX_CMA :
998  default_type = ACCT_TYPE_NONE;
999  /* Cash Management Account */
1000  account_type_name = _("Unknown OFX CMA account");
1001  break;
1002  case OFX_CREDITCARD :
1003  default_type = ACCT_TYPE_CREDIT;
1004  account_type_name = _("Unknown OFX credit card account");
1005  break;
1006  case OFX_INVESTMENT :
1007  default_type = ACCT_TYPE_BANK;
1008  account_type_name = _("Unknown OFX investment account");
1009  break;
1010  default:
1011  PERR("WRITEME: ofx_proc_account() This is an unknown account type!");
1012  break;
1013  }
1014  }
1015 
1016  /* If the OFX importer was started in Gnucash in a 'new_book' situation,
1017  * as described above, the first time the 'ofx_proc_account_cb' function
1018  * is called a book is created. (This happens after the 'new_book' flag
1019  * is set in 'gnc_get_current_commodities', called above.) So, before
1020  * calling 'gnc_import_select_account', allow the user to set book
1021  * options. */
1022  if (new_book)
1023  gnc_new_book_option_display (GTK_WIDGET (gnc_ui_get_main_window (NULL)));
1024 
1025  gnc_utf8_strip_invalid(data.account_name);
1026  gnc_utf8_strip_invalid(data.account_id);
1027  account_description = g_strdup_printf (/* This string is a default account
1028  name. It MUST NOT contain the
1029  character ':' anywhere in it or
1030  in any translation. */
1031  "%s \"%s\"",
1032  account_type_name,
1033  data.account_name);
1034 
1035  main_widget = gnc_gen_trans_list_widget (info->gnc_ofx_importer_gui);
1036 
1037  /* On first use, the import-main-matcher is hidden / not realized so to
1038  * get a parent use the transient parent of the matcher */
1039  if (gtk_widget_get_realized (main_widget))
1040  parent = main_widget;
1041  else
1042  parent = GTK_WIDGET(gtk_window_get_transient_for (GTK_WINDOW(main_widget)));
1043 
1044  account = gnc_import_select_account (parent,
1045  data.account_id, 1,
1046  account_description, default_commodity,
1047  default_type, NULL, NULL);
1048 
1049  if (account)
1050  {
1051  info->last_import_account = account;
1052  }
1053 
1054  g_free(account_description);
1055  }
1056  else
1057  {
1058  PERR("account online ID not available");
1059  }
1060 
1061  return 0;
1062 }
1063 
1064 double ofx_get_investment_amount(const struct OfxTransactionData* data)
1065 {
1066  double amount = data->amount;
1067 #ifdef HAVE_LIBOFX_VERSION_0_10
1068  if (data->invtransactiontype == OFX_INVBANKTRAN)
1069  return 0.0;
1070  if (data->currency_ratio_valid && data->currency_ratio != 0)
1071  amount *= data->currency_ratio;
1072 #endif
1073  g_assert(data);
1074  switch (data->invtransactiontype)
1075  {
1076  case OFX_BUYDEBT:
1077  case OFX_BUYMF:
1078  case OFX_BUYOPT:
1079  case OFX_BUYOTHER:
1080  case OFX_BUYSTOCK:
1081  return fabs(amount);
1082  case OFX_SELLDEBT:
1083  case OFX_SELLMF:
1084  case OFX_SELLOPT:
1085  case OFX_SELLOTHER:
1086  case OFX_SELLSTOCK:
1087  return -1 * fabs(amount);
1088  default:
1089  return -1 * amount;
1090  }
1091 }
1092 
1093 // Forward declaration, required because several static functions depend on one-another.
1094 static void
1095 gnc_file_ofx_import_process_file (ofx_info* info);
1096 
1097 // gnc_ofx_process_next_file processes the next file in the info->file_list.
1098 static void
1099 gnc_ofx_process_next_file (GtkDialog *dialog, gpointer user_data)
1100 {
1101  ofx_info* info = (ofx_info*) user_data;
1102  // Free the statement (if it was allocated)
1103  g_free (info->statement);
1104  info->statement = NULL;
1105 
1106  // Done with the previous OFX file, process the next one if any.
1107  info->file_list = g_slist_delete_link (info->file_list, info->file_list);
1108  if (info->file_list)
1109  gnc_file_ofx_import_process_file (info);
1110  else
1111  {
1112  // Final cleanup.
1113  g_free (info);
1114  }
1115 }
1116 
1117 static void
1118 gnc_ofx_on_match_click (GtkDialog *dialog, gint response_id, gpointer user_data)
1119 {
1120  // Record the response of the user. If cancel we won't go to the next file, etc.
1121  ofx_info* info = (ofx_info*)user_data;
1122  info->response = response_id;
1123 }
1124 
1125 static void
1126 gnc_ofx_match_done (GtkDialog *dialog, gpointer user_data)
1127 {
1128  ofx_info* info = (ofx_info*) user_data;
1129 
1130  /* The the user did not click OK, don't process the rest of the
1131  * transaction, don't go to the next of xfile.
1132  */
1133  if (info->response != GTK_RESPONSE_OK)
1134  {
1135  g_free (info);
1136  return;
1137  }
1138 
1139  if (info->trans_list)
1140  {
1141  /* Re-run the match dialog if there are transactions
1142  * remaining in our list (happens if several accounts exist
1143  * in the same ofx).
1144  */
1145  info->gnc_ofx_importer_gui = gnc_gen_trans_list_new (GTK_WIDGET (info->parent), NULL, FALSE, 42, FALSE);
1146  runMatcher (info, NULL, true);
1147  return;
1148  }
1149 
1150  if (info->run_reconcile && info->statement)
1151  {
1152  // Open a reconcile window.
1153  Account* account = gnc_import_select_account (gnc_gen_trans_list_widget(info->gnc_ofx_importer_gui),
1154  info->statement->account_id,
1155  0, NULL, NULL, ACCT_TYPE_NONE, NULL, NULL);
1156  if (account && info->statement->ledger_balance_valid)
1157  {
1158  gnc_numeric value = double_to_gnc_numeric (info->statement->ledger_balance,
1159  xaccAccountGetCommoditySCU (account),
1161 
1162  RecnWindow* rec_window = recnWindowWithBalance (GTK_WIDGET (info->parent), account, value,
1163  info->statement->ledger_balance_date);
1164 
1165  // Connect to destroy, at which point we'll process the next OFX file..
1166  g_signal_connect (G_OBJECT (gnc_ui_reconcile_window_get_window (rec_window)), "destroy",
1167  G_CALLBACK (gnc_ofx_process_next_file), info);
1168  return;
1169  }
1170  }
1171  gnc_ofx_process_next_file (NULL, info);
1172 }
1173 
1174 // This callback is triggered when the user checks or unchecks the reconcile after match
1175 // check box in the matching dialog.
1176 static void
1177 reconcile_when_close_toggled_cb (GtkToggleButton *togglebutton, ofx_info* info)
1178 {
1179  info->run_reconcile = gtk_toggle_button_get_active (togglebutton);
1180 }
1181 
1182 static void
1183 runMatcher(ofx_info* info, char * selected_filename, gboolean go_to_next_file)
1184 {
1185  GtkWindow *parent = info->parent;
1186  GList* trans_list_remain = NULL;
1187  Account* first_account = NULL;
1188 
1189  /* If we have multiple accounts in the ofx file, we need to
1190  * process transactions one account at a time, in case there are
1191  * transfers between accounts.
1192  */
1193  info->num_trans_processed = 0;
1194  for(GList* node = info->trans_list; node; node=node->next)
1195  {
1196  Transaction* trans = node->data;
1197  Split* split = xaccTransGetSplit (trans, 0);
1198  if (first_account == NULL) first_account = xaccSplitGetAccount (split);
1199  if (xaccSplitGetAccount (split) == first_account)
1200  {
1201  gnc_gen_trans_list_add_trans (info->gnc_ofx_importer_gui, trans);
1202  info->num_trans_processed ++;
1203  }
1204  else trans_list_remain = g_list_prepend (trans_list_remain, trans);
1205  }
1206  g_list_free (info->trans_list);
1207  info->trans_list = g_list_reverse (trans_list_remain);
1208 
1209  // See whether the view has anything in it and warn the user if not.
1210  if (gnc_gen_trans_list_empty (info->gnc_ofx_importer_gui))
1211  {
1212  gnc_gen_trans_list_delete (info->gnc_ofx_importer_gui);
1213  if (info->num_trans_processed)
1214  {
1215  gchar* acct_name = gnc_get_account_name_for_register (first_account);
1216  gnc_info_dialog (parent, _("While importing transactions from OFX file '%s' into account '%s', found %d previously imported transactions, no new transactions."),
1217  selected_filename, acct_name, info->num_trans_processed);
1218  g_free (acct_name);
1219  // This is required to ensure we don't mistakenly assume the user canceled.
1220  info->response = GTK_RESPONSE_OK;
1221  gnc_ofx_match_done (NULL,info);
1222  return;
1223  }
1224  }
1225  else
1226  {
1227  /* Show the match dialog and connect to the "destroy" signal so we can trigger a reconcile when
1228  the user clicks OK when done matching transactions if required. Connecting to response isn't enough
1229  because only when the matcher is destroyed do imported transactions get recorded */
1230  g_signal_connect (G_OBJECT (gnc_gen_trans_list_widget (info->gnc_ofx_importer_gui)), "destroy",
1231  G_CALLBACK (gnc_ofx_match_done), info);
1232 
1233  // Connect to response so we know if the user pressed "cancel".
1234  g_signal_connect (G_OBJECT (gnc_gen_trans_list_widget (info->gnc_ofx_importer_gui)), "response",
1235  G_CALLBACK (gnc_ofx_on_match_click), info);
1236 
1237  gnc_gen_trans_list_show_all (info->gnc_ofx_importer_gui);
1238 
1239  // Show or hide the check box for reconciling after match, depending on whether a statement was received.
1240  gnc_gen_trans_list_show_reconcile_after_close_button (info->gnc_ofx_importer_gui, info->statement != NULL, info->run_reconcile);
1241 
1242  // Finally connect to the reconcile after match check box so we can be notified if the user wants/does not want to reconcile.
1243  g_signal_connect (G_OBJECT (gnc_gen_trans_list_get_reconcile_after_close_button (info->gnc_ofx_importer_gui)), "toggled",
1244  G_CALLBACK (reconcile_when_close_toggled_cb), info);
1245  }
1246 }
1247 
1248 // Aux function to process the OFX file in info->file_list
1249 static void
1250 gnc_file_ofx_import_process_file (ofx_info* info)
1251 {
1252  LibofxContextPtr libofx_context;
1253  char* filename = NULL;
1254  char * selected_filename = NULL;
1255  GtkWindow *parent = info->parent;
1256 
1257  if (info->file_list == NULL)
1258  return;
1259 
1260  filename = info->file_list->data;
1261  libofx_context = libofx_get_new_context();
1262 
1263 #ifdef G_OS_WIN32
1264  selected_filename = g_win32_locale_filename_from_utf8 (filename);
1265  g_free (filename);
1266 #else
1267  selected_filename = filename;
1268 #endif
1269  DEBUG("Filename found: %s", selected_filename);
1270 
1271  // Reset the reconciliation information.
1272  info->num_trans_processed = 0;
1273  info->statement = NULL;
1274 
1275  /* Initialize libofx and set the callbacks*/
1276  ofx_set_statement_cb (libofx_context, ofx_proc_statement_cb, info);
1277  ofx_set_account_cb (libofx_context, ofx_proc_account_cb, info);
1278  ofx_set_transaction_cb (libofx_context, ofx_proc_transaction_cb, info);
1279  ofx_set_security_cb (libofx_context, ofx_proc_security_cb, info);
1280  /*ofx_set_status_cb(libofx_context, ofx_proc_status_cb, 0);*/
1281 
1282  // Create the match dialog, and run the ofx file through the importer.
1283  info->gnc_ofx_importer_gui = gnc_gen_trans_list_new (GTK_WIDGET(parent), NULL, FALSE, 42, FALSE);
1284  libofx_proc_file (libofx_context, selected_filename, AUTODETECT);
1285 
1286  // Free the libofx context before recursing to process the next file
1287  libofx_free_context(libofx_context);
1288  runMatcher(info, selected_filename,true);
1289  g_free(selected_filename);
1290 }
1291 
1292 // The main import function. Starts the chain of file imports (if there are several)
1293 void gnc_file_ofx_import (GtkWindow *parent)
1294 {
1295  extern int ofx_PARSER_msg;
1296  extern int ofx_DEBUG_msg;
1297  extern int ofx_WARNING_msg;
1298  extern int ofx_ERROR_msg;
1299  extern int ofx_INFO_msg;
1300  extern int ofx_STATUS_msg;
1301  GSList* selected_filenames = NULL;
1302  char *default_dir;
1303  GList *filters = NULL;
1304  GSList* iter = NULL;
1305  ofx_info* info = NULL;
1306  GtkFileFilter* filter = gtk_file_filter_new ();
1307 
1308 
1309  ofx_PARSER_msg = false;
1310  ofx_DEBUG_msg = false;
1311  ofx_WARNING_msg = true;
1312  ofx_ERROR_msg = true;
1313  ofx_INFO_msg = true;
1314  ofx_STATUS_msg = false;
1315 
1316  DEBUG("gnc_file_ofx_import(): Begin...\n");
1317 
1318  default_dir = gnc_get_default_directory(GNC_PREFS_GROUP);
1319  gtk_file_filter_set_name (filter, _("Open/Quicken Financial Exchange file (*.ofx, *.qfx)"));
1320  gtk_file_filter_add_pattern (filter, "*.[oqOQ][fF][xX]");
1321  filters = g_list_prepend( filters, filter );
1322 
1323  selected_filenames = gnc_file_dialog_multi (parent,
1324  _("Select one or multiple OFX/QFX file(s) to process"),
1325  filters,
1326  default_dir,
1327  GNC_FILE_DIALOG_IMPORT);
1328  g_free(default_dir);
1329 
1330  if (selected_filenames)
1331  {
1332  /* Remember the directory as the default. */
1333  default_dir = g_path_get_dirname(selected_filenames->data);
1334  gnc_set_default_directory(GNC_PREFS_GROUP, default_dir);
1335  g_free(default_dir);
1336 
1337  /* Look up the needed preferences */
1338  auto_create_commodity =
1339  gnc_prefs_get_bool (GNC_PREFS_GROUP_IMPORT, GNC_PREF_AUTO_COMMODITY);
1340 
1341  DEBUG("Opening selected file(s)");
1342  // Create the structure that holds the list of files to process and the statement info.
1343  info = g_new(ofx_info,1);
1344  info->num_trans_processed = 0;
1345  info->statement = NULL;
1346  info->last_investment_account = NULL;
1347  info->last_import_account = NULL;
1348  info->last_income_account = NULL;
1349  info->parent = parent;
1350  info->run_reconcile = FALSE;
1351  info->file_list = selected_filenames;
1352  info->trans_list = NULL;
1353  info->response = 0;
1354  // Call the aux import function.
1355  gnc_file_ofx_import_process_file (info);
1356  }
1357 }
1358 
1359 
void gnc_gen_trans_list_show_reconcile_after_close_button(GNCImportMainMatcher *info, gboolean reconcile_after_close, gboolean active)
Show and set the reconcile after close check button.
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Add a new commodity to the commodity table.
GNCImportMainMatcher * gnc_gen_trans_list_new(GtkWidget *parent, const gchar *heading, gboolean all_from_same_account, gint match_date_hardlimit, gboolean show_all)
Create a new generic transaction dialog window and return it.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:362
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:510
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...
Definition: Split.c:1319
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&#39;s split list.
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.
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
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3236
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2682
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
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.
Account * gnc_import_select_account(GtkWidget *parent, const gchar *account_online_id_value, gboolean auto_create, 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 matcher main window.
Ofx import module interface.
Generic and very flexible account matcher/picker.
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.
Definition: qoflog.h:244
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
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.
Definition: gnc-date.cpp:117
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...
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1425
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Stock accounts will typically be shown in registers which show three columns: price, number of shares, and value.
Definition: Account.h:125
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2396
gchar * gnc_get_account_name_for_register(const Account *account)
Get either the full name of the account or the simple name, depending on the configuration parameter ...
Definition: gnc-ui-util.c:579
#define xaccAccountGetGUID(X)
Definition: Account.h:248
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&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
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...
Definition: Account.cpp:4561
GtkWidget * gnc_gen_trans_list_widget(GNCImportMainMatcher *info)
Returns the widget of this dialog.
Income accounts are used to denote income.
Definition: Account.h:143
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1728
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&#39;t use this for now, see NUM_ACCOUNT_TYPES
Definition: Account.h:174
gboolean gnc_gen_trans_list_empty(GNCImportMainMatcher *info)
Checks whether there are no transactions to match.
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:110
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.
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...
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...
Definition: Account.h:105
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
GLib helper routines.
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...
Definition: Account.cpp:1430
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3405
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1366
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
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&#39;t use this for now, see NUM_ACCOUNT_TYPES
Definition: Account.h:172
Utility functions for writing import modules.
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2052
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3258
A Generic commodity matcher/picker.
Not a type.
Definition: Account.h:108
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
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...
Definition: gnc-date.cpp:1142
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1471
The Credit card account is used to denote credit (e.g.
Definition: Account.h:116
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2031