Esempio n. 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");
}
Esempio n. 2
0
void MyMoneyForecast::addFutureTransactions(void)
{
  MyMoneyTransactionFilter filter;
  MyMoneyFile* file = MyMoneyFile::instance();

  // collect and process all transactions that have already been entered but
  // are located in the future.
  filter.setDateFilter(forecastStartDate(), forecastEndDate());
  filter.setReportAllSplits(false);

  QValueList<MyMoneyTransaction> transactions = file->transactionList(filter);
  QValueList<MyMoneyTransaction>::const_iterator it_t = transactions.begin();

  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());
        if(isForecastAccount(acc)) {
          dailyBalances balance;
          balance = m_accountList[acc.id()];
          //if it is income, the balance is stored as negative number
          if(acc.accountType() == MyMoneyAccount::Income) {
            balance[(*it_t).postDate()] += ((*it_s).shares() * MyMoneyMoney(-1, 1));
          } else {
            balance[(*it_t).postDate()] += (*it_s).shares();
          }
          m_accountList[acc.id()] = balance;
        }
      }
    }
  }

#if 0
  QFile trcFile("forecast.csv");
    trcFile.open(IO_WriteOnly);
    QTextStream s(&trcFile);

    {
      s << "Already present transactions\n";
      QMap<QString, dailyBalances>::Iterator it_a;
      QMap<QString, QString>::ConstIterator it_n;
      for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
      MyMoneyAccount acc = file->account(*it_n);
      it_a = m_accountList.find(*it_n);
      s << "\"" << acc.name() << "\",";
      for(int i = 0; i < 90; ++i) {
      s << "\"" << (*it_a)[i].formatMoney("") << "\",";
    }
    s << "\n";
  }
}
#endif

}
Esempio n. 3
0
QString CsvUtil::nameToId(const QString& name, MyMoneyAccount& parent)
{
  //  Adapted from KMyMoneyApp::createAccount(MyMoneyAccount& newAccount, MyMoneyAccount& parentAccount, MyMoneyAccount& brokerageAccount, MyMoneyMoney openingBal)
  //  Needed to find/create category:sub-categories
  MyMoneyFile* file = MyMoneyFile::instance();

  QString id = file->categoryToAccount(name, MyMoneyAccount::UnknownAccountType);
  // if it does not exist, we have to create it
  if (id.isEmpty()) {
    MyMoneyAccount newAccount;
    MyMoneyAccount parentAccount = parent;
    newAccount.setName(name) ;
    int pos;
    // check for ':' in the name and use it as separator for a hierarchy
    while ((pos = newAccount.name().indexOf(MyMoneyFile::AccountSeperator)) != -1) {
      QString part = newAccount.name().left(pos);
      QString remainder = newAccount.name().mid(pos + 1);
      const MyMoneyAccount& existingAccount = file->subAccountByName(parentAccount, part);
      if (existingAccount.id().isEmpty()) {
        newAccount.setName(part);
        newAccount.setAccountType(parentAccount.accountType());
        file->addAccount(newAccount, parentAccount);
        parentAccount = newAccount;
      } else {
        parentAccount = existingAccount;
      }
      newAccount.setParentAccountId(QString());  // make sure, there's no parent
      newAccount.clearId();                       // and no id set for adding
      newAccount.removeAccountIds();              // and no sub-account ids
      newAccount.setName(remainder);
    }//end while
    newAccount.setAccountType(parentAccount.accountType());

    // make sure we have a currency. If none is assigned, we assume base currency
    if (newAccount.currencyId().isEmpty())
      newAccount.setCurrencyId(file->baseCurrency().id());

    file->addAccount(newAccount, parentAccount);
    id = newAccount.id();
  }
  return id;
}
Esempio n. 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());
}
Esempio n. 5
0
void MyMoneyQifWriter::writeCategoryEntry(QTextStream &s, const QString& accountId, const QString& leadIn)
{
  MyMoneyAccount acc = MyMoneyFile::instance()->account(accountId);
  QString name = acc.name();

  s << "N" << leadIn << name << endl;
  s << (MyMoneyAccount::accountGroup(acc.accountType()) == MyMoneyAccount::Expense ? "E" : "I") << endl;
  s << "^" << endl;

  QStringList list = acc.accountList();
  QStringList::Iterator it;
  name += ":";
  for(it = list.begin(); it != list.end(); ++it) {
    writeCategoryEntry(s, *it, name);
  }
}
Esempio n. 6
0
void CsvUtil::scanCategories(QString& id, const MyMoneyAccount& invAcc, const MyMoneyAccount& parentAccount, const QString& defaultName)
{
  if (!m_scannedCategories) {
    previouslyUsedCategories(invAcc.id(), m_feeId, m_interestId);
    m_scannedCategories = true;
  }

  if (id.isEmpty()) {
    MyMoneyFile* file = MyMoneyFile::instance();
    MyMoneyAccount acc = file->accountByName(defaultName);
    // if it does not exist, we have to create it
    if (acc.id().isEmpty()) {
      MyMoneyAccount parent = parentAccount;
      acc.setName(defaultName);
      acc.setAccountType(parent.accountType());
      acc.setCurrencyId(parent.currencyId());
      file->addAccount(acc, parent);
    }
    id = acc.id();
  }
}
Esempio n. 7
0
void KForecastView::updateBudget(QTreeWidgetItem *item)
{
  MyMoneySecurity currency;
  MyMoneyMoney tAmountMM;

  MyMoneyForecast forecast = item->data(0, ForecastRole).value<MyMoneyForecast>();

  MyMoneyFile* file = MyMoneyFile::instance();
  int it_c = 1; // iterator for the columns of the listview
  QDate forecastDate = forecast.forecastStartDate();

  MyMoneyAccount account = item->data(0, AccountRole).value<MyMoneyAccount>();

  if (account.isInvest()) {
    MyMoneySecurity underSecurity = file->security(account.currencyId());
    currency = file->security(underSecurity.tradingCurrency());
  } else {
    currency = file->security(account.currencyId());
  }

  //iterate columns
  for (; forecastDate <= forecast.forecastEndDate(); forecastDate = forecastDate.addMonths(1), ++it_c) {
    MyMoneyMoney amountMM;
    amountMM = forecast.forecastBalance(account, forecastDate);
    if (account.accountType() == MyMoneyAccount::Expense)
      amountMM = -amountMM;

    tAmountMM += amountMM;
    setAmount(item, it_c, amountMM);
    setValue(item, it_c, amountMM, forecastDate);
    showAmount(item, it_c, amountMM, currency);
  }

  //set total column
  setAmount(item, it_c, tAmountMM);
  setValue(item, it_c, tAmountMM, forecast.forecastEndDate());
  showAmount(item, it_c, tAmountMM, currency);
}
Esempio n. 8
0
void MyMoneyAccountTest::testSetFunctions()
{
  MyMoneyAccount a;

  QDate today(QDate::currentDate());
  QVERIFY(a.name().isEmpty());
  QVERIFY(a.lastModified() == QDate());
  QVERIFY(a.description().isEmpty());

  a.setName("Account");
  a.setInstitutionId("Institution1");
  a.setLastModified(today);
  a.setDescription("Desc");
  a.setNumber("123456");
  a.setAccountType(MyMoneyAccount::MoneyMarket);

  QVERIFY(a.name() == "Account");
  QVERIFY(a.institutionId() == "Institution1");
  QVERIFY(a.lastModified() == today);
  QVERIFY(a.description() == "Desc");
  QVERIFY(a.number() == "123456");
  QVERIFY(a.accountType() == MyMoneyAccount::MoneyMarket);
}
Esempio n. 9
0
const MyMoneySplit KMyMoneyUtils::stockSplit(const MyMoneyTransaction& t)
{
  QList<MyMoneySplit>::ConstIterator it_s;
  MyMoneySplit investmentAccountSplit;
  for (it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
    if (!(*it_s).accountId().isEmpty()) {
      MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId());
      if (acc.isInvest()) {
        return *it_s;
      }
      // if we have a reference to an investment account, we remember it here
      if (acc.accountType() == MyMoneyAccount::Investment)
        investmentAccountSplit = *it_s;
    }
  }
  // if we haven't found a stock split, we see if we've seen
  // an investment account on the way. If so, we return it.
  if (!investmentAccountSplit.id().isEmpty())
    return investmentAccountSplit;

  // if none was found, we return an empty split.
  return MyMoneySplit();
}
Esempio n. 10
0
bool MyMoneyTemplate::addAccountStructure(QDomElement& parent, const MyMoneyAccount& acc)
{
  QDomElement account = m_doc.createElement("account");
  parent.appendChild(account);

  if (MyMoneyFile::instance()->isStandardAccount(acc.id()))
    account.setAttribute(QString("name"), QString());
  else
    account.setAttribute(QString("name"), acc.name());
  account.setAttribute(QString("type"), acc.accountType());

  // FIXME: add tax flag stuff

  // any child accounts?
  if (acc.accountList().count() > 0) {
    QList<MyMoneyAccount> list;
    MyMoneyFile::instance()->accountList(list, acc.accountList(), false);
    QList<MyMoneyAccount>::Iterator it;
    for (it = list.begin(); it != list.end(); ++it) {
      addAccountStructure(account, *it);
    }
  }
  return true;
}
Esempio n. 11
0
void MyMoneyForecast::addScheduledTransactions (void)
{
  MyMoneyFile* file = MyMoneyFile::instance();

  // now process all the schedules that may have an impact
  QValueList<MyMoneySchedule> schedule;

  schedule = file->scheduleList("", MyMoneySchedule::TYPE_ANY, MyMoneySchedule::OCCUR_ANY, MyMoneySchedule::STYPE_ANY,
                                QDate(), forecastEndDate());
  if(schedule.count() > 0) {
    QValueList<MyMoneySchedule>::Iterator it;
    do {
      qBubbleSort(schedule);
      it = schedule.begin();
      if(it == schedule.end())
        break;

      if((*it).isFinished()) {
        schedule.erase(it);
        continue;
      }

      QDate date = (*it).nextPayment((*it).lastPayment());
      if(!date.isValid()) {
        schedule.remove(it);
        continue;
      }

      QDate nextDate =
        (*it).adjustedNextPayment((*it).adjustedDate((*it).lastPayment(),
                                                     (*it).weekendOption()));
      if (nextDate > forecastEndDate()) {
        // We're done with this schedule, let's move on to the next
        schedule.remove(it);
        continue;
      }

      // found the next schedule. process it

      MyMoneyAccount acc = (*it).account();

      if(!acc.id().isEmpty()) {
        try {
          if(acc.accountType() != MyMoneyAccount::Investment) {
            MyMoneyTransaction t = (*it).transaction();

            // only process the entry, if it is still active
            if(!(*it).isFinished() && nextDate != QDate()) {
              // make sure we have all 'starting balances' so that the autocalc works
              QValueList<MyMoneySplit>::const_iterator it_s;
              QMap<QString, MyMoneyMoney> balanceMap;

              for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s ) {
                MyMoneyAccount acc = file->account((*it_s).accountId());
                if(isForecastAccount(acc)) {
                  // collect all overdues on the first day
                  QDate forecastDate = nextDate;
                  if(QDate::currentDate() >= nextDate)
                    forecastDate = QDate::currentDate().addDays(1);

                  dailyBalances balance;
                  balance = m_accountList[acc.id()];
                  for(QDate f_day = QDate::currentDate(); f_day < forecastDate; ) {
                    balanceMap[acc.id()] += m_accountList[acc.id()][f_day];
                    f_day = f_day.addDays(1);
                  }
                }
              }

              // take care of the autoCalc stuff
              calculateAutoLoan(*it, t, balanceMap);

              // now add the splits to the balances
              for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s ) {
                MyMoneyAccount acc = file->account((*it_s).accountId());
                if(isForecastAccount(acc)) {
                  dailyBalances balance;
                  balance = m_accountList[acc.id()];
                  //int offset = QDate::currentDate().daysTo(nextDate);
                  //if(offset <= 0) {  // collect all overdues on the first day
                  //  offset = 1;
                  //}
                  // collect all overdues on the first day
                  QDate forecastDate = nextDate;
                  if(QDate::currentDate() >= nextDate)
                    forecastDate = QDate::currentDate().addDays(1);

                  if(acc.accountType() == MyMoneyAccount::Income) {
                    balance[forecastDate] += ((*it_s).shares() * MyMoneyMoney(-1, 1));
                  } else {
                    balance[forecastDate] += (*it_s).shares();
                  }
                  m_accountList[acc.id()] = balance;
                }
              }
            }
          }
          (*it).setLastPayment(date);

        } catch(MyMoneyException* e) {
          kdDebug(2) << __func__ << " Schedule " << (*it).id() << " (" << (*it).name() << "): " << e->what() << endl;

          schedule.remove(it);
          delete e;
        }
      } else {
        // remove schedule from list
        schedule.remove(it);
      }
    }
    while(1);
  }

#if 0
{
  s << "\n\nAdded scheduled transactions\n";
  QMap<QString, dailyBalances>::Iterator it_a;
  QMap<QString, QString>::ConstIterator it_n;
  for(it_n = m_nameIdx.begin(); it_n != m_nameIdx.end(); ++it_n) {
  MyMoneyAccount acc = file->account(*it_n);
  it_a = m_accountList.find(*it_n);
  s << "\"" << acc.name() << "\",";
  for(int i = 0; i < 90; ++i) {
    s << "\"" << (*it_a)[i].formatMoney("") << "\",";
  }
  s << "\n";
}
}
#endif
}
Esempio n. 12
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;
    }
  }
}
Esempio n. 13
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;
        }
      }
    }
  }
}
Esempio n. 14
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);
        }
      }
    }
  }
}
Esempio n. 15
0
void CsvUtil::createAccount(MyMoneyAccount& newAccount, MyMoneyAccount& parentAccount, MyMoneyAccount& brokerageAccount, MyMoneyMoney openingBal)
{
  MyMoneyFile* file = MyMoneyFile::instance();

  // make sure we have a currency. If none is assigned, we assume base currency
  if (newAccount.currencyId().isEmpty())
    newAccount.setCurrencyId(file->baseCurrency().id());

  MyMoneyFileTransaction ft;
  try {
    int pos;
    // check for ':' in the name and use it as separator for a hierarchy
    while ((pos = newAccount.name().indexOf(MyMoneyFile::AccountSeperator)) != -1) {
      QString part = newAccount.name().left(pos);
      QString remainder = newAccount.name().mid(pos + 1);
      const MyMoneyAccount& existingAccount = file->subAccountByName(parentAccount, part);
      if (existingAccount.id().isEmpty()) {
        newAccount.setName(part);

        file->addAccount(newAccount, parentAccount);
        parentAccount = newAccount;
      } else {
        parentAccount = existingAccount;
      }
      newAccount.setParentAccountId(QString());  // make sure, there's no parent
      newAccount.clearId();                       // and no id set for adding
      newAccount.removeAccountIds();              // and no sub-account ids
      newAccount.setName(remainder);
    }

    const MyMoneySecurity& sec = file->security(newAccount.currencyId());
    // Check the opening balance
    if (openingBal.isPositive() && newAccount.accountGroup() == MyMoneyAccount::Liability) {
      QString message = i18n("This account is a liability and if the "
                             "opening balance represents money owed, then it should be negative.  "
                             "Negate the amount?\n\n"
                             "Please click Yes to change the opening balance to %1,\n"
                             "Please click No to leave the amount as %2,\n"
                             "Please click Cancel to abort the account creation."
                             , MyMoneyUtils::formatMoney(-openingBal, newAccount, sec)
                             , MyMoneyUtils::formatMoney(openingBal, newAccount, sec));

      int ans = KMessageBox::questionYesNoCancel(0, message);
      if (ans == KMessageBox::Yes) {
        openingBal = -openingBal;

      } else if (ans == KMessageBox::Cancel)
        return;
    }

    file->addAccount(newAccount, parentAccount);

    if (newAccount.accountType() == MyMoneyAccount::Investment
        && !brokerageAccount.name().isEmpty()) {
      file->addAccount(brokerageAccount, parentAccount);

      // set a link from the investment account to the brokerage account
      file->modifyAccount(newAccount);
      file->createOpeningBalanceTransaction(brokerageAccount, openingBal);

    } else
      file->createOpeningBalanceTransaction(newAccount, openingBal);

    ft.commit();
  } catch (const MyMoneyException &e) {
    KMessageBox::information(0, i18n("Unable to add account: %1", e.what()));
  }
}
Esempio n. 16
0
KNewAccountDlg::KNewAccountDlg(const MyMoneyAccount& account, bool isEditing, bool categoryEditor, QWidget *parent, const char *name, const QString& title)
  : KNewAccountDlgDecl(parent,name,true),
    m_account(account),
    m_bSelectedParentAccount(false),
    m_categoryEditor(categoryEditor),
    m_isEditing(isEditing)
{
  QString columnName = ( (categoryEditor) ? i18n("Categories") : i18n("Accounts") );

  m_qlistviewParentAccounts->setRootIsDecorated(true);
  m_qlistviewParentAccounts->setAllColumnsShowFocus(true);
  m_qlistviewParentAccounts->setSectionHeader(columnName);
  m_qlistviewParentAccounts->setMultiSelection(false);
  m_qlistviewParentAccounts->header()->setResizeEnabled(true);
  m_qlistviewParentAccounts->setColumnWidthMode(0, QListView::Maximum);
  m_qlistviewParentAccounts->setEnabled(false);
  // never show the horizontal scroll bar
  m_qlistviewParentAccounts->setHScrollBarMode(QScrollView::AlwaysOff);

  m_subAccountLabel->setText(i18n("Is a sub account"));

  m_qlistviewParentAccounts->header()->setFont(KMyMoneyGlobalSettings::listHeaderFont());

  accountNameEdit->setText(account.name());
  descriptionEdit->setText(account.description());

  typeCombo->setEnabled(true);
  MyMoneyFile *file = MyMoneyFile::instance();

  // load the price mode combo
  m_priceMode->insertItem(i18n("default price mode", "<default>"), 0);
  m_priceMode->insertItem(i18n("Price per share"), 1);
  m_priceMode->insertItem(i18n("Total for all shares"), 2);

  int priceMode = 0;
  if(m_account.accountType() == MyMoneyAccount::Investment) {
    m_priceMode->setEnabled(true);
    if(!m_account.value("priceMode").isEmpty())
      priceMode = m_account.value("priceMode").toInt();
  }
  m_priceMode->setCurrentItem(priceMode);

  bool haveMinBalance = false;
  bool haveMaxCredit = false;
  if (categoryEditor)
  {
    // get rid of the tabs that are not used for categories
    QWidget* tab = m_tab->page(m_tab->indexOf(m_institutionTab));
    if(tab)
      m_tab->removePage(tab);
    tab = m_tab->page(m_tab->indexOf(m_limitsTab));
    if(tab)
      m_tab->removePage(tab);

    //m_qlistviewParentAccounts->setEnabled(true);
    startDateEdit->setEnabled(false);
    accountNoEdit->setEnabled(false);

    m_institutionBox->hide();
    m_qcheckboxNoVat->hide();

    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Income));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Expense));

    // Hardcoded but acceptable
    switch (account.accountType())
    {
      case MyMoneyAccount::Income:
        typeCombo->setCurrentItem(0);
        break;

      case MyMoneyAccount::Expense:
      default:
        typeCombo->setCurrentItem(1);
        break;
    }
    m_currency->setEnabled(true);
    if (m_isEditing)
    {
      typeCombo->setEnabled(false);
      m_currency->setDisabled(MyMoneyFile::instance()->isReferenced(m_account));
    }
    m_qcheckboxPreferred->hide();

    m_qcheckboxTax->setChecked(account.value("Tax") == "Yes");
    loadVatAccounts();
  }
  else
  {
    // get rid of the tabs that are not used for accounts
    QWidget* taxtab = m_tab->page(m_tab->indexOf(m_taxTab));
    if (taxtab) {
      if(m_account.isAssetLiability()) {
        m_vatCategory->setText(i18n( "VAT account"));
        m_vatAssignmentFrame->hide();
        m_qcheckboxTax->setChecked(account.value("Tax") == "Yes");
      } else {
        m_tab->removePage(taxtab);
      }
    }

    switch(m_account.accountType()) {
      case MyMoneyAccount::Savings:
      case MyMoneyAccount::Cash:
        haveMinBalance = true;
        break;

      case MyMoneyAccount::Checkings:
        haveMinBalance = true;
        haveMaxCredit = true;
        break;

      case MyMoneyAccount::CreditCard:
        haveMaxCredit = true;
        break;

      default:
        // no limit available, so we might get rid of the tab
        QWidget* tab = m_tab->page(m_tab->indexOf(m_limitsTab));
        if(tab)
          m_tab->removePage(tab);
        // don't try to hide the widgets we just wiped
        // in the next step
        haveMaxCredit = haveMinBalance = true;
        break;
    }

    if(!haveMaxCredit) {
      m_maxCreditLabel->setEnabled(false);
      m_maxCreditLabel->hide();
      m_maxCreditEarlyEdit->hide();
      m_maxCreditAbsoluteEdit->hide();
    }
    if(!haveMinBalance) {
      m_minBalanceLabel->setEnabled(false);
      m_minBalanceLabel->hide();
      m_minBalanceEarlyEdit->hide();
      m_minBalanceAbsoluteEdit->hide();
    }

    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Checkings));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Savings));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Cash));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::CreditCard));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Loan));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Investment));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Asset));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Liability));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Stock));
/*
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::CertificateDep));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::MoneyMarket));
    typeCombo->insertItem(KMyMoneyUtils::accountTypeToString(MyMoneyAccount::Currency));
*/

    // Hardcoded but acceptable
    switch (account.accountType())
    {
      default:
      case MyMoneyAccount::Checkings:
        typeCombo->setCurrentItem(0);
        break;
      case MyMoneyAccount::Savings:
        typeCombo->setCurrentItem(1);
        break;
      case MyMoneyAccount::Cash:
        typeCombo->setCurrentItem(2);
        break;
      case MyMoneyAccount::CreditCard:
        typeCombo->setCurrentItem(3);
        break;
      case MyMoneyAccount::Loan:
        typeCombo->setCurrentItem(4);
        break;
      case MyMoneyAccount::Investment:
        typeCombo->setCurrentItem(5);
        break;
      case MyMoneyAccount::Asset:
        typeCombo->setCurrentItem(6);
        break;
      case MyMoneyAccount::Liability:
        typeCombo->setCurrentItem(7);
        break;
      case MyMoneyAccount::Stock:
        m_institutionBox->hide();
        typeCombo->setCurrentItem(8);
        break;
/*
      case MyMoneyAccount::CertificateDep:
        typeCombo->setCurrentItem(5);
        break;
      case MyMoneyAccount::MoneyMarket:
        typeCombo->setCurrentItem(7);
        break;
      case MyMoneyAccount::Currency:
        typeCombo->setCurrentItem(8);
        break;
*/
    }

    if(!m_account.openingDate().isValid())
      m_account.setOpeningDate(QDate::currentDate());

    startDateEdit->setDate(m_account.openingDate());
    accountNoEdit->setText(account.number());
    m_qcheckboxPreferred->setChecked(account.value("PreferredAccount") == "Yes");
    m_qcheckboxNoVat->setChecked(account.value("NoVat") == "Yes");
    loadKVP("iban", ibanEdit);
    loadKVP("minBalanceAbsolute", m_minBalanceAbsoluteEdit);
    loadKVP("minBalanceEarly", m_minBalanceEarlyEdit);
    loadKVP("maxCreditAbsolute", m_maxCreditAbsoluteEdit);
    loadKVP("maxCreditEarly", m_maxCreditEarlyEdit);
    // reverse the sign for display purposes
    if(!m_maxCreditAbsoluteEdit->lineedit()->text().isEmpty())
      m_maxCreditAbsoluteEdit->setValue(m_maxCreditAbsoluteEdit->value()*MyMoneyMoney(-1,1));
    if(!m_maxCreditEarlyEdit->lineedit()->text().isEmpty())
      m_maxCreditEarlyEdit->setValue(m_maxCreditEarlyEdit->value()*MyMoneyMoney(-1,1));
    loadKVP("lastNumberUsed", m_lastCheckNumberUsed);


    // we do not allow to change the account type once an account
    // was created. Same applies to currency if it is referenced.
    if (m_isEditing)
    {
      typeCombo->setEnabled(false);
      m_currency->setDisabled(MyMoneyFile::instance()->isReferenced(m_account));
    }
    if(m_account.isInvest()) {
      typeCombo->setEnabled(false);
      m_qcheckboxPreferred->hide();
      m_currencyText->hide();
      m_currency->hide();
    } else {
      // use the old field and override a possible new value
      if(!MyMoneyMoney(account.value("minimumBalance")).isZero()) {
        m_minBalanceAbsoluteEdit->setValue(MyMoneyMoney(account.value("minimumBalance")));
      }
    }

//    m_qcheckboxTax->hide(); TODO should only be visible for VAT category/account
  }

  m_currency->setSecurity(file->currency(account.currencyId()));

  // Load the institutions
  // then the accounts
  QString institutionName;

  try
  {
    if (m_isEditing && !account.institutionId().isEmpty())
      institutionName = file->institution(account.institutionId()).name();
    else
      institutionName = QString();
  }
  catch (MyMoneyException *e)
  {
    qDebug("exception in init for account dialog: %s", e->what().latin1());
    delete e;
  }

  initParentWidget(account.parentAccountId(), account.id());
  if(m_account.isInvest())
    m_qlistviewParentAccounts->setEnabled(false);

  if (!categoryEditor)
    slotLoadInstitutions(institutionName);

  accountNameEdit->setFocus();

  if (title)
    setCaption(title);

  // load button icons
  KIconLoader* il = KGlobal::iconLoader();
  cancelButton->setGuiItem(KStdGuiItem::cancel());
  createButton->setGuiItem(KStdGuiItem::ok());

  connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
  connect(createButton, SIGNAL(clicked()), this, SLOT(okClicked()));
  connect(m_qlistviewParentAccounts, SIGNAL(selectionChanged(QListViewItem*)),
    this, SLOT(slotSelectionChanged(QListViewItem*)));
  connect(m_qbuttonNew, SIGNAL(clicked()), this, SLOT(slotNewClicked()));
  connect(typeCombo, SIGNAL(activated(const QString&)),
    this, SLOT(slotAccountTypeChanged(const QString&)));

  connect(accountNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckFinished()));

  connect(m_vatCategory, SIGNAL(toggled(bool)), this, SLOT(slotVatChanged(bool)));
  connect(m_vatAssignment, SIGNAL(toggled(bool)), this, SLOT(slotVatAssignmentChanged(bool)));
  connect(m_vatCategory, SIGNAL(toggled(bool)), this, SLOT(slotCheckFinished()));
  connect(m_vatAssignment, SIGNAL(toggled(bool)), this, SLOT(slotCheckFinished()));
  connect(m_vatRate, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckFinished()));
  connect(m_vatAccount, SIGNAL(stateChanged()), this, SLOT(slotCheckFinished()));

  connect(m_minBalanceEarlyEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMinBalanceAbsoluteEdit(const QString&)));
  connect(m_minBalanceAbsoluteEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMinBalanceEarlyEdit(const QString&)));
  connect(m_maxCreditEarlyEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMaxCreditAbsoluteEdit(const QString&)));
  connect(m_maxCreditAbsoluteEdit, SIGNAL(valueChanged(const QString&)), this, SLOT(slotAdjustMaxCreditEarlyEdit(const QString&)));

  connect(m_qcomboboxInstitutions, SIGNAL(activated(const QString&)), this, SLOT(slotLoadInstitutions(const QString&)));

  m_vatCategory->setChecked(false);
  m_vatAssignment->setChecked(false);

  // make sure our account does not have an id and no parent assigned
  // and certainly no children in case we create a new account
  if(!m_isEditing) {
    m_account.clearId();
    m_account.setParentAccountId(QString());
    QStringList::ConstIterator it;
    while((it = m_account.accountList().begin()) != m_account.accountList().end())
      m_account.removeAccountId(*it);

    if(m_parentItem == 0) {
      // force loading of initial parent
      m_account.setAccountType(MyMoneyAccount::UnknownAccountType);
      MyMoneyAccount::_accountTypeE type = account.accountType();
      if(type == MyMoneyAccount::UnknownAccountType)
        type = MyMoneyAccount::Checkings;
      slotAccountTypeChanged(KMyMoneyUtils::accountTypeToString(type));
    }
  } else {
    if(!m_account.value("VatRate").isEmpty()) {
      m_vatCategory->setChecked(true);
      m_vatRate->setValue(MyMoneyMoney(m_account.value("VatRate"))*MyMoneyMoney(100,1));
    } else {
      if(!m_account.value("VatAccount").isEmpty()) {
        QString accId = m_account.value("VatAccount").latin1();
        try {
          // make sure account exists
          MyMoneyFile::instance()->account(accId);
          m_vatAssignment->setChecked(true);
          m_vatAccount->setSelected(accId);
          m_grossAmount->setChecked(true);
          if(m_account.value("VatAmount") == "Net")
            m_netAmount->setChecked(true);
        } catch(MyMoneyException *e) {
          delete e;
        }
      }
    }
  }
  slotVatChanged(m_vatCategory->isChecked());
  slotVatAssignmentChanged(m_vatAssignment->isChecked());
  slotCheckFinished();

  kMandatoryFieldGroup* requiredFields = new kMandatoryFieldGroup (this);
  requiredFields->setOkButton(createButton); // button to be enabled when all fields present
  requiredFields->add(accountNameEdit);

  // using a timeout is the only way, I got the 'ensureItemVisible'
  // working when creating the dialog. I assume, this
  // has something to do with the delayed update of the display somehow.
  QTimer::singleShot(50, this, SLOT(timerDone()));
}