#include #include #include #include #include "../mg/mglib.h" #include "sv1.h" #include "sv1200a.h" #include "svlib01.h" #include "svriep.h" /////////////////////////////////////////////////////////// // 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) { for (int i = n; i > 0; i--) { _periodo++; if (_periodo > last_period(_anno, _frequenza)) { _anno++; _periodo = 1; } } } 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; _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; if (p < _periodo_inizio) 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 TApplication { enum { MAX_ROWS = 8 }; TMask* _msk; TStats_agg _stats; TFrequenza_colonne _freq; TCodart_livelli* _liv_art; TCodgiac_livelli* _liv_giac; TToken_string _key; TString _last_key; protected: virtual bool menu(MENU_TAG mt); virtual bool create(); virtual bool destroy(); virtual void on_config_change(); 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); bool test_field(const TString& cod, TMask_field& f) const; 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); public: TMask& curr_mask() { return *_msk; } void fill_field_list(TMask& m); void set_frequency(); bool set_column_frequency(); bool recalc_period(); TString& build_key(const TRectype& rec); void genera_file(); }; inline TStampa_stat& app() { return (TStampa_stat&)main_app(); } void TStampa_stat::fill_field_list(TMask& m) { TList_field& tipoart = (TList_field&)m.field(F_TIPOART); TToken_string codes, descr; codes = "M|P"; descr = "Merce|Prestazioni"; if (!_stats.omaggio_is_merce()) { codes.add("O"); descr.add("Omaggi"); } tipoart.replace_items(codes, descr); 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; for (int l = 0; l <= cal.last_level(); l++) { if (l && !cal.enabled(l)) continue; row = "A"; if (l) row << l; row.add("Codice articolo"); if (l) row << '[' << l << ']'; list.add(row); } TCodgiac_livelli& cgl = *_liv_giac; for (l = 0; l <= cgl.last_level(); l++) { if (l && !cgl.enabled(l)) continue; row = "L"; if (l) row << l; row.add("Livello giacenza"); if (l) row << '[' << l << ']'; list.add(row); } list.add("D|Tipo documento"); list.add("V|Categoria vendita"); list.add("C|Codice cliente"); list.add("G|Codice agente"); list.add("Z|Codice zona"); list.add("M|Codice magazzino"); } void TStampa_stat::set_frequency() { TPeriodo::set_frequency(_stats.frequency()); TMask& m = curr_mask(); char freq[2] = { frequency2char(_stats.frequency()), '\0' }; m.set(F_FREQUENZA, freq); TList_field& multiplo = (TList_field&)m.field(F_MULTIPLO); if (_stats.frequency() == fs_settimanale) { multiplo.reset(); multiplo.disable(); } else multiplo.enable(); TToken_string std_codes("G|S|Q|1|2|3|4|6|A"); TToken_string std_descr("Giornaliera|Settimanale|Quindicinale|Mensile|" "Bimestrale|Trimestrale|Quadrimestrale|Semestrale|Annuale"); TToken_string codes(8), descr(80); switch(_stats.frequency()) { case fs_giornaliera : codes = std_codes; break; case fs_settimanale : codes = "S|3|6|A"; break; case fs_quindicinale : codes = std_codes.mid(4); break; case fs_mensile : codes = std_codes.mid(6); 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; } TString tmp; for (const char* cod = codes.get(0); cod; cod = codes.get()) { tmp = cod; const int pos = std_codes.get_pos(tmp); CHECK(pos >= 0, "Invalid frequency char"); tmp = std_descr.get(pos); descr.add(tmp); } multiplo.replace_items(codes, descr); } 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 = curr_mask(); 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::genera_file() { const TMask& m = curr_mask(); const int first = -m.get_int(F_RAFFRONTO); const int columns = m.get_int(F_PERIODO); TLocalisamfile riep(LF_SVRIEP); TRectype& curr = riep.curr(); const TRecfield fr_anno(curr, SVR_ANNO); const TRecfield fr_periodo(curr, SVR_PERIODO); for (int err = riep.first(); err == NOERR; err = riep.next()) { const TPeriodo periodo(fr_anno, fr_periodo); int col = _freq.period2column(periodo); if (col >= first && col < columns) { } } } bool TStampa_stat::menu(MENU_TAG) { TMask& m = curr_mask(); TSheet_field& sheet = m.sfield(F_CHIAVE); TString tmp; KEY k; while ((k = m.run()) != K_QUIT) { set_column_frequency(); _key.cut(0); for (int r = 0; r < sheet.items(); r++) { tmp = sheet.row(r).get(0); if (!tmp.blank()) _key.add(tmp); } genera_file(); } return FALSE; } bool TStampa_stat::create() { _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); _msk->sfield(F_CHIAVE).set_notify(chiave_notify); TMask& sm = _msk->sfield(F_CHIAVE).sheet_mask(); sm.set_handler(S_CAMPO, campo_handler); _liv_art = new TCodart_livelli; _liv_giac = new TCodgiac_livelli; dispatch_e_menu(BAR_ITEM(1)); return TRUE; } bool TStampa_stat::destroy() { delete _liv_art; delete _liv_giac; delete _msk; return TRUE; } bool TStampa_stat::recalc_period() { bool ok = set_column_frequency(); TMask& m = curr_mask(); 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; if (k == K_SPACE) { TMask& m = f.mask(); 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); } 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); 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"); int r = 0; for (const char* cod = s1.get(0); cod; cod = s1.get(), r++) { TToken_string& row = sheet.row(r); row = cod; cod = s2.get(r); row.add(cod); sheet.check_row(r); } sheet.force_update(); } return TRUE; } bool TStampa_stat::chiave_notify(TSheet_field& s, int r, KEY k) { bool ok = TRUE; if (k == K_INS) ok = s.items() < MAX_ROWS; return ok; } bool TStampa_stat::test_field(const TString& cod, TMask_field& f) const { bool ok = TRUE; switch(cod[0]) { case 'C': if (!_stats.grp_cliente()) ok = f.error_box("Le statistiche sono raggruppate per cliente"); break; case 'G': if (!_stats.grp_agente()) ok = f.error_box("Le statistiche sono raggruppate per agente"); break; case 'L': if (!_stats.grp_giacenza()) ok = f.error_box("Le statistiche sono raggruppate per livello di giacenza"); break; case 'M': if (!_stats.grp_magazzino()) ok = f.error_box("Le statistiche sono raggruppate per magazzino"); break; case 'Z': if (!_stats.grp_zona()) ok = f.error_box("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] == 'A' || campo[0] == 'L')) { char str[2]; str[0] = campo[0]; str[1] = '\0'; found = used.get_pos(str) >= 0; } if (found) { ok = error_box("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) { bool ok = TRUE; if (f.to_check(k)) ok = app().test_field(f.get(), f); return ok; } /////////////////////////////////////////////////////////// // Pseudo main /////////////////////////////////////////////////////////// int sv1200(int argc, char* argv[]) { TStampa_stat app; app.run(argc, argv, "Stampa statistiche"); return 0; }