campo-sirio/ab/ab2101.cpp
sauro 0556a09bb9 Aggiunti i seguenti file per la ricezione e trasferimento da AS400:
ab2100a.h   Definizione dei campi della maschera
ab2.ccp     Menu principale del modulo ab2
ab2.h       Definizione dei nomi delle applicazioni del menu
ab2100.cpp  Sottomenu che separa la ricezione dal trasferimento e implementazione
            delle classi principali
ab2100.h    Definizione delle costanti indicanti l'indice dei campi nel file di configurazione
ab2100a.uml Maschera
ab2101.cpp  Codice per la parte della ricezione
movdett.h   Definizione di costanti per il tracciato di lf_movdett
saldi.h     Definizione di costanti per il tracciato di lf_saldi

La parte riguardante la ricezione per voci, relazioni e sottorelazioni non e' ancora funzionante


git-svn-id: svn://10.65.10.50/trunk@5632 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-11-17 15:08:54 +00:00

984 lines
35 KiB
C++
Executable File

//AB2101.CPP: Ricezione tabelle
#include <utility.h> //Definizione di fexit
#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 <progind.h>
#include <assoc.h>
#define FLAG_COGE '1'
#define FLAG_DETT '2'
#define FLAG_MOVIMENTO '3' // così i movs sono alla fine
#define FLAG_INDICE "I"
#define FLAG_SOTTOD "S"
#define FLAG_COMPOSTA "C"
#define FLAG_ANALISI "A"
#define FLAG_VOCI "V"
long TABfile_text::_idcaradd=1; //In questo modo questa variabile è visibile a tutti gli oggetti di questa classe
//Costruttore di TABfile_text: lo inizializzo a 0
TABfile_text::TABfile_text(const char* file_name, const char* set_config_name)
: TFile_text(file_name, set_config_name),_idncomp(1),_idcoldich(1)
{
TLocalisamfile f(LF_CARADD);
if (f.last()==NOERR)
_idcaradd=atol(f.get(ABCA_ID))+1;
else
_idcaradd=1;
}
class TAlbero_record : public TAssoc_array
{
static TToken_string wrk_string;
public:
void dept_first(TToken_string key, TRectype * padre, TRectype * prec, int &curr_id, TString_array & allkeys, TToken_string ** prog_key);
TToken_string& cerca_fratello (TToken_string &key, TString_array& allkeys, TToken_string ** next_key);
TToken_string& cerca_figlio (TToken_string &key, TString_array& allkeys, TToken_string ** next_key);
TAlbero_record() {}
virtual ~TAlbero_record(){}
};
TToken_string TAlbero_record ::wrk_string;
//Classe derivata per la ricezione
class TRicezione:public TRiceTras
{
TString _tipo_bilancio;
protected:
virtual void leggi_temp_link(TRectype& cur_rec,TToken_string& k);
public:
void set_tipo_bil(const TString&);
const TString & get_tipo_bil() const {return _tipo_bilancio;}
virtual bool menu(MENU_TAG);
//Controlla che il percorso e il file specificati esistono
static bool inseriscipercorso(TMask_field& f, KEY k);
//Esegue il ciclo di ricezione
void ricevi(TMask &);
void build_balancetree(int);
void naviga_array(TAlbero_record &a);
void scrivi_array(TAssoc_array &s_rec, int);
void build_relana(TString&, const TMask&, const TFilename&);
void build_ana_tree(long&, TRectype&, TRectype*, TRectype*, TAssoc_array&);
TRicezione() {}
virtual ~TRicezione() {}
};
inline TRicezione& app()
{
return (TRicezione&) main_app();
}
void TABfile_text::cambia_anno(TString& str)
{
if (atoi(str)>0)
{
if (str > "50") //Trasformo dal formato aa al formato aaaa
str.insert("19");
else
str.insert("20");
}
}
void TABfile_text::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 TABfile_text::preformat_field(TRelation& rel,const TFieldref&field,const TRecord_text& rec,TString &str)
void TABfile_text::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 TABfile_text::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
}
}
bool TABfile_text::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
rel.lfile().put(ABMD_TIPOBIL,app().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,app().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,app().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,app().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;
if ((rec.get(TIPO_VOCE_VOCI) != FLAG_INDICE) )
{//Scrivo la chiave anche sul file secondario della relazione
long idcaradd_ra=ID_NULLO;
rel.lfile(LF_CARADD).put(ABCA_ID,_idcaradd);
TLocalisamfile fil(LF_VOCI);
fil.curr()=rel.curr();
if (fil.read() != NOERR)
{
// Voce non ancora inserita; la caradd diventa il default
rel.lfile().put(ABVC_IDCARADD,_idcaradd);
_idcaradd++;
//long prova = atol(rec.get(NCA_VOCI));
} else {
// non scrivero' la voce
write_rec=FALSE;
// cerco il default
TLocalisamfile caradd(LF_CARADD);
caradd.put(ABCA_ID,rel.lfile().get(ABVC_IDCARADD));
caradd.read();
caradd.put(ABCA_ID,_idcaradd);
if (rel.lfile(LF_CARADD).curr()!=caradd.curr())
{
// diverso dal default: va scritto in relana
idcaradd_ra=_idcaradd;
rel.lfile(LF_CARADD).put(ABCA_ID,idcaradd_ra);
rel.lfile(LF_CARADD).write();
_idcaradd++;
}
}
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_CODVC,rec.get(CODVC_VOCI)); //Codice della tabella di analisi
// >>>relvoc.put(ABRL_NCOMP,atol(rec.get(NCA_VOCI))); //Id progressivo della tabella di analisi
relvoc.put(ABRL_CODCOMP,rel.lfile().get(ABVC_CODVC));
relvoc.write(); //Scrivo effettivamente sull'isamfile
//Aggiorno RELANA
TLocalisamfile &ran=rel.lfile(LF_RELANA);
ran.put(ABRA_CODAN,relvoc.get(ABRL_CODVC));
ran.put(ABRA_ID,relvoc.get(ABRL_NCOMP)); //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_NCOMP));
//>>>ran.put(ABRA_VOCEINCID,voceincid.right_just(12,'0'));
ran.put(ABRA_IDCARADD,idcaradd_ra);
ran.put(ABRA_USACARADD,idcaradd_ra==ID_NULLO ? FALSE : TRUE);
ran.write();
//Aggiorno il collegamento a dichiarazione
//TLocalisamfile col(LF_COLLDICH);
//col.put(ABCD_ID,_idcoldich); //e alla relazione secondaria
//_idcoldich++;
}
} 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);
return TRUE;
}//Fine parte riservata alle relaizioni
if (logic_num==LF_RELANA)
{//Parte riservata a SOTTORELAZIONI e COLLEGAMENTO A DICHIARAZIONE
rel.lfile().put(ABRA_IDCOLDICH,_idcoldich); //Assegno l'ID del collegamento alla relazione principale
rel.lfile(LF_COLLDICH).put(ABCD_ID,_idcoldich); //e alla relazione secondaria
_idcoldich++;
//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); //gatto
voc.put(ABVC_CODVC,codice_voce);
if (voc.read() == NOERR)
{//Ho trovato la voce
TRelation rela(LF_RELANA);
rela.add(LF_CARADD,"ID=IDCARADD");
rela.lfile().put(ABRA_CODAN,rec.get(CODAN_SOTTOREL));
rela.lfile().put(ABRA_ID,voc.get(ABVC_IDCARADD));
if (rela.read() == NOERR)
{//Ho trovato le caratteristiche addizionali di default della voce
rel.lfile(LF_CARADD).put(ABCA_ID,rela.lfile(LF_CARADD).get(ABCA_ID));
if (rel.lfile(LF_CARADD).curr()==rela.lfile(LF_CARADD).curr())
return TRUE; //Se sono uguali (ho già inserito l'ID corretto) sovrascrivo le caradd
}
}
//Non ho trovato la VOCE o CARATTERISTICA ADDIZIONALE oppure è diversa
//l'ID è già stato incrementato in precedenza
rel.lfile().put(ABRA_IDCARADD,_idcaradd); //Aggiungo il collegamento alla carat. add.
rel.lfile().put(ABRA_USACARADD,"X"); //Setto il flag
rel.lfile(LF_CARADD).put(ABCA_ID,_idcaradd);
_idcaradd++;
return TRUE;
}
return TRUE;
}
//Handler per controllare la validita' del campo F_PERCORSO
bool TRicezione::inseriscipercorso(TMask_field& f, KEY k)
{
if (f.to_check(k))
{
TString percorso;
bool esiste;
percorso=f.get(); //Leggo il contenuto del campo
esiste = fexist(percorso); //Controllo l'esistenza del file
if (esiste==FALSE)
return error_box("Il percorso o il file specificato non esiste.");
}
return TRUE;
}
void TRicezione::ricevi(TMask & msk)
{
TRecord_text rec; //Istanzio un tipo record_text
//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(LF_ABPCON,rec);
}
if (msk.get_bool(F_PERIODI_BILANCI)) //Scelta di convertire la tabella periodi bilanci
{
_trasfile->autosave(LF_TABCOM,rec);
}
if (msk.get_bool(F_ANALISI)) //scelta di cnverite la tabella tipi analisi di bilancio
{
_trasfile->autosave(LF_ANALISI,rec);
}
if (msk.get_bool(F_MOVIMENTI)) //scelta di cnverite la tabella tipi analisi di bilancio
{
_trasfile->autosave(LF_MOVDETT,rec);
}
if (msk.get_bool(F_SALDI)) //scelta di cnverite la tabella tipi analisi di bilancio
{
_trasfile->autosave(LF_ABSALDI,rec);
}
if (msk.get_bool(F_VOCI))
{
_trasfile->autosave(LF_VOCI,rec);
}
if (msk.get_bool(F_RELAZ))
{
_trasfile->autosave(LF_RELVOCI,rec);
}
}
}
//Finita prima fase di aggionamento, si passa eventualmente alla seconda
}
// prepara l'albero di record per la navigazione e lo naviga
void TRicezione::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);
}
// 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("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
TString cod_dett_succ=(r+1).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;
}
void TRicezione::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("Si è verificato un errore nella costruzione dell'albero");
err = rel->write();
}
rec=(TRectype*)s_rec.succ_item();
}
}
void TRicezione::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::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::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; //Dichiaro un nuovo file_text
rel.add(LF_COLLDICH,"ID=IDCOLDICH");
rel.add(LF_CARADD,"ID=IDCARADD");
rel.write_enable();
ft = set_config_name(config_file,msk,percorso);
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 ???");
//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;
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
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);
} while (radici.get(ABRL_TIPOCOD)=="A");
}
// naviga per ricostruire il numero di sottorelazione
void TRicezione::build_ana_tree(long &currid, TRectype & nodo, TRectype * father, TRectype * brother, TAssoc_array & tabtree)
{
TRectype *ana_node;
TToken_string key;
//TString16 curr_ana = nodo.get(RELVOCI_CODANA); //S Non so dove venga usata
// calcola il numero di sottorelazione
int c=1;
do {
key.add(nodo.get(ABRL_TIPOCOD));
key.add(nodo.get(ABRL_CODVC));
key.add(nodo.get(ABRL_NCOMP));
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);
rela.put(ABRA_CODAN,key.get(1));
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_NCOMP,1); //Prendo la prima istanza
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_NCOMP,nodo.get_int(ABRL_NCOMP)+1);
if (relvoci.read()==NOERR)
{
// && relvoci.get(RELVOCI_CODANA)==curr_ana
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);
}
void TRicezione::set_tipo_bil(const TString &tipo_bil)
{
_tipo_bilancio = tipo_bil;
}
//Funzione membro che effettua la conversione
bool TRicezione::menu(MENU_TAG)
{
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);
//A questo punto il percorso e' corretto
if (msk.run()== K_ENTER) //Eseguo la maschera
{
//Visualizza una finestra di attesa
TIndwin idle(0,"Attendere: aggiornamento della tabella in corso.\n\nL'operazione potrebbe richiedere qualche minuto ... ",FALSE,FALSE,60);
percorso=msk.get(F_PERCORSO); //Leggo il contenuto di F_PERCORSO
_trasfile=set_config_name(config_file,msk,percorso);
_trasfile->open('r'); //Apro il file di testo in rettura
set_tipo_bil(msk.get(F_TIPO_BILANCIO));
ricevi(msk);
_trasfile->close();
delete _trasfile;
_trasfile =NULL;
if (msk.get_bool(F_MOVIMENTI))
build_balancetree(LF_MOVDETT);
if (msk.get_bool(F_SRELAZ))
build_relana(config_file,msk,percorso);
//messaggio finale
message_box(" ... aggiornamento delle tabelle selezionate effettuato");
} //end if (msk.run())
return FALSE;
}
int ab2101(int argc, char **argv)
{
TRicezione a;
a.run(argc,argv,"Ricezione da file di testo");
return 0;
}