Files correlati : Ricompilazione Demo : [ ] Commento : riporto dalla 11 git-svn-id: svn://10.65.10.50/branches/R_10_00@20915 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			831 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			831 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
#include <applicat.h>
 | 
						|
#include <automask.h>
 | 
						|
#include <progind.h>
 | 
						|
#include <recarray.h>
 | 
						|
#include <recset.h>
 | 
						|
#include <reputils.h>
 | 
						|
 | 
						|
#include <doc.h>
 | 
						|
#include <rdoc.h>
 | 
						|
#include "../cg/cglib01.h"
 | 
						|
#include "../ve/velib.h"
 | 
						|
 | 
						|
#include "halib.h"
 | 
						|
#include "ha0.h"
 | 
						|
#include "ha0500a.h"
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TAutomask
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
class THardy_elab_docs_mask : public TAutomask
 | 
						|
{
 | 
						|
protected:
 | 
						|
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
 | 
						|
 | 
						|
public:
 | 
						|
  THardy_elab_docs_mask();
 | 
						|
  ~THardy_elab_docs_mask();
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
THardy_elab_docs_mask::THardy_elab_docs_mask() : TAutomask ("ha0500a")
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
THardy_elab_docs_mask::~THardy_elab_docs_mask()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
bool THardy_elab_docs_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
 | 
						|
{ 
 | 
						|
	switch (o.dlg())
 | 
						|
	{
 | 
						|
  case F_ADATA:
 | 
						|
    if (e == fe_close || e == fe_modify)
 | 
						|
    {
 | 
						|
      //se la data iniziale è piena -> l'anno deve essere lo stesso nelle 2 date;
 | 
						|
      //se invece è vuota -> la data iniziale viene presa come la data iniziale dell'esercizio della data finale...
 | 
						|
      //..ma questo qui non serve e viene rinviato alla query principale del recordset
 | 
						|
      const TDate adata = get_date(F_ADATA);
 | 
						|
      TEsercizi_contabili esc;
 | 
						|
      const int adata_esc = esc.date2esc(adata);
 | 
						|
 | 
						|
      TDate dadata = o.get();
 | 
						|
      if (dadata.ok())
 | 
						|
      {
 | 
						|
        const int dadata_esc = esc.date2esc(dadata);
 | 
						|
        if (adata_esc != dadata_esc)
 | 
						|
          return error_box("Le date devono appartenere allo stesso esercizio!");
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  /*case F_TIPOCONTR:
 | 
						|
    if (e == fe_modify)
 | 
						|
    {
 | 
						|
      //in base alla tipologia di contratti da elaborare decide numerazione e tipo delle NAC da generare
 | 
						|
      TConfig config(CONFIG_DITTA, "ha");
 | 
						|
      TString4 codnum, tipodoc;
 | 
						|
 | 
						|
      switch (o.get()[0])
 | 
						|
      {
 | 
						|
      case 'A':
 | 
						|
        codnum = config.get("NaAntNum");
 | 
						|
        tipodoc = config.get("NaAntTip");
 | 
						|
        break;
 | 
						|
      case 'R':
 | 
						|
        codnum = config.get("NaRifaNum");
 | 
						|
        tipodoc = config.get("NaRifaTip");
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        codnum = config.get("NaPostNum");
 | 
						|
        tipodoc = config.get("NaPostTip");
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      set(F_CODNUM_NAC, codnum);
 | 
						|
      set(F_CODTIPO_NAC, tipodoc);
 | 
						|
    }
 | 
						|
    break;*/
 | 
						|
    //in caso di elaborazione definitiva è obbligatorio..
 | 
						|
    //..eliminare tutte le NAC provvisorie generate in precedenza
 | 
						|
  case F_DEFINITIVO:
 | 
						|
    if (e == fe_modify)   
 | 
						|
    {
 | 
						|
      if (o.get() == "X")
 | 
						|
      {
 | 
						|
        set(F_KILLPROVV, "X");
 | 
						|
        disable(F_KILLPROVV);
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
        enable(F_KILLPROVV);
 | 
						|
        set(F_KILLPROVV, " ");
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
///////////////////////////////////////
 | 
						|
// TSkeleton_application
 | 
						|
///////////////////////////////////////
 | 
						|
class THardy_elab_docs : public TSkeleton_application
 | 
						|
{
 | 
						|
 | 
						|
protected:
 | 
						|
  //metodi alto livello
 | 
						|
  void elabora(const TMask& mask);
 | 
						|
  int kill_provv_nac(const TMask& mask);
 | 
						|
  long genera_recordset(const TMask& mask, TISAM_recordset& recset);
 | 
						|
  void elabora_documenti(const TMask& mask, TISAM_recordset& recset, TLog_report& log);
 | 
						|
 | 
						|
  //metodi medio livello
 | 
						|
  bool aggiorna_contratti(const TRiga_documento& rdoc, TContratto_premi& contratto);
 | 
						|
  bool elabora_contratti(TDocumento& curr_doc, TArray& contratti_cliente);
 | 
						|
  bool genera_nac(const TMask& mask, TArray& contratti_cliente, TArray& documenti_cliente, TLog_report& log);
 | 
						|
 | 
						|
  //metodi basso livello
 | 
						|
  int find_contratti_cliente(const long codcf, const TMask& mask, TArray& contratti_cliente);
 | 
						|
  void check_date(const TDate& datafine, TDate& dataini);
 | 
						|
  int find_numerazioni(const TString& tipo_to_elab, TString_array& num_doc);
 | 
						|
 | 
						|
public:
 | 
						|
  virtual void main_loop();
 | 
						|
  virtual bool create();
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
//metodo per ricavare la data iniziale di elaborazione qualora l'utonto non la metta e l'esercizio da usare
 | 
						|
void THardy_elab_docs::check_date(const TDate& datafine, TDate& dataini)
 | 
						|
{
 | 
						|
  TEsercizi_contabili esc;
 | 
						|
  TDate datafine_tmp = datafine;
 | 
						|
  const int esercizio = esc.date2esc(datafine);
 | 
						|
  esc.code2range(esercizio, dataini, datafine_tmp);
 | 
						|
}
 | 
						|
 | 
						|
int THardy_elab_docs::find_numerazioni(const TString& tipo_to_elab, TString_array& num_doc)
 | 
						|
{
 | 
						|
  TISAM_recordset num_recset("USE %NUM");
 | 
						|
  for (bool ok = num_recset.move_first(); ok; ok = num_recset.move_next())    //giro sui vari tipi numerazione
 | 
						|
  {
 | 
						|
    const TString4 codtab = num_recset.get("CODTAB").as_string();
 | 
						|
 | 
						|
    const TCodice_numerazione numerazione(codtab);
 | 
						|
    for (int t = numerazione.ntipi_doc() - 1; t >= 0; t--)
 | 
						|
    {
 | 
						|
      const TString& tipo_doc = numerazione.tipo_doc(t);
 | 
						|
      if (tipo_doc == tipo_to_elab)
 | 
						|
      {
 | 
						|
        if (num_doc.find(codtab) < 0) // Evito aggiunta di doppioni
 | 
						|
          num_doc.add(codtab);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    } //for (int t = codnum..
 | 
						|
  } //for (bool ok = num_recset...
 | 
						|
 | 
						|
  return num_doc.items();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//metodo per accoppare tutte le NAC provvisorie generate in precedenza
 | 
						|
int THardy_elab_docs::kill_provv_nac(const TMask& mask)
 | 
						|
{
 | 
						|
  int nac_killed = 0;
 | 
						|
  const TDate& adata = mask.get_date(F_ADATA);
 | 
						|
  int anno = adata.year();
 | 
						|
 | 
						|
  TConfig config(CONFIG_DITTA, "ha");
 | 
						|
 | 
						|
  TToken_string numerazioni;
 | 
						|
  numerazioni.add(config.get("NaAntNum"));
 | 
						|
  numerazioni.add(config.get("NaRifaNum"));
 | 
						|
  numerazioni.add(config.get("NaPostNum"));
 | 
						|
 | 
						|
  FOR_EACH_TOKEN(numerazioni, codnum)
 | 
						|
  {
 | 
						|
    TRelation rel_doc(LF_DOC);
 | 
						|
 | 
						|
    TRectype& rec = rel_doc.curr();
 | 
						|
    rec.put(DOC_PROVV, "P");
 | 
						|
    rec.put(DOC_ANNO, anno);
 | 
						|
    rec.put(DOC_CODNUM, codnum);
 | 
						|
 | 
						|
    TCursor cur_doc (&rel_doc, "", 1, &rec, &rec);
 | 
						|
    const long items = cur_doc.items();
 | 
						|
    cur_doc.freeze();
 | 
						|
    TProgind progind(items, "Eliminazione NAC provvisorie in corso...", false, true);
 | 
						|
 | 
						|
    for (cur_doc = 0; cur_doc.pos() < items; ++cur_doc)
 | 
						|
    { 
 | 
						|
      progind.addstatus(1);
 | 
						|
      TDocumento doc(rec);
 | 
						|
      int err = doc.remove();
 | 
						|
      if (err == NOERR)
 | 
						|
        nac_killed++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return nac_killed;
 | 
						|
}
 | 
						|
 | 
						|
//metodo che filtra tutti i documenti in base ai parametri della maschera
 | 
						|
long THardy_elab_docs::genera_recordset(const TMask& mask, TISAM_recordset& recset)
 | 
						|
{
 | 
						|
  //parametri di elaborazione
 | 
						|
  //per prima cosa controlla se il cliente è stato specificato; questo influisce sulla scelta della chiave di ricerca sul file
 | 
						|
  int key = 3;
 | 
						|
  const long codcf = mask.get_long(F_CODCF);
 | 
						|
  if (codcf > 0)
 | 
						|
    key = 2;
 | 
						|
 | 
						|
  //e costruiamola 'sta query!
 | 
						|
  //usa i documenti con chiave variabile (vedi sopra)
 | 
						|
  TString query;
 | 
						|
  query << "USE DOC KEY " << key;
 | 
						|
  //lo stato dipende da quanto sta scritto sulla elaborazione differita (stato iniziale dei docs da considerare)
 | 
						|
  //viene messo CODNUM nella SELECT perchè, essendoci un range di date nelle chiavi, la numerazione verrebbe ignorata! (provato!)
 | 
						|
  query << "\nSELECT (STATO=#STATOINI)";
 | 
						|
 | 
						|
  //in base al tipo documento che si deve elaborare (settato in configurazione), ci possono essere più numerazioni da considerare!
 | 
						|
  TConfig config(CONFIG_DITTA, "ha");
 | 
						|
  const TString& tipo_to_elab = config.get("TipoFatt");
 | 
						|
  //e adesso cerca le numerazioni che contengono il tipo preso dalla configurazione
 | 
						|
  TString_array num_doc;
 | 
						|
  const int numerazioni_valide = find_numerazioni(tipo_to_elab, num_doc);
 | 
						|
  if (numerazioni_valide > 0)
 | 
						|
  {
 | 
						|
    query << "&&(";
 | 
						|
 | 
						|
    for (int i = 0; i < numerazioni_valide; i++)
 | 
						|
    {
 | 
						|
      if (i > 0)
 | 
						|
        query << "||";
 | 
						|
 | 
						|
      query << "(CODNUM='" << num_doc[i] << "')";
 | 
						|
    }
 | 
						|
 | 
						|
    query << ")";
 | 
						|
  }
 | 
						|
  //se c'è l'agente specificato...
 | 
						|
  const TString& agente = mask.get(F_CODAGE);
 | 
						|
  const bool has_007 = agente.full();
 | 
						|
  if (has_007)
 | 
						|
    query << "&&(CODAG=#CODAG)";
 | 
						|
  //ordinamento agente-codcf-numdoc
 | 
						|
  query << "\nBY ";
 | 
						|
  if (has_007)
 | 
						|
    query << DOC_CODAG << " ";
 | 
						|
 | 
						|
  query << DOC_CODCF << " " << DOC_NDOC;
 | 
						|
 | 
						|
  //from-to dipendente da chiave
 | 
						|
  switch (key)
 | 
						|
  {
 | 
						|
  case 2: //chiave per tipocf-codcf-provv-anno-datadoc-codnum
 | 
						|
    {
 | 
						|
      query << "\nFROM TIPOCF=C CODCF=#CODCF PROVV=D ANNO=#ANNO DATADOC=#DADATA";
 | 
						|
      query << "\nTO TIPOCF=C CODCF=#CODCF PROVV=D ANNO=#ANNO DATADOC=#ADATA";
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  case 3: //chiave per datadoc-provv-anno-codnum
 | 
						|
    {
 | 
						|
      query << "\nFROM DATADOC=#DADATA PROVV=D ANNO=#ANNO";
 | 
						|
      query << "\nTO DATADOC=#ADATA PROVV=D ANNO=#ANNO";
 | 
						|
    }
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  //setta la nuova query al recordset (inizialmente nato dequeryzzato)
 | 
						|
  recset.set(query);
 | 
						|
 | 
						|
  //settaggio delle variabili
 | 
						|
  const TDate adata = mask.get_date(F_ADATA);
 | 
						|
  TDate dadata = mask.get_date(F_DADATA);
 | 
						|
  //se la data iniziale è vuota deve coincidere con l'inizio dell'esercizio della data finale (obbligatoria!)
 | 
						|
  int esc = adata.year();
 | 
						|
  if (!dadata.ok())
 | 
						|
    check_date(adata, dadata);
 | 
						|
 | 
						|
  //lo stato dei documenti da considerare va a raccatarlo nel config
 | 
						|
  const TString& stato_ini = config.get("StatoIniFatt");
 | 
						|
  recset.set_var("#STATOINI", stato_ini);
 | 
						|
 | 
						|
  if (agente.full())
 | 
						|
    recset.set_var("#CODAG", agente);
 | 
						|
  if (codcf > 0)
 | 
						|
    recset.set_var("#CODCF", codcf);
 | 
						|
  recset.set_var("#ANNO", long(esc));
 | 
						|
  recset.set_var("#DADATA", dadata);
 | 
						|
  recset.set_var("#ADATA", adata);
 | 
						|
 | 
						|
  return recset.items();
 | 
						|
}
 | 
						|
 | 
						|
//metodo che riempie un array con tutti i contratti del cliente passatogli (in base alla tipologia di contratti da elaborare)
 | 
						|
int THardy_elab_docs::find_contratti_cliente(const long codcf, const TMask& mask, TArray& contratti_cliente)
 | 
						|
{
 | 
						|
  contratti_cliente.destroy();
 | 
						|
  //deve cercare tutti i contratti del cliente e metterli nell'array
 | 
						|
  TString query;
 | 
						|
  query << "USE DOC KEY 4";
 | 
						|
  query << "\nSELECT ((TIPODOC=#A_TIPODOC)||(TIPODOC=#R_TIPODOC)||(TIPODOC=#P_TIPODOC))";
 | 
						|
  query << "\nFROM TIPOCF=C CODCF=#CODCF";
 | 
						|
  query << "\nTO TIPOCF=C CODCF=#CODCF";
 | 
						|
 | 
						|
  TISAM_recordset recset(query);
 | 
						|
 | 
						|
  //settaggio delle variabili
 | 
						|
  //il codice numerazione lo trova nella configurazione Hardy, e lo deve scegliere in base alla tipologia di contratti che sta esaminando!
 | 
						|
  TConfig config(CONFIG_DITTA, "ha");
 | 
						|
 | 
						|
  const TString& tip_ant = config.get("CoAntTip");
 | 
						|
  const TString& tip_rifa = config.get("CoRifaTip");
 | 
						|
  const TString& tip_post = config.get("CoPostTip");
 | 
						|
 | 
						|
  recset.set_var("#A_TIPODOC", tip_ant);
 | 
						|
  recset.set_var("#R_TIPODOC", tip_rifa);
 | 
						|
  recset.set_var("#P_TIPODOC", tip_post);
 | 
						|
  
 | 
						|
  recset.set_var("#CODCF", codcf);
 | 
						|
 | 
						|
  const long n_contratti = recset.items(); //questo serve solo al sagace programmatore
 | 
						|
 | 
						|
  //aggiunge i contratti all'array: solo quelli in auge nel periodo di calcolo selezionato sulla maschera!
 | 
						|
  for (bool ok = recset.move_first(); ok; ok = recset.move_next())
 | 
						|
	{
 | 
						|
    //contratti anticipo 'A': datainizio esiste sempre, datafine non esiste (va ad esaurimento)
 | 
						|
    //contratti posticipo 'P': datainizio esiste sempre, datafine può non esistere
 | 
						|
    //contratti rifatturazione 'R': come contratti anticipo
 | 
						|
 | 
						|
    //controlla validità del contratto con le date scelte per l'elaborazione dei documenti
 | 
						|
    const TDate data_ini_contratto = recset.get(DOC_DATACOMP).as_date();
 | 
						|
 | 
						|
    TDate data_ini_elab = mask.get_date(F_DADATA);
 | 
						|
    const TDate data_fine_elab = mask.get_date(F_ADATA);
 | 
						|
    if (!data_ini_elab.ok())
 | 
						|
      check_date(data_fine_elab, data_ini_elab);
 | 
						|
 | 
						|
    //quindi la datainizio vale per tutti allo stesso modo (è obbligatoria nei contratti)
 | 
						|
    //se l'elaborazione finisce prima che cominci il contratto -> il contratto non serve a nulla
 | 
						|
    if (data_ini_contratto > data_fine_elab)
 | 
						|
      continue;
 | 
						|
    //la data fine vale invece solo per i contratti 'P' e potrebbe non esserci (contratti senza scadenza)
 | 
						|
    TDate data_fine_contratto;
 | 
						|
 | 
						|
    //se la data fine contratto non è valida (ma è presente!) non dobbiamo fare nulla, perchè il contratto non va elaborato
 | 
						|
    data_fine_contratto = recset.get(DOC_DATAFCOMP).as_date();
 | 
						|
    if (data_fine_contratto.ok())
 | 
						|
    {
 | 
						|
      if (data_fine_contratto < data_ini_elab)
 | 
						|
        continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //ci tocca istanziarci un contratto_premi
 | 
						|
    TContratto_premi* curr_contratto = new TContratto_premi(recset.cursor()->curr());
 | 
						|
    //azzeratore del campo con il totale reso per elaborazione, nel caso di contratti Anticipo/Rifatturazione, riga spese
 | 
						|
    const char tipo_contr = curr_contratto->tipo_contratto();
 | 
						|
    if (tipo_contr == 'A' || tipo_contr == 'R')
 | 
						|
    {
 | 
						|
      FOR_EACH_PHYSICAL_RDOC(*curr_contratto, r, rdoc)
 | 
						|
      {
 | 
						|
        if (rdoc->get(RDOC_TIPORIGA) == HARDY_TIPORIGA_SOMMA)
 | 
						|
        {
 | 
						|
          rdoc->zero(RCA_2_RESO_CORRENTE);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    contratti_cliente.add(curr_contratto);
 | 
						|
  }
 | 
						|
 | 
						|
  return contratti_cliente.items();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool THardy_elab_docs::aggiorna_contratti(const TRiga_documento& rdoc, TContratto_premi& contratto)
 | 
						|
{
 | 
						|
  bool elaborato = false;
 | 
						|
  const char tipo_contratto = contratto.tipo_contratto();
 | 
						|
  //parametri della riga fattura
 | 
						|
  TString80 rdoc_codart = rdoc.get(RDOC_CODART);
 | 
						|
  rdoc_codart.trim();
 | 
						|
  const real rdoc_qta = rdoc.get_real(RDOC_QTA);
 | 
						|
  const TString4 rdoc_umqta = rdoc.get(RDOC_UMQTA);
 | 
						|
 | 
						|
  FOR_EACH_PHYSICAL_RDOC(contratto, rm, rigamerce)
 | 
						|
  {
 | 
						|
    const TString& rigamerce_codart = rigamerce->get(RDOC_CODART);
 | 
						|
    //se trova il codart in una delle righe di contratto...
 | 
						|
    if (rdoc_codart == rigamerce_codart)
 | 
						|
    {
 | 
						|
      const real rigamerce_premio = rigamerce->get_real(RC_1_PREMIO);
 | 
						|
      //se il premio non è nullo procede all'aggiornamento del restituito (solo contratti A/R e righe spese) e del bonus (tutti i contratti e righe merce)
 | 
						|
      if (rigamerce_premio != ZERO)
 | 
						|
      {
 | 
						|
        //normalizzazione della qta
 | 
						|
        const TString& umqta_tot = rigamerce->get(RDOC_UMQTA);  //prende la UM dal contratto che farà da riferimento!
 | 
						|
        TArticolo articolo(rdoc_codart);
 | 
						|
        const real normalized_rdoc_qta = articolo.convert_to_um(rdoc_qta, umqta_tot, rdoc_umqta, true);
 | 
						|
 | 
						|
        //aggiornamento delle righe di tipo spesa (verigh02) per aggiornare le somme restituite nel caso di contratti di anticipo/rifatturazione
 | 
						|
        if (tipo_contratto == 'A' || tipo_contratto == 'R')
 | 
						|
        {
 | 
						|
          FOR_EACH_PHYSICAL_RDOC(contratto, ra, rigacontratto)
 | 
						|
          {
 | 
						|
            //cerca una riga anticipo da evadere sul contratto per aggiornare la somma restituita sull'anticipo
 | 
						|
            if (rigacontratto->is_spese())
 | 
						|
            {
 | 
						|
              //si informa su quale fosse la somma anticipata
 | 
						|
              const real somma_anticipata = rigacontratto->get_real(RCA_2_ANTICIPATO);
 | 
						|
              //aggiorna la somma restituita dovuta al contratto (parte da zero per ogni elaborazione di NAC)
 | 
						|
              real somma_restituita = rigacontratto->get_real(RCA_2_RESO_CORRENTE);
 | 
						|
              //controlla che il contratto non sia per caso già stato pareggiato! quindi il reso deve essere < dell'anticipato per procedere
 | 
						|
 | 
						|
              //la somma restituita deve essere incrementata per la qta di merce (caffè) che c'è sulla riga della fattura in esame...
 | 
						|
              //..moltiplicata per il premio che c'è nella riga di tipo merce del contratto in esame
 | 
						|
              somma_restituita += normalized_rdoc_qta * rigamerce_premio;
 | 
						|
              rigacontratto->put(RCA_2_RESO_CORRENTE, somma_restituita);
 | 
						|
              elaborato = true;
 | 
						|
              break;
 | 
						|
 | 
						|
            }
 | 
						|
          } //FOR_EACH_PHYSICAL..   fine casino sulla riga di tipo spese
 | 
						|
 | 
						|
        } //if(tipo_contratto == "A"...
 | 
						|
 | 
						|
        //questo va bene invece per ogni riga merce (verigh01), sia per contratti di tipo A/R che di tipo P
 | 
						|
        if (rigamerce->is_merce())
 | 
						|
        {
 | 
						|
          real somma_bonus = rigamerce->get_real(RC_1_BONUS);
 | 
						|
          somma_bonus += normalized_rdoc_qta * rigamerce_premio;
 | 
						|
          rigamerce->put(RC_1_BONUS, somma_bonus);
 | 
						|
 | 
						|
          rigamerce->add(RDOC_QTA, normalized_rdoc_qta);              //riscrive sul campo di appoggio del contratto
 | 
						|
 | 
						|
          elaborato = true;
 | 
						|
        }
 | 
						|
 | 
						|
      } //if(rigamerce_premio != ZERO...
 | 
						|
 | 
						|
 | 
						|
    } //if(rdoc_codart...
 | 
						|
  } //FOR_EACH_PHYSICAL..
 | 
						|
  return elaborato;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//aggiorna, in base al documento in esame curr_doc, le somme restituite nelle righe di tipo verigh02 nei contratti validi..
 | 
						|
//..del cliente
 | 
						|
bool THardy_elab_docs::elabora_contratti(TDocumento& curr_doc, TArray& contratti_cliente)
 | 
						|
{
 | 
						|
  bool elaborato = false;
 | 
						|
 | 
						|
  FOR_EACH_PHYSICAL_RDOC(curr_doc, r, rdoc)  if (rdoc->is_merce())  //giro su tutte le righe merce delle fatture
 | 
						|
  {
 | 
						|
    TString80 rdoc_codart = rdoc->get(RDOC_CODART); //non si riesce ad usare un TString& perchè lo perde dopo un pò
 | 
						|
    rdoc_codart.trim();
 | 
						|
    const real rdoc_qta = rdoc->quantita();
 | 
						|
 | 
						|
    //controlla se il codart della riga esiste in uno dei contratti validi
 | 
						|
    for (int i = 0; i < contratti_cliente.items(); i++)
 | 
						|
    {
 | 
						|
      TContratto_premi& contratto = (TContratto_premi&)contratti_cliente[i];
 | 
						|
      elaborato |= aggiorna_contratti(*rdoc, contratto);
 | 
						|
    } //for(int i..
 | 
						|
  } //FOR_EACH...
 | 
						|
 | 
						|
  return elaborato;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool THardy_elab_docs::genera_nac(const TMask& mask, TArray& contratti_cliente, TArray& documenti_cliente, TLog_report& log)
 | 
						|
{
 | 
						|
  //si informa se l'elaborazione è definitiva o meno
 | 
						|
  const bool definitivo = mask.get_bool(F_DEFINITIVO);
 | 
						|
 | 
						|
  //giro su tutti i contratti del cliente che stanno nell'array (ogni contratto genera una NAC)
 | 
						|
  FOR_EACH_ARRAY_ITEM(contratti_cliente, r, riga)
 | 
						|
  {
 | 
						|
    TContratto_premi& contratto = *(TContratto_premi*)riga;
 | 
						|
    const long ndoc = contratto.numero();    //il numdoc del contratto serve nelle segnalazioni
 | 
						|
    const long codcf = contratto.codcf();    //il codice cliente ci serve nella generazione della NAC..
 | 
						|
    const char tipo_contratto = contratto.tipo_contratto();  //..e pure il tipo di contratto in esame!
 | 
						|
 | 
						|
    //segnaliamo l'elaborazione del contratto sul log
 | 
						|
    TString log_msg;
 | 
						|
    log_msg.format("Contratto:%6ld Cliente:%6ld", ndoc, codcf);
 | 
						|
    //log_msg << "Contratto: " << ndoc << " Cliente: " << codcf;
 | 
						|
 | 
						|
    //  generazione del documento NAC dal contratto
 | 
						|
    //  -------------------------------------------
 | 
						|
 | 
						|
    //  TESTATA
 | 
						|
 | 
						|
    //alcuni parametri delle righe vanno presi dalla configurazione
 | 
						|
    TConfig config(CONFIG_DITTA, "ha");
 | 
						|
    TString4 nac_codnum, nac_tipo;
 | 
						|
    TString8 cod_riga;
 | 
						|
    switch (tipo_contratto)
 | 
						|
    {
 | 
						|
    case 'A':
 | 
						|
      nac_codnum = config.get("NaAntNum");
 | 
						|
      nac_tipo = config.get("NaAntTip");
 | 
						|
      cod_riga = config.get("NaAntSpe");
 | 
						|
      break;
 | 
						|
    case 'R':
 | 
						|
      nac_codnum = config.get("NaRifaNum");
 | 
						|
      nac_tipo = config.get("NaRifaTip");
 | 
						|
      cod_riga = config.get("NaRifaSpe");
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      nac_codnum = config.get("NaPostNum");
 | 
						|
      nac_tipo = config.get("NaPostTip");
 | 
						|
      cod_riga = config.get("NaPostSpe");
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    const int anno = mask.get_date(F_ADATA).year();
 | 
						|
    //solo in caso di elaborazione definitiva si scrivono NAC di tipo D; sennò di tipo P, che sono uccidibili..
 | 
						|
    //..all'inizio di ogni nuova elaborazione
 | 
						|
    char provv = 'P';
 | 
						|
    if (definitivo)
 | 
						|
      provv = 'D';
 | 
						|
 | 
						|
    TDocumento nac(provv, anno, nac_codnum, 0);   //num_doc = 0 perchè viene aggiornato in fase di registrazione
 | 
						|
    nac.set_tipo(nac_tipo);
 | 
						|
    nac.put(DOC_STATO, 1);
 | 
						|
    nac.put(DOC_DATADOC, mask.get(F_DATAELAB));
 | 
						|
    nac.put(DOC_TIPOCF, 'C');
 | 
						|
    nac.put(DOC_CODCF, codcf);
 | 
						|
 | 
						|
 | 
						|
    //  RIGHE
 | 
						|
 | 
						|
    //ogni riga di tipo merce (verigh01) del contratto origina una riga della NAC
 | 
						|
    //noto il codice di riga spesa (che farà le veci del codart), troviamo il tipo riga dalla tabella SPP e tutte le features che servono
 | 
						|
    const TRectype& rec_spp = cache().get("SPP", cod_riga);
 | 
						|
    const TString4 tipo_riga =  rec_spp.get("S8");
 | 
						|
    const TString80 descr_riga_spp = rec_spp.get("S0");
 | 
						|
    const TString4 codiva = rec_spp.get("S3");
 | 
						|
 | 
						|
    //giro sulle righe del contratto, che originano le righe NAC
 | 
						|
    for (int i = 1; i <= contratto.rows(); i++)
 | 
						|
    {
 | 
						|
      const TRiga_documento& riga_contratto = contratto[i];  //le righe di un documento partono da 1! (standard del mercoledì)
 | 
						|
      const TString& tiporiga = riga_contratto.get(RDOC_TIPORIGA);
 | 
						|
 | 
						|
      TString80 riga_contratto_codart = riga_contratto.get(RDOC_CODART);
 | 
						|
 | 
						|
      //solo le righe di tipo merce (verigh01) dei contratti devono comparire nelle NAC
 | 
						|
      if (tiporiga == HARDY_TIPORIGA_MERCE)
 | 
						|
      {
 | 
						|
        const real riga_contratto_qta = riga_contratto.get_real(RDOC_QTA);
 | 
						|
        const TString4 riga_contratto_um = riga_contratto.get(RDOC_UMQTA);
 | 
						|
        const real riga_contratto_premio = riga_contratto.get_real(RC_1_PREMIO);
 | 
						|
 | 
						|
        // riga merce NAC
 | 
						|
        TRiga_documento& nac_row = nac.new_row(tipo_riga);
 | 
						|
        nac_row.put(RDOC_CODART, cod_riga);
 | 
						|
    
 | 
						|
        //panegirico della descrizione
 | 
						|
        nac_row.put(RDOC_DESCR, descr_riga_spp);
 | 
						|
 | 
						|
        TString msg;
 | 
						|
        const TDate adata = mask.get_date(F_ADATA);
 | 
						|
        TDate dadata = mask.get_date(F_DADATA);
 | 
						|
        if (!dadata.ok())
 | 
						|
          check_date(adata, dadata);
 | 
						|
 | 
						|
        msg << " " << dadata << " -- " << adata << " --(Art." << riga_contratto_codart << ")";
 | 
						|
        nac_row.put(RDOC_DESCEST, msg);
 | 
						|
        nac_row.put(RDOC_DESCLUNGA, "X");
 | 
						|
 | 
						|
        //importi, qta, umqta
 | 
						|
        nac_row.put(RDOC_UMQTA, riga_contratto_um);
 | 
						|
        nac_row.put(RDOC_QTA, riga_contratto_qta);
 | 
						|
        nac_row.put(RDOC_PREZZO, riga_contratto_premio);
 | 
						|
 | 
						|
        //iva
 | 
						|
        nac_row.put(RDOC_CODIVA, codiva);
 | 
						|
      }
 | 
						|
 | 
						|
      //trattazione speciale delle righe spese (verigh02) (solo 'A'nticipi e 'R'ifatturazioni)
 | 
						|
      if (tiporiga == HARDY_TIPORIGA_SOMMA && (tipo_contratto == 'A' || tipo_contratto == 'R'))
 | 
						|
      {
 | 
						|
        const real somma_anticipata = riga_contratto.get_real(RCA_2_ANTICIPATO);
 | 
						|
        real somma_resa_storica = riga_contratto.get_real(RCA_2_RESO_STORICO);
 | 
						|
        real somma_resa_corrente = riga_contratto.get_real(RCA_2_RESO_CORRENTE);
 | 
						|
 | 
						|
        const real esubero = somma_resa_storica + somma_resa_corrente - somma_anticipata;
 | 
						|
        if (esubero > ZERO)
 | 
						|
        {
 | 
						|
          somma_resa_corrente -= esubero;
 | 
						|
 | 
						|
          //se c'è un esubero nel rimborso dell'anticipo esisterà solo una riga nella NAC, con una cifra pari alla somma..
 | 
						|
          //..che mancava a pareggiare l'anticipo (anche se l'esubero eccedesse tale differenza, sulla NAC ci va la somma a..
 | 
						|
          //..pareggio! così freghiamo qualcosa al cliente)
 | 
						|
          nac.destroy_rows();
 | 
						|
 | 
						|
          // riga spesa NAC
 | 
						|
          TRiga_documento& nac_row = nac.new_row(tipo_riga);
 | 
						|
          nac_row.put(RDOC_CODART, cod_riga);
 | 
						|
    
 | 
						|
          //panegirico della descrizione
 | 
						|
          nac_row.put(RDOC_DESCR, descr_riga_spp);
 | 
						|
 | 
						|
          TString msg;
 | 
						|
          const TDate adata = mask.get_date(F_ADATA);
 | 
						|
          TDate dadata = mask.get_date(F_DADATA);
 | 
						|
          if (!dadata.ok())
 | 
						|
            check_date(adata, dadata);
 | 
						|
 | 
						|
          msg << " " << dadata << " -- " << adata;
 | 
						|
          nac_row.put(RDOC_DESCEST, msg);
 | 
						|
          nac_row.put(RDOC_DESCLUNGA, "X");
 | 
						|
 | 
						|
          //importi, qta
 | 
						|
          nac_row.put(RDOC_QTA, 1);
 | 
						|
          nac_row.put(RDOC_PREZZO, somma_resa_corrente);
 | 
						|
 | 
						|
          //iva
 | 
						|
          nac_row.put(RDOC_CODIVA, codiva);
 | 
						|
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //  salvataggi vari
 | 
						|
    //  ---------------
 | 
						|
    //  NAC
 | 
						|
    //  viene scritta comunque, con provv='D' se elaborazione definitiva
 | 
						|
    int err = nac.write();
 | 
						|
 | 
						|
    TString wrk_msg;
 | 
						|
    if (err == NOERR)
 | 
						|
    {
 | 
						|
      wrk_msg.format(" -- Generata NAC: %-4s%-4s%c %7ld", (const char*)nac_codnum, (const char*)nac_tipo, provv, nac.get_long(DOC_NDOC));
 | 
						|
      log_msg << wrk_msg;
 | 
						|
    }
 | 
						|
    else
 | 
						|
      log_msg << " -- Impossibile generare NAC !!";
 | 
						|
 | 
						|
    //  CONTRATTO
 | 
						|
 | 
						|
    //se il contratto è di tipo A/R aggiorna la riga spese speciale (verigh02)
 | 
						|
    if ((tipo_contratto == 'A' || tipo_contratto == 'R') && err == NOERR)
 | 
						|
    {
 | 
						|
      FOR_EACH_PHYSICAL_RDOC(contratto, r, rdoc)
 | 
						|
      {
 | 
						|
        if (rdoc->get(RDOC_TIPORIGA) == HARDY_TIPORIGA_SOMMA)
 | 
						|
        {
 | 
						|
          const real anticipato = rdoc->get_real(RCA_2_ANTICIPATO);
 | 
						|
          real reso_storico = rdoc->get_real(RCA_2_RESO_STORICO);
 | 
						|
          reso_storico += rdoc->get_real(RCA_2_RESO_CORRENTE);
 | 
						|
          rdoc->put(RCA_2_RESO_STORICO, reso_storico);
 | 
						|
          //se il contratto è andato a pareggio avverte dilegentemente l'operatore
 | 
						|
          if (reso_storico >= anticipato)
 | 
						|
            log_msg << " -- Contratto pareggiato!";
 | 
						|
 | 
						|
        } //if (rdoc->get(RDOC_TIPORIGA)...
 | 
						|
      } //FOR_EACH_PHYSICAL_RDOC(contratto...
 | 
						|
    } //if (tipo_contratto == 'A'..
 | 
						|
 | 
						|
 | 
						|
    // se non ci sono errori -> in caso di elaborazione definitiva procede alla registrazione..
 | 
						|
    //.. del contratto (ricordiamo che in memoria il contratto ha già le righe aggiornate
 | 
						|
    if (definitivo && err == NOERR)
 | 
						|
    {
 | 
						|
      //alla fine della fiera aggiorna il contratto
 | 
						|
      err = contratto.rewrite();
 | 
						|
 | 
						|
      if (err == NOERR)
 | 
						|
        log_msg << " -- Contratto aggiornato";
 | 
						|
      else
 | 
						|
        log_msg << " -- Impossibile aggiornare contratto";
 | 
						|
    }
 | 
						|
 
 | 
						|
    log.log(0, log_msg);
 | 
						|
    log.log(0, "");
 | 
						|
 | 
						|
  } //FOR_EACH_ARRAY_ITEM(...  giro sui contratti cliente
 | 
						|
 | 
						|
  
 | 
						|
  //il metodo ritornerà il successo o meno della registrazione
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void THardy_elab_docs::elabora_documenti(const TMask& mask, TISAM_recordset& fatture, TLog_report& log)
 | 
						|
{
 | 
						|
  TProgind pi(fatture.items(), TR("Elaborazione documenti in corso..."), true, true);
 | 
						|
 | 
						|
  //inizializza variabili da usare nella scansione del recordset
 | 
						|
  long old_codcf = 0L;
 | 
						|
  //array con l'insieme dei contratti e dei documenti elaborati per un singolo cliente!
 | 
						|
  TArray contratti_cliente, documenti_cliente;
 | 
						|
 | 
						|
  //giro sulle fatture (è il giro di più alto livello che viene esteso all'interno delle elabora_contratti)
 | 
						|
  for (bool ok = fatture.move_first(); ok; ok = fatture.move_next())
 | 
						|
	{
 | 
						|
    if (!pi.addstatus(1))
 | 
						|
      break;
 | 
						|
 | 
						|
    const long codcf = fatture.get(DOC_CODCF).as_int();
 | 
						|
    //al cambio cliente deve controllare i contratti di quel cliente nel periodo di elaborazione!!
 | 
						|
    if (codcf != old_codcf)
 | 
						|
    {
 | 
						|
      //generazione NAC del cliente precedente (una per contratto cliente)
 | 
						|
      if (old_codcf > 0)
 | 
						|
        genera_nac(mask, contratti_cliente, documenti_cliente, log);
 | 
						|
 | 
						|
 | 
						|
      CHECK(codcf > old_codcf, "Ordinamento clienti errato!");
 | 
						|
      //aggiorna old_codcf in modo da poter controllare i contratti solo al cambio codcf
 | 
						|
      old_codcf = codcf;
 | 
						|
 | 
						|
      const int n_contratti = find_contratti_cliente(codcf, mask, contratti_cliente);
 | 
						|
      if (n_contratti == 0)
 | 
						|
      {
 | 
						|
        TString msg;
 | 
						|
        msg << "Il cliente " << codcf << " non ha un contratto premi valido nel periodo di elaborazione selezionato ma ha fatture.";
 | 
						|
        log.log_error(msg);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (contratti_cliente.items() > 0)
 | 
						|
    {
 | 
						|
      //se ha trovato uno o più contratti validi nel periodo passa alla elaborazione dei documenti del cliente
 | 
						|
      TDocumento* curr_doc = new TDocumento(fatture.cursor()->curr());
 | 
						|
      //elabora il documento corrente aggiornando le somme restituite sui contratti validi
 | 
						|
      if (elabora_contratti(*curr_doc, contratti_cliente))
 | 
						|
        documenti_cliente.add(curr_doc);
 | 
						|
      else
 | 
						|
        delete(curr_doc);
 | 
						|
    }
 | 
						|
  } //for (bool ok = recset.move_first()...
 | 
						|
 | 
						|
  //generazione NAC dell'ultimo cliente (una per contratto cliente)
 | 
						|
  genera_nac(mask, contratti_cliente, documenti_cliente, log);
 | 
						|
 | 
						|
  //se elaborazione definitiva -> cambia lo stato ai documenti di vendita elaborati, mettendolo uguale..
 | 
						|
  //..a quello deciso in configurazione
 | 
						|
  const bool definitivo = mask.get_bool(F_DEFINITIVO);
 | 
						|
  if (definitivo)
 | 
						|
  {
 | 
						|
    TConfig config(CONFIG_DITTA, "ha");
 | 
						|
    const TString& stato_finale = config.get("StatoFinFatt");
 | 
						|
    FOR_EACH_ARRAY_ITEM(documenti_cliente, r, riga)
 | 
						|
    {
 | 
						|
      TDocumento& fattura = *(TDocumento*)riga;
 | 
						|
      fattura.put(DOC_STATO, stato_finale);
 | 
						|
      fattura.rewrite();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//metodo di alto livello con i punti principali del programma (come da analisi...)
 | 
						|
void THardy_elab_docs::elabora(const TMask& mask)
 | 
						|
{
 | 
						|
  //1)  eventuale accoppamento di tutti i documenti provvisori creati con precedenti elaborazioni precedenti
 | 
						|
  int nac_killed = 0;
 | 
						|
  if (mask.get_bool(F_KILLPROVV))
 | 
						|
    nac_killed = kill_provv_nac(mask);
 | 
						|
 | 
						|
  //log report con segnalazioni sui clienti trattati (bene o male)
 | 
						|
  TLog_report log("Sintesi elaborazione");
 | 
						|
  log.kill_duplicates();
 | 
						|
  log.log(0, "");
 | 
						|
 | 
						|
  //2)  recordset ordinato codag-codcf-numdoc con tutti i docs che soddisfano i parametri dell'utente
 | 
						|
  //    ---------------------------------------------------------------------------------------------
 | 
						|
  TISAM_recordset recset("");
 | 
						|
  const long items = genera_recordset(mask, recset);
 | 
						|
  if (items == 0)
 | 
						|
  {
 | 
						|
    log.log(1, "Non esistono documenti di vendita che soddisfino i parametri selezionati! Ritenta sarai più fortunato!");
 | 
						|
  }
 | 
						|
 | 
						|
  //3)  elaborazione documenti e contratti, generazione NAC, salvataggi
 | 
						|
  //    ---------------------------------------------------------------
 | 
						|
  elabora_documenti(mask, recset, log);
 | 
						|
 | 
						|
  //3)  scrittura log
 | 
						|
  //    -------------
 | 
						|
  log.print_or_preview();
 | 
						|
}
 | 
						|
 | 
						|
void THardy_elab_docs::main_loop()
 | 
						|
{
 | 
						|
  THardy_elab_docs_mask mask;
 | 
						|
  while (mask.run() == K_ENTER)
 | 
						|
  {
 | 
						|
    elabora(mask);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool THardy_elab_docs::create()
 | 
						|
{
 | 
						|
  open_files(LF_DOC, LF_RIGHEDOC, 0);
 | 
						|
 | 
						|
	return TSkeleton_application::create();
 | 
						|
}
 | 
						|
 | 
						|
int ha0500 (int argc, char* argv[])
 | 
						|
{
 | 
						|
  THardy_elab_docs elabapp;
 | 
						|
  elabapp.run(argc, argv, TR("Generazione NAC"));
 | 
						|
  return 0;
 | 
						|
} |