]>
Dogcows Code - chaz/homebank/blob - src/imp_qif.c
0aba86bba1b42f78bf705346a5fd4952a5719d70
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 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/>.
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
));
49 da_qif_tran_free(QIF_Tran
*item
)
55 if(item
->date
!= NULL
)
57 if(item
->info
!= NULL
)
59 if(item
->payee
!= NULL
)
61 if(item
->memo
!= NULL
)
63 if(item
->category
!= NULL
)
64 g_free(item
->category
);
65 if(item
->account
!= NULL
)
66 g_free(item
->account
);
68 for(i
=0;i
<TXN_MAX_SPLIT
;i
++)
70 QIFSplit
*s
= &item
->splits
[i
];
74 if(s
->category
!= NULL
)
86 da_qif_tran_destroy(QifContext
*ctx
)
88 GList
*qiflist
= g_list_first(ctx
->q_tra
);
90 while (qiflist
!= NULL
)
92 QIF_Tran
*item
= qiflist
->data
;
93 da_qif_tran_free(item
);
94 qiflist
= g_list_next(qiflist
);
96 g_list_free(ctx
->q_tra
);
101 da_qif_tran_new(QifContext
*ctx
)
109 da_qif_tran_move(QIF_Tran
*sitem
, QIF_Tran
*ditem
)
111 if(sitem
!= NULL
&& ditem
!= NULL
)
113 memcpy(ditem
, sitem
, sizeof(QIF_Tran
));
114 memset(sitem
, 0, sizeof(QIF_Tran
));
120 da_qif_tran_append(QifContext
*ctx
, QIF_Tran
*item
)
122 ctx
->q_tra
= g_list_append(ctx
->q_tra
, item
);
126 /* = = = = = = = = = = = = = = = = */
129 hb_qif_parser_get_amount(gchar
*string
)
137 DB( g_print("\n(qif) hb_qif_parser_get_amount\n") );
143 l
= strlen(string
) - 1;
145 // the first non-digit is a grouping, or a decimal separator
146 // if the non-digit is after a 3 digit serie, it might be a grouping
150 DB( g_print(" %d :: %c :: ds='%c' ndcount=%d\n", i
, string
[i
], dc
, ndcount
) );
152 if( string
[i
] == '-' || string
[i
] == '+' ) continue;
154 if( g_ascii_isdigit( string
[i
] ))
160 if( (ndcount
!= 3) && (string
[i
] == '.' || string
[i
]==',') )
168 DB( g_print(" s='%s' :: ds='%c'\n", string
, dc
) );
171 new_str
= g_malloc (l
+3); //#1214077
175 if( g_ascii_isdigit( string
[i
] ) || string
[i
] == '-' )
180 if( string
[i
] == dc
)
184 amount
= g_ascii_strtod(new_str
, NULL
);
186 DB( g_print(" -> amount was='%s' => to='%s' double='%f'\n", string
, new_str
, amount
) );
193 /* O if m-d-y (american)
194 1 if d-m-y (european) */
197 hb_qif_parser_guess_datefmt(QifContext *ctx)
199 gboolean retval = TRUE;
204 DB( g_print("(qif) get_datetype\n") );
206 qiflist = g_list_first(ctx->q_tra);
207 while (qiflist != NULL)
209 QIF_Tran *item = qiflist->data;
211 r = hb_qif_parser_get_dmy(item->date, &d, &m, &y);
212 valid = g_date_valid_dmy(d, m, y);
214 DB( g_print(" -> date: %s :: %d %d %d :: %d\n", item->date, d, m, y, valid ) );
222 qiflist = g_list_next(qiflist);
230 account_qif_get_child_transfer(Transaction
*src
, GList
*list
)
234 //DB( g_print("(transaction) transaction_get_child_transfer\n") );
236 //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->account, src->kxferacc) );
238 list
= g_list_first(list
);
242 if( item
->paymode
== PAYMODE_INTXFER
)
244 if( src
->date
== item
->date
&&
245 src
->kacc
== item
->kxferacc
&&
246 src
->kxferacc
== item
->kacc
&&
247 ABS(src
->amount
) == ABS(item
->amount
) )
249 //DB( g_print(" found : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) );
254 list
= g_list_next(list
);
257 //DB( g_print(" not found...\n") );
264 hb_qif_parser_get_block_type(gchar
*qif_line
)
267 gint type
= QIF_NONE
;
269 DB( g_print("--------\n(account) block type\n") );
271 //DB( g_print(" -> str: %s type: %d\n", qif_line, type) );
274 if(g_str_has_prefix(qif_line
, "!Account") || g_str_has_prefix(qif_line
, "!account"))
280 typestr
= g_strsplit(qif_line
, ":", 2);
282 if( g_strv_length(typestr
) == 2 )
284 gchar
*qif_line
= g_utf8_casefold(typestr
[1], -1);
286 //DB( g_print(" -> str[1]: %s\n", typestr[1]) );
288 if( g_str_has_prefix(qif_line
, "bank") )
290 type
= QIF_TRANSACTION
;
293 if( g_str_has_prefix(qif_line
, "cash") )
295 type
= QIF_TRANSACTION
;
298 if( g_str_has_prefix(qif_line
, "ccard") )
300 type
= QIF_TRANSACTION
;
303 if( g_str_has_prefix(qif_line
, "invst") )
305 type
= QIF_TRANSACTION
;
308 if( g_str_has_prefix(qif_line
, "oth a") )
310 type
= QIF_TRANSACTION
;
313 if( g_str_has_prefix(qif_line
, "oth l") )
315 type
= QIF_TRANSACTION
;
318 if( g_str_has_prefix(qif_line
, "security") )
323 if( g_str_has_prefix(qif_line
, "prices") )
333 //DB( g_print(" -> return type: %d\n", type) );
340 hb_qif_parser_parse(QifContext
*ctx
, gchar
*filename
, const gchar
*encoding
)
343 QIF_Tran tran
= { 0 };
345 DB( g_print("(qif) hb_qif_parser_parse\n") );
347 io
= g_io_channel_new_file(filename
, "r", NULL
);
353 gint type
= QIF_NONE
;
357 DB( g_print(" -> encoding should be %s\n", encoding
) );
358 if( encoding
!= NULL
)
360 g_io_channel_set_encoding(io
, encoding
, NULL
);
363 DB( g_print(" -> encoding is %s\n", g_io_channel_get_encoding(io
)) );
365 cur_acc
= g_strdup(QIF_UNKNOW_ACCOUNT_NAME
);
369 io_stat
= g_io_channel_read_line(io
, &qif_line
, NULL
, NULL
, &err
);
371 if( io_stat
== G_IO_STATUS_EOF
)
373 if( io_stat
== G_IO_STATUS_ERROR
)
375 DB (g_print(" + ERROR %s\n",err
->message
));
378 if( io_stat
== G_IO_STATUS_NORMAL
)
380 hb_string_strip_crlf(qif_line
);
382 //DB (g_print("** new QIF line: '%s' **\n", qif_line));
385 if(g_str_has_prefix(qif_line
, "!")) /* !Type: or !Option: or !Account otherwise ignore */
387 type
= hb_qif_parser_get_block_type(qif_line
);
388 DB ( g_print("-> ---- QIF block: '%s' (type = %d) ----\n", qif_line
, type
) );
391 value
= &qif_line
[1];
393 if( type
== QIF_ACCOUNT
)
401 cur_acc
= g_strdup(value
);
402 DB ( g_print(" name: '%s'\n", value
) );
406 case 'T': // Type of account
409 DB ( g_print(" type: '%s'\n", value
) );
413 case 'L': // Credit limit (only for credit card accounts)
414 if(g_str_has_prefix(qif_line
, "L"))
417 DB ( g_print(" credit limit: '%s'\n", value
) );
421 case '$': // Statement balance amount
424 DB ( g_print(" balance: '%s'\n", value
) );
430 DB ( g_print("should create account '%s' here\n", cur_acc
) );
432 DB ( g_print(" ----------------\n") );
438 if( type
== QIF_TRANSACTION
)
446 // US Quicken seems to be using the ' to indicate post-2000 two-digit years
447 //(such as 01/01'00 for Jan 1 2000)
448 ptr
= g_strrstr (value
, "\'");
449 if(ptr
!= NULL
) { *ptr
= '/'; }
451 ptr
= g_strrstr (value
, " ");
452 if(ptr
!= NULL
) { *ptr
= '0'; }
455 tran
.date
= g_strdup(value
);
461 tran
.amount
= hb_qif_parser_get_amount(value
);
465 case 'C': // cleared status
467 tran
.reconciled
= FALSE
;
468 if(g_str_has_prefix(value
, "X") || g_str_has_prefix(value
, "R") )
470 tran
.reconciled
= TRUE
;
475 case 'N': // check num or reference number
481 tran
.info
= g_strdup(value
);
492 tran
.payee
= g_strdup(value
);
502 tran
.memo
= g_strdup(value
);
507 case 'L': // category
509 // LCategory of transaction
510 // L[Transfer account name]
511 // LCategory of transaction/Class of transaction
512 // L[Transfer account]/Class of transaction
513 // this is managed at insertion
516 g_free(tran
.category
);
518 tran
.category
= g_strdup(value
);
527 if(tran
.nb_splits
< TXN_MAX_SPLIT
)
531 case 'S': // split category
533 QIFSplit
*s
= &tran
.splits
[tran
.nb_splits
];
538 s
->category
= g_strdup(value
);
543 case 'E': // split memo
545 QIFSplit
*s
= &tran
.splits
[tran
.nb_splits
];
549 s
->memo
= g_strdup(value
);
554 case '$': // split amount
556 QIFSplit
*s
= &tran
.splits
[tran
.nb_splits
];
558 s
->amount
= hb_qif_parser_get_amount(value
);
559 // $ line normally end a split
561 g_print(" -> new split added: [%d] S=%s, E=%s, $=%.2f\n", tran
.nb_splits
, s
->category
, s
->memo
, s
->amount
);
574 case '^': // end of line
581 tran
.account
= g_strdup(cur_acc
);
583 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
) );
585 newitem
= da_qif_tran_malloc();
586 da_qif_tran_move(&tran
, newitem
);
587 da_qif_tran_append(ctx
, newitem
);
592 //todo: should clear mem alloc here
602 // end QIF_TRANSACTION
604 // end of stat normal
610 g_io_channel_unref (io
);
619 ** this is our main qif entry point
622 account_import_qif(gchar
*filename
, ImportContext
*ictx
)
624 QifContext ctx
= { 0 };
628 DB( g_print("(qif) account import qif\n") );
630 // allocate our GLists
631 da_qif_tran_new(&ctx
);
632 ctx
.is_ccard
= FALSE
;
635 hb_qif_parser_parse(&ctx
, filename
, ictx
->encoding
);
637 // check iso date format in file
638 //isodate = hb_qif_parser_check_iso_date(&ctx);
639 //DB( g_print(" -> date is dd/mm/yy: %d\n", isodate) );
641 DB( g_print("(qif) transform to hb txn\n") );
643 DB( g_print(" -> %d qif txn\n", g_list_length(ctx
.q_tra
)) );
645 // transform our qif transactions to homebank ones
646 qiflist
= g_list_first(ctx
.q_tra
);
647 while (qiflist
!= NULL
)
649 QIF_Tran
*item
= qiflist
->data
;
650 Transaction
*newope
, *child
;
651 Account
*accitem
, *existitem
;
657 newope
= da_transaction_malloc();
659 newope
->date
= hb_date_get_julian(item
->date
, ictx
->datefmt
);
660 if( newope
->date
== 0 )
661 ictx
->cnt_err_date
++;
663 //newope->paymode = atoi(str_array[1]);
664 //newope->info = g_strdup(str_array[2]);
666 newope
->wording
= g_strdup(item
->memo
);
667 newope
->info
= g_strdup(item
->info
);
668 newope
->amount
= item
->amount
;
670 //#773282 invert amount for ccard accounts
672 newope
->amount
*= -1;
675 if( item
->payee
!= NULL
)
677 payitem
= da_pay_get_by_name(item
->payee
);
680 //DB( g_print(" -> append pay: '%s'\n", item->payee ) );
682 payitem
= da_pay_malloc();
683 payitem
->name
= g_strdup(item
->payee
);
684 payitem
->imported
= TRUE
;
685 da_pay_append(payitem
);
687 ictx
->cnt_new_pay
+= 1;
689 newope
->kpay
= payitem
->key
;
692 // LCategory of transaction
693 // L[Transfer account name]
694 // LCategory of transaction/Class of transaction
695 // L[Transfer account]/Class of transaction
696 if( item
->category
!= NULL
)
698 if(g_str_has_prefix(item
->category
, "[")) // this is a transfer account name
702 //DB ( g_print(" -> transfer to: '%s'\n", item->category) );
705 accname
= hb_strdup_nobrackets(item
->category
);
708 accitem
= da_acc_get_by_name(accname
);
711 DB( g_print(" -> append dest acc: '%s'\n", accname
) );
713 accitem
= da_acc_malloc();
714 accitem
->name
= g_strdup(accname
);
715 accitem
->imported
= TRUE
;
716 accitem
->imp_name
= g_strdup(accname
);
717 da_acc_append(accitem
);
720 newope
->kxferacc
= accitem
->key
;
721 newope
->paymode
= PAYMODE_INTXFER
;
727 //DB ( g_print(" -> append cat: '%s'\n", item->category) );
729 catitem
= da_cat_append_ifnew_by_fullname(item
->category
, TRUE
);
730 if( catitem
!= NULL
)
732 ictx
->cnt_new_cat
+= 1;
733 newope
->kcat
= catitem
->key
;
738 // splits, if not a xfer
739 if( newope
->paymode
!= PAYMODE_INTXFER
)
741 for(nsplit
=0;nsplit
<item
->nb_splits
;nsplit
++)
743 QIFSplit
*s
= &item
->splits
[nsplit
];
746 DB( g_print(" -> append split %d: '%s' '%.2f' '%s'\n", nsplit
, s
->category
, s
->amount
, s
->memo
) );
748 if( s
->category
!= NULL
)
750 catitem
= da_cat_append_ifnew_by_fullname(s
->category
, TRUE
); // TRUE = imported
751 if( catitem
!= NULL
)
753 DB( g_print(" -> append ok\n" ) );
755 hbs
= da_split_new(catitem
->key
, s
->amount
, s
->memo
);
756 da_transaction_splits_append(newope
, hbs
);
765 name
= strcmp(QIF_UNKNOW_ACCOUNT_NAME
, item
->account
) == 0 ? QIF_UNKNOW_ACCOUNT_NAME
: item
->account
;
767 DB( g_print(" -> account name is '%s'\n", name
) );
769 accitem
= da_acc_get_by_imp_name(name
);
770 if( accitem
== NULL
)
772 // check for an existing account before creating it
773 existitem
= da_acc_get_by_name(name
);
775 accitem
= import_create_account(name
, NULL
);
776 DB( g_print(" -> creating account '%s'\n", name
) );
778 if( existitem
!= NULL
)
780 accitem
->imp_key
= existitem
->key
;
781 DB( g_print(" -> existitem is '%d' %s\n", existitem
->key
, existitem
->name
) );
785 newope
->kacc
= accitem
->key
;
787 newope
->flags
|= OF_ADDED
;
788 if( newope
->amount
> 0 )
789 newope
->flags
|= OF_INCOME
;
791 if( item
->reconciled
)
792 newope
->flags
|= OF_VALID
;
794 child
= account_qif_get_child_transfer(newope
, list
);
797 //DB( g_print(" -> transaction already exist\n" ) );
799 da_transaction_free(newope
);
803 //DB( g_print(" -> append trans. acc:'%s', memo:'%s', val:%.2f\n", item->account, item->memo, item->amount ) );
805 list
= g_list_append(list
, newope
);
808 qiflist
= g_list_next(qiflist
);
811 // destroy our GLists
812 da_qif_tran_destroy(&ctx
);
814 DB( g_print(" -> %d txn converted\n", g_list_length(list
)) );
815 DB( g_print(" -> %d errors\n", ictx
->cnt_err_date
) );
This page took 0.070758 seconds and 4 git commands to generate.