campo-sirio/ca/ca3700.cpp
guy ebeaf18246 Patch level : 10.0
Files correlati     : ca3
Ricompilazione Demo : [ ]
Commento            :
Riporto modifiche di Bonazzi


git-svn-id: svn://10.65.10.50/branches/R_10_00@22607 c028cbd2-c16b-5b4b-a496-9718f37d4682
2012-03-09 15:49:52 +00:00

2256 lines
78 KiB
C++
Executable File
Raw Blame History

#include <applicat.h>
#include <defmask.h>
#include <execp.h>
#include <progind.h>
#include <reprint.h>
#include <reputils.h>
#include <doc.h>
#include <rdoc.h>
#include "../cg/cg2103.h"
#include "../cg/cglib01.h"
#include "../ve/velib04.h"
#include "cdc.h"
#include "commesse.h"
#include "panapdc.h"
#include "pconana.h"
#include "movana.h"
#include "rmovana.h"
#include "saldana.h"
#include "ca3.h"
#include "ca3700.h"
#include "calib01.h"
#include "calib02.h"
////////////////////////////////////////////////////////
// MASCHERA
////////////////////////////////////////////////////////
class TPrint_rendiconto_ca_mask : public TAnal_report_mask
{
char _print_mode;
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
const TString& get_report_class() const;
bool test_compatible_report();
public:
char print_mode() const { return _print_mode; }
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 DLG_PREVIEW: //gestione del tasto anteprima!
if (e == fe_button)
{
stop_run('A');
}
break;
case DLG_EXPORT:
if (e == fe_button)
{
TString path = get(F_PATH);
if (path.empty())
return error_box(TR("Specificare una cartella dove creare il file rendiconto.xls!"));
}
break;
#ifndef DBG
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;
#endif
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"));
}
if (e == fe_init)
_print_mode = 'S';
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);
}
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 prefix = cfg.get_int("PdcPrefix");
if (prefix >= pconana_levels)
prefix = pconana_levels-1;
//setta nel campo F_PIANO il tipo di piano dei conti usato in base alla configurazione..
//..e disabilita il campo (non si puo' cambiare la configurazione in una stampa!!)
disable(F_PIANO);
set(F_PIANO, use_pdcc ? "C" : "A");
// Controllo se voglio (e posso) usare il conto analitico come prefisso di quello contabile
if (use_pdcc && prefix > 0)
{
const TMultilevel_code_info& info = ca_multilevel_code_info(LF_PCONANA);
const int levels = info.levels();
if (levels >= 2 && prefix < 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 < prefix)
{
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();
}
///////////////////////////////////////////////////////////////
// TRiclass
///////////////////////////////////////////////////////////////
class TRiclass : public TCache
{
TString16 _prefix;
protected:
TObject* key2obj(const char* key);
public:
void set_prefix(const TString& p) { _prefix = p; }
bool is_riclassificato(const TString& str_conto) const;
TRiclass() : TCache(883) {}
};
TObject* TRiclass::key2obj(const char* key)
{
CHECK(_prefix.full(), "Empty pconana prefix");
const TFixed_string str_conto(key);
TRelation panarel(LF_PANAPDC);
TString filter;
filter << '(' << PANAPDC_CODCONTO << "[1," << _prefix.len() << "]==\"" << _prefix << "\")";
TRectype& fromto = panarel.curr();
if (str_conto.len() >= 3)
fromto.put(PANAPDC_GRUPPO, str_conto.left(3));
if (str_conto.len() >= 6)
fromto.put(PANAPDC_CONTO, str_conto.mid(3,3));
else
filter << "&&(" << PANAPDC_CONTO << "=\"\")";
if (str_conto.len() >= 12)
fromto.put(PANAPDC_SOTTOCONTO, str_conto.mid(6,6));
else
filter << "&&(" << PANAPDC_SOTTOCONTO << "=\"\")";
TCursor panacur(&panarel, filter, 2, &fromto, &fromto);
bool ok = panacur.items() > 0;
return new real(ok ? UNO : ZERO);
}
//cerca se str_conto <20> riclassificato
bool TRiclass::is_riclassificato(const TString& str_conto) const
{
TString80 codice = str_conto;
const real* o = (const real*)((TRiclass*)this)->objptr(codice); //Allah!!!
if (o->is_zero() && codice.len() == 12)
{
codice.cut(6);
o = (const real*)((TRiclass*)this)->objptr(codice); //Budda!!!
}
if (o->is_zero() && codice.len() == 6)
{
codice.cut(3);
o = (const real*)((TRiclass*)this)->objptr(codice); //Jeowah!!!
}
return !o->is_zero();
}
///////////////////////////////////////////////////////////////
// RECORDSET
///////////////////////////////////////////////////////////////
#define IMPEGNATO 1
#define MATURATO 2
#define FATTURATO 4
class TPrint_rendiconto_ca_recordset : public TISAM_recordset
{
bool _riclassificato;
bool _reverse_cos_ric;
bool _implode_rows;
TString _prefix;
TAssoc_array _ratrisc;
TString_array _num_fdr;
TString_array _num_par;
TRiclass _ricl;
protected:
int _anno;
TString4 _piano;
TDate _dadata, _adata;
bool _vitaintera;
long _danumreg, _anumreg;
TString _daconto, _aconto, _codcosto, _codcms, _codfas;
protected:
static bool mov_filter(const TRelation* rel);
bool valid_record(const TRelation& rel) const;
virtual void set_custom_filter(TCursor& cur) const;
void calcola_date_da_maschera(const TMask& msk, TDate& dal, TDate& al);
int crea_filtro_rmovana(const TMask& msk, TRectype& da_rmovana, TRectype& a_rmovana, TString& filtro);
void crea_righe_da_rmovana(TLocalisamfile& tmp, const TPrint_rendiconto_ca_mask& msk, TLog_report& log);
int crea_filtro_rdoc(const TMask& msk, TRectype& da_rdoc, TRectype& a_rdoc, TString& filtro_date);
void crea_righe_da_rdoc(TLocalisamfile& tmp, const TPrint_rendiconto_ca_mask& msk, TLog_report& log);
void crea_trr(const TFilename& trr) const;
void scrive_riga(TLocalisamfile& tmp, const TRectype& rmovana, const TRectype& movana, const TDocumento* doc,
TLog_report& log);
void scrive_riga_speciale(TLocalisamfile& tmp, const TDocumento* doc, const TString_array& special_docs);
int sort_indbil(int indbil) const;
const TString& riclassifica(const TBill& zio, TRectype& tmpcurr) const;
const TString& riclassifica(const TString& contone, TRectype& tmpcurr) const;
bool is_causale_rateo_risconto(const char* codcaus) const;
int ricava_tipo_documento (const TDocumento& doc) const;
public: //da libreria
virtual const TVariant& get(const char* column_name) const;
public:
void set_filter(const TPrint_rendiconto_ca_mask& msk, int cms_row, TLog_report& log);
void set_cms_cdc_fase(const char* cdc, const char* cms, const char* fase);
real get_budget_print(const TString& conto, char tipo) const; //per la stampa
void get_budget_export(const TString& codcdc, const TString& codcms, const TString& codfase,
TImporto& att, TImporto& pas, TImporto& cos, TImporto& ric) const; //per l'esportazione
TPrint_rendiconto_ca_recordset(const TString& sql);
~TPrint_rendiconto_ca_recordset();
};
TPrint_rendiconto_ca_recordset::TPrint_rendiconto_ca_recordset(const TString& sql)
: TISAM_recordset(sql), _riclassificato(false)
{
//Controlla sul file di configurazione di CA (ditta.ini,[ca]) se esistono causali di tipo..
//..rateo/risconto che devono essere calcolate come solo maturato (Eva Braun request)
TConfig& config = ca_config();
//riempie l'assoc_array contenente i codici causale rateo/risconto
for (int j = 0;;j++)
{
const TString& codcaus = config.get("RR", NULL, j); //scansione delle righe RR(i)=.. sul paragrafo di configurazione CA
if (codcaus.blank())
break;
_ratrisc.add(codcaus, codcaus);
}
//TString_array contenente le numerazioni delle fatture da ricevere
for (int j = 0;;j++)
{
const TString& codfdr = config.get("NF", NULL, j); //scansione delle righe NF(i)=.. sul paragrafo di configurazione CA
if (codfdr.blank())
break;
_num_fdr.add(codfdr);
}
//TString_array contenente le numerazioni delle parcelle e lo stato da cui considerarle fatture
for (int j = 0;;j++)
{
TToken_string num_par(config.get("PA", NULL, j)); //scansione delle righe PA(i)=.. sul paragrafo di configurazione CA
if (num_par.empty_items())
break;
_num_par.add(num_par);
}
}
TPrint_rendiconto_ca_recordset::~TPrint_rendiconto_ca_recordset()
{ }
//filtro ulteriore sul file rendy.dbf gi<67> creato
//questo filtro, all'apparenza inutile, serve per filtrare sulle rmovana create al volo dagli rdoc..
//..che potrebbero presentare conti non pertinenti dovuti ai conti stessi legati ai codart ecc.
void TPrint_rendiconto_ca_recordset::set_custom_filter(TCursor& cur) const
{
//la region serve solo nella chiave 1!!!
if (cur.key() == 1)
{
//filtro sul file esterno (tmp, cio<69> rendy.dbf) sui conti selezionati sulla maschera
TRectype darec(cur.curr()), arec(cur.curr()); //curr perch<63> <20> il file externisamfile
darec.zero();
arec.zero();
if (_daconto.not_empty())
{
darec.put("ORDCONT", 1);
darec.put("CONTO", _daconto);
}
if (_aconto.not_empty())
{
arec.put("ORDCONT", 5);
arec.put("CONTO", _aconto);
}
cur.setregion(darec, arec);
}
//filtro sulla data(non avendo anche codnum non ho la chiave completa per mettere la data nella setregion)
TString filtro;
if (_dadata.ok() || _adata.ok())
{
if (_vitaintera)
filtro << "(BETWEEN(DATA," << _dadata.date2ansi() << ",0))";
else
filtro << "(BETWEEN(DATA," << _dadata.date2ansi() << "," << _adata.date2ansi() << "))";
}
//vera selezione sui conti
if (_daconto.full() || _aconto.full())
{
if (filtro.not_empty())
filtro << "&&";
if (_daconto == _aconto)
filtro << "(CONTO[1," << _daconto.len() << "]==\"" << _daconto << "\")";
else
filtro << "(BETWEEN(CONTO,\"" << _daconto << "\",\"" << _aconto << "~\"))";
}
cur.setfilter(filtro);
}
void TPrint_rendiconto_ca_recordset::set_cms_cdc_fase(const char* cdc, const char* cms, const char* fase)
{
_codcosto = cdc;
_codcms = cms;
_codfas = fase;
}
void TPrint_rendiconto_ca_recordset::get_budget_export(const TString& codcdc, const TString& codcms, const TString& codfase,
TImporto& att, TImporto& pas, TImporto& cos, TImporto& ric) const
{
TString query;
query << "USE SALDANA\nSELECT ";
if (codcdc.full())
query << "(COSTO='" << codcdc << "')&&";
if (codcms.full())
query << "(COMMESSA='" << codcms << "')&&";
if (codfase.full())
query << "(FASE='" << codfase << "')&&";
query.rtrim(2);
TISAM_recordset saldana(query);
for (bool ok = saldana.move_first(); ok; ok = saldana.move_next())
{
const TString80 str_conto = saldana.get("CONTO").as_string();
if (_riclassificato && !_ricl.is_riclassificato(str_conto))
continue;
const TAnal_bill zio(str_conto);
const int indbil = zio.indicatore_bilancio();
TImporto saldo = ca_get_imp(saldana, SALDANA_SEZIONEP, SALDANA_SALDOP);
saldo += ca_get_imp(saldana, SALDANA_SEZIONEV, SALDANA_SALDOV);
switch(indbil)
{
case 1: att += saldo; break;
case 2: pas += saldo; break;
case 3: cos += saldo; break;
case 4: ric += saldo; break;
default: break;
}
}
att.normalize('D');
cos.normalize('D');
pas.normalize('A');
ric.normalize('A');
}
//sconvolgente metodo per la normalizzazione dei conti
real TPrint_rendiconto_ca_recordset::get_budget_print(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, "#PIANO") == 0)
{
TVariant& var = get_tmp_var();
if (_piano == "A")
var = "Analitico";
else
var = "Contabile";
return var;
}
if (strcmp(column_name, "#DACONTO") == 0)
{
TVariant& var = get_tmp_var();
var = _daconto;
return var;
}
if (strcmp(column_name, "#ACONTO") == 0)
{
TVariant& var = get_tmp_var();
var = _aconto;
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_print(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_print(conto, 'V');
}
}
return TISAM_recordset::get(column_name);
}
int TPrint_rendiconto_ca_recordset::sort_indbil(int indbil) const
{
if (_reverse_cos_ric) //sono del CRPA/DINAMICA
{
if (indbil == 3 || indbil == 4)
indbil = 7 - indbil;
}
return indbil;
}
const TString& TPrint_rendiconto_ca_recordset::riclassifica(const TBill& zio, TRectype& tmpcurr) const
{
TString conto_riclassificato;
//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, zio.gruppo());
TString filtro;
if (_prefix.full())
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 (zio.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 (zio.conto() == current_conto && zio.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!!Quindi ritorna una stringa vuota che sara' il segnale..
//..per interrompere l'analisi del record corrente
if ((_daconto.not_empty() && conto_riclassificato < _daconto) ||
(_aconto.not_empty() && conto_riclassificato.compare(_aconto, _aconto.len()) > 0))
return EMPTY_STRING;
return get_tmp_string() = conto_riclassificato;
}
const TString& TPrint_rendiconto_ca_recordset::riclassifica(const TString& contone, TRectype& tmpcurr) const
{
CHECK(contone.len() == 12, "Conto di lunghezza assurda");
const int gruppo = atoi(contone.left(3));
const int conto = atoi(contone.mid(3,3));
const long sottoconto = atol(contone.mid(6,6));
const TBill zio(gruppo, conto, sottoconto);
return riclassifica(zio, tmpcurr);
}
static int bill2indbil(const TString& codconto, bool is_anal)
{
int indbil = 0;
if (is_anal)
{
const TAnal_bill bill(codconto);
indbil = bill.indicatore_bilancio();
}
else
{
const int gruppo = atoi(codconto.left(3));
const int conto = atoi(codconto.mid(3,3));
const long sottoconto = atol(codconto.mid(6,6));
const TBill bill(gruppo, conto, sottoconto);
indbil = bill.indicatore_bilancio();
}
return indbil;
}
//controlla se la causale passata e' di tipo rateo/risconto
bool TPrint_rendiconto_ca_recordset::is_causale_rateo_risconto(const char* codcaus) const
{
return _ratrisc.objptr(codcaus) != NULL;
}
int TPrint_rendiconto_ca_recordset::ricava_tipo_documento (const TDocumento& doc) const
{
int tipo_documento = doc.tipo_riclassificato();
if (tipo_documento == TTipo_documento::_fattura)
{
//attenzione! se il documento fosse una ignorantissima parcella, il tipo documento verrebbe..
//..deciso in base allo stato del documento stesso, secondo la regola data nella configurazione del..
//..rendiconto
const TString4 codnum = doc.numerazione();
const TString4 stato = doc.get(DOC_STATO);
FOR_EACH_ARRAY_ROW(_num_par, r, riga)
{
const TString4 par_codnum = riga->get(0);
if (par_codnum == codnum)
{
const TString4 par_stato = riga->get(1);
if (stato < par_stato)
tipo_documento = TTipo_documento::_bolla;
break;
}
}
}
return tipo_documento;
}
//compila i campi del file temporaneo che sara' poi stampato
void TPrint_rendiconto_ca_recordset::scrive_riga(TLocalisamfile& tmp, const TRectype& rmovana, const TRectype& movana,
const TDocumento* doc, TLog_report& log)
{
TRectype& tmpcurr = tmp.curr();
tmpcurr.zero();
TString8 codnum; //codnum da usare sia per compilare il campo "CODNUM"
//----- CONTI -----//
const TString80 codconto_originale = rmovana.get(RMOVANA_CODCONTO);
if (codconto_originale.blank())
{
TString error_string;
const long error_numreg = rmovana.get_long(RMOVANA_NUMREG);
const int error_numrig = rmovana.get_int(RMOVANA_NUMRIG);
error_string.format("NON esiste il conto sulla riga %d del movimento %ld !!", error_numrig, error_numreg);
log.log(2, error_string);
return;
}
TString80 codconto = codconto_originale;
TString codcontocg;
int indbil = 0;
bool conto_non_riclass = false; //indicatore che serve per tener conto di specialissimi conti del CRPA...
//E' una lampante dimostrazione di quanto sia generico questo programma...
// 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!!!...
//Ricordare che SOLO se si ha un conto contabile e' possibile riclassificare in analitico!!!
if (_riclassificato) //traduzione:sei il CRPA/DINAMICA
{
//stringa che conterr<72> il conto riclassificato (se sara' trovato)
const TString conto_riclassificato = riclassifica(codconto, tmpcurr);
//se il conto viene ritornato vuoto significa che non ricade nell'intervallo dei conti..
//..riclassificati selezionato dall'utente...non puo' essere scartato a priori perche' puo'..
//..essere un conto speciale del CRPA
codcontocg = codconto;
indbil = bill2indbil(codcontocg, false);
if (conto_riclassificato.empty())
{
conto_non_riclass = true;
codconto.cut(0);
}
else //..senno' lo scrive come conto riclassificato
codconto = conto_riclassificato;
} //if(_riclassificato) Se non e' un conto riclassificato -> analitico puro o contabile puro
else //...senn<6E> si usano..
{
if (_piano == "A") //..il normale piano dei conti analitico.. Conto analitico puro
indbil = bill2indbil(codconto, true);
else //..o il normale piano dei conti contabile Conto contabile puro
{
codcontocg = codconto;
indbil = bill2indbil(codcontocg, false);
}
}
//La scrittura dei conti su tmpcurr e' rinviata in fondo al metodo...
//---- FINE CONTI ----//
//---- DOC D'ORIGINE DELL' ANALMOV ----//
//tipo movimento CONSUNTIVO (o TEMPORANEO); per i movimenti di budget (P o V) vedi l'else
const char tipomov = movana.get_char(MOVANA_TIPOMOV);
#ifdef DBG
const long movana_numreg = movana.get_long(MOVANA_NUMREG);
if (movana_numreg == 19571)
const int cazzone = 1;
#endif
//serve un documento da cui ricavare i parametri di stampa
TDocumento* original_doc = (TDocumento*)doc;
bool should_delete = false;
if (original_doc == NULL && movana.get_long(MOVANA_DNDOC) > 0)
{
const TString4 dacodnum = movana.get(MOVANA_DCODNUM);
original_doc = 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 = original_doc != NULL;
//i movimenti possono essere normali o generati da documento...
if (dadoc) //movimento generato da documento
{
codnum = movana.get(MOVANA_DCODNUM); //serve anche in fondo al metodo
tmpcurr.put("CODNUM", codnum); //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", original_doc->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
}
int selettore = 0;
const int anno_caus = movana.get_date(MOVANA_DATAREG).year();
const TCausale caus(movana.get(MOVANA_CODCAUS), anno_caus); //la causale serve un po' ovunque...
//caso in cui il movimento derivi da un documento
//ricerca del mitico documento padre della riga documento attuale!
if (original_doc != NULL)
{
tmpcurr.put("NUMDOCRIF", original_doc->get(DOC_NUMDOCRIF)); //docrif del documento originante il movana
tmpcurr.put("DATADOCRIF", original_doc->get(DOC_DATADOCRIF)); //datadocrif del documento originante il movana
//procedura per ottenere i campi del documento
int tipo_babbo = TTipo_documento::_altro;
//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 = ricava_tipo_documento(*original_doc);
TToken_string riferimento(20, '\n'); //tokenstring su cui scrivere gli estremi dei docs padri (se li trova!)
TString80 rif; //stringa di lavoro su cui viene scritto un doc originale
const int rows = original_doc->physical_rows(); //righe del doc attuale
for (int i = 1; i <= rows; i++) //scandisce tutte le righe del doc..
{
const TRiga_documento& riga = (*original_doc)[i];
//commessa e fase della riga documento
const TString codcms_rigadoc = riga.codice_commessa();
const TString codfase_rigadoc = riga.fase_commessa();
const TString codcdc_rigadoc = riga.codice_costo();
//per evitare di scrivere per ogni riga documento tutte le righe del doc babbo (in pratica..
//..per evitare di avere n righe ordine ogni riga fattura) confronta commessa e fase e cdc..
//..della riga movimento analitico con quelli la riga movimento e procede solo nel..
//..caso coincidano (richiesta Adolfica! heil Magnavakken!)
//Altra richiesta Adolfica: nel caso di ripartizioni, per non perdere la connessione tra..
//..commessa/fase/cdc originale della riga analitica non ripartita e cms/fase/cdc della riga doc,..
//..e' necessario controllare l'esistenza dei campi ori che segnalano una ripartizione avvenuta.
//Se i campi ori sono compilati vanno usati!!! In caso contrario verrebbe perso il legame tra riga anal..
//..e riga doc e doc_babbo, perdendo la giusta configurazione del SELETTORE
TString codcms_rmovana = rmovana.get(RMOVANA_CODCMSORI);
if (!codcms_rmovana.full())
codcms_rmovana = rmovana.get(RMOVANA_CODCMS);
TString codfase_rmovana = rmovana.get(RMOVANA_CODFASEORI);
if (!codfase_rmovana.full())
codfase_rmovana = rmovana.get(RMOVANA_CODFASE);
TString codcdc_rmovana = rmovana.get(RMOVANA_CODCCORI);
if (!codcdc_rmovana.full())
codcdc_rmovana = rmovana.get(RMOVANA_CODCCOSTO);
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);
rif.cut(0) << babbo_codnum << '-' << anno << '-' << ndoc;
if (tipo_babbo == TTipo_documento::_altro)
{
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..
}
if (codcms_rigadoc == codcms_rmovana && codfase_rigadoc == codfase_rmovana && codcdc_rigadoc == codcdc_rmovana)
{
//caso particolare dei conti del CRPA. Se il conto non e' riclassificato (ma siamo in presenza..
//.di un piano dei conti riclassificato)...
if (conto_non_riclass)
{
//Controlla se il documento di origine (padre del documento da cui deriva l'attuale riga..
//..di analitica) era una FDR/FDE...
const TCodice_numerazione kodice_num(babbo_codnum);
//Se lo era...
if (kodice_num.fattura_emettere_ricevere())
{
//Ricrea il documento origine
TDocumento doc_babbo('D', anno, babbo_codnum, ndoc);
//elaborazione analitica del documento originale
TContabilizzazione_analitica cont_anal;
TAnal_mov mov_babbo;
//se riesce a contabilizzare il documento origine (si spera, senno' so' cazzi!)..
cont_anal.elabora(doc_babbo, 0, NULL, false, mov_babbo);
if (mov_babbo.rows() > 0)
{
const int anal_rows = mov_babbo.rows();
for (int k = 1; k <= anal_rows; k++)
{
//cerca la riga con il conto che gli serve e lo assegna a codconto, attualmente vuoto..
//..in quanto non e' stato riclassificato
const TRectype& mov_babbo_riga = mov_babbo.body()[k];
const TString& conto_babbo = mov_babbo_riga.get(RMOVANA_CODCONTO);
if (conto_babbo != codcontocg)
{
//ovviamente deve riclassificare il conto_babbo!
codconto = riclassifica(conto_babbo, tmpcurr);
indbil = bill2indbil(codconto, true);
break;
}
}
} //if (mov_babbo.rows() > 0)
}
else
continue;
}
if (riferimento.get_pos(rif) < 0) //il doc originale va aggiunto solo se non esiste gia'!
{
riferimento.add(rif);
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..
}
} //if (codcms_rigadoc == codcms_rmovana..
} //if (babbo != NULL)..
} //for (int i..
tmpcurr.put("DOCORIG", riferimento); //documento di riferimento (mitologico documento originale)
//---- FINE DOC ORIG DELL'ANALMOV ----//
/*[Tipo documento] //schema divino per destinare gli importi nei campi corretti
O=I**
B=IM*
BO=*M*
FB=**F
FO=*MF
F=IMF*/
//---- IMPEGNATO,MATURATO O FATTURATO? QUESTO E' IL PROBLEMA.. ----//
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;
}
const TString4 dacodnum = movana.get(MOVANA_DCODNUM);
if (_num_fdr.find(dacodnum) >= 0) // is_special_doc
{
TLocalisamfile rdoc(LF_RIGHEDOC);
rdoc.setkey(4);
rdoc.put(RDOC_DAPROVV, movana.get(MOVANA_DPROVV));
rdoc.put(RDOC_DAANNO, movana.get(MOVANA_DANNO));
rdoc.put(RDOC_DACODNUM, dacodnum);
rdoc.put(RDOC_DANDOC, movana.get(MOVANA_DNDOC));
if (rdoc.read(_isgteq) == NOERR &&
rdoc.get(RDOC_DAPROVV) == movana.get(MOVANA_DPROVV) &&
rdoc.get_int(RDOC_DAANNO) == movana.get_int(MOVANA_DANNO) &&
rdoc.get(RDOC_DACODNUM) == dacodnum &&
rdoc.get_long(RDOC_DANDOC) == movana.get_long(MOVANA_DNDOC))
selettore &= ~FATTURATO;
}
} //if(original_doc != NULL)
else //movimenti puri di analitica (no documento di origine!)
{
if (is_causale_rateo_risconto(caus.codice())) //movimenti con causali "rateo/risconto"
{
selettore = MATURATO;
}
else //movimenti con causali "normali"
{
selettore = FATTURATO;
selettore |= MATURATO;
selettore |= IMPEGNATO;
}
} //if(original_doc != NULL)
//riempie i record del file temporaneo nel caso di rmovana con documento di origine
char sezione = rmovana.get_char(RMOVANA_SEZIONE);
TImporto imp(sezione, rmovana.get_real(RMOVANA_IMPORTO));
TipoIVA tipoiva = caus.iva(); //tipo iva legato alla causale (codcaus e' letto ad inizio procedura)
char sezione_normale = sezione; //inizializza la sezione normale a sezione per evitare vuoti
if (tipoiva == iva_vendite)
sezione_normale = 'A';
else
if (tipoiva == iva_acquisti)
sezione_normale = 'D';
else
if (tipoiva == nessuna_iva)
{
if (caus.tipomov() > 0 && caus.tipomov() < 3) //solo causali Fattura e Nota di Credito!
{
if (caus.sezione_clifo() == 'D')
sezione_normale = 'A';
else
sezione_normale = 'D';
}
else
{
if (indbil == 1 || indbil == 3) //attivita' e costi sono in DARE
sezione_normale = 'D';
else //passivita' e ricavi sono in AVERE
sezione_normale = 'A';
}
}
else
{ //iva errata -> non ha causali -> cerca di capire se cliente o fornitore
if (original_doc != NULL)
{
if (original_doc->get_char(DOC_TIPOCF) == 'C')
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();
}
//----Scrittura Conti sul file----//
//Scrittura dei conti (i valori delle variabili sono stati settati nella parte iniziale del metodo)
//mette i conti nel file (se piano dei conti puramente contabile i valori coincidono)
if (codconto.blank())
{
TString error_message;
error_message.format("Il conto %s non <20> riclassificato!", (const char*)codcontocg);
log.log(2, error_message);
}
tmpcurr.put("CONTO", codconto); //conto
tmpcurr.put("CONTOCG", codcontocg); //conto_cg
//fa il sort l'indicatore di bilancio del conto e lo utilizza per ordinare i record nel file..
//..di appoggio;se sei del CRPA/CSA vuoi i costi dopo i ricavi!
const int ordcont = sort_indbil(indbil);
tmpcurr.put("ORDCONT", ordcont);
//----Scrittura dati riga movimento----//
tmpcurr.put("NUMREG", rmovana.get(RMOVANA_NUMREG)); //numero di registrazione analitica
tmpcurr.put("NUMREGCG", movana.get(MOVANA_NUMREGCG)); //numero di registrazione contabile
tmpcurr.put("DESC", descr); //descrizione movana
tmpcurr.put("NRIGA", rmovana.get(RMOVANA_NUMRIG)); //numero riga
tmpcurr.put("DESCRIGA", rmovana.get(RMOVANA_DESCR)); //descrizione rmovana
tmpcurr.put("CODCMS", rmovana.get(RMOVANA_CODCMS)); //codice commessa
tmpcurr.put("CODCOSTO", rmovana.get(RMOVANA_CODCCOSTO)); //codice cdc
tmpcurr.put("CODFASE", rmovana.get(RMOVANA_CODFASE)); //codice fase
if (should_delete)
delete original_doc;
//I movimenti di budget (preventivi e variazioni) vanno nascosti nei body!!! Devono essere considerati in..
//..quanto servono per sapere quali conti sono stati movimentati per i budget, in modo che per ogni conto..
//..il report si crei la testata e faccia il relativo calcolo del saldo del conto! (cerca #PREVENTIVO)
if (tipomov == 'P' || tipomov == 'V')
tmpcurr.put("HIDDEN", "X");
//scrive sul file di appoggio il record appena riempito
int err = tmp.write();
//se e' in modalita' di ricompattamento righe ripartite..
if (_implode_rows)
{
//..se ha un errore di riscrittura significa che ci sono righe dello stesso movimento ricompattate..
//..in precedenza Quindi incrementa di 1 il numero riga fino al primo posto libero
while (err == _isreinsert)
{
const int new_nriga = tmpcurr.get_int("NRIGA") + 1;
tmpcurr.put("NRIGA", new_nriga);
err = tmp.write();
}
}
}
//compila i campi del file temporaneo che sara' poi stampato per i documenti speciali..
//..quali le fatture da emettere e ricevere, la cui lista e' nel ca_config
void TPrint_rendiconto_ca_recordset::scrive_riga_speciale(TLocalisamfile& tmp, const TDocumento* doc, const TString_array& special_docs)
{
//prende il tipocf che gli serve un po' ovunque in seguito..
const char tipocf = doc->get_char(DOC_TIPOCF);
const int rows = doc->physical_rows();
TContabilizzazione_analitica contab;
for (int i = 1; i <= rows; i++)
{
const TRiga_documento& rigadoc = (*doc)[i];
const TString& dacodnum = rigadoc.get(RDOC_DACODNUM);
if (special_docs.find(dacodnum) >= 0) // Riga proveniente da special doc
{
TString codconto, codcontocg;
TRectype& tmpcurr = tmp.curr();
tmpcurr.zero();
//se usa il piano dei conti contabile -> _piano = C..
if (_piano == "C")
{
//trova il conto senza movana e rmovana!!!
TBill conto;
if (contab.search_costo_ricavo(rigadoc, conto, false)) // was true
codconto = codcontocg = conto.string(0x8);
}
else //se ivece usa il piano dei conti analitico -> _piano = A...
{
if (_riclassificato)
{
TBill conto;
if (contab.search_costo_ricavo(rigadoc, conto, true))
{
//stringa che conterr<72> il conto riclassificato (se sara' trovato)
codconto = riclassifica(conto, tmpcurr);
codcontocg = conto.string(0x8);
}
} //if(_riclassificato)
else
{
if (rigadoc.is_articolo())
{
const TRectype& anamag = cache().get(LF_ANAMAG, rigadoc.get(RDOC_CODARTMAG));
codconto = anamag.get(tipocf == 'F' ? ANAMAG_CONTOINDA : ANAMAG_CONTOINDV);
}
else
{
if (rigadoc.is_spese() || rigadoc.is_prestazione() ||
rigadoc.is_risorsa() || rigadoc.is_attrezzatura())
{
const char tipo = rigadoc.tipo().tipo();
const TSpesa_prest spp(rigadoc.get(RDOC_CODART), tipo);
codconto = tipocf == 'F' ? spp.conto_analitico_acquisti() : spp.conto_analitico_vendite();
}
}
}
}
//non trova il conto -> esce dalla riga e passa alla successiva
if (codconto.empty())
continue;
const int indbil = codcontocg.full() ? bill2indbil(codcontocg, false)
: bill2indbil(codconto, true) ;
tmpcurr.put("CONTO", codconto);
tmpcurr.put("CONTOCG", codcontocg);
tmpcurr.put("ORDCONT", sort_indbil(indbil));
//comincia a riempire i record
//prima i campi che prende direttamente dal doc speciale
tmpcurr.put("CODNUM", doc->get(DOC_CODNUM)); //numerazione doc speciale
tmpcurr.put("ANNO", doc->get(DOC_ANNO)); //anno doc speciale
tmpcurr.put("NUMRD", doc->get(DOC_NDOC)); //numero del doc speciale
tmpcurr.put("DATA", doc->get(DOC_DATADOC)); //data del doc speciale
tmpcurr.put("NUMDOCRIF", doc->get(DOC_NUMDOCRIF)); //docrif del documento
tmpcurr.put("DATADOCRIF", doc->get(DOC_DATADOCRIF)); //datadocrif del documento
tmpcurr.put("NUMREG", doc->get(DOC_NUMREGCA)); //numero di registrazione analitica
tmpcurr.put("NUMREGCG", doc->get(DOC_NUMREG)); //numero di registrazione contabile
TToken_string clifo_key;
clifo_key.add(tipocf);
clifo_key.add(doc->get(DOC_CODCF));
const TString& ragsoc = cache().get(LF_CLIFO, clifo_key, CLI_RAGSOC);
tmpcurr.put("DESC", ragsoc); //descrizione doc: ci mette il clifo (come nei movana normali)
tmpcurr.put("DESCRIGA", rigadoc.get(RDOC_DESCR)); //descrizione rdoc
tmpcurr.put("NRIGA", rigadoc.get(RDOC_NRIGA)); //numero riga
tmpcurr.put("CODCMS", rigadoc.get(RDOC_CODCMS)); //codice commessa
tmpcurr.put("CODCOSTO", rigadoc.get(RDOC_CODCOSTO)); //codice cdc
tmpcurr.put("CODFASE", rigadoc.get(RDOC_FASCMS)); //codice fase
//procedura per ottenere i campi del documento origine di quello in esame
const int tipo_documento = doc->tipo_riclassificato();
int tipo_babbo = TTipo_documento::_altro;
TToken_string riferimento(20, '\n'); //tokenstring su cui scrivere gli estremi dei docs padri (se li trova!)
TString80 rif; //stringa di lavoro su cui viene scritto un doc originale
const int rows = doc->physical_rows(); //righe del doc attuale
const TRectype* babbo = rigadoc.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);
rif.cut(0) << babbo_codnum << '-' << anno << '-' << ndoc;
tmpcurr.put("DOCORIG", rif); //documento di riferimento (mitologico documento originale)
} //if (babbo != NULL)..
const real importo = rigadoc.imponibile();
const TTipo_documento& tipodoc = doc->tipo();
const TString& codcaus = tipodoc.causale();
if (codcaus.full())
{
TImporto imp(tipocf == 'F' ? 'D' : 'A', importo);
const int anno_caus = doc->get_int(DOC_ANNO);
TCausale caus(codcaus, anno_caus);
TipoIVA tipoiva = caus.iva();
char sezione_normale;
if (tipoiva == iva_vendite)
sezione_normale = 'A';
else
if (tipoiva == nessuna_iva)
{
if (caus.sezione_clifo() == 'D')
sezione_normale = 'A';
else
sezione_normale = 'D';
}
else
{ //iva errata -> non ha causali -> cerca di capire se cliente o fornitore
if (doc != NULL && doc->get_char(DOC_TIPOCF) == 'C')
sezione_normale = 'A';
else
sezione_normale = 'D';
}
imp.normalize(sezione_normale);
//i documenti speciali vanno SOLO in FATTURATO
tmpcurr.put("FATTURATO", imp.valore());
}
else //if(codcaus.full()
{
//i documenti speciali vanno SOLO in FATTURATO
tmpcurr.put("FATTURATO", importo);
}
tmp.write();
} //if(special_docs...
} // for (inti=1;i<=rows...
}
void TPrint_rendiconto_ca_recordset::calcola_date_da_maschera(const TMask& msk, TDate& dal, TDate& al)
{
//se siamo fortunati l'anno si pu<70> trovare cos<6F>..
int anno = msk.get_int(F_ANNO);
if (anno > 0)
{
TEsercizi_contabili esc;
esc.code2range(anno, dal, al);
}
if (_dadata.ok())
dal = _dadata;
if (_adata.ok())
al = _adata;
}
//nuovo modo di costruire il filtro e darec arec, da quando esistono le chiavi per codcm e codcdc su lf_rmovana
int TPrint_rendiconto_ca_recordset::crea_filtro_rmovana(const TMask& msk, TRectype& da_rmovana, TRectype& a_rmovana, TString& filtro)
{
int cur_key = 4;
//intanto sistema darec arec
da_rmovana.put(RMOVANA_CODCMS, _codcms);
da_rmovana.put(RMOVANA_CODCCOSTO, _codcosto);
a_rmovana = da_rmovana;
//se c'<27> solo cdc deve cambiare la chiave..
if (_codcms.blank() && _codcosto.full())
cur_key = 5;
//adesso tocca al filtro
//conti
if (!_riclassificato && (_daconto.full() || _aconto.full()))
{
if (_daconto == _aconto)
filtro << "(CODCONTO[1," << _daconto.len() << "]==\"" << _daconto << "\")";
else
filtro << "BETWEEN(CODCONTO,\"" << _daconto << "\",\"" << _aconto << "~\")";
}
//date
if (!_vitaintera)
{
TDate dal, al;
calcola_date_da_maschera(msk, dal, al);
if (filtro.not_empty())
filtro << "&&";
filtro << "(BETWEEN(DATACOMP," << dal.date2ansi() << ',' << al.date2ansi() << "))";
}
//fase
if (_codfas.not_empty())
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RMOVANA_CODFASE << "==\"" << _codfas << "\")";
}
return cur_key;
}
//scanning delle righe dei movimenti di analitica
void TPrint_rendiconto_ca_recordset::crea_righe_da_rmovana(TLocalisamfile& tmp, const TPrint_rendiconto_ca_mask& msk,
TLog_report& log)
{
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);
TString filtro;
//nuovo metodo di filtraggio (chiave 4 o 5)
int cur_key = crea_filtro_rmovana(msk, da_rmovana, a_rmovana, filtro);
TCursor cur_rmovana(&rel_rmovana, filtro, cur_key, &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);
//aggiunta adolfica di implosione righe movimenti eventualmente ripartite in precedenza..
//..modifica che serve solo al CRPA
//se si e' scelto di compattare le rmovana...
if (_implode_rows)
{
TRecord_array righe_attuali(LF_RMOVANA, RMOVANA_NUMRIG);
TRecord_array righe_compattate(LF_RMOVANA, RMOVANA_NUMRIG);
TRectype old_movana(LF_MOVANA);
long old_numreg = 0L;
//si usa <= per forzare il cambio testata anche sull'ultimo movimento (in modo da uscire correttamente)
//NON mettere < e basta che sbaglia l'ultimo!!!
for (cur_rmovana = 0; cur_rmovana.pos() <= rmovana_items; ++cur_rmovana)
{
//legge la testata iniziale
const long numreg = rmovana.get_long(RMOVANA_NUMREG);
#ifdef DBG
if (numreg == 32736)
const int cazzissimo = 1;
#endif
//se la testata e' cambiata, allora ha cambiato movana e quindi le righe da compattare sono..
//..quelle che ha gia' messo nell'array delle righe_attuali
if (numreg != old_numreg)
{
if (righe_attuali.rows() > 0) //quando righe_attuali e' vuoto sei al primo giro
{
//quindi implode le righe attuali del movimento, generando l'array delle righe_compattate
ca_implode_rows(righe_attuali, righe_compattate);
//adesso fa la scrittura delle righe compattate
const int last_row = righe_compattate.last_row();
for (int i = righe_compattate.first_row(); i > 0 && i <= last_row; i = righe_compattate.succ_row(i))
scrive_riga(tmp, righe_compattate.row(i), old_movana, NULL, log);
}
//aggiorna il valore di testata con quella nuova per il prossimo movimento
old_movana = movana;
old_numreg = numreg;
//pulisce gli array che sono pronti ad essere nuovamente riempiti
righe_attuali.destroy_rows();
righe_compattate.destroy_rows();
}
//aggiunge le righe analitiche all'array da compattare (se rmovana e' vuoto ha gia' terminato)
if (numreg > 0)
{
righe_attuali.insert_row(rmovana);
}
else
break;
}
}
else //if(_implode_rows.. metodo standard senza ripartizioni
{
for (cur_rmovana = 0; cur_rmovana.pos() < rmovana_items; ++cur_rmovana)
{
if (!pi.addstatus(1))
break;
scrive_riga(tmp, rmovana, movana, NULL, log);
}
}
}
}
//fatta su chiave 6 e 7 di lf_rdoc; non controlla le date, ammettendo movimenti non rientranti nell'intervallo di..
//..date scelto dalla maschera, purch<63> tali movimenti appartengano a commessa/cdc in esame
int TPrint_rendiconto_ca_recordset::crea_filtro_rdoc(const TMask& msk, TRectype& da_rdoc, TRectype& a_rdoc, TString& filtro_date)
{
int cur_key = 6;
//intanto sistema darec arec
da_rdoc.put(RDOC_CODCMS, _codcms);
da_rdoc.put(RDOC_CODCOSTO, _codcosto);
a_rdoc = da_rdoc;
//se c'<27> solo cdc..
if (_codcms.blank() && _codcosto.full())
cur_key = 7;
//filtro date
if (!_vitaintera)
{
TDate dal, al;
calcola_date_da_maschera(msk, dal, al);
if (filtro_date.not_empty())
filtro_date << "&&";
filtro_date << "(BETWEEN(33->DATADOC," << dal.date2ansi() << ',' << al.date2ansi() << "))";
}
return cur_key;
}
//scanning delle righe dei documenti
void TPrint_rendiconto_ca_recordset::crea_righe_da_rdoc(TLocalisamfile& tmp, const TPrint_rendiconto_ca_mask& msk,
TLog_report& log)
{
TRelation rel_rdoc(LF_RIGHEDOC);
rel_rdoc.add(LF_DOC, "CODNUM==CODNUM|ANNO==ANNO|PROVV==PROVV|NDOC==NDOC"); //aggiunge le testate
TRectype da_rdoc(LF_RIGHEDOC);
TRectype a_rdoc(LF_RIGHEDOC);
TString filtro_date;
//metodo moderno
const int cur_key = crea_filtro_rdoc(msk, da_rdoc, a_rdoc, filtro_date);
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
bool update = false;
TConfig& config = ca_config();
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 (cur_key == 3) //questo solo se si usa la chiave 3 (metodo restrittivo antico)
{
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()) //questo in ogni modo, anche con chiave 6 o 7 (oltre che 3)
{
if (filtro.not_empty())
filtro << "&&";
filtro << "(" << RDOC_FASCMS << "==\"" << _codfas << "\")";
}
//il filtro <20> completo;pu<70> eseguire la scansione
TCursor cur_rdoc(&rel_rdoc, "", cur_key, &da_rdoc, &a_rdoc);
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)
{
if (!pi.addstatus(1))
break;
//La riga esaminata deve avere una testata valida!!!!Se la testata non esiste va saltata..
//..la riga
const TRectype& curr_doc = cur_rdoc.curr(LF_DOC);
if (!curr_doc.empty())
{
//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);
//**Modifca richiesta dal CRPA!Le righe documento che hanno DACODNUM di tipo fattura da..
//..ricevere/emettere, vanno ri-contabilizzate lo stesso anche se lo sono gia' state. Il loro..
//..importo verra' poi messo nel fatturato.
const TRectype& curr_rdoc = cur_rdoc.curr();
const TString& rdoc_dacodnum = curr_rdoc.get(RDOC_DACODNUM);
#ifdef DBG
if (rdoc_dacodnum == "FDE" && curr_rdoc.get_int(RDOC_ANNO) == 2011 && curr_rdoc.get_int(RDOC_NDOC) == 3)
const int culone = 1;
#endif
const bool is_special_doc = _num_fdr.find(rdoc_dacodnum) >= 0;
//documento non contabilizzato o fattura da ricevere con numerazione configurata speciale
if (numregca == 0) // || is_special_doc)
{
const TString curr_key = curr_doc.build_key();
if (curr_key == old_key)
continue;
else
old_key = curr_key;
TDocumento doc(curr_doc);
//documento NON contabilizzato
if (numregca == 0)
{
TAnal_mov mov;
cont_anal.elabora(doc, 0, NULL, false, mov, false);
//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(tmp, rmov, mov, &doc, log); //documenti "normali"
} //for int j...
}
else
{
//righe di documento configurate come da emettere/ricevere (documenti speciali)
scrive_riga_speciale(tmp, &doc, _num_fdr);
}
} //if (numregca==0...
} //if !curr_doc.empty()
//Ha trovato una riga senza testata! non puo' considerarla ma avverte l'utente del problema
else
{
const TRectype& bad_row = cur_rdoc.curr();
const TString4 bad_codnum = bad_row.get(RDOC_CODNUM);
const int bad_anno = bad_row.get_int(RDOC_ANNO);
const long bad_ndoc = bad_row.get_long(RDOC_NDOC);
const int bad_nriga = bad_row.get_int(RDOC_NRIGA);
TString error_string;
error_string << bad_codnum << "|" << bad_anno << "|D|" << bad_ndoc << "|" << bad_nriga;
warning_box("Riga documento %s priva di testata!", (const char*)error_string);
}
} //for cur_rdoc..
} //if rdoc_items
}
void TPrint_rendiconto_ca_recordset::crea_trr(const TFilename& trr) const
{
ofstream of(trr);
of << 1000 << endl;
of << 22 << endl;
of << "ORDCONT|1|1|0|Ordinatore in base a indicatore di bilancio" << 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 << "CODCMS|1|20|0|Codice commessa" << endl;
of << "CODCOSTO|1|20|0|Codice centro di costo" << endl;
of << "CODFASE|1|20|0|Codice fase (eventualmente legato a CODCMS)" << endl;
of << "NUMREG|3|7|0|Numero registrazione del movimento analitico" << endl;
of << "NUMREGCG|3|7|Numero registrazione contabile" << 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|50|0|Riferimenti 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 << 3 << endl;
of << "ORDCONT+CONTO+DATA+CODNUM+NUMRD+NUMREG+NRIGA" << endl;
of << "CODCMS+ORDCONT+CONTO+DATA+CODNUM+NUMRD+NUMREG+NRIGA|X" << endl;
of << "CODCOSTO+ORDCONT+CONTO+DATA+CODNUM+NUMRD+NUMREG+NRIGA|X" << endl;
}
void TPrint_rendiconto_ca_recordset::set_filter(const TPrint_rendiconto_ca_mask& msk, int cms_row, TLog_report& log)
{
//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);
//crea in memoria il nuovo file temporaneo e lo azzera (non si sa mai..)
TExternisamfile tmp(dbf, trr, true);
tmp.zap();
//prende un po' di dati dalla maschera...
_piano, _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?
//Ovvero: sei il CRPA o un qualsiasi altro utente del mondo?
_piano = msk.get(F_PIANO);
if (_piano == "A")
{
TConfig& cfg = ca_config();
const bool use_pdcc = cfg.get_bool("UsePdcc");
_riclassificato = use_pdcc;
}
else
_riclassificato = false;
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.full())
_prefix << pr;
else
break;
}
_ricl.set_prefix(_prefix);
}
//c'e' un range di conti da considerare?
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);
}
//vuoi l'ordinamento normale o sei la Roberta del CRPA?
_reverse_cos_ric = msk.get_bool(F_REV_COSRIC);
//sei al CRPA e vuoi implodere le righemovana ripartite in precedenza?
_implode_rows = msk.get_bool(F_IMPLODE_ROWS);
//c'e' un fottuto range di date? oppure si va a vita intera?
_dadata = msk.get_date(F_DATAINI);
_adata = msk.get_date(F_DATAFIN);
_vitaintera = msk.get_bool(F_VITAINTERA);
//metodi per riempire il file da cui generare il report
//dati estratti dalle righe movimenti di contabilita' analitica
crea_righe_da_rmovana(tmp, msk, log);
//dati estratti dalle righe documenti
crea_righe_da_rdoc(tmp, msk, log);
}
////////////////////////////////////////////////////////
// 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, const int recset_key, TLog_report& log);
};
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, const int recset_key, TLog_report& log)
{
TAnal_report::set_recordset(NULL); // Forza azzeramento file Rendy.dbf prima di ricostruirlo
TString query ="USE RENDY.DBF";
query << " KEY " << recset_key << "\n";
query << "JOIN 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, log);
TAnal_report::set_recordset(recset);
}
////////////////////////////////////////////////////////
// APPLICAZIONE
////////////////////////////////////////////////////////
class TPrint_rendiconto_ca : public TSkeleton_application
{
TPrint_rendiconto_ca_mask* _msk;
protected:
virtual void print();
void esporta_csv_row(ostream& file_to_date, const int first_level, const TString& cod_cms_cdc,
const real importi[5][4], real importi_totali[5][4]);
void esporta_csv(TPrint_rendiconto_ca_recordset& rendy, const int r);
void incrementa(TToken_string& riga, const int col, const real& valore) const;
public:
const TMultilevel_code_info& get_first_level() const;
virtual void main_loop();
};
void TPrint_rendiconto_ca::print()
{
if (_msk != NULL)
_msk->send_key(K_SPACE, DLG_PRINT);
}
void TPrint_rendiconto_ca::incrementa(TToken_string& riga, const int col, const real& valore) const
{
real r; riga.get(col, r);
r += valore;
riga.add(r.string(), col);
}
void TPrint_rendiconto_ca::esporta_csv_row(ostream& file_to_date, const int first_level, const TString& cod_cms_cdc,
const real importi[5][4], real importi_totali[5][4])
{
const int posizione_importi = first_level == LF_COMMESSE ? 5 : 2;
//crea una token string su cui mettere i valori dei record letti dal file .dbf
TToken_string riga(512, '\t');
riga.add(cod_cms_cdc);
//decodifica della commessa/cdc (non <20> ammessa una commessa "TOTALI" che lo incasina
if (cod_cms_cdc != "TOTALI")
{
const TRectype& rec = cache().get(first_level, cod_cms_cdc);
const TString& descrizione = rec.get("DESCRIZ");
riga.add(descrizione);
if (first_level == LF_COMMESSE)
{
riga.add(rec.get(COMMESSE_DATAINIZIO));
riga.add(rec.get(COMMESSE_DATAFINE));
riga.add(rec.get(COMMESSE_DATAPROR));
}
}
//in base al valore di indbil e budget i valori degli importi vengono posizionati nel record
for (int indbil = 1; indbil <= 4; indbil++)
{
int col = 0;
switch (indbil)
{
case 1: col = posizione_importi + 14; break; //attivit<69>
case 2: col = posizione_importi + 21; break; //passivit<69>
case 3: col = posizione_importi; break; //costi
case 4: col = posizione_importi + 7; break; //ricavi
default: break;
}
//colonne budget/impegnato/maturato/fatturato
for (int j = 0; j < 4; j++)
{
riga.add(importi[indbil][j].string(), col + j);
importi_totali[indbil][j] += importi[indbil][j];
}
//colonne da_impegnare/da_maturare/da_fatturare
const real da_impegnare = importi[indbil][0] - importi[indbil][1];
riga.add(da_impegnare.string(), col + 4);
const real da_maturare = importi[indbil][1] - importi[indbil][2];
riga.add(da_maturare.string(), col + 5);
const real da_fatturare = importi[indbil][1] - importi[indbil][3];
riga.add(da_fatturare.string(), col + 6);
}
//scrive in excel mode
for (int i = posizione_importi; i < posizione_importi + 28; i++)
{
const real r = riga.get(i);
if (!r.is_zero())
{
TString80 str;
str << r;
str.replace('.', ',');
riga.add(str, i);
}
}
//aggiunge la riga al file da esportare
file_to_date << riga << endl;
}
//metodo di alto livello per l'esportazione dei dati di totale in un file per excel
void TPrint_rendiconto_ca::esporta_csv(TPrint_rendiconto_ca_recordset& rendy, const int r)
{
//primo livello di configurazione
const int first_level = get_first_level().logic();
//piano dei conti riclassificato?
TConfig& cfg = ca_config();
const bool riclassificato = cfg.get_bool("UsePdcc");
//aggiorna il file da esportare appendendo la nuova riga
TFilename path = _msk->get(F_PATH);
path.lower();
path.add("rendiconto.xls");
ofstream file_to_date(path, ios::app);
const bool invert_cosric = _msk->get_bool(F_REV_COSRIC);
//array bidimensionale con gli importi per indbil e colonna
real importi[5][4];
//array bidimensionale con gli importi totali finali
real importi_totali[5][4];
TString80 last_codice, curr_codice;
TSheet_field& sf = _msk->sfield(F_RIGHE);
TString80 codcms, codcdc, codfas;
if (first_level == LF_CDC)
{
ca_extract_sheet_field(sf, r, LF_COMMESSE, codcms);
ca_extract_sheet_field(sf, r, LF_FASI, codfas);
}
else
{
ca_extract_sheet_field(sf, r, LF_CDC, codcdc);
ca_extract_sheet_field(sf, r, LF_FASI, codfas);
}
//recordset sul file rendy.dbf, da scandire tutto un record per volta
rendy.requery();
for (bool ok = rendy.move_first(); ok; ok = rendy.move_next())
{
curr_codice = rendy.get(first_level == LF_COMMESSE ? "CODCMS" : "CODCOSTO").as_string();
//operazioni da fare al cambio commessa/cdc (codice primo livello)
if (curr_codice != last_codice)
{
//SCRIVE UNA RIGA SUL FILE DA ESPORTARE
//lo schema <20> questo: budget\impegnato\maturato\fatturato\da impegnare\da maturare\da fatturare
//controlla se last_codice sia pieno per non aggiungere una inutile riga di zeri all'inizio
if (last_codice.full())
esporta_csv_row(file_to_date, first_level, last_codice, importi, importi_totali);
memset(importi, 0, sizeof(importi)); //Allah! Azzeratore dell'array con i totali per commessa (o cdc)
last_codice = curr_codice; //memorizza il cambio codice (cms/cdc)
//calcolatore dei saldi: va fatta attraverso i saldi!!! perch<63> i budget sono multianno
TImporto att, pas, ric, cos;
if (first_level == LF_CDC)
rendy.get_budget_export(curr_codice, codcms, codfas, att, pas, cos, ric);
else
rendy.get_budget_export(codcdc, curr_codice, codfas, att, pas, cos, ric);
//aggiunge i valori dei saldi all'array con gli importi; li mette nella colonna [0] che <20> quella dei budget..
//..e nella riga corrispondente all'indicatore bilancio
importi[1][0] = pas.valore();
importi[2][0] = att.valore();
importi[3][0] = cos.valore();
importi[4][0] = ric.valore();
}
//aggiorna tutti gli altri valori dell'array degli importi che non siano budget (cosa che fa solo a cambio codice)..
//..come si vede sopra
const bool hidden = rendy.get("HIDDEN").as_bool();
if (!hidden)
{
const real impegnato = rendy.get("IMPEGNATO").as_real();
const real fatturato = rendy.get("FATTURATO").as_real();
const real maturato = rendy.get("MATURATO").as_real();
//occhio all'inversione ricavi/costi, che causa il ribaltamento del significato di ordcont
int indbil = rendy.get("ORDCONT").as_int();
if (invert_cosric && (indbil == 3 || indbil == 4))
indbil = 7 - indbil;
//aggiornamento degli importi non budget di commessa/cdc
importi[indbil][1] += impegnato;
importi[indbil][2] += maturato;
importi[indbil][3] += fatturato;
}
} //for (bool ok = rendy.move_first()...
//gestione speciale dell'ultima riga
if (last_codice.full())
{
//SCRIVE L'ULTIMA RIGA RELATIVA A CMS/CDC SUL FILE DA ESPORTARE
esporta_csv_row(file_to_date, first_level, last_codice, importi, importi_totali);
//AGGIUNGE L'EVENTUALE RIGA DEI TOTALI
TToken_string str_tot = _msk->sfield(F_RIGHE).row(r);
//la riga con i totali ci va solo se non <20> stato specificato il primo livello (es. commessa o cdc)
const TFixed_string first_field = str_tot.get(0);
if (first_field.blank())
{
str_tot.replace('|', ' ');
str_tot.strip_double_spaces();
str_tot.insert("TOTALI\t");
//riga con gli importi totali;per ottenerla basta chiamare la esporta_csv_row con gli array invertiti, in modo che..
//..venga aggiornato l'array degli importi_totali; l'altro verr<72> sputtanato ma chi se ne frega! <20> gi<67> stato..
//..esportato qualche riga sopra
esporta_csv_row(file_to_date, first_level, str_tot, importi_totali, importi);
//doppia riga vuota di stacco
file_to_date << endl << endl;
}
} //if(last_codice.full())
}
//metodo per accattarsi o' primo livello della configurazione CA
const TMultilevel_code_info& TPrint_rendiconto_ca::get_first_level() const
{
const TString& first_lev = ca_config().get("Level", "ca", 1);
const int logic = first_lev == "CDC" ? LF_CDC : LF_COMMESSE;
return ca_multilevel_code_info(logic);
}
void TPrint_rendiconto_ca::main_loop()
{
_msk = new TPrint_rendiconto_ca_mask;
TPrint_rendiconto_ca_mask& mask = *_msk;
const int first_level = get_first_level().logic(); //primo livello nella configurazione CA
while (true)
{
//il programma deve cominciare l'eleaborazione solo nel caso di Stampa/Anteprima (K_ENTER) o Esportazione CSV (K_F6)
KEY key = mask.run();
if (key == K_QUIT)
break;
//chiave di ordinamento del recordset; di base <20> 1 (utilizzato per la stampa); va lasciata qui per essere resettata..
//..ad ogni giro, in modo da sistemarsi quando si passa da esportazione a stampa e viceversa!
int recset_key = 1;
//resetta e prepara le intestazioni del file rendiconto.xls
if (key == K_F6)
{
TFilename file_xls = mask.get(F_PATH);
file_xls.lower();
file_xls.add("rendiconto.xls");
ofstream file_to_date(file_xls);
const int posizione_importi = first_level == LF_COMMESSE ? 5 : 2;
//intestazione primaria
TToken_string intestazione_1(512, '\t');
//l'intestazione primaria dipende anche dalla configurazione dei livelli!
if (first_level == LF_COMMESSE) //commessa-cdc
{
intestazione_1.add("Commessa");
intestazione_1.add("Descr. commessa");
intestazione_1.add("Data inizio");
intestazione_1.add("Data fine");
intestazione_1.add("Data proroga");
recset_key = 2; //chiave del recordset per commessa
}
else //cdc-commessa
{
intestazione_1.add("C.d.C.");
intestazione_1.add("Descr. cdc");
recset_key = 3; //chiave del recordset per centro di costo
}
for (int i = 0; i < 4; i++)
{
switch (i)
{
case 0: intestazione_1.add("Costi"); break;
case 1: intestazione_1.add("Ricavi"); break;
case 2: intestazione_1.add("Attivit<EFBFBD>"); break;
case 3: intestazione_1.add("Passivit<EFBFBD>"); break;
}
for (int j = 0; j < 6; j++)
intestazione_1.add("");
}
file_to_date << intestazione_1 << endl;
//intestazione secondaria
TToken_string intestazione_2(512, '\t');
//campi descrittivi iniziali vuoti (solo intestazione_1)
intestazione_2.add(" ", posizione_importi - 1);
for (int l = 0; l < 4; l++)
{
for (int n = 0; n < 7; n++)
{
switch (n)
{
case 0: intestazione_2.add("Budget"); break;
case 1: intestazione_2.add("Impegnato"); break;
case 2: intestazione_2.add("Maturato"); break;
case 3: intestazione_2.add("Fatturato"); break;
case 4: intestazione_2.add("Da impegnare"); break;
case 5: intestazione_2.add("Da maturare"); break;
case 6: intestazione_2.add("Da fatturare"); break;
}
}
}
file_to_date << intestazione_2 << endl;
} //if(key==K_F6)
//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);
//log report con segnalazioni su errori (tipo conti inesistenti o robaccia simile..)
TLog_report log(TR("Errori rilevati"));
log.kill_duplicates();
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
//si amplia il range di ricerca temporale di 1 anno nel passato perch<63> i movana..
//..preventivi possono essere stati decisi prima dell'inizio effettivo commessa
TDate dataini, datafin;
const int anno = mask.get_int(F_ANNO);
if (anno > 0) //se non <20> stata specificata alcuna dataini, ma <20> stato specificato un anno di esercizio...
{
TEsercizi_contabili esc;
esc.code2range(anno, dataini, datafin);
}
if (!mask.field(F_DATAINI).empty())
dataini = mask.get_date(F_DATAINI);
if (!mask.field(F_DATAFIN).empty())
datafin = mask.get_date(F_DATAFIN);
const TMultilevel_code_info& liv1 = get_first_level(); //stabilisce quale <20> il primo livello (tra CDC e CMS)..
const bool is_cms = liv1.logic() == LF_COMMESSE;
TISAM_recordset set(is_cms ? "USE COMMESSE" : "USE CDC"); //..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!
{
if (!pi.addstatus(1))
break;
//Filtro sulle date
//DATE VALIDE STRETTAMENTE PER COMMESSE
//per prima cosa controlla se veramente la commessa rientri nei parametri temporali impostati sulla maschera
//Se infatti <20> completamente al di fuori di tale intervallo, che cavolo la controlla a fare
row = set.get((unsigned int)0).as_string(); //prende il valore del primo campo del file (CDC o CMS code)
if (is_cms && (dataini.ok() || datafin.ok()))
{
const TRectype& rec_commesse = set.cursor()->curr();
TDate datainicms, datafcomp;
ca_durata_commessa(rec_commesse, datainicms, datafcomp);
if ((dataini.ok() && datafcomp < dataini) || (datafin.ok() && datainicms > datafin))
continue;
}
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, recset_key, log); //fa la set filter sulla prima riga (che <20> quella usata)
//se stampa o anteprima..
if (key == K_F6)
esporta_csv((TPrint_rendiconto_ca_recordset&)*rep.recordset(), 0); //esportazione in excel
else
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, recset_key, log); //..chiama il metodone globale che crea e compila il file..
//..temporaneo i cui dati riempiranno il report
//se stampa o anteprima
if (key == K_F6) //esportazione in excel
esporta_csv((TPrint_rendiconto_ca_recordset&)*rep.recordset(), r); //il recordset <20> del tipo TPrint_rendiconto
else
book.add(rep); //aggiunge il report relativo alla cdc/cms corrente al book
}
}
//anteprima report degli errori rilevati
if (log.recordset()->items() > 0)
log.preview();
if (key == K_ENTER)
book.print(); //stampa il book dei report
else
book.preview(); //anteprima del book dei report
} //while(true)...
delete _msk;
_msk = NULL;
}
int ca3700(int argc, char* argv[])
{
TPrint_rendiconto_ca a;
a.run(argc, argv, TR("Stampa rendiconto"));
return 0;
}