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/>.
22 #include "hb-transaction.h"
25 /****************************************************************************/
27 /****************************************************************************/
36 /* our global datas */
37 extern struct HomeBank
*GLOBALS
;
38 extern struct Preferences
*PREFS
;
41 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
44 static void da_split_free(Split
*item
)
48 if(item
->memo
!= NULL
)
56 static Split
*da_split_malloc(void)
58 return g_malloc0(sizeof(Split
));
62 Split
*da_split_new(guint32 kcat
, gdouble amount
, gchar
*memo
)
64 Split
*split
= da_split_malloc();
67 split
->amount
= amount
;
68 split
->memo
= g_strdup(memo
);
74 static Split
*da_split_clone(Split
*src_split
)
76 Split
*new_split
= g_memdup(src_split
, sizeof(Split
));
78 DB( g_print("da_split_clone\n") );
82 //duplicate the string
83 new_split
->memo
= g_strdup(src_split
->memo
);
84 DB( g_print(" clone %p -> %p\n", src_split
, new_split
) );
90 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
93 guint
da_transaction_splits_count(Transaction
*txn
)
97 for(i
=0;i
<TXN_MAX_SPLIT
;i
++)
99 if(txn
->splits
[i
] == NULL
)
107 void da_transaction_splits_free(Transaction
*txn
)
111 count
= da_transaction_splits_count(txn
);
115 DB( g_print("da_transaction_splits_free\n") );
119 DB( g_print("- freeing %d :: %p\n", i
, txn
->splits
[i
]) );
121 da_split_free(txn
->splits
[i
]);
122 txn
->splits
[i
] = NULL
;
125 txn
->flags
&= ~(OF_SPLIT
);
130 void da_transaction_splits_append(Transaction
*txn
, Split
*split
)
132 guint count
= da_transaction_splits_count(txn
);
134 DB( g_print("da_transaction_splits_append\n") );
136 DB( g_print("- split[%d] at %p for ope %p\n", count
, split
, txn
) );
138 txn
->flags
|= OF_SPLIT
;
139 txn
->splits
[count
] = split
;
140 txn
->splits
[count
+ 1] = NULL
;
142 DB( g_print("- %d splits\n", da_transaction_splits_count(txn
)) );
146 void da_transaction_splits_clone(Transaction
*stxn
, Transaction
*dtxn
)
150 DB( g_print("da_transaction_splits_clone\n") );
152 count
= da_transaction_splits_count(stxn
);
155 dtxn
->splits
[i
] = da_split_clone(stxn
->splits
[i
]);
159 dtxn
->flags
|= OF_SPLIT
;
161 DB( g_print(" clone %p -> %p, %d splits\n", stxn
, dtxn
, count
) );
166 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
169 da_transaction_clean(Transaction
*item
)
173 if(item
->wording
!= NULL
)
175 g_free(item
->wording
);
176 item
->wording
= NULL
;
178 if(item
->info
!= NULL
)
183 if(item
->tags
!= NULL
)
185 DB( g_print(" -> item->tags %p\n", item
->tags
) );
190 da_transaction_splits_free(item
);
192 if(item
->same
!= NULL
)
194 g_list_free(item
->same
);
203 da_transaction_free(Transaction
*item
)
207 da_transaction_clean(item
);
214 da_transaction_malloc(void)
216 return g_malloc0(sizeof(Transaction
));
220 Transaction
*da_transaction_copy(Transaction
*src_txn
, Transaction
*dst_txn
)
224 DB( g_print("da_transaction_copy\n") );
226 da_transaction_clean (dst_txn
);
228 memmove(dst_txn
, src_txn
, sizeof(Transaction
));
230 //duplicate the string
231 dst_txn
->wording
= g_strdup(src_txn
->wording
);
232 dst_txn
->info
= g_strdup(src_txn
->info
);
235 dst_txn
->tags
= NULL
;
236 count
= transaction_tags_count(src_txn
);
238 dst_txn
->tags
= g_memdup(src_txn
->tags
, count
*sizeof(guint32
));
240 da_transaction_splits_clone(src_txn
, dst_txn
);
246 Transaction
*da_transaction_init_from_template(Transaction
*txn
, Archive
*arc
)
249 txn
->amount
= arc
->amount
;
250 txn
->kacc
= arc
->kacc
;
251 txn
->paymode
= arc
->paymode
;
252 txn
->flags
= arc
->flags
| OF_ADDED
;
253 txn
->kpay
= arc
->kpay
;
254 txn
->kcat
= arc
->kcat
;
255 txn
->kxferacc
= arc
->kxferacc
;
256 txn
->wording
= g_strdup(arc
->wording
);
263 Transaction
*da_transaction_clone(Transaction
*src_item
)
265 Transaction
*new_item
= g_memdup(src_item
, sizeof(Transaction
));
268 DB( g_print("da_transaction_clone\n") );
272 //duplicate the string
273 new_item
->wording
= g_strdup(src_item
->wording
);
274 new_item
->info
= g_strdup(src_item
->info
);
277 new_item
->tags
= NULL
;
278 count
= transaction_tags_count(src_item
);
280 new_item
->tags
= g_memdup(src_item
->tags
, count
*sizeof(guint32
));
282 da_transaction_splits_clone(src_item
, new_item
);
289 da_transaction_new(void)
295 void da_transaction_destroy(GList
*list
)
297 GList
*tmplist
= g_list_first(list
);
299 while (tmplist
!= NULL
)
301 Transaction
*item
= tmplist
->data
;
302 da_transaction_free(item
);
303 tmplist
= g_list_next(tmplist
);
309 static gint
da_transaction_compare_func(Transaction
*a
, Transaction
*b
)
311 return ((gint
)a
->date
- b
->date
);
315 GList
*da_transaction_sort(GList
*list
)
317 return( g_list_sort(list
, (GCompareFunc
)da_transaction_compare_func
));
321 static void da_transaction_insert_memo(Transaction
*item
)
323 // append the memo if new
324 if( item
->wording
!= NULL
)
326 if( g_hash_table_lookup(GLOBALS
->h_memo
, item
->wording
) == NULL
)
328 g_hash_table_insert(GLOBALS
->h_memo
, g_strdup(item
->wording
), NULL
);
335 gboolean
da_transaction_insert_sorted(Transaction
*newitem
)
337 GList
*tmplist
= g_list_first(GLOBALS
->ope_list
);
339 // find the breaking date
340 while (tmplist
!= NULL
)
342 Transaction
*item
= tmplist
->data
;
344 if(item
->date
> newitem
->date
)
347 tmplist
= g_list_next(tmplist
);
350 // here we're at the insert point, let's insert our new txn just before
351 GLOBALS
->ope_list
= g_list_insert_before(GLOBALS
->ope_list
, tmplist
, newitem
);
353 da_transaction_insert_memo(newitem
);
358 // nota: this is called only when loading xml file
359 gboolean
da_transaction_prepend(Transaction
*item
)
361 GLOBALS
->ope_list
= g_list_prepend(GLOBALS
->ope_list
, item
);
362 da_transaction_insert_memo(item
);
367 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
370 da_transaction_get_max_kxfer(void)
376 DB( g_print("da_transaction_get_max_kxfer\n") );
378 list
= g_list_first(GLOBALS
->ope_list
);
382 if( item
->paymode
== PAYMODE_INTXFER
)
384 if( item
->kxfer
> max_key
)
385 max_key
= item
->kxfer
;
387 list
= g_list_next(list
);
390 DB( g_print(" max_key : %d \n", max_key
) );
396 static void da_transaction_goto_orphan(Transaction
*txn
)
398 const gchar
*oatn
= "orphaned transactions";
401 acc
= da_acc_get_by_name((gchar
*)oatn
);
404 acc
= da_acc_malloc();
405 acc
->name
= g_strdup(oatn
);
408 txn
->kacc
= acc
->key
;
412 void da_transaction_consistency(Transaction
*item
)
419 // check account exists
420 acc
= da_acc_get(item
->kacc
);
423 g_warning("txn consistency: fixed invalid acc %d", item
->kacc
);
424 da_transaction_goto_orphan(item
);
427 // check category exists
428 cat
= da_cat_get(item
->kcat
);
431 g_warning("txn consistency: fixed invalid cat %d", item
->kcat
);
435 // check split category #1340142
436 nbsplit
= da_transaction_splits_count(item
);
437 for(i
=0;i
<nbsplit
;i
++)
439 Split
*split
= item
->splits
[i
];
440 cat
= da_cat_get(split
->kcat
);
443 g_warning("txn consistency: fixed invalid split cat %d", split
->kcat
);
448 // check payee exists
449 pay
= da_pay_get(item
->kpay
);
452 g_warning("txn consistency: fixed invalid pay %d", item
->kpay
);
456 // reset dst acc for non xfer transaction
457 if( item
->paymode
!= PAYMODE_INTXFER
)
460 //#1295877 ensure income flag is correctly set
461 item
->flags
&= ~(OF_INCOME
);
462 if( item
->amount
> 0)
463 item
->flags
|= (OF_INCOME
);
465 //#1308745 ensure remind flag unset if reconciled
466 if( item
->flags
& OF_VALID
)
467 item
->flags
&= ~(OF_REMIND
);
472 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
473 /* new transfer functions */
475 Transaction
*transaction_strong_get_child_transfer(Transaction
*src
)
479 DB( g_print("\n[transaction] transaction_strong_get_child_transfer\n") );
481 DB( g_print(" - search: %d %s %f %d=>%d\n", src
->date
, src
->wording
, src
->amount
, src
->kacc
, src
->kxferacc
) );
483 list
= g_list_first(GLOBALS
->ope_list
);
486 Transaction
*item
= list
->data
;
488 //if( item->paymode == PAYMODE_INTXFER && item->kacc == src->kxferacc && item->kxfer == src->kxfer )
489 if( item
->paymode
== PAYMODE_INTXFER
&& item
->kxfer
== src
->kxfer
&& item
!= src
)
491 DB( g_print(" - found : %d %s %f %d=>%d\n", item
->date
, item
->wording
, item
->amount
, item
->kacc
, item
->kxferacc
) );
494 list
= g_list_next(list
);
496 DB( g_print(" - not found...\n") );
502 * this function retrieve into a glist the potential child transfer
503 * for the source transaction
505 GList
*transaction_match_get_child_transfer(Transaction
*src
)
510 DB( g_print("\n[transaction] transaction_match_get_child_transfer\n") );
512 //DB( g_print(" - search : %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->account, src->kxferacc) );
514 list
= g_list_first(GLOBALS
->ope_list
);
517 Transaction
*item
= list
->data
;
518 if( src
->date
== item
->date
&&
519 src
->kxferacc
== item
->kacc
&&
520 ABS(src
->amount
) == ABS(item
->amount
) &&
523 //DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) );
525 match
= g_list_append(match
, item
);
527 list
= g_list_next(list
);
530 DB( g_print(" - found : %d\n", g_list_length(match
)) );
536 void transaction_xfer_search_or_add_child(Transaction
*ope
, GtkWidget
*treeview
)
538 GList
*matchlist
= transaction_match_get_child_transfer(ope
);
540 guint count
= g_list_length(matchlist
);
543 DB( g_print("\n[transaction] transaction_xfer_search_or_add_child\n") );
545 DB( g_print(" - found result is %d, switching\n", count
) );
549 case 0: //we should create the child
550 transaction_xfer_create_child(ope
, treeview
);
553 //todo: maybe with just 1 match the user must choose ?
554 //#942346: bad idea so to no let the user confirm, so let hil confirm
556 case 1: //transform the transaction to a child transfer
558 GList *list = g_list_first(matchlist);
559 transaction_xfer_change_to_child(ope, list->data);
564 default: //the user must choose himself
568 child
= ui_dialog_transaction_xfer_select_child(matchlist
);
570 transaction_xfer_create_child(ope
, treeview
);
572 transaction_xfer_change_to_child(ope
, child
);
577 g_list_free(matchlist
);
586 void transaction_xfer_create_child(Transaction
*ope
, GtkWidget
*treeview
)
592 DB( g_print("\n[transaction] transaction_xfer_create_child\n") );
594 if( ope
->kxferacc
> 0 )
596 child
= da_transaction_clone(ope
);
598 child
->amount
= -child
->amount
;
599 child
->flags
^= (OF_INCOME
); // invert flag
600 child
->flags
&= ~(OF_REMIND
); // remove flag
602 child
->flags
&= ~(OF_VALID
); // remove reconcile state
606 child
->kacc
= child
->kxferacc
;
607 child
->kxferacc
= swap
;
609 /* update acc flags */
610 acc
= da_acc_get( child
->kacc
);
613 acc
->flags
|= AF_ADDED
;
616 guint maxkey
= da_transaction_get_max_kxfer();
618 DB( g_print(" + maxkey is %d\n", maxkey
) );
621 ope
->kxfer
= maxkey
+1;
622 child
->kxfer
= maxkey
+1;
624 DB( g_print(" + strong link to %d\n", ope
->kxfer
) );
627 DB( g_print(" + add transfer, %p\n", child
) );
629 da_transaction_insert_sorted(child
);
631 account_balances_add (child
);
634 transaction_add_treeview(child
, treeview
, ope
->kacc
);
641 void transaction_xfer_change_to_child(Transaction
*ope
, Transaction
*child
)
645 DB( g_print("\n[transaction] transaction_xfer_change_to_child\n") );
647 child
->paymode
= PAYMODE_INTXFER
;
649 ope
->kxferacc
= child
->kacc
;
650 child
->kxferacc
= ope
->kacc
;
652 /* update acc flags */
653 acc
= da_acc_get( child
->kacc
);
655 acc
->flags
|= AF_CHANGED
;
658 guint maxkey
= da_transaction_get_max_kxfer();
659 ope
->kxfer
= maxkey
+1;
660 child
->kxfer
= maxkey
+1;
665 void transaction_xfer_sync_child(Transaction
*s_txn
, Transaction
*child
)
668 DB( g_print("\n[transaction] transaction_xfer_sync_child\n") );
670 account_balances_sub (child
);
672 child
->date
= s_txn
->date
;
673 child
->amount
= -s_txn
->amount
;
674 child
->flags
= child
->flags
| OF_CHANGED
;
676 child
->flags
&= ~(OF_INCOME
);
677 if( child
->amount
> 0)
678 child
->flags
|= (OF_INCOME
);
679 child
->kpay
= s_txn
->kpay
;
680 child
->kcat
= s_txn
->kcat
;
682 g_free(child
->wording
);
683 child
->wording
= g_strdup(s_txn
->wording
);
686 child
->info
= g_strdup(s_txn
->info
);
688 //#1252230 sync account also
689 child
->kacc
= s_txn
->kxferacc
;
690 child
->kxferacc
= s_txn
->kacc
;
692 account_balances_add (child
);
694 //todo: synchronise tags here also ?
699 void transaction_xfer_delete_child(Transaction
*src
)
703 DB( g_print("\n[transaction] transaction_xfer_delete_child\n") );
705 dst
= transaction_strong_get_child_transfer( src
);
707 DB( g_print(" -> return is %s, %p\n", dst
->wording
, dst
) );
711 DB( g_print("deleting...") );
714 account_balances_sub(dst
);
715 GLOBALS
->ope_list
= g_list_remove(GLOBALS
->ope_list
, dst
);
720 Transaction
*transaction_old_get_child_transfer(Transaction
*src
)
725 DB( g_print("\n[transaction] transaction_get_child_transfer\n") );
727 //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->account, src->kxferacc) );
729 list
= g_list_first(GLOBALS
->ope_list
);
733 if( item
->paymode
== PAYMODE_INTXFER
)
735 if( src
->date
== item
->date
&&
736 src
->kacc
== item
->kxferacc
&&
737 src
->kxferacc
== item
->kacc
&&
738 ABS(src
->amount
) == ABS(item
->amount
) )
740 //DB( g_print(" found : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) );
745 list
= g_list_next(list
);
748 DB( g_print(" not found...\n") );
756 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
759 void transaction_add(Transaction
*ope
, GtkWidget
*treeview
, guint32 accnum
)
764 DB( g_print("\n[transaction] transaction add\n") );
766 //controls accounts valid (archive scheduled maybe bad)
767 acc
= da_acc_get(ope
->kacc
);
768 if(acc
== NULL
) return;
770 if(ope
->paymode
== PAYMODE_INTXFER
)
772 acc
= da_acc_get(ope
->kxferacc
);
773 if(acc
== NULL
) return;
776 da_transaction_splits_free(ope
);
779 //allocate a new entry and copy from our edited structure
780 newope
= da_transaction_clone(ope
);
782 //init flag and keep remind status
783 // already done in deftransaction_get
784 //ope->flags |= (OF_ADDED);
785 //remind = (ope->flags & OF_REMIND) ? TRUE : FALSE;
786 //ope->flags &= (~OF_REMIND);
788 /* cheque number is already stored in deftransaction_get */
789 /* todo:move this to transaction add
790 store a new cheque number into account ? */
792 if( (newope
->paymode
== PAYMODE_CHECK
) && (newope
->info
) && !(newope
->flags
& OF_INCOME
) )
796 /* get the active account and the corresponding cheque number */
797 acc
= da_acc_get( newope
->kacc
);
798 cheque
= atol(newope
->info
);
800 //DB( g_print(" -> should store cheque number %d to %d", cheque, newope->account) );
801 if( newope
->flags
& OF_CHEQ2
)
803 acc
->cheque2
= MAX(acc
->cheque2
, cheque
);
807 acc
->cheque1
= MAX(acc
->cheque1
, cheque
);
811 /* add normal transaction */
812 acc
= da_acc_get( newope
->kacc
);
815 acc
->flags
|= AF_ADDED
;
817 DB( g_print(" + add normal %p\n", newope
) );
818 //da_transaction_append(newope);
819 da_transaction_insert_sorted(newope
);
822 transaction_add_treeview(newope
, treeview
, accnum
);
824 account_balances_add(newope
);
826 if(newope
->paymode
== PAYMODE_INTXFER
)
828 transaction_xfer_search_or_add_child(newope
, treeview
);
836 void transaction_add_treeview(Transaction
*ope
, GtkWidget
*treeview
, guint32 accnum
)
841 //GtkTreeSelection *sel;
843 DB( g_print("\n[transaction] transaction add treeview\n") );
845 if(ope
->kacc
== accnum
)
847 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(treeview
));
848 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
850 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
851 LST_DSPOPE_DATAS
, ope
,
854 //activate that new line
855 //path = gtk_tree_model_get_path(model, &iter);
856 //gtk_tree_view_expand_to_path(GTK_TREE_VIEW(treeview), path);
858 //sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
859 //gtk_tree_selection_select_iter(sel, &iter);
861 //gtk_tree_path_free(path);
867 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
868 static gboolean
misc_text_match(gchar
*text
, gchar
*searchtext
, gboolean exact
)
870 gboolean match
= FALSE
;
875 //DB( g_print("search %s in %s\n", rul->name, ope->wording) );
876 if( searchtext
!= NULL
)
880 if( g_strrstr(text
, searchtext
) != NULL
)
882 DB( g_print(" found case '%s'\n", searchtext
) );
888 gchar
*word
= g_utf8_casefold(text
, -1);
889 gchar
*needle
= g_utf8_casefold(searchtext
, -1);
891 if( g_strrstr(word
, needle
) != NULL
)
893 DB( g_print(" found nocase '%s'\n", searchtext
) );
905 static Assign
*transaction_auto_assign_eval_txn(GList
*l_rul
, Transaction
*txn
)
910 DB( g_print("- eval every rules, and return the last that match\n") );
912 list
= g_list_first(l_rul
);
915 Assign
*rul
= list
->data
;
919 if(rul
->field
== 1) //payee
921 Payee
*pay
= da_pay_get(txn
->kpay
);
925 if( misc_text_match(text
, rul
->name
, rul
->flags
& ASGF_EXACT
))
928 list
= g_list_next(list
);
935 static Assign
*transaction_auto_assign_eval(GList
*l_rul
, gchar
*text
)
940 DB( g_print("- eval every rules, and return the last that match\n") );
942 list
= g_list_first(l_rul
);
945 Assign
*rul
= list
->data
;
947 if( rul
->field
== 0 ) //memo
949 if( misc_text_match(text
, rul
->name
, rul
->flags
& ASGF_EXACT
))
952 list
= g_list_next(list
);
959 gint
transaction_auto_assign(GList
*ope_list
, guint32 key
)
965 DB( g_print("\n[transaction] transaction_auto_assign\n") );
967 l_ope
= g_list_first(ope_list
);
968 l_rul
= g_hash_table_get_values(GLOBALS
->h_rul
);
970 while (l_ope
!= NULL
)
972 Transaction
*ope
= l_ope
->data
;
974 DB( g_print("- eval ope '%s' : acc=%d, pay=%d, cat=%d\n", ope
->wording
, ope
->kacc
, ope
->kpay
, ope
->kcat
) );
976 //#1215521: added key == 0
977 if( (key
== ope
->kacc
|| key
== 0) )
981 if( !(ope
->flags
& OF_SPLIT
) && (ope
->kpay
== 0 || ope
->kcat
== 0) )
983 rul
= transaction_auto_assign_eval_txn(l_rul
, ope
);
986 if( ope
->kpay
== 0 && (rul
->flags
& ASGF_DOPAY
) )
988 ope
->kpay
= rul
->kpay
;
989 ope
->flags
|= OF_CHANGED
;
992 if( ope
->kcat
== 0 && (rul
->flags
& ASGF_DOCAT
) )
994 ope
->kcat
= rul
->kcat
;
995 ope
->flags
|= OF_CHANGED
;
1001 else if( ope
->flags
& OF_SPLIT
)
1003 guint i
, nbsplit
= da_transaction_splits_count(ope
);
1005 gboolean split_change
= FALSE
;
1007 for(i
=0;i
<nbsplit
;i
++)
1009 split
= ope
->splits
[i
];
1011 DB( g_print("- eval split '%s'\n", split
->memo
) );
1013 if(split
->kcat
== 0)
1015 rul
= transaction_auto_assign_eval(l_rul
, split
->memo
);
1018 if( split
->kcat
== 0 && rul
->kcat
> 0 )
1020 split
->kcat
= rul
->kcat
;
1021 ope
->flags
|= OF_CHANGED
;
1022 split_change
= TRUE
;
1029 if(split_change
== TRUE
)
1036 l_ope
= g_list_next(l_ope
);
1045 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1049 transaction_tags_count(Transaction
*ope
)
1052 guint32
*ptr
= ope
->tags
;
1054 if( ope
->tags
== NULL
)
1057 while(*ptr
++ != 0 && count
< 32)
1066 guint
transaction_splits_parse(Transaction
*ope
, gchar
*cats
, gchar
*amounts
, gchar
*memos
)
1068 gchar
**cat_a
, **amt_a
, **mem_a
;
1074 DB( g_print(" split parse %s :: %s :: %s\n", cats
, amounts
, memos
) );
1076 cat_a
= g_strsplit (cats
, "||", 0);
1077 amt_a
= g_strsplit (amounts
, "||", 0);
1078 mem_a
= g_strsplit (memos
, "||", 0);
1080 count
= g_strv_length(amt_a
);
1081 if( (count
== g_strv_length(cat_a
)) && (count
== g_strv_length(mem_a
)) )
1083 for(i
=0;i
<count
;i
++)
1085 kcat
= atoi(cat_a
[i
]);
1086 amount
= g_ascii_strtod(amt_a
[i
], NULL
);
1087 split
= da_split_new(kcat
, amount
, mem_a
[i
]);
1088 da_transaction_splits_append (ope
, split
);
1091 ope
->flags
|= OF_SPLIT
;
1095 g_warning("invalid split parse");
1107 guint
transaction_splits_tostring(Transaction
*ope
, gchar
**cats
, gchar
**amounts
, gchar
**memos
)
1111 char buf
[G_ASCII_DTOSTR_BUF_SIZE
];
1112 GString
*cat_a
= g_string_new (NULL
);
1113 GString
*amt_a
= g_string_new (NULL
);
1114 GString
*mem_a
= g_string_new (NULL
);
1116 count
= da_transaction_splits_count(ope
);
1117 for(i
=0;i
<count
;i
++)
1119 split
= ope
->splits
[i
];
1120 g_string_append_printf (cat_a
, "%d", split
->kcat
);
1121 g_string_append(amt_a
, g_ascii_dtostr (buf
, sizeof (buf
), split
->amount
) );
1122 g_string_append(mem_a
, split
->memo
);
1126 g_string_append(cat_a
, "||");
1127 g_string_append(amt_a
, "||");
1128 g_string_append(mem_a
, "||");
1132 *cats
= g_string_free(cat_a
, FALSE
);
1133 *amounts
= g_string_free(amt_a
, FALSE
);
1134 *memos
= g_string_free(mem_a
, FALSE
);
1141 transaction_tags_parse(Transaction
*ope
, const gchar
*tagstring
)
1147 DB( g_print("(transaction_set_tags)\n") );
1149 DB( g_print(" - tagstring='%s'\n", tagstring
) );
1151 str_array
= g_strsplit (tagstring
, " ", 0);
1152 count
= g_strv_length( str_array
);
1157 DB( g_print(" -> reset storage %p\n", ope
->tags
) );
1163 ope
->tags
= g_new0(guint32
, count
+ 1);
1165 DB( g_print(" -> storage %p\n", ope
->tags
) );
1167 for(i
=0;i
<count
;i
++)
1169 tag
= da_tag_get_by_name(str_array
[i
]);
1172 Tag
*newtag
= da_tag_malloc();
1174 newtag
->name
= g_strdup(str_array
[i
]);
1175 da_tag_append(newtag
);
1176 tag
= da_tag_get_by_name(str_array
[i
]);
1179 DB( g_print(" -> storing %d=>%s at tags pos %d\n", tag
->key
, tag
->name
, i
) );
1181 ope
->tags
[i
] = tag
->key
;
1185 //hex_dump(ope->tags, sizeof(guint32*)*count+1);
1187 g_strfreev (str_array
);
1193 transaction_tags_tostring(Transaction
*ope
)
1200 DB( g_print("transaction_get_tagstring\n") );
1202 DB( g_print(" -> tags at=%p\n", ope
->tags
) );
1204 if( ope
->tags
== NULL
)
1211 count
= transaction_tags_count(ope
);
1213 DB( g_print(" -> tags at=%p, nbtags=%d\n", ope
->tags
, count
) );
1215 str_array
= g_new0(gchar
*, count
+1);
1217 DB( g_print(" -> str_array at %p\n", str_array
) );
1219 //hex_dump(ope->tags, sizeof(guint32*)*(count+1));
1221 for(i
=0;i
<count
;i
++)
1223 DB( g_print(" -> try to get tag %d\n", ope
->tags
[i
]) );
1225 tag
= da_tag_get(ope
->tags
[i
]);
1228 DB( g_print(" -> get %s at %d\n", tag
->name
, i
) );
1229 str_array
[i
] = tag
->name
;
1232 str_array
[i
] = NULL
;
1237 tagstring
= g_strjoinv(" ", str_array
);