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

0001 /*
0002     SPDX-FileCopyrightText: 2013-2015 Christian Dávid <christian-david@web.de>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #ifndef ONLINEJOB_H
0007 #define ONLINEJOB_H
0008 
0009 #define STRINGIFY(x) #x
0010 #define TOSTRING(x) STRINGIFY(x)
0011 #define BADTASKEXCEPTION badTaskCast("Casted onlineTask with wrong type. " __FILE__ ":" TOSTRING(__LINE__))
0012 #define EMPTYTASKEXCEPTION emptyTask("Requested onlineTask of onlineJob without any task. " __FILE__ ":" TOSTRING(__LINE__))
0013 
0014 #include <stdexcept>
0015 #include <QMetaType>
0016 #include <QString>
0017 #include "mymoneyobject.h"
0018 #include "onlinejobmessage.h"
0019 
0020 class onlineTask;
0021 class MyMoneyAccount;
0022 
0023 namespace eMyMoney {
0024 namespace OnlineJob {
0025 enum class sendingState;
0026 }
0027 }
0028 
0029 /**
0030  * @brief Class to share jobs which can be processed by an online banking plugin
0031  *
0032  * This class stores only the status information and a pointer to an @r onlineTask which stores
0033  * the real data. So onlineJob is similar to an shared pointer.
0034  *
0035  * If you know the type of the onlineTask, @r onlineJobTyped is the first choice to use.
0036  *
0037  * It is save to use because accesses to pointers (e.g. task() ) throw an exception if onlineJob is null.
0038  *
0039  * Online jobs are usually not created directly but over @r onlineJobAdministration::createOnlineJob. This is
0040  * required to allow loading of onlineTasks at runtime and only if needed.
0041  *
0042  * This class was created to help writing stable and reliable code. Before an unsafe structure (= pointer)
0043  * is accessed it is checked. Exceptions are thrown if the content is unsafe.
0044  *
0045  * @see onlineTask
0046  * @see onlineJobTyped
0047  * @todo LOW make data implicitly shared
0048  */
0049 class onlineJobPrivate;
0050 class KMM_MYMONEY_EXPORT onlineJob : public MyMoneyObject
0051 {
0052     Q_DECLARE_PRIVATE(onlineJob)
0053 
0054     KMM_MYMONEY_UNIT_TESTABLE
0055 
0056 public:
0057     /**
0058     * @brief Constructor for null onlineJobs
0059     *
0060     * A onlineJob which is null cannot become valid again.
0061     * @see isNull()
0062     */
0063     onlineJob();
0064     explicit onlineJob(const QString &id);
0065 
0066     /**
0067      * @brief Default constructor
0068      *
0069      * The onlineJob takes ownership of the task. The task is deleted in the destructor.
0070      */
0071     onlineJob(onlineTask* task, const QString& id); // krazy:exclude=explicit
0072     onlineJob(onlineTask* task); // krazy:exclude=explicit
0073 
0074     /**
0075      * @brief Create new onlineJob as copy of other
0076      *
0077      * This constructor does not copy the status information but the task only.
0078      */
0079     onlineJob(const QString &id,
0080               const onlineJob& other);
0081 
0082     onlineJob(const onlineJob & other);
0083     onlineJob(onlineJob && other);
0084     onlineJob & operator=(onlineJob other);
0085     friend void swap(onlineJob& first, onlineJob& second);
0086 
0087     virtual ~onlineJob();
0088 
0089     void setTask(onlineTask *task);
0090 
0091     /**
0092      * @brief Returns task attached to this onlineJob
0093      *
0094      * You should not store this pointer but use onlineJob::task() (or @r onlineJobTyped::task())
0095      * every time you access it.
0096      *
0097      * @note The return type may change in future (e.g. to an atomic pointer). But you can always expect
0098      * the operator @c -> to work like it does for onlineTask*.
0099      *
0100      * @throws emptyTask if isNull()
0101      */
0102     onlineTask* task();
0103 
0104     /** @copydoc task(); */
0105     const onlineTask* task() const;
0106 
0107     /**
0108      * @brief Returns task attached to this onlineJob as const
0109      * @throws emptyTask if isNull()
0110      */
0111     const onlineTask* constTask() const;
0112 
0113     /**
0114      * @brief Returns task of type T attached to this onlineJob
0115      *
0116      * Internally a dynamic_cast is done and the result is checked.
0117      *
0118      * @throws emptyTask if isNull()
0119      * @throws badTaskCast if attached task cannot be casted to T
0120      */
0121     template<class T> T* task();
0122 
0123     /** @copydoc task() */
0124     template<class T> const T* task() const;
0125     template<class T> const T* constTask() const {
0126         return task<T>();
0127     }
0128 
0129     template<class T> bool canTaskCast() const;
0130 
0131     QString taskIid() const;
0132 
0133     /** @todo implement */
0134     bool hasReferenceTo(const QString &id) const override;
0135 
0136     /**
0137      * @brief Account this job is related to
0138      *
0139      * Each job must have an account on which the job operates. This is used to determine
0140      * the correct onlinePlugin which can execute this job. If the job is related to more
0141      * than one account (e.g. a password change) select a random one.
0142      *
0143      * @return accountId or QString() if none is set or job isNull.
0144      */
0145     virtual QString responsibleAccount() const;
0146 
0147     /**
0148      * @brief Returns the MyMoneyAccount this job is related to
0149      * @see responsibleAccount()
0150      */
0151     MyMoneyAccount responsibleMyMoneyAccount() const;
0152 
0153     /**
0154      * @brief Check if this onlineJob is editable by the user
0155      *
0156      * A job is no longer editable by the user if it is used for documentary purposes
0157      * e.g. the job was sent to the bank. In that case create a new job based on the
0158      * old one.
0159      *
0160      * @todo make it possible to use onlineJobs as templates
0161      */
0162     virtual bool isEditable() const;
0163 
0164     /**
0165      * @brief Checks if this onlineJob has an attached task
0166      *
0167      * @return true if no task is attached to this job
0168      */
0169     virtual bool isNull() const;
0170 
0171     /**
0172      * @brief Checks if an valid onlineTask is attached
0173      *
0174      * @return true if task().isValid(), false if isNull() or !task.isValid()
0175      */
0176     virtual bool isValid() const;
0177 
0178     /**
0179      * @brief DateTime the job was sent to the bank
0180      *
0181      * A valid return does not mean that this job was accepted by the bank.
0182      *
0183      * @return A valid QDateTime if send to bank, an QDateTime() if not send.
0184      */
0185     virtual QDateTime sendDate() const;
0186 
0187     /**
0188      * @brief Mark this job as send
0189      *
0190      * To be used by online plugin only!
0191      *
0192      * Set dateTime to QDateTime to mark unsend.
0193      */
0194     virtual void setJobSend(const QDateTime &dateTime);
0195     virtual void setJobSend();
0196 
0197     /**
0198      * @brief The bank's answer to this job
0199      *
0200      * To be used by online plugin only!
0201      *
0202      * Set dateTime to QDateTime() and bankAnswer to noState to mark unsend. If bankAnswer == noState dateTime.isNull() must be true!
0203      */
0204     void setBankAnswer(const eMyMoney::OnlineJob::sendingState state, const QDateTime &dateTime);
0205     void setBankAnswer(const eMyMoney::OnlineJob::sendingState state);
0206 
0207     /**
0208      * @brief DateTime of the last status update by the bank
0209      *
0210      */
0211     QDateTime bankAnswerDate() const;
0212 
0213     /**
0214      * @brief Returns last status sand by bank
0215      * @return
0216      */
0217     eMyMoney::OnlineJob::sendingState bankAnswerState() const;
0218 
0219     /**
0220      * @brief locks the onlineJob for sending it
0221      *
0222      * Used when the job is in sending process by the online plugin.
0223      *
0224      * A locked onlineJob cannot be removed from the storage.
0225      *
0226      * @note The onlineJob can still be edited and stored. But it should be done by
0227      * the one how owns the lock only.
0228      *
0229      * @todo Enforce the lock somehow? Note: the onlinePlugin must still be able to
0230      * write to the job.
0231      *
0232      * @param enable true locks the job, false unlocks the job
0233      */
0234     virtual bool setLock(bool enable = true);
0235 
0236     /**
0237      * @brief Get lock status
0238      */
0239     virtual bool isLocked() const;
0240 
0241     /**
0242      * @brief Make this onlineJob a "new" onlineJob
0243      *
0244      * Removes all status information, log, and the id. Only
0245      * the task is keept.
0246      */
0247     virtual void reset();
0248 
0249     /**
0250      * @brief addJobMessage
0251      *
0252      * To be used by online plugin only.
0253      * @param message
0254      */
0255     void addJobMessage(const onlineJobMessage &message);
0256 
0257     /**
0258      * @brief Convenient method to set add a log message
0259      */
0260     void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode, const QDateTime& timestamp);
0261     void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode);
0262     void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message);
0263 
0264 
0265     /**
0266      * @brief jobMessageList
0267      * @return
0268      */
0269     virtual QList<onlineJobMessage> jobMessageList() const;
0270 
0271 
0272     void clearJobMessageList();
0273 
0274     /**
0275      * @brief Thrown if a cast of a task fails
0276      *
0277      * This is inspired by std::bad_cast
0278      */
0279     class badTaskCast : public std::runtime_error
0280     {
0281     public:
0282         explicit badTaskCast(const char *msg) : std::runtime_error(msg) {}  // krazy:exclude=inline
0283     };
0284 
0285     /**
0286      * @brief Thrown if a task of an invalid onlineJob is requested
0287      */
0288     class emptyTask : public std::runtime_error
0289     {
0290     public:
0291         explicit emptyTask(const char *msg) : std::runtime_error(msg) {}  // krazy:exclude=inline
0292     };
0293 
0294     /** @brief onlineTask attached to this job */
0295     onlineTask* m_task;
0296 
0297 private:
0298 
0299     /** @brief Copies stored pointers (used by copy constructors) */
0300     inline void copyPointerFromOtherJob(const onlineJob& other);
0301 };
0302 
0303 inline void swap(onlineJob& first, onlineJob& second) // krazy:exclude=inline
0304 {
0305     using std::swap;
0306     swap(first.d_ptr, second.d_ptr);
0307     swap(first.m_task, second.m_task);
0308 }
0309 
0310 inline onlineJob::onlineJob(onlineJob && other) : onlineJob() // krazy:exclude=inline
0311 {
0312     swap(*this, other);
0313 }
0314 
0315 inline onlineJob & onlineJob::operator=(onlineJob other) // krazy:exclude=inline
0316 {
0317     swap(*this, other);
0318     return *this;
0319 }
0320 
0321 template<class T>
0322 T* onlineJob::task()
0323 {
0324     T* ret = dynamic_cast<T*>(m_task);
0325     if (ret == 0)
0326         throw EMPTYTASKEXCEPTION;
0327     return ret;
0328 }
0329 
0330 template<class T>
0331 const T* onlineJob::task() const
0332 {
0333     const T* ret = dynamic_cast<const T*>(m_task);
0334     if (ret == 0)
0335         throw BADTASKEXCEPTION;
0336     return ret;
0337 }
0338 
0339 Q_DECLARE_METATYPE(onlineJob)
0340 
0341 #endif // ONLINEJOB_H