diff --git a/ca/ca3300.cpp b/ca/ca3300.cpp index 6db5fb95b..a36c9ec30 100755 --- a/ca/ca3300.cpp +++ b/ca/ca3300.cpp @@ -2,6 +2,7 @@ #include #include +#include "movana.h" #include "pconana.h" #include "rmovana.h" @@ -32,7 +33,7 @@ const TString& TPrint_bilancio_ca_mask::get_compatible_library() const { TString& lib = get_tmp_string(); lib = "ca3300"; - const char stp = get(F_STAMPAMPROV)[0]; // Raffronto o No? + const char stp = get(F_TIPOSTAMPA)[0]; // Raffronto o No? const char bil = get(F_BILANCIO)[0]; // Verifica o sezioni Contrapposte if (bil == 'V') lib << (stp == 'R' ? 'a' : 'b'); // Verifica @@ -70,7 +71,7 @@ bool TPrint_bilancio_ca_mask::on_field_event(TOperable_field& o, TField_event e, switch (o.dlg()) { case F_BILANCIO: - case F_STAMPAMPROV: + case F_TIPOSTAMPA: if (e == fe_init || e == fe_modify) test_compatible_report(); break; @@ -227,24 +228,172 @@ TPrint_bilancio_ca_mask::TPrint_bilancio_ca_mask() create_sheet(); } +//////////////////////////////////////////////////////// +// TSaldi_cache +//////////////////////////////////////////////////////// + +struct TSaldanal : public TObject +{ + TImporto _ini, _dare, _avere, _fin; + bool _movimentato; +}; + +class TSaldi_cache : private TCache +{ + TDate _dal, _al; + +protected: + virtual TObject* key2obj(const char* key); + +public: + void set_range(const TDate& dal, const TDate& al); + const TSaldanal& saldo(const char* conto, const char* costo, + const char* commessa, const char* fase, char tipo); +}; + +TObject* TSaldi_cache::key2obj(const char* key) +{ + TSaldanal* s = new TSaldanal; + + TToken_string tok(key); + TString80 conto = tok.get(); conto.trim(); + TString80 costo = tok.get(); costo.trim(); + TString80 commessa = tok.get(); commessa.trim(); + TString80 fase = tok.get(); fase.trim(); + const char tipo = tok.get_char(); + + TAnal_balance bal; + s->_movimentato = bal.saldi(conto, costo, commessa, fase, _dal, _al, tipo, + s->_ini, s->_dare, s->_avere); + s->_fin = s->_ini; s->_fin += s->_dare; s->_fin += s->_avere; + s->_fin.normalize(); + + return s; +} + +const TSaldanal& TSaldi_cache::saldo(const char* conto, const char* costo, + const char* commessa, const char* fase, char tipo) +{ + TToken_string key; + key.add(conto, 0); + key.add(costo, 1); + key.add(commessa, 2); + key.add(fase, 3); + key.add(tipo, 4); + return *(const TSaldanal*)objptr(key); +} + +void TSaldi_cache::set_range(const TDate& dal, const TDate& al) +{ + if (_dal != dal || _al != al) + { + _dal = dal; + _al = al; + destroy(); + } +} + +TSaldi_cache _saldi; + //////////////////////////////////////////////////////// // Recordset //////////////////////////////////////////////////////// class TPiano_conti_recordset : public TISAM_recordset { + char _tipo; TString _da_conto, _a_conto; TString _codcms, _codfas, _codcosto; + TDate _dal, _al; + bool _movimentati, _nonnulli; protected: - bool valid_record(const TRelation& rel); + bool valid_record(const TRelation& rel) const; + static bool pianoconti_filter(const TRelation* rel); + virtual void set_custom_filter(TCursor& cursor) const; public: + virtual const TVariant& get(const char* column_name) const; + void set_filter(const TMask& m, int r); TPiano_conti_recordset(const char* sql); }; +const TVariant& TPiano_conti_recordset::get(const char* column_name) const +{ + if (strncmp(column_name, "SALDO:", 6) == 0) + { + const TString& conto = get(PCONANA_CODCONTO).as_string(); + const TSaldanal& s = _saldi.saldo(conto, _codcosto, _codcms, _codfas, _tipo); + const char* sub_field = column_name+6; + TVariant& var = get_tmp_var(); + if (strcmp(sub_field, "INI_DARE") == 0) + { + var = s._ini.sezione() == 'D' ? s._ini.valore() : ZERO; + } else + if (strcmp(sub_field, "INI_AVERE") == 0) + { + var = s._ini.sezione() == 'A' ? s._ini.valore() : ZERO; + } else + if (strcmp(sub_field, "MOV_DARE") == 0) + { + var = s._dare.valore(); + } else + if (strcmp(sub_field, "MOV_AVERE") == 0) + { + var = s._avere.valore(); + } else + if (strcmp(sub_field, "FIN_DARE") == 0) + { + var = s._fin.sezione() == 'D' ? s._fin.valore() : ZERO; + } else + if (strcmp(sub_field, "FIN_AVERE") == 0) + { + var = s._fin.sezione() == 'A' ? s._fin.valore() : ZERO; + } + return var; + } + if (strcmp(column_name, "#COSTO") == 0) + { + TVariant& var = get_tmp_var(); + var = _codcosto; + return var; + } + if (strcmp(column_name, "#COMMESSA") == 0) + { + TVariant& var = get_tmp_var(); + var = _codcms; + return var; + } + if (strcmp(column_name, "#FASE") == 0) + { + TVariant& var = get_tmp_var(); + var = _codfas; + return var; + } + return TISAM_recordset::get(column_name); +} + +bool TPiano_conti_recordset::valid_record(const TRelation& rel) const +{ + if (_movimentati || _nonnulli) + { + const TString& conto = rel.curr().get(PCONANA_CODCONTO); + const TSaldanal& s = _saldi.saldo(conto, _codcosto, _codcms, _codfas, _tipo); + if (_movimentati && !s._movimentato) + return false; + if (_nonnulli && s._ini.is_zero() && s._dare.is_zero() && s._avere.is_zero()) + return false; + } + return true; +} + +static const TPiano_conti_recordset* _current_recset = NULL; + +bool TPiano_conti_recordset::pianoconti_filter(const TRelation* rel) +{ return _current_recset->valid_record(*rel); } + void TPiano_conti_recordset::set_custom_filter(TCursor& cursor) const { TRectype darec = cursor.curr(); @@ -253,6 +402,17 @@ void TPiano_conti_recordset::set_custom_filter(TCursor& cursor) const darec.zero(); darec.put(PCONANA_CODCONTO, _da_conto); arec.zero(); arec.put(PCONANA_CODCONTO, _a_conto); cursor.setregion(darec, arec); + + TString filter; + int len = 0; + const TMultilevel_code_info& info = ca_multilevel_code_info(LF_PCONANA); + for (int l = info.levels()-1; l >= 0; l--) + len += info.len(l); + filter << "NUM(LEN(CODCONTO)==" << len << ")"; + cursor.setfilter(filter); + + _current_recset = this; + cursor.set_filterfunction(pianoconti_filter); } void TPiano_conti_recordset::set_filter(const TMask& m, int r) @@ -262,6 +422,14 @@ void TPiano_conti_recordset::set_filter(const TMask& m, int r) _da_conto << m.get(F_PDC1_INI+i); _a_conto << m.get(F_PDC1_FIN+i); } + + _dal = m.get(F_DATADA); + _al = m.get(F_DATAA); + _saldi.set_range(_dal, _al); + + _tipo = m.get(F_TIPOMOV)[0]; + _movimentati = m.get_int(F_STAMPAV) == 1; + _nonnulli = m.get_int(F_STAMPAV) == 2; if (r >= 0) { @@ -275,7 +443,6 @@ void TPiano_conti_recordset::set_filter(const TMask& m, int r) _codcms = rec.get(RMOVANA_CODCMS); _codfas = rec.get(RMOVANA_CODFASE); } - } TPiano_conti_recordset::TPiano_conti_recordset(const char* sql) : TISAM_recordset(sql) @@ -321,8 +488,84 @@ public: virtual void main_loop(); }; +void randomov() +{ +#ifdef DBG + TLocalisamfile fmov(LF_MOVANA); + if (fmov.first() != NOERR && yesno_box("Vuoi generare un po' di movimenti casuali?")) + { + const TMultilevel_code_info& info = ca_multilevel_code_info(LF_PCONANA); + TString filter; + int len = 0; + for (int l = info.levels()-1; l >= 0; l--) + len += info.len(l); + filter << "LEN(CODCONTO)==" << len; + + TRelation relconti(LF_PCONANA); + TCursor curconti(&relconti, filter); + const TRecnotype conti = curconti.items(); + curconti.freeze(); + + TRelation relcaus(LF_CAUSALI); + TCursor curcaus(&relcaus, "MOVIND=\"X\""); + const TRecnotype causali = curcaus.items(); + curcaus.freeze(); + + TEsercizi_contabili esc; + + for (int m = 0; m < 100; m++) + { + TAnal_mov mov; + + TDate data(TODAY); data -= rand()%365; + mov.put(MOVANA_DATAREG, data); + mov.put(MOVANA_DATACOMP, data-1L); + mov.put(MOVANA_DATADOC, data-2L); + mov.put(MOVANA_ANNOES, esc.date2esc(data)); + mov.put(MOVANA_DESCR, "Movimento random"); + switch (rand() % 10) + { + case 0: mov.put(MOVANA_TIPOMOV, "P"); break; + case 1: mov.put(MOVANA_TIPOMOV, "V"); break; + default: mov.put(MOVANA_TIPOMOV, " "); break; // Alta probabilita' + } + + if (causali > 0) + { + curcaus = rand() % causali; + mov.put(MOVANA_CODCAUS, curcaus.curr().get("CODCAUS")); + } + + const int rows = rand()%10+1; + TImporto tot; + for (int i = 0; i < rows; i++) + { + TRectype& rmov = mov.new_row(); + rmov.put(RMOVANA_DATAREG, mov.get(MOVANA_DATAREG)); + rmov.put(RMOVANA_ANNOES, mov.get(MOVANA_ANNOES)); + + curconti = rand() % conti; + rmov.put(RMOVANA_CODCONTO, curconti.curr().get(PCONANA_CODCONTO)); + const TImporto imp(i & 0x1 ? 'A' : 'D', real(10*(rand()%1000+1))); + rmov.put(RMOVANA_SEZIONE, imp.sezione()); + rmov.put(RMOVANA_IMPORTO, imp.valore()); + tot += imp; + } + + tot.normalize(); + mov.put(MOVANA_SEZIONE, tot.sezione()); + mov.put(MOVANA_TOTDOC, tot.valore()); + mov.write(fmov); + } + } +#endif +} + + void TPrint_bilancio_ca::main_loop() { + randomov(); + TPrint_bilancio_ca_mask mask; while (mask.run() != K_QUIT) { diff --git a/ca/ca3300.h b/ca/ca3300.h index feb702c56..20a8cfbf8 100755 --- a/ca/ca3300.h +++ b/ca/ca3300.h @@ -13,7 +13,8 @@ #define F_STAMPAV 311 #define F_DATADA 312 #define F_DATAA 313 -#define F_STAMPAMPROV 314 +#define F_TIPOMOV 314 +#define F_TIPOSTAMPA 315 //campi generati dal pdc #define F_PDC1_INI 316 diff --git a/ca/ca3300.uml b/ca/ca3300.uml index 48c24e607..f24272405 100755 --- a/ca/ca3300.uml +++ b/ca/ca3300.uml @@ -50,7 +50,7 @@ BEGIN DISPLAY "Data fine esercizio" D1 OUTPUT F_ANNO CODTAB FLAGS "Z" - CHECKTYPE REQUIRED + CHECKTYPE NORMAL WARNING "Esercizio assente" ADD RUN cg0 -5 esc MESSAGE K_SPACE,F_STAMPA @@ -71,7 +71,7 @@ BEGIN MESSAGE SHOW,4@|HIDE,3@ END -LIST F_STAMPAMPROV 11 +LIST F_TIPOSTAMPA 11 BEGIN PROMPT 12 4 "" ITEM "P|Preventivo" @@ -79,7 +79,7 @@ BEGIN ITEM "R|Raffronto" END -RADIUOBUTTON F_STAMPA 26 +RADIOBUTTON F_STAMPA 26 BEGIN PROMPT 31 4 "@bStampa" ITEM "1|Per date limite" @@ -105,9 +105,17 @@ BEGIN GROUP 5 END +LIST F_TIPOMOV 1 25 +BEGIN + PROMPT 2 8 "Tipo movimento " + ITEM " |Normale" + ITEM "P|Preventivo" + ITEM "V|Variazione preventivo" +END + LIST F_STAMPAV 20 BEGIN - PROMPT 2 8 "Selezione conti " + PROMPT 2 9 "Selezione conti " ITEM "1|Movimentati" ITEM "2|Con saldo non nullo" ITEM "3|Tutti" @@ -116,20 +124,20 @@ END BOOLEAN F_CODICI BEGIN - PROMPT 42 8 "Non stampare codici conti " + PROMPT 42 9 "Non stampare codici conti " GROUP 4 END STRING F_REPORT 256 66 BEGIN - PROMPT 2 9 "Report " + PROMPT 2 10 "Report " FLAGS "B" CHECKTYPE REQUIRED END SPREADSHEET F_RIGHE BEGIN - PROMPT 0 10 "" + PROMPT 0 11 "" ITEM "Cdc 1" ITEM "Cdc 2" ITEM "Cdc 3" diff --git a/ca/calib02.cpp b/ca/calib02.cpp index e4151e112..dd5edea5a 100755 --- a/ca/calib02.cpp +++ b/ca/calib02.cpp @@ -3,6 +3,14 @@ #include "calib01.h" #include "calib02.h" +#include "movana.h" +#include "rmovana.h" +#include "saldana.h" + +/////////////////////////////////////////////////////////// +// TAnal_report +/////////////////////////////////////////////////////////// + bool TAnal_report::get_usr_val(const TString& name, TVariant& var) const { // CODCONTO:1, CODCMS:3, FASCMS:2, ecc... @@ -105,7 +113,6 @@ void TAnal_report::msg_format_conto (TVariant_stack& stack) void TAnal_report::msg_format_commessa_costo(TVariant_stack& stack) { const TMultilevel_code_info& main_info = ca_multilevel_code_info(LF_FASI); - msg_format(main_info.parent(), stack); } @@ -126,3 +133,144 @@ bool TAnal_report::execute_usr_word(unsigned int opcode, TVariant_stack& stack) return true; } +/////////////////////////////////////////////////////////// +// TAnal_balance +/////////////////////////////////////////////////////////// + +TImporto TAnal_balance::saldo_fine_anno(const char* conto, const char* costo, + const char* commessa, const char* fase, + int anno, char tipo) const +{ + TImporto saldo; + + if (anno > 0) + { + TString query, select; + + if (costo && *costo) + select << "(CODCOSTO=='" << costo << "')"; + if (commessa && *commessa) + { + if (select.not_empty()) select << "&&"; + select << "(CODCMS=='" << commessa << "')"; + } + if (fase && *fase) + { + if (select.not_empty()) select << "&&"; + select << "(FASCMS=='" << fase << "')"; + } + + query << "USE SALDANA"; + if (select.not_empty()) + query << "SELECT " << select; + query << "\nFROM CONTO=#CONTO" + << "\nTO CONTO=#CONTO ANNO=#ANNO"; + + TString4 strtipo; strtipo << tipo; + TISAM_recordset saldini(query); + saldini.set_var("#CONTO", TVariant(conto)); + saldini.set_var("#ANNO", TVariant(long(anno))); + + TString8 sezname = SALDANA_SEZIONE; + TString8 salname = SALDANA_SALDO; + if (tipo == 'P' || tipo == 'V') + { + sezname << tipo; + salname << tipo; + } + + for (int i = 0; i < saldini.items(); i++) + { + const char sez = saldini.get(sezname).as_string()[0]; + const real imp = saldini.get(salname).as_real(); + saldo += TImporto(sez, imp); + } + saldo.normalize(); + } + + return saldo; +} + +bool TAnal_balance::saldo_movimenti(const char* conto, const char* costo, + const char* commessa, const char* fase, + const TDate& dal, const TDate& al, char tipo, + TImporto& ini, TImporto& dare, TImporto& avere) const +{ + TString4 strtipo; + if (tipo > ' ') + strtipo << tipo; + + TDate dataini; + if (dal.ok()) + { + TEsercizi_contabili esc; + const int annoprec = esc.date2prevesc(dal); + if (annoprec > 0) + dataini = esc[annoprec].fine()+1L; + } + + TString query; + query << "USE RMOVANA KEY 2\n" + << "SELECT (107.TIPOMOV=\"" << strtipo << "\")"; + if (dataini.ok()) + query << "&&(ANSI(107.DATACOMP)>=" << dataini.date2ansi() << ")"; + if (al.ok()) + query << "&&(ANSI(107.DATACOMP)<=" << al.date2ansi() << ")"; + if (costo && *costo) + query << "&&(CODCOSTO==\"" << costo << "\")"; + if (commessa && *commessa) + query << "&&(CODCMS==\"" << commessa << "\")"; + if (fase && *fase) + query << "&&(CODFASE==\"" << fase << "\")"; + query << "\nJOIN MOVANA INTO NUMREG==NUMREG\n"; + + query << "FROM CODCONTO=" << conto; + if (dataini.ok()) + query << " DATAREG=" << TDate(dataini-90L).string(); + query << "\n"; + + query << "TO CODCONTO=" << conto; + if (al.ok()) + query << " DATAREG=" << al.string(); + query << "\n"; + + TISAM_recordset rmovana(query); + + bool movimentato = false; + for (int i = 0; i < rmovana.items(); i++) + { + rmovana.move_to(i); + + const TDate data = rmovana.get("107.DATACOMP").as_date(); + const TImporto imp(rmovana.get(RMOVANA_SEZIONE).as_string()[0], + rmovana.get(RMOVANA_IMPORTO).as_real()); + if (data >= dal) + { + if (imp.sezione() == 'D') + dare += imp; + else + avere += imp; + movimentato = true; + } + else + { + ini += imp; + } + } + ini.normalize(); + + return movimentato; +} + +bool TAnal_balance::saldi(const char* conto, const char* costo, + const char* commessa, const char* fase, + const TDate& dal, const TDate& al, char tipo, + TImporto& ini, TImporto& dare, TImporto& avere) const +{ + TEsercizi_contabili esc; + const int annoprec = esc.date2prevesc(dal); + ini = saldo_fine_anno(conto, costo, commessa, fase, annoprec, tipo); + const bool mov = saldo_movimenti(conto, costo, commessa, fase, dal, al, tipo, + ini, dare, avere); + return mov; +} diff --git a/ca/calib02.h b/ca/calib02.h index 07a5d1a4b..9547c700d 100755 --- a/ca/calib02.h +++ b/ca/calib02.h @@ -29,4 +29,25 @@ protected: // protected is safer public: // meglio pubic? }; +/////////////////////////////////////////////////////////// +// TAnal_balance +/////////////////////////////////////////////////////////// + +class TAnal_balance : public TObject +{ +public: + TImporto saldo_fine_anno(const char* conto, const char* costo, + const char* commessa, const char* fase, + int annofin, char tipo) const; + bool saldo_movimenti(const char* conto, const char* costo, + const char* commessa, const char* fase, + const TDate& dal, const TDate& al, char tipo, + TImporto& ini, TImporto& dare, TImporto& avere) const; + bool saldi(const char* conto, const char* costo, + const char* commessa, const char* fase, + const TDate& dal, const TDate& al, char tipo, + TImporto& ini, TImporto& dare, TImporto& avere) const; +}; + + #endif diff --git a/ca/f108.trr b/ca/f108.trr index e82ffcec5..6765f2be5 100755 --- a/ca/f108.trr +++ b/ca/f108.trr @@ -18,4 +18,4 @@ CODFASEORI|1|10|0|Codice fase originario CODCONTORI|1|20|0|Codice conto originario 2 NUMREG+NUMRIG| -CODCCOSTO+CODCMS+DATAREG+NUMREG+NUMRIG|X +CODCONTO+DATAREG+NUMREG+NUMRIG|X