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

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 implements classes SKGCategoryObject.
0008  *
0009  * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgcategoryobject.h"
0012 
0013 #include <klocalizedstring.h>
0014 
0015 #include "skgdocumentbank.h"
0016 #include "skgsuboperationobject.h"
0017 #include "skgtraces.h"
0018 
0019 SKGCategoryObject::SKGCategoryObject() : SKGCategoryObject(nullptr)
0020 {}
0021 
0022 SKGCategoryObject::SKGCategoryObject(SKGDocument* iDocument, int iID) : SKGNamedObject(iDocument, QStringLiteral("v_category"), iID)
0023 {}
0024 
0025 SKGCategoryObject::~SKGCategoryObject()
0026     = default;
0027 
0028 SKGCategoryObject::SKGCategoryObject(const SKGCategoryObject& iObject) = default;
0029 
0030 SKGCategoryObject::SKGCategoryObject(const SKGObjectBase& iObject)
0031 
0032 {
0033     if (iObject.getRealTable() == QStringLiteral("category")) {
0034         copyFrom(iObject);
0035     } else {
0036         *this = SKGNamedObject(iObject.getDocument(), QStringLiteral("v_category"), iObject.getID());
0037     }
0038 }
0039 
0040 SKGCategoryObject& SKGCategoryObject::operator= (const SKGObjectBase& iObject)
0041 {
0042     copyFrom(iObject);
0043     return *this;
0044 }
0045 
0046 SKGCategoryObject& SKGCategoryObject::operator= (const SKGCategoryObject& iObject)
0047 {
0048     copyFrom(iObject);
0049     return *this;
0050 }
0051 
0052 SKGError SKGCategoryObject::setName(const QString& iName)
0053 {
0054     SKGError err;
0055     if (iName.contains(OBJECTSEPARATOR)) {
0056         err = SKGError(ERR_FAIL,  i18nc("Error message", "Invalid name '%1' because of the name cannot contain '%2'", iName, QString(OBJECTSEPARATOR)));
0057     } else {
0058         err = SKGNamedObject::setName(iName);
0059     }
0060     return err;
0061 }
0062 
0063 QString SKGCategoryObject::getWhereclauseId() const
0064 {
0065     // Could we use the id
0066     QString output = SKGObjectBase::getWhereclauseId();  // clazy:exclude=skipped-base-method
0067     if (output.isEmpty()) {
0068         if (!(getAttribute(QStringLiteral("t_name")).isEmpty())) {
0069             output = "t_name='" % SKGServices::stringToSqlString(getAttribute(QStringLiteral("t_name"))) % '\'';
0070         }
0071         QString rd_category_id = getAttribute(QStringLiteral("rd_category_id"));
0072         if (!output.isEmpty()) {
0073             output += QStringLiteral(" AND ");
0074         }
0075         if (rd_category_id.isEmpty()) {
0076             output += QStringLiteral("(rd_category_id=0 OR rd_category_id IS NULL OR rd_category_id='')");
0077         } else {
0078             output += "rd_category_id=" % rd_category_id;
0079         }
0080     }
0081     return output;
0082 }
0083 
0084 QString SKGCategoryObject::getFullName() const
0085 {
0086     return getAttribute(QStringLiteral("t_fullname"));
0087 }
0088 
0089 SKGError SKGCategoryObject::createPathCategory(SKGDocumentBank* iDocument,
0090         const QString& iFullPath,
0091         SKGCategoryObject& oCategory,
0092         bool iSendPopupMessageOnCreation,
0093         bool iRenameIfAlreadyExist)
0094 {
0095     SKGError err;
0096     SKGTRACEINFUNCRC(10, err)
0097 
0098     // Check if category is already existing
0099     if (iFullPath.isEmpty()) {
0100         oCategory = SKGCategoryObject(nullptr, 0);
0101     } else if (iDocument != nullptr) {
0102         if (!iRenameIfAlreadyExist) {
0103             iDocument->getObject(QStringLiteral("v_category"), "t_fullname='" % SKGServices::stringToSqlString(iFullPath) % '\'', oCategory);
0104         } else {
0105             oCategory.resetID();
0106         }
0107         if (oCategory.getID() == 0) {
0108             // No, we have to create it
0109             // Search category separator
0110             int posSeparator = iFullPath.lastIndexOf(OBJECTSEPARATOR);
0111             if (posSeparator == -1) {
0112                 oCategory = SKGCategoryObject(iDocument);
0113                 err = oCategory.setName(iFullPath);
0114 
0115                 // Check if already existing
0116                 if (!err && iRenameIfAlreadyExist) {
0117                     int index = 1;
0118                     while (!err && oCategory.exist()) {
0119                         index++;
0120                         err = oCategory.setName(iFullPath % " (" % SKGServices::intToString(index) % ')');
0121                     }
0122                 }
0123 
0124                 IFOKDO(err, oCategory.save())
0125             } else {
0126                 // Get first and second parts of the branch
0127                 QString first = iFullPath.mid(0, posSeparator);
0128                 QString second = iFullPath.mid(posSeparator + QString(OBJECTSEPARATOR).length(), iFullPath.length() - posSeparator - QString(OBJECTSEPARATOR).length());
0129 
0130                 // Get first category
0131                 SKGCategoryObject FirstCategory;
0132                 err = SKGCategoryObject::createPathCategory(iDocument, first, FirstCategory);
0133 
0134                 IFOK(err) {
0135                     // Get second category
0136                     err = FirstCategory.addCategory(oCategory);
0137 
0138                     // Add second under first
0139                     IFOKDO(err, oCategory.setName(second))
0140 
0141                     // Check if already existing
0142                     if (!err && iRenameIfAlreadyExist) {
0143                         int index = 2;
0144                         while (!err && oCategory.exist()) {
0145                             err = oCategory.setName(second % " (" % SKGServices::intToString(index) % ')');
0146                             ++index;
0147                         }
0148                     }
0149 
0150                     // save
0151                     IFOKDO(err, oCategory.save())
0152                 }
0153             }
0154 
0155             if (!err && iSendPopupMessageOnCreation) {
0156                 iDocument->sendMessage(i18nc("Information message", "The category '%1' has been created", iFullPath), SKGDocument::Positive);
0157             }
0158         }
0159     }
0160 
0161     return err;
0162 }
0163 
0164 SKGError SKGCategoryObject::addCategory(SKGCategoryObject& oCategory)
0165 {
0166     SKGError err;
0167     SKGTRACEINFUNCRC(10, err)
0168     if (getID() == 0) {
0169         err = SKGError(ERR_FAIL,  i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGCategoryObject::addCategory")));
0170     } else {
0171         oCategory = SKGCategoryObject(qobject_cast<SKGDocumentBank*>(getDocument()));
0172         err = oCategory.setAttribute(QStringLiteral("rd_category_id"), SKGServices::intToString(getID()));
0173     }
0174     return err;
0175 }
0176 
0177 SKGError SKGCategoryObject::setParentCategory(const SKGCategoryObject& iCategory)
0178 {
0179     SKGError err;
0180     SKGTRACEINFUNCRC(10, err)
0181     if (iCategory.getID() == 0) {
0182         err = SKGError(ERR_FAIL,  i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGCategoryObject::setParentCategory")));
0183     } else {
0184         // Check if it is a loop
0185         SKGCategoryObject current = iCategory;
0186         do {
0187             if (current == *this) {
0188                 err = SKGError(ERR_FAIL,  i18nc("Error message", "You cannot create a loop."));
0189             } else {
0190                 SKGCategoryObject parent2;
0191                 current.getParentCategory(parent2);
0192                 current = parent2;
0193             }
0194         } while (!err && current.getID() != 0);
0195 
0196         IFOKDO(err, setAttribute(QStringLiteral("rd_category_id"), SKGServices::intToString(iCategory.getID())))
0197     }
0198     return err;
0199 }
0200 
0201 SKGError SKGCategoryObject::removeParentCategory()
0202 {
0203     return setAttribute(QStringLiteral("rd_category_id"), QStringLiteral("0"));
0204 }
0205 
0206 SKGError SKGCategoryObject::getParentCategory(SKGCategoryObject& oCategory) const
0207 {
0208     SKGError err;
0209     QString parent_id = getAttribute(QStringLiteral("rd_category_id"));
0210     if (!parent_id.isEmpty() && parent_id != QStringLiteral("0")) {
0211         err = getDocument()->getObject(QStringLiteral("v_category"), "id=" % parent_id, oCategory);
0212     }
0213     return err;
0214 }
0215 
0216 SKGError SKGCategoryObject::getRootCategory(SKGCategoryObject& oCategory) const
0217 {
0218     SKGError err;
0219     SKGCategoryObject parent2;
0220     err = getParentCategory(parent2);
0221     IFOK(err) {
0222         if (!parent2.exist()) {
0223             // No parent
0224             oCategory = *this;
0225         } else {
0226             // Parent exist
0227             err = parent2.getRootCategory(oCategory);
0228         }
0229     }
0230     return err;
0231 }
0232 
0233 
0234 SKGError SKGCategoryObject::getCategories(SKGListSKGObjectBase& oCategoryList) const
0235 {
0236     return getDocument()->getObjects(QStringLiteral("v_category"),
0237                                      "rd_category_id=" % SKGServices::intToString(getID()),
0238                                      oCategoryList);
0239 }
0240 
0241 double SKGCategoryObject::getCurrentAmount() const
0242 {
0243     QString v = getAttribute(QStringLiteral("f_SUMCURRENTAMOUNT"));
0244     if (v.isEmpty()) {
0245         SKGNamedObject cat(getDocument(), QStringLiteral("v_category_display"), getID());
0246         v = cat.getAttribute(QStringLiteral("f_SUMCURRENTAMOUNT"));
0247     }
0248     return SKGServices::stringToDouble(v);
0249 }
0250 
0251 SKGError SKGCategoryObject::getSubOperations(SKGListSKGObjectBase& oSubOperations) const
0252 {
0253     SKGError err = getDocument()->getObjects(QStringLiteral("v_suboperation"),
0254                    "r_category_id=" % SKGServices::intToString(getID()),
0255                    oSubOperations);
0256     return err;
0257 }
0258 
0259 SKGError SKGCategoryObject::bookmark(bool iBookmark)
0260 {
0261     return setAttribute(QStringLiteral("t_bookmarked"), iBookmark ? QStringLiteral("Y") : QStringLiteral("N"));
0262 }
0263 
0264 bool SKGCategoryObject::isBookmarked() const
0265 {
0266     return (getAttribute(QStringLiteral("t_bookmarked")) == QStringLiteral("Y"));
0267 }
0268 
0269 SKGError SKGCategoryObject::setClosed(bool iClosed)
0270 {
0271     return setAttribute(QStringLiteral("t_close"), iClosed ? QStringLiteral("Y") : QStringLiteral("N"));
0272 }
0273 
0274 bool SKGCategoryObject::isClosed() const
0275 {
0276     return (getAttribute(QStringLiteral("t_close")) == QStringLiteral("Y"));
0277 }
0278 
0279 SKGError SKGCategoryObject::merge(const SKGCategoryObject& iCategory)
0280 {
0281     SKGError err;
0282 
0283     SKGObjectBase::SKGListSKGObjectBase ops;
0284     IFOKDO(err, iCategory.getSubOperations(ops))
0285     int nb = ops.count();
0286     for (int i = 0; !err && i < nb; ++i) {
0287         SKGSubOperationObject op(ops.at(i));
0288         err = op.setCategory(*this);
0289         IFOKDO(err, op.save(true, false))
0290     }
0291 
0292     SKGObjectBase::SKGListSKGObjectBase cats;
0293     IFOKDO(err, iCategory.getCategories(cats))
0294     nb = cats.count();
0295     for (int i = 0; !err && i < nb; ++i) {
0296         SKGCategoryObject cat(cats.at(i));
0297         err = cat.setParentCategory(*this);
0298         IFOKDO(err, cat.save(true, false))
0299     }
0300 
0301     IFOKDO(err, iCategory.remove(false))
0302     return err;
0303 }
0304 
0305