diff options
Diffstat (limited to 'kmymoney2/reports/objectinfotable.cpp')
-rw-r--r-- | kmymoney2/reports/objectinfotable.cpp | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/kmymoney2/reports/objectinfotable.cpp b/kmymoney2/reports/objectinfotable.cpp new file mode 100644 index 0000000..649f6c2 --- /dev/null +++ b/kmymoney2/reports/objectinfotable.cpp @@ -0,0 +1,368 @@ +/*************************************************************************** + objectinfotable.cpp + ------------------- + begin : Sat 28 jun 2008 + copyright : (C) 2004-2005 by Ace Jones + 2008 by Alvaro Soliverez + email : acejones@users.sourceforge.net + asoliverez@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +// ---------------------------------------------------------------------------- +// QT Includes +#include <qvaluelist.h> +#include <qfile.h> +#include <qtextstream.h> + +// ---------------------------------------------------------------------------- +// KDE Includes +// This is just needed for i18n(). Once I figure out how to handle i18n +// without using this macro directly, I'll be freed of KDE dependency. + +#include <klocale.h> +#include <kdebug.h> + +// ---------------------------------------------------------------------------- +// Project Includes +#include "../mymoney/mymoneyfile.h" +#include "../mymoney/mymoneyreport.h" +#include "../mymoney/mymoneyexception.h" +#include "../kmymoneyutils.h" +#include "reportaccount.h" +#include "reportdebug.h" +#include "objectinfotable.h" + +namespace reports { + +// **************************************************************************** +// +// ObjectInfoTable implementation +// +// **************************************************************************** + +/** + * TODO + * + * - Collapse 2- & 3- groups when they are identical + * - Way more test cases (especially splits & transfers) + * - Option to collapse splits + * - Option to exclude transfers + * + */ + +ObjectInfoTable::ObjectInfoTable(const MyMoneyReport& _report): ListTable(_report) +{ + // seperated into its own method to allow debugging (setting breakpoints + // directly in ctors somehow does not work for me (ipwizard)) + // TODO: remove the init() method and move the code back to the ctor + init(); +} + +void ObjectInfoTable::init ( void ) +{ + switch ( m_config.rowType() ) + { + case MyMoneyReport::eSchedule: + constructScheduleTable(); + m_columns = "nextduedate,name"; + break; + case MyMoneyReport::eAccountInfo: + constructAccountTable(); + m_columns = "institution,type,name"; + break; + case MyMoneyReport::eAccountLoanInfo: + constructAccountLoanTable(); + m_columns = "institution,type,name"; + break; + default: + break; + } + + // Sort the data to match the report definition + m_subtotal="value"; + + switch ( m_config.rowType() ) + { + case MyMoneyReport::eSchedule: + m_group = "type"; + m_subtotal="value"; + break; + case MyMoneyReport::eAccountInfo: + case MyMoneyReport::eAccountLoanInfo: + m_group = "topcategory,institution"; + m_subtotal="currentbalance"; + break; + default: + throw new MYMONEYEXCEPTION ( "ObjectInfoTable::ObjectInfoTable(): unhandled row type" ); + } + + QString sort = m_group + "," + m_columns + ",id,rank"; + + switch ( m_config.rowType() ) { + case MyMoneyReport::eSchedule: + if ( m_config.detailLevel() == MyMoneyReport::eDetailAll ) { + m_columns="name,payee,paymenttype,occurence,nextduedate,category"; + } else { + m_columns="name,payee,paymenttype,occurence,nextduedate"; + } + break; + case MyMoneyReport::eAccountInfo: + m_columns="type,name,number,description,openingdate,currencyname,balancewarning,maxbalancelimit,creditwarning,maxcreditlimit,tax,favorite"; + break; + case MyMoneyReport::eAccountLoanInfo: + m_columns="type,name,number,description,openingdate,currencyname,payee,loanamount,interestrate,nextinterestchange,periodicpayment,finalpayment,favorite"; + break; + default: + m_columns = ""; + } + + TableRow::setSortCriteria ( sort ); + qHeapSort ( m_rows ); +} + +void ObjectInfoTable::constructScheduleTable ( void ) +{ + MyMoneyFile* file = MyMoneyFile::instance(); + + QValueList<MyMoneySchedule> schedules; + + schedules = file->scheduleList ( "", MyMoneySchedule::TYPE_ANY, MyMoneySchedule::OCCUR_ANY, MyMoneySchedule::STYPE_ANY, m_config.fromDate(), m_config.toDate() ); + + QValueList<MyMoneySchedule>::const_iterator it_schedule = schedules.begin(); + while ( it_schedule != schedules.end() ) + { + MyMoneySchedule schedule = *it_schedule; + + ReportAccount account = schedule.account(); + + if ( m_config.includes ( account ) ) { + //get fraction for account + int fraction = account.fraction(); + + //use base currency fraction if not initialized + if ( fraction == -1 ) + fraction = MyMoneyFile::instance()->baseCurrency().smallestAccountFraction(); + + TableRow scheduleRow; + + //convert to base currency if needed + MyMoneyMoney xr = MyMoneyMoney(1,1); + if (m_config.isConvertCurrency() && account.isForeignCurrency()) { + xr = account.baseCurrencyPrice(QDate::currentDate()).reduce(); + } + + // help for sort and render functions + scheduleRow["rank"] = "0"; + + //schedule data + scheduleRow["id"] = schedule.id(); + scheduleRow["name"] = schedule.name(); + scheduleRow["nextduedate"] = schedule.nextDueDate().toString ( Qt::ISODate ); + scheduleRow["type"] = KMyMoneyUtils::scheduleTypeToString ( schedule.type() ); + scheduleRow["occurence"] = i18n( schedule.occurenceToString() ); + scheduleRow["paymenttype"] = KMyMoneyUtils::paymentMethodToString ( schedule.paymentType() ); + + //scheduleRow["category"] = account.name(); + + //to get the payee we must look into the splits of the transaction + MyMoneyTransaction transaction = schedule.transaction(); + MyMoneySplit split = transaction.splitByAccount ( account.id(), true ); + scheduleRow["value"] = (split.value() * xr).toString(); + MyMoneyPayee payee = file->payee ( split.payeeId() ); + scheduleRow["payee"] = payee.name(); + m_rows += scheduleRow; + + //the text matches the main split + bool transaction_text = m_config.match(&split); + + if ( m_config.detailLevel() == MyMoneyReport::eDetailAll ) + { + //get the information for all splits + QValueList<MyMoneySplit> splits = transaction.splits(); + QValueList<MyMoneySplit>::const_iterator split_it = splits.begin(); + for ( ;split_it != splits.end(); split_it++ ) + { + TableRow splitRow; + ReportAccount splitAcc = ( *split_it ).accountId(); + + splitRow["rank"] = "1"; + splitRow["id"] = schedule.id(); + splitRow["name"] = schedule.name(); + splitRow["type"] = KMyMoneyUtils::scheduleTypeToString ( schedule.type() ); + splitRow["nextduedate"] = schedule.nextDueDate().toString ( Qt::ISODate ); + + if ( ( *split_it ).value() == MyMoneyMoney::autoCalc ) { + splitRow["split"] = MyMoneyMoney::autoCalc.toString(); + } else if ( ! splitAcc.isIncomeExpense() ) { + splitRow["split"] = ( *split_it ).value().toString(); + } else { + splitRow["split"] = ( - ( *split_it ).value() ).toString(); + } + + //if it is an assett account, mark it as a transfer + if ( ! splitAcc.isIncomeExpense() ) { + splitRow["category"] = ( ( * split_it ).value().isNegative() ) + ? i18n ( "Transfer from %1" ).arg ( splitAcc.fullName() ) + : i18n ( "Transfer to %1" ).arg ( splitAcc.fullName() ); + } else { + splitRow ["category"] = splitAcc.fullName(); + } + + //add the split only if it matches the text or it matches the main split + if(m_config.match( &(*split_it) ) + || transaction_text ) + m_rows += splitRow; + } + } + } + ++it_schedule; + } +} + +void ObjectInfoTable::constructAccountTable ( void ) +{ + MyMoneyFile* file = MyMoneyFile::instance(); + + //make sure we have all subaccounts of investment accounts + includeInvestmentSubAccounts(); + + QValueList<MyMoneyAccount> accounts; + file->accountList(accounts); + QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin(); + while ( it_account != accounts.end() ) + { + TableRow accountRow; + ReportAccount account = *it_account; + + if(m_config.includes(account) + && account.accountType() != MyMoneyAccount::Stock + && !account.isClosed()) + { + MyMoneyMoney value; + accountRow["rank"] = "0"; + accountRow["topcategory"] = KMyMoneyUtils::accountTypeToString(account.accountGroup()); + accountRow["institution"] = (file->institution(account.institutionId())).name(); + accountRow["type"] = KMyMoneyUtils::accountTypeToString(account.accountType()); + accountRow["name"] = account.name(); + accountRow["number"] = account.number(); + accountRow["description"] = account.description(); + accountRow["openingdate"] = account.openingDate().toString( Qt::ISODate ); + //accountRow["currency"] = (file->currency(account.currencyId())).tradingSymbol(); + accountRow["currencyname"] = (file->currency(account.currencyId())).name(); + accountRow["balancewarning"] = account.value("minBalanceEarly"); + accountRow["maxbalancelimit"] = account.value("minBalanceAbsolute"); + accountRow["creditwarning"] = account.value("maxCreditEarly"); + accountRow["maxcreditlimit"] = account.value("maxCreditAbsolute"); + accountRow["tax"] = account.value("Tax"); + accountRow["favorite"] = account.value("PreferredAccount"); + + //investment accounts show the balances of all its subaccounts + if(account.accountType() == MyMoneyAccount::Investment) { + value = investmentBalance(account); + } else { + value = file->balance(account.id()); + } + + //convert to base currency if needed + if (m_config.isConvertCurrency() && account.isForeignCurrency()) { + MyMoneyMoney xr = account.baseCurrencyPrice(QDate::currentDate()).reduce(); + value = value * xr; + } + accountRow["currentbalance"] = value.toString(); + + m_rows += accountRow; + } + ++it_account; + } +} + +void ObjectInfoTable::constructAccountLoanTable ( void ) +{ + MyMoneyFile* file = MyMoneyFile::instance(); + + QValueList<MyMoneyAccount> accounts; + file->accountList(accounts); + QValueList<MyMoneyAccount>::const_iterator it_account = accounts.begin(); + while ( it_account != accounts.end() ) + { + TableRow accountRow; + ReportAccount account = *it_account; + MyMoneyAccountLoan loan = *it_account; + + if(m_config.includes(account) && + ( account.accountType() == MyMoneyAccount::Loan + || account.accountType() == MyMoneyAccount::AssetLoan ) + && !account.isClosed()) + { + //convert to base currency if needed + MyMoneyMoney xr = MyMoneyMoney(1,1); + if (m_config.isConvertCurrency() && account.isForeignCurrency()) { + xr = account.baseCurrencyPrice(QDate::currentDate()).reduce(); + } + + accountRow["rank"] = "0"; + accountRow["topcategory"] = KMyMoneyUtils::accountTypeToString(account.accountGroup()); + accountRow["institution"] = (file->institution(account.institutionId())).name(); + accountRow["type"] = KMyMoneyUtils::accountTypeToString(account.accountType()); + accountRow["name"] = account.name(); + accountRow["number"] = account.number(); + accountRow["description"] = account.description(); + accountRow["openingdate"] = account.openingDate().toString( Qt::ISODate ); + //accountRow["currency"] = (file->currency(account.currencyId())).tradingSymbol(); + accountRow["currencyname"] = (file->currency(account.currencyId())).name(); + accountRow["payee"] = file->payee(loan.payee()).name(); + accountRow["loanamount"] = (loan.loanAmount() * xr).toString(); + accountRow["interestrate"] = (loan.interestRate(QDate::currentDate())/MyMoneyMoney(100,1)*xr).toString(); + accountRow["nextinterestchange"] = loan.nextInterestChange().toString( Qt::ISODate ); + accountRow["periodicpayment"] = (loan.periodicPayment() * xr).toString(); + accountRow["finalpayment"] = (loan.finalPayment() * xr).toString(); + accountRow["favorite"] = account.value("PreferredAccount"); + + MyMoneyMoney value = file->balance(account.id()); + value = value * xr; + accountRow["currentbalance"] = value.toString(); + m_rows += accountRow; + } + ++it_account; + } +} + +MyMoneyMoney ObjectInfoTable::investmentBalance(const MyMoneyAccount& acc) +{ + MyMoneyFile* file = MyMoneyFile::instance(); + MyMoneyMoney value; + + value = file->balance(acc.id()); + QValueList<QString>::const_iterator it_a; + for(it_a = acc.accountList().begin(); it_a != acc.accountList().end(); ++it_a) { + MyMoneyAccount stock = file->account(*it_a); + try { + MyMoneyMoney val; + MyMoneyMoney balance = file->balance(stock.id()); + MyMoneySecurity security = file->security(stock.currencyId()); + MyMoneyPrice price = file->price(stock.currencyId(), security.tradingCurrency()); + val = balance * price.rate(security.tradingCurrency()); + // adjust value of security to the currency of the account + MyMoneySecurity accountCurrency = file->currency(acc.currencyId()); + val = val * file->price(security.tradingCurrency(), accountCurrency.id()).rate(accountCurrency.id()); + val = val.convert(acc.fraction()); + value += val; + } catch(MyMoneyException* e) { + qWarning("%s", (QString("cannot convert stock balance of %1 to base currency: %2").arg(stock.name(), e->what())).data()); + delete e; + } + } + return value; +} + +} +// vim:cin:si:ai:et:ts=2:sw=2: |