Message info
 
To:kde-commits@kde.org From:Allan Anderson Subject:[kmymoney] kmymoney/converter: Bug: 213284. Add support for export of investment accounts. Date:Thu, 5 Apr 2012 23:11:11 +0200 (CEST)
 

Git commit 79451a82f2040cae8b09896ba304d9bbfb14f2db by Allan Anderson.
Committed on 23/02/2012 at 17:55.
Pushed by allananderson into branch 'master'.

Bug: 213284. Add support for export of investment accounts.
Remove unused parameter.
Rename findSubAccounts() to extractInvestmentEntries(), better to reflect its full function.
Add local 'count' variable to writeInvestmentEntry().
Minor style changes.
Fix erroneous handling of values in Sell transactions.
Remove line added in error.
Re-instate line removed in error.

M +250 -39 kmymoney/converter/mymoneyqifwriter.cpp
M +12 -8 kmymoney/converter/mymoneyqifwriter.h

http://commits.kde.org/kmymoney/79451a82f2040cae8b09896ba304d9bbfb14f2db

diff --git a/kmymoney/converter/mymoneyqifwriter.cpp b/kmymoney/converter/mymoneyqifwriter.cpp
index 3f76484..ab21f79 100644
--- a/kmymoney/converter/mymoneyqifwriter.cpp
+++ b/kmymoney/converter/mymoneyqifwriter.cpp
@@ -9,6 +9,7 @@
John C <thetacoturtle@users.sourceforge.net>
Thomas Baumgart <ipwizard@users.sourceforge.net>
Kevin Tambascio <ktambascio@users.sourceforge.net>
+ Allan Anderson agander93@gmail.com
***************************************************************************/

/***************************************************************************
@@ -27,6 +28,7 @@

#include <QFile>
#include <QList>
+#include <QDebug>

// ----------------------------------------------------------------------------
// KDE Headers
@@ -78,55 +80,62 @@ void MyMoneyQifWriter::write(const QString& filename, const QString& profile,
}

qifFile.close();
+ qDebug() << "Export completed.\n";
} else {
KMessageBox::error(0, i18n("Unable to open file '%1' for writing", filename));
}
}

-void MyMoneyQifWriter::writeAccountEntry(QTextStream &s, const QString& accountId, const QDate& startDate, const QDate& endDate)
+void MyMoneyQifWriter::writeAccountEntry(QTextStream& s, const QString& accountId, const QDate& startDate, const QDate& endDate)
{
MyMoneyFile* file = MyMoneyFile::instance();
MyMoneyAccount account;

account = file->account(accountId);
MyMoneyTransactionFilter filter(accountId);
- filter.setDateFilter(startDate, endDate);
- QList<MyMoneyTransaction> list = file->transactionList(filter);
+
QString openingBalanceTransactionId;
+ QString type = m_qifProfile.profileType();

- s << "!Type:" << m_qifProfile.profileType() << endl;
- if (!startDate.isValid() || startDate <= account.openingDate()) {
- s << "D" << m_qifProfile.date(account.openingDate()) << endl;
- openingBalanceTransactionId = file->openingBalanceTransaction(account);
- MyMoneySplit split;
- if (!openingBalanceTransactionId.isEmpty()) {
- MyMoneyTransaction openingBalanceTransaction = file->transaction(openingBalanceTransactionId);
- split = openingBalanceTransaction.splitByAccount(account.id(), true /* match */);
- }
- s << "T" << m_qifProfile.value('T', split.value()) << endl;
+ s << "!Type:" << type << endl;
+ if (type == "Invst") {
+ extractInvestmentEntries(s, accountId, startDate, endDate);
} else {
- s << "D" << m_qifProfile.date(startDate) << endl;
- s << "T" << m_qifProfile.value('T', file->balance(accountId, startDate.addDays(-1))) << endl;
- }
- s << "CX" << endl;
- s << "P" << m_qifProfile.openingBalanceText() << endl;
- s << "L";
- if (m_qifProfile.accountDelimiter().length())
- s << m_qifProfile.accountDelimiter()[0];
- s << account.name();
- if (m_qifProfile.accountDelimiter().length() > 1)
- s << m_qifProfile.accountDelimiter()[1];
- s << endl;
- s << "^" << endl;
-
- QList<MyMoneyTransaction>::ConstIterator it;
- signalProgress(0, list.count());
- int count = 0;
- for (it = list.constBegin(); it != list.constEnd(); ++it) {
- // don't include the openingBalanceTransaction again
- if ((*it).id() != openingBalanceTransactionId)
- writeTransactionEntry(s, *it, accountId);
- signalProgress(++count, 0);
+ filter.setDateFilter(startDate, endDate);
+ QList<MyMoneyTransaction> list = file->transactionList(filter);
+ if (!startDate.isValid() || startDate <= account.openingDate()) {
+ s << "D" << m_qifProfile.date(account.openingDate()) << endl;
+ openingBalanceTransactionId = file->openingBalanceTransaction(account);
+ MyMoneySplit split;
+ if (!openingBalanceTransactionId.isEmpty()) {
+ MyMoneyTransaction openingBalanceTransaction = file->transaction(openingBalanceTransactionId);
+ split = openingBalanceTransaction.splitByAccount(account.id(), true /* match */);
+ }
+ s << "T" << m_qifProfile.value('T', split.value()) << endl;
+ } else {
+ s << "D" << m_qifProfile.date(startDate) << endl;
+ s << "T" << m_qifProfile.value('T', file->balance(accountId, startDate.addDays(-1))) << endl;
+ }
+ s << "CX" << endl;
+ s << "P" << m_qifProfile.openingBalanceText() << endl;
+ s << "L";
+ if (m_qifProfile.accountDelimiter().length())
+ s << m_qifProfile.accountDelimiter()[0];
+ s << account.name();
+ if (m_qifProfile.accountDelimiter().length() > 1)
+ s << m_qifProfile.accountDelimiter()[1];
+ s << endl;
+ s << "^" << endl;
+
+ QList<MyMoneyTransaction>::ConstIterator it;
+ signalProgress(0, list.count());
+ int count = 0;
+ for (it = list.constBegin(); it != list.constEnd(); ++it) {
+ // don't include the openingBalanceTransaction again
+ if ((*it).id() != openingBalanceTransactionId)
+ writeTransactionEntry(s, *it, accountId);
+ signalProgress(++count, 0);
+ }
}
}

@@ -211,8 +220,8 @@ void MyMoneyQifWriter::writeTransactionEntry(QTextStream &s, const MyMoneyTransa
if (acc.accountGroup() != MyMoneyAccount::Income
&& acc.accountGroup() != MyMoneyAccount::Expense) {
s << "L" << m_qifProfile.accountDelimiter()[0]
- << MyMoneyFile::instance()->accountToCategory(sp.accountId())
- << m_qifProfile.accountDelimiter()[1] << endl;
+ << MyMoneyFile::instance()->accountToCategory(sp.accountId())
+ << m_qifProfile.accountDelimiter()[1] << endl;
} else {
s << "L" << file->accountToCategory(sp.accountId()) << endl;
}
@@ -237,8 +246,8 @@ void MyMoneyQifWriter::writeSplitEntry(QTextStream& s, const MyMoneySplit& split
if (acc.accountGroup() != MyMoneyAccount::Income
&& acc.accountGroup() != MyMoneyAccount::Expense) {
s << m_qifProfile.accountDelimiter()[0]
- << file->accountToCategory(split.accountId())
- << m_qifProfile.accountDelimiter()[1];
+ << file->accountToCategory(split.accountId())
+ << m_qifProfile.accountDelimiter()[1];
} else {
s << file->accountToCategory(split.accountId());
}
@@ -253,4 +262,206 @@ void MyMoneyQifWriter::writeSplitEntry(QTextStream& s, const MyMoneySplit& split
s << "$" << m_qifProfile.value('$', -split.value()) << endl;
}

+void MyMoneyQifWriter::extractInvestmentEntries(QTextStream &s, const QString& accountId, const QDate& startDate, const QDate& endDate)
+{
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QList<QString> accList = file->account(accountId).accountList();
+ QList<QString>::ConstIterator itAcc;
+ for (itAcc = accList.constBegin(); itAcc != accList.constEnd(); ++itAcc) {
+ MyMoneyTransactionFilter filter((*itAcc));
+ filter.setDateFilter(startDate, endDate);
+ QList<MyMoneyTransaction> list = file->transactionList(filter);
+ QList<MyMoneyTransaction>::ConstIterator it;
+ signalProgress(0, list.count());
+ int count = 0;
+ for (it = list.constBegin(); it != list.constEnd(); ++it) {
+ writeInvestmentEntry(s, *it, ++count);
+ signalProgress(count, 0);
+ }
+ }
+}
+
+void MyMoneyQifWriter::writeInvestmentEntry(QTextStream& stream, const MyMoneyTransaction& t, const int count)
+{
+ QString s;
+ QString memo;
+ MyMoneyFile* file = MyMoneyFile::instance();
+ QString chkAccnt = QString();
+ bool isXfer = false;
+ bool noError = true;
+ QList<MyMoneySplit> lst = t.splits();
+ QList<MyMoneySplit>::Iterator it;
+ MyMoneyAccount::_accountTypeE typ;
+ QString chkAccntId;
+ MyMoneyMoney qty;
+ MyMoneyMoney value;
+ QMap<MyMoneyAccount::_accountTypeE, QString> map;
+
+ for (int i = 0; i < lst.count(); i++) {
+ QString actionType = lst[i].action();
+ MyMoneyAccount acc = file->account(lst[i].accountId());
+ QString accName = acc.name();
+ typ = acc.accountType();
+ map.insert(typ, lst[i].accountId());
+ if (typ == MyMoneyAccount::Stock) {
+ memo = lst[i].memo();
+ }
+ }
+ //
+ // Add date.
+ //
+ if (noError) {
+ s += "D" + m_qifProfile.date(t.postDate()) + '\n';
+ }
+ for (it = lst.begin(); it != lst.end(); ++it) {
+ QString accName;
+ QString actionType = (*it).action();
+ MyMoneyAccount acc = file->account((*it).accountId());
+ typ = acc.accountType();
+ //
+ // MyMoneyAccount::Checkings.
+ //
+ if ((acc.accountType() == MyMoneyAccount::Checkings) || (acc.accountType() == MyMoneyAccount::Cash)) {
+ chkAccntId = (*it).accountId();
+ chkAccnt = file->account(chkAccntId).name();
+ } else if (acc.accountType() == MyMoneyAccount::Income) {
+ //
+ // MyMoneyAccount::Income.
+ //
+ } else if (acc.accountType() == MyMoneyAccount::Expense) {
+ //
+ // MyMoneyAccount::Expense.
+ //
+ } else if (acc.accountType() == MyMoneyAccount::Stock) {
+ //
+ // MyMoneyAccount::Stock.
+ //
+ qty = (*it).shares();
+ value = (*it).value();
+
+ accName = acc.name();
+ if ((actionType == "Dividend") || (actionType == "Buy") || (actionType == "IntIncome")) {
+ isXfer = true;
+ }
+ //
+ // Actions.
+ //
+ QString action;
+ if ((*it).action() == "Dividend") {
+ action = "DivX";
+ } else if ((*it).action() == "IntIncome") {
+ action = "IntIncX";
+ }
+ if ((action == "DivX") || (action == "IntIncX")) {
+ if (map.value(MyMoneyAccount::Checkings).isEmpty()) {
+ KMessageBox::sorry(0,
+ QString("<qt>%1</qt>").arg(i18n("Transaction number <b>%1</b> is missing an account assignment.\nTransaction dropped.", count)),
+ i18n("Invalid transaction"));
+ noError = false;
+ return;
+ }
+ MyMoneySplit sp = t.splitByAccount(map.value(MyMoneyAccount::Checkings), true);
+ QString txt = sp.value().formatMoney("", 2);
+ if (noError) {
+ s += "T" + txt + '\n';
+ }
+ } else if ((*it).action() == "Buy") {
+
+ if (qty.isNegative()) {
+ action = "Sell";
+ } else {
+ action = "Buy";
+ }
+ } else if ((*it).action() == "Add") {
+ qty = (*it).shares();
+ if (qty.isNegative()) {
+ action = "Shrsout";
+ } else {
+ action = "Shrsin";
+ }
+ } else if ((*it).action() == "Reinvest") {
+ action = "ReinvDiv";
+ } else {
+ action = (*it).action();
+ }
+
+ //
+ // Add action.
+ //
+ if (noError) {
+ s += "N" + action + '\n';
+ }
+ QString txt;
+ if ((action == "Buy") || (action == "Sell") || (action == "ReinvDiv")) {
+ //
+ // Add total.
+ //
+ txt = value.formatMoney("", 2);
+ if (action == "Sell") {
+ value = -value;
+ txt = value.formatMoney("", 2);
+ }
+ if (noError) {
+ s += "T" + txt + '\n';
+ }
+ //
+ // Add price.
+ //
+ txt = (*it).price().formatMoney("", 6);
+ if (noError) {
+ s += "I" + txt + '\n';
+ }
+ if (!qty.isZero()) {
+ //
+ // Add quantity.
+ //
+ if (noError) {
+ if (action == "Sell") {
+ qty = -qty;
+ }
+ s += "Q" + m_qifProfile.value('Q', qty) + '\n';
+ }
+ }
+ } else if ((action == "Shrsin") || (action == "Shrsout")) {
+ //
+ // Add quantity for "Shrsin" || "Shrsout".
+ //
+ if (noError) {
+ if (action == "Shrsout") {
+ qty = -qty;
+ }
+ s += "Q" + m_qifProfile.value('Q', qty) + '\n';
+ }
+ }
+ }
+ if (!accName.isEmpty()) {
+ if (noError) {
+ s += "Y" + accName + '\n';
+ }
+ }
+ }
+ if (!memo.isEmpty()) {
+ if (noError) {
+ memo.replace('\n', "\n");
+ s += "M" + memo + '\n';
+ }
+ }
+ if ((!chkAccnt.isEmpty()) && isXfer) {
+ //
+ // Add account - including its hierarchy.
+ //
+ if (noError) {
+ s += "L" + m_qifProfile.accountDelimiter()[0] + file->accountToCategory(chkAccntId)
+ + m_qifProfile.accountDelimiter()[1] + '\n';
+ stream << s;
+ } else {
+ // Don't output the transaction
+ }
+ } else {
+ stream << s;
+ }
+ stream << '^' << '\n';
+}
+
#include "mymoneyqifwriter.moc"
+
diff --git a/kmymoney/converter/mymoneyqifwriter.h b/kmymoney/converter/mymoneyqifwriter.h
index 2f66f9b..176b8c4 100644
--- a/kmymoney/converter/mymoneyqifwriter.h
+++ b/kmymoney/converter/mymoneyqifwriter.h
@@ -71,12 +71,13 @@ public:
* @param startDate Transactions before this date will not be exported
* @param endDate Transactions after this date will not be exported
*/
- void write(const QString& filename, const QString& profile,
- const QString& accountId, const bool accountData,
+ void write(const QString &filename, const QString &profile,
+ const QString &accountId, const bool accountData,
const bool categoryData,
- const QDate& startDate, const QDate& endDate);
+ const QDate &startDate, const QDate &endDate);

private:
+
/**
* This method writes the entries necessary for an account. First
* the leadin, and then the transactions that are in the account
@@ -88,7 +89,7 @@ private:
* @param startDate date from which entries are written
* @param endDate date until which entries are written
*/
- void writeAccountEntry(QTextStream& s, const QString& accountId, const QDate& startDate, const QDate& endDate);
+ void writeAccountEntry(QTextStream &s, const QString &accountId, const QDate &startDate, const QDate &endDate);

/**
* This method writes the category entries to the stream
@@ -97,7 +98,7 @@ private:
*
* @param s reference to textstream
*/
- void writeCategoryEntries(QTextStream& s);
+ void writeCategoryEntries(QTextStream &s);

/**
* This method writes the category entry for account with
@@ -108,10 +109,12 @@ private:
* @param accountId id of the account to be written
* @param leadIn constant text that will be prepended to the account's name
*/
- void writeCategoryEntry(QTextStream& s, const QString& accountId, const QString& leadIn);
+ void writeCategoryEntry(QTextStream &s, const QString &accountId, const QString &leadIn);

- void writeTransactionEntry(QTextStream &s, const MyMoneyTransaction& t, const QString& accountId);
- void writeSplitEntry(QTextStream &s, const MyMoneySplit& t);
+ void writeTransactionEntry(QTextStream &s, const MyMoneyTransaction &t, const QString &accountId);
+ void writeSplitEntry(QTextStream &s, const MyMoneySplit &t);
+ void extractInvestmentEntries(QTextStream &s, const QString &accountId, const QDate &startDate, const QDate &endDate);
+ void writeInvestmentEntry(QTextStream &stream, const MyMoneyTransaction &t, const int count);

signals:
/**
@@ -134,6 +137,7 @@ signals:

private:
MyMoneyQifProfile m_qifProfile;
+
};

#endif