campo-sirio/ps/pd6342300.cpp
alex 5a2a236544 Patch level : 10.0 no patch
Files correlati     :
Ricompilazione Demo : [ ]
Commento            :


Habilita


git-svn-id: svn://10.65.10.50/branches/R_10_00@21155 c028cbd2-c16b-5b4b-a496-9718f37d4682
2010-11-19 14:45:15 +00:00

525 lines
16 KiB
C++
Executable File
Raw Blame History

#include <applicat.h>
#include <automask.h>
#include <colors.h>
#include <defmask.h>
#include <progind.h>
#include <recarray.h>
#include <relation.h>
#include <textset.h>
#include "../cg/cglib01.h"
#include "../ca/calib01.h"
#include "../ca/calib02.h"
#include "pd6342.h"
#include "pd6342300a.h"
#include "../ca/movana.h"
#include "../ca/rmovana.h"
#include "../ca/rip.h"
#include "../ca/rrip.h"
//--------------------------------------------------------------------
// MASCHERA
//--------------------------------------------------------------------
class TRib_movanal_msk : public TAnal_report_mask
{
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
TRib_movanal_msk();
};
bool TRib_movanal_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case F_DATAINI:
case F_DATAFIN:
if (e == fe_close)
{
const int anno = get_int(F_ANNO);
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"));
}
break;
default:
break;
}
return TAnal_report_mask::on_field_event(o, e, jolly);
}
TRib_movanal_msk::TRib_movanal_msk() : TAnal_report_mask("pd6342300a")
{
}
class TCSV_recset : public TCSV_recordset
{
public:
// bool save_as_html(const char* path);
TCSV_recset(TAssoc_array & calc);
};
TCSV_recset::TCSV_recset(TAssoc_array & calc) : TCSV_recordset("CSV(;)\n")
{
set_separator(';');
TAssoc_array kcol;
TString_array rowkeys;
TString_array colkeys;
FOR_EACH_ASSOC_OBJECT(calc, obj, key, item)
{
rowkeys.add(key);
TAssoc_array * row = (TAssoc_array *) item;
FOR_EACH_ASSOC_OBJECT((*row), rowobj, colkey, rowitem)
kcol.add(colkey);
}
rowkeys.sort();
kcol.get_keys(colkeys);
colkeys.sort();
destroy_column();
const int ncols = colkeys.items();
const int nrows = rowkeys.items();
TString colname(20);
create_column("Key");
new_rec("");
for (int i= 1; i <= ncols; i++)
{
colname = colkeys.row(i - 1);
colname.replace(',', ' ');
colname.strip_double_spaces();
create_column(colname, _realfld);
set(i, colname);
}
for (int i= 0; i < nrows; i++)
{
new_rec("");
TString rowkey = rowkeys.row(i);
TAssoc_array * row = (TAssoc_array *) calc.objptr(rowkey);
rowkey.replace(',', ' ');
rowkey.strip_double_spaces();
set(0, rowkey);
if (row != NULL)
{
for (int j= 1; j <= ncols; j++)
{
const real * val = (const real *) row->objptr(colkeys.row(j - 1));
if (val != NULL)
set(j, *val);
}
}
}
}
//--------------------------------------------------------------------
// APPLICAZIONE
//--------------------------------------------------------------------
class TRib_movanal_app : public TSkeleton_application
{
TCache_ripartizioni _cache_rip;
bool _definitivo;
TAssoc_array _calc;
protected:
virtual const char * extra_modules() const {return "ca";}
virtual void main_loop();
bool elabora_righe(TAnal_mov& anal_mov, TRecord_array& input_rows);
bool ripartizione(const TAnal_ripartizioni_batch& rrip, const TRectype& rec, const TToken_string& path_item, TRecord_array& output_rows, TArray & output_paths);
bool pareggio(TAnal_mov& anal_mov, const TAnal_ripartizioni_batch& rrip, const TRectype& rec, const TToken_string& path, TRecord_array& output_rows, TArray & output_paths);
public:
bool elabora_movimento(TAnal_mov& anal_mov, const bool esplodi);
TRib_movanal_app(){}
};
bool TRib_movanal_app::pareggio(TAnal_mov& anal_mov, const TAnal_ripartizioni_batch& rrip, const TRectype& rec, const TToken_string& path,
TRecord_array& output_rows, TArray & output_paths)
{
bool ho_pareggiato = false;
TImporto totdoc(anal_mov.get_char(MOVANA_SEZIONE), anal_mov.get_real(MOVANA_TOTDOC));
const TImporto imp_riga(rec.get_char(RMOVANA_SEZIONE), rec.get_real(RMOVANA_IMPORTO));
totdoc -= imp_riga;
totdoc.normalize();
anal_mov.put(MOVANA_TOTDOC, totdoc.valore());
anal_mov.put(MOVANA_SEZIONE, totdoc.sezione());
//aggiunge la riga originale alle righe di output (e' un pareggio)
const int original_nriga = output_rows.rows() + 1;
TRectype* newrec = new TRectype(rec);
newrec->put(RMOVANA_NUMRIG, original_nriga);
output_rows.add_row(newrec);
//swappa la sezione e la manda al ripartitore in modo da generare righe con la sezione rovesciata rispetto a quella..
//..originale ed ottenere cosi' il pareggio
TRectype swaprec(rec);
swaprec.put(RMOVANA_SEZIONE, imp_riga.sezione() == 'D' ? 'A' : 'D');
ho_pareggiato = ripartizione(rrip, swaprec, path, output_rows, output_paths);
//elimina il codcontoori da tutte le righe aggiunte per il pareggio
for (int i = output_rows.rows(); i > original_nriga; i--)
output_rows.row(i, false).zero(RMOVANA_CODCONTORI);
return ho_pareggiato;
}
bool TRib_movanal_app::ripartizione(const TAnal_ripartizioni_batch& rrip, const TRectype& rec, const TToken_string& path_item, TRecord_array& output_rows, TArray & output_paths)
{
bool ho_ripartito = false;
// Importo totale da distribuire arrotondato ai decimali della valuta di conto
const real importo = rec.get_real(RMOVANA_IMPORTO);
const char sez = rec.get_char(RMOVANA_SEZIONE);
TGeneric_distrib distrib(importo, TCurrency::get_firm_dec());
TToken_string rowkey("", ',');
rowkey.add(rec.get(RMOVANA_CODCCOSTO));
rowkey.add(rec.get(RMOVANA_CODCMS));
rowkey.add(rec.get(RMOVANA_CODFASE));
TToken_string browkey = rowkey;
TAssoc_array * row = (TAssoc_array *)_calc.objptr(rowkey);
if (row == NULL)
_calc.add(rowkey, row = new TAssoc_array);
real * value = (real *) row->objptr(browkey);
if (value == NULL)
row->add(rowkey, value = new real);
*value = *value + (sez == 'D' ? importo : -importo);
browkey.add("+");
row = (TAssoc_array *)_calc.objptr(browkey);
if (row == NULL)
_calc.add(browkey, row = new TAssoc_array);
value = (real *) row->objptr(rowkey);
if (value == NULL)
row->add(rowkey, value = new real);
*value = *value + (sez == 'D' ? -importo : importo);
// Calcolo tutte le percentuali da ripartire
int i;
const int righe_ripartizione = rrip.rows();
for (i = 1; i <= rrip.rows(); i++)
{
const real importanza_riga = rrip[i].get_real(RRIP_RIPARTO);
distrib.add(importanza_riga);
}
for (i = 1; i <= righe_ripartizione; i++)
{
const real imp = distrib.get(); // Legge la quota da distribuire
if (imp != ZERO)
{
TRectype* newrec = new TRectype(rec);
//poi copia i valori dei campi cdc,cms,fsc,in quelli di tipo ori (nello stesso record)
if (rec.get(RMOVANA_CODCCORI).blank() && rec.get(RMOVANA_CODCMSORI).blank() &&
rec.get(RMOVANA_CODFASEORI).blank()) // RMOVANA_CODCONTORI <20> vuoto nel caso di pareggio
{
ca_copia_campo(rec, RMOVANA_CODCCOSTO, *newrec, RMOVANA_CODCCORI);
ca_copia_campo(rec, RMOVANA_CODCMS, *newrec, RMOVANA_CODCMSORI);
ca_copia_campo(rec, RMOVANA_CODFASE, *newrec, RMOVANA_CODFASEORI);
ca_copia_campo(rec, RMOVANA_CODCONTO, *newrec, RMOVANA_CODCONTORI);
}
else
{
ca_copia_campo(rec, RMOVANA_CODCCORI, *newrec, RMOVANA_CODCCORI);
ca_copia_campo(rec, RMOVANA_CODCCORI, *newrec, RMOVANA_CODCMSORI);
ca_copia_campo(rec, RMOVANA_CODCCORI, *newrec, RMOVANA_CODFASEORI);
ca_copia_campo(rec, RMOVANA_CODCCORI, *newrec, RMOVANA_CODCONTORI);
}
//e mette nei campi std i valori che trova nelle righe ripartizione
ca_copia_campo(rrip[i], RRIP_CODCOSTO, *newrec, RMOVANA_CODCCOSTO);
ca_copia_campo(rrip[i], RRIP_CODCMS, *newrec, RMOVANA_CODCMS);
ca_copia_campo(rrip[i], RRIP_CODFASE, *newrec, RMOVANA_CODFASE);
ca_copia_campo(rrip[i], RRIP_CODCONTO, *newrec, RMOVANA_CODCONTO);
TToken_string ripkey("", ',');
ripkey.add(newrec->get(RMOVANA_CODCCOSTO));
ripkey.add(newrec->get(RMOVANA_CODCMS));
ripkey.add(newrec->get(RMOVANA_CODFASE));
// ripkey.add(newrec->get(RMOVANA_CODCONTO));
const int rows = output_rows.rows();
int r = -1;
for (int j = 1; r < 0 && j <= rows; j++)
if (ca_can_pack_rows(*newrec, output_rows[j]))
r = j;
if (r < 0)
{
newrec->put(RMOVANA_NUMRIG, rows + 1);
newrec->put(RMOVANA_IMPORTO, imp); //e la mette nella nuova riga
output_rows.add_row(newrec);
TToken_string * rowpath = (TToken_string *) output_paths.objptr(r);
if (rowpath == NULL)
output_paths.add(rowpath = new TToken_string, r);
rowpath->add(path_item);
}
else
{
output_rows[r].add(RMOVANA_IMPORTO, imp);
}
real * value = (real *) row->objptr(ripkey);
if (value == NULL)
row->add(ripkey, value = new real);
*value = *value + (sez == 'D' ? imp : -imp);
ho_ripartito = true;
} //if(imp!=ZERO)...
} //for(i=1;i<=righe_ripartizione...
return ho_ripartito;
}
bool TRib_movanal_app::elabora_righe(TAnal_mov& anal_mov, TRecord_array& input_rows)
{
bool ho_cambiato_qualchecosa = false;
const int annoes = anal_mov.get_int(MOVANA_ANNOES);
const char tipomov = anal_mov.get_char(MOVANA_TIPOMOV);
TRecord_array output_rows = input_rows; output_rows.destroy_rows();
TArray input_paths;
TArray output_paths;
int loop = 0;
while (loop++ < 20)
{
bool modified = false;
const int nrows = input_rows.rows();
for (int r = 1; r <= nrows; r++)
{
const TRectype& rec = input_rows.row(r);
TAnal_bill zio(rec);
const int rmovana_indbil = zio.indicatore_bilancio();
//ripartizione batch: passa il conto perche' per prima cosa provera' una ripartizione di tipo 'P' con chiave 3; se non..
//..ci riuscira', provera' da solo (metodi della TCache_ripartizioni) le ripartizioni di tipo 'B' con chiave 4.
const TAnal_ripartizioni_batch& rrip = _cache_rip.righe(zio, annoes, rmovana_indbil, tipomov);
if (input_paths.objptr(r) == NULL)
input_paths.add(new TToken_string, r);
TToken_string & input_path = (TToken_string &) input_paths[r];
const char tiporip = rrip.tiporip();
//ci sono righe di ripartizione
const int righe_ripartizione = rrip.rows();
bool ripartisci = righe_ripartizione > 0;
//se ci sono righe di ripartizione/pareggio si va a ripartire!
TToken_string path_item("", ',');
path_item.add(rec.get(RMOVANA_CODCCOSTO));
path_item.add(rec.get(RMOVANA_CODCMS));
path_item.add(rec.get(RMOVANA_CODFASE));
path_item.add(rec.get(RMOVANA_CODCONTO));
if (ripartisci)
ripartisci = input_path.find(path_item) < 0;
input_path.add(path_item);
if (ripartisci)
{
if (input_rows.rows() + righe_ripartizione > 999)
break;
switch (tiporip)
{
//procedura di ripartizione batch 'B' originale; se tiporip=='P' invece ci vuole il pareggio del movana
case 'B':
modified |= ripartizione(rrip, rec, path_item, output_rows, output_paths);
break;
case 'P':
modified |= pareggio(anal_mov, rrip, rec, input_path, output_rows, output_paths);
break;
default:
break;
}
}
else //if(ripartisci... nessuna riga di ripartizione->aggiungo la riga input all'output
{
TRectype* newrec = new TRectype(rec);
newrec->put(RMOVANA_NUMRIG, output_rows.rows() + 1);
output_rows.add_row(newrec);
}
} //for(int r=1; r<=nrows...
if (modified && input_rows.rows() != output_rows.rows())
{
ho_cambiato_qualchecosa = true;
input_rows = output_rows;
input_paths = output_paths;
output_rows.destroy_rows();
output_paths.destroy();
}
else
break;
}
return ho_cambiato_qualchecosa;
}
bool TRib_movanal_app::elabora_movimento(TAnal_mov& anal_mov, const bool esplodi)
{
TRecord_array& input_rows = anal_mov.body(); //record_array con le righe del mov_anal (INPUT)
bool do_rewrite = false;
//Per prima cosa prende le righe del movimento su RMOVANA e le ricompatta..
if(anal_mov.get_long(MOVANA_NUMREG) == 358L)
int i = 1;
if (esplodi)
{
//Imploditore
//..poi lo riesplode in tutte le righe che possono nascere secondo le regole delle ripartizioni!
//Esploditore
do_rewrite = elabora_righe(anal_mov, input_rows);
if (_definitivo) //se l'elaborazione e' definitiva...
{
anal_mov.put(MOVANA_BLOCCATO, 'X'); //..mette bloccato = X nella testata del movimento
do_rewrite = true;
}
}
else
{
//Imploditore
TRecord_array compact_rows = input_rows; //record array con le righe compattate da creare con la..
compact_rows.destroy_rows(); //..implode_rows(); intanto le azzera per sicurezza
do_rewrite = ca_implode_rows(input_rows, compact_rows);
for (int r = 1; r <= compact_rows.rows(); r++)
{
TRectype& rec = compact_rows[r];
rec.zero(RMOVANA_CODCCORI);
rec.zero(RMOVANA_CODCMSORI);
rec.zero(RMOVANA_CODFASEORI);
rec.zero(RMOVANA_CODCONTORI);
}
if (do_rewrite)
{
input_rows = compact_rows; // rimette i record compattati negli originali
anal_mov.update_totdoc(); //aggiorna il totale movana (necessarip per ripartizioni a pareggio, di sicurezza per le altre)
}
}
return do_rewrite; //se ha elaborato delle righe e/o e' una elaborazione definitiva, riscrive la..
}
static bool ripartisci_callback(const TRelation& rel, void* pJolly)
{
TRib_movanal_app& app = *(TRib_movanal_app*)pJolly;
const long numreg = rel.curr().get_long(MOVANA_NUMREG);
TAnal_mov anal_mov(numreg);
//se va tutto bene riscrive l'intero movimento analitico con conseguente ricalcolo saldi
app.elabora_movimento(anal_mov, false);
if (app.elabora_movimento(anal_mov, true))
anal_mov.rewrite(rel.lfile());
return true;
}
static bool compatta_callback(const TRelation& rel, void* pJolly)
{
TRib_movanal_app& app = *(TRib_movanal_app*)pJolly;
const long numreg = rel.curr().get_long(MOVANA_NUMREG);
TAnal_mov anal_mov(numreg);
//se va tutto bene riscrive l'intero movimento analitico con conseguente ricalcolo saldi
if (app.elabora_movimento(anal_mov, false))
anal_mov.rewrite(rel.lfile());
return true;
}
void TRib_movanal_app::main_loop()
{
TRib_movanal_msk mask;
while (mask.run() == K_ENTER)
{
//deve scandire il file MOVANA con chiave 2 (per data e numero di registrazione)
TRelation rel_movana(LF_MOVANA);
TRectype darec(LF_MOVANA), arec(LF_MOVANA);
const TDate & dal = mask.get_date(F_DATAINI);
darec.put(MOVANA_DATACOMP, dal);
const TDate & al = mask.get_date(F_DATAFIN);
arec.put(MOVANA_DATACOMP, al);
_cache_rip.set_esercizio(mask.get_int(F_ANNO));
const TString & tipo = mask.get(F_CLASSEMOV);
TString filter;
if (tipo.blank())
filter = "BLOCCATO!=\"X\"";
else
if (tipo == "N")
filter = "(BLOCCATO!=\"X\")&&(TIPOMOV==\"\")";
else
filter = "(BLOCCATO!=\"X\")&&(TIPOMOV!=\"\")";
TCursor cur_movana(&rel_movana, filter, 2, &darec, &arec);
const long items = cur_movana.items();
if (items > 0)
{
bool run = yesno_box(FR("Si desidera elaborare %ld movimenti?"), items);
//e' una compattazione?
const bool compattazione = mask.get_bool(F_COMPATTA);
//se e' un ripartizione potrebbe essere definitiva!
if (!compattazione)
{
// avvisa l'utente scapestrato che se fa una ripartizione definitiva
// blocchera' i movimenti che processa e non potra' piu' tornare indietro
_definitivo = mask.get_bool(F_DEFINITIVO);
if (run && _definitivo)
run = yesno_box(TR("E' stata selezionata l'elaborazione definitiva\nSi desidera proseguire?"));
}
//Presa la decisione si parte! Tenetevi forte...
if (run)
{
if (compattazione)
cur_movana.scan(compatta_callback, this, TR("Compattamento movimenti..."));
else
cur_movana.scan(ripartisci_callback, this, TR("Ripartizione movimenti..."));
TFilename fname(mask.get(F_PATH));
fname.add(mask.get(F_NAME));
if (fname.full())
{
TCSV_recset recset(_calc);
recset.save_as(fname, fmt_unknown);
}
} //if(run)...
}
else
message_box(TR("Non ci sono movimenti da elaborare nel periodo selezionato"));
}
}
int pd6342300(int argc, char* argv[])
{
TRib_movanal_app app;
app.run(argc, argv, TR("Ripartizione movimenti di analitica (Habilita)"));
return 0;
}