780 lines
26 KiB
C++
780 lines
26 KiB
C++
|
#include <applicat.h>
|
|||
|
#include <automask.h>
|
|||
|
#include <dongle.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 <20> piena -> l'anno deve essere lo stesso nelle 2 date;
|
|||
|
//se invece <20> 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 <20> 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_anticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto);
|
|||
|
bool aggiorna_contratti_posticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto);
|
|||
|
bool aggiorna_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 <20> 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<63>, 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<70> 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'<27> 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 <20> 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 ((CODNUM=#A_CODNUM)||(CODNUM=#R_CODNUM)||(CODNUM=#P_CODNUM))";
|
|||
|
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& num_ant = config.get("CoAntNum");
|
|||
|
const TString& num_rifa = config.get("CoRifaNum");
|
|||
|
const TString& num_post = config.get("CoPostNum");
|
|||
|
|
|||
|
recset.set_var("#A_CODNUM", num_ant);
|
|||
|
recset.set_var("#R_CODNUM", num_rifa);
|
|||
|
recset.set_var("#P_CODNUM", num_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())
|
|||
|
{
|
|||
|
//controlla il tipo di contratto
|
|||
|
const char tipo_contr = recset.get(DOC_TIPOCFFATT).as_string()[0];
|
|||
|
|
|||
|
//contratti anticipo 'A': datainizio esiste sempre, datafine non esiste (va ad esaurimento)
|
|||
|
//contratti posticipo 'P': datainizio esiste sempre, datafine pu<70> non esistere
|
|||
|
//contratti rifatturazione 'R': come contratti anticipo
|
|||
|
|
|||
|
//controlla validit<69> 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 (<28> 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;
|
|||
|
if (tipo_contr == 'P')
|
|||
|
{
|
|||
|
data_fine_contratto = recset.get(DOC_DATAFCOMP).as_date();
|
|||
|
if (data_fine_contratto.ok())
|
|||
|
{
|
|||
|
if (data_fine_contratto < data_ini_elab)
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
TDocumento* curr_contratto = new TDocumento(recset.get(DOC_PROVV).as_string()[0], recset.get(DOC_ANNO).as_int(),
|
|||
|
recset.get(DOC_CODNUM).as_string(), recset.get(DOC_NDOC).as_int());
|
|||
|
contratti_cliente.add(curr_contratto);
|
|||
|
}
|
|||
|
|
|||
|
return contratti_cliente.items();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
bool THardy_elab_docs::aggiorna_contratti_anticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto)
|
|||
|
{
|
|||
|
bool elaborato = false;
|
|||
|
|
|||
|
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 <20> nullo procede all'aggiornamento del restituito
|
|||
|
if (rigamerce_premio != ZERO)
|
|||
|
{
|
|||
|
//aggiornamento delle righe di tipo spesa (verigH02) per aggiornare le somme restituite
|
|||
|
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())
|
|||
|
{
|
|||
|
//usa qtagg3 come campo di appoggio per il calcolo della somma restituita dovuta al contratto (parte da zero per ogni elaborazione di NAC)
|
|||
|
real somma_restituita = rigacontratto->get_real(RCA_2_RESTITUITO);
|
|||
|
//la somma restituita deve essere incrementata per la qta di merce (caff<66>) che c'<27> sulla riga della fattura in esame...
|
|||
|
//..moltiplicata per il premio che c'<27> nella riga di tipo merce del contratto in esame
|
|||
|
somma_restituita += rdoc_qta * rigamerce_premio;
|
|||
|
rigacontratto->put(RCA_2_RESTITUITO, somma_restituita);
|
|||
|
elaborato = true;
|
|||
|
}
|
|||
|
} //FOR_EACH_PHYSICAL.. fine casino sulla riga di tipo spese
|
|||
|
|
|||
|
if (rigamerce->is_merce())
|
|||
|
{
|
|||
|
real somma_bonus = rigamerce->get_real(RC_1_BONUS);
|
|||
|
somma_bonus += rdoc_qta * rigamerce_premio;
|
|||
|
rigamerce->put(RC_1_BONUS, somma_bonus);
|
|||
|
elaborato = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//aggiornamento delle quantit<69> per le righe di tipo merce (verigH01)
|
|||
|
if (rigamerce->is_merce())
|
|||
|
{
|
|||
|
real qta_tot = rigamerce->get_real(RDOC_QTA); //prende la qta tot dal contratto (<28> usato un campo di appoggio RDOC_QTA)
|
|||
|
qta_tot += rdoc_qta; //aggiunge la qta della riga documento
|
|||
|
rigamerce->put(RDOC_QTA, qta_tot); //riscrive sul campo di appoggio del contratto
|
|||
|
}
|
|||
|
|
|||
|
} //if(rdoc_codart...
|
|||
|
} //FOR_EACH_PHYSICAL..
|
|||
|
return elaborato;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
bool THardy_elab_docs::aggiorna_contratti_posticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto)
|
|||
|
{
|
|||
|
bool elaborato = false;
|
|||
|
|
|||
|
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);
|
|||
|
//..aggiorna direttamente il bonus totale per l'articolo presente sulla riga
|
|||
|
if (rigamerce_premio != ZERO)
|
|||
|
{
|
|||
|
//usa QTAGG3 come campo di appoggio per il calcolo della somma restituita dovuta al contratto (parte da zero per ogni elaborazione di NAC)
|
|||
|
real somma_bonus = rigamerce->get_real(RC_1_BONUS);
|
|||
|
somma_bonus += rdoc_qta * rigamerce_premio;
|
|||
|
rigamerce->put(RC_1_BONUS, somma_bonus);
|
|||
|
elaborato = true;
|
|||
|
} //if(rigamerce...
|
|||
|
|
|||
|
//aggiornamento delle righe di tipo merce (verigH01)
|
|||
|
if (rigamerce->is_merce())
|
|||
|
{
|
|||
|
real qta_tot = rigamerce->get_real(RDOC_QTA);
|
|||
|
qta_tot += rdoc_qta;
|
|||
|
rigamerce->put(RDOC_QTA, qta_tot);
|
|||
|
}
|
|||
|
|
|||
|
} //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::aggiorna_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<63> 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++)
|
|||
|
{
|
|||
|
TDocumento& contratto = (TDocumento&)contratti_cliente[i];
|
|||
|
const TString& tipo_contratto = contratto.get(DOC_TIPOCFFATT);
|
|||
|
|
|||
|
//in base al tipo di contratto (Anticipo/Posticipo/Rifatturazione) decide cosa fare
|
|||
|
if (tipo_contratto == "A" || tipo_contratto == "R")
|
|||
|
{
|
|||
|
elaborato |= aggiorna_contratti_anticipo(rdoc_codart, rdoc_qta, contratto);
|
|||
|
} //if(tipo_contratto...
|
|||
|
else if (tipo_contratto == "P")
|
|||
|
{
|
|||
|
elaborato |= aggiorna_contratti_posticipo(rdoc_codart, rdoc_qta, 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 <20> 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)
|
|||
|
{
|
|||
|
TDocumento& contratto = *(TDocumento*)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.get(DOC_TIPOCFFATT)[0]; //..e pure il tipo di contratto in esame!
|
|||
|
|
|||
|
//segnaliamo l'elaborazione del contratto sul log
|
|||
|
TString msg;
|
|||
|
msg << "Elaborato contratto premi n." << ndoc << " del cliente " << codcf;
|
|||
|
log.log(0, msg);
|
|||
|
|
|||
|
|
|||
|
// 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<6E> 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<63> 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<61> 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<65>)
|
|||
|
const TString& tiporiga = riga_contratto.get(RDOC_TIPORIGA);
|
|||
|
const TString& tipo_riga_contratto = cache().get("%TRI", tiporiga, "S7");
|
|||
|
|
|||
|
//solo le righe di tipo merce (verigh01) dei contratti devono comparire nelle NAC
|
|||
|
if (tipo_riga_contratto == "M")
|
|||
|
{
|
|||
|
TString80 riga_contratto_codart = riga_contratto.get(RDOC_CODART);
|
|||
|
riga_contratto_codart.trim();
|
|||
|
const real riga_contratto_bonus = riga_contratto.get_real(RDOC_QTAGG3);
|
|||
|
if (riga_contratto_bonus != ZERO)
|
|||
|
int cazzone = 1;
|
|||
|
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 (dovrebbe essere un'unica riga per NAC, il cui valore sta in QTAGG3 ed <20> stato calcolato nella aggiorna_contratti())
|
|||
|
TRiga_documento& nac_row = nac.new_row(tipo_riga);
|
|||
|
nac_row.put(RDOC_NRIGA, i);
|
|||
|
nac_row.put(RDOC_CODART, cod_riga);
|
|||
|
|
|||
|
//panegirico della descrizione
|
|||
|
nac_row.put(RDOC_DESCR, descr_riga_spp);
|
|||
|
|
|||
|
msg.cut(0); //risparmiamo sulle stringhe, mica sono gratis
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// salvataggi vari
|
|||
|
// ---------------
|
|||
|
//la NAC viene scritta comunque, con provv='D' se elaborazione definitiva
|
|||
|
int err = nac.write();
|
|||
|
|
|||
|
msg.cut(0); //la fase di risparmio stringhe continua
|
|||
|
if (err == NOERR)
|
|||
|
msg << "Generata NAC ";
|
|||
|
else
|
|||
|
msg << "Impossibile generare NAC ";
|
|||
|
msg << " - provv:" << provv << " - num:" << nac_codnum << " - tipo:" << nac_tipo << " - anno:" << anno << " |" << r;
|
|||
|
log.log(0, msg);
|
|||
|
|
|||
|
// se non ci sono errori -> in caso di elaborazione definitiva procede alla registrazione..
|
|||
|
//.. del contratto (ricordiamo che in memoria il contratto ha gi<67> le righe aggiornate
|
|||
|
if (definitivo && err == NOERR)
|
|||
|
{
|
|||
|
//prima di registrare il contratto vanno svuotati i campi appoggio sulle righe che sono stati usati..
|
|||
|
//..per qta e premi vari e riempiti nella aggiorna_contratti()
|
|||
|
for (int i = 1; i <= contratto.rows(); i++)
|
|||
|
{
|
|||
|
TRiga_documento& riga_contratto = contratto[i];
|
|||
|
riga_contratto.put(RDOC_QTAGG3, ZERO);
|
|||
|
riga_contratto.put(RDOC_QTA, ZERO);
|
|||
|
}
|
|||
|
|
|||
|
//alla fine della fiera aggiorna il contratto
|
|||
|
err = contratto.rewrite();
|
|||
|
msg.cut(0);
|
|||
|
if (err == NOERR)
|
|||
|
msg << "Aggiornato contratto premi n. ";
|
|||
|
else
|
|||
|
msg << "Impossibile aggiornare il contratto premi n. ";
|
|||
|
|
|||
|
msg << ndoc << " del cliente " << codcf;
|
|||
|
log.log(0, msg);
|
|||
|
}
|
|||
|
|
|||
|
log.log(0, "");
|
|||
|
|
|||
|
} //FOR_EACH_ARRAY_ITEM(... giro sui contratti cliente
|
|||
|
|
|||
|
|
|||
|
//il metodo ritorner<65> il successo o meno della registrazione
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void THardy_elab_docs::elabora_documenti(const TMask& mask, TISAM_recordset& recset, TLog_report& log)
|
|||
|
{
|
|||
|
TProgind pi(recset.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 (<28> il giro di pi<70> alto livello che viene esteso all'interno delle aggiorna_contratti)
|
|||
|
for (bool ok = recset.move_first(); ok; ok = recset.move_next())
|
|||
|
{
|
|||
|
if (!pi.addstatus(1))
|
|||
|
break;
|
|||
|
|
|||
|
const long codcf = recset.get(DOC_CODCF).as_int();
|
|||
|
//al cambio cliente deve controllare i contratti di quel cliente nel periodo di elaborazione!!
|
|||
|
if (codcf != old_codcf)
|
|||
|
{
|
|||
|
//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<70> contratti validi nel periodo passa alla elaborazione dei documenti del cliente
|
|||
|
TDocumento* curr_doc = new TDocumento(recset.cursor()->curr());
|
|||
|
//elabora il documento corrente aggiornando le somme restituite sui contratti validi
|
|||
|
if (aggiorna_contratti(*curr_doc, contratti_cliente))
|
|||
|
documenti_cliente.add(curr_doc);
|
|||
|
else
|
|||
|
delete(curr_doc);
|
|||
|
}
|
|||
|
} //for (bool ok = recset.move_first()...
|
|||
|
|
|||
|
//generazione NAC (una per contratto cliente)
|
|||
|
genera_nac(mask, contratti_cliente, documenti_cliente, log);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//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<70> 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()
|
|||
|
{
|
|||
|
//controlla se la chiave ha l'autorizzazione a questo programma (solo per hardy!)
|
|||
|
Tdninst dninst;
|
|||
|
if (!dninst.can_I_run(true))
|
|||
|
return error_box(TR("Programma non autorizzato!"));
|
|||
|
|
|||
|
open_files(LF_DOC, LF_RIGHEDOC, 0);
|
|||
|
|
|||
|
return TSkeleton_application::create();
|
|||
|
}
|
|||
|
|
|||
|
int ha0500 (int argc, char* argv[])
|
|||
|
{
|
|||
|
THardy_elab_docs main_app;
|
|||
|
main_app.run(argc, argv, TR("Elaborazione documenti Hardy"));
|
|||
|
return true;
|
|||
|
}
|