You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
10 KiB
360 lines
10 KiB
/***************************************************************************
|
|
reportaccount.cpp
|
|
-------------------
|
|
begin : Mon May 17 2004
|
|
copyright : (C) 2004-2005 by Ace Jones
|
|
email : <ace.j@hotpop.com>
|
|
Thomas Baumgart <ipwizard@users.sourceforge.net>
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// QT Includes
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// 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. This
|
|
// is a minor problem because we use these terms when rendering to HTML,
|
|
// and a more major problem because we need it to translate account types
|
|
// (e.g. MyMoneyAccount::Checkings) into their text representation. We also
|
|
// use that text representation in the core data structure of the report. (Ace)
|
|
|
|
#include <tdelocale.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Project Includes
|
|
|
|
#include "../mymoney/mymoneyfile.h"
|
|
#include "../mymoney/mymoneysecurity.h"
|
|
#include "reportdebug.h"
|
|
#include "reportaccount.h"
|
|
|
|
namespace reports {
|
|
|
|
ReportAccount::ReportAccount( void )
|
|
{
|
|
}
|
|
|
|
ReportAccount::ReportAccount( const ReportAccount& copy ):
|
|
MyMoneyAccount( copy ), m_nameHierarchy( copy.m_nameHierarchy )
|
|
{
|
|
// NOTE: I implemented the copy constructor solely for debugging reasons
|
|
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
}
|
|
|
|
ReportAccount::ReportAccount( const TQString& accountid ):
|
|
MyMoneyAccount( MyMoneyFile::instance()->account(accountid) )
|
|
{
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
DEBUG_OUTPUT(TQString("Account %1").arg(accountid));
|
|
calculateAccountHierarchy();
|
|
}
|
|
|
|
ReportAccount::ReportAccount( const MyMoneyAccount& account ):
|
|
MyMoneyAccount( account )
|
|
{
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
DEBUG_OUTPUT(TQString("Account %1").arg(account.id()));
|
|
calculateAccountHierarchy();
|
|
}
|
|
|
|
void ReportAccount::calculateAccountHierarchy( void )
|
|
{
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
TQString resultid = id();
|
|
TQString parentid = parentAccountId();
|
|
|
|
#ifdef DEBUG_HIDE_SENSITIVE
|
|
m_nameHierarchy.prepend(file->account(resultid).id());
|
|
#else
|
|
m_nameHierarchy.prepend(file->account(resultid).name());
|
|
#endif
|
|
while (!file->isStandardAccount(parentid))
|
|
{
|
|
// take on the identity of our parent
|
|
resultid = parentid;
|
|
|
|
// and try again
|
|
parentid = file->account(resultid).parentAccountId();
|
|
#ifdef DEBUG_HIDE_SENSITIVE
|
|
m_nameHierarchy.prepend(file->account(resultid).id());
|
|
#else
|
|
m_nameHierarchy.prepend(file->account(resultid).name());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
MyMoneyMoney ReportAccount::deepCurrencyPrice( const TQDate& date ) const
|
|
{
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
|
|
MyMoneyMoney result(1, 1);
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
|
|
MyMoneySecurity undersecurity = file->security( currencyId() );
|
|
if ( ! undersecurity.isCurrency() )
|
|
{
|
|
MyMoneyPrice price = file->price(undersecurity.id(),undersecurity.tradingCurrency(),date);
|
|
if ( price.isValid() )
|
|
{
|
|
result = price.rate(undersecurity.tradingCurrency());
|
|
|
|
DEBUG_OUTPUT(TQString("Converting under %1 to deep %2, price on %3 is %4")
|
|
.arg(undersecurity.name())
|
|
.arg(file->security(undersecurity.tradingCurrency()).name())
|
|
.arg(date.toString())
|
|
.arg(result.toDouble()));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_OUTPUT(TQString("No price to convert under %1 to deep %2 on %3")
|
|
.arg(undersecurity.name())
|
|
.arg(file->security(undersecurity.tradingCurrency()).name())
|
|
.arg(date.toString()));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
MyMoneyMoney ReportAccount::baseCurrencyPrice( const TQDate& date ) const
|
|
{
|
|
// Note that whether or not the user chooses to convert to base currency, all the values
|
|
// for a given account/category are converted to the currency for THAT account/category
|
|
// The "Convert to base currency" tells the report to convert from the account/category
|
|
// currency to the file's base currency.
|
|
//
|
|
// An example where this matters is if Category 'C' and account 'U' are in USD, but
|
|
// Account 'J' is in JPY. Say there are two transactions, one is US$100 from U to C,
|
|
// the other is JPY10,000 from J to C. Given a JPY price of USD$0.01, this means
|
|
// C will show a balance of $200 NO MATTER WHAT the user chooses for 'convert to base
|
|
// currency. This confused me for a while, which is why I wrote this comment.
|
|
// --acejones
|
|
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
|
|
MyMoneyMoney result(1, 1);
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
|
|
if(isForeignCurrency())
|
|
{
|
|
result = foreignCurrencyPrice(file->baseCurrency().id(), date);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
MyMoneyMoney ReportAccount::foreignCurrencyPrice( const TQString foreignCurrency, const TQDate& date ) const
|
|
{
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
|
|
MyMoneyPrice price;
|
|
MyMoneyMoney result(1, 1);
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
MyMoneySecurity security = file->security(foreignCurrency);
|
|
|
|
//check whether it is a currency or a commodity. In the latter case case, get the trading currency
|
|
TQString tradingCurrency;
|
|
if(security.isCurrency()) {
|
|
tradingCurrency = foreignCurrency;
|
|
} else {
|
|
tradingCurrency = security.tradingCurrency();
|
|
}
|
|
|
|
//It makes no sense to get the price if both currencies are the same
|
|
if(currency().id() != tradingCurrency) {
|
|
price = file->price(currency().id(), tradingCurrency, date);
|
|
|
|
if(price.isValid())
|
|
{
|
|
result = price.rate(tradingCurrency);
|
|
DEBUG_OUTPUT(TQString("Converting deep %1 to currency %2, price on %3 is %4")
|
|
.arg(file->currency(currency().id()).name())
|
|
.arg(file->currency(foreignCurrency).name())
|
|
.arg(date.toString())
|
|
.arg(result.toDouble()));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_OUTPUT(TQString("No price to convert deep %1 to currency %2 on %3")
|
|
.arg(file->currency(currency().id()).name())
|
|
.arg(file->currency(foreignCurrency).name())
|
|
.arg(date.toString()));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Fetch the trading currency of this account's currency
|
|
*
|
|
* @return The account's currency trading currency
|
|
*/
|
|
MyMoneySecurity ReportAccount::currency( void ) const
|
|
{
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
|
|
// First, get the deep currency
|
|
MyMoneySecurity deepcurrency = file->security( currencyId() );
|
|
if ( ! deepcurrency.isCurrency() )
|
|
deepcurrency = file->security( deepcurrency.tradingCurrency() );
|
|
|
|
// Return the deep currency's ID
|
|
return deepcurrency;
|
|
}
|
|
|
|
/**
|
|
* Determine if this account's deep currency is different from the file's
|
|
* base currency
|
|
*
|
|
* @return bool True if this account is in a foreign currency
|
|
*/
|
|
bool ReportAccount::isForeignCurrency( void ) const
|
|
{
|
|
return ( currency().id() != MyMoneyFile::instance()->baseCurrency().id() );
|
|
}
|
|
|
|
bool ReportAccount::operator<(const ReportAccount& second) const
|
|
{
|
|
// DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
|
|
bool result = false;
|
|
bool haveresult = false;
|
|
TQStringList::const_iterator it_first = m_nameHierarchy.begin();
|
|
TQStringList::const_iterator it_second = second.m_nameHierarchy.begin();
|
|
while ( it_first != m_nameHierarchy.end() )
|
|
{
|
|
// The first string is longer than the second, but otherwise identical
|
|
if ( it_second == second.m_nameHierarchy.end() )
|
|
{
|
|
result = false;
|
|
haveresult = true;
|
|
break;
|
|
}
|
|
|
|
if ( (*it_first) < (*it_second) )
|
|
{
|
|
result = true;
|
|
haveresult = true;
|
|
break;
|
|
}
|
|
else if ( (*it_first) > (*it_second) )
|
|
{
|
|
result = false;
|
|
haveresult = true;
|
|
break;
|
|
}
|
|
|
|
++it_first;
|
|
++it_second;
|
|
}
|
|
|
|
// The second string is longer than the first, but otherwise identical
|
|
if ( !haveresult && ( it_second != second.m_nameHierarchy.end() ) )
|
|
result = true;
|
|
|
|
// DEBUG_OUTPUT(TQString("%1 < %2 is %3").arg(debugName(),second.debugName()).arg(result));
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The name of only this account. No matter how deep the hierarchy, this
|
|
* method only returns the last name in the list, which is the engine name]
|
|
* of this account.
|
|
*
|
|
* @return TQString The account's name
|
|
*/
|
|
TQString ReportAccount::name( void ) const
|
|
{
|
|
return m_nameHierarchy.back();
|
|
}
|
|
|
|
// MyMoneyAccount:fullHierarchyDebug()
|
|
TQString ReportAccount::debugName( void ) const
|
|
{
|
|
return m_nameHierarchy.join("|");
|
|
}
|
|
|
|
// MyMoneyAccount:fullHierarchy()
|
|
TQString ReportAccount::fullName( void ) const
|
|
{
|
|
return m_nameHierarchy.join(": ");
|
|
}
|
|
|
|
// MyMoneyAccount:isTopCategory()
|
|
bool ReportAccount::isTopLevel( void ) const
|
|
{
|
|
return ( m_nameHierarchy.size() == 1 );
|
|
}
|
|
|
|
// MyMoneyAccount:hierarchyDepth()
|
|
unsigned ReportAccount::hierarchyDepth( void ) const
|
|
{
|
|
return ( m_nameHierarchy.size() );
|
|
}
|
|
|
|
ReportAccount ReportAccount::parent( void ) const
|
|
{
|
|
return ReportAccount( parentAccountId() );
|
|
}
|
|
|
|
ReportAccount ReportAccount::topParent( void ) const
|
|
{
|
|
DEBUG_ENTER(__PRETTY_FUNCTION__);
|
|
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
TQString resultid = id();
|
|
TQString parentid = parentAccountId();
|
|
|
|
while (!file->isStandardAccount(parentid))
|
|
{
|
|
// take on the identity of our parent
|
|
resultid = parentid;
|
|
|
|
// and try again
|
|
parentid = file->account(resultid).parentAccountId();
|
|
}
|
|
|
|
return ReportAccount( resultid );
|
|
}
|
|
|
|
TQString ReportAccount::topParentName( void ) const
|
|
{
|
|
return m_nameHierarchy.first();
|
|
}
|
|
|
|
bool ReportAccount::isLiquidAsset( void ) const
|
|
{
|
|
return accountType() == MyMoneyAccount::Cash ||
|
|
accountType() == MyMoneyAccount::Checkings ||
|
|
accountType() == MyMoneyAccount::Savings;
|
|
}
|
|
|
|
|
|
bool ReportAccount::isLiquidLiability( void ) const
|
|
{
|
|
return accountType() == MyMoneyAccount::CreditCard;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // end namespace reports
|