Public Member Functions | Static Public Member Functions
RecordList Class Reference

Brief description of class still missing. More...

#include <RecordList.h>

List of all members.

Public Member Functions

void clear ()
QStringList contracts () const
double countValid () const
void match (RecordList &o)
void preprocess (const QString &contract)
void preprocess ()
void print () const
void print (Group::Category c) const
bool read (QString fileName, bool warning, AtomicBoolean &terminate)
 RecordList ()
void removeNull ()
QString report () const
void setMode (Mode m)
bool setSupplierEquivalences (const QString &fileName, bool warning)
 ~RecordList ()

Static Public Member Functions

static bool write (const QString &fileName, const RecordList &r1, const RecordList &r2)

Detailed Description

Brief description of class still missing.

Full description of class still missing


Constructor & Destructor Documentation

Description of constructor still missing

References Geslab, and TRACE.

{
  TRACE;
  _mode=Geslab;
}

Description of destructor still missing

References clear(), and TRACE.

{
  TRACE;
  clear();
}

Member Function Documentation

References TRACE.

Referenced by FileReader::run(), and ~RecordList().

{
  TRACE;
  qDeleteAll(_groups);
  qDeleteAll(*this);
  _groups.clear();
  QList<AccountingRecord *>::clear();
}
QStringList RecordList::contracts ( ) const

References AccountingRecord::contract(), and QGpCoreTools::unique().

{
  QStringList l;
  for(int i=0; i<count(); i++) {
    AccountingRecord * r=(*this)[i];
    l.append(r->contract());
  }
  qSort(l);
  unique(l);
  return l;
}
double RecordList::countValid ( ) const

Return the ratio of valid records compared to the total.

References AccountingRecord::category(), and Group::Valid.

{
  int nValid=0;
  for(QList<AccountingRecord *>::const_iterator it=begin(); it!=end(); it++) {
    AccountingRecord * r=*it;
    if(r->category()==Group::Valid) {
      nValid++;
    }
  }
  return nValid/(double)count();
}

References Group::Ambiguous, AccountingRecord::amount(), AccountingRecord::category(), Group::Cents, Group::CentsAmbiguous, AccountingRecord::compareString(), Group::DistinctAmount, Group::lessThan(), AccountingRecord::lessThanAmount(), Group::None, Group::SameAmount, Group::SameAmountAmbiguous, AccountingRecord::supplier(), and Group::Valid.

{
  setN2();
  o.setN2();
  qSort(begin(), end(), AccountingRecord::lessThanAmount);
  qSort(o.begin(), o.end(), AccountingRecord::lessThanAmount);

  // Check for Valid
  for(int i=0; i<count(); i++) {
    AccountingRecord * r1=(*this)[i];
    QList<AccountingRecord *> candidates2;
    if(r1->category()==Group::None) {
      int jStart=o.indexAfter(0.9*r1->amount());
      int jEnd=o.indexAfter(1.1*r1->amount());
      for(int j=jStart;j<jEnd ; j++) {
        AccountingRecord * r2=o[j];
        if(r2->category()==Group::None &&
           AccountingRecord::compareString(r1->supplier(), r2->supplier()) &&
           fabs(r1->amount()-r2->amount())<0.005) {
           candidates2.append(r2);
        }
      }
      // Check for similar right after r1
      QList<AccountingRecord *> candidates1;
      for(int k=i; k<count(); k++) {
        AccountingRecord * r=(*this)[k];
        if(r->category()==Group::None) {
          if(AccountingRecord::compareString(r1->supplier(), r->supplier()) &&
             fabs(r1->amount()-r->amount())<0.005) {
            candidates1.append(r);
          } else {
            break;
          }
        }
      }
      if(!candidates1.isEmpty() && !candidates2.isEmpty()) {
        groupCandidates(Group::Valid, Group::Ambiguous,
                        candidates1, candidates2);
      }
    }
  }

  // Check for same amounts
  for(int i=0; i<count(); i++) {
    AccountingRecord * r1=(*this)[i];
    QList<AccountingRecord *> candidates2;
    if(r1->category()==Group::None) {
      int jStart=o.indexAfter(0.9*r1->amount());
      int jEnd=o.indexAfter(1.1*r1->amount());
      for(int j=jStart;j<jEnd ; j++) {
        AccountingRecord * r2=o[j];
        if(r2->category()==Group::None &&
           fabs(r1->amount()-r2->amount())<0.005) {
          candidates2.append(r2);
        }
      }
      QList<AccountingRecord *> candidates1;
      for(int k=i; k<count(); k++) {
        AccountingRecord * r=(*this)[k];
        if(r->category()==Group::None) {
          if(fabs(r1->amount()-r->amount())<0.005) {
            candidates1.append(r);
          } else {
            break;
          }
        }
      }
      if(!candidates1.isEmpty() && !candidates2.isEmpty()) {
        groupCandidates(Group::SameAmount, Group::SameAmountAmbiguous,
                        candidates1, candidates2);
      }
    }
  }

  // Check for similar amounts: < 1 euro
  for(int i=0; i<count(); i++) {
    AccountingRecord * r1=(*this)[i];
    QList<AccountingRecord *> candidates2;
    if(r1->category()==Group::None) {
      int jStart=o.indexAfter(0.9*r1->amount());
      int jEnd=o.indexAfter(1.1*r1->amount());
      for(int j=jStart;j<jEnd ; j++) {
        AccountingRecord * r2=o[j];
        if(r2->category()==Group::None &&
           fabs(r1->amount()-r2->amount())<0.1) {
          candidates2.append(r2);
        }
      }
      // Check for similar right after r1
      QList<AccountingRecord *> candidates1;
      for(int k=i; k<count(); k++) {
        AccountingRecord * r=(*this)[k];
        if(r->category()==Group::None) {
          if(fabs(r1->amount()-r->amount())<0.1) {
            candidates1.append(r);
          } else {
            break;
          }
        }
      }
      if(!candidates1.isEmpty() && !candidates2.isEmpty()) {
        groupCandidates(Group::Cents, Group::CentsAmbiguous,
                        candidates1, candidates2);
      }
    }
  }

  // Check for similar amounts: < 10 cents
  for(int i=0; i<count(); i++) {
    AccountingRecord * r1=(*this)[i];
    QList<AccountingRecord *> candidates2;
    if(r1->category()==Group::None) {
      int jStart=o.indexAfter(0.9*r1->amount());
      int jEnd=o.indexAfter(1.1*r1->amount());
      for(int j=jStart;j<jEnd ; j++) {
        AccountingRecord * r2=o[j];
        if(r2->category()==Group::None &&
           fabs(r1->amount()-r2->amount())<0.1) {
          candidates2.append(r2);
        }
      }
      // Check for similar right after r1
      QList<AccountingRecord *> candidates1;
      for(int k=i; k<count(); k++) {
        AccountingRecord * r=(*this)[k];
        if(r->category()==Group::None) {
          if(fabs(r1->amount()-r->amount())<0.1) {
            candidates1.append(r);
          } else {
            break;
          }
        }
      }
      if(!candidates1.isEmpty() && !candidates2.isEmpty()) {
        groupCandidates(Group::Cents, Group::CentsAmbiguous,
                        candidates1, candidates2);
      }
    }
  }

  // Check for same suppliers and distinct amount
  for(int i=0; i<count(); i++) {
    AccountingRecord * r1=(*this)[i];
    QList<AccountingRecord *> candidates2;
    if(r1->category()==Group::None) {
      for(int j=0;j<o.count() ; j++) {
        AccountingRecord * r2=o[j];
        if(r2->category()==Group::None &&
           AccountingRecord::compareString(r1->supplier(), r2->supplier())) {
          candidates2.append(r2);
        }
      }
      // Check for similar after r1 |(not only right after like before)
      QList<AccountingRecord *> candidates1;
      for(int k=i; k<count(); k++) {
        AccountingRecord * r=(*this)[k];
        if(r->category()==Group::None) {
          if(AccountingRecord::compareString(r1->supplier(), r->supplier())) {
            candidates1.append(r);
          }
        }
      }
      if(!candidates1.isEmpty() && !candidates2.isEmpty()) {
        groupCandidates(Group::DistinctAmount, Group::DistinctAmount,
                        candidates1, candidates2);
      }
    }
  }

  // Create groups for remaining records
  for(int i=0; i<count(); i++) {
    AccountingRecord * r=(*this)[i];
    if(r->category()==Group::None) {
      QList<AccountingRecord *> candidates1, candidates2;
      candidates1.append(r);
      groupCandidates(Group::None, Group::None, candidates1, candidates2);
    }
  }
  for(int i=0; i<o.count(); i++) {
    AccountingRecord * r=o[i];
    if(r->category()==Group::None) {
      QList<AccountingRecord *> candidates1, candidates2;
      candidates2.append(r);
      groupCandidates(Group::None, Group::None, candidates1, candidates2);
    }
  }
  qSort(_groups.begin(), _groups.end(), Group::lessThan);
}
void RecordList::preprocess ( const QString &  contract)

References Geslab, removeNull(), Sifac, and Sorgho.

{
  switch(_mode) {
  case Sifac:
    keepContractOnly(contract);
    sumSifac();
    removeNull();
    removeSupplier("divers paie a facon");
    break;
  case Geslab:
    setContract(contract);
    sumGeslab();
    removeNull();
    break;
  case Sorgho:
    keepContractOnly(contract);
    sumSorgho();
    removeNull();
    break;
  }
}
void RecordList::print ( ) const
{
  for(QList<AccountingRecord *>::const_iterator it=begin(); it!=end(); it++) {
    (*it)->print();
  }
}

References AccountingRecord::category(), AccountingRecord::print(), and AccountingRecord::printChildren().

{
  for(QList<AccountingRecord *>::const_iterator it=begin(); it!=end(); it++) {
    AccountingRecord * r=*it;
    if(r->category()==c) {
      r->print();
      r->printChildren();
    }
  }
}
bool RecordList::read ( QString  fileName,
bool  warning,
AtomicBoolean terminate 
)

References fileName, Geslab, MSG_ID, QGpCoreTools::LineParser::setDelimiters(), QGpCoreTools::LineParser::setSkipEmpty(), Sifac, Sorgho, QGpCoreTools::tr(), TRACE, and QGpCoreTools::AtomicBoolean::value().

Referenced by FileReader::run().

{
  static const QString title(tr("Read file to compare"));
  TRACE;
  if(fileName.isEmpty()) {
    if(warning) {
      Message::warning(MSG_ID, title, tr("Empty file name"));
    }
    return false;
  }
  _fileName=fileName;
  QFile f(_fileName);
  if(!f.open(QIODevice::ReadOnly)) {
    if(warning) {
      Message::warning(MSG_ID, title, tr("Cannot open file %1 for reading").arg(_fileName));
    }
    return false;
  }
  QTextStream s(&f);
  s.setCodec("IBM850");
  LineParser lp;
  lp.setDelimiters("\t");
  lp.setSkipEmpty(false);
  int lineNumber=0;
  switch(_mode) {
  case Sifac:
    if(!readHeaderSifac(s, lp, lineNumber)) {
      Message::warning(MSG_ID, title, tr("Cannot find header line in file %1").arg(_fileName));
      return false;
    }
    break;
  case Geslab:
    if(!readHeaderGeslab(s, lp, lineNumber)) {
      s.seek(0);
    }
    break;
  case Sorgho:
    break;
  }
  bool ok;
  switch(_mode) {
  case Sifac:
    ok=readSifac(s, lp, lineNumber, terminate);
    break;
  case Geslab:
    ok=readGeslab(s, lp, lineNumber, terminate);
    break;
  case Sorgho:
    ok=readSorgho(s, lp, lineNumber, terminate);
    break;
  }
  if(!ok || terminate.value()) {
    return false;
  }
  if(isEmpty()) {
    Message::warning(MSG_ID, title, tr("Cannot find header line in file %1").arg(_fileName));
    return false;
  }
  return true;
}

References AccountingRecord::amount(), and QGpCoreTools::endl().

Referenced by preprocess().

{
  int n=count();
  for(int i=0; i<count(); ) {
    AccountingRecord * r=(*this)[i];
    if(fabs(r->amount())<0.005) {
      delete takeAt(i);
    } else {
      i++;
    }
  }
  if(n>count()) {
    App::stream() << QString("Removed %1 null records\n").arg(n-count()) << endl;
  }
}
QString RecordList::report ( ) const

References Group::Ambiguous, AccountingRecord::category(), Group::Cents, Group::CentsAmbiguous, Group::DistinctAmount, Group::None, Group::SameAmount, Group::SameAmountAmbiguous, QGpCoreTools::tr(), and Group::Valid.

{
  int nValid=0, nAmbiguous=0, nSameAmount=0, nSameAmountAmbiguous=0, nCents=0, nCentsAmbiguous=0,
      nDistinctAmount=0, nNone=0;
  for(QList<AccountingRecord *>::const_iterator it=begin(); it!=end(); it++) {
    AccountingRecord * r=*it;
    switch(r->category()) {
    case Group::Valid: nValid++; break;
    case Group::Ambiguous: nAmbiguous++; break;
    case Group::SameAmount: nSameAmount++; break;
    case Group::SameAmountAmbiguous: nSameAmountAmbiguous++; break;
    case Group::Cents: nCents++; break;
    case Group::CentsAmbiguous: nCentsAmbiguous++; break;
    case Group::DistinctAmount: nDistinctAmount++; break;
    case Group::None: nNone++; break;
    }
  }
  return tr("Out of %1 records\n"
            "%2 records are valid\n"
            "%3 records are ambiguous\n"
            "%4 records have the same amount\n"
            "%5 records have same the amount with ambiguity\n"
            "%6 records differ only by less than 10 cents\n"
            "%7 records differ only by less than 10 cents with ambiguity\n"
            "%8 records have distinct amount\n"
            "%9 records have no match\n\n")
                   .arg(count())
                   .arg(nValid)
                   .arg(nAmbiguous)
                   .arg(nSameAmount)
                   .arg(nSameAmountAmbiguous)
                   .arg(nCents)
                   .arg(nCentsAmbiguous)
                   .arg(nDistinctAmount)
                   .arg(nNone);
}
void RecordList::setMode ( Mode  m) [inline]

Referenced by FileReader::run().

{_mode=m;}
bool RecordList::setSupplierEquivalences ( const QString &  fileName,
bool  warning 
)

References MSG_ID, QGpCoreTools::LineParser::setDelimiters(), QGpCoreTools::LineParser::setSkipEmpty(), QGpCoreTools::LineParser::setString(), QGpCoreTools::LineParser::toString(), QGpCoreTools::tr(), and TRACE.

Referenced by FileReader::run().

{
  TRACE;
  if(fileName.isEmpty()) {
    if(warning) {
      Message::warning(MSG_ID, tr("Supplier equivalences"), tr("Empty file name"));
    }
    return false;
  }
  QFile f(fileName);
  if(!f.open(QIODevice::ReadOnly)) {
    if(warning) {
      Message::warning(MSG_ID, tr("Supplier equivalences"), tr("Cannot open file %1 for reading").arg(fileName));
    }
    return false;
  }
  QTextStream s(&f);
  s.setCodec("IBM850");
  LineParser lp;
  lp.setDelimiters("\t");
  lp.setSkipEmpty(false);
  int lineNumber=0;
  bool ok=true;
  _supplierEquivalence.clear();
  while(!s.atEnd()) {
    lineNumber++;
    lp.setString(s.readLine());
    QString key=lp.toString(0, ok);
    QString value=lp.toString(1, ok);
    if(!ok) {
      return false;
    }
    _supplierEquivalence.insert(key, value);
  }
  return true;
}
bool RecordList::write ( const QString &  fileName,
const RecordList r1,
const RecordList r2 
) [static]

References AccountingRecord::header(), MSG_ID, AccountingRecord::skip(), and QGpCoreTools::tr().

{
  QFile f(fileName);
  if(!f.open(QIODevice::WriteOnly)) {
    Message::warning(MSG_ID, tr("Saving results"), tr("Error writing to file %1").arg(fileName));
    return false;
  }
  QTextStream s(&f);
  s.setCodec("Windows-1252"); // Or incorrectly Windows ANSI, this is the default in Excel under Windows
  s << "\t" << r1._fileName;
  AccountingRecord::skip(s, r1._mode);
  s << "\t" << r2._fileName;
  AccountingRecord::skip(s, r2._mode);
  s  << "\t\t\n";
  s << tr("Contract\t");
  AccountingRecord::header(s, r1._mode);
  s << "\t";
  AccountingRecord::header(s, r2._mode);
  s  << tr("\tCategory\tGroup\n");
  for(int i=0; i<r1._groups.count(); i++) {
    r1._groups.at(i)->write(s, r1._mode, r2._mode, i+1);
  }
  return true;
}

The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines