File indexing completed on 2024-06-23 05:03:14

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 ledger import / export.
0008  *
0009  * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgimportpluginledger.h"
0012 
0013 #include <klocalizedstring.h>
0014 #include <kpluginfactory.h>
0015 
0016 #include <qsavefile.h>
0017 #include <qfile.h>
0018 #include <qprocess.h>
0019 #include <qdir.h>
0020 #include <quuid.h>
0021 
0022 #include "skgbankincludes.h"
0023 #include "skgdocumentbank.h"
0024 #include "skgservices.h"
0025 #include "skgtraces.h"
0026 
0027 /**
0028  * This plugin factory.
0029  */
0030 K_PLUGIN_CLASS_WITH_JSON(SKGImportPluginLedger, "metadata.json")
0031 
0032 SKGImportPluginLedger::SKGImportPluginLedger(QObject* iImporter, const QVariantList& iArg)
0033     : SKGImportPlugin(iImporter)
0034 {
0035     SKGTRACEINFUNC(10)
0036     Q_UNUSED(iArg)
0037 
0038     m_importParameters[QStringLiteral("ledger_account_identification")] = QStringLiteral("COMPTE,COMPTES,CAPITAUX,ASSETS,LIABILITIES,SAVING");
0039 }
0040 
0041 SKGImportPluginLedger::~SKGImportPluginLedger()
0042     = default;
0043 
0044 bool SKGImportPluginLedger::isExportPossible()
0045 {
0046     SKGTRACEINFUNC(10)
0047     return (m_importer->getDocument() == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("LEDGER"));
0048 }
0049 
0050 SKGError SKGImportPluginLedger::exportFile()
0051 {
0052     SKGError err;
0053     QSaveFile file(m_importer->getLocalFileName(false));
0054     if (!file.open(QIODevice::WriteOnly)) {
0055         err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Save file '%1' failed", m_importer->getFileName().toDisplayString()));
0056     } else {
0057         auto listUUIDs = SKGServices::splitCSVLine(m_exportParameters.value(QStringLiteral("uuid_of_selected_accounts_or_operations")));
0058 
0059         QString wc;
0060         for (const auto& uuid : qAsConst(listUUIDs)) {
0061             auto items = SKGServices::splitCSVLine(uuid, '-');
0062             if (items.at(1) == QStringLiteral("operation")) {
0063                 if (!wc.isEmpty()) {
0064                     wc += QLatin1String(" AND ");
0065                 }
0066                 wc += " i_OPID=" + items.at(0);
0067             } else if (items.at(1) == QStringLiteral("account")) {
0068                 if (!wc.isEmpty()) {
0069                     wc += QLatin1String(" AND ");
0070                 }
0071                 wc += " rd_account_id=" + items.at(0);
0072             }
0073         }
0074         if (wc.isEmpty()) {
0075             wc = QStringLiteral("1=1");
0076         }  else {
0077             IFOKDO(err, m_importer->getDocument()->sendMessage(i18nc("An information message",  "Only selected accounts and transactions have been exported")))
0078         }
0079 
0080         QLocale en(QLocale::C);
0081         QTextStream stream(&file);
0082         if (!m_importer->getCodec().isEmpty()) {
0083             stream.setCodec(m_importer->getCodec().toLatin1().constData());
0084         }
0085         stream << "; -*- ledger file generated by Skrooge -*-" << SKGENDL;
0086         err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export %1 file", "ledger"), 2);
0087         IFOK(err) {
0088             auto punit = m_importer->getDocument()->getPrimaryUnit();
0089             SKGObjectBase::SKGListSKGObjectBase units;
0090             err = m_importer->getDocument()->getObjects(QStringLiteral("v_unit"), QStringLiteral("t_type NOT IN ('C', '1', '2')"), units);
0091             int nb = units.count();
0092             IFOK(err) {
0093                 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
0094                 for (int i = 0; !err && i < nb; ++i) {
0095                     SKGUnitObject unit(units.at(i));
0096                     QString qs = en.toCurrencyString(SKGServices::stringToDouble(unit.getAttribute(QStringLiteral("f_CURRENTAMOUNT"))), punit.Symbol, punit.NbDecimal);
0097                     stream << "P " << SKGServices::dateToSqlString(QDate::currentDate()).replace('-', '/')
0098                            << " \"" << unit.getSymbol() << '"'
0099                            << " " << qs
0100                            << SKGENDL;
0101                     stream << SKGENDL;
0102 
0103                     IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0104                 }
0105 
0106                 SKGENDTRANSACTION(m_importer->getDocument(),  err)
0107             }
0108         }
0109 
0110         IFOKDO(err, m_importer->getDocument()->stepForward(1))
0111 
0112         IFOK(err) {
0113             SKGObjectBase::SKGListSKGObjectBase transactions;
0114             err = m_importer->getDocument()->getObjects(QStringLiteral("v_operation"), wc % QStringLiteral(" AND t_template='N' ORDER BY d_date"), transactions);
0115             int nb = transactions.count();
0116             IFOK(err) {
0117                 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export transactions"), nb);
0118                 for (int i = 0; !err && i < nb; ++i) {
0119                     SKGOperationObject op(transactions.at(i));
0120                     auto status = op.getStatus();
0121                     auto number = op.getNumber();
0122 
0123                     SKGPayeeObject payee;
0124                     op.getPayee(payee);
0125 
0126                     SKGUnitObject unit;
0127                     op.getUnit(unit);
0128                     bool isCurrency = unit.getType() == SKGUnitObject::CURRENCY || unit.getType() == SKGUnitObject::PRIMARY || unit.getType() == SKGUnitObject::SECONDARY;
0129 
0130                     auto payeeString = payee.getName();
0131                     if (payeeString.isEmpty()) {
0132                         payeeString = op.getComment();
0133                     }
0134 
0135                     auto nbDec = SKGServices::stringToInt(op.getAttribute(QStringLiteral("i_NBDEC")));
0136                     if (nbDec == 0) {
0137                         nbDec = 2;
0138                     }
0139                     QString symbol = unit.getSymbol();
0140                     if (symbol.contains(QStringLiteral(" "))) {
0141                         symbol = '"' + symbol + '"';
0142                     }
0143                     QString qs = en.toCurrencyString(SKGServices::stringToDouble(op.getAttribute(QStringLiteral("f_QUANTITY"))), QStringLiteral(" "), nbDec);
0144                     if (isCurrency) {
0145                         qs = symbol + qs;
0146                     } else {
0147                         qs = qs + ' ' + symbol;
0148                     }
0149 
0150                     stream << SKGServices::dateToSqlString(op.getDate()).replace('-', '/')
0151                            << (status == SKGOperationObject::CHECKED ? " *" : status == SKGOperationObject::MARKED ? " !" : "")
0152                            << (!number.isEmpty() ? QStringLiteral(" (") % number % ")" : QString())
0153                            << QStringLiteral(" ") << payeeString
0154                            << SKGENDL;
0155                     stream << "  ; Skrooge ID: " << op.getID() << SKGENDL;
0156                     stream << "  ; Import ID: " << op.getImportID() << SKGENDL;
0157                     auto properties = op.getProperties();
0158                     for (const auto& p : qAsConst(properties)) {
0159                         stream << "  ; " << p << ": " << op.getProperty(p) << SKGENDL;
0160                     }
0161                     stream << "  " << i18nc("The default category for the accounts for ledger export", "Account") << ':' << op.getAttribute(QStringLiteral("t_ACCOUNT"))
0162                            << "  " << qs
0163                            << SKGENDL;
0164 
0165                     SKGObjectBase::SKGListSKGObjectBase subtransactions;
0166                     IFOKDO(err, op.getSubOperations(subtransactions))
0167                     int nbsuboperations = subtransactions.count();
0168                     for (int j = 0; !err && j < nbsuboperations; ++j) {
0169                         SKGSubOperationObject sop(subtransactions.at(j));
0170                         SKGCategoryObject cat;
0171                         sop.getCategory(cat);
0172                         auto catString = cat.getFullName().replace(OBJECTSEPARATOR, QLatin1String(":"));
0173                         if (catString.isEmpty()) {
0174                             catString = i18nc("Category not defined", "Not defined");
0175                         }
0176                         QString qs = en.toCurrencyString(-sop.getQuantity(), QStringLiteral(" "), nbDec);
0177                         if (isCurrency) {
0178                             qs = unit.getSymbol() + qs;
0179                         } else {
0180                             qs = qs + ' ' + unit.getSymbol();
0181                         }
0182 
0183                         stream << "  " << i18nc("The default category for the categories for ledger export", "Category") << ':' <<  catString
0184                                << "  " << qs;
0185                         if (sop.getDate() != op.getDate()) {
0186                             stream << "  ; [=" << SKGServices::dateToSqlString(sop.getDate()).replace('-', '/') << "]";
0187                         }
0188 
0189                         auto comment = sop.getComment();
0190                         if (!comment.isEmpty()) {
0191                             stream << "  ;comment=" << comment;
0192                         }
0193                         stream << "  ; Skrooge ID: " << sop.getID();
0194                         stream << SKGENDL;
0195                     }
0196                     stream << SKGENDL;
0197 
0198                     IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0199                 }
0200 
0201                 SKGENDTRANSACTION(m_importer->getDocument(),  err)
0202             }
0203         }
0204 
0205         IFOKDO(err, m_importer->getDocument()->stepForward(2))
0206 
0207         SKGENDTRANSACTION(m_importer->getDocument(),  err)
0208 
0209         // Close file
0210         file.commit();
0211     }
0212     return err;
0213 }
0214 
0215 bool SKGImportPluginLedger::isImportPossible()
0216 {
0217     SKGTRACEINFUNC(10)
0218     return (m_importer->getDocument() == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("LEDGER"));
0219 }
0220 
0221 bool SKGImportPluginLedger::isAccount(const QString& type)
0222 {
0223     return m_importParameters.value(QStringLiteral("ledger_account_identification")).split(',').indexOf(type) != -1;
0224 }
0225 
0226 SKGError SKGImportPluginLedger::importFile()
0227 {
0228     if (m_importer->getDocument() == nullptr) {
0229         return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
0230     }
0231     SKGError err;
0232     SKGTRACEINFUNCRC(2, err)
0233 
0234     // Initialisation
0235     // Generate xml
0236     QString uniqueId = QUuid::createUuid().toString();
0237     QString temporaryPath = QDir::tempPath() % "/" % uniqueId % ".xml";
0238     QString cmd = "ledger -f \"" % m_importer->getLocalFileName() % "\" xml --output " % temporaryPath;
0239     SKGTRACEL(10) << "Execution of :" << cmd << SKGENDL;
0240     QProcess p;
0241     p.start(QStringLiteral("/bin/bash"), QStringList() << QStringLiteral("-c") << cmd);
0242     if (p.waitForFinished(1000 * 60 * 5) && p.exitCode() == 0) {
0243         // Open file
0244         QFile file(temporaryPath);
0245         if (!file.open(QIODevice::ReadOnly)) {
0246             err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Open file '%1' failed", m_importer->getFileName().toDisplayString()));
0247         } else {
0248             QDomDocument doc;
0249 
0250             // Set the file
0251             QString errorMsg;
0252             int errorLine = 0;
0253             int errorCol = 0;
0254             bool contentOK = doc.setContent(file.readAll(), &errorMsg, &errorLine, &errorCol);
0255             file.close();
0256 
0257             // Get root
0258             QDomElement docElem = doc.documentElement();
0259             if (!contentOK) {
0260                 err.setReturnCode(ERR_ABORT).setMessage(i18nc("Error message",  "%1-%2: '%3'", errorLine, errorCol, errorMsg));
0261                 err.addError(ERR_INVALIDARG, i18nc("Error message",  "Invalid XML content in file '%1'", m_importer->getFileName().toDisplayString()));
0262             } else {
0263                 err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "LEDGER"), 2);
0264 
0265                 QMap<QString, SKGUnitObject> mapIdUnit;
0266                 QMap<QString, SKGAccountObject> mapIdAccount;
0267                 QMap<QString, SKGCategoryObject> mapIdCategory;
0268                 QMap<QString, SKGPayeeObject> mapIdPayee;
0269 
0270                 // Step 1-Create units
0271                 IFOK(err) {
0272                     auto commodityL = docElem.elementsByTagName(QStringLiteral("commodity"));
0273                     int nb = commodityL.count();
0274                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
0275                     for (int i = 0; !err && i < nb; ++i) {
0276                         // Get unit object
0277                         auto commodity = commodityL.at(i).toElement();
0278                         auto symbol = commodity.firstChildElement(QStringLiteral("symbol")).toElement().text();
0279 
0280                         // Creation of the units
0281                         SKGUnitObject unitObj(m_importer->getDocument());
0282                         IFOKDO(err, unitObj.setName(symbol))
0283                         IFOKDO(err, unitObj.setSymbol(symbol))
0284                         IFOKDO(err, unitObj.setNumberDecimal(2))
0285                         IFOKDO(err, unitObj.save())
0286 
0287                         // Creation of the unit values
0288                         auto annotation = commodity.firstChildElement(QStringLiteral("annotation")).toElement();
0289                         auto price = annotation.firstChildElement(QStringLiteral("price")).toElement();
0290                         auto commodity2 = price.firstChildElement(QStringLiteral("commodity")).toElement();
0291                         auto quantity = price.firstChildElement(QStringLiteral("quantity")).toElement().text().trimmed();
0292                         auto symbol2 = commodity2.firstChildElement(QStringLiteral("symbol")).toElement();
0293                         auto date = annotation.firstChildElement(QStringLiteral("date")).toElement().text().trimmed();
0294                         if (!date.isNull() && !symbol2.isNull() && !quantity.isNull()) {
0295                             SKGUnitValueObject unitValueObj;
0296                             IFOKDO(err, unitObj.addUnitValue(unitValueObj))
0297                             IFOKDO(err, unitValueObj.setDate(QDate::fromString(date, QStringLiteral("yyyy/MM/dd"))))
0298                             IFOKDO(err, unitValueObj.setQuantity(1.0 / SKGServices::stringToDouble(quantity)))
0299                             IFOKDO(err, unitValueObj.save())
0300                         }
0301 
0302                         mapIdUnit[symbol] = unitObj;
0303 
0304                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0305                     }
0306 
0307                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
0308                 }
0309                 IFOKDO(err, m_importer->getDocument()->stepForward(1))
0310 
0311                 // Step 2-Create transaction
0312                 IFOK(err) {
0313                     auto transactionL = docElem.elementsByTagName(QStringLiteral("transaction"));
0314                     int nb = transactionL.count();
0315                     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import transactions"), nb);
0316                     for (int i = 0; !err && i < nb; ++i) {
0317                         // Get account object
0318                         auto transaction = transactionL.at(i).toElement();
0319 
0320                         auto date = transaction.firstChildElement(QStringLiteral("date")).toElement().text().trimmed();
0321                         auto payee = transaction.firstChildElement(QStringLiteral("payee")).toElement().text().trimmed();
0322                         auto note = transaction.firstChildElement(QStringLiteral("note")).toElement().text().trimmed();
0323                         auto status = getAttribute(transaction, QStringLiteral("state"));
0324 
0325                         // Create transaction and suboperation
0326                         SKGOperationObject opObj;
0327                         SKGSubOperationObject subObj;
0328                         auto postingL = transaction.elementsByTagName(QStringLiteral("posting"));
0329 
0330                         auto symbol = postingL.at(0).toElement().elementsByTagName(QStringLiteral("symbol")).at(0).toElement().text().trimmed();
0331                         int nb2 = postingL.count();
0332 
0333                         //Put account in the first place
0334                         QList<QDomElement> list_porting;
0335                         for (int i2 = 0; !err && i2 < nb2; ++i2) {
0336                             auto posting = postingL.at(i2).toElement();
0337                             auto account = posting.firstChildElement(QStringLiteral("account")).toElement();
0338                             auto type = account.firstChildElement(QStringLiteral("name")).toElement().text().split(QStringLiteral(":"))[0].toUpper().trimmed();
0339 
0340                             if (isAccount(type)) {
0341                                 list_porting.insert(0, posting);
0342                             } else {
0343                                 list_porting.append(posting);
0344                             }
0345                         }
0346                         SKGOperationObject opPreviousObj;
0347                         for (int i2 = 0; !err && i2 < nb2; ++i2) {
0348                             auto posting = list_porting.at(i2);
0349                             auto account = posting.firstChildElement(QStringLiteral("account")).toElement();
0350                             auto name = account.firstChildElement(QStringLiteral("name")).toElement().text().trimmed();
0351                             auto snote = posting.firstChildElement(QStringLiteral("note")).toElement().text().trimmed();
0352 
0353                             auto postamount = posting.firstChildElement(QStringLiteral("post-amount")).toElement();
0354 
0355                             auto amount = postamount.firstChildElement(QStringLiteral("amount")).toElement();
0356                             auto quantity = amount.firstChildElement(QStringLiteral("quantity")).toElement().text().trimmed();
0357 
0358                             auto names = name.split(QStringLiteral(":"));
0359                             QString type;
0360                             if (names.length() > 1) {
0361                                 type = names[0].toUpper();
0362                                 name = name.right(name.length() - type.length() - 1);
0363                             }
0364                             SKGTRACEL(2) << "Sub transaction : " << name << ": " << date << ": " << payee << " | " << quantity << SKGENDL;
0365 
0366                             auto isaccount = isAccount(type);
0367                             if (i2 > 0) {
0368                                 if (isaccount) {
0369                                     // Save the subtransaction
0370                                     IFOKDO(err, subObj.save())
0371                                 } else {
0372                                     // Forget the subtransaction
0373                                     IFOKDO(err, opObj.load())
0374                                 }
0375                             }
0376                             if (isaccount || !opObj.exist()) {
0377                                 auto account_id = getAttribute(account, QStringLiteral("ref"));
0378 
0379                                 SKGAccountObject accountObj;
0380                                 if (!mapIdAccount.contains(account_id)) {
0381                                     auto err2 = m_importer->getDocument()->getObject(QStringLiteral("v_account"), "t_name='" % SKGServices::stringToSqlString(name) % '\'', accountObj);
0382                                     if (!!err2) {
0383                                         SKGBankObject bankDefault(m_importer->getDocument());
0384                                         IFOKDO(err, bankDefault.setName(QStringLiteral("LEDGER")))
0385                                         IFOKDO(err, bankDefault.save())
0386                                         IFOK(err) {
0387                                             IFOKDO(err, bankDefault.addAccount(accountObj))
0388                                             IFOKDO(err, accountObj.setName(name))
0389                                             IFOKDO(err, accountObj.save())
0390                                             mapIdAccount[account_id] = accountObj;
0391                                         }
0392                                     }
0393                                 } else {
0394                                     accountObj = mapIdAccount[account_id];
0395                                 }
0396 
0397                                 // Creation of the transaction
0398                                 IFOKDO(err, accountObj.addOperation(opObj, true))
0399                                 IFOKDO(err, opObj.setDate(QDate::fromString(date, QStringLiteral("yyyy/MM/dd"))))
0400 
0401                                 IFOKDO(err, opObj.setUnit(mapIdUnit[symbol]))
0402                                 if (!payee.isEmpty()) {
0403                                     SKGPayeeObject payeeObject;
0404                                     if (!mapIdPayee.contains(payee)) {
0405                                         IFOKDO(err, SKGPayeeObject::createPayee(m_importer->getDocument(), payee, payeeObject))
0406                                         mapIdPayee[payee] = payeeObject;
0407                                     } else {
0408                                         payeeObject = mapIdPayee[payee];
0409                                     }
0410 
0411                                     IFOKDO(err, opObj.setPayee(payeeObject))
0412                                 }
0413                                 IFOKDO(err, opObj.setComment(note))
0414                                 IFOKDO(err, opObj.setImported(true))
0415                                 IFOKDO(err, opObj.setImportID(QStringLiteral("LEDGER-")))
0416                                 IFOKDO(err, opObj.setStatus(status == QStringLiteral("cleared") ? SKGOperationObject::CHECKED :
0417                                                             status == QStringLiteral("pending") ? SKGOperationObject::MARKED : SKGOperationObject::NONE))
0418                                 IFOKDO(err, opObj.save())
0419 
0420                                 if (opPreviousObj.getID()) {
0421                                     IFOKDO(err, opPreviousObj.setGroupOperation(opObj));
0422                                     IFOKDO(err, opPreviousObj.save())
0423                                 } else {
0424                                     opPreviousObj = opObj;
0425                                 }
0426                             }
0427 
0428                             // Creation of the subtransaction
0429                             IFOKDO(err, opObj.addSubOperation(subObj))
0430                             if (!isaccount) {
0431                                 SKGCategoryObject catObj;
0432                                 if (!mapIdCategory.contains(name)) {
0433                                     IFOKDO(err, SKGCategoryObject::createPathCategory(m_importer->getDocument(), name.replace(QStringLiteral(":"), QStringLiteral(" > ")), catObj))
0434                                     mapIdCategory[name] = catObj;
0435                                 } else {
0436                                     catObj = mapIdCategory[name];
0437                                 }
0438                                 IFOKDO(err, subObj.setCategory(catObj))
0439                             }
0440                             if (snote.startsWith(QStringLiteral("[=")) && snote.endsWith(QStringLiteral("]"))) {
0441                                 IFOKDO(err, subObj.setDate(QDate::fromString(snote.mid(2, snote.length() - 3), QStringLiteral("yyyy/MM/dd"))))
0442                             } else {
0443                                 IFOKDO(err, subObj.setComment(snote))
0444                             }
0445                             IFOKDO(err, subObj.setQuantity((isaccount ? 1 : -1)*SKGServices::stringToDouble(quantity)))
0446                             if (!isaccount || i2 == nb2 - 1) {
0447                                 IFOKDO(err, subObj.save())
0448                             }
0449                         }
0450 
0451                         if (!err && i % 500 == 0) {
0452                             err = m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE"));
0453                         }
0454                         IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0455                     }
0456 
0457                     SKGENDTRANSACTION(m_importer->getDocument(),  err)
0458                 }
0459                 IFOKDO(err, m_importer->getDocument()->stepForward(2))
0460                 SKGENDTRANSACTION(m_importer->getDocument(),  err)
0461 
0462                 IFOKDO(err, m_importer->getDocument()->executeSqliteOrder(QStringLiteral("ANALYZE")))
0463             }
0464         }
0465     } else {
0466         err.setReturnCode(ERR_FAIL).setMessage(i18nc("Error message",  "The execution of '%1' failed", cmd)).addError(ERR_FAIL, i18nc("Error message",  "The ledger conversion in xml of '%1' failed", m_importer->getFileName().toDisplayString()));
0467     }
0468     return err;
0469 }
0470 
0471 QString SKGImportPluginLedger::getMimeTypeFilter() const
0472 {
0473     return "*.ledger|" % i18nc("A file format", "Ledger file");
0474 }
0475 
0476 QString SKGImportPluginLedger::getAttribute(const QDomElement& iElement, const QString& iAttribute)
0477 {
0478     QString val = iElement.attribute(iAttribute);
0479     if (val == QStringLiteral("(null)")) {
0480         val = QString();
0481     }
0482     return val;
0483 }
0484 #include <skgimportpluginledger.moc>