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

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