1 /***************************************************************************
2 * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3 * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 ***************************************************************************/
6 /** @file
7 * This file is Skrooge plugin for unit management.
8 *
9 * @author Stephane MANKOWSKI / Guillaume DE BURE
10 */
11 #include "skgunitplugin.h"
12
13 #include <kaboutdata.h>
14 #include <kactioncollection.h>
15 #include <kpluginfactory.h>
16 #include <kservicetypetrader.h>
17
18 #include <qaction.h>
19 #include <qinputdialog.h>
20 #include <qprocess.h>
21
22 #include "skgdocumentbank.h"
23 #include "skghtmlboardwidget.h"
24 #include "skgmainpanel.h"
25 #include "skgtraces.h"
26 #include "skgtransactionmng.h"
27 #include "skgunit_settings.h"
28 #include "skgunitboardwidget.h"
29 #include "skgunitpluginwidget.h"
30 #include "skgunitvalueobject.h"
31
32 /**
33 * This plugin factory.
34 */
K_PLUGIN_FACTORY(SKGUnitPluginFactory,registerPlugin<SKGUnitPlugin> ();)35 K_PLUGIN_FACTORY(SKGUnitPluginFactory, registerPlugin<SKGUnitPlugin>();)
36
37 SKGUnitPlugin::SKGUnitPlugin(QWidget* iWidget, QObject* iParent, const QVariantList& /*iArg*/)
38 : SKGInterfacePlugin(iParent), m_currentBankDocument(nullptr)
39 {
40 Q_UNUSED(iWidget)
41 SKGTRACEINFUNC(10)
42 }
43
~SKGUnitPlugin()44 SKGUnitPlugin::~SKGUnitPlugin()
45 {
46 SKGTRACEINFUNC(10)
47 m_currentBankDocument = nullptr;
48 }
49
setupActions(SKGDocument * iDocument)50 bool SKGUnitPlugin::setupActions(SKGDocument* iDocument)
51 {
52 SKGTRACEINFUNC(10)
53
54 m_currentBankDocument = qobject_cast<SKGDocumentBank*>(iDocument);
55 if (m_currentBankDocument == nullptr) {
56 return false;
57 }
58
59 setComponentName(QStringLiteral("skrooge_unit"), title());
60 setXMLFile(QStringLiteral("skrooge_unit.rc"));
61
62 // Menu
63 auto actSplitShare = new QAction(SKGServices::fromTheme(QStringLiteral("format-text-strikethrough")), i18nc("Verb", "Split share..."), this);
64 connect(actSplitShare, &QAction::triggered, this, &SKGUnitPlugin::onSplitShare);
65 actionCollection()->setDefaultShortcut(actSplitShare, Qt::ALT + Qt::Key_Slash);
66 registerGlobalAction(QStringLiteral("edit_split_stock"), actSplitShare, QStringList() << QStringLiteral("unit"), 1, 1, 310); // TODO(Stephane MANKOWSKI): must be a share
67
68 // -----------
69 auto act = new QAction(SKGServices::fromTheme(icon()), i18nc("Verb", "Delete unused units"), this);
70 connect(act, &QAction::triggered, this, &SKGUnitPlugin::deleteUnusedUnits);
71 registerGlobalAction(QStringLiteral("clean_delete_unused_units"), act);
72 return true;
73 }
74
getNbDashboardWidgets()75 int SKGUnitPlugin::getNbDashboardWidgets()
76 {
77 return 2;
78 }
79
getDashboardWidgetTitle(int iIndex)80 QString SKGUnitPlugin::getDashboardWidgetTitle(int iIndex)
81 {
82 if (iIndex == 0) {
83 return i18nc("Noun, the title of a section", "Quotes");
84 }
85 return i18nc("Noun, the title of a section", "Stock portfolio");
86 }
87
getDashboardWidget(int iIndex)88 SKGBoardWidget* SKGUnitPlugin::getDashboardWidget(int iIndex)
89 {
90 if (iIndex == 0) {
91 return new SKGUnitBoardWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument);
92 }
93 // Get QML mode for dashboard
94 KConfigSkeleton* skl = SKGMainPanel::getMainPanel()->getPluginByName(QStringLiteral("Dashboard plugin"))->getPreferenceSkeleton();
95 KConfigSkeletonItem* sklItem = skl->findItem(QStringLiteral("qmlmode"));
96 bool qml = sklItem->property().toBool();
97
98 auto listForFilter = QStringList() << QStringLiteral("t_name")
99 << QStringLiteral("t_symbol")
100 << QStringLiteral("t_country")
101 << QStringLiteral("t_type")
102 << QStringLiteral("t_internet_code")
103 << QStringLiteral("t_source")
104 << QStringLiteral("t_bookmarked");
105
106 return new SKGHtmlBoardWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument,
107 getDashboardWidgetTitle(iIndex),
108 QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/html/default/portfolio.") % (qml ? QStringLiteral("qml") : QStringLiteral("html"))),
109 QStringList() << QStringLiteral("v_operation_display"),
110 SKGSimplePeriodEdit::NONE,
111 listForFilter);
112 }
113
refresh()114 void SKGUnitPlugin::refresh()
115 {
116 SKGTRACEINFUNC(10)
117 if ((SKGMainPanel::getMainPanel() != nullptr) && (m_currentBankDocument != nullptr)) {
118 // Automatic download
119 QString doc_id = m_currentBankDocument->getUniqueIdentifier();
120 if (m_docUniqueIdentifier != doc_id) {
121 m_docUniqueIdentifier = doc_id;
122 // Check if current unit is existing
123 bool exist = false;
124 SKGError err = m_currentBankDocument->existObjects(QStringLiteral("unit"), QLatin1String(""), exist);
125 IFOK(err) {
126 if (!exist) {
127 SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Create default unit"), err)
128 IFOK(err) {
129 // Create default unit
130 SKGUnitObject unit;
131 QString unitS = QLocale().currencySymbol(QLocale::CurrencyIsoCode);
132 if (!unitS.isEmpty()) {
133 err = SKGUnitObject::createCurrencyUnit(m_currentBankDocument, unitS, unit);
134 }
135
136 // The file is considered has not modified
137 m_currentBankDocument->setFileNotModified();
138 }
139 } else if (skgunit_settings::download_on_open()) {
140 // Check frequency
141 QString lastAutomaticDownload = m_currentBankDocument->getParameter(QStringLiteral("SKG_LAST_UNIT_AUTOMATIC_DOWNLOAD"));
142 if (lastAutomaticDownload.isEmpty()) {
143 lastAutomaticDownload = QStringLiteral("1970-01-01");
144 }
145 QDate lastAutomaticDownloadDate = QDate::fromString(lastAutomaticDownload, QStringLiteral("yyyy-MM-dd"));
146 if ((lastAutomaticDownloadDate.daysTo(QDate::currentDate()) >= 1 && skgunit_settings::download_frequency() == 0) ||
147 (lastAutomaticDownloadDate.daysTo(QDate::currentDate()) >= 7 && skgunit_settings::download_frequency() == 1) ||
148 (lastAutomaticDownloadDate.daysTo(QDate::currentDate()) >= 30 && skgunit_settings::download_frequency() == 2))
149
150 {
151 // Download all units
152 SKGObjectBase::SKGListSKGObjectBase selection;
153 err = m_currentBankDocument->getObjects(QStringLiteral("unit"), QLatin1String(""), selection);
154 int nb = selection.count();
155 SKGBEGINPROGRESSTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Automatic download of units"), err, nb)
156 for (int i = 0; !err && i < nb; ++i) {
157 SKGUnitObject unit(selection.at(i));
158 err = SKGUnitPluginWidget::downloadUnitValue(unit, SKGUnitPluginWidget::getDownloadModeFromSettings());
159
160 // Send message
161 IFOKDO(err, m_currentBankDocument->sendMessage(i18nc("An information to the user", "The unit '%1' has been downloaded", unit.getDisplayName()), SKGDocument::Hidden))
162
163 IFOKDO(err, m_currentBankDocument->stepForward(i + 1))
164 }
165
166 // Memorize the last download date
167 IFOKDO(err, m_currentBankDocument->setParameter(QStringLiteral("SKG_LAST_UNIT_AUTOMATIC_DOWNLOAD"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd"))))
168 }
169 }
170 }
171
172 // Display error
173 SKGMainPanel::displayErrorMessage(err);
174 }
175 }
176 }
177
getWidget()178 SKGTabPage* SKGUnitPlugin::getWidget()
179 {
180 SKGTRACEINFUNC(10)
181 return new SKGUnitPluginWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument);
182 }
183
getPreferenceWidget()184 QWidget* SKGUnitPlugin::getPreferenceWidget()
185 {
186 SKGTRACEINFUNC(10)
187 auto w = new QWidget();
188 ui.setupUi(w);
189
190 // Get sources from.desktop file
191 QStringList sources;
192 const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source"));
193 for (const auto& service : list2) {
194 auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString();
195 auto keyAPI = service->property(QStringLiteral("X-SKROOGE-keyAPI"), QVariant::Bool).toBool();
196 if (!sources.contains(name) && keyAPI) {
197 sources.push_back(name);
198 }
199 }
200 sources.sort();
201
202 auto nb = sources.count();
203 auto lwidgets = new QHash<QString, QLineEdit*>();
204 for (auto i = 0; i < nb; ++i) {
205 // Get Current value
206 auto ln = new QLineEdit(w);
207 ln->setText(m_currentBankDocument->getParameter("KEYAPI_" + sources[i]));
208 lwidgets->insert(sources.value(i), ln);
209
210 ui.kAPIKeyLayout->addWidget(new QLabel(sources[i] + ':', w), i, 0);
211 ui.kAPIKeyLayout->addWidget(ln, i, 1);
212 }
213
214 connect(ui.kcfg_download_on_open, &QCheckBox::toggled, ui.kcfg_download_frequency, &KComboBox::setEnabled);
215 connect(ui.kSave, &QPushButton::clicked, this, [ = ]() {
216 SKGError err;
217 {
218 SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Save API keys"), err)
219 foreach (auto k, lwidgets->keys()) {
220 m_currentBankDocument->setParameter("KEYAPI_" + k, lwidgets->value(k)->text());
221 }
222 }
223 // Display error
224 SKGMainPanel::displayErrorMessage(err);
225 });
226
227 return w;
228 }
229
getPreferenceSkeleton()230 KConfigSkeleton* SKGUnitPlugin::getPreferenceSkeleton()
231 {
232 return skgunit_settings::self();
233 }
234
title() const235 QString SKGUnitPlugin::title() const
236 {
237 return i18nc("Noun, units for operations, usually currencies or a shares", "Units");
238 }
239
icon() const240 QString SKGUnitPlugin::icon() const
241 {
242 return QStringLiteral("taxes-finances");
243 }
244
toolTip() const245 QString SKGUnitPlugin::toolTip() const
246 {
247 return i18nc("A tool tip", "Unit management");
248 }
249
tips() const250 QStringList SKGUnitPlugin::tips() const
251 {
252 QStringList output;
253 output.push_back(i18nc("Description of a tips", "<p>... you can download <a href=\"skg://skrooge_unit_plugin\">units</a>.</p>"));
254 output.push_back(i18nc("Description of a tips", "<p>... <a href=\"skg://skrooge_unit_plugin\">units</a> can be downloaded <a href=\"skg://tab_configure?page=Skrooge Unit Plugin\">automatically</a> when a document is opened.</p>"));
255 output.push_back(i18nc("Description of a tips", "<p>... you can split a <a href=\"skg://skrooge_unit_plugin\">share</a>.</p>"));
256 output.push_back(i18nc("Description of a tips", "<p>... <a href=\"skg://skrooge_unit_plugin\">units</a> can be merged by drag & drop.</p>"));
257 output.push_back(i18nc("Description of a tips", "<p>... you can download more <a href=\"skg://skrooge_unit_plugin\">sources</a> of quote.</p>"));
258 output.push_back(i18nc("Description of a tips", "<p>... you can create and share your own source of quote.</p>"));
259
260 return output;
261 }
262
getOrder() const263 int SKGUnitPlugin::getOrder() const
264 {
265 return 60;
266 }
267
isInPagesChooser() const268 bool SKGUnitPlugin::isInPagesChooser() const
269 {
270 return true;
271 }
272
onSplitShare()273 void SKGUnitPlugin::onSplitShare()
274 {
275 SKGError err;
276 SKGTRACEINFUNCRC(10, err)
277
278 // Get Selection
279 if (SKGMainPanel::getMainPanel() != nullptr) {
280 SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
281 int nb = selection.count();
282 if (nb == 1) {
283 bool ok = false;
284 double ratio = QInputDialog::getDouble(SKGMainPanel::getMainPanel(), i18nc("Question", "Split share"),
285 i18nc("Question", "Ratio (2 means 2-for-1, 0.5 means 1-for-2):"), 2.0,
286 0, std::numeric_limits<double>::max(), 8, &ok);
287 if (ok) {
288 SKGUnitObject unit(selection.at(0));
289 SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Split stock '%1' by '%2'", unit.getName(), ratio), err)
290 IFOKDO(err, unit.split(ratio))
291 }
292 }
293
294 // status
295 IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Stock split.")))
296 else {
297 err.addError(ERR_FAIL, i18nc("Error message", "Splitting stock failed."));
298 }
299
300 // Display error
301 SKGMainPanel::displayErrorMessage(err);
302 }
303 }
304
advice(const QStringList & iIgnoredAdvice)305 SKGAdviceList SKGUnitPlugin::advice(const QStringList& iIgnoredAdvice)
306 {
307 SKGTRACEINFUNC(10)
308 SKGAdviceList output;
309 output.reserve(20);
310
311 // Get all currencies
312 SKGStringListList result;
313 m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT (SELECT count(1) FROM operation WHERE operation.rc_unit_id=unit.id), unit.t_name FROM unit WHERE t_type='C' GROUP BY t_name ORDER BY count(1) DESC"), result);
314 int nb = result.count();
315
316 // Check primary unit
317 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_primaryunit"))) {
318 if (m_currentBankDocument->getPrimaryUnit().Name.isEmpty() && nb > 1) {
319 // Get unit
320 QString unit = result.at(1).at(1);
321
322 SKGAdvice ad;
323 ad.setUUID("skgunitplugin_primaryunit|" % unit);
324 ad.setPriority(8);
325 ad.setShortMessage(i18nc("Advice on making the best (short)", "Define a primary currency"));
326 ad.setLongMessage(i18nc("Advice on making the best (long)", "To avoid misunderstanding and conflicts between units at conversion time, you should define a primary currency. It is the currency against which all other will be converted"));
327 SKGAdvice::SKGAdviceActionList autoCorrections;
328 {
329 SKGAdvice::SKGAdviceAction a;
330 a.Title = i18nc("Advice on making the best (action)", "Set '%1' as primary currency", unit);
331 a.IconName = icon();
332 a.IsRecommended = true;
333 autoCorrections.push_back(a);
334 }
335 {
336 SKGAdvice::SKGAdviceAction a;
337 a.Title = i18nc("Advice on making the best (action)", "Edit units");
338 a.IconName = icon();
339 a.IsRecommended = false;
340 autoCorrections.push_back(a);
341 }
342 ad.setAutoCorrections(autoCorrections);
343 output.push_back(ad);
344
345 --nb;
346 }
347 }
348
349 // Check secondary unit
350 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_secondaryunit"))) {
351 if (m_currentBankDocument->getSecondaryUnit().Name.isEmpty() && nb > 1) {
352 // Get unit
353 QString unit = result.at(1).at(1);
354
355 SKGAdvice ad;
356 ad.setUUID("skgunitplugin_secondaryunit|" % unit);
357 ad.setPriority(2);
358 ad.setShortMessage(i18nc("Advice on making the best (short)", "Define a secondary currency"));
359 ad.setLongMessage(i18nc("Advice on making the best (long)", "When a secondary unit is defined, Skrooge will display it as an additional amount information."));
360 SKGAdvice::SKGAdviceActionList autoCorrections;
361 {
362 SKGAdvice::SKGAdviceAction a;
363 a.Title = i18nc("Advice on making the best (action)", "Set '%1' as secondary currency", unit);
364 a.IconName = icon();
365 a.IsRecommended = true;
366 autoCorrections.push_back(a);
367 }
368 {
369 SKGAdvice::SKGAdviceAction a;
370 a.Title = i18nc("Advice on making the best (action)", "Edit units");
371 a.IconName = icon();
372 a.IsRecommended = false;
373 autoCorrections.push_back(a);
374 }
375 ad.setAutoCorrections(autoCorrections);
376 output.push_back(ad);
377 }
378 }
379
380 // Shares not downloaded
381 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_notdownloaded"))) {
382 m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT t_name, t_internet_code from unit WHERE t_internet_code<>'' AND (julianday('now', 'localtime')-(SELECT MAX(julianday(d_date)) FROM unitvalue WHERE rd_unit_id=unit.id ))>30 OR NOT EXISTS (SELECT 1 FROM unitvalue WHERE unitvalue.rd_unit_id=unit.id)"), result);
383 nb = result.count();
384 SKGAdvice::SKGAdviceActionList autoCorrections;
385 autoCorrections.reserve(nb);
386 for (int i = 1; i < nb; ++i) { // Ignore header
387 // Get parameters
388 const QStringList& line = result.at(i);
389 const QString& unit = line.at(0);
390 const QString& internet_code = line.at(1);
391
392 SKGAdvice ad;
393 ad.setUUID("skgunitplugin_notdownloaded|" % unit);
394 ad.setPriority(5);
395 ad.setShortMessage(i18nc("Advice on making the best (short)", "Unit '%1' has not been downloaded for more than a month", unit));
396 ad.setLongMessage(i18nc("Advice on making the best (long)", "Do not forget download units to have a better view of your accounts"));
397 autoCorrections.resize(0);
398 {
399 SKGAdvice::SKGAdviceAction a;
400 a.Title = i18nc("Advice on making the best (action)", "Edit units");
401 a.IconName = icon();
402 a.IsRecommended = false;
403 autoCorrections.push_back(a);
404 }
405 if (!internet_code.isEmpty()) {
406 SKGAdvice::SKGAdviceAction a;
407 a.Title = i18nc("Advice on making the best (action)", "Download '%1'", unit);
408 a.IconName = QStringLiteral("download");
409 a.IsRecommended = true;
410 autoCorrections.push_back(a);
411 }
412 ad.setAutoCorrections(autoCorrections);
413 output.push_back(ad);
414 }
415 }
416
417 // Check unused units
418 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_unused"))) {
419 bool exist = false;
420 m_currentBankDocument->existObjects(QStringLiteral("unit"), QStringLiteral("t_type NOT IN ('I', '1', '2') AND NOT EXISTS (SELECT 1 FROM operation WHERE operation.rc_unit_id=unit.id) AND NOT EXISTS (SELECT 1 FROM unit as unit2 WHERE unit2.rd_unit_id=unit.id)"), exist);
421 if (exist) {
422 SKGAdvice ad;
423 ad.setUUID(QStringLiteral("skgunitplugin_unused"));
424 ad.setPriority(5);
425 ad.setShortMessage(i18nc("Advice on making the best (short)", "Many unused units"));
426 ad.setLongMessage(i18nc("Advice on making the best (long)", "You can improve performances by removing units for which no operation is registered."));
427 QStringList autoCorrections;
428 autoCorrections.push_back(QStringLiteral("skg://clean_delete_unused_units"));
429 ad.setAutoCorrections(autoCorrections);
430 output.push_back(ad);
431 }
432 }
433
434 // Check unit too complex
435 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_amountnotdefined"))) {
436 m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT t_name FROM v_unit WHERE t_type IN ('2','C') AND f_CURRENTAMOUNT=1"), result);
437 nb = result.count();
438 SKGAdvice::SKGAdviceActionList autoCorrections;
439 autoCorrections.reserve(nb);
440 for (int i = 1; i < nb; ++i) { // Ignore header
441 // Get parameters
442 const QStringList& line = result.at(i);
443 const QString& unit = line.at(0);
444
445 SKGAdvice ad;
446 ad.setUUID("skgunitplugin_amountnotdefined|" % unit);
447 ad.setPriority(9);
448 ad.setShortMessage(i18nc("Advice on making the best (short)", "The amount of the unit '%1' is not defined", unit));
449 ad.setLongMessage(i18nc("Advice on making the best (long)", "'%1' has an amount defined at 1. Most of the time this is not normal and causes wrong computation. Check if this is normal.", unit));
450 autoCorrections.resize(0);
451 {
452 SKGAdvice::SKGAdviceAction a;
453 a.Title = i18nc("Advice on making the best (action)", "Edit units");
454 a.IconName = icon();
455 a.IsRecommended = false;
456 autoCorrections.push_back(a);
457 }
458 ad.setAutoCorrections(autoCorrections);
459 output.push_back(ad);
460 }
461 }
462
463 // Check unit too complex
464 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_toocomplex"))) {
465 m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT A.t_name FROM unit A, unit B, unit C, unit D WHERE A.rd_unit_id=B.id AND B.rd_unit_id=C.id AND C.rd_unit_id=D.id"), result);
466 nb = result.count();
467 SKGAdvice::SKGAdviceActionList autoCorrections;
468 autoCorrections.reserve(nb);
469 for (int i = 1; i < nb; ++i) { // Ignore header
470 // Get parameters
471 const QStringList& line = result.at(i);
472 const QString& unit = line.at(0);
473
474 SKGAdvice ad;
475 ad.setUUID(QStringLiteral("skgunitplugin_toocomplex"));
476 ad.setPriority(9);
477 ad.setShortMessage(i18nc("Advice on making the best (short)", "The definition of the unit '%1' is too complex", unit));
478 ad.setLongMessage(i18nc("Advice on making the best (long)", "'%1' is defined relatively to another unit defined relatively to a third one. This is too complex and not supported by Skrooge.", unit));
479 autoCorrections.resize(0);
480 {
481 SKGAdvice::SKGAdviceAction a;
482 a.Title = i18nc("Advice on making the best (action)", "Edit units");
483 a.IconName = icon();
484 a.IsRecommended = false;
485 autoCorrections.push_back(a);
486 }
487 ad.setAutoCorrections(autoCorrections);
488 output.push_back(ad);
489 }
490 }
491
492 // Unit with very old values
493 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_veryold"))) {
494 m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT t_name from unit WHERE (SELECT COUNT(*) FROM unitvalue WHERE unitvalue.rd_unit_id=unit.id)>1 AND EXISTS (SELECT 1 FROM unitvalue WHERE unitvalue.rd_unit_id=unit.id AND unitvalue.d_date<=(SELECT date('now', 'localtime', '-50 year')))"), result);
495 nb = result.count();
496 SKGAdvice::SKGAdviceActionList autoCorrections;
497 autoCorrections.reserve(nb);
498 for (int i = 1; i < nb; ++i) { // Ignore header
499 // Get parameters
500 const QStringList& line = result.at(i);
501 const QString& unit = line.at(0);
502
503 SKGAdvice ad;
504 ad.setUUID("skgunitplugin_veryold|" % unit);
505 ad.setPriority(3);
506 ad.setShortMessage(i18nc("Advice on making the best (short)", "Unit '%1' has very old values", unit));
507 ad.setLongMessage(i18nc("Advice on making the best (long)", "Unit '%1' has very old values. Check if this is normal.", unit));
508 autoCorrections.resize(0);
509 {
510 SKGAdvice::SKGAdviceAction a;
511 a.Title = i18nc("Advice on making the best (action)", "Edit units");
512 a.IconName = icon();
513 a.IsRecommended = false;
514 autoCorrections.push_back(a);
515 }
516 ad.setAutoCorrections(autoCorrections);
517 output.push_back(ad);
518 }
519 }
520
521 // No decimal settings
522 if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_decimalsymbol")) && QLocale().decimalPoint().isNull()) {
523 SKGAdvice ad;
524 ad.setUUID(QStringLiteral("skgunitplugin_decimalsymbol"));
525 ad.setPriority(9);
526 ad.setShortMessage(i18nc("Advice on making the best (short)", "No decimal symbol defined"));
527 ad.setLongMessage(i18nc("Advice on making the best (long)", "In KDE localization settings, there is no decimal symbol defined for currencies. This could be confusing."));
528 SKGAdvice::SKGAdviceActionList autoCorrections;
529 {
530 SKGAdvice::SKGAdviceAction a;
531 a.Title = i18nc("Advice on making the best (action)", "Edit KDE settings");
532 a.IconName = QStringLiteral("configure");
533 a.IsRecommended = false;
534 autoCorrections.push_back(a);
535 }
536 ad.setAutoCorrections(autoCorrections);
537 output.push_back(ad);
538 }
539
540 return output;
541 }
542
executeAdviceCorrection(const QString & iAdviceIdentifier,int iSolution)543 SKGError SKGUnitPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution)
544 {
545 if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_primaryunit|"))) {
546 if (iSolution == 1) {
547 SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin"));
548 } else {
549 // Get parameters
550 QString unit = iAdviceIdentifier.right(iAdviceIdentifier.length() - 26);
551
552 SKGError err;
553 {
554 SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Define primary currency"), err)
555 SKGUnitObject unitObj(m_currentBankDocument);
556 err = unitObj.setName(unit);
557 IFOKDO(err, unitObj.load())
558 IFOKDO(err, unitObj.setType(SKGUnitObject::PRIMARY))
559 IFOKDO(err, unitObj.save())
560
561 // Send message
562 IFOKDO(err, unitObj.getDocument()->sendMessage(i18nc("An information to the user", "The unit '%1' is now the primary unit", unitObj.getDisplayName()), SKGDocument::Hidden))
563 }
564
565 // status bar
566 IFOKDO(err, SKGError(0, i18nc("Message for successful user action", "Primary currency defined.")))
567 else {
568 err.addError(ERR_FAIL, i18nc("Error message", "Primary currency definition failed"));
569 }
570
571 // Display error
572 SKGMainPanel::displayErrorMessage(err);
573 }
574
575 return SKGError();
576 }
577 if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_secondaryunit|"))) {
578 if (iSolution == 1) {
579 SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin"));
580 } else {
581 // Get parameters
582 QString unit = iAdviceIdentifier.right(iAdviceIdentifier.length() - 28);
583
584 SKGError err;
585 {
586 SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Define secondary currency"), err)
587 SKGUnitObject unitObj(m_currentBankDocument);
588 err = unitObj.setName(unit);
589 IFOKDO(err, unitObj.load())
590 IFOKDO(err, unitObj.setType(SKGUnitObject::SECONDARY))
591 IFOKDO(err, unitObj.save())
592
593 // Send message
594 IFOKDO(err, unitObj.getDocument()->sendMessage(i18nc("An information to the user", "The unit '%1' is now the secondary unit", unitObj.getDisplayName()), SKGDocument::Hidden))
595 }
596
597 // status bar
598 IFOKDO(err, SKGError(0, i18nc("Message for successful user action", "Secondary currency defined.")))
599 else {
600 err.addError(ERR_FAIL, i18nc("Error message", "Secondary currency definition failed"));
601 }
602
603 // Display error
604 SKGMainPanel::displayErrorMessage(err);
605 }
606
607 return SKGError();
608 }
609 if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_notdownloaded|"))) {
610 if (iSolution == 0) {
611 SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin"));
612 } else {
613 // Get parameters
614 QString unit = iAdviceIdentifier.right(iAdviceIdentifier.length() - 28);
615
616 SKGError err;
617 SKGUnitObject unitObj(m_currentBankDocument);
618 err = unitObj.setName(unit);
619 IFOKDO(err, unitObj.load())
620 IFOKDO(err, SKGUnitPluginWidget::downloadUnitValue(unitObj, SKGUnitPluginWidget::getDownloadModeFromSettings()))
621
622 // Display error
623 SKGMainPanel::displayErrorMessage(err);
624 }
625
626 return SKGError();
627 }
628 if ((m_currentBankDocument != nullptr) && (iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_veryold|")) ||
629 iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_toocomplex")) ||
630 iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_amountnotdefined|")))
631 ) {
632 SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin"));
633 return SKGError();
634 }
635 if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_decimalsymbol"))) {
636 QProcess::execute(QStringLiteral("kcmshell5"), QStringList() << QStringLiteral("formats"));
637 return SKGError();
638 }
639 return SKGInterfacePlugin::executeAdviceCorrection(iAdviceIdentifier, iSolution);
640 }
641
deleteUnusedUnits() const642 void SKGUnitPlugin::deleteUnusedUnits() const
643 {
644 SKGError err;
645 _SKGTRACEINFUNCRC(10, err)
646 if (m_currentBankDocument != nullptr) {
647 SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Delete unused units"), err)
648
649 // Modification of payee object
650 QString sql = QStringLiteral("DELETE FROM unit WHERE t_type NOT IN ('I', '1', '2') AND NOT EXISTS (SELECT 1 FROM operation WHERE operation.rc_unit_id=unit.id) AND NOT EXISTS (SELECT 1 FROM unit as unit2 WHERE unit2.rd_unit_id=unit.id)");
651 err = m_currentBankDocument->executeSqliteOrder(sql);
652 }
653
654 // status bar
655 IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Unused units deleted")))
656 else {
657 err.addError(ERR_FAIL, i18nc("Error message", "Unused units deletion failed"));
658 }
659
660 // Display error
661 SKGMainPanel::displayErrorMessage(err);
662 }
663
664 #include <skgunitplugin.moc>
665