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