1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2018 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"
29 /****************************************************************************/
31 /****************************************************************************/
40 /* our global datas */
41 extern struct HomeBank
*GLOBALS
;
42 extern struct Preferences
*PREFS
;
45 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
48 da_transaction_clean(Transaction
*item
)
52 if(item
->memo
!= NULL
)
57 if(item
->info
!= NULL
)
62 if(item
->tags
!= NULL
)
64 DB( g_print(" -> item->tags %p\n", item
->tags
) );
69 da_splits_free(item
->splits
);
70 item
->flags
&= ~(OF_SPLIT
); //Flag that Splits are cleared
72 if(item
->same
!= NULL
)
74 g_list_free(item
->same
);
82 da_transaction_free(Transaction
*item
)
86 da_transaction_clean(item
);
93 da_transaction_malloc(void)
95 return rc_alloc(sizeof(Transaction
));
99 Transaction
*da_transaction_copy(Transaction
*src_txn
, Transaction
*dst_txn
)
101 DB( g_print("da_transaction_copy\n") );
103 da_transaction_clean (dst_txn
);
105 memmove(dst_txn
, src_txn
, sizeof(Transaction
));
107 //duplicate the string
108 dst_txn
->memo
= g_strdup(src_txn
->memo
);
109 dst_txn
->info
= g_strdup(src_txn
->info
);
112 transaction_tags_clone(src_txn
, dst_txn
);
114 if (da_splits_clone(src_txn
->splits
, dst_txn
->splits
) > 0)
115 dst_txn
->flags
|= OF_SPLIT
; //Flag that Splits are active
121 Transaction
*da_transaction_init_from_template(Transaction
*txn
, Archive
*arc
)
124 txn
->amount
= arc
->amount
;
125 //#1258344 keep the current account if tpl is empty
127 txn
->kacc
= arc
->kacc
;
128 txn
->paymode
= arc
->paymode
;
129 txn
->flags
= arc
->flags
| OF_ADDED
;
130 txn
->status
= arc
->status
;
131 txn
->kpay
= arc
->kpay
;
132 txn
->kcat
= arc
->kcat
;
133 txn
->kxferacc
= arc
->kxferacc
;
134 txn
->memo
= g_strdup(arc
->memo
);
136 if( da_splits_clone(arc
->splits
, txn
->splits
) > 0)
137 txn
->flags
|= OF_SPLIT
; //Flag that Splits are active
143 Transaction
*da_transaction_clone(Transaction
*src_item
)
145 Transaction
*new_item
= rc_dup(src_item
, sizeof(Transaction
));
147 DB( g_print("da_transaction_clone\n") );
151 //duplicate the string
152 new_item
->memo
= g_strdup(src_item
->memo
);
153 new_item
->info
= g_strdup(src_item
->info
);
156 transaction_tags_clone(src_item
, new_item
);
158 if( da_splits_clone(src_item
->splits
, new_item
->splits
) > 0)
159 new_item
->flags
|= OF_SPLIT
; //Flag that Splits are active
167 da_transaction_new(void)
174 da_transaction_length(void)
176 GList
*lst_acc
, *lnk_acc
;
179 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
180 lnk_acc
= g_list_first(lst_acc
);
181 while (lnk_acc
!= NULL
)
183 Account
*acc
= lnk_acc
->data
;
185 count
+= g_queue_get_length (acc
->txn_queue
);
186 lnk_acc
= g_list_next(lnk_acc
);
188 g_list_free(lst_acc
);
193 static void da_transaction_queue_free_ghfunc(Transaction
*item
, gpointer data
)
195 da_transaction_free (item
);
199 void da_transaction_destroy(void)
203 lacc
= g_hash_table_get_values(GLOBALS
->h_acc
);
204 list
= g_list_first(lacc
);
207 Account
*acc
= list
->data
;
209 g_queue_foreach(acc
->txn_queue
, (GFunc
)da_transaction_queue_free_ghfunc
, NULL
);
210 list
= g_list_next(list
);
216 static gint
da_transaction_compare_datafunc(Transaction
*a
, Transaction
*b
, gpointer data
)
218 return ((gint
)a
->date
- b
->date
);
222 void da_transaction_queue_sort(GQueue
*queue
)
224 g_queue_sort(queue
, (GCompareDataFunc
)da_transaction_compare_datafunc
, NULL
);
228 static gint
da_transaction_compare_func(Transaction
*a
, Transaction
*b
)
230 return ((gint
)a
->date
- b
->date
);
234 GList
*da_transaction_sort(GList
*list
)
236 return( g_list_sort(list
, (GCompareFunc
)da_transaction_compare_func
));
240 gboolean
da_transaction_insert_memo(Transaction
*item
)
242 gboolean retval
= FALSE
;
244 // append the memo if new
245 if( item
->memo
!= NULL
)
247 if( g_hash_table_lookup(GLOBALS
->h_memo
, item
->memo
) == NULL
)
249 retval
= g_hash_table_insert(GLOBALS
->h_memo
, g_strdup(item
->memo
), NULL
);
256 gboolean
da_transaction_insert_sorted(Transaction
*newitem
)
261 acc
= da_acc_get(newitem
->kacc
);
265 lnk_txn
= g_queue_peek_tail_link(acc
->txn_queue
);
266 while (lnk_txn
!= NULL
)
268 Transaction
*item
= lnk_txn
->data
;
270 if(item
->date
<= newitem
->date
)
273 lnk_txn
= g_list_previous(lnk_txn
);
276 // we're at insert point, insert after txn
277 g_queue_insert_after(acc
->txn_queue
, lnk_txn
, newitem
);
279 da_transaction_insert_memo(newitem
);
284 // nota: this is called only when loading xml file
285 gboolean
da_transaction_prepend(Transaction
*item
)
289 acc
= da_acc_get(item
->kacc
);
294 item
->kcur
= acc
->kcur
;
295 g_queue_push_tail(acc
->txn_queue
, item
);
296 da_transaction_insert_memo(item
);
301 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
304 da_transaction_get_max_kxfer(void)
306 GList
*lst_acc
, *lnk_acc
;
310 DB( g_print("da_transaction_get_max_kxfer\n") );
312 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
313 lnk_acc
= g_list_first(lst_acc
);
314 while (lnk_acc
!= NULL
)
316 Account
*acc
= lnk_acc
->data
;
318 list
= g_queue_peek_head_link(acc
->txn_queue
);
321 Transaction
*item
= list
->data
;
323 if( item
->paymode
== PAYMODE_INTXFER
)
325 max_key
= MAX(max_key
, item
->kxfer
);
327 list
= g_list_next(list
);
330 lnk_acc
= g_list_next(lnk_acc
);
332 g_list_free(lst_acc
);
334 DB( g_print(" max_key : %d \n", max_key
) );
340 static void da_transaction_goto_orphan(Transaction
*txn
)
342 const gchar
*oatn
= "orphaned transactions";
343 Account
*ori_acc
, *acc
;
346 DB( g_print("\n[transaction] goto orphan\n") );
348 g_warning("txn consistency: moving to orphan %d '%s' %.2f", txn
->date
, txn
->memo
, txn
->amount
);
350 acc
= da_acc_get_by_name((gchar
*)oatn
);
353 acc
= da_acc_malloc();
354 acc
->name
= g_strdup(oatn
);
356 DB( g_print(" - created orphan acc %d\n", acc
->key
) );
359 ori_acc
= da_acc_get(txn
->kacc
);
362 found
= g_queue_remove(ori_acc
->txn_queue
, txn
);
363 DB( g_print(" - found in origin ? %d\n", found
) );
366 txn
->kacc
= acc
->key
;
367 da_transaction_insert_sorted (txn
);
368 DB( g_print("moved txn to %d\n", txn
->kacc
) );
374 void da_transaction_consistency(Transaction
*item
)
381 DB( g_print("\n[transaction] consistency\n") );
383 // ensure date is between range
384 item
->date
= CLAMP(item
->date
, HB_MINDATE
, HB_MAXDATE
);
386 // check account exists
387 acc
= da_acc_get(item
->kacc
);
390 g_warning("txn consistency: fixed invalid acc %d", item
->kacc
);
391 da_transaction_goto_orphan(item
);
392 GLOBALS
->changes_count
++;
395 // check category exists
396 cat
= da_cat_get(item
->kcat
);
399 g_warning("txn consistency: fixed invalid cat %d", item
->kcat
);
401 GLOBALS
->changes_count
++;
404 // check split category #1340142
405 split_cat_consistency(item
->splits
);
407 //# 1416624 empty category when split
408 nbsplit
= da_splits_count(item
->splits
);
409 if(nbsplit
> 0 && item
->kcat
> 0)
411 g_warning("txn consistency: fixed invalid cat on split txn");
413 GLOBALS
->changes_count
++;
416 // check payee exists
417 pay
= da_pay_get(item
->kpay
);
420 g_warning("txn consistency: fixed invalid pay %d", item
->kpay
);
422 GLOBALS
->changes_count
++;
425 // reset dst acc for non xfer transaction
426 if( item
->paymode
!= PAYMODE_INTXFER
)
432 // check dst account exists
433 if( item
->paymode
== PAYMODE_INTXFER
)
435 gint tak
= item
->kxferacc
;
437 item
->kxferacc
= ABS(tak
); //I crossed negative here one day
438 acc
= da_acc_get(item
->kxferacc
);
441 g_warning("txn consistency: fixed invalid dst_acc %d", item
->kxferacc
);
442 da_transaction_goto_orphan(item
);
444 item
->paymode
= PAYMODE_XFER
;
445 GLOBALS
->changes_count
++;
449 //#1628678 tags for internal xfer should be checked as well
452 //#1295877 ensure income flag is correctly set
453 item
->flags
&= ~(OF_INCOME
);
454 if( item
->amount
> 0)
455 item
->flags
|= (OF_INCOME
);
457 //#1308745 ensure remind flag unset if reconciled
459 //if( item->flags & OF_VALID )
460 // item->flags &= ~(OF_REMIND);
465 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
466 /* new transfer functions */
468 static void transaction_xfer_create_child(Transaction
*ope
)
474 DB( g_print("\n[transaction] xfer_create_child\n") );
476 if( ope
->kxferacc
> 0 )
478 child
= da_transaction_clone(ope
);
480 ope
->flags
|= OF_CHANGED
;
481 child
->flags
|= OF_ADDED
;
483 child
->amount
= -child
->amount
;
484 child
->flags
^= (OF_INCOME
); // invert flag
486 if( child
->status
!= TXN_STATUS_REMIND
)
487 child
->status
= TXN_STATUS_NONE
;
488 //child->flags &= ~(OF_VALID); // delete reconcile state
491 child
->kacc
= child
->kxferacc
;
492 child
->kxferacc
= swap
;
494 /* update acc flags */
495 acc
= da_acc_get( child
->kacc
);
498 acc
->flags
|= AF_ADDED
;
501 guint maxkey
= da_transaction_get_max_kxfer();
503 DB( g_print(" + maxkey is %d\n", maxkey
) );
506 ope
->kxfer
= maxkey
+1;
507 child
->kxfer
= maxkey
+1;
509 DB( g_print(" + strong link to %d\n", ope
->kxfer
) );
512 DB( g_print(" + add transfer, %p to acc %d\n", child
, acc
->key
) );
514 da_transaction_insert_sorted(child
);
516 account_balances_add (child
);
518 GValue txn_value
= G_VALUE_INIT
;
519 ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value
, child
), NULL
);
527 //todo: add strong control and extend to payee, maybe memo ?
528 static gboolean
transaction_xfer_child_might(Transaction
*stxn
, Transaction
*dtxn
, gint daygap
)
530 gboolean retval
= FALSE
;
532 //DB( g_print("\n[transaction] xfer_child_might\n") );
539 g_print(" %d %d %d %f %d\n",
540 stxn->kcur, stxn->date, stxn->kacc, ABS(stxn->amount), stxn->kxfer );
543 g_print(" %d %d %d %f %d\n",
544 dtxn->kcur, dtxn->date, dtxn->kacc, ABS(dtxn->amount), dtxn->kxfer );
547 if( stxn
->kcur
== dtxn
->kcur
&&
548 stxn
->date
== dtxn
->date
&&
549 //v5.1 make no sense: stxn->kxferacc == dtxn->kacc &&
550 stxn
->kacc
!= dtxn
->kacc
&&
551 ABS(stxn
->amount
) == ABS(dtxn
->amount
) &&
557 //g_print(" return %d\n", retval);
562 static GList
*transaction_xfer_child_might_list_get(Transaction
*ope
)
564 GList
*lst_acc
, *lnk_acc
;
565 GList
*list
, *matchlist
= NULL
;
567 //DB( g_print("\n[transaction] xfer_child_might_list_get\n") );
569 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
570 lnk_acc
= g_list_first(lst_acc
);
571 while (lnk_acc
!= NULL
)
573 Account
*acc
= lnk_acc
->data
;
575 if( !(acc
->flags
& AF_CLOSED
) && (acc
->key
!= ope
->kacc
) )
577 list
= g_queue_peek_tail_link(acc
->txn_queue
);
580 Transaction
*item
= list
->data
;
582 // no need to go higher than src txn date
583 if(item
->date
< ope
->date
)
586 if( transaction_xfer_child_might(ope
, item
, 0) == TRUE
)
588 //DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->account, item->kxferacc) );
589 matchlist
= g_list_append(matchlist
, item
);
591 list
= g_list_previous(list
);
595 lnk_acc
= g_list_next(lnk_acc
);
597 g_list_free(lst_acc
);
603 void transaction_xfer_search_or_add_child(GtkWindow
*parentwindow
, Transaction
*ope
, gboolean manual
)
608 DB( g_print("\n[transaction] xfer_search_or_add_child\n") );
610 matchlist
= transaction_xfer_child_might_list_get(ope
);
611 count
= g_list_length(matchlist
);
613 DB( g_print(" - found %d might match, switching\n", count
) );
617 case 0: //we should create the child
618 transaction_xfer_create_child(ope
);
621 //todo: maybe with just 1 match the user must choose ?
622 //#942346: bad idea so to no let the user confirm, so let hil confirm
624 case 1: //transform the transaction to a child transfer
626 GList *list = g_list_first(matchlist);
627 transaction_xfer_change_to_child(ope, list->data);
632 default: //the user must choose himself
636 child
= ui_dialog_transaction_xfer_select_child(ope
, matchlist
);
638 transaction_xfer_create_child(ope
);
640 transaction_xfer_change_to_child(ope
, child
);
644 g_list_free(matchlist
);
648 Transaction
*transaction_xfer_child_strong_get(Transaction
*src
)
653 DB( g_print("\n[transaction] xfer_child_strong_get\n") );
655 dstacc
= da_acc_get(src
->kxferacc
);
656 if( !dstacc
|| src
->kxfer
<= 0 )
659 DB( g_print(" - search: %d %s %f %d=>%d - %d\n", src
->date
, src
->memo
, src
->amount
, src
->kacc
, src
->kxferacc
, src
->kxfer
) );
661 list
= g_queue_peek_tail_link(dstacc
->txn_queue
);
664 Transaction
*item
= list
->data
;
667 //if( item->paymode == PAYMODE_INTXFER
668 // && item->kacc == src->kxferacc
669 // && item->kxfer == src->kxfer )
670 if( item
->paymode
== PAYMODE_INTXFER
671 && item
->kxfer
== src
->kxfer
674 DB( g_print(" - found : %d %s %f %d=>%d - %d\n", item
->date
, item
->memo
, item
->amount
, item
->kacc
, item
->kxferacc
, src
->kxfer
) );
677 list
= g_list_previous(list
);
680 DB( g_print(" - not found...\n") );
687 void transaction_xfer_change_to_child(Transaction
*ope
, Transaction
*child
)
691 DB( g_print("\n[transaction] xfer_change_to_child\n") );
693 if(ope
->kcur
!= child
->kcur
)
696 ope
->flags
|= OF_CHANGED
;
697 child
->flags
|= OF_CHANGED
;
699 child
->paymode
= PAYMODE_INTXFER
;
701 ope
->kxferacc
= child
->kacc
;
702 child
->kxferacc
= ope
->kacc
;
704 /* update acc flags */
705 dstacc
= da_acc_get( child
->kacc
);
707 dstacc
->flags
|= AF_CHANGED
;
710 guint maxkey
= da_transaction_get_max_kxfer();
711 ope
->kxfer
= maxkey
+1;
712 child
->kxfer
= maxkey
+1;
717 void transaction_xfer_child_sync(Transaction
*s_txn
, Transaction
*child
)
721 DB( g_print("\n[transaction] xfer_child_sync\n") );
725 DB( g_print(" - no child found\n") );
729 DB( g_print(" - found do sync\n") );
731 /* update acc flags */
732 acc
= da_acc_get( child
->kacc
);
734 acc
->flags
|= AF_CHANGED
;
736 account_balances_sub (child
);
738 child
->date
= s_txn
->date
;
739 child
->amount
= -s_txn
->amount
;
740 child
->flags
= child
->flags
| OF_CHANGED
;
742 child
->flags
&= ~(OF_INCOME
);
743 if( child
->amount
> 0)
744 child
->flags
|= (OF_INCOME
);
745 child
->kpay
= s_txn
->kpay
;
746 child
->kcat
= s_txn
->kcat
;
749 child
->memo
= g_strdup(s_txn
->memo
);
752 child
->info
= g_strdup(s_txn
->info
);
754 account_balances_add (child
);
756 //#1252230 sync account also
757 //#1663789 idem after 5.1
758 //source changed: update child key (move of s_txn is done in external_edit)
759 if( s_txn
->kacc
!= child
->kxferacc
)
761 child
->kxferacc
= s_txn
->kacc
;
764 //dest changed: move child & update child key
765 if( s_txn
->kxferacc
!= child
->kacc
)
767 transaction_acc_move(child
, child
->kacc
, s_txn
->kxferacc
);
770 //synchronise tags since 5.1
773 transaction_tags_clone (s_txn
, child
);
778 void transaction_xfer_remove_child(Transaction
*src
)
782 DB( g_print("\n[transaction] xfer_remove_child\n") );
784 dst
= transaction_xfer_child_strong_get( src
);
787 Account
*acc
= da_acc_get(dst
->kacc
);
791 DB( g_print("deleting...") );
792 account_balances_sub(dst
);
793 g_queue_remove(acc
->txn_queue
, dst
);
794 //#1419304 we keep the deleted txn to a trash stack
795 //da_transaction_free (dst);
796 g_trash_stack_push(&GLOBALS
->txn_stk
, dst
);
799 acc
->flags
|= AF_CHANGED
;
808 // still useful for upgrade from < file v0.6 (hb v4.4 kxfer)
809 Transaction
*transaction_old_get_child_transfer(Transaction
*src
)
814 DB( g_print("\n[transaction] get_child_transfer\n") );
816 //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->memo, src->amount, src->account, src->kxferacc) );
817 acc
= da_acc_get(src
->kxferacc
);
821 list
= g_queue_peek_head_link(acc
->txn_queue
);
824 Transaction
*item
= list
->data
;
826 // no need to go higher than src txn date
827 if(item
->date
> src
->date
)
830 if( item
->paymode
== PAYMODE_INTXFER
)
832 if( src
->date
== item
->date
&&
833 src
->kacc
== item
->kxferacc
&&
834 src
->kxferacc
== item
->kacc
&&
835 ABS(src
->amount
) == ABS(item
->amount
) )
837 //DB( g_print(" found : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->account, item->kxferacc) );
842 list
= g_list_next(list
);
846 DB( g_print(" not found...\n") );
852 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
855 void transaction_remove(Transaction
*ope
)
859 //controls accounts valid (archive scheduled maybe bad)
860 acc
= da_acc_get(ope
->kacc
);
861 if(acc
== NULL
) return;
863 account_balances_sub(ope
);
865 if( ope
->paymode
== PAYMODE_INTXFER
)
867 transaction_xfer_remove_child( ope
);
870 g_queue_remove(acc
->txn_queue
, ope
);
871 acc
->flags
|= AF_CHANGED
;
872 //#1419304 we keep the deleted txn to a trash stack
873 //da_transaction_free(entry);
874 g_trash_stack_push(&GLOBALS
->txn_stk
, ope
);
878 Transaction
*transaction_add(Transaction
*ope
)
883 DB( g_print("\n[transaction] transaction_add\n") );
885 //controls accounts valid (archive scheduled maybe bad)
886 acc
= da_acc_get(ope
->kacc
);
887 if(acc
== NULL
) return NULL
;
889 DB( g_print(" acc is '%s' %d\n", acc
->name
, acc
->key
) );
891 ope
->kcur
= acc
->kcur
;
893 if(ope
->paymode
== PAYMODE_INTXFER
)
895 acc
= da_acc_get(ope
->kxferacc
);
896 if(acc
== NULL
) return NULL
;
899 da_splits_free(ope
->splits
);
900 ope
->flags
&= ~(OF_SPLIT
); //Flag that Splits are cleared
904 //allocate a new entry and copy from our edited structure
905 newope
= da_transaction_clone(ope
);
907 //init flag and keep remind status
908 // already done in deftransaction_get
909 //ope->flags |= (OF_ADDED);
910 //remind = (ope->flags & OF_REMIND) ? TRUE : FALSE;
911 //ope->flags &= (~OF_REMIND);
913 /* cheque number is already stored in deftransaction_get */
914 /* todo:move this to transaction add
915 store a new cheque number into account ? */
917 if( (newope
->paymode
== PAYMODE_CHECK
) && (newope
->info
) && !(newope
->flags
& OF_INCOME
) )
921 /* get the active account and the corresponding cheque number */
922 acc
= da_acc_get( newope
->kacc
);
925 cheque
= atol(newope
->info
);
927 //DB( g_print(" -> should store cheque number %d to %d", cheque, newope->account) );
928 if( newope
->flags
& OF_CHEQ2
)
930 acc
->cheque2
= MAX(acc
->cheque2
, cheque
);
934 acc
->cheque1
= MAX(acc
->cheque1
, cheque
);
939 /* add normal transaction */
940 acc
= da_acc_get( newope
->kacc
);
943 acc
->flags
|= AF_ADDED
;
945 DB( g_print(" + add normal %p to acc %d\n", newope
, acc
->key
) );
946 //da_transaction_append(newope);
947 da_transaction_insert_sorted(newope
);
949 account_balances_add(newope
);
951 if(newope
->paymode
== PAYMODE_INTXFER
)
953 transaction_xfer_search_or_add_child(NULL
, newope
, FALSE
);
956 GValue txn_value
= G_VALUE_INIT
;
957 ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value
, newope
), NULL
);
964 gboolean
transaction_acc_move(Transaction
*txn
, guint32 okacc
, guint32 nkacc
)
966 Account
*oacc
, *nacc
;
968 DB( g_print("\n[transaction] acc_move\n") );
973 oacc
= da_acc_get(okacc
);
974 nacc
= da_acc_get(nkacc
);
977 account_balances_sub(txn
);
978 if( g_queue_remove(oacc
->txn_queue
, txn
) )
980 g_queue_push_tail(nacc
->txn_queue
, txn
);
981 txn
->kacc
= nacc
->key
;
982 txn
->kcur
= nacc
->kcur
;
983 nacc
->flags
|= AF_CHANGED
;
984 account_balances_add(txn
);
989 //ensure to keep txn into current account
991 account_balances_add(txn
);
998 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1001 static gboolean
misc_text_match(gchar
*text
, gchar
*searchtext
, gboolean exact
)
1003 gboolean match
= FALSE
;
1008 //DB( g_print("search %s in %s\n", rul->name, ope->memo) );
1009 if( searchtext
!= NULL
)
1013 if( g_strrstr(text
, searchtext
) != NULL
)
1015 DB( g_print(" found case '%s'\n", searchtext
) );
1021 gchar
*word
= g_utf8_casefold(text
, -1);
1022 gchar
*needle
= g_utf8_casefold(searchtext
, -1);
1024 if( g_strrstr(word
, needle
) != NULL
)
1026 DB( g_print(" found nocase '%s'\n", searchtext
) );
1037 static gboolean
misc_regex_match(gchar
*text
, gchar
*searchtext
, gboolean exact
)
1039 gboolean match
= FALSE
;
1044 DB( g_print("- match RE %s in %s\n", searchtext
, text
) );
1045 if( searchtext
!= NULL
)
1047 match
= g_regex_match_simple(searchtext
, text
, ((exact
== TRUE
)?0:G_REGEX_CASELESS
) | G_REGEX_OPTIMIZE
, G_REGEX_MATCH_NOTEMPTY
);
1048 if (match
== TRUE
) { DB( g_print(" found pattern '%s'\n", searchtext
) ); }
1054 static Assign
*transaction_auto_assign_eval_txn(GList
*l_rul
, Transaction
*txn
)
1056 Assign
*rule
= NULL
;
1059 DB( g_print("\n[transaction] auto_assign_eval_txn\n") );
1061 DB( g_print("- eval every rules, and return the last that match\n") );
1063 list
= g_list_first(l_rul
);
1064 while (list
!= NULL
)
1066 Assign
*rul
= list
->data
;
1070 if(rul
->field
== 1) //payee
1072 Payee
*pay
= da_pay_get(txn
->kpay
);
1077 if( !(rul
->flags
& ASGF_REGEX
) )
1079 if( misc_text_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1084 if( misc_regex_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1088 list
= g_list_next(list
);
1095 static Assign
*transaction_auto_assign_eval(GList
*l_rul
, gchar
*text
)
1097 Assign
*rule
= NULL
;
1100 DB( g_print("\n[transaction] auto_assign_eval\n") );
1102 DB( g_print("- eval every rules, and return the last that match\n") );
1104 list
= g_list_first(l_rul
);
1105 while (list
!= NULL
)
1107 Assign
*rul
= list
->data
;
1109 if( rul
->field
== 0 ) //memo
1111 if( !(rul
->flags
& ASGF_REGEX
) )
1113 if( misc_text_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1118 if( misc_regex_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1122 list
= g_list_next(list
);
1129 gint
transaction_auto_assign(GList
*ope_list
, guint32 kacc
)
1135 DB( g_print("\n[transaction] auto_assign\n") );
1137 l_rul
= g_hash_table_get_values(GLOBALS
->h_rul
);
1139 l_ope
= g_list_first(ope_list
);
1140 while (l_ope
!= NULL
)
1142 Transaction
*ope
= l_ope
->data
;
1143 gboolean changed
= FALSE
;
1145 DB( g_print("- eval ope '%s' : acc=%d, pay=%d, cat=%d\n", ope
->memo
, ope
->kacc
, ope
->kpay
, ope
->kcat
) );
1147 //#1215521: added kacc == 0
1148 if( (kacc
== ope
->kacc
|| kacc
== 0) )
1152 rul
= transaction_auto_assign_eval_txn(l_rul
, ope
);
1155 if( (ope
->kpay
== 0 && (rul
->flags
& ASGF_DOPAY
)) || (rul
->flags
& ASGF_OVWPAY
) )
1157 if(ope
->kpay
!= rul
->kpay
) { changed
= TRUE
; }
1158 ope
->kpay
= rul
->kpay
;
1161 if( !(ope
->flags
& OF_SPLIT
) )
1163 if( (ope
->kcat
== 0 && (rul
->flags
& ASGF_DOCAT
)) || (rul
->flags
& ASGF_OVWCAT
) )
1165 if(ope
->kcat
!= rul
->kcat
) { changed
= TRUE
; }
1166 ope
->kcat
= rul
->kcat
;
1170 if( (ope
->paymode
== 0 && (rul
->flags
& ASGF_DOMOD
)) || (rul
->flags
& ASGF_OVWMOD
) )
1172 //ugly hack - don't allow modify intxfer
1173 if(ope
->paymode
!= PAYMODE_INTXFER
&& rul
->paymode
!= PAYMODE_INTXFER
)
1175 if(ope
->paymode
!= rul
->paymode
) { changed
= TRUE
; }
1176 ope
->paymode
= rul
->paymode
;
1182 if( ope
->flags
& OF_SPLIT
)
1184 guint i
, nbsplit
= da_splits_count(ope
->splits
);
1186 for(i
=0;i
<nbsplit
;i
++)
1188 Split
*split
= ope
->splits
[i
];
1190 DB( g_print("- eval split '%s'\n", split
->memo
) );
1192 rul
= transaction_auto_assign_eval(l_rul
, split
->memo
);
1195 //#1501144: check if user wants to set category in rule
1196 if( (split
->kcat
== 0 || (rul
->flags
& ASGF_OVWCAT
)) && (rul
->flags
& ASGF_DOCAT
) )
1198 if(split
->kcat
!= rul
->kcat
) { changed
= TRUE
; }
1199 split
->kcat
= rul
->kcat
;
1207 ope
->flags
|= OF_CHANGED
;
1212 l_ope
= g_list_next(l_ope
);
1221 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1225 transaction_tags_count(Transaction
*ope
)
1228 guint32
*ptr
= ope
->tags
;
1230 //DB( g_print("\n[transaction] tags_count\n") );
1232 if( ope
->tags
== NULL
)
1235 while(*ptr
++ != 0 && count
< 32)
1242 void transaction_tags_clone(Transaction
*src_txn
, Transaction
*dst_txn
)
1246 dst_txn
->tags
= NULL
;
1247 count
= transaction_tags_count(src_txn
);
1250 //1501962: we must also copy the final 0
1251 dst_txn
->tags
= g_memdup(src_txn
->tags
, (count
+1)*sizeof(guint32
));
1256 transaction_tags_parse(Transaction
*ope
, const gchar
*tagstring
)
1262 DB( g_print("\n[transaction] tags_parse\n") );
1264 DB( g_print(" - tagstring='%s'\n", tagstring
) );
1266 str_array
= g_strsplit (tagstring
, " ", 0);
1267 count
= g_strv_length( str_array
);
1272 DB( g_print(" -> reset storage %p\n", ope
->tags
) );
1278 ope
->tags
= g_new0(guint32
, count
+ 1);
1280 DB( g_print(" -> storage %p\n", ope
->tags
) );
1282 for(i
=0;i
<count
;i
++)
1284 tag
= da_tag_get_by_name(str_array
[i
]);
1287 Tag
*newtag
= da_tag_malloc();
1289 newtag
->name
= g_strdup(str_array
[i
]);
1290 da_tag_append(newtag
);
1291 tag
= da_tag_get_by_name(str_array
[i
]);
1294 DB( g_print(" -> storing %d=>%s at tags pos %d\n", tag
->key
, tag
->name
, i
) );
1296 ope
->tags
[i
] = tag
->key
;
1301 //hex_dump(ope->tags, sizeof(guint32*)*count+1);
1303 g_strfreev (str_array
);
1309 transaction_tags_tostring(Transaction
*ope
)
1316 DB( g_print("\n[transaction] tags_tostring\n") );
1318 DB( g_print(" -> tags at=%p\n", ope
->tags
) );
1320 if( ope
->tags
== NULL
)
1327 count
= transaction_tags_count(ope
);
1329 DB( g_print(" -> tags at=%p, nbtags=%d\n", ope
->tags
, count
) );
1331 str_array
= g_new0(gchar
*, count
+1);
1333 DB( g_print(" -> str_array at %p\n", str_array
) );
1335 //hex_dump(ope->tags, sizeof(guint32*)*(count+1));
1337 for(i
=0;i
<count
;i
++)
1339 DB( g_print(" -> try to get tag %d\n", ope
->tags
[i
]) );
1341 tag
= da_tag_get(ope
->tags
[i
]);
1344 DB( g_print(" -> get %s at %d\n", tag
->name
, i
) );
1345 str_array
[i
] = tag
->name
;
1348 str_array
[i
] = NULL
;
1353 tagstring
= g_strjoinv(" ", str_array
);