campo-sirio/src/ca/ca3600.cpp
Alessandro Bonazzi 21f20739ad Patch level : 12.0 1100
Files correlati     : f151.dir f151.trr ca1.exe ca2.exe ca3.exe ca3100.uml
                      ca3100a.rep ca3100b.rep ca3200.uml ca3200a.rep
                      ca3200b.rep ca3300.uml ca3300a.rep ca3300b.rep
                      ca3300c.rep ca3300d.rep ca3600.uml ca3600a.rep
                      ca3700.uml ca3700a.rep ca3700b.rep ca3800.uml
                      ca3800a.rep ca3800as.rep ca3800b.rep ca3800bs.rep
                      ca3800c.rep ca3800cs.rep ca3883.cpp ca3900.uml
                      ca3900a.rep
Commento :

Aggiunta contabilità separata alle stampe di analitica.
Aggiunto meccanismo per lanciare le stampe in batch.
Sintassi: ca3 -7 -b <nome del file che contiene i valori dell maschera> <tipo di output <P>rint|<E>xport|E<X>cel|PD<F>|<T>esto|<D>Base|<V>isualizza> <nome del file di output

Esempio: ca3 -7 -b select.sav X c:\out\rend

esporta il rendiconto di commessa usando i parametri salvati in select.sav nel file c:\out\rend.xls
2021-12-13 23:17:33 +01:00

1247 lines
41 KiB
C++
Executable File
Raw Blame History

#include <applicat.h>
#include <defmask.h>
#include <execp.h>
#include <progind.h>
#include <recarray.h>
#include <repapp.h>
#include <clifo.h>
#include <mov.h>
#include <partite.h>
#include <rmov.h>
#include <rmoviva.h>
#include "..\cg\cgsaldac.h"
#include "..\cg\cglib.h"
#include "pconana.h"
#include "commesse.h"
#include "cdc.h"
#include "fasi.h"
#include "movana.h"
#include "rmovana.h"
#include "ca3.h"
#include "ca3600.h"
#include "calib01.h"
#include "calib02.h"
#include "camask.h"
//===============================================================================================
////////////////////////////////////////////////////////
// MASCHERA
////////////////////////////////////////////////////////
class TPag_per_cms_mask: public TAnal_report_mask
{
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
void config_loader(TSheet_field& sf, const char* paragrafo);
void config_setter(TSheet_field& sf, const char* paragrafo);
public:
TPag_per_cms_mask();
virtual ~TPag_per_cms_mask() {}
};
bool TPag_per_cms_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case DLG_SAVEREC:
if (e == fe_button)
{
config_setter(sfield(F_PDCC), "Pdcc");
// config_setter(sfield(F_PDCA), "Pdca"); ***per ora solo Pdcc***
}
break;
default:
break;
}
return TAnal_report_mask::on_field_event(o, e, jolly);
}
TPag_per_cms_mask::TPag_per_cms_mask()
:TAnal_report_mask("ca3600")
{
//Prima pagina
// creazione dei campi della pagina della maschera con lo sheet di cdc/cms/fasi
create_sheet(F_RIGHE);
//carica i parametri dei conti per lo sheet dei conti contabili
config_loader(sfield(F_PDCC), "Pdcc");
// 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();
}
void TPag_per_cms_mask::config_loader(TSheet_field& sf, const char* paragrafo)
{
TFilename configname = "ca3600a.ini"; //carica file configurazione conti
configname.custom_path();
TConfig configfile(configname, paragrafo);
TString_array conti;
configfile.list_variables(conti, false, paragrafo, true);
FOR_EACH_ARRAY_ROW(conti, i, row)
{
sf.row(-1) = configfile.get(*row); //carica la riga del .ini senza il contatore
sf.check_row(i);
}
}
void TPag_per_cms_mask::config_setter(TSheet_field& sf, const char* paragrafo)
{
TFilename configname = "ca3600a.ini"; //carica file configurazione conti
configname.custom_path();
TConfig configfile(configname, paragrafo);
configfile.remove_all(); //svuota il paragrafo sul .ini prima di ricompilarlo (se non si facesse
//non si riuscirebbero ad ammazzare le righe sul .ini
FOR_EACH_SHEET_ROW (sf, i, row)
{
TToken_string conto("");
conto.add(row->get(0));
conto.add(row->get(1));
conto.add(row->get(2));
conto.add(row->get(3)); //*****nel caso di pdca deve tener conto dei livelli variabili
configfile.set("conto", conto, NULL, true, i);
}
}
///////////////////////////////////////////////////////////////
// RECORDSET
///////////////////////////////////////////////////////////////
class TPag_per_cms_recordset : public TISAM_recordset
{
TExternisamfile* _tmp;
protected:
TDate _dadata, _adata;
long _dacodfor, _acodfor;
TString16 _campodata;
TString _codcosto, _codcms, _codfas, _contsep;
TAssoc_array _costi,_pagamenti,_fiscali,_sociali; //array che contengono i conti letti dal .ini
protected: //da libreria
virtual const TVariant& get(const char* column_name) const;
protected:
void crea_trr(const TFilename& trr) const;
static bool part_callback(const TRelation& rel, void* pJolly);
static bool mov_callback(const TRelation& rel, void* pJolly);
long find_movimento(const TRectype& riga_pag) const;
void find_commesse(const long nreg, const TRectype& riga_pag);
void find_commesse_cg(const TRectype& mov);
bool check_cms_cdc_fsc(const TRectype& rec_analriga);
const TString& query_movama_by_numregcg(const long nreg);
void lettura_conti(TAssoc_array& assoc, const char tipoconto);
int cerca_riga_fattura_origine(const TPartita& match, const TRectype& riga_pag);
real totale_documento(const TRectype& mov) const;
real calcola_pagato_prec(const TPartita& match, const int riga_fatt, const TRectype& riga_pag);
bool test_swap(TCausale& caus, bool ritsoc) const;
bool cerca_conto(const char tipo, const TBill& bill, const TAssoc_array& assoc) const;
int cerca_costo(const TBill& bill) const;
int cerca_pagamento(const TBill& bill) const;
bool cerca_fiscali(const TBill& bill) const;
bool cerca_sociali(const TBill& bill) const;
public:
virtual void set_filter(const TPag_per_cms_mask& msk, const int cms_row, const long dacodfor, const long acodfor, const TString& campodata);
virtual void set_custom_filter(TCursor& cur) const;
void scan_pags();
void scan_movs();
TPag_per_cms_recordset(const TString& sql) : TISAM_recordset(sql) { _tmp = NULL;}
~TPag_per_cms_recordset();
};
//////////////////////////////////
// generica
//////////////////////////////////
static TPag_per_cms_recordset* myself = NULL;
TPag_per_cms_recordset::~TPag_per_cms_recordset()
{ }
void TPag_per_cms_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();
//filtro sulla data(non avendo anche codnum non ho la chiave completa per mettere la data nella setregion)
TString filtro;
TString80 f;
if (_dadata.ok())
{
f.format("(ANSI(%s)>=\"%s\")", (const char*)_campodata, _dadata.string(ANSI));
filtro << f;
}
if (_adata.ok())
{
if (filtro.not_empty())
filtro << "&&";
f.format("(ANSI(%s)<=\"%s\")", (const char*)_campodata, _adata.string(ANSI));
filtro << f;
}
cur.setregion(darec, arec);
cur.setfilter(filtro);
myself = (TPag_per_cms_recordset*)this;
}
//simpatico metodo per riempire in automatico i campi di intestazione speciali
const TVariant& TPag_per_cms_recordset::get(const char* column_name) const
{
if (*column_name == '#')
{
if (strcmp(column_name, "#COSTO") == 0)
return get_tmp_var() = _codcosto;
else
if (strcmp(column_name, "#COMMESSA") == 0)
return get_tmp_var() = _codcms;
else
if (strcmp(column_name, "#FASE") == 0)
return get_tmp_var() = _codfas;
else
if (strcmp(column_name, "#CONTSEP") == 0)
return get_tmp_var() = _contsep;
}
return TISAM_recordset::get(column_name);
}
void TPag_per_cms_recordset::crea_trr(const TFilename& trr) const
{
TString chiave;
ofstream of(trr);
of << 1000 << endl;
of << 16 << endl;
of << "CODFORN|3|6|0|Codice fornitore" << endl;
of << "DESFORN|1|50|0|Descrizione fornitore" << endl;
of << "NREG|3|7|0|Numero registrazione" << endl;
of << "DATAREG|5|8|0|Data registrazione" << endl;
of << "DATAPAG|5|8|0|Data pagamento" << endl;
of << "DESCRPAG|1|50|0|Descrizione pagamento" << endl;
of << "NDOC|1|6|0|Numero documento" << endl;
of << "DATADOC|5|8|0|Data documento" << endl;
of << "PROT|2|5|0|Protocollo iva" << endl;
of << "TOTDOC|4|18|5|Totale documento" << endl;
of << "TOTPAG|4|18|5|Totale pagamento" << endl;
of << "TOTRES|4|18|5|Totale residuo" << endl;
of << "CDC|1|20|0|Centro di costo" << endl;
of << "CMS|1|20|0|Commessa" << endl;
of << "FSC|1|10|0|Fase" << endl;
of << "HIDDEN|8|1|0|Record nascosto" << endl;
of << 1 << endl;
//l'ordinamento dipende dal tipo di data selezionato sulla maschera
chiave << "CODFORN+FSC+NREG+";
chiave << _campodata;
of << chiave << endl;
}
void TPag_per_cms_recordset::lettura_conti(TAssoc_array& assoc, const char tipoconto)
{
TConfig conti("ca3600a.ini","Pdcc"); //paragrafo da scandire nell'ini (solo conti contabili!!)
TAssoc_array& vars = conti.list_variables();
FOR_EACH_ASSOC_STRING(vars, h, k, val) //riempie l'assoc con i soli valori del paragrafo dell'ini
{
if (*val == tipoconto) //mette nell'assocarray solo i conti corrispondenti al tipoconto passato
assoc.add(val);
}
}
bool TPag_per_cms_recordset::cerca_conto(const char tipo, const TBill& bill, const TAssoc_array& assoc) const
{
TToken_string key(15);
key.add(tipo);
key.add(bill.gruppo());
if (assoc.is_key(key))
return true;
key.add(bill.conto());
if (assoc.is_key(key))
return true;
key.add(bill.sottoconto());
if (assoc.is_key(key))
return true;
return false;
}
int TPag_per_cms_recordset::cerca_costo(const TBill& bill) const
{
if (cerca_conto('C', bill, _costi))
return 1;
else
return 0;
}
int TPag_per_cms_recordset::cerca_pagamento(const TBill& bill) const
{
if (cerca_conto('P', bill, _pagamenti))
return 2;
else
return 0;
}
bool TPag_per_cms_recordset::cerca_fiscali(const TBill& bill) const
{
return cerca_conto('F', bill, _fiscali);
}
bool TPag_per_cms_recordset::cerca_sociali(const TBill& bill) const
{
return cerca_conto('S', bill, _sociali);
}
// Controlla sulla causale se il segno del totale documento (ritsoc=FALSE)
// o quello delle ritenute sociali (ritsoc=TRUE) e' invertito rispetto al normale
bool TPag_per_cms_recordset::test_swap(TCausale& caus, bool ritsoc) const
{
const char sez = ritsoc ? caus.sezione_ritsoc() : caus.sezione_clifo();
const bool s = (caus.iva() == iva_vendite) ^ (sez == 'D');
return s;
}
// Calcola il totale del documento tenendo conto del segno della prima riga e di quella delle
// ritenute sociali sulla causale
real TPag_per_cms_recordset::totale_documento(const TRectype& mov) const
{
real tot = mov.get_real(MOV_TOTDOC); // Legge totale
const real ritfis = mov.get_real(MOV_RITFIS);
tot += ritfis; // Somma ritenute fiscali
const real ritsoc = mov.get_real(MOV_RITSOC);
if (!ritsoc.is_zero())
{
TCausale caus(mov.get(MOV_CODCAUS));
const bool swapt = test_swap(caus, false); // Totale invertito ?
const bool swaps = test_swap(caus, true); // Ritenute sociali invertite ?
if (swapt ^ swaps) // Somma ritenute sociali con segno
tot -= ritsoc;
else
tot += ritsoc;
}
return tot;
}
int TPag_per_cms_recordset::cerca_riga_fattura_origine(const TPartita& match, const TRectype& riga_pag)
{
//scansione delle righe partita passata, precedenti alla riga_pag
const int k = riga_pag.get_int(PART_NRIGA);
for (int i = match.pred(k); i > 0; i = match.pred(i))
{
const TRiga_partite& riga_part = match.riga(i);
if (riga_part.is_fattura())
{
for (int j = riga_part.rate(); j > 0; j--)
{
if (match.esiste(i, j, k)) //se esiste il pagamento k della rata j della riga partita i contenente la fattura
return i;
}
}
}
return 0;
}
real TPag_per_cms_recordset::calcola_pagato_prec(const TPartita& match, const int riga_fatt, const TRectype& riga_pag)
{
real pagato = ZERO;
if (riga_fatt > 0)
{
const int k = riga_pag.get_int(PART_NRIGA);
const TDate data_rif = riga_pag.get(_campodata); //data di riferimento selezionata sulla maschera
const TRiga_partite& riga_part = match.riga(riga_fatt);
for (int i = riga_part.rate(); i > 0; i--)
{
TRiga_scadenze& sc = riga_part.rata(i);
for (int j = sc.last(); j > 0; j = sc.pred(j))
{
const TRiga_partite& pag = match.riga(j);
const TDate datapag = pag.get_date(_campodata);
const long cmp = datapag - data_rif;
//la riga pagamento e' da considerare quando ha data anteriore a quella di riferimento oppur
//ha data uguale ma numero di registrazione inferiore (insomma, il pagamento e' precedente
//a quello di riga_pag)
if (cmp < 0 || (cmp == 0 && j <= k))
{
pagato += pag.get_real(PAGSCA_IMPORTO);
}
}
}
}
return pagato;
}
/////////////////////////////////////
// movimenti senza saldaconto
/////////////////////////////////////
long TPag_per_cms_recordset::find_movimento(const TRectype& riga_pag) const
{
int n_fatture = 0; //numero di fatture trovate
int first_fatt = 0; //numero riga della prima fattura
//scan della partita dall'ultima alla prima riga
const TPartita partita(riga_pag);
for (int p = partita.last(); p > 0; p = partita.pred(p))
{
const TRiga_partite& fatt = partita.riga(p);
if (fatt.is_fattura())
{
n_fatture++;
first_fatt = p;
}
}
if (n_fatture > 1)
{
const int linea_pag = riga_pag.get_int(PART_NRIGA);
int linea_fattura = 0;
for (int f = first_fatt; (f > 0) && (f <= partita.last()) && (linea_fattura == 0); f = partita.succ(f))
{
const TRiga_partite& fatt = partita.riga(f);
if (fatt.is_fattura())
{
for (int r = 1; r <= fatt.rate(); r++)
{
const TRiga_scadenze& rata = fatt.rata(r);
if (rata.exist(linea_pag))
{
linea_fattura = f;
break;
}
}
}
}
if (linea_fattura > 0) // oppure anche (linea_fattura > first_fatt)
first_fatt = linea_fattura;
}
long nreg = 0;
if (first_fatt > 0)
{
const TRiga_partite& fatt = partita.riga(first_fatt);
nreg = fatt.get_long(PART_NREG);
}
return nreg;
}
//prepara gli oggetti (_righecosti,_righepagamenti) contenenti le righe dei pagamenti..
//..senza saldaconto
void TPag_per_cms_recordset::find_commesse_cg(const TRectype& mov)
{
const long numregcg = mov.get_long(MOV_NUMREG);
//cerca un record di MOVANA che abbia numregcg = nreg;usa il nuovo metodo fighissimo..
//..con la isam query implementato nella query_movama_by_numregcg()
TISAM_recordset movana(query_movama_by_numregcg(numregcg));
const TRecnotype items = movana.items();
if (items > 0)
{
if (items > 1)
error_box(TR("Esiste piu' di un movimento analitico collegato al movimento contabile %ld"),numregcg);
movana.move_last(); //si posiziona sul record corretto
//prepara il record tmpcurr sul file temporaneo _tmp su cui registrare i dati da stampare
TRectype& tmpcurr = _tmp->curr();
tmpcurr.zero();
//crea il movana legato al mov
const TAnal_mov anal_mov(mov);
const TRecord_array& anal_rows = anal_mov.body();
for (int j = 1; j <= anal_rows.rows(); j++) //scansiona righe analitiche..
{
const TRectype& anal_row = anal_rows[j];
if (check_cms_cdc_fsc(anal_row))
{
//prende il conto sulla riga analitica e lo confronta con quelli della configurazione
const TString& conto_riga_analitica = anal_row.get(RMOVANA_CODCONTO);
const int gruppo_anal = atoi(conto_riga_analitica.left(3));
const int conto_anal = atoi(conto_riga_analitica.mid(3,3));
const long sottoconto_anal = atol(conto_riga_analitica.mid(6,6));
const TBill conto(gruppo_anal, conto_anal, sottoconto_anal);
int tipo = cerca_costo(conto) || cerca_pagamento(conto);
if (tipo > 0)
{
const char sezione = anal_row.get_char(RMOVANA_SEZIONE);
const real valore = anal_row.get_real(RMOVANA_IMPORTO);
TImporto imp(sezione, valore);
switch (tipo)
{
case 1:imp.normalize('D');break;
case 2:imp.normalize('A');break;
//case 3:imp.normalize('D');break;
//case 4:imp.normalize('A');break;
default:break;
}
//deve aggiungere ora al file temporaneo il record
//codice fornitore e descrizione
const long codforn = mov.get_long(MOV_CODCF);
if (codforn > 0)
{
tmpcurr.put("CODFORN", codforn);
TString16 keyclifo;
keyclifo.format("F|%ld", codforn);
const TRectype& rec_clifo = cache().get(LF_CLIFO, keyclifo);
tmpcurr.put("DESFORN", rec_clifo.get(CLI_RAGSOC));
}
//nreg,data pagamento,descrizione pagamento
tmpcurr.put("NREG", numregcg);
tmpcurr.put("DATAREG", mov.get_date(MOV_DATAREG));
tmpcurr.put("DATAPAG", mov.get_date(MOV_DATACOMP));
//documento origine
tmpcurr.put("NDOC", mov.get_long(MOV_NUMDOC));
tmpcurr.put("DATADOC", movana.get(MOV_DATADOC).as_date());
tmpcurr.put("TOTDOC", movana.get(MOV_TOTDOC).as_real());
//importi
tmpcurr.put("TOTPAG", imp.valore());
//tmpcurr.put("TOTRES", ); //pagamenti precedenti al
//campi relativi a cdc,commessa,fase
tmpcurr.put("CMS",anal_row.get(RMOVANA_CODCMS));
tmpcurr.put("CDC",anal_row.get(RMOVANA_CODCCOSTO));
tmpcurr.put("FSC",anal_row.get(RMOVANA_CODFASE));
//e finalmente aggiunge il record al file temporaneo
_tmp->write();
}
}
} //for(j<anal_rows...
} //if(items>0...
}
bool TPag_per_cms_recordset::mov_callback(const TRelation& rel, void* pJolly)
{
TPag_per_cms_recordset* recordset = (TPag_per_cms_recordset*)pJolly;
recordset->find_commesse_cg(rel.curr());
return true;
}
void TPag_per_cms_recordset::scan_movs()
{
if (_campodata == PART_DATAPAG) // I movimenti non hanno DATAPAG
_campodata = MOV_DATAREG;
TString filtro = "(REG==\"\")&&(TIPOMOV==\"\")";
TRectype darec(LF_MOV), arec(LF_MOV);
if (_campodata == MOV_DATAREG)
{
if (_dadata.ok())
darec.put(MOV_DATAREG, _dadata);
if (_adata.ok())
arec.put(MOV_DATAREG, _adata);
}
else
{
TString80 f;
if (_dadata.ok())
{
f.format("&&(ANSI(%s)>=\"%s\")", (const char*)_campodata, _dadata.string(ANSI));
filtro << f;
}
if (_adata.ok())
{
f.format("&&(ANSI(%s)<=\"%s\")", (const char*)_campodata, _adata.string(ANSI));
filtro << f;
}
}
TRelation rel(LF_MOV);
TCursor cur(&rel, filtro, 2, &darec, &arec);
cur.scan(mov_callback, this, "Movimenti senza saldaconto...");
}
bool TPag_per_cms_recordset::check_cms_cdc_fsc(const TRectype& rec_analriga)
{
if (_codcosto.not_empty() && _codcosto != rec_analriga.get(RMOVANA_CODCCOSTO))
return false;
if (_codcms.not_empty() && _codcms != rec_analriga.get(RMOVANA_CODCMS))
return false;
if (_codfas.not_empty() && _codfas != rec_analriga.get(RMOVANA_CODFASE))
return false;
if (_contsep.not_empty())
{
const TRectype & movana = cache().get(LF_MOVANA, rec_analriga.get_long(RMOVANA_NUMREG));
if (_contsep != movana.get(MOVANA_CONTSEP))
return false;
}
return true;
}
//////////////////////////////////////
// movimenti con saldaconto
//////////////////////////////////////
const TString& TPag_per_cms_recordset::query_movama_by_numregcg(const long nreg)
{
TString& query = get_tmp_string();
query << "USE MOVANA KEY 3\n";
query << "FROM NUMREGCG=" << nreg << "\n";
query << "TO NUMREGCG=" << nreg;
return query;
}
//prepara l'assoc con tutte le righe da mandare in stampa per quanto riguarda i movimenti con
//saldaconto (siano essi con o senza iva)
void TPag_per_cms_recordset::find_commesse(const long nreg, const TRectype& riga_pag)
{
//cerca un record di MOVANA che abbia numregcg = nreg;usa il nuovo metodo fighissimo..
//..con la isam query implementato nella query_movama_by_numregcg()
TISAM_recordset movana(query_movama_by_numregcg(nreg));
const TRecnotype items = movana.items();
if (items <= 0)
return;
if (items > 1)
warning_box(TR("Esiste piu' di un movimento analitico collegato al movimento contabile %ld"),nreg);
movana.move_last(); //si posiziona sul record corretto
//crea il movana e le sue righe
const TAnal_mov anal_mov(movana.get(MOVANA_NUMREG).as_int());
TRecord_array& anal_rows = anal_mov.body();
//scandisce le righe del movana alla ricerca di righe compatibili con le commesse sullo sheet
int m;
for (m = anal_rows.last_row(); m > 0; m--)
{
if (check_cms_cdc_fsc(anal_rows[m]))
break;
}
//se non ne ha trovata manco una di righe buone esce!
if (m <= 0)
return;
//prepara il record tmpcurr sul file temporaneo _tmp su cui registrare i dati da stampare
TRectype& tmpcurr = _tmp->curr();
tmpcurr.zero();
//crea un movimento p.n. con il numero reg che viene passato al metodo (nreg relativo..
//..ad un movimento della fattura originaria)
TMovimentoPN pn;
pn.curr().put(MOV_NUMREG, nreg);
if (pn.read() == NOERR)
{
const TRectype& movfat = pn.curr();
real totdoc_cms;
real totdoc, totdoc_netto;
TAssoc_array commesse;
//Movimenti CON SALDACONTO
//se movimento IVA..
if (pn.iva_items() > 0)
{
//trova le RMOVANA del MOVANA corrente che hanno il conto = a quello della i-esima rigaiva
for (int j = 0; j < pn.iva_items(); j++)
{
const TRectype& rmoviva = pn.iva(j);
const TBill zio(rmoviva);
//il tutto si fa solo se l'indicatore di bilancio del conto nella riga iva e' != 5
if (zio.indicatore_bilancio() != 5)
{
//e vediamo 'sto conto della riga iva..
const int gruppo_iva = zio.gruppo();
const int conto_iva = zio.conto();
const long sottoconto_iva = zio.sottoconto();
real imponibile_iva = rmoviva.get_real(RMI_IMPONIBILE);
real imposta_iva = rmoviva.get_real(RMI_IMPOSTA);
const TString& tipodet = rmoviva.get(RMI_TIPODET);
//controlla se l'imposta va sommata (tipo detrazione iva non nulla)
if (tipodet.full())
imponibile_iva += imposta_iva;
//distributore per il lordo iva (che sara' distribuito successivamente in base..
//..agli importi delle righe analitiche corretti per le % iva
TGeneric_distrib agip (imponibile_iva, TCurrency::get_firm_dec());
for (int k = 1; k <= anal_rows.rows(); k++) //scansiona righe analitiche..
{
real perc_ded_iva = UNO; //%iva deducibile (di default 100, a meno del prorata)
if (imposta_iva != ZERO)
{
//controllo prorata
const TString80 commessa_riga_anal = anal_rows[k].get(RMOVANA_CODCMS);
const TRectype& pla = cache().get(LF_COMMESSE, commessa_riga_anal);
const bool prorata = pla.get_bool("PRORATA");
if (prorata)
{
const TDate datareg = pn.curr().get_date(MOV_DATAREG);
const int anno = datareg.year();
TRegistro registro(pn.curr().get(MOV_REG), anno);
//%deducibilit<69> iva rivista con il prorata
perc_ded_iva = (CENTO - registro.prorata(anno))/CENTO;
imposta_iva.round(TCurrency::get_firm_dec()); //ci vanno i decimali della ditta
}
} //if imposta_iva...
//prende il conto sulla riga analitica e lo confronta con quello della riga iva
const int gruppo_anal = atoi(anal_rows[k].get(RMOVANA_CODCONTO).left(3));
const int conto_anal = atoi(anal_rows[k].get(RMOVANA_CODCONTO).mid(3,3));
const long sottoconto_anal = atol(anal_rows[k].get(RMOVANA_CODCONTO).mid(6,6));
//il codconto anale e iva coincidono?..
if (gruppo_iva == gruppo_anal && conto_iva == conto_anal && sottoconto_iva == sottoconto_anal)
{
//..in tal caso aggiunge l'importo della riga analitica al distributore, dopo..
//..averlo corretto in base alle % precedentemente calcolate
real importo_anal = anal_rows[k].get_real(RMOVANA_IMPORTO);
const real perc_iva = imposta_iva / imponibile_iva;
const real perc_corretta_iva = perc_iva * (UNO - perc_ded_iva);
importo_anal = importo_anal * (UNO - perc_corretta_iva);
agip.add(importo_anal);
} //if(gruppo_iva==...
} //for (anal_rows...
for (int l = 1; l <= anal_rows.rows(); l++) //..allora le scansiona..
{
//prende il conto sulla riga analitica e lo confronta con quello della riga iva
const int gruppo_anal = atoi(anal_rows[l].get(RMOVANA_CODCONTO).left(3));
const int conto_anal = atoi(anal_rows[l].get(RMOVANA_CODCONTO).mid(3,3));
const long sottoconto_anal = atol(anal_rows[l].get(RMOVANA_CODCONTO).mid(6,6));
//il codconto anale e iva coincidono?
if (gruppo_iva == gruppo_anal && conto_iva == conto_anal && sottoconto_iva == sottoconto_anal)
{
//impoerto
real importo = agip.get();
//commessa,cdc,fase della riga analitica devono essere coincidenti con quelle dello sheet
if (check_cms_cdc_fsc(anal_rows[l]))
{
//costruzione dell'assoc_array 'commesse' con cms/cdc/fsc ed importi
TToken_string cms_cdc_fsc;
cms_cdc_fsc.add(anal_rows[l].get(RMOVANA_CODCMS));
cms_cdc_fsc.add(anal_rows[l].get(RMOVANA_CODCCOSTO));
cms_cdc_fsc.add(anal_rows[l].get(RMOVANA_CODFASE));
real* imp = (real*)commesse.objptr(cms_cdc_fsc);
//aggiunge un elemento all'assoc_array...
if (imp == NULL)
{
imp = new real;
commesse.add(cms_cdc_fsc, imp);
}
*imp += importo;
totdoc_cms += importo;
} //if check_cms_cdc_fsc...
} //if(gruppo_iva==...
} //for (anal_rows...
} //if indicatore_bilancio!=5...
} //for (pn.iva_items(...
totdoc = totale_documento(pn.curr()); //tot doc con ritenute fiscali + ritenute sociali (da stampare)
totdoc_netto = pn.curr().get_real(MOV_TOTDOC); //questo si usa solo per il calcolo del residuo
} //if(pn.iva_items(...
else //..movimento NON iva (sempre con saldaconto)
{
for (int j = 0; j < pn.cg_items(); j++)
{
const TRectype& rmov = pn.cg(j);
const TBill zio_cg(rmov);
TImporto importo(rmov.get_char(RMV_SEZIONE), rmov.get_real(RMV_IMPORTO));
importo.normalize('D');
if (zio_cg.tipo() > ' ')
{
totdoc -= importo.valore();
totdoc_netto -= importo.valore(); //valore per il calcolo del residuo
}
else
if (cerca_fiscali(zio_cg) || cerca_sociali(zio_cg))
totdoc -= importo.valore(); //valore da stampare nella colonna Tot.fattura con ritenute
} //for j < pn.cg_items...
for (int k = 1; k <= anal_rows.rows(); k++) //..allora le scansiona..
{
//prende gr/co/sott sulla riga analitica...
const int gruppo_anal = atoi(anal_rows[k].get(RMOVANA_CODCONTO).left(3));
const int conto_anal = atoi(anal_rows[k].get(RMOVANA_CODCONTO).mid(3,3));
const long sottoconto_anal = atol(anal_rows[k].get(RMOVANA_CODCONTO).mid(6,6));
//..e crea il conto contabile corrispondente
TBill conto_cg(gruppo_anal, conto_anal, sottoconto_anal);
//l'indicatore di bilancio del conto contabile appena creato e' valido?
if (conto_cg.indicatore_bilancio() != 5)
{
const real importo_anal = anal_rows[k].get_real(RMOVANA_IMPORTO);
//costruzione dell'assoc_array 'commesse' con cms/cdc/fsc ed importi
TToken_string cms_cdc_fsc;
cms_cdc_fsc.add(anal_rows[k].get(RMOVANA_CODCMS));
cms_cdc_fsc.add(anal_rows[k].get(RMOVANA_CODCCOSTO));
cms_cdc_fsc.add(anal_rows[k].get(RMOVANA_CODFASE));
real* imp = (real*)commesse.objptr(cms_cdc_fsc);
if (imp == NULL)
{
imp = new real;
commesse.add(cms_cdc_fsc, imp);
}
TImporto importo(anal_rows[k].get_char(RMOVANA_SEZIONE), anal_rows[k].get_real(RMOVANA_IMPORTO));
importo.normalize('D');
*imp += importo.valore();
totdoc_cms += importo.valore();
} //if(conto_cg.indicatore...
} //for(k<anal_rows...
} //else (pn.iva_items(...
//parte comune a movimenti IVA e non (vengono anche qui considerate le ritenute fiscali
//e sociali perche' possono essere state inserite direttamente nella partita e non nel movimento
//(quindi non si puo' in questo caso applicare la totale_documento()
//Le ritenute fiscali vanno sempre sommate..
real totpagato = riga_pag.get_real(PART_IMPORTO) + riga_pag.get_real(PART_RITENUTE);
//Le ritenute sociali invece vanno testate con la test_swap..
const real ritsoc = riga_pag.get_real(PART_RITSOC);
if (!ritsoc.is_zero())
{
const TRectype& mov = pn.curr();
TCausale caus(mov.get(MOV_CODCAUS));
const bool swapt = test_swap(caus, false); // Totale invertito ?
const bool swaps = test_swap(caus, true); // Ritenute sociali invertite ?
if (swapt ^ swaps) // Somma ritenute sociali con segno
totpagato -= ritsoc;
else
totpagato += ritsoc;
}
const real percentuale = totpagato / totdoc_netto;
//calcolo del residuo (solo movimenti saldacontati)
//mi servono,dalla riga partita che viene passata,i valori dei campi per la chiave del
//file delle scadenze
const TPartita match(riga_pag);
//ci serve la riga di fattura che origina la nostra riga pagamento
const int riga_fatt = cerca_riga_fattura_origine(match, riga_pag);
//quanto era stato pagato del documento prima della attuale riga_pag
const real totpagato_prec = calcola_pagato_prec(match, riga_fatt, riga_pag);
const real perc_prec = totpagato_prec / totdoc_netto;
TGeneric_distrib distributore(totdoc_cms * percentuale, TCurrency::get_firm_dec());
TGeneric_distrib distributore_prec(totdoc_cms * perc_prec, TCurrency::get_firm_dec());
{
FOR_EACH_ASSOC_OBJECT(commesse, h, k, imp)
{
const real& impcms = *(real*)imp;
distributore.add(impcms);
distributore_prec.add(impcms); //distributore di importo pagato sulle commesse
}
}
FOR_EACH_ASSOC_OBJECT(commesse, h, k, imp)
{
const real& impcms = *(real*)imp;
// campi del pagamento che vanno spediti nel file temporaneo
//codice fornitore e descrizione
const long codforn = riga_pag.get_long(PART_SOTTOCONTO);
tmpcurr.put("CODFORN", codforn);
TString16 keyclifo;
keyclifo.format("F|%ld", codforn);
const TRectype& rec_clifo = cache().get(LF_CLIFO, keyclifo);
tmpcurr.put("DESFORN", rec_clifo.get(CLI_RAGSOC));
//nreg,data pagamento,descrizione pagamento
tmpcurr.put("NREG", nreg);
tmpcurr.put("DATAPAG", riga_pag.get_date(PART_DATAPAG));
tmpcurr.put("DATAREG", riga_pag.get_date(PART_DATAREG));
tmpcurr.put("DESCRPAG", riga_pag.get(PART_DESCR));
//documento origine
tmpcurr.put("NDOC", movfat.get_long(MOV_NUMDOC));
tmpcurr.put("DATADOC", movfat.get_date(MOV_DATADOC));
tmpcurr.put("PROT", movfat.get_long(MOV_PROTIVA));
tmpcurr.put("TOTDOC", totdoc);
tmpcurr.put("TOTPAG", distributore.get()); //pagamento nella partita
//totres = importo da pagare (sulla fattura) - pagamenti precedenti al
tmpcurr.put("TOTRES", impcms - distributore_prec.get());
//campi relativi a cdc,commessa,fase
TToken_string cdc_cms_fsc = k;
tmpcurr.put("CMS",cdc_cms_fsc.get(0));
tmpcurr.put("CDC",cdc_cms_fsc.get(1));
tmpcurr.put("FSC",cdc_cms_fsc.get(2));
//e finalmente aggiunge il record al file temporaneo
_tmp->write();
} //FOR_EACH_...
} //pn.read()...
}
bool TPag_per_cms_recordset::part_callback(const TRelation& rel, void* pJolly)
{
TPag_per_cms_recordset* recordset = (TPag_per_cms_recordset*)pJolly;
const TRectype& riga_part_pag = rel.curr();
const long nreg = recordset->find_movimento(riga_part_pag); //prima cerco un movimento della fattura...
if (nreg > 0) //..se ne trovo almeno uno cerco la commessa corrispondente
recordset->find_commesse(nreg, riga_part_pag);
return true;
}
void TPag_per_cms_recordset::scan_pags()
{
//costruzione filtro
TRectype dafiltrec(LF_PARTITE);
dafiltrec.put(PART_TIPOCF, 'F');
dafiltrec.put(PART_GRUPPO, 0);
dafiltrec.put(PART_CONTO, 0);
dafiltrec.put(PART_SOTTOCONTO, _dacodfor);
TRectype afiltrec(dafiltrec);
afiltrec.put(PART_SOTTOCONTO, _acodfor);
TString filtro = "(TIPOMOV>=\"3\")"; //deve essere un pagamento a fornitore!!!
if (_dadata.ok())
{
TString80 f;
f.format("&&(ANSI(%s)>=\"%s\")", (const char*)_campodata, _dadata.string(ANSI));
filtro << f;
}
if (_adata.ok())
{
TString80 f;
f.format("&&(ANSI(%s)<=\"%s\")", (const char*)_campodata, _adata.string(ANSI));
filtro << f;
}
//applica il filtro alla relazione
TRelation rel(LF_PARTITE);
TCursor cur(&rel, filtro, 1, &dafiltrec, &afiltrec);
cur.scan(part_callback, this, "Movimenti con saldaconto...");
}
void TPag_per_cms_recordset::set_filter(const TPag_per_cms_mask& msk, const int cms_row, const long dacodfor, const long acodfor, const TString& campodata)
{
//se esiste il file temporano con tracciato persomalizzato lo cancella e lo ricrea vuoto
TFilename trr; //file tracciato record
trr.tempdir();
trr.add("paid");
TFilename dbf(trr); //file dati
trr.ext("trr");
dbf.ext("dbf");
//scelta tipo data di estrazione (registrazione, documento, pagamento)
//deve stare qui per poter generare la chiave del file temporaneo in base al tipo di data di estrazione
_campodata = campodata;
//stessa cosa per il simpatico codice fornitore
_dacodfor = dacodfor;
_acodfor = acodfor;
//crea il file .trr in base ai parametri del metodo
crea_trr(trr);
//svuota la memoria dal vecchio file temporaneo
if (_tmp != nullptr)
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
_codcosto = _codcms = _codfas = "";
if (cms_row >= 0)
{
TSheet_field& sf = msk.sfield(F_RIGHE);
TMask& sm = sf.sheet_mask(); //metodo ingannatore per ottenere tutti i campi dallo sheet..
sf.update_mask(cms_row); //..delle cms/fsc/cdc senza rifare il giro della configurazione..
TRelation rel(LF_RMOVANA); //..anale
sm.autosave(rel);
_codcosto = rel.curr().get(RMOVANA_CODCCOSTO);
_codcms = rel.curr().get(RMOVANA_CODCMS);
_codfas = rel.curr().get(RMOVANA_CODFASE);
}
//lettura eventuali date limite (il controllo sul loro valore sara' nei metodi di costruzione
//dei filtri
_dadata = msk.get_date(F_DATAINI);
_adata = msk.get_date(F_DATAFIN);
_contsep = msk.get(F_CONTSEP);
//carica i conti memorizzati nel ca3600.ini,registrandoli negli assoc_array _costi ecc...
lettura_conti(_costi, 'C');
lettura_conti(_pagamenti, 'P');
lettura_conti(_fiscali, 'F');
lettura_conti(_sociali, 'S');
//scansione movimenti con saldaconto
scan_pags();
//se c'e' un filtro sui fornitori, non si fa lo scan dei movimenti senza saldaconto
if (dacodfor <= 0 && acodfor <= 0)
scan_movs();
}
////////////////////////////////////////////////////////
// REPORT
////////////////////////////////////////////////////////
class TPag_per_cms_rep : public TAnal_report
{
protected:
virtual bool set_recordset(const TString& sql);
virtual bool get_usr_val(const TString& name, TVariant& var) const;
virtual void set_dbase_fixed_fields(bool on = true);
public:
void set_filter(const TPag_per_cms_mask& msk, const int cms_row, const long dacodfor, const long acodfor, const TString& campodata);
};
bool TPag_per_cms_rep::get_usr_val(const TString& name, TVariant& var) const
{
return TAnal_report::get_usr_val(name, var);
}
void TPag_per_cms_rep::set_dbase_fixed_fields(bool on)
{
field("B1.201")->show(on);
field("B1.202")->show(on);
field("B1.203")->show(on);
field("B1.204")->show(on);
}
bool TPag_per_cms_rep::set_recordset(const TString& sql)
{
TPag_per_cms_recordset* rs = new TPag_per_cms_recordset(sql);
return TAnal_report::set_recordset(rs);
}
void TPag_per_cms_rep::set_filter(const TPag_per_cms_mask& msk, const int cms_row, const long dacodfor, const long acodfor, const TString& campodata)
{
TAnal_report::set_recordset(NULL);
const char* query ="USE 1000"; //\nJOIN MOVANA INTO NUMREG==NUMRD\nJOIN RMOVANA INTO NUMREG==NUMRD NUMRIG==NRIGA";
TPag_per_cms_recordset* recset = new TPag_per_cms_recordset(query);
recset->set_filter(msk, cms_row, dacodfor, acodfor, campodata);
TAnal_report::set_recordset(recset);
}
//===============================================================================================
////////////////////////////////////////////////////////
// APPLICAZIONE
////////////////////////////////////////////////////////
class TPag_per_cms : public TReport_application
{
TPag_per_cms_mask* _mask;
TPag_per_cms_rep * _rep;
protected:
virtual TReport & get_report(const TAutomask & m);
virtual TTrec * get_dbase_recdesc(TReport & rep, const TAutomask & mask);
virtual TAutomask & get_mask();
virtual void execute_print(TReport_book & book, TAutomask & mask, TReport & rep, export_type type = _export_printer);
virtual const char * output_name(const TAutomask & mask, const TReport & rep) const { return "pagcms"; }
// @cmember Distruzione dei dati dell'utente
virtual bool user_destroy();
public:
void stampa_per_commessa(const TPag_per_cms_mask& mask, TReport_book& book,
TPag_per_cms_rep& rep, const long dacodfor, const long acodfor,
const TString& campodata);
const TMultilevel_code_info& get_level_one() const;
TPag_per_cms() : _mask(nullptr), _rep(nullptr) {}
~TPag_per_cms() {}
};
TReport & TPag_per_cms::get_report(const TAutomask & m)
{
if (_rep == nullptr)
_rep = new TPag_per_cms_rep;
_rep->load(_mask->get(DLG_REPORT));
return *_rep;
}
TAutomask & TPag_per_cms::get_mask()
{
if (_mask == nullptr)
_mask = new TPag_per_cms_mask;
return *_mask;
}
TTrec * TPag_per_cms::get_dbase_recdesc(TReport & rep, const TAutomask & mask)
{
TTrec * desc = new TTrec;
TToken_string def;
TRectype cms(LF_COMMESSE);
TRectype fasi(LF_FASI);
TRectype cdc(LF_CDC);
TRectype rmovana(LF_RMOVANA);
TRectype movana(LF_MOVANA);
desc->add_fielddef(movana.rec_des(), MOVANA_NUMREG);
desc->add_fielddef(movana.rec_des(), MOVANA_DATAREG);
desc->add_fielddef(movana.rec_des(), MOVANA_DATAREG);
desc->set_name("DATAPAG");
desc->add_fielddef(movana.rec_des(), MOVANA_DESCR);
desc->add_fielddef(movana.rec_des(), MOVANA_NUMDOC);
desc->add_fielddef(movana.rec_des(), MOVANA_DATADOC);
desc->add_fielddef("PROT", _longfld, 6);
desc->add_fielddef("TOTDOC", _realfld, 18, 2);
desc->add_fielddef("TOTPAG", _realfld, 18, 2);
desc->add_fielddef(cdc.rec_des(), CDC_CODCOSTO);
desc->add_fielddef(cms.rec_des(), COMMESSE_CODCMS);
desc->add_fielddef(fasi.rec_des(), FASI_CODFASE);
desc->add_fielddef(movana.rec_des(), MOVANA_CONTSEP);
TToken_string keydef(CDC_CODCOSTO, '+');
keydef.add(COMMESSE_CODCMS);
keydef.add(FASI_CODFASE);
keydef.add(MOVANA_NUMREG);
desc->add_keydef(keydef, true);
return desc;
}
//metodo per accattarsi o' primo livello della configurazione CA
const TMultilevel_code_info& TPag_per_cms::get_level_one() 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 TPag_per_cms::stampa_per_commessa(const TPag_per_cms_mask& mask, TReport_book& book, TPag_per_cms_rep& rep,
const long dacodfor, const long acodfor,
const TString& campodata)
{
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_level_one(); //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
TProgress_monitor pi(set.items(), video_string, true);
for (int i = 0; pi.add_status() && set.move_to(i); i++) //fighissimo metodo per scandire un file in 1 riga!
{
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, dacodfor, acodfor, campodata); //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, dacodfor, acodfor, campodata); //..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
}
}
}
void TPag_per_cms::execute_print(TReport_book & book, TAutomask & mask, TReport & rep, export_type type)
{
//il programma si puo' usare SOLO se in contabilita' analitica si usa il piano dei conti contabile
TConfig& cfg = ca_config();
const bool use_pdcc = cfg.get_bool("UsePdcc");
if (!use_pdcc)
{
error_box(TR("Programma funzionante SOLO se in contabilita' analitica si usa il piano dei conti contabile"));
return;
}
//scelta tipo data di estrazione (registrazione, documento, pagamento)
//viene presa qui perche' serve subito alla set_filter del report prima che venga..
//..utilizzata nel recordset
TString16 campodata = PART_DATAREG;
switch(_mask->get_int(F_TIPODATA))
{
case 1: campodata = PART_DATADOC; break;
case 2: campodata = PART_DATAPAG; break;
default: break;
}
//scansione su tutti i fornitori selezionati; questa opzione e' praticamente utile solo..
//..quando il numero di fornitori selezionati non e' elevato;infatti,per ogni fornitore..
//..selezionato, viene eseguito tutto il giro del programma
const long dacodfor = _mask->get_long(F_DACODFOR);
const long acodfor = _mask->get_long(F_ACODFOR);
rep.set_export_sections(type);
stampa_per_commessa(*_mask, book, (TPag_per_cms_rep &) rep, dacodfor, acodfor, campodata); //se non si specifica alcun clifo...
rep.reset_export_sections();
}
bool TPag_per_cms::user_destroy()
{
safe_delete(_mask);
safe_delete(_rep);
return TReport_application::user_destroy();
}
int ca3600(int argc, char* argv[])
{
TPag_per_cms a;
a.run(argc,argv,TR("Stampa pagato per commessa"));
return 0;
}