1 /*
2  * This file is part of KMyMoney, A Personal Finance Manager by KDE
3  * Copyright (C) 2013-2015 Christian Dávid <christian-david@web.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "onlinejobmodel.h"
20 
21 #include <QIcon>
22 #include <QDateTime>
23 
24 #include <KLocalizedString>
25 
26 #include "mymoneyobject.h"
27 #include "mymoneyfile.h"
28 #include "mymoneyaccount.h"
29 #include "mymoneyutils.h"
30 #include "onlinetasks/interfaces/tasks/onlinetask.h"
31 #include "onlinetasks/interfaces/tasks/credittransfer.h"
32 #include "mymoney/onlinejobtyped.h"
33 #include "payeeidentifier.h"
34 #include "payeeidentifiertyped.h"
35 #include "payeeidentifier/ibanbic/ibanbic.h"
36 #include "icons/icons.h"
37 #include "mymoneyexception.h"
38 #include "mymoneyenums.h"
39 #include "mymoneymoney.h"
40 #include "mymoneysecurity.h"
41 
42 using namespace Icons;
43 
onlineJobModel(QObject * parent)44 onlineJobModel::onlineJobModel(QObject *parent) :
45     QAbstractTableModel(parent),
46     m_jobIdList(QStringList())
47 {
48   MyMoneyFile *const file = MyMoneyFile::instance();
49   connect(file, &MyMoneyFile::objectAdded,
50           this, &onlineJobModel::slotObjectAdded);
51   connect(file, &MyMoneyFile::objectModified,
52           this, &onlineJobModel::slotObjectModified);
53   connect(file, &MyMoneyFile::objectRemoved,
54           this, &onlineJobModel::slotObjectRemoved);
55 }
56 
load()57 void onlineJobModel::load()
58 {
59   unload();
60   beginInsertRows(QModelIndex(), 0, 0);
61   foreach (const onlineJob job, MyMoneyFile::instance()->onlineJobList()) {
62     m_jobIdList.append(job.id());
63   }
64   endInsertRows();
65 }
66 
unload()67 void onlineJobModel::unload()
68 {
69   if (!m_jobIdList.isEmpty()) {
70     beginResetModel();
71     m_jobIdList.clear();
72     endResetModel();
73   }
74 }
75 
rowCount(const QModelIndex & parent) const76 int onlineJobModel::rowCount(const QModelIndex & parent) const
77 {
78   if (parent.isValid())
79     return 0;
80   return m_jobIdList.count();
81 }
82 
columnCount(const QModelIndex & parent) const83 int onlineJobModel::columnCount(const QModelIndex & parent) const
84 {
85   if (parent.isValid())
86     return 0;
87   return 4;
88 }
89 
headerData(int section,Qt::Orientation orientation,int role) const90 QVariant onlineJobModel::headerData(int section, Qt::Orientation orientation, int role) const
91 {
92   if (role != Qt::DisplayRole)
93     return QVariant();
94   if (orientation == Qt::Horizontal) {
95     switch (section) {
96       case columns::ColAccount: return i18n("Account");
97       case columns::ColAction: return i18n("Action");
98       case columns::ColDestination: return i18n("Destination");
99       case columns::ColValue: return i18n("Value");
100     }
101   }
102   return QVariant();
103 }
104 
105 /**
106  * @todo LOW improve speed
107  * @todo use now onlineJob system
108  */
data(const QModelIndex & index,int role) const109 QVariant onlineJobModel::data(const QModelIndex & index, int role) const
110 {
111   if (index.parent().isValid())
112     return QVariant();
113 
114   Q_ASSERT(m_jobIdList.length() > index.row());
115   onlineJob job;
116 
117   try {
118     job = MyMoneyFile::instance()->getOnlineJob(m_jobIdList[index.row()]);
119   } catch (const MyMoneyException &) {
120     return QVariant();
121   }
122 
123   // id of MyMoneyObject
124   if (role == roles::OnlineJobId)
125     return QVariant::fromValue(job.id());
126   else if (role == roles::OnlineJobRole)
127     return QVariant::fromValue(job);
128 
129   // If job is null, display an error message and exit
130   if (job.isNull()) {
131     if (index.column() == columns::ColAction) {
132       switch (role) {
133         case Qt::DisplayRole: return i18n("Not able to display this job.");
134         case Qt::ToolTipRole: return i18n("Could not find a plugin to display this job or it does not contain any data.");
135       }
136     }
137     return QVariant();
138   }
139 
140   // Show general information
141   if (index.column() == columns::ColAccount) {
142     // Account column
143     if (role == Qt::DisplayRole) {
144       return QVariant::fromValue(job.responsibleMyMoneyAccount().name());
145     } else if (role == Qt::DecorationRole) {
146       if (job.isLocked())
147         return Icons::get(Icon::TaskOngoing);
148 
149       switch (job.bankAnswerState()) {
150         case eMyMoney::OnlineJob::sendingState::acceptedByBank: return Icons::get(Icon::TaskComplete);
151         case eMyMoney::OnlineJob::sendingState::sendingError:
152         case eMyMoney::OnlineJob::sendingState::abortedByUser:
153         case eMyMoney::OnlineJob::sendingState::rejectedByBank: return Icons::get(Icon::TaskReject);
154         case eMyMoney::OnlineJob::sendingState::noBankAnswer: break;
155       }
156       if (job.sendDate().isValid()) {
157         return Icons::get(Icon::TaskAccepted);
158       } else if (!job.isValid()) {
159         return Icons::get(Icon::Warning);
160       }
161     } else if (role == Qt::ToolTipRole) {
162       if (job.isLocked())
163         return i18n("Job is being processed at the moment.");
164 
165       switch (job.bankAnswerState()) {
166         case eMyMoney::OnlineJob::sendingState::acceptedByBank: return i18nc("Arg 1 is a date/time", "This job was accepted by the bank on %1.", job.bankAnswerDate().toString(Qt::DefaultLocaleShortDate));
167         case eMyMoney::OnlineJob::sendingState::sendingError: return i18nc("Arg 1 is a date/time", "Sending this job failed (tried on %1).", job.sendDate().toString(Qt::DefaultLocaleShortDate));
168         case eMyMoney::OnlineJob::sendingState::abortedByUser: return i18n("Sending this job was manually aborted.");
169         case eMyMoney::OnlineJob::sendingState::rejectedByBank: return i18nc("Arg 1 is a date/time", "The bank rejected this job on %1.", job.bankAnswerDate().toString(Qt::DefaultLocaleShortDate));
170         case eMyMoney::OnlineJob::sendingState::noBankAnswer:
171           if (job.sendDate().isValid())
172             return i18nc("Arg 1 is a date/time", "The bank accepted this job on %1.", job.sendDate().toString(Qt::DefaultLocaleShortDate));
173           else if (!job.isValid())
174             return i18n("This job needs further editing and cannot be sent therefore.");
175           else
176             return i18n("This job is ready for sending.");
177       }
178     }
179 
180     return QVariant();
181   } else if (index.column() == columns::ColAction) {
182     if (role == Qt::DisplayRole)
183       return QVariant::fromValue(job.task()->jobTypeName());
184     return QVariant();
185   }
186 
187   // Show credit transfer data
188   try {
189     onlineJobTyped<creditTransfer> transfer(job);
190 
191     if (index.column() == columns::ColValue) {
192       if (role == Qt::DisplayRole)
193         return QVariant::fromValue(MyMoneyUtils::formatMoney(transfer.task()->value(), transfer.task()->currency()));
194       if (role == Qt::TextAlignmentRole)
195         return int (Qt::AlignVCenter | Qt::AlignRight);
196     } else if (index.column() == columns::ColDestination) {
197       if (role == Qt::DisplayRole) {
198         const payeeIdentifierTyped<payeeIdentifiers::ibanBic> ibanBic(transfer.constTask()->beneficiary());
199         return QVariant(ibanBic->ownerName());
200       }
201     }
202   } catch (const MyMoneyException &) {
203   }
204 
205   return QVariant();
206 }
207 
reloadAll()208 void onlineJobModel::reloadAll()
209 {
210   emit dataChanged(index(rowCount() - 1, 0), index(rowCount() - 1, columnCount() - 1));
211 }
212 
213 /**
214  * This method removes the rows from MyMoneyFile.
215  */
removeRow(int row,const QModelIndex & parent)216 bool onlineJobModel::removeRow(int row, const QModelIndex& parent)
217 {
218   if (parent.isValid())
219     return false;
220 
221   Q_ASSERT(m_jobIdList.count() < row);
222   MyMoneyFile* file = MyMoneyFile::instance();
223   MyMoneyFileTransaction transaction;
224   const onlineJob job = file->getOnlineJob(m_jobIdList[row]);
225   file->removeOnlineJob(job);
226   transaction.commit();
227   return true;
228 }
229 
230 /**
231  * This method removes the rows from MyMoneyFile.
232  */
removeRows(int row,int count,const QModelIndex & parent)233 bool onlineJobModel::removeRows(int row, int count, const QModelIndex & parent)
234 {
235   if (parent.isValid())
236     return false;
237 
238   Q_ASSERT(m_jobIdList.count() > row);
239   Q_ASSERT(m_jobIdList.count() >= (row + count));
240 
241   MyMoneyFile* file = MyMoneyFile::instance();
242   MyMoneyFileTransaction transaction;
243   for (int i = 0; i < count; ++i) {
244     const onlineJob job = file->getOnlineJob(m_jobIdList[row+i]);
245     file->removeOnlineJob(job);
246   }
247   transaction.commit();
248   return true;
249 }
250 
slotObjectAdded(eMyMoney::File::Object objType,const QString & id)251 void onlineJobModel::slotObjectAdded(eMyMoney::File::Object objType, const QString& id)
252 {
253   if (Q_LIKELY(objType != eMyMoney::File::Object::OnlineJob))
254     return;
255   beginInsertRows(QModelIndex(), rowCount(), rowCount());
256   m_jobIdList.append(id);
257   endInsertRows();
258 }
259 
slotObjectModified(eMyMoney::File::Object objType,const QString & id)260 void onlineJobModel::slotObjectModified(eMyMoney::File::Object objType, const QString& id)
261 {
262   if (Q_LIKELY(objType != eMyMoney::File::Object::OnlineJob))
263     return;
264 
265   int row = m_jobIdList.indexOf(id);
266   if (row != -1)
267     emit dataChanged(index(row, 0), index(row, columnCount() - 1));
268 }
269 
slotObjectRemoved(eMyMoney::File::Object objType,const QString & id)270 void onlineJobModel::slotObjectRemoved(eMyMoney::File::Object objType, const QString& id)
271 {
272   if (Q_LIKELY(objType != eMyMoney::File::Object::OnlineJob))
273     return;
274 
275   int row = m_jobIdList.indexOf(id);
276   if (row != -1) {
277     m_jobIdList.removeAll(id);
278     beginRemoveRows(QModelIndex(), row, row);
279     endRemoveRows();
280   }
281 }
282