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 KMY import / export.
8 *
9 * @author Stephane MANKOWSKI / Guillaume DE BURE
10 */
11 #include "skgimportpluginkmy.h"
12
13 #include <kcompressiondevice.h>
14 #include <kpluginfactory.h>
15
16 #include <qdom.h>
17 #include <qmath.h>
18
19 #include "skgbankincludes.h"
20 #include "skgimportexportmanager.h"
21 #include "skgobjectbase.h"
22 #include "skgpayeeobject.h"
23 #include "skgservices.h"
24 #include "skgtraces.h"
25
26 /**
27 * Operations treated.
28 */
29 QSet<QString> SKGImportPluginKmy::m_opTreated;
30
31 /**
32 * Map id / unit.
33 */
34 QMap<QString, SKGUnitObject> SKGImportPluginKmy::m_mapIdUnit;
35
36 /**
37 * Map id / account.
38 */
39 QMap<QString, SKGAccountObject> SKGImportPluginKmy::m_mapIdAccount;
40
41 /**
42 * Map id / category.
43 */
44 QMap<QString, SKGCategoryObject> SKGImportPluginKmy::m_mapIdCategory;
45
46 /**
47 * Map id / payee.
48 */
49 QMap<QString, SKGPayeeObject> SKGImportPluginKmy::m_mapIdPayee;
50
51 /**
52 * This plugin factory.
53 */
K_PLUGIN_FACTORY(SKGImportPluginKmyFactory,registerPlugin<SKGImportPluginKmy> ();)54 K_PLUGIN_FACTORY(SKGImportPluginKmyFactory, registerPlugin<SKGImportPluginKmy>();)
55
56 SKGImportPluginKmy::SKGImportPluginKmy(QObject* iImporter, const QVariantList& iArg)
57 : SKGImportPlugin(iImporter)
58 {
59 SKGTRACEINFUNC(10)
60 Q_UNUSED(iArg)
61 }
62
63 SKGImportPluginKmy::~SKGImportPluginKmy()
64 = default;
65
isImportPossible()66 bool SKGImportPluginKmy::isImportPossible()
67 {
68 SKGTRACEINFUNC(10)
69 return isExportPossible();
70 }
71
importSecurities(QDomElement & docElem)72 SKGError SKGImportPluginKmy::importSecurities(QDomElement& docElem)
73 {
74 SKGError err;
75 QDomElement securities = docElem.firstChildElement(QStringLiteral("SECURITIES"));
76 if (!err && !securities.isNull()) {
77 SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-SECURITIES", err)
78 QDomNodeList securityList = securities.elementsByTagName(QStringLiteral("SECURITY"));
79 int nb = securityList.count();
80 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
81 for (int i = 0; !err && i < nb; ++i) {
82 QDomElement security = securityList.at(i).toElement();
83 QString unitName = security.attribute(QStringLiteral("name"));
84
85 // We try a creation
86 SKGUnitObject unitObj(m_importer->getDocument());
87 SKGUnitObject::createCurrencyUnit(m_importer->getDocument(), unitName, unitObj);
88
89 if (!err && (unitObj.getID() == 0)) {
90 // Creation of unit
91 err = unitObj.setName(unitName);
92 QString symbol = security.attribute(QStringLiteral("symbol"));
93 if (symbol.isEmpty()) {
94 symbol = unitName;
95 }
96 IFOKDO(err, unitObj.setSymbol(symbol))
97 IFOKDO(err, unitObj.setCountry(security.attribute(QStringLiteral("trading-market"))))
98 IFOKDO(err, unitObj.setType(SKGUnitObject::SHARE))
99 IFOK(err) {
100 // Set pairs
101 QDomNodeList pairList = security.elementsByTagName(QStringLiteral("PAIR"));
102 int nb2 = pairList.count();
103 for (int j = 0; !err && j < nb2; ++j) {
104 QDomElement pair = pairList.at(j).toElement();
105 if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("kmm-security-id")) {
106 err = unitObj.setInternetCode(pair.attribute(QStringLiteral("value")));
107 }
108 }
109 }
110 IFOKDO(err, unitObj.save())
111 }
112
113 m_mapIdUnit[security.attribute(QStringLiteral("id"))] = unitObj;
114
115 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
116 }
117
118 SKGENDTRANSACTION(m_importer->getDocument(), err)
119 }
120 return err;
121 }
122
importPrices(QDomElement & docElem)123 SKGError SKGImportPluginKmy::importPrices(QDomElement& docElem)
124 {
125 SKGError err;
126 QDomElement prices = docElem.firstChildElement(QStringLiteral("PRICES"));
127 if (!err && !prices.isNull()) {
128 SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-PRICES", err)
129 QDomNodeList pricepairList = prices.elementsByTagName(QStringLiteral("PRICEPAIR"));
130 int nb = pricepairList.count();
131 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
132 for (int i = 0; !err && i < nb; ++i) {
133 QDomElement pricepair = pricepairList.at(i).toElement();
134
135 SKGUnitObject unitObj = m_mapIdUnit.value(pricepair.attribute(QStringLiteral("from")));
136 if (unitObj.getID() != 0) {
137 // Unit is existing
138 QDomNodeList pricesList = pricepair.elementsByTagName(QStringLiteral("PRICE"));
139 int nb2 = pricesList.count();
140 for (int j = 0; !err && j < nb2; ++j) {
141 QDomElement price = pricesList.at(j).toElement();
142
143 SKGUnitValueObject unitValObj;
144 err = unitObj.addUnitValue(unitValObj);
145 IFOKDO(err, unitValObj.setDate(QDate::fromString(price.attribute(QStringLiteral("date")), QStringLiteral("yyyy-MM-dd"))))
146 IFOKDO(err, unitValObj.setQuantity(toKmyValue(price.attribute(QStringLiteral("price")))))
147 IFOKDO(err, unitValObj.save(true, false))
148 }
149 }
150
151 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
152 }
153
154 SKGENDTRANSACTION(m_importer->getDocument(), err)
155 }
156 return err;
157 }
158
importInstitutions(QMap<QString,SKGBankObject> & mapIdBank,QDomElement & docElem)159 SKGError SKGImportPluginKmy::importInstitutions(QMap<QString, SKGBankObject>& mapIdBank, QDomElement& docElem)
160 {
161 SKGError err;
162 QDomElement institutions = docElem.firstChildElement(QStringLiteral("INSTITUTIONS"));
163 if (!err && !institutions.isNull()) {
164 SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-INSTITUTIONS", err)
165 QDomNodeList institutionList = institutions.elementsByTagName(QStringLiteral("INSTITUTION"));
166 int nb = institutionList.count();
167 for (int i = 0; !err && i < nb; ++i) {
168 // Get bank object
169 QDomElement bank = institutionList.at(i).toElement();
170 SKGBankObject bankObject(m_importer->getDocument());
171 err = bankObject.setName(bank.attribute(QStringLiteral("name")));
172 IFOKDO(err, bankObject.setNumber(bank.attribute(QStringLiteral("sortcode"))))
173 IFOKDO(err, bankObject.save())
174 mapIdBank[bank.attribute(QStringLiteral("id"))] = bankObject;
175 }
176 }
177 return err;
178 }
179
importPayees(QMap<QString,SKGPayeeObject> & mapIdPayee,QDomElement & docElem)180 SKGError SKGImportPluginKmy::importPayees(QMap<QString, SKGPayeeObject>& mapIdPayee, QDomElement& docElem)
181 {
182 SKGError err;
183 QDomElement payees = docElem.firstChildElement(QStringLiteral("PAYEES"));
184 if (!err && !payees.isNull()) {
185 SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-PAYEES", err)
186 QDomNodeList payeeList = payees.elementsByTagName(QStringLiteral("PAYEE"));
187 int nb = payeeList.count();
188 for (int i = 0; !err && i < nb; ++i) {
189 // Get account object
190 QDomElement payee = payeeList.at(i).toElement();
191 QDomElement address = payee.firstChildElement(QStringLiteral("ADDRESS"));
192 SKGPayeeObject payeeObject;
193 err = SKGPayeeObject::createPayee(m_importer->getDocument(), payee.attribute(QStringLiteral("name")), payeeObject);
194 IFOK(err) {
195 QString add = address.attribute(QStringLiteral("street")) % ' ' % address.attribute(QStringLiteral("postcode")) % ' ' % address.attribute(QStringLiteral("city")) % ' ' % address.attribute(QStringLiteral("state")) % ' ' % address.attribute(QStringLiteral("telephone"));
196 add.replace(QStringLiteral(" "), QStringLiteral(" "));
197 err = payeeObject.setAddress(add.trimmed());
198 IFOKDO(err, payeeObject.save())
199 }
200 IFOK(err) {
201 mapIdPayee[payee.attribute(QStringLiteral("id"))] = payeeObject;
202 }
203 }
204 }
205 return err;
206 }
207
importTransactions(QDomElement & docElem,SKGAccountObject & kmymoneyTemporaryAccount,QMap<QString,SKGPayeeObject> & mapIdPayee)208 SKGError SKGImportPluginKmy::importTransactions(QDomElement& docElem, SKGAccountObject& kmymoneyTemporaryAccount, QMap<QString, SKGPayeeObject>& mapIdPayee)
209 {
210 SKGError err;
211 SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-TRANSACTION", err)
212 QDomNodeList transactionList = docElem.elementsByTagName(QStringLiteral("TRANSACTION"));
213 int nb = transactionList.count();
214 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import operations"), nb);
215 QVector<QDomNode> suboperationsList;
216 for (int i = 0; !err && i < nb; ++i) {
217 // Get operation object
218 QDomElement operation = transactionList.at(i).toElement();
219
220 SKGOperationObject operationObj;
221 err = kmymoneyTemporaryAccount.addOperation(operationObj, true);
222 IFOKDO(err, operationObj.setDate(QDate::fromString(operation.attribute(QStringLiteral("postdate")), QStringLiteral("yyyy-MM-dd"))))
223 IFOKDO(err, operationObj.setComment(operation.attribute(QStringLiteral("memo"))))
224 IFOKDO(err, operationObj.setImported(true))
225 IFOKDO(err, operationObj.setImportID("KMY-" % operation.attribute(QStringLiteral("id"))))
226 IFOK(err) {
227 QString unitName = operation.attribute(QStringLiteral("commodity"));
228 if (unitName.isEmpty()) {
229 unitName = QStringLiteral("??");
230 }
231 SKGUnitObject unit(m_importer->getDocument());
232 err = unit.setName(unitName);
233 IFOKDO(err, unit.setSymbol(unitName))
234 IFOK(err) {
235 if (unit.exist()) {
236 err = unit.load();
237 } else {
238 err = unit.save();
239 }
240
241 IFOKDO(err, operationObj.setUnit(unit))
242 }
243 }
244 IFOKDO(err, operationObj.save(false, false))
245
246 // Is it a schedule ?
247 IFOK(err) {
248 QDomElement recu = operation.parentNode().toElement();
249 if (recu.tagName() == QStringLiteral("SCHEDULED_TX")) {
250 // Yes ==> creation of the schedule
251 IFOKDO(err, operationObj.load())
252 IFOKDO(err, operationObj.setTemplate(true))
253 IFOKDO(err, operationObj.save(true, false))
254
255 // Yes ==> creation of the schedule
256 SKGRecurrentOperationObject recuObj;
257 IFOKDO(err, operationObj.addRecurrentOperation(recuObj))
258 IFOKDO(err, recuObj.setDate(operationObj.getDate()))
259 IFOKDO(err, recuObj.autoWriteEnabled(recu.attribute(QStringLiteral("autoEnter")) == QStringLiteral("1")))
260 IFOKDO(err, recuObj.setAutoWriteDays(0))
261
262 int occu = SKGServices::stringToInt(recu.attribute(QStringLiteral("occurenceMultiplier")));
263 QString occuType = recu.attribute(QStringLiteral("occurence")); // krazy:exclude=spelling
264 SKGRecurrentOperationObject::PeriodUnit period;
265 if (occuType == QStringLiteral("32") ||
266 occuType == QStringLiteral("1024") ||
267 occuType == QStringLiteral("256") ||
268 occuType == QStringLiteral("8192")) {
269 period = SKGRecurrentOperationObject::MONTH;
270 } else if (occuType == QStringLiteral("1")) {
271 period = SKGRecurrentOperationObject::DAY;
272 IFOKDO(err, recuObj.timeLimit(true))
273 IFOKDO(err, recuObj.setTimeLimit(1))
274 } else if (occuType == QStringLiteral("2")) {
275 period = SKGRecurrentOperationObject::DAY;
276 } else if (occuType == QStringLiteral("4")) {
277 period = SKGRecurrentOperationObject::WEEK;
278 } else if (occuType == QStringLiteral("18")) {
279 period = SKGRecurrentOperationObject::WEEK;
280 occu *= 2;
281 } else {
282 period = SKGRecurrentOperationObject::YEAR;
283 }
284
285 IFOKDO(err, recuObj.setPeriodIncrement(occu))
286 IFOKDO(err, recuObj.setPeriodUnit(period))
287
288 IFOK(err) {
289 QString endDate = recu.attribute(QStringLiteral("endDate"));
290 if (!endDate.isEmpty()) {
291 IFOKDO(err, recuObj.timeLimit(true))
292 IFOKDO(err, recuObj.setTimeLimit(QDate::fromString(recu.attribute(QStringLiteral("endDate")), QStringLiteral("yyyy-MM-dd"))))
293 }
294 }
295
296 if (occuType == QStringLiteral("1") && !recu.attribute(QStringLiteral("lastPayment")).isEmpty()) {
297 // Single schedule already done
298 IFOKDO(err, recuObj.timeLimit(true))
299 IFOKDO(err, recuObj.setTimeLimit(0))
300 }
301 IFOKDO(err, recuObj.save(true, false))
302 }
303 }
304
305 // Get splits
306 bool parentSet = false;
307 double quantity = 0;
308 QDomElement splits = operation.firstChildElement(QStringLiteral("SPLITS"));
309
310 int nbSuboperations = 0;
311 suboperationsList.resize(0);
312 {
313 QDomNodeList suboperationsListTmp = splits.elementsByTagName(QStringLiteral("SPLIT"));
314 nbSuboperations = suboperationsListTmp.count();
315
316 for (int j = 0; !err && j < nbSuboperations; ++j) {
317 QDomElement suboperation = suboperationsListTmp.at(j).toElement();
318 if (m_mapIdCategory.contains(suboperation.attribute(QStringLiteral("account")))) {
319 suboperationsList.push_front(suboperation);
320 } else {
321 suboperationsList.push_back(suboperation);
322 }
323 }
324 }
325
326 SKGSubOperationObject suboperationObj;
327 for (int j = 0; !err && j < nbSuboperations; ++j) {
328 QDomElement suboperation = suboperationsList.at(j).toElement();
329
330 // Set operation attributes
331 IFOKDO(err, operationObj.setPayee(mapIdPayee[suboperation.attribute(QStringLiteral("payee"))]))
332 if (!err && operationObj.getComment().isEmpty()) {
333 err = operationObj.setComment(suboperation.attribute(QStringLiteral("memo")));
334 }
335 IFOKDO(err, operationObj.setNumber(suboperation.attribute(QStringLiteral("number"))))
336
337 // Set state
338 if (operationObj.getStatus() == SKGOperationObject::NONE) {
339 QString val = suboperation.attribute(QStringLiteral("reconcileflag"));
340 IFOKDO(err, operationObj.setStatus(val == QStringLiteral("1") ? SKGOperationObject::POINTED : val == QStringLiteral("2") ? SKGOperationObject::CHECKED : SKGOperationObject::NONE))
341 }
342 IFOKDO(err, operationObj.save())
343
344 if (m_mapIdCategory.contains(suboperation.attribute(QStringLiteral("account")))) {
345 // It is a split on category
346 SKGCategoryObject cat = m_mapIdCategory.value(suboperation.attribute(QStringLiteral("account")));
347
348 double q = -toKmyValue(suboperation.attribute(QStringLiteral("shares")));
349 if (!err && ((suboperationObj.getID() == 0) || suboperationObj.getQuantity() != q)) {
350 err = operationObj.addSubOperation(suboperationObj);
351 }
352 IFOKDO(err, suboperationObj.setQuantity(q))
353 IFOKDO(err, suboperationObj.setCategory(cat))
354 IFOKDO(err, suboperationObj.setComment(suboperation.attribute(QStringLiteral("memo"))))
355 IFOKDO(err, suboperationObj.save(true, false))
356 } else {
357 QString accountSubOp = suboperation.attribute(QStringLiteral("account"));
358 if (!accountSubOp.isEmpty()) {
359 if (nbSuboperations == 1) {
360 SKGUnitObject unit = m_mapIdUnit.value(accountSubOp);
361 if (unit.getID() != 0) {
362 IFOKDO(err, operationObj.setUnit(unit))
363 }
364 }
365
366 if (!m_mapIdAccount.contains(accountSubOp) || (nbSuboperations == 2 &&
367 m_mapIdAccount.value(accountSubOp) == kmymoneyTemporaryAccount &&
368 suboperationsList.at(0).toElement().attribute(QStringLiteral("action")).isEmpty() &&
369 suboperationsList.at(1).toElement().attribute(QStringLiteral("action")).isEmpty())) {
370 // Set as initial balance
371 IFOKDO(err, operationObj.setAttribute(QStringLiteral("d_date"), QStringLiteral("0000-00-00")))
372 IFOKDO(err, operationObj.setStatus(SKGOperationObject::CHECKED))
373 IFOKDO(err, operationObj.save(true, false))
374
375 if (!err && (suboperationObj.getID() == 0)) {
376 err = operationObj.addSubOperation(suboperationObj);
377 }
378
379 IFOKDO(err, suboperationObj.setAttribute(QStringLiteral("d_date"), QStringLiteral("0000-00-00")))
380 IFOKDO(err, suboperationObj.save(true, false))
381 } else {
382 // It is a transfer of account
383 SKGAccountObject act = m_mapIdAccount.value(accountSubOp);
384
385 if (parentSet) {
386 // If the parent is already set, it means that is a transfer
387 SKGOperationObject operationObj2;
388 IFOKDO(err, act.addOperation(operationObj2, true))
389 IFOKDO(err, operationObj2.setTemplate(operationObj.isTemplate()))
390 IFOKDO(err, operationObj2.setDate(operationObj.getDate()))
391 IFOKDO(err, operationObj2.setNumber(operationObj.getNumber()))
392 IFOKDO(err, operationObj2.setComment(operationObj.getComment()))
393 SKGPayeeObject payeeObject;
394 operationObj.getPayee(payeeObject);
395 IFOKDO(err, operationObj2.setPayee(payeeObject))
396 IFOK(err) {
397 QString val = suboperation.attribute(QStringLiteral("reconcileflag"));
398 err = operationObj2.setStatus(val == QStringLiteral("1") ? SKGOperationObject::POINTED : val == QStringLiteral("2") ? SKGOperationObject::CHECKED : SKGOperationObject::NONE);
399 }
400 IFOKDO(err, operationObj2.setImported(true))
401 IFOKDO(err, operationObj2.setImportID(operationObj.getImportID()))
402
403 SKGUnitObject unit = m_mapIdUnit.value(accountSubOp);
404 if (unit.getID() != 0) {
405 IFOKDO(err, operationObj2.setUnit(unit))
406 } else {
407 IFOKDO(err, operationObj.getUnit(unit))
408 IFOKDO(err, operationObj2.setUnit(unit))
409 }
410 IFOKDO(err, operationObj2.save())
411 IFOKDO(err, operationObj2.setGroupOperation(operationObj))
412 IFOKDO(err, operationObj2.save())
413
414 // Create sub operation on operationObj2
415 SKGSubOperationObject suboperationObj2;
416 IFOKDO(err, operationObj2.addSubOperation(suboperationObj2))
417 IFOK(err) {
418 // We must take the quality of the split having an action
419 quantity = toKmyValue(suboperation.attribute(QStringLiteral("shares")));
420 err = suboperationObj2.setQuantity(quantity);
421 }
422 IFOKDO(err, suboperationObj2.setComment(suboperation.attribute(QStringLiteral("memo"))))
423 IFOKDO(err, suboperationObj2.save(true, false))
424 } else {
425 // We set the parent
426 if (Q_LIKELY(!err) && (act.getID() == 0)) {
427 err = SKGError(ERR_FAIL, i18nc("Error message", "Account with identifier %1 not found", suboperation.attribute(QStringLiteral("account"))));
428 }
429 IFOKDO(err, operationObj.setParentAccount(act, true))
430 IFOKDO(err, operationObj.save())
431
432 // Compute quantity
433 quantity = toKmyValue(suboperation.attribute(QStringLiteral("shares")));
434
435 // Create sub operation on operationObj
436 quantity -= SKGServices::stringToDouble(operationObj.getAttribute(QStringLiteral("f_QUANTITY")));
437 if (quantity != 0 || nbSuboperations == 1) {
438 IFOKDO(err, operationObj.addSubOperation(suboperationObj))
439 IFOKDO(err, suboperationObj.setQuantity(quantity))
440 IFOKDO(err, suboperationObj.setComment(suboperation.attribute(QStringLiteral("memo"))))
441 IFOKDO(err, suboperationObj.save(true, false))
442 }
443
444 parentSet = true;
445 }
446 }
447 }
448 }
449 }
450
451 if (!err && i % 500 == 0) {
452 err = m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE"));
453 }
454
455 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
456 }
457
458 SKGENDTRANSACTION(m_importer->getDocument(), err)
459
460 return err;
461 }
462
importBudget(QDomElement & docElem)463 SKGError SKGImportPluginKmy::importBudget(QDomElement& docElem)
464 {
465 SKGError err;
466 QDomElement budgets = docElem.firstChildElement(QStringLiteral("BUDGETS"));
467 if (!err && !budgets.isNull()) {
468 SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-BUDGETS", err)
469 // Build cache of categories
470 QMap<int, bool> catExpense;
471 {
472 SKGStringListList list;
473 err = m_importer->getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT id, t_TYPEEXPENSE FROM v_category_display"), list);
474 int nb = list.count();
475 for (int i = 1; i < nb; ++i) {
476 catExpense[SKGServices::stringToInt(list.at(i).at(0))] = (list.at(i).at(0) == QStringLiteral("-"));
477 }
478 }
479
480 QDomNodeList budgetList = budgets.elementsByTagName(QStringLiteral("BUDGET"));
481 int nb = budgetList.count();
482 IFOKDO(err, m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import budgets"), nb))
483 for (int i = 0; !err && i < nb; ++i) {
484 QDomElement budget = budgetList.at(i).toElement();
485 QDomNodeList accountList = budget.elementsByTagName(QStringLiteral("ACCOUNT"));
486 int nb2 = accountList.count();
487 for (int j = 0; !err && j < nb2; ++j) {
488 QDomElement account = accountList.at(j).toElement();
489 SKGCategoryObject cat = m_mapIdCategory.value(account.attribute(QStringLiteral("id")));
490 QString budgetlevel = account.attribute(QStringLiteral("budgetlevel"));
491
492 QDomNodeList periodList = account.elementsByTagName(QStringLiteral("PERIOD"));
493 int nb3 = periodList.count();
494 for (int k = 0; !err && k < nb3; ++k) {
495 QDomElement period = periodList.at(k).toElement();
496
497 double q = toKmyValue(period.attribute(QStringLiteral("amount")));
498
499 // Are we able to find to sign with the category ?
500 if (catExpense[cat.getID()]) {
501 q = -q;
502 }
503
504 QStringList dates = SKGServices::splitCSVLine(period.attribute(QStringLiteral("start")), '-');
505 if (dates.count() == 3) {
506 // We try a creation
507 for (int m = 1; !err && m <= (budgetlevel == QStringLiteral("monthly") ? 12 : 1); ++m) {
508 SKGBudgetObject budget2(m_importer->getDocument());
509 err = budget2.setCategory(cat);
510 IFOKDO(err, budget2.setBudgetedAmount(q))
511 IFOKDO(err, budget2.setYear(SKGServices::stringToDouble(dates.at(0))))
512 IFOKDO(err, budget2.setMonth(budgetlevel == QStringLiteral("monthbymonth") ? SKGServices::stringToDouble(dates.at(1)) :
513 budgetlevel == QStringLiteral("yearly") ? 0 : m));
514 IFOKDO(err, budget2.save(true, false))
515 }
516 }
517 }
518 }
519
520 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
521 }
522
523 SKGENDTRANSACTION(m_importer->getDocument(), err)
524 }
525 return err;
526 }
527
importAccounts(SKGBankObject & bank,SKGAccountObject & kmymoneyTemporaryAccount,QMap<QString,SKGBankObject> & mapIdBank,QDomElement & docElem)528 SKGError SKGImportPluginKmy::importAccounts(SKGBankObject& bank, SKGAccountObject& kmymoneyTemporaryAccount, QMap<QString, SKGBankObject>& mapIdBank, QDomElement& docElem)
529 {
530 SKGError err;
531 IFOKDO(err, m_importer->getDocument()->addOrModifyAccount(QStringLiteral("KMYMONEY-TEMPORARY-ACCOUNT"), QString(), QStringLiteral("KMYMONEY")))
532 IFOKDO(err, bank.setName(QStringLiteral("KMYMONEY")))
533 IFOKDO(err, bank.load())
534 IFOKDO(err, kmymoneyTemporaryAccount.setName(QStringLiteral("KMYMONEY-TEMPORARY-ACCOUNT")))
535 IFOKDO(err, kmymoneyTemporaryAccount.load())
536
537 QDomElement accounts = docElem.firstChildElement(QStringLiteral("ACCOUNTS"));
538 if (!err && !accounts.isNull()) {
539 SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-ACCOUNTS", err)
540 QDomNodeList accountList = accounts.elementsByTagName(QStringLiteral("ACCOUNT"));
541 int nb = accountList.count();
542 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import accounts"), nb);
543 QMap<QString, QString> type15Account;
544 QMap<QString, QString> type15Unit;
545 for (int i = 0; !err && i < nb; ++i) {
546 // Get account object
547 QDomElement account = accountList.at(i).toElement();
548 QString type = account.attribute(QStringLiteral("type"));
549 if (type == QStringLiteral("15")) {
550 // Actions: the real account is the parent
551 type15Account[account.attribute(QStringLiteral("id"))] = account.attribute(QStringLiteral("parentaccount"));
552 type15Unit[account.attribute(QStringLiteral("id"))] = account.attribute(QStringLiteral("currency"));
553 } else if (type != QStringLiteral("12") && type != QStringLiteral("13") && type != QStringLiteral("16")) {
554 // Get the bank
555 QString bankId = account.attribute(QStringLiteral("institution"));
556 SKGBankObject bankObj = (bankId.isEmpty() ? bank : mapIdBank[account.attribute(QStringLiteral("institution"))]);
557
558 // Creation of the account
559 SKGAccountObject accountObj;
560 IFOKDO(err, bankObj.addAccount(accountObj))
561 IFOKDO(err, accountObj.setName(account.attribute(QStringLiteral("name"))))
562 IFOKDO(err, accountObj.setNumber(account.attribute(QStringLiteral("number"))))
563 IFOKDO(err, accountObj.setComment(account.attribute(QStringLiteral("description"))))
564 IFOK(err) {
565 SKGAccountObject::AccountType typeA = (type == QStringLiteral("4") ? SKGAccountObject::CREDITCARD : (type == QStringLiteral("7") ? SKGAccountObject::INVESTMENT : (type == QStringLiteral("9") ? SKGAccountObject::ASSETS : (type == QStringLiteral("3") ? SKGAccountObject::WALLET : (type == QStringLiteral("10") ? SKGAccountObject::LOAN : SKGAccountObject::CURRENT)))));
566 err = accountObj.setType(typeA);
567 }
568 IFOK(err) {
569 // Set pairs
570 QDomNodeList pairList = account.elementsByTagName(QStringLiteral("PAIR"));
571 int nb2 = pairList.count();
572 for (int j = 0; !err && j < nb2; ++j) {
573 QDomElement pair = pairList.at(j).toElement();
574 if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("mm-closed") && pair.attribute(QStringLiteral("value")).toLower() == QStringLiteral("yes")) {
575 err = accountObj.setClosed(true);
576 } else if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("preferredaccount") && pair.attribute(QStringLiteral("value")).toLower() == QStringLiteral("yes")) {
577 err = accountObj.bookmark(true);
578 } else if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("minbalanceabsolute")) {
579 err = accountObj.setMinLimitAmount(toKmyValue(pair.attribute(QStringLiteral("value"))));
580 IFOKDO(err, accountObj.minLimitAmountEnabled(true))
581 } else if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("maxcreditabsolute")) {
582 err = accountObj.setMaxLimitAmount(-toKmyValue(pair.attribute(QStringLiteral("value"))));
583 IFOKDO(err, accountObj.maxLimitAmountEnabled(true))
584 }
585 }
586 }
587 IFOKDO(err, accountObj.save())
588
589 // Change parent bank in case of ASSETS
590 if (accountObj.getType() == SKGAccountObject::WALLET) {
591 // Get blank bank
592 SKGBankObject blankBank(m_importer->getDocument());
593 IFOKDO(err, blankBank.setName(QString()))
594 if (blankBank.exist()) {
595 err = blankBank.load();
596 } else {
597 err = blankBank.save();
598 }
599 IFOKDO(err, accountObj.setBank(blankBank))
600 IFOKDO(err, accountObj.save())
601 }
602
603 m_mapIdAccount[account.attribute(QStringLiteral("id"))] = accountObj;
604 } else if (type == QStringLiteral("16")) {
605 m_mapIdAccount[account.attribute(QStringLiteral("id"))] = kmymoneyTemporaryAccount;
606 } else {
607 // Create category
608 SKGCategoryObject cat = m_mapIdCategory.value(account.attribute(QStringLiteral("id")));
609 if (cat.getID() != 0) {
610 // Already existing ==> we must set the right name
611 err = cat.setName(account.attribute(QStringLiteral("name")));
612 IFOKDO(err, cat.save())
613 } else {
614 // We must create it
615 cat = SKGCategoryObject(m_importer->getDocument());
616 err = cat.setName(account.attribute(QStringLiteral("name")));
617 IFOKDO(err, cat.save())
618 }
619 if (err) {
620 // The category already exists
621 SKGCategoryObject catp;
622 err = cat.getParentCategory(catp);
623 QString fullName = catp.getFullName() % OBJECTSEPARATOR % cat.getName();
624 IFOKDO(err, cat.remove(false))
625 IFOKDO(err, SKGCategoryObject::createPathCategory(m_importer->getDocument(), fullName, cat))
626 }
627 m_mapIdCategory[account.attribute(QStringLiteral("id"))] = cat;
628
629 // Create sub categories
630 QDomNodeList subaccountList = account.elementsByTagName(QStringLiteral("SUBACCOUNT"));
631 int nb2 = subaccountList.count();
632 for (int j = 0; !err && j < nb2; ++j) {
633 QDomElement subaccount = subaccountList.at(j).toElement();
634
635 // Is child already existing ?
636 SKGCategoryObject cat2 = m_mapIdCategory.value(subaccount.attribute(QStringLiteral("id")));
637 if (cat2.getID() != 0) {
638 // Yes ==> reparent
639 err = cat2.setParentCategory(cat);
640 IFOKDO(err, cat2.save(true, false))
641 } else {
642 // No ==> create
643 IFOKDO(err, cat.addCategory(cat2))
644 IFOKDO(err, cat2.setName(subaccount.attribute(QStringLiteral("id"))))
645 IFOKDO(err, cat2.save())
646 m_mapIdCategory[subaccount.attribute(QStringLiteral("id"))] = cat2;
647 }
648 }
649 }
650
651 QStringList list = type15Account.keys();
652 for (const auto& k : qAsConst(list)) {
653 m_mapIdAccount[k] = m_mapIdAccount.value(type15Account[k]);
654 m_mapIdUnit[account.attribute(QStringLiteral("id"))] = m_mapIdUnit.value(account.attribute(QStringLiteral("currency")));
655 }
656
657 list = type15Unit.keys();
658 for (const auto& k : qAsConst(list)) {
659 m_mapIdUnit[k] = m_mapIdUnit[type15Unit[k]];
660 }
661
662 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
663 }
664
665 SKGENDTRANSACTION(m_importer->getDocument(), err)
666 }
667 return err;
668 }
669
importFile()670 SKGError SKGImportPluginKmy::importFile()
671 {
672 if (m_importer == nullptr) {
673 return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
674 }
675
676 SKGError err;
677 SKGTRACEINFUNCRC(2, err)
678
679 // Initialisation
680 m_mapIdUnit.clear();
681 m_mapIdAccount.clear();
682 m_mapIdCategory.clear();
683 m_mapIdPayee.clear();
684
685 // Open file
686 KCompressionDevice file(m_importer->getLocalFileName(), KCompressionDevice::GZip);
687 if (!file.open(QIODevice::ReadOnly)) {
688 err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message", "Open file '%1' failed", m_importer->getFileName().toDisplayString()));
689 } else {
690 QDomDocument doc;
691
692 // Set the file without uncompression
693 QString errorMsg;
694 int errorLine = 0;
695 int errorCol = 0;
696 bool contentOK = doc.setContent(file.readAll(), &errorMsg, &errorLine, &errorCol);
697 file.close();
698
699 if (!contentOK) {
700 err.setReturnCode(ERR_ABORT).setMessage(i18nc("Error message", "%1-%2: '%3'", errorLine, errorCol, errorMsg)).addError(ERR_INVALIDARG, i18nc("Error message", "Invalid XML content in file '%1'", m_importer->getFileName().toDisplayString()));
701 } else {
702 // Get root
703 QDomElement docElem = doc.documentElement();
704 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "KMY"), 8);
705
706 // Step 1-Get units
707 IFOKDO(err, importSecurities(docElem))
708 IFOKDO(err, m_importer->getDocument()->stepForward(1))
709
710 // Step 2-Get units prices
711 IFOKDO(err, importPrices(docElem))
712 IFOKDO(err, m_importer->getDocument()->stepForward(2))
713
714 // Step 3-Create banks
715 QMap<QString, SKGBankObject> mapIdBank;
716 IFOKDO(err, importInstitutions(mapIdBank, docElem))
717 IFOKDO(err, m_importer->getDocument()->stepForward(3))
718
719 // Step 4-Create account and categories
720 // Create bank and temporary account for kmymoney import
721 SKGAccountObject kmymoneyTemporaryAccount(m_importer->getDocument());
722 SKGBankObject bank(m_importer->getDocument());
723 IFOKDO(err, importAccounts(bank, kmymoneyTemporaryAccount, mapIdBank, docElem))
724 IFOKDO(err, m_importer->getDocument()->stepForward(4))
725
726 // Step 5-Read payees
727 QMap<QString, SKGPayeeObject> mapIdPayee;
728 IFOKDO(err, importPayees(mapIdPayee, docElem))
729 IFOKDO(err, m_importer->getDocument()->stepForward(5))
730
731 // Step 6-Create operations
732 IFOKDO(err, importTransactions(docElem, kmymoneyTemporaryAccount, mapIdPayee))
733 IFOKDO(err, m_importer->getDocument()->stepForward(6))
734
735 // Step 7-Get budgets
736 IFOKDO(err, importBudget(docElem))
737 IFOKDO(err, m_importer->getDocument()->stepForward(7))
738
739 // Step 8-Remove useless account and temporary account
740 {
741 IFOKDO(err, kmymoneyTemporaryAccount.remove(false, true))
742 IFOKDO(err, m_importer->getDocument()->executeSqliteOrder("DELETE FROM account WHERE rd_bank_id=" % SKGServices::intToString(bank.getID()) % " AND (SELECT COUNT(1) FROM operation WHERE operation.rd_account_id=account.id)=0"))
743 }
744 IFOKDO(err, m_importer->getDocument()->stepForward(8))
745
746 SKGENDTRANSACTION(m_importer->getDocument(), err)
747
748 IFOKDO(err, m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE")))
749 }
750 }
751
752 // Clean
753 m_mapIdUnit.clear();
754 m_mapIdAccount.clear();
755 m_mapIdCategory.clear();
756 m_mapIdPayee.clear();
757
758 return err;
759 }
760
isExportPossible()761 bool SKGImportPluginKmy::isExportPossible()
762 {
763 SKGTRACEINFUNC(10)
764 return (m_importer == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("KMY"));
765 }
766
exportHeader(QDomDocument & doc,QDomElement & root)767 SKGError SKGImportPluginKmy::exportHeader(QDomDocument& doc, QDomElement& root)
768 {
769 SKGError err;
770 QDomElement fileindo = doc.createElement(QStringLiteral("FILEINFO"));
771 root.appendChild(fileindo);
772
773 {
774 // <CREATION_DATE>
775 QDomElement creation_date = doc.createElement(QStringLiteral("CREATION_DATE"));
776 fileindo.appendChild(creation_date);
777 creation_date.setAttribute(QStringLiteral("date"), SKGServices::dateToSqlString(QDateTime::currentDateTime()));
778
779 // <LAST_MODIFIED_DATE>
780 QDomElement last_modified_date = doc.createElement(QStringLiteral("LAST_MODIFIED_DATE"));
781 fileindo.appendChild(last_modified_date);
782 last_modified_date.setAttribute(QStringLiteral("date"), SKGServices::dateToSqlString(QDateTime::currentDateTime()));
783
784 // <VERSION>
785 QDomElement version = doc.createElement(QStringLiteral("VERSION"));
786 fileindo.appendChild(version);
787 version.setAttribute(QStringLiteral("id"), QStringLiteral("1"));
788
789 // <FIXVERSION>
790 QDomElement fixversion = doc.createElement(QStringLiteral("FIXVERSION"));
791 fileindo.appendChild(fixversion);
792 fixversion.setAttribute(QStringLiteral("id"), QStringLiteral("2"));
793 }
794
795 // <USER>
796 QDomElement user = doc.createElement(QStringLiteral("USER"));
797 root.appendChild(user);
798 user.setAttribute(QStringLiteral("email"), QString());
799 user.setAttribute(QStringLiteral("name"), QString());
800 {
801 // ADDRESS
802 QDomElement address = doc.createElement(QStringLiteral("ADDRESS"));
803 user.appendChild(address);
804 address.setAttribute(QStringLiteral("street"), QString());
805 address.setAttribute(QStringLiteral("zipcode"), QString());
806 address.setAttribute(QStringLiteral("county"), QString());
807 address.setAttribute(QStringLiteral("city"), QString());
808 address.setAttribute(QStringLiteral("telephone"), QString());
809 }
810 return err;
811 }
812
exportSecurities(QDomDocument & doc,QDomElement & root,const QString & stdUnit)813 SKGError SKGImportPluginKmy::exportSecurities(QDomDocument& doc, QDomElement& root, const QString& stdUnit)
814 {
815 SKGError err;
816 QDomElement securities = doc.createElement(QStringLiteral("SECURITIES"));
817 root.appendChild(securities);
818
819 QDomElement currencies = doc.createElement(QStringLiteral("CURRENCIES"));
820 root.appendChild(currencies);
821
822 SKGObjectBase::SKGListSKGObjectBase objects;
823 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_unit"), QStringLiteral("t_type!='I'"), objects))
824 int nb = objects.count();
825 securities.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
826
827 QStringList importedCurrency;
828 IFOK(err) {
829 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
830 for (int i = 0; !err && i < nb; ++i) {
831 SKGUnitObject obj(objects.at(i));
832 if (obj.getType() == SKGUnitObject::SHARE || obj.getType() == SKGUnitObject::OBJECT) {
833 QDomElement security = doc.createElement(QStringLiteral("SECURITY"));
834 securities.appendChild(security);
835
836 SKGUnitObject parentUnit;
837 obj.getUnit(parentUnit);
838 QString unitP = SKGUnitObject::getInternationalCode(parentUnit.getName());
839 if (unitP.isEmpty()) {
840 unitP = stdUnit;
841 }
842
843 security.setAttribute(QStringLiteral("id"), obj.getName());
844 security.setAttribute(QStringLiteral("trading-currency"), unitP);
845 security.setAttribute(QStringLiteral("saf"), QStringLiteral("100000"));
846 security.setAttribute(QStringLiteral("symbol"), obj.getSymbol());
847 security.setAttribute(QStringLiteral("trading-market"), obj.getCountry());
848 security.setAttribute(QStringLiteral("type"), QStringLiteral("4"));
849 security.setAttribute(QStringLiteral("name"), obj.getName());
850
851 QString internetCode = obj.getInternetCode();
852 if (!internetCode.isEmpty()) {
853 QDomElement keyvaluepairs2 = doc.createElement(QStringLiteral("KEYVALUEPAIRS"));
854 security.appendChild(keyvaluepairs2);
855
856 QDomElement pair1 = doc.createElement(QStringLiteral("PAIR"));
857 keyvaluepairs2.appendChild(pair1);
858 pair1.setAttribute(QStringLiteral("key"), QStringLiteral("kmm-online-source"));
859 pair1.setAttribute(QStringLiteral("value"), QStringLiteral("Yahoo"));
860
861 QDomElement pair2 = doc.createElement(QStringLiteral("PAIR"));
862 keyvaluepairs2.appendChild(pair2);
863 pair2.setAttribute(QStringLiteral("key"), QStringLiteral("kmm-security-id"));
864 pair2.setAttribute(QStringLiteral("value"), internetCode);
865 }
866 } else {
867 QDomElement currency = doc.createElement(QStringLiteral("CURRENCY"));
868 currencies.appendChild(currency);
869
870 QString unit = SKGUnitObject::getInternationalCode(obj.getName());
871 if (unit.isEmpty()) {
872 unit = obj.getName();
873 }
874
875 currency.setAttribute(QStringLiteral("saf"), QStringLiteral("100"));
876 currency.setAttribute(QStringLiteral("symbol"), obj.getSymbol());
877 currency.setAttribute(QStringLiteral("type"), QStringLiteral("3"));
878 currency.setAttribute(QStringLiteral("id"), unit);
879 currency.setAttribute(QStringLiteral("name"), obj.getName());
880 currency.setAttribute(QStringLiteral("ppu"), QStringLiteral("100"));
881 currency.setAttribute(QStringLiteral("scf"), QStringLiteral("100"));
882
883 importedCurrency.push_back(obj.getSymbol());
884 }
885 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
886 }
887
888 SKGENDTRANSACTION(m_importer->getDocument(), err)
889 }
890
891 // <CURRENCIES>
892 QStringList units = SKGUnitObject::getListofKnownCurrencies(false);
893 nb = units.count();
894 int nbreal = 0;
895 for (int i = 0; i < nb; ++i) {
896 SKGServices::SKGUnitInfo info = SKGUnitObject::getUnitInfo(units.at(i));
897 if (info.Name != info.Symbol && !importedCurrency.contains(info.Symbol)) {
898 QDomElement currency = doc.createElement(QStringLiteral("CURRENCY"));
899 currencies.appendChild(currency);
900 currency.setAttribute(QStringLiteral("saf"), QStringLiteral("100"));
901 currency.setAttribute(QStringLiteral("symbol"), info.Symbol);
902 currency.setAttribute(QStringLiteral("type"), QStringLiteral("3"));
903 currency.setAttribute(QStringLiteral("id"), SKGUnitObject::getInternationalCode(info.Name));
904 currency.setAttribute(QStringLiteral("name"), info.Name);
905 currency.setAttribute(QStringLiteral("ppu"), QStringLiteral("100"));
906 currency.setAttribute(QStringLiteral("scf"), QStringLiteral("100"));
907
908 ++nbreal;
909 }
910 }
911 currencies.setAttribute(QStringLiteral("count"), SKGServices::intToString(nbreal));
912
913 // <PRICES>
914 QDomElement prices = doc.createElement(QStringLiteral("PRICES"));
915 root.appendChild(prices);
916 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_unit"), QStringLiteral("t_type='S'"), objects))
917 nb = objects.count();
918 prices.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
919 IFOK(err) {
920 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
921 for (int i = 0; !err && i < nb; ++i) {
922 SKGUnitObject obj(objects.at(i));
923 QDomElement pricepair = doc.createElement(QStringLiteral("PRICEPAIR"));
924 prices.appendChild(pricepair);
925
926 QString unitP = SKGUnitObject::getInternationalCode(obj.getName());
927 if (unitP.isEmpty()) {
928 unitP = stdUnit;
929 }
930
931 pricepair.setAttribute(QStringLiteral("from"), obj.getName());
932 pricepair.setAttribute(QStringLiteral("to"), unitP);
933
934 SKGObjectBase::SKGListSKGObjectBase unitValues;
935 err = obj.getUnitValues(unitValues);
936 int nb2 = unitValues.count();
937 for (int j = 0; !err && j < nb2; ++j) {
938 QDomElement price = doc.createElement(QStringLiteral("PRICE"));
939 pricepair.appendChild(price);
940
941 SKGUnitValueObject unitval(unitValues.at(j));
942 price.setAttribute(QStringLiteral("price"), SKGImportPluginKmy::kmyValue(unitval.getQuantity()));
943 price.setAttribute(QStringLiteral("source"), QStringLiteral("Utilisateur"));
944 price.setAttribute(QStringLiteral("date"), SKGServices::dateToSqlString(unitval.getDate()));
945 }
946
947 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
948 }
949
950 SKGENDTRANSACTION(m_importer->getDocument(), err)
951 }
952
953 // <REPORTS>
954 QDomElement reports = doc.createElement(QStringLiteral("REPORTS"));
955 root.appendChild(reports);
956 reports.setAttribute(QStringLiteral("count"), QStringLiteral("0"));
957
958 return err;
959 }
960
exportBudgets(QDomDocument & doc,QDomElement & root)961 SKGError SKGImportPluginKmy::exportBudgets(QDomDocument& doc, QDomElement& root)
962 {
963 SKGError err;
964 QDomElement budgets = doc.createElement(QStringLiteral("BUDGETS"));
965 root.appendChild(budgets);
966
967 SKGObjectBase::SKGListSKGObjectBase objects;
968 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_budget"), QStringLiteral("1=1 ORDER BY i_year, i_month"), objects))
969 int nb = objects.count();
970 int nbBudgets = 0;
971 int currentYear = 0;
972 QDomElement budget;
973
974 QMap<QString, QDomElement> mapCatAccount;
975 IFOK(err) {
976 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export budgets"), nb);
977 for (int i = 0; !err && i < nb; ++i) {
978 SKGBudgetObject obj(objects.at(i));
979 SKGCategoryObject cat;
980 obj.getCategory(cat);
981 QString catId = getKmyUniqueIdentifier(cat);
982 int year = obj.getYear();
983 QString yearString = SKGServices::intToString(year);
984 int month = obj.getMonth();
985 QString monthString = SKGServices::intToString(month);
986 if (monthString.isEmpty()) {
987 monthString = '0' % monthString;
988 }
989 if (currentYear != year) {
990 budget = doc.createElement(QStringLiteral("BUDGET"));
991 budgets.appendChild(budget);
992 budget.setAttribute(QStringLiteral("version"), QStringLiteral("2"));
993 budget.setAttribute(QStringLiteral("id"), yearString);
994 budget.setAttribute(QStringLiteral("start"), yearString % "-01-01");
995 budget.setAttribute(QStringLiteral("name"), yearString);
996
997 currentYear = year;
998 mapCatAccount.clear();
999 ++nbBudgets;
1000 }
1001
1002 QDomElement account = mapCatAccount[catId];
1003 if (account.isNull() && !catId.isEmpty()) {
1004 account = doc.createElement(QStringLiteral("ACCOUNT"));
1005 budget.appendChild(account);
1006 account.setAttribute(QStringLiteral("budgetsubaccounts"), QStringLiteral("0"));
1007 account.setAttribute(QStringLiteral("id"), catId);
1008 mapCatAccount[catId] = account;
1009 }
1010 if (!account.isNull()) {
1011 account.setAttribute(QStringLiteral("budgetlevel"), obj.getMonth() == 0 ? QStringLiteral("yearly") : QStringLiteral("monthbymonth"));
1012
1013 QDomElement period = doc.createElement(QStringLiteral("PERIOD"));
1014 account.appendChild(period);
1015 period.setAttribute(QStringLiteral("amount"), SKGImportPluginKmy::kmyValue(qAbs(obj.getBudgetedAmount())));
1016 period.setAttribute(QStringLiteral("start"), yearString % '-' % (obj.getMonth() == 0 ? QStringLiteral("01") : monthString) % "-01");
1017 }
1018
1019 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
1020 }
1021
1022 SKGENDTRANSACTION(m_importer->getDocument(), err)
1023 }
1024 budgets.setAttribute(QStringLiteral("count"), SKGServices::intToString(nbBudgets));
1025 return err;
1026 }
1027
exportSchedules(QDomDocument & doc,QDomElement & root)1028 SKGError SKGImportPluginKmy::exportSchedules(QDomDocument& doc, QDomElement& root)
1029 {
1030 SKGError err;
1031 QDomElement schedules = doc.createElement(QStringLiteral("SCHEDULES"));
1032 root.appendChild(schedules);
1033
1034 SKGObjectBase::SKGListSKGObjectBase objects;
1035 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_recurrentoperation"), QString(), objects))
1036 int nb = objects.count();
1037 schedules.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
1038 IFOK(err) {
1039 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export scheduled operations"), nb);
1040 for (int i = 0; !err && i < nb; ++i) {
1041 SKGRecurrentOperationObject obj(objects.at(i));
1042 SKGOperationObject op;
1043 err = obj.getParentOperation(op);
1044 IFOK(err) {
1045 QDomElement scheduled_tx = doc.createElement(QStringLiteral("SCHEDULED_TX"));
1046 schedules.appendChild(scheduled_tx);
1047
1048 scheduled_tx.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(obj));
1049 scheduled_tx.setAttribute(QStringLiteral("name"), getKmyUniqueIdentifier(obj));
1050 scheduled_tx.setAttribute(QStringLiteral("startDate"), obj.getAttribute(QStringLiteral("d_date")));
1051 scheduled_tx.setAttribute(QStringLiteral("lastPayment"), obj.getAttribute(QStringLiteral("d_date")));
1052 bool autoEnter = obj.isAutoWriteEnabled();
1053 scheduled_tx.setAttribute(QStringLiteral("autoEnter"), autoEnter ? QStringLiteral("1") : QStringLiteral("0"));
1054
1055 QString occuType;
1056 int occu = obj.getPeriodIncrement();
1057 SKGRecurrentOperationObject::PeriodUnit punit = obj.getPeriodUnit();
1058 if (punit == SKGRecurrentOperationObject::MONTH) {
1059 occuType = QStringLiteral("32");
1060 } else if (punit == SKGRecurrentOperationObject::WEEK) {
1061 occuType = '4';
1062 } else if (punit == SKGRecurrentOperationObject::DAY) {
1063 occuType = '2';
1064 } else {
1065 occuType = QStringLiteral("16384");
1066 }
1067
1068 scheduled_tx.setAttribute(QStringLiteral("occurenceMultiplier"), SKGServices::intToString(occu));
1069 scheduled_tx.setAttribute(QStringLiteral("occurence"), occuType); // krazy:exclude=spelling
1070 scheduled_tx.setAttribute(QStringLiteral("weekendOption"), QStringLiteral("0"));
1071 scheduled_tx.setAttribute(QStringLiteral("paymentType"), QStringLiteral("1"));
1072 QChar type = '1';
1073 SKGOperationObject op2;
1074 if (op.isTransfer(op2)) {
1075 type = '4';
1076 } else if (op.getCurrentAmount() > 0) {
1077 type = '2';
1078 }
1079 scheduled_tx.setAttribute(QStringLiteral("type"), type);
1080 scheduled_tx.setAttribute(QStringLiteral("fixed"), QStringLiteral("1"));
1081
1082 QString endDate;
1083 if (obj.hasTimeLimit()) {
1084 QDate firstDate = obj.getDate();
1085
1086 // We must compute the date
1087 int p = occu * (obj.getTimeLimit() - 1);
1088 if (punit == SKGRecurrentOperationObject::DAY) {
1089 firstDate = firstDate.addDays(p);
1090 } else if (punit == SKGRecurrentOperationObject::MONTH) {
1091 firstDate = firstDate.addMonths(p);
1092 } else if (punit == SKGRecurrentOperationObject::YEAR) {
1093 firstDate = firstDate.addYears(p);
1094 }
1095
1096 endDate = firstDate.toString(QStringLiteral("yyyy-MM-dd"));
1097 }
1098 scheduled_tx.setAttribute(QStringLiteral("endDate"), endDate);
1099
1100 err = exportOperation(op, doc, scheduled_tx);
1101 }
1102 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
1103 }
1104
1105 SKGENDTRANSACTION(m_importer->getDocument(), err)
1106 }
1107 return err;
1108 }
1109
exportTransactions(QDomDocument & doc,QDomElement & root,const QString & stdUnit)1110 SKGError SKGImportPluginKmy::exportTransactions(QDomDocument& doc, QDomElement& root, const QString& stdUnit)
1111 {
1112 SKGError err;
1113 QDomElement transactions = doc.createElement(QStringLiteral("TRANSACTIONS"));
1114 root.appendChild(transactions);
1115
1116 SKGObjectBase::SKGListSKGObjectBase objects;
1117 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_operation"), QStringLiteral("t_template='N' ORDER BY d_date DESC"), objects))
1118 int nb = objects.count();
1119 transactions.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
1120 IFOK(err) {
1121 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export operations"), nb);
1122 for (int i = 0; !err && i < nb; ++i) {
1123 SKGOperationObject op(objects.at(i));
1124 err = exportOperation(op, doc, transactions);
1125 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
1126 }
1127
1128 SKGENDTRANSACTION(m_importer->getDocument(), err)
1129 }
1130
1131 // <KEYVALUEPAIRS>
1132 QDomElement keyvaluepairs = doc.createElement(QStringLiteral("KEYVALUEPAIRS"));
1133 root.appendChild(keyvaluepairs);
1134 {
1135 QDomElement pair = doc.createElement(QStringLiteral("PAIR"));
1136 keyvaluepairs.appendChild(pair);
1137 pair.setAttribute(QStringLiteral("key"), QStringLiteral("kmm-baseCurrency"));
1138 pair.setAttribute(QStringLiteral("value"), stdUnit);
1139 }
1140 return err;
1141 }
1142
exportPayees(QDomDocument & doc,QDomElement & root)1143 SKGError SKGImportPluginKmy::exportPayees(QDomDocument& doc, QDomElement& root)
1144 {
1145 SKGError err;
1146 QDomElement payees = doc.createElement(QStringLiteral("PAYEES"));
1147 root.appendChild(payees);
1148
1149 SKGObjectBase::SKGListSKGObjectBase listPayees;
1150 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_payee"), QString(), listPayees))
1151 int nb = listPayees.count();
1152 payees.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
1153 IFOK(err) {
1154 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export payees"), nb);
1155 for (int i = 0; !err && i < nb; ++i) {
1156 SKGPayeeObject payeeObject(listPayees.at(i));
1157 QDomElement payee = doc.createElement(QStringLiteral("PAYEE"));
1158 payees.appendChild(payee);
1159
1160 payee.setAttribute(QStringLiteral("matchingenabled"), QStringLiteral("0"));
1161 payee.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(payeeObject));
1162 payee.setAttribute(QStringLiteral("name"), payeeObject.getName());
1163 payee.setAttribute(QStringLiteral("email"), QString());
1164 payee.setAttribute(QStringLiteral("reference"), QString());
1165
1166 QDomElement address = doc.createElement(QStringLiteral("ADDRESS"));
1167 payee.appendChild(address);
1168
1169 address.setAttribute(QStringLiteral("street"), payeeObject.getAddress());
1170 address.setAttribute(QStringLiteral("postcode"), QString());
1171 address.setAttribute(QStringLiteral("zip"), QString());
1172 address.setAttribute(QStringLiteral("city"), QString());
1173 address.setAttribute(QStringLiteral("telephone"), QString());
1174 address.setAttribute(QStringLiteral("state"), QString());
1175
1176 m_mapIdPayee[SKGServices::intToString(i + 1)] = payeeObject;
1177
1178 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
1179 }
1180
1181 SKGENDTRANSACTION(m_importer->getDocument(), err)
1182 }
1183 return err;
1184 }
1185
exportInstitutions(QDomDocument & doc,QDomElement & root)1186 SKGError SKGImportPluginKmy::exportInstitutions(QDomDocument& doc, QDomElement& root)
1187 {
1188 SKGError err;
1189 QDomElement institutions = doc.createElement(QStringLiteral("INSTITUTIONS"));
1190 root.appendChild(institutions);
1191 SKGObjectBase::SKGListSKGObjectBase objects;
1192 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_bank"), QStringLiteral("EXISTS(SELECT 1 FROM account WHERE account.rd_bank_id=v_bank.id)"), objects))
1193 int nb = objects.count();
1194 institutions.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
1195 IFOK(err) {
1196 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export banks"), nb);
1197 for (int i = 0; !err && i < nb; ++i) {
1198 SKGBankObject obj(objects.at(i));
1199 QDomElement institution = doc.createElement(QStringLiteral("INSTITUTION"));
1200 institutions.appendChild(institution);
1201
1202 institution.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(obj));
1203 institution.setAttribute(QStringLiteral("name"), obj.getName());
1204 institution.setAttribute(QStringLiteral("sortcode"), obj.getNumber());
1205 institution.setAttribute(QStringLiteral("manager"), QString());
1206
1207 QDomElement address = doc.createElement(QStringLiteral("ADDRESS"));
1208 institution.appendChild(address);
1209
1210 address.setAttribute(QStringLiteral("street"), QString());
1211 address.setAttribute(QStringLiteral("zip"), QString());
1212 address.setAttribute(QStringLiteral("city"), QString());
1213 address.setAttribute(QStringLiteral("telephone"), QString());
1214
1215 QDomElement accountids = doc.createElement(QStringLiteral("ACCOUNTIDS"));
1216 institution.appendChild(accountids);
1217
1218 SKGObjectBase::SKGListSKGObjectBase accounts;
1219 err = obj.getAccounts(accounts);
1220 int nb2 = accounts.count();
1221 for (int j = 0; !err && j < nb2; ++j) {
1222 QDomElement accountid = doc.createElement(QStringLiteral("ACCOUNTID"));
1223 accountids.appendChild(accountid);
1224
1225 accountid.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(accounts.at(j)));
1226 }
1227 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
1228 }
1229
1230 SKGENDTRANSACTION(m_importer->getDocument(), err)
1231 }
1232
1233 return err;
1234 }
1235
exportCategories(QDomDocument & doc,QDomElement & accounts,const QString & stdUnit,QDomElement & accountIncome,QDomElement & accountExpense,int nbAccount)1236 SKGError SKGImportPluginKmy::exportCategories(QDomDocument& doc, QDomElement& accounts, const QString& stdUnit, QDomElement& accountIncome, QDomElement& accountExpense, int nbAccount)
1237 {
1238 // The v_category_display are retrieved to improve performances of getCurrentAmount
1239 SKGError err;
1240 SKGObjectBase::SKGListSKGObjectBase objects;
1241 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_category_display"), QString(), objects))
1242 accounts.setAttribute(QStringLiteral("count"), SKGServices::intToString(5 + nbAccount + objects.count()));
1243 int nb = objects.count();
1244 IFOK(err) {
1245 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export categories"), nb);
1246 for (int i = 0; !err && i < nb; ++i) {
1247 SKGCategoryObject obj(objects.at(i));
1248 QDomElement account = doc.createElement(QStringLiteral("ACCOUNT"));
1249 accounts.appendChild(account);
1250
1251 account.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(obj));
1252 account.setAttribute(QStringLiteral("name"), obj.getName());
1253 account.setAttribute(QStringLiteral("number"), QString());
1254 account.setAttribute(QStringLiteral("type"), obj.getCurrentAmount() < 0 ? QStringLiteral("13") : QStringLiteral("12"));
1255
1256 account.setAttribute(QStringLiteral("institution"), QString());
1257
1258 SKGCategoryObject parentCat;
1259 obj.getParentCategory(parentCat);
1260
1261 QString parentId = (parentCat.getID() != 0 ? getKmyUniqueIdentifier(parentCat) : (obj.getCurrentAmount() < 0 ? QStringLiteral("AStd::Expense") : QStringLiteral("AStd::Income")));
1262 if (parentId == QStringLiteral("AStd::Expense")) {
1263 QDomElement subaccount = doc.createElement(QStringLiteral("SUBACCOUNT"));
1264 accountExpense.appendChild(subaccount);
1265 subaccount.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(obj));
1266 } else if (parentId == QStringLiteral("AStd::Income")) {
1267 QDomElement subaccount = doc.createElement(QStringLiteral("SUBACCOUNT"));
1268 accountIncome.appendChild(subaccount);
1269 subaccount.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(obj));
1270 }
1271
1272 account.setAttribute(QStringLiteral("parentaccount"), parentId);
1273 account.setAttribute(QStringLiteral("lastmodified"), QString());
1274 account.setAttribute(QStringLiteral("lastreconciled"), QString());
1275 account.setAttribute(QStringLiteral("opened"), QString());
1276 account.setAttribute(QStringLiteral("currency"), stdUnit);
1277 account.setAttribute(QStringLiteral("description"), QString());
1278
1279 QDomElement subaccounts = doc.createElement(QStringLiteral("SUBACCOUNTS"));
1280 account.appendChild(subaccounts);
1281
1282 SKGObjectBase::SKGListSKGObjectBase categories;
1283 IFOKDO(err, obj.getCategories(categories))
1284 int nb2 = categories.count();
1285 for (int j = 0; !err && j < nb2; ++j) {
1286 QDomElement subaccount = doc.createElement(QStringLiteral("SUBACCOUNT"));
1287 subaccounts.appendChild(subaccount);
1288
1289 subaccount.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(categories.at(j)));
1290 }
1291 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
1292 }
1293
1294 SKGENDTRANSACTION(m_importer->getDocument(), err)
1295 }
1296 return err;
1297 }
1298
exportAccounts(QDomDocument & doc,QDomElement & root,const QString & stdUnit,QDomElement & accounts,QDomElement & accountIncome,QDomElement & accountExpense,int & nbAccounts)1299 SKGError SKGImportPluginKmy::exportAccounts(QDomDocument& doc, QDomElement& root, const QString& stdUnit, QDomElement& accounts, QDomElement& accountIncome, QDomElement& accountExpense, int& nbAccounts)
1300 {
1301 SKGError err;
1302 accounts = doc.createElement(QStringLiteral("ACCOUNTS"));
1303 root.appendChild(accounts);
1304
1305 QDomElement accountAsset;
1306 {
1307 QDomElement account = doc.createElement(QStringLiteral("ACCOUNT"));
1308 accounts.appendChild(account);
1309
1310 account.setAttribute(QStringLiteral("id"), QStringLiteral("AStd::Equity"));
1311 account.setAttribute(QStringLiteral("name"), QStringLiteral("Equity"));
1312 account.setAttribute(QStringLiteral("number"), QString());
1313 account.setAttribute(QStringLiteral("type"), QStringLiteral("16"));
1314 account.setAttribute(QStringLiteral("institution"), QString());
1315 account.setAttribute(QStringLiteral("parentaccount"), QString());
1316 account.setAttribute(QStringLiteral("lastmodified"), QString());
1317 account.setAttribute(QStringLiteral("lastreconciled"), QString());
1318 account.setAttribute(QStringLiteral("opened"), QString());
1319 account.setAttribute(QStringLiteral("currency"), stdUnit);
1320 account.setAttribute(QStringLiteral("description"), QString());
1321
1322 QDomElement subaccounts = doc.createElement(QStringLiteral("SUBACCOUNTS"));
1323 account.appendChild(subaccounts);
1324 }
1325
1326 {
1327 QDomElement account = doc.createElement(QStringLiteral("ACCOUNT"));
1328 accounts.appendChild(account);
1329
1330 account.setAttribute(QStringLiteral("id"), QStringLiteral("AStd::Asset"));
1331 account.setAttribute(QStringLiteral("name"), QStringLiteral("Asset"));
1332 account.setAttribute(QStringLiteral("number"), QString());
1333 account.setAttribute(QStringLiteral("type"), QStringLiteral("9"));
1334 account.setAttribute(QStringLiteral("institution"), QString());
1335 account.setAttribute(QStringLiteral("parentaccount"), QString());
1336 account.setAttribute(QStringLiteral("lastmodified"), QString());
1337 account.setAttribute(QStringLiteral("lastreconciled"), QString());
1338 account.setAttribute(QStringLiteral("opened"), QString());
1339 account.setAttribute(QStringLiteral("currency"), stdUnit);
1340 account.setAttribute(QStringLiteral("description"), QString());
1341
1342 QDomElement subaccounts = doc.createElement(QStringLiteral("SUBACCOUNTS"));
1343 account.appendChild(subaccounts);
1344 accountAsset = subaccounts;
1345 }
1346
1347 {
1348 QDomElement account = doc.createElement(QStringLiteral("ACCOUNT"));
1349 accounts.appendChild(account);
1350
1351 account.setAttribute(QStringLiteral("id"), QStringLiteral("AStd::Liability"));
1352 account.setAttribute(QStringLiteral("name"), QStringLiteral("Liability"));
1353 account.setAttribute(QStringLiteral("number"), QString());
1354 account.setAttribute(QStringLiteral("type"), QStringLiteral("10"));
1355 account.setAttribute(QStringLiteral("institution"), QString());
1356 account.setAttribute(QStringLiteral("parentaccount"), QString());
1357 account.setAttribute(QStringLiteral("lastmodified"), QString());
1358 account.setAttribute(QStringLiteral("lastreconciled"), QString());
1359 account.setAttribute(QStringLiteral("opened"), QString());
1360 account.setAttribute(QStringLiteral("currency"), stdUnit);
1361 account.setAttribute(QStringLiteral("description"), QString());
1362
1363 QDomElement subaccounts = doc.createElement(QStringLiteral("SUBACCOUNTS"));
1364 account.appendChild(subaccounts);
1365 }
1366
1367 {
1368 QDomElement account = doc.createElement(QStringLiteral("ACCOUNT"));
1369 accounts.appendChild(account);
1370
1371 account.setAttribute(QStringLiteral("id"), QStringLiteral("AStd::Income"));
1372 account.setAttribute(QStringLiteral("name"), QStringLiteral("Income"));
1373 account.setAttribute(QStringLiteral("number"), QString());
1374 account.setAttribute(QStringLiteral("type"), QStringLiteral("12"));
1375 account.setAttribute(QStringLiteral("institution"), QString());
1376 account.setAttribute(QStringLiteral("parentaccount"), QString());
1377 account.setAttribute(QStringLiteral("lastmodified"), QString());
1378 account.setAttribute(QStringLiteral("lastreconciled"), QString());
1379 account.setAttribute(QStringLiteral("opened"), QString());
1380 account.setAttribute(QStringLiteral("currency"), stdUnit);
1381 account.setAttribute(QStringLiteral("description"), QString());
1382
1383 QDomElement subaccounts = doc.createElement(QStringLiteral("SUBACCOUNTS"));
1384 account.appendChild(subaccounts);
1385 accountIncome = subaccounts;
1386 }
1387
1388 {
1389 QDomElement account = doc.createElement(QStringLiteral("ACCOUNT"));
1390 accounts.appendChild(account);
1391
1392 account.setAttribute(QStringLiteral("id"), QStringLiteral("AStd::Expense"));
1393 account.setAttribute(QStringLiteral("name"), QStringLiteral("Expense"));
1394 account.setAttribute(QStringLiteral("number"), QString());
1395 account.setAttribute(QStringLiteral("type"), QStringLiteral("13"));
1396 account.setAttribute(QStringLiteral("institution"), QString());
1397 account.setAttribute(QStringLiteral("parentaccount"), QString());
1398 account.setAttribute(QStringLiteral("lastmodified"), QString());
1399 account.setAttribute(QStringLiteral("lastreconciled"), QString());
1400 account.setAttribute(QStringLiteral("opened"), QString());
1401 account.setAttribute(QStringLiteral("currency"), stdUnit);
1402 account.setAttribute(QStringLiteral("description"), QString());
1403
1404 QDomElement subaccounts = doc.createElement(QStringLiteral("SUBACCOUNTS"));
1405 account.appendChild(subaccounts);
1406 accountExpense = subaccounts;
1407 }
1408
1409 SKGObjectBase::SKGListSKGObjectBase objects;
1410 IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_account"), QString(), objects))
1411 int nb = objects.count();
1412 IFOK(err) {
1413 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export accounts"), nb);
1414 for (int i = 0; !err && i < nb; ++i) {
1415 SKGAccountObject obj(objects.at(i));
1416 QDomElement account = doc.createElement(QStringLiteral("ACCOUNT"));
1417 accounts.appendChild(account);
1418
1419 account.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(obj));
1420 account.setAttribute(QStringLiteral("name"), obj.getName());
1421 account.setAttribute(QStringLiteral("number"), obj.getNumber());
1422 account.setAttribute(QStringLiteral("type"), obj.getType() == SKGAccountObject::CREDITCARD ? QStringLiteral("4") :
1423 (obj.getType() == SKGAccountObject::INVESTMENT ? QStringLiteral("7") :
1424 (obj.getType() == SKGAccountObject::ASSETS ? QStringLiteral("9") :
1425 (obj.getType() == SKGAccountObject::WALLET ? QStringLiteral("3") :
1426 (obj.getType() == SKGAccountObject::LOAN ? QStringLiteral("10") :
1427 QStringLiteral("1"))))));
1428
1429 SKGBankObject bank;
1430 err = obj.getBank(bank);
1431 account.setAttribute(QStringLiteral("institution"), getKmyUniqueIdentifier(bank));
1432
1433 account.setAttribute(QStringLiteral("parentaccount"), QStringLiteral("AStd::Asset"));
1434 account.setAttribute(QStringLiteral("lastmodified"), QString());
1435 account.setAttribute(QStringLiteral("lastreconciled"), QString());
1436 account.setAttribute(QStringLiteral("opened"), QString());
1437 SKGUnitObject unit;
1438 obj.getUnit(unit);
1439 QString unitS = SKGUnitObject::getInternationalCode(unit.getName());
1440 if (unitS.isEmpty()) {
1441 unitS = QStringLiteral("EUR");
1442 }
1443 account.setAttribute(QStringLiteral("currency"), unitS);
1444 account.setAttribute(QStringLiteral("description"), QString());
1445
1446 // Bookmarked account
1447 QDomElement keyvaluepairs = doc.createElement(QStringLiteral("KEYVALUEPAIRS"));
1448 account.appendChild(keyvaluepairs);
1449 if (obj.isBookmarked()) {
1450 QDomElement pair = doc.createElement(QStringLiteral("PAIR"));
1451 keyvaluepairs.appendChild(pair);
1452 pair.setAttribute(QStringLiteral("key"), QStringLiteral("PreferredAccount"));
1453 pair.setAttribute(QStringLiteral("value"), QStringLiteral("Yes"));
1454 }
1455 // Closed account
1456 if (obj.isClosed()) {
1457 QDomElement pair = doc.createElement(QStringLiteral("PAIR"));
1458 keyvaluepairs.appendChild(pair);
1459 pair.setAttribute(QStringLiteral("key"), QStringLiteral("mm-closed"));
1460 pair.setAttribute(QStringLiteral("value"), QStringLiteral("yes"));
1461 }
1462
1463 // Maximum and minimum limits
1464 if (obj.isMaxLimitAmountEnabled()) {
1465 QDomElement pair = doc.createElement(QStringLiteral("PAIR"));
1466 keyvaluepairs.appendChild(pair);
1467 pair.setAttribute(QStringLiteral("key"), QStringLiteral("maxCreditAbsolute"));
1468 pair.setAttribute(QStringLiteral("value"), kmyValue(-obj.getMaxLimitAmount()));
1469 }
1470 if (obj.isMinLimitAmountEnabled()) {
1471 QDomElement pair = doc.createElement(QStringLiteral("PAIR"));
1472 keyvaluepairs.appendChild(pair);
1473 pair.setAttribute(QStringLiteral("key"), QStringLiteral("minBalanceAbsolute"));
1474 pair.setAttribute(QStringLiteral("value"), kmyValue(obj.getMinLimitAmount()));
1475 }
1476
1477 // Add it in asset
1478 QDomElement subaccount = doc.createElement(QStringLiteral("SUBACCOUNT"));
1479 accountAsset.appendChild(subaccount);
1480 subaccount.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(obj));
1481
1482 IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
1483 }
1484
1485 SKGENDTRANSACTION(m_importer->getDocument(), err)
1486 }
1487
1488 nbAccounts = nb;
1489 return err;
1490 }
1491
exportFile()1492 SKGError SKGImportPluginKmy::exportFile()
1493 {
1494 // Initialisation
1495 m_opTreated.clear();
1496
1497 if (m_importer == nullptr) {
1498 return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
1499 }
1500 SKGError err;
1501 SKGTRACEINFUNCRC(2, err)
1502
1503 // Open file
1504 KCompressionDevice file(m_importer->getLocalFileName(false), KCompressionDevice::GZip);
1505 if (!file.open(QIODevice::WriteOnly)) {
1506 err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message", "Save file '%1' failed", m_importer->getFileName().toDisplayString()));
1507 } else {
1508 QDomDocument doc(QStringLiteral("KMYMONEY-FILE"));
1509 QDomComment comment = doc.createComment(QStringLiteral("Generated by libskgbankmodeler"));
1510 doc.appendChild(comment);
1511
1512 QDomElement root = doc.createElement(QStringLiteral("KMYMONEY-FILE"));
1513 doc.appendChild(root);
1514 {
1515 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export %1 file", "KMY"), 8);
1516 IFOK(err) {
1517 // Step 1-<FILEINFO>
1518 IFOKDO(err, exportHeader(doc, root))
1519 IFOKDO(err, m_importer->getDocument()->stepForward(1))
1520
1521 // // Step 2-<INSTITUTIONS>
1522 IFOKDO(err, exportInstitutions(doc, root))
1523 IFOKDO(err, m_importer->getDocument()->stepForward(2))
1524
1525 // Step 3-<PAYEES>
1526 IFOKDO(err, exportPayees(doc, root))
1527 IFOKDO(err, m_importer->getDocument()->stepForward(3))
1528
1529 // Step 4-<ACCOUNTS>
1530 // Std accounts
1531 QString stdUnit = SKGUnitObject::getInternationalCode(m_importer->getDocument()->getPrimaryUnit().Name);
1532 if (stdUnit.isEmpty()) {
1533 stdUnit = QStringLiteral("EUR");
1534 }
1535
1536 QDomElement accountIncome;
1537 QDomElement accountExpense;
1538 QDomElement accounts;
1539
1540 int nbAccounts = 0;
1541 IFOKDO(err, exportAccounts(doc, root, stdUnit, accounts, accountIncome, accountExpense, nbAccounts))
1542 IFOKDO(err, m_importer->getDocument()->stepForward(4))
1543
1544 // Step 5
1545 IFOKDO(err, exportCategories(doc, accounts, stdUnit, accountIncome, accountExpense, nbAccounts))
1546 IFOKDO(err, m_importer->getDocument()->stepForward(5))
1547
1548 // Step 6-<TRANSACTIONS>
1549 IFOKDO(err, exportTransactions(doc, root, stdUnit))
1550
1551 // Step 6-<SCHEDULES>
1552 IFOKDO(err, exportSchedules(doc, root))
1553 IFOKDO(err, m_importer->getDocument()->stepForward(6))
1554
1555 // Step 7-<BUDGETS>
1556 IFOKDO(err, exportBudgets(doc, root))
1557 IFOKDO(err, m_importer->getDocument()->stepForward(7))
1558
1559 // Step 8-<SECURITIES> and <CURRENCIES>
1560 IFOKDO(err, exportSecurities(doc, root, stdUnit))
1561
1562 // Save file
1563 IFOK(err) {
1564 file.write(doc.toString().toUtf8());
1565 }
1566 IFOKDO(err, m_importer->getDocument()->stepForward(8))
1567 }
1568
1569 SKGENDTRANSACTION(m_importer->getDocument(), err)
1570 }
1571
1572 file.close();
1573 }
1574
1575 // Clean
1576 m_opTreated.clear();
1577
1578 return err;
1579 }
1580
exportOperation(const SKGOperationObject & iOperation,QDomDocument & iDoc,QDomElement & iTransaction)1581 SKGError SKGImportPluginKmy::exportOperation(const SKGOperationObject& iOperation, QDomDocument& iDoc, QDomElement& iTransaction)
1582 {
1583 SKGError err;
1584 SKGTRACEINFUNCRC(2, err)
1585 if (!m_opTreated.contains(getKmyUniqueIdentifier(iOperation))) {
1586 QDomElement transaction = iDoc.createElement(QStringLiteral("TRANSACTION"));
1587 iTransaction.appendChild(transaction);
1588
1589 SKGUnitObject unit;
1590 iOperation.getUnit(unit);
1591
1592 QString date = iOperation.getAttribute(QStringLiteral("d_date"));
1593 transaction.setAttribute(QStringLiteral("id"), getKmyUniqueIdentifier(iOperation));
1594 transaction.setAttribute(QStringLiteral("entrydate"), date);
1595 transaction.setAttribute(QStringLiteral("postdate"), date);
1596 transaction.setAttribute(QStringLiteral("memo"), iOperation.getComment());
1597 transaction.setAttribute(QStringLiteral("commodity"), SKGUnitObject::getInternationalCode(unit.getName()));
1598
1599 QString reconcileflag = (iOperation.getStatus() == SKGOperationObject::POINTED ? QStringLiteral("1") : (iOperation.getStatus() == SKGOperationObject::CHECKED ? QStringLiteral("2") : QStringLiteral("0")));
1600
1601 SKGAccountObject act;
1602 IFOKDO(err, iOperation.getParentAccount(act))
1603
1604 QDomElement splits = iDoc.createElement(QStringLiteral("SPLITS"));
1605 transaction.appendChild(splits);
1606
1607 QDomElement split = iDoc.createElement(QStringLiteral("SPLIT"));
1608 splits.appendChild(split);
1609
1610 SKGPayeeObject payeeObject;
1611 iOperation.getPayee(payeeObject);
1612 QString payeeId = (payeeObject.getID() != 0 ? getKmyUniqueIdentifier(payeeObject) : QString());
1613
1614 int indexSubOp = 1;
1615
1616 // Split for account
1617 split.setAttribute(QStringLiteral("payee"), payeeId);
1618 split.setAttribute(QStringLiteral("reconciledate"), QString());
1619 split.setAttribute(QStringLiteral("id"), "S" % SKGServices::intToString(indexSubOp++).rightJustified(4, '0'));
1620 double val2 = SKGServices::stringToDouble(iOperation.getAttribute(QStringLiteral("f_QUANTITY")));
1621 split.setAttribute(QStringLiteral("shares"), SKGImportPluginKmy::kmyValue(val2));
1622 split.setAttribute(QStringLiteral("action"), QString());
1623 split.setAttribute(QStringLiteral("bankid"), QString());
1624 split.setAttribute(QStringLiteral("number"), iOperation.getNumber());
1625 split.setAttribute(QStringLiteral("reconcileflag"), reconcileflag);
1626 split.setAttribute(QStringLiteral("memo"), iOperation.getComment());
1627 QString originalAmount = iOperation.getProperty(QStringLiteral("SKG_OP_ORIGINAL_AMOUNT"));
1628 if (!originalAmount.isEmpty()) {
1629 val2 = qAbs(SKGServices::stringToDouble(originalAmount)) * (val2 / qAbs(val2));
1630 }
1631 split.setAttribute(QStringLiteral("value"), SKGImportPluginKmy::kmyValue(val2));
1632 split.setAttribute(QStringLiteral("account"), getKmyUniqueIdentifier(act));
1633
1634 SKGOperationObject obj2;
1635 if (!err && iOperation.isTransfer(obj2)) {
1636 // It is a Transfer
1637 QString reconcileflag2 = (obj2.getStatus() == SKGOperationObject::POINTED ? QStringLiteral("1") : (obj2.getStatus() == SKGOperationObject::CHECKED ? QStringLiteral("2") : QStringLiteral("0")));
1638
1639 SKGAccountObject act2;
1640 IFOKDO(err, obj2.getParentAccount(act2))
1641
1642 QDomElement split2 = iDoc.createElement(QStringLiteral("SPLIT"));
1643 splits.appendChild(split2);
1644
1645 // Split for account
1646 val2 = -val2;
1647 split2.setAttribute(QStringLiteral("payee"), payeeId);
1648 split2.setAttribute(QStringLiteral("reconciledate"), QString());
1649 split2.setAttribute(QStringLiteral("id"), "S" % SKGServices::intToString(indexSubOp++).rightJustified(4, '0'));
1650 split2.setAttribute(QStringLiteral("shares"), SKGImportPluginKmy::kmyValue(SKGServices::stringToDouble(obj2.getAttribute(QStringLiteral("f_QUANTITY")))));
1651 split2.setAttribute(QStringLiteral("action"), QString());
1652 split2.setAttribute(QStringLiteral("bankid"), QString());
1653 split2.setAttribute(QStringLiteral("number"), obj2.getNumber());
1654 split2.setAttribute(QStringLiteral("reconcileflag"), reconcileflag2);
1655 split2.setAttribute(QStringLiteral("memo"), obj2.getComment());
1656 split2.setAttribute(QStringLiteral("value"), SKGImportPluginKmy::kmyValue(val2));
1657 split2.setAttribute(QStringLiteral("account"), getKmyUniqueIdentifier(act2));
1658
1659 m_opTreated.insert(getKmyUniqueIdentifier(obj2));
1660 } else {
1661 SKGObjectBase::SKGListSKGObjectBase subops;
1662 IFOKDO(err, iOperation.getSubOperations(subops))
1663 int nb2 = subops.count();
1664 for (int j = 0; !err && j < nb2; ++j) {
1665 QDomElement split2 = iDoc.createElement(QStringLiteral("SPLIT"));
1666 splits.appendChild(split2);
1667
1668 SKGSubOperationObject subop(subops.at(j));
1669 SKGCategoryObject cat;
1670 subop.getCategory(cat);
1671 split2.setAttribute(QStringLiteral("payee"), payeeId);
1672 split2.setAttribute(QStringLiteral("reconciledate"), QString());
1673 split2.setAttribute(QStringLiteral("id"), "S" % SKGServices::intToString(indexSubOp++).rightJustified(4, '0'));
1674 QString shape3 = SKGImportPluginKmy::kmyValue(-subop.getQuantity());
1675 split2.setAttribute(QStringLiteral("shares"), shape3);
1676 split2.setAttribute(QStringLiteral("action"), QString());
1677 split2.setAttribute(QStringLiteral("bankid"), QString());
1678 split2.setAttribute(QStringLiteral("number"), iOperation.getNumber());
1679 split2.setAttribute(QStringLiteral("reconcileflag"), reconcileflag);
1680 split2.setAttribute(QStringLiteral("memo"), subop.getComment());
1681 split2.setAttribute(QStringLiteral("value"), shape3);
1682 split2.setAttribute(QStringLiteral("account"), date == QStringLiteral("0000-00-00") ? QStringLiteral("AStd::Equity") : (cat.getID() != 0 ? getKmyUniqueIdentifier(cat) : QString()));
1683 }
1684 }
1685
1686 m_opTreated.insert(getKmyUniqueIdentifier(iOperation));
1687 }
1688 return err;
1689 }
1690
kmyValue(double iValue)1691 QString SKGImportPluginKmy::kmyValue(double iValue)
1692 {
1693 QString output;
1694 for (int i = 0; output.isEmpty() && i < 11; ++i) {
1695 QString d = SKGServices::doubleToString(pow(10, i) * iValue);
1696 if (d.indexOf('.') == -1) {
1697 output = d % '/' % SKGServices::intToString(qPow(10, i));
1698 }
1699 }
1700 return output;
1701 }
1702
toKmyValue(const QString & iString)1703 double SKGImportPluginKmy::toKmyValue(const QString& iString)
1704 {
1705 double output = 0;
1706 QStringList vals = SKGServices::splitCSVLine(iString, '/');
1707 if (vals.count() == 1) {
1708 output = SKGServices::stringToDouble(vals.at(0));
1709 } else if (vals.count() == 2) {
1710 output = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));
1711 }
1712 return output;
1713 }
1714
getKmyUniqueIdentifier(const SKGObjectBase & iObject)1715 QString SKGImportPluginKmy::getKmyUniqueIdentifier(const SKGObjectBase& iObject)
1716 {
1717 QString id;
1718 if (iObject.getID() != 0) {
1719 QString table = iObject.getRealTable();
1720 if (table == QStringLiteral("operation") || table == QStringLiteral("suboperation")) {
1721 // T000000000000003623
1722 id = 'T' % SKGServices::intToString(iObject.getID()).rightJustified(18, '0');
1723 } else if (table == QStringLiteral("payee")) {
1724 // P000030
1725 id = 'P' % SKGServices::intToString(iObject.getID()).rightJustified(6, '0');
1726 } else {
1727 id = iObject.getUniqueID();
1728 }
1729 }
1730 return id;
1731 }
1732
getMimeTypeFilter() const1733 QString SKGImportPluginKmy::getMimeTypeFilter() const
1734 {
1735 return "*.kmy|" % i18nc("A file format", "KMyMoney document");
1736 }
1737
1738 #include <skgimportpluginkmy.moc>
1739