campo-sirio/ve/velib07.cpp

821 lines
22 KiB
C++
Executable File
Raw Blame History

#include "velib07.h"
#include "../cg/cgsaldac.h"
#include "../cg/cglib02.h"
#include "../db/dblib.h"
#include <pconti.h>
///////////////////////////////////////////////////////////
// TMateriali_base_recordset
///////////////////////////////////////////////////////////
const TVariant& TMateriali_base_recordset::get(const char* column_name) const
{
if (column_name[0] != '#')
{
TVariant& var = get_tmp_var();
int rownum = current_row();
if (reverse())
rownum = items() - 1 - rownum;
const TRiga_esplosione* row = (const TRiga_esplosione*)boom().objptr(rownum);
if (row != NULL)
{
const TFixed_string name(column_name);
if (name == "LASTQTA")
var = row->last_qta();
else
if (name == "TOTQTA")
var = row->val();
else
{
if (rownum != _lastrow)
{
((TMateriali_base_recordset *) this)->_lastrow = rownum;
const TCodice_articolo & comp = row->componente();
const TCodice_articolo & dist = row->distinta();
TLocalisamfile rd(LF_RDIST);
rd.setkey(2);
rd.put("CODCOMP", comp);
rd.put("CODDIST", dist);
if (rd.read() == NOERR)
*_rdist = rd.curr();
}
if (_rdist != NULL)
{
const TString & v = _rdist->get(column_name);
var = v;
}
}
}
return var;
}
return TRecordset::get(column_name);
}
const TVariant& TMateriali_base_recordset::get(unsigned int column) const
{
const TRecordset_column_info & ci = column_info(column);
return get(ci._name);
}
void TMateriali_base_recordset::requery()
{
_boom.destroy();
int pos1 = query_text().find("MATBASE");
if (pos1 > 0)
{
pos1 += 7;
set_reverse(query_text()[pos1] == '-');
if (reverse())
pos1++;
int pos = query_text().find("==", pos1);
int pos2 = -1;
if (pos > 0)
{
TString val(query_text().mid(pos + 2));
pos2 = val.find("FILTER");
if (pos2 > 0)
val.cut(pos2 - 1);
if (val.starts_with("\"") || val.starts_with("'"))
{
val.ltrim(1);
val.rtrim(1);
}
else
{
TVariant var = get(val);
val = var.as_string();
}
const TCodice_articolo art(val);
TDistinta_tree distinta;
if (distinta.set_root(art))
{
while (isspace(query_text()[pos1]))
pos1++;
const int level = atoi(query_text().mid(pos1));
if (level > 0 || query_text()[pos1] =='0')
while (isdigit(query_text()[pos1]))
pos1++;
while (isspace(query_text()[pos1]))
pos1++;
TString8 filter;
if (query_text()[pos1] != 'S')
while (isalpha(query_text()[pos1]))
filter << query_text()[pos1++];
distinta.explode(_boom, true, RAGGR_EXP_NONE, level, filter);
}
pos = query_text().find("FILTER", pos);
if (pos > 0)
{
pos = query_text().find("==", pos);
if (pos > 0)
{
TString val(query_text().mid(pos + 2));
if (val.starts_with("\"") || val.starts_with("'"))
{
val.ltrim(1);
val.rtrim(1);
}
else
{
TVariant var = get(val);
val = var.as_string();
}
const int items = _boom.items();
for (int i = 0; i < items; i++)
{
const TRiga_esplosione * row = (const TRiga_esplosione *)_boom.objptr(i);
if ( row != NULL && row->componente() != val)
_boom.destroy(i);
}
_boom.pack();
}
}
}
}
}
TMateriali_base_recordset::TMateriali_base_recordset(const char* use) : _query(use)
{
_lastrow = -1;
_rdist = new TRectype(LF_RDIST);
const int nfields = _rdist->items();
int pos = 1;
for ( int i = 0 ; i < nfields; i++)
{
TRecordset_column_info * ci = new TRecordset_column_info;
ci->_name = _rdist->fieldname(i);
ci->_pos = pos;
ci->_type = _rdist->type(ci->_name);
const int len = _rdist->length(ci->_name);
pos += len;
ci->_width = len;
_column.add(ci);
}
}
///////////////////////////////////////////////////////////
// TScalare_recordset
///////////////////////////////////////////////////////////
void TScalare_recordset::requery()
{
boom().destroy();
int pos1 = query_text().find("SCALARE");
if (pos1 > 0)
{
pos1 += 7;
set_reverse(query_text()[pos1] == '-');
if (reverse())
pos1++;
int pos = query_text().find("==", pos1);
if (pos > 0)
{
TString val(query_text().mid(pos + 2));
if (val.starts_with("\"") || val.starts_with("'"))
{
val.ltrim(1);
val.rtrim(1);
}
else
{
TVariant var = get(val);
val = var.as_string();
}
const TCodice_articolo art(val);
TDistinta_tree distinta;
if (distinta.set_root(art))
{
while (isspace(query_text()[pos1]))
pos1++;
const int level = atoi(query_text().mid(pos1));
if (level > 0 || query_text()[pos1] =='0')
while (isdigit(query_text()[pos1]))
pos1++;
while (isspace(query_text()[pos1]))
pos1++;
TString8 filter;
if (query_text()[pos1] != 'S')
while (isalpha(query_text()[pos1]))
filter << query_text()[pos1++];
distinta.explode(boom(), false, RAGGR_EXP_NONE, level, filter);
}
pos = query_text().find("FILTER", pos);
if (pos > 0)
{
pos = query_text().find("==", pos);
if (pos > 0)
{
TString val(query_text().mid(pos + 2));
if (val.starts_with("\"") || val.starts_with("'"))
{
val.ltrim(1);
val.rtrim(1);
}
else
{
TVariant var = get(val);
val = var.as_string();
}
const int items = boom().items();
for (int i = 0; i < items; i++)
{
const TRiga_esplosione * row = (const TRiga_esplosione *)boom().objptr(i);
if ( row != NULL && row->componente() != val)
boom().destroy(i);
}
boom().pack();
}
}
}
}
}
///////////////////////////////////////////////////////////
// TDocument_cache
///////////////////////////////////////////////////////////
TObject* TDocument_cache::key2obj(const char* key)
{
TToken_string k(key);
const char provv = *k.get(0);
const int anno = k.get_int();
const TString4 codnum= k.get();
const long ndoc = k.get_long();
TDocumento* doc = new TDocumento(provv, anno, codnum, ndoc);
doc->get("IMPONIBILI"); // Bastardata per far funzionare la successiva dirty_fields
doc->dirty_fields();
return doc;
}
TDocumento& TDocument_cache::doc(const TRectype& rec)
{
TToken_string key;
key = rec.get(DOC_PROVV);
key.add(rec.get(DOC_ANNO));
key.add(rec.get(DOC_CODNUM));
key.add(rec.get(DOC_NDOC));
TDocumento& d = *(TDocumento*)objptr(key);
return d;
}
TDocument_cache:: TDocument_cache() : TCache(3)
{
}
TDocument_cache:: ~TDocument_cache()
{
}
///////////////////////////////////////////////////////////
// TDocument_recordset
///////////////////////////////////////////////////////////
const TVariant& TDocument_recordset::get_field(int num, const char* field) const
{
if (*field != '#')
{
const int idx = relation()->log2ind(num);
if (idx < 0)
return NULL_VARIANT;
const int logic = num > 0 ? num : relation()->file(idx).num();
if (logic == LF_DOC || logic == LF_RIGHEDOC)
{
const TRectype& rec = relation()->file(idx).curr();
// Se non e' un campo standard, ma e' calcolato da una formula...
if (rec.type(field) == _nullfld && strncmp(field, "G1:", 3) != 0)
{
const TDocumento& doc = ((TDocument_cache&)_cache).doc(rec);
TVariant& var = get_tmp_var();
if (xvt_str_compare_ignoring_case(field, "SEGNO") == 0)
{
var = doc.is_nota_credito() ? -UNO : UNO;
} else
if (xvt_str_compare_ignoring_case(field, "IS_COSTO") == 0)
{
bool costo = (doc.tipo().is_costo()) || (!doc.tipo().is_ricavo() && doc.get_char(DOC_TIPOCF)=='F');
var = costo ? UNO : ZERO;
} else
if (xvt_str_compare_ignoring_case(field, "IS_RICAVO") == 0)
{
bool ricavo = (doc.tipo().is_ricavo()) || (!doc.tipo().is_costo() && doc.get_char(DOC_TIPOCF)=='C');
var = ricavo ? UNO : ZERO;
}
else
{
const TFieldref ref(field, logic);
if (logic == LF_DOC)
{
var = ref.read(doc);
}
else
{
const int nriga = rec.get_int(RDOC_NRIGA);
if (nriga > 0 && nriga <= doc.rows())
{
const TRiga_documento& rdoc = doc[nriga];
var = ref.read(rdoc);
}
else
var = NULL_VARIANT;
}
}
return var;
}
}
}
return TISAM_recordset::get_field(num, field);
}
///////////////////////////////////////////////////////////
// TDocument_report
///////////////////////////////////////////////////////////
bool TDocument_report::set_recordset(const TString& query)
{
if (query.find("MATBASE") > 0)
return TReport::set_recordset(new TMateriali_base_recordset(query));
if (query.find("SCALARE") > 0)
return TReport::set_recordset(new TScalare_recordset(query));
return TReport::set_recordset(new TDocument_recordset(query));
}
bool TDocument_report::load(const char* name)
{
const bool ok = TReport::load(name);
if (ok)
{
// Purtroppo il recordset delle sottosezioni deve essere reimpostato a mano
for (int i = 11; i <= 999; i++)
{
TReport_section* sec = find_section('B', i);
if (sec != NULL)
{
TRecordset* recset = sec->recordset();
if (recset != NULL)
{
const TString use = recset->query_text();
if (use.find("MATBASE") > 0)
recset = new TMateriali_base_recordset(use);
else
if (use.find("SCALARE") > 0)
recset = new TScalare_recordset(use);
else
recset = new TDocument_recordset(use);
sec->set_recordset(recset);
}
}
}
}
return ok;
}
void TDocument_report::output_values(const TRectype& rec, const TString& output)
{
TToken_string out(output, '!');
TString curr;
for (const char * str = out.get(0); str; str = out.get())
{ // scansione sugli elementi dell'output
curr = str;
int poseq = curr.find('='); // divide la stringa corrente in lvalue e rvalue
if (poseq < 0)
{
curr_field()->set(rec.get(curr));
}
else
{
int posrv = poseq+1;
if (poseq >= 0 && curr[posrv] == '=')
posrv++;
TString16 fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale
const TString& dat = rec.get(curr.mid(posrv)); // preleva il nome del campo del file alla destra dell'uguale e lo legge dal record
TReport_field* campo = field(fld);
if (campo != NULL)
campo->set(dat);
}
}
}
void TDocument_report::reset_values(const TString& output)
{
TToken_string out(output, '!');
TString curr;
for (const char * str = out.get(0); str; str = out.get())
{ // scansione sugli elementi dell'output
curr = str;
int poseq = curr.find('='); // divide la stringa corrente in lvalue e rvalue
if (poseq < 0)
{
curr_field()->set("");
}
else
{
TString16 fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale
TReport_field* campo = field(fld);
if (campo != NULL)
campo->set("");
}
}
}
bool TDocument_report::msg_parent_doc(TVariant_stack& stack)
{
TReport_field& cf = *curr_field();
int idx =((TISAM_recordset *)recordset())->cursor()->relation()->log2ind(LF_DOC);
if (idx < 0)
return false;
const TRectype& rec = ((TISAM_recordset*)recordset())->cursor()->relation()->file(idx).curr();
TDocumento & doc = (TDocumento &)((TDocument_recordset*)recordset())->doc(rec);
const TRiga_documento * rdoc = NULL;
// Se il campo corrente non appartiene al body allora cerco la prima riga documento buona!
if (cf.section().type() == 'B')
{
idx = ((TISAM_recordset*)recordset())->cursor()->relation()->log2ind(LF_RIGHEDOC);
if (idx < 0)
return false;
const TRectype& rec = ((TISAM_recordset*)recordset())->cursor()->relation()->file(idx).curr();
const int n = rec.get_long("NRIGA");
rdoc = &(doc[n]);
}
else
{
const TRiga_documento * first_desc = NULL;
for (int r = 1; r <= doc.physical_rows(); r++)
{
const TRiga_documento& row = doc[r];
if (row.get(RDOC_DANDOC).not_empty())
{
if (row.is_descrizione())
{
if (first_desc == NULL)
first_desc = &row; // Non e' una riga buona, ma nemmeno da buttare!
}
else
{
rdoc = &row;
break; // Ho trovato la riga buona!
}
}
}
if (rdoc == NULL && first_desc != NULL)
rdoc = first_desc;
}
int level = stack.pop().as_int();
for (; rdoc != NULL && level > 0; level--)
rdoc = (const TRiga_documento*)(rdoc->find_original_rdoc());
const TString& values = stack.pop().as_string();
const bool is_full = stack.peek().as_bool();
if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty())
{
const char provv = rdoc->get_char(RDOC_PROVV);
const int anno = rdoc->get_int(RDOC_ANNO);
const TString4 codnum = rdoc->get(RDOC_CODNUM);
const long ndoc = rdoc->get_long(RDOC_NDOC);
if (is_full)
{
TDocumento doc(provv, anno, codnum, ndoc);
output_values(doc, values);
}
else
{
TToken_string key;
key.add(provv); key.add(anno); key.add(codnum); key.add(ndoc);
const TRectype& doc = cache().get(LF_DOC, key);
output_values(doc, values);
}
}
else
reset_values(values);
return true;
}
bool TDocument_report::msg_parent_row(TVariant_stack& stack)
{
int idx = ((TISAM_recordset*)recordset())->cursor()->relation()->log2ind(LF_RIGHEDOC);
if (idx < 0)
return false;
const TRectype& rec = ((TISAM_recordset*)recordset())->cursor()->relation()->file(idx).curr();
const int n = rec.get_long("NRIGA");
idx =((TISAM_recordset *)recordset())->cursor()->relation()->log2ind(LF_DOC);
if (idx < 0)
return false;
TDocumento & doc = (TDocumento &)((TDocument_recordset*)recordset())->doc(rec);
const TRiga_documento * rdoc = &(doc[n]);
// Se il campo corrente non appartiene al body allora cerco la prima riga documento buona!
int level = stack.pop().as_int();
for (; rdoc != NULL && level > 0; level--)
rdoc = (const TRiga_documento *)(rdoc->find_original_rdoc());
const TString& values = stack.pop().as_string();
const bool is_full = stack.peek().as_bool();
if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty())
{
if (is_full)
{
const char provv = rdoc->get_char(RDOC_PROVV);
const int anno = rdoc->get_int(RDOC_ANNO);
const TString4 codnum = rdoc->get(RDOC_CODNUM);
const long ndoc = rdoc->get_long(RDOC_NDOC);
TDocumento doc(provv, anno, codnum, ndoc);
output_values(doc[rdoc->get_int(RDOC_NRIGA)], values);
}
else
output_values(*rdoc, values);
}
return true;
}
size_t TDocument_report::get_usr_words(TString_array& words) const
{
TReport::get_usr_words(words);
const char* const name[] = { "DOC_PARENT_DOC", "DOC_PARENT_ROW", NULL };
((TDocument_report*)this)->_first_msg = words.items(); // Calcola il primo numero disponibile
for (size_t i = 0; name[i] != NULL; i++)
words.add(name[i]);
return words.items();
}
bool TDocument_report::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
{
if (opcode < _first_msg)
return TReport::execute_usr_word(opcode, stack);
opcode -= _first_msg;
switch (opcode)
{
case 0 : msg_parent_doc(stack); break;
case 1 : msg_parent_row(stack); break;
default: break;
}
while (!stack.pop().is_null()); // Svuota eventuali parametri variabili inutilizzati
return true;
}
/////////////////////////////////////////
// Metodi non appartenenti a classi
/////////////////////////////////////////
// METODI PER IL CALCOLO DEL FIDO
//estrazioni mastri clienti e/o fornitori
static const TString_array& mastro(char tipocf)
{
static TString_array m[2];
const TString_array& a = m[tipocf == 'C' ? 0 : 1];
if (a.empty())
{
TISAM_recordset mastri("USE PCON SELECT (CONTO!=\"\")&&(SOTTOCONTO=\"\")");
for (bool ok = mastri.move_first(); ok; ok = mastri.move_next())
{
const int gruppo = mastri.get(PCN_GRUPPO).as_int();
const int conto = mastri.get(PCN_CONTO).as_int();
const int indbil = mastri.get(PCN_INDBIL).as_int();
const char tipocf = mastri.get(PCN_TMCF).as_string()[0];
TToken_string info;
info.add(gruppo);
info.add(conto);
info.add(indbil);
m[tipocf == 'C' ? 0 : 1].add(info);
}
}
return a;
}
static real calcola_saldo_contabile(const long codcf, const TDate& datacalc)
{
real saldone;
TEsercizi_contabili esc;
TDate datainies, datafines;
const int codes = esc.date2esc(datacalc);
if (codes > 0)
esc.code2range(codes, datainies, datafines);
else
{
datainies = datacalc;
datainies.set_day(1);
datainies.set_month(1);
}
const TString_array& a = mastro('C');
//per tutti i mastri selezionati va a calcolare il saldo del cliente/fornitore in input
FOR_EACH_ARRAY_ROW(a, i, row)
{
const int gruppo = row->get_int(0);
const int conto = row->get_int(1);
const int indbil = row->get_int(2);
TSaldo saldo;
real saldo_periodo = saldo.saldo_periodo(gruppo, conto, codcf, datainies, datacalc, indbil, false);
saldone += saldo_periodo;
}
return saldone;
}
static TImporto get_importo(const TISAM_recordset& partite, const char* sezione, const char* valore)
{
const char sez = partite.get(sezione).as_string()[0];
const real val = partite.get(valore).as_real();
return TImporto(sez, val);
}
static real calcola_esposto_da_saldaconto (long codcf, const TDate& datacalc)
{
const int riskdays = ini_get_int(CONFIG_DITTA, "ve", "FIDO_RISKDAYS");
//estrae le righe partita relative a pagamenti successivi alla data di rischio (e con tipopag >2,<7)
TString query;
query << "USE PART\nSELECT BETWEEN(DATAPAG,#DATASBF,0)&&BETWEEN(TIPOPAG,2,7)\n";
query << "FROM TIPOC=C GRUPPO=0 CONTO=0 SOTTOCONTO=#CODCF ANNO=#ANNO\n";
query << "TO TIPOC=C GRUPPO=0 CONTO=0 SOTTOCONTO=#CODCF";
TISAM_recordset partite(query);
partite.set_var("#CODCF", codcf);
partite.set_var("#DATACALC", datacalc);
//data considerante i giorni di rischio ammessi dall'utonto
TDate data_sbf = datacalc;
data_sbf -= riskdays;
partite.set_var("#DATASBF", data_sbf); //data salvo buon fine
partite.set_var("#ANNO", TVariant((long)data_sbf.year()));
//importone somma degli importi delle righe del recordset
TImporto importone_esposto;
for (bool ok = partite.move_first(); ok; ok = partite.move_next())
{
TImporto importo_riga;
//fatture,note di credito,pagamenti
TImporto importo_partita = get_importo(partite, PART_SEZ, PART_IMPORTO);
importo_riga += importo_partita;
//pagamenti (tm=3), insoluti (tm=5), pagamenti insoluti(tm=6)
if (partite.get(PART_TIPOMOV).as_int() >= tm_pagamento)
{
TImporto importo_abbuono = get_importo(partite, PART_SEZABB, PART_ABBUONI);
importo_riga += importo_abbuono;
//pagamenti in valuta
if (!partite.get(PART_CODVAL).is_empty())
{
TImporto importo_diff_cambio = get_importo(partite, PART_SEZDIFCAM, PART_DIFFCAM);
importo_riga += importo_diff_cambio;
}
}
//somma importi presenti sulla riga partita (fatture, pagamenti, insoluti, pagamenti insoluti)
importone_esposto += importo_riga;
}
//la normalizzazione del totale delle partite va fatta in base al fatto che si parli di 'C'liente o 'F'ornitore
//const char sezione_finale = (tipocf == 'C') ? 'A' : 'D';
importone_esposto.normalize('A');
//valore in output
real esposto;
esposto += importone_esposto.valore();
return esposto;
}
static real calcola_fido_da_documenti(long codcf, const TDate& datacalc, const TDoc_key& ignore)
{
real totalone;
// scansione delle righe FIDO_XX(j)=.. sul paragrafo di configurazione VE
// per avere i parametri di numerazione/tipo da considerare
TConfig config(CONFIG_DITTA, "ve");
for (int j = 0; ;j++)
{
const TString& num_fido = config.get("FIDO_NUM", NULL, j);
//se manca la numerazione si pu<70> fermare,in quanto non pu<70> esistere un tipo senza numerazione
if (num_fido.blank())
break;
const TString& tipo_fido = config.get("FIDO_TIP", NULL, j);
const TString& da_stato_fido = config.get("FIDO_DASTA", NULL, j);
const TString& a_stato_fido = config.get("FIDO_ASTA", NULL, j);
const bool residuo_fido = config.get_bool("FIDO_RES", NULL, j);
//per la numerazione scelta queryzza gli archivi alla ricerca dei documenti che rientrano nei parametri
TString query;
query << "USE DOC KEY 2\n";
query << "SELECT (CODNUM=#CODNUM)&&(TIPODOC=#TIPODOC)&&(BETWEEN(STATO,#DASTATO,#ASTATO))\n";
query << "FROM TIPOCF=C CODCF=#CODCF PROVV='D'\n";
query << "TO TIPOCF=C CODCF=#CODCF PROVV='D' ANNO=#ANNO DATADOC=#DATACALC";
TISAM_recordset documenti(query);
documenti.set_var("#CODCF", codcf);
documenti.set_var("#ANNO", (long)datacalc.year());
documenti.set_var("#DATACALC", datacalc);
documenti.set_var("#CODNUM", num_fido);
documenti.set_var("#TIPODOC", tipo_fido);
documenti.set_var("#DASTATO", da_stato_fido);
documenti.set_var("#ASTATO", a_stato_fido);
const int items = documenti.items();
if (items > 0)
{
const TRectype& curr = documenti.cursor()->curr();
//adesso che ha i documenti che cercava..
for (bool ok = documenti.move_first(); ok; ok = documenti.move_next())
{
if (ignore.full())
{
const TDoc_key k(curr);
if (k == ignore)
continue;
}
const TDocumento doc(curr);
//deve tener conto di eventuali docs in valuta
TCurrency_documento totdoc(ZERO, doc);
//documento a residuo (tipo ordini)
if (residuo_fido)
totdoc.set_num(doc.valore(false, true));
else //documento normale (tipo fattura)
totdoc.set_num(doc.totale_doc());
totdoc.change_to_firm_val();
//le nac vanno con segno rovesciato
if (doc.is_nota_credito())
totdoc = -totdoc;
totalone += totdoc.get_num();
}
}
}
return totalone;
}
//metodo per il calcolo fido di un cliente ad una data definita
real calcola_fido_cliente (long codcf, const TDate& datacalc, const TDoc_key& ignore)
{
//PRIMA PARTE: controlla i movimenti
real saldo_contabile = calcola_saldo_contabile(codcf, datacalc);
//SECONDA PARTE: controlla il saldaconto
real esposto_saldaconto = calcola_esposto_da_saldaconto(codcf, datacalc);
//TERZA PARTE: controlla i documenti
real tot_documenti = calcola_fido_da_documenti(codcf, datacalc, ignore);
return saldo_contabile + esposto_saldaconto + tot_documenti;
}
// FINE METODI PER IL CALCOLO DEL FIDO