|
|
|
/***************************************************************************
|
|
|
|
investtransactioneditor.cpp
|
|
|
|
----------
|
|
|
|
begin : Fri Dec 15 2006
|
|
|
|
copyright : (C) 2006 by Thomas Baumgart
|
|
|
|
email : 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
|
|
|
|
|
|
|
|
#include <typeinfo>
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// QT Includes
|
|
|
|
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
#include <tqeventloop.h>
|
|
|
|
#include <tqradiobutton.h>
|
|
|
|
#include <tqbuttongroup.h>
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// KDE Includes
|
|
|
|
|
|
|
|
#include <ktextedit.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <kcombobox.h>
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <kstdguiitem.h>
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Project Includes
|
|
|
|
|
|
|
|
#include <kmymoney/investtransactioneditor.h>
|
|
|
|
#include <kmymoney/kmymoneycategory.h>
|
|
|
|
#include <kmymoney/kmymoneydateinput.h>
|
|
|
|
#include <kmymoney/kmymoneyedit.h>
|
|
|
|
#include <kmymoney/kmymoneylineedit.h>
|
|
|
|
#include <kmymoney/kmymoneyaccountcompletion.h>
|
|
|
|
#include <kmymoney/kmymoneyaccountselector.h>
|
|
|
|
#include <kmymoney/mymoneyfile.h>
|
|
|
|
#include <kmymoney/transactionform.h>
|
|
|
|
|
|
|
|
#include "../dialogs/ksplittransactiondlg.h"
|
|
|
|
#include "../dialogs/kcurrencycalculator.h"
|
|
|
|
|
|
|
|
#include "../kmymoneyglobalsettings.h"
|
|
|
|
|
|
|
|
#include "investactivities.h"
|
|
|
|
|
|
|
|
using namespace KMyMoneyRegister;
|
|
|
|
using namespace KMyMoneyTransactionForm;
|
|
|
|
using namespace Invest;
|
|
|
|
|
|
|
|
class InvestTransactionEditor::Private {
|
|
|
|
friend class Invest::Activity;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Private(InvestTransactionEditor* parent) :
|
|
|
|
m_parent(parent),
|
|
|
|
m_activity(0)
|
|
|
|
{
|
|
|
|
m_phonyAccount = MyMoneyAccount("Phony-ID", MyMoneyAccount());
|
|
|
|
}
|
|
|
|
|
|
|
|
~Private() {
|
|
|
|
delete m_activity;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget* haveWidget(const TQString& name) { return m_parent->haveWidget(name); }
|
|
|
|
|
|
|
|
InvestTransactionEditor* m_parent;
|
|
|
|
Activity* m_activity;
|
|
|
|
MyMoneyAccount m_phonyAccount;
|
|
|
|
MyMoneySplit m_phonySplit;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
InvestTransactionEditor::InvestTransactionEditor() :
|
|
|
|
d(new Private(this))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
InvestTransactionEditor::~InvestTransactionEditor()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
InvestTransactionEditor::InvestTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::InvestTransaction* item, const KMyMoneyRegister::SelectedTransactions& list, const TQDate& lastPostDate) :
|
|
|
|
TransactionEditor(regForm, item, list, lastPostDate),
|
|
|
|
d(new Private(this))
|
|
|
|
{
|
|
|
|
// dissect the transaction into its type, splits, currency, security etc.
|
|
|
|
dissectTransaction(m_transaction, m_split,
|
|
|
|
m_assetAccountSplit,
|
|
|
|
m_feeSplits,
|
|
|
|
m_interestSplits,
|
|
|
|
m_security,
|
|
|
|
m_currency,
|
|
|
|
m_transactionType);
|
|
|
|
|
|
|
|
// determine initial activity object
|
|
|
|
activityFactory(m_transactionType);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::activityFactory(MyMoneySplit::investTransactionTypeE type)
|
|
|
|
{
|
|
|
|
if(!d->m_activity || type != d->m_activity->type()) {
|
|
|
|
delete d->m_activity;
|
|
|
|
switch(type) {
|
|
|
|
default:
|
|
|
|
case MyMoneySplit::BuyShares:
|
|
|
|
d->m_activity = new Buy(this);
|
|
|
|
break;
|
|
|
|
case MyMoneySplit::SellShares:
|
|
|
|
d->m_activity = new Sell(this);
|
|
|
|
break;
|
|
|
|
case MyMoneySplit::Dividend:
|
|
|
|
case MyMoneySplit::Yield:
|
|
|
|
d->m_activity = new Div(this);
|
|
|
|
break;
|
|
|
|
case MyMoneySplit::ReinvestDividend:
|
|
|
|
d->m_activity = new Reinvest(this);
|
|
|
|
break;
|
|
|
|
case MyMoneySplit::AddShares:
|
|
|
|
d->m_activity = new Add(this);
|
|
|
|
break;
|
|
|
|
case MyMoneySplit::RemoveShares:
|
|
|
|
d->m_activity = new Remove(this);
|
|
|
|
break;
|
|
|
|
case MyMoneySplit::SplitShares:
|
|
|
|
d->m_activity = new Split(this);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::dissectTransaction(const MyMoneyTransaction& transaction, const MyMoneySplit& split, MyMoneySplit& assetAccountSplit, TQValueList<MyMoneySplit>& feeSplits, TQValueList<MyMoneySplit>& interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency, MyMoneySplit::investTransactionTypeE& transactionType)
|
|
|
|
{
|
|
|
|
// collect the splits. split references the stock account and should already
|
|
|
|
// be set up. assetAccountSplit references the corresponding asset account (maybe
|
|
|
|
// empty), feeSplits is the list of all expenses and interestSplits
|
|
|
|
// the list of all incomes
|
|
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
|
|
TQValueList<MyMoneySplit>::ConstIterator it_s;
|
|
|
|
for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
|
|
|
|
MyMoneyAccount acc = file->account((*it_s).accountId());
|
|
|
|
if((*it_s).id() == split.id()) {
|
|
|
|
security = file->security(acc.currencyId());
|
|
|
|
} else if(acc.accountGroup() == MyMoneyAccount::Expense) {
|
|
|
|
feeSplits.append(*it_s);
|
|
|
|
// feeAmount += (*it_s).value();
|
|
|
|
} else if(acc.accountGroup() == MyMoneyAccount::Income) {
|
|
|
|
interestSplits.append(*it_s);
|
|
|
|
// interestAmount += (*it_s).value();
|
|
|
|
} else {
|
|
|
|
assetAccountSplit = *it_s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// determine transaction type
|
|
|
|
if(split.action() == MyMoneySplit::ActionAddShares) {
|
|
|
|
transactionType = (!split.shares().isNegative()) ? MyMoneySplit::AddShares : MyMoneySplit::RemoveShares;
|
|
|
|
} else if(split.action() == MyMoneySplit::ActionBuyShares) {
|
|
|
|
transactionType = (!split.value().isNegative()) ? MyMoneySplit::BuyShares : MyMoneySplit::SellShares;
|
|
|
|
} else if(split.action() == MyMoneySplit::ActionDividend) {
|
|
|
|
transactionType = MyMoneySplit::Dividend;
|
|
|
|
} else if(split.action() == MyMoneySplit::ActionReinvestDividend) {
|
|
|
|
transactionType = MyMoneySplit::ReinvestDividend;
|
|
|
|
} else if(split.action() == MyMoneySplit::ActionYield) {
|
|
|
|
transactionType = MyMoneySplit::Yield;
|
|
|
|
} else if(split.action() == MyMoneySplit::ActionSplitShares) {
|
|
|
|
transactionType = MyMoneySplit::SplitShares;
|
|
|
|
} else
|
|
|
|
transactionType = MyMoneySplit::BuyShares;
|
|
|
|
|
|
|
|
currency.setTradingSymbol("???");
|
|
|
|
try {
|
|
|
|
currency = file->security(transaction.commodity());
|
|
|
|
} catch(MyMoneyException *e) {
|
|
|
|
delete e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::createEditWidgets(void)
|
|
|
|
{
|
|
|
|
KMyMoneyActivityCombo* activity = new KMyMoneyActivityCombo();
|
|
|
|
m_editWidgets["activity"] = activity;
|
|
|
|
connect(activity, TQT_SIGNAL(activitySelected(MyMoneySplit::investTransactionTypeE)), this, TQT_SLOT(slotUpdateActivity(MyMoneySplit::investTransactionTypeE)));
|
|
|
|
connect(activity, TQT_SIGNAL(activitySelected(MyMoneySplit::investTransactionTypeE)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
|
|
|
|
m_editWidgets["postdate"] = new kMyMoneyDateInput;
|
|
|
|
connect(m_editWidgets["postdate"], TQT_SIGNAL(dateChanged(const TQDate&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
|
|
|
|
KMyMoneySecurity* security = new KMyMoneySecurity;
|
|
|
|
security->setHint(i18n("Security"));
|
|
|
|
m_editWidgets["security"] = security;
|
|
|
|
connect(security, TQT_SIGNAL(itemSelected(const TQString&)), this, TQT_SLOT(slotUpdateSecurity(const TQString&)));
|
|
|
|
connect(security, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(security, TQT_SIGNAL(createItem(const TQString&, TQString&)), this, TQT_SLOT(slotCreateSecurity(const TQString&, TQString&)));
|
|
|
|
connect(security, TQT_SIGNAL(objectCreation(bool)), this, TQT_SIGNAL(objectCreation(bool)));
|
|
|
|
|
|
|
|
KMyMoneyCategory* asset = new KMyMoneyCategory(0, 0, false);
|
|
|
|
asset->setHint(i18n("Asset account"));
|
|
|
|
m_editWidgets["asset-account"] = asset;
|
|
|
|
connect(asset, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(asset, TQT_SIGNAL(objectCreation(bool)), this, TQT_SIGNAL(objectCreation(bool)));
|
|
|
|
|
|
|
|
KMyMoneyCategory* fees = new KMyMoneyCategory(0, 0, true);
|
|
|
|
fees->setHint(i18n("Fees"));
|
|
|
|
m_editWidgets["fee-account"] = fees;
|
|
|
|
connect(fees, TQT_SIGNAL(itemSelected(const TQString&)), this, TQT_SLOT(slotUpdateFeeCategory(const TQString&)));
|
|
|
|
connect(fees, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(fees, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateFeeVisibility(const TQString&)));
|
|
|
|
connect(fees, TQT_SIGNAL(createItem(const TQString&, TQString&)), this, TQT_SLOT(slotCreateFeeCategory(const TQString&, TQString&)));
|
|
|
|
connect(fees, TQT_SIGNAL(objectCreation(bool)), this, TQT_SIGNAL(objectCreation(bool)));
|
|
|
|
connect(fees->splitButton(), TQT_SIGNAL(clicked()), this, TQT_SLOT(slotEditFeeSplits()));
|
|
|
|
|
|
|
|
KMyMoneyCategory* interest = new KMyMoneyCategory(0, 0, true);
|
|
|
|
interest->setHint(i18n("Interest"));
|
|
|
|
m_editWidgets["interest-account"] = interest;
|
|
|
|
connect(interest, TQT_SIGNAL(itemSelected(const TQString&)), this, TQT_SLOT(slotUpdateInterestCategory(const TQString&)));
|
|
|
|
connect(interest, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(interest, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateInterestVisibility(const TQString&)));
|
|
|
|
connect(interest, TQT_SIGNAL(createItem(const TQString&, TQString&)), this, TQT_SLOT(slotCreateInterestCategory(const TQString&, TQString&)));
|
|
|
|
connect(interest, TQT_SIGNAL(objectCreation(bool)), this, TQT_SIGNAL(objectCreation(bool)));
|
|
|
|
connect(interest->splitButton(), TQT_SIGNAL(clicked()), this, TQT_SLOT(slotEditInterestSplits()));
|
|
|
|
|
|
|
|
KTextEdit* memo = new KTextEdit;
|
|
|
|
memo->setTabChangesFocus(true);
|
|
|
|
m_editWidgets["memo"] = memo;
|
|
|
|
|
|
|
|
kMyMoneyEdit* value = new kMyMoneyEdit;
|
|
|
|
value->setHint(i18n("Shares"));
|
|
|
|
value->setResetButtonVisible(false);
|
|
|
|
m_editWidgets["shares"] = value;
|
|
|
|
connect(value, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(value, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateTotalAmount()));
|
|
|
|
|
|
|
|
value = new kMyMoneyEdit;
|
|
|
|
value->setHint(i18n("Price"));
|
|
|
|
value->setResetButtonVisible(false);
|
|
|
|
value->setPrecision(KMyMoneyGlobalSettings::pricePrecision());
|
|
|
|
m_editWidgets["price"] = value;
|
|
|
|
connect(value, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(value, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateTotalAmount()));
|
|
|
|
|
|
|
|
value = new kMyMoneyEdit;
|
|
|
|
// TODO once we have the selected transactions as array of Transaction
|
|
|
|
// we can allow multiple splits for fee and interest
|
|
|
|
value->setResetButtonVisible(false);
|
|
|
|
m_editWidgets["fee-amount"] = value;
|
|
|
|
connect(value, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(value, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateTotalAmount()));
|
|
|
|
|
|
|
|
value = new kMyMoneyEdit;
|
|
|
|
// TODO once we have the selected transactions as array of Transaction
|
|
|
|
// we can allow multiple splits for fee and interest
|
|
|
|
value->setResetButtonVisible(false);
|
|
|
|
m_editWidgets["interest-amount"] = value;
|
|
|
|
connect(value, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
connect(value, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateTotalAmount()));
|
|
|
|
|
|
|
|
KMyMoneyReconcileCombo* reconcile = new KMyMoneyReconcileCombo;
|
|
|
|
m_editWidgets["status"] = reconcile;
|
|
|
|
connect(reconcile, TQT_SIGNAL(itemSelected(const TQString&)), this, TQT_SLOT(slotUpdateButtonState()));
|
|
|
|
|
|
|
|
KMyMoneyRegister::TQWidgetContainer::iterator it_w;
|
|
|
|
for(it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) {
|
|
|
|
(*it_w)->installEventFilter(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQLabel* label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::AlignRight | TQt::DontClip);
|
|
|
|
m_editWidgets["total"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["total-label"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["asset-label"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["fee-label"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["fee-amount-label"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["interest-label"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["interest-amount-label"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["price-label"] = label;
|
|
|
|
|
|
|
|
label = new TQLabel("", 0);
|
|
|
|
label->setAlignment(TQt::AlignVCenter | TQt::DontClip);
|
|
|
|
m_editWidgets["shares-label"] = label;
|
|
|
|
|
|
|
|
// if we don't have more than 1 selected transaction, we don't need
|
|
|
|
// the "don't change" item in some of the combo widgets
|
|
|
|
if(m_transactions.count() < 2) {
|
|
|
|
reconcile->removeDontCare();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int InvestTransactionEditor::slotEditFeeSplits(void)
|
|
|
|
{
|
|
|
|
return editSplits("fee-account", "fee-amount", m_feeSplits, false, TQT_SLOT(slotEditFeeSplits()));
|
|
|
|
}
|
|
|
|
|
|
|
|
int InvestTransactionEditor::slotEditInterestSplits(void)
|
|
|
|
{
|
|
|
|
return editSplits("interest-account", "interest-amount", m_interestSplits, true, TQT_SLOT(slotEditInterestSplits()));
|
|
|
|
}
|
|
|
|
|
|
|
|
int InvestTransactionEditor::editSplits(const TQString& categoryWidgetName, const TQString& amountWidgetName, TQValueList<MyMoneySplit>& splits, bool isIncome, const char* slotEditSplits)
|
|
|
|
{
|
|
|
|
int rc = TQDialog::Rejected;
|
|
|
|
|
|
|
|
if(!m_openEditSplits) {
|
|
|
|
// only get in here in a single instance
|
|
|
|
m_openEditSplits = true;
|
|
|
|
|
|
|
|
// force focus change to update all data
|
|
|
|
KMyMoneyCategory* category = dynamic_cast<KMyMoneyCategory*>(m_editWidgets[categoryWidgetName]);
|
|
|
|
TQWidget* w = category->splitButton();
|
|
|
|
if(w)
|
|
|
|
w->setFocus();
|
|
|
|
|
|
|
|
kMyMoneyEdit* amount = dynamic_cast<kMyMoneyEdit*>(haveWidget(amountWidgetName));
|
|
|
|
|
|
|
|
MyMoneyTransaction transaction;
|
|
|
|
transaction.setCommodity(m_currency.id());
|
|
|
|
if(splits.count() == 0 && !category->selectedItem().isEmpty()) {
|
|
|
|
MyMoneySplit s;
|
|
|
|
s.setAccountId(category->selectedItem());
|
|
|
|
s.setShares(amount->value());
|
|
|
|
s.setValue(s.shares());
|
|
|
|
splits << s;
|
|
|
|
}
|
|
|
|
// use the transactions commodity as the currency indicator for the splits
|
|
|
|
// this is used to allow some useful setting for the fractions in the amount fields
|
|
|
|
try {
|
|
|
|
d->m_phonyAccount.setCurrencyId(m_transaction.commodity());
|
|
|
|
d->m_phonyAccount.fraction(MyMoneyFile::instance()->security(m_transaction.commodity()));
|
|
|
|
} catch(MyMoneyException *e) {
|
|
|
|
tqDebug("Unable to setup precision");
|
|
|
|
delete e;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(createPseudoTransaction(transaction, splits)) {
|
|
|
|
MyMoneyMoney value;
|
|
|
|
|
|
|
|
KSplitTransactionDlg* dlg = new KSplitTransactionDlg(transaction,
|
|
|
|
d->m_phonySplit,
|
|
|
|
d->m_phonyAccount,
|
|
|
|
false,
|
|
|
|
isIncome,
|
|
|
|
0,
|
|
|
|
m_priceInfo,
|
|
|
|
m_regForm);
|
|
|
|
// connect(dlg, TQT_SIGNAL(newCategory(MyMoneyAccount&)), this, TQT_SIGNAL(newCategory(MyMoneyAccount&)));
|
|
|
|
|
|
|
|
if((rc = dlg->exec()) == TQDialog::Accepted) {
|
|
|
|
transaction = dlg->transaction();
|
|
|
|
// collect splits out of the transaction
|
|
|
|
splits.clear();
|
|
|
|
TQValueList<MyMoneySplit>::const_iterator it_s;
|
|
|
|
MyMoneyMoney fees;
|
|
|
|
for(it_s = transaction.splits().begin(); it_s != transaction.splits().end(); ++it_s) {
|
|
|
|
if((*it_s).accountId() == d->m_phonyAccount.id())
|
|
|
|
continue;
|
|
|
|
splits << *it_s;
|
|
|
|
fees += (*it_s).shares();
|
|
|
|
}
|
|
|
|
if(isIncome)
|
|
|
|
fees = -fees;
|
|
|
|
|
|
|
|
TQString categoryId;
|
|
|
|
setupCategoryWidget(category, splits, categoryId, slotEditSplits);
|
|
|
|
amount->setValue(fees);
|
|
|
|
slotUpdateTotalAmount();
|
|
|
|
}
|
|
|
|
|
|
|
|
delete dlg;
|
|
|
|
}
|
|
|
|
|
|
|
|
// focus jumps into the memo field
|
|
|
|
if((w = haveWidget("memo")) != 0) {
|
|
|
|
w->setFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_openEditSplits = false;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InvestTransactionEditor::createPseudoTransaction(MyMoneyTransaction& t, const TQValueList<MyMoneySplit>& splits)
|
|
|
|
{
|
|
|
|
t.removeSplits();
|
|
|
|
|
|
|
|
MyMoneySplit split;
|
|
|
|
split.setAccountId(d->m_phonyAccount.id());
|
|
|
|
split.setValue(-subtotal(splits));
|
|
|
|
split.setShares(split.value());
|
|
|
|
t.addSplit(split);
|
|
|
|
d->m_phonySplit = split;
|
|
|
|
|
|
|
|
TQValueList<MyMoneySplit>::const_iterator it_s;
|
|
|
|
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
|
|
|
|
split = *it_s;
|
|
|
|
split.clearId();
|
|
|
|
t.addSplit(split);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotCreateSecurity(const TQString& name, TQString& id)
|
|
|
|
{
|
|
|
|
MyMoneyAccount acc;
|
|
|
|
TQRegExp exp("([^:]+)");
|
|
|
|
if(exp.search(name) != -1) {
|
|
|
|
acc.setName(exp.cap(1));
|
|
|
|
|
|
|
|
emit createSecurity(acc, m_account);
|
|
|
|
|
|
|
|
// return id
|
|
|
|
id = acc.id();
|
|
|
|
|
|
|
|
if(!id.isEmpty()) {
|
|
|
|
slotUpdateSecurity(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotCreateFeeCategory(const TQString& name, TQString& id)
|
|
|
|
{
|
|
|
|
MyMoneyAccount acc;
|
|
|
|
acc.setName(name);
|
|
|
|
|
|
|
|
emit createCategory(acc, MyMoneyFile::instance()->expense());
|
|
|
|
|
|
|
|
// return id
|
|
|
|
id = acc.id();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotUpdateFeeCategory(const TQString& id)
|
|
|
|
{
|
|
|
|
haveWidget("fee-amount")->setDisabled(id.isEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotUpdateFeeVisibility(const TQString& txt)
|
|
|
|
{
|
|
|
|
haveWidget("fee-amount")->setHidden(txt.isEmpty());
|
|
|
|
TQWidget* w = haveWidget("fee-amount-label");
|
|
|
|
if(w)
|
|
|
|
w->setShown(haveWidget("fee-amount")->isVisible());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotUpdateInterestCategory(const TQString& id)
|
|
|
|
{
|
|
|
|
haveWidget("interest-amount")->setDisabled(id.isEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotUpdateInterestVisibility(const TQString& txt)
|
|
|
|
{
|
|
|
|
KMyMoneyCategory* interest = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
|
|
|
|
TQWidget* w = haveWidget("interest-amount-label");
|
|
|
|
|
|
|
|
if(dynamic_cast<Reinvest*>(d->m_activity)) {
|
|
|
|
interest->splitButton()->hide();
|
|
|
|
haveWidget("interest-amount")->setHidden(true);
|
|
|
|
// for the reinvest case, we don't ever hide the label do avoid a shine through
|
|
|
|
// of the underlying transaction data.
|
|
|
|
w = 0;
|
|
|
|
} else {
|
|
|
|
haveWidget("interest-amount")->setHidden(txt.isEmpty());
|
|
|
|
// FIXME once we can handle split interest, we need to uncomment the next line
|
|
|
|
// interest->splitButton()->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(w)
|
|
|
|
w->setShown(haveWidget("interest-amount")->isVisible());
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotCreateInterestCategory(const TQString& name, TQString& id)
|
|
|
|
{
|
|
|
|
MyMoneyAccount acc;
|
|
|
|
acc.setName(name);
|
|
|
|
|
|
|
|
emit createCategory(acc, MyMoneyFile::instance()->income());
|
|
|
|
|
|
|
|
// return id
|
|
|
|
id = acc.id();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotReloadEditWidgets(void)
|
|
|
|
{
|
|
|
|
KMyMoneyCategory* interest = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
|
|
|
|
KMyMoneyCategory* fees = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
|
|
|
|
KMyMoneySecurity* security = dynamic_cast<KMyMoneySecurity*>(haveWidget("security"));
|
|
|
|
|
|
|
|
AccountSet aSet;
|
|
|
|
TQString id;
|
|
|
|
|
|
|
|
// interest-account
|
|
|
|
aSet.clear();
|
|
|
|
aSet.addAccountGroup(MyMoneyAccount::Income);
|
|
|
|
aSet.load(interest->selector());
|
|
|
|
setupCategoryWidget(interest, m_interestSplits, id, TQT_SLOT(slotEditInterestSplits()));
|
|
|
|
|
|
|
|
// fee-account
|
|
|
|
aSet.clear();
|
|
|
|
aSet.addAccountGroup(MyMoneyAccount::Expense);
|
|
|
|
aSet.load(fees->selector());
|
|
|
|
setupCategoryWidget(fees, m_feeSplits, id, TQT_SLOT(slotEditFeeSplits()));
|
|
|
|
|
|
|
|
// security
|
|
|
|
aSet.clear();
|
|
|
|
aSet.load(security->selector(), i18n("Security"), m_account.accountList(), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::loadEditWidgets(KMyMoneyRegister::Action /* action */)
|
|
|
|
{
|
|
|
|
TQString id;
|
|
|
|
|
|
|
|
kMyMoneyDateInput* postDate = dynamic_cast<kMyMoneyDateInput*>(haveWidget("postdate"));
|
|
|
|
KMyMoneyReconcileCombo* reconcile = dynamic_cast<KMyMoneyReconcileCombo*>(haveWidget("status"));
|
|
|
|
KMyMoneySecurity* security = dynamic_cast<KMyMoneySecurity*>(haveWidget("security"));
|
|
|
|
KMyMoneyActivityCombo* activity = dynamic_cast<KMyMoneyActivityCombo*>(haveWidget("activity"));
|
|
|
|
KMyMoneyCategory* asset = dynamic_cast<KMyMoneyCategory*>(haveWidget("asset-account"));
|
|
|
|
KTextEdit* memo = dynamic_cast<KTextEdit*>(m_editWidgets["memo"]);
|
|
|
|
kMyMoneyEdit* value;
|
|
|
|
KMyMoneyCategory* interest = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
|
|
|
|
KMyMoneyCategory* fees = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
|
|
|
|
|
|
|
|
// check if the current transaction has a reference to an equity account
|
|
|
|
bool haveEquityAccount = false;
|
|
|
|
TQValueList<MyMoneySplit>::const_iterator it_s;
|
|
|
|
for(it_s = m_transaction.splits().begin(); !haveEquityAccount && it_s != m_transaction.splits().end(); ++it_s) {
|
|
|
|
MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
|
|
|
|
if(acc.accountType() == MyMoneyAccount::Equity)
|
|
|
|
haveEquityAccount = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// asset-account
|
|
|
|
AccountSet aSet;
|
|
|
|
aSet.clear();
|
|
|
|
aSet.addAccountType(MyMoneyAccount::Checkings);
|
|
|
|
aSet.addAccountType(MyMoneyAccount::Savings);
|
|
|
|
aSet.addAccountType(MyMoneyAccount::Cash);
|
|
|
|
aSet.addAccountType(MyMoneyAccount::Asset);
|
|
|
|
aSet.addAccountType(MyMoneyAccount::Currency);
|
|
|
|
aSet.addAccountType(MyMoneyAccount::CreditCard);
|
|
|
|
if(KMyMoneyGlobalSettings::expertMode() || haveEquityAccount)
|
|
|
|
aSet.addAccountGroup(MyMoneyAccount::Equity);
|
|
|
|
aSet.load(asset->selector());
|
|
|
|
|
|
|
|
// security
|
|
|
|
security->setSuppressObjectCreation(false); // allow object creation on the fly
|
|
|
|
aSet.clear();
|
|
|
|
aSet.load(security->selector(), i18n("Security"), m_account.accountList(), true);
|
|
|
|
|
|
|
|
if(!isMultiSelection()) {
|
|
|
|
// date
|
|
|
|
if(m_transaction.postDate().isValid())
|
|
|
|
postDate->setDate(m_transaction.postDate());
|
|
|
|
else if(m_lastPostDate.isValid())
|
|
|
|
postDate->setDate(m_lastPostDate);
|
|
|
|
else
|
|
|
|
postDate->setDate(TQDate::currentDate());
|
|
|
|
|
|
|
|
// security (but only if it's not the investment account)
|
|
|
|
if(m_split.accountId() != m_account.id()) {
|
|
|
|
security->completion()->setSelected(m_split.accountId());
|
|
|
|
security->slotItemSelected(m_split.accountId());
|
|
|
|
}
|
|
|
|
|
|
|
|
// activity
|
|
|
|
activity->setActivity(d->m_activity->type());
|
|
|
|
slotUpdateActivity(activity->activity());
|
|
|
|
|
|
|
|
asset->completion()->setSelected(m_assetAccountSplit.accountId());
|
|
|
|
asset->slotItemSelected(m_assetAccountSplit.accountId());
|
|
|
|
|
|
|
|
// interest-account
|
|
|
|
aSet.clear();
|
|
|
|
aSet.addAccountGroup(MyMoneyAccount::Income);
|
|
|
|
aSet.load(interest->selector());
|
|
|
|
setupCategoryWidget(interest, m_interestSplits, id, TQT_SLOT(slotEditInterestSplits()));
|
|
|
|
slotUpdateInterestVisibility(interest->currentText());
|
|
|
|
|
|
|
|
// fee-account
|
|
|
|
aSet.clear();
|
|
|
|
aSet.addAccountGroup(MyMoneyAccount::Expense);
|
|
|
|
aSet.load(fees->selector());
|
|
|
|
setupCategoryWidget(fees, m_feeSplits, id, TQT_SLOT(slotEditFeeSplits()));
|
|
|
|
slotUpdateFeeVisibility(fees->currentText());
|
|
|
|
|
|
|
|
// memo
|
|
|
|
memo->setText(m_split.memo());
|
|
|
|
|
|
|
|
// shares
|
|
|
|
// don't set the value if the number of shares is zero so that
|
|
|
|
// we can see the hint
|
|
|
|
value = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
|
|
|
|
if(typeid(*(d->m_activity)) != typeid(Invest::Split(this)))
|
|
|
|
value->setPrecision(MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction()));
|
|
|
|
else
|
|
|
|
value->setPrecision(-1);
|
|
|
|
|
|
|
|
if(!m_split.shares().isZero())
|
|
|
|
value->setValue(m_split.shares().abs());
|
|
|
|
|
|
|
|
// price
|
|
|
|
updatePriceMode(m_split);
|
|
|
|
|
|
|
|
// fee amount
|
|
|
|
value = dynamic_cast<kMyMoneyEdit*>(haveWidget("fee-amount"));
|
|
|
|
value->setValue(subtotal(m_feeSplits));
|
|
|
|
|
|
|
|
// interest amount
|
|
|
|
value = dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount"));
|
|
|
|
value->setValue(-subtotal(m_interestSplits));
|
|
|
|
|
|
|
|
// total
|
|
|
|
slotUpdateTotalAmount();
|
|
|
|
|
|
|
|
// status
|
|
|
|
if(m_split.reconcileFlag() == MyMoneySplit::Unknown)
|
|
|
|
m_split.setReconcileFlag(MyMoneySplit::NotReconciled);
|
|
|
|
reconcile->setState(m_split.reconcileFlag());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
postDate->loadDate(TQDate());
|
|
|
|
reconcile->setState(MyMoneySplit::Unknown);
|
|
|
|
memo->setText(TQString());
|
|
|
|
|
|
|
|
// We don't allow to change the activity
|
|
|
|
activity->setActivity(d->m_activity->type());
|
|
|
|
slotUpdateActivity(activity->activity());
|
|
|
|
activity->setDisabled(true);
|
|
|
|
|
|
|
|
// scan the list of selected transactions and check that they have
|
|
|
|
// the same activity.
|
|
|
|
KMyMoneyRegister::SelectedTransactions::iterator it_t = m_transactions.begin();
|
|
|
|
const TQString& action = m_item->split().action();
|
|
|
|
bool isNegative = m_item->split().shares().isNegative();
|
|
|
|
bool allSameActivity = true;
|
|
|
|
for(it_t = m_transactions.begin(); allSameActivity && (it_t != m_transactions.end()); ++it_t) {
|
|
|
|
allSameActivity = (action == (*it_t).split().action() && (*it_t).split().shares().isNegative() == isNegative);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList fields;
|
|
|
|
fields << "shares" << "price" << "fee-amount" << "interest-amount";
|
|
|
|
TQStringList::const_iterator it_f;
|
|
|
|
for(it_f = fields.begin(); it_f != fields.end(); ++it_f) {
|
|
|
|
value = dynamic_cast<kMyMoneyEdit*>(haveWidget((*it_f)));
|
|
|
|
value->setText("");
|
|
|
|
value->setAllowEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we have transactions with different activities, disable some more widgets
|
|
|
|
if(!allSameActivity) {
|
|
|
|
fields << "asset-account" << "fee-account" << "interest-account";
|
|
|
|
TQStringList::const_iterator it_f;
|
|
|
|
for(it_f = fields.begin(); it_f != fields.end(); ++it_f) {
|
|
|
|
haveWidget(*it_f)->setDisabled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget* InvestTransactionEditor::firstWidget(void) const
|
|
|
|
{
|
|
|
|
return 0; // let the creator use the first widget in the tab order
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InvestTransactionEditor::isComplete(TQString& reason) const
|
|
|
|
{
|
|
|
|
reason = TQString();
|
|
|
|
return d->m_activity->isComplete(reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
MyMoneyMoney InvestTransactionEditor::subtotal(const TQValueList<MyMoneySplit>& splits) const
|
|
|
|
{
|
|
|
|
TQValueList<MyMoneySplit>::const_iterator it_s;
|
|
|
|
MyMoneyMoney sum;
|
|
|
|
|
|
|
|
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
|
|
|
|
sum += (*it_s).value();
|
|
|
|
}
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotUpdateSecurity(const TQString& stockId)
|
|
|
|
{
|
|
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
|
|
MyMoneyAccount stock = file->account(stockId);
|
|
|
|
m_security = file->security(stock.currencyId());
|
|
|
|
m_currency = file->security(m_security.tradingCurrency());
|
|
|
|
bool currencyKnown = !m_currency.id().isEmpty();
|
|
|
|
if(!currencyKnown) {
|
|
|
|
m_currency.setTradingSymbol("???");
|
|
|
|
} else {
|
|
|
|
if(typeid(*(d->m_activity)) != typeid(Invest::Split(this))) {
|
|
|
|
dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"))->setPrecision(MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction()));
|
|
|
|
} else {
|
|
|
|
dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"))->setPrecision(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updatePriceMode();
|
|
|
|
|
|
|
|
d->m_activity->preloadAssetAccount();
|
|
|
|
|
|
|
|
haveWidget("shares")->setEnabled(currencyKnown);
|
|
|
|
haveWidget("price")->setEnabled(currencyKnown);
|
|
|
|
haveWidget("fee-amount")->setEnabled(currencyKnown);
|
|
|
|
haveWidget("interest-amount")->setEnabled(currencyKnown);
|
|
|
|
|
|
|
|
slotUpdateTotalAmount();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::totalAmount(MyMoneyMoney& amount) const
|
|
|
|
{
|
|
|
|
KMyMoneyActivityCombo* activityCombo = dynamic_cast<KMyMoneyActivityCombo*>(haveWidget("activity"));
|
|
|
|
kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
|
|
|
|
kMyMoneyEdit* priceEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
|
|
|
|
kMyMoneyEdit* feesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("fee-amount"));
|
|
|
|
kMyMoneyEdit* interestEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("interest-amount"));
|
|
|
|
|
|
|
|
if(priceMode() == InvestTransactionEditor::PricePerTransaction)
|
|
|
|
amount = priceEdit->value().abs();
|
|
|
|
else
|
|
|
|
amount = sharesEdit->value().abs() * priceEdit->value().abs();
|
|
|
|
|
|
|
|
if(feesEdit->isVisible()) {
|
|
|
|
MyMoneyMoney fee = feesEdit->value();
|
|
|
|
MyMoneyMoney factor(-1,1);
|
|
|
|
switch(activityCombo->activity()) {
|
|
|
|
case MyMoneySplit::BuyShares:
|
|
|
|
case MyMoneySplit::ReinvestDividend:
|
|
|
|
factor = MyMoneyMoney(1,1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
amount += (fee * factor);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(interestEdit->isVisible()) {
|
|
|
|
MyMoneyMoney interest = interestEdit->value();
|
|
|
|
MyMoneyMoney factor(1,1);
|
|
|
|
switch(activityCombo->activity()) {
|
|
|
|
case MyMoneySplit::BuyShares:
|
|
|
|
factor = MyMoneyMoney(-1,1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
amount += (interest * factor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotUpdateTotalAmount(void)
|
|
|
|
{
|
|
|
|
TQLabel* total = dynamic_cast<TQLabel*>(haveWidget("total"));
|
|
|
|
|
|
|
|
if(total && total->isVisible()) {
|
|
|
|
MyMoneyMoney amount;
|
|
|
|
totalAmount(amount);
|
|
|
|
total->setText(amount.formatMoney(m_currency.tradingSymbol(), MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction())));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::slotUpdateActivity(MyMoneySplit::investTransactionTypeE activity)
|
|
|
|
{
|
|
|
|
// create new activity object if required
|
|
|
|
activityFactory(activity);
|
|
|
|
|
|
|
|
KMyMoneyCategory* cat;
|
|
|
|
|
|
|
|
// hide all dynamic widgets (make sure to use the parentWidget for the
|
|
|
|
// category widgets)
|
|
|
|
haveWidget("interest-account")->parentWidget()->hide();
|
|
|
|
haveWidget("fee-account")->parentWidget()->hide();
|
|
|
|
|
|
|
|
TQStringList dynwidgets;
|
|
|
|
dynwidgets << "total-label" << "asset-label" << "fee-label" << "fee-amount-label" << "interest-label" << "interest-amount-label" << "price-label" << "shares-label";
|
|
|
|
|
|
|
|
// hiding labels works by clearing them. hide() does not do the job
|
|
|
|
// as the underlying text in the TQTable object will shine through
|
|
|
|
TQStringList::const_iterator it_s;
|
|
|
|
for(it_s = dynwidgets.begin(); it_s != dynwidgets.end(); ++it_s) {
|
|
|
|
TQLabel* w = dynamic_cast<TQLabel*>(haveWidget(*it_s));
|
|
|
|
if(w)
|
|
|
|
w->setText(" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
// real widgets can be hidden
|
|
|
|
dynwidgets.clear();
|
|
|
|
dynwidgets << "asset-account" << "interest-amount" << "fee-amount" << "shares" << "price" << "total";
|
|
|
|
|
|
|
|
for(it_s = dynwidgets.begin(); it_s != dynwidgets.end(); ++it_s) {
|
|
|
|
TQWidget* w = haveWidget(*it_s);
|
|
|
|
if(w)
|
|
|
|
w->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
d->m_activity->showWidgets();
|
|
|
|
|
|
|
|
d->m_activity->preloadAssetAccount();
|
|
|
|
|
|
|
|
cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("interest-account"));
|
|
|
|
if(cat->parentWidget()->isVisible())
|
|
|
|
slotUpdateInterestVisibility(cat->currentText());
|
|
|
|
|
|
|
|
cat = dynamic_cast<KMyMoneyCategory*>(haveWidget("fee-account"));
|
|
|
|
if(cat->parentWidget()->isVisible())
|
|
|
|
slotUpdateFeeVisibility(cat->currentText());
|
|
|
|
}
|
|
|
|
|
|
|
|
InvestTransactionEditor::priceModeE InvestTransactionEditor::priceMode(void) const
|
|
|
|
{
|
|
|
|
priceModeE mode = static_cast<priceModeE>(0);
|
|
|
|
KMyMoneySecurity* sec = dynamic_cast<KMyMoneySecurity*>(m_editWidgets["security"]);
|
|
|
|
TQString accId;
|
|
|
|
if(!sec->currentText().isEmpty()) {
|
|
|
|
accId = sec->selectedItem();
|
|
|
|
if(accId.isEmpty())
|
|
|
|
accId = m_account.id();
|
|
|
|
}
|
|
|
|
while(!accId.isEmpty() && mode == 0) {
|
|
|
|
MyMoneyAccount acc = MyMoneyFile::instance()->account(accId);
|
|
|
|
if(acc.value("priceMode").isEmpty())
|
|
|
|
accId = acc.parentAccountId();
|
|
|
|
else
|
|
|
|
mode = static_cast<priceModeE>(acc.value("priceMode").toInt());
|
|
|
|
}
|
|
|
|
|
|
|
|
// if it's still <default> then use that default
|
|
|
|
if(mode == 0)
|
|
|
|
mode = PricePerShare;
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InvestTransactionEditor::setupPrice(const MyMoneyTransaction& t, MyMoneySplit& split)
|
|
|
|
{
|
|
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
|
|
MyMoneyAccount acc = file->account(split.accountId());
|
|
|
|
MyMoneySecurity toCurrency(file->security(acc.currencyId()));
|
|
|
|
int fract = acc.fraction();
|
|
|
|
|
|
|
|
if(acc.currencyId() != t.commodity()) {
|
|
|
|
TQMap<TQString, MyMoneyMoney>::Iterator it_p;
|
|
|
|
TQString key = t.commodity() + "-" + acc.currencyId();
|
|
|
|
it_p = m_priceInfo.find(key);
|
|
|
|
|
|
|
|
// if it's not found, then collect it from the user first
|
|
|
|
MyMoneyMoney price;
|
|
|
|
if(it_p == m_priceInfo.end()) {
|
|
|
|
MyMoneySecurity fromCurrency = file->security(t.commodity());
|
|
|
|
MyMoneyMoney fromValue, toValue;
|
|
|
|
|
|
|
|
fromValue = split.value();
|
|
|
|
MyMoneyPrice priceInfo = MyMoneyFile::instance()->price(fromCurrency.id(), toCurrency.id());
|
|
|
|
toValue = split.value() * priceInfo.rate(toCurrency.id());
|
|
|
|
|
|
|
|
KCurrencyCalculator calc(fromCurrency,
|
|
|
|
toCurrency,
|
|
|
|
fromValue,
|
|
|
|
toValue,
|
|
|
|
t.postDate(),
|
|
|
|
fract,
|
|
|
|
m_regForm, "currencyCalculator");
|
|
|
|
|
|
|
|
if(calc.exec() == TQDialog::Rejected) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
price = calc.price();
|
|
|
|
m_priceInfo[key] = price;
|
|
|
|
} else {
|
|
|
|
price = (*it_p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// update shares if the transaction commodity is the currency
|
|
|
|
// of the current selected account
|
|
|
|
split.setShares((split.value() * price).convert(fract));
|
|
|
|
} else {
|
|
|
|
split.setShares(split.value().convert(fract));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InvestTransactionEditor::createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool /* skipPriceDialog */)
|
|
|
|
{
|
|
|
|
MyMoneyFile* file = MyMoneyFile::instance();
|
|
|
|
// we start with the previous values, make sure we can add them later on
|
|
|
|
t = torig;
|
|
|
|
MyMoneySplit s0 = sorig;
|
|
|
|
s0.clearId();
|
|
|
|
|
|
|
|
KMyMoneySecurity* sec = dynamic_cast<KMyMoneySecurity*>(m_editWidgets["security"]);
|
|
|
|
if(!isMultiSelection() || (isMultiSelection() && !sec->currentText().isEmpty())) {
|
|
|
|
TQString securityId = sec->selectedItem();
|
|
|
|
if(!securityId.isEmpty()) {
|
|
|
|
s0.setAccountId(securityId);
|
|
|
|
MyMoneyAccount stockAccount = file->account(securityId);
|
|
|
|
TQString currencyId = stockAccount.currencyId();
|
|
|
|
MyMoneySecurity security = file->security(currencyId);
|
|
|
|
|
|
|
|
t.setCommodity(security.tradingCurrency());
|
|
|
|
} else {
|
|
|
|
s0.setAccountId(m_account.id());
|
|
|
|
t.setCommodity(m_account.currencyId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// extract price info from original transaction
|
|
|
|
m_priceInfo.clear();
|
|
|
|
TQValueList<MyMoneySplit>::const_iterator it_s;
|
|
|
|
if(!torig.id().isEmpty()) {
|
|
|
|
for(it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) {
|
|
|
|
if((*it_s).id() != sorig.id()) {
|
|
|
|
MyMoneyAccount cat = file->account((*it_s).accountId());
|
|
|
|
if(cat.currencyId() != m_account.currencyId()) {
|
|
|
|
if(!(*it_s).shares().isZero() && !(*it_s).value().isZero()) {
|
|
|
|
m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
t.removeSplits();
|
|
|
|
|
|
|
|
kMyMoneyDateInput* postDate = dynamic_cast<kMyMoneyDateInput*>(m_editWidgets["postdate"]);
|
|
|
|
if(postDate->date().isValid()) {
|
|
|
|
t.setPostDate(postDate->date());
|
|
|
|
}
|
|
|
|
|
|
|
|
// memo and number field are special: if we have multiple transactions selected
|
|
|
|
// and the edit field is empty, we treat it as "not modified".
|
|
|
|
// FIXME a better approach would be to have a 'dirty' flag with the widgets
|
|
|
|
// which identifies if the originally loaded value has been modified
|
|
|
|
// by the user
|
|
|
|
KTextEdit* memo = dynamic_cast<KTextEdit*>(m_editWidgets["memo"]);
|
|
|
|
if(memo) {
|
|
|
|
if(!isMultiSelection() || (isMultiSelection() && !memo->text().isEmpty() ) )
|
|
|
|
s0.setMemo(memo->text());
|
|
|
|
}
|
|
|
|
|
|
|
|
MyMoneySplit assetAccountSplit;
|
|
|
|
TQValueList<MyMoneySplit> feeSplits;
|
|
|
|
TQValueList<MyMoneySplit> interestSplits;
|
|
|
|
MyMoneySecurity security, currency;
|
|
|
|
MyMoneySplit::investTransactionTypeE transactionType;
|
|
|
|
|
|
|
|
// extract the splits from the original transaction
|
|
|
|
dissectTransaction(torig, sorig,
|
|
|
|
assetAccountSplit,
|
|
|
|
feeSplits,
|
|
|
|
interestSplits,
|
|
|
|
security,
|
|
|
|
currency,
|
|
|
|
transactionType);
|
|
|
|
|
|
|
|
// check if the trading currency is the same if the security has changed
|
|
|
|
// in case it differs, check that we have a price (request from user)
|
|
|
|
// and convert all splits
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// do the conversions here
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// keep the current activity object and create a new one
|
|
|
|
// that can be destroyed later on
|
|
|
|
Activity* activity = d->m_activity;
|
|
|
|
d->m_activity = 0; // make sure we create a new one
|
|
|
|
activityFactory(activity->type());
|
|
|
|
|
|
|
|
// if the activity is not set in the combo widget, we keep
|
|
|
|
// the one which is used in the original transaction
|
|
|
|
KMyMoneyActivityCombo* activityCombo = dynamic_cast<KMyMoneyActivityCombo*>(haveWidget("activity"));
|
|
|
|
if(activityCombo->activity() == MyMoneySplit::UnknownTransactionType) {
|
|
|
|
activityFactory(transactionType);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we mark the split reconciled here, we'll use today's date if no reconciliation date is given
|
|
|
|
KMyMoneyReconcileCombo* status = dynamic_cast<KMyMoneyReconcileCombo*>(m_editWidgets["status"]);
|
|
|
|
if(status->state() != MyMoneySplit::Unknown)
|
|
|
|
s0.setReconcileFlag(status->state());
|
|
|
|
|
|
|
|
if(s0.reconcileFlag() == MyMoneySplit::Reconciled && !s0.reconcileDate().isValid())
|
|
|
|
s0.setReconcileDate(TQDate::currentDate());
|
|
|
|
|
|
|
|
// call the creation logic for the current selected activity
|
|
|
|
bool rc = d->m_activity->createTransaction(t, s0, assetAccountSplit, feeSplits, m_feeSplits, interestSplits, m_interestSplits, security, currency);
|
|
|
|
|
|
|
|
// now switch back to the original activity
|
|
|
|
delete d->m_activity;
|
|
|
|
d->m_activity = activity;
|
|
|
|
|
|
|
|
// add the splits to the transaction
|
|
|
|
if(rc) {
|
|
|
|
if(!assetAccountSplit.accountId().isEmpty()) {
|
|
|
|
assetAccountSplit.clearId();
|
|
|
|
t.addSplit(assetAccountSplit);
|
|
|
|
}
|
|
|
|
|
|
|
|
t.addSplit(s0);
|
|
|
|
|
|
|
|
TQValueList<MyMoneySplit>::iterator it_s;
|
|
|
|
for(it_s = feeSplits.begin(); it_s != feeSplits.end(); ++it_s) {
|
|
|
|
(*it_s).clearId();
|
|
|
|
t.addSplit(*it_s);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(it_s = interestSplits.begin(); it_s != interestSplits.end(); ++it_s) {
|
|
|
|
(*it_s).clearId();
|
|
|
|
t.addSplit(*it_s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust the value to the smallestAccountFraction found
|
|
|
|
// for the commodity of the transaction.
|
|
|
|
for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
|
|
|
|
MyMoneySplit s = (*it_s);
|
|
|
|
s.setValue((*it_s).value().convert(currency.smallestAccountFraction()));
|
|
|
|
t.modifySplit(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::updatePriceMode(const MyMoneySplit& split)
|
|
|
|
{
|
|
|
|
TQLabel* label = dynamic_cast<TQLabel*>(haveWidget("price-label"));
|
|
|
|
if(label) {
|
|
|
|
kMyMoneyEdit* sharesEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("shares"));
|
|
|
|
kMyMoneyEdit* priceEdit = dynamic_cast<kMyMoneyEdit*>(haveWidget("price"));
|
|
|
|
MyMoneyMoney price;
|
|
|
|
if(!split.id().isEmpty())
|
|
|
|
price = split.price().reduce();
|
|
|
|
else
|
|
|
|
price = priceEdit->value().abs();
|
|
|
|
|
|
|
|
if(priceMode() == PricePerTransaction && label->text() != i18n("Price")) {
|
|
|
|
label->setText(i18n("Price"));
|
|
|
|
if(!sharesEdit->value().isZero())
|
|
|
|
priceEdit->setValue(sharesEdit->value().abs() * price);
|
|
|
|
|
|
|
|
} else if(priceMode() == PricePerShare && label->text() == i18n("Price")) {
|
|
|
|
label->setText(i18n("Price/Share"));
|
|
|
|
if(!sharesEdit->value().isZero())
|
|
|
|
priceEdit->setValue(price / sharesEdit->value().abs());
|
|
|
|
|
|
|
|
} else if(priceMode() == PricePerTransaction) {
|
|
|
|
priceEdit->setValue(sharesEdit->value().abs() * price);
|
|
|
|
|
|
|
|
} else
|
|
|
|
priceEdit->setValue(price);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InvestTransactionEditor::setupFinalWidgets(void)
|
|
|
|
{
|
|
|
|
addFinalWidget(haveWidget("memo"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "investtransactioneditor.moc"
|
|
|
|
|