MyMoneyTransaction KMyMoneyUtils::scheduledTransaction(const MyMoneySchedule& schedule) { MyMoneyTransaction t = schedule.transaction(); try { if (schedule.type() == MyMoneySchedule::TYPE_LOANPAYMENT) { calculateAutoLoan(schedule, t, QMap<QString, MyMoneyMoney>()); } } catch (const MyMoneyException &e) { qDebug("Unable to load schedule details for '%s' during transaction match: %s", qPrintable(schedule.name()), qPrintable(e.what())); } t.clearId(); t.setEntryDate(QDate()); return t; }
void MyMoneyForecast::calculateAutoLoan(const MyMoneySchedule& schedule, MyMoneyTransaction& transaction, const QMap<QString, MyMoneyMoney>& balances) { if (schedule.type() == MyMoneySchedule::TYPE_LOANPAYMENT) { //get amortization and interest autoCalc splits MyMoneySplit amortizationSplit = transaction.amortizationSplit(); MyMoneySplit interestSplit = transaction.interestSplit(); if(!amortizationSplit.id().isEmpty() && !interestSplit.id().isEmpty()) { MyMoneyAccountLoan acc(MyMoneyFile::instance()->account(amortizationSplit.accountId())); MyMoneyFinancialCalculator calc; QDate dueDate; // FIXME: setup dueDate according to when the interest should be calculated // current implementation: take the date of the next payment according to // the schedule. If the calculation is based on the payment reception, and // the payment is overdue then take the current date dueDate = schedule.nextDueDate(); if(acc.interestCalculation() == MyMoneyAccountLoan::paymentReceived) { if(dueDate < QDate::currentDate()) dueDate = QDate::currentDate(); } // we need to calculate the balance at the time the payment is due MyMoneyMoney balance; if(balances.count() == 0) balance = MyMoneyFile::instance()->balance(acc.id(), dueDate.addDays(-1)); else balance = balances[acc.id()]; /* QValueList<MyMoneyTransaction> list; QValueList<MyMoneyTransaction>::ConstIterator it; MyMoneySplit split; MyMoneyTransactionFilter filter(acc.id()); filter.setDateFilter(QDate(), dueDate.addDays(-1)); list = MyMoneyFile::instance()->transactionList(filter); for(it = list.begin(); it != list.end(); ++it) { try { split = (*it).splitByAccount(acc.id()); balance += split.value(); } catch(MyMoneyException *e) { // account is not referenced within this transaction delete e; } } */ // FIXME: for now, we only support interest calculation at the end of the period calc.setBep(); // FIXME: for now, we only support periodic compounding calc.setDisc(); calc.setPF(MyMoneySchedule::eventsPerYear(schedule.occurence())); MyMoneySchedule::occurenceE compoundingOccurence = static_cast<MyMoneySchedule::occurenceE>(acc.interestCompounding()); if(compoundingOccurence == MyMoneySchedule::OCCUR_ANY) compoundingOccurence = schedule.occurence(); calc.setCF(MyMoneySchedule::eventsPerYear(compoundingOccurence)); calc.setPv(balance.toDouble()); calc.setIr(static_cast<FCALC_DOUBLE> (acc.interestRate(dueDate).abs().toDouble())); calc.setPmt(acc.periodicPayment().toDouble()); MyMoneyMoney interest(calc.interestDue()), amortization; interest = interest.abs(); // make sure it's positive for now amortization = acc.periodicPayment() - interest; if(acc.accountType() == MyMoneyAccount::AssetLoan) { interest = -interest; amortization = -amortization; } amortizationSplit.setShares(amortization); interestSplit.setShares(interest); // FIXME: for now we only assume loans to be in the currency of the transaction amortizationSplit.setValue(amortization); interestSplit.setValue(interest); transaction.modifySplit(amortizationSplit); transaction.modifySplit(interestSplit); } } }
void KMyMoneyBriefSchedule::loadSchedule() { try { if (m_index < m_scheduleList.count()) { MyMoneySchedule sched = m_scheduleList[m_index]; m_indexLabel->setText(i18n("%1 of %2") .arg(QString::number(m_index+1)) .arg(QString::number(m_scheduleList.count()))); m_name->setText(sched.name()); m_type->setText(KMyMoneyUtils::scheduleTypeToString(sched.type())); m_account->setText(sched.account().name()); QString text; MyMoneyMoney amount = sched.transaction().splitByAccount(sched.account().id()).value(); amount = amount.abs(); if (sched.willEnd()) { int transactions = sched.paymentDates(m_date, sched.endDate()).count()-1; text = i18n("Payment on %1 for %2 with %3 transactions remaining occuring %4.") .arg(KGlobal::locale()->formatDate(m_date, true)) .arg(amount.formatMoney(sched.account().fraction())) .arg(QString::number(transactions)) .arg(i18n(sched.occurenceToString())); } else { text = i18n("Payment on %1 for %2 occuring %4.") .arg(KGlobal::locale()->formatDate(m_date, true)) .arg(amount.formatMoney(sched.account().fraction())) .arg(i18n(sched.occurenceToString())); } if (m_date < QDate::currentDate()) { if (sched.isOverdue()) { QDate startD = (sched.lastPayment().isValid()) ? sched.lastPayment() : sched.startDate(); if (m_date.isValid()) startD = m_date; int days = startD.daysTo(QDate::currentDate()); int transactions = sched.paymentDates(startD, QDate::currentDate()).count(); text += "<br><font color=red>"; text += i18n("%1 days overdue (%2 occurences).") .arg(QString::number(days)) .arg(QString::number(transactions)); text += "</color>"; } } m_details->setText(text); m_prevButton->setEnabled(true); m_nextButton->setEnabled(true); m_skipButton->setEnabled(sched.occurencePeriod() != MyMoneySchedule::OCCUR_ONCE); if (m_index == 0) m_prevButton->setEnabled(false); if (m_index == (m_scheduleList.count()-1)) m_nextButton->setEnabled(false); } } catch (MyMoneyException *e) { delete e; } }
void MyMoneyStorageXML::writeSchedule(QDomElement& scheduledTx, const MyMoneySchedule& tx) { tx.writeXML(*m_doc, scheduledTx); }