File indexing completed on 2024-05-19 05:07:25

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 class QString;
0019 class QDate;
0020 class QRegularExpression;
0021 
0022 // ----------------------------------------------------------------------------
0023 // KDE Includes
0024 
0025 // ----------------------------------------------------------------------------
0026 // Project Includes
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 isRegExp the user should see a regular expression if true or a wildcard if false
0128      * @param invert If true, value must not be contained in any of the above mentioned fields
0129      *
0130      */
0131     void setTextFilter(const QRegularExpression& exp, bool isRegExp, bool invert);
0132 
0133     /**
0134       * This method will add the account with id @p id to the list of matching accounts.
0135       * If the list is empty, any transaction will match.
0136       *
0137       * @param id internal ID of the account
0138       */
0139     void addAccount(const QString& id);
0140 
0141     /**
0142       * This is a convenience method and behaves exactly like the above
0143       * method but for a list of id's.
0144       */
0145     void addAccount(const QStringList& ids);
0146 
0147     /**
0148       * This method will add the category with id @p id to the list of matching categories.
0149       * If the list is empty, only transaction with a single asset/liability account will match.
0150       *
0151       * @param id internal ID of the account
0152       */
0153     void addCategory(const QString& id);
0154 
0155     /**
0156       * This is a convenience method and behaves exactly like the above
0157       * method but for a list of id's.
0158       */
0159     void addCategory(const QStringList& ids);
0160 
0161     /**
0162       * This method sets the date filter to match only transactions with posting dates in
0163       * the date range specified by @p from and @p to. If @p from equal QDate()
0164       * all transactions with dates prior to @p to match. If @p to equals QDate()
0165       * all transactions with posting dates past @p from match. If @p from and @p to
0166       * are equal QDate() the filter is not activated and all transactions match.
0167       *
0168       * @param from from date
0169       * @param to   to date
0170       */
0171     void setDateFilter(const QDate& from, const QDate& to);
0172 
0173     void setDateFilter(eMyMoney::TransactionFilter::Date range);
0174 
0175     /**
0176       * This method sets the amount filter to match only transactions with
0177       * an amount in the range specified by @p from and @p to.
0178       * If a specific amount should be searched, @p from and @p to should be
0179       * the same value.
0180       *
0181       * @param from smallest value to match
0182       * @param to   largest value to match
0183       */
0184     void setAmountFilter(const MyMoneyMoney& from, const MyMoneyMoney& to);
0185 
0186     /**
0187       * This method will add the payee with id @p id to the list of matching payees.
0188       * If the list is empty, any transaction will match.
0189       *
0190       * @param id internal id of the payee
0191       */
0192     void addPayee(const QString& id);
0193 
0194     /**
0195       * This method will add the tag with id @ta id to the list of matching tags.
0196       * If the list is empty, any transaction will match.
0197       *
0198       * @param id internal id of the tag
0199       */
0200     void addTag(const QString& id);
0201 
0202     /**
0203       */
0204     void addType(const int type);
0205 
0206     /**
0207       */
0208     void addValidity(const int type);
0209 
0210     /**
0211       */
0212     void addState(const int state);
0213 
0214     /**
0215       * This method sets the number filter to match only transactions with
0216       * a number in the range specified by @p from and @p to.
0217       * If a specific number should be searched, @p from and @p to should be
0218       * the same value.
0219       *
0220       * @param from smallest value to match
0221       * @param to   largest value to match
0222       *
0223       * @note @p from and @p to can contain alphanumeric text
0224       */
0225     void setNumberFilter(const QString& from, const QString& to);
0226 
0227     /**
0228       * This method is used to check a specific transaction against the filter.
0229       * The transaction will match the whole filter, if all specified filters
0230       * match. If the filter is cleared using the clear() method, any transaction
0231       * matches. Matching splits from the transaction are returned by @ref
0232       * matchingSplits().
0233       *
0234       * @param transaction A transaction
0235       *
0236       * @retval true The transaction matches the filter set
0237       * @retval false The transaction does not match at least one of
0238       *               the filters in the filter set
0239       */
0240     bool match(const MyMoneyTransaction& transaction);
0241 
0242     /**
0243       * This method is used to check a specific split against the
0244       * text filter. The split will match if all specified and
0245       * checked filters match. If the filter is cleared using the clear()
0246       * method, any split matches.
0247       *
0248       * @param sp pointer to the split to be checked
0249       *
0250       * @retval true The split matches the filter set
0251       * @retval false The split does not match at least one of
0252       *               the filters in the filter set
0253       */
0254     bool matchText(const MyMoneySplit& s, const MyMoneyAccount &acc) const;
0255 
0256     /**
0257       * This method is used to check a specific split against the
0258       * amount filter. The split will match if all specified and
0259       * checked filters match. If the filter is cleared using the clear()
0260       * method, any split matches.
0261       *
0262       * @param sp const reference to the split to be checked
0263       *
0264       * @retval true The split matches the filter set
0265       * @retval false The split does not match at least one of
0266       *               the filters in the filter set
0267       */
0268     bool matchAmount(const MyMoneySplit& s) const;
0269 
0270     /**
0271      * Convenience method which actually returns matchText(sp) && matchAmount(sp).
0272      */
0273     bool match(const MyMoneySplit& s) const;
0274 
0275     /**
0276       * This method is used to switch the amount of splits reported
0277       * by matchingSplits(). If the argument @p report is @p true (the default
0278       * if no argument specified) then matchingSplits() will return all
0279       * matching splits of the transaction. If @p report is set to @p false,
0280       * then only the very first matching split will be returned by
0281       * matchingSplits().
0282       *
0283       * @param report controls the behaviour of matchingsSplits() as explained above.
0284       */
0285     void setReportAllSplits(const bool report = true);
0286 
0287     /**
0288      * Consider splits in categories
0289      *
0290      * With this setting, splits in categories that are not considered
0291      * by default are taken into account.
0292      *
0293      * @param check check state
0294      */
0295     void setConsiderCategorySplits(const bool check = true);
0296 
0297     /**
0298      * Consider income and expense categories
0299      *
0300      * If the account or category filter is enabled, categories of
0301      * income and expense type are included if enabled with this
0302      * method.
0303      *
0304      * @param check check state
0305      */
0306     void setConsiderCategory(const bool check = true);
0307 
0308     void setTreatTransfersAsIncomeExpense(const bool check = true);
0309 
0310     /**
0311      * This method is to avoid returning matching splits list
0312      * if only its count is needed
0313      * @return count of matching splits
0314      */
0315     uint matchingSplitsCount(const MyMoneyTransaction& transaction);
0316 
0317     /**
0318       * This method returns a list of the matching splits for the filter.
0319       * If m_reportAllSplits is set to false, then only the very first
0320       * split will be returned. Use setReportAllSplits() to change the
0321       * behaviour.
0322       *
0323       * @return reference list of MyMoneySplit objects containing the
0324       *         matching splits. If multiple splits match, only the first
0325       *         one will be returned.
0326       *
0327       * @note an empty list will be returned, if the filter only required
0328       *       to check the data contained in the MyMoneyTransaction
0329       *       object (e.g. posting-date, state, etc.).
0330       *
0331       * @note The constructors set m_reportAllSplits differently. Please
0332       *       see the documentation of the constructors MyMoneyTransactionFilter()
0333       *       and MyMoneyTransactionFilter(const QString&) for details.
0334       */
0335     QVector<MyMoneySplit> matchingSplits(const MyMoneyTransaction& transaction);
0336 
0337     /**
0338       * This method returns the from date set in the filter. If
0339       * no value has been set up for this filter, then QDate() is
0340       * returned.
0341       *
0342       * @return returns m_fromDate
0343       */
0344     QDate fromDate() const;
0345 
0346     /**
0347       * This method returns the to date set in the filter. If
0348       * no value has been set up for this filter, then QDate() is
0349       * returned.
0350       *
0351       * @return returns m_toDate
0352       */
0353     QDate toDate() const;
0354 
0355     /**
0356       * This method is used to return information about the
0357       * presence of a specific category in the category filter.
0358       * The category in question is included in the filter set,
0359       * if it has been set or no category filter is set.
0360       *
0361       * @param cat id of category in question
0362       * @return true if category is in filter set, false otherwise
0363       */
0364     bool includesCategory(const QString& cat) const;
0365 
0366     /**
0367       * This method is used to return information about the
0368       * presence of a specific account in the account filter.
0369       * The account in question is included in the filter set,
0370       * if it has been set or no account filter is set.
0371       *
0372       * @param acc id of account in question
0373       * @return true if account is in filter set, false otherwise
0374       */
0375     bool includesAccount(const QString& acc) const;
0376 
0377     /**
0378       * This method is used to return information about the
0379       * presence of a specific payee in the account filter.
0380       * The payee in question is included in the filter set,
0381       * if it has been set or no account filter is set.
0382       *
0383       * @param pye id of payee in question
0384       * @return true if payee is in filter set, false otherwise
0385       */
0386     bool includesPayee(const QString& pye) const;
0387 
0388     /**
0389       * This method is used to return information about the
0390       * presence of a specific tag in the account filter.
0391       * The tag in question is included in the filter set,
0392       * if it has been set or no account filter is set.
0393       *
0394       * @param tag id of tag in question
0395       * @return true if tag is in filter set, false otherwise
0396       */
0397     bool includesTag(const QString& tag) const;
0398 
0399     /**
0400       * This method is used to return information about the
0401       * presence of a date filter.
0402       *
0403       * @param from result value for the beginning of the date range
0404       * @param to result value for the end of the date range
0405       * @return true if a date filter is set
0406       */
0407     bool dateFilter(QDate& from, QDate& to) const;
0408 
0409     /**
0410       * This method is used to return information about the
0411       * presence of an amount filter.
0412       *
0413       * @param from result value for the low end of the amount range
0414       * @param to result value for the high end of the amount range
0415       * @return true if an amount filter is set
0416       */
0417     bool amountFilter(MyMoneyMoney& from, MyMoneyMoney& to) const;
0418 
0419     /**
0420       * This method is used to return information about the
0421       * presence of an number filter.
0422       *
0423       * @param from result value for the low end of the number range
0424       * @param to result value for the high end of the number range
0425       * @return true if a number filter is set
0426       */
0427     bool numberFilter(QString& from, QString& to) const;
0428 
0429     /**
0430       * This method returns whether a payee filter has been set,
0431       * and if so, it returns all the payees set in the filter.
0432       *
0433       * @param list list to append payees into
0434       * @return return true if a payee filter has been set
0435       */
0436     bool payees(QStringList& list) const;
0437 
0438     /**
0439      * This method returns all payees set in the filter.
0440      *
0441      * @return QStringList of payeeIds to match;
0442      */
0443     QStringList payees() const;
0444 
0445     /**
0446       * This method returns whether a tag filter has been set,
0447       * and if so, it returns all the tags set in the filter.
0448       *
0449       * @param list list to append tags into
0450       * @return return true if a tag filter has been set
0451       */
0452     bool tags(QStringList& list) const;
0453 
0454     /**
0455      * This method returns all tag ids that have been
0456      * added to the filter. If no tag filter has been set,
0457      * an empty list is returned.
0458      *
0459      * @returns list of tag ids
0460      */
0461     QStringList tags() const;
0462 
0463     /**
0464       * This method returns whether an account filter has been set,
0465       * and if so, it returns all the accounts set in the filter.
0466       *
0467       * @param list list to append accounts into
0468       * @return return true if an account filter has been set
0469       */
0470     bool accounts(QStringList& list) const;
0471 
0472     /**
0473      * This method returns all accounts set in the filter.
0474      *
0475      * @return QStringList of payeeIds to match;
0476      */
0477     QStringList accounts() const;
0478 
0479     /**
0480       * This method returns whether a category filter has been set,
0481       * and if so, it returns all the categories set in the filter.
0482       *
0483       * @param list list to append categories into
0484       * @return return true if a category filter has been set
0485       */
0486     bool categories(QStringList& list) const;
0487 
0488     /**
0489       * This method returns whether a type filter has been set,
0490       * and if so, it returns the first type in the filter.
0491       *
0492       * @param i int to replace with first type filter, untouched otherwise
0493       * @return return true if a type filter has been set
0494       */
0495     bool firstType(int& i) const;
0496 
0497     bool types(QList<int>& list) const;
0498 
0499     /**
0500       * This method returns whether a state filter has been set,
0501       * and if so, it returns the first state in the filter.
0502       *
0503       * @param i reference to int to replace with first state filter, untouched otherwise
0504       * @return return true if a state filter has been set
0505       */
0506     bool firstState(int& i) const;
0507 
0508     bool states(QList<int>& list) const;
0509 
0510     /**
0511       * This method returns whether a validity filter has been set,
0512       * and if so, it returns the first validity in the filter.
0513       *
0514       * @param i reference to int to replace with first validity filter, untouched otherwise
0515       * @return return true if a validity filter has been set
0516       */
0517     bool firstValidity(int& i) const;
0518 
0519     bool validities(QList<int>& list) const;
0520 
0521     /**
0522      * This method returns whether a text filter has been set,
0523      * and if so, it returns the text filter.
0524      *
0525      * @param text regexp to replace with text filter, or blank if none set
0526      * @param isRegExp reference to bool which will return if @a text should
0527      *                 be treated as regex (@c true) or wildcard (@c false)
0528      * @return return true if a text filter has been set
0529      */
0530     bool textFilter(QRegularExpression& text, bool& isRegExp) const;
0531 
0532     /**
0533      * This method returns whether the text filter should return
0534      * that DO NOT contain the text
0535      */
0536     bool isInvertingText() const;
0537 
0538     /**
0539      * This method returns whether transfers should be treated as
0540      * income/expense transactions or not
0541      */
0542     bool treatTransfersAsIncomeExpense() const;
0543 
0544     /**
0545       * This method translates a plain-language date range into QDate
0546       * start & end
0547       *
0548       * @param range Plain-language range of dates, e.g. 'CurrentYear'
0549       * @param start QDate will be set to corresponding to the first date in @p range
0550       * @param end QDate will be set to corresponding to the last date in @p range
0551       * @return return true if a range was successfully set, or false if @p range was invalid
0552       */
0553     static bool translateDateRange(eMyMoney::TransactionFilter::Date range, QDate& start, QDate& end);
0554 
0555     static void setFiscalYearStart(int firstMonth, int firstDay);
0556 
0557     FilterSet filterSet() const;
0558 
0559     /**
0560       * This member removes all references to object identified by @p id. Used
0561       * to remove objects which are about to be removed from the engine.
0562       */
0563     void removeReference(const QString& id);
0564 
0565 private:
0566     /**
0567       * This is a conversion tool from eMyMoney::Split::State
0568       * to MyMoneyTransactionFilter::stateE types
0569       *
0570       * @param split reference to split in question
0571       *
0572       * @return converted reconcile flag of the split passed as parameter
0573       */
0574     int splitState(const MyMoneySplit& split) const;
0575 
0576     /**
0577       * This is a conversion tool from MyMoneySplit::action
0578       * to MyMoneyTransactionFilter::typeE types
0579       *
0580       * @param t reference to transaction
0581       * @param split reference to split in question
0582       *
0583       * @return converted action of the split passed as parameter
0584       */
0585     int splitType(const MyMoneyTransaction& t, const MyMoneySplit& split, const MyMoneyAccount &acc) const;
0586 
0587     /**
0588       * This method checks if a transaction is valid or not. A transaction
0589       * is considered valid, if the sum of all splits is zero, invalid otherwise.
0590       *
0591       * @param transaction reference to transaction to be checked
0592       * @retval valid transaction is valid
0593       * @retval invalid transaction is invalid
0594       */
0595     eMyMoney::TransactionFilter::Validity validTransaction(const MyMoneyTransaction& transaction) const;
0596 };
0597 
0598 inline void swap(MyMoneyTransactionFilter& first, MyMoneyTransactionFilter& second) // krazy:exclude=inline
0599 {
0600     using std::swap;
0601     swap(first.d_ptr, second.d_ptr);
0602 }
0603 
0604 inline MyMoneyTransactionFilter::MyMoneyTransactionFilter(MyMoneyTransactionFilter && other) : MyMoneyTransactionFilter() // krazy:exclude=inline
0605 {
0606     swap(*this, other);
0607 }
0608 
0609 inline MyMoneyTransactionFilter & MyMoneyTransactionFilter::operator=(MyMoneyTransactionFilter other) // krazy:exclude=inline
0610 {
0611     swap(*this, other);
0612     return *this;
0613 }
0614 
0615 /**
0616   * Make it possible to hold @ref MyMoneyTransactionFilter objects inside @ref QVariant objects.
0617   */
0618 Q_DECLARE_METATYPE(MyMoneyTransactionFilter)
0619 Q_DECLARE_OPERATORS_FOR_FLAGS(MyMoneyTransactionFilter::FilterSet)
0620 
0621 #endif