File indexing completed on 2024-05-12 16:42:43

0001 /*
0002     SPDX-FileCopyrightText: 2003-2019 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-FileCopyrightText: 2004 Ace Jones <acejones@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2008-2010 Alvaro Soliverez <asoliverez@gmail.com>
0005     SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #ifndef MYMONEYTRANSACTIONFILTER_H
0010 #define MYMONEYTRANSACTIONFILTER_H
0011 
0012 #include "kmm_mymoney_export.h"
0013 
0014 // ----------------------------------------------------------------------------
0015 // QT Includes
0016 
0017 #include <QMetaType>
0018 
0019 // ----------------------------------------------------------------------------
0020 // KDE Includes
0021 
0022 // ----------------------------------------------------------------------------
0023 // Project Includes
0024 
0025 class QString;
0026 class QDate;
0027 
0028 template <typename T> class QList;
0029 
0030 class MyMoneyMoney;
0031 class MyMoneySplit;
0032 class MyMoneyAccount;
0033 
0034 namespace eMyMoney {
0035 namespace TransactionFilter {
0036 enum class Date;
0037 enum class Validity;
0038 }
0039 }
0040 
0041 /**
0042   * @author Thomas Baumgart
0043   * @author Łukasz Wojniłowicz
0044   */
0045 
0046 class MyMoneyTransaction;
0047 class MyMoneyTransactionFilterPrivate;
0048 class KMM_MYMONEY_EXPORT MyMoneyTransactionFilter
0049 {
0050     Q_DECLARE_PRIVATE(MyMoneyTransactionFilter)
0051 
0052 protected:
0053     MyMoneyTransactionFilterPrivate* d_ptr;  // name shouldn't colide with the one in mymoneyreport.h
0054 
0055 public:
0056     enum FilterFlags {
0057         textFilterActive     = 0x0001,
0058         accountFilterActive  = 0x0002,
0059         payeeFilterActive    = 0x0004,
0060         tagFilterActive      = 0x0008,
0061         categoryFilterActive = 0x0010,
0062         nrFilterActive       = 0x0020,
0063         dateFilterActive     = 0x0040,
0064         amountFilterActive   = 0x0080,
0065         typeFilterActive     = 0x0100,
0066         stateFilterActive    = 0x0200,
0067         validityFilterActive = 0x0400
0068     };
0069     Q_DECLARE_FLAGS(FilterSet, FilterFlags)
0070 
0071     /**
0072       * This is the standard constructor for a transaction filter.
0073       * It creates the object and calls setReportAllSplits() to
0074       * report all matching splits as separate entries. Use
0075       * setReportAllSplits() to override this behaviour.
0076       */
0077     MyMoneyTransactionFilter();
0078 
0079     /**
0080       * This is a convenience constructor to allow construction of
0081       * a simple account filter. It is basically the same as the
0082       * following:
0083       *
0084       * @code
0085       * :
0086       *   MyMoneyTransactionFilter filter;
0087       *   filter.setReportAllSplits(false);
0088       *   filter.addAccount(id);
0089       * :
0090       * @endcode
0091       *
0092       * @param id reference to account id
0093       */
0094     explicit MyMoneyTransactionFilter(const QString& id);
0095 
0096     MyMoneyTransactionFilter(const MyMoneyTransactionFilter & other);
0097     MyMoneyTransactionFilter(MyMoneyTransactionFilter && other);
0098     MyMoneyTransactionFilter & operator=(MyMoneyTransactionFilter other);
0099     friend void swap(MyMoneyTransactionFilter& first, MyMoneyTransactionFilter& second);
0100 
0101     virtual ~MyMoneyTransactionFilter();
0102 
0103     /**
0104       * This method is used to clear the filter. All settings will be
0105       * removed.
0106       */
0107     void clear();
0108 
0109     /**
0110       * This method is used to clear the accounts filter only.
0111       */
0112     void clearAccountFilter();
0113 
0114     /**
0115       * This method is used to set the regular expression filter to the value specified
0116       * as parameter @p exp. The following text based fields are searched:
0117       *
0118       * - Memo
0119       * - Payee
0120       * - Tag
0121       * - Category
0122       * - Shares / Value
0123       * - Number
0124       *
0125       * @param exp The regular expression that must be found in a transaction
0126       *            before it is included in the result set.
0127       * @param invert If true, value must not be contained in any of the above mentioned fields
0128       *
0129       */
0130     void setTextFilter(const QRegExp& exp, bool invert = false);
0131 
0132     /**
0133       * This method will add the account with id @p id to the list of matching accounts.
0134       * If the list is empty, any transaction will match.
0135       *
0136       * @param id internal ID of the account
0137       */
0138     void addAccount(const QString& id);
0139 
0140     /**
0141       * This is a convenience method and behaves exactly like the above
0142       * method but for a list of id's.
0143       */
0144     void addAccount(const QStringList& ids);
0145 
0146     /**
0147       * This method will add the category with id @p id to the list of matching categories.
0148       * If the list is empty, only transaction with a single asset/liability account will match.
0149       *
0150       * @param id internal ID of the account
0151       */
0152     void addCategory(const QString& id);
0153 
0154     /**
0155       * This is a convenience method and behaves exactly like the above
0156       * method but for a list of id's.
0157       */
0158     void addCategory(const QStringList& ids);
0159 
0160     /**
0161       * This method sets the date filter to match only transactions with posting dates in
0162       * the date range specified by @p from and @p to. If @p from equal QDate()
0163       * all transactions with dates prior to @p to match. If @p to equals QDate()
0164       * all transactions with posting dates past @p from match. If @p from and @p to
0165       * are equal QDate() the filter is not activated and all transactions match.
0166       *
0167       * @param from from date
0168       * @param to   to date
0169       */
0170     void setDateFilter(const QDate& from, const QDate& to);
0171 
0172     void setDateFilter(eMyMoney::TransactionFilter::Date range);
0173 
0174     /**
0175       * This method sets the amount filter to match only transactions with
0176       * an amount in the range specified by @p from and @p to.
0177       * If a specific amount should be searched, @p from and @p to should be
0178       * the same value.
0179       *
0180       * @param from smallest value to match
0181       * @param to   largest value to match
0182       */
0183     void setAmountFilter(const MyMoneyMoney& from, const MyMoneyMoney& to);
0184 
0185     /**
0186       * This method will add the payee with id @p id to the list of matching payees.
0187       * If the list is empty, any transaction will match.
0188       *
0189       * @param id internal id of the payee
0190       */
0191     void addPayee(const QString& id);
0192 
0193     /**
0194       * This method will add the tag with id @ta id to the list of matching tags.
0195       * If the list is empty, any transaction will match.
0196       *
0197       * @param id internal id of the tag
0198       */
0199     void addTag(const QString& id);
0200 
0201     /**
0202       */
0203     void addType(const int type);
0204 
0205     /**
0206       */
0207     void addValidity(const int type);
0208 
0209     /**
0210       */
0211     void addState(const int state);
0212 
0213     /**
0214       * This method sets the number filter to match only transactions with
0215       * a number in the range specified by @p from and @p to.
0216       * If a specific number should be searched, @p from and @p to should be
0217       * the same value.
0218       *
0219       * @param from smallest value to match
0220       * @param to   largest value to match
0221       *
0222       * @note @p from and @p to can contain alphanumeric text
0223       */
0224     void setNumberFilter(const QString& from, const QString& to);
0225 
0226     /**
0227       * This method is used to check a specific transaction against the filter.
0228       * The transaction will match the whole filter, if all specified filters
0229       * match. If the filter is cleared using the clear() method, any transaction
0230       * matches. Matching splits from the transaction are returned by @ref
0231       * matchingSplits().
0232       *
0233       * @param transaction A transaction
0234       *
0235       * @retval true The transaction matches the filter set
0236       * @retval false The transaction does not match at least one of
0237       *               the filters in the filter set
0238       */
0239     bool match(const MyMoneyTransaction& transaction);
0240 
0241     /**
0242       * This method is used to check a specific split against the
0243       * text filter. The split will match if all specified and
0244       * checked filters match. If the filter is cleared using the clear()
0245       * method, any split matches.
0246       *
0247       * @param sp pointer to the split to be checked
0248       *
0249       * @retval true The split matches the filter set
0250       * @retval false The split does not match at least one of
0251       *               the filters in the filter set
0252       */
0253     bool matchText(const MyMoneySplit& s, const MyMoneyAccount &acc) const;
0254 
0255     /**
0256       * This method is used to check a specific split against the
0257       * amount filter. The split will match if all specified and
0258       * checked filters match. If the filter is cleared using the clear()
0259       * method, any split matches.
0260       *
0261       * @param sp const reference to the split to be checked
0262       *
0263       * @retval true The split matches the filter set
0264       * @retval false The split does not match at least one of
0265       *               the filters in the filter set
0266       */
0267     bool matchAmount(const MyMoneySplit& s) const;
0268 
0269     /**
0270      * Convenience method which actually returns matchText(sp) && matchAmount(sp).
0271      */
0272     bool match(const MyMoneySplit& s) const;
0273 
0274     /**
0275       * This method is used to switch the amount of splits reported
0276       * by matchingSplits(). If the argument @p report is @p true (the default
0277       * if no argument specified) then matchingSplits() will return all
0278       * matching splits of the transaction. If @p report is set to @p false,
0279       * then only the very first matching split will be returned by
0280       * matchingSplits().
0281       *
0282       * @param report controls the behaviour of matchingsSplits() as explained above.
0283       */
0284     void setReportAllSplits(const bool report = true);
0285 
0286     /**
0287      * Consider splits in categories
0288      *
0289      * With this setting, splits in categories that are not considered
0290      * by default are taken into account.
0291      *
0292      * @param check check state
0293      */
0294     void setConsiderCategorySplits(const bool check = true);
0295 
0296     /**
0297      * Consider income and expense categories
0298      *
0299      * If the account or category filter is enabled, categories of
0300      * income and expense type are included if enabled with this
0301      * method.
0302      *
0303      * @param check check state
0304      */
0305     void setConsiderCategory(const bool check = true);
0306 
0307     void setTreatTransfersAsIncomeExpense(const bool check = true);
0308 
0309     /**
0310      * This method is to avoid returning matching splits list
0311      * if only its count is needed
0312      * @return count of matching splits
0313      */
0314     uint matchingSplitsCount(const MyMoneyTransaction& transaction);
0315 
0316     /**
0317       * This method returns a list of the matching splits for the filter.
0318       * If m_reportAllSplits is set to false, then only the very first
0319       * split will be returned. Use setReportAllSplits() to change the
0320       * behaviour.
0321       *
0322       * @return reference list of MyMoneySplit objects containing the
0323       *         matching splits. If multiple splits match, only the first
0324       *         one will be returned.
0325       *
0326       * @note an empty list will be returned, if the filter only required
0327       *       to check the data contained in the MyMoneyTransaction
0328       *       object (e.g. posting-date, state, etc.).
0329       *
0330       * @note The constructors set m_reportAllSplits differently. Please
0331       *       see the documentation of the constructors MyMoneyTransactionFilter()
0332       *       and MyMoneyTransactionFilter(const QString&) for details.
0333       */
0334     QVector<MyMoneySplit> matchingSplits(const MyMoneyTransaction& transaction);
0335 
0336     /**
0337       * This method returns the from date set in the filter. If
0338       * no value has been set up for this filter, then QDate() is
0339       * returned.
0340       *
0341       * @return returns m_fromDate
0342       */
0343     QDate fromDate() const;
0344 
0345     /**
0346       * This method returns the to date set in the filter. If
0347       * no value has been set up for this filter, then QDate() is
0348       * returned.
0349       *
0350       * @return returns m_toDate
0351       */
0352     QDate toDate() const;
0353 
0354     /**
0355       * This method is used to return information about the
0356       * presence of a specific category in the category filter.
0357       * The category in question is included in the filter set,
0358       * if it has been set or no category filter is set.
0359       *
0360       * @param cat id of category in question
0361       * @return true if category is in filter set, false otherwise
0362       */
0363     bool includesCategory(const QString& cat) const;
0364 
0365     /**
0366       * This method is used to return information about the
0367       * presence of a specific account in the account filter.
0368       * The account in question is included in the filter set,
0369       * if it has been set or no account filter is set.
0370       *
0371       * @param acc id of account in question
0372       * @return true if account is in filter set, false otherwise
0373       */
0374     bool includesAccount(const QString& acc) const;
0375 
0376     /**
0377       * This method is used to return information about the
0378       * presence of a specific payee in the account filter.
0379       * The payee in question is included in the filter set,
0380       * if it has been set or no account filter is set.
0381       *
0382       * @param pye id of payee in question
0383       * @return true if payee is in filter set, false otherwise
0384       */
0385     bool includesPayee(const QString& pye) const;
0386 
0387     /**
0388       * This method is used to return information about the
0389       * presence of a specific tag in the account filter.
0390       * The tag in question is included in the filter set,
0391       * if it has been set or no account filter is set.
0392       *
0393       * @param tag id of tag in question
0394       * @return true if tag is in filter set, false otherwise
0395       */
0396     bool includesTag(const QString& tag) const;
0397 
0398     /**
0399       * This method is used to return information about the
0400       * presence of a date filter.
0401       *
0402       * @param from result value for the beginning of the date range
0403       * @param to result value for the end of the date range
0404       * @return true if a date filter is set
0405       */
0406     bool dateFilter(QDate& from, QDate& to) const;
0407 
0408     /**
0409       * This method is used to return information about the
0410       * presence of an amount filter.
0411       *
0412       * @param from result value for the low end of the amount range
0413       * @param to result value for the high end of the amount range
0414       * @return true if an amount filter is set
0415       */
0416     bool amountFilter(MyMoneyMoney& from, MyMoneyMoney& to) const;
0417 
0418     /**
0419       * This method is used to return information about the
0420       * presence of an number filter.
0421       *
0422       * @param from result value for the low end of the number range
0423       * @param to result value for the high end of the number range
0424       * @return true if a number filter is set
0425       */
0426     bool numberFilter(QString& from, QString& to) const;
0427 
0428     /**
0429       * This method returns whether a payee filter has been set,
0430       * and if so, it returns all the payees set in the filter.
0431       *
0432       * @param list list to append payees into
0433       * @return return true if a payee filter has been set
0434       */
0435     bool payees(QStringList& list) const;
0436 
0437     /**
0438       * This method returns whether a tag filter has been set,
0439       * and if so, it returns all the tags set in the filter.
0440       *
0441       * @param list list to append tags into
0442       * @return return true if a tag filter has been set
0443       */
0444     bool tags(QStringList& list) const;
0445 
0446     /**
0447       * This method returns whether an account filter has been set,
0448       * and if so, it returns all the accounts set in the filter.
0449       *
0450       * @param list list to append accounts into
0451       * @return return true if an account filter has been set
0452       */
0453     bool accounts(QStringList& list) const;
0454 
0455     /**
0456       * This method returns whether a category filter has been set,
0457       * and if so, it returns all the categories set in the filter.
0458       *
0459       * @param list list to append categories into
0460       * @return return true if a category filter has been set
0461       */
0462     bool categories(QStringList& list) const;
0463 
0464     /**
0465       * This method returns whether a type filter has been set,
0466       * and if so, it returns the first type in the filter.
0467       *
0468       * @param i int to replace with first type filter, untouched otherwise
0469       * @return return true if a type filter has been set
0470       */
0471     bool firstType(int& i) const;
0472 
0473     bool types(QList<int>& list) const;
0474 
0475     /**
0476       * This method returns whether a state filter has been set,
0477       * and if so, it returns the first state in the filter.
0478       *
0479       * @param i reference to int to replace with first state filter, untouched otherwise
0480       * @return return true if a state filter has been set
0481       */
0482     bool firstState(int& i) const;
0483 
0484     bool states(QList<int>& list) const;
0485 
0486     /**
0487       * This method returns whether a validity filter has been set,
0488       * and if so, it returns the first validity in the filter.
0489       *
0490       * @param i reference to int to replace with first validity filter, untouched otherwise
0491       * @return return true if a validity filter has been set
0492       */
0493     bool firstValidity(int& i) const;
0494 
0495     bool validities(QList<int>& list) const;
0496 
0497     /**
0498       * This method returns whether a text filter has been set,
0499       * and if so, it returns the text filter.
0500       *
0501       * @param text regexp to replace with text filter, or blank if none set
0502       * @return return true if a text filter has been set
0503       */
0504     bool textFilter(QRegExp& text) const;
0505 
0506     /**
0507      * This method returns whether the text filter should return
0508      * that DO NOT contain the text
0509      */
0510     bool isInvertingText() const;
0511 
0512     /**
0513      * This method returns whether transfers should be treated as
0514      * income/expense transactions or not
0515      */
0516     bool treatTransfersAsIncomeExpense() const;
0517 
0518     /**
0519       * This method translates a plain-language date range into QDate
0520       * start & end
0521       *
0522       * @param range Plain-language range of dates, e.g. 'CurrentYear'
0523       * @param start QDate will be set to corresponding to the first date in @p range
0524       * @param end QDate will be set to corresponding to the last date in @p range
0525       * @return return true if a range was successfully set, or false if @p range was invalid
0526       */
0527     static bool translateDateRange(eMyMoney::TransactionFilter::Date range, QDate& start, QDate& end);
0528 
0529     static void setFiscalYearStart(int firstMonth, int firstDay);
0530 
0531     FilterSet filterSet() const;
0532 
0533     /**
0534       * This member removes all references to object identified by @p id. Used
0535       * to remove objects which are about to be removed from the engine.
0536       */
0537     void removeReference(const QString& id);
0538 
0539 private:
0540     /**
0541       * This is a conversion tool from eMyMoney::Split::State
0542       * to MyMoneyTransactionFilter::stateE types
0543       *
0544       * @param split reference to split in question
0545       *
0546       * @return converted reconcile flag of the split passed as parameter
0547       */
0548     int splitState(const MyMoneySplit& split) const;
0549 
0550     /**
0551       * This is a conversion tool from MyMoneySplit::action
0552       * to MyMoneyTransactionFilter::typeE types
0553       *
0554       * @param t reference to transaction
0555       * @param split reference to split in question
0556       *
0557       * @return converted action of the split passed as parameter
0558       */
0559     int splitType(const MyMoneyTransaction& t, const MyMoneySplit& split, const MyMoneyAccount &acc) const;
0560 
0561     /**
0562       * This method checks if a transaction is valid or not. A transaction
0563       * is considered valid, if the sum of all splits is zero, invalid otherwise.
0564       *
0565       * @param transaction reference to transaction to be checked
0566       * @retval valid transaction is valid
0567       * @retval invalid transaction is invalid
0568       */
0569     eMyMoney::TransactionFilter::Validity validTransaction(const MyMoneyTransaction& transaction) const;
0570 };
0571 
0572 inline void swap(MyMoneyTransactionFilter& first, MyMoneyTransactionFilter& second) // krazy:exclude=inline
0573 {
0574     using std::swap;
0575     swap(first.d_ptr, second.d_ptr);
0576 }
0577 
0578 inline MyMoneyTransactionFilter::MyMoneyTransactionFilter(MyMoneyTransactionFilter && other) : MyMoneyTransactionFilter() // krazy:exclude=inline
0579 {
0580     swap(*this, other);
0581 }
0582 
0583 inline MyMoneyTransactionFilter & MyMoneyTransactionFilter::operator=(MyMoneyTransactionFilter other) // krazy:exclude=inline
0584 {
0585     swap(*this, other);
0586     return *this;
0587 }
0588 
0589 /**
0590   * Make it possible to hold @ref MyMoneyTransactionFilter objects inside @ref QVariant objects.
0591   */
0592 Q_DECLARE_METATYPE(MyMoneyTransactionFilter)
0593 Q_DECLARE_OPERATORS_FOR_FLAGS(MyMoneyTransactionFilter::FilterSet)
0594 
0595 #endif