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.
kmymoney/kmymoney2/dialogs/keditloanwizard.cpp

519 lines
19 KiB

/***************************************************************************
keditloanwizard.cpp - description
-------------------
begin : Wed Nov 12 2003
copyright : (C) 2000-2003 by Michael Edwardes
email : mte@users.sourceforge.net
Javier Campos Morales <javi_c@users.sourceforge.net>
Felix Rodriguez <frodriguez@users.sourceforge.net>
John C <thetacoturtle@users.sourceforge.net>
Thomas Baumgart <ipwizard@users.sourceforge.net>
Kevin Tambascio <ktambascio@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
// ----------------------------------------------------------------------------
// TQt Includes
#include <tqradiobutton.h>
#include <tqbuttongroup.h>
#include <tqlabel.h>
// ----------------------------------------------------------------------------
// TDE Includes
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <knuminput.h>
#include <kpushbutton.h>
// ----------------------------------------------------------------------------
// Project Includes
#include <../dialogs/knewloanwizard.h>
#include "keditloanwizard.h"
#include "../widgets/kmymoneylineedit.h"
#include "../widgets/kmymoneyedit.h"
#include "../widgets/kmymoneycombo.h"
#include "../widgets/kmymoneyaccountselector.h"
#include "../widgets/kmymoneydateinput.h"
#include "../mymoney/mymoneyfile.h"
#include "../kmymoneyutils.h"
KEditLoanWizard::KEditLoanWizard(const MyMoneyAccount& account, TQWidget *parent, const char *name ) :
KNewLoanWizard(parent, name)
{
MyMoneyFile* file = MyMoneyFile::instance();
setCaption(i18n("Edit loan wizard"));
m_effectiveDateLabel->setText(TQString("\n") + i18n(
"Please enter the date from which on the following changes will be effective. "
"The date entered must be later than the opening date of this account (%1), but must "
"not be in the future. The default will be today.").arg(TDEGlobal::locale()->formatDate(account.openingDate(), true)));
m_account = account;
try {
TQString id = m_account.value("schedule");
m_schedule = file->schedule(id);
} catch (MyMoneyException *e) {
delete e;
}
m_lastSelection = -1;
m_editInterestRateButton->animateClick();
loadWidgets(m_account);
if(m_account.openingDate() > TQDate::currentDate()) {
m_effectiveDateNoteLabel->setText(TQString("\n") + i18n(
"Note: you will not be able to modify this account today, because the opening date \"%1\" is in the future. "
"Please revisit this dialog when the time has come."
).arg(TDEGlobal::locale()->formatDate(m_account.openingDate(), true)));
} else {
m_effectiveDateNoteLabel->hide();
}
// turn off all pages that are contained here for derived classes
setAppropriate(m_newIntroPage, false);
setAppropriate(m_newGeneralInfoPage, false);
setAppropriate(m_lendBorrowPage, false);
setAppropriate(m_namePage, false);
setAppropriate(m_newCalculateLoanPage, false);
setAppropriate(m_newPaymentsPage, false);
removePage(m_assetAccountPage);
m_assetAccountPage = 0;
// turn on all pages that are contained here for derived classes
setAppropriate(m_editIntroPage, true);
setAppropriate(m_editSelectionPage, true);
// setup connections
connect(m_effectiveChangeDateEdit, TQ_SIGNAL(dateChanged(const TQDate&)), this, TQ_SLOT(slotCheckPageFinished()));
connect(m_newPaymentEdit, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(slotCheckPageFinished()));
connect(m_newInterestRateEdit, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(slotCheckPageFinished()));
// make sure, we show the correct start page
showPage(m_editIntroPage);
}
KEditLoanWizard::~KEditLoanWizard()
{
}
void KEditLoanWizard::loadWidgets(const MyMoneyAccount& /* account */)
{
MyMoneyFile* file = MyMoneyFile::instance();
TQString paymentAccountId, interestAccountId;
m_nameEdit->loadText(m_account.name());
m_loanAmountEdit->loadText(m_account.loanAmount().formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
m_finalPaymentEdit->loadText(m_account.finalPayment().formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
m_firstDueDateEdit->setDate(m_account.openingDate());
if(m_account.fixedInterestRate()) {
m_fixedInterestButton->animateClick();
} else {
m_variableInterestButton->animateClick();
}
MyMoneyMoney ir;
if(m_schedule.startDate() > TQDate::currentDate()) {
ir = m_account.interestRate(m_schedule.startDate());
} else {
ir = m_account.interestRate(TQDate::currentDate());
}
m_interestRateEdit->loadText(ir.formatMoney("", 3));
m_newInterestRateEdit->loadText(ir.formatMoney("", 3));
m_newInterestRateEdit->setPrecision(3);
m_interestRateLabel->setText(TQString(" ") + ir.formatMoney("", 3) + TQString("%"));
m_paymentFrequencyUnitEdit->setCurrentItem(i18n(m_schedule.occurenceToString().utf8()));
updateTermWidgets(m_account.term());
// the base payment (amortization and interest) is determined
// by adding all splits that are not automatically calculated.
// If the loan is a liability, we reverse the sign at the end
MyMoneyMoney basePayment;
MyMoneyMoney addPayment;
m_transaction = m_schedule.transaction();
TQValueList<MyMoneySplit>::ConstIterator it_s;
for(it_s = m_schedule.transaction().splits().begin();
it_s != m_schedule.transaction().splits().end();
++it_s) {
MyMoneyAccount acc = file->account((*it_s).accountId());
// if it's the split that references the source/dest
// of the money, we check if we borrow or loan money
if(paymentAccountId.isEmpty()
&& acc.isAssetLiability() && !acc.isLoan()
&& (*it_s).value() != MyMoneyMoney::autoCalc) {
if((*it_s).value().isNegative()) {
m_lendButton->setChecked(false);
m_borrowButton->setChecked(true);
} else {
m_lendButton->setChecked(true);
m_borrowButton->setChecked(false);
}
// we keep the amount of the full payment and subtract the
// base payment later to get information about the additional payment
addPayment = (*it_s).value();
paymentAccountId = (*it_s).accountId();
MyMoneyPayee payee;
if(!(*it_s).payeeId().isEmpty()) {
try {
payee = file->payee((*it_s).payeeId());
m_payeeEdit->setSelectedItem(payee.id());
} catch(MyMoneyException *e) {
delete e;
tqWarning("Payee for schedule has been deleted");
}
}
// remove this split with one that will be replaced
// later and has a phony id
m_transaction.removeSplit(*it_s);
m_split.clearId();
m_transaction.addSplit(m_split);
}
if((*it_s).action() == MyMoneySplit::ActionInterest) {
interestAccountId = (*it_s).accountId();
}
if((*it_s).value() != MyMoneyMoney::autoCalc) {
basePayment += (*it_s).value();
} else {
// remove the splits which should not show up
// for additional fees
m_transaction.removeSplit(*it_s);
}
}
if(m_borrowButton->isChecked()) {
basePayment = -basePayment;
addPayment = -addPayment;
}
// now make adjustment to get the amount of the additional fees
addPayment -= basePayment;
// load account selection widgets now that we know if
// we borrow or lend money
loadAccountList();
int fraction = m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()));
m_paymentEdit->loadText(basePayment.formatMoney(fraction));
m_newPaymentEdit->loadText(basePayment.formatMoney(fraction));
m_paymentLabel->setText(TQString(" ") + basePayment.formatMoney(fraction));
m_additionalCost->setText(addPayment.formatMoney(fraction));
m_interestAccountEdit->setSelected(interestAccountId);
m_paymentAccountEdit->setSelected(paymentAccountId);
m_nextDueDateEdit->setDate(m_schedule.nextPayment());
int changeFrequencyUnit;
int amt = m_account.interestChangeFrequency(&changeFrequencyUnit);
if(amt != -1) {
m_interestFrequencyAmountEdit->setValue(amt);
m_interestFrequencyUnitEdit->setCurrentItem(changeFrequencyUnit);
}
// keep track, if the loan should be fully repayed
m_fullyRepayLoan = m_account.finalPayment() < basePayment;
updateLoanInfo();
updateSummary();
}
void KEditLoanWizard::next()
{
bool dontLeavePage = false;
TQButton* button = m_selectionButtonGroup->find(m_lastSelection);
if(currentPage() == m_editSelectionPage) {
if(button != 0
&& m_lastSelection != m_selectionButtonGroup->id(m_selectionButtonGroup->selected())) {
TQString errMsg = i18n(
"Your previous selection was \"%1\". If you select another option, "
"KMyMoney will dismiss the changes you have just entered. "
"Do you wish to proceed?").arg(button->text());
if(KMessageBox::questionYesNo(this, errMsg) == KMessageBox::No) {
dontLeavePage = true;
} else {
loadWidgets(m_account);
}
}
if(!dontLeavePage) {
button = m_selectionButtonGroup->selected();
// turn off all pages except the summary at the end
// and the one's we need for the selected option
// and load the widgets with the current values
// general info
setAppropriate(m_namePage, false);
setAppropriate(m_interestTypePage, false);
setAppropriate(m_previousPaymentsPage, false);
setAppropriate(m_recordPaymentPage, false);
setAppropriate(m_variableInterestDatePage, false);
setAppropriate(m_firstPaymentPage, false);
// loan calculation
setAppropriate(m_paymentEditPage, false);
setAppropriate(m_interestEditPage, false);
setAppropriate(m_paymentFrequencyPage, false);
setAppropriate(m_interestCalculationPage, false);
setAppropriate(m_loanAmountPage, false);
setAppropriate(m_interestPage, false);
setAppropriate(m_durationPage, false);
setAppropriate(m_paymentPage, false);
setAppropriate(m_finalPaymentPage, false);
setAppropriate(m_calculationOverviewPage, false);
// payment
setAppropriate(m_interestCategoryPage, false);
setAppropriate(m_additionalFeesPage, false);
setAppropriate(m_schedulePage, false);
setAppropriate(m_summaryPage, true);
setAppropriate(m_effectiveDatePage, true);
if(indexOf(m_summaryPage) != -1) {
removePage(m_summaryPage);
setFinishEnabled(m_summaryEditPage, true);
}
if(button == m_editInterestRateButton) {
setAppropriate(m_interestTypePage, true);
setAppropriate(m_variableInterestDatePage, true);
setAppropriate(m_paymentEditPage, true);
setAppropriate(m_interestEditPage, true);
setAppropriate(m_summaryEditPage, true);
} else if(button == m_editOtherCostButton) {
setAppropriate(m_additionalFeesPage, true);
setAppropriate(m_summaryEditPage, true);
} else if(button == m_editOtherInfoButton) {
setAppropriate(m_namePage, true);
setAppropriate(m_interestCalculationPage, true);
setAppropriate(m_interestPage, true);
setAppropriate(m_durationPage, true);
setAppropriate(m_paymentPage, true);
setAppropriate(m_finalPaymentPage, true);
setAppropriate(m_calculationOverviewPage, true);
setAppropriate(m_interestCategoryPage, true);
setAppropriate(m_additionalFeesPage, true);
setAppropriate(m_schedulePage, true);
setAppropriate(m_summaryEditPage, false);
addPage(m_summaryPage, i18n("Summary"));
setAppropriate(m_summaryPage, true);
setFinishEnabled(m_summaryEditPage, false);
setFinishEnabled(m_summaryPage, true);
} else {
tqFatal("%s,%d: This should never happen", __FILE__, __LINE__);
}
m_lastSelection = m_selectionButtonGroup->id(m_selectionButtonGroup->selected());
} // if(!dontLeavePage)
} else if(currentPage() == m_additionalFeesPage) {
button = m_selectionButtonGroup->selected();
if(button == m_editOtherCostButton) {
updateLoanInfo();
updateEditSummary();
}
} else if(currentPage() == m_interestEditPage) {
// copy the necessary data to the widgets used for calculation
m_interestRateEdit->setValue(m_newInterestRateEdit->value());
m_paymentEdit->setValue(m_newPaymentEdit->value());
// if interest rate and payment amount is given, then force
// the term to be recalculated. The final payment is adjusted to
// 0 if the loan was ment to be fully repayed
updateTermWidgets(m_account.term());
if(!m_interestRateEdit->lineedit()->text().isEmpty()
&& !m_paymentEdit->lineedit()->text().isEmpty()) {
// if there's an amortization going on, we can evaluate
// the new term. If the amortization is 0 (interest only
// payments) then we keep the term as entered by the user.
if(m_loanAmountEdit->value() != m_finalPaymentEdit->value()) {
m_durationValueEdit->setValue(0);
}
if(m_fullyRepayLoan)
m_finalPaymentEdit->loadText(MyMoneyMoney(0).formatMoney(m_account.fraction(MyMoneyFile::instance()->security(m_account.currencyId()))));
}
/*
// we need to calculate the balance at the time of the change
// in order to accurately recalculate the term. A special
// situation arises, when we keep track of all payments and
// the full loan is not yet paid out. In this case, we take the
// the loan amount minus all amortization payments as the current
// balance.
// FIXME: This needs some more thoughts. We leave it out for
// now and always calculate with the full loan amount.
MyMoneyMoney balance = m_account.openingBalance();
TQValueList<MyMoneyTransaction> list;
TQValueList<MyMoneyTransaction>::ConstIterator it;
MyMoneySplit split;
MyMoneyTransactionFilter filter(m_account.id());
filter.setDateFilter(TQDate(), m_effectiveChangeDateEdit->date().addDays(-1));
list = MyMoneyFile::instance()->transactionList(filter);
for(it = list.begin(); it != list.end(); ++it) {
try {
split = (*it).splitByAccount(m_account.id());
balance += split.value();
} catch(MyMoneyException *e) {
// account is not referenced within this transaction
delete e;
}
}
m_loanAmountEdit->setText(balance.formatMoney());
*/
// now re-calculate the figures
dontLeavePage = !calculateLoan();
// reset the original loan amount to the widget
m_loanAmountEdit->setValue(m_account.loanAmount());
if(!dontLeavePage) {
updateLoanInfo();
updateEditSummary();
}
}
if(!dontLeavePage)
KNewLoanWizard::next();
// These might have been set by KNewLoanWizard::next()
setAppropriate(m_previousPaymentsPage, false);
setAppropriate(m_recordPaymentPage, false);
// we never need to show this page
if(currentPage() == m_previousPaymentsPage)
KNewLoanWizard::next();
}
void KEditLoanWizard::slotCheckPageFinished(void)
{
KNewLoanWizard::slotCheckPageFinished();
// if we're on one of the specific edit pages, the next button
// is enabled. If the values in the edit widgets are not
// appropriate, we just have to disable it.
if(currentPage() == m_effectiveDatePage) {
if(m_effectiveChangeDateEdit->date() < m_account.openingDate()
|| m_effectiveChangeDateEdit->date() > TQDate::currentDate())
nextButton()->setEnabled(false);
} else if(currentPage() == m_interestEditPage) {
if(!m_newPaymentEdit->isValid()
&& !m_newInterestRateEdit->isValid())
nextButton()->setEnabled(false);
}
}
void KEditLoanWizard::updateEditSummary(void)
{
updateSummary();
m_payment7->setText(m_summaryPeriodicPayment->text());
m_additionalFees7->setText(m_summaryAdditionalFees->text());
m_totalPayment7->setText(m_summaryTotalPeriodicPayment->text());
m_interestRate7->setText(m_summaryInterestRate->text());
m_startDateChanges->setText(TDEGlobal::locale()->formatDate(m_effectiveChangeDateEdit->date(), true));
// calculate the number of affected transactions
MyMoneyTransactionFilter filter(m_account.id());
filter.setDateFilter(m_effectiveChangeDateEdit->date(), TQDate());
int count = 0;
TQValueList<MyMoneyTransaction> list;
TQValueList<MyMoneyTransaction>::ConstIterator it;
list = MyMoneyFile::instance()->transactionList(filter);
for(it = list.begin(); it != list.end(); ++it) {
TQValueList<MyMoneySplit>::ConstIterator it_s;
int match = 0;
for(it_s = (*it).splits().begin(); it_s != (*it).splits().end(); ++it_s) {
// we only count those transactions that have an interest
// and amortization part
if((*it_s).action() == MyMoneySplit::ActionInterest)
match |= 0x01;
if((*it_s).action() == MyMoneySplit::ActionAmortization)
match |= 0x02;
}
if(match == 0x03)
count++;
}
m_affectedPayments->setText(TQString().sprintf("%d", count));
}
const MyMoneySchedule KEditLoanWizard::schedule(void) const
{
MyMoneySchedule sched = m_schedule;
sched.setTransaction(transaction());
sched.setOccurence(MyMoneySchedule::stringToOccurence(m_paymentFrequencyUnitEdit->currentText()));
if(m_nextDueDateEdit->date() < m_schedule.startDate())
sched.setStartDate(m_nextDueDateEdit->date());
return sched;
}
const MyMoneyAccount KEditLoanWizard::account(void) const
{
MyMoneyAccountLoan acc(m_account);
if(m_interestOnReceptionButton->isChecked())
acc.setInterestCalculation(MyMoneyAccountLoan::paymentReceived);
else
acc.setInterestCalculation(MyMoneyAccountLoan::paymentDue);
acc.setFixedInterestRate(m_fixedInterestButton->isChecked());
acc.setFinalPayment(MyMoneyMoney(m_finalPaymentEdit->text()));
acc.setTerm(term());
acc.setPeriodicPayment(m_paymentEdit->value());
acc.setInterestRate(m_effectiveChangeDateEdit->date(), m_interestRateEdit->value());
acc.setPayee(m_payeeEdit->selectedItem());
if(m_variableInterestButton->isChecked()) {
acc.setNextInterestChange(m_interestChangeDateEdit->date());
acc.setInterestChangeFrequency(m_interestFrequencyAmountEdit->value(),
m_interestFrequencyUnitEdit->currentItem());
}
return acc;
}
const MyMoneyTransaction KEditLoanWizard::transaction() const
{
MyMoneyTransaction t = KNewLoanWizard::transaction();
MyMoneySplit s = t.splitByAccount(TQString("Phony-ID"));
s.setAccountId(m_account.id());
t.modifySplit(s);
return t;
}
#include "keditloanwizard.moc"