diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2011-07-04 22:38:03 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2011-07-04 22:38:03 +0000 |
commit | dadc34655c3ab961b0b0b94a10eaaba710f0b5e8 (patch) | |
tree | 99e72842fe687baea16376a147619b6048d7e441 /kmymoney2/mymoney/mymoneytransaction.cpp | |
download | kmymoney-dadc34655c3ab961b0b0b94a10eaaba710f0b5e8.tar.gz kmymoney-dadc34655c3ab961b0b0b94a10eaaba710f0b5e8.zip |
Added kmymoney
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kmymoney@1239792 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kmymoney2/mymoney/mymoneytransaction.cpp')
-rw-r--r-- | kmymoney2/mymoney/mymoneytransaction.cpp | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/kmymoney2/mymoney/mymoneytransaction.cpp b/kmymoney2/mymoney/mymoneytransaction.cpp new file mode 100644 index 0000000..10b4c08 --- /dev/null +++ b/kmymoney2/mymoney/mymoneytransaction.cpp @@ -0,0 +1,484 @@ +/*************************************************************************** + + mymoneytransaction.cpp + ------------------- + copyright : (C) 2000 by Michael Edwardes, + 2002 by Thomas Baumgart + email : mte@users.sourceforge.net, + ipwizard@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +// ---------------------------------------------------------------------------- +// QT Includes + +// ---------------------------------------------------------------------------- +// Project Includes + +#include "mymoneytransaction.h" + +MyMoneyTransaction::MyMoneyTransaction() : + MyMoneyObject() +{ + m_nextSplitID = 1; + m_entryDate = QDate(); + m_postDate = QDate(); +} + +MyMoneyTransaction::MyMoneyTransaction(const QString id, const MyMoneyTransaction& transaction) : + MyMoneyObject(id) +{ + *this = transaction; + m_id = id; + if(m_entryDate == QDate()) + m_entryDate = QDate::currentDate(); + + QValueList<MyMoneySplit>::Iterator it; + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + (*it).setTransactionId(id); + } +} + +MyMoneyTransaction::MyMoneyTransaction(const QDomElement& node, const bool forceId) : + MyMoneyObject(node, forceId) +{ + if("TRANSACTION" != node.tagName()) + throw new MYMONEYEXCEPTION("Node was not TRANSACTION"); + + m_nextSplitID = 1; + + m_postDate = stringToDate(node.attribute("postdate")); + m_entryDate = stringToDate(node.attribute("entrydate")); + m_bankID = QStringEmpty(node.attribute("bankid")); + m_memo = QStringEmpty(node.attribute("memo")); + m_commodity = QStringEmpty(node.attribute("commodity")); + + QDomNode child = node.firstChild(); + while ( !child.isNull() && child.isElement() ) + { + QDomElement c = child.toElement(); + if(c.tagName() == "SPLITS") { + // Process any split information found inside the transaction entry. + QDomNodeList nodeList = c.elementsByTagName("SPLIT"); + for(unsigned int i = 0; i < nodeList.count(); ++i) { + MyMoneySplit s(nodeList.item(i).toElement()); + if(!m_bankID.isEmpty()) + s.setBankID(m_bankID); + if(!s.accountId().isEmpty()) + addSplit(s); + else + qDebug("Dropped split because it did not have an account id"); + } + + } else if(c.tagName() == "KEYVALUEPAIRS") { + MyMoneyKeyValueContainer kvp(c); + setPairs(kvp.pairs()); + } + child = child.nextSibling(); + } + m_bankID = QString(); +} + +MyMoneyTransaction::~MyMoneyTransaction() +{ +} + +bool MyMoneyTransaction::operator == (const MyMoneyTransaction& right) const +{ + return (MyMoneyObject::operator==(right) && + MyMoneyKeyValueContainer::operator==(right) && + (m_commodity == right.m_commodity) && + ((m_memo.length() == 0 && right.m_memo.length() == 0) || (m_memo == right.m_memo)) && + (m_splits == right.m_splits) && + (m_entryDate == right.m_entryDate) && + (m_postDate == right.m_postDate) ); +} + +bool MyMoneyTransaction::accountReferenced(const QString& id) const +{ + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).accountId() == id) + return true; + } + return false; +} + +void MyMoneyTransaction::addSplit(MyMoneySplit& split) +{ + if(!split.id().isEmpty()) + throw new MYMONEYEXCEPTION("Cannot add split with assigned id (" + split.id() + ")"); + +/* + QValueList<MyMoneySplit>::Iterator it; + + // if the account referenced in this split is already + // referenced in another split, we add the amount of + // this split to the other one. All other data contained + // in the new split will be discarded. + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).accountId() == split.accountId()) { + (*it).setValue((*it).value()+split.value()); + split = (*it); + return; + } + } +*/ + + if(split.accountId().isEmpty()) + throw new MYMONEYEXCEPTION("Cannot add split that does not contain an account reference"); + + MyMoneySplit newSplit(nextSplitID(), split); + split = newSplit; + split.setTransactionId(id()); + m_splits.append(split); +} + +void MyMoneyTransaction::modifySplit(MyMoneySplit& split) +{ +// This version of the routine allows only a single +// split to reference one account. If a second split +// is modified to reference an account already referenced +// by another split, the values will be added and the +// duplicate removed. +/* + QValueList<MyMoneySplit>::Iterator it; + QValueList<MyMoneySplit>::Iterator self = m_splits.end(); + QValueList<MyMoneySplit>::Iterator dup = self; + bool duplicateAccount = false; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if(split.id() == (*it).id()) { + self = it; + } else if(split.accountId() == (*it).accountId()) { + (*it).setValue((*it).value() + split.value()); + dup = it; + duplicateAccount = true; + } + } + + if(self == m_splits.end()) + throw new MYMONEYEXCEPTION("Invalid split id '" + split.id() + "'"); + + if(duplicateAccount) { + m_splits.remove(self); + split = *dup; + } else + *self = split; +*/ + +// This is the other version which allows having more splits referencing +// the same account. + if(split.accountId().isEmpty()) + throw new MYMONEYEXCEPTION("Cannot modify split that does not contain an account reference"); + + QValueList<MyMoneySplit>::Iterator it; + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if(split.id() == (*it).id()) { + *it = split; + return; + } + } + throw new MYMONEYEXCEPTION(QString("Invalid split id '%1'").arg(split.id())); +} + +void MyMoneyTransaction::removeSplit(const MyMoneySplit& split) +{ + QValueList<MyMoneySplit>::Iterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if(split.id() == (*it).id()) { + m_splits.remove(it); + break; + } + } + if(it == m_splits.end()) + throw new MYMONEYEXCEPTION(QString("Invalid split id '%1'").arg(split.id())); +} + +void MyMoneyTransaction::removeSplits(void) +{ + m_splits.clear(); + m_nextSplitID = 1; +} + +const MyMoneySplit& MyMoneyTransaction::splitByPayee(const QString& payeeId) const +{ + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).payeeId() == payeeId) + return *it; + } + throw new MYMONEYEXCEPTION(QString("Split not found for payee '%1'").arg(QString(payeeId))); +} + +const MyMoneySplit& MyMoneyTransaction::splitByAccount(const QString& accountId, const bool match) const +{ + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if(match == true && (*it).accountId() == accountId) + return *it; + if(match == false && (*it).accountId() != accountId) + return *it; + } + throw new MYMONEYEXCEPTION(QString("Split not found for account %1%2").arg(match?"":"!").arg(QString(accountId))); +} + +const MyMoneySplit& MyMoneyTransaction::splitByAccount(const QStringList& accountIds, const bool match) const +{ + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if(match == true && accountIds.contains((*it).accountId()) ) + return *it; + if(match == false && !accountIds.contains((*it).accountId())) + return *it; + } + throw new MYMONEYEXCEPTION(QString("Split not found for account %1%1...%2").arg(match?"":"!").arg(accountIds.front(),accountIds.back())); +} + +const MyMoneySplit& MyMoneyTransaction::splitById(const QString& splitId) const +{ + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).id() == splitId) + return *it; + } + throw new MYMONEYEXCEPTION(QString("Split not found for id '%1'").arg(QString(splitId))); +} + +const QString MyMoneyTransaction::nextSplitID() +{ + QString id; + id = "S" + id.setNum(m_nextSplitID++).rightJustify(SPLIT_ID_SIZE, '0'); + return id; +} + +const QString MyMoneyTransaction::firstSplitID() +{ + QString id; + id = "S" + id.setNum(1).rightJustify(SPLIT_ID_SIZE, '0'); + return id; +} + +const MyMoneyMoney MyMoneyTransaction::splitSum(void) const +{ + MyMoneyMoney result(0); + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + result += (*it).value(); + } + return result; +} + +void MyMoneyTransaction::setPostDate(const QDate& date) { m_postDate = date; } +void MyMoneyTransaction::setEntryDate(const QDate& date) { m_entryDate = date; } +void MyMoneyTransaction::setMemo(const QString& memo) { m_memo = memo; } + +bool MyMoneyTransaction::isLoanPayment(void) const +{ + try { + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).isAmortizationSplit()) + return true; + } + } catch (MyMoneyException *e) { + delete e; + } + return false; +} + +const MyMoneySplit& MyMoneyTransaction::amortizationSplit(void) const +{ + static MyMoneySplit nullSplit; + + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).isAmortizationSplit() && (*it).isAutoCalc()) + return *it; + } + return nullSplit; +} + +const MyMoneySplit& MyMoneyTransaction::interestSplit(void) const +{ + static MyMoneySplit nullSplit; + + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).isInterestSplit() && (*it).isAutoCalc()) + return *it; + } + return nullSplit; +} + +unsigned long MyMoneyTransaction::hash(const QString& txt, unsigned long h) +{ + unsigned long g; + + for(unsigned i=0; i < txt.length(); ++i) { + unsigned short uc = txt[i].unicode(); + for(unsigned j = 0; j < 2; ++j) { + unsigned char c = uc & 0xff; + // if either the cell or the row of the Unicode char is 0, stop processing + if(!c) + break; + h = (h << 4) + c; + if( (g = (h & 0xf0000000)) ) { + h = h ^ (g >> 24); + h = h ^ g; + } + uc >>= 8; + } + } + return h; +} + +bool MyMoneyTransaction::isStockSplit(void) const +{ + return (m_splits.count() == 1 && m_splits[0].action() == MyMoneySplit::ActionSplitShares); +} + +bool MyMoneyTransaction::isImported(void) const +{ + return value("Imported").lower() == QString("true"); +} + +void MyMoneyTransaction::setImported(bool state) +{ + if(state) + setValue("Imported", "true"); + else + deletePair("Imported"); +} + +bool MyMoneyTransaction::isDuplicate(const MyMoneyTransaction& r) const +{ + bool rc = true; + if(splitCount() != r.splitCount()) { + rc = false; + } else { + if(abs(m_postDate.daysTo(r.postDate())) > 3) { + rc = false; + } else { + unsigned long accHash[2]; + unsigned long valHash[2]; + unsigned long numHash[2]; + for(int i = 0; i < 2; ++i) + accHash[i] = valHash[i] = numHash[i] = 0; + + QValueList<MyMoneySplit>::ConstIterator it; + for(it = splits().begin(); it != splits().end(); ++it) { + accHash[0] += hash((*it).accountId()); + valHash[0] += hash((*it).value().formatMoney("", 4)); + numHash[0] += hash((*it).number()); + } + for(it = r.splits().begin(); it != r.splits().end(); ++it) { + accHash[1] += hash((*it).accountId()); + valHash[1] += hash((*it).value().formatMoney("", 4)); + numHash[1] += hash((*it).number()); + } + + if(accHash[0] != accHash[1] + || valHash[0] != valHash[1] + || numHash[0] != numHash[1] + ) { + rc = false; + } + } + } + + return rc; +} + +void MyMoneyTransaction::writeXML(QDomDocument& document, QDomElement& parent) const +{ + QDomElement el = document.createElement("TRANSACTION"); + + writeBaseXML(document, el); + + el.setAttribute("postdate", dateToString(m_postDate)); + el.setAttribute("memo", m_memo); + el.setAttribute("entrydate", dateToString(m_entryDate)); + el.setAttribute("commodity", m_commodity); + + QDomElement splits = document.createElement("SPLITS"); + QValueList<MyMoneySplit>::ConstIterator it; + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + (*it).writeXML(document, splits); + } + el.appendChild(splits); + + MyMoneyKeyValueContainer::writeXML(document, el); + + parent.appendChild(el); +} + +bool MyMoneyTransaction::hasReferenceTo(const QString& id) const +{ + QValueList<MyMoneySplit>::const_iterator it; + bool rc = (id == m_commodity); + for(it = m_splits.begin(); rc == false && it != m_splits.end(); ++it) { + rc = (*it).hasReferenceTo(id); + } + return rc; +} + +bool MyMoneyTransaction::hasAutoCalcSplit(void) const +{ + QValueList<MyMoneySplit>::ConstIterator it; + + for(it = m_splits.begin(); it != m_splits.end(); ++it) { + if((*it).isAutoCalc()) + return true; + } + return false; +} + +QString MyMoneyTransaction::accountSignature(bool includeSplitCount) const +{ + QMap<QString, int> accountList; + QValueList<MyMoneySplit>::const_iterator it_s; + for(it_s = m_splits.begin(); it_s != m_splits.end(); ++it_s) { + accountList[(*it_s).accountId()] += 1; + } + + QMap<QString, int>::const_iterator it_a; + QString rc; + for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) { + if(it_a != accountList.begin()) + rc += "-"; + rc += it_a.key(); + if(includeSplitCount) + rc += QString("*%1").arg(*it_a); + } + return rc; +} + +QString MyMoneyTransaction::uniqueSortKey(void) const +{ + QString year, month, day, key; + const QDate& postdate = postDate(); + year = year.setNum(postdate.year()).rightJustify(YEAR_SIZE, '0'); + month = month.setNum(postdate.month()).rightJustify(MONTH_SIZE, '0'); + day = day.setNum(postdate.day()).rightJustify(DAY_SIZE, '0'); + key = year + "-" + month + "-" + day + "-" + m_id; + return key; +} |