Logo Search packages:      
Sourcecode: qbankmanager version File versions  Download package

checkduplicates.cpp

/***************************************************************************
 $RCSfile: checkduplicates.cpp,v $
                             -------------------
    cvs         : $Id: checkduplicates.cpp,v 1.12 2005/08/25 15:51:24 aquamaniac Exp $
    begin       : Mon Mar 01 2004
    copyright   : (C) 2004 by Martin Preuss
    email       : martin@libchipcard.de

 ***************************************************************************
 *          Please see toplevel file COPYING for license details           *
 ***************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif


#include "checkduplicates.h"
#include "kbanking.h"
#include "handledupe.h"

#include <qdatetime.h>
#include <qdatetimeedit.h>
#include <qmessagebox.h>
#include <qlineedit.h>
#include <qprogressdialog.h>
#include <qapplication.h>
#include <qpushbutton.h>
#include <qdir.h>

#include <gwenhywfar/debug.h>




CheckDuplicates::CheckDuplicates(KBanking *kb,
                                 QWidget* parent,
                                 const char* name,
                                 WFlags fl)
:CheckDuplicatesUI(parent, name, fl)
,_app(kb)
,_aborted(false){

  QObject::connect((QObject*)abortButton, SIGNAL(clicked()),
                   this, SLOT(slotAbortClicked()));

  accountsProgress->setTotalSteps(-1);
  accountsProgress->setProgress(-1);
  transactionsProgress->setTotalSteps(-1);
  transactionsProgress->setProgress(-1);
}



CheckDuplicates::~CheckDuplicates(){
}



bool CheckDuplicates::check() {
  std::list<Account*>::const_iterator it;
  int accnt;
  bool dontAskAgain=false;
  TransactionImporter::DupeCheckResult lastRes=
    TransactionImporter::DupeCheck_Error;

  accountsProgress->setTotalSteps(_app->getAppAccounts().size());
  accountsProgress->setProgress(0);
  accnt=0;
  for (it=_app->getAppAccounts().begin();
       it!=_app->getAppAccounts().end();
       it++) {
    AH_STORAGE *st;
    int year, month, day;
    int rv;
    GWEN_IDLIST *idl;

    st=(*it)->getStorage();
    assert(st);

    idl=AH_Storage_GetAvailableDays(st);
    assert(idl);
    rv=AH_Storage_GetFirstDay(st, idl, &year, &month, &day);
    if (!rv) {
      GWEN_TIME *ct;
      GWEN_TIME *ft;
      int totalDays;

      ct=GWEN_CurrentTime();
      assert(ct);
      ft=GWEN_Time_new(year, month-1, day, 0, 0, 0, 1);
      assert(ft);

      totalDays=(int)((GWEN_Time_Seconds(ct)-GWEN_Time_Seconds(ft))/
                      (60*60*24));
      transactionsProgress->setTotalSteps(totalDays);
      transactionsProgress->setProgress(0);
      GWEN_Time_free(ct);

      while(!rv) {
        GWEN_TYPE_UINT32 id = 0;
        GWEN_DB_NODE *db;
        std::list<RefPointer<Transaction> > tl;
        std::list<RefPointer<Transaction> >::iterator xait;
        GWEN_TIME *ti;

        ti=0;
        DBG_DEBUG(0, "Loading day %04d/%02d/%02d", year, month, day);
  
        qApp->processEvents();
        if (_aborted) {
          DBG_ERROR(0, "User aborted");
          GWEN_IdList_free(idl);
          if (id)
            AH_Storage_AbandonDay(st, id);
          return false;
        }
  
        id=AH_Storage_OpenDay(st, year, month, day, 1);
        if (!id) {
          DBG_ERROR(0, "Error loading day %04d/%02d/%02d",
                    year, month, day);
          GWEN_IdList_free(idl);
          return false;
        }
    
        db=AH_Storage_GetFirstTransaction(st, id);
        if (!db) {
          DBG_WARN(0, "No transactions in day %04d/%02d/%02d",
                   year, month, day);
        }
        while(db) {
          RefPointer<Transaction> t;
  
          t=new Transaction();
          if (!t.ref().fromDb(db)) {
            DBG_ERROR(0, "Bad format of transaction in day %04d/%02d/%02d",
                      year, month, day);
            AH_Storage_AbandonDay(st, id);
            GWEN_IdList_free(idl);
            return false;
          }
          DBG_DEBUG(0, "Got a transaction");
  
          if (tl.empty()) {
            tl.push_back(t);
          }
          else {
            bool handled=false;

            for (xait=tl.begin(); xait!=tl.end(); xait++) {
              if ((*xait).ref().matchFuzzy(t.ref(),
                                           _app->getFuzzyThreshold())) {
                std::list<RefPointer<Transaction> > dummyL;
                TransactionImporter::DupeCheckResult res;

                handled=true;
                dummyL.push_back(t);

                if (dontAskAgain)
                  res=lastRes;
                else
                  res=HandleDupe::askUser(*it, (*xait), t, tl, dummyL,
                                          dontAskAgain, 0);
                lastRes=res;

                switch(res) {
                case TransactionImporter::DupeCheck_Error:
                  DBG_ERROR(0, "Error handling duplicate");
                  AH_Storage_AbandonDay(st, id);
                  return false;
                case TransactionImporter::DupeCheck_DismissNew:
                  break;
                case TransactionImporter::DupeCheck_AddNew:
                  tl.push_back(t);
                  break;
                case TransactionImporter::DupeCheck_RemoveOld:
                  tl.erase(xait);
                  break;
                case TransactionImporter::DupeCheck_ReplaceOld:
                  tl.erase(xait);
                  tl.push_back(t);
                  break;
                default:
                  DBG_ERROR(0, "Unknown return code %d", res);
                  AH_Storage_AbandonDay(st, id);
                  GWEN_IdList_free(idl);
                  return false;
                }
                break;
              } // if matchFuzzy
            } // for
            if (!handled)
              tl.push_back(t);
          }
  
          db=AH_Storage_GetNextTransaction(st, id);
        } // for transaction
  
        // rebuild databas for this day
        if (AH_Storage_ClearDay(st, id)) {
          DBG_ERROR(0, "Could not clear day %04d/%02d/%02d", year, month, day);
          AH_Storage_AbandonDay(st, id);
          GWEN_IdList_free(idl);
          return false;
        }
        // add all transactions from new list
        for (xait=tl.begin(); xait!=tl.end(); xait++) {
          GWEN_DB_NODE *dbT;
  
          dbT=GWEN_DB_Group_new("transaction");
          if (!(*xait).ref().toDb(dbT)) {
            DBG_ERROR(0, "Could not store transaction to DB");
            AH_Storage_AbandonDay(st, id);
            GWEN_IdList_free(idl);
            return false;
          }
          if (AH_Storage_AddTransaction(st, id, dbT)) {
            DBG_ERROR(0, "Could not add transaction to storage");
            AH_Storage_AbandonDay(st, id);
            GWEN_DB_Group_free(dbT);
            GWEN_IdList_free(idl);
            return false;
          }
          GWEN_DB_Group_free(dbT);
        } // for
  
        if (AH_Storage_CloseDay(st, id)) {
          DBG_ERROR(0, "Error closing day %04d/%02d/%02d",
                    year, month, day);
          GWEN_IdList_free(idl);
          return false;
        }

        ti=GWEN_Time_new(year, month-1, day, 0, 0, 0, 1);
        transactionsProgress->setProgress((int)((GWEN_Time_Seconds(ti)-
                                                 GWEN_Time_Seconds(ft)
                                                )/
                                                (60*60*24)));
        GWEN_Time_free(ti);

        rv=AH_Storage_GetNextDay(st, idl, &year, &month, &day);
      } /* while !rv */
      GWEN_Time_free(ft);
    } /* if first day */
    GWEN_IdList_free(idl);

    accnt++;
    accountsProgress->setProgress(accnt);
  } // for account

  accountsProgress->setTotalSteps(1);
  accountsProgress->setProgress(1);
  transactionsProgress->setTotalSteps(1);
  transactionsProgress->setProgress(1);

  abortButton->setEnabled(false);
  return true;
}



void CheckDuplicates::slotAbortClicked(){
  _aborted=true;
  abortButton->setEnabled(false);
}



bool CheckDuplicates::adjustDates() {
  std::list<Account*>::const_iterator it;
  int accnt;

  setCaption(tr("Updating Transaction Database"));
  accountsProgress->setTotalSteps(_app->getAppAccounts().size());
  accountsProgress->setProgress(0);
  accnt=0;
  for (it=_app->getAppAccounts().begin();
       it!=_app->getAppAccounts().end();
       it++) {
    AH_STORAGE *st;
    int year, month, day;
    int rv;
    GWEN_IDLIST *idl;
    std::list<RefPointer<Transaction> > tl;
    std::list<RefPointer<Transaction> >::iterator xait;

    // reset last transaction date
    (*it)->setLastTransactionDate(0);
    st=(*it)->getStorage();
    assert(st);

    idl=AH_Storage_GetAvailableDays(st);
    assert(idl);
    rv=AH_Storage_GetFirstDay(st, idl, &year, &month, &day);
    if (!rv) {
      GWEN_TIME *ct;
      GWEN_TIME *ft;
      int totalDays;

      ct=GWEN_CurrentTime();
      assert(ct);
      ft=GWEN_Time_new(year, month-1, day, 12, 0, 0, 1);
      assert(ft);

      totalDays=(int)((GWEN_Time_Seconds(ct)-GWEN_Time_Seconds(ft))/
                      (60*60*24));
      transactionsProgress->setTotalSteps(totalDays);
      transactionsProgress->setProgress(0);
      GWEN_Time_free(ct);

      while(!rv) {
        GWEN_TYPE_UINT32 id = 0;
        GWEN_DB_NODE *db;
        GWEN_TIME *ti;

        ti=0;
        DBG_DEBUG(0, "Loading day %04d/%02d/%02d", year, month, day);
  
        qApp->processEvents();
        if (_aborted) {
          DBG_ERROR(0, "User aborted");
          GWEN_IdList_free(idl);
          if (id)
            AH_Storage_AbandonDay(st, id);
          return false;
        }
  
        id=AH_Storage_OpenDay(st, year, month, day, 0);
        if (!id) {
          DBG_ERROR(0, "Error loading day %04d/%02d/%02d",
                    year, month, day);
          GWEN_IdList_free(idl);
          return false;
        }
    
        db=AH_Storage_GetFirstTransaction(st, id);
        if (!db) {
          DBG_WARN(0, "No transactions in day %04d/%02d/%02d",
                   year, month, day);
        }
        while(db) {
          RefPointer<Transaction> t;
          GWEN_TIME *ti;
  
          t=new Transaction();
          if (!t.ref().fromDb(db)) {
            DBG_ERROR(0, "Bad format of transaction in day %04d/%02d/%02d",
                      year, month, day);
            AH_Storage_AbandonDay(st, id);
            GWEN_IdList_free(idl);
            return false;
          }

          // do something with the transaction
          ti=App::adjustedDate(t.ref().getDate());
          t.ref().setDate(ti);
          GWEN_Time_free(ti);

          ti=App::adjustedDate(t.ref().getValutaDate());
          t.ref().setValutaDate(ti);
          GWEN_Time_free(ti);

          tl.push_back(t);

          db=AH_Storage_GetNextTransaction(st, id);
        } // for transaction
  
        if (AH_Storage_CloseDay(st, id)) {
          DBG_ERROR(0, "Error closing day %04d/%02d/%02d",
                    year, month, day);
          GWEN_IdList_free(idl);
          return false;
        }

        ti=GWEN_Time_new(year, month-1, day, 0, 0, 0, 1);
        transactionsProgress->setProgress((int)((GWEN_Time_Seconds(ti)-
                                                 GWEN_Time_Seconds(ft)
                                                )/
                                                (60*60*24)));
        GWEN_Time_free(ti);

        rv=AH_Storage_GetNextDay(st, idl, &year, &month, &day);
      } /* while !rv */
      GWEN_Time_free(ft);
    } /* if first day */
    GWEN_IdList_free(idl);


    if (1) {
      const GWEN_TIME *lastDate=0;
      GWEN_TYPE_UINT32 id=0;
      AH_STORAGE *nst;
      QString qs;
      std::string s;

      qs=QString::fromUtf8(AH_Storage_GetPath(st))+
        "-"+
        QString::number(
#ifdef OS_WIN32
                  rand()
#else
                  random()
#endif // OS_WIN32
                  );
      s=KBanking::QStringToUtf8String(qs);
      DBG_ERROR(0, "Creating temporary storage \"%s\"",
                s.c_str());

      nst=AH_Storage_new(s.c_str());

      for (xait=tl.begin(); xait!=tl.end(); xait++) {
        GWEN_DB_NODE *dbT;
        const GWEN_TIME *currentDate=0;

        currentDate=(*xait).ref().getDate();
        if (!currentDate)
          currentDate=(*xait).ref().getValutaDate();
        assert(currentDate);

        // ensure day data
        if (lastDate!=currentDate) {
          if (id) {
            if (AH_Storage_CloseDay(nst, id)) {
              DBG_ERROR(0, "Could not close day");
              AH_Storage_free(nst);
              return false;
            }
          }
          GWEN_Time_GetBrokenDownDate(currentDate,
                                      &day, &month, &year);
          id=AH_Storage_OpenDay(nst, year, month+1, day, 0);
          if (!id) {
            DBG_ERROR(0, "Could not create day %04d/%02d/%02d",
                      year, month+1, day);
            AH_Storage_free(nst);
            return false;
          }
        }

        dbT=GWEN_DB_Group_new("transaction");
        if (!(*xait).ref().toDb(dbT)) {
          DBG_ERROR(0, "Could not store transaction to DB");
          GWEN_DB_Group_free(dbT);
          AH_Storage_AbandonDay(st, id);
          return false;
        }
        if (AH_Storage_AddTransaction(nst, id, dbT)) {
          DBG_ERROR(0, "Could not add transaction to storage");
          AH_Storage_AbandonDay(nst, id);
          GWEN_DB_Group_free(dbT);
          return false;
        }
        GWEN_DB_Group_free(dbT);
      } // for each transaction
      if (id) {
        if (AH_Storage_CloseDay(nst, id)) {
          DBG_ERROR(0, "Could not close day");
          AH_Storage_AbandonDay(nst, id);
          // TODO
        }
      } // if day still open

      // rename current storage to new backup and new storage to current one
      if (!tl.empty()) {
        if (!QDir::root()
            .rename(QString::fromUtf8(AH_Storage_GetPath(st)),
                    QString(QString::fromUtf8(AH_Storage_GetPath(st))+
                            ".bak"))) {
          DBG_ERROR(0, "Could not rename \"%s\" to \"%s\"",
                    AH_Storage_GetPath(st),
                    QString(QString::fromUtf8(AH_Storage_GetPath(st))+
                            ".bak").latin1());
        }
        else {
          if (!QDir::root()
              .rename(qs, QString::fromUtf8(AH_Storage_GetPath(st)))){
            DBG_ERROR(0, "Could not rename new folder (%s)", s.c_str());
          }
        }
      }
    } // if 1

    accnt++;
    accountsProgress->setProgress(accnt);
  } // for account

  accountsProgress->setTotalSteps(1);
  accountsProgress->setProgress(1);
  transactionsProgress->setTotalSteps(1);
  transactionsProgress->setProgress(1);

  abortButton->setEnabled(false);

  QMessageBox::information(0,
                           tr("Transaction Database Updated"),
                           tr("<qt>"
                              "<p>"
                              "Your transaction database has been updated to "
                              "the new format."
                              "</p>"
                              "<p>"
                              "Your application data folder still contains the "
                              "old database with the extension <i>.bak</i>."
                              "</p>"
                              "<p>"
                              "You can safely remove them after exiting "
                              "<b>QBankManager</b>"
                              "</p>"
                              "</qt>"),
                           tr("Dismiss"), 0, 0, 0);

  return true;
}



bool CheckDuplicates::gatherInfoFromPurpose() {
  std::list<Account*>::const_iterator it;
  int accnt;

  setCaption(tr("Updating Transaction Database"));
  accountsProgress->setTotalSteps(_app->getAppAccounts().size());
  accountsProgress->setProgress(0);
  accnt=0;
  for (it=_app->getAppAccounts().begin();
       it!=_app->getAppAccounts().end();
       it++) {
    AH_STORAGE *st;
    int year, month, day;
    int rv;
    GWEN_IDLIST *idl;
    std::list<RefPointer<Transaction> > tl;
    std::list<RefPointer<Transaction> >::iterator xait;

    st=(*it)->getStorage();
    assert(st);

    idl=AH_Storage_GetAvailableDays(st);
    assert(idl);
    rv=AH_Storage_GetFirstDay(st, idl, &year, &month, &day);
    if (!rv) {
      GWEN_TIME *ct;
      GWEN_TIME *ft;
      int totalDays;

      ct=GWEN_CurrentTime();
      assert(ct);
      ft=GWEN_Time_new(year, month-1, day, 12, 0, 0, 1);
      assert(ft);

      totalDays=(int)((GWEN_Time_Seconds(ct)-GWEN_Time_Seconds(ft))/
                      (60*60*24));
      transactionsProgress->setTotalSteps(totalDays);
      transactionsProgress->setProgress(0);
      GWEN_Time_free(ct);

      while(!rv) {
        GWEN_TYPE_UINT32 id = 0;
        GWEN_DB_NODE *db;
        GWEN_TIME *ti;

        ti=0;
        DBG_DEBUG(0, "Loading day %04d/%02d/%02d", year, month, day);
  
        qApp->processEvents();
        if (_aborted) {
          DBG_ERROR(0, "User aborted");
          GWEN_IdList_free(idl);
          if (id)
            AH_Storage_AbandonDay(st, id);
          return false;
        }
  
        id=AH_Storage_OpenDay(st, year, month, day, 0);
        if (!id) {
          DBG_ERROR(0, "Error loading day %04d/%02d/%02d",
                    year, month, day);
          GWEN_IdList_free(idl);
          return false;
        }
    
        db=AH_Storage_GetFirstTransaction(st, id);
        if (!db) {
          DBG_WARN(0, "No transactions in day %04d/%02d/%02d",
                   year, month, day);
        }
        while(db) {
          RefPointer<Transaction> t;
  
          t=new Transaction();
          if (!t.ref().fromDb(db)) {
            DBG_ERROR(0, "Bad format of transaction in day %04d/%02d/%02d",
                      year, month, day);
            AH_Storage_AbandonDay(st, id);
            GWEN_IdList_free(idl);
            return false;
          }

          // do something with the transaction
          t.ref().gatherInfoFromPurpose();
          tl.push_back(t);

          db=AH_Storage_GetNextTransaction(st, id);
        } // for transaction
  
        if (AH_Storage_CloseDay(st, id)) {
          DBG_ERROR(0, "Error closing day %04d/%02d/%02d",
                    year, month, day);
          GWEN_IdList_free(idl);
          return false;
        }

        ti=GWEN_Time_new(year, month-1, day, 0, 0, 0, 1);
        transactionsProgress->setProgress((int)((GWEN_Time_Seconds(ti)-
                                                 GWEN_Time_Seconds(ft)
                                                )/
                                                (60*60*24)));
        GWEN_Time_free(ti);

        rv=AH_Storage_GetNextDay(st, idl, &year, &month, &day);
      } /* while !rv */
      GWEN_Time_free(ft);
    } /* if first day */
    GWEN_IdList_free(idl);


    if (1) {
      const GWEN_TIME *lastDate=0;
      GWEN_TYPE_UINT32 id=0;
      AH_STORAGE *nst;
      QString qs;
      std::string s;

      qs=QString::fromUtf8(AH_Storage_GetPath(st))+
        "-"+
        QString::number(
#ifdef OS_WIN32
                  rand()
#else
                  random()
#endif // OS_WIN32
                  );
      s=KBanking::QStringToUtf8String(qs);
      DBG_ERROR(0, "Creating temporary storage \"%s\"",
                s.c_str());

      nst=AH_Storage_new(s.c_str());

      for (xait=tl.begin(); xait!=tl.end(); xait++) {
        GWEN_DB_NODE *dbT;
        const GWEN_TIME *currentDate=0;

        currentDate=(*xait).ref().getDate();
        if (!currentDate)
          currentDate=(*xait).ref().getValutaDate();
        assert(currentDate);

        // ensure day data
        if (lastDate!=currentDate) {
          if (id) {
            if (AH_Storage_CloseDay(nst, id)) {
              DBG_ERROR(0, "Could not close day");
              AH_Storage_free(nst);
              return false;
            }
          }
          GWEN_Time_GetBrokenDownDate(currentDate,
                                      &day, &month, &year);
          id=AH_Storage_OpenDay(nst, year, month+1, day, 0);
          if (!id) {
            DBG_ERROR(0, "Could not create day %04d/%02d/%02d",
                      year, month+1, day);
            AH_Storage_free(nst);
            return false;
          }
        }

        dbT=GWEN_DB_Group_new("transaction");
        if (!(*xait).ref().toDb(dbT)) {
          DBG_ERROR(0, "Could not store transaction to DB");
          GWEN_DB_Group_free(dbT);
          AH_Storage_AbandonDay(st, id);
          return false;
        }
        if (AH_Storage_AddTransaction(nst, id, dbT)) {
          DBG_ERROR(0, "Could not add transaction to storage");
          AH_Storage_AbandonDay(nst, id);
          GWEN_DB_Group_free(dbT);
          return false;
        }
        GWEN_DB_Group_free(dbT);
      } // for each transaction
      if (id) {
        if (AH_Storage_CloseDay(nst, id)) {
          DBG_ERROR(0, "Could not close day");
          AH_Storage_AbandonDay(nst, id);
          // TODO
        }
      } // if day still open

      // rename current storage to new backup and new storage to current one
      if (!tl.empty()) {
        if (!QDir::root()
            .rename(QString::fromUtf8(AH_Storage_GetPath(st)),
                    QString(QString::fromUtf8(AH_Storage_GetPath(st))+
                            ".bak"))) {
          DBG_ERROR(0, "Could not rename \"%s\" to \"%s\"",
                    AH_Storage_GetPath(st),
                    QString(QString::fromUtf8(AH_Storage_GetPath(st))+
                            ".bak").latin1());
        }
        else {
          if (!QDir::root()
              .rename(qs, QString::fromUtf8(AH_Storage_GetPath(st)))){
            DBG_ERROR(0, "Could not rename new folder (%s)", s.c_str());
          }
        }
      }
    } // if 1

    accnt++;
    accountsProgress->setProgress(accnt);
  } // for account

  accountsProgress->setTotalSteps(1);
  accountsProgress->setProgress(1);
  transactionsProgress->setTotalSteps(1);
  transactionsProgress->setProgress(1);

  abortButton->setEnabled(false);

  QMessageBox::information(0,
                           tr("Transaction Database Updated"),
                           tr("<qt>"
                              "<p>"
                              "Your transaction database has been updated to "
                              "the new format."
                              "</p>"
                              "<p>"
                              "Your application data folder still contains the "
                              "old database with the extension <i>.bak</i>."
                              "</p>"
                              "<p>"
                              "You can safely remove them after exiting "
                              "<b>QBankManager</b>"
                              "</p>"
                              "</qt>"),
                           tr("Dismiss"), 0, 0, 0);

  return true;
}








Generated by  Doxygen 1.6.0   Back to index