#include #include #include #include #include #include #include #include #include #include #include "at8.h" #include "at8100a.h" #include "atlib.h" #include "contsan.h" #include "donaz.h" #include "idoneita.h" #include "soggetti.h" #include "convoc.h" #include "rconvoc.h" #include "storico.h" #define ATFILENAME "pippo.txt" //////////////////////////////////////////////////////// // Classe TCtrn2at_file customizzata dalla TFile_text // //////////////////////////////////////////////////////// class TCtrn2at_file: public TFile_text { protected: virtual void validate(TCursor& cur,TRecord_text &rec, TToken_string &val, TString& str); public: virtual int autosave(TRelation& rel, const TRecord_text& rec); TCtrn2at_file(const TString& file_name, const TString& config_name); virtual ~TCtrn2at_file() { } }; TCtrn2at_file::TCtrn2at_file(const TString& file_name, const TString& config_name) : TFile_text(file_name, config_name) { } int TCtrn2at_file::autosave(TRelation& rel, const TRecord_text& rec) { const TString& type = rec.type();//prendo il tracciato record del tipo del record_text TTracciato_record& tr = *t_rec(type); TArray& a_tc = tr.tracciati_campo(); const int items = a_tc.items(); TString valore; for (int i = 0; i < items; i++) { const TTracciato_campo& tc = tr.get(i); TFieldref field(tc.field()); if (field.name().not_empty()) { if (field.file()==0) field.set_file(rel.lfile().num()); valore = rec.row(i); // formatta il campo del file di testo secondo le specifiche del campo su file isam preformat_field(field,valore,rel,tr.type()); const TRectype& rel_rec = rel.curr(field.file()); TFieldtypes tipo_campo = rel_rec.type(field.name()); bool vuoto = valore.blank(); if (valore[0] == '@') //se trovo il carattere @ -> azzero il campo valore.cut(0); switch(tipo_campo) //in base al tipo di campo formatta i valori seguendo le specifiche del tracciato { case _datefld: //tipo data... { if (real::is_null(valore)) { valore.cut(0); vuoto = TRUE; } TDate data(valore); format_date(data, fpicture(tc), valore);//formatta la data secondo le specifiche del tracciato } break; case _realfld: //tipi numerici case _intfld: case _longfld: { const real numero(valore); vuoto = numero.is_zero(); valore = numero.string(fpicture(tc));//formatta il numero secondo le specifiche del tracciato int length = flength(tc,rel_rec); if (falign(tc) == 'L') valore.left_just(length, ffiller(tc)); else valore.right_just(length, ffiller(tc)); } break; default: valore = format_field(tc, rel.lfile().num(), valore);//formatta il campo secondo le specifiche del record break; } if (!vuoto && rel.exist(field.file())) field.write(valore, rel);//faccio una write sulla relazione del fieldref } } int err = NOERR; if (pre_writerel(rel,rec)) { err= rel.write(); if (err == _isdupkey || err ==_isreinsert) err = rel.rewrite(); } return err; } ///////////////////////////////////////////////////// // Classe TCtrn2at: applicazione principale // ///////////////////////////////////////////////////// class TCtrn2at: public TSkeleton_application { TMask* _msk; TCtrn2at_file* _trasfile; int _numdon1, _numdon2; TString16 _catini1, _catfin1, _catini2, _catfin2; bool _sttess2, _dataisc; protected: virtual bool create(void); virtual void main_loop(); virtual bool destroy(void) ; void transfer(void); void inizializza_file(void); static bool annulla_handler(TMask_field& f, KEY k); bool test_donation(TRectype& recsog, const char* tipo, const TDate& datadon, const TString& luogodon); bool test_inter(TRectype& recsog, const char* tipo, const TDate& datadon, int inter); void calcola_categoria(TRectype& recsog); public: const TMask& msk() const { return *_msk; } TCtrn2at() {} virtual ~TCtrn2at() {} }; // restituisce un riferimento all' applicazione inline TCtrn2at& app() { return (TCtrn2at&) main_app();} // creazione dell'applicazione bool TCtrn2at::create() { open_files(LF_SOGGETTI, LF_DONAZ, LF_CONTSAN, LF_IDONEITA, LF_CONVOC, LF_RCONVOC, LF_STORICO, 0); _msk = new TMask("at8100a"); _msk->set(F_FILENAME,ATFILENAME); _trasfile = NULL; TConfig config(CONFIG_STUDIO); _numdon1 = config.get_int("NumDon1"); _numdon2 = config.get_int("NumDon2"); _catini1 = config.get("CatIni1"); _catfin1 = config.get("CatFin1"); _catini2 = config.get("CatIni2"); _catfin2 = config.get("CatFin2"); _sttess2 = config.get_bool("StTess2"); _dataisc = config.get_bool("DataIsc"); return TSkeleton_application::create(); } // distruzione dell'applicazione bool TCtrn2at::destroy() { delete _msk; return TSkeleton_application::destroy(); } // carica la maschera void TCtrn2at::main_loop() { // Preimposta gli eventuali valori specificati sulla riga di comando //error_box("Attenzione: manca la configurazione del trasferimento!"); KEY key = K_ENTER; while (key != K_QUIT) { key = _msk->run(); if (key == K_ENTER) transfer(); } } bool TCtrn2at::test_donation(TRectype& recsog, const char* tipo, const TDate& datadon, const TString& luogodon) { //ricostruisce le donazioni del soggetto in esame TRectype* key = new TRectype(LF_DONAZ); key->put(DON_CODICE, recsog.get(SOG_CODICE)); TRecord_array donazioni(LF_DONAZ,DON_PROGDON); donazioni.read(key); // verificare se ha fatto una donazione di tipo con data successiva all'ultima donazione const int r=donazioni.last_row(); if (r > 0) { const TRectype& lastdon = donazioni[r]; if (lastdon.get_date(DON_DATADON) >= datadon) return FALSE; } //aggiunge la nuova donazione // compila i dati della donazione in esame TRectype* rec = new TRectype(LF_DONAZ); rec->put(DON_CODICE, recsog.get(SOG_CODICE)); rec->put(DON_PROGDON,r+1); rec->put(DON_DATADON, datadon); rec->put(DON_TIPODON, tipo); rec->put(DON_CODSEZ,recsog.get(SOG_CODSEZ)); rec->put(DON_CODSOT,recsog.get(SOG_CODSOT)); rec->put(DON_LUOGODON, luogodon); if (r == 0) //puó essere una prima donazione... rec->put(DON_PRIMADON,"X"); donazioni.insert_row(rec); donazioni.write(TRUE); calcola_donazioni_lib(recsog, &donazioni); // questo metodo sistema tutto!!! calcola_categoria(recsog); // aggiorno data e utente ultimo aggiornamento const TDate oggi(TODAY); recsog.put(SOG_DATAULTAGG,oggi); recsog.put(SOG_UTENULTAGG,"WINSIT"); return TRUE; } void TCtrn2at::calcola_categoria(TRectype& recsog) { TTable ctd("CTD"); TString16 catdon = recsog.get(SOG_CATDON); const int totdon = recsog.get_int(SOG_TOTDON); ctd.put("CODTAB",catdon); if (ctd.read() == NOERR) { bool dimissione = ctd.get_bool("B0"); if (dimissione) { const TString& cat_coll = ctd.get("S6"); if (cat_coll.not_empty()) { catdon = cat_coll; recsog.put(SOG_CATDON, catdon); } } if ((catdon == _catini1 || _catini1.empty()) && (totdon>=_numdon1) && _catfin1.not_empty()) { recsog.put(SOG_CATDON, _catfin1); catdon = _catfin1; } bool tstampata = recsog.get_bool(SOG_T_STAMPATA); if ((catdon == _catini2 || _catini2.empty()) && (totdon>=_numdon2) && _catfin2.not_empty() && (!_sttess2 || tstampata)) { recsog.put(SOG_CATDON, _catfin2); catdon = _catfin2; } } } bool TCtrn2at::test_inter(TRectype& recsog, const char* tipo, const TDate& datadon, int inter) { const char* tipoido = stricmp(tipo, "SI") != 0 ? "AF" : "SI"; int intervallo = 0; TRectype* key_cont = new TRectype(LF_CONTSAN); key_cont->put(CON_CODICE, recsog.get(SOG_CODICE)); TRecord_array controlli(LF_CONTSAN,CON_PROGCON); controlli.read(key_cont); TRectype* key = new TRectype(LF_IDONEITA); key->put(IDO_CODICE, recsog.get(SOG_CODICE)); TRecord_array idoneita(LF_IDONEITA,IDO_PROGIDO); idoneita.read(key); TString16 stato; if (tipo == "SI") { stato = recsog.get(SOG_STATOSI); intervallo = recsog.get_int(SOG_INTSI); } else { stato = recsog.get(SOG_STATOAF); intervallo = recsog.get_int(SOG_INTAF); } if (stato.empty()) stato = recsog.get(SOG_STATO); if (modstato_tcs(stato) != 'S' && stato.not_empty() && intervallo == inter) return FALSE; const int r = idoneita.last_row(); //se trova una data idoneita >= di quella in esame, quest'ultima viene ignorata if (r > 0) { const TRectype& lastido = idoneita[r]; if ((lastido.get_date(IDO_DATAIDO) >= datadon) && (tipoido == lastido.get(IDO_TIPOIDO))) return FALSE; } TRectype* rec = new TRectype(LF_IDONEITA); rec->put(IDO_CODICE, recsog.get(SOG_CODICE)); //rec->put(IDO_PROGIDO, r+1); rec->put(IDO_DATAIDO, datadon); rec->put(IDO_TIPOIDO, tipoido); // Il mondo è bello perchè c'é l'AVIS (tutte le donaz. non SI sono AF! mah?!) rec->put(IDO_IDO_SOS, "ID"); rec->put(IDO_INTERVALLO, inter); // aggiunto da cristina il 18/09/2002 altrimenti non so che quella riga é stata aggiunta da CT rec->put(IDO_RESPONSAB, "TRASF. DA CT"); idoneita.add_row(rec); idoneita.write(); con_reord(recsog, &controlli, &idoneita); // verifico se occorre azzerare numero convocazioni e data ultima convocazione TDate dataultdon = recsog.get(SOG_DATAULTDON); if ((datadon - dataultdon) > 730) { recsog.put(SOG_DATACONV, NULLDATE); recsog.put(SOG_NUMCONV, 0); } // aggiorno data e utente ultimo aggiornamento (Cristina 18/09/2002) const TDate oggi(TODAY); recsog.put(SOG_DATAULTAGG,oggi); recsog.put(SOG_UTENULTAGG,"WINSIT"); return TRUE; } // trasferimento dati da file CT su programma avis void TCtrn2at::transfer() { TFilename ctboini = "at8100a.ini"; _trasfile = new TCtrn2at_file(_msk->get(F_FILENAME), ctboini); inizializza_file(); const long dimension = fsize(_msk->get(F_FILENAME)); TProgind pi(dimension,"Acquisizione in corso..."); TRelation rel(LF_SOGGETTI); TRectype& sogg = rel.curr(); TString8 str; // Stringa jolly di lavoro TRecord_text curr; while (_trasfile->read(curr) == NOERR) { pi.setstatus(_trasfile->read_file()->tellg()); //controlla se il donatore é AVIS oppure un cane sciolto o, peggio ancora, un adepto della //concorrenza!!!(ovviamente si va a stringhe fisse e non a tabelle! roba da avis.....) str = curr.get(31); //donatore della concorrenza -> lo salta str.trim(); if (str == "ADVS") continue; if (str == "NOASS") //se il donatore é un cane sciolto -> va in sezione NI ed in categoria NI { curr.add("NI",0); curr.add("@",1); sogg.put(SOG_CATDON,"NI"); } str = curr.get(2); sogg.put(SOG_CODICE, atol(str)); if (rel.read(_isequal) != NOERR) sogg.zero(); //controlla se il donatore ha cambiato sezione spostandosi da Bologna in provincia; //in questo caso gli deve cancellare il sottogruppo (veramente un procedimento da //galera, ma se l'avis e winsit vogliono cosí.....) str = curr.get(0); str.trim(); TString8 str1; str1 = curr.get(1); str1.trim(); if (str != sogg.get(SOG_CODSEZ) && str != "01" && str1 == "") curr.add("@",1); //esegue l'effettivo passaggio dati basandosi sulla formattazione del file .ini _trasfile->autosave(rel, curr); const char* tipo[] = { "SI", "PL", "PI", "PP" }; for (int i = 0; i < 4; i++) { bool update = FALSE; TDate datadon(TODAY); str = curr.get(23+i); if (!str.blank()) { datadon = TDate(str); str = curr.get(32); str.trim(); //cambio codice del punto di prelievo per casi speciali (sarebbe necessaria una tabella, //ma con l'AVIS é tempo sprecato....) if (str == "UROM") str = "013"; else if (str == "UROB") str = "O.BE"; else if (str == "IMOLA") str = "70"; update |= test_donation(sogg, tipo[i], datadon, str); } str = curr.get(27+i); if (!real::is_null(str)) update |= test_inter(sogg, tipo[i], datadon, atoi(str)); if (update) { calcola_categoria(sogg); rel.rewrite(); } } } _trasfile->close(); message_box("Operazione terminata"); } //inizializza il file di testo su cui emettere i dati void TCtrn2at::inizializza_file() { TFilename filect = _msk->get(F_FILENAME); //aggiungere lettura automatica nomi file _trasfile->open(filect,'r'); } // handler per gestire la conferma dell'annullamento dei dati inseriti // nella maschera bool TCtrn2at::annulla_handler(TMask_field& f, KEY k) { TMask &m = f.mask(); if (k == K_SPACE) { if (yesno_box("Vuoi veramente annullare i dati inseriti")) m.reset(); } return TRUE; } // gestione dei messaggi estesi nei campi void TCtrn2at_file::validate(TCursor& cur,TRecord_text &rec, TToken_string &s, TString& str) { const TString code(s.get(0)); TString valore; if (code == "_UPPERCASE") { valore.upper(); } else NFCHECK("Macro non definita: %s", (const char *)code); str = valore; } int at8100(int argc, char* argv[]) { TCtrn2at a ; a.run(argc, argv, "Acquisizione dati da Eliot - CT"); return 0; }