File indexing completed on 2024-06-16 04:47:22

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 OFX import / export.
0008  *
0009  * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgimportpluginofx.h"
0012 
0013 #include <qcryptographichash.h>
0014 #include <qfile.h>
0015 
0016 #include <klocalizedstring.h>
0017 #include <kpluginfactory.h>
0018 
0019 #include "skgbankincludes.h"
0020 #include "skgimportexportmanager.h"
0021 #include "skgservices.h"
0022 #include "skgtraces.h"
0023 
0024 SKGError SKGImportPluginOfx::m_ofxError;
0025 QStringList SKGImportPluginOfx::m_ofxInitialBalanceName;
0026 QList<double> SKGImportPluginOfx::m_ofxInitialBalanceAmount;
0027 QList<QDate> SKGImportPluginOfx::m_ofxInitialBalanceDate;
0028 QMap<QString, SKGAccountObject> SKGImportPluginOfx::m_accounts;
0029 /**
0030  * This plugin factory.
0031  */
0032 K_PLUGIN_CLASS_WITH_JSON(SKGImportPluginOfx, "metadata.json")
0033 
0034 SKGImportPluginOfx::SKGImportPluginOfx(QObject* iImporter, const QVariantList& iArg)
0035     : SKGImportPlugin(iImporter)
0036 {
0037     SKGTRACEINFUNC(10)
0038     Q_UNUSED(iArg)
0039     SKGImportPluginOfx::m_accounts.clear();
0040 }
0041 
0042 SKGImportPluginOfx::~SKGImportPluginOfx()
0043     = default;
0044 
0045 bool SKGImportPluginOfx::isImportPossible()
0046 {
0047     SKGTRACEINFUNC(10)
0048     return (m_importer->getDocument() == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("OFX") || m_importer->getFileNameExtension() == QStringLiteral("QFX"));
0049 }
0050 
0051 SKGError SKGImportPluginOfx::importFile()
0052 {
0053     if (m_importer->getDocument() == nullptr) {
0054         return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
0055     }
0056 
0057     SKGError err;
0058     SKGTRACEINFUNCRC(2, err)
0059 
0060     if (!QFile(m_importer->getLocalFileName()).exists()) {
0061         err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Open file '%1' failed", m_importer->getFileName().toDisplayString()));
0062     }
0063     IFOKDO(err, m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "OFX")))
0064     IFOK(err) {
0065         SKGImportPluginOfx::m_ofxError = SKGError();
0066         SKGImportPluginOfx::m_ofxInitialBalanceName.clear();
0067         SKGImportPluginOfx::m_ofxInitialBalanceAmount.clear();
0068         SKGImportPluginOfx::m_ofxInitialBalanceDate.clear();
0069 
0070         try {
0071             // Check file type
0072             // auto type = libofx_detect_file_type( m_importer->getLocalFileName().toUtf8().data());
0073 
0074             LibofxContextPtr ctx = libofx_get_new_context();
0075 
0076             ofx_set_account_cb(ctx, SKGImportPluginOfx::ofxAccountCallback, m_importer);
0077             ofx_set_statement_cb(ctx, SKGImportPluginOfx::ofxStatementCallback, m_importer);
0078             ofx_set_transaction_cb(ctx, SKGImportPluginOfx::ofxTransactionCallback, m_importer);
0079             // ofx_set_security_cb(ctx, ofxSecurityCallback, this);
0080             libofx_proc_file(ctx, m_importer->getLocalFileName().toUtf8().data(), AUTODETECT);
0081             IFOKDO(err, SKGImportPluginOfx::m_ofxError) {
0082                 // This is an option ==> no error management
0083                 SKGError err2;
0084                 int nb = SKGImportPluginOfx::m_ofxInitialBalanceName.count();
0085                 for (int i = 0; !err2 && i < nb; ++i) {
0086                     SKGAccountObject act;
0087                     err2 = m_importer->getDocument()->getObject(QStringLiteral("v_account"), "t_number='" % SKGServices::stringToSqlString(m_ofxInitialBalanceName.at(i)) % '\'', act);
0088 
0089                     // Date of balance
0090                     auto date = m_ofxInitialBalanceDate.at(i);
0091 
0092                     // Get unit
0093                     SKGUnitObject unit;
0094                     if (!err2) {
0095                         err2 = m_importer->getDefaultUnit(unit);
0096                     }
0097 
0098                     // Current amount
0099                     double currentAmount = act.getAmount(date);
0100 
0101                     // Update account
0102                     if (!err2) {
0103                         err2 = act.setInitialBalance(m_ofxInitialBalanceAmount.at(i) - currentAmount, unit);
0104                     }
0105                     if (!err2) {
0106                         err2 = act.save();
0107                     }
0108                     if (!err2) {
0109                         err2 = m_importer->getDocument()->sendMessage(i18nc("An information message", "The initial balance of '%1' has been set", act.getName()));
0110                     }
0111                 }
0112             }
0113             libofx_free_context(ctx);
0114         } catch (...) {  // NOLINT(whitespace/parens)
0115             err = SKGError(ERR_HANDLE, i18nc("Error message", "OFX import failed"));
0116         }
0117 
0118         SKGImportPluginOfx::m_ofxInitialBalanceName.clear();
0119         SKGImportPluginOfx::m_ofxInitialBalanceAmount.clear();
0120         SKGImportPluginOfx::m_ofxInitialBalanceDate.clear();
0121 
0122         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0123     }
0124     return err;
0125 }
0126 
0127 QString SKGImportPluginOfx::getAccountName(OfxAccountData* iAccountData)
0128 {
0129     SKGTRACEINFUNC(3)
0130     QString accountNumber;
0131     if (iAccountData != nullptr) {
0132         accountNumber = QString::fromUtf8(iAccountData->account_id);
0133         QString bankNumber = QString::fromUtf8(iAccountData->bank_id);
0134         // Correction BUG 234771 vvvvv
0135         accountNumber = accountNumber.trimmed();
0136         bankNumber = bankNumber.trimmed();
0137         if (accountNumber.isEmpty()) {
0138             accountNumber = QString::fromUtf8(iAccountData->account_number);
0139         }
0140         // Correction BUG 234771 ^^^^^
0141         if (accountNumber.startsWith(bankNumber % ' ')) {
0142             accountNumber = accountNumber.right(accountNumber.length() - bankNumber.length() - 1);
0143             QStringList splitNumbers = accountNumber.split(' ');
0144             if (splitNumbers.count() == 2) {
0145                 accountNumber = splitNumbers.at(1);
0146             }
0147         }
0148     }
0149     SKGTRACEL(3) << "accountNumber=" << accountNumber << SKGENDL;
0150     return accountNumber;
0151 }
0152 
0153 SKGError SKGImportPluginOfx::getAccount(OfxAccountData* iAccountData, SKGDocumentBank* iDoc, SKGAccountObject& oAccount)
0154 {
0155     SKGError err;
0156     SKGTRACEINFUNCRC(3, err)
0157     if ((iAccountData != nullptr) && (iDoc != nullptr)) {
0158         // Check if account is already existing
0159         QString name = getAccountName(iAccountData);
0160         if (m_accounts.contains(name)) {
0161             SKGTRACEL(3) << "Found in index" << SKGENDL;
0162             oAccount = m_accounts[name];
0163         } else {
0164             SKGTRACEL(3) << "NOT found in index" << SKGENDL;
0165             QString wc = "t_number='" % SKGServices::stringToSqlString(name) % "' OR EXISTS(SELECT 1 FROM parameters WHERE t_uuid_parent=v_account.id||'-account' AND t_name='alias' AND t_value= '" % SKGServices::stringToSqlString(name) % "')";
0166             err = iDoc->getObject(QStringLiteral("v_account"), wc, oAccount);
0167         }
0168     }
0169 
0170     return err;
0171 }
0172 
0173 int SKGImportPluginOfx::ofxStatementCallback(struct OfxStatementData data, void* pv)  // clazy:exclude=function-args-by-ref
0174 {
0175     if (SKGImportPluginOfx::m_ofxError) {
0176         return 0;
0177     }
0178     SKGTRACEINFUNCRC(5, SKGImportPluginOfx::m_ofxError)
0179 
0180     auto* impotExporter = static_cast<SKGImportExportManager*>(pv);
0181     if (impotExporter == nullptr) {
0182         return 0;
0183     }
0184     SKGDocumentBank* doc = impotExporter->getDocument();
0185     if (doc == nullptr) {
0186         return 0;
0187     }
0188 
0189     // // Get data
0190     OfxAccountData* accountData = data.account_ptr;
0191     if ((accountData != nullptr) && static_cast<bool>(data.ledger_balance_valid)) {
0192         // Get account
0193         SKGAccountObject act;
0194         SKGImportPluginOfx::m_ofxError = getAccount(accountData, doc, act);
0195         if (!SKGImportPluginOfx::m_ofxError) {
0196             impotExporter->addAccountToCheck(act, data.ledger_balance);
0197             if (act.getNbOperation() > 1) {
0198                 SKGImportPluginOfx::m_ofxError = doc->sendMessage(i18nc("An information message", "The initial balance of '%1' has not been set because some transactions are already existing", act.getName()));
0199             } else {
0200                 auto d = QDate::currentDate();
0201                 if (static_cast<bool>(data.ledger_balance_date_valid)) {
0202                     QDateTime date_time;
0203                     date_time.setSecsSinceEpoch(data.ledger_balance_date);
0204                     d = date_time.date();
0205                 }
0206                 m_ofxInitialBalanceName.push_back(getAccountName(accountData));
0207                 m_ofxInitialBalanceDate.push_back(d);
0208                 m_ofxInitialBalanceAmount.push_back(data.ledger_balance);
0209             }
0210         }
0211     }
0212 
0213     return SKGImportPluginOfx::m_ofxError.getReturnCode();
0214 }
0215 
0216 int SKGImportPluginOfx::ofxAccountCallback(struct OfxAccountData data, void* pv)
0217 {
0218     if (SKGImportPluginOfx::m_ofxError) {
0219         return 0;
0220     }
0221     SKGTRACEINFUNCRC(5, SKGImportPluginOfx::m_ofxError)
0222 
0223     auto* impotExporter = static_cast<SKGImportExportManager*>(pv);
0224     if (impotExporter == nullptr) {
0225         return 0;
0226     }
0227     SKGDocumentBank* doc = impotExporter->getDocument();
0228     if (doc == nullptr) {
0229         return 0;
0230     }
0231 
0232     SKGObjectBase tmp;
0233     QString agencyNumber = QString::fromUtf8(data.branch_id);
0234     QString accountNumber = QString::fromUtf8(data.account_id);
0235     QString bankNumber = QString::fromUtf8(data.bank_id);
0236     // Correction BUG 234771 vvvvv
0237     accountNumber = accountNumber.trimmed();
0238     bankNumber = bankNumber.trimmed();
0239     // Correction BUG 234771 ^^^^^
0240     if (accountNumber.isEmpty()) {
0241         accountNumber = QString::fromUtf8(data.account_number);
0242     }
0243     if (accountNumber.startsWith(bankNumber % ' ')) {
0244         accountNumber = accountNumber.right(accountNumber.length() - bankNumber.length() - 1);
0245         QStringList splitNumbers = accountNumber.split(' ');
0246         if (splitNumbers.count() == 2) {
0247             agencyNumber = splitNumbers.at(0);
0248             accountNumber = splitNumbers.at(1);
0249         }
0250     }
0251 
0252     // Check if account is already existing
0253     SKGAccountObject account;
0254     SKGImportPluginOfx::m_ofxError = getAccount(&data, doc, account);
0255     if (!SKGImportPluginOfx::m_ofxError) {
0256         // Already existing
0257         account = tmp;
0258         SKGImportPluginOfx::m_ofxError = impotExporter->setDefaultAccount(&account);
0259     } else {
0260         // Not existing
0261         QString bankId = (static_cast<bool>(data.bank_id_valid) ? QString::fromUtf8(data.bank_id) : QString::fromUtf8(data.broker_id));
0262         if (!bankId.isEmpty()) {
0263             bankId = i18nc("Adjective, an unknown item", "Unknown");
0264         }
0265 
0266         // Check if bank is already existing
0267         SKGBankObject bank;
0268         SKGImportPluginOfx::m_ofxError = doc->getObject(QStringLiteral("v_bank"), "t_bank_number='" % SKGServices::stringToSqlString(bankId) % '\'', tmp);
0269         if (!SKGImportPluginOfx::m_ofxError) {
0270             // Already existing
0271             bank = tmp;
0272         } else {
0273             // Create new bank
0274             bank = SKGBankObject(doc);
0275             SKGImportPluginOfx::m_ofxError = bank.setName(bankId);
0276             if (!SKGImportPluginOfx::m_ofxError) {
0277                 SKGImportPluginOfx::m_ofxError = bank.setNumber(QString::fromUtf8(data.bank_id));
0278             }
0279             if (!SKGImportPluginOfx::m_ofxError) {
0280                 SKGImportPluginOfx::m_ofxError = bank.save();
0281             }
0282         }
0283 
0284         // Create new account
0285         QString name = QString::fromUtf8(data.account_name);
0286         if (name.isEmpty()) {
0287             name = QString::fromUtf8(data.account_id);
0288         } else {
0289             name = name.remove(QStringLiteral("Bank account "));
0290         }
0291         if (name.isEmpty()) {
0292             name = QString::fromUtf8(data.account_id);
0293         }
0294 
0295         if (!SKGImportPluginOfx::m_ofxError) {
0296             SKGImportPluginOfx::m_ofxError = bank.addAccount(account);
0297         }
0298         if (!SKGImportPluginOfx::m_ofxError) {
0299             SKGImportPluginOfx::m_ofxError = account.setName(name);
0300         }
0301         if (!SKGImportPluginOfx::m_ofxError) {
0302             SKGImportPluginOfx::m_ofxError = account.setNumber(accountNumber);
0303         }
0304         if (!SKGImportPluginOfx::m_ofxError) {
0305             SKGImportPluginOfx::m_ofxError = account.setAgencyNumber(agencyNumber);
0306         }
0307         if (!SKGImportPluginOfx::m_ofxError) {
0308             SKGImportPluginOfx::m_ofxError = account.setComment(QString::fromUtf8(data.account_name));
0309         }
0310         SKGAccountObject::AccountType type = SKGAccountObject::CURRENT;
0311         if (static_cast<bool>(data.account_type_valid)) {
0312             switch (data.account_type) {
0313             case OfxAccountData::OFX_CHECKING:
0314             case OfxAccountData::OFX_SAVINGS:
0315             case OfxAccountData::OFX_CREDITLINE:
0316             case OfxAccountData::OFX_CMA:
0317                 type = SKGAccountObject::CURRENT;
0318                 break;
0319             case OfxAccountData::OFX_MONEYMRKT:
0320             case OfxAccountData::OFX_INVESTMENT:
0321                 type = SKGAccountObject::INVESTMENT;
0322                 break;
0323             case OfxAccountData::OFX_CREDITCARD:
0324                 type = SKGAccountObject::CREDITCARD;
0325                 break;
0326             default:
0327                 break;
0328             }
0329         }
0330 
0331         if (!SKGImportPluginOfx::m_ofxError) {
0332             SKGImportPluginOfx::m_ofxError = account.setType(type);
0333         }
0334         if (!SKGImportPluginOfx::m_ofxError) {
0335             SKGImportPluginOfx::m_ofxError = account.save();
0336             m_accounts[accountNumber] = account;
0337             SKGTRACEL(3) << "Add account '" << accountNumber << "' in index" << SKGENDL;
0338         }
0339 
0340         if (!SKGImportPluginOfx::m_ofxError) {
0341             SKGImportPluginOfx::m_ofxError = impotExporter->setDefaultAccount(&account);
0342         }
0343 
0344         SKGTRACEL(10) << "Account [" << name << "] created" << SKGENDL;
0345     }
0346 
0347     if (static_cast<bool>(data.currency_valid)) {
0348         // Check if unit is already existing
0349         SKGUnitObject unit(doc);
0350         SKGImportPluginOfx::m_ofxError = doc->getObject(QStringLiteral("v_unit"), "t_name='" % SKGServices::stringToSqlString(QString::fromUtf8(data.currency)) % "' OR t_name like '%(" % SKGServices::stringToSqlString(QString::fromUtf8(data.currency)) % ")%'", tmp);
0351         if (!SKGImportPluginOfx::m_ofxError) {
0352             // Already existing
0353             unit = tmp;
0354             SKGImportPluginOfx::m_ofxError = impotExporter->setDefaultUnit(&unit);
0355         } else {
0356             // Create new account
0357             SKGImportPluginOfx::m_ofxError = unit.setName(QString::fromUtf8(data.currency));
0358             if (!SKGImportPluginOfx::m_ofxError) {
0359                 SKGImportPluginOfx::m_ofxError = unit.setSymbol(QString::fromUtf8(data.currency));
0360             }
0361             if (!SKGImportPluginOfx::m_ofxError) {
0362                 SKGImportPluginOfx::m_ofxError = unit.save();
0363             }
0364 
0365             if (!SKGImportPluginOfx::m_ofxError) {
0366                 SKGImportPluginOfx::m_ofxError = impotExporter->setDefaultUnit(&unit);
0367             }
0368         }
0369     }
0370     return SKGImportPluginOfx::m_ofxError.getReturnCode();
0371 }
0372 
0373 int SKGImportPluginOfx::ofxTransactionCallback(struct OfxTransactionData data, void* pv)  // clazy:exclude=function-args-by-ref
0374 {
0375     if (SKGImportPluginOfx::m_ofxError) {
0376         return 0;
0377     }
0378     SKGTRACEINFUNCRC(5, SKGImportPluginOfx::m_ofxError)
0379 
0380     auto* impotExporter = static_cast<SKGImportExportManager*>(pv);
0381     if (impotExporter == nullptr) {
0382         return 0;
0383     }
0384     SKGDocumentBank* doc = impotExporter->getDocument();
0385     if (doc == nullptr) {
0386         return 0;
0387     }
0388 
0389     // Get account
0390     SKGAccountObject account;
0391     SKGImportPluginOfx::m_ofxError = getAccount(data.account_ptr, doc, account);
0392     if (!SKGImportPluginOfx::m_ofxError) {
0393         // Get transaction date
0394         QDateTime date_time;
0395         date_time.setSecsSinceEpoch(static_cast<bool>(data.date_initiated_valid) ? data.date_initiated : data.date_posted);
0396         QDate date = date_time.date();
0397 
0398         // Get unit
0399         SKGUnitObject unit;
0400         SKGImportPluginOfx::m_ofxError = impotExporter->getDefaultUnit(unit);
0401 
0402         // Create id
0403         QString ID;
0404         if (static_cast<bool>(data.fi_id_valid)) {
0405             if (QString::fromUtf8(data.fi_id).count('0') != QString::fromUtf8(data.fi_id).count()) {
0406                 ID = QStringLiteral("ID-") % QString::fromUtf8(data.fi_id);
0407             }
0408         } else if (static_cast<bool>(data.reference_number_valid)) {
0409             if (QString::fromUtf8(data.reference_number).count('0') != QString::fromUtf8(data.reference_number).count()) {
0410                 ID = QStringLiteral("REF-") % data.reference_number;
0411             }
0412         }
0413 
0414         if (ID.isEmpty()) {
0415             QByteArray hash = QCryptographicHash::hash(QString(SKGServices::dateToSqlString(date) % SKGServices::doubleToString(data.amount)).toUtf8(), QCryptographicHash::Md5);
0416             ID = QStringLiteral("ID-") % hash.toHex();
0417         }
0418 
0419         // Create operation
0420         SKGOperationObject ope;
0421         if (!SKGImportPluginOfx::m_ofxError) {
0422             SKGImportPluginOfx::m_ofxError = account.addOperation(ope, true);
0423         }
0424         if (!SKGImportPluginOfx::m_ofxError) {
0425             SKGImportPluginOfx::m_ofxError = ope.setDate(date);
0426         }
0427         if (!SKGImportPluginOfx::m_ofxError) {
0428             SKGImportPluginOfx::m_ofxError = ope.setUnit(unit);
0429         }
0430         if (!SKGImportPluginOfx::m_ofxError) {
0431             SKGImportPluginOfx::m_ofxError = ope.setAttribute(QStringLiteral("t_imported"), QStringLiteral("T"));
0432         }
0433         if (!SKGImportPluginOfx::m_ofxError) {
0434             SKGImportPluginOfx::m_ofxError = ope.setImportID(ID);
0435         }
0436         if (!SKGImportPluginOfx::m_ofxError) {
0437             QString payeeName;
0438             if (static_cast<bool>(data.payee_id_valid)) {
0439                 payeeName = QString::fromUtf8(data.payee_id);
0440             } else if (static_cast<bool>(data.name_valid)) {
0441                 payeeName = QString::fromUtf8(data.name);
0442             }
0443             if (!payeeName.isEmpty()) {
0444                 SKGPayeeObject payeeObj;
0445                 SKGImportPluginOfx::m_ofxError = SKGPayeeObject::createPayee(doc, payeeName, payeeObj);
0446                 if (!SKGImportPluginOfx::m_ofxError) {
0447                     SKGImportPluginOfx::m_ofxError = ope.setPayee(payeeObj);
0448                 }
0449             }
0450         }
0451         if (!SKGImportPluginOfx::m_ofxError && static_cast<bool>(data.memo_valid)) {
0452             SKGImportPluginOfx::m_ofxError = ope.setComment(QString::fromUtf8(data.memo));
0453         }
0454         if (!SKGImportPluginOfx::m_ofxError && static_cast<bool>(data.check_number_valid)) {
0455             SKGImportPluginOfx::m_ofxError = ope.setNumber(data.check_number);
0456         }
0457         if (!SKGImportPluginOfx::m_ofxError && static_cast<bool>(data.invtransactiontype_valid)) {
0458             SKGImportPluginOfx::m_ofxError = ope.setMode(i18nc("Noun, the title of an item", "Title"));
0459         }
0460         if (!SKGImportPluginOfx::m_ofxError && static_cast<bool>(data.transactiontype_valid)) {
0461             QString mode;
0462             if (data.transactiontype == OFX_CREDIT) {
0463                 mode = i18nc("Noun, type of OFX transaction", "Credit");
0464             } else if (data.transactiontype == OFX_DEBIT) {
0465                 mode = i18nc("Noun, type of OFX transaction", "Debit");
0466             } else if (data.transactiontype == OFX_INT) {
0467                 mode = i18nc("Noun, type of OFX transaction", "Interest");
0468             } else if (data.transactiontype == OFX_DIV) {
0469                 mode = i18nc("Noun, type of OFX transaction", "Dividend");
0470             } else if (data.transactiontype == OFX_FEE) {
0471                 mode = i18nc("Noun, type of OFX transaction", "FI fee");
0472             } else if (data.transactiontype == OFX_SRVCHG) {
0473                 mode = i18nc("Noun, type of OFX transaction", "Service charge");
0474             } else if (data.transactiontype == OFX_DEP) {
0475                 mode = i18nc("Noun, type of OFX transaction", "Deposit");
0476             } else if (data.transactiontype == OFX_ATM) {
0477                 mode = i18nc("Noun, type of OFX transaction", "ATM");
0478             } else if (data.transactiontype == OFX_POS) {
0479                 mode = i18nc("Noun, type of OFX transaction", "Point of sale");
0480             } else if (data.transactiontype == OFX_XFER) {
0481                 mode = i18nc("An transaction mode", "Transfer");
0482             } else if (data.transactiontype == OFX_CHECK) {
0483                 mode = i18nc("An transaction mode", "Check");
0484             } else if (data.transactiontype == OFX_PAYMENT) {
0485                 mode = i18nc("Noun, type of OFX transaction", "Electronic payment");
0486             } else if (data.transactiontype == OFX_CASH) {
0487                 mode = i18nc("An transaction mode", "Withdrawal");
0488             } else if (data.transactiontype == OFX_DIRECTDEP) {
0489                 mode = i18nc("Noun, type of OFX transaction", "Deposit");
0490             } else if (data.transactiontype == OFX_REPEATPMT) {
0491                 mode = i18nc("Noun, type of OFX transaction", "Repeating payment");
0492             } else if (data.transactiontype == OFX_DIRECTDEBIT) {
0493                 mode = i18nc("An transaction mode", "Direct debit");
0494             }
0495 
0496             SKGImportPluginOfx::m_ofxError = ope.setMode(mode);
0497         }
0498         if (!SKGImportPluginOfx::m_ofxError) {
0499             SKGImportPluginOfx::m_ofxError = ope.save();
0500         }
0501 
0502         // Create sub operation
0503         SKGSubOperationObject subop;
0504         if (!SKGImportPluginOfx::m_ofxError) {
0505             SKGImportPluginOfx::m_ofxError = ope.addSubOperation(subop);
0506         }
0507         if (!SKGImportPluginOfx::m_ofxError && static_cast<bool>(data.amount_valid)) {
0508             bool mustFlipSign = (data.transactiontype == OFX_DEBIT || data.transactiontype == OFX_FEE || data.transactiontype == OFX_SRVCHG ||
0509                                  data.transactiontype == OFX_PAYMENT || data.transactiontype == OFX_CASH || data.transactiontype == OFX_DIRECTDEBIT ||
0510                                  data.transactiontype == OFX_REPEATPMT) && data.amount > 0;  // OFX spec version 2.1.1, section 3.2.9.2
0511             double sign = mustFlipSign ? -1.0 : 1.0;
0512             double commission = static_cast<bool>(data.commission_valid) ? data.commission : 0;
0513             SKGImportPluginOfx::m_ofxError = subop.setQuantity(sign * (data.amount + commission));
0514         }
0515         if (!SKGImportPluginOfx::m_ofxError && static_cast<bool>(data.memo_valid)) {
0516             SKGImportPluginOfx::m_ofxError = subop.setComment(QString::fromUtf8(data.memo));
0517         }
0518         if (!SKGImportPluginOfx::m_ofxError) {
0519             SKGImportPluginOfx::m_ofxError = subop.save();
0520         }
0521 
0522         // Commission
0523         if (!SKGImportPluginOfx::m_ofxError && static_cast<bool>(data.commission_valid) && static_cast<bool>(data.amount_valid) && data.commission > 0) {
0524             // Create splitter operation
0525             SKGSubOperationObject subop2;
0526             if (!SKGImportPluginOfx::m_ofxError) {
0527                 SKGImportPluginOfx::m_ofxError = ope.addSubOperation(subop2);
0528             }
0529             if (!SKGImportPluginOfx::m_ofxError) {
0530                 SKGImportPluginOfx::m_ofxError = subop2.setComment(i18nc("Noun, a quantity of money taken by a financial institution to perform an operation", "Commission"));
0531             }
0532             if (!SKGImportPluginOfx::m_ofxError) {
0533                 SKGImportPluginOfx::m_ofxError = subop2.setQuantity(-data.commission);
0534             }
0535             if (!SKGImportPluginOfx::m_ofxError) {
0536                 SKGImportPluginOfx::m_ofxError = subop2.save();
0537             }
0538         }
0539     }
0540     return SKGImportPluginOfx::m_ofxError.getReturnCode();
0541 }
0542 
0543 QString SKGImportPluginOfx::getMimeTypeFilter() const
0544 {
0545     return "*.ofx *.qfx|" % i18nc("A file format", "OFX file");
0546 }
0547 
0548 #include <skgimportpluginofx.moc>