diff --git a/kmymoney/dialogs/kreportconfigurationfilterdlg.h b/kmymoney/dialogs/kreportconfigurationfilterdlg.h --- a/kmymoney/dialogs/kreportconfigurationfilterdlg.h +++ b/kmymoney/dialogs/kreportconfigurationfilterdlg.h @@ -69,6 +69,7 @@ QPointer m_tabChart; QPointer m_tabRange; QPointer m_tabCapitalGain; + QPointer m_tabPerformance; MyMoneyReport m_initialState; MyMoneyReport m_currentState; diff --git a/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp b/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp --- a/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp +++ b/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp @@ -68,6 +68,7 @@ #include #include #include +#include KReportConfigurationFilterDlg::KReportConfigurationFilterDlg( MyMoneyReport report, QWidget *parent) @@ -141,6 +142,10 @@ m_tabCapitalGain = new ReportTabCapitalGain(m_ui->m_criteriaTab); m_ui->m_criteriaTab->insertTab(1, m_tabCapitalGain, i18n("Report")); } + if (m_initialState.queryColumns() & MyMoneyReport::eQCperformance) { + m_tabPerformance = new ReportTabPerformance(m_ui->m_criteriaTab); + m_ui->m_criteriaTab->insertTab(1, m_tabPerformance, i18n("Report")); + } } m_ui->m_criteriaTab->setCurrentIndex(m_ui->m_criteriaTab->indexOf(m_tabGeneral)); @@ -290,7 +295,15 @@ m_currentState.setTermSeparator(m_tabCapitalGain->ui->m_termSeparator->date()); m_currentState.setShowSTLTCapitalGains(m_tabCapitalGain->ui->m_showSTLTCapitalGains->isChecked()); m_currentState.setSettlementPeriod(m_tabCapitalGain->ui->m_settlementPeriod->value()); + m_currentState.setShowingColumnTotals(!m_tabCapitalGain->ui->m_checkHideTotals->isChecked()); + m_currentState.setInvestmentSum(static_cast(m_tabCapitalGain->ui->m_investmentSum->currentData().toInt())); + } + + if (m_tabPerformance) { + m_currentState.setShowingColumnTotals(!m_tabPerformance->ui->m_checkHideTotals->isChecked()); + m_currentState.setInvestmentSum(static_cast(m_tabPerformance->ui->m_investmentSum->currentData().toInt())); } + done(true); } @@ -534,6 +547,25 @@ m_tabCapitalGain->ui->m_termSeparator->setDate(m_initialState.termSeparator()); m_tabCapitalGain->ui->m_showSTLTCapitalGains->setChecked(m_initialState.isShowingSTLTCapitalGains()); m_tabCapitalGain->ui->m_settlementPeriod->setValue(m_initialState.settlementPeriod()); + m_tabCapitalGain->ui->m_checkHideTotals->setChecked(!m_initialState.isShowingColumnTotals()); + m_tabCapitalGain->ui->m_investmentSum->blockSignals(true); + m_tabCapitalGain->ui->m_investmentSum->clear(); + m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only owned"), MyMoneyReport::eSumOwned); + m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only sold"), MyMoneyReport::eSumSold); + m_tabCapitalGain->ui->m_investmentSum->blockSignals(false); + m_tabCapitalGain->ui->m_investmentSum->setCurrentIndex(m_tabCapitalGain->ui->m_investmentSum->findData(m_initialState.investmentSum())); + } + + if (m_tabPerformance) { + m_tabPerformance->ui->m_checkHideTotals->setChecked(!m_initialState.isShowingColumnTotals()); + m_tabPerformance->ui->m_investmentSum->blockSignals(true); + m_tabPerformance->ui->m_investmentSum->clear(); + m_tabPerformance->ui->m_investmentSum->addItem(i18n("From period"), MyMoneyReport::eSumPeriod); + m_tabPerformance->ui->m_investmentSum->addItem(i18n("Owned and sold"), MyMoneyReport::eSumOwnedAndSold); + m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only owned"), MyMoneyReport::eSumOwned); + m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only sold"), MyMoneyReport::eSumSold); + m_tabPerformance->ui->m_investmentSum->blockSignals(false); + m_tabPerformance->ui->m_investmentSum->setCurrentIndex(m_tabPerformance->ui->m_investmentSum->findData(m_initialState.investmentSum())); } // diff --git a/kmymoney/mymoney/mymoneyreport.h b/kmymoney/mymoney/mymoneyreport.h --- a/kmymoney/mymoney/mymoneyreport.h +++ b/kmymoney/mymoney/mymoneyreport.h @@ -65,6 +65,7 @@ enum EQueryColumns { eQCnone = 0x0, eQCbegin = 0x1, eQCnumber = 0x1, eQCpayee = 0x2, eQCcategory = 0x4, eQCtag = 0x8, eQCmemo = 0x10, eQCaccount = 0x20, eQCreconciled = 0x40, eQCaction = 0x80, eQCshares = 0x100, eQCprice = 0x200, eQCperformance = 0x400, eQCloan = 0x800, eQCbalance = 0x1000, eQCcapitalgain = 0x2000, eQCend = 0x4000 }; enum EDetailLevel { eDetailNone = 0, eDetailAll, eDetailTop, eDetailGroup, eDetailTotal, eDetailEnd }; + enum EInvestmentSum { eSumPeriod = 0, eSumOwnedAndSold, eSumOwned, eSumSold, eSumBought}; enum EChartType { eChartNone = 0, eChartLine, eChartBar, eChartPie, eChartRing, eChartStackedBar, eChartEnd }; enum dataOptionE { automatic = 0, userDefined, dataOptionCount }; @@ -140,6 +141,9 @@ EDetailLevel detailLevel() const { return m_detailLevel; } + EInvestmentSum investmentSum() const { + return m_investmentSum; + } bool isHideTransactions() const { return m_hideTransactions; } @@ -278,6 +282,9 @@ void setDetailLevel(EDetailLevel _detail) { m_detailLevel = _detail; } + void setInvestmentSum(EInvestmentSum _sum) { + m_investmentSum = _sum; + } void setHideTransactions(bool _f) { m_hideTransactions = _f; } @@ -592,6 +599,10 @@ */ enum EDetailLevel m_detailLevel; /** + * Whether to sum: all, sold, bought or owned value + */ + enum EInvestmentSum m_investmentSum; + /** * Whether to show transactions or just totals. */ bool m_hideTransactions; diff --git a/kmymoney/mymoney/mymoneyreport.cpp b/kmymoney/mymoney/mymoneyreport.cpp --- a/kmymoney/mymoney/mymoneyreport.cpp +++ b/kmymoney/mymoney/mymoneyreport.cpp @@ -52,6 +52,7 @@ MyMoneyReport::MyMoneyReport() : m_name("Unconfigured Pivot Table Report"), m_detailLevel(eDetailNone), + m_investmentSum(eSumSold), m_hideTransactions(false), m_convertCurrency(true), m_favorite(false), @@ -111,6 +112,7 @@ m_name(_name), m_comment(_comment), m_detailLevel(_ss), + m_investmentSum(_ct & eQCcapitalgain ? eSumSold : eSumPeriod), m_hideTransactions(false), m_convertCurrency(true), m_favorite(false), @@ -392,6 +394,7 @@ e.setAttribute("rowtype", kRowTypeText[m_rowType]); e.setAttribute("showrowtotals", m_showRowTotals); + e.setAttribute("showcolumntotals", m_showColumnTotals); e.setAttribute("detail", kDetailLevelText[m_detailLevel]); e.setAttribute("includesmovingaverage", m_includeMovingAverage); @@ -442,13 +445,20 @@ e.setAttribute("investments", m_investments); e.setAttribute("loans", m_loans); e.setAttribute("hidetransactions", m_hideTransactions); + e.setAttribute("showcolumntotals", m_showColumnTotals); e.setAttribute("detail", kDetailLevelText[m_detailLevel]); + // write performance tab + if (m_queryColumns & eQCperformance || m_queryColumns & eQCcapitalgain) + e.setAttribute("investmentsum", m_investmentSum); + // write capital gains tab if (m_queryColumns & eQCcapitalgain) { - e.setAttribute("settlementperiod", m_settlementPeriod); - e.setAttribute("showSTLTCapitalGains", m_showSTLTCapitalGains); - e.setAttribute("tseparator", m_tseparator.toString(Qt::ISODate)); + if (m_investmentSum == MyMoneyReport::eSumSold) { + e.setAttribute("settlementperiod", m_settlementPeriod); + e.setAttribute("showSTLTCapitalGains", m_showSTLTCapitalGains); + e.setAttribute("tseparator", m_tseparator.toString(Qt::ISODate)); + } } } else if (m_reportType == eInfoTable) e.setAttribute("showrowtotals", m_showRowTotals); @@ -770,13 +780,21 @@ m_investments = e.attribute("investments", "0").toUInt(); m_loans = e.attribute("loans", "0").toUInt(); m_hideTransactions = e.attribute("hidetransactions", "0").toUInt(); + m_showColumnTotals = e.attribute("showcolumntotals", "1").toUInt(); m_detailLevel = kDetailLevelText.indexOf(e.attribute("detail", "none")) == eDetailAll ? eDetailAll : eDetailNone; + // read performance or capital gains tab + if (m_queryColumns & eQCperformance) + m_investmentSum = static_cast(e.attribute("investmentsum", QString().setNum(MyMoneyReport::eSumPeriod)).toInt()); + // read capital gains tab if (m_queryColumns & eQCcapitalgain) { - m_showSTLTCapitalGains = e.attribute("showSTLTCapitalGains", "0").toUInt(); - m_settlementPeriod = e.attribute("settlementperiod", "3").toUInt(); - m_tseparator = QDate::fromString(e.attribute("tseparator", QDate::currentDate().addYears(-1).toString(Qt::ISODate)),Qt::ISODate); + m_investmentSum = static_cast(e.attribute("investmentsum", QString().setNum(MyMoneyReport::eSumSold)).toInt()); + if (m_investmentSum == MyMoneyReport::eSumSold) { + m_showSTLTCapitalGains = e.attribute("showSTLTCapitalGains", "0").toUInt(); + m_settlementPeriod = e.attribute("settlementperiod", "3").toUInt(); + m_tseparator = QDate::fromString(e.attribute("tseparator", QDate::currentDate().addYears(-1).toString(Qt::ISODate)),Qt::ISODate); + } } } else if (m_reportType == eInfoTable) { if (e.hasAttribute("showrowtotals")) diff --git a/kmymoney/reports/listtable.cpp b/kmymoney/reports/listtable.cpp --- a/kmymoney/reports/listtable.cpp +++ b/kmymoney/reports/listtable.cpp @@ -165,18 +165,20 @@ i18nHeaders["action"] = i18n("Action"); i18nHeaders["shares"] = i18n("Shares"); i18nHeaders["price"] = i18n("Price"); - i18nHeaders["latestprice"] = i18n("Price"); + i18nHeaders["lastprice"] = i18n("Last Price"); + i18nHeaders["buyprice"] = i18n("Buy Price"); i18nHeaders["netinvvalue"] = i18n("Net Value"); - i18nHeaders["buys"] = i18n("Buys"); - i18nHeaders["sells"] = i18n("Sells"); - i18nHeaders["buysST"] = i18n("Short-term Buys"); - i18nHeaders["sellsST"] = i18n("Short-term Sells"); - i18nHeaders["buysLT"] = i18n("Long-term Buys"); - i18nHeaders["sellsLT"] = i18n("Long-term Sells"); + i18nHeaders["buys"] = i18n("Buy Value"); + i18nHeaders["sells"] = i18n("Sell Value"); + i18nHeaders["buysST"] = i18n("Short-term Buy Value"); + i18nHeaders["sellsST"] = i18n("Short-term Sell Value"); + i18nHeaders["buysLT"] = i18n("Long-term Buy Value"); + i18nHeaders["sellsLT"] = i18n("Long-term Sell Value"); i18nHeaders["reinvestincome"] = i18n("Dividends Reinvested"); i18nHeaders["cashincome"] = i18n("Dividends Paid Out"); i18nHeaders["startingbal"] = i18n("Starting Balance"); i18nHeaders["endingbal"] = i18n("Ending Balance"); + i18nHeaders["marketvalue"] = i18n("Market Value"); i18nHeaders["return"] = i18n("Annualized Return"); i18nHeaders["returninvestment"] = i18n("Return On Investment"); i18nHeaders["fees"] = i18n("Fees"); @@ -205,18 +207,19 @@ i18nHeaders["finalpayment"] = i18n("Final Payment"); i18nHeaders["currentbalance"] = i18n("Current Balance"); i18nHeaders["capitalgain"] = i18n("Capital Gain"); + i18nHeaders["percentagegain"] = i18n("Percentage Gain"); i18nHeaders["capitalgainST"] = i18n("Short-term Gain"); i18nHeaders["capitalgainLT"] = i18n("Long-term Gain"); // the list of columns which represent money, so we can display them correctly - QStringList moneyColumns = QString("value,shares,price,latestprice,netinvvalue,buys,buysST,buysLT,sells,sellsST,sellsLT,cashincome,reinvestincome,startingbal,fees,interest,payment,balance,balancewarning,maxbalancelimit,creditwarning,maxcreditlimit,loanamount,periodicpayment,finalpayment,currentbalance,startingbal,endingbal,capitalgain,capitalgainST,capitalgainLT").split(','); + QStringList moneyColumns = QString("value,price,lastprice,buyprice,netinvvalue,buys,buysST,buysLT,sells,sellsST,sellsLT,cashincome,reinvestincome,startingbal,fees,interest,payment,balance,balancewarning,maxbalancelimit,creditwarning,maxcreditlimit,loanamount,periodicpayment,finalpayment,currentbalance,startingbal,endingbal,capitalgain,capitalgainST,capitalgainLT,marketvalue").split(','); // the list of columns which represent shares, which is like money except the // transaction currency will not be displayed QStringList sharesColumns = QString("shares").split(','); // the list of columns which represent a percentage, so we can display them correctly - QStringList percentColumns = QString("return,returninvestment,interestrate").split(','); + QStringList percentColumns = QString("return,returninvestment,interestrate,percentagegain").split(','); // the list of columns which represent dates, so we can display them correctly QStringList dateColumns = QString("postdate,entrydate,nextduedate,openingdate,nextinterestchange").split(','); @@ -457,7 +460,7 @@ .arg((*it_column == "value") ? " class=\"value\"" : "") .arg(i18n("Calculated"), tlinkBegin, tlinkEnd); csv += "\"" + i18n("Calculated") + "\","; - } else if (*it_column == "price") { + } else if ((*it_column).endsWith(QLatin1String("price"))) { int pricePrecision = file->security(file->account((*it_row)["accountid"]).currencyId()).pricePrecision(); result += QString("%3%2 %1%4") .arg(MyMoneyMoney(data).formatMoney(QString(), pricePrecision), currencyID, tlinkBegin, tlinkEnd); diff --git a/kmymoney/reports/querytable.h b/kmymoney/reports/querytable.h --- a/kmymoney/reports/querytable.h +++ b/kmymoney/reports/querytable.h @@ -69,11 +69,14 @@ void constructAccountTable(); void constructTotalRows(); void constructTransactionTable(); + void sumInvestmentValues(const ReportAccount &account, QList &cfList, QList &shList) const; + void constructPerformanceRow(const ReportAccount& account, TableRow& result, CashFlowList &all) const; void constructCapitalGainRow(const ReportAccount& account, TableRow& result) const; MyMoneyMoney helperROI(const MyMoneyMoney& buys, const MyMoneyMoney& sells, const MyMoneyMoney& startingBal, const MyMoneyMoney& endingBal, const MyMoneyMoney& cashIncome) const; MyMoneyMoney helperIRR(const CashFlowList& all) const; - void constructPerformanceRow(const ReportAccount& account, TableRow& result, CashFlowList &all) const; void constructSplitsTable(); +private: + enum InvestmentValue {Buys = 0, Sells, BuysOfSells, SellsOfBuys, LongTermBuysOfSells, LongTermSellsOfBuys, BuysOfOwned, ReinvestIncome, CashIncome, End}; }; diff --git a/kmymoney/reports/querytable.cpp b/kmymoney/reports/querytable.cpp --- a/kmymoney/reports/querytable.cpp +++ b/kmymoney/reports/querytable.cpp @@ -375,15 +375,41 @@ if (qc & MyMoneyReport::eQCprice) m_columns += ",price"; if (qc & MyMoneyReport::eQCperformance) { - m_columns += ",startingbal,buys,sells,reinvestincome,cashincome,return,returninvestment,endingbal"; - m_subtotal = "startingbal,buys,sells,reinvestincome,cashincome,return,returninvestment,endingbal"; + switch (m_config.investmentSum()) { + case MyMoneyReport::eSumOwnedAndSold: + m_columns += ",buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; + m_subtotal = "buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; + break; + case MyMoneyReport::eSumOwned: + m_columns += ",buys,reinvestincome,marketvalue,return,returninvestment"; + m_subtotal = "buys,reinvestincome,marketvalue,return,returninvestment"; + break; + case MyMoneyReport::eSumSold: + m_columns += ",buys,sells,cashincome,return,returninvestment"; + m_subtotal = "buys,sells,cashincome,return,returninvestment"; + break; + case MyMoneyReport::eSumPeriod: + default: + m_columns += ",startingbal,buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; + m_subtotal = "startingbal,buys,sells,reinvestincome,cashincome,endingbal,return,returninvestment"; + break; + } } if (qc & MyMoneyReport::eQCcapitalgain) { - m_columns += ",buys,sells,capitalgain"; - m_subtotal = "buys,sells,capitalgain"; - if (m_config.isShowingSTLTCapitalGains()) { - m_columns += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; - m_subtotal += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; + switch (m_config.investmentSum()) { + case MyMoneyReport::eSumOwned: + m_columns += ",shares,buyprice,lastprice,buys,marketvalue,percentagegain,capitalgain"; + m_subtotal = "buys,marketvalue,percentagegain,capitalgain"; + break; + case MyMoneyReport::eSumSold: + default: + m_columns += ",buys,sells,capitalgain"; + m_subtotal = "buys,sells,capitalgain"; + if (m_config.isShowingSTLTCapitalGains()) { + m_columns += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; + m_subtotal += ",buysST,sellsST,capitalgainST,buysLT,sellsLT,capitalgainLT"; + } + break; } } if (qc & MyMoneyReport::eQCloan) { @@ -485,9 +511,11 @@ // custom total values calculations foreach (auto subtotal, subtotals) { if (subtotal == "returninvestment") - totalsRow[subtotal] = helperROI((*currencyGrp).at(i + 1).value("buys"), (*currencyGrp).at(i + 1).value("sells"), - (*currencyGrp).at(i + 1).value("startingbal"), (*currencyGrp).at(i + 1).value("endingbal"), + totalsRow[subtotal] = helperROI((*currencyGrp).at(i + 1).value("buys") - (*currencyGrp).at(i + 1).value("reinvestincome"), (*currencyGrp).at(i + 1).value("sells"), + (*currencyGrp).at(i + 1).value("startingbal"), (*currencyGrp).at(i + 1).value("endingbal") + (*currencyGrp).at(i + 1).value("marketvalue"), (*currencyGrp).at(i + 1).value("cashincome")).toString(); + else if (subtotal == "percentagegain") + totalsRow[subtotal] = (((*currencyGrp).at(i + 1).value("buys") + (*currencyGrp).at(i + 1).value("marketvalue")) / (*currencyGrp).at(i + 1).value("buys").abs()).toString(); else if (subtotal == "price") totalsRow[subtotal] = MyMoneyMoney((*currencyGrp).at(i + 1).value("price") / (*currencyGrp).at(i + 1).value("rows_count")).toString(); } @@ -543,9 +571,11 @@ foreach (auto subtotal, subtotals) { if (subtotal == "returninvestment") - totalsRow[subtotal] = helperROI((*currencyGrp).at(0).value("buys"), (*currencyGrp).at(0).value("sells"), - (*currencyGrp).at(0).value("startingbal"), (*currencyGrp).at(0).value("endingbal"), + totalsRow[subtotal] = helperROI((*currencyGrp).at(0).value("buys") - (*currencyGrp).at(0).value("reinvestincome"), (*currencyGrp).at(0).value("sells"), + (*currencyGrp).at(0).value("startingbal"), (*currencyGrp).at(0).value("endingbal") + (*currencyGrp).at(0).value("marketvalue"), (*currencyGrp).at(0).value("cashincome")).toString(); + else if (subtotal == "percentagegain") + totalsRow[subtotal] = (((*currencyGrp).at(0).value("buys") + (*currencyGrp).at(0).value("marketvalue")) / (*currencyGrp).at(0).value("buys").abs()).toString(); else if (subtotal == "price") totalsRow[subtotal] = MyMoneyMoney((*currencyGrp).at(0).value("price") / (*currencyGrp).at(0).value("rows_count")).toString(); } @@ -1189,173 +1219,14 @@ return annualReturn; } -void QueryTable::constructPerformanceRow(const ReportAccount& account, TableRow& result, CashFlowList &all) const +void QueryTable::sumInvestmentValues(const ReportAccount& account, QList& cfList, QList& shList) const { - MyMoneyFile* file = MyMoneyFile::instance(); - MyMoneySecurity security; - - //get fraction depending on type of account - int fraction = account.currency().smallestAccountFraction(); - - // - // Calculate performance - // - - // The following columns are created: - // Account, Value on , Buys, Sells, Income, Value on , Return% - - MyMoneyReport report = m_config; - QDate startingDate; - QDate endingDate; - MyMoneyMoney price; - report.validDateRange(startingDate, endingDate); - startingDate = startingDate.addDays(-1); - - //calculate starting balance - if (m_config.isConvertCurrency()) { - price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate); - } else { - price = account.deepCurrencyPrice(startingDate); - } - - //work around if there is no price for the starting balance - if (!(file->balance(account.id(), startingDate)).isZero() - && account.deepCurrencyPrice(startingDate) == MyMoneyMoney::ONE) { - MyMoneyTransactionFilter filter; - //get the transactions for the time before the report - filter.setDateFilter(QDate(), startingDate); - filter.addAccount(account.id()); - filter.setReportAllSplits(true); - - QList startTransactions = file->transactionList(filter); - if (startTransactions.size() > 0) { - //get the last transaction - MyMoneyTransaction startTrans = startTransactions.back(); - MyMoneySplit s = startTrans.splitByAccount(account.id()); - //get the price from the split of that account - price = s.price(); - if (m_config.isConvertCurrency()) - price = price * account.baseCurrencyPrice(startingDate); - } - } - if (m_config.isConvertCurrency()) { - price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate); - } else { - price = account.deepCurrencyPrice(startingDate); - } - - MyMoneyMoney startingBal = file->balance(account.id(), startingDate) * price; + for (int i = InvestmentValue::Buys; i < InvestmentValue::End; ++i) + cfList.append(CashFlowList()); + for (int i = InvestmentValue::Buys; i <= InvestmentValue::BuysOfOwned; ++i) + shList.append(MyMoneyMoney()); - //convert to lowest fraction - startingBal = startingBal.convert(fraction); - - //calculate ending balance - if (m_config.isConvertCurrency()) { - price = account.deepCurrencyPrice(endingDate) * account.baseCurrencyPrice(endingDate); - } else { - price = account.deepCurrencyPrice(endingDate); - } - MyMoneyMoney endingBal = file->balance((account).id(), endingDate) * price; - - //convert to lowest fraction - endingBal = endingBal.convert(fraction); - - CashFlowList buys; - CashFlowList sells; - CashFlowList reinvestincome; - CashFlowList cashincome; - - report.setReportAllSplits(false); - report.setConsiderCategory(true); - report.clearAccountFilter(); - report.addAccount(account.id()); - QList transactions = file->transactionList(report); - QList::const_iterator it_transaction = transactions.constBegin(); - while (it_transaction != transactions.constEnd()) { - // s is the split for the stock account - MyMoneySplit s = (*it_transaction).splitByAccount(account.id()); - - MyMoneySplit assetAccountSplit; - QList feeSplits; - QList interestSplits; - MyMoneySecurity currency; - MyMoneySplit::investTransactionTypeE transactionType; - KMyMoneyUtils::dissectTransaction((*it_transaction), s, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); - - //get price for the day of the transaction if we have to calculate base currency - //we are using the value of the split which is in deep currency - if (m_config.isConvertCurrency()) { - price = account.baseCurrencyPrice((*it_transaction).postDate()); //we only need base currency because the value is in deep currency - } else { - price = MyMoneyMoney::ONE; - } - - MyMoneyMoney value = assetAccountSplit.value() * price; - - if (transactionType == MyMoneySplit::BuyShares) - buys += CashFlowListItem((*it_transaction).postDate(), value); - else if (transactionType == MyMoneySplit::SellShares) - sells += CashFlowListItem((*it_transaction).postDate(), value); - else if (transactionType == MyMoneySplit::ReinvestDividend) { - value = interestSplits.first().value() * price; - reinvestincome += CashFlowListItem((*it_transaction).postDate(), -value); - } else if (transactionType == MyMoneySplit::Dividend || transactionType == MyMoneySplit::Yield) - cashincome += CashFlowListItem((*it_transaction).postDate(), value); - ++it_transaction; - } - // Note that reinvested dividends are not included , because these do not - // represent a cash flow event. - all += buys; - all += sells; - all += cashincome; - all += CashFlowListItem(startingDate, -startingBal); - all += CashFlowListItem(endingDate, endingBal); - - MyMoneyMoney buysTotal = buys.total(); - MyMoneyMoney sellsTotal = sells.total(); - MyMoneyMoney cashIncomeTotal = cashincome.total(); - MyMoneyMoney reinvestIncomeTotal = reinvestincome.total(); - - MyMoneyMoney returnInvestment = helperROI(buysTotal, sellsTotal, startingBal, endingBal, cashIncomeTotal); - MyMoneyMoney annualReturn = helperIRR(all); - - // check if there are any meaningfull values before adding them to results - if (!(buysTotal.isZero() && sellsTotal.isZero() && - cashIncomeTotal.isZero() && reinvestIncomeTotal.isZero() && - startingBal.isZero() && endingBal.isZero())) { - result["return"] = annualReturn.toString(); - result["returninvestment"] = returnInvestment.toString(); - result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); - result["buys"] = buysTotal.toString(); - result["sells"] = sellsTotal.toString(); - result["cashincome"] = cashIncomeTotal.toString(); - result["reinvestincome"] = reinvestIncomeTotal.toString(); - result["startingbal"] = startingBal.toString(); - result["endingbal"] = endingBal.toString(); - } -} - -void QueryTable::constructCapitalGainRow(const ReportAccount& account, TableRow& result) const -{ MyMoneyFile* file = MyMoneyFile::instance(); - MyMoneySecurity security; - MyMoneyMoney price; - MyMoneyMoney sellValue; - MyMoneyMoney buyValue; - MyMoneyMoney sellShares; - MyMoneyMoney buyShares; - - MyMoneyMoney sellLongValue; - MyMoneyMoney buyLongValue; - MyMoneyMoney sellLongShares; - MyMoneyMoney buyLongShares; - - // - // Calculate capital gain - // - - // The following columns are created: - // Account, Buys, Sells, Capital Gain MyMoneyReport report = m_config; QDate startingDate; @@ -1366,23 +1237,28 @@ const int settlementPeriod = report.settlementPeriod(); QDate termSeparator = report.termSeparator().addDays(-settlementPeriod); report.validDateRange(startingDate, endingDate); - // Saturday and Sunday aren't valid settlement dates - if (endingDate.dayOfWeek() == Qt::Saturday) - endingDate.addDays(-1); - else if (endingDate.dayOfWeek() == Qt::Sunday) - endingDate.addDays(-2); - - if (termSeparator.dayOfWeek() == Qt::Saturday) - termSeparator.addDays(-1); - else if (termSeparator.dayOfWeek() == Qt::Sunday) - termSeparator.addDays(-2); - - if (startingDate.daysTo(endingDate) <= settlementPeriod) // no days to check for - return; newStartingDate = startingDate; - newEndingDate = endingDate.addDays(-settlementPeriod); - termSeparator = termSeparator.addDays(-settlementPeriod); - MyMoneyMoney endingShares = file->balance(account.id(), newEndingDate); // get how many shares there are over zero value + newEndingDate = endingDate; + + if (report.queryColumns() & MyMoneyReport::eQCcapitalgain) { + // Saturday and Sunday aren't valid settlement dates + if (endingDate.dayOfWeek() == Qt::Saturday) + endingDate.addDays(-1); + else if (endingDate.dayOfWeek() == Qt::Sunday) + endingDate.addDays(-2); + + if (termSeparator.dayOfWeek() == Qt::Saturday) + termSeparator.addDays(-1); + else if (termSeparator.dayOfWeek() == Qt::Sunday) + termSeparator.addDays(-2); + if (startingDate.daysTo(endingDate) <= settlementPeriod) // no days to check for + return; + termSeparator = termSeparator.addDays(-settlementPeriod); + newEndingDate = endingDate.addDays(-settlementPeriod); + } + + shList[BuysOfOwned] = file->balance(account.id(), newEndingDate); // get how many shares there are at the end of period + MyMoneyMoney stashedBuysOfOwned = shList.at(BuysOfOwned); bool reportedDateRange = true; // flag marking sell transactions between startingDate and endingDate report.setReportAllSplits(false); @@ -1398,143 +1274,365 @@ MyMoneySplit assetAccountSplit; QList feeSplits; QList interestSplits; + MyMoneySecurity security; MyMoneySecurity currency; MyMoneySplit::investTransactionTypeE transactionType; KMyMoneyUtils::dissectTransaction((*it_t), shareSplit, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); + QDate postDate = (*it_t).postDate(); + MyMoneyMoney price; //get price for the day of the transaction if we have to calculate base currency //we are using the value of the split which is in deep currency if (m_config.isConvertCurrency()) - price = account.baseCurrencyPrice((*it_t).postDate()); //we only need base currency because the value is in deep currency + price = account.baseCurrencyPrice(postDate); //we only need base currency because the value is in deep currency else price = MyMoneyMoney::ONE; MyMoneyMoney value = assetAccountSplit.value() * price; MyMoneyMoney shares = shareSplit.shares(); if (transactionType == MyMoneySplit::BuyShares) { - if (endingShares.isZero()) { // add sold shares - if (buyShares + shares > sellShares.abs()) { // add partially sold shares - MyMoneyMoney tempVal = (((sellShares.abs() - buyShares)) / shares) * value; - buyValue += tempVal; - buyShares = sellShares.abs(); - if (isSTLT && (*it_t).postDate() < termSeparator) { - buyLongValue += tempVal; - buyLongShares = buyShares; + if (reportedDateRange) { + cfList[Buys].append(CashFlowListItem(postDate, value)); + shList[Buys] += shares; + } + + if (shList.at(BuysOfOwned).isZero()) { // add sold shares + if (shList.at(BuysOfSells) + shares > shList.at(Sells).abs()) { // add partially sold shares + MyMoneyMoney tempVal = (((shList.at(Sells).abs() - shList.at(BuysOfSells))) / shares) * value; + cfList[BuysOfSells].append(CashFlowListItem(postDate, tempVal)); + shList[BuysOfSells] = shList.at(Sells).abs(); + if (isSTLT && postDate < termSeparator) { + cfList[LongTermBuysOfSells].append(CashFlowListItem(postDate, tempVal)); + shList[LongTermBuysOfSells] = shList.at(BuysOfSells); } - } else { // add wholly sold shares - buyValue += value; - buyShares += shares; - if (isSTLT && (*it_t).postDate() < termSeparator) { - buyLongValue += value; - buyLongShares += shares; + } else { // add wholly sold shares + cfList[BuysOfSells].append(CashFlowListItem(postDate, value)); + shList[BuysOfSells] += shares; + if (isSTLT && postDate < termSeparator) { + cfList[LongTermBuysOfSells].append(CashFlowListItem(postDate, value)); + shList[LongTermBuysOfSells] += shares; } } - } else if (endingShares >= shares) { // substract not-sold shares - endingShares -= shares; - } else { // substract partially not-sold shares - MyMoneyMoney tempVal = ((shares - endingShares) / shares) * value; - MyMoneyMoney tempVal2 = (shares - endingShares); - buyValue += tempVal; - buyShares += tempVal2; - if (isSTLT && (*it_t).postDate() < termSeparator) { - buyLongValue += tempVal; - buyLongShares += tempVal2; + } else if (shList.at(BuysOfOwned) >= shares) { // substract not-sold shares + shList[BuysOfOwned] -= shares; + cfList[BuysOfOwned].append(CashFlowListItem(postDate, value)); + } else { // substract partially not-sold shares + MyMoneyMoney tempVal = ((shares - shList.at(BuysOfOwned)) / shares) * value; + MyMoneyMoney tempVal2 = (shares - shList.at(BuysOfOwned)); + cfList[BuysOfSells].append(CashFlowListItem(postDate, tempVal)); + shList[BuysOfSells] += tempVal2; + if (isSTLT && postDate < termSeparator) { + cfList[LongTermBuysOfSells].append(CashFlowListItem(postDate, tempVal)); + shList[LongTermBuysOfSells] += tempVal2; } - endingShares = MyMoneyMoney(); + cfList[BuysOfOwned].append(CashFlowListItem(postDate, (shList.at(BuysOfOwned) / shares) * value)); + shList[BuysOfOwned] = MyMoneyMoney(); } } else if (transactionType == MyMoneySplit::SellShares && reportedDateRange) { - sellValue += value; - sellShares += shares; - } else if (transactionType == MyMoneySplit::SplitShares) { // shares variable is denominator of split ratio here - sellShares /= shares; - buyShares /= shares; - buyLongShares /= shares; - } else if (transactionType == MyMoneySplit::AddShares) { // added shares, when sold give 100% capital gain - if (endingShares.isZero()) { // add added shares - if (buyShares + shares > sellShares.abs()) { // add partially added shares - buyShares = sellShares.abs(); - if ((*it_t).postDate() < termSeparator) - buyLongShares = buyShares; - } else { // add wholly added shares - buyShares += shares; - if ((*it_t).postDate() < termSeparator) - buyLongShares += shares; + cfList[Sells].append(CashFlowListItem(postDate, value)); + shList[Sells] += shares; + } else if (transactionType == MyMoneySplit::SplitShares) { // shares variable is denominator of split ratio here + for (int i = Buys; i <= InvestmentValue::BuysOfOwned; ++i) + shList[i] /= shares; + } else if (transactionType == MyMoneySplit::AddShares || // added shares, when sold give 100% capital gain + transactionType == MyMoneySplit::ReinvestDividend) { + if (shList.at(BuysOfOwned).isZero()) { // add added/reinvested shares + if (shList.at(BuysOfSells) + shares > shList.at(Sells).abs()) { // add partially added/reinvested shares + shList[BuysOfSells] = shList.at(Sells).abs(); + if (postDate < termSeparator) + shList[LongTermBuysOfSells] = shList[BuysOfSells]; + } else { // add wholly added/reinvested shares + shList[BuysOfSells] += shares; + if (postDate < termSeparator) + shList[LongTermBuysOfSells] += shares; } - } else if (endingShares >= shares) { // substract not-added shares - endingShares -= shares; - } else { // substract partially not-added shares - MyMoneyMoney tempVal = (shares - endingShares); - buyShares += tempVal; - if ((*it_t).postDate() < termSeparator) - buyLongShares += tempVal; - endingShares = MyMoneyMoney(); + } else if (shList.at(BuysOfOwned) >= shares) { // substract not-added/not-reinvested shares + shList[BuysOfOwned] -= shares; + cfList[BuysOfOwned].append(CashFlowListItem(postDate, value)); + } else { // substract partially not-added/not-reinvested shares + MyMoneyMoney tempVal = (shares - shList.at(BuysOfOwned)); + shList[BuysOfSells] += tempVal; + if (postDate < termSeparator) + shList[LongTermBuysOfSells] += tempVal; + + cfList[BuysOfOwned].append(CashFlowListItem(postDate, (shList.at(BuysOfOwned) / shares) * value)); + shList[BuysOfOwned] = MyMoneyMoney(); } - } else if (transactionType == MyMoneySplit::RemoveShares && reportedDateRange) { // removed shares give no value in return so no capital gain on them - sellShares += shares; - } + qDebug() << "szeres: " << shares.toDouble() << "prais: " << price.toDouble() << "value:" << value.toDouble(); + if (transactionType == MyMoneySplit::ReinvestDividend) { + value = MyMoneyMoney(); + foreach (const auto split, interestSplits) + value += split.value(); + value *= price; + cfList[ReinvestIncome].append(CashFlowListItem(postDate, -value)); + } + } else if (transactionType == MyMoneySplit::RemoveShares && reportedDateRange) // removed shares give no value in return so no capital gain on them + shList[Sells] += shares; + else if (transactionType == MyMoneySplit::Dividend || transactionType == MyMoneySplit::Yield) + cfList[CashIncome].append(CashFlowListItem(postDate, value)); + } reportedDateRange = false; newEndingDate = newStartingDate; newStartingDate = newStartingDate.addYears(-1); report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier - } while (!sellShares.isZero() && account.openingDate() <= newEndingDate && sellShares.abs() > buyShares.abs()); + + } while ( + ( + (report.investmentSum() == MyMoneyReport::eSumOwned && !shList[BuysOfOwned].isZero()) || + (report.investmentSum() == MyMoneyReport::eSumSold && !shList.at(Sells).isZero() && shList.at(Sells).abs() > shList.at(BuysOfSells).abs()) || + (report.investmentSum() == MyMoneyReport::eSumOwnedAndSold && (!shList[BuysOfOwned].isZero() || (!shList.at(Sells).isZero() && shList.at(Sells).abs() > shList.at(BuysOfSells).abs()))) + ) && account.openingDate() <= newEndingDate + ); // we've got buy value and no sell value of long-term shares, so get them - if (isSTLT && !buyLongShares.isZero()) { + if (isSTLT && !shList[LongTermBuysOfSells].isZero()) { newStartingDate = startingDate; newEndingDate = endingDate.addDays(-settlementPeriod); report.setDateFilter(newStartingDate, newEndingDate); // search for matching buy transactions year earlier QList transactions = file->transactionList(report); - endingShares = buyLongShares; + shList[BuysOfOwned] = shList[LongTermBuysOfSells]; foreach (const auto transaction, transactions) { MyMoneySplit shareSplit = transaction.splitByAccount(account.id()); MyMoneySplit assetAccountSplit; QList feeSplits; QList interestSplits; + MyMoneySecurity security; MyMoneySecurity currency; MyMoneySplit::investTransactionTypeE transactionType; KMyMoneyUtils::dissectTransaction(transaction, shareSplit, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); + QDate postDate = transaction.postDate(); + MyMoneyMoney price; if (m_config.isConvertCurrency()) - price = account.baseCurrencyPrice(transaction.postDate()); //we only need base currency because the value is in deep currency + price = account.baseCurrencyPrice(postDate); //we only need base currency because the value is in deep currency else price = MyMoneyMoney::ONE; MyMoneyMoney value = assetAccountSplit.value() * price; MyMoneyMoney shares = shareSplit.shares(); + if (transactionType == MyMoneySplit::SellShares) { - if ((sellLongShares + shares).abs() >= buyLongShares) { // add partially sold long-term shares - sellLongValue += (sellLongShares.abs() - buyLongShares) / shares * value; - sellLongShares = buyLongShares; + if ((shList.at(LongTermSellsOfBuys) + shares).abs() >= shList.at(LongTermBuysOfSells)) { // add partially sold long-term shares + cfList[LongTermSellsOfBuys].append(CashFlowListItem(postDate, (shList.at(LongTermSellsOfBuys).abs() - shList.at(LongTermBuysOfSells)) / shares * value)); + shList[LongTermSellsOfBuys] = shList.at(LongTermBuysOfSells); break; } else { // add wholly sold long-term shares - sellLongValue += value; - sellLongShares += shares; + cfList[LongTermSellsOfBuys].append(CashFlowListItem(postDate, value)); + shList[LongTermSellsOfBuys] += shares; } } else if (transactionType == MyMoneySplit::RemoveShares) { - if ((sellLongShares + shares).abs() >= buyLongShares) { - sellLongShares = buyLongShares; + if ((shList.at(LongTermSellsOfBuys) + shares).abs() >= shList.at(LongTermBuysOfSells)) { + shList[LongTermSellsOfBuys] = shList.at(LongTermBuysOfSells); break; } else - sellLongShares += shares; + shList[LongTermSellsOfBuys] += shares; } } } - // check if there are any meaningfull values before adding them to results - if (!(buyValue.isZero() && sellValue.isZero())) { - result["equitytype"] = KMyMoneyUtils::securityTypeToString(security.securityType()); - result["buys"] = buyValue.toString(); - result["sells"] = sellValue.toString(); - result["capitalgain"] = (buyValue + sellValue).toString(); - if (isSTLT) { - result["buysLT"] = buyLongValue.toString(); - result["sellsLT"] = sellLongValue.toString(); - result["capitalgainLT"] = (buyLongValue + sellLongValue).toString(); - result["buysST"] = (buyValue - buyLongValue).toString(); - result["sellsST"] = (sellValue - sellLongValue).toString(); - result["capitalgainST"] = ((buyValue - buyLongValue) + (sellValue - sellLongValue)).toString(); + shList[BuysOfOwned] = stashedBuysOfOwned; + report.setDateFilter(startingDate, endingDate); // reset data filter for next security + return; +} + +void QueryTable::constructPerformanceRow(const ReportAccount& account, TableRow& result, CashFlowList &all) const +{ + MyMoneyReport report = m_config; + QDate startingDate; + QDate endingDate; + report.validDateRange(startingDate, endingDate); + startingDate = startingDate.addDays(-1); + + MyMoneyFile* file = MyMoneyFile::instance(); + //get fraction depending on type of account + int fraction = account.currency().smallestAccountFraction(); + MyMoneyMoney price; + if (m_config.isConvertCurrency()) + price = account.deepCurrencyPrice(startingDate) * account.baseCurrencyPrice(startingDate); + else + price = account.deepCurrencyPrice(startingDate); + + MyMoneyMoney startingBal = file->balance(account.id(), startingDate) * price; + + //convert to lowest fraction + startingBal = startingBal.convert(fraction); + + //calculate ending balance + if (m_config.isConvertCurrency()) + price = account.deepCurrencyPrice(endingDate) * account.baseCurrencyPrice(endingDate); + else + price = account.deepCurrencyPrice(endingDate); + + MyMoneyMoney endingBal = file->balance((account).id(), endingDate) * price; + + //convert to lowest fraction + endingBal = endingBal.convert(fraction); + + QList cfList; + QList shList; + sumInvestmentValues(account, cfList, shList); + + MyMoneyMoney buysTotal; + MyMoneyMoney sellsTotal; + MyMoneyMoney cashIncomeTotal; + MyMoneyMoney reinvestIncomeTotal; + + switch (m_config.investmentSum()) { + case MyMoneyReport::eSumOwnedAndSold: + buysTotal = cfList.at(BuysOfSells).total() + cfList.at(BuysOfOwned).total(); + sellsTotal = cfList.at(Sells).total(); + cashIncomeTotal = cfList.at(CashIncome).total(); + reinvestIncomeTotal = cfList.at(ReinvestIncome).total(); + startingBal = MyMoneyMoney(); + if (buysTotal.isZero() && sellsTotal.isZero() && + cashIncomeTotal.isZero() && reinvestIncomeTotal.isZero()) + return; + + all.append(cfList.at(BuysOfSells)); + all.append(cfList.at(BuysOfOwned)); + all.append(cfList.at(Sells)); + all.append(cfList.at(CashIncome)); + + result[QLatin1String("sells")] = sellsTotal.toString(); + result[QLatin1String("cashincome")] = cashIncomeTotal.toString(); + result[QLatin1String("reinvestincome")] = reinvestIncomeTotal.toString(); + result[QLatin1String("endingbal")] = endingBal.toString(); + break; + case MyMoneyReport::eSumOwned: + buysTotal = cfList.at(BuysOfOwned).total(); + startingBal = MyMoneyMoney(); + if (buysTotal.isZero() && endingBal.isZero()) + return; + all.append(cfList.at(BuysOfOwned)); + all.append(CashFlowListItem(endingDate, endingBal)); + + result[QLatin1String("reinvestincome")] = reinvestIncomeTotal.toString(); + result[QLatin1String("marketvalue")] = endingBal.toString(); + break; + case MyMoneyReport::eSumSold: + buysTotal = cfList.at(BuysOfSells).total(); + sellsTotal = cfList.at(Sells).total(); + cashIncomeTotal = cfList.at(CashIncome).total(); + startingBal = endingBal = MyMoneyMoney(); + // check if there are any meaningfull values before adding them to results + if (buysTotal.isZero() && sellsTotal.isZero() && cashIncomeTotal.isZero()) + return; + all.append(cfList.at(BuysOfSells)); + all.append(cfList.at(Sells)); + all.append(cfList.at(CashIncome)); + + result[QLatin1String("sells")] = sellsTotal.toString(); + result[QLatin1String("cashincome")] = cashIncomeTotal.toString(); + break; + case MyMoneyReport::eSumPeriod: + default: + buysTotal = cfList.at(Buys).total(); + sellsTotal = cfList.at(Sells).total(); + cashIncomeTotal = cfList.at(CashIncome).total(); + reinvestIncomeTotal = cfList.at(ReinvestIncome).total(); + if (buysTotal.isZero() && sellsTotal.isZero() && + cashIncomeTotal.isZero() && reinvestIncomeTotal.isZero() && + startingBal.isZero() && endingBal.isZero()) + return; + + all.append(cfList.at(Buys)); + all.append(cfList.at(Sells)); + all.append(cfList.at(CashIncome)); + all.append(CashFlowListItem(startingDate, -startingBal)); + all.append(CashFlowListItem(endingDate, endingBal)); + + result[QLatin1String("sells")] = sellsTotal.toString(); + result[QLatin1String("cashincome")] = cashIncomeTotal.toString(); + result[QLatin1String("reinvestincome")] = reinvestIncomeTotal.toString(); + result[QLatin1String("startingbal")] = startingBal.toString(); + result[QLatin1String("endingbal")] = endingBal.toString(); + break; + } + + MyMoneyMoney returnInvestment = helperROI(buysTotal - reinvestIncomeTotal, sellsTotal, startingBal, endingBal, cashIncomeTotal); + MyMoneyMoney annualReturn = helperIRR(all); + + result[QLatin1String("buys")] = buysTotal.toString(); + result[QLatin1String("return")] = annualReturn.toString(); + result[QLatin1String("returninvestment")] = returnInvestment.toString(); + result[QLatin1String("equitytype")] = KMyMoneyUtils::securityTypeToString(file->security(account.currencyId()).securityType()); +} + +void QueryTable::constructCapitalGainRow(const ReportAccount& account, TableRow& result) const +{ + MyMoneyFile* file = MyMoneyFile::instance(); + QList cfList; + QList shList; + sumInvestmentValues(account, cfList, shList); + + MyMoneyMoney buysTotal = cfList.at(BuysOfSells).total(); + MyMoneyMoney sellsTotal = cfList.at(Sells).total(); + MyMoneyMoney longTermBuysOfSellsTotal = cfList.at(LongTermBuysOfSells).total(); + MyMoneyMoney longTermSellsOfBuys = cfList.at(LongTermSellsOfBuys).total(); + + switch (m_config.investmentSum()) { + case MyMoneyReport::eSumOwned: + { + if (shList.at(BuysOfOwned).isZero()) + return; + + MyMoneyReport report = m_config; + QDate startingDate; + QDate endingDate; + report.validDateRange(startingDate, endingDate); + + //get fraction depending on type of account + int fraction = account.currency().smallestAccountFraction(); + MyMoneyMoney price; + + //calculate ending balance + if (m_config.isConvertCurrency()) + price = account.deepCurrencyPrice(endingDate) * account.baseCurrencyPrice(endingDate); + else + price = account.deepCurrencyPrice(endingDate); + + MyMoneyMoney endingBal = shList.at(BuysOfOwned) * price; + + //convert to lowest fraction + endingBal = endingBal.convert(fraction); + + buysTotal = cfList.at(BuysOfOwned).total() - cfList.at(ReinvestIncome).total(); + + int pricePrecision = file->security(account.currencyId()).pricePrecision(); + result[QLatin1String("buys")] = buysTotal.toString(); + result[QLatin1String("shares")] = shList.at(BuysOfOwned).toString(); + result[QLatin1String("buyprice")] = (buysTotal.abs() / shList.at(BuysOfOwned)).convertPrecision(pricePrecision).toString(); + result[QLatin1String("lastprice")] = price.toString(); + result[QLatin1String("marketvalue")] = endingBal.toString(); + result[QLatin1String("capitalgain")] = (buysTotal + endingBal).toString(); + result[QLatin1String("percentagegain")] = ((buysTotal + endingBal)/buysTotal.abs()).toString(); + break; + } + case MyMoneyReport::eSumSold: + default: + buysTotal = cfList.at(BuysOfSells).total() - cfList.at(ReinvestIncome).total(); + sellsTotal = cfList.at(Sells).total(); + longTermBuysOfSellsTotal = cfList.at(LongTermBuysOfSells).total(); + longTermSellsOfBuys = cfList.at(LongTermSellsOfBuys).total(); + // check if there are any meaningfull values before adding them to results + if (buysTotal.isZero() && sellsTotal.isZero() && + longTermBuysOfSellsTotal.isZero() && longTermSellsOfBuys.isZero()) + return; + + result[QLatin1String("buys")] = buysTotal.toString(); + result[QLatin1String("sells")] = sellsTotal.toString(); + result[QLatin1String("capitalgain")] = (buysTotal + sellsTotal).toString(); + if (m_config.isShowingSTLTCapitalGains()) { + result[QLatin1String("buysLT")] = longTermBuysOfSellsTotal.toString(); + result[QLatin1String("sellsLT")] = longTermSellsOfBuys.toString(); + result[QLatin1String("capitalgainLT")] = (longTermBuysOfSellsTotal + longTermSellsOfBuys).toString(); + result[QLatin1String("buysST")] = (buysTotal - longTermBuysOfSellsTotal).toString(); + result[QLatin1String("sellsST")] = (sellsTotal - longTermSellsOfBuys).toString(); + result[QLatin1String("capitalgainST")] = ((buysTotal - longTermBuysOfSellsTotal) + (sellsTotal - longTermSellsOfBuys)).toString(); } + break; } - report.setDateFilter(startingDate, endingDate); // reset data filter for next security + + result[QLatin1String("equitytype")] = KMyMoneyUtils::securityTypeToString(file->security(account.currencyId()).securityType()); } void QueryTable::constructAccountTable() diff --git a/kmymoney/widgets/CMakeLists.txt b/kmymoney/widgets/CMakeLists.txt --- a/kmymoney/widgets/CMakeLists.txt +++ b/kmymoney/widgets/CMakeLists.txt @@ -172,7 +172,7 @@ reporttabgeneral.ui reporttabrowcolquery.ui reporttabrowcolpivot.ui reporttabrange.ui reporttabchart.ui - reporttabcapitalgain.ui + reporttabcapitalgain.ui reporttabperformance.ui daterangedlgdecl.ui ) diff --git a/kmymoney/widgets/reporttabcapitalgain.ui b/kmymoney/widgets/reporttabcapitalgain.ui --- a/kmymoney/widgets/reporttabcapitalgain.ui +++ b/kmymoney/widgets/reporttabcapitalgain.ui @@ -7,7 +7,7 @@ 0 0 441 - 102 + 166 @@ -22,7 +22,45 @@ - + + + + Settlement period + + + + + + + Terms separator + + + + + + + + + + Before this date investments are counted as long-term investments. + + + + + + + Show short-term and long-term capital gains + + + + + + + Sum investments + + + + Time in days between the settlement date and the transaction date. @@ -35,21 +73,17 @@ - - - - Settlement period - - + + - - - - Before this date investments are counted as long-term investments. + + + + Hide Totals - + Qt::Horizontal @@ -62,20 +96,10 @@ - - - - Terms separator - - - - - - - - + + - Show short-term and long-term capital gains + diff --git a/kmymoney/widgets/reporttabimpl.h b/kmymoney/widgets/reporttabimpl.h --- a/kmymoney/widgets/reporttabimpl.h +++ b/kmymoney/widgets/reporttabimpl.h @@ -33,6 +33,7 @@ class ReportTabChart; class ReportTabRange; class ReportTabCapitalGain; +class ReportTabPerformance; } class ReportTabGeneral : public QWidget @@ -96,10 +97,21 @@ class ReportTabCapitalGain : public QWidget { + Q_OBJECT public: ReportTabCapitalGain(QWidget *parent); virtual ~ReportTabCapitalGain(); Ui::ReportTabCapitalGain* ui; +private slots: + void slotInvestmentSumChanged(int index); +}; + +class ReportTabPerformance : public QWidget +{ +public: + ReportTabPerformance(QWidget *parent); + virtual ~ReportTabPerformance(); + Ui::ReportTabPerformance* ui; }; class MyDoubleValidator : public QDoubleValidator diff --git a/kmymoney/widgets/reporttabimpl.cpp b/kmymoney/widgets/reporttabimpl.cpp --- a/kmymoney/widgets/reporttabimpl.cpp +++ b/kmymoney/widgets/reporttabimpl.cpp @@ -29,6 +29,7 @@ #include "ui_reporttabchart.h" #include "ui_reporttabrange.h" #include "ui_reporttabcapitalgain.h" +#include "ui_reporttabperformance.h" #include #include "mymoney/mymoneyreport.h" @@ -262,10 +263,37 @@ { ui = new Ui::ReportTabCapitalGain; ui->setupUi(this); + connect(ui->m_investmentSum, SIGNAL(currentIndexChanged(int)), this, SLOT(slotInvestmentSumChanged(int))); } ReportTabCapitalGain::~ReportTabCapitalGain() { delete ui; } +void ReportTabCapitalGain::slotInvestmentSumChanged(int index) { + Q_UNUSED(index); + if (ui->m_investmentSum->currentData() == MyMoneyReport::eSumOwned) { + ui->m_settlementPeriod->setValue(0); + ui->m_settlementPeriod->setEnabled(false); + ui->m_showSTLTCapitalGains->setChecked(false); + ui->m_showSTLTCapitalGains->setEnabled(false); + ui->m_termSeparator->setEnabled(false); + } else { + ui->m_settlementPeriod->setEnabled(true); + ui->m_showSTLTCapitalGains->setEnabled(true); + ui->m_termSeparator->setEnabled(true); + } +} + +ReportTabPerformance::ReportTabPerformance(QWidget *parent) + : QWidget(parent) +{ + ui = new Ui::ReportTabPerformance; + ui->setupUi(this); +} + +ReportTabPerformance::~ReportTabPerformance() +{ + delete ui; +} diff --git a/kmymoney/widgets/reporttabcapitalgain.ui b/kmymoney/widgets/reporttabperformance.ui copy from kmymoney/widgets/reporttabcapitalgain.ui copy to kmymoney/widgets/reporttabperformance.ui --- a/kmymoney/widgets/reporttabcapitalgain.ui +++ b/kmymoney/widgets/reporttabperformance.ui @@ -1,13 +1,13 @@ - ReportTabCapitalGain - + ReportTabPerformance + 0 0 441 - 102 + 84 @@ -23,29 +23,12 @@ - - - Time in days between the settlement date and the transaction date. - - - 30 - - - 3 - - + - + - Settlement period - - - - - - - Before this date investments are counted as long-term investments. + Sum investments @@ -62,20 +45,17 @@ - - + + - Terms separator + - - - - + - Show short-term and long-term capital gains + Hide Totals @@ -100,13 +80,6 @@ - - - kMyMoneyDateInput - QWidget -
kmymoneydateinput.h
-
-