Changeset View
Changeset View
Standalone View
Standalone View
kmymoney/reports/querytable.cpp
Show First 20 Lines • Show All 1096 Lines • ▼ Show 20 Line(s) | 980 | { | |||
---|---|---|---|---|---|
1097 | all += sells; | 1097 | all += sells; | ||
1098 | all += cashincome; | 1098 | all += cashincome; | ||
1099 | all += CashFlowListItem(startingDate, -startingBal); | 1099 | all += CashFlowListItem(startingDate, -startingBal); | ||
1100 | all += CashFlowListItem(endingDate, endingBal); | 1100 | all += CashFlowListItem(endingDate, endingBal); | ||
1101 | 1101 | | |||
1102 | MyMoneyMoney returnInvestment; | 1102 | MyMoneyMoney returnInvestment; | ||
1103 | MyMoneyMoney buysTotal = buys.total(); | 1103 | MyMoneyMoney buysTotal = buys.total(); | ||
1104 | MyMoneyMoney sellsTotal = sells.total(); | 1104 | MyMoneyMoney sellsTotal = sells.total(); | ||
1105 | MyMoneyMoney cashincomeTotal = cashincome.total(); | 1105 | MyMoneyMoney cashIncomeTotal = cashincome.total(); | ||
1106 | MyMoneyMoney reinvestIncomeTotal = reinvestincome.total(); | ||||
1107 | | ||||
1106 | if (!buysTotal.isZero() || !startingBal.isZero()) { | 1108 | if (!buysTotal.isZero() || !startingBal.isZero()) { | ||
1107 | returnInvestment = (sellsTotal + buysTotal + cashincomeTotal + endingBal - startingBal) / (startingBal - buysTotal); | 1109 | returnInvestment = (sellsTotal + buysTotal + cashIncomeTotal + endingBal - startingBal) / (startingBal - buysTotal); | ||
1108 | returnInvestment = returnInvestment.convert(10000); | 1110 | returnInvestment = returnInvestment.convert(10000); | ||
1109 | } else | 1111 | } else | ||
1110 | returnInvestment = MyMoneyMoney(); // if no investment then no return on investment | 1112 | returnInvestment = MyMoneyMoney(); // if no investment then no return on investment | ||
1111 | 1113 | | |||
1114 | MyMoneyMoney annualReturn; | ||||
1112 | try { | 1115 | try { | ||
1113 | double irr = all.IRR(); | 1116 | double irr = all.IRR(); | ||
1114 | #ifdef Q_CC_MSVC | 1117 | #ifdef Q_CC_MSVC | ||
1115 | MyMoneyMoney annualReturn = MyMoneyMoney(_isnan(irr) ? 0 : irr, 10000); | 1118 | annualReturn = MyMoneyMoney(_isnan(irr) ? 0 : irr, 10000); | ||
1116 | #else | 1119 | #else | ||
1117 | MyMoneyMoney annualReturn = MyMoneyMoney(std::isnan(irr) ? 0 : irr, 10000); | 1120 | annualReturn = MyMoneyMoney(std::isnan(irr) ? 0 : irr, 10000); | ||
1118 | #endif | 1121 | #endif | ||
1119 | result["return"] = annualReturn.toString(); | | |||
1120 | result["returninvestment"] = returnInvestment.toString(); | | |||
1121 | } catch (QString e) { | 1122 | } catch (QString e) { | ||
1122 | qDebug() << e; | 1123 | qDebug() << e; | ||
1123 | } | 1124 | } | ||
1124 | 1125 | | |||
1126 | // check if there are any meaningfull values before adding them to results | ||||
1127 | if (!(buysTotal.isZero() && sellsTotal.isZero() && | ||||
1128 | cashIncomeTotal.isZero() && reinvestIncomeTotal.isZero() && | ||||
1129 | startingBal.isZero() && endingBal.isZero())) { | ||||
1130 | result["return"] = annualReturn.toString(); | ||||
1131 | result["returninvestment"] = returnInvestment.toString(); | ||||
1125 | result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); | 1132 | result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); | ||
1126 | result["buys"] = buys.total().toString(); | 1133 | result["buys"] = buysTotal.toString(); | ||
1127 | result["sells"] = sells.total().toString(); | 1134 | result["sells"] = sellsTotal.toString(); | ||
1128 | result["cashincome"] = cashincome.total().toString(); | 1135 | result["cashincome"] = cashIncomeTotal.toString(); | ||
1129 | result["reinvestincome"] = reinvestincome.total().toString(); | 1136 | result["reinvestincome"] = reinvestIncomeTotal.toString(); | ||
1130 | result["startingbal"] = startingBal.toString(); | 1137 | result["startingbal"] = startingBal.toString(); | ||
1131 | result["endingbal"] = endingBal.toString(); | 1138 | result["endingbal"] = endingBal.toString(); | ||
1132 | } | 1139 | } | ||
1140 | } | ||||
1133 | 1141 | | |||
1134 | void QueryTable::constructCapitalGainRow(const ReportAccount& account, TableRow& result) const | 1142 | void QueryTable::constructCapitalGainRow(const ReportAccount& account, TableRow& result) const | ||
1135 | { | 1143 | { | ||
1136 | MyMoneyFile* file = MyMoneyFile::instance(); | 1144 | MyMoneyFile* file = MyMoneyFile::instance(); | ||
1137 | MyMoneySecurity security; | 1145 | MyMoneySecurity security; | ||
1138 | MyMoneyMoney price; | 1146 | MyMoneyMoney price; | ||
1139 | MyMoneyMoney sellValue; | 1147 | MyMoneyMoney sellValue; | ||
1140 | MyMoneyMoney buyValue; | 1148 | MyMoneyMoney buyValue; | ||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Line(s) | 1177 | for (QList<MyMoneyTransaction>::const_reverse_iterator it_t = transactions.crbegin(); it_t != transactions.crend(); ++it_t) { | |||
1224 | } | 1232 | } | ||
1225 | } | 1233 | } | ||
1226 | reportedDateRange = false; | 1234 | reportedDateRange = false; | ||
1227 | newEndingDate = newStartingDate; | 1235 | newEndingDate = newStartingDate; | ||
1228 | newStartingDate = newStartingDate.addYears(-1); | 1236 | newStartingDate = newStartingDate.addYears(-1); | ||
1229 | report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier | 1237 | report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier | ||
1230 | } while (!sellShares.isZero() && account.openingDate() <= newEndingDate && sellShares.abs() > buyShares.abs()); | 1238 | } while (!sellShares.isZero() && account.openingDate() <= newEndingDate && sellShares.abs() > buyShares.abs()); | ||
1231 | 1239 | | |||
1240 | // check if there are any meaningfull values before adding them to results | ||||
1241 | if (!(buyValue.isZero() && sellValue.isZero())) { | ||||
1232 | result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); | 1242 | result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); | ||
1233 | result["buys"] = buyValue.toString(); | 1243 | result["buys"] = buyValue.toString(); | ||
1234 | result["sells"] = sellValue.toString(); | 1244 | result["sells"] = sellValue.toString(); | ||
1235 | result["capitalgain"] = (buyValue + sellValue).toString(); | 1245 | result["capitalgain"] = (buyValue + sellValue).toString(); | ||
1236 | 1246 | } | |||
1237 | report.setDateFilter(startingDate, endingDate); // reset data filter for next security | 1247 | report.setDateFilter(startingDate, endingDate); // reset data filter for next security | ||
1238 | } | 1248 | } | ||
1239 | 1249 | | |||
1240 | void QueryTable::constructAccountTable() | 1250 | void QueryTable::constructAccountTable() | ||
1241 | { | 1251 | { | ||
1242 | MyMoneyFile* file = MyMoneyFile::instance(); | 1252 | MyMoneyFile* file = MyMoneyFile::instance(); | ||
1243 | 1253 | | |||
1244 | //make sure we have all subaccounts of investment accounts | 1254 | //make sure we have all subaccounts of investment accounts | ||
1245 | includeInvestmentSubAccounts(); | 1255 | includeInvestmentSubAccounts(); | ||
1246 | 1256 | | |||
1247 | QList<MyMoneyAccount> accounts; | 1257 | QList<MyMoneyAccount> accounts; | ||
1248 | file->accountList(accounts); | 1258 | file->accountList(accounts); | ||
1249 | QList<MyMoneyAccount>::const_iterator it_account = accounts.constBegin(); | 1259 | for (auto it_account = accounts.constBegin(); it_account != accounts.constEnd(); ++it_account) { | ||
1250 | while (it_account != accounts.constEnd()) { | | |||
1251 | ReportAccount account = *it_account; | | |||
1252 | | ||||
1253 | //get fraction for account | | |||
1254 | int fraction = account.currency().smallestAccountFraction(); | | |||
1255 | | ||||
1256 | //use base currency fraction if not initialized | | |||
1257 | if (fraction == -1) | | |||
1258 | fraction = MyMoneyFile::instance()->baseCurrency().smallestAccountFraction(); | | |||
1259 | | ||||
1260 | // Note, "Investment" accounts are never included in account rows because | 1260 | // Note, "Investment" accounts are never included in account rows because | ||
1261 | // they don't contain anything by themselves. In reports, they are only | 1261 | // they don't contain anything by themselves. In reports, they are only | ||
1262 | // useful as a "topaccount" aggregator of stock accounts | 1262 | // useful as a "topaccount" aggregator of stock accounts | ||
1263 | if (account.isAssetLiability() && m_config.includes(account) && account.accountType() != MyMoneyAccount::Investment) { | 1263 | if ((*it_account).isAssetLiability() && m_config.includes((*it_account)) && (*it_account).accountType() != MyMoneyAccount::Investment) { | ||
1264 | // don't add the account if it is closed. In fact, the business logic | ||||
1265 | // should prevent that an account can be closed with a balance not equal | ||||
1266 | // to zero, but we never know. | ||||
1267 | MyMoneyMoney shares = file->balance((*it_account).id(), m_config.toDate()); | ||||
1268 | if (shares.isZero() && (*it_account).isClosed()) | ||||
1269 | continue; | ||||
1270 | | ||||
1271 | ReportAccount account(*it_account); | ||||
1264 | TableRow qaccountrow; | 1272 | TableRow qaccountrow; | ||
1273 | if (m_config.queryColumns() == MyMoneyReport::eQCperformance) { | ||||
1274 | constructPerformanceRow(account, qaccountrow); | ||||
1275 | } else if (m_config.queryColumns() == MyMoneyReport::eQCcapitalgain) { | ||||
1276 | constructCapitalGainRow(account, qaccountrow); | ||||
1277 | } else | ||||
1278 | qaccountrow["equitytype"].clear(); | ||||
1279 | | ||||
1280 | if (qaccountrow.isEmpty()) // don't add the account if there are no calculated values | ||||
1281 | continue; | ||||
1265 | 1282 | | |||
1266 | // help for sort and render functions | 1283 | // help for sort and render functions | ||
1267 | qaccountrow["rank"] = '0'; | 1284 | qaccountrow["rank"] = '0'; | ||
1268 | | ||||
1269 | // | 1285 | // | ||
1270 | // Handle currency conversion | 1286 | // Handle currency conversion | ||
1271 | // | 1287 | // | ||
1272 | 1288 | | |||
1273 | MyMoneyMoney displayprice(1, 1); | 1289 | MyMoneyMoney displayprice(1, 1); | ||
1274 | if (m_config.isConvertCurrency()) { | 1290 | if (m_config.isConvertCurrency()) { | ||
1275 | // display currency is base currency, so set the price | 1291 | // display currency is base currency, so set the price | ||
1276 | if (account.isForeignCurrency()) | 1292 | if (account.isForeignCurrency()) | ||
1277 | displayprice = account.baseCurrencyPrice(m_config.toDate()).reduce(); | 1293 | displayprice = account.baseCurrencyPrice(m_config.toDate()).reduce(); | ||
1278 | } else { | 1294 | } else { | ||
1279 | // display currency is the account's deep currency. display this fact in the report | 1295 | // display currency is the account's deep currency. display this fact in the report | ||
1280 | qaccountrow["currency"] = account.currency().id(); | 1296 | qaccountrow["currency"] = account.currency().id(); | ||
1281 | } | 1297 | } | ||
1282 | 1298 | | |||
1283 | qaccountrow["account"] = account.name(); | 1299 | qaccountrow["account"] = account.name(); | ||
1284 | qaccountrow["accountid"] = account.id(); | 1300 | qaccountrow["accountid"] = account.id(); | ||
1285 | qaccountrow["topaccount"] = account.topParentName(); | 1301 | qaccountrow["topaccount"] = account.topParentName(); | ||
1286 | 1302 | | |||
1287 | MyMoneyMoney shares = file->balance(account.id(), m_config.toDate()); | | |||
1288 | qaccountrow["shares"] = shares.toString(); | 1303 | qaccountrow["shares"] = shares.toString(); | ||
1289 | 1304 | | |||
1305 | //get fraction for account | ||||
1306 | int fraction = account.currency().smallestAccountFraction(); | ||||
1307 | | ||||
1308 | //use base currency fraction if not initialized | ||||
1309 | if (fraction == -1) | ||||
1310 | fraction = file->baseCurrency().smallestAccountFraction(); | ||||
1311 | | ||||
1290 | MyMoneyMoney netprice = account.deepCurrencyPrice(m_config.toDate()).reduce() * displayprice; | 1312 | MyMoneyMoney netprice = account.deepCurrencyPrice(m_config.toDate()).reduce() * displayprice; | ||
1291 | qaccountrow["price"] = (netprice.reduce()).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString(); | 1313 | qaccountrow["price"] = (netprice.reduce()).convert(MyMoneyMoney::precToDenom(KMyMoneyGlobalSettings::pricePrecision())).toString(); | ||
1292 | qaccountrow["value"] = (netprice.reduce() * shares.reduce()).convert(fraction).toString(); | 1314 | qaccountrow["value"] = (netprice.reduce() * shares.reduce()).convert(fraction).toString(); | ||
1293 | 1315 | | |||
1294 | QString iid = (*it_account).institutionId(); | 1316 | QString iid = (*it_account).institutionId(); | ||
1295 | 1317 | | |||
1296 | // If an account does not have an institution, get it from the top-parent. | 1318 | // If an account does not have an institution, get it from the top-parent. | ||
1297 | if (iid.isEmpty() && ! account.isTopLevel()) { | 1319 | if (iid.isEmpty() && ! account.isTopLevel()) { | ||
1298 | ReportAccount topaccount = account.topParent(); | 1320 | ReportAccount topaccount = account.topParent(); | ||
1299 | iid = topaccount.institutionId(); | 1321 | iid = topaccount.institutionId(); | ||
1300 | } | 1322 | } | ||
1301 | 1323 | | |||
1302 | if (iid.isEmpty()) | 1324 | if (iid.isEmpty()) | ||
1303 | qaccountrow["institution"] = i18nc("No institution", "None"); | 1325 | qaccountrow["institution"] = i18nc("No institution", "None"); | ||
1304 | else | 1326 | else | ||
1305 | qaccountrow["institution"] = file->institution(iid).name(); | 1327 | qaccountrow["institution"] = file->institution(iid).name(); | ||
1306 | 1328 | | |||
1307 | qaccountrow["type"] = KMyMoneyUtils::accountTypeToString((*it_account).accountType()); | 1329 | qaccountrow["type"] = KMyMoneyUtils::accountTypeToString((*it_account).accountType()); | ||
1308 | 1330 | | |||
1309 | if (m_config.queryColumns() == MyMoneyReport::eQCperformance) { | | |||
1310 | constructPerformanceRow(account, qaccountrow); | | |||
1311 | } else if (m_config.queryColumns() == MyMoneyReport::eQCcapitalgain) { | | |||
1312 | constructCapitalGainRow(account, qaccountrow); | | |||
1313 | } else | | |||
1314 | qaccountrow["equitytype"].clear(); | | |||
1315 | | ||||
1316 | // don't add the account if it is closed. In fact, the business logic | | |||
1317 | // should prevent that an account can be closed with a balance not equal | | |||
1318 | // to zero, but we never know. | | |||
1319 | if (!(shares.isZero() && account.isClosed())) | | |||
1320 | m_rows += qaccountrow; | 1331 | m_rows += qaccountrow; | ||
1321 | } | 1332 | } | ||
1322 | | ||||
1323 | ++it_account; | | |||
1324 | } | 1333 | } | ||
1325 | } | 1334 | } | ||
1326 | 1335 | | |||
1327 | void QueryTable::constructSplitsTable() | 1336 | void QueryTable::constructSplitsTable() | ||
1328 | { | 1337 | { | ||
1329 | MyMoneyFile* file = MyMoneyFile::instance(); | 1338 | MyMoneyFile* file = MyMoneyFile::instance(); | ||
1330 | 1339 | | |||
1331 | //make sure we have all subaccounts of investment accounts | 1340 | //make sure we have all subaccounts of investment accounts | ||
▲ Show 20 Lines • Show All 346 Lines • Show Last 20 Lines |