1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2017 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
->wording
!= NULL
)
54 g_free(item
->wording
);
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
);
83 da_transaction_free(Transaction
*item
)
87 da_transaction_clean(item
);
94 da_transaction_malloc(void)
96 return rc_alloc(sizeof(Transaction
));
100 Transaction
*da_transaction_copy(Transaction
*src_txn
, Transaction
*dst_txn
)
102 DB( g_print("da_transaction_copy\n") );
104 da_transaction_clean (dst_txn
);
106 memmove(dst_txn
, src_txn
, sizeof(Transaction
));
108 //duplicate the string
109 dst_txn
->wording
= g_strdup(src_txn
->wording
);
110 dst_txn
->info
= g_strdup(src_txn
->info
);
113 transaction_tags_clone(src_txn
, dst_txn
);
115 if (da_splits_clone(src_txn
->splits
, dst_txn
->splits
) > 0)
116 dst_txn
->flags
|= OF_SPLIT
; //Flag that Splits are active
122 Transaction
*da_transaction_init_from_template(Transaction
*txn
, Archive
*arc
)
125 txn
->amount
= arc
->amount
;
126 //#1258344 keep the current account if tpl is empty
128 txn
->kacc
= arc
->kacc
;
129 txn
->paymode
= arc
->paymode
;
130 txn
->flags
= arc
->flags
| OF_ADDED
;
131 txn
->status
= arc
->status
;
132 txn
->kpay
= arc
->kpay
;
133 txn
->kcat
= arc
->kcat
;
134 txn
->kxferacc
= arc
->kxferacc
;
135 txn
->wording
= g_strdup(arc
->wording
);
137 if( da_splits_clone(arc
->splits
, txn
->splits
) > 0)
138 txn
->flags
|= OF_SPLIT
; //Flag that Splits are active
144 Transaction
*da_transaction_clone(Transaction
*src_item
)
146 Transaction
*new_item
= rc_dup(src_item
, sizeof(Transaction
));
148 DB( g_print("da_transaction_clone\n") );
152 //duplicate the string
153 new_item
->wording
= g_strdup(src_item
->wording
);
154 new_item
->info
= g_strdup(src_item
->info
);
157 transaction_tags_clone(src_item
, new_item
);
159 if( da_splits_clone(src_item
->splits
, new_item
->splits
) > 0)
160 new_item
->flags
|= OF_SPLIT
; //Flag that Splits are active
168 da_transaction_new(void)
175 da_transaction_length(void)
177 GList
*lst_acc
, *lnk_acc
;
180 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
181 lnk_acc
= g_list_first(lst_acc
);
182 while (lnk_acc
!= NULL
)
184 Account
*acc
= lnk_acc
->data
;
186 count
+= g_queue_get_length (acc
->txn_queue
);
187 lnk_acc
= g_list_next(lnk_acc
);
189 g_list_free(lst_acc
);
194 static void da_transaction_queue_free_ghfunc(Transaction
*item
, gpointer data
)
196 da_transaction_free (item
);
200 void da_transaction_destroy(void)
204 lacc
= g_hash_table_get_values(GLOBALS
->h_acc
);
205 list
= g_list_first(lacc
);
208 Account
*acc
= list
->data
;
210 g_queue_foreach(acc
->txn_queue
, (GFunc
)da_transaction_queue_free_ghfunc
, NULL
);
211 list
= g_list_next(list
);
217 static gint
da_transaction_compare_datafunc(Transaction
*a
, Transaction
*b
, gpointer data
)
219 return ((gint
)a
->date
- b
->date
);
223 void da_transaction_queue_sort(GQueue
*queue
)
225 g_queue_sort(queue
, (GCompareDataFunc
)da_transaction_compare_datafunc
, NULL
);
229 static gint
da_transaction_compare_func(Transaction
*a
, Transaction
*b
)
231 return ((gint
)a
->date
- b
->date
);
235 GList
*da_transaction_sort(GList
*list
)
237 return( g_list_sort(list
, (GCompareFunc
)da_transaction_compare_func
));
241 static void da_transaction_insert_memo(Transaction
*item
)
243 // append the memo if new
244 if( item
->wording
!= NULL
)
246 if( g_hash_table_lookup(GLOBALS
->h_memo
, item
->wording
) == NULL
)
248 g_hash_table_insert(GLOBALS
->h_memo
, g_strdup(item
->wording
), NULL
);
254 gboolean
da_transaction_insert_sorted(Transaction
*newitem
)
259 acc
= da_acc_get(newitem
->kacc
);
263 lnk_txn
= g_queue_peek_tail_link(acc
->txn_queue
);
264 while (lnk_txn
!= NULL
)
266 Transaction
*item
= lnk_txn
->data
;
268 if(item
->date
<= newitem
->date
)
271 lnk_txn
= g_list_previous(lnk_txn
);
274 // we're at insert point, insert after txn
275 g_queue_insert_after(acc
->txn_queue
, lnk_txn
, newitem
);
277 da_transaction_insert_memo(newitem
);
282 // nota: this is called only when loading xml file
283 gboolean
da_transaction_prepend(Transaction
*item
)
287 acc
= da_acc_get(item
->kacc
);
289 item
->kcur
= acc
->kcur
;
290 g_queue_push_tail(acc
->txn_queue
, item
);
291 da_transaction_insert_memo(item
);
296 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
299 da_transaction_get_max_kxfer(void)
301 GList
*lst_acc
, *lnk_acc
;
305 DB( g_print("da_transaction_get_max_kxfer\n") );
307 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
308 lnk_acc
= g_list_first(lst_acc
);
309 while (lnk_acc
!= NULL
)
311 Account
*acc
= lnk_acc
->data
;
313 list
= g_queue_peek_head_link(acc
->txn_queue
);
316 Transaction
*item
= list
->data
;
318 if( item
->paymode
== PAYMODE_INTXFER
)
320 max_key
= MAX(max_key
, item
->kxfer
);
322 list
= g_list_next(list
);
325 lnk_acc
= g_list_next(lnk_acc
);
327 g_list_free(lst_acc
);
329 DB( g_print(" max_key : %d \n", max_key
) );
335 static void da_transaction_goto_orphan(Transaction
*txn
)
337 const gchar
*oatn
= "orphaned transactions";
340 acc
= da_acc_get_by_name((gchar
*)oatn
);
343 acc
= da_acc_malloc();
344 acc
->name
= g_strdup(oatn
);
347 txn
->kacc
= acc
->key
;
351 void da_transaction_consistency(Transaction
*item
)
358 // ensure date is between range
359 item
->date
= CLAMP(item
->date
, HB_MINDATE
, HB_MAXDATE
);
361 // check account exists
362 acc
= da_acc_get(item
->kacc
);
365 g_warning("txn consistency: fixed invalid acc %d", item
->kacc
);
366 da_transaction_goto_orphan(item
);
367 GLOBALS
->changes_count
++;
370 // check category exists
371 cat
= da_cat_get(item
->kcat
);
374 g_warning("txn consistency: fixed invalid cat %d", item
->kcat
);
376 GLOBALS
->changes_count
++;
379 // check split category #1340142
380 split_cat_consistency(item
->splits
);
382 //# 1416624 empty category when split
383 nbsplit
= da_splits_count(item
->splits
);
384 if(nbsplit
> 0 && item
->kcat
> 0)
386 g_warning("txn consistency: fixed invalid cat on split txn");
388 GLOBALS
->changes_count
++;
391 // check payee exists
392 pay
= da_pay_get(item
->kpay
);
395 g_warning("txn consistency: fixed invalid pay %d", item
->kpay
);
397 GLOBALS
->changes_count
++;
400 // reset dst acc for non xfer transaction
401 if( item
->paymode
!= PAYMODE_INTXFER
)
404 //#1628678 tags for internal xfer should be checked as well
407 //#1295877 ensure income flag is correctly set
408 item
->flags
&= ~(OF_INCOME
);
409 if( item
->amount
> 0)
410 item
->flags
|= (OF_INCOME
);
412 //#1308745 ensure remind flag unset if reconciled
414 //if( item->flags & OF_VALID )
415 // item->flags &= ~(OF_REMIND);
420 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
421 /* new transfer functions */
423 static void transaction_xfer_create_child(Transaction
*ope
)
429 DB( g_print("\n[transaction] xfer_create_child\n") );
431 if( ope
->kxferacc
> 0 )
433 child
= da_transaction_clone(ope
);
435 ope
->flags
|= OF_CHANGED
;
436 child
->flags
|= OF_ADDED
;
438 child
->amount
= -child
->amount
;
439 child
->flags
^= (OF_INCOME
); // invert flag
441 child
->status
= TXN_STATUS_NONE
;
442 //child->flags &= ~(OF_VALID); // delete reconcile state
445 child
->kacc
= child
->kxferacc
;
446 child
->kxferacc
= swap
;
448 /* update acc flags */
449 acc
= da_acc_get( child
->kacc
);
452 acc
->flags
|= AF_ADDED
;
455 guint maxkey
= da_transaction_get_max_kxfer();
457 DB( g_print(" + maxkey is %d\n", maxkey
) );
460 ope
->kxfer
= maxkey
+1;
461 child
->kxfer
= maxkey
+1;
463 DB( g_print(" + strong link to %d\n", ope
->kxfer
) );
466 DB( g_print(" + add transfer, %p to acc %d\n", child
, acc
->key
) );
468 da_transaction_insert_sorted(child
);
470 account_balances_add (child
);
472 GValue txn_value
= G_VALUE_INIT
;
473 ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value
, child
), NULL
);
481 //todo: add strong control and extend to payee, maybe memo ?
482 static gboolean
transaction_xfer_child_might(Transaction
*stxn
, Transaction
*dtxn
, gint daygap
)
484 gboolean retval
= FALSE
;
486 //DB( g_print("\n[transaction] xfer_child_might\n") );
493 g_print(" %d %d %d %f %d\n",
494 stxn->kcur, stxn->date, stxn->kacc, ABS(stxn->amount), stxn->kxfer );
497 g_print(" %d %d %d %f %d\n",
498 dtxn->kcur, dtxn->date, dtxn->kacc, ABS(dtxn->amount), dtxn->kxfer );
501 if( stxn
->kcur
== dtxn
->kcur
&&
502 stxn
->date
== dtxn
->date
&&
503 //v5.1 make no sense: stxn->kxferacc == dtxn->kacc &&
504 stxn
->kacc
!= dtxn
->kacc
&&
505 ABS(stxn
->amount
) == ABS(dtxn
->amount
) &&
511 //g_print(" return %d\n", retval);
516 static GList
*transaction_xfer_child_might_list_get(Transaction
*ope
)
518 GList
*lst_acc
, *lnk_acc
;
519 GList
*list
, *matchlist
= NULL
;
521 //DB( g_print("\n[transaction] xfer_child_might_list_get\n") );
523 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
524 lnk_acc
= g_list_first(lst_acc
);
525 while (lnk_acc
!= NULL
)
527 Account
*acc
= lnk_acc
->data
;
529 if( !(acc
->flags
& AF_CLOSED
) && (acc
->key
!= ope
->kacc
) )
531 list
= g_queue_peek_tail_link(acc
->txn_queue
);
534 Transaction
*item
= list
->data
;
536 // no need to go higher than src txn date
537 if(item
->date
< ope
->date
)
540 if( transaction_xfer_child_might(ope
, item
, 0) == TRUE
)
542 //DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) );
543 matchlist
= g_list_append(matchlist
, item
);
545 list
= g_list_previous(list
);
549 lnk_acc
= g_list_next(lnk_acc
);
551 g_list_free(lst_acc
);
557 void transaction_xfer_search_or_add_child(GtkWindow
*parentwindow
, Transaction
*ope
, gboolean manual
)
562 DB( g_print("\n[transaction] xfer_search_or_add_child\n") );
564 matchlist
= transaction_xfer_child_might_list_get(ope
);
565 count
= g_list_length(matchlist
);
567 DB( g_print(" - found %d might match, switching\n", count
) );
571 case 0: //we should create the child
572 transaction_xfer_create_child(ope
);
575 //todo: maybe with just 1 match the user must choose ?
576 //#942346: bad idea so to no let the user confirm, so let hil confirm
578 case 1: //transform the transaction to a child transfer
580 GList *list = g_list_first(matchlist);
581 transaction_xfer_change_to_child(ope, list->data);
586 default: //the user must choose himself
590 child
= ui_dialog_transaction_xfer_select_child(ope
, matchlist
);
592 transaction_xfer_create_child(ope
);
594 transaction_xfer_change_to_child(ope
, child
);
598 g_list_free(matchlist
);
602 Transaction
*transaction_xfer_child_strong_get(Transaction
*src
)
607 DB( g_print("\n[transaction] xfer_child_strong_get\n") );
609 dstacc
= da_acc_get(src
->kxferacc
);
610 if( !dstacc
|| src
->kxfer
<= 0 )
613 DB( g_print(" - search: %d %s %f %d=>%d - %d\n", src
->date
, src
->wording
, src
->amount
, src
->kacc
, src
->kxferacc
, src
->kxfer
) );
615 list
= g_queue_peek_tail_link(dstacc
->txn_queue
);
618 Transaction
*item
= list
->data
;
621 //if( item->paymode == PAYMODE_INTXFER
622 // && item->kacc == src->kxferacc
623 // && item->kxfer == src->kxfer )
624 if( item
->paymode
== PAYMODE_INTXFER
625 && item
->kxfer
== src
->kxfer
628 DB( g_print(" - found : %d %s %f %d=>%d - %d\n", item
->date
, item
->wording
, item
->amount
, item
->kacc
, item
->kxferacc
, src
->kxfer
) );
631 list
= g_list_previous(list
);
634 DB( g_print(" - not found...\n") );
641 void transaction_xfer_change_to_child(Transaction
*ope
, Transaction
*child
)
645 DB( g_print("\n[transaction] xfer_change_to_child\n") );
647 if(ope
->kcur
!= child
->kcur
)
650 ope
->flags
|= OF_CHANGED
;
651 child
->flags
|= OF_CHANGED
;
653 child
->paymode
= PAYMODE_INTXFER
;
655 ope
->kxferacc
= child
->kacc
;
656 child
->kxferacc
= ope
->kacc
;
658 /* update acc flags */
659 dstacc
= da_acc_get( child
->kacc
);
661 dstacc
->flags
|= AF_CHANGED
;
664 guint maxkey
= da_transaction_get_max_kxfer();
665 ope
->kxfer
= maxkey
+1;
666 child
->kxfer
= maxkey
+1;
671 void transaction_xfer_sync_child(Transaction
*s_txn
, Transaction
*child
)
674 DB( g_print("\n[transaction] xfer_sync_child\n") );
676 account_balances_sub (child
);
678 child
->date
= s_txn
->date
;
679 child
->amount
= -s_txn
->amount
;
680 child
->flags
= child
->flags
| OF_CHANGED
;
682 child
->flags
&= ~(OF_INCOME
);
683 if( child
->amount
> 0)
684 child
->flags
|= (OF_INCOME
);
685 child
->kpay
= s_txn
->kpay
;
686 child
->kcat
= s_txn
->kcat
;
688 g_free(child
->wording
);
689 child
->wording
= g_strdup(s_txn
->wording
);
692 child
->info
= g_strdup(s_txn
->info
);
694 //#1252230 sync account also
695 child
->kacc
= s_txn
->kxferacc
;
696 child
->kxferacc
= s_txn
->kacc
;
698 account_balances_add (child
);
700 //synchronise tags since 5.1
703 transaction_tags_clone (s_txn
, child
);
708 void transaction_xfer_remove_child(Transaction
*src
)
712 DB( g_print("\n[transaction] xfer_remove_child\n") );
714 dst
= transaction_xfer_child_strong_get( src
);
716 DB( g_print(" -> return is %s, %p\n", dst
->wording
, dst
) );
720 Account
*acc
= da_acc_get(dst
->kacc
);
722 DB( g_print("deleting...") );
725 account_balances_sub(dst
);
726 g_queue_remove(acc
->txn_queue
, dst
);
727 da_transaction_free (dst
);
732 // still useful for upgrade from < file v0.6 (hb v4.4 kxfer)
733 Transaction
*transaction_old_get_child_transfer(Transaction
*src
)
738 DB( g_print("\n[transaction] get_child_transfer\n") );
740 //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->account, src->kxferacc) );
741 acc
= da_acc_get(src
->kxferacc
);
743 list
= g_queue_peek_head_link(acc
->txn_queue
);
746 Transaction
*item
= list
->data
;
748 // no need to go higher than src txn date
749 if(item
->date
> src
->date
)
752 if( item
->paymode
== PAYMODE_INTXFER
)
754 if( src
->date
== item
->date
&&
755 src
->kacc
== item
->kxferacc
&&
756 src
->kxferacc
== item
->kacc
&&
757 ABS(src
->amount
) == ABS(item
->amount
) )
759 //DB( g_print(" found : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) );
764 list
= g_list_next(list
);
767 DB( g_print(" not found...\n") );
773 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
776 void transaction_add(Transaction
*ope
, GtkWidget
*treeview
, guint32 accnum
)
781 DB( g_print("\n[transaction] transaction_add\n") );
783 //controls accounts valid (archive scheduled maybe bad)
784 acc
= da_acc_get(ope
->kacc
);
785 if(acc
== NULL
) return;
787 DB( g_print(" acc is '%s' %d\n", acc
->name
, acc
->key
) );
789 ope
->kcur
= acc
->kcur
;
791 if(ope
->paymode
== PAYMODE_INTXFER
)
793 acc
= da_acc_get(ope
->kxferacc
);
794 if(acc
== NULL
) return;
797 da_splits_free(ope
->splits
);
798 ope
->flags
&= ~(OF_SPLIT
); //Flag that Splits are cleared
802 //allocate a new entry and copy from our edited structure
803 newope
= da_transaction_clone(ope
);
805 //init flag and keep remind status
806 // already done in deftransaction_get
807 //ope->flags |= (OF_ADDED);
808 //remind = (ope->flags & OF_REMIND) ? TRUE : FALSE;
809 //ope->flags &= (~OF_REMIND);
811 /* cheque number is already stored in deftransaction_get */
812 /* todo:move this to transaction add
813 store a new cheque number into account ? */
815 if( (newope
->paymode
== PAYMODE_CHECK
) && (newope
->info
) && !(newope
->flags
& OF_INCOME
) )
819 /* get the active account and the corresponding cheque number */
820 acc
= da_acc_get( newope
->kacc
);
821 cheque
= atol(newope
->info
);
823 //DB( g_print(" -> should store cheque number %d to %d", cheque, newope->account) );
824 if( newope
->flags
& OF_CHEQ2
)
826 acc
->cheque2
= MAX(acc
->cheque2
, cheque
);
830 acc
->cheque1
= MAX(acc
->cheque1
, cheque
);
834 /* add normal transaction */
835 acc
= da_acc_get( newope
->kacc
);
838 acc
->flags
|= AF_ADDED
;
840 DB( g_print(" + add normal %p to acc %d\n", newope
, acc
->key
) );
841 //da_transaction_append(newope);
842 da_transaction_insert_sorted(newope
);
845 transaction_add_treeview(newope
, treeview
, accnum
);
847 account_balances_add(newope
);
849 if(newope
->paymode
== PAYMODE_INTXFER
)
851 transaction_xfer_search_or_add_child(NULL
, newope
, FALSE
);
854 GValue txn_value
= G_VALUE_INIT
;
855 ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value
, newope
), NULL
);
860 void transaction_add_treeview(Transaction
*ope
, GtkWidget
*treeview
, guint32 accnum
)
865 //GtkTreeSelection *sel;
867 DB( g_print("\n[transaction] add_treeview\n") );
869 if(ope
->kacc
== accnum
)
871 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(treeview
));
872 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
874 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
875 LST_DSPOPE_DATAS
, ope
,
878 //activate that new line
879 //path = gtk_tree_model_get_path(model, &iter);
880 //gtk_tree_view_expand_to_path(GTK_TREE_VIEW(treeview), path);
882 //sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
883 //gtk_tree_selection_select_iter(sel, &iter);
885 //gtk_tree_path_free(path);
891 gboolean
transaction_acc_move(Transaction
*txn
, guint32 okacc
, guint32 nkacc
)
893 Account
*oacc
, *nacc
;
895 DB( g_print("\n[transaction] acc_move\n") );
897 oacc
= da_acc_get(okacc
);
898 nacc
= da_acc_get(nkacc
);
901 if( g_queue_remove(oacc
->txn_queue
, txn
) )
903 g_queue_push_tail(nacc
->txn_queue
, txn
);
904 txn
->kacc
= nacc
->key
;
905 txn
->kcur
= nacc
->kcur
;
906 nacc
->flags
|= AF_CHANGED
;
910 //ensure to keep txn into current account
917 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
920 static gboolean
misc_text_match(gchar
*text
, gchar
*searchtext
, gboolean exact
)
922 gboolean match
= FALSE
;
927 //DB( g_print("search %s in %s\n", rul->name, ope->wording) );
928 if( searchtext
!= NULL
)
932 if( g_strrstr(text
, searchtext
) != NULL
)
934 DB( g_print(" found case '%s'\n", searchtext
) );
940 gchar
*word
= g_utf8_casefold(text
, -1);
941 gchar
*needle
= g_utf8_casefold(searchtext
, -1);
943 if( g_strrstr(word
, needle
) != NULL
)
945 DB( g_print(" found nocase '%s'\n", searchtext
) );
956 static gboolean
misc_regex_match(gchar
*text
, gchar
*searchtext
, gboolean exact
)
958 gboolean match
= FALSE
;
963 DB( g_print("- match RE %s in %s\n", searchtext
, text
) );
964 if( searchtext
!= NULL
)
966 match
= g_regex_match_simple(searchtext
, text
, ((exact
== TRUE
)?0:G_REGEX_CASELESS
) | G_REGEX_OPTIMIZE
, G_REGEX_MATCH_NOTEMPTY
);
967 if (match
== TRUE
) { DB( g_print(" found pattern '%s'\n", searchtext
) ); }
973 static Assign
*transaction_auto_assign_eval_txn(GList
*l_rul
, Transaction
*txn
)
978 DB( g_print("\n[transaction] auto_assign_eval_txn\n") );
980 DB( g_print("- eval every rules, and return the last that match\n") );
982 list
= g_list_first(l_rul
);
985 Assign
*rul
= list
->data
;
989 if(rul
->field
== 1) //payee
991 Payee
*pay
= da_pay_get(txn
->kpay
);
996 if( !(rul
->flags
& ASGF_REGEX
) )
998 if( misc_text_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1003 if( misc_regex_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1007 list
= g_list_next(list
);
1014 static Assign
*transaction_auto_assign_eval(GList
*l_rul
, gchar
*text
)
1016 Assign
*rule
= NULL
;
1019 DB( g_print("\n[transaction] auto_assign_eval\n") );
1021 DB( g_print("- eval every rules, and return the last that match\n") );
1023 list
= g_list_first(l_rul
);
1024 while (list
!= NULL
)
1026 Assign
*rul
= list
->data
;
1028 if( rul
->field
== 0 ) //memo
1030 if( !(rul
->flags
& ASGF_REGEX
) )
1032 if( misc_text_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1037 if( misc_regex_match(text
, rul
->text
, rul
->flags
& ASGF_EXACT
) )
1041 list
= g_list_next(list
);
1048 gint
transaction_auto_assign(GList
*ope_list
, guint32 kacc
)
1054 DB( g_print("\n[transaction] auto_assign\n") );
1056 l_rul
= g_hash_table_get_values(GLOBALS
->h_rul
);
1058 l_ope
= g_list_first(ope_list
);
1059 while (l_ope
!= NULL
)
1061 Transaction
*ope
= l_ope
->data
;
1062 gboolean changed
= FALSE
;
1064 DB( g_print("- eval ope '%s' : acc=%d, pay=%d, cat=%d\n", ope
->wording
, ope
->kacc
, ope
->kpay
, ope
->kcat
) );
1066 //#1215521: added kacc == 0
1067 if( (kacc
== ope
->kacc
|| kacc
== 0) )
1071 rul
= transaction_auto_assign_eval_txn(l_rul
, ope
);
1074 if( (ope
->kpay
== 0 && (rul
->flags
& ASGF_DOPAY
)) || (rul
->flags
& ASGF_OVWPAY
) )
1076 if(ope
->kpay
!= rul
->kpay
) { changed
= TRUE
; }
1077 ope
->kpay
= rul
->kpay
;
1080 if( !(ope
->flags
& OF_SPLIT
) )
1082 if( (ope
->kcat
== 0 && (rul
->flags
& ASGF_DOCAT
)) || (rul
->flags
& ASGF_OVWCAT
) )
1084 if(ope
->kcat
!= rul
->kcat
) { changed
= TRUE
; }
1085 ope
->kcat
= rul
->kcat
;
1089 if( (ope
->paymode
== 0 && (rul
->flags
& ASGF_DOMOD
)) || (rul
->flags
& ASGF_OVWMOD
) )
1091 //ugly hack - don't allow modify intxfer
1092 if(ope
->paymode
!= PAYMODE_INTXFER
&& rul
->paymode
!= PAYMODE_INTXFER
)
1094 if(ope
->paymode
!= rul
->paymode
) { changed
= TRUE
; }
1095 ope
->paymode
= rul
->paymode
;
1101 if( ope
->flags
& OF_SPLIT
)
1103 guint i
, nbsplit
= da_splits_count(ope
->splits
);
1105 for(i
=0;i
<nbsplit
;i
++)
1107 Split
*split
= ope
->splits
[i
];
1109 DB( g_print("- eval split '%s'\n", split
->memo
) );
1111 rul
= transaction_auto_assign_eval(l_rul
, split
->memo
);
1114 //#1501144: check if user wants to set category in rule
1115 if( (split
->kcat
== 0 || (rul
->flags
& ASGF_OVWCAT
)) && (rul
->flags
& ASGF_DOCAT
) )
1117 if(split
->kcat
!= rul
->kcat
) { changed
= TRUE
; }
1118 split
->kcat
= rul
->kcat
;
1126 ope
->flags
|= OF_CHANGED
;
1131 l_ope
= g_list_next(l_ope
);
1140 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1144 transaction_tags_count(Transaction
*ope
)
1147 guint32
*ptr
= ope
->tags
;
1149 //DB( g_print("\n[transaction] tags_count\n") );
1151 if( ope
->tags
== NULL
)
1154 while(*ptr
++ != 0 && count
< 32)
1161 void transaction_tags_clone(Transaction
*src_txn
, Transaction
*dst_txn
)
1165 dst_txn
->tags
= NULL
;
1166 count
= transaction_tags_count(src_txn
);
1169 //1501962: we must also copy the final 0
1170 dst_txn
->tags
= g_memdup(src_txn
->tags
, (count
+1)*sizeof(guint32
));
1175 transaction_tags_parse(Transaction
*ope
, const gchar
*tagstring
)
1181 DB( g_print("\n[transaction] tags_parse\n") );
1183 DB( g_print(" - tagstring='%s'\n", tagstring
) );
1185 str_array
= g_strsplit (tagstring
, " ", 0);
1186 count
= g_strv_length( str_array
);
1191 DB( g_print(" -> reset storage %p\n", ope
->tags
) );
1197 ope
->tags
= g_new0(guint32
, count
+ 1);
1199 DB( g_print(" -> storage %p\n", ope
->tags
) );
1201 for(i
=0;i
<count
;i
++)
1203 tag
= da_tag_get_by_name(str_array
[i
]);
1206 Tag
*newtag
= da_tag_malloc();
1208 newtag
->name
= g_strdup(str_array
[i
]);
1209 da_tag_append(newtag
);
1210 tag
= da_tag_get_by_name(str_array
[i
]);
1213 DB( g_print(" -> storing %d=>%s at tags pos %d\n", tag
->key
, tag
->name
, i
) );
1215 ope
->tags
[i
] = tag
->key
;
1220 //hex_dump(ope->tags, sizeof(guint32*)*count+1);
1222 g_strfreev (str_array
);
1228 transaction_tags_tostring(Transaction
*ope
)
1235 DB( g_print("\n[transaction] tags_tostring\n") );
1237 DB( g_print(" -> tags at=%p\n", ope
->tags
) );
1239 if( ope
->tags
== NULL
)
1246 count
= transaction_tags_count(ope
);
1248 DB( g_print(" -> tags at=%p, nbtags=%d\n", ope
->tags
, count
) );
1250 str_array
= g_new0(gchar
*, count
+1);
1252 DB( g_print(" -> str_array at %p\n", str_array
) );
1254 //hex_dump(ope->tags, sizeof(guint32*)*(count+1));
1256 for(i
=0;i
<count
;i
++)
1258 DB( g_print(" -> try to get tag %d\n", ope
->tags
[i
]) );
1260 tag
= da_tag_get(ope
->tags
[i
]);
1263 DB( g_print(" -> get %s at %d\n", tag
->name
, i
) );
1264 str_array
[i
] = tag
->name
;
1267 str_array
[i
] = NULL
;
1272 tagstring
= g_strjoinv(" ", str_array
);