campo-sirio/sv/svlib01.cpp
guy 92aff241e4 Patch level :
Files correlati     : sv2.exe
Ricompilazione Demo : [ ]
Commento            :
Ottimizzato ricalcolo statistiche (6x)


git-svn-id: svn://10.65.10.50/branches/R_10_00@22472 c028cbd2-c16b-5b4b-a496-9718f37d4682
2011-10-31 11:40:02 +00:00

733 lines
17 KiB
C++
Executable File
Raw Blame History

#include <prefix.h>
#include <diction.h>
#include "svlib01.h"
#include "../ve/velib.h"
#include "svriep.h"
#include "svstat.h"
///////////////////////////////////////////////////////////
// Funzioni di utilita' comune
///////////////////////////////////////////////////////////
#define FREQ_CODES " GSQ12346A"
TFrequenza_statistiche char2frequency(char c)
{
const TFixed_string list(FREQ_CODES);
TFrequenza_statistiche f = TFrequenza_statistiche(list.find(c));
return f;
}
char frequency2char(TFrequenza_statistiche f)
{
const char* list = FREQ_CODES;
return list[f];
}
TString & char2freqname(char c)
{
static TString16 s;
const TFixed_string list(FREQ_CODES);
TToken_string std_descr;
std_descr.add(TR("Giorno"));
std_descr.add(TR("Settimana"));
std_descr.add(TR("Quindicina"));
std_descr.add(TR("Mese"));
std_descr.add(TR("Bimestre"));
std_descr.add(TR("Trimestre"));
std_descr.add(TR("Quadrimestre"));
std_descr.add(TR("Semestre"));
std_descr.add(TR("Anno"));
s= std_descr.get(list.find(c)-1);
return s;
}
int last_period(const TDate & d, TFrequenza_statistiche f)
{
return last_period(d.year(),f);
}
int last_period(int anno, TFrequenza_statistiche f)
{
int n = 0;
switch(f)
{
case fs_giornaliera : n = 365 + (TDate::last_day(2, anno) == 29); break;
case fs_settimanale : n = 52; break;
case fs_quindicinale : n = 24; break;
case fs_mensile : n = 12; break;
case fs_bimestrale : n = 6; break;
case fs_trimestrale : n = 4; break;
case fs_quadrimestrale : n = 3; break;
case fs_semestrale : n = 2; break;
case fs_annuale : n = 1; break;
default: NFCHECK("Invalid frequency");
}
return n;
}
int divide(TFrequenza_statistiche f1, TFrequenza_statistiche f2)
{
CHECK(f1 >= f2 && f2 != fs_nulla, "Invalid frequency division");
if (f1 == f2)
return 1;
switch (f1)
{
case fs_annuale:
switch(f2)
{
case fs_semestrale : return 2;
case fs_quadrimestrale: return 3;
case fs_trimestrale : return 4;
case fs_bimestrale : return 6;
case fs_mensile : return 12;
case fs_quindicinale : return 24;
case fs_settimanale : return 52;
case fs_giornaliera : return 365 ;
default : break;
}
break;
case fs_semestrale:
switch(f2)
{
case fs_trimestrale :return 2;
case fs_bimestrale :return 3;
case fs_mensile :return 6;
case fs_quindicinale :return 12;
case fs_settimanale :return 26;
// case fs_giornaliera : return (365)/2;
default :break;
}
break;
case fs_quadrimestrale:
switch(f2)
{
case fs_bimestrale :return 2;
case fs_mensile :return 4;
case fs_quindicinale :return 8;
// case fs_giornaliera : return 365/3;
default :break;
}
case fs_trimestrale:
switch(f2)
{
case fs_mensile :return 3;
case fs_quindicinale :return 6;
case fs_settimanale :return 13;
// case fs_giornaliera : return 365/4;
default :break;
}
break;
case fs_bimestrale:
switch(f2)
{
case fs_mensile :return 2;
case fs_quindicinale :return 4;
// case fs_giornaliera : return 365/6;
default :break;
}
break;
case fs_mensile:
if (f2 == fs_quindicinale)
return 2;
break;
case fs_quindicinale :
switch(f2)
{
case fs_giornaliera : return 15;
default :break;
}
break;
case fs_settimanale :
switch(f2)
{
case fs_giornaliera : return 7;
default :break;
}
break;
default:
break;
}
return 0;
}
//@cmember ritorna la parte "periodo" di una data (l'anno si ottiene da year())
// tutti i periodi cominciano da 1
int date2period(const TDate& datadoc, TFrequenza_statistiche freq)
{
int classe;
if (freq > fs_settimanale)
{
classe = datadoc.month();
switch(freq)
{
case fs_quindicinale:
classe = (classe-1) * 2 + 1;
if (datadoc.day() > 15) classe++;
break;
case fs_bimestrale:
classe = (classe-1) / 2 + 1;
break;
case fs_trimestrale:
classe = (classe-1) / 3 + 1;
break;
case fs_quadrimestrale:
classe = (classe-1) / 4 + 1;
break;
case fs_semestrale:
classe = (classe-1) / 6 + 1;
break;
case fs_annuale:
classe = 1;
break;
default: // fs_mensile
break;
}
}
else
{
const TDate primo(1, 1, datadoc.year());
classe = int(datadoc - primo);
if (freq == fs_settimanale)
{
classe /= 7;
if (classe > 51) classe = 51;
}
classe++;
}
return classe;
}
long date2long(const TDate d, TFrequenza_statistiche f)
{
return long(d.year())*long(last_period(d.year(),f))+date2period(d,f);
}
long period2long(const int anno, const int periodo, TFrequenza_statistiche f)
{
if (f==fs_annuale)
return long(anno)*long(100)+periodo;
else
return long(anno)*long(last_period(anno,f))+periodo;
}
// calcola approssimativamente la data corrispondente ad una coppia anno/periodo
const TDate & period2date(const int anno, int periodo, TFrequenza_statistiche f)
{
static TDate d;
d.set_year(anno+(periodo-1)/last_period(anno,f));
d.set_month(1);
d.set_day(1);
periodo=periodo % last_period(anno,f);
switch(f)
{
case fs_giornaliera: d+=periodo-1; break;
case fs_settimanale: d+=(periodo-1)*7; break;
case fs_quindicinale: d+=(periodo-1)*15; break;
case fs_mensile: d.set_month(periodo); break;
case fs_bimestrale: d.set_month(periodo*2); break;
case fs_trimestrale: d.set_month(periodo*3); break;
case fs_quadrimestrale:d.set_month(periodo*4); break;
case fs_semestrale: d.set_month(periodo*6); break;
case fs_annuale:
case fs_nulla:
default:
break;
}
return d;
}
const TDate& floor(TDate& data, TFrequenza_statistiche freq)
{
switch (freq)
{
case fs_settimanale:
{
/*
const TDate primo(1, 1, data.year());
int settimana = int((data - primo) / 7);
if (settimana > 51) settimana = 51;
data = primo;
data += settimana * 7;
*/
data -= data.wday()-1;
}
break;
case fs_quindicinale:
data.set_day(data.day() <= 15 ? 1 : 16);
break;
case fs_mensile:
data.set_day(1);
break;
case fs_bimestrale:
data.set_day(1);
data.set_month(((data.month()-1) / 2) * 2 + 1);
break;
case fs_trimestrale:
data.set_day(1);
data.set_month(((data.month()-1) / 3) * 3 + 1);
break;
case fs_quadrimestrale:
data.set_day(1);
data.set_month(((data.month()-1) / 4) * 4 + 1);
break;
case fs_semestrale:
data.set_day(1);
data.set_month(data.month() <= 6 ? 1 : 7);
break;
case fs_annuale:
data.set_day(1);
data.set_month(1);
break;
default: break;
}
return data;
}
const TDate& ceil(TDate& data, TFrequenza_statistiche freq)
{
floor(data, freq);
switch (freq)
{
case fs_settimanale:
data += 6;
if (data.month() == 12 && data.day() >= 29)
data.set_end_month();
break;
case fs_quindicinale:
if (data.day() == 1)
data.set_day(15);
else
data.set_end_month();
break;
case fs_mensile:
data.set_end_month();
break;
case fs_bimestrale:
data.addmonth(1);
data.set_end_month();
break;
case fs_trimestrale:
data.addmonth(2);
data.set_end_month();
break;
case fs_quadrimestrale:
data.addmonth(3);
data.set_end_month();
break;
case fs_semestrale:
data.addmonth(5);
data.set_end_month();
break;
case fs_annuale:
data.set_month(12);
data.set_day(31);
break;
default: break;
}
return data;
}
///////////////////////////////////////////////////////////
// TStats_agg
///////////////////////////////////////////////////////////
void TStats_agg::init()
{
_ditta = prefix().get_codditta();
TConfig ini(CONFIG_DITTA, "sv");
_frequenza = char2frequency(ini.get_char("Frequenza"));
_merce = ini.get_bool("StatMerce");
_prestazioni = ini.get_bool("StatPrestazioni");
_spesedoc = ini.get_bool("StatSpesedoc");
_omaggi = ini.get_bool("StatOmaggi");
_omaggio_is_merce = ini.get_bool("OmaggioIsMerce");
_omaggi_valore = ini.get_bool("OmaggioValore");
_art_nocode = ini.get_bool("ArtNoCode");
_art_noanag = ini.get_bool("ArtNoAnag");
_art_noanag_grp = ini.get_bool("ArtNoAnagGrp");
_agente = ini.get_bool("AgenteGrp");
_cliente = ini.get_bool("ClienteGrp");
_zona = ini.get_bool("ZonaGrp");
_giacenza = ini.get_bool("GiacenzaGrp");
_magazzino = ini.get_bool("MagazzinoGrp");
_catvend = ini.get_bool("CatVendGrp");
_valfield = ini.get("ValFld");
}
void TStats_agg::test_firm() const
{
const long ditta = prefix().get_codditta();
if (ditta > 0 && ditta != _ditta)
{
CHECK(_data.items() == 0, "Non cambiare ditta durante un'operazione di ricalcolo!");
((TStats_agg*)this)->init();
}
}
// scrive la chiave nel record
// utilizza la convenzione in TStats_agg::find per la tokenstring
void TStats_agg::put_key(TRectype& stat, TToken_string& key) const
{
CHECK(stat.num() == LF_SVRIEP, "Ci vuole un record delle statistiche");
stat.zero();
key.restart();
stat.put(SVR_ANNO, key.get());
stat.put(SVR_PERIODO, key.get());
stat.put(SVR_TIPODOC, key.get());
stat.put(SVR_TIPOART, key.get());
stat.put(SVR_CODART, key.get());
stat.put(SVR_UMQTA, key.get());
stat.put(SVR_CODAG, key.get());
stat.put(SVR_TIPOCF, key.get());
stat.put(SVR_CODCF, key.get());
stat.put(SVR_ZONA, key.get());
stat.put(SVR_GIAC, key.get());
stat.put(SVR_MAG, key.get());
stat.put(SVR_CATVEN, key.get());
}
// ricerca la chiave nell'assocarray
// la convenzione per la tokenstring <20> utilizzata in put_key
TStats_agg::TStats_data& TStats_agg::find(const TRiga_documento& rdoc)
{
test_firm();
const TDocumento& doc = rdoc.doc();
const TDate datadoc = doc.get_date(DOC_DATADOC);
TToken_string key(64);
key.add(datadoc.year());
key.add(date2period(datadoc));
key.add(doc.get(DOC_TIPODOC));
char tipo = rdoc.tipo().tipo();
if (tipo == RIGA_OMAGGI && _omaggio_is_merce)
tipo = RIGA_MERCE;
key.add(tipo);
TString80 codart;
if (tipo != RIGA_PRESTAZIONI && tipo != RIGA_SPESEDOC)
{
codart = rdoc.get(RDOC_CODARTMAG);
if (codart.empty() && !_art_noanag_grp)
codart = rdoc.get(RDOC_CODART);
}
else
codart = rdoc.get(RDOC_CODART);
key.add(codart);
// l'unit<69> di misura non viene MAI RAGGRUPPATA sul riepilogo statistiche!
key.add(rdoc.get(RDOC_UMQTA));
if (_agente)
key.add(doc.get(DOC_CODAG));
else
key.add("");
if (_cliente)
{
key.add(doc.get(DOC_TIPOCF));
key.add(doc.get(DOC_CODCF));
} else {
key.add("");
key.add("");
}
if (_zona)
key.add(doc.get(DOC_ZONA));
else
key.add("");
if (_giacenza)
key.add(rdoc.get(RDOC_LIVELLO));
else
key.add("");
if (_magazzino)
key.add(rdoc.get(RDOC_CODMAG));
else
key.add("");
if (_catvend)
key.add(doc.get(DOC_CATVEN));
else
key.add("");
TStats_data* ptr = (TStats_data*)_data.objptr(key);
if (ptr == NULL)
{
ptr = new TStats_data;
_data.add(key, ptr);
}
return *ptr;
}
bool TStats_agg::can_add(const TRiga_documento& rdoc) const
{
test_firm();
const TTipo_documento& tip = rdoc.doc().tipo();
bool ok = tip.statistiche();
if (ok) // Controlla se il tipo documento e' attivo per le statistiche
{
const char tipo = rdoc.tipo().tipo();
switch(tipo)
{
case RIGA_MERCE : ok = _merce; break;
case RIGA_OMAGGI : ok = _omaggi; break;
case RIGA_PRESTAZIONI: ok = _prestazioni; break;
case RIGA_SPESEDOC : ok = _spesedoc; break;
default : ok = false; break;
}
if (ok && (tipo == RIGA_MERCE || tipo == RIGA_OMAGGI) && !rdoc.is_articolo())
{
const TString& codart = rdoc.get(RDOC_CODART);
if (codart.empty())
ok = _art_nocode;
else
ok = _art_noanag;
}
}
return ok;
}
void TStats_agg::reset()
{
_data.destroy();
}
bool TStats_agg::algebric_sum(const TRiga_documento& rdoc, int sign)
{
const bool ok = can_add(rdoc);
if (ok)
{
TStats_data& data = find(rdoc);
real val_riga;
if (_valfield.empty())
{
if (_omaggi_valore && rdoc.is_omaggio())
val_riga = rdoc.imponibile_omaggio(2); // Considera il valore indipendentemente dall'addebito IVA
else
val_riga = rdoc.imponibile();
}
else
val_riga = rdoc.get_real(_valfield);
const TDocumento& d = rdoc.doc();
if (d.in_valuta())
{
TCurrency_documento v(val_riga, d);
v.change_to_firm_val();
val_riga = v.get_num();
}
if (sign < 0)
data._valore -= val_riga;
else
data._valore += val_riga;
real qta = rdoc.quantita();
if (qta.is_zero())
qta = UNO;
if (sign < 0)
data._quantita -= qta;
else
data._quantita += qta;
}
return ok;
}
bool TStats_agg::sub(const TRiga_documento& rdoc)
{
return algebric_sum(rdoc, -1);
}
bool TStats_agg::add(const TRiga_documento& rdoc)
{
return algebric_sum(rdoc, +1);
}
bool TStats_agg::empty()
{
TLocalisamfile stat(LF_SVRIEP);
// return stat.empty(); // Per ora non e' affatto affidabile
return stat.first() != NOERR;
}
bool TStats_agg::update()
{
test_firm();
bool ok = TRUE;
TToken_string key(64);
TFast_isamfile stat(LF_SVRIEP);
stat.set_curr(new TSVriep_record);
TRectype& curr = stat.curr();
_data.restart();
for (THash_object* h = _data.get_hashobj(); h; h = _data.get_hashobj())
{
TStats_data& data = (TStats_data&)h->obj();
if (data._quantita.is_zero() && data._valore.is_zero())
continue;
key = h->key();
bool saved = FALSE;
while (!saved)
{
put_key(curr, key);
int err = stat.read(_isequal, _lock);
if (err != NOERR)
put_key(curr, key);
real quantita(curr.get(SVR_QUANTITA));
real valore(curr.get(SVR_VALORE));
quantita += data._quantita;
valore += data._valore;
curr.put(SVR_QUANTITA, quantita);
curr.put(SVR_VALORE, valore);
if (err == NOERR)
err = stat.rewrite();
else
err = stat.write();
switch(err)
{
case NOERR : saved = TRUE;
break;
case _isreinsert: break;
default : saved = !yesno_box(FR("Errore %d nell'aggiornamento statistiche:"
"Si desidera ritentare?"), err);
break;
}
}
}
reset();
return ok;
}
TStats_agg::TStats_agg() : _ditta(-1)
{
}
///////////////////////////////////////////////////////////
// Record del file svriep
///////////////////////////////////////////////////////////
TSVriep_record:: TSVriep_record(): TVariable_rectype(LF_SVRIEP)
{}
TSVriep_record::~TSVriep_record()
{}
const TString & TSVriep_record::get_str(const char* fieldname) const
{
static TString80 chiavi;
chiavi=TRectype::get_str(SVR_CHIAVI);
if (strcmp(fieldname,SVR_CODART)==0)
return chiavi.mid(0,20);
else if (strcmp(fieldname,SVR_CODAG)==0)
return chiavi.mid(20,5);
else if (strcmp(fieldname,SVR_TIPOCF)==0)
return chiavi.mid(25,1);
else if (strcmp(fieldname,SVR_CODCF)==0)
return chiavi.mid(26,6);
else if (strcmp(fieldname,SVR_ZONA)==0)
return chiavi.mid(32,3);
else if (strcmp(fieldname,SVR_GIAC)==0)
return chiavi.mid(35,15);
else if (strcmp(fieldname,SVR_CATVEN)==0)
return chiavi.mid(50,3);
else if (strcmp(fieldname,SVR_MAG)==0)
return chiavi.mid(53,3);
else
return TRectype::get_str(fieldname);
}
void TSVriep_record::put_str(const char* fieldname, const char* v)
{
const TString80 val(v);
TString80 chiavi(TRectype::get_str(SVR_CHIAVI));
if (strcmp(fieldname,SVR_CODART)==0)
chiavi.overwrite(val,0);
else if (strcmp(fieldname,SVR_CODAG)==0)
chiavi.overwrite(val,20);
else if (strcmp(fieldname,SVR_TIPOCF)==0)
chiavi.overwrite(val,25);
else if (strcmp(fieldname,SVR_CODCF)==0)
chiavi.overwrite(val,26);
else if (strcmp(fieldname,SVR_ZONA)==0)
chiavi.overwrite(val,32);
else if (strcmp(fieldname,SVR_GIAC)==0)
chiavi.overwrite(val,35);
else if (strcmp(fieldname,SVR_CATVEN)==0)
chiavi.overwrite(val,50);
else if (strcmp(fieldname,SVR_MAG)==0)
chiavi.overwrite(val,53);
else
{
TRectype::put_str(fieldname,val);
return ;
}
TRectype::put_str(SVR_CHIAVI,chiavi);
return ;
}
///////////////////////////////////////////////////////////
// cerca di restituire una chiave di bassa priorit<69> (livello
const TString & TStat_cache::getkey2discard()
{
THash_object * o;
CHECK(items()>0,"E' stata chiamata la funzione getkey2discard con la cache vuota");
while ((o=_cache.get_hashobj()) == NULL) ;
if (((TRectype &)o->obj()).get_int(SVS_LIVELLO)<=1)
{
while ((o=_cache.get_hashobj()) == NULL) ;
if (((TRectype &)o->obj()).get_int(SVS_LIVELLO)==0)
while ((o=_cache.get_hashobj()) == NULL) ;
}
return o->key();
}
TStat_cache::TStat_cache (TLocalisamfile *f, bool lock):
TRWrecord_cache( f,1,lock)
{
}
// azzera la cache e distrugge il file!
void TStat_cache::zap()
{
clear();
int err=NOERR;
while (err==NOERR)
{
err=file().first();
if (err==NOERR)
err=file().remove();
}
}