// cg4305: liquidazione IVA
// funzionalita' accessorie (calcolo acconto, estrazione deleghe)

#include <defmask.h>
#include <progind.h>
#include <prefix.h>
#include <sheet.h>
#include <utility.h>
#include <config.h>

#include "cg4300.h"
#include "cg4300b.h"
#include "cg4300c.h"                           
#include "cg4800b.h"                           

#define IVA_DA_VERSARE_ALTRI_MESI real(50500.0)
#define IVA_DA_VERSARE_MESE_12    real(500.0) //chiesto conferma a Milano: e' proprio cosi'

// -------------------------------------------------- estrazione deleghe
bool TLiquidazione_app::set_deleghe()
{
  TMask m("cg4300b.msk");  
  
  m.field(FLD_CGB_YEAR).set_handler(ch_year_handler);

  m.field(FLD_CGB_YEAR).set(_year);    
  m.field(CHK_CGB_PRINT).set(_isprint ? "X" : "");    
  
  int k = 0;
  long j;
  _calcall = FALSE;

  for (;;)
  {
    if (k == K_ESC || k == K_ENTER)
      break;

    k = m.run();
    
    _isprint = m.get_bool(CHK_CGB_PRINT);
    
    switch (k)
    {
    case DLG_SELECT:

      _ditte->run();
      for (j = 0l; j < _ditte->items(); j++)
        if (_ditte->checked(j)) _selected.set(j);
      break;

    case BUT_CGB_ALL:
      
      _ditte->check(-1);
      for (j = 0l; j < _ditte->items(); j++)
        if (_ditte->checked(j) && !_ditte->disabled(j)) 
          _selected.set(j);
      _calcall = TRUE;
      k = K_ENTER;
      break;
    }
  }

  if (k == K_ENTER)
  {
    _year  = m.get(FLD_CGB_YEAR);
    _month = atoi(m.get(FLD_CGB_MONTH));
  }

  return k == K_ENTER;
}

bool TLiquidazione_app::extract_deleghe()
{
  char buf[256]; TArray desc;
  _prind = new TProgind(_calcall ? _n_ditte : _selected.ones(),
                        "         Estrazione deleghe        \n"
                        "        preparazione archivi       \n "
                        "                                   \n ",
                        TRUE,TRUE,40);

  for (int l = 0; l < _ditte->items(); l++)
  {
    if (_prind->iscancelled())
      break;

    if (!(_calcall || _selected[l]) || _ditte->disabled(l)) 
      continue;

    TApplication::set_firm(atol(_ditte->row(l).get(1)));

    _nditte->curr().zero();
    _nditte->curr().put("CODDITTA",_ditte->row(l).get(1));
    _nditte->read();
    
    // must succeed 
    look_lia();    
    _freqviva = _lia->get("S7");
    
    sprintf (buf,"Estrazione deleghe (%d):\nditta %s\n ",
             _month,
             (const char*)_nditte_r->get("RAGSOC"));
    _prind->set_text(buf);
    
    
    if (is_month_ok_strict(_month) || _month == 13)
    {
      _isbenzinaro = _nditte->curr(LF_ATTIV).get_bool("ART74_4");
      bool   mens  = _freqviva == "M";
      //_isannual    = (_month == 12 && !mens && !_isbenzinaro) ||
      //  (_month == 13 && (mens || _isbenzinaro));
      _isriepilogo = _month == 13;
      _isendliq = _isannual || _isriepilogo;

      extract_delega(_month, desc);
    }
    _prind->addstatus(1);
  }

  TApplication::set_firm(__firm);
  delete _prind;

  if (_isprint)
  {
    _DescrItem* ddeb = NULL;                    
    _DescrItem* dcrd = NULL;                    
    
    // scorri desc e prepara descritems
    for (int i = 0; i < desc.items(); i++)
    {
      TToken_string& tt = (TToken_string&)desc[i]; 
      
      real tp(tt.get(3));
      if (tp.sign() > 0)
      {
        if (ddeb == NULL) 
        {
          ddeb = new _DescrItem(DELDEB); 
          ddeb->_f0 = _month; 
        }
        ddeb->_arr.add(tt);
      }
      else
      {
        if (dcrd == NULL) 
        {
          dcrd = new _DescrItem(DELCRED);
          dcrd->_f0 = _month; 
        }
        dcrd->_arr.add(tt);
      }
    }    
    if (dcrd != NULL) _descr_arr.add(dcrd);
    if (ddeb != NULL) _descr_arr.add(ddeb);  
  }
  
  return TRUE;
}

bool TLiquidazione_app::extract_delega(int month, TArray& desc)
{
  TToken_string* tt = NULL;
  bool versare = FALSE;
  
  if (look_lim(month))
  {
    real topay = result_liq(month); // TBC non si puo' fa' accussi'!!!!! pena il casino!
    if (month == 12)   
    {
      if (topay > IVA_DA_VERSARE_MESE_12)
        versare = TRUE;
    }
    else if (topay > IVA_DA_VERSARE_ALTRI_MESI) 
      versare = TRUE;
    
    real intr  = _lim->get_real("R14");
    topay     += intr;   // lo vogliono registrato con interessi
    real nrnd  = topay;
    topay.round(-3);     // importo totale del versamento arrotondato
    
    //bool wasdel = look_del(month, _isannual ? 2 : 1);
    bool wasdel = look_del(month, 1);    
    
    //la stampa deve essere fatta sia se a credito che a debito
    if (!topay.is_zero())
    {                                     
      tt = new TToken_string(80);
      tt->add(_nditte->curr().get("CODDITTA"));
      tt->add(_nditte->curr().get("RAGSOC"));
      tt->add(_freqviva);
      tt->add(topay.string());                 
      tt->add("");
    }
    
    //if (topay.sign() > 0)
    if (versare)
    {
      look_del(month, 1, TRUE);  //ci mette abi, cab o con 
                                 //che legge dall'anagrafica!!!
      bool stampato = _del->get_bool("B0");
      if (stampato)  //se esiste e stampato si richiede conferma aggiornamento
      {
        if (topay != _del->get_real("R0"))
          video_conferma(topay, intr, nrnd);
      }
      else           //aggiorna importo versamento
      {   
        _del->put("R0",topay);
        _del->put("R1",intr);
        _del->put("R2",nrnd); // non arrotondato, per calcolo risultato a debito/cr
        _del->rewrite();
      }
      
      tt->add(_del->get("S7"));
      tt->add(_del->get("S8"));
      tt->add(_del->get("S9"));
      tt->add(_nditte->curr().get("PTEL"));
      tt->add(_nditte->curr().get("TEL")); 
      /***
      TString desc(_del->get("S1"));
      if (desc.not_empty())
        tt->add(desc);
      else tt->add(_del->get("S2"));  
      ***/     
      TString desc;
      if (_del->get("S9").not_empty())
      {
       TTable ucc("%UCC");
       ucc.zero();
       ucc.put("CODTAB", _del->get("S9"));
       if (ucc.read() == NOERR)
         desc = ucc.get("S0");
      }   
      else if (_del->get("S7").not_empty())
      {
       TTable ban("%BAN");
       TString16 cod;
       cod = _del->get("S7");
       if (_del->get("S8").not_empty()) cod << _del->get("S8"); 
       ban.zero();
       ban.put("CODTAB", cod);
       if (ban.read() == NOERR)
        desc = ban.get("S0");
      }  
      tt->add(desc);
    }  
    else if (wasdel)  //se esiste e no versare
      _del->remove();
  }       
  
  if (tt != NULL) 
    desc.add(tt);

  return TRUE;
}

bool TLiquidazione_app::video_conferma(const real& newimp, const real& intr,
                                       const real& narr)
{                                               
  TMask m("cg4800b");  

  m.field(F_CODDITTA).set(_nditte->lfile().get("CODDITTA"));
  m.field(F_RAGSOC).set(_nditte->lfile().get("RAGSOC"));
  m.field(F_DATAVER).set(_del->get_date("D0"));
  m.field(F_ABI).set(_del->get("S7"));
  m.field(F_CAB).set(_del->get("S8"));
  m.field(F_CON).set(_del->get("S9"));       
  m.field(F_IMPVER).set(_del->get("R0"));
  m.field(F_NEWIMP).set(newimp.string());    

  for (bool stop = FALSE; !stop;)
  {
    KEY k = m.run();        
    
    switch(k)
    {
    case K_SAVE: 
    {
      KEY k = yesnocancel_box("Delega gia' stampata. Si desidera ugualmente confermare l'aggiornamento?");
      if (k ==  K_YES)
      {
        _del->put("B0", "");
        _del->put("R0",newimp);
        _del->put("R1",intr);
        _del->put("R2",narr); 
        _del->rewrite();
      }
      if (k == K_YES || k == K_NO) 
        stop = TRUE;
    }    
    break;  
  case K_ESC:
    //case K_QUIT:     
    stop = TRUE;
    break;
  }
  }
  return TRUE;
}    

// -------------------------------------------- calcolo acconto dicembre
bool TLiquidazione_app::set_acconto(real& inf, real& ina)
{
  TMask m("cg4300c.msk");
  
  m.set(CHK_CGC_PRINT,"X");
  m.field(FLD_CGC_YEAR).set_handler(ch_year_handler);
  m.field(FLD_CGC_YEAR).set(_year);

  int k = 0;  long j;

  _calcall = FALSE;

  for (;;)
  {
    if (k == K_ESC || k == K_ENTER)
      break;
    k = m.run();
    
    _year     = m.get(FLD_CGC_YEAR);
    _isprint  = m.get_bool(CHK_CGC_PRINT);
    _isbase   = m.get_bool(CHK_CGC_BASE);
    _basecalc = (tbc)m.get_long(RDB_CGC_BASE); 
    
    //inf       = real(m.get(FLD_CGC_INF));                
    //ina       = real(m.get(FLD_CGC_INA));
    
    inf = ina = ZERO;                
    
    switch (k)
    {
    case DLG_SELECT:

      // scegli ditte
      _ditte->run();
      
      for (j = 0l; j < _ditte->items(); j++)
        if (_ditte->checked(j)) _selected.set(j);

      break;
    case BUT_CGC_ALL:
      _ditte->check(-1);
      for (j = 0l; j < _ditte->items(); j++)
        if (_ditte->checked(j) && !_ditte->disabled(j)) 
          _selected.set(j);
      _calcall = TRUE;
      k = K_ENTER;
      break;
    }
  }
  return k == K_ENTER;
}

bool TLiquidazione_app::recalc_acconti(real& inf, real& ina)
{                 
  char buf[256];

  bool onemade = FALSE;
  
  long firm = TApplication::get_firm();
  _prind = new TProgind(_n_ditte,
                        "              Calcolo acconto         "
                        "\n         Preparazione archivi      "
                        "\n                                   ",
                        TRUE,TRUE,40);

  for (int l = 0; l < _ditte->items(); l++) 
  {
    if (_prind->iscancelled()) 
      break;
    if ((_calcall || _selected[l]) && !_ditte->disabled(l))
    {
      if (onemade == FALSE && _isprint)
      {
        _DescrItem* d = new _DescrItem(ACCHEAD);
        d->_f0 = _basecalc == incorso;
        d->_f1 = _isbase;
        _descr_arr.add(d);
      }
      
      _nditte->curr().zero();
      _nditte->curr().put("CODDITTA",_ditte->row(l).get(1));
      _nditte->read();

      TApplication::set_firm(_nditte->curr().get_long("CODDITTA"));     
      
      _isbenzinaro = _nditte->curr(LF_ATTIV).get_bool("ART74_4");
      
      look_lia();
      _freqviva = _lia->get("S7"); 
      inf = _lia->get_real("R13");
      ina = _lia->get_real("R14");
      
      sprintf (buf,"Calcolo acconto:\nditta %s",
               (const char*)_nditte_r->get("RAGSOC"));
      _prind->set_text(buf);
      recalc_acconto(inf, ina);
      onemade = TRUE;
    }
    _prind->addstatus(1);
  }
  
  TApplication::set_firm(firm);
  delete _prind;
  return TRUE;
}

bool TLiquidazione_app::recalc_acconto(real& inf, real& ina)
{
  real bc = 0.0;
  real acc = 0.0;
  real cre = 0.0;
  real deb = 0.0;
  real iva_ven = 0.0;
  real iva_acq = 0.0;
  real iva_ret = 0.0;
  real iva_rim = 0.0;
  real ult_det = 0.0;
  real iva_pro = 0.0;
  real cre_pre = 0.0; 
  real acq_intr = 0.0;
  bool isdifferita = FALSE;
  bool error = FALSE;
  TString16 tipo_acc;
  
  // TBI rewrite from scratch
  // this is absolutely fundamental        
  if (_basecalc == precedente)
  {
    // determina casistica
    enum { mm, tt, mt, tm, boh } history = boh;
    char thh = *_freqviva;
    
    TString16 thyear = _year;
    _year = format("%d", atoi(_year)-1);
    
    if (!look_lia()) 
      error = 3;   
    else
    {
      char ohh = _lia->get_char("S7");
      
      if (ohh == 'M') history = thh == 'M' ? mm : mt;
      if (ohh == 'T') history = thh == 'M' ? tm : tt; 
      if (history == boh) return FALSE;
      
      // casino benzinari                      
      TString attprev = _nditte->curr().get("CODATTPREV"); 
      long codd = _nditte->curr().get_long("CODDITTA");
      TLocalisamfile& atts = _nditte->lfile(LF_ATTIV);
      atts.zero();
      atts.put("CODDITTA", codd);
      atts.put("CODATT",  attprev);
      if (atts.read() != NOERR) atts.zero();
      if (atts.get_bool("ART74_4"))   // e' proprio un gran benzinaro
      { 
        TConfig cnf(CONFIG_DITTA, "cg");
        history = cnf.get_bool("GesT74") ? mm : tt;
      }                                                                                 
      
      switch (history)
      {
      case mm:
        // base calcolo: 12a anno preced, Rideterminare a seconda dell'acconto
        // versato; ris = 88% del debito (0 se credito)
        if (!look_lim(12)) error = 2;
        else 
        { 
          bc += _lim->get_real("R0"); 
          real av = _lim->get_real("R11");   
          bc += av;
        }
        break;
      case tt:        
      case tm: 
        // base calcolo: 13a anno precedente. Rideterm. per eventuale acconto
        if (!look_lim(13)) error = 2;    // TBC sara' 13a davvero? Secondo me e' 12
        else 
        {
          bc += _lim->get_real("R0");
          real av = _lim->get_real("R11");   
          bc += av;  
        }
        if (_basecalc == tm) 
          // tm come tt ma si divide per 3 la base di calcolo prima di calcolare l'88%
          bc /= real(3.0);
        break;
      case mt:  
        // basecalcolo: 10, 11, 12 anno prec., 10 e 11 se a debito, 12 vedi acconto;
        // sommare e prendi 88% se a debito
        if (!look_lim(10)) error = 2;  
        else 
        { 
          real app = _lim->get_real("R0");
          if (app.sign() > 0) //a debito
            bc += app;
        }
        if (!look_lim(11)) error = 2;
        else 
        {
          real app = _lim->get_real("R0");
          if (app.sign() > 0) //a debito
            bc += app;
        }
        if (!look_lim(12)) error = 2;
        else 
        {
          bc += _lim->get_real("R0");
          real av = _lim->get_real("R11");   
          bc += av;  
        }
        break;
      }      
      
      if (bc.sign() > 0) //debito
      { 
        acc = bc * ACCONTO_DICEMBRE;
        acc.round(ROUND_LIRA);  
      }
      
      tipo_acc = "S";        
    }    
    _year = thyear;
  }
else if (_basecalc == incorso)
{      
  // that's pazzesc but as it turns out there's no better way
  _comp_acconto = TRUE;
  // force recalc of current month
  _recalc = one;               
  int need_refresh = FALSE;
  for (int mese = 1; mese < _month; mese++)
    if (is_month_ok_strict(mese) && (!look_lim(mese) || !_lim->get_bool("B0")))
    {
      need_refresh = TRUE; 
      break;
    }
  if (need_refresh && yesno_box("Alcuni mesi precedenti non "
                                "risultano ricalcolati. E' consigliabile il ricalcolo. "
                                "Si desidera eseguirlo?"))
    _recalc = ever;

  for (int m = 1; m <= _month; m++)  
    if (is_month_plain(m) || _recalc == ever)
    {               
      if (_prind->iscancelled()) break;
      update_firm(m);
    }

  // calcola l'acconto
  if (look_lim(12))  //posiziona anche la tabella lam
  {                     
    // bc = result_liq(12);
    // somma i non fatturati/non annotati 
    // bc += inf + ina;           
    cre = _lim->get_real("R12");
    
    //quando calcolo la 12° ci vado a sommare il 
    //versa. dovuto all'acconto 
    //allora devo ricalcolarmi l'effettivo credito
    cre -= _lim->get_real("R11");
    deb = _lim->get_real("R13") + inf + ina;
    
    bc = deb - cre;
    
    if (bc.sign() > 0) acc = bc; 
    
    // 11/09/1995
    iva_ven = _lam->get_real("R0"); //iva sulle vendite annotate fino al 20/12
    iva_acq = _lam->get_real("R1"); //iva sugli acquisti annotati fino al 20/12
    cre_pre = _lam->get_real("R2"); //credito precedente
    iva_ret = _lim->get_real("R5"); //rettifica
    iva_rim = _lim->get_real("R1"); //iva chiesta a rimborso
    ult_det = _lim->get_real("R6"); //ulteriori detrazioni 
    //iva_pro:                      //iva relativa alla percentuale di prorata
    TTable plm ("PLM");
    plm.zero();
    plm.put("CODTAB",_year);
    TRectype rec (plm.curr());
    plm.read(_isgteq);
    for (; !plm.eof(); plm.next())
    {
      if (plm.curr() != rec) break;
      iva_pro += plm.get_real("R2");
    }
    //acq_intr 
    TTable pom ("POM");
    pom.zero();
    pom.put("CODTAB",_year);
    rec = pom.curr();
    pom.read(_isgteq);
    for (; !pom.eof(); pom.next())
    {
      if (pom.curr() != rec) break;
      acq_intr += pom.get_real("R0");
    }
    tipo_acc = "A";                 //flag per dire che si e' utilizzato il metodo analitico
    //stop
  }
  else error = 1;

  // pulisci il water
  _comp_acconto = FALSE;  
  _isprint = FALSE;
  /*
     update_firm(12); 
  */
  for (int i = 1; i <= _month; i++)  
    if (is_month_plain(i))
      update_firm(i);
  
  //18/10/1995
  _lim->put("B0","");
  _lim->rewrite();
  if (look_lim(13))  
  {
   _lim->put("B0","");
   _lim->rewrite();
  }
  //fine    
  _isprint = TRUE;
}

// sbatti l'acconto (e non solo!) in LIA
if (look_lia())
{
  TConfig cnf(CONFIG_DITTA, "cg");
  isdifferita = cnf.get_bool("GeLiDi"); 
  if (isdifferita && _basecalc == incorso)
  {
    acc *= real(2.0);
    acc /= real(3.0);
  }
  _lia->put("R4",acc);
  _lia->put("R7",iva_ven);
  _lia->put("R8",iva_acq);
  _lia->put("R9",iva_ret);
  _lia->put("R10",iva_rim);
  _lia->put("R11",ult_det);
  _lia->put("R12",iva_pro); 
  TToken_string rr;
  rr.add(cre_pre.string(),0);
  rr.add(acq_intr.string(),1); 
  _lia->put("S1",rr);          
  _lia->put("S8",tipo_acc);
  _lia->rewrite();
}

/*** Non bisogna aggiornare la delega
  bool wasdel = look_del(12,7); 

  if (acc.sign() > 0 && acc >= ACCONTO_MINIMO_DA_VERSARE)
  {
  // crea o aggiorna delega  
  // TBC everything 
  look_del(12,7,TRUE);
  _del->put("R0", acc);
  _del->rewrite();
  }
  else if (wasdel)
  _del->remove();
  ***/

// per questa volta lasciamo perdere la describe_acconto
if (_isprint)
{
  // segnalazioni di errore da gesticolare: 
  // error = 0: no error
  // error = 1: manca tabella risultati liquidazione per l'anno indicato
  // error = 2: manca tabella risultati liquidazione per l'anno precedente  
  // error = 3: manca tabella dichiarazione annuale  per l'anno precedente
  _DescrItem* d = new _DescrItem(ACCONTO);
  d->_r0 = bc;
  d->_r1 = acc;
  d->_r2 = cre;
  d->_r3 = deb;
  d->_f0 = _basecalc == incorso;
  d->_f1 = _isbase;
  d->_f2 = error;
  d->_f3 = isdifferita;
  d->_s0 = _nditte->curr().get("CODDITTA");
  d->_s1 = _nditte->curr().get("RAGSOC");
  _descr_arr.add(d);
}  
return TRUE;
}

