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 SKGOperationObject. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgoperationobject.h" 0012 0013 #include <klocalizedstring.h> 0014 0015 #include "skgaccountobject.h" 0016 #include "skgdocument.h" 0017 #include "skgpayeeobject.h" 0018 #include "skgrecurrentoperationobject.h" 0019 #include "skgservices.h" 0020 #include "skgsuboperationobject.h" 0021 #include "skgtraces.h" 0022 #include "skgunitobject.h" 0023 0024 SKGOperationObject::SKGOperationObject() : SKGOperationObject(nullptr) 0025 {} 0026 0027 SKGOperationObject::SKGOperationObject(SKGDocument* iDocument, int iID) : SKGObjectBase(iDocument, QStringLiteral("v_operation"), iID) 0028 {} 0029 0030 SKGOperationObject::~SKGOperationObject() 0031 = default; 0032 0033 SKGOperationObject::SKGOperationObject(const SKGOperationObject& iObject) 0034 = default; 0035 0036 SKGOperationObject::SKGOperationObject(const SKGObjectBase& iObject) 0037 { 0038 if (iObject.getRealTable() == QStringLiteral("operation")) { 0039 copyFrom(iObject); 0040 } else { 0041 *this = SKGObjectBase(iObject.getDocument(), QStringLiteral("v_operation"), iObject.getID()); 0042 } 0043 } 0044 0045 SKGOperationObject& SKGOperationObject::operator= (const SKGObjectBase& iObject) 0046 { 0047 copyFrom(iObject); 0048 return *this; 0049 } 0050 0051 SKGOperationObject& SKGOperationObject::operator= (const SKGOperationObject& iObject) 0052 { 0053 copyFrom(iObject); 0054 return *this; 0055 } 0056 0057 SKGError SKGOperationObject::duplicate(SKGOperationObject& oOperation, QDate iDate, bool iTemplateMode) const 0058 { 0059 SKGError err; 0060 SKGTRACEINFUNCRC(20, err) 0061 QDate previousDate = getDate(); 0062 0063 // Create the duplicated operation 0064 oOperation = SKGOperationObject(getDocument(), this->getID()); // To be sure the object is on v_operation 0065 IFOKDO(err, oOperation.load()) 0066 IFOKDO(err, oOperation.resetID()) 0067 IFOKDO(err, oOperation.setDate(iDate)) 0068 IFOKDO(err, oOperation.setStatus(SKGOperationObject::NONE)) 0069 IFOKDO(err, oOperation.setImported(false)) 0070 IFOKDO(err, oOperation.setTemplate(iTemplateMode)) 0071 IFOKDO(err, oOperation.setImportID(QLatin1String(""))) 0072 IFOKDO(err, oOperation.bookmark(false)) 0073 IFOKDO(err, oOperation.setNumber(QLatin1String(""))) 0074 IFOKDO(err, oOperation.setGroupOperation(oOperation)) 0075 IFOKDO(err, oOperation.setAttribute(QStringLiteral("d_createdate"), SKGServices::dateToSqlString(QDateTime::currentDateTime()))) 0076 IFOKDO(err, oOperation.save(false, false)) 0077 0078 // Duplicate subop 0079 IFOK(err) { 0080 SKGListSKGObjectBase subops; 0081 err = getSubOperations(subops); 0082 int nbsupops = subops.count(); 0083 for (int i = 0; !err && i < nbsupops; ++i) { 0084 SKGSubOperationObject subop(subops.at(i)); 0085 err = subop.resetID(); 0086 IFOKDO(err, subop.setParentOperation(oOperation)) 0087 IFOKDO(err, subop.setDate(subop.getDate().addDays(previousDate.daysTo(iDate)))) 0088 IFOKDO(err, subop.save(false)) 0089 } 0090 } 0091 0092 // Duplicate grouped transaction to support recurrent transfers 0093 IFOK(err) { 0094 SKGListSKGObjectBase goupops; 0095 err = getGroupedOperations(goupops); 0096 int nbgoupops = goupops.count(); 0097 for (int i = 0; !err && i < nbgoupops; ++i) { 0098 SKGOperationObject groupop(goupops.at(i)); 0099 if (groupop != *this) { 0100 // Create the duplicated operation 0101 SKGOperationObject newgroupop = groupop; 0102 err = newgroupop.resetID(); 0103 IFOKDO(err, newgroupop.setDate(iDate)) 0104 IFOKDO(err, newgroupop.setStatus(SKGOperationObject::NONE)) 0105 IFOKDO(err, newgroupop.setImported(false)) 0106 IFOKDO(err, newgroupop.setTemplate(iTemplateMode)) 0107 IFOKDO(err, newgroupop.setImportID(QLatin1String(""))) 0108 IFOKDO(err, newgroupop.bookmark(false)) 0109 IFOKDO(err, newgroupop.setNumber(QLatin1String(""))) 0110 IFOKDO(err, newgroupop.setGroupOperation(newgroupop)) 0111 IFOKDO(err, newgroupop.setGroupOperation(oOperation)) 0112 IFOKDO(err, newgroupop.save(false)) 0113 0114 // Duplicate subop 0115 IFOK(err) { 0116 SKGListSKGObjectBase subops; 0117 err = groupop.getSubOperations(subops); 0118 int nbsupops = subops.count(); 0119 for (int j = 0; !err && j < nbsupops; ++j) { 0120 SKGSubOperationObject subop(subops.at(j)); 0121 err = subop.resetID(); 0122 IFOKDO(err, subop.setParentOperation(newgroupop)) 0123 IFOKDO(err, subop.setDate(subop.getDate().addDays(previousDate.daysTo(iDate)))) 0124 IFOKDO(err, subop.save(false)) 0125 } 0126 } 0127 } 0128 } 0129 } 0130 0131 IFOKDO(err, oOperation.load()) 0132 return err; 0133 } 0134 0135 0136 SKGError SKGOperationObject::getParentAccount(SKGAccountObject& oAccount) const 0137 { 0138 SKGObjectBase objTmp; 0139 SKGError err = getDocument()->getObject(QStringLiteral("v_account"), "id=" % getAttribute(QStringLiteral("rd_account_id")), objTmp); 0140 oAccount = objTmp; 0141 return err; 0142 } 0143 0144 SKGError SKGOperationObject::setParentAccount(const SKGAccountObject& iAccount, bool iForce) 0145 { 0146 SKGError err; 0147 QString currentAccount = getAttribute(QStringLiteral("rd_account_id")); 0148 QString newAccount = SKGServices::intToString(iAccount.getID()); 0149 if (newAccount == QStringLiteral("0")) { 0150 err = SKGError(ERR_FAIL, i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGOperationObject::setParentAccount"))); 0151 } else { 0152 if (newAccount != currentAccount) { 0153 if (iAccount.isClosed() && !iForce) { 0154 err = SKGError(ERR_FAIL, i18nc("Error message", "Impossible to add a transaction in a closed account")); 0155 } else { 0156 err = setAttribute(QStringLiteral("rd_account_id"), newAccount); 0157 } 0158 } 0159 } 0160 return err; 0161 } 0162 0163 SKGError SKGOperationObject::setMode(const QString& iMode) 0164 { 0165 return setAttribute(QStringLiteral("t_mode"), iMode); 0166 } 0167 0168 QString SKGOperationObject::getMode() const 0169 { 0170 return getAttribute(QStringLiteral("t_mode")); 0171 } 0172 0173 SKGError SKGOperationObject::setPayee(const SKGPayeeObject& iPayee) 0174 { 0175 return setAttribute(QStringLiteral("r_payee_id"), SKGServices::intToString(iPayee.getID())); 0176 } 0177 0178 SKGError SKGOperationObject::getPayee(SKGPayeeObject& oPayee) const 0179 { 0180 SKGError err = getDocument()->getObject(QStringLiteral("v_payee"), "id=" % SKGServices::intToString(SKGServices::stringToInt(getAttribute(QStringLiteral("r_payee_id")))), oPayee); 0181 return err; 0182 } 0183 0184 SKGError SKGOperationObject::setComment(const QString& iComment) 0185 { 0186 return setAttribute(QStringLiteral("t_comment"), iComment); 0187 } 0188 0189 QString SKGOperationObject::getComment() const 0190 { 0191 return getAttribute(QStringLiteral("t_comment")); 0192 } 0193 0194 SKGError SKGOperationObject::setNumber(const QString& iNumber) 0195 { 0196 return setAttribute(QStringLiteral("t_number"), iNumber); 0197 } 0198 0199 QString SKGOperationObject::getNumber() const 0200 { 0201 return getAttribute(QStringLiteral("t_number")); 0202 } 0203 0204 SKGOperationObject::OperationStatus SKGOperationObject::getStatus() const 0205 { 0206 QString t_status = getAttribute(QStringLiteral("t_status")); 0207 if (t_status == QStringLiteral("Y")) { 0208 return SKGOperationObject::CHECKED; 0209 } 0210 if (t_status == QStringLiteral("P")) { 0211 return SKGOperationObject::MARKED; 0212 } 0213 return SKGOperationObject::NONE; 0214 } 0215 0216 SKGError SKGOperationObject::setStatus(SKGOperationObject::OperationStatus iStatus) 0217 { 0218 return setAttribute(QStringLiteral("t_status"), (iStatus == SKGOperationObject::CHECKED ? QStringLiteral("Y") : (iStatus == SKGOperationObject::MARKED ? QStringLiteral("P") : QStringLiteral("N")))); 0219 } 0220 0221 SKGError SKGOperationObject::setDate(QDate iDate, bool iRefreshSubOperations) 0222 { 0223 SKGError err; 0224 // Compute delta of the change of date 0225 QDate previousDate = getDate(); 0226 if (iRefreshSubOperations) { 0227 // Apply the delta on sub transactions 0228 SKGObjectBase::SKGListSKGObjectBase listSubOperations; 0229 getSubOperations(listSubOperations); // Error is not manage to avoid error in case of first creation 0230 int nbSubOperations = listSubOperations.count(); 0231 for (int i = 0; !err && i < nbSubOperations; ++i) { 0232 SKGSubOperationObject sop(listSubOperations.at(i)); 0233 QDate previousSubDate = sop.getDate(); 0234 if (previousSubDate.isValid()) { 0235 if (previousDate.isValid()) { 0236 int delta = previousDate.daysTo(iDate); 0237 err = sop.setDate(previousSubDate.addDays(delta)); 0238 IFOKDO(err, sop.save(true, false)) 0239 } 0240 } else { 0241 err = sop.setDate(iDate); 0242 IFOKDO(err, sop.save(true, false)) 0243 } 0244 } 0245 } 0246 IFOKDO(err, setAttribute(QStringLiteral("d_date"), SKGServices::dateToSqlString(iDate))) 0247 return err; 0248 } 0249 0250 QDate SKGOperationObject::getDate() const 0251 { 0252 return SKGServices::stringToTime(getAttribute(QStringLiteral("d_date"))).date(); 0253 } 0254 0255 SKGError SKGOperationObject::getUnit(SKGUnitObject& oUnit) const 0256 { 0257 SKGError err = (getDocument() == nullptr ? SKGError(ERR_POINTER, i18nc("Error message", "Transaction impossible because the document is missing")) : getDocument()->getObject(QStringLiteral("v_unit"), "id=" % getAttribute(QStringLiteral("rc_unit_id")), oUnit)); 0258 // SKGError err = getDocument()->getObject(QStringLiteral("v_unit"), "id=" % getAttribute(QStringLiteral("rc_unit_id")), oUnit); 0259 return err; 0260 } 0261 0262 SKGError SKGOperationObject::setUnit(const SKGUnitObject& iUnit) 0263 { 0264 return setAttribute(QStringLiteral("rc_unit_id"), SKGServices::intToString(iUnit.getID())); 0265 } 0266 0267 bool SKGOperationObject::isInGroup() const 0268 { 0269 return (getAttribute(QStringLiteral("i_group_id")) != QStringLiteral("0")); 0270 } 0271 0272 bool SKGOperationObject::isTransfer(SKGOperationObject& oOperation) const 0273 { 0274 SKGTRACEINFUNC(10) 0275 SKGObjectBase::SKGListSKGObjectBase ops; 0276 getGroupedOperations(ops); 0277 if (ops.count() == 2) { 0278 oOperation = (*this == SKGOperationObject(ops.at(0)) ? ops.at(1) : ops.at(0)); 0279 } 0280 return (getAttribute(QStringLiteral("t_TRANSFER")) == QStringLiteral("Y")); 0281 } 0282 0283 SKGError SKGOperationObject::getGroupedOperations(SKGListSKGObjectBase& oGroupedOperations) const 0284 { 0285 SKGError err; 0286 QString gpId1 = getAttribute(QStringLiteral("i_group_id")); 0287 if (gpId1 == QStringLiteral("0") || gpId1.isEmpty()) { 0288 oGroupedOperations.clear(); 0289 } else { 0290 err = getDocument()->getObjects(QStringLiteral("v_operation"), "i_group_id=" % gpId1, oGroupedOperations); 0291 } 0292 return err; 0293 } 0294 0295 SKGError SKGOperationObject::getGroupOperation(SKGOperationObject& oOperation) const 0296 { 0297 SKGError err = getDocument()->getObject(QStringLiteral("v_operation"), "id=" % getAttribute(QStringLiteral("i_group_id")), oOperation); 0298 return err; 0299 } 0300 0301 SKGError SKGOperationObject::setGroupOperation(const SKGOperationObject& iOperation) 0302 { 0303 SKGError err; 0304 SKGTRACEINFUNCRC(20, err) 0305 0306 // Is it a remove group ? 0307 if (iOperation == *this) { 0308 // Yes 0309 err = setAttribute(QStringLiteral("i_group_id"), QStringLiteral("0")); 0310 } else { 0311 // Get previous groups 0312 QString group1 = getAttribute(QStringLiteral("i_group_id")); 0313 QString group2 = iOperation.getAttribute(QStringLiteral("i_group_id")); 0314 0315 // Create a new group 0316 SKGStringListList result; 0317 err = getDocument()->executeSelectSqliteOrder(QStringLiteral("SELECT max(i_group_id) from operation"), result); 0318 IFOK(err) { 0319 // Compute new group id 0320 QString newIdGroup('1'); 0321 if (result.count() == 2) { 0322 newIdGroup = SKGServices::intToString(SKGServices::stringToInt(result.at(1).at(0)) + 1); 0323 } 0324 0325 // Set group id 0326 SKGOperationObject op1 = SKGOperationObject(iOperation.getDocument(), iOperation.getID()); 0327 err = op1.setAttribute(QStringLiteral("i_group_id"), newIdGroup); 0328 IFOKDO(err, op1.save(true, false)) 0329 0330 IFOKDO(err, setAttribute(QStringLiteral("i_group_id"), newIdGroup)) 0331 0332 // Update all objects of group2 0333 if (!err && !group1.isEmpty() && group1 != QStringLiteral("0")) { 0334 err = getDocument()->executeSqliteOrder("UPDATE operation SET i_group_id=" % newIdGroup % " WHERE i_group_id=" % group1); 0335 } 0336 0337 // Update all objects of group2 0338 if (!err && !group2.isEmpty() && group2 != QStringLiteral("0")) { 0339 err = getDocument()->executeSqliteOrder("UPDATE operation SET i_group_id=" % newIdGroup % " WHERE i_group_id=" % group2); 0340 } 0341 } 0342 } 0343 0344 return err; 0345 } 0346 0347 SKGError SKGOperationObject::bookmark(bool iBookmark) 0348 { 0349 return setAttribute(QStringLiteral("t_bookmarked"), iBookmark ? QStringLiteral("Y") : QStringLiteral("N")); 0350 } 0351 0352 bool SKGOperationObject::isBookmarked() const 0353 { 0354 return (getAttribute(QStringLiteral("t_bookmarked")) == QStringLiteral("Y")); 0355 } 0356 0357 SKGError SKGOperationObject::setImported(bool iImported) 0358 { 0359 return setAttribute(QStringLiteral("t_imported"), iImported ? QStringLiteral("Y") : QStringLiteral("N")); 0360 } 0361 0362 bool SKGOperationObject::isImported() const 0363 { 0364 return (getAttribute(QStringLiteral("t_imported")) != QStringLiteral("N")); 0365 } 0366 0367 SKGError SKGOperationObject::setImportID(const QString& iImportID) 0368 { 0369 SKGError err = setAttribute(QStringLiteral("t_import_id"), iImportID); 0370 if (!err && !iImportID.isEmpty()) { 0371 err = setAttribute(QStringLiteral("t_imported"), QStringLiteral("T")); 0372 } 0373 return err; 0374 } 0375 0376 QString SKGOperationObject::getImportID() const 0377 { 0378 return getAttribute(QStringLiteral("t_import_id")); 0379 } 0380 0381 SKGError SKGOperationObject::setTemplate(bool iTemplate) 0382 { 0383 return setAttribute(QStringLiteral("t_template"), iTemplate ? QStringLiteral("Y") : QStringLiteral("N")); 0384 } 0385 0386 bool SKGOperationObject::isTemplate() const 0387 { 0388 return (getAttribute(QStringLiteral("t_template")) != QStringLiteral("N")); 0389 } 0390 0391 int SKGOperationObject::getNbSubOperations() const 0392 { 0393 return SKGServices::stringToInt(getAttribute(QStringLiteral("i_NBSUBOPERATIONS"))); 0394 } 0395 0396 SKGError SKGOperationObject::addSubOperation(SKGSubOperationObject& oSubOperation) 0397 { 0398 SKGError err; 0399 if (getID() == 0) { 0400 err = SKGError(ERR_FAIL, i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGOperationObject::addSubOperation"))); 0401 } else { 0402 oSubOperation = SKGSubOperationObject(getDocument()); 0403 err = oSubOperation.setParentOperation(*this); 0404 IFOKDO(err, oSubOperation.setDate(getDate())) 0405 } 0406 return err; 0407 } 0408 0409 SKGError SKGOperationObject::getSubOperations(SKGListSKGObjectBase& oSubOperations) const 0410 { 0411 SKGError err; 0412 if (getID() == 0) { 0413 err = SKGError(ERR_FAIL, i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGOperationObject::getSubOperations"))); 0414 } else { 0415 err = getDocument()->getObjects(QStringLiteral("v_suboperation"), 0416 "rd_operation_id=" % SKGServices::intToString(getID()) % " ORDER BY i_order", oSubOperations); 0417 } 0418 return err; 0419 } 0420 0421 double SKGOperationObject::getCurrentAmount() const 0422 { 0423 return SKGServices::stringToDouble(getAttribute(QStringLiteral("f_CURRENTAMOUNT"))); 0424 } 0425 0426 double SKGOperationObject::getBalance() const 0427 { 0428 double output = 0.0; 0429 SKGStringListList result; 0430 SKGError err = getDocument()->executeSelectSqliteOrder("SELECT TOTAL(f_CURRENTAMOUNT) FROM v_operation WHERE t_template='N' AND " 0431 "rd_account_id=" % getAttribute(QStringLiteral("rd_account_id")) % " AND (d_date<'" % getAttribute(QStringLiteral("d_date")) % "' OR " 0432 "(d_date='" % getAttribute(QStringLiteral("d_date")) % "' AND id<=" % SKGServices::intToString(getID()) % "))", result); 0433 IFOK(err) { 0434 output = SKGServices::stringToDouble(result.at(1).at(0)); 0435 } 0436 0437 return output; 0438 } 0439 0440 double SKGOperationObject::getAmount(QDate iDate) const 0441 { 0442 // Get quantity 0443 double quantity = SKGServices::stringToDouble(getAttribute(QStringLiteral("f_QUANTITY"))); 0444 0445 // Is the unit value already in cache ? 0446 double coef = 1; 0447 QString val = getDocument()->getCachedValue("unitvalue-" % getAttribute(QStringLiteral("rc_unit_id"))); 0448 if (!val.isEmpty()) { 0449 // Yes 0450 coef = SKGServices::stringToDouble(val); 0451 } else { 0452 // No 0453 SKGUnitObject unit; 0454 if (getUnit(unit).isSucceeded()) { 0455 coef = unit.getAmount(iDate); 0456 } 0457 } 0458 0459 return coef * quantity; 0460 } 0461 0462 SKGError SKGOperationObject::addRecurrentOperation(SKGRecurrentOperationObject& oRecurrentOperation) const 0463 { 0464 SKGError err; 0465 if (getID() == 0) { 0466 err = SKGError(ERR_FAIL, i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGOperationObject::addRecurrentOperation"))); 0467 } else { 0468 oRecurrentOperation = SKGRecurrentOperationObject(getDocument()); 0469 err = oRecurrentOperation.setParentOperation(*this); 0470 IFOK(err) oRecurrentOperation.setDate(getDate()); 0471 } 0472 return err; 0473 } 0474 0475 SKGError SKGOperationObject::getRecurrentOperations(SKGListSKGObjectBase& oRecurrentOperation) const 0476 { 0477 SKGError err; 0478 if (getID() == 0) { 0479 err = SKGError(ERR_FAIL, i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGOperationObject::getRecurrentOperation"))); 0480 } else { 0481 err = getDocument()->getObjects(QStringLiteral("v_recurrentoperation"), 0482 "rd_operation_id=" % SKGServices::intToString(getID()), oRecurrentOperation); 0483 } 0484 return err; 0485 } 0486 0487 int SKGOperationObject::getRecurrentOperation() const 0488 { 0489 const auto recurrentId = SKGServices::stringToInt(getAttribute(QStringLiteral("r_recurrentoperation_id"))); 0490 if (recurrentId != 0) { 0491 return recurrentId; 0492 } else { 0493 SKGObjectBase::SKGListSKGObjectBase recops; 0494 SKGError err = getRecurrentOperations(recops); 0495 IFOK(err) { 0496 if (!recops.isEmpty()) { 0497 return recops.first().getID(); 0498 } 0499 } 0500 } 0501 0502 return 0; 0503 } 0504 0505 SKGError SKGOperationObject::setRecurrentOperation(int recurrentId) 0506 { 0507 SKGError err; 0508 const auto currentRecurrentId = getRecurrentOperation(); 0509 if (currentRecurrentId != 0 && recurrentId != 0 && currentRecurrentId == recurrentId) { 0510 err = SKGError(ERR_FAIL, i18nc("Error message", "Trying to set the same recurrent transaction with id=%1.", recurrentId)); 0511 return err; 0512 } else if (isTemplate()) { 0513 err = SKGError(ERR_FAIL, i18nc("Error message", "Cannot set a recurrent for a template operation.")); 0514 return err; 0515 } 0516 0517 SKGRecurrentOperationObject oldRop(getDocument(), currentRecurrentId); 0518 SKGRecurrentOperationObject newRop(getDocument(), recurrentId); 0519 if (oldRop.exist()) { 0520 // Unlink from the current schedule 0521 SKGOperationObject oldRopParent; 0522 err = oldRop.getParentOperation(oldRopParent); 0523 if (oldRopParent == *this) { 0524 SKGObjectBase::SKGListSKGObjectBase transactions; 0525 IFOKDO(err, oldRop.getRecurredOperations(transactions)) 0526 IFOK(err) { 0527 if (!transactions.isEmpty()) { 0528 SKGOperationObject lastObj(transactions.last()); 0529 IFOKDO(err, oldRop.setParentOperation(lastObj)) 0530 IFOKDO(err, oldRop.setDate(lastObj.getDate())) 0531 IFOKDO(err, oldRop.setDate(oldRop.getNextDate())) 0532 IFOKDO(err, oldRop.save()) 0533 IFOKDO(err, lastObj.setAttribute(QStringLiteral("r_recurrentoperation_id"), QString("0"))) 0534 IFOKDO(err, lastObj.save()) 0535 } else { 0536 IFOKDO(err, oldRop.remove(true, true)) 0537 } 0538 } 0539 } 0540 0541 IFOKDO(err, setAttribute(QStringLiteral("r_recurrentoperation_id"), QString("0"))) 0542 IFOKDO(err, save()) 0543 } 0544 0545 if (newRop.exist()) { 0546 // Link to a new schedule 0547 const auto currentDate = getDate(); 0548 QDate lastDate; 0549 SKGOperationObject newRopParent; 0550 err = newRop.getParentOperation(newRopParent); 0551 if (newRopParent.isTemplate()) { 0552 SKGObjectBase::SKGListSKGObjectBase transactions; 0553 IFOKDO(err, newRop.getRecurredOperations(transactions)) 0554 IFOK(err) { 0555 if (!transactions.isEmpty()) { 0556 SKGOperationObject lastObj(transactions.last()); 0557 lastDate = lastObj.getDate(); 0558 } 0559 } 0560 } else { 0561 lastDate = newRopParent.getDate(); 0562 } 0563 if (currentDate.isValid() && lastDate.isValid() && currentDate >= lastDate) { 0564 IFOK(err) { 0565 if (!newRopParent.isTemplate()) { 0566 // Set old parent op as recurrent 0567 IFOKDO(err, newRopParent.setAttribute(QStringLiteral("r_recurrentoperation_id"), SKGServices::intToString(recurrentId))) 0568 IFOKDO(err, newRopParent.save()) 0569 0570 // Set this transaction as reference 0571 IFOKDO(err, newRop.setParentOperation(*this)) 0572 } else { 0573 // Set this op as recurrent 0574 IFOKDO(err, setAttribute(QStringLiteral("r_recurrentoperation_id"), SKGServices::intToString(recurrentId))) 0575 IFOKDO(err, save()) 0576 } 0577 0578 IFOKDO(err, newRop.setDate(currentDate)) 0579 IFOKDO(err, newRop.setDate(newRop.getNextDate())) 0580 IFOKDO(err, newRop.save()) 0581 } 0582 } else { 0583 IFOKDO(err, setAttribute(QStringLiteral("r_recurrentoperation_id"), SKGServices::intToString(recurrentId))) 0584 IFOKDO(err, save()) 0585 } 0586 } 0587 0588 return err; 0589 } 0590 0591 SKGError SKGOperationObject::mergeAttribute(const SKGOperationObject& iDeletedOne, SKGOperationObject::AmountAlignmentMode iMode, bool iSendMessage) 0592 { 0593 // Merge operation 0594 SKGError err = setDate(iDeletedOne.getDate()); 0595 IFOKDO(err, setImportID(iDeletedOne.getImportID())) 0596 IFOKDO(err, setAttribute(QStringLiteral("t_imported"), iDeletedOne.getAttribute(QStringLiteral("t_imported")))) 0597 if (!err && getComment().isEmpty()) { 0598 err = setComment(iDeletedOne.getComment()); 0599 } 0600 SKGPayeeObject payee; 0601 getPayee(payee); 0602 if (!err && !payee.exist()) { 0603 iDeletedOne.getPayee(payee); 0604 err = setPayee(payee); 0605 } 0606 if (!err && getMode().isEmpty()) { 0607 err = setMode(iDeletedOne.getMode()); 0608 } 0609 if (!err && !isBookmarked()) { 0610 err = bookmark(iDeletedOne.isBookmarked()); 0611 } 0612 if (!err && getNumber().isEmpty()) { 0613 err = setNumber(iDeletedOne.getNumber()); 0614 } 0615 IFOKDO(err, save()) 0616 0617 // Merge subtransactions 0618 double currentAmount = getCurrentAmount(); 0619 double targettAmount = iDeletedOne.getCurrentAmount(); 0620 if (qAbs(currentAmount - targettAmount) > 0.0001) { 0621 SKGObjectBase::SKGListSKGObjectBase subOps1; 0622 IFOKDO(err, getSubOperations(subOps1)) 0623 0624 SKGObjectBase::SKGListSKGObjectBase subOps2; 0625 IFOKDO(err, iDeletedOne.getSubOperations(subOps2)) 0626 0627 // Align amounts 0628 SKGOperationObject::AmountAlignmentMode mode = iMode; 0629 if (mode == DEFAULT) { 0630 if (subOps2.count() == 1 && subOps1.count() == 1) { 0631 mode = PROPORTIONAL; 0632 } else if (subOps2.count() >= 1 && subOps1.count() >= 1) { 0633 mode = ADDSUBOPERATION; 0634 } 0635 } 0636 0637 if (mode == SKGOperationObject::ADDSUBOPERATION) { 0638 // Add sub transaction to align amount 0639 SKGSubOperationObject so1; 0640 IFOKDO(err, addSubOperation(so1)) 0641 IFOKDO(err, so1.setQuantity(targettAmount - currentAmount)) 0642 IFOKDO(err, so1.save()) 0643 } else { 0644 // Keep ratio 0645 for (const auto& sopbase : qAsConst(subOps1)) { 0646 SKGSubOperationObject sop(sopbase); 0647 IFOKDO(err, sop.setQuantity(targettAmount * sop.getQuantity() / currentAmount)) 0648 IFOKDO(err, sop.save()) 0649 } 0650 } 0651 IFOKDO(err, load()) 0652 if (iSendMessage) { 0653 IFOK(err) getDocument()->sendMessage(i18nc("An information message", "Amount has been changed to be aligned with the imported transaction"), SKGDocument::Positive); 0654 } 0655 } 0656 0657 // transfers properties 0658 IFOKDO(err, getDocument()->executeSqliteOrder(QStringLiteral("DELETE FROM parameters WHERE t_uuid_parent='") % getUniqueID() % QStringLiteral("' AND t_name IN (SELECT t_name FROM parameters WHERE t_uuid_parent='") % iDeletedOne.getUniqueID() % QStringLiteral("')"))) 0659 IFOKDO(err, getDocument()->executeSqliteOrder(QStringLiteral("UPDATE parameters SET t_uuid_parent='") % getUniqueID() % QStringLiteral("' WHERE t_uuid_parent='") % iDeletedOne.getUniqueID() % QStringLiteral("'"))) 0660 0661 // Delete useless operation 0662 IFOKDO(err, iDeletedOne.remove(false, true)) 0663 return err; 0664 } 0665 0666 SKGError SKGOperationObject::mergeSuboperations(const SKGOperationObject& iDeletedOne) 0667 { 0668 SKGError err; 0669 SKGObjectBase::SKGListSKGObjectBase subops; 0670 err = iDeletedOne.getSubOperations(subops); 0671 int nb = subops.count(); 0672 for (int i = 0; !err && i < nb; ++i) { 0673 SKGSubOperationObject subop(subops.at(i)); 0674 err = subop.setParentOperation(*this); 0675 IFOKDO(err, subop.save()) 0676 } 0677 IFOKDO(err, iDeletedOne.remove(false)) 0678 return err; 0679 } 0680 0681 0682