]>
Dogcows Code - chaz/homebank/blob - src/hb-import-qif.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2016 Maxime DOYEN
4 * This file is part of HomeBank.
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.
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.
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/>.
22 //#include "ui-assist-import.h"
23 #include "hb-import.h"
25 /****************************************************************************/
27 /****************************************************************************/
36 /* our global datas */
37 extern struct HomeBank
*GLOBALS
;
38 extern struct Preferences
*PREFS
;
41 /* = = = = = = = = = = = = = = = = */
43 da_qif_tran_malloc(void)
45 return g_malloc0(sizeof(QIF_Tran
));
50 da_qif_tran_free(QIF_Tran
*item
)
56 if(item
->date
!= NULL
)
58 if(item
->info
!= NULL
)
60 if(item
->payee
!= NULL
)
62 if(item
->memo
!= NULL
)
64 if(item
->category
!= NULL
)
65 g_free(item
->category
);
66 if(item
->account
!= NULL
)
67 g_free(item
->account
);
69 for(i
=0;i
<TXN_MAX_SPLIT
;i
++)
71 QIFSplit
*s
= &item
->splits
[i
];
75 if(s
->category
!= NULL
)
85 da_qif_tran_destroy(QifContext
*ctx
)
87 GList
*qiflist
= g_list_first(ctx
->q_tra
);
89 while (qiflist
!= NULL
)
91 QIF_Tran
*item
= qiflist
->data
;
92 da_qif_tran_free(item
);
93 qiflist
= g_list_next(qiflist
);
95 g_list_free(ctx
->q_tra
);
101 da_qif_tran_new(QifContext
*ctx
)
108 da_qif_tran_move(QIF_Tran
*sitem
, QIF_Tran
*ditem
)
110 if(sitem
!= NULL
&& ditem
!= NULL
)
112 memcpy(ditem
, sitem
, sizeof(QIF_Tran
));
113 memset(sitem
, 0, sizeof(QIF_Tran
));
119 da_qif_tran_append(QifContext
*ctx
, QIF_Tran
*item
)
121 ctx
->q_tra
= g_list_append(ctx
->q_tra
, item
);
125 /* = = = = = = = = = = = = = = = = */
128 hb_qif_parser_get_amount(gchar
*string
)
136 //DB( g_print("\n[qif] hb_qif_parser_get_amount\n") );
142 l
= strlen(string
) - 1;
144 // the first non-digit is a grouping, or a decimal separator
145 // if the non-digit is after a 3 digit serie, it might be a grouping
149 //DB( g_print(" %d :: %c :: ds='%c' ndcount=%d\n", i, string[i], dc, ndcount) );
151 if( string
[i
] == '-' || string
[i
] == '+' ) continue;
153 if( g_ascii_isdigit( string
[i
] ))
159 if( (ndcount
!= 3) && (string
[i
] == '.' || string
[i
]==',') )
167 //DB( g_print(" s='%s' :: ds='%c'\n", string, dc) );
170 new_str
= g_malloc (l
+3); //#1214077
174 if( g_ascii_isdigit( string
[i
] ) || string
[i
] == '-' )
179 if( string
[i
] == dc
)
183 amount
= g_ascii_strtod(new_str
, NULL
);
185 //DB( g_print(" -> amount was='%s' => to='%s' double='%f'\n", string, new_str, amount) );
192 /* O if m-d-y (american)
193 1 if d-m-y (european) */
196 hb_qif_parser_guess_datefmt(QifContext *ctx)
198 gboolean retval = TRUE;
203 DB( g_print("(qif) get_datetype\n") );
205 qiflist = g_list_first(ctx->q_tra);
206 while (qiflist != NULL)
208 QIF_Tran *item = qiflist->data;
210 r = hb_qif_parser_get_dmy(item->date, &d, &m, &y);
211 valid = g_date_valid_dmy(d, m, y);
213 DB( g_print(" -> date: %s :: %d %d %d :: %d\n", item->date, d, m, y, valid ) );
221 qiflist = g_list_next(qiflist);
229 account_qif_get_child_transfer(Transaction
*src
, GList
*list
)
233 DB( g_print("([qif] get_child_transfer\n") );
235 //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->account, src->kxferacc) );
237 list
= g_list_first(list
);
241 if( item
->paymode
== PAYMODE_INTXFER
)
243 if( src
->date
== item
->date
&&
244 src
->kacc
== item
->kxferacc
&&
245 src
->kxferacc
== item
->kacc
&&
246 ABS(src
->amount
) == ABS(item
->amount
) )
248 //DB( g_print(" found : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) );
253 list
= g_list_next(list
);
256 //DB( g_print(" not found...\n") );
263 hb_qif_parser_get_block_type(gchar
*qif_line
)
266 gint type
= QIF_NONE
;
268 DB( g_print("--------\n[qif] block type\n") );
270 //DB( g_print(" -> str: %s type: %d\n", qif_line, type) );
273 if(g_str_has_prefix(qif_line
, "!Account") || g_str_has_prefix(qif_line
, "!account"))
279 typestr
= g_strsplit(qif_line
, ":", 2);
281 if( g_strv_length(typestr
) == 2 )
283 gchar
*qif_line
= g_utf8_casefold(typestr
[1], -1);
285 //DB( g_print(" -> str[1]: %s\n", typestr[1]) );
287 if( g_str_has_prefix(qif_line
, "bank") )
289 type
= QIF_TRANSACTION
;
292 if( g_str_has_prefix(qif_line
, "cash") )
294 type
= QIF_TRANSACTION
;
297 if( g_str_has_prefix(qif_line
, "ccard") )
299 type
= QIF_TRANSACTION
;
302 if( g_str_has_prefix(qif_line
, "invst") )
304 type
= QIF_TRANSACTION
;
307 if( g_str_has_prefix(qif_line
, "oth a") )
309 type
= QIF_TRANSACTION
;
312 if( g_str_has_prefix(qif_line
, "oth l") )
314 type
= QIF_TRANSACTION
;
317 if( g_str_has_prefix(qif_line
, "security") )
322 if( g_str_has_prefix(qif_line
, "prices") )
332 //DB( g_print(" -> return type: %d\n", type) );
339 hb_qif_parser_parse(QifContext
*ctx
, gchar
*filename
, const gchar
*encoding
)
342 QIF_Tran tran
= { 0 };
344 DB( g_print("\n[qif] hb_qif_parser_parse\n") );
346 io
= g_io_channel_new_file(filename
, "r", NULL
);
352 gint type
= QIF_NONE
;
356 DB( g_print(" -> encoding should be %s\n", encoding
) );
357 if( encoding
!= NULL
)
359 g_io_channel_set_encoding(io
, encoding
, NULL
);
362 DB( g_print(" -> encoding is %s\n", g_io_channel_get_encoding(io
)) );
364 cur_acc
= g_strdup(QIF_UNKNOW_ACCOUNT_NAME
);
368 io_stat
= g_io_channel_read_line(io
, &qif_line
, NULL
, NULL
, &err
);
370 if( io_stat
== G_IO_STATUS_EOF
)
372 if( io_stat
== G_IO_STATUS_ERROR
)
374 DB (g_print(" + ERROR %s\n",err
->message
));
377 if( io_stat
== G_IO_STATUS_NORMAL
)
379 hb_string_strip_crlf(qif_line
);
381 //DB (g_print("** new QIF line: '%s' **\n", qif_line));
384 if(g_str_has_prefix(qif_line
, "!")) /* !Type: or !Option: or !Account otherwise ignore */
386 type
= hb_qif_parser_get_block_type(qif_line
);
387 DB ( g_print("-> ---- QIF block: '%s' (type = %d) ----\n", qif_line
, type
) );
390 value
= &qif_line
[1];
392 if( type
== QIF_ACCOUNT
)
400 cur_acc
= g_strdup(value
);
401 DB ( g_print(" name: '%s'\n", value
) );
405 case 'T': // Type of account
408 DB ( g_print(" type: '%s'\n", value
) );
412 case 'L': // Credit limit (only for credit card accounts)
413 if(g_str_has_prefix(qif_line
, "L"))
416 DB ( g_print(" credit limit: '%s'\n", value
) );
420 case '$': // Statement balance amount
423 DB ( g_print(" balance: '%s'\n", value
) );
429 DB ( g_print("should create account '%s' here\n", cur_acc
) );
431 DB ( g_print(" ----------------\n") );
437 if( type
== QIF_TRANSACTION
)
445 // US Quicken seems to be using the ' to indicate post-2000 two-digit years
446 //(such as 01/01'00 for Jan 1 2000)
447 ptr
= g_strrstr (value
, "\'");
448 if(ptr
!= NULL
) { *ptr
= '/'; }
450 ptr
= g_strrstr (value
, " ");
451 if(ptr
!= NULL
) { *ptr
= '0'; }
454 tran
.date
= g_strdup(value
);
460 tran
.amount
= hb_qif_parser_get_amount(value
);
464 case 'C': // cleared status
466 tran
.reconciled
= FALSE
;
467 if(g_str_has_prefix(value
, "X") || g_str_has_prefix(value
, "R") )
469 tran
.reconciled
= TRUE
;
471 tran
.cleared
= FALSE
;
472 if(g_str_has_prefix(value
, "*") || g_str_has_prefix(value
, "c") )
479 case 'N': // check num or reference number
485 tran
.info
= g_strdup(value
);
496 tran
.payee
= g_strdup(value
);
506 tran
.memo
= g_strdup(value
);
511 case 'L': // category
513 // LCategory of transaction
514 // L[Transfer account name]
515 // LCategory of transaction/Class of transaction
516 // L[Transfer account]/Class of transaction
517 // this is managed at insertion
520 g_free(tran
.category
);
522 tran
.category
= g_strdup(value
);
531 if(tran
.nb_splits
< TXN_MAX_SPLIT
)
535 case 'S': // split category
537 QIFSplit
*s
= &tran
.splits
[tran
.nb_splits
];
542 s
->category
= g_strdup(value
);
547 case 'E': // split memo
549 QIFSplit
*s
= &tran
.splits
[tran
.nb_splits
];
553 s
->memo
= g_strdup(value
);
558 case '$': // split amount
560 QIFSplit
*s
= &tran
.splits
[tran
.nb_splits
];
562 s
->amount
= hb_qif_parser_get_amount(value
);
563 // $ line normally end a split
565 g_print(" -> new split added: [%d] S=%s, E=%s, $=%.2f\n", tran
.nb_splits
, s
->category
, s
->memo
, s
->amount
);
578 case '^': // end of line
585 tran
.account
= g_strdup(cur_acc
);
587 DB ( g_print(" -> store qif txn: dat:'%s' amt:%.2f pay:'%s' mem:'%s' cat:'%s' acc:'%s' nbsplit:%d\n", tran
.date
, tran
.amount
, tran
.payee
, tran
.memo
, tran
.category
, tran
.account
, tran
.nb_splits
) );
589 newitem
= da_qif_tran_malloc();
590 da_qif_tran_move(&tran
, newitem
);
591 da_qif_tran_append(ctx
, newitem
);
596 //todo: should clear mem alloc here
606 // end QIF_TRANSACTION
608 // end of stat normal
614 g_io_channel_unref (io
);
621 ** this is our main qif entry point
624 account_import_qif(gchar
*filename
, ImportContext
*ictx
)
626 QifContext ctx
= { 0 };
630 DB( g_print("\n[qif] account import qif\n") );
632 // allocate our GLists
633 da_qif_tran_new(&ctx
);
634 ctx
.is_ccard
= FALSE
;
637 hb_qif_parser_parse(&ctx
, filename
, ictx
->encoding
);
639 // check iso date format in file
640 //isodate = hb_qif_parser_check_iso_date(&ctx);
641 //DB( g_print(" -> date is dd/mm/yy: %d\n", isodate) );
643 DB( g_print("\n\n -> transform to hb txn\n") );
645 DB( g_print(" -> %d qif txn\n", g_list_length(ctx
.q_tra
)) );
647 // transform our qif transactions to homebank ones
648 qiflist
= g_list_first(ctx
.q_tra
);
649 while (qiflist
!= NULL
)
651 QIF_Tran
*item
= qiflist
->data
;
652 Transaction
*newope
, *child
;
656 gchar
*name
, *tmpmemo
, *tmppayee
;
659 newope
= da_transaction_malloc();
661 newope
->date
= hb_date_get_julian(item
->date
, ictx
->datefmt
);
662 if( newope
->date
== 0 )
663 ictx
->cnt_err_date
++;
665 //newope->paymode = atoi(str_array[1]);
666 //newope->info = g_strdup(str_array[2]);
668 //#916690 manage memo, swap memo/payee
669 tmpmemo
= item
->memo
;
670 tmppayee
= item
->payee
;
671 if( PREFS
->dtex_qifswap
)
673 tmpmemo
= item
->payee
;
674 tmppayee
= item
->memo
;
677 if( PREFS
->dtex_qifmemo
)
678 newope
->wording
= g_strdup(tmpmemo
);
680 newope
->info
= g_strdup(item
->info
);
681 newope
->amount
= item
->amount
;
683 //#773282 invert amount for ccard accounts
685 newope
->amount
*= -1;
688 if( tmppayee
!= NULL
)
690 payitem
= da_pay_get_by_name(tmppayee
);
693 //DB( g_print(" -> append pay: '%s'\n", tmppayee ) );
695 payitem
= da_pay_malloc();
696 payitem
->name
= g_strdup(tmppayee
);
697 payitem
->imported
= TRUE
;
698 da_pay_append(payitem
);
700 ictx
->cnt_new_pay
+= 1;
702 newope
->kpay
= payitem
->key
;
705 // LCategory of transaction
706 // L[Transfer account name]
707 // LCategory of transaction/Class of transaction
708 // L[Transfer account]/Class of transaction
709 if( item
->category
!= NULL
)
711 if(g_str_has_prefix(item
->category
, "[")) // this is a transfer account name
715 //DB ( g_print(" -> transfer to: '%s'\n", item->category) );
718 accname
= hb_strdup_nobrackets(item
->category
);
720 accitem
= import_create_account(accname
, NULL
);
722 newope
->kxferacc
= accitem
->key
;
723 newope
->paymode
= PAYMODE_INTXFER
;
729 //DB ( g_print(" -> append cat: '%s'\n", item->category) );
731 catitem
= da_cat_append_ifnew_by_fullname(item
->category
, TRUE
);
732 if( catitem
!= NULL
)
734 ictx
->cnt_new_cat
+= 1;
735 newope
->kcat
= catitem
->key
;
740 // splits, if not a xfer
741 if( newope
->paymode
!= PAYMODE_INTXFER
)
743 for(nsplit
=0;nsplit
<item
->nb_splits
;nsplit
++)
745 QIFSplit
*s
= &item
->splits
[nsplit
];
749 DB( g_print(" -> append split %d: '%s' '%.2f' '%s'\n", nsplit
, s
->category
, s
->amount
, s
->memo
) );
751 if( s
->category
!= NULL
)
753 catitem
= da_cat_append_ifnew_by_fullname(s
->category
, TRUE
); // TRUE = imported
754 if( catitem
!= NULL
)
760 hbs
= da_split_new(kcat
, s
->amount
, s
->memo
);
762 da_splits_append(newope
->splits
, hbs
);
764 //da_transaction_splits_append(newope, hbs);
770 name
= strcmp(QIF_UNKNOW_ACCOUNT_NAME
, item
->account
) == 0 ? "" : item
->account
;
772 DB( g_print(" -> account name is '%s'\n", name
) );
774 accitem
= import_create_account(name
, NULL
);
776 newope
->kacc
= accitem
->key
;
778 newope
->flags
|= OF_ADDED
;
779 if( newope
->amount
> 0 )
780 newope
->flags
|= OF_INCOME
;
782 if( item
->reconciled
)
783 newope
->status
= TXN_STATUS_RECONCILED
;
786 newope
->status
= TXN_STATUS_CLEARED
;
788 child
= account_qif_get_child_transfer(newope
, list
);
791 //DB( g_print(" -> transaction already exist\n" ) );
793 da_transaction_free(newope
);
797 //DB( g_print(" -> append trans. acc:'%s', memo:'%s', val:%.2f\n", item->account, item->memo, item->amount ) );
799 list
= g_list_append(list
, newope
);
802 qiflist
= g_list_next(qiflist
);
805 // destroy our GLists
806 da_qif_tran_destroy(&ctx
);
808 DB( g_print(" -> %d txn converted\n", g_list_length(list
)) );
809 DB( g_print(" -> %d errors\n", ictx
->cnt_err_date
) );
This page took 0.07945 seconds and 4 git commands to generate.