GnuCash  4.8a-132-gcdaeb421d+
import-backend.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 \********************************************************************/
29 #include <config.h>
30 
31 #include <gtk/gtk.h>
32 #include <glib/gi18n.h>
33 #include <stdlib.h>
34 #include <math.h>
35 
36 #include <errno.h>
37 
38 #include "import-backend.h"
39 #include "import-utilities.h"
40 #include "Account.h"
41 #include "Query.h"
42 #include "gnc-engine.h"
43 #include "engine-helpers.h"
44 #include "gnc-prefs.h"
45 #include "gnc-ui-util.h"
46 
47 #define GNCIMPORT_DESC "desc"
48 #define GNCIMPORT_MEMO "memo"
49 #define GNCIMPORT_PAYEE "payee"
50 
51 /********************************************************************\
52  * Constants *
53 \********************************************************************/
54 
55 static QofLogModule log_module = GNC_MOD_IMPORT;
56 
57 /********************************************************************\
58  * Forward declared prototypes *
59 \********************************************************************/
60 
61 static void
62 matchmap_store_destination (GncImportMatchMap *matchmap,
63  GNCImportTransInfo *trans_info,
64  gboolean use_match);
65 
66 
67 /********************************************************************\
68  * Structures passed between the functions *
69 \********************************************************************/
70 
72 {
73  GNCImportMatchInfo *selected_match;
74  gboolean selected_manually;
75 };
76 
78 {
79  Transaction * trans;
80  Split * first_split;
81 
82  /* GList of GNCImportMatchInfo's, one for each possible duplicate match. */
83  GList * match_list;
84  GNCImportSelectedMatchInfo selected_match_info;
85 
86  GNCImportAction action;
87  GNCImportAction previous_action;
88 
89  /* A list of tokenized strings to use for bayesian matching purposes */
90  GList * match_tokens;
91 
92  /* In case of a single destination account it is stored here. */
93  Account *dest_acc;
94  gboolean dest_acc_selected_manually;
95 
96  /* Reference id to link gnc transaction to external object. E.g. aqbanking job id. */
97  guint32 ref_id;
98 };
99 
100 /* Some simple getters and setters for the above data types. */
101 
102 GList *
103 gnc_import_TransInfo_get_match_list (const GNCImportTransInfo *info)
104 {
105  g_assert (info);
106  return info->match_list;
107 }
108 
109 void
110 gnc_import_TransInfo_set_match_list (GNCImportTransInfo *info, GList* match_list)
111 {
112  g_assert (info);
113  info->match_list = match_list;
114  if (match_list)
115  {
116  info->selected_match_info.selected_match = match_list->data;
117  }
118  else
119  {
120  info->selected_match_info.selected_match = NULL;
121  gnc_import_TransInfo_set_action (info, GNCImport_ADD);
122  }
123 }
124 
125 Transaction *
126 gnc_import_TransInfo_get_trans (const GNCImportTransInfo *info)
127 {
128  g_assert (info);
129  return info->trans;
130 }
131 
132 gboolean
133 gnc_import_TransInfo_is_balanced (const GNCImportTransInfo *info)
134 {
135  g_assert (info);
136  /* Assume that the importer won't create a transaction that involves two or more
137  currencies and no non-currency commodity. In that case can use the simpler
138  value imbalance check. */
140  {
141  return TRUE;
142  }
143  else
144  {
145  return FALSE;
146  }
147 }
148 
149 Split *
150 gnc_import_TransInfo_get_fsplit (const GNCImportTransInfo *info)
151 {
152  g_assert (info);
153  return info->first_split;
154 }
155 
157 gnc_import_TransInfo_get_selected_match (const GNCImportTransInfo *info)
158 {
159  g_assert (info);
160  return info->selected_match_info.selected_match;
161 }
162 
163 void
165  GNCImportMatchInfo *match,
166  gboolean selected_manually)
167 {
168  g_assert (info);
169  info->selected_match_info.selected_match = match;
170  info->selected_match_info.selected_manually = selected_manually;
171 }
172 
173 gboolean
174 gnc_import_TransInfo_get_match_selected_manually (const GNCImportTransInfo *info)
175 {
176  g_assert (info);
177  return info->selected_match_info.selected_manually;
178 }
179 
180 GNCImportAction
181 gnc_import_TransInfo_get_action (const GNCImportTransInfo *info)
182 {
183  g_assert (info);
184  return info->action;
185 }
186 
187 void
188 gnc_import_TransInfo_set_action (GNCImportTransInfo *info,
189  GNCImportAction action)
190 {
191  g_assert (info);
192  if (action != info->action)
193  {
194  info->previous_action = info->action;
195  info->action = action;
196  }
197 }
198 
199 Account *
200 gnc_import_TransInfo_get_destacc (const GNCImportTransInfo *info)
201 {
202  g_assert (info);
203  return info->dest_acc;
204 }
205 void gnc_import_TransInfo_set_destacc (GNCImportTransInfo *info,
206  Account *acc,
207  gboolean selected_manually)
208 {
209  g_assert (info);
210  info->dest_acc = acc;
211  info->dest_acc_selected_manually = selected_manually;
212 
213  /* Store the mapping to the other account in the MatchMap. */
214  if (selected_manually)
215  {
216  matchmap_store_destination (NULL, info, FALSE);
217  }
218 }
219 
220 gboolean
222 {
223  g_assert (info);
224  return info->dest_acc_selected_manually;
225 }
226 
227 guint32
228 gnc_import_TransInfo_get_ref_id (const GNCImportTransInfo *info)
229 {
230  g_assert (info);
231  return info->ref_id;
232 }
233 
234 void
235 gnc_import_TransInfo_set_ref_id (GNCImportTransInfo *info,
236  guint32 ref_id)
237 {
238  g_assert (info);
239  info->ref_id = ref_id;
240 }
241 
242 
243 Split *
245 {
246  g_assert (info);
247  return info->split;
248 }
249 
250 gint
252 {
253  if (info)
254  {
255  return info->probability;
256  }
257  else
258  {
259  return 0;
260  }
261 }
262 
263 void gnc_import_TransInfo_delete (GNCImportTransInfo *info)
264 {
265  if (info)
266  {
267  g_list_free (info->match_list);
268  /*If the transaction exists and is still open, it must be destroyed*/
269  if (info->trans && xaccTransIsOpen(info->trans))
270  {
271  xaccTransDestroy(info->trans);
272  xaccTransCommitEdit(info->trans);
273  }
274  if (info->match_tokens)
275  {
276  GList *node;
277 
278  for (node = info->match_tokens; node; node = node->next)
279  g_free (node->data);
280 
281  g_list_free (info->match_tokens);
282  }
283  g_free(info);
284  }
285 }
286 
287 GdkPixbuf* gen_probability_pixbuf(gint score_original, GNCImportSettings *settings, GtkWidget * widget)
288 {
289  GdkPixbuf* retval = NULL;
290  gint i, j;
291  gint score;
292  const gint height = 15;
293  const gint width_each_bar = 7;
294  gchar * green_bar = ("bggggb ");
295  gchar * yellow_bar = ("byyyyb ");
296  gchar * red_bar = ("brrrrb ");
297  gchar * black_bar = ("bbbbbb ");
298  const gint width_first_bar = 1;
299  gchar * black_first_bar = ("b");
300  const gint num_colors = 5;
301  gchar * size_str;
302  gchar * none_color_str = g_strdup_printf(" c None");
303  gchar * green_color_str = g_strdup_printf("g c green");
304  gchar * yellow_color_str = g_strdup_printf("y c yellow");
305  gchar * red_color_str = g_strdup_printf("r c red");
306  gchar * black_color_str = g_strdup_printf("b c black");
307  gchar * xpm[2+num_colors+height];
308  gint add_threshold, clear_threshold;
309 
310  g_assert(settings);
311  g_assert(widget);
312  if (score_original < 0)
313  {
314  score = 0;
315  }
316  else
317  {
318  score = score_original;
319  }
320  size_str = g_strdup_printf("%d%s%d%s%d%s", (width_each_bar * score) + width_first_bar/*width*/, " ", height, " ", num_colors, " 1"/*characters per pixel*/);
321 
322  /*DEBUG("Begin");*/
323  xpm[0] = size_str;
324  xpm[1] = none_color_str;
325  xpm[2] = green_color_str;
326  xpm[3] = yellow_color_str;
327  xpm[4] = red_color_str;
328  xpm[5] = black_color_str;
329  add_threshold = gnc_import_Settings_get_add_threshold(settings);
330  clear_threshold = gnc_import_Settings_get_clear_threshold(settings);
331 
332  for (i = 0; i < height; i++)
333  {
334  xpm[num_colors+1+i] = g_new0(char, (width_each_bar * score) + width_first_bar + 1);
335  for (j = 0; j <= score; j++)
336  {
337  if (i == 0 || i == height - 1)
338  {
339  if (j == 0)
340  {
341  strcat(xpm[num_colors+1+i], black_first_bar);
342  }
343  else
344  {
345  strcat(xpm[num_colors+1+i], black_bar);
346  }
347  }
348  else
349  {
350  if (j == 0)
351  {
352  strcat(xpm[num_colors+1+i], black_first_bar);
353  }
354  else if (j <= add_threshold)
355  {
356  strcat(xpm[num_colors+1+i], red_bar);
357  }
358  else if (j >= clear_threshold)
359  {
360  strcat(xpm[num_colors+1+i], green_bar);
361  }
362  else
363  {
364  strcat(xpm[num_colors+1+i], yellow_bar);
365  }
366  }
367  }
368  }
369 
370  retval = gdk_pixbuf_new_from_xpm_data((const gchar **)xpm);
371  for (i = 0; i <= num_colors + height; i++)
372  {
373  /*DEBUG("free_loop i=%d%s%s",i,": ",xpm[i]);*/
374  g_free(xpm[i]);
375  }
376 
377  return retval;
378 }
379 
380 /*************************************************************************
381  * MatchMap- related functions (storing and retrieving)
382  */
383 
384 /* Tokenize a string and append to an existing GList(or an empty GList)
385  * the tokens
386  */
387 static GList*
388 tokenize_string(GList* existing_tokens, const char *string)
389 {
390  char **tokenized_strings; /* array of strings returned by g_strsplit() */
391  char **stringpos;
392 
393  tokenized_strings = g_strsplit(string, " ", 0);
394  stringpos = tokenized_strings;
395 
396  /* add each token to the token GList */
397  while (stringpos && *stringpos)
398  {
399  if (strlen(*stringpos) > 0)
400  {
401  /* check for duplicated tokens */
402  gboolean duplicated = FALSE;
403  for (GList* token = existing_tokens; token != NULL; token = token->next)
404  {
405  if (g_strcmp0(token->data, *stringpos) == 0)
406  {
407  duplicated = TRUE;
408  break;
409  }
410  }
411  if (duplicated == FALSE)
412  {
413  /* prepend the char* to the token GList */
414  existing_tokens = g_list_prepend(existing_tokens, g_strdup(*stringpos));
415  }
416  }
417 
418  /* then move to the next string */
419  stringpos++;
420  }
421 
422  /* free up the strings that g_strsplit() created */
423  g_strfreev(tokenized_strings);
424 
425  return existing_tokens;
426 }
427 
428 /* create and return a list of tokens for a given transaction info. */
429 static GList*
430 TransactionGetTokens(GNCImportTransInfo *info)
431 {
432  Transaction* transaction;
433  GList* tokens;
434  const char* text;
435  time64 transtime;
436  struct tm *tm_struct;
437  char local_day_of_week[16];
438 
439  g_return_val_if_fail (info, NULL);
440  if (info->match_tokens) return info->match_tokens;
441 
442  transaction = gnc_import_TransInfo_get_trans(info);
443  g_assert(transaction);
444 
445  tokens = 0; /* start off with an empty list */
446 
447  /* make tokens from the transaction description */
448  text = xaccTransGetDescription(transaction);
449  tokens = tokenize_string(tokens, text);
450 
451  /* The day of week the transaction occurred is a good indicator of
452  * what account this transaction belongs in. Get the date and covert
453  * it to day of week as a token
454  */
455  transtime = xaccTransGetDate(transaction);
456  tm_struct = gnc_gmtime(&transtime);
457  if (!qof_strftime(local_day_of_week, sizeof(local_day_of_week), "%A", tm_struct))
458  {
459  PERR("TransactionGetTokens: error, strftime failed\n");
460  }
461  gnc_tm_free (tm_struct);
462  /* we cannot add a locally allocated string to this array, dup it so
463  * it frees the same way the rest do
464  */
465  tokens = g_list_prepend(tokens, g_strdup(local_day_of_week));
466 
467  /* make tokens from the memo of each split of this transaction */
468  for (GList *split=xaccTransGetSplitList (transaction); split; split=split->next)
469  {
470  text = xaccSplitGetMemo(split->data);
471  tokens = tokenize_string(tokens, text);
472  }
473 
474  /* remember the list of tokens for later.. */
475  info->match_tokens = tokens;
476 
477  /* return the pointer to the GList */
478  return tokens;
479 }
480 /* Destroy an import map. But all stored entries will still continue
481  * to exist in the underlying kvp frame of the account.
482  */
483 static void
484 gnc_imap_destroy (GncImportMatchMap *imap)
485 {
486  if (!imap) return;
487  g_free (imap);
488 }
489 
490 /* searches using the GNCImportTransInfo through all existing transactions
491  * if there is an exact match of the description and memo
492  */
493 static Account *
494 matchmap_find_destination (GncImportMatchMap *matchmap, GNCImportTransInfo *info)
495 {
496  GncImportMatchMap *tmp_map;
497  Account *result;
498  GList* tokens;
499  gboolean useBayes;
500 
501  g_assert (info);
502  tmp_map = ((matchmap != NULL) ? matchmap :
506 
507  useBayes = gnc_prefs_get_bool (GNC_PREFS_GROUP_IMPORT, GNC_PREF_USE_BAYES);
508  if (useBayes)
509  {
510  /* get the tokens for this transaction* */
511  tokens = TransactionGetTokens(info);
512 
513  /* try to find the destination account for this transaction from its tokens */
514  result = gnc_account_imap_find_account_bayes(tmp_map, tokens);
515 
516  }
517  else
518  {
519  /* old system of transaction to account matching */
520  result = gnc_account_imap_find_account
521  (tmp_map, GNCIMPORT_DESC,
523  }
524 
525  /* Disable matching by memo, until bayesian filtering is implemented.
526  * It's currently unlikely to help, and has adverse effects,
527  * causing false positives, since very often the type of the
528  * transaction is stored there.
529 
530  if (result == NULL)
531  result = gnc_account_imap_find_account
532  (tmp_map, GNCIMPORT_MEMO,
533  xaccSplitGetMemo (gnc_import_TransInfo_get_fsplit (info)));
534  */
535 
536  if (matchmap == NULL)
537  gnc_imap_destroy (tmp_map);
538 
539  return result;
540 }
541 
546 static void
547 matchmap_store_destination (GncImportMatchMap *matchmap,
548  GNCImportTransInfo *trans_info,
549  gboolean use_match)
550 {
551  GncImportMatchMap *tmp_matchmap = NULL;
552  Account *dest;
553  const char *descr, *memo;
554  GList *tokens;
555  gboolean useBayes;
556 
557  g_assert (trans_info);
558 
559  /* This will store the destination account of the selected match if
560  the reconcile match selected has only two splits. Good idea
561  Christian! */
562  dest = ((use_match) ?
566  (gnc_import_TransInfo_get_selected_match (trans_info)))) :
567  gnc_import_TransInfo_get_destacc (trans_info));
568  if (dest == NULL)
569  return;
570 
571  tmp_matchmap = ((matchmap != NULL) ?
572  matchmap :
575  (gnc_import_TransInfo_get_fsplit (trans_info))));
576 
577  /* see what matching system we are currently using */
578  useBayes = gnc_prefs_get_bool (GNC_PREFS_GROUP_IMPORT, GNC_PREF_USE_BAYES);
579  if (useBayes)
580  {
581  /* tokenize this transaction */
582  tokens = TransactionGetTokens(trans_info);
583 
584  /* add the tokens to the imap with the given destination account */
585  gnc_account_imap_add_account_bayes(tmp_matchmap, tokens, dest);
586 
587  }
588  else
589  {
590  /* old matching system */
592  (gnc_import_TransInfo_get_trans (trans_info));
593  if (descr && (strlen (descr) > 0))
594  gnc_account_imap_add_account (tmp_matchmap,
595  GNCIMPORT_DESC,
596  descr,
597  dest);
598  memo = xaccSplitGetMemo
599  (gnc_import_TransInfo_get_fsplit (trans_info));
600  if (memo && (strlen (memo) > 0))
601  gnc_account_imap_add_account (tmp_matchmap,
602  GNCIMPORT_MEMO,
603  memo,
604  dest);
605  } /* if(useBayes) */
606 
607  if (matchmap == NULL)
608  gnc_imap_destroy (tmp_matchmap);
609 }
610 
611 
612 
615 void split_find_match (GNCImportTransInfo * trans_info,
616  Split * split,
617  gint display_threshold,
618  gint date_threshold,
619  gint date_not_threshold,
620  double fuzzy_amount_difference)
621 {
622  /* DEBUG("Begin"); */
623 
624  /*Ignore the split if the transaction is open for edit, meaning it
625  was just downloaded. */
626  if (xaccTransIsOpen(xaccSplitGetParent(split)) == FALSE)
627  {
628  GNCImportMatchInfo * match_info;
629  gint prob = 0;
630  gboolean update_proposed;
631  double downloaded_split_amount, match_split_amount;
632  time64 match_time, download_time;
633  int datediff_day;
634  Transaction *new_trans = gnc_import_TransInfo_get_trans (trans_info);
635  Split *new_trans_fsplit = gnc_import_TransInfo_get_fsplit (trans_info);
636 
637  /* Matching heuristics */
638 
639  /* Amount heuristics */
640  downloaded_split_amount =
641  gnc_numeric_to_double (xaccSplitGetAmount(new_trans_fsplit));
642  /*DEBUG(" downloaded_split_amount=%f", downloaded_split_amount);*/
643  match_split_amount = gnc_numeric_to_double(xaccSplitGetAmount(split));
644  /*DEBUG(" match_split_amount=%f", match_split_amount);*/
645  if (fabs(downloaded_split_amount - match_split_amount) < 1e-6)
646  /* bug#347791: Double type shouldn't be compared for exact
647  equality, so we're using fabs() instead. */
648  /*if (gnc_numeric_equal(xaccSplitGetAmount
649  (new_trans_fsplit),
650  xaccSplitGetAmount(split)))
651  -- gnc_numeric_equal is an expensive function call */
652  {
653  prob = prob + 3;
654  /*DEBUG("heuristics: probability + 3 (amount)");*/
655  }
656  else if (fabs (downloaded_split_amount - match_split_amount) <=
657  fuzzy_amount_difference)
658  {
659  /* ATM fees are sometimes added directly in the transaction.
660  So you withdraw 100$ and get charged 101,25$ in the same
661  transaction */
662  prob = prob + 2;
663  /*DEBUG("heuristics: probability + 2 (amount)");*/
664  }
665  else
666  {
667  /* If a transaction's amount doesn't match within the
668  threshold, it's very unlikely to be the same transaction
669  so we give it an extra -5 penalty */
670  prob = prob - 5;
671  /* DEBUG("heuristics: probability - 1 (amount)"); */
672  }
673 
674  /* Date heuristics */
675  match_time = xaccTransGetDate (xaccSplitGetParent (split));
676  download_time = xaccTransGetDate (new_trans);
677  datediff_day = llabs(match_time - download_time) / 86400;
678  /* Sorry, there are not really functions around at all that
679  provide for less hacky calculation of days of date
680  differences. Whatever. On the other hand, the difference
681  calculation itself will work regardless of month/year
682  turnarounds. */
683  /*DEBUG("diff day %d", datediff_day);*/
684  if (datediff_day == 0)
685  {
686  prob = prob + 3;
687  /*DEBUG("heuristics: probability + 3 (date)");*/
688  }
689  else if (datediff_day <= date_threshold)
690  {
691  prob = prob + 2;
692  /*DEBUG("heuristics: probability + 2 (date)");*/
693  }
694  else if (datediff_day > date_not_threshold)
695  {
696  /* Extra penalty if that split lies awfully far away from
697  the given one. */
698  prob = prob - 5;
699  /*DEBUG("heuristics: probability - 5 (date)"); */
700  /* Changed 2005-02-21: Revert the hard-limiting behaviour
701  back to the previous large penalty. (Changed 2004-11-27:
702  The penalty is so high that we can forget about this
703  split anyway and skip the rest of the tests.) */
704  }
705 
706  /* Check if date and amount are identical */
707  update_proposed = (prob < 6);
708 
709  /* Check number heuristics */
710  {
711  const char *new_trans_str = gnc_get_num_action(new_trans, new_trans_fsplit);
712  if (new_trans_str && strlen(new_trans_str) != 0)
713  {
714  long new_trans_number, split_number;
715  const gchar *split_str;
716  char *endptr;
717  gboolean conversion_ok = TRUE;
718 
719  /* To distinguish success/failure after strtol call */
720  errno = 0;
721  new_trans_number = strtol(new_trans_str, &endptr, 10);
722  /* Possible addressed problems: over/underflow, only non
723  numbers on string and string empty */
724  if (errno || endptr == new_trans_str)
725  conversion_ok = FALSE;
726 
727  split_str = gnc_get_num_action (xaccSplitGetParent (split), split);
728  errno = 0;
729  split_number = strtol(split_str, &endptr, 10);
730  if (errno || endptr == split_str)
731  conversion_ok = FALSE;
732 
733  if ( (conversion_ok && (split_number == new_trans_number)) ||
734  (g_strcmp0(new_trans_str, split_str) == 0) )
735  {
736  /* An exact match of the Check number gives a +4 */
737  prob += 4;
738  /*DEBUG("heuristics: probability + 4 (Check number)");*/
739  }
740  else if (strlen(new_trans_str) > 0 && strlen(split_str) > 0)
741  {
742  /* If both number are not empty yet do not match, add a
743  little extra penalty */
744  prob -= 2;
745  }
746  }
747  }
748 
749  /* Memo heuristics */
750  {
751  const char *memo = xaccSplitGetMemo(new_trans_fsplit);
752  if (memo && strlen(memo) != 0)
753  {
754  if (safe_strcasecmp(memo, xaccSplitGetMemo(split)) == 0)
755  {
756  /* An exact match of memo gives a +2 */
757  prob = prob + 2;
758  /* DEBUG("heuristics: probability + 2 (memo)"); */
759  }
760  else if ((strncasecmp(memo, xaccSplitGetMemo(split),
761  strlen(xaccSplitGetMemo(split)) / 2)
762  == 0))
763  {
764  /* Very primitive fuzzy match worth +1. This matches the
765  first 50% of the strings to skip annoying transaction
766  number some banks seem to include in the memo but someone
767  should write something more sophisticated */
768  prob = prob + 1;
769  /*DEBUG("heuristics: probability + 1 (memo)"); */
770  }
771  }
772  }
773 
774  /* Description heuristics */
775  {
776  const char *descr = xaccTransGetDescription(new_trans);
777  if (descr && strlen(descr) != 0)
778  {
779  if (safe_strcasecmp(descr,
781  == 0)
782  {
783  /*An exact match of Description gives a +2 */
784  prob = prob + 2;
785  /*DEBUG("heuristics: probability + 2 (description)");*/
786  }
787  else if ((strncasecmp(descr,
789  strlen(xaccTransGetDescription (new_trans)) / 2)
790  == 0))
791  {
792  /* Very primitive fuzzy match worth +1. This matches the
793  first 50% of the strings to skip annoying transaction
794  number some banks seem to include in the memo but someone
795  should write something more sophisticated */
796  prob = prob + 1;
797  /*DEBUG("heuristics: probability + 1 (description)"); */
798  }
799  }
800  }
801 
802  /* Is the probability high enough? Otherwise do nothing and return. */
803  if (prob < display_threshold)
804  {
805  return;
806  }
807 
808  /* The probability is high enough, so allocate an object
809  here. Allocating it only when it's actually being used is
810  probably quite some performance gain. */
811  match_info = g_new0(GNCImportMatchInfo, 1);
812 
813  match_info->probability = prob;
814  match_info->update_proposed = update_proposed;
815  match_info->split = split;
816  match_info->trans = xaccSplitGetParent(split);
817 
818 
819  /* Append that to the list. Do not use g_list_append because
820  it is slow. The list is sorted afterwards anyway. */
821  trans_info->match_list =
822  g_list_prepend(trans_info->match_list,
823  match_info);
824  }
825 }/* end split_find_match */
826 
827 /***********************************************************************
828  */
829 
832 gboolean
834  GNCImportTransInfo *trans_info)
835 {
836  Split * other_split;
837  gnc_numeric imbalance_value;
838  Transaction *trans;
839 
840  /* DEBUG("Begin"); */
841 
842  g_assert (trans_info);
843  /*DEBUG("Iteration %d, action %d, split %s", i,
844  trans_info->action,
845  xaccTransGetDescription (gnc_import_TransInfo_get_trans
846  (trans_info)))*/
847  switch (gnc_import_TransInfo_get_action (trans_info))
848  {
849  case GNCImport_SKIP:
850  return FALSE;
851  case GNCImport_ADD:
852  /* Transaction gets imported. */
853 
854  /* Is the transaction not balanced and there is a non-NULL destination account? */
855  if (gnc_import_TransInfo_is_balanced(trans_info) == FALSE
856  && gnc_import_TransInfo_get_destacc(trans_info) != NULL)
857  {
858  /* Create the 'other' split. */
859  Split *split =
861  (gnc_account_get_book
862  (gnc_import_TransInfo_get_destacc (trans_info)));
864  (gnc_import_TransInfo_get_trans (trans_info), split);
866  (gnc_import_TransInfo_get_destacc (trans_info), split);
867  /*xaccSplitSetBaseValue
868  (split,
869  gnc_numeric_neg(xaccTransGetImbalance
870  (gnc_import_TransInfo_get_trans (trans_info))),
871  xaccTransGetCurrency
872  (gnc_import_TransInfo_get_trans (trans_info)));*/
873  {
874  /* This is a quick workaround for the bug described in
875  http://lists.gnucash.org/pipermail/gnucash-devel/2003-August/009982.html
876  Assume that importers won't create transactions involving two or more
877  currencies so we can use xaccTransGetImbalanceValue. */
878  imbalance_value =
880  (gnc_import_TransInfo_get_trans (trans_info)));
881  xaccSplitSetValue (split, imbalance_value);
882  xaccSplitSetAmount (split, imbalance_value);
883  }
884  /*xaccSplitSetMemo (split, _("Auto-Balance split"));
885  -- disabled due to popular request */
886  }
887 
889  /*Set reconcile date to today*/
891  gnc_time (NULL));
892  /* Done editing. */
893  trans = gnc_import_TransInfo_get_trans (trans_info);
894  xaccTransCommitEdit(trans);
895  xaccTransRecordPrice(trans, PRICE_SOURCE_SPLIT_IMPORT);
896  return TRUE;
897  case GNCImport_UPDATE:
898  {
899  GNCImportMatchInfo *selected_match =
901 
902  /* If there is no selection, ignore this transaction. */
903  if (!selected_match)
904  {
905  PWARN("No matching translaction to be cleared was chosen. Imported transaction will be ignored.");
906  break;
907  }
908 
909  /* Transaction gets not imported but the matching one gets
910  updated and reconciled. */
911  if (gnc_import_MatchInfo_get_split(selected_match) == NULL)
912  {
913  PERR("The split I am trying to update and reconcile is NULL, shouldn't happen!");
914  }
915  else
916  {
917  /* Update and reconcile the matching transaction */
918  /*DEBUG("BeginEdit selected_match")*/
919  xaccTransBeginEdit(selected_match->trans);
920 
921  xaccTransSetDatePostedSecsNormalized(selected_match->trans,
923  gnc_import_TransInfo_get_fsplit(trans_info))));
924 
925  xaccSplitSetAmount(selected_match->split,
927  gnc_import_TransInfo_get_fsplit(trans_info)));
928  xaccSplitSetValue(selected_match->split,
930  gnc_import_TransInfo_get_fsplit(trans_info)));
931 
932  imbalance_value = xaccTransGetImbalanceValue(
933  gnc_import_TransInfo_get_trans(trans_info));
934  other_split = xaccSplitGetOtherSplit(selected_match->split);
935  if (!gnc_numeric_zero_p(imbalance_value) && other_split)
936  {
937  if (xaccSplitGetReconcile(other_split) == NREC)
938  {
939  imbalance_value = gnc_numeric_neg(imbalance_value);
940  xaccSplitSetValue(other_split, imbalance_value);
941  xaccSplitSetAmount(other_split, imbalance_value);
942  }
943  /* else GC will automatically insert a split to equity
944  to balance the transaction */
945  }
946 
947  xaccTransSetDescription(selected_match->trans,
949  gnc_import_TransInfo_get_trans(trans_info)));
950 
951  xaccTransSetNotes(selected_match->trans,
953  gnc_import_TransInfo_get_trans(trans_info)));
954 
955  if (xaccSplitGetReconcile(selected_match->split) == NREC)
956  {
957  xaccSplitSetReconcile(selected_match->split, CREC);
958  }
959 
960  /* Set reconcile date to today */
961  xaccSplitSetDateReconciledSecs(selected_match->split, gnc_time (NULL));
962 
963  /* Copy the online id to the reconciled transaction, so
964  the match will be remembered */
965  if (gnc_import_split_has_online_id(trans_info->first_split))
966  {
967  gnc_import_set_split_online_id(selected_match->split,
968  gnc_import_get_split_online_id(trans_info->first_split));
969  }
970 
971  /* Done editing. */
972  /*DEBUG("CommitEdit selected_match")*/
973  xaccTransCommitEdit(selected_match->trans);
974 
975  /* Store the mapping to the other account in the MatchMap. */
976  matchmap_store_destination(matchmap, trans_info, TRUE);
977 
978  /* Erase the downloaded transaction */
979  xaccTransDestroy(trans_info->trans);
980  /*DEBUG("CommitEdit trans")*/
981  xaccTransCommitEdit(trans_info->trans);
982  /* Very important: Make sure the freed transaction is not freed again! */
983  trans_info->trans = NULL;
984  }
985  }
986  return TRUE;
987  case GNCImport_CLEAR:
988  {
989  GNCImportMatchInfo *selected_match =
991 
992  /* If there is no selection, ignore this transaction. */
993  if (!selected_match)
994  {
995  PWARN("No matching translaction to be cleared was chosen. Imported transaction will be ignored.");
996  break;
997  }
998 
999  /* Transaction gets not imported but the matching one gets
1000  reconciled. */
1001  if (gnc_import_MatchInfo_get_split (selected_match) == NULL)
1002  {
1003  PERR("The split I am trying to reconcile is NULL, shouldn't happen!");
1004  }
1005  else
1006  {
1007  /* Reconcile the matching transaction */
1008  /*DEBUG("BeginEdit selected_match")*/
1009  xaccTransBeginEdit(selected_match->trans);
1010 
1012  (selected_match->split) == NREC)
1014  (selected_match->split, CREC);
1015  /* Set reconcile date to today */
1017  (selected_match->split, gnc_time (NULL));
1018 
1019  /* Copy the online id to the reconciled transaction, so
1020  the match will be remembered */
1021  if (gnc_import_split_has_online_id(trans_info->first_split))
1022  gnc_import_set_split_online_id
1023  (selected_match->split,
1024  gnc_import_get_split_online_id(trans_info->first_split));
1025 
1026  /* Done editing. */
1027  /*DEBUG("CommitEdit selected_match")*/
1029  (selected_match->trans);
1030 
1031  /* Store the mapping to the other account in the MatchMap. */
1032  matchmap_store_destination (matchmap, trans_info, TRUE);
1033 
1034  /* Erase the downloaded transaction */
1035  xaccTransDestroy(trans_info->trans);
1036  /*DEBUG("CommitEdit trans")*/
1037  xaccTransCommitEdit(trans_info->trans);
1038  /* Very important: Make sure the freed transaction is not freed again! */
1039  trans_info->trans = NULL;
1040  }
1041  }
1042  return TRUE;
1043  default:
1044  DEBUG("Invalid GNCImportAction for this imported transaction.");
1045  break;
1046  }
1047  /*DEBUG("End");*/
1048  return FALSE;
1049 }
1050 
1051 /********************************************************************\
1052  * check_trans_online_id() Callback function used by
1053  * gnc_import_exists_online_id. Takes pointers to transaction and split,
1054  * returns 0 if their online_ids do NOT match, or if the split
1055  * belongs to the transaction
1056 \********************************************************************/
1057 static gint check_trans_online_id(Transaction *trans1, void *user_data)
1058 {
1059  Account *account;
1060  Split *split1;
1061  Split *split2 = user_data;
1062  const gchar *online_id1;
1063  const gchar *online_id2;
1064 
1065  account = xaccSplitGetAccount(split2);
1066  split1 = xaccTransFindSplitByAccount(trans1, account);
1067  if (split1 == split2)
1068  return 0;
1069 
1070  /* hack - we really want to iterate over the _splits_ of the account
1071  instead of the transactions */
1072  g_assert(split1 != NULL);
1073 
1074  if (gnc_import_split_has_online_id(split1))
1075  online_id1 = gnc_import_get_split_online_id(split1);
1076  else
1077  online_id1 = gnc_import_get_trans_online_id(trans1);
1078 
1079  online_id2 = gnc_import_get_split_online_id(split2);
1080 
1081  if ((online_id1 == NULL) ||
1082  (online_id2 == NULL) ||
1083  (strcmp(online_id1, online_id2) != 0))
1084  {
1085  return 0;
1086  }
1087  else
1088  {
1089  /*printf("test_trans_online_id(): Duplicate found\n");*/
1090  return 1;
1091  }
1092 }
1093 
1096 gboolean gnc_import_exists_online_id (Transaction *trans, GHashTable* acct_id_hash)
1097 {
1098  gboolean online_id_exists = FALSE;
1099  Account *dest_acct;
1100  Split *source_split;
1101 
1102  /* Look for an online_id in the first split */
1103  source_split = xaccTransGetSplit(trans, 0);
1104  g_assert(source_split);
1105 
1106  // No online id, no point in continuing. We'd crash if we tried.
1107  if (!gnc_import_get_split_online_id (source_split))
1108  return FALSE;
1109  // Create a hash per account of a hash of all split IDs. Then the test below will be fast if
1110  // we have many transactions to import.
1111  dest_acct = xaccSplitGetAccount (source_split);
1112  if (!g_hash_table_contains (acct_id_hash, dest_acct))
1113  {
1114  GHashTable* new_hash = g_hash_table_new (g_str_hash, g_str_equal);
1115  GList* split_list = xaccAccountGetSplitList(dest_acct);
1116  g_hash_table_insert (acct_id_hash, dest_acct, new_hash);
1117  for (;split_list;split_list=split_list->next)
1118  {
1119  if (gnc_import_split_has_online_id (split_list->data))
1120  g_hash_table_add (new_hash, (void*) gnc_import_get_split_online_id (split_list->data));
1121  }
1122  }
1123  online_id_exists = g_hash_table_contains (g_hash_table_lookup (acct_id_hash, dest_acct),
1124  gnc_import_get_split_online_id (source_split));
1125 
1126  /* If it does, abort the process for this transaction, since it is
1127  already in the system. */
1128  if (online_id_exists == TRUE)
1129  {
1130  DEBUG("%s", "Transaction with same online ID exists, destroying current transaction");
1131  xaccTransDestroy(trans);
1132  xaccTransCommitEdit(trans);
1133  }
1134  return online_id_exists;
1135 }
1136 
1137 
1138 /* ******************************************************************
1139  */
1140 
1142 GNCImportTransInfo *
1143 gnc_import_TransInfo_new (Transaction *trans, GncImportMatchMap *matchmap)
1144 {
1145  GNCImportTransInfo *transaction_info;
1146  Split *split;
1147  g_assert (trans);
1148 
1149  transaction_info = g_new0(GNCImportTransInfo, 1);
1150 
1151  transaction_info->trans = trans;
1152  /* Only use first split, the source split */
1153  split = xaccTransGetSplit(trans, 0);
1154  g_assert(split);
1155  transaction_info->first_split = split;
1156 
1157  /* Try to find a previously selected destination account
1158  string match for the ADD action */
1159  gnc_import_TransInfo_set_destacc (transaction_info,
1160  matchmap_find_destination (matchmap, transaction_info),
1161  FALSE);
1162  return transaction_info;
1163 }
1164 
1165 
1167 static gint compare_probability (gconstpointer a,
1168  gconstpointer b)
1169 {
1170  return(((GNCImportMatchInfo *)b)->probability -
1171  ((GNCImportMatchInfo *)a)->probability);
1172 }
1173 
1178 void
1179 gnc_import_TransInfo_init_matches (GNCImportTransInfo *trans_info,
1180  GNCImportSettings *settings)
1181 {
1182  GNCImportMatchInfo * best_match = NULL;
1183  g_assert (trans_info);
1184 
1185  if (trans_info->match_list != NULL)
1186  {
1187  trans_info->match_list = g_list_sort(trans_info->match_list,
1188  compare_probability);
1189  best_match = g_list_nth_data(trans_info->match_list, 0);
1191  best_match,
1192  FALSE);
1193  if (best_match != NULL &&
1194  best_match->probability >= gnc_import_Settings_get_clear_threshold(settings))
1195  {
1196  trans_info->action = GNCImport_CLEAR;
1197  }
1198  else if (best_match == NULL ||
1199  best_match->probability <= gnc_import_Settings_get_add_threshold(settings))
1200  {
1201  trans_info->action = GNCImport_ADD;
1202  }
1204  {
1205  trans_info->action = GNCImport_SKIP;
1206  }
1208  {
1209  trans_info->action = GNCImport_UPDATE;
1210  }
1211  else
1212  {
1213  trans_info->action = GNCImport_ADD;
1214  }
1215  }
1216  else
1217  {
1218  trans_info->action = GNCImport_ADD;
1219  }
1220  if (best_match &&
1221  trans_info->action == GNCImport_CLEAR &&
1223  {
1224  if (best_match->update_proposed)
1225  {
1226  trans_info->action = GNCImport_UPDATE;
1227  }
1228  }
1229 
1230  trans_info->previous_action = trans_info->action;
1231 }
1232 
1233 
1234 /* Try to automatch a transaction to a destination account if the */
1235 /* transaction hasn't already been manually assigned to another account */
1236 gboolean
1237 gnc_import_TransInfo_refresh_destacc (GNCImportTransInfo *transaction_info,
1238  GncImportMatchMap *matchmap)
1239 {
1240  Account *orig_destacc;
1241  Account *new_destacc = NULL;
1242  g_assert(transaction_info);
1243 
1244  orig_destacc = gnc_import_TransInfo_get_destacc(transaction_info);
1245 
1246  /* if we haven't manually selected a destination account for this transaction */
1247  if (gnc_import_TransInfo_get_destacc_selected_manually(transaction_info) == FALSE)
1248  {
1249  /* Try to find the destination account for this transaction based on prior ones */
1250  new_destacc = matchmap_find_destination(matchmap, transaction_info);
1251  gnc_import_TransInfo_set_destacc(transaction_info, new_destacc, FALSE);
1252  }
1253  else
1254  {
1255  new_destacc = orig_destacc;
1256  }
1257 
1258  /* account has changed */
1259  if (new_destacc != orig_destacc)
1260  {
1261  return TRUE;
1262  }
1263  else /* account is the same */
1264  {
1265  return FALSE;
1266  }
1267 }
1268 
1269 
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
gsize qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
qof_strftime calls qof_format_time to print a given time and afterwards tries to put the result into ...
Definition: gnc-date.cpp:1058
GNCImportTransInfo * gnc_import_TransInfo_new(Transaction *trans, GncImportMatchMap *matchmap)
Create a new object of GNCImportTransInfo here.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:362
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
gint gnc_import_Settings_get_clear_threshold(GNCImportSettings *settings)
Return the selected threshold.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
void gnc_import_TransInfo_set_selected_match_info(GNCImportTransInfo *info, GNCImportMatchInfo *match, gboolean selected_manually)
Sets the currently selected match in this TransInfo.
SplitList * xaccAccountGetSplitList(const Account *acc)
The xaccAccountGetSplitList() routine returns a pointer to a GList of the splits in the account...
Definition: Account.cpp:3964
void split_find_match(GNCImportTransInfo *trans_info, Split *split, gint display_threshold, gint date_threshold, gint date_not_threshold, double fuzzy_amount_difference)
The transaction matching heuristics are here.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
utility functions for the GnuCash UI
GdkPixbuf * gen_probability_pixbuf(gint score_original, GNCImportSettings *settings, GtkWidget *widget)
This function generates a new pixmap representing a match score.
void gnc_import_TransInfo_delete(GNCImportTransInfo *info)
Destructor.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
void gnc_import_TransInfo_set_ref_id(GNCImportTransInfo *info, guint32 ref_id)
Set the reference id for this TransInfo.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
#define GNC_PREFS_GROUP_IMPORT
The preferences used by the importer.
Generic importer backend interface.
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
gint safe_strcasecmp(const gchar *da, const gchar *db)
case sensitive comparison of strings da and db - either may be NULL.
Definition: qofutil.cpp:100
Split * gnc_import_TransInfo_get_fsplit(const GNCImportTransInfo *info)
Returns the first split of the transaction of this TransInfo.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
Transaction * gnc_import_TransInfo_get_trans(const GNCImportTransInfo *info)
Returns the transaction of this TransInfo.
void xaccTransRecordPrice(Transaction *trans, PriceSource source)
The xaccTransRecordPrice() method iterates through the splits and and record the non-currency equival...
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void gnc_import_TransInfo_set_destacc(GNCImportTransInfo *info, Account *acc, gboolean selected_manually)
Set the &#39;other account&#39; of this transaction (used for auto-balance if needed).
guint32 gnc_import_TransInfo_get_ref_id(const GNCImportTransInfo *info)
Returns the reference id for this TransInfo.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
void gnc_import_TransInfo_init_matches(GNCImportTransInfo *trans_info, GNCImportSettings *settings)
Iterates through all splits of the originating account of trans_info.
Account * gnc_account_imap_find_account_bayes(GncImportMatchMap *imap, GList *tokens)
Look up an Account in the map.
Definition: Account.cpp:5793
GNCImportAction gnc_import_TransInfo_get_action(const GNCImportTransInfo *info)
Returns the currently selected action for this TransInfo.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
Definition: gnc-date.cpp:99
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
Split * gnc_import_MatchInfo_get_split(const GNCImportMatchInfo *info)
Get the split (&#39;this-side split&#39;) of this MatchInfo.
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
gint gnc_import_MatchInfo_get_probability(const GNCImportMatchInfo *info)
Get the probability (confidence level) of this MatchInfo.
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
void gnc_account_imap_add_account_bayes(GncImportMatchMap *imap, GList *tokens, Account *acc)
Updates the imap for a given account using a list of tokens.
Definition: Account.cpp:5856
Account handling public routines.
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
The xaccTransGetImbalanceValue() method returns the total value of the transaction.
gboolean gnc_import_process_trans_item(GncImportMatchMap *matchmap, GNCImportTransInfo *trans_info)
/brief – Processes one match according to its selected action.
void gnc_import_TransInfo_set_action(GNCImportTransInfo *info, GNCImportAction action)
Set the action for this TransInfo.
gboolean gnc_import_exists_online_id(Transaction *trans, GHashTable *acct_id_hash)
Checks whether the given transaction&#39;s online_id already exists in its parent account.
gboolean gnc_import_TransInfo_refresh_destacc(GNCImportTransInfo *transaction_info, GncImportMatchMap *matchmap)
Try to automatch a given transaction to a destination account.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
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.
#define CREC
The Split has been cleared.
Definition: Split.h:71
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
GncImportMatchMap * gnc_account_imap_create_imap(Account *acc)
Obtain an ImportMatchMap object from an Account or a Book.
Definition: Account.cpp:5423
Generic api to store and retrieve preferences.
void gnc_import_TransInfo_set_match_list(GNCImportTransInfo *info, GList *match_list)
Assigns the list of possible matches.
void xaccSplitSetDateReconciledSecs(Split *split, time64 secs)
Set the date on which this split was reconciled by specifying the time as time64. ...
gboolean gnc_import_Settings_get_action_update_enabled(GNCImportSettings *settings)
Return the selected action is enable state.
gboolean gnc_import_TransInfo_get_match_selected_manually(const GNCImportTransInfo *info)
Returns if the currently selected match was selected by the user.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
Utility functions for writing import modules.
Account * gnc_import_TransInfo_get_destacc(const GNCImportTransInfo *info)
Returns the &#39;other account&#39; of this transaction.
struct tm * gnc_gmtime(const time64 *secs)
fill out a time struct from a 64-bit time value
Definition: gnc-date.cpp:189
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
GList * gnc_import_TransInfo_get_match_list(const GNCImportTransInfo *info)
Returns the stored list of possible matches.
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
GNCImportMatchInfo * gnc_import_TransInfo_get_selected_match(const GNCImportTransInfo *info)
Returns the currently selected match in this TransInfo.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gboolean gnc_import_Settings_get_action_skip_enabled(GNCImportSettings *settings)
Return the selected action is enable state.
gboolean gnc_import_TransInfo_is_balanced(const GNCImportTransInfo *info)
Returns if the transaction stored in the TransInfo is currently balanced.
gint gnc_import_Settings_get_add_threshold(GNCImportSettings *settings)
Return the selected threshold.
#define NREC
not reconciled or cleared
Definition: Split.h:74
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69
gboolean gnc_import_TransInfo_get_destacc_selected_manually(const GNCImportTransInfo *info)
Returns if the currently selected destination account for auto-matching was selected by the user...