#include <applicat.h>
#include <execp.h>
#include <defmask.h>
#include <modaut.h>
#include <progind.h>
#include <recset.h>
#include <sheet.h>
#include <smartcard.h>
#include <tabutil.h>
#include <urldefid.h>
#include <utility.h>

#include "sconti.h"             
#include "veini.h"
#include "vepriv.h"
#include "verig.h"
#include "veuml1.h"
#include "veini.h"
#include "sconti.h"

#include "velib07.h"

#include "../cg/cg2103.h"
#include "../db/dblib.h"             
#include "../mg/mglib.h"
#include "../db/dblib.h"

#include "../mg/anamag.h"
#include "../mg/codcorr.h"
#include "../mg/deslin.h"
#include "../mg/umart.h"
#include "../ca/calib01.h"
#include "../ca/commesse.h"



#define MAX_VIS_RATE 5

bool numdocrif_hndl( TMask_field& field, KEY key )
{
	if (key == K_ENTER)
	{
		TDocumento_mask& m = (TDocumento_mask&)field.mask();
		TString16 campo = DOC_NUMDOCRIF;
		if (field.field() != NULL)
			campo = field.field()->name();

		TRectype filtrec(LF_DOC);
		filtrec.put(DOC_TIPOCF, m.get(F_TIPOCF));
		filtrec.put(DOC_CODCF, m.get(F_CODCF));
		filtrec.put(DOC_PROVV, m.get(F_PROVV));
		filtrec.put(DOC_ANNO, m.get(F_ANNO));

		TRelation rel(LF_DOC);
		TString sortkey = "TIPOCF|CODCF|PROVV|ANNO|CODNUM|"; sortkey << campo;
		TSorted_cursor cur(&rel, sortkey, "", 2, &filtrec, &filtrec);
    TString16 f; f.format("CODNUM==\"%s\"", (const char*)m.get(F_CODNUM));

		cur.setfilter(f);

		filtrec.put(DOC_CODNUM, m.get(F_CODNUM));
		filtrec.put(campo, field.get());
		cur.curr() = filtrec;
		cur.read(_isequal);

		if (cur.file().status() == NOERR)
		{
			const long numdoc = m.get_long(F_NDOC);
			if (numdoc != cur.curr().get_long(DOC_NDOC))
				return yesno_box("Il numero di riferimento %s � gi� stato utilizzato\nsi desidera registrare ugualmente?",
													(const char *)field.get());
		}
	}
	return true;
}

bool totdoc_hndl( TMask_field& field, KEY key )
{
	if (key == K_ENTER)
	{
		TDocumento_mask & m = (TDocumento_mask &) field.mask();
		const real totdoc = m.doc().totale_doc();
		const real totdoc_check(field.get()); 
		
		
		if (m.doc().physical_rows() > 0 && totdoc != totdoc_check)
		{
			const TString16 tchk(totdoc_check.string());
			
			return yesno_box("Il totale documento digitato (%s) non corrisponde\nal totale documento (%s) calcolato,\n devo registrare ugualmente",
												(const char *) tchk, totdoc.string());
		}
	}
	return true;
}

bool smart_hndl( TMask_field& field, KEY key )

{
	if (key == K_SPACE)
	{
		TDocumento_mask & m = (TDocumento_mask &) field.mask();
		TSmart_card * s = m.smartcard();

		if (s != NULL)
		{
			smartcard_error err = s->connect_card();
			if (err == no_smarterror)
				err = s->check_key(m);
			if (err == no_smarterror)
			{
				s->card2mask(m);
				if (s->with_card(m))
					m.enable(DLG_SAVEREC);
				m.disable(F_CODCF);
				m.disable(F_RAGSOC);
			}
			else
			{
				s->display_error(err);
				if (err == new_card)
					if (m.get(F_CODCF).empty() && m.field(F_CODCF).on_key(K_F9) == false)
					{
						s->disconnect_card();
						return false;
					}
			}
		}
	}
	else
		if (key == K_ENTER)
		{
			TDocumento_mask & m = (TDocumento_mask &) field.mask();
			TSmart_card * s = m.smartcard();

			if (s != NULL && s->card_connected())
			{
				s->mask2card(m);
				smartcard_error err = s->write();
				if (err != no_smarterror)
					s->display_error(err);
				if (m.insert_mode() && m.doc().codice_numerazione().save_and_new())
					s->disconnect_card();
			}
		}

	return true;
}

bool fido_hndl(TMask_field& field, KEY key)
{
  if (key == K_ENTER && !field.empty())
  {
    TDocumento_mask & m = (TDocumento_mask &) field.mask();
    const real fido_bau(field.get());
    const char tipocf = m.get(F_TIPOCF)[0];
    const long codcf = m.get_long(F_CODCF);
    const TDate& datadoc = m.get_date(F_DATADOC);
    const int riskdays = ini_get_int(CONFIG_DITTA, "ve", "FIDO_RISKDAYS");
    const real perc_toll = ini_get_string(CONFIG_DITTA, "ve", "FIDO_PERCTOLL");
    //calcola l'esposizione PRIMA del documento corrente
    const real esposizione = calcola_fido_cliente (tipocf, codcf, datadoc, riskdays);
    //prende il valore del documento corrente
    const real totdoc = m.doc().totale_doc();
    //esposizione comprensiva del documento corrente
    const real esposizione_totale = esposizione + totdoc; 
    const real fido_con_tolleranza = fido_bau * (CENTO + perc_toll) / CENTO;

    if (esposizione_totale > fido_con_tolleranza)
      return yesno_box(FR("Attenzione! Il cliente %ld risulta fuori fido.\nEsposizione corrente: %s\n"
                          "Tot. Doc. corrente: %s\nEsposizione totale: %s\nRegistrare ugualmente il documento?"), 
                          codcf, esposizione.stringa(), totdoc.stringa(), esposizione_totale.stringa()); 
  }
  return true;
}

bool ora_hndl( TMask_field& field, KEY key )

{
	if (field.to_check(key,true))
	{
		TString16 ora;
		
		if (field.automagic() && field.get().empty())
		{
			struct tm* t = xvt_time_now();
			ora.format("%02d%02d", t->tm_hour, t->tm_min);
			field.set((ora));
		}
		else
		{
			ora = field.get();
			if (ora.not_empty())
			{
				if (!isdigit(ora[0]) ||	!isdigit(ora[1]) ||	!isdigit(ora[2]) ||
						!isdigit(ora[3]) ||	atoi(ora.left(2)) > 23 || atoi(ora.mid(2)) > 59)
					return error_box(TR("Ora errata"));
			}
			else
				 if (field.required())
					 return error_box(TR("Ora obbligatoria"));
		}
	}

	return true;
}

bool dummy_hndl(TMask_field& field, KEY key)
{
	warning_box(FR("Al campo %d � arrivato un KEY %d"), field.dlg( ), key );
	return true;
}

// Handler per il calcolo delle date di pagamento
bool condpag_hndl( TMask_field& field, KEY key )
{
	TDocumento_mask& m = (TDocumento_mask &) field.mask( );
	
	if ( field.to_check(key) || (key == K_TAB && !m.is_running()))
	{
		const TString& condpag = m.get(F_CODPAG);
		if (condpag.not_empty())
		{
			TDocumento& doc = m.doc();
			// Aggiorna dati necessari per determinare il pagamento
			doc.put(DOC_CODPAG, condpag);
			doc.put(DOC_DATADOC, m.get(F_DATADOC));
			doc.put(DOC_DATAINSC, m.get(F_DATAINSC));
			doc.put(DOC_TIPOCF, m.get(F_TIPOCF));
			doc.put(DOC_CODCF, m.get(F_CODCF));
			TPagamento& pag = doc.pagamento();		 
			pag.set_total(CENTO, real(10), real(10));
			pag.set_rate_auto();
			
			const int numrate = pag.n_rate( );
			for(int i = 0; i < MAX_VIS_RATE; i++)
			{
				if (i < numrate)
				{
					m.show(F_DATASCAD1+i);
					m.set(F_DATASCAD1+i, pag.data_rata(i));
				}
				else	
					m.hide(F_DATASCAD1+i);
			}
		}
	}
	return true;
}

bool note_hndl( TMask_field& f, KEY key )
{
	TDocumento_mask& m = (TDocumento_mask &) f.mask();

	if (key == K_TAB && (f.focusdirty() || !m.is_running()))
	{ 
		const TRectype& note = cache().get("%NOT", f.get());
		if (!note.empty())
		{
			if (m.is_running() || m.field(F_NOTECLI).empty()) // Preserva descrizione presente in caricamento
			{
				// gestione del campo con descrizione estesa
				TString stringone;
				for (int i = 0; i < 6; i++)
				{
					const char fieldname[3] = { 'S', i+'0', '\0' };
					stringone << note.get(fieldname);
				}
				stringone.replace(char(0xB6), '\n');
				m.set(F_NOTECLI, stringone);
			}

			if (m.doc().modificabile() && m.field(DLG_SAVEREC).enabled())
			{
				const bool reg_disabled = note.get_bool("B0");	
				if (reg_disabled)
				{
					message_box(FR("Registrazione disabilitata : %s"), (const char*)note.get("S0"));
					m.disable(DLG_SAVEREC);
				}
			}
		}


	}
	
	return true;

}

// Handler per il calcolo delle date di pagamento
bool data_hndl( TMask_field& field, KEY key )
{
	TDocumento_mask& m = (TDocumento_mask &) field.mask();
	if (field.to_check(key))
	{								
		if (m.id2pos(F_DATAINSC) >= 0)
		{
			TEdit_field & e = m.efield(F_DATAINSC);
			e.set_dirty();
			e.on_hit();
		}

		if (m.id2pos(F_DATACAMBIO1) >= 0 && !m.get(F_CODVAL).empty())
			m.set(F_DATACAMBIO1, field.get(), true);
	}
	if (key == K_ENTER || field.to_check(key))
	{
		const TDate datadoc(m.get(F_DATADOC));
		if (!datadoc.ok())
			return field.error_box("La data documento deve essere comunque indicata.");
			
    if (m.id2pos(F_DATACAMBIO1) >= 0 && !m.get(F_CODVAL).empty())
      m.set(F_DATACAMBIO1, field.get(), TRUE);
  }
  if (key == K_ENTER || field.to_check(key))
  {           
    const TDate datadoc(m.get(F_DATADOC));
    const int annodoc = m.get_int(F_ANNO);
    if (datadoc.year() != annodoc)
    {
      if (datadoc.ok())
        return field.error_box(TR("La data documento deve appartenere all'anno %d"), annodoc);
      else
        return field.error_box(TR("La data documento deve essere comunque indicata"));
    }
      
		const TCodice_numerazione codnum(m.get(F_CODNUM));
		if (codnum.test_eser())
		{
			if (esercizi().date2esc(datadoc) <= 0)
				return field.error_box("La data documento non appartiene ad un esercizio valido.");
			if (main_app().has_module(CGAUT))
			{
				const TTipo_documento& td = m.doc().tipo();
				TString4 codcaus = td.causale();
				if (codcaus.empty())
				{
					const TRectype& clifo = m.doc().clifor().vendite();
					codcaus = clifo.get("CODCAUS");
				}
				if (codcaus.not_empty())
				{
					const int year = datadoc.year();
					TCausale caus;
					if (!caus.read(codcaus, year))
						return error_box(TR("Causale assente!")); // L'errore viene segnalato nella read
				}
			}
		}
		if (codnum.dont_test_datadoc())
			return true;	// Non devo fare altri test

		TLocalisamfile doc(LF_DOC);

		doc.curr() = m.doc().head(); 
		bool same_key = false;

		doc.read(_isgteq);
		if (doc.eof() || doc.prev() == NOERR)
		{											 
      const TDate dataprev = doc.get_date(DOC_DATADOC);
			same_key = doc.curr().same_key(m.doc().head(), 1, 1);
			if (same_key && datadoc < dataprev)
				return field.error_box("Data documento inferiore alla data del documento precedente");
		} 
    
    doc.curr() = m.doc().head(); 
    doc.read(_isgreat);
    same_key = doc.curr().same_key(m.doc().head(), 1, 1);
    if (doc.good() && same_key && datadoc > doc.get_date(DOC_DATADOC))
      return field.error_box("Data documento superiore alla data del documento successivo"); 
	}
	return true;
}
	
// handler di campi delle maschere di riga
void TDocumento_mask::user_set_row_handler(TMask& rm, short field, int index)
{
	switch (index)
	{
	case 1:	rm.set_handler( field, pricerange_handler );	break;
	case 2:	rm.set_handler( field, dummy_hndl );	break;
  case 3:	
    if (field == FR_CODART)
			rm.set_handler( field, search_price_handler );
		break;
  case 4:
		if (field == FR_CODART)
			rm.set_handler( field, find_price_handler );
		break;
  case 5:
		if (field == FR_CODART)
			rm.set_handler( field, link_row_handler );
		break;
	case 6:	
		if (field == FR_CODART)
			rm.set_handler( field, evasion_check_handler );
		break;
	case 7: 
		if (field == FR_CODART)
			rm.set_handler(field, distinta_link_handler);
		break;
	case 8: 
			if (field >= FR_LIV1 && field <= FR_LIV4)
				rm.set_handler(field, gen_livelli_handler);
			break;
	default:
		break;
	}
}

HIDDEN TString4 curr_um;
HIDDEN real curr_fc = UNO;

bool iva_handler( TMask_field& f, KEY key )
{
	TDocumento_mask & mask = (TDocumento_mask &) f.mask().get_sheet()->mask();

	if (key == 0 || (key == K_ENTER && f.empty()))
	{
		const TString16 codiva = mask.condv().clifo().vendite().get(CFV_ASSFIS);
		if (codiva.not_empty())
			f.set(codiva);
		f.check();
	}

  if (key == 0 || (key == K_ENTER && f.empty()))
  {
    const TString4 codiva = mask.doc().codesiva();
    if (codiva.not_empty())
      f.set(codiva);
    f.check();
  }

  if (key == K_ENTER && /*f.focusdirty() &&*/ f.get().empty())
  {
    TMask & row_mask = f.mask();
    const int r = row_mask.get_sheet()->selected() + 1;
    const TRiga_documento& riga = mask.doc()[r];
    
    const int pos_ai = row_mask.id2pos(FR_ADDIVA);
    bool  addiva = false;
    
    if (pos_ai >= 0)
      addiva = row_mask.fld(pos_ai).get() == "X"; // Controlla le righe Omaggio solo se e' settato l'addebito IVA
    
    const bool check = riga.is_merce() || riga.is_spese() || riga.is_prestazione() || 
                       (riga.is_omaggio() && addiva);
    
    if (check)
    {
      const int pos_p = row_mask.id2pos(FR_PREZZO);
      const int pos_q = row_mask.id2pos(FR_QTA);
      const bool pe = pos_p >= 0 && row_mask.fld(pos_p).enabled();
      const bool qe = pos_q >= 0 && row_mask.fld(pos_q).enabled();
      const bool pf = pe && row_mask.fld(pos_p).get().not_empty();
      const bool qf = qe && row_mask.fld(pos_q).get().not_empty();
      const bool required = pf && !(qe && !qf);
      if (required)
        return f.error_box("Il codice IVA e' obbligatorio.");
    }
  }
  return true;
} 

bool dcons_handler( TMask_field& f, KEY key )
{
	if (key == K_F8)
	{
		TMask& row_mask = f.mask();
		TSheet_field& s = *row_mask.get_sheet();
		TDocumento_mask & mask = (TDocumento_mask &) s.mask();
		int r = f.mask().get_sheet()->selected() + 1;

		if (r > 1)
		{
			TDocumento & doc = mask.doc();
			const TRiga_documento& prev = doc[r - 1];
			TDate first_date = prev.get_date(RDOC_DATACONS);
			TDate second_date = row_mask.get_date(FR_DATACONS);

			if (!second_date.ok())
				second_date = mask.get_date(F_DATACONS);
			if (second_date.ok())
			{
				if (!first_date.ok())
					first_date = mask.get_date(F_DATACONS);
				if (first_date.ok())
				{
					if (second_date.is_end_month() && first_date.is_end_month())
					{
						int year = second_date.year();
						int month = second_date.month();
						const int months = ( year * 12 + month) - (first_date.year() * 12 + first_date.month());
						if (months > 0)
						{
							for (r++ ; r <= doc.physical_rows(); r++)
							{
								TRiga_documento & riga = doc[r];
								TToken_string & tr = s.row(r - 1);

								month += months;
								if (month > 12)
								{
									year++;
									month -= 12;
								}
								TDate d(1, month, year);

								d.set_end_month();
								riga.put(RDOC_DATACONS, d);
								tr.add(riga.get(RDOC_DATACONS), s.cid2index(FR_DATACONS));
							}
							s.force_update();
						}

					}
					else
						if (second_date.day() == first_date.day())
						{
							const int months = ( second_date.year() * 12 + second_date.month()) - (first_date.year() * 12 + first_date.month());
							if (months > 0)
							{
								for (r++ ; r <= doc.physical_rows(); r++)
								{
									TRiga_documento & riga = doc[r];
									TToken_string & tr = s.row(r - 1);

									second_date.addmonth(months);
									riga.put(RDOC_DATACONS, second_date);
									tr.add(riga.get(RDOC_DATACONS), s.cid2index(FR_DATACONS));
								}
								s.force_update();
							}
						}
						else
						{
							const int days = second_date - first_date;

							if (days > 0)
							{
								for (r++ ; r <= doc.physical_rows(); r++)
								{
									TRiga_documento & riga = doc[r];
									TToken_string & tr = s.row(r - 1);

									second_date += days;
									riga.put(RDOC_DATACONS, second_date);
									tr.add(riga.get(RDOC_DATACONS), s.cid2index(FR_DATACONS));
								}
								s.force_update();
							}
						}
				}
			}
		}
	}
	return true;
}

bool tipo_riga_handler(TMask_field& f, KEY key)
{
	if (key == K_SPACE && f.focusdirty())
	{
		TMask & row_mask = f.mask();		
		TVariable_sheet_field * sf = (TVariable_sheet_field *) row_mask.get_sheet();

		if (sf != NULL)
		{
			TDocumento_mask & docmask = (TDocumento_mask&)sf->mask();
			if (docmask.is_running())
			{
				const int curr_row = sf->selected();
				TToken_string & row = sf->row(curr_row);
				const int col = sf->cid2index(FR_TIPORIGA);
				const TString16 old_tipo_riga = row.get(col);
				const TString16 tipo_riga = f.get();

				if (!row_mask.is_running())
				{
					if (old_tipo_riga != tipo_riga)
					{
						row.add(tipo_riga, col);
						docmask.doc()[curr_row + 1].set_tipo(tipo_riga);
						TMask * rm = docmask.riga_mask(curr_row);
						sf->post_insert(curr_row);
						sf->check_row(curr_row);
						sf->force_update(curr_row);
					}
				}
				else
					if (old_tipo_riga != tipo_riga)
					{
						f.set(old_tipo_riga);
						return error_box("Impossibile cambiare il tipo nella maschera di riga");
					}
			}
		}
	}
	return true;

}


bool codmag_handler( TMask_field& f, KEY key )
{
//  if (f.to_check(key, true))
  if (key == K_TAB && f.focusdirty())
  {        
    TMask& row_mask = f.mask();    
    TSheet_field& sf = *row_mask.get_sheet();
    TDocumento_mask& docmask = (TDocumento_mask&)sf.mask();
    
    if (sf.column_enabled(sf.cid2index(FR_CODDEP)))
    {  
      const int pos = row_mask.id2pos(FR_CODDEP);
      const TString & val = f.get();
                                                                                  
      if (pos >= 0 && val.not_empty())                                                               
      {
        const TRectype& mag = cache().get("MAG", val);
        const bool active = mag.get_bool("B0");
        row_mask.fld(pos).enable(active);                              
        if (!active)
          row_mask.fld(pos).reset();                              
      }
    }


    if (f.get().empty() && docmask.doc().tipo().mov_mag())
      return f.error_box("Indicare il magazzino.");
    
    docmask.update_giacenza();
  }
  return true;
}             


bool codmag_coll_handler( TMask_field& f, KEY key )
{
  if (key == K_TAB && f.focusdirty())
  {        
    TMask& row_mask = f.mask();    
    TSheet_field& sf = *row_mask.get_sheet();
    
    if (sf.column_enabled( ((TSheet_field &)f).cid2index(FR_CODDEPC)))
    {  
      const int pos = row_mask.id2pos(FR_CODDEPC);
      const TString & val = f.get();
                                                                                  
      if (pos >= 0 && val.not_empty())                                                               
      {
        const TRectype& mag = cache().get("MAG", val);
        const bool active = mag.get_bool("B0");
        row_mask.fld(pos).enable(active);                              
        if (!active)
          row_mask.fld(pos).reset();                              
      }
    }
  }
  return true;
}  



void upd_colli_peso_tara(TMask& m, const TString & codart)
{
	// const real qta = m.get_real(FR_QTA) * curr_fc;	// curr_fc puo' non essere inizializzata e vale -1
	// Usando il metodo apposito di TArticolo non si sbaglia micca mai. 
	// Sarebbe bene sparare (come dice Luca) a curr_fc ovunque copaia
	TArticolo & articolo  = cached_article(codart);
	const real qta = articolo.convert_to_um(m.get_real(FR_QTA), NULL, m.get(FR_UMQTA));

	const real ppcollo = articolo.get_real(ANAMAG_PPCOLLO);
	
	real ncolli = ppcollo.is_zero() ? UNO : qta / ppcollo;
	ncolli.ceil(0);
	
	int pos = m.id2pos(FR_NCOLLI);
	if (pos >= 0)	
		if (ppcollo != ZERO)
			m.fld(pos).set(ncolli.string());
		else	
			m.fld(pos).reset();

	pos = m.id2pos(FR_TARA);
	if (pos >= 0)
	{
		const real tara = ncolli * articolo.get_real(ANAMAG_TARA);
		m.fld(pos).set(tara.string());
	}
	pos = m.id2pos(FR_PNETTO);
	if (pos >= 0)
	{
		const real peso = qta * articolo.get_real(ANAMAG_PESO);
		m.fld(pos).set(peso.string());
	}

}



bool pricerange_handler(TMask_field& f, KEY key )
{             
  if (key == K_TAB && f.focusdirty())
  {            
    TMask& row_mask = f.mask();   
    TSheet_field& sh = *row_mask.get_sheet();
    TDocumento_mask& mask = (TDocumento_mask &)sh.mask(); 
    
    if (mask.doc().tipo().controllo_prezzi())
    {
      const int current_doc_row = sh.selected() + 1;      
      TRiga_documento & riga = mask.doc()[current_doc_row];
      const real old_price = riga.get_real(RDOC_PREZZO);
      const real new_price = row_mask.get_real(FR_PREZZO);
      
      if (!old_price.is_zero())
      {
        const TTipo_riga_documento& tipo_riga = riga.tipo();
        const int incr = tipo_riga.incr_perc_prezzo();
        const int decr = tipo_riga.decr_perc_prezzo();
    
        if (incr == 0 && decr == 0)
        {
          if (old_price != new_price && !yesno_box("Il prezzo � variato, confermare"))
            return false;
        }
        else
        {
          real inf = old_price * (UNO - (decr/CENTO));
          if (inf > new_price && !yesno_box("Il prezzo � diminuito di pi� del %d%%, confermare", decr))
            return false;
          real sup = old_price * (UNO + (incr/CENTO));
          if (sup < new_price && !yesno_box("Il prezzo � aumentato di pi� del %d%%, confermare", incr))
            return false;
        }
      }                 
      riga.put(RDOC_PREZZO, new_price);
    }
  }
  
	return true;
}

static bool __in_handler = false;

static int sort_sheet(const TObject** a, const TObject** b)
{
	TToken_string * t1 = (TToken_string *) *a;
	TToken_string * t2 = (TToken_string *) *b;
	const char * a1 = t1->get(2);
	const char * a2 = t2->get(2);
	int cmp = strcmp(a1, a2);

	if (cmp == 0)
	{
		TDate d1(t1->get(1));
		TDate d2(t2->get(1));

		cmp = d2 - d1;
		if (cmp == 0)
			return t2->get_int(8) - t1->get_int(8);
	}
	return cmp;
}

// Classe indispensabile alla Sig.ra Firpo
class TPrice_sheet : public TArray_sheet
{
  TEdit_field& _fld;

protected:
  virtual bool get_ini_paragraph(const TEdit_field& f, TString& name) const;

  virtual void handler(WINDOW win, EVENT* ep);
  TEdit_field& field() { return _fld; }

public:
  TPrice_sheet(TEdit_field& f);
};

void TPrice_sheet::handler(WINDOW win, EVENT* ep) 
{                 
  if (ep->type == E_MOUSE_DOWN)
  {   
    switch (ep->v.mouse.button )
    {      
    case  1: 
      { 
        MENU_ITEM* menu = xvt_res_get_menu(BROWSE_BAR);
        if (menu)
        {         
					dictionary_translate_menu(menu);
          const PNT& p = ep->v.mouse.where;
          RCT cr; xvt_vobj_get_client_rect(win, &cr);
          XVT_POPUP_ALIGNMENT pa = XVT_POPUP_CENTER;
          if (p.h < cr.right / 3)
            pa = XVT_POPUP_LEFT_ALIGN;
          else
            if (p.h > 2 * cr.right / 3)
              pa = XVT_POPUP_RIGHT_ALIGN;
            
          xvt_menu_popup(menu->child, win, p, pa, NULL);
          xvt_res_free_menu_tree(menu);       
        }  
        return;
      }
      break;
    default:
      break;
    }  
  }                   
  else
  if (ep->type == E_COMMAND)
  {
    switch (ep->v.cmd.tag)
    {     
    case BROWSE_BAR + 1:
      save_columns_order(field());
			return;
    case BROWSE_BAR + 2:
      set_columns_order(NULL);
      return;
    case BROWSE_BAR + 3:
      fld(0).on_key(K_F11);
      return;
    default:
      break;  
    }
  }
  
  TArray_sheet::handler(win, ep);
}

bool TPrice_sheet::get_ini_paragraph(const TEdit_field& field, TString& parag) const
{
  const bool ok = TSheet::get_ini_paragraph(field, parag);
  if (ok) 
    parag << "_F80";
  return ok;
}

TPrice_sheet::TPrice_sheet(TEdit_field& f)
            : TArray_sheet(0, 3, -1, 16, TR("Ricerca Prezzi"), 
HR("Num.|Data@10|Codice articolo@20|Descrizione@40|Quantit�@15P|Prezzo@18P|Sconto@10|Numerazione@18|Tipo Documento@18"), 0, 1),
_fld(f)
{
  load_columns_order(_fld);
}

static void search_price(TEdit_field& f, KEY key )
{
	TMask& row_mask = f.mask();   
  TSheet_field& sh = *row_mask.get_sheet();
  TDocumento_mask& mask = (TDocumento_mask &)sh.mask();
	
  TPrice_sheet sheet(f);

	TString_array & el = sheet.rows_array();
	TRelation * rel = new TRelation(LF_DOC);
	TRectype from(rel->curr());
	TRectype to(rel->curr());
	TDate datadoc = mask.get_date(F_DATADOC);
	const long codcf = mask.get_long(F_CODCF);
	const long numdoc = mask.get_long(F_NDOC);
	const int last_anno = mask.get_int(F_ANNO);
	const int current_doc_row = sh.selected() + 1;
	const int first_anno = last_anno - ((TTipo_riga_documento&)mask.doc()[current_doc_row].tipo()).search_years();
	TToken_string nums(((TTipo_riga_documento&)mask.doc()[current_doc_row].tipo()).search_nums());
	const TString& tipocf = mask.get(F_TIPOCF);

	from.put(DOC_TIPOCF, tipocf);
	to.put(DOC_TIPOCF, tipocf);
	from.put(DOC_CODCF, codcf);
	to.put(DOC_CODCF, codcf);
	from.put(DOC_PROVV, "D");
	to.put(DOC_PROVV, "D");
	from.put(DOC_ANNO, first_anno);
	to.put(DOC_ANNO, last_anno);
	to.put(DOC_DATADOC, datadoc);

	if (nums.empty())
		nums =  mask.get(F_CODNUM);

	TString4 first_num(nums.get(0));
	TString4 last_num(first_num);;
	
  TString filter;
	filter << "((CODNUM==\"" << first_num << "\")";
	for (const char * s = nums.get(); s && *s; s = nums.get()) 
	{
		if (first_num > s)
			first_num = s;
		if (last_num < s)
			last_num = s;
		filter << "||(CODNUM==\"" << s << "\")";
	}
	filter << ")";

	TCursor cur(rel, filter, 2, &from, &to);
	const int items = cur.items();
	cur.freeze();
	TRecord_array r(LF_RIGHEDOC, RDOC_NRIGA);
	TRectype rec(LF_RIGHEDOC);

	for(cur = 0L; cur.pos() < items; ++cur)
	{
		const TDate data(cur.curr().get(DOC_DATADOC));
		const TString80	num(cache().get("%NUM", cur.curr().get(DOC_CODNUM), "S0"));
		const TString80	tipo(cache().get("%TIP", cur.curr().get(DOC_TIPODOC), "S0"));

		rec.zero();
		rec.put(RDOC_PROVV, cur.curr().get(DOC_PROVV));
		rec.put(RDOC_ANNO, cur.curr().get(DOC_ANNO));
		rec.put(RDOC_CODNUM, cur.curr().get(DOC_CODNUM));
		rec.put(RDOC_NDOC, cur.curr().get(DOC_NDOC));
		r.read(rec);

		int last_row = r.last_row();

		for (int i = r.first_row(); i <= last_row; i = r.succ_row(i))
		{
			const TRectype & rdoc = r.row(i);
			const TString & codart = rdoc.get(RDOC_CODART);

			if (codart.full())
			{
				TToken_string row;
				row.add(rdoc.get(RDOC_NDOC));
				row.add(data);
				row.add(codart);
 				row.add(rdoc.get(RDOC_DESCR));
				row.add(rdoc.get(RDOC_QTA));
				row.add(rdoc.get(RDOC_PREZZO));
				row.add(rdoc.get(RDOC_SCONTO));
				row.add(num);
				row.add(tipo);
				row.add(rdoc.get(RDOC_NRIGA));
				el.add(row);
			}
		}
	}
	el.TArray::sort(sort_sheet);

	const int max_rows = ((TTipo_riga_documento&)mask.doc()[current_doc_row].tipo()).max_rows_art();

	if (max_rows > 0)
	{
		const int items = el.items();
		TString80 last_cod;
		long last_doc = 0L;
		real last_price(ZERO);
		int count = 0;
		for (int i = 0 ; i < items; i++)
		{
			const TString & codart = el.row(i).get(2);
			long ndoc = el.row(i).get_long(0);
			real price(el.row(i).get(5));

			if (codart != last_cod)
			{
				last_cod = codart;
				last_doc = ndoc;
				last_price = price;
				count = 1;
			}
			else
			{
				if (ndoc == last_doc && price == last_price)
				{
					el.destroy(i);
				}
				else
				{
					last_doc = ndoc;
					last_price = price;
					count++;
					if (count > max_rows)
						el.destroy(i);
				}
			}
		}
		el.pack();
	}
	
	if (sheet.run() == K_ENTER)
	{              
		__in_handler = true;
    const TToken_string& selected = sheet.row(-1);

	  real prezzo; selected.get(5, prezzo);
		row_mask.set(FR_PREZZO, prezzo);
    TString80 str; selected.get(2, str);
		row_mask.set(FR_CODART, str, 3);
		row_mask.field(FR_CODART).set_dirty(false);
		row_mask.set(FR_PREZZO, prezzo);
		selected.get(6, str);
		row_mask.set(FR_SCONTO, str);
		__in_handler = false;
	}
}

class TPrice_article_sheet : public TBrowse_sheet
{
protected:
  virtual bool get_ini_paragraph(const TEdit_field& field, TString& parag) const;

public:
  TPrice_article_sheet(TCursor& cur, TEdit_field& f);
};

bool TPrice_article_sheet::get_ini_paragraph(const TEdit_field& field, TString& parag) const
{
  const bool ok = TSheet::get_ini_paragraph(field, parag);
  if (ok) 
    parag << "_F81";
  return ok;
}

TPrice_article_sheet::TPrice_article_sheet(TCursor& cur, TEdit_field& f)
:	TBrowse_sheet(&cur, HR("NDOC|33->DATADOC|PREZZO|QTA|SCONTO|-201->S0|-202->S0"),
								TR("Ricerca Prezzi"),
								HR("Num.|Data@10|Prezzo@18P|Quantit�@15P|Sconto@10|Numerazione@18|Tipo Documento@18"),
								0, f, TToken_string())
{ }


static void search_price_article(TEdit_field& f, KEY key )
{
	TMask& row_mask = f.mask();   
  TSheet_field& sh = *row_mask.get_sheet();
  TDocumento_mask& mask = (TDocumento_mask &)sh.mask();
	const int current_doc_row = sh.selected() + 1;      
	const TString80 codart(row_mask.get(FR_CODART));
	TDate datadoc = mask.get_date(F_DATADOC);
	const char tipocf = mask.get(F_TIPOCF)[0];
	const long codcf = mask.get_long(F_CODCF);

	TToken_string nums(((TTipo_riga_documento&)mask.doc()[current_doc_row].tipo()).search_nums());

	if (nums.blank())
		nums =  mask.get(F_CODNUM);

	TString4 first_num(nums.get(0));
	TString4 last_num(first_num);
	TString filter;
	
	filter << "(33->TIPOCF==\"" << tipocf << "\")&&(33->CODCF==\"" << codcf << "\")&&(ANSI(33->DATADOC)<=\"" << datadoc.string(ANSI) << "\")" << "&&((CODNUM==\"" << first_num << "\")";
	FOR_EACH_TOKEN(nums, s) 
	{
		if (first_num > s)
			first_num = s;
		if (last_num < s)
			last_num = s;
		filter << "||(CODNUM==\"" << s << "\")";
	}
	filter << ")";

	TRelation rel(LF_RIGHEDOC);
	TRectype from(rel.curr());
	TRectype to(rel.curr());
	rel.add(LF_DOC, "PROVV==PROVV|ANNO=ANNO|CODNUM==CODNUM|NDOC==NDOC");

	const int last_anno = mask.get_int(F_ANNO);
	const int first_anno = last_anno - ((TTipo_riga_documento&)mask.doc()[current_doc_row].tipo()).search_years();
	TString80 livello;
			
	for (int l = 0; l<4 ; l++)
		mask.doc().livelli().pack_grpcode(livello, row_mask.get(FR_LIV1 + l),l + 1);


	from.put(RDOC_CODART, codart);
	from.put(RDOC_LIVELLO, livello);
	from.put(RDOC_CODNUM, first_num);
	from.put(RDOC_ANNO, first_anno);
	from.put(RDOC_PROVV, 'D');
	to.put(RDOC_CODART, codart);
	to.put(RDOC_LIVELLO, livello);
	to.put(RDOC_CODNUM, last_num);
	to.put(RDOC_ANNO, last_anno);
	to.put(RDOC_PROVV, 'D');
	TSorted_cursor cur(&rel, "33->DATADOC-|CODNUM|NDOC-", filter, 5, &from, &to);
	cur.items();
	cur.freeze();
	cur.relation()->add("%NUM", "CODTAB==CODNUM", 1, 0, 201);
	cur.relation()->add("%TIP", "CODTAB==TIPODOC", 1, LF_DOC, 202);

	TPrice_article_sheet sheet(cur, f);
	sheet.add_string (FR_DESCR, 0, "", 38, 0, 50, "D", 30);
  sheet.set(FR_CODART, codart);
	sheet.set(FR_DESCR, cache().get(LF_ANAMAG, codart, "DESCR"));

	if (sheet.run() == K_ENTER)
	{              
		__in_handler = true;
		row_mask.set(FR_CODART, codart, 0x3);
		row_mask.field(FR_CODART).set_dirty(false);
		__in_handler = false;
    TToken_string& row = sheet.row(-1);
		const TString& prezzo = row.get(2);
		row_mask.set(FR_PREZZO, prezzo);
		const TString& sconto = row.get(4);
		row_mask.set(FR_SCONTO, sconto);
	}
}

bool search_price_handler(TMask_field& f, KEY key )
{
	TMask& row_mask = f.mask();   
	TSheet_field& sh = *row_mask.get_sheet();

	if (key == K_F8 && !sh.sheet_mask().is_running())
	{
    TEdit_field& ef = (TEdit_field&)f;
		const TString& codart = row_mask.get(FR_CODART);
		if (codart.blank())
			search_price(ef, key);
		else
			search_price_article(ef,key);
		return true;
	}
	else
		if ((key == K_TAB && f.focusdirty()))
		{
		  TDocumento_mask& mask = (TDocumento_mask &)sh.mask();

			const TCodice_articolo codart = row_mask.get(FR_CODART);

			if (!__in_handler && codart.full() && row_mask.get(FR_PREZZO).empty())
			{
				TDate datadoc = mask.get_date(F_DATADOC);
				const char tipocf = mask.get(F_TIPOCF)[0];
				const long codcf = mask.get_long(F_CODCF);
				const int current_doc_row = sh.selected() + 1;      
			
				TToken_string nums(((TTipo_riga_documento&)mask.doc()[current_doc_row].tipo()).search_nums());

				if (nums.empty())
					nums =  mask.get(F_CODNUM);

				TString4 first_num(nums.get(0));
				TString4 last_num(first_num);;
				
				TString form;
				form << "(33->TIPOCF==\"" << tipocf << "\")&&(33->CODCF==\"" << codcf << "\")&&(ANSI(33->DATADOC)<=\"" << datadoc.string(ANSI) << "\")" << "&&((CODNUM==\"" << first_num << "\")";
				for (const char * s = nums.get(); s && *s; s = nums.get()) 
				{
					if (first_num > s)
						first_num = s;
					if (last_num < s)
						last_num = s;
					form << "||(CODNUM==\"" << s << "\")";
				}
				form << ")";
  
				TRelation rel(LF_RIGHEDOC);
				TRectype from(rel.curr());
				TRectype to(rel.curr());
				rel.add(LF_DOC, "PROVV==PROVV|ANNO=ANNO|CODNUM==CODNUM|NDOC==NDOC");

				const int last_anno = mask.get_int(F_ANNO);
				const int first_anno = last_anno - ((TTipo_riga_documento&)mask.doc()[current_doc_row].tipo()).search_years();
				TString80 livello;
						
				for (int l = 0; l<4 ; l++)
					mask.doc().livelli().pack_grpcode(livello, row_mask.get(FR_LIV1 + l),l + 1);

				from.put(RDOC_CODART, codart);
				from.put(RDOC_LIVELLO, livello);
				from.put(RDOC_CODNUM, first_num);
				from.put(RDOC_ANNO, first_anno);
				from.put(RDOC_PROVV, "D");
				to.put(RDOC_CODART, codart);
				to.put(RDOC_LIVELLO, livello);
				to.put(RDOC_CODNUM, last_num);
				to.put(RDOC_ANNO, last_anno);
				to.put(RDOC_PROVV, "D");
				
				TSorted_cursor cur(&rel, "33->DATADOC-|CODNUM|NDOC-", "", 5, &from, &to);
				cur.setfilter(form, true);
				if (cur.items() > 0L)
				{
					cur = 0L;
					__in_handler = true;
					row_mask.set(FR_CODART, codart, 0x3);
					row_mask.field(FR_CODART).set_dirty(false);
					__in_handler = false;
					const TString& prezzo = cur.curr().get(RDOC_PREZZO);
					row_mask.set(FR_PREZZO, prezzo);
					const TString& sconto = cur.curr().get(RDOC_SCONTO);
					row_mask.set(FR_SCONTO, sconto);
				}
			}
		}
	return codart_handler( f, key);
}

bool find_price_handler(TMask_field& f, KEY key )
{
	TMask& row_mask = f.mask();   
	TSheet_field& sh = *row_mask.get_sheet();

	if (key == K_F8 && !sh.sheet_mask().is_running())
	{
    TEdit_field& ef = (TEdit_field&)f;
		const TString& codart = row_mask.get(FR_CODART);
		if (codart.empty())
			search_price(ef, key);
		else
			search_price_article(ef,key);
		return true;
	}
	return codart_handler( f, key);
}

///////////////////////////////////////////////////////////
// TCache_documenti
///////////////////////////////////////////////////////////
class TCache_documenti : public TRecord_cache
{
protected:
  virtual TObject* rec2obj(const TRectype& rec) const;

public:
  TDocumento& doc(const char* key);
  TCache_documenti();
  virtual ~TCache_documenti() { }
};

TCache_documenti::TCache_documenti()
               : TRecord_cache(LF_DOC, 1)
{ 
  test_file_changes();   // Tieni d'occhio le modifiche sul file
  set_items_limit(256);  // Standard
}        

TObject* TCache_documenti::rec2obj(const TRectype& curr) const
{
  return new TDocumento(curr);
}

TDocumento & TCache_documenti::doc(const char* key)
{
  return (TDocumento &)query(key);
}

TDocumento & cached_doc(const char* key)
{
	static TCache_documenti * _cache_docs = NULL;

	if (_cache_docs == NULL)
		_cache_docs = new TCache_documenti();
	return _cache_docs->doc(key);
}

class TLink_riga_documento : public TRiga_documento
{
protected:
 
  const TDocumento_mask * _mask;
	virtual const TString& get_str(const char* fieldname) const;

public:
	virtual const TDocumento & doc() const;
  void set_mask(const TDocumento_mask * m) { _mask = m;}
  virtual real qtaresidua() const;

  TLink_riga_documento(const TDocumento_mask * m = NULL, const char* tipo = NULL) : TRiga_documento(NULL, tipo), _mask(m){}
	
};

const TString& TLink_riga_documento::get_str(const char* fieldname) const
{
  if (strcmp(fieldname, "RESIDUO") == 0)
	{
		TString & value = get_tmp_string(80);

		value = qtaresidua().string();
		return value;
	}
  
  return TRiga_documento::get_str(fieldname);
}

const TDocumento & TLink_riga_documento::doc() const
{
	if (has_doc())
		return TRiga_documento::doc();
	TToken_string key;

	key.add(get_char(RDOC_PROVV));
	key.add(get_int(RDOC_ANNO));
	key.add(get(RDOC_CODNUM));
	key.add(get_long(RDOC_NDOC));
	return cached_doc(key);;
}

real TLink_riga_documento::qtaresidua() const
{
	real residuo = TRiga_documento::qtaresidua();
	TToken_string key, key_to_compare;
	const TDocumento_mask& m = (const TDocumento_mask &) *_mask;
	const TDocumento &doc = m.doc();
	const int rows = doc.physical_rows();
	const int current_doc_row = m.sfield(F_SHEET).selected() + 1;      

	key.add(get(RDOC_PROVV));
	key.add(get(RDOC_ANNO));
	key.add(get(RDOC_CODNUM));
	key.add(get(RDOC_NDOC));
	key.add(get(RDOC_IDRIGA));

	real * qta  = (real *) m.father_rows().objptr(key);

	if (qta != NULL)
		residuo -= *qta;
	for (int j = 1; j <= rows; j++)
	{
		if (j != current_doc_row)
		{
			const TRiga_documento & row = doc[j];

			key_to_compare.cut(0);
			key_to_compare.add(row.get(RDOC_DAPROVV));
			key_to_compare.add(row.get(RDOC_DAANNO));
			key_to_compare.add(row.get(RDOC_DACODNUM));
			key_to_compare.add(row.get(RDOC_DANDOC));
			key_to_compare.add(row.get(RDOC_DAIDRIGA));

			if (key == key_to_compare)
				residuo -= row.quantita();
		}
	}
	return residuo;
}

class TLink_article_sheet : public TBrowse_sheet
{
protected:
  virtual bool get_ini_paragraph(const TEdit_field& field, TString& parag) const;

public:
  TLink_article_sheet(TCursor& cur, TEdit_field& f);
};

bool TLink_article_sheet::get_ini_paragraph(const TEdit_field& field, TString& parag) const
{
  const bool ok = TSheet::get_ini_paragraph(field, parag);
  if (ok) 
    parag << "_F82";
  return ok;
}

TLink_article_sheet::TLink_article_sheet(TCursor& cur, TEdit_field& f)
:	TBrowse_sheet(&cur, "-201->S0|-202->S0|NDOC|33->DATADOC|QTA|QTAEVASA",
								TR("Ricerca Prezzi"),
								HR("Numerazione@18|Tipo Documento@18|Num.|Data@10|Quantit�@15P|Evaso@15P"),
								0, f, TToken_string())
{ }


bool link_row_handler(TMask_field& f, KEY key )
{
	TMask& row_mask = f.mask();   
	TSheet_field& sh = *row_mask.get_sheet();

	if (key == K_F8 && !sh.sheet_mask().is_running())
	{
		TDocumento_mask& mask = (TDocumento_mask &)sh.mask();
		TDocumento &doc = mask.doc();
		const int current_doc_row = sh.selected() + 1;      
		TRiga_documento & r = doc[current_doc_row];
		TTipo_riga_documento & tipo = (TTipo_riga_documento &) r.tipo();

		if ((tipo.search_active_docs().blank()) || (tipo.search_active_docs().find(doc.tipo().codice()) >= 0))
		{
			TEdit_field& ef = (TEdit_field&)f;
			const TString& codart = row_mask.get(FR_CODART);
			const bool select_clifo = tipo.select_clifo();

			if (codart.full() && r.get(RDOC_DACODNUM).empty())
			{
				TDate datadoc = mask.get_date(F_DATADOC);
				TToken_string nums(((TTipo_riga_documento&)r.tipo()).search_nums());
				const int sel = sh.selected();
				TToken_string & sh_row = sh.row(sel);
				const TString row_cod(sh_row.get(sh.cid2index(FR_CODART)));
				TString80 from_livello, to_livello;
				int len = 0;
						
				for (int l = 1; l <= doc.livelli().last_level() ; l++)
				{
					doc.livelli().pack_grpcode(from_livello, row_mask.get(FR_LIV1 + l - 1),l);
					len += doc.livelli().code_length(l);
				}
				to_livello = from_livello;

				if (doc.livelli().last_level() > 0 && to_livello.blank())
					to_livello.fill('{', len);
				if (row_cod.blank())
				{
					sh_row.add("", sh.cid2index(FR_CHECKED));
					sh_row.add(codart, sh.cid2index(FR_CODART));
					sh.check_row(sel);
				}
				r.autosave(sh);

				if (nums.blank())
					nums = mask.get(F_CODNUM);

				TString4 first_num(nums.get(0));
				TString4 last_num(first_num);
				TString filter;
				
				filter << "(RIGAEVASA!=\"X\")&&(CODART==\"" << codart << "\")&&((LIVELLO>=\""
							 << from_livello << "\")&&(LIVELLO<=\"" << to_livello << "\"))&&(ANSI(33->DATADOC)<=\"" << datadoc.string(ANSI) << "\")";
				if (nums.items() > 0)
				{
					const bool more_nums = (nums.items() > 1);
		  		bool add_or = false;

					filter<< "&&";
					if (more_nums)
						filter<< "(";
				FOR_EACH_TOKEN(nums, s) 
				{
					if (add_or)
						filter << "||";
					add_or = true;
					if (first_num > s)
						first_num = s;
					if (last_num < s)
						last_num = s;
					filter << "(CODNUM==\"" << s << "\")";
				}
				if (more_nums)
					filter << ")";
				}

				TRelation rel(LF_RIGHEDOC);
				TRectype from(rel.curr());
				TRectype to(rel.curr());
				
				rel.lfile().set_curr(new TLink_riga_documento(&mask));

				rel.add(LF_DOC, "PROVV==PROVV|ANNO=ANNO|CODNUM==CODNUM|NDOC==NDOC");

				const int last_anno = mask.get_int(F_ANNO);
				const int first_anno = last_anno - tipo.search_years();

				from.put(RDOC_CODART, codart);
				from.put(RDOC_LIVELLO, from_livello);
				from.put(RDOC_CODNUM, first_num);
				from.put(RDOC_ANNO, first_anno);
				from.put(RDOC_PROVV, 'D');
				to.put(RDOC_CODART, codart);
				to.put(RDOC_LIVELLO, to_livello);
				to.put(RDOC_CODNUM, last_num);
				to.put(RDOC_ANNO, last_anno);
				to.put(RDOC_PROVV, 'D');
				TSorted_cursor cur(&rel, "33->DATADOC|CODNUM|NDOC", filter, 5, &from, &to);
				cur.items();
				cur.freeze();
				cur.relation()->add("%NUM", "CODTAB==CODNUM", 1, 0, 201);
				cur.relation()->add("%TIP", "CODTAB==TIPODOC", 1, LF_DOC, 202);

				TLink_article_sheet sheet(cur, (TEdit_field&)f);
				sheet.add_string (FR_DESCR, 0, "", 38, 0, 50, "D", 30);
				sheet.set(FR_CODART, codart);
				sheet.set(FR_DESCR, cache().get(LF_ANAMAG, codart, "DESCR"));
				
				if (sheet.run() == K_ENTER)
				{              
					r.set_original_rdoc_key(cur.curr());
					const TRectype * orig_doc = r.find_original_doc(); // warning
					if (orig_doc != NULL)
					{
						TDocumento father_doc(*orig_doc);
						TLink_riga_documento & father_row = (TLink_riga_documento &) cur.curr();
						const TString16 livello = father_row.get(RDOC_LIVELLO);

						father_row.set_doc(&doc);
						r.put(RDOC_LIVELLO, livello);
						r.put(RDOC_QTA, father_row.qtaresidua());
						TToken_string flds = tipo.fields_to_update();

						FOR_EACH_TOKEN(flds, fld)
						{
							const TString & val = father_row.get(fld);

							r.put(fld, val);
						}
						r.autoload(sh);
						sh.force_update(sel);
					}
				}
			}
			return true;
		}
	}
	return codart_handler( f, key);
}

bool codart_handler(TMask_field& f, KEY key )
{
	TMask& row_mask = f.mask();
	TSheet_field& sh = *row_mask.get_sheet();
	TDocumento_mask& mask = (TDocumento_mask &)sh.mask();
	const int current_doc_row = sh.selected() + 1;

	if (f.to_check(key, true))
	{ 
		if (!f.empty())
			row_mask.enable(FR_LIV1);
		else
		{
			row_mask.reset(FR_LIV1);
			row_mask.disable(FR_LIV1);
		}		
		row_mask.field(FR_LIV1).on_hit();
	}
	
	if (key == K_TAB && (f.focusdirty() || row_mask.get(FR_CHECKED).empty()))
	{
		TCond_vendita & condv = mask.condv();

		condv.set_testa(&mask);
		condv.set_riga(&row_mask);

		TString80 codart = f.get();	 
		TRectype anamag = cache().get(LF_ANAMAG, codart);	// anamag puo' cambiare
		bool found = !anamag.empty();
		TString16 umcorr;
		
		if (found)
			row_mask.set(FR_CODARTMAG, codart, true);
		else
		{
			TLocalisamfile codalt(LF_CODCORR);

			codalt.setkey(2);
			codalt.put(CODCORR_CODARTALT, codart);
			if (codalt.read() == NOERR)
			{
				codart = codalt.get(CODCORR_CODART);
				anamag = cache().get(LF_ANAMAG, codart);
				found = !anamag.empty();
				if (found)
				{
          row_mask.set(FR_CODARTMAG, codart, true);
					umcorr = codalt.get(CODCORR_UM);

					const TString & liv1 = codalt.get(CODCORR_LIV1);

					if (liv1.full())
						row_mask.set(FR_LIV1, liv1);
					
					const TString & liv2 = codalt.get(CODCORR_LIV2);

					if (liv2.full())
						row_mask.set(FR_LIV2, liv2);

					const TString & liv3 = codalt.get(CODCORR_LIV3);

					if (liv3.full())
						row_mask.set(FR_LIV3, liv3);

					const TString & liv4 = codalt.get(CODCORR_LIV4);

					if (liv4.full())
						row_mask.set(FR_LIV4, liv4);
				}
			}
		}
		row_mask.set(FR_CHECKED, "X");

		TString desc;
    if (!found)
    {
			row_mask.set(FR_CODARTMAG, "", true);
      if (main_app().has_module(DBAUT))
      {
        const TRectype& dist = cache().get(LF_DIST, codart);
        if (!dist.empty())
        {
          desc = dist.get("DESCR");
          umcorr = dist.get("UM");
        }
      }
    }
		else
		{
			const TString4 lingua = mask.get(F_CODLIN);
			const TCodice_articolo codart = row_mask.get(FR_CODARTMAG);
      desc = anamag.get(ANAMAG_DESCR);

			if (mask.doc()[current_doc_row].is_omaggio())	
			{
				static TString* dicitura_omaggio = NULL;
				if (dicitura_omaggio == NULL)
				{
					TConfig c(CONFIG_STUDIO, "ve");
					dicitura_omaggio = new TString(c.get("DESOMAGGI"));
					if (dicitura_omaggio->blank())
						*dicitura_omaggio = TR("(OMAGGIO)");
				}
				desc << ' ' << *dicitura_omaggio;
			}
			if (lingua.not_empty())
			{
				TLocalisamfile deslin(LF_DESLIN);


				deslin.setkey(2);
				deslin.put(DESLIN_CODART, codart);
				deslin.put(DESLIN_CODLIN, lingua);
				if (deslin.read() == NOERR)
				{
					static int __lingua_only = 3;
				
					if (__lingua_only > 2)
					{
						TConfig c(CONFIG_DITTA, "ve");
						__lingua_only = c.get_bool("LINGUA_ONLY");
					}
					if (__lingua_only)
						desc = deslin.get(DESLIN_DESCR);
					else
						desc << '\n' << deslin.get(DESLIN_DESCR);
				}
			}

			const TString& descest = anamag.get("DESCRAGG");
			if (descest.not_empty())
				desc << "\n" << descest;

      if (!mask.doc()[current_doc_row].tipo().no_desc())  
			  row_mask.set(FR_DESCR, desc);

			TString80 key; key << codart << "|1";
			const TRectype& umart = cache().get(LF_UMART, key);
			if (!umart.empty())
			{
				curr_um = umart.get(UMART_UM);
				curr_fc = umart.get_real(UMART_FC);
			}
			else
			{
				curr_um.cut(0);
				curr_fc = 1.0;
			}
			row_mask.set(FR_UMQTA, curr_um);
			upd_colli_peso_tara(row_mask, codart);
		}

    condv.ricerca();
		if (mask.doc().tipo().calcolo_lordo())
	    mask.doc()[current_doc_row].put(RDOC_PREZZOL, row_mask.get(FR_PREZZO));  
		else
	    mask.doc()[current_doc_row].put(RDOC_PREZZO, row_mask.get(FR_PREZZO));
	    
		const int pos = row_mask.id2pos(FR_CODIVA);

		if (pos >= 0)
			iva_handler(row_mask.fld(pos), 0);

		if (found)
		{
			TString16 caus(row_mask.get(FR_CAUS));
				
			if (caus.empty())
				caus = mask.get(F_CAUSMAG);


			if (caus.not_empty())
			{
				const TCausale_magazzino & c = cached_causale_magazzino(caus);


				if (!c.movimenta_sospesi())
				{
					const TRectype & rec = cache().get(LF_ANAMAG, row_mask.get(FR_CODARTMAG));


					if (rec.get_bool("SOSPESO")) 
						return error_box(TR("Articolo %s sospeso, quindi non movimentabile"), (const char *)codart);
				}
			}
		}
	}
	else
		if (key == K_F8 && !sh.sheet_mask().is_running())
		{
			static int explode_db = 3;
			static bool valcomp = false;
			static bool matbase = true;		
			static TExplosion_grouping raggart = RAGGR_EXP_NONE;
			static bool elrorig = false;
			static int livello = 1;
			static int ordin = 0;
			
			if (explode_db > 2)
			{
				TConfig d(CONFIG_DITTA, "ve");
																	 
				explode_db = d.get_bool("EXPLODEDB", "ve");
				valcomp = d.get_bool("VALCOMP", "ve");
				matbase = d.get_bool("TIPOESPL", "ve");
				raggart = (TExplosion_grouping) d.get_int("RAGGART", "ve");
				livello = d.get_int("LIVESPL", "ve");
				elrorig = d.get_bool("ELRORIG", "ve");
				ordin = d.get_int("ORDDB", "ve");
			}
			if (explode_db && !sh.sheet_mask().is_running())
			{
				TDocumento & doc = mask.doc();
				TRiga_documento & curr_row = doc[current_doc_row];	

				sh.update_row(current_doc_row - 1);
				curr_row.autosave(sh);

				TDistinta_tree db;
				TArray components;

				db.set_root(curr_row);

				const int items = db.explode(components, matbase, raggart, livello, "A", ordin);
				if (items > 0)
				{ 
					TProgind pi(items, "Esplosione in corso...",false, true);
					int row = current_doc_row;
					const TString16 tiporiga(curr_row.tipo().codice());

					TString_array& str_arr = sh.rows_array();

					for (int i = components.first(); i < items; i = components.succ(i))
					{
						pi.addstatus(1L);
						TRiga_esplosione & r = (TRiga_esplosione &) components[i];
						TRiga_documento & new_row = doc.insert_row(row + 1, tiporiga);
						//sh.insert(row, false);								 
						str_arr.insert(new TToken_string, row);
						
						TDocumento::copy_data(new_row, curr_row);
						new_row.put(RDOC_CODART, r.articolo());
						new_row.put(RDOC_CODARTMAG, r.articolo());
						new_row.put(RDOC_LIVELLO, r.giacenza());
						new_row.zero(RDOC_DESCR);
						new_row.zero(RDOC_DESCLUNGA);
						new_row.zero(RDOC_DESCEST);
						new_row.put(RDOC_CHECKED, "");
						new_row.put(RDOC_UMQTA, r.um());
						new_row.put(RDOC_GENERATA, "X");
						new_row.put(RDOC_QTA, r.val() /* * qta_fin */);
						new_row.autoload(sh);
						sh.check_row(row);
						new_row.autosave(sh);				// Da sheet a rdoc
						if (!valcomp)
						{
							new_row.zero(RDOC_PREZZO);
							// new_row.autoload(sh);			// Da rdoc a shee
							sh.row(row).add("0", FR_PREZZO-FIRST_FIELD);
							row_mask.reset(FR_PREZZO);
						}
						row++;
					}
					if (elrorig)
					{
						doc.destroy_row(current_doc_row, true);
						sh.destroy(current_doc_row - 1, false);
						row--;
					}
					else
						if (valcomp)
						{
							curr_row.zero(RDOC_PREZZO);
							curr_row.autoload(sh);
						}
					sh.force_update();
					sh.select(row-1);
				}
			}
        mask.update_giacenza();
		}

	return true;
}


bool codartmag_handler( TMask_field& f, KEY key )
{
	TMask & m = f.mask(); 
	TSheet_field& s = *m.get_sheet();
	TDocumento_mask& mask= (TDocumento_mask&)s.mask();
 
	bool to_check = key == K_TAB && f.focusdirty();
	if (!to_check)
		to_check = !mask.is_running();

	if (to_check)
	{
		const TString& codart = f.get();
		const bool artmag = codart.not_empty();

		m.show(FR_UMQTA, artmag);
		m.show(FR_UMQTA2, !artmag);

		mask.update_giacenza();
	}
	return true;

}

bool liv_handler( TMask_field& f, KEY key )
{
	bool ok = true;
	TDocumento_mask & mask=(TDocumento_mask &) f.mask().get_sheet()->mask();

	if (key == K_TAB && f.focusdirty() && !f.get().empty()) 
	{
		const int levnum=f.dlg()-FR_LIV1+1;
		// Se e' abilitato l'autoinserimento del livello di giacenza...
		if (mask.livelli().autoinsert(levnum))
			mask.livelli().autoinsert(levnum, f);
	}

	if (f.to_check(key, true))
	{
		if (f.dlg() < FR_LIV4)
		{
			TMask& row_mask = f.mask();	 
			TMask_field & next = row_mask.field(f.dlg() + 1);
			if (f.get().not_empty())
				next.enable();
			else
			{
				next.reset();
				next.disable();
			}
			next.on_hit(); 
		}
		TDocumento_mask& mask=(TDocumento_mask&)f.mask().get_sheet()->mask();
		mask.update_giacenza();
	}
	return ok;
}


void set_curr_um(const TString & um)
{
	curr_um = um;
	curr_fc = -1.0;
}

bool umart_handler( TMask_field& f, KEY key )
{
  TMask& row_mask = f.mask( );               
  TSheet_field& sh = *row_mask.get_sheet();
  TDocumento_mask & mask = (TDocumento_mask &)sh.mask();
  // Se qualcuno cerca di modificare la maschera
  if ( key == K_TAB && f.focusdirty() && mask.is_running())
  { 
    const int current_doc_row = sh.selected() + 1;      

    TCond_vendita & condv = mask.condv();
    condv.set_riga(&row_mask);

    const TString& um = f.get();
    real fc(1.0);
    
    if (um.not_empty() && curr_um.not_empty() && um != curr_um)
    {           
      TLocalisamfile umart(LF_UMART);
      umart.setkey(2);                               
      umart.put(UMART_CODART, row_mask.get(FR_CODARTMAG));
      umart.put(UMART_UM, um);
      if (umart.read() == NOERR)
      {
        real qta(row_mask.get_real(FR_QTA));
        fc = umart.get_real(UMART_FC);
        if (curr_fc < ZERO)
        {
          umart.put(UMART_CODART, row_mask.get(FR_CODARTMAG));
          umart.put(UMART_UM, curr_um);
          if (umart.read() == NOERR)
            curr_fc = umart.get_real(UMART_FC);
          else
            curr_fc = 1.0;
        }
        qta *= curr_fc;          
        qta /= fc;
        qta.round(5);
        row_mask.set(FR_QTA, qta);
        qta = row_mask.get_real(FR_QTAEVASA);
        qta *= curr_fc;          
        qta /= fc;
        qta.round(5);
        row_mask.set(FR_QTAEVASA, qta);
      }
    }
    curr_um = um;
    curr_fc = fc;
    condv.ricerca(true);
		if (mask.doc().tipo().calcolo_lordo())
	    mask.doc()[current_doc_row].put(RDOC_PREZZOL, row_mask.get(FR_PREZZO));  
		else
	    mask.doc()[current_doc_row].put(RDOC_PREZZO, row_mask.get(FR_PREZZO));  

    const int pos = row_mask.id2pos(FR_CODIVA);

    if (pos >= 0)
      iva_handler(row_mask.fld(pos), 0);
  }   
  return true;
}

bool um_handler( TMask_field& f, KEY key )
{
	// Se qualcuno cerca di modificare la maschera
	if ( key == K_TAB && f.focusdirty())
	{ 
		TMask& row_mask = f.mask( ); 
		TTable & ums	= (TTable &) ((TEdit_field &) f).browse()->cursor()->file();

		const TString16 um(f.get());
		real fc(1.0);

		if (um.not_empty() && curr_um.not_empty() && um != curr_um)
		{
			ums.put("CODTAB", curr_um);
			if (ums.read() == NOERR)
			{
				real qta(row_mask.get_real(FR_QTA));
				const TString16 umsrif0(ums.get("S7"));
				const real fc0 = ums.get_real("R10");
				if (um == umsrif0)
					fc = fc0;
				else
				{
					ums.put("CODTAB", um);
					if (ums.read() == NOERR)
					{
						const real fc1 = ums.get_real("R10");
						const TString16 umsrif1(ums.get("S7"));

						if (fc1 > ZERO)
						{
							if (curr_um == umsrif1)
								 fc = 1 / fc1;
							else
								 if (umsrif0 == ums.get("S7"))
									 fc = fc0 / ums.get_real("R10");
						}
					}
				}
				qta *= fc;
				qta.round(5);
				row_mask.set(FR_QTA, qta);
				qta = row_mask.get_real(FR_QTAEVASA);
				qta *= fc;
				qta.round(5);
				row_mask.set(FR_QTAEVASA, qta);
			}
		}
		curr_um = um;
		curr_fc = fc;
	}
	return true;
}

bool descr_handler( TMask_field& f, KEY key )
{
	if (key == K_TAB && f.focusdirty())
	{
		const TString s(f.get());
		if (s.find('\n') < 0)
		{
			TLocalisamfile & anamag = (TLocalisamfile &) ((TEdit_field &) f).browse()->cursor()->file();

			if (f.get() == anamag.get(ANAMAG_DESCR))
				f.mask().set(FR_CODART, anamag.get(ANAMAG_CODART), 3);
		}
	}
	return true;
}

bool qtaart_handler( TMask_field& f, KEY key )
{
	// Se qualcuno cerca di modificare la maschera
	if ( key == K_TAB && f.focusdirty())
	{ 
		TMask& row_mask = f.mask();
		TSheet_field& sh = *row_mask.get_sheet();
		TDocumento_mask& mask = (TDocumento_mask&) sh.mask();
		const int current_doc_row = sh.selected() + 1;
		TCond_vendita & condv = mask.condv();

    condv.set_riga(&row_mask);
		condv.ricerca(false, true);
		if (mask.doc().tipo().calcolo_lordo())
	    mask.doc()[current_doc_row].put(RDOC_PREZZOL, row_mask.get(FR_PREZZO));  
		else
	    mask.doc()[current_doc_row].put(RDOC_PREZZO, row_mask.get(FR_PREZZO));  
		const TString& codart = row_mask.get(FR_CODARTMAG);

		if (codart.not_empty())
			upd_colli_peso_tara(row_mask, codart);

	} //if(key==K_TAB
	else
		if (key == K_ENTER && f.dirty())
		{
			TDocumento_mask& mask=(TDocumento_mask&)f.mask().get_sheet()->mask();
			TDocumento & doc = mask.doc();

			if ((doc.tipo().check_giac() || doc.tipo().check_disp()) &&
					main_app().has_module(MGAUT, CHK_DONGLE) && doc.tipo().mov_mag())
			{
				TSheet_field& sf = mask.sfield(F_SHEET);
				TToken_string& row = sf.row(sf.selected());			 
				const TString codart = row.get(sf.cid2index(FR_CODARTMAG));

				if (codart.not_empty())
				{
					TString16 codmag = row.get(sf.cid2index(FR_CODMAG));
					const TString16 coddep = row.get(sf.cid2index(FR_CODDEP));
					if (!coddep.blank())
						codmag << coddep;

					TString16 livello;
					for (int i = 0; i < 4; i++)
					{
						const char* liv = row.get(sf.cid2index(FR_LIV1+i));
						if (*liv > ' ')
							livello << liv;
						else
							break;
					}

					real qta(row.get(sf.cid2index(FR_QTA)));
					const TString16 caus(mask.get(F_CAUSMAG));
					TCausale_magazzino & c = cached_causale_magazzino(caus);
					const long nmovmag = doc.get_long(DOC_MOVMAG);

					if (nmovmag != 0)
					{
						TLocalisamfile rmovmag(LF_RMOVMAG);
						
						rmovmag.setkey(2);
						rmovmag.put(RMOVMAG_CODART, codart);
						rmovmag.put(RMOVMAG_LIVGIAC, livello);
						rmovmag.put(RMOVMAG_CODMAG, codmag);
						rmovmag.put(RMOVMAG_NUMREG, nmovmag);
						if (rmovmag.read() == NOERR)
							qta -= rmovmag.get_real(RMOVMAG_QUANT);
					}
					if (doc.tipo().check_giac())
					{
						real giac(mask.get(F_CURGIAC));

                        if (giac < -(c.sgn(s_giac) * qta) && !yesno_box("Attenzione giacenza negativa, Devo continuare ?"))
							return false;
					}
					else
						if (doc.tipo().check_disp())		 
						{
							real disp(mask.get(F_CURDISP));

                            if (disp < -(c.sgn(s_giac) * qta) && !yesno_box("Attenzione disponibilita' negativa, Devo continuare ?"))
								return false;
						}
				}
			}
		}
		return qta_handler(f, key);
}

bool qta_handler( TMask_field& f, KEY key )
{
	// Se qualcuno cerca di modificare la maschera
	if ( key == K_TAB && f.focusdirty())
	{ 
		TMask& row_mask = f.mask( );
		const real qta_evasa = row_mask.get_real(FR_QTAEVASA);
		const real qta(f.get());

		if (qta_evasa > 0 && qta_evasa >= qta)
		{
			row_mask.set(FR_RIGAEVASA, "X");
			row_mask.disable(FR_RIGAEVASA);
		}
		else
			row_mask.enable(FR_RIGAEVASA);
	} 

	return true;
}

bool qta_evasa_handler( TMask_field& f, KEY key )
{
	TMask& row_mask = f.mask( );
	if (f.to_check(key) || (key == K_TAB && !row_mask.is_running()))
	{
		const real qta_evasa(f.get());
		const real qta = row_mask.get_real(FR_QTA);

		bool enable_evasa = true;
		if (qta_evasa > 0 && qta_evasa >= qta)
		{
			row_mask.set(FR_RIGAEVASA, "X");
			enable_evasa = false;
		}
		row_mask.enable(FR_RIGAEVASA, enable_evasa);
		if (!row_mask.is_running())
		{
			TSheet_field* sheet = row_mask.get_sheet();
			const int riga = sheet->selected();
			sheet->enable_cell(riga, sheet->cid2index(FR_RIGAEVASA), enable_evasa);
		}
	} 
	return true;
}

bool causmag_handler( TMask_field& f, KEY key )
{
  if (f.to_check(key))
  {
    TMask& row_mask = f.mask( );               
    TDocumento_mask& mask = (TDocumento_mask &) row_mask.get_sheet()->mask();
    TString8 causmag(f.get());

		if (causmag.blank())
      causmag = mask.get(F_CAUSMAG);
    if (causmag.full())
    {
			TCausale_magazzino & c = cached_causale_magazzino(causmag);

			if (c.has_default_mag() && row_mask.get(FR_CODMAG).empty())
      {
        row_mask.set(FR_CODMAG, c.default_mag(), true);
        row_mask.set(FR_CODDEP, "", true);
      }
      if (c.has_default_dep() && row_mask.get(FR_CODDEP).empty())
        row_mask.set(FR_CODDEP, c.default_dep(), true);  
        
      if (c.caus_collegata().full())
      {
        c = cache().get("%CAU", c.caus_collegata());
        if (c.has_default_mag() && row_mask.get(FR_CODMAGC).empty())
        {
          row_mask.set(FR_CODMAGC, c.default_mag(), true);
          row_mask.set(FR_CODDEPC, "", true);
        }
        if (c.has_default_dep() && row_mask.get(FR_CODDEPC).empty())
          row_mask.set(FR_CODDEPC, c.default_dep(), true); 
          
        static int copy_defmagc = -883;
        if (copy_defmagc < 0)
        {     
          TFilename fname; mask.doc().tipo().profile_name(fname); 
          TConfig c_tipo_documento(fname,"MAIN");
          copy_defmagc = c_tipo_documento.get_bool("DEFMAGXCOLL");
        }
        if (copy_defmagc!=0)
        {
          if (row_mask.get(FR_CODMAGC).empty())       
            row_mask.set(FR_CODMAGC, mask.stdmag(), true);
          if (row_mask.get(FR_CODDEPC).empty())
            row_mask.set(FR_CODDEPC, mask.stddep(), true);
        }
      }
      if (!c.movimenta_sospesi())
      { 
        const TRectype & rec = cache().get(LF_ANAMAG, row_mask.get(FR_CODARTMAG));
            
        if (rec.get_bool("SOSPESO")) 
          return error_box("Articolo %s sospeso, quindi non movimentabile", (const char *)rec.get(ANAMAG_CODART));
      }
    }
  } 
  return true;
}
	 
bool sppr_handler( TMask_field& f, KEY key )
{ 
	TMask& row_mask = f.mask();
	
	if (key == K_TAB && (f.focusdirty() || row_mask.get(FR_DESCR).empty()))
	{
		const TRectype& curr = ((TEdit_field&)f).browse()->cursor()->curr();
		const TSpesa_prest sp(curr);
	
    const int pos = row_mask.id2pos(FR_PREZZO);
		if (pos >= 0 && !sp.empty())
		{
      const char tipo = sp.tipo();
			const bool qta_val_fl = tipo == 'Q';
			const bool perc_fl = tipo == 'P';
			int pos = row_mask.id2pos(FR_UMQTASP);

			if (pos >= 0)
				row_mask.fld(pos).enable(!perc_fl);
			pos = row_mask.id2pos(FR_PREZZO);
			if (pos >= 0)
				row_mask.fld(pos).enable(!perc_fl);
			pos = row_mask.id2pos(FR_SCONTO);
			if (pos >= 0)
				row_mask.fld(pos).enable(!perc_fl);
			pos = row_mask.id2pos(FR_QTA);
			if (pos >= 0)
			{
				row_mask.fld(pos).show(!perc_fl);
				row_mask.fld(pos).enable(qta_val_fl);
			}
			pos = row_mask.id2pos(FR_PERCSP);
			if (pos >= 0)
			{
				row_mask.fld(pos).show(perc_fl);
				row_mask.fld(pos).enable(perc_fl);
			}
			if (!perc_fl)
			{
        const TDocumento_mask& mask = (const TDocumento_mask&)row_mask.get_sheet()->mask();
				const real cambio = mask.get_real(F_CAMBIO);
				real prezzo = sp.prezzo();
				const TString& doc_valuta = mask.get(F_CODVAL);
				const bool controeuro = mask.get_bool(F_CONTROEURO);

				sppr_calc(sp, doc_valuta, cambio, prezzo, controeuro ?	_exchange_contro : _exchange_base);
					if (mask.doc().tipo().calcolo_lordo())
						prezzo = TRiga_documento::iva(sp.cod_iva()).lordo(prezzo, ALL_DECIMALS);
				row_mask.set(FR_PREZZO, prezzo);					
			}
		}

    const int posiva = row_mask.id2pos(FR_CODIVA);
		if (posiva >= 0)
			iva_handler(row_mask.fld(posiva), 0);

		if (row_mask.id2pos(FR_CDC1) >= 0)
		{
			const TString80 cdc(sp.cdc());
			const TString80 cms(sp.cms());
			const TString80 fase(sp.fase());

			for (short i = FR_CDC1; i <= FR_CDC12; i++)
			{
				const int pos = row_mask.id2pos(i);
				if (pos >=0)
				{
					TEdit_field& e = (TEdit_field&)row_mask.fld(pos);
					const TFieldref& fr = *e.field();

					if (fr.name() == RDOC_CODCOSTO)
						e.set(cdc.sub(fr.from(), fr.to()));
					else
						if (fr.name() == RDOC_CODCMS)
							e.set(cms.sub(fr.from(), fr.to()));
						else
							if (fr.name() == RDOC_FASCMS)
								e.set(fase.sub(fr.from(), fr.to()));
				}
			}					
		}
	} 
	return true;
}

static TString __header("883");
static TString __fieldlist;

bool TDocumento_mask::numdocrif_search_handler(TMask_field& f, KEY key)
{
	if (key == K_F9)
	{
		TMask& m = f.mask();

		TRectype filtrec(LF_DOC);

		filtrec.put(DOC_TIPOCF, m.get(F_TIPOCF));
		filtrec.put(DOC_CODCF, m.get(F_CODCF));

		const long codcf = atol(m.get(F_CODCF));

		if (codcf != 0)
			filtrec.put(DOC_TIPOCF, m.get(F_TIPOCF));

		TRelation rel(LF_DOC);
		rel.add(LF_CLIFO, "TIPOCF==TIPOCF|CODCF==CODCF");
		rel.add(LF_RIGHEDOC, "PROVV==PROVV|ANNO==ANNO|CODNUM==CODNUM|NDOC==NDOC|NRIGA==1");

		TSorted_cursor cur(&rel, "TIPOCF|CODCF|PROVV|ANNO|CODNUM|NUMDOCRIF", "", 2, &filtrec, &filtrec);
    TString80 filter; 
    filter.format("(CODNUM==\"%s\") && (PROVV==\"D\") && (ANNO==\"%d\")",
									(const char *)m.get(F_CODNUM), m.get_int(F_ANNO));
    cur.setfilter(filter);
		TToken_string siblings;
 		TToken_string header(HR("Codice|Ragione Sociale@50|Docum.Rif.|Data@10|Docum.Rif. 1|Docum.Rif. 2|Docum.Rif. 3|Documento|Data\nDocumento@10|Totale\nDocumento@18V|Valuta"));
		TToken_string fieldlist("CODCF|20->RAGSOC|NUMDOCRIF|DATADOCRIF|DOC1|DOC2|DOC3|NDOC|DATADOC|G1:TOTDOC|CODVAL");
			
		if (__header == "883")
		{
			TFilename name(m.source_file());

			name.ext("ini");
			TConfig c(name, "Search");

			__header = c.get("Header");
			__fieldlist = c.get("FieldList");
		}
		fieldlist << __fieldlist;
		header << __header;
    
		TBrowse_sheet sheet(&cur, fieldlist,
                        TR("Documento di riferimento"),
												header, 
                        0, (TEdit_field&)f, siblings);
		if (sheet.run() == K_ENTER)
		{
      const long ndoc = sheet.row(-1).get_long(7);
			m.set(F_NDOC, ndoc);
			m.stop_run(K_AUTO_ENTER);
		}
	}
	return true;
}

bool TDocumento_mask::ragsoc_search_handler(TMask_field& f, KEY key)
{
	if (key == K_F9)
	{
		TMask& m = f.mask();

		TRectype filtrec(LF_DOC);

		filtrec.put(DOC_CODNUM, m.get(F_CODNUM));
		filtrec.put(DOC_PROVV, m.get(F_PROVV));
		filtrec.put(DOC_ANNO, m.get(F_ANNO));

		TRelation rel(LF_DOC);
    rel.add(LF_CLIFO, "TIPOCF==TIPOCF|CODCF==CODCF");
		TSorted_cursor cur(&rel, "TIPOCF|UPPER(20->RAGSOC)|PROVV|ANNO|CODNUM|PROVV|NDOC", "", 1, &filtrec, &filtrec);
    TString16 filter; filter.format("CODNUM==\"%s\"", (const char*)m.get(F_CODNUM));

    cur.setfilter(filter, true);
		TToken_string siblings;
		TToken_string header(HR("Ragione Sociale@50|Codice|Documento|Data\nDocumento@10|Totale\nDocumento@18V|Valuta|Partita IVA"));
		TToken_string fieldlist("20->RAGSOC|CODCF|NDOC|DATADOC|G1:TOTDOC|CODVAL|20->PAIV");
			
		if (__header == "883")
		{
			TFilename name(m.source_file());

			name.ext("ini");
			TConfig c(name, "Search");

			__header = c.get("Header");
			__fieldlist = c.get("FieldList");
		}
		fieldlist << __fieldlist;
		header << __header;

    TBrowse_sheet sheet(&cur, fieldlist,
                        TR("Ragione Sociale"),
                        header,
                        0, (TEdit_field&)f, siblings);


		TString ragsoc(f.get()); ragsoc.upper();
		
		rel.zero();
		rel.curr().put(DOC_TIPOCF, m.get(F_TIPOCF));
		rel.curr(LF_CLIFO).put(CLI_RAGSOC, ragsoc);
		
		sheet.cursor()->read();
		if (sheet.run() == K_ENTER)
		{
			const long ndoc = sheet.row(-1).get_long(2);
			m.set(F_NDOC, ndoc);
			m.stop_run(K_AUTO_ENTER);
		}
	}
	return true;
}


bool TDocumento_mask::datadocrif_handler(TMask_field& f, KEY key)
{
	if (key == K_ENTER && f.empty())
	{
		const TDocumento_mask& m = (const TDocumento_mask&)f.mask();
		if (m.get_bool(F_RAGGREFF))
		{
			const TDocumento& doc = m.doc();
			if (doc.is_nota_credito())
				return f.error_box("E' necessario specificare data e numero documento di riferimento\n"
													 "quando si desidera generare effetti raggruppati");
		}
	}
	return true;
}

bool link_handler( TMask_field& f, KEY key )
{
	if (key == K_SPACE)
	{
		TSheet_field & sf = *f.mask().get_sheet();
		const TDocumento_mask & m = (const TDocumento_mask & )sf.mask();
		TDocumento & d = (TDocumento &) m.doc();
		int row = sf.selected();
		const TRiga_documento & r = d[row + 1];
		const TMask & row_mask = f.mask();

		if (r.linked())
			r.edit(LF_DOC, "DAPROVV|DAANNO|DACODNUM|DANDOC");
		else
			if (!row_mask.is_running() && row_mask.id2pos(FR_CODART) >= 0)
			{
				TBrowse * brw = row_mask.efield(FR_CODART).browse();

				if (row_mask.get(FR_CODART).empty() && brw)
				{                
					TCursor& cur = *brw->cursor();
					TToken_string siblings;
			  
					TToken_string head(brw->head());
					head.insert("@1|", 0); 
					TToken_string items(brw->items());
					items.insert(" |", 0); 
			    
					cur = 0L;
					siblings.add(FR_CODART);

					TBrowse_sheet sht(&cur, items, "Selezione Multipla", head, 0, row_mask.efield(FR_CODART), siblings);

					if (sht.run() == K_ENTER && sht.one_checked())
					{
						const int items_selected = sht.checked();
						const long totit = cur.items();
						if (items_selected * d.physical_rows() < 950)
						{
							int processed = 0L;
							TToken_string out_id(brw->get_output_fields());
							TToken_string out_fnames(brw->get_output_field_names());
							const TString4 tipo(row_mask.get(FR_TIPORIGA));

							cur.freeze(TRUE);
							for (cur = 0L; cur.pos() < totit; ++cur)
								if (sht.checked(cur.pos()))
								{
									if (++processed < items_selected)
										sf.insert(row, false); // call notify ?
									d.insert_row(row + 1);
									d[row + 1].put(RDOC_TIPORIGA, tipo);
									TToken_string & shrow = sf.row(row);
									shrow.add(tipo, sf.cid2index(FR_TIPORIGA));
									shrow.add("", sf.cid2index(FR_CHECKED));

									TMask & m = sf.sheet_row_mask(row);

									m.set(FR_TIPORIGA, tipo);
									out_fnames.restart();
									for (short id = out_id.get_int(0); id > 0; id = out_id.get_int())
									{
										const TString16 fn(out_fnames.get());
										const TFieldref fr(fn, 0);
										m.set(id, fr.read(cur.curr()));
										shrow.add(m.get(id), sf.cid2index(id));
									}
									sf.check_row(row, 0x2);
									d[row + 1].autosave(sf);
									row++;
								}
							cur.freeze(FALSE);
							sf.force_update();
						}
					} 
				}
			}
	}
	return true;
}

bool ca_mag_handler(TMask_field& f, bool cdc = true)
{
	TMask& row_mask = f.mask();
	const TSheet_field & sf = *f.mask().get_sheet();
	const TDocumento_mask & mask = (TDocumento_mask & )sf.mask();
	short i, first_fld, last_fld;
	const int lffile = cdc ? LF_CDC : LF_COMMESSE;
	const TMultilevel_code_info & info = ca_multilevel_code_info(lffile);
	TString80 cod;

	last_fld = f.dlg();
	first_fld = last_fld - info.levels() + 1;
	for (i = first_fld; i <= last_fld; i++)
		cod << row_mask.get(i);
	if (cod.blank())
	{
		cod.cut(0);
		last_fld = cdc ? mask.cdc_end() : mask.cms_end();
		first_fld = last_fld - info.levels() + 1;

		for (i = first_fld; i <= last_fld; i++)
			cod << mask.get(i);
	}

	const TRectype & rec = cache().get(lffile, cod);
	const TString16 codmag = rec.get("CODMAG");

	if (codmag.not_empty())
	{
		row_mask.set(FR_CODMAG, codmag.left(3), true);
		row_mask.set(FR_CODDEP, codmag.mid(3), true);
	}
	return true;
}

bool cms_mag_handler(TMask_field& f, KEY key)
{
	if ((key == K_TAB && f.focusdirty()) || key == K_ENTER)
	{
		ca_mag_handler(f, false);
		TMask & m = f.mask(); 
		const TSheet_field & s = *m.get_sheet();
		TDocumento_mask & mask = (TDocumento_mask & )s.mask();
		const TRectype & curr = m.efield(mask.cms_start_sh()).browse()->cursor()->curr();
		const TString codcosto = curr.get(COMMESSE_CODCOSTO);
		const TString & codcms = curr.get(COMMESSE_CODCMS);

		if (mask.cdc_start_sh() >= 0 && mask.codcms_sh() != codcms) // && codcosto.full())
		{
			for (short i = mask.cdc_start_sh(); i <= mask.cdc_end_sh(); i++)
			{
				TEdit_field & e = m.efield(i);
				const TFieldref * f = e.field();

				if (f != NULL)
				{
					const int from = f->from();
					const int to = f->to();

					m.set(i, codcosto.sub(from, to), 0x2);
				}
			}
			mask.codcms_sh() = codcms;
		}
	}
	return true;
}

bool cdc_mag_handler(TMask_field& f, KEY key)
{
	if ((key == K_TAB && f.focusdirty()) || key == K_ENTER)
		ca_mag_handler(f);
	return true;
}

bool codcms_handler(TMask_field& f, KEY key)
{
	TDocumento_mask & mask = (TDocumento_mask & )f.mask();
	if ((key == K_TAB && f.focusdirty()) || key == K_ENTER)
	{
		const TRectype & curr = mask.efield(mask.cms_start()).browse()->cursor()->curr();
		const TString & codcms = curr.get(COMMESSE_CODCMS);

		if (mask.cdc_start() >= 0 && mask.codcms() != codcms)
		{
      const TString codcosto = curr.get(COMMESSE_CODCOSTO);
			for (short i = mask.cdc_start(); i <= mask.cdc_end(); i++)
			{
				TEdit_field & e = mask.efield(i);
				const TFieldref * f = e.field();

				if (f != NULL)
				{
					const int from = f->from();
					const int to = f->to();

					mask.set(i, codcosto.sub(from, to), 0x2);
				}
			}
			mask.codcms() = codcms;
		}
	}
	else
		if (key == K_TAB && !mask.is_running())
			mask.codcms() = mask.doc().get(DOC_CODCMS);

	return true;
}

bool evasion_check_handler(TMask_field& f, KEY key )
{
  if (key == K_ENTER && f.dirty())
  {
		const real qta(f.get());
		if (qta <= ZERO)
			return true;
		const TFieldref * fld = f.field();
		if (fld == NULL)
			return true;
    TSheet_field & sf = *f.mask().get_sheet();
    TDocumento_mask & m = (TDocumento_mask & )sf.mask();
    const TDocumento & d = m.doc();
		const int nrow = sf.selected() + 1;
    const TRiga_documento & r = d[nrow];
		const TString16 name = fld->name();
		const TRectype * orig_doc = r.find_original_doc(); // warning

		if (orig_doc != NULL)
		{
			const long ndoc = d.get_long(DOC_NDOC);
			TToken_string key;

			key.add(orig_doc->get(DOC_PROVV));
			key.add(orig_doc->get(DOC_ANNO));
			key.add(orig_doc->get(DOC_CODNUM));
			key.add(orig_doc->get(DOC_NDOC));

			TDocumento & father_doc = cached_doc(key);
			const TRectype * row = r.find_original_rdoc();

			if (row != NULL)
			{
				const TRiga_documento & father_row = father_doc[row->get_int(RDOC_NRIGA)];
				const real ordinato(father_row.get(name));

				TString query("USE RDOC KEY 4 SELECT NDOC!=");
				const int anno = r.get_int(RDOC_DAANNO);
				const TString4 & codnum = r.get(RDOC_DACODNUM);
				const long numdoc = r.get_long(RDOC_DANDOC);
				TString select;

				select << " DAPROVV='" << r.get(RDOC_DAPROVV) << "'";
				select << " DAANNO='" << r.get(RDOC_DAANNO) << "'";
				select << " DACODNUM='" << r.get(RDOC_DACODNUM) << "'";
				select << " DANDOC='" << r.get(RDOC_DANDOC) << "'";
				select << " DAIDRIGA='" << r.get(RDOC_DAIDRIGA) << "'";

				query  << ndoc ;
				query << "\nFROM " << select;
				query << "\nTO " << select;
				
				TISAM_recordset recset(query);
				real evaso;

				for (bool ok = recset.move_first(); ok ; ok = recset.move_next())
					evaso += recset.get(name).as_real();

				const int doc_rows = d.physical_rows();

				for (int i = 1; i <= doc_rows; i++)
				{
					if (i != nrow)
					{
						const TRiga_documento & row = d[i];

						if (r.get(RDOC_CODART) == row.get(RDOC_CODART))
							evaso += row.get_real(name);
					}

				}

				const real residuo = ordinato - evaso;
				if (residuo < qta)
					if (!yesno_box(FR("La quantita' %s e' superiore al residuo %s,\nvuoi continuare ugualmente"), qta.stringa(), residuo.stringa()))
					{
						if (!f.mask().is_running())
						{
							m.set_focus_field(F_SHEET);
							sf.post_select(nrow - 1);
						}
						return false;
					}
					else
						if (!f.mask().is_running())
							m.set_focus_field(F_SHEET);
			}
		}

	}
	if (f.dlg() == FR_QTA)
		return qtaart_handler(f, key); 

	return true;
}


bool distinta_link_handler(TMask_field& f, KEY key )
{
	if (key == K_F8)
	{
		TMask& row_mask = f.mask();   
		TSheet_field& sh = *row_mask.get_sheet();

		TFilename tempfile;
		TCodice_articolo codart(row_mask.get(FR_CODART));
		const bool exist = !cache().get(LF_DIST, codart).empty();

		tempfile.temp("ve0");
		tempfile.ext("ini");


		{
			TConfig configfile(tempfile);
			TString8 para;
			para << LF_DIST;

			configfile.set("Action", exist ? "Modify" : "Insert", "Transaction");
			configfile.set("Mode", "R", "Transaction");
			configfile.set("CODDIST", codart, para);
		}

		TString commandline;

		commandline.format("db0 -4 /i%s",(const char*)tempfile);

		TExternal_app db(commandline);
		db.run();

		remove_file(tempfile);

		TDocumento_mask & m = (TDocumento_mask & )sh.mask();
    const TDocumento & d = m.doc();
		const int row = sh.selected() + 1;

		if (row < d.physical_rows() && d[row + 1].get_bool(RDOC_GENERATA))
			return true;
	}
	return codart_handler( f, key);
}

bool gen_livelli_handler(TMask_field& f, KEY key )
{
	if (key == K_F8 && f.get().blank())
	{
		TMask& row_mask = f.mask();   
		TSheet_field& sh = *row_mask.get_sheet();
		TDocumento_mask & m = (TDocumento_mask & )sh.mask();
    const TDocumento & d = m.doc();
		const int row = sh.selected() + 1;
		const int livello = f.dlg() - FR_LIV1;
		const TRiga_documento & r = d[row];
		TToken_string * str = r.tipo().genconf(livello);
		if (str != NULL)
		{
			const TString codart = row_mask.get(FR_CODART);

			if (codart.full())
			{
				TString code;
				const TRectype & anamag = cache().get(LF_ANAMAG, codart);
				const int items = str->items();

				for (int i = 0; i < items; i++)
				{
					const TString & name = str->get(i);
					if (name.starts_with("PROG"))
					{
						TTable lv(format("LV%1d", livello + 1));
						const int chars = atoi(name.after("PROG"));

						lv.put("CODTAB", code);
						if (lv.read(_isequal) != NOERR)
						{
							lv.zero();
							lv.put("CODTAB", code);
							lv.write();
						}
						const int prog = lv.get_int("I0") + 1;
						lv.put("I0", prog);
						lv.rewrite();
						TString s; s << prog; s.lpad(chars, '0');
						code << s;
					}
					else
						if (name.starts_with("33."))
						{
							TFieldref fld(name.after("33."), LF_DOC);

							code << fld.read(d);
						}
						else
							if (name.starts_with("34."))
							{
								TFieldref fld(name.after("34."), LF_RIGHEDOC);
	
								code << fld.read(d);
							}
							else
								if (name.starts_with("47."))
								{
									TFieldref fld(name.after("47."), LF_ANAMAG);
		
									code << fld.read(anamag);
								}
				}
				row_mask.set(f.dlg(), code, 0x3);
			}
		}
	}
	return true;
}