#include #include #include #include #include #include #include #include #include #include #include #include #include "..\mg\umart.h" #include "..\mg\anamag.h" #include "dl0.h" #include "dl0500.h" #include "dl0500a.h" #include "dl0500b.h" //-----FORM--------------------------------------------------------------------------------------// class TRicerca_form : public TForm { public: TRicerca_form(); virtual ~TRicerca_form(); }; TRicerca_form::TRicerca_form() :TForm ("dl0500a") { } TRicerca_form::~TRicerca_form() { } //-----AUTOMASK---------------------------------------------------------------------------------// class TRicerca_mask : public TAutomask { TRelation * _rel; TCursor * _cur; protected: bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TRicerca_mask(); virtual ~TRicerca_mask(){}; }; TRicerca_mask::TRicerca_mask() :TAutomask ("dl0500a") { } bool TRicerca_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_P_BARCODE: case F_P_GIAC: case F_P_TITOLO: case F_P_ARTISTA: case F_P_COMPOSITORE: case F_P_ETICHETTA: case F_P_PREZZO: case F_P_GENERE: case F_P_TIPOSUPPORTO: if (e == fe_close) { for (int i = 8; i >= 0; i--) //attenzione! e' necessario che gli ID dei bools siano contigui { if (get_bool(F_P_BARCODE+i)) break; } if (i < 0) return error_box("Selezionare almeno un campo per la stampa"); } default: break; } return TRUE; } //-------SKELETON APPLICATION------------------------------------------------------------------------------// enum TFilter_type { dl_normal, dl_date, dl_um }; enum TFilter_comp { dl_eq, dl_gt, dl_lt, dl_match }; struct TFilter_exp : public TObject { TFilter_type _type; TString16 _field; TFilter_comp _cmp; TString80 _value; TFilter_exp() : _type(dl_normal), _cmp(dl_eq) { } }; class TRicerca: public TSkeleton_application { TRicerca_mask * _mask; static TMask * _ordmask; bool _barcode, _giac, _titolo, _artista, _compositore, _etichetta, _prezzo, _genere, _tiposupp; static TArray _filtro; protected: virtual bool create(void); virtual bool destroy(void); virtual void main_loop(); static bool process_link(int id, const char * lnk); static void genera_ordine(); static bool fast_filter(const TRelation* rel); public: void add_expr_filter(const char * field, short id, TFilter_comp cmp) const; void add_meta_filter(const char * field, short id) const; void add_range_filter(const char * field, short fid, short tid = -1) const; TRicerca() {} virtual ~TRicerca() {} }; TArray TRicerca::_filtro; // restituisce un riferimento all' applicazione inline TRicerca& app() { return (TRicerca&) main_app();} //la maschera dl0500b, essendo statica, va dichiarata anche fuori dalla classe TMask * TRicerca::_ordmask = NULL; // creazione dell'applicazione bool TRicerca::create() { open_files(LF_ANAMAG, LF_UMART, LF_MAG, LF_DOC, LF_RCONDV, 0); _mask = new TRicerca_mask; TConfig config("discolat.ini","ADVRES"); _barcode = config.get_bool("BARCODE"); _giac = config.get_bool("GIAC"); _titolo = config.get_bool("TITOLO"); _artista = config.get_bool("ARTISTA"); _compositore = config.get_bool("COMPOSITORE"); _etichetta = config.get_bool("ETICHETTA"); _prezzo = config.get_bool("PREZZO"); _genere = config.get_bool("GENERE"); _tiposupp = config.get_bool("TIPOSUPP"); _mask->set(F_P_BARCODE, _barcode); _mask->set(F_P_GIAC, _giac); _mask->set(F_P_TITOLO, _titolo); _mask->set(F_P_ARTISTA, _artista); _mask->set(F_P_COMPOSITORE, _compositore); _mask->set(F_P_ETICHETTA, _etichetta); _mask->set(F_P_PREZZO, _prezzo); _mask->set(F_P_GENERE, _genere); _mask->set(F_P_TIPOSUPPORTO, _tiposupp); const int leadtime = config.get_int("LEADTIME"); _ordmask = new TMask("dl0500b"); //creazione della maschera intermedia per la generazione righe ordini config.set_paragraph("SENDORD"); _ordmask->set(F_CODCF, config.get("CODDL")); _ordmask->set(F_CODORD, config.get("CODORD")); TDate datacons(TODAY); datacons += leadtime; _ordmask->set(F_DATACONS, datacons); return TSkeleton_application::create(); } // distruzione dell'applicazione bool TRicerca::destroy() { TConfig config("discolat.ini", "SENDORD"); config.set("CODDL", _ordmask->get(F_CODCF)); config.set("CODORD", _ordmask->get(F_CODORD)); delete _ordmask; delete _mask; return TSkeleton_application::destroy(); } //aggiunge effettivamente un'espressione ad un filtro void TRicerca::add_expr_filter(const char * field, short id, TFilter_comp cmp) const { TMask_field& fld = _mask->field(id); //prende il campo dalla maschera if (!fld.empty()) //..se non e' vuoto { TFilter_exp* fe = new TFilter_exp; fe->_field = field; fe->_cmp = cmp; //se e' un campo data deve ANSIzzare il contenuto del campo per aggiungerlo al filtro if (fld.class_id() == CLASS_DATE_FIELD) { fe->_type = dl_date; const TDate date = fld.get(); fe->_value = date.string(ANSI); } else { if (stricmp(field, "UM") == 0) fe->_type = dl_um; fe->_value = fld.get(); //aggiunge il contenuto del campo al filtro } _filtro.add(fe); } } //aggiunge ad un filtro una espressione con l'* void TRicerca::add_meta_filter(const char * field, short id) const { const TString& value = _mask->get(id); TFilter_comp cmp = dl_eq; if (value.find('*') >= 0 || value.find('?') >= 0) cmp = dl_match; add_expr_filter(field, id, cmp); } //aggiunge ad un filtro un range di valori presi due campi o da uno (se coincidenti) void TRicerca::add_range_filter(const char * field, short fid, short tid) const { if (tid > fid) { add_expr_filter(field, fid, dl_gt); add_expr_filter(field, tid, dl_lt); } else add_expr_filter(field, fid, dl_eq); } //metodo ascetico per generare le righe di uno sheet dalla setlinkhandler (vedi la chiamata + sotto) bool TRicerca::process_link(int id, const char * lnk) { TSheet_field& sheet = _ordmask->sfield(F_RIGHE); TToken_string& row = sheet.row(-1); row = "1"; //mette innanzitutto la qta di default (1) row.add(lnk); //poi ci aggiunge il codart sheet.check_row(sheet.items()-1); KEY k = _ordmask->run(); switch(k) { case K_ESC: sheet.destroy(sheet.items()-1); break; case K_ENTER: break; default: genera_ordine(); //chiama il metodo x la generazione dell'ordine break; } return false; } // metodo x la generazione dell'ordine void TRicerca::genera_ordine() { TFilename iniord; //creazione di un file di configurazione temporaneo contenente i dati dell'ordine iniord.temp("DL"); // il nome comincia con DL TConfig ini(iniord,"Transaction"); //paragrafo Transaction del file iniord ini.set("Action", "Insert"); const TDate datacons = _ordmask->get(F_DATACONS); //setta la data di consegna in base alla data di compilazione ordine const TDate oggi(TODAY); //e al leadtime che legge nel file discolat.ini const long leadtime = datacons - oggi; if (leadtime > 0) { TConfig inidata("discolat.ini", "ADVRES"); inidata.set("LEADTIME", leadtime); } //paragrafo testata documento ordine TString16 para; para.format("%d",LF_DOC); ini.set_paragraph(para); //paragrafo della testata: scrive tutti i parametri utili nell'ini ini.set(DOC_PROVV, "D"); ini.set(DOC_ANNO, oggi.year()); //anno di compilazione ordine ini.set(DOC_CODNUM, _ordmask->get(F_CODORD)); //codice numerazione ordine ini.set(DOC_TIPODOC, _ordmask->get(F_TIPODOC)); //tipo documento dell'ordine ini.set(DOC_TIPOCF, "F"); ini.set(DOC_CODCF, _ordmask->get(F_CODCF)); //codice fornitore ini.set(DOC_DATACONS, datacons); //data di consegna TConfig inilist("cat2dl.ini", "PARAMS"); //codice del listino all'ingrosso ini.set(DOC_CODLIST, inilist.get("LISTINGR")); //l'ordine deve essere aggiunto come il successivo all'ultimo gia' presente nelle testate documento TLocalisamfile doc(LF_DOC); //prepara i dati della chiave 1 a meno del campo NDOC doc.put(DOC_PROVV, ini.get(DOC_PROVV)); doc.put(DOC_ANNO, ini.get(DOC_ANNO)); doc.put(DOC_CODNUM, ini.get(DOC_CODNUM)); const TRectype test(doc.curr()); //come record di confronto si prende quello corrente doc.put(DOC_NDOC, "9999999"); //paragrafi delle righe dell'ordine TSheet_field& sheet = _ordmask->sfield(F_RIGHE); TString80 codart; for (int i = 0; i < sheet.items(); i++) { para.format("%d,%d",LF_RIGHEDOC,i+1); ini.set_paragraph(para); TToken_string& row = sheet.row(i); real qta = row.get(0); //la qta sta nel primo campo dello sheet... codart = row.get(1); //..il codart nella seconda ini.set(RDOC_TIPORIGA, "01"); //tiporigamerce ini.set(RDOC_CODART, codart); // ini.set(RDOC_CODARTMAG, codart); inutile ini.set(RDOC_QTA, qta.string()); } ini.set_paragraph("Transaction"); //forza la scrittura dell'ultimo paragrafo! //prepara la stringa di esecuzione del programma degli ordini e lo lancia TString cmd; cmd << "ve0 -0 /i" << iniord; TExternal_app app(cmd); app.run(); sheet.destroy(); //accoppa lo sheet da cui e' nato l'ordine ::remove(iniord); //sopprime il file temporaneo } bool TRicerca::fast_filter(const TRelation* rel) { for (int i = 0; i < _filtro.items(); i++) { const TFilter_exp& fe = (const TFilter_exp&)_filtro[i]; TString80 field_value; switch (fe._type) { case dl_date: { const TDate d = rel->curr().get(fe._field); field_value = d.string(ANSI); } break; case dl_um: { TString80 key = rel->curr().get(ANAMAG_CODART); key << "|1"; field_value = cache().get(LF_UMART, key, fe._field); } break; default: field_value = rel->curr().get(fe._field); } switch (fe._cmp) { case dl_lt: if (field_value > fe._value) return FALSE; break; case dl_gt: if (field_value < fe._value) return FALSE; break; case dl_match: if (!field_value.match(fe._value)) return FALSE; break; default: if (field_value != fe._value) return FALSE; } } return TRUE; } void TRicerca::main_loop() { while (_mask->run() == K_ENTER) { //prende dalla maschera i booleani dei campi da stampare... _barcode = _mask->get_bool(F_P_BARCODE); _giac = _mask->get_bool(F_P_GIAC); _titolo = _mask->get_bool(F_P_TITOLO); _artista = _mask->get_bool(F_P_ARTISTA); _compositore = _mask->get_bool(F_P_COMPOSITORE); _etichetta = _mask->get_bool(F_P_ETICHETTA); _prezzo = _mask->get_bool(F_P_PREZZO); _genere = _mask->get_bool(F_P_GENERE); _tiposupp = _mask->get_bool(F_P_TIPOSUPPORTO); //..e li scrive nel file ini TConfig config("discolat.ini","ADVRES"); config.set("BARCODE", _barcode); config.set("GIAC", _giac); config.set("TITOLO", _titolo); config.set("ARTISTA", _artista); config.set("COMPOSITORE", _compositore); config.set("ETICHETTA", _etichetta); config.set("PREZZO", _prezzo); config.set("GENERE", _genere); config.set("TIPOSUPP", _tiposupp); //laboriosissima costruzione del filtro _filtro.destroy(); add_range_filter(ANAMAG_CODART, F_DABARCODE, F_ABARCODE); add_meta_filter(ANAMAG_USER2, F_ARTISTA); add_meta_filter(ANAMAG_DESCR, F_TITOLO); add_meta_filter(ANAMAG_USER3, F_COMPOSITORE); add_meta_filter(ANAMAG_USER4, F_ETICHETTA); add_range_filter(ANAMAG_GRMERC, F_GENEREMUSICALE); add_range_filter(ANAMAG_USER5, F_DATAE_INI, F_DATAE_FIN); add_range_filter(ANAMAG_USER6, F_DATAV_INI, F_DATAV_FIN); //caso sfigato: c'e' il tipo supporto tra i parametri di filtro! add_range_filter("UM", F_TIPOSUPPORTO); // setta i links presenti nel form (sono gli elementi scritti in blu(b) su bianco(w)) // procedimento standard in questi casi TArray& arr = printer().links(); if (arr.items() == 0) arr.add(new TToken_string("Ordina|b|w")); printer().setlinkhandler(process_link); //dopo il filtrone tocca al cursore x scandire i records TRicerca_form form; //ottimizzazione tempi di ricerca: caso di filtro semplice (senza AND, con ?= o ==) form.cursor()->set_filterfunction(fast_filter, FALSE); //setta il form columnwise form.find_field('B', odd_page, FF_B_CODART).show(_barcode); form.find_field('B', odd_page, FF_B_GIAC).show(_giac); form.find_field('B', odd_page, FF_B_TITOLO).show(_titolo); form.find_field('B', odd_page, FF_B_ARTISTA).show(_artista); form.find_field('B', odd_page, FF_B_COMPOSITORE).show(_compositore); form.find_field('B', odd_page, FF_B_ETICHETTA).show(_etichetta);; form.find_field('B', odd_page, FF_B_PREZZO).show(_prezzo); form.find_field('B', odd_page, FF_B_GENERE).show(_genere); form.find_field('B', odd_page, FF_B_SUPPORTO).show(_tiposupp); //procedimento mistico di costruzione del form columnwise const int hh = 5; //altezza header = 5 righe int rows[4]; rows[0] = hh - 2; rows[1] = hh; rows[2] = printer().formlen(); rows[3] = 0; form.genera_intestazioni(odd_page, hh - 1); form.genera_fincatura(odd_page, hh - 2, rows[2], rows); form.print(); } } int dl0500(int argc, char* argv[]) { TRicerca a ; a.run(argc, argv, "Ricerca avanzata"); return 0; }