#include #include #include #include #include #include #include #include "at0.h" #include "lf.h" #include "atlib.h" // nomi campi maschera #include "at0400a.h" // nomi dei campi #include "soggetti.h" #include "sezioni.h" #include "convoc.h" #include "rconvoc.h" #define ALIAS_CTD -100 #define ALIAS_TCS -200 #define IDON_SI "SI" #define IDON_AF "AF" class TConvoc_app: public TRelation_application { static bool filter_func_convoc(const TRelation* rel); TMask* _msk; TRelation* _rel; TRelation* _relsog; TCursor* _cur; // cursore per selezione soggetti TLocalisamfile* _rconvoc; TLocalisamfile* _soggetti; TRecord_array* _sconvocati; // sheet convocati long _lastcod; // progressivo convocazione da assegnare long _numero; // numero convocazione TDate _data; // data convocazione TString16 _punto; // punto di raccolta TString16 _tipo; // tipo donazione TString16 _codsez; // codice sezione convocata TString16 _codsot; // codice sottogruppo TDate _dataini; bool _ritarda; int _maxrit; protected: virtual bool user_create(); virtual bool user_destroy(); virtual const char* get_next_key(); virtual int scrivi(const TMask& m, bool ri); virtual int write(const TMask& m); virtual int rewrite(const TMask& m); virtual int read(TMask& m); virtual bool remove(); virtual bool changing_mask(int mode) { return FALSE; } virtual TMask* get_mask( int mode = 0) { return _msk; } virtual TRelation* get_relation() const { return _rel; } static bool convocati_notify(TSheet_field& s, int r, KEY k); static bool esegui_handler(TMask_field& f, KEY k); static bool data_handler(TMask_field&f, KEY k); public: TConvoc_app() {} }; HIDDEN inline TConvoc_app& app() { return (TConvoc_app&) main_app(); } bool TConvoc_app::filter_func_convoc(const TRelation* rel) { bool filtrato = FALSE; TRectype& sog = rel->curr(); const TString16 cat = sog.get(SOG_CATDON); const char stato = modstato_tcs(sog.get(SOG_STATO)); const TString16 escluso = sog.get(SOG_ESCLUSO); const bool dimesso = rel->lfile(ALIAS_CTD).get_bool("B0"); filtrato = (cat.not_empty() && (stato == 'I' || stato == 'F') && !dimesso && escluso.empty()); if (filtrato) { filtrato = FALSE; const TString16 punto = sog.get(SOG_PUNTORACC); const TString16 codsez = sog.get(SOG_CODSEZ); const TString16 codsot = sog.get(SOG_CODSOT); if (punto == app()._punto) filtrato = TRUE; else { if (app()._codsez.not_empty() && app()._codsez == codsez) filtrato = (punto.empty()); if ((app()._codsot.not_empty()) && (app()._codsot != codsot)) filtrato = FALSE; } // filtro per data prossima donazione //const TDate dataprossi = sog.get(SOG_DATAPROSSI); //filtrato = (dataprossi.ok()) && (dataprossi <= data) && filtrato; // filtro per intervallo tra cartoline/solleciti/ritardatari if (filtrato) { filtrato = FALSE; const TDate data = app()._data; const int numconv = sog.get_int(SOG_NUMCONV); const TDate dataultconv = sog.get(SOG_DATACONV); const TDate dataultsol = sog.get(SOG_DATAULTSOL); TRectype& sez = rel->curr(LF_SEZIONI); const int giocarsol = sez.get_int(SEZ_GIOCARSOL); const int giosolsol = sez.get_int(SEZ_GIOSOLSOL); const int gioultsol = sez.get_int(SEZ_GIOULTSOL); const int giorit = sez.get_int(SEZ_GIOPERRIT); const int numsol = sez.get_int(SEZ_NUMMAXSOL); if (numconv == 0) filtrato = TRUE; else if ((numconv == 1) && (data-dataultconv>=giocarsol)) filtrato = TRUE; else if ((numconv >= 2 && numconv <= numsol-1) && (data-dataultconv >= giosolsol)) filtrato = TRUE; else if ((numconv == numsol && numsol > 0) && (data-dataultconv >= gioultsol)) filtrato = TRUE; else if ((numconv > numsol && numsol > 0) && (app()._ritarda) && (data-dataultsol<=app()._maxrit) && (data-dataultconv>=giorit)) filtrato = TRUE; } } return filtrato; } bool TConvoc_app::data_handler(TMask_field& f, KEY k) { if (f.to_check(k)) { const TDate data = f.get(); const int giorno = data.wday(); TString16 datagio = ""; switch (giorno) { case 0: datagio = "Domenica"; break; case 1: datagio = "Lunedi"; break; case 2: datagio = "Martedi"; break; case 3: datagio = "Mercoledi"; break; case 4: datagio = "Giovedi"; break; case 5: datagio = "Venerdi"; break; case 6: datagio = "Sabato"; break; } f.mask().set(F_DATAGIO,datagio); } return TRUE; } bool TConvoc_app::esegui_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TMask& m = f.mask(); TCursor* cur = app()._cur; app()._numero = m.get_long(F_NUMERO); app()._data = m.get(F_DATA); app()._punto = m.get(F_PUNTO); app()._tipo = m.get(F_TIPO); app()._codsez = m.get(F_CODSEZ); app()._codsot = m.get(F_CODSOT); app()._dataini = m.get(F_DATAINI); app()._ritarda = m.get_bool(F_RITARDA); app()._maxrit = m.get_int(F_MAXRIT); if (app()._numero == 0 || !app()._data.ok() || app()._punto.empty() || app()._tipo.empty()) return f.error_box("Mancano i dati fondamentali per la convocazione"); // filtro per sezione //TRectype da(LF_SOGGETTI); //if (app()._codsez.not_empty()) // da.put(SOG_CODSEZ, app()._codsez); //if (app()._codsot.not_empty()) // da.put(SOG_CODSOT, app()._codsot); //cur->setregion(da, da); //TString256 filtro; // filtro per categoria donatori non vuota e non dimessi // e non escluso e idoneo //filtro.format("(CATDON != \"\") && (%d->B0 == \"\") && (ESCLUSO == \"\") && ((%d->S6 == \"I\" ) || (%d->S6 == \"F\"))",ALIAS_CTD,ALIAS_TCS,ALIAS_TCS); // filtro per punto di raccolta //filtro << " && "; //if (app()._codsez.empty()) // filtro << format("(PUNTORACC == \"%s\")",(const char*)app()._punto); //else // filtro << "(PUNTORACC == \"\")"; // filtro per data donazione non vuota // e <= data inizio convocazione // per ora subito SI // lo facciamo con la set_filterfunction //cur->setfilter((const char*) filtro, TRUE); const TDate data = app()._data; const TDate dataini = app()._dataini; TDate datalimite = dataini; datalimite.set_year(datalimite.year()-2); // filtro per data prossima donazione TRectype da(LF_SOGGETTI); TRectype a(LF_SOGGETTI); da.put(SOG_DATAPROSSI,datalimite); a.put(SOG_DATAPROSSI,data); cur->setregion(da, a); cur->set_filterfunction(filter_func_convoc, TRUE); TSheet_field& s = (TSheet_field&)m.field(F_CONVOCATI); s.destroy(); TRectype& rec = cur->curr(); TRectype& sez = cur->curr(LF_SEZIONI); int nconv=0; int nsoll=0; int nrit=0; TDate datasog = data; const int giorni = (int)(data-dataini); // giorni su cui suddividere la chiamata -1 const int dim = giorni+1; int* numperdata = new int[dim]; int quanti = ((int)(cur->items())/(giorni+1)); // quanti donatori per giorno if (quanti < 1) quanti = 1; for (int i=0; iitems(); int r=0; TProgind prg (last, "Elaborazione in corso... Prego attendere", FALSE, TRUE, 30); for ( *cur=0; cur->pos() < last; ++(*cur) ) { prg.addstatus(1); const int numconv = rec.get_int(SOG_NUMCONV); const TDate dataultconv = rec.get(SOG_DATACONV); const TDate dataultsol = rec.get(SOG_DATAULTSOL); const TDate dataprossi = rec.get(SOG_DATAPROSSI); const int giocarsol = sez.get_int(SEZ_GIOCARSOL); const int giosolsol = sez.get_int(SEZ_GIOSOLSOL); const int gioultsol = sez.get_int(SEZ_GIOULTSOL); const int giorit = sez.get_int(SEZ_GIOPERRIT); const int numsol = sez.get_int(SEZ_NUMMAXSOL); char chiamata = ' '; if (numconv == 0) chiamata = 'C'; else if ((numconv == 1) && (data-dataultconv>=giocarsol)) chiamata = 'S'; else if ((numconv >= 2 && numconv <= numsol-1) && (data-dataultconv >= giosolsol)) chiamata = 'S'; else if ((numconv == numsol && numsol > 0) && (data-dataultconv >= gioultsol)) chiamata = 'S'; else if ((numconv > numsol && numsol > 0) && (app()._ritarda) && (data-dataultsol<=app()._maxrit) && (data-dataultconv>=giorit)) chiamata = 'R'; switch (chiamata) { case 'C': nconv++; break; case 'S': nsoll++; break; case 'R': nrit++; break; } if (giorni > 0) { datasog = NULLDATE; int partenza; if (dataprossi <= dataini) partenza = 0; else partenza = (int)(dataprossi-dataini); for (int r=partenza;r<=giorni;r++) { if ((numperdata[r]add("CTD", "CODTAB==CATDON",1,0,-ALIAS_CTD); _relsog->add("TCS", "CODTAB==STATO",1,0,-ALIAS_TCS); _relsog->add(LF_SEZIONI, "CODSEZ==CODSEZ|CODSOT==CODSOT"); _cur = new TCursor(_relsog, "", 6); //cursore ordinamento per data prossima donazione _rconvoc = new TLocalisamfile(LF_RCONVOC); _soggetti = new TLocalisamfile(LF_SOGGETTI); _sconvocati = new TRecord_array(LF_RCONVOC,RCV_PROGCONV); _msk->set_handler(F_ESEGUI,esegui_handler); _msk->set_handler(F_DATA,data_handler); TSheet_field& sc = (TSheet_field&)_msk->field(F_CONVOCATI); sc.set_notify(convocati_notify); //TMask& scmask = sc.sheet_mask(); _rel->lfile().last(); _lastcod = _rel->lfile().get_long(COV_NUMERO); return TRUE; } bool TConvoc_app::user_destroy() { delete _rel; delete _relsog; delete _msk; delete _cur; delete _rconvoc; delete _soggetti; delete _sconvocati; return TRUE; } const char* TConvoc_app::get_next_key() { // autonumerazione progressiva delle convocazioni return format("%d|%ld", F_NUMERO, _lastcod+1 ); } bool TConvoc_app::remove() { // cancella convocati // cancella testata convocazione bool ok = TRUE; // cancella convocati int err = _sconvocati->remove(); if (err == _iseof || err == _isemptyfile) err = NOERR; // cancella la testata if (err == NOERR) ok = TRelation_application::remove(); return (ok && err == NOERR); } int TConvoc_app::read(TMask& m) { int err = TRelation_application::read(m); if (err == NOERR) { TRectype* key = new TRectype(LF_RCONVOC); key->put(RCV_NUMERO, m.get(F_NUMERO)); err = _sconvocati->read(key); if (err == NOERR) { TLocalisamfile soggetti(LF_SOGGETTI); TSheet_field& s = (TSheet_field&)m.field(F_CONVOCATI); s.destroy(); for (int r=1; r<=_sconvocati->rows(); r++) { TToken_string& row = s.row(r-1); const TRectype& riga = _sconvocati->row(r); const TString& codice = riga.get(RCV_CODICE); row.add(codice); soggetti.put(SOG_CODICE,codice); if (soggetti.read() != NOERR) soggetti.zero(); row.add(soggetti.get(SOG_COGNOME)); row.add(soggetti.get(SOG_NOME)); row.add(riga.get(RCV_DATACONV)); row.add(riga.get(RCV_CHIAMATA)); row.add(riga.get(RCV_STAMPATO)); row.add(riga.get(RCV_ANNULLATO)); row.add(soggetti.get(SOG_DATANASC)); row.add(soggetti.get(SOG_CATDON)); row.add(soggetti.get(SOG_TESSAVIS)); } } else if (err == _iseof || err == _isemptyfile) err = NOERR; } return err; } int TConvoc_app::write(const TMask& m) { long curcod = m.get_long(F_NUMERO); if (curcod > _lastcod) _lastcod = curcod; return TConvoc_app::scrivi(m, FALSE); } int TConvoc_app::rewrite(const TMask& m) { return TConvoc_app::scrivi(m, TRUE); } int TConvoc_app::scrivi(const TMask& m, bool ri) { // questo trucco è autorizzato dal capo! //TMask& hmask = (TMask&) m; //TDate oggi(TODAY); //hmask.set(F_DATAULTAGG,oggi); //hmask.set(F_UTENULTAGG,user()); int err = ri ? TRelation_application::rewrite(m) : TRelation_application::write(m); if (err == NOERR) { TLocalisamfile soggetti(LF_SOGGETTI); _sconvocati->destroy_rows(); TSheet_field& s = (TSheet_field&)m.field(F_CONVOCATI); TRectype* key = new TRectype(LF_RCONVOC); key->put(RCV_NUMERO, m.get(F_NUMERO)); _sconvocati->set_key(key); for (int r=s.items(); r>0; r--) { TToken_string& row = s.row(r-1); TRectype& rec = _sconvocati->row(r,TRUE); const long codice = row.get_long(0); const TDate dataconv = row.get(3); const char chiamata = row.get_char(4); rec.put(RCV_CODICE,codice); rec.put(RCV_DATACONV,dataconv); rec.put(RCV_CHIAMATA,chiamata); rec.put(RCV_STAMPATO,row.get(5)); rec.put(RCV_ANNULLATO,row.get(6)); if (!ri) { // aggiornamento archivio soggetti soggetti.put(SOG_CODICE,codice); if (soggetti.read() == NOERR) { if (chiamata == 'S') soggetti.put(SOG_DATAULTSOL,dataconv); soggetti.put(SOG_DATACONV,dataconv); int numconv = soggetti.get_int(SOG_NUMCONV); soggetti.put(SOG_NUMCONV,numconv+1); soggetti.rewrite(); } } } err = ri ? _sconvocati->rewrite() : _sconvocati->write(); } return err; } bool TConvoc_app::convocati_notify(TSheet_field& s, int r, KEY k) { bool result = TRUE; switch (k) { case K_CTRL+K_DEL: // avvenuta cancellazione riga { int numconv = s.mask().get_int(F_NUMCONV); s.mask().set(F_NUMCONV,numconv-1); } break; case K_CTRL+K_INS: { int numconv = s.mask().get_int(F_NUMCONV); s.mask().set(F_NUMCONV,numconv+1); } break; case K_INS: result = FALSE; break; } return result; } int at0400(int argc, char* argv[]) { TConvoc_app a; a.run(argc, argv, "Gestione convocazione"); return 0; }