diff options
Diffstat (limited to 'kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp')
-rw-r--r-- | kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp | 1691 |
1 files changed, 1691 insertions, 0 deletions
diff --git a/kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp b/kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp new file mode 100644 index 0000000..1bfae86 --- /dev/null +++ b/kmymoney2/wizards/newaccountwizard/knewaccountwizard.cpp @@ -0,0 +1,1691 @@ +/*************************************************************************** + knewaccountwizard.cpp + ------------------- + begin : Tue Sep 25 2006 + copyright : (C) 2007 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. * + * * + ***************************************************************************/ + +#include <locale.h> + +// ---------------------------------------------------------------------------- +// QT Includes + +#include <qcheckbox.h> +#include <qfocusdata.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qlabel.h> + +// ---------------------------------------------------------------------------- +// KDE Includes + +#include <klocale.h> +#include <klistbox.h> +#include <klineedit.h> +#include <kmessagebox.h> +#include <knuminput.h> + +// ---------------------------------------------------------------------------- +// Project Includes + +#include <kmymoney/kmymoneycombo.h> +#include <kmymoney/kmymoneyedit.h> +#include <kmymoney/kmymoneycategory.h> +#include <kmymoney/mymoneyfile.h> +#include <kmymoney/kmymoneycurrencyselector.h> +#include <kmymoney/kmymoneyaccountselector.h> +#include <kmymoney/kmymoneyaccounttree.h> +#include <kmymoney/mymoneyfinancialcalculator.h> +#include <kmymoney/kmymoneychecklistitem.h> +#include <kmymoney/kmymoneylistviewitem.h> +#include <kmymoney/kcurrencycalculator.h> +#include <kmymoney/mymoneyaccount.h> +#include <kmymoney/kmymoneyglobalsettings.h> + +#include "knewaccountwizard.h" +#include "knewaccountwizard_p.h" +#include <kmymoney/kguiutils.h> + +#include "../../dialogs/ksplittransactiondlg.h" +#include "../../dialogs/kequitypriceupdatedlg.h" +#include "../../kmymoney2.h" + +using namespace NewAccountWizard; + +namespace NewAccountWizard { + enum steps { + StepInstitution = 1, + StepAccount, + StepBroker, + StepDetails, + StepPayments, + StepFees, + StepSchedule, + StepPayout, + StepParentAccount, + StepFinish + }; +}; +NewAccountWizard::Wizard::Wizard(QWidget *parent, const char *name, bool modal, WFlags flags) + : KMyMoneyWizard(parent, name, modal, flags) +{ + setTitle(i18n("KMyMoney New Account Setup")); + addStep(i18n("Institution")); + addStep(i18n("Account")); + addStep(i18n("Broker")); + addStep(i18n("Details")); + addStep(i18n("Payments")); + addStep(i18n("Fees")); + addStep(i18n("Schedule")); + addStep(i18n("Payout")); + addStep(i18n("Parent Account")); + addStep(i18n("Finish")); + setStepHidden(StepBroker); + setStepHidden(StepSchedule); + setStepHidden(StepPayout); + setStepHidden(StepDetails); + setStepHidden(StepPayments); + setStepHidden(StepFees); + + m_institutionPage = new InstitutionPage(this); + m_accountTypePage = new AccountTypePage(this); + // Investment Pages + m_brokeragepage = new BrokeragePage(this); + // Credit Card Pages + m_schedulePage = new CreditCardSchedulePage(this); + // Loan Pages + m_generalLoanInfoPage = new GeneralLoanInfoPage(this); + m_loanDetailsPage = new LoanDetailsPage(this); + m_loanPaymentPage = new LoanPaymentPage(this); + m_loanSchedulePage = new LoanSchedulePage(this); + m_loanPayoutPage = new LoanPayoutPage(this); + // Not a loan page + m_hierarchyPage = new HierarchyPage(this); + // Finish + m_accountSummaryPage = new AccountSummaryPage(this); + + setFirstPage(m_institutionPage); +} + +void NewAccountWizard::Wizard::setAccount(const MyMoneyAccount& acc) +{ + m_account = acc; + m_accountTypePage->setAccount(m_account); +} + +const MyMoneySecurity& NewAccountWizard::Wizard::currency(void) const +{ + return m_accountTypePage->currency(); +} + +MyMoneyMoney NewAccountWizard::Wizard::interestRate(void) const +{ + return m_loanDetailsPage->m_interestRate->value() / MyMoneyMoney(100,1); +} + +int NewAccountWizard::Wizard::precision(void) const +{ + return MyMoneyMoney::denomToPrec(currency().smallestAccountFraction()); +} + +const MyMoneyAccount& NewAccountWizard::Wizard::account(void) +{ + m_account = MyMoneyAccountLoan(); + m_account.setName(m_accountTypePage->m_accountName->text()); + m_account.setOpeningDate(m_accountTypePage->m_openingDate->date()); + m_account.setAccountType(m_accountTypePage->accountType()); + m_account.setInstitutionId(m_institutionPage->institution().id()); + m_account.setNumber(m_institutionPage->m_accountNumber->text()); + m_account.setValue("IBAN", m_institutionPage->m_iban->text()); + if(m_accountTypePage->m_preferredAccount->isChecked()) + m_account.setValue("PreferredAccount", "Yes"); + else + m_account.deletePair("PreferredAccount"); + + m_account.setCurrencyId(currency().id()); + if(m_account.isLoan()) { + // in case we lend the money we adjust the account type + if(!moneyBorrowed()) + m_account.setAccountType(MyMoneyAccount::AssetLoan); + m_account.setLoanAmount(m_loanDetailsPage->m_loanAmount->value()); + m_account.setInterestRate(m_account.openingDate(), m_loanDetailsPage->m_interestRate->value()); + m_account.setInterestCalculation(m_loanDetailsPage->m_paymentDue->currentItem() == 0 ? MyMoneyAccountLoan::paymentReceived : MyMoneyAccountLoan::paymentDue); + m_account.setFixedInterestRate(m_generalLoanInfoPage->m_interestType->currentItem() == 0); + m_account.setFinalPayment(m_loanDetailsPage->m_balloonAmount->value()); + m_account.setTerm(m_loanDetailsPage->term()); + m_account.setPeriodicPayment(m_loanDetailsPage->m_paymentAmount->value()); + m_account.setPayee(m_generalLoanInfoPage->m_payee->selectedItem()); + m_account.setInterestCompounding(m_generalLoanInfoPage->m_compoundFrequency->currentItem()); + + if(!m_account.fixedInterestRate()) { + m_account.setNextInterestChange(m_generalLoanInfoPage->m_interestChangeDateEdit->date()); + m_account.setInterestChangeFrequency(m_generalLoanInfoPage->m_interestFrequencyAmountEdit->value(), m_generalLoanInfoPage->m_interestFrequencyUnitEdit->currentItem()); + } + } + return m_account; +} + +MyMoneyTransaction NewAccountWizard::Wizard::payoutTransaction(void) +{ + MyMoneyTransaction t; + if(m_account.isLoan() // we're creating a loan + && openingBalance().isZero() // and don't have an opening balance + && !m_loanPayoutPage->m_noPayoutTransaction->isChecked()) { // and the user wants to have a payout transaction + t.setPostDate(m_loanPayoutPage->m_payoutDate->date()); + t.setCommodity(m_account.currencyId()); + MyMoneySplit s; + s.setAccountId(m_account.id()); + s.setShares(m_loanDetailsPage->m_loanAmount->value()); + if(moneyBorrowed()) + s.setShares(-s.shares()); + s.setValue(s.shares()); + t.addSplit(s); + + s.clearId(); + s.setValue(-s.value()); + s.setAccountId(m_loanPayoutPage->payoutAccountId()); + MyMoneyMoney shares; + KCurrencyCalculator::setupSplitPrice(shares, t, s, QMap<QString, MyMoneyMoney>(), this); + s.setShares(shares); + t.addSplit(s); + } + return t; +} + +const MyMoneyAccount& NewAccountWizard::Wizard::parentAccount(void) +{ + return m_accountTypePage->allowsParentAccount() + ? m_hierarchyPage->parentAccount() + : ( m_accountTypePage->accountType() == MyMoneyAccount::Loan + ? m_generalLoanInfoPage->parentAccount() + : m_accountTypePage->parentAccount() ); +} + +MyMoneyAccount NewAccountWizard::Wizard::brokerageAccount(void) const +{ + MyMoneyAccount account; + if(m_account.accountType() == MyMoneyAccount::Investment + && m_brokeragepage->m_createBrokerageButton->isChecked()) { + account.setName(m_account.brokerageName()); + account.setAccountType(MyMoneyAccount::Checkings); + account.setInstitutionId(m_account.institutionId()); + account.setOpeningDate(m_account.openingDate()); + account.setCurrencyId(m_brokeragepage->m_brokerageCurrency->security().id()); + if(m_brokeragepage->m_accountNumber->isEnabled() && !m_brokeragepage->m_accountNumber->text().isEmpty()) + account.setNumber(m_brokeragepage->m_accountNumber->text()); + if(m_brokeragepage->m_iban->isEnabled() && !m_brokeragepage->m_iban->text().isEmpty()) + account.setValue("IBAN", m_brokeragepage->m_iban->text()); + } + return account; +} + +const MyMoneySchedule& NewAccountWizard::Wizard::schedule(void) +{ + m_schedule = MyMoneySchedule(); + + if(!m_account.id().isEmpty()) { + if(m_schedulePage->m_reminderCheckBox->isChecked() && (m_account.accountType() == MyMoneyAccount::CreditCard)) { + m_schedule.setName(m_schedulePage->m_name->text()); + m_schedule.setType(MyMoneySchedule::TYPE_TRANSFER); + m_schedule.setPaymentType(static_cast<MyMoneySchedule::paymentTypeE>(m_schedulePage->m_method->currentItem())); + m_schedule.setFixed(false); + m_schedule.setOccurencePeriod(MyMoneySchedule::OCCUR_MONTHLY); + m_schedule.setOccurenceMultiplier(1); + MyMoneyTransaction t; + MyMoneySplit s; + s.setPayeeId(m_schedulePage->m_payee->selectedItem()); + s.setAccountId(m_schedulePage->m_paymentAccount->selectedItem()); + s.setMemo(i18n("Credit card payment")); + s.setShares(-m_schedulePage->m_amount->value()); + s.setValue(s.shares()); + t.addSplit(s); + + s.clearId(); + s.setAccountId(m_account.id()); + s.setShares(m_schedulePage->m_amount->value()); + s.setValue(s.shares()); + t.addSplit(s); + + // setup the next due date + t.setPostDate(m_schedulePage->m_date->date()); + m_schedule.setTransaction(t); + + } else if(m_account.isLoan()) { + m_schedule.setName(i18n("Loan payment for %1").arg(m_accountTypePage->m_accountName->text())); + m_schedule.setType(MyMoneySchedule::TYPE_LOANPAYMENT); + if(moneyBorrowed()) + m_schedule.setPaymentType(MyMoneySchedule::STYPE_DIRECTDEBIT); + else + m_schedule.setPaymentType(MyMoneySchedule::STYPE_DIRECTDEPOSIT); + + m_schedule.setFixed(true); + m_schedule.setOccurence(m_generalLoanInfoPage->m_paymentFrequency->currentItem()); + + MyMoneyTransaction t; + MyMoneySplit s; + // payment split + s.setPayeeId(m_generalLoanInfoPage->m_payee->selectedItem()); + s.setAccountId(m_loanSchedulePage->m_paymentAccount->selectedItem()); + s.setMemo(i18n("Loan payment")); + if(moneyBorrowed()) { + s.setShares(-(m_loanPaymentPage->basePayment() + m_loanPaymentPage->additionalFees())); + } else { + s.setShares(m_loanPaymentPage->basePayment() + m_loanPaymentPage->additionalFees()); + } + s.setValue(s.shares()); + t.addSplit(s); + + // principal split + s.clearId(); + s.setAccountId(m_account.id()); + s.setShares(MyMoneyMoney::autoCalc); + s.setValue(MyMoneyMoney::autoCalc); + s.setMemo(i18n("Amortization")); + s.setAction(MyMoneySplit::ActionAmortization); + t.addSplit(s); + + // interest split + s.clearId(); + s.setAccountId(m_loanSchedulePage->m_interestCategory->selectedItem()); + s.setShares(MyMoneyMoney::autoCalc); + s.setValue(MyMoneyMoney::autoCalc); + s.setMemo(i18n("Interest")); + s.setAction(MyMoneySplit::ActionInterest); + t.addSplit(s); + + // additional fee splits + QValueList<MyMoneySplit> additionalSplits; + m_loanPaymentPage->additionalFeesSplits(additionalSplits); + QValueList<MyMoneySplit>::const_iterator it; + MyMoneyMoney factor(moneyBorrowed() ? 1 : -1, 1); + + for(it = additionalSplits.begin(); it != additionalSplits.end(); ++it) { + s = (*it); + s.clearId(); + s.setShares(s.shares() * factor); + s.setValue(s.value() * factor); + t.addSplit(s); + } + + // setup the next due date + t.setPostDate(m_loanSchedulePage->firstPaymentDueDate()); + m_schedule.setTransaction(t); + } + } + return m_schedule; +} + +MyMoneyMoney NewAccountWizard::Wizard::openingBalance(void) const +{ + // equity accounts don't have an opening balance + if(m_accountTypePage->accountType() == MyMoneyAccount::Equity) + return MyMoneyMoney(); + + if(m_accountTypePage->accountType() == MyMoneyAccount::Loan) { + if(m_generalLoanInfoPage->recordAllPayments()) + return MyMoneyMoney(0, 1); + if(moneyBorrowed()) + return -(m_generalLoanInfoPage->m_openingBalance->value()); + return m_generalLoanInfoPage->m_openingBalance->value(); + } + return m_accountTypePage->m_openingBalance->value(); +} + +MyMoneyPrice NewAccountWizard::Wizard::conversionRate(void) const +{ + if(MyMoneyFile::instance()->baseCurrency().id() == m_accountTypePage->m_currencyComboBox->security().id()) + return MyMoneyPrice(MyMoneyFile::instance()->baseCurrency().id(), + m_accountTypePage->m_currencyComboBox->security().id(), + m_accountTypePage->m_openingDate->date(), + MyMoneyMoney(1,1), + i18n("User")); + return MyMoneyPrice(MyMoneyFile::instance()->baseCurrency().id(), + m_accountTypePage->m_currencyComboBox->security().id(), + m_accountTypePage->m_openingDate->date(), + m_accountTypePage->m_conversionRate->value(), + i18n("User")); +} + +bool NewAccountWizard::Wizard::moneyBorrowed(void) const +{ + return m_generalLoanInfoPage->m_loanDirection->currentItem() == 0; +} + +class NewAccountWizard::InstitutionPage::Private +{ +public: + QValueList<MyMoneyInstitution> m_list; +}; + +InstitutionPage::InstitutionPage(Wizard* wizard, const char* name) : + KInstitutionPageDecl(wizard), + WizardPage<Wizard>(StepInstitution, this, wizard, name), + d(new Private()) +{ + connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); + connect(m_newInstitutionButton, SIGNAL(clicked()), this, SLOT(slotNewInstitution())); + connect(m_institutionComboBox, SIGNAL(activated(int)), this, SLOT(slotSelectInstitution(int))); + + slotLoadWidgets(); + m_institutionComboBox->setCurrentItem(0); + slotSelectInstitution(0); +} + +InstitutionPage::~InstitutionPage() +{ + delete d; +} + +void InstitutionPage::slotLoadWidgets(void) +{ + m_institutionComboBox->clear(); + + d->m_list.clear(); + MyMoneyFile::instance()->institutionList(d->m_list); + qHeapSort(d->m_list); + + QValueList<MyMoneyInstitution>::const_iterator it_l; + m_institutionComboBox->insertItem(""); + for(it_l = d->m_list.begin(); it_l != d->m_list.end(); ++it_l) { + m_institutionComboBox->insertItem((*it_l).name()); + } +} + +void InstitutionPage::slotNewInstitution(void) +{ + MyMoneyInstitution institution; + + emit m_wizard->createInstitution(institution); + + if(!institution.id().isEmpty()) { + QValueList<MyMoneyInstitution>::const_iterator it_l; + int i = 0; + for(it_l = d->m_list.begin(); it_l != d->m_list.end(); ++it_l) { + if((*it_l).id() == institution.id()) { + // select the item and remember that the very first one is the empty item + m_institutionComboBox->setCurrentItem(i+1); + slotSelectInstitution(i+1); + m_accountNumber->setFocus(); + break; + } + ++i; + } + } +} + +void InstitutionPage::slotSelectInstitution(int id) +{ + m_accountNumber->setEnabled(id != 0); + m_iban->setEnabled(id != 0); +} + +const MyMoneyInstitution& InstitutionPage::institution(void) const +{ + static MyMoneyInstitution emptyInstitution; + if(m_institutionComboBox->currentItem() == 0) + return emptyInstitution; + + return d->m_list[m_institutionComboBox->currentItem()-1]; +} + +KMyMoneyWizardPage* InstitutionPage::nextPage(void) const +{ + return m_wizard->m_accountTypePage; +} + +AccountTypePage::AccountTypePage(Wizard* wizard, const char* name) : + KAccountTypePageDecl(wizard), + WizardPage<Wizard>(StepAccount, this, wizard, name), + m_showPriceWarning(true) +{ + m_typeSelection->insertItem(i18n("Checking"), MyMoneyAccount::Checkings); + m_typeSelection->insertItem(i18n("Savings"), MyMoneyAccount::Savings); + m_typeSelection->insertItem(i18n("Credit Card"), MyMoneyAccount::CreditCard); + m_typeSelection->insertItem(i18n("Cash"), MyMoneyAccount::Cash); + m_typeSelection->insertItem(i18n("Loan"), MyMoneyAccount::Loan); + m_typeSelection->insertItem(i18n("Investment"), MyMoneyAccount::Investment); + m_typeSelection->insertItem(i18n("Asset"), MyMoneyAccount::Asset); + m_typeSelection->insertItem(i18n("Liability"), MyMoneyAccount::Liability); + if(KMyMoneyGlobalSettings::expertMode()) { + m_typeSelection->insertItem(i18n("Equity"), MyMoneyAccount::Equity); + } + + m_typeSelection->setCurrentItem(MyMoneyAccount::Checkings); + + m_currencyComboBox->setSecurity(MyMoneyFile::instance()->baseCurrency()); + + m_mandatoryGroup->add(m_accountName); + m_mandatoryGroup->add(m_conversionRate->lineedit()); + + m_conversionRate->setPrecision(KMyMoneyGlobalSettings::pricePrecision()); + m_conversionRate->setValue(MyMoneyMoney(1,1)); + slotUpdateCurrency(); + + connect(m_typeSelection, SIGNAL(itemSelected(int)), this, SLOT(slotUpdateType(int))); + connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); + connect(m_currencyComboBox, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrency())); + connect(m_conversionRate, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateConversionRate(const QString&))); + connect(m_conversionRate, SIGNAL(valueChanged(const QString&)), this, SLOT(slotPriceWarning())); + connect(m_onlineQuote, SIGNAL(clicked()), this, SLOT(slotGetOnlineQuote())); +} + +void AccountTypePage::slotUpdateType(int i) +{ + hideShowPages(static_cast<MyMoneyAccount::accountTypeE> (i)); + m_openingBalance->setDisabled(static_cast<MyMoneyAccount::accountTypeE> (i) == MyMoneyAccount::Equity); +} + +void AccountTypePage::hideShowPages(MyMoneyAccount::accountTypeE accountType) const +{ + bool hideSchedulePage = (accountType != MyMoneyAccount::CreditCard) + && (accountType != MyMoneyAccount::Loan); + bool hideLoanPage = (accountType != MyMoneyAccount::Loan); + m_wizard->setStepHidden(StepDetails, hideLoanPage); + m_wizard->setStepHidden(StepPayments, hideLoanPage); + m_wizard->setStepHidden(StepFees, hideLoanPage); + m_wizard->setStepHidden(StepSchedule, hideSchedulePage); + m_wizard->setStepHidden(StepPayout, (accountType != MyMoneyAccount::Loan)); + m_wizard->setStepHidden(StepBroker, accountType != MyMoneyAccount::Investment); + m_wizard->setStepHidden(StepParentAccount, accountType == MyMoneyAccount::Loan); + // Force an update of the steps in case the list has changed + m_wizard->reselectStep(); +}; + +KMyMoneyWizardPage* AccountTypePage::nextPage(void) const +{ + if(accountType() == MyMoneyAccount::Loan) + return m_wizard->m_generalLoanInfoPage; + if(accountType() == MyMoneyAccount::CreditCard) + return m_wizard->m_schedulePage; + if(accountType() == MyMoneyAccount::Investment) + return m_wizard->m_brokeragepage; + return m_wizard->m_hierarchyPage; +} + +void AccountTypePage::slotUpdateCurrency(void) +{ + MyMoneyAccount acc; + acc.setAccountType(accountType()); + + m_openingBalance->setPrecision(MyMoneyMoney::denomToPrec(acc.fraction(currency()))); + + bool show = m_currencyComboBox->security().id() != MyMoneyFile::instance()->baseCurrency().id(); + m_conversionLabel->setShown(show); + m_conversionRate->setShown(show); + m_conversionExample->setShown(show); + m_onlineQuote->setShown(show); + m_conversionRate->setEnabled(show); // make sure to include/exclude in mandatoryGroup + m_mandatoryGroup->changed(); + slotUpdateConversionRate(m_conversionRate->lineedit()->text()); +} + +void AccountTypePage::slotGetOnlineQuote(void) +{ + QString id = MyMoneyFile::instance()->baseCurrency().id()+" "+m_currencyComboBox->security().id(); + KEquityPriceUpdateDlg dlg(this, id); + if(dlg.exec() == QDialog::Accepted) { + MyMoneyPrice price = dlg.price(id); + if(price.isValid()) { + m_conversionRate->setValue(price.rate(m_currencyComboBox->security().id())); + if(price.date() != m_openingDate->date()) { + priceWarning(true); + } + } + } +} + +void AccountTypePage::slotPriceWarning(void) +{ + priceWarning(false); +} + +void AccountTypePage::priceWarning(bool always) +{ + if(m_showPriceWarning || always) { + KMessageBox::information(this, i18n("Please make sure to enter the correct conversion for the selected opening date. If you requested an online quote it might be provided for a different date."), i18n("Check date")); + } + m_showPriceWarning = false; +} + +void AccountTypePage::slotUpdateConversionRate(const QString& txt) +{ + m_conversionExample->setText(i18n("1 %1 equals %2"). + arg(MyMoneyFile::instance()->baseCurrency().tradingSymbol()). + arg(MyMoneyMoney(txt).formatMoney(m_currencyComboBox->security().tradingSymbol(), KMyMoneyGlobalSettings::pricePrecision()))); +} + +void AccountTypePage::slotLoadWidgets(void) +{ + m_currencyComboBox->update(QString("x")); +} + +bool AccountTypePage::isComplete(void) const +{ + // check that the conversion rate is positive if enabled + bool rc = !m_conversionRate->isVisible() || (!m_conversionRate->value().isZero() && !m_conversionRate->value().isNegative()); + if(!rc) { + QToolTip::add(m_wizard->m_nextButton, i18n("Conversion rate is not positive")); + + } else { + rc = KMyMoneyWizardPage::isComplete(); + + if(!rc) { + QToolTip::add(m_wizard->m_nextButton, i18n("No account name supplied")); + } + } + hideShowPages(accountType()); + return rc; +} + +MyMoneyAccount::accountTypeE AccountTypePage::accountType(void) const +{ + return static_cast<MyMoneyAccount::accountTypeE>(m_typeSelection->currentItem()); +} + +const MyMoneySecurity& AccountTypePage::currency(void) const +{ + return m_currencyComboBox->security(); +} + +void AccountTypePage::setAccount(const MyMoneyAccount& acc) +{ + m_typeSelection->setCurrentItem(acc.accountType()); + m_openingDate->setDate(acc.openingDate()); + m_accountName->setText(acc.name()); +} + +const MyMoneyAccount& AccountTypePage::parentAccount(void) +{ + switch(accountType()) { + case MyMoneyAccount::CreditCard: + case MyMoneyAccount::Liability: + case MyMoneyAccount::Loan: // Can be either but we return liability here + return MyMoneyFile::instance()->liability(); + break; + case MyMoneyAccount::Equity: + return MyMoneyFile::instance()->equity(); + default: + break; + } + return MyMoneyFile::instance()->asset(); +} + +bool AccountTypePage::allowsParentAccount(void) const +{ + return accountType() != MyMoneyAccount::Loan; +} + +BrokeragePage::BrokeragePage(Wizard* wizard, const char* name) : + KBrokeragePageDecl(wizard), + WizardPage<Wizard>(StepBroker, this, wizard, name) +{ + connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); +} + +void BrokeragePage::slotLoadWidgets(void) +{ + m_brokerageCurrency->update(QString("x")); +} + +void BrokeragePage::enterPage(void) +{ + // assign the currency of the investment account to the + // brokerage account if nothing else has ever been selected + if(m_brokerageCurrency->security().id().isEmpty()) { + m_brokerageCurrency->setSecurity(m_wizard->m_accountTypePage->m_currencyComboBox->security()); + } + + // check if the institution relevant fields should be enabled or not + bool enabled = m_wizard->m_institutionPage->m_accountNumber->isEnabled(); + m_accountNumberLabel->setEnabled(enabled); + m_accountNumber->setEnabled(enabled); + m_ibanLabel->setEnabled(enabled); + m_iban->setEnabled(enabled); +} + +KMyMoneyWizardPage* BrokeragePage::nextPage(void) const +{ + return m_wizard->m_hierarchyPage; +} + +CreditCardSchedulePage::CreditCardSchedulePage(Wizard* wizard, const char* name) : + KSchedulePageDecl(wizard), + WizardPage<Wizard>(StepSchedule, this, wizard, name) +{ + m_mandatoryGroup->add(m_name); + m_mandatoryGroup->add(m_payee); + m_mandatoryGroup->add(m_amount->lineedit()); + m_mandatoryGroup->add(m_paymentAccount); + connect(m_paymentAccount, SIGNAL(itemSelected(const QString&)), object(), SIGNAL(completeStateChanged())); + connect(m_payee, SIGNAL(itemSelected(const QString&)), object(), SIGNAL(completeStateChanged())); + connect(m_date, SIGNAL(dateChanged(const QDate&)), object(), SIGNAL(completeStateChanged())); + + connect(m_payee, SIGNAL(createItem(const QString&, QString&)), wizard, SIGNAL(createPayee(const QString&, QString&))); + + m_reminderCheckBox->setChecked(true); + connect(m_reminderCheckBox, SIGNAL(toggled(bool)), object(), SIGNAL(completeStateChanged())); + + connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); + + m_method->insertItem(i18n("Write check"), MyMoneySchedule::STYPE_WRITECHEQUE); +#if 0 + m_method->insertItem(i18n("Direct debit"), MyMoneySchedule::STYPE_DIRECTDEBIT); + m_method->insertItem(i18n("Bank transfer"), MyMoneySchedule::STYPE_BANKTRANSFER); +#endif + m_method->insertItem(i18n("Standing order"), MyMoneySchedule::STYPE_STANDINGORDER); + m_method->insertItem(i18n("Manual deposit"), MyMoneySchedule::STYPE_MANUALDEPOSIT); + m_method->insertItem(i18n("Direct deposit"), MyMoneySchedule::STYPE_DIRECTDEPOSIT); + m_method->insertItem(i18n("Other"), MyMoneySchedule::STYPE_OTHER); + m_method->setCurrentItem(MyMoneySchedule::STYPE_DIRECTDEBIT); + + slotLoadWidgets(); +} + +void CreditCardSchedulePage::enterPage(void) +{ + if(m_name->text().isEmpty()) + m_name->setText(i18n("CreditCard %1 monthly payment").arg(m_wizard->m_accountTypePage->m_accountName->text())); +} + +bool CreditCardSchedulePage::isComplete(void) const +{ + bool rc = true; + QString msg = i18n("Finish entry and create account"); + if(m_reminderCheckBox->isChecked()) { + msg = i18n("Finish entry and create account and schedule"); + if(m_date->date() < m_wizard->m_accountTypePage->m_openingDate->date()) { + rc = false; + msg = i18n("Next due date is prior to opening date"); + } + if(m_paymentAccount->selectedItem().isEmpty()) { + rc = false; + msg = i18n("No account selected"); + } + if(m_amount->lineedit()->text().isEmpty()) { + rc = false; + msg = i18n("No amount for payment selected"); + } + if(m_payee->selectedItem().isEmpty()) { + rc = false; + msg = i18n("No payee for payment selected"); + } + if(m_name->text().isEmpty()) { + rc = false; + msg = i18n("No name assigned for schedule"); + } + } + QToolTip::add(m_wizard->m_finishButton, msg); + + return rc; +} + +void CreditCardSchedulePage::slotLoadWidgets(void) +{ + AccountSet set; + set.addAccountGroup(MyMoneyAccount::Asset); + set.load(m_paymentAccount->selector()); + + m_payee->loadPayees(MyMoneyFile::instance()->payeeList()); +} + +KMyMoneyWizardPage* CreditCardSchedulePage::nextPage(void) const +{ + return m_wizard->m_hierarchyPage; +} + +GeneralLoanInfoPage::GeneralLoanInfoPage(Wizard* wizard, const char* name) : + KGeneralLoanInfoPageDecl(wizard), + WizardPage<Wizard>(StepDetails, this, wizard, name), + m_firstTime(true) +{ + m_mandatoryGroup->add(m_payee); + + // remove the unsupported payment and compounding frequencies and setup default + m_paymentFrequency->removeItem(MyMoneySchedule::OCCUR_ONCE); + m_paymentFrequency->removeItem(MyMoneySchedule::OCCUR_EVERYOTHERYEAR); + m_paymentFrequency->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY); + m_compoundFrequency->removeItem(MyMoneySchedule::OCCUR_ONCE); + m_compoundFrequency->removeItem(MyMoneySchedule::OCCUR_EVERYOTHERYEAR); + m_compoundFrequency->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY); + + slotLoadWidgets(); + + connect(m_payee, SIGNAL(createItem(const QString&, QString&)), wizard, SIGNAL(createPayee(const QString&, QString&))); + connect(m_anyPayments, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged())); + connect(m_recordings, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged())); + + connect(m_interestType, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged())); + connect(m_interestChangeDateEdit, SIGNAL(dateChanged(const QDate&)), object(), SIGNAL(completeStateChanged())); + connect(m_openingBalance, SIGNAL(textChanged(const QString&)), object(), SIGNAL(completeStateChanged())); + + connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); +} + +KMyMoneyWizardPage* GeneralLoanInfoPage::nextPage(void) const +{ + return m_wizard->m_loanDetailsPage; +} + +bool GeneralLoanInfoPage::recordAllPayments(void) const +{ + bool rc = true; // all payments + if(m_recordings->isEnabled()) { + if(m_recordings->currentItem() != 0) + rc = false; + } + return rc; +} + +void GeneralLoanInfoPage::enterPage(void) +{ + if(m_firstTime) { + // setup default dates to last of this month and one year on top + QDate firstDay(QDate::currentDate().year(), QDate::currentDate().month(), 1); + m_firstPaymentDate->setDate(firstDay.addMonths(1).addDays(-1)); + m_interestChangeDateEdit->setDate(m_firstPaymentDate->date().addYears(1));; + m_firstTime = false; + } +} + +bool GeneralLoanInfoPage::isComplete(void) const +{ + m_wizard->setStepHidden(StepPayout, !m_wizard->openingBalance().isZero()); + bool rc = KMyMoneyWizardPage::isComplete(); + if(!rc) { + QToolTip::add(m_wizard->m_nextButton, i18n("No payee supplied")); + } + + // fixup availability of items on this page + m_recordings->setDisabled(m_anyPayments->currentItem() == 0); + + m_interestFrequencyAmountEdit->setDisabled(m_interestType->currentItem() == 0); + m_interestFrequencyUnitEdit->setDisabled(m_interestType->currentItem() == 0); + m_interestChangeDateEdit->setDisabled(m_interestType->currentItem() == 0); + + m_openingBalance->setDisabled(recordAllPayments()); + + if(m_openingBalance->isEnabled() && m_openingBalance->lineedit()->text().length() == 0) { + rc = false; + QToolTip::add(m_wizard->m_nextButton, i18n("No opening balance supplied")); + } + + if(rc + && (m_interestType->currentItem() != 0) + && (m_interestChangeDateEdit->date() <= m_firstPaymentDate->date())) { + rc = false; + QToolTip::add(m_wizard->m_nextButton, i18n("An interest change can only happen after the first payment")); + } + return rc; +} + +const MyMoneyAccount& GeneralLoanInfoPage::parentAccount(void) +{ + return ( m_loanDirection->currentItem() == 0 ) + ? MyMoneyFile::instance()->liability() + : MyMoneyFile::instance()->asset(); +} + +void GeneralLoanInfoPage::slotLoadWidgets(void) +{ + m_payee->loadPayees(MyMoneyFile::instance()->payeeList()); +} + +LoanDetailsPage::LoanDetailsPage(Wizard* wizard, const char* name) : + KLoanDetailsPageDecl(wizard), + WizardPage<Wizard>(StepPayments, this, wizard, name), + m_needCalculate(true) +{ + // force the balloon payment to zero (default) + m_balloonAmount->setValue(MyMoneyMoney()); + // allow any precision for the interest rate + m_interestRate->setPrecision(-1); + + connect(m_paymentDue, SIGNAL(activated(int)), this, SLOT(slotValuesChanged())); + + connect(m_termAmount, SIGNAL(valueChanged(int)), this, SLOT(slotValuesChanged())); + connect(m_termUnit, SIGNAL(highlighted(int)), this, SLOT(slotValuesChanged())); + connect(m_loanAmount, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged())); + connect(m_interestRate, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged())); + connect(m_paymentAmount, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged())); + connect(m_balloonAmount, SIGNAL(textChanged(const QString&)), this, SLOT(slotValuesChanged())); + + connect(m_calculateButton, SIGNAL(clicked()), this, SLOT(slotCalculate())); +} + +void LoanDetailsPage::enterPage(void) +{ + // we need to remove a bunch of entries of the payment frequencies + m_termUnit->clear(); + + m_mandatoryGroup->clear(); + if(!m_wizard->openingBalance().isZero()) { + m_mandatoryGroup->add(m_loanAmount->lineedit()); + if(m_loanAmount->lineedit()->text().length() == 0) { + m_loanAmount->setValue(m_wizard->openingBalance().abs()); + } + } + + switch(m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentItem()) { + default: + m_termUnit->insertItem(i18n("Payments"), MyMoneySchedule::OCCUR_ONCE); + m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_ONCE); + break; + case MyMoneySchedule::OCCUR_MONTHLY: + m_termUnit->insertItem(i18n("Months"), MyMoneySchedule::OCCUR_MONTHLY); + m_termUnit->insertItem(i18n("Years"), MyMoneySchedule::OCCUR_YEARLY); + m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY); + break; + case MyMoneySchedule::OCCUR_YEARLY: + m_termUnit->insertItem(i18n("Years"), MyMoneySchedule::OCCUR_YEARLY); + m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_YEARLY); + break; + } +} + +void LoanDetailsPage::slotValuesChanged(void) +{ + m_needCalculate = true; + m_wizard->completeStateChanged(); +} + +void LoanDetailsPage::slotCalculate(void) +{ + MyMoneyFinancialCalculator calc; + long double val; + int PF, CF; + QString result; + bool moneyBorrowed = m_wizard->moneyBorrowed(); + bool moneyLend = !moneyBorrowed; + + // FIXME: for now, we only support interest calculation at the end of the period + calc.setBep(); + // FIXME: for now, we only support periodic compounding + calc.setDisc(); + + PF = m_wizard->m_generalLoanInfoPage->m_paymentFrequency->eventsPerYear(); + CF = m_wizard->m_generalLoanInfoPage->m_compoundFrequency->eventsPerYear(); + + if(PF == 0 || CF == 0) + return; + + calc.setPF(PF); + calc.setCF(CF); + + + if(!m_loanAmount->lineedit()->text().isEmpty()) { + val = static_cast<long double> (m_loanAmount->value().abs().toDouble()); + if(moneyBorrowed) + val = -val; + calc.setPv(val); + } + + if(!m_interestRate->lineedit()->text().isEmpty()) { + val = static_cast<long double> (m_interestRate->value().abs().toDouble()); + calc.setIr(val); + } + + if(!m_paymentAmount->lineedit()->text().isEmpty()) { + val = static_cast<long double> (m_paymentAmount->value().abs().toDouble()); + if(moneyLend) + val = -val; + calc.setPmt(val); + } + + if(!m_balloonAmount->lineedit()->text().isEmpty()) { + val = static_cast<long double> (m_balloonAmount->value().abs().toDouble()); + if(moneyLend) + val = -val; + calc.setFv(val); + } + + if(m_termAmount->value() != 0) { + calc.setNpp(static_cast<long double>(term())); + } + + // setup of parameters is done, now do the calculation + try { + if(m_loanAmount->lineedit()->text().isEmpty()) { + // calculate the amount of the loan out of the other information + val = calc.presentValue(); + m_loanAmount->loadText(MyMoneyMoney(static_cast<double>(val)).abs().formatMoney("", m_wizard->precision())); + result = i18n("KMyMoney has calculated the amount of the loan as %1.") + .arg(m_loanAmount->lineedit()->text()); + + } else if(m_interestRate->lineedit()->text().isEmpty()) { + // calculate the interest rate out of the other information + val = calc.interestRate(); + m_interestRate->loadText(MyMoneyMoney(static_cast<double>(val)).abs().formatMoney("", 3)); + result = i18n("KMyMoney has calculated the interest rate to %1%.") + .arg(m_interestRate->lineedit()->text()); + + } else if(m_paymentAmount->lineedit()->text().isEmpty()) { + // calculate the periodical amount of the payment out of the other information + val = calc.payment(); + m_paymentAmount->setValue(MyMoneyMoney(static_cast<double>(val)).abs()); + // reset payment as it might have changed due to rounding + val = static_cast<long double> (m_paymentAmount->value().abs().toDouble()); + if(moneyLend) + val = -val; + calc.setPmt(val); + + result = i18n("KMyMoney has calculated a periodic payment of %1 to cover principal and interest.") + .arg(m_paymentAmount->lineedit()->text()); + + val = calc.futureValue(); + if((moneyBorrowed && val < 0 && fabsl(val) >= fabsl(calc.payment())) + || (moneyLend && val > 0 && fabs(val) >= fabs(calc.payment()))) { + calc.setNpp(calc.npp()-1); + // updateTermWidgets(calc.npp()); + val = calc.futureValue(); + MyMoneyMoney refVal(static_cast<double>(val)); + m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + result += QString(" "); + result += i18n("The number of payments has been decremented and the balloon payment has been modified to %1.") + .arg(m_balloonAmount->lineedit()->text()); + } else if((moneyBorrowed && val < 0 && fabsl(val) < fabsl(calc.payment())) + || (moneyLend && val > 0 && fabs(val) < fabs(calc.payment()))) { + m_balloonAmount->loadText(MyMoneyMoney(0,1).formatMoney("", m_wizard->precision())); + } else { + MyMoneyMoney refVal(static_cast<double>(val)); + m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + result += i18n("The balloon payment has been modified to %1.") + .arg(m_balloonAmount->lineedit()->text()); + } + + } else if(m_termAmount->value() == 0) { + // calculate the number of payments out of the other information + val = calc.numPayments(); + if(val == 0) + throw new MYMONEYEXCEPTION("incorrect fincancial calculation"); + + // if the number of payments has a fractional part, then we + // round it to the smallest integer and calculate the balloon payment + result = i18n("KMyMoney has calculated the term of your loan as %1. ") + .arg(updateTermWidgets(floorl(val))); + + if(val != floorl(val)) { + calc.setNpp(floorl(val)); + val = calc.futureValue(); + MyMoneyMoney refVal(static_cast<double>(val)); + m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + result += i18n("The balloon payment has been modified to %1.") + .arg(m_balloonAmount->lineedit()->text()); + } + + } else { + // calculate the future value of the loan out of the other information + val = calc.futureValue(); + + // we differentiate between the following cases: + // a) the future value is greater than a payment + // b) the future value is less than a payment or the loan is overpaid + // c) all other cases + // + // a) means, we have paid more than we owed. This can't be + // b) means, we paid more than we owed but the last payment is + // less in value than regular payments. That means, that the + // future value is to be treated as (fully payed back) + // c) the loan is not payed back yet + if((moneyBorrowed && val < 0 && fabsl(val) > fabsl(calc.payment())) + || (moneyLend && val > 0 && fabs(val) > fabs(calc.payment()))) { + // case a) + qDebug("Future Value is %Lf", val); + throw new MYMONEYEXCEPTION("incorrect fincancial calculation"); + + } else if((moneyBorrowed && val < 0 && fabsl(val) <= fabsl(calc.payment())) + || (moneyLend && val > 0 && fabs(val) <= fabs(calc.payment()))) { + // case b) + val = 0; + } + + MyMoneyMoney refVal(static_cast<double>(val)); + result = i18n("KMyMoney has calculated a balloon payment of %1 for this loan.") + .arg(refVal.abs().formatMoney("", m_wizard->precision())); + + if(!m_balloonAmount->lineedit()->text().isEmpty()) { + if((m_balloonAmount->value().abs() - refVal.abs()).abs().toDouble() > 1) { + throw new MYMONEYEXCEPTION("incorrect fincancial calculation"); + } + result = i18n("KMyMoney has successfully verified your loan information."); + } + m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + } + + } catch (MyMoneyException *e) { + delete e; + KMessageBox::error(0, + i18n("You have entered mis-matching information. Please modify " + "your figures or leave one value empty " + "to let KMyMoney calculate it for you"), + i18n("Calculation error")); + return; + } + + result += i18n("\n\nAccept this or modify the loan information and recalculate."); + + KMessageBox::information(0, result, i18n("Calculation successful")); + m_needCalculate = false; + + // now update change + m_wizard->completeStateChanged(); +} + +int LoanDetailsPage::term(void) const +{ + int factor = 0; + + if(m_termAmount->value() != 0) { + factor = 1; + switch(m_termUnit->currentItem()) { + case MyMoneySchedule::OCCUR_YEARLY: // years + factor = 12; + // tricky fall through here + + case MyMoneySchedule::OCCUR_MONTHLY: // months + factor *= 30; + factor *= m_termAmount->value(); + // factor now is the duration in days. we divide this by the + // payment frequency and get the number of payments + factor /= m_wizard->m_generalLoanInfoPage->m_paymentFrequency->daysBetweenEvents(); + break; + + default: + qDebug("Unknown term unit %d in LoanDetailsPage::term(). Using payments.", m_termUnit->currentItem()); + // tricky fall through here + + case MyMoneySchedule::OCCUR_ONCE: // payments + factor = m_termAmount->value(); + break; + } + } + return factor; +} + +QString LoanDetailsPage::updateTermWidgets(const long double val) +{ + long long vl = static_cast<long long>(floorl(val)); + + QString valString; + MyMoneySchedule::occurenceE unit = m_termUnit->currentItem(); + + if((unit == MyMoneySchedule::OCCUR_MONTHLY) + && ((vl % 12) == 0)) { + vl /= 12; + unit = MyMoneySchedule::OCCUR_YEARLY; + } + + switch(unit) { + case MyMoneySchedule::OCCUR_MONTHLY: + valString = i18n("one month", "%n months", vl); + m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_MONTHLY); + break; + case MyMoneySchedule::OCCUR_YEARLY: + valString = i18n("one year", "%n years", vl); + m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_YEARLY); + break; + default: + valString = i18n("one payment", "%n payments", vl); + m_termUnit->setCurrentItem(MyMoneySchedule::OCCUR_ONCE); + break; + } + m_termAmount->setValue(vl); + return valString; +} + +bool LoanDetailsPage::isComplete(void) const +{ + // bool rc = KMyMoneyWizardPage::isComplete(); + + int fieldCnt = 0; + QWidget* calculatedField = 0; + + if(m_loanAmount->lineedit()->text().length() > 0) { + fieldCnt++; + } else { + calculatedField = m_loanAmount; + } + + if(m_interestRate->lineedit()->text().length() > 0) { + fieldCnt++; + } else { + calculatedField = m_interestRate; + } + + if(m_termAmount->value() != 0) { + fieldCnt++; + } else { + calculatedField = m_termAmount; + } + + if(m_paymentAmount->lineedit()->text().length() > 0) { + fieldCnt++; + } else { + calculatedField = m_paymentAmount; + } + + if(m_balloonAmount->lineedit()->text().length() > 0) { + fieldCnt++; + } else { + calculatedField = m_balloonAmount; + } + + if(fieldCnt == 5) + calculatedField = 0; + + m_calculateButton->setEnabled(fieldCnt == 4 || (fieldCnt == 5 && m_needCalculate)); + + m_calculateButton->setAutoDefault(false); + m_calculateButton->setDefault(false); + if(m_needCalculate && fieldCnt == 4) { + QToolTip::add(m_wizard->m_nextButton, i18n("Press Calculate to verify the values")); + m_calculateButton->setAutoDefault(true); + m_calculateButton->setDefault(true); + } else if(fieldCnt != 5) { + QToolTip::add(m_wizard->m_nextButton, i18n("Not all details supplied")); + m_calculateButton->setAutoDefault(true); + m_calculateButton->setDefault(true); + } + m_wizard->m_nextButton->setAutoDefault(!m_calculateButton->autoDefault()); + m_wizard->m_nextButton->setDefault(!m_calculateButton->autoDefault()); + + return (fieldCnt == 5) && !m_needCalculate; +} + +KMyMoneyWizardPage* LoanDetailsPage::nextPage(void) const +{ + return m_wizard->m_loanPaymentPage; +} + + +class NewAccountWizard::LoanPaymentPage::Private +{ +public: + MyMoneyAccount phonyAccount; + MyMoneySplit phonySplit; + MyMoneyTransaction additionalFeesTransaction; + MyMoneyMoney additionalFees; +}; + +LoanPaymentPage::LoanPaymentPage(Wizard* wizard, const char* name) : + KLoanPaymentPageDecl(wizard), + WizardPage<Wizard>(StepFees, this, wizard, name), + d(new Private) +{ + d->phonyAccount = MyMoneyAccount(QString("Phony-ID"), MyMoneyAccount()); + + d->phonySplit.setAccountId(d->phonyAccount.id()); + d->phonySplit.setValue(0); + d->phonySplit.setShares(0); + + d->additionalFeesTransaction.addSplit(d->phonySplit); + + connect(m_additionalFeesButton, SIGNAL(clicked()), this, SLOT(slotAdditionalFees())); +} + +LoanPaymentPage::~LoanPaymentPage() +{ + delete d; +} + +MyMoneyMoney LoanPaymentPage::basePayment(void) const +{ + return m_wizard->m_loanDetailsPage->m_paymentAmount->value(); +} + +MyMoneyMoney LoanPaymentPage::additionalFees(void) const +{ + return d->additionalFees; +} + +void LoanPaymentPage::additionalFeesSplits(QValueList<MyMoneySplit>& list) +{ + list.clear(); + + QValueList<MyMoneySplit>::ConstIterator it; + for(it = d->additionalFeesTransaction.splits().begin(); it != d->additionalFeesTransaction.splits().end(); ++it) { + if((*it).accountId() != d->phonyAccount.id()) { + list << (*it); + } + } +} + +void LoanPaymentPage::updateAmounts(void) +{ + m_additionalFees->setText(d->additionalFees.formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision())); + m_totalPayment->setText((basePayment() + d->additionalFees).formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision())); +} + +void LoanPaymentPage::enterPage(void) +{ + const MyMoneySecurity& currency = m_wizard->currency(); + + m_basePayment->setText(basePayment().formatMoney(currency.tradingSymbol(), m_wizard->precision())); + d->phonyAccount.setCurrencyId(currency.id()); + d->additionalFeesTransaction.setCommodity(currency.id()); + + updateAmounts(); +} + +void LoanPaymentPage::slotAdditionalFees(void) +{ + QMap<QString, MyMoneyMoney> priceInfo; + KSplitTransactionDlg* dlg = new KSplitTransactionDlg(d->additionalFeesTransaction, d->phonySplit, d->phonyAccount, false, !m_wizard->moneyBorrowed(), MyMoneyMoney(0), priceInfo); + + // connect(dlg, SIGNAL(newCategory(MyMoneyAccount&)), this, SIGNAL(newCategory(MyMoneyAccount&))); + + if(dlg->exec() == QDialog::Accepted) { + d->additionalFeesTransaction = dlg->transaction(); + // sum up the additional fees + QValueList<MyMoneySplit>::ConstIterator it; + + d->additionalFees = MyMoneyMoney(0); + for(it = d->additionalFeesTransaction.splits().begin(); it != d->additionalFeesTransaction.splits().end(); ++it) { + if((*it).accountId() != d->phonyAccount.id()) { + d->additionalFees += (*it).shares(); + } + } + updateAmounts(); + } + + delete dlg; +} + +KMyMoneyWizardPage* LoanPaymentPage::nextPage(void) const +{ + return m_wizard->m_loanSchedulePage; +} + + +LoanSchedulePage::LoanSchedulePage(Wizard* wizard, const char* name) : + KLoanSchedulePageDecl(wizard), + WizardPage<Wizard>(StepSchedule, this, wizard, name) +{ + m_mandatoryGroup->add(m_interestCategory->lineEdit()); + m_mandatoryGroup->add(m_paymentAccount->lineEdit()); + connect(m_interestCategory, SIGNAL(createItem(const QString&, QString&)), this, SLOT(slotCreateCategory(const QString&, QString&))); + connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); +} + +void LoanSchedulePage::slotCreateCategory(const QString& name, QString& id) +{ + MyMoneyAccount acc, parent; + acc.setName(name); + + if(m_wizard->moneyBorrowed()) + parent = MyMoneyFile::instance()->expense(); + else + parent = MyMoneyFile::instance()->income(); + + emit m_wizard->createCategory(acc, parent); + + // return id + id = acc.id(); +} + +QDate LoanSchedulePage::firstPaymentDueDate(void) const +{ + if(m_firstPaymentDueDate->isEnabled()) + return m_firstPaymentDueDate->date(); + return m_wizard->m_generalLoanInfoPage->m_firstPaymentDate->date(); +} + +void LoanSchedulePage::enterPage(void) +{ + m_interestCategory->setFocus(); + m_firstPaymentDueDate->setDisabled(m_wizard->m_generalLoanInfoPage->recordAllPayments()); + slotLoadWidgets(); +} + +void LoanSchedulePage::slotLoadWidgets(void) +{ + AccountSet set; + if(m_wizard->moneyBorrowed()) + set.addAccountGroup(MyMoneyAccount::Expense); + else + set.addAccountGroup(MyMoneyAccount::Income); + set.load(m_interestCategory->selector()); + + set.clear(); + set.addAccountGroup(MyMoneyAccount::Asset); + set.load(m_paymentAccount->selector()); +} + +KMyMoneyWizardPage* LoanSchedulePage::nextPage(void) const +{ + // if the balance widget of the general loan info page is enabled and + // the value is not zero, then the payout already happened and we don't + // aks for it. + if(m_wizard->openingBalance().isZero()) + return m_wizard->m_loanPayoutPage; + return m_wizard->m_accountSummaryPage; +} + +LoanPayoutPage::LoanPayoutPage(Wizard* wizard, const char* name) : + KLoanPayoutPageDecl(wizard), + WizardPage<Wizard>(StepPayout, this, wizard, name) +{ + m_mandatoryGroup->add(m_assetAccount->lineEdit()); + m_mandatoryGroup->add(m_loanAccount->lineEdit()); + + KIconLoader* il = KGlobal::iconLoader(); + KGuiItem createAssetButtenItem( i18n( "&Create..." ), + QIconSet(il->loadIcon("filenew", KIcon::Small, KIcon::SizeSmall)), + i18n("Create a new asset account"), + i18n("If the asset account does not yet exist, press this button to create it.")); + m_createAssetButton->setGuiItem(createAssetButtenItem); + QToolTip::add(m_createAssetButton, createAssetButtenItem.toolTip()); + QWhatsThis::add(m_createAssetButton, createAssetButtenItem.whatsThis()); + connect(m_createAssetButton, SIGNAL(clicked()), this, SLOT(slotCreateAssetAccount())); + + connect(m_noPayoutTransaction, SIGNAL(toggled(bool)), this, SLOT(slotButtonsToggled())); + connect(m_refinanceLoan, SIGNAL(toggled(bool)), this, SLOT(slotButtonsToggled())); + + connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); + slotLoadWidgets(); +} + +void LoanPayoutPage::slotButtonsToggled(void) +{ + // we don't go directly, as the order of the emission of signals to slots is + // not defined. Using a single shot timer postpones the call of m_mandatoryGroup::changed() + // until the next round of the main loop so we can be sure to see all relevant changes + // that happened in the meantime (eg. widgets are enabled and disabled) + QTimer::singleShot(0, m_mandatoryGroup, SLOT(changed())); +} + +void LoanPayoutPage::slotCreateAssetAccount(void) +{ + MyMoneyAccount acc; + acc.setAccountType(MyMoneyAccount::Asset); + acc.setOpeningDate(m_wizard->m_accountTypePage->m_openingDate->date()); + + emit m_wizard->createAccount(acc); + + if(!acc.id().isEmpty()) { + m_assetAccount->setSelectedItem(acc.id()); + } +} + +void LoanPayoutPage::slotLoadWidgets(void) +{ + AccountSet set; + set.addAccountGroup(MyMoneyAccount::Asset); + set.load(m_assetAccount->selector()); + + set.clear(); + set.addAccountType(MyMoneyAccount::Loan); + set.load(m_loanAccount->selector()); +} + +void LoanPayoutPage::enterPage(void) +{ + // only allow to create new asset accounts for liability loans + m_createAssetButton->setEnabled(m_wizard->moneyBorrowed()); + m_refinanceLoan->setEnabled(m_wizard->moneyBorrowed()); + if(!m_wizard->moneyBorrowed()) { + m_refinanceLoan->setChecked(false); + } + m_payoutDetailFrame->setDisabled(m_noPayoutTransaction->isChecked()); +} + +KMyMoneyWizardPage* LoanPayoutPage::nextPage(void) const +{ + return m_wizard->m_accountSummaryPage; +} + +bool LoanPayoutPage::isComplete(void) const +{ + return KMyMoneyWizardPage::isComplete() | m_noPayoutTransaction->isChecked(); +} + +const QString& LoanPayoutPage::payoutAccountId(void) const +{ + if(m_refinanceLoan->isChecked()) { + return m_loanAccount->selectedItem(); + } else { + return m_assetAccount->selectedItem(); + } +} + +HierarchyPage::HierarchyPage(Wizard* wizard, const char* name) : + KHierarchyPageDecl(wizard), + WizardPage<Wizard>(StepParentAccount, this, wizard, name) +{ + // the next line causes a warning to be shown in the console output + // since at least one of the major groups is selected, and the user + // cannot deselect an account, at least one is selected all the time + // and we don't need this check + // m_mandatoryGroup->add(m_qlistviewParentAccounts); + m_qlistviewParentAccounts->setEnabled(true); + m_qlistviewParentAccounts->setRootIsDecorated(true); + m_qlistviewParentAccounts->setAllColumnsShowFocus(true); + m_qlistviewParentAccounts->addColumn("Accounts"); + m_qlistviewParentAccounts->setMultiSelection(false); + m_qlistviewParentAccounts->header()->setResizeEnabled(true); + m_qlistviewParentAccounts->setColumnWidthMode(0, QListView::Maximum); + // never show the horizontal scroll bar + // m_qlistviewParentAccounts->setHScrollBarMode(QScrollView::AlwaysOff); +} + +void HierarchyPage::enterPage(void) +{ + // Ensure that the list reflects the Account Type + // - if the type has changed + // - - clear the list + // - - populate the account list (also occurs first time we come here) + MyMoneyAccount topAccount = m_wizard->m_accountTypePage->parentAccount(); + + // If the list was not populated with this top account we populate it now + if ( &m_topAccount == NULL || m_topAccount.id() != topAccount.id()) + { + if ( &m_topAccount != NULL ) + { + // If the list has alrady been populated clear it + if ( (*m_qlistviewParentAccounts).childCount() > 0 ) + (*m_qlistviewParentAccounts).clear(); + } + + // Add the Tree for the Top Account + KMyMoneyAccountTreeItem *topAccountTree = buildAccountTree(m_qlistviewParentAccounts, topAccount, false); + topAccountTree->setOpen(true); + // Record the top account used to populate the list + m_topAccount = topAccount; + } +} + +KMyMoneyAccountTreeItem* HierarchyPage::buildAccountTree + ( KMyMoneyAccountTreeBase* parent + , const MyMoneyAccount& account + , bool open ) const +{ + // Recursively add child accounts to the list + if ( account.accountType() == MyMoneyAccount::Investment) + return NULL; + KMyMoneyAccountTreeItem* childItem = new KMyMoneyAccountTreeItem( parent, account ); + if ( open ) + childItem->setOpen(true); + for ( QStringList::ConstIterator it = account.accountList().begin(); + it != account.accountList().end(); + ++it ) + { + MyMoneyAccount acc = MyMoneyFile::instance()->account(*it); + if(acc.isClosed()) + continue; + if(acc.accountType() == MyMoneyAccount::Investment) + continue; + buildAccountTree( childItem, acc, open ); + } + return childItem; +} + +KMyMoneyAccountTreeItem* HierarchyPage::buildAccountTree + ( KMyMoneyAccountTreeItem* parent + , const MyMoneyAccount& account + , bool open ) const +{ + // Recursively add child accounts to the list + if ( account.accountType() == MyMoneyAccount::Investment) + return NULL; + KMyMoneyAccountTreeItem* childItem = new KMyMoneyAccountTreeItem( parent, account ); + if ( open ) + childItem->setOpen(true); + for ( QStringList::ConstIterator it = account.accountList().begin(); + it != account.accountList().end(); + ++it ) + { + MyMoneyAccount acc = MyMoneyFile::instance()->account(*it); + if(acc.isClosed()) + continue; + if (account.accountType() == MyMoneyAccount::Investment) + continue; + buildAccountTree( childItem, acc, open ); + } + return childItem; +} + +KMyMoneyWizardPage* HierarchyPage::nextPage(void) const +{ + return m_wizard->m_accountSummaryPage; +} + +const MyMoneyAccount& HierarchyPage::parentAccount(void) +{ + // TODO + // Instead of returning the Parent Account we can simply + // return the account associated with the current item + // in the ListView + KMyMoneyAccountTreeItem* item = dynamic_cast<KMyMoneyAccountTreeItem*>(m_qlistviewParentAccounts->currentItem()); + return dynamic_cast<const MyMoneyAccount&>(item->itemObject()); +} + +AccountSummaryPage::AccountSummaryPage(Wizard* wizard, const char* name) : + KAccountSummaryPageDecl(wizard), + WizardPage<Wizard>(StepFinish, this, wizard, name) +{ + m_dataList->setSorting(-1); + m_dataList->setColumnWidthMode(1, QListView::Maximum); + m_dataList->setResizeMode(QListView::LastColumn); +} + +void AccountSummaryPage::enterPage(void) +{ + MyMoneyAccount acc = m_wizard->account(); + MyMoneySecurity sec = m_wizard->currency(); + acc.fraction(sec); + + // assign an id to the account inside the wizard which is required for a schedule + // get the schedule and clear the id again in the wizards object. + MyMoneyAccount tmp(QString("Phony-ID"), acc); + m_wizard->setAccount(tmp); + MyMoneySchedule sch = m_wizard->schedule(); + m_wizard->setAccount(acc); + + m_dataList->clear(); + + // Account data + QListViewItem* group = new KMyMoneyCheckListItem(m_dataList, i18n("Account information"), QString(), QString(), QCheckListItem::RadioButtonController); + group->setOpen(true); + QListViewItem* p; + p = new KListViewItem(group, i18n("Name"), acc.name()); + if(!acc.isLoan()) + p = new KListViewItem(group, p, i18n("Subaccount of"), + m_wizard->parentAccount().name()); + if(acc.accountType() == MyMoneyAccount::AssetLoan) + p = new KListViewItem(group, p, i18n("Type"), i18n("Loan")); + else + p = new KListViewItem(group, p, i18n("Type"), m_wizard->m_accountTypePage->m_typeSelection->currentText()); + p = new KListViewItem(group, p, i18n("Currency"), m_wizard->currency().name()); + p = new KListViewItem(group, p, i18n("Opening date"), KGlobal::locale()->formatDate(acc.openingDate())); + if(m_wizard->currency().id() != MyMoneyFile::instance()->baseCurrency().id()) { + p = new KListViewItem(group, p, i18n("Conversion rate"), m_wizard->conversionRate().rate(QString()).formatMoney("", KMyMoneyGlobalSettings::pricePrecision())); + } + if(!acc.isLoan() || !m_wizard->openingBalance().isZero()) + p = new KListViewItem(group, p, i18n("Opening balance"), m_wizard->openingBalance().formatMoney(acc, sec)); + + if(!m_wizard->m_institutionPage->institution().id().isEmpty()) { + p = new KListViewItem(group, p, i18n("Institution"), m_wizard->m_institutionPage->institution().name()); + if(!acc.number().isEmpty()) { + p = new KListViewItem(group, p, i18n("Number"), acc.number()); + } + if(!acc.value("IBAN").isEmpty()) { + p = new KListViewItem(group, p, i18n("IBAN"), acc.value("IBAN")); + } + } + + if(acc.accountType() == MyMoneyAccount::Investment) { + if(m_wizard->m_brokeragepage->m_createBrokerageButton->isChecked()) { + group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Brokerage Account"), QString(), QString(), QCheckListItem::RadioButtonController); + group->setOpen(true); + p = new KListViewItem(group, p, i18n("Name"), QString("%1 (Brokerage)").arg(acc.name())); + p = new KListViewItem(group, p, i18n("Currency"), m_wizard->m_brokeragepage->m_brokerageCurrency->security().name()); + if(m_wizard->m_brokeragepage->m_accountNumber->isEnabled() && !m_wizard->m_brokeragepage->m_accountNumber->text().isEmpty()) + p = new KListViewItem(group, p, i18n("Number"), m_wizard->m_brokeragepage->m_accountNumber->text()); + if(m_wizard->m_brokeragepage->m_iban->isEnabled() && !m_wizard->m_brokeragepage->m_iban->text().isEmpty()) + p = new KListViewItem(group, p, i18n("IBAN"), m_wizard->m_brokeragepage->m_iban->text()); + } + } + + // Loan + if(acc.isLoan()) { + group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Loan information"), QString(), QString(), QCheckListItem::RadioButtonController); + group->setOpen(true); + if(m_wizard->moneyBorrowed()) { + p = new KListViewItem(group, p, i18n("Amount borrowed"), m_wizard->m_loanDetailsPage->m_loanAmount->value().formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision())); + } else { + p = new KListViewItem(group, p, i18n("Amount lent"), m_wizard->m_loanDetailsPage->m_loanAmount->value().formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision())); + } + p = new KListViewItem(group, p, i18n("Interest rate"), QString("%1 %").arg(m_wizard->m_loanDetailsPage->m_interestRate->value().formatMoney("", -1))); + p = new KListViewItem(group, p, i18n("Interest rate is"), m_wizard->m_generalLoanInfoPage->m_interestType->currentText()); + p = new KListViewItem(group, p, i18n("Principal and interest"), m_wizard->m_loanDetailsPage->m_paymentAmount->value().formatMoney(acc, sec)); + p = new KListViewItem(group, p, i18n("Additional fees"), m_wizard->m_loanPaymentPage->additionalFees().formatMoney(acc, sec)); + p = new KListViewItem(group, p, i18n("Payment frequency"), m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentText()); + p = new KListViewItem(group, p, i18n("Payment account"), m_wizard->m_loanSchedulePage->m_paymentAccount->currentText()); + + if(!m_wizard->m_loanPayoutPage->m_noPayoutTransaction->isChecked() && m_wizard->openingBalance().isZero()) { + group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Payout information"), QString(), QString(), QCheckListItem::RadioButtonController); + group->setOpen(true); + if(m_wizard->m_loanPayoutPage->m_refinanceLoan->isChecked()) { + p = new KListViewItem(group, p, i18n("Refinance"), m_wizard->m_loanPayoutPage->m_loanAccount->currentText()); + } else { + if(m_wizard->moneyBorrowed()) + p = new KListViewItem(group, p, i18n("Transfer amount to"), m_wizard->m_loanPayoutPage->m_assetAccount->currentText()); + else + p = new KListViewItem(group, p, i18n("Transfer amount from"), m_wizard->m_loanPayoutPage->m_assetAccount->currentText()); + } + p = new KListViewItem(group, p, i18n("Payment date"), KGlobal::locale()->formatDate(m_wizard->m_loanPayoutPage->m_payoutDate->date())); + } + } + + // Schedule + if(!(sch == MyMoneySchedule())) { + group = new KMyMoneyCheckListItem(m_dataList, group, i18n("Schedule information"), QString(), QString(), QCheckListItem::RadioButtonController); + group->setOpen(true); + p = new KListViewItem(group, i18n("Name"), sch.name()); + if(acc.accountType() == MyMoneyAccount::CreditCard) { + MyMoneyAccount paymentAccount = MyMoneyFile::instance()->account(m_wizard->m_schedulePage->m_paymentAccount->selectedItem()); + p = new KListViewItem(group, p, i18n("Occurence"), i18n("Monthly")); + p = new KListViewItem(group, p, i18n("Paid from"), paymentAccount.name()); + p = new KListViewItem(group, p, i18n("Pay to"), m_wizard->m_schedulePage->m_payee->currentText()); + p = new KListViewItem(group, p, i18n("Amount"), m_wizard->m_schedulePage->m_amount->value().formatMoney(acc, sec)); + p = new KListViewItem(group, p, i18n("First payment due"), KGlobal::locale()->formatDate(sch.nextDueDate())); + p = new KListViewItem(group, p, i18n("Payment method"), m_wizard->m_schedulePage->m_method->currentText()); + } + if(acc.isLoan()) { + p = new KListViewItem(group, p, i18n("Occurence"), m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentText()); + p = new KListViewItem(group, p, i18n("Amount"), (m_wizard->m_loanPaymentPage->basePayment() + m_wizard->m_loanPaymentPage->additionalFees()).formatMoney(acc, sec)); + p = new KListViewItem(group, p, i18n("First payment due"), KGlobal::locale()->formatDate(m_wizard->m_loanSchedulePage->firstPaymentDueDate())); + } + } +} + +#include "knewaccountwizard.moc" |