diff --git a/ca/ca3700.cpp b/ca/ca3700.cpp index cd650b02e..282532817 100755 --- a/ca/ca3700.cpp +++ b/ca/ca3700.cpp @@ -9,6 +9,7 @@ #include "../cg/cglib01.h" #include "../ve/velib04.h" +#include "commesse.h" #include "panapdc.h" #include "pconana.h" #include "movana.h" @@ -146,6 +147,14 @@ bool TPrint_rendiconto_ca_mask::on_field_event(TOperable_field& o, TField_event return false; } break; + case DLG_EXPORT: + if (e == fe_button) + { + TString path = get(F_PATH); + if (path.empty()) + return error_box(TR("Specificare una cartella dove creare il file rendiconto.xls!")); + } + break; default: break; } @@ -260,6 +269,7 @@ protected: int _anno; TString4 _piano; TDate _dadata, _adata; + bool _vitaintera; long _danumreg, _anumreg; TString _daconto, _aconto, _codcosto, _codcms, _codfas; @@ -339,7 +349,7 @@ void TPrint_rendiconto_ca_recordset::set_custom_filter(TCursor& cur) const if (_dadata.ok()) filtro << "(ANSI(DATA)>=" << _dadata << ")"; - if (_adata.ok()) + if (_adata.ok() && !_vitaintera) //se vitaintera non si può avere una data limite superiore { if (filtro.not_empty()) filtro << "&&"; @@ -476,7 +486,7 @@ const TVariant& TPrint_rendiconto_ca_recordset::get(const char* column_name) con int TPrint_rendiconto_ca_recordset::sort_indbil(int indbil) const { - if (_reverse_cos_ric) //sono del CRPA/CSA + if (_reverse_cos_ric) //sono del CRPA/DINAMICA { if (indbil == 3 || indbil == 4) indbil = 7 - indbil; @@ -592,13 +602,13 @@ void TPrint_rendiconto_ca_recordset::scrive_riga(const TRectype& rmovana, const TString codcontocg; int indbil = 0; bool conto_non_riclass = false; //indicatore che serve per tener conto di specialissimi conti del CRPA... - //E' una lampante dimostrazione di quanto sia generico questo programma... + //E' una lampante dimostrazione di quanto sia generico questo programma... // il conto puo' essere analitico o contabile... //se è compilato l'archivio di collegamento PANAPDC.. //..si deve usare come conto il campo codconto del panapdc!!!... //Ricordare che SOLO se si ha un conto contabile e' possibile riclassificare in analitico!!! - if (_riclassificato) //traduzione:sei il CRPA/CSA + if (_riclassificato) //traduzione:sei il CRPA/DINAMICA { //stringa che conterrà il conto riclassificato (se sara' trovato) const TString conto_riclassificato = riclassifica(codconto, tmpcurr); @@ -900,11 +910,14 @@ F=IMF*/ tmpcurr.put("ORDCONT", ordcont); //----Scrittura dati riga movimento----// - tmpcurr.put("NUMREG", rmovana.get(RMOVANA_NUMREG)); + tmpcurr.put("NUMREG", rmovana.get(RMOVANA_NUMREG)); //numero di registrazione analitica tmpcurr.put("NUMREGCG", movana.get(MOVANA_NUMREGCG)); //numero di registrazione contabile - tmpcurr.put("DESC", descr); //descrizione movana - tmpcurr.put("NRIGA", rmovana.get(RMOVANA_NUMRIG)); //numero riga + tmpcurr.put("DESC", descr); //descrizione movana + tmpcurr.put("NRIGA", rmovana.get(RMOVANA_NUMRIG)); //numero riga tmpcurr.put("DESCRIGA", rmovana.get(RMOVANA_DESCR)); //descrizione rmovana + tmpcurr.put("CODCMS", rmovana.get(RMOVANA_CODCMS)); //codice commessa + tmpcurr.put("CODCOSTO", rmovana.get(RMOVANA_CODCCOSTO)); //codice cdc + tmpcurr.put("CODFASE", rmovana.get(RMOVANA_CODFASE)); //codice fase if (should_delete) delete newdoc; @@ -1009,15 +1022,19 @@ void TPrint_rendiconto_ca_recordset::scrive_riga_speciale(const TDocumento* doc, //comincia a riempire i record //prima i campi che prende direttamente dal doc speciale - tmpcurr.put("CODNUM", doc->get(DOC_CODNUM)); - tmpcurr.put("ANNO", doc->get(DOC_ANNO)); - tmpcurr.put("NUMRD", doc->get(DOC_NDOC)); - tmpcurr.put("DATA", doc->get(DOC_DATADOC)); - tmpcurr.put("NUMDOCRIF", doc->get(DOC_NUMDOCRIF)); //docrif del documento + tmpcurr.put("CODNUM", doc->get(DOC_CODNUM)); //numerazione doc speciale + tmpcurr.put("ANNO", doc->get(DOC_ANNO)); //anno doc speciale + tmpcurr.put("NUMRD", doc->get(DOC_NDOC)); //numero del doc speciale + tmpcurr.put("DATA", doc->get(DOC_DATADOC)); //data del doc speciale + tmpcurr.put("NUMDOCRIF", doc->get(DOC_NUMDOCRIF)); //docrif del documento tmpcurr.put("DATADOCRIF", doc->get(DOC_DATADOCRIF)); //datadocrif del documento - tmpcurr.put("NUMREG", doc->get(DOC_NUMREGCA)); - tmpcurr.put("NUMREGCG", doc->get(DOC_NUMREG)); //numero di registrazione contabile - tmpcurr.put("NRIGA", rigadoc.get(RDOC_NRIGA)); //numero riga + tmpcurr.put("NUMREG", doc->get(DOC_NUMREGCA)); //numero di registrazione analitica + tmpcurr.put("NUMREGCG", doc->get(DOC_NUMREG)); //numero di registrazione contabile + + tmpcurr.put("NRIGA", rigadoc.get(RDOC_NRIGA)); //numero riga + tmpcurr.put("CODCMS", rigadoc.get(RDOC_CODCMS)); //codice commessa + tmpcurr.put("CODCOSTO", rigadoc.get(RDOC_CODCOSTO)); //codice cdc + tmpcurr.put("CODFASE", rigadoc.get(RDOC_FASCMS)); //codice fase //procedura per ottenere i campi del documento origine di quello in esame const int tipo_documento = doc->tipo_riclassificato(); @@ -1105,7 +1122,7 @@ void TPrint_rendiconto_ca_recordset::crea_righe_da_rmovana() if (_dadata.ok()) filtro << "(ANSI(DATACOMP)>=" << _dadata.date2ansi() << ")"; - if (_adata.ok()) + if (_adata.ok() && !_vitaintera) //se vitaintera non si può avere una data limite superiore { if (filtro.not_empty()) filtro << "&&"; @@ -1229,7 +1246,7 @@ void TPrint_rendiconto_ca_recordset::crea_righe_da_rdoc(const TPrint_rendiconto_ if (_dadata.ok()) filtro_date << "(ANSI(33->DATADOC)>=" << _dadata.date2ansi() << ")"; - if (_adata.ok()) + if (_adata.ok() && !_vitaintera) //se vitaintera non si può avere una data limite superiore { if (filtro_date.not_empty()) filtro_date << "&&"; @@ -1410,13 +1427,16 @@ void TPrint_rendiconto_ca_recordset::crea_trr(const TFilename& trr) const { ofstream of(trr); of << 1000 << endl; - of << 19 << endl; + of << 22 << endl; of << "ORDCONT|1|1|0|Ordinatore in base a indicatore di bilancio" << endl; of << "CONTO|1|20|0|Conto analitico" << endl; of << "DATA|5|8|0|Data movimento o documento" << endl; of << "CODNUM|1|4|0|Numerazione documento" << endl; of << "NUMRD|3|7|0|Numero registrazione contabile o numero documento di origine" << endl; of << "NRIGA|2|3|0|Riga movimento o documento" << endl; + of << "CODCMS|1|20|0|Codice commessa" << endl; + of << "CODCOSTO|1|20|0|Codice centro di costo" << endl; + of << "CODFASE|1|20|0|Codice fase (eventualmente legato a CODCMS)" << endl; of << "NUMREG|3|7|0|Numero registrazione del movimento analitico" << endl; of << "NUMREGCG|3|7|Numero registrazione contabile" << endl; of << "ANNO|9|4|0|Anno" << endl; @@ -1509,10 +1529,10 @@ void TPrint_rendiconto_ca_recordset::set_filter(const TPrint_rendiconto_ca_mask& //sei al CRPA e vuoi implodere le righemovana ripartite in precedenza? _implode_rows = msk.get_bool(F_IMPLODE_ROWS); - //c'e' un fottuto range di date? + //c'e' un fottuto range di date? oppure si va a vita intera? _dadata = msk.get_date(F_DATAINI); _adata = msk.get_date(F_DATAFIN); - + _vitaintera = msk.get_bool(F_VITAINTERA); //metodi per riempire il file da cui generare il report //dati estratti dalle righe movimenti di contabilita' analitica @@ -1570,6 +1590,8 @@ protected: void print_or_preview(bool pr); virtual void print() { print_or_preview(true); } virtual void preview() { print_or_preview(false); } + void esporta_csv(TMask& mask, TRecordset& rendy, const TString& codcms, const TString& cdc, const TString& codfase); + void incrementa(TToken_string& riga, const int col, const real& valore) const; public: const TMultilevel_code_info& get_first_level() const; @@ -1582,6 +1604,82 @@ void TPrint_rendiconto_ca::print_or_preview(bool pr) _msk->send_key(K_SPACE, pr ? DLG_PRINT : DLG_PREVIEW); } +void TPrint_rendiconto_ca::incrementa(TToken_string& riga, const int col, const real& valore) const +{ + real r; riga.get(col, r); + r += valore; + riga.add(r.string(), col); +} + +//metodo di alto livello per l'esportazione dei dati di totale in un file per excel +void TPrint_rendiconto_ca::esporta_csv(TMask& mask, TRecordset& rendy, + const TString& codcms, const TString& cdc, const TString& codfase) +{ + //crea una token string su cui mettere i valori dei record letti dal file .dbf + TToken_string riga(512, '\t'); + + riga.add(codcms); + riga.add(cache().get(LF_COMMESSE, codcms, COMMESSE_DESCRIZ)); + riga.add(cdc); + riga.add(codfase); + + //recordset sul file .dbf, da scandire tutto uno per volta + for (bool ok = rendy.move_first(); ok; ok = rendy.move_next()) + { + const int indbil = rendy.get("ORDCONT").as_int(); + const bool budget = rendy.get("HIDDEN").as_bool(); + + const real impegnato = rendy.get("IMPEGNATO").as_real(); + const real fatturato = rendy.get("FATTURATO").as_real(); + const real maturato = rendy.get("MATURATO").as_real(); + + //in base al valore di indbil e budget i valori degli importi vengono posizionati nel record + int col; + switch (indbil) + { + case 1: col = 18; break; //attività + case 2: col = 25; break; //passività + case 3: col = 4; break; //costi + case 4: col = 11; break; //ricavi + } + +//simpatico metodo algoritmico per stabilire la colonna iniziale di sezione, invalidato da richieste dinamica/crpa + //const int col = 4 + (7*(indbil-1)); + + //lo schema è questo: budget\impegnato\fatturato\maturato\da impegnare\da fatturare\da maturare + if (budget) + { + incrementa(riga, col, impegnato); + } + else + { + incrementa(riga, col + 1, impegnato); + incrementa(riga, col + 2, fatturato); + incrementa(riga, col + 3, maturato); + //il da maturare è più incasinato, perchè deve tener conto di valori già totalizzati sulla riga + const real imp_budget = riga.get(col); + const real imp_consuntivo = riga.get(col + 1); + const real da_impegnare = imp_budget - imp_consuntivo; + riga.add(da_impegnare.string(), col + 4); //da impegnare + incrementa(riga, col + 5, impegnato - fatturato); //da fatturare + incrementa(riga, col + 6, impegnato - maturato); //da maturare + } + } //for (bool ok = rendy.move_first()... + for (int i = 4; i < 32; i++) + { + const real r = riga.get(i); + if (!r.is_zero()) + riga.add(r.stringe(), i); + } + + //aggiorna il file da esportare appendendo la nuova riga + TFilename path = mask.get(F_PATH); + path.lower(); + path.add("rendiconto.xls"); + ofstream file_to_date(path, ios::app); + file_to_date << riga << endl; +} + //metodo per accattarsi o' primo livello della configurazione CA const TMultilevel_code_info& TPrint_rendiconto_ca::get_first_level() const { @@ -1596,8 +1694,83 @@ void TPrint_rendiconto_ca::main_loop() _msk = new TPrint_rendiconto_ca_mask; TPrint_rendiconto_ca_mask& mask = *_msk; - while (mask.run() == K_ENTER) + while (true) { + //il programma deve cominciare l'eleaborazione solo nel caso di Stampa/Anteprima (K_ENTER) o Esportazione CSV (K_F6) + KEY key = mask.run(); + if (key != K_ENTER && key != K_F6) + break; + + //resetta e prepara le intestazioni del file rendiconto.xls + if (key == K_F6) + { + TFilename file_xls = mask.get(F_PATH); + file_xls.lower(); + file_xls.add("rendiconto.xls"); + ofstream file_to_date(file_xls); + + //intestazione primaria + TToken_string intestazione_1(512, '\t'); + + intestazione_1.add("Commessa"); + intestazione_1.add("Descr. commessa"); + intestazione_1.add("C.d.C."); + intestazione_1.add("Fase"); + + const bool reverse_cos_ric = mask.get_bool(F_REV_COSRIC); //occhio al flag di rovesciamento + + for (int i = 0; i < 4; i++) + { + switch (i) + { + case 0: + { + if (reverse_cos_ric) + intestazione_1.add("Ricavi"); + else + intestazione_1.add("Costi"); + } + break; + case 1: + { + if (reverse_cos_ric) + intestazione_1.add("Costi"); + else + intestazione_1.add("Ricavi"); + } + break; + case 2: intestazione_1.add("Attività"); break; + case 3: intestazione_1.add("Passività"); break; + } + for (int j = 0; j < 6; j++) + intestazione_1.add(""); + } + file_to_date << intestazione_1 << endl; + + //intestazione secondaria + TToken_string intestazione_2(512, '\t'); + + for (int k = 0; k < 4; k++) + intestazione_2.add(""); + for (int l = 0; l < 4; l++) + { + for (int n = 0; n < 7; n++) + { + switch (n) + { + case 0: intestazione_2.add("Budget"); break; + case 1: intestazione_2.add("Impegnato"); break; + case 2: intestazione_2.add("Fatturato"); break; + case 3: intestazione_2.add("Maturato"); break; + case 4: intestazione_2.add("Da impegnare"); break; + case 5: intestazione_2.add("Da fatturare"); break; + case 6: intestazione_2.add("Da maturare"); break; + } + } + } + file_to_date << intestazione_2 << endl; + } + //report e book dei report TReport_book book; TString path = mask.get(F_REPORT); @@ -1630,8 +1803,18 @@ void TPrint_rendiconto_ca::main_loop() for (int l = liv1.levels()-2; l >= 0; l--) //se la struttura è a più livelli costruisce la tokenstring row.insert("|", liv1.total_len(l)); - rep.set_filter(mask, 0); //fa la set filter sulla prima riga (che è quella usata) - book.add(rep); + rep.set_filter(mask, 0); //fa la set filter sulla prima riga (che è quella usata) + + //se stampa o anteprima.. + if (key == K_ENTER) + book.add(rep); + else + { + const TString codcms = row.get(0); + const TString cdc = row.get(); + const TString codfase = row.get(); + esporta_csv(mask, *rep.recordset(), codcms, cdc, codfase); + } } sheet.destroy(); //cancella le commesse aggiunte in automatico sullo sheet } @@ -1640,16 +1823,29 @@ void TPrint_rendiconto_ca::main_loop() FOR_EACH_SHEET_ROW(sheet, r, row) //per ogni cdc/cms che appare nello sheet di pag.1 della msk.. { rep.set_filter(mask, r); //..chiama il metodone globale che crea e compila il file.. - //..temporaneo i cui dati riempiranno il report - book.add(rep); //aggiunge il report relativo alla cdc/cms corrente al book + //..temporaneo i cui dati riempiranno il report + //se stampa o anteprima + if (key == K_ENTER) + book.add(rep); //aggiunge il report relativo alla cdc/cms corrente al book + else + { + const TString codcms = row->get(0); + const TString cdc = row->get(); + const TString codfase = row->get(); + esporta_csv(mask, *rep.recordset(), codcms, cdc, codfase); + } } } + //se stampa o anteprima + if (key == K_ENTER) + { + if (mask.print_mode() == 'A') + book.preview(); + else + book.print(); //stampa il book dei report + } - if (mask.print_mode() == 'A') - book.preview(); - else - book.print(); //stampa il book dei report - } + } //while(true)... delete _msk; _msk = NULL; diff --git a/ca/ca3700.h b/ca/ca3700.h index ba7d95a1c..d77bf7d03 100755 --- a/ca/ca3700.h +++ b/ca/ca3700.h @@ -11,6 +11,8 @@ #define F_DATAFIN 257 #define F_REV_COSRIC 258 #define F_IMPLODE_ROWS 259 +#define F_VITAINTERA 261 +#define F_PATH 262 //campi generati dai piani dei conti #define F_PIANO 319 diff --git a/ca/ca3700.uml b/ca/ca3700.uml index 3c5915e6d..eab9ec955 100755 --- a/ca/ca3700.uml +++ b/ca/ca3700.uml @@ -3,6 +3,14 @@ TOOLBAR "topbar" 0 0 0 2 #include + +BUTTON DLG_EXPORT 2 2 +BEGIN + PROMPT 1 1 "~Esporta XLS" + MESSAGE EXIT,K_F6 + PICTURE TOOL_EXPORT +END + ENDPAGE TOOLBAR "bottombar" 0 -2 0 1 @@ -90,14 +98,32 @@ BEGIN ITEM "Cdc12" END +BOOLEAN F_VITAINTERA +BEGIN + PROMPT 2 -6 "Includere esercizi successivi (vita intera)" + MESSAGE FALSE ENABLE,F_DATAFIN + MESSAGE TRUE CLEAR,F_DATAFIN +END + DATE F_DATAINI BEGIN - PROMPT 2 -4 "Dalla data " + PROMPT 2 -5 "Dalla data " END DATE F_DATAFIN BEGIN - PROMPT 40 -4 "Alla data " + PROMPT 36 -5 "Alla data " +END + +TEXT DLG_NULL +BEGIN + PROMPT 2 -3 "Digitare o selezionare attraverso la ricerca la cartella in cui creare il file rendiconto.xls. E' necessario indicare l'intero percorso!" +END + +STRING F_PATH 256 40 +BEGIN + PROMPT 2 -2 "Cartella dove esportare il file rendiconto.xls " + DSELECT END ENDPAGE