#include "movdett.h" //Contiene le definizioni di costanti relative ai nomi dei campi di LF_MOVDETT #include "saldi.h" //Contiene le definizioni di costanti relative ai nomi dei campi di LF_SALDI #include "voci.h" //Contiene le definizioni di costanti relative ai nomi dei cmapi di LF_VOCI #include "relvoci.h" //Contiene le definizioni di costanti relative ai nomi dei cmapi di LF_RELVOCI #include "relana.h" //Contiene le definizioni di costanti relative ai nomi dei cmapi di LF_RELANA #include "caradd.h" //Contiene le definizioni di costanti relative ai nomi dei cmapi di LF_CARADD #include "colldich.h" //Contiene le definizioni di costanti relative ai nomi dei cmapi di LF_COLLDICH #include "ab2100.h" //Definizione della classe principale e di constanti che indicano l'indice nel file di configurazione #include "ab2100a.h" //Campi della maschera #include #include #include //Definizione di fexit TToken_string TAlbero_record ::wrk_string; /* ********************************************************************************************************* */ /* TFile_text_AS400 */ /*********************************************************************************************************** */ //Costruttore di TFile_text_AS400: lo inizializzo a 0 TFile_text_AS400::TFile_text_AS400(const char* file_name, const char* config_name) : TFile_text(file_name, config_name),_idncomp(1),_tipo_bilancio("") { } inline TRicezione& app() { return (TRicezione&) main_app(); } void TFile_text_AS400::cambia_anno(TString& str) { //Trasformo dal formato aa al formato aaaa solo se la data è nel formato aa: //se str > 99 allora significa che la data è già in formato aaaa e quindi non deve eseguire nessun cambio if ((atoi(str)>0) && (atoi(str) < 99)) { if (str > "50") str.insert("19"); else str.insert("20"); } } void TFile_text_AS400::cambia_data(TString &str) { if (atoi(str)>0) { int aa= atoi(str.left(2)); int mm= atoi(str.mid(2,2)); int gg= atoi(str.right(2)); if (aa > 50) aa=aa+1900; else aa=aa+2000; TDate data(gg,mm,aa); str=data.string(); } } //Questa funzione esegue la conversione dell'anno dal formato aa al formato aaaa //void TFile_text_AS400::preformat_field(TRelation& rel,const TFieldref&field,const TRecord_text& rec,TString &str) void TFile_text_AS400::preformat_field(const TFieldref& field, TString &str,TRelation& rel,const TString &tipo_tr) { if (field.file()==LF_MOVDETT) {//Parte riservata ai MOVIMENTI/DETTAGLI if (field.name()==ABMD_ANNO) cambia_anno(str); //formatto l'anno: aa --> aaaa if (field.name()==ABMD_DREG || field.name()==ABMD_DDOC) cambia_data(str); //formatta la data aammgg --> aaaammgg }//Fine MOVIMENTI/DETTAGLI if (field.file()==LF_ABSALDI) {//Parte riservata ai SALDI if (field.name()==ABMD_ANNO) //formatto l'anno: aa ---> aaaa cambia_anno(str); }//Fine parte riservata ai SALDI if (field.file()==LF_VOCI) {//Va cambiato il TIPOVC da S a C, tutti gli altri casi rimangono inalterati if((field.name()==ABVC_TIPOVC) && (str == FLAG_SOTTOD)) str = FLAG_COMPOSTA; } if (field.file()==LF_RELVOCI) { if((field.name()==ABRL_CODCOMP)) {//Lo accorcio di 5 caratteri str.ltrim(5); } } } //Assegno valori temporanei a IDPADRE, IDFIGLIO, IDSUCC, IDPREC void TFile_text_AS400::scrivi_temp_link(TRelation& rel,const TRecord_text& rec) { if ((rec.type() == MOVIMENTO3) || (rec.type() == MOVIMENTO4) || (rec.type() == MOVIMENTO5)) { real r(rec.get(PROGRESSIVO_DETT_MOVDETT));//Eseguo una conversione per un controllo numerico if (r > 0) //E' un PROGRESSIVO DETTAGLIO { TString16 str1,str2; str1 << FLAG_DETT << rec.get(PROGRESSIVO_DETT_MOVDETT).left(5); rel.lfile().put(ABMD_IDPADRE,str1); str2 << rec.get(PROGRESSIVO_DETT_MOVDETT).right(5); rel.lfile().put(ABMD_IDFIGLIO,str2); rel.lfile().put(ABMD_IDSUCC,0); //Assegno il numero di registrazione 0 rel.lfile().put(ABMD_IDPREC,0); //Assegno il numero di riga 0 } else //E' un COGE { TString16 str1,str2; str1 << FLAG_COGE << rec.get(CONTO_COGE_MOVDETT).left(5); rel.lfile().put(ABMD_IDPADRE,str1); str2 << rec.get(CONTO_COGE_MOVDETT).right(5); rel.lfile().put(ABMD_IDFIGLIO,str2); rel.lfile().put(ABMD_IDSUCC,0); //Assegno il numero di registrazione 0 rel.lfile().put(ABMD_IDPREC,0); //Assegno il numero di riga 0 } } else { //E' un movimento: tipo_rec =movi1 o movi2 TString16 str1,str2; //Se è un movimento di progressivo real r(rec.get(PROGRESSIVO_DETT_MOVDETT)); //Eseguo una conversione per un controllo numerico if (r > 0) { str1 << FLAG_MOVIMENTO << rec.get(PROGRESSIVO_DETT_MOVDETT).left(5); str2 << rec.get(PROGRESSIVO_DETT_MOVDETT).right(5); } else //... è un movimento di un saldo o di un coge { real r(rec.get(CONTO_COGE_MOVDETT)); //Eseguo una conversione per un controllo numerico if (r > 0) { str1 << FLAG_MOVIMENTO << rec.get(CONTO_COGE_MOVDETT).left(5); str2 << rec.get(CONTO_COGE_MOVDETT).right(5); } else { //C'è scritto la stessa cosa dell'if, in reltà CONTO_COGE contiene solo zeri //e mi serve per riempire correttamente str1 che deve essere del tipo FCCCCC dove //F è il flag_movimento e C è la prima parte del CONTO_COGE: se non avessi messo //così str1 sarebbe stata del tipo F str1 << FLAG_MOVIMENTO << rec.get(CONTO_COGE_MOVDETT).left(5); str2 << rec.get(CONTO_COGE_MOVDETT).right(5); } } rel.lfile().put(ABMD_IDPADRE,str1); rel.lfile().put(ABMD_IDFIGLIO,str2); rel.lfile().put(ABMD_IDSUCC,rec.get(NUMERO_REG_MOVDETT)); //Assegno il numero di registrazione rel.lfile().put(ABMD_IDPREC,rec.get(NUMERO_RIGA_MOVDETT)); //Assegno il numero di riga } } void TFile_text_AS400::aggiorna_rel_link(TLocalisamfile &relvoc) { if (relvoc.get_long(ABRL_IDCOMP) > 1) { //Ci deve essere un precedente //Recupero la relazione precedente TLocalisamfile temp(LF_RELVOCI); temp.put(ABRL_TIPOCOD,relvoc.get(ABRL_TIPOCOD)); temp.put(ABRL_CODVC,relvoc.get(ABRL_CODVC)); temp.put(ABRL_IDCOMP,relvoc.get_long(ABRL_IDCOMP)-1); if (temp.read() == NOERR) {//Ho recuperato la relazione precedente temp.put(ABRL_NEXTCOMP,relvoc.get(ABRL_IDCOMP)); //Aggiorno la relazione precedente relvoc.put(ABRL_PREVCOMP,relvoc.get_long(ABRL_IDCOMP)-1); //Aggiorno la relazione attuale temp.rewrite();// Scrivo la precedente } else CHECK (FALSE, "Non ho trovato il prevcomp di una relazione che dovrebbe averlo"); } else { //Non c'è la relazione precedente relvoc.put(ABRL_PREVCOMP,ID_NULLO); //Aggiorno la relazione attuale } } bool TFile_text_AS400::pre_writerel(TRelation& rel,const TRecord_text& rec) { int logic_num=rel.lfile().num(); //Carico il numero logico del file che sto utilizzando if (logic_num==LF_ABSALDI) {//Parte riservata ai SALDI: modifico (immetto) il tipo di bilancio con il valore passato da maschera //solo se questo campo è vuoto, nel caso contratio lascio il valore letto // TString prova = get_tipo_bil(); rel.lfile().put(ABMD_TIPOBIL,get_tipo_bil()); return TRUE; }//Fine parte riservata ai SALDI if (logic_num==LF_MOVDETT) { //Parte riservata ai DETTAGLI e MOVIMENTI //Inserisco nel file isam tutti i dati che mi servono //per la costruzione dell'albero. //Si divide in 3 parti. //PARTE 1: Assegno degli id temporanei TString id = "1"; //Costruisco un chiave composta con i vari campi letti che interessano TToken_string key; key.add(rec.get(CODICE_DITTA_MOVDETT)); key.add(rec.get(ANNO_BILANCIO_MOVDETT)); key.add(rec.get(CODICE_PERIODO_MOVDETT)); key.add(rec.get(CODICE_TABELLA_MOVDETT)); //Controllo che esiste nell'assoc_array un elemento con chiave uguale a quella appena generata //se esiste last_id contiene l'ultimo indice associato a quella chiave TString *last_id=(TString*)_last_id.objptr(key); if (last_id) { long val=atol(*last_id); //Se esiste incremento l'indice val++; id.format("%ld",val); } _last_id.add(key,id,TRUE); //se esiste già una chiave giusta, sovrascrivo l'indice aggiornato //se non esiste creo la nuova chiave con indice 1 rel.lfile().put(ABMD_ID,id); //scrivo sulla relazione assegnando a ABMD_ID l'indice calcolato //FINE PARTE 1 //PARTE 2: inserisco il TIPODETT, TIPOBIL e evenutalmente CODDETT if ((rec.type() == MOVIMENTO3) || (rec.type() == MOVIMENTO4) || (rec.type() == MOVIMENTO5)) { //E' di tipo "dettaglio" o "conto contabile": non può essere "movimento" real r(rec.get(CONTO_COGE_MOVDETT)); //Eseguo una conversione per un controllo numerico if (r > 0) {//E' un COGE e quindi inserisco anche il Coddett rel.lfile().put(ABMD_TIPODETT,"CG"); rel.lfile().put(ABMD_CODDETT,rec.get(CONTO_COGE_MOVDETT)); rel.lfile().put(ABMD_TIPOBIL,get_tipo_bil()); } else {//In questo caso inserisco Coddett = 0 per azzerare eventuali altri valori //già scritti precedentemente rel.lfile().put(ABMD_TIPODETT,"DT"); rel.lfile().put(ABMD_CODDETT,0); rel.lfile().put(ABMD_TIPOBIL,get_tipo_bil()); } } else {//Può essere solo un "movimento" perchè il tipo record è MOVI1 o MOVI2 rel.lfile().put(ABMD_TIPODETT,"MO"); rel.lfile().put(ABMD_TIPOBIL,get_tipo_bil()); rel.lfile().put(ABMD_CODDETT,0); //Azzero il contenuto del campo da valori precedenti real r(rec.get(CONTO_COGE_MOVDETT)); //Eseguo una conversione per un controllo numerico if (r > 0) {//E' un movimento di un COGE e quindi devo scrivere anche CODDETT rel.lfile().put(ABMD_CODDETT,rec.get(CONTO_COGE_MOVDETT)); } }//FINE PARTE 2 //PARTE 3. Nel caso in cui il record sia un movimento, devo gestire diversamente il saldo: //Se il flag di riclassificazione è attivato, l'importo del movimento va scritto in RDARE o RAVERE //a seconda del flag D/A //Se il flag di riclassificazione non è ativato // l'importo va inserito nel saldo (e settato il flag D/A) se il record è MOVI1 // l'importo va inserito in PDARE o PAVERE a seconda del flag D/A if (rec.type() == MOVIMENTO1 || rec.type() == MOVIMENTO2) { if (rec.get(FLAG_RICLASSIFICAZIONE_MOVDETT) == "X") {//L'importo va comunque in RDARE o RAVERE if (rec.get(FLAG_DA_MOVDETT) == "D") rel.lfile().put(ABMD_RDARE,rec.get(IMPORTO_MOVDETT)); else rel.lfile().put(ABMD_RAVERE,rec.get(IMPORTO_MOVDETT)); } else {//L'importo va nel campo IMPORTO se MOVIMENTO1 if (rec.type() == MOVIMENTO1) { rel.lfile().put(ABMD_IMPORTO,rec.get(IMPORTO_MOVDETT)); rel.lfile().put(ABMD_FLDA,rec.get(FLAG_DA_MOVDETT)); } else {// ... oppure in PDARE o PAVERE se MOVI2 if (rec.get(FLAG_DA_MOVDETT) == "D") rel.lfile().put(ABMD_PDARE,rec.get(IMPORTO_MOVDETT)); else rel.lfile().put(ABMD_PAVERE,rec.get(IMPORTO_MOVDETT)); } } }//FINE PARTE 3 //PARTE 4 scrivi_temp_link(rel,rec); //FINE PARTE 4 return TRUE; }//Fine parte riservata ai DETTAGLI e MOVIMENTI if (logic_num==LF_VOCI) {//Parte riservata alle voci bool write_rec=TRUE; TAdditional_cars &caradd= (TAdditional_cars &)(rel.lfile(LF_CARADD)); TAdditional_cols &col= (TAdditional_cols &)(rel.lfile(LF_COLLDICH)); if ((rec.get(TIPO_VOCE_VOCI) != FLAG_INDICE) ) {//Scrivo la chiave anche sul file secondario della relazione real idcaradd_ra; idcaradd_ra = 0; // TString prova = *idcaradd_ra.string(); TLocalisamfile fil(LF_VOCI); fil.curr()=rel.curr(); if (fil.read() != NOERR) { // Voce non ancora inserita; la caradd diventa il default caradd.write(); rel.lfile().put(ABVC_IDCARADD,caradd.get(ABCA_ID)); } else { // non scrivero' la voce write_rec=FALSE; // cerco il default if (!caradd.current().same_as(rel.lfile().get_real(ABVC_IDCARADD))) { // diverso dal default: va scritto in relana caradd.write(); idcaradd_ra=caradd.get_real(ABCA_ID); } } if (atol(rec.get(NCA_VOCI)) > 0) {//Aggiorno anche radici: inserisco solo le "voci" di primo livello //e sono le tabelle di analisi, cioè le radici dell'albero //Aggiorno RELVOCI TLocalisamfile & relvoc=rel.lfile(LF_RELVOCI); relvoc.put(ABRL_TIPOCOD,FLAG_ANALISI); //Analisi di bilancio relvoc.put(ABRL_CODCOMP,rel.lfile().get(ABVC_CODVC)); relvoc.put(ABRL_NEXTCOMP,ID_NULLO); //La relazione successiva non la vedo ancora aggiorna_rel_link(relvoc); relvoc.write(); //Scrivo effettivamente sull'isamfile //Aggiorno il collegamento a dichiarazione col.write(); //Aggiorno RELANA TLocalisamfile &ran=rel.lfile(LF_RELANA); ran.put(ABRA_CODAN,(relvoc.get(ABRL_CODVC)).sright(2)); ran.put(ABRA_ID,relvoc.get(ABRL_IDCOMP)); //Assegno questo "ID" provvisorio per poterlo rintracciare dopo ran.put(ABRA_DESCRIZ,rel.lfile().get(ABVC_DESCR)); ran.put(ABRA_TIPOCOD,FLAG_ANALISI); ran.put(ABRA_CODVC,relvoc.get(ABRL_CODVC)); ran.put(ABRA_NCOMP,relvoc.get(ABRL_IDCOMP)); ran.put(ABRA_IDCARADD,idcaradd_ra.string("############")); ran.put(ABRA_USACARADD,idcaradd_ra==ID_NULLO ? FALSE : TRUE); ran.put(ABRA_IDCOLDICH,col.get_long(ABCD_ID)); ran.write(); } } else // tipo di voce non più supportata write_rec=FALSE; return write_rec; }//Fine parte riservata alle voci if (logic_num==LF_RELVOCI) {//Parte riservata alle relazioni rel.lfile().put(ABRL_TIPOCOD,FLAG_VOCI); rel.lfile().put(ABRL_NEXTCOMP,ID_NULLO); //La relazione successiva non la vedo ancora aggiorna_rel_link(rel.lfile()); return TRUE; }//Fine parte riservata alle relaizioni if (logic_num==LF_RELANA) {//Parte riservata a SOTTORELAZIONI e COLLEGAMENTO A DICHIARAZIONE TAdditional_cars &caradd = (TAdditional_cars &)(rel.lfile(LF_CARADD)); TAdditional_cols &col = (TAdditional_cols &)(rel.lfile(LF_COLLDICH)); //Abilito la scrittura sulle relazioni collegate rel.write_enable(LF_COLLDICH,TRUE); col.write(); rel.write_enable(LF_COLLDICH,FALSE); rel.lfile().put(ABRA_IDCOLDICH,col.get_long(ABCD_ID)); //Assegno l'ID del collegamento alla relazione principale //Parte riservata a SOTTORELAZIONI e CARATTERISTICHE ADDIZIONALI TString codice_voce=rel.lfile().get(ABRA_CODVC);//Estraggo da RELANA il codice di ricerca su VOCI // codice_voce.ltrim(2); //e la formatto TLocalisamfile voc(LF_VOCI); voc.put(ABVC_CODVC,codice_voce); if (voc.read() == NOERR) { //Ho trovato la voce //Ricerco la caratteristica addizionale di default //Confronto le caratteristiche addizionali del record che //sta per essere salvato e le caratteristiche di default if (! caradd.current().same_as(voc.get_real(ABVC_IDCARADD))) { //Non ho trovato la VOCE o CARATTERISTICA ADDIZIONALE oppure è diversa caradd.write(); rel.lfile().put(ABRA_USACARADD,TRUE); //Setto il flag // long prova = atol (caradd.get(ABCA_ID)); //Solo per debug rel.lfile().put(ABRA_IDCARADD,caradd.get(ABCA_ID)); //Aggiungo il collegamento alla carat. add. } else { rel.lfile().put(ABRA_USACARADD,FALSE); //Setto il flag rel.lfile().put(ABRA_IDCARADD, ID_NULLO ); //Aggiungo il collegamento alla carat. add. di default } } else CHECK (FALSE,"Si è verificato una inconsistenza nei dati: ho trovato una sottorelazione \n che non ha la relativa voce"); return TRUE; } // Fine LF_RELANA return TRUE; } /* ********************************************************************************************************* */ /* TTrasfer */ /*********************************************************************************************************** */ //Questo Handler viene "richiamato" da tre campi: // F_PERCORSO, F_PERCORSO_UTENTE, F_TIPO_RICE bool TTrasfer::inseriscipercorso(TMask_field& f, KEY k) { bool modificato = FALSE; //Questa mi dice quando c'è stata una modifica sulla maschera if ((k==K_TAB) && (f.focusdirty()) && ((f.dlg()==F_PERCORSO) || (f.dlg() == F_PERCORSO_UTENTE))) //Entro in questo if solo se ho eseguito delle modifiche al campo F_PERCORSO //o F_PERCORSO_UTENTE e all'uscita degli stessi //Per il campo F_PERCORSO_UTENTE mi serve solo controllare che esista il percorso e il file indicati { TString percorso =f.get(); //Leggo il contenuto del campo bool esiste=fexist(percorso); //Controllo l'esistenza del file if (!esiste) return f.error_box(TR("Il percorso o il file specificato non esiste.")); modificato=TRUE; } if ((k==K_SPACE) && (f.dlg()==F_TIPO_RICE) && f.focusdirty()) {//Entro in questo if solo dopo aver modificato il contenuto del campo //F_TIPO_RICE e all'uscita dallo stesso TString percorso =f.mask().get(F_PERCORSO); //Leggo il contenuto del campo bool esiste=fexist(percorso); //Controllo l'esistenza del file if (!esiste) return f.error_box(TR("Il percorso o il file specificato non esiste.")); modificato=TRUE; } if (((f.dlg() == F_PERCORSO) || (f.dlg() == F_TIPO_RICE ))&& modificato) {//Entro in questo if tutte le volte che è stato modificato il campo F_PERCORSO //o F_TIPO_RICE if (f.mask().get_int(F_TIPO_RICE) == RICEZIONE_AS400) { //Questa parte dell'handler è riservata solo al campo F_PERCORSO //se è abilitata la ricezione da AS400: in tutti gli altri casi //non è garantito che ci sia un record di testa TWait_cursor hourglass; TRecord_text rec_temp; //Istanzio un tipo record_text TString config_file_temp(f.mask().get(F_PERCORSO_UTENTE));//Nome del file di configurazione TFilename percorso_temp(f.mask().get(F_PERCORSO)); //Contiene il percorso completo del file sorgente int tipo_ricezione = f.mask().get_int(F_TIPO_RICE); app().set_transfer(tipo_ricezione,percorso_temp,config_file_temp); TFile_text *file_temp=NULL; file_temp=app().trans_file(); file_temp->open('r'); //Apro il file di testo in rettura int err = file_temp->read(rec_temp); //Leggo la prima riga del file di testo (dovrebbe contenere il record di testata) if((err == NOERR) && (rec_temp.type() == RECORD_TESTA)) //Controllo la lettura e che ci sia il record di testa {//La lettura della testata ha avuto successo bool abilita_piaco = (rec_temp.get(AB_PIANO_CONTI) == ABILITATO); f.mask().enable(F_PIANO_CONTI,abilita_piaco); bool abilita_periodi = (rec_temp.get(AB_PERIODI_BIL) == ABILITATO); f.mask().enable(F_PERIODI_BILANCI,abilita_periodi); bool abilita_analisi = (rec_temp.get(AB_ANALISI) == ABILITATO); f.mask().enable(F_ANALISI,abilita_analisi); bool abilita_saldi_movimenti = (rec_temp.get(AB_SALDI) == ABILITATO) || (rec_temp.get(AB_DETT) == ABILITATO) || (rec_temp.get(AB_MOV) == ABILITATO); f.mask().enable(F_SALDI,abilita_saldi_movimenti); f.mask().enable(F_MOVIMENTI,abilita_saldi_movimenti); } else //non sono riuscito a trovare la testato o il tipo record dove me lo aspettavo error_box (TR("Non ho trovato il record di testata o non riesco a leggere il file di configurazione")); file_temp->close(); delete file_temp; file_temp =NULL; } else {//Ho scelto una ricezione INTERNA o USER_DEFINED: abilito tutti gli altri campi //poichè non è previsto che ci sia un campo di testata f.mask().enable(F_PIANO_CONTI,TRUE); f.mask().enable(F_PERIODI_BILANCI,TRUE); f.mask().enable(F_ANALISI,TRUE); f.mask().enable(F_SALDI,TRUE); f.mask().enable(F_MOVIMENTI,TRUE); f.mask().enable(F_VOCI,TRUE); f.mask().enable(F_RELAZ,TRUE); f.mask().enable(F_SRELAZ,TRUE); } }// Non sono sul campo F_PERCORSO return TRUE; } //Funzione membro che effettua la conversione void TRicezione::main_loop() { _files.add(new TLocalisamfile(LF_CARADD),1); _files.add(new TLocalisamfile(LF_COLLDICH),2); TString config_file; //Nome del file di configurazione TMask msk("AB2100A"); //Maschera dove si chiede di immettere il percorso del file sorgente TFilename percorso; //Contiene il percorso completo del file sorgente msk.set_handler(F_PERCORSO, inseriscipercorso); //Assegno un handler al campo F_PERCORSO //inseriscipercorso controlla che il percorso (e il file) esista e sia corretto msk.set_handler(F_PERCORSO_UTENTE, inseriscipercorso); msk.set_handler(F_TIPO_RICE, inseriscipercorso); //A questo punto il percorso e' corretto if (msk.run()== K_ENTER) //Eseguo la maschera { //Visualizza una finestra di attesa TIndwin idle(0,TR("Attendere: aggiornamento della tabella in corso. \n L'operazione potrebbe richiedere qualche minuto ... "),FALSE,FALSE,60); percorso=msk.get(F_PERCORSO); //Leggo il contenuto di F_PERCORSO if (msk.get_int(F_TIPO_RICE) == RICEZIONE_AS400) { _rice = new TRicezione_AS400(percorso); } if (msk.get_int(F_TIPO_RICE) == RICEZIONE_INTERNA) { _rice = new TObject_reception(percorso); } if (msk.get_int(F_TIPO_RICE) == RICEZIONE_USER_DEFINED) { _rice = new TObject_reception(percorso); } _rice->ricevi(msk); /* if ((msk.get_int(F_TIPO_RICE) == RICEZIONE_AS400) && (msk.get_bool(F_MOVIMENTI))) { build_balancetree(LF_MOVDETT); } */ //La chiusura del _trasfile non può essere eseguita prima poichè questo //serve nella costruzione dell'albero dei movimenti /* if (msk.get_bool(F_SRELAZ)) build_relana(config_file,msk,percorso); */ //messaggio finale message_box(TR(" ... aggiornamento delle tabelle selezionate effettuato")); } //end if (msk.run()) // return FALSE; } void TObject_reception::ricevi(TMask & msk) { TRecord_text rec; //Istanzio un tipo record_text if ((msk.get_bool(F_VOCI)) && (msk.get_int(F_TIPO_RICE) == RICEZIONE_AS400)) {//Eseguo questa parte solo per la ricezione AS400 TRelation *r=_trasfile->t_rec(LF_VOCI)->relation(); TAdditional_cars * ca=new TAdditional_cars(_excllock); r->replacef(ca,LF_CARADD); TAdditional_cols * co=new TAdditional_cols(); r->replacef(co,LF_COLLDICH); } //Ciclo di lettura-scrittura fino a quando la lettura è possibile while (_trasfile->ok_r()) { if(_trasfile->read(rec) == NOERR) { if (msk.get_bool(F_PIANO_CONTI)) //Controllo se si è scelto di convertire il piano dei conti { _trasfile->autosave(rec,LF_ABPCON); } if (msk.get_bool(F_PERIODI_BILANCI)) //Scelta di convertire la tabella periodi bilanci { _trasfile->autosave(rec,LF_TABCOM); } if (msk.get_bool(F_ANALISI)) //scelta di cnverite la tabella tipi analisi di bilancio { _trasfile->autosave(rec,LF_ANALISI); } if (msk.get_bool(F_MOVIMENTI)) //scelta di cnverite la tabella tipi analisi di bilancio { _trasfile->autosave(rec,LF_MOVDETT); } if (msk.get_bool(F_SALDI)) //scelta di cnverite la tabella tipi analisi di bilancio { _trasfile->autosave(rec,LF_ABSALDI); } if (msk.get_bool(F_VOCI)) { _trasfile->autosave(rec,LF_VOCI); } if (msk.get_bool(F_RELAZ)) { _trasfile->autosave(rec,LF_RELVOCI); if (msk.get_int(F_TIPO_RICE) != RICEZIONE_AS400) {// Se è abilitito è abilitato la RICEZIONE_INTERNA devo ricevere anche questi files _trasfile->autosave(rec,LF_RELANA); _trasfile->autosave(rec,LF_CARADD); _trasfile->autosave(rec,LF_COLLDICH); } } } } //Finita prima fase di aggionamento, si passa eventualmente alla seconda } /* ********************************************************************************************************* */ /* TAlbero_record */ /*********************************************************************************************************** */ // visita in dept first e aggiunge man mano i link corretti ai nodi void TAlbero_record::dept_first(TToken_string key, TRectype * padre, TRectype * prec, int &curr_id, TString_array & allkeys, TToken_string ** prog_key) // param . per ricerche COGE { TRectype * myself=(TRectype * )objptr(key); // ********* // insert this node myself->put(ABMD_ID,curr_id); myself->put(ABMD_IDPADRE,padre ? padre->get(ABMD_ID):ID_NULLO); myself->put(ABMD_IDFIGLIO,ID_NULLO); myself->put(ABMD_IDPREC,prec ? prec->get(ABMD_ID) : ID_NULLO); myself->put(ABMD_IDSUCC,ID_NULLO); if (prec==NULL) // il primo figlio aggiorna il tipodett del padre if (padre) { padre->put(ABMD_DETTFIGLIO,myself->get(ABMD_TIPODETT)); } else { // il padre è un saldo TLocalisamfile rel(LF_ABSALDI); //Creo un nuova relazione //compongo la chiave che mi interessa rel.put(ABS_CODDITTA,myself->get(ABMD_CODDITTA)); rel.put(ABS_ANNO,myself->get(ABMD_ANNO)); rel.put(ABS_CODPDB,myself->get(ABMD_CODPDB)); rel.put(ABS_TIPOBIL,myself->get(ABMD_TIPOBIL)); rel.put(ABS_CODCBL,myself->get(ABMD_CODCBL)); //ricerco la chiave if (rel.read()==NOERR) {//se esiste aggiorno il campo rel.put(ABS_DETTFIGLIO,myself->get(ABMD_TIPODETT)); rel.rewrite(); } else {// ... questa situazione non dovrebbe accadere: se succede si è verificata una //inconsistenza nei dati fatal_box(TR("Si è verificato una inconsistenza nei dati: \n controllare che tutti i movimenti abbiano il relativo saldo")); } } TToken_string key_figlio, key_fratello; // ********* // scende sul figlio key_figlio=cerca_figlio(key,allkeys,prog_key); if (key_figlio.not_empty()) // esiste il figlio { curr_id++; myself->put(ABMD_IDFIGLIO,curr_id); dept_first(key_figlio, myself, NULL ,curr_id, allkeys, prog_key); } // ********* // passa al fratello key_fratello=cerca_fratello(key,allkeys,prog_key); if (key_fratello.not_empty()) // esiste il fratello { curr_id++; myself->put(ABMD_IDSUCC,curr_id); dept_first(key_fratello, padre, myself ,curr_id, allkeys, prog_key); } } //key is: FLAG|CODDETT|NREG|NRIG TToken_string& TAlbero_record ::cerca_figlio (TToken_string &key, TString_array& allkeys, // parametri ricerca COGE TToken_string ** next_key ) { TString cod_dett(key.get(1)); wrk_string.cut(0); if (*key.get(0)==FLAG_COGE) { // sono un COGE? il figlio può essere un mov o un COGE // cerco un MOV wrk_string.cut(0); wrk_string.add(FLAG_MOVIMENTO); wrk_string.add(cod_dett); wrk_string.add("0"); wrk_string.add("1"); if (!is_key(wrk_string)) { // il mov non c'è, cerco un COGE wrk_string.cut(0); TString cod_grp(cod_dett.left(2)), cod_con(cod_dett.mid(2,4)), cod_scon(cod_dett.right(4)); if (atoi(cod_scon) > 0) // sono all'ultimo livello return wrk_string; if (*next_key) { TString cod_dett_succ=(*next_key)->get(1); if (atoi(cod_con) > 0) { // il figlio di un conto è un sottoconto e ha lo stesso gruppo/conto if (cod_dett_succ.left(2)!=cod_grp ||cod_dett_succ.mid(2,4)!=cod_con) return wrk_string; } else { // il figlio di un gruppo è un conto e ha lo stesso gruppo if (cod_dett_succ.left(2)!=cod_grp) return wrk_string; } wrk_string.add(FLAG_COGE); wrk_string.add(cod_dett_succ); wrk_string.add("0"); wrk_string.add("0"); *next_key=(TToken_string *)allkeys.succ_item(); } } } else if (*key.get(0)==FLAG_DETT) { // sono un dettaglio immesso // il figlio può solo essere un mov wrk_string.add(FLAG_MOVIMENTO); wrk_string.add(cod_dett); wrk_string.add("0"); wrk_string.add("1"); } // else ... sono un movimento? non ho figli! else return wrk_string; if (!is_key(wrk_string)) wrk_string.cut(0); return wrk_string; } //key is: FLAG|CODDETT|NREG|NRIG TToken_string& TAlbero_record ::cerca_fratello (TToken_string &key, TString_array& allkeys, // parametri ricerca COGE TToken_string ** next_key ) { TString cod_dett(key.get(1)); wrk_string.cut(0); if (*key.get(0)==FLAG_COGE) { // sono un COGE? // cerco la chiave successiva TString cod_grp(cod_dett.left(2)), cod_con(cod_dett.mid(2,4)), cod_scon(cod_dett.right(4)); if (*next_key) { TString cod_dett_succ=(*next_key)->get(1); if (atoi(cod_scon) > 0) { // fratello di un sottoconto if (cod_dett_succ.left(2)!=cod_grp ||cod_dett_succ.mid(2,4)!=cod_con) return wrk_string; } else if (atoi(cod_con) > 0) { // fratello di un conto if (cod_dett_succ.left(2)!=cod_grp) return wrk_string; } else { // fratello di un gruppo if (*(*next_key)->get(0)!=FLAG_COGE) return wrk_string; } wrk_string.add(FLAG_COGE); wrk_string.add(cod_dett_succ); wrk_string.add("0"); wrk_string.add("0"); *next_key=(TToken_string *)allkeys.succ_item(); } } else if (*key.get(0)==FLAG_DETT) { real r(cod_dett); //Eseguo una conversione per una operazione numerica r+=1; TString cod_dett_succ=r.string(); cod_dett_succ.right_just(10,'0'); // sono un dettaglio immesso wrk_string.add(FLAG_DETT); wrk_string.add(cod_dett_succ); wrk_string.add("0"); wrk_string.add("0"); } else { // sono un movimento TString nrig(key.get(3)); nrig.format("%d",atoi(nrig)+1); wrk_string.add(FLAG_MOVIMENTO); wrk_string.add(cod_dett); wrk_string.add(key.get(2)); wrk_string.add(nrig); } if (!is_key(wrk_string)) wrk_string.cut(0); return wrk_string; } /* ********************************************************************************************************* */ /* TRicezione_AS400 */ /*********************************************************************************************************** */ // prepara l'albero di record per la navigazione e lo naviga void TRicezione_AS400::naviga_array(TAlbero_record &a) { int curr_id=1; TString_array allkeys; a.get_keys(allkeys); allkeys.sort(); TToken_string radice,*next_key; radice=(TToken_string &)*allkeys.first_item();// radice next_key=(TToken_string *)allkeys.succ_item();// chiave seguente (figlio? fratello?) a.dept_first(radice, NULL,NULL, curr_id,allkeys,&next_key); } void TRicezione_AS400::scrivi_array(TAssoc_array &s_rec, int logic_num) { TRectype *rec; //Creo un tipo di record dove inserire il record int i=s_rec.items(); TRelation *rel=_trasfile->t_rec(logic_num)->relation(); rec=(TRectype*)s_rec.first_item(); //Metto il primo record dell'assoc_array in un tipo_record for (i=0; i < s_rec.items(); i++) { rel->curr()=*rec; //Metto sul record corrente della relazione il record letto int err = rel->rewrite(); //Scrivo sulla relazione //non dovrebbe mai succedere if (err != NOERR) { message_box(TR("Si è verificato un errore nella costruzione dell'albero")); err = rel->write(); } rec=(TRectype*)s_rec.succ_item(); } } void TRicezione_AS400::leggi_temp_link(TRectype& cur_rec,TToken_string& k) { TString campo1 = cur_rec.get(ABMD_IDPADRE); TString campo2 = cur_rec.get(ABMD_IDFIGLIO); k.add(campo1.left(1)); campo1=campo1.ltrim(1); campo2.right_just(5,'0'); campo1 = campo1 << campo2; k.add(campo1); k.add(atol(cur_rec.get(ABMD_IDSUCC))); k.add(atol(cur_rec.get(ABMD_IDPREC))); } void TRicezione_AS400::build_balancetree(int logic_num) { TAlbero_record seleziona_record; //Dichiarazione di un assoc_array TRelation rel(logic_num); //Creo un nuova relazione TRectype prev_rec(logic_num); //Creo un tipo di record temporaneo dove inserire il record precedente TRectype& cur_rec =rel.lfile().curr(); //Creo un tipo di record dove inserire il record attuale for (int err = rel.first(); err == NOERR; err = rel.next()) { if (cur_rec.compare_key(prev_rec,1,1) != 0) //Confronto la chiave precedente con quella appena letta escludendo //l'ultimo campo della chiave {//La chiave è diversa, quindi l'assoc array è completo if (seleziona_record.items() > 0) { naviga_array(seleziona_record); //Aggiorno gli indici scrivi_array(seleziona_record,logic_num); //e riscrivo tutto sul file isam } seleziona_record.destroy(); //Vuoto completamente l'array prev_rec = cur_rec; //Aggiorno il record precedente } //Se arriva qui, significa che ho trovato una chiave uguale e deve essere inserita nell'array //Questa parte ricostruisce la chiave originaria TToken_string k; //Chiave dell'assoc_array leggi_temp_link(cur_rec,k); //La chiave è stata ricostruita cur_rec.put(ABMD_IDPADRE,0); //Azzero i campi da riscrivere cur_rec.put(ABMD_IDFIGLIO,0); cur_rec.put(ABMD_IDSUCC,0); cur_rec.put(ABMD_IDPREC,0); //Aggiorno l'assoc_array con la chiave corretta seleziona_record.add(k,cur_rec); } if (seleziona_record.items() > 0) { //Queste due servono per l'ultima tipo di chiave letta naviga_array(seleziona_record); scrivi_array(seleziona_record,logic_num); } } void TRicezione_AS400::build_relana(TString& config_file, const TMask &msk, const TFilename& percorso) { TString16 curr_ana; TToken_string key; TLocalisamfile radici(LF_RELVOCI); TRelation rel(LF_RELANA); TAssoc_array tabtree; TRecord_text rec; //Creo un record text TFile_text *ft=NULL; //Dichiaro un nuovo file_text rel.add(LF_COLLDICH,"ID=IDCOLDICH"); rel.add(LF_CARADD,"ID=IDCARADD"); //ft = set_config_name(config_file,msk,percorso); ft = trans_file(); // ft->close(); //Chiudo il file ft->open('r'); //Apro il file di testo in lettura //Inizia il ciclo sulle Analisi in radici if (radici.first() != NOERR) //Mi posiziono sul primo record di LF_RELVOCI return; //e controllo che i dati siano "corretti" CHECK(radici.get(ABRL_TIPOCOD)==FLAG_ANALISI, "Ci sono voci ma non tabelle ???"); TAdditional_cars * ca=new TAdditional_cars(_excllock); rel.replacef(ca,LF_CARADD); TAdditional_cols * co=new TAdditional_cols(); rel.replacef(co,LF_COLLDICH); //Posiziona la lettura sul file di testo do { ft->read(rec); } while (rec.type() != TIPO_SRELAZ); //Aggiorno il tipo di analisi corrente curr_ana = radici.get(ABRL_CODVC); do { tabtree.destroy(); //Azzero l'assoc_array long currid=1; #ifdef DBG // Questa parte stampa in un file di testo la struttura ad albro // dell'analisi: da usare solo in fase di debug int level=0; FILE * stream=fopen("\\st1.txt","w"); print_ana_tree(level,radici.curr(),stream); fclose(stream); #endif build_ana_tree(currid,radici.curr(),NULL,NULL,tabtree); // costruisce l'albero in memoria // legge dal file di testo e completa i record in tabtree do { // chiave per l'assoc array key.cut(0); key.add(FLAG_VOCI); key.add(rec.get(CODVC_SOTTOREL)); real k1(rec.get(NCOMP_SOTTOREL)); key.add(k1.string()); real k2(rec.get(NSREL_SOTTOREL)); key.add(k2.string()); // rintraccia il record sull'assoc array rel.lfile().curr() = (TRectype & )tabtree[key]; //Aggiorno il TIPOCOD: non può essere fatto in PRE_WRITE perchè può assumere valori diversi rel.lfile().put(ABRA_TIPOCOD,FLAG_VOCI); // modifica e scarica il record // TRectype prova(LF_COLLDICH); // prova= rel.lfile(LF_COLLDICH).curr(); ft->autosave(rel,rec); //La relazione principale è basata su RELANA tabtree.remove(key); } while ((ft->read(rec) == NOERR) && (rec.type() == TIPO_SRELAZ)); //A questo punto ho scritto sull'isamfile tutte le voci: ora devo //scrivere le analisi tabtree.restart(); for (int i=tabtree.items(); i > 0 ; i--) { THash_object *obj; obj=tabtree.get_hashobj(); //Ritorna il primo elemento dell'assoc_array completo di chiave TToken_string key(obj->key()); //Estraggo la chiave dell'oggetto estratto dall'assoc_array rel.lfile().write((TRectype&)obj->obj()); //Aggiorno il file isam tabtree.remove(key); //Tolgo il record dall'assoc_array } // passa alla prossima Analisi while (radici.next() == NOERR && curr_ana == radici.get(ABRL_CODVC)); //Aggiorno il tipo di analisi corrente curr_ana = radici.get(ABRL_CODVC); //Riposiziono la lettura sul testo do { ft->read(rec); } while ((rec.type() != TIPO_SRELAZ) && (rec.get(CODVC_VOCI) == curr_ana.sright(2))); //Formatto la chiave } while (radici.get(ABRL_TIPOCOD)=="A"); } // naviga per ricostruire il numero di sottorelazione void TRicezione_AS400::build_ana_tree(long &currid, TRectype & nodo, TRectype * father, TRectype * brother, TAssoc_array & tabtree) { TRectype *ana_node; TToken_string key; // calcola il numero di sottorelazione int c=1; do { key.cut(0); //Vuota la chiave key.add(nodo.get(ABRL_TIPOCOD)); key.add(nodo.get(ABRL_CODVC)); key.add(nodo.get(ABRL_IDCOMP)); key.add(c); c++; } while (tabtree.objptr(key)!=NULL); ana_node = new TRectype(LF_RELANA); //ana_node->zero(' '); //Solo per vederlo a livello di debug // setta il nodo if (father == NULL) {//Sono la radice principale e leggo i dati già inseriti con la vecchia chiave TLocalisamfile rela(LF_RELANA); TString codan = key.get(1); //Questa chiave letta da LF_RELVOCI è in realtà lunga 10 caratteri rela.put(ABRA_CODAN,codan.sright(2)); //mentre quella di LF_RELANA è lunga solo 2 (i due caratteri più a destra) TString16 old_id = key.get(); rela.put(ABRA_ID,atol(old_id)); if (rela.read() == NOERR) //Leggo i dati inseriti precedentemente { *ana_node=rela.curr(); rela.remove(); //E li elimino dal file_isam per aggiornare la chiave } else CHECK (FALSE,"Errore di consistenza nei dati"); } //Aggiorno la chiave ana_node->put(ABRA_ID, currid); ana_node->put(ABRA_IDPADRE, father ? father->get(ABRA_ID) : ID_NULLO); ana_node->put(ABRA_IDPREC, brother ? brother->get(ABRA_ID) : ID_NULLO); tabtree.add(key,ana_node); // passa al figlio leggendo su RELVOCI se esso esiste TLocalisamfile relvoci(LF_RELVOCI); relvoci.put(ABRL_TIPOCOD,'V'); //Deve essere una voce relvoci.put(ABRL_CODVC,nodo.get(ABRL_CODCOMP));//Prendo il codice del mio figlio relvoci.put(ABRL_IDCOMP,1); //Prendo la prima componente if (relvoci.read()==NOERR) { currid++; ana_node->put(ABRA_IDFIGLIO, currid); build_ana_tree(currid,relvoci.curr(),ana_node,NULL,tabtree); //Richiamo questa funzione } else ana_node->put(ABRA_IDFIGLIO, ID_NULLO); // passa al fratello relvoci.curr().zero(); relvoci.put(ABRL_TIPOCOD,nodo.get(ABRL_TIPOCOD)); relvoci.put(ABRL_CODVC,nodo.get(ABRL_CODVC)); relvoci.put(ABRL_IDCOMP,nodo.get_int(ABRL_IDCOMP)+1); if (relvoci.read()==NOERR) { currid++; ana_node->put(ABRA_IDSUCC, currid); build_ana_tree(currid,relvoci.curr(),father,ana_node,tabtree); } else ana_node->put(ABRA_IDSUCC, ID_NULLO); } // Questa funzione serve solo in fase di debug: // naviga per ricostruire il numero di sottorelazione #ifdef DBG void TRicezione_AS400::print_ana_tree(int &level,TRectype & nodo,FILE * stream) { TToken_string key; TString codvoce; codvoce.fill(' ',3*level); codvoce << nodo.get(ABRL_CODCOMP); fprintf(stream,"%s\n",(const char *) codvoce); // calcola il numero di sottorelazione // passa al figlio leggendo su RELVOCI se esso esiste TLocalisamfile relvoci(LF_RELVOCI); relvoci.put(ABRL_TIPOCOD,'V'); //Deve essere una voce relvoci.put(ABRL_CODVC,nodo.get(ABRL_CODCOMP));//Prendo il codice del mio figlio relvoci.put(ABRL_IDCOMP,1); //Prendo la prima componente if (relvoci.read()==NOERR) { level ++; print_ana_tree(level,relvoci.curr(),stream); //Richiamo questa funzione level --; } // passa al fratello relvoci.curr().zero(); relvoci.put(ABRL_TIPOCOD,nodo.get(ABRL_TIPOCOD)); relvoci.put(ABRL_CODVC,nodo.get(ABRL_CODVC)); relvoci.put(ABRL_IDCOMP,nodo.get_int(ABRL_IDCOMP)+1); if (relvoci.read()==NOERR) { // && relvoci.get(RELVOCI_CODANA)==curr_ana print_ana_tree(level,relvoci.curr(),stream); } } #endif void TRicezione_AS400::ricevi(TMask & msk) { trasfile()->set_tipo_bilancio(msk.get(F_TIPO_BILANCIO)); // Eseguo la ricezione normale TObject_reception::ricevi(msk); // E aggiungo il resto ... if (msk.get_bool(F_MOVIMENTI)) { build_balancetree(LF_MOVDETT); } if (msk.get_bool(F_SRELAZ)) { TString config_file; TFilename percorso; percorso=msk.get(F_PERCORSO); //Leggo il contenuto di F_PERCORSO: è stato controllato prima build_relana(config_file,msk,percorso); } //La chiusura del _trasfile non può essere eseguita prima poichè questo //serve nella costruzione dell'albero dei movimenti if (_trasfile != NULL) { _trasfile->close(); delete _trasfile; _trasfile =NULL; } } TObject_reception::TObject_reception(const TFilename &percorso) { if (_trasfile != NULL) delete _trasfile; _trasfile = new TFile_text(percorso, "ab2100b.ini"); /*DA CAMBIARE*/ _trasfile->open('r'); //apro il TFile_text in lettura } TRicezione_AS400::TRicezione_AS400(const TFilename &percorso) { if (_trasfile != NULL) delete _trasfile; TString config("ab2100a.ini"); _trasfile = new TFile_text_AS400(percorso, config); //Leggo il file di configurazione _trasfile->open('r'); //apro il TFile_text in lettura } TRicezione_userdef ::TRicezione_userdef(const TString & config, const TFilename &percorso) { if (_trasfile != NULL) delete _trasfile; _trasfile = new TFile_text(percorso, config); //Leggo il file di configurazione _trasfile->open('r'); //apro il TFile_text in lettura } int ab2101(int argc, char **argv) { TRicezione a; a.run(argc,argv,TR("Ricezione da file di testo")); return 0; }