diff --git a/kmymoney/wizards/newinvestmentwizard/konlineupdatewizardpage.cpp b/kmymoney/wizards/newinvestmentwizard/konlineupdatewizardpage.cpp index e32f89404..bb3e3c0b1 100644 --- a/kmymoney/wizards/newinvestmentwizard/konlineupdatewizardpage.cpp +++ b/kmymoney/wizards/newinvestmentwizard/konlineupdatewizardpage.cpp @@ -1,129 +1,129 @@ /*************************************************************************** konlineupdatewizardpage - description ------------------- begin : Sun Jun 27 2010 copyright : (C) 2010 by Fernando Vilas email : kmymoney-devel@kde.org (C) 2017 by Łukasz Wojniłowicz ***************************************************************************/ /*************************************************************************** * * * 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 "konlineupdatewizardpage.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes #include "ui_konlineupdatewizardpage.h" #include "mymoneymoney.h" #include "mymoneysecurity.h" #include "webpricequote.h" KOnlineUpdateWizardPage::KOnlineUpdateWizardPage(QWidget *parent) : QWizardPage(parent), ui(new Ui::KOnlineUpdateWizardPage) { ui->setupUi(this); - ui->m_onlineFactor->setValue(MyMoneyMoney::ONE); ui->m_onlineFactor->setPrecision(4); + ui->m_onlineFactor->setValue(MyMoneyMoney::ONE); // make ui->m_onlineSourceCombo sortable QSortFilterProxyModel* proxy = new QSortFilterProxyModel(ui->m_onlineSourceCombo); proxy->setSourceModel(ui->m_onlineSourceCombo->model()); proxy->setSortCaseSensitivity(Qt::CaseInsensitive); ui->m_onlineSourceCombo->model()->setParent(proxy); ui->m_onlineSourceCombo->setModel(proxy); // Connect signals-slots connect(ui->m_useFinanceQuote, &QAbstractButton::toggled, this, &KOnlineUpdateWizardPage::slotSourceChanged); // Register the fields with the QWizard and connect the // appropriate signals to update the "Next" button correctly registerField("onlineFactor", ui->m_onlineFactor, "value"); registerField("onlineSourceCombo", ui->m_onlineSourceCombo, "currentText", SIGNAL(currentIndexChanged(QString))); registerField("useFinanceQuote", ui->m_useFinanceQuote); connect(ui->m_onlineSourceCombo, static_cast(&QComboBox::currentIndexChanged), this, &KOnlineUpdateWizardPage::slotCheckPage); connect(ui->m_onlineFactor, &KMyMoneyEdit::textChanged, this, &QWizardPage::completeChanged); connect(ui->m_onlineSourceCombo, static_cast(&QComboBox::activated), this, &QWizardPage::completeChanged); connect(ui->m_useFinanceQuote, &QAbstractButton::toggled, this, &QWizardPage::completeChanged); } KOnlineUpdateWizardPage::~KOnlineUpdateWizardPage() { delete ui; } /** * Set the values based on the @param security */ void KOnlineUpdateWizardPage::init2(const MyMoneySecurity& security) { int idx; if (security.value("kmm-online-quote-system") == "Finance::Quote") { FinanceQuoteProcess p; ui->m_useFinanceQuote->setChecked(true); idx = ui->m_onlineSourceCombo->findText(p.niceName(security.value("kmm-online-source"))); } else { idx = ui->m_onlineSourceCombo->findText(security.value("kmm-online-source")); } // in case we did not find the entry, we use the empty one if (idx == -1) idx = ui->m_onlineSourceCombo->findText(QString()); ui->m_onlineSourceCombo->setCurrentIndex(idx); if (!security.value("kmm-online-factor").isEmpty()) ui->m_onlineFactor->setValue(MyMoneyMoney(security.value("kmm-online-factor"))); } /** * Update the "Next" button */ bool KOnlineUpdateWizardPage::isComplete() const { return !(ui->m_onlineFactor->isEnabled() && ui->m_onlineFactor->value().isZero()); } bool KOnlineUpdateWizardPage::isOnlineFactorEnabled() const { return ui->m_onlineFactor->isEnabled(); } void KOnlineUpdateWizardPage::slotCheckPage(const QString& txt) { ui->m_onlineFactor->setEnabled(!txt.isEmpty()); } void KOnlineUpdateWizardPage::slotSourceChanged(bool useFQ) { ui->m_onlineSourceCombo->clear(); ui->m_onlineSourceCombo->insertItem(0, QString()); if (useFQ) { ui->m_onlineSourceCombo->addItems(WebPriceQuote::quoteSources(WebPriceQuote::FinanceQuote)); } else { ui->m_onlineSourceCombo->addItems(WebPriceQuote::quoteSources()); } ui->m_onlineSourceCombo->model()->sort(0); } diff --git a/kmymoney/wizards/newloanwizard/keditloanwizard.cpp b/kmymoney/wizards/newloanwizard/keditloanwizard.cpp index fb41a9b7c..249c0a4c3 100644 --- a/kmymoney/wizards/newloanwizard/keditloanwizard.cpp +++ b/kmymoney/wizards/newloanwizard/keditloanwizard.cpp @@ -1,550 +1,550 @@ /*************************************************************************** keditloanwizard.cpp - description ------------------- begin : Wed Nov 12 2003 copyright : (C) 2000-2003 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio (C) 2017 by Łukasz Wojniłowicz ***************************************************************************/ /*************************************************************************** * * * 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 "keditloanwizard.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes #include "ui_interesteditwizardpage.h" #include "ui_paymentfrequencywizardpage.h" #include "ui_paymenteditwizardpage.h" #include "ui_loanattributeswizardpage.h" #include "ui_effectivedatewizardpage.h" #include "ui_interesttypewizardpage.h" #include "ui_editselectionwizardpage.h" #include "ui_finalpaymentwizardpage.h" #include "knewloanwizard.h" #include "knewloanwizard_p.h" #include "kmymoneylineedit.h" #include "kmymoneyedit.h" #include "kmymoneyaccountselector.h" #include "mymoneyfile.h" #include "mymoneyinstitution.h" #include "mymoneyaccount.h" #include "mymoneyaccountloan.h" #include "mymoneypayee.h" #include "mymoneyschedule.h" #include "mymoneytransactionfilter.h" class KEditLoanWizardPrivate : public KNewLoanWizardPrivate { Q_DISABLE_COPY(KEditLoanWizardPrivate) public: KEditLoanWizardPrivate(KEditLoanWizard *qq) : KNewLoanWizardPrivate(qq), m_lastSelection(0), m_fullyRepayLoan(false) { } MyMoneySchedule m_schedule; int m_lastSelection; bool m_fullyRepayLoan; }; KEditLoanWizard::KEditLoanWizard(const MyMoneyAccount& account, QWidget *parent) : KNewLoanWizard(*new KEditLoanWizardPrivate(this), parent) { Q_D(KEditLoanWizard); auto file = MyMoneyFile::instance(); setWindowTitle(i18n("Edit loan wizard")); d->m_account = account; try { QString id = d->m_account.value("schedule"); d->m_schedule = file->schedule(id); } catch (const MyMoneyException &) { } d->m_lastSelection = -1; loadWidgets(d->m_account); if (d->m_account.openingDate() > QDate::currentDate()) { //FIXME: port d->ui->m_effectiveDatePage->ui->m_effectiveDateNoteLabel->setText(QString("\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.", QLocale().toString(d->m_account.openingDate()))); } else { d->ui->m_effectiveDatePage->ui->m_effectiveDateNoteLabel->hide(); } // turn off all pages that are contained here for derived classes d->m_pages.clearBit(Page_Intro); d->m_pages.clearBit(Page_NewGeneralInfo); d->m_pages.clearBit(Page_LendBorrow); d->m_pages.clearBit(Page_Name); d->m_pages.clearBit(Page_NewCalculateLoan); d->m_pages.clearBit(Page_NewPayments); removePage(Page_AssetAccount); d->ui->m_assetAccountPage = 0; // turn on all pages that are contained here for derived classes d->m_pages.setBit(Page_EditIntro); d->m_pages.setBit(Page_EditSelection); // make sure, we show the correct start page setStartId(Page_EditIntro); } KEditLoanWizard::~KEditLoanWizard() { } void KEditLoanWizard::loadWidgets(const MyMoneyAccount& /* account */) { Q_D(KEditLoanWizard); auto file = MyMoneyFile::instance(); QString paymentAccountId, interestAccountId; //FIXME: port d->ui->m_namePage->ui->m_nameEdit->loadText(d->m_account.name()); d->ui->m_loanAmountPage->ui->m_loanAmountEdit->loadText(d->m_account.loanAmount().formatMoney(d->m_account.fraction(MyMoneyFile::instance()->security(d->m_account.currencyId())))); d->ui->m_finalPaymentPage->ui->m_finalPaymentEdit->loadText(d->m_account.finalPayment().formatMoney(d->m_account.fraction(MyMoneyFile::instance()->security(d->m_account.currencyId())))); setField("firstDueDateEdit", d->m_account.openingDate()); //FIXME: port if (d->m_account.fixedInterestRate()) { d->ui->m_interestTypePage->ui->m_fixedInterestButton->click(); } else { d->ui->m_interestTypePage->ui->m_variableInterestButton->click(); } QString institutionName; try { institutionName = file->institution(d->m_account.institutionId()).name(); } catch (const MyMoneyException &) { } d->ui->m_loanAttributesPage->setInstitution(institutionName); MyMoneyMoney ir; if (d->m_schedule.startDate() > QDate::currentDate()) { ir = d->m_account.interestRate(d->m_schedule.startDate()); } else { ir = d->m_account.interestRate(QDate::currentDate()); } //FIXME: port - d->ui->m_interestPage->ui->m_interestRateEdit->loadText(ir.formatMoney(QString(), 3)); d->ui->m_interestPage->ui->m_interestRateEdit->setPrecision(3); - d->ui->m_interestEditPage->ui->m_newInterestRateEdit->loadText(ir.formatMoney(QString(), 3)); + d->ui->m_interestPage->ui->m_interestRateEdit->loadText(ir.formatMoney(QString(), 3)); d->ui->m_interestEditPage->ui->m_newInterestRateEdit->setPrecision(3); + d->ui->m_interestEditPage->ui->m_newInterestRateEdit->loadText(ir.formatMoney(QString(), 3)); d->ui->m_interestEditPage->ui->m_interestRateLabel->setText(QString(" ") + ir.formatMoney(QString(), 3) + QString("%")); d->ui->m_paymentFrequencyPage->ui->m_paymentFrequencyUnitEdit->setCurrentIndex(d->ui->m_paymentFrequencyPage->ui->m_paymentFrequencyUnitEdit->findData(QVariant((int)d->m_schedule.occurrence()), Qt::UserRole, Qt::MatchExactly)); d->ui->m_durationPage->updateTermWidgets(d->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; d->m_transaction = d->m_schedule.transaction(); foreach (const MyMoneySplit& it_s, d->m_schedule.transaction().splits()) { 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()) { setField("lendButton", false); setField("borrowButton", true); } else { setField("lendButton", true); setField("borrowButton", 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()); setField("payeeEdit", payee.id()); } catch (const MyMoneyException &) { qWarning("Payee for schedule has been deleted"); } } // remove this split with one that will be replaced // later and has a phony id d->m_transaction.removeSplit(it_s); d->m_split.clearId(); d->m_transaction.addSplit(d->m_split); } if (it_s.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::Interest)) { 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 d->m_transaction.removeSplit(it_s); } } if (field("borrowButton").toBool()) { 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 d->loadAccountList(); int fraction = d->m_account.fraction(MyMoneyFile::instance()->security(d->m_account.currencyId())); //FIXME: port d->ui->m_paymentPage->ui->m_paymentEdit->loadText(basePayment.formatMoney(fraction)); d->ui->m_paymentEditPage->ui->m_newPaymentEdit->loadText(basePayment.formatMoney(fraction)); d->ui->m_paymentEditPage->ui->m_paymentLabel->setText(QString(" ") + basePayment.formatMoney(fraction)); setField("additionalCost", addPayment.formatMoney(fraction)); d->ui->m_interestCategoryPage->ui->m_interestAccountEdit->setSelected(interestAccountId); d->ui->m_schedulePage->ui->m_paymentAccountEdit->setSelected(paymentAccountId); setField("nextDueDateEdit", d->m_schedule.nextPayment()); int changeFrequencyUnit; int amt = d->m_account.interestChangeFrequency(&changeFrequencyUnit); if (amt != -1) { setField("interestFrequencyAmountEdit", amt); setField("interestFrequencyUnitEdit", changeFrequencyUnit); } // keep track, if the loan should be fully repayed d->m_fullyRepayLoan = d->m_account.finalPayment() < basePayment; d->updateLoanInfo(); } bool KEditLoanWizard::validateCurrentPage() { Q_D(KEditLoanWizard); auto dontLeavePage = false; //FIXME: port m_lastSelection QAbstractButton* button = d->ui->m_editSelectionPage->ui->m_selectionButtonGroup->button(d->m_lastSelection); if (currentPage() == d->ui->m_editSelectionPage) { if (button != 0 && d->m_lastSelection != d->ui->m_editSelectionPage->ui->m_selectionButtonGroup->checkedId()) { QString 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?", button->text()); if (KMessageBox::questionYesNo(this, errMsg) == KMessageBox::No) { dontLeavePage = true; } else { loadWidgets(d->m_account); } } if (!dontLeavePage) { // 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 d->m_pages.clearBit(Page_Name); d->m_pages.clearBit(Page_InterestType); d->m_pages.clearBit(Page_PreviousPayments); d->m_pages.clearBit(Page_RecordPayment); d->m_pages.clearBit(Page_VariableInterestDate); d->m_pages.clearBit(Page_FirstPayment); // loan calculation d->m_pages.clearBit(Page_PaymentEdit); d->m_pages.clearBit(Page_InterestEdit); d->m_pages.clearBit(Page_PaymentFrequency); d->m_pages.clearBit(Page_InterestCalculation); d->m_pages.clearBit(Page_LoanAmount); d->m_pages.clearBit(Page_Interest); d->m_pages.clearBit(Page_Duration); d->m_pages.clearBit(Page_Payment); d->m_pages.clearBit(Page_FinalPayment); d->m_pages.clearBit(Page_CalculationOverview); // payment d->m_pages.clearBit(Page_InterestCategory); d->m_pages.clearBit(Page_AdditionalFees); d->m_pages.clearBit(Page_Schedule); d->m_pages.setBit(Page_Summary); // Attributes d->m_pages.clearBit(Page_LoanAttributes); d->m_pages.setBit(Page_EffectiveDate); if (page(Page_Summary) != 0) { removePage(Page_Summary); } if (field("editInterestRateButton").toBool()) { d->m_pages.setBit(Page_PaymentFrequency); d->m_pages.setBit(Page_InterestType); d->m_pages.setBit(Page_VariableInterestDate); d->m_pages.setBit(Page_PaymentEdit); d->m_pages.setBit(Page_InterestEdit); d->m_pages.setBit(Page_InterestCategory); d->m_pages.setBit(Page_Schedule); d->m_pages.setBit(Page_SummaryEdit); } else if (field("editOtherCostButton").toBool()) { d->m_pages.setBit(Page_PaymentFrequency); d->m_pages.setBit(Page_AdditionalFees); d->m_pages.setBit(Page_InterestCategory); d->m_pages.setBit(Page_Schedule); d->m_pages.setBit(Page_SummaryEdit); } else if (field("editOtherInfoButton").toBool()) { d->m_pages.setBit(Page_Name); d->m_pages.setBit(Page_InterestCalculation); d->m_pages.setBit(Page_Interest); d->m_pages.setBit(Page_Duration); d->m_pages.setBit(Page_Payment); d->m_pages.setBit(Page_FinalPayment); d->m_pages.setBit(Page_CalculationOverview); d->m_pages.setBit(Page_InterestCategory); d->m_pages.setBit(Page_AdditionalFees); d->m_pages.setBit(Page_Schedule); d->m_pages.clearBit(Page_SummaryEdit); setPage(Page_Summary, d->ui->m_summaryPage); d->m_pages.setBit(Page_Summary); } else if (field("editAttributesButton").toBool()) { d->m_pages.setBit(Page_LoanAttributes); d->m_pages.clearBit(Page_EffectiveDate); } else { qWarning("%s,%d: This should never happen", __FILE__, __LINE__); } d->m_lastSelection = d->ui->m_editSelectionPage->ui->m_selectionButtonGroup->checkedId(); } // if(!dontLeavePage) } else if (currentPage() == d->ui->m_additionalFeesPage) { if (field("editOtherCostButton").toBool()) { d->updateLoanInfo(); updateEditSummary(); } } else if (currentPage() == d->ui->m_interestEditPage) { // copy the necessary data to the widgets used for calculation //FIXME: port to fields d->ui->m_interestPage->ui->m_interestRateEdit->setValue(field("newInterestRateEdit").value()); d->ui->m_paymentPage->ui->m_paymentEdit->setValue(field("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 d->ui->m_durationPage->updateTermWidgets(d->m_account.term()); if (field("interestRateEditValid").toBool() && field("paymentEditValid").toBool()) { // 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 (field("loanAmountEdit").value() != field("finalPaymentEdit").value()) { setField("durationValueEdit", 0); } if (d->m_fullyRepayLoan) d->ui->m_finalPaymentPage->ui->m_finalPaymentEdit->loadText(MyMoneyMoney().formatMoney(d->m_account.fraction(MyMoneyFile::instance()->security(d->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(); QList list; QList::ConstIterator it; MyMoneySplit split; MyMoneyTransactionFilter filter(m_account.id()); filter.setDateFilter(QDate(), 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 (const MyMoneyException &e) { // account is not referenced within this transaction } } m_loanAmountEdit->setText(balance.formatMoney()); */ // now re-calculate the figures dontLeavePage = !d->calculateLoan(); // reset the original loan amount to the widget //FIXME: port to fields d->ui->m_loanAmountPage->ui->m_loanAmountEdit->setValue(d->m_account.loanAmount()); if (!dontLeavePage) { d->updateLoanInfo(); updateEditSummary(); } } if (!dontLeavePage) dontLeavePage = ! KNewLoanWizard::validateCurrentPage(); // These might have been set by KNewLoanWizard d->m_pages.clearBit(Page_PreviousPayments); d->m_pages.clearBit(Page_RecordPayment); if (dontLeavePage) return false; // we never need to show this page if (currentPage() == d->ui->m_previousPaymentsPage) dontLeavePage = KNewLoanWizard::validateCurrentPage(); return ! dontLeavePage; } void KEditLoanWizard::updateEditSummary() { Q_D(KEditLoanWizard); // calculate the number of affected transactions MyMoneyTransactionFilter filter(d->m_account.id()); filter.setDateFilter(field("effectiveChangeDateEdit").toDate(), QDate()); int count = 0; QList list; list = MyMoneyFile::instance()->transactionList(filter); foreach (const MyMoneyTransaction& it, list) { int match = 0; foreach (const MyMoneySplit& it_s, it.splits()) { // we only count those transactions that have an interest // and amortization part if (it_s.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::Interest)) match |= 0x01; if (it_s.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::Amortization)) match |= 0x02; } if (match == 0x03) ++count; } setField("affectedPayments", QString().sprintf("%d", count)); } const MyMoneySchedule KEditLoanWizard::schedule() const { Q_D(const KEditLoanWizard); MyMoneySchedule sched = d->m_schedule; sched.setTransaction(transaction()); sched.setOccurrence(eMyMoney::Schedule::Occurrence(field("paymentFrequencyUnitEdit").toInt())); if (field("nextDueDateEdit").toDate() < d->m_schedule.startDate()) sched.setStartDate(field("nextDueDateEdit").toDate()); return sched; } const MyMoneyAccount KEditLoanWizard::account() const { Q_D(const KEditLoanWizard); MyMoneyAccountLoan acc(d->m_account); if (field("interestOnReceptionButton").toBool()) acc.setInterestCalculation(MyMoneyAccountLoan::paymentReceived); else acc.setInterestCalculation(MyMoneyAccountLoan::paymentDue); auto file = MyMoneyFile::instance(); QString institution = d->ui->m_loanAttributesPage->ui->m_qcomboboxInstitutions->currentText(); if (institution != i18n("(No Institution)")) { const auto list = file->institutionList(); for (const auto& testInstitution : list) { if (testInstitution.name() == institution) { acc.setInstitutionId(testInstitution.id()); break; } } } else { acc.setInstitutionId(QString()); } acc.setFixedInterestRate(field("fixedInterestButton").toBool()); acc.setFinalPayment(field("finalPaymentEdit").value()); acc.setTerm(d->ui->m_durationPage->term()); acc.setPeriodicPayment(field("paymentEdit").value()); acc.setInterestRate(field("effectiveChangeDateEdit").toDate(), field("interestRateEdit").value()); acc.setPayee(field("payeeEdit").toString()); if (field("variableInterestButton").toBool()) { acc.setNextInterestChange(field("interestChangeDateEdit").toDate()); acc.setInterestChangeFrequency(field("interestFrequencyAmountEdit").toInt(), field("interestFrequencyUnitEdit").toInt()); } return acc; } const MyMoneyTransaction KEditLoanWizard::transaction() const { Q_D(const KEditLoanWizard); auto t = d->transaction(); auto s = t.splitByAccount(QString("Phony-ID")); s.setAccountId(d->m_account.id()); t.modifySplit(s); return t; }