File indexing completed on 2024-06-16 04:47:25
0001 /*************************************************************************** 0002 * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr 0003 * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 ***************************************************************************/ 0006 /** @file 0007 * A skrooge plugin to manage budgets 0008 * 0009 * @author Stephane MANKOWSKI 0010 */ 0011 #include "skgbudgetplugin.h" 0012 0013 #include <kaboutdata.h> 0014 #include <kactioncollection.h> 0015 #include <klocalizedstring.h> 0016 #include <kpluginfactory.h> 0017 #include <kstandardaction.h> 0018 0019 #include "skgbudgetobject.h" 0020 #include "skgbudgetpluginwidget.h" 0021 #include "skgbudgetruleobject.h" 0022 #include "skgdocumentbank.h" 0023 #include "skgmainpanel.h" 0024 #include "skgtraces.h" 0025 #include "skgtransactionmng.h" 0026 0027 /** 0028 * This plugin factory. 0029 */ 0030 K_PLUGIN_CLASS_WITH_JSON(SKGBudgetPlugin, "metadata.json") 0031 0032 SKGBudgetPlugin::SKGBudgetPlugin(QWidget* iWidget, QObject* iParent, const QVariantList& /*iArg*/) : SKGInterfacePlugin(iParent), m_currentBankDocument(nullptr) 0033 { 0034 Q_UNUSED(iWidget) 0035 SKGTRACEINFUNC(10) 0036 } 0037 0038 SKGBudgetPlugin::~SKGBudgetPlugin() 0039 { 0040 SKGTRACEINFUNC(10) 0041 m_currentBankDocument = nullptr; 0042 } 0043 0044 bool SKGBudgetPlugin::setupActions(SKGDocument* iDocument) 0045 { 0046 SKGTRACEINFUNC(10) 0047 0048 m_currentBankDocument = qobject_cast<SKGDocumentBank*>(iDocument); 0049 if (m_currentBankDocument == nullptr) { 0050 return false; 0051 } 0052 0053 setComponentName(QStringLiteral("skrooge_budget"), title()); 0054 setXMLFile(QStringLiteral("skrooge_budget.rc")); 0055 0056 // Create yours actions here 0057 // ----------- 0058 QStringList overlayrun; 0059 overlayrun.push_back(QStringLiteral("system-run")); 0060 auto act = new QAction(SKGServices::fromTheme(icon(), overlayrun), i18nc("Verb", "Process budget rules"), this); 0061 connect(act, &QAction::triggered, this, &SKGBudgetPlugin::onProcessRules); 0062 registerGlobalAction(QStringLiteral("tool_process_budget_rules"), act); 0063 return true; 0064 } 0065 0066 SKGTabPage* SKGBudgetPlugin::getWidget() 0067 { 0068 SKGTRACEINFUNC(10) 0069 return new SKGBudgetPluginWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument); 0070 } 0071 0072 QString SKGBudgetPlugin::title() const 0073 { 0074 return i18nc("The title", "Budget"); 0075 } 0076 0077 QString SKGBudgetPlugin::icon() const 0078 { 0079 return QStringLiteral("view-calendar-whatsnext"); 0080 } 0081 0082 QString SKGBudgetPlugin::toolTip() const 0083 { 0084 return i18nc("The tool tip", "Budget"); 0085 } 0086 0087 int SKGBudgetPlugin::getOrder() const 0088 { 0089 return 32; 0090 } 0091 0092 QStringList SKGBudgetPlugin::tips() const 0093 { 0094 QStringList output; 0095 return output; 0096 } 0097 0098 bool SKGBudgetPlugin::isInPagesChooser() const 0099 { 0100 return true; 0101 } 0102 0103 SKGAdviceList SKGBudgetPlugin::advice(const QStringList& iIgnoredAdvice) 0104 { 0105 SKGTRACEINFUNC(10) 0106 SKGAdviceList output; 0107 QString month = QDate::currentDate().toString(QStringLiteral("yyyy-MM")); 0108 QString year = QDate::currentDate().toString(QStringLiteral("yyyy")); 0109 0110 // Alarms 0111 if (!iIgnoredAdvice.contains(QStringLiteral("skgbudgetplugin_alarm"))) { 0112 SKGObjectBase::SKGListSKGObjectBase budgets; 0113 // Query is done on v_budget_display because v_budget_display is faster than v_budget 0114 SKGError err = m_currentBankDocument->getObjects(QStringLiteral("v_budget_display"), "(f_CURRENTAMOUNT/f_budgeted_modified>0.8 OR (f_CURRENTAMOUNT<0 AND f_budgeted_modified>0)) AND ABS(f_CURRENTAMOUNT-f_budgeted_modified)>" % SKGServices::doubleToString(EPSILON) % " AND f_budgeted<0 AND (t_PERIOD='" % month % "' OR t_PERIOD='" % year % "');", budgets); 0115 int nb = budgets.count(); 0116 if (nb != 0) { 0117 SKGServices::SKGUnitInfo primary = m_currentBankDocument->getPrimaryUnit(); 0118 SKGAdvice::SKGAdviceActionList autoCorrections; 0119 for (int i = 0; !err && i < nb; ++i) { 0120 SKGBudgetObject budget(budgets.at(i)); 0121 double f_CURRENTAMOUNT = SKGServices::stringToDouble(budget.getAttribute(QStringLiteral("f_CURRENTAMOUNT"))); 0122 double f_budgeted_modified = SKGServices::stringToDouble(budget.getAttribute(QStringLiteral("f_budgeted_modified"))); 0123 0124 SKGAdvice ad; 0125 ad.setUUID("skgbudgetplugin_alarm|" % SKGServices::intToString(budget.getID())); 0126 ad.setPriority((f_CURRENTAMOUNT < f_budgeted_modified ? 9 : 6)); 0127 ad.setShortMessage(i18nc("Advice on making the best (short)", "Budget alarm for '%1'", budget.getAttribute(QStringLiteral("t_CATEGORY")))); 0128 ad.setLongMessage(i18nc("Advice on making the best (long)", "Take care to your budget.<br> %1.<br>%2 / %3", 0129 budget.getAttribute(QStringLiteral("t_CATEGORY")), 0130 m_currentBankDocument->formatMoney(f_CURRENTAMOUNT, primary), 0131 m_currentBankDocument->formatMoney(f_budgeted_modified, primary))); 0132 autoCorrections.resize(0); 0133 { 0134 SKGAdvice::SKGAdviceAction a; 0135 a.Title = i18nc("Advice on making the best (action)", "Open transactions corresponding to this budget"); 0136 a.IconName = QStringLiteral("quickopen"); 0137 a.IsRecommended = false; 0138 autoCorrections.push_back(a); 0139 } 0140 ad.setAutoCorrections(autoCorrections); 0141 output.push_back(ad); 0142 } 0143 } 0144 } 0145 0146 if (!iIgnoredAdvice.contains(QStringLiteral("skgbudgetplugin_oldprocessing"))) { 0147 QString lastBudgetProcessingDate = m_currentBankDocument->getParameter(QStringLiteral("SKG_LAST_BUDGET_PROCESSING")); 0148 if (lastBudgetProcessingDate.isEmpty() || SKGServices::stringToTime(lastBudgetProcessingDate).date() < QDate::currentDate().addMonths(-1)) { // Ignore header 0149 bool exist = false; 0150 m_currentBankDocument->existObjects(QStringLiteral("budgetrule"), QLatin1String(""), exist); 0151 if (exist) { 0152 SKGAdvice ad; 0153 ad.setUUID(QStringLiteral("skgbudgetplugin_oldprocessing")); 0154 ad.setPriority(3); 0155 ad.setShortMessage(i18nc("Advice on making the best (short)", "Old budget treatment")); 0156 ad.setLongMessage(i18nc("Advice on making the best (long)", "The budget has not been treated for at least one month.")); 0157 SKGAdvice::SKGAdviceActionList autoCorrections; 0158 { 0159 SKGAdvice::SKGAdviceAction a; 0160 a.Title = QStringLiteral("skg://tool_process_budget_rules"); 0161 a.IsRecommended = true; 0162 autoCorrections.push_back(a); 0163 } 0164 ad.setAutoCorrections(autoCorrections); 0165 output.push_back(ad); 0166 } 0167 } 0168 } 0169 0170 return output; 0171 } 0172 SKGError SKGBudgetPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution) 0173 { 0174 if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgbudgetplugin_alarm|"))) { 0175 // Get parameters 0176 QString id = iAdviceIdentifier.right(iAdviceIdentifier.length() - 22); 0177 SKGBudgetObject budget(m_currentBankDocument, SKGServices::stringToInt(id)); 0178 budget.load(); 0179 0180 QAction* act = SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("open")); 0181 if (act != nullptr) { 0182 act->setData(budget.getUniqueID()); 0183 act->trigger(); 0184 } 0185 0186 return SKGError(); 0187 } 0188 return SKGInterfacePlugin::executeAdviceCorrection(iAdviceIdentifier, iSolution); 0189 } 0190 0191 void SKGBudgetPlugin::onProcessRules() 0192 { 0193 SKGError err; 0194 _SKGTRACEINFUNCRC(10, err) 0195 0196 { 0197 SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Process budget rules"), err) 0198 err = SKGBudgetRuleObject::processAllRules(m_currentBankDocument); 0199 } 0200 // status bar 0201 IFOK(err) { 0202 err = SKGError(0, i18nc("Successful message after an user action", "Budget rules processed")); 0203 } else { 0204 err.addError(ERR_FAIL, i18nc("Error message", "Budget rules failed")); 0205 } 0206 0207 // Display error 0208 SKGMainPanel::displayErrorMessage(err); 0209 } 0210 0211 #include <skgbudgetplugin.moc>