File indexing completed on 2024-05-12 16:42:41

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