#include <progind.h>

#include "velib04.h"
#include "../cg/cgsaldac.h"
#include "../ef/ef0101.h"

#include <doc.h>
#include <rdoc.h>
#include <effetti.h>
#include <reffetti.h>
#include <cfven.h>


///////////////////////////////////////////////////////////
// TGenerazione_effetti
///////////////////////////////////////////////////////////

TGenerazione_effetti::TGenerazione_effetti(const char* cod) 
                    : TElaborazione(cod)
{
  _valid_array.set(2);   // tratta
  _valid_array.set(3);   // riba
  _valid_array.set(5);   // paghero'
  _valid_array.set(7);   // tratta accettata
  _valid_array.set(8);   // rapporti interbancari diretti (rid)
  _valid_array.reset(9); // bonifici 
  
  _docfile  = new TLocalisamfile(LF_DOC);
  _rdocfile = new TLocalisamfile(LF_RIGHEDOC);
  _occas    = new TLocalisamfile(LF_OCCAS);
  _clifo    = new TLocalisamfile(LF_CLIFO);
  _cfven    = new TLocalisamfile(LF_CFVEN);
  _tab      = new TLocalisamfile(LF_TAB);
  _efffile  = new TLocalisamfile(LF_EFFETTI);
  _refffile = new TLocalisamfile(LF_REFFETTI);
  
  _can_write = TRUE;
  _error = no_error;
  _total_bills = 0L;
}

TGenerazione_effetti::TGenerazione_effetti(const TRectype& rec) 
                    : TElaborazione(rec)
{
  _valid_array.set(2);   // tratta
  _valid_array.set(3);   // riba
  _valid_array.set(5);   // paghero'
  _valid_array.set(7);   // tratta accettata
  _valid_array.set(8);   // rapporti interbancari diretti (rid)
  _valid_array.reset(9); // bonifici 
  _docfile  = new TLocalisamfile(LF_DOC);
  _rdocfile = new TLocalisamfile(LF_RIGHEDOC);
  _occas    = new TLocalisamfile(LF_OCCAS);
  _clifo    = new TLocalisamfile(LF_CLIFO);
  _cfven    = new TLocalisamfile(LF_CFVEN);
  _tab      = new TLocalisamfile(LF_TAB);
  _efffile  = new TLocalisamfile(LF_EFFETTI);
  _refffile = new TLocalisamfile(LF_REFFETTI);

  _can_write = TRUE;
  _error = no_error;
  _total_bills = 0L;
}

TGenerazione_effetti::~TGenerazione_effetti() 
{
  delete _docfile;
  delete _rdocfile;
  delete _occas;
  delete _clifo;
  delete _cfven;
  delete _efffile;
  delete _refffile;
  delete _tab;
}

void TGenerazione_effetti::display_error(TDocumento& doc)
{
  TString msg;
  TString numerazione = doc.numerazione();
  const long numero = doc.numero();

  switch (_error)
  {
    case nr_doc_error:
      msg.format("Rilevato un numero di documento errato contabilizzando il documento %s/%ld."
                "Verificare il numero documento e il codice numerazione inseriti in tabella.",(const char*)numerazione,numero);
      break;    
    case chg_stat_error:
      msg.format("Rilevato un errore cambiando lo stato al documento %s/%ld."
                "Verificare l'integrita' del file documenti.",(const char*)numerazione,numero);
      break;
    case datadoc_error:
      msg.format("Rilevato una data documento vuota relativamente al documento %s/%ld."
                "Verificare l'informazione inserita.",(const char*)numerazione,numero);
      break;
    case codpag_error:
      msg.format("Rilevato un codice pagamento non esistente relativamente al documento %s/%ld."
                "Verificare l'esistenza del codice pagamento inserito.",(const char*)numerazione,numero);
      break;
    case scadenze_error:
      msg.format("Calcolate 0 scadenze relativamente al documento %s/%ld."
                "Verificare la correttezza del codice pagamento inserito.",(const char*)numerazione,numero);
      break;
    case write_error:
      if (_efffile->status() != NOERR)
        msg.format("Si e' verificato l' errore %d in scrittura sul file effetti relativamente al documento %s/%ld"
                "Verificare la consistenza del file.",_efffile->status(),(const char*)numerazione,numero);
      else
        msg.format("Si e' verificato l' errore %d in scrittura sul file righe effetti relativamente al documento %s/%ld"
                "Verificare la consistenza del file.",_refffile->status(),(const char*)numerazione,numero);
      break;
    default:
      msg.format("E' stato rilevato un errore generico contabilizzando il documento %s/%ld.",
                  (const char*)numerazione,numero);
      break;
  }
  warning_box(msg);
  _error = no_error; // reset error, as any other one would do, so you can show me the other ones.
  _can_write = FALSE; // But from now on u cannot write anymore. U must exit this program and repair errors occurred.
}

error_type TGenerazione_effetti::change_doc_status(TDocumento& doc)
// Cambia lo stato del documento
{
  doc.stato(get("S4")[0]);
  if (doc.rewrite() != NOERR)
    _error = chg_stat_error; 
  return _error;
}

error_type TGenerazione_effetti::change_group_status(TDocumento& doc, TAssoc_array& group_array)
// Cambia lo stato dei documenti raggruppati
{
  const int items = group_array.items();
  if (items > 0) 
  {
    _error = no_error;
    TToken_string * group_element;
    int i=0;
    // Ciclo sugli elementi dell'assoc_array
    for (group_element = (TToken_string *) group_array.first_item(); group_element != NULL && i < items; i++,group_element = (TToken_string*)group_array.succ_item())
    {
      group_element->restart();
      const int doc_items = group_element->items();
      for (int j=0;j<doc_items;j++)
      {
        TToken_string t(group_element->get(j),'$');
        char provv = t.get_char(0);
        int anno = t.get_int(1);
        TString codnum(t.get(2));
        long numdoc = t.get_long(3);
        if (doc.read(provv,anno,codnum,numdoc) == NOERR) // Legge il documento 
        {
          doc.put(DOC_STATO,get("S4")[0]);
          doc.rewrite();
        }
      }
    }
  }
  return _error;
}

error_type TGenerazione_effetti::write_groups()
{
  const int items = _effetti_array.items();
  int err = NOERR;
  int i;
  
  _error = no_error;
  for (i = 0; i<items && err == NOERR; i++) // scorre gli effetti generati e li scrive su file
  {
    TEffetto& effetto = (TEffetto&)_effetti_array[i];
    const real importo = effetto.get_real(EFF_IMPORTO);

    if (importo > ZERO) // Gli effetti negativi non vanno scritti
		{
			const char tipocf = effetto.get_char(EFF_TIPOCF);
			const long codcf = effetto.get_long(EFF_CODCF);
			TString key;

			key.format("%c|%ld", tipocf, codcf);
			const real impmin(cache().get(LF_CFVEN, key, CFV_IMPMINEFF));

      if (importo >= impmin)
	      err = effetto.write(*_efffile); // Pensa a tutto lui per rinumerare...
			else
				_effetti_array.destroy(i);
		}
  }
	_effetti_array.pack();
  if (err != NOERR)
  { 
    i--;
    for (int j = 0; j<i; j++) // rimuove gli effetti raggruppati, per non lasciare documenti raggruppati parzialmente
    {
      TEffetto& effetto = (TEffetto&)_effetti_array[j];
      // posso fare tranquillamente la remove, visto che la numerazione dell'effetto e' gia' stata effettuata
      effetto.remove(*_efffile);
    }
    error_box("Errore %d nella scrittura gruppi di effetti. Nessun raggruppamento effettuato.",err);
  }
  return _error;
}

// Criteri di raggruppamento effetti.
// Un documento puo' essere raggruppato con i seguenti criteri:
// - flag di raggruppamento effetti a TRUE (obbligatorio)
// - cliente                               (obbligatorio)
// - valuta                                (obbligatorio)
// - data scadenza                         (opzionale)
// - flag di sosp. d'imposta               (opzionale)
// - cambio valuta                         (opzionale)
// - cond di pagamento                     (opzionale)
// - banca                                 (opzionale)
// - tipo doc.                             (opzionale)
// - cod. numerazione                      (opzionale)
// - agente                                (opzionale)
// I parametri opzionali sono decisi nella tabella elaborazioni
// Spiegazione del raggruppamento:
// Il raggruppamento di documenti diversi in uno stesso effetto consiste nella creazione
// di piu' righe dello stesso effetto.
// Ad esempio supponiamo di avere il cliente 10 con 4 fatture ognuna con condizioni di pagamento diverse
// la fattura 1 e' suddivisa in 2 rate (10.000 + 30.000)
// la fattura 2 e' suddivisa in 4 rate (15.000 + 20.000 + 25.000 + 30.000)
// la fattura 3 e' suddivisa in 5 rate (20.000 + 40.000 + 80.000 + 160.000 + 320.000)
// la fattura 4 e' suddivisa in 3 rate (50.000 + 100.000 + 150.000)
// Il numero di effetti generati equivale al massimo numero di rate (5 in questo caso)
// quindi avremo 5 effetti:
// il primo avra' 4 righe (prima rata di tutte le fatture)
// il secondo avra' 4 righe (seconda rata di tutte le fatture)
// il terzo avra' 3 righe (terza rata delle fatture 2,3,4)
// il quarto avra' 2 righe (quarta rata delle fatture 2 e 3)
// il quinto avra' 1 riga (quinta rata della fattura 3)
// La testata di ogni effetto conterra' il totale (somma) dei singoli importi delle righe
// ovvero:
// tot. primo effetto:        95.000
// tot. secondo effetto:     190.000
// tot. terzo effetto:       255.000
// tot. quarto effetto:      190.000
// tot. quinto effetto:      320.000
// I dati della testata (soprattutto la data di scadenza) di ogni effetto vengono presi dal 
// primo documento valido per la generazione dell'effetto corrente:
// per i primi due effetti vale la fattura 1
// per gli effetti 3 e 4 vale la fattura 2
// per l'effetto 5 vale la fattura 3.
// Questo e' quanto ho appreso (Hope I'm right...) ;-)

long TGenerazione_effetti::group_bills(TAssoc_array& group_array)
{
  // Bail out if there aren't items...
  const int items = group_array.items();
  if (!good() || items == 0)
    return 0L;

  TDocumento doc;
  _error = no_error;
  
  int i=0,j,n,offset=0;
  TString msg1,msg2;
  TString16 codpag;
  real imprata, imprataval, importo, importoval;
  msg1 = "Raggruppamento effetti";
  
#ifdef DBG      
  TProgind p(items,msg1,TRUE,TRUE,1);
#else
  TProgind p(items,msg1,FALSE,TRUE,1);
#endif 
  TToken_string * group_element;
  // Ciclo sugli elementi dell'assoc_array
  for (group_element = (TToken_string *) group_array.first_item(); group_element != NULL && i < items; i++,group_element = (TToken_string*)group_array.succ_item())
  {
#ifdef DBG      
    if (p.iscancelled()) break;
#endif
    p.setstatus(i+1);
    // Ciclo sui documenti da raggruppare
    group_element->restart();
    const int doc_items = group_element->items();
    
    int last_rata = 0;
    
    for (j=0;j<doc_items;j++)
    {
#ifdef DBG      
      if (p.iscancelled()) break;
#endif
      TToken_string t(group_element->get(j),'$');
      const char provv = t.get_char(0);
      const int anno = t.get_int(1);
      const TString4 codnum(t.get(2));
      const long numdoc = t.get_long(3);
      if (doc.read(provv,anno,codnum,numdoc) != NOERR) 
        continue; // Legge il documento (giusto saltare e proseguire se non lo trova?)
      
      msg2 = "Documento: ";
      msg2 << codnum << "/" << numdoc;
      xvtil_statbar_set(msg2);
      do_events();
      // Ricalcola le scadenze
      codpag = doc.get(DOC_CODPAG);
    
      const TRectype& cpg = cache().get("%CPG", codpag);
      if (cpg.empty())
      {
        _error = codpag_error;
        display_error(doc);
        return 0L;
      }    
      const real tot = doc.totale_doc() - doc.ritenute();
      doc.put(DOC_CODPAG, codpag); //placeholder
      
      const TCurrency_documento totale_fatt(tot, doc);
      const bool valuta = doc.in_valuta();
      const real change = doc.cambio(); 
      const TDate datafatt = doc.get_date(DOC_DATADOC);
      const bool is_nota_credito = doc.is_nota_credito();
      const long numdocrif = doc.get_long(DOC_NUMDOCRIF);
      const int annodocrif = doc.get_date(DOC_DATADOCRIF).year();
      
      // Qui il controllo sul residuo da pagare per il documento corrente non va effettuato,
      // proprio perch� si sta effettuando un raggruppamento di effetti; eventuali documenti
      // con importo negativi (assimilati a note di credito) vanno presi in considerazione
      // per la composizione dell'importo finale dell'effetto. Un effetto puo' essere composto
      // anche da righe di valore negativo ma esso non verr� scritto solo nel caso in cui l'importo
      // totale (la somma delle singole righe) sia negativo a sua volta
      
      {
        calc_pagamento(doc);
        
        TPagamento& pag = doc.pagamento();
        int numrate = pag.n_rate( );  
        if (numrate <= 0)
        {
          _error = scadenze_error;
          display_error(doc);
          return 0L;
        }
        
        if (numrate > last_rata)
        {
          if (valid_type(pag.tipo_rata(numrate-1)))
            last_rata = numrate;
          else  
            last_rata = 0;
        } 
        
        // Scorre le scadenze
        for (n = 1; n <= numrate && good(); n++)
        {
          if (valid_type(pag.tipo_rata(n-1)))
          {
            // Se non esiste effetto n-esimo (corrisponde al numero di rata corrente+offset)
            // lo genera con la relativa riga. Se esiste vi somma gli importi ed accoda la riga
            const int index = n+offset-1;
            // Nuovo effetto: crea effetto con i dati di questo documento (e' il primo che incontro nella scansione)
            if (index >= _effetti_array.items()) 
            {
              TEffetto* effetto = new TEffetto;
              // Setta i dati della testata;
              effetto->put(EFF_DATASCAD, pag.data_rata(n-1));
              effetto->put(EFF_TIPOPAG,pag.tipo_rata(n-1));
              effetto->put(EFF_ULTCLASS,pag.ulc_rata(n-1));
              effetto->put(EFF_TIPOCF, doc.get_char(DOC_TIPOCF));
              effetto->put(EFF_CODCF, doc.get_long(DOC_CODCF));
              effetto->put(EFF_CODVAL, doc.get(DOC_CODVAL));
              effetto->put(EFF_CAMBIO, change);
              effetto->put(EFF_DATACAMBIO,doc.get_date(DOC_DATACAMBIO));
              effetto->put(EFF_CONTROEURO,doc.get_date(DOC_CONTROEURO));
              effetto->put(EFF_CODABI,doc.get(DOC_CODABIA));
              effetto->put(EFF_CODCAB,doc.get(DOC_CODCABA));
              effetto->put(EFF_IBAN,doc.get(DOC_IBAN));
              effetto->put(EFF_EFFCOMP,TRUE);
              _effetti_array.add(effetto);
            }
            // aggiorna totale effetto (testata)
            TEffetto& effetto=(TEffetto&)_effetti_array[index];
            const int rows = effetto.rows_r();

            importo = effetto.get_real(EFF_IMPORTO);
            imprata = pag.importo_rata(n-1,FALSE);
            imprataval = valuta ? pag.importo_rata(n-1,TRUE) : ZERO;

            if (is_nota_credito)
            {
              // Cerca fattura da pagare con la nota di credito
              int r;
              
              for (r = 1; r <= rows; r++)
              {
                const int annoeff = effetto.row_r(r).get_int(REFF_ANNODOC);
                const long codeff = effetto.row_r(r).get_long(REFF_NFATT);
                if (annoeff == annodocrif && codeff == numdocrif)
                  break;
              }
              if (r <= rows)  // Se l'ha trovata ...
              {
                const real importo_rata_lit = effetto.row_r(r).get_real(REFF_IMPORTO);
                const real importo_rata_val = valuta ? effetto.row_r(r).get_real(REFF_IMPORTOVAL) : ZERO;
                real delta_lit = imprata - importo_rata_lit;
                real delta_val = valuta ? imprataval - importo_rata_val : ZERO;
                // Controlla se l'importo della nota di credito supera quello della fattura
                if (delta_lit > ZERO || delta_val > ZERO)
                {   
                  // Detrae l'eccedenza dalla rata corrente e la sposta nella rata successiva
                  imprata -= delta_lit;
                  imprataval -= delta_val;
                  
                  if (n == numrate)
                  {                   
                    // Crea eventuale ultima rata mancante 
                    pag.add_rata();   
                    numrate++;
                  }
                  else
                  {
                    // Incrementa importo rata
                    delta_lit += pag.importo_rata(n, FALSE);
                    delta_val += pag.importo_rata(n, TRUE);
                  }
                  const TDate oggi(TODAY);
                  const int tiporata = pag.tipo_rata(n-1);
                  pag.set_rata(n, delta_val, delta_lit, oggi, tiporata, "", FALSE);
                }
              }
              else
                break; // Esce dal ciclo delle rate
              
              imprata = -imprata;
              imprataval = -imprataval;
            }
            // Aggiorna importi in lire/valuta dell'effetto
            importo += imprata;
            effetto.put(EFF_IMPORTO,importo);
            if (valuta)
            {
              importoval = effetto.get_real(EFF_IMPORTOVAL);
              importoval += imprataval;
              effetto.put(EFF_IMPORTOVAL,importoval);
            }
            // Crea la nuova riga di questo effetto
            TRectype& riga = effetto.row_r(rows+1,TRUE);
    //        reffetto.put(REFF_NPROGTR,nprog);
            riga.put(REFF_NRIGATR,rows+1);
            riga.put(REFF_NRATA,n);
            riga.put(REFF_DATAFATT, datafatt);
            riga.put(REFF_PROVV,provv);
            riga.put(REFF_ANNODOC,anno);
            riga.put(REFF_CODNUM,codnum);
            riga.put(REFF_NFATT,numdoc);
            riga.put(REFF_IMPFATT,totale_fatt.get_num());
            riga.put(REFF_IMPORTO,imprata);
            riga.put(REFF_ANNO, annodocrif);
            riga.put(REFF_NUMPART, numdocrif);
            if (valuta)
            {
              riga.put(REFF_IMPFATTVAL,totale_fatt.get_num());
              TCurrency_documento totfatlit(totale_fatt); totfatlit.change_to_firm_val();
              riga.put(REFF_IMPFATT,totfatlit.get_num());
              riga.put(REFF_IMPORTOVAL,imprataval);
            }
          }
        } // Ciclo sulle scadenze
      }
    } // Ciclo sui documenti di questo gruppo
    offset=_effetti_array.items();           
    
    if (last_rata > 0)
    {
      TEffetto& last_effetto = (TEffetto&)_effetti_array[offset-1];
      last_effetto.put(EFF_ULTRATA, "X");
    }
  }   // Ciclo sui gruppi
  
  // Cambia lo stato a tutti i documenti raggruppati
  long tot = 0L;
  if (_can_write)
  {
    xvtil_statbar_set("Scrittura effetti raggruppati in corso...");
    do_events();                   
    if (write_groups() == no_error)
    {
      tot = _effetti_array.items();
      change_group_status(doc, group_array);
    } 
  }
  _effetti_array.destroy();
  group_array.destroy();
  
  return tot;
}

bool TGenerazione_effetti::valid_type(int pag) const
{
  return _valid_array[pag];
}

void TGenerazione_effetti::calc_pagamento(TDocumento& doc)
{
  TPagamento& pag = doc.pagamento();

//  const real change      = doc.cambio();
	const real tot = doc.totale_doc() - doc.ritenute();
  const TCurrency_documento tot_doc(tot, doc);
  const TCurrency_documento totspese(doc.spese(), doc);
  const TCurrency_documento totimposte(doc.imposta(TRUE), doc);
  const TCurrency_documento totimponibili(tot_doc - totimposte - totspese);
  TCurrency_documento anticipo(doc.get_real(DOC_IMPPAGATO), doc);
   const bool valuta = doc.in_valuta();
  
  //Riaggiusta le rate a seconda del valore gia' pagato
  TGeneric_distrib d(anticipo.get_num(), doc.decimals());

  d.add(totimponibili.get_num());
  d.add(totimposte.get_num());
  d.add(totspese.get_num());
        
  const TCurrency_documento pagtotimponibili(totimponibili.get_num() - d.get(), doc);
  const TCurrency_documento pagtotimposte(totimposte.get_num() - d.get(), doc);
  const TCurrency_documento pagtotspese(totspese.get_num() - d.get(), doc);
  
  if (valuta)
  {
    TCurrency_documento val2(pagtotimposte); val2.change_to_firm_val();
    TCurrency_documento val3(pagtotspese); val3.change_to_firm_val();
    TCurrency_documento val1(tot_doc); val1.change_to_firm_val(); val1 -= val2 + val3;
    
    pag.set_total_valuta(pagtotimponibili, pagtotimposte, pagtotspese, val1, val2, val3);
  }
  else
    pag.set_total(pagtotimponibili, pagtotimposte, pagtotspese);
  pag.set_rate_auto();

  const int numrate = pag.n_rate();

  // Scorre all'indietro per rimuovere le rate a 0, evitando fastidiose
  // complicazioni dovute al pack delle rate effettuato dalla remove_rate()
  for (int i=numrate-1; i>=0; i--)
  {
    if (pag.importo_rata(i,valuta) == ZERO)
      pag.remove_rata(i);
  }
  
}

void TGenerazione_effetti::generate_bill(TDocumento& doc) // bill in inglese significa anche effetto eheheh ;-)
{
// That's my JOB! 
// Ogni rata della fattura (si parla di effetti attivi per ora) genera 1 effetto.
// con almeno una riga.
// Ad es. Se ho una fattura suddivisa in 3 rate essa generera' 3 effetti  con una riga.
// Nel caso si decida di raggruppare gli effetti (vedi criteri di raggruppamento)
// avro' un effetto con tante righe quante scadenze di fattura sono raggruppabili
// Le fatture possono generare effetti solo per i seguenti tipi di pagamento:
// 2 - Tratta
// 3 - Ri.Ba.
// 5 - Paghero'
// 7 - Tratta accettata
// 8 - Rapporti interbancari diretti
// Caso mai tale insieme risultasse incompleto od errato basta solo modificare l'enum posto all'inizio del programma
  
  if (!doc.is_nota_credito()) // I documenti immessi come note di credito non generano effetti...(che senso hanno gli effetti con importi negativi?)
  {
    const TString16 codpag(doc.get(DOC_CODPAG));
    const TRectype& cpg = cache().get("%CPG", codpag);
    if (cpg.empty())
    {
      _error = codpag_error;
      return;
    }
    TString16 data(doc.get(DOC_DATAINSC)); 
   
    if (data.empty())
      data = doc.get(DOC_DATADOC);
  
		const real tot = doc.totale_doc() - doc.ritenute();
    const TCurrency_documento totale_fatt(tot, doc); // Importo in valuta 
    const TCurrency_documento imppagato(doc.get_real(DOC_IMPPAGATO), doc); // Anticipo pagamento
    if (totale_fatt > imppagato && !doc.get_bool(DOC_ACCSALDO)) // procede se non e' a saldo
    {
      const bool is_anticipo = imppagato.get_num() != ZERO;
      const bool valuta = doc.in_valuta();
      const real change = doc.cambio(); 
      
      // calcolo delle scadenze
      calc_pagamento(doc);
      
      TPagamento & pag = doc.pagamento();
//      CHECK(pag,"Failed to create a TPagamento");
      const int numrate = pag.n_rate( );  
      if (numrate <= 0)
      {
        _error = scadenze_error;
        return;
      }
      
      _efffile->last();
      // Variabili per la scrittura dell'effetto
      long nprog = _efffile->get_long(EFF_NPROGTR)+1;
      const char tipocf = doc.get_char(DOC_TIPOCF);
      const long codcf = doc.get_long(DOC_CODCF);
      const TString4 codval(doc.get(DOC_CODVAL));
      const TDate data_cambio = doc.get_date(DOC_DATACAMBIO);
      const bool contro_euro = doc.get_bool(DOC_CONTROEURO);
      const long codabi = doc.get_long(DOC_CODABIA);
      const long codcab = doc.get_long(DOC_CODCABA);
      const TString80 iban = doc.get(DOC_IBAN);
      const TString16 provv(doc.get(DOC_PROVV));
      const int anno = doc.get_int(DOC_ANNO);
      const TString16 codnum(doc.get(DOC_CODNUM));
      const long nfatt = doc.get_long(DOC_NDOC);
      const TDate datafatt = doc.get_date(DOC_DATADOC);
      TRectype& effetto = _efffile->curr();
      TRectype& reffetto = _refffile->curr();
      real importo;
      for (int i = 0; i < numrate && good(); i++)
      {
        const int nrata = is_anticipo ? i + 2: i + 1;
        
        if (valid_type(pag.tipo_rata(i)))
        {
          effetto.zero();
          reffetto.zero();
          effetto.put(EFF_NPROGTR,nprog);
          effetto.put(EFF_DATASCAD, pag.data_rata(i));
          effetto.put(EFF_TIPOPAG,pag.tipo_rata(i));
          effetto.put(EFF_ULTCLASS,pag.ulc_rata(i));
          effetto.put(EFF_TIPOCF, tipocf);
          effetto.put(EFF_CODCF, codcf);
          effetto.put(EFF_CODVAL, codval);    
          if (valuta)
          {
            effetto.put(EFF_CAMBIO, change);        
            effetto.put(EFF_DATACAMBIO,data_cambio);
            effetto.put(EFF_CONTROEURO, contro_euro);        
          }
          effetto.put(EFF_CODABI,codabi);
          effetto.put(EFF_CODCAB,codcab);
          effetto.put(EFF_IBAN,iban);
          effetto.put(EFF_EFFCOMP,TRUE);
          if (i == numrate - 1) effetto.put(EFF_ULTRATA,TRUE);
          // Put sulla riga dell'effetto
          reffetto.put(REFF_NPROGTR,nprog);
          reffetto.put(REFF_NRIGATR,1);
          reffetto.put(REFF_DATAFATT, datafatt);
          reffetto.put(REFF_NRATA,nrata);
          reffetto.put(REFF_PROVV,provv);
          reffetto.put(REFF_ANNODOC,anno);
          reffetto.put(REFF_CODNUM,codnum);
          reffetto.put(REFF_NFATT,nfatt);
          reffetto.put(REFF_ANNO, doc.get_date(DOC_DATADOCRIF).year());          
          reffetto.put(REFF_NUMPART, doc.get(DOC_NUMDOCRIF));          
          
          importo = pag.importo_rata(i,FALSE);
          effetto.put(EFF_IMPORTO,importo);
          reffetto.put(REFF_IMPFATT,totale_fatt.get_num());
          reffetto.put(REFF_IMPORTO,importo);
					
					TString key;

					key.format("%c|%ld", tipocf, codcf);
					const real impmin(cache().get(LF_CFVEN, key, CFV_IMPMINEFF));

          if (importo >= impmin)
					{
						if (valuta) 
						{
							importo = pag.importo_rata(i,TRUE);  // Importo in valuta
							TCurrency_documento totfatlit(totale_fatt); totfatlit.change_to_firm_val();
							effetto.put(EFF_IMPORTOVAL,importo);
							reffetto.put(REFF_IMPFATTVAL,totale_fatt.get_num());
							reffetto.put(REFF_IMPFATT,totfatlit.get_num());
							reffetto.put(REFF_IMPORTOVAL,importo);
						}
          
						if (_efffile->write() == NOERR && _refffile->write() == NOERR)
						{
							_total_bills++;
							nprog++;
						}
						else _error = write_error;
					}
        }
      }
    }
  }
  
  if (good() && _can_write)
    change_doc_status(doc);
}

bool TGenerazione_effetti::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out,
                                 const TDate& data_elab, bool interattivo)
{  
  TString msg;
  _error = no_error;
  _total_bills = 0L;
  
  const int items = doc_in.items(); // Numero dei documenti in questa elaborazione
  for (int i = 0; i < items ; i++)  // Scorriamo tutti i documenti nella lista
  {
    TDocumento& doc = doc_in[i];
    msg.format("Generazione effetti documento %s/%ld.", (const char*) doc.numerazione(), doc.numero());
    xvtil_statbar_set(msg);
    do_events();

    generate_bill(doc);       // Genera gli effetti corrispondenti
    if (!good()) 
      display_error(doc);
  }

  return _can_write;
}