File indexing completed on 2024-05-26 05:10:42
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 * This file is Skrooge plugin for transaction management. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgoperationpluginwidget.h" 0012 0013 #include <kcolorscheme.h> 0014 #include <kstandardaction.h> 0015 0016 #include <qcompleter.h> 0017 #include <qdir.h> 0018 #include <qdom.h> 0019 #include <qfile.h> 0020 #include <qheaderview.h> 0021 #include <qinputdialog.h> 0022 #include <qmap.h> 0023 #include <qscriptengine.h> 0024 #include <qstandardpaths.h> 0025 #include <qstringlistmodel.h> 0026 #include <qtablewidget.h> 0027 0028 #include "skgbankincludes.h" 0029 #include "skgcalculatoredit.h" 0030 #include "skgmainpanel.h" 0031 #include "skgobjectbase.h" 0032 #include "skgobjectmodel.h" 0033 #include "skgoperation_settings.h" 0034 #include "skgpayeeobject.h" 0035 #include "skgservices.h" 0036 #include "skgshow.h" 0037 #include "skgsplittabledelegate.h" 0038 #include "skgtraces.h" 0039 #include "skgtreeview.h" 0040 0041 SKGOperationPluginWidget::SKGOperationPluginWidget(QWidget* iParent, SKGDocumentBank* iDocument) 0042 : SKGTabPage(iParent, iDocument), m_objectModel(nullptr), m_fastEditionAction(nullptr), m_lastFastEditionOperationFound(0), m_showClosedAccounts(false), 0043 m_numberFieldIsNotUptodate(true), m_modeInfoZone(0), m_tableDelegate(nullptr) 0044 { 0045 SKGTRACEINFUNC(1) 0046 if (iDocument == nullptr) { 0047 return; 0048 } 0049 0050 m_timer.setSingleShot(true); 0051 connect(&m_timer, &QTimer::timeout, this, &SKGOperationPluginWidget::onRefreshInformationZone, Qt::QueuedConnection); 0052 0053 ui.setupUi(this); 0054 0055 ui.kAccountLabel2->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_ACCOUNT")))); 0056 ui.kDateLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("d_date")))); 0057 ui.kAmountLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("f_CURRENTAMOUNT")))); 0058 ui.kPayeeLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_payee")))); 0059 ui.kTypeLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_mode")))); 0060 ui.kNumberEdit->setPlaceholderText(iDocument->getDisplay(QStringLiteral("t_number"))); 0061 ui.kCategoryLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_CATEGORY")))); 0062 ui.kCommentLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_comment")))); 0063 ui.kTrackerLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_REFUND")))); 0064 0065 ui.kUnitEdit->setDocument(iDocument); 0066 ui.kUnitShare->setDocument(iDocument); 0067 0068 0069 ui.kTitle->hide(); 0070 ui.kReconciliatorFrame2->hide(); 0071 ui.kReconciliateAccount->hide(); 0072 0073 m_attributesForSplit << QStringLiteral("d_date") << QStringLiteral("t_category") << QStringLiteral("f_value") << QStringLiteral("t_comment") << QStringLiteral("t_refund"); 0074 int nb = m_attributesForSplit.count(); 0075 ui.kSubOperationsTable->setColumnCount(nb); 0076 for (int i = 0; i < nb; ++i) { 0077 QString att = m_attributesForSplit.at(i); 0078 auto item = new QTableWidgetItem(iDocument->getIcon(att), iDocument->getDisplay(att)); 0079 ui.kSubOperationsTable->setHorizontalHeaderItem(i, item); 0080 } 0081 0082 { 0083 // Bind transaction view 0084 m_objectModel = new SKGObjectModel(qobject_cast<SKGDocumentBank*>(getDocument()), QStringLiteral("v_operation_display_all"), QStringLiteral("1=0"), this, QLatin1String(""), false); 0085 ui.kOperationView->setModel(m_objectModel); 0086 0087 // Add registered global action in contextual menu 0088 if (SKGMainPanel::getMainPanel() != nullptr) { 0089 m_fastEditionAction = SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("fast_edition")); 0090 } 0091 0092 connect(ui.kOperationView->getView(), &SKGTreeView::clickEmptyArea, this, &SKGOperationPluginWidget::cleanEditor); 0093 connect(ui.kOperationView->getView(), &SKGTreeView::doubleClicked, this, &SKGOperationPluginWidget::onDoubleClick); 0094 connect(ui.kOperationView->getView(), &SKGTreeView::selectionChangedDelayed, this, [ = ] {this->onSelectionChanged();}); 0095 } 0096 0097 // Add Standard KDE Icons to buttons to Transactions 0098 ui.kModifyOperationBtn->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-ok"))); 0099 ui.kAddOperationBtn->setIcon(SKGServices::fromTheme(QStringLiteral("list-add"))); 0100 ui.kCleanBtn->setIcon(SKGServices::fromTheme(QStringLiteral("edit-clear"))); 0101 ui.kReconciliatorButton->setIcon(SKGServices::fromTheme(QStringLiteral("view-refresh"))); 0102 ui.kValidate->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-ok"))); 0103 ui.kValidate->setIconSize(QSize(48, 48)); 0104 ui.kAutoPoint->setIcon(SKGServices::fromTheme(QStringLiteral("games-solve"))); 0105 ui.kCreateFakeOperation->setIcon(SKGServices::fromTheme(QStringLiteral("list-add"))); 0106 ui.kFastEditBtn->setIcon(SKGServices::fromTheme(QStringLiteral("games-solve"))); 0107 0108 { 0109 SKGWidgetSelector::SKGListQWidget list; 0110 list.push_back(ui.SKGBasicSection); 0111 list.push_back(ui.SKGPayeeModeSection); 0112 list.push_back(ui.SKGSmallButtons); 0113 list.push_back(ui.SKGEditionButtonsWidget); 0114 list.push_back(ui.SKGSingleOpSection); 0115 ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("dialog-ok")), i18n("Standard"), i18n("Display the edit panel for standard transactions"), list); 0116 } 0117 0118 { 0119 SKGWidgetSelector::SKGListQWidget list; 0120 list.push_back(ui.SKGBasicSection); 0121 list.push_back(ui.SKGPayeeModeSection); 0122 list.push_back(ui.SKGSmallButtons); 0123 list.push_back(ui.SKGEditionButtonsWidget); 0124 list.push_back(ui.SKGSplitOpSection); 0125 ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("split")), i18n("Split"), i18n("Display the edit panel for split transactions"), list); 0126 } 0127 { 0128 SKGWidgetSelector::SKGListQWidget list; 0129 list.push_back(ui.SKGBasicSection); 0130 list.push_back(ui.SKGPayeeModeSection); 0131 list.push_back(ui.SKGSmallButtons); 0132 list.push_back(ui.SKGEditionButtonsWidget); 0133 list.push_back(ui.SKGSingleOpSection); 0134 list.push_back(ui.kTargetAccountEdit); 0135 list.push_back(ui.kTargetAccountLabel); 0136 ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("exchange-positions")), i18n("Transfer"), i18n("Display the edit panel for transfers between accounts"), list); 0137 } 0138 { 0139 SKGWidgetSelector::SKGListQWidget list; 0140 list.push_back(ui.SKGBasicSection); 0141 list.push_back(ui.SKGPayeeModeSection); 0142 list.push_back(ui.SKGSmallButtons); 0143 list.push_back(ui.SKGEditionButtonsWidget); 0144 list.push_back(ui.SKGSharesSection); 0145 ui.kWidgetSelector->addButton(SKGServices::fromTheme(QStringLiteral("view-bank-account-savings")), i18n("Shares"), i18n("Display the edit panel for purchasing or selling shares"), list); 0146 } 0147 connect(ui.kWidgetSelector, &SKGWidgetSelector::selectedModeChanged, this, &SKGOperationPluginWidget::onBtnModeClicked); 0148 0149 ui.kFreezeBtn->setIcon(SKGServices::fromTheme(QStringLiteral("emblem-locked"))); 0150 0151 // Fast edition 0152 connect(qApp, &QApplication::focusChanged, this, &SKGOperationPluginWidget::onFocusChanged); 0153 connect(m_fastEditionAction, &QAction::triggered, this, &SKGOperationPluginWidget::onFastEdition); 0154 0155 // SubOperations 0156 connect(ui.kAmountEdit, &SKGCalculatorEdit::textChanged, this, &SKGOperationPluginWidget::onQuantityChanged); 0157 connect(ui.kDateEdit, &SKGDateEdit::dateChanged, this, &SKGOperationPluginWidget::onDateChanged); 0158 connect(ui.kSubOperationsTable, &SKGTableWidget::cellChanged, this, &SKGOperationPluginWidget::onSubopCellChanged); 0159 connect(ui.kSubOperationsTable->verticalHeader(), &QHeaderView::sectionClicked, this, &SKGOperationPluginWidget::onRemoveSubOperation); 0160 0161 ui.kSubOperationsTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); 0162 ui.kSubOperationsTable->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); 0163 ui.kSubOperationsTable->setWordWrap(false); 0164 m_tableDelegate = new SKGSplitTableDelegate(ui.kSubOperationsTable, getDocument(), m_attributesForSplit); 0165 m_tableDelegate->addParameterValue(QStringLiteral("total"), '0'); 0166 ui.kSubOperationsTable->setItemDelegate(m_tableDelegate); 0167 ui.kSubOperationsTable->setTextElideMode(Qt::ElideMiddle); 0168 connect(ui.kSubOperationsTable, &SKGTableWidget::removeLine, this, &SKGOperationPluginWidget::onRemoveSubOperation); 0169 0170 ui.kTargetAccountEdit->hide(); 0171 ui.kTargetAccountLabel->hide(); 0172 ui.SKGSplitOpSection->hide(); 0173 ui.SKGSharesSection->hide(); 0174 0175 ui.kWidgetSelector->setSelectedMode(0); 0176 0177 // Set Event filters to catch CTRL+ENTER or SHIFT+ENTER 0178 mainWidget()->installEventFilter(this); 0179 this->installEventFilter(this); 0180 0181 // Set Event filters for locking widgets 0182 ui.kTypeEdit->lineEdit()->installEventFilter(this); 0183 ui.kTypeEdit->installEventFilter(this); 0184 ui.kUnitEdit->lineEdit()->installEventFilter(this); 0185 ui.kUnitEdit->installEventFilter(this); 0186 ui.kCategoryEdit->lineEdit()->installEventFilter(this); 0187 ui.kCategoryEdit->installEventFilter(this); 0188 ui.kCommentEdit->lineEdit()->installEventFilter(this); 0189 ui.kCommentEdit->installEventFilter(this); 0190 ui.kPayeeEdit->lineEdit()->installEventFilter(this); 0191 ui.kPayeeEdit->installEventFilter(this); 0192 ui.kTrackerEdit->lineEdit()->installEventFilter(this); 0193 ui.kTrackerEdit->installEventFilter(this); 0194 ui.kAccountEdit->installEventFilter(this); 0195 ui.kTargetAccountLabel->installEventFilter(this); 0196 ui.kAmountEdit->installEventFilter(this); 0197 ui.kNumberEdit->installEventFilter(this); 0198 0199 connect(getDocument(), &SKGDocument::tableModified, this, &SKGOperationPluginWidget::dataModified, Qt::QueuedConnection); 0200 0201 connect(ui.kUnitEdit, &SKGUnitComboBox::editTextChanged, this, &SKGOperationPluginWidget::refreshSubOperationAmount, Qt::QueuedConnection); 0202 connect(ui.kUnitEdit, &SKGUnitComboBox::editTextChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 0203 connect(ui.kUnitShare, static_cast<void (SKGUnitComboBox::*)(int)>(&SKGUnitComboBox::currentIndexChanged), this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 0204 connect(ui.kAmountEdit, &SKGCalculatorEdit::textChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 0205 connect(ui.kAmountSharesEdit, &SKGCalculatorEdit::textChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 0206 connect(ui.kCommissionEdit, &SKGCalculatorEdit::textChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 0207 connect(ui.kTaxEdit, &SKGCalculatorEdit::textChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 0208 connect(ui.kAccountEdit, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::currentTextChanged), this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 0209 connect(ui.kOperationView->getShowWidget(), &SKGShow::stateChanged, this, &SKGOperationPluginWidget::onFilterChanged, Qt::QueuedConnection); 0210 connect(ui.kPayeeEdit->lineEdit(), &QLineEdit::returnPressed, this, &SKGOperationPluginWidget::onPayeeChanged, Qt::QueuedConnection); 0211 0212 connect(ui.kReconcilitorAmountEdit, &SKGCalculatorEdit::textChanged, this, &SKGOperationPluginWidget::onRefreshInformationZone); 0213 connect(ui.kAddOperationBtn, &QPushButton::clicked, this, &SKGOperationPluginWidget::onAddOperationClicked); 0214 connect(ui.kModifyOperationBtn, &QPushButton::clicked, this, &SKGOperationPluginWidget::onUpdateOperationClicked); 0215 connect(ui.kReconciliatorButton, &QToolButton::clicked, this, &SKGOperationPluginWidget::onRotateAccountTools); 0216 connect(ui.kValidate, &QToolButton::clicked, this, &SKGOperationPluginWidget::onValidateMarkedOperations); 0217 connect(ui.kCleanBtn, &QPushButton::clicked, this, &SKGOperationPluginWidget::cleanEditor); 0218 connect(ui.kSubOperationsTable, &SKGTableWidget::itemSelectionChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified); 0219 connect(ui.kAutoPoint, &QToolButton::clicked, this, &SKGOperationPluginWidget::onAutoPoint); 0220 connect(ui.kFreezeBtn, &QToolButton::clicked, this, &SKGOperationPluginWidget::onFreeze); 0221 connect(ui.kCreateFakeOperation, &QToolButton::clicked, this, &SKGOperationPluginWidget::onAddFakeOperation); 0222 connect(ui.kFastEditBtn, &QPushButton::clicked, this, &SKGOperationPluginWidget::onFastEdition); 0223 0224 dataModified(QLatin1String(""), 0); 0225 onOperationCreatorModified(); 0226 0227 setAllWidgetsEnabled(); 0228 } 0229 0230 SKGOperationPluginWidget::~SKGOperationPluginWidget() 0231 { 0232 SKGTRACEINFUNC(1) 0233 m_objectModel = nullptr; 0234 m_fastEditionAction = nullptr; 0235 } 0236 0237 QString SKGOperationPluginWidget::currentAccount() 0238 { 0239 QStringList accounts = SKGServices::splitCSVLine(ui.kOperationView->getShowWidget()->getState()); 0240 for (const auto& item : qAsConst(accounts)) { 0241 if (item.startsWith(QLatin1String("##_"))) { 0242 return item.right(item.length() - 3); 0243 } 0244 } 0245 return QLatin1String(""); 0246 } 0247 0248 bool SKGOperationPluginWidget::isWidgetEditionEnabled(QWidget* iWidget) 0249 { 0250 return ((iWidget != nullptr) && (!iWidget->property("frozen").isValid() || !iWidget->property("frozen").toBool())); 0251 } 0252 0253 void SKGOperationPluginWidget::setWidgetEditionEnabled(QWidget* iWidget, bool iEnabled) 0254 { 0255 if ((iWidget != nullptr) && isWidgetEditionEnabled(iWidget) != iEnabled) { 0256 if (iEnabled) { 0257 iWidget->setStyleSheet(QStringLiteral("background-image:none;")); 0258 iWidget->setProperty("frozen", false); 0259 } else { 0260 auto color = KColorScheme(QPalette::Normal).background(KColorScheme::ActiveBackground).color().name().right(6); 0261 iWidget->setStyleSheet("background-color:#" % color); 0262 iWidget->setProperty("frozen", true); 0263 } 0264 0265 QString addOn = i18nc("A tool tip", "This field is frozen (it will not be affected by Fast Edition). Double click to unfreeze it"); 0266 QString t = iWidget->toolTip().remove('\n' % addOn).remove(addOn); 0267 if (!iEnabled) { 0268 t = iWidget->toolTip(); 0269 if (!t.isEmpty()) { 0270 t += '\n'; 0271 } 0272 t += addOn; 0273 } 0274 iWidget->setToolTip(t); 0275 0276 // 348619: Freeze the unit when amount is frozen 0277 if (iWidget == ui.kAmountEdit) { 0278 setWidgetEditionEnabled(ui.kUnitEdit->lineEdit(), iEnabled); 0279 } 0280 } 0281 } 0282 0283 bool SKGOperationPluginWidget::eventFilter(QObject* iObject, QEvent* iEvent) 0284 { 0285 if ((iEvent != nullptr) && iEvent->type() == QEvent::MouseButtonDblClick) { 0286 auto* line = qobject_cast<QLineEdit*>(iObject); 0287 if (line != nullptr) { 0288 setWidgetEditionEnabled(line, !isWidgetEditionEnabled(line)); 0289 } 0290 } else if ((iEvent != nullptr) && iEvent->type() == QEvent::FocusIn) { 0291 auto* line = qobject_cast<QLineEdit*>(iObject); 0292 if (line != nullptr) { 0293 m_previousValue = line->text(); 0294 } else { 0295 auto* cmb = qobject_cast<SKGComboBox*>(iObject); 0296 if (cmb != nullptr) { 0297 m_previousValue = cmb->text(); 0298 } 0299 } 0300 } else if ((iEvent != nullptr) && iEvent->type() == QEvent::FocusOut) { 0301 auto* line = qobject_cast<QLineEdit*>(iObject); 0302 if (line != nullptr) { 0303 if (m_previousValue != line->text() && !line->text().isEmpty()) { 0304 setWidgetEditionEnabled(line, false); 0305 } 0306 } else { 0307 auto* cmb = qobject_cast<SKGComboBox*>(iObject); 0308 if (cmb != nullptr) { 0309 if (m_previousValue != cmb->text() && !cmb->text().isEmpty()) { 0310 setWidgetEditionEnabled(cmb->lineEdit(), false); 0311 } 0312 } 0313 } 0314 } else if ((iEvent != nullptr) && iEvent->type() == QEvent::KeyPress) { 0315 auto* keyEvent = dynamic_cast<QKeyEvent*>(iEvent); 0316 if (keyEvent && (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && iObject == this) { 0317 if ((QApplication::keyboardModifiers() & Qt::ControlModifier) != 0u && ui.kAddOperationBtn->isEnabled()) { 0318 ui.kAddOperationBtn->click(); 0319 } else if ((QApplication::keyboardModifiers() &Qt::ShiftModifier) != 0u && ui.kModifyOperationBtn->isEnabled()) { 0320 ui.kModifyOperationBtn->click(); 0321 } 0322 } else if (keyEvent && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) && iObject == ui.kNumberEdit) { 0323 int c = SKGServices::stringToInt(ui.kNumberEdit->text()); 0324 if (c != 0) { 0325 ui.kNumberEdit->setText(SKGServices::intToString(keyEvent->key() == Qt::Key_Up ? c + 1 : c - 1)); 0326 } 0327 } 0328 } 0329 0330 return SKGTabPage::eventFilter(iObject, iEvent); 0331 } 0332 0333 void SKGOperationPluginWidget::onFreeze() 0334 { 0335 if (!ui.kFreezeBtn->isChecked()) { 0336 ui.kFreezeBtn->setIcon(SKGServices::fromTheme(QStringLiteral("emblem-locked"))); 0337 // At least one fiels is already frozen ==> unfreeze 0338 setAllWidgetsEnabled(); 0339 } else { 0340 QStringList overlay; 0341 overlay.push_back(QStringLiteral("edit-delete")); 0342 ui.kFreezeBtn->setIcon(SKGServices::fromTheme(QStringLiteral("emblem-locked"), overlay)); 0343 // No wildget frozen ==> freeze widget containing test 0344 if (!ui.kTypeEdit->text().isEmpty()) { 0345 setWidgetEditionEnabled(ui.kTypeEdit->lineEdit(), false); 0346 } 0347 if (!ui.kUnitEdit->text().isEmpty()) { 0348 setWidgetEditionEnabled(ui.kUnitEdit->lineEdit(), false); 0349 } 0350 if (!ui.kCategoryEdit->text().isEmpty()) { 0351 setWidgetEditionEnabled(ui.kCategoryEdit->lineEdit(), false); 0352 } 0353 if (!ui.kCommentEdit->text().isEmpty()) { 0354 setWidgetEditionEnabled(ui.kCommentEdit->lineEdit(), false); 0355 } 0356 if (!ui.kPayeeEdit->text().isEmpty()) { 0357 setWidgetEditionEnabled(ui.kPayeeEdit->lineEdit(), false); 0358 } 0359 if (!ui.kTrackerEdit->text().isEmpty()) { 0360 setWidgetEditionEnabled(ui.kTrackerEdit->lineEdit(), false); 0361 } 0362 // if(!ui.kAccountEdit->text().isEmpty()) setWidgetEditionEnabled(ui.kAccountEdit, false); 0363 if (!ui.kAmountEdit->text().isEmpty()) { 0364 setWidgetEditionEnabled(ui.kAmountEdit, false); 0365 } 0366 if (!ui.kNumberEdit->text().isEmpty()) { 0367 setWidgetEditionEnabled(ui.kNumberEdit, false); 0368 } 0369 if (!ui.kTargetAccountEdit->text().isEmpty()) { 0370 setWidgetEditionEnabled(ui.kTargetAccountEdit, false); 0371 } 0372 } 0373 } 0374 0375 void SKGOperationPluginWidget::setAllWidgetsEnabled() 0376 { 0377 SKGTRACEINFUNC(10) 0378 // Enable widgets 0379 setWidgetEditionEnabled(ui.kTypeEdit->lineEdit(), true); 0380 setWidgetEditionEnabled(ui.kUnitEdit->lineEdit(), true); 0381 setWidgetEditionEnabled(ui.kCategoryEdit->lineEdit(), true); 0382 setWidgetEditionEnabled(ui.kCommentEdit->lineEdit(), true); 0383 setWidgetEditionEnabled(ui.kPayeeEdit->lineEdit(), true); 0384 setWidgetEditionEnabled(ui.kTrackerEdit->lineEdit(), true); 0385 setWidgetEditionEnabled(ui.kAccountEdit, true); 0386 setWidgetEditionEnabled(ui.kTargetAccountEdit, true); 0387 setWidgetEditionEnabled(ui.kAmountEdit, true); 0388 setWidgetEditionEnabled(ui.kNumberEdit, true); 0389 } 0390 0391 QString SKGOperationPluginWidget::getAttributeOfSelection(const QString& iAttribute) 0392 { 0393 QString output; 0394 SKGObjectBase::SKGListSKGObjectBase selectedObjects = ui.kOperationView->getView()->getSelectedObjects(); 0395 int nb = selectedObjects.count(); 0396 for (int i = 0; i < nb ; ++i) { 0397 const SKGObjectBase& obj = selectedObjects.at(i); 0398 QString val = obj.getAttribute(iAttribute); 0399 if (i > 0 && val != output) { 0400 output = NOUPDATE; 0401 break; 0402 } 0403 output = val; 0404 } 0405 0406 return output; 0407 } 0408 0409 void SKGOperationPluginWidget::onSelectionChanged() 0410 { 0411 SKGTRACEINFUNC(10) 0412 0413 int mode = ui.kWidgetSelector->getSelectedMode(); 0414 0415 // Enable widgets 0416 setAllWidgetsEnabled(); 0417 ui.kFreezeBtn->setChecked(false); 0418 ui.kFreezeBtn->setIcon(SKGServices::fromTheme(QStringLiteral("emblem-locked"))); 0419 0420 // Mapping 0421 int nbSelect = ui.kOperationView->getView()->getNbSelectedObjects(); 0422 bool onConsolidatedTable = false; 0423 if ((nbSelect != 0) && (m_objectModel != nullptr)) { 0424 SKGObjectBase objbase = ui.kOperationView->getView()->getFirstSelectedObject(); 0425 SKGOperationObject obj; 0426 onConsolidatedTable = (objbase.getTable() == QStringLiteral("v_suboperation_consolidated")); 0427 if (onConsolidatedTable) { 0428 obj = SKGOperationObject(obj.getDocument(), SKGServices::stringToInt(obj.getAttribute(QStringLiteral("i_OPID")))); 0429 } else { 0430 obj = objbase; 0431 } 0432 0433 ui.kDateEdit->setDate(SKGServices::stringToTime(objbase.getAttribute(QStringLiteral("d_date"))).date()); 0434 m_previousDate = ui.kDateEdit->date(); 0435 ui.kCommentEdit->setText(objbase.getAttribute(onConsolidatedTable ? QStringLiteral("t_REALCOMMENT") : QStringLiteral("t_comment"))); 0436 QString number = objbase.getAttribute(QStringLiteral("t_number")); 0437 ui.kNumberEdit->setText(number); 0438 QString accountName = objbase.getAttribute(QStringLiteral("t_ACCOUNT")); 0439 if (!m_showClosedAccounts && !accountName.isEmpty() && !ui.kAccountEdit->contains(accountName)) { 0440 // Refresh list of accounts if a closed account is selected 0441 m_showClosedAccounts = true; 0442 dataModified(QLatin1String(""), 0); 0443 } 0444 ui.kAccountEdit->setText(accountName); 0445 ui.kPayeeEdit->setText(objbase.getAttribute(QStringLiteral("t_PAYEE"))); 0446 ui.kTypeEdit->setText(objbase.getAttribute(QStringLiteral("t_mode"))); 0447 QString unit = objbase.getAttribute(QStringLiteral("t_UNIT")); 0448 ui.kUnitEdit->setText(unit); 0449 QString cat = objbase.getAttribute(QStringLiteral("t_REALCATEGORY")); 0450 if (cat.isEmpty()) { 0451 cat = objbase.getAttribute(QStringLiteral("t_CATEGORY")); 0452 } 0453 ui.kCategoryEdit->setText(cat); 0454 ui.kTrackerEdit->setText(objbase.getAttribute(onConsolidatedTable ? QStringLiteral("t_REALREFUND") : QStringLiteral("t_REFUND"))); 0455 QString quantity = objbase.getAttribute(QStringLiteral("f_REALQUANTITY")); 0456 if (quantity.isEmpty()) { 0457 quantity = objbase.getAttribute(QStringLiteral("f_QUANTITY")); 0458 } 0459 double quantityVal = SKGServices::stringToDouble(quantity); 0460 SKGUnitObject unitObject = ui.kUnitEdit->getUnit(); 0461 int nbDec = unitObject.getNumberDecimal(); 0462 if (nbDec == 0) { 0463 nbDec = 2; 0464 } 0465 quantity = SKGServices::toCurrencyString(qAbs(quantityVal), QLatin1String(""), nbDec); 0466 if (quantity.startsWith(QLocale().positiveSign())) { 0467 quantity = quantity.right(quantity.length() - 1); 0468 } 0469 if (quantityVal > 0) { 0470 quantity = '+' % quantity; 0471 } else { 0472 quantity = '-' % quantity; 0473 } 0474 ui.kAmountEdit->setText(quantity); 0475 0476 if (nbSelect > 1) { 0477 // In case of multi selection 0478 if (mode >= 0) { 0479 ui.kWidgetSelector->setSelectedMode(0); 0480 } 0481 ui.kAccountEdit->setText(getAttributeOfSelection(QStringLiteral("t_ACCOUNT"))); 0482 ui.kTypeEdit->setText(getAttributeOfSelection(QStringLiteral("t_mode"))); 0483 ui.kUnitEdit->setText(getAttributeOfSelection(QStringLiteral("t_UNIT"))); 0484 ui.kCategoryEdit->setText(getAttributeOfSelection(onConsolidatedTable ? QStringLiteral("t_REALCATEGORY") : QStringLiteral("t_CATEGORY"))); 0485 ui.kTrackerEdit->setText(getAttributeOfSelection(onConsolidatedTable ? QStringLiteral("t_REALREFUND") : QStringLiteral("t_REFUND"))); 0486 ui.kCommentEdit->setText(getAttributeOfSelection(onConsolidatedTable ? QStringLiteral("t_REALCOMMENT") : QStringLiteral("t_comment"))); 0487 ui.kPayeeEdit->setText(getAttributeOfSelection(QStringLiteral("t_PAYEE"))); 0488 0489 QString d = getAttributeOfSelection(QStringLiteral("d_date")); 0490 if (d == NOUPDATE) { 0491 ui.kDateEdit->setCurrentText(NOUPDATE); 0492 } 0493 0494 QString q = getAttributeOfSelection(onConsolidatedTable ? QStringLiteral("f_REALQUANTITY") : QStringLiteral("f_QUANTITY")); 0495 ui.kAmountEdit->setText(q != NOUPDATE ? quantity : NOUPDATE); 0496 ui.kNumberEdit->setText(QLatin1String("")); 0497 } else { 0498 if (obj.getStatus() == SKGOperationObject::MARKED) { 0499 displayReconciliationInfo(); 0500 } else if (m_modeInfoZone != 1) { 0501 displayBalance(); 0502 } 0503 0504 // It is a single selection 0505 // Is it a split ? 0506 int nbSubOperations = obj.getNbSubOperations(); 0507 if (nbSubOperations > 1 && !onConsolidatedTable) { 0508 // yes, it is a split 0509 if (mode >= 0) { 0510 ui.kWidgetSelector->setSelectedMode(1); 0511 } 0512 0513 displaySubOperations(); 0514 } else { 0515 // Is it a transfer ? 0516 SKGOperationObject op2; 0517 if (obj.isTransfer(op2) && op2.exist()) { 0518 // yes it is a transfer 0519 SKGAccountObject account2; 0520 op2.getParentAccount(account2); 0521 QString accountName2 = account2.getName(); 0522 if (!m_showClosedAccounts && !ui.kTargetAccountEdit->contains(accountName2)) { 0523 // Refresh list of accounts if a closed account is selected 0524 m_showClosedAccounts = true; 0525 dataModified(QLatin1String(""), 0); 0526 } 0527 ui.kTargetAccountEdit->setText(accountName2); 0528 if (mode >= 0) { 0529 ui.kWidgetSelector->setSelectedMode(2); 0530 } 0531 } else { 0532 if (mode >= 0) { 0533 ui.kWidgetSelector->setSelectedMode(0); 0534 } 0535 } 0536 } 0537 } 0538 } 0539 0540 ui.kNumberEdit->setEnabled(nbSelect <= 1); 0541 0542 bool splitTest = nbSelect <= 1 && !onConsolidatedTable; 0543 ui.kWidgetSelector->setEnabledMode(1, splitTest); 0544 if (!splitTest && mode == 1) { 0545 ui.kWidgetSelector->setSelectedMode(0); 0546 } 0547 0548 onOperationCreatorModified(); 0549 0550 Q_EMIT selectionChanged(); 0551 } 0552 0553 void SKGOperationPluginWidget::onOperationCreatorModified() 0554 { 0555 SKGTRACEINFUNC(10) 0556 0557 int mode = ui.kWidgetSelector->getSelectedMode(); 0558 0559 // Set icons 0560 if (!isTemplateMode()) { 0561 ui.kModifyOperationBtn->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-ok"))); 0562 ui.kAddOperationBtn->setIcon(SKGServices::fromTheme(QStringLiteral("list-add"))); 0563 } else { 0564 QStringList overlay; 0565 overlay.push_back(QStringLiteral("edit-guides")); 0566 ui.kModifyOperationBtn->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-ok"), overlay)); 0567 ui.kAddOperationBtn->setIcon(SKGServices::fromTheme(QStringLiteral("list-add"), overlay)); 0568 } 0569 0570 // Is it an existing unit ? 0571 QString unitName = ui.kUnitEdit->currentText(); 0572 SKGUnitObject unit(getDocument()); 0573 unit.setName(unitName); 0574 unit.setSymbol(unitName); 0575 if (unit.load().isSucceeded()) { 0576 ui.kWidgetSelector->setEnabledMode(3, true); 0577 if (mode == 3 && unit.getType() == SKGUnitObject::SHARE) { 0578 // Update units 0579 auto unit = ui.kUnitShare->getUnit(); 0580 ui.kUnitCommission->setText(unit.getSymbol()); 0581 ui.kUnitTax->setText(unit.getSymbol()); 0582 0583 // Update total in "purchase / sale share" page 0584 double total = ui.kAmountSharesEdit->value() + (ui.kCommissionEdit->value() + ui.kTaxEdit->value()) * (ui.kAmountEdit->value() > 0 ? 1 : -1); 0585 ui.KTotal->setText(SKGServices::toCurrencyString(total, unit.getSymbol(), unit.getNumberDecimal())); 0586 } else { 0587 // BUG 2692665 0588 auto unitShareName = ui.kUnitShare->currentText(); 0589 if (unitShareName.isEmpty()) { 0590 ui.kUnitShare->setText(unitName); 0591 ui.kUnitCommission->setText(unitName); 0592 ui.kUnitTax->setText(unitName); 0593 ui.KTotal->setText(unitName); 0594 0595 } else { 0596 ui.kUnitCommission->setText(unitShareName); 0597 ui.kUnitTax->setText(unitShareName); 0598 ui.KTotal->setText(unitShareName); 0599 } 0600 } 0601 0602 } else { 0603 ui.kWidgetSelector->setEnabledMode(3, false); 0604 if (mode == 3) { 0605 ui.kWidgetSelector->setSelectedMode(0); 0606 } 0607 } 0608 0609 bool activated = mode != -1 && 0610 !ui.kAccountEdit->currentText().isEmpty() && 0611 ((!ui.kAmountEdit->text().isEmpty() && (ui.kAmountEdit->valid() || ui.kAmountEdit->text() == NOUPDATE)) || !ui.kAmountEdit->isEnabled()) && 0612 !unitName.isEmpty() && 0613 (mode != 3 || !ui.kAmountSharesEdit->text().isEmpty()); 0614 0615 int nbSelect = getNbSelectedObjects(); 0616 0617 ui.kAddOperationBtn->setEnabled(activated); 0618 ui.kModifyOperationBtn->setEnabled(activated && nbSelect > 0 && (ui.kWidgetSelector->getSelectedMode() == 0 || ui.kWidgetSelector->getSelectedMode() == 1 || ui.kWidgetSelector->getSelectedMode() == 2)); 0619 0620 m_numberFieldIsNotUptodate = true; 0621 if (ui.kNumberEdit->hasFocus()) { 0622 fillNumber(); 0623 } 0624 } 0625 0626 void SKGOperationPluginWidget::onPayeeChanged() 0627 { 0628 if (skgoperation_settings::setCategoryForPayee() && ui.kCategoryEdit->text().isEmpty()) { 0629 ui.kCategoryEdit->setText(qobject_cast<SKGDocumentBank*>(getDocument())->getCategoryForPayee(ui.kPayeeEdit->text(), false)); 0630 } 0631 } 0632 0633 void SKGOperationPluginWidget::onUpdateOperationClicked() 0634 { 0635 SKGError err; 0636 SKGTRACEINFUNCRC(10, err) 0637 // Get Selection 0638 SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects(); 0639 0640 int nb = selection.count(); 0641 { 0642 SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Transaction update"), err, nb) 0643 err = updateSelection(selection); 0644 } 0645 0646 // status bar 0647 IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Transaction updated"))) 0648 else { 0649 err.addError(ERR_FAIL, i18nc("Error message", "Transaction update failed")); 0650 } 0651 0652 // Display error 0653 SKGMainPanel::displayErrorMessage(err, true); 0654 0655 // Set focus on table 0656 ui.kOperationView->getView()->setFocus(); 0657 } 0658 0659 SKGError SKGOperationPluginWidget::updateSelection(const SKGObjectBase::SKGListSKGObjectBase& iSelection, bool iForceCreation) 0660 { 0661 SKGError err; 0662 SKGTRACEINFUNCRC(10, err) 0663 0664 // Initialisation 0665 double ratio = -1; 0666 bool refreshSubOperation = true; 0667 0668 // Get Selection 0669 int nb = iSelection.count(); 0670 double rate = -1; 0671 0672 for (int i = 0; !err && i < nb; ++i) { 0673 const SKGObjectBase& obj = iSelection.at(i); 0674 SKGOperationObject operationObj; 0675 if (obj.getTable() == QStringLiteral("v_suboperation_consolidated")) { 0676 operationObj = SKGOperationObject(obj.getDocument(), SKGServices::stringToInt(obj.getAttribute(QStringLiteral("i_OPID")))); 0677 } else { 0678 operationObj = SKGOperationObject(obj.getDocument(), obj.getID()); 0679 } 0680 0681 SKGObjectBase::SKGListSKGObjectBase gops; 0682 IFOKDO(err, operationObj.getGroupedOperations(gops)) 0683 if (gops.count() == 2 && ui.kWidgetSelector->getSelectedMode() < 2) { 0684 getDocument()->sendMessage(i18nc("An information message", "You modified one part of a transfer"), SKGDocument::Warning); 0685 } 0686 0687 // Update transaction if single selection 0688 if (ui.kWidgetSelector->getSelectedMode() == 0) { 0689 // Get subop 0690 SKGSubOperationObject subOp; 0691 int nbSubop = 0; 0692 if (obj.getTable() == QStringLiteral("v_suboperation_consolidated")) { 0693 // It is a sub operation 0694 subOp = SKGSubOperationObject(obj.getDocument(), SKGServices::stringToInt(obj.getAttribute(QStringLiteral("i_SUBOPID")))); 0695 nbSubop = 1; 0696 } else { 0697 // It is a real operation, we take the first one 0698 SKGObjectBase::SKGListSKGObjectBase subOps; 0699 IFOKDO(err, operationObj.getSubOperations(subOps)) 0700 nbSubop = subOps.count(); 0701 if (nbSubop != 0) { 0702 subOp = subOps[0]; 0703 } 0704 } 0705 0706 QString trackerName = ui.kTrackerEdit->text().trimmed(); 0707 if (!err && trackerName != NOUPDATE) { 0708 SKGTrackerObject tracker; 0709 err = SKGTrackerObject::createTracker(qobject_cast<SKGDocumentBank*>(getDocument()), trackerName, tracker, true); 0710 IFOKDO(err, subOp.setTracker(tracker)) 0711 } 0712 0713 SKGCategoryObject cat; 0714 QString catName = ui.kCategoryEdit->text().trimmed(); 0715 if (!err && catName != NOUPDATE) { 0716 err = SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), catName, cat, true); 0717 IFOKDO(err, subOp.setCategory(cat)) 0718 } else { 0719 // Get current category to be able to find the appropriate sign 0720 subOp.getCategory(cat); 0721 } 0722 0723 if (!err && ui.kAmountEdit->text() != NOUPDATE) { 0724 if (nbSubop > 1) { 0725 err = SKGError(25, i18nc("Error message", "Cannot update a split transaction")); 0726 } else { 0727 double val = ui.kAmountEdit->value(); 0728 0729 // Is the sign forced ? 0730 if (ui.kAmountEdit->sign() == 0) { 0731 // No 0732 SKGObjectBase cat2(cat.getDocument(), QStringLiteral("v_category_display"), cat.getID()); 0733 0734 // Are we able to find to sign with the category ? 0735 if (cat2.getAttribute(QStringLiteral("t_TYPEEXPENSE")) == QStringLiteral("-")) { 0736 val = -val; 0737 } 0738 } 0739 err = subOp.setQuantity(val); 0740 } 0741 } 0742 0743 if (!err && ui.kCommentEdit->text() != NOUPDATE) { 0744 err = subOp.setComment(ui.kCommentEdit->text()); 0745 } 0746 IFOKDO(err, subOp.save()) 0747 } else if (ui.kWidgetSelector->getSelectedMode() == 1) { 0748 // Case split 0749 refreshSubOperation = false; 0750 int nbsubop = ui.kSubOperationsTable->rowCount(); 0751 QList<int> listIdSubOp; // clazy:exclude=container-inside-loop 0752 listIdSubOp.reserve(nbsubop); 0753 for (int j = 0; !err && j < nbsubop; ++j) { 0754 // Get values 0755 QTableWidgetItem* item = ui.kSubOperationsTable->item(j, m_attributesForSplit.indexOf(QStringLiteral("t_category"))); 0756 int id = (iForceCreation ? 0 : item->data(Qt::UserRole).toInt()); 0757 QString catName = item->text(); 0758 0759 item = ui.kSubOperationsTable->item(j, m_attributesForSplit.indexOf(QStringLiteral("t_comment"))); 0760 QString comment = item->text(); 0761 0762 item = ui.kSubOperationsTable->item(j, m_attributesForSplit.indexOf(QStringLiteral("f_value"))); 0763 double val = item->data(101).toDouble(); 0764 QString formula = item->toolTip(); 0765 0766 item = ui.kSubOperationsTable->item(j, m_attributesForSplit.indexOf(QStringLiteral("t_refund"))); 0767 QString trackerName = item->text(); 0768 0769 item = ui.kSubOperationsTable->item(j, m_attributesForSplit.indexOf(QStringLiteral("d_date"))); 0770 QDate date = SKGServices::stringToTime(item->toolTip()).date(); 0771 if (!date.isValid()) { 0772 date = ui.kDateEdit->date(); 0773 } 0774 0775 SKGSubOperationObject subOperation; 0776 if (id != 0) { 0777 // Update existing sub op 0778 subOperation = SKGSubOperationObject(qobject_cast<SKGDocumentBank*>(getDocument()), id); 0779 } else { 0780 // Create new sub op 0781 err = operationObj.addSubOperation(subOperation); 0782 } 0783 0784 // Create sub transaction object 0785 IFOK(err) { 0786 SKGCategoryObject cat; 0787 err = SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), catName, cat, true); 0788 IFOKDO(err, subOperation.setCategory(cat)) 0789 } 0790 IFOK(err) { 0791 SKGTrackerObject tracker; 0792 err = SKGTrackerObject::createTracker(qobject_cast<SKGDocumentBank*>(getDocument()), trackerName, tracker, true); 0793 IFOKDO(err, subOperation.setTracker(tracker)) 0794 } 0795 IFOKDO(err, subOperation.setOrder(ui.kSubOperationsTable->visualRow(j))) 0796 IFOKDO(err, subOperation.setDate(date)) 0797 IFOKDO(err, subOperation.setComment(comment)) 0798 IFOKDO(err, subOperation.setQuantity(val)) 0799 if (formula.startsWith(QLatin1String("=")) && !err) { 0800 err = subOperation.setFormula(formula); 0801 } 0802 IFOKDO(err, subOperation.save()) 0803 0804 // The sub transaction created or updated mustn't be removed 0805 listIdSubOp.push_back(subOperation.getID()); 0806 } 0807 0808 // Remove useless subop 0809 IFOK(err) { 0810 SKGObjectBase::SKGListSKGObjectBase subOps; 0811 err = operationObj.getSubOperations(subOps); 0812 int nbsubop2 = subOps.count(); 0813 for (int j = 0; !err && j < nbsubop2; ++j) { 0814 const SKGObjectBase& sop = subOps.at(j); 0815 if (!listIdSubOp.contains(sop.getID())) { 0816 err = sop.remove(false); 0817 } 0818 } 0819 } 0820 } else if (ui.kWidgetSelector->getSelectedMode() == 2) { 0821 // Case transfer 0822 // Create sub transaction object 0823 double operationQuantity = ui.kAmountEdit->value(); 0824 0825 0826 SKGSubOperationObject subOperation; 0827 SKGObjectBase::SKGListSKGObjectBase subOps; 0828 IFOKDO(err, operationObj.getSubOperations(subOps)) 0829 IFOK(err) { 0830 subOperation = subOps.at(0); 0831 0832 double oldQuantity = subOperation.getQuantity(); 0833 0834 if (ui.kAmountEdit->sign() == 0) { 0835 operationQuantity = qAbs(operationQuantity); 0836 } else if (ui.kAmountEdit->sign() > 0) { 0837 operationQuantity = -qAbs(operationQuantity); 0838 } else { 0839 operationQuantity = qAbs(operationQuantity); 0840 if (oldQuantity == 0) { 0841 err = getDocument()->sendMessage(i18nc("An information message", "Absolute value has been used for transfer creation.")); 0842 } 0843 } 0844 0845 if (ui.kAmountEdit->text().trimmed() != NOUPDATE) { 0846 err = subOperation.setQuantity(-operationQuantity); 0847 } else { 0848 operationQuantity = -subOperation.getQuantity(); 0849 } 0850 } 0851 0852 SKGTrackerObject tracker; 0853 QString trackerName = ui.kTrackerEdit->text().trimmed(); 0854 if (!err) { 0855 if (trackerName != NOUPDATE) { 0856 err = SKGTrackerObject::createTracker(qobject_cast<SKGDocumentBank*>(getDocument()), trackerName, tracker, true); 0857 IFOKDO(err, subOperation.setTracker(tracker)) 0858 } else { 0859 err = subOperation.getTracker(tracker); 0860 } 0861 } 0862 0863 SKGCategoryObject cat; 0864 QString catName = ui.kCategoryEdit->text().trimmed(); 0865 if (!err) { 0866 if (catName != NOUPDATE) { 0867 err = SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), ui.kCategoryEdit->text(), cat, true); 0868 IFOKDO(err, subOperation.setCategory(cat)) 0869 } else { 0870 err = subOperation.getCategory(cat); 0871 } 0872 } 0873 IFOKDO(err, subOperation.setComment(operationObj.getComment())) 0874 IFOKDO(err, subOperation.save()) 0875 0876 // Get account 0877 SKGAccountObject accountObj2(getDocument()); 0878 IFOKDO(err, accountObj2.setName(ui.kTargetAccountEdit->currentText())) 0879 IFOKDO(err, accountObj2.load()) 0880 0881 // Check unit of target account 0882 SKGUnitObject unit; 0883 IFOKDO(err, operationObj.getUnit(unit)) 0884 0885 // Get date 0886 QDate operationDate; 0887 if (ui.kDateEdit->currentText().trimmed() != NOUPDATE) { 0888 operationDate = ui.kDateEdit->date(); 0889 } else { 0890 operationDate = operationObj.getDate(); 0891 } 0892 0893 0894 // Correction bug 2299303 vvv 0895 SKGUnitObject unitTargetAccount; 0896 IFOKDO(err, accountObj2.getUnit(unitTargetAccount)) 0897 if (!err && unitTargetAccount.exist() && unit != unitTargetAccount) { 0898 // The unit of the transaction is not compliant with the unit of the target account 0899 // We ask to the user if he wants to continue or convert into the target account 0900 bool ok = false; 0901 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 0902 int decimal = qMax(unit.getNumberDecimal(), unitTargetAccount.getNumberDecimal()); 0903 double newval; 0904 double defaultnewval = SKGUnitObject::convert(operationQuantity, unit, unitTargetAccount, operationDate); 0905 if (nb == 1) { 0906 newval = QInputDialog::getDouble(SKGMainPanel::getMainPanel(), 0907 i18nc("Question", "Confirmation"), 0908 i18nc("Question", "The operation's unit is not compatible with the target account.\n" 0909 "Click Cancel if you want to continue anyway; " 0910 "otherwise, enter the value in the target account's unit (%1):", unitTargetAccount.getSymbol()), 0911 defaultnewval, 0912 -std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), decimal, &ok); 0913 } else { 0914 if (rate == -1) { 0915 newval = QInputDialog::getDouble(SKGMainPanel::getMainPanel(), 0916 i18nc("Question", "Confirmation"), 0917 i18nc("Question", "Some operation's units are not compatible with the target account.\n" 0918 "The first selected transaction is:%1\n" 0919 "Click Cancel if you want to continue anyway; " 0920 "otherwise, enter the value in the target account's unit (%2):\nThe same rate will be applied to all transactions.", operationObj.getDisplayName(), unitTargetAccount.getSymbol()), 0921 defaultnewval, 0922 -std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), decimal, &ok); 0923 if (ok) { 0924 rate = defaultnewval / newval; 0925 } else { 0926 // Mode cancel for all 0927 rate = -2; 0928 } 0929 } else { 0930 if (rate != -2) { 0931 ok = true; 0932 newval = defaultnewval / rate; 0933 } 0934 } 0935 } 0936 QApplication::restoreOverrideCursor(); 0937 if (ok) { 0938 operationQuantity = newval; 0939 unit = unitTargetAccount; 0940 } else { 0941 // Mode cancel for all 0942 rate = -2; 0943 } 0944 } 0945 // Correction bug 2299303 ^^^ 0946 0947 // create transferred operation 0948 SKGOperationObject operation2; 0949 0950 IFOK(err) { 0951 if (gops.count() == 2) { 0952 operation2 = (obj == SKGOperationObject(gops.at(0)) ? gops.at(1) : gops.at(0)); 0953 if (ui.kTargetAccountEdit->text() != NOUPDATE) { 0954 err = operation2.setParentAccount(accountObj2); 0955 } 0956 } else { 0957 err = accountObj2.addOperation(operation2); 0958 } 0959 } 0960 if (nb == 1) { 0961 IFOKDO(err, operation2.setMode(ui.kTypeEdit->currentText())) 0962 QString payeeName = ui.kPayeeEdit->currentText(); 0963 if (!err && payeeName != NOUPDATE) { 0964 SKGPayeeObject payeeObject; 0965 err = SKGPayeeObject::createPayee(qobject_cast<SKGDocumentBank*>(getDocument()), payeeName, payeeObject, true); 0966 IFOKDO(err, operation2.setPayee(payeeObject)) 0967 } 0968 IFOKDO(err, operation2.setNumber(ui.kNumberEdit->text())) 0969 IFOKDO(err, operation2.setComment(ui.kCommentEdit->text())) 0970 IFOKDO(err, operation2.setDate(operationDate, refreshSubOperation)) 0971 IFOKDO(err, operation2.setUnit(unit)) 0972 0973 } else { 0974 IFOKDO(err, operation2.setMode(operationObj.getMode())) 0975 IFOKDO(err, operation2.setAttribute(QStringLiteral("r_payee_id"), operationObj.getAttribute(QStringLiteral("r_payee_id")))) 0976 IFOKDO(err, operation2.setNumber(operationObj.getNumber())) 0977 IFOKDO(err, operation2.setComment(operationObj.getComment())) 0978 IFOKDO(err, operation2.setDate(operationDate, refreshSubOperation)) 0979 IFOKDO(err, operation2.setUnit(unit)) 0980 } 0981 IFOKDO(err, operation2.setGroupOperation(operationObj)) 0982 IFOKDO(err, operationObj.load()) 0983 IFOKDO(err, operation2.setTemplate(isTemplateMode())) 0984 IFOKDO(err, operation2.save()) 0985 0986 // Create sub transaction object 0987 SKGSubOperationObject subOperation2; 0988 0989 SKGObjectBase::SKGListSKGObjectBase subops; 0990 IFOKDO(err, operation2.getSubOperations(subops)) 0991 IFOK(err) { 0992 if (!subops.isEmpty()) { 0993 subOperation2 = subops.at(0); 0994 } else { 0995 err = operation2.addSubOperation(subOperation2); 0996 } 0997 } 0998 IFOKDO(err, subOperation2.setQuantity(operationQuantity)) 0999 IFOKDO(err, subOperation2.setTracker(tracker)) 1000 IFOKDO(err, subOperation2.setCategory(cat)) 1001 IFOKDO(err, subOperation2.setComment(operationObj.getComment())) 1002 IFOKDO(err, subOperation2.save()) 1003 } 1004 1005 IFOKDO(err, operationObj.setTemplate(isTemplateMode())) 1006 if (ui.kDateEdit->currentText() != NOUPDATE) { 1007 IFOKDO(err, operationObj.setDate(ui.kDateEdit->date(), refreshSubOperation)) 1008 } 1009 1010 if (nb == 1) { 1011 IFOKDO(err, operationObj.setNumber(ui.kNumberEdit->text())) 1012 } 1013 if (!err && ui.kCommentEdit->text() != NOUPDATE) { 1014 if (obj.getTable() != QStringLiteral("v_suboperation_consolidated") || obj.getAttribute(QStringLiteral("i_NBSUBOPERATIONS")) == QStringLiteral("1")) { 1015 err = operationObj.setComment(ui.kCommentEdit->text()); 1016 } 1017 } 1018 1019 if (!err && ui.kAccountEdit->text() != NOUPDATE) { 1020 SKGAccountObject account(getDocument()); 1021 err = account.setName(ui.kAccountEdit->text()); 1022 IFOKDO(err, account.load()) 1023 IFOKDO(err, operationObj.setParentAccount(account)) 1024 } 1025 if (!err && ui.kTypeEdit->text() != NOUPDATE) { 1026 err = operationObj.setMode(ui.kTypeEdit->text()); 1027 } 1028 QString payeeName = ui.kPayeeEdit->currentText(); 1029 if (!err && payeeName != NOUPDATE) { 1030 SKGPayeeObject payeeObject; 1031 err = SKGPayeeObject::createPayee(qobject_cast<SKGDocumentBank*>(getDocument()), payeeName, payeeObject, true); 1032 IFOKDO(err, operationObj.setPayee(payeeObject)) 1033 } 1034 if (!err && ui.kUnitEdit->text() != NOUPDATE) { 1035 // Correction bug 282983 vvv 1036 // Check unit of target account 1037 SKGAccountObject account; 1038 IFOKDO(err, operationObj.getParentAccount(account)) 1039 SKGUnitObject unitTargetAccount; 1040 IFOKDO(err, account.getUnit(unitTargetAccount)) 1041 1042 SKGUnitObject unit = ui.kUnitEdit->getUnit(); 1043 1044 if (!err && unitTargetAccount.exist() && unit != unitTargetAccount) { 1045 // Correction bug 283842 vvvv 1046 bool ok = false; 1047 if (ratio == -1) { 1048 // The unit of the transaction is not compliant with the unit of the target account 1049 // We ask to the user if he wants to continue or convert into the target account 1050 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 1051 double currentAmount = ui.kAmountEdit->value(); 1052 int decimal = qMax(unit.getNumberDecimal(), unitTargetAccount.getNumberDecimal()); 1053 double newval = QInputDialog::getDouble(SKGMainPanel::getMainPanel(), 1054 i18nc("Question", "Confirmation"), 1055 i18nc("Question", "The operation's unit is not compatible with the target account.\n" 1056 "Click Cancel if you want to continue anyway; " 1057 "otherwise, enter the value in the target account's unit (%1):", unitTargetAccount.getSymbol()), 1058 SKGUnitObject::convert(currentAmount, unit, unitTargetAccount, ui.kDateEdit->date()), 1059 -std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), decimal, &ok); 1060 ratio = newval / currentAmount; 1061 QApplication::restoreOverrideCursor(); 1062 } 1063 if (ok) { 1064 // Apply ratio to all operation 1065 SKGObjectBase::SKGListSKGObjectBase subops; 1066 err = operationObj.getSubOperations(subops); 1067 int nbsubops = subops.count(); 1068 for (int j = 0; !err && j < nbsubops; ++j) { 1069 SKGSubOperationObject subop(subops.at(j)); 1070 err = subop.setQuantity(subop.getQuantity() * ratio); 1071 IFOKDO(err, subop.save(true, false)) 1072 } 1073 1074 // Change unit 1075 unit = unitTargetAccount; 1076 } else { 1077 err = getDocument()->sendMessage(i18nc("Warning message", "You created a transaction in %1 in an account in %2.", unit.getSymbol(), unitTargetAccount.getSymbol()), SKGDocument::Warning); 1078 } 1079 // Correction bug 283842 ^^^^ 1080 } 1081 // Correction bug 282983 ^^^ 1082 IFOKDO(err, operationObj.setUnit(unit)) 1083 } 1084 1085 // Save 1086 IFOKDO(err, operationObj.save()) 1087 1088 // Send message 1089 if (!iForceCreation) { 1090 IFOKDO(err, operationObj.getDocument()->sendMessage(i18nc("An information message", "The transaction '%1' has been updated", operationObj.getDisplayName()), SKGDocument::Hidden)) 1091 } 1092 1093 IFOKDO(err, getDocument()->stepForward(i + 1)) 1094 } 1095 1096 return err; 1097 } 1098 1099 void SKGOperationPluginWidget::onAddOperationClicked() 1100 { 1101 SKGError err; 1102 SKGTRACEINFUNC(10) 1103 1104 // Get parameters 1105 QString accountName = ui.kAccountEdit->currentText(); 1106 SKGOperationObject operation; 1107 { 1108 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Transaction creation"), err) 1109 1110 // Check entries 1111 if (ui.kAccountEdit->text() == NOUPDATE || 1112 ui.kTypeEdit->text() == NOUPDATE || 1113 ui.kUnitEdit->text() == NOUPDATE || 1114 ui.kCategoryEdit->text() == NOUPDATE || 1115 ui.kTrackerEdit->text() == NOUPDATE || 1116 ui.kCommentEdit->text() == NOUPDATE || 1117 ui.kAmountEdit->text() == NOUPDATE || 1118 ui.kDateEdit->currentText() == NOUPDATE || 1119 ui.kPayeeEdit->text() == NOUPDATE) { 1120 err = SKGError(ERR_FAIL, i18nc("Error message", "Impossible to create a transaction with one attribute valuated with %1", NOUPDATE)); 1121 } 1122 1123 // Get account 1124 SKGAccountObject accountObj(getDocument()); 1125 IFOKDO(err, accountObj.setName(accountName)) 1126 IFOKDO(err, accountObj.load()) 1127 1128 // Create transaction object 1129 IFOKDO(err, accountObj.addOperation(operation)) 1130 IFOKDO(err, operation.setMode(ui.kTypeEdit->currentText())) 1131 SKGPayeeObject payeeObject; 1132 IFOK(err) { 1133 QString payeeName = ui.kPayeeEdit->currentText(); 1134 err = SKGPayeeObject::createPayee(qobject_cast<SKGDocumentBank*>(getDocument()), payeeName, payeeObject, true); 1135 IFOKDO(err, operation.setPayee(payeeObject)) 1136 } 1137 IFOKDO(err, operation.setNumber(ui.kNumberEdit->text())) 1138 IFOKDO(err, operation.setComment(ui.kCommentEdit->text())) 1139 IFOKDO(err, operation.setDate(ui.kDateEdit->date())) 1140 IFOKDO(err, operation.setTemplate(isTemplateMode())) 1141 SKGUnitObject unit = ui.kUnitEdit->getUnit(); 1142 IFOKDO(err, operation.setUnit(unit)) 1143 if (skgoperation_settings::automaticPointInReconciliation() && m_modeInfoZone == 1) { 1144 IFOKDO(err, operation.setStatus(SKGOperationObject::MARKED)) 1145 } 1146 IFOKDO(err, operation.save()) 1147 1148 if (ui.kWidgetSelector->getSelectedMode() <= 2) { 1149 // STD OPERATION (SPLIT , TRANSFER OR NOT) 1150 // We must create a suboperation, just be sure to be able to update it 1151 SKGSubOperationObject subOperation; 1152 IFOKDO(err, operation.addSubOperation(subOperation)) 1153 IFOKDO(err, subOperation.setQuantity(0)) 1154 IFOKDO(err, subOperation.save()) 1155 1156 SKGObjectBase::SKGListSKGObjectBase list; 1157 list << operation; 1158 IFOKDO(err, updateSelection(list, true)) 1159 1160 } else if (ui.kWidgetSelector->getSelectedMode() == 3) { 1161 // PURCHASE OR SALE SHARE 1162 // Create sub transaction object 1163 SKGSubOperationObject subOperation; 1164 double val = ui.kAmountEdit->value(); 1165 IFOKDO(err, operation.addSubOperation(subOperation)) 1166 IFOKDO(err, subOperation.setQuantity(val)) 1167 IFOKDO(err, subOperation.save()) 1168 1169 if (!err && val > 0) { 1170 err = operation.setProperty(QStringLiteral("SKG_OP_ORIGINAL_AMOUNT"), SKGServices::doubleToString(ui.kAmountSharesEdit->value())); 1171 } 1172 IFOKDO(err, operation.save()) 1173 1174 // Get account 1175 SKGAccountObject accountObj2(getDocument()); 1176 IFOKDO(err, accountObj2.setName(ui.kPaymentAccountEdit->currentText())) 1177 IFOKDO(err, accountObj2.load()) 1178 1179 SKGUnitObject unit = ui.kUnitShare->getUnit(); 1180 1181 SKGUnitObject unitTargetAccount; 1182 IFOKDO(err, accountObj2.getUnit(unitTargetAccount)) 1183 double ratio = 1.0; 1184 if (!err && unitTargetAccount.exist() && unit != unitTargetAccount) { 1185 // The unit of the transaction is not compliant with the unit of the target account 1186 // We ask to the user if he wants to continue or convert into the target account 1187 bool ok = false; 1188 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); 1189 int decimal = qMax(unit.getNumberDecimal(), unitTargetAccount.getNumberDecimal()); 1190 double defaultnewval = SKGUnitObject::convert(ui.kAmountSharesEdit->value(), unit, unitTargetAccount, ui.kDateEdit->date()); 1191 double newval = QInputDialog::getDouble(SKGMainPanel::getMainPanel(), 1192 i18nc("Question", "Confirmation"), 1193 i18nc("Question", "The payment's unit (%1) is not compatible with the target account (%2).\n" 1194 "Click Cancel if you want to continue anyway; " 1195 "otherwise, enter the value in the target account's unit (%3):", unit.getSymbol(), accountObj2.getName(), unitTargetAccount.getSymbol()), 1196 defaultnewval, 1197 -std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), decimal, &ok); 1198 if (ok) { 1199 ratio = newval / ui.kAmountSharesEdit->value(); 1200 unit = unitTargetAccount; 1201 } 1202 QApplication::restoreOverrideCursor(); 1203 } 1204 1205 // create payment transaction for shares 1206 SKGOperationObject operation2; 1207 IFOKDO(err, accountObj2.addOperation(operation2)) 1208 IFOKDO(err, operation2.setMode(ui.kTypeEdit->currentText())) 1209 IFOKDO(err, operation2.setPayee(payeeObject)) 1210 IFOKDO(err, operation2.setNumber(ui.kNumberEdit->text())) 1211 IFOKDO(err, operation2.setComment(ui.kCommentEdit->text())) 1212 IFOKDO(err, operation2.setDate(ui.kDateEdit->date())) 1213 IFOKDO(err, operation2.setUnit(unit)) 1214 IFOKDO(err, operation2.setGroupOperation(operation)) 1215 IFOKDO(err, operation2.setTemplate(isTemplateMode())) 1216 IFOKDO(err, operation2.save()) 1217 1218 // Create main sub operation 1219 SKGSubOperationObject subOperation2; 1220 IFOKDO(err, operation2.addSubOperation(subOperation2)) 1221 IFOKDO(err, subOperation2.setComment(i18nc("Noun", "Shares"))) 1222 IFOKDO(err, subOperation2.setQuantity(ui.kAmountSharesEdit->value() * (val > 0 ? -1 : 1) * ratio)) 1223 IFOKDO(err, subOperation2.save()) 1224 1225 // Create commission sub operation 1226 if (ui.kCommissionEdit->value() != 0.0) { 1227 SKGSubOperationObject subOperation3; 1228 IFOKDO(err, operation2.addSubOperation(subOperation3)) 1229 IFOKDO(err, subOperation3.setComment(skgoperation_settings::commentCommissionOperation())) 1230 1231 QString category = skgoperation_settings::categoryCommissionOperation(); 1232 if (!category.isEmpty()) { 1233 SKGCategoryObject c; 1234 IFOKDO(err, SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), category, c, true)) 1235 IFOKDO(err, subOperation3.setCategory(c)) 1236 } 1237 1238 IFOKDO(err, subOperation3.setQuantity(-ui.kCommissionEdit->value() * ratio)) 1239 IFOKDO(err, subOperation3.save()) 1240 } 1241 1242 // Create tax sub operation 1243 if (ui.kTaxEdit->value() != 0.0) { 1244 SKGSubOperationObject subOperation4; 1245 IFOKDO(err, operation2.addSubOperation(subOperation4)) 1246 IFOKDO(err, subOperation4.setComment(skgoperation_settings::commentTaxOperation())) 1247 1248 QString category = skgoperation_settings::categoryTaxOperation(); 1249 if (!category.isEmpty()) { 1250 SKGCategoryObject c; 1251 IFOKDO(err, SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), category, c, true)) 1252 IFOKDO(err, subOperation4.setCategory(c)) 1253 } 1254 1255 IFOKDO(err, subOperation4.setQuantity(-ui.kTaxEdit->value() * ratio)) 1256 IFOKDO(err, subOperation4.save()) 1257 } 1258 } 1259 1260 // Send message 1261 IFOKDO(err, operation.getDocument()->sendMessage(i18nc("An information to the user that something was added", "The transaction '%1' has been added", operation.getDisplayName()), SKGDocument::Hidden)) 1262 } 1263 1264 // status bar 1265 IFOK(err) { 1266 err = SKGError(0, i18nc("Successful message after an user action", "Transaction created")); 1267 ui.kOperationView->getView()->selectObject(operation.getUniqueID()); 1268 } else { 1269 err.addError(ERR_FAIL, i18nc("Error message", "Transaction creation failed")); 1270 } 1271 1272 // Display error 1273 SKGMainPanel::displayErrorMessage(err, true); 1274 1275 // Set focus on date 1276 ui.kDateEdit->setFocus(); 1277 } 1278 1279 SKGTreeView* SKGOperationPluginWidget::getTableView() 1280 { 1281 return ui.kOperationView->getView(); 1282 } 1283 1284 QString SKGOperationPluginWidget::getState() 1285 { 1286 SKGTRACEINFUNC(10) 1287 QDomDocument doc(QStringLiteral("SKGML")); 1288 QDomElement root; 1289 if (m_lastState.hasChildNodes()) { 1290 doc = m_lastState; 1291 root = doc.documentElement(); 1292 } else { 1293 root = doc.createElement(QStringLiteral("parameters")); 1294 doc.appendChild(root); 1295 } 1296 1297 root.setAttribute(QStringLiteral("currentPage"), SKGServices::intToString(ui.kWidgetSelector->getSelectedMode())); 1298 root.setAttribute(QStringLiteral("modeInfoZone"), SKGServices::intToString(m_modeInfoZone)); 1299 root.setAttribute(QStringLiteral("reconcilitorAmount"), ui.kReconcilitorAmountEdit->text()); 1300 root.removeAttribute(QStringLiteral("account")); 1301 1302 // Memorize table settings 1303 root.setAttribute(QStringLiteral("view"), ui.kOperationView->getState()); 1304 1305 return doc.toString(); 1306 } 1307 1308 void SKGOperationPluginWidget::setState(const QString& iState) 1309 { 1310 SKGTRACEINFUNC(10) 1311 QDomDocument doc(QStringLiteral("SKGML")); 1312 doc.setContent(iState); 1313 QDomElement root = doc.documentElement(); 1314 1315 QString account = root.attribute(QStringLiteral("account")); 1316 QString currentPage = root.attribute(QStringLiteral("currentPage")); 1317 QString title = root.attribute(QStringLiteral("title")); 1318 QString title_icon = root.attribute(QStringLiteral("title_icon")); 1319 QString modeInfoZoneS = root.attribute(QStringLiteral("modeInfoZone")); 1320 QString reconcilitorAmountS = root.attribute(QStringLiteral("reconcilitorAmount")); 1321 QString operationTable = root.attribute(QStringLiteral("operationTable")); 1322 QString selection = root.attribute(QStringLiteral("selection")); 1323 QString templates = root.attribute(QStringLiteral("template")); 1324 m_operationWhereClause = root.attribute(QStringLiteral("operationWhereClause")); 1325 1326 // Default values in case of reset 1327 if (currentPage.isEmpty()) { 1328 currentPage = '0'; 1329 } 1330 if (operationTable.isEmpty()) { 1331 if (m_operationWhereClause.isEmpty()) { 1332 operationTable = QStringLiteral("v_operation_display_all"); 1333 } else { 1334 operationTable = QStringLiteral("v_operation_display"); 1335 } 1336 } 1337 1338 // Set 1339 SKGAccountObject acc; 1340 SKGNamedObject::getObjectByName(getDocument(), QStringLiteral("v_account"), account, acc); 1341 if (acc.isClosed() && !m_showClosedAccounts) { 1342 m_showClosedAccounts = true; 1343 dataModified(QLatin1String(""), 0); 1344 } 1345 bool previous = ui.kReconcilitorAmountEdit->blockSignals(true); 1346 ui.kReconcilitorAmountEdit->setText(reconcilitorAmountS); 1347 ui.kReconcilitorAmountEdit->blockSignals(previous); 1348 ui.kWidgetSelector->setSelectedMode(SKGServices::stringToInt(currentPage)); 1349 if (!title.isEmpty()) { 1350 QFontMetrics fm(fontMetrics()); 1351 ui.kTitle->setComment("<html><body><b>" % SKGServices::stringToHtml(fm.elidedText(title, Qt::ElideMiddle, 2000)) % "</b></body></html>"); 1352 ui.kTitle->setToolTip(title); 1353 ui.kTitle->show(); 1354 } 1355 if (!title_icon.isEmpty()) { 1356 ui.kTitle->setIcon(SKGServices::fromTheme(title_icon), KTitleWidget::ImageLeft); 1357 } 1358 1359 if (m_objectModel != nullptr) { 1360 m_objectModel->setTable(operationTable); 1361 } 1362 if ((m_objectModel != nullptr) && !m_operationWhereClause.isEmpty()) { 1363 ui.kOperationView->getShowWidget()->setEnabled(false); 1364 m_objectModel->setFilter(m_operationWhereClause); 1365 } 1366 if (!operationTable.isEmpty() || !m_operationWhereClause.isEmpty()) { 1367 // We keep a copy of given state in case of bookmark 1368 m_lastState = doc; 1369 } else { 1370 m_lastState = QDomDocument(); 1371 } 1372 1373 // Update model 1374 if (m_objectModel != nullptr) { 1375 previous = m_objectModel->blockRefresh(true); 1376 onAccountChanged(); 1377 m_objectModel->blockRefresh(previous); 1378 } 1379 1380 // !!! Must be done here after onFilterChanged 1381 QString v = root.attribute(QStringLiteral("view")); 1382 if (!v.isEmpty()) { 1383 ui.kOperationView->setState(v); 1384 } 1385 if (!account.isEmpty()) { 1386 QStringList parameters = SKGServices::splitCSVLine(ui.kOperationView->getShowWidget()->getState()); 1387 if (parameters.isEmpty()) { 1388 parameters.push_back(QLatin1String("")); 1389 parameters.push_back(QStringLiteral("transactions")); 1390 parameters.push_back(QStringLiteral("hide")); 1391 } 1392 parameters[0] = "##_" % account; 1393 ui.kOperationView->getShowWidget()->setState(SKGServices::stringsToCsv(parameters)); 1394 } 1395 1396 if (templates == QStringLiteral("Y")) { 1397 QStringList parameters = SKGServices::splitCSVLine(ui.kOperationView->getShowWidget()->getState()); 1398 parameters.removeAll(QStringLiteral("transactions")); 1399 parameters.push_back(QStringLiteral("templates")); 1400 ui.kOperationView->getShowWidget()->setState(SKGServices::stringsToCsv(parameters)); 1401 } 1402 1403 QStringList parameters = SKGServices::splitCSVLine(ui.kOperationView->getShowWidget()->getState()); 1404 if (!parameters.contains(QStringLiteral("transactions")) && !parameters.contains(QStringLiteral("templates"))) { 1405 parameters.push_back(QStringLiteral("transactions")); 1406 ui.kOperationView->getShowWidget()->setState(SKGServices::stringsToCsv(parameters)); 1407 } 1408 1409 if (!selection.isEmpty()) { 1410 QStringList uuids = SKGServices::splitCSVLine(selection); 1411 ui.kOperationView->getView()->selectObjects(uuids, true); // FIXME // TODO(Stephane MANKOWSKI) 1412 onSelectionChanged(); 1413 } 1414 1415 // Refresh of the information zone 1416 if (!modeInfoZoneS.isEmpty()) { 1417 m_modeInfoZone = SKGServices::stringToInt(modeInfoZoneS) - 1; 1418 } else { 1419 m_modeInfoZone = -1; 1420 } 1421 onRotateAccountTools(); 1422 } 1423 1424 QString SKGOperationPluginWidget::getDefaultStateAttribute() 1425 { 1426 if ((m_objectModel != nullptr) && m_objectModel->getTable() == QStringLiteral("v_suboperation_consolidated")) { 1427 return QStringLiteral("SKGOPERATION_CONSOLIDATED_DEFAULT_PARAMETERS"); 1428 } 1429 1430 if (!m_operationWhereClause.isEmpty()) { 1431 return QLatin1String(""); 1432 } 1433 1434 return QStringLiteral("SKGOPERATION_DEFAULT_PARAMETERS"); 1435 } 1436 1437 void SKGOperationPluginWidget::fillTargetAccount() 1438 { 1439 int nbAccounts = ui.kAccountEdit->count(); 1440 QString current = ui.kAccountEdit->text(); 1441 QString currentTarget = ui.kTargetAccountEdit->text(); 1442 QString currentRecon = ui.kReconciliateAccount->text(); 1443 ui.kTargetAccountEdit->clear(); 1444 ui.kReconciliateAccount->clear(); 1445 ui.kReconciliateAccount->addItem(QLatin1String("")); 1446 for (int i = 0; i < nbAccounts; ++i) { 1447 if (ui.kAccountEdit->itemText(i) != current) { 1448 ui.kTargetAccountEdit->addItem(ui.kAccountEdit->itemIcon(i), ui.kAccountEdit->itemText(i)); 1449 ui.kReconciliateAccount->addItem(ui.kAccountEdit->itemIcon(i), ui.kAccountEdit->itemText(i)); 1450 } 1451 } 1452 if (ui.kTargetAccountEdit->contains(currentTarget)) { 1453 ui.kTargetAccountEdit->setText(currentTarget); 1454 } 1455 1456 SKGError err; 1457 SKGAccountObject currentActObj(getDocument()); 1458 IFOKDO(err, currentActObj.setName(current)) 1459 IFOKDO(err, currentActObj.load()) 1460 1461 SKGAccountObject linkedActObj; 1462 IFOKDO(err, currentActObj.getLinkedAccount(linkedActObj)) 1463 if (linkedActObj.getID() != 0) { 1464 currentRecon = linkedActObj.getName(); 1465 } 1466 1467 if (ui.kReconciliateAccount->contains(currentRecon)) { 1468 ui.kReconciliateAccount->setText(currentRecon); 1469 } 1470 } 1471 1472 void SKGOperationPluginWidget::dataModified(const QString& iTableName, int iIdTransaction, bool iLightTransaction) 1473 { 1474 SKGTRACEINFUNC(10) 1475 Q_UNUSED(iIdTransaction) 1476 1477 // Refresh widgets 1478 QSqlDatabase* db = getDocument()->getMainDatabase(); 1479 setEnabled(db != nullptr); 1480 if (db != nullptr) { 1481 if (iTableName == QStringLiteral("account") || iTableName.isEmpty()) { 1482 SKGShow* showWidget = ui.kOperationView->getShowWidget(); 1483 QString current = currentAccount(); 1484 QString currentState = showWidget->getState(); 1485 1486 // Disconnect combo filter account 1487 disconnect(showWidget, &SKGShow::stateChanged, this, &SKGOperationPluginWidget::onAccountChanged); 1488 disconnect(showWidget, &SKGShow::stateChanged, this, &SKGOperationPluginWidget::onRefreshInformationZoneDelayed); 1489 disconnect(showWidget, &SKGShow::stateChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified); 1490 disconnect(ui.kAccountEdit, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::currentTextChanged), this, &SKGOperationPluginWidget::fillTargetAccount); 1491 1492 // Clear 1493 ui.kAccountEdit->clear(); 1494 ui.kPaymentAccountEdit->clear(); 1495 1496 SKGStringListList listAccount; 1497 getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT t_ICON, t_name, t_bookmarked, id, t_type from v_account_display ") % (m_showClosedAccounts ? "" : "where t_close='N' ") 1498 % "order by t_bookmarked DESC, t_name ASC", listAccount); 1499 1500 int nbAccounts = listAccount.count() - 1; 1501 if (!m_lastState.hasChildNodes()) { 1502 ui.kTitle->hide(); 1503 } 1504 1505 // Set show widget 1506 showWidget->clear(); 1507 1508 if (nbAccounts > 1) { 1509 showWidget->addGroupedItem(QStringLiteral("all"), i18nc("Option to for display of transactions", "All"), QLatin1String(""), QStringLiteral("1=1"), QStringLiteral("account"), Qt::META + Qt::Key_A); 1510 showWidget->addSeparator(); 1511 } 1512 1513 QString uncheck; 1514 bool accountSeparatorAdded = false; 1515 for (int i = 1; i <= nbAccounts; ++i) { // Ignore header 1516 const bool wallet = (listAccount.at(i).at(4) == QStringLiteral("W")); 1517 QString iconName = wallet ? QStringLiteral("wallet-closed") : QStandardPaths::locate(QStandardPaths::GenericDataLocation, "skrooge/images/logo/" % listAccount.at(i).at(0)); 1518 if (iconName.isEmpty()) { 1519 iconName = listAccount.at(i).at(0); 1520 } 1521 QIcon icon(iconName); 1522 QString text = listAccount.at(i).at(1); 1523 QString id = "##_" % text; 1524 if (nbAccounts == 1) { 1525 QStringList items = SKGServices::splitCSVLine(currentState); 1526 if (items.isEmpty()) { 1527 items.push_back(QStringLiteral("all")); 1528 } 1529 if (items[0] == QStringLiteral("all") || !items[0].startsWith(QLatin1String("##_"))) { 1530 items[0] = id; 1531 } 1532 if (items.count() == 1) { 1533 items.push_back(QStringLiteral("transactions")); 1534 items.push_back(QStringLiteral("hide")); 1535 } 1536 currentState = SKGServices::stringsToCsv(items); 1537 } 1538 ui.kAccountEdit->addItem(icon, text); 1539 ui.kPaymentAccountEdit->addItem(icon, text); 1540 1541 if (!accountSeparatorAdded && listAccount.at(i).at(2) == QStringLiteral("N")) { 1542 if (i > 1) { 1543 showWidget->addSeparator(); 1544 } 1545 accountSeparatorAdded = true; 1546 } 1547 1548 QString account_id = listAccount.at(i).at(3); 1549 showWidget->addGroupedItem(id, text, iconName, "rd_account_id=" + account_id, QStringLiteral("account"), 1550 (i < 10 ? QKeySequence::fromString("Meta+" % SKGServices::intToString(i)) : QKeySequence())); 1551 1552 SKGStringListList listLinkedAccounts; 1553 getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT id FROM v_account_display where t_close='N' AND r_account_id=") + account_id, listLinkedAccounts); 1554 int nbLinkedAccount = listLinkedAccounts.count(); 1555 if (nbLinkedAccount > 1) { 1556 QString f = account_id; 1557 for (int j = 1; j < nbLinkedAccount; ++j) { // Ignore header 1558 f += ",'" + listLinkedAccounts.at(j).at(0) + '\''; 1559 } 1560 1561 showWidget->addGroupedItem(id + "_cc", i18nc("Information", "%1 + its credit cards", text), iconName, "rd_account_id IN(" + f + ')', QStringLiteral("account"), 1562 QKeySequence()); 1563 } 1564 1565 if (!uncheck.isEmpty()) { 1566 uncheck = uncheck % ";"; 1567 } 1568 uncheck = uncheck % id; 1569 } 1570 1571 int nb = showWidget->count(); 1572 for (int i = 1; i < nb; ++i) { 1573 showWidget->setListIdToUncheckWhenChecked(i, uncheck % ";all"); 1574 } 1575 if (nbAccounts > 1) { 1576 showWidget->setListIdToUncheckWhenChecked(0, uncheck); 1577 } 1578 1579 showWidget->addSeparator(); 1580 showWidget->addGroupedItem(QStringLiteral("transactions"), i18nc("Option to for display of transactions", "Transactions"), QStringLiteral("view-bank-account"), QStringLiteral("d_date!='0000-00-00' AND t_template='N'"), 1581 QStringLiteral("type"), Qt::META + Qt::Key_O); 1582 showWidget->addGroupedItem(QStringLiteral("templates"), i18nc("Option to for display of transactions", "Templates"), QStringLiteral("edit-guides"), QStringLiteral("d_date!='0000-00-00' AND t_template='Y'"), 1583 QStringLiteral("type"), Qt::META + Qt::Key_T); 1584 showWidget->addSeparator(); 1585 showWidget->addItem(QStringLiteral("hidepointed"), i18nc("Option to for display of transactions", "Hide marked transactions"), QStringLiteral("dialog-ok"), QStringLiteral("t_status<>'P'"), QLatin1String(""), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_P); 1586 showWidget->addItem(QStringLiteral("hide"), i18nc("Option to for display of transactions", "Hide checked transactions"), QStringLiteral("dialog-ok"), QStringLiteral("t_status<>'Y'"), QLatin1String(""), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_C); 1587 showWidget->addSeparator(); 1588 showWidget->addPeriodItem(QStringLiteral("period")); 1589 showWidget->setMode(SKGShow::AND); 1590 if (currentState.isEmpty()) { 1591 showWidget->setDefaultState(QStringLiteral("all;transactions;hide")); 1592 } else { 1593 showWidget->setState(currentState); 1594 } 1595 1596 if (!current.isEmpty()) { 1597 ui.kAccountEdit->setText(current); 1598 } 1599 1600 // Connect combo filter account 1601 connect(ui.kAccountEdit, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::currentTextChanged), this, &SKGOperationPluginWidget::fillTargetAccount, Qt::QueuedConnection); 1602 connect(showWidget, &SKGShow::stateChanged, this, &SKGOperationPluginWidget::onAccountChanged, Qt::QueuedConnection); 1603 connect(showWidget, &SKGShow::stateChanged, this, &SKGOperationPluginWidget::onRefreshInformationZoneDelayed, Qt::QueuedConnection); 1604 connect(showWidget, &SKGShow::stateChanged, this, &SKGOperationPluginWidget::onOperationCreatorModified, Qt::QueuedConnection); 1605 1606 fillTargetAccount(); 1607 1608 if (nbAccounts == 0) { 1609 ui.kTitle->setText(i18nc("Message", "First, you have to create an account.")); 1610 ui.kTitle->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-information")), KTitleWidget::ImageLeft); 1611 ui.kTitle->show(); 1612 showWidget->hide(); 1613 } else { 1614 showWidget->show(); 1615 } 1616 } 1617 1618 if (iTableName == QStringLiteral("refund") || iTableName.isEmpty()) { 1619 SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kTrackerEdit, getDocument(), QStringLiteral("refund"), QStringLiteral("t_name"), QStringLiteral("t_close='N'")); 1620 } 1621 if (!iLightTransaction) { 1622 if (iTableName == QStringLiteral("category") || iTableName.isEmpty()) { 1623 SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kCategoryEdit, getDocument(), QStringLiteral("category"), QStringLiteral("t_fullname"), QStringLiteral("t_close='N'")); 1624 } 1625 if (iTableName == QStringLiteral("payee") || iTableName.isEmpty()) { 1626 SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kPayeeEdit, getDocument(), QStringLiteral("payee"), QStringLiteral("t_name"), QStringLiteral("t_close='N'")); 1627 } 1628 if (iTableName == QStringLiteral("operation") || iTableName.isEmpty()) { 1629 SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kTypeEdit, getDocument(), QStringLiteral("operation"), QStringLiteral("t_mode"), QLatin1String(""), true); 1630 SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kCommentEdit, getDocument(), QStringLiteral("v_operation_all_comment"), QStringLiteral("t_comment"), QLatin1String(""), true); 1631 1632 // Set type number 1633 m_numberFieldIsNotUptodate = true; 1634 1635 // Correction 215658: vvv because the table is modified, the selection is modified 1636 onSelectionChanged(); 1637 // Correction 215658: ^^^ 1638 1639 onRefreshInformationZoneDelayed(); 1640 } 1641 } else if (iTableName == QStringLiteral("operation") || iTableName.isEmpty()) { 1642 onRefreshInformationZoneDelayed(); 1643 } 1644 } 1645 } 1646 1647 void SKGOperationPluginWidget::onDoubleClick() 1648 { 1649 _SKGTRACEINFUNC(10) 1650 1651 // Get selection 1652 SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects(); 1653 if (selection.count() == 1) { 1654 SKGOperationObject op(selection.at(0)); 1655 1656 if (op.isTemplate() && selection.at(0).getRealTable() == QStringLiteral("operation")) { 1657 // this is a template, we have to create an operation 1658 SKGError err; 1659 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Transaction creation"), err) 1660 SKGOperationObject operation; 1661 err = op.duplicate(operation); 1662 if (skgoperation_settings::automaticPointInReconciliation() && m_modeInfoZone == 1) { 1663 IFOKDO(err, operation.setStatus(SKGOperationObject::MARKED)) 1664 IFOKDO(err, operation.save()) 1665 } 1666 1667 // Send message 1668 IFOKDO(err, operation.getDocument()->sendMessage(i18nc("An information to the user that something was added", "The transaction '%1' has been added", operation.getDisplayName()), SKGDocument::Hidden)) 1669 1670 // status bar 1671 IFOK(err) { 1672 setTemplateMode(false); 1673 err = SKGError(0, i18nc("Successful message after an user action", "Transaction created")); 1674 ui.kOperationView->getView()->selectObject(operation.getUniqueID()); 1675 } else { 1676 err.addError(ERR_FAIL, i18nc("Error message", "Transaction creation failed")); 1677 } 1678 1679 // Display error 1680 SKGMainPanel::displayErrorMessage(err); 1681 1682 } else { 1683 // This is not a template, we have to open it 1684 SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("open"))->trigger(); 1685 } 1686 } 1687 } 1688 1689 void SKGOperationPluginWidget::onRefreshInformationZoneDelayed() 1690 { 1691 m_timer.start(300); 1692 } 1693 1694 void SKGOperationPluginWidget::onRefreshInformationZone() 1695 { 1696 SKGTRACEINFUNC(1) 1697 ui.kReconciliateAccount->hide(); 1698 1699 auto* doc = qobject_cast<SKGDocumentBank*>(getDocument()); 1700 QString current = currentAccount(); 1701 if (doc != nullptr && SKGMainPanel::getMainPanel()) { 1702 if (m_modeInfoZone == 0) { 1703 // Refresh info area 1704 // Compute where clause 1705 QString filter = QStringLiteral("1=1"); 1706 if (!current.isEmpty()) { 1707 filter = "t_name='" % SKGServices::stringToSqlString(current) % '\''; 1708 } 1709 ui.kInfo->setText(i18nc("Message", "Computing…")); 1710 doc->concurrentExecuteSelectSqliteOrder("SELECT TOTAL(f_CURRENTAMOUNT), TOTAL(f_CHECKED), TOTAL(f_COMING_SOON), TOTAL(f_COMING_SOON_FROM_LINKED_ACCOUNT) from v_account_display WHERE " % filter, [ = ](const SKGStringListList & iResult) { 1711 if (iResult.count() == 2 && SKGMainPanel::getMainPanel()->pageIndex(this) != -1) { 1712 SKGServices::SKGUnitInfo unit1 = doc->getPrimaryUnit(); 1713 SKGServices::SKGUnitInfo unit2 = doc->getSecondaryUnit(); 1714 if (!current.isEmpty()) { 1715 SKGAccountObject account(getDocument()); 1716 if (account.setName(current).isSucceeded()) { 1717 if (account.load().isSucceeded()) { 1718 SKGUnitObject unitAccount; 1719 if (account.getUnit(unitAccount).isSucceeded()) { 1720 if (!unitAccount.getSymbol().isEmpty()) { 1721 unit1.Symbol = unitAccount.getSymbol(); 1722 unit1.Value = SKGServices::stringToDouble(unitAccount.getAttribute(QStringLiteral("f_CURRENTAMOUNT"))); 1723 1724 if (unit1.Symbol != qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit().Symbol) { 1725 unit2 = qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit(); 1726 } 1727 } 1728 } 1729 } 1730 } 1731 } 1732 1733 double v1 = SKGServices::stringToDouble(iResult.at(1).at(0)); 1734 double v2 = SKGServices::stringToDouble(iResult.at(1).at(1)); 1735 double v3 = SKGServices::stringToDouble(iResult.at(1).at(2)); 1736 double v4 = SKGServices::stringToDouble(iResult.at(1).at(3)); 1737 QString s1 = doc->formatMoney(v1, unit1); 1738 QString s2 = doc->formatMoney(v2, unit1); 1739 QString s3 = doc->formatMoney(v3, unit1); 1740 QString s4 = doc->formatMoney(v4, unit1); 1741 QString zero = doc->formatMoney(0, unit1); 1742 ui.kInfo->setText(i18nc("Message", "Balance: %1 Checked: %2 To be Checked: %3", s1, s2, !current.isEmpty() && s4 != zero ? s3 % " + " % s4 : s3)); 1743 if (!unit2.Symbol.isEmpty() && (unit2.Value != 0.0)) { 1744 s1 = doc->formatMoney(v1, unit2); 1745 s2 = doc->formatMoney(v2, unit2); 1746 s3 = doc->formatMoney(v3, unit2); 1747 s4 = doc->formatMoney(v4, unit2); 1748 } 1749 ui.kInfo->setToolTip(i18nc("Message", "<p>Balance: %1</p><p>Checked: %2</p><p>To be Checked: %3</p>", s1, s2, !current.isEmpty() && s4 != zero ? s3 % " + " % s4 : s3)); 1750 } 1751 }); 1752 } else if (m_modeInfoZone == 1) { 1753 // Refresh reconciliation area 1754 SKGServices::SKGUnitInfo unit1 = doc->getPrimaryUnit(); 1755 SKGServices::SKGUnitInfo unit2 = doc->getSecondaryUnit(); 1756 // Compute where clause 1757 QString filter = '\'' % SKGServices::stringToSqlString(currentAccount()) % '\''; 1758 SKGStringListList listTmp; 1759 getDocument()->executeSelectSqliteOrder( 1760 "SELECT ABS(TOTAL(f_CURRENTAMOUNT_EXPENSE)),TOTAL(f_CURRENTAMOUNT_INCOME) FROM v_operation_display WHERE t_status='P' AND t_ACCOUNT=" % filter, 1761 listTmp); 1762 if (listTmp.count() == 2) { 1763 SKGAccountObject::AccountType accountType = SKGAccountObject::OTHER; 1764 if (!current.isEmpty()) { 1765 SKGAccountObject account(getDocument()); 1766 if (account.setName(current).isSucceeded()) { 1767 if (account.load().isSucceeded()) { 1768 accountType = account.getType(); 1769 1770 SKGUnitObject unitAccount; 1771 if (account.getUnit(unitAccount).isSucceeded()) { 1772 if (!unitAccount.getSymbol().isEmpty()) { 1773 unit1.Symbol = unitAccount.getSymbol(); 1774 unit1.Value = SKGServices::stringToDouble(unitAccount.getAttribute(QStringLiteral("f_CURRENTAMOUNT"))); 1775 1776 if (unit1.Symbol != qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit().Symbol) { 1777 unit2 = qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit(); 1778 } 1779 } 1780 } 1781 } 1782 } 1783 } 1784 if (accountType == SKGAccountObject::SKGAccountObject::CREDITCARD) { 1785 ui.kReconciliationTitle->setText(i18nc("A title", "Total amount:")); 1786 ui.kReconciliateAccount->show(); 1787 } else { 1788 ui.kReconciliationTitle->setText(i18nc("A title", "Final balance:")); 1789 } 1790 1791 ui.kAutoPoint->setVisible(accountType != SKGAccountObject::WALLET); 1792 1793 SKGStringListList listTmp2; 1794 double diff = 0; 1795 getDocument()->executeSelectSqliteOrder( 1796 "SELECT TOTAL(f_CHECKEDANDPOINTED) from v_account_display WHERE t_name=" % filter, 1797 listTmp2); 1798 if (listTmp2.count() == 2) { 1799 diff = SKGServices::stringToDouble(listTmp2.at(1).at(0)) - ui.kReconcilitorAmountEdit->value() * unit1.Value; 1800 } 1801 1802 // Set tooltip 1803 if (current.isEmpty()) { 1804 ui.kReconciliatorInfo->setText(i18nc("Description", "You must select only one account to use reconciliation.")); 1805 ui.kReconciliatorInfo->setToolTip(ui.kReconciliatorInfo->text()); 1806 } else { 1807 double v1 = SKGServices::stringToDouble(listTmp.at(1).at(0)); 1808 double v2 = SKGServices::stringToDouble(listTmp.at(1).at(1)); 1809 QString sdiff = doc->formatMoney(diff, unit1); 1810 QString s1 = doc->formatMoney(v1, unit1); 1811 QString s2 = doc->formatMoney(v2, unit1); 1812 ui.kReconciliatorInfo->setText(i18nc("Message", "%1 - Delta: %2 Expenditure: %3 Income: %4", unit1.Symbol, sdiff, s1, s2)); 1813 1814 // Comparison 1815 QString zero = doc->formatMoney(0, unit1); 1816 QString negativezero = doc->formatMoney(-EPSILON, unit1); 1817 ui.kValidate->setVisible(sdiff == zero || sdiff == negativezero); 1818 ui.kCreateFakeOperation->setVisible(!ui.kValidate->isVisible()); 1819 ui.kAutoPoint->setVisible(!ui.kValidate->isVisible()); 1820 1821 if (!unit2.Symbol.isEmpty() && (unit2.Value != 0.0)) { 1822 sdiff = doc->formatMoney(diff, unit2); 1823 s1 = doc->formatMoney(v1, unit2); 1824 s2 = doc->formatMoney(v2, unit2); 1825 } 1826 ui.kReconciliatorInfo->setToolTip(i18nc("Message", "<p>Delta: %1</p><p>Expenditure: %2</p><p>Income: %3</p>", sdiff, s1, s2)); 1827 } 1828 } 1829 } 1830 } 1831 } 1832 1833 void SKGOperationPluginWidget::onAccountChanged() 1834 { 1835 SKGTRACEINFUNC(1) 1836 if (!currentAccount().isEmpty() && ui.kOperationView->getView()->getNbSelectedObjects() == 0) { 1837 // Get account object 1838 SKGAccountObject act(getDocument()); 1839 SKGError err = act.setName(currentAccount()); 1840 IFOKDO(err, act.load()) 1841 1842 // Get unit 1843 SKGUnitObject unit; 1844 IFOKDO(err, act.getUnit(unit)) 1845 if (!err && !unit.getSymbol().isEmpty()) { 1846 ui.kUnitEdit->setText(unit.getSymbol()); 1847 } 1848 } 1849 onFilterChanged(); 1850 } 1851 1852 void SKGOperationPluginWidget::onFilterChanged() 1853 { 1854 SKGTRACEINFUNC(1) 1855 if (!isEnabled()) { 1856 return; 1857 } 1858 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 1859 1860 // Enable/ disable widgets 1861 bool onOneAccount = (!currentAccount().isEmpty()); 1862 ui.kReconciliatorFrame2->setEnabled(onOneAccount); 1863 if (!onOneAccount && m_modeInfoZone == 1) { 1864 ui.kReconciliatorFrame2->hide(); 1865 ui.kInfo->show(); 1866 m_modeInfoZone = 0; 1867 } 1868 1869 QString current = currentAccount(); 1870 if (!current.isEmpty() && ui.kOperationView->getView()->getNbSelectedObjects() == 0) { 1871 ui.kAccountEdit->setText(current); 1872 } 1873 1874 QApplication::restoreOverrideCursor(); 1875 } 1876 1877 void SKGOperationPluginWidget::fillNumber() 1878 { 1879 SKGTRACEINFUNC(10) 1880 QStringList list; 1881 QString account = ui.kAccountEdit->text(); 1882 QString wc; 1883 if (!account.isEmpty()) { 1884 wc = "rd_account_id IN (SELECT id FROM account WHERE t_name='" + SKGServices::stringToSqlString(account) + "')"; 1885 } 1886 getDocument()->getDistinctValues(QStringLiteral("v_operation_next_numbers"), QStringLiteral("t_number"), wc, list); 1887 1888 // Fill completion 1889 auto comp = new QCompleter(list); 1890 comp->setFilterMode(Qt::MatchContains); 1891 ui.kNumberEdit->setCompleter(comp); 1892 1893 m_numberFieldIsNotUptodate = false; 1894 } 1895 1896 void SKGOperationPluginWidget::onFocusChanged() 1897 { 1898 _SKGTRACEINFUNC(10) 1899 if (!qApp->closingDown()) { 1900 if ((SKGMainPanel::getMainPanel() != nullptr) && SKGMainPanel::getMainPanel()->currentPage() == this) { 1901 if (m_numberFieldIsNotUptodate && ui.kNumberEdit->hasFocus()) { 1902 fillNumber(); 1903 } 1904 1905 bool test = ui.kTypeEdit->hasFocus() || 1906 // ui.kAmountEdit->hasFocus() || 1907 // ui.kNumberEdit->hasFocus() || 1908 ui.kUnitEdit->hasFocus() || 1909 ui.kCategoryEdit->hasFocus() || 1910 ui.kTrackerEdit->hasFocus() || 1911 ui.kCommentEdit->hasFocus() || 1912 ui.kPayeeEdit->hasFocus(); 1913 if (m_fastEditionAction != nullptr) { 1914 m_fastEditionAction->setEnabled(test); 1915 } 1916 } 1917 } 1918 } 1919 1920 void SKGOperationPluginWidget::onFastEdition() 1921 { 1922 if (SKGMainPanel::getMainPanel()->currentPage() != this) { 1923 return; 1924 } 1925 SKGTRACEINFUNC(10) 1926 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 1927 SKGError err; 1928 1929 // Get widget item 1930 QWidget* w = QApplication::focusWidget(); 1931 auto* cmb = qobject_cast<SKGComboBox*>(w); 1932 if (cmb != nullptr) { 1933 setWidgetEditionEnabled(cmb->lineEdit(), false); 1934 } else { 1935 setWidgetEditionEnabled(w, false); 1936 } 1937 1938 // Build the where clause 1939 QString wc; 1940 if (ui.kTypeEdit->hasFocus()) { 1941 wc = "t_mode LIKE '" % SKGServices::stringToSqlString(ui.kTypeEdit->text()) % "%'"; 1942 } else if (ui.kUnitEdit->hasFocus()) { 1943 wc = "t_UNIT LIKE '" % SKGServices::stringToSqlString(ui.kUnitEdit->text()) % "%'"; 1944 } else if (ui.kCategoryEdit->hasFocus()) { 1945 wc = "t_CATEGORY LIKE '" % SKGServices::stringToSqlString(ui.kCategoryEdit->text()) % "%'"; 1946 } else if (ui.kTrackerEdit->hasFocus()) { 1947 wc = "t_REFUND LIKE '" % SKGServices::stringToSqlString(ui.kTrackerEdit->text()) % "%'"; 1948 } else if (ui.kCommentEdit->hasFocus()) { 1949 wc = "t_comment LIKE '" % SKGServices::stringToSqlString(ui.kCommentEdit->text()) % "%'"; 1950 } else if (ui.kPayeeEdit->hasFocus()) { 1951 wc = "t_PAYEE LIKE '" % SKGServices::stringToSqlString(ui.kPayeeEdit->text()) % "%'"; 1952 } 1953 1954 if (!wc.isEmpty()) { 1955 QString accountName = ui.kAccountEdit->currentText(); 1956 if (!accountName.isEmpty() && skgoperation_settings::oncurrentaccountonly()) { 1957 wc += " AND t_ACCOUNT LIKE '" % SKGServices::stringToSqlString(accountName) % "%'"; 1958 } 1959 1960 // Read Setting 1961 QString fasteditmode = skgoperation_settings::fasteditmode(); 1962 1963 /* 1964 0-Search in templates only 1965 1-Search first in templates and after in transactions 1966 2-Search in transactions only 1967 3-Search first in transactions and after in templates 1968 */ 1969 if (fasteditmode == QStringLiteral("0")) { 1970 wc += QStringLiteral(" AND t_template='Y'"); 1971 } else if (fasteditmode == QStringLiteral("2")) { 1972 wc += QStringLiteral(" AND t_template='N'"); 1973 } 1974 1975 if (wc != m_lastFastEditionWhereClause) { 1976 m_lastFastEditionWhereClause = wc; 1977 m_lastFastEditionOperationFound = 0; 1978 } 1979 1980 // Look for last operation 1981 if (m_lastFastEditionOperationFound != 0) { 1982 wc += " AND id<" % SKGServices::intToString(m_lastFastEditionOperationFound); 1983 } 1984 1985 // Add order by 1986 wc += QStringLiteral(" ORDER BY "); 1987 if (fasteditmode == QStringLiteral("1")) { 1988 wc += QStringLiteral(" t_template DESC, "); 1989 } else if (fasteditmode == QStringLiteral("3")) { 1990 wc += QStringLiteral(" t_template ASC, "); 1991 } 1992 wc += QStringLiteral("d_date DESC, id DESC LIMIT 1"); 1993 1994 SKGObjectBase::SKGListSKGObjectBase transactions; 1995 err = getDocument()->getObjects(QStringLiteral("v_operation_display_all"), wc, transactions); 1996 if (!err && !transactions.isEmpty()) { 1997 SKGOperationObject op(transactions.at(0)); 1998 1999 m_lastFastEditionOperationFound = op.getID(); 2000 if (isWidgetEditionEnabled(ui.kTypeEdit->lineEdit())) { 2001 ui.kTypeEdit->setText(op.getMode()); 2002 } 2003 if (isWidgetEditionEnabled(ui.kUnitEdit->lineEdit())) { 2004 ui.kUnitEdit->setText(op.getAttribute(QStringLiteral("t_UNIT"))); 2005 } 2006 if (isWidgetEditionEnabled(ui.kCategoryEdit->lineEdit())) { 2007 ui.kCategoryEdit->setText(op.getAttribute(QStringLiteral("t_CATEGORY"))); 2008 } 2009 if (isWidgetEditionEnabled(ui.kCommentEdit->lineEdit())) { 2010 ui.kCommentEdit->setText(op.getComment()); 2011 } 2012 if (isWidgetEditionEnabled(ui.kPayeeEdit->lineEdit())) { 2013 ui.kPayeeEdit->setText(op.getAttribute(QStringLiteral("t_PAYEE"))); 2014 } 2015 if (isWidgetEditionEnabled(ui.kTrackerEdit->lineEdit())) { 2016 ui.kTrackerEdit->setText(op.getAttribute(QStringLiteral("t_REFUND"))); 2017 } 2018 if (currentAccount().isEmpty()) { 2019 ui.kAccountEdit->setText(op.getAttribute(QStringLiteral("t_ACCOUNT"))); 2020 } 2021 if (isWidgetEditionEnabled(ui.kAmountEdit)) { 2022 QString quantity = op.getAttribute(QStringLiteral("f_QUANTITY")); 2023 2024 double quantityVal = SKGServices::stringToDouble(quantity); 2025 SKGUnitObject unitObject = ui.kUnitEdit->getUnit(); 2026 int nbDec = unitObject.getNumberDecimal(); 2027 if (nbDec == 0) { 2028 nbDec = 2; 2029 } 2030 quantity = SKGServices::toCurrencyString(qAbs(quantityVal), QLatin1String(""), nbDec); 2031 if (quantity.startsWith(QLocale().positiveSign())) { 2032 quantity = quantity.right(quantity.length() - 1); 2033 } 2034 if (quantityVal > 0) { 2035 quantity = '+' % quantity; 2036 } else { 2037 quantity = '-' % quantity; 2038 } 2039 ui.kAmountEdit->setText(quantity); 2040 } 2041 2042 // set next number 2043 if (isWidgetEditionEnabled(ui.kNumberEdit)) { 2044 int number = SKGServices::stringToInt(op.getNumber()); 2045 if (number == 0) { 2046 ui.kNumberEdit->setText(QLatin1String("")); 2047 } else { 2048 if (m_numberFieldIsNotUptodate) { 2049 fillNumber(); 2050 } 2051 2052 QCompleter* comp = ui.kNumberEdit->completer(); 2053 if (comp != nullptr) { 2054 QStringList list = qobject_cast<QStringListModel*>(comp->model())->stringList(); 2055 int nb = list.count(); 2056 int cpt = 0; 2057 while (nb >= 0 && cpt >= 0 && cpt < 1000) { 2058 ++number; 2059 2060 if (list.contains(SKGServices::intToString(number))) { 2061 cpt = -2; 2062 } 2063 ++cpt; 2064 } 2065 2066 if (cpt < 0) { 2067 ui.kNumberEdit->setText(SKGServices::intToString(number)); 2068 } 2069 } 2070 } 2071 } 2072 2073 // Get nb transaction linked 2074 SKGObjectBase::SKGListSKGObjectBase groupedOperations; 2075 op.getGroupedOperations(groupedOperations); 2076 int nbGroupedOp = groupedOperations.count(); 2077 2078 // Get nb sub op 2079 SKGObjectBase::SKGListSKGObjectBase subOperations; 2080 op.getSubOperations(subOperations); 2081 int nbSupOp = subOperations.count(); 2082 2083 if (nbSupOp > 1) { 2084 // It is a SPLIT operation 2085 ui.kWidgetSelector->setSelectedMode(1); 2086 QDate d = ui.kDateEdit->date(); 2087 if (!d.isValid()) { 2088 d = QDate::currentDate(); 2089 } 2090 displaySubOperations(op, false, d); 2091 2092 } else { 2093 if (nbGroupedOp > 1) { 2094 // It is a TRANSFER 2095 SKGOperationObject op2(groupedOperations.at(0)); 2096 if (op2 == op) { 2097 op2 = groupedOperations.at(1); 2098 } 2099 2100 SKGAccountObject targetAccount; 2101 op2.getParentAccount(targetAccount); 2102 2103 if (isWidgetEditionEnabled(ui.kTargetAccountEdit)) { 2104 ui.kTargetAccountEdit->setText(targetAccount.getName()); 2105 } 2106 } else { 2107 ui.kWidgetSelector->setSelectedMode(0); 2108 } 2109 } 2110 2111 } else { 2112 m_lastFastEditionWhereClause = QLatin1String(""); 2113 m_lastFastEditionOperationFound = 0; 2114 } 2115 } 2116 2117 if (w != nullptr) { 2118 w->setFocus(Qt::OtherFocusReason); 2119 } 2120 QApplication::restoreOverrideCursor(); 2121 2122 // Display error 2123 SKGMainPanel::displayErrorMessage(err); 2124 } 2125 2126 bool SKGOperationPluginWidget::isTemplateMode() 2127 { 2128 QAction* act = ui.kOperationView->getShowWidget()->getAction(QStringLiteral("templates")); 2129 return ((act != nullptr) && act->isChecked()); 2130 } 2131 2132 void SKGOperationPluginWidget::setTemplateMode(bool iTemplate) 2133 { 2134 SKGTRACEINFUNC(10) 2135 2136 if (iTemplate != isTemplateMode()) { 2137 QAction* act = ui.kOperationView->getShowWidget()->getAction(QStringLiteral("templates")); 2138 if (act != nullptr) { 2139 act->setChecked(iTemplate); 2140 } 2141 2142 act = ui.kOperationView->getShowWidget()->getAction(QStringLiteral("transactions")); 2143 if (act != nullptr) { 2144 act->setChecked(!iTemplate); 2145 } 2146 } 2147 } 2148 2149 void SKGOperationPluginWidget::onBtnModeClicked(int mode) 2150 { 2151 SKGTRACEINFUNC(10) 2152 if (mode != 1 && mode != -1) { 2153 ui.kSubOperationsTable->setRowCount(0); 2154 ui.kSubOperationsTable->clearContents(); 2155 } 2156 2157 if (mode == 1) { 2158 if (ui.kSubOperationsTable->rowCount() == 0) { 2159 addSubOperationLine(0, ui.kDateEdit->date(), ui.kCategoryEdit->text(), ui.kTrackerEdit->text(), ui.kCommentEdit->text(), ui.kAmountEdit->value(), nullptr); 2160 } 2161 } 2162 onOperationCreatorModified(); 2163 } 2164 2165 void SKGOperationPluginWidget::displaySubOperations(const SKGOperationObject& iOperation, bool iKeepId, QDate iSubOperationsDate) 2166 { 2167 SKGTRACEINFUNC(10) 2168 ui.kSubOperationsTable->setRowCount(0); 2169 ui.kSubOperationsTable->clearContents(); 2170 2171 int nbSubOperations = 0; 2172 2173 SKGObjectBase::SKGListSKGObjectBase subOperations; 2174 SKGError err = iOperation.getSubOperations(subOperations); 2175 nbSubOperations = subOperations.count(); 2176 for (int i = 0; i < nbSubOperations; ++i) { 2177 SKGSubOperationObject subOperation(subOperations.at(i)); 2178 2179 SKGCategoryObject category; 2180 subOperation.getCategory(category); 2181 2182 SKGTrackerObject tracker; 2183 subOperation.getTracker(tracker); 2184 2185 addSubOperationLine(i, iSubOperationsDate.isValid() ? iSubOperationsDate : subOperation.getDate(), category.getFullName(), tracker.getName(), 2186 subOperation.getComment(), subOperation.getQuantity(), subOperation.getFormula(), 2187 (iKeepId ? subOperation.getID() : 0)); 2188 } 2189 2190 onQuantityChanged(); 2191 } 2192 2193 void SKGOperationPluginWidget::displaySubOperations() 2194 { 2195 SKGTRACEINFUNC(10) 2196 SKGOperationObject operation; 2197 if (getSelectedOperation(operation).isSucceeded()) { 2198 displaySubOperations(operation); 2199 } 2200 } 2201 2202 double SKGOperationPluginWidget::getRemainingQuantity() 2203 { 2204 SKGTRACEINFUNC(10) 2205 double sumQuantities = 0; 2206 int nbSubOperations = ui.kSubOperationsTable->rowCount(); 2207 2208 for (int i = 0; i < nbSubOperations ; ++i) { 2209 QTableWidgetItem* quantityItem = ui.kSubOperationsTable->item(i, m_attributesForSplit.indexOf(QStringLiteral("f_value"))); 2210 if (quantityItem != nullptr) { 2211 sumQuantities = sumQuantities + quantityItem->data(101).toDouble(); 2212 } 2213 } 2214 2215 return ui.kAmountEdit->value() - sumQuantities; 2216 } 2217 2218 void SKGOperationPluginWidget::onDateChanged(QDate iDate) 2219 { 2220 SKGTRACEINFUNC(10) 2221 bool previous = ui.kSubOperationsTable->blockSignals(true); // Disable signals so that filling cell doesn't create new lines 2222 if (sender() == ui.kDateEdit && iDate.isValid() && m_previousDate.isValid()) { 2223 // Refresh dates 2224 int nbSubOperations = ui.kSubOperationsTable->rowCount(); 2225 for (int i = 0; i < nbSubOperations ; ++i) { 2226 QTableWidgetItem* dateItem = ui.kSubOperationsTable->item(i, m_attributesForSplit.indexOf(QStringLiteral("d_date"))); 2227 if (dateItem != nullptr) { 2228 auto datestring = dateItem->toolTip(); 2229 QDate previousSubDate = SKGServices::stringToTime(datestring).date(); 2230 if (previousSubDate.isValid()) { 2231 int delta = m_previousDate.daysTo(iDate); 2232 2233 auto newDate = previousSubDate.addDays(delta); 2234 dateItem->setText(SKGMainPanel::dateToString(newDate)); 2235 dateItem->setToolTip(SKGServices::dateToSqlString(newDate)); 2236 } 2237 } 2238 } 2239 } 2240 m_previousDate = iDate; 2241 ui.kSubOperationsTable->blockSignals(previous); // Reenable signals 2242 } 2243 2244 void SKGOperationPluginWidget::refreshSubOperationAmount() 2245 { 2246 SKGTRACEINFUNC(10) 2247 bool previous = ui.kSubOperationsTable->blockSignals(true); // Disable signals so that filling cell doesn't create new lines 2248 2249 int nbSubOperations = ui.kSubOperationsTable->rowCount(); 2250 2251 // Refresh computed amounts 2252 auto unit = ui.kUnitEdit->getUnit().getUnitInfo(); 2253 unit.Value = 1.0; 2254 for (int i = 0; i < nbSubOperations ; ++i) { 2255 QTableWidgetItem* quantityItem = ui.kSubOperationsTable->item(i, m_attributesForSplit.indexOf(QStringLiteral("f_value"))); 2256 if (quantityItem != nullptr) { 2257 QString formula = quantityItem->toolTip(); 2258 if (formula.startsWith(QLatin1String("="))) { 2259 formula = formula.right(formula.length() - 1); 2260 formula.replace(',', '.'); // Replace comma by a point in case of typo 2261 formula.remove(' '); 2262 formula.replace(QStringLiteral("total"), SKGServices::doubleToString(ui.kAmountEdit->value())); 2263 2264 QScriptEngine myEngine; 2265 QScriptValue result = myEngine.evaluate(formula); 2266 if (result.isNumber()) { 2267 auto value = result.toNumber(); 2268 quantityItem->setText(getDocument()->formatMoney(value, unit, false)); 2269 quantityItem->setData(101, value); 2270 } 2271 } else { 2272 auto value = quantityItem->data(101).toDouble(); 2273 quantityItem->setText(getDocument()->formatMoney(value, unit, false)); 2274 } 2275 } 2276 } 2277 ui.kSubOperationsTable->blockSignals(previous); // Reenable signals 2278 } 2279 2280 void SKGOperationPluginWidget::onQuantityChanged() 2281 { 2282 SKGTRACEINFUNC(10) 2283 int nbSubOperations = ui.kSubOperationsTable->rowCount(); 2284 2285 bool previous = ui.kSubOperationsTable->blockSignals(true); // Disable signals so that filling cell doesn't create new lines 2286 if (sender() == ui.kAmountEdit) { 2287 // Update the total amount 2288 m_tableDelegate->addParameterValue(QStringLiteral("total"), ui.kAmountEdit->value()); 2289 2290 // Refresh computed amounts 2291 refreshSubOperationAmount(); 2292 } 2293 2294 // This code put the remaining quantity on the all sub transactions with the same ratios ^^^ 2295 // Specific code for the last one to avoid "round" error 2296 QTableWidgetItem* remainingQuantityItem = ui.kSubOperationsTable->item(nbSubOperations - 1, m_attributesForSplit.indexOf(QStringLiteral("f_value"))); 2297 if (remainingQuantityItem != nullptr) { 2298 // 348490 vvv 2299 double remain = remainingQuantityItem->data(101).toDouble() + getRemainingQuantity(); 2300 if (qAbs(remain) < 1e-10) { 2301 onRemoveSubOperation(nbSubOperations - 1); 2302 } else { 2303 auto unit = ui.kUnitEdit->getUnit().getUnitInfo(); 2304 unit.Value = 1.0; 2305 remainingQuantityItem->setText(getDocument()->formatMoney(remain, unit, false)); 2306 remainingQuantityItem->setData(101, remain); 2307 remainingQuantityItem->setToolTip(SKGServices::doubleToString(remain)); 2308 } 2309 // 348490 ^^^ 2310 } 2311 ui.kSubOperationsTable->blockSignals(previous); // Reenable signals 2312 } 2313 2314 void SKGOperationPluginWidget::onSubopCellChanged(int row, int column) 2315 { 2316 SKGTRACEINFUNC(10) 2317 QTableWidgetItem* subop_cell = ui.kSubOperationsTable->item(row, column); 2318 QBrush base_brush = ui.kSubOperationsTable->item(row, 0)->foreground(); 2319 2320 if (column == m_attributesForSplit.indexOf(QStringLiteral("f_value"))) { 2321 // If the quantity in the last line is edited, we add a new 2322 // line with the new remaining quantity 2323 addSubOperationLine(ui.kSubOperationsTable->rowCount(), ui.kDateEdit->date(), QLatin1String(""), 2324 QLatin1String(""), QLatin1String(""), 0, QLatin1String("")); 2325 2326 if (subop_cell->data(101).toDouble() != 0) { 2327 onQuantityChanged(); 2328 } else { 2329 base_brush = KColorScheme(QPalette::Normal).foreground(KColorScheme::NegativeText); 2330 } 2331 subop_cell->setForeground(base_brush); 2332 2333 refreshSubOperationAmount(); 2334 } 2335 } 2336 2337 void SKGOperationPluginWidget::onRemoveSubOperation(int iRow) 2338 { 2339 SKGTRACEINFUNC(10) 2340 bool previous = ui.kSubOperationsTable->blockSignals(true); 2341 ui.kSubOperationsTable->removeRow(iRow); 2342 2343 // If all rows removed, add an empty line 2344 if (ui.kSubOperationsTable->rowCount() == 0) { 2345 addSubOperationLine(0, ui.kDateEdit->date(), QLatin1String(""), QLatin1String(""), QLatin1String(""), 0, QLatin1String("")); 2346 } 2347 2348 if (!previous) { 2349 onQuantityChanged(); 2350 } 2351 ui.kSubOperationsTable->blockSignals(previous); 2352 } 2353 2354 void SKGOperationPluginWidget::onRotateAccountTools() 2355 { 2356 SKGTRACEINFUNC(10) 2357 if (m_modeInfoZone == 0) { 2358 displayReconciliationInfo(); 2359 } else { 2360 displayBalance(); 2361 } 2362 } 2363 2364 2365 void SKGOperationPluginWidget::displayBalance() 2366 { 2367 if (m_modeInfoZone != 0) { 2368 ui.kReconciliatorFrame2->hide(); 2369 ui.kInfo->show(); 2370 m_modeInfoZone = 0; 2371 onRefreshInformationZoneDelayed(); 2372 } 2373 } 2374 2375 void SKGOperationPluginWidget::displayReconciliationInfo() 2376 { 2377 if (!currentAccount().isEmpty()) { 2378 // Only show reconciliation info if only one account is displayed 2379 ui.kReconciliatorFrame2->show(); 2380 ui.kInfo->hide(); 2381 m_modeInfoZone = 1; 2382 onRefreshInformationZoneDelayed(); 2383 } else { 2384 // If more than one account is displayed, skip reconciliation mode 2385 // (it doesn't make sense to reconcile several accounts at once) 2386 // and move to the next modeInfoZone 2387 m_modeInfoZone = 1; 2388 onRotateAccountTools(); 2389 } 2390 } 2391 2392 void SKGOperationPluginWidget::onAutoPoint() 2393 { 2394 SKGError err; 2395 SKGTRACEINFUNCRC(10, err) 2396 2397 { 2398 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Auto mark account"), err) 2399 SKGAccountObject act(getDocument()); 2400 err = act.setName(currentAccount()); 2401 IFOKDO(err, act.load()) 2402 IFOKDO(err, act.autoReconcile(ui.kReconcilitorAmountEdit->value())) 2403 2404 // Send message 2405 IFOKDO(err, act.getDocument()->sendMessage(i18nc("An information message", "The account '%1' has been auto marked", act.getDisplayName()), SKGDocument::Hidden)) 2406 } 2407 // status bar 2408 IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Account auto marked."))) 2409 2410 // Display error 2411 SKGMainPanel::displayErrorMessage(err); 2412 } 2413 2414 void SKGOperationPluginWidget::onAddFakeOperation() 2415 { 2416 SKGError err; 2417 SKGTRACEINFUNCRC(10, err) { 2418 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Create fake transaction"), err) 2419 2420 SKGAccountObject accountObj(getDocument()); 2421 IFOKDO(err, accountObj.setName(currentAccount())) 2422 IFOKDO(err, accountObj.load()) 2423 2424 SKGOperationObject op; 2425 IFOKDO(err, accountObj.addOperation(op)) 2426 IFOKDO(err, op.setDate(QDate::currentDate())) 2427 IFOKDO(err, op.setComment(skgoperation_settings::commentFakeOperation())) 2428 QString payee = skgoperation_settings::payeeFakeOperation(); 2429 if (!payee.isEmpty()) { 2430 SKGPayeeObject p; 2431 IFOKDO(err, SKGPayeeObject::createPayee(qobject_cast<SKGDocumentBank*>(getDocument()), payee, p, true)) 2432 IFOKDO(err, op.setPayee(p)) 2433 } 2434 2435 SKGUnitObject unit; 2436 IFOKDO(err, accountObj.getUnit(unit)) 2437 IFOKDO(err, op.setUnit(unit)) 2438 if (skgoperation_settings::automaticPointInReconciliation() && m_modeInfoZone == 1) { 2439 IFOKDO(err, op.setStatus(SKGOperationObject::MARKED)) 2440 } 2441 IFOKDO(err, op.save()) 2442 2443 SKGSubOperationObject sop; 2444 IFOKDO(err, op.addSubOperation(sop)) 2445 2446 SKGStringListList listTmp2; 2447 double diff = 0; 2448 getDocument()->executeSelectSqliteOrder( 2449 "SELECT f_CHECKEDANDPOINTED from v_account_display WHERE t_name='" % SKGServices::stringToSqlString(currentAccount()) % '\'', 2450 listTmp2); 2451 if (listTmp2.count() == 2) { 2452 diff = SKGServices::stringToDouble(listTmp2.at(1).at(0)) / unit.getAmount() - ui.kReconcilitorAmountEdit->value(); 2453 } 2454 2455 IFOKDO(err, sop.setQuantity(-diff)) 2456 IFOKDO(err, sop.setComment(skgoperation_settings::commentFakeOperation())) 2457 QString category = skgoperation_settings::categoryFakeOperation(); 2458 if (!category.isEmpty()) { 2459 SKGCategoryObject c; 2460 IFOKDO(err, SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), category, c, true)) 2461 IFOKDO(err, sop.setCategory(c)) 2462 } 2463 IFOKDO(err, sop.save()) 2464 2465 // Send message 2466 IFOKDO(err, op.getDocument()->sendMessage(i18nc("An information to the user that something was added", "The transaction '%1' has been added", op.getDisplayName()), SKGDocument::Hidden)) 2467 } 2468 2469 // status bar 2470 IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Fake transaction created."))) 2471 else { 2472 err.addError(ERR_FAIL, i18nc("Error message", "Creation failed")); 2473 } 2474 2475 // Display error 2476 SKGMainPanel::displayErrorMessage(err); 2477 } 2478 2479 2480 void SKGOperationPluginWidget::onValidateMarkedOperations() 2481 { 2482 SKGError err; 2483 SKGTRACEINFUNCRC(10, err) 2484 2485 QString account = currentAccount(); 2486 if (!account.isEmpty()) { 2487 // Get reconciled account 2488 SKGAccountObject act(getDocument()); 2489 IFOKDO(err, act.setName(account)) 2490 IFOKDO(err, act.load()) 2491 2492 QString bindAccount = ui.kReconciliateAccount->currentText(); 2493 2494 if (act.getType() == SKGAccountObject::CREDITCARD && !bindAccount.isEmpty()) { 2495 // 2496 IFOK(err) { 2497 SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Switch to checked"), err, 3) 2498 SKGAccountObject accountObj2(getDocument()); 2499 IFOKDO(err, accountObj2.setName(bindAccount)) 2500 IFOKDO(err, accountObj2.load()) 2501 IFOKDO(err, getDocument()->stepForward(1)) 2502 2503 IFOKDO(err, act.transferDeferredOperations(accountObj2)) 2504 IFOKDO(err, getDocument()->stepForward(2)) 2505 2506 // Change reconciliation date of the account 2507 IFOKDO(err, act.setReconciliationDate(QDate::currentDate())) 2508 IFOKDO(err, act.setReconciliationBalance(ui.kReconcilitorAmountEdit->value())) 2509 IFOKDO(err, act.setLinkedAccount(accountObj2)) 2510 IFOKDO(err, act.save()) 2511 2512 // Send message 2513 IFOKDO(err, act.getDocument()->sendMessage(i18nc("An information message", "The account '%1' is reconciled", act.getDisplayName()), SKGDocument::Positive)) 2514 2515 IFOKDO(err, getDocument()->stepForward(3)) 2516 } 2517 } else { 2518 // Change state of all transactions 2519 SKGObjectBase::SKGListSKGObjectBase list; 2520 IFOKDO(err, getDocument()->getObjects(QStringLiteral("v_operation_display"), "t_status='P' AND t_ACCOUNT='" % SKGServices::stringToSqlString(account) % '\'', list)) 2521 int nb = list.count(); 2522 IFOK(err) { 2523 SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Switch to checked"), err, nb + 1) 2524 2525 if (act.getType() == SKGAccountObject::CREDITCARD && bindAccount.isEmpty()) { 2526 // Reset the linked account 2527 IFOKDO(err, act.setLinkedAccount(SKGAccountObject())) 2528 IFOKDO(err, act.save()) 2529 } 2530 2531 for (int i = 0; !err && i < nb; ++i) { 2532 // Set transaction checked 2533 SKGOperationObject op(list.at(i)); 2534 err = op.setStatus(SKGOperationObject::CHECKED); 2535 IFOKDO(err, op.save()) 2536 2537 // Send message 2538 IFOKDO(err, op.getDocument()->sendMessage(i18nc("An information message", "The transaction '%1' has been checked", op.getDisplayName()), SKGDocument::Hidden)) 2539 2540 IFOKDO(err, getDocument()->stepForward(i + 1)) 2541 } 2542 2543 // Change reconciliation date of the account 2544 IFOKDO(err, act.setReconciliationDate(QDate::currentDate())) 2545 IFOKDO(err, act.setReconciliationBalance(ui.kReconcilitorAmountEdit->value())) 2546 IFOKDO(err, act.save()) 2547 2548 // Send message 2549 IFOKDO(err, act.getDocument()->sendMessage(i18nc("An information message", "The account '%1' is reconciled", act.getDisplayName()), SKGDocument::Positive)) 2550 2551 IFOKDO(err, getDocument()->stepForward(nb + 1)) 2552 } 2553 } 2554 } 2555 2556 // status bar 2557 IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Transaction checked."))) 2558 else { 2559 err.addError(ERR_FAIL, i18nc("Error message", "Switch failed")); 2560 } 2561 2562 // Display error 2563 SKGMainPanel::displayErrorMessage(err); 2564 } 2565 2566 void SKGOperationPluginWidget::addSubOperationLine(int row, QDate date, const QString& category, const QString& tracker, const QString& comment, double quantity, const QString& formula, int id) 2567 { 2568 SKGTRACEINFUNC(10) 2569 bool previous = ui.kSubOperationsTable->blockSignals(true); 2570 2571 ui.kSubOperationsTable->insertRow(row); 2572 2573 // Add a delete icon on the line: 2574 auto hitem = new QTableWidgetItem(SKGServices::fromTheme(QStringLiteral("edit-delete")), QLatin1String("")); 2575 ui.kSubOperationsTable->setVerticalHeaderItem(row, hitem); 2576 QHeaderView* headerView = ui.kSubOperationsTable->verticalHeader(); 2577 headerView->setSectionsMovable(true); 2578 2579 // Category 2580 auto categoryItem = new QTableWidgetItem(category); 2581 categoryItem->setToolTip(category); 2582 categoryItem->setData(Qt::UserRole, id); 2583 ui.kSubOperationsTable->setItem(row, m_attributesForSplit.indexOf(QStringLiteral("t_category")), categoryItem); 2584 2585 // Comment 2586 auto commentItem = new QTableWidgetItem(comment); 2587 commentItem->setToolTip(comment); 2588 ui.kSubOperationsTable->setItem(row, m_attributesForSplit.indexOf(QStringLiteral("t_comment")), commentItem); 2589 2590 // Quantity 2591 auto unit = ui.kUnitEdit->getUnit().getUnitInfo(); 2592 unit.Value = 1.0; 2593 auto quantityItem = new QTableWidgetItem(getDocument()->formatMoney(quantity, unit, false)); 2594 quantityItem->setTextAlignment(Qt::AlignVCenter | Qt::AlignRight); 2595 quantityItem->setData(101, quantity); 2596 quantityItem->setToolTip(formula.isEmpty() ? SKGServices::doubleToString(quantity) : formula); 2597 ui.kSubOperationsTable->setItem(row, m_attributesForSplit.indexOf(QStringLiteral("f_value")), quantityItem); 2598 2599 // Refund 2600 auto trackerItem = new QTableWidgetItem(tracker); 2601 trackerItem->setToolTip(tracker); 2602 categoryItem->setData(Qt::UserRole, id); 2603 ui.kSubOperationsTable->setItem(row, m_attributesForSplit.indexOf(QStringLiteral("t_refund")), trackerItem); 2604 2605 // Date 2606 auto dateItem = new QTableWidgetItem(SKGMainPanel::dateToString(date)); 2607 dateItem->setToolTip(SKGServices::dateToSqlString(date)); 2608 ui.kSubOperationsTable->setItem(row, m_attributesForSplit.indexOf(QStringLiteral("d_date")), dateItem); 2609 2610 ui.kSubOperationsTable->blockSignals(previous); 2611 2612 ui.kSubOperationsTable->resizeColumnsToContents(); 2613 ui.kSubOperationsTable->horizontalHeader()->setStretchLastSection(true); 2614 if (row == 0 && category.isEmpty()) { 2615 ui.kSubOperationsTable->horizontalHeader()->resizeSection(0, 300); 2616 } 2617 } 2618 2619 QWidget* SKGOperationPluginWidget::mainWidget() 2620 { 2621 return ui.kOperationView->getView(); 2622 } 2623 2624 SKGError SKGOperationPluginWidget::getSelectedOperation(SKGOperationObject& operation) 2625 { 2626 SKGError err; 2627 SKGObjectBase::SKGListSKGObjectBase selectedOperations = getSelectedObjects(); 2628 if (!selectedOperations.isEmpty()) { 2629 operation = selectedOperations.at(0); 2630 err.setReturnCode(0); 2631 } else { 2632 err.setReturnCode(1).setMessage(i18nc("Error message", "No Transaction Selected")); 2633 } 2634 return err; 2635 } 2636 2637 void SKGOperationPluginWidget::cleanEditor() 2638 { 2639 if (getNbSelectedObjects() == 0 || sender() == ui.kCleanBtn) { 2640 ui.kOperationView->getView()->clearSelection(); 2641 ui.kDateEdit->setDate(QDate::currentDate()); 2642 ui.kPayeeEdit->setText(QLatin1String("")); 2643 ui.kCategoryEdit->setText(QLatin1String("")); 2644 ui.kTrackerEdit->setText(QLatin1String("")); 2645 ui.kAmountEdit->setText(QLatin1String("")); 2646 ui.kTypeEdit->setText(QLatin1String("")); 2647 ui.kCommentEdit->setText(QLatin1String("")); 2648 ui.kNumberEdit->setText(QLatin1String("")); 2649 2650 if (!currentAccount().isEmpty()) { 2651 ui.kAccountEdit->setText(currentAccount()); 2652 } 2653 2654 // BUG 376025 vvvv 2655 ui.kUnitEdit->setDocument(qobject_cast<SKGDocumentBank*>(getDocument())); 2656 // BUG 376025 ^^^^ 2657 ui.kUnitShare->setDocument(qobject_cast<SKGDocumentBank*>(getDocument())); 2658 2659 setAllWidgetsEnabled(); 2660 m_previousDate = QDate::currentDate(); 2661 } 2662 if (sender() == ui.kCleanBtn) { 2663 ui.kWidgetSelector->setSelectedMode(0); 2664 } 2665 } 2666 2667 bool SKGOperationPluginWidget::isEditor() 2668 { 2669 return true; 2670 } 2671 2672 void SKGOperationPluginWidget::activateEditor() 2673 { 2674 if (ui.kWidgetSelector->getSelectedMode() == -1) { 2675 ui.kWidgetSelector->setSelectedMode(0); 2676 } 2677 ui.kPayeeEdit->setFocus(); 2678 }