#include "tc0.h"
#include "tc0701.h"
#include "tc0700a.h"

#include <automask.h>
#include <progind.h>
#include <reprint.h>

#include <clifo.h>
#include <comuni.h>
#include <mov.h>
#include <rmov.h>
#include <rmoviva.h>
#include <multirel.h>
#include <pconti.h>

#include "../cg/cglib01.h"

#define TSINDETR    	600 // e pensare che ne vendono migliaia
#define TSACQDESTRIV	200

///////////////////////////////////////////////////////////
// TRiclassifica_cache
///////////////////////////////////////////////////////////

HIDDEN const char* const __tiporicconti = "TSCONTI";

TObject* TTSRiclassifica_cache::key2obj(const char* key)
{
	TToken_string tok(key);
	TString8 tab, cod;
	tok.get(0,tab);
	tok.get(1, cod);
	_multirel.put(MULTI_COD, tab);
	_multirel.put(MULTI_FIRST, cod);
	_multirel.zero(MULTI_SECOND);
	if (_multirel.read() == NOERR)
		return new TString(_multirel.get(MULTI_DATA));
	return NULL;
}

long TTSRiclassifica_cache::decode(const char* tab, const TString& cod)
{
	TToken_string tok;
	tok.add(tab);
	tok.add(cod);
	const TString* ric = (const TString*) objptr(tok);
	return (ric ? atol(*ric) : 0);
}

const char * TTSRiclassifica_cache::sdecode(const char* tab, const TString& cod)
{
	TToken_string tok;
	tok.add(tab);
	tok.add(cod);
	const TString* ric = (const TString*) objptr(tok);
	return ric ? (const char *) *ric : "";
}


const long TSbill2ricl(char & t, int gr, int co, long so)
{
	TRecord_cache *	__conti = NULL;

	if (__conti == NULL)
		__conti = new TRecord_cache(LF_RICLPDC, 1);

  long codricl = 0;
	if (gr > 0)
	{
		TToken_string cod;
		cod.add(__tiporicconti);
		cod.add(gr);
		cod.add(co);
		if (t <= ' ')
			cod.add(so);

		// Provo il sottoconto ma se non riesco provo con conto e poi anche gruppo
		for (int c = 3; c > 0 && codricl <= 0; c--)
		{
			codricl = atol(__conti->get(cod, "CODICE"));
			cod.add(0, c);
		}
	}
  return codricl;
}

TTS_sender& app() { return (TTS_sender&)main_app(); }

///////////////////////////////////////////////////////////
// TTS_textset
///////////////////////////////////////////////////////////

class TTS_textset : public TAS400_recordset
{
  TAssoc_array _contatori;

protected:
  long add_count(const char* tipo, long n = 1);

protected:
  void add_field(const char* trc, const char* name = "Filler", int len = 0, char tipo = 'a', 
								 int from = -1, const char* def = NULL);

public:
  virtual bool destroy(TRecnotype r);
  virtual const TString& rec_type(TRecnotype r = -1) const;
  virtual bool set(const char* field, const TVariant& v);
  
  TTS_textset(const char* query = "");
};

class TIVA_item : public TObject
{
	int _row;
	long _conto;
	long _codiva;
	long _codiva11;
	real _imponibile;
	real _imposta;
	TString4 _codcomp;

public:
	int & row() { return _row;}
	long & conto() { return _conto;}
	long & codiva() { return _codiva;}
	long & codiva11() { return _codiva11;}
	real & imponibile() { return _imponibile;}
	real & imposta() { return _imposta;}
	const TString & codcomp() { return _codcomp;}
	TIVA_item(int row, long conto, long codiva, long codiva11, const char * codcomp) : _row(row), _conto(conto), _codiva(codiva), _codiva11(codiva11), _codcomp(codcomp) {}
	virtual ~TIVA_item() {}
};

long TTS_textset::add_count(const char* tipo, long i)
{
  CHECK(strlen(tipo) == 1, "Tipo record non valido");
  real* n = (real*)_contatori.objptr(tipo);
  if (n == NULL)
  {
    n = new real;
    _contatori.add(tipo, n);
  }
  *n += i;
  return n->integer();
}

const TString& TTS_textset::rec_type(TRecnotype r) const
{
  const TString& t = TAS400_recordset::rec_type(r);
  return t;
}

bool TTS_textset::destroy(TRecnotype r)
{
	bool ok;
  if (r >= 0)
  {
    const TString4 t = TAS400_recordset::rec_type(r); // Igora subtipo record!
	  ok = TAS400_recordset::destroy(r);
	
		if (ok)
      add_count(t, -1);
	}
  else
	{
    ok = TAS400_recordset::destroy(r);
		if (ok)
			_contatori.destroy();
  }
  return ok; 
}

void TTS_textset::add_field(const char* trc, const char* name, int len, 
														char tipo, int from, const char* def)
{
	const bool required = false;
  CHECK(trc && *trc, "Tracciato nullo");
  TString80 fname; fname << trc << '.' << name;

  const TFieldtypes t = tipo == 'n' ? _longzerofld : _alfafld;
  const int pos = from - 1;
  if (def && *def)
  {
    CHECKS(def == NULL || (int)strlen(def) <= len, "Invalid default value ", def);
    TVariant var(def); var.convert_to(t);
    create_field(fname, pos, len, t, required, var);
  }
  else
    create_field(fname, pos, len, t, required);
}

bool TTS_textset::set(const char* field, const TVariant& var)
{
  const char* err = NULL;
  int c = -1;
  const TAS400_column_info* info = parse_field(field, c, false);
  bool ok = info != NULL;
  if (ok)
  {
    switch (var.type())
    {
    case _datefld:
      if (var.is_zero())
        ok = set_field(*info, NULL_VARIANT);  
      else
      {
        long ansi = 0;
        const TDate d = var.as_date();
        if (info->_width == 6)
          ansi = d.day()*10000 + d.month()*100 + d.year()%100;
        else
          ansi = d.date2ansi();
        ok = set_field(*info, TVariant(ansi)); 
      }
      break;
    case _realfld:
      if (var.is_zero())
        ok = set_field(*info, NULL_VARIANT);  
      else
      {
        real v = var.as_real(); v *= CENTO;
        ok = set_field(*info, TVariant(v.integer()));  
      }
      break;
    default:
      ok = set_field(*info, var); 
      break;
    }
    if (!ok)
      err = TR("Campo obbligatorio non compilato");
  }
  else
    err = TR("Campo non riconosciuto");
  
  if (err != NULL)
  {
    TString msg;
    msg  << field << ": " << err;
    app().log(2, msg);
  }
  return ok;
}

TTS_textset::TTS_textset(const char* query)
             : TAS400_recordset(TString("AS400(7001,1,6)\n") << query)
{
  const char an = 'a';
  const char n = 'n';
  const bool o = true;
  const bool f = false;
  
  add_field("0", "TRF-DITTA",			5,	 n,	1);			// codice ditta multi
  add_field("0", "TRF-VERSIONE",	1,	 n,	6, "3");	// versione
  add_field("0", "TRF-TARC",			1,	 n,	7, "0");	// tipo record

	// dati cliente/fornitore
  add_field("0", "TRF-COD-CLIFOR",  5,  n,	 8, "0");	// codice cliente/fornitore
  add_field("0", "TRF-RASO",			 32, an,  13);		// ragione sociale
  add_field("0", "TRF-IND",				 30, an,  45);		// indirizzo
  add_field("0", "TRF-CAP",				  5,  n,  75);		// cap
  add_field("0", "TRF-CITTA",			 25, an,  80);		// citta
  add_field("0", "TRF-PROV",				2, an, 105);		// provincia
  add_field("0", "TRF-COFI",			 16, an, 107);		// codice fiscale
  add_field("0", "TRF-PIVA",			 11, an, 123);		// partita iva
  add_field("0", "TRF-PF",					1, an, 134);		// persona fisica S/N
  add_field("0", "TRF-DIVIDE",			2,  n, 135);		// posizione spazio tra cognome e nome
  add_field("0", "TRF-PAESE",				4,  n, 137);		// paese estero di residenza
  add_field("0", "TRF-PIVA-ESTERO",12, an, 141);		// partita iva estera
  add_field("0", "TRF-COFI-ESTERO",20, an, 153);		// codice fiscale estero
  add_field("0", "TRF-SESSO",			  1, an, 173);		// sesso M/F
  add_field("0", "TRF-DTNAS",			  8,  n, 174);		// data di nascita
  add_field("0", "TRF-COMNA",			 25, an, 182);		// comune di nascita
  add_field("0", "TRF-PRVNA",			  2, an, 207);		// provincia di nascita
  add_field("0", "TRF-PREF",			  4, an, 209);		// prefisso telefonico
  add_field("0", "TRF-NTELENUM",	 20, an, 213);		// numero telefonico
  add_field("0", "TRF-FAX-PREF",		4, an, 233);		// prefisso fax
  add_field("0", "TRF-FAX-NUM",		  9, an, 237);		// numero fax
  add_field("0", "TRF-CFCONTO",     7,  n, 246);		// codice conto di costo abituale
  add_field("0", "TRF-CFCODPAG",	  4,  n, 253);		// codice condizioni pagamenti
  add_field("0", "TRF-CFBANCA",			5,  n, 257);		// codice abi
  add_field("0", "TRF-CFAGENZIA",		5,  n, 262);		// codice cab
  add_field("0", "TRF-CFINTERM",		1,  n, 267);		// codice intermerdio clienti/fornitori
	
	// dati fattura
  add_field("0", "TRF-CAUSALE",						 3,  n, 268);		// codice causale movimento
  add_field("0", "TRF-CAU-DES",						15, an, 271);		// descrizione causale
  add_field("0", "TRF-CAU-AGG",						18, an, 286);		// causale aggiuntiva 
  add_field("0", "TRF-CAU-AGG-1",					34, an, 304);		// ulteriore causale aggiuntiva
  add_field("0", "TRF-CAU-AGG-2",					34, an, 338);		// ulteriore causale aggiuntiva
  add_field("0", "TRF-DATA-REGISTRAZIONE", 8,  n, 372);		// data registrazione
  add_field("0", "TRF-DATA-DOC",					 8,  n, 380);		// data documento
  add_field("0", "TRF-NUM-DOC-FOR",				 8,  n, 388);		// numero documento fornitore compreso sezionale
  add_field("0", "TRF-NDOC",							 5,  n, 396);		// numero documento
  add_field("0", "TRF-SERIE",							 2,  n, 401);		// sezionale iva
  add_field("0", "TRF-EC-PARTITA",				 6,  n, 403);		// estratto conto numero partita
  add_field("0", "TRF-EC-PARTITA-ANNO",		 4,  n, 409);		// estratto conto anno partita
  add_field("0", "TRF-EC-COD-VAL",				 3,  n, 413);		// estratto conto in valuta codice valuta esetera
  add_field("0", "TRF-EC-CAMBIO",					13,  n, 416);		// estratto conto in valuta cambio valuta estera
  add_field("0", "TRF-EC-DATA-CAMBIO",		 8,  n, 429);		// estratto conto in valuta data cambio
  add_field("0", "TRF-EC-TOT-DOC-VAL",		16,  n, 437);		// estratto conto in valuta totale documento in valuta
  add_field("0", "TRF-EC-TOT-IVA-VAL",		16,  n, 453);		// estratto conto in valuta totale iva in valuta
  add_field("0", "TRF-PLAFOND",						 6,  n, 469);		// mmaaaa riferimento plafond e fatture differite

	TString80 field;
	// dati iva
	for (int i=0; i<8; i++)
	{
		field.format("TRF-IMPONIB_%d", i);  
		add_field("0", field,	12,  n, 475+(31*i));	// imponibile
		field.format("TRF-ALIQ_%d", i);  
		add_field("0", field,	 3,  n, 487+(31*i));	// aliquota iva o codice esenzione
		field.format("TRF-ALIQ_AGRICOLA_%d", i);  
		add_field("0", field,	 3,  n, 490+(31*i));	// aliquota iva di compensazione agricola
		field.format("TRF-IVA11_%d", i);  
		add_field("0", field,	 2,  n, 493+(31*i));	// codice di memorizzazione per iva11
		field.format("TRF-IMPOSTA_%d", i);  
		add_field("0", field,	11,  n, 495+(31*i));	// imposta
	}

	// totale fattura
  add_field("0", "TRF-TOT-FATT",				12,  n, 723);		// totale fattura

  int i;
  // conti di ricavo/costo
	for (i=0; i<8; i++)
	{
		field.format("TRF-CONTORIC_%d", i);  
		add_field("0", field,	 7,  n, 735+(19*i));	// codice conto di ricavo/costo
		field.format("TRF-IMP-RIC_%d", i);  
		add_field("0", field,	12,  n, 742+(19*i));	// importo ricavo/costo
	}

	// dati eventuale pagamentofattura o movimenti diversi
  add_field("0", "TRF-CAU-PAGAM",				 3,  n, 887);		// codice causale
  add_field("0", "TRF-CAU-DES-PAGAM",		15, an, 890);		// descrizione causale
  add_field("0", "TRF-CAU-AGG-1-PAGAM",	34, an, 905);		// ulteriore descrizione aggiuntiva
  add_field("0", "TRF-CAU-AGG-2-PAGAM",	34, an, 939);		// ulteriore descrizione aggiuntiva

	// altri movimenti
	for (i=0; i<80; i++)
	{
		field.format("TRF-CONTO_%d", i);  
	  add_field("0", field,	 7,  n,  973+(64*i));		// codice conto
		field.format("TRF-DA_%d", i);  
		add_field("0", field,  1, an,  980+(64*i));		// segno operazione D/A
		field.format("TRF-IMPORTO_%d", i);  
		add_field("0", field, 12,  n,  981+(64*i));		// importo
		field.format("TRF-CAU-AGGIUNT_%d", i);  
		add_field("0", field,	18, an,  993+(64*i));		// causale aggiuntiva
		field.format("TRF-EC-PARTITA-PAG_%d", i);  
		add_field("0", field,	 6,  n, 1011+(64*i));		// estratto conto numero partita
		field.format("TRF-EC-PARTITA-ANNO-PAG_%d", i);  
		add_field("0", field,  4,  n, 1017+(64*i));		// estratto conto anno partita
		field.format("TRF-EC-IMP-VAL_%d", i);  
		add_field("0", field,	16,  n, 1021+(64*i));		// estratto conto in valuta 
	}

	// ratei e risconti
	for (i=0; i<10; i++)
	{
		field.format("TRF-RIFER-TAB_%d", i);  
		add_field("0", field,	 1, an, 6093+(19*i));		// tabella di riferimento
		field.format("TRF-IND-RIGA_%d", i);  
		add_field("0", field,	 2,  n, 6094+(19*i));		// indice della tabella
		field.format("TRF-DT-INI_%d", i);  
		add_field("0", field,	 8,  n, 6096+(19*i));		// data inizio
		field.format("TRF-DT-INI_%d", i);  
		add_field("0", field,  8,  n, 6104+(19*i));		// data fine
	}

	// ndoc a 6 cifre se non bastano le 5 di tf-ndoc
  add_field("0", "TRF-DOC6",				 6,  n, 6283);		// ndoc a 6 cifre se non bastano le 5 di trf-doc

	// ulteriori dati cliente/fornitore
  add_field("0", "TRF-AN-OMONIMI",	 1, an, 6289);		// considera omonimo
  add_field("0", "TRF-AN-TIPO-SOGG", 1,  n, 6290);		// tipo soggetto ritenuta di acconto

	// ulteriori dati ev. pagamento o movimenti diversi
	for (i=0; i<80; i++)
	{
		field.format("TRF-EC-PARTITA-SEZ-PAG_%d", i);  
		add_field("0", field,	 2,  n, 6291+(2*i));		// numero sezionale partita estratto conto
	}
	// ulteriori dati gestione professionista per eventuale pagamento fattura o dati fattura
  add_field("0", "TRF-NUM-DOC-PAG-PROF",		 7,  n, 6451);		// numero doc. incasso/pagamento
  add_field("0", "TRF-DATA-DOC-PAG-PROF",		 8,  n, 6458);		// data doc. incasso/pagamento
  add_field("0", "TRF-RIT-ACC",							12,  n, 6466);		// ritenuta d'acconto
  add_field("0", "TRF-RIT-PREV",						12,  n, 6478);		// ritenuta previdenziale
  add_field("0", "TRF-RIT-1",								12,  n, 6490);		// altre ritenute 1
  add_field("0", "TRF-RIT-2",								12,  n, 6502);		// 2
  add_field("0", "TRF-RIT-3",								12,  n, 6514);		// 3
  add_field("0", "TRF-RIT-4",								12,  n, 6526);		// 4

	// ulteriori dati per unita' produttive ricavi
	for (i=0; i<8; i++)
	{
		field.format("TRF-UNITA-RICAVI_%d", i);  
		add_field("0", field, 2,  n, 6538+(2*i));		// 
	}
	// ulteriori dati per unita' produttive pagamenti
	for (i=0; i<80; i++)
	{
		field.format("TRF-UNITA-PAGAM_%d", i);  
		add_field("0", field,	 2,  n, 6554+(2*i));		// 
	}

	// ulteriori dati cliente/fornitore
	add_field("0", "TRF-FAX-PREF-1",		 4, an, 6714);		// prefisso fax sostitutivo
	add_field("0", "TRF-FAX-NUM-1",			20, an, 6718);		// numero fax sositutivo
	add_field("0", "TRF-SOLO-CLIFOR",		 1, an, 6738);		// C crea solo cliente F crea solo fornitore (non genera primanota)
	add_field("0", "TRF-80-SEGUENTE",		 1, an, 6739);		// s=record successivo identico a quello attuale ma con tabella pag compilata (ultima=u)

	// ulteriori dati gestione professionista per eventuale pagamento fattura o dati fattura
	add_field("0", "TRF-CONTO-RIT-ACC",		 7,  n, 6740);		// conto ritenuta d'acconto
	add_field("0", "TRF-CONTO-RIT-PREV",	 7,  n, 6747);		// conto ritenuta previdenziale
	add_field("0", "TRF-CONTO-RIT-1",			 7,  n, 6754);		// conto ritenuta 1
	add_field("0", "TRF-CONTO-RIT-2",			 7,  n, 6761);		// conto ritenuta 2
	add_field("0", "TRF-CONTO-RIT-3",			 7,  n, 6768);		// conto ritenuta 3
	add_field("0", "TRF-CONTO-RIT-4",			 7,  n, 6775);		// conto ritenuta 4
	add_field("0", "TRF-DIFFERIMENTO-IVA", 1, an, 6782);		// differimento registrazione iva per autotrasportatori S/N
	add_field("0", "TRF-STORICO",					 1, an, 6783);		// aggiornamento storico anagrafica
	add_field("0", "TRF-STORICO-DATA",		 8,  n, 6784);		// data aggiornamento storico anagrafica
	add_field("0", "TRF-CAUS-ORI",				 3,  n, 6792);		// causale originaria
	add_field("0", "TRF-PREV-TIPOMOV",		 1, an, 6795);		// previsionale
	add_field("0", "TRF-PREV-RATRIS",			 1, an, 6796);		// rateo /risconto
	add_field("0", "TRF-PREV-DTCOMP-INI",	 8,  n, 6797);		// data iniziale competenza
	add_field("0", "TRF-PREV-DTCOMP-FIN",	 8,  n, 6805);		// data finale competenza
	add_field("0", "TRF-PREV-FLAG-CONT",	 1, an, 6813);		// non contabilizza
	add_field("0", "TRF-PREV-RIFERIMENTO",20,	an, 6814);		// riferimento record interno
	add_field("0", "FILLER",						 166, an, 6834);		// spazio
	add_field("0", "FINE-RECORD",					 2, an, 7000, "\r\n");		// terminatore record

// Record opzionale
  add_field("1", "TRF1-DITTA",			5,	 n,	1);			// codice ditta multi
  add_field("1", "TRF1-VERSIONE",	1,	 n,	6, "3");	// versione
  add_field("1", "TRF1-TARC",			1,	 n,	7, "1");	// tipo record

// intra	

	add_field("1", "TRF-NUM-AUTOFATT",  5, n, 8);			// Numero autofattura Solo per acquisti
  add_field("1", "TRF-SERIE-AUTOFATT", 2, n, 13);		// Sezionale iva
  add_field("1", "TRF-COD-VAL", 3, an, 15);					// Codice valuta
  add_field("1", "TRF-TOTVAL", 14, n, 18);          // Totale importo in valuta (2 dec)

	//  Movimenti INTRASTAT

  add_field("1", "TRF-NOMENCLATURA", 8, an, 32);		// Codice nomenclatura combinata
  add_field("1", "TRF-IMP-LIRE", 12, n, 40);				// Importo in lire
  add_field("1", "TRF-IMP-VAL", 12, n, 52);					// Importo in valuta (2 DEC)
  add_field("1", "TRF-NATURA", 1, an, 64);					// Natura della transazione
  add_field("1", "TRF-MASSA", 12, n, 65);						// Massa netta
  add_field("1", "TRF-UN-SUPPL", 12, n, 77);				// Unit� sostitutiva
  add_field("1", "TRF-VAL-STAT", 12, n, 89);				// Valore statistico
  add_field("1", "TRF-REGIME", 1, an, 101);					// Regime ( condizioni di consegna )
  add_field("1", "TRF-TRASPORTO", 1, an, 102);			// Trasporto
  add_field("1", "TRF-PAESE-PROV", 3, n, 103);			// Paese di provenienza
  add_field("1", "TRF-PAESE-ORIG", 3, n, 106);			// Paese di origine
  add_field("1", "TRF-PAESE-DEST", 3, n, 109);			// Paese di destinazione
  add_field("1", "TRF-PROV-DEST", 2, an, 112);			// Provincia di destinazione
  add_field("1", "TRF-PROV-ORIG", 2, an, 114);			// Provincia di origine
	add_field("1", "TRF-SEGNO-RET", 1, an, 116);			// Segno della rettifica (+/-)
	add_field("1", "TRF-INTRA-TIPO", 1, an, 1732);		// Tipo movimento INTRASTAT 1=Cessioni 2=Ret.cessioni 3=Acquisti 4=Ret.acq.
	add_field("1", "TRF-MESE-ANNO-RIF", 6, n, 1733);  // Mmaaaa competenza rettifiche
	add_field("1", "FILLER", 173, an, 1739);					// Filler
  
//	Ritenuta d�acconto                         

  add_field("1", "TRF-RITA-TIPO", 1, n, 1912);			// 1=Prestazioni e collaborazioni 2=Provvigioni
  add_field("1", "TRF-RITA-IMPON", 11, n, 1913);		// Imponibile
  add_field("1", "TRF-RITA-ALIQ", 4, n, 1924);			// Aliquota (2 dec)
  add_field("1", "TRF-RITA-IMPRA", 10, n, 1928);		// Ritenuta
  add_field("1", "TRF-RITA-PRONS", 11, n, 1938);		// Se TRF-RITA-TIPO = 1 Indicare l�importo del contributo integrativo (2%) , se TRF-RITA-TIPO = 2 Indicare l�importo delle provvigioni non soggette.
  add_field("1", "TRF-RITA-MESE", 6, n, 1949);			// MMAAAA competenza (pagamento fattura)
  add_field("1", "TRF-RITA-CAUSA", 2, n, 1955);			// Codice causale prestazione
  add_field("1", "TRF-RITA-TRIBU", 4, n, 1957);			// Codice tributo
  add_field("1", "TRF-RITA-DTVERS", 8, n, 1961);		// Data versamento
  add_field("1", "TRF-RITA-IMPAG", 11, n, 1969);		// Importo versato
  add_field("1", "TRF-RITA-TPAG", 1, n, 1980);			// Tipo versamento 1=Tesoreria 2=C/C postale 3=Banca
  add_field("1", "TRF-RITA-SERIE", 4, an, 1981);		// Serie 
  add_field("1", "TRF-RITA-QUIETANZA", 12, an, 1985); // Quietanza
  add_field("1", "TRF-RITA-NUM-BOLL", 12, an, 1997);	// Numero bollettino C/C
  add_field("1", "TRF-RITA-ABI", 5, n, 2009);				// Codice abi
  add_field("1", "TRF-RITA-CAB", 5, n, 2014);				// Codice cab
  add_field("1", "TRF-RITA-AACOMP", 4, n, 2019);		// Anno di competenza provvigioni se diverso da quello delle ritenute
  add_field("1", "TRF-RITA-CRED", 11, n, 2023);			// Credito d�imposta utilizzato verticalmente per non versare

// Dati contributo INPS e modello GLA/D

  add_field("1", "TRF-RITA-SOGG", 1, an, 2034);			// Soggetto al contributo S=Si N=No
  add_field("1", "TRF-RITA-BASEIMP", 11, n, 2035);	// Base imponibile
  add_field("1", "TRF-RITA-FRANCHIGIA", 11, n, 2046);	// Importo gi� assoggettato
  add_field("1", "TRF-RITA-CTO-PERC", 11, n, 2057);	// Ritenuta conto percipiente
  add_field("1", "TRF-RITA-CTO-DITT", 11, n, 2068); // Ritenuta conto ditta
  add_field("1", "FILLER", 11, an, 2079);						// Filler
  add_field("1", "TRF-RITA-DATA", 8, n, 2090);			// Data versamento
  add_field("1", "TRF-RITA-TOTDOC", 11, n, 2098);		// Totale documento
  add_field("1", "TRF-RITA-IMPVERS", 11, n, 2109);	// Importo versato
  add_field("1", "TRF-RITA-DATA-I", 8, n, 2120);		// Data inizio
  add_field("1", "TRF-RITA-DATA-F", 8, n, 2128);		// Data competenza
  add_field("1", "TRF-EMENS-ATT", 2, n, 2136);			// EMENS - Codice attivit� 
  add_field("1", "TRF-EMENS-RAP", 2, n, 2138);			// EMENS - Tipo rapporto
  add_field("1", "TRF-EMENS-ASS", 3, n, 2140);			// EMENS - Altra assicurazione
  add_field("1", "FILLER", 195, an, 2143);					// Filler

// Dati portafoglio

  add_field("1", "TRF-POR-CODPAG", 3, n, 2338);			// Codice condizione di pagamento
  add_field("1", "TRF-POR-BANCA", 5, n, 2341);			// ABI
  add_field("1", "TRF-POR-AGENZIA", 5, n, 2346);		// CAB
  add_field("1", "TRF-POR-DESAGENZIA", 30, an, 2351);	// Descrizione agenzia
  add_field("1", "TRF-POR-TOT-RATE", 2, n, 2381);		// Numero totale rate
  add_field("1", "TRF-POR-TOTDOC", 12, n, 2383);		// Totale documenti

// Dettaglio effetti
// La tabella dettaglio effetti (lunghezza complessiva di 804 caratteri) � composta da 12 elementi i che comprendono i campi da TRF-POR-NUM-RATA a  TRF-POR-TIPO-RD. Le posizioni indicate sono quindi relative al primo elemento
  add_field("1", "TRF-POR-NUM-RATA", 2, n, 2395);		// Numero rata 
  add_field("1", "TRF-POR-DATASCAD", 8, n, 2397);		// Data scadenza
  add_field("1", "TRF-POR-TIPOEFF", 1, n, 2405);		// Tipo effetto 1=Tratta 2=Ricevuta bancaria 3=Rimessa diretta 4=Cessioni 5=Solo descrittivo 6=Contanti alla consegna  
  add_field("1", "TRF-POR-IMPORTO-EFF", 12, n, 2406); // Importo effetto
  add_field("1", "TRF-POR-IMPORTO-EFFVAL", 15, n, 2418); // Portafoglio in valuta. Importo effetto in valuta (3 dec)
  add_field("1", "TRF-POR-IMPORTO-BOLLI", 12, n, 2433);	 // Importo bolli
  add_field("1", "TRF-POR-IMPORTO-BOLIVAL", 15, n, 2445); // Portafoglio in valuta. Importo bolli  in valuta (3 dec)
  add_field("1", "TRF-POR-FLAG", 1, an, 2460);			// Stato effetto 0=Aperto 1=Chiuso 2=Insoluto 3=Personalizzato
  add_field("1", "TRF-POR-TIPO-RD", 1, an, 2461);		// Sottotipo rimessa diretta
  add_field("1", "TRF-POR-CODAGE", 4, n, 3199);			// Codice agente
  add_field("1", "FILLER", 3797, an, 3203);					// Filler
	add_field("1", "FINE1-RECORD",					 2, an, 7000, "\r\n");		// terminatore record 0D0A HEX 0D non obbligatorio )
}

///////////////////////////////////////////////////////////
// TTS_sender
///////////////////////////////////////////////////////////

const TString & TTS_sender::descr2agg(const char* d)
{
	TString & descr = get_tmp_string(128);

	descr = d;
	int p = descr.find("Inc. ft. ");

	if (p < 0)
		p = descr.find("Pag. ft. ");
	if (p < 0)
		p = descr.find("Nota cr. ");
	if (p >= 0)
		descr.ltrim(p + 9);
	descr = descr.left(18);

	return descr;
}

bool TTS_sender::new_rec(const char* t)
{
	CHECK(t && *t, "Tipo non valido");
	return _tsfile->new_rec(t) >= 0;
}

void TTS_sender::log(int sev, const char* msg)
{ 
	if (_log != NULL)
	{
		if (sev > 0 && _tsfile != NULL)
		{
			TString m;
			m << TR("Record") << ' ' << _tsfile->rec_type() << ": " << msg;
			_log->log(sev, m); 
			_errors_logged = true;
		}
		else
			_log->log(sev, msg);
	}
}

void TTS_sender::set(const char* field, const TVariant& var) 
{ 
  _tsfile->set(field, var);
}

const TVariant& TTS_sender::get(const char* field) 
{ 
  return _tsfile->get(field);
}


void TTS_sender::remove_last()
{ 
	_tsfile->destroy(_tsfile->last());
	_tsfile->move_last();
}

bool TTS_sender::add_optional_rec(TRecordset& mov, bool rec_to_add)
{
	if (rec_to_add)
	{
		new_rec("1");
		set("TRF1-DITTA",	dittamulti(mov));
	}
	return false;
}

bool TTS_sender::add_regol(TRecordset& mov, bool rec_to_add)
{
	rec_to_add = add_optional_rec(mov, rec_to_add);
	
	TString16 codval = mov.get(MOV_CODVALI).as_string();
	real corrvaluta = mov.get(MOV_CORRVALUTA).as_real();

	if (codval.blank())
	{
		codval = TCurrency::get_firm_val();
		corrvaluta = mov.get(MOV_TOTDOC).as_real();
	}
	codval = scod2ricl("TSVAL", codval);
	set("TRF-COD-VAL", codval);

  const bool is_intra = mov_intra(mov);
	if (is_intra)
	{
		corrvaluta *= CENTO;
		set("TRF-TOTVAL", corrvaluta);
	}

  const TRecnotype pos = mov.current_row(); // Salva la posizione

	if (find_regolarizzazione(mov))
	{
		set("TRF-NUM-AUTOFATT", mov.get(MOV_PROTIVA).as_int());

		const TString16 codice = scod2ricl("TSREG", mov.get(MOV_REG));
		const long codreg = atol(codice.mid(1));
		set("TRF-SERIE-AUTOFATT", codreg);
	}
	else
	{
		if (is_intra)
			log(2, TR("Manca la regolarizzazione del movimento intra"));
		else
			log(2, TR("Manca la regolarizzazione del movimento reverse charge"));
	}

	mov.move_to(pos); // Ripristina posizione

	return rec_to_add;
}

void TTS_sender::add_ulteriori(TRecordset& mov)
{
	bool rec_to_add = true;

	if (mov_intra(mov) ||	mov_reverse_charge(mov))
		add_regol(mov, rec_to_add);
}

void TTS_sender::add_ratei_risconti(const TRecordset& mov)
{
}

const TString & TTS_sender::dittamulti(const TRecordset& mov) const 
{
	if (multi_activity())
	{
		const TString4 codice(mov.get(MOV_REG).as_string());

		if (codice.full())
		{
			int annoiva = mov.get(MOV_DATAREG).as_date().year();
			TString16 key;

			key.format("%04d%s", annoiva, (const char *) codice);
			const TString8 attivita = cache().get("REG", key, "S8");
			const TString * ditta = (const TString * )_dittemulti.objptr(attivita);

			if (ditta != NULL)
				return *ditta;
		}
	}
	return _dittamulti;
}

void TTS_sender::add_new_rec(const TRecordset& mov)
{
	set("TRF-80-SEGUENTE", "S");
	if (new_rec("0"))
	{
		add_header(mov, false);
		set("TRF-80-SEGUENTE", "U");
	}
}

void TTS_sender::add_diversi(const TRecordset& mov, const bool moviva)
{
	const bool vendite = mov.get(MOV_TIPO).as_string()[0] != 'F';
	const TString16 codice = scod2ricl("TSREG", mov.get(MOV_REG));
	const bool corrispettivo = codice[0] == 'C';

	long contoclifor = 0L;
	char seznor = ' ';

	if (moviva)
	{
		if (test_swap(mov))
			seznor = vendite ? 'D' : 'A';
		else
			seznor = vendite ? 'A' : 'D';
	}
  
	const bool dont_send_clifo = _riclassifica.is_key("TSNOHCLI");
	TRecordset & rmov = rmovrecset(mov);
  int i = 0 , j = 0, k = 0;
	bool added_rec = false, valid_rec = false;
	bool first_cli = true;
	TString80 field;
	TString16 key;
	const bool intra_rev = add_iva_to_mov(mov);
	bool ok = rmov.move_first();
	const bool as400 = moviva && (rmov.get(RMV_ROWTYPE).as_string()[0] <= ' ');

	for (; ok; ok = rmov.move_next(), i++)
	{
		bool riga_ritenute = false;
		const int gr = rmov.get(RMV_GRUPPO).as_int();
		const int co = rmov.get(RMV_CONTO).as_int();
		const long so = rmov.get(RMV_SOTTOCONTO).as_int();
		char t = rmov.get(RMV_TIPOC).as_string()[0];
		bool one_clifor =(dont_send_clifo && t > ' ');
		const long contoricl = bill2ricl(t, gr, co, so, !moviva); //, one_clifor);
//		bool add_rec = (j >= 80) || (dont_send_clifo && t > ' ');
		bool add_rec = (j >= 80) || t > ' ';
		if (moviva)
		{
			if (as400)
			{
				if (t > ' ' && !corrispettivo && first_cli)
				{
					first_cli = false;
					contoclifor = contoricl;
					continue;
				}
				key.format("%08ld", contoricl);
				if (_contiiva.is_key(key))
					continue;
				if (_contirit.is_key(key))
				{
					riga_ritenute = true;
					if (_professionista && vendite)
						_rit_acc += rmov.get(RMV_IMPORTO).as_real();
				}
				else
				{
					if (!corrispettivo)
					{
						if (k < 8)
						{
							const real importo = rmov.get(RMV_IMPORTO).as_real();
							const char sez = rmov.get(RMV_SEZIONE).as_string()[0];
							TImporto i(sez, importo);

							i.normalize(seznor);
							field.format("TRF-CONTORIC_%d", k);  
							set(field, contoricl);
							field.format("TRF-IMP-RIC_%d", k);  
							set(field, i.valore());
							k++;
						}
						else
							log(2, TR("Registrazione con pi� di 8 conti di costo/ricavo"));
					}
					continue;
				}
			}
			else
			{
				const char tiporiga = rmov.get(RMV_ROWTYPE).as_string()[0];

				switch (tiporiga)
				{
				case 'T':
						first_cli = false;
						contoclifor = contoricl;
				case 'I':
				case 'D':
				case 'N':
					continue;
				case 'F':
				case 'S':
					riga_ritenute = true;
					break;
				default:
					break;
				}
			}
		}

		if (add_rec)
		{
			if (!first_cli)
			{
				add_new_rec(mov);
				j = 0;
				added_rec = true;
				valid_rec = false;
			}
//			if (dont_send_clifo && get("TRF-RASO").as_string().blank() && t > ' ' && so > 0 )
			if (get("TRF-RASO").as_string().blank() && t > ' ' && so > 0 )
				add_clifor(t, so);
		}
		if (!moviva && t > ' ' && first_cli)
			first_cli = false;
		if (!(riga_ritenute && intra_rev))
		{
			if (!_professionista || !vendite)
			{
				field.format("TRF-CONTO_%d", j);  
				set(field, contoricl);
				field.format("TRF-IMPORTO_%d", j);  
				set(field, rmov.get(RMV_IMPORTO));
				field.format("TRF-DA_%d", j);  
				set(field, rmov.get(RMV_SEZIONE));
				field.format("TRF-CAU-AGGIUNT_%d", j);  
				set(field, descr2agg(rmov.get(RMV_DESCR).as_string()));
				const long numpart = atol(mov.get(MOV_NUMDOC).as_string());
				TString snumpart;
				snumpart.format("%06ld", numpart);
				field.format("TRF-EC-PARTITA-PAG_%d", i);  
				set(field, snumpart);		// estratto conto numero partita
				field.format("TRF-EC-PARTITA-ANNO-PAG_%d", i);  
				set(field, mov.get(MOV_ANNOIVA));		// estratto conto anno partita
				j++;
				if (riga_ritenute)
				{
					if (contoclifor > 0L)
					{
						field.format("TRF-CONTO_%d", j);  
						set(field, contoclifor);
						field.format("TRF-IMPORTO_%d", j);  
						set(field, rmov.get(RMV_IMPORTO));
						field.format("TRF-DA_%d", j);  
						const TString4 sez = rmov.get(RMV_SEZIONE).as_string() == "D" ? "A" :"D";
						set(field, sez);
						field.format("TRF-CAU-AGGIUNT_%d", j);  
						set(field, descr2agg(rmov.get(RMV_DESCR).as_string()));
						const long numpart = atol(mov.get(MOV_NUMDOC).as_string());
						TString snumpart;
						snumpart.format("%06ld", numpart);
						field.format("TRF-EC-PARTITA-PAG_%d", i);  
						set(field, snumpart);		// estratto conto numero partita
						field.format("TRF-EC-PARTITA-ANNO-PAG_%d", i);  
						set(field, mov.get(MOV_ANNOIVA));		// estratto conto anno partita
						j++;
					}
					else
						log(2, "Conto cliente/formitore non trovato per giroconto ritenute o intra o reverse charge");
				}
			}
			else
				set("TRF-RIT-ACC", _rit_acc);

		}
		valid_rec = true;
	}
	if (added_rec && !valid_rec)
	{
		remove_last();
		set("TRF-80-SEGUENTE", "U");
	}
}

void TTS_sender::add_conti_ricavo_costo(const TRecordset& mov)
{
	TRecordset & rmov = rmovrecset(mov);

	rmov.move_first();
	const char tiporiga = rmov.get(RMV_ROWTYPE).as_string()[0];
	TString16 codice = scod2ricl("TSREG", mov.get(MOV_REG));
	const bool corrispettivo = codice[0] == 'C';
	if (tiporiga <= ' ' && ! corrispettivo)
		return;

	TRecordset & riva = rivarecset(mov);
	const bool acquisto = mov.get(MOV_TIPO).as_string()[0] == 'F';
	int i = 0, j = 0;
	real fattore = UNO;
	TString16 key;

  if (test_swap(mov))
		fattore = -fattore;
  _iva.destroy();
	for (bool ok = riva.move_first(); ok; ok = riva.move_next(), i++)
  {
		const int gr = riva.get(RMI_GRUPPO).as_int();
		const int co = riva.get(RMI_CONTO).as_int();
		const long so = riva.get(RMI_SOTTOCONTO).as_int();
		char t = riva.get(RMI_TIPOC).as_string()[0];
		const long hcli = mov.get(MOV_CODCF).as_int();
		const long contoricl = bill2ricl(t, gr, co, so); // , hcli == so); // ok
  	
		real imponibile = riva.get(RMI_IMPONIBILE).as_real() * fattore;
	
		if (corrispettivo)
		{
			if (riva.get(RMI_IMPOSTA).is_zero())
			{
				TCodiceIVA c(riva.get(RMI_CODIVA).as_string());
				c.scorpora(imponibile);
			}
		}
		else
		{
      //da modificare nella 3.1
			const TString4 tipodet = riva.get(RMI_TIPODET).as_string();
			const bool indetraibile = tipodet.full();
			
			if (acquisto && indetraibile)
				imponibile += riva.get(RMI_IMPOSTA).as_real() * fattore;
		}
		key.format("%08ld", contoricl);
		TIVA_item * item = (TIVA_item *) _iva.objptr(key);

		if (item == NULL)
		{
			item = new TIVA_item(j++, contoricl, 0L, 0L, "");
			_iva.add(key, item);
		}
		item->imponibile() += imponibile;
	}

	TString80 field;

	if (_iva.items() > 8)
		log(2, TR("Registrazione con pi� di 8 conti di costo/ricavo"));


	FOR_EACH_ASSOC_OBJECT(_iva, o, k, it)                       
  {
		TIVA_item & item = (TIVA_item &) *it;
		const int row = item.row();

		if (row < 8)
		{
			field.format("TRF-CONTORIC_%d", row);  
			set(field, item.conto());
			field.format("TRF-IMP-RIC_%d", row);  
			set(field, item.imponibile());
		}
	}
}

void TTS_sender::add_tot_fattura(const TRecordset& mov)
{
	const bool vendite = mov.get(MOV_TIPO).as_string()[0] != 'F';
	real totdoc = mov.get(MOV_TOTDOC).as_real();
	const real ritfis = mov.get(MOV_RITFIS).as_real();
	const real ritsoc = mov.get(MOV_RITSOC).as_real();

	if (ritfis != ZERO)
		totdoc += ritfis;
  if (ritsoc != ZERO)
	{
		if (swap_ritsoc(mov))                      // Somma ritenute sociali con segno
			totdoc -= ritsoc;
	  else
		  totdoc += ritsoc;                        
	}
  if (test_swap(mov))
		totdoc = -totdoc;
	set("TRF-TOT-FATT", totdoc);

	if (_professionista && vendite)
		set("TRF-RIT-ACC", ritfis);
	_rit_acc = ZERO;
}

void TTS_sender::add_datiiva(const TRecordset& mov)
{
  TRecordset & rmoviva = rivarecset(mov);
	TString16 codice = scod2ricl("TSREG", mov.get(MOV_REG));
	const bool corrispettivo = codice[0] == 'C';
	const bool acquisto = mov.get(MOV_TIPO).as_string()[0] == 'F';
	int i = 0, j = 0;
	real fattore = UNO;
	TString16 key;
	const int codiva11rev = mov_reverse_charge(mov) ? cod2ricl("TSI11", TVariant(iva11_reverse(mov))) : 0L;

  if (test_swap(mov))
		fattore = -fattore;
	_iva.destroy();
	for (bool ok = rmoviva.move_first(); ok; ok = rmoviva.move_next(), i++)
  {
		real imponibile = rmoviva.get(RMI_IMPONIBILE).as_real() * fattore;
		real imposta = rmoviva.get(RMI_IMPOSTA).as_real() * fattore;
		TCodiceIVA c(rmoviva.get(RMI_CODIVA).as_string());
		bool agricolo = c.get_int("S4") == 1;
		TString16 codcomp;
		TString key;
		key.format("%03ld|%03ld|%06ld", rmoviva.get(RMI_GRUPPO).as_int(), rmoviva.get(RMI_CONTO).as_int(), rmoviva.get(RMI_SOTTOCONTO).as_int());
	
		if (corrispettivo)
			if (imposta == ZERO)
				imposta = c.scorpora(imponibile);
		if (regime_agricolo(mov) && agricolo)
		{
			const TRectype & pcon = cache().get(LF_PCON, key);
			codcomp = pcon.get(PCN_IVACOMP);
		}
		long codiva = cod2ricl("TSIVA", rmoviva.get(RMI_CODIVA));
		long codiva11 = 0L;
		//da modificare nella 3.1
		const TString4 tipodet = rmoviva.get(RMI_TIPODET).as_string();
		const bool indetraibile = tipodet.full();
		const TString4 tipocr = rmoviva.get(RMI_TIPOCR).as_string();
		const bool acqvent = _ventilazione && (imposta != ZERO) && tipocr == "1";
			
		if (acquisto && indetraibile)
			codiva += TSINDETR; // maialata
		if (acquisto && acqvent)
			codiva += TSACQDESTRIV; // maialata 2 
		if (codiva11rev > 0L)
			codiva11 = codiva11rev;
		else
			if (rmoviva.get(RMI_TIPOCR).as_int() > 0)
				codiva11 = cod2ricl("TSI11", tipocr);
		key.format("%04ld%04ld%s", codiva, codiva11, (const char *) key);
		TIVA_item * item = (TIVA_item *) _iva.objptr(key);

		if (item == NULL)
		{
			item = new TIVA_item(j++, 0L, codiva, codiva11, codcomp);
			_iva.add(key, item);
		}
		item->imponibile() += imponibile;
		item->imposta() += imposta;
	}

	TString80 field;

	if (_iva.items() > 8)
		log(2, TR("Registrazione con piu di 8 righe IVA"));


	FOR_EACH_ASSOC_OBJECT(_iva, o, k, it)                       
  {
		TIVA_item & item = (TIVA_item &) *it;
		const int row = item.row();

		if (row < 8)
		{
			field.format("TRF-IMPONIB_%d", row);  
			set(field, item.imponibile());
			field.format("TRF-ALIQ_%d", row);
			set(field, item.codiva());
			field.format("TRF-ALIQ_AGRICOLA_%d", row);  
			set(field, item.codcomp());
			field.format("TRF-IVA11_%d", row);  
			set(field, item.codiva11());
			field.format("TRF-IMPOSTA_%d", row);  
			set(field, item.imposta());
		}
	}
}

void TTS_sender::add_header(const TRecordset& mov, const bool fullhesd)
{
  const bool moviva = !mov.get(MOV_REG).is_empty();
	const TString8 src_caus(mov.get(MOV_CODCAUS).as_string());
	const long codcaus = src_caus.full() ? cod2ricl("TSCAU", src_caus) : _empty_caus;

	// dati obbligatori
  set("TRF-DITTA", dittamulti(mov));
  set("TRF-CAUSALE", codcaus);
	
	const TString descaus(decode_causale(mov));
  const TString & desc = mov.get(MOV_DESCR).as_string();
  
	set("TRF-CAU-DES", descaus.left(15));
	if (!moviva)
	{
		set("TRF-CAU-AGG", descaus.mid(15));
	set("TRF-CAU-AGG-1", desc.left(34));
  set("TRF-CAU-AGG-2", desc.mid(34));
	}
	else
	{
		set("TRF-CAU-AGG", desc.left(18));
		set("TRF-CAU-AGG-1", desc.mid(18));
	}
	
	const TDate datareg(mov.get(MOV_DATAREG).as_string());
  
	set("TRF-DATA-REGISTRAZIONE", datareg.string(full, '\0'));
  
	const TDate datadoc( mov.get(MOV_DATADOC).as_string());
	
	set("TRF-DATA-DOC",					  datadoc.string(full, '\0'));

	TString numdoc(mov.get(MOV_NUMDOC).as_string());
	TString16 codice = moviva ? scod2ricl("TSREG", mov.get(MOV_REG)) : "000";

  numdoc.left(6);
	if (numdoc.full())
	{
		TString s;

		for (int i = 0; i < numdoc.len(); i++)
			if (isdigit(numdoc[i]))
				s << numdoc[i];
		numdoc.lpad(6, '0');
		numdoc << codice.mid(1);
	}
	set("TRF-NUM-DOC-FOR",			  numdoc);
  set("TRF-NDOC",							  mov.get(MOV_PROTIVA));
  const bool send_clifo = !_riclassifica.is_key("TSNOHCLI");

  if (send_clifo)
		set("TRF-COD-CLIFOR",	mov.get(MOV_CODCF));
	
	if (moviva)
	{
		const long codreg = atol(codice.mid(1));

		set("TRF-SERIE", codreg);
	}
}

void TTS_sender::get_citta_provincia(const TRecordset& cli, TString & dencom, TString & provcom, bool nascita)
{
	TString16 key;

	if (nascita)
	{
		key << cli.get(CLI_STATONASC); 
		key << '|' << cli.get(CLI_COMNASC);
	}
	else
	{
		key << cli.get(CLI_STATOCF);
		key << '|' << cli.get(CLI_COMCF);
    
    if (key.len() < 5)
    {
      key = "|";
      key << cap2comune(cli.get(CLI_CAPCF).as_string(), cli.get(CLI_LOCCF).as_string());
    }
	}

  const TRectype& com = cache().get(LF_COMUNI, key);
	dencom = com.get(COM_DENCOM);
	provcom = com.get(COM_PROVCOM);

  if (!nascita)
  {
    const TString& localita = cli.get(CLI_LOCCF).as_string();
    if (localita.full() && xvt_str_fuzzy_compare(localita, dencom) < 0.75)
    {
			if (dencom.full())
				dencom.insert(", ");
      dencom.insert(localita);
    }
  }
}

void TTS_sender::add_clifor(char tipocf, long codcf)
{
	// dati clienti/fornitore
	if (codcf != 0)
	{
		const TRecordset& cli = clirecset(tipocf, codcf);
		const char tipocf = cli.get(CLI_TIPOCF).as_string()[0];
    TString80 indirizzo;

		indirizzo << cli.get(CLI_INDCF) << ' ' 
							<< cli.get(CLI_CIVCF) << ' ' 
							<< cli.get(CLI_LOCCF);
		TString ragsoc(cli.get(CLI_RAGSOC).as_string());
		const char tipopers = cli.get(CLI_TIPOPERS).as_string()[0];
		const bool fisica = tipopers=='F';
		int divide = 0;

		if (fisica)
		{
			TString80 r1(ragsoc.left(30));
			TString80 r2(ragsoc.mid(30));

			r1.trim();
			r2.trim();
			ragsoc = r1;
			divide = ragsoc.len() + 1;
			ragsoc << " " << r2;
		}
	  const bool send_clifo = !_riclassifica.is_key("TSNOHCLI");

		if (send_clifo)
 			set("TRF-COD-CLIFOR",	codcf);
		set("TRF-RASO", ragsoc);
		set("TRF-IND",	indirizzo);
		set("TRF-CAP",	cli.get(CLI_CAPCF));

		TString dencom;
		TString4 provcom;
		get_citta_provincia(cli, dencom, provcom);
		
		set("TRF-CITTA",	dencom.left(80));
		set("TRF-PROV",		provcom);

		set("TRF-COFI", cli.get(CLI_COFI));
		set("TRF-PIVA", cli.get(CLI_PAIV));
		
		set("TRF-PF",	fisica ? "S" : "N");
		
		set("TRF-DIVIDE", divide);
		const long stato = cod2ricl("TSNAZ", cli.get(CLI_STATOCF));
		set("TRF-PAESE", stato);

		//set("TRF-PIVA-ESTERO",);		// partita iva estera
		//set("TRF-COFI-ESTERO",);		// codice fiscale estero

		if (fisica)  
		{
			//set("TRF-SESSO",);		// sesso M/F
			const TDate dnasc(cli.get(CLI_DATANASC).as_string());

			set("TRF-DTNAS",	dnasc.string(full, '\0'));
	
			get_citta_provincia(cli, dencom, provcom, true);
			
			set("TRF-COMNA",	dencom.left(80));
			set("TRF-PRVNA",	provcom);
		}
		set("TRF-PREF",			cli.get(CLI_PTEL));
		set("TRF-NTELENUM",	cli.get(CLI_TEL));
		set("TRF-FAX-PREF",	cli.get(CLI_PFAX));
		set("TRF-FAX-NUM",	cli.get(CLI_FAX));
		
		if (tipocf == 'F')
		{
			const int gr = cli.get(CLI_GRUPPORIC).as_int();
			const int co = cli.get(CLI_CONTORIC).as_int();
			const int so = cli.get(CLI_SOTTOCRIC).as_int();
			
			char t = ' ';
			const long contoricl = bill2ricl(t, gr, co, so); //ok
			
			set("TRF-CFCONTO", contoricl);
		}
		
		const long codpag = cod2ricl("TSCDP", cli.get(CLI_CODPAG));
		set("TRF-CFCODPAG",	 codpag);		
		
		set("TRF-CFBANCA",	 cli.get(CLI_CODABI));
		set("TRF-CFAGENZIA", cli.get(CLI_CODCAB));
		if (_riclassifica.is_key("TSSTOCLI"))
		{
			set("TRF-STORICO", "S");
			TDate datalim = get_mask().get_date(F_DATA_AL);
			set("TRF-STORICO-DATA", datalim.date2ansi());
		}
	}
}

void TTS_sender::add_mov(TRecordset& mov)
{
  TString msg; msg << TR("Registrazione n.") << ' ' << mov.get(MOV_NUMREG);
  log(0, msg);
  if (new_rec("0"))
	{
		char tipocf = mov.get(MOV_TIPO).as_string()[0];
		long codcf = mov.get(MOV_CODCF).as_int();
		
		add_clifor(tipocf, codcf);
		add_header(mov);

	  const bool moviva = !mov.get(MOV_REG).is_empty();
	
		if (moviva)
		{
	  	add_datiiva(mov);
		  add_tot_fattura(mov);
		  add_conti_ricavo_costo(mov);
		}
		add_ratei_risconti(mov);  // Non ce li abbiamo micca!
 		add_diversi(mov, moviva);
		add_ulteriori(mov);	
	}
}

const long TTS_sender::bill2ricl(char & t, int gr, int co, long so, const bool header_cli)
{
  long codricl = 0;
	if (gr > 0)
	{
		const bool ricl = _riclassifica.is_key(__tiporicconti);

		if (ricl)
		{
			codricl = ::TSbill2ricl(t, gr, co, so);

			if (codricl <= 0)
			{
				TString msg;
				msg << TR("Conto") << " " << gr << " " << co << " " << so  << " :" << TR("Non presente in tabella");
				log(2, msg);
			}
			else
			{
				if (codricl % 10000 > 0)
					t = ' ';
				if (t > ' ')
				{
					if (header_cli)
					{
						if (t == 'C')
							codricl = 9999999L;
						else
							codricl = 9999998L;
					}
					else
						codricl += so;
				}
			}
		}
		else
		{
			if (t > ' ')
			{
				if (header_cli)
				{
					if (t == 'C')
						codricl = 9999999L;
					else
						codricl = 9999998L;
				}
				else
					codricl = gr*100000+so;

			}
			else
				codricl = gr*100000+co*1000+so;
		}
	}
  return codricl;
}

const TString & TTS_sender::scod2ricl(const char* tab, const TString& cod)
{
  TString & codricl = get_tmp_string();
	if (cod.full())
	{
		const bool ricl = _riclassifica.is_key(tab);
		const char* err = NULL;
		if (ricl)
		{
			codricl = _tabelle->sdecode(tab, cod);
			if (codricl.blank())
				err = TR("Non presente in tabella");  
		}
		else
			codricl = cod;
		if (err)
		{
			TString msg;
			msg << TR("Codice") << " " <<  cod << " " << TR("Tabella") << " " << tab << " :" << err;
			log(2, msg);
		}
	}
  return codricl;
}

const TString & TTS_sender::scod2ricl(const char* tab, const TVariant& cod)
{
	return scod2ricl(tab, cod.as_string());
}

const long TTS_sender::cod2ricl(const char* tab, const TString& cod)
{
  long codricl = 0;
	if (cod.full())
	{
		const bool ricl = _riclassifica.is_key(tab);
		const char* err = NULL;
		if (ricl)
		{
			codricl = _tabelle->decode(tab, cod);
			if (codricl <= 0)
				err = TR("Non presente in tabella");  
		}
		else
		{
			if (real::is_natural(cod))
				codricl = atol(cod);
			else
				err = TR("Non e' un codice numerico");  
		}
		if (err)
		{
			TString msg;
			msg << TR("Codice") << " " <<  cod << " " << TR("Tabella") << " " << tab << " :" << err;
			log(2, msg);
		}
	}
  return codricl;
}

const long TTS_sender::cod2ricl(const char* tab, const TVariant& cod)
{
	return cod2ricl(tab, cod.as_string());
}

void TTS_sender::set_parameters()
{
	TConfig configtc(CONFIG_DITTA, "tc");

	_dittamulti = configtc.get("TSDitta");
	_professionista = configtc.get_bool("TSPROFESS");
	_ventilazione = configtc.get_bool("TSVENT");

	for (int j = 0; configtc.exist("TSDATT", j); j++)
	{
		const TString8 att(configtc.get("TSDATT", NULL, j));
		const TString8 ditta(configtc.get("TSDDITTA", NULL, j));

		if (att.full())
			_dittemulti.add(att, ditta);
	}

	_empty_caus = configtc.get_long("TSREMCAU");

	TAssoc_array& tab = configtc.list_variables();
	
	
	FOR_EACH_ASSOC_STRING(tab, h, k, v)
	{
		TString16 var(k);

		if (var.starts_with("TSR"))
		{
			const bool ric = (*v > ' ') && strchr("1SXY", *v) != NULL;

			if (ric)
			{
				var.format("TS%s", (const char *)var.mid(3));
				_riclassifica.add(var, NULL);
			}
		}
	}
	int i = 0, gr = 0;

	for (i = 0, gr = configtc.get_int("TSGIVA", NULL, i); gr > 0; i++, gr = configtc.get_int("TSGIVA", NULL, i))
	{
		int co = configtc.get_int("TSCIVA", NULL, i);
		long so = configtc.get_long("TSSIVA", NULL, i);
		char t = ' ';

		long contoricl = bill2ricl(t, gr, co, so); // ok
		TString16 key; key.format("%08ld", contoricl);
		_contiiva.add(key, NULL);
	}
	for (i = 0, gr = configtc.get_int("TSGRIT", NULL, i); gr > 0; i++, gr = configtc.get_int("TSGRIT", NULL, i))
	{
		int co = configtc.get_int("TSCRIT", NULL, i);
		long so = configtc.get_long("TSSRIT", NULL, i);
		char t = ' ';

		long contoricl = bill2ricl(t, gr, co, so); // ok
		TString16 key; key.format("%08ld", contoricl);
		_contirit.add(key, NULL);
	}
}

bool TTS_sender::create()
{
	_tabelle = new TTSRiclassifica_cache;
	set_parameters();
	return TSkeleton_application::create();
}

bool TTS_sender::destroy()
{
	delete _tabelle;
	return TSkeleton_application::destroy();
}

void TTS_sender::main_loop()
{
	TMask & m = get_mask();
  while (m.run() != K_QUIT)
  {
    const char* const title = TR("Invio a TeamSystem");
    _tsfile = new TTS_textset;
    _log = new TLog_report(title);
    _errors_logged = false;

		TRecordset & mov = movrecset();
    TProgind pi(mov.items(), TR("Scansione movimenti"), true, true);

    for (bool ok = mov.move_first(); ok; ok = mov.move_next())
    {
      if (!pi.addstatus(1))
        break;
			if (!mov_regolarizzazione(mov))
				add_mov(mov);					
		}
    TReport_book book;
    book.add(*_log);
#ifdef DBG
    TAS400_report rep(*_tsfile);
    book.add(rep);
#endif
    book.preview();

    bool save = true;
    if (_errors_logged)
    {
      save = yesno_box(TR("Sono stati riscontrati uno o piu' errori:\n"
                          "Si desidera salvare il file ugualmente?"));
    }
    if (save)
    {
			TFilename name = m.get(F_PATH);

		  name.add(m.get(F_FILE));
			_tsfile->save_as(name);
			postprocess_movs(mov);
    }

    delete _log;
		_log = NULL;
    delete _tsfile;
		_tsfile = NULL;
  }
}