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