campo-sirio/ha/ha0500.cpp
guy 077cb844e9 Patch level : 10.0
Files correlati     : ha0 ha3 ha3900a.msk hatbatt.msk
Ricompilazione Demo : [ ]
Commento            :
Correzioni varie su gestione attrezzature


git-svn-id: svn://10.65.10.50/branches/R_10_00@22587 c028cbd2-c16b-5b4b-a496-9718f37d4682
2012-02-24 14:57:04 +00:00

828 lines
29 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() : TAutomask ("ha0500a") {}
};
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(TR("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 codcfatt, 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 TString4 tipo_doc_to_elab1 = config.get("TipoFatt");
const TString4 tipo_doc_to_elab2 = config.get("TipoFatt2");
// Inutile testare tutte le numerazioni, basta il tipo documento
query << "&&((" << DOC_TIPODOC << "=='" << tipo_doc_to_elab1 << "')||(" << DOC_TIPODOC << "=='" << tipo_doc_to_elab2 << "'))";
//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 codcfatt, const TMask& mask, TArray& contratti_cliente)
{
contratti_cliente.destroy();
//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 TString4 tip_ant = config.get("CoAntTip");
const TString4 tip_rifa = config.get("CoRifaTip");
const TString4 tip_post = config.get("CoPostTip");
TAssoc_array cod_num_cont;
cod_num_cont.add(config.get("CoAntNum"));
cod_num_cont.add(config.get("CoRifaNum"));
cod_num_cont.add(config.get("CoPostNum"));
FOR_EACH_ASSOC_OBJECT(cod_num_cont, h, k, o)
{
//deve cercare tutti i contratti del cliente e metterli nell'array
TString query;
query << "USE DOC KEY 5";
query << "\nSELECT ((TIPODOC=#A_TIPODOC)||(TIPODOC=#R_TIPODOC)||(TIPODOC=#P_TIPODOC))&&(STR(DOC2=#CODCF))";
query << "\nFROM PROVV=D CODNUM=" << k;
query << "\nTO PROVV=D CODNUM=" << k;
TISAM_recordset recset(query);
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", codcfatt);
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);
// 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 TString8 codage = contratto.get(DOC_CODAG);
if (codage.full()) // Controlla se esiste una spesa su misura per l'agente
{
TString8 codspesa = cod_riga;
codspesa << codage.right(3);
const TRectype& rec_spp = cache().get("SPP", codspesa);
if (!rec_spp.empty())
cod_riga = codspesa;
}
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);
nac.put(DOC_CODAG, codage);
nac.put(DOC_CODPAG, contratto.get(DOC_CODPAG));
nac.put(DOC_DOC1, contratto.get(DOC_DOC1));
nac.put(DOC_DATADOCRIF, contratto.get(DOC_DATADOCRIF));
// 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;
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 diligentemente 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!");
}
//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;
}