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

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