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 }