1 /***************************************************************************
2  * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3  * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4  * SPDX-License-Identifier: GPL-3.0-or-later
5  ***************************************************************************/
6 /** @file
7  * This file is Skrooge plugin for MMB import / export.
8  *
9  * @author Stephane MANKOWSKI / Guillaume DE BURE
10  */
11 #include "skgimportpluginmmb.h"
12 
13 #include <qfile.h>
14 #include <qsqldatabase.h>
15 #include <qsqlerror.h>
16 
17 #include <klocalizedstring.h>
18 #include <kpluginfactory.h>
19 
20 #include "skgbankincludes.h"
21 #include "skgimportexportmanager.h"
22 #include "skgobjectbase.h"
23 #include "skgservices.h"
24 #include "skgtraces.h"
25 
26 /**
27  * This plugin factory.
28  */
K_PLUGIN_FACTORY(SKGImportPluginMmbFactory,registerPlugin<SKGImportPluginMmb> ();)29 K_PLUGIN_FACTORY(SKGImportPluginMmbFactory, registerPlugin<SKGImportPluginMmb>();)
30 
31 SKGImportPluginMmb::SKGImportPluginMmb(QObject* iImporter, const QVariantList& iArg)
32     : SKGImportPlugin(iImporter)
33 {
34     SKGTRACEINFUNC(10)
35     Q_UNUSED(iArg)
36 }
37 
38 SKGImportPluginMmb::~SKGImportPluginMmb()
39     = default;
40 
isImportPossible()41 bool SKGImportPluginMmb::isImportPossible()
42 {
43     SKGTRACEINFUNC(10)
44     return (m_importer == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("MMB"));
45 }
46 
importFile()47 SKGError SKGImportPluginMmb::importFile()
48 {
49     if (m_importer == nullptr) {
50         return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
51     }
52     SKGError err;
53     SKGTRACEINFUNCRC(2, err)
54 
55     {
56         QSqlDatabase originalDocument(QSqlDatabase::addDatabase(QStringLiteral("SKGSQLCIPHER"), QStringLiteral("originalDocument")));
57         originalDocument.setDatabaseName(m_importer->getLocalFileName());
58         if (!originalDocument.open()) {
59             // Set error message
60             QSqlError sqlErr = originalDocument.lastError();
61             err = SKGError(SQLLITEERROR + sqlErr.nativeErrorCode().toInt(), sqlErr.text());
62         }
63         IFOK(err) {
64             QMap<QString, SKGUnitObject> mapUnit;
65             err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "MMB"), 9);
66 
67             // Step 1 - units
68             IFOK(err) {
69                 SKGStringListList listUnits;
70                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT CURRENCYID, CURRENCYNAME, PFX_SYMBOL, SFX_SYMBOL, DECIMAL_POINT, GROUP_SEPARATOR, UNIT_NAME, CENT_NAME, SCALE, BASECONVRATE, CURRENCY_SYMBOL, "
71                         "(CASE WHEN EXISTS (SELECT 1 FROM INFOTABLE_V1 WHERE INFONAME='BASECURRENCYID' AND INFOVALUE=CURRENCYID) THEN 'Y' ELSE 'N' END) AS PRIMARYUNIT FROM CURRENCYFORMATS_V1"), listUnits);
72                 IFOK(err) {
73                     int nb = listUnits.count() - 1;
74                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
75                     for (int i = 0; !err && i < nb; ++i) {
76                         const QStringList& attributes = listUnits.at(i + 1);
77 
78                         SKGUnitObject unit(m_importer->getDocument());
79                         err = unit.setName(attributes.at(1));
80                         IFOK(err) {
81                             QString symbol = attributes.at(2);
82                             if (symbol.isEmpty()) {
83                                 symbol = attributes.at(3);
84                             }
85                             err = unit.setSymbol(symbol);
86                         }
87                         if (!err && attributes.at(11) == QStringLiteral("Y")) {
88                             err = unit.setType(SKGUnitObject::PRIMARY);
89                         }
90                         IFOKDO(err, unit.save())
91 
92                         mapUnit[attributes.at(0)] = unit;
93 
94                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
95                     }
96 
97                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
98                 }
99             }
100             IFOKDO(err, m_importer->getDocument()->stepForward(1))
101 
102             // Step 2 - bank and accounts
103             QMap<QString, SKGAccountObject> mapAccount;
104             IFOK(err) {
105                 SKGStringListList listAccounts;
106                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT ACCOUNTID, ACCOUNTNAME, ACCOUNTTYPE, ACCOUNTNUM, STATUS, NOTES, HELDAT, WEBSITE, CONTACTINFO, ACCESSINFO, INITIALBAL, FAVORITEACCT, CURRENCYID FROM ACCOUNTLIST_V1"), listAccounts);
107                 IFOK(err) {
108                     int nb = listAccounts.count() - 1;
109                     IFOKDO(err, m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import banks and accounts"), nb))
110                     for (int i = 0; !err && i < nb; ++i) {
111                         const QStringList& attributes = listAccounts.at(i + 1);
112 
113                         // Create bank
114                         SKGBankObject bank(m_importer->getDocument());
115                         IFOK(err) {
116                             QString bankName = attributes.at(6);
117                             if (bankName.isEmpty()) {
118                                 bankName = QStringLiteral("MMEX");
119                             }
120                             err = bank.setName(bankName);
121                         }
122                         IFOKDO(err, bank.save())
123 
124                         // Create account
125                         SKGAccountObject account;
126                         err = bank.addAccount(account);
127                         IFOKDO(err, account.setName(attributes.at(1)))
128                         IFOKDO(err, account.setType(attributes.at(2) == QStringLiteral("Checking") ? SKGAccountObject::CURRENT : SKGAccountObject::INVESTMENT))
129                         IFOKDO(err, account.setNumber(attributes.at(3)))
130                         IFOKDO(err, account.setComment(attributes.at(5)))
131                         IFOKDO(err, account.setAgencyAddress(attributes.at(8)))
132                         IFOKDO(err, account.bookmark(attributes.at(11) == QStringLiteral("TRUE")))
133                         IFOKDO(err, account.setClosed(attributes.at(4) != QStringLiteral("Open")))
134                         IFOKDO(err, account.save())
135                         IFOKDO(err, account.setInitialBalance(SKGServices::stringToDouble(attributes.at(10)), mapUnit[attributes.at(12)]))
136                         IFOKDO(err, account.save())
137 
138                         mapAccount[attributes.at(0)] = account;
139 
140                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
141                     }
142 
143                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
144                 }
145             }
146             IFOKDO(err, m_importer->getDocument()->stepForward(2))
147 
148             // Step 3 - categories
149             QMap<QString, SKGCategoryObject> mapCategory;
150             IFOK(err) {
151                 SKGStringListList listCategories;
152                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT CATEGID, CATEGNAME FROM CATEGORY_V1"), listCategories);
153                 IFOK(err) {
154                     int nb = listCategories.count() - 1;
155                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import categories"), nb);
156                     for (int i = 0; !err && i < nb; ++i) {
157                         const QStringList& attributes = listCategories.at(i + 1);
158 
159                         SKGCategoryObject cat(m_importer->getDocument());
160                         err = cat.setName(attributes.at(1));
161                         IFOKDO(err, cat.save())
162 
163                         mapCategory[attributes.at(0)] = cat;
164 
165                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
166                     }
167 
168                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
169                 }
170             }
171             IFOKDO(err, m_importer->getDocument()->stepForward(3))
172 
173             // Step 4 - sub categories
174             QMap<QString, SKGCategoryObject> mapSubCategory;
175             IFOK(err) {
176                 SKGStringListList listCategories;
177                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT SUBCATEGID, SUBCATEGNAME, CATEGID FROM SUBCATEGORY_V1"), listCategories);
178                 IFOK(err) {
179                     int nb = listCategories.count() - 1;
180                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import categories"), nb);
181                     for (int i = 0; !err && i < nb; ++i) {
182                         const QStringList& attributes = listCategories.at(i + 1);
183 
184                         SKGCategoryObject cat(m_importer->getDocument());
185                         err = cat.setName(attributes.at(1));
186                         IFOKDO(err, cat.setParentCategory(mapCategory[attributes.at(2)]))
187                         IFOKDO(err, cat.save())
188 
189                         mapSubCategory[attributes.at(0)] = cat;
190 
191                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
192                     }
193 
194                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
195                 }
196             }
197             IFOKDO(err, m_importer->getDocument()->stepForward(4))
198 
199             // Step 5 - payee
200             QMap<QString, SKGPayeeObject> mapPayee;
201             IFOK(err) {
202                 SKGStringListList listPayee;
203                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT PAYEEID, PAYEENAME FROM PAYEE_V1"), listPayee);
204                 IFOK(err) {
205                     int nb = listPayee.count() - 1;
206                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import payees"), nb);
207                     for (int i = 0; !err && i < nb; ++i) {
208                         const QStringList& attributes = listPayee.at(i + 1);
209 
210                         SKGPayeeObject payee(m_importer->getDocument());
211                         err = payee.setName(attributes.at(1));
212                         IFOKDO(err, payee.save())
213 
214                         mapPayee[attributes.at(0)] = payee;
215 
216                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
217                     }
218 
219                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
220                 }
221             }
222             IFOKDO(err, m_importer->getDocument()->stepForward(5))
223 
224             // Step 6 - operations
225             QMap<QString, SKGOperationObject> mapOperation;
226             IFOK(err) {
227                 SKGStringListList listOperations;
228                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT * FROM ("
229                         "SELECT TRANSID, ACCOUNTID, TOACCOUNTID, PAYEEID, TRANSCODE, TRANSAMOUNT, STATUS, TRANSACTIONNUMBER, NOTES, CATEGID, SUBCATEGID, TRANSDATE, FOLLOWUPID, TOTRANSAMOUNT, 'N/A'  , 'N/A', 'N/A' FROM CHECKINGACCOUNT_V1 UNION "
230                         "SELECT BDID,    ACCOUNTID, TOACCOUNTID, PAYEEID, TRANSCODE, TRANSAMOUNT, STATUS, TRANSACTIONNUMBER, NOTES, CATEGID, SUBCATEGID, TRANSDATE, FOLLOWUPID, TOTRANSAMOUNT, REPEATS, NEXTOCCURRENCEDATE, NUMOCCURRENCES FROM BILLSDEPOSITS_V1)"), listOperations);
231                 IFOK(err) {
232                     int nb = listOperations.count() - 1;
233                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import operations"), nb);
234                     for (int i = 0; !err && i < nb; ++i) {
235                         const QStringList& attributes = listOperations.at(i + 1);
236                         if (attributes.at(6) != QStringLiteral("V")) {  // Void
237                             bool recurrent = (attributes.at(14) != QStringLiteral("N/A"));
238                             const QString& idTarget = attributes.at(2);
239                             SKGAccountObject acc = mapAccount[attributes.at(1)];
240                             SKGUnitObject unit;
241                             IFOKDO(err, acc.getUnit(unit))
242 
243                             SKGOperationObject op;
244                             IFOKDO(err, acc.addOperation(op, true))
245                             IFOK(err) {
246                                 const QString& id = attributes.at(3);
247                                 if (id != QStringLiteral("-1")) {
248                                     err = op.setPayee(mapPayee[id]);
249                                 }
250                             }
251                             IFOKDO(err, op.setNumber(attributes.at(7)))
252                             IFOKDO(err, op.setComment(attributes.at(8)))
253                             IFOKDO(err, op.setDate(SKGServices::stringToTime(attributes.at(11)).date()))
254                             IFOKDO(err, op.setAttribute(QStringLiteral("t_imported"), QStringLiteral("T")))
255                             IFOKDO(err, op.setImportID("MMEX-" % attributes.at(0)))
256                             IFOKDO(err, op.setUnit(unit))
257                             IFOKDO(err, op.bookmark(attributes.at(6) == QStringLiteral("F")))
258                             IFOKDO(err, op.setTemplate(recurrent))
259                             IFOKDO(err, op.setStatus(attributes.at(6) == QStringLiteral("R") ? SKGOperationObject::CHECKED : SKGOperationObject::NONE))
260                             IFOKDO(err, op.save())
261 
262                             // Get splits
263                             IFOK(err) {
264                                 SKGStringListList listSubOperations;
265                                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT SPLITTRANSID, CATEGID, SUBCATEGID, SPLITTRANSAMOUNT FROM ") % (recurrent ? "BUDGET" : "") % "SPLITTRANSACTIONS_V1 WHERE TRANSID=" % attributes.at(0), listSubOperations);
266                                 IFOK(err) {
267                                     int nb2 = listSubOperations.count() - 1;
268                                     if (nb2 <= 0) {
269                                         // No split
270                                         SKGSubOperationObject subop;
271                                         IFOKDO(err, op.addSubOperation(subop))
272                                         IFOK(err) {
273                                             QString id = attributes.at(10);
274                                             if (id == QStringLiteral("-1")) {
275                                                 id = attributes.at(9);
276                                                 if (id != QStringLiteral("-1")) {
277                                                     err = subop.setCategory(mapSubCategory[id]);
278                                                 }
279                                             } else {
280                                                 err = subop.setCategory(mapCategory[id]);
281                                             }
282                                         }
283                                         IFOK(err) {
284                                             double q = SKGServices::stringToDouble(attributes.at(5));
285                                             if (attributes.at(4) == QStringLiteral("Withdrawal") || idTarget != QStringLiteral("-1")) {
286                                                 q = -q;
287                                             }
288                                             err = subop.setQuantity(q);
289                                         }
290                                         IFOKDO(err, subop.save())
291                                     } else {
292                                         // Has splits
293                                         for (int j = 0; !err && j < nb2; ++j) {
294                                             const QStringList& attributesSubOp = listSubOperations.at(j + 1);
295 
296                                             SKGSubOperationObject subop;
297                                             IFOKDO(err, op.addSubOperation(subop))
298                                             IFOK(err) {
299                                                 QString id = attributesSubOp.at(2);
300                                                 if (id == QStringLiteral("-1")) {
301                                                     id = attributesSubOp.at(1);
302                                                     if (id != QStringLiteral("-1")) {
303                                                         err = subop.setCategory(mapCategory[id]);
304                                                     }
305                                                 } else {
306                                                     err = subop.setCategory(mapSubCategory[id]);
307                                                 }
308                                             }
309                                             IFOK(err) {
310                                                 double q = SKGServices::stringToDouble(attributesSubOp.at(3));
311                                                 if (attributes.at(4) == QStringLiteral("Withdrawal") || idTarget != QStringLiteral("-1")) {
312                                                     q = -q;
313                                                 }
314                                                 err = subop.setQuantity(q);
315                                             }
316                                             IFOKDO(err, subop.save())
317                                         }
318                                     }
319                                 }
320                             }
321 
322                             // Case Transfer
323                             if (!err && idTarget != QStringLiteral("-1")) {
324                                 SKGOperationObject op2;
325                                 err = op.duplicate(op2, op.getDate());
326                                 IFOKDO(err, op2.setStatus(op.getStatus()))
327                                 IFOKDO(err, op2.bookmark(op.isBookmarked()))
328                                 IFOKDO(err, op2.setAttribute(QStringLiteral("t_imported"), QStringLiteral("T")))
329                                 IFOKDO(err, op2.setImportID("MMEX-" % attributes.at(0) % "_TR"))
330                                 IFOKDO(err, op2.save())
331 
332                                 SKGObjectBase::SKGListSKGObjectBase subops;
333                                 IFOKDO(err, op.getSubOperations(subops))
334                                 if (!err && !subops.isEmpty()) {
335                                     SKGSubOperationObject subop2(subops.at(0));
336                                     err = subop2.setQuantity(-subop2.getQuantity());
337                                     IFOKDO(err, subop2.save())
338                                 }
339                                 IFOKDO(err, op.setParentAccount(mapAccount[idTarget]))
340                                 IFOKDO(err, op.setGroupOperation(op2))
341                                 IFOKDO(err, op.save())
342                             }
343 
344                             // Create recurrent transaction
345                             if (recurrent) {
346                                 SKGRecurrentOperationObject recu;
347                                 IFOKDO(err, op.addRecurrentOperation(recu))
348                                 IFOKDO(err, recu.setDate(SKGServices::stringToTime(attributes.at(15)).date()))
349                                 int nbTimes = SKGServices::stringToInt(attributes.at(16));
350                                 if (!err && nbTimes != -1) {
351                                     err = recu.setTimeLimit(nbTimes);
352                                     IFOKDO(err, recu.timeLimit(true))
353                                 }
354                                 int repeats = SKGServices::stringToInt(attributes.at(14));
355                                 IFOK(err) {
356                                     switch (repeats) {
357                                     case 1:
358                                         // Weekly
359                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::WEEK);
360                                         IFOKDO(err, recu.setPeriodIncrement(1))
361                                         break;
362                                     case 2:
363                                         // Bi-Weekly
364                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::WEEK);
365                                         IFOKDO(err, recu.setPeriodIncrement(2))
366                                         break;
367                                     case 3:
368                                         // Monthly
369                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::MONTH);
370                                         IFOKDO(err, recu.setPeriodIncrement(1))
371                                         break;
372                                     case 4:
373                                         // Bi-Monthly
374                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::MONTH);
375                                         IFOKDO(err, recu.setPeriodIncrement(2))
376                                         break;
377                                     case 5:
378                                         // Quarterly
379                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::MONTH);
380                                         IFOKDO(err, recu.setPeriodIncrement(3))
381                                         break;
382                                     case 6:
383                                         // Half yearly
384                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::MONTH);
385                                         IFOKDO(err, recu.setPeriodIncrement(6))
386                                         break;
387                                     case 7:
388                                         // Yearly
389                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::YEAR);
390                                         IFOKDO(err, recu.setPeriodIncrement(1))
391                                         break;
392                                     case 8:
393                                         // Four months
394                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::MONTH);
395                                         IFOKDO(err, recu.setPeriodIncrement(4))
396                                         break;
397                                     case 9:
398                                         // Four weeks
399                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::WEEK);
400                                         IFOKDO(err, recu.setPeriodIncrement(4))
401                                         break;
402                                     case 10:
403                                         // Daily
404                                         err = recu.setPeriodUnit(SKGRecurrentOperationObject::DAY);
405                                         IFOKDO(err, recu.setPeriodIncrement(1))
406                                         break;
407 
408                                     default:
409                                         break;
410                                     }
411                                 }
412                                 IFOKDO(err, recu.save(true, false))
413                             }
414                             mapOperation[attributes.at(0)] = op;
415                         }
416 
417                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
418                     }
419 
420                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
421                 }
422             }
423             IFOKDO(err, m_importer->getDocument()->stepForward(6))
424 
425             // Step 7 - stock
426             IFOK(err) {
427                 SKGStringListList listStock;
428                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT STOCKID, HELDAT, PURCHASEDATE, STOCKNAME, SYMBOL, NUMSHARES, PURCHASEPRICE, NOTES, CURRENTPRICE, VALUE, COMMISSION FROM STOCK_V1"), listStock);
429                 IFOK(err) {
430                     int nb = listStock.count() - 1;
431                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import stocks"), nb);
432                     for (int i = 0; !err && i < nb; ++i) {
433                         const QStringList& attributes = listStock.at(i + 1);
434 
435                         // Create unit
436                         SKGUnitObject unit(m_importer->getDocument());
437                         err = unit.setName(attributes.at(3));
438                         IFOKDO(err, unit.setSymbol(attributes.at(4)))
439                         IFOKDO(err, unit.setType(SKGUnitObject::SHARE))
440                         IFOKDO(err, unit.save())
441 
442                         SKGUnitValueObject unitValue;
443                         IFOKDO(err, unit.addUnitValue(unitValue))
444                         IFOKDO(err, unitValue.setDate(SKGServices::stringToTime(attributes.at(2)).date()))
445                         IFOKDO(err, unitValue.setQuantity(SKGServices::stringToDouble(attributes.at(6))))
446                         IFOKDO(err, unitValue.save(true, false))
447 
448                         SKGUnitValueObject unitValue2;
449                         IFOKDO(err, unit.addUnitValue(unitValue2))
450                         IFOKDO(err, unitValue2.setDate(QDate::currentDate()))
451                         IFOKDO(err, unitValue2.setQuantity(SKGServices::stringToDouble(attributes.at(8))))
452                         IFOKDO(err, unitValue2.save(true, false))
453 
454                         // Create operation
455                         SKGAccountObject acc = mapAccount[attributes.at(1)];
456                         SKGUnitObject unitCurrency;
457                         IFOKDO(err, acc.getUnit(unitCurrency))
458 
459                         SKGOperationObject op;
460                         IFOKDO(err, acc.addOperation(op, true))
461                         IFOKDO(err, op.setComment(attributes.at(7)))
462                         IFOKDO(err, op.setDate(SKGServices::stringToTime(attributes.at(2)).date()))
463                         IFOKDO(err, op.setAttribute(QStringLiteral("t_imported"), QStringLiteral("T")))
464                         IFOKDO(err, op.setImportID("MMEX-STOCK-" % attributes.at(0)))
465                         IFOKDO(err, op.setUnit(unit))
466                         IFOKDO(err, op.save())
467 
468                         SKGSubOperationObject subop;
469                         IFOKDO(err, op.addSubOperation(subop))
470                         IFOKDO(err, subop.setQuantity(SKGServices::stringToDouble(attributes.at(5))))
471                         IFOKDO(err, subop.save(true, false))
472 
473                         /*SKGOperationObject op2;
474                         if(!err) err = acc.addOperation(op2, true);
475                         if(!err) err = op2.setComment(attributes.at(7));
476                         if(!err) err = op2.setDate(SKGServices::stringToTime(attributes.at(2)).date());
477                         if(!err) err = op2.setAttribute(QStringLiteral("t_imported"), QStringLiteral("T"));
478                         if(!err) err = op2.setImportID("MMEX-STOCK-" % attributes.at(0)% "_TR");
479                         if(!err) err = op2.setUnit(unitCurrency);
480                         if(!err) err = op2.save();
481 
482                         SKGSubOperationObject subop2;
483                         if(!err) err = op2.addSubOperation(subop2);
484                         if(!err) err = subop2.setQuantity(-SKGServices::stringToDouble(attributes.at(5))*SKGServices::stringToDouble(attributes.at(6)));
485                         if(!err) err = subop2.save();
486 
487                         if(!err) err = op.setGroupOperation(op2);
488                         if(!err) err = op.save();*/
489 
490                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
491                     }
492 
493                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
494                 }
495             }
496             IFOKDO(err, m_importer->getDocument()->stepForward(7))
497 
498             // Step 8 - asset
499             IFOK(err) {
500                 SKGStringListList listAssets;
501                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT ASSETID, STARTDATE, ASSETNAME, VALUE, VALUECHANGE, NOTES, VALUECHANGERATE, ASSETTYPE FROM ASSETS_V1"), listAssets);
502                 IFOK(err) {
503                     int nb = listAssets.count() - 1;
504                     if (nb != 0) {
505                         // Create account
506                         // Create bank
507                         SKGBankObject bank(m_importer->getDocument());
508                         IFOKDO(err, bank.setName(QStringLiteral("MMEX")))
509                         IFOKDO(err, bank.save())
510 
511                         // Create account
512                         SKGAccountObject account;
513                         err = bank.addAccount(account);
514                         IFOKDO(err, account.setName(i18nc("Noun, a type of account", "Assets")))
515                         IFOKDO(err, account.setType(SKGAccountObject::ASSETS))
516                         IFOKDO(err, account.save())
517 
518                         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import assets"), nb);
519                         for (int i = 0; !err && i < nb; ++i) {
520                             const QStringList& attributes = listAssets.at(i + 1);
521 
522                             // Create unit
523                             SKGUnitObject unit(m_importer->getDocument());
524                             err = unit.setName(attributes.at(2));
525                             IFOKDO(err, unit.setSymbol(attributes.at(2)))
526                             IFOKDO(err, unit.setType(SKGUnitObject::OBJECT))
527                             IFOKDO(err, unit.setInternetCode(QStringLiteral("=") % (attributes.at(4) == QStringLiteral("Depreciates") ? QStringLiteral("-") : QStringLiteral("+")) % attributes.at(6)))
528                             IFOKDO(err, unit.save())
529 
530                             SKGUnitValueObject unitValue;
531                             IFOKDO(err, unit.addUnitValue(unitValue))
532                             IFOKDO(err, unitValue.setDate(SKGServices::stringToTime(attributes.at(1)).date()))
533                             IFOKDO(err, unitValue.setQuantity(SKGServices::stringToDouble(attributes.at(3))))
534                             IFOKDO(err, unitValue.save(true, false))
535 
536                             // Create operation
537                             SKGOperationObject op;
538                             IFOKDO(err, account.addOperation(op, true))
539                             IFOKDO(err, op.setComment(attributes.at(5)))
540                             IFOKDO(err, op.setDate(SKGServices::stringToTime(attributes.at(1)).date()))
541                             IFOKDO(err, op.setAttribute(QStringLiteral("t_imported"), QStringLiteral("T")))
542                             IFOKDO(err, op.setImportID("MMEX-ASSET-" % attributes.at(0)))
543                             IFOKDO(err, op.setUnit(unit))
544                             IFOKDO(err, op.save())
545 
546                             SKGSubOperationObject subop;
547                             IFOKDO(err, op.addSubOperation(subop))
548                             IFOKDO(err, subop.setQuantity(1.0))
549                             IFOKDO(err, subop.save(true, false))
550 
551                             IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
552                         }
553 
554                         SKGENDTRANSACTION(m_importer->getDocument(),  err)
555                     }
556                 }
557             }
558             IFOKDO(err, m_importer->getDocument()->stepForward(8))
559 
560             // Step 9 - budgets
561             IFOK(err) {
562                 SKGStringListList listBudgets;
563                 err = SKGServices::executeSelectSqliteOrder(originalDocument, QStringLiteral("SELECT BUDGETENTRYID, (SELECT Y.BUDGETYEARNAME FROM BUDGETYEAR_V1 Y WHERE Y.BUDGETYEARID=BUDGETTABLE_V1.BUDGETYEARID), CATEGID, SUBCATEGID, PERIOD, AMOUNT FROM BUDGETTABLE_V1"), listBudgets);
564                 IFOK(err) {
565                     int nb = listBudgets.count() - 1;
566                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import budgets"), nb);
567                     for (int i = 0; !err && i < nb; ++i) {
568                         const QStringList& attributes = listBudgets.at(i + 1);
569 
570                         const QString& period = attributes.at(4);
571 
572                         int step = 0;
573                         double coef = 0;
574                         if (period == QStringLiteral("Weekly")) {
575                             coef = 52.0 / 12.0;
576                             step = 1;
577                         } else if (period == QStringLiteral("Monthly")) {
578                             coef = 1;
579                             step = 1;
580                         } else if (period == QStringLiteral("Bi-Weekly")) {
581                             coef = 52.0 / 12.0 / 2.0;
582                             step = 1;
583                         } else if (period == QStringLiteral("Bi-Monthly")) {
584                             coef = 1;
585                             step = 2;
586                         } else if (period == QStringLiteral("Quarterly")) {
587                             coef = 1;
588                             step = 4;
589                         } else if (period == QStringLiteral("Half-Yearly")) {
590                             coef = 1;
591                             step = 6;
592                         } else if (period == QStringLiteral("Yearly")) {
593                             coef = 1;
594                             step = 12;
595                         }
596 
597                         if (step != 0) {
598                             for (int j = 0; !err && j < 12; j = j + step) {
599                                 SKGBudgetObject bug(m_importer->getDocument());
600                                 err = bug.setYear(SKGServices::stringToInt(attributes.at(1)));
601                                 IFOKDO(err, bug.setMonth(step == 12 ? 0 : j + 1))
602                                 IFOK(err) {
603                                     QString id = attributes.at(3);
604                                     if (id == QStringLiteral("-1")) {
605                                         id = attributes.at(2);
606                                         if (id != QStringLiteral("-1")) {
607                                             err = bug.setCategory(mapCategory[id]);
608                                         }
609                                     } else {
610                                         err = bug.setCategory(mapSubCategory[id]);
611                                     }
612                                 }
613                                 IFOKDO(err, bug.setBudgetedAmount(coef * SKGServices::stringToDouble(attributes.at(5))))
614                                 IFOKDO(err, bug.save())
615                             }
616                         }
617 
618                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
619                     }
620 
621                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
622                 }
623             }
624             IFOKDO(err, m_importer->getDocument()->stepForward(9))
625 
626             SKGENDTRANSACTION(m_importer->getDocument(),  err)
627 
628             IFOKDO(err, m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE")))
629         }
630         originalDocument.close();
631     }
632     QSqlDatabase::removeDatabase(QStringLiteral("originalDocument"));
633     return err;
634 }
635 
getMimeTypeFilter() const636 QString SKGImportPluginMmb::getMimeTypeFilter() const
637 {
638     return "*.mmb|" % i18nc("A file format", "Money Manager Ex document");
639 }
640 
641 #include <skgimportpluginmmb.moc>
642