// oggetto TArticolo, multirecord dell'articolo di anagrafica magazzino
// oggetto TArticolo_giacenza, multirecord dell'articolo di magazzino
// oggetto TMov_Mag , multirecord del movimento di magazzino
//  funzione di ricostruzione saldi
#include <currency.h>
#include <dongle.h>
#include <modaut.h>
#include <progind.h>
#include <tabutil.h>

#include "mglib.h" 

#include "anamag.h"
#include "mag.h"
#include "movmag.h"
#include "rmovmag.h"

#include "..\cg\cglib01.h"
#include "..\ve\veconf.h"

// libreria per i movimenti
class TTimed_skipbox: public TTimed_breakbox
{
public:
  TTimed_skipbox(const char * message,int seconds,int x=40,int y=10);
  ~TTimed_skipbox();
};

TTimed_skipbox:: TTimed_skipbox(const char * message,int seconds,int x,int y)
               : TTimed_breakbox(message,seconds,x,y)
{
  hide(DLG_CANCEL);
  add_button(DLG_CANCEL, 0, "Ignora", -22, -1, 12, 2,"",0);
}

TTimed_skipbox::~TTimed_skipbox()
{}

char* Nome_valorizz[16] =
{
  "Ultimo costo", "Media ultimi costi", "Prezzo di listino",
  "Costo standard", "Costo medio acquisto" , 
  "Costo medio ponderato" ,
  "FIFO annuale", "LIFO annuale",
  "FIFO", "LIFO",
  "FIFO Ragionieristico", "LIFO Ragionieristico"
} ;

HIDDEN TString16 _mg_null_str;

const TString & TArticolo::get_str(const char* fieldname) const
{                 
  if (*fieldname != '#')
    return TRectype::get_str(fieldname);
  char * fname = (char *) fieldname + 1;
  const int logicnum = atoi(fname);
  const char * op1 =  strchr(fname, '_');
  int index = 0;
  if (op1)
  {
    op1=op1+1;
    if (*op1 == '#')
      index = atoi(fname + 1);
  }
  const char* op2 = strstr(fname, "->"); 
  CHECKS(op2, "Can't find '->' in string ", fieldname);
  op2=op2+2;

  switch (logicnum)
  {
    case LF_UMART:
      { 
        if (index == 0)
          index = find_um(op1);
        if (index > 0 && op2)
          return um().row(index).get(op2);
      }
      break;
    case LF_CODCORR:
      {
        if (index == 0)
          index = find_codcorr(op1);
        if (index > 0 && op2)
          return codcorr().row(index).get(op2);
      }
      break;
    case LF_DESLIN:
      {
        if (index == 0)
          index = find_deslin(op1);
        if (index > 0 && op2)
          return deslin().row(index).get(op2);
      }
      break;
    default:
      break;
  }     
  return EMPTY_STRING;
}

void TArticolo::set_body_key(TRectype & rowrec)
{
  const int logicnum = rowrec.num();
  const TString& cod = codice();
  
  switch (logicnum)
  { 
    case LF_UMART:
      rowrec.put(UMART_CODART, cod);
      break;
    case LF_DESLIN:
      rowrec.put(DESLIN_CODART, cod);
      break;
    case LF_CODCORR:
      rowrec.put(CODCORR_CODART, cod);
      break;
    default:
      break;
  }
}

int TArticolo::read(TRectype & rec, word op, word lockop)
{ 
  const TString80 compstr(rec.get(ANAMAG_CODART));
  if (op == _isequal && lockop == _nolock && codice() == compstr)
    return NOERR;

  put(ANAMAG_CODART, compstr);
  const int err = TMultiple_rectype::read(rec, op , lockop);

  if (err != NOERR)
    zero();                                   
  return err;  
}

int TArticolo::read(const char * cod, word op, word lockop)
{                             
  TRectype tmp(*this);
  tmp.put(ANAMAG_CODART,cod);
  return read( tmp, op, lockop); 
}

const TString& TArticolo::codice() const 
{ 
  ((TArticolo *)this)->_codice=get(ANAMAG_CODART); 
  return _codice;
}  

const TString & TArticolo::descrizione(const char* lingua) const
{
  if (lingua && *lingua)
  {    
    TString16 f; f.format("#%d_%s->%s", LF_DESLIN, lingua, DESLIN_DESCR);
    return get(f);
  }
  return get(ANAMAG_DESCR);
}

void TArticolo::update_ultcosti(const real& costo, const TDate& data, long numreg, int _unused_)
{
  const TDate data1(get_date(ANAMAG_DULTCOS1));
  const TDate data2(get_date(ANAMAG_DULTCOS2));
  // modificato il 2-2-1999; 
  const long numreg1 = get_long(ANAMAG_NUMREG1);
  const long numreg2 = get_long(ANAMAG_NUMREG2);
  if (data >= data1 || (numreg == numreg1 &&  // movimento piu' recente o aggiornamento dello stesso movimento ...
      (data > data2 || numreg > numreg2)))    // ... e "data" superiore al penultimo
  {
    const real costo1(get_real(ANAMAG_ULTCOS1));
    put(ANAMAG_ULTCOS1,costo);
    put(ANAMAG_DULTCOS1,data);
    put(ANAMAG_NUMREG1,numreg);
    if (numreg != numreg1 && (data > data1 || numreg > numreg1))
    {
      // trasforma l'ultimo costo in penultimo
      put(ANAMAG_ULTCOS2,costo1);
      put(ANAMAG_DULTCOS2,data1);
      put(ANAMAG_NUMREG2,numreg1);
    }
  }
  else
  {
    const real costo2 = get_real(ANAMAG_ULTCOS2);
    if (data >= data2 || numreg == numreg2 || numreg == numreg1)
    {
      put(ANAMAG_DULTCOS2,data);
      put(ANAMAG_ULTCOS2,costo);
      put(ANAMAG_NUMREG2,numreg);
    }
    if (numreg == numreg1 )
    {
      // trasforma il penultimo costo in ultimo 
      put(ANAMAG_ULTCOS1,costo2);
      put(ANAMAG_DULTCOS1,data2);
      put(ANAMAG_NUMREG1,numreg2);
    }
  } 
}

void TArticolo::set_prezzo_vendita(const real& prezzo, const char* unita)
{
  TPrice p;   // Arrotondatore automatico
  
  if (unita && *unita)
  {
    const int i = find_um(unita);
    if (i > 0)    
    {
      TRectype& rec = (TRectype&)um().row(i);
      p.set_num(prezzo);
      rec.put(UMART_PREZZO, p.get_num());
    }  
  }
  else
  {
    TString16 codum;
    for (int i = um().rows(); i > 0; i--)  
    {                                     
      TRectype& rec = (TRectype&)um().row(i);
      codum = rec.get(UMART_UM);
      if (i == 1) 
        p.set_num(prezzo);
      else
        p.set_num(convert_to_um(prezzo, codum));
      rec.put(UMART_PREZZO, p.get_num());
    }
  }  
}

bool TArticolo::unlock() 
{
  bool rv;
  if (codice().not_empty())
  {
    static TLocalisamfile *anag=NULL; if (anag==NULL) anag= new TLocalisamfile(LF_ANAMAG);
    rv=(anag->read(*this, _isequal,_unlock)==NOERR);
    return rv;
  } 
  return FALSE;
}

bool TArticolo::lock_and_prompt(const char * cod) 
{
  TString mess;
  int err;

  do
  {
    if (cod && *cod)
      err = read(cod,_isequal,_testandlock);
    else
      err = _iskeyerr;
    switch (err)
    {
      case NOERR:
        return TRUE;
      case _iskeyerr:
        mess << "Il codice articolo ''" << cod << "'' non e' valido";
        break;
      case _islocked:
        mess.cut(0);
        mess << "Il record di anagrafica\ndell'articolo ''" << cod << "'' e' gia' usato da un altro programma. Scegliere se ritentare la lettura o ignorare l'articolo.";
        break;
      case _iskeynotfound:
        mess.cut(0);
        mess << "Il record di anagrafica\ndell'articolo ''"<< cod << "'' non esiste.";  
        //error_box(mess);
        //return FALSE;
        break;
      default:
        mess.cut(0);
        mess << "Non riesco ad accedere al\nrecord di anagrafica dell'articolo ''"<< cod << "'' - errore " << err << ".";
    }
    TTimed_skipbox bbox((const char *)mess,10);
    if (bbox.run()==K_ESC)
      return FALSE;
  } while (TRUE);
  return FALSE;
}

real TArticolo::convert_to_um(const real& v, const char * to_um, const char * from_um)
{
  // Se from_um non specificato significa che la qta che si desidera convertire e' in UM base
  int i1, i2 = 0;
  i1 = find_um(to_um);
  
  if (from_um != NULL)
    i2 = find_um(from_um);
  
  TRecord_array& u = um();
  real fc1 = i1 ? ((TRectype&)u[i1]).get_real("FC") : 1.00; // Fattore di conversione 
  real fc2 = i2 ? ((TRectype&)u[i2]).get_real("FC") : 1.00; 
  real r = (v * fc2) / fc1;  
  // TBI: ricerca sulla tabella UMS nel caso di um non presenti in LF_UMART
  
  return r;
}

TArticolo::TArticolo(const char* codice)
       : TMultiple_rectype(LF_ANAMAG)
{ 
  add_file(LF_UMART,"NRIGA");
  add_file(LF_CODCORR,"NRIGA");
  add_file(LF_DESLIN,"NRIGA");
  if (codice && *codice)
  {
    int err=read(codice);
    if (err!=NOERR)
      error_box("Impossibile leggere l'articolo %s: Errore %d",codice, err);
  }    
}

TArticolo::TArticolo(const TRectype& rec)
       : TMultiple_rectype(rec)
{ 
  add_file(LF_UMART,"NRIGA");
  add_file(LF_CODCORR,"NRIGA");
  add_file(LF_DESLIN,"NRIGA");
  read(rec.get(ANAMAG_CODART));
}

TArticolo::~TArticolo() 
{
}

// *****************
// TArticolo_giacenza

const TString & TArticolo_giacenza::get_str(const char* fieldname) const
{ 
  if (*fieldname != '#')
    return TRectype::get_str(fieldname);
  char * fname = (char *) fieldname + 1;
  const int logicnum = atoi(fname);
  if (logicnum !=LF_MAG && logicnum !=LF_STOMAG)
      return TArticolo::get_str(fieldname);

  const char * op1 =  strchr(fname, '_');
  int index = 0;
  if (op1)
  {
    op1=op1+1;
    fname = (char *) op1;
    if (*op1 == '#')
      index = atoi(fname + 1);             
  }
  const char * op2 = strchr(fname, '_');
  if (op2) 
  {
    op2=op2+1;
    fname = (char *) op2 + 1;
  }
  const char * op3 = strchr(fname, '_');
  if (op3)
    op3=op3+1;
  const char * op4 = strstr(fname, "->"); 
  CHECKS(op4, "Can't find '->' in string ", fieldname);
  op4=op4+2;
       
  switch (logicnum)
  {
    case LF_MAG:
      if (index == 0)
        index = find_mag(op1, op2, op3);
      if (index > 0 && op3)
        return mag(op1).row(index).get(op4);
      break;
    case LF_STOMAG:
      if (index = 0)
        index = find_storico(op1);
      if (index > 0)
        return storico(op1).row(index).get(op4);
      break;
  }    
  return EMPTY_STRING;
}

void TArticolo_giacenza::set_body_key(TRectype & rowrec)
{
  const int logicnum = rowrec.num();
  const char * cod = (const char *) codice();
  
  switch (logicnum)
  { 
    case LF_STOMAG:
      rowrec.put(STOMAG_CODART, cod);
      rowrec.put(STOMAG_ANNOESRIF, _anno_sto);
      break;
    case LF_MAG:
      rowrec.put(MAG_ANNOES, _anno_mag);
      rowrec.put(MAG_CODART, cod);
      break;
    default:
      TArticolo::set_body_key(rowrec);
      break;
  }
}

void TArticolo_giacenza::set_anno_mag (const char * anno)
{
  if (_anno_mag != anno)
    remove_body(LF_MAG);
  _anno_mag = anno;
}

void TArticolo_giacenza::set_anno_sto (const char * anno)
{
  if (_anno_sto != anno)
    remove_body(LF_STOMAG);
  _anno_sto = anno;
}                       

void TArticolo_giacenza::zero(char c)
{                    
  reset_anno_sto();
  reset_anno_mag();
  TArticolo::zero(c);
}

int TArticolo_giacenza::find_mag(TRecord_array& rmag, const char * codmag, const char * livello, int from) const
{
  const int last = rmag.last_row();

  if (last > 0 && from < last)
  {
    const int codmag_len = codmag  ? strlen(codmag) : 0;
    const int livello_len = livello ? strlen(livello) : 0;   
    
    if (codmag_len == 0 && livello_len == 0)
      return from + 1;

    for (int i = rmag.succ_row(from); i <= last; i = rmag.succ_row(i))
    {
      const TRectype & rec = rmag.row(i);
    
      if (codmag_len == 0 || rec.get(MAG_CODMAG).compare(codmag, codmag_len) == 0)  
        if (livello_len == 0 || rec.get(MAG_LIVELLO).compare(livello, livello_len) == 0)
         return i;
    }
  }
  return -1;
}

int TArticolo_giacenza::find_mag(const char * annoes, const char * codmag, const char * livello, int from) const
{
  TRecord_array & rmag = mag(annoes);
  return find_mag(rmag, codmag, livello, from);  
}

int TArticolo_giacenza::find_storico(TRecord_array& rsto, const char * codmag, int from) const
{
  const int last = rsto.last_row();
  
  if (last > 0 && from <= last)
  {
    const int codmag_len = codmag  ? strlen(codmag) : 0;
    
    if (codmag_len == 0)
      return from + 1;

    for (int i = rsto.succ_row(from); i <= last; i = rsto.succ_row(i))
    {
      const TRectype & rec = rsto.row(i);
    
      if (rec.get(STOMAG_CODMAG).compare(codmag, codmag_len) == 0)
         return i;
    }
  }
  return -1;
}

int TArticolo_giacenza::find_storico(const char * annoesrif, const char * codmag, int from) const
{
  TRecord_array & rsto = storico(annoesrif);
  return find_storico(rsto, codmag, from);
}

TRecord_array & TArticolo_giacenza::mag(const char * annoes) const
{
  TString16 anno = annoes;
  if (anno.blank())
  {
    TEsercizi_contabili ese;
    anno.format("%04d", ese.last_mag());
  }
  ((TArticolo_giacenza*)this)->set_anno_mag(anno);
  return body(LF_MAG);
}

TRecord_array & TArticolo_giacenza::storico(const char * annoesrif) const
{
  TString16 anno = annoesrif;
  if (anno.blank())
  {
    TEsercizi_contabili ese;
    anno.format("%04d", ese.last_mag());
  }
  ((TArticolo_giacenza *) this)->set_anno_sto(anno); 
  return body(LF_STOMAG);
}

bool TArticolo_giacenza::is_last_esercizio(const char* annoes) const
{
  bool yes = TRUE;
  if (annoes && *annoes)
  {
    const int anno = atoi(annoes);
    if (anno > 0)
    {
      TEsercizi_contabili e;
      yes = !e.esercizio(anno).chiusura_mag().ok() ;
    }
  }
  return yes;
}

bool TArticolo_giacenza::azzera_saldi(const char* cod_es, bool save_to_disk)
{
  TRecord_array& rec_arr = TArticolo_giacenza::mag(cod_es);

  const int last = rec_arr.last_row();
  for (int r = last;r > 0 ; r = rec_arr.pred_row(r)) // Scorre le righe
  {
    TRectype& mag = rec_arr[r];

    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);
  }
  return save_to_disk ? (rec_arr.write(TRUE) == NOERR) : TRUE;
}
                 
bool TArticolo_giacenza::riporta_saldi(const char * oldes, const char* newes, const TTipo_valorizz tipo, 
                                       const char* catven, const char* codlis, bool save_to_disk)
{
  TString codes(newes), mag, liv;
  TRecord_array& rec_arr = TArticolo_giacenza::mag(oldes);
  const int last = rec_arr.last_row();
  real rim, val, giac, inpf, proc, icl, acl;
  TCurrency currency(ZERO, "_FIRM");

  rec_arr.renum_key(MAG_ANNOES, codes); // Rinumera 
  for (int r = last;r > 0 ; r = rec_arr.pred_row(r)) // Scorre le righe
  {
    TRectype& rec = rec_arr[r];
    mag  = rec.get(MAG_CODMAG); mag.cut(3);
    liv  = rec.get(MAG_LIVELLO);
    giac = rec.get_real(MAG_GIAC); 
    inpf = rec.get_real(MAG_PRODFIN);
    proc = rec.get_real(MAG_PRODCOMP);
    acl  = rec.get_real(MAG_ACL);
    icl  = rec.get_real(MAG_INCL);
    rim = giac + inpf - proc + acl - icl;
    switch (tipo)
    {
      case valorizz_costmedio:
        val = costo_medio(oldes, mag, liv);
        break;
      case valorizz_costmediopond:
        val = costo_mediopond(oldes, mag, liv);
        break;
      case valorizz_ultcos: 
        val = ultimo_costo(oldes);
        break;
      case valorizz_mediacos:
        val = media_costi(oldes);
        break;
      case valorizz_przlist:
        val = prezzo_listino(oldes, catven, codlis);
        break;
      case valorizz_coststd:
        val = costo_standard(oldes);
        break;
      case valorizz_FIFOa:
        val = FIFO_annuale(oldes, mag, liv);
        break;
      case valorizz_LIFOa:
        val = LIFO_annuale(oldes, mag, liv);
        break;
      case valorizz_FIFO:
        val = FIFO(oldes, mag, liv);
        break;
      case valorizz_LIFO:
        val = LIFO(oldes, mag, liv);
        break;
      case valorizz_FIFOr:
        val = FIFO_ragionieristico(oldes, mag, liv);
        break;
      case valorizz_LIFOr:
        val = LIFO_ragionieristico(oldes, mag, liv);
        break;
      default:
        break;
    }
    // Setta il prezzo al nr di decimali fissati per i prezzi della valuta corrente
    if (tipo < valorizz_FIFOa)
    {
      currency.set_price(TRUE);
      currency.set_num(val);
      val = currency.string();
    }
    val *= rim;

    // Setta l'importo al nr di decimali fissati per gli importi della valuta corrente
    currency.set_price(FALSE);
    currency.set_num(val);
    val = currency.string();
    rec.put(MAG_RIM, rim); rec.put(MAG_VALRIM, val);
    rec.zero(MAG_ACQ); rec.zero(MAG_VALACQ);
    rec.zero(MAG_ENT); rec.zero(MAG_VALENT);
    rec.zero(MAG_VEN); rec.zero(MAG_VALVEN);
    rec.zero(MAG_USC); rec.zero(MAG_VALUSC);
    rec.zero(MAG_SCARTI);
    if (!riporta_ordinato())
    {
    	rec.zero(MAG_ORDF); rec.zero(MAG_VALORDF);
    	rec.zero(MAG_ORDC); rec.zero(MAG_VALORDC);
    }
  }
  
  // Per non perdere le modifiche in memoria, al fine di avere i saldi riportati correttamente
  // visto che non vengono salvati e poi riletti da disco, li si salvano nel TRecord_array
  // dell'esercizio newes
  if (!save_to_disk)
  {
    TRecord_array  copia(rec_arr);
    TRecord_array& nuovo = TArticolo_giacenza::mag(codes);
    
    if (copia.rows() > 0)
      nuovo = copia;
    else
      azzera_saldi(codes, FALSE);
  }
  
  // Scrive il pastrocchio (eventualmente sovrascrive)
  return save_to_disk ? (rec_arr.write(TRUE) == NOERR) : TRUE;
}

real TArticolo_giacenza::disponibilita(const char * annoes, const char * codmag, const char * livello, bool solo_giac) const
{  
  real giac;

  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, livello); i > 0; 
    i = find_mag(annoes, codmag, livello, i)) 
  {                                    
    const TRectype & rec = rmag.row(i);
    giac += rec.get_real(MAG_GIAC);
    if (!solo_giac)
    {
      giac += rec.get_real(MAG_ORDF) - rec.get_real(MAG_ORDC);
      giac += rec.get_real(MAG_PRODFIN) - rec.get_real(MAG_PRODCOMP);
      giac += rec.get_real(MAG_ACL) - rec.get_real(MAG_INCL);
    }
  }
  if (!solo_giac && !riporta_ordinato())      // Se l-ordinato viene riportato
  {                                 
    TEsercizi_contabili ese;
    const int prev = ese.pred(atoi(annoes));     // Controllo anche l'anno precedente
    if (prev > 0)                        
    {
      TString16 oldannoes;  oldannoes.format("%04d", prev);
      const TRecord_array& oldrmag = mag(oldannoes);
      for (int i = find_mag(oldannoes, codmag, livello); i > 0; 
        i = find_mag(oldannoes, codmag, livello, i)) 
      {                                    
        const TRectype& rec = oldrmag.row(i);
        giac += rec.get_real(MAG_ORDF);  // Sommo l'ordinato fornitori
        giac -= rec.get_real(MAG_ORDC);  // Sottraggo l'ordinato clienti
      }
    }
  }
  return giac;
}

real TArticolo_giacenza::ultimo_costo(const char * annoes) const  
{
  if (is_last_esercizio(annoes))                          
  {
    const real costo = get_real(ANAMAG_ULTCOS1);
    return costo == ZERO ? costo_standard(annoes) : costo;
  }
  else                                                   
  {
    const int index = find_storico(annoes); 
    if (index < 0 ) return ZERO;
    const real costo = storico(annoes).row(index).get_real(STOMAG_ULTCOS1);
    return costo == ZERO ? costo_standard(annoes) : costo;
  }
}

real TArticolo_giacenza::media_costi(const char * annoes) const
{
  if (is_last_esercizio(annoes))
  {
    real costo = get_real(ANAMAG_ULTCOS1);
    costo = (costo + get_real(ANAMAG_ULTCOS2)) / 2.0;
    return costo == ZERO ? costo_standard(annoes) : costo;
  }
  else
  {           
    const int index = find_storico(annoes); 
    if (index < 0 ) return ZERO;
    const TRectype & rec = storico(annoes).row(index);
    real costo = rec.get_real(STOMAG_ULTCOS1);
  
    costo = (costo + rec.get_real(STOMAG_ULTCOS2)) / 2.0;
    return costo == ZERO ? costo_standard(annoes) : costo;
  }
}

real TArticolo_giacenza::prezzo_listino(const char * annoes, const char * catven, const char * codlist) const
{            
  if (is_last_esercizio(annoes))
  {
    TString codart=codice();
    TConfig cfg(CONFIG_DITTA);
    if (codlist && *codlist>' ')
    {
      TCondizione_vendita cv(&cfg);
      cv.put_listino(codlist,catven);
      if (cv.ricerca(codart))
        return cv.get_prezzo();
    }
    // se non lo trova, cerca nel prezzo indicato nelle UM
    TString16 f;
    f.format("#%d->%s", LF_UMART, UMART_PREZZO);
    return get_real(f); 
  }
  else
  {
    const int index = find_storico(annoes); 
    if (index < 0 ) return ZERO;
    return storico(annoes).row(index).get_real(STOMAG_PRZLIST);
  }
}

real TArticolo_giacenza::costo_standard(const char * annoes) const
{ 
  if (is_last_esercizio(annoes))
    return get_real(ANAMAG_COSTSTD);
  else
  {
    const int index = find_storico(annoes); 
    if (index < 0 ) return ZERO;
    return storico(annoes).row(index).get_real(STOMAG_COSTSTD);
  }
}


real TArticolo_giacenza::costo_medio(const char * annoes, const char * codmag, const char * livello) const
{  
  real acq;
  real valacq;                       
  
#ifdef DBG
  if (strlen(codmag)>3)
    NFCHECK("Non � pi� possibile avere valorizzazione a livello di deposito");
#endif

  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, livello); i > 0; 
    i = find_mag(annoes, codmag, livello, i)) 
  {                                    
    const TRectype & rec = rmag.row(i);

    acq += rec.get_real(MAG_ACQ);
    valacq += rec.get_real(MAG_VALACQ);
  }
  return acq == ZERO ? costo_standard(annoes) : valacq / acq;
}

// costo medio ponderato per periodi pari alla durata dell'esercizio
real TArticolo_giacenza::costo_mediopond(const char * annoes, const char * codmag, const char * livello) const
{  
  real acq;
  real valacq;                       

#ifdef DBG
  if (strlen(codmag)>3)
    NFCHECK("Non � pi� possibile avere valorizzazione a livello di deposito");
#endif

  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, livello); i > 0; i = find_mag(annoes, codmag, livello, i)) 
  {                                    
    const TRectype & rec = rmag.row(i);

    acq += rec.get_real(MAG_ACQ) ;
    acq +=  rec.get_real(MAG_RIM) ;
    valacq += rec.get_real(MAG_VALACQ);
    valacq += rec.get_real(MAG_VALRIM);
  }
  return acq == ZERO ? costo_standard(annoes) : valacq / acq;
}

real TArticolo_giacenza::LIFO_annuale(const char * annoes, const char * codmag, const char * livello,
                                      bool giac_eff, bool valorizza_componenti) const
{ 
  CHECK(strlen(codmag)<=3,"Non � pi� possibile avere valorizzazione a livello di deposito");
  real rim,valrim;
  real acq,valacq;
  real giacenza;
  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, livello); i > 0; i = find_mag(annoes, codmag, livello, i)) 
  {
    const TRectype & rec = rmag.row(i);

    rim += rec.get_real(MAG_RIM);
    valrim += rec.get_real(MAG_VALRIM);
    acq += rec.get_real(MAG_ACQ);
    valacq += rec.get_real(MAG_VALACQ);
    giacenza += giacenza_corretta(rec,giac_eff,valorizza_componenti);
  }  
  if (giacenza <= ZERO)
    return ZERO;
  if (giacenza > rim)
    return ((giacenza - rim) * (acq == ZERO ? costo_standard(annoes) : valacq / acq) + valrim) / giacenza;
  return valrim / rim;
}


real TArticolo_giacenza::FIFO_annuale(const char * annoes, const char * codmag, const char * livello,
                                      bool giac_eff, bool valorizza_componenti) const
{
  CHECK(strlen(codmag)<=3,"Non � pi� possibile avere valorizzazione a livello di deposito");
  real rim,valrim;
  real acq,valacq;
  real giacenza;
  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, livello); i > 0; i = find_mag(annoes, codmag, livello, i)) 
  {
    const TRectype & rec = rmag.row(i);

    rim += rec.get_real(MAG_RIM);
    valrim += rec.get_real(MAG_VALRIM);
    acq += rec.get_real(MAG_ACQ);
    valacq += rec.get_real(MAG_VALACQ);
    giacenza += giacenza_corretta(rec,giac_eff,valorizza_componenti);
  }
  if (giacenza <= ZERO)
    return ZERO;
  if (rim == ZERO)
    return ZERO;
  if (giacenza > acq)
    return ((giacenza - acq) * (valrim / rim) + valacq) / giacenza;
  return valacq / acq;
}


real TArticolo_giacenza::LIFO(const char * annoes, const char * codmag, const char * livello,
                              bool giac_eff, bool valorizza_componenti) const
{                            
  CHECK(strlen(codmag)<=3,"Non � pi� possibile avere valorizzazione a livello di deposito");
  real rim,valrim;
  real acq,valacq;
  real giacenza;
  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, livello); i > 0; i = find_mag(annoes, codmag, livello, i)) 
  {
    const TRectype & rec = rmag.row(i);

    rim += rec.get_real(MAG_RIM);
    valrim += rec.get_real(MAG_VALRIM);
    acq += rec.get_real(MAG_ACQ);
    valacq += rec.get_real(MAG_VALACQ);
    giacenza += giacenza_corretta(rec,giac_eff,valorizza_componenti);
  }

  if (giacenza <= ZERO)
    return ZERO;
  if (giacenza > rim)
    return ((giacenza - rim) * (acq == ZERO ? costo_standard(annoes) : valacq / acq) + valrim) / giacenza;
    
  TRecord_array & rstorico = storico(annoes);  
//  const int last = rstorico.last_row();
  
  valrim=ZERO;
  rim = giacenza;
  for (i = find_storico(annoes, codmag); i > 0; i = find_storico(annoes, codmag, i))
  {
    TRectype & rec = rstorico[i];
    const real qta = rec.get(STOMAG_QUANT);
    
    if (qta > giacenza)
    {
      valrim += (rec.get_real(STOMAG_VALORE)) * giacenza;
      break;
    }
    else
    {
      valrim += rec.get_real(STOMAG_VALORE) * qta;
      giacenza -= qta;
    }
  }
  return rim == ZERO ? ZERO :valrim / rim;
}

real TArticolo_giacenza::FIFO(const char * annoes, const char * codmag, const char * livello,
                              bool giac_eff, bool valorizza_componenti) const
{
  CHECK(strlen(codmag)<=3,"Non � pi� possibile avere valorizzazione a livello di deposito");
  real rim,valrim;
  real acq,valacq;
  real giacenza;
  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, livello); i > 0; i = find_mag(annoes, codmag, livello, i)) 
  {
    const TRectype & rec = rmag.row(i);

    rim += rec.get_real(MAG_RIM);
    valrim += rec.get_real(MAG_VALRIM);
    acq += rec.get_real(MAG_ACQ);
    valacq += rec.get_real(MAG_VALACQ);
    giacenza += giacenza_corretta(rec,giac_eff,valorizza_componenti);
  }

  if (giacenza <= ZERO)
    return ZERO;
  if (giacenza <= acq)
  {
    return valacq / acq;
  }    
                              
  TRecord_array & rstorico = storico(annoes);  
  const int last = rstorico.last_row();
  real res = giacenza - acq;
  rim = ZERO;
  valrim = ZERO;   
  TFixed_string cmag(codmag);                         
  int codmag_len = codmag ? strlen(cmag) : 0;
  for (i = last; i > 0; i--) 
  {
    const TRectype & rec = rstorico.row(i);
    if (codmag_len == 0 || rec.get(STOMAG_CODMAG).compare(codmag, codmag_len) == 0)
    {
      const real qta = rec.get(STOMAG_QUANT);
      
      if (qta > res)
      {                                                          
        rim += res;
        valrim += (rec.get_real(STOMAG_VALORE)) * res;
      }
      else
      {
        rim += qta;
        valrim += rec.get_real(STOMAG_VALORE) * qta;
        res -= qta;
      }
    }
  }    
  if (rim.is_zero() || giacenza.is_zero()) 
    return ZERO;
  
  return ((giacenza - acq) * (valrim / rim) + valacq) / giacenza;
}

real TArticolo_giacenza::FIFO_ragionieristico(const char * annoes, const char * codmag, const char * livello,
                                              bool giac_eff, bool valorizza_componenti) const
{
  CHECK(strlen(codmag)<=3, "Non � pi� possibile avere valorizzazione a livello di deposito");
  return ZERO; // da implementare
}

real TArticolo_giacenza::LIFO_ragionieristico(const char * annoes, const char * codmag, const char * livello,
                                              bool giac_eff, bool valorizza_componenti) const
{             
  CHECK(strlen(codmag)<=3, "Non � pi� possibile avere valorizzazione a livello di deposito");
  return ZERO;  // da implementare
}

void TArticolo_giacenza::copia_storico(TRecord_array& nrstorico,const char * annoes,const char * codmag)
{
  CHECK(annoes && *annoes,"Copia_storico: Indicare l'anno esercizio dello storico");

  TString nuovoanno(nrstorico.key().get(STOMAG_ANNOESRIF));
  //nrstorico.destroy_rows();
  
  TRecord_array & rstorico = storico(annoes);  

  int last = nrstorico.last_row();
  int codmag_len = (codmag && *codmag) ? strlen(codmag) : 0;

  for (int i = rstorico.last_row(); i > 0; i--) 
  {
    const TRectype& rst =  rstorico[i];
    if (codmag_len == 0 || rst.get(STOMAG_CODMAG).compare(codmag, codmag_len) == 0)
    {
      TRectype newrec(rst);
      newrec.put(STOMAG_ANNOESRIF,nuovoanno);
      newrec.put(STOMAG_NRIGA,++last);
      nrstorico.insert_row(newrec);
    }
  }
}

HIDDEN int sort_storico(const TObject ** a, const TObject ** b)
{
  TRectype * rec_a = (TRectype *) *a;
  TRectype * rec_b = (TRectype *) *b;
  TString16 mag_a = rec_a->get(STOMAG_CODMAG);
  int res = mag_a.compare(rec_b->get(STOMAG_CODMAG));

  if (res == 0)
    res = rec_a->get_int(STOMAG_ANNOES) - rec_b->get_int(STOMAG_ANNOES);
  return res;
}

void TArticolo_giacenza::add_storico(TRecord_array& nrstorico,const char * annoes,const char * codmag, const real & qta, const real & prz)
{
  //CHECK(annorif && *annorif,"Add_storico: Indicare l'anno esercizio dello storico");
  //TRecord_array & rstorico = storico(annorif);  
  TString annorif(nrstorico.key().get(STOMAG_ANNOESRIF));
  for (int i=nrstorico.last_row(); i>0; i--)
  {
    TString mag=nrstorico[i].get(STOMAG_CODMAG);
    if (mag<=codmag)
      break;
  }
  TRectype storec(LF_STOMAG);
  storec.put(STOMAG_ANNOESRIF,annorif);
  storec.put(STOMAG_ANNOES,annoes);
  storec.put(STOMAG_CODART,codice());
  storec.put(STOMAG_NRIGA,i+1);
  storec.put(STOMAG_CODMAG,codmag);
  storec.put(STOMAG_QUANT,qta);
  storec.put(STOMAG_VALORE,prz);
  nrstorico.insert_row(storec);
}

// annoes indica l'anno dell'esercizio da chiudere
void TArticolo_giacenza::agg_storicoLIFO(const char * annoes, const char * codmag, 
                              bool giac_eff, bool valorizza_componenti) 
{                            
  CHECK(strlen(codmag)<=3,"Non � pi� possibile avere valorizzazione a livello di deposito");
  CHECK(codmag && *codmag,"Necessario indicare il magazzino");

  real rim,acq,valacq,giacenza;
  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, ""); i > 0; i = find_mag(annoes, codmag, "", i)) 
  {
    const TRectype & rec = rmag.row(i);
    rim += rec.get_real(MAG_RIM);
    acq += rec.get_real(MAG_ACQ);
    valacq += rec.get_real(MAG_VALACQ);
    giacenza += giacenza_corretta(rec,giac_eff,valorizza_componenti);
  }

  TString nuovoanno;
  TPrice prz;
  real qta;
  
  TEsercizi_contabili ese;
  nuovoanno.format("%d", ese.next(atoi(annoes)));

  TRecord_array nuovo_storico(storico(nuovoanno));
  copia_storico(nuovo_storico, annoes, codmag);
  
  if (giacenza <= ZERO)
    giacenza=ZERO;
  if (giacenza > rim)
  {
    qta=giacenza-rim;
    if (acq.is_zero())        
      prz.set_num(ZERO);
    else
      prz.set_num(valacq/acq);
    add_storico(nuovo_storico,annoes,codmag,qta,prz.get_num());
  }
  else
  {
    real res = rim-giacenza;
    //TRecord_array & rstorico = storico(nuovoanno);
    for (i = find_storico(nuovo_storico, codmag); i > 0; i = find_storico(nuovo_storico, codmag, i))
    {
      TRectype & rec = nuovo_storico[i];
      const real qta_sto=rec.get_real(STOMAG_QUANT);
      if (qta_sto > res)
      {
        qta=qta_sto-res;
        rec.put(STOMAG_QUANT,qta);
        break;
      }
      else 
      {
        nuovo_storico.destroy_row(i);
        res -= qta_sto;
      }
    }
  }

  nuovo_storico.pack();
  nuovo_storico.sort(sort_storico);
  nuovo_storico.write();
}


void TArticolo_giacenza::agg_storicoFIFO(const char * annoes, const char * codmag, 
                              bool giac_eff, bool valorizza_componenti) 
{
  CHECK(strlen(codmag)<=3,"Non � pi� possibile avere valorizzazione a livello di deposito");
  CHECK(codmag && *codmag,"Necessario indicare il magazzino");
  real rim,acq,valacq,giacenza;
  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, ""); i > 0; i = find_mag(annoes, codmag, "", i)) 
  {
    const TRectype & rec = rmag.row(i);
    rim += rec.get_real(MAG_RIM);
    acq += rec.get_real(MAG_ACQ);
    valacq += rec.get_real(MAG_VALACQ);
    giacenza += giacenza_corretta(rec,giac_eff,valorizza_componenti);
  }

  if (giacenza <= ZERO)
    return ;
//  if (giacenza <= acq)
//    return;

  TString nuovoanno;
  TEsercizi_contabili ese;
  nuovoanno.format("%d", ese.next(atoi(annoes)));

  TRecord_array nuovo_storico(storico(nuovoanno));
  copia_storico(nuovo_storico, annoes, codmag);

  real qta;
  
  real res = giacenza - acq;
  for (i = find_storico(nuovo_storico, codmag); i > 0; i = find_storico(nuovo_storico, codmag, i))
  {
    TRectype & rec = nuovo_storico[i];
    const real qta_sto = rec.get(STOMAG_QUANT);
    if (res > qta_sto)
    {
      res -= qta_sto;
    } else {
      if (res>ZERO)
      {
        qta=res;
        rec.put(STOMAG_QUANT, qta);
        res=ZERO;
      } else {
        nuovo_storico.destroy_row(i);
      }
    }
  }
  // aggiunge la quota dell'anno in corso
//  qta=giacenza-rim;
  qta = min(giacenza, acq);      
  TPrice prz;
  if (!acq.is_zero())        
    prz.set_num(valacq/acq);
  add_storico(nuovo_storico, annoes, codmag, qta, prz.get_num());   

  nuovo_storico.pack();
  nuovo_storico.sort(sort_storico);
  nuovo_storico.write();
}

void TArticolo_giacenza::agg_storico(const char * annoes, const char * codmag, 
                              bool giac_eff, bool valorizza_componenti, const real& val) 
{
  CHECK(strlen(codmag)<=3,"Non � pi� possibile avere valorizzazione a livello di deposito");
  CHECK(codmag && *codmag,"Necessario indicare il magazzino");

//  TPrice prz(val);
  TPrice prz;
  real qta;

  TRecord_array & rmag = mag(annoes);
  for (int i = find_mag(annoes, codmag, ""); i > 0; i = find_mag(annoes, codmag, "", i)) 
  {
    const TRectype & rec = rmag.row(i);
    qta += giacenza_corretta(rec, giac_eff, valorizza_componenti);
  }

  TString nuovoanno;
  TEsercizi_contabili ese;
  nuovoanno.format("%d", ese.next(atoi(annoes)));
  
  TRecord_array& nuovo_storico = storico(nuovoanno);
  
  //nuovo_storico.destroy_rows();
  add_storico(nuovo_storico, annoes, codmag, qta, prz.get_num());
  nuovo_storico.sort(sort_storico);
  nuovo_storico.write();
}

void TArticolo_giacenza::put_ultimo_costo(const real& costo, const TDate& data)
{
  TDate d = get(ANAMAG_DULTCOS1);
  if (data >= d)
  {
    if (data > d)
    {
      put(ANAMAG_ULTCOS2, get(ANAMAG_ULTCOS1));
      put(ANAMAG_DULTCOS2, get(ANAMAG_DULTCOS1));
    }
    put(ANAMAG_DULTCOS1, data);
    put(ANAMAG_ULTCOS1, costo);
  }
  else
  {
    d = get(ANAMAG_DULTCOS2);
    if (data >= d)
    {
      put(ANAMAG_ULTCOS2, costo);
      put(ANAMAG_DULTCOS2, data);
    }
  }
}

void TArticolo_giacenza::put_costo_standard(const real& costo)
{
  put(ANAMAG_COSTSTD, costo);
}

// calcola la giacenza corretta dai campi Conto Lavoro e Produzione 
real TArticolo_giacenza::giacenza_corretta(const TRectype & rec ,bool giac_eff,bool valorizza_componenti) const
{
  CHECK(rec.num() == LF_MAG, "Il record passato deve essere di LF_MAG");
  real giacenza(rec.get_real(MAG_GIAC));
  if (giac_eff)
  { 
    giacenza += rec.get_real(MAG_INCL);
    giacenza -= rec.get_real(MAG_ACL); 
    giacenza += valorizza_componenti ? ZERO : (rec.get_real(MAG_PRODFIN)-rec.get_real(MAG_PRODCOMP));
  }
  return giacenza;
}

real TArticolo_giacenza::giacenza_anno(const char* codmag,
                                       const char* livello, 
                                       int anno) const
{
  TString16 annoes;
  if (anno > 0)
    annoes.format("%04d", anno);

  const TRecord_array& rmag = mag(annoes);
  real giac;
  for (int i = find_mag(annoes, codmag, livello); i > 0; 
       i = find_mag(annoes, codmag, livello, i)) 
  {
    const TRectype& rec = rmag.row(i);
    if (!rec.get(MAG_CODMAG).empty())
      giac += rec.get_real("GIAC");
  }
  return giac;
}

real TArticolo_giacenza::scorta_minima(const char* codmag,
                                       const char* livello, 
                                       int anno, bool liv_riordino) const
{
  TString16 annoes;
  if (anno > 0)
    annoes.format("%04d", anno);

  const TRecord_array& rmag = mag(annoes);
  real sm;
  int nmag=0;
  for (int i = find_mag(annoes, codmag, livello); i > 0; 
       i = find_mag(annoes, codmag, livello, i)) 
  {
    const TRectype& rec = rmag.row(i);
    if (!rec.get(MAG_CODMAG).empty())
    {
      if (liv_riordino)
        sm += rec.get_real("LIVRIOR");
      else
        sm += rec.get_real("SCORTAMIN");
      nmag++;
    }
  }
  if (nmag)
    sm = sm / nmag;
  return sm;
}

long TArticolo_giacenza::lead_time(const char* codmag,
                                       const char* livello, 
                                       int anno) const
{
  TString4 annoes;
  if (anno > 0)
    annoes.format("%04d", anno);

  const TRecord_array& rmag = mag(annoes);
  real sm;
  int nmag=0;
  for (int i = find_mag(annoes, codmag, livello); i > 0; 
       i = find_mag(annoes, codmag, livello, i)) 
  {
    const TRectype& rec = rmag.row(i);
    if (!rec.get(MAG_CODMAG).empty())
    {
      if (rec.get_real(MAG_GIORNIRIOR).is_zero())
        sm += get_real(ANAMAG_GIORNIRIOR);
      else
        sm += rec.get_real(MAG_GIORNIRIOR);
      nmag++;
    }
  }
  if (nmag)
    sm = sm / nmag;
  else
    sm = get_real(ANAMAG_GIORNIRIOR);
  return sm.integer();
}


TArticolo_giacenza::TArticolo_giacenza(const char* codice)
                  : TArticolo(codice)
{
  add_file(LF_MAG,"NRIGA");
  add_file(LF_STOMAG,"NRIGA");
}

TArticolo_giacenza::TArticolo_giacenza(const TRectype& rec)
                  : TArticolo(rec)
{
  add_file(LF_MAG,"NRIGA");
  add_file(LF_STOMAG,"NRIGA");
}

// Giacenze alla data


int TArticolo_giacenza_data::write(TBaseisamfile&) const
{
  NFCHECK("Non e' possibile scrivere un Articolo con giacenza alla data");
  return NOERR;
}

int TArticolo_giacenza_data::rewrite(TBaseisamfile& f) const
{ return write(f); }

int TArticolo_giacenza_data::remove(TBaseisamfile& f) const
{ return write(f); }

void TArticolo_giacenza_data::al(const TDate& data, const char* codmag, const char* livello,
                                 TTipo_valorizz tipo, const char* catven, const char* codlis)
{  
  const TEsercizi_contabili esc;
  const int anno = esc.date2esc(data);
  const TDate inizio = esc[anno].inizio();
  TString16 annoes; annoes.format("%04d", anno); 
  TString16 predes;
  
  bool reset_giac = TRUE;
  const int anno_pred = esc.pred(anno);
  if (anno_pred != 0)
  {                
    predes.format("%04d", anno_pred);
    const TDate dc = esc[anno_pred].chiusura_mag();
    reset_giac = dc.ok();
  }
  
  remove_body(LF_MAG); // Azzero la cache dei magazzini
  
  if (reset_giac)
    azzera_saldi(annoes, FALSE);
  else
    riporta_saldi(predes, annoes, tipo, catven, codlis, FALSE);
  
  TRelation rel(LF_RMOVMAG); rel.add(LF_MOVMAG, "NUMREG==NUMREG");
  
  TRectype filter(LF_RMOVMAG);
  filter.put(RMOVMAG_CODART, codice());
  if (livello && *livello)   
    filter.put(RMOVMAG_LIVGIAC, livello);
  if (codmag && *codmag)
    filter.put(RMOVMAG_CODMAG, codmag);
  
  TCursor cur(&rel, "", 2, &filter, &filter, 0x2);
  const long items = cur.items();
  cur.freeze();
  
  TProgind* pi = NULL;
  if (items >= 10)
  {
    TString80 str; str << "Calcolo giacenza articolo " << codice();
    pi = new TProgind(items, str, FALSE, TRUE);
  }
  
  TMov_mag* p_movmag = new TMov_mag;  
  rel.lfile(LF_MOVMAG).set_curr(p_movmag);
  TMov_mag& movmag = *p_movmag;
  const TRectype& rmovmag = rel.curr();
  TRecord_array& rmag = mag(annoes);
  
  for (cur = 0; cur.pos() < items; ++cur)
  {
    if (pi) pi->addstatus(1);
    const TDate datacomp = movmag.get(MOVMAG_DATACOMP);
    if (datacomp >= inizio && datacomp <= data)
    {  
      const TString16 codmag = rmovmag.get(RMOVMAG_CODMAG);
      const TString16 livello = rmovmag.get(RMOVMAG_LIVGIAC);
      const int nrig = rmovmag.get_int(RMOVMAG_NRIG);
      const int i = find_mag(annoes, codmag, livello);
      if (i >= 0)  // Se il record di giacenza esiste lo aggiorno ...
      {
        TRectype& rec = (TRectype&)rmag.row(i);
        movmag.update_balances(rec, nrig, +1);
      }
      else        // ... altrimenti lo creo e poi lo aggiorno
      {
        TRectype& rec = rmag.row(-1, TRUE);
        rec.put(MAG_ANNOES, annoes);    // Setto i campi fondamentali!
        rec.put(MAG_CODMAG, codmag);
        rec.put(MAG_LIVELLO, livello);
        movmag.update_balances(rec, nrig, +1);
      }
    }
  }
  
  if (pi) delete pi;
}

TArticolo_giacenza_data::TArticolo_giacenza_data(const char* codice) 
                       : TArticolo_giacenza(codice)
{ }

TArticolo_giacenza_data::TArticolo_giacenza_data(const TRectype& rec) 
                       : TArticolo_giacenza(rec)
{ }

// TArticolo_giacenza_loadable
TArticolo_giacenza_loadable::TArticolo_giacenza_loadable(const char* codice) 
                       : TArticolo_giacenza_data(codice)
{ }

TArticolo_giacenza_loadable::TArticolo_giacenza_loadable(const TRectype& rec) 
                       : TArticolo_giacenza_data(rec)
{ }

// Carica il record array delle giacenza dal file temporaneo specificato
void TArticolo_giacenza_loadable::load(TIsamtempfile& f)
{
  TString16 annoes;
  TString codart(codice());
  int err;
  // Il file temporaneo contiene le giacenze alla data per tutti 
  // gli articoli per un SOLO anno esercizio.
  // Reperisce l'anno esercizio dal record corrente, visto che deve essere uguale su tutti
  const TRecnotype pos = f.recno();
  
  annoes = f.get("ANNOES");
  f.put("CODART", codart);
  
  remove_body(LF_MAG);
  TRecord_array& rmag = mag(annoes);
  rmag.destroy_rows();
  // Scorre le giacenze del file temporaneo per questo articolo
  for (err = f.read(_isgteq) ; err == NOERR && codart == f.get("CODART"); err = f.next())
    rmag.add_row(f.curr());
  
  // Ripristina la posizione  
  f.readat(pos);
}

// causali 

int TCausale_magazzino::sgn(TTipo_saldomag tiposaldo) const
{
  int index = -1;
  switch (tiposaldo)
  {
    case s_giac : index =  0; break;
    case s_acq  : index =  2; break;
    case s_ent  : index =  4; break;
    case s_ven  : index =  6; break;
    case s_usc  : index =  8; break;
    case s_ordc : index = 10; break;
    case s_ordf : index = 12; break;
    case s_incl : index = 14; break;
    case s_acl  : index = 16; break;
    case s_prodc: index = 18; break;
    case s_prodf: index = 20; break;
    case s_rim  : index = 22; break;
    case s_scart: index = 24; break;
    case s_label: index = 26; break;
    case s_user1: index = 28; break;
    case s_user2: index = 30; break;
    case s_user3: index = 32; break;
    case s_user4: index = 34; break;
    case s_user5: index = 36; break;
    case s_user6: index = 38; break;
    default     : index = -1; break;
  }
  int segno = 0;
  if (index >= 0)
  {
    const TString& segni = get("S2");
    segno = atoi(segni.mid(index, 2));
  }
  return segno;
}

bool TCausale_magazzino::is_fiscale()
{
  bool rt = FALSE; 
  if (raggfisc().not_empty()) // Per essere fiscale deve avere il raggruppamento fiscale
  {
    const char tm = tipomov();
    rt = tm == 'S' || tm == 'C'; // La causale deve essere Carico o Scarico...
    if (rt)
    {
      const TRectype& rfc = cache().get("%RFC", raggfisc());
      const char ragg = rfc.get_char("S6");
      rt &= (ragg == 'S' || ragg == 'C'); // Ed il raggruppamento deve essere Carico o Scarico
    }
  }
  return rt;
}


TCausale_magazzino::TCausale_magazzino(const char * codice):
                    TRectype(cache().get("%CAU", codice))
{ }            

TCausale_magazzino::TCausale_magazzino(const TRectype &r):
                    TRectype(r)
{
  CHECK(r.num() == LF_TABCOM, "Tipo record errato sulla causale di magazzino");
}            

const real CENTO=real(100.0);

bool TCondizione_vendita::ricerca(const char * codice, const real & qta) 
{
  int tiporic;
  switch (_condv.get_char("TIPO")) {
    case 'L':  
      tiporic=A_LISTINI;
    break;
    case 'C':  
      tiporic=A_CONTRATTI;
    break;
    case 'O':  
      tiporic=A_OFFERTE;
    break;
  }
  return cerca(tiporic,codice, qta);
}


bool TCondizione_vendita::cerca( int tiporicerca, const char * codriga , const real & qta, const char * um)
{
//  if (_condv.get("COD").empty())
//    return FALSE;
  bool found = FALSE;
  TString80 cod; cod << codriga << "|1";

  if(config_ditta().get_bool("GES", "ve", tiporicerca))
  {
    _condv.setkey( 1 );
    switch( tiporicerca )
    {
      case A_CONTRATTI:          
      {
      }
      break;
      case A_LISTINI:                                    
        {
          _condv.put("TIPOCF", "");
          _condv.put("CODCF", "");  
          if( !config_ditta().get_bool("GESLISCV", "ve"))
            _condv.put("CATVEN", "");
        }
        break;
      case A_OFFERTE:
        {
        }
        break;
    }
    if( _condv.read() == NOERR )
    { 
      // si posiziona sulla riga 
      const bool gest_scagl = _condv.get_bool("GESTSCAGL");
      const TString16 seqricrighe( _condv.get( "SEQRIC" ) );
        
      for( int i = 0; !found && i < seqricrighe.len( ); i ++ )
      {
        _rcondv.zero(' ');
        _rcondv.put( "TIPO", _condv.get( "TIPO"));
        _rcondv.put( "CATVEN", _condv.get( "CATVEN"));
        _rcondv.put( "TIPOCF", _condv.get( "TIPOCF"));
        _rcondv.put( "CODCF", _condv.get( "CODCF"));
        _rcondv.put("COD", _condv.get("COD"));  
        if( _condv.get_bool( "GESTUM" ) )
          _rcondv.put( "UM", (um && *um ) ? um : cache().get(LF_UMART, cod).get("UM"));
        if (gest_scagl)
          _rcondv.put("NSCAGL", 1);
          
        char ricerca = seqricrighe[ i ];
        _rcondv.put( "TIPORIGA", ricerca );
        switch( ricerca )
        {
          case 'A':              
            {
              _rcondv.put( "CODRIGA", codriga);
              int err=_rcondv.read();
              found = err == NOERR;
              if (!found)
                if (err=_rcondv.prev() == NOERR)
                  if (err=_rcondv.get("TIPORIGA")[0] == 'A')
                  {
                      const TString cod_found(_rcondv.get("CODRIGA"));
                      found = cod_found.compare(codriga, cod_found.len()) == 0;
                  }
            }
            break;
          case 'R':
            _rcondv.put("CODRIGA", anamag().get( "RAGGFIS"));
            _rcondv.read();
             found = _rcondv.good();
            break;
          case 'S':                       
            {
              _rcondv.put( "CODRIGA", anamag().get("GRMERC"));
              _rcondv.read( );              
              found = _rcondv.good();
            }
            break;
          case 'G':                       
            {
              _rcondv.put( "CODRIGA", anamag().get("GRMERC").left(3));
              _rcondv.read( );              
               found = _rcondv.good();
            }
            break;
          default:
            break;
        }                       
      }
      // individua lo scaglione corretto in base alla quantita'
      if (found && gest_scagl)
      {                   
        TRectype rec(_rcondv.curr());
        int last_scagl = 0;      
        int scagl = _rcondv.get_int("NSCAGL");
        real qta_lim(_rcondv.get_real("QLIM"));
        while (_rcondv.good() && scagl > last_scagl && qta_lim > ZERO && qta > qta_lim)
        {                    
          if (_rcondv.next() == NOERR)
          {
            last_scagl = scagl;
            scagl = _rcondv.get_int("NSCAGL");
            qta_lim =_rcondv.get_real("QLIM");
            rec = _rcondv.curr();
          }
        }
        _rcondv.read(rec);
      }                                                                  
      _prezzo = _rcondv.get_real("PREZZO");      
    }
  }  
  
  if (!found)
  {             
/*  
    TLocalisamfile um(LF_UMART);  // Use Frate cercone when possible!
    um.put("CODART", codriga);
    um.put("NRIGA", 1);
    if (um.read() == NOERR)
    {             
      _prezzo = um.get_real("PREZZO");      
      found = TRUE;
    }
    else 
      _prezzo = ZERO;
*/                               
    const TRectype& um = cache().get(LF_UMART, cod);
    _prezzo = um.get_real("PREZZO");
    found = _prezzo != ZERO;
  }
  
  return found;
}
    
void TCondizione_vendita::put_condv(const char *tipocv,const char *codicecv,const char *catven,const char *tipocf,const char *codcf)
{
  _condv.zero(' ');
  _condv.put("TIPO",tipocv);
  _condv.put("CATVEN",catven);
  _condv.put("TIPOCF",tipocf);
  _condv.put("CODCF",codcf);
  _condv.put("COD",codicecv);
}

void TCondizione_vendita::put_listino(const char * codlist,const char *catven)
{
  if( !config_ditta().get_bool("GESLISCV", "ve"))
    put_condv("L",codlist,"","","");
  else  
    put_condv("L",codlist,catven,"","");
}
void TCondizione_vendita::put_contratto(const char * codcontr,const char *tipocf,const char *codcf)
{
  put_condv("C",codcontr,"",tipocf,codcf);
}
void TCondizione_vendita::put_offerta(const char * codoff)
{
  put_condv("C",codoff,"","","");
}


TCondizione_vendita::TCondizione_vendita(TConfig * ditta, 
    TLocalisamfile * anamag, TLocalisamfile * umart)
             : _condv(LF_CONDV), _rcondv(LF_RCONDV),
               _sconti( LF_SCONTI ),
               _anamag(anamag), _umart(umart), _config_ditta(ditta), _ivarid(FALSE)
{
}