#include #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; long _progressivo; TString8 _codart; TString16 _matricola, _cespite; 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); } //mai dimenticarsi la moka! public: bool set_clifo(long codcf); bool select_attr(const TString& codart, const long progressivo); const long get_codcf() const; const TString& get_codart() const; const long get_progressivo() const; const TString& get_matricola() const; const TString& get_cespite() 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 == "S10") { 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 long TCoffee_tree::get_progressivo() const { return _progressivo; } const TString& TCoffee_tree::get_matricola() const { return _matricola; } const TString& TCoffee_tree::get_cespite() const { return _cespite; } 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 long progressivo) { 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; const long curr_progressivo = _recset.get("CODTAB[6,12]").as_int(); if (curr_progressivo == progressivo) { _curr_node.format("%ld", _recset.current_row()); found = true; _progressivo = progressivo; _matricola = _recset.get("S0[6,20]").as_string(); _cespite = _recset.get("S1").as_string(); 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); //prima ordina per data dalla piu' recente alla piu' antica.. 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); //..poi per tipo (dal vuoto in avanti if (cmp == 0) { const int tipo_pos = s.cid2index(S_TIPO); const char c1 = s1.get_char(tipo_pos); const char c2 = s2.get_char(tipo_pos); cmp = int (c1 - c2); } 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(); const long present_clifo = get_long(F_CODCF); //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 const long line_clifo = rec.get_long("I0"); //se il clifo presente sulla riga e' diverso da quello attuale la riga assumera' un vago colore pervinca if (line_clifo != present_clifo) sf_righe.set_back_and_fore_color(DISABLED_BACK_COLOR, DISABLED_COLOR, sf_righe.items()-1); //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 long progressivo = ct->get_progressivo(); 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 + progressivo (prima parte del CODTAB del record di tabmod) TString80 codtab; codtab.format("%-5s%07d", (const char*)codart, progressivo); //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] - progressivo=codtab[6,12] - 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); //poi quelli specifici della riga 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=#DAATTR"; query << "\nTO CODTAB=#AATTR"; TISAM_recordset recset(query); TString80 daattr, aattr; daattr.format("%s%05d", (const char*)codtab, righe_tot + 1); aattr.format("%s%05d", (const char*)codtab, 99999); recset.set_var("#DAATTR", daattr); recset.set_var("#AATTR", aattr); //accoppa tutte le righe in esubero dalla tabella &HIS const long recset_items = recset.items(); 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_PROGRESSIVO: 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_CODART); const long progressivo = get_long(F_PROGRESSIVO); if (ct->select_attr(codart, progressivo)) { 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_CODART, codattr.left(5)); set(F_PROGRESSIVO, codattr.mid(5,7)); check_field(F_CODART); //chiede di salvare le modifiche al cambio attrezzatura save_if_dirty(); //seleziona sull'albero ct->select_attr(get(F_CODART), get_long(F_PROGRESSIVO)); //la select_attr fa sapere all'albero matricola e cespite -> si possono mettere sulla maschera) set(F_MATRICOLA, ct->get_matricola()); set(F_CESPITE, ct->get_cespite()); //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_CODART).empty() || get(F_PROGRESSIVO) <= 0L) return warning_box(TR("E' necessario compilare articolo e progressivo per aggiungere una nuova attrezzatura!")); TString80 codtab; const TString& codart = get(F_CODART); const long progressivo = get_long(F_PROGRESSIVO); codtab.format("%-5s%07d", (const char*)codart, progressivo); //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 questi articolo e progressivo 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)); TString matricola; matricola.format("%-5s%-15s", (const char*)get(F_CODART), (const char*)get(F_MATRICOLA)); ini.set("S0", matricola); ini.set("S1", get(F_CESPITE)); } //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"); const TString& cespite = ini.get("S1"); const TString& full_matricola = ini.get("S0"); const TString16 matricola = full_matricola.mid(5,15); //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); tab_his.put("S2", matricola); tab_his.put("S1", cespite); 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_CODART, codtab.left(5), true); set(F_PROGRESSIVO, codtab.mid(5,7), true); set(F_MATRICOLA, matricola); set(F_CESPITE, cespite); } } } 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); //se non facesse questa precisazione non potrebbe inserire le righe in alto 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; }