File indexing completed on 2024-06-09 05:03:30

0001 /*
0002     SPDX-FileCopyrightText: 2004 Thomas Baumgart <kmymoney-devel@kde.org>
0003     SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "knewinvestmentwizard.h"
0008 
0009 // ----------------------------------------------------------------------------
0010 // QT Includes
0011 
0012 #include <QList>
0013 #include <QPointer>
0014 
0015 // ----------------------------------------------------------------------------
0016 // KDE Includes
0017 
0018 #include <KMessageBox>
0019 #include <KHelpClient>
0020 #include <KLocalizedString>
0021 
0022 // ----------------------------------------------------------------------------
0023 // Project Includes
0024 
0025 #include "ui_knewinvestmentwizard.h"
0026 
0027 #include "kmymoneyutils.h"
0028 #include "mymoneyaccount.h"
0029 #include "mymoneyenums.h"
0030 #include "mymoneyexception.h"
0031 #include "mymoneyfile.h"
0032 #include "mymoneymoney.h"
0033 #include "mymoneysecurity.h"
0034 /// @todo AlkOnlineQuote remove following include when ported to Alkimia
0035 #include "webpricequote.h"
0036 
0037 #include "kmmyesno.h"
0038 
0039 class KNewInvestmentWizardPrivate
0040 {
0041     Q_DISABLE_COPY(KNewInvestmentWizardPrivate)
0042     Q_DECLARE_PUBLIC(KNewInvestmentWizard)
0043 
0044 public:
0045     explicit KNewInvestmentWizardPrivate(KNewInvestmentWizard *qq) :
0046         q_ptr(qq),
0047         ui(new Ui::KNewInvestmentWizard),
0048         m_createAccount(false)
0049     {
0050     }
0051 
0052     ~KNewInvestmentWizardPrivate()
0053     {
0054         delete ui;
0055     }
0056 
0057     void init1()
0058     {
0059         Q_Q(KNewInvestmentWizard);
0060         ui->m_onlineUpdatePage->slotSourceChanged(false);
0061 
0062         // make sure, the back button does not clear fields
0063         q->setOption(QWizard::IndependentPages, true);
0064 
0065         // enable the help button
0066         q->setOption(q->HaveHelpButton, true);
0067         q->connect(q, &KNewInvestmentWizard::helpRequested, q, &KNewInvestmentWizard::slotHelp);
0068 
0069         m_createAccount = true;
0070 
0071         // Update label in case of edit
0072         if (!m_account.id().isEmpty()) {
0073             ui->m_investmentTypePage->setIntroLabelText(i18n("This wizard allows you to modify the selected investment."));
0074         }
0075         if (!m_security.id().isEmpty()) {
0076             ui->m_investmentTypePage->setIntroLabelText(i18n("This wizard allows you to modify the selected security."));
0077         }
0078 
0079         KMyMoneyUtils::updateWizardButtons(q);
0080     }
0081 
0082     void init2()
0083     {
0084         ui->m_investmentTypePage->init2(m_security);
0085         ui->m_investmentDetailsPage->init2(m_security);
0086         ui->m_onlineUpdatePage->init2(m_security);
0087         ui->m_onlineUpdatePage->slotCheckPage(m_security.value("kmm-online-source"));
0088     }
0089 
0090     KNewInvestmentWizard      *q_ptr;
0091     Ui::KNewInvestmentWizard  *ui;
0092 
0093     MyMoneyAccount    m_account;
0094     MyMoneySecurity   m_security;
0095     bool              m_createAccount;
0096 };
0097 
0098 KNewInvestmentWizard::KNewInvestmentWizard(QWidget *parent) :
0099     QWizard(parent),
0100     d_ptr(new KNewInvestmentWizardPrivate(this))
0101 {
0102     Q_D(KNewInvestmentWizard);
0103     d->ui->setupUi(this);
0104     d->init1();
0105     d->ui->m_onlineUpdatePage->slotCheckPage(QString());
0106 
0107     d->ui->m_investmentDetailsPage->setupInvestmentSymbol();
0108 
0109     connect(d->ui->m_investmentDetailsPage, &KInvestmentDetailsWizardPage::checkForExistingSymbol, this, &KNewInvestmentWizard::slotCheckForExistingSymbol);
0110 }
0111 
0112 KNewInvestmentWizard::KNewInvestmentWizard(const MyMoneyAccount& acc, QWidget *parent) :
0113     QWizard(parent),
0114     d_ptr(new KNewInvestmentWizardPrivate(this))
0115 {
0116     Q_D(KNewInvestmentWizard);
0117     d->ui->setupUi(this);
0118     d->m_account = acc;
0119     setWindowTitle(i18n("Investment detail wizard"));
0120     d->init1();
0121 
0122     // load the widgets with the data
0123     setName(d->m_account.name());
0124     d->m_security = MyMoneyFile::instance()->security(d->m_account.currencyId());
0125 
0126     d->init2();
0127 
0128     int priceMode = 0;
0129     if (!d->m_account.value("priceMode").isEmpty())
0130         priceMode = d->m_account.value("priceMode").toInt();
0131     d->ui->m_investmentDetailsPage->setCurrentPriceMode(priceMode);
0132 
0133 }
0134 
0135 KNewInvestmentWizard::KNewInvestmentWizard(const MyMoneySecurity& security, QWidget *parent) :
0136     QWizard(parent),
0137     d_ptr(new KNewInvestmentWizardPrivate(this))
0138 {
0139     Q_D(KNewInvestmentWizard);
0140     d->ui->setupUi(this);
0141     d->m_security = security;
0142     setWindowTitle(i18n("Security detail wizard"));
0143     d->init1();
0144     d->m_createAccount = false;
0145 
0146     // load the widgets with the data
0147     setName(security.name());
0148 
0149     d->init2();
0150 
0151     // no chance to change the price mode here
0152     d->ui->m_investmentDetailsPage->setCurrentPriceMode(0);
0153     d->ui->m_investmentDetailsPage->setPriceModeEnabled(false);
0154 }
0155 
0156 KNewInvestmentWizard::~KNewInvestmentWizard()
0157 {
0158 }
0159 
0160 void KNewInvestmentWizard::setName(const QString& name)
0161 {
0162     Q_D(KNewInvestmentWizard);
0163     d->ui->m_investmentDetailsPage->setName(name);
0164 }
0165 
0166 void KNewInvestmentWizard::slotCheckForExistingSymbol(const QString& symbol)
0167 {
0168     Q_D(KNewInvestmentWizard);
0169     Q_UNUSED(symbol);
0170 
0171     if (field("investmentName").toString().isEmpty()) {
0172         const QList<MyMoneySecurity> list = MyMoneyFile::instance()->securityList();
0173         auto type = static_cast<eMyMoney::Security::Type>(field("securityType").toInt());
0174 
0175         for (const MyMoneySecurity& it_s : list) {
0176             if (it_s.securityType() == type
0177                     && it_s.tradingSymbol() == field("investmentSymbol").toString()) {
0178                 d->m_security = MyMoneySecurity();
0179                 if (KMessageBox::questionTwoActions(this,
0180                                                     i18n("The selected symbol is already on file. Do you want to reuse the existing security?"),
0181                                                     i18n("Security found"),
0182                                                     KMMYesNo::yes(),
0183                                                     KMMYesNo::no())
0184                     == KMessageBox::PrimaryAction) {
0185                     d->m_security = it_s;
0186                     d->init2();
0187                     d->ui->m_investmentDetailsPage->loadName(d->m_security.name());
0188                 }
0189                 break;
0190             }
0191         }
0192     }
0193 }
0194 
0195 void KNewInvestmentWizard::slotHelp()
0196 {
0197     KHelpClient::invokeHelp("details.investments.newinvestmentwizard");
0198 }
0199 
0200 void KNewInvestmentWizard::createObjects(const QString& parentId)
0201 {
0202     Q_D(KNewInvestmentWizard);
0203     auto file = MyMoneyFile::instance();
0204 
0205     auto type = static_cast<eMyMoney::Security::Type>(field("securityType").toInt());
0206     auto roundingMethod = static_cast<AlkValue::RoundingMethod>(field("roundingMethod").toInt());
0207     MyMoneyFileTransaction ft;
0208     try {
0209         // update all relevant attributes only, if we create a stock
0210         // account and the security is unknown or we modify the security
0211         MyMoneySecurity newSecurity(d->m_security);
0212         newSecurity.setName(field("investmentName").toString());
0213         newSecurity.setTradingSymbol(field("investmentSymbol").toString());
0214         newSecurity.setTradingMarket(field("tradingMarket").toString());
0215         newSecurity.setSmallestAccountFraction(field("fraction").value<MyMoneyMoney>().formatMoney("", 0, false).toUInt());
0216         newSecurity.setPricePrecision(MyMoneyMoney(field("pricePrecision").toUInt()).formatMoney("", 0, false).toUInt());
0217         newSecurity.setTradingCurrency(field("tradingCurrencyEdit").value<MyMoneySecurity>().id());
0218         newSecurity.setSecurityType(type);
0219         newSecurity.setRoundingMethod(roundingMethod);
0220         newSecurity.deletePair("kmm-online-source");
0221         newSecurity.deletePair("kmm-online-quote-system");
0222         newSecurity.deletePair("kmm-online-factor");
0223         newSecurity.deletePair("kmm-security-id");
0224 
0225         if (!field("onlineSourceCombo").toString().isEmpty()) {
0226             if (field("useFinanceQuote").toBool()) {
0227                 FinanceQuoteProcess p;
0228                 newSecurity.setValue("kmm-online-quote-system", "Finance::Quote");
0229                 newSecurity.setValue("kmm-online-source", p.crypticName(field("onlineSourceCombo").toString()));
0230             } else {
0231                 newSecurity.setValue("kmm-online-source", field("onlineSourceCombo").toString());
0232             }
0233         }
0234         if (d->ui->m_onlineUpdatePage->isOnlineFactorEnabled() && (field("onlineFactor").value<MyMoneyMoney>() != MyMoneyMoney::ONE))
0235             newSecurity.setValue("kmm-online-factor", field("onlineFactor").value<MyMoneyMoney>().toString());
0236         if (!field("investmentIdentification").toString().isEmpty())
0237             newSecurity.setValue("kmm-security-id", field("investmentIdentification").toString());
0238 
0239         if (d->m_security.id().isEmpty() || newSecurity != d->m_security) {
0240             d->m_security = newSecurity;
0241 
0242             // add or update it
0243             if (d->m_security.id().isEmpty()) {
0244                 file->addSecurity(d->m_security);
0245             } else {
0246                 file->modifySecurity(d->m_security);
0247             }
0248         }
0249 
0250         if (d->m_createAccount) {
0251             // now that the security exists, we can add the account to store it
0252             d->m_account.setName(field("investmentName").toString());
0253             if (d->m_account.accountType() == eMyMoney::Account::Type::Unknown)
0254                 d->m_account.setAccountType(eMyMoney::Account::Type::Stock);
0255 
0256             d->m_account.setCurrencyId(d->m_security.id());
0257             switch (d->ui->m_investmentDetailsPage->priceMode()) {
0258             case 0:
0259                 d->m_account.deletePair("priceMode");
0260                 break;
0261             case 1:
0262             case 2:
0263                 d->m_account.setValue("priceMode", QString("%1").arg(d->ui->m_investmentDetailsPage->priceMode()));
0264                 break;
0265             }
0266             // update account's fraction in case its security fraction has changed
0267             // otherwise KMM restart is required because this won't happen automatically
0268             d->m_account.fraction(d->m_security);
0269             if (d->m_account.id().isEmpty()) {
0270                 MyMoneyAccount parent = file->account(parentId);
0271                 file->addAccount(d->m_account, parent);
0272             } else
0273                 file->modifyAccount(d->m_account);
0274         }
0275         ft.commit();
0276     } catch (const MyMoneyException &e) {
0277         KMessageBox::detailedError(this, i18n("Unexpected error occurred while adding new investment"), QString::fromLatin1(e.what()));
0278     }
0279 }
0280 
0281 void KNewInvestmentWizard::newInvestment(const MyMoneyAccount& parent)
0282 {
0283     QPointer<KNewInvestmentWizard> dlg = new KNewInvestmentWizard;
0284     if (dlg->exec() == QDialog::Accepted)
0285         dlg->createObjects(parent.id());
0286     delete dlg;
0287 }
0288 
0289 void KNewInvestmentWizard::newInvestment(MyMoneyAccount& account, const MyMoneyAccount& parent)
0290 {
0291     QString dontShowAgain = "CreateNewInvestments";
0292     if (KMessageBox::questionTwoActions(nullptr,
0293                                         i18n("<qt>The security <b>%1</b> currently does not exist as sub-account of <b>%2</b>. "
0294                                              "Do you want to create it?</qt>",
0295                                              account.name(),
0296                                              parent.name()),
0297                                         i18n("Create security"),
0298                                         KMMYesNo::yes(),
0299                                         KMMYesNo::no(),
0300                                         dontShowAgain)
0301         == KMessageBox::PrimaryAction) {
0302         QPointer<KNewInvestmentWizard> dlg = new KNewInvestmentWizard;
0303         dlg->setName(account.name());
0304         if (dlg->exec() == QDialog::Accepted) {
0305             dlg->createObjects(parent.id());
0306             account = dlg->account();
0307         }
0308         delete dlg;
0309     } else {
0310         // in case the user said no but turned on the don't show again selection, we will enable
0311         // the message no matter what. Otherwise, the user is not able to use this feature
0312         // in the future anymore.
0313         KMessageBox::enableMessage(dontShowAgain);
0314     }
0315 }
0316 
0317 void KNewInvestmentWizard::editInvestment(const MyMoneyAccount& parent)
0318 {
0319     QPointer<KNewInvestmentWizard> dlg = new KNewInvestmentWizard(parent);
0320     if (dlg->exec() == QDialog::Accepted)
0321         dlg->createObjects(parent.id());
0322     delete dlg;
0323 }
0324 
0325 MyMoneyAccount KNewInvestmentWizard::account() const
0326 {
0327     Q_D(const KNewInvestmentWizard);
0328     return d->m_account;
0329 }