GnuCash  5.6-150-g038405b370+
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
import-backend.cpp
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 "Account.hpp"
42 #include "Query.h"
43 #include "gnc-engine.h"
44 #include "engine-helpers.h"
45 #include "gnc-prefs.h"
46 #include "gnc-ui-util.h"
47 
48 #include <algorithm>
49 
50 #define GNCIMPORT_DESC "desc"
51 #define GNCIMPORT_MEMO "memo"
52 #define GNCIMPORT_PAYEE "payee"
53 
54 /********************************************************************\
55  * Constants *
56 \********************************************************************/
57 
58 static QofLogModule log_module = GNC_MOD_IMPORT;
59 
60 /********************************************************************\
61  * Forward declared prototypes *
62 \********************************************************************/
63 
64 static void matchmap_store_destination(Account* base_acc,
65  GNCImportTransInfo* trans_info,
66  gboolean use_match);
67 
68 static void trans_info_calculate_dest_amount (GNCImportTransInfo *info);
69 
70 
71 /********************************************************************\
72  * Structures passed between the functions *
73 \********************************************************************/
74 
76 {
77  GNCImportMatchInfo *selected_match;
78  gboolean selected_manually;
79 };
80 
82 {
83  Transaction * trans;
84  Split * first_split;
85 
86  /* GList of GNCImportMatchInfo's, one for each possible duplicate match. */
87  GList * match_list;
88  GNCImportSelectedMatchInfo selected_match_info;
89 
90  GNCImportAction action;
91  GNCImportAction previous_action;
92 
93  /* A list of tokenized strings to use for bayesian matching purposes */
94  GList * match_tokens;
95 
96  /* In case of a single destination account it is stored here. */
97  Account *dest_acc;
98  gboolean dest_acc_selected_manually;
99 
100  /* Reference id to link gnc transaction to external object. E.g. aqbanking job id. */
101  guint32 ref_id;
102 
103  /* When updating a matched transaction, append Description and Notes instead of replacing */
104  gboolean append_text;
105 
106  /* Extra data we can use to build the balancing split. It may be passed on by the
107  * code that calls the generic importer */
108  gnc_numeric lsplit_price;
109  char *lsplit_action;
110  char *lsplit_memo;
111  char lsplit_rec_state;
112  time64 lsplit_rec_date;
113 
114  gnc_numeric lsplit_value;
115  /* Amount for the balancing split. This may be passed by the import front-
116  * ends or calculated. The latter is only possible when
117  * the destination account is known and may require an exchange rate
118  * if that account is not in the same commodity as the transaction. */
119  gnc_numeric lsplit_amount;
120  gboolean lsplit_amount_selected_manually;
121 };
122 
123 /* Some simple getters and setters for the above data types. */
124 
125 GList *
126 gnc_import_TransInfo_get_match_list (const GNCImportTransInfo *info)
127 {
128  g_assert (info);
129  return info->match_list;
130 }
131 
132 void
133 gnc_import_TransInfo_remove_top_match (GNCImportTransInfo *info)
134 {
135  g_return_if_fail (info);
136  info->match_list = g_list_remove (info->match_list, static_cast<gpointer>(info->match_list->data));
137  if (info->match_list)
138  info->selected_match_info.selected_match = static_cast<GNCImportMatchInfo*>(info->match_list->data);
139  else
140  {
141  info->selected_match_info.selected_match = nullptr;
142  gnc_import_TransInfo_set_action (info, GNCImport_ADD);
143  };
144 }
145 
146 Transaction *
147 gnc_import_TransInfo_get_trans (const GNCImportTransInfo *info)
148 {
149  g_assert (info);
150  return info->trans;
151 }
152 
153 gboolean
154 gnc_import_TransInfo_is_balanced (const GNCImportTransInfo *info)
155 {
156  g_assert (info);
158 }
159 
160 Split *
161 gnc_import_TransInfo_get_fsplit (const GNCImportTransInfo *info)
162 {
163  g_assert (info);
164  return info->first_split;
165 }
166 
168 gnc_import_TransInfo_get_selected_match (const GNCImportTransInfo *info)
169 {
170  g_assert (info);
171  return info->selected_match_info.selected_match;
172 }
173 
174 void
176  GNCImportMatchInfo *match,
177  gboolean selected_manually)
178 {
179  g_assert (info);
180  info->selected_match_info.selected_match = match;
181  info->selected_match_info.selected_manually = selected_manually;
182 }
183 
184 gboolean
185 gnc_import_TransInfo_get_match_selected_manually (const GNCImportTransInfo *info)
186 {
187  g_assert (info);
188  return info->selected_match_info.selected_manually;
189 }
190 
191 GNCImportAction
192 gnc_import_TransInfo_get_action (const GNCImportTransInfo *info)
193 {
194  g_assert (info);
195  return info->action;
196 }
197 
198 void
199 gnc_import_TransInfo_set_action (GNCImportTransInfo *info,
200  GNCImportAction action)
201 {
202  g_assert (info);
203  if (action != info->action)
204  {
205  info->previous_action = info->action;
206  info->action = action;
207  }
208 }
209 
210 Account *
211 gnc_import_TransInfo_get_destacc (const GNCImportTransInfo *info)
212 {
213  g_assert (info);
214  return info->dest_acc;
215 }
216 void gnc_import_TransInfo_set_destacc (GNCImportTransInfo *info,
217  Account *acc,
218  gboolean selected_manually)
219 {
220  g_assert (info);
221  info->dest_acc = acc;
222  info->dest_acc_selected_manually = selected_manually;
223 
224  /* Store the mapping to the other account in the MatchMap. */
225  if (selected_manually)
226  matchmap_store_destination (nullptr, info, false);
227 
228  trans_info_calculate_dest_amount (info);
229 }
230 
231 gboolean
233 {
234  g_assert (info);
235  return info->dest_acc_selected_manually;
236 }
237 
238 guint32
239 gnc_import_TransInfo_get_ref_id (const GNCImportTransInfo *info)
240 {
241  g_assert (info);
242  return info->ref_id;
243 }
244 
245 void
246 gnc_import_TransInfo_set_ref_id (GNCImportTransInfo *info,
247  guint32 ref_id)
248 {
249  g_assert (info);
250  info->ref_id = ref_id;
251 }
252 
253 gnc_numeric
254 gnc_import_TransInfo_get_price (const GNCImportTransInfo *info)
255 {
256  g_assert (info);
257  return info->lsplit_price;
258 }
259 
260 void
261 gnc_import_TransInfo_set_price (GNCImportTransInfo *info,
262  gnc_numeric lprice)
263 {
264  g_assert (info);
265  info->lsplit_price = lprice;
266  /* if a valid price is explicitly set, assume the user wants to
267  * use it to calculate balance split amount.
268  * Ensure this gets recalculated */
269  if (gnc_numeric_check (lprice) == 0)
270  {
271  info->lsplit_amount_selected_manually = false;
272  trans_info_calculate_dest_amount(info);
273  }
274 }
275 
276 gnc_numeric
277 gnc_import_TransInfo_get_dest_amount (const GNCImportTransInfo *info)
278 {
279  g_assert (info);
280  return info->lsplit_amount;
281 }
282 
283 gnc_numeric
284 gnc_import_TransInfo_get_dest_value (const GNCImportTransInfo *info)
285 {
286  g_assert (info);
287  return info->lsplit_value;
288 }
289 
290 void
292  GNCImportLastSplitInfo *lsplit)
293 {
294  g_assert (info);
295  if (lsplit)
296  {
297  info->lsplit_price = lsplit->price;
298  info->lsplit_action = g_strdup(lsplit->action);
299  info->lsplit_memo = g_strdup(lsplit->memo);
300  if (gnc_numeric_check (lsplit->amount) == 0)
301  {
302  info->lsplit_amount = lsplit->amount;
303  info->lsplit_amount_selected_manually = true;
304  }
305  /* Bayesian matching may have already set a candidate destination
306  * account. However if the csv data also provides one, the one from the
307  * csv data is preferred. */
308  if (lsplit->account)
309  info->dest_acc = lsplit->account;
310  info->lsplit_rec_state = lsplit->rec_state;
311  info->lsplit_rec_date = lsplit->rec_date;
312  }
313 }
314 
315 void
316 gnc_import_TransInfo_set_append_text (GNCImportTransInfo *info,
317  gboolean append_text)
318 {
319  g_assert (info);
320  info->append_text = append_text;
321 }
322 
323 
324 Split *
326 {
327  g_assert (info);
328  return info->split;
329 }
330 
331 gint
333 {
334  if (info)
335  return info->probability;
336  else
337  return 0;
338 }
339 
340 void gnc_import_TransInfo_delete (GNCImportTransInfo *info)
341 {
342  if (info)
343  {
344  g_list_free_full (info->match_list, g_free);
345  /*If the transaction exists and is still open, it must be destroyed*/
346  if (xaccTransIsOpen(info->trans))
347  {
348  xaccTransDestroy(info->trans);
349  xaccTransCommitEdit(info->trans);
350  }
351  g_list_free_full (info->match_tokens, g_free);
352  g_free(info->lsplit_action);
353  g_free(info->lsplit_memo);
354 
355  g_free(info);
356  }
357 }
358 
359 GdkPixbuf* gen_probability_pixbuf(gint score_original, GNCImportSettings *settings, GtkWidget * widget)
360 {
361  constexpr gint height = 15;
362  constexpr gint width_each_bar = 7;
363  constexpr gint width_first_bar = 1;
364  constexpr gint num_colors = 5;
365  gchar * xpm[2 + num_colors + height];
366 
367  g_assert(settings);
368  g_assert(widget);
369 
370  auto score = std::max (0, score_original);
371 
372  /* Add size definition to xpm */
373  xpm[0] = g_strdup_printf("%d%s%d%s%d%s", (width_each_bar * score) + width_first_bar/*width*/, " ", height, " ", num_colors, " 1"/*characters per pixel*/);
374 
375  /* Define used colors */
376  xpm[1] = g_strdup(" c None");
377  xpm[2] = g_strdup("g c green");
378  xpm[3] = g_strdup("y c yellow");
379  xpm[4] = g_strdup("r c red");
380  xpm[5] = g_strdup("b c black");
381 
382  auto add_threshold = gnc_import_Settings_get_add_threshold(settings);
383  auto clear_threshold = gnc_import_Settings_get_clear_threshold(settings);
384  for (int i = 0; i < height; i++)
385  {
386  xpm[num_colors+1+i] = g_new0(char, (width_each_bar * score) + width_first_bar + 1);
387  for (int j = 0; j <= score; j++)
388  {
389  if (j == 0)
390  strcat(xpm[num_colors+1+i], "b");
391  else if (i == 0 || i == height - 1)
392  strcat(xpm[num_colors+1+i], "bbbbbb ");
393  else if (j <= add_threshold)
394  strcat(xpm[num_colors+1+i], "brrrrb ");
395  else if (j >= clear_threshold)
396  strcat(xpm[num_colors+1+i], "bggggb ");
397  else
398  strcat(xpm[num_colors+1+i], "byyyyb ");
399  }
400  }
401 
402  auto retval = gdk_pixbuf_new_from_xpm_data((const gchar **)xpm);
403  for (int i = 0; i <= num_colors + height; i++)
404  g_free(xpm[i]);
405 
406  return retval;
407 }
408 
409 /*************************************************************************
410  * MatchMap related functions (storing and retrieving)
411  */
412 
413 /* Tokenize a string and append the tokens to an existing GList
414  * (or an empty GList)
415  */
416 static GList*
417 tokenize_string(GList* existing_tokens, const char *string)
418 {
419  char **tokenized_strings = g_strsplit(string, " ", 0);
420  char **stringpos = tokenized_strings;
421 
422  /* add each unique non-empty token to the token GList */
423  while (stringpos && *stringpos)
424  {
425  if ((strlen(*stringpos) > 0) &&
426  (!g_list_find_custom (existing_tokens, *stringpos, (GCompareFunc)g_strcmp0)))
427  existing_tokens = g_list_prepend(existing_tokens, g_strdup(*stringpos));
428 
429  stringpos++;
430  }
431 
432  /* free up the strings that g_strsplit() created */
433  g_strfreev(tokenized_strings);
434 
435  return existing_tokens;
436 }
437 
438 /* create and return a list of tokens for a given transaction info. */
439 static GList*
440 TransactionGetTokens(GNCImportTransInfo *info)
441 {
442 
443  g_return_val_if_fail (info, nullptr);
444  if (info->match_tokens) return info->match_tokens;
445 
446  auto transaction = gnc_import_TransInfo_get_trans(info);
447  g_assert(transaction);
448 
449  /* make tokens from the transaction description */
450  auto text = xaccTransGetDescription(transaction);
451  GList *tokens = nullptr;
452  tokens = tokenize_string(tokens, text);
453 
454  /* The day of week the transaction occurred is a good indicator of
455  * what account this transaction belongs in. Get the date and convert
456  * it to day of week as a token
457  */
458  auto transtime = xaccTransGetDate(transaction);
459  auto tm_struct = gnc_gmtime(&transtime);
460  char local_day_of_week[16];
461  if (!qof_strftime(local_day_of_week, sizeof(local_day_of_week), "%A", tm_struct))
462  PERR("TransactionGetTokens: error, strftime failed\n");
463  gnc_tm_free (tm_struct);
464  /* we cannot add a locally allocated string to this array, dup it so
465  * it frees the same way the rest do
466  */
467  tokens = g_list_prepend(tokens, g_strdup(local_day_of_week));
468 
469  /* make tokens from the memo of each split of this transaction */
470  for (GList *node=xaccTransGetSplitList (transaction); node; node=node->next)
471  {
472  text = xaccSplitGetMemo(static_cast<Split*>(node->data));
473  tokens = tokenize_string(tokens, text);
474  }
475 
476  info->match_tokens = tokens;
477  return tokens;
478 }
479 
480 /* searches using the GNCImportTransInfo through all existing transactions
481  * if there is an exact match of the description and memo
482  */
483 static Account *
484 matchmap_find_destination (Account *base_acc, GNCImportTransInfo *info)
485 {
486  g_assert (info);
487  auto orig_acc = (base_acc ? base_acc : xaccSplitGetAccount
489 
490  Account *result = nullptr;
491  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_IMPORT, GNC_PREF_USE_BAYES))
492  {
493  /* get the tokens for this transaction* */
494  GList* tokens = TransactionGetTokens(info);
495 
496  /* try to find the destination account for this transaction from its tokens */
497  result = gnc_account_imap_find_account_bayes(orig_acc, tokens);
498 
499  }
500  else
501  result = gnc_account_imap_find_account
502  (orig_acc, GNCIMPORT_DESC,
504 
505  return result;
506 }
507 
512 static void
513 matchmap_store_destination (Account *base_acc,
514  GNCImportTransInfo *trans_info,
515  gboolean use_match)
516 {
517  g_assert (trans_info);
518 
519  /* This will store the destination account of the selected match if
520  the reconcile match selected has only two splits. */
521  Account *dest = nullptr;
522  if (use_match)
523  dest = xaccSplitGetAccount
527  else
528  dest = gnc_import_TransInfo_get_destacc (trans_info);
529  if (!dest)
530  return;
531 
532  auto orig_acc = (base_acc ? base_acc : xaccSplitGetAccount
533  (gnc_import_TransInfo_get_fsplit (trans_info)));
534 
535  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_IMPORT, GNC_PREF_USE_BAYES))
536  {
537  /* tokenize this transaction */
538  auto tokens = TransactionGetTokens(trans_info);
539 
540  /* add the tokens to the imap with the given destination account */
541  gnc_account_imap_add_account_bayes(orig_acc, tokens, dest);
542  }
543  else
544  {
545  auto desc = xaccTransGetDescription
546  (gnc_import_TransInfo_get_trans (trans_info));
547  auto memo = xaccSplitGetMemo
548  (gnc_import_TransInfo_get_fsplit (trans_info));
549 
550  if (desc && *desc)
551  gnc_account_imap_add_account (orig_acc, GNCIMPORT_DESC, desc, dest);
552  if (memo && *memo)
553  gnc_account_imap_add_account (orig_acc, GNCIMPORT_MEMO, memo, dest);
554  }
555 }
556 
557 
558 
561 void split_find_match (GNCImportTransInfo * trans_info,
562  Split * split,
563  gint display_threshold,
564  gint date_threshold,
565  gint date_not_threshold,
566  double fuzzy_amount_difference)
567 {
568  gint prob = 0;
569 
570  auto new_trans = gnc_import_TransInfo_get_trans (trans_info);
571  auto new_trans_fsplit = gnc_import_TransInfo_get_fsplit (trans_info);
572 
573  /* Matching heuristics */
574 
575  /* Amount heuristics */
576  auto downloaded_split_amount =
577  gnc_numeric_to_double (xaccSplitGetAmount(new_trans_fsplit));
578  /*DEBUG(" downloaded_split_amount=%f", downloaded_split_amount);*/
579  auto match_split_amount = gnc_numeric_to_double(xaccSplitGetAmount(split));
580  /*DEBUG(" match_split_amount=%f", match_split_amount);*/
581  if (fabs(downloaded_split_amount - match_split_amount) < 1e-6)
582  /* bug#347791: Double type shouldn't be compared for exact
583  equality, so we're using fabs() instead. */
584  /*if (gnc_numeric_equal(xaccSplitGetAmount
585  (new_trans_fsplit),
586  xaccSplitGetAmount(split)))
587  -- gnc_numeric_equal is an expensive function call */
588  {
589  prob = prob + 3;
590  /*DEBUG("heuristics: probability + 3 (amount)");*/
591  }
592  else if (fabs (downloaded_split_amount - match_split_amount) <=
593  fuzzy_amount_difference)
594  {
595  /* ATM fees are sometimes added directly in the transaction.
596  So you withdraw 100$ and get charged 101,25$ in the same
597  transaction */
598  prob = prob + 2;
599  /*DEBUG("heuristics: probability + 2 (amount)");*/
600  }
601  else
602  {
603  /* If a transaction's amount doesn't match within the
604  threshold, it's very unlikely to be the same transaction
605  so we give it an extra -5 penalty */
606  prob = prob - 5;
607  /* DEBUG("heuristics: probability - 1 (amount)"); */
608  }
609 
610  /* Date heuristics */
611  auto match_time = xaccTransGetDate (xaccSplitGetParent (split));
612  auto download_time = xaccTransGetDate (new_trans);
613  auto datediff_day = llabs(match_time - download_time) / 86400;
614  /* Sorry, there are not really functions around at all that
615  provide for less hacky calculation of days of date
616  differences. Whatever. On the other hand, the difference
617  calculation itself will work regardless of month/year
618  turnarounds. */
619  /*DEBUG("diff day %d", datediff_day);*/
620  if (datediff_day == 0)
621  {
622  prob = prob + 3;
623  /*DEBUG("heuristics: probability + 3 (date)");*/
624  }
625  else if (datediff_day <= date_threshold)
626  {
627  prob = prob + 2;
628  /*DEBUG("heuristics: probability + 2 (date)");*/
629  }
630  else if (datediff_day > date_not_threshold)
631  {
632  /* Extra penalty if that split lies awfully far away from
633  the given one. */
634  prob = prob - 5;
635  /*DEBUG("heuristics: probability - 5 (date)"); */
636  /* Changed 2005-02-21: Revert the hard-limiting behaviour
637  back to the previous large penalty. (Changed 2004-11-27:
638  The penalty is so high that we can forget about this
639  split anyway and skip the rest of the tests.) */
640  }
641 
642  /* Check if date and amount are identical */
643  auto update_proposed = (prob < 6);
644 
645  /* Check number heuristics */
646  auto new_trans_str = gnc_get_num_action(new_trans, new_trans_fsplit);
647  if (new_trans_str && *new_trans_str)
648  {
649  char *endptr;
650  auto conversion_ok = true;
651 
652  /* To distinguish success/failure after strtol call */
653  errno = 0;
654  auto new_trans_number = strtol(new_trans_str, &endptr, 10);
655  /* Possible addressed problems: over/underflow, only non
656  numbers on string and string empty */
657  conversion_ok = !(errno || endptr == new_trans_str);
658 
659  auto split_str = gnc_get_num_action (xaccSplitGetParent (split), split);
660  errno = 0;
661  auto split_number = strtol(split_str, &endptr, 10);
662  conversion_ok = !(errno || endptr == split_str);
663 
664  if ( (conversion_ok && (split_number == new_trans_number)) ||
665  (g_strcmp0(new_trans_str, split_str) == 0) )
666  {
667  /* An exact match of the Check number gives a +4 */
668  prob += 4;
669  /*DEBUG("heuristics: probability + 4 (Check number)");*/
670  }
671  else if (strlen(new_trans_str) > 0 && strlen(split_str) > 0)
672  {
673  /* If both number are not empty yet do not match, add a
674  little extra penalty */
675  prob -= 2;
676  }
677  }
678 
679  /* Memo heuristics */
680  auto memo = xaccSplitGetMemo(new_trans_fsplit);
681  if (memo && *memo)
682  {
683  if (safe_strcasecmp(memo, xaccSplitGetMemo(split)) == 0)
684  {
685  /* An exact match of memo gives a +2 */
686  prob = prob + 2;
687  /* DEBUG("heuristics: probability + 2 (memo)"); */
688  }
689  else if ((strncasecmp(memo, xaccSplitGetMemo(split),
690  strlen(xaccSplitGetMemo(split)) / 2) == 0))
691  {
692  /* Very primitive fuzzy match worth +1. This matches the
693  first 50% of the strings to skip annoying transaction
694  number some banks seem to include in the memo but someone
695  should write something more sophisticated */
696  prob = prob + 1;
697  /*DEBUG("heuristics: probability + 1 (memo)"); */
698  }
699  }
700 
701  /* Description heuristics */
702  auto descr = xaccTransGetDescription(new_trans);
703  if (descr && *descr)
704  {
705  if (safe_strcasecmp(descr,
707  {
708  /*An exact match of Description gives a +2 */
709  prob = prob + 2;
710  /*DEBUG("heuristics: probability + 2 (description)");*/
711  }
712  else if ((strncasecmp(descr,
714  strlen(xaccTransGetDescription (new_trans)) / 2) == 0))
715  {
716  /* Very primitive fuzzy match worth +1. This matches the
717  first 50% of the strings to skip annoying transaction
718  number some banks seem to include in the description but someone
719  should write something more sophisticated */
720  prob = prob + 1;
721  /*DEBUG("heuristics: probability + 1 (description)"); */
722  }
723  }
724 
725  /* Is the probability high enough? Otherwise do nothing and return. */
726  if (prob < display_threshold)
727  return;
728 
729  /* The probability is high enough, so allocate an object
730  here. Allocating it only when it's actually being used is
731  probably quite some performance gain. */
732  auto match_info = g_new0(GNCImportMatchInfo, 1);
733 
734  match_info->probability = prob;
735  match_info->update_proposed = update_proposed;
736  match_info->split = split;
737  match_info->trans = xaccSplitGetParent(split);
738 
739 
740  /* Append that to the list. Do not use g_list_append because
741  it is slow. The list is sorted afterwards anyway. */
742  trans_info->match_list = g_list_prepend(trans_info->match_list, match_info);
743 }
744 
745 /***********************************************************************
746  */
747 
748 static char*
749 maybe_append_string (const char* match_string, const char* imp_string)
750 {
751  if (!(match_string && *match_string))
752  return g_strdup(imp_string);
753 
754  if (!(imp_string && *imp_string))
755  return nullptr;
756 
757  auto norm_match_string = g_utf8_normalize (match_string, -1, G_NORMALIZE_NFC);
758  auto norm_imp_string = g_utf8_normalize (imp_string, -1, G_NORMALIZE_NFC);
759 
760  char *retval = nullptr;
761  if (g_utf8_strlen (norm_imp_string, -1) > g_utf8_strlen (norm_match_string, -1) ||
762  !strstr (norm_match_string, norm_imp_string))
763  retval = g_strconcat(match_string, "|", imp_string, nullptr);
764 
765  g_free (norm_match_string);
766  g_free (norm_imp_string);
767  return retval;
768 
769 }
770 
771 /* Append or replace transaction description and notes
772  * depending on the Append checkbox
773  */
774 static void
775 update_desc_and_notes (const GNCImportTransInfo* trans_info)
776 {
777  auto selected_match = gnc_import_TransInfo_get_selected_match (trans_info);
778  auto imp_trans = gnc_import_TransInfo_get_trans (trans_info);
779 
780  if (trans_info->append_text)
781  {
782  auto match_trans = selected_match->trans;
783  auto repl_str =
784  maybe_append_string (xaccTransGetDescription(match_trans),
785  xaccTransGetDescription(imp_trans));
786  if (repl_str)
787  xaccTransSetDescription(match_trans, repl_str);
788  g_free (repl_str);
789 
790  repl_str =
791  maybe_append_string (xaccTransGetNotes(match_trans),
792  xaccTransGetNotes(imp_trans));
793  if (repl_str)
794  xaccTransSetNotes (match_trans, repl_str);
795  g_free (repl_str);
796  }
797  else
798  {
799  xaccTransSetDescription (selected_match->trans,
800  xaccTransGetDescription (imp_trans));
801  xaccTransSetNotes (selected_match->trans,
802  xaccTransGetNotes (imp_trans));
803  }
804 }
805 
806 static void
807 process_reconcile(Account *base_acc,
808  GNCImportTransInfo *trans_info,
809  GNCImportMatchInfo *selected_match)
810 {
811  /* Reconcile the matching transaction */
812  /*DEBUG("BeginEdit selected_match")*/
813  xaccTransBeginEdit(selected_match->trans);
814 
815  if (xaccSplitGetReconcile(selected_match->split) == NREC)
816  xaccSplitSetReconcile(selected_match->split, CREC);
817 
818  /* Set reconcile date to today */
819  xaccSplitSetDateReconciledSecs(selected_match->split, gnc_time (nullptr));
820 
821  /* Copy the online id to the reconciled transaction, so
822  * the match will be remembered */
823  auto online_id = gnc_import_get_split_online_id(trans_info->first_split);
824  if (online_id && *online_id)
825  gnc_import_set_split_online_id(selected_match->split, online_id);
826 
827  g_free (online_id);
828 
829  /* Done editing. */
830  /*DEBUG("CommitEdit selected_match")*/
831  xaccTransCommitEdit(selected_match->trans);
832 
833  /* Store the mapping to the other account in the MatchMap. */
834  matchmap_store_destination(base_acc, trans_info, true);
835 
836  /* Erase the downloaded transaction */
837  xaccTransDestroy(trans_info->trans);
838  /*DEBUG("CommitEdit trans")*/
839  xaccTransCommitEdit(trans_info->trans);
840  /* Very important: Make sure the freed transaction is not freed again! */
841  trans_info->trans = nullptr;
842 }
843 
846 gboolean
848  GNCImportTransInfo *trans_info)
849 {
850  g_assert (trans_info);
851  /*DEBUG("Iteration %d, action %d, split %s", i,
852  trans_info->action,
853  xaccTransGetDescription (gnc_import_TransInfo_get_trans
854  (trans_info)))*/
855  switch (gnc_import_TransInfo_get_action (trans_info))
856  {
857  case GNCImport_SKIP:
858  return false;
859  case GNCImport_ADD:
860  /* Transaction gets imported. */
861  if (!gnc_import_TransInfo_is_balanced(trans_info)
862  && gnc_import_TransInfo_get_destacc(trans_info))
863  {
864  /* Create the 'other' split. */
865  auto trans = gnc_import_TransInfo_get_trans (trans_info);
866  auto acct = gnc_import_TransInfo_get_destacc (trans_info);
867  auto split = xaccMallocSplit (gnc_account_get_book (acct));
868  xaccTransAppendSplit (trans, split);
869  xaccAccountInsertSplit (acct, split);
870  xaccSplitSetValue (split, trans_info->lsplit_value);
871  if (!gnc_numeric_zero_p (trans_info->lsplit_amount))
872  xaccSplitSetAmount (split, trans_info->lsplit_amount);
873  else
874  {
875  /* Bad! user asked to create a balancing split in an account with
876  * different currency/commodit than the transaction but didn't provide
877  * an exchange rate.
878  * Continue anyway pretenting split is in transaction currency. */
879  xaccSplitSetAmount (split, trans_info->lsplit_value);
880  PWARN("Missing exchange rate while adding transaction '%s', will assume rate of 1",
882  }
883  }
884 
886  /*Set reconcile date to today*/
888  gnc_time (nullptr));
889  /* Done editing. */
890  xaccTransCommitEdit(trans_info->trans);
891  xaccTransRecordPrice(trans_info->trans, PRICE_SOURCE_SPLIT_IMPORT);
892  return true;
893  case GNCImport_UPDATE:
894  {
895  auto selected_match = gnc_import_TransInfo_get_selected_match(trans_info);
896 
897  /* If there is no selection, ignore this transaction. */
898  if (!selected_match)
899  {
900  PWARN("No matching transaction to be cleared was chosen. Imported transaction will be ignored.");
901  break;
902  }
903 
904  /* Transaction gets not imported but the matching one gets
905  updated and reconciled. */
906  if (!gnc_import_MatchInfo_get_split(selected_match))
907  PERR("The split I am trying to update and reconcile is nullptr, shouldn't happen!");
908  else
909  {
910  /* Update and reconcile the matching transaction */
911  /*DEBUG("BeginEdit selected_match")*/
912  xaccTransBeginEdit(selected_match->trans);
913 
914  auto fsplit = gnc_import_TransInfo_get_fsplit(trans_info);
915  xaccTransSetDatePostedSecsNormalized(selected_match->trans,
917 
918  auto match_split_amount = xaccSplitGetAmount(selected_match->split);
919  xaccSplitSetAmount(selected_match->split, xaccSplitGetAmount(fsplit));
920  xaccSplitSetValue(selected_match->split, xaccSplitGetValue(fsplit));
921 
922  auto imbalance_value = gnc_import_TransInfo_get_dest_value(trans_info);
923  auto other_split = xaccSplitGetOtherSplit(selected_match->split);
924  if (!gnc_numeric_zero_p(imbalance_value) && other_split)
925  {
926  if (xaccSplitGetReconcile(other_split) == NREC)
927  {
928  xaccSplitSetValue(other_split, imbalance_value);
929  auto new_amt = gnc_import_TransInfo_get_dest_value(trans_info);
930  if (gnc_numeric_zero_p(new_amt))
931  {
932  auto other_split_amount = xaccSplitGetAmount(other_split);
933  auto price = gnc_numeric_div(match_split_amount, other_split_amount,
936 
937  new_amt = gnc_numeric_mul(xaccSplitGetAmount(fsplit), price,
940  }
941  xaccSplitSetAmount(other_split, new_amt);
942  }
943  else
944  {
945  /* else GC will automatically insert a split to equity
946  to balance the transaction */
947  PWARN("Updated transaction '%s', but not other split.",
948  xaccTransGetDescription(selected_match->trans));
949  }
950  }
951 
952  auto fs_memo = xaccSplitGetMemo (trans_info->first_split);
953  if (fs_memo && *fs_memo)
954  xaccSplitSetMemo(selected_match->split, fs_memo);
955 
956  update_desc_and_notes(trans_info);
957 
958  /*DEBUG("CommitEdit selected_match")*/
959  xaccTransCommitEdit(selected_match->trans);
960 
961  process_reconcile (base_acc, trans_info, selected_match);
962  }
963  }
964  return true;
965  case GNCImport_CLEAR:
966  {
967  auto selected_match = gnc_import_TransInfo_get_selected_match (trans_info);
968 
969  /* If there is no selection, ignore this transaction. */
970  if (!selected_match)
971  {
972  PWARN("No matching translaction to be cleared was chosen. Imported transaction will be ignored.");
973  break;
974  }
975 
976  /* Transaction gets not imported but the matching one gets
977  reconciled. */
978  if (!gnc_import_MatchInfo_get_split (selected_match))
979  PERR("The split I am trying to reconcile is nullptr, shouldn't happen!");
980  else
981  {
982  /* Reconcile the matching transaction */
983  process_reconcile(base_acc, trans_info, selected_match);
984  }
985  }
986  return true;
987  default:
988  DEBUG("Invalid GNCImportAction for this imported transaction.");
989  break;
990  }
991  /*DEBUG("End");*/
992  return false;
993 }
994 
995 static GHashTable*
996 hash_account_online_ids (Account *account)
997 {
998  auto acct_hash = g_hash_table_new_full
999  (g_str_hash, g_str_equal, g_free, nullptr);
1000  for (auto split : xaccAccountGetSplits (account))
1001  {
1002  auto id = gnc_import_get_split_online_id (split);
1003  if (id && *id)
1004  g_hash_table_insert (acct_hash, (void*) id, GINT_TO_POINTER (1));
1005  }
1006  return acct_hash;
1007 }
1008 
1011 gboolean gnc_import_exists_online_id (Transaction *trans, GHashTable* acct_id_hash)
1012 {
1013 
1014  /* Look for an online_id in the first split */
1015  auto source_split = xaccTransGetSplit(trans, 0);
1016  g_assert(source_split);
1017 
1018  auto source_online_id = gnc_import_get_split_online_id (source_split);
1019 
1020  // No online id, no point in continuing. We'd crash if we tried.
1021  if (!source_online_id)
1022  return false;
1023 
1024  // Create a hash per account of a hash of all split IDs. Then the
1025  // test below will be fast if we have many transactions to import.
1026  auto dest_acct = xaccSplitGetAccount (source_split);
1027 
1028  auto online_id_hash = static_cast<GHashTable*>(g_hash_table_lookup (acct_id_hash, dest_acct));
1029 
1030  if (!online_id_hash)
1031  {
1032  online_id_hash = hash_account_online_ids (dest_acct);
1033  g_hash_table_insert (acct_id_hash, dest_acct, online_id_hash);
1034  }
1035 
1036  auto online_id_exists = g_hash_table_contains (online_id_hash, source_online_id);
1037  g_free (source_online_id);
1038  return online_id_exists;
1039 }
1040 
1041 
1042 /* ******************************************************************
1043  */
1044 
1045 /* Calculate lsplit_amount based on knowledge gathered so far
1046  * If insufficient info is available (eg multi currency transaction with missing
1047  * exchange rate provided), set amount to 0 */
1048 static void trans_info_calculate_dest_amount (GNCImportTransInfo *info)
1049 {
1050  info->lsplit_value = gnc_numeric_neg (xaccTransGetImbalanceValue (info->trans));
1051  if (!info->lsplit_amount_selected_manually)
1052  info->lsplit_amount = {0, 1};
1053 
1054  if (info->dest_acc)
1055  {
1056  auto tcurr = xaccTransGetCurrency(info->trans);
1057  auto dcurr = xaccAccountGetCommodity(info->dest_acc);
1058 
1059  if (gnc_numeric_zero_p(info->lsplit_value))
1060  return;
1061 
1062  if (gnc_commodity_equiv(tcurr, dcurr))
1063  info->lsplit_amount = info->lsplit_value;
1064  else if (info->lsplit_amount_selected_manually &&
1065  gnc_numeric_check(info->lsplit_amount) == 0)
1066  {
1067  /* Nothing to do, user has provided amount already */
1068  }
1069  else if (gnc_numeric_check(info->lsplit_price) == 0)
1070  {
1071  /* We are in a multi currency situation and have a valid price
1072  * Reminder: value = amount * price => amount = value / price */
1073  gnc_numeric inv_price = gnc_numeric_invert (info->lsplit_price);
1074  info->lsplit_amount = gnc_numeric_mul (info->lsplit_value,
1075  inv_price,
1078  }
1079  }
1080 }
1081 
1083 GNCImportTransInfo *
1084 gnc_import_TransInfo_new (Transaction *trans, Account *base_acc)
1085 {
1086  g_assert (trans);
1087 
1088  auto t_info = g_new0(GNCImportTransInfo, 1);
1089 
1090  t_info->trans = trans;
1091  /* Only use first split, the source split */
1092  auto split = xaccTransGetSplit(trans, 0);
1093  g_assert(split);
1094  t_info->first_split = split;
1095 
1096  /* Try to find a previously selected destination account
1097  string match for the ADD action */
1099  matchmap_find_destination (base_acc, t_info),
1100  false);
1101 
1102  return t_info;
1103 }
1104 
1105 
1107 static gint compare_probability (gconstpointer a,
1108  gconstpointer b)
1109 {
1110  return(((GNCImportMatchInfo *)b)->probability -
1111  ((GNCImportMatchInfo *)a)->probability);
1112 }
1113 
1118 void
1119 gnc_import_TransInfo_init_matches (GNCImportTransInfo *trans_info,
1120  GNCImportSettings *settings)
1121 {
1122  g_assert (trans_info);
1123 
1124  if (trans_info->match_list)
1125  {
1126  trans_info->match_list = g_list_sort(trans_info->match_list,
1127  compare_probability);
1128  auto best_match = static_cast<GNCImportMatchInfo*>(g_list_nth_data(trans_info->match_list, 0));
1129  gnc_import_TransInfo_set_selected_match_info (trans_info, best_match, false);
1130  if (best_match &&
1131  best_match->probability >= gnc_import_Settings_get_clear_threshold(settings))
1132  {
1134  best_match->update_proposed)
1135  trans_info->action = GNCImport_UPDATE;
1136  else
1137  trans_info->action = GNCImport_CLEAR;
1138  }
1139  else if (!best_match ||
1140  best_match->probability <= gnc_import_Settings_get_add_threshold(settings))
1141  trans_info->action = GNCImport_ADD;
1143  trans_info->action = GNCImport_SKIP;
1145  trans_info->action = GNCImport_UPDATE;
1146  else
1147  trans_info->action = GNCImport_ADD;
1148  }
1149  else
1150  trans_info->action = GNCImport_ADD;
1151 
1152 
1153  trans_info->previous_action = trans_info->action;
1154 }
1155 
1156 
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:1056
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:381
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
gnc_numeric gnc_import_TransInfo_get_dest_value(const GNCImportTransInfo *info)
Returns the destination split value for this TransInfo.
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.
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.
STRUCTS.
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.
GNCImportTransInfo * gnc_import_TransInfo_new(Transaction *trans, Account *base_acc)
Create a new object of GNCImportTransInfo here.
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_account_imap_add_account_bayes(Account *acc, GList *tokens, Account *added_acc)
Updates the imap for a given account using a list of tokens.
Definition: Account.cpp:5521
void gnc_import_TransInfo_init_matches(GNCImportTransInfo *trans_info, GNCImportSettings *settings)
Iterates through all splits of trans_info&#39;s originating account match list.
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:96
#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.
gboolean gnc_import_process_trans_item(Account *base_acc, GNCImportTransInfo *trans_info)
/brief – Processes one match according to its selected action.
gdouble gnc_numeric_to_double(gnc_numeric n)
Convert numeric to floating-point value.
gnc_numeric gnc_numeric_invert(gnc_numeric num)
Invert a gnc_numeric.
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
Account handling public routines.
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
The xaccTransGetImbalanceValue() method returns the total value of the transaction.
Account public routines (C++ api)
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
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.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
gnc_numeric gnc_import_TransInfo_get_dest_amount(const GNCImportTransInfo *info)
Returns the destination split amount for this TransInfo.
void gnc_import_TransInfo_set_append_text(GNCImportTransInfo *info, gboolean append_text)
Set the append_text for this TransInfo.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
Division.
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:73
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
Generic api to store and retrieve preferences.
void gnc_import_TransInfo_set_price(GNCImportTransInfo *info, gnc_numeric lprice)
Set the exchange rate for this TransInfo.
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
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3371
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1052
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:177
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gnc_numeric gnc_import_TransInfo_get_price(const GNCImportTransInfo *info)
Returns the exchange rate for this TransInfo.
GList * gnc_import_TransInfo_get_match_list(const GNCImportTransInfo *info)
Returns the stored list of possible matches.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
GNCImportMatchInfo * gnc_import_TransInfo_get_selected_match(const GNCImportTransInfo *info)
Returns the currently selected match in this TransInfo.
void gnc_import_TransInfo_remove_top_match(GNCImportTransInfo *info)
Remove the first match in the list of possible matches.
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
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.
void gnc_import_TransInfo_set_last_split_info(GNCImportTransInfo *info, GNCImportLastSplitInfo *lsplit)
Sets additional parameters to be used to generate the closing split.
#define NREC
not reconciled or cleared
Definition: Split.h:76
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69
Account * gnc_account_imap_find_account_bayes(Account *acc, GList *tokens)
Look up an Account in the map.
Definition: Account.cpp:5475
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...