530c414206
git-svn-id: svn://10.65.10.50/branches/R_10_00@22904 c028cbd2-c16b-5b4b-a496-9718f37d4682
1187 lines
42 KiB
C++
Executable File
1187 lines
42 KiB
C++
Executable File
#include <applicat.h>
|
|
#include <automask.h>
|
|
#include <progind.h>
|
|
#include <recarray.h>
|
|
#include <recset.h>
|
|
#include <reputils.h>
|
|
#include <utility.h>
|
|
|
|
#include <doc.h>
|
|
#include <rdoc.h>
|
|
#include "../cg/cglib01.h"
|
|
#include "../cg/cgsaldac.h"
|
|
#include "../ef/ef0101.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_DADATA:
|
|
if ((e == fe_close || e == fe_modify) && !o.empty())
|
|
{
|
|
//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
|
|
TDate da_data = o.get();
|
|
const TDate a_data = get_date(F_ADATA);
|
|
if (da_data.ok())
|
|
{
|
|
bool changed = false;
|
|
if (da_data.day() != 1)
|
|
{
|
|
da_data.set_day(1);
|
|
changed = true;
|
|
}
|
|
const int tc = get_int(F_TIPOCONTR);
|
|
if (tc != 8) // non è nolo
|
|
{
|
|
const int m = da_data.month();
|
|
const int r = m % 3;
|
|
if (r != 1)
|
|
{
|
|
da_data.set_month(m - (r == 0 ? 2 : (r-1)));
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed)
|
|
o.set(da_data.string());
|
|
}
|
|
}
|
|
break;
|
|
case F_ADATA:
|
|
if ((e == fe_close || e == fe_modify) && !o.empty())
|
|
{
|
|
const TDate al = o.get();
|
|
const TDate dal = get(F_DADATA);
|
|
if (dal.ok() && dal.year() != al.year())
|
|
return error_box(TR("Le date devono appartenere allo stesso anno!"));
|
|
}
|
|
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().full())
|
|
{
|
|
set(F_KILLPROVV, "X");
|
|
disable(F_KILLPROVV);
|
|
}
|
|
else
|
|
{
|
|
reset(F_KILLPROVV);
|
|
enable(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_contratto(const TRiga_documento& rdoc, TContratto_premi& contratto, TLog_report& log);
|
|
bool deve_generare_nac(const TContratto_premi& contratto, const TDate& data) const;
|
|
word elabora_contratti(TDocumento& curr_doc, TArray& contratti_cliente, const TDate& data_fine, TLog_report& log);
|
|
bool genera_nac(const TMask& mask, TArray& contratti_cliente, TAssoc_array& nac_nolo, TArray& documenti_cliente, TLog_report& log);
|
|
bool genera_fat(const TMask& mask, TContratto_premi& contratto, TToken_string& nakey, TLog_report& log);
|
|
bool genera_eff(const TDocumento& fat, const real& tot_nac, TLog_report& log);
|
|
|
|
//metodi basso livello
|
|
word find_contratti_cliente(const long codcfatt, const TMask& mask, int flags, TArray& contratti_cliente);
|
|
void check_date(const TDate& datafine, TDate& dataini);
|
|
int find_numerazioni(const TString& tipo_to_elab, TString_array& num_doc);
|
|
int month_diff(const TDate& inizio, const TDate& fine) const;
|
|
|
|
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)
|
|
{
|
|
const TDate& adata = mask.get_date(F_ADATA);
|
|
const int anno = adata.year();
|
|
|
|
TConfig config(CONFIG_DITTA, "ha");
|
|
TToken_string numerazioni;
|
|
numerazioni.add(config.get("NaAntNum"));
|
|
numerazioni.add(config.get("NaNoloNum"));
|
|
numerazioni.add(config.get("NaPostNum"));
|
|
numerazioni.add(config.get("NaRifaNum"));
|
|
|
|
int nac_killed = 0;
|
|
|
|
TRelation rel_doc(LF_DOC);
|
|
TRectype& rec = rel_doc.curr();
|
|
|
|
FOR_EACH_TOKEN(numerazioni, codnum) if (*codnum > ' ')
|
|
{
|
|
rec.zero();
|
|
rec.put(DOC_PROVV, 'P');
|
|
rec.put(DOC_ANNO, anno);
|
|
rec.put(DOC_CODNUM, codnum);
|
|
|
|
TCursor cur_doc (&rel_doc, "", 1, &rec, &rec);
|
|
const TRecnotype items = cur_doc.items();
|
|
cur_doc.freeze();
|
|
TProgind progind(items, TR("Eliminazione NAC provvisorie in corso..."));
|
|
for (cur_doc = 0; cur_doc.pos() < items; ++cur_doc)
|
|
{
|
|
if (!progind.addstatus(1))
|
|
break;
|
|
TDocumento doc(rec);
|
|
if (doc.remove() == 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)
|
|
{
|
|
const int tc = mask.get_int(F_TIPOCONTR);
|
|
|
|
//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)";
|
|
if (tc != 8) // Per i contratti NON di nolo ...
|
|
query << "&&(STATO<#STATOFIN)"; // ... scarta i documenti definitivi
|
|
|
|
//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 << "'))";
|
|
|
|
|
|
if (codcf <= 0)
|
|
query << "\nBY " << DOC_CODCF << ' ' << DOC_NDOC; //ordinamento codcf-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"
|
|
<< "\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"
|
|
<< "\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!)
|
|
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");
|
|
const TString& stato_fin = config.get("StatoFinFatt");
|
|
|
|
recset.set_var("#STATOINI", stato_ini);
|
|
recset.set_var("#STATOFIN", stato_fin);
|
|
|
|
//se c'è l'agente specificato...
|
|
const TString& agente = mask.get(F_CODAGE);
|
|
if (agente.full())
|
|
recset.set_var("#CODAG", agente);
|
|
if (codcf > 0)
|
|
recset.set_var("#CODCF", codcf);
|
|
recset.set_var("#ANNO", long(adata.year()));
|
|
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)
|
|
// flags: 0x7 = tutti tranne nolo; 0x8 = nolo
|
|
word THardy_elab_docs::find_contratti_cliente(const long codcfatt, const TMask& mask, int flags, TArray& contratti_cliente)
|
|
{
|
|
word freq = 0;
|
|
contratti_cliente.destroy();
|
|
|
|
const TDate data_fine_elab = mask.get_date(F_ADATA);
|
|
TDate data_ini_elab = mask.get_date(F_DADATA);
|
|
if (!data_ini_elab.ok())
|
|
check_date(data_fine_elab, data_ini_elab);
|
|
|
|
// settaggio delle variabili
|
|
// il codice numerazione lo trova nella configurazione Hardy,
|
|
// lo deve scegliere in base alla tipologia di contratti che sta esaminando!
|
|
for (int f = 0; f < 4; f++) if (flags & (1 << f))
|
|
{
|
|
TString4 codnum, tipodoc;
|
|
switch (f)
|
|
{
|
|
case 0:
|
|
codnum = ini_get_string(CONFIG_DITTA, "ha", "CoAntNum");
|
|
tipodoc = ini_get_string(CONFIG_DITTA, "ha", "CoAntTip");
|
|
break;
|
|
case 1:
|
|
codnum = ini_get_string(CONFIG_DITTA, "ha", "CoRifaNum");
|
|
tipodoc = ini_get_string(CONFIG_DITTA, "ha", "CoRifaTip");
|
|
break;
|
|
case 2:
|
|
codnum = ini_get_string(CONFIG_DITTA, "ha", "CoPostNum");
|
|
tipodoc = ini_get_string(CONFIG_DITTA, "ha", "CoPostTip");
|
|
break;
|
|
case 3:
|
|
codnum = ini_get_string(CONFIG_DITTA, "ha", "CoNoloNum");
|
|
tipodoc = ini_get_string(CONFIG_DITTA, "ha", "CoNoloTip");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
const TString& agente = mask.get(F_CODAGE);
|
|
|
|
//deve cercare tutti i contratti del cliente e metterli nell'array
|
|
TString query;
|
|
query << "USE DOC KEY 5";
|
|
query << "\nSELECT (TIPODOC=#TIPODOC)&&(STATO!=9)";
|
|
if (codcfatt > 0) query <<"&&(STR(DOC2=#CODCF))";
|
|
if (agente.full()) query << "&&(CODAG=#CODAG)";
|
|
query << "\nFROM PROVV=D CODNUM=" << codnum;
|
|
query << "\nTO PROVV=D CODNUM=" << codnum;
|
|
|
|
TISAM_recordset recset(query);
|
|
recset.set_var("#TIPODOC", tipodoc);
|
|
if (codcfatt > 0)
|
|
recset.set_var("#CODCF", codcfatt);
|
|
if (agente.full())
|
|
recset.set_var("#CODAG", agente);
|
|
|
|
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 nolo 'N': datainizio esiste sempre, datafine esiste sempre
|
|
//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();
|
|
|
|
//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 = recset.get(DOC_DATAFCOMP).as_date();
|
|
|
|
if (f == 3) // if (tipo_contratto == "N")
|
|
{
|
|
const TDate data_recesso = recset.get(DOC_DATASCIMP).as_date();
|
|
if (data_recesso.ok())
|
|
data_fine_contratto = data_recesso;
|
|
else
|
|
{
|
|
const int rate = recset.get(DOC_NCOLLI).as_int();
|
|
const int paga = recset.get(DOC_NUMANT).as_int();
|
|
if (paga >= rate) // Fine pagamento rate
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//se la data fine contratto non è valida (ma è presente!) non dobbiamo fare nulla, perchè il contratto non va elaborato
|
|
if (data_fine_contratto.ok() && 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();
|
|
|
|
FOR_EACH_PHYSICAL_RDOC(*curr_contratto, r, rdoc)
|
|
{
|
|
const TString& tr = rdoc->get(RDOC_TIPORIGA);
|
|
if (tr == HARDY_TIPORIGA_SOMMA && (tipo_contr == 'A' || tipo_contr == 'R'))
|
|
{
|
|
rdoc->zero(RCA_2_RESO_CORRENTE);
|
|
|
|
const real prezzo = rdoc->prezzo(false, false);
|
|
const real resost = rdoc->get(RCA_2_RESO_STORICO);
|
|
if (resost >= prezzo) // Contratto esaurito da ignorare
|
|
{
|
|
delete curr_contratto;
|
|
curr_contratto = NULL;
|
|
}
|
|
break;
|
|
} else
|
|
if (tr == HARDY_TIPORIGA_MERCE)
|
|
rdoc->zero(RDOC_QTA);
|
|
}
|
|
|
|
if (curr_contratto != NULL) // Ignora contratti chiusi
|
|
{
|
|
contratti_cliente.add(curr_contratto);
|
|
switch (curr_contratto->frequenza())
|
|
{
|
|
case 'A': freq |= 0x8; break;
|
|
case 'S': freq |= 0x4; break;
|
|
case 'T': freq |= 0x2; break;
|
|
default : freq |= 0x1; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return freq;
|
|
}
|
|
|
|
int THardy_elab_docs::month_diff(const TDate& inizio, const TDate& fine) const
|
|
{
|
|
const int i = inizio.year()*12 + inizio.month();
|
|
const int f = fine.year()*12 + fine.month();
|
|
return f-i;
|
|
}
|
|
|
|
|
|
bool THardy_elab_docs::aggiorna_contratto(const TRiga_documento& rdoc, TContratto_premi& contratto, TLog_report& log)
|
|
{
|
|
bool elaborato = false;
|
|
const bool definitivo = rdoc.get_char(RDOC_PROVV) == 'D';
|
|
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 (verig02) 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())
|
|
{
|
|
if (definitivo) // Non scrivo aaggiornamenti provvisori
|
|
{
|
|
//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
|
|
const real reso = normalized_rdoc_qta * rigamerce_premio;
|
|
rigacontratto->add(RCA_2_RESO_CORRENTE, reso);
|
|
}
|
|
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())
|
|
{
|
|
const real bonus = normalized_rdoc_qta * rigamerce_premio;
|
|
if (definitivo) // Non scrivo aaggiornamenti provvisori
|
|
{
|
|
rigamerce->add(RC_1_BONUS, bonus);
|
|
rigamerce->add(RDOC_QTA, normalized_rdoc_qta); //riscrive sul campo di appoggio del contratto
|
|
}
|
|
elaborato = true;
|
|
|
|
TString msg;
|
|
msg.format("Doc. %d/%s %ld - %s: %s %s -> Bonus %s Contr. %d/%s %ld",
|
|
rdoc.get_int(RDOC_ANNO), (const char*)rdoc.get(RDOC_CODNUM), rdoc.get_long(RDOC_NDOC),
|
|
(const char*)rdoc_codart, normalized_rdoc_qta.stringa(4, 0), (const char*)rdoc_umqta, bonus.stringa(7,2),
|
|
contratto.get_int(DOC_ANNO), (const char*)contratto.get(DOC_CODNUM), contratto.get_long(DOC_NDOC));
|
|
log.log(0, msg);
|
|
}
|
|
|
|
} //if(rigamerce_premio != ZERO...
|
|
} //if(rdoc_codart...
|
|
} //FOR_EACH_PHYSICAL..
|
|
return elaborato;
|
|
}
|
|
|
|
bool THardy_elab_docs::deve_generare_nac(const TContratto_premi& contratto, const TDate& data) const
|
|
{
|
|
const int mese = data.month();
|
|
bool yes = false;
|
|
switch (contratto.frequenza())
|
|
{
|
|
case 'A': yes = mese == 12; break; // Gli annuali valgono solo a dicembre
|
|
case 'M': yes = true; break; // I mensili (nolo) valgono sempre
|
|
case 'S': yes = mese == 6 || mese == 12; // I semestrali valgono solo a giugno e dicembre
|
|
case 'T': yes = data.month() % 3 == 0; break; // I trimestrali valgono solo a marzo, giugno, settembre e dicembre
|
|
default: break;
|
|
}
|
|
return yes;
|
|
}
|
|
|
|
//aggiorna, in base al documento in esame curr_doc, le somme restituite nelle righe di tipo verigh02 nei contratti validi
|
|
word THardy_elab_docs::elabora_contratti(TDocumento& curr_doc, TArray& contratti_cliente, const TDate& data_fine, TLog_report& log)
|
|
{
|
|
const TDate datadoc = curr_doc.get(DOC_DATADOC);
|
|
word elaborato = 0;
|
|
|
|
TString4 olddoc2 = curr_doc.get(DOC_DOC2); olddoc2.rpad(4); // Quattro spazi o X in corrispondenza dell'elaborazione
|
|
TString4 newdoc2 = olddoc2;
|
|
|
|
FOR_EACH_PHYSICAL_RDOC(curr_doc, r, rdoc) if (rdoc->is_merce()) //giro su tutte le righe merce delle fatture
|
|
{
|
|
//controlla se il codart della riga esiste in uno o più contratti validi
|
|
for (int i = 0; i < contratti_cliente.items(); i++)
|
|
{
|
|
TContratto_premi& contratto = (TContratto_premi&)contratti_cliente[i];
|
|
if (!contratto.data_valida(datadoc))
|
|
continue;
|
|
|
|
// Calcola l'inizio di validità dei documenti in base alla frequenza (14-01-2013)
|
|
TDate data_inizio(1, 1, data_fine.year());
|
|
const int mese = data_fine.month();
|
|
int pdef = 0;
|
|
switch (contratto.frequenza())
|
|
{
|
|
case 'M': pdef = 0; data_inizio.set_month(mese); break; // Solo contratti NOLO
|
|
case 'S': pdef = 2; data_inizio.set_month(mese > 6 ? 7 : 1); break;
|
|
case 'T': pdef = 1; data_inizio.set_month(max(1, mese-2)); break;
|
|
default : pdef = 3; break;
|
|
}
|
|
|
|
// Elabora solo i documenti che ricadano nell'intervallo valido
|
|
if (datadoc >= data_inizio && datadoc <= data_fine && olddoc2[pdef] <= ' ')
|
|
{
|
|
if (aggiorna_contratto(*rdoc, contratto, log))
|
|
{
|
|
switch (contratto.frequenza())
|
|
{
|
|
case 'A': elaborato |= 0x8; break;
|
|
case 'S': elaborato |= 0x4; break;
|
|
case 'T': elaborato |= 0x2; break;
|
|
default : elaborato |= 0x1; break; // Solo contratti NOLO
|
|
}
|
|
if (deve_generare_nac(contratto, data_fine))
|
|
newdoc2.overwrite("X", pdef, 1);
|
|
}
|
|
}
|
|
} //for(int i..
|
|
} //FOR_EACH...
|
|
|
|
if (newdoc2 != olddoc2)
|
|
curr_doc.put(DOC_DOC2, newdoc2);
|
|
|
|
return elaborato;
|
|
}
|
|
|
|
|
|
bool THardy_elab_docs::genera_nac(const TMask& mask, TArray& contratti_cliente,
|
|
TAssoc_array& fat_nolo, TArray& documenti_cliente, TLog_report& log)
|
|
{
|
|
bool una_nac_definitiva = false;
|
|
|
|
if (contratti_cliente.empty())
|
|
return una_nac_definitiva;
|
|
|
|
//si informa se l'elaborazione è definitiva o meno
|
|
const bool definitivo = mask.get_bool(F_DEFINITIVO);
|
|
const TDate data_fine = mask.get(F_ADATA);
|
|
|
|
//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!
|
|
|
|
TString80 tip = "";
|
|
switch (tipo_contratto)
|
|
{
|
|
case 'A': tip = TR("Anticipo"); break;
|
|
case 'N': tip = TR("Nolo"); break;
|
|
case 'P': tip = TR("Posticipo"); break;
|
|
case 'R': tip = TR("Rifatturzaione"); break;
|
|
default : break;
|
|
}
|
|
|
|
const bool nac_ok = deve_generare_nac(contratto, data_fine);
|
|
|
|
TString80 freq = "";
|
|
switch (contratto.frequenza())
|
|
{
|
|
case 'A': freq = TR("annuale"); break;
|
|
case 'M': freq << TR("rata ") << (contratto.get_int(DOC_NUMANT)+1); break;
|
|
case 'S': freq << (data_fine.month() < 7 ? TR("I sem.") : TR("II sem.")); break;
|
|
case 'T': freq << itor((data_fine.month()/3)) << TR(" trim."); break;
|
|
default : break;
|
|
}
|
|
|
|
//segnaliamo l'elaborazione del contratto sul log
|
|
TString log_msg;
|
|
log_msg.format(FR("Cliente:%ld Contratto:%ld %s %s"), codcf, ndoc, (const char*)tip, (const char*)freq);
|
|
log_msg << "(NAC ";
|
|
if (nac_ok)
|
|
log_msg << "def.";
|
|
else
|
|
log_msg << "provv.";
|
|
log_msg << ')';
|
|
|
|
// generazione del documento NAC dal contratto
|
|
// -------------------------------------------
|
|
// TESTATA
|
|
|
|
//alcuni parametri delle righe vanno presi dalla configurazione
|
|
TString4 nac_codnum, nac_tipo;
|
|
TString8 cod_riga;
|
|
switch (tipo_contratto)
|
|
{
|
|
case 'A':
|
|
nac_codnum = ini_get_string(CONFIG_DITTA, "ha", "NaAntNum");
|
|
nac_tipo = ini_get_string(CONFIG_DITTA, "ha", "NaAntTip");
|
|
cod_riga = ini_get_string(CONFIG_DITTA, "ha", "NaAntSpe");
|
|
break;
|
|
case 'N':
|
|
nac_codnum = ini_get_string(CONFIG_DITTA, "ha", "NaNoloNum");
|
|
nac_tipo = ini_get_string(CONFIG_DITTA, "ha", "NaNoloTip");
|
|
cod_riga = ini_get_string(CONFIG_DITTA, "ha", "NaNoloSpe");
|
|
break;
|
|
case 'R':
|
|
nac_codnum = ini_get_string(CONFIG_DITTA, "ha", "NaRifaNum");
|
|
nac_tipo = ini_get_string(CONFIG_DITTA, "ha", "NaRifaTip");
|
|
cod_riga = ini_get_string(CONFIG_DITTA, "ha", "NaRifaSpe");
|
|
break;
|
|
default:
|
|
nac_codnum = ini_get_string(CONFIG_DITTA, "ha", "NaPostNum");
|
|
nac_tipo = ini_get_string(CONFIG_DITTA, "ha", "NaPostTip");
|
|
cod_riga = ini_get_string(CONFIG_DITTA, "ha", "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 TDate datadoc = mask.get(tipo_contratto == 'N' ? F_DATANOLO : F_DATAELAB);
|
|
const int anno = datadoc.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
|
|
const char provv = definitivo && nac_ok ? 'D' : 'P';
|
|
|
|
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, datadoc);
|
|
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));
|
|
|
|
TToken_string cnkey; // Chiave contratto
|
|
cnkey.add(contratto.get(DOC_PROVV));
|
|
cnkey.add(contratto.get(DOC_ANNO));
|
|
cnkey.add(contratto.get(DOC_CODNUM));
|
|
cnkey.add(contratto.get(DOC_NDOC));
|
|
TToken_string* fatkey = (TToken_string*)fat_nolo.objptr(cnkey);
|
|
if (fatkey != NULL)
|
|
{
|
|
// Skip fatkey->get(0) = PROVV
|
|
nac.put(DOC_ANNORIF, fatkey->get(1));
|
|
nac.put(DOC_CODNUMRIF, fatkey->get());
|
|
nac.put(DOC_NUMDOCRIF, fatkey->get());
|
|
nac.put(DOC_DATADOCRIF, fatkey->get());
|
|
}
|
|
else
|
|
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_spp = rec_spp.get("S8");
|
|
const TString80 descr_riga_spp = rec_spp.get("S0");
|
|
const TString4 codiva = rec_spp.get("S3");
|
|
|
|
TDate adata = mask.get_date(F_ADATA);
|
|
TDate dadata = mask.get_date(F_DADATA);
|
|
if (!dadata.ok())
|
|
check_date(adata, dadata);
|
|
|
|
TDate dmin(1, 1, adata.year());
|
|
switch (contratto.frequenza())
|
|
{
|
|
case 'M': dmin.set_month(adata.month()); break; // Solo nolo
|
|
case 'S': dmin.set_month(adata.month() > 6 ? 7 : 1); break;
|
|
case 'T': dmin.set_month(max(1, adata.month()-2)); break;
|
|
default: break;
|
|
}
|
|
if (dmin > dadata)
|
|
dadata = dmin;
|
|
|
|
if (!contratto.data_valida(dadata))
|
|
dadata = contratto.data_inizio();
|
|
|
|
if (!contratto.data_valida(adata))
|
|
adata = contratto.data_fine();
|
|
|
|
TString msg_date; msg_date << " " << dadata << " -- " << adata;
|
|
|
|
//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_spp);
|
|
nac_row.put(RDOC_CODART, cod_riga);
|
|
|
|
//panegirico della descrizione
|
|
nac_row.put(RDOC_DESCR, descr_riga_spp);
|
|
nac_row.put(RDOC_DESCEST, msg_date);
|
|
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);
|
|
|
|
//Imposta riga contratto di provenienza
|
|
nac_row.set_original_rdoc_key(riga_contratto);
|
|
} else
|
|
|
|
//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_spp);
|
|
nac_row.put(RDOC_CODART, cod_riga);
|
|
|
|
//panegirico della descrizione
|
|
nac_row.put(RDOC_DESCR, descr_riga_spp);
|
|
nac_row.put(RDOC_DESCEST, msg_date);
|
|
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);
|
|
|
|
//Imposta riga contratto di provenienza
|
|
nac_row.set_original_rdoc_key(riga_contratto);
|
|
}
|
|
}
|
|
}
|
|
|
|
// salvataggi vari
|
|
// ---------------
|
|
// NAC
|
|
// viene scritta comunque, con provv='D' se elaborazione definitiva
|
|
int err = nac.write();
|
|
|
|
if (err == NOERR)
|
|
{
|
|
TString wrk_msg;
|
|
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 (verig02)
|
|
if (err == NOERR) switch (tipo_contratto)
|
|
{
|
|
case 'A':
|
|
case 'R':
|
|
{
|
|
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...
|
|
}
|
|
break;
|
|
case 'N':
|
|
if (fatkey != NULL)
|
|
{
|
|
const char provv = fatkey->get_char(0);
|
|
const int anno = fatkey->get_int();
|
|
const char* codnum = fatkey->get();
|
|
const long ndoc = fatkey->get_long();
|
|
const TDocumento fat(provv, anno, codnum, ndoc);
|
|
genera_eff(fat, nac.totale_doc(), log);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// 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 (err == NOERR && definitivo && nac_ok)
|
|
{
|
|
//alla fine della fiera aggiorna il contratto
|
|
err = contratto.rewrite();
|
|
|
|
if (err == NOERR)
|
|
{
|
|
log_msg << " -- Contratto aggiornato";
|
|
una_nac_definitiva = true;
|
|
}
|
|
else
|
|
log_msg << " -- Impossibile aggiornare contratto: errore " << err;
|
|
}
|
|
|
|
if (err == NOERR)
|
|
log.log(nac_ok ? 1 : 0, log_msg);
|
|
else
|
|
log.log(2, log_msg);
|
|
|
|
log.log(0, "");
|
|
|
|
|
|
} //FOR_EACH_ARRAY_ITEM(... giro sui contratti cliente
|
|
|
|
if (una_nac_definitiva)
|
|
{
|
|
const int tc = mask.get_int(F_TIPOCONTR); // 0x7 (tutti tranne nolo) o 0x8 (solo nolo)
|
|
if (tc != 0x8)
|
|
{
|
|
const TString4 stato_finale = ini_get_string(CONFIG_DITTA, "ha", "StatoFinFatt");
|
|
FOR_EACH_ARRAY_ITEM(documenti_cliente, r, riga)
|
|
{
|
|
TDocumento& fattura = *(TDocumento*)riga;
|
|
// fattura.put(DOC_STATO, stato_finale);
|
|
fattura.rewrite();
|
|
}
|
|
|
|
TString msg;
|
|
msg.format(FR("Aggiornato stato elaborazione di %d fatture"), documenti_cliente.items());
|
|
log.log(0, msg);
|
|
}
|
|
}
|
|
|
|
|
|
//il metodo ritornerà il successo o meno della registrazione
|
|
return una_nac_definitiva;
|
|
}
|
|
|
|
bool THardy_elab_docs::genera_fat(const TMask& mask, TContratto_premi& contratto, TToken_string& fat_nolo, TLog_report& log)
|
|
{
|
|
//si informa se l'elaborazione è definitiva o meno
|
|
const char provv = mask.get_bool(F_DEFINITIVO) ? 'D' : 'P';
|
|
const TDate datadoc = mask.get(F_DATAELAB);
|
|
|
|
const TString4 fat_codnum = ini_get_string(CONFIG_DITTA, "ha", "NaNoloNum");
|
|
const TString4 fat_tipodoc = ini_get_string(CONFIG_DITTA, "ha", "FtNoloTip");
|
|
const TString4 fat_codpag = ini_get_string(CONFIG_DITTA, "ha", "CodPagFat");
|
|
const TString8 cod_spesa = ini_get_string(CONFIG_DITTA, "ha", "FtNoloSpe");
|
|
|
|
TDocumento fat(provv, datadoc.year(), fat_codnum, 0); //num_doc = 0 perchè viene aggiornato in fase di registrazione
|
|
fat.set_tipo(fat_tipodoc);
|
|
fat.put(DOC_STATO, 1);
|
|
fat.put(DOC_DATADOC, datadoc);
|
|
fat.put(DOC_TIPOCF, 'C');
|
|
fat.put(DOC_CODCF, contratto.get(DOC_CODCF));
|
|
fat.cli2doc();
|
|
fat.put(DOC_CODAG, contratto.get(DOC_CODAG));
|
|
fat.put(DOC_DOC1, contratto.get(DOC_NDOC));
|
|
fat.put(DOC_DATADOCRIF, contratto.get(DOC_DATADOC));
|
|
fat.put(DOC_CODPAG, fat_codpag);
|
|
|
|
const TRectype& rec_spp = cache().get("SPP", cod_spesa);
|
|
const TString80 descr_riga_spp = rec_spp.get("S0");
|
|
const TString4 codiva = rec_spp.get("S3");
|
|
const TString4 tipo_riga_spp = rec_spp.get("S8");
|
|
|
|
TString msg_rata;
|
|
|
|
real importo = contratto.get_real(DOC_IMPPAGATO);
|
|
const TDate recesso = contratto.data_recesso();
|
|
if (recesso.ok() && recesso <= mask.get_date(F_ADATA))
|
|
{
|
|
const real rate_da_pagare = contratto.get_int(DOC_NCOLLI) - contratto.get_int(DOC_NUMANT);
|
|
importo *= rate_da_pagare;
|
|
contratto.put(DOC_NUMANT, contratto.get(DOC_NCOLLI)); // Chiude contratto forzosamente
|
|
msg_rata = TR("\nRata di cessazione contratto");
|
|
}
|
|
else
|
|
{
|
|
const TDate d = mask.get(F_ADATA);
|
|
contratto.add(DOC_NUMANT, UNO); // Incrementa numero di rate pagate
|
|
|
|
msg_rata << TR("\nRata ") << contratto.get(DOC_NUMANT) << '/' << contratto.get_int(DOC_NCOLLI)
|
|
<< ' ' << itom(d.month()) << ' ' << d.year();
|
|
}
|
|
|
|
if (provv == 'D')
|
|
{
|
|
const int err = contratto.rewrite();
|
|
if (err != NOERR)
|
|
log.log(2, TR("Impossibile aggiornare il numero di rate pagate sul contratto"));
|
|
}
|
|
|
|
TRiga_documento& rdoc = fat.new_row(tipo_riga_spp);
|
|
rdoc.put(RDOC_CODART, cod_spesa);
|
|
rdoc.put(RDOC_DESCR, descr_riga_spp);
|
|
rdoc.put(RDOC_DESCEST, msg_rata);
|
|
rdoc.put(RDOC_DESCLUNGA, "X");
|
|
|
|
rdoc.put(RDOC_QTA, UNO);
|
|
rdoc.put(RDOC_PREZZO, importo);
|
|
rdoc.put(RDOC_CODIVA, codiva);
|
|
|
|
const int err = fat.write();
|
|
|
|
if (err == NOERR)
|
|
{
|
|
TString log_msg;
|
|
log_msg.format("Generata FATTURA: %-4s%-4s%c %7ld",
|
|
(const char*)fat_codnum, (const char*)fat_tipodoc, fat.get_char(DOC_PROVV), fat.get_long(DOC_NDOC));
|
|
log.log(0, log_msg);
|
|
|
|
fat_nolo = fat.get(DOC_PROVV);
|
|
fat_nolo.add(fat.get(DOC_ANNO));
|
|
fat_nolo.add(fat.get(DOC_CODNUM));
|
|
fat_nolo.add(fat.get(DOC_NDOC));
|
|
fat_nolo.add(fat.get(DOC_DATADOC));
|
|
}
|
|
else
|
|
{
|
|
log.log(2, TR("Impossibile generare la FATTURA"));
|
|
}
|
|
|
|
return err == NOERR;
|
|
}
|
|
|
|
bool THardy_elab_docs::genera_eff(const TDocumento& fat, const real& tot_nac, TLog_report& log)
|
|
{
|
|
#ifdef NDEBUG
|
|
if (fat.get_char(DOC_PROVV) != 'D')
|
|
return false;
|
|
#endif
|
|
|
|
const real tot_fat = fat.totale_doc();
|
|
if (tot_fat == tot_nac)
|
|
return false;
|
|
|
|
const bool credito = tot_fat > tot_nac;
|
|
const real importo = credito ? (tot_fat - tot_nac) : (tot_nac - tot_fat);
|
|
|
|
TDate datascad = fat.get(DOC_DATADOC); datascad.set_end_month();
|
|
|
|
TEffetto eff;
|
|
eff.put(EFF_DATASCAD, datascad);
|
|
eff.put(EFF_TIPOPAG, credito ? tp_rid : tp_bonifico);
|
|
eff.put(EFF_TIPOCF, fat.get(DOC_TIPOCF));
|
|
eff.put(EFF_CODCF, fat.get(DOC_CODCF));
|
|
eff.put(EFF_CODABI, fat.get(DOC_CODABIA));
|
|
eff.put(EFF_CODCAB, fat.get(DOC_CODCABA));
|
|
|
|
TRectype& reff = eff.row_r(1, true);
|
|
reff.put(REFF_ANNO, fat.get(DOC_ANNO));
|
|
reff.put(REFF_NUMPART, fat.get(DOC_NDOC));
|
|
reff.put(REFF_NRIGA, 1);
|
|
reff.put(REFF_NRATA, 1);
|
|
reff.put(REFF_PROVV, fat.get(DOC_PROVV));
|
|
reff.put(REFF_ANNODOC, fat.get(DOC_ANNO));
|
|
reff.put(REFF_CODNUM, fat.get(DOC_CODNUM));
|
|
reff.put(REFF_NFATT, fat.get(DOC_NDOC));
|
|
reff.put(REFF_DATAFATT,fat.get(DOC_DATADOC));
|
|
reff.put(REFF_IMPFATT, tot_fat);
|
|
reff.put(REFF_IMPORTO, importo);
|
|
reff.put(REFF_ACCSAL, 'A');
|
|
|
|
TLocalisamfile file(LF_EFFETTI);
|
|
int err = eff.write(file);
|
|
if (err == NOERR)
|
|
{
|
|
TString msg;
|
|
msg << "Registrato effetto " << eff.numero();
|
|
log.log(0, msg);
|
|
}
|
|
else
|
|
log.log(2, "Impossibile registrare l'effetto");
|
|
|
|
return err == NOERR;
|
|
}
|
|
|
|
void THardy_elab_docs::elabora_documenti(const TMask& mask, TISAM_recordset& fatture, TLog_report& log)
|
|
{
|
|
TProgind pi(fatture.items(), TR("Elaborazione documenti in corso..."));
|
|
|
|
//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;
|
|
TAssoc_array fat_nolo;
|
|
|
|
const int tc = mask.get_int(F_TIPOCONTR); // 0x7 (tutti tranne nolo) o 0x8 (solo nolo)
|
|
|
|
if (tc & 0x8) // Elaborazione nolo?
|
|
{
|
|
// Elabora tutti i contratti di nolo per generare fatture ed effetti
|
|
const word freq = find_contratti_cliente(mask.get_long(F_CODCF), mask, 0x8, contratti_cliente);
|
|
if (freq) // Nolo sarebbe solo mensile -> if (freq == 0x01)
|
|
{
|
|
FOR_EACH_ARRAY_ROW(contratti_cliente, n_nolo, r_nolo)
|
|
{
|
|
TContratto_premi& contratto = *(TContratto_premi*)r_nolo;
|
|
|
|
TToken_string fatkey;
|
|
if (genera_fat(mask, contratto, fatkey, log))
|
|
{
|
|
TToken_string cnkey; // Chiave contratto
|
|
cnkey.add(contratto.get(DOC_PROVV));
|
|
cnkey.add(contratto.get(DOC_ANNO));
|
|
cnkey.add(contratto.get(DOC_CODNUM));
|
|
cnkey.add(contratto.get(DOC_NDOC));
|
|
fat_nolo.add(cnkey, fatkey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// giro sulle fatture (è il giro di più alto livello che viene esteso all'interno delle elabora_contratti)
|
|
const TDate data_fine = mask.get(F_ADATA);
|
|
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 && !documenti_cliente.empty())
|
|
genera_nac(mask, contratti_cliente, fat_nolo, documenti_cliente, log);
|
|
|
|
//aggiorna old_codcf in modo da poter controllare i contratti solo al cambio codcf
|
|
old_codcf = codcf;
|
|
documenti_cliente.destroy();
|
|
const word freq = find_contratti_cliente(codcf, mask, tc, contratti_cliente);
|
|
if (freq != 0)
|
|
{
|
|
TString8 key; key.format("C|%ld", codcf);
|
|
TString msg; msg << TR("Cliente") << ' ' << codcf << ' ' << cache().get(LF_CLIFO, key, CLI_RAGSOC);
|
|
log.log(0, msg);
|
|
}
|
|
}
|
|
|
|
if (!contratti_cliente.empty()) // Test sulla presenza di contratti
|
|
{
|
|
const TRectype& head = fatture.cursor()->curr();
|
|
|
|
//se ha trovato uno o più contratti validi nel periodo passa alla elaborazione dei documenti del cliente
|
|
TDocumento* curr_doc = new TDocumento(head);
|
|
|
|
// elabora il documento corrente aggiornando le somme restituite sui contratti validi
|
|
const word freq = elabora_contratti(*curr_doc, contratti_cliente, data_fine, log);
|
|
if (freq != 0)
|
|
documenti_cliente.add(curr_doc);
|
|
else
|
|
delete(curr_doc);
|
|
}
|
|
} //for (bool ok = recset.move_first()...
|
|
|
|
//generazione NAC dell'ultimo cliente (una per contratto cliente)
|
|
if (!contratti_cliente.empty() && !documenti_cliente.empty())
|
|
{
|
|
genera_nac(mask, contratti_cliente, fat_nolo, documenti_cliente, log);
|
|
documenti_cliente.destroy();
|
|
}
|
|
}
|
|
|
|
//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.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, TR("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_TABCOM, LF_TAB, LF_CLIFO, LF_DOC, LF_RIGHEDOC, LF_ANAMAG, 0);
|
|
return TSkeleton_application::create();
|
|
}
|
|
|
|
int ha0500 (int argc, char* argv[])
|
|
{
|
|
THardy_elab_docs elabapp;
|
|
elabapp.run(argc, argv, TR("Generazione NAC"));
|
|
return 0;
|
|
}
|
|
|