File indexing completed on 2024-04-28 16:30:13

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 defines classes SKGRuleObject.
0008  *
0009  *
0010  * @author Stephane MANKOWSKI / Guillaume DE BURE
0011  */
0012 #include "skgruleobject.h"
0013 
0014 #include <klocalizedstring.h>
0015 
0016 #include <qdom.h>
0017 
0018 #include "skgdocumentbank.h"
0019 #include "skgoperationobject.h"
0020 #include "skgtraces.h"
0021 #include "skgtransactionmng.h"
0022 #include "skgunitvalueobject.h"
0023 
0024 SKGRuleObject::SKGRuleObject() : SKGRuleObject(nullptr)
0025 {}
0026 
0027 SKGRuleObject::SKGRuleObject(SKGDocument* iDocument, int iID) : SKGObjectBase(iDocument, QStringLiteral("v_rule"), iID)
0028 {}
0029 
0030 SKGRuleObject::SKGRuleObject(const SKGRuleObject& iObject) = default;
0031 
0032 SKGRuleObject::SKGRuleObject(const SKGObjectBase& iObject)
0033 {
0034     if (iObject.getRealTable() == QStringLiteral("rule")) {
0035         copyFrom(iObject);
0036     } else {
0037         *this = SKGObjectBase(iObject.getDocument(), QStringLiteral("v_rule"), iObject.getID());
0038     }
0039 }
0040 
0041 SKGRuleObject& SKGRuleObject::operator= (const SKGObjectBase& iObject)
0042 {
0043     copyFrom(iObject);
0044     return *this;
0045 }
0046 
0047 SKGRuleObject& SKGRuleObject::operator= (const SKGRuleObject& iObject)
0048 {
0049     copyFrom(iObject);
0050     return *this;
0051 }
0052 
0053 SKGRuleObject::~SKGRuleObject()
0054     = default;
0055 
0056 QString SKGRuleObject::getDisplayName() const
0057 {
0058     return getSearchDescription();
0059 }
0060 
0061 SKGError SKGRuleObject::bookmark(bool iBookmark)
0062 {
0063     return setAttribute(QStringLiteral("t_bookmarked"), iBookmark ? QStringLiteral("Y") : QStringLiteral("N"));
0064 }
0065 
0066 bool SKGRuleObject::isBookmarked() const
0067 {
0068     return getAttribute(QStringLiteral("t_bookmarked")) == QStringLiteral("Y");
0069 }
0070 
0071 SKGError SKGRuleObject::save(bool iInsertOrUpdate, bool iReloadAfterSave)
0072 {
0073     // Do the save
0074     SKGError err = SKGObjectBase::save(iInsertOrUpdate, iReloadAfterSave);
0075 
0076     // Raise alarm
0077     if (!err && getActionType() == ALARM) {
0078         err = execute();
0079     }
0080 
0081     return err;
0082 }
0083 
0084 SKGError SKGRuleObject::setXMLSearchDefinition(const QString& iXml)
0085 {
0086     setSearchDescription(SKGRuleObject::getDescriptionFromXML(getDocument(), iXml, false, SEARCH));
0087     return setAttribute(QStringLiteral("t_definition"), iXml);
0088 }
0089 
0090 QString SKGRuleObject::getXMLSearchDefinition() const
0091 {
0092     return getAttribute(QStringLiteral("t_definition"));
0093 }
0094 
0095 SKGError SKGRuleObject::setXMLActionDefinition(const QString& iXml)
0096 {
0097     setActionDescription(SKGRuleObject::getDescriptionFromXML(getDocument(), iXml, false, getActionType()));
0098     return setAttribute(QStringLiteral("t_action_definition"), iXml);
0099 }
0100 
0101 QString SKGRuleObject::getXMLActionDefinition() const
0102 {
0103     return getAttribute(QStringLiteral("t_action_definition"));
0104 }
0105 
0106 SKGError SKGRuleObject::setSearchDescription(const QString& iDescription)
0107 {
0108     return setAttribute(QStringLiteral("t_description"), iDescription);
0109 }
0110 
0111 QString SKGRuleObject::getSearchDescription() const
0112 {
0113     return getAttribute(QStringLiteral("t_description"));
0114 }
0115 
0116 SKGError SKGRuleObject::setActionDescription(const QString& iDescription)
0117 {
0118     return setAttribute(QStringLiteral("t_action_description"), iDescription);
0119 }
0120 
0121 QString SKGRuleObject::getActionDescription() const
0122 {
0123     return getAttribute(QStringLiteral("t_action_description"));
0124 }
0125 
0126 SKGError SKGRuleObject::setActionType(SKGRuleObject::ActionType iType)
0127 {
0128     SKGError err = setAttribute(QStringLiteral("t_action_type"),
0129                                 (iType == SEARCH ? QStringLiteral("S") :
0130                                  (iType == UPDATE ? QStringLiteral("U") :
0131                                   (iType == APPLYTEMPLATE ? QStringLiteral("T") :
0132                                    QStringLiteral("A")))));
0133     return err;
0134 }
0135 
0136 SKGRuleObject::ActionType SKGRuleObject::getActionType() const
0137 {
0138     QString typeString = getAttribute(QStringLiteral("t_action_type"));
0139     return (typeString == QStringLiteral("S") ? SEARCH :
0140             (typeString == QStringLiteral("U") ? UPDATE :
0141              (typeString == QStringLiteral("T") ? APPLYTEMPLATE :
0142               ALARM)));
0143 }
0144 
0145 SKGError SKGRuleObject::setOrder(double iOrder)
0146 {
0147     SKGError err;
0148     double order = iOrder;
0149     if (order == -1) {
0150         order = 1;
0151         SKGStringListList result;
0152         err = getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT max(f_sortorder) from rule"), result);
0153         if (!err && result.count() == 2) {
0154             order = SKGServices::stringToDouble(result.at(1).at(0)) + 1;
0155         }
0156     }
0157     IFOKDO(err, setAttribute(QStringLiteral("f_sortorder"), SKGServices::doubleToString(order)))
0158     return err;
0159 }
0160 
0161 QString SKGRuleObject::getSelectSqlOrder(const QString& iAdditionalCondition) const
0162 {
0163     QString wc = iAdditionalCondition;
0164     QString wc2 = SKGRuleObject::getDescriptionFromXML(getDocument(), getXMLSearchDefinition(), true, SEARCH);
0165     if (!wc2.isEmpty()) {
0166         if (wc.isEmpty()) {
0167             wc = wc2;
0168         } else {
0169             wc = '(' % wc % ") AND (" % wc2 % ')';
0170         }
0171     }
0172     if (wc.isEmpty()) {
0173         wc = QStringLiteral("1=1");
0174     }
0175     wc = "t_template='N' AND d_date!='0000-00-00' AND (" % wc % ')';
0176     return wc;
0177 }
0178 
0179 SKGRuleObject::SKGAlarmInfo SKGRuleObject::getAlarmInfo() const
0180 {
0181     SKGTRACEINFUNC(10)
0182     SKGRuleObject::SKGAlarmInfo alarm;
0183     alarm.Raised = false;
0184     alarm.Message = QLatin1String("");
0185     alarm.Amount = 0.0;
0186     alarm.Limit = 0.0;
0187     if (getActionType() == SKGRuleObject::ALARM) {
0188         // Alarm mode
0189         QString wc = getSelectSqlOrder();
0190         if (wc.isEmpty()) {
0191             wc = QStringLiteral("1=1");
0192         }
0193 
0194         SKGDocument* doc = getDocument();
0195 
0196         QStringList list = SKGRuleObject::getFromXML(doc, getXMLActionDefinition(), true, ALARM, false);
0197         if (!list.isEmpty()) {
0198             QString sql = list.at(0);
0199             sql.replace(QStringLiteral("#WC#"), wc);
0200 
0201             SKGStringListList result;
0202             doc->executeSelectSqliteOrder(sql, result);
0203             if (result.count() == 2) {
0204                 const auto& r = result.at(1);
0205                 alarm.Raised = (r.at(0) == QStringLiteral("1"));
0206                 alarm.Message = r.at(3);
0207                 alarm.Amount = SKGServices::stringToDouble(r.at(1));
0208                 alarm.Limit = SKGServices::stringToDouble(r.at(2));
0209             }
0210         }
0211     }
0212     return alarm;
0213 }
0214 
0215 SKGError SKGRuleObject::execute(ProcessMode iMode)
0216 {
0217     SKGError err;
0218     SKGTRACEINFUNCRC(10, err)
0219     if (getActionType() == SKGRuleObject::UPDATE) {
0220         // Update mode
0221         QString addSql;
0222         if (iMode == IMPORTED) {
0223             addSql = QStringLiteral("t_imported!='N'");
0224         } else if (iMode == IMPORTEDNOTVALIDATE) {
0225             addSql = QStringLiteral("t_imported='P'");
0226         } else if (iMode == IMPORTING) {
0227             addSql = QStringLiteral("t_imported='T'");
0228         } else if (iMode == NOTCHECKED) {
0229             addSql = QStringLiteral("t_status!='Y'");
0230         }
0231         QString wc = getSelectSqlOrder(addSql);
0232 
0233         SKGDocument* doc = getDocument();
0234         if (doc != nullptr) {
0235             QStringList list = SKGRuleObject::getFromXML(doc, getXMLActionDefinition(), true, UPDATE, true);  // SQL + SET clause
0236             int nb = list.count();
0237             err = doc->beginTransaction("#INTERNAL#" % i18nc("Progression step", "Apply rule"), nb);
0238             IFOK(err) {
0239                 // All sql orders must be executed to be sure than i_tmp is reset
0240                 SKGError err2;
0241                 for (int i = 0; i < nb; ++i) {
0242                     QString sql = list.at(i);
0243                     sql.replace(QStringLiteral("#WC#"), wc);
0244                     err2 = doc->executeSqliteOrder(sql);
0245                     if (!err2) {
0246                         err2 = doc->stepForward(i + 1);
0247                     }
0248                     if (err2 && !err) {
0249                         err = err2;
0250                     }
0251                 }
0252             }
0253 
0254             IFOK(err) {
0255                 SKGStringListList result;
0256                 err = doc->executeSelectSqliteOrder(QStringLiteral("SELECT changes()"), result);
0257                 if (!err && result.count() == 2) {
0258                     int nbChanges = SKGServices::stringToInt(result.at(1).at(0));
0259                     if (nbChanges != 0) {
0260                         doc->sendMessage(i18np("1 transaction modified by %2", "%1 transactions modified by %2", nbChanges, getAttribute(QStringLiteral("i_ORDER"))));
0261                     }
0262                 }
0263             }
0264 
0265             SKGENDTRANSACTION(doc,  err)
0266         }
0267     } else if (getActionType() == SKGRuleObject::ALARM) {
0268         // Alarm mode
0269         auto doc = qobject_cast<SKGDocumentBank*>(getDocument());
0270         if (doc != nullptr) {
0271             SKGRuleObject::SKGAlarmInfo alarm = getAlarmInfo();
0272             if (!alarm.Message.isEmpty()) {
0273                 SKGServices::SKGUnitInfo unit = doc->getPrimaryUnit();
0274 
0275                 // Build the message
0276                 if (alarm.Message.contains(QLatin1String("%3"))) {
0277                     alarm.Message = alarm.Message.arg(doc->formatMoney(alarm.Amount, unit, false), doc->formatMoney(alarm.Limit, unit, false), doc->formatMoney(alarm.Amount - alarm.Limit, unit, false));
0278                 } else if (alarm.Message.contains(QLatin1String("%2"))) {
0279                     alarm.Message = alarm.Message.arg(doc->formatMoney(alarm.Amount, unit, false), doc->formatMoney(alarm.Limit, unit, false));
0280                 } else if (alarm.Message.contains(QLatin1String("%1"))) {
0281                     alarm.Message = alarm.Message.arg(doc->formatMoney(alarm.Amount, unit, false));
0282                 }
0283                 getDocument()->sendMessage(alarm.Message);
0284             }
0285         }
0286     } else if (getActionType() == SKGRuleObject::APPLYTEMPLATE) {
0287         // Template mode
0288         QString addSql;
0289         if (iMode == IMPORTED) {
0290             addSql = QStringLiteral("t_imported!='N'");
0291         } else if (iMode == IMPORTEDNOTVALIDATE) {
0292             addSql = QStringLiteral("t_imported='P'");
0293         } else if (iMode == IMPORTING) {
0294             addSql = QStringLiteral("t_imported='T'");
0295         }
0296         QString wc = getSelectSqlOrder(addSql);
0297 
0298         auto doc = qobject_cast<SKGDocumentBank*>(getDocument());
0299         if (doc != nullptr) {
0300             QStringList list = SKGRuleObject::getFromXML(doc, getXMLActionDefinition(), true, APPLYTEMPLATE, false);
0301             if (!list.isEmpty()) {
0302                 const QString& id = list.at(0);
0303 
0304                 // Get template
0305                 SKGOperationObject templateToApply(doc, SKGServices::stringToInt(id));
0306 
0307                 // Get transactions to modify
0308                 SKGObjectBase::SKGListSKGObjectBase objectsToModify;
0309                 IFOKDO(err, doc->getObjects(QStringLiteral("v_operation_prop"), wc, objectsToModify))
0310                 int nb = objectsToModify.count();
0311                 for (int i = 0; !err && i < nb; ++i) {
0312                     SKGOperationObject operationObj(doc, SKGServices::stringToInt(objectsToModify.at(i).getAttribute(QStringLiteral("i_OPID"))));
0313 
0314                     SKGOperationObject op;
0315                     IFOKDO(err, templateToApply.duplicate(op))
0316                     IFOKDO(err, op.mergeAttribute(operationObj, SKGOperationObject::PROPORTIONAL, false))
0317                 }
0318             }
0319         }
0320     }
0321     IFKO(err) err.addError(ERR_FAIL, i18nc("Error message", "Rule %1 failed", getAttribute(QStringLiteral("i_ORDER"))));
0322     return err;
0323 }
0324 
0325 double SKGRuleObject::getOrder() const
0326 {
0327     return SKGServices::stringToDouble(getAttribute(QStringLiteral("f_sortorder")));
0328 }
0329 
0330 QString SKGRuleObject::getDisplayForOperator(const QString& iOperator, const QString& iParam1, const QString& iParam2, const QString& iAtt2)
0331 {
0332     QString output = iOperator;
0333     if (output == QStringLiteral("#ATT# LIKE '%#V1S#%'")) {
0334         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "contains '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0335     } else if (output == QStringLiteral("#ATT# NOT LIKE '%#V1S#%'")) {
0336         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "does not contain '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0337     } else if (output == QStringLiteral("#ATT# LIKE '#V1S#%'")) {
0338         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "starts with '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0339     } else if (output == QStringLiteral("#ATT# NOT LIKE '#V1S#%'")) {
0340         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "does not start with '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0341     } else if (output == QStringLiteral("#ATT# LIKE '%#V1S#'")) {
0342         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "ends with '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0343     } else if (output == QStringLiteral("#ATT# NOT LIKE '%#V1S#'")) {
0344         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "does not end with '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0345     } else if (output == QStringLiteral("#ATT#=''")) {
0346         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is empty");
0347     } else if (output == QStringLiteral("#ATT#!=''")) {
0348         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is not empty");
0349     } else if (output == QStringLiteral("#ATT#=REGEXPCAPTURE('#V1S#', #ATT2#, #V2#)")) {
0350         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=regexpcapture(#ATT2#, '#V1S#', #V2#)").replace(QStringLiteral("#V1S#"), iParam1).replace(QStringLiteral("#V2#"), iParam2).replace(QStringLiteral("#ATT2#"), iAtt2);
0351     } else if (output == QStringLiteral("REGEXP('#V1S#', #ATT#)")) {
0352         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "regexp '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0353     } else if (output == QStringLiteral("NOT(REGEXP('#V1S#', #ATT#))")) {
0354         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "not regexp '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0355     } else if (output == QStringLiteral("WILDCARD('#V1S#', #ATT#)")) {
0356         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "wildcard '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0357     } else if (output == QStringLiteral("NOT(WILDCARD('#V1S#', #ATT#))")) {
0358         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "not wildcard '#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0359     } else if (output == QStringLiteral("#ATT#=#V1#")) {
0360         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=#V1#").replace(QStringLiteral("#V1#"), iParam1);
0361     } else if (output == QStringLiteral("#ATT#!=#V1#")) {
0362         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "!=#V1#").replace(QStringLiteral("#V1#"), iParam1);
0363     } else if (output == QStringLiteral("#ATT#>#V1#")) {
0364         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", ">#V1#").replace(QStringLiteral("#V1#"), iParam1);
0365     } else if (output == QStringLiteral("#ATT#<#V1#")) {
0366         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "<#V1#").replace(QStringLiteral("#V1#"), iParam1);
0367     } else if (output == QStringLiteral("#ATT#>=#V1#")) {
0368         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", ">=#V1#").replace(QStringLiteral("#V1#"), iParam1);
0369     } else if (output == QStringLiteral("#ATT#<=#V1#")) {
0370         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "<=#V1#").replace(QStringLiteral("#V1#"), iParam1);
0371     } else if (output == QStringLiteral("#ATT#='#V1S#'")) {
0372         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "='#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0373     } else if (output == QStringLiteral("#ATT#!='#V1S#'")) {
0374         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "!='#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0375     } else if (output == QStringLiteral("#ATT#>'#V1S#'")) {
0376         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", ">'#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0377     } else if (output == QStringLiteral("#ATT#<'#V1S#'")) {
0378         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "<'#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0379     } else if (output == QStringLiteral("#ATT#>='#V1S#'")) {
0380         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", ">='#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0381     } else if (output == QStringLiteral("#ATT#<='#V1S#'")) {
0382         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "<='#V1S#'").replace(QStringLiteral("#V1S#"), iParam1);
0383     } else if (output == QStringLiteral("#ATT#>=#V1# AND #ATT#<=#V2#")) {
0384         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is between #V1# and #V2#").replace(QStringLiteral("#V1#"), iParam1).replace(QStringLiteral("#V2#"), iParam2);
0385     } else if (output == QStringLiteral("((#ATT#>='#V1S#' AND #ATT#<='#V2S#') OR (#ATT#>='#V2S#' AND #ATT#<='#V1S#'))")) {
0386         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is between '#V1S#' and '#V2S#'").replace(QStringLiteral("#V1S#"), iParam1).replace(QStringLiteral("#V2S#"), iParam2);
0387     } else if (output == QStringLiteral("#ATT#=lower(#ATT#)")) {
0388         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is set to lower");
0389     } else if (output == QStringLiteral("#ATT#=upper(#ATT#)")) {
0390         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is set to upper");
0391     } else if (output == QStringLiteral("#ATT#=capitalize(#ATT#)")) {
0392         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is set to capitalize");
0393     } else if (output == QStringLiteral("#ATT#!=lower(#ATT#)")) {
0394         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is not lower");
0395     } else if (output == QStringLiteral("#ATT#!=upper(#ATT#)")) {
0396         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is not upper");
0397     } else if (output == QStringLiteral("#ATT#!=capitalize(#ATT#)")) {
0398         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is not capitalize");
0399     } else if (output == QStringLiteral("#ATT#= lower(#ATT#)")) {
0400         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is lower");
0401     } else if (output == QStringLiteral("#ATT#= upper(#ATT#)")) {
0402         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is upper");
0403     } else if (output == QStringLiteral("#ATT#= capitalize(#ATT#)")) {
0404         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is capitalize");
0405     } else if (output == QStringLiteral("#ATT#=replace(#ATT2#,'#V1S#','#V2S#')")) {
0406         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=#ATT2# with '#V1S#' replaced by '#V2S#'").replace(QStringLiteral("#V1S#"), iParam1).replace(QStringLiteral("#V2S#"), iParam2).replace(QStringLiteral("#ATT2#"), iAtt2);
0407     } else if (output == QStringLiteral("#ATT#=substr(#ATT2#,'#V1#','#V2#')")) {
0408         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=substring of #ATT2# from #V1# to #V2#").replace(QStringLiteral("#V1#"), iParam1).replace(QStringLiteral("#V2#"), iParam2).replace(QStringLiteral("#ATT2#"), iAtt2);
0409     } else if (output == QStringLiteral("#ATT#=#ATT2#")) {
0410         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=#ATT2#").replace(QStringLiteral("#ATT2#"), iAtt2);
0411     } else if (output == QStringLiteral("#ATT#=WORD(#ATT2#,#V1S#)")) {
0412         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=word(#ATT2#,#V1S#)").replace(QStringLiteral("#ATT2#"), iAtt2).replace(QStringLiteral("#V1S#"), iParam1);
0413     } else if (output == QStringLiteral("#ATT#=todate(#ATT2#,'#DF#')")) {
0414         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=#ATT2# as date with format #DF#").replace(QStringLiteral("#ATT2#"), iAtt2).replace(QStringLiteral("#DF#"), iParam2);
0415     } else if (output == QStringLiteral("#ATT#=todate(WORD(#ATT2#,#V1S#),'#DF#')")) {
0416         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "=word(#ATT2#,#V1S#) as date with format #DF#").replace(QStringLiteral("#ATT2#"), iAtt2).replace(QStringLiteral("#V1S#"), iParam1).replace(QStringLiteral("#DF#"), iParam2);
0417     } else if (output == QStringLiteral("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now', 'localtime'))")) {
0418         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in current month");
0419     } else if (output == QStringLiteral("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now', 'localtime','start of month','-1 month'))")) {
0420         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in previous month");
0421     } else if (output == QStringLiteral("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now', 'localtime'))")) {
0422         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in current year");
0423     } else if (output == QStringLiteral("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now', 'localtime','start of month','-1 year'))")) {
0424         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in previous year");
0425     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-30 day') AND #ATT#<=date('now', 'localtime')")) {
0426         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in last 30 days");
0427     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-3 month') AND #ATT#<=date('now', 'localtime')")) {
0428         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in last 3 months");
0429     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-6 month') AND #ATT#<=date('now', 'localtime')")) {
0430         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in last 6 months");
0431     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-12 month') AND #ATT#<=date('now', 'localtime')")) {
0432         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in last 12 months");
0433     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-2 year') AND #ATT#<=date('now', 'localtime')")) {
0434         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in last 2 years");
0435     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-3 year') AND #ATT#<=date('now', 'localtime')")) {
0436         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in last 3 years");
0437     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-5 year') AND #ATT#<=date('now', 'localtime')")) {
0438         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "is in last 5 years");
0439     } else if (output == QStringLiteral("ABS(TOTAL(#ATT#))#OP##V1#,ABS(TOTAL(#ATT#)), #V1#, '#V2S#'")) {
0440         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "If total(#ATT#)#OP##V1# then send '#V2S#'").replace(QStringLiteral("#V1#"), iParam1).replace(QStringLiteral("#V2S#"), iParam2).replace(QStringLiteral("#OP#"), iAtt2);
0441     } else if (output == QStringLiteral("APPLYTEMPLATE(#V1#)")) {
0442         output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, …)", "Apply the template '#V2S#'").replace(QStringLiteral("#V2S#"), iParam2);
0443     }
0444 
0445     return output;
0446 }
0447 
0448 QString SKGRuleObject::getToolTipForOperator(const QString& iOperator)
0449 {
0450     QString output = iOperator;
0451     if (output == QStringLiteral("#ATT# LIKE '%#V1S#%'")) {
0452         output = i18nc("Help for a condition", "To find out if the attribute contains a given string");
0453     } else if (output == QStringLiteral("#ATT# NOT LIKE '%#V1S#%'")) {
0454         output = i18nc("Help for a condition", "To find out if the attribute doesn't contain a given string");
0455     } else if (output == QStringLiteral("#ATT# LIKE '#V1S#%'")) {
0456         output = i18nc("Help for a condition", "To find out if the attribute is starting by a given string");
0457     } else if (output == QStringLiteral("#ATT# NOT LIKE '#V1S#%'")) {
0458         output = i18nc("Help for a condition", "To find out if the attribute is not starting by a given string");
0459     } else if (output == QStringLiteral("#ATT# LIKE '%#V1S#'")) {
0460         output = i18nc("Help for a condition", "To find out if the attribute is ending by a given string");
0461     } else if (output == QStringLiteral("#ATT# NOT LIKE '%#V1S#'")) {
0462         output = i18nc("Help for a condition", "To find out if the attribute is not ending by a given string");
0463     } else if (output == QStringLiteral("#ATT#=''")) {
0464         output = i18nc("Help for a condition", "To find out if the attribute is empty");
0465     } else if (output == QStringLiteral("#ATT#!=''")) {
0466         output = i18nc("Help for a condition", "To find out if the attribute is not empty");
0467     } else if (output == QStringLiteral("#ATT#=REGEXPCAPTURE('#V1S#', #ATT2#, #V2#)")) {
0468         output = i18nc("Help for a condition", "To get a captured value by a given regular expression (eg. \"(\\d+)(\\s*)(cm|inch(es)?)\")");
0469     } else if (output == QStringLiteral("REGEXP('#V1S#', #ATT#)")) {
0470         output = i18nc("Help for a condition", "To find out if the attribute is matching a given regular expression (eg. \"^[H,h]ello$\")");
0471     } else if (output == QStringLiteral("NOT(REGEXP('#V1S#', #ATT#))")) {
0472         output = i18nc("Help for a condition", "To find out if the attribute is not matching a given regular expression (eg. \"^[H,h]ello$\")");
0473     } else if (output == QStringLiteral("WILDCARD('#V1S#', #ATT#)")) {
0474         output = i18nc("Help for a condition", "To find out if the attribute is matching a given wildcard expression (eg. \"_ello\")");
0475     } else if (output == QStringLiteral("NOT(WILDCARD('#V1S#', #ATT#))")) {
0476         output = i18nc("Help for a condition", "To find out if the attribute is not matching a given wildcard expression (eg. \"_ello\")");
0477     } else if (output == QStringLiteral("#ATT#=#V1#")) {
0478         output = i18nc("Help for a condition", "To find out if the attribute is equal to a given value");
0479     } else if (output == QStringLiteral("#ATT#!=#V1#")) {
0480         output = i18nc("Help for a condition", "To find out if the attribute is not equal to a given value");
0481     } else if (output == QStringLiteral("#ATT#>#V1#")) {
0482         output = i18nc("Help for a condition", "To find out if the attribute is greater than a given value");
0483     } else if (output == QStringLiteral("#ATT#<#V1#")) {
0484         output = i18nc("Help for a condition", "To find out if the attribute is smaller than a given value");
0485     } else if (output == QStringLiteral("#ATT#>=#V1#")) {
0486         output = i18nc("Help for a condition", "To find out if the attribute is greater or equal to a given value");
0487     } else if (output == QStringLiteral("#ATT#<=#V1#")) {
0488         output = i18nc("Help for a condition", "To set the attribute with a given value");
0489     } else if (output == QStringLiteral("#ATT#='#V1S#'")) {
0490         output = i18nc("Help for a condition", "To find out if the attribute is equal to a given string");
0491     } else if (output == QStringLiteral("#ATT#!='#V1S#'")) {
0492         output = i18nc("Help for a condition", "To find out if the attribute is not equal to a given string");
0493     } else if (output == QStringLiteral("#ATT#>'#V1S#'")) {
0494         output = i18nc("Help for a condition", "To find out if the attribute is greater than a given string");
0495     } else if (output == QStringLiteral("#ATT#<'#V1S#'")) {
0496         output = i18nc("Help for a condition", "To find out if the attribute is smaller than a given string");
0497     } else if (output == QStringLiteral("#ATT#>='#V1S#'")) {
0498         output = i18nc("Help for a condition", "To find out if the attribute is greater or equal to a given string");
0499     } else if (output == QStringLiteral("#ATT#<='#V1S#'")) {
0500         output = i18nc("Help for a condition", "To find out if the attribute is smaller or equal to a given string");
0501     } else if (output == QStringLiteral("#ATT#>=#V1# AND #ATT#<=#V2#")) {
0502         output = i18nc("Help for a condition", "To find out if the attribute is between two given values");
0503     } else if (output == QStringLiteral("((#ATT#>='#V1S#' AND #ATT#<='#V2S#') OR (#ATT#>='#V2S#' AND #ATT#<='#V1S#'))")) {
0504         output = i18nc("Help for a condition", "To find out if the attribute is between two given strings");
0505     } else if (output == QStringLiteral("#ATT#=lower(#ATT#)")) {
0506         output = i18nc("Help for a condition", "To set the attribute in lower case (eg. hello)");
0507     } else if (output == QStringLiteral("#ATT#=upper(#ATT#)")) {
0508         output = i18nc("Help for a condition", "To set the attribute in upper case (eg. HELLO)");
0509     } else if (output == QStringLiteral("#ATT#=capitalize(#ATT#)")) {
0510         output = i18nc("Help for a condition", "To set the attribute in capitalized case (eg. Hello)");
0511     } else if (output == QStringLiteral("#ATT#!=lower(#ATT#)")) {
0512         output = i18nc("Help for a condition", "To find out if the attribute is not in lower case (eg. hello)");
0513     } else if (output == QStringLiteral("#ATT#!=upper(#ATT#)")) {
0514         output = i18nc("Help for a condition", "To find out if the attribute is not in upper case (eg. HELLO)");
0515     } else if (output == QStringLiteral("#ATT#!=capitalize(#ATT#)")) {
0516         output = i18nc("Help for a condition", "To find out if the attribute is not in capitalized case (eg. Hello)");
0517     } else if (output == QStringLiteral("#ATT#= lower(#ATT#)")) {
0518         output = i18nc("Help for a condition", "To find out if the attribute is in lower case (eg. hello)");
0519     } else if (output == QStringLiteral("#ATT#= upper(#ATT#)")) {
0520         output = i18nc("Help for a condition", "To find out if the attribute is in upper case (eg. HELLO)");
0521     } else if (output == QStringLiteral("#ATT#= capitalize(#ATT#)")) {
0522         output = i18nc("Help for a condition", "To find out if the attribute is in capitalized case (eg. Hello)");
0523     } else if (output == QStringLiteral("#ATT#=replace(#ATT2#,'#V1S#','#V2S#')")) {
0524         output = i18nc("Help for a condition", "To set the attribute with the value of another attribute where a value is replaced by another one");
0525     } else if (output == QStringLiteral("#ATT#=substr(#ATT2#,'#V1#','#V2#')")) {
0526         output = i18nc("Help for a condition", "To set the attribute with a part of the value of another attribute");
0527     } else if (output == QStringLiteral("#ATT#=#ATT2#")) {
0528         output = i18nc("Help for a condition", "To set the attribute with the value of another attribute");
0529     } else if (output == QStringLiteral("#ATT#=WORD(#ATT2#,#V1S#)")) {
0530         output = i18nc("Help for a condition", "To set the attribute with a word of the value of another attribute converted in date format");
0531     } else if (output == QStringLiteral("#ATT#=todate(#ATT2#,'#DF#')")) {
0532         output = i18nc("Help for a condition", "To set the date attribute with the value of another attribute");
0533     } else if (output == QStringLiteral("#ATT#=todate(WORD(#ATT2#,#V1S#),'#DF#')")) {
0534         output = i18nc("Help for a condition", "To set the date attribute with a word of another attribute converted in date format");
0535     } else if (output == QStringLiteral("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now', 'localtime'))")) {
0536         output = i18nc("Help for a condition", "To find out if the date of the transaction is today");
0537     } else if (output == QStringLiteral("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now', 'localtime','start of month','-1 month'))")) {
0538         output = i18nc("Help for a condition", "To find out if the date of the transaction is in previous month");
0539     } else if (output == QStringLiteral("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now', 'localtime'))")) {
0540         output = i18nc("Help for a condition", "To find out if the date of the transaction is in current year");
0541     } else if (output == QStringLiteral("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now', 'localtime','start of month','-1 year'))")) {
0542         output = i18nc("Help for a condition", "To find out if the date of the transaction is in previous year");
0543     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-30 day') AND #ATT#<=date('now', 'localtime')")) {
0544         output = i18nc("Help for a condition", "To find out if the date of the transaction is in last 30 days");
0545     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-3 month') AND #ATT#<=date('now', 'localtime')")) {
0546         output = i18nc("Help for a condition", "To find out if the date of the transaction is in last 3 months");
0547     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-6 month') AND #ATT#<=date('now', 'localtime')")) {
0548         output = i18nc("Help for a condition", "To find out if the date of the transaction is in last 6 months");
0549     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-12 month') AND #ATT#<=date('now', 'localtime')")) {
0550         output = i18nc("Help for a condition", "To find out if the date of the transaction is in last 12 months");
0551     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-2 year') AND #ATT#<=date('now', 'localtime')")) {
0552         output = i18nc("Help for a condition", "To find out if the date of the transaction is in last 2 years");
0553     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-3 year') AND #ATT#<=date('now', 'localtime')")) {
0554         output = i18nc("Help for a condition", "To find out if the date of the transaction is in last 3 years");
0555     } else if (output == QStringLiteral("#ATT#>date('now', 'localtime','-5 year') AND #ATT#<=date('now', 'localtime')")) {
0556         output = i18nc("Help for a condition", "To find out if the date of the transaction is in last 5 years");
0557     }
0558 
0559     return output;
0560 }
0561 
0562 QStringList SKGRuleObject::getListOfOperators(SKGServices::AttributeType iAttributeType, SKGRuleObject::ActionType iType)
0563 {
0564     QStringList output;
0565     if (iType == UPDATE) {
0566         // Mode update
0567         if (iAttributeType == SKGServices::TEXT) {
0568             output.push_back(QStringLiteral("#ATT#='#V1S#'"));
0569             output.push_back(QStringLiteral("#ATT#=lower(#ATT#)"));
0570             output.push_back(QStringLiteral("#ATT#=upper(#ATT#)"));
0571             output.push_back(QStringLiteral("#ATT#=capitalize(#ATT#)"));
0572             output.push_back(QStringLiteral("#ATT#=replace(#ATT2#,'#V1S#','#V2S#')"));
0573             output.push_back(QStringLiteral("#ATT#=REGEXPCAPTURE('#V1S#', #ATT2#, #V2#)"));
0574         } else if (iAttributeType == SKGServices::INTEGER || iAttributeType == SKGServices::FLOAT) {
0575             output.push_back(QStringLiteral("#ATT#=#V1#"));
0576         } else if (iAttributeType == SKGServices::DATE || iAttributeType == SKGServices::BOOL || iAttributeType == SKGServices::TRISTATE) {
0577             output.push_back(QStringLiteral("#ATT#='#V1S#'"));
0578         }
0579         if (iAttributeType == SKGServices::DATE) {
0580             output.push_back(QStringLiteral("#ATT#=todate(#ATT2#,'#DF#')"));
0581             output.push_back(QStringLiteral("#ATT#=todate(WORD(#ATT2#,#V1S#),'#DF#')"));
0582         } else if (iAttributeType != SKGServices::BOOL && iAttributeType != SKGServices::TRISTATE) {
0583             output.push_back(QStringLiteral("#ATT#=substr(#ATT2#,'#V1#','#V2#')"));
0584             output.push_back(QStringLiteral("#ATT#=#ATT2#"));
0585             output.push_back(QStringLiteral("#ATT#=WORD(#ATT2#,#V1S#)"));
0586         }
0587     } else if (iType == SEARCH) {
0588         // Mode query
0589         if (iAttributeType == SKGServices::TEXT) {
0590             output.push_back(QStringLiteral("#ATT# LIKE '%#V1S#%'"));
0591             output.push_back(QStringLiteral("#ATT# NOT LIKE '%#V1S#%'"));
0592             output.push_back(QStringLiteral("#ATT# LIKE '#V1S#%'"));
0593             output.push_back(QStringLiteral("#ATT# NOT LIKE '#V1S#%'"));
0594             output.push_back(QStringLiteral("#ATT# LIKE '%#V1S#'"));
0595             output.push_back(QStringLiteral("#ATT# NOT LIKE '%#V1S#'"));
0596             output.push_back(QStringLiteral("#ATT#=''"));
0597             output.push_back(QStringLiteral("#ATT#!=''"));
0598             output.push_back(QStringLiteral("#ATT#= lower(#ATT#)"));
0599             output.push_back(QStringLiteral("#ATT#!=lower(#ATT#)"));
0600             output.push_back(QStringLiteral("#ATT#= upper(#ATT#)"));
0601             output.push_back(QStringLiteral("#ATT#!=upper(#ATT#)"));
0602             output.push_back(QStringLiteral("#ATT#= capitalize(#ATT#)"));
0603             output.push_back(QStringLiteral("#ATT#!=capitalize(#ATT#)"));
0604             output.push_back(QStringLiteral("REGEXP('#V1S#', #ATT#)"));
0605             output.push_back(QStringLiteral("NOT(REGEXP('#V1S#', #ATT#))"));
0606             output.push_back(QStringLiteral("WILDCARD('#V1S#', #ATT#)"));
0607             output.push_back(QStringLiteral("NOT(WILDCARD('#V1S#', #ATT#))"));
0608         }
0609 
0610         if (iAttributeType == SKGServices::INTEGER || iAttributeType == SKGServices::FLOAT) {
0611             output.push_back(QStringLiteral("#ATT#=#V1#"));
0612             output.push_back(QStringLiteral("#ATT#!=#V1#"));
0613             output.push_back(QStringLiteral("#ATT#>#V1#"));
0614             output.push_back(QStringLiteral("#ATT#<#V1#"));
0615             output.push_back(QStringLiteral("#ATT#>=#V1#"));
0616             output.push_back(QStringLiteral("#ATT#<=#V1#"));
0617             output.push_back(QStringLiteral("#ATT#>=#V1# AND #ATT#<=#V2#"));
0618         }
0619 
0620         if (iAttributeType == SKGServices::BOOL || iAttributeType == SKGServices::TRISTATE || iAttributeType == SKGServices::TEXT || iAttributeType == SKGServices::DATE) {
0621             output.push_back(QStringLiteral("#ATT#='#V1S#'"));
0622         }
0623 
0624         if (iAttributeType == SKGServices::TRISTATE || iAttributeType == SKGServices::TEXT || iAttributeType == SKGServices::DATE) {
0625             output.push_back(QStringLiteral("#ATT#!='#V1S#'"));
0626         }
0627 
0628         if (iAttributeType == SKGServices::TEXT || iAttributeType == SKGServices::DATE) {
0629             output.push_back(QStringLiteral("#ATT#>'#V1S#'"));
0630             output.push_back(QStringLiteral("#ATT#<'#V1S#'"));
0631             output.push_back(QStringLiteral("#ATT#>='#V1S#'"));
0632             output.push_back(QStringLiteral("#ATT#<='#V1S#'"));
0633             output.push_back(QStringLiteral("((#ATT#>='#V1S#' AND #ATT#<='#V2S#') OR (#ATT#>='#V2S#' AND #ATT#<='#V1S#'))"));
0634         }
0635 
0636         if (iAttributeType == SKGServices::DATE) {
0637             output.push_back(QStringLiteral("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now', 'localtime'))"));
0638             output.push_back(QStringLiteral("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now', 'localtime','start of month','-1 month'))"));
0639             output.push_back(QStringLiteral("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now', 'localtime'))"));
0640             output.push_back(QStringLiteral("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now', 'localtime','start of month','-1 year'))"));
0641             output.push_back(QStringLiteral("#ATT#>date('now', 'localtime','-30 day') AND #ATT#<=date('now', 'localtime')"));
0642             output.push_back(QStringLiteral("#ATT#>date('now', 'localtime','-3 month') AND #ATT#<=date('now', 'localtime')"));
0643             output.push_back(QStringLiteral("#ATT#>date('now', 'localtime','-6 month') AND #ATT#<=date('now', 'localtime')"));
0644             output.push_back(QStringLiteral("#ATT#>date('now', 'localtime','-12 month') AND #ATT#<=date('now', 'localtime')"));
0645             output.push_back(QStringLiteral("#ATT#>date('now', 'localtime','-2 year') AND #ATT#<=date('now', 'localtime')"));
0646             output.push_back(QStringLiteral("#ATT#>date('now', 'localtime','-3 year') AND #ATT#<=date('now', 'localtime')"));
0647             output.push_back(QStringLiteral("#ATT#>date('now', 'localtime','-5 year') AND #ATT#<=date('now', 'localtime')"));
0648         }
0649     } else if (iType == ALARM) {
0650         output.push_back(QStringLiteral("ABS(TOTAL(#ATT#))#OP##V1#,ABS(TOTAL(#ATT#)), #V1#, '#V2S#'"));
0651     } else if (iType == APPLYTEMPLATE) {
0652         output.push_back(QStringLiteral("APPLYTEMPLATE(#V1#)"));
0653     }
0654     return output;
0655 }
0656 
0657 QStringList SKGRuleObject::getFromXML(SKGDocument* iDocument, const QString& iXML, bool iSQL, SKGRuleObject::ActionType iType, bool iFullUpdate)
0658 {
0659     QStringList output;
0660     if (iFullUpdate) {
0661         // Add markers
0662         output.push_back(QStringLiteral("UPDATE v_operation_prop set i_tmp=1 WHERE #WC#"));
0663     }
0664 
0665     QDomDocument doc(QStringLiteral("SKGML"));
0666     doc.setContent(iXML);
0667     QDomElement root = doc.documentElement();
0668     if (root.tagName() == QStringLiteral("element") || iType != SEARCH) {
0669         // Mode advanced
0670         QDomNode l = root.firstChild();
0671         while (!l.isNull()) {
0672             QDomElement elementl = l.toElement();
0673             if (!elementl.isNull()) {
0674                 QString lineDescription;
0675 
0676                 QDomNode n = elementl.firstChild();
0677                 bool parenthesisNeeded = false;
0678                 while (!n.isNull()) {
0679                     QDomElement element = n.toElement();
0680                     if (!element.isNull()) {
0681                         // Build element description
0682                         QString elementDescription;
0683                         QString attribute = element.attribute(QStringLiteral("attribute"));
0684                         QString propName;
0685                         if (iSQL) {
0686                             attribute = SKGServices::stringToSqlString(attribute);
0687                             if (attribute.startsWith(QLatin1String("p_"))) {
0688                                 // Case property
0689                                 propName = attribute.right(attribute.length() - 2);
0690                                 if (iType == SEARCH) {
0691                                     attribute = "i_PROPPNAME='" % SKGServices::stringToSqlString(propName) % "' AND i_PROPVALUE";
0692                                 } else {
0693                                     attribute = QStringLiteral("t_value");
0694                                 }
0695                             }
0696 
0697                             QString part = element.attribute(QStringLiteral("operator"));
0698                             part = part.replace(QStringLiteral("#V1#"), SKGServices::stringToSqlString(element.attribute(QStringLiteral("value"))));
0699                             part = part.replace(QStringLiteral("#V1S#"), SKGServices::stringToSqlString(element.attribute(QStringLiteral("value"))));
0700                             part = part.replace(QStringLiteral("#V2#"), SKGServices::stringToSqlString(element.attribute(QStringLiteral("value2"))));
0701                             part = part.replace(QStringLiteral("#V2S#"), SKGServices::stringToSqlString(element.attribute(QStringLiteral("value2"))));
0702                             part = part.replace(QStringLiteral("#DF#"), SKGServices::stringToSqlString(element.attribute(QStringLiteral("value2"))));
0703                             part = part.replace(QStringLiteral("#OP#"), SKGServices::stringToSqlString(element.attribute(QStringLiteral("operator2"))));
0704 
0705                             elementDescription += part;
0706                         } else {
0707                             attribute = "operation." % attribute;
0708                             if (iDocument != nullptr) {
0709                                 attribute = iDocument->getDisplay(attribute);
0710                             }
0711 
0712                             if (iType != ALARM && iType != APPLYTEMPLATE) {
0713                                 elementDescription = attribute;
0714                                 elementDescription += ' ';
0715                             }
0716 
0717                             QString tmp = element.attribute(QStringLiteral("att2s"));
0718                             if (tmp.isEmpty()) {
0719                                 tmp = element.attribute(QStringLiteral("operator2"));
0720                             }
0721                             QString part = SKGRuleObject::getDisplayForOperator(element.attribute(QStringLiteral("operator")),
0722                                            element.attribute(QStringLiteral("value")),
0723                                            element.attribute(QStringLiteral("value2")),
0724                                            tmp);
0725 
0726                             elementDescription += part;
0727                         }
0728 
0729                         elementDescription = elementDescription.replace(QStringLiteral("#ATT#"), attribute);
0730 
0731                         // Att2
0732                         QString attribute2 = element.attribute(QStringLiteral("att2"));
0733                         if (iSQL) {
0734                             attribute2 = SKGServices::stringToSqlString(attribute2);
0735                             if (attribute2.startsWith(QLatin1String("p_"))) {
0736                                 QString propertyName = attribute2.right(attribute2.length() - 2);
0737                                 attribute2 = "IFNULL((SELECT op2.i_PROPVALUE FROM v_operation_prop op2 WHERE op2.id=v_operation_prop.id AND op2.i_PROPPNAME='" % SKGServices::stringToSqlString(propertyName) % "'),'')";
0738                             }
0739 
0740                             if (element.attribute(QStringLiteral("attribute")).startsWith(QLatin1String("p_"))) {
0741                                 attribute2 = "(SELECT " % attribute2 %  " FROM v_operation_prop WHERE i_PROPPID=parameters.id)";
0742                             }
0743                         }
0744                         elementDescription = elementDescription.replace(QStringLiteral("#ATT2#"), attribute2);
0745 
0746                         // Add it to line description
0747                         if (iSQL) {
0748                             if (iType == UPDATE) {
0749                                 if (!iFullUpdate) {
0750                                     output.push_back(elementDescription);
0751                                 } else {
0752                                     if (attribute == QStringLiteral("t_REALCATEGORY")) {
0753                                         elementDescription.replace(attribute, QStringLiteral("t_fullname"));
0754 
0755                                         QString parentcat;
0756                                         QString cat = element.attribute(QStringLiteral("value"));
0757                                         bool stop = false;
0758                                         while (!stop) {
0759                                             int posSeparator = cat.indexOf(OBJECTSEPARATOR);
0760                                             if (posSeparator == -1) {
0761                                                 if (parentcat.isEmpty()) {
0762                                                     output.push_back(QStringLiteral("UPDATE category SET rd_category_id=0 WHERE rd_category_id IS NULL OR rd_category_id=''"));
0763                                                     output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(cat) % "', 0)");
0764                                                 } else {
0765                                                     output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(cat) % "',(SELECT id FROM category WHERE t_fullname='" % SKGServices::stringToSqlString(parentcat) % "'))");
0766                                                 }
0767                                                 stop = true;
0768                                             } else {
0769                                                 // Get first and second parts of the branch
0770                                                 QString first = cat.mid(0, posSeparator);
0771                                                 QString second = cat.mid(posSeparator + QString(OBJECTSEPARATOR).length(), cat.length() - posSeparator - QString(OBJECTSEPARATOR).length());
0772                                                 if (parentcat.isEmpty()) {
0773                                                     output.push_back(QStringLiteral("UPDATE category SET rd_category_id=0 WHERE rd_category_id IS NULL OR rd_category_id=''"));
0774                                                     output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(first) % "', 0)");
0775                                                 } else {
0776                                                     output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(first) % "',(SELECT id FROM category WHERE t_fullname='" % SKGServices::stringToSqlString(parentcat) % "'))");
0777                                                 }
0778 
0779                                                 if (parentcat.isEmpty()) {
0780                                                     parentcat = first;
0781                                                 } else {
0782                                                     parentcat = parentcat % OBJECTSEPARATOR % first;
0783                                                 }
0784                                                 cat = second;
0785                                             }
0786                                         }
0787                                         output.push_back("UPDATE suboperation set r_category_id=(SELECT id FROM category WHERE " % elementDescription % ") WHERE i_tmp=1");
0788                                     } else if (element.attribute(QStringLiteral("attribute")).startsWith(QLatin1String("p_"))) {
0789                                         output.push_back("INSERT OR IGNORE INTO parameters (t_uuid_parent, t_name, i_tmp) SELECT o.id||'-operation', '" % SKGServices::stringToSqlString(propName) % "', 1 FROM operation o WHERE o.i_tmp=1");
0790                                         output.push_back("UPDATE parameters set " % elementDescription % " WHERE i_tmp=1 AND t_name='" % SKGServices::stringToSqlString(propName) % "' AND NOT(" % elementDescription % ')');
0791                                         output.push_back("DELETE FROM parameters WHERE i_tmp=1 AND t_name='" % SKGServices::stringToSqlString(propName) % "' AND t_value=''");
0792                                     } else {
0793                                         output.push_back("UPDATE v_operation_prop set " % elementDescription % " WHERE i_tmp=1 AND NOT(" % elementDescription % ')');
0794                                     }
0795                                 }
0796                             } else if (iType == ALARM) {
0797                                 output.push_back("SELECT " % elementDescription % " FROM v_operation_prop WHERE #WC#");
0798                             } else if (iType == APPLYTEMPLATE) {
0799                                 output.push_back(element.attribute(QStringLiteral("value")));
0800                             }
0801                         }
0802 
0803                         if (!lineDescription.isEmpty()) {
0804                             lineDescription += (iType == UPDATE ? QStringLiteral(" , ") : (iSQL ? QStringLiteral(" AND ") : i18nc("logical operator in a search query", " and ")));
0805                             parenthesisNeeded = true;
0806                         }
0807                         lineDescription += elementDescription;
0808                     }
0809                     n = n.nextSibling();
0810                 }
0811 
0812                 if (!(iType != SEARCH && iSQL) && !lineDescription.isEmpty()) {
0813                     if (iType == SEARCH && parenthesisNeeded) {
0814                         lineDescription = '(' % lineDescription % ')';
0815                     }
0816                     output.push_back(lineDescription);
0817                 }
0818             }
0819             l = l.nextSibling();
0820         }
0821     } else {
0822         output.push_back(root.attribute(iSQL ? QStringLiteral("sql") : QStringLiteral("query")));
0823     }
0824 
0825     if (iFullUpdate) {
0826         // Remove markers
0827         output.push_back(QStringLiteral("UPDATE v_operation_prop set i_tmp=0 WHERE i_tmp=1"));
0828     }
0829     return output;
0830 }
0831 
0832 QString SKGRuleObject::getDescriptionFromXML(SKGDocument* iDocument, const QString& iXML, bool iSQL, SKGRuleObject::ActionType iType)
0833 {
0834     QString output;
0835 
0836     QStringList list = getFromXML(iDocument, iXML, iSQL, iType);
0837     int nb = list.count();
0838     for (int i = 0; i < nb; ++i) {
0839         output.append(list.at(i));
0840         if (i < nb - 1) {
0841             output.append(iType != SEARCH ? QStringLiteral(" , ") : (iSQL ? QStringLiteral(" OR ") : i18nc("logical operator in a search query", " or ")));
0842         }
0843     }
0844     return output;
0845 }
0846 
0847 SKGError SKGRuleObject::createPayeeCategoryRule(SKGDocument* iDocument, const QString& iPayee, const QString& iCategory, SKGRuleObject& oRule)
0848 {
0849     SKGError err;
0850     oRule = SKGRuleObject(iDocument);
0851     // TODO(Stephane MANKOWSKI): escape values
0852     IFOKDO(err, oRule.setActionType(SKGRuleObject::UPDATE))
0853     IFOKDO(err, oRule.setSearchDescription(iDocument->getDisplay(QStringLiteral("t_PAYEE")) % ' ' % getDisplayForOperator(QStringLiteral("#ATT#='#V1S#'"), iPayee, QString(), QString())))
0854     IFOKDO(err, oRule.setXMLSearchDefinition("<!DOCTYPE SKGML><element> <!--OR--> <element>  <!--AND-->  <element value=\"" % iPayee % "\" attribute=\"t_PAYEE\" operator=\"#ATT#='#V1S#'\"/> </element></element>"))
0855     IFOKDO(err, oRule.setActionDescription(iDocument->getDisplay(QStringLiteral("t_REALCATEGORY")) % ' ' % getDisplayForOperator(QStringLiteral("#ATT#='#V1S#'"), iCategory, QString(), QString())))
0856     IFOKDO(err, oRule.setXMLActionDefinition("<!DOCTYPE SKGML><element> <!--OR--> <element>  <!--AND-->  <element value=\"" % iCategory % "\" attribute=\"t_REALCATEGORY\" operator=\"#ATT#='#V1S#'\"/> </element></element>"))
0857     IFOKDO(err, oRule.save())
0858 
0859     return err;
0860 }
0861