#include #include #include #include #include #include #include #include #include #include #include "../mg/anamag.h" #include "ha3.h" #include "ha3900a.h" ////////////////////////////////////////////// // Albero ////////////////////////////////////////////// //Albero per la gestione delle macchine di un cliente class TCoffee_tree : public TBidirectional_tree { TString8 _curr_node; long _codcf; TString8 _codart; TString16 _matricola; TISAM_recordset _recset; public: virtual bool goto_root(); virtual bool goto_firstson() { return false; } virtual bool goto_rbrother(); virtual bool goto_node(const TString &id); virtual bool could_have_son() const { return false; } virtual bool has_son() const { return false; } virtual bool has_rbrother() const; virtual TObject* curr_node() const { return (TObject*)&_curr_node; } virtual void node2id(const TObject* obj, TString& id) const { id = *(TString*)obj; } virtual bool has_root() const; virtual bool has_father() const { return false; } virtual bool has_lbrother() const; virtual bool goto_father() { return false; } virtual bool goto_lbrother(); virtual bool get_description(TString& desc) const; virtual TFieldtypes get_var(const TString& name, TVariant& var) const; virtual TImage* image(bool selected) const { return get_res_icon(10232); } public: bool set_clifo(long codcf); bool select_attr(const TString& codart, const TString& matricola); const long get_codcf() const; const TString& get_codart() const; const TString& get_matricola() const; TCoffee_tree() : _codcf(0), _recset("USE &ATT") { set_clifo(0L); } }; bool TCoffee_tree::has_root() const { return _recset.items() > 0L; } bool TCoffee_tree::goto_root() { const bool ok = _recset.move_first(); if (ok) _curr_node = "0"; else _curr_node.cut(0); return ok; } bool TCoffee_tree::has_rbrother() const { const long pos = atol(_curr_node); return pos < _recset.items() - 1; } bool TCoffee_tree::goto_rbrother() { const long pos = atol(_curr_node) + 1; const bool ok = _recset.move_to(pos); if (ok) _curr_node.format("%ld", pos); return ok; } bool TCoffee_tree::has_lbrother() const { return atol(_curr_node) > 0L; } bool TCoffee_tree::goto_lbrother() { const long pos = atol(_curr_node) - 1; const bool ok = pos >= 0 && _recset.move_to(pos); if (ok) _curr_node.format("%ld", pos); return ok; } bool TCoffee_tree::goto_node(const TString &id) { const long pos = atol(id); const bool ok = _recset.move_to(pos); if (ok) _curr_node = id; return ok; } bool TCoffee_tree::get_description(TString& desc) const { desc = _recset.get("CODTAB").as_string(); return desc.full(); } TFieldtypes TCoffee_tree::get_var(const TString& name, TVariant& var) const { //se il campo richiesto è la descrizione ci vuole quella dell'articolo, non dell'attrezzatura.. //..che risulta vuota if (name == "S0") { TString8 codart = _recset.get("CODTAB[1,5]").as_string(); codart.trim(); var = cache().get(LF_ANAMAG, codart, ANAMAG_DESCR); } else var = _recset.get(name); return var.type(); } const TString& TCoffee_tree::get_codart() const { return _codart; } const TString& TCoffee_tree::get_matricola() const { return _matricola; } const long TCoffee_tree::get_codcf() const { return _codcf; } bool TCoffee_tree::set_clifo(long codcf) { _codcf = codcf; TString query; query << "USE &ATT\nSELECT I0=" << codcf; _recset.set(query); return goto_root(); } bool TCoffee_tree::select_attr(const TString& codart, const TString& matricola) { bool found = false; for (bool ok = _recset.move_first(); ok; ok = _recset.move_next()) { TString8 curr_codart = _recset.get("CODTAB[1,5]").as_string(); curr_codart.trim(); if (curr_codart == codart) { _codart = codart; TString16 curr_matricola = _recset.get("CODTAB[16,30]").as_string(); curr_matricola.trim(); if (curr_matricola == matricola) { _curr_node.format("%ld", _recset.current_row()); found = true; _matricola = matricola; break; } } } return found; } ////////////////////////////////////////////// // Metodi static di ordinamento dello sheet ////////////////////////////////////////////// static int sort_by_data(TSheet_field& s, int r1, int r2) { TToken_string& s1 = s.row(r1); TToken_string& s2 = s.row(r2); const int datacomp_pos = s.cid2index(S_DATA); const TDate d1 = s1.get(datacomp_pos); const TDate d2 = s2.get(datacomp_pos); int cmp = int(d2 - d1); return cmp; } ////////////////////////////////////////////// // Maschera ////////////////////////////////////////////// class TGestione_attrezzature_mask : public TAutomask { bool _sheet_dirty; protected: void fill_sheet_storico(const TString& codattr); bool write(); void save_if_dirty(); virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TGestione_attrezzature_mask(); }; //metodo che riempie il primo sheet delle attrezzature in base ai filtri su cliente/attrezztura void TGestione_attrezzature_mask::fill_sheet_storico(const TString& codattr) { //riempie lo sheet dello storico in base all'attrezzatura scelta nell'albero TString query; query << "USE &HIS"; query << "\nFROM CODTAB=#CODATTR"; query << "\nTO CODTAB=#CODATTR"; TISAM_recordset recset(query); recset.set_var("#CODATTR", codattr); const long recset_items = recset.items(); TSheet_field& sf_righe = sfield(F_STORICO); sf_righe.destroy(); //maschera di sheet TMask& msk = sf_righe.sheet_mask(); //record del recordset con i valori da mettere sulla riga sheet const TRectype& rec = recset.cursor()->curr(); //new style (seza _pos_campo!) for (bool ok = recset.move_first(); ok; ok = recset.move_next()) { TToken_string& row = sf_righe.row(-1); //riga sheet da riempire //per ogni campo della maschera di sheet setta.. //..il valore di quei campi che hanno un field FOR_EACH_MASK_FIELD(msk, i, f) { const short id = f->dlg(); if (id >= 101 && id < 200) { const TFieldref* fr = f->field(); if (fr != NULL) row.add(fr->read(rec), id - 101); } } } //mostra e aggiorna lo sheet ordinato per data (in alto le date maggiori) sf_righe.sort(sort_by_data); sf_righe.show(); sf_righe.force_update(); } //metodo di salvataggio dei record dello sheet bool TGestione_attrezzature_mask::write() { TTreelist_field& tf = (TTreelist_field&)field(F_ATTREZZATURE); TCoffee_tree* ct = (TCoffee_tree*)tf.tree(); if (ct == NULL) return false; const TString& codart = ct->get_codart(); const TString& matricola = ct->get_matricola(); TSheet_field& sf_righe = sfield(F_STORICO); //maschera di riga dello sheet TMask& sm = sf_righe.sheet_mask(); //tabella di modulo con lo storico interventi TModule_table his("&HIS"); TRectype& rec_his = his.curr(); //codice articolo + matricola (prima parte del CODTAB del record di tabmod) TString80 codtab; codtab.format("%-15s%-15s", (const char*)codart, (const char*)matricola); //contatore delle righe che vengono salvate int righe_tot = 0; //giro su tutte le righe dello sheet FOR_EACH_SHEET_ROW(sf_righe, r, riga) { short id = 101; //giro su tutti i campi della riga (che è una sporca token_string) //per prima cosa mette la chiave del record che è così fatta: // codart=codtab[1,5] - matricola=codtab[16,30] - nriga=codtab[31,35] TString80 curr_codtab; curr_codtab.format("%05d", sf_righe.items() - r); curr_codtab.insert(codtab); //azzera il record senno' nei campi vuoti ci metterebbe quelli del record precedente //deve azzerare la tabella, senno' perde il codice modulo HA ed il codice tabella HIS his.zero(); rec_his.put("CODTAB", curr_codtab); FOR_EACH_TOKEN(*riga, str) { const TMask_field& mf = sm.field(id); const TFieldref* fr = mf.field(); //solo i campi della maschera di riga che hanno un FIELD vengono salvati, gli altri si arrangino! if (fr != NULL) { fr->write(str, rec_his); } id ++; } his.rewrite_write(); righe_tot ++; } //compatta le righe dello storico, eliminando quelle in esubero TString query; query << "USE &HIS"; query << "\nFROM CODTAB=#DACODTAB"; TISAM_recordset recset(query); TString80 dacodtab; dacodtab.format("%05d", righe_tot + 1); dacodtab.insert(codtab); recset.set_var("#DACODTAB", dacodtab); //accoppa tutte le righe in esubero dalla tabella &HIS for (bool ok = recset.move_first(); ok; ok = recset.move_next()) recset.cursor()->relation()->remove(); //una volta che ha salvato lo sheet deve risultare immacolato! _sheet_dirty = false; return true; } void TGestione_attrezzature_mask::save_if_dirty() { if (_sheet_dirty && yesno_box(TR("Salvare le modifiche ?"))) write(); } bool TGestione_attrezzature_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { //campi case F_CODCF: if (e == fe_modify) { //albero magico: selezionando un cliente riempie l'albero con tutte le attrezzature del cliente TTreelist_field& tf = (TTreelist_field&)field(F_ATTREZZATURE); TCoffee_tree* ct = (TCoffee_tree*)tf.tree(); if (ct != NULL) { ct->set_clifo(atol(o.get())); tf.win().force_update(); } } break; case F_COD_MATR: if (e == fe_modify) { //albero magico: selezionando un'attrezzatura, si posiziona direttamente sulla giusta posizione nell'albero.. //..(il cliente viene riempito dalla maschera) TTreelist_field& tf = (TTreelist_field&)field(F_ATTREZZATURE); TCoffee_tree* ct = (TCoffee_tree*)tf.tree(); if (ct != NULL) { ct->set_clifo(get_long(F_CODCF)); const TString& codart = get(F_COD_ART); const TString& matricola = get(F_COD_MATR); if (ct->select_attr(codart, matricola)) { tf.select_current(); send_key(K_SPACE, F_ATTREZZATURE, &o); } } } break; case F_ATTREZZATURE: if (e == fe_modify) { TTreelist_field& tf = (TTreelist_field&)field(F_ATTREZZATURE); TCoffee_tree* ct = (TCoffee_tree*)tf.tree(); if (ct != NULL) { TString80 codattr; ct->get_description(codattr); //riempie i campi di intestazione maschera set(F_COD_ART, codattr.left(5)); set(F_COD_MATR, codattr.mid(15,15)); //chiede di salvare le modifiche al cambio attrezzatura save_if_dirty(); //riempie lo sheet fill_sheet_storico(codattr); } } break; case F_STORICO: if (e == se_query_modify || e == se_notify_del) { _sheet_dirty = true; } if (e == se_notify_add) { //quando si aggiunge una riga si deve fare il sorting in modo che venga come prima riga in alto TSheet_field& sf = sfield(o.dlg()); TToken_string& row = sf.row(jolly); //riga corrente appena aggiunta row.add(TDate(TODAY), sf.cid2index(S_DATA)); row.add(get(F_CODCF), sf.cid2index(S_CODCF)); sf.sort(sort_by_data); sf.force_update(); sf.post_select(0); //evidenzia la prima riga } break; //bottoni case DLG_ADD_NEW: if (e == fe_button) { //1) per prima cosa deve controllare che siano pieni i campi chiave della tabella ttrezzature, senno' non puo'.. //...aggiungere una cippa if (get(F_COD_ART).empty() || get(F_COD_MATR).empty()) return warning_box(TR("E' necessario compilare articolo e matricola per aggiungere una nuova attrezzatura!")); TString80 codtab; const TString& codart = get(F_COD_ART); const TString& matricola = get(F_COD_MATR); codtab.format("%-15s%-15s", (const char*)codart, (const char*)matricola); //2) controllo effettiva "nuovezza" dell'attrezzatura.. //...se l'utonto tentasse di inserire come nuova un'attrezzatura già esistente va cazziato! TModule_table tab_att("&ATT"); tab_att.put("CODTAB", codtab); const int err = tab_att.read(); if (err == NOERR) return warning_box(TR("L'attrezzatura con questa matricola esiste gia'!")); //3) invio dati al gestore della tabella &ATT delle attrezzature tramite .ini TFilename trans_ini; trans_ini.temp(NULL, "ini"); TString4 filenumber; filenumber << LF_TABMOD; //i config vanno chiusi tra {} senno' non si riescono ad usare { TConfig ini(trans_ini, "Transaction"); ini.set("Action", "INSERT"); ini.set_paragraph(filenumber); ini.set("CODTAB", codtab); ini.set("I0", get(F_CODCF)); ini.set("D0", TDate(TODAY)); } //invio del config al gestore della tabella &ATT TString80 cmd; cmd << "ha0 -0 &ATT /i" << trans_ini; TExternal_app app(cmd); //4) lettura dell'ini di ritorno compilato ed aggiornamento conseguente di tabella e maschera if (app.run() == NOERR) { //4a) setta sulla maschera i valori di ritorno del .ini (riempiti dal gestore di &ATT) TConfig ini(trans_ini, "Transaction"); if (ini.get("Result") == "OK") { ini.set_paragraph(filenumber); TString80 codtab = ini.get("CODTAB"); codtab.strip("\""); //elimina eventuali " che vengono dall'ini const long codcf = ini.get_long("I0"); const TDate data_storico = ini.get("D0"); //4b) da file ini crea un record nuovo sulla tabella &HIS; se non lo facesse l'albero con le attrezzature non.. //....potrebbe mai vedere la nuova attrezzatura aggiunta; sara' poi l'albero stesso ad occuparsi dello sheet TModule_table tab_his("&HIS"); TString80 his_codtab = codtab; his_codtab << "00001"; //l'attrezzatura è nuova! deve essere il primo record tab_his.put("CODTAB", his_codtab); tab_his.put("I0", codcf); tab_his.put("D0", data_storico); int can_write = tab_his.write(); if (can_write != NOERR) return warning_box(TR("Impossibile aggiungere l'attrezzatura! Risulta gia' presente.")); set(F_CODCF, codcf, true); set(F_COD_ART, codtab.left(5)); set(F_COD_MATR, codtab.mid(15,15), true); } } } break; case DLG_SAVEREC: if (e == fe_button && check_fields()) { write(); } break; case DLG_CANCEL: if (e == fe_button && jolly == 0) //il jolly=0 significa che si riferisce alla maschera principale!.. { //..se non ci fosse azzererebbe tutto anche quando si fa annulla sulla maschera di riga! //nel caso l'utonto clicchi su ANNULLA dopo aver fatto modifiche sara' meglio chiedere conferma se le vuole mantenere save_if_dirty(); //azzera i campi della maschera reset(); TTreelist_field& tf = (TTreelist_field&)field(F_ATTREZZATURE); TCoffee_tree* ct = (TCoffee_tree*)tf.tree(); if (ct != NULL) { ct->set_clifo(0L); tf.win().force_update(); } return false; } break; case DLG_QUIT: if (e == fe_button) { //nel caso l'utonto clicchi su FINE dopo aver fatto modifiche sara' meglio chiedere conferma se le vuole mantenere save_if_dirty(); } break; default: break; } return true; } TGestione_attrezzature_mask::TGestione_attrezzature_mask() : TAutomask("ha3900a") { //assegna l'albero del caffe' al campo di tipo albero sulla maschera TTreelist_field& tf = (TTreelist_field&)field(F_ATTREZZATURE); TCoffee_tree* ct = new TCoffee_tree; tf.set_tree(ct); TSheet_field& sf_storico = sfield(F_STORICO); sf_storico.set_append(false); //inizializza lo "sporcatore" dello sheet _sheet_dirty = false; } ////////////////////////////////////////////// // Applicazione ////////////////////////////////////////////// class TGestione_attrezzature : public TSkeleton_application { virtual void main_loop(); }; void TGestione_attrezzature::main_loop() { TGestione_attrezzature_mask mask; while (mask.run() == K_ENTER) { } } int ha3900(int argc, char* argv[]) { TGestione_attrezzature app; app.run(argc, argv, TR("Gestione storico attrezzature")); return 0; }