]> Dogcows Code - chaz/homebank/blobdiff - src/hb-import.c
import homebank-5.2.4
[chaz/homebank] / src / hb-import.c
index 8f6655d341b19d7c6ad55781f4389ee13d0ece72..7520c03a77a76cb6c78947f906f5dcb554d1b08a 100644 (file)
@@ -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.
  *
@@ -37,51 +37,1332 @@ extern struct HomeBank *GLOBALS;
 extern struct Preferences *PREFS;
 
 
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
+static void 
+da_import_context_gen_txn_destroy(ImportContext *context)
+{
+GList *list;
+
+       DB( g_print("\n[import] free gen txn list\n") );
+       list = g_list_first(context->gen_lst_txn);
+       while (list != NULL)
+       {
+       GenTxn *gentxn = list->data;
+               da_gen_txn_free(gentxn);
+               list = g_list_next(list);
+       }
+       g_list_free(context->gen_lst_txn);
+       context->gen_lst_txn = NULL;
+}
+
+
+static void 
+da_import_context_gen_acc_destroy(ImportContext *context)
+{
+GList *list;
+
+       DB( g_print("\n[import] free gen acc list\n") );
+       list = g_list_first(context->gen_lst_acc);
+       while (list != NULL)
+       {
+       GenAcc *genacc = list->data;
+               da_gen_acc_free(genacc);
+               list = g_list_next(list);
+       }
+       g_list_free(context->gen_lst_acc);
+       context->gen_lst_acc = NULL;
+
+}
+
 
+static void 
+da_import_context_clear(ImportContext *context)
+{
+       DB( g_print("\n[import] context clear\n") );
+
+       da_import_context_gen_txn_destroy(context);
+       da_import_context_gen_acc_destroy(context);
+       context->gen_next_acckey = 1;
 
+}
 
-Account *import_create_account(gchar *name, gchar *number)
+
+void 
+da_import_context_destroy(ImportContext *context)
 {
-Account *accitem, *existitem;
+GList *list;
+
+       DB( g_print("\n[import] context destroy\n") );
 
-       //first check we do not have already this imported account
-       existitem = da_acc_get_by_imp_name(name);
-       if(existitem != NULL)
-               return existitem;
+       da_import_context_gen_txn_destroy(context);
+       da_import_context_gen_acc_destroy(context);
+
+       DB( g_print(" free gen file list\n") );
+       list = g_list_first(context->gen_lst_file);
+       while (list != NULL)
+       {
+       GenFile *genfile = list->data;
+               da_gen_file_free(genfile);
+               list = g_list_next(list);
+       }
+       g_list_free(context->gen_lst_file);
+       context->gen_lst_file = NULL;
+}
+
+
+void 
+da_import_context_new(ImportContext *context)
+{
+       context->gen_lst_file = NULL;
 
-       DB( g_print(" ** create acc: '%s' '%s'\n", name, number) );
+       context->gen_lst_acc  = NULL;
+       context->gen_lst_txn  = NULL;
+       context->gen_next_acckey = 1;
+}
+
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
+
+GenFile *
+da_gen_file_malloc(void)
+{
+       return g_malloc0(sizeof(GenFile));
+}
+
+void 
+da_gen_file_free(GenFile *genfile)
+{
+       if(genfile != NULL)
+       {
+               if(genfile->filepath != NULL)
+                       g_free(genfile->filepath);
+
+               g_free(genfile);
+       }
+}
+
+
+GenFile *
+da_gen_file_get(GList *lst_file, guint32 key)
+{
+GenFile *existfile = NULL;
+GList *list;
+
+       list = g_list_first(lst_file);
+       while (list != NULL)
+       {
+       GenFile *genfile = list->data;
+
+               if( key == genfile->key )
+               {
+                       existfile = genfile;
+                       break;
+               }
+               list = g_list_next(list);
+       }
+       return existfile;
+}
+
+
+static GenFile *
+da_gen_file_get_by_name(GList *lst_file, gchar *filepath)
+{
+GenFile *existfile = NULL;
+GList *list;
 
-       accitem = da_acc_malloc();
-       accitem->key  = da_acc_get_max_key() + 1;
-       accitem->pos  = da_acc_length() + 1;
+       DB( g_print("da_gen_file_get_by_name\n") );
 
-       // existing named account ?
-       existitem = da_acc_get_by_name(name);
-       if(existitem != NULL)
-               accitem->imp_key = existitem->key;
+       list = g_list_first(lst_file);
+       while (list != NULL)
+       {
+       GenFile *genfile = list->data;
+
+               DB( g_print(" strcasecmp '%s' '%s'\n", filepath, genfile->filepath) );
+       
+               if(!strcasecmp(filepath, genfile->filepath))
+               {
+                       existfile = genfile;
+                       DB( g_print(" found\n") );
+                       break;
+               }
+               list = g_list_next(list);
+       }
+
+       return existfile;
+}
+
+
+GenFile *
+da_gen_file_append_from_filename(ImportContext *ictx, gchar *filename)
+{
+GenFile *genfile = NULL;
+gint filetype;
+
+       //todo: should check if its a file !!
+
+       filetype = homebank_alienfile_recognize(filename);
+
+       DB( g_print(" - filename '%s', type is %d\n", filename, filetype ) );
+
+       // we keep everything here
+       //if( (filetype == FILETYPE_OFX) || (filetype == FILETYPE_QIF) || (filetype == FILETYPE_CSV_HB) )
+       //{
+       GenFile *existgenfile;
+
+               existgenfile = da_gen_file_get_by_name(ictx->gen_lst_file, filename);
+               if(existgenfile == NULL)
+               {
+                       genfile = da_gen_file_malloc();
+                       genfile->filepath = g_strdup(filename);
+                       genfile->filetype = filetype;
+                       
+                       //append to list
+                       genfile->key = g_list_length (ictx->gen_lst_file) + 1;
+                       ictx->gen_lst_file = g_list_append(ictx->gen_lst_file, genfile);
+
+               }
+       //}
+
+       return genfile;
+}
+
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
+
+
+GenAcc *
+da_gen_acc_malloc(void)
+{
+       return g_malloc0(sizeof(GenAcc));
+}
+
+void 
+da_gen_acc_free(GenAcc *genacc)
+{
+       if(genacc != NULL)
+       {
+               if(genacc->name != NULL)
+                       g_free(genacc->name);
+               if(genacc->number != NULL)
+                       g_free(genacc->number);
+
+               g_free(genacc);
+       }
+}
+
+
+GenAcc *
+da_gen_acc_get_by_key(GList *lst_acc, guint32 key)
+{
+GenAcc *existacc = NULL;
+GList *list;
+
+       list = g_list_first(lst_acc);
+       while (list != NULL)
+       {
+       GenAcc *genacc = list->data;
+
+               if( key == genacc->key )
+               {
+                       existacc = genacc;
+                       break;
+               }
+               list = g_list_next(list);
+       }
+       return existacc;
+}
+
+
+static GenAcc *
+da_gen_acc_get_by_name(GList *lst_acc, gchar *name)
+{
+GenAcc *existacc = NULL;
+GList *list;
+
+       //DB( g_print("da_gen_acc_get_by_name\n") );
+
+       list = g_list_first(lst_acc);
+       while (list != NULL)
+       {
+       GenAcc *genacc = list->data;
+
+               //DB( g_print(" strcasecmp '%s' '%s'\n", name, genacc->name) );
+       
+               if(!strcasecmp(name, genacc->name))
+               {
+                       existacc = genacc;
+                       //DB( g_print(" found\n") );
+                       break;
+               }
+               list = g_list_next(list);
+       }
+
+       return existacc;
+}
 
-       if(!existitem && *name != 0)
-               accitem->name = g_strdup(name);
+
+Account *
+hb_import_acc_find_existing(gchar *name, gchar *number)
+{
+Account *retacc = NULL;
+GList *lacc, *list;
+
+       DB( g_print("\n[import] acc_find_existing\n") );
+
+       DB( g_print(" - search number '%s'\n", number) );
+       lacc = list = g_hash_table_get_values(GLOBALS->h_acc);
+       while (list != NULL)
+       {
+       Account *acc = list->data;
+               
+               //DB( g_print(" - eval acc '%s' or '%s'\n", acc->name, acc->number) );
+               if(number != NULL && acc->number && strlen(acc->number) )
+               {
+                       //prefer identifying with number & search number into acc->number
+                       if(g_strstr_len(number, -1, acc->number) != NULL)
+                       {
+                               DB( g_print(" - match number '%s'\n", acc->number) );
+                               retacc = acc;
+                               break;
+                       }
+               }
+               list = g_list_next(list);
+       }
+
+       //# 1815964 only test name if all number test failed
+       //if not found try with name    
+       if(retacc == NULL)
+       {
+               DB( g_print(" - search name '%s'\n", name) );
+               list = g_list_first(lacc);
+               while (list != NULL)
+               {
+               Account *acc = list->data;
+                       
+                       //DB( g_print(" - eval acc '%s' or '%s'\n", acc->name, acc->number) );
+                       if(retacc == NULL && name != NULL)
+                       {
+                               if(g_strstr_len(name, -1, acc->name) != NULL)
+                               {
+                                       DB( g_print(" - match name '%s'\n", acc->name) );
+                                       retacc = acc;
+                                       break;
+                               }
+                       }
+                       list = g_list_next(list);
+               }
+       }
+
+       g_list_free(lacc);
+
+       return retacc;
+}
+
+
+GenAcc *
+hb_import_gen_acc_get_next(ImportContext *ictx, gint filetype, gchar *name, gchar *number)
+{
+GenAcc *newacc;
+
+       DB( g_print("\n[import] acc_get_next\n") );
+
+       DB( g_print(" - type='%d', name='%s', number='%s'\n", filetype, name, number) );
+
+       // try to find a same name account
+       if( name != NULL )
+       {
+               newacc = da_gen_acc_get_by_name(ictx->gen_lst_acc, name);
+               if(newacc != NULL)
+               {
+                       DB( g_print(" - found existing '%s'\n", name) );
+                       goto end;
+               }
+       }
+
+       newacc = da_gen_acc_malloc();
+       if(newacc)
+       {
+               newacc->kfile = ictx->curr_kfile;
+               newacc->key = ictx->gen_next_acckey++;
+               newacc->kacc = DST_ACC_GLOBAL;
+               
+               if(name != NULL)
+               {
+                       newacc->is_unamed = FALSE;
+                       newacc->name = g_strdup(name);
+               }
+               else
+               {
+               GenFile *genfile;
+               gchar *basename;
+               
+                       newacc->is_unamed = TRUE;
+
+                       genfile = da_gen_file_get (ictx->gen_lst_file, newacc->kfile);
+                       basename = g_path_get_basename(genfile->filepath);
+                       
+                       newacc->name = g_strdup_printf("%s %d", basename, newacc->key);
+                       g_free(basename);
+               }
+               
+               if(number != NULL)
+                       newacc->number = g_strdup(number);
+
+               ictx->gen_lst_acc = g_list_append(ictx->gen_lst_acc, newacc);
+       }
+
+       DB( g_print(" - create new '%s'\n", newacc->name) );
+
+end:
+       newacc->filetype = filetype;
+       ictx->curr_kacc = newacc->key;
+
+       return newacc;
+}
+
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
+
+
+GenTxn *
+da_gen_txn_malloc(void)
+{
+       return g_malloc0(sizeof(GenTxn));
+}
+
+
+void 
+da_gen_txn_free(GenTxn *gentxn)
+{
+gint i;
+
+       if(gentxn != NULL)
+       {
+               if(gentxn->account != NULL)
+                       g_free(gentxn->account);
+
+               if(gentxn->rawinfo != NULL)
+                       g_free(gentxn->rawinfo);
+               if(gentxn->rawpayee != NULL)
+                       g_free(gentxn->rawpayee);
+               if(gentxn->rawmemo != NULL)
+                       g_free(gentxn->rawmemo);
+
+               if(gentxn->date != NULL)
+                       g_free(gentxn->date);
+               if(gentxn->info != NULL)
+                       g_free(gentxn->info);
+               if(gentxn->payee != NULL)
+                       g_free(gentxn->payee);
+               if(gentxn->memo != NULL)
+                       g_free(gentxn->memo);
+               if(gentxn->category != NULL)
+                       g_free(gentxn->category);
+               if(gentxn->tags != NULL)
+                       g_free(gentxn->tags);
+
+               for(i=0;i<TXN_MAX_SPLIT;i++)
+               {
+               GenSplit *s = &gentxn->splits[i];
+               
+                       if(s->memo != NULL)
+                               g_free(s->memo);
+                       if(s->category != NULL)
+                               g_free(s->category);    
+               }
+
+               if(gentxn->lst_existing != NULL)
+               {
+                       g_list_free(gentxn->lst_existing);
+                       gentxn->lst_existing = NULL;
+               }
+
+               g_free(gentxn);
+       }
+}
+
+static gint 
+da_gen_txn_compare_func(GenTxn *a, GenTxn *b)
+{
+gint retval = (gint)(a->julian - b->julian); 
+
+       if(!retval)
+               retval = (ABS(a->amount) - ABS(b->amount)) > 0 ? 1 : -1;
+       return (retval);
+}
+
+
+GList *
+da_gen_txn_sort(GList *list)
+{
+       return( g_list_sort(list, (GCompareFunc)da_gen_txn_compare_func));
+}
+
+
+void 
+da_gen_txn_move(GenTxn *sgentxn, GenTxn *dgentxn)
+{
+       if(sgentxn != NULL && dgentxn != NULL)
+       {
+               memcpy(dgentxn, sgentxn, sizeof(GenTxn));
+               memset(sgentxn, 0, sizeof(GenTxn));
+       }
+}
+
+
+void 
+da_gen_txn_append(ImportContext *ctx, GenTxn *gentxn)
+{
+       gentxn->kfile = ctx->curr_kfile;
+       gentxn->kacc  = ctx->curr_kacc;
+       gentxn->to_import = TRUE;
+       ctx->gen_lst_txn = g_list_append(ctx->gen_lst_txn, gentxn);
+}
+
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+
+
+static void _string_utf8_ucfirst(gchar **str)
+{
+gint str_len;
+gchar *first, *lc;
+
+       if( *str == NULL )
+               return;
+       
+       str_len = strlen(*str);
+       if( str_len <= 1 )
+               return;
+
+       first = g_utf8_strup(*str, 1);
+       lc    = g_utf8_strdown( g_utf8_next_char(*str), -1 );
+       g_free(*str);
+       *str = g_strjoin(NULL, first, lc, NULL);
+       g_free(first);
+       g_free(lc);
+}
+
+
+static gchar *
+_string_concat(gchar *str, gchar *addon)
+{
+gchar *retval;
+
+       DB( g_print(" - concat '%s' + '%s'\n", str, addon) );
+
+       if(str == NULL)
+               retval = g_strdup(addon);
        else
-               accitem->name = g_strdup_printf(_("(account %d)"), accitem->key);
+       {
+               retval = g_strjoin(" ", str, addon, NULL);
+               g_free(str);
+       }
 
-       accitem->imp_name = g_strdup(name);
+       DB( g_print(" - retval='%s'\n", retval) );      
+       return retval;
+}
 
-       if(number)
-               accitem->number = g_strdup(number);
 
-       //fixed 5.1.2
-       accitem->kcur = GLOBALS->kcur;
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
 
-       accitem->imported = TRUE;
-       da_acc_insert(accitem);
+gchar *hb_import_filetype_char_get(GenAcc *genacc)
+{
+gchar *retval = "";
+
+       switch(genacc->filetype)
+       {
+#ifndef NOOFX
+               case FILETYPE_OFX:
+                       retval = "OFX/QFX";
+                       break;
+#endif
+               case FILETYPE_QIF:
+                       retval = "QIF";
+                       break;
 
-       return accitem;
+               case FILETYPE_CSV_HB:
+                       retval = "CSV";
+                       break;
+       }
+
+       return retval;
 }
 
 
+void 
+hb_import_load_all(ImportContext *ictx)
+{
+GList *list;
+
+       DB( g_print("\n[import] load all\n") );
+
+       da_import_context_clear (ictx);
+       
+       list = g_list_first(ictx->gen_lst_file);
+       while (list != NULL)
+       {
+       GenFile *genfile = list->data;
+       
+               if(genfile->filetype != FILETYPE_UNKNOWN)
+               {
+                       //todo: move this to alien analysis
+                       genfile->encoding = homebank_file_getencoding(genfile->filepath);
+               
+                       ictx->curr_kfile = genfile->key;
+
+                       DB( g_print(" -> key = '%d'\n", genfile->key) );
+                       DB( g_print(" -> filepath = '%s'\n", genfile->filepath) );
+                       DB( g_print(" -> encoding = '%s'\n", genfile->encoding) );
+
+                       genfile->loaded = FALSE;
+                       genfile->invaliddatefmt = FALSE;                
+       
+                       switch(genfile->filetype)
+                       {
+               #ifndef NOOFX
+                               case FILETYPE_OFX:
+                                       homebank_ofx_import(ictx, genfile);
+                                       break;
+               #endif
+                               case FILETYPE_QIF:
+                                       homebank_qif_import(ictx, genfile);
+                                       break;
 
+                               case FILETYPE_CSV_HB:
+                                       homebank_csv_import(ictx, genfile);
+                                       break;
+                       }
 
+                       genfile->loaded = TRUE;
+               }
 
+               list = g_list_next(list);
+       }
+       
+       // sort by date
+       ictx->gen_lst_txn = da_gen_txn_sort(ictx->gen_lst_txn);
 
+}
+
+
+gint 
+hb_import_gen_acc_count_txn(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list;
+gint count = 0;
+
+       DB( g_print("\n[import] gen_acc_count_txn\n") );
+       
+       genacc->n_txnall = 0;
+       genacc->n_txnimp = 0;
+
+       list = g_list_first(ictx->gen_lst_txn);
+       while (list != NULL)
+       {
+       GenTxn *gentxn = list->data;
+
+               if(gentxn->kacc == genacc->key)
+               {
+                       genacc->n_txnall++;
+                       count++;
+
+                       DB( g_print(" count %03d: gentxn in=%d dup=%d '%s'\n", count, gentxn->to_import, gentxn->is_dst_similar, gentxn->memo) );
+
+                       if(gentxn->to_import) 
+                               genacc->n_txnimp++;
+               }
+               list = g_list_next(list);
+       }
+       return count;
+}
+
+
+/**
+ * uncheck duplicate within the import context files
+ */
+gint 
+hb_import_gen_txn_check_duplicate(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list1, *list2;
+gint count = 0;
+
+       DB( g_print("\n[import] gen_txn_check_duplicate\n") );
+
+       
+       list1 = g_list_first(ictx->gen_lst_txn);
+       while (list1 != NULL)
+       {
+       GenTxn *gentxn1 = list1->data;
+
+               if( (genacc->key == gentxn1->kacc) && (gentxn1->julian != 0) ) //same account, valid date
+               {
+                       list2 = g_list_next(list1);
+                       while (list2 != NULL)
+                       {
+                       GenTxn *gentxn2 = list2->data;
+
+                               if( (gentxn2->julian > gentxn1->julian) )
+                                       break;
+
+                               //todo: maybe reinforce controls here
+                               if( (gentxn2->kacc == gentxn1->kacc) 
+                                       && (gentxn2->julian == gentxn1->julian)
+                                       && (gentxn2->amount == gentxn1->amount)
+                                       && (hb_string_compare(gentxn2->memo, gentxn1->memo) == 0)
+                                       && (hb_string_compare(gentxn2->payee, gentxn1->payee) == 0)
+                                 )
+                               {
+                                       gentxn1->to_import = FALSE;
+                                       gentxn1->is_imp_similar = TRUE;
+                                       count++;
+
+                                       DB( g_print(" found import dup  %d=%d %.2f %.2f in=%d dup=%d\n", gentxn1->julian, gentxn2->julian, gentxn2->amount, gentxn1->amount, gentxn1->to_import, gentxn1->is_imp_similar) );
+
+                               }
+                               list2 = g_list_next(list2);
+                       }
+               }
+               list1 = g_list_next(list1);
+       }
+       return count;
+}
+
+
+/**
+ * uncheck existing txn into target account
+ *
+ */
+gint 
+hb_import_gen_txn_check_target_similar(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list1, *list2;
+gint count = 0;
+
+       DB( g_print("\n[import] gen_txn_check_target_similar\n") );
+
+       list1 = g_list_first(ictx->gen_lst_txn);
+       while (list1 != NULL)
+       {
+       GenTxn *gentxn = list1->data;
+
+               if(genacc->key == gentxn->kacc)
+               {
+                       gentxn->to_import = TRUE;
+                       gentxn->is_dst_similar = FALSE;
+
+                       if(genacc->kacc == DST_ACC_SKIP)
+                       {               
+                               gentxn->to_import = FALSE;
+                       }
+                       else
+                       {
+                       Account *acc = da_acc_get(genacc->kacc);
+                       
+                               if(acc != NULL)
+                               {
+                                       //clear previous existing
+                                       if(gentxn->lst_existing != NULL)
+                                       {
+                                               g_list_free(gentxn->lst_existing);
+                                               gentxn->lst_existing = NULL;
+                                       }
+                                       
+                                       // try to find existing transaction
+                                       list2 = g_queue_peek_tail_link(acc->txn_queue);
+                                       while (list2 != NULL)
+                                       {
+                                       Transaction *txn = list2->data;
+
+                                               //break if the date goes below the gentxn date + gap
+                                               if( txn->date < (gentxn->julian - ictx->opt_daygap) )
+                                                       break;
+
+                                               //#1586211 add of date tolerance
+                                               //todo: maybe reinforce controls here
+                                               if( ( txn->kacc == genacc->kacc ) 
+                                                && ( gentxn->julian <= (txn->date + ictx->opt_daygap) )
+                                                && ( gentxn->julian >= (txn->date - ictx->opt_daygap) )
+                                                && ( txn->amount == gentxn->amount ) 
+                                               )
+                                               {
+                                                       gentxn->lst_existing = g_list_append(gentxn->lst_existing, txn);
+                                                       gentxn->to_import = FALSE;
+                                                       gentxn->is_dst_similar = TRUE;
+                                                       count++;
+
+                                                       DB( g_print(" found dst acc dup %d %.2f '%s' in=%d, dup=%d\n", gentxn->julian, gentxn->amount, gentxn->memo, gentxn->to_import, gentxn->is_dst_similar) );
+                                               }
+                                               
+                                               list2 = g_list_previous(list2);
+                                       }
+                               }
+                               
+                       }
+               }
+
+               list1 = g_list_next(list1);
+       }
+
+       return count;
+}
+
+
+/**
+ * try to indentify xfer for OFX
+ *
+ */
+static gint 
+hb_import_gen_xfer_eval(ImportContext *ictx, GList *list)
+{
+GList *root, *list1, *list2;
+GList *match = NULL;
+gint count = 0;
+
+       DB( g_print("\n[import] gen xfer eval\n") );
+       
+       root = list1 = g_list_first(list);
+       while (list1 != NULL)
+       {
+       Transaction *txn1 = list1->data;
+       GenAcc *acc;
+
+               acc = da_gen_acc_get_by_key(ictx->gen_lst_acc, txn1->kacc);
+
+               DB( g_print(" src: kacc:%d dat:%d amt:%.2f %s kfxacc:%d\n", txn1->kacc, txn1->date, txn1->amount, txn1->memo, txn1->kxferacc) );
+
+               if( (acc != NULL) && (acc->filetype == FILETYPE_OFX) )
+               {
+                       match = NULL;
+                       count = 0;
+                       list2 = g_list_next(root);
+                       while (list2 != NULL)
+                       {
+                       Transaction *txn2 = list2->data;
+
+                               //DB( g_print(" -- chk: kacc:%d dat:%d amt:%.2f %s\n", txn2->kacc, txn2->date, txn2->amount, txn2->memo) );
+                               if( (txn2->date > txn1->date) )
+                                       break;
+
+                               if( (txn2 == txn1) || (txn2->paymode == PAYMODE_INTXFER) )
+                                       goto next;
+
+                               //todo: maybe reinforce controls here
+                               if( (txn2->kacc != txn1->kacc) 
+                                       && (txn2->date == txn1->date)
+                                       && (txn2->amount == -txn1->amount)
+                                       && (hb_string_compare(txn2->memo, txn1->memo) == 0)
+                                 )
+                               {
+                                       DB( g_print("  match: kacc:%d dat:%d amt:%.2f %s kfxacc:%d\n", txn2->kacc, txn2->date, txn2->amount, txn2->memo, txn2->kxferacc) );
+                                       match = g_list_append(match, txn2);
+                                       count++;
+                               }
+                       next:
+                               list2 = g_list_next(list2);
+                       }
+               
+                       if(count == 1)  //we found a single potential xfer, transform it
+                       {
+                       Transaction *txn2 ;
+
+                               DB( g_print("  single found => convert both\n") );
+
+                               list2 = g_list_first(match);    
+                               txn2 = list2->data;
+
+                               
+                               txn1->paymode = PAYMODE_INTXFER;
+                               transaction_xfer_change_to_child(txn1, txn2);
+                               
+                               /*list2 = g_list_first(match);  
+                               txn2 = list2->data;
+                               
+                               txn1->paymode = PAYMODE_INTXFER;
+                               txn1->kxferacc = txn2->kacc;
+                               
+                               txn2->paymode = PAYMODE_INTXFER;
+                               txn2->kxferacc = txn1->kacc;
+                               */
+                       }
+                       // if more than one, we cannot be sure
+                       g_list_free(match);
+               }
+
+               list1 = g_list_next(list1);
+       }
+       
+       return count;
+}
+
+
+/**
+ * apply the user option: date format, payee/memo/info mapping
+ *
+ */
+gboolean 
+hb_import_option_apply(ImportContext *ictx, GenAcc *genacc)
+{
+GList *list;
+
+       DB( g_print("\n[import] option apply\n") );
+
+       DB( g_print(" - type=%d\n", genacc->filetype) );
+
+       genacc->n_txnbaddate = 0;
+
+       list = g_list_first(ictx->gen_lst_txn);
+       while (list != NULL)
+       {
+       GenTxn *gentxn = list->data;
+
+               if(gentxn->kacc == genacc->key)
+               {
+                       if(genacc->filetype != FILETYPE_OFX)
+                       {
+                               gentxn->julian = hb_date_get_julian(gentxn->date, ictx->opt_dateorder);
+                               if( gentxn->julian == 0 )
+                               {
+                                       genacc->n_txnbaddate++;
+                               }
+                       }
+
+                       if(genacc->filetype == FILETYPE_OFX)
+                       {
+                               DB( g_print(" - ofx option apply\n") );
+
+                               g_free(gentxn->payee);
+                               g_free(gentxn->memo);
+                               g_free(gentxn->info);
+                               gentxn->payee = NULL;
+                               gentxn->memo = NULL;
+                               gentxn->info = NULL;
+
+                               // OFX:check_number
+                               gentxn->info = g_strdup(gentxn->rawinfo);
+
+                               //#1791482 map name to info (concat only)
+                               switch(ictx->opt_ofxname)
+                               {
+                                       //ofxname is stored into rawpayee
+                                       case 1:
+                                               gentxn->memo = g_strdup(gentxn->rawpayee);
+                                               break;
+                                       case 2:
+                                               gentxn->payee = g_strdup(gentxn->rawpayee);
+                                               break;
+                                       case 3:
+                                               g_free(gentxn->info);
+                                               gentxn->info = _string_concat(gentxn->rawinfo, gentxn->rawpayee);
+                                               break;
+                               }
+
+                               if(gentxn->rawmemo != NULL)
+                               {
+                                       switch(ictx->opt_ofxmemo)
+                                       {
+                                               //case 0: ignore
+                                               case 1: //add to info
+                                                       gentxn->info = _string_concat(gentxn->info, gentxn->rawmemo);
+                                                       break;
+
+                                               case 2: //add to memo
+                                                       gentxn->memo = _string_concat(gentxn->memo, gentxn->rawmemo);                                   
+                                                       break;
+
+                                               case 3: //add to payee
+                                                       gentxn->payee = _string_concat(gentxn->payee, gentxn->rawmemo);                                 
+                                                       break;
+                                       }
+                               }
+
+                               DB( g_print(" - payee is '%s'\n", gentxn->payee) );
+                               DB( g_print(" - memo is '%s'\n", gentxn->memo) );
+                               DB( g_print(" - info is '%s'\n", gentxn->info) );
+                               DB( g_print("\n") );
+
+                       }
+                       else
+                       if(genacc->filetype == FILETYPE_QIF)
+                       {
+                               DB( g_print(" - qif option apply\n") );
+
+                               g_free(gentxn->payee);
+                               g_free(gentxn->memo);
+                               gentxn->payee = NULL;
+                               gentxn->memo = NULL;
+
+                               if(!ictx->opt_qifswap)
+                               {
+                                       gentxn->payee = g_strdup(gentxn->rawpayee);
+                                       if(ictx->opt_qifmemo)
+                                               gentxn->memo = g_strdup(gentxn->rawmemo);
+                               }
+                               else
+                               {
+                                       gentxn->payee = g_strdup(gentxn->rawmemo);
+                                       if(ictx->opt_qifmemo)
+                                               gentxn->memo = g_strdup(gentxn->rawpayee);
+                               }
+
+                               DB( g_print(" - payee is '%s'\n", gentxn->payee) );
+                               DB( g_print(" - memo is '%s'\n", gentxn->memo) );
+
+                       }
+                       else
+                       if(genacc->filetype == FILETYPE_CSV_HB)
+                       {
+                               DB( g_print(" - csv option apply\n") );
+
+                               //#1791656 missing: info, payee and tagsg_freg_free(gentxn->payee);
+                               g_free(gentxn->payee);
+                               g_free(gentxn->memo);
+                               g_free(gentxn->info);
+
+                               gentxn->payee = g_strdup(gentxn->rawpayee);
+                               gentxn->memo = g_strdup(gentxn->rawmemo);
+                               gentxn->info = g_strdup(gentxn->rawinfo);
+                       }
+                       
+                       //at last do ucfirst
+                       if( (ictx->opt_ucfirst == TRUE) )
+                       {
+                               _string_utf8_ucfirst(&gentxn->memo);
+                               _string_utf8_ucfirst(&gentxn->payee);
+                               //category ?
+                       }
+                               
+               }
+               list = g_list_next(list);
+       }
+       
+       DB( g_print(" - nb_err=%d\n", genacc->n_txnbaddate) );
+       
+       return genacc->n_txnbaddate == 0 ? TRUE : FALSE;
+}
+
+
+/**
+ * convert a GenTxn to a Transaction
+ *
+ */
+Transaction *
+hb_import_convert_txn(GenAcc *genacc, GenTxn *gentxn)
+{
+Transaction *newope;
+Account *accitem;
+Payee *payitem;
+Category *catitem;
+gint nsplit;
+
+       DB( g_print("\n[import] convert txn\n") );
+
+       newope = NULL;
+
+       DB( g_print(" - gentxt %s %s %s\n", gentxn->account, gentxn->date, gentxn->memo) );
+       DB( g_print(" - genacc '%s' '%p'\n", gentxn->account, genacc) );
+
+       if( genacc != NULL)
+       {
+               newope = da_transaction_malloc();
+       
+               newope->kacc         = genacc->kacc;
+               newope->date             = gentxn->julian;
+               newope->paymode          = gentxn->paymode;
+               newope->info             = g_strdup(gentxn->info);
+               newope->memo             = g_strdup(gentxn->memo);
+               newope->amount           = gentxn->amount;
+
+               if(newope->amount > 0)
+                       newope->flags |= OF_INCOME;
+
+               //#773282 invert amount for ccard accounts
+               //todo: manage this (qif), it is not set to true anywhere
+               //if(ictx->is_ccard)
+               //      gentxn->amount *= -1;
+
+               // payee + append
+               if( gentxn->payee != NULL )
+               {
+                       payitem = da_pay_get_by_name(gentxn->payee);
+                       if(payitem == NULL)
+                       {
+                               //DB( g_print(" -> append pay: '%s'\n", item->payee ) );
+
+                               payitem = da_pay_malloc();
+                               payitem->name = g_strdup(gentxn->payee);
+                               //payitem->imported = TRUE;
+                               da_pay_append(payitem);
+
+                               //ictx->cnt_new_pay += 1;
+                       }
+                       newope->kpay = payitem->key;
+               }
+
+               // LCategory of transaction
+               // L[Transfer account name]
+               // LCategory of transaction/Class of transaction
+               // L[Transfer account]/Class of transaction
+               if( gentxn->category != NULL )
+               {
+                       if(g_str_has_prefix(gentxn->category, "["))     // this is a transfer account name
+                       {
+                       gchar *accname;
+
+                               //DB ( g_print(" -> transfer to: '%s'\n", item->category) );
+
+                               //remove brackets
+                               accname = hb_strdup_nobrackets(gentxn->category);
+
+                               // search target account + append if not exixts
+                               accitem = da_acc_get_by_name(accname);
+                               if(accitem == NULL)
+                               {
+                                       DB( g_print(" -> append int xfer dest acc: '%s'\n", accname ) );
+
+                                       accitem = da_acc_malloc();
+                                       accitem->name = g_strdup(accname);
+                                       //accitem->imported = TRUE;
+                                       //accitem->imp_name = g_strdup(accname);
+                                       da_acc_append(accitem);
+                               }
+
+                               newope->kxferacc = accitem->key;
+                               newope->paymode = PAYMODE_INTXFER;
+
+                               g_free(accname);
+                       }
+                       else
+                       {
+                               //DB ( g_print(" -> append cat: '%s'\n", item->category) );
+
+                               catitem = da_cat_append_ifnew_by_fullname(gentxn->category);
+                               if( catitem != NULL )
+                               {
+                                       //ictx->cnt_new_cat += 1;
+                                       newope->kcat = catitem->key;
+                               }
+                       }
+               }
+
+               //#1791656 miss tags also...
+               if( gentxn->tags != NULL )
+               {
+                       g_free(newope->tags);
+                       newope->tags = tags_parse(gentxn->tags);
+               }
+               
+               // splits, if not a xfer
+               if( gentxn->paymode != PAYMODE_INTXFER )
+               {
+                       if( gentxn->nb_splits > 0 )
+                       {
+                               newope->splits = da_split_new();
+                               for(nsplit=0;nsplit<gentxn->nb_splits;nsplit++)
+                               {
+                               GenSplit *s = &gentxn->splits[nsplit];
+                               Split *hbs;
+                               guint32 kcat = 0;
+                       
+                                       DB( g_print(" -> append split %d: '%s' '%.2f' '%s'\n", nsplit, s->category, s->amount, s->memo) );
+
+                                       if( s->category != NULL )
+                                       {
+                                               catitem = da_cat_append_ifnew_by_fullname(s->category);
+                                               if( catitem != NULL )
+                                               {
+                                                       kcat = catitem->key;
+                                               }
+                                       }
+
+                                       //todo: remove this when no more use ||
+                                       hb_string_replace_char('|', s->memo);
+                                       hbs = da_split_malloc ();
+                                       hbs->kcat   = kcat;
+                                       hbs->memo   = g_strdup(s->memo);
+                                       hbs->amount = s->amount;
+                                       da_splits_append(newope->splits, hbs);
+                                       hbs = NULL;                             
+                               }
+                       }
+               }
+               
+               newope->flags |= OF_ADDED;
+               if( newope->amount > 0 )
+                       newope->flags |= OF_INCOME;
+
+               if( gentxn->reconciled )
+                       newope->status = TXN_STATUS_RECONCILED;
+               else
+               if( gentxn->cleared )
+                       newope->status = TXN_STATUS_CLEARED;
+       }
+       return newope;
+}
+
+
+void 
+hb_import_apply(ImportContext *ictx)
+{
+GList *list, *lacc;
+GList *txnlist;
+guint32 kcommon = 0;
+guint changes = 0;
+
+       DB( g_print("\n[import] apply\n") );
+
+       //create accounts
+       list = g_list_first(ictx->gen_lst_acc);
+       while (list != NULL)
+       {
+       GenAcc *genacc = list->data;
+
+               DB( g_print(" #1 genacc: %d %s %s => %d\n", genacc->key, genacc->name, genacc->number, genacc->kacc) );
+
+               //we do create the common account once
+               if( (genacc->kacc == DST_ACC_GLOBAL) )
+               {
+                       if( kcommon == 0 )
+                       {
+                       Account *acc = da_acc_malloc ();
+                               
+                               acc->name = g_strdup(_("imported account"));
+                               if( da_acc_append(acc) )
+                               {
+                                       kcommon = acc->key;
+                                       changes++;                                              
+                               }
+                       }
+
+                       genacc->kacc = kcommon;
+               }
+               else
+               if( (genacc->kacc == DST_ACC_NEW) )
+               {
+               Account *acc = da_acc_malloc ();
+               
+                       acc->name = g_strdup(genacc->name);
+                       if( da_acc_append(acc) )
+                       {
+                               acc->number = g_strdup(genacc->number);
+                               acc->initial = genacc->initial;
+                               
+                               //store the target acc key
+                               genacc->kacc = acc->key;
+                               changes++;
+                       }
+               }
+               
+               list = g_list_next(list);
+       }
+
+       // insert every transactions into a temporary list
+       // we do this to keep a finished real txn list for detect xfer below
+       DB( g_print(" #2 insert txn\n") );
+
+       txnlist = NULL;
+       lacc = g_list_first(ictx->gen_lst_acc);
+       while (lacc != NULL)
+       {
+       GenAcc *genacc = lacc->data;
+
+               if(genacc->kacc != DST_ACC_SKIP)
+               {
+                       list = g_list_first(ictx->gen_lst_txn);
+                       while (list != NULL)
+                       {
+                       GenTxn *gentxn = list->data;
+
+                               if(gentxn->kacc == genacc->key && gentxn->to_import == TRUE)
+                               {
+                               Transaction *txn, *dtxn;
+               
+                                       txn = hb_import_convert_txn(genacc, gentxn);
+                                       if( txn )
+                                       {
+                                               dtxn = transaction_add(NULL, txn);
+                                               txnlist = g_list_append(txnlist, dtxn);                                 
+                                               da_transaction_free(txn);
+                                               //#1820618 forgot to report changes count
+                                               changes++;
+                                       }
+                               }
+                               list = g_list_next(list);
+                       }
+               }
+               lacc = g_list_next(lacc);
+       }
+
+       //auto assign
+       DB( g_print(" call auto assign\n") );
+       transaction_auto_assign(txnlist, 0);
+       
+       //check for ofx internal xfer
+       DB( g_print(" call hb_import_gen_xfer_eval\n") );
+       hb_import_gen_xfer_eval(ictx, txnlist);
+
+       g_list_free(txnlist);
+
+       GLOBALS->changes_count += changes;
+       
+}
+
+
+#if MYDEBUG
+void _import_context_debug_file_list(ImportContext *ctx)
+{
+GList *list;
+
+       g_print("\n--debug-- file list %d\n", g_list_length(ctx->gen_lst_file) );
+
+       list = g_list_first(ctx->gen_lst_file);
+       while (list != NULL)
+       {
+       GenFile *item = list->data;
+
+               g_print(" genfile: %d '%s' '%s'\ndf=%d invalid=%d\n", item->key, item->filepath, item->encoding, item->datefmt, item->invaliddatefmt);
+
+               list = g_list_next(list);
+       }
+
+}
+
+void _import_context_debug_acc_list(ImportContext *ctx)
+{
+GList *list;
+
+       g_print("\n--debug-- acc list %d\n", g_list_length(ctx->gen_lst_acc) );
+
+       list = g_list_first(ctx->gen_lst_acc);
+       while (list != NULL)
+       {
+       GenAcc *item = list->data;
+
+               g_print(" genacc: %d %s %s => %d\n", item->key, item->name, item->number, item->kacc);
+
+               list = g_list_next(list);
+       }
+
+}
+
+
+void _import_context_debug_txn_list(ImportContext *ctx)
+{
+GList *list;
+
+       g_print("\n--debug-- txn list %d\n", g_list_length(ctx->gen_lst_txn) );
+
+       list = g_list_first(ctx->gen_lst_txn);
+       while (list != NULL)
+       {
+       GenTxn *item = list->data;
+
+               g_print(" gentxn: (%d) %s %s (%d) %s %.2f\n", item->kfile, item->account, item->date, item->julian, item->memo, item->amount);
+
+               list = g_list_next(list);
+       }
+
+}
+
+#endif
 
This page took 0.045225 seconds and 4 git commands to generate.