void MyMoneyAccountTest::testAssignmentConstructor() { MyMoneyAccount a; a.setAccountType(MyMoneyAccount::Checkings); a.setName("Account"); a.setInstitutionId("Inst1"); a.setDescription("Bla"); a.setNumber("assigned Number"); a.setValue("Key", "Value"); a.addAccountId("ChildAccount"); MyMoneyAccount b; b.setLastModified(QDate::currentDate()); b = a; QVERIFY(b.name() == "Account"); QVERIFY(b.institutionId() == "Inst1"); QVERIFY(b.accountType() == MyMoneyAccount::Checkings); QVERIFY(b.lastModified() == QDate()); QVERIFY(b.openingDate() == a.openingDate()); QVERIFY(b.description() == "Bla"); QVERIFY(b.number() == "assigned Number"); QVERIFY(b.value("Key") == "Value"); QVERIFY(b.accountList().count() == 1); QVERIFY(b.accountList()[0] == "ChildAccount"); }
MyMoneyMoney MyMoneyForecast::calculateAccountTrend(const MyMoneyAccount& acc, int trendDays) { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyTransactionFilter filter; MyMoneyMoney netIncome; QDate startDate; QDate openingDate = acc.openingDate(); //validate arguments if(trendDays < 1) { throw new MYMONEYEXCEPTION("Illegal arguments when calling calculateAccountTrend. trendDays must be higher than 0"); } //If it is a new account, we don't take into account the first day //because it is usually a weird one and it would mess up the trend if(openingDate.daysTo(QDate::currentDate())<trendDays){ startDate = (acc.openingDate()).addDays(1); } else { startDate = QDate::currentDate().addDays(-trendDays); } //get all transactions for the period filter.setDateFilter(startDate, QDate::currentDate()); if(acc.accountGroup() == MyMoneyAccount::Income || acc.accountGroup() == MyMoneyAccount::Expense) { filter.addCategory(acc.id()); } else { filter.addAccount(acc.id()); } filter.setReportAllSplits(false); QValueList<MyMoneyTransaction> transactions = file->transactionList(filter); QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin(); //add all transactions for that account for(; it_t != transactions.end(); ++it_t ) { const QValueList<MyMoneySplit>& splits = (*it_t).splits(); QValueList<MyMoneySplit>::const_iterator it_s = splits.begin(); for(; it_s != splits.end(); ++it_s ) { if(!(*it_s).shares().isZero()) { if(acc.id()==(*it_s).accountId()) netIncome += (*it_s).value(); } } } //calculate trend of the account in the past period MyMoneyMoney accTrend; //don't take into account the first day of the account if(openingDate.daysTo(QDate::currentDate())<trendDays) { accTrend = netIncome/MyMoneyMoney(openingDate.daysTo(QDate::currentDate())-1,1); } else { accTrend = netIncome/MyMoneyMoney(trendDays,1); } return accTrend; }
void MyMoneyQifWriter::writeAccountEntry(QTextStream &s, const QString& accountId, const QDate& startDate, const QDate& endDate) { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyAccount account; account = file->account(accountId); MyMoneyTransactionFilter filter(accountId); filter.setDateFilter(startDate, endDate); QValueList<MyMoneyTransaction> list = file->transactionList(filter); QString openingBalanceTransactionId; s << "!Type:" << m_qifProfile.profileType() << endl; if(!startDate.isValid() || startDate <= account.openingDate()) { s << "D" << m_qifProfile.date(account.openingDate()) << endl; openingBalanceTransactionId = file->openingBalanceTransaction(account); MyMoneySplit split; if(!openingBalanceTransactionId.isEmpty()) { MyMoneyTransaction openingBalanceTransaction = file->transaction(openingBalanceTransactionId); split = openingBalanceTransaction.splitByAccount(account.id(), true /* match */); } s << "T" << m_qifProfile.value('T', split.value()) << endl; } else { s << "D" << m_qifProfile.date(startDate) << endl; s << "T" << m_qifProfile.value('T', file->balance(accountId, startDate.addDays(-1))) << endl; } s << "CX" << endl; s << "P" << m_qifProfile.openingBalanceText() << endl; s << "L"; if(m_qifProfile.accountDelimiter().length()) s << m_qifProfile.accountDelimiter()[0]; s << account.name(); if(m_qifProfile.accountDelimiter().length() > 1) s << m_qifProfile.accountDelimiter()[1]; s << endl; s << "^" << endl; QValueList<MyMoneyTransaction>::ConstIterator it; signalProgress(0, list.count()); int count = 0; for(it = list.begin(); it != list.end(); ++it) { // don't include the openingBalanceTransaction again if((*it).id() != openingBalanceTransactionId) writeTransactionEntry(s, *it, accountId); signalProgress(++count, 0); } }
void MyMoneyAccountTest::testEmptyConstructor() { MyMoneyAccount a; QVERIFY(a.id().isEmpty()); QVERIFY(a.name().isEmpty()); QVERIFY(a.accountType() == MyMoneyAccount::UnknownAccountType); QVERIFY(a.openingDate() == QDate()); QVERIFY(a.lastModified() == QDate()); QVERIFY(a.lastReconciliationDate() == QDate()); QVERIFY(a.accountList().count() == 0); QVERIFY(a.balance().isZero()); }
void MyMoneyForecast::calculateAccountTrendList() { MyMoneyFile* file = MyMoneyFile::instance(); int auxForecastTerms; int totalWeight = 0; //Calculate account trends QMap<QString, QString>::Iterator it_n; for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) { MyMoneyAccount acc = file->account(*it_n); m_accountTrendList[acc.id()][0] = MyMoneyMoney(0,1); // for today, the trend is 0 auxForecastTerms = forecastCycles(); if(skipOpeningDate()) { QDate openingDate; if(acc.accountType() == MyMoneyAccount::Stock) { MyMoneyAccount parentAccount = file->account(acc.parentAccountId()); openingDate = parentAccount.openingDate(); } else { openingDate = acc.openingDate(); } if(openingDate > historyStartDate() ) { //if acc opened after forecast period auxForecastTerms = 1 + ((openingDate.daysTo(historyEndDate()) + 1)/ accountsCycle()); // set forecastTerms to a lower value, to calculate only based on how long this account was opened } } switch (historyMethod()) { //moving average case 0: { for(int t_day = 1; t_day <= accountsCycle(); t_day++) m_accountTrendList[acc.id()][t_day] = accountMovingAverage(acc, t_day, auxForecastTerms); //moving average break; } //weighted moving average case 1: { //calculate total weight for moving average if(auxForecastTerms == forecastCycles()) { totalWeight = (auxForecastTerms * (auxForecastTerms + 1))/2; //totalWeight is the triangular number of auxForecastTerms } else { //if only taking a few periods, totalWeight is the sum of the weight for most recent periods for(int i = 1, w = forecastCycles(); i <= auxForecastTerms; ++i, --w) totalWeight += w; } for(int t_day = 1; t_day <= accountsCycle(); t_day++) m_accountTrendList[acc.id()][t_day] = accountWeightedMovingAverage(acc, t_day, totalWeight); break; } case 2: { //calculate mean term MyMoneyMoney meanTerms = MyMoneyMoney((auxForecastTerms * (auxForecastTerms + 1))/2, 1) / MyMoneyMoney(auxForecastTerms, 1); for(int t_day = 1; t_day <= accountsCycle(); t_day++) m_accountTrendList[acc.id()][t_day] = accountLinearRegression(acc, t_day, auxForecastTerms, meanTerms); break; } default: break; } } }
void MyMoneyForecast::setStartingBalance(const MyMoneyAccount &acc) { MyMoneyFile* file = MyMoneyFile::instance(); //Get current account balance if ( acc.isInvest() ) { //investments require special treatment //get the security id of that account MyMoneySecurity undersecurity = file->security ( acc.currencyId() ); //only do it if the security is not an actual currency if ( ! undersecurity.isCurrency() ) { //set the default value MyMoneyMoney rate = MyMoneyMoney ( 1, 1 ); //get te MyMoneyPrice price = file->price ( undersecurity.id(), undersecurity.tradingCurrency(), QDate::currentDate() ); if ( price.isValid() ) { rate = price.rate ( undersecurity.tradingCurrency() ); } m_accountList[acc.id()][QDate::currentDate()] = file->balance(acc.id(), QDate::currentDate()) * rate; } } else { m_accountList[acc.id()][QDate::currentDate()] = file->balance(acc.id(), QDate::currentDate()); } //if the method is linear regression, we have to add the opening balance to m_accountListPast if(forecastMethod() == eHistoric && historyMethod() == 2) { //FIXME workaround for stock opening dates QDate openingDate; if(acc.accountType() == MyMoneyAccount::Stock) { MyMoneyAccount parentAccount = file->account(acc.parentAccountId()); openingDate = parentAccount.openingDate(); } else { openingDate = acc.openingDate(); } //add opening balance only if it opened after the history start if(openingDate >= historyStartDate()) { MyMoneyMoney openingBalance; openingBalance = file->balance(acc.id(), openingDate); //calculate running sum for(QDate it_date = openingDate; it_date <= historyEndDate(); it_date = it_date.addDays(1) ) { //investments require special treatment if ( acc.isInvest() ) { //get the security id of that account MyMoneySecurity undersecurity = file->security ( acc.currencyId() ); //only do it if the security is not an actual currency if ( ! undersecurity.isCurrency() ) { //set the default value MyMoneyMoney rate = MyMoneyMoney ( 1, 1 ); //get the rate for that specific date MyMoneyPrice price = file->price ( undersecurity.id(), undersecurity.tradingCurrency(), it_date ); if ( price.isValid() ) { rate = price.rate ( undersecurity.tradingCurrency() ); } m_accountListPast[acc.id()][it_date] += openingBalance * rate; } } else { m_accountListPast[acc.id()][it_date] += openingBalance; } } } } }
void MyMoneyForecast::pastTransactions() { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyTransactionFilter filter; filter.setDateFilter(historyStartDate(), historyEndDate()); filter.setReportAllSplits(false); QValueList<MyMoneyTransaction> transactions = file->transactionList(filter); QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin(); //Check past transactions for(; it_t != transactions.end(); ++it_t ) { const QValueList<MyMoneySplit>& splits = (*it_t).splits(); QValueList<MyMoneySplit>::const_iterator it_s = splits.begin(); for(; it_s != splits.end(); ++it_s ) { if(!(*it_s).shares().isZero()) { MyMoneyAccount acc = file->account((*it_s).accountId()); //workaround for stock accounts which have faulty opening dates QDate openingDate; if(acc.accountType() == MyMoneyAccount::Stock) { MyMoneyAccount parentAccount = file->account(acc.parentAccountId()); openingDate = parentAccount.openingDate(); } else { openingDate = acc.openingDate(); } if(isForecastAccount(acc) //If it is one of the accounts we are checking, add the amount of the transaction && ( (openingDate < (*it_t).postDate() && skipOpeningDate()) || !skipOpeningDate() ) ){ //don't take the opening day of the account to calculate balance dailyBalances balance; //FIXME deal with leap years balance = m_accountListPast[acc.id()]; if(acc.accountType() == MyMoneyAccount::Income) {//if it is income, the balance is stored as negative number balance[(*it_t).postDate()] += ((*it_s).shares() * MyMoneyMoney(-1, 1)); } else { balance[(*it_t).postDate()] += (*it_s).shares(); } // check if this is a new account for us m_accountListPast[acc.id()] = balance; } } } } //purge those accounts with no transactions on the period if(isIncludingUnusedAccounts() == false) purgeForecastAccountsList(m_accountListPast); //calculate running sum QMap<QString, QString>::Iterator it_n; for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) { MyMoneyAccount acc = file->account(*it_n); m_accountListPast[acc.id()][historyStartDate().addDays(-1)] = file->balance(acc.id(), historyStartDate().addDays(-1)); for(QDate it_date = historyStartDate(); it_date <= historyEndDate(); ) { m_accountListPast[acc.id()][it_date] += m_accountListPast[acc.id()][it_date.addDays(-1)]; //Running sum it_date = it_date.addDays(1); } } //adjust value of investments to deep currency for ( it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n ) { MyMoneyAccount acc = file->account ( *it_n ); if ( acc.isInvest() ) { //get the id of the security for that account MyMoneySecurity undersecurity = file->security ( acc.currencyId() ); if ( ! undersecurity.isCurrency() ) //only do it if the security is not an actual currency { MyMoneyMoney rate = MyMoneyMoney ( 1, 1 ); //set the default value MyMoneyPrice price; for ( QDate it_date = historyStartDate().addDays(-1) ; it_date <= historyEndDate();) { //get the price for the tradingCurrency that day price = file->price ( undersecurity.id(), undersecurity.tradingCurrency(), it_date ); if ( price.isValid() ) { rate = price.rate ( undersecurity.tradingCurrency() ); } //value is the amount of shares multiplied by the rate of the deep currency m_accountListPast[acc.id() ][it_date] = m_accountListPast[acc.id() ][it_date] * rate; it_date = it_date.addDays(1); } } } } }