]> Dogcows Code - chaz/homebank/blob - src/hb-import.c
import homebank-5.2.4
[chaz/homebank] / src / hb-import.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "homebank.h"
21 #include "hb-import.h"
22
23
24 /****************************************************************************/
25 /* Debug macros */
26 /****************************************************************************/
27 #define MYDEBUG 0
28
29 #if MYDEBUG
30 #define DB(x) (x);
31 #else
32 #define DB(x);
33 #endif
34
35 /* our global datas */
36 extern struct HomeBank *GLOBALS;
37 extern struct Preferences *PREFS;
38
39
40 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
41 static void
42 da_import_context_gen_txn_destroy(ImportContext *context)
43 {
44 GList *list;
45
46 DB( g_print("\n[import] free gen txn list\n") );
47 list = g_list_first(context->gen_lst_txn);
48 while (list != NULL)
49 {
50 GenTxn *gentxn = list->data;
51 da_gen_txn_free(gentxn);
52 list = g_list_next(list);
53 }
54 g_list_free(context->gen_lst_txn);
55 context->gen_lst_txn = NULL;
56 }
57
58
59 static void
60 da_import_context_gen_acc_destroy(ImportContext *context)
61 {
62 GList *list;
63
64 DB( g_print("\n[import] free gen acc list\n") );
65 list = g_list_first(context->gen_lst_acc);
66 while (list != NULL)
67 {
68 GenAcc *genacc = list->data;
69 da_gen_acc_free(genacc);
70 list = g_list_next(list);
71 }
72 g_list_free(context->gen_lst_acc);
73 context->gen_lst_acc = NULL;
74
75 }
76
77
78 static void
79 da_import_context_clear(ImportContext *context)
80 {
81 DB( g_print("\n[import] context clear\n") );
82
83 da_import_context_gen_txn_destroy(context);
84 da_import_context_gen_acc_destroy(context);
85 context->gen_next_acckey = 1;
86
87 }
88
89
90 void
91 da_import_context_destroy(ImportContext *context)
92 {
93 GList *list;
94
95 DB( g_print("\n[import] context destroy\n") );
96
97 da_import_context_gen_txn_destroy(context);
98 da_import_context_gen_acc_destroy(context);
99
100 DB( g_print(" free gen file list\n") );
101 list = g_list_first(context->gen_lst_file);
102 while (list != NULL)
103 {
104 GenFile *genfile = list->data;
105 da_gen_file_free(genfile);
106 list = g_list_next(list);
107 }
108 g_list_free(context->gen_lst_file);
109 context->gen_lst_file = NULL;
110 }
111
112
113 void
114 da_import_context_new(ImportContext *context)
115 {
116 context->gen_lst_file = NULL;
117
118 context->gen_lst_acc = NULL;
119 context->gen_lst_txn = NULL;
120 context->gen_next_acckey = 1;
121 }
122
123
124 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
125
126 GenFile *
127 da_gen_file_malloc(void)
128 {
129 return g_malloc0(sizeof(GenFile));
130 }
131
132 void
133 da_gen_file_free(GenFile *genfile)
134 {
135 if(genfile != NULL)
136 {
137 if(genfile->filepath != NULL)
138 g_free(genfile->filepath);
139
140 g_free(genfile);
141 }
142 }
143
144
145 GenFile *
146 da_gen_file_get(GList *lst_file, guint32 key)
147 {
148 GenFile *existfile = NULL;
149 GList *list;
150
151 list = g_list_first(lst_file);
152 while (list != NULL)
153 {
154 GenFile *genfile = list->data;
155
156 if( key == genfile->key )
157 {
158 existfile = genfile;
159 break;
160 }
161 list = g_list_next(list);
162 }
163 return existfile;
164 }
165
166
167 static GenFile *
168 da_gen_file_get_by_name(GList *lst_file, gchar *filepath)
169 {
170 GenFile *existfile = NULL;
171 GList *list;
172
173 DB( g_print("da_gen_file_get_by_name\n") );
174
175 list = g_list_first(lst_file);
176 while (list != NULL)
177 {
178 GenFile *genfile = list->data;
179
180 DB( g_print(" strcasecmp '%s' '%s'\n", filepath, genfile->filepath) );
181
182 if(!strcasecmp(filepath, genfile->filepath))
183 {
184 existfile = genfile;
185 DB( g_print(" found\n") );
186 break;
187 }
188 list = g_list_next(list);
189 }
190
191 return existfile;
192 }
193
194
195 GenFile *
196 da_gen_file_append_from_filename(ImportContext *ictx, gchar *filename)
197 {
198 GenFile *genfile = NULL;
199 gint filetype;
200
201 //todo: should check if its a file !!
202
203 filetype = homebank_alienfile_recognize(filename);
204
205 DB( g_print(" - filename '%s', type is %d\n", filename, filetype ) );
206
207 // we keep everything here
208 //if( (filetype == FILETYPE_OFX) || (filetype == FILETYPE_QIF) || (filetype == FILETYPE_CSV_HB) )
209 //{
210 GenFile *existgenfile;
211
212 existgenfile = da_gen_file_get_by_name(ictx->gen_lst_file, filename);
213 if(existgenfile == NULL)
214 {
215 genfile = da_gen_file_malloc();
216 genfile->filepath = g_strdup(filename);
217 genfile->filetype = filetype;
218
219 //append to list
220 genfile->key = g_list_length (ictx->gen_lst_file) + 1;
221 ictx->gen_lst_file = g_list_append(ictx->gen_lst_file, genfile);
222
223 }
224 //}
225
226 return genfile;
227 }
228
229
230 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
231
232
233 GenAcc *
234 da_gen_acc_malloc(void)
235 {
236 return g_malloc0(sizeof(GenAcc));
237 }
238
239 void
240 da_gen_acc_free(GenAcc *genacc)
241 {
242 if(genacc != NULL)
243 {
244 if(genacc->name != NULL)
245 g_free(genacc->name);
246 if(genacc->number != NULL)
247 g_free(genacc->number);
248
249 g_free(genacc);
250 }
251 }
252
253
254 GenAcc *
255 da_gen_acc_get_by_key(GList *lst_acc, guint32 key)
256 {
257 GenAcc *existacc = NULL;
258 GList *list;
259
260 list = g_list_first(lst_acc);
261 while (list != NULL)
262 {
263 GenAcc *genacc = list->data;
264
265 if( key == genacc->key )
266 {
267 existacc = genacc;
268 break;
269 }
270 list = g_list_next(list);
271 }
272 return existacc;
273 }
274
275
276 static GenAcc *
277 da_gen_acc_get_by_name(GList *lst_acc, gchar *name)
278 {
279 GenAcc *existacc = NULL;
280 GList *list;
281
282 //DB( g_print("da_gen_acc_get_by_name\n") );
283
284 list = g_list_first(lst_acc);
285 while (list != NULL)
286 {
287 GenAcc *genacc = list->data;
288
289 //DB( g_print(" strcasecmp '%s' '%s'\n", name, genacc->name) );
290
291 if(!strcasecmp(name, genacc->name))
292 {
293 existacc = genacc;
294 //DB( g_print(" found\n") );
295 break;
296 }
297 list = g_list_next(list);
298 }
299
300 return existacc;
301 }
302
303
304 Account *
305 hb_import_acc_find_existing(gchar *name, gchar *number)
306 {
307 Account *retacc = NULL;
308 GList *lacc, *list;
309
310 DB( g_print("\n[import] acc_find_existing\n") );
311
312 DB( g_print(" - search number '%s'\n", number) );
313 lacc = list = g_hash_table_get_values(GLOBALS->h_acc);
314 while (list != NULL)
315 {
316 Account *acc = list->data;
317
318 //DB( g_print(" - eval acc '%s' or '%s'\n", acc->name, acc->number) );
319 if(number != NULL && acc->number && strlen(acc->number) )
320 {
321 //prefer identifying with number & search number into acc->number
322 if(g_strstr_len(number, -1, acc->number) != NULL)
323 {
324 DB( g_print(" - match number '%s'\n", acc->number) );
325 retacc = acc;
326 break;
327 }
328 }
329 list = g_list_next(list);
330 }
331
332 //# 1815964 only test name if all number test failed
333 //if not found try with name
334 if(retacc == NULL)
335 {
336 DB( g_print(" - search name '%s'\n", name) );
337 list = g_list_first(lacc);
338 while (list != NULL)
339 {
340 Account *acc = list->data;
341
342 //DB( g_print(" - eval acc '%s' or '%s'\n", acc->name, acc->number) );
343 if(retacc == NULL && name != NULL)
344 {
345 if(g_strstr_len(name, -1, acc->name) != NULL)
346 {
347 DB( g_print(" - match name '%s'\n", acc->name) );
348 retacc = acc;
349 break;
350 }
351 }
352 list = g_list_next(list);
353 }
354 }
355
356 g_list_free(lacc);
357
358 return retacc;
359 }
360
361
362 GenAcc *
363 hb_import_gen_acc_get_next(ImportContext *ictx, gint filetype, gchar *name, gchar *number)
364 {
365 GenAcc *newacc;
366
367 DB( g_print("\n[import] acc_get_next\n") );
368
369 DB( g_print(" - type='%d', name='%s', number='%s'\n", filetype, name, number) );
370
371 // try to find a same name account
372 if( name != NULL )
373 {
374 newacc = da_gen_acc_get_by_name(ictx->gen_lst_acc, name);
375 if(newacc != NULL)
376 {
377 DB( g_print(" - found existing '%s'\n", name) );
378 goto end;
379 }
380 }
381
382 newacc = da_gen_acc_malloc();
383 if(newacc)
384 {
385 newacc->kfile = ictx->curr_kfile;
386 newacc->key = ictx->gen_next_acckey++;
387 newacc->kacc = DST_ACC_GLOBAL;
388
389 if(name != NULL)
390 {
391 newacc->is_unamed = FALSE;
392 newacc->name = g_strdup(name);
393 }
394 else
395 {
396 GenFile *genfile;
397 gchar *basename;
398
399 newacc->is_unamed = TRUE;
400
401 genfile = da_gen_file_get (ictx->gen_lst_file, newacc->kfile);
402 basename = g_path_get_basename(genfile->filepath);
403
404 newacc->name = g_strdup_printf("%s %d", basename, newacc->key);
405 g_free(basename);
406 }
407
408 if(number != NULL)
409 newacc->number = g_strdup(number);
410
411 ictx->gen_lst_acc = g_list_append(ictx->gen_lst_acc, newacc);
412 }
413
414 DB( g_print(" - create new '%s'\n", newacc->name) );
415
416 end:
417 newacc->filetype = filetype;
418 ictx->curr_kacc = newacc->key;
419
420 return newacc;
421 }
422
423
424 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
425
426
427 GenTxn *
428 da_gen_txn_malloc(void)
429 {
430 return g_malloc0(sizeof(GenTxn));
431 }
432
433
434 void
435 da_gen_txn_free(GenTxn *gentxn)
436 {
437 gint i;
438
439 if(gentxn != NULL)
440 {
441 if(gentxn->account != NULL)
442 g_free(gentxn->account);
443
444 if(gentxn->rawinfo != NULL)
445 g_free(gentxn->rawinfo);
446 if(gentxn->rawpayee != NULL)
447 g_free(gentxn->rawpayee);
448 if(gentxn->rawmemo != NULL)
449 g_free(gentxn->rawmemo);
450
451 if(gentxn->date != NULL)
452 g_free(gentxn->date);
453 if(gentxn->info != NULL)
454 g_free(gentxn->info);
455 if(gentxn->payee != NULL)
456 g_free(gentxn->payee);
457 if(gentxn->memo != NULL)
458 g_free(gentxn->memo);
459 if(gentxn->category != NULL)
460 g_free(gentxn->category);
461 if(gentxn->tags != NULL)
462 g_free(gentxn->tags);
463
464 for(i=0;i<TXN_MAX_SPLIT;i++)
465 {
466 GenSplit *s = &gentxn->splits[i];
467
468 if(s->memo != NULL)
469 g_free(s->memo);
470 if(s->category != NULL)
471 g_free(s->category);
472 }
473
474 if(gentxn->lst_existing != NULL)
475 {
476 g_list_free(gentxn->lst_existing);
477 gentxn->lst_existing = NULL;
478 }
479
480 g_free(gentxn);
481 }
482 }
483
484 static gint
485 da_gen_txn_compare_func(GenTxn *a, GenTxn *b)
486 {
487 gint retval = (gint)(a->julian - b->julian);
488
489 if(!retval)
490 retval = (ABS(a->amount) - ABS(b->amount)) > 0 ? 1 : -1;
491 return (retval);
492 }
493
494
495 GList *
496 da_gen_txn_sort(GList *list)
497 {
498 return( g_list_sort(list, (GCompareFunc)da_gen_txn_compare_func));
499 }
500
501
502 void
503 da_gen_txn_move(GenTxn *sgentxn, GenTxn *dgentxn)
504 {
505 if(sgentxn != NULL && dgentxn != NULL)
506 {
507 memcpy(dgentxn, sgentxn, sizeof(GenTxn));
508 memset(sgentxn, 0, sizeof(GenTxn));
509 }
510 }
511
512
513 void
514 da_gen_txn_append(ImportContext *ctx, GenTxn *gentxn)
515 {
516 gentxn->kfile = ctx->curr_kfile;
517 gentxn->kacc = ctx->curr_kacc;
518 gentxn->to_import = TRUE;
519 ctx->gen_lst_txn = g_list_append(ctx->gen_lst_txn, gentxn);
520 }
521
522
523 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
524
525
526 static void _string_utf8_ucfirst(gchar **str)
527 {
528 gint str_len;
529 gchar *first, *lc;
530
531 if( *str == NULL )
532 return;
533
534 str_len = strlen(*str);
535 if( str_len <= 1 )
536 return;
537
538 first = g_utf8_strup(*str, 1);
539 lc = g_utf8_strdown( g_utf8_next_char(*str), -1 );
540 g_free(*str);
541 *str = g_strjoin(NULL, first, lc, NULL);
542 g_free(first);
543 g_free(lc);
544 }
545
546
547 static gchar *
548 _string_concat(gchar *str, gchar *addon)
549 {
550 gchar *retval;
551
552 DB( g_print(" - concat '%s' + '%s'\n", str, addon) );
553
554 if(str == NULL)
555 retval = g_strdup(addon);
556 else
557 {
558 retval = g_strjoin(" ", str, addon, NULL);
559 g_free(str);
560 }
561
562 DB( g_print(" - retval='%s'\n", retval) );
563 return retval;
564 }
565
566
567 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
568
569 gchar *hb_import_filetype_char_get(GenAcc *genacc)
570 {
571 gchar *retval = "";
572
573 switch(genacc->filetype)
574 {
575 #ifndef NOOFX
576 case FILETYPE_OFX:
577 retval = "OFX/QFX";
578 break;
579 #endif
580 case FILETYPE_QIF:
581 retval = "QIF";
582 break;
583
584 case FILETYPE_CSV_HB:
585 retval = "CSV";
586 break;
587 }
588
589 return retval;
590 }
591
592
593 void
594 hb_import_load_all(ImportContext *ictx)
595 {
596 GList *list;
597
598 DB( g_print("\n[import] load all\n") );
599
600 da_import_context_clear (ictx);
601
602 list = g_list_first(ictx->gen_lst_file);
603 while (list != NULL)
604 {
605 GenFile *genfile = list->data;
606
607 if(genfile->filetype != FILETYPE_UNKNOWN)
608 {
609 //todo: move this to alien analysis
610 genfile->encoding = homebank_file_getencoding(genfile->filepath);
611
612 ictx->curr_kfile = genfile->key;
613
614 DB( g_print(" -> key = '%d'\n", genfile->key) );
615 DB( g_print(" -> filepath = '%s'\n", genfile->filepath) );
616 DB( g_print(" -> encoding = '%s'\n", genfile->encoding) );
617
618 genfile->loaded = FALSE;
619 genfile->invaliddatefmt = FALSE;
620
621 switch(genfile->filetype)
622 {
623 #ifndef NOOFX
624 case FILETYPE_OFX:
625 homebank_ofx_import(ictx, genfile);
626 break;
627 #endif
628 case FILETYPE_QIF:
629 homebank_qif_import(ictx, genfile);
630 break;
631
632 case FILETYPE_CSV_HB:
633 homebank_csv_import(ictx, genfile);
634 break;
635 }
636
637 genfile->loaded = TRUE;
638 }
639
640 list = g_list_next(list);
641 }
642
643 // sort by date
644 ictx->gen_lst_txn = da_gen_txn_sort(ictx->gen_lst_txn);
645
646 }
647
648
649 gint
650 hb_import_gen_acc_count_txn(ImportContext *ictx, GenAcc *genacc)
651 {
652 GList *list;
653 gint count = 0;
654
655 DB( g_print("\n[import] gen_acc_count_txn\n") );
656
657 genacc->n_txnall = 0;
658 genacc->n_txnimp = 0;
659
660 list = g_list_first(ictx->gen_lst_txn);
661 while (list != NULL)
662 {
663 GenTxn *gentxn = list->data;
664
665 if(gentxn->kacc == genacc->key)
666 {
667 genacc->n_txnall++;
668 count++;
669
670 DB( g_print(" count %03d: gentxn in=%d dup=%d '%s'\n", count, gentxn->to_import, gentxn->is_dst_similar, gentxn->memo) );
671
672 if(gentxn->to_import)
673 genacc->n_txnimp++;
674 }
675 list = g_list_next(list);
676 }
677 return count;
678 }
679
680
681 /**
682 * uncheck duplicate within the import context files
683 */
684 gint
685 hb_import_gen_txn_check_duplicate(ImportContext *ictx, GenAcc *genacc)
686 {
687 GList *list1, *list2;
688 gint count = 0;
689
690 DB( g_print("\n[import] gen_txn_check_duplicate\n") );
691
692
693 list1 = g_list_first(ictx->gen_lst_txn);
694 while (list1 != NULL)
695 {
696 GenTxn *gentxn1 = list1->data;
697
698 if( (genacc->key == gentxn1->kacc) && (gentxn1->julian != 0) ) //same account, valid date
699 {
700 list2 = g_list_next(list1);
701 while (list2 != NULL)
702 {
703 GenTxn *gentxn2 = list2->data;
704
705 if( (gentxn2->julian > gentxn1->julian) )
706 break;
707
708 //todo: maybe reinforce controls here
709 if( (gentxn2->kacc == gentxn1->kacc)
710 && (gentxn2->julian == gentxn1->julian)
711 && (gentxn2->amount == gentxn1->amount)
712 && (hb_string_compare(gentxn2->memo, gentxn1->memo) == 0)
713 && (hb_string_compare(gentxn2->payee, gentxn1->payee) == 0)
714 )
715 {
716 gentxn1->to_import = FALSE;
717 gentxn1->is_imp_similar = TRUE;
718 count++;
719
720 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) );
721
722 }
723 list2 = g_list_next(list2);
724 }
725 }
726 list1 = g_list_next(list1);
727 }
728 return count;
729 }
730
731
732 /**
733 * uncheck existing txn into target account
734 *
735 */
736 gint
737 hb_import_gen_txn_check_target_similar(ImportContext *ictx, GenAcc *genacc)
738 {
739 GList *list1, *list2;
740 gint count = 0;
741
742 DB( g_print("\n[import] gen_txn_check_target_similar\n") );
743
744 list1 = g_list_first(ictx->gen_lst_txn);
745 while (list1 != NULL)
746 {
747 GenTxn *gentxn = list1->data;
748
749 if(genacc->key == gentxn->kacc)
750 {
751 gentxn->to_import = TRUE;
752 gentxn->is_dst_similar = FALSE;
753
754 if(genacc->kacc == DST_ACC_SKIP)
755 {
756 gentxn->to_import = FALSE;
757 }
758 else
759 {
760 Account *acc = da_acc_get(genacc->kacc);
761
762 if(acc != NULL)
763 {
764 //clear previous existing
765 if(gentxn->lst_existing != NULL)
766 {
767 g_list_free(gentxn->lst_existing);
768 gentxn->lst_existing = NULL;
769 }
770
771 // try to find existing transaction
772 list2 = g_queue_peek_tail_link(acc->txn_queue);
773 while (list2 != NULL)
774 {
775 Transaction *txn = list2->data;
776
777 //break if the date goes below the gentxn date + gap
778 if( txn->date < (gentxn->julian - ictx->opt_daygap) )
779 break;
780
781 //#1586211 add of date tolerance
782 //todo: maybe reinforce controls here
783 if( ( txn->kacc == genacc->kacc )
784 && ( gentxn->julian <= (txn->date + ictx->opt_daygap) )
785 && ( gentxn->julian >= (txn->date - ictx->opt_daygap) )
786 && ( txn->amount == gentxn->amount )
787 )
788 {
789 gentxn->lst_existing = g_list_append(gentxn->lst_existing, txn);
790 gentxn->to_import = FALSE;
791 gentxn->is_dst_similar = TRUE;
792 count++;
793
794 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) );
795 }
796
797 list2 = g_list_previous(list2);
798 }
799 }
800
801 }
802 }
803
804 list1 = g_list_next(list1);
805 }
806
807 return count;
808 }
809
810
811 /**
812 * try to indentify xfer for OFX
813 *
814 */
815 static gint
816 hb_import_gen_xfer_eval(ImportContext *ictx, GList *list)
817 {
818 GList *root, *list1, *list2;
819 GList *match = NULL;
820 gint count = 0;
821
822 DB( g_print("\n[import] gen xfer eval\n") );
823
824 root = list1 = g_list_first(list);
825 while (list1 != NULL)
826 {
827 Transaction *txn1 = list1->data;
828 GenAcc *acc;
829
830 acc = da_gen_acc_get_by_key(ictx->gen_lst_acc, txn1->kacc);
831
832 DB( g_print(" src: kacc:%d dat:%d amt:%.2f %s kfxacc:%d\n", txn1->kacc, txn1->date, txn1->amount, txn1->memo, txn1->kxferacc) );
833
834 if( (acc != NULL) && (acc->filetype == FILETYPE_OFX) )
835 {
836 match = NULL;
837 count = 0;
838 list2 = g_list_next(root);
839 while (list2 != NULL)
840 {
841 Transaction *txn2 = list2->data;
842
843 //DB( g_print(" -- chk: kacc:%d dat:%d amt:%.2f %s\n", txn2->kacc, txn2->date, txn2->amount, txn2->memo) );
844 if( (txn2->date > txn1->date) )
845 break;
846
847 if( (txn2 == txn1) || (txn2->paymode == PAYMODE_INTXFER) )
848 goto next;
849
850 //todo: maybe reinforce controls here
851 if( (txn2->kacc != txn1->kacc)
852 && (txn2->date == txn1->date)
853 && (txn2->amount == -txn1->amount)
854 && (hb_string_compare(txn2->memo, txn1->memo) == 0)
855 )
856 {
857 DB( g_print(" match: kacc:%d dat:%d amt:%.2f %s kfxacc:%d\n", txn2->kacc, txn2->date, txn2->amount, txn2->memo, txn2->kxferacc) );
858 match = g_list_append(match, txn2);
859 count++;
860 }
861 next:
862 list2 = g_list_next(list2);
863 }
864
865 if(count == 1) //we found a single potential xfer, transform it
866 {
867 Transaction *txn2 ;
868
869 DB( g_print(" single found => convert both\n") );
870
871 list2 = g_list_first(match);
872 txn2 = list2->data;
873
874
875 txn1->paymode = PAYMODE_INTXFER;
876 transaction_xfer_change_to_child(txn1, txn2);
877
878 /*list2 = g_list_first(match);
879 txn2 = list2->data;
880
881 txn1->paymode = PAYMODE_INTXFER;
882 txn1->kxferacc = txn2->kacc;
883
884 txn2->paymode = PAYMODE_INTXFER;
885 txn2->kxferacc = txn1->kacc;
886 */
887 }
888 // if more than one, we cannot be sure
889 g_list_free(match);
890 }
891
892 list1 = g_list_next(list1);
893 }
894
895 return count;
896 }
897
898
899 /**
900 * apply the user option: date format, payee/memo/info mapping
901 *
902 */
903 gboolean
904 hb_import_option_apply(ImportContext *ictx, GenAcc *genacc)
905 {
906 GList *list;
907
908 DB( g_print("\n[import] option apply\n") );
909
910 DB( g_print(" - type=%d\n", genacc->filetype) );
911
912 genacc->n_txnbaddate = 0;
913
914 list = g_list_first(ictx->gen_lst_txn);
915 while (list != NULL)
916 {
917 GenTxn *gentxn = list->data;
918
919 if(gentxn->kacc == genacc->key)
920 {
921 if(genacc->filetype != FILETYPE_OFX)
922 {
923 gentxn->julian = hb_date_get_julian(gentxn->date, ictx->opt_dateorder);
924 if( gentxn->julian == 0 )
925 {
926 genacc->n_txnbaddate++;
927 }
928 }
929
930 if(genacc->filetype == FILETYPE_OFX)
931 {
932 DB( g_print(" - ofx option apply\n") );
933
934 g_free(gentxn->payee);
935 g_free(gentxn->memo);
936 g_free(gentxn->info);
937 gentxn->payee = NULL;
938 gentxn->memo = NULL;
939 gentxn->info = NULL;
940
941 // OFX:check_number
942 gentxn->info = g_strdup(gentxn->rawinfo);
943
944 //#1791482 map name to info (concat only)
945 switch(ictx->opt_ofxname)
946 {
947 //ofxname is stored into rawpayee
948 case 1:
949 gentxn->memo = g_strdup(gentxn->rawpayee);
950 break;
951 case 2:
952 gentxn->payee = g_strdup(gentxn->rawpayee);
953 break;
954 case 3:
955 g_free(gentxn->info);
956 gentxn->info = _string_concat(gentxn->rawinfo, gentxn->rawpayee);
957 break;
958 }
959
960 if(gentxn->rawmemo != NULL)
961 {
962 switch(ictx->opt_ofxmemo)
963 {
964 //case 0: ignore
965 case 1: //add to info
966 gentxn->info = _string_concat(gentxn->info, gentxn->rawmemo);
967 break;
968
969 case 2: //add to memo
970 gentxn->memo = _string_concat(gentxn->memo, gentxn->rawmemo);
971 break;
972
973 case 3: //add to payee
974 gentxn->payee = _string_concat(gentxn->payee, gentxn->rawmemo);
975 break;
976 }
977 }
978
979 DB( g_print(" - payee is '%s'\n", gentxn->payee) );
980 DB( g_print(" - memo is '%s'\n", gentxn->memo) );
981 DB( g_print(" - info is '%s'\n", gentxn->info) );
982 DB( g_print("\n") );
983
984 }
985 else
986 if(genacc->filetype == FILETYPE_QIF)
987 {
988 DB( g_print(" - qif option apply\n") );
989
990 g_free(gentxn->payee);
991 g_free(gentxn->memo);
992 gentxn->payee = NULL;
993 gentxn->memo = NULL;
994
995 if(!ictx->opt_qifswap)
996 {
997 gentxn->payee = g_strdup(gentxn->rawpayee);
998 if(ictx->opt_qifmemo)
999 gentxn->memo = g_strdup(gentxn->rawmemo);
1000 }
1001 else
1002 {
1003 gentxn->payee = g_strdup(gentxn->rawmemo);
1004 if(ictx->opt_qifmemo)
1005 gentxn->memo = g_strdup(gentxn->rawpayee);
1006 }
1007
1008 DB( g_print(" - payee is '%s'\n", gentxn->payee) );
1009 DB( g_print(" - memo is '%s'\n", gentxn->memo) );
1010
1011 }
1012 else
1013 if(genacc->filetype == FILETYPE_CSV_HB)
1014 {
1015 DB( g_print(" - csv option apply\n") );
1016
1017 //#1791656 missing: info, payee and tagsg_freg_free(gentxn->payee);
1018 g_free(gentxn->payee);
1019 g_free(gentxn->memo);
1020 g_free(gentxn->info);
1021
1022 gentxn->payee = g_strdup(gentxn->rawpayee);
1023 gentxn->memo = g_strdup(gentxn->rawmemo);
1024 gentxn->info = g_strdup(gentxn->rawinfo);
1025 }
1026
1027 //at last do ucfirst
1028 if( (ictx->opt_ucfirst == TRUE) )
1029 {
1030 _string_utf8_ucfirst(&gentxn->memo);
1031 _string_utf8_ucfirst(&gentxn->payee);
1032 //category ?
1033 }
1034
1035 }
1036 list = g_list_next(list);
1037 }
1038
1039 DB( g_print(" - nb_err=%d\n", genacc->n_txnbaddate) );
1040
1041 return genacc->n_txnbaddate == 0 ? TRUE : FALSE;
1042 }
1043
1044
1045 /**
1046 * convert a GenTxn to a Transaction
1047 *
1048 */
1049 Transaction *
1050 hb_import_convert_txn(GenAcc *genacc, GenTxn *gentxn)
1051 {
1052 Transaction *newope;
1053 Account *accitem;
1054 Payee *payitem;
1055 Category *catitem;
1056 gint nsplit;
1057
1058 DB( g_print("\n[import] convert txn\n") );
1059
1060 newope = NULL;
1061
1062 DB( g_print(" - gentxt %s %s %s\n", gentxn->account, gentxn->date, gentxn->memo) );
1063 DB( g_print(" - genacc '%s' '%p'\n", gentxn->account, genacc) );
1064
1065 if( genacc != NULL)
1066 {
1067 newope = da_transaction_malloc();
1068
1069 newope->kacc = genacc->kacc;
1070 newope->date = gentxn->julian;
1071 newope->paymode = gentxn->paymode;
1072 newope->info = g_strdup(gentxn->info);
1073 newope->memo = g_strdup(gentxn->memo);
1074 newope->amount = gentxn->amount;
1075
1076 if(newope->amount > 0)
1077 newope->flags |= OF_INCOME;
1078
1079 //#773282 invert amount for ccard accounts
1080 //todo: manage this (qif), it is not set to true anywhere
1081 //if(ictx->is_ccard)
1082 // gentxn->amount *= -1;
1083
1084 // payee + append
1085 if( gentxn->payee != NULL )
1086 {
1087 payitem = da_pay_get_by_name(gentxn->payee);
1088 if(payitem == NULL)
1089 {
1090 //DB( g_print(" -> append pay: '%s'\n", item->payee ) );
1091
1092 payitem = da_pay_malloc();
1093 payitem->name = g_strdup(gentxn->payee);
1094 //payitem->imported = TRUE;
1095 da_pay_append(payitem);
1096
1097 //ictx->cnt_new_pay += 1;
1098 }
1099 newope->kpay = payitem->key;
1100 }
1101
1102 // LCategory of transaction
1103 // L[Transfer account name]
1104 // LCategory of transaction/Class of transaction
1105 // L[Transfer account]/Class of transaction
1106 if( gentxn->category != NULL )
1107 {
1108 if(g_str_has_prefix(gentxn->category, "[")) // this is a transfer account name
1109 {
1110 gchar *accname;
1111
1112 //DB ( g_print(" -> transfer to: '%s'\n", item->category) );
1113
1114 //remove brackets
1115 accname = hb_strdup_nobrackets(gentxn->category);
1116
1117 // search target account + append if not exixts
1118 accitem = da_acc_get_by_name(accname);
1119 if(accitem == NULL)
1120 {
1121 DB( g_print(" -> append int xfer dest acc: '%s'\n", accname ) );
1122
1123 accitem = da_acc_malloc();
1124 accitem->name = g_strdup(accname);
1125 //accitem->imported = TRUE;
1126 //accitem->imp_name = g_strdup(accname);
1127 da_acc_append(accitem);
1128 }
1129
1130 newope->kxferacc = accitem->key;
1131 newope->paymode = PAYMODE_INTXFER;
1132
1133 g_free(accname);
1134 }
1135 else
1136 {
1137 //DB ( g_print(" -> append cat: '%s'\n", item->category) );
1138
1139 catitem = da_cat_append_ifnew_by_fullname(gentxn->category);
1140 if( catitem != NULL )
1141 {
1142 //ictx->cnt_new_cat += 1;
1143 newope->kcat = catitem->key;
1144 }
1145 }
1146 }
1147
1148 //#1791656 miss tags also...
1149 if( gentxn->tags != NULL )
1150 {
1151 g_free(newope->tags);
1152 newope->tags = tags_parse(gentxn->tags);
1153 }
1154
1155 // splits, if not a xfer
1156 if( gentxn->paymode != PAYMODE_INTXFER )
1157 {
1158 if( gentxn->nb_splits > 0 )
1159 {
1160 newope->splits = da_split_new();
1161 for(nsplit=0;nsplit<gentxn->nb_splits;nsplit++)
1162 {
1163 GenSplit *s = &gentxn->splits[nsplit];
1164 Split *hbs;
1165 guint32 kcat = 0;
1166
1167 DB( g_print(" -> append split %d: '%s' '%.2f' '%s'\n", nsplit, s->category, s->amount, s->memo) );
1168
1169 if( s->category != NULL )
1170 {
1171 catitem = da_cat_append_ifnew_by_fullname(s->category);
1172 if( catitem != NULL )
1173 {
1174 kcat = catitem->key;
1175 }
1176 }
1177
1178 //todo: remove this when no more use ||
1179 hb_string_replace_char('|', s->memo);
1180 hbs = da_split_malloc ();
1181 hbs->kcat = kcat;
1182 hbs->memo = g_strdup(s->memo);
1183 hbs->amount = s->amount;
1184 da_splits_append(newope->splits, hbs);
1185 hbs = NULL;
1186 }
1187 }
1188 }
1189
1190 newope->flags |= OF_ADDED;
1191 if( newope->amount > 0 )
1192 newope->flags |= OF_INCOME;
1193
1194 if( gentxn->reconciled )
1195 newope->status = TXN_STATUS_RECONCILED;
1196 else
1197 if( gentxn->cleared )
1198 newope->status = TXN_STATUS_CLEARED;
1199 }
1200 return newope;
1201 }
1202
1203
1204 void
1205 hb_import_apply(ImportContext *ictx)
1206 {
1207 GList *list, *lacc;
1208 GList *txnlist;
1209 guint32 kcommon = 0;
1210 guint changes = 0;
1211
1212 DB( g_print("\n[import] apply\n") );
1213
1214 //create accounts
1215 list = g_list_first(ictx->gen_lst_acc);
1216 while (list != NULL)
1217 {
1218 GenAcc *genacc = list->data;
1219
1220 DB( g_print(" #1 genacc: %d %s %s => %d\n", genacc->key, genacc->name, genacc->number, genacc->kacc) );
1221
1222 //we do create the common account once
1223 if( (genacc->kacc == DST_ACC_GLOBAL) )
1224 {
1225 if( kcommon == 0 )
1226 {
1227 Account *acc = da_acc_malloc ();
1228
1229 acc->name = g_strdup(_("imported account"));
1230 if( da_acc_append(acc) )
1231 {
1232 kcommon = acc->key;
1233 changes++;
1234 }
1235 }
1236
1237 genacc->kacc = kcommon;
1238 }
1239 else
1240 if( (genacc->kacc == DST_ACC_NEW) )
1241 {
1242 Account *acc = da_acc_malloc ();
1243
1244 acc->name = g_strdup(genacc->name);
1245 if( da_acc_append(acc) )
1246 {
1247 acc->number = g_strdup(genacc->number);
1248 acc->initial = genacc->initial;
1249
1250 //store the target acc key
1251 genacc->kacc = acc->key;
1252 changes++;
1253 }
1254 }
1255
1256 list = g_list_next(list);
1257 }
1258
1259 // insert every transactions into a temporary list
1260 // we do this to keep a finished real txn list for detect xfer below
1261 DB( g_print(" #2 insert txn\n") );
1262
1263 txnlist = NULL;
1264 lacc = g_list_first(ictx->gen_lst_acc);
1265 while (lacc != NULL)
1266 {
1267 GenAcc *genacc = lacc->data;
1268
1269 if(genacc->kacc != DST_ACC_SKIP)
1270 {
1271 list = g_list_first(ictx->gen_lst_txn);
1272 while (list != NULL)
1273 {
1274 GenTxn *gentxn = list->data;
1275
1276 if(gentxn->kacc == genacc->key && gentxn->to_import == TRUE)
1277 {
1278 Transaction *txn, *dtxn;
1279
1280 txn = hb_import_convert_txn(genacc, gentxn);
1281 if( txn )
1282 {
1283 dtxn = transaction_add(NULL, txn);
1284 txnlist = g_list_append(txnlist, dtxn);
1285 da_transaction_free(txn);
1286 //#1820618 forgot to report changes count
1287 changes++;
1288 }
1289 }
1290 list = g_list_next(list);
1291 }
1292 }
1293 lacc = g_list_next(lacc);
1294 }
1295
1296 //auto assign
1297 DB( g_print(" call auto assign\n") );
1298 transaction_auto_assign(txnlist, 0);
1299
1300 //check for ofx internal xfer
1301 DB( g_print(" call hb_import_gen_xfer_eval\n") );
1302 hb_import_gen_xfer_eval(ictx, txnlist);
1303
1304 g_list_free(txnlist);
1305
1306 GLOBALS->changes_count += changes;
1307
1308 }
1309
1310
1311 #if MYDEBUG
1312 void _import_context_debug_file_list(ImportContext *ctx)
1313 {
1314 GList *list;
1315
1316 g_print("\n--debug-- file list %d\n", g_list_length(ctx->gen_lst_file) );
1317
1318 list = g_list_first(ctx->gen_lst_file);
1319 while (list != NULL)
1320 {
1321 GenFile *item = list->data;
1322
1323 g_print(" genfile: %d '%s' '%s'\ndf=%d invalid=%d\n", item->key, item->filepath, item->encoding, item->datefmt, item->invaliddatefmt);
1324
1325 list = g_list_next(list);
1326 }
1327
1328 }
1329
1330 void _import_context_debug_acc_list(ImportContext *ctx)
1331 {
1332 GList *list;
1333
1334 g_print("\n--debug-- acc list %d\n", g_list_length(ctx->gen_lst_acc) );
1335
1336 list = g_list_first(ctx->gen_lst_acc);
1337 while (list != NULL)
1338 {
1339 GenAcc *item = list->data;
1340
1341 g_print(" genacc: %d %s %s => %d\n", item->key, item->name, item->number, item->kacc);
1342
1343 list = g_list_next(list);
1344 }
1345
1346 }
1347
1348
1349 void _import_context_debug_txn_list(ImportContext *ctx)
1350 {
1351 GList *list;
1352
1353 g_print("\n--debug-- txn list %d\n", g_list_length(ctx->gen_lst_txn) );
1354
1355 list = g_list_first(ctx->gen_lst_txn);
1356 while (list != NULL)
1357 {
1358 GenTxn *item = list->data;
1359
1360 g_print(" gentxn: (%d) %s %s (%d) %s %.2f\n", item->kfile, item->account, item->date, item->julian, item->memo, item->amount);
1361
1362 list = g_list_next(list);
1363 }
1364
1365 }
1366
1367 #endif
1368
This page took 0.096515 seconds and 4 git commands to generate.