#include "velib07.h"

#include <pconti.h>

#include "../cg/cgsaldac.h"
#include "../cg/cglib02.h"
#include "../db/dblib.h"

///////////////////////////////////////////////////////////
// TMateriali_base_recordset
///////////////////////////////////////////////////////////

const TVariant& TMateriali_base_recordset::get(const char* column_name) const
{
	if (column_name[0] != '#')
	{
		TVariant& var = get_tmp_var();
		int rownum = current_row();

		if (reverse())
			rownum = items() - 1 - rownum;

		const	TRiga_esplosione* row = (const TRiga_esplosione*)boom().objptr(rownum);
		
		if (row != NULL)
 		{
   	  const TFixed_string name(column_name);
 		  if (name == "LASTQTA")
				var = row->last_qta();
			else
				if (name == "TOTQTA")
					var = row->val();
				else
				{
					if (rownum != _lastrow)
					{
						((TMateriali_base_recordset *) this)->_lastrow = rownum;
						const TCodice_articolo & comp  = row->componente();
						const TCodice_articolo & dist  = row->distinta();
						TLocalisamfile rd(LF_RDIST);

						rd.setkey(2);
						rd.put("CODCOMP", comp);
						rd.put("CODDIST", dist);
						if (rd.read() == NOERR)
							*_rdist = rd.curr();
					}
					
					
					if (_rdist != NULL)
					{
						const TString & v = _rdist->get(column_name);

						var = v;
					}
				}
		}
		return var;
	}
	return TRecordset::get(column_name);
}

const TVariant& TMateriali_base_recordset::get(unsigned int column) const
{
	const TRecordset_column_info & ci  = column_info(column);
	return get(ci._name);
}

void TMateriali_base_recordset::requery()
{
	_boom.destroy();
	int pos1 = query_text().find("MATBASE");
	if (pos1 > 0)
	{
		pos1 += 7;
		set_reverse(query_text()[pos1] == '-');
		if (reverse())
			pos1++;
		int pos = query_text().find("==", pos1);
		int pos2 = -1;
		if (pos > 0)
		{
			TString val(query_text().mid(pos + 2));
			pos2 = val.find("FILTER");

			if (pos2 > 0)
				val.cut(pos2 - 1);

			if (val.starts_with("\"") || val.starts_with("'"))
			{
				val.ltrim(1);
				val.rtrim(1);
			}
			else
			{
				TVariant var = get(val);
				val = var.as_string();
			}

			const TCodice_articolo art(val);
     	TDistinta_tree	distinta;
			if (distinta.set_root(art))
			{
				while (isspace(query_text()[pos1]))
					pos1++;
				const int level = atoi(query_text().mid(pos1));
				if (level > 0 || query_text()[pos1] =='0')
					while (isdigit(query_text()[pos1]))
						pos1++;
				while (isspace(query_text()[pos1]))
					pos1++;
				TString8 filter;
				if (query_text()[pos1] != 'S')
					while (isalpha(query_text()[pos1]))
						filter << query_text()[pos1++];
				distinta.explode(_boom, true, RAGGR_EXP_NONE, level, filter);
			}
			pos = query_text().find("FILTER", pos);
			if (pos > 0) 
			{
				pos = query_text().find("==", pos);
				if (pos > 0) 
				{
					TString val(query_text().mid(pos + 2));

					if (val.starts_with("\"") || val.starts_with("'"))
					{
						val.ltrim(1);
						val.rtrim(1);
					}
					else
					{
						TVariant var = get(val);
						val = var.as_string();
					}
					const int items = _boom.items();
					for (int i = 0; i < items; i++)
					{
						const	TRiga_esplosione * row = (const TRiga_esplosione *)_boom.objptr(i);
						if ( row != NULL && row->componente() != val)
							_boom.destroy(i);
					} 
					_boom.pack();
				}
			}
		}
	}
}

TMateriali_base_recordset::TMateriali_base_recordset(const char* use) : _query(use)
{
	_lastrow = -1;
	_rdist = new TRectype(LF_RDIST);
	const int nfields = _rdist->items();
	
	int pos = 1;
	for ( int i = 0 ; i < nfields; i++)
	{
		TRecordset_column_info * ci = new TRecordset_column_info;

		ci->_name = _rdist->fieldname(i);
		ci->_pos = pos;
		ci->_type = _rdist->type(ci->_name);

		const int len = _rdist->length(ci->_name);

		pos += len;
		ci->_width = len;
		_column.add(ci);
	}
}

///////////////////////////////////////////////////////////
// TScalare_recordset
///////////////////////////////////////////////////////////

void TScalare_recordset::requery()
{
  boom().destroy();
	int pos1 = query_text().find("SCALARE");
	if (pos1 > 0)
	{
		pos1 += 7;
		set_reverse(query_text()[pos1] == '-');
		if (reverse())
			pos1++;
		int pos = query_text().find("==", pos1);
		if (pos > 0)
		{
			TString val(query_text().mid(pos + 2));

			if (val.starts_with("\"") || val.starts_with("'"))
			{
				val.ltrim(1);
				val.rtrim(1);
			}
			else
			{
				TVariant var = get(val);
				val = var.as_string();
			}

			const TCodice_articolo art(val);
    	TDistinta_tree	distinta;
			if (distinta.set_root(art))
			{
				while (isspace(query_text()[pos1]))
					pos1++;
				const int level = atoi(query_text().mid(pos1));
				if (level > 0 || query_text()[pos1] =='0')
					while (isdigit(query_text()[pos1]))
						pos1++;
				while (isspace(query_text()[pos1]))
					pos1++;
				TString8 filter;
				if (query_text()[pos1] != 'S')
					while (isalpha(query_text()[pos1]))
						filter << query_text()[pos1++];
				distinta.explode(boom(), false, RAGGR_EXP_NONE, level, filter);
			}
			pos = query_text().find("FILTER", pos);
			if (pos > 0) 
			{
				pos = query_text().find("==", pos);
				if (pos > 0) 
				{
					TString val(query_text().mid(pos + 2));

					if (val.starts_with("\"") || val.starts_with("'"))
					{
						val.ltrim(1);
						val.rtrim(1);
					}
					else
					{
						TVariant var = get(val);
						val = var.as_string();
					}
					const int items = boom().items();
					for (int i = 0; i < items; i++)
					{
						const	TRiga_esplosione * row = (const TRiga_esplosione *)boom().objptr(i);
						if ( row != NULL && row->componente() != val)
							boom().destroy(i);
					}
					boom().pack();
				}
			}
		}
	}
}

///////////////////////////////////////////////////////////
// TDocument_cache
///////////////////////////////////////////////////////////
TObject* TDocument_cache::key2obj(const char* key)
{
  TToken_string k(key);
  const char provv = *k.get(0);
  const int anno = k.get_int();
  const TString4 codnum= k.get();
  const long ndoc = k.get_long();
  TDocumento* doc = new TDocumento(provv, anno, codnum, ndoc);
  doc->get("IMPONIBILI"); // Bastardata per far funzionare la successiva dirty_fields
  doc->dirty_fields();
  return doc;
}

TDocumento& TDocument_cache::doc(const TRectype& rec)
{
  TToken_string key;
  key = rec.get(DOC_PROVV);
  key.add(rec.get(DOC_ANNO));
  key.add(rec.get(DOC_CODNUM));
  key.add(rec.get(DOC_NDOC));
  TDocumento& d =  *(TDocumento*)objptr(key);
  return d;
}


TDocument_cache:: TDocument_cache() : TCache(3) 
{
}

TDocument_cache:: ~TDocument_cache()
{
}


///////////////////////////////////////////////////////////
// TDocument_recordset
///////////////////////////////////////////////////////////

const TVariant& TDocument_recordset::get_field(int num, const char* field) const
{
  if (*field != '#')
  {
    const int idx = relation()->log2ind(num);
    if (idx < 0)
      return NULL_VARIANT;
    const int logic = num > 0 ? num : relation()->file(idx).num();
    if (logic == LF_DOC || logic == LF_RIGHEDOC)
    {
      const TRectype& rec = relation()->file(idx).curr();
      // Se non e' un campo standard, ma e' calcolato da una formula...
      if (rec.type(field) == _nullfld && strncmp(field, "G1:", 3) != 0) 
      {
        const TDocumento& doc = ((TDocument_cache&)_cache).doc(rec);
        TVariant& var = get_tmp_var();

        if (xvt_str_compare_ignoring_case(field, "SEGNO") == 0)
        {
          var = doc.is_nota_credito() ? -UNO : UNO;   
        } else
        if (xvt_str_compare_ignoring_case(field, "IS_COSTO") == 0)
        {
			    bool costo = (doc.tipo().is_costo()) || (!doc.tipo().is_ricavo() && doc.get_char(DOC_TIPOCF)=='F');
          var = costo ? UNO : ZERO;
        } else
        if (xvt_str_compare_ignoring_case(field, "IS_RICAVO") == 0)
        {
			    bool ricavo = (doc.tipo().is_ricavo()) || (!doc.tipo().is_costo() && doc.get_char(DOC_TIPOCF)=='C');
          var = ricavo ? UNO : ZERO;
        }
        else
        {
          const TFieldref ref(field, logic);
          if (logic == LF_DOC)
          {
            var = ref.read(doc);
          }
          else
          {
            const int nriga = rec.get_int(RDOC_NRIGA);
            if (nriga > 0 && nriga <= doc.rows())
            {
              const TRiga_documento& rdoc = doc[nriga];
              var = ref.read(rdoc);
            }
            else
              var = NULL_VARIANT;
          }
        }
        return var;     
      }
    }
  }
  return TISAM_recordset::get_field(num, field);
}


///////////////////////////////////////////////////////////
// TDocument_report
///////////////////////////////////////////////////////////

bool TDocument_report::set_recordset(const TString& query)
{
	if (query.find("MATBASE") > 0)
		return TReport::set_recordset(new TMateriali_base_recordset(query));
	if (query.find("SCALARE") > 0)
		return TReport::set_recordset(new TScalare_recordset(query));

  return TReport::set_recordset(new TDocument_recordset(query));
}

bool TDocument_report::load(const char* name)
{
  const bool ok = TReport::load(name);
  if (ok)
  {
    // Purtroppo il recordset delle sottosezioni deve essere reimpostato a mano
    for (int i = 11; i <= 999; i++)
    {
      TReport_section* sec = find_section('B', i);
      if (sec != NULL)
      {
        TRecordset* recset = sec->recordset();
        if (recset != NULL)
        {
          const TString use = recset->query_text();
					if (use.find("MATBASE") > 0)
						recset = new TMateriali_base_recordset(use);
					else
						if (use.find("SCALARE") > 0)
							recset = new TScalare_recordset(use);
						else
          recset = new TDocument_recordset(use);
          sec->set_recordset(recset);
        }
      }
    }
  }
  return ok;
}

void TDocument_report::output_values(const TRectype& rec, const TString& output)
{
  TToken_string out(output, '!');
  TString curr;
  for (const char * str = out.get(0); str; str = out.get())
  { // scansione sugli elementi dell'output
    curr = str;
    int poseq = curr.find('='); // divide la stringa corrente in lvalue e rvalue
    if (poseq < 0)
    {
      curr_field()->set(rec.get(curr));
    }
    else
    {
      int posrv = poseq+1;
      if (poseq >= 0 && curr[posrv] == '=')
        posrv++;
      TString16 fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale
      const TString& dat = rec.get(curr.mid(posrv)); // preleva il nome del campo del file alla destra dell'uguale e lo legge dal record
      TReport_field* campo = field(fld);
      if (campo != NULL)
        campo->set(dat);
    }
  }
}

void TDocument_report::reset_values(const TString& output)
{
  TToken_string out(output, '!');
  TString curr;
  for (const char * str = out.get(0); str; str = out.get())
  { // scansione sugli elementi dell'output
    curr = str;
    int poseq = curr.find('='); // divide la stringa corrente in lvalue e rvalue
    if (poseq < 0)
    {
      curr_field()->set("");
    }
    else
    {
      TString16 fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale
      TReport_field* campo = field(fld);
      if (campo != NULL)
        campo->set("");
    }
  }
}

bool TDocument_report::msg_parent_doc(TVariant_stack& stack)
{
  TReport_field& cf = *curr_field();

	int idx =((TISAM_recordset *)recordset())->cursor()->relation()->log2ind(LF_DOC);

  if (idx < 0)
		return false;

	const TRectype& rec = ((TISAM_recordset*)recordset())->cursor()->relation()->file(idx).curr();
	TDocumento & doc  = (TDocumento &)((TDocument_recordset*)recordset())->doc(rec);
	const TRiga_documento * rdoc = NULL;

	  // Se il campo corrente non appartiene al body allora cerco la prima riga documento buona!
  if (cf.section().type() == 'B')
	{
	  idx = ((TISAM_recordset*)recordset())->cursor()->relation()->log2ind(LF_RIGHEDOC);
		if (idx < 0)
			return false;

		const TRectype& rec = ((TISAM_recordset*)recordset())->cursor()->relation()->file(idx).curr();
		const int n = rec.get_long("NRIGA");

		rdoc = &(doc[n]);
	}
	else
  {
    const TRiga_documento * first_desc = NULL;

    for (int r = 1; r <= doc.physical_rows(); r++)
    {
      const TRiga_documento& row = doc[r];
      if (row.get(RDOC_DANDOC).not_empty())
      {
        if (row.is_descrizione())
        {
          if (first_desc == NULL)
            first_desc = &row;  // Non e' una riga buona, ma nemmeno da buttare!
        }
        else
        {
          rdoc = &row;
          break; // Ho trovato la riga buona!
        }
      }
    }
    if (rdoc == NULL && first_desc != NULL)
	    rdoc = first_desc;
  }

  int level = stack.pop().as_int();   
  for (; rdoc != NULL && level > 0; level--)
    rdoc = (const TRiga_documento *)(rdoc->find_original_rdoc());

  const TString& values = stack.pop().as_string();
  const bool is_full = stack.peek().as_bool();
    
  if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty())
  {
    const char provv      = rdoc->get_char(RDOC_PROVV);
    const int anno        = rdoc->get_int(RDOC_ANNO);
    const TString4 codnum = rdoc->get(RDOC_CODNUM);
    const long ndoc       = rdoc->get_long(RDOC_NDOC);         
      
    if (is_full)
    {
      TDocumento doc(provv, anno, codnum, ndoc);
      output_values(doc, values);
    }
    else  
    {                               
      TToken_string key;
      key.add(provv); key.add(anno); key.add(codnum); key.add(ndoc);
      const TRectype& doc = cache().get(LF_DOC, key);
      output_values(doc, values);
    }
  }
  else
    reset_values(values);
  
  return true;
}

bool TDocument_report::msg_parent_row(TVariant_stack& stack)
{
	int idx = ((TISAM_recordset*)recordset())->cursor()->relation()->log2ind(LF_RIGHEDOC);
	if (idx < 0)
		return false;

	const TRectype& rec = ((TISAM_recordset*)recordset())->cursor()->relation()->file(idx).curr();
	const int n = rec.get_long("NRIGA");
	idx =((TISAM_recordset *)recordset())->cursor()->relation()->log2ind(LF_DOC);

  if (idx < 0)
		return false;

	TDocumento & doc  = (TDocumento &)((TDocument_recordset*)recordset())->doc(rec);

	const TRiga_documento * rdoc = &(doc[n]);

	  // Se il campo corrente non appartiene al body allora cerco la prima riga documento buona!
  
  int level = stack.pop().as_int();
  for (; rdoc != NULL && level > 0; level--)
    rdoc = (const TRiga_documento *)(rdoc->find_original_rdoc());

  const TString& values = stack.pop().as_string();
  const bool is_full = stack.peek().as_bool();
  
  if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty())
  {
    if (is_full)
    {
      const char provv      = rdoc->get_char(RDOC_PROVV);
      const int anno        = rdoc->get_int(RDOC_ANNO);
      const TString4 codnum = rdoc->get(RDOC_CODNUM);
      const long ndoc       = rdoc->get_long(RDOC_NDOC);
      TDocumento doc(provv, anno, codnum, ndoc);
      output_values(doc[rdoc->get_int(RDOC_NRIGA)], values);
    }
    else
      output_values(*rdoc, values);
  }
  return true;
}

size_t TDocument_report::get_usr_words(TString_array& words) const
{
  TReport::get_usr_words(words);
  
  const char* const name[] = { "DOC_PARENT_DOC", "DOC_PARENT_ROW", NULL };

  ((TDocument_report*)this)->_first_msg = words.items(); // Calcola il primo numero disponibile
  for (size_t i = 0; name[i] != NULL; i++)
    words.add(name[i]);
  
  return words.items();
}

bool TDocument_report::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
{
  if (opcode < _first_msg)
    return TReport::execute_usr_word(opcode, stack);
  opcode -= _first_msg;
  switch (opcode)
  {
  case 0 : msg_parent_doc(stack); break;
  case 1 : msg_parent_row(stack); break;
  default: break;
  }

  while (!stack.pop().is_null());  // Svuota eventuali parametri variabili inutilizzati

  return true;
}

/////////////////////////////////////////
//  Metodi non appartenenti a classi
/////////////////////////////////////////

// METODI PER IL CALCOLO DEL FIDO

//estrazioni mastri clienti e/o fornitori
static const TString_array& mastro(char tipocf)
{
  static TString_array m[2];
  const TString_array& a = m[tipocf == 'C' ? 0 : 1];

  if (a.empty())
  {
    TISAM_recordset mastri("USE PCON SELECT (CONTO!=\"\")&&(SOTTOCONTO=\"\")");
    for (bool ok = mastri.move_first(); ok; ok = mastri.move_next())
    {
      const int gruppo = mastri.get(PCN_GRUPPO).as_int();
      const int conto = mastri.get(PCN_CONTO).as_int();
      const int indbil = mastri.get(PCN_INDBIL).as_int();
      const char tipocf = mastri.get(PCN_TMCF).as_string()[0];
      TToken_string info;
      info.add(gruppo);
      info.add(conto);
      info.add(indbil);
      m[tipocf == 'C' ? 0 : 1].add(info);
    }
  }
  return a;
}

static real calcola_saldo_contabile(const char tipocf, const long codcf, const TDate& datacalc)
{
  real saldone;

  TEsercizi_contabili esc;
  TDate datainies, datafines;
  const int codes = esc.date2esc(datacalc);
  if (codes > 0)      
    esc.code2range(codes, datainies, datafines);
  else
  {
    datainies = datacalc;
    datainies.set_day(1);
    datainies.set_month(1);
  }

  const TString_array& a = mastro(tipocf);

  //per tutti i mastri selezionati va a calcolare il saldo del cliente/fornitore in input
  FOR_EACH_ARRAY_ROW(a, i, row)
  {
    const int gruppo = row->get_int(0);
    const int conto = row->get_int(1);
    const int indbil = row->get_int(2);

    TSaldo saldo;
    real saldo_periodo = saldo.saldo_periodo(gruppo, conto, codcf, datainies, datacalc, indbil, false);

    saldone += saldo_periodo;
  }
  return saldone;
}

static TImporto get_importo(const TISAM_recordset& partite, const char* sezione, const char* valore)
{
  const char sez = partite.get(sezione).as_string()[0];
  const real val = partite.get(valore).as_real();
  return TImporto(sez, val);
}


static real calcola_esposto_da_saldaconto (const char tipocf, const long codcf, const TDate& datacalc, const int riskdays)
{
  //estrae le righe partita relative a pagamenti successivi alla data di rischio (e con tipopag >2,<7)
  TString query;
  query << "USE PART\nSELECT BETWEEN(DATAPAG,#DATASBF,0)&&BETWEEN(TIPOPAG,2,7)\n";
  query << "FROM TIPOC=#TIPOCF GRUPPO=0 CONTO=0 SOTTOCONTO=#CODCF ANNO=#ANNO\n";
  query << "TO TIPOC=#TIPOCF GRUPPO=0 CONTO=0 SOTTOCONTO=#CODCF";

  TISAM_recordset partite(query);

  TString4 str_tipocf = tipocf;
  partite.set_var("#TIPOCF", TVariant(str_tipocf));
  partite.set_var("#CODCF", codcf);
  partite.set_var("#DATACALC", datacalc);
  //data considerante i giorni di rischio ammessi dall'utonto
  TDate data_sbf = datacalc;
  data_sbf -= riskdays;
  partite.set_var("#DATASBF", data_sbf);  //data salvo buon fine
  partite.set_var("#ANNO", TVariant((long)data_sbf.year()));


  //importone somma degli importi delle righe del recordset
  TImporto importone_esposto;

  for (bool ok = partite.move_first(); ok; ok = partite.move_next())
  {
    TImporto importo_riga;

    //fatture,note di credito,pagamenti
    TImporto importo_partita = get_importo(partite, PART_SEZ, PART_IMPORTO);
    importo_riga += importo_partita;

    //pagamenti (tm=3), insoluti (tm=5), pagamenti insoluti(tm=6)
    if (partite.get(PART_TIPOMOV).as_int() >= tm_pagamento)
    {
      TImporto importo_abbuono = get_importo(partite, PART_SEZABB, PART_ABBUONI);
      importo_riga += importo_abbuono;
      //pagamenti in valuta
      if (!partite.get(PART_CODVAL).is_empty())
      {
        TImporto importo_diff_cambio = get_importo(partite, PART_SEZDIFCAM, PART_DIFFCAM);
        importo_riga += importo_diff_cambio;
      }
    }

    //somma importi presenti sulla riga partita (fatture, pagamenti, insoluti, pagamenti insoluti)
    importone_esposto += importo_riga;

  }
  //la normalizzazione del totale delle partite va fatta in base al fatto che si parli di 'C'liente o 'F'ornitore
  const char sezione_finale = (tipocf == 'C') ? 'A' : 'D';
  importone_esposto.normalize(sezione_finale);

  //valore in output
  real esposto;
  esposto += importone_esposto.valore();
  
  return esposto;
}


static real calcola_fido_da_documenti(const char tipocf, const long codcf, const TDate& datacalc)
{
  real totalone;
  TConfig config(CONFIG_DITTA, "ve");

  //scansione delle righe FIDO_XX(j)=.. sul paragrafo di configurazione VE per avere i parametri di numerazione/tipo..
  //..da considerare
	for (int j = 0;;j++)
	{
		const TString& num_fido = config.get("FIDO_NUM", NULL, j);
    //se manca la numerazione si pu� fermare,in quanto non pu� esistere un tipo senza numerazione
    if (num_fido.blank())
			break;
    const TString& tipo_fido = config.get("FIDO_TIP", NULL, j);
    const TString4 da_stato_fido = config.get("FIDO_DASTA", NULL, j);
    const TString4 a_stato_fido = config.get("FIDO_ASTA", NULL, j);
    const bool residuo_fido = config.get_bool("FIDO_RES", NULL, j);

    //per la numerazione scelta queryzza gli archivi alla ricerca dei documenti che rientrano nei parametri
    TString query;
    query << "USE DOC KEY 2\n";
    query << "SELECT (CODNUM=#CODNUM)&&(TIPODOC=#TIPODOC)&&(BETWEEN(STATO,#DASTATO,#ASTATO))\n";
    query << "FROM TIPOCF=#TIPOCF CODCF=#CODCF PROVV='D'\n";
    query << "TO TIPOCF=#TIPOCF CODCF=#CODCF PROVV='D' ANNO=#ANNO DATADOC=#DATACALC";

    TISAM_recordset documenti(query);

    const char str_tipocf[2] = { tipocf, 0 };
    documenti.set_var("#TIPOCF", TVariant(str_tipocf));
    documenti.set_var("#CODCF", codcf);
    documenti.set_var("#ANNO", TVariant((long)datacalc.year()));
    documenti.set_var("#DATACALC", datacalc);
    documenti.set_var("#CODNUM", TVariant(num_fido));
    documenti.set_var("#TIPODOC", TVariant(tipo_fido));
    documenti.set_var("#DASTATO", TVariant(da_stato_fido));
    documenti.set_var("#ASTATO", TVariant(a_stato_fido));

    const int items = documenti.items();

    //adesso che ha i documenti che cercava..
    for (bool ok = documenti.move_first(); ok; ok = documenti.move_next())
    {
      const TDocumento doc(documenti.cursor()->curr());
      //deve tener conto di eventuali docs in valuta
      TCurrency_documento totdoc(ZERO, doc);

      //documento a residuo (tipo ordini)
      if (residuo_fido)
      {
        totdoc.set_num(doc.valore(false, true));
      }
      else  //documento normale (tipo fattura)
      {
        totdoc.set_num(doc.totale_doc());
      }

      totdoc.change_to_firm_val();

      //le nac vanno con segno rovesciato
      if (doc.is_nota_credito())
        totdoc = -totdoc;

      totalone += totdoc.get_num();
    }
	}

  return totalone;
}


//metodo per il calcolo fido di un cliente ad una data definita
real calcola_fido_cliente (const char tipocf, const long codcf, const TDate& datacalc, const int riskdays)
{
  //PRIMA PARTE: controlla i movimenti
  real saldo_contabile = calcola_saldo_contabile(tipocf, codcf, datacalc);
  //SECONDA PARTE: controlla il saldaconto
  real esposto_saldaconto = calcola_esposto_da_saldaconto(tipocf, codcf, datacalc, riskdays);
  //TERZA PARTE: controlla i documenti
  real tot_documenti = calcola_fido_da_documenti(tipocf, codcf, datacalc);

  return saldo_contabile + esposto_saldaconto + tot_documenti;
}

// FINE METODI PER IL CALCOLO DEL FIDO