#include #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, _pos_dtinicms, _pos_dtfincms, _pos_dtprorcms; protected: real check_perc_tot(); int calc_date_cespite(TDate& dtini, TDate& dtfine); void calc_date_limite(const TString& codcms, TDate& dtini, TDate& dtfine); void calc_percutil(); 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); _pos_dtinicms = sf_righe.cid2index(S_DTINICMS); _pos_dtfincms = sf_righe.cid2index(S_DTFINCMS); _pos_dtprorcms = sf_righe.cid2index(S_DTPRORCMS); //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::check_perc_tot() { 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_date_cespite(TDate& dtini, TDate& dtfine) { //si informa sulla vita del cespite const TString& idcespite = get(F_IDCESPITE); //controlla che il cespite sia vivo nell'esercizio selezionato e quanto dura tale esistenza const TRectype& rec_cespi = cache().get(LF_CESPI, idcespite); const TDate dtcomp = rec_cespi.get_date(CESPI_DTCOMP); const TDate dtalien = rec_cespi.get_date(CESPI_DTALIEN); const int anno = get_int(F_ESERCIZIO); TEsercizi_contabili esc; esc.code2range(anno, dtini, dtfine); long durata = dtfine - dtini + 1; if (dtalien.ok()) { //cespite alienato prima dell'esercizio if (dtalien < dtini) return 0; //cespite alienato durante l'esercizio if (dtalien < dtfine) dtfine = dtalien; } if (dtcomp.ok()) { //cespite acquistato dopo l'esercizio if (dtcomp.ok() && dtcomp > dtfine) return 0; //cespite acquistato durante l'esercizio if (dtcomp.ok() && dtcomp > dtini) dtini = dtcomp; } //durata "cespitizzata" dell'esercizio durata = dtfine - dtini + 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; } } //questo è il metodo supermagico ed iperdecisivo per calcolare la %utilizzo in base a tutti i dati.. //..vaganti nella maschera e nello sheet. E' il cuore del programma! void TCesp_anal_mask::calc_percutil() { //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 long durata = calc_date_cespite(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 && giorni_genspa > 0) { TToken_string& row_genspa = sf_righe.row(-1); row_genspa = key_genspa; row_genspa.add(dtini, _pos_dtinicms); row_genspa.add(dtfine, _pos_dtfincms); //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; } //se la riga genspa esiste (sia che l'abbia appena creata che esistesse da tempo immemorabile)... //..calcola la % di giorni genspa nell'esercizio cespitizzato (è la %util di genspa) real perc_genspa = ZERO; if (riga_genspa >= 0) { giorni_commessa.add_long(giorni_genspa, riga_genspa); perc_genspa = giorni_genspa * CENTO / durata; perc_genspa.round(2); sf_righe.row(riga_genspa).add(perc_genspa.string(), _pos_util); } // 5) procede a caricare un distrib con i valori di giorni_commessa TGeneric_distrib tamoil(CENTO - perc_genspa, 2); for (int i = 0 ; i < sf_righe.items(); i++) { if (i != riga_genspa) 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) { if (gg != riga_genspa) linea->add(tamoil.get().string(), _pos_util); } //..e alla fine vediamo che succede! sf_righe.force_update(); } 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_IDCESPITE_N: case F_ESERCIZIO: if (e == fe_modify || e == fe_close) { //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); if (calc_date_cespite(dtinies, dtfines) <= 0) return error_box("Cespite NON appartenente all'esercizio selezionato!"); set(F_INIZIO_CES, dtinies); set(F_FINE_CES, dtfines); } break; case F_RIGHE: //all'uscita della riga... if (e == se_notify_modify) { //controllo di duplicazione chiave della riga (cms/fase/cdc) TAssoc_array keys_list; TSheet_field& ss = sfield(F_RIGHE); FOR_EACH_SHEET_ROW(ss,i,r) { const TString& cms = r->get(_pos_cms); const TString& cdc = r->get(_pos_cdc); const TString& fase = r->get(_pos_fase); TToken_string row_key; row_key.add(cms, _pos_cms); row_key.add(fase, _pos_fase); row_key.add(cdc, _pos_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_CODCDC: if (e == fe_modify && !o.empty()) { TMask& mask_riga = o.mask(); const int anno = get_int(F_ESERCIZIO); TDate dtini, dtfine; TEsercizi_contabili esc; esc.code2range(anno, dtini, dtfine); calc_date_cespite(dtini, dtfine); TDate dtiniuse = mask_riga.get_date(S_DTINIUSE); if (dtiniuse.empty()) mask_riga.set(S_DTINIUSE, dtini); TDate dtfinuse = mask_riga.get_date(S_DTFINUSE); if (dtfinuse.empty()) mask_riga.set(S_DTFINUSE, dtfine); } break; case S_CODCMS: if (e == fe_modify && !o.empty()) { TMask& mask_riga = o.mask(); const TString& codcms = o.get(); TDate dtini, dtfine; calc_date_limite(codcms, dtini, dtfine); TDate dtiniuse = mask_riga.get_date(S_DTINIUSE); if (dtiniuse.empty()) mask_riga.set(S_DTINIUSE, dtini); TDate dtfinuse = mask_riga.get_date(S_DTFINUSE); if (dtfinuse.empty()) mask_riga.set(S_DTFINUSE, dtfine); } break; case S_DTINIUSE: if (e == fe_modify || e == fe_close) { TDate dtini, dtfine; const TString& codcms = o.mask().get(S_CODCMS); calc_date_limite(codcms, dtini, dtfine); const TDate dtiniuse = o.get(); if (dtiniuse.ok() && dtiniuse < 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 = o.mask().get(S_CODCMS); calc_date_limite(codcms, dtini, dtfine); const TDate dtfinuse = o.get(); if (dtfinuse.ok() && dtfinuse > 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) { //in caso di richiesta esplicita di ricalcolo, viene ordinato lo sheet.. //..in base al primo campo (in genere cms) e poi effettuato il calcolo TSheet_field& sf_righe = sfield(F_RIGHE); sf_righe.sort(); calc_percutil(); } break; case DLG_SAVEREC: if (e == fe_button) { const real perc_tot = check_perc_tot(); if (perc_tot != CENTO) { const bool proseguo = yesno_box("Percentuale complessiva diversa da 100%.\nRegistrare ugualmente?"); if (!proseguo) return false; } } 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 bool remove(); 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::remove() { _rel->read(_isequal, _unlock); TSheet_field& sf = _msk->sfield(F_RIGHE); int err = sf.record()->remove(); return err == NOERR; } 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; }