Пример #1
0
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");
}
Пример #2
0
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;
}
Пример #3
0
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);
  }
}
Пример #4
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());
}
Пример #5
0
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;
    }
  }
}
Пример #6
0
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;
        }
      }
    }
  }
}
Пример #7
0
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);
        }
      }
    }
  }
}