#include <applicat.h>
#include <dongle.h>
#include <modaut.h>
#include <printer.h>
#include <recarray.h>

#include "ce3.h"
#include "celib.h"
#include "../cg/cglib01.h"
#include "ce2101.h"

#include "ce3300a.h"
#include "ce3300.h"

#include "ammce.h"
#include "ammmv.h"
#include "cespi.h"
#include "movam.h"
#include "movce.h"
#include "salce.h"

//===============================================================================================//
//-----FORM--------------------------------------------------------------------------------------//
class TForm_prospettocesp : public TForm_cespiti
{ 
   
public:
  virtual bool validate(TForm_item &cf, TToken_string &s);
  void set_testata() {set_header(1,TRUE);}
  void set_pedata() {set_footer(1,FALSE); set_footer(1,TRUE);}
  TPrint_section& get_body() {return section('B', odd_page);}
  TForm_prospettocesp();
  
  virtual ~TForm_prospettocesp();
};
  
TForm_prospettocesp::TForm_prospettocesp() :TForm_cespiti ("ce3300a")            //costruttore
{
}

TForm_prospettocesp::~TForm_prospettocesp()
{ 
}

bool TForm_prospettocesp::validate(TForm_item &cf, TToken_string &s)
{
  return TForm_cespiti::validate(cf,s);   //richiama la validate standard della classe genitore (TForm_cespiti)
}

//==============================================================================================//
//-----AUTOMASK---------------------------------------------------------------------------------//  
class TStampaprospetto_mask : public TAutomask
{
  TRelation * _rel;
  TCursor * _cur;

protected:
  bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:               

  TStampaprospetto_mask();
  
  virtual ~TStampaprospetto_mask(){};
};
  
TStampaprospetto_mask::TStampaprospetto_mask() :TAutomask ("ce3300a")
{
  ditta_cespiti().init_mask(* this);

  const bool has_ca = dongle().active(CAAUT);
  //se la chiave ha CA mostra i campi gruppo 2 (analitica)..
  if (has_ca)
    show(-1);
  else
    hide(-1);
}  
  
bool TStampaprospetto_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
  switch (o.dlg())
  {
  case F_SITFISC :
    if (e == fe_close)
    {
      if (!get_bool(F_SITFISC) && !get_bool(F_SITCIV) && !get_bool(F_SITGEST))     //deve essere selezionata almeno 1 situaz.
        return error_box(TR("Selezionare almeno una delle Situazioni da stampare"));     
    }
    break;
  default: break;
  }  
  return TRUE;
}

//=======================================================================================================================//
struct TTotali : public TObject
{
  real _tot_csto;
  real _tot_riv;
  real _tot_riveser;
  real _tot_acqincr;
  real _tot_cesselim2;
  real _tot_fondinieser;
  real _tot_incr;
  real _tot_cesselim3;
  real _tot_reinplus;
  real _tot_ammnor;
  real _tot_ammacc;
  real _tot_ammant;
  
  void azzera();
  TTotali& operator += (const TTotali& t);  
};

void TTotali::azzera()
{
  _tot_csto = 0;
  _tot_riv = 0;
  _tot_riveser = 0;
  _tot_acqincr = 0;
  _tot_cesselim2 = 0;
  _tot_fondinieser = 0;
  _tot_incr = 0;
  _tot_cesselim3 = 0;
  _tot_reinplus = 0;
  _tot_ammnor = 0;
  _tot_ammacc = 0;
  _tot_ammant = 0;
}

//-----------------------------------------------------------------------------------------------------------------------//
TTotali& TTotali::operator += (const TTotali& t)
{
  _tot_csto += t._tot_csto;
  _tot_riv += t._tot_riv;
  _tot_riveser += t._tot_riveser;
  _tot_acqincr += t._tot_acqincr;
  _tot_cesselim2 += t._tot_cesselim2;
  _tot_fondinieser += t._tot_fondinieser;
  _tot_incr += t._tot_incr;
  _tot_cesselim3 += t._tot_cesselim3;
  _tot_reinplus += t._tot_reinplus;
  _tot_ammnor += t._tot_ammnor;
  _tot_ammacc += t._tot_ammacc;
  _tot_ammant += t._tot_ammant;
  
  return *this;  //ritorna se stesso, quindi i valori dei totali
}

//=======================================================================================================================//
//-----SKELETON APPLICATION----------------------------------------------------------------------------------------------//
class TStampa_prospetto : public TSkeleton_application
{
  TStampaprospetto_mask * _mask;
  TForm_prospettocesp * _form;

protected:
  virtual bool create();
  virtual bool destroy();
  virtual void main_loop();

  void set_intestazione( const int tipo, const int ordinamento);
  void set_pavimentazione();
  void stampa_totali_cat(const TString& codicecat, const TString& descrcat);  //stampa sul form i valori totali per categoria
  void stampa_totali_tipo(TTipo_cespite tcesp);     //stampa sul form i valori totali per tipo cespite (materiale, immateriale, pluriennale)
  void stampa_totali_generali();     //stampa sul form i valori totali per tutti i cespiti
  void fill_body(const TTotali& tot);   //riempie il campo body con tutti i totali
  void print_body();  //stampa effettivamente il body
  void set_field(int id, const real& val); //mette in un campo del body odd un valore numerico
  void set_field(int id, const char* val); //mette in un campo del body odd una stringa
  void aggiorna_totali(TCursor& cur, const int tipo, TTipo_cespite tcesp);   //calcola effettivamente i totali di ciascuna categoria

public:
  TStampa_prospetto() {}
  
private:
  TDate _dataini;
  TDate _datafine;
  TTotali _cat, _mtr, _gen; //sono i tre set di totali (categoria, materiali, generali)
    
};

bool TStampa_prospetto::create()
{
  open_files(LF_CESPI, LF_SALCE, LF_AMMCE, LF_MOVCE, LF_AMMMV, 0);
  _mask = new TStampaprospetto_mask;
  _form = new TForm_prospettocesp;
  
  return TSkeleton_application::create();
}

bool TStampa_prospetto::destroy()
{
  delete _mask;
  delete _form;
  return TSkeleton_application::destroy();
}

//------------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::set_intestazione( const int tipo, const int ordinamento)
{  
// scrive l'header first, contenente i dati della ditta e dell'esercizio  
  _form->find_field('H', first_page, FR_CODDITTA).set(_mask->get(F_CODDITTA));
  _form->find_field('H', first_page, FR_RAGSOC).set(_mask->get(F_DESCRDITTA));
  _form->find_field('H', first_page, FR_GRUPPO).set(_mask->get(F_GRUPPO));
  _form->find_field('H', first_page, FR_D_GRUPPO).set(_mask->get(F_D_GRUPPO));
  _form->find_field('H', first_page, FR_SPECIE).set(_mask->get(F_SPECIE));
  _form->find_field('H', first_page, FR_D_SPECIE).set(_mask->get(F_D_SPECIE));
  _form->find_field('H', first_page, FR_DATAINIZIO).set(_dataini);
  _form->find_field('H', first_page, FR_DATAFINE).set(_datafine);
  
// in base all'ordinamento (per categoria o per impianto) scrive la riga con codice e descrizione  
  if (ordinamento == 0)
  {
    _form->find_field('H', first_page, FR_INT_COD).set(FR("@bCat.@r"));
    _form->find_field('H', first_page, FR_INT_DESC).set(FR("@bDescrizione categoria@r"));
  }
  else
  {
    _form->find_field('H', first_page, FR_INT_COD).set(TR("Imp."));
    _form->find_field('H', first_page, FR_INT_DESC).set(TR("    Descr. impianto"));
  }

//in base al(ai) tipo(i) di situazione cambia una riga dell'header    
  switch(tipo)      
  {
  case 1:
    _form->find_field('H', first_page, FR_SITUAZIONE).set(TR("fiscale"));
    break;
  case 2:
    _form->find_field('H', first_page, FR_SITUAZIONE).set(TR("civilistica"));
    break;
  case 3:
    _form->find_field('H', first_page, FR_SITUAZIONE).set(TR("gestionale"));
    break;
  }  
  _form->set_testata();
}

//-----------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::set_pavimentazione()
{
  _form->set_pedata();
}
//-----------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::print_body()
{                                          
  set_pavimentazione();                       // stampa il fondo pagina
  TPrint_section& body = _form->get_body();
  body.update();
  if (body.height() > printer().rows_left())
    printer().formfeed(); 
  for (word i = 0; i < body.height(); i++)        // stampa le righe del body
    printer().print(body.row(i));                
}
//-----------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::stampa_totali_cat(const TString& codicecat, const TString& descrcat )
{
// scrive codice e descrizione della categoria di cui stampa i valori
  set_field(FR_TC_CAT,codicecat);
  set_field(FR_TC_D_CAT,descrcat);
  
// riempie il body con i totali per categoria
  fill_body(_cat);

// stampa effettivamente il body sul form 
  print_body(); 
  
// somma sui totali materiali
  _mtr += _cat;
    
  _gen += _cat;
}
//-------------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::stampa_totali_tipo(TTipo_cespite tcesp)
{
// scrive il tipo di cespiti di cui calcola il totale
  set_field(FR_TC_CAT,"");
  TString80 tipodescr;
  tipodescr << TR("TOTALI BENI") << ' ';
  switch (tcesp)
  {
  case tc_pluriennale: tipodescr << TR("PLURIENNALI"); break;
  case tc_immateriale: tipodescr << TR("IMMATERIALI"); break;
  default: tipodescr << TR("MATERIALI"); break;
  }
  set_field(FR_TC_D_CAT,tipodescr);
  
// riempie il body con i totali per tipologia cespite (per situazione)
  fill_body(_mtr);

// stampa effettivamente il body sul form 
  print_body();
}
//-------------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::stampa_totali_generali()
{ 
// scrive TOTALI GENERALI
  set_field(FR_TC_CAT,"");
  set_field(FR_TC_D_CAT,TR("TOTALI GENERALI"));
// riempie il body con i totali generali per situazione selezionata
  fill_body(_gen);

// stampa effettivamente il body sul form 
  print_body();
}
//-------------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::set_field(int id, const real& val)
{
  _form->find_field('B', odd_page, id).set(val.string()); 
}
//-------------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::set_field(int id, const char* val)
{
  _form->find_field('B', odd_page, id).set(val); 
}
//-------------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::fill_body(const TTotali& tot)
{
// riempie il body odd, contenente i totali; lo fa chiamando la set_field per ogni campo
  set_field(FR_TC_CSTO,tot._tot_csto);
  set_field(FR_TC_TOTRIV,tot._tot_riv);
  real tempval1 = tot._tot_csto+tot._tot_riv;
  set_field(FR_TC_VALINIES,tempval1);
  set_field(FR_TC_RIVALES,tot._tot_riveser);
  set_field(FR_TC_ACQINCR,tot._tot_acqincr);
  set_field(FR_TC_CESSELIM2,tot._tot_cesselim2);
  tempval1 += tot._tot_riveser + tot._tot_acqincr - tot._tot_cesselim2;
  set_field(FR_TC_VALBIL,tempval1);
  set_field(FR_TC_FONDINIES,tot._tot_fondinieser);
  set_field(FR_TC_INCR,tot._tot_incr);
  set_field(FR_TC_CESSELIM3,tot._tot_cesselim3);
  set_field(FR_TC_REINPLUS,tot._tot_reinplus);
  set_field(FR_TC_AMMNOR,tot._tot_ammnor);
  set_field(FR_TC_AMMACC,tot._tot_ammacc);
  set_field(FR_TC_AMMANT,tot._tot_ammant);
  real tempval2 = tot._tot_fondinieser + tot._tot_incr - tot._tot_cesselim3 + tot._tot_reinplus + tot._tot_ammnor + tot._tot_ammacc +tot._tot_ammant;
  set_field(FR_TC_FONDBIL,tempval2);
  tempval2 = tempval1 - tempval2;
  if (tempval2 < ZERO)
    tempval2 = ZERO;
  set_field(FR_TC_RESBIL,tempval2);
}
//-------------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::aggiorna_totali(TCursor& curcespi, const int tipo, TTipo_cespite tcesp)
{ 
// valori della riga 1 (dipendenti da tipo solo le rivgf/rivgc)
  const TRectype& recsalce = curcespi.curr(LF_SALCE);
  const real csto1 = recsalce.get_real(SALCE_CSTO);

  const TRectype& cespi = curcespi.curr();
  const bool leasing = cespi.get_bool(CESPI_LEASING);
  
	_cat._tot_csto += csto1;
  if (tipo == 2)
    _cat._tot_csto -= recsalce.get_real(SALCE_VNONAMMC);
  else
    _cat._tot_csto -= recsalce.get_real(SALCE_VNONAMM);
	_cat._tot_csto -= recsalce.get_real(SALCE_VNONAMM06);
  
  real rivsalce = recsalce.get_real(SALCE_RIV75);
	rivsalce += recsalce.get_real(SALCE_RIV83);
  rivsalce += recsalce.get_real(SALCE_RIV90);
  rivsalce += recsalce.get_real(SALCE_RIV91);
  
	_cat._tot_riv += rivsalce;
  if (tipo == 1 || leasing)
    _cat._tot_riv += recsalce.get_real(SALCE_RIVGF); else
  if (tipo == 2 && !leasing)
    _cat._tot_riv += recsalce.get_real(SALCE_RIVGC);

// valori della riga 2 (e, gi� che si fa la scansione dei movimenti, anche i valori dei movam della riga 3)
// (i valori della riga 2 non dipendono da tipo, mentre quelli della riga 3 si, in quanto hanno movam) 
  TRectype recmovce(LF_MOVCE);
  const TString16 idcespite = cespi.get(CESPI_IDCESPITE);
  recmovce.put(MOVCE_IDCESPITE, idcespite);

  real amv_ammnor, amv_ammacc, amv_ammant;
    
  TRelation relmovce(LF_MOVCE);
// viene aggiunta la relazione su movam (che contiene il filtro su tpamm dovuto al tipo di situazione scelto nella maschera)..
  TString expr;
  expr << "IDCESPITE==IDCESPITE|IDMOV==IDMOV|TPAMM==" << tipo; 
  relmovce.add(LF_MOVAM, expr);
//.. e quindi viene aggiunta la relazione su ammmv (che contiene il filtro su tpamm dovuto al tipo di situazione scelto nella
// maschera) utilizzando la stessa espressione di filtro, in quanto la chiave di ammmv � identica a quella di movam (ol�!)
  relmovce.add(LF_AMMMV, expr);
// Scansione movimenti in base alla chiave IDCESPITE+IDMOV
  TCursor curmovce (&relmovce, "", 2, &recmovce, &recmovce);
  const TRecnotype num1 = curmovce.items();

  if (num1 > 0)
  {
    curmovce.freeze();
  
    const TRectype& movce = curmovce.curr();
    const TRectype& movam = curmovce.curr(LF_MOVAM);
    const TRectype& ammmv = curmovce.curr(LF_AMMMV);
    for (curmovce=0; curmovce.pos() < num1; ++curmovce)
    { 
      const TDate dtmov = movce.get_date(MOVCE_DTMOV);
      if (dtmov >= _dataini && dtmov <= _datafine)
      { 
        const TString4 codmov = movce.get(MOVCE_CODMOV);
        const char tmc = cache().get("%TMC", codmov, "S6")[0];   //prende il valore del campo S6 nella tabella tipi movimento
        const char segno = movce.get_char(MOVCE_SEGNO);           
        const real signum = segno == '-' ? -UNO : UNO;   //serve per sommare i movimenti con il loro segno effettivo
      
			  real rivmovce = movce.get_real(MOVCE_RIV75);
        rivmovce += movce.get_real(MOVCE_RIV83);
        rivmovce += movce.get_real(MOVCE_RIV90);
        rivmovce += movce.get_real(MOVCE_RIV91);

        const real csto2 = movce.get_real(MOVCE_CSTO);
  // inquietante modo di selezionare la rivg (rivgf o rivgc) in base al tipo senza usare una if else!
        real rivg;
        if (tipo == 1 || leasing)
          rivg = movce.get_real(MOVCE_RIVGF); else
        if (tipo == 2 && !leasing)
          rivg = movce.get_real(MOVCE_RIVGC);

        real qmovam = movam.get_real(MOVAM_QNOR);
        qmovam += movam.get_real(MOVAM_QACC);
        qmovam += movam.get_real(MOVAM_QANT);  

        real qammmv;
        qammmv += ammmv.get_real(AMMMV_QNOR);
        qammmv += ammmv.get_real(AMMMV_QACC);
        qammmv += ammmv.get_real(AMMMV_QANT);  

        if (tmc == 'R')        
          _cat._tot_riveser += (rivmovce + rivg) * signum; else
        if (tmc == 'P')        
          _cat._tot_reinplus += movce.get_real(MOVCE_PLUSREIN) * signum; else
        if (tmc == 'I' || (tmc <= ' ' && segno == '+'))
        {
          _cat._tot_acqincr += (csto2 + rivmovce + rivg) * signum;
          _cat._tot_incr += qmovam * signum;
        } else
        if (tmc == 'E' || (tmc <= ' ' && segno == '-'))
        {
          _cat._tot_cesselim2 += (csto2 + rivmovce + rivg) * (-signum);
          _cat._tot_cesselim3 += qmovam * (-signum);
          _cat._tot_cesselim3 += qammmv * (-signum); // Aggiunto il 04/05/2008
        }

        // viene preso l'ammortamento da ammmv (che verr� poi sommato nella riga 4, pi� sotto, a quello
        // preso da ammce); l'ammortamento viene preso qui in quanto � relativo ai movimenti che vengono qui scanditi
        amv_ammnor += qammmv;
 
      }  //fine controllo sulle date
    }  //fine scansione sui movimenti
  }
  
// valori delle righe 3 e 4 di ammce (questi valori dipendono dal tipo di situazione selezionato nella maschera)
// record con chiave idcespite,codes,tpamm
  TRectype recammce(LF_AMMCE);
  recammce.put(AMMCE_IDCESPITE, idcespite);
  recammce.put(AMMCE_CODES, _mask->get(F_ESERCIZIO));
// filtro sul tpamm (va messo per non prendere tutti gli ammortamenti (dei 3 tipi) assieme)  
  expr.cut(0) << AMMCE_TPAMM << "=" << tipo;
  TRelation relammce(LF_AMMCE);
  
  TCursor curammce (&relammce, expr, 1, &recammce, &recammce);
  const TRecnotype num2 = curammce.items();
  curammce.freeze();
  const TRectype& ammce = curammce.curr();

  // scandisce gli ammce del cespite (al massimo 2 per ogni codes, ovvero iniziale e finale)  
  for (curammce=0; curammce.pos()<num2; ++curammce)
  { 
// se tpsaldo = 1 (inizio) gli ammortamenti sono....
    if (ammce.get_int(AMMCE_TPSALDO) == 1)
    {  
      _cat._tot_fondinieser += ammce.get_real(AMMCE_QNOR);
      _cat._tot_fondinieser += ammce.get_real(AMMCE_QACC);
      _cat._tot_fondinieser += ammce.get_real(AMMCE_QANT);
    }
// se invece tpsaldo = 2 (fine) gli ammortamenti sono....
    else
    {
      _cat._tot_ammnor += ammce.get_real(AMMCE_QNOR);
      _cat._tot_ammacc += ammce.get_real(AMMCE_QACC);
      _cat._tot_ammant += ammce.get_real(AMMCE_QANT);

// gli ammortamenti devono tenere conto anche di quelli sui movimenti, calcolati
// durante la scansione dei movimenti      
      _cat._tot_ammnor += amv_ammnor;
      _cat._tot_ammacc += amv_ammacc;
      _cat._tot_ammant += amv_ammant;
    }
    
  }  // fine scansione sugli ammce  

}  // fine routine

//-----------------------------------------------------------------------------------------------------------------------//
void TStampa_prospetto::main_loop()
{ 
  _mask->set(F_SITFISC,"X");
  while (_mask->run() == K_ENTER)
  {
    const int esercizio = _mask->get_int(F_ESERCIZIO);
    const int gru = _mask->get_int(F_GRUPPO);
    const TString4 spe = _mask->get(F_SPECIE);
    ditta_cespiti().set_attivita(esercizio, gru, spe);   

// record su esercizio,gruppo,specie
    TRectype rec(LF_CESPI);    
    rec.put(CESPI_CODCGRA, gru);
    rec.put(CESPI_CODSPA, spe);   
// relazione su lf_cespi e lf_salce
    TRelation relcespi(LF_CESPI);
    TString espr;
    espr << "IDCESPITE==IDCESPITE|CODES==" << esercizio;
    relcespi.add(LF_SALCE,espr);
// vanno esclusi i cespiti alienati?
    const bool exclude_aliens = _mask->get_bool(F_EXCLUDE_ALIENS);
// filtro su esercizio gruppo specie e data acquisto cespite sia <= alla data fine esercizio selezionato       
    TString filtro;
    _dataini = _mask->get_date(F_INIZIO_ES);
    _datafine = _mask->get_date(F_FINE_ES);
    filtro << "(CODCGRA=\"" << _mask->get_int(F_GRUPPO)<< "\")&&" ;
    filtro << "(CODSPA=\"" << _mask->get(F_SPECIE)<< "\")&&" ;
    filtro << "(" << LF_SALCE << "->CODES=" << esercizio << ")&&" ;
    filtro << "(ANSI(" << LF_CESPI << "->DTCOMP)<=" << _datafine.date2ansi() << ")"; 
    if (exclude_aliens)
      filtro << "&&((ANSI(" << LF_CESPI << "->DTALIEN)='')||(ANSI(" << LF_CESPI << "->DTALIEN)>=" << _dataini.date2ansi() << "))";
// prepara il cursore di tipo sorted perch� ho due tipi di ordinamento possibili: per categoria e per impianto
    const int ordinamento = _mask->get_int(F_ORDINA);
    TString16 ordin = ordinamento == 0 ? CESPI_CODCAT : CESPI_CODIMP;
    ordin << '|' <<CESPI_IDCESPITE;     
    TSorted_cursor sortcur (&relcespi, ordin, filtro, 1, &rec, &rec);
    //sortcur.setregion(rec,rec);  
    //sortcur.setfilter(filtro,TRUE);
    
    const TRecnotype num = sortcur.items();
    sortcur.freeze();
    printer().open();
// scansione sulle 3 possibili situazioni stampabili: 1=fiscale; 2=civilistica; 3=gestionale.
    for (int sit = 1; sit <= 3; sit++)
    { 
// stampa solo le situazioni selezionate
      if (sit == 1 && !_mask->get_bool(F_SITFISC))
        continue;
      if (sit == 2 && !_mask->get_bool(F_SITCIV))
        continue;
      if (sit == 3 && !_mask->get_bool(F_SITGEST))
        continue;
// setta l'intestazione del form...
      set_intestazione(sit, ordinamento);
// ed il fondo pagina
      set_pavimentazione();
  // gestione categorie ed effettivo main loop di stampa   
  // azzera i totali generali (se mai non lo fossero)  
      _gen.azzera();
  // scansiona sui 3 tipi di cespite (materiale, immateriale, pluriennale)    
      for (int i = 0; i <= 2; i++)
      {
        const TTipo_cespite tipocespite = (TTipo_cespite)i;  // trasforma l'intero i in un tipo cespite
      
        TString8 currcodcat = "@@";  //codice categoria iniziale (non si pu� metterlo nullo perch� potrebbe esistere)
        TString80 currdescat = "";
        
        _mtr.azzera();        // azzeratore tipi cespite (materiali, immateriali, pluriennali)
        for (sortcur=0; sortcur.pos()<num; ++sortcur)    //scansione su tutti i cespiti della categoria indicata in precedenza
        { 
          const TCespite ces(sortcur.curr());
          if (ces.tipo() == tipocespite)          //considera solo i cespiti del tipo attualmente selezionato 
          {
            const TString8 codcat = sortcur.curr().get(ordinamento == 0 ? CESPI_CODCAT : CESPI_CODIMP);
            if (codcat != currcodcat)            //cambia categoria
            {
              if (currcodcat != "@@")
                stampa_totali_cat(currcodcat,currdescat);  //serve per stampare l'ultima categoria (perch� ogni categoria viene stampata quando inizia la scansione della successiva)
                
              _cat.azzera();
              currcodcat = codcat;
              if (ordinamento == 0)                       //se ordinato (ed aggregato) per categoria...
                currdescat = ces.categoria().get("S0");
              else                                        //se ordinato (ed aggregato) per impianto...
                currdescat = cache().get("CIM", currcodcat, "S0");
                      
            }
            aggiorna_totali (sortcur, sit, tipocespite);
          }    
        } // fine scansione cespiti della categoria selezionata
        if (currcodcat != "@@")
          stampa_totali_cat(currcodcat,currdescat);
          
        stampa_totali_tipo(tipocespite);
      } // fine scansione tipi cespite 
      
      stampa_totali_generali();
// salta una pagina al termine della situazione stampata      
      printer().formfeed();
    } // fine scansione su situazione da stampare (civilistica,fiscale,gestionale)

    printer().close();
  }    


}

   
int ce3300(int argc, char* argv[])
{ 
  TStampa_prospetto a;
  a.run(argc,argv,TR("Stampa prospetto cespiti"));
  return 0;
}