/************************* * * * * * * * * * * * * *************************** Copyright (c) 1999-2005 Ryan Bobko ryan@ostrich-emulators.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************** * * * * * * * * * * * * **************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "upgplugin.h" #include "qhacctable.h" #include "qhacc.h" #include "qhaccutils.h" #include #include #include #include // plugin factory calls extern "C" { QHaccPlugin * create(){ return new UPGPlugin; } void destroy( UPGPlugin * p ){ delete p; } } const UPGInfo UPGPlugin::pinfo; UPGPlugin::UPGPlugin() : LocalFileDBPlugin(){} UPGPlugin::~UPGPlugin(){} const PluginInfo& UPGPlugin::info() const { return pinfo; } bool UPGPlugin::iload( QString& err ){ bool goodload=true; // make sure we're not trying to upgrade an already-upgraded dataset const QString pfile=home+"/"+QC::TABLENAMES[QC::PREFT]; iloadt( *dbs[QC::PREFT], pfile, err ); TableRow trprefver=dbs[QC::PREFT]->getWhere( TableSelect( QC::PPREF, "QHACCVERSION" ) ); int prefver=0; if( !trprefver.isNull() ){ prefver=trprefver.geti( QC::PVALUE ); if( prefver>=QHacc::COMPATV ){ std::ostream * str=0; if( Utils::error( Utils::ERROPER, str ) ) *str<<"\nThis dataset does not require upgrading at this time."<clear(); return LocalFileDBPlugin::iload( err ); } } if( prefver==0 ){ // heuristic: if we already have a splits file, assume we're // running at least version 2.9.2 QFile sp( home+"/"+QC::TABLENAMES[QC::SPLTT] ); if( sp.exists() ) goodload=upgradeFrom292( err ); else goodload=upgradeFrom28( err ); } else{ if( prefver==0x030000 ) goodload=upgradeFrom3( err ); else if( prefver==0x030100 ) goodload=upgradeFrom31( err ); } if( goodload ){ // we need to update the compatible version numbering const TableSelect TS=TableSelect( QC::PPREF, TableCol( "QHACCVERSION" ) ); TableRow row=dbs[QC::PREFT]->getWhere( TS ); if( !row.isNull() ){ dbs[QC::PREFT]->updateWhere( TS, TableUpdate( QC::PVALUE, TableCol( QHacc::COMPATV ) ) ); } else{ TableRow row( 2 ); row.set( QC::PPREF, "QHACCVERSION" ); row.set( QC::PVALUE, QHacc::COMPATV ); dbs[QC::PREFT]->add( row ); } } return goodload; } bool UPGPlugin::upgradeFrom292( QString& err ){ // basically, if you're upgrading from 2.9.2 or later, you just need to // change the datefield formats in the transactions, splits, and jobs // tables, and rename the ledgers file to journals const QString jfile=home+"/ledgers"; QFile f( jfile ); if( f.exists() && !iloadt( *dbs[QC::JRNLT], jfile, err ) ) return false; if( LocalFileDBPlugin::iload( err ) ){ // good load so far, so update the date fields // first: transactions uint rows=dbs[QC::TRANT]->rows(); QHaccTable tbl( QC::TCOLS, QC::TCOLTYPES, 0, rows ); for( uint i=0; iat( i ); row.set( QC::TDATE, Utils::dateFromString( row[QC::TDATE].gets(), "/", QC::AMERICAN ) ); tbl+=row; } dbs[QC::TRANT]->clear(); dbs[QC::TRANT]->load( &tbl ); // next: splits rows=dbs[QC::SPLTT]->rows(); QHaccTable tbl2( QC::SCOLS, QC::SCOLTYPES, 0, rows ); for( uint i=0; iat( i ); row.set( QC::SRECODATE, Utils::dateFromString( row[QC::SRECODATE].gets(), "/", QC::AMERICAN ) ); tbl2+=row; } dbs[QC::SPLTT]->clear(); dbs[QC::SPLTT]->load( &tbl2 ); // lastly: jobs rows=dbs[QC::JOBST]->rows(); QHaccTable tbl3( QC::JCOLS, QC::JCOLTYPES, 0, rows ); for( uint i=0; iat( i ); row.set( QC::JLASTRUN, Utils::dateFromString( row[QC::JLASTRUN].gets(), "/", QC::AMERICAN ) ); tbl3+=row; } dbs[QC::JOBST]->clear(); dbs[QC::JOBST]->load( &tbl3 ); // we're now at 3.0, so do the 3.1 upgrade const TableSelect TS( QC::PPREF, TableCol( "LOCATION" ) ); TableRow loct=dbs[QC::PREFT]->getWhere( TS ); if( !loct.isNull() ){ // the location pref used to have 4 values in it, but now it only has 2 QStringList lister=QStringList::split( " ", loct[QC::PVALUE].gets() ); QString str=lister[2]+" "+lister[3]; dbs[QC::PREFT]->updateWhere( TS, TableUpdate( QC::PPREF, str ) ); } // and now, we're at 3.1, so do the 3.3 upgrade // update splits to match the taxable field from its parent account auto_ptr rslt=engine->getAs( TableGet() ); const uint RR=rslt->rows(); for( uint i=0; iat( i ); const TableCol TC( acct[QC::ATAXED] ); const TableSelect TS( QC::SACCTID, acct[QC::AID] ); dbs[QC::SPLTT]->updateWhere( TS, TableUpdate( QC::STAXABLE, TC ) ); } // update transactions to be non-void dbs[QC::TRANT]->updateWhere( TableSelect(), TableUpdate( QC::TVOID, false ) ); } return upgradeFrom3( err, false ); } bool UPGPlugin::upgradeFrom28( QString& err ){ // old transaction values const int OTID= 0; const int OTNUM= 1; const int OTPAYEE= 2; const int OTMEMO= 3; const int OTSUM= 4; const int OTDATE= 5; const int OTRECO= 6; const int OTACCTID= 7; const int OTSPLITGROUP= 8; const int OTLID= 9; const int OTCOLS= 10; const ColType OTCOLTYPES[]={ CTUINT, CTSTRING, CTSTRING, CTSTRING, CTSTRING, CTDATE, CTUINT, CTUINT, CTUINT, CTUINT }; bool goodload=true; // load the old transaction file QHaccTable oldtrans( OTCOLS, OTCOLTYPES ); oldtrans.setPK( OTID ); const QString fn=home+"/"+QC::TABLENAMES[QC::TRANT]; QFile f1( fn ); if( f1.exists() ) goodload=iloadt( oldtrans, fn, err ); // load the old memorized transaction file QHaccTable oldmem( OTCOLS, OTCOLTYPES ); const QString fn2=home+"/memorized"; QFile f2( fn2 ); if( f2.exists() && !iloadt( oldmem, fn2, err ) ) goodload=false; // now load everything else for( int i=0; i mrslt=oldmem.getWhere( TableSelect( OTID, TableCol( 0 ), TableSelect::NE ), rr ); /* cout<<"old mem table is:"<at( i ).toString()<at( i ); oldmem.updateWhere( TableSelect( OTSPLITGROUP, tr[OTSPLITGROUP] ), TableUpdate( OTSPLITGROUP, TableCol( ++maxsplitid ) ) ); // we need to track which account gets the memorized trans tcs[0]=tr[OTACCTID]; tcs[1]=TableCol( maxsplitid ); tcs[2]=tr[OTSUM]; amems+=TableRow( tcs, AMEMCOLS ); } /* cout<<"now, old mem table is:"<at( i ).toString()<startLoad( otrows ); // probably too many for double-entry dbs[QC::SPLTT]->startLoad( otrows ); maxsplitid=maxtid=0; uint maxnid=0; int ot[]={ OTID, OTNUM, OTPAYEE, OTMEMO, OTDATE, OTLID }; int nt[]={ QC::TID, QC::TNUM, QC::TPAYEE, QC::TMEMO, QC::TDATE, QC::TLID }; const int TS=6; int os[]={ OTSUM, OTRECO, OTACCTID, OTID }; int ns[]={ QC::SSUM, QC::SRECO, QC::SACCTID, QC::STID }; const int SS=4; QHaccTableIndex sgidx( &oldtrans, OTSPLITGROUP, CTUINT ); TableCol lastsg( 0 ); for( uint i=0; iadd( TableRow( ncs, QC::NCOLS ) ); } if( trans[QC::TLID]=="" ) trans.set( QC::TLID, TableCol( 1 ) ); //cout<<"adding trans "<add( trans ); } // lastsg check else oldt.set( OTID, TableCol( maxtid ) ); // every old transaction is a new split Split split( QC::SCOLS ); for( int j=0; jadd( split ); lastsg=oldt[OTSPLITGROUP]; } // oldtrans loop dbs[QC::TRANT]->stopLoad(); dbs[QC::SPLTT]->stopLoad(); // we need to add an account with id=0 // and while we're at it, we may as well remove unused prefs, too Account zero( QC::ACOLS ); zero.set( QC::AID, TableCol( 0 ) ); TableSelect ts( QC::PPREF, TableCol( "DEFAULTACCOUNTCAT" ) ); TableRow row=dbs[QC::PREFT]->getWhere( ts ); if( !row.isNull() ){ zero.set( QC::ACATEGORY, row[QC::PVALUE] ); dbs[QC::PREFT]->deleteWhere( ts ); } ts=TableSelect( QC::PPREF, TableCol( "DEFAULTACCOUNTTAX" ) ); row=dbs[QC::PREFT]->getWhere( ts ); if( !row.isNull() ){ zero.set( QC::ATAXED, row[QC::PVALUE] ); dbs[QC::PREFT]->deleteWhere( ts ); } ts=TableSelect( QC::PPREF, TableCol( "DEFAULTACCOUNTTYPE" ) ); row=dbs[QC::PREFT]->getWhere( ts ); if( !row.isNull() ){ zero.set( QC::ATYPE, row[QC::PVALUE] ); dbs[QC::PREFT]->deleteWhere( ts ); } ts=TableSelect( QC::PPREF, TableCol( "TRANSTYPES" ) ); row=dbs[QC::PREFT]->getWhere( ts ); if( !row.isNull() ){ zero.set( QC::ATRANSNUMS, row[QC::PVALUE] ); dbs[QC::PREFT]->deleteWhere( ts ); } // add the new default account dbs[QC::ACCTT]->add( zero ); // now, let's rename a few preferences... dbs[QC::PREFT]->updateWhere( TableSelect( QC::PPREF, TableCol( "HIDELEDGERS" ) ), TableUpdate( QC::PPREF, TableCol( "HIDEJOURNALS" ) ) ); dbs[QC::PREFT]->updateWhere( TableSelect( QC::PPREF, TableCol( "LEDGERINDEX" ) ), TableUpdate( QC::PPREF, TableCol( "JOURNALINDEX" ) ) ); dbs[QC::PREFT]->updateWhere( TableSelect( QC::PPREF, TableCol( "HEADINGSIZES" ) ), TableUpdate( QC::PPREF, TableCol( "VIEWHEADINGSIZES" ) ) ); } return goodload; } bool UPGPlugin::upgradeFrom3( QString& err, bool loadfiles ){ // we don't really have anything to upgrade, but we do need to // change a couple preferences bool ret=true; if( loadfiles ) ret=LocalFileDBPlugin::iload( err ); if( ret ){ const TableSelect TS( QC::PPREF, TableCol( "LOCATION" ) ); TableRow loct=dbs[QC::PREFT]->getWhere( TS ); if( !loct.isNull() ){ // the location pref used to have 4 values in it, but now it only has 2 QStringList lister=QStringList::split( " ", loct[QC::PVALUE].gets() ); QString str=lister[2]+" "+lister[3]; dbs[QC::PREFT]->updateWhere( TS, TableUpdate( QC::PPREF, str ) ); } } return upgradeFrom31( err, false ); } bool UPGPlugin::upgradeFrom31( QString& err, bool loadfiles ){ bool ret=true; if( loadfiles ) ret=LocalFileDBPlugin::iload( err ); if( ret ){ // update splits to match the taxable field from its parent account auto_ptr rslt=engine->getAs( TableGet() ); const uint RR=rslt->rows(); for( uint i=0; iat( i ); const TableCol TC( acct[QC::ATAXED] ); const TableSelect TS( QC::SACCTID, acct[QC::AID] ); dbs[QC::SPLTT]->updateWhere( TS, TableUpdate( QC::STAXABLE, TC ) ); } // update transactions to be non-void dbs[QC::TRANT]->updateWhere( TableSelect(), TableUpdate( QC::TVOID, false ) ); } return ret; } UPGInfo::UPGInfo(){ description="Upgrade to 3.3"; stubby="UPG"; guisel=false; }