File indexing completed on 2025-02-09 06:04:45

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007  * This file is Skrooge plugin for KMY import / export.
0008  *
0009  * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgimportpluginkmy.h"
0012 
0013 #include <kcompressiondevice.h>
0014 #include <kpluginfactory.h>
0015 
0016 #include <qdom.h>
0017 #include <qmath.h>
0018 
0019 #include "skgbankincludes.h"
0020 #include "skgimportexportmanager.h"
0021 #include "skgobjectbase.h"
0022 #include "skgpayeeobject.h"
0023 #include "skgservices.h"
0024 #include "skgtraces.h"
0025 
0026 /**
0027  * Transactions treated.
0028  */
0029 QSet<QString> SKGImportPluginKmy::m_opTreated;
0030 
0031 /**
0032  * Map id / unit.
0033  */
0034 QMap<QString, SKGUnitObject> SKGImportPluginKmy::m_mapIdUnit;
0035 
0036 /**
0037  * Map id / account.
0038  */
0039 QMap<QString, SKGAccountObject> SKGImportPluginKmy::m_mapIdAccount;
0040 
0041 /**
0042  * Map id / category.
0043  */
0044 QMap<QString, SKGCategoryObject> SKGImportPluginKmy::m_mapIdCategory;
0045 
0046 /**
0047  * Map id / payee.
0048  */
0049 QMap<QString, SKGPayeeObject> SKGImportPluginKmy::m_mapIdPayee;
0050 
0051 /**
0052  * This plugin factory.
0053  */
0054 K_PLUGIN_CLASS_WITH_JSON(SKGImportPluginKmy, "metadata.json")
0055 
0056 SKGImportPluginKmy::SKGImportPluginKmy(QObject* iImporter, const QVariantList& iArg)
0057     : SKGImportPlugin(iImporter)
0058 {
0059     SKGTRACEINFUNC(10)
0060     Q_UNUSED(iArg)
0061 }
0062 
0063 SKGImportPluginKmy::~SKGImportPluginKmy()
0064     = default;
0065 
0066 bool SKGImportPluginKmy::isImportPossible()
0067 {
0068     SKGTRACEINFUNC(10)
0069     return isExportPossible();
0070 }
0071 
0072 SKGError SKGImportPluginKmy::importSecurities(QDomElement& docElem)
0073 {
0074     SKGError err;
0075     QDomElement securities = docElem.firstChildElement(QStringLiteral("SECURITIES"));
0076     if (!err && !securities.isNull()) {
0077         SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-SECURITIES", err)
0078         QDomNodeList securityList = securities.elementsByTagName(QStringLiteral("SECURITY"));
0079         int nb = securityList.count();
0080         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
0081         for (int i = 0; !err && i < nb; ++i) {
0082             QDomElement security = securityList.at(i).toElement();
0083             QString unitName = security.attribute(QStringLiteral("name"));
0084 
0085             // We try a creation
0086             SKGUnitObject unitObj(m_importer->getDocument());
0087             SKGUnitObject::createCurrencyUnit(m_importer->getDocument(), unitName, unitObj);
0088 
0089             if (!err && (unitObj.getID() == 0)) {
0090                 // Creation of unit
0091                 err = unitObj.setName(unitName);
0092                 QString symbol = security.attribute(QStringLiteral("symbol"));
0093                 if (symbol.isEmpty()) {
0094                     symbol = unitName;
0095                 }
0096                 IFOKDO(err, unitObj.setSymbol(symbol))
0097                 IFOKDO(err, unitObj.setCountry(security.attribute(QStringLiteral("trading-market"))))
0098                 IFOKDO(err, unitObj.setType(SKGUnitObject::SHARE))
0099                 IFOK(err) {
0100                     // Set pairs
0101                     QDomNodeList pairList = security.elementsByTagName(QStringLiteral("PAIR"));
0102                     int nb2 = pairList.count();
0103                     for (int j = 0; !err && j < nb2; ++j) {
0104                         QDomElement pair = pairList.at(j).toElement();
0105                         if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("kmm-security-id")) {
0106                             err = unitObj.setInternetCode(pair.attribute(QStringLiteral("value")));
0107                         }
0108                     }
0109                 }
0110                 IFOKDO(err, unitObj.save())
0111             }
0112 
0113             m_mapIdUnit[security.attribute(QStringLiteral("id"))] = unitObj;
0114 
0115             IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0116         }
0117 
0118         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0119     }
0120     return err;
0121 }
0122 
0123 SKGError SKGImportPluginKmy::importPrices(QDomElement& docElem)
0124 {
0125     SKGError err;
0126     QDomElement prices = docElem.firstChildElement(QStringLiteral("PRICES"));
0127     if (!err && !prices.isNull()) {
0128         SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-PRICES", err)
0129         QDomNodeList pricepairList = prices.elementsByTagName(QStringLiteral("PRICEPAIR"));
0130         int nb = pricepairList.count();
0131         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
0132         for (int i = 0; !err && i < nb; ++i) {
0133             QDomElement pricepair = pricepairList.at(i).toElement();
0134 
0135             SKGUnitObject unitObj = m_mapIdUnit.value(pricepair.attribute(QStringLiteral("from")));
0136             if (unitObj.getID() != 0) {
0137                 // Unit is existing
0138                 QDomNodeList pricesList = pricepair.elementsByTagName(QStringLiteral("PRICE"));
0139                 int nb2 = pricesList.count();
0140                 for (int j = 0; !err && j < nb2; ++j) {
0141                     QDomElement price = pricesList.at(j).toElement();
0142 
0143                     SKGUnitValueObject unitValObj;
0144                     err = unitObj.addUnitValue(unitValObj);
0145                     IFOKDO(err, unitValObj.setDate(QDate::fromString(price.attribute(QStringLiteral("date")), QStringLiteral("yyyy-MM-dd"))))
0146                     IFOKDO(err, unitValObj.setQuantity(toKmyValue(price.attribute(QStringLiteral("price")))))
0147                     IFOKDO(err, unitValObj.save(true, false))
0148                 }
0149             }
0150 
0151             IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0152         }
0153 
0154         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0155     }
0156     return err;
0157 }
0158 
0159 SKGError SKGImportPluginKmy::importInstitutions(QMap<QString, SKGBankObject>& mapIdBank, QDomElement& docElem)
0160 {
0161     SKGError err;
0162     QDomElement institutions = docElem.firstChildElement(QStringLiteral("INSTITUTIONS"));
0163     if (!err && !institutions.isNull()) {
0164         SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-INSTITUTIONS", err)
0165         QDomNodeList institutionList = institutions.elementsByTagName(QStringLiteral("INSTITUTION"));
0166         int nb = institutionList.count();
0167         for (int i = 0; !err && i < nb; ++i) {
0168             // Get bank object
0169             QDomElement bank = institutionList.at(i).toElement();
0170             SKGBankObject bankObject(m_importer->getDocument());
0171             err = bankObject.setName(bank.attribute(QStringLiteral("name")));
0172             IFOKDO(err, bankObject.setNumber(bank.attribute(QStringLiteral("sortcode"))))
0173             IFOKDO(err, bankObject.save())
0174             mapIdBank[bank.attribute(QStringLiteral("id"))] = bankObject;
0175         }
0176     }
0177     return err;
0178 }
0179 
0180 SKGError SKGImportPluginKmy::importPayees(QMap<QString, SKGPayeeObject>& mapIdPayee, QDomElement& docElem)
0181 {
0182     SKGError err;
0183     QDomElement payees = docElem.firstChildElement(QStringLiteral("PAYEES"));
0184     if (!err && !payees.isNull()) {
0185         SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-PAYEES", err)
0186         QDomNodeList payeeList = payees.elementsByTagName(QStringLiteral("PAYEE"));
0187         int nb = payeeList.count();
0188         for (int i = 0; !err && i < nb; ++i) {
0189             // Get account object
0190             QDomElement payee = payeeList.at(i).toElement();
0191             QDomElement address = payee.firstChildElement(QStringLiteral("ADDRESS"));
0192             SKGPayeeObject payeeObject;
0193             err = SKGPayeeObject::createPayee(m_importer->getDocument(), payee.attribute(QStringLiteral("name")), payeeObject);
0194             IFOK(err) {
0195                 QString add = address.attribute(QStringLiteral("street")) % ' ' % address.attribute(QStringLiteral("postcode")) % ' ' % address.attribute(QStringLiteral("city")) % ' ' % address.attribute(QStringLiteral("state")) % ' ' % address.attribute(QStringLiteral("telephone"));
0196                 add.replace(QStringLiteral("  "), QStringLiteral(" "));
0197                 err = payeeObject.setAddress(add.trimmed());
0198                 IFOKDO(err, payeeObject.save())
0199             }
0200             IFOK(err) {
0201                 mapIdPayee[payee.attribute(QStringLiteral("id"))] = payeeObject;
0202             }
0203         }
0204     }
0205     return err;
0206 }
0207 
0208 SKGError SKGImportPluginKmy::importTransactions(QDomElement& docElem, SKGAccountObject& kmymoneyTemporaryAccount, QMap<QString, SKGPayeeObject>& mapIdPayee)
0209 {
0210     SKGError err;
0211     SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-TRANSACTION", err)
0212     QDomNodeList transactionList = docElem.elementsByTagName(QStringLiteral("TRANSACTION"));
0213     int nb = transactionList.count();
0214     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import transactions"), nb);
0215     QVector<QDomNode> suboperationsList;
0216     for (int i = 0; !err && i < nb; ++i) {
0217         // Get transaction object
0218         QDomElement operation = transactionList.at(i).toElement();
0219 
0220         SKGOperationObject operationObj;
0221         err = kmymoneyTemporaryAccount.addOperation(operationObj, true);
0222         IFOKDO(err, operationObj.setDate(QDate::fromString(operation.attribute(QStringLiteral("postdate")), QStringLiteral("yyyy-MM-dd"))))
0223         IFOKDO(err, operationObj.setComment(operation.attribute(QStringLiteral("memo"))))
0224         IFOKDO(err, operationObj.setImported(true))
0225         IFOKDO(err, operationObj.setImportID("KMY-" % operation.attribute(QStringLiteral("id"))))
0226         IFOK(err) {
0227             QString unitName = operation.attribute(QStringLiteral("commodity"));
0228             if (unitName.isEmpty()) {
0229                 unitName = QStringLiteral("??");
0230             }
0231             SKGUnitObject unit(m_importer->getDocument());
0232             err = unit.setName(unitName);
0233             IFOKDO(err, unit.setSymbol(unitName))
0234             IFOK(err) {
0235                 if (unit.exist()) {
0236                     err = unit.load();
0237                 } else {
0238                     err = unit.save();
0239                 }
0240 
0241                 IFOKDO(err, operationObj.setUnit(unit))
0242             }
0243         }
0244         IFOKDO(err, operationObj.save(false, false))
0245 
0246         // Is it a schedule ?
0247         IFOK(err) {
0248             QDomElement recu = operation.parentNode().toElement();
0249             if (recu.tagName() == QStringLiteral("SCHEDULED_TX")) {
0250                 // Yes ==> creation of the schedule
0251                 IFOKDO(err, operationObj.load())
0252                 IFOKDO(err, operationObj.setTemplate(true))
0253                 IFOKDO(err, operationObj.save(true, false))
0254 
0255                 // Yes ==> creation of the schedule
0256                 SKGRecurrentOperationObject recuObj;
0257                 IFOKDO(err, operationObj.addRecurrentOperation(recuObj))
0258                 IFOKDO(err, recuObj.setDate(operationObj.getDate()))
0259                 IFOKDO(err, recuObj.autoWriteEnabled(recu.attribute(QStringLiteral("autoEnter")) == QStringLiteral("1")))
0260                 IFOKDO(err, recuObj.setAutoWriteDays(0))
0261 
0262                 int occu = SKGServices::stringToInt(recu.attribute(QStringLiteral("occurenceMultiplier")));
0263                 QString occuType = recu.attribute(QStringLiteral("occurence"));  // krazy:exclude=spelling
0264                 SKGRecurrentOperationObject::PeriodUnit period;
0265                 if (occuType == QStringLiteral("32") ||
0266                     occuType == QStringLiteral("1024") ||
0267                     occuType == QStringLiteral("256") ||
0268                     occuType == QStringLiteral("8192")) {
0269                     period = SKGRecurrentOperationObject::MONTH;
0270                 } else if (occuType == QStringLiteral("1")) {
0271                     period = SKGRecurrentOperationObject::DAY;
0272                     IFOKDO(err, recuObj.timeLimit(true))
0273                     IFOKDO(err, recuObj.setTimeLimit(1))
0274                 } else if (occuType == QStringLiteral("2")) {
0275                     period = SKGRecurrentOperationObject::DAY;
0276                 } else if (occuType == QStringLiteral("4")) {
0277                     period = SKGRecurrentOperationObject::WEEK;
0278                 } else if (occuType == QStringLiteral("18")) {
0279                     period = SKGRecurrentOperationObject::WEEK;
0280                     occu *= 2;
0281                 } else {
0282                     period = SKGRecurrentOperationObject::YEAR;
0283                 }
0284 
0285                 IFOKDO(err, recuObj.setPeriodIncrement(occu))
0286                 IFOKDO(err, recuObj.setPeriodUnit(period))
0287 
0288                 IFOK(err) {
0289                     QString endDate = recu.attribute(QStringLiteral("endDate"));
0290                     if (!endDate.isEmpty()) {
0291                         IFOKDO(err, recuObj.timeLimit(true))
0292                         IFOKDO(err, recuObj.setTimeLimit(QDate::fromString(recu.attribute(QStringLiteral("endDate")), QStringLiteral("yyyy-MM-dd"))))
0293                     }
0294                 }
0295 
0296                 if (occuType == QStringLiteral("1") && !recu.attribute(QStringLiteral("lastPayment")).isEmpty()) {
0297                     // Single schedule already done
0298                     IFOKDO(err, recuObj.timeLimit(true))
0299                     IFOKDO(err, recuObj.setTimeLimit(0))
0300                 }
0301                 IFOKDO(err, recuObj.save(true, false))
0302             }
0303         }
0304 
0305         // Get splits
0306         bool parentSet = false;
0307         double quantity = 0;
0308         QDomElement splits = operation.firstChildElement(QStringLiteral("SPLITS"));
0309 
0310         int nbSuboperations = 0;
0311         suboperationsList.resize(0);
0312         {
0313             QDomNodeList suboperationsListTmp = splits.elementsByTagName(QStringLiteral("SPLIT"));
0314             nbSuboperations = suboperationsListTmp.count();
0315 
0316             for (int j = 0; !err && j < nbSuboperations; ++j) {
0317                 QDomElement suboperation = suboperationsListTmp.at(j).toElement();
0318                 if (m_mapIdCategory.contains(suboperation.attribute(QStringLiteral("account")))) {
0319                     suboperationsList.push_front(suboperation);
0320                 } else {
0321                     suboperationsList.push_back(suboperation);
0322                 }
0323             }
0324         }
0325 
0326         SKGSubOperationObject suboperationObj;
0327         for (int j = 0; !err && j < nbSuboperations; ++j) {
0328             QDomElement suboperation = suboperationsList.at(j).toElement();
0329 
0330             // Set transaction attributes
0331             IFOKDO(err, operationObj.setPayee(mapIdPayee[suboperation.attribute(QStringLiteral("payee"))]))
0332             if (!err && operationObj.getComment().isEmpty()) {
0333                 err = operationObj.setComment(suboperation.attribute(QStringLiteral("memo")));
0334             }
0335             IFOKDO(err, operationObj.setNumber(suboperation.attribute(QStringLiteral("number"))))
0336 
0337             // Set state
0338             if (operationObj.getStatus() == SKGOperationObject::NONE) {
0339                 QString val = suboperation.attribute(QStringLiteral("reconcileflag"));
0340                 IFOKDO(err, operationObj.setStatus(val == QStringLiteral("1") ? SKGOperationObject::MARKED : val == QStringLiteral("2") ? SKGOperationObject::CHECKED : SKGOperationObject::NONE))
0341             }
0342             IFOKDO(err, operationObj.save())
0343 
0344             if (m_mapIdCategory.contains(suboperation.attribute(QStringLiteral("account")))) {
0345                 // It is a split on category
0346                 SKGCategoryObject cat = m_mapIdCategory.value(suboperation.attribute(QStringLiteral("account")));
0347 
0348                 double q = -toKmyValue(suboperation.attribute(QStringLiteral("shares")));
0349                 if (!err && ((suboperationObj.getID() == 0) || suboperationObj.getQuantity() != q)) {
0350                     err = operationObj.addSubOperation(suboperationObj);
0351                 }
0352                 IFOKDO(err, suboperationObj.setQuantity(q))
0353                 IFOKDO(err, suboperationObj.setCategory(cat))
0354                 IFOKDO(err, suboperationObj.setComment(suboperation.attribute(QStringLiteral("memo"))))
0355                 IFOKDO(err, suboperationObj.save(true, false))
0356             } else {
0357                 QString accountSubOp = suboperation.attribute(QStringLiteral("account"));
0358                 if (!accountSubOp.isEmpty()) {
0359                     if (nbSuboperations == 1) {
0360                         SKGUnitObject unit = m_mapIdUnit.value(accountSubOp);
0361                         if (unit.getID() != 0) {
0362                             IFOKDO(err, operationObj.setUnit(unit))
0363                         }
0364                     }
0365 
0366                     if (!m_mapIdAccount.contains(accountSubOp) || (nbSuboperations == 2 &&
0367                             m_mapIdAccount.value(accountSubOp) == kmymoneyTemporaryAccount &&
0368                             suboperationsList.at(0).toElement().attribute(QStringLiteral("action")).isEmpty() &&
0369                             suboperationsList.at(1).toElement().attribute(QStringLiteral("action")).isEmpty())) {
0370                         // Set as initial balance
0371                         IFOKDO(err, operationObj.setAttribute(QStringLiteral("d_date"), QStringLiteral("0000-00-00")))
0372                         IFOKDO(err, operationObj.setStatus(SKGOperationObject::CHECKED))
0373                         IFOKDO(err, operationObj.save(true, false))
0374 
0375                         if (!err && (suboperationObj.getID() == 0)) {
0376                             err = operationObj.addSubOperation(suboperationObj);
0377                         }
0378 
0379                         IFOKDO(err, suboperationObj.setAttribute(QStringLiteral("d_date"), QStringLiteral("0000-00-00")))
0380                         IFOKDO(err, suboperationObj.save(true, false))
0381                     } else {
0382                         // It is a transfer of account
0383                         SKGAccountObject act = m_mapIdAccount.value(accountSubOp);
0384 
0385                         if (parentSet) {
0386                             // If the parent is already set, it means that is a transfer
0387                             SKGOperationObject operationObj2;
0388                             IFOKDO(err, act.addOperation(operationObj2, true))
0389                             IFOKDO(err, operationObj2.setTemplate(operationObj.isTemplate()))
0390                             IFOKDO(err, operationObj2.setDate(operationObj.getDate()))
0391                             IFOKDO(err, operationObj2.setNumber(operationObj.getNumber()))
0392                             IFOKDO(err, operationObj2.setComment(operationObj.getComment()))
0393                             SKGPayeeObject payeeObject;
0394                             operationObj.getPayee(payeeObject);
0395                             IFOKDO(err, operationObj2.setPayee(payeeObject))
0396                             IFOK(err) {
0397                                 QString val = suboperation.attribute(QStringLiteral("reconcileflag"));
0398                                 err = operationObj2.setStatus(val == QStringLiteral("1") ? SKGOperationObject::MARKED : val == QStringLiteral("2") ? SKGOperationObject::CHECKED : SKGOperationObject::NONE);
0399                             }
0400                             IFOKDO(err, operationObj2.setImported(true))
0401                             IFOKDO(err, operationObj2.setImportID(operationObj.getImportID()))
0402 
0403                             SKGUnitObject unit = m_mapIdUnit.value(accountSubOp);
0404                             if (unit.getID() != 0) {
0405                                 IFOKDO(err, operationObj2.setUnit(unit))
0406                             } else {
0407                                 IFOKDO(err, operationObj.getUnit(unit))
0408                                 IFOKDO(err, operationObj2.setUnit(unit))
0409                             }
0410                             IFOKDO(err, operationObj2.save())
0411                             IFOKDO(err, operationObj2.setGroupOperation(operationObj))
0412                             IFOKDO(err, operationObj2.save())
0413 
0414                             // Create sub transaction on operationObj2
0415                             SKGSubOperationObject suboperationObj2;
0416                             IFOKDO(err, operationObj2.addSubOperation(suboperationObj2))
0417                             IFOK(err) {
0418                                 // We must take the quality of the split having an action
0419                                 quantity = toKmyValue(suboperation.attribute(QStringLiteral("shares")));
0420                                 err = suboperationObj2.setQuantity(quantity);
0421                             }
0422                             IFOKDO(err, suboperationObj2.setComment(suboperation.attribute(QStringLiteral("memo"))))
0423                             IFOKDO(err, suboperationObj2.save(true, false))
0424                         } else {
0425                             // We set the parent
0426                             if (Q_LIKELY(!err) && (act.getID() == 0)) {
0427                                 err = SKGError(ERR_FAIL, i18nc("Error message", "Account with identifier %1 not found", suboperation.attribute(QStringLiteral("account"))));
0428                             }
0429                             IFOKDO(err, operationObj.setParentAccount(act, true))
0430                             IFOKDO(err, operationObj.save())
0431 
0432                             // Compute quantity
0433                             quantity = toKmyValue(suboperation.attribute(QStringLiteral("shares")));
0434 
0435                             // Create sub transaction on operationObj
0436                             quantity -= SKGServices::stringToDouble(operationObj.getAttribute(QStringLiteral("f_QUANTITY")));
0437                             if (quantity != 0 || nbSuboperations == 1) {
0438                                 IFOKDO(err, operationObj.addSubOperation(suboperationObj))
0439                                 IFOKDO(err, suboperationObj.setQuantity(quantity))
0440                                 IFOKDO(err, suboperationObj.setComment(suboperation.attribute(QStringLiteral("memo"))))
0441                                 IFOKDO(err, suboperationObj.save(true, false))
0442                             }
0443 
0444                             parentSet = true;
0445                         }
0446                     }
0447                 }
0448             }
0449         }
0450 
0451         if (!err && i % 500 == 0) {
0452             err = m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE"));
0453         }
0454 
0455         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0456     }
0457 
0458     SKGENDTRANSACTION(m_importer->getDocument(),  err)
0459 
0460     return err;
0461 }
0462 
0463 SKGError SKGImportPluginKmy::importBudget(QDomElement& docElem)
0464 {
0465     SKGError err;
0466     QDomElement budgets = docElem.firstChildElement(QStringLiteral("BUDGETS"));
0467     if (!err && !budgets.isNull()) {
0468         SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-BUDGETS", err)
0469         // Build cache of categories
0470         QMap<int, bool> catExpense;
0471         {
0472             SKGStringListList list;
0473             err = m_importer->getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT id, t_TYPEEXPENSE FROM v_category_display"), list);
0474             int nb = list.count();
0475             for (int i = 1; i < nb; ++i) {
0476                 catExpense[SKGServices::stringToInt(list.at(i).at(0))] = (list.at(i).at(0) == QStringLiteral("-"));
0477             }
0478         }
0479 
0480         QDomNodeList budgetList = budgets.elementsByTagName(QStringLiteral("BUDGET"));
0481         int nb = budgetList.count();
0482         IFOKDO(err, m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import budgets"), nb))
0483         for (int i = 0; !err && i < nb; ++i) {
0484             QDomElement budget = budgetList.at(i).toElement();
0485             QDomNodeList accountList = budget.elementsByTagName(QStringLiteral("ACCOUNT"));
0486             int nb2 = accountList.count();
0487             for (int j = 0; !err && j < nb2; ++j) {
0488                 QDomElement account = accountList.at(j).toElement();
0489                 SKGCategoryObject cat = m_mapIdCategory.value(account.attribute(QStringLiteral("id")));
0490                 QString budgetlevel = account.attribute(QStringLiteral("budgetlevel"));
0491 
0492                 QDomNodeList periodList = account.elementsByTagName(QStringLiteral("PERIOD"));
0493                 int nb3 = periodList.count();
0494                 for (int k = 0; !err && k < nb3; ++k) {
0495                     QDomElement period = periodList.at(k).toElement();
0496 
0497                     double q = toKmyValue(period.attribute(QStringLiteral("amount")));
0498 
0499                     // Are we able to find to sign with the category ?
0500                     if (catExpense[cat.getID()]) {
0501                         q = -q;
0502                     }
0503 
0504                     QStringList dates = SKGServices::splitCSVLine(period.attribute(QStringLiteral("start")), '-');
0505                     if (dates.count() == 3) {
0506                         // We try a creation
0507                         for (int m = 1; !err && m <= (budgetlevel == QStringLiteral("monthly") ? 12 : 1); ++m) {
0508                             SKGBudgetObject budget2(m_importer->getDocument());
0509                             err = budget2.setCategory(cat);
0510                             IFOKDO(err, budget2.setBudgetedAmount(q))
0511                             IFOKDO(err, budget2.setYear(SKGServices::stringToDouble(dates.at(0))))
0512                             IFOKDO(err, budget2.setMonth(budgetlevel == QStringLiteral("monthbymonth") ? SKGServices::stringToDouble(dates.at(1)) :
0513                                                          budgetlevel == QStringLiteral("yearly") ? 0 : m));
0514                             IFOKDO(err, budget2.save(true, false))
0515                         }
0516                     }
0517                 }
0518             }
0519 
0520             IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0521         }
0522 
0523         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0524     }
0525     return err;
0526 }
0527 
0528 SKGError SKGImportPluginKmy::importAccounts(SKGBankObject& bank, SKGAccountObject& kmymoneyTemporaryAccount, QMap<QString, SKGBankObject>& mapIdBank, QDomElement& docElem)
0529 {
0530     SKGError err;
0531     IFOKDO(err, m_importer->getDocument()->addOrModifyAccount(QStringLiteral("KMYMONEY-TEMPORARY-ACCOUNT"), QString(), QStringLiteral("KMYMONEY")))
0532     IFOKDO(err, bank.setName(QStringLiteral("KMYMONEY")))
0533     IFOKDO(err, bank.load())
0534     IFOKDO(err, kmymoneyTemporaryAccount.setName(QStringLiteral("KMYMONEY-TEMPORARY-ACCOUNT")))
0535     IFOKDO(err, kmymoneyTemporaryAccount.load())
0536 
0537     QDomElement accounts = docElem.firstChildElement(QStringLiteral("ACCOUNTS"));
0538     if (!err && !accounts.isNull()) {
0539         SKGTRACEINRC(10, "SKGImportPluginKmy::importFile-ACCOUNTS", err)
0540         QDomNodeList accountList = accounts.elementsByTagName(QStringLiteral("ACCOUNT"));
0541         int nb = accountList.count();
0542         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import accounts"), nb);
0543         QMap<QString, QString> type15Account;
0544         QMap<QString, QString> type15Unit;
0545         for (int i = 0; !err && i < nb; ++i) {
0546             // Get account object
0547             QDomElement account = accountList.at(i).toElement();
0548             QString type = account.attribute(QStringLiteral("type"));
0549             if (type == QStringLiteral("15")) {
0550                 // Actions: the real account is the parent
0551                 type15Account[account.attribute(QStringLiteral("id"))] = account.attribute(QStringLiteral("parentaccount"));
0552                 type15Unit[account.attribute(QStringLiteral("id"))] = account.attribute(QStringLiteral("currency"));
0553             } else if (type != QStringLiteral("12") && type != QStringLiteral("13") && type != QStringLiteral("16")) {
0554                 // Get the bank
0555                 QString bankId = account.attribute(QStringLiteral("institution"));
0556                 SKGBankObject bankObj = (bankId.isEmpty() ? bank : mapIdBank[account.attribute(QStringLiteral("institution"))]);
0557 
0558                 // Creation of the account
0559                 SKGAccountObject accountObj;
0560                 IFOKDO(err, bankObj.addAccount(accountObj))
0561                 IFOKDO(err, accountObj.setName(account.attribute(QStringLiteral("name"))))
0562                 IFOKDO(err, accountObj.setNumber(account.attribute(QStringLiteral("number"))))
0563                 IFOKDO(err, accountObj.setComment(account.attribute(QStringLiteral("description"))))
0564                 IFOK(err) {
0565                     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)))));
0566                     err = accountObj.setType(typeA);
0567                 }
0568                 IFOK(err) {
0569                     // Set pairs
0570                     QDomNodeList pairList = account.elementsByTagName(QStringLiteral("PAIR"));
0571                     int nb2 = pairList.count();
0572                     for (int j = 0; !err && j < nb2; ++j) {
0573                         QDomElement pair = pairList.at(j).toElement();
0574                         if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("mm-closed") && pair.attribute(QStringLiteral("value")).toLower() == QStringLiteral("yes")) {
0575                             err = accountObj.setClosed(true);
0576                         } else if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("preferredaccount") && pair.attribute(QStringLiteral("value")).toLower() == QStringLiteral("yes")) {
0577                             err = accountObj.bookmark(true);
0578                         } else if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("minbalanceabsolute")) {
0579                             err = accountObj.setMinLimitAmount(toKmyValue(pair.attribute(QStringLiteral("value"))));
0580                             IFOKDO(err, accountObj.minLimitAmountEnabled(true))
0581                         } else if (pair.attribute(QStringLiteral("key")).toLower() == QStringLiteral("maxcreditabsolute")) {
0582                             err = accountObj.setMaxLimitAmount(-toKmyValue(pair.attribute(QStringLiteral("value"))));
0583                             IFOKDO(err, accountObj.maxLimitAmountEnabled(true))
0584                         }
0585                     }
0586                 }
0587                 IFOKDO(err, accountObj.save())
0588 
0589                 // Change parent bank in case of ASSETS
0590                 if (accountObj.getType() == SKGAccountObject::WALLET) {
0591                     // Get blank bank
0592                     SKGBankObject blankBank(m_importer->getDocument());
0593                     IFOKDO(err, blankBank.setName(QString()))
0594                     if (blankBank.exist()) {
0595                         err = blankBank.load();
0596                     } else {
0597                         err = blankBank.save();
0598                     }
0599                     IFOKDO(err, accountObj.setBank(blankBank))
0600                     IFOKDO(err, accountObj.save())
0601                 }
0602 
0603                 m_mapIdAccount[account.attribute(QStringLiteral("id"))] = accountObj;
0604             } else if (type == QStringLiteral("16")) {
0605                 m_mapIdAccount[account.attribute(QStringLiteral("id"))] = kmymoneyTemporaryAccount;
0606             } else {
0607                 // Create category
0608                 SKGCategoryObject cat = m_mapIdCategory.value(account.attribute(QStringLiteral("id")));
0609                 if (cat.getID() != 0) {
0610                     // Already existing ==> we must set the right name
0611                     err = cat.setName(account.attribute(QStringLiteral("name")));
0612                     IFOKDO(err, cat.save())
0613                 } else {
0614                     // We must create it
0615                     cat = SKGCategoryObject(m_importer->getDocument());
0616                     err = cat.setName(account.attribute(QStringLiteral("name")));
0617                     IFOKDO(err, cat.save())
0618                 }
0619                 if (err) {
0620                     // The category already exists
0621                     SKGCategoryObject catp;
0622                     err = cat.getParentCategory(catp);
0623                     QString fullName = catp.getFullName() % OBJECTSEPARATOR % cat.getName();
0624                     IFOKDO(err, cat.remove(false))
0625                     IFOKDO(err, SKGCategoryObject::createPathCategory(m_importer->getDocument(), fullName, cat))
0626                 }
0627                 m_mapIdCategory[account.attribute(QStringLiteral("id"))] = cat;
0628 
0629                 // Create sub categories
0630                 QDomNodeList subaccountList = account.elementsByTagName(QStringLiteral("SUBACCOUNT"));
0631                 int nb2 = subaccountList.count();
0632                 for (int j = 0; !err && j < nb2; ++j) {
0633                     QDomElement subaccount = subaccountList.at(j).toElement();
0634 
0635                     // Is child already existing ?
0636                     SKGCategoryObject cat2 = m_mapIdCategory.value(subaccount.attribute(QStringLiteral("id")));
0637                     if (cat2.getID() != 0) {
0638                         // Yes ==> reparent
0639                         err = cat2.setParentCategory(cat);
0640                         IFOKDO(err, cat2.save(true, false))
0641                     } else {
0642                         // No ==> create
0643                         IFOKDO(err, cat.addCategory(cat2))
0644                         IFOKDO(err, cat2.setName(subaccount.attribute(QStringLiteral("id"))))
0645                         IFOKDO(err, cat2.save())
0646                         m_mapIdCategory[subaccount.attribute(QStringLiteral("id"))] = cat2;
0647                     }
0648                 }
0649             }
0650 
0651             QStringList list = type15Account.keys();
0652             for (const auto& k : qAsConst(list)) {
0653                 m_mapIdAccount[k] = m_mapIdAccount.value(type15Account[k]);
0654                 m_mapIdUnit[account.attribute(QStringLiteral("id"))] = m_mapIdUnit.value(account.attribute(QStringLiteral("currency")));
0655             }
0656 
0657             list = type15Unit.keys();
0658             for (const auto& k : qAsConst(list)) {
0659                 m_mapIdUnit[k] = m_mapIdUnit[type15Unit[k]];
0660             }
0661 
0662             IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0663         }
0664 
0665         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0666     }
0667     return err;
0668 }
0669 
0670 SKGError SKGImportPluginKmy::importFile()
0671 {
0672     if (m_importer->getDocument() == nullptr) {
0673         return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
0674     }
0675 
0676     SKGError err;
0677     SKGTRACEINFUNCRC(2, err)
0678 
0679     // Initialisation
0680     m_mapIdUnit.clear();
0681     m_mapIdAccount.clear();
0682     m_mapIdCategory.clear();
0683     m_mapIdPayee.clear();
0684 
0685     // Open file
0686     KCompressionDevice file(m_importer->getLocalFileName(), KCompressionDevice::GZip);
0687     if (!file.open(QIODevice::ReadOnly)) {
0688         err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Open file '%1' failed", m_importer->getFileName().toDisplayString()));
0689     } else {
0690         QDomDocument doc;
0691 
0692         // Set the file without uncompression
0693         QString errorMsg;
0694         int errorLine = 0;
0695         int errorCol = 0;
0696         bool contentOK = doc.setContent(file.readAll(), &errorMsg, &errorLine, &errorCol);
0697         file.close();
0698 
0699         if (!contentOK) {
0700             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()));
0701         } else {
0702             // Get root
0703             QDomElement docElem = doc.documentElement();
0704             err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "KMY"), 8);
0705 
0706             // Step 1-Get units
0707             IFOKDO(err, importSecurities(docElem))
0708             IFOKDO(err, m_importer->getDocument()->stepForward(1))
0709 
0710             // Step 2-Get units prices
0711             IFOKDO(err, importPrices(docElem))
0712             IFOKDO(err, m_importer->getDocument()->stepForward(2))
0713 
0714             // Step 3-Create banks
0715             QMap<QString, SKGBankObject> mapIdBank;
0716             IFOKDO(err, importInstitutions(mapIdBank, docElem))
0717             IFOKDO(err, m_importer->getDocument()->stepForward(3))
0718 
0719             // Step 4-Create account and categories
0720             // Create bank and temporary account for kmymoney import
0721             SKGAccountObject kmymoneyTemporaryAccount(m_importer->getDocument());
0722             SKGBankObject bank(m_importer->getDocument());
0723             IFOKDO(err, importAccounts(bank, kmymoneyTemporaryAccount, mapIdBank, docElem))
0724             IFOKDO(err, m_importer->getDocument()->stepForward(4))
0725 
0726             // Step 5-Read payees
0727             QMap<QString, SKGPayeeObject> mapIdPayee;
0728             IFOKDO(err, importPayees(mapIdPayee, docElem))
0729             IFOKDO(err, m_importer->getDocument()->stepForward(5))
0730 
0731             // Step 6-Create transactions
0732             IFOKDO(err, importTransactions(docElem, kmymoneyTemporaryAccount, mapIdPayee))
0733             IFOKDO(err, m_importer->getDocument()->stepForward(6))
0734 
0735             // Step 7-Get budgets
0736             IFOKDO(err, importBudget(docElem))
0737             IFOKDO(err, m_importer->getDocument()->stepForward(7))
0738 
0739             // Step 8-Remove useless account and temporary account
0740             {
0741                 IFOKDO(err, kmymoneyTemporaryAccount.remove(false, true))
0742                 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"))
0743             }
0744             IFOKDO(err, m_importer->getDocument()->stepForward(8))
0745 
0746             SKGENDTRANSACTION(m_importer->getDocument(),  err)
0747 
0748             IFOKDO(err, m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE")))
0749         }
0750     }
0751 
0752     // Clean
0753     m_mapIdUnit.clear();
0754     m_mapIdAccount.clear();
0755     m_mapIdCategory.clear();
0756     m_mapIdPayee.clear();
0757 
0758     return err;
0759 }
0760 
0761 bool SKGImportPluginKmy::isExportPossible()
0762 {
0763     SKGTRACEINFUNC(10)
0764     return (m_importer->getDocument() == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("KMY"));
0765 }
0766 
0767 SKGError SKGImportPluginKmy::exportHeader(QDomDocument& doc, QDomElement& root)
0768 {
0769     SKGError err;
0770     QDomElement fileindo = doc.createElement(QStringLiteral("FILEINFO"));
0771     root.appendChild(fileindo);
0772 
0773     {
0774         // <CREATION_DATE>
0775         QDomElement creation_date = doc.createElement(QStringLiteral("CREATION_DATE"));
0776         fileindo.appendChild(creation_date);
0777         creation_date.setAttribute(QStringLiteral("date"), SKGServices::dateToSqlString(QDateTime::currentDateTime()));
0778 
0779         // <LAST_MODIFIED_DATE>
0780         QDomElement last_modified_date = doc.createElement(QStringLiteral("LAST_MODIFIED_DATE"));
0781         fileindo.appendChild(last_modified_date);
0782         last_modified_date.setAttribute(QStringLiteral("date"), SKGServices::dateToSqlString(QDateTime::currentDateTime()));
0783 
0784         // <VERSION>
0785         QDomElement version = doc.createElement(QStringLiteral("VERSION"));
0786         fileindo.appendChild(version);
0787         version.setAttribute(QStringLiteral("id"), QStringLiteral("1"));
0788 
0789         // <FIXVERSION>
0790         QDomElement fixversion = doc.createElement(QStringLiteral("FIXVERSION"));
0791         fileindo.appendChild(fixversion);
0792         fixversion.setAttribute(QStringLiteral("id"), QStringLiteral("2"));
0793     }
0794 
0795     // <USER>
0796     QDomElement user = doc.createElement(QStringLiteral("USER"));
0797     root.appendChild(user);
0798     user.setAttribute(QStringLiteral("email"), QString());
0799     user.setAttribute(QStringLiteral("name"), QString());
0800     {
0801         // ADDRESS
0802         QDomElement address = doc.createElement(QStringLiteral("ADDRESS"));
0803         user.appendChild(address);
0804         address.setAttribute(QStringLiteral("street"), QString());
0805         address.setAttribute(QStringLiteral("zipcode"), QString());
0806         address.setAttribute(QStringLiteral("county"), QString());
0807         address.setAttribute(QStringLiteral("city"), QString());
0808         address.setAttribute(QStringLiteral("telephone"), QString());
0809     }
0810     return err;
0811 }
0812 
0813 SKGError SKGImportPluginKmy::exportSecurities(QDomDocument& doc, QDomElement& root, const QString& stdUnit)
0814 {
0815     SKGError err;
0816     QDomElement securities = doc.createElement(QStringLiteral("SECURITIES"));
0817     root.appendChild(securities);
0818 
0819     QDomElement currencies = doc.createElement(QStringLiteral("CURRENCIES"));
0820     root.appendChild(currencies);
0821 
0822     SKGObjectBase::SKGListSKGObjectBase objects;
0823     IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_unit"), QStringLiteral("t_type!='I'"), objects))
0824     int nb = objects.count();
0825     securities.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
0826 
0827     QStringList importedCurrency;
0828     IFOK(err) {
0829         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
0830         for (int i = 0; !err && i < nb; ++i) {
0831             SKGUnitObject obj(objects.at(i));
0832             if (obj.getType() == SKGUnitObject::SHARE || obj.getType() == SKGUnitObject::OBJECT) {
0833                 QDomElement security = doc.createElement(QStringLiteral("SECURITY"));
0834                 securities.appendChild(security);
0835 
0836                 SKGUnitObject parentUnit;
0837                 obj.getUnit(parentUnit);
0838                 QString unitP = SKGUnitObject::getInternationalCode(parentUnit.getName());
0839                 if (unitP.isEmpty()) {
0840                     unitP = stdUnit;
0841                 }
0842 
0843                 security.setAttribute(QStringLiteral("id"), obj.getName());
0844                 security.setAttribute(QStringLiteral("trading-currency"), unitP);
0845                 security.setAttribute(QStringLiteral("saf"), QStringLiteral("100000"));
0846                 security.setAttribute(QStringLiteral("symbol"), obj.getSymbol());
0847                 security.setAttribute(QStringLiteral("trading-market"), obj.getCountry());
0848                 security.setAttribute(QStringLiteral("type"), QStringLiteral("4"));
0849                 security.setAttribute(QStringLiteral("name"), obj.getName());
0850 
0851                 QString internetCode = obj.getInternetCode();
0852                 if (!internetCode.isEmpty()) {
0853                     QDomElement keyvaluepairs2 = doc.createElement(QStringLiteral("KEYVALUEPAIRS"));
0854                     security.appendChild(keyvaluepairs2);
0855 
0856                     QDomElement pair1 = doc.createElement(QStringLiteral("PAIR"));
0857                     keyvaluepairs2.appendChild(pair1);
0858                     pair1.setAttribute(QStringLiteral("key"), QStringLiteral("kmm-online-source"));
0859                     pair1.setAttribute(QStringLiteral("value"), QStringLiteral("Yahoo"));
0860 
0861                     QDomElement pair2 = doc.createElement(QStringLiteral("PAIR"));
0862                     keyvaluepairs2.appendChild(pair2);
0863                     pair2.setAttribute(QStringLiteral("key"), QStringLiteral("kmm-security-id"));
0864                     pair2.setAttribute(QStringLiteral("value"), internetCode);
0865                 }
0866             } else {
0867                 QDomElement currency = doc.createElement(QStringLiteral("CURRENCY"));
0868                 currencies.appendChild(currency);
0869 
0870                 QString unit = SKGUnitObject::getInternationalCode(obj.getName());
0871                 if (unit.isEmpty()) {
0872                     unit = obj.getName();
0873                 }
0874 
0875                 currency.setAttribute(QStringLiteral("saf"), QStringLiteral("100"));
0876                 currency.setAttribute(QStringLiteral("symbol"), obj.getSymbol());
0877                 currency.setAttribute(QStringLiteral("type"), QStringLiteral("3"));
0878                 currency.setAttribute(QStringLiteral("id"), unit);
0879                 currency.setAttribute(QStringLiteral("name"), obj.getName());
0880                 currency.setAttribute(QStringLiteral("ppu"), QStringLiteral("100"));
0881                 currency.setAttribute(QStringLiteral("scf"), QStringLiteral("100"));
0882 
0883                 importedCurrency.push_back(obj.getSymbol());
0884             }
0885             IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0886         }
0887 
0888         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0889     }
0890 
0891     // <CURRENCIES>
0892     QStringList units = SKGUnitObject::getListofKnownCurrencies(false);
0893     nb = units.count();
0894     int nbreal = 0;
0895     for (int i = 0; i < nb; ++i) {
0896         SKGServices::SKGUnitInfo info = SKGUnitObject::getUnitInfo(units.at(i));
0897         if (info.Name != info.Symbol && !importedCurrency.contains(info.Symbol)) {
0898             QDomElement currency = doc.createElement(QStringLiteral("CURRENCY"));
0899             currencies.appendChild(currency);
0900             currency.setAttribute(QStringLiteral("saf"), QStringLiteral("100"));
0901             currency.setAttribute(QStringLiteral("symbol"), info.Symbol);
0902             currency.setAttribute(QStringLiteral("type"), QStringLiteral("3"));
0903             currency.setAttribute(QStringLiteral("id"), SKGUnitObject::getInternationalCode(info.Name));
0904             currency.setAttribute(QStringLiteral("name"), info.Name);
0905             currency.setAttribute(QStringLiteral("ppu"), QStringLiteral("100"));
0906             currency.setAttribute(QStringLiteral("scf"), QStringLiteral("100"));
0907 
0908             ++nbreal;
0909         }
0910     }
0911     currencies.setAttribute(QStringLiteral("count"), SKGServices::intToString(nbreal));
0912 
0913     // <PRICES>
0914     QDomElement prices = doc.createElement(QStringLiteral("PRICES"));
0915     root.appendChild(prices);
0916     IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_unit"), QStringLiteral("t_type='S'"), objects))
0917     nb = objects.count();
0918     prices.setAttribute(QStringLiteral("count"), SKGServices::intToString(nb));
0919     IFOK(err) {
0920         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
0921         for (int i = 0; !err && i < nb; ++i) {
0922             SKGUnitObject obj(objects.at(i));
0923             QDomElement pricepair = doc.createElement(QStringLiteral("PRICEPAIR"));
0924             prices.appendChild(pricepair);
0925 
0926             QString unitP = SKGUnitObject::getInternationalCode(obj.getName());
0927             if (unitP.isEmpty()) {
0928                 unitP = stdUnit;
0929             }
0930 
0931             pricepair.setAttribute(QStringLiteral("from"), obj.getName());
0932             pricepair.setAttribute(QStringLiteral("to"), unitP);
0933 
0934             SKGObjectBase::SKGListSKGObjectBase unitValues;
0935             err = obj.getUnitValues(unitValues);
0936             int nb2 = unitValues.count();
0937             for (int j = 0; !err && j < nb2; ++j) {
0938                 QDomElement price = doc.createElement(QStringLiteral("PRICE"));
0939                 pricepair.appendChild(price);
0940 
0941                 SKGUnitValueObject unitval(unitValues.at(j));
0942                 price.setAttribute(QStringLiteral("price"), SKGImportPluginKmy::kmyValue(unitval.getQuantity()));
0943                 price.setAttribute(QStringLiteral("source"), QStringLiteral("Utilisateur"));
0944                 price.setAttribute(QStringLiteral("date"), SKGServices::dateToSqlString(unitval.getDate()));
0945             }
0946 
0947             IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0948         }
0949 
0950         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0951     }
0952 
0953     // <REPORTS>
0954     QDomElement reports = doc.createElement(QStringLiteral("REPORTS"));
0955     root.appendChild(reports);
0956     reports.setAttribute(QStringLiteral("count"), QStringLiteral("0"));
0957 
0958     return err;
0959 }
0960 
0961 SKGError SKGImportPluginKmy::exportBudgets(QDomDocument& doc, QDomElement& root)
0962 {
0963     SKGError err;
0964     QDomElement budgets = doc.createElement(QStringLiteral("BUDGETS"));
0965     root.appendChild(budgets);
0966 
0967     SKGObjectBase::SKGListSKGObjectBase objects;
0968     IFOKDO(err, m_importer->getDocument()->getObjects(QStringLiteral("v_budget"), QStringLiteral("1=1 ORDER BY i_year, i_month"), objects))
0969     int nb = objects.count();
0970     int nbBudgets = 0;
0971     int currentYear = 0;
0972     QDomElement budget;
0973 
0974     QMap<QString, QDomElement> mapCatAccount;
0975     IFOK(err) {
0976         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export budgets"), nb);
0977         for (int i = 0; !err && i < nb; ++i) {
0978             SKGBudgetObject obj(objects.at(i));
0979             SKGCategoryObject cat;
0980             obj.getCategory(cat);
0981             QString catId = getKmyUniqueIdentifier(cat);
0982             int year = obj.getYear();
0983             QString yearString = SKGServices::intToString(year);
0984             int month = obj.getMonth();
0985             QString monthString = SKGServices::intToString(month);
0986             if (monthString.isEmpty()) {
0987                 monthString = '0' % monthString;
0988             }
0989             if (currentYear != year) {
0990                 budget = doc.createElement(QStringLiteral("BUDGET"));
0991                 budgets.appendChild(budget);
0992                 budget.setAttribute(QStringLiteral("version"), QStringLiteral("2"));
0993                 budget.setAttribute(QStringLiteral("id"), yearString);
0994                 budget.setAttribute(QStringLiteral("start"), yearString % "-01-01");
0995                 budget.setAttribute(QStringLiteral("name"), yearString);
0996 
0997                 currentYear = year;
0998                 mapCatAccount.clear();
0999                 ++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 
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 transactions"), 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 
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 transactions"), 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 
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 
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 
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 
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 
1492 SKGError SKGImportPluginKmy::exportFile()
1493 {
1494     // Initialisation
1495     m_opTreated.clear();
1496 
1497     if (m_importer->getDocument() == 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 
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::MARKED ? 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::MARKED ? 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 
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 
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 
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 
1733 QString SKGImportPluginKmy::getMimeTypeFilter() const
1734 {
1735     return "*.kmy|" % i18nc("A file format", "KMyMoney document");
1736 }
1737 
1738 #include <skgimportpluginkmy.moc>