X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=blobdiff_plain;f=src%2Fhb-transaction.c;fp=src%2Fhb-transaction.c;h=0368946f9fbb4267bb383d7ace7200f70f03a6a2;hp=29812d9ce5e1050640b55f05998c512d66a95c0a;hb=236cb5e47660876f46488ea8f76ecd5bebfa1fac;hpb=8892e90b335f94c296462a91534334b674226cd9 diff --git a/src/hb-transaction.c b/src/hb-transaction.c index 29812d9..0368946 100644 --- a/src/hb-transaction.c +++ b/src/hb-transaction.c @@ -1,5 +1,5 @@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2018 Maxime DOYEN + * Copyright (C) 1995-2019 Maxime DOYEN * * This file is part of HomeBank. * @@ -24,7 +24,7 @@ #include "hb-split.h" /****************************************************************************/ -/* Debug macros */ +/* Debug macro */ /****************************************************************************/ #define MYDEBUG 0 @@ -63,8 +63,12 @@ da_transaction_clean(Transaction *item) item->tags = NULL; } - da_splits_free(item->splits); - item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared + if(item->splits != NULL) + { + da_split_destroy(item->splits); + item->splits = NULL; + item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared + } if(item->same != NULL) { @@ -93,30 +97,10 @@ da_transaction_malloc(void) } -Transaction *da_transaction_copy(Transaction *src_txn, Transaction *dst_txn) -{ - DB( g_print("da_transaction_copy\n") ); - - da_transaction_clean (dst_txn); - - memmove(dst_txn, src_txn, sizeof(Transaction)); - - //duplicate the string - dst_txn->memo = g_strdup(src_txn->memo); - dst_txn->info = g_strdup(src_txn->info); - - //duplicate tags - transaction_tags_clone(src_txn, dst_txn); - - if (da_splits_clone(src_txn->splits, dst_txn->splits) > 0) - dst_txn->flags |= OF_SPLIT; //Flag that Splits are active - - return dst_txn; -} - - Transaction *da_transaction_init_from_template(Transaction *txn, Archive *arc) { + DB( g_print("da_transaction_init_from_template\n") ); + //txn->date = 0; txn->amount = arc->amount; //#1258344 keep the current account if tpl is empty @@ -128,15 +112,44 @@ Transaction *da_transaction_init_from_template(Transaction *txn, Archive *arc) txn->kpay = arc->kpay; txn->kcat = arc->kcat; txn->kxferacc = arc->kxferacc; - txn->memo = g_strdup(arc->memo); + txn->memo = g_strdup(arc->memo); txn->info = NULL; - if( da_splits_clone(arc->splits, txn->splits) > 0) + + //copy tags (with free previous here) + g_free(txn->tags); + txn->tags = tags_clone(arc->tags); + + da_split_destroy (txn->splits); + txn->splits = da_splits_clone(arc->splits); + if( da_splits_length (txn->splits) > 0 ) txn->flags |= OF_SPLIT; //Flag that Splits are active return txn; } +Transaction *da_transaction_set_default_template(Transaction *txn) +{ +Account *acc; +Archive *arc; + + DB( g_print("da_transaction_set_default_template\n") ); + + acc = da_acc_get(txn->kacc); + if(acc != NULL && acc->karc > 0) + { + arc = da_archive_get(acc->karc); + if( arc ) + { + DB( g_print(" - init with default template\n") ); + da_transaction_init_from_template(txn, arc); + } + } + + return txn; +} + + Transaction *da_transaction_clone(Transaction *src_item) { Transaction *new_item = g_memdup(src_item, sizeof(Transaction)); @@ -149,10 +162,12 @@ Transaction *new_item = g_memdup(src_item, sizeof(Transaction)); new_item->memo = g_strdup(src_item->memo); new_item->info = g_strdup(src_item->info); - //duplicate tags - transaction_tags_clone(src_item, new_item); + //duplicate tags/splits + //no g_free here to avoid free the src tags (memdup copied the ptr) + new_item->tags = tags_clone(src_item->tags); - if( da_splits_clone(src_item->splits, new_item->splits) > 0) + new_item->splits = da_splits_clone(src_item->splits); + if( da_splits_length (new_item->splits) > 0 ) new_item->flags |= OF_SPLIT; //Flag that Splits are active } @@ -238,12 +253,15 @@ gboolean da_transaction_insert_memo(Transaction *item) { gboolean retval = FALSE; - // append the memo if new if( item->memo != NULL ) { - if( g_hash_table_lookup(GLOBALS->h_memo, item->memo) == NULL ) + //# 1673048 add filter on status and date obsolete + if( (PREFS->txn_memoacp == TRUE) && (item->date >= (GLOBALS->today - PREFS->txn_memoacp_days)) ) { - retval = g_hash_table_insert(GLOBALS->h_memo, g_strdup(item->memo), NULL); + if( g_hash_table_lookup(GLOBALS->h_memo, item->memo) == NULL ) + { + retval = g_hash_table_insert(GLOBALS->h_memo, g_strdup(item->memo), NULL); + } } } return retval; @@ -373,7 +391,7 @@ void da_transaction_consistency(Transaction *item) Account *acc; Category *cat; Payee *pay; -gint nbsplit; +guint nbsplit; DB( g_print("\n[transaction] consistency\n") ); @@ -398,16 +416,17 @@ gint nbsplit; GLOBALS->changes_count++; } - // check split category #1340142 - split_cat_consistency(item->splits); - - //# 1416624 empty category when split - nbsplit = da_splits_count(item->splits); - if(nbsplit > 0 && item->kcat > 0) + //#1340142 check split category + if( item->splits != NULL ) { - g_warning("txn consistency: fixed invalid cat on split txn"); - item->kcat = 0; - GLOBALS->changes_count++; + nbsplit = da_splits_consistency(item->splits); + //# 1416624 empty category when split + if(nbsplit > 0 && item->kcat > 0) + { + g_warning("txn consistency: fixed invalid cat on split txn"); + item->kcat = 0; + GLOBALS->changes_count++; + } } // check payee exists @@ -444,7 +463,7 @@ gint nbsplit; } //#1628678 tags for internal xfer should be checked as well - + //#1787826 intxfer should not have split //#1295877 ensure income flag is correctly set item->flags &= ~(OF_INCOME); @@ -553,12 +572,14 @@ gboolean retval = FALSE; } -static GList *transaction_xfer_child_might_list_get(Transaction *ope) +static GList *transaction_xfer_child_might_list_get(Transaction *ope, guint32 kdstacc) { GList *lst_acc, *lnk_acc; GList *list, *matchlist = NULL; - //DB( g_print("\n[transaction] xfer_child_might_list_get\n") ); + DB( g_print("\n[transaction] xfer_child_might_list_get\n") ); + + DB( g_print(" - kdstacc:%d\n", kdstacc) ); lst_acc = g_hash_table_get_values(GLOBALS->h_acc); lnk_acc = g_list_first(lst_acc); @@ -566,7 +587,7 @@ GList *list, *matchlist = NULL; { Account *acc = lnk_acc->data; - if( !(acc->flags & AF_CLOSED) && (acc->key != ope->kacc) ) + if( !(acc->flags & AF_CLOSED) && (acc->key != ope->kacc) && ( (acc->key == kdstacc) || kdstacc == 0 ) ) { list = g_queue_peek_tail_link(acc->txn_queue); while (list != NULL) @@ -579,7 +600,7 @@ GList *list, *matchlist = NULL; if( transaction_xfer_child_might(ope, item, 0) == TRUE ) { - //DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->account, item->kxferacc) ); + DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->kacc, item->kxferacc) ); matchlist = g_list_append(matchlist, item); } list = g_list_previous(list); @@ -594,14 +615,14 @@ GList *list, *matchlist = NULL; } -void transaction_xfer_search_or_add_child(GtkWindow *parentwindow, Transaction *ope, gboolean manual) +void transaction_xfer_search_or_add_child(GtkWindow *parent, Transaction *ope, guint32 kdstacc) { GList *matchlist; gint count; DB( g_print("\n[transaction] xfer_search_or_add_child\n") ); - matchlist = transaction_xfer_child_might_list_get(ope); + matchlist = transaction_xfer_child_might_list_get(ope, kdstacc); count = g_list_length(matchlist); DB( g_print(" - found %d might match, switching\n", count) ); @@ -613,7 +634,7 @@ gint count; break; //todo: maybe with just 1 match the user must choose ? - //#942346: bad idea so to no let the user confirm, so let hil confirm + //#942346: bad idea so to no let the user confirm, so let him confirm /* case 1: //transform the transaction to a child transfer { @@ -625,13 +646,20 @@ gint count; default: //the user must choose himself { + gint result; Transaction *child; - child = ui_dialog_transaction_xfer_select_child(ope, matchlist); - if(child == NULL) - transaction_xfer_create_child(ope); - else + result = ui_dialog_transaction_xfer_select_child(parent, ope, matchlist, &child); + if( result == GTK_RESPONSE_ACCEPT ) + { transaction_xfer_change_to_child(ope, child); + } + else //GTK_RESPONSE_CANCEL + { + ope->paymode = PAYMODE_NONE; + ope->kxfer = 0; + ope->kxferacc = 0; + } } } @@ -762,9 +790,8 @@ Account *acc; } //synchronise tags since 5.1 - if(child->tags) - g_free(child->tags); - transaction_tags_clone (s_txn, child); + g_free(child->tags); + child->tags = tags_clone (s_txn->tags); } @@ -869,7 +896,22 @@ Account *acc; } -Transaction *transaction_add(Transaction *ope) +void transaction_changed(Transaction *txn) +{ +Account *acc; + + if( txn == NULL ) + return; + + acc = da_acc_get(txn->kacc); + if(acc == NULL) + return; + + acc->flags |= AF_CHANGED; +} + + +Transaction *transaction_add(GtkWindow *parent, Transaction *ope) { Transaction *newope; Account *acc; @@ -890,7 +932,8 @@ Account *acc; if(acc == NULL) return NULL; // delete any splits - da_splits_free(ope->splits); + da_split_destroy(ope->splits); + ope->splits = NULL; ope->flags &= ~(OF_SPLIT); //Flag that Splits are cleared } @@ -944,7 +987,7 @@ Account *acc; if(newope->paymode == PAYMODE_INTXFER) { - transaction_xfer_search_or_add_child(NULL, newope, FALSE); + transaction_xfer_search_or_add_child(parent, newope, newope->kxferacc); } } @@ -1003,7 +1046,7 @@ gboolean match = FALSE; { if( g_strrstr(text, searchtext) != NULL ) { - DB( g_print(" found case '%s'\n", searchtext) ); + DB( g_print("-- found case '%s'\n", searchtext) ); match = TRUE; } } @@ -1014,7 +1057,7 @@ gboolean match = FALSE; if( g_strrstr(word, needle) != NULL ) { - DB( g_print(" found nocase '%s'\n", searchtext) ); + DB( g_print("-- found nocase '%s'\n", searchtext) ); match = TRUE; } g_free(word); @@ -1032,30 +1075,26 @@ gboolean match = FALSE; if(text == NULL) return FALSE; - DB( g_print("- match RE %s in %s\n", searchtext, text) ); + DB( g_print("-- match RE %s in %s\n", searchtext, text) ); if( searchtext != NULL ) { match = g_regex_match_simple(searchtext, text, ((exact == TRUE)?0:G_REGEX_CASELESS) | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY ); - if (match == TRUE) { DB( g_print(" found pattern '%s'\n", searchtext) ); } + if (match == TRUE) { DB( g_print("-- found pattern '%s'\n", searchtext) ); } } return match; } -static Assign *transaction_auto_assign_eval_txn(GList *l_rul, Transaction *txn) +static GList *transaction_auto_assign_eval_txn(GList *l_rul, Transaction *txn) { -Assign *rule = NULL; +GList *ret_list = NULL; GList *list; - - DB( g_print("\n[transaction] auto_assign_eval_txn\n") ); - - DB( g_print("- eval every rules, and return the last that match\n") ); +gchar *text; list = g_list_first(l_rul); while (list != NULL) { Assign *rul = list->data; - gchar *text; text = txn->memo; if(rul->field == 1) //payee @@ -1068,30 +1107,28 @@ GList *list; if( !(rul->flags & ASGF_REGEX) ) { if( misc_text_match(text, rul->text, rul->flags & ASGF_EXACT) ) - rule = rul; + ret_list = g_list_append(ret_list, rul); } else { if( misc_regex_match(text, rul->text, rul->flags & ASGF_EXACT) ) - rule = rul; + ret_list = g_list_append(ret_list, rul); } list = g_list_next(list); } - return rule; + DB( g_print("- evaluated txn '%s'=> %d match\n", text, g_list_length (ret_list)) ); + + return ret_list; } -static Assign *transaction_auto_assign_eval(GList *l_rul, gchar *text) +static GList *transaction_auto_assign_eval(GList *l_rul, gchar *text) { -Assign *rule = NULL; +GList *ret_list = NULL; GList *list; - DB( g_print("\n[transaction] auto_assign_eval\n") ); - - DB( g_print("- eval every rules, and return the last that match\n") ); - list = g_list_first(l_rul); while (list != NULL) { @@ -1102,26 +1139,29 @@ GList *list; if( !(rul->flags & ASGF_REGEX) ) { if( misc_text_match(text, rul->text, rul->flags & ASGF_EXACT) ) - rule = rul; + ret_list = g_list_append(ret_list, rul); } else { if( misc_regex_match(text, rul->text, rul->flags & ASGF_EXACT) ) - rule = rul; + ret_list = g_list_append(ret_list, rul); } } list = g_list_next(list); } - return rule; + DB( g_print("- evaluated split '%s' => %d match\n", text, g_list_length (ret_list)) ); + + return ret_list; } -gint transaction_auto_assign(GList *ope_list, guint32 kacc) +guint transaction_auto_assign(GList *ope_list, guint32 kacc) { GList *l_ope; GList *l_rul; -gint changes = 0; +GList *l_match, *l_tmp; +guint changes = 0; DB( g_print("\n[transaction] auto_assign\n") ); @@ -1133,63 +1173,67 @@ gint changes = 0; Transaction *ope = l_ope->data; gboolean changed = FALSE; - DB( g_print("- eval ope '%s' : acc=%d, pay=%d, cat=%d\n", ope->memo, ope->kacc, ope->kpay, ope->kcat) ); + DB( g_print("\n- work on txn '%s' : acc=%d, pay=%d, cat=%d, %s\n", ope->memo, ope->kacc, ope->kpay, ope->kcat, (ope->flags & OF_SPLIT) ? "is_split" : "" ) ); //#1215521: added kacc == 0 if( (kacc == ope->kacc || kacc == 0) ) { - Assign *rul; - - rul = transaction_auto_assign_eval_txn(l_rul, ope); - if( rul != NULL ) + if( !(ope->flags & OF_SPLIT) ) { - if( (ope->kpay == 0 && (rul->flags & ASGF_DOPAY)) || (rul->flags & ASGF_OVWPAY) ) + l_match = l_tmp = transaction_auto_assign_eval_txn(l_rul, ope); + while( l_tmp != NULL ) { - if(ope->kpay != rul->kpay) { changed = TRUE; } - ope->kpay = rul->kpay; - } + Assign *rul = l_tmp->data; + + if( (ope->kpay == 0 && (rul->flags & ASGF_DOPAY)) || (rul->flags & ASGF_OVWPAY) ) + { + if(ope->kpay != rul->kpay) { changed = TRUE; } + ope->kpay = rul->kpay; + } - if( !(ope->flags & OF_SPLIT) ) - { if( (ope->kcat == 0 && (rul->flags & ASGF_DOCAT)) || (rul->flags & ASGF_OVWCAT) ) { if(ope->kcat != rul->kcat) { changed = TRUE; } ope->kcat = rul->kcat; } - } - if( (ope->paymode == 0 && (rul->flags & ASGF_DOMOD)) || (rul->flags & ASGF_OVWMOD) ) - { - //ugly hack - don't allow modify intxfer - if(ope->paymode != PAYMODE_INTXFER && rul->paymode != PAYMODE_INTXFER) + if( (ope->paymode == 0 && (rul->flags & ASGF_DOMOD)) || (rul->flags & ASGF_OVWMOD) ) { - if(ope->paymode != rul->paymode) { changed = TRUE; } - ope->paymode = rul->paymode; + //ugly hack - don't allow modify intxfer + if(ope->paymode != PAYMODE_INTXFER && rul->paymode != PAYMODE_INTXFER) + { + if(ope->paymode != rul->paymode) { changed = TRUE; } + ope->paymode = rul->paymode; + } } + l_tmp = g_list_next(l_tmp); } - + g_list_free(l_match); } - - if( ope->flags & OF_SPLIT ) + else { - guint i, nbsplit = da_splits_count(ope->splits); - + guint i, nbsplit = da_splits_length(ope->splits); + for(i=0;isplits[i]; + Split *split = da_splits_get(ope->splits, i); DB( g_print("- eval split '%s'\n", split->memo) ); - rul = transaction_auto_assign_eval(l_rul, split->memo); - if( rul != NULL ) + l_match = l_tmp = transaction_auto_assign_eval(l_rul, split->memo); + while( l_tmp != NULL ) { + Assign *rul = l_tmp->data; + //#1501144: check if user wants to set category in rule if( (split->kcat == 0 || (rul->flags & ASGF_OVWCAT)) && (rul->flags & ASGF_DOCAT) ) { if(split->kcat != rul->kcat) { changed = TRUE; } split->kcat = rul->kcat; } - } + l_tmp = g_list_next(l_tmp); + } + g_list_free(l_match); } } @@ -1209,144 +1253,267 @@ gint changes = 0; } -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -guint -transaction_tags_count(Transaction *ope) +static gboolean transaction_similar_match(Transaction *stxn, Transaction *dtxn, guint32 daygap) { -guint count = 0; -guint32 *ptr = ope->tags; - - //DB( g_print("\n[transaction] tags_count\n") ); - - if( ope->tags == NULL ) - return 0; +gboolean retval = FALSE; - while(*ptr++ != 0 && count < 32) - count++; + if(stxn == dtxn) + return FALSE; - return count; + DB( g_print(" date: %d - %d = %d\n", stxn->date, dtxn->date, stxn->date - dtxn->date) ); + + if( stxn->kcur == dtxn->kcur + && stxn->amount == dtxn->amount + && ( (stxn->date - dtxn->date) <= daygap ) + //todo: at import we also check payee, but maybe too strict here + && (hb_string_compare(stxn->memo, dtxn->memo) == 0) + ) + { + retval = TRUE; + } + return retval; } -void transaction_tags_clone(Transaction *src_txn, Transaction *dst_txn) +void transaction_similar_unmark(Account *acc) { -guint count; +GList *lnk_txn; - dst_txn->tags = NULL; - count = transaction_tags_count(src_txn); - if(count > 0) + lnk_txn = g_queue_peek_tail_link(acc->txn_queue); + while (lnk_txn != NULL) { - //1501962: we must also copy the final 0 - dst_txn->tags = g_memdup(src_txn->tags, (count+1)*sizeof(guint32)); + Transaction *stxn = lnk_txn->data; + stxn->marker = TXN_MARK_NONE; + lnk_txn = g_list_previous(lnk_txn); } } -guint -transaction_tags_parse(Transaction *ope, const gchar *tagstring) + +gint transaction_similar_mark(Account *acc, guint32 daygap) { -gchar **str_array; -guint count, i; -Tag *tag; +GList *lnk_txn, *list2; +gint nball = 0; +gint nbdup = 0; - DB( g_print("\n[transaction] tags_parse\n") ); + //warning the list must be sorted by date then amount + //ideally (easier to parse) we shoudl get a list sorted by amount, then date + DB( g_print("\n[transaction] check duplicate\n") ); - DB( g_print(" - tagstring='%s'\n", tagstring) ); + DB( g_print("\n - account:'%s' gap:%d\n", acc->name, daygap) ); - str_array = g_strsplit (tagstring, " ", 0); - count = g_strv_length( str_array ); + #if MYDEBUG == 1 + GTimer *t = g_timer_new(); + g_print(" - start parse\n"); + #endif - g_free(ope->tags); - ope->tags = NULL; - DB( g_print(" -> reset storage %p\n", ope->tags) ); + /* + llast = g_list_last(old ope list); + DB( g_print("- end last : %f sec\n", g_timer_elapsed(t, NULL)) ); + g_timer_reset(t); + ltxn = llast->data; + g_date_clear(&gd, 1); + g_date_set_julian(&gd, ltxn->date); + g_print(" - last julian=%u %02d-%02d-%04d\n", ltxn->date, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd)); - if( count > 0 ) - { + minjulian = ltxn->date - (366*2); + g_date_clear(&gd, 1); + g_date_set_julian(&gd, minjulian); + g_print(" - min julian=%u %02d-%02d-%04d\n", minjulian, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd)); + */ + + transaction_similar_unmark(acc); - ope->tags = g_new0(guint32, count + 1); + //mark duplicate + lnk_txn = g_queue_peek_tail_link(acc->txn_queue); + while (lnk_txn != NULL) + { + Transaction *stxn = lnk_txn->data; - DB( g_print(" -> storage %p\n", ope->tags) ); + //if(stxn->date < minjulian) + // break; + DB( g_print("------\n eval src: %d, '%s', '%s', %.2f\n", stxn->date, stxn->info, stxn->memo, stxn->amount) ); - for(i=0;idata; - newtag->name = g_strdup(str_array[i]); - da_tag_append(newtag); - tag = da_tag_get_by_name(str_array[i]); - } + DB( g_print(" + with dst: %d, '%s', '%s', %.2f\n", dtxn->date, dtxn->info, dtxn->memo, dtxn->amount) ); - DB( g_print(" -> storing %d=>%s at tags pos %d\n", tag->key, tag->name, i) ); + if( (stxn->date - dtxn->date) > daygap ) + { + DB( g_print(" break %d %d\n", (dtxn->date - daygap) , (stxn->date - daygap)) ); + break; + } + + if( dtxn->marker == TXN_MARK_NONE ) + { + if( transaction_similar_match(stxn, dtxn, daygap) ) + { + stxn->marker = TXN_MARK_DUPSRC; + dtxn->marker = TXN_MARK_DUPDST; + DB( g_print(" = dtxn marker=%d\n", dtxn->marker) ); + nball++; + } + } + else + { + DB( g_print(" already marked %d\n", dtxn->marker) ); + } - ope->tags[i] = tag->key; + + list2 = g_list_previous(list2); } - ope->tags[i] = 0; + + DB( g_print(" = stxn marker=%d\n", stxn->marker) ); + if( stxn->marker == TXN_MARK_DUPSRC ) + nbdup++; + + lnk_txn = g_list_previous(lnk_txn); } - //hex_dump(ope->tags, sizeof(guint32*)*count+1); + DB( g_print(" - end parse : %f sec\n", g_timer_elapsed(t, NULL)) ); + DB( g_timer_destroy (t) ); - g_strfreev (str_array); + DB( g_print(" - found: %d/%d dup\n", nbdup, nball ) ); - return count; + return nbdup; } -gchar * -transaction_tags_tostring(Transaction *ope) + +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ +/* = = experimental = = */ +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + + +/* +probably add a structure hosted into a glist here +with kind of problem: duplicate, child xfer, orphan xfer +and collect all that with target txn +*/ + + +/*void future_transaction_test_account(Account *acc) { -guint count, i; -gchar **str_array; -gchar *tagstring; -Tag *tag; +GList *lnk_txn, *list2; +gint nball = 0; +gint nbdup = 0; +gint nbxfer = 0; +GPtrArray *array; - DB( g_print("\n[transaction] tags_tostring\n") ); +//future +gint gapday = 0, i; - DB( g_print(" -> tags at=%p\n", ope->tags) ); + //warning the list must be sorted by date then amount + //ideally (easier to parse) we shoudl get a list sorted by amount, then date - if( ope->tags == NULL ) - { + DB( g_print("\n[transaction] check duplicate\n") ); - return NULL; - } - else - { - count = transaction_tags_count(ope); - DB( g_print(" -> tags at=%p, nbtags=%d\n", ope->tags, count) ); - str_array = g_new0(gchar*, count+1); + DB( g_print("\n - account:'%s'\n", acc->name) ); + + GTimer *t = g_timer_new(); + g_print(" - start parse\n"); + - DB( g_print(" -> str_array at %p\n", str_array) ); + llast = g_list_last(old ope list); + DB( g_print("- end last : %f sec\n", g_timer_elapsed(t, NULL)) ); + g_timer_reset(t); - //hex_dump(ope->tags, sizeof(guint32*)*(count+1)); + ltxn = llast->data; + g_date_clear(&gd, 1); + g_date_set_julian(&gd, ltxn->date); + g_print(" - last julian=%u %02d-%02d-%04d\n", ltxn->date, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd)); - for(i=0;idate - (366*2); + g_date_clear(&gd, 1); + g_date_set_julian(&gd, minjulian); + g_print(" - min julian=%u %02d-%02d-%04d\n", minjulian, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd)); + + array = g_ptr_array_sized_new (25); + + lnk_txn = g_queue_peek_tail_link(acc->txn_queue); + while (lnk_txn != NULL) + { + Transaction *stxn = lnk_txn->data; + + //if(stxn->date < minjulian) + // break; + DB( g_print("------\n eval src: %d, '%s', '%s', %2.f\n", stxn->date, stxn->info, stxn->memo, stxn->amount) ); + + stxn->marker = 0; + list2 = g_list_previous(lnk_txn); + while (list2 != NULL) { - DB( g_print(" -> try to get tag %d\n", ope->tags[i]) ); + Transaction *dtxn = list2->data; + + stxn->marker = 0; + if( (dtxn->date + gapday) < (stxn->date + gapday) ) + break; + + DB( g_print(" + with dst: %d, '%s', '%s', %2.f\n", dtxn->date, dtxn->info, dtxn->memo, dtxn->amount) ); - tag = da_tag_get(ope->tags[i]); - if( tag ) + if( transaction_similar_match(stxn, dtxn, gapday) ) { - DB( g_print(" -> get %s at %d\n", tag->name, i) ); - str_array[i] = tag->name; + g_ptr_array_add (array, stxn); + g_ptr_array_add (array, dtxn); + nbdup++; + DB( g_print(" + dst=1 src=1\n") ); } - else - str_array[i] = NULL; - + nball++; + list2 = g_list_previous(list2); } - tagstring = g_strjoinv(" ", str_array); + lnk_txn = g_list_previous(lnk_txn); + } - g_free (str_array); + DB( g_print(" - end parse : %f sec\n", g_timer_elapsed(t, NULL)) ); + DB( g_timer_destroy (t) ); + for(i=0;ilen;i++) + { + Transaction *txn = g_ptr_array_index(array, i); + txn->marker = 1; } - return tagstring; + g_ptr_array_free(array, TRUE); + + DB( g_print(" - found: %d/%d dup, %d xfer\n", nbdup, nball, nbxfer ) ); + } + + + + +//todo: add a limitation, no need to go through all txn +// 1 year in th past, or abolute number ? +gint future_transaction_test_notification(void) +{ +GList *lst_acc, *lnk_acc; + + DB( g_print("\ntransaction_test_notification\n") ); + + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) + { + Account *acc = lnk_acc->data; + + transaction_similar_mark(acc); + + lnk_acc = g_list_next(lnk_acc); + } + g_list_free(lst_acc); + + return 0; +} +*/ + + +