1 /*
2 * Copyright 2003-2019 Thomas Baumgart <tbaumgart@kde.org>
3 * Copyright 2004 Ace Jones <acejones@users.sourceforge.net>
4 * Copyright 2008-2010 Alvaro Soliverez <asoliverez@gmail.com>
5 * Copyright 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifndef MYMONEYTRANSACTIONFILTER_H
22 #define MYMONEYTRANSACTIONFILTER_H
23
24 #include "kmm_mymoney_export.h"
25
26 // ----------------------------------------------------------------------------
27 // QT Includes
28
29 #include <QMetaType>
30
31 // ----------------------------------------------------------------------------
32 // KDE Includes
33
34 // ----------------------------------------------------------------------------
35 // Project Includes
36
37 class QString;
38 class QDate;
39
40 template <typename T> class QList;
41
42 class MyMoneyMoney;
43 class MyMoneySplit;
44 class MyMoneyAccount;
45
46 namespace eMyMoney { namespace TransactionFilter { enum class Date;
47 enum class Validity; } }
48
49 /**
50 * @author Thomas Baumgart
51 * @author Łukasz Wojniłowicz
52 */
53
54 class MyMoneyTransaction;
55 class MyMoneyTransactionFilterPrivate;
56 class KMM_MYMONEY_EXPORT MyMoneyTransactionFilter
57 {
Q_DECLARE_PRIVATE(MyMoneyTransactionFilter)58 Q_DECLARE_PRIVATE(MyMoneyTransactionFilter)
59
60 protected:
61 MyMoneyTransactionFilterPrivate* d_ptr; // name shouldn't colide with the one in mymoneyreport.h
62
63 public:
64 enum FilterFlags {
65 textFilterActive = 0x0001,
66 accountFilterActive = 0x0002,
67 payeeFilterActive = 0x0004,
68 tagFilterActive = 0x0008,
69 categoryFilterActive = 0x0010,
70 nrFilterActive = 0x0020,
71 dateFilterActive = 0x0040,
72 amountFilterActive = 0x0080,
73 typeFilterActive = 0x0100,
74 stateFilterActive = 0x0200,
75 validityFilterActive = 0x0400
76 };
77 Q_DECLARE_FLAGS(FilterSet, FilterFlags)
78
79 /**
80 * This is the standard constructor for a transaction filter.
81 * It creates the object and calls setReportAllSplits() to
82 * report all matching splits as separate entries. Use
83 * setReportAllSplits() to override this behaviour.
84 */
85 MyMoneyTransactionFilter();
86
87 /**
88 * This is a convenience constructor to allow construction of
89 * a simple account filter. It is basically the same as the
90 * following:
91 *
92 * @code
93 * :
94 * MyMoneyTransactionFilter filter;
95 * filter.setReportAllSplits(false);
96 * filter.addAccount(id);
97 * :
98 * @endcode
99 *
100 * @param id reference to account id
101 */
102 explicit MyMoneyTransactionFilter(const QString& id);
103
104 MyMoneyTransactionFilter(const MyMoneyTransactionFilter & other);
105 MyMoneyTransactionFilter(MyMoneyTransactionFilter && other);
106 MyMoneyTransactionFilter & operator=(MyMoneyTransactionFilter other);
107 friend void swap(MyMoneyTransactionFilter& first, MyMoneyTransactionFilter& second);
108
109 virtual ~MyMoneyTransactionFilter();
110
111 /**
112 * This method is used to clear the filter. All settings will be
113 * removed.
114 */
115 void clear();
116
117 /**
118 * This method is used to clear the accounts filter only.
119 */
120 void clearAccountFilter();
121
122 /**
123 * This method is used to set the regular expression filter to the value specified
124 * as parameter @p exp. The following text based fields are searched:
125 *
126 * - Memo
127 * - Payee
128 * - Tag
129 * - Category
130 * - Shares / Value
131 * - Number
132 *
133 * @param exp The regular expression that must be found in a transaction
134 * before it is included in the result set.
135 * @param invert If true, value must not be contained in any of the above mentioned fields
136 *
137 */
138 void setTextFilter(const QRegExp& exp, bool invert = false);
139
140 /**
141 * This method will add the account with id @p id to the list of matching accounts.
142 * If the list is empty, any transaction will match.
143 *
144 * @param id internal ID of the account
145 */
146 void addAccount(const QString& id);
147
148 /**
149 * This is a convenience method and behaves exactly like the above
150 * method but for a list of id's.
151 */
152 void addAccount(const QStringList& ids);
153
154 /**
155 * This method will add the category with id @p id to the list of matching categories.
156 * If the list is empty, only transaction with a single asset/liability account will match.
157 *
158 * @param id internal ID of the account
159 */
160 void addCategory(const QString& id);
161
162 /**
163 * This is a convenience method and behaves exactly like the above
164 * method but for a list of id's.
165 */
166 void addCategory(const QStringList& ids);
167
168 /**
169 * This method sets the date filter to match only transactions with posting dates in
170 * the date range specified by @p from and @p to. If @p from equal QDate()
171 * all transactions with dates prior to @p to match. If @p to equals QDate()
172 * all transactions with posting dates past @p from match. If @p from and @p to
173 * are equal QDate() the filter is not activated and all transactions match.
174 *
175 * @param from from date
176 * @param to to date
177 */
178 void setDateFilter(const QDate& from, const QDate& to);
179
180 void setDateFilter(eMyMoney::TransactionFilter::Date range);
181
182 /**
183 * This method sets the amount filter to match only transactions with
184 * an amount in the range specified by @p from and @p to.
185 * If a specific amount should be searched, @p from and @p to should be
186 * the same value.
187 *
188 * @param from smallest value to match
189 * @param to largest value to match
190 */
191 void setAmountFilter(const MyMoneyMoney& from, const MyMoneyMoney& to);
192
193 /**
194 * This method will add the payee with id @p id to the list of matching payees.
195 * If the list is empty, any transaction will match.
196 *
197 * @param id internal id of the payee
198 */
199 void addPayee(const QString& id);
200
201 /**
202 * This method will add the tag with id @ta id to the list of matching tags.
203 * If the list is empty, any transaction will match.
204 *
205 * @param id internal id of the tag
206 */
207 void addTag(const QString& id);
208
209 /**
210 */
211 void addType(const int type);
212
213 /**
214 */
215 void addValidity(const int type);
216
217 /**
218 */
219 void addState(const int state);
220
221 /**
222 * This method sets the number filter to match only transactions with
223 * a number in the range specified by @p from and @p to.
224 * If a specific number should be searched, @p from and @p to should be
225 * the same value.
226 *
227 * @param from smallest value to match
228 * @param to largest value to match
229 *
230 * @note @p from and @p to can contain alphanumeric text
231 */
232 void setNumberFilter(const QString& from, const QString& to);
233
234 /**
235 * This method is used to check a specific transaction against the filter.
236 * The transaction will match the whole filter, if all specified filters
237 * match. If the filter is cleared using the clear() method, any transaction
238 * matches. Matching splits from the transaction are returned by @ref
239 * matchingSplits().
240 *
241 * @param transaction A transaction
242 *
243 * @retval true The transaction matches the filter set
244 * @retval false The transaction does not match at least one of
245 * the filters in the filter set
246 */
247 bool match(const MyMoneyTransaction& transaction);
248
249 /**
250 * This method is used to check a specific split against the
251 * text filter. The split will match if all specified and
252 * checked filters match. If the filter is cleared using the clear()
253 * method, any split matches.
254 *
255 * @param sp pointer to the split to be checked
256 *
257 * @retval true The split matches the filter set
258 * @retval false The split does not match at least one of
259 * the filters in the filter set
260 */
261 bool matchText(const MyMoneySplit& s, const MyMoneyAccount &acc) const;
262
263 /**
264 * This method is used to check a specific split against the
265 * amount filter. The split will match if all specified and
266 * checked filters match. If the filter is cleared using the clear()
267 * method, any split matches.
268 *
269 * @param sp const reference to the split to be checked
270 *
271 * @retval true The split matches the filter set
272 * @retval false The split does not match at least one of
273 * the filters in the filter set
274 */
275 bool matchAmount(const MyMoneySplit& s) const;
276
277 /**
278 * Convenience method which actually returns matchText(sp) && matchAmount(sp).
279 */
280 bool match(const MyMoneySplit& s) const;
281
282 /**
283 * This method is used to switch the amount of splits reported
284 * by matchingSplits(). If the argument @p report is @p true (the default
285 * if no argument specified) then matchingSplits() will return all
286 * matching splits of the transaction. If @p report is set to @p false,
287 * then only the very first matching split will be returned by
288 * matchingSplits().
289 *
290 * @param report controls the behaviour of matchingsSplits() as explained above.
291 */
292 void setReportAllSplits(const bool report = true);
293
294 /**
295 * Consider splits in categories
296 *
297 * With this setting, splits in categories that are not considered
298 * by default are taken into account.
299 *
300 * @param check check state
301 */
302 void setConsiderCategorySplits(const bool check = true);
303
304 /**
305 * Consider income and expense categories
306 *
307 * If the account or category filter is enabled, categories of
308 * income and expense type are included if enabled with this
309 * method.
310 *
311 * @param check check state
312 */
313 void setConsiderCategory(const bool check = true);
314
315 void setTreatTransfersAsIncomeExpense(const bool check = true);
316
317 /**
318 * This method is to avoid returning matching splits list
319 * if only its count is needed
320 * @return count of matching splits
321 */
322 uint matchingSplitsCount(const MyMoneyTransaction& transaction);
323
324 /**
325 * This method returns a list of the matching splits for the filter.
326 * If m_reportAllSplits is set to false, then only the very first
327 * split will be returned. Use setReportAllSplits() to change the
328 * behaviour.
329 *
330 * @return reference list of MyMoneySplit objects containing the
331 * matching splits. If multiple splits match, only the first
332 * one will be returned.
333 *
334 * @note an empty list will be returned, if the filter only required
335 * to check the data contained in the MyMoneyTransaction
336 * object (e.g. posting-date, state, etc.).
337 *
338 * @note The constructors set m_reportAllSplits differently. Please
339 * see the documentation of the constructors MyMoneyTransactionFilter()
340 * and MyMoneyTransactionFilter(const QString&) for details.
341 */
342 QVector<MyMoneySplit> matchingSplits(const MyMoneyTransaction& transaction);
343
344 /**
345 * This method returns the from date set in the filter. If
346 * no value has been set up for this filter, then QDate() is
347 * returned.
348 *
349 * @return returns m_fromDate
350 */
351 QDate fromDate() const;
352
353 /**
354 * This method returns the to date set in the filter. If
355 * no value has been set up for this filter, then QDate() is
356 * returned.
357 *
358 * @return returns m_toDate
359 */
360 QDate toDate() const;
361
362 /**
363 * This method is used to return information about the
364 * presence of a specific category in the category filter.
365 * The category in question is included in the filter set,
366 * if it has been set or no category filter is set.
367 *
368 * @param cat id of category in question
369 * @return true if category is in filter set, false otherwise
370 */
371 bool includesCategory(const QString& cat) const;
372
373 /**
374 * This method is used to return information about the
375 * presence of a specific account in the account filter.
376 * The account in question is included in the filter set,
377 * if it has been set or no account filter is set.
378 *
379 * @param acc id of account in question
380 * @return true if account is in filter set, false otherwise
381 */
382 bool includesAccount(const QString& acc) const;
383
384 /**
385 * This method is used to return information about the
386 * presence of a specific payee in the account filter.
387 * The payee in question is included in the filter set,
388 * if it has been set or no account filter is set.
389 *
390 * @param pye id of payee in question
391 * @return true if payee is in filter set, false otherwise
392 */
393 bool includesPayee(const QString& pye) const;
394
395 /**
396 * This method is used to return information about the
397 * presence of a specific tag in the account filter.
398 * The tag in question is included in the filter set,
399 * if it has been set or no account filter is set.
400 *
401 * @param tag id of tag in question
402 * @return true if tag is in filter set, false otherwise
403 */
404 bool includesTag(const QString& tag) const;
405
406 /**
407 * This method is used to return information about the
408 * presence of a date filter.
409 *
410 * @param from result value for the beginning of the date range
411 * @param to result value for the end of the date range
412 * @return true if a date filter is set
413 */
414 bool dateFilter(QDate& from, QDate& to) const;
415
416 /**
417 * This method is used to return information about the
418 * presence of an amount filter.
419 *
420 * @param from result value for the low end of the amount range
421 * @param to result value for the high end of the amount range
422 * @return true if an amount filter is set
423 */
424 bool amountFilter(MyMoneyMoney& from, MyMoneyMoney& to) const;
425
426 /**
427 * This method is used to return information about the
428 * presence of an number filter.
429 *
430 * @param from result value for the low end of the number range
431 * @param to result value for the high end of the number range
432 * @return true if a number filter is set
433 */
434 bool numberFilter(QString& from, QString& to) const;
435
436 /**
437 * This method returns whether a payee filter has been set,
438 * and if so, it returns all the payees set in the filter.
439 *
440 * @param list list to append payees into
441 * @return return true if a payee filter has been set
442 */
443 bool payees(QStringList& list) const;
444
445 /**
446 * This method returns whether a tag filter has been set,
447 * and if so, it returns all the tags set in the filter.
448 *
449 * @param list list to append tags into
450 * @return return true if a tag filter has been set
451 */
452 bool tags(QStringList& list) const;
453
454 /**
455 * This method returns whether an account filter has been set,
456 * and if so, it returns all the accounts set in the filter.
457 *
458 * @param list list to append accounts into
459 * @return return true if an account filter has been set
460 */
461 bool accounts(QStringList& list) const;
462
463 /**
464 * This method returns whether a category filter has been set,
465 * and if so, it returns all the categories set in the filter.
466 *
467 * @param list list to append categories into
468 * @return return true if a category filter has been set
469 */
470 bool categories(QStringList& list) const;
471
472 /**
473 * This method returns whether a type filter has been set,
474 * and if so, it returns the first type in the filter.
475 *
476 * @param i int to replace with first type filter, untouched otherwise
477 * @return return true if a type filter has been set
478 */
479 bool firstType(int& i) const;
480
481 bool types(QList<int>& list) const;
482
483 /**
484 * This method returns whether a state filter has been set,
485 * and if so, it returns the first state in the filter.
486 *
487 * @param i reference to int to replace with first state filter, untouched otherwise
488 * @return return true if a state filter has been set
489 */
490 bool firstState(int& i) const;
491
492 bool states(QList<int>& list) const;
493
494 /**
495 * This method returns whether a validity filter has been set,
496 * and if so, it returns the first validity in the filter.
497 *
498 * @param i reference to int to replace with first validity filter, untouched otherwise
499 * @return return true if a validity filter has been set
500 */
501 bool firstValidity(int& i) const;
502
503 bool validities(QList<int>& list) const;
504
505 /**
506 * This method returns whether a text filter has been set,
507 * and if so, it returns the text filter.
508 *
509 * @param text regexp to replace with text filter, or blank if none set
510 * @return return true if a text filter has been set
511 */
512 bool textFilter(QRegExp& text) const;
513
514 /**
515 * This method returns whether the text filter should return
516 * that DO NOT contain the text
517 */
518 bool isInvertingText() const;
519
520 /**
521 * This method returns whether transfers should be treated as
522 * income/expense transactions or not
523 */
524 bool treatTransfersAsIncomeExpense() const;
525
526 /**
527 * This method translates a plain-language date range into QDate
528 * start & end
529 *
530 * @param range Plain-language range of dates, e.g. 'CurrentYear'
531 * @param start QDate will be set to corresponding to the first date in @p range
532 * @param end QDate will be set to corresponding to the last date in @p range
533 * @return return true if a range was successfully set, or false if @p range was invalid
534 */
535 static bool translateDateRange(eMyMoney::TransactionFilter::Date range, QDate& start, QDate& end);
536
537 static void setFiscalYearStart(int firstMonth, int firstDay);
538
539 FilterSet filterSet() const;
540
541 /**
542 * This member removes all references to object identified by @p id. Used
543 * to remove objects which are about to be removed from the engine.
544 */
545 void removeReference(const QString& id);
546
547 private:
548 /**
549 * This is a conversion tool from eMyMoney::Split::State
550 * to MyMoneyTransactionFilter::stateE types
551 *
552 * @param split reference to split in question
553 *
554 * @return converted reconcile flag of the split passed as parameter
555 */
556 int splitState(const MyMoneySplit& split) const;
557
558 /**
559 * This is a conversion tool from MyMoneySplit::action
560 * to MyMoneyTransactionFilter::typeE types
561 *
562 * @param t reference to transaction
563 * @param split reference to split in question
564 *
565 * @return converted action of the split passed as parameter
566 */
567 int splitType(const MyMoneyTransaction& t, const MyMoneySplit& split, const MyMoneyAccount &acc) const;
568
569 /**
570 * This method checks if a transaction is valid or not. A transaction
571 * is considered valid, if the sum of all splits is zero, invalid otherwise.
572 *
573 * @param transaction reference to transaction to be checked
574 * @retval valid transaction is valid
575 * @retval invalid transaction is invalid
576 */
577 eMyMoney::TransactionFilter::Validity validTransaction(const MyMoneyTransaction& transaction) const;
578 };
579
swap(MyMoneyTransactionFilter & first,MyMoneyTransactionFilter & second)580 inline void swap(MyMoneyTransactionFilter& first, MyMoneyTransactionFilter& second) // krazy:exclude=inline
581 {
582 using std::swap;
583 swap(first.d_ptr, second.d_ptr);
584 }
585
MyMoneyTransactionFilter(MyMoneyTransactionFilter && other)586 inline MyMoneyTransactionFilter::MyMoneyTransactionFilter(MyMoneyTransactionFilter && other) : MyMoneyTransactionFilter() // krazy:exclude=inline
587 {
588 swap(*this, other);
589 }
590
591 inline MyMoneyTransactionFilter & MyMoneyTransactionFilter::operator=(MyMoneyTransactionFilter other) // krazy:exclude=inline
592 {
593 swap(*this, other);
594 return *this;
595 }
596
597 /**
598 * Make it possible to hold @ref MyMoneyTransactionFilter objects inside @ref QVariant objects.
599 */
600 Q_DECLARE_METATYPE(MyMoneyTransactionFilter)
601 Q_DECLARE_OPERATORS_FOR_FLAGS(MyMoneyTransactionFilter::FilterSet)
602
603 #endif
604