#include #include #include #include #include #include #include #include "sv1.h" #include "sv1200a.h" #include "sv1200b.h" #include "sv1200c.h" #include "svlib01.h" #include "svriep.h" #include "svstat.h" #include "../mg/anamag.h" #include "../mg/mglib.h" #include "../mg/umart.h" #include "../pr/agenti.h" #include "../ve/clifor.h" #define STR_TOTGEN "T" #define STR_TIPODOC "D" #define STR_UMISURA "U" #define STR_ARTICOLO "A" #define STR_LIVGIAC "L" #define STR_CATVEN "V" #define STR_CLIFOR "C" #define STR_AGENTE "G" #define STR_MAGAZZ "M" #define STR_ZONA "Z" #define STR_ARTFIELD "B" #define CHR_TOTGEN 'T' #define CHR_TIPODOC 'D' #define CHR_UMISURA 'U' #define CHR_ARTICOLO 'A' #define CHR_LIVGIAC 'L' #define CHR_CATVEN 'V' #define CHR_CLIFOR 'C' #define CHR_CLI 'C' #define CHR_FOR 'F' #define CHR_AGENTE 'G' #define CHR_MAGAZZ 'M' #define CHR_ZONA 'Z' #define CHR_ARTFIELD 'B' #define COMP_AS_VALUE 'V' #define COMP_AS_DIFF 'D' #define COMP_AS_PERC 'P' #define COLONNA_VALORE "V" #define COLONNA_QTA "Q" #define COLONNA_ENTRAMBI "E" #define ALG_VALORI 'V' #define ALG_PROGRESSIVI 'P' #define ALG_MOBILI 'M' #define LARG_COLCODICE 49 #define POS_PRIMACOL 51 #define PICTURE_VALORI "###.###.###.##@" #define LARG_COLVAL 16 #define PICTURE_QUANTITA "###.###.##@,@##" #define LARG_COLQTA 16 #define PICTURE_PERCENT "###@,@" #define LARG_COLPERC 8 #define FORMWIDTH 150 #define DEFAULT_OUTFILE "outstat0" /////////////////////////////////////////////////////////// // TPeriodo /////////////////////////////////////////////////////////// class TPeriodo : public TSortable { static TFrequenza_statistiche _frequenza; int _anno; int _periodo; protected: virtual int compare(const TSortable& s) const; void set(const TPeriodo& ap) { set(ap._anno, ap._periodo); } public: static void set_frequency(TFrequenza_statistiche f) { CHECK(f != fs_nulla, "Frequenza nulla"); _frequenza = f; } static TFrequenza_statistiche frequency() { return _frequenza; } int operator -(const TPeriodo& ap) const; int difference(const TPeriodo& p, TFrequenza_statistiche freq) const; const TPeriodo& operator +=(int n); const TPeriodo& sum(int n, TFrequenza_statistiche freq); TDate first_day() const; TDate last_day() const; void set_year(int y); void set_period(int p); void set(int y, int p) { set_year(y); set_period(p); } void set(const TDate& d); const TPeriodo& operator=(const TPeriodo& ap) { set(ap); return ap; } const TPeriodo& operator=(const TDate& d) { set(d); return *this; } TPeriodo() : _anno(1900), _periodo(1) { } TPeriodo(int anno, int periodo) { set(anno, periodo); } TPeriodo(const TDate& d) { set(d); } TPeriodo(const TPeriodo& ap) { set(ap); } virtual ~TPeriodo() { } }; TFrequenza_statistiche TPeriodo::_frequenza = fs_nulla; int TPeriodo::compare(const TSortable& s) const { const TPeriodo& ap = (const TPeriodo&)s; int diff = _anno - ap._anno; if (diff == 0) diff = _periodo - ap._periodo; return diff; } int TPeriodo::operator -(const TPeriodo& ap) const { int result = 0; int annomin, periodomin, annomax, periodomax; const bool swapped = compare(ap) < 0; if (swapped) { annomin = _anno; periodomin = _periodo; annomax = ap._anno; periodomax = ap._periodo; } else { annomin = ap._anno; periodomin = ap._periodo; annomax = _anno; periodomax = _periodo; } if (annomin < annomax) { result += last_period(annomin, _frequenza) - periodomin + 1; for (annomin++; annomin < annomax; annomin++) result += last_period(annomin, _frequenza); periodomin = 1; } result += periodomax - periodomin; return swapped ? -result : result; } int TPeriodo::difference(const TPeriodo& p, TFrequenza_statistiche freq) const { CHECK(freq > _frequenza, "Incomputable difference"); const TDate d1 = first_day(); const TDate d2 = p.first_day(); const TFrequenza_statistiche old_freq = _frequenza; _frequenza = freq; const TPeriodo p1(d1); const TPeriodo p2(d2); const int diff = p1 - p2; _frequenza = old_freq; return diff; } const TPeriodo& TPeriodo::operator +=(int n) { // Sembra orrendo ma per ora e' modo piu' sicuro! if (n >= 0) { int lp = last_period(_anno, _frequenza); for (int i = n; i > 0; i--) { _periodo++; if (_periodo > lp) { _anno++; _periodo = 1; lp = last_period(_anno, _frequenza); } } } else { for (int i = n; i < 0; i++) { _periodo--; if (_periodo <= 0) { _anno--; _periodo = last_period(_anno, _frequenza); } } } return *this; } const TPeriodo& TPeriodo::sum(int n, TFrequenza_statistiche freq) { CHECK(freq > _frequenza, "Incomputable sum"); TDate d = first_day(); const TFrequenza_statistiche old_freq = _frequenza; _frequenza = freq; TPeriodo p1(d); p1 += n; d = p1.first_day(); _frequenza = old_freq; set(d); return *this; } TDate TPeriodo::first_day() const { TDate d(1, 1, _anno); switch(_frequenza) { case fs_annuale : break; case fs_semestrale : if (_periodo > 1) d.set_month(7); break; case fs_quadrimestrale: d.set_month((_periodo - 1) * 4 + 1); break; case fs_trimestrale : d.set_month((_periodo - 1) * 3 + 1); break; case fs_bimestrale : d.set_month((_periodo - 1) * 2 + 1); break; case fs_mensile : d.set_month(_periodo); break; case fs_quindicinale : d.set_month((_periodo - 1) / 2 + 1); if ((_periodo & 0x1) == 0) d.set_day(16); break; case fs_settimanale : d += 7 * (_periodo - 1); break; case fs_giornaliera : d += _periodo - 1; } return d; } TDate TPeriodo::last_day() const { TDate d = first_day(); ceil(d, _frequenza); return d; } void TPeriodo::set_year(int y) { CHECKD(y >= 1900 && y < 3000, "Bad year ", y); _anno = y; } void TPeriodo::set_period(int p) { CHECKD(p > 0 && p <= last_period(_anno, _frequenza), "Bad period ", p); _periodo = p; } void TPeriodo::set(const TDate& d) { set(d.year(), date2period(d, _frequenza)); } /////////////////////////////////////////////////////////// // TFrequenza_colonne /////////////////////////////////////////////////////////// class TFrequenza_colonne : public TObject { TFrequenza_statistiche _frequenza; int _multiplo; TPeriodo _periodo_inizio; TDate _data_inizio; public: void init(TFrequenza_statistiche f, int m, const TDate& d); int period2column(const TPeriodo& p) const; int date2column(const TDate& d) const; TDate column_first_day(int n) const; TDate column_last_day(int n) const; const TPeriodo& inizio() const { return _periodo_inizio; } }; void TFrequenza_colonne::init(TFrequenza_statistiche f, int m, const TDate& d) { // _frequenza = (f == fs_nulla || m <= 0) ? TPeriodo::frequency() : f; _frequenza = (f == fs_nulla || m >0) ? TPeriodo::frequency() : f; _multiplo = (m <= 0) ? divide(_frequenza, TPeriodo::frequency()) : m; _periodo_inizio = d; _data_inizio = _periodo_inizio.first_day(); } int TFrequenza_colonne::period2column(const TPeriodo& p) const { int result; if (_multiplo > 0) { int diff = p - _periodo_inizio; result = diff / _multiplo; // Corregge arrotondamento per periodi inferiori a _periodo_inizio // ad esempio: -1 / 12 = 0 e non -1 (risultato corretto) if (diff < 0 && ((diff % _multiplo) != 0)) result--; } else result = p.difference(_periodo_inizio, _frequenza); return result; } int TFrequenza_colonne::date2column(const TDate& d) const { const TPeriodo p(d); return period2column(p); } TDate TFrequenza_colonne::column_first_day(int n) const { TPeriodo p(_periodo_inizio); if (_multiplo > 0) p += n * _multiplo; else p.sum(n, _frequenza); TDate d = p.first_day(); return d; } TDate TFrequenza_colonne::column_last_day(int n) const { TDate d = column_first_day(n+1); --d; return d; } /////////////////////////////////////////////////////////// // Stampa statistiche /////////////////////////////////////////////////////////// class TStampa_stat : public TPrint_application { enum { MAX_ROWS = 8 }; // numero massimo di raggruppamenti enum { LINEA_DATI='D', LINEA_RAFFRONTI='R', LINEA_TARGET='T'}; // codici per le righe TMask * _msk, *_print_msk,*_export_msk; TStats_agg _stats; TFrequenza_colonne _freq; TCodart_livelli* _liv_art; TCodgiac_livelli* _liv_giac; TRecord_cache *_tipodoc,*_catven, *_umart; TToken_string _key; TString _last_key; TRectype * _last_data; TString_array _des_fld; TString_array _file_fld; TString_array _key_fld; TString_array _field_fld; bool _ragg_per_um; // ****************** // costruzione file di Output TStat_cache * _svcache; // cache R/W per le statistiche int _last_lev_grp, // livello dell'ultimo raggruppamento incontrato _liv_riga; // livello della riga TArray _group_recs; // array dei record dei raggruppamenti TArray _group_recs_raff; // array dei record dei raggruppamenti (raffronti) int _indent[MAX_ROWS];// array delle posizione di indentazione real _totval_riga[SVS_NUMCOLONNE]; //array dei totali degli "anni" della riga real _totqta_riga[SVS_NUMCOLONNE]; //array dei totali degli "anni" della riga int _colpage, // numero di pagina ripetuta per contenere in larghezza tutte le colonne _last_page; // ultima pagina della "prima copia" int _larg[7]; int _largcol, // larghezza di una colonna _numcol_dati, // numero di colonne contenenti dati _numcol, // numero totale di colonne (dati+totali) _pagewidth, // larghezza di una pagina _col_anno ; // numero di colonne che formano un "Anno" (=periodo di rif.) bool _st_totr; // flag stampa totali di riga bool _st_totc; // flag stampa totali di colonna bool _st_tota; // flag stampa totali di "anno" bool _st_val; // Stampa valori bool _st_qta; // Stampa quantita' bool _st_uni; // Stampa valori/quantita' TString16 _valid_types;// Stringa contenente i tipi di riga da stampare // ****************** // stampa file di Output TString _wrk_row, _save_code; // stringhe di lavoro per le righe di stampa TRelation * _rel; // relazione per la stampa private: void put_column(TRectype & statrec,int col, const TSVriep_record& curr); const real fc_um(const TRectype& statrec,const TSVriep_record& rieprec); void invalid_columns(TRectype & statrec); void standardize_um(TSVriep_record& rieprec, bool force=FALSE); // generazione del file di output void set_ragg_per_um(); bool filtro_chiavi(TSVriep_record &curr); void update_file(const char * key, const char * code,const char tipo, const int level, const int col, TSVriep_record& curr, const TString & fld, int row); void genera_file(const char *outfn); // handler per i campi di maschera static bool chiave_notify(TSheet_field& f, int r, KEY k); static bool chiave_handler(TMask_field& f, KEY k); static bool campo_handler(TMask_field& f, KEY k); static bool artfld_handler(TMask_field& f, KEY k); static bool filename_handler(TMask_field& f, KEY k); static bool codice_handler(TMask_field& f, KEY k); static bool multiplo_handler(TMask_field& f, KEY k); static bool numero_handler(TMask_field& f, KEY k); static bool periodo_handler(TMask_field& f, KEY k); static bool dataini_handler(TMask_field& f, KEY k); static bool datafin_handler(TMask_field& f, KEY k); static bool raffronto_handler(TMask_field& f, KEY k); static bool dataraf_handler(TMask_field& f, KEY k); protected: virtual bool user_create(); virtual bool user_destroy(); virtual bool set_print(int i); virtual void set_page(int file, int count); virtual bool preprocess_print(int file, int counter) ; virtual print_action postprocess_print(int file, int counter); virtual bool preprocess_page(int file, int counter); virtual print_action postprocess_page(int file, int counter); virtual void preprocess_header(); virtual void preprocess_footer(); virtual void on_config_change(); void set_descr(int& row); int handle_levchange(int row,const int level); int set_rows_colonne(int row, const TRectype &strec); void set_row_atpos(char section,int row,const char * f,int pos); void set_filled_row(char section,int row,char c,int pos, int len); void reset_grplevels(); bool test_field(const TString& cod, TMask_field& f) const; void set_printmask(); void fill_field_list(TMask& m); void set_frequency(); bool set_column_frequency(); bool recalc_period(); TString& build_key(const TRectype& rec); const TString& nome_colonna1(int c, TString& nome); const TString& nome_colonna2(int c, TString& nome); const TString& nome_totale(int t, TString& nome); const TString& partkey_name(const char *lev_code, int row, TString& park) const; const TString& get_part(TString & lev_code, TSVriep_record & rieprec, const TString & fld); // const; const TString& get_descrpart(const char *lev_code, TSVriep_record &rieprec, const TString & fld, int row); void adjust_record(TRectype &strec, int from) const; int numlevels() const { return selmask().sfield(F_CHIAVE).items(); } public: TMask& selmask() const { return *_msk; } TMask& printmask() const { return *_print_msk; } TMask& expmask() const { return *_export_msk; } virtual bool menu(MENU_TAG); TStampa_stat() {} virtual ~TStampa_stat() { } }; inline TStampa_stat& app() { return (TStampa_stat&)main_app(); } print_action TStampa_stat::postprocess_print(int file, int count) { reset_footer(); reset_header(); _last_page=get_page_number(); _colpage++; //printer().formfeed(); return TPrint_application::postprocess_print(file,count); } bool TStampa_stat::preprocess_page(int file, int count) { return TPrint_application::preprocess_page(file,count); } print_action TStampa_stat::postprocess_page(int file, int count) { reset_print(); return TPrint_application::postprocess_page(file,count); } bool TStampa_stat::set_print(int i) { if (printmask().run() == K_QUIT) return FALSE; _st_totr=printmask().get_bool(F_STTOTALIRIGA); _st_totc=printmask().get_bool(F_STTOTALICOL); _st_tota=printmask().get_bool(F_STTOTALIANNO); _largcol = 0; for (int l = 0; l < 7; l++) _larg[l] = 0; if (_st_val) { _largcol += LARG_COLVAL; _larg[0] = LARG_COLVAL; if (printmask().get_bool(F_STRAFFRONTO)) { switch (printmask().get(F_TIPORAFFRONTO)[0]) { case COMP_AS_DIFF: _largcol += LARG_COLVAL; _larg[1] = LARG_COLVAL; break; case COMP_AS_PERC: _largcol += LARG_COLPERC; _larg[1] = LARG_COLPERC; break; case COMP_AS_VALUE: default: break; } } if (_st_totr) { _largcol += LARG_COLPERC; _larg[2] = LARG_COLPERC; } } if (_st_qta) { _largcol += LARG_COLQTA; _larg[3] = LARG_COLVAL; if (printmask().get_bool(F_STRAFFRONTO)) { switch (printmask().get(F_TIPORAFFRONTO)[0]) { case COMP_AS_DIFF: _largcol += LARG_COLVAL; _larg[4] = LARG_COLVAL; break; case COMP_AS_PERC: _largcol += LARG_COLPERC; _larg[4] = LARG_COLPERC; break; case COMP_AS_VALUE: default: break; } } if (_st_totr) { _largcol += LARG_COLPERC; _larg[5] = LARG_COLPERC; } } if (_st_uni) { _largcol += LARG_COLVAL; _larg[6] = LARG_COLVAL; } if (_largcol <= 0) _largcol = 1; _numcol_dati = selmask().get_int(F_PERIODO); _col_anno =min(_numcol_dati,printmask().get_int(F_COLANNO)); //numero di colonne che formano un "Anno" if (_col_anno <= 0) _col_anno = 12; // ??? _numcol = _numcol_dati+ (_st_tota ? int((_numcol_dati -1)/_col_anno+1) : 0); // _pagewidth=POS_PRIMACOL+int((printer().formwidth()-POS_PRIMACOL)/_largcol)*_largcol; _pagewidth=POS_PRIMACOL+int((printer().calc_num_cols()-POS_PRIMACOL)/_largcol)*_largcol; // reset delle variabili per la gestione di gruppi ai vari livelli _colpage=1; _last_page=0; reset_grplevels(); // setta header e footer int row=0; // resetta _save_code per stampare linee raffronti nel caso non abbiano la corrispondente linea dati _save_code = ""; reset_header(); reset_footer(); printer().footerlen(3); return TRUE; } bool TStampa_stat::preprocess_print(int file, int counter) { // _pagewidth=POS_PRIMACOL+int((printer().formwidth()-POS_PRIMACOL)/_largcol)*_largcol; return TRUE; } void TStampa_stat::preprocess_footer() { set_filled_row('F',1,'_',0,_pagewidth); _wrk_row.format(FR("Pagina @#"),get_page_number()-_last_page*(_colpage-1)); set_row_atpos('F',2,_wrk_row,(_colpage-1)*_pagewidth+(_pagewidth-9)/2); } void TStampa_stat::preprocess_header() { int bkg=0,col=0,row=0,lastrow; // ***************** // header set_header(++row,""); set_header(++row,""); if (selmask().get(F_DESCR).empty()) set_row_atpos('H',++row,FR("@bStampa statistiche "),0); else { _wrk_row.format("@b%s",(const char *)selmask().get(F_DESCR)); set_row_atpos('H',++row,(const char *)_wrk_row,0); _wrk_row.format(FR("dal %s al %s "),(const char *)selmask().get(F_DATAINI),(const char *)selmask().get(F_DATAFIN)); set_row_atpos('H',row,(const char *)_wrk_row,51); if (printmask().get_bool(F_STRAFFRONTO )) { _wrk_row.format(FR("confrontata con i corrispondenti periodi a partire dal %s"),(const char *)selmask().get(F_DATARAF)); set_row_atpos('H',++row,(const char *)_wrk_row,0); } } set_header(++row,""); set_row_atpos('H',++row,FR(" Codice @23gDescrizione"),0); lastrow=row; for (int c=0; c < _numcol; c++) // colonne { if (_st_tota && c && (((c+1)%(_col_anno+1))==0 || c==_numcol-1) ) { nome_totale(1+int((c-1)/_col_anno), _wrk_row); set_row_atpos('H',row,_wrk_row,POS_PRIMACOL+c*_largcol+_largcol/2 ); } else { TString col1, col2; int pos = POS_PRIMACOL+c*_largcol; nome_colonna1(col, col1); nome_colonna2(col, col2); col1 << ' ' << col2; const int l = col1.len(); TParagraph_string s(col1, _largcol); col1 = s.get(); col1.center_just(_largcol); set_row_atpos('H', row, col1, pos); col2 = s.get(); if (col2.empty()) lastrow = row + 1; else { col2.center_just(_largcol); set_row_atpos('H', row + 1, col2, pos); lastrow = row + 2; } if (_st_val) { pos += _larg[0]; set_row_atpos('H',lastrow,TR("Valore"), pos - 7); if (printmask().get_bool(F_STRAFFRONTO)) { pos += _larg[1]; switch (printmask().get(F_TIPORAFFRONTO)[0]) { case COMP_AS_DIFF: set_row_atpos('H',lastrow,TR("Differenza"), pos - 11); break; case COMP_AS_PERC: set_row_atpos('H',lastrow,TR("%%Diff"), pos - 7); break; case COMP_AS_VALUE: default: break; } } if (_st_totr) { set_row_atpos('H', lastrow, TR("Perc."), pos); pos += _larg[2]; } } if (_st_qta) { pos += _larg[3]; set_row_atpos('H',lastrow,TR("Quantita'"),pos - 12); if (printmask().get_bool(F_STRAFFRONTO)) { pos += _larg[4]; switch (printmask().get(F_TIPORAFFRONTO)[0]) { case COMP_AS_DIFF: set_row_atpos('H',lastrow,TR("Differenza"), pos - 13); break; case COMP_AS_PERC: set_row_atpos('H',lastrow,TR("%%Diff"), pos - 7); break; case COMP_AS_VALUE: default: break; } } if (_st_totr) { set_row_atpos('H', lastrow, TR("Perc."), pos); pos += _larg[5]; } } if (_st_uni) set_row_atpos('H',lastrow,TR("Valore medio"), pos + _larg[6] - 12); col++; } } row=lastrow; set_header(++row,""); // ***************** // background const int lasthline=(printmask().get_bool(F_STRAFFRONTO )? 5 :4); _wrk_row.format("PnW1l(1,2,%d,2)l(1,%d,%d,%d)l(1,%d,%d,%d)",_pagewidth,lasthline,_pagewidth,lasthline,row,_pagewidth,row); row++; set_background(_wrk_row); } const TString& TStampa_stat::nome_colonna1(int c, TString& s_park) { const char code_freq=selmask().get(F_MULTIPLO)[0]; const TFrequenza_statistiche freq = char2frequency(code_freq); const TFrequenza_statistiche maskfreq = char2frequency(selmask().get(F_FREQUENZA)[0]); const int numero=selmask().get_int(F_NUMERO); // numero di periodi in una col const TDate din=selmask().get(F_DATAINI); // data iniziale const int start=date2period(din,freq); // periodo della prima colonna const int lastp=last_period(din,freq); // numero di periodi in un anno if (freq == maskfreq && numero > 1 && maskfreq != fs_giornaliera) { // numerico; può essere un qualsiasi multiplo della freq s_park.format("%s %d÷%d",(const char *)char2freqname(code_freq),1+(start+c*numero-1)%lastp , 1+(start+(c+1)*numero-2)%lastp); } else { if (freq == maskfreq && maskfreq == fs_giornaliera && numero>1) { // Le date vanno da qualsiasi giorno a qualsiasi giorno TDate dfrom(app()._freq.column_first_day(c)); s_park.format("Dal %s",(const char *)dfrom.string()); } else switch (freq) { case fs_giornaliera: { TDate d = din; d += c*numero; s_park.format("%s",(const char*)itow(d.wday())); } break; case fs_settimanale: case fs_quindicinale: case fs_bimestrale: case fs_trimestrale: case fs_quadrimestrale: case fs_semestrale: s_park.format("%d^%s",1+(start+c-1)%lastp,(const char *)char2freqname(code_freq)); break; case fs_annuale: s_park.format(FR("Anno %d"),din.year()+start+c-1); break; case fs_mensile: s_park.format("%s",itom(start+c) ); break; } } // s_park.center_just(_largcol); return s_park; } const TString& TStampa_stat::nome_colonna2(int c, TString& s_park) { const TDate din=selmask().get(F_DATAINI); // data iniziale const char code_freq=selmask().get(F_MULTIPLO)[0]; const int numero=selmask().get_int(F_NUMERO); // numero di periodi in una col const TFrequenza_statistiche freq = char2frequency(code_freq); const TFrequenza_statistiche maskfreq = char2frequency(selmask().get(F_FREQUENZA)[0]); const int lastp=last_period(din,freq); // numero di periodi in un anno const int start=date2period(din,freq); // periodo della prima colonna s_park.cut(0); if (freq == maskfreq && numero > 1 && maskfreq==fs_giornaliera) { TDate dto(app()._freq.column_last_day(c)); s_park.format(FR("Al %s"),(const char *)dto.string()); } else { switch (freq) { case fs_giornaliera: { TDate d = din; d += c*numero; s_park.format("%s",(const char *)d.string()); } break; case fs_annuale: break; case fs_mensile: s_park.format("%d",din.year()+int((start+c-1)/lastp)); break; case fs_settimanale: case fs_quindicinale: case fs_bimestrale: case fs_trimestrale: case fs_quadrimestrale: case fs_semestrale: s_park.format(FR(" anno %d"),din.year()+int((start+c-1)/lastp)); break; } } return s_park; } const TString& TStampa_stat::nome_totale(int c, TString& s_park) { const char code_freq=selmask().get(F_MULTIPLO)[0]; s_park.cut(0); { switch (code_freq) { case fs_giornaliera: // giorno case fs_settimanale: case fs_quindicinale: case fs_mensile: case fs_bimestrale: case fs_trimestrale: case fs_quadrimestrale: case fs_semestrale: case fs_annuale: default: s_park.format(FR("Totale %d"),c); } } return s_park; } void TStampa_stat::set_descr(int& row) { const int MAX_DESC_LEN = 27; TRectype& strec = current_cursor()->curr(); TParagraph_string descr("",MAX_DESC_LEN); // Spezzatura manuale, per evitare righe accavallate TString r; const int lastlev = numlevels(); const int level = strec.get_int(SVS_LIVELLO); int lencode = 0; if (_group_recs.objptr(level+1)) { const TRectype& rec_grp= (const TRectype&)_group_recs[level+1]; lencode = rec_grp.get(SVS_CODICE).len(); } adjust_record(strec,lencode); partkey_name(strec.get(SVS_LEVCODE), lastlev - level - 1, r); r.upper(0,0); if (r.blank()) r.cut(0); else r << " "; r << strec.get(SVS_CODICE).mid(lencode); descr = strec.get(SVS_DESCR); if (descr.not_empty()) r << "@23g" << descr.get(0); set_row_atpos('R',++row,(const char *)r,_indent[level]); // Seconda riga eventuale... const int items = descr.items(); if (items > 1) { r = ""; r << descr.get(1); // Sfrutta al massimo la seconda riga, mettendo anche il terzo elemento // e cmq trimmando al 25o carattere if (items > 2) { r << " " << descr.get(2); if (r.len() > MAX_DESC_LEN) r.cut(MAX_DESC_LEN); } r.insert("@23g"); set_row_atpos('R',++row,(const char *)r,_indent[level]); } } void TStampa_stat::set_page(int file, int count) { // prepara la pagina di stampa TRectype& strec = current_cursor()->curr(); const int level = strec.get_int(SVS_LIVELLO); const int lastlev = numlevels(); int row=0; // ***************** // gestione totali di raggruppamento row = handle_levchange(row, level); const char tipo_riga = *strec.get(SVS_TIPO); if (level > 0) { // salva i record dei livelli di raggruppamento if (level == lastlev) strec.zero(SVS_CODICE); switch (tipo_riga) { case LINEA_DATI: _group_recs.add(strec,level); break; case LINEA_RAFFRONTI: _group_recs_raff.add(strec,level); break; } } // ***************** // gestione delle "righe" if (level != lastlev && printmask().get_bool(F_FLAGSTOTALI+lastlev-level)) { switch (tipo_riga) { case LINEA_DATI: if (level >= _liv_riga) { _save_code = strec.get(SVS_CODICE); set_descr(row); } if (level == _liv_riga) row = set_rows_colonne(row, strec); break; case LINEA_RAFFRONTI: if (printmask().get_bool(F_STRAFFRONTO)) { if (_save_code != strec.get(SVS_CODICE)) { TRectype stempty(LF_SVSTAT); stempty.put(SVS_CODICE,strec.get(SVS_CODICE)); stempty.put(SVS_LEVCODE,strec.get(SVS_LEVCODE)); stempty.put(SVS_LIVELLO,strec.get(SVS_LIVELLO)); stempty.put(SVS_TIPO,strec.get(SVS_TIPO)); set_descr(row); row = set_rows_colonne(row, stempty); } if (level == _liv_riga) row = set_rows_colonne(++row, strec); } break; } } // ***************** // totale generale e break di livello if (current_cursor()->pos() == current_cursor()->items()-1) { handle_levchange(row, numlevels()); } } // fa le set row per la "riga" contenente i valori delle colonne di statistica int TStampa_stat::set_rows_colonne(int row, const TRectype &strec) { TRectype &last_data = *_last_data; TString16 colname; TString r_totc; real col_value; bool aggiungi_perc=TRUE; int col=0; // contatore di colonna corrente int position; // posizione fisica della colonna corrente // ********** // setta i totali di riga if (strec.get_char(SVS_TIPO)==LINEA_DATI || strec.get_char(SVS_TIPO)==LINEA_RAFFRONTI && printmask().get(F_TIPORAFFRONTO)[0]==COMP_AS_VALUE) { for (col = 0; col < _numcol_dati; col++) { colname.format("%c%d", SVS_VALCOLNAME, col); const int idx = int(col/_col_anno); if (col%_col_anno == 0) _totval_riga[idx] = _totqta_riga[idx] = ZERO; _totval_riga[idx] += strec.get_real(colname); colname.format("%c%d", SVS_QTACOLNAME, col); _totqta_riga[idx] += strec.get_real(colname); } } // ********** // setta le colonne TString pictures[3]; TCurrency currency; for (int t = 0; t < 3; t++) { TString& pic = pictures[t]; if (t == 1) { pic = PICTURE_QUANTITA; continue; } currency.set_price(t == 2); const int dec = currency.decimals(); pic = PICTURE_VALORI; if (dec > 0) { pic << ','; for (int d = 0; d < dec; d++) pic << '@'; if (pic.len() > LARG_COLVAL) { pic.ltrim(pic.len() - LARG_COLVAL); if (pic[0] == '.') pic[0] = '#'; } } } col = 0; for (int c = 0; c < _numcol_dati; c++) { const int idx = int(c / _col_anno); position = POS_PRIMACOL + col*_largcol; for (int t = 0; t < 3; t++) // Ciclo su valore, quantita' e unitario { if (t == 0 && !_st_val) continue; if (t == 1 && !_st_qta) continue; if (t == 2 && !_st_uni) continue; const real& tot_riga = t == 1 ? _totqta_riga[idx] : _totval_riga[idx]; colname.format("%c%d", t == 1 ? SVS_QTACOLNAME : SVS_VALCOLNAME, c); const TString& PICT = pictures[t]; real colval = strec.get_real(colname); if (t == 2) { colname.format("%c%d", SVS_QTACOLNAME, c); const fraction valun(colval, strec.get_real(colname)); colval = valun; } int offset = (t - 1) * 3; if (offset >= 0) position += _larg[offset + 0] + _larg[offset + 1] + _larg[offset + 2]; offset += 3; switch (strec.get_char(SVS_TIPO)) { case LINEA_DATI: last_data=strec; set_row_atpos('R',row,colval.string(PICT),position); break; case LINEA_RAFFRONTI: switch (printmask().get(F_TIPORAFFRONTO)[0]) { case COMP_AS_VALUE: set_row_atpos('R',row, colval.string(PICT),position); break; case COMP_AS_DIFF: if (t < 2) { set_row_atpos('R',row, colval.string(PICT),position); set_row_atpos('R',row,((real)(last_data.get_real(colname)-strec.get_real(colname))).string(PICT),position + _larg[offset]); } break; case COMP_AS_PERC: if (t < 2) { set_row_atpos('R',row, colval.string(PICT),position); if (!colval.is_zero()) { real p = 100.0 * (last_data.get_real(colname) - colval) / colval; p.round(1); set_row_atpos('R',row,p.string(PICTURE_PERCENT),position + _larg[offset] ); } aggiungi_perc=FALSE; } break; } break; case LINEA_TARGET: // v2.0 set_row_atpos('R',row,colval.string(PICT),position); break; } if (t < 2 && strec.get_char(SVS_TIPO) == LINEA_DATI) { // colonna con la percentuale rispetto al totale di riga if (_st_totr && aggiungi_perc && !tot_riga.is_zero()) { const int pos = position + _larg[offset] + _larg[offset + 1]; real p = 100.0 * colval / tot_riga; p.round(1); set_row_atpos('R',row,p.string(PICTURE_PERCENT),pos); } // riga con i totali di colonna if (_st_totc && aggiungi_perc ) { TRectype & _rec_totale=(TRectype &)_group_recs[numlevels()]; const real tot = _rec_totale.get_real(colname); if (!tot.is_zero()) { real p = 100.0 * colval / tot; p.round(1); r_totc = p.string(PICTURE_PERCENT); set_row_atpos('R',row+1,(const char *)r_totc,position+_largcol-LARG_COLPERC); } else set_row_atpos('R',row+1,"",0); // aggiunge comunque una riga vuota per la spaziatura } // colonna con il totale di un "anno" if (_st_tota && aggiungi_perc && (((c+1)%_col_anno)==0 || c== _numcol_dati-1)) { col++; int position_a = position + _largcol; set_row_atpos('R',row,(const char *)tot_riga.string(PICT),position_a); if (_st_totr && aggiungi_perc) { set_row_atpos('R',row,(const char *)real(100).string(PICTURE_PERCENT),position_a + _larg[offset]); } } } } col++; } if (_st_totc) ++row; return row; } void TStampa_stat::set_filled_row(char section,int row,char c,int pos,int len) { const int MAX=100; // limite massimo per una singola set_row; 5 char per costruire la goto while (len> MAX ) { _wrk_row.fill(c,MAX); set_row_atpos(section,row,(const char *)_wrk_row,pos); len-=MAX; pos+=MAX; } _wrk_row.fill(c,len); set_row_atpos(section,row,(const char *)_wrk_row,pos); } // fa le set_row per la "riga" contenente i valori delle colonne di statistica void TStampa_stat::set_row_atpos(char section,int nrow,const char * f,int pos) { TString256 ss; if (pos <= _colpage*_pagewidth) { int l = strlen(f); const int firstpos=(_colpage-1)*_pagewidth; if (pos+l >= firstpos) { // there's something to print in this page! if (pos+l > _colpage*_pagewidth) { l=_colpage*_pagewidth-pos; repeat_print(); } ss.format("@%03dg",max(pos, firstpos ) % _pagewidth); if (pos< firstpos) ss.overwrite(f+firstpos-pos,5); else ss.overwrite(f,5); ss.cut(5+l); // !?!? this cause trouble if special couples are used at the middle of the string: // "@b" or "%%" can be split into two non-significant chars } //else : too much to the left: already printed! } else //: too much to the right: will be printed next time! repeat_print(); switch (section) { case 'R': set_row(nrow,ss); break; case 'H': set_header(nrow,ss); break; case 'F': set_footer(nrow,ss); break; } } // stampa i totali ad ogni break di livello int TStampa_stat::handle_levchange(int row, const int level) { while (level > _last_lev_grp) { // ho lasciato un livello "basso" _last_lev_grp++; if (_last_lev_grp > _liv_riga && printmask().get_bool(F_FLAGSTOTALI+numlevels()-_last_lev_grp) || _last_lev_grp==numlevels()) { if (_group_recs.objptr(_last_lev_grp) == NULL) { NFCHECK("Totali inconsistenti"); } else { TRectype& rec_grp1=(TRectype &)_group_recs[_last_lev_grp]; int lencode=0; if (_last_lev_grp < numlevels()) { TRectype & rec_grp2=(TRectype &)_group_recs[_last_lev_grp+1]; lencode=rec_grp2.get(SVS_CODICE).len(); } adjust_record(rec_grp1,lencode); set_filled_row('R',++row,'_',POS_PRIMACOL,_largcol * _numcol ); partkey_name(rec_grp1.get(SVS_LEVCODE), numlevels() - _last_lev_grp - 1, _wrk_row); _wrk_row.insert(FR("@bTotale "), 0); _wrk_row << ' ' << rec_grp1.get(SVS_CODICE).mid(lencode); _wrk_row << ' ' << rec_grp1.get(SVS_DESCR).left(23); //_wrk_row.cut(LARG_COLCODICE); there are also @ chars! set_row_atpos('R',++row,(const char *)_wrk_row,_indent[_last_lev_grp]); row = set_rows_colonne(row, rec_grp1); if (printmask().get_bool(F_STRAFFRONTO )) { TRectype& rec_grp_raff=(TRectype &)_group_recs_raff[_last_lev_grp]; if (_group_recs_raff.objptr(level+1)) { const TRectype& rec_grp= (const TRectype&)_group_recs_raff[level+1]; lencode = rec_grp.get(SVS_CODICE).len(); } adjust_record(rec_grp_raff,lencode); row = set_rows_colonne(++row, rec_grp_raff); } } } } if (_last_lev_grp != level) _last_lev_grp = level; return row; } void TStampa_stat::reset_grplevels() { _last_lev_grp = numlevels(); _liv_riga = _last_lev_grp+1; _group_recs.destroy(); _group_recs_raff.destroy(); int pos=0; for (int l = 0; l <= _last_lev_grp; l++) { if (printmask().get_bool(F_FLAGSTOTALI+l)) { _liv_riga = _last_lev_grp-l; _indent[_liv_riga] = pos*2; pos++; } else _indent[_last_lev_grp-l] = 0; } } bool TStampa_stat::user_create() { // ************ // files: documenti e statistiche open_files(LF_RIGHEDOC, LF_CONDV, LF_RCONDV, LF_ANAMAG, LF_SCONTI, LF_UMART, LF_TAB, LF_TABCOM, LF_CLIFO, LF_CFVEN, LF_INDSP, LF_OCCAS, LF_MOVMAG, LF_RMOVMAG,LF_PROVV, 0); open_files(LF_SVRIEP,LF_SVSTAT,LF_AGENTI, 0); _stats.init(); if (_stats.frequency()==fs_nulla) return error_box(TR("E' necessario impostare la frequenza statistica per la ditta")); // ************ // maschere _msk = new TMask("sv1200a"); _msk->set_handler(F_CODICE, codice_handler); _msk->set_handler(F_MULTIPLO, multiplo_handler); _msk->set_handler(F_NUMERO, numero_handler); _msk->set_handler(F_PERIODO, periodo_handler); _msk->set_handler(F_DATAINI, dataini_handler); _msk->set_handler(F_DATAFIN, datafin_handler); _msk->set_handler(F_RAFFRONTO, raffronto_handler); _msk->set_handler(F_DATARAF, dataraf_handler); _msk->set_handler(F_CHIAVE, chiave_handler); TMask& sm = _msk->sfield(F_CHIAVE).sheet_mask(); sm.set_handler(S_CAMPO, campo_handler); sm.set_handler(S_ARTFLD, artfld_handler); _print_msk = new TMask("sv1200b"); _export_msk = new TMask("sv1200c"); _export_msk->set_handler(F_FILENAME, filename_handler); // ************ // oggetti per la gestione delle parti del codice _liv_art = new TCodart_livelli; _liv_giac = new TCodgiac_livelli; _tipodoc = new TRecord_cache("%TIP"); _catven = new TRecord_cache("CVE"); _umart = new TRecord_cache(LF_UMART, 2); // _spp = new TTable("SPP"); // _prs = new TTable("PRS"); // ************ // cursore di stampa add_file(LF_SVSTAT); add_cursor(new TCursor(new TRelation(LF_SVSTAT))); // cache per l'output _svcache=NULL; set_real_picture(""); _last_data = new TRectype(LF_SVSTAT); return TRUE; } bool TStampa_stat::user_destroy() { // maschere delete _msk; delete _print_msk; delete _export_msk; // livelli di codice delete _liv_art; delete _liv_giac; // cancella le cache delete _tipodoc; delete _catven; delete _umart; // cancella i files delete _last_data; delete current_cursor()->relation(); return TRUE; } bool TStampa_stat::menu(MENU_TAG ) { TMask& m = selmask(); TSheet_field& sheet = m.sfield(F_CHIAVE); TString tmp; KEY k; m.set(F_STAMPA_VAL, "X"); while ((k = m.run()) != K_QUIT) { _numcol_dati = m.get_int(F_PERIODO); _st_val = m.get_bool(F_STAMPA_VAL); _st_qta = m.get_bool(F_STAMPA_QTA); _st_uni = m.get_bool(F_STAMPA_UNI); _valid_types = ""; if (m.get_bool(F_TIPOART1)) _valid_types << RIGA_MERCE; if (m.get_bool(F_TIPOART2)) _valid_types << RIGA_PRESTAZIONI; if (m.get_bool(F_TIPOART3)) _valid_types << RIGA_SPESEDOC; if (m.get_bool(F_TIPOART4)) _valid_types << RIGA_OMAGGI; set_column_frequency(); _key.cut(0); TRelation anamag(LF_ANAMAG); TRelation_description rd(anamag); TSheet_field & s_chiave = selmask().sfield(F_CHIAVE); TFilename des_file_name("sv1200.ini"); TConfig c(des_file_name, "Descriptions"); for (int r = 0; r < sheet.items(); r++) { tmp = sheet.row(r).get(0); if (!tmp.blank()) _key.add(tmp); if (tmp == STR_ARTFIELD) { TString16 field(s_chiave.cell(r,s_chiave.cid2index(S_ARTFLD))); if (c.exist(field,2)) { TToken_string t(c.get(field, "Descriptions", 2)); _file_fld.add(t.get(), r); _key_fld.add(t.get(), r); _field_fld.add(t.get(), r); } if (c.exist(field,1)) _des_fld.add(c.get(field, "Descriptions", 1), r); else { int pos = field.find('['); TString16 sub; if (pos > 0) { sub = field.mid(pos); field.cut(pos); } TString des(rd.get_field_description(field)); des << sub; _des_fld.add(des, r); } } } if (k == K_SAVE) { set_ragg_per_um(); TTable psv("PSV"); psv.put("CODTAB", m.get(F_CODICE)); if (psv.read() == NOERR) expmask().set(F_FILENAME, psv.get("S3")); // File precaricato da PSV->S3 if (expmask().run()!=K_ESC) { TFilename fname(expmask().get(F_FILENAME)); fname.insert("%"); genera_file(fname); } } else { TFilename fname("svs"); genera_file(fname); TIsamtempfile * f = new TIsamtempfile(LF_SVSTAT,fname,FALSE,TRUE); set_printmask(); current_cursor()->relation()->replace(f); // Forza la ricostruzione del cursore... current_cursor()->setfilter("CODICE>=\"A\""); current_cursor()->setfilter(""); do_print(1); current_cursor()->relation()->replace(new TLocalisamfile(LF_SVSTAT)); } } return FALSE; } void TStampa_stat::fill_field_list(TMask& m) { // opzioni per il tipo di dato m.enable(F_TIPOART4, !_stats.omaggio_is_merce()); // opzioni per i campi della chiave TSheet_field& s = m.sfield(F_CHIAVE); TMask& sm = s.sheet_mask(); TString_array& list = sm.efield(S_CAMPO).sheet()->rows_array(); list.destroy(); TToken_string row(80); TCodart_livelli& cal = *_liv_art; bool is_articolo = FALSE; int l; for (l = 0; l <= cal.last_level(); l++) { if (l && !cal.enabled(l)) continue; is_articolo = TRUE; row = STR_ARTICOLO; if (l) row << l; row.add(TR("Codice articolo")); if (l) row << '[' << l << ']'; list.add(row); } if (is_articolo) { row = STR_ARTFIELD; row.add(TR("Campo dell'anagrafica articoli")); list.add(row); } TCodgiac_livelli& cgl = *_liv_giac; for (l = 0; l <= cgl.last_level(); l++) { if (l && !cgl.enabled(l)) continue; row = STR_LIVGIAC; if (l) row << l; row.add(TR("Livello giacenza")); if (l) row << '[' << l << ']'; list.add(row); } row = "D"; row.add(TR("Tipo documento")); list.add(row); row = "V"; row.add(TR("Categoria vendita")); list.add(row); row = "C"; row.add(TR("Codice cliente")); list.add(row); row = "Z"; row.add(TR("Codice zona")); list.add(row); row = "G"; row.add(TR("Codice agente")); list.add(row); row = "M"; row.add(TR("Codice magazzino")); list.add(row); } void TStampa_stat::set_frequency() { TPeriodo::set_frequency(_stats.frequency()); TMask& m = selmask(); char freq[2] = { frequency2char(_stats.frequency()), '\0' }; m.set(F_FREQUENZA, freq); TList_field& multiplo = (TList_field&)m.field(F_MULTIPLO); TToken_string codes(8), descr(80); switch(_stats.frequency()) { case fs_giornaliera : codes = "G|S|Q|1|2|3|4|6|A"; break; case fs_settimanale : codes = "S|3|6|A"; break; case fs_quindicinale : codes = "Q|1|2|3|4|6|A"; break; case fs_mensile : codes = "1|2|3|4|6|A"; break; case fs_bimestrale : codes = "2|4|6|A"; break; case fs_trimestrale : codes = "3|6|A"; break; case fs_quadrimestrale: codes = "4|A"; break; case fs_semestrale : codes = "6|A"; break; case fs_annuale : codes = "A"; break; default :break; } for (const char* cod = codes.get(0); cod; cod = codes.get()) descr.add(char2freqname(cod[0])); multiplo.replace_items(codes, descr); if (_stats.frequency() == fs_settimanale) { if (m.focus_field().dlg() == F_MULTIPLO) m.set_focus_field(F_NUMERO); // scappa dal campo multiplo.reset(); multiplo.disable(); } else multiplo.enable(); // setta la durata dell'anno //m.set(F_COL_ANNO, last_period(1992,_stats.frequency())); } void TStampa_stat::on_config_change() { _stats.init(); _liv_art->init(); _liv_giac->init(); set_frequency(); fill_field_list(*_msk); } bool TStampa_stat::set_column_frequency() { const TMask& m = selmask(); const TDate data_inizio = m.get(F_DATAINI); bool ok = data_inizio.year() >= 1900; if (ok) { const TFrequenza_statistiche multiplo = char2frequency(m.get(F_MULTIPLO)[0]); const int numero = m.get_int(F_NUMERO); _freq.init(multiplo, numero, data_inizio); } return ok; } TString& TStampa_stat::build_key(const TRectype& rec) { _last_key.cut(0); TString16 tmp; for (const char* field = _key.get(0); field; field = _key.get()) { tmp = field; switch(tmp[0]) { case 'A': if (tmp[1] > '0') { const int liv = tmp[1] - '0'; const int start = _liv_art->code_start(liv); const int len = _liv_art->code_length(liv); tmp = rec.get(SVR_CODART).mid(start, len); _last_key << tmp; } else _last_key << rec.get(SVR_CODART); break; default: break; } } return _last_key; } void TStampa_stat::update_file(const char * key, const char *lev_code,const char tipo_dato, const int level, const int col, TSVriep_record& curr, const TString & fld, int row) { CHECK(col>=0,"Le colonne partono da 0"); static TRectype* statrec = NULL; if (statrec == NULL) statrec = new TRectype(LF_SVSTAT); TToken_string cachekey(key); cachekey.rtrim(); // necessario perché la chiave sia buona per l'hash table if (cachekey.blank()) cachekey.add(" "); cachekey.add(tipo_dato); *statrec = _svcache->get(cachekey); if (_svcache->io_result()!=NOERR) { // nuovo record; statrec->put(SVS_CODICE,key); statrec->put(SVS_LEVCODE,lev_code); statrec->put(SVS_LIVELLO,level); statrec->put(SVS_TIPO,tipo_dato); statrec->put(SVS_UMQTA,curr.get(SVR_UMQTA)); } if (*lev_code== CHR_TOTGEN) // totale generale statrec->put(SVS_DESCR,""); else { TString descr(get_descrpart(lev_code,curr,fld, row)); for (int pos = descr.find('%'); pos >=0; pos = descr.find('%', pos + 2)) descr.insert("%", pos); if (descr.len() > SVS_LEN_DESCR) descr.cut(SVS_LEN_DESCR); statrec->put(SVS_DESCR, descr); } put_column(*statrec,col,curr); _svcache->put(*statrec); } // aggiorna la colonna del record statrec con i dati di SVriep void TStampa_stat::put_column(TRectype& statrec, int col, const TSVriep_record& rieprec) { if (col < 0 || col > SVS_NUMCOLONNE) return; if (_st_qta || _st_uni) { const TString16 um(rieprec.get(SVR_UMQTA)); if (um.not_empty()) { const real fc = fc_um(statrec,rieprec); if (fc.is_zero()) invalid_columns(statrec); else { const real qta = rieprec.get_real(SVR_QUANTITA) * fc; TString4 colname; colname.format("%c%d", SVS_QTACOLNAME, col); statrec.add(colname, qta); //statrec.put(SVS_TOTALERIGA,statrec.get_real(SVS_TOTALERIGA)+rieprec.get_real(SVR_QUANTITA)*fc); } } // no UM ? no valid data! } if (_st_val || _st_uni) { const real val = rieprec.get_real(SVR_VALORE); TString4 colname; colname.format("%c%d", SVS_VALCOLNAME, col); statrec.add(colname, val); //statrec.put(SVS_TOTALERIGA, statrec.get_real(SVS_TOTALERIGA)+rieprec.get_real(SVR_VALORE)); } } // Converte le UM scrivendo la nuova UM sul record e restituendo il fattore di conv. void TStampa_stat::standardize_um(TSVriep_record& rieprec, bool force) { if (force || _ragg_per_um) { TString4 um("N."); // Unita' di default NON valida! real fc; const char tipoart = rieprec.get_char(SVR_TIPOART); if (tipoart==RIGA_MERCE || tipoart==RIGA_OMAGGI) { // è un articolo (erce); converto alla UM principale dell'art. TString key(rieprec.get(SVR_CODART)); key << "|1"; const TRectype& rec_umart = cache().get(LF_UMART, key); um = rec_umart.get(UMART_UM); fc = rec_umart.get_real(UMART_FC); } else { // non è un articolo: converte in base alla UM di riferimento in tabella const TRectype& ums = cache().get("%UMS", um); um = ums.get("S7"); fc = ums.get_real("R10"); } if (um != rieprec.get(SVS_UMQTA)) { // conversione tra UM diverse const real qta = rieprec.get_real(SVR_QUANTITA); rieprec.put(SVR_QUANTITA, fc * qta); rieprec.put(SVR_UMQTA, um); } } } // Calcola il fattore di conversione necessario per passare da rieprec a statrec const real TStampa_stat::fc_um(const TRectype& statrec,const TSVriep_record& rieprec) { real fc = UNO; const TString4 statum = statrec.get(SVS_UMQTA); TString4 um = rieprec.get(SVR_UMQTA); if (um != statum) { // converte in base alla UM di riferimento in tabella const char tipoart = rieprec.get_char(SVR_TIPOART); if (tipoart==RIGA_MERCE || tipoart==RIGA_OMAGGI) { // è un articolo (erce) TString80 art = rieprec.get(SVR_CODART); art.trim(); TLocalisamfile umart(LF_UMART); umart.setkey(2); umart.put(UMART_CODART, art); umart.put(UMART_UM, um); if (umart.read() == NOERR) { fc = umart.get_real(UMART_FC); umart.put(UMART_UM, statum); if (umart.read() == NOERR) { // è una UM dell'articolo: uso i fc per convertirla um = umart.get(UMART_UM); fc /= umart.get_real(UMART_FC); } } else { error_box("L'articolo '%s' non ha l'unita' di misura %s\n" "ma esistono statistiche che la utilizzano ugualmente", (const char*)art, (const char*)um); } } if (um != statum) // Non sono riuscito a trovare una conversione certa ... { // ... allora provo con le unita' di misura standard const TRectype& ums = cache().get("%UMS", um); um = ums.get("S7"); fc = ums.get_real("R10"); } if (um != statum) { // impossibile associare al totale una unità di misura fc = ZERO; } } return fc; } // rende non validi i valori delle colonne void TStampa_stat::invalid_columns(TRectype& statrec) { statrec.zero(SVS_UMQTA); TString16 colname; for (int col = 0; col < SVS_NUMCOLONNE; col++) { colname.format("%C%d", SVS_QTACOLNAME, col); statrec.zero(colname); } //statrec.put(SVS_TOTALERIGA,0); } // funzione di filtro del cursore bool TStampa_stat::filtro_chiavi(TSVriep_record &curr) { // !?!?! static TString16 code_campo(" "); TString16 fld_campo; // !?!?! static TString val_stringa(32,' '); TSheet_field & s_chiave = selmask().sfield(F_CHIAVE); const int num_liv_output=s_chiave.items(); TString est1,est2; bool ok=TRUE; // Verifica che il tipoarticolo corrisponda con quello richiesto dall'utente ok = _valid_types.find(curr.get_char(SVR_TIPOART)) >= 0; for (int l=0; ok && l< num_liv_output; l++) { code_campo=s_chiave.cell(l,s_chiave.cid2index(S_CAMPO)); fld_campo=s_chiave.cell(l,s_chiave.cid2index(S_ARTFLD)); if (code_campo==STR_CLIFOR) // cliente/fornitore ha in testa il TIPOCF { // ok &= curr.get_char(SVR_TIPOCF)==; !?!?! manca la selezione dei soli cli o for val_stringa=get_part(code_campo,curr, fld_campo)+1; } else { val_stringa=get_part(code_campo,curr, fld_campo); val_stringa.trim(); } if (!(est1=s_chiave.cell(l,s_chiave.cid2index(S_DAL))).blank()) { if (code_campo==STR_CLIFOR) // cliente/fornitore e' numerico ok &= (atoi((const char *)val_stringa) >= atoi((const char *)est1)); else ok &= (val_stringa>=est1); } if (ok && !(est2=s_chiave.cell(l,s_chiave.cid2index(S_AL))).blank()) { if (code_campo==STR_CLIFOR) // cliente/fornitore e' numerico ok &= (atoi((const char *)val_stringa) <= atoi((const char *)est2)); else ok &= val_stringa<=est2; } } return ok; } // ritorna se la query è suddivisa per unità di misura void TStampa_stat::set_ragg_per_um() { TSheet_field & s_chiave = selmask().sfield(F_CHIAVE); for (int l=0; l< s_chiave.items(); l++) { if (*s_chiave.cell(l,s_chiave.cid2index(S_CAMPO))==CHR_UMISURA) { _ragg_per_um=FALSE; return; } } _ragg_per_um=TRUE; } void TStampa_stat::genera_file(const char *outfn) { TString key; // chiave per il record del file statistiche const TMask& m = selmask(); const char alg=m.get(F_TIPOCALC)[0]; const int first_col = - (alg==ALG_MOBILI ? _col_anno-1:0); // prima colonna dati da osservare const int first_raffr = -m.get_int(F_RAFFRONTO)- (alg==ALG_MOBILI ? _col_anno-1:0);// prima colonna dati da confrontare const int first_data = first_raffr ; // prima colonna dati TSheet_field & s_chiave = m.sfield(F_CHIAVE); // file di OUTPUT _svcache = new TStat_cache(new TIsamtempfile(LF_SVSTAT,outfn,TRUE,FALSE)); // file di INPUT TLocalisamfile riep(LF_SVRIEP); riep.set_curr(new TSVriep_record); TSVriep_record& curr = (TSVriep_record&) riep.curr(); const TRecfield fr_anno(curr, SVR_ANNO); const TRecfield fr_periodo(curr, SVR_PERIODO); const bool dok = m.get_date(F_DATARAF).ok(); const TDate dd = m.get_date(dok ? F_DATARAF : F_DATAINI); curr.put(SVR_ANNO, dd.year()); curr.put(SVR_PERIODO, _stats.date2period(dd)); const int num_liv_output=s_chiave.items(); const long start_status=period2long(curr.get_int(SVR_ANNO),curr.get_int(SVR_PERIODO),_stats.frequency()); const TDate datafin = m.get_date(F_DATAFIN); const int yearfin = datafin.year(); const int periofin = _stats.date2period(datafin); TProgind statusbar(period2long(datafin.year(), periofin,_stats.frequency())-start_status, TR("Creazione del file di output"), FALSE, TRUE, 60); _svcache->zap(); // ********************** // ciclo principale: scorre il riepilogo statistiche per anno+periodo // e genera i risultati in una cache TString16 levcode; TString16 fld; for (int err = riep.read(_isgteq); err == NOERR && (curr.get_int(SVR_ANNO) < yearfin || (curr.get_int(SVR_ANNO) == yearfin && curr.get_int(SVR_PERIODO) <= periofin)) ; err = riep.next()) { statusbar.setstatus(period2long(curr.get_int(SVR_ANNO),curr.get_int(SVR_PERIODO),_stats.frequency())-start_status); if (filtro_chiavi(curr)) { const TPeriodo periodo(fr_anno, fr_periodo); const int col = _freq.period2column(periodo); if (col >= first_data && col < _numcol_dati) { // NOTA: eventualmente sarebbe utile forzare l'uso della UM standard se è una riga // non comprendente l'articolo ...... standardize_um(curr); // costruisce il file statistiche... key.cut(0); for (int l=0; l< num_liv_output; l++) { levcode=s_chiave.cell(l,s_chiave.cid2index(S_CAMPO)); fld=s_chiave.cell(l,s_chiave.cid2index(S_ARTFLD)); key << get_part(levcode,curr, fld); // setta il range in base all'algoritmo (Valori/progressivi/mobili) const int range=(alg==ALG_VALORI ? col : alg==ALG_PROGRESSIVI ? ((1+int(col/_col_anno))*_col_anno-1) : (col+_col_anno-1)); if (col>=first_col) // periodo da osservare { if (l==0) for (int c=max(col,0);c <= range ; c++) update_file(" ",STR_TOTGEN,LINEA_DATI,num_liv_output,c,curr, fld, l); if (*s_chiave.cell(l,s_chiave.cid2index(S_TOTALE))=='X') for (int c=max(col,0);c <= range ; c++) update_file(key,levcode,LINEA_DATI,num_liv_output-l-1,c,curr, fld, l); } if (first_raffr !=first_col && col >= first_raffr && colflush(); delete _svcache; } void TStampa_stat::set_printmask() { TMask &mp=selmask(); // visualizza i checkbox per i totali const int nlivelli = mp.sfield(F_CHIAVE).items(); TString80 nomeliv; printmask().field(F_FLAGSTOTALI).set("X"); TSheet_field& sc = mp.sfield(F_CHIAVE); for (int f=0; fname(lev_code_num); else park=" "; break; case CHR_LIVGIAC: // liv giac CHECK(lev_code_num>0,"I livelli di giacenza sono utilizzabili solo singolarmente"); park =_liv_giac->name(lev_code_num); break; case CHR_CATVEN: // cat. vendita park=TR("cat. ven."); break; case CHR_CLI: // cliente park=TR("cliente "); break; case CHR_FOR: // fornitore park=TR("fornitore "); break; case CHR_AGENTE: // agente park=TR("agente "); break; case CHR_MAGAZZ: // mag park=TR("magazzino"); break; case CHR_ZONA: // zona park=TR("zona"); break; case CHR_UMISURA: // unità di misura park=TR("unita' di misura"); break; case CHR_TOTGEN: // totale generale park=TR("generale"); break; case CHR_ARTFIELD: // campo anagrafica park=_des_fld.row(row); break; default: NFCHECK("ai chent recognaiz the code (%s) of the key part!", lev_code); park = " "; break; } return park; } // strippa gli spazi dal codice di questo livello // toglie il carattere 'C' o 'F' dal codice clientefor e lo mette come codice di livello void TStampa_stat::adjust_record(TRectype &strec, int from) const { char lev_code=strec.get_char(SVS_LEVCODE); if (lev_code==CHR_CLIFOR) { TString codprec = strec.get(SVS_CODICE).left(from); TString& s = (TString&)strec.get(SVS_CODICE).mid(from); while ((lev_code=s.shift())==' '); codprec << s; strec.put(SVS_LEVCODE, lev_code); strec.put(SVS_CODICE, codprec); } else { if (from) { TString codprec=strec.get(SVS_CODICE).left(from); TString& s = (TString&)strec.get(SVS_CODICE).mid(from); while ((lev_code=s.shift())==' '); codprec << lev_code << s; strec.put(SVS_CODICE,codprec); } } } const TString& TStampa_stat::get_part(TString & lev_code, TSVriep_record &rieprec, const TString & fld) // const { static TString park(25, ' '); int lev_code_num=atoi(lev_code+1); switch (lev_code[0]) { case CHR_TIPODOC: // tipo documento park = rieprec.get(SVR_TIPODOC); break; case CHR_ARTICOLO: // articolo if (lev_code_num==0) { park=rieprec.get(SVR_CODART); park.rpad(25); break; } else { park =_liv_art->unpack_grpcode(rieprec.get(SVR_CODART),lev_code_num); park.rpad(_liv_art->code_length(lev_code_num)); break; } case CHR_ARTFIELD: // campo dell' anagrafica articolo { const char t = rieprec.get_char(SVR_TIPOART); TFieldref f; f = fld; const TRectype anamag(LF_ANAMAG); int l = f.len(anamag); if (l > 25) l = 25; if (t == RIGA_MERCE || t == RIGA_OMAGGI) { const TRectype & rec = cache().get(LF_ANAMAG, rieprec.get(SVR_CODART)); park = f.read(rec); park.rpad(l); } else park.spaces(l); } break; case CHR_LIVGIAC: // liv giac CHECK(lev_code_num>0,"I livelli di giacenza sono utilizzabili solo singolarmente"); park = _liv_giac->unpack_grpcode(rieprec.get(SVR_GIAC),lev_code_num); park.rpad(_liv_giac->code_length(lev_code_num)); break; case CHR_CATVEN: // cat. vendita park=rieprec.get(SVR_CATVEN); park.rpad(3); break; case CHR_FOR: // cliente / fornitore case CHR_CLI: // cliente / fornitore if (rieprec.get_char(SVR_TIPOCF)>' ') lev_code[0]=rieprec.get_char(SVR_TIPOCF); park.format("%c%6ld",lev_code[0],rieprec.get_long(SVR_CODCF)); break; case CHR_AGENTE: // agente park.format("%5s",(const char*)rieprec.get(SVR_CODAG)); break; case CHR_MAGAZZ: // mag park=rieprec.get(SVR_MAG); park.rpad(3); break; case CHR_ZONA: // zona park=rieprec.get(SVR_ZONA); park.rpad(3); break; case CHR_UMISURA: // unità di misura park=rieprec.get(SVR_UMQTA); park.rpad(3); break; default: NFCHECK("ai chent recognaiz the code of the key part!"); park= " "; } if (park.blank()) park.replace(' ','?'); return park; } const TString& TStampa_stat::get_descrpart(const char *lev_code, TSVriep_record &rieprec, const TString & fld, int row) { int lev_code_num=atoi(lev_code+1); switch (*lev_code) { case CHR_TIPODOC: // tipo documento { const TString16 tipodoc = rieprec.get(SVR_TIPODOC); const TString& descr = _tipodoc->get(tipodoc).get("S0"); return descr; } case CHR_ARTICOLO: // articolo { const char t = rieprec.get_char(SVR_TIPOART); switch (t) { case RIGA_MERCE: case RIGA_OMAGGI: if (lev_code_num==0 || lev_code_num== _liv_art->last_level()) { const TRectype & rec = cache().get(LF_ANAMAG, rieprec.get(SVR_CODART)); return rec.get(ANAMAG_DESCR); } else { return _liv_art->group_descr(rieprec.get(SVR_CODART),lev_code_num); } break; case RIGA_PRESTAZIONI: return cache().get("PRS", rieprec.get(SVR_CODART), "S0"); break; case RIGA_SPESEDOC: return cache().get("SPP", rieprec.get(SVR_CODART), "S0"); break; default: break; } } case CHR_ARTFIELD: // campo anagrafica { if (_file_fld.objptr(row) != NULL) { TString16 tab(_file_fld.row(row)); int file = atoi(tab); const TRectype & anag = cache().get(LF_ANAMAG, rieprec.get(SVR_CODART)); TFieldref f; f = _key_fld.row(row); const TString & key = f.read(anag); if (key.not_empty()) { if (file != 0) { const TRectype & rec = cache().get(file, key); return rec.get(_field_fld.row(row)); } else { const TRectype & rec = cache().get(tab, key); return rec.get(_field_fld.row(row)); } } } return EMPTY_STRING; } break; case CHR_LIVGIAC: // liv giac CHECK(lev_code_num>0,"I livelli di giacenza sono utilizzabili solo singolarmente"); return _liv_giac->group_descr(rieprec.get(SVR_GIAC),lev_code_num); case CHR_CATVEN: // cat. vendita return _catven->get(rieprec.get(SVR_CATVEN)).get("S0"); case CHR_FOR: // fornitore case CHR_CLI: // cliente { TToken_string key; key.add(rieprec.get_char(SVR_TIPOCF)); key.add(rieprec.get_long(SVR_CODCF)); return cache().get(LF_CLIFO, key, CLI_RAGSOC); } case CHR_AGENTE: // agente return cache().get(LF_AGENTI, rieprec.get(SVR_CODAG), AGE_RAGSOC); case CHR_MAGAZZ: // mag return cache().get("MAG", rieprec.get(SVR_MAG), "S0"); case CHR_ZONA: // zona return cache().get("ZON", rieprec.get(SVR_ZONA), "S0"); case CHR_UMISURA: // Unità di misura return cache().get("%UMS", rieprec.get(SVR_UMQTA), "S0"); default: NFCHECK("ai chent recognaiz the code of the key part!"); return EMPTY_STRING; } } bool TStampa_stat::recalc_period() { bool ok = set_column_frequency(); TMask& m = selmask(); if (ok) { TDate data(m.get(F_DATAFIN)); if (data.ok()) { int col = _freq.date2column(data); if (col < 0) col = 0; if (col > 35) col = 35; data = app()._freq.column_last_day(col); m.set(F_DATAFIN, data); m.set(F_PERIODO, col+1); ok = TRUE; } data = m.get(F_DATARAF); if (data.ok()) { int col = _freq.date2column(data); m.set(F_RAFFRONTO, -col); } } return ok; } bool TStampa_stat::multiplo_handler(TMask_field& f, KEY k) { bool ok = TRUE; TMask& m = f.mask(); if (k == K_SPACE || k == K_ENTER) { TFrequenza_statistiche base = char2frequency(m.get(F_FREQUENZA)[0]); TFrequenza_statistiche freq = char2frequency(f.get()[0]); if (base == freq) { m.enable(F_NUMERO); } else { int n = divide(freq, base); m.set(F_NUMERO, n); m.disable(F_NUMERO); } // setta la durata dell'anno m.set(F_COL_ANNO, last_period(1992,freq)); app().recalc_period(); } return ok; } bool TStampa_stat::numero_handler(TMask_field& f, KEY k) { bool ok = TRUE; if (f.to_check(k)) app().recalc_period(); return ok; } bool TStampa_stat::periodo_handler(TMask_field& f, KEY k) { bool ok = TRUE; if (f.to_check(k)) { int col = atoi(f.get()); if (col > 0 && col <= 36) { if (app().set_column_frequency()) { TDate d = app()._freq.column_last_day(col-1); f.mask().set(F_DATAFIN, d); } } } return ok; } bool TStampa_stat::dataini_handler(TMask_field& f, KEY k) { bool ok = TRUE; if (k == K_TAB && f.focusdirty()) { TMask& m = f.mask(); TDate data(f.get()); const TFrequenza_statistiche base = char2frequency(m.get(F_FREQUENZA)[0]); const TFrequenza_statistiche freq = char2frequency(m.get(F_MULTIPLO)[0]); // floor(data, divide(freq, base) == 0 ? freq : base); // perche'? floor(data, freq); f.set(data.string()); app().recalc_period(); } return ok; } bool TStampa_stat::datafin_handler(TMask_field& f, KEY k) { bool ok = TRUE; if (k == K_TAB && f.focusdirty()) { app().recalc_period(); } return ok; } bool TStampa_stat::raffronto_handler(TMask_field& f, KEY k) { if (f.to_check(k)) { if (app().set_column_frequency()) { const int col = atoi(f.get()); if (col > 0) { TDate data = app()._freq.column_first_day(-col); f.mask().set(F_DATARAF, data); } else f.mask().reset(F_DATARAF); } } return TRUE; } bool TStampa_stat::dataraf_handler(TMask_field& f, KEY k) { if (f.to_check(k)) { TMask& m = f.mask(); TDate data(f.get()); if (data.ok()) { if (app().set_column_frequency()) { int col = app()._freq.date2column(data); if (col < 0) { m.set(F_RAFFRONTO, -col); data = app()._freq.column_first_day(col); f.set(data.string()); } else data = botime; } } if (!data.ok()) m.reset(F_RAFFRONTO); } return TRUE; } bool TStampa_stat::codice_handler(TMask_field& f, KEY k) { if (k == K_TAB && f.focusdirty()) { TMask& m = f.mask(); if (app().set_column_frequency()) { int col = m.get_int(F_RAFFRONTO); if (col > 0) { TDate data = app()._freq.column_first_day(-col); m.set(F_DATARAF, data); } } // Record corrente della tabella statistiche const TRectype& rec = ((TEdit_field&)f).browse()->cursor()->curr(); TSheet_field& sheet = m.sfield(F_CHIAVE); sheet.destroy(); TToken_string s1 = rec.get("S1"); TToken_string s2 = rec.get("S2"); TToken_string s4 = rec.get("S4"); TString s5 = rec.get("S5"); if (s4.not_empty()) if (s4[s4.len() - 1] == '|' && s5[0] == '|') s4 << " "; s4 <0 && *s.row(r-1).get(1)==' ') { s.row(r).add(" ",1); s.force_update(r); } } else { // disabilito i totale seguenti for (r++;r < maxr; r++) if (*s.row(r).get(1)!=' ') { s.row(r).add(" ",1); s.force_update(r); } } } } return ok; } bool TStampa_stat::test_field(const TString& cod, TMask_field& f) const { bool ok = TRUE; switch(cod[0]) { case CHR_ARTICOLO: if (cod[1] != '\0' && !_liv_art->enabled()) ok = f.error_box(TR("I livelli di codice articolo non sono abilitati")); break; case CHR_LIVGIAC: if (!_stats.grp_giacenza()) ok = f.error_box(TR("Le statistiche sono raggruppate per livello di giacenza")); else if (!_liv_giac->enabled()) ok = f.error_box(TR("I livelli di giacenza non sono abilitati")); break; case CHR_CLIFOR: if (!_stats.grp_cliente()) ok = f.error_box(TR("Le statistiche sono raggruppate per cliente/fornitore")); break; case CHR_AGENTE: if (!_stats.grp_agente()) ok = f.error_box(TR("Le statistiche sono raggruppate per agente")); break; case CHR_MAGAZZ: if (!_stats.grp_magazzino()) ok = f.error_box(TR("Le statistiche sono raggruppate per magazzino")); break; case CHR_ZONA: if (!_stats.grp_zona()) ok = f.error_box(TR("Le statistiche sono raggruppate per zona")); break; default : break; } return ok; } bool TStampa_stat::chiave_handler(TMask_field& f, KEY k) { bool ok = TRUE; if (k == K_ENTER) { TSheet_field& sheet = (TSheet_field&)f; TToken_string used; TString16 campo; for (int r = 0; r < sheet.items(); r++) { TToken_string& row = sheet.row(r); campo = row.get(0); if (campo.blank()) continue; ok = app().test_field(campo, f); bool found = used.get_pos(campo) >= 0; if (!found && (campo[0] == CHR_ARTICOLO || campo[0] == CHR_LIVGIAC)) { const char str[2] = { campo[0], '\0' }; found = used.get_pos(str) >= 0; } if (campo[0] != CHR_ARTFIELD && found) { ok = error_box(FR("Il codice %s inserito alla riga %d e' gia'\n" "utilizzato in una riga precedente."), (const char*)campo, r+1); } else used.add(campo); } } return ok; } bool TStampa_stat::campo_handler(TMask_field& f, KEY k) { if (f.to_check(k, TRUE)) { const bool is_fld = f.get()== STR_ARTFIELD; if (!is_fld) f.mask().reset(S_ARTFLD); f.mask().field(S_ARTFLD).check_type(is_fld ? CHECK_REQUIRED : CHECK_NONE); f.mask().enable(S_ARTFLD, is_fld); return app().test_field(f.get(), f); } return TRUE; } bool TStampa_stat::artfld_handler(TMask_field& f, KEY k) { bool ok = TRUE; switch (k) { case K_TAB: case K_ENTER: if (!f.empty() && f.to_check(k)) { const TRectype rec(LF_ANAMAG); TString16 field = f.get(); int pos = field.find('['); if (pos > 0) field.cut(pos); if (!rec.exist(field)) ok = f.error_box(FR("Il campo '%s' non esiste."), (const char*)field); } break; case K_F9: { TRelation anamag(LF_ANAMAG); TRelation_description rd(anamag); if (rd.choose_field(f.get())) f.set(rd.field_name()); } break; default: break; } return ok; } /////////////////////////////////////////////////////////// // Pseudo main /////////////////////////////////////////////////////////// int sv1200(int argc, char* argv[]) { TStampa_stat mainapp; mainapp.run(argc, argv, TR("Stampa statistiche")); return 0; }