#include #include #include #include #include #include "../cg/cglib01.h" #include "lvcondv.h" #include "lvrcondv.h" #include "lvlib.h" #include "../mg/clifogiac.h" #include "../ve/rcondv.h" #include "lv0400.h" //LV_NEW_CONTRACT: metodo generale utilizzato sia nella maschera che nell'applicazione //che restituisce il primo codcont libero long lv_new_contract(long cliente, int indsped) { //leggo dalla configurazione se la numerazione dei contratti //è sequenziale per ditta o per cliente long codcont = 0; if (ini_get_bool(CONFIG_DITTA, "lv", "UniCont")) //se la numerazione è per ditta, cerco in tutto LVCONDV il codcont più grande { TISAM_recordset recset ("USE LVCONDV"); for (bool ok=recset.move_first(); ok; ok = recset.move_next()) { const long codice=recset.get("CODCONT").as_int(); if (codice>codcont) codcont=codice; } } else //altrimenti cerco il codcont più grande di un determinato cliente { TString query; query<<"USE LVCONDV\n" <<"FROM CODCF=#CLIENTE\n" <<"TO CODCF=#CLIENTE\n"; TISAM_recordset recset (query); recset.set_var("#CLIENTE",cliente); if (recset.move_last()) codcont=recset.get("CODCONT").as_int(); } codcont++; return codcont; } ////////////////////////////// //// TCONTRATTI_MSK //// ////////////////////////////// //classe TContratti_msk class TContratti_msk: public TAutomask { long _post_contr; TString80 _artrig; int _riga; protected: void azzera_conguaglio(); bool on_art_select(TField_event e); virtual void on_idle(); virtual bool on_field_event(TOperable_field& o,TField_event e,long jolly); public: int get_riga(); bool set_riga(const int val); TContratti_msk(); }; //AZZERA_CONGUAGLIO: metodo che azzera tutti conguagli di un contratto dopo aver dato la conferma void TContratti_msk::azzera_conguaglio() { TLaundry_contract cont(get_long(F_CODCF), get_long(F_CODCONT)); TSheet_field& sheet = sfield(F_RIGHE); FOR_EACH_SHEET_ROW(sheet, r, row) row->add(0L, sheet.cid2index(S_CONG)); sheet.force_update(); } //ON_ART_SELECT: metodo che riempie i campi delle dotazioni e del consegnato sullo sheet e sulla maschera //e riporta i dati dello sheet nel dettaglio sulla maschera (sotto lo sheet) bool TContratti_msk::on_art_select(TField_event e) { //dallo sheet identifico la riga selezionata e estraggo i dati di interesse TSheet_field& ss = sfield(F_RIGHE); TToken_string& row = ss.row(ss.selected()); const TString80 codart(row.get(ss.cid2index(S_CODART))); const long codcf = get_long(F_CODCF); const int indsped = get_int(F_INDSPED); //instanzio un TArticolo_lavanderie per poter recuperare i dati di interesse TArticolo_lavanderie& artrec = cached_article_laundry(codart, 'C', codcf, indsped); //setto datasc a oggi e fisso l'anno esercizio TDate datasc(TODAY); const int annoes = esercizi().date2esc(datasc); //estraggo il record corrispondente su LF_CLIFOGIAC const TRecmag_lavanderie& reclav = artrec.find_rec(annoes); //recupero la maschera di riga TMask& rowmask = ss.sheet_mask(); if (!ini_get_bool(CONFIG_DITTA, "lv", "Qtamodi")) { field(F_DOTTMP).disable(); rowmask.field(S_DOTIN).disable(); rowmask.field(S_DOTOD).disable(); rowmask.field(S_DOTTMP).disable(); } if (rowmask.get(S_UM).blank() && artrec.um().rows() > 0) { const TString& um = artrec.um()[1].get(UMART_UM); rowmask.set(S_UM, um); } //se esiste il record su LF_CLIFOGIAC, recupero l'unità di misura dalla riga dello sheet selezionata //e setto i campi delle dotazioni e dei consegnati ai valori corretti riportati alla giusta unità di misura real dotin = ZERO; real dotod = ZERO; real dottmp = ZERO; real consyear = ZERO; real consmonth = ZERO; if (!reclav.empty()) { if (rowmask.get(S_DOTIN).blank()) { //calcolo dotazione iniziale, scritta sia sulla maschera che sullo sheet dotin = reclav.get_real(CLIFOGIAC_DOTIN); //calcolo dotazione odierna, scritta sia sulla maschera che sullo sheet dotod = reclav.get_real(CLIFOGIAC_DOTOD); //calcolo dotazione temporanea, scritta sia sulla maschera che sullo sheet dottmp = reclav.get_real(CLIFOGIAC_DOTTM); } //calcolo consegnato anno, scritto sia sulla maschera che sullo sheet consyear = reclav.get_real("CONSANNO"); //calcolo consegnato mese, scritto sia sulla maschera che sullo sheet consmonth = reclav.get_real("CONSMESE"); } if (rowmask.get(S_DOTIN).blank()) { rowmask.set(S_DOTIN, dotin); rowmask.set(S_DOTOD, dotod); rowmask.set(S_DOTTMP, dottmp); } rowmask.set(S_CONSANNO, consyear); rowmask.set(S_CONSMESE, consmonth); //instanzio una cache sull'anagrafica di magazzino //per leggere il valore di PPCONF corretto e sempre aggiornato const TRectype& anamag = cache().get(LF_ANAMAG, codart); int ppconf = anamag.get_int(ANAMAG_PPCONF); rowmask.set(S_PPCONF, ppconf); row.add(ppconf, ss.cid2index(S_PPCONF)); //ciclo i dati di interesse della riga selezionata nel dettaglio //sulla maschera principale if (e != fe_init) for (short id = F_CODART; id <= F_CODART + 36; id++) { const int pos = id2pos(id); if (pos > 0) { TMask_field& f = fld(pos); const TString& oldval = f.get(); const char* newval = row.get(ss.cid2index(id - 400)); if (oldval != newval) { f.set(newval); if (f.is_kind_of(CLASS_LIST_FIELD)) f.on_hit(); } } } if (ppconf <= 0) { set(F_CALCCONS, "0"); disable(F_CALCCONS); rowmask.set(S_CALCCONS, "0"); rowmask.field(S_CALCCONS).disable(); rowmask.field(S_CONG).disable(); } else { enable(F_CALCCONS); rowmask.field(S_CALCCONS).enable(); rowmask.field(S_CONG).enable(); TToken_string row = ss.row(ss.selected()); } return true; } //ON_IDLE: ridefinizione del metodo on_idle() delle TAutomask per settare il focus //nel posto desiderato void TContratti_msk::on_idle() { TAutomask::on_idle(); TSheet_field& s = sfield(F_RIGHE); //se riconosco in quale riga devo andare, setto il focus su quella riga if (_riga >= 0) { field(F_RIGHE).set_focus(); s.set_focus_cell_id(_riga, S_CODART); _riga = -1; } else if (_post_contr > 0) { set(F_CODCONT, _post_contr); _post_contr = 0; efield(F_CODCONT); } } //ON_FIELD_EVENT: definizione del metodo che setta i comportamenti dei vari campi della mashera bool TContratti_msk::on_field_event(TOperable_field& o,TField_event e,long jolly) { switch(o.dlg()) { case F_CODCF: case F_RICALT: //se sono in query_mode e se il campo risulta pieno e modificato, //e il codcont vuoto, allora riempio in automatico l'indirizzo di spedizione //e propongo il contratto valido nella giornata di oggi if (query_mode()) { if (e == fe_modify && !o.empty() && efield(F_CODCONT).empty()) { const long codcf = atol(o.get()); const int indsped = get_int(F_INDSPED); const TDate oggi(TODAY); _post_contr = lv_find_contract(codcf, indsped, oggi); field(F_RAGSOC).set_focus(); } } break; case F_RIGHE: //se lo sheet ha ricevuto un se_enter, allora aggiorno i campi del dettaglio sulla mashera principale if (e == se_enter) { TSheet_field& ss = (TSheet_field&)o; TToken_string& row = ss.row(ss.selected()); for (short id = F_CODART; id <= F_CODART+35; id++) { const int pos=id2pos(id); if (pos>0) { TMask_field& f = fld(pos); const TString& oldval = f.get(); const char* newval = row.get(ss.cid2index(id - 400)); if (oldval != newval) { f.set(newval); if (f.is_kind_of(CLASS_LIST_FIELD)) f.on_hit(); } f.set_dirty(false); } } //questo pezzo serve per gestire enable e disable dei campi in modo corretto //senza massage in maschera, sia sullo sheet che sul dettaglio TMask& rowmask = ss.sheet_mask(); if (field(F_PPCONF).empty()) { set(F_CALCCONS, "0"); disable(F_CALCCONS); rowmask.set(S_CALCCONS, "0"); rowmask.field(S_CALCCONS).disable(); rowmask.field(S_CONG).disable(); } else { enable(F_CALCCONS); rowmask.field(S_CALCCONS).enable(); rowmask.field(S_CONG).enable(); } _artrig = row.get(0); //salvo nella variabile globale il codart della riga selezionata } //se ho cancellato una riga dello sheet, chiedo conferma che sia effettivamente quello che si vuole fare if (e == se_query_del) { TSheet_field& ss = (TSheet_field&)o; TToken_string& row = ss.row(ss.selected()); const TString codart = row.get(ss.cid2index(S_CODART)); const long dotin = row.get_long(ss.cid2index(S_DOTIN)); if (dotin > 0) { warning_box("Impossibile cancellare l'articolo %s perchè ha una dotazione iniziale non nulla", (const char*) codart); return false; } const TDate oggi(TODAY); const int danno = oggi.year() - 1; const int aanno = oggi.year() + 1; //controllo articolo in buoni di consegna const TString8 tipoela = ini_get_string(CONFIG_DITTA, "lv", "FatDif"); const TString4 codnumbc = ini_get_string(CONFIG_DITTA, "lv", "NUM_GEN"); const TString4 tipodocbc = ini_get_string(CONFIG_DITTA, "lv", "TIPODOC_GEN"); const char statofbc = cache().get("%ELD", tipoela, "S4").left(0)[0]; TString query; query << "USE RDOC KEY 5\n" << "SELECT (DOC.TIPODOC=\"" << tipodocbc << "\")&&(DOC.STATO<\"" << statofbc << "\")\n" << "JOIN DOC INTO PROVV=PROVV ANNO=ANNO CODNUM=CODNUM NDOC=NDOC\n" << "FROM CODART=\"" << codart << "\" ANNO=" << danno << "CODNUM=\"" << codnumbc << "\"\n" << "TO CODART=\"" << codart << "\" ANNO=" << danno << "CODNUM=\"" << codnumbc << "\"\n"; TISAM_recordset bcon(query); if(bcon.items() > 0) { TString str; str << "Non è possibile cancellare dal contratto l'articolo " << codart << "in quanto è presente su " << bcon.items() << " ancora da fatturare"; warning_box(str); return false; } //controllo articolo in buoni di ritiro const TString4 codnumbr = ini_get_string(CONFIG_DITTA, "lv", "NUM_RIT", NULL, 0); const TString4 tipodocbr = ini_get_string(CONFIG_DITTA, "lv", "TIPODOC_RIT", NULL, 0); const char statofbr = cache().get("%TIP", tipodocbr, "S2").mid(1,1)[0]; query.cut(0); query << "USE RDOC KEY 5\n" << "SELECT (DOC.TIPODOC=\"" << tipodocbr << "\")&&(DOC.STATO<\"" << statofbr << "\")\n" << "JOIN DOC INTO PROVV=PROVV ANNO=ANNO CODNUM=CODNUM NDOC=NDOC\n" << "FROM CODART=\"" << codart << "\" ANNO=" << danno << "CODNUM=\"" << codnumbr << "\"\n" << "TO CODART=\"" << codart << "\" ANNO=" << danno << "CODNUM=\"" << codnumbr << "\"\n"; TISAM_recordset brit(query); if(brit.items() > 0) { TString str; str << "Non è possibile cancellare dal contratto l'articolo " << codart << "in quanto è presente su " << brit.items() << " ancora da evadere"; warning_box(str); return false; } //controllo articolo in buoni di prelievo const TString4 codnumbp = ini_get_string(CONFIG_DITTA, "lv", "NUM_PRE", NULL, 0); const TString4 tipodocbp = ini_get_string(CONFIG_DITTA, "lv", "TIPODOC_PRE", NULL, 0); const char statofbp = cache().get("%TIP", tipodocbp, "S2").mid(2,1)[0]; query.cut(0); query << "USE RDOC KEY 5\n" << "SELECT (DOC.TIPODOC=\"" << tipodocbp << "\")&&(DOC.STATO<\"" << statofbp << "\")\n" << "JOIN DOC INTO PROVV=PROVV ANNO=ANNO CODNUM=CODNUM NDOC=NDOC\n" << "FROM CODART=\"" << codart << "\" ANNO=" << danno << "CODNUM=\"" << codnumbp << "\"\n" << "TO CODART=\"" << codart << "\" ANNO=" << danno << "CODNUM=\"" << codnumbp << "\"\n"; TISAM_recordset bpre(query); if(bpre.items() > 0) { TString str; str << "Non è possibile cancellare dal contratto l'articolo " << codart << "in quanto è presente su " << bpre.items() << " ancora da evadere"; warning_box(str); return false; } if (!yesno_box("Si desidera veramente cancellare l'articolo %s",(const char*) codart)) return false; } if (e == se_leave || e == se_notify_modify) _artrig.cut(0); break; case F_TIPOCAN: case F_NOLCICTE: { //copio il valore del campo in questione della testata su tutte le righe se F_TIPOCAN vale //% su valore convenzionale per cliente, altrimente lascio quello che c'è const int tipocan = atoi(get(F_TIPOCAN)); if (e == fe_modify || e == fe_init) { TSheet_field& ss = sfield(F_RIGHE); //recupero le posizioni dei campi che devo modificare const int pos_tipoforf = ss.cid2index(S_TIPOFORF); const int pos_nolcic = ss.cid2index(S_NOLCIC); const int pos_vcartcli = ss.cid2index(S_VCARTCLI); const char nolcicte = field(F_NOLCICTE).get()[0]; if (tipocan == 2) { FOR_EACH_SHEET_ROW(ss, r, row) { TToken_string& riga = ss.row(r); //scrivo i valori alle posizioni corrette riga.add(4, pos_tipoforf); riga.add(nolcicte, pos_nolcic); riga.add('C', pos_vcartcli); //disabilito le celle interessate ss.disable_cell(r, pos_tipoforf); ss.disable_cell(r, pos_nolcic); ss.disable_cell(r, pos_vcartcli); } field(F_TIPOFORF).disable(); field(F_NOLCIC).disable(); } else { FOR_EACH_SHEET_ROW(ss, r, row) { TToken_string& riga = ss.row(r); //abilito le celle alle posizioni corrette ss.enable_cell(r, pos_tipoforf); ss.enable_cell(r, pos_nolcic); ss.enable_cell(r, pos_vcartcli); if (riga.get_int(pos_tipoforf) == 4) riga.add('A', pos_vcartcli); } field(F_TIPOFORF).enable(); field(F_NOLCIC).enable(); } ss.force_update(); if (ss.items() > 0) ss.select(0); // Forza aggiornamento del dettaglio di riga (saponetta) } } break; case F_TIPOFORF: { //se questo campo risulta modificato, lo copio in alto e forzo l'update if (e == fe_modify/* || e == fe_init*/) { TSheet_field& ss = sfield(F_RIGHE); const int sel = ss.selected(); if (sel >= 0) { TToken_string& riga = ss.row(sel); riga.add(o.get(), ss.cid2index(S_TIPOFORF)); if (ss.mask().get_int(F_TIPOCAN) != 2) { riga.add('A', ss.cid2index(S_VCARTCLI)); ss.disable_cell(sel, ss.cid2index(S_VCARTCLI)); } ss.force_update(sel); } } } break; case F_RITAUDTTMPRIG: { //obbligo a settare il flag prima in testata, altrimenti non lo lascio settare per le righe if (e == fe_modify || e == fe_init) { if (o.get()[0] == 'X') { if (field(F_RITAUDTTMP).get()[0] != 'X') { warning_box("E' necessario prima attivare il ritiro automatico della dotazione temporanea in testata"); o.set(""); } } if (e == fe_modify) { TSheet_field& ss = sfield(F_RIGHE); const int sel = ss.selected(); if (sel >= 0) { const int index = ss.cid2index(S_RITAUDTTMP); const char* oldval = ss.row(sel).get(index); const TString& newval = o.get(); if (newval != oldval) { ss.sheet_mask().set(S_RITAUDTTMP,newval); ss.row(sel).add(newval,index); ss.force_update(sel); } } } } } break; case F_CALCCONS: //questo pezzo gestisce in maniera corretta gli enable e disable del campo conguaglio sullo sheet if (e == fe_modify) { TSheet_field& ss = sfield(F_RIGHE); const int sel = ss.selected(); if (sel >= 0) { TToken_string& riga = ss.row(sel); riga.add(o.get(), ss.cid2index(F_CALCCONS)); if (riga.get_long(ss.cid2index(S_PPCONF)) <= 0) ss.disable_cell(sel, ss.cid2index(S_CONG)); else { if (atoi(o.get()) == 1) ss.enable_cell(sel, ss.cid2index(S_CONG)); else ss.disable_cell(sel, ss.cid2index(S_CONG)); } } ss.force_update(sel); } break; case S_CODART: if (!o.empty()) //se il campo risulta pieno { if (e == fe_modify) //e se risulta modificato { const TString& codart = o.get(); TSheet_field& ss = sfield(F_RIGHE); TMask& m = o.mask(); // maschera di riga! const int rigasel = ss.selected(); const TString80 art = o.get(); FOR_EACH_SHEET_ROW(ss, r, riga) { if(r == rigasel) continue; const TString80 tmp = riga->get(0); if(tmp == art) { TString msg; msg << "L'articolo " << codart << " è già presente a contratto e non è possibile reinserirlo."; warning_box(msg); m.set(S_CODART, _artrig); TToken_string& row = ss.row(rigasel); row.add(_artrig, 0); ss.force_update(rigasel); return false; } } //PROPONI PREZZO TToken_string key; key.add('C'); key.add(field(F_CODCF).get()); const TRectype& cfven = cache().get(LF_CFVEN, key); bool trvlst = false; if (!cfven.empty()) { //se è settata la categoria merceologica, leggo sia il listino che la cat merc, altrimenti solo il listino TString8 codlis = cfven.get(CFV_CODLIST); TString8 catven; if (!ini_get_bool(CONFIG_DITTA,"ve", "GESLISCV")) catven = ""; else catven = cfven.get(CFV_CATVEN); //cerco il prezzo sul listino key.cut(0); key.add('L'); //tipo key.add(catven); //catven key.add(""); //tipocf key.add(""); //codcf key.add(codlis); //codlis key.add('A'); //tiporiga key.add(codart); //codriga key.add(""); //um key.add(""); //nscagl const TRectype& rcondv = cache().get(LF_RCONDV, key); if (!rcondv.empty()) { m.set(S_PREZZOST, rcondv.get_real(RCONDV_PREZZO)); trvlst = true; } } real prezzo; //se non ho trovato un listino, o se non c'è un listino impostato //propongo come prezzo il valore convenzionale if (!trvlst) { key.cut(0); key.add(codart); key.add(1); const TRectype& umart = cache().get(LF_UMART, key); m.set(S_PREZZOST, umart.get_real(UMART_PREZZO)); if (umart.get(UMART_PREZZO).full()) { prezzo = umart.get_real(UMART_PREZZO); trvlst = true; } } if (!trvlst && insert_mode()) warning_box(TR("Non è stato trovato nessun prezzo da proporre")); //se ho scritto un articolo diverso da quello che esisteva prima //e se si desidera veramente modificarlo, allora permetto la modifica //e forzo l'updatre della riga, altrimenti riscrivo l'articolo che c'era prima //e lascio tutto invariato if (codart != _artrig) { if (_artrig.empty() || noyes_box("Si desidera veramente modificare l'articolo %s",(const char*) _artrig)) _artrig = codart; else m.set(S_CODART, _artrig); TToken_string& row = ss.row(ss.selected()); row.add(_artrig, ss.cid2index(S_CODART)); row.add(prezzo.string(), ss.cid2index(S_PREZZOST)); ss.force_update(ss.selected()); } //se all'articolo è associata un'unità di misura, la propongo //in automatico e richiamo il metodo (); altrimenti lo richiamo //solo se è arrivato un fe_init al campo on_art_select(e); } else if (e == fe_init && (o.get() != _artrig)) on_art_select(e); } break; case S_CONG: case S_DOTIN: case S_DOTOD: case S_DOTTMP: { if (e == fe_modify) { TString str; str << "ATTENZIONE: Una quantità risulta modificata a mano; dopo questa operazione i totali dei movimenti" << "di magazzino potrebbero non corrispondere ai numeri qui salvati"; warning_box(str); TSheet_field& ss = sfield(F_RIGHE); TMask& m = o.mask(); // maschera di riga! const int rigasel = ss.selected(); const long qta = o.get_long(); m.set(o.dlg(), qta); TToken_string& row = ss.row(rigasel); row.add(qta, ss.cid2index(o.dlg())); //ss.force_update(rigasel); } } break; case DLG_PLANNING: //se viene premuto il bottone "Giri", lancia lv0500 (generatore automatico dei giri) if (e == fe_button && edit_mode()) { TRelation_application& app = (TRelation_application&) main_app(); app.get_relation()->read(_isequal,_unlock); TString str; str << "lv0 -4 " << get(F_CODCF) << " " << get(F_CODCONT); TExternal_app planning(str); planning.run(); app.get_relation()->read(_isequal,_lock); } break; case DLG_NEWREC: if (e == fe_button) { //se sono in edit_mode, forzo l'uscita dal contratto attuale if (edit_mode()) { send_key(K_ESC, 0); return false; } //se sono in query_mode e esiste già un cliente selzionato, allora richiamo il metodo LV_NEW_CONTRACT() //e calcolo il primo codcont libero proponendolo in automatico if (query_mode()) { const long codcf = get_long(F_CODCF); if (codcf > 0) { const int indsped = get_int(F_INDSPED); const long codcont = lv_new_contract(codcf, indsped); if (codcont > 0) set(F_CODCONT, codcont); } } } break; case DLG_RESET: if (e == fe_button && yesno_box(TR("Si è sicuri di voler azzerare i conguagli di questo contratto?"))) azzera_conguaglio(); default: //se sto modificando un campo con indice > 500 e diverso da F_CAUSLAVDESCRIG //allora forzo l'update dello sheet sulla riga selezionata if (e == fe_modify && is_running() && o.dlg() > 500/*&& o.dlg() != F_CAUSLAVDESCRIG*/) { TSheet_field& ss = sfield(F_RIGHE); const int sel = ss.selected(); if (sel >= 0) { const short rowid = o.dlg() - 400; const int index = ss.cid2index(rowid); const char* oldval = ss.row(sel).get(index); const TString& newval = o.get(); if (newval != oldval) { ss.sheet_mask().set(rowid,newval); ss.row(sel).add(newval,index); ss.force_update(sel); } } } break; } return true; } int TContratti_msk::get_riga() { return _riga; } bool TContratti_msk::set_riga(const int val) { _riga = val; return true; } //Costruttore; nasconde o mostra il campo F_INDSPED a seconda di cosa è scritto in configurazione TContratti_msk::TContratti_msk():TAutomask("lv0400a"), _post_contr(0) { if (!ini_get_bool(CONFIG_DITTA, "lv", "Useindsp")) field(F_INDSPED).hide(); } ////////////////////////////// //// TCONTRATTI_APP //// ////////////////////////////// //classe TContratti_app class TContratti_app: public TRelation_application { TContratti_msk* _msk; TRelation* _rel; TString80 _codart; private: void save_rows(const TMask& m); TString build_query(const TMask& m) const; int find_art(TSheet_field& s,const TString& art) const; protected: virtual TMask* get_mask (int mode) {return _msk; } virtual TRelation* get_relation() const {return _rel;} virtual bool user_create(); virtual bool user_destroy(); virtual void on_config_change(); //METODO VUOTO virtual bool get_next_key(TToken_string& key); //METODO MAI UTILIZZATO? virtual int read(TMask& m); virtual int write(const TMask& m); virtual int rewrite(const TMask& m); virtual bool protected_record(TRectype & rec); //METODO MAI UTILIZZATO? virtual bool remove(); virtual void init_query_mode(TMask& m); virtual void init_insert_mode(TMask& m); virtual void init_modify_mode(TMask& m); bool elimina_planning(const long& codcont, const long& codcf) const; bool kill_planning (TISAM_recordset& selrighe) const; }; //SAVE_ROWS: questo metodo salva effettivamente le righe vislualizzate sullo sheet sul file //LF_LVRCONDV e aggiorna e/o aggiunge record su LF_CLIFOGIAC void TContratti_app::save_rows(const TMask& m) { //instanzio un TISAM_recordset sulle righe contratto TISAM_recordset righeset(build_query(m)); //instazio un TLocalisamfile partendo dal recordset che ho appena creato //(cioè su LF_LVRCONDV) TLocalisamfile& file = righeset.cursor()->file(); //recupero lo sheet TSheet_field& righe = m.sfield(F_RIGHE); //scorro tutte le righe contratto e elimino tutte quelle che non ci sono più sullo sheet for (bool ok = righeset.move_first(); ok; ok = righeset.move_next()) { const TString& art = righeset.get("CODART").as_string(); if (find_art(righe, art) < 0) file.remove(); } //instanzio un TLocalisamfile su LF_CLIFOGIAC TLocalisamfile magcli(LF_CLIFOGIAC); //setto alcune variabili di interesse const TDate oggi(TODAY); const int year = oggi.year(); const long clifo = m.get_long(F_CODCF); const int indsp = m.get_int(F_INDSPED); TEsercizi_contabili esc; const int last_esc = esc.last(); const int pred_esc = esc.pred(last_esc); const bool pred_esc_chiuso = esc[pred_esc].chiusura_mag().ok(); const int esercizio = (pred_esc_chiuso ? last_esc : pred_esc); //recupero la maschera di riga TMask& msk = righe.sheet_mask(); //per ogni riga dello sheet FOR_EACH_SHEET_ROW(righe, r, row) { file.zero(); file.put("CODCF",clifo); file.put("CODCONT",m.get(F_CODCONT)); //per ogni campo della maschera scrivi setta all'interno del record corrente di file //il valore di quei campi che hanno un field FOR_EACH_MASK_FIELD(msk,i,f) { const TFieldref* fr = f->field(); if (fr != NULL) { const int pos = righe.cid2index(f->dlg()); fr->write(row->get(pos), file.curr()); } } //leggo il codart const TString80 codart = row->get(righe.cid2index(S_CODART)); if (codart.full()) { file.rewrite_write(); //se il codart è pieno e le quantità sono modificabili (da configurazione) if (ini_get_bool(CONFIG_DITTA, "lv", "Qtamodi")) { TArticolo_lavanderie& artrec = cached_article_laundry(codart, 'C', clifo, indsp); TRecmag_lavanderie& reclav = (TRecmag_lavanderie&)artrec.find_rec(esercizio); TRecmag_lavanderie& reclav_prec = (TRecmag_lavanderie&)artrec.find_rec(pred_esc); //gestione LF_CLIFOGIAC if(reclav.empty()) { reclav.put(CLIFOGIAC_TIPOCF, 'C'); reclav.put(CLIFOGIAC_CODCF, clifo); reclav.put(CLIFOGIAC_ANNOES, esercizio); reclav.put(CLIFOGIAC_INDSPED, indsp); reclav.put(CLIFOGIAC_CODART, codart); reclav.put(CLIFOGIAC_NRIGA, 1); } //riscrivo la dotazione iniziale convertita nell'unità di misura principale real dotin = row->get(righe.cid2index(S_DOTIN)); if(!pred_esc_chiuso) dotin -= reclav_prec.get_real(CLIFOGIAC_DOTIN); reclav.put(CLIFOGIAC_DOTIN, dotin); //riscrivo la dotazione odierna convertita nell'unità di misura principale real dotod = row->get(righe.cid2index(S_DOTOD)); if(!pred_esc_chiuso) dotod -= reclav_prec.get_real(CLIFOGIAC_DOTOD); reclav.put(CLIFOGIAC_DOTOD, dotod); //riscrivo la dotazione temporanea convertita nell'unità di misura principale real dottm = row->get(righe.cid2index(S_DOTTMP)); if(!pred_esc_chiuso) dottm -= reclav_prec.get_real(CLIFOGIAC_DOTTM); reclav.put(CLIFOGIAC_DOTTM, dottm); //riscrivo il consegnato anno convertito nell'unità di misura principale const real conan = row->get(righe.cid2index(S_CONSANNO)); reclav.put(CLIFOGIAC_CONSANNO, conan); reclav.rewrite_write(magcli); } } } //fine FOR_EACH_ROW } //BUILD_QUERY: metodo che crea la query sulle righe contratti //recuperando i dati di interesse dalla maschera TString TContratti_app:: build_query(const TMask& m) const { TString query = ""; query << "USE LVRCONDV\n" << "FROM CODCF=" << m.get(F_CODCF) << " CODCONT=" << m.get(F_CODCONT) << "\n" << "TO CODCF=" << m.get(F_CODCF) << " CODCONT=" << m.get(F_CODCONT); return query; } //FIND_ART: metodo che restituisce l'indice della riga dello sheet che contiene //l'articolo desiderato (-1 se non lo trova) int TContratti_app::find_art(TSheet_field& s, const TString& art) const { int r = -1; //scorro le righe dello sheet partendo dall'ultima for (r = s.items()-1 ; r>=0 ; r--) { const char* codart = s.row(r).get(0); if (art == codart) break; } return r; } //USER_CREATE: metodo che crea TRelation e TContratti_msk solo se si è in un esercizio valido //e che setta i comportamenti sulle righe aggiunte agli sheet bool TContratti_app:: user_create() { //se gli sono stati passati più parametri, allora setto la variabile globale _codart... //...con il parametro desiderato, se no lo setto a stringa vuota if (argc() > 2) { _codart = argv(3); _codart.ltrim(2); } else _codart = ""; const TDate oggi(TODAY); if (esercizi().date2esc(oggi) == 0) return error_box("Attenzione non esiste l'esercizio corrispondente al %s", oggi.string()); _rel=new TRelation (LF_LVCONDV); _msk= new TContratti_msk; _msk->set_riga(-1); TSheet_field& ss = _msk->sfield(F_RIGHE); ss.set_auto_append(false); ss.set_append(false); return true; } //USER_DESTROY: metodo che distrugge le variabili globali alla fine dell'esecuzione bool TContratti_app:: user_destroy() { delete _msk; delete _rel; return true; } //ON_CONFIG_CHANGE: per adesso un semplice segnaposto void TContratti_app:: on_config_change() { } //GET_NEXT_KEY: metodo che restituisce la chiave di ricerca sui contratti prendendo il prossimo codcont libero bool TContratti_app:: get_next_key(TToken_string& key) { const long cliente=_msk->get_long(F_CODCF); if (cliente <= 0) return false; key.add(F_CODCF); key.add(cliente); key.add(F_CODCONT); long codcont= lv_new_contract(cliente, _msk->get_int(F_INDSPED)); key.add(codcont); return true; } //READ: ridefinizione del metodo read() delle TRealtion_application int TContratti_app::read(TMask& m) { //eseguo la read() standard int err = TRelation_application::read(m); //se la read va a buon fine if(err == NOERR) { //instanzio un TISAM_recordset sulle righe contratto TISAM_recordset righeset(build_query(m)); const TRectype& rec = righeset.cursor()->curr(); //instanzio un TLcalisamfile su LF_CLIFOGIAC TLocalisamfile magcli(LF_CLIFOGIAC); //setto alcune variabili di interesse //la data deve essere un esercizio; è da prendere sempre l'ultimo esercizio esistente TEsercizi_contabili esc; const int last_esc = esc.last(); /*const TDate oggi(TODAY); const int year = oggi.year();*/ const long clifo = m.get_long(F_CODCF); const int indsp = m.get_int(F_INDSPED); //recupero sheet e realtiva mashera di riga TSheet_field& righe = m.sfield(F_RIGHE); TMask& msk = righe.sheet_mask(); righe.destroy(); //per ogni riga dello sheet int pos = -1; for (bool ok = righeset.move_first(); ok; ok = righeset.move_next()) { ++pos; TToken_string& row = righe.row(-1); //per ogni campo della maschera scrivi setta all'interno del record corrente di file //il valore di quei campi che hanno un field FOR_EACH_MASK_FIELD(msk,i,f) { const TFieldref*fr=f->field(); if (fr!= NULL) row.add(fr->read(rec),righe.cid2index(f->dlg())); } const TString80 codart(row.get(righe.cid2index(S_CODART))); //se non gli ho passato nessun codart, allora dico che voglio dare il focus alla prima riga dello sheet //aktrimenti dico che volgio dare il focus alla riga dello sheet che contiene l'articolo che gli ho passato if (_codart.empty()) _msk->set_riga(0); else if (codart == _codart) { _msk->set_riga(pos); _codart.cut(0); } //estraggo il record corrispondente su LF_CLIFOGIAC TArticolo_lavanderie& artrec = cached_article_laundry(codart, 'C', clifo, indsp); artrec.find_rec(0); //svuoto la cache a forza const TRecmag_lavanderie& reclav = artrec.find_rec(last_esc); //lettura dei dati da LF_CLIFOGIAC //se esiste il record su LF_CLIFOGIAC, recupero l'unità di misura dalla riga dello sheet selezionata //e setto i campi delle dotazioni e dei consegnati ai valori corretti riportati alla giusta unità di misura if (!reclav.empty()) { //calcolo dotazione iniziale, scritta sia sulla maschera che sullo sheet const real dotin = reclav.get_real(CLIFOGIAC_DOTIN); row.add(dotin.stringa(), righe.cid2index(S_DOTIN)); //calcolo dotazione odierna, scritta sia sulla maschera che sullo sheet const real dotod = reclav.get_real(CLIFOGIAC_DOTOD); row.add(dotod.stringa(), righe.cid2index(S_DOTOD)); //calcolo dotazione temporanea, scritta sia sulla maschera che sullo sheet const real dottmp = reclav.get_real(CLIFOGIAC_DOTTM); row.add(dottmp.stringa(), righe.cid2index(S_DOTTMP)); } //forzo una check_row righe.check_row(righe.items()-1, 3); } } return err; } //WRITE: ridefinizione del metodo write() delle TRelation_application int TContratti_app::write(const TMask& m) { //esegui la write standard int err = TRelation_application::write(m); //se va a buon fine esegui la save_rows() e ricorda all'utente i passaggi per planning if(err == NOERR) { save_rows(m); warning_box(TR("Ricordarsi di inserire i passaggi per planning")); } return err; } //REWRITE: ridefinizione del metodo rewrite() delle TRelation_application int TContratti_app::rewrite(const TMask& m) { //esegui la rewrite standard int err = TRelation_application::rewrite(m); //se va a buon fine esegui la save_rows() if(err == NOERR) save_rows(m); return err; } //PROTECTED_RECORD: metodo che rendo un record non cancellabile bool TContratti_app::protected_record(TRectype & rec) { TLaundry_contract cont(rec); return !cont.can_be_deleted(); } //REMOVE: ridefinizione del metodo remove() delle TRelation_application bool TContratti_app::remove() { //recupero i dati dalla testata del contratto prima di cancellarla const TRectype& tcont = get_relation()->curr(); const int daanno = tcont.get_date(LVCONDV_DATAIN).year(); const int aanno = TDate(TODAY).year(); const long clifo = tcont.get_long(LVCONDV_CODCF); const long indsp = tcont.get_long(LVCONDV_CODINDSP); //eseguo la remove standard bool ok = TRelation_application::remove(); //se va a buon fine, elimino anche le righe contratto dal file specifico if(ok) { TISAM_recordset righeset(build_query(*_msk)); TLocalisamfile& rcont = righeset.cursor()->file(); //elimino le giacenze per cliente SOLO se le quantità sono modificabili if (ini_get_bool(CONFIG_DITTA, "lv", "Qtamodi")) { TLocalisamfile magcli(LF_CLIFOGIAC); for (bool ok = righeset.move_first(); ok; ok = righeset.move_next()) { //con questo ciclo elimino tutte le giacenze per cliente dall'anno di inizio validità //del contratto all'anno attuale (essendo nel ciclo che scorre le righe contratto //elimino tutti gli articoli presenti per quel contratto) for (int y = daanno; y <= aanno; y++) { magcli.put(CLIFOGIAC_ANNOES, y); magcli.put(CLIFOGIAC_TIPOCF, 'C'); magcli.put(CLIFOGIAC_CODCF, clifo); magcli.put(CLIFOGIAC_INDSPED, indsp); magcli.put(CLIFOGIAC_CODART, righeset.get(LVRCONDV_CODART).as_string()); magcli.put(CLIFOGIAC_NRIGA, 1); magcli.remove(); } } rcont.remove(); } //elimino i planning esistenti per quel cliente - contratto elimina_planning(_msk->get_long(F_CODCONT),_msk->get_long(F_CODCF)); } return ok; } //INIT_QUERY_MODE: ridefinizione del metodo init_query_mode() standard void TContratti_app::init_query_mode(TMask& m) { //abilita il campo F_RAGSOC se il campo F_CODCF è abilitato m.field(F_RAGSOC).enable(m.field(F_CODCF).enabled()); m.reset(); } //INIT_MODIFY_MODE: ridefinizione del metodo init_modify_mode() standard void TContratti_app::init_modify_mode(TMask& m) { //setto alcune variabili di interesse const TDate oggi(TODAY); const int year = oggi.year(); const long clifo = m.get_long(F_CODCF); const int indsp = m.get_int(F_INDSPED); const TEsercizi_contabili escon; //instanzio un TLocaisamfile su LF_CLIFOGIAC TLocalisamfile magcli(LF_CLIFOGIAC); //recupero lo sheet TSheet_field& righe = m.sfield(F_RIGHE); //per ogni riga dello sheet aggiorno le dotazioni su LF_CLIFOGIAC //per tutti ????, se il record esiste già FOR_EACH_SHEET_ROW(righe,r,row) { const TString80 codart=row->get(righe.cid2index(S_CODART)); // righe.disable_cell(r, righe.cid2index(S_CODART)); // righe.disable_cell(r, righe.cid2index(S_DESCR)); // righe.disable_cell(r, righe.cid2index(S_UM)); for (int y = escon.last() + oggi.month() == 12; y >= year; y--) { magcli.put(CLIFOGIAC_ANNOES, y); magcli.put(CLIFOGIAC_TIPOCF, 'C'); magcli.put(CLIFOGIAC_CODCF, clifo); magcli.put(CLIFOGIAC_INDSPED, indsp); magcli.put(CLIFOGIAC_CODART, codart); if (magcli.read() == NOERR) { row->add(magcli.get(CLIFOGIAC_DOTIN), righe.cid2index(S_DOTIN)); row->add(magcli.get(CLIFOGIAC_DOTOD), righe.cid2index(S_DOTOD)); row->add(magcli.get(CLIFOGIAC_DOTTM), righe.cid2index(S_DOTTMP)); break; } } } } //INIT_INSERT_MODE: ridefinizione del metodo init_insert_mode() standard void TContratti_app::init_insert_mode(TMask& m) { //se esiste già un contratto in essere alla data odierna per questo cliente, //contrassegna quello attuale come "PROPOSTA" const long codcf = m.get_long(F_CODCF); const long indsp = m.get_int(F_INDSPED); const TDate oggi(TODAY); const long old_contr = lv_find_contract(codcf, indsp, oggi); const long cur_contr = m.get_long(F_CODCONT); if (old_contr > 0 && old_contr < cur_contr) m.set(F_PROPOSTA, "X"); } //ELIMINA PLANNING: metodo che prepara il recordset sui planning con le righe da eliminare bool TContratti_app::elimina_planning(const long& codcont, const long& codcf) const { //creo il recordset TISAM_recordset selrighe("USE LVRCONSPLAN KEY 3\nFROM CODCF=#CODCF CODCONT=#CODCONT \nTO CODCF=#CODCF CODCONT=#CODCONT"); //setto le variabili selrighe.set_var("#CODCF",codcf); selrighe.set_var("#CODCONT",codcont); //richiamo la funzione che effettivamente fa la cancellazione delle righe interessate kill_planning(selrighe); return true; } //KILL_PLANNING: metodo che effettivamente fa la cancellazione dei planning interessati bool TContratti_app::kill_planning (TISAM_recordset& selrighe) const { //se effettivamente ci sono delle righe da cancellare, allora le cancello const int righe = selrighe.items(); if (righe > 0) { TProgind pi(righe, TR("Eliminazione planning in corso..."), true, true); TLocalisamfile& rplan = selrighe.cursor()->file(); for (bool ok = selrighe.move_last(); ok; ok = selrighe.move_prev()) { if (!pi.addstatus(1)) break; rplan.remove(); } } return true; } int lv0400(int argc, char* argv[]) { TContratti_app app; app.run (argc,argv,TR("Gestione contratti")); return 0; }