// oggetto TCausale_magazzino
// oggetto TMov_Mag , multirecord del movimento di magazzino
//  funzione di ricostruzione saldi

#include <diction.h> 
#include <progind.h> 

#include "mglib.h" 
#include "movmag.h"
#include "rmovmag.h"
#include <cfven.h>

#ifndef __CGLIB01_H
#include "../cg/cglib01.h"
#endif
#ifndef __DBLIB_H
#include "../db/dblib.h"
#endif


// *********************
// movimenti di magazzino

// movimenti
// dati della linea di movimento di magazzino
class TLine_movmag : public TObject
{
  TString16 _codcaus;
  TString16 _um;
  real _quant;
  real _prezzo;

public: 
  const TString& codcaus() const {return _codcaus;}
  const TString& um()   const   {return _um;}
  const real& quant()    const    {return _quant;}
  const real& prezzo()    const   {return _prezzo;}
  void set(const TString& cau,const TString& um,const real& q, const real& p);
  int operator==(TLine_movmag &);
  
  virtual TObject* dup() const { return new TLine_movmag(*this); }
  
  TLine_movmag() {}; 
  TLine_movmag(const TLine_movmag &); 
  virtual ~TLine_movmag() {}; 
};

void TLine_movmag ::set(const TString& cau,const TString& um,const real& q, const real& p)
{
  _codcaus=cau;
  _um=um;
  _quant=q;
  _prezzo=p;
}

TLine_movmag ::TLine_movmag(const TLine_movmag &l)
{
  _codcaus=l._codcaus;
  _um=l._um;
  _quant=l._quant;
  _prezzo=l._prezzo;
}

int TLine_movmag::operator==(TLine_movmag &l)
{
  return (_codcaus==l._codcaus)&&(_um==l._um)&&(_quant==l._quant)&&(_prezzo==l._prezzo);
}


// ********************************
// TMov_mag  

TCausale_magazzino *TMov_mag::_causmag = NULL;

TMov_mag::TMov_mag() : 
  TMultiple_rectype(LF_MOVMAG),
  lines_to_add(), lines_to_subtract()
{   
  add_file(LF_RMOVMAG,"NRIG");
}

TMov_mag::~TMov_mag() 
{   
}

const TCausale_magazzino& TMov_mag::causale(const char* cod) const
{
  if (cod == NULL || *cod == '\0')
    cod = get(MOVMAG_CODCAUS);
  if (!_causmag)
    _causmag = new TCausale_magazzino(cod);
  else
    *_causmag = cache().get("%CAU",cod);
  return *_causmag;
}

void TMov_mag::zero(char c)
{
  TMultiple_rectype::zero(c);

  lines_to_add.destroy();   
  lines_to_subtract.destroy();
}

// valuta il valore della chiave per un nuovo record
bool TMov_mag::renum()
{
  put(MOVMAG_NUMREG,get_next_key());
  return TRUE;
}

// copia la chiave dal file principale a quello delle righe
void TMov_mag::set_body_key(TRectype & rowrec)
{
  rowrec.put(RMOVMAG_NUMREG,get(MOVMAG_NUMREG));
} 


void TMov_mag::load_rows_file(int logicnum)
{
  CHECK(logicnum==LF_RMOVMAG,"L'unico file collegabile ai movimenti sono le righe"); 
  TMultiple_rectype::load_rows_file(logicnum);
  mark_current_lines();
}


int TMov_mag::remove(TBaseisamfile& f) const 
{
  int res;
  if ((res=TMultiple_rectype::remove(f))==NOERR ) 
  {
    // effettua la variazione dei saldi
    ((TMov_mag *)this)->update_balances();  
  }
  return res;
}


void TMov_mag::add_extrarows() const
{
  add_autorows();
  add_explrows();
//  if (add_explrows())
//    add_autorows();
}

bool  TMov_mag::add_autorows() const
{
  bool added=FALSE;
  TString16 codmag;
  
  // aggiunge le righe automatiche
  for (int r = rows(); r > 0; r--) 
  {        
    TRecord_array & b = body();             
    TRectype & row = b[r];
    TString16 codcaus(row.get(RMOVMAG_CODCAUS));
    if (codcaus.empty())
      codcaus=get(MOVMAG_CODCAUS);
    const TCausale_magazzino& cau = causale(codcaus);
    codcaus=cau.caus_collegata();
    if (codcaus.not_empty())
    {
      const TCausale_magazzino& cau_coll = causale(codcaus);
      if (!row.get_bool(RMOVMAG_ESPLOSA))
      {
        // deve esserci una riga collegata
        if (!b.exist(r + 1) || b[r + 1].get_char(RMOVMAG_TIPORIGA) != riga_automatica)
        {
          // manca, la inserisco
          TRectype * linea_auto = new TRectype(row);
          
          codmag = codmag_rauto(r);
          if (codmag.empty())
            codmag = cau_coll.default_magdep();
          if (codmag.not_empty())
            linea_auto->put(RMOVMAG_CODMAG, codmag);
          const char * prezzo = prezzo_rauto(r);
          if (prezzo != NULL)
            linea_auto->put(RMOVMAG_PREZZO, prezzo);
          linea_auto->put(RMOVMAG_NRIG, r+1);     
          linea_auto->put(RMOVMAG_TIPORIGA, (char) riga_automatica);
          linea_auto->put(RMOVMAG_CODCAUS, codcaus);
          b.insert_row(linea_auto);
          added=TRUE;
        }
      }
    }
  } // ciclo righe
  return added;
}

bool TMov_mag::add_explrows() const
{
  TDistinta_tree  distinta;
  TArticolo       articolo;
  TArray boom;
  bool added=FALSE;

  // aggiunge le righe da explosione distinta
  for (int r = rows(); r > 0; r--) 
  {        
    TRecord_array & b = body();             
    TRectype & row = b[r];
    TString16 codcaus(row.get(RMOVMAG_CODCAUS));
    if (codcaus.empty())
      codcaus=get(MOVMAG_CODCAUS);
    const TCausale_magazzino& cau = causale(codcaus);
    if (cau.esplodente() && !b[r].get_bool(RMOVMAG_ESPLOSA))
    {
      const TString codart = row.get(RMOVMAG_CODART);
      const char tipo_costo = cau.get("S11")[0];
      const int livello = cau.get_int("I0");
      const TString4 umroot(row.get(RMOVMAG_UM));
      const int rigaprec = r - 1;
      const bool is_coll = r > 0 && b[r].get_char(RMOVMAG_TIPORIGA) == riga_automatica;
      // mancano le righe, le inserisco
      boom.destroy();
      bool ok=distinta.set_root(row);
      if (ok)
      { 
        bool stop_prod = cau.get_bool("B4");
        
        distinta.explode(boom, TRUE, RAGGR_EXP_NONE, livello, "A", 0, stop_prod);
        //TString codmag(codmag_rauto(r));
        real prezzo(prezzo_rauto(r));
        TRectype * linea_auto;
        for (int newrow=0; newrow < boom.items() ; newrow++)
        {       
          TRiga_esplosione & riga_esp=(TRiga_esplosione & )(boom[newrow]);
          linea_auto = new TRectype(row);
          linea_auto->put(RMOVMAG_CODART, riga_esp.articolo());
          linea_auto->put(RMOVMAG_LIVGIAC, riga_esp.giacenza());
          linea_auto->put(RMOVMAG_UM, riga_esp.um());
          linea_auto->put(RMOVMAG_QUANT, riga_esp.val());
          //if (codmag.not_empty())
          //  linea_auto->put(RMOVMAG_CODMAG, codmag);
          //if (!prezzo.is_zero())
          articolo.read(riga_esp.articolo());
          if (tipo_costo == 'U')
            prezzo = articolo.get_real(ANAMAG_ULTCOS1);
          else
            if (tipo_costo == 'S')
              prezzo = articolo.get_real(ANAMAG_COSTSTD);
          linea_auto->put(RMOVMAG_PREZZO, prezzo);
          linea_auto->put(RMOVMAG_NRIG, r+1+newrow);
          linea_auto->put(RMOVMAG_ESPLOSA, TRUE);

          char coll_type = articolo.get_char(ANAMAG_COLLTYPE);
          TString16 codmag;
            
          if (coll_type == 'M')
          {
            if (is_coll)
              codmag = b[rigaprec].get(RMOVMAG_CODMAG);
          }
          else
            if (coll_type == 'F')
            {                         
              TString key("F|");                   
                
              key << articolo.get(ANAMAG_CODFORN);
              codmag = cache().get(LF_CFVEN, key, CFV_CODMAG);
            }
            else
              if (coll_type == 'A')
                codmag = articolo.get(ANAMAG_CODMAG);
          if (codmag.not_empty())
            linea_auto->put(RMOVMAG_CODMAG, codmag);
          b.insert_row(linea_auto);
          added=TRUE;
        }
        // ora ci sono, mi basta eliminare la riga "padre"
        if (boom.items() > 0 )
        {
          if (boom.items() == 1 && codart == ((TRiga_esplosione &)boom[0]).articolo())
            error_box(FR("Movimento di magazzino %ld:\ndistinta %s ciclica"), get_long(MOVMAG_NUMREG),(const char *)codart);
          b.destroy_row(r,TRUE);
        }
        else
          message_box(FR("Movimento di magazzino %ld:\nimpossibile esplodere l'articolo %s"), get_long(MOVMAG_NUMREG),(const char *)codart);
      }
    }
  } // ciclo righe
  return added;
}

int TMov_mag::write(TBaseisamfile& f) const 
{
  int res;
  add_extrarows();
  if ((res=TMultiple_rectype::write(f))==NOERR ) 
  {
    TMov_mag &myself=((TMov_mag &)*this);
  
    const int nrows = rows();
    
    for (int i = 1; i <= nrows; i++)
      myself.line_inserted(line2key(i), line2data(i));    
      // effettua la variazione dei saldi
    myself.update_balances();  
  }
  return res;
}

int TMov_mag::rewrite(TBaseisamfile& f) const 
{
  int res;
  add_extrarows();
  if ((res=TMultiple_rectype::rewrite(f))==NOERR ) 
  {
    TMov_mag &myself=((TMov_mag &)*this);
    
    const int nrows = rows();
  
    for (int i = 1; i <= nrows; i++)
      myself.line_inserted(line2key(i), line2data(i));    
      // effettua la variazione dei saldi
    myself.update_balances();  
  }
  return res;
}

const char* TMov_mag::get_next_key()  
{
  static TString16 nextcod;
  TLocalisamfile f(LF_MOVMAG);
  f.last();
  long a = f.get_long(MOVMAG_NUMREG)+1;
  return nextcod.format("%ld", a);
}

bool TMov_mag::key_complete()
{
  const bool ok = head().get_long(MOVMAG_NUMREG) > 0L;
  return ok;
}

//*******
// gestione delle variazione dei saldi
//
//
int TMov_mag::force_update_bal()
{
  int res;
  // reset delle strutture per il controlli delle variazioni dei saldi
  mark_current_lines(FALSE);
  res=update_balances();  
  return res;
}

// restituisce il valore dei dati
TLine_movmag& TMov_mag::line2data(int nrig) const
{
  static TLine_movmag line; 
  TRecord_array & b = body();             
  const TRectype& r = b.row(nrig);
  const TString16 c = r.get(RMOVMAG_CODCAUS).blank() ? get(MOVMAG_CODCAUS) : r.get(RMOVMAG_CODCAUS);
  const TString16 u = r.get(RMOVMAG_UM);
  const real q = r.get_real(RMOVMAG_QUANT);
  const real p = r.get_real(RMOVMAG_PREZZO);

  line.set(c, u, q, p);
  return line;
}


TToken_string & TMov_mag::line2key(int numriga) const
{
  static TToken_string _key;
  TRecord_array & b = body();             
  const TRectype& r = b.row(numriga);
  TString16 nr;

  nr << numriga;           
  _key.cut(0);
  _key.add(r.get(RMOVMAG_CODART));
  _key.add(r.get(RMOVMAG_CODMAG));
  _key.add(r.get(RMOVMAG_LIVGIAC));
  _key.add(nr);
  return _key;
}

TString TMov_mag::key2field(TToken_string &key,const char *fieldname) 
{
  if (strcmp(fieldname,RMOVMAG_CODART)==0)
    return key.get(0);
  if (strcmp(fieldname,RMOVMAG_CODMAG)==0)
    return key.get(1);
  if (strcmp(fieldname,RMOVMAG_LIVGIAC)==0)
    return key.get(2);
  CHECKS(FALSE, "Nome di campo non appartenente al file righe mov ", fieldname);
  return EMPTY_STRING;
}


int TMov_mag::line_inserted(TToken_string &k, TLine_movmag &r)
{
  if (_annoes != get(MOVMAG_ANNOES) || _datacomp != get_date(MOVMAG_DATACOMP))
    lines_to_add.add(k,r);
  else
  {
    if (lines_to_subtract.is_key(k)&& (TLine_movmag &)lines_to_subtract[k]==r)
      // modifica annullata
      lines_to_subtract.remove(k);
    else      
      // linea modificata
      lines_to_add.add(k,r);
  }
  return 0;
}


int TMov_mag::line_deleted(TToken_string &k, TLine_movmag &r)
{
  if (_annoes != get(MOVMAG_ANNOES) || _datacomp != get_date(MOVMAG_DATACOMP))
    lines_to_subtract.add(k,r);
  else
  {
    if (lines_to_add.is_key(k)&& r==(TLine_movmag &)lines_to_add[k] )
      // modifica annullata
      lines_to_add.remove(k); 
    else
      // linea modificata
      lines_to_subtract.add(k,r);
  }
  return 0;
}


void TMov_mag::mark_current_lines(const bool as_deleted)
{
  const int nrows = rows(); // lasciare la riga qui perch� comporta il caricamento del body
  _annoes  =get(MOVMAG_ANNOES);
  _datacomp=get_date(MOVMAG_DATACOMP);
  lines_to_add.destroy();   
  lines_to_subtract.destroy();
  for (int i = 1; i<= nrows; i++)
  {
    if (as_deleted)
      line_deleted(line2key(i), line2data(i));    
    else
      line_inserted(line2key(i), line2data(i));    
  }
}


bool TMov_mag::unlock_anamag(const char *codart) 
{
  TLocalisamfile anamag(LF_ANAMAG);
  
  anamag.put(ANAMAG_CODART,codart);
  return (anamag.read(_isequal,_unlock)==NOERR);
}

bool TMov_mag::lock_anamag(const char *codart) 
{
  TLocalisamfile anamag(LF_ANAMAG);
  anamag.put(ANAMAG_CODART,codart);
  
  KEY key = K_ENTER;
  while (key != K_ESC)
  {
    if (anamag.read(_isequal,_testandlock)==NOERR) 
      return TRUE;

    TString mess;
    mess << TR("Il record di anagrafica dell'articolo '")<< codart << TR("' risulta essere gi� in uso.");
    TTimed_breakbox bbox((const char *)mess,10);

    key = bbox.run();  
  }
  return FALSE;
}


void TMov_mag::giac_putkey(TLocalisamfile & mag,TString16 annoes,TToken_string curr_key) 
{
  mag.zero(' ');    
  mag.put(MAG_ANNOES,annoes);
  mag.put(MAG_CODMAG,key2field(curr_key,RMOVMAG_CODMAG));
  mag.put(MAG_CODART,key2field(curr_key,RMOVMAG_CODART));
  mag.put(MAG_LIVELLO,key2field(curr_key,RMOVMAG_LIVGIAC));
}

// aggiorna tutti i saldi in base alle modifiche fatte.
//      il lock su anagrafica dovrebbe garantire il lock su tutte le 
//      giacenze dell'articolo
int TMov_mag::update_balances() 
{
  bool updated_bal=TRUE;
  TLocalisamfile mag(LF_MAG);

  mag.setkey(2);

  TString_array keys_to_add,keys_to_remove;

  lines_to_add.get_keys(keys_to_add);
  lines_to_subtract.get_keys(keys_to_remove);

  // aggiunge i saldi nuovi
  keys_to_add.sort();

  TToken_string* curr_key = (TToken_string*)keys_to_add.first_item();
  int nriga=1;
  while (curr_key)        
  { 
    const TString cod = key2field(*curr_key, RMOVMAG_CODART);
    
    if (curr_art.lock_and_prompt(cod))
    {
      // lock gained
      TLine_movmag & line_mov=(TLine_movmag &)lines_to_add[*curr_key];
      const TCausale_magazzino& causmag = causale(line_mov.codcaus());
      
      if (causmag.update_ultcos())
      {              
        const real prezzo = curr_art.convert_to_um(line_mov.prezzo(), line_mov.um(), NULL, false);
        curr_art.update_ultcosti(prezzo,get_date("DATACOMP"), get_long("NUMREG"),nriga++);
        curr_art.rewrite();
      }
      giac_putkey(mag,get(MOVMAG_ANNOES),*curr_key);
      if (mag.read()!=NOERR)
      {
        // non trovato: aggiungo
        giac_putkey(mag,get(MOVMAG_ANNOES),*curr_key);
        mag.put(MAG_NRIGA,1+curr_art.mag(get(MOVMAG_ANNOES)).rows());
        mag.write();
      } 
      // modifica questo record (e lo sblocca)
      update_balances(mag.curr(), line_mov, +1);
      /*// ottimizzazione :(cerca di sfruttare la lettura fatta per un eventuale saldo vecchio)
      // ci� causa la modifica dell'oggetto TMov_mag (il metodo non � pi� const)
      if (_annoes == get("ANNOES") 
          && lines_to_subtract.is_key(*curr_key)) {
        update_balances(mag.curr(),(TLine_movmag &)lines_to_subtract[*curr_key],-1);
        ((TMov_mag *)this)->lines_to_add.remove(*curr_key);
        ((TMov_mag *)this)->lines_to_subtract.remove(*curr_key);
      }*/
      mag.rewrite();
      // conclude la TRANSAZIONE prima di sbloccare il record dell'articolo
      TToken_string *rem_key=(TToken_string *)keys_to_remove.first_item();
      while ( rem_key)
      {
        if (key2field(*rem_key,RMOVMAG_CODART)==key2field(*curr_key,RMOVMAG_CODART)) {
          giac_putkey(mag,_annoes,*rem_key);
          if (mag.read()==NOERR)
          {
            update_balances(mag.curr(),(TLine_movmag &)lines_to_subtract[*rem_key],-1);
            mag.rewrite();
          } 
          keys_to_remove.remove_item();
        }       
        rem_key=(TToken_string *)keys_to_remove.succ_item();
      } 
      curr_art.unlock();
    }
    curr_key=(TToken_string *)keys_to_add.succ_item();
  } 
  // togli i saldi vecchi
  curr_key=(TToken_string *)keys_to_remove.first_item();

  while (curr_key)
  {
    if (curr_art.lock_and_prompt((const char *)key2field(*curr_key,RMOVMAG_CODART)))
    {
      giac_putkey(mag,_annoes,*curr_key);
      // modifica questo record (e lo sblocca)
      if (mag.read()==NOERR)
      {
        update_balances(mag.curr(),(TLine_movmag &)lines_to_subtract[*curr_key],-1);
        mag.rewrite();
      } 
      curr_art.unlock();
    }
    curr_key=(TToken_string *)keys_to_remove.succ_item();
  }
  mark_current_lines();

  return updated_bal;
}

// aggiorna i saldi del record corrente 
// in base alla causale e alla modifica fatta (con segno + o -)
int TMov_mag::update_balances(TRectype & magrec, const TLine_movmag &l,int rett_sign) 
{
  TLocalisamfile umart(LF_UMART);              
  umart.setkey(2);
  umart.put(UMART_CODART,magrec.get(MAG_CODART));
  umart.put(UMART_UM , l.um());
  const int err = umart.read();
  
  const real fc = err == NOERR ? umart.get_real(UMART_FC) : 1.0;
  const real qt = l.quant();
  
  real diff = real(rett_sign) * qt * fc; 
  if (err == NOERR && fc != 1.0)
  {
    umart.setkey(1);
    umart.put(UMART_CODART,magrec.get(MAG_CODART));
    umart.put(UMART_NRIGA , 1);
    if (umart.read() == NOERR)
      TArticolo::round_um(diff, umart.get(UMART_UM));
  }

  real diff_val = real(rett_sign) * qt * l.prezzo();
  
  // Se � una causale che movimenta il valore ma la qta � 0
  // anche diff_val avr� lo stesso valore, impostando 0 di conseguenza
  // anche nei campi relativi a VALACQ, VALRIM etc etc.
  // Quindi al limite come controllo finale su movimenti che movimentano la qta
  // nel caso il calcolo dia proprio ZERO, impostiamo diff_val all'importo del valore stesso
  const TCausale_magazzino& caus = causale(l.codcaus());
  if (qt == ZERO && caus.update_val())
    diff_val = real(rett_sign) * l.prezzo();
  
  if (caus.update_qta())
  {
    update_balance(magrec,"GIAC",diff* (real)caus.sgn(s_giac)); // update ..
    update_balance(magrec,"ACQ",diff* (real)caus.sgn(s_acq)); // update ..
    update_balance(magrec,"ENT",diff* (real)caus.sgn(s_ent));
    update_balance(magrec,"VEN",diff* (real)caus.sgn(s_ven));
    update_balance(magrec,"USC",diff* (real)caus.sgn(s_usc));
    update_balance(magrec,"ORDC",diff* (real)caus.sgn(s_ordc));
    update_balance(magrec,"ORDF",diff* (real)caus.sgn(s_ordf));
    update_balance(magrec,"RIM",diff* (real)caus.sgn(s_rim));
    update_balance(magrec,"SCARTI",diff* (real)caus.sgn(s_scart));
    update_balance(magrec,"INCL",diff* (real)caus.sgn(s_incl));
    update_balance(magrec,"ACL",diff* (real)caus.sgn(s_acl));
    update_balance(magrec,"PRODCOMP",diff* (real)caus.sgn(s_prodc));
    update_balance(magrec,"PRODFIN",diff* (real)caus.sgn(s_prodf));
    update_balance(magrec,"NLABEL",diff* (real)caus.sgn(s_label));
    update_balance(magrec,"USER1",diff* (real)caus.sgn(s_user1));
    update_balance(magrec,"USER2",diff* (real)caus.sgn(s_user2));
    update_balance(magrec,"USER3",diff* (real)caus.sgn(s_user3));
    update_balance(magrec,"USER4",diff* (real)caus.sgn(s_user4));
    update_balance(magrec,"USER5",diff* (real)caus.sgn(s_user5));
    update_balance(magrec,"USER6",diff* (real)caus.sgn(s_user6));
  }
  if (caus.update_val())
  {
    update_balance(magrec,"VALACQ",diff_val* (real)caus.sgn(s_acq)); // update ..
    update_balance(magrec,"VALENT",diff_val* (real)caus.sgn(s_ent));
    update_balance(magrec,"VALVEN",diff_val* (real)caus.sgn(s_ven));
    update_balance(magrec,"VALUSC",diff_val* (real)caus.sgn(s_usc));
    update_balance(magrec,"VALORDC",diff_val* (real)caus.sgn(s_ordc));
    update_balance(magrec,"VALORDF",diff_val* (real)caus.sgn(s_ordf));
    update_balance(magrec,"VALRIM",diff_val* (real)caus.sgn(s_rim));
    update_balance(magrec,"VALSCARTI",diff_val* (real)caus.sgn(s_scart));
    update_balance(magrec,"USERVAL1",diff* (real)caus.sgn(s_user1));
    update_balance(magrec,"USERVAL2",diff* (real)caus.sgn(s_user2));
    update_balance(magrec,"USERVAL3",diff* (real)caus.sgn(s_user3));
    update_balance(magrec,"USERVAL4",diff* (real)caus.sgn(s_user4));
    update_balance(magrec,"USERVAL5",diff* (real)caus.sgn(s_user5));
    update_balance(magrec,"USERVAL6",diff* (real)caus.sgn(s_user6));
  }
  return 0;
}

int TMov_mag::update_balances(TRectype& magrec, int numrig, int rett_sign) 
{
  const TLine_movmag& lmm = line2data(numrig);
  return update_balances(magrec, lmm, rett_sign);
}

HIDDEN TEsercizi_contabili _esercizi;

int TMov_mag::codice_esercizio(const TDate &d)
{
  return _esercizi.date2esc(d);
}

void TMov_mag::update_balance(TRectype & magrec, const char * fieldname, real diff) const
{
  magrec.put(fieldname,magrec.get_real(fieldname)+diff);
}

void zero_balances(TRectype & mag)
{
  mag.put(MAG_GIAC,0);
  mag.put(MAG_RIM,0);mag.put(MAG_VALRIM,0);
  mag.put(MAG_ACQ,0);mag.put(MAG_VALACQ,0);
  mag.put(MAG_ENT,0);mag.put(MAG_VALENT,0);
  mag.put(MAG_VEN,0);mag.put(MAG_VALVEN,0);
  mag.put(MAG_USC,0);mag.put(MAG_VALUSC,0);
  mag.put(MAG_ORDF,0);mag.put(MAG_VALORDF,0);
  mag.put(MAG_ORDC,0);mag.put(MAG_VALORDC,0);
  mag.put(MAG_SCARTI,0);mag.put(MAG_VALSCARTI,0);
  mag.put(MAG_PRODCOMP,0);
  mag.put(MAG_PRODFIN,0);
  mag.put(MAG_INCL,0);
  mag.put(MAG_ACL,0);
  mag.put(MAG_NLABEL,0);
}

void copy_oldbalances(const TRectype& oldmag,TRectype & mag)
{
  mag.put(MAG_GIAC,oldmag.get(MAG_GIAC));
  mag.put(MAG_RIM,oldmag.get(MAG_RIM));
  mag.put(MAG_VALRIM,oldmag.get(MAG_VALRIM));
  mag.put(MAG_ACQ,0);
  mag.put(MAG_VALACQ,0);
  mag.put(MAG_ENT,0);
  mag.put(MAG_VALENT,0);
  mag.put(MAG_VEN,0);
  mag.put(MAG_VALVEN,0);
  mag.put(MAG_USC,0);
  mag.put(MAG_VALUSC,0);
  mag.put(MAG_ORDF,oldmag.get(MAG_ORDF));
  mag.put(MAG_VALORDF,oldmag.get(MAG_VALORDF));
  mag.put(MAG_ORDC,oldmag.get(MAG_ORDC));
  mag.put(MAG_VALORDC,oldmag.get(MAG_VALORDC));
  mag.put(MAG_SCARTI,0);
  mag.put(MAG_VALSCARTI,0);
  mag.put(MAG_PRODCOMP,oldmag.get(MAG_PRODCOMP));
  mag.put(MAG_PRODFIN,oldmag.get(MAG_PRODFIN));
  mag.put(MAG_INCL,oldmag.get(MAG_INCL));
  mag.put(MAG_ACL,oldmag.get(MAG_ACL));
  mag.put(MAG_NLABEL,0);
}

//**********************
bool rebuild_balances(const TString& annoes,
  const TTipo_valorizz tipo_valorizz, const char* catven, const char* codlis)
{

  TRelation rel(LF_MOVMAG); // relazione con un solo file (LF_MOVMAG) ma col record Head_Body
  TMov_mag * m_m= new TMov_mag; // record del movimento di magazzino
  rel.lfile().set_curr(m_m);

  TRelation rel2(LF_ANAMAG); // relazione con un solo file (LF_ANAMAG) ma col record Head_Body
  TArticolo_giacenza * a_g= new TArticolo_giacenza; // record dell'articolo di magazzino
  rel2.lfile().set_curr(a_g);

  bool ok=TRUE;
  // Aggiorna il cazzillo per caricare eventuali date di chiusura e altre amenita' simili
  TEsercizi_contabili esercizi;
  esercizi.update();

  const int cod_pred_es = esercizi.pred(atoi(annoes));
  TString16 pred_es;  pred_es.format("%d",cod_pred_es);
  const bool reset_giac = cod_pred_es != 0 ? esercizi.esercizio(cod_pred_es).chiusura_mag().ok() : TRUE;

  TString information;
  // azzera tutte giacenze (ciclo sulle giacenze)
  TCursor cur2(&rel2);
  const long maxart=cur2.objects();
  
  if (maxart > 0)
  {
    information.format(FR("Ricostruzione saldi esercizio %s: azzeramento..."),(const char *)annoes);
    TProgind barra_art(maxart,information, FALSE, TRUE);
    cur2.freeze();
    for (long a=0; a<maxart; a++) 
    {
      barra_art.addstatus(1);
      cur2=a;
      TArticolo_giacenza & articolo=(TArticolo_giacenza &)cur2.curr();
      if (articolo.lock_and_prompt(articolo.codice()))
      {
        if (reset_giac)
          articolo.azzera_saldi(annoes);
        else
          articolo.riporta_saldi(pred_es, annoes, tipo_valorizz, catven, codlis);
        articolo.unlock();
      }
    } 
  }
  
  // ricostruisce i saldi (ciclo sui movimenti)
  TString filterexpr;
  filterexpr << LF_MOVMAG << "->ANNOES==" << annoes;  
  TCursor cur(&rel,filterexpr); // cursore filtrato
  const long maxmov=cur.objects();
  if (maxmov > 0)
  {
    cur.freeze();
    information.format(FR("Ricostruzione saldi esercizio %s: ricalcolo ..."),(const char *)annoes);
    TProgind barra_mov(maxmov,information, FALSE, TRUE);
    TMov_mag & mov_rec=(TMov_mag &)cur.curr();
    for (long m=0; m<maxmov; m++) 
    {
      barra_mov.addstatus(1);
      cur=m;
      if (!mov_rec.force_update_bal())
        ok=FALSE;
    }
  }  
  return ok;
}