File indexing completed on 2024-05-12 05:06:44

0001 /*
0002     SPDX-FileCopyrightText: 2002-2019 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-FileCopyrightText: 2004 Kevin Tambascio <ktambascio@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2005-2006 Ace Jones <acejones@users.sourceforge.net>
0005     SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "mymoneysplit.h"
0010 #include "mymoneysplit_p.h"
0011 
0012 // ----------------------------------------------------------------------------
0013 // QT Includes
0014 
0015 #include <QSet>
0016 
0017 // ----------------------------------------------------------------------------
0018 // KDE Includes
0019 
0020 // ----------------------------------------------------------------------------
0021 // Project Includes
0022 
0023 #include "mymoneyutils.h"
0024 #include "mymoneytransaction.h"
0025 #include "mymoneyexception.h"
0026 
0027 MyMoneySplit::MyMoneySplit() :
0028     MyMoneyObject(*new MyMoneySplitPrivate)
0029 {
0030 }
0031 
0032 MyMoneySplit::MyMoneySplit(const QString &id) :
0033     MyMoneyObject(*new MyMoneySplitPrivate, id)
0034 {
0035     Q_D(MyMoneySplit);
0036     d->m_reconcileFlag = eMyMoney::Split::State::NotReconciled;
0037 }
0038 
0039 MyMoneySplit::MyMoneySplit(const MyMoneySplit& other) :
0040     MyMoneyObject(*new MyMoneySplitPrivate(*other.d_func()), other.id()),
0041     MyMoneyKeyValueContainer(other)
0042 {
0043 }
0044 
0045 MyMoneySplit::MyMoneySplit(const QString& id, const MyMoneySplit& other) :
0046     MyMoneyObject(*new MyMoneySplitPrivate(*other.d_func()), id),
0047     MyMoneyKeyValueContainer(other)
0048 {
0049 }
0050 
0051 MyMoneySplit::~MyMoneySplit()
0052 {
0053 }
0054 
0055 bool MyMoneySplit::operator == (const MyMoneySplit& right) const
0056 {
0057     Q_D(const MyMoneySplit);
0058     auto d2 = static_cast<const MyMoneySplitPrivate *>(right.d_func());
0059     // clang-format off
0060     return MyMoneyObject::operator==(right)
0061         && MyMoneyKeyValueContainer::operator==(right)
0062         && d->m_account == d2->m_account
0063         && d->m_costCenter == d2->m_costCenter
0064         && d->m_payee == d2->m_payee
0065         && d->m_tagList == d2->m_tagList
0066         && d->m_memo == d2->m_memo
0067         && d->m_action == d2->m_action
0068         && d->m_reconcileDate == d2->m_reconcileDate
0069         && d->m_reconcileFlag == d2->m_reconcileFlag
0070         && ((d->m_number.length() == 0 && d2->m_number.length() == 0) || d->m_number == d2->m_number)
0071         && d->m_shares == d2->m_shares
0072         && d->m_value == d2->m_value
0073         && d->m_price == d2->m_price
0074         && d->m_transactionId == d2->m_transactionId;
0075     // clang-format on
0076 }
0077 
0078 MyMoneySplit MyMoneySplit::operator-() const
0079 {
0080     MyMoneySplit rc(*this);
0081     rc.d_func()->m_shares = -rc.d_func()->m_shares;
0082     rc.d_func()->m_value = -rc.d_func()->m_value;
0083     return rc;
0084 }
0085 
0086 QString MyMoneySplit::accountId() const
0087 {
0088     Q_D(const MyMoneySplit);
0089     return d->m_account;
0090 }
0091 
0092 void MyMoneySplit::setAccountId(const QString& account)
0093 {
0094     Q_D(MyMoneySplit);
0095     d->m_account = account;
0096     d->clearReferences();
0097 }
0098 
0099 QString MyMoneySplit::costCenterId() const
0100 {
0101     Q_D(const MyMoneySplit);
0102     return d->m_costCenter;
0103 }
0104 
0105 void MyMoneySplit::setCostCenterId(const QString& costCenter)
0106 {
0107     Q_D(MyMoneySplit);
0108     d->m_costCenter = costCenter;
0109     d->clearReferences();
0110 }
0111 
0112 QString MyMoneySplit::memo() const
0113 {
0114     Q_D(const MyMoneySplit);
0115     return d->m_memo;
0116 }
0117 
0118 void MyMoneySplit::setMemo(const QString& memo)
0119 {
0120     Q_D(MyMoneySplit);
0121     d->m_memo = memo;
0122 }
0123 
0124 eMyMoney::Split::State MyMoneySplit::reconcileFlag() const
0125 {
0126     Q_D(const MyMoneySplit);
0127     return d->m_reconcileFlag;
0128 }
0129 
0130 QDate MyMoneySplit::reconcileDate() const
0131 {
0132     Q_D(const MyMoneySplit);
0133     return d->m_reconcileDate;
0134 }
0135 
0136 void MyMoneySplit::setReconcileDate(const QDate& date)
0137 {
0138     Q_D(MyMoneySplit);
0139     d->m_reconcileDate = date;
0140 }
0141 
0142 void MyMoneySplit::setReconcileFlag(const eMyMoney::Split::State flag)
0143 {
0144     Q_D(MyMoneySplit);
0145     d->m_reconcileFlag = flag;
0146 }
0147 
0148 MyMoneyMoney MyMoneySplit::shares() const
0149 {
0150     Q_D(const MyMoneySplit);
0151     return d->m_shares;
0152 }
0153 
0154 void MyMoneySplit::setShares(const MyMoneyMoney& shares)
0155 {
0156     Q_D(MyMoneySplit);
0157     d->m_shares = shares;
0158 }
0159 
0160 void MyMoneySplit::negateShares()
0161 {
0162     Q_D(MyMoneySplit);
0163     d->m_shares = -d->m_shares;
0164 }
0165 
0166 QString MyMoneySplit::value(const QString& key) const
0167 {
0168     return MyMoneyKeyValueContainer::value(key);
0169 }
0170 
0171 void MyMoneySplit::setValue(const QString& key, const QString& value, const QString& defaultValue)
0172 {
0173     MyMoneyKeyValueContainer::setValue(key, value, defaultValue);
0174 }
0175 
0176 void MyMoneySplit::setValue(const MyMoneyMoney& value)
0177 {
0178     Q_D(MyMoneySplit);
0179     d->m_value = value;
0180 }
0181 
0182 void MyMoneySplit::setValue(const MyMoneyMoney& value, const QString& transactionCurrencyId, const QString& splitCurrencyId)
0183 {
0184     if (transactionCurrencyId == splitCurrencyId)
0185         setValue(value);
0186     else
0187         setShares(value);
0188 }
0189 
0190 void MyMoneySplit::negateValue()
0191 {
0192     Q_D(MyMoneySplit);
0193     d->m_value = -d->m_value;
0194 }
0195 
0196 QString MyMoneySplit::payeeId() const
0197 {
0198     Q_D(const MyMoneySplit);
0199     return d->m_payee;
0200 }
0201 
0202 void MyMoneySplit::setPayeeId(const QString& payee)
0203 {
0204     Q_D(MyMoneySplit);
0205     d->m_payee = payee;
0206     d->clearReferences();
0207 }
0208 
0209 QList<QString> MyMoneySplit::tagIdList() const
0210 {
0211     Q_D(const MyMoneySplit);
0212     return d->m_tagList;
0213 }
0214 
0215 void MyMoneySplit::setTagIdList(const QList<QString>& tagList)
0216 {
0217     Q_D(MyMoneySplit);
0218     d->m_tagList = tagList;
0219     d->clearReferences();
0220 }
0221 
0222 void MyMoneySplit::setAction(eMyMoney::Split::InvestmentTransactionType type)
0223 {
0224     switch (type) {
0225     case eMyMoney::Split::InvestmentTransactionType::BuyShares:
0226     case eMyMoney::Split::InvestmentTransactionType::SellShares:
0227         setAction(actionName(Split::Action::BuyShares));
0228         break;
0229     case eMyMoney::Split::InvestmentTransactionType::Dividend:
0230         setAction(actionName(Split::Action::Dividend));
0231         break;
0232     case eMyMoney::Split::InvestmentTransactionType::Yield:
0233         setAction(actionName(Split::Action::Yield));
0234         break;
0235     case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend:
0236         setAction(actionName(Split::Action::ReinvestDividend));
0237         break;
0238     case eMyMoney::Split::InvestmentTransactionType::AddShares:
0239     case eMyMoney::Split::InvestmentTransactionType::RemoveShares:
0240         setAction(actionName(Split::Action::AddShares));
0241         break;
0242     case eMyMoney::Split::InvestmentTransactionType::SplitShares:
0243         setAction(actionName(Split::Action::SplitShares));
0244         break;
0245     case eMyMoney::Split::InvestmentTransactionType::InterestIncome:
0246         setAction(actionName(Split::Action::InterestIncome));
0247         break;
0248     case eMyMoney::Split::InvestmentTransactionType::UnknownTransactionType:
0249         break;
0250     }
0251 }
0252 
0253 eMyMoney::Split::InvestmentTransactionType MyMoneySplit::investmentTransactionType() const
0254 {
0255     Q_D(const MyMoneySplit);
0256     switch(actionStringToAction(d->m_action)) {
0257     case Split::Action::BuyShares:
0258         return (d->m_shares.isNegative()) ? Split::InvestmentTransactionType::SellShares : Split::InvestmentTransactionType::BuyShares;
0259 
0260     case Split::Action::Dividend:
0261         return Split::InvestmentTransactionType::Dividend;
0262 
0263     case Split::Action::Yield:
0264         return Split::InvestmentTransactionType::Yield;
0265 
0266     case Split::Action::ReinvestDividend:
0267         return Split::InvestmentTransactionType::ReinvestDividend;
0268 
0269     case Split::Action::AddShares:
0270         return (d->m_shares.isNegative()) ? Split::InvestmentTransactionType::RemoveShares : Split::InvestmentTransactionType::AddShares;
0271 
0272     case Split::Action::SplitShares:
0273         return Split::InvestmentTransactionType::SplitShares;
0274 
0275     case Split::Action::InterestIncome:
0276         return Split::InvestmentTransactionType::InterestIncome;
0277 
0278     default:
0279         return Split::InvestmentTransactionType::UnknownTransactionType;
0280     }
0281 }
0282 
0283 QString MyMoneySplit::action() const
0284 {
0285     Q_D(const MyMoneySplit);
0286     return d->m_action;
0287 }
0288 
0289 void MyMoneySplit::setAction(const QString& action)
0290 {
0291     Q_D(MyMoneySplit);
0292     d->m_action = action;
0293 }
0294 
0295 bool MyMoneySplit::isAmortizationSplit() const
0296 {
0297     Q_D(const MyMoneySplit);
0298     return d->m_action == actionName(Split::Action::Amortization);
0299 }
0300 
0301 bool MyMoneySplit::isInterestSplit() const
0302 {
0303     Q_D(const MyMoneySplit);
0304     return d->m_action == actionName(Split::Action::Interest);
0305 }
0306 
0307 QString MyMoneySplit::number() const
0308 {
0309     Q_D(const MyMoneySplit);
0310     return d->m_number;
0311 }
0312 
0313 void MyMoneySplit::setNumber(const QString& number)
0314 {
0315     Q_D(MyMoneySplit);
0316     d->m_number = number;
0317 }
0318 
0319 bool MyMoneySplit::isAutoCalc() const
0320 {
0321     Q_D(const MyMoneySplit);
0322     return (d->m_shares == MyMoneyMoney::autoCalc) || (d->m_value == MyMoneyMoney::autoCalc);
0323 }
0324 
0325 QString MyMoneySplit::bankID() const
0326 {
0327     Q_D(const MyMoneySplit);
0328     return d->m_bankID;
0329 }
0330 
0331 void MyMoneySplit::setBankID(const QString& bankID)
0332 {
0333     Q_D(MyMoneySplit);
0334     d->m_bankID = bankID;
0335 }
0336 
0337 QString MyMoneySplit::transactionId() const
0338 {
0339     Q_D(const MyMoneySplit);
0340     return d->m_transactionId;
0341 }
0342 
0343 void MyMoneySplit::setTransactionId(const QString& id)
0344 {
0345     Q_D(MyMoneySplit);
0346     d->m_transactionId = id;
0347 }
0348 
0349 
0350 MyMoneyMoney MyMoneySplit::value() const
0351 {
0352     Q_D(const MyMoneySplit);
0353     return d->m_value;
0354 }
0355 
0356 MyMoneyMoney MyMoneySplit::value(const QString& transactionCurrencyId, const QString& splitCurrencyId) const
0357 {
0358     Q_D(const MyMoneySplit);
0359     return (transactionCurrencyId == splitCurrencyId) ? d->m_value : d->m_shares;
0360 }
0361 
0362 void MyMoneySplit::setPrice(const MyMoneyMoney& price)
0363 {
0364     Q_D(MyMoneySplit);
0365     d->m_price = price;
0366 }
0367 
0368 MyMoneyMoney MyMoneySplit::price() const
0369 {
0370     Q_D(const MyMoneySplit);
0371     if (!d->m_price.isZero())
0372         return d->m_price;
0373     if (!d->m_value.isZero() && !d->m_shares.isZero())
0374         return d->m_value / d->m_shares;
0375     return MyMoneyMoney::ONE;
0376 }
0377 
0378 bool MyMoneySplit::isMatched() const
0379 {
0380     Q_D(const MyMoneySplit);
0381     return d->m_isMatched;
0382 }
0383 
0384 void MyMoneySplit::addMatch(const MyMoneyTransaction& _t)
0385 {
0386     Q_D(MyMoneySplit);
0387     //  now we allow matching of two manual transactions
0388     d->m_matchedTransaction = _t;
0389     d->m_matchedTransaction.clearId();
0390     d->m_isMatched = true;
0391 }
0392 
0393 void MyMoneySplit::removeMatch()
0394 {
0395     Q_D(MyMoneySplit);
0396     d->m_matchedTransaction = MyMoneyTransaction();
0397     d->m_isMatched = false;
0398 }
0399 
0400 MyMoneyTransaction MyMoneySplit::matchedTransaction() const
0401 {
0402     Q_D(const MyMoneySplit);
0403     if (d->m_isMatched)
0404         return d->m_matchedTransaction;
0405 
0406     return MyMoneyTransaction();
0407 }
0408 
0409 bool MyMoneySplit::replaceId(const QString& newId, const QString& oldId)
0410 {
0411     auto changed = false;
0412     Q_D(MyMoneySplit);
0413 
0414     if (d->m_payee == oldId) {
0415         d->m_payee = newId;
0416         changed = true;
0417     } else if (d->m_account == oldId) {
0418         d->m_account = newId;
0419         changed = true;
0420     } else if (d->m_costCenter == oldId) {
0421         d->m_costCenter = newId;
0422         changed = true;
0423     }
0424 
0425     if (isMatched()) {
0426         MyMoneyTransaction t = matchedTransaction();
0427         if (t.replaceId(newId, oldId)) {
0428             removeMatch();
0429             addMatch(t);
0430             changed = true;
0431         }
0432     }
0433 
0434     return changed;
0435 }
0436 
0437 QHash<Split::Action, QString> actionNamesLUT()
0438 {
0439     static const QHash<Split::Action, QString> actionNames {
0440         {Split::Action::Check,            QStringLiteral("Check")},
0441         {Split::Action::Deposit,          QStringLiteral("Deposit")},
0442         {Split::Action::Transfer,         QStringLiteral("Transfer")},
0443         {Split::Action::Withdrawal,       QStringLiteral("Withdrawal")},
0444         {Split::Action::ATM,              QStringLiteral("ATM")},
0445         {Split::Action::Amortization,     QStringLiteral("Amortization")},
0446         {Split::Action::Interest,         QStringLiteral("Interest")},
0447         {Split::Action::BuyShares,        QStringLiteral("Buy")},
0448         {Split::Action::Dividend,         QStringLiteral("Dividend")},
0449         {Split::Action::ReinvestDividend, QStringLiteral("Reinvest")},
0450         {Split::Action::Yield,            QStringLiteral("Yield")},
0451         {Split::Action::AddShares,        QStringLiteral("Add")},
0452         {Split::Action::SplitShares,      QStringLiteral("Split")},
0453         {Split::Action::InterestIncome,   QStringLiteral("IntIncome")},
0454     };
0455     return actionNames;
0456 }
0457 
0458 QString MyMoneySplit::actionName(Split::Action action)
0459 {
0460     return actionNamesLUT().value(action);
0461 }
0462 
0463 Split::Action MyMoneySplit::actionStringToAction(const QString &text) const
0464 {
0465     return actionNamesLUT().key(text, Split::Action::Unknown);
0466 }