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

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 AFB120 import / export.
0008  *
0009  * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgimportpluginafb120.h"
0012 
0013 #include <kpluginfactory.h>
0014 
0015 #include <qcryptographichash.h>
0016 #include <qfile.h>
0017 #include <qmath.h>
0018 
0019 #include "skgbankincludes.h"
0020 #include "skgimportexportmanager.h"
0021 #include "skgservices.h"
0022 #include "skgtraces.h"
0023 
0024 /**
0025  * This plugin factory.
0026  */
0027 K_PLUGIN_CLASS_WITH_JSON(SKGImportPluginAFB120, "metadata.json")
0028 
0029 SKGImportPluginAFB120::SKGImportPluginAFB120(QObject* iImporter, const QVariantList& iArg)
0030     : SKGImportPlugin(iImporter)
0031 {
0032     SKGTRACEINFUNC(10)
0033     Q_UNUSED(iArg)
0034 }
0035 
0036 SKGImportPluginAFB120::~SKGImportPluginAFB120()
0037     = default;
0038 
0039 bool SKGImportPluginAFB120::isImportPossible()
0040 {
0041     SKGTRACEINFUNC(10)
0042     return (m_importer->getDocument() == nullptr ? true : m_importer->getFileNameExtension() == QStringLiteral("AFB120") || m_importer->getFileNameExtension() == QStringLiteral("CFO"));
0043 }
0044 
0045 double SKGImportPluginAFB120::toAmount(const QString& iAmount, int iNbDecimal)
0046 {
0047     QString amount = iAmount;
0048     QChar lastChar = amount.right(1).at(0);
0049     int codeAscii = lastChar.toLatin1();
0050     int sign = (codeAscii > 79 && codeAscii != 123 ? -1 : 1);
0051     if (codeAscii == 123 || codeAscii == 125) {
0052         amount[amount.count() - 1] = '0';
0053     } else {
0054         bool ok = false;
0055         amount[amount.count() - 1] = QChar(codeAscii + QChar('1').toLatin1() - QString(sign == -1 ? QStringLiteral("0x4A") : QStringLiteral("0x41")).toUInt(&ok, 16));
0056     }
0057     return static_cast<double>(sign) * SKGServices::stringToDouble(amount) / qPow(10, iNbDecimal);
0058 }
0059 
0060 SKGError SKGImportPluginAFB120::importFile()
0061 {
0062     if (m_importer->getDocument() == nullptr) {
0063         return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
0064     }
0065     SKGError err;
0066     SKGTRACEINFUNCRC(2, err)
0067 
0068     // Begin transaction
0069     err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "AFB120"), 2);
0070     IFOK(err) {
0071         // Open file
0072         IFOK(err) {
0073             QFile file(m_importer->getLocalFileName());
0074             if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
0075                 err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Open file '%1' failed", m_importer->getFileName().toDisplayString()));
0076             } else {
0077                 // Read lines
0078                 QStringList lines;
0079                 {
0080                     QTextStream stream(&file);
0081                     if (!m_importer->getCodec().isEmpty()) {
0082                         stream.setCodec(m_importer->getCodec().toLatin1().constData());
0083                     }
0084                     while (!stream.atEnd()) {
0085                         // Read line
0086                         QString line = stream.readLine().trimmed();
0087                         if (!line.isEmpty()) {
0088                             lines.push_back(line);
0089                         }
0090                     }
0091                 }
0092                 // close file
0093                 file.close();
0094 
0095                 // Step 1 done
0096                 IFOKDO(err, m_importer->getDocument()->stepForward(1))
0097 
0098                 // Read lines
0099                 SKGAccountObject account;
0100                 SKGUnitObject unit;
0101                 QString bankName = QStringLiteral("AFB120");
0102                 QString inititalAmount;
0103 
0104                 int nb = lines.count();
0105                 IFOKDO(err, m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import transactions"), nb))
0106                 for (int i = 0; i < nb && !err; ++i) {
0107                     // Read line
0108                     const QString& line = lines.at(i);
0109                     if (!line.isEmpty()) {
0110                         if (line.startsWith(QLatin1String("01"))) {
0111                             // Previous balance
0112                             QString accountNumber = line.mid(22 - 1, 11);
0113                             inititalAmount = line.mid(91 - 1, 14);
0114 
0115                             SKGObjectBase::SKGListSKGObjectBase listAccount;
0116                             err = m_importer->getDocument()->getObjects(QStringLiteral("v_account"), "t_number='" % accountNumber % '\'', listAccount);
0117                             IFOK(err) {
0118                                 if (listAccount.count() == 1) {
0119                                     // Yes ! Only one account found
0120                                     account = listAccount.at(0);
0121                                     err = m_importer->getDocument()->sendMessage(i18nc("An information message",  "Using account '%1' for import", account.getName()));
0122                                 } else {
0123                                     if (listAccount.count() > 1) {
0124                                         err = m_importer->getDocument()->sendMessage(i18nc("An information message",  "More than one possible account found."));
0125                                     }
0126 
0127                                     SKGBankObject bank(m_importer->getDocument());
0128                                     IFOKDO(err, bank.setName(bankName))
0129                                     IFOKDO(err, bank.setNumber(bankName))
0130                                     if (!err && bank.load().isFailed()) {
0131                                         err = bank.save();
0132                                     }
0133                                     IFOKDO(err, bank.addAccount(account))
0134                                     IFOKDO(err, account.setName(accountNumber))
0135                                     IFOKDO(err, account.setNumber(accountNumber))
0136                                     IFOKDO(err, account.setType(SKGAccountObject::CURRENT))
0137                                     if (!err && account.load().isFailed()) {
0138                                         err = account.save();
0139                                     }
0140                                     IFOKDO(err, m_importer->getDocument()->sendMessage(i18nc("An information message",  "Default account '%1' created for import", accountNumber)))
0141                                 }
0142                             }
0143                         } else if (line.startsWith(QLatin1String("04"))) {
0144                             // Transaction
0145                             QString unitCode = line.mid(17 - 1, 3);
0146                             QString nbDecimal = line.mid(20 - 1, 1);
0147                             // QString codeMode = line.mid(33 - 1, 2);
0148                             QString dateJJMMAA = line.mid(35 - 1, 6);
0149                             QString comment = line.mid(49 - 1, 31).trimmed();
0150                             QString amount = line.mid(91 - 1, 14);
0151 
0152                             // Initialize balance
0153                             if (unit.getID() == 0) {
0154                                 err = SKGUnitObject::createCurrencyUnit(m_importer->getDocument(), unitCode, unit);
0155                                 if (account.getNbOperation() > 1) {
0156                                     IFOKDO(err, m_importer->getDocument()->sendMessage(i18nc("An information message", "The initial balance of '%1' has not been set because some transactions are already existing", account.getName()), SKGDocument::Warning))
0157                                 } else {
0158                                     // Set initial balance
0159                                     IFOKDO(err, account.setInitialBalance(toAmount(inititalAmount, SKGServices::stringToInt(nbDecimal)), unit))
0160                                     IFOKDO(err, account.save())
0161                                     IFOKDO(err, m_importer->getDocument()->sendMessage(i18nc("An information message", "The initial balance of '%1' has been set with AFB120 file content", account.getName())))
0162                                 }
0163                             }
0164 
0165                             SKGOperationObject operation;
0166                             IFOKDO(err, account.addOperation(operation, true))
0167                             IFOKDO(err, operation.setDate(SKGServices::stringToTime(SKGServices::dateToSqlString(dateJJMMAA, QStringLiteral("DDMMYYYY"))).date()))
0168                             IFOKDO(err, operation.setUnit(unit))
0169                             IFOKDO(err, operation.setAttribute(QStringLiteral("t_imported"), QStringLiteral("T")))
0170                             IFOKDO(err, operation.setComment(comment))
0171                             QByteArray hash = QCryptographicHash::hash(line.toUtf8(), QCryptographicHash::Md5);
0172                             IFOKDO(err, operation.setImportID(QStringLiteral("AFB120-") % hash.toHex()))
0173                             IFOKDO(err, operation.save(false))
0174 
0175                             SKGSubOperationObject subop;
0176                             IFOKDO(err, operation.addSubOperation(subop))
0177                             IFOKDO(err, subop.setComment(comment))
0178                             IFOKDO(err, subop.setQuantity(toAmount(amount, SKGServices::stringToInt(nbDecimal))))
0179                             IFOKDO(err, subop.save(false, false))
0180                         }
0181                     }
0182                     IFOKDO(err, m_importer->getDocument()->stepForward(i + 1))
0183                 }
0184                 SKGENDTRANSACTION(m_importer->getDocument(),  err)
0185 
0186                 // Step 2 done
0187                 IFOKDO(err, m_importer->getDocument()->stepForward(2))
0188             }
0189         }
0190     }
0191     SKGENDTRANSACTION(m_importer->getDocument(),  err)
0192 
0193     return err;
0194 }
0195 
0196 QString SKGImportPluginAFB120::getMimeTypeFilter() const
0197 {
0198     return "*.afb120 *.cfo|" % i18nc("A file format", "AFB120 file (cfomb)");
0199 }
0200 
0201 #include <skgimportpluginafb120.moc>