00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00029 #include "config.h"
00030
00031 #include <gtk/gtk.h>
00032 #include <glib/gi18n.h>
00033 #include <stdlib.h>
00034 #include <math.h>
00035
00036 #include <errno.h>
00037
00038 #include "gnc-gconf-utils.h"
00039 #include "import-backend.h"
00040 #include "import-utilities.h"
00041 #include "Account.h"
00042 #include "Query.h"
00043 #include "gnc-engine.h"
00044 #include "gnc-ui-util.h"
00045
00046 #define GCONF_SECTION "dialogs/import/generic_matcher"
00047 #define BAYES_OPTION "use_bayes"
00048
00049
00050
00051
00052
00053 static QofLogModule log_module = GNC_MOD_IMPORT;
00054
00055
00056
00057
00058
00059 static const int MATCH_DATE_THRESHOLD = 4;
00060 static const int MATCH_DATE_NOT_THRESHOLD = 14;
00061
00062
00063
00064
00065
00066 static void
00067 matchmap_store_destination (GncImportMatchMap *matchmap,
00068 GNCImportTransInfo *trans_info,
00069 gboolean use_match);
00070
00071
00072
00073
00074
00075
00076 struct _transactioninfo
00077 {
00078 Transaction * trans;
00079 Split * first_split;
00080
00081
00082 GList * match_list;
00083 GNCImportMatchInfo * selected_match_info;
00084 gboolean match_selected_manually;
00085
00086 GNCImportAction action;
00087 GNCImportAction previous_action;
00088
00089
00090 GList * match_tokens;
00091
00092
00093 Account *dest_acc;
00094 gboolean dest_acc_selected_manually;
00095
00096
00097 guint32 ref_id;
00098 };
00099
00100 struct _matchinfo
00101 {
00102 Transaction * trans;
00103 Split * split;
00104
00105 gint probability;
00106 gboolean update_proposed;
00107 };
00108
00109
00110
00111 GList *
00112 gnc_import_TransInfo_get_match_list (const GNCImportTransInfo *info)
00113 {
00114 g_assert (info);
00115 return info->match_list;
00116 }
00117
00118 Transaction *
00119 gnc_import_TransInfo_get_trans (const GNCImportTransInfo *info)
00120 {
00121 g_assert (info);
00122 return info->trans;
00123 }
00124
00125 gboolean
00126 gnc_import_TransInfo_is_balanced (const GNCImportTransInfo *info)
00127 {
00128 g_assert (info);
00129
00130
00131
00132 if (gnc_numeric_zero_p(xaccTransGetImbalanceValue(gnc_import_TransInfo_get_trans(info))))
00133 {
00134 return TRUE;
00135 }
00136 else
00137 {
00138 return FALSE;
00139 }
00140 }
00141
00142 Split *
00143 gnc_import_TransInfo_get_fsplit (const GNCImportTransInfo *info)
00144 {
00145 g_assert (info);
00146 return info->first_split;
00147 }
00148
00149 GNCImportMatchInfo *
00150 gnc_import_TransInfo_get_selected_match (const GNCImportTransInfo *info)
00151 {
00152 g_assert (info);
00153 return info->selected_match_info;
00154 }
00155
00156 void
00157 gnc_import_TransInfo_set_selected_match (GNCImportTransInfo *info,
00158 GNCImportMatchInfo *match,
00159 gboolean selected_manually)
00160 {
00161 g_assert (info);
00162 info->selected_match_info = match;
00163 info->match_selected_manually = selected_manually;
00164 }
00165
00166 gboolean
00167 gnc_import_TransInfo_get_match_selected_manually (const GNCImportTransInfo *info)
00168 {
00169 g_assert (info);
00170 return info->match_selected_manually;
00171 }
00172
00173 GNCImportAction
00174 gnc_import_TransInfo_get_action (const GNCImportTransInfo *info)
00175 {
00176 g_assert (info);
00177 return info->action;
00178 }
00179
00180 void
00181 gnc_import_TransInfo_set_action (GNCImportTransInfo *info,
00182 GNCImportAction action)
00183 {
00184 g_assert (info);
00185 if (action != info->action)
00186 {
00187 info->previous_action = info->action;
00188 info->action = action;
00189 }
00190 }
00191
00192 Account *
00193 gnc_import_TransInfo_get_destacc (const GNCImportTransInfo *info)
00194 {
00195 g_assert (info);
00196 return info->dest_acc;
00197 }
00198 void gnc_import_TransInfo_set_destacc (GNCImportTransInfo *info,
00199 Account *acc,
00200 gboolean selected_manually)
00201 {
00202 g_assert (info);
00203 info->dest_acc = acc;
00204 info->dest_acc_selected_manually = selected_manually;
00205
00206
00207 if (selected_manually)
00208 {
00209 matchmap_store_destination (NULL, info, FALSE);
00210 }
00211 }
00212
00213 gboolean
00214 gnc_import_TransInfo_get_destacc_selected_manually (const GNCImportTransInfo *info)
00215 {
00216 g_assert (info);
00217 return info->dest_acc_selected_manually;
00218 }
00219
00220 guint32
00221 gnc_import_TransInfo_get_ref_id (const GNCImportTransInfo *info)
00222 {
00223 g_assert (info);
00224 return info->ref_id;
00225 }
00226
00227 void
00228 gnc_import_TransInfo_set_ref_id (GNCImportTransInfo *info,
00229 guint32 ref_id)
00230 {
00231 g_assert (info);
00232 info->ref_id = ref_id;
00233 }
00234
00235
00236 Split *
00237 gnc_import_MatchInfo_get_split (const GNCImportMatchInfo * info)
00238 {
00239 g_assert (info);
00240 return info->split;
00241 }
00242
00243 gint
00244 gnc_import_MatchInfo_get_probability (const GNCImportMatchInfo * info)
00245 {
00246 if (info)
00247 {
00248 return info->probability;
00249 }
00250 else
00251 {
00252 return 0;
00253 }
00254 }
00255
00256 void gnc_import_TransInfo_delete (GNCImportTransInfo *info)
00257 {
00258 if (info)
00259 {
00260 g_list_free (info->match_list);
00261
00262 if (info->trans && xaccTransIsOpen(info->trans))
00263 {
00264 xaccTransDestroy(info->trans);
00265 xaccTransCommitEdit(info->trans);
00266 }
00267 if (info->match_tokens)
00268 {
00269 GList *node;
00270
00271 for (node = info->match_tokens; node; node = node->next)
00272 g_free (node->data);
00273
00274 g_list_free (info->match_tokens);
00275 }
00276 g_free(info);
00277 }
00278 }
00279
00280 GdkPixbuf* gen_probability_pixbuf(gint score_original, GNCImportSettings *settings, GtkWidget * widget)
00281 {
00282 GdkPixbuf* retval = NULL;
00283 gint i, j;
00284 gint score;
00285 const gint height = 15;
00286 const gint width_each_bar = 7;
00287 gchar * green_bar = ("bggggb ");
00288 gchar * yellow_bar = ("byyyyb ");
00289 gchar * red_bar = ("brrrrb ");
00290 gchar * black_bar = ("bbbbbb ");
00291 const gint width_first_bar = 1;
00292 gchar * black_first_bar = ("b");
00293 const gint num_colors = 5;
00294 gchar * size_str;
00295 gchar * none_color_str = g_strdup_printf(" c None");
00296 gchar * green_color_str = g_strdup_printf("g c green");
00297 gchar * yellow_color_str = g_strdup_printf("y c yellow");
00298 gchar * red_color_str = g_strdup_printf("r c red");
00299 gchar * black_color_str = g_strdup_printf("b c black");
00300 gchar * xpm[2+num_colors+height];
00301 gint add_threshold, clear_threshold;
00302
00303 g_assert(settings);
00304 g_assert(widget);
00305 if (score_original < 0)
00306 {
00307 score = 0;
00308 }
00309 else
00310 {
00311 score = score_original;
00312 }
00313 size_str = g_strdup_printf("%d%s%d%s%d%s", (width_each_bar * score) + width_first_bar, " ", height, " ", num_colors, " 1");
00314
00315
00316 xpm[0] = size_str;
00317 xpm[1] = none_color_str;
00318 xpm[2] = green_color_str;
00319 xpm[3] = yellow_color_str;
00320 xpm[4] = red_color_str;
00321 xpm[5] = black_color_str;
00322 add_threshold = gnc_import_Settings_get_add_threshold(settings);
00323 clear_threshold = gnc_import_Settings_get_clear_threshold(settings);
00324
00325 for (i = 0; i < height; i++)
00326 {
00327 xpm[num_colors+1+i] = g_new0(char, (width_each_bar * score) + width_first_bar + 1);
00328 for (j = 0; j <= score; j++)
00329 {
00330 if (i == 0 || i == height - 1)
00331 {
00332 if (j == 0)
00333 {
00334 strcat(xpm[num_colors+1+i], black_first_bar);
00335 }
00336 else
00337 {
00338 strcat(xpm[num_colors+1+i], black_bar);
00339 }
00340 }
00341 else
00342 {
00343 if (j == 0)
00344 {
00345 strcat(xpm[num_colors+1+i], black_first_bar);
00346 }
00347 else if (j <= add_threshold)
00348 {
00349 strcat(xpm[num_colors+1+i], red_bar);
00350 }
00351 else if (j >= clear_threshold)
00352 {
00353 strcat(xpm[num_colors+1+i], green_bar);
00354 }
00355 else
00356 {
00357 strcat(xpm[num_colors+1+i], yellow_bar);
00358 }
00359 }
00360 }
00361 }
00362
00363 retval = gdk_pixbuf_new_from_xpm_data((const gchar **)xpm);
00364 for (i = 0; i <= num_colors + height; i++)
00365 {
00366
00367 g_free(xpm[i]);
00368 }
00369
00370 return retval;
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380 static GList*
00381 tokenize_string(GList* existing_tokens, const char *string)
00382 {
00383 char **tokenized_strings;
00384 char **stringpos;
00385
00386 tokenized_strings = g_strsplit(string, " ", 0);
00387 stringpos = tokenized_strings;
00388
00389
00390 while (stringpos && *stringpos)
00391 {
00392
00393 existing_tokens = g_list_prepend(existing_tokens, g_strdup(*stringpos));
00394
00395
00396 stringpos++;
00397 }
00398
00399
00400 g_strfreev(tokenized_strings);
00401
00402 return existing_tokens;
00403 }
00404
00405
00406 static GList*
00407 TransactionGetTokens(GNCImportTransInfo *info)
00408 {
00409 Transaction* transaction;
00410 GList* tokens;
00411 const char* text;
00412 time_t transtime;
00413 struct tm *tm_struct;
00414 char local_day_of_week[16];
00415 Split* split;
00416 int split_index;
00417
00418 g_return_val_if_fail (info, NULL);
00419 if (info->match_tokens) return info->match_tokens;
00420
00421 transaction = gnc_import_TransInfo_get_trans(info);
00422 g_assert(transaction);
00423
00424 tokens = 0;
00425
00426
00427 text = xaccTransGetDescription(transaction);
00428 tokens = tokenize_string(tokens, text);
00429
00430
00431
00432
00433
00434 transtime = xaccTransGetDate(transaction);
00435 tm_struct = gmtime(&transtime);
00436 if (!qof_strftime(local_day_of_week, sizeof(local_day_of_week), "%A", tm_struct))
00437 {
00438 PERR("TransactionGetTokens: error, strftime failed\n");
00439 }
00440
00441
00442
00443
00444 tokens = g_list_prepend(tokens, g_strdup(local_day_of_week));
00445
00446
00447 split_index = 0;
00448 while ((split = xaccTransGetSplit(transaction, split_index)))
00449 {
00450 text = xaccSplitGetMemo(split);
00451 tokens = tokenize_string(tokens, text);
00452 split_index++;
00453 }
00454
00455
00456 info->match_tokens = tokens;
00457
00458
00459 return tokens;
00460 }
00461
00462
00463
00464
00465 static Account *
00466 matchmap_find_destination (GncImportMatchMap *matchmap, GNCImportTransInfo *info)
00467 {
00468 GncImportMatchMap *tmp_map;
00469 Account *result;
00470 GList* tokens;
00471 gboolean useBayes;
00472
00473 g_assert (info);
00474 tmp_map = ((matchmap != NULL) ? matchmap :
00475 gnc_imap_create_from_account
00476 (xaccSplitGetAccount
00477 (gnc_import_TransInfo_get_fsplit (info))));
00478
00479 useBayes = gnc_gconf_get_bool(GCONF_SECTION, BAYES_OPTION, NULL);
00480 if (useBayes)
00481 {
00482
00483 tokens = TransactionGetTokens(info);
00484
00485
00486 result = gnc_imap_find_account_bayes(tmp_map, tokens);
00487
00488 }
00489 else
00490 {
00491
00492 result = gnc_imap_find_account
00493 (tmp_map, GNCIMPORT_DESC,
00494 xaccTransGetDescription (gnc_import_TransInfo_get_trans (info)));
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508 if (matchmap == NULL)
00509 gnc_imap_destroy (tmp_map);
00510
00511 return result;
00512 }
00513
00518 static void
00519 matchmap_store_destination (GncImportMatchMap *matchmap,
00520 GNCImportTransInfo *trans_info,
00521 gboolean use_match)
00522 {
00523 GncImportMatchMap *tmp_matchmap = NULL;
00524 Account *dest;
00525 const char *descr, *memo;
00526 GList *tokens;
00527 gboolean useBayes;
00528
00529 g_assert (trans_info);
00530
00531
00532
00533
00534 dest = ((use_match) ?
00535 xaccSplitGetAccount
00536 (xaccSplitGetOtherSplit
00537 (gnc_import_MatchInfo_get_split
00538 (gnc_import_TransInfo_get_selected_match (trans_info)))) :
00539 gnc_import_TransInfo_get_destacc (trans_info));
00540 if (dest == NULL)
00541 return;
00542
00543 tmp_matchmap = ((matchmap != NULL) ?
00544 matchmap :
00545 gnc_imap_create_from_account
00546 (xaccSplitGetAccount
00547 (gnc_import_TransInfo_get_fsplit (trans_info))));
00548
00549
00550 useBayes = gnc_gconf_get_bool(GCONF_SECTION, BAYES_OPTION, NULL);
00551 if (useBayes)
00552 {
00553
00554 tokens = TransactionGetTokens(trans_info);
00555
00556
00557 gnc_imap_add_account_bayes(tmp_matchmap, tokens, dest);
00558
00559 }
00560 else
00561 {
00562
00563 descr = xaccTransGetDescription
00564 (gnc_import_TransInfo_get_trans (trans_info));
00565 if (descr && (strlen (descr) > 0))
00566 gnc_imap_add_account (tmp_matchmap,
00567 GNCIMPORT_DESC,
00568 descr,
00569 dest);
00570 memo = xaccSplitGetMemo
00571 (gnc_import_TransInfo_get_fsplit (trans_info));
00572 if (memo && (strlen (memo) > 0))
00573 gnc_imap_add_account (tmp_matchmap,
00574 GNCIMPORT_MEMO,
00575 memo,
00576 dest);
00577 }
00578
00579 if (matchmap == NULL)
00580 gnc_imap_destroy (tmp_matchmap);
00581 }
00582
00583
00584
00587 static void split_find_match (GNCImportTransInfo * trans_info,
00588 Split * split,
00589 gint display_threshold,
00590 double fuzzy_amount_difference)
00591 {
00592
00593
00594
00595
00596 if (xaccTransIsOpen(xaccSplitGetParent(split)) == FALSE)
00597 {
00598 GNCImportMatchInfo * match_info;
00599 gint prob = 0;
00600 gboolean update_proposed;
00601 double downloaded_split_amount, match_split_amount;
00602 time_t match_time, download_time;
00603 int datediff_day;
00604 Transaction *new_trans = gnc_import_TransInfo_get_trans (trans_info);
00605 Split *new_trans_fsplit = gnc_import_TransInfo_get_fsplit (trans_info);
00606
00607
00608
00609
00610 downloaded_split_amount =
00611 gnc_numeric_to_double (xaccSplitGetAmount(new_trans_fsplit));
00612
00613 match_split_amount = gnc_numeric_to_double(xaccSplitGetAmount(split));
00614
00615 if (fabs(downloaded_split_amount - match_split_amount) < 1e-6)
00616
00617
00618
00619
00620
00621
00622 {
00623 prob = prob + 3;
00624
00625 }
00626 else if (fabs (downloaded_split_amount - match_split_amount) <=
00627 fuzzy_amount_difference)
00628 {
00629
00630
00631
00632 prob = prob + 2;
00633
00634 }
00635 else
00636 {
00637
00638
00639
00640 prob = prob - 5;
00641
00642 }
00643
00644
00645 match_time = xaccTransGetDate (xaccSplitGetParent (split));
00646 download_time = xaccTransGetDate (new_trans);
00647 datediff_day = abs(match_time - download_time) / 86400;
00648
00649
00650
00651
00652
00653
00654 if (datediff_day == 0)
00655 {
00656 prob = prob + 3;
00657
00658 }
00659 else if (datediff_day <= MATCH_DATE_THRESHOLD)
00660 {
00661 prob = prob + 2;
00662
00663 }
00664 else if (datediff_day > MATCH_DATE_NOT_THRESHOLD)
00665 {
00666
00667
00668 prob = prob - 5;
00669
00670
00671
00672
00673
00674 }
00675
00676
00677 update_proposed = (prob < 6);
00678
00679
00680 {
00681 const char *new_trans_str = xaccTransGetNum(new_trans);
00682 if (new_trans_str && strlen(new_trans_str) != 0)
00683 {
00684 long new_trans_number, split_number;
00685 const gchar *split_str;
00686 char *endptr;
00687 gboolean conversion_ok = TRUE;
00688
00689
00690 errno = 0;
00691 new_trans_number = strtol(new_trans_str, &endptr, 10);
00692
00693
00694 if (errno || endptr == new_trans_str)
00695 conversion_ok = FALSE;
00696
00697 split_str = xaccTransGetNum (xaccSplitGetParent (split));
00698 errno = 0;
00699 split_number = strtol(split_str, &endptr, 10);
00700 if (errno || endptr == split_str)
00701 conversion_ok = FALSE;
00702
00703 if ( (conversion_ok && (split_number == new_trans_number)) ||
00704 (safe_strcmp(new_trans_str, split_str) == 0) )
00705 {
00706
00707 prob += 4;
00708
00709 }
00710 else if (strlen(new_trans_str) > 0 && strlen(split_str) > 0)
00711 {
00712
00713
00714 prob -= 2;
00715 }
00716 }
00717 }
00718
00719
00720 {
00721 const char *memo = xaccSplitGetMemo(new_trans_fsplit);
00722 if (memo && strlen(memo) != 0)
00723 {
00724 if (safe_strcasecmp(memo, xaccSplitGetMemo(split)) == 0)
00725 {
00726
00727 prob = prob + 2;
00728
00729 }
00730 else if ((strncasecmp(memo, xaccSplitGetMemo(split),
00731 strlen(xaccSplitGetMemo(split)) / 2)
00732 == 0))
00733 {
00734
00735
00736
00737
00738 prob = prob + 1;
00739
00740 }
00741 }
00742 }
00743
00744
00745 {
00746 const char *descr = xaccTransGetDescription(new_trans);
00747 if (descr && strlen(descr) != 0)
00748 {
00749 if (safe_strcasecmp(descr,
00750 xaccTransGetDescription(xaccSplitGetParent(split)))
00751 == 0)
00752 {
00753
00754 prob = prob + 2;
00755
00756 }
00757 else if ((strncasecmp(descr,
00758 xaccTransGetDescription (xaccSplitGetParent(split)),
00759 strlen(xaccTransGetDescription (new_trans)) / 2)
00760 == 0))
00761 {
00762
00763
00764
00765
00766 prob = prob + 1;
00767
00768 }
00769 }
00770 }
00771
00772
00773 if (prob < display_threshold)
00774 {
00775 return;
00776 }
00777
00778
00779
00780
00781 match_info = g_new0(GNCImportMatchInfo, 1);
00782
00783 match_info->probability = prob;
00784 match_info->update_proposed = update_proposed;
00785 match_info->split = split;
00786 match_info->trans = xaccSplitGetParent(split);
00787
00788
00789
00790
00791 trans_info->match_list =
00792 g_list_prepend(trans_info->match_list,
00793 match_info);
00794 }
00795 }
00796
00797
00800 void gnc_import_find_split_matches(GNCImportTransInfo *trans_info,
00801 gint process_threshold,
00802 double fuzzy_amount_difference,
00803 gint match_date_hardlimit)
00804 {
00805 GList * list_element;
00806 Query *query = qof_query_create_for(GNC_ID_SPLIT);
00807 g_assert (trans_info);
00808
00809
00810 {
00811
00812
00813
00814
00815
00816
00817 Account *importaccount =
00818 xaccSplitGetAccount (gnc_import_TransInfo_get_fsplit (trans_info));
00819 time_t download_time = xaccTransGetDate (gnc_import_TransInfo_get_trans (trans_info));
00820
00821 qof_query_set_book (query, gnc_get_current_book());
00822 xaccQueryAddSingleAccountMatch (query, importaccount,
00823 QOF_QUERY_AND);
00824 xaccQueryAddDateMatchTT (query,
00825 TRUE, download_time - match_date_hardlimit * 86400,
00826 TRUE, download_time + match_date_hardlimit * 86400,
00827 QOF_QUERY_AND);
00828 list_element = qof_query_run (query);
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841 }
00842
00843
00844
00845
00846 while (list_element != NULL)
00847 {
00848 split_find_match (trans_info, list_element->data,
00849 process_threshold, fuzzy_amount_difference);
00850 list_element = g_list_next (list_element);
00851 }
00852
00853 qof_query_destroy (query);
00854 }
00855
00856
00857
00858
00859
00862 gboolean
00863 gnc_import_process_trans_item (GncImportMatchMap *matchmap,
00864 GNCImportTransInfo *trans_info)
00865 {
00866 Split * other_split;
00867 gnc_numeric imbalance_value;
00868
00869
00870
00871 g_assert (trans_info);
00872
00873
00874
00875
00876 switch (gnc_import_TransInfo_get_action (trans_info))
00877 {
00878 case GNCImport_SKIP:
00879 return FALSE;
00880 case GNCImport_ADD:
00881
00882
00883
00884 if (gnc_import_TransInfo_is_balanced(trans_info) == FALSE
00885 && gnc_import_TransInfo_get_destacc(trans_info) != NULL)
00886 {
00887
00888 Split *split =
00889 xaccMallocSplit
00890 (gnc_account_get_book
00891 (gnc_import_TransInfo_get_destacc (trans_info)));
00892 xaccTransAppendSplit
00893 (gnc_import_TransInfo_get_trans (trans_info), split);
00894 xaccAccountInsertSplit
00895 (gnc_import_TransInfo_get_destacc (trans_info), split);
00896
00897
00898
00899
00900
00901
00902 {
00903
00904
00905
00906
00907 imbalance_value =
00908 gnc_numeric_neg (xaccTransGetImbalanceValue
00909 (gnc_import_TransInfo_get_trans (trans_info)));
00910 xaccSplitSetValue (split, imbalance_value);
00911 xaccSplitSetAmount (split, imbalance_value);
00912 }
00913
00914
00915 }
00916
00917 xaccSplitSetReconcile(gnc_import_TransInfo_get_fsplit (trans_info), CREC);
00918
00919 xaccSplitSetDateReconciledSecs(gnc_import_TransInfo_get_fsplit (trans_info),
00920 time(NULL));
00921
00922 xaccTransCommitEdit(gnc_import_TransInfo_get_trans (trans_info));
00923 return TRUE;
00924 case GNCImport_UPDATE:
00925 {
00926 GNCImportMatchInfo *selected_match =
00927 gnc_import_TransInfo_get_selected_match(trans_info);
00928
00929
00930 if (!selected_match)
00931 {
00932 PWARN("No matching translaction to be cleared was chosen. Imported transaction will be ignored.");
00933 break;
00934 }
00935
00936
00937
00938 if (gnc_import_MatchInfo_get_split(selected_match) == NULL)
00939 {
00940 PERR("The split I am trying to update and reconcile is NULL, shouldn't happen!");
00941 }
00942 else
00943 {
00944
00945
00946 xaccTransBeginEdit(selected_match->trans);
00947
00948 xaccTransSetDatePostedSecs(selected_match->trans,
00949 xaccTransGetDate(xaccSplitGetParent(
00950 gnc_import_TransInfo_get_fsplit(trans_info))));
00951
00952 xaccSplitSetAmount(selected_match->split,
00953 xaccSplitGetAmount(
00954 gnc_import_TransInfo_get_fsplit(trans_info)));
00955 xaccSplitSetValue(selected_match->split,
00956 xaccSplitGetValue(
00957 gnc_import_TransInfo_get_fsplit(trans_info)));
00958
00959 imbalance_value = xaccTransGetImbalanceValue(
00960 gnc_import_TransInfo_get_trans(trans_info));
00961 other_split = xaccSplitGetOtherSplit(selected_match->split);
00962 if (!gnc_numeric_zero_p(imbalance_value) && other_split)
00963 {
00964 if (xaccSplitGetReconcile(other_split) == NREC)
00965 {
00966 imbalance_value = gnc_numeric_neg(imbalance_value);
00967 xaccSplitSetValue(other_split, imbalance_value);
00968 xaccSplitSetAmount(other_split, imbalance_value);
00969 }
00970
00971
00972 }
00973
00974 xaccTransSetDescription(selected_match->trans,
00975 xaccTransGetDescription(
00976 gnc_import_TransInfo_get_trans(trans_info)));
00977
00978 if (xaccSplitGetReconcile(selected_match->split) == NREC)
00979 {
00980 xaccSplitSetReconcile(selected_match->split, CREC);
00981 }
00982
00983
00984 xaccSplitSetDateReconciledSecs(selected_match->split, time(NULL));
00985
00986
00987
00988 if (gnc_import_split_has_online_id(trans_info->first_split))
00989 {
00990 gnc_import_set_split_online_id(selected_match->split,
00991 gnc_import_get_split_online_id(trans_info->first_split));
00992 }
00993
00994
00995
00996 xaccTransCommitEdit(selected_match->trans);
00997
00998
00999 matchmap_store_destination(matchmap, trans_info, TRUE);
01000
01001
01002 xaccTransDestroy(trans_info->trans);
01003
01004 xaccTransCommitEdit(trans_info->trans);
01005
01006 trans_info->trans = NULL;
01007 }
01008 }
01009 return TRUE;
01010 case GNCImport_CLEAR:
01011 {
01012 GNCImportMatchInfo *selected_match =
01013 gnc_import_TransInfo_get_selected_match (trans_info);
01014
01015
01016 if (!selected_match)
01017 {
01018 PWARN("No matching translaction to be cleared was chosen. Imported transaction will be ignored.");
01019 break;
01020 }
01021
01022
01023
01024 if (gnc_import_MatchInfo_get_split (selected_match) == NULL)
01025 {
01026 PERR("The split I am trying to reconcile is NULL, shouldn't happen!");
01027 }
01028 else
01029 {
01030
01031
01032 xaccTransBeginEdit(selected_match->trans);
01033
01034 if (xaccSplitGetReconcile
01035 (selected_match->split) == NREC)
01036 xaccSplitSetReconcile
01037 (selected_match->split, CREC);
01038
01039 xaccSplitSetDateReconciledSecs
01040 (selected_match->split, time(NULL));
01041
01042
01043
01044 if (gnc_import_split_has_online_id(trans_info->first_split))
01045 gnc_import_set_split_online_id
01046 (selected_match->split,
01047 gnc_import_get_split_online_id(trans_info->first_split));
01048
01049
01050
01051 xaccTransCommitEdit
01052 (selected_match->trans);
01053
01054
01055 matchmap_store_destination (matchmap, trans_info, TRUE);
01056
01057
01058 xaccTransDestroy(trans_info->trans);
01059
01060 xaccTransCommitEdit(trans_info->trans);
01061
01062 trans_info->trans = NULL;
01063 }
01064 }
01065 return TRUE;
01066 default:
01067 DEBUG("Invalid GNCImportAction for this imported transaction.");
01068 }
01069
01070 return FALSE;
01071 }
01072
01073
01074
01075
01076
01077
01078
01079 static gint check_trans_online_id(Transaction *trans1, void *user_data)
01080 {
01081 Account *account;
01082 Split *split1;
01083 Split *split2 = user_data;
01084 const gchar *online_id1;
01085 const gchar *online_id2;
01086
01087 account = xaccSplitGetAccount(split2);
01088 split1 = xaccTransFindSplitByAccount(trans1, account);
01089 if (split1 == split2)
01090 return 0;
01091
01092
01093
01094 g_assert(split1 != NULL);
01095
01096 if (gnc_import_split_has_online_id(split1))
01097 online_id1 = gnc_import_get_split_online_id(split1);
01098 else
01099 online_id1 = gnc_import_get_trans_online_id(trans1);
01100
01101 online_id2 = gnc_import_get_split_online_id(split2);
01102
01103 if ((online_id1 == NULL) ||
01104 (online_id2 == NULL) ||
01105 (strcmp(online_id1, online_id2) != 0))
01106 {
01107 return 0;
01108 }
01109 else
01110 {
01111
01112 return 1;
01113 }
01114 }
01115
01118 gboolean gnc_import_exists_online_id (Transaction *trans)
01119 {
01120 int i;
01121 gboolean online_id_exists = FALSE;
01122 Account *dest_acct;
01123 Split *source_split;
01124
01125
01126 source_split = xaccTransGetSplit(trans, 0);
01127 g_assert(source_split);
01128
01129
01130 dest_acct = xaccSplitGetAccount(source_split);
01131 online_id_exists = xaccAccountForEachTransaction(dest_acct,
01132 check_trans_online_id,
01133 source_split);
01134
01135
01136
01137 if (online_id_exists == TRUE)
01138 {
01139 DEBUG("%s", "Transaction with same online ID exists, destroying current transaction");
01140 xaccTransDestroy(trans);
01141 xaccTransCommitEdit(trans);
01142 }
01143 return online_id_exists;
01144 }
01145
01146
01147
01148
01149
01151 GNCImportTransInfo *
01152 gnc_import_TransInfo_new (Transaction *trans, GncImportMatchMap *matchmap)
01153 {
01154 GNCImportTransInfo *transaction_info;
01155 Split *split;
01156 g_assert (trans);
01157
01158 transaction_info = g_new0(GNCImportTransInfo, 1);
01159
01160 transaction_info->trans = trans;
01161
01162 split = xaccTransGetSplit(trans, 0);
01163 g_assert(split);
01164 transaction_info->first_split = split;
01165
01166
01167
01168 gnc_import_TransInfo_set_destacc (transaction_info,
01169 matchmap_find_destination (matchmap, transaction_info),
01170 FALSE);
01171 return transaction_info;
01172 }
01173
01174
01176 static gint compare_probability (gconstpointer a,
01177 gconstpointer b)
01178 {
01179 return(((GNCImportMatchInfo *)b)->probability -
01180 ((GNCImportMatchInfo *)a)->probability);
01181 }
01182
01187 void
01188 gnc_import_TransInfo_init_matches (GNCImportTransInfo *trans_info,
01189 GNCImportSettings *settings)
01190 {
01191 GNCImportMatchInfo * best_match = NULL;
01192 g_assert (trans_info);
01193
01194
01195
01196 gnc_import_find_split_matches(trans_info,
01197 gnc_import_Settings_get_display_threshold (settings),
01198 gnc_import_Settings_get_fuzzy_amount (settings),
01199 gnc_import_Settings_get_match_date_hardlimit (settings));
01200
01201 if (trans_info->match_list != NULL)
01202 {
01203 trans_info->match_list = g_list_sort(trans_info->match_list,
01204 compare_probability);
01205 best_match = g_list_nth_data(trans_info->match_list, 0);
01206 gnc_import_TransInfo_set_selected_match (trans_info,
01207 best_match,
01208 FALSE);
01209 if (best_match != NULL &&
01210 best_match->probability >= gnc_import_Settings_get_clear_threshold(settings))
01211 {
01212 trans_info->action = GNCImport_CLEAR;
01213 trans_info->selected_match_info = best_match;
01214 }
01215 else if (best_match == NULL ||
01216 best_match->probability <= gnc_import_Settings_get_add_threshold(settings))
01217 {
01218 trans_info->action = GNCImport_ADD;
01219 }
01220 else if (gnc_import_Settings_get_action_skip_enabled(settings))
01221 {
01222 trans_info->action = GNCImport_SKIP;
01223 }
01224 else if (gnc_import_Settings_get_action_update_enabled(settings))
01225 {
01226 trans_info->action = GNCImport_UPDATE;
01227 }
01228 else
01229 {
01230 trans_info->action = GNCImport_ADD;
01231 }
01232 }
01233 else
01234 {
01235 trans_info->action = GNCImport_ADD;
01236 }
01237 if (best_match &&
01238 trans_info->action == GNCImport_CLEAR &&
01239 gnc_import_Settings_get_action_update_enabled(settings))
01240 {
01241 if (best_match->update_proposed)
01242 {
01243 trans_info->action = GNCImport_UPDATE;
01244 }
01245 }
01246
01247 trans_info->previous_action = trans_info->action;
01248 }
01249
01250
01251
01252
01253 gboolean
01254 gnc_import_TransInfo_refresh_destacc (GNCImportTransInfo *transaction_info,
01255 GncImportMatchMap *matchmap)
01256 {
01257 Account *orig_destacc;
01258 Account *new_destacc = NULL;
01259 g_assert(transaction_info);
01260
01261 orig_destacc = gnc_import_TransInfo_get_destacc(transaction_info);
01262
01263
01264 if (gnc_import_TransInfo_get_destacc_selected_manually(transaction_info) == FALSE)
01265 {
01266
01267 new_destacc = matchmap_find_destination(matchmap, transaction_info);
01268 gnc_import_TransInfo_set_destacc(transaction_info, new_destacc, FALSE);
01269 }
01270 else
01271 {
01272 new_destacc = orig_destacc;
01273 }
01274
01275
01276 if (new_destacc != orig_destacc)
01277 {
01278 return TRUE;
01279 }
01280 else
01281 {
01282 return FALSE;
01283 }
01284 }
01285
01286