#include <diction.h>
#include <printer.h>
#include <viswin.h>

#include "velib04.h"

#include "../ca/movana.h"
#include "../ca/rmovana.h"
#include "../ca/rrip.h"
#include "../cg/cg2101.h"
#include "../cg/cg2103.h"
#include "../mg/anamag.h"

///////////////////////////////////////////////////////////
// TCache_causali
///////////////////////////////////////////////////////////

class TCache_causali : public TCache
{
protected:
  TObject* key2obj(const char* key);

public:
  const TCausale& causale(const TDocumento& doc, const TString & fld_cms);
  TCache_causali() : TCache(17) { }
};

TObject* TCache_causali::key2obj(const char* key)
{
	TToken_string k(key);
	TString4 cod;
	k.get(0, cod);
	cod.trim();
	int year; k.get(1, year);
  return new TCausale(cod, year);
}

const TCausale& TCache_causali::causale(const TDocumento& doc, const TString & fld_cms)
{
	TString4 codcaus;
	TToken_string key;

	if (!fld_cms.blank())
	{
		const TString & cms = doc.commessa_principale();

		if (!cms.blank())
		{
			key.add(cms);
			const TString16 fld_val = cache().get(LF_COMMESSE, key, fld_cms);

			if (!fld_val.blank())
			{
				key = "CTCMS";
				key.add(doc.tipo().codice());
				key.add(fld_val);
				codcaus = cache().get(LF_MULTIREL, key, "DATA");
			}
		}
	}
	if (codcaus.blank())
	{
		// Cerca il codice causale sul cliente
		const char* const fld = doc.is_nota_credito() ? CFV_CODCAUSNC : CFV_CODCAUS;

		key.format("%c|%ld", doc.get_char(DOC_TIPOCF), doc.get_long(DOC_CODCF));
		codcaus = cache().get(LF_CFVEN, key, fld); 
		if (codcaus.blank()) // Se non lo trova guarda sul tipo documento
		{
			const TTipo_documento& tipo = doc.tipo();
			codcaus = tipo.causale();
		}
	}

	//Assegna l'anno della causale
	const int year = doc.get_date(DOC_DATADOC).year();
	key.format("%4s|%4d", (const char*)codcaus, year);
  // Trasforma il codice in causale vera e propria
  return (const TCausale&)*objptr(key);
}

///////////////////////////////////////////////////////////
// TContabilizzazione_analitica
///////////////////////////////////////////////////////////

const TCausale& TContabilizzazione_analitica::doc2caus(const TDocumento& doc)
{
  CHECK(_caus, "Cache nulla");
  return _caus->causale(doc, _fld_cms_cont);
}

const TCausale& TContabilizzazione_analitica::rdoc2caus(const TRiga_documento& rdoc)
{
  return doc2caus(rdoc.doc());
}

// Copiata dalla contabilizzazione ed eliminati riferimenti a tutte le variabili globali del cazzo
bool TContabilizzazione_analitica::search_costo_ricavo(const TRiga_documento& r, TBill& conto, bool riclassifica_fdr_fde)
{
  TString16 clifo_key; 
  clifo_key.format("%c|%ld", r.doc().get_char(DOC_TIPOCF), r.doc().get_long(DOC_CODCF));

  const TRectype& cli_file = cache().get(LF_CLIFO, clifo_key);
  const bool skip_clifo = cli_file.empty();
  
  const bool is_cli = clifo_key[0] != 'F';
  bool skip_art_related = false;
  
  const TCodiceIVA codiva(r.get(RDOC_CODIVA));
  const char t = r.tipo().tipo();
  
  switch (t)
  {
    case RIGA_OMAGGI: // righe omaggio come articoli spiaccicato identico (avranno imponibile 0)
    case RIGA_MERCE:  // righe di merce
    {
      // posiziona l'anagrafica sull'articolo specificato sulla ..iga
      const TRectype& anamag = cache().get(LF_ANAMAG, r.get(RDOC_CODARTMAG));
      if (anamag.empty()) // se non trova l'articolo saltera' anche gmc,smc,rfa.
        skip_art_related = true;
      
      TString4 tok;
      // Scorre la stringa di ricerca
      const int items = _search_seq.items();
      for (int i=0; i < items;i++)
      { 
        _search_seq.get(i, tok);
        if (tok == "CF")
        {
          if (skip_clifo) continue;
          const int gr = cli_file.get_int(CLI_GRUPPORIC);
          const int co = cli_file.get_int(CLI_CONTORIC);
          const long so = cli_file.get_long(CLI_SOTTOCRIC);
          conto.set(gr,co,so);
          if (conto.ok()) 
						break; // se lo trova esce (tutti != 0)
        } else
        if (tok == "CA")
        {
          const TCausale& caus = rdoc2caus(r);
          if (caus.IVA2bill(codiva,conto)) 
            break; // se lo trova esce
        } else
        if (tok == "AR")
        {
          if (skip_art_related) 
            continue;
          int gr = anamag.get_int(is_cli ? ANAMAG_GRUPPOV : ANAMAG_GRUPPOA);
          int co = anamag.get_int(is_cli ? ANAMAG_CONTOV : ANAMAG_CONTOA);
          long so = anamag.get_long(is_cli ? ANAMAG_SOTTOCV : ANAMAG_SOTTOCA);
          conto.set(gr,co,so);
          if (!conto.ok()) // se il conto non c'e' guarda la categoria acquisti/vendite
          {
            const TString16 codtab = anamag.get(is_cli ? ANAMAG_CATCONV : ANAMAG_CATCONA);
            const TRectype& t = cache().get(is_cli ? "CRA" : "CAA", codtab);     
            if (!t.empty())
            {
              gr = t.get_int("I0");
              co = t.get_int("I1");
              so = t.get_long("I2");
              conto.set(gr,co,so);
            }
          }
          if (conto.ok()) 
						break;
        } else
        if (tok == "GM" || tok == "SM" || tok == "RF")
        {
          if (skip_art_related) 
            continue;
          const bool is_fis = tok == "RF";
          TString16 codtab = anamag.get(is_fis ? ANAMAG_RAGGFIS : ANAMAG_GRMERC);
          if (tok == "GM" && codtab.len() > 3)
            codtab.cut(3); // gli ultimi 2 si riferiscono al sottogruppo.
          const TRectype& tab = cache().get(is_fis ? "RFA" : "GMC", codtab);
          if (!tab.empty())
          {
            const int gr = tab.get_int(is_cli ? "I3" : "I0");
            const int co = tab.get_int(is_cli ? "I4" : "I1");
            const long so = tab.get_long(is_cli ? "I5" : "I2");
            conto.set(gr,co,so);
          }
          if (conto.ok()) 
            break;
        } else
        if (tok == "CV" || tok == "CC")
        {
          const bool is_cve = tok == "CV";
          if (is_cve && !is_cli) 
            continue; // se e' un fornitore salta questa condizione
          TString16 cod = is_cve ? r.doc().get(DOC_CATVEN) : EMPTY_STRING;
          if (cod.empty())
          {
            if (skip_clifo) 
              continue; // se non aveva trovato il cliente salta al prossimo

            const TRectype& cfven = cache().get(LF_CFVEN, clifo_key);
            cod = cfven.get(is_cve ? CFV_CATVEN : CFV_CODCATC);
          }
          const TRectype& t = cache().get(is_cve ? "CVE" : "CCO", cod);
          if (!t.empty())
          {
            const bool x =(is_cve || is_cli);
            const int gr = t.get_int(x ? "I3" : "I0");
            const int co = t.get_int(x ? "I4" : "I1");
            const long so = t.get_long(x ? "I5": "I2");
            conto.set(gr,co,so);
          }
          if (conto.ok()) 
            break;
        }
      }
      break; // case 'M'
    }
    case RIGA_SPESEDOC: 
    case RIGA_PRESTAZIONI:
    case RIGA_ATTREZZATURE: 
    case RIGA_RISORSE:
    {
      const TSpesa_prest tab(r.get(RDOC_CODART), t);
      if (!tab.empty())
      {
        int gr = tab.get_int(is_cli ? "I0" : "I3");
        int co = tab.get_int(is_cli ? "I1" : "I4");
        long so = tab.get_long(is_cli ? "I2" : "I5");
        conto.set(gr,co,so);                    
        if (!is_cli && !conto.ok())
        {
          gr = r.get_int("QTAGG1");
          co = r.get_int("QTAGG2");
          so = r.get_long("QTAGG3");
          conto.set(gr,co,so);                    
        }
      }
      
      // Cerca il conto nella stringa di ricerca (solo per prestazioni)
      if (t == RIGA_PRESTAZIONI && !conto.find()) 
      {
        TString4 tok;
        // Scorre la stringa di ricerca ma solo per causale o CLI/FO
        const int items = _search_seq.items();
        for (int i=0; i<items;i++)
        { 
          _search_seq.get(i, tok);
          if (tok == "CF")
          {
            if (skip_clifo) 
              continue;
            const int gr = cli_file.get_int(CLI_GRUPPORIC);
            const int co = cli_file.get_int(CLI_CONTORIC);
            const long so = cli_file.get_long(CLI_SOTTOCRIC);
            conto.set(gr,co,so);
            if (conto.ok()) 
              break;
          } else
          if (tok == "CA")
          {
            const TCausale& caus = rdoc2caus(r);
            if (caus.IVA2bill(codiva,conto)) 
              break;
          }
        }
      }

			static int __searching = false;
			
			if (!conto.ok() && t == RIGA_SPESEDOC && !__searching)
			{
				const int rows = r.doc().physical_rows();
				int row = -1;

				for (int i = 1; row < 0 && i <= rows; i++)
				{
					const char tipo = r.doc()[i].tipo().tipo();
					if (tipo != RIGA_DESCRIZIONI &&	tipo != RIGA_SCONTI && tipo != RIGA_OMAGGI)
						row = i;
				}
				if (row > 0)
				{
					__searching = true;
					search_costo_ricavo(r.doc()[row], conto, riclassifica_fdr_fde);
					__searching = false;
				}
			}
      break; 
    }
    case RIGA_SCONTI:       
    case RIGA_DESCRIZIONI: 
    default :
      break;
  } // end of switch
	if (riclassifica_fdr_fde && conto.ok())
	{
		const TRectype * rdoc = r.find_original_rdoc();
	      
		if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty())
		{
			TString80 key(rdoc->get(RDOC_CODNUM));
	        
			const TCodice_numerazione& num = cached_numerazione(key);
			if (num.fattura_emettere_ricevere())
			{
				key.format("%3d%3d%6ld", conto.gruppo(), conto.conto(), conto.sottoconto());
				const TRectype* rs = &cache().get("MRE", key);
				if (rs->empty())
				{
					key.cut(6);
					rs = &cache().get("MRE", key);
					if (rs->empty())
					{
						key.cut(3);
						rs = &cache().get("MRE", key);
					}
				}         
				if (!rs->empty())
				{ 
					const int gr = rs->get_int("I0"); 
					const int co = rs->get_int("I1"); 
					const long so = rs->get_int("I2"); 
					const char tipo = rs->get_char("S6");

					conto.set(gr, co, so, tipo);
				}
			}
		}
	}
  return conto.ok() && conto.find();
}

bool TContabilizzazione_analitica::find_conti_iva_indetraibile(const TRiga_documento& riga, const TBill & bill, TString_array& conti, int annoes, const char tipomov, bool & pareggio)
{
  const TString80 riga_cos = riga.codice_costo();
  const TString80 riga_cms = riga.codice_commessa();
  const TString16 riga_fsc = riga.fase_commessa();
  TToken_string conto;

	conto = bill.string(0x8); // format("%03d%03d%06ld", bill.gruppo(), bill.conto(), bill.sottoconto());
  conto.add(riga_cos, 1);
  conto.add(riga_cms, 2);
  conto.add(riga_fsc, 3);
  conto.add(100, 4);
  conti.add(conto);

	const TAnal_ripartizioni_batch & rip = _rip.righe(bill, annoes, tipomov);
		
	pareggio  = rip.rows() == 0;
	for (int i = 1; i <= rip.rows(); i++)
	{
		const TRectype& rigarip = rip.row(i);

		conto = rigarip.get(RRIP_CODCONTO);

		const TString  costo = rigarip.get(RRIP_CODCOSTO);

		conto.add(costo.full() ? costo : riga_cos, 1);

		const TString & commessa = rigarip.get(RRIP_CODCMS);

		conto.add(commessa.full() ? commessa : riga_cms, 2);

		const TString & fase = rigarip.get(RRIP_CODFASE);

		conto.add(fase.full() ? fase: riga_fsc, 3);
		conto.add(rigarip.get(RRIP_RIPARTO), 4);
		conti.add(conto);
	}
  return !conti.empty();
}

bool TContabilizzazione_analitica::find_conti(const TRiga_documento& riga, TString_array& conti, int annoes, bool riclassifica_fdr_fde, const char tipomov, bool & pareggio)
{
  bool bArcticleFound = false;

  const char tipocf = riga.doc().get_char(DOC_TIPOCF);
  TString80 contanal;
  TToken_string conto;
  TBill bill;          // Cerco il conto contabile

	pareggio = false;
	if (riga.is_sconto())
	{
		if (riga.is_sconto_perc())
			bill = _sco_perc_bill_an;
		else
			bill = _sco_imp_bill_an;
		if (!bill.is_analitico())
			return true;
		if (_usepdcc)
			contanal = bill.string(0x8); // format("%03d%03d%06ld", bill.gruppo(), bill.conto(), bill.sottoconto());
	}
	else
	{
		if (!search_costo_ricavo(riga, bill, riclassifica_fdr_fde))
			return true;
		if (!bill.is_analitico())
			return true;

		if (riga.is_articolo())
		{
			const TRectype& anamag = cache().get(LF_ANAMAG, riga.get(RDOC_CODARTMAG));
			bArcticleFound = !anamag.empty();
			if (_usepdcc)
				contanal = bill.string(0x8); // format("%03d%03d%06ld", bill.gruppo(), bill.conto(), bill.sottoconto());
			else
				contanal = anamag.get(tipocf == 'F' ?  ANAMAG_CONTOINDA : ANAMAG_CONTOINDV);
		}
		else
		{
			if (riga.is_spese() || riga.is_prestazione() ||
					riga.is_risorsa() || riga.is_attrezzatura())
			{
				const char tipo = riga.tipo().tipo();
				const TSpesa_prest spp(riga.get(RDOC_CODART), tipo);

				bArcticleFound = !spp.empty();
				if (_usepdcc)
					contanal.format("%03d%03d%06ld", bill.gruppo(), bill.conto(), bill.sottoconto());
				else
					contanal = tipocf == 'F' ?  spp.conto_analitico_acquisti() : spp.conto_analitico_vendite() ;
			}
		}
		if (!bArcticleFound)  // Se l'anagrafica non esiste va bene cosi'
			return true;
	}

  const TString80 riga_cos = riga.codice_costo();
  const TString80 riga_cms = riga.codice_commessa();
  const TString16 riga_fsc = riga.fase_commessa();

  if (contanal.full())  // Non ho trovato il conto in anagrafica ...
  { 
    // Ho trovato il conto in anagrafica ...
    TToken_string conto = contanal;

		conto.add(riga_cos, 1);
    conto.add(riga_cms, 2);
    conto.add(riga_fsc, 3);
    conto.add(100, 4);
    conti.add(conto);
  }
	const TAnal_ripartizioni_batch & rip = _rip.righe(bill, annoes, tipomov);
	
	pareggio = rip.rows() > 0;
	for (int i = 1; i <= rip.rows(); i++)
	{
		const TRectype& rigarip = rip.row(i);

		conto = rigarip.get(RRIP_CODCONTO);

		const TString  costo = rigarip.get(RRIP_CODCOSTO);

		conto.add(costo.full() ? costo : riga_cos, 1);

		const TString & commessa = rigarip.get(RRIP_CODCMS);

		conto.add(commessa.full() ? commessa : riga_cms, 2);

		const TString & fase = rigarip.get(RRIP_CODFASE);

		conto.add(fase.full() ? fase: riga_fsc, 3);
		conto.add(rigarip.get(RRIP_RIPARTO), 4);
		conti.add(conto);
	}

  return !conti.empty();
}

void TContabilizzazione_analitica::init_distrib(TString_array& conti, TGeneric_distrib& distrib, bool pareggio)
{
  FOR_EACH_ARRAY_ROW(conti, i, row)
  {
		if (!pareggio || i > 0)
		{
			real slice = row->get(4);
			if (slice <= ZERO)
				slice = UNO;
			distrib.add(slice);
		}
  }
}

bool TContabilizzazione_analitica::elabora(TDocumento& doc, long numreg_cg, TViswin* viswin, bool can_write, TAnal_mov& mov, bool riclassifica_fdr_fde)
{
  TDate datareg, datacomp, datadoc;
  int annoes = 0;
  TString descr, msg, codcaus;
  bool dare = false;
  TCausale & caus = (TCausale &) doc2caus(doc);

  if (numreg_cg > 0)
  {
    const TRectype& mov_cg = cache().get(LF_MOV, numreg_cg);
    datareg = mov_cg.get_date(MOV_DATAREG);
    datacomp = mov_cg.get_date(MOV_DATACOMP);
    annoes = mov_cg.get_int(MOV_ANNOES);
    descr = mov_cg.get(MOV_DESCR);
    dare = !(caus.sezione_clifo() == 'D');
  }
  else
  {
		datadoc = doc.get(DOC_DATADOC);
    datareg = datacomp = datadoc;
    annoes = esercizi().date2esc(datareg);
		doc.riferimento(descr);
		if (descr.empty())
			descr = doc.tipo().descrizione();

		const TString8 rif = doc.get(DOC_NUMDOCRIF);
		codcaus = caus.codice();
		const bool use_rif = caus.iva() == iva_acquisti && rif.not_empty();
		if (use_rif)
		{
			descr << TR(" n. ") << rif;
			descr << TR(" del ") << doc.get(DOC_DATADOCRIF);
		}
		else
		{
			descr << TR(" n. ") << doc.numero();
			descr << TR(" del ") << datadoc;
		}


    dare = doc.get_char(DOC_TIPOCF) == 'F';
    if (doc.is_nota_credito())
      dare= !dare;
  }
  const char sezione = dare ? 'D' : 'A';
  const int decimals = TCurrency::get_firm_dec();

  long numreg_ca = doc.get_long(DOC_NUMREGCA);
  if (numreg_ca > 0)
  {
    const int err = mov.read(numreg_ca);
    if (err == NOERR)
    {
      if (viswin != NULL)
      {
        msg.format("--- Il documento verr� ricontabilizzato nel movimento analitico %ld", numreg_ca);
        viswin->add_line(msg);
      }
      mov.body().destroy_rows();
    }
    else
      mov.put(MOVANA_NUMREG, numreg_ca = 0);
  }
  mov.put(MOVANA_DATAREG,  datareg);
  mov.put(MOVANA_DATACOMP, datacomp);
	mov.put(MOVANA_DATADOC, datadoc);
  mov.put(MOVANA_ANNOES,   annoes);
  mov.put(MOVANA_DESCR,    descr);
  mov.put(MOVANA_NUMREGCG, numreg_cg);               // Movimento contabile associato
	mov.put(MOVANA_CODCAUS,  codcaus);
  mov.put(MOVANA_DPROVV,   doc.get(DOC_PROVV));      // Documento originale
  mov.put(MOVANA_DANNO,    doc.get(DOC_ANNO));
  mov.put(MOVANA_DCODNUM,  doc.get(DOC_CODNUM));
  mov.put(MOVANA_DNDOC,    doc.get(DOC_NDOC));


  TImporto totdoc; // Totale movimento analitico
	const TipoIVA tiva = caus.iva();
	const bool vendita = tiva == iva_vendite;
	TBill bill; caus.bill(RIGA_IVA_NON_DETRAIBILE, bill); 

 // Scandisco le righe del documento,
  const int righe_doc = doc.physical_rows();  //ignora sconti ed esenzioni (senn� sarebbe doc.rows()
  for (int r = 1; r <= righe_doc; r++)
  {
    const TRiga_documento& riga = doc[r];
		bool pareggio = false;

//  salto descrizioni, e omaggi
    if (riga.is_descrizione() || riga.is_omaggio())
      continue;

    // salto valori nulli
		const real qta = riga.get(RDOC_QTA);
		real valore = riga.importo(true, false);
    
    if (valore.is_zero())
      continue;

		if (tiva != iva_vendite && !riga.is_sconto())
		{
			const TString4 tipodet = riga.get(RDOC_TIPODET);
			int td;
			const real pind = indetraibile_al(tipodet, caus, datareg.year(), td);

			if (pind > ZERO)
			{
				const real ivaind = (riga.imposta(false) * pind) / CENTO;
				if (bill.ok())
				{
					if (bill.is_analitico())
					{
						TString_array conti_ind;
            const char tipomov = mov.get_char(MOVANA_TIPOMOV);
						if (find_conti_iva_indetraibile(riga, bill, conti_ind, annoes, tipomov, pareggio)) //qui
						{
					    TGeneric_distrib esso(ivaind, decimals);

					    init_distrib(conti_ind, esso, pareggio);
							FOR_EACH_ARRAY_ROW(conti_ind, j, row_ind)
							{
								TRectype& rmov = mov.new_row();
								rmov.put(RMOVANA_ANNOES, annoes);
								rmov.put(RMOVANA_CODCONTO, row_ind->get(0));
								rmov.put(RMOVANA_CODCCOSTO,row_ind->get());
								rmov.put(RMOVANA_CODCMS,   row_ind->get());
								rmov.put(RMOVANA_CODFASE,  row_ind->get());
								rmov.put(RMOVANA_DESCR,    riga.get(RDOC_DESCR));

								const bool negative = pareggio && j > 0;
								const bool totale = pareggio && j == 0;
								TImporto imp(sezione, totale ? ivaind : real(esso.get()));

								if (negative)
									imp.swap_section();
								imp.normalize();
								rmov.put(RMOVANA_SEZIONE, imp.sezione());
								rmov.put(RMOVANA_IMPORTO, imp.valore());
								totdoc += imp;
							}
						}
					}
				}
				else
					valore += ivaind;
			}
		}              
  		
    if (valore.is_zero())
      continue;

    TString_array conti;
    const char tipomov = mov.get_char(MOVANA_TIPOMOV);
    const bool ok = find_conti(riga, conti, annoes, riclassifica_fdr_fde, tipomov, pareggio);
    if (!ok)
    {
      if (viswin != NULL)
      {
        TString msg; 
        msg.format(FR("*** Riga %d: Manca il conto analitico dell'articolo '%s'"), r, (const char*)riga.get(RDOC_CODART));
        viswin->add_line(msg);
      }
      _error = conto_error;
      can_write = false;
      continue;
    }

    TGeneric_distrib esso(valore, decimals);

    init_distrib(conti, esso, pareggio);
    FOR_EACH_ARRAY_ROW(conti, i, row)
    {
      TRectype& rmov = mov.new_row();
      rmov.put(RMOVANA_ANNOES, annoes);
      rmov.put(RMOVANA_CODCONTO, row->get(0));
      rmov.put(RMOVANA_CODCCOSTO,row->get());
      rmov.put(RMOVANA_CODCMS,   row->get());
      rmov.put(RMOVANA_CODFASE,  row->get());
      rmov.put(RMOVANA_DESCR,    riga.get(RDOC_DESCR));

			const bool negative = pareggio && i > 0;
			const bool totale = pareggio && i == 0;
			TImporto imp(sezione, totale ? valore : real(esso.get()));

			if (negative)
				imp.swap_section();
      imp.normalize();
      rmov.put(RMOVANA_SEZIONE, imp.sezione());
      rmov.put(RMOVANA_IMPORTO, imp.valore());
      totdoc += imp;
    }
  }

	if (_usepdcc)
	{
		const TBill& cinc = (vendita ? _spin_billv : _spin_billa);
		const TBill& cbol = (vendita ? _spbo_billv : _spbo_billa);
		real tot_netto = doc.totale_netto();
		TString4 codiva_es;
		const real sp_incasso = doc.spese_incasso(tot_netto, decimals, _netto);
  
		doc.iva_esente(codiva_es);
		TCodiceIVA ivasp(codiva_es.not_empty() ? codiva_es : doc.codiva_spese());

  // Aggiunge le spese bolli
		tot_netto += sp_incasso + ivasp.imposta(sp_incasso, decimals) - doc.ritenute();
		const real sp_bolli = doc.bolli(tot_netto, decimals, _netto);

		if (sp_incasso != ZERO && cinc.is_analitico())
		{
			TRectype& rmov = mov.new_row();

			rmov.put(RMOVANA_ANNOES, annoes);
			rmov.put(RMOVANA_CODCONTO, cinc.string(0x8));
			rmov.put(RMOVANA_CODCCOSTO, doc.codice_costo());
			rmov.put(RMOVANA_CODCMS,   doc.codice_commessa());
			rmov.put(RMOVANA_CODFASE,  doc.fase_commessa());
      rmov.put(RMOVANA_DESCR, "Spese di incasso");

			TImporto imp(sezione, sp_incasso);

			imp.normalize();
			rmov.put(RMOVANA_SEZIONE, imp.sezione());
			rmov.put(RMOVANA_IMPORTO, imp.valore());
			totdoc += imp;
    }

		if (sp_bolli != ZERO && cbol.is_analitico())
		{
			TRectype& rmov = mov.new_row();

			rmov.put(RMOVANA_ANNOES, annoes);
			rmov.put(RMOVANA_CODCONTO, cbol.string(0x8));
			rmov.put(RMOVANA_CODCCOSTO, doc.codice_costo());
			rmov.put(RMOVANA_CODCMS,   doc.codice_commessa());
			rmov.put(RMOVANA_CODFASE,  doc.fase_commessa());
      rmov.put(RMOVANA_DESCR, "Spese bolli");

			TImporto imp(sezione, sp_bolli);

			imp.normalize();
			rmov.put(RMOVANA_SEZIONE, imp.sezione());
			rmov.put(RMOVANA_IMPORTO, imp.valore());
			totdoc += imp;
		}
	}

  if (can_write && mov.rows() > 0)
  {
    totdoc.normalize();
    mov.put(MOVANA_SEZIONE, totdoc.sezione());
    mov.put(MOVANA_TOTDOC, totdoc.valore());

    TLocalisamfile movana(LF_MOVANA);
    if (numreg_ca > 0)
      mov.rewrite(movana);
    else
    {
      mov.write(movana);
      numreg_ca = mov.get_long(MOVANA_NUMREG);
      doc.put(DOC_NUMREGCA, numreg_ca);
    }
    if (viswin != NULL)
    {
      msg.format(FR("--- Movimento analitico $[r,w]%ld$[n,w] del %s"), numreg_ca, datacomp.string());
      viswin->add_line(msg);
    }
  }

  return can_write;
}

static bool link_handler_ana(int n, const char* nreg)
{   
  switch (n)
  {
  case 0:
    {
      TRectype mov(LF_MOVANA);
      mov.put(MOVANA_NUMREG, nreg);
      return mov.edit();
    } 
    break;
  default:
    break;
  }
  return false;
}

bool TContabilizzazione_analitica::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out,
                                           const TDate& data_elab, bool interattivo)
{ 
  TPrinter& p = printer();
	TViswin v(NULL, TR("Contabilizzazione documenti in analitica"), false, true, true);
  _total_docs = 0;

	p.links().add("Movimento Analitico |r|w", 0);
  p.setlinkhandler(link_handler_ana);
	pre_process_input(doc_in);
	v.open_modal();                   
  for (int i = 0; i < doc_in.items(); i++)
  {
		TAnal_mov mov;
    if (elabora(doc_in[i], 0, &v, true, mov))
    {
      // Cambia stato al documento elborato con successo
      TDocumento& di = doc_in[i];
			di.stato(stato_finale_doc_iniziale()[0]);
      if (di.rewrite() == NOERR)
        _total_docs++;
      else
      {
        TString msg;
        msg << TR("*** Impossibile cambiare stato al documento") 
            << ' ' << di.get(DOC_ANNO) 
            << ' ' << di.get(DOC_CODNUM) 
            << ' ' << di.get(DOC_NDOC);
        v.add_line(msg);
      }
    }
		else
      break;
  }
  v.close_print();
  v.close_modal();  

  if (_total_docs > 0)
  {
	  post_process_input(doc_in);
    post_process_output(doc_out);
  }

  if (v.run() == K_CTRL+'S') // Ho premuto Stampa
    p.print_txt(v.text());

  return true;
}

void TContabilizzazione_analitica::init()
{
	TConfig& cfg = ca_config();
	_usepdcc = cfg.get_bool("UsePdcc");

  TConfig  conf(CONFIG_DITTA, "ve");
  _search_seq = conf.get("RICERCACR");

	int gr = conf.get_int("SCOPRCODCON","ve",1);
	int co = conf.get_int("SCOPRCODCON","ve",2);
	long so = conf.get_long("SCOPRCODCON","ve",3);
	_sco_perc_bill_an.set(gr,co,so);

	gr = conf.get_int("SCOIMCODCON","ve",1);
	co = conf.get_int("SCOIMCODCON","ve",2);
	so = conf.get_long("SCOIMCODCON","ve",3);
	_fld_cms_cont = conf.get("CMSCNTFIELD","ve");
	_sco_imp_bill_an.set(gr,co,so);

  gr = conf.get_int("SPINCODCONA","ve",1);
  co = conf.get_int("SPINCODCONA","ve",2);
  so = conf.get_long("SPINCODCONA","ve",3);
  _spin_billa.set(gr,co,so);

  gr = conf.get_int("SPINCODCONV","ve",1);
  co = conf.get_int("SPINCODCONV","ve",2);
  so = conf.get_long("SPINCODCONV","ve",3);
  _spin_billv.set(gr,co,so);

  gr = conf.get_int("SPBOCODCONA","ve",1);
  co = conf.get_int("SPBOCODCONA","ve",2);
  so = conf.get_long("SPBOCODCONA","ve",3);
  _spbo_billa.set(gr,co,so);

  gr = conf.get_int("SPBOCODCONV","ve",1);
  co = conf.get_int("SPBOCODCONV","ve",2);
  so = conf.get_long("SPBOCODCONV","ve",3);
  _spbo_billv.set(gr,co,so);
  
  _spin_cod = conf.get("SPINCODIVA","ve");
  _spbo_cod = conf.get("SPBOCODIVA","ve");
  
  _caus = new TCache_causali;
}

TContabilizzazione_analitica::TContabilizzazione_analitica(const char* cod) 
                            : TElaborazione(cod), _error(no_error), _caus(NULL)
{
	init();
}

TContabilizzazione_analitica::TContabilizzazione_analitica(const TRectype& rec)
                            : TElaborazione(rec), _error(no_error), _caus(NULL)
{
	init();
}

TContabilizzazione_analitica::~TContabilizzazione_analitica() 
{ 
  if (_caus != NULL)
    delete _caus;
}