File indexing completed on 2024-05-12 05:07:34

0001 /*
0002     SPDX-FileCopyrightText: 2020 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "config-kmymoney.h"
0007 
0008 #include "templatewriter.h"
0009 
0010 // ----------------------------------------------------------------------------
0011 // QT Includes
0012 
0013 #include <QDebug>
0014 #include <QDir>
0015 #include <QDomElement>
0016 #include <QList>
0017 #include <QSaveFile>
0018 #include <QStandardPaths>
0019 #include <QTemporaryFile>
0020 #include <QUrl>
0021 
0022 // ----------------------------------------------------------------------------
0023 // KDE Includes
0024 
0025 #include <KLocalizedString>
0026 #include <KIO/StoredTransferJob>
0027 #include <KJobWidgets>
0028 #include <KXmlGuiWindow>
0029 #include <KMessageBox>
0030 #include <KTextEdit>
0031 
0032 // ----------------------------------------------------------------------------
0033 // Project Includes
0034 
0035 #include "templatesmodel.h"
0036 #include "mymoneytemplate.h"
0037 #include "kmymoneyutils.h"
0038 #include "mymoneyfile.h"
0039 #include "mymoneyaccount.h"
0040 #include "mymoneyexception.h"
0041 
0042 
0043 class TemplateWriterPrivate
0044 {
0045     Q_DISABLE_COPY(TemplateWriterPrivate)
0046 
0047 public:
0048     explicit TemplateWriterPrivate(TemplateWriter* qq)
0049         : q_ptr(qq)
0050     {
0051         m_doc = QDomDocument("KMYMONEY-TEMPLATE");
0052 
0053         QDomProcessingInstruction instruct = m_doc.createProcessingInstruction(QString("xml"), QString("version=\"1.0\" encoding=\"utf-8\""));
0054         m_doc.appendChild(instruct);
0055 
0056         m_mainElement = m_doc.createElement("kmymoney-account-template");
0057         m_doc.appendChild(m_mainElement);
0058     }
0059 
0060     ~TemplateWriterPrivate()
0061     {
0062     }
0063 
0064     void prepareDomDocument(const MyMoneyTemplate& tmpl)
0065     {
0066         QDomElement title = m_doc.createElement("title");
0067         QDomText t = m_doc.createTextNode(tmpl.title());
0068         title.appendChild(t);
0069         m_mainElement.appendChild(title);
0070 
0071         QDomElement shortDesc = m_doc.createElement("shortdesc");
0072         t = m_doc.createTextNode(tmpl.shortDescription());
0073         shortDesc.appendChild(t);
0074         m_mainElement.appendChild(shortDesc);
0075 
0076         QDomElement longDesc = m_doc.createElement("longdesc");
0077         t = m_doc.createTextNode(tmpl.longDescription());
0078         longDesc.appendChild(t);
0079         m_mainElement.appendChild(longDesc);
0080     }
0081 
0082     void collectAccounts()
0083     {
0084         // prepare vat account map
0085         QList<MyMoneyAccount> accountList;
0086         MyMoneyFile::instance()->accountList(accountList);
0087         int i = 0;
0088         QList<MyMoneyAccount>::Iterator it;
0089         for (it = accountList.begin(); it != accountList.end(); ++it) {
0090             if (!(*it).pairs().contains("VatAccount"))
0091                 continue;
0092             m_vatAccountMap[(*it).value("VatAccount")] = QString::fromLatin1("%1").arg(i++, 3, 10, QLatin1Char('0'));
0093         }
0094 
0095         QDomElement accounts = m_doc.createElement("accounts");
0096         m_mainElement.appendChild(accounts);
0097 
0098         addAccountStructure(accounts, MyMoneyFile::instance()->asset());
0099         addAccountStructure(accounts, MyMoneyFile::instance()->expense());
0100         addAccountStructure(accounts, MyMoneyFile::instance()->income());
0101         addAccountStructure(accounts, MyMoneyFile::instance()->liability());
0102         addAccountStructure(accounts, MyMoneyFile::instance()->equity());
0103     }
0104 
0105     void addAccountStructure(QDomElement& parent, const MyMoneyAccount& acc)
0106     {
0107         QDomElement account = m_doc.createElement("account");
0108         parent.appendChild(account);
0109 
0110         if (MyMoneyFile::instance()->isStandardAccount(acc.id()))
0111             account.setAttribute(QString("name"), QString());
0112         else
0113             account.setAttribute(QString("name"), acc.name());
0114         account.setAttribute(QString("type"), (int)acc.accountType());
0115 
0116         if (acc.pairs().contains("Tax")) {
0117             QDomElement flag = m_doc.createElement("flag");
0118             flag.setAttribute(QString("name"), "Tax");
0119             flag.setAttribute(QString("value"), acc.value("Tax"));
0120             account.appendChild(flag);
0121         }
0122         if (m_vatAccountMap.contains(acc.id()))
0123             account.setAttribute(QString("id"), m_vatAccountMap[acc.id()]);
0124 
0125         if (acc.pairs().contains("VatRate")) {
0126             QDomElement flag = m_doc.createElement("flag");
0127             flag.setAttribute(QString("name"), "VatRate");
0128             flag.setAttribute(QString("value"), acc.value("VatRate"));
0129             account.appendChild(flag);
0130         }
0131         if (acc.pairs().contains("VatAccount")) {
0132             QDomElement flag = m_doc.createElement("flag");
0133             flag.setAttribute(QString("name"), "VatAccount");
0134             flag.setAttribute(QString("value"), m_vatAccountMap[acc.value("VatAccount")]);
0135             account.appendChild(flag);
0136         }
0137         if (acc.pairs().contains("OpeningBalanceAccount")) {
0138             QString openingBalanceAccount = acc.value("OpeningBalanceAccount");
0139             if (openingBalanceAccount == "Yes") {
0140                 QDomElement flag = m_doc.createElement("flag");
0141                 flag.setAttribute(QString("name"), "OpeningBalanceAccount");
0142                 flag.setAttribute(QString("currency"), acc.currencyId());
0143                 account.appendChild(flag);
0144             }
0145         }
0146 
0147         // any child accounts?
0148         if (acc.accountList().count() > 0) {
0149             QList<MyMoneyAccount> list;
0150             MyMoneyFile::instance()->accountList(list, acc.accountList(), false);
0151             std::sort(list.begin(), list.end(), [](MyMoneyAccount &a1, MyMoneyAccount &a2) {
0152                 return a1.name() < a2.name();
0153             } );
0154             QList<MyMoneyAccount>::Iterator it;
0155             for (it = list.begin(); it != list.end(); ++it) {
0156                 addAccountStructure(account, *it);
0157             }
0158         }
0159     }
0160 
0161     bool saveTemplate(const QUrl &url)
0162     {
0163 
0164         auto saveToLocalFile = [&](QSaveFile* qfile)
0165         {
0166             QTextStream stream(qfile);
0167 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0168             stream.setCodec("UTF-8");
0169 #endif
0170             stream << m_doc.toString();
0171             stream.flush();
0172         };
0173 
0174         QString filename;
0175 
0176 
0177         if (!url.isValid()) {
0178             m_errMsg = i18n("Invalid template URL '%1'", url.toDisplayString());
0179             return false;
0180         }
0181 
0182         if (url.isLocalFile()) {
0183             filename = url.toLocalFile();
0184             QSaveFile qfile(filename/*, 0600*/);
0185             if (qfile.open(QIODevice::WriteOnly)) {
0186                 saveToLocalFile(&qfile);
0187                 if (!qfile.commit()) {
0188                     m_errMsg = i18n("Unable to write changes to '%1'", filename);
0189                     return false;
0190                 }
0191             } else {
0192                 m_errMsg = i18n("Unable to open template file '%1'", filename);
0193                 return false;
0194             }
0195         } else {
0196             QTemporaryFile tmpfile;
0197             tmpfile.open();
0198             QSaveFile qfile(tmpfile.fileName());
0199             if (qfile.open(QIODevice::WriteOnly)) {
0200                 saveToLocalFile(&qfile);
0201                 if (!qfile.commit()) {
0202                     m_errMsg = i18n("Unable to write changes to '%1'", tmpfile.fileName());
0203                     return false;
0204                 }
0205             } else {
0206                 m_errMsg = i18n("Unable to open template file '%1'", tmpfile.fileName());
0207                 return false;
0208             }
0209 
0210             int permission = -1;
0211             QFile file(tmpfile.fileName());
0212             file.open(QIODevice::ReadOnly);
0213             KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite);
0214             if (!putjob->exec()) {
0215                 m_errMsg = i18n("Unable to upload to '%1'.<br />%2", url.toDisplayString(), putjob->errorString());
0216                 return false;
0217             }
0218             file.close();
0219         }
0220         return true;
0221     }
0222 
0223 public:
0224     TemplateWriter*                         q_ptr;
0225     QMap<QString,QString>                   m_vatAccountMap;
0226     QDomDocument                            m_doc;
0227     QDomElement                             m_mainElement;
0228     QString                                 m_errMsg;
0229 };
0230 
0231 
0232 TemplateWriter::TemplateWriter(QWidget* parent) :
0233     QObject(parent),
0234     d_ptr(new TemplateWriterPrivate(this))
0235 {
0236 }
0237 
0238 TemplateWriter::~TemplateWriter()
0239 {
0240     Q_D(TemplateWriter);
0241     delete d;
0242 }
0243 
0244 
0245 bool TemplateWriter::exportTemplate(const MyMoneyTemplate& tmpl, const QUrl &url)
0246 {
0247     Q_D(TemplateWriter);
0248 
0249     d->prepareDomDocument(tmpl);
0250     d->collectAccounts();
0251     return d->saveTemplate(url);
0252 }
0253 
0254 QString TemplateWriter::errorMessage() const
0255 {
0256     Q_D(const TemplateWriter);
0257     return d->m_errMsg;
0258 }