Changeset View
Changeset View
Standalone View
Standalone View
kmymoney/reports/querytable.cpp
Show First 20 Lines • Show All 369 Lines • ▼ Show 20 Line(s) | 369 | if (qc & MyMoneyReport::eQCmemo) | |||
---|---|---|---|---|---|
370 | m_columns += ",memo"; | 370 | m_columns += ",memo"; | ||
371 | if (qc & MyMoneyReport::eQCaction) | 371 | if (qc & MyMoneyReport::eQCaction) | ||
372 | m_columns += ",action"; | 372 | m_columns += ",action"; | ||
373 | if (qc & MyMoneyReport::eQCshares) | 373 | if (qc & MyMoneyReport::eQCshares) | ||
374 | m_columns += ",shares"; | 374 | m_columns += ",shares"; | ||
375 | if (qc & MyMoneyReport::eQCprice) | 375 | if (qc & MyMoneyReport::eQCprice) | ||
376 | m_columns += ",price"; | 376 | m_columns += ",price"; | ||
377 | if (qc & MyMoneyReport::eQCperformance) { | 377 | if (qc & MyMoneyReport::eQCperformance) { | ||
378 | m_columns += ",startingbal,buys,sells,reinvestincome,cashincome,return,returninvestment,endingbal"; | 378 | switch (m_config.investmentSum()) { | ||
379 | m_subtotal = "startingbal,buys,sells,reinvestincome,cashincome,return,returninvestment,endingbal"; | 379 | case MyMoneyReport::eSumOwnedAndSold: | ||
380 | m_columns += ",buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; | ||||
381 | m_subtotal = "buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; | ||||
382 | break; | ||||
383 | case MyMoneyReport::eSumOwned: | ||||
384 | m_columns += ",buys,reinvestincome,marketvalue,return,returninvestment"; | ||||
385 | m_subtotal = "buys,reinvestincome,marketvalue,return,returninvestment"; | ||||
386 | break; | ||||
387 | case MyMoneyReport::eSumSold: | ||||
388 | m_columns += ",buys,sells,cashincome,return,returninvestment"; | ||||
389 | m_subtotal = "buys,sells,cashincome,return,returninvestment"; | ||||
390 | break; | ||||
391 | case MyMoneyReport::eSumPeriod: | ||||
392 | default: | ||||
393 | m_columns += ",startingbal,buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; | ||||
394 | m_subtotal = "startingbal,buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; | ||||
395 | break; | ||||
396 | } | ||||
380 | } | 397 | } | ||
381 | if (qc & MyMoneyReport::eQCcapitalgain) { | 398 | if (qc & MyMoneyReport::eQCcapitalgain) { | ||
399 | switch (m_config.investmentSum()) { | ||||
400 | case MyMoneyReport::eSumOwned: | ||||
401 | m_columns += ",shares,buyprice,lastprice,buys,marketvalue,percentagegain,capitalgain"; | ||||
402 | m_subtotal = "buys,marketvalue,percentagegain,capitalgain"; | ||||
403 | break; | ||||
404 | case MyMoneyReport::eSumSold: | ||||
405 | default: | ||||
382 | m_columns += ",buys,sells,capitalgain"; | 406 | m_columns += ",buys,sells,capitalgain"; | ||
383 | m_subtotal = "buys,sells,capitalgain"; | 407 | m_subtotal = "buys,sells,capitalgain"; | ||
384 | if (m_config.isShowingSTLTCapitalGains()) { | 408 | if (m_config.isShowingSTLTCapitalGains()) { | ||
385 | m_columns += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; | 409 | m_columns += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; | ||
386 | m_subtotal += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; | 410 | m_subtotal += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; | ||
387 | } | 411 | } | ||
412 | break; | ||||
413 | } | ||||
388 | } | 414 | } | ||
389 | if (qc & MyMoneyReport::eQCloan) { | 415 | if (qc & MyMoneyReport::eQCloan) { | ||
390 | m_columns += ",payment,interest,fees"; | 416 | m_columns += ",payment,interest,fees"; | ||
391 | m_postcolumns = "balance"; | 417 | m_postcolumns = "balance"; | ||
392 | } | 418 | } | ||
393 | if (qc & MyMoneyReport::eQCbalance) | 419 | if (qc & MyMoneyReport::eQCbalance) | ||
394 | m_postcolumns = "balance"; | 420 | m_postcolumns = "balance"; | ||
395 | 421 | | |||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Line(s) | 503 | while(upperGrp != (*currencyGrp)[i].end()) { | |||
480 | // (*lowerGrp) = MyMoneyMoney(); | 506 | // (*lowerGrp) = MyMoneyMoney(); | ||
481 | ++upperGrp; | 507 | ++upperGrp; | ||
482 | ++lowerGrp; | 508 | ++lowerGrp; | ||
483 | } | 509 | } | ||
484 | 510 | | |||
485 | // custom total values calculations | 511 | // custom total values calculations | ||
486 | foreach (auto subtotal, subtotals) { | 512 | foreach (auto subtotal, subtotals) { | ||
487 | if (subtotal == "returninvestment") | 513 | if (subtotal == "returninvestment") | ||
488 | totalsRow[subtotal] = helperROI((*currencyGrp).at(i + 1).value("buys"), (*currencyGrp).at(i + 1).value("sells"), | 514 | totalsRow[subtotal] = helperROI((*currencyGrp).at(i + 1).value("buys") - (*currencyGrp).at(i + 1).value("reinvestincome"), (*currencyGrp).at(i + 1).value("sells"), | ||
489 | (*currencyGrp).at(i + 1).value("startingbal"), (*currencyGrp).at(i + 1).value("endingbal"), | 515 | (*currencyGrp).at(i + 1).value("startingbal"), (*currencyGrp).at(i + 1).value("endingbal") + (*currencyGrp).at(i + 1).value("marketvalue"), | ||
490 | (*currencyGrp).at(i + 1).value("cashincome")).toString(); | 516 | (*currencyGrp).at(i + 1).value("cashincome")).toString(); | ||
517 | else if (subtotal == "percentagegain") | ||||
518 | totalsRow[subtotal] = (((*currencyGrp).at(i + 1).value("buys") + (*currencyGrp).at(i + 1).value("marketvalue")) / (*currencyGrp).at(i + 1).value("buys").abs()).toString(); | ||||
491 | else if (subtotal == "price") | 519 | else if (subtotal == "price") | ||
492 | totalsRow[subtotal] = MyMoneyMoney((*currencyGrp).at(i + 1).value("price") / (*currencyGrp).at(i + 1).value("rows_count")).toString(); | 520 | totalsRow[subtotal] = MyMoneyMoney((*currencyGrp).at(i + 1).value("price") / (*currencyGrp).at(i + 1).value("rows_count")).toString(); | ||
493 | } | 521 | } | ||
494 | 522 | | |||
495 | // total values that aren't calculated here, but are taken untouched from external source, e.g. constructPerformanceRow | 523 | // total values that aren't calculated here, but are taken untouched from external source, e.g. constructPerformanceRow | ||
496 | if (!stashedTotalRows.isEmpty()) { | 524 | if (!stashedTotalRows.isEmpty()) { | ||
497 | for (int j = 0; j < stashedTotalRows.count(); ++j) { | 525 | for (int j = 0; j < stashedTotalRows.count(); ++j) { | ||
498 | if (stashedTotalRows.at(j).value("currency") != currencyID) | 526 | if (stashedTotalRows.at(j).value("currency") != currencyID) | ||
Show All 39 Lines | 564 | while (currencyGrp != totalCurrency.end()) { | |||
538 | QMap<QString, MyMoneyMoney>::const_iterator grandTotalGrp = (*currencyGrp)[0].constBegin(); | 566 | QMap<QString, MyMoneyMoney>::const_iterator grandTotalGrp = (*currencyGrp)[0].constBegin(); | ||
539 | while(grandTotalGrp != (*currencyGrp)[0].constEnd()) { | 567 | while(grandTotalGrp != (*currencyGrp)[0].constEnd()) { | ||
540 | totalsRow[grandTotalGrp.key()] = grandTotalGrp.value().toString(); | 568 | totalsRow[grandTotalGrp.key()] = grandTotalGrp.value().toString(); | ||
541 | ++grandTotalGrp; | 569 | ++grandTotalGrp; | ||
542 | } | 570 | } | ||
543 | 571 | | |||
544 | foreach (auto subtotal, subtotals) { | 572 | foreach (auto subtotal, subtotals) { | ||
545 | if (subtotal == "returninvestment") | 573 | if (subtotal == "returninvestment") | ||
546 | totalsRow[subtotal] = helperROI((*currencyGrp).at(0).value("buys"), (*currencyGrp).at(0).value("sells"), | 574 | totalsRow[subtotal] = helperROI((*currencyGrp).at(0).value("buys") - (*currencyGrp).at(0).value("reinvestincome"), (*currencyGrp).at(0).value("sells"), | ||
547 | (*currencyGrp).at(0).value("startingbal"), (*currencyGrp).at(0).value("endingbal"), | 575 | (*currencyGrp).at(0).value("startingbal"), (*currencyGrp).at(0).value("endingbal") + (*currencyGrp).at(0).value("marketvalue"), | ||
548 | (*currencyGrp).at(0).value("cashincome")).toString(); | 576 | (*currencyGrp).at(0).value("cashincome")).toString(); | ||
577 | else if (subtotal == "percentagegain") | ||||
578 | totalsRow[subtotal] = (((*currencyGrp).at(0).value("buys") + (*currencyGrp).at(0).value("marketvalue")) / (*currencyGrp).at(0).value("buys").abs()).toString(); | ||||
549 | else if (subtotal == "price") | 579 | else if (subtotal == "price") | ||
550 | totalsRow[subtotal] = MyMoneyMoney((*currencyGrp).at(0).value("price") / (*currencyGrp).at(0).value("rows_count")).toString(); | 580 | totalsRow[subtotal] = MyMoneyMoney((*currencyGrp).at(0).value("price") / (*currencyGrp).at(0).value("rows_count")).toString(); | ||
551 | } | 581 | } | ||
552 | 582 | | |||
553 | if (!stashedTotalRows.isEmpty()) { | 583 | if (!stashedTotalRows.isEmpty()) { | ||
554 | for (int j = 0; j < stashedTotalRows.count(); ++j) { | 584 | for (int j = 0; j < stashedTotalRows.count(); ++j) { | ||
555 | foreach (auto subtotal, subtotals) { | 585 | foreach (auto subtotal, subtotals) { | ||
556 | if (subtotal == "return") | 586 | if (subtotal == "return") | ||
▲ Show 20 Lines • Show All 627 Lines • ▼ Show 20 Line(s) | 1213 | #else | |||
1184 | annualReturn = MyMoneyMoney(std::isnan(irr) ? 0 : irr, 10000); | 1214 | annualReturn = MyMoneyMoney(std::isnan(irr) ? 0 : irr, 10000); | ||
1185 | #endif | 1215 | #endif | ||
1186 | } catch (QString e) { | 1216 | } catch (QString e) { | ||
1187 | qDebug() << e; | 1217 | qDebug() << e; | ||
1188 | } | 1218 | } | ||
1189 | return annualReturn; | 1219 | return annualReturn; | ||
1190 | } | 1220 | } | ||
1191 | 1221 | | |||
1192 | void QueryTable::constructPerformanceRow(const ReportAccount& account, TableRow& result, CashFlowList &all) const | 1222 | void QueryTable::sumInvestmentValues(const ReportAccount& account, QList<CashFlowList>& cfList, QList<MyMoneyMoney>& shList) const | ||
1193 | { | 1223 | { | ||
1194 | MyMoneyFile* file = MyMoneyFile::instance(); | 1224 | for (int i = InvestmentValue::Buys; i < InvestmentValue::End; ++i) | ||
1195 | MyMoneySecurity security; | 1225 | cfList.append(CashFlowList()); | ||
1196 | 1226 | for (int i = InvestmentValue::Buys; i <= InvestmentValue::BuysOfOwned; ++i) | |||
1197 | //get fraction depending on type of account | 1227 | shList.append(MyMoneyMoney()); | ||
1198 | int fraction = account.currency().smallestAccountFraction(); | | |||
1199 | | ||||
1200 | // | | |||
1201 | // Calculate performance | | |||
1202 | // | | |||
1203 | | ||||
1204 | // The following columns are created: | | |||
1205 | // Account, Value on <Opening>, Buys, Sells, Income, Value on <Closing>, Return% | | |||
1206 | | ||||
1207 | MyMoneyReport report = m_config; | | |||
1208 | QDate startingDate; | | |||
1209 | QDate endingDate; | | |||
1210 | MyMoneyMoney price; | | |||
1211 | report.validDateRange(startingDate, endingDate); | | |||
1212 | startingDate = startingDate.addDays(-1); | | |||
1213 | | ||||
1214 | //calculate starting balance | | |||
1215 | if (m_config.isConvertCurrency()) { | | |||
1216 | price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate); | | |||
1217 | } else { | | |||
1218 | price = account.deepCurrencyPrice(startingDate); | | |||
1219 | } | | |||
1220 | | ||||
1221 | //work around if there is no price for the starting balance | | |||
1222 | if (!(file->balance(account.id(), startingDate)).isZero() | | |||
1223 | && account.deepCurrencyPrice(startingDate) == MyMoneyMoney::ONE) { | | |||
1224 | MyMoneyTransactionFilter filter; | | |||
1225 | //get the transactions for the time before the report | | |||
1226 | filter.setDateFilter(QDate(), startingDate); | | |||
1227 | filter.addAccount(account.id()); | | |||
1228 | filter.setReportAllSplits(true); | | |||
1229 | | ||||
1230 | QList<MyMoneyTransaction> startTransactions = file->transactionList(filter); | | |||
1231 | if (startTransactions.size() > 0) { | | |||
1232 | //get the last transaction | | |||
1233 | MyMoneyTransaction startTrans = startTransactions.back(); | | |||
1234 | MyMoneySplit s = startTrans.splitByAccount(account.id()); | | |||
1235 | //get the price from the split of that account | | |||
1236 | price = s.price(); | | |||
1237 | if (m_config.isConvertCurrency()) | | |||
1238 | price = price * account.baseCurrencyPrice(startingDate); | | |||
1239 | } | | |||
1240 | } | | |||
1241 | if (m_config.isConvertCurrency()) { | | |||
1242 | price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate); | | |||
1243 | } else { | | |||
1244 | price = account.deepCurrencyPrice(startingDate); | | |||
1245 | } | | |||
1246 | | ||||
1247 | MyMoneyMoney startingBal = file->balance(account.id(), startingDate) * price; | | |||
1248 | | ||||
1249 | //convert to lowest fraction | | |||
1250 | startingBal = startingBal.convert(fraction); | | |||
1251 | | ||||
1252 | //calculate ending balance | | |||
1253 | if (m_config.isConvertCurrency()) { | | |||
1254 | price = account.deepCurrencyPrice(endingDate) * account.baseCurrencyPrice(endingDate); | | |||
1255 | } else { | | |||
1256 | price = account.deepCurrencyPrice(endingDate); | | |||
1257 | } | | |||
1258 | MyMoneyMoney endingBal = file->balance((account).id(), endingDate) * price; | | |||
1259 | | ||||
1260 | //convert to lowest fraction | | |||
1261 | endingBal = endingBal.convert(fraction); | | |||
1262 | | ||||
1263 | CashFlowList buys; | | |||
1264 | CashFlowList sells; | | |||
1265 | CashFlowList reinvestincome; | | |||
1266 | CashFlowList cashincome; | | |||
1267 | | ||||
1268 | report.setReportAllSplits(false); | | |||
1269 | report.setConsiderCategory(true); | | |||
1270 | report.clearAccountFilter(); | | |||
1271 | report.addAccount(account.id()); | | |||
1272 | QList<MyMoneyTransaction> transactions = file->transactionList(report); | | |||
1273 | QList<MyMoneyTransaction>::const_iterator it_transaction = transactions.constBegin(); | | |||
1274 | while (it_transaction != transactions.constEnd()) { | | |||
1275 | // s is the split for the stock account | | |||
1276 | MyMoneySplit s = (*it_transaction).splitByAccount(account.id()); | | |||
1277 | | ||||
1278 | MyMoneySplit assetAccountSplit; | | |||
1279 | QList<MyMoneySplit> feeSplits; | | |||
1280 | QList<MyMoneySplit> interestSplits; | | |||
1281 | MyMoneySecurity currency; | | |||
1282 | MyMoneySplit::investTransactionTypeE transactionType; | | |||
1283 | KMyMoneyUtils::dissectTransaction((*it_transaction), s, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); | | |||
1284 | | ||||
1285 | //get price for the day of the transaction if we have to calculate base currency | | |||
1286 | //we are using the value of the split which is in deep currency | | |||
1287 | if (m_config.isConvertCurrency()) { | | |||
1288 | price = account.baseCurrencyPrice((*it_transaction).postDate()); //we only need base currency because the value is in deep currency | | |||
1289 | } else { | | |||
1290 | price = MyMoneyMoney::ONE; | | |||
1291 | } | | |||
1292 | | ||||
1293 | MyMoneyMoney value = assetAccountSplit.value() * price; | | |||
1294 | 1228 | | |||
1295 | if (transactionType == MyMoneySplit::BuyShares) | | |||
1296 | buys += CashFlowListItem((*it_transaction).postDate(), value); | | |||
1297 | else if (transactionType == MyMoneySplit::SellShares) | | |||
1298 | sells += CashFlowListItem((*it_transaction).postDate(), value); | | |||
1299 | else if (transactionType == MyMoneySplit::ReinvestDividend) { | | |||
1300 | value = interestSplits.first().value() * price; | | |||
1301 | reinvestincome += CashFlowListItem((*it_transaction).postDate(), -value); | | |||
1302 | } else if (transactionType == MyMoneySplit::Dividend || transactionType == MyMoneySplit::Yield) | | |||
1303 | cashincome += CashFlowListItem((*it_transaction).postDate(), value); | | |||
1304 | ++it_transaction; | | |||
1305 | } | | |||
1306 | // Note that reinvested dividends are not included , because these do not | | |||
1307 | // represent a cash flow event. | | |||
1308 | all += buys; | | |||
1309 | all += sells; | | |||
1310 | all += cashincome; | | |||
1311 | all += CashFlowListItem(startingDate, -startingBal); | | |||
1312 | all += CashFlowListItem(endingDate, endingBal); | | |||
1313 | | ||||
1314 | MyMoneyMoney buysTotal = buys.total(); | | |||
1315 | MyMoneyMoney sellsTotal = sells.total(); | | |||
1316 | MyMoneyMoney cashIncomeTotal = cashincome.total(); | | |||
1317 | MyMoneyMoney reinvestIncomeTotal = reinvestincome.total(); | | |||
1318 | | ||||
1319 | MyMoneyMoney returnInvestment = helperROI(buysTotal, sellsTotal, startingBal, endingBal, cashIncomeTotal); | | |||
1320 | MyMoneyMoney annualReturn = helperIRR(all); | | |||
1321 | | ||||
1322 | // check if there are any meaningfull values before adding them to results | | |||
1323 | if (!(buysTotal.isZero() && sellsTotal.isZero() && | | |||
1324 | cashIncomeTotal.isZero() && reinvestIncomeTotal.isZero() && | | |||
1325 | startingBal.isZero() && endingBal.isZero())) { | | |||
1326 | result["return"] = annualReturn.toString(); | | |||
1327 | result["returninvestment"] = returnInvestment.toString(); | | |||
1328 | result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); | | |||
1329 | result["buys"] = buysTotal.toString(); | | |||
1330 | result["sells"] = sellsTotal.toString(); | | |||
1331 | result["cashincome"] = cashIncomeTotal.toString(); | | |||
1332 | result["reinvestincome"] = reinvestIncomeTotal.toString(); | | |||
1333 | result["startingbal"] = startingBal.toString(); | | |||
1334 | result["endingbal"] = endingBal.toString(); | | |||
1335 | } | | |||
1336 | } | | |||
1337 | | ||||
1338 | void QueryTable::constructCapitalGainRow(const ReportAccount& account, TableRow& result) const | | |||
1339 | { | | |||
1340 | MyMoneyFile* file = MyMoneyFile::instance(); | 1229 | MyMoneyFile* file = MyMoneyFile::instance(); | ||
1341 | MyMoneySecurity security; | | |||
1342 | MyMoneyMoney price; | | |||
1343 | MyMoneyMoney sellValue; | | |||
1344 | MyMoneyMoney buyValue; | | |||
1345 | MyMoneyMoney sellShares; | | |||
1346 | MyMoneyMoney buyShares; | | |||
1347 | | ||||
1348 | MyMoneyMoney sellLongValue; | | |||
1349 | MyMoneyMoney buyLongValue; | | |||
1350 | MyMoneyMoney sellLongShares; | | |||
1351 | MyMoneyMoney buyLongShares; | | |||
1352 | | ||||
1353 | // | | |||
1354 | // Calculate capital gain | | |||
1355 | // | | |||
1356 | | ||||
1357 | // The following columns are created: | | |||
1358 | // Account, Buys, Sells, Capital Gain | | |||
1359 | 1230 | | |||
1360 | MyMoneyReport report = m_config; | 1231 | MyMoneyReport report = m_config; | ||
1361 | QDate startingDate; | 1232 | QDate startingDate; | ||
1362 | QDate endingDate; | 1233 | QDate endingDate; | ||
1363 | QDate newStartingDate; | 1234 | QDate newStartingDate; | ||
1364 | QDate newEndingDate; | 1235 | QDate newEndingDate; | ||
1365 | const bool isSTLT = report.isShowingSTLTCapitalGains(); | 1236 | const bool isSTLT = report.isShowingSTLTCapitalGains(); | ||
1366 | const int settlementPeriod = report.settlementPeriod(); | 1237 | const int settlementPeriod = report.settlementPeriod(); | ||
1367 | QDate termSeparator = report.termSeparator().addDays(-settlementPeriod); | 1238 | QDate termSeparator = report.termSeparator().addDays(-settlementPeriod); | ||
1368 | report.validDateRange(startingDate, endingDate); | 1239 | report.validDateRange(startingDate, endingDate); | ||
1240 | newStartingDate = startingDate; | ||||
1241 | newEndingDate = endingDate; | ||||
1242 | | ||||
1243 | if (report.queryColumns() & MyMoneyReport::eQCcapitalgain) { | ||||
1369 | // Saturday and Sunday aren't valid settlement dates | 1244 | // Saturday and Sunday aren't valid settlement dates | ||
1370 | if (endingDate.dayOfWeek() == Qt::Saturday) | 1245 | if (endingDate.dayOfWeek() == Qt::Saturday) | ||
1371 | endingDate.addDays(-1); | 1246 | endingDate.addDays(-1); | ||
1372 | else if (endingDate.dayOfWeek() == Qt::Sunday) | 1247 | else if (endingDate.dayOfWeek() == Qt::Sunday) | ||
1373 | endingDate.addDays(-2); | 1248 | endingDate.addDays(-2); | ||
1374 | 1249 | | |||
1375 | if (termSeparator.dayOfWeek() == Qt::Saturday) | 1250 | if (termSeparator.dayOfWeek() == Qt::Saturday) | ||
1376 | termSeparator.addDays(-1); | 1251 | termSeparator.addDays(-1); | ||
1377 | else if (termSeparator.dayOfWeek() == Qt::Sunday) | 1252 | else if (termSeparator.dayOfWeek() == Qt::Sunday) | ||
1378 | termSeparator.addDays(-2); | 1253 | termSeparator.addDays(-2); | ||
1379 | | ||||
1380 | if (startingDate.daysTo(endingDate) <= settlementPeriod) // no days to check for | 1254 | if (startingDate.daysTo(endingDate) <= settlementPeriod) // no days to check for | ||
1381 | return; | 1255 | return; | ||
1382 | newStartingDate = startingDate; | | |||
1383 | newEndingDate = endingDate.addDays(-settlementPeriod); | | |||
1384 | termSeparator = termSeparator.addDays(-settlementPeriod); | 1256 | termSeparator = termSeparator.addDays(-settlementPeriod); | ||
1385 | MyMoneyMoney endingShares = file->balance(account.id(), newEndingDate); // get how many shares there are over zero value | 1257 | newEndingDate = endingDate.addDays(-settlementPeriod); | ||
1258 | } | ||||
1259 | | ||||
1260 | shList[BuysOfOwned] = file->balance(account.id(), newEndingDate); // get how many shares there are at the end of period | ||||
1261 | MyMoneyMoney stashedBuysOfOwned = shList.at(BuysOfOwned); | ||||
1386 | 1262 | | |||
1387 | bool reportedDateRange = true; // flag marking sell transactions between startingDate and endingDate | 1263 | bool reportedDateRange = true; // flag marking sell transactions between startingDate and endingDate | ||
1388 | report.setReportAllSplits(false); | 1264 | report.setReportAllSplits(false); | ||
1389 | report.setConsiderCategory(true); | 1265 | report.setConsiderCategory(true); | ||
1390 | report.clearAccountFilter(); | 1266 | report.clearAccountFilter(); | ||
1391 | report.addAccount(account.id()); | 1267 | report.addAccount(account.id()); | ||
1392 | report.setDateFilter(newStartingDate, newEndingDate); | 1268 | report.setDateFilter(newStartingDate, newEndingDate); | ||
1393 | 1269 | | |||
1394 | do { | 1270 | do { | ||
1395 | QList<MyMoneyTransaction> transactions = file->transactionList(report); | 1271 | QList<MyMoneyTransaction> transactions = file->transactionList(report); | ||
1396 | for (QList<MyMoneyTransaction>::const_reverse_iterator it_t = transactions.crbegin(); it_t != transactions.crend(); ++it_t) { | 1272 | for (QList<MyMoneyTransaction>::const_reverse_iterator it_t = transactions.crbegin(); it_t != transactions.crend(); ++it_t) { | ||
1397 | MyMoneySplit shareSplit = (*it_t).splitByAccount(account.id()); | 1273 | MyMoneySplit shareSplit = (*it_t).splitByAccount(account.id()); | ||
1398 | MyMoneySplit assetAccountSplit; | 1274 | MyMoneySplit assetAccountSplit; | ||
1399 | QList<MyMoneySplit> feeSplits; | 1275 | QList<MyMoneySplit> feeSplits; | ||
1400 | QList<MyMoneySplit> interestSplits; | 1276 | QList<MyMoneySplit> interestSplits; | ||
1277 | MyMoneySecurity security; | ||||
1401 | MyMoneySecurity currency; | 1278 | MyMoneySecurity currency; | ||
1402 | MyMoneySplit::investTransactionTypeE transactionType; | 1279 | MyMoneySplit::investTransactionTypeE transactionType; | ||
1403 | KMyMoneyUtils::dissectTransaction((*it_t), shareSplit, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); | 1280 | KMyMoneyUtils::dissectTransaction((*it_t), shareSplit, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); | ||
1281 | QDate postDate = (*it_t).postDate(); | ||||
1282 | MyMoneyMoney price; | ||||
1404 | //get price for the day of the transaction if we have to calculate base currency | 1283 | //get price for the day of the transaction if we have to calculate base currency | ||
1405 | //we are using the value of the split which is in deep currency | 1284 | //we are using the value of the split which is in deep currency | ||
1406 | if (m_config.isConvertCurrency()) | 1285 | if (m_config.isConvertCurrency()) | ||
1407 | price = account.baseCurrencyPrice((*it_t).postDate()); //we only need base currency because the value is in deep currency | 1286 | price = account.baseCurrencyPrice(postDate); //we only need base currency because the value is in deep currency | ||
1408 | else | 1287 | else | ||
1409 | price = MyMoneyMoney::ONE; | 1288 | price = MyMoneyMoney::ONE; | ||
1410 | MyMoneyMoney value = assetAccountSplit.value() * price; | 1289 | MyMoneyMoney value = assetAccountSplit.value() * price; | ||
1411 | MyMoneyMoney shares = shareSplit.shares(); | 1290 | MyMoneyMoney shares = shareSplit.shares(); | ||
1412 | 1291 | | |||
1413 | if (transactionType == MyMoneySplit::BuyShares) { | 1292 | if (transactionType == MyMoneySplit::BuyShares) { | ||
1414 | if (endingShares.isZero()) { // add sold shares | 1293 | if (reportedDateRange) { | ||
1415 | if (buyShares + shares > sellShares.abs()) { // add partially sold shares | 1294 | cfList[Buys].append(CashFlowListItem(postDate, value)); | ||
1416 | MyMoneyMoney tempVal = (((sellShares.abs() - buyShares)) / shares) * value; | 1295 | shList[Buys] += shares; | ||
1417 | buyValue += tempVal; | 1296 | } | ||
1418 | buyShares = sellShares.abs(); | 1297 | | ||
1419 | if (isSTLT && (*it_t).postDate() < termSeparator) { | 1298 | if (shList.at(BuysOfOwned).isZero()) { // add sold shares | ||
1420 | buyLongValue += tempVal; | 1299 | if (shList.at(BuysOfSells) + shares > shList.at(Sells).abs()) { // add partially sold shares | ||
1421 | buyLongShares = buyShares; | 1300 | MyMoneyMoney tempVal = (((shList.at(Sells).abs() - shList.at(BuysOfSells))) / shares) * value; | ||
1301 | cfList[BuysOfSells].append(CashFlowListItem(postDate, tempVal)); | ||||
1302 | shList[BuysOfSells] = shList.at(Sells).abs(); | ||||
1303 | if (isSTLT && postDate < termSeparator) { | ||||
1304 | cfList[LongTermBuysOfSells].append(CashFlowListItem(postDate, tempVal)); | ||||
1305 | shList[LongTermBuysOfSells] = shList.at(BuysOfSells); | ||||
1422 | } | 1306 | } | ||
1423 | } else { // add wholly sold shares | 1307 | } else { // add wholly sold shares | ||
1424 | buyValue += value; | 1308 | cfList[BuysOfSells].append(CashFlowListItem(postDate, value)); | ||
1425 | buyShares += shares; | 1309 | shList[BuysOfSells] += shares; | ||
1426 | if (isSTLT && (*it_t).postDate() < termSeparator) { | 1310 | if (isSTLT && postDate < termSeparator) { | ||
1427 | buyLongValue += value; | 1311 | cfList[LongTermBuysOfSells].append(CashFlowListItem(postDate, value)); | ||
1428 | buyLongShares += shares; | 1312 | shList[LongTermBuysOfSells] += shares; | ||
1429 | } | 1313 | } | ||
1430 | } | 1314 | } | ||
1431 | } else if (endingShares >= shares) { // substract not-sold shares | 1315 | } else if (shList.at(BuysOfOwned) >= shares) { // substract not-sold shares | ||
1432 | endingShares -= shares; | 1316 | shList[BuysOfOwned] -= shares; | ||
1317 | cfList[BuysOfOwned].append(CashFlowListItem(postDate, value)); | ||||
1433 | } else { // substract partially not-sold shares | 1318 | } else { // substract partially not-sold shares | ||
1434 | MyMoneyMoney tempVal = ((shares - endingShares) / shares) * value; | 1319 | MyMoneyMoney tempVal = ((shares - shList.at(BuysOfOwned)) / shares) * value; | ||
1435 | MyMoneyMoney tempVal2 = (shares - endingShares); | 1320 | MyMoneyMoney tempVal2 = (shares - shList.at(BuysOfOwned)); | ||
1436 | buyValue += tempVal; | 1321 | cfList[BuysOfSells].append(CashFlowListItem(postDate, tempVal)); | ||
1437 | buyShares += tempVal2; | 1322 | shList[BuysOfSells] += tempVal2; | ||
1438 | if (isSTLT && (*it_t).postDate() < termSeparator) { | 1323 | if (isSTLT && postDate < termSeparator) { | ||
1439 | buyLongValue += tempVal; | 1324 | cfList[LongTermBuysOfSells].append(CashFlowListItem(postDate, tempVal)); | ||
1440 | buyLongShares += tempVal2; | 1325 | shList[LongTermBuysOfSells] += tempVal2; | ||
1441 | } | 1326 | } | ||
1442 | endingShares = MyMoneyMoney(); | 1327 | cfList[BuysOfOwned].append(CashFlowListItem(postDate, (shList.at(BuysOfOwned) / shares) * value)); | ||
1328 | shList[BuysOfOwned] = MyMoneyMoney(); | ||||
1443 | } | 1329 | } | ||
1444 | } else if (transactionType == MyMoneySplit::SellShares && reportedDateRange) { | 1330 | } else if (transactionType == MyMoneySplit::SellShares && reportedDateRange) { | ||
1445 | sellValue += value; | 1331 | cfList[Sells].append(CashFlowListItem(postDate, value)); | ||
1446 | sellShares += shares; | 1332 | shList[Sells] += shares; | ||
1447 | } else if (transactionType == MyMoneySplit::SplitShares) { // shares variable is denominator of split ratio here | 1333 | } else if (transactionType == MyMoneySplit::SplitShares) { // shares variable is denominator of split ratio here | ||
1448 | sellShares /= shares; | 1334 | for (int i = Buys; i <= InvestmentValue::BuysOfOwned; ++i) | ||
1449 | buyShares /= shares; | 1335 | shList[i] /= shares; | ||
1450 | buyLongShares /= shares; | 1336 | } else if (transactionType == MyMoneySplit::AddShares || // added shares, when sold give 100% capital gain | ||
1451 | } else if (transactionType == MyMoneySplit::AddShares) { // added shares, when sold give 100% capital gain | 1337 | transactionType == MyMoneySplit::ReinvestDividend) { | ||
1452 | if (endingShares.isZero()) { // add added shares | 1338 | if (shList.at(BuysOfOwned).isZero()) { // add added/reinvested shares | ||
1453 | if (buyShares + shares > sellShares.abs()) { // add partially added shares | 1339 | if (shList.at(BuysOfSells) + shares > shList.at(Sells).abs()) { // add partially added/reinvested shares | ||
1454 | buyShares = sellShares.abs(); | 1340 | shList[BuysOfSells] = shList.at(Sells).abs(); | ||
1455 | if ((*it_t).postDate() < termSeparator) | 1341 | if (postDate < termSeparator) | ||
1456 | buyLongShares = buyShares; | 1342 | shList[LongTermBuysOfSells] = shList[BuysOfSells]; | ||
1457 | } else { // add wholly added shares | 1343 | } else { // add wholly added/reinvested shares | ||
1458 | buyShares += shares; | 1344 | shList[BuysOfSells] += shares; | ||
1459 | if ((*it_t).postDate() < termSeparator) | 1345 | if (postDate < termSeparator) | ||
1460 | buyLongShares += shares; | 1346 | shList[LongTermBuysOfSells] += shares; | ||
1461 | } | 1347 | } | ||
1462 | } else if (endingShares >= shares) { // substract not-added shares | 1348 | } else if (shList.at(BuysOfOwned) >= shares) { // substract not-added/not-reinvested shares | ||
1463 | endingShares -= shares; | 1349 | shList[BuysOfOwned] -= shares; | ||
1464 | } else { // substract partially not-added shares | 1350 | cfList[BuysOfOwned].append(CashFlowListItem(postDate, value)); | ||
1465 | MyMoneyMoney tempVal = (shares - endingShares); | 1351 | } else { // substract partially not-added/not-reinvested shares | ||
1466 | buyShares += tempVal; | 1352 | MyMoneyMoney tempVal = (shares - shList.at(BuysOfOwned)); | ||
1467 | if ((*it_t).postDate() < termSeparator) | 1353 | shList[BuysOfSells] += tempVal; | ||
1468 | buyLongShares += tempVal; | 1354 | if (postDate < termSeparator) | ||
1469 | endingShares = MyMoneyMoney(); | 1355 | shList[LongTermBuysOfSells] += tempVal; | ||
1470 | } | 1356 | | ||
1471 | } else if (transactionType == MyMoneySplit::RemoveShares && reportedDateRange) { // removed shares give no value in return so no capital gain on them | 1357 | cfList[BuysOfOwned].append(CashFlowListItem(postDate, (shList.at(BuysOfOwned) / shares) * value)); | ||
1472 | sellShares += shares; | 1358 | shList[BuysOfOwned] = MyMoneyMoney(); | ||
1473 | } | 1359 | } | ||
1360 | qDebug() << "szeres: " << shares.toDouble() << "prais: " << price.toDouble() << "value:" << value.toDouble(); | ||||
1361 | if (transactionType == MyMoneySplit::ReinvestDividend) { | ||||
1362 | value = MyMoneyMoney(); | ||||
1363 | foreach (const auto split, interestSplits) | ||||
1364 | value += split.value(); | ||||
1365 | value *= price; | ||||
1366 | cfList[ReinvestIncome].append(CashFlowListItem(postDate, -value)); | ||||
1367 | } | ||||
1368 | } else if (transactionType == MyMoneySplit::RemoveShares && reportedDateRange) // removed shares give no value in return so no capital gain on them | ||||
1369 | shList[Sells] += shares; | ||||
1370 | else if (transactionType == MyMoneySplit::Dividend || transactionType == MyMoneySplit::Yield) | ||||
1371 | cfList[CashIncome].append(CashFlowListItem(postDate, value)); | ||||
1372 | | ||||
1474 | } | 1373 | } | ||
1475 | reportedDateRange = false; | 1374 | reportedDateRange = false; | ||
1476 | newEndingDate = newStartingDate; | 1375 | newEndingDate = newStartingDate; | ||
1477 | newStartingDate = newStartingDate.addYears(-1); | 1376 | newStartingDate = newStartingDate.addYears(-1); | ||
1478 | report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier | 1377 | report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier | ||
1479 | } while (!sellShares.isZero() && account.openingDate() <= newEndingDate && sellShares.abs() > buyShares.abs()); | 1378 | | ||
1379 | } while ( | ||||
1380 | ( | ||||
1381 | (report.investmentSum() == MyMoneyReport::eSumOwned && !shList[BuysOfOwned].isZero()) || | ||||
1382 | (report.investmentSum() == MyMoneyReport::eSumSold && !shList.at(Sells).isZero() && shList.at(Sells).abs() > shList.at(BuysOfSells).abs()) || | ||||
1383 | (report.investmentSum() == MyMoneyReport::eSumOwnedAndSold && (!shList[BuysOfOwned].isZero() || (!shList.at(Sells).isZero() && shList.at(Sells).abs() > shList.at(BuysOfSells).abs()))) | ||||
1384 | ) && account.openingDate() <= newEndingDate | ||||
1385 | ); | ||||
1480 | 1386 | | |||
1481 | // we've got buy value and no sell value of long-term shares, so get them | 1387 | // we've got buy value and no sell value of long-term shares, so get them | ||
1482 | if (isSTLT && !buyLongShares.isZero()) { | 1388 | if (isSTLT && !shList[LongTermBuysOfSells].isZero()) { | ||
1483 | newStartingDate = startingDate; | 1389 | newStartingDate = startingDate; | ||
1484 | newEndingDate = endingDate.addDays(-settlementPeriod); | 1390 | newEndingDate = endingDate.addDays(-settlementPeriod); | ||
1485 | report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier | 1391 | report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier | ||
1486 | QList<MyMoneyTransaction> transactions = file->transactionList(report); | 1392 | QList<MyMoneyTransaction> transactions = file->transactionList(report); | ||
1487 | endingShares = buyLongShares; | 1393 | shList[BuysOfOwned] = shList[LongTermBuysOfSells]; | ||
1488 | 1394 | | |||
1489 | foreach (const auto transaction, transactions) { | 1395 | foreach (const auto transaction, transactions) { | ||
1490 | MyMoneySplit shareSplit = transaction.splitByAccount(account.id()); | 1396 | MyMoneySplit shareSplit = transaction.splitByAccount(account.id()); | ||
1491 | MyMoneySplit assetAccountSplit; | 1397 | MyMoneySplit assetAccountSplit; | ||
1492 | QList<MyMoneySplit> feeSplits; | 1398 | QList<MyMoneySplit> feeSplits; | ||
1493 | QList<MyMoneySplit> interestSplits; | 1399 | QList<MyMoneySplit> interestSplits; | ||
1400 | MyMoneySecurity security; | ||||
1494 | MyMoneySecurity currency; | 1401 | MyMoneySecurity currency; | ||
1495 | MyMoneySplit::investTransactionTypeE transactionType; | 1402 | MyMoneySplit::investTransactionTypeE transactionType; | ||
1496 | KMyMoneyUtils::dissectTransaction(transaction, shareSplit, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); | 1403 | KMyMoneyUtils::dissectTransaction(transaction, shareSplit, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); | ||
1404 | QDate postDate = transaction.postDate(); | ||||
1405 | MyMoneyMoney price; | ||||
1497 | if (m_config.isConvertCurrency()) | 1406 | if (m_config.isConvertCurrency()) | ||
1498 | price = account.baseCurrencyPrice(transaction.postDate()); //we only need base currency because the value is in deep currency | 1407 | price = account.baseCurrencyPrice(postDate); //we only need base currency because the value is in deep currency | ||
1499 | else | 1408 | else | ||
1500 | price = MyMoneyMoney::ONE; | 1409 | price = MyMoneyMoney::ONE; | ||
1501 | MyMoneyMoney value = assetAccountSplit.value() * price; | 1410 | MyMoneyMoney value = assetAccountSplit.value() * price; | ||
1502 | MyMoneyMoney shares = shareSplit.shares(); | 1411 | MyMoneyMoney shares = shareSplit.shares(); | ||
1412 | | ||||
1503 | if (transactionType == MyMoneySplit::SellShares) { | 1413 | if (transactionType == MyMoneySplit::SellShares) { | ||
1504 | if ((sellLongShares + shares).abs() >= buyLongShares) { // add partially sold long-term shares | 1414 | if ((shList.at(LongTermSellsOfBuys) + shares).abs() >= shList.at(LongTermBuysOfSells)) { // add partially sold long-term shares | ||
1505 | sellLongValue += (sellLongShares.abs() - buyLongShares) / shares * value; | 1415 | cfList[LongTermSellsOfBuys].append(CashFlowListItem(postDate, (shList.at(LongTermSellsOfBuys).abs() - shList.at(LongTermBuysOfSells)) / shares * value)); | ||
1506 | sellLongShares = buyLongShares; | 1416 | shList[LongTermSellsOfBuys] = shList.at(LongTermBuysOfSells); | ||
1507 | break; | 1417 | break; | ||
1508 | } else { // add wholly sold long-term shares | 1418 | } else { // add wholly sold long-term shares | ||
1509 | sellLongValue += value; | 1419 | cfList[LongTermSellsOfBuys].append(CashFlowListItem(postDate, value)); | ||
1510 | sellLongShares += shares; | 1420 | shList[LongTermSellsOfBuys] += shares; | ||
1511 | } | 1421 | } | ||
1512 | } else if (transactionType == MyMoneySplit::RemoveShares) { | 1422 | } else if (transactionType == MyMoneySplit::RemoveShares) { | ||
1513 | if ((sellLongShares + shares).abs() >= buyLongShares) { | 1423 | if ((shList.at(LongTermSellsOfBuys) + shares).abs() >= shList.at(LongTermBuysOfSells)) { | ||
1514 | sellLongShares = buyLongShares; | 1424 | shList[LongTermSellsOfBuys] = shList.at(LongTermBuysOfSells); | ||
1515 | break; | 1425 | break; | ||
1516 | } else | 1426 | } else | ||
1517 | sellLongShares += shares; | 1427 | shList[LongTermSellsOfBuys] += shares; | ||
1428 | } | ||||
1518 | } | 1429 | } | ||
1519 | } | 1430 | } | ||
1431 | | ||||
1432 | shList[BuysOfOwned] = stashedBuysOfOwned; | ||||
1433 | report.setDateFilter(startingDate, endingDate); // reset data filter for next security | ||||
1434 | return; | ||||
1520 | } | 1435 | } | ||
1521 | 1436 | | |||
1437 | void QueryTable::constructPerformanceRow(const ReportAccount& account, TableRow& result, CashFlowList &all) const | ||||
1438 | { | ||||
1439 | MyMoneyReport report = m_config; | ||||
1440 | QDate startingDate; | ||||
1441 | QDate endingDate; | ||||
1442 | report.validDateRange(startingDate, endingDate); | ||||
1443 | startingDate = startingDate.addDays(-1); | ||||
1444 | | ||||
1445 | MyMoneyFile* file = MyMoneyFile::instance(); | ||||
1446 | //get fraction depending on type of account | ||||
1447 | int fraction = account.currency().smallestAccountFraction(); | ||||
1448 | MyMoneyMoney price; | ||||
1449 | if (m_config.isConvertCurrency()) | ||||
1450 | price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate); | ||||
1451 | else | ||||
1452 | price = account.deepCurrencyPrice(startingDate); | ||||
1453 | | ||||
1454 | MyMoneyMoney startingBal = file->balance(account.id(), startingDate) * price; | ||||
1455 | | ||||
1456 | //convert to lowest fraction | ||||
1457 | startingBal = startingBal.convert(fraction); | ||||
1458 | | ||||
1459 | //calculate ending balance | ||||
1460 | if (m_config.isConvertCurrency()) | ||||
1461 | price = account.deepCurrencyPrice(endingDate) * account.baseCurrencyPrice(endingDate); | ||||
1462 | else | ||||
1463 | price = account.deepCurrencyPrice(endingDate); | ||||
1464 | | ||||
1465 | MyMoneyMoney endingBal = file->balance((account).id(), endingDate) * price; | ||||
1466 | | ||||
1467 | //convert to lowest fraction | ||||
1468 | endingBal = endingBal.convert(fraction); | ||||
1469 | | ||||
1470 | QList<CashFlowList> cfList; | ||||
1471 | QList<MyMoneyMoney> shList; | ||||
1472 | sumInvestmentValues(account, cfList, shList); | ||||
1473 | | ||||
1474 | MyMoneyMoney buysTotal; | ||||
1475 | MyMoneyMoney sellsTotal; | ||||
1476 | MyMoneyMoney cashIncomeTotal; | ||||
1477 | MyMoneyMoney reinvestIncomeTotal; | ||||
1478 | | ||||
1479 | switch (m_config.investmentSum()) { | ||||
1480 | case MyMoneyReport::eSumOwnedAndSold: | ||||
1481 | buysTotal = cfList.at(BuysOfSells).total() + cfList.at(BuysOfOwned).total(); | ||||
1482 | sellsTotal = cfList.at(Sells).total(); | ||||
1483 | cashIncomeTotal = cfList.at(CashIncome).total(); | ||||
1484 | reinvestIncomeTotal = cfList.at(ReinvestIncome).total(); | ||||
1485 | startingBal = MyMoneyMoney(); | ||||
1486 | if (buysTotal.isZero() && sellsTotal.isZero() && | ||||
1487 | cashIncomeTotal.isZero() && reinvestIncomeTotal.isZero()) | ||||
1488 | return; | ||||
1489 | | ||||
1490 | all.append(cfList.at(BuysOfSells)); | ||||
1491 | all.append(cfList.at(BuysOfOwned)); | ||||
1492 | all.append(cfList.at(Sells)); | ||||
1493 | all.append(cfList.at(CashIncome)); | ||||
1494 | | ||||
1495 | result[QLatin1String("sells")] = sellsTotal.toString(); | ||||
1496 | result[QLatin1String("cashincome")] = cashIncomeTotal.toString(); | ||||
1497 | result[QLatin1String("reinvestincome")] = reinvestIncomeTotal.toString(); | ||||
1498 | result[QLatin1String("endingbal")] = endingBal.toString(); | ||||
1499 | break; | ||||
1500 | case MyMoneyReport::eSumOwned: | ||||
1501 | buysTotal = cfList.at(BuysOfOwned).total(); | ||||
1502 | startingBal = MyMoneyMoney(); | ||||
1503 | if (buysTotal.isZero() && endingBal.isZero()) | ||||
1504 | return; | ||||
1505 | all.append(cfList.at(BuysOfOwned)); | ||||
1506 | all.append(CashFlowListItem(endingDate, endingBal)); | ||||
1507 | | ||||
1508 | result[QLatin1String("reinvestincome")] = reinvestIncomeTotal.toString(); | ||||
1509 | result[QLatin1String("marketvalue")] = endingBal.toString(); | ||||
1510 | break; | ||||
1511 | case MyMoneyReport::eSumSold: | ||||
1512 | buysTotal = cfList.at(BuysOfSells).total(); | ||||
1513 | sellsTotal = cfList.at(Sells).total(); | ||||
1514 | cashIncomeTotal = cfList.at(CashIncome).total(); | ||||
1515 | startingBal = endingBal = MyMoneyMoney(); | ||||
1522 | // check if there are any meaningfull values before adding them to results | 1516 | // check if there are any meaningfull values before adding them to results | ||
1523 | if (!(buyValue.isZero() && sellValue.isZero())) { | 1517 | if (buysTotal.isZero() && sellsTotal.isZero() && cashIncomeTotal.isZero()) | ||
1524 | result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); | 1518 | return; | ||
1525 | result["buys"] = buyValue.toString(); | 1519 | all.append(cfList.at(BuysOfSells)); | ||
1526 | result["sells"] = sellValue.toString(); | 1520 | all.append(cfList.at(Sells)); | ||
1527 | result["capitalgain"] = (buyValue + sellValue).toString(); | 1521 | all.append(cfList.at(CashIncome)); | ||
1528 | if (isSTLT) { | 1522 | | ||
1529 | result["buysLT"] = buyLongValue.toString(); | 1523 | result[QLatin1String("sells")] = sellsTotal.toString(); | ||
1530 | result["sellsLT"] = sellLongValue.toString(); | 1524 | result[QLatin1String("cashincome")] = cashIncomeTotal.toString(); | ||
1531 | result["capitalgainLT"] = (buyLongValue + sellLongValue).toString(); | 1525 | break; | ||
1532 | result["buysST"] = (buyValue - buyLongValue).toString(); | 1526 | case MyMoneyReport::eSumPeriod: | ||
1533 | result["sellsST"] = (sellValue - sellLongValue).toString(); | 1527 | default: | ||
1534 | result["capitalgainST"] = ((buyValue - buyLongValue) + (sellValue - sellLongValue)).toString(); | 1528 | buysTotal = cfList.at(Buys).total(); | ||
1529 | sellsTotal = cfList.at(Sells).total(); | ||||
1530 | cashIncomeTotal = cfList.at(CashIncome).total(); | ||||
1531 | reinvestIncomeTotal = cfList.at(ReinvestIncome).total(); | ||||
1532 | if (buysTotal.isZero() && sellsTotal.isZero() && | ||||
1533 | cashIncomeTotal.isZero() && reinvestIncomeTotal.isZero() && | ||||
1534 | startingBal.isZero() && endingBal.isZero()) | ||||
1535 | return; | ||||
1536 | | ||||
1537 | all.append(cfList.at(Buys)); | ||||
1538 | all.append(cfList.at(Sells)); | ||||
1539 | all.append(cfList.at(CashIncome)); | ||||
1540 | all.append(CashFlowListItem(startingDate, -startingBal)); | ||||
1541 | all.append(CashFlowListItem(endingDate, endingBal)); | ||||
1542 | | ||||
1543 | result[QLatin1String("sells")] = sellsTotal.toString(); | ||||
1544 | result[QLatin1String("cashincome")] = cashIncomeTotal.toString(); | ||||
1545 | result[QLatin1String("reinvestincome")] = reinvestIncomeTotal.toString(); | ||||
1546 | result[QLatin1String("startingbal")] = startingBal.toString(); | ||||
1547 | result[QLatin1String("endingbal")] = endingBal.toString(); | ||||
1548 | break; | ||||
1535 | } | 1549 | } | ||
1550 | | ||||
1551 | MyMoneyMoney returnInvestment = helperROI(buysTotal - reinvestIncomeTotal, sellsTotal, startingBal, endingBal, cashIncomeTotal); | ||||
1552 | MyMoneyMoney annualReturn = helperIRR(all); | ||||
1553 | | ||||
1554 | result[QLatin1String("buys")] = buysTotal.toString(); | ||||
1555 | result[QLatin1String("return")] = annualReturn.toString(); | ||||
1556 | result[QLatin1String("returninvestment")] = returnInvestment.toString(); | ||||
1557 | result[QLatin1String("equitytype")] = KMyMoneyUtils::securityTypeToString(file->security(account.currencyId()).securityType()); | ||||
1536 | } | 1558 | } | ||
1537 | report.setDateFilter(startingDate, endingDate); // reset data filter for next security | 1559 | | ||
1560 | void QueryTable::constructCapitalGainRow(const ReportAccount& account, TableRow& result) const | ||||
1561 | { | ||||
1562 | MyMoneyFile* file = MyMoneyFile::instance(); | ||||
1563 | QList<CashFlowList> cfList; | ||||
1564 | QList<MyMoneyMoney> shList; | ||||
1565 | sumInvestmentValues(account, cfList, shList); | ||||
1566 | | ||||
1567 | MyMoneyMoney buysTotal = cfList.at(BuysOfSells).total(); | ||||
1568 | MyMoneyMoney sellsTotal = cfList.at(Sells).total(); | ||||
1569 | MyMoneyMoney longTermBuysOfSellsTotal = cfList.at(LongTermBuysOfSells).total(); | ||||
1570 | MyMoneyMoney longTermSellsOfBuys = cfList.at(LongTermSellsOfBuys).total(); | ||||
1571 | | ||||
1572 | switch (m_config.investmentSum()) { | ||||
1573 | case MyMoneyReport::eSumOwned: | ||||
1574 | { | ||||
1575 | if (shList.at(BuysOfOwned).isZero()) | ||||
1576 | return; | ||||
1577 | | ||||
1578 | MyMoneyReport report = m_config; | ||||
1579 | QDate startingDate; | ||||
1580 | QDate endingDate; | ||||
1581 | report.validDateRange(startingDate, endingDate); | ||||
1582 | | ||||
1583 | //get fraction depending on type of account | ||||
1584 | int fraction = account.currency().smallestAccountFraction(); | ||||
1585 | MyMoneyMoney price; | ||||
1586 | | ||||
1587 | //calculate ending balance | ||||
1588 | if (m_config.isConvertCurrency()) | ||||
1589 | price = account.deepCurrencyPrice(endingDate) * account.baseCurrencyPrice(endingDate); | ||||
1590 | else | ||||
1591 | price = account.deepCurrencyPrice(endingDate); | ||||
1592 | | ||||
1593 | MyMoneyMoney endingBal = shList.at(BuysOfOwned) * price; | ||||
1594 | | ||||
1595 | //convert to lowest fraction | ||||
1596 | endingBal = endingBal.convert(fraction); | ||||
1597 | | ||||
1598 | buysTotal = cfList.at(BuysOfOwned).total() - cfList.at(ReinvestIncome).total(); | ||||
1599 | | ||||
1600 | int pricePrecision = file->security(account.currencyId()).pricePrecision(); | ||||
1601 | result[QLatin1String("buys")] = buysTotal.toString(); | ||||
1602 | result[QLatin1String("shares")] = shList.at(BuysOfOwned).toString(); | ||||
1603 | result[QLatin1String("buyprice")] = (buysTotal.abs() / shList.at(BuysOfOwned)).convertPrecision(pricePrecision).toString(); | ||||
1604 | result[QLatin1String("lastprice")] = price.toString(); | ||||
1605 | result[QLatin1String("marketvalue")] = endingBal.toString(); | ||||
1606 | result[QLatin1String("capitalgain")] = (buysTotal + endingBal).toString(); | ||||
1607 | result[QLatin1String("percentagegain")] = ((buysTotal + endingBal)/buysTotal.abs()).toString(); | ||||
1608 | break; | ||||
1609 | } | ||||
1610 | case MyMoneyReport::eSumSold: | ||||
1611 | default: | ||||
1612 | buysTotal = cfList.at(BuysOfSells).total() - cfList.at(ReinvestIncome).total(); | ||||
1613 | sellsTotal = cfList.at(Sells).total(); | ||||
1614 | longTermBuysOfSellsTotal = cfList.at(LongTermBuysOfSells).total(); | ||||
1615 | longTermSellsOfBuys = cfList.at(LongTermSellsOfBuys).total(); | ||||
1616 | // check if there are any meaningfull values before adding them to results | ||||
1617 | if (buysTotal.isZero() && sellsTotal.isZero() && | ||||
1618 | longTermBuysOfSellsTotal.isZero() && longTermSellsOfBuys.isZero()) | ||||
1619 | return; | ||||
1620 | | ||||
1621 | result[QLatin1String("buys")] = buysTotal.toString(); | ||||
1622 | result[QLatin1String("sells")] = sellsTotal.toString(); | ||||
1623 | result[QLatin1String("capitalgain")] = (buysTotal + sellsTotal).toString(); | ||||
1624 | if (m_config.isShowingSTLTCapitalGains()) { | ||||
1625 | result[QLatin1String("buysLT")] = longTermBuysOfSellsTotal.toString(); | ||||
1626 | result[QLatin1String("sellsLT")] = longTermSellsOfBuys.toString(); | ||||
1627 | result[QLatin1String("capitalgainLT")] = (longTermBuysOfSellsTotal + longTermSellsOfBuys).toString(); | ||||
1628 | result[QLatin1String("buysST")] = (buysTotal - longTermBuysOfSellsTotal).toString(); | ||||
1629 | result[QLatin1String("sellsST")] = (sellsTotal - longTermSellsOfBuys).toString(); | ||||
1630 | result[QLatin1String("capitalgainST")] = ((buysTotal - longTermBuysOfSellsTotal) + (sellsTotal - longTermSellsOfBuys)).toString(); | ||||
1631 | } | ||||
1632 | break; | ||||
1633 | } | ||||
1634 | | ||||
1635 | result[QLatin1String("equitytype")] = KMyMoneyUtils::securityTypeToString(file->security(account.currencyId()).securityType()); | ||||
1538 | } | 1636 | } | ||
1539 | 1637 | | |||
1540 | void QueryTable::constructAccountTable() | 1638 | void QueryTable::constructAccountTable() | ||
1541 | { | 1639 | { | ||
1542 | MyMoneyFile* file = MyMoneyFile::instance(); | 1640 | MyMoneyFile* file = MyMoneyFile::instance(); | ||
1543 | 1641 | | |||
1544 | //make sure we have all subaccounts of investment accounts | 1642 | //make sure we have all subaccounts of investment accounts | ||
1545 | includeInvestmentSubAccounts(); | 1643 | includeInvestmentSubAccounts(); | ||
▲ Show 20 Lines • Show All 468 Lines • Show Last 20 Lines |