1 /*
2  * Copyright 2002-2017  Thomas Baumgart <tbaumgart@kde.org>
3  * Copyright 2004       Kevin Tambascio <ktambascio@users.sourceforge.net>
4  * Copyright 2005-2006  Ace Jones <acejones@users.sourceforge.net>
5  * Copyright 2017-2018  Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "mymoneysplit.h"
22 #include "mymoneysplit_p.h"
23 
24 // ----------------------------------------------------------------------------
25 // QT Includes
26 
27 // ----------------------------------------------------------------------------
28 // KDE Includes
29 
30 // ----------------------------------------------------------------------------
31 // Project Includes
32 
33 #include "mymoneyutils.h"
34 #include "mymoneytransaction.h"
35 #include "mymoneyexception.h"
36 
MyMoneySplit()37 MyMoneySplit::MyMoneySplit() :
38   MyMoneyObject(*new MyMoneySplitPrivate)
39 {
40 }
41 
MyMoneySplit(const QString & id)42 MyMoneySplit::MyMoneySplit(const QString &id) :
43     MyMoneyObject(*new MyMoneySplitPrivate, id)
44 {
45   Q_D(MyMoneySplit);
46   d->m_reconcileFlag = eMyMoney::Split::State::NotReconciled;
47 }
48 
MyMoneySplit(const MyMoneySplit & other)49 MyMoneySplit::MyMoneySplit(const MyMoneySplit& other) :
50   MyMoneyObject(*new MyMoneySplitPrivate(*other.d_func()), other.id()),
51   MyMoneyKeyValueContainer(other)
52 {
53 }
54 
MyMoneySplit(const QString & id,const MyMoneySplit & other)55 MyMoneySplit::MyMoneySplit(const QString& id, const MyMoneySplit& other) :
56   MyMoneyObject(*new MyMoneySplitPrivate(*other.d_func()), id),
57   MyMoneyKeyValueContainer(other)
58 {
59 }
60 
~MyMoneySplit()61 MyMoneySplit::~MyMoneySplit()
62 {
63 }
64 
operator ==(const MyMoneySplit & right) const65 bool MyMoneySplit::operator == (const MyMoneySplit& right) const
66 {
67   Q_D(const MyMoneySplit);
68   auto d2 = static_cast<const MyMoneySplitPrivate *>(right.d_func());
69   return MyMoneyObject::operator==(right) &&
70          MyMoneyKeyValueContainer::operator==(right) &&
71          d->m_account == d2->m_account &&
72          d->m_costCenter == d2->m_costCenter &&
73          d->m_payee == d2->m_payee &&
74          d->m_tagList == d2->m_tagList &&
75          d->m_memo == d2->m_memo &&
76          d->m_action == d2->m_action &&
77          d->m_reconcileDate == d2->m_reconcileDate &&
78          d->m_reconcileFlag == d2->m_reconcileFlag &&
79          ((d->m_number.length() == 0 && d2->m_number.length() == 0) || d->m_number == d2->m_number) &&
80          d->m_shares == d2->m_shares &&
81          d->m_value == d2->m_value &&
82          d->m_price == d2->m_price &&
83          d->m_transactionId == d2->m_transactionId;
84 }
85 
operator -() const86 MyMoneySplit MyMoneySplit::operator-() const
87 {
88     MyMoneySplit rc(*this);
89   rc.d_func()->m_shares = -rc.d_func()->m_shares;
90   rc.d_func()->m_value = -rc.d_func()->m_value;
91   return rc;
92 }
93 
accountId() const94 QString MyMoneySplit::accountId() const
95 {
96   Q_D(const MyMoneySplit);
97   return d->m_account;
98 }
99 
setAccountId(const QString & account)100 void MyMoneySplit::setAccountId(const QString& account)
101 {
102   Q_D(MyMoneySplit);
103   d->m_account = account;
104 }
105 
costCenterId() const106 QString MyMoneySplit::costCenterId() const
107 {
108   Q_D(const MyMoneySplit);
109   return d->m_costCenter;
110 }
111 
setCostCenterId(const QString & costCenter)112 void MyMoneySplit::setCostCenterId(const QString& costCenter)
113 {
114   Q_D(MyMoneySplit);
115   d->m_costCenter = costCenter;
116 }
117 
memo() const118 QString MyMoneySplit::memo() const
119 {
120   Q_D(const MyMoneySplit);
121   return d->m_memo;
122 }
123 
setMemo(const QString & memo)124 void MyMoneySplit::setMemo(const QString& memo)
125 {
126   Q_D(MyMoneySplit);
127   d->m_memo = memo;
128 }
129 
reconcileFlag() const130 eMyMoney::Split::State MyMoneySplit::reconcileFlag() const
131 {
132   Q_D(const MyMoneySplit);
133   return d->m_reconcileFlag;
134 }
135 
reconcileDate() const136 QDate MyMoneySplit::reconcileDate() const
137 {
138   Q_D(const MyMoneySplit);
139   return d->m_reconcileDate;
140 }
141 
setReconcileDate(const QDate & date)142 void MyMoneySplit::setReconcileDate(const QDate& date)
143 {
144   Q_D(MyMoneySplit);
145   d->m_reconcileDate = date;
146 }
147 
setReconcileFlag(const eMyMoney::Split::State flag)148 void MyMoneySplit::setReconcileFlag(const eMyMoney::Split::State flag)
149 {
150   Q_D(MyMoneySplit);
151   d->m_reconcileFlag = flag;
152 }
153 
shares() const154 MyMoneyMoney MyMoneySplit::shares() const
155 {
156   Q_D(const MyMoneySplit);
157   return d->m_shares;
158 }
159 
setShares(const MyMoneyMoney & shares)160 void MyMoneySplit::setShares(const MyMoneyMoney& shares)
161 {
162   Q_D(MyMoneySplit);
163   d->m_shares = shares;
164 }
165 
negateShares()166 void MyMoneySplit::negateShares()
167 {
168   Q_D(MyMoneySplit);
169   d->m_shares = -d->m_shares;
170 }
171 
value(const QString & key) const172 QString MyMoneySplit::value(const QString& key) const
173 {
174   return MyMoneyKeyValueContainer::value(key);
175 }
176 
setValue(const QString & key,const QString & value)177 void MyMoneySplit::setValue(const QString& key, const QString& value)
178 {
179   MyMoneyKeyValueContainer::setValue(key, value);
180 }
181 
setValue(const MyMoneyMoney & value)182 void MyMoneySplit::setValue(const MyMoneyMoney& value)
183 {
184   Q_D(MyMoneySplit);
185   d->m_value = value;
186 }
187 
setValue(const MyMoneyMoney & value,const QString & transactionCurrencyId,const QString & splitCurrencyId)188 void MyMoneySplit::setValue(const MyMoneyMoney& value, const QString& transactionCurrencyId, const QString& splitCurrencyId)
189 {
190   if (transactionCurrencyId == splitCurrencyId)
191     setValue(value);
192   else
193     setShares(value);
194 }
195 
negateValue()196 void MyMoneySplit::negateValue()
197 {
198     Q_D(MyMoneySplit);
199     d->m_value = -d->m_value;
200 }
201 
payeeId() const202 QString MyMoneySplit::payeeId() const
203 {
204   Q_D(const MyMoneySplit);
205   return d->m_payee;
206 }
207 
setPayeeId(const QString & payee)208 void MyMoneySplit::setPayeeId(const QString& payee)
209 {
210   Q_D(MyMoneySplit);
211   d->m_payee = payee;
212 }
213 
tagIdList() const214 QList<QString> MyMoneySplit::tagIdList() const
215 {
216   Q_D(const MyMoneySplit);
217   return d->m_tagList;
218 }
219 
setTagIdList(const QList<QString> & tagList)220 void MyMoneySplit::setTagIdList(const QList<QString>& tagList)
221 {
222   Q_D(MyMoneySplit);
223   d->m_tagList = tagList;
224 }
225 
setAction(eMyMoney::Split::InvestmentTransactionType type)226 void MyMoneySplit::setAction(eMyMoney::Split::InvestmentTransactionType type)
227 {
228   switch (type) {
229     case eMyMoney::Split::InvestmentTransactionType::BuyShares:
230     case eMyMoney::Split::InvestmentTransactionType::SellShares:
231       setAction(actionName(Split::Action::BuyShares));
232       break;
233     case eMyMoney::Split::InvestmentTransactionType::Dividend:
234       setAction(actionName(Split::Action::Dividend));
235       break;
236     case eMyMoney::Split::InvestmentTransactionType::Yield:
237       setAction(actionName(Split::Action::Yield));
238       break;
239     case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend:
240       setAction(actionName(Split::Action::ReinvestDividend));
241       break;
242     case eMyMoney::Split::InvestmentTransactionType::AddShares:
243     case eMyMoney::Split::InvestmentTransactionType::RemoveShares:
244       setAction(actionName(Split::Action::AddShares));
245       break;
246     case eMyMoney::Split::InvestmentTransactionType::SplitShares:
247       setAction(actionName(Split::Action::SplitShares));
248       break;
249     case eMyMoney::Split::InvestmentTransactionType::InterestIncome:
250       setAction(actionName(Split::Action::InterestIncome));
251       break;
252     case eMyMoney::Split::InvestmentTransactionType::UnknownTransactionType:
253       break;
254   }
255 }
256 
action() const257 QString MyMoneySplit::action() const
258 {
259   Q_D(const MyMoneySplit);
260   return d->m_action;
261 }
262 
setAction(const QString & action)263 void MyMoneySplit::setAction(const QString& action)
264 {
265   Q_D(MyMoneySplit);
266   d->m_action = action;
267 }
268 
isAmortizationSplit() const269 bool MyMoneySplit::isAmortizationSplit() const
270 {
271   Q_D(const MyMoneySplit);
272   return d->m_action == actionName(Split::Action::Amortization);
273 }
274 
isInterestSplit() const275 bool MyMoneySplit::isInterestSplit() const
276 {
277   Q_D(const MyMoneySplit);
278   return d->m_action == actionName(Split::Action::Interest);
279 }
280 
number() const281 QString MyMoneySplit::number() const
282 {
283   Q_D(const MyMoneySplit);
284   return d->m_number;
285 }
286 
setNumber(const QString & number)287 void MyMoneySplit::setNumber(const QString& number)
288 {
289   Q_D(MyMoneySplit);
290   d->m_number = number;
291 }
292 
isAutoCalc() const293 bool MyMoneySplit::isAutoCalc() const
294 {
295   Q_D(const MyMoneySplit);
296   return (d->m_shares == MyMoneyMoney::autoCalc) || (d->m_value == MyMoneyMoney::autoCalc);
297 }
298 
bankID() const299 QString MyMoneySplit::bankID() const
300 {
301   Q_D(const MyMoneySplit);
302   return d->m_bankID;
303 }
304 
setBankID(const QString & bankID)305 void MyMoneySplit::setBankID(const QString& bankID)
306 {
307   Q_D(MyMoneySplit);
308   d->m_bankID = bankID;
309 }
310 
transactionId() const311 QString MyMoneySplit::transactionId() const
312 {
313   Q_D(const MyMoneySplit);
314   return d->m_transactionId;
315 }
316 
setTransactionId(const QString & id)317 void MyMoneySplit::setTransactionId(const QString& id)
318 {
319   Q_D(MyMoneySplit);
320   d->m_transactionId = id;
321 }
322 
323 
value() const324 MyMoneyMoney MyMoneySplit::value() const
325 {
326   Q_D(const MyMoneySplit);
327   return d->m_value;
328 }
329 
value(const QString & transactionCurrencyId,const QString & splitCurrencyId) const330 MyMoneyMoney MyMoneySplit::value(const QString& transactionCurrencyId, const QString& splitCurrencyId) const
331 {
332   Q_D(const MyMoneySplit);
333   return (transactionCurrencyId == splitCurrencyId) ? d->m_value : d->m_shares;
334 }
335 
actualPrice() const336 MyMoneyMoney MyMoneySplit::actualPrice() const
337 {
338   Q_D(const MyMoneySplit);
339   return d->m_price;
340 }
341 
setPrice(const MyMoneyMoney & price)342 void MyMoneySplit::setPrice(const MyMoneyMoney& price)
343 {
344   Q_D(MyMoneySplit);
345   d->m_price = price;
346 }
347 
price() const348 MyMoneyMoney MyMoneySplit::price() const
349 {
350   Q_D(const MyMoneySplit);
351   if (!d->m_price.isZero())
352     return d->m_price;
353   if (!d->m_value.isZero() && !d->m_shares.isZero())
354     return d->m_value / d->m_shares;
355   return MyMoneyMoney::ONE;
356 }
357 
hasReferenceTo(const QString & id) const358 bool MyMoneySplit::hasReferenceTo(const QString& id) const
359 {
360   Q_D(const MyMoneySplit);
361   auto rc = false;
362   if (isMatched()) {
363     rc = matchedTransaction().hasReferenceTo(id);
364   }
365   for (int i = 0; i < d->m_tagList.size(); i++)
366     if (id == d->m_tagList[i])
367       return true;
368   return rc || (id == d->m_account) || (id == d->m_payee) || (id == d->m_costCenter);
369 }
370 
isMatched() const371 bool MyMoneySplit::isMatched() const
372 {
373   Q_D(const MyMoneySplit);
374   return d->m_isMatched;
375 }
376 
addMatch(const MyMoneyTransaction & _t)377 void MyMoneySplit::addMatch(const MyMoneyTransaction& _t)
378 {
379   Q_D(MyMoneySplit);
380   //  now we allow matching of two manual transactions
381   d->m_matchedTransaction = _t;
382   d->m_matchedTransaction.clearId();
383   d->m_isMatched = true;
384 }
385 
removeMatch()386 void MyMoneySplit::removeMatch()
387 {
388   Q_D(MyMoneySplit);
389   d->m_matchedTransaction = MyMoneyTransaction();
390   d->m_isMatched = false;
391 }
392 
matchedTransaction() const393 MyMoneyTransaction MyMoneySplit::matchedTransaction() const
394 {
395   Q_D(const MyMoneySplit);
396   if (d->m_isMatched)
397     return d->m_matchedTransaction;
398 
399   return MyMoneyTransaction();
400 }
401 
replaceId(const QString & newId,const QString & oldId)402 bool MyMoneySplit::replaceId(const QString& newId, const QString& oldId)
403 {
404   auto changed = false;
405   Q_D(MyMoneySplit);
406 
407   if (d->m_payee == oldId) {
408     d->m_payee = newId;
409     changed = true;
410   } else if (d->m_account == oldId) {
411     d->m_account = newId;
412     changed = true;
413   } else if (d->m_costCenter == oldId) {
414     d->m_costCenter = newId;
415     changed = true;
416   }
417 
418   if (isMatched()) {
419     MyMoneyTransaction t = matchedTransaction();
420     if (t.replaceId(newId, oldId)) {
421       removeMatch();
422       addMatch(t);
423       changed = true;
424     }
425   }
426 
427   return changed;
428 }
429 
actionName(Split::Action action)430 QString MyMoneySplit::actionName(Split::Action action)
431 {
432   static const QHash<Split::Action, QString> actionNames {
433     {Split::Action::Check,            QStringLiteral("Check")},
434     {Split::Action::Deposit,          QStringLiteral("Deposit")},
435     {Split::Action::Transfer,         QStringLiteral("Transfer")},
436     {Split::Action::Withdrawal,       QStringLiteral("Withdrawal")},
437     {Split::Action::ATM,              QStringLiteral("ATM")},
438     {Split::Action::Amortization,     QStringLiteral("Amortization")},
439     {Split::Action::Interest,         QStringLiteral("Interest")},
440     {Split::Action::BuyShares,        QStringLiteral("Buy")},
441     {Split::Action::Dividend,         QStringLiteral("Dividend")},
442     {Split::Action::ReinvestDividend, QStringLiteral("Reinvest")},
443     {Split::Action::Yield,            QStringLiteral("Yield")},
444     {Split::Action::AddShares,        QStringLiteral("Add")},
445     {Split::Action::SplitShares,      QStringLiteral("Split")},
446     {Split::Action::InterestIncome,   QStringLiteral("IntIncome")},
447   };
448   return actionNames[action];
449 }
450