campo-sirio/ca/ca3700.cpp
luca bee78e6470 Patch level :2.2 224
Files correlati     :
Ricompilazione Demo : [ ]
Commento            :risolto problema dei prefissi mancanti sui conti analitici nella stampa del rendiconto (errore segnalato da roberto nei dati ruffo). Aggiunta primissima stesura della stampa pagato (assolutamente non funzionante! Appare solo la maschera)


git-svn-id: svn://10.65.10.50/trunk@13501 c028cbd2-c16b-5b4b-a496-9718f37d4682
2005-11-17 16:40:54 +00:00

1145 lines
35 KiB
C++
Executable File
Raw Blame History

#include <applicat.h>
#include <execp.h>
#include <progind.h>
#include <reprint.h>
#include <doc.h>
#include <rdoc.h>
#include "../cg/cg2103.h"
#include "../cg/cglib01.h"
#include "../ve/velib04.h"
#include "panapdc.h"
#include "pconana.h"
#include "movana.h"
#include "rmovana.h"
#include "ca3.h"
#include "ca3700.h"
#include "calib01.h"
#include "calib02.h"
////////////////////////////////////////////////////////
// MASCHERA
////////////////////////////////////////////////////////
class TPrint_rendiconto_ca_mask : public TAnal_report_mask
{
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
const TString& get_report_class() const;
bool test_compatible_report();
bool esistono_riclassificazioni() const;
public:
TPrint_rendiconto_ca_mask();
virtual ~TPrint_rendiconto_ca_mask() {}
};
const TString& TPrint_rendiconto_ca_mask::get_report_class() const
{
TString& classe = get_tmp_string();
classe = "ca3700a";
return classe;
}
bool TPrint_rendiconto_ca_mask::test_compatible_report()
{
const TString& cls = get_report_class();
const TString& name = get(F_REPORT);
bool ok = name.not_empty();
if (ok)
{
TReport rep;
ok = rep.load(name);
if (ok)
{
const TString& classe = rep.get_class();
ok = classe == cls;
}
}
if (!ok)
{
set(F_REPORT, cls);
TFilename path = cls;
path.ext("rep");
ok = path.custom_path();
}
return ok;
}
bool TPrint_rendiconto_ca_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case F_RIGHE:
if (e == fe_init) //azzera le righe dello sheet con le commesse ad inizio programma
{ //esplicita e bizzarra richiesta del CRPA
TSheet_field& s = (TSheet_field&)o;
s.destroy();
s.force_update();
}
break;
case F_DATAINI:
case F_DATAFIN:
if (e == fe_close)
{
const int anno = get_int(F_ANNO);
if (anno > 0) //se viene selezionato un esercizio..
{
TEsercizi_contabili esc; //..le date devono essere incluse nell'esercizio selezionato!
const TDate data = o.get();
if (!data.empty() && esc.date2esc(data) != anno)
return error_box(TR("La data deve appartenere all'anno selezionato"));
}
/* else //se l'esercizio <20> vuoto le date diventano obbligatorie!!
{
if (o.empty())
return error_box(TR("La data <20> obbligatoria in quanto manca l'esercizio"));
}*/
}
break;
case F_REPORT:
if (e == fe_button)
{
const TString8 lib = get_report_class();
TFilename path = o.get();
if (select_custom_file(path, "rep", lib))
{
path = path.name();
path.ext("");
o.set(path);
}
} else
if (e == fe_close)
{
if (!test_compatible_report())
return error_box(TR("Impossibile trovare un report compatibile"));
}
break;
case F_PRE1:
case F_PRE2:
case F_PRE3:
if ((e == fe_init || e == fe_modify) && o.active())
{
const int k = o.dlg()-F_PRE1;
set(F_PAN1_INI + k, o.get(), 0x2);
disable(F_PAN1_INI + k);
disable(F_PANDES1_INI + k);
set(F_PAN1_FIN + k, o.get(), 0x2);
disable(F_PAN1_FIN + k);
disable(F_PANDES1_FIN + k);
}
break;
default:
break;
}
return TAnal_report_mask::on_field_event(o, e, jolly);
}
bool TPrint_rendiconto_ca_mask::esistono_riclassificazioni() const
{
TLocalisamfile ric(LF_PANAPDC);
return ric.first() == NOERR;
}
TPrint_rendiconto_ca_mask::TPrint_rendiconto_ca_mask()
:TAnal_report_mask("ca3700")
{
TConfig& cfg = ca_config();
const bool use_pdcc = cfg.get_bool("UsePdcc");
const TMultilevel_code_info& pconana_info = ca_multilevel_code_info(LF_PCONANA);
const int pconana_levels = pconana_info.levels();
int pconana_prefix = cfg.get_int("PdcPrefix");
if (pconana_prefix >= pconana_levels)
pconana_prefix = pconana_levels-1;
disable(F_PIANO);
set(F_PIANO, use_pdcc ? "C" : "A");
// Controllo se voglio (e posso) usare il conto analitico come prefisso di quello contabile
const int pref = cfg.get_int("PdcPrefix");
if (use_pdcc && pref > 0)
{
const TMultilevel_code_info& info = ca_multilevel_code_info(LF_PCONANA);
const int levels = info.levels();
if (levels >= 2 && pref < levels && esistono_riclassificazioni())
{
enable(F_PIANO);
ca_create_fields(*this, 1, LF_PCONANA, 2, 4, F_PRE1, F_PREDES1, 0x0, PCONANA_CODCONTO);
// Nascondi i campi che non fanno parte del prefisso
for (int i = 0; i < levels; i++)
{
if (i < pref)
{
field(F_PRE1 + i).check_type(CHECK_REQUIRED);
field(F_PRE1 + i).set_group(6);
field(F_PREDES1 + i).set_group(6);
}
else
{
field(F_PRE1 + i).hide();
field(F_PREDES1 + i).hide();
}
}
}
}
for (int g = 5; g <= 6; g++)
{
const int logicnum = g == 5 ? LF_PCON : LF_PCONANA;
const short da_dlg = g == 5 ? F_PDC1_INI : F_PAN1_INI;
const short da_des = g == 5 ? F_PDCDES1_INI : F_PANDES1_INI;
const short a_dlg = g == 5 ? F_PDC1_FIN : F_PAN1_FIN;
const short a_des = g == 5 ? F_PDCDES1_FIN : F_PANDES1_FIN;
const int nfields = ca_create_fields(*this, 1, logicnum, 2, 10, da_dlg, da_des, 0x0, PCONANA_CODCONTO);
ca_create_fields(*this, 1, logicnum, 2, 16, a_dlg, a_des, 0x0, PCONANA_CODCONTO);
for (int i = 0; i < nfields; i++)
{
TMask_field& daconto = field(da_dlg + i);
daconto.set_group(1);
daconto.set_group(4);
daconto.set_group(g);
daconto.check_type(CHECK_SEARCH);
field(da_des+i).set_group(4);
field(da_des+i).set_group(g);
TMask_field& aconto = field(a_dlg + i);
aconto.set_group(2);
aconto.set_group(4);
aconto.set_group(g);
aconto.check_type(CHECK_SEARCH);
field(a_des+i).set_group(4);
field(a_des+i).set_group(g);
}
}
// creazione dei campi della pagina della maschera con lo sheet di cdc/cms/fasi
create_sheet(F_RIGHE);
// setta gli handlers a tutti i campi generati della maschera;senza questa chiamata la on_field_event
// non puo' funzionare sui campi generati!!!
set_handlers();
}
///////////////////////////////////////////////////////////////
// RECORDSET
///////////////////////////////////////////////////////////////
#define IMPEGNATO 1
#define MATURATO 2
#define FATTURATO 4
class TPrint_rendiconto_ca_recordset : public TISAM_recordset
{
TExternisamfile* _tmp;
bool _riclassificato;
TString _prefix, _da_conto_riclas, _a_conto_riclas;
protected:
int _anno;
int _tipoconti;
TDate _dadata, _adata;
long _danumreg, _anumreg;
TString _daconto, _aconto, _codcosto, _codcms, _codfas;
protected: //da libreria
virtual const TVariant& get(const char* column_name) const;
protected:
static bool mov_filter(const TRelation* rel);
bool valid_record(const TRelation& rel) const;
virtual void set_custom_filter(TCursor& cur) const;
void crea_righe_da_rmovana();
void crea_righe_da_rdoc(const TPrint_rendiconto_ca_mask& msk);
void crea_trr(const TFilename& trr) const;
void scrive_riga(const TRectype& rmovana, const TRectype& movana, const TDocumento* doc);
real get_budget(const TString& conto, char tipo) const;
public:
virtual void set_filter(const TPrint_rendiconto_ca_mask& msk, int cms_row);
TPrint_rendiconto_ca_recordset(const TString& sql) : TISAM_recordset(sql), _riclassificato(false) { _tmp = NULL;}
~TPrint_rendiconto_ca_recordset();
};
static TPrint_rendiconto_ca_recordset* myself = NULL;
TPrint_rendiconto_ca_recordset::~TPrint_rendiconto_ca_recordset()
{ }
void TPrint_rendiconto_ca_recordset::set_custom_filter(TCursor& cur) const
{
relation()->replace(_tmp); //sostituisce il vero file rmovana con quello temporaneo
//filtro sul file esterno (_tmp, cio<69> 1000) sui conti selezionati sulla maschera
TRectype darec(cur.curr()), arec(cur.curr()); //curr perch<63> <20> il file externisamfile
darec.zero();
arec.zero();
if (!_riclassificato)
{
if (_daconto.not_empty())
darec.put("CONTO", _daconto);
if (_aconto.not_empty())
arec.put("CONTO", _aconto);
}
else
{
darec.put("CONTO", _da_conto_riclas);
arec.put("CONTO", _a_conto_riclas);
}
//filtro sulla data(non avendo anche codnum non ho la chiave completa per mettere la data nella setregion)
TString filtro;
if (_dadata.ok())
filtro << "(ANSI(DATA)>=" << _dadata << ")";
if (_adata.ok())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(ANSI(DATA)<=" << _adata << ")";
}
cur.setregion(darec, arec);
cur.setfilter(filtro);
myself = (TPrint_rendiconto_ca_recordset*)this;
}
//sconvolgente metodo per la normalizzazione dei conti
real TPrint_rendiconto_ca_recordset::get_budget(const TString& conto, char tipo) const
{
//data del cazzo che per<65> serve per costruire il conto analitico
const TDate null_date;
//ecco il conto analitico...
TAnal_bill zio(conto, _codcosto, _codcms, _codfas);
//..adesso si necessita del saldo del conto analitico appena creato..
word tipo_movimento = 0;
switch (tipo)
{
case 'P': tipo_movimento |= _saldanal_preventivo; break;
case 'V': tipo_movimento |= _saldanal_variazione; break;
default: tipo_movimento |= _saldanal_consuntivo; break;
}
if (_riclassificato)
tipo_movimento |= _saldanal_riclassify;
//..ecco quindi il saldo..
const TSaldanal& saldo = ca_saldo(zio, null_date, null_date, tipo_movimento);
//..che deve essere normalizzato in base alla sua sezione ed all'indicatore di bilancio del conto
TImporto imp = saldo._fin;
switch (zio.indicatore_bilancio())
{
case 1:
case 3:
imp.normalize('D');
break;
case 2:
case 4:
imp.normalize('A');
break;
default:
break;
}
return imp.valore();
}
const TVariant& TPrint_rendiconto_ca_recordset::get(const char* column_name) const
{
if (*column_name == '#')
{
if (strcmp(column_name, "#COSTO") == 0)
{
TVariant& var = get_tmp_var();
var = _codcosto;
return var;
}
if (strcmp(column_name, "#COMMESSA") == 0)
{
TVariant& var = get_tmp_var();
var = _codcms;
return var;
}
if (strcmp(column_name, "#FASE") == 0)
{
TVariant& var = get_tmp_var();
var = _codfas;
return var;
}
if (strcmp(column_name, "#DACONTO") == 0)
{
TVariant& var = get_tmp_var();
if (!_riclassificato)
var = _daconto;
else
var = _da_conto_riclas;
return var;
}
if (strcmp(column_name, "#ACONTO") == 0)
{
TVariant& var = get_tmp_var();
if (!_riclassificato)
var = _aconto;
else
var = _a_conto_riclas;
return var;
}
//cerca l'indicatore di bilancio del conto;utilizzato per stabilire il campo ove sommare..
//..i budget nella coda report
if (strcmp(column_name, "#INDBIL") == 0)
{
const TString& conto = TISAM_recordset::get("CONTO").as_string();
TAnal_bill zio(conto);
return get_tmp_var() = (long)zio.indicatore_bilancio();
}
//calcola il valore e la sezione del campo budget di un conto basandosi sull'indicatore di..
//..bilancio ed il saldo del conto (movimenti analitici di tipo preventivo)
if (strcmp(column_name, "#PREVENTIVO") == 0)
{
//stessa cosa del precedente ma per movimenti di tipo variazione preventivo
const TString& conto = TISAM_recordset::get("CONTO").as_string();
return get_tmp_var() = get_budget(conto, 'P');
}
if (strcmp(column_name, "#VARIAZIONE") == 0)
{
//prende il conto
const TString& conto = TISAM_recordset::get("CONTO").as_string();
return get_tmp_var() = get_budget(conto, 'V');
}
}
return TISAM_recordset::get(column_name);
}
//compila i campi del file temporaneo che sra' poi stampato
void TPrint_rendiconto_ca_recordset::scrive_riga(const TRectype& rmovana, const TRectype& movana, const TDocumento* doc)
{
TRectype& tmpcurr = _tmp->curr();
tmpcurr.zero();
TString8 codnum_desc; //codnum da usare sia per compilare il campo "CODNUM"
codnum_desc.cut(0);
// il conto puo' essere analitico o contabile...
//se <20> compilato l'archivio di collegamento PANAPDC
//si deve usare come conto il campo codconto del panapdc!!!...
if (_riclassificato)
{
TString conto_riclassificato; //stringa che conterr<72> il conto riclassificato (se sara' trovato)
//prende il gruppo dalla riga rmovana in esame
const int gruppo = atoi(rmovana.get(RMOVANA_CODCONTO).left(3));
const int conto = atoi(rmovana.get(RMOVANA_CODCONTO).mid(3,3));
const long sottoconto = atol(rmovana.get(RMOVANA_CODCONTO).mid(6,6));
//relazione e cursore su panapdc alla ricerca del conto riclassificato corrispondente
//alla triade gr/co/sottoc di rmovana
TRelation rel_panapdc(LF_PANAPDC);
//servono solamente i record con il gruppo = al gruppo di rmovana
TRectype da_panapdc(LF_PANAPDC);
da_panapdc.put(PANAPDC_GRUPPO, gruppo);
TString filtro;
if (_prefix.not_empty())
filtro << "(CODCONTO[1," << _prefix.len() << "]=='" << _prefix << "')";
TCursor cur_panapdc(&rel_panapdc, filtro, 2, &da_panapdc, &da_panapdc);
const long panapdc_items = cur_panapdc.items();
cur_panapdc.freeze();
if (panapdc_items > 0) //se non ci sono record con il gruppo=rmovana.gruppo ed il prefisso voluto->salta l'rmovana
{
TRectype& rec_panapdc = cur_panapdc.curr();
for (cur_panapdc = 0; cur_panapdc.pos() < panapdc_items; ++cur_panapdc)
{
int current_conto = rec_panapdc.get_int(PANAPDC_CONTO);
long current_sottoconto = rec_panapdc.get_long(PANAPDC_SOTTOCONTO);
if (current_conto == 0 && current_sottoconto == 0)
{
conto_riclassificato = rec_panapdc.get(PANAPDC_CODCONTO);
tmpcurr.put("CONTO", conto_riclassificato);
break; //esce dal casino e passa ai campi successivi
}
else if (conto == current_conto && current_sottoconto == 0)
{
conto_riclassificato = rec_panapdc.get(PANAPDC_CODCONTO);
tmpcurr.put("CONTO", conto_riclassificato);
break; //esce dal casino e passa ai campi successivi
}
else if (conto == current_conto && sottoconto == current_sottoconto)
{
conto_riclassificato = rec_panapdc.get(PANAPDC_CODCONTO);
tmpcurr.put("CONTO", conto_riclassificato);
break; //esce dal casino e passa ai campi successivi
}
} //for sugli elementi del cursore
} //if panapdc_items > 0
//ATTENZIONE! Se era stata operata una selezione sui conti riclassificati nella maschera
//ed il conto riclassificato attuale non ricade nell'intervallo selezionato il programma
//non deve aggiungere il record al file!!
if ((_da_conto_riclas.not_empty() && conto_riclassificato < _da_conto_riclas) ||
(_a_conto_riclas.not_empty() && conto_riclassificato.compare(_a_conto_riclas, _a_conto_riclas.len()) > 0))
return;
} //if(_riclassificato)
else //...senn<6E> si usa il normale piano dei conti analitico (cio<69> tutti tranne che il CRPA)
tmpcurr.put("CONTO", rmovana.get(RMOVANA_CODCONTO)); //conto
//in ogni caso riempio il campo conto_cg
tmpcurr.put("CONTOCG", rmovana.get(RMOVANA_CODCONTO)); //conto_cg
//tipo movimento CONSUNTIVO (o TEMPORANEO)
const char tipomov = movana.get_char(MOVANA_TIPOMOV);
if (tipomov <= ' ' || tipomov == 'T')
{
//serve un documento da cui ricavare i parametri di stampa
TDocumento* newdoc = (TDocumento*)doc;
bool should_delete = false;
if (newdoc == NULL && movana.get(MOVANA_DNDOC).not_empty())
{
const TString4 dacodnum = movana.get(MOVANA_DCODNUM);
newdoc = new TDocumento('D', movana.get_int(MOVANA_DANNO), dacodnum, movana.get_long(MOVANA_DNDOC));
should_delete = true; //settato true per cancellare il doc al termine del metodo(senn<6E> addio memoria!)
}
const bool dadoc = newdoc != NULL;
//i movimenti possono essere normali o generati da documento...
if (dadoc) //movimento generato da documento
{
codnum_desc = movana.get(MOVANA_DCODNUM); //serve anche in fondo al metodo
tmpcurr.put("CODNUM", codnum_desc); //codnum del documento che origina il movana
tmpcurr.put("ANNO", movana.get(MOVANA_DANNO)); //anno del doc di origine
tmpcurr.put("NUMRD", movana.get(MOVANA_DNDOC)); //numero del doc che origina movana
tmpcurr.put("DATA", newdoc->get(DOC_DATADOC)); //data del documento che genera movana..
} //..non esiste il campo in movana
else //movimento normale (senza documento)
{
tmpcurr.put("CODNUM", movana.get(MOVANA_CODCAUS)); //mette la causale del movimento
tmpcurr.put("ANNO", movana.get(MOVANA_ANNOES)); //anno del movimento
tmpcurr.put("NUMRD", movana.get(MOVANA_NUMREGCG)); //numregcg del movana
tmpcurr.put("DATA", movana.get(MOVANA_DATACOMP)); //data del movana
}
//ricerca del mitico documento padre della riga documento attuale!
int selettore = 0;
if (newdoc != NULL)
{
tmpcurr.put("NUMDOCRIF", newdoc->get(DOC_NUMDOCRIF)); //docrif del documento originante il movana
tmpcurr.put("DATADOCRIF", newdoc->get(DOC_DATADOCRIF)); //datadocrif del documento originante il movana
//procedura per ottenere i campi del documento
//deve tener conto del vero tipo del documento,nel caso sia classificato come _altro;in questo
//..caso si deve accorgere se e' in realta' una bolla o una fattura (utilizza la tipo_riclassificato())
const int tipo_documento = newdoc->tipo_riclassificato();
int tipo_babbo = TTipo_documento::_altro;
TString80 riferimento; //stringa su cui scrivere gli estremi del doc padre (se lo trova!)
real totale_doc_babbo; //totale del doc padre
const int rows = newdoc->physical_rows(); //righe del doc attuale
for (int i = 1; riferimento.empty() && i <= rows; i++)
{
const TRiga_documento& riga = (*newdoc)[i];
const TRectype* babbo = riga.find_original_rdoc(); //cerca il doc padre della riga doc attuale
if (babbo != NULL) //se trova il doc padre..
{
const TString4 babbo_codnum = babbo->get(RDOC_CODNUM);
const int anno = babbo->get_int(RDOC_ANNO);
const long ndoc = babbo->get_long(RDOC_NDOC);
riferimento << babbo_codnum << '-' << anno << '-' << ndoc;
TDocumento doc_babbo('D', anno, babbo_codnum, ndoc); //crea una copia del doc padre per prendere..
tipo_babbo = doc_babbo.tipo_riclassificato(); //..il tipo documento..
totale_doc_babbo = doc_babbo.totale_doc(); //..il suo totale
} //if (babbo != NULL)..
} //for (int i..
/*[Tipo documento] //schema divino per destinare gli importi nei campi corretti
O=I**
B=IM*
BO=*M*
FB=**F
FO=*MF
F=IMF*/
switch (tipo_documento)
{
case TTipo_documento::_bolla: //bolla B -> IM a meno che non sia bolla da ordine BO -> M
selettore = MATURATO;
if (tipo_babbo != TTipo_documento::_ordine)
selettore |= IMPEGNATO;
break;
case TTipo_documento::_fattura:
selettore = FATTURATO; //fattura da bolla FB -> F
if (tipo_babbo == TTipo_documento::_ordine) //fattura da ordine FO -> MF
{
selettore |= MATURATO;
} else
if (tipo_babbo == TTipo_documento::_altro) //fattura senza padri F -> IMF
selettore |= (IMPEGNATO | MATURATO);
break;
case TTipo_documento::_ordine:
selettore = IMPEGNATO;
break;
case TTipo_documento::_altro:
CHECK(false, "Ma dove cavolo stai passando Willis?");
break;
default:
break;
}
tmpcurr.put("DOCORIG", riferimento);
} //if(newdoc != NULL)
else //movimenti puri di analitica (no documento di origine!)
{
selettore = FATTURATO;
selettore |= MATURATO;
selettore |= IMPEGNATO;
} //if(newdoc != NULL)
//riempie i record del file temporaneo nel caso di rmovana con documento di origine
const char sezione = rmovana.get_char(RMOVANA_SEZIONE);
TImporto imp(sezione, rmovana.get_real(RMOVANA_IMPORTO));
TCausale caus(movana.get(MOVANA_CODCAUS));
TipoIVA tipoiva = caus.iva();
char sezione_normale;
if (tipoiva == iva_vendite)
sezione_normale = 'A';
else
if (tipoiva == iva_acquisti)
sezione_normale = 'D';
else
{
if (caus.sezione_clifo() == 'D')
sezione_normale = 'A';
else
sezione_normale = 'D';
}
imp.normalize(sezione_normale);
//riempie i record del file temporaneo nel caso di rmovana con documento di origine
if (selettore & FATTURATO)
tmpcurr.put("FATTURATO", imp.valore());
if (selettore & MATURATO)
tmpcurr.put("MATURATO", imp.valore());
if (selettore & IMPEGNATO)
tmpcurr.put("IMPEGNATO", imp.valore());
//campi comuni a rmovana e rdoc senza particolari operazioni
TString descr = movana.get(MOVANA_DESCR);
int pos = descr.find('$'); //solo per il CRPA!
if (pos > 0)
{
descr.ltrim(pos+1);
descr.trim();
}
tmpcurr.put("NUMREG", rmovana.get(RMOVANA_NUMREG));
tmpcurr.put("DESC", descr); //descrizione movana
tmpcurr.put("NRIGA", rmovana.get(RMOVANA_NUMRIG)); //numero riga
tmpcurr.put("DESCRIGA", rmovana.get(RMOVANA_DESCR)); //descrizione rmovana
//La procedura seguente non avra' piu' senso dopo l'eliminazione degli stati!!***
/*int err = _tmp->write(); // aggiunge i record al file temporaneo
//procedura di controllo della scrittura su file! se il documento <20> gi<67> stato contbilizzato..
//..sul file temporaneo esiste gi<67> un record con la chiave del record,dovuto al doc,..
//..che deve essere qui aggiunto!significa che l'intervallo di stati della numerazione selezionato..
//..nello sheet <20> errato (probabilmente lo stato finale <20> troppo alto)
if (err != NOERR)
{
TString msg;
msg.format(FR("Errore di scrittura %d sul file temporaneo.\n"), err);
msg << "Documento " << codnum_desc << " " << descr << " gia' contabilizzato.\nControllare lo stato della numerazione.";
error_box (msg);
}*/
if (should_delete)
delete newdoc;
} //if (tipomov == ..)
else
{
tmpcurr.put("HIDDEN", "X");
}
_tmp->write();
}
//scanning delle righe dei movimenti di analitica
void TPrint_rendiconto_ca_recordset::crea_righe_da_rmovana()
{
TRelation rel_rmovana(LF_RMOVANA);
rel_rmovana.add(LF_MOVANA, "NUMREG==NUMREG"); //aggiunge le testate x avere tipi mov e descr
//..crea un cursore su rmovana per vedere se i conti selezionati hanno veri movimenti che soddisfano
//i parametri del filtro sulla maschera. ACHTUNG! Questo filtro ha senso solo se non esiste la
//riclassificazione!!!
TRectype da_rmovana(LF_RMOVANA);
TRectype a_rmovana(LF_RMOVANA);
if (!_riclassificato)
{
da_rmovana.put(RMOVANA_CODCONTO, _daconto);
a_rmovana.put(RMOVANA_CODCONTO, _aconto);
}
TString filtro;
if (_dadata.ok())
filtro << "(ANSI(DATACOMP)>=" << _dadata.date2ansi() << ")";
if (_adata.ok())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(ANSI(DATACOMP)<=" << _adata.date2ansi() << ")";
}
if (_codcosto.not_empty())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RMOVANA_CODCCOSTO << "==\"" << _codcosto << "\")";
}
if (_codcms.not_empty())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RMOVANA_CODCMS << "==\"" << _codcms << "\")";
}
if (_codfas.not_empty())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RMOVANA_CODFASE << "==\"" << _codfas << "\")";
}
TCursor cur_rmovana(&rel_rmovana, filtro, 2, &da_rmovana, &a_rmovana);
const TRecnotype rmovana_items = cur_rmovana.items();
//scorre le righe movimenti di analitica che soddisfano il filtro
//il join a movana serve nel caso necessitino dati di testata per la riga in questione
if (rmovana_items > 0)
{
cur_rmovana.freeze();
const TRectype& rmovana = cur_rmovana.curr();
const TRectype& movana = rel_rmovana.curr(LF_MOVANA);
TProgind pi(rmovana_items, "Scansione righe movimenti...", true, true);
for (cur_rmovana = 0; cur_rmovana.pos() < rmovana_items; ++cur_rmovana)
{
pi.addstatus(1);
if (pi.iscancelled())
break;
scrive_riga(rmovana, movana, NULL);
}
}
}
//scanning delle righe dei documenti
void TPrint_rendiconto_ca_recordset::crea_righe_da_rdoc(const TPrint_rendiconto_ca_mask& msk)
{
TRelation rel_rdoc(LF_RIGHEDOC);
rel_rdoc.add(LF_DOC, "CODNUM==CODNUM|ANNO==ANNO|PROVV==PROVV|NDOC==NDOC"); //aggiunge le testate
TRectype dardoc(LF_RIGHEDOC);
TRectype ardoc(LF_RIGHEDOC);
TString filtro_date;
dardoc.put(RDOC_PROVV, 'D');
ardoc.put(RDOC_PROVV, 'D');
//se siamo fortunati l'anno si pu<70> trovare cos<6F>..
int anno = msk.get_int(F_ANNO);
if (anno > 0)
{
dardoc.put(RDOC_ANNO, anno);
ardoc.put(RDOC_ANNO, anno);
}
else
{
dardoc.put(RDOC_ANNO, _dadata.year());
ardoc.put(RDOC_ANNO, _adata.year());
if (_dadata.year() == _adata.year())
anno = _dadata.year();
}
if (_dadata.ok())
filtro_date << "(ANSI(33->DATADOC)>=" << _dadata.date2ansi() << ")";
if (_adata.ok())
{
if (filtro_date.not_empty())
filtro_date << "&&";
filtro_date << "(ANSI(33->DATADOC)<=" << _adata.date2ansi() << ")";
}
TContabilizzazione_analitica cont_anal; //oggetto necessario per contabilizzare il documento in osservazione
//inizialmente il filtro di scansione delle righedoc coincide con quello sulle date
TString filtro = filtro_date;
//Filtro sulle righe documento (e testate collegate)
//Controlla sul file di configurazione di CA (ditta.ini,[ca]) se esistono numerazioni da escludere..
//..e se, per alcune numerazioni, deve tener conto dello stato del documento
TConfig& config = ca_config();
bool update = false;
for (int i = 0;;i++) //scansione delle righe ND(i)=.. sul paragrafo di configurazione CA
{
TToken_string num_doc(config.get("ND", NULL, i));
const TString4 codnum = num_doc.get(0);
if (codnum.blank())
break;
const bool exclude = num_doc.get_char(1) == 'X';
if (filtro.not_empty())
filtro << "&&";
if (exclude) //numerazioni da escludere
{
filtro << "(CODNUM!=\"" << codnum << "\")";
}
else //numerazioni per le quali tener conto dello stato
{
filtro << "((CODNUM!=\"" << codnum << "\")";
filtro << "||((" << LF_DOC << "->STATO>=\"" << num_doc.get(2) << "\")";
filtro << "&&(" << LF_DOC << "->STATO<=\"" << num_doc.get(3) << "\")))";
update = true;
}
}
//poi deve aggiungere il filtro per cdc/cms/fas
if (_codcosto.not_empty())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RDOC_CODCOSTO << "==\"" << _codcosto << "\")";
}
if (_codcms.not_empty())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RDOC_CODCMS << "==\"" << _codcms << "\")";
}
if (_codfas.not_empty())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RDOC_FASCMS << "==\"" << _codfas << "\")";
}
//il filtro <20> completo;pu<70> eseguire la scansione
TCursor cur_rdoc(&rel_rdoc, "", 3, &dardoc, &ardoc);
cur_rdoc.setfilter(filtro, update);
const TRecnotype rdoc_items = cur_rdoc.items();
if (rdoc_items > 0)
{
cur_rdoc.freeze();
TProgind pi(rdoc_items, "Scansione righe documenti...", true, true);
//memorizza l'ultimo doc per evitare doppioni in caso di doc con pi<70> righe (rielaborerebbe..
//..lo stesso documento tante volte quante sono le sue righe!)
TString old_key;
//scanning del file dei documenti alla ricerca di quelli che hanno la data ed il CODNUM
//validi nei filtri impostati dall'utente
for (cur_rdoc = 0; cur_rdoc.pos() < rdoc_items; ++cur_rdoc)
{
pi.addstatus(1);
if (pi.iscancelled())
break;
const TRectype& curr_doc = cur_rdoc.curr(LF_DOC);
//controlla se il documento cui appartiene la rigadoc e' stato contabilizzato;
//se e' stato contabilizzato lo salta in quanto la riga documento apparira' attraverso le righe
//dei movimenti di analitica
const long numregca = curr_doc.get_long(DOC_NUMREGCA);
if (numregca == 0)
{
const TString curr_key = curr_doc.build_key();
if (curr_key == old_key)
continue;
else
old_key = curr_key;
TDocumento doc(curr_doc);
TAnal_mov mov;
cont_anal.elabora(doc, 0, NULL, false, mov);
//estrae il tipo ed il codice clifo dal documento per metterlo nel movana che ha generato
//con la elabora (richiesta puramente adolfica!)
TString16 key;
key << doc.get(DOC_TIPOCF) << '|' << doc.get(DOC_CODCF);
const TString clifo = cache().get(LF_CLIFO, key, CLI_RAGSOC);
mov.put(MOVANA_DESCR, clifo);
for (int j = 1; j <= mov.rows(); j++)
{
//controlla che la riga in esame abbia realmente la cms/cdc/fas indicata nel filtro;
//procedimento necessario per evitare la stampa di righe appartenenti a docs elaborati
//perch<63> contenenti 1 riga con cms corretta ed altre righe con cms sbagliate
const TRectype& rmov = mov.body()[j];
if (_codcms.not_empty() && rmov.get(RMOVANA_CODCMS) != _codcms)
continue;
if (_codcosto.not_empty() && rmov.get(RMOVANA_CODCCOSTO) != _codcosto)
continue;
if (_codfas.not_empty() && rmov.get(RMOVANA_CODFASE) != _codfas)
continue;
scrive_riga(rmov, mov, &doc);
} //for int j...
} //if numregca
} //for cur_rdoc..
} //if rdoc_items
}
void TPrint_rendiconto_ca_recordset::crea_trr(const TFilename& trr) const
{
ofstream of(trr);
of << 1000 << endl;
of << 17 << endl;
of << "CONTO|1|20|0|Conto analitico" << endl;
of << "DATA|5|8|0|Data movimento o documento" << endl;
of << "CODNUM|1|4|0|Numerazione documento" << endl;
of << "NUMRD|3|7|0|Numero registrazione contabile o numero documento di origine" << endl;
of << "NRIGA|2|3|0|Riga movimento o documento" << endl;
of << "NUMREG|3|7|0|Numero registrazione del movimento analitico" << endl;
of << "ANNO|9|4|0|Anno" << endl;
of << "NUMDOCRIF|1|7|0|Numero documento riferimento" << endl;
of << "DATADOCRIF|5|8|0|Data documento riferimento" << endl;
of << "DESC|1|50|0|Descrizione movimento o documento" << endl;
of << "DESCRIGA|1|50|0|Descrizione riga movimento o documento" << endl;
of << "DOCORIG|1|20|0|Riferimento ordine/bolla" << endl;
of << "FATTURATO|4|18|5|Fatturato" << endl;
of << "MATURATO|4|18|5|Maturato" << endl;
of << "IMPEGNATO|4|18|5|Impegnato" << endl;
of << "CONTOCG|1|12|0|Conto contabile" << endl;
of << "HIDDEN|8|1|0|Record nascosto" << endl;
of << 1 << endl;
of << "CONTO+DATA+CODNUM+NUMRD+NRIGA" << endl;
}
void TPrint_rendiconto_ca_recordset::set_filter(const TPrint_rendiconto_ca_mask& msk, int cms_row)
{
//se esiste il file temporano con tracciato persomalizzato lo cancella e lo ricrea vuoto
TFilename trr; //file tracciato record
trr.tempdir();
trr.add("rendy");
TFilename dbf(trr); //file dati
trr.ext("trr");
dbf.ext("dbf");
//crea il file .trr in base ai parametri del metodo
crea_trr(trr);
//svuota la memoria dal vecchio file temporaneo
if (_tmp != NULL)
delete _tmp;
//crea in memoria il nuovo file temporaneo e lo azzera (non si sa mai..)
_tmp = new TExternisamfile(dbf, trr);
_tmp->zap();
//prende un po' di dati dalla maschera...
_daconto, _aconto, _codcosto = _codcms = _codfas = "";
if (cms_row >= 0)
{
TSheet_field& sf = msk.sfield(F_RIGHE);
TMask& sm = sf.sheet_mask();
sf.update_mask(cms_row);
TRelation rel(LF_RMOVANA);
sm.autosave(rel);
_codcosto = rel.curr().get(RMOVANA_CODCCOSTO);
_codcms = rel.curr().get(RMOVANA_CODCMS);
_codfas = rel.curr().get(RMOVANA_CODFASE);
}
const char tc = msk.get(F_PIANO)[0]; // Piano dei conti Contabile o Analitico?
const short dlg_da = tc == 'C' ? F_PDC1_INI : F_PAN1_INI;
const short dlg_al = tc == 'C' ? F_PDC1_FIN : F_PAN1_FIN;
//si utilizza la riclassificazione dei conti?
if (msk.get(F_PIANO) == "A")
_riclassificato = true;
else
_riclassificato = false;
//conti non riclassificati
if (!_riclassificato)
{
for (int i = 0; i < 4 && msk.id2pos(dlg_da+i) > 0; i++)
{
_daconto << msk.get(dlg_da+i);
_aconto << msk.get(dlg_al+i);
}
}
else //conti riclassificati
{
for (int i = 0; i < 4 && msk.id2pos(dlg_da+i) > 0; i++)
{
_da_conto_riclas << msk.get(dlg_da+i);
_a_conto_riclas << msk.get(dlg_al+i);
}
}
_dadata = msk.get_date(F_DATAINI);
_adata = msk.get_date(F_DATAFIN);
if (_riclassificato)
{
//esiste un prefisso a pi<70> livelli?
for (short id = F_PRE1; id <= F_PRE3 && msk.id2pos(id) > 0; id++)
{
const TString& pr = msk.get(id);
if (pr.not_empty())
_prefix << pr;
else
break;
}
}
//metodi per riempire il file da cui generare il report
//dati estratti dalle righe movimenti di contabilita' analitica
crea_righe_da_rmovana();
//dati estratti dalle righe documenti
crea_righe_da_rdoc(msk);
}
////////////////////////////////////////////////////////
// REPORT
////////////////////////////////////////////////////////
class TPrint_rendiconto_ca_rep : public TAnal_report
{
protected:
virtual bool set_recordset(const TString& sql);
virtual bool get_usr_val(const TString& name, TVariant& var) const;
public:
void set_filter(const TPrint_rendiconto_ca_mask& msk, int cms_row);
};
bool TPrint_rendiconto_ca_rep::get_usr_val(const TString& name, TVariant& var) const
{
return TAnal_report::get_usr_val(name, var);
}
bool TPrint_rendiconto_ca_rep::set_recordset(const TString& sql)
{
TPrint_rendiconto_ca_recordset* rs = new TPrint_rendiconto_ca_recordset(sql);
return TAnal_report::set_recordset(rs);
}
void TPrint_rendiconto_ca_rep::set_filter(const TPrint_rendiconto_ca_mask& msk, int cms_row)
{
TAnal_report::set_recordset(NULL); // Forza azzeramento file Rendy.dbf prima di ricostruirlo
const char* query ="USE 1000\nJOIN MOVANA INTO NUMREG==NUMRD\nJOIN RMOVANA INTO NUMREG==NUMRD NUMRIG==NRIGA";
TPrint_rendiconto_ca_recordset* recset = new TPrint_rendiconto_ca_recordset(query);
recset->set_filter(msk, cms_row);
TAnal_report::set_recordset(recset);
}
////////////////////////////////////////////////////////
// APPLICAZIONE
////////////////////////////////////////////////////////
class TPrint_rendiconto_ca : public TSkeleton_application
{
public:
const TMultilevel_code_info& get_first_level() const;
virtual void main_loop();
};
//metodo per accattarsi o' primo livello della configurazione CA
const TMultilevel_code_info& TPrint_rendiconto_ca::get_first_level() const
{
TConfig& cfg = ca_config();
const TString& first_lev = cfg.get("Level(1)");
const int logic = first_lev == "CDC" ? LF_CDC : LF_COMMESSE;
return ca_multilevel_code_info(logic);
}
void TPrint_rendiconto_ca::main_loop()
{
TPrint_rendiconto_ca_mask mask;
while (mask.run() == K_ENTER)
{
//report e book dei report
TReport_book book;
TString path = mask.get(F_REPORT);
if (path.empty())
path = "ca3700a";
TPrint_rendiconto_ca_rep rep;
rep.load(path);
TSheet_field& sheet = mask.sfield(F_RIGHE);
TString video_string; //stringa che compare nella progind
if (sheet.empty()) //se non ci sono righe sullo sheet (selezione su tutte le cms/cdc)...
{
TToken_string& row = sheet.row(-1); //crea la prima riga dello sheet
const TMultilevel_code_info& liv1 = get_first_level(); //stabilisce quale <20> il primo livello (tra CDC e CMS)..
TISAM_recordset set(liv1.logic() == LF_CDC ? "USE CDC" : "USE COMMESSE"); //..e di conseguenza scrive la use giusta
TProgind pi(set.items(), video_string, true, true);
for (int i = 0; set.move_to(i); i++) //fighissimo metodo per scandire un file in 1 riga!
{
pi.addstatus(1);
if (pi.iscancelled())
break;
row = set.get((unsigned int)0).as_string(); //prende il valore del primo campo del file (CDC o CMS code)
video_string = TR("Scansione");
video_string << " " << row; //completa la stringa da visualizzare sulla progind
pi.set_text(video_string);
for (int l = liv1.levels()-2; l >= 0; l--) //se la struttura <20> a pi<70> livelli costruisce la tokenstring
row.insert("|", liv1.total_len(l));
rep.set_filter(mask, 0); //fa la set filter sulla prima riga (che <20> quella usata)
book.add(rep);
}
sheet.destroy(); //cancella le commesse aggiunte in automatico sullo sheet
}
else //se ha almeno una riga sullo sheet delle cms/cdc...
{
FOR_EACH_SHEET_ROW(sheet, r, row) //per ogni cdc/cms che appare nello sheet di pag.1 della msk..
{
rep.set_filter(mask, r); //..chiama il metodone globale che crea e compila il file..
//..temporaneo i cui dati riempiranno il report
book.add(rep); //aggiunge il report relativo alla cdc/cms corrente al book
}
}
book.print_or_preview(); //stampa il book dei report
}
}
int ca3700(int argc, char* argv[])
{
TPrint_rendiconto_ca a;
a.run(argc, argv, TR("Stampa rendiconto"));
return 0;
}