#include #include #include #include "../ca/commesse.h" #include "../ca/calib01.h" #include "../cg/cglib01.h" #include "ce4100a.h" #include "cespi.h" struct date_commessa : public TObject { TDate _dataini_cms, _datafine_cms; }; //============================================================================================= //maschera class TCesp_anal_mask: public TAutomask { int _pos_cms, _pos_fase, _pos_cdc, _pos_dtiniuse, _pos_dtfinuse, _pos_util; protected: int calc_durata_esercizio_cespitizzata(TDate& dtinies, TDate& dtfines); void calc_date_limite(const TString& codcms, TDate& dtini, TDate& dtfine); public: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); real TCesp_anal_mask::somma_perc() const; TCesp_anal_mask(); }; TCesp_anal_mask::TCesp_anal_mask() : TAutomask ("ce4100a") { //setta le posizioni dei campi dello sheet TSheet_field& sf_righe = sfield(F_RIGHE); _pos_cms = sf_righe.cid2index(S_CODCMS); _pos_fase = sf_righe.cid2index(S_CODFASE); _pos_cdc = sf_righe.cid2index(S_CODCDC); _pos_dtiniuse = sf_righe.cid2index(S_DTINIUSE); _pos_dtfinuse = sf_righe.cid2index(S_DTFINUSE); _pos_util = sf_righe.cid2index(S_PERCUTIL); //mette i checktype sui campi dello sheet in base alla configurazione.. //..analitica della ditta TConfig& cfg = ca_config(); TMask& sf_righe_msk = sf_righe.sheet_mask(); if (cfg.get_bool("CmsRequired")) { TEdit_field& e_cms = sf_righe_msk.efield(S_CODCMS); e_cms.check_type(CHECK_REQUIRED); } if (cfg.get_bool("CdcRequired")) { TEdit_field& e_cdc = sf_righe_msk.efield(S_CODCDC); e_cdc.check_type(CHECK_REQUIRED); } if (cfg.get_bool("FscRequired")) { TEdit_field& e_fase = sf_righe_msk.efield(S_CODFASE); e_fase.check_type(CHECK_REQUIRED); } } real TCesp_anal_mask::somma_perc() const { TSheet_field& ss = sfield(F_RIGHE); real tot_perc; FOR_EACH_SHEET_ROW(ss,i,r) tot_perc += real(r->get(_pos_util)); return tot_perc; } int TCesp_anal_mask::calc_durata_esercizio_cespitizzata(TDate& dtinies, TDate& dtfines) { const int anno = get_int(F_ESERCIZIO); TEsercizi_contabili esc; esc.code2range(anno, dtinies, dtfines); //vita cespite const TString& cespite = get(F_IDCESPITE); const TRectype& rec_cespi = cache().get(LF_CESPI, cespite); const TDate& dtcomp = rec_cespi.get_date(CESPI_DTCOMP); const TDate& dtalien = rec_cespi.get_date(CESPI_DTALIEN); //cespite acquistato durante l'esercizio if (dtcomp.ok() && dtcomp > dtinies) dtinies = dtcomp; //cespite alienato durante l'esercizio if (dtalien.ok() && dtalien < dtfines) dtfines = dtalien; //durata "cespitizzata" dell'esercizio const int durata = dtfines - dtinies + 1; return durata; } void TCesp_anal_mask::calc_date_limite(const TString& codcms, TDate& dtini, TDate& dtfine) { //date limite coincidenti con date vita cespite nell'esercizio (caso standard, senza commessa) const TDate dtinicesp = get_date(F_INIZIO_CES); const TDate dtfincesp = get_date(F_FINE_CES); //se invece la commessa viene aggiunta, le sue date limite influenzano il limite di uso! if (codcms.full()) { const TRectype& rec_cms = cache().get(LF_COMMESSE, codcms); ca_durata_commessa(rec_cms, dtini, dtfine); //se le date di commessa sforano l'esercizio selezionato, vengono ricondotte alle date.. //..dell'esercizio stesso if (dtfine.ok() && (dtfine > dtfincesp)) dtfine = dtfincesp; if ((dtini.ok()) && (dtini < dtinicesp)) dtini = dtinicesp; } else { dtfine = dtfincesp; dtini = dtinicesp; } } bool TCesp_anal_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { //maschera principale //------------------- case F_IDCESPITE: case F_ESERCIZIO: if (e == fe_modify) { //nel caso vengano cambiati il cespite e/o l'esercizio, deve controllare la vita del cespite.. //..nell'esercizio TDate dtinies = get_date(F_INIZIO_ES); TDate dtfines = get_date(F_FINE_ES); calc_durata_esercizio_cespitizzata(dtinies, dtfines); set(F_INIZIO_CES, dtinies); set(F_FINE_CES, dtfines); } break; case F_RIGHE: if (e == se_notify_add) //quando si aggiunge una riga... { TSheet_field& ss = (TSheet_field&)o; //propone come date iniziale e finale di uso quelle dell'esercizio selezionato! const int anno = get_int(F_ESERCIZIO); TDate dtinies, dtfines; TEsercizi_contabili esc; esc.code2range(anno, dtinies, dtfines); calc_durata_esercizio_cespitizzata(dtinies, dtfines); TToken_string& new_row = ss.row(jolly); new_row.add(dtinies, _pos_dtiniuse); new_row.add(dtfines, _pos_dtfinuse); //mette nel campo %util il valore max possibile al momento real residuo = CENTO - somma_perc(); if (residuo > 0) { TToken_string& row = ss.row(jolly); row.add(residuo.string(),_pos_util); } } if (e == fe_close && (insert_mode() || edit_mode())) { //controllo sulle percentuali totali di un cespite if (somma_perc() != CENTO) return noyes_box("La percentuale complessiva di utilizzo del cespite e' diversa da 100" "\nSi desidera proseguire ugualmente?"); TAssoc_array keys_list; TSheet_field& ss = sfield(F_RIGHE); FOR_EACH_SHEET_ROW(ss,i,r) { //controllo di esistenza codici commessa e cdc const TString& cms = r->get(_pos_cms); if (cms.blank()) return error_box("Specificare la commessa sulla riga %d", i+1); const TString& cdc = r->get(_pos_cdc); if (cdc.blank()) return error_box("Specificare il centro di costo sulla riga %d", i+1); //controllo di duplicazione chiave della riga (cms/fase/cdc) TToken_string row_key; row_key.add(cms); const TString& fase = r->get(_pos_fase); row_key.add(fase); row_key.add(cdc); if (keys_list.is_key(row_key)) return error_box("Codice riga %s duplicato", (const char *)row_key); keys_list.add(row_key); } } break; //maschera di riga sheet //---------------------- //controllo sulle date limite di utilizzo: se c'è la commessa le date lim uso devono ricadere.. //..all'interno della vita della commessa, se invece la commessa non c'è le date lim uso devono.. //..ricadere all'interno della vita utile del cespite nell'esercizio case S_DTINIUSE: if (e == fe_modify || e == fe_close) { TDate dtini, dtfine; const TString& codcms = get(S_CODCMS); calc_date_limite(codcms, dtini, dtfine); if (o.get() < dtini) return error_box("La data inizio uso non può essere antecedente alla data inizio commessa!"); } break; case S_DTFINUSE: if (e == fe_modify || e == fe_close) { TDate dtini, dtfine; const TString& codcms = get(S_CODCMS); calc_date_limite(codcms, dtini, dtfine); if (o.get() > dtfine) return error_box("La data fine uso non può essere successiva alla data fine commessa!"); } break; //bottoni //------- case DLG_CALCPERC: if (e == fe_button) { //ripartisce in automatico le percentuali di utilizzo analizzando le durate e le compresenze.. //..delle commesse sullo sheet nell'anno selezionato, oltre che ovviamente la durata del cespite.. //..nell'anno selezionato // 1) stabilisce la durata dell'esercizio per il cespite: infatti può essere stato comprato o venduto.. //..nel corso dell'esercizio stesso TDate dtini, dtfine; //durata "cespitizzata" dell'esercizio const int durata = calc_durata_esercizio_cespitizzata(dtini, dtfine); // 2) chiave generale su cui mettere le quote che non appartengono ad alcuna.. //..commessa! La si trova nella configurazione esercizio cespiti (tanto per incasinarci.. //..la vita), ovvero tabella CCE const TString& anno = get(F_ESERCIZIO); const TRectype& rec_cce = cache().get("CCE", anno); //trova per l'anno sulla maschera quali sono i valori standard; TToken_string key_genspa; key_genspa.add(rec_cce.get("S2"), _pos_cdc); key_genspa.add(rec_cce.get("S3"), _pos_cms); key_genspa.add(rec_cce.get("S4"), _pos_fase); //conatore dei giorni cui casca la chiave genspa long giorni_genspa = 0L; TSheet_field& sf_righe = sfield(F_RIGHE); TPointer_array giorni_commessa; int riga_genspa = -1; // 3) giro su tutti i giorni inclusi tra le date limite in modo da trovare i giorni utili.. //..di ciascuna commessa e gli eventuali giorni vuoti da scaricare in genspa for (TDate data = dtini; data <= dtfine; ++data) { bool almeno_una = false; FOR_EACH_SHEET_ROW(sf_righe, r, row) { TToken_string key_riga; key_riga.add(row->get(_pos_cms)); key_riga.add(row->get(_pos_fase)); key_riga.add(row->get(_pos_cdc)); //la commessa genspa non va calcolata qui! if (key_riga != key_genspa) { const TDate dt_ini_use = row->get(_pos_dtiniuse); const TDate dt_fin_use = row->get(_pos_dtfinuse); //se la data in esame appartiene allintrvallo date di utilizzo sulla riga if (data >= dt_ini_use && data <= dt_fin_use) { const long giorni = giorni_commessa.get_long(r) + 1; giorni_commessa.add_long(giorni, r); almeno_una = true; } } else riga_genspa = r; } //FOR_EACH_SHEET_ROW... //se la data in questione non appartiene all'intervallo di utilizzo di nessuna riga.. //..->la data è scoperta e va a finire nel calderone del genspa if (!almeno_una) giorni_genspa ++; } //for(TDate... // 4) attenzione alla commesse generica di riempimento (cms_genspa!) se non esiste va aggiunta //se invece la cms_genspa ha già la sua riga -> deve solo aggiornare la %util (lo fa dopo.. //..assieme alle commesse normali) if (riga_genspa < 0) { TToken_string& row_genspa = sf_righe.row(-1); row_genspa = key_genspa; //aggiunge la commessa genspa all'array dei giorni_commessa, in modo che venga poi considerata.. //..nel riproporzionamento successivo con il distrib riga_genspa = sf_righe.items() - 1; } giorni_commessa.add_long(giorni_genspa, riga_genspa); // 5) procede a caricare un distrib con i valori di giorni_commessa TGeneric_distrib tamoil(CENTO, 2); for (int i = 0 ; i < sf_righe.items(); i++) tamoil.add(giorni_commessa.get_long(i)); // 6) adesso scarica il distrib, mettendo la % di ogni commessa nel campo di %di utilizzo FOR_EACH_SHEET_ROW(sf_righe, gg, linea) linea->add(tamoil.get().string(), _pos_util); //..e alla fine vediamo che succede! sf_righe.force_update(); } break; default: break; } return true; } //=============================================================================================== //Applicazione class TCesp_anal: public TRelation_application { TCesp_anal_mask *_msk; // maschera principale TRelation *_rel; // relazione principale //metodi virtuali obbligatori per gli oggetti TRelation_application protected: virtual bool user_create(); virtual bool user_destroy(); virtual TMask* get_mask(int mode) { return _msk; } virtual bool changing_mask(int mode) { return false;} virtual void init_query_mode(TMask& m); virtual void init_query_insert_mode(TMask& m); virtual void init_insert_mode(TMask& m); virtual void init_modify_mode(TMask& m); virtual TRelation* get_relation() const { return _rel; } public: virtual ~TCesp_anal() {} }; //metodi per la maschera //abilita i campi per inserimento nuovo cespite,attivando i campi del gruppo 2 (che fanno riferimento al file LF_CESPI) void TCesp_anal::init_query_insert_mode(TMask& m) { m.enable(-2); m.show(-2); m.hide(-1); } //abilita i campi per ricercare un cespite gia' inserito,attivando i campi del gruppo 1(LF_SALCECMS) void TCesp_anal::init_query_mode(TMask& m) { m.show(-1); m.hide(-2); m.set(F_DESC,""); } void TCesp_anal::init_insert_mode(TMask& m) { m.hide(-1); m.disable(-2); } void TCesp_anal::init_modify_mode(TMask& m) { m.hide(-2); } bool TCesp_anal::user_create() { _rel = new TRelation(LF_SALCECMS); _msk = new TCesp_anal_mask; return true; } bool TCesp_anal::user_destroy() { delete _rel; delete _msk; return true; } int ce4100(int argc, char* argv[]) { TCesp_anal a; a.run(argc,argv,TR("Ripartizione analitica cespiti")); return 0; }