File indexing completed on 2024-05-19 16:15:30

0001 /*
0002     SPDX-FileCopyrightText: 2000-2004 Michael Edwardes <mte@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2002-2018 Thomas Baumgart <tbaumgart@kde.org>
0004     SPDX-FileCopyrightText: 2005 Ace Jones <acejones@users.sourceforge.net>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #ifndef MYMONEYSCHEDULE_H
0009 #define MYMONEYSCHEDULE_H
0010 
0011 // ----------------------------------------------------------------------------
0012 // QT Includes
0013 
0014 #include <QMetaType>
0015 
0016 // ----------------------------------------------------------------------------
0017 // Project Includes
0018 
0019 #include "kmm_mymoney_export.h"
0020 #include "mymoneyunittestable.h"
0021 #include "mymoneyobject.h"
0022 
0023 class QString;
0024 class QDate;
0025 
0026 class IMyMoneyProcessingCalendar;
0027 class MyMoneyAccount;
0028 class MyMoneyTransaction;
0029 
0030 namespace eMyMoney {
0031 namespace Schedule {
0032 enum class Type;
0033 enum class Occurrence;
0034 enum class PaymentType;
0035 enum class WeekendOption;
0036 }
0037 }
0038 
0039 template <typename T> class QList;
0040 
0041 /**
0042   * @author Michael Edwardes
0043   */
0044 
0045 /**
0046   * This class represents a schedule. (A series of bills, deposits or
0047   * transfers).
0048   *
0049   * @short A class to represent a schedule.
0050   * @see MyMoneyScheduled
0051   */
0052 class MyMoneySchedulePrivate;
0053 class KMM_MYMONEY_EXPORT MyMoneySchedule : public MyMoneyObject
0054 {
0055     Q_DECLARE_PRIVATE(MyMoneySchedule)
0056 
0057     friend class MyMoneyStorageANON;
0058     KMM_MYMONEY_UNIT_TESTABLE
0059 
0060 public:
0061     /**
0062       * Standard constructor
0063       */
0064     MyMoneySchedule();
0065     explicit MyMoneySchedule(const QString &id);
0066 
0067     /**
0068       * Constructor for initialising the object.
0069       *
0070       * Please note that the optional fields are not set and the transaction
0071       * MUST be set before it can be used.
0072       *
0073       * @a startDate is not used anymore and internally set to QDate()
0074       */
0075     explicit MyMoneySchedule(const QString& name,
0076                              eMyMoney::Schedule::Type type,
0077                              eMyMoney::Schedule::Occurrence occurrence,
0078                              int occurrenceMultiplier,
0079                              eMyMoney::Schedule::PaymentType paymentType,
0080                              const QDate& startDate,
0081                              const QDate& endDate,
0082                              bool fixed,
0083                              bool autoEnter);
0084 
0085     MyMoneySchedule(const QString& id,
0086                     const MyMoneySchedule& other);
0087 
0088     MyMoneySchedule(const MyMoneySchedule & other);
0089     MyMoneySchedule(MyMoneySchedule && other);
0090     MyMoneySchedule & operator=(MyMoneySchedule other);
0091     friend void swap(MyMoneySchedule& first, MyMoneySchedule& second);
0092 
0093     /**
0094       * Standard destructor
0095       */
0096     ~MyMoneySchedule();
0097 
0098     /**
0099       * Simple get method that returns the base occurrence frequency.
0100       *
0101       * @return eMyMoney::Schedule::Occurrence The instance frequency
0102       *         reduced to the simple units.
0103       */
0104     eMyMoney::Schedule::Occurrence baseOccurrence() const;
0105 
0106     /**
0107       * Simple get method that returns the occurrence period
0108       * multiplier and occurrence
0109       *
0110       * @return eMyMoney::Schedule::Occurrence The instance period
0111       *
0112       */
0113     eMyMoney::Schedule::Occurrence occurrence() const;
0114 
0115     /**
0116       * Simple get method that returns the occurrence period multiplier.
0117       *
0118       * @return int The frequency multiplier
0119       */
0120     int occurrenceMultiplier() const;
0121 
0122     /**
0123       * Simple get method that returns the schedule type.
0124       *
0125       * @return eMyMoney::Schedule::Type The instance type.
0126       */
0127     eMyMoney::Schedule::Type type() const;
0128 
0129     /**
0130       * Simple get method that returns the schedule startDate. If
0131       * the schedule has been executed once, the date of the first
0132       * execution is returned. Otherwise, the next due date is
0133       * returned.
0134       *
0135       * @return reference to QDate containing the start date.
0136       */
0137     QDate startDate() const;
0138 
0139     /**
0140       * Simple get method that returns the schedule paymentType.
0141       *
0142       * @return eMyMoney::Schedule::PaymentType The instance paymentType.
0143       */
0144     eMyMoney::Schedule::PaymentType paymentType() const;
0145 
0146     /**
0147       * Simple get method that returns true if the schedule is fixed.
0148       *
0149       * @return bool To indicate whether the instance is fixed.
0150       */
0151     bool isFixed() const;
0152 
0153     /**
0154       * Simple get method that returns true if the schedule will end
0155       * at some time.
0156       *
0157       * @return bool Indicates whether the instance will end.
0158       */
0159     bool willEnd() const;
0160 
0161     /**
0162       * Simple get method that returns the number of transactions remaining.
0163       *
0164       * @return int The number of transactions remaining for the instance.
0165       */
0166     int transactionsRemaining() const;
0167 
0168     /**
0169       * Simple method that returns the number of transactions remaining
0170       * until a given date.
0171       *
0172       * @param endDate Date to count transactions to.
0173       * @return int The number of transactions remaining for the instance.
0174       */
0175     int transactionsRemainingUntil(const QDate& endDate) const;
0176 
0177     /**
0178       * Simple get method that returns the schedule end date.
0179       *
0180       * @return QDate The end date for the instance.
0181       */
0182     QDate endDate() const;
0183 
0184     /**
0185       * Get the state if the schedule should be processed at the last day
0186       * of a month
0187       *
0188       * @return state of the flag
0189       */
0190     bool lastDayInMonth() const;
0191 
0192     /**
0193       * Simple get method that returns true if the transaction should be
0194       * automatically entered into the register.
0195       *
0196       * @return bool Indicates whether the instance will be automatically entered.
0197       */
0198     bool autoEnter() const;
0199 
0200     /**
0201       * Simple get method that returns the transaction data for the schedule.
0202       *
0203       * @return MyMoneyTransaction The transaction data for the instance.
0204       */
0205     MyMoneyTransaction transaction() const;
0206 
0207     /**
0208       * Simple method that sets the transaction for the schedule.
0209       * The transaction must have a valid postDate set, otherwise
0210       * it will not be accepted. This test is bypassed, if @a noDateCheck
0211       * is set to true
0212       *
0213       * @param transaction The new transaction.
0214       * @param noDateCheck if @a true, the date check is bypassed
0215       * @return none
0216       */
0217     void setTransaction(const MyMoneyTransaction& transaction, bool noDateCheck);
0218 
0219     /**
0220       * Simple method that returns the schedules last payment. If the
0221       * schedule has never been executed, QDate() will be returned.
0222       *
0223       * @return QDate The last payment for the schedule.
0224       */
0225     QDate lastPayment() const;
0226 
0227     /**
0228       * Simple method that returns the next due date for the schedule.
0229       *
0230       * @return reference to QDate containing the next due date.
0231       *
0232       * @note The date returned can represent a value that is past
0233       *       a possible end of the schedule. Make sure to consider
0234       *       the return value of isFinished() when using the value returned.
0235       */
0236     QDate nextDueDate() const;
0237 
0238     /**
0239       * This method returns the next due date adjusted
0240       * according to the rules specified by the schedule's weekend option.
0241       *
0242       * @return QDate containing the adjusted next due date. If the
0243       *         schedule is finished (@sa isFinished()) then the method
0244       *         returns an invalid QDate.
0245       *
0246       * @sa weekendOption()
0247       * @sa adjustedDate()
0248       */
0249     QDate adjustedNextDueDate() const;
0250 
0251     /**
0252       * This method adjusts returns the date adjusted according to the
0253       * rules specified by the schedule's weekend option.
0254       *
0255       * @return QDate containing the adjusted date.
0256       */
0257     QDate adjustedDate(QDate date, eMyMoney::Schedule::WeekendOption option) const;
0258 
0259     /**
0260 
0261       * Get the weekendOption that determines how the schedule check code
0262       * will enter transactions that occur on a non-processing day (usually
0263       * a weekend).
0264       *
0265       * This not used by MyMoneySchedule but by the support code.
0266     **/
0267     eMyMoney::Schedule::WeekendOption weekendOption() const;
0268 
0269     /**
0270       * Simple method that sets the frequency for the schedule.
0271       *
0272       * @param occ The new occurrence (frequency).
0273       * @return none
0274       */
0275     void setOccurrence(eMyMoney::Schedule::Occurrence occ);
0276 
0277     /**
0278       * Simple method that sets the schedule period
0279       *
0280       * @param occ The new occurrence period (frequency)
0281       * @return none
0282       */
0283     void setOccurrencePeriod(eMyMoney::Schedule::Occurrence occ);
0284 
0285     /**
0286       * Simple method that sets the frequency multiplier for the schedule.
0287       *
0288       * @param occmultiplier The new occurrence (frequency) multiplier.
0289       * @return none
0290       */
0291     void setOccurrenceMultiplier(int occmultiplier);
0292 
0293     /**
0294       * Simple method that sets the type for the schedule.
0295       *
0296       * @param type The new type.
0297       * @return none
0298       */
0299     void setType(eMyMoney::Schedule::Type type);
0300 
0301     /**
0302       * Simple method that sets the start date for the schedule.
0303       *
0304       * @param date The new start date.
0305       * @return none
0306       */
0307     void setStartDate(const QDate& date);
0308 
0309     /**
0310       * Simple method that sets the payment type for the schedule.
0311       *
0312       * @param type The new payment type.
0313       * @return none
0314       */
0315     void setPaymentType(eMyMoney::Schedule::PaymentType type);
0316 
0317     /**
0318       * Simple method to set whether the schedule is fixed or not.
0319       *
0320       * @param fixed boolean to indicate whether the instance is fixed.
0321       * @return none
0322       */
0323     void setFixed(bool fixed);
0324 
0325     /**
0326       * Simple method that sets the transaction for the schedule.
0327       * The transaction must have a valid postDate set, otherwise
0328       * it will not be accepted.
0329       *
0330       * @param transaction The new transaction.
0331       * @return none
0332       */
0333     void setTransaction(const MyMoneyTransaction& transaction);
0334 
0335     /**
0336       * Simple set method to set the end date for the schedule.
0337       *
0338       * @param date The new end date.
0339       * @return none
0340       */
0341     void setEndDate(const QDate& date);
0342 
0343     /**
0344       * Simple method to set whether the schedule should be performed at
0345       * the last day of a month.
0346       *
0347       * @param state boolean The state to set
0348       * @return none
0349       */
0350     void setLastDayInMonth(bool state);
0351 
0352     /**
0353       * Simple set method to set whether this transaction should be automatically
0354       * entered into the journal whenever it is due.
0355       *
0356       * @param autoenter boolean to indicate whether we need to automatically
0357       *                  enter the transaction.
0358       * @return none
0359       */
0360     void setAutoEnter(bool autoenter);
0361 
0362     /**
0363       * Simple set method to set the schedule's next payment date.
0364       *
0365       * @param date The next payment date.
0366       * @return none
0367       */
0368     void setNextDueDate(const QDate& date);
0369 
0370     /**
0371       * Simple set method to set the schedule's last payment. If
0372       * this method is called for the first time on the object,
0373       * the @a m_startDate member will be set to @a date as well.
0374       *
0375       * This method should be called whenever a schedule is entered or skipped.
0376       *
0377       * @param date The last payment date.
0378       * @return none
0379       */
0380     void setLastPayment(const QDate& date);
0381 
0382     /**
0383       * Set the weekendOption that determines how the schedule check code
0384       * will enter transactions that occur on a non-processing day (usually
0385       * a weekend). The following values
0386       * are valid:
0387       *
0388       * - MoveNothing: don't modify date
0389       * - MoveBefore: modify the date to the previous processing day
0390       * - MoveAfter: modify the date to the next processing day
0391       *
0392       * If an invalid option is given, the option is set to MoveNothing.
0393       *
0394       * @param option See list in description
0395       * @return none
0396       *
0397       * @note This not used by MyMoneySchedule but by the support code.
0398       **/
0399     void setWeekendOption(const eMyMoney::Schedule::WeekendOption option);
0400 
0401     /**
0402       * Validates the schedule instance.
0403       *
0404       * Makes sure the paymentType matches the type and that the required
0405       * fields have been set.
0406       *
0407       * @param id_check if @p true, the method will check for an empty id.
0408       *                 if @p false, this check is skipped. Default is @p true.
0409       *
0410       * @return If this method returns, all checks are passed. Otherwise,
0411       *         it will throw a MyMoneyException object.
0412       *
0413       * @exception MyMoneyException with detailed error information is thrown
0414       *            in case of failure of any check.
0415       */
0416     void validate(bool id_check = true) const;
0417 
0418     /**
0419       * Calculates the date of the next payment adjusted according to the
0420       * rules specified by the schedule's weekend option.
0421       *
0422       * @param refDate The reference date from which the next payment
0423       *                date will be calculated (defaults to current date)
0424       *
0425       * @return QDate The adjusted date the next payment is due. This date is
0426       *               always past @a refDate.  In case of an error or if there
0427       *               are no more payments then an empty/invalid QDate() will
0428       *               be returned.
0429       */
0430     QDate adjustedNextPayment(const QDate& refDate) const;
0431     QDate adjustedNextPayment() const;
0432 
0433     /**
0434       * Calculates the date of the next payment.
0435       *
0436       * @param refDate The reference date from which the next payment
0437       *                date will be calculated (defaults to current date)
0438       *
0439       * @return QDate The date the next payment is due. This date is
0440       *         always past @a refDate.  In case of an error or
0441       *         if there are no more payments then an empty/invalid QDate()
0442       *         will be returned.
0443       */
0444     QDate nextPayment(const QDate& refDate) const;
0445     QDate nextPayment() const;
0446 
0447     /**
0448       * Calculates the date of the next payment and adjusts if asked.
0449       *
0450       * @param adjust Whether to adjust the calculated date according to the
0451       *               rules specified by the schedule's weekend option.
0452       * @param refDate The reference date from which the next payment
0453       *                date will be calculated (defaults to current date)
0454       *
0455       * @return QDate The date the next payment is due. This date is
0456       *         always past @a refDate.  In case of an error or
0457       *         if there is no more payments then an empty/invalid QDate()
0458       *         will be returned.
0459       */
0460     QDate nextPaymentDate(const bool& adjust, const QDate& refDate) const;
0461     QDate nextPaymentDate(const bool& adjust) const;
0462 
0463     /**
0464       * Calculates the dates of the payment over a certain period of time.
0465       *
0466       * An empty list is returned for no payments or error.
0467       *
0468       * @param startDate The start date for the range calculations
0469       * @param endDate The end date for the range calculations.
0470       * @return QList<QDate> The dates on which the payments are due.
0471       */
0472     QList<QDate> paymentDates(const QDate& startDate, const QDate& endDate) const;
0473 
0474     /**
0475       * Returns the instances name
0476       *
0477       * @return The name
0478       */
0479     QString name() const;
0480 
0481     /**
0482       * Changes the instance name
0483       *
0484       * @param nm The new name
0485       * @return none
0486       */
0487     void setName(const QString& nm);
0488 
0489     bool operator ==(const MyMoneySchedule& right) const;
0490     bool operator !=(const MyMoneySchedule& right) const;
0491 
0492     bool operator <(const MyMoneySchedule& right) const;
0493 
0494     MyMoneyAccount account(int cnt = 1) const;
0495     MyMoneyAccount transferAccount() const;
0496     QDate dateAfter(int transactions) const;
0497 
0498     bool isOverdue() const;
0499     bool isFinished() const;
0500     bool hasRecordedPayment(const QDate&) const;
0501     void recordPayment(const QDate&);
0502     QList<QDate> recordedPayments() const;
0503 
0504     /**
0505       * This method checks if a reference to the given object exists. It returns,
0506       * a @p true if the object is referencing the one requested by the
0507       * parameter @p id. If it does not, this method returns @p false.
0508       *
0509       * @param id id of the object to be checked for references
0510       * @retval true This object references object with id @p id.
0511       * @retval false This object does not reference the object with id @p id.
0512       */
0513     virtual bool hasReferenceTo(const QString& id) const final override;
0514 
0515     /**
0516      * This method replaces all occurrences of id @a oldId with
0517      * @a newId.  All other ids are not changed.
0518      *
0519      * @return true if any change has been performed
0520      * @return false if nothing has been modified
0521      */
0522     bool replaceId(const QString& newId, const QString& oldId);
0523 
0524     /**
0525      * Returns the human-readable format of Schedule's occurrence
0526      *
0527      * @return QString representing the human readable format
0528      */
0529     QString occurrenceToString() const;
0530 
0531     /**
0532      * This method is used to convert the occurrence type from its
0533      * internal representation into a human readable format.
0534      *
0535      * @param type numerical representation of the MyMoneySchedule
0536      *                  occurrence type
0537      *
0538      * @return QString representing the human readable format
0539      */
0540     static QString occurrenceToString(eMyMoney::Schedule::Occurrence type);
0541 
0542     /**
0543      * This method is used to convert a multiplier and base occurrence type
0544      * from its internal representation into a human readable format.
0545      * When multiplier * occurrence is equivalent to a simple occurrence
0546      * the method returns the same as occurrenceToString of the simple occurrence
0547      *
0548      * @param mult occurrence multiplier
0549      * @param type occurrence period
0550      *
0551      * @return QString representing the human readable format
0552      */
0553     static QString occurrenceToString(int mult, eMyMoney::Schedule::Occurrence type);
0554 
0555     /**
0556      * This method is used to convert an occurrence period from
0557      * its internal representation into a human-readable format.
0558      *
0559      * @param type numerical representation of the MyMoneySchedule
0560      *                  occurrence type
0561      *
0562      * @return QString representing the human readable format
0563      */
0564     static QString occurrencePeriodToString(eMyMoney::Schedule::Occurrence type);
0565 
0566     /**
0567      * This method is used to convert the payment type from its
0568      * internal representation into a human readable format.
0569      *
0570      * @param paymentType numerical representation of the MyMoneySchedule
0571      *                  payment type
0572      *
0573      * @return QString representing the human readable format
0574      */
0575     static QString paymentMethodToString(eMyMoney::Schedule::PaymentType paymentType);
0576 
0577     /**
0578      * This method is used to convert the schedule weekend option from its
0579      * internal representation into a human readable format.
0580      *
0581      * @param weekendOption numerical representation of the MyMoneySchedule
0582      *                  weekend option
0583      *
0584      * @return QString representing the human readable format
0585      */
0586     static QString weekendOptionToString(eMyMoney::Schedule::WeekendOption weekendOption);
0587 
0588     /**
0589      * This method is used to convert the schedule type from its
0590      * internal representation into a human readable format.
0591      *
0592      * @param type numerical representation of the MyMoneySchedule
0593      *                  schedule type
0594      *
0595      * @return QString representing the human readable format
0596      */
0597     static QString scheduleTypeToString(eMyMoney::Schedule::Type type);
0598 
0599     int variation() const;
0600     void setVariation(int var);
0601 
0602     /**
0603      *
0604      * Convert an occurrence to the maximum number of events possible during a single
0605      * calendar year.
0606      * A fortnight is treated as 15 days.
0607      *
0608      * @param occurrence  The occurrence
0609      *
0610      * @return int  Number of days between events
0611      */
0612     static int eventsPerYear(eMyMoney::Schedule::Occurrence occurrence);
0613 
0614     /**
0615      *
0616      * Convert an occurrence to the number of days between events
0617      * Treats a month as 30 days.
0618      * Treats a fortnight as 15 days.
0619      *
0620      * @param occurrence  The occurrence
0621      *
0622      * @return int  Number of days between events
0623      */
0624     static int daysBetweenEvents(eMyMoney::Schedule::Occurrence occurrence);
0625 
0626     /**
0627       * Helper method to convert simple occurrence to compound occurrence + multiplier
0628       *
0629       * @param multiplier Returned by reference.  Adjusted multiplier
0630       * @param occurrence Returned by reference.  Occurrence type
0631       */
0632     static void simpleToCompoundOccurrence(int& multiplier, eMyMoney::Schedule::Occurrence& occurrence);
0633 
0634     /**
0635       * Helper method to convert compound occurrence + multiplier to simple occurrence
0636       *
0637       * @param multiplier Returned by reference.  Adjusted multiplier
0638       * @param occurrence Returned by reference.  Occurrence type
0639       */
0640     static void compoundToSimpleOccurrence(int& multiplier, eMyMoney::Schedule::Occurrence& occurrence);
0641 
0642     /**
0643       * This method is used to set the static point to relevant
0644       * IMyMoneyProcessingCalendar.
0645       */
0646     static void setProcessingCalendar(IMyMoneyProcessingCalendar* pc);
0647 
0648 private:
0649     /**
0650       * This method returns a pointer to the processing calendar object.
0651       *
0652       * @return const pointer to the current attached processing calendar object.
0653       *         If no object is attached, returns 0.
0654       */
0655     IMyMoneyProcessingCalendar* processingCalendar() const;
0656 
0657     /**
0658       * This method forces the day of the passed @p date to
0659       * be the day of the start date of this schedule kept
0660       * in m_startDate. It is internally used when calculating
0661       * the payment dates over several periods.
0662       *
0663       * @param date reference to QDate object to be checked and adjusted
0664       */
0665     void fixDate(QDate& date) const;
0666 
0667     /**
0668       * This method adds a number of Half Months to the given Date.
0669       * This is used for EveryHalfMonth occurrences.
0670       * The addition uses the following rules to add a half month:
0671       * Day 1-13: add 15 days
0672       * Day 14: add 15 days (except February: the last day of the month)
0673       * Day 15: last day of the month
0674       * Day 16-29 (not last day in February): subtract 15 days and add 1 month
0675       * 30 and last day: 15th of next month
0676       *
0677       * This calculation pairs days 1 to 12 with 16 to 27.
0678       * Day 15 is paired with the last day of every month.
0679       * Repeated addition has issues in the following cases:
0680       * - Days 13 to 14 are paired with 28 to 29 until addition hits the last day of February
0681       *   after which the (15,last) pair will be used.
0682       * - Addition from Day 30 leads immediately to the (15th,last) day pair.
0683       *
0684       * @param date The date
0685       * @param mult The number of half months to add.  Default is 1.
0686       *
0687       * @return QDate date with mult half months added
0688       */
0689     QDate addHalfMonths(QDate date, int mult = 1) const;
0690 
0691     /**
0692       * Checks if a given date should be considered a processing day
0693       * based on a calendar. See @a IMyMoneyProcessingCalendar and
0694       * setProcessingCalendar(). If no processingCalendar has been
0695       * setup using setProcessingCalendar it returns @c true on Mon..Fri
0696       * and @c false on Sat..Sun.
0697       */
0698     bool isProcessingDate(const QDate& date) const;
0699 };
0700 
0701 inline void swap(MyMoneySchedule& first, MyMoneySchedule& second) // krazy:exclude=inline
0702 {
0703     using std::swap;
0704     swap(first.d_ptr, second.d_ptr);
0705 }
0706 
0707 inline MyMoneySchedule::MyMoneySchedule(MyMoneySchedule && other) : MyMoneySchedule() // krazy:exclude=inline
0708 {
0709     swap(*this, other);
0710 }
0711 
0712 inline MyMoneySchedule & MyMoneySchedule::operator=(MyMoneySchedule other) // krazy:exclude=inline
0713 {
0714     swap(*this, other);
0715     return *this;
0716 }
0717 
0718 /**
0719   * Make it possible to hold @ref MyMoneySchedule objects inside @ref QVariant objects.
0720   */
0721 Q_DECLARE_METATYPE(MyMoneySchedule)
0722 
0723 #endif