File indexing completed on 2024-04-28 16:30:12
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 SKGRecurrentOperationObject. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgrecurrentoperationobject.h" 0012 0013 #include <klocalizedstring.h> 0014 0015 #include "skgdocumentbank.h" 0016 #include "skgoperationobject.h" 0017 #include "skgservices.h" 0018 #include "skgsuboperationobject.h" 0019 #include "skgtraces.h" 0020 0021 SKGRecurrentOperationObject::SKGRecurrentOperationObject(): SKGRecurrentOperationObject(nullptr) 0022 {} 0023 0024 SKGRecurrentOperationObject::SKGRecurrentOperationObject(SKGDocument* iDocument, int iID): SKGObjectBase(iDocument, QStringLiteral("v_recurrentoperation"), iID) 0025 {} 0026 0027 SKGRecurrentOperationObject::~SKGRecurrentOperationObject() 0028 = default; 0029 0030 SKGRecurrentOperationObject::SKGRecurrentOperationObject(const SKGRecurrentOperationObject& iObject) = default; 0031 0032 SKGRecurrentOperationObject::SKGRecurrentOperationObject(const SKGObjectBase& iObject) 0033 { 0034 if (iObject.getRealTable() == QStringLiteral("recurrentoperation")) { 0035 copyFrom(iObject); 0036 } else { 0037 *this = SKGObjectBase(iObject.getDocument(), QStringLiteral("v_recurrentoperation"), iObject.getID()); 0038 } 0039 } 0040 0041 SKGRecurrentOperationObject& SKGRecurrentOperationObject::operator= (const SKGObjectBase& iObject) 0042 { 0043 copyFrom(iObject); 0044 return *this; 0045 } 0046 0047 SKGRecurrentOperationObject& SKGRecurrentOperationObject::operator= (const SKGRecurrentOperationObject& iObject) 0048 { 0049 copyFrom(iObject); 0050 return *this; 0051 } 0052 0053 SKGError SKGRecurrentOperationObject::getParentOperation(SKGOperationObject& oOperation) const 0054 { 0055 SKGObjectBase objTmp; 0056 SKGError err = getDocument()->getObject(QStringLiteral("v_operation"), "id=" % getAttribute(QStringLiteral("rd_operation_id")), objTmp); 0057 oOperation = objTmp; 0058 return err; 0059 } 0060 0061 SKGError SKGRecurrentOperationObject::setParentOperation(const SKGOperationObject& iOperation) 0062 { 0063 return setAttribute(QStringLiteral("rd_operation_id"), SKGServices::intToString(iOperation.getID())); 0064 } 0065 0066 SKGError SKGRecurrentOperationObject::setTemplate(bool iTemplate) 0067 { 0068 SKGError err; 0069 0070 if (iTemplate == isTemplate()) { 0071 err.addError(ERR_UNEXPECTED, i18nc("Error message", "Trying to set the same template status \"%1\" to a recurrent operation", iTemplate)); 0072 return err; 0073 } 0074 0075 SKGOperationObject parentOp; 0076 err = getParentOperation(parentOp); 0077 if (iTemplate) { 0078 // Convert to template 0079 SKGOperationObject operationObjOrig = parentOp; 0080 IFOKDO(err, operationObjOrig.duplicate(parentOp, operationObjOrig.getDate(), true)) 0081 0082 IFOKDO(err, setParentOperation(parentOp)) 0083 IFOKDO(err, save()) 0084 0085 IFOKDO(err, operationObjOrig.setAttribute(QStringLiteral("r_recurrentoperation_id"), SKGServices::intToString(getID()))) 0086 IFOKDO(err, operationObjOrig.save()) 0087 } else { 0088 // Convert to non-template 0089 SKGObjectBase::SKGListSKGObjectBase transactions; 0090 IFOKDO(err, getRecurredOperations(transactions)) 0091 IFOK(err) { 0092 if (!transactions.isEmpty()) { 0093 SKGOperationObject lastObj(transactions.last()); 0094 IFOKDO(err, setParentOperation(lastObj)) 0095 IFOKDO(err, save()) 0096 IFOKDO(err, lastObj.setAttribute(QStringLiteral("r_recurrentoperation_id"), QString())) 0097 IFOKDO(err, lastObj.save()) 0098 0099 SKGObjectBase::SKGListSKGObjectBase goupops; 0100 IFOKDO(err, parentOp.getGroupedOperations(goupops)) 0101 IFOK(err) { 0102 int nbgoupops = goupops.count(); 0103 for (int i = 0; !err && i < nbgoupops; ++i) { 0104 SKGOperationObject groupop(goupops.at(i)); 0105 if (groupop != parentOp) { 0106 IFOKDO(err, groupop.remove(true)) 0107 } 0108 } 0109 } 0110 0111 IFOKDO(err, parentOp.remove(true)) 0112 } else { 0113 err.addError(ERR_FAIL, i18nc("Error message", "Need at least one transaction to convert a schedule to a non-template one")); 0114 } 0115 } 0116 } 0117 0118 return err; 0119 } 0120 0121 bool SKGRecurrentOperationObject::isTemplate() const 0122 { 0123 SKGOperationObject op; 0124 SKGError err = getParentOperation(op); 0125 IFOK(err) return op.isTemplate(); 0126 return false; 0127 } 0128 0129 SKGError SKGRecurrentOperationObject::setPeriodIncrement(int iIncrement) 0130 { 0131 return setAttribute(QStringLiteral("i_period_increment"), SKGServices::intToString(iIncrement)); 0132 } 0133 0134 int SKGRecurrentOperationObject::getPeriodIncrement() const 0135 { 0136 return SKGServices::stringToInt(getAttribute(QStringLiteral("i_period_increment"))); 0137 } 0138 0139 SKGRecurrentOperationObject::PeriodUnit SKGRecurrentOperationObject::getPeriodUnit() const 0140 { 0141 QString t_period_unit = getAttribute(QStringLiteral("t_period_unit")); 0142 if (t_period_unit == QStringLiteral("D")) { 0143 return SKGRecurrentOperationObject::DAY; 0144 } 0145 if (t_period_unit == QStringLiteral("W")) { 0146 return SKGRecurrentOperationObject::WEEK; 0147 } 0148 if (t_period_unit == QStringLiteral("M")) { 0149 return SKGRecurrentOperationObject::MONTH; 0150 } 0151 return SKGRecurrentOperationObject::YEAR; 0152 } 0153 0154 SKGError SKGRecurrentOperationObject::setPeriodUnit(SKGRecurrentOperationObject::PeriodUnit iPeriod) 0155 { 0156 return setAttribute(QStringLiteral("t_period_unit"), (iPeriod == SKGRecurrentOperationObject::DAY ? QStringLiteral("D") : (iPeriod == SKGRecurrentOperationObject::WEEK ? QStringLiteral("W") : (iPeriod == SKGRecurrentOperationObject::MONTH ? QStringLiteral("M") : QStringLiteral("Y"))))); 0157 } 0158 0159 SKGError SKGRecurrentOperationObject::setAutoWriteDays(int iDays) 0160 { 0161 return setAttribute(QStringLiteral("i_auto_write_days"), SKGServices::intToString(iDays)); 0162 } 0163 0164 int SKGRecurrentOperationObject::getAutoWriteDays() const 0165 { 0166 return SKGServices::stringToInt(getAttribute(QStringLiteral("i_auto_write_days"))); 0167 } 0168 0169 SKGError SKGRecurrentOperationObject::setWarnDays(int iDays) 0170 { 0171 return setAttribute(QStringLiteral("i_warn_days"), SKGServices::intToString(iDays)); 0172 } 0173 0174 int SKGRecurrentOperationObject::getWarnDays() const 0175 { 0176 return SKGServices::stringToInt(getAttribute(QStringLiteral("i_warn_days"))); 0177 } 0178 0179 bool SKGRecurrentOperationObject::hasTimeLimit() const 0180 { 0181 return (getAttribute(QStringLiteral("t_times")) == QStringLiteral("Y")); 0182 } 0183 0184 SKGError SKGRecurrentOperationObject::timeLimit(bool iTimeLimit) 0185 { 0186 return setAttribute(QStringLiteral("t_times"), iTimeLimit ? QStringLiteral("Y") : QStringLiteral("N")); 0187 } 0188 0189 SKGError SKGRecurrentOperationObject::setTimeLimit(QDate iLastDate) 0190 { 0191 // Get parameters 0192 QDate firstDate = this->getDate(); 0193 if (iLastDate < firstDate) { 0194 return setTimeLimit(0); 0195 } 0196 SKGRecurrentOperationObject::PeriodUnit period = this->getPeriodUnit(); 0197 int occu = qMax(this->getPeriodIncrement(), 1); 0198 0199 // Compute nb time 0200 int nbd = firstDate.daysTo(iLastDate); 0201 if (period == SKGRecurrentOperationObject::DAY) { 0202 nbd = nbd / occu; 0203 } else if (period == SKGRecurrentOperationObject::WEEK) { 0204 nbd = nbd / (7 * occu); 0205 } else if (period == SKGRecurrentOperationObject::MONTH) { 0206 nbd = (iLastDate.day() >= firstDate.day() ? 0 : -1) + (iLastDate.year() - firstDate.year()) * 12 + (iLastDate.month() - firstDate.month()); 0207 } else if (period == SKGRecurrentOperationObject::YEAR) { 0208 nbd = nbd / (365 * occu); 0209 } 0210 0211 if (nbd < -1) { 0212 nbd = -1; 0213 } 0214 return setTimeLimit(nbd + 1); 0215 } 0216 0217 SKGError SKGRecurrentOperationObject::setTimeLimit(int iTimeLimit) 0218 { 0219 return setAttribute(QStringLiteral("i_nb_times"), SKGServices::intToString(iTimeLimit)); 0220 } 0221 0222 int SKGRecurrentOperationObject::getTimeLimit() const 0223 { 0224 return SKGServices::stringToInt(getAttribute(QStringLiteral("i_nb_times"))); 0225 } 0226 0227 SKGError SKGRecurrentOperationObject::setDate(QDate iDate) 0228 { 0229 return setAttribute(QStringLiteral("d_date"), SKGServices::dateToSqlString(iDate)); 0230 } 0231 0232 QDate SKGRecurrentOperationObject::getNextDate() const 0233 { 0234 QDate nextDate = getDate(); 0235 SKGRecurrentOperationObject::PeriodUnit punit = getPeriodUnit(); 0236 int p = getPeriodIncrement(); 0237 if (punit == SKGRecurrentOperationObject::DAY) { 0238 nextDate = nextDate.addDays(p); 0239 } else if (punit == SKGRecurrentOperationObject::WEEK) { 0240 nextDate = nextDate.addDays(7 * p); 0241 } else if (punit == SKGRecurrentOperationObject::MONTH) { 0242 nextDate = nextDate.addMonths(p); 0243 } else if (punit == SKGRecurrentOperationObject::YEAR) { 0244 nextDate = nextDate.addYears(p); 0245 } 0246 return nextDate; 0247 } 0248 0249 QDate SKGRecurrentOperationObject::getDate() const 0250 { 0251 return SKGServices::stringToTime(getAttribute(QStringLiteral("d_date"))).date(); 0252 } 0253 0254 SKGError SKGRecurrentOperationObject::warnEnabled(bool iWarn) 0255 { 0256 return setAttribute(QStringLiteral("t_warn"), iWarn ? QStringLiteral("Y") : QStringLiteral("N")); 0257 } 0258 0259 bool SKGRecurrentOperationObject::isWarnEnabled() const 0260 { 0261 return (getAttribute(QStringLiteral("t_warn")) == QStringLiteral("Y")); 0262 } 0263 0264 SKGError SKGRecurrentOperationObject::autoWriteEnabled(bool iAutoWrite) 0265 { 0266 return setAttribute(QStringLiteral("t_auto_write"), iAutoWrite ? QStringLiteral("Y") : QStringLiteral("N")); 0267 } 0268 0269 bool SKGRecurrentOperationObject::isAutoWriteEnabled() const 0270 { 0271 return (getAttribute(QStringLiteral("t_auto_write")) == QStringLiteral("Y")); 0272 } 0273 0274 SKGError SKGRecurrentOperationObject::getRecurredOperations(SKGListSKGObjectBase& oOperations) const 0275 { 0276 return getDocument()->getObjects(QStringLiteral("v_operation"), "r_recurrentoperation_id=" % SKGServices::intToString(getID()) % " ORDER BY d_date", oOperations); 0277 } 0278 0279 SKGError SKGRecurrentOperationObject::process(int& oNbInserted, bool iForce, QDate iDate) 0280 { 0281 SKGError err; 0282 SKGTRACEINFUNCRC(10, err) 0283 oNbInserted = 0; 0284 0285 if (!hasTimeLimit() || getTimeLimit() > 0) { 0286 if (isAutoWriteEnabled() || iForce) { 0287 QDate nextDate = getDate(); 0288 if (nextDate.isValid() && iDate >= nextDate.addDays(-getAutoWriteDays())) { 0289 SKGOperationObject op; 0290 err = getParentOperation(op); 0291 IFOK(err) { 0292 // Create the duplicated operation 0293 SKGOperationObject newOp; 0294 err = op.duplicate(newOp, nextDate); 0295 IFOKDO(err, newOp.setRecurrentOperation(getID())) 0296 IFOKDO(err, load()) 0297 0298 if (!err && hasTimeLimit()) { 0299 err = setTimeLimit(getTimeLimit() - 1); 0300 } 0301 IFOKDO(err, save()) 0302 0303 // Process again in case of multi insert needed 0304 int nbi = 0; 0305 IFOKDO(err, process(nbi, iForce, iDate)) 0306 oNbInserted = oNbInserted + 1 + nbi; 0307 0308 // Send message 0309 IFOKDO(err, newOp.load()) 0310 IFOK(err) { 0311 err = getDocument()->sendMessage(i18nc("An information message", "Transaction '%1' has been inserted", newOp.getDisplayName()), SKGDocument::Positive); 0312 } 0313 } 0314 } 0315 } 0316 0317 if (isWarnEnabled() && !err) { 0318 QDate nextDate = getDate(); 0319 if (QDate::currentDate() >= nextDate.addDays(-getWarnDays())) { 0320 SKGOperationObject op; 0321 err = getParentOperation(op); 0322 IFOK(err) { 0323 int nbdays = QDate::currentDate().daysTo(nextDate); 0324 if (nbdays > 0) { 0325 err = getDocument()->sendMessage(i18np("Transaction '%2' will be inserted in one day", "Transaction '%2' will be inserted in %1 days", nbdays, getDisplayName())); 0326 } 0327 } 0328 } 0329 } 0330 } 0331 return err; 0332 } 0333 0334 SKGError SKGRecurrentOperationObject::process(SKGDocumentBank* iDocument, int& oNbInserted, bool iForce, QDate iDate) 0335 { 0336 SKGError err; 0337 oNbInserted = 0; 0338 0339 // Get all transaction with auto_write 0340 SKGListSKGObjectBase recuOps; 0341 if (iDocument != nullptr) { 0342 err = iDocument->getObjects(QStringLiteral("v_recurrentoperation"), QLatin1String(""), recuOps); 0343 } 0344 0345 int nb = recuOps.count(); 0346 for (int i = 0; !err && i < nb; ++i) { 0347 SKGRecurrentOperationObject recu(recuOps.at(i)); 0348 int nbi = 0; 0349 err = recu.process(nbi, iForce, iDate); 0350 oNbInserted += nbi; 0351 } 0352 0353 return err; 0354 } 0355 0356 0357