]>
Dogcows Code - chaz/homebank/blob - src/hb-filter.c
7450ca9eb217079d0cfd5253f7f63cf9b67d02d7
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/>.
21 #include "hb-filter.h"
23 /****************************************************************************/
25 /****************************************************************************/
34 /* our global datas */
35 extern struct HomeBank
*GLOBALS
;
36 extern struct Preferences
*PREFS
;
41 /* = = = = = = = = = = = = = = = = = = = = */
44 Filter
*da_filter_malloc(void)
46 return g_malloc0(sizeof(Filter
));
49 void da_filter_free(Filter
*flt
)
60 /* = = = = = = = = = = = = = = = = = = = = */
62 gchar
*filter_daterange_text_get(Filter
*flt
)
68 date
= g_date_new_julian(flt
->mindate
);
69 g_date_strftime (buffer1
, 128-1, PREFS
->date_format
, date
);
70 g_date_set_julian(date
, flt
->maxdate
);
71 g_date_strftime (buffer2
, 128-1, PREFS
->date_format
, date
);
74 return g_strdup_printf(_("<i>from</i> %s <i>to</i> %s"), buffer1
, buffer2
);
79 static void filter_default_date_set(Filter
*flt
)
81 flt
->mindate
= HB_MINDATE
;
82 flt
->maxdate
= HB_MAXDATE
;
86 static void filter_clear(Filter
*flt
)
90 for(i
=0;i
<FILTER_MAX
;i
++)
102 *flt
->last_tab
= '\0';
106 void filter_default_all_set(Filter
*flt
)
112 DB( g_print("(filter) reset %p\n", flt
) );
116 flt
->nbdaysfuture
= 0;
118 flt
->range
= FLT_RANGE_LAST12MONTHS
;
119 flt
->type
= FLT_TYPE_ALL
;
120 flt
->status
= FLT_STATUS_ALL
;
122 flt
->forceremind
= PREFS
->showremind
;
124 flt
->option
[FILTER_DATE
] = 1;
125 filter_default_date_set(flt
);
127 for(i
=0;i
<NUM_PAYMODE_MAX
;i
++)
128 flt
->paymode
[i
] = TRUE
;
130 filter_preset_daterange_set(flt
, flt
->range
, 0);
133 g_hash_table_iter_init (&iter
, GLOBALS
->h_acc
);
134 while (g_hash_table_iter_next (&iter
, &key
, &value
))
136 Account
*item
= value
;
141 g_hash_table_iter_init (&iter
, GLOBALS
->h_pay
);
142 while (g_hash_table_iter_next (&iter
, &key
, &value
))
149 g_hash_table_iter_init (&iter
, GLOBALS
->h_cat
);
150 while (g_hash_table_iter_next (&iter
, &key
, &value
))
152 Category
*item
= value
;
159 static void filter_set_date_bounds(Filter
*flt
, guint32 kacc
)
161 GList
*lst_acc
, *lnk_acc
;
164 DB( g_print("(filter) set date bounds %p\n", flt
) );
169 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
170 lnk_acc
= g_list_first(lst_acc
);
171 while (lnk_acc
!= NULL
)
173 Account
*acc
= lnk_acc
->data
;
175 //#1674045 ony rely on nosummary
176 //if( !(acc->flags & AF_CLOSED) )
180 DB( g_print(" - do '%s'\n", acc
->name
) );
182 lnk_txn
= g_queue_peek_head_link(acc
->txn_queue
);
185 if( (kacc
== 0) || (txn
->kacc
== kacc
) )
187 if( flt
->mindate
== 0 )
188 flt
->mindate
= txn
->date
;
190 flt
->mindate
= MIN(flt
->mindate
, txn
->date
);
194 lnk_txn
= g_queue_peek_tail_link(acc
->txn_queue
);
197 if( (kacc
== 0) || (txn
->kacc
== kacc
) )
199 if( flt
->maxdate
== 0 )
200 flt
->maxdate
= txn
->date
;
202 flt
->maxdate
= MAX(flt
->maxdate
, txn
->date
);
207 lnk_acc
= g_list_next(lnk_acc
);
210 if( flt
->mindate
== 0 )
211 flt
->mindate
= HB_MINDATE
;
213 if( flt
->maxdate
== 0 )
214 flt
->maxdate
= HB_MAXDATE
;
216 g_list_free(lst_acc
);
220 void filter_preset_daterange_add_futuregap(Filter
*filter
, gint nbdays
)
225 filter
->nbdaysfuture
= 0;
229 switch( filter
->range
)
231 case FLT_RANGE_THISMONTH
:
232 case FLT_RANGE_THISQUARTER
:
233 case FLT_RANGE_THISYEAR
:
234 case FLT_RANGE_LAST30DAYS
:
235 case FLT_RANGE_LAST60DAYS
:
236 case FLT_RANGE_LAST90DAYS
:
237 case FLT_RANGE_LAST12MONTHS
:
238 filter
->nbdaysfuture
= nbdays
;
245 void filter_preset_daterange_set(Filter
*flt
, gint range
, guint32 kacc
)
248 guint32 refjuliandate
, month
, year
, qnum
;
250 DB( g_print("(filter) daterange set %p %d\n", flt
, range
) );
252 //filter_default_date_set(flt);
253 filter_set_date_bounds(flt
, kacc
);
257 // by default refjuliandate is today
258 // but we adjust if to max transaction date found
260 refjuliandate
= GLOBALS
->today
;
261 /*if(flt->maxdate < refjuliandate)
262 refjuliandate = flt->maxdate;*/
264 date
= g_date_new_julian(refjuliandate
);
265 month
= g_date_get_month(date
);
266 year
= g_date_get_year(date
);
267 qnum
= ((month
- 1) / 3) + 1;
269 DB( g_print("m=%d, y=%d, qnum=%d\n", month
, year
, qnum
) );
273 case FLT_RANGE_THISMONTH
:
274 g_date_set_day(date
, 1);
275 flt
->mindate
= g_date_get_julian(date
);
276 g_date_add_days(date
, g_date_get_days_in_month(month
, year
)-1);
277 flt
->maxdate
= g_date_get_julian(date
);
280 case FLT_RANGE_LASTMONTH
:
281 g_date_set_day(date
, 1);
282 g_date_subtract_months(date
, 1);
283 flt
->mindate
= g_date_get_julian(date
);
284 month
= g_date_get_month(date
);
285 year
= g_date_get_year(date
);
286 g_date_add_days(date
, g_date_get_days_in_month(month
, year
)-1);
287 flt
->maxdate
= g_date_get_julian(date
);
290 case FLT_RANGE_THISQUARTER
:
291 g_date_set_day(date
, 1);
292 g_date_set_month(date
, (qnum
-1)*3+1);
293 flt
->mindate
= g_date_get_julian(date
);
294 g_date_add_months(date
, 3);
295 g_date_subtract_days(date
, 1);
296 flt
->maxdate
= g_date_get_julian(date
);
299 case FLT_RANGE_LASTQUARTER
:
300 g_date_set_day(date
, 1);
301 g_date_set_month(date
, (qnum
-1)*3+1);
302 g_date_subtract_months(date
, 3);
303 flt
->mindate
= g_date_get_julian(date
);
304 g_date_add_months(date
, 3);
305 g_date_subtract_days(date
, 1);
306 flt
->maxdate
= g_date_get_julian(date
);
309 case FLT_RANGE_THISYEAR
:
310 g_date_set_dmy(date
, PREFS
->fisc_year_day
, PREFS
->fisc_year_month
, year
);
311 if( refjuliandate
>= g_date_get_julian (date
))
313 flt
->mindate
= g_date_get_julian(date
);
317 g_date_set_dmy(date
, PREFS
->fisc_year_day
, PREFS
->fisc_year_month
, year
-1);
318 flt
->mindate
= g_date_get_julian(date
);
320 g_date_add_years (date
, 1);
321 g_date_subtract_days (date
, 1);
322 flt
->maxdate
= g_date_get_julian(date
);
325 case FLT_RANGE_LASTYEAR
:
326 g_date_set_dmy(date
, PREFS
->fisc_year_day
, PREFS
->fisc_year_month
, year
);
327 if( refjuliandate
>= g_date_get_julian (date
))
329 g_date_set_dmy(date
, PREFS
->fisc_year_day
, PREFS
->fisc_year_month
, year
-1);
330 flt
->mindate
= g_date_get_julian(date
);
334 g_date_set_dmy(date
, PREFS
->fisc_year_day
, PREFS
->fisc_year_month
, year
-2);
335 flt
->mindate
= g_date_get_julian(date
);
337 g_date_add_years (date
, 1);
338 g_date_subtract_days (date
, 1);
339 flt
->maxdate
= g_date_get_julian(date
);
342 case FLT_RANGE_LAST30DAYS
:
343 flt
->mindate
= refjuliandate
- 30;
344 flt
->maxdate
= refjuliandate
;
347 case FLT_RANGE_LAST60DAYS
:
348 flt
->mindate
= refjuliandate
- 60;
349 flt
->maxdate
= refjuliandate
;
352 case FLT_RANGE_LAST90DAYS
:
353 flt
->mindate
= refjuliandate
- 90;
354 flt
->maxdate
= refjuliandate
;
357 case FLT_RANGE_LAST12MONTHS
:
358 g_date_subtract_months(date
, 12);
359 flt
->mindate
= g_date_get_julian(date
);
360 flt
->maxdate
= refjuliandate
;
363 // case FLT_RANGE_OTHER:
365 // case FLT_RANGE_ALLDATE:
373 void filter_preset_type_set(Filter
*flt
, gint type
)
378 flt
->option
[FILTER_AMOUNT
] = 0;
379 flt
->minamount
= G_MINDOUBLE
;
380 flt
->maxamount
= G_MINDOUBLE
;
384 case FLT_TYPE_EXPENSE
:
385 flt
->option
[FILTER_AMOUNT
] = 1;
386 flt
->minamount
= -G_MAXDOUBLE
;
387 flt
->maxamount
= G_MINDOUBLE
;
390 case FLT_TYPE_INCOME
:
391 flt
->option
[FILTER_AMOUNT
] = 1;
392 flt
->minamount
= G_MINDOUBLE
;
393 flt
->maxamount
= G_MAXDOUBLE
;
400 void filter_preset_status_set(Filter
*flt
, gint status
)
406 flt
->status
= status
;
407 flt
->option
[FILTER_STATUS
] = 0;
408 flt
->reconciled
= TRUE
;
410 //#1602835 fautly set
411 //flt->forceadd = TRUE;
412 //flt->forcechg = TRUE;
414 flt
->option
[FILTER_CATEGORY
] = 0;
415 lcat
= list
= g_hash_table_get_values(GLOBALS
->h_cat
);
418 catitem
= list
->data
;
419 catitem
->filter
= FALSE
;
420 list
= g_list_next(list
);
426 case FLT_STATUS_UNCATEGORIZED
:
427 flt
->option
[FILTER_CATEGORY
] = 1;
428 catitem
= da_cat_get(0); // no category
430 catitem
->filter
= TRUE
;
433 case FLT_STATUS_UNRECONCILED
:
434 flt
->option
[FILTER_STATUS
] = 2;
435 flt
->reconciled
= TRUE
;
436 flt
->cleared
= FALSE
;
439 case FLT_STATUS_UNCLEARED
:
440 flt
->option
[FILTER_STATUS
] = 2;
441 flt
->reconciled
= FALSE
;
445 case FLT_STATUS_RECONCILED
:
446 flt
->option
[FILTER_STATUS
] = 1;
447 flt
->reconciled
= TRUE
;
448 flt
->cleared
= FALSE
;
451 case FLT_STATUS_CLEARED
:
452 flt
->option
[FILTER_STATUS
] = 1;
453 flt
->reconciled
= FALSE
;
461 static gint
filter_text_compare(gchar
*txntext
, gchar
*searchtext
, gboolean exact
)
467 if( g_strstr_len(txntext
, -1, searchtext
) != NULL
)
469 DB( g_print(" found case '%s'\n", searchtext
) );
475 gchar
*word
= g_utf8_casefold(txntext
, -1);
476 gchar
*needle
= g_utf8_casefold(searchtext
, -1);
478 if( g_strrstr(word
, needle
) != NULL
)
480 DB( g_print(" found nocase '%s'\n", needle
) );
491 /* used for quicksearch text into transaction */
492 gboolean
filter_txn_search_match(gchar
*needle
, Transaction
*txn
, gint flags
)
494 gboolean retval
= FALSE
;
499 if(flags
& FLT_QSEARCH_MEMO
)
501 //#1668036 always try match on txn memo first
504 retval
|= filter_text_compare(txn
->memo
, needle
, FALSE
);
509 if(txn
->flags
& OF_SPLIT
)
514 count
= da_splits_count(txn
->splits
);
519 split
= txn
->splits
[i
];
520 tmpinsert
= filter_text_compare(split
->memo
, needle
, FALSE
);
529 if(flags
& FLT_QSEARCH_INFO
)
533 retval
|= filter_text_compare(txn
->info
, needle
, FALSE
);
538 if(flags
& FLT_QSEARCH_PAYEE
)
540 payitem
= da_pay_get(txn
->kpay
);
543 retval
|= filter_text_compare(payitem
->name
, needle
, FALSE
);
548 if(flags
& FLT_QSEARCH_CATEGORY
)
551 if(txn
->flags
& OF_SPLIT
)
556 count
= da_splits_count(txn
->splits
);
561 split
= txn
->splits
[i
];
562 catitem
= da_cat_get(split
->kcat
);
565 gchar
*fullname
= da_cat_get_fullname (catitem
);
567 tmpinsert
= filter_text_compare(fullname
, needle
, FALSE
);
578 catitem
= da_cat_get(txn
->kcat
);
581 gchar
*fullname
= da_cat_get_fullname (catitem
);
583 retval
|= filter_text_compare(fullname
, needle
, FALSE
);
590 if(flags
& FLT_QSEARCH_TAGS
)
592 tags
= transaction_tags_tostring(txn
);
595 retval
|= filter_text_compare(tags
, needle
, FALSE
);
601 //#1741339 add quicksearch for amount
602 if(flags
& FLT_QSEARCH_AMOUNT
)
604 gchar formatd_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
606 hb_strfnum(formatd_buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, txn
->amount
, txn
->kcur
, FALSE
);
607 retval
|= filter_text_compare(formatd_buf
, needle
, FALSE
);
616 gint
filter_test(Filter
*flt
, Transaction
*txn
)
623 //DB( g_print("(filter) test\n") );
627 /*** start filtering ***/
630 if(flt
->forceadd
== TRUE
&& (txn
->flags
& OF_ADDED
))
633 if(flt
->forcechg
== TRUE
&& (txn
->flags
& OF_CHANGED
))
636 /* force remind if not filter on status */
637 if(flt
->forceremind
== TRUE
&& (txn
->status
== TXN_STATUS_REMIND
))
641 if(flt
->option
[FILTER_DATE
]) {
642 insert
= ( (txn
->date
>= flt
->mindate
) && (txn
->date
<= (flt
->maxdate
+ flt
->nbdaysfuture
) ) ) ? 1 : 0;
643 if(flt
->option
[FILTER_DATE
] == 2) insert
^= 1;
645 if(!insert
) goto end
;
648 if(flt
->option
[FILTER_ACCOUNT
]) {
649 accitem
= da_acc_get(txn
->kacc
);
652 insert
= ( accitem
->filter
== TRUE
) ? 1 : 0;
653 if(flt
->option
[FILTER_ACCOUNT
] == 2) insert
^= 1;
656 if(!insert
) goto end
;
659 if(flt
->option
[FILTER_PAYEE
]) {
660 payitem
= da_pay_get(txn
->kpay
);
663 insert
= ( payitem
->filter
== TRUE
) ? 1 : 0;
664 if(flt
->option
[FILTER_PAYEE
] == 2) insert
^= 1;
667 if(!insert
) goto end
;
670 if(flt
->option
[FILTER_CATEGORY
]) {
671 if(txn
->flags
& OF_SPLIT
)
676 insert
= 0; //fix: 1151259
677 count
= da_splits_count(txn
->splits
);
682 split
= txn
->splits
[i
];
683 catitem
= da_cat_get(split
->kcat
);
686 tmpinsert
= ( catitem
->filter
== TRUE
) ? 1 : 0;
687 if(flt
->option
[FILTER_CATEGORY
] == 2) tmpinsert
^= 1;
694 catitem
= da_cat_get(txn
->kcat
);
697 insert
= ( catitem
->filter
== TRUE
) ? 1 : 0;
698 if(flt
->option
[FILTER_CATEGORY
] == 2) insert
^= 1;
702 if(!insert
) goto end
;
705 if(flt
->option
[FILTER_STATUS
]) {
706 gint insert1
= 0, insert2
= 0;
709 insert1
= ( txn
->status
== TXN_STATUS_RECONCILED
) ? 1 : 0;
711 insert2
= ( txn
->status
== TXN_STATUS_CLEARED
) ? 1 : 0;
713 insert
= insert1
| insert2
;
714 if(flt
->option
[FILTER_STATUS
] == 2) insert
^= 1;
716 if(!insert
) goto end
;
719 if(flt
->option
[FILTER_PAYMODE
]) {
720 insert
= ( flt
->paymode
[txn
->paymode
] == TRUE
) ? 1 : 0;
721 if(flt
->option
[FILTER_PAYMODE
] == 2) insert
^= 1;
723 if(!insert
) goto end
;
726 if(flt
->option
[FILTER_AMOUNT
]) {
727 insert
= ( (txn
->amount
>= flt
->minamount
) && (txn
->amount
<= flt
->maxamount
) ) ? 1 : 0;
729 if(flt
->option
[FILTER_AMOUNT
] == 2) insert
^= 1;
731 if(!insert
) goto end
;
734 if(flt
->option
[FILTER_TEXT
])
737 gint insert1
, insert2
, insert3
;
739 insert1
= insert2
= insert3
= 0;
744 insert1
= filter_text_compare(txn
->info
, flt
->info
, flt
->exact
);
752 //#1668036 always try match on txn memo first
755 insert2
= filter_text_compare(txn
->memo
, flt
->memo
, flt
->exact
);
758 if( (insert2
== 0) && (txn
->flags
& OF_SPLIT
) )
763 count
= da_splits_count(txn
->splits
);
768 split
= txn
->splits
[i
];
769 tmpinsert
= filter_text_compare(split
->memo
, flt
->memo
, flt
->exact
);
770 insert2
|= tmpinsert
;
781 tags
= transaction_tags_tostring(txn
);
784 insert3
= filter_text_compare(tags
, flt
->tag
, flt
->exact
);
791 insert
= insert1
&& insert2
&& insert3
? 1 : 0;
793 if(flt
->option
[FILTER_TEXT
] == 2) insert
^= 1;
796 if(!insert
) goto end
;
799 // DB( g_print(" %d :: %d :: %d\n", flt->mindate, txn->date, flt->maxdate) );
800 // DB( g_print(" [%d] %s => %d (%d)\n", txn->account, txn->memo, insert, count) );
This page took 0.073361 seconds and 3 git commands to generate.