#include "770100a.h"
#include "770101.h"
#include "770102.h"
#include <tabutil.h>

void TSchedaPercipienti::init_mask(TMask& m)
{
  update_lasts(m);
  
  // se collegamento 
  if (tipo_coll() != nessuno)
  {
    const bool variazione = coll_variazione();
    if (!variazione) compila_testata(m);
    switch (tipo_coll())
    {
      case pagamento:
      case occasionale:
        // Compilo riga di pagamento SOLO SE NON ce ne sono gia'..
        if ( (tipo_coll() == pagamento && _rel->pag_items() == 0) 
              ||
              tipo_coll() == occasionale )          
        {
          const real totrit(m.get(F_TOTRIT));
          const real totdoc(m.get(F_TOTDOC));
          const real compenso(m.get(F_COMPENS));
          const real spese(m.get(F_SPESE));
                    
          if  ((tipo_coll() == pagamento && (_coll._compenso + totrit == totdoc) )
               ||
               (tipo_coll() == occasionale))
          {
            TSheet_field& pags = pag_sheet_enabled(m);            
            TRectype rpag(_rel->pag(0));
            rpag.zero();
            real& imponibile = _coll._compenso;
            rpag.put("DATAPAG",    _coll._datadoc);
            rpag.put("COMPENSO",   compenso);
            rpag.put("SPESA",      spese);
            // Update spreadsheet
            rec2row(pags.row(0), rpag, 0);  
            // ricalcolo riga pagamento
            TString16 codcau(m.get(F_CODCAUS));
            TTable cau("%ca7");
            cau.zero();
            cau.put("CODTAB", codcau);
            if (cau.read() != NOERR)
              warning_box("Causale non presente in tabella");
            const real h_PercAssImp = cau.get_real("R4");
            const real h_PercCassaPrev = cau.get_real("R5"); 
            const real h_PercRitenuta = cau.get_real("R0");
            const real h_PercInps = cau.get_real("R1"); 
            const real h_PercAssImpInps = cau.get_real("R2");
            const real h_PercCommitInps = cau.get_real("R3");
            Pag_struct c;
            Pag_struct s;
            TToken_string& t = pags.row(0);
            from_sheet_to_struct(t, s);
            calcola_riga_pag(s,
                             c, 
                             TRUE,  
                             h_PercAssImp,
                             h_PercCassaPrev,
                             h_PercRitenuta,
                             h_PercInps,
                             h_PercAssImpInps,
                             h_PercCommitInps);     
            from_struct_to_sheet(s, t);   
            // forzo ridisegno sheet                                      
            pags.force_update();
          }
        }
      default:               
        // per evitare di riscrivere tutto dopo registra      
        _coll._tipo_coll = nessuno;
        break;
    }
  }             
  fill_sheet(m);
}

bool TSchedaPercipienti::vers_notify(TSheet_field& s, int r, KEY k)
{
  switch(k)
  {                      
     
// Inserimento riga      
    case K_INS:
// Impedisce inserimento di nuove righe
      return FALSE;     
              
// Inizio modifica riga     
    case K_SPACE: 
    {
// Pulisco descrizioni luogo e tipo versamento (solo se non gia' indicati!)
      TSheet_field& vers = app().vers();   
      TMask& mp = vers.sheet_mask();          
      TString16 tipo(mp.get(F_TIPOVERS));
      TString16 luo (mp.get(F_LUOVERS));
      if (tipo.empty())
        mp.reset(70);  
      if (luo.empty())
        mp.reset(71);        
      break;
    } 

    default:
      break;
  }
  return TRUE;
}

bool TSchedaPercipienti::pags_notify(TSheet_field& s, int r, KEY k)
{
  switch(k)
  {                         
       
    // Inserimento riga      
    case K_INS:
      // Impedisce inserimento di nuove righe
      return FALSE;     

    // Inizio modifica riga     
    case K_SPACE:
    {
      break;                        
    }

    // Fine modifica di una riga  
    case K_ENTER:
      break;                                  

    default:
      break;
  }
  return TRUE;
}

TSheet_field& TSchedaPercipienti::pags() const
{
  TSheet_field& s = pag_sheet_enabled(curr_mask());
  return s;
}

TSheet_field& TSchedaPercipienti::vers() const
{
  TSheet_field& s = (TSheet_field&)curr_mask().field(F_VERSAMENTI);
  return s;
}
              
bool TSchedaPercipienti::my_empty_items(TToken_string& r, bool vers)
{      
  TString rr;     
  
  // controlla se riga versamento significativa
  if (vers)
   for (int i=0; i < COLONNE_SIGNIFICATIVE_SPREADSHEET_VERSAMENTI; i++)
   {
     rr = r.get(i);
     rr.trim();     
     switch (i) {
       case 0: // 1015
        if (rr.not_empty()) 
          return FALSE;
        break;       
       case 1:        
        if (rr.not_empty()) 
          return FALSE;
        break;       
       case 2:   // lugo e tipo vers.
       case 3:
        if (rr.not_empty())
          if (rr != "N") 
            return FALSE;
        break;
       case 4:
       case 5:
        if (rr.not_empty()) 
          return FALSE;      
        break;
       case 6:
         if (rr.not_empty()) {
           real   rrr(real::ita2eng(rr));
           if (rrr != ZERO) 
             return FALSE;
         }
         break;
       default:
         break;
    }
  }        
  
  // controlla se riga pagamento significativa
  else
  {
    rr = r.get(token_pos("DATAPAG"));   
    rr.trim();
    if (rr.not_empty()) 
      return FALSE;   
  }   

          
  return TRUE;
}

void TSchedaPercipienti::pag_pack()
{
  TString_array& rows = pags().rows_array();

  const int max = rows.items();
  for (int i = 0; i < max; i++)
  {
    TToken_string& r = (TToken_string&)rows[i];
    if (my_empty_items(r, FALSE))             // Remove all empty strings
      rows.destroy(i, FALSE);
  }

  rows.pack();
}
  
void TSchedaPercipienti::ver_pack()
{
  TString_array& rows = vers().rows_array();

  const int max = rows.items();
  for (int i = 0; i < max; i++)
  {
    TToken_string& r = (TToken_string&)rows[i];
    if (my_empty_items(r, TRUE))             // Remove all empty strings
      rows.destroy(i, FALSE);
  }
  rows.pack();
}


// Inizializza array sheet dei pagamenti
void TSchedaPercipienti::load_pag_sheet(const long numvers)
{
  real  comp, spese, imp, ritpag;
  int   i, iNumRigaAS;
  
  TSheet_field& pag = pags();
  _pags->destroy();

  
  // numero di riga dell'array-sheet. Viene incrementato
  // solo quando si trovano pagamenti 'giusti' (cioe' solo
  // quando si aggiungono elementi all'array-sheet)
  iNumRigaAS = 0;   
  for ( i = 0; i < pag.items(); i++)
  {
    TToken_string* d    = new TToken_string(64);
    TToken_string& riga = pag.row(i);

    // Scarto le righe non significative 
    if (my_empty_items(riga, FALSE)) continue;

    const long nvers = riga.get_long(token_pos("NUMVERS"));
    
    // "Se il pagamento e' gia' stato selezionato DA UN ALTRO versamento
    //  NON si deve vedere! "    
    if (nvers > 0  &&  nvers != numvers) 
      continue; 

    const long npag = i;    
    const int LARGHEZZA_COL = 15;
    TString80 dep;

    d->add(" "); // 0 spazio per la 'X' di selezione

    dep = riga.get(token_pos("DATAPAG"));
    d->add(dep); // 1 data pagamento

    comp = riga.get(token_pos("COMPENSO")); 
    const TCurrency soldi_compenso(comp);
    dep = soldi_compenso.string(TRUE);
    dep.right_just(LARGHEZZA_COL);
    d->add(dep); // 2 compenso

    ritpag = riga.get(token_pos("RITENUTA"));
    const TCurrency soldi_ritenuta(ritpag);
    dep = soldi_ritenuta.string(TRUE);
    dep.right_just(LARGHEZZA_COL);        
    d->add(dep); // 3 ritenuta    
    
    d->add(i); // 4 numero riga
    
    d->add(nvers); // 5 numero versamento collegato   
    
    _pags->add(*d);   // aggiungo la riga nell'array_sheet
    // Setto il bit alla posizione numpag e metto la X
    if (nvers == numvers)
    {
      _selected.set(npag);    
      _pags->check(iNumRigaAS, TRUE);
    }                        
    iNumRigaAS++; // ignoro in questo contatore i pagamenti che NON 
                  // si vedono (se il pagamento e' scartato prima di qui
                  // non ci passa)
  }
}  

void TSchedaPercipienti::attach_pag_vers (int pag, long numvers)
{
  TSheet_field&  pag_s = pags();
  TToken_string& riga  = pag_s.row(pag);

// setta NUMVERS nello sheet
  riga.destroy(token_pos("NUMVERS"));
  riga.add(numvers, token_pos("NUMVERS"));

// setta NUMVERS nel record
  _rel->pag(pag).put("NUMVERS", numvers);  
}

void TSchedaPercipienti::detach_pag_vers (int pag)
{
  TSheet_field& pag_s = pags();
  TToken_string& riga = pag_s.row(pag);

  riga.destroy(token_pos("NUMVERS"));
  riga.add(-1L, token_pos("NUMVERS"));   

// setta NUMVERS nel record
  _rel->pag(pag).put("NUMVERS", -1L);    
}
                                                         
//
// VERS_ATTACHED ( numvers )
//
// Determina se c'e' ALMENO UN pagamento collegato al versamento NUMVERS
//                                                         
bool TSchedaPercipienti::vers_attached(const long numvers)
{
  long numv = 0L;

// Aggiorna lo sheet dei pagamenti per questo versamento
  app().load_pag_sheet(numvers);                        

  for (int j = 0; j < _pags->items(); j++)
  {
    // Leggo NUMVERS
    TToken_string& riga  = _pags->row(j);
    numv = riga.get_long(AS_POS_NVER);

    if (numv > 0L)
      if (numv == numvers) 
        return TRUE;
  }
  return FALSE;
}

// 
// CHECK_PAGAMENTI
// Questo serve solo a impedire di uscire senza aver collegato almeno
// un pagamento
bool TSchedaPercipienti::check_pagamenti(TMask_field& f, KEY k)
{
  const long  numvers = get_numvers(f);
  return app().vers_attached(numvers);
} 

void TSchedaPercipienti::setta_ritvers(TMask_field& f, const real& ritenuta) 
{
  TString80 rit_str(ritenuta.string());
  f.mask().set(F_RITVERS, rit_str);     
  f.mask().field(F_RITVERS).set_dirty(); // Forza on_hit()    
}

// Guardo se ho compilato la data OPP. il flag 1015
// Leggo la maschera o la riga dello ss
bool TSchedaPercipienti::compilato_vers(TMask_field& f)
{
  TString16 datav;
  char v1015;
  
  if (f.mask().is_running())
  {
    datav = f.mask().get(F_DATAVERS);
    v1015 = f.mask().get(F_VERS_1015)[0];
  }
  else             
  {
    TSheet_field& ver    = app().vers();   
    const int riga_corr  = ver.selected();
    TToken_string& riga  = ver.row(riga_corr);
    v1015                = riga.get(0)[0];
    datav                = riga.get(1);
    datav.trim();
  }
  return datav.not_empty() || v1015 == 'X';
}     


// GET_NUMVERS
//
// Determina il numero di versamento corrente, prendendolo
// dalla riga corrente dello spreadsheet
long TSchedaPercipienti::get_numvers(TMask_field& f)
{
  long numvers = 0L;
  TSheet_field& ver    = app().vers();   
  const int riga_corr  = ver.selected();
  TToken_string& riga  = ver.row(riga_corr);
  numvers = riga_corr + 1;
  
  return numvers;
}     

bool TSchedaPercipienti::pag_azzera(TMask_field& f, KEY k)
{     
  if (k == K_SPACE)          
  {
    Pag_struct s;
    app().from_struct_to_mask(app().clear_struct(s), f.mask());
  }
  return TRUE;
}

bool TSchedaPercipienti::ver_azzera (TMask_field& f, KEY k)
{     
  long        numvers = get_numvers(f);
  int         nriga   = 0;      
  TNikArray_sheet& pags = *app()._pags;
  
  if (k == K_SPACE)
  {    
    app().load_pag_sheet(numvers);       

    for (int j = 0; j < pags.items(); j++)
    {
      TToken_string& riga  = pags.row(j);
      long numv = riga.get_long(AS_POS_NVER);

      if (numv > 0L)
        if (numv == numvers) 
        {
          nriga =  pags.row(j).get_int(AS_POS_NRIGA);      
          pags.row(j).add(-1L, AS_POS_NVER);            
          app().detach_pag_vers(nriga);
        }
    }
  }
  return TRUE;
}

//
// PAG_SELECT
//
// Collegamento tra versamenti e pagamenti
//
// Calcolo ritenuta = SUM(ritpag) {dei pagamenti collegati} 
//
// Usa: load_pag_sheet() attach_pag_vers() e detach_pag_vers()
//
bool TSchedaPercipienti::pag_select (TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {                           
    if (!app().compilato_vers(f)) 
      return f.warning_box("Inserire prima la data del versamento");

    long        numvers = get_numvers(f);
    long        numpag  = 0L;
    int         nriga   = 0;      
    // 13.7.95 Ricalcola la ritenuta, azzerando contenuto precedente
    real    ritenuta = ZERO;
    TBit_array& selected = app()._selected; 
    
    selected.reset();

    // Costruisce array_sheet dei pagamenti     
    app().load_pag_sheet(numvers);       
    
    TNikArray_sheet& ASpags = *app()._pags;
                                                 
    // seleziona e aggiungi alle gia' selezionate 
    if (ASpags.run() == K_ENTER)
    {
      for (int j = 0; j < ASpags.items(); j++)
      {
        // get effettivo numero riga pag.
        nriga =  ASpags.row(j).get_int(AS_POS_NRIGA);
                              
        int mesec = -1;
        int annoc = -1; // competenza
                                      
        if (ASpags.checked(j)) 
        {
// Scrive nello spread-sheet e nella relazione
          app().attach_pag_vers(nriga, numvers); 

 // Scrive nell'array_sheet (e' da qui che leggo dopo)
          ASpags.row(j).add((long)numvers, AS_POS_NVER);
          
          TDate datapag(ASpags.row(j).get(1));
          if (mesec < 0)
          {
            mesec = datapag.month();
            annoc = datapag.year();
          }
          else
          {
            if (mesec != datapag.month() || annoc != datapag.year())
			{
// TBI inserire un'altra riga di versamento (?)
			}
          }
          selected.set(numpag);

          real dep(real::ita2eng(ASpags.row(j).get(AS_POS_RITPAG)));
          ritenuta    +=  dep;
        }
        else       // pags.checked()
        {
// resetta se era stato settato prima        
          if (selected[numpag])  
          {
            selected.reset(numpag);
            ASpags.row(j).add(-1L, AS_POS_NVER);
            app().detach_pag_vers(nriga);
          }
        }
      }
      setta_ritvers(f, ritenuta);
    }  // if k==K_ENTER
  }
  return TRUE;
}

void TSchedaPercipienti::work_tipoluogo(TMask_field& f)
{
  TMask&  m       = f.mask();
  char tipo = m.get(F_TIPOVERS)[0];
  char luogo = m.get(F_LUOVERS)[0];     
  bool v1015 = m.get_bool(F_VERS_1015);
  TSheet_field& ss = app().vers();
  const int row = ss.selected();
                        
  m.hide (-2);            // nasconde tutto

  // disabilita CAB se versamento 1015
  // perch� non appartenendo alla riga
  // non viene disabilitato nella "rec2row"
  if (v1015)                  
    m.disable(F_CAB);
  else               
    m.enable(F_CAB);
    
  
  if (tipo == 'B')                     
  {
    // ABI e CAB          
    m.show (-6);
    
     // abilita progressivo vers.banca
    if (!v1015)
      m.enable(SM_PROGRBANCA);
  }
  else
  {
    m.disable(SM_PROGRBANCA);

    if (tipo == 'D')
    {
      if (luogo == 'T') 
      {
        m.show(-3);     // SOLO quietanza
        ss.disable_cell(row,4);
      }
      else 
      {
        m.show(-4);     // serie e numero
        ss.enable_cell(row,4);    
      }
    }
//    else        
    if (tipo == 'C')
    {
      m.show (-5);  // SOLO numero versamento
      ss.disable_cell(row,4); 
    } 
  }
}

bool TSchedaPercipienti::luo_hndl(TMask_field& f, KEY k)
{
  if (k == K_TAB)
    work_tipoluogo(f);
    
  if (k == K_ENTER)
  {
    work_tipoluogo(f);
    TMask&  m       = f.mask();
    char    tipo    = m.get(F_TIPOVERS)[0];
    char    luogo   = m.get(F_LUOVERS)[0];

// Se ho indicato il luogo => devo indicare anche il TIPO
    if (isalpha(luogo)) 
      return tipo == ' ' || tipo == '\0' ? 
        f.warning_box("Indicare il tipo del versamento") : TRUE;
  }
  return TRUE;
                               
}

bool TSchedaPercipienti::abicab_hndl(TMask_field& f, KEY k)
{
  if (f.to_check(k))                                           
  {
    TString16 park(f.get());
    TMask&  m       = f.mask();
    char    tipo    = m.get(F_TIPOVERS)[0];

// ABI/CAB solo se tipo e' B
    if (tipo != 'B')
      return TRUE;
          
    for (int i=0; i<park.len(); i++)
    {                                                                  
      // controllo se codice CAB supera le 5 cifre
      if (i > 5)
      {
        f.reset();
        return f.warning_box("Codice CAB non valido"); 
      }
      // controllo numericit� del codice ABI/CAB
      if (!isdigit(park[i]))
        return f.warning_box("Il codice ABI/CAB deve essere numerico");
    }     
  }
  return TRUE;
}

bool TSchedaPercipienti::tipo_hndl(TMask_field& f, KEY k)
{
  if (k == K_TAB)
    work_tipoluogo(f);

  if (k == K_ENTER || k == K_TAB)
  {
    TMask&  m       = f.mask();
    char    tipo    = m.get(F_TIPOVERS)[0];
    char    luogo   = m.get(F_LUOVERS)[0];
    
// Se ho indicato il tipo => devo indicare anche il LUOGO
    if (isalpha(tipo)) 
      return luogo == ' ' || luogo == '\0' ? 
        f.warning_box("Indicare il luogo del versamento") : TRUE;
  }
  return TRUE;
}
                             
//
// VERS1015_HANDLER
//                             
bool TSchedaPercipienti::vers1015_handler(TMask_field& f, KEY k)
{
  if (k == K_ENTER)
  {
    TString16 datas      = f.mask().get(F_DATAVERS);
    const bool v1015     = f.mask().get_bool(F_VERS_1015);
    const bool attaccati = check_pagamenti(f,k);

    if (attaccati)
      if (!v1015 && datas.empty())
        return f.warning_box("Manca la data del versamento");
        
// Non considerare versamenti non significativi    
    if (v1015 || datas.not_empty())
      return attaccati ? TRUE : f.warning_box("Nessun pagamento collegato");

    const real rite (f.mask().get(F_RITVERS));
// Pero' se c'e' la ritenuta non lo far passare
    if (rite != ZERO)
      return f.warning_box("Manca la data oppure il flag di versamento 1015");
              
    return TRUE;
  }
          
  if (k == K_SPACE || k == K_F2)
  {
    TSheet_field& ss = app().vers();
    const bool v1015 = (f.get() == "X");
    const int  row   = ss.selected();
    int i;

// Disabilito tutto MA NON ritenuta        
    if (v1015) 
    {
// Se son gia' disabilitati non fare nulla
      if (ss.cell_disabled(row, 1)) 
        return TRUE;

      f.mask().reset(102);
      f.mask().reset(103);
      f.mask().reset(104);
      f.mask().reset(105);
      f.mask().reset(106);  
      
      f.mask().disable(102);
      f.mask().disable(103);            
      f.mask().disable(104);
      f.mask().disable(105);
      f.mask().disable(106);
                  
      for (i=1; i<6; i++)          
        ss.disable_cell(row,i);
    }
    else
    { 
      f.mask().enable(102);
      f.mask().enable(103);      
      f.mask().enable(104);
      f.mask().enable(105);
      f.mask().enable(106);
    
      for (i=1; i<6; i++)
        ss.enable_cell(row,i);    
    }
  }
  return TRUE;
}


// handler codice causale
bool TSchedaPercipienti::check_causale(TMask_field& f, KEY k)
{
  TMask& m = f.mask();
  TString16 cod_qua(m.get(F_CODQUA));
  
  // creo run-time gli items per la causale quadro  
  app().build_causqua_items(m, cod_qua);  
    
  
  if (k == K_TAB && m.is_running())
  {
    // leggo causale indicata
    TFixed_string cod_caus(f.get(),3);
    
    // cose da fare solo se viene modificato il codice causale
    if (f.to_check(k))
    {
      // forzo causale quadro con il valore in tabella
      TEdit_field& f_causqua = m.efield(F_CAUSQUA);
      f_causqua.reset();
      if (cod_qua == "SC")
        f_causqua.set(m.get(F_TABCAUSQUASC));
      if (cod_qua == "SE")
        f_causqua.set(m.get(F_TABCAUSQUASE));
      if (cod_qua == "SF")
        f_causqua.set(m.get(F_TABCAUSQUASF));
      if (cod_qua == "SG")
        f_causqua.set(m.get(F_TABCAUSQUASG));

      // attiva sheet pagamenti in base al quadro
      app().activate_pag_sheet(m);  
    }           
  }  
  
  return TRUE;
}

bool TSchedaPercipienti::pag_standard_handler(TMask_field& f, KEY k)
{
  static Pag_struct s; 
  static Pag_struct c; 
  static Pag_struct nullpag;
  app().clear_struct(nullpag);
  
  // reperisco dati documento
  TMask& mm = app().curr_mask();
  const bool d_forzatura = mm.get_bool(F_FORCED);  
  TString16 d_codqua(mm.get(F_CODQUA));
  
  // eseguo calcolo solo per K_TAB (singolo campo),
  // oppure per K_ENTER, ma solo per il primo campo,
  // questo per migliorare le prestazioni
  if (f.to_check(k))
  { 
    if (k == K_TAB || (k == K_ENTER && f.dlg() == 101))
    { 
    
      // reperisco valori nascosti compilati dalla tabella causali
      const real h_PercAssImp = mm.get_real(F_QUOTAIMP);
      const real h_PercCassaPrev = mm.get_real(F_CASSA_PREV); 
      const real h_PercRitenuta = mm.get_real(F_PERRIT);     
      const bool h_FlagInps = mm.get_bool(F_FLAG_INPS);
      const real h_PercInps = mm.get_real(F_PERC_INPS); 
      const real h_PercAssImpInps = mm.get_real(F_PERC_ASS_INPS);
      const real h_PercCommitInps = mm.get_real(F_PERC_COMMIT_INPS);
  
      // inizializzo struttura calcolati
      app().clear_struct(c);
  
      // riempimento struttura pagamento
      app().from_mask_to_struct(f.mask(), s);   
      
      // non proseguo se riga vuota
      if (s == c) return TRUE;
      
      // richiamo calcolo di riga
      app().calcola_riga_pag(s,
                             c, 
                             FALSE,  
                             h_PercAssImp,
                             h_PercCassaPrev,
                             h_PercRitenuta,
                             h_PercInps,
                             h_PercAssImpInps,
                             h_PercCommitInps);   
      
      // riporto valori a maschera
      app().from_struct_to_mask(s, f.mask());
    }
    
    
    // eseguo controlli solo per K_ENTER
    // utilizzando i valori memorizzati nelle strutture statiche
    if (k == K_ENTER)
    { 
    
      // non proseguo se riga vuota
      if (s == nullpag) return TRUE;
      
      // reperisco nome campo su record
      const TString& name = f.field()->name();
      
      // controllo data pagamento
      if (name == "DATAPAG")
        if (!s.datapag.ok() && (s.compenso != ZERO || s.spesa != ZERO))   
          return f.error_box("Data pagamento non indicata");
        
      // controllo compenso e/o spese 
      if (name == "COMPENSO" || name == "SPESA")
        if (s.compenso == ZERO && s.spesa == ZERO)
          return f.error_box("Compenso o spese non indicati");    
          
      // controllo imponibile 
      if (name == "IMPONIBILE")       
        if (d_codqua != "E1" && abs(s.imponibile) > abs(s.compenso))
          return f.error_box("Imponibile maggiore del compenso");       
          
      // controllo ritenuta
      if (name == "RITENUTA" && !d_forzatura)
        if (s.ritenuta != c.ritenuta)
          return f.error_box("Ritenuta diversa da importo calcolato");            
  
      // controllo detrazioni lavoro dipendente
      if (name == "DETLAVDIP")
        if (s.detlavdip == ZERO && s.giolavdip != 0) 
          return f.error_box("Detrazioni lavoro dipendente non indicate");                    
          
      // controllo CPA
      if (name == "IMPCPA") 
      {                              
        if ((d_codqua != "SC") && s.impcpa != ZERO) 
          return f.error_box("CPA valido solo per causali con quadro SC");
        if (abs(s.impcpa) > abs(s.compenso)) 
          return f.error_box("CPA maggiore del compenso");
      }               
      
      // controllo somme reg.conv.
      if (name == "SOMREGCONV") 
      {                              
//        if ((d_codqua != "SC" && d_codqua != "SE") && s.somregconv != ZERO) nell'ultima versione dei quadri le SOMREGCONV valgono per tutti i tipi di quadro (SC,SE,SF,SG)
//          return f.error_box("Somme reg.conv. valido solo per causali con quadro SC e SE");     12/07/2000
        if (!app()._soggnres && s.somregconv != ZERO) 
          return f.error_box("Somme reg.conv. valido solo se percipiente non residente");
      }   
      
      // controllo contributo 10% percipiente
      if (name == "CTSSNPERC" && !d_forzatura)
        if (s.ctssnperc != c.ctssnperc)
          return f.error_box("Contributo Inps percipiente diverso da importo calcolato");           
    
      // controllo contributo 10% complessivo
      if (name == "CTSSNCOMP" && !d_forzatura)
        if (s.ctssncomp != c.ctssncomp)
          return f.error_box("Contributo Inps complessivo diverso da importo calcolato");           
          
      // controllo numero quote
      if (name == "NQUOTE" && !d_forzatura)
        if (s.nquote == ZERO)
          return f.error_box("Numero quote non indicate");              
    }       
  } 
 
  return TRUE;
}