1 /*
2 * Copyright 2013-2015 Christian Dávid <christian-david@web.de>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifndef ONLINEJOB_H
19 #define ONLINEJOB_H
20
21 #define STRINGIFY(x) #x
22 #define TOSTRING(x) STRINGIFY(x)
23 #define BADTASKEXCEPTION badTaskCast("Casted onlineTask with wrong type. " __FILE__ ":" TOSTRING(__LINE__))
24 #define EMPTYTASKEXCEPTION emptyTask("Requested onlineTask of onlineJob without any task. " __FILE__ ":" TOSTRING(__LINE__))
25
26 #include <stdexcept>
27 #include <QMetaType>
28 #include <QString>
29 #include "mymoneyobject.h"
30 #include "onlinejobmessage.h"
31
32 class onlineTask;
33 class MyMoneyAccount;
34
35 namespace eMyMoney { namespace OnlineJob { enum class sendingState; } }
36
37 /**
38 * @brief Class to share jobs which can be processed by an online banking plugin
39 *
40 * This class stores only the status information and a pointer to an @r onlineTask which stores
41 * the real data. So onlineJob is similar to an shared pointer.
42 *
43 * If you know the type of the onlineTask, @r onlineJobTyped is the first choice to use.
44 *
45 * It is save to use because accesses to pointers (e.g. task() ) throw an exception if onlineJob is null.
46 *
47 * Online jobs are usually not created directly but over @r onlineJobAdministration::createOnlineJob. This is
48 * required to allow loading of onlineTasks at runtime and only if needed.
49 *
50 * This class was created to help writing stable and reliable code. Before an unsafe structure (= pointer)
51 * is accessed it is checked. Exceptions are thrown if the content is unsafe.
52 *
53 * @see onlineTask
54 * @see onlineJobTyped
55 * @todo LOW make data implicitly shared
56 */
57 class onlineJobPrivate;
58 class KMM_MYMONEY_EXPORT onlineJob : public MyMoneyObject
59 {
60 Q_DECLARE_PRIVATE(onlineJob)
61
62 KMM_MYMONEY_UNIT_TESTABLE
63
64 public:
65 /**
66 * @brief Constructor for null onlineJobs
67 *
68 * A onlineJob which is null cannot become valid again.
69 * @see isNull()
70 */
71 onlineJob();
72 explicit onlineJob(const QString &id);
73
74 /**
75 * @brief Default constructor
76 *
77 * The onlineJob takes ownership of the task. The task is deleted in the destructor.
78 */
79 onlineJob(onlineTask* task, const QString& id); // krazy:exclude=explicit
80 onlineJob(onlineTask* task); // krazy:exclude=explicit
81
82 /**
83 * @brief Create new onlineJob as copy of other
84 *
85 * This constructor does not copy the status information but the task only.
86 */
87 onlineJob(const QString &id,
88 const onlineJob& other);
89
90 onlineJob(const onlineJob & other);
91 onlineJob(onlineJob && other);
92 onlineJob & operator=(onlineJob other);
93 friend void swap(onlineJob& first, onlineJob& second);
94
95 virtual ~onlineJob();
96
97 void setTask(onlineTask *task);
98
99 /**
100 * @brief Returns task attached to this onlineJob
101 *
102 * You should not store this pointer but use onlineJob::task() (or @r onlineJobTyped::task())
103 * every time you access it.
104 *
105 * @note The return type may change in future (e.g. to an atomic pointer). But you can always expect
106 * the operator @c -> to work like it does for onlineTask*.
107 *
108 * @throws emptyTask if isNull()
109 */
110 onlineTask* task();
111
112 /** @copydoc task(); */
113 const onlineTask* task() const;
114
115 /**
116 * @brief Returns task attached to this onlineJob as const
117 * @throws emptyTask if isNull()
118 */
119 const onlineTask* constTask() const;
120
121 /**
122 * @brief Returns task of type T attached to this onlineJob
123 *
124 * Internally a dynamic_cast is done and the result is checked.
125 *
126 * @throws emptyTask if isNull()
127 * @throws badTaskCast if attached task cannot be casted to T
128 */
129 template<class T> T* task();
130
131 /** @copydoc task() */
132 template<class T> const T* task() const;
constTask()133 template<class T> const T* constTask() const {
134 return task<T>();
135 }
136
137 template<class T> bool canTaskCast() const;
138
139 QString taskIid() const;
140
141 /** @todo implement */
142 bool hasReferenceTo(const QString &id) const override;
143
144 /**
145 * @brief Account this job is related to
146 *
147 * Each job must have an account on which the job operates. This is used to determine
148 * the correct onlinePlugin which can execute this job. If the job is related to more
149 * than one account (e.g. a password change) select a random one.
150 *
151 * @return accountId or QString() if none is set or job isNull.
152 */
153 virtual QString responsibleAccount() const;
154
155 /**
156 * @brief Returns the MyMoneyAccount this job is related to
157 * @see responsibleAccount()
158 */
159 MyMoneyAccount responsibleMyMoneyAccount() const;
160
161 /**
162 * @brief Check if this onlineJob is editable by the user
163 *
164 * A job is no longer editable by the user if it is used for documentary purposes
165 * e.g. the job was sent to the bank. In that case create a new job based on the
166 * old one.
167 *
168 * @todo make it possible to use onlineJobs as templates
169 */
170 virtual bool isEditable() const;
171
172 /**
173 * @brief Checks if this onlineJob has an attached task
174 *
175 * @return true if no task is attached to this job
176 */
177 virtual bool isNull() const;
178
179 /**
180 * @brief Checks if an valid onlineTask is attached
181 *
182 * @return true if task().isValid(), false if isNull() or !task.isValid()
183 */
184 virtual bool isValid() const;
185
186 /**
187 * @brief DateTime the job was sent to the bank
188 *
189 * A valid return does not mean that this job was accepted by the bank.
190 *
191 * @return A valid QDateTime if send to bank, an QDateTime() if not send.
192 */
193 virtual QDateTime sendDate() const;
194
195 /**
196 * @brief Mark this job as send
197 *
198 * To be used by online plugin only!
199 *
200 * Set dateTime to QDateTime to mark unsend.
201 */
202 virtual void setJobSend(const QDateTime &dateTime);
203 virtual void setJobSend();
204
205 /**
206 * @brief The bank's answer to this job
207 *
208 * To be used by online plugin only!
209 *
210 * Set dateTime to QDateTime() and bankAnswer to noState to mark unsend. If bankAnswer == noState dateTime.isNull() must be true!
211 */
212 void setBankAnswer(const eMyMoney::OnlineJob::sendingState state, const QDateTime &dateTime);
213 void setBankAnswer(const eMyMoney::OnlineJob::sendingState state);
214
215 /**
216 * @brief DateTime of the last status update by the bank
217 *
218 */
219 QDateTime bankAnswerDate() const;
220
221 /**
222 * @brief Returns last status sand by bank
223 * @return
224 */
225 eMyMoney::OnlineJob::sendingState bankAnswerState() const;
226
227 /**
228 * @brief locks the onlineJob for sending it
229 *
230 * Used when the job is in sending process by the online plugin.
231 *
232 * A locked onlineJob cannot be removed from the storage.
233 *
234 * @note The onlineJob can still be edited and stored. But it should be done by
235 * the one how owns the lock only.
236 *
237 * @todo Enforce the lock somehow? Note: the onlinePlugin must still be able to
238 * write to the job.
239 *
240 * @param enable true locks the job, false unlocks the job
241 */
242 virtual bool setLock(bool enable = true);
243
244 /**
245 * @brief Get lock status
246 */
247 virtual bool isLocked() const;
248
249 /**
250 * @brief Make this onlineJob a "new" onlineJob
251 *
252 * Removes all status information, log, and the id. Only
253 * the task is keept.
254 */
255 virtual void reset();
256
257 /**
258 * @brief addJobMessage
259 *
260 * To be used by online plugin only.
261 * @param message
262 */
263 void addJobMessage(const onlineJobMessage &message);
264
265 /**
266 * @brief Convenient method to set add a log message
267 */
268 void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode, const QDateTime& timestamp);
269 void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode);
270 void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message);
271
272
273 /**
274 * @brief jobMessageList
275 * @return
276 */
277 virtual QList<onlineJobMessage> jobMessageList() const;
278
279
280 void clearJobMessageList();
281
282 /**
283 * @brief Thrown if a cast of a task fails
284 *
285 * This is inspired by std::bad_cast
286 */
287 class badTaskCast : public std::runtime_error
288 {
289 public:
badTaskCast(const char * msg)290 explicit badTaskCast(const char *msg) : std::runtime_error(msg) {} // krazy:exclude=inline
291 };
292
293 /**
294 * @brief Thrown if a task of an invalid onlineJob is requested
295 */
296 class emptyTask : public std::runtime_error
297 {
298 public:
emptyTask(const char * msg)299 explicit emptyTask(const char *msg) : std::runtime_error(msg) {} // krazy:exclude=inline
300 };
301
302 /** @brief onlineTask attached to this job */
303 onlineTask* m_task;
304
305 private:
306
307 /** @brief Copies stored pointers (used by copy constructors) */
308 inline void copyPointerFromOtherJob(const onlineJob& other);
309 };
310
swap(onlineJob & first,onlineJob & second)311 inline void swap(onlineJob& first, onlineJob& second) // krazy:exclude=inline
312 {
313 using std::swap;
314 swap(first.d_ptr, second.d_ptr);
315 swap(first.m_task, second.m_task);
316 }
317
onlineJob(onlineJob && other)318 inline onlineJob::onlineJob(onlineJob && other) : onlineJob() // krazy:exclude=inline
319 {
320 swap(*this, other);
321 }
322
323 inline onlineJob & onlineJob::operator=(onlineJob other) // krazy:exclude=inline
324 {
325 swap(*this, other);
326 return *this;
327 }
328
329 template<class T>
task()330 T* onlineJob::task()
331 {
332 T* ret = dynamic_cast<T*>(m_task);
333 if (ret == 0)
334 throw EMPTYTASKEXCEPTION;
335 return ret;
336 }
337
338 template<class T>
task()339 const T* onlineJob::task() const
340 {
341 const T* ret = dynamic_cast<const T*>(m_task);
342 if (ret == 0)
343 throw BADTASKEXCEPTION;
344 return ret;
345 }
346
347 Q_DECLARE_METATYPE(onlineJob)
348
349 #endif // ONLINEJOB_H
350