campo-sirio/ve/velib01.cpp
alex 59431cf055 Corretto calcolo iva per numeri negativi
git-svn-id: svn://10.65.10.50/trunk@3923 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-11-23 08:32:10 +00:00

2731 lines
71 KiB
C++
Executable File
Raw Blame History

#include <tabutil.h>
#include <clifo.h>
#ifndef __APPLICAT_H
#include <applicat.h>
#endif
#ifndef __EXPR_H
#include <expr.h>
#endif
#ifndef __STACK_H
#include <stack.h>
#endif
#ifndef __UTILITY_H
#include <utility.h>
#endif
#include "velib01.h"
#include "sconti.h"
#ifndef __VE0100C_H
#include "ve0100c.h"
#endif
#ifndef __VERIG_H
#include "verig.h"
#endif
#ifndef __VEUML_H
#include "veuml.h"
#endif
#ifndef __VEUML1_H
#include "veuml1.h"
#endif
#ifndef __VEINI_H
#include "veini.h"
#endif
#ifndef __DEFMASK_H
#include <defmask.h>
#endif
#ifndef __PAGAMENT_H
#include "..\cg\pagament.h"
#endif
#ifndef __SCONTI_H
#include "sconti.h"
#endif
TSpesa_prest::TSpesa_prest(const char* codice, char tipo)
: TRectype(LF_TAB)
{
settab(tipo == 'S' ? "SPP" : "PRS");
if (codice && *codice)
read(codice);
}
TSpesa_prest::TSpesa_prest(const TRectype& rec)
: TRectype(rec)
{
}
int TSpesa_prest::read(const char* codice)
{
TTable t(get("COD"));
put("CODTAB", codice);
int err = TRectype::read(t);
if (err != NOERR)
yesnofatal_box("Tipo spesa assente : %s", codice);
return err;
}
TIVA::TIVA(const char* codice)
: TRectype(LF_TABCOM)
{
settab("IVA");
if (codice && *codice)
read(codice);
}
TIVA::TIVA(const TRectype& rec)
: TRectype(rec)
{
}
int TIVA::read(const char* codice)
{
TTable t("%IVA");
put("CODTAB", codice);
int err = TRectype::read(t);
if (err != NOERR)
yesnofatal_box("Codice IVA assente : %s", codice);
return err;
}
bool ora_hndl( TMask_field& field, KEY key )
{
if (field.to_check(key))
{
TFixed_string ora( field.get( ), 6 );
ora.trim( );
if (ora.not_empty() || field.required() )
{
if ( isdigit( ora[ 0 ] ) )
{
if ( ora[ 2 ] != ':')
{
if ( ora.len( ) > 4 )
ora.overwrite( ":", 2 );
else
ora.insert( ":", 2 );
}
}
const bool ok = ((isdigit(ora[0]))&&(isdigit(ora[1]))&&(isdigit(ora[3]))&&(isdigit(ora[4]))) &&
((atoi(&(ora[0]))<24)&&(atoi(&(ora[3]))<60));
if (ok )
field.set((ora));
else
return error_box("Ora errata o formato non valido");
}
}
return TRUE;
}
bool dummy_hndl(TMask_field& field, KEY key)
{
warning_box( "Al campo %d <20> arrivato un KEY %d", field.dlg( ), key );
return TRUE;
}
// Handler per il calcolo delle date di pagamento
bool condpag_hndl( TMask_field& field, KEY key )
{
TDocumento_mask& m = (TDocumento_mask &) field.mask( );
if ( field.to_check(key) || (key == K_TAB && !m.is_running()))
{
const TString16 condpag(m.get(F_CODPAG));
TString16 data(m.get(F_DATAINSC));
if (data.empty())
data = m.get(F_DATADOC);
if ( condpag.not_empty())
{
TPagamento pag(condpag, data);
pag.set_total( 100, 10, 10 );
pag.set_rate_auto( );
int numrate = pag.n_rate( );
if (numrate > 5)
numrate = 5;
for( int i = 0; i < numrate; i ++ )
{
m.show( F_DATASCAD1 + i );
m.set( F_DATASCAD1 + i, pag.data_rata(i).string());
}
for( ; i < 5; i ++ )
m.hide( F_DATASCAD1 + i );
}
}
return TRUE;
}
bool note_hndl( TMask_field& f, KEY key )
{
TDocumento_mask & m = (TDocumento_mask &) f.mask();
if (key == K_TAB && (f.focusdirty() || !m.is_running()))
{
TTable & note = (TTable &) ((TEdit_field &) f).browse()->cursor()->file();
const TString16 cod(f.get());
if (cod != note.get("CODTAB"))
{
note.zero();
note.put("CODTAB", cod);
if (note.read() != NOERR)
note.zero();
}
const bool reg_disabled = note.get_bool("B0");
if (reg_disabled)
message_box("Registrazione disbilitata : %s", (const char *) note.get("S0"));
m.enable(DLG_SAVEREC, !reg_disabled);
}
return TRUE;
}
// handler delle righe
HIDDEN void row_set_handler( TMask& m, const int field, const int index )
{
switch ( index )
{
case 1:
m.set_handler( field, dummy_hndl );
break;
default:
yesnofatal_box( FALSE, "Funzione di handler sulla riga non definita( %d ).", index );
}
}
HIDDEN TString16 curr_um;
HIDDEN real curr_fc(1.0);
HIDDEN bool iva_handler( TMask_field& f, KEY key )
{
if (key == 0 || key == K_ENTER)
{
TDocumento_mask & mask = (TDocumento_mask &) f.mask().get_sheet()->mask();
const TString16 codiva = mask.condv().clifo().get(LF_CFVEN, "ASSFIS");
if (codiva.not_empty())
f.set(codiva);
f.check();
}
return TRUE;
}
HIDDEN bool codart_handler( TMask_field& f, KEY key )
{
// Se qualcuno cerca di modificare la maschera
if ( key == K_TAB && f.focusdirty())
{
TMask& row_mask = f.mask();
TDocumento_mask & mask = (TDocumento_mask &) row_mask.get_sheet()->mask();
TCond_vendita & condv = mask.condv();
condv.set_testa(&mask);
condv.set_riga(&row_mask);
TLocalisamfile & anamag = ((TEdit_field &) f).browse()->cursor()->file();
TLocalisamfile & umart = ((TEdit_field &) row_mask.field(FR_UMQTA)).browse()->cursor()->file();
condv.set_anamag(anamag);
condv.set_umart(umart);
TString80 codart(f.get());
anamag.setkey(1);
anamag.put("CODART", codart);
if (anamag.read() != NOERR)
{
TLocalisamfile codalt(LF_CODCORR);
codalt.setkey(2);
codalt.put("CODARTALT", codart);
if (codalt.read() == NOERR)
{
codart = codalt.get("CODART");
anamag.zero();
anamag.put("CODART", codart);
if (anamag.read() == NOERR)
f.set(codart);
}
}
if (anamag.good())
{
const TString16 lingua = mask.get(F_CODLIN);
const TString codart(row_mask.get(FR_CODART));
TString desc(anamag.get("DESCR"));
if (lingua.not_empty())
{
TLocalisamfile deslin(LF_DESLIN);
deslin.setkey(2);
deslin.put("CODART", codart);
deslin.put("CODLIN", lingua);
if (deslin.read() == NOERR)
desc = deslin.get("DESCR");
}
row_mask.set(FR_DESCR, desc);
umart.setkey(1);
umart.zero();
umart.put("CODART", codart);
if (umart.read(_isgteq) == NOERR && codart == umart.get("CODART"))
{
curr_um = umart.get("UM");
curr_fc = umart.get_real("FC");
}
else
{
curr_um.cut(0);
curr_fc = 1.0;
}
row_mask.set(FR_UMQTA, curr_um);
}
condv.ricerca();
const int pos = row_mask.id2pos(FR_CODIVA);
if (pos >= 0)
iva_handler(row_mask.fld(pos), 0);
}
return TRUE;
}
HIDDEN bool umart_handler( TMask_field& f, KEY key )
{
// Se qualcuno cerca di modificare la maschera
if ( key == K_TAB && f.focusdirty())
{
TMask& row_mask = f.mask( );
TDocumento_mask & mask = (TDocumento_mask &) row_mask.get_sheet()->mask();
TLocalisamfile & anamag = ((TEdit_field &) row_mask.field(FR_CODART)).browse()->cursor()->file();
TLocalisamfile & umart = ((TEdit_field &) f).browse()->cursor()->file();
TCond_vendita & condv = mask.condv();
condv.set_testa(&mask);
condv.set_riga(&row_mask);
condv.set_anamag(anamag);
condv.set_umart(umart);
condv.ricerca(TRUE);
const TString16 um(f.get());
real fc(1.0);
if (um.not_empty() && curr_um.not_empty() && um != curr_um)
{
umart.setkey(2);
umart.put("CODART", row_mask.get(FR_CODART));
umart.put("UM", um);
if (umart.read() == NOERR)
{
real qta(row_mask.get_real(FR_QTA));
qta *= curr_fc;
fc = umart.get_real("FC");
qta /= fc;
row_mask.set(FR_QTA, qta);
}
}
curr_um = um;
curr_fc = fc;
}
return TRUE;
}
HIDDEN bool descr_handler( TMask_field& f, KEY key )
{
if (key == K_TAB && f.focusdirty())
{
const TString s(f.get());
if (s.find('\n') < 0)
{
TLocalisamfile & anamag = ((TEdit_field &) f).browse()->cursor()->file();
anamag.zero();
anamag.setkey(2);
anamag.put("DESCR", ((TZoom_field &) f).get_first_line());
if (anamag.read() == NOERR)
{
f.mask().set(FR_CODART, anamag.get("CODART"));
f.mask().field(FR_CODART).set_dirty();
f.mask().check_field(FR_CODART);
}
}
}
return TRUE;
}
HIDDEN bool qta_handler( TMask_field& f, KEY key )
{
// Se qualcuno cerca di modificare la maschera
if ( key == K_TAB && f.focusdirty())
{
TMask& row_mask = f.mask( );
TDocumento_mask & mask = (TDocumento_mask &) row_mask.get_sheet()->mask();
TLocalisamfile & anamag = ((TEdit_field &) row_mask.field(FR_CODART)).browse()->cursor()->file();
TLocalisamfile & umart = ((TEdit_field &) row_mask.field(FR_UMQTA)).browse()->cursor()->file();
TCond_vendita & condv = mask.condv();
condv.set_testa(&mask);
condv.set_riga(&row_mask);
condv.set_anamag(anamag);
condv.set_umart(umart);
condv.ricerca(FALSE, TRUE);
}
return TRUE;
}
HIDDEN bool sppr_handler( TMask_field& f, KEY key )
{
if (key == K_TAB && f.focusdirty())
{
TMask& row_mask = f.mask( );
const int pos = row_mask.id2pos(FR_PREZZO);
if (pos >= 0)
{
TMask & mask = row_mask.get_sheet()->mask();
TRectype & spprrec = ((TEdit_field &) row_mask.field(FR_CODART)).browse()->cursor()->file().curr();
if (spprrec.get("CODTAB") == row_mask.get(FR_CODART) && spprrec.get_char("S6") != 'P')
{
real cambio = mask.get(F_CAMBIO);
real prezzo = row_mask.get(FR_PREZZO);
const TString16 doc_valuta(mask.get(F_CODVAL));
const TString16 sppr_valuta(spprrec.get("S4"));
if (sppr_valuta != doc_valuta && cambio != 0.0)
{
TTable val("%VAL");
val.put("CODTAB", sppr_valuta);
if (val.read() == NOERR)
{
const real sppr_cambio = val.get_real("R10");
if (sppr_cambio != ZERO)
prezzo *= sppr_cambio;
}
prezzo /= mask.get_real(F_CAMBIO);
}
row_mask.set(FR_PREZZO, prezzo);
const int pos =row_mask.id2pos(FR_CODIVA);
if (pos >= 0)
iva_handler(row_mask.fld(pos), 0);
}
}
}
return TRUE;
}
///////////////////////////////////////////////////////////
// Funzioni per il calcolo dei prezzi netti/lordi
///////////////////////////////////////////////////////////
real lordo2netto(real& lordo, const TString& codiva, int ndec)
{
TTable tabiva("%IVA");
real aliquota = 0.0;
tabiva.put("CODTAB", codiva);
if (tabiva.read() == NOERR) aliquota = tabiva.get_real("R0");
return lordo2netto(lordo,aliquota, ndec);
}
real netto2lordo(const real& netto, const TString& codiva, int ndec)
{
TTable tabiva("%IVA");
real aliquota = 0.0;
tabiva.put("CODTAB", codiva);
if (tabiva.read() == NOERR) aliquota = tabiva.get_real("R0");
return netto2lordo(netto,aliquota, ndec);
}
real lordo2netto(real& lordo, const real& iva, int ndec)
{
real netto;
real imposta = 0.0;
real imposta_rec = 0.0;
if (!iva.is_zero())
{
imposta = (lordo * iva) / (iva + 100.0); // Calcola l'imposta...
if (imposta < ZERO)
imposta.floor(ndec);
else
imposta.ceil(ndec);
}
netto = lordo - imposta; // Questo e' l'importo netto
imposta_rec = (netto * iva) / 100.0; // Ricalcola l'imposta con il nuovo imponibile
if (imposta_rec < ZERO)
imposta_rec.floor(ndec);
else
imposta_rec.ceil(ndec);
if (imposta != imposta_rec) // In questo caso corregge l'importo lordo
lordo = netto + imposta_rec;
return netto;
}
real netto2lordo(const real& netto, const real& iva, int ndec)
{
real lordo;
real imposta = 0.0;
if (!iva.is_zero())
{
imposta = (netto * iva) / 100.0; // Calcola l'imposta
if(imposta < ZERO)
imposta.floor(ndec);
else
imposta.ceil(ndec);
}
lordo = imposta + netto; // prezzo lordo
return lordo;
}
real prezzo_scontato(const real& prezzo, const char * sconto)
{
real scontato = prezzo;
if (sconto && *sconto)
{
TCond_vendita cv;
cv.set_sconto(sconto);
scontato = cv.sconto_val() * prezzo;
}
return scontato;
}
enum TTipo_calcolo { _nessun_calcolo, _qtaprezzo, _valore, _percentuale, _scontoimp, _scontoperc};
real iva(real imponibile, const TIVA & iva,int ndec)
{
real val = imponibile * iva.aliquota() / 100.0;
if (val <ZERO)
val.floor(ndec);
else
val.ceil(ndec);
return val;
}
real TDocumento::spese_incasso(real & imp, int ndec, bool netto) const
{
real imp_spese;
real percentuale = get_real("PERCSPINC");
static TArray spese_inc;
if (percentuale > ZERO)
{
if (spese_inc.objptr(_rim_dir) == NULL)
{
TConfig conf(CONFIG_STUDIO);
for (TTipo_pag p = _rim_dir; p < _nessun_pag; p = (TTipo_pag) ((int)p + 1))
{
real r(conf.get("IMPSPINC", "ve", p));
spese_inc.add(r, p);
}
}
TPagamento & pag = ((TDocumento *)this)->pagamento();
const int nrate = pag.n_rate();
for (int i = 0; i < nrate; i++)
{
const TTipo_pag p = (TTipo_pag) pag.tipo_rata(i);
imp_spese += (real &) spese_inc[p];
}
imp_spese *= percentuale / 100.0;
real cambio = get_real("CAMBIO");
if (cambio == ZERO)
cambio = 1.0;
imp_spese /= cambio;
imp_spese.round(ndec);
if (netto == FALSE)
{
static TString16 codiva;
static long firm = -1;
long new_firm = main_app().get_firm();
if (firm != new_firm)
{
TConfig conf(CONFIG_DITTA);
codiva = conf.get("SPINCODIVA", "ve");
firm = new_firm;
}
imp_spese += iva(imp_spese, TRiga_documento::iva(codiva), ndec);
}
}
return imp_spese;
}
real TDocumento::bolli(real & imp, int ndec, bool netto) const
{
real tot_bolli;
static TArray sca_bolli;
static TArray imp_bolli;
static int nscagl;
TLocalisamfile clifo(LF_CLIFO);
bool estero = 2;
if (get_bool("ADDBOLLI"))
{
real cambio = get_real("CAMBIO");
if (cambio == ZERO)
cambio = 1.0;
real importo = imp*cambio;
TPagamento & pag = ((TDocumento*)this)->pagamento();
const int nrate = pag.n_rate();
real old_bolli = -1.00;
real iva_bolli;
for (int j = 0; j < 5 && tot_bolli != old_bolli; j++)
{
old_bolli = tot_bolli;
const real imposte = imposta() * cambio + iva_bolli;
const real imp_spese = spese() * cambio + tot_bolli - iva_bolli;
const real imponibile = importo - imposte - imp_spese;
tot_bolli = ZERO;
pag.set_total(imponibile, imposte, imp_spese);
pag.set_rate_auto();
for (int i = 0; i < nrate; i++)
{
const TTipo_pag p = (TTipo_pag) pag.tipo_rata(i);
real imp = pag.importo_rata(i);
switch (p)
{
case _ric_ban:
{
if (sca_bolli.objptr(0) == NULL)
{
TConfig conf(CONFIG_STUDIO);
for (nscagl = 0; nscagl < 7; nscagl++)
{
real s(conf.get("SPBOSCA", "ve", nscagl + 1));
real i(conf.get("SPBOIMP", "ve", nscagl + 1));
if (s == ZERO && i == ZERO)
break;
sca_bolli.add(s, nscagl);
imp_bolli.add(i, nscagl);
}
}
for (int i = 0; i < nscagl - 1; i++)
if ((real &) sca_bolli[i] >= imp)
break;
if (imp_bolli.items() > 0)
tot_bolli += (real &) imp_bolli[i];
}
break;
case _tratta:
case _tratta_acc:
{
if (estero == 2)
{
clifo.put("TIPOCF", get("TIPOCF"));
clifo.put("CODCF", get("CODCF"));
if (clifo.read() != NOERR)
clifo.zero();
const TString16 stato(clifo.get("STATOPAIV"));
estero = stato.not_empty() && stato != "IT";
if (!estero)
estero = clifo.get("STATOCF").not_empty() || clifo.get("COMCF")[0] == 'Z';
}
real r(imp);
r.ceil(-3);
if (estero)
r *= 0.009;
else
r *= 0.012;
r.round(-2);
tot_bolli += r;
}
break;
case _cessione:
case _paghero:
case _let_cred:
case _rim_dir:
case _rid:
case _bonfico:
default:
break;
}
}
if (netto == FALSE)
{
static TString16 codiva;
static long firm = -1;
long new_firm = main_app().get_firm();
if (firm != new_firm)
{
TConfig conf(CONFIG_DITTA);
codiva = conf.get("SPBOCODIVA", "ve");
firm = new_firm;
}
iva_bolli = iva(tot_bolli, TRiga_documento::iva(codiva), ndec);
tot_bolli += iva_bolli;
}
importo += (tot_bolli - old_bolli);
}
tot_bolli /= cambio;
tot_bolli.round(ndec);
}
return tot_bolli;
}
///////////////////////////////////////////////////////////
// Formula generica
///////////////////////////////////////////////////////////
HIDDEN enum _formula {_somma, _bolli, _bolli_int, _spinc, _prezzo, _importo, _sconto, _iva, _provv, _tipo};
TExpr_documento::TExpr_documento(const char* expression, TTypeexp type,
TDocumento * doc, TRiga_documento * row)
: TExpression(type), _doc(doc), _row(row)
{
if (!set(expression, type))
error_box("Wrong expression : %s", expression);
}
int TExpr_documento::parse_user_func(const char * name, int nparms) const
{
if (strcmp(name, "SOMMA") == 0)
return nparms > 0 || nparms < 3 ? _somma : -1;
else
if (strcmp(name, "BOLLI") == 0)
return nparms > 0 || nparms < 4 ? _bolli : -1;
else
if (strcmp(name, "_BOLLI") == 0)
return nparms > 0 || nparms < 3 ? _bolli_int : -1;
else
if (strcmp(name, "SPESEINC") == 0)
return nparms > 0 || nparms < 4 ? _spinc : -1;
else
if (strcmp(name, "PREZZO") == 0)
return nparms < 4 ? _prezzo : -1;
else
if (strcmp(name, "IMPORTO") == 0)
return nparms < 4 ? _importo : -1;
else
if (strcmp(name, "SCONTO") == 0)
return nparms < 2 ? _sconto : -1;
else
if (strcmp(name, "IVA") == 0)
return nparms < 2 ? _iva : -1;
else
if (strcmp(name, "PROVV") == 0)
return nparms < 2 ? _provv : -1;
else
if (strcmp(name, "TIPO") == 0)
return nparms == 0 ? _tipo : -1;
else
return -1;
}
void TExpr_documento::evaluate_user_func(int index, int nparms, TEval_stack & stack, TTypeexp type) const
{
switch (index)
{
case _somma:
{
const TString cond(nparms == 2 ? stack.pop_string() : "STR(1)");
const TString & fieldname = stack.pop_string();
real somma;
if (_doc != NULL)
{
TExpr_documento cond_expr(cond, _strexpr, _doc);
const int nrows = _doc->rows();
const int nvars = cond_expr.numvar();
for (int i = nrows; i > 0 ; i--)
{
TRiga_documento & riga = (TRiga_documento &) (*_doc)[i];
for (int j = nvars - 1; j >= 0; j--)
{
const char* s = cond_expr.varname(j);
TFieldref f(s,0);
cond_expr.setvar(j, f.read(riga));
}
cond_expr.set_row(&riga);
if ((bool)cond_expr)
somma += riga.get_real(fieldname);
}
}
stack.push(somma);
}
break;
case _spinc:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
bool netto = FALSE;
if (nparms > 2)
ndec = (int) stack.pop_real().integer();
if (nparms > 1)
netto = !stack.pop_real().is_zero();
real & r = stack.peek_real();
if (_doc)
r = _doc->spese_incasso(r, ndec, netto);
else
r = ZERO;
}
break;
case _bolli:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
bool netto = FALSE;
if (nparms > 2)
ndec = (int) stack.pop_real().integer();
if (nparms > 1)
netto = !stack.pop_real().is_zero();
real & r = stack.peek_real();
if (_doc)
{
r += _doc->spese_incasso(r, ndec);
r = _doc->bolli(r, ndec, netto);
}
else
r = ZERO;
}
break;
case _bolli_int:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
if (nparms > 2)
ndec = (int) stack.pop_real().integer();
real & r = stack.peek_real();
if (_doc)
{
real r1 = _doc->spese_incasso(r, ndec);
r += r1;
r1 += _doc->bolli(r, ndec);
r = r1;
}
else
r = ZERO;
}
break;
case _prezzo:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
bool lordo = FALSE;
bool scontato = FALSE;
if (nparms > 2)
ndec = (int) stack.pop_real().integer();
if (nparms > 1)
lordo = !stack.pop_real().is_zero();
if (nparms > 0)
scontato = !stack.peek_real().is_zero();
else
stack.push(ZERO);
real & val = stack.peek_real();
if (_row)
val = _row->prezzo(scontato, lordo, ndec);
else val = ZERO;
}
break;
case _importo:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
bool lordo = FALSE;
bool scontato = FALSE;
if (nparms > 2)
ndec = (int) stack.pop_real().integer();
if (nparms > 1)
lordo = !stack.pop_real().is_zero();
if (nparms > 0)
scontato = !stack.peek_real().is_zero();
else
stack.push(ZERO);
real & val = stack.peek_real();
if (_row)
val = _row->importo(scontato, lordo, ndec);
else
val = ZERO;
}
break;
case _sconto:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
if (nparms > 0)
ndec = (int) stack.peek_real().integer();
else
stack.push(ZERO);
real & val = stack.peek_real();
if (_row)
{
if (_row->tipo().tipo() == 'C')
val = -_row->importo(FALSE, FALSE, ndec);
else
val = _row->importo(FALSE, FALSE, ndec) - _row->importo(TRUE, FALSE, ndec);
}
else
val = ZERO;
}
break;
case _iva:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
if (nparms > 0)
ndec = (int) stack.peek_real().integer();
else
stack.push(ZERO);
real & val = stack.peek_real();
if (_row)
val = _row->iva(ndec);
else
val = ZERO;
}
break;
case _provv:
{
int ndec = _doc && _doc->in_valuta() ? 3 : 0;
if (nparms > 0)
ndec = (int) stack.peek_real().integer();
else
stack.push(ZERO);
real & val = stack.peek_real();
if (_row)
{
val = _row->importo(TRUE, FALSE, ndec) * _row->get_real("PERCPROV") / 100.0;
val.round(ndec);
}
else
val = ZERO;
}
break;
case _tipo:
{
TString s;
if (_row)
s << _row->tipo().tipo();
stack.push(s);
}
break;
default:
TExpression::evaluate_user_func(index, nparms, stack, type);
break;
}
}
TObject* TExpr_documento::dup() const
{
TExpr_documento* o = new TExpr_documento(*this);
return o;
}
///////////////////////////////////////////////////////////
// Formula generica
///////////////////////////////////////////////////////////
TFormula_documento::TFormula_documento(TTipo_formula tipo, const char* codice)
: TRectype(LF_TABCOM), _expr(NULL)
{
_tab = tipo == _documento ? "FRD" : "FRR";
settab(_tab);
_tab.insert("%");
if (codice && *codice)
read(codice);
}
TFormula_documento::TFormula_documento(const TRectype& rec)
: TRectype(rec), _expr(NULL)
{
_tab = "%";
_tab << rec.get("COD");
_expr = new TExpr_documento(expr_string(), expr_type());
}
TFormula_documento::~TFormula_documento()
{
if (_expr) delete _expr;
}
int TFormula_documento::read(const char* codice)
{
if (_expr != NULL)
{
delete _expr;
_expr = NULL;
}
TTable t(_tab);
put("CODTAB", codice);
int err = TRectype::read(t);
if (err == NOERR)
{
const TString e(expr_string());
_expr = new TExpr_documento(e, expr_type());
}
else
{
zero();
put("CODTAB", codice);
}
return err;
}
///////////////////////////////////////////////////////////
// Tipo documento
///////////////////////////////////////////////////////////
TAssoc_array TTipo_documento::_formule_documento;
TTipo_documento::TTipo_documento(const char* tipodoc)
: TRectype(LF_TABCOM)
{
settab("TIP");
if (tipodoc && *tipodoc)
read(tipodoc);
}
TTipo_documento::TTipo_documento(const TRectype& rec)
: TRectype(rec)
{
read_formule();
}
TTipo_documento::~TTipo_documento()
{ }
int TTipo_documento::read(const char* tipodoc)
{
TTable t("%TIP");
put("CODTAB", tipodoc);
int err = TRectype::read(t);
_formule = "";
if (err == NOERR)
read_formule();
else
yesnofatal_box("Tipo documento errato: %s", tipodoc);
return err;
}
void TTipo_documento::read_formule()
{
TFilename prof(profile_name());
prof.ext("ini");
TConfig profile(prof);
_formule = profile.get("CAMPICALC", "MAIN");
_formule.add(profile.get("CALCOLI", "MAIN"));
_imponibile = profile.get("IMPONIBILE", "MAIN");
if (_imponibile.not_empty() && _formule.find(_imponibile) < 0)
{
error_box("Campo imponibile (%s) sconosciuto nel tipo documento %s", (const char *) _imponibile, (const char *) codice());
_imponibile.cut(0);
}
_imposta = profile.get("IMPOSTA", "MAIN");
if (_imposta.not_empty() && _formule.find(_imposta) < 0)
{
error_box("Campo imposta (%s) sconosciuto nel tipo documento %s", (const char *) _imposta, (const char *) codice());
_imposta.cut(0);
}
_totale = profile.get("TOTALE", "MAIN");
_totale_netto = "_";
_totale_netto << _totale;
if (_totale.not_empty() && _formule.find(_totale) < 0)
{
error_box("Campo totale documento (%s) sconosciuto nel tipo documento %s", (const char *) _totale, (const char *) codice());
_totale.cut(0);
}
_basesconto = profile.get("BASESCONTO", "MAIN");
if (_basesconto.not_empty() && _formule.find(_basesconto) < 0)
{
error_box("Campo sconto documento (%s) sconosciuto nel tipo documento %s", (const char *) _basesconto, (const char *) codice());
_basesconto.cut(0);
}
_spese = profile.get("SPESE", "MAIN");
if (_spese.not_empty() && _formule.find(_spese) < 0)
{
error_box("Campo spese (%s) sconosciuto nel tipo documento %s", (const char *) _spese, (const char *) codice());
_spese.cut(0);
}
}
TFormula_documento * TTipo_documento::succ_formula(bool restart)
{
if (restart)
_formule.restart();
const TString16 formula(_formule.get());
if (formula.not_empty())
{
TFormula_documento * o = (TFormula_documento*)_formule_documento.objptr(formula);
if (o == NULL)
{
o = new TFormula_documento(_documento, formula);
_formule_documento.add(formula, o);
}
return o;
}
else
return NULL;
}
///////////////////////////////////////////////////////////
// Tipo riga di un documento
///////////////////////////////////////////////////////////
TAssoc_array TTipo_riga_documento::_formule_riga;
TTipo_riga_documento::TTipo_riga_documento(const char* tiporig)
: TRectype(LF_TABCOM), _mask(NULL)
{
settab("TRI");
_name = "verig";
_name << codice();
if (tiporig && *tiporig)
read(tiporig);
}
TTipo_riga_documento::TTipo_riga_documento(const TRectype& rec)
: TRectype(rec), _mask(NULL)
{
_name = "verig";
_name << codice();
read_formule();
}
TTipo_riga_documento::~TTipo_riga_documento()
{
if (_mask) delete _mask;
}
int TTipo_riga_documento::read(const char* tiporig)
{
TTable t("%TRI");
put("CODTAB", tiporig);
int err = TRectype::read(t);
if (err == NOERR)
read_formule();
else
yesnofatal_box("Tipo riga documento errato: %s", tiporig);
return err;
}
void TTipo_riga_documento::read_formule()
{
TFilename prof(profile_name());
prof.ext("ini");
TConfig profile(prof);
_formule = profile.get("CAMPICALC", "MAIN");
_formule.add(profile.get("CALCOLI", "MAIN"));
_imponibile = profile.get("IMPONIBILE", "MAIN");
if (_imponibile.not_empty() && _formule.find(_imponibile) < 0)
{
error_box("Campo imponibile (%s) sconosciuto nel tipo riga %s", (const char *) _imponibile, (const char *) codice());
_imponibile.cut(0);
}
_imposta = profile.get("IMPOSTA", "MAIN");
if (_imposta.not_empty() && _formule.find(_imposta) < 0)
{
error_box("Campo imposta (%s) sconosciuto nel tipo riga %s", (const char *) _imposta, (const char *) codice());
_imposta.cut(0);
}
}
TFormula_documento * TTipo_riga_documento::succ_formula(bool restart)
{
if (restart)
_formule.restart();
const TString16 formula(_formule.get());
if (formula.not_empty())
{
TFormula_documento * o = (TFormula_documento*)_formule_riga.objptr(formula);
if (o == NULL)
{
o = new TFormula_documento(_riga, formula);
_formule_riga.add(formula, o);
}
return o;
}
else
return NULL;
}
TVariable_mask * TTipo_riga_documento::mask()
{
if (mask_loaded())
return _mask;
_mask = new TVariable_mask(mask_name());
TFilename proname(profile_name());
proname.ext( "ini" );
TConfig pro( proname );
int numhandler = pro.get_int( "NHANDLER", "HANDLERS" );
for( int i = 1; i <= numhandler; i ++ )
{
TString chiave;
chiave.format( "%d", i );
TToken_string riga = pro.get( chiave, "HANDLERS" );
row_set_handler( *_mask, riga.get_int( 0 ), riga.get_int( 1 ) );
}
const int pos = _mask->id2pos(FR_CODART);
if (pos >= 0)
{
const TMask_field & f = _mask->field(FR_CODART);
if (f.is_edit())
{
TBrowse * browse = ((TEdit_field &) f).browse();
const char tipo_r = tipo();
if (browse )
{
const TCursor * cur = browse->cursor();
if (cur)
{
const int num = cur->file().num();
if (num == LF_ANAMAG)
{
_mask->set_handler( FR_CODART, codart_handler );
_mask->set_handler( FR_UMQTA, umart_handler );
_mask->set_handler( FR_DESCR, descr_handler );
_mask->set_handler( FR_QTA, qta_handler );
}
else
if (tipo_r == 'S' || tipo_r == 'P')
_mask->set_handler( FR_CODART, sppr_handler );
}
}
}
}
const int posiva = _mask->id2pos(FR_CODIVA);
if (posiva >= 0)
_mask->set_handler( FR_CODIVA, iva_handler );
return _mask;
}
///////////////////////////////////////////////////////////
// Riga documento per vendite
///////////////////////////////////////////////////////////
TAssoc_array TRiga_documento::_tipi;
TAssoc_array TRiga_documento::_spese;
TAssoc_array TRiga_documento::_ive;
TRiga_documento::TRiga_documento(TDocumento* doc, const char * tipo)
: TAuto_variable_rectype(LF_RIGHEDOC), _doc(doc)
{
if (tipo)
set_tipo(tipo);
}
TRiga_documento::TRiga_documento(const TRiga_documento& rec, TDocumento* doc,
const char * tipo)
: TAuto_variable_rectype(rec), _doc(doc)
{
if (tipo)
set_tipo(tipo);
}
const TTipo_riga_documento& TRiga_documento::tipo() const
{
const TString16 tiporig(get("TIPORIGA"));
CHECK(tiporig.not_empty(), "Tipo riga documento nullo");
TTipo_riga_documento* o = (TTipo_riga_documento*)_tipi.objptr(tiporig);
if (o == NULL)
{
if (_tipi.items() == 0)
{
TTable tri("%TRI"); // Tabella dei tipi riga
for (tri.first(); !tri.eof(); tri.next())
{
const TString16 codice = tri.get("CODTAB");
_tipi.add(codice, new TTipo_riga_documento(tri.curr()));
}
}
o = (TTipo_riga_documento*)_tipi.objptr(tiporig);
if (o == NULL)
{
o = new TTipo_riga_documento(tiporig);
_tipi.add(tiporig, o);
}
}
return *o;
}
const TSpesa_prest & TRiga_documento::spesa() const
{
const char tipor = tipo().tipo();
CHECK(tipor == 'S' || tipor == 'P', "Tipo riga incompatibile con le spese");
static long firm = -1;
long new_firm = main_app().get_firm();
if (firm != new_firm)
{
_spese.destroy();
firm = new_firm;
}
const TString16 codice(get("CODART"));
TString16 index; index << tipor << codice;
TSpesa_prest * s = (TSpesa_prest *) _spese.objptr(index);
if (s == NULL)
{
s = new TSpesa_prest(codice, tipor);
_spese.add(index, s);
}
return *s;
}
const TIVA & TRiga_documento::iva(const char *codice)
{
TIVA * v = (TIVA *) _ive.objptr(codice);
if (v == NULL)
{
v = new TIVA(codice);
_ive.add(codice, v);
}
return *v;
}
bool TRiga_documento::sola_descrizione() const
{
char t = tipo().tipo();
if (t <= ' ' && get("QTA").empty() && get("PREZZO").empty())
t = 'D';
return t == 'D';
}
void TRiga_documento::forza_sola_descrizione()
{
// In realta' il test serve anche a caricare la lista dei tipi riga!
if (!tipo_valido() || tipo().tipo() != 'D')
{
_tipi.restart();
for (const TObject* o = _tipi.get(); o; o = _tipi.get())
{
const TTipo_riga_documento* trd = (const TTipo_riga_documento*)o;
if (trd->tipo() == 'D')
{
put("TIPORIGA", trd->codice());
break;
}
}
zero("QTA");
zero("PREZZO");
}
}
TRectype & TRiga_documento::operator =(const TRectype & r)
{
TRectype::operator=(r);
reset_fields(*this);
set_fields(*this);
return *this;
}
TRectype & TRiga_documento::operator =(const char * r)
{
TRectype::operator=(r);
reset_fields(*this);
set_fields(*this);
return *this;
}
// Ritorna TRUE se le due righe del documento possono essere sommate
bool TRiga_documento::raggruppabile(const TRiga_documento& r, TToken_string& campi) const
{
bool ok = TRUE;
TString campo;
for (const char* c = campi.get(0); c && ok; c = campi.get())
{
campo = get(c); // Separare le due get!
ok &= campo == r.get(c);
}
return ok;
}
TRiga_documento& TRiga_documento::operator +=(const TRiga_documento& r)
{
TToken_string campi("QTA|NCOLLI|QTAEVASA");
for (const char* c = campi.get(0); c && ok; c = campi.get())
{
real num(r.get_real(c));
if (!num.is_zero())
{
num += get_real(c);
put(c, num);
}
}
if (!get_bool("RIGAEVASA"))
{
const real qta = get_real("QTA");
const real qtaeva = get_real("QTAEVASA");
if (qtaeva >= qta)
put("RIGAEVASA", "X");
}
return *this;
}
void TRiga_documento::set_fields(TAuto_variable_rectype & rec)
{
if (get("TIPORIGA").not_empty())
{
TTipo_riga_documento & tipo_riga = (TTipo_riga_documento &) tipo();
for (const TFormula_documento * f = tipo_riga.first_formula(); f; f = tipo_riga.succ_formula())
{
TExpr_documento * exp = f->expr();
add_field(new TDocumento_variable_field(f->name(), exp));
if (exp)
{
exp->set_doc(_doc);
exp->set_row(this);
}
}
}
}
real TRiga_documento::prezzo(bool scontato, bool lordo, int ndec) const
{
real prezzo = get_real("PREZZO");
if (scontato)
prezzo = prezzo_scontato(prezzo, get("SCONTO"));
prezzo.round(ndec);
if (lordo)
prezzo = netto2lordo(prezzo, get("CODIVA"), ndec);
prezzo.round(ndec);
return prezzo;
}
real TRiga_documento::importo(bool scontato, bool lordo, int ndec, bool iva_calc) const
{
real importo;
TTipo_calcolo c = _nessun_calcolo;
const char tipor = tipo().tipo();
const real qta = get_real("QTA");
TString16 field_perc;
TCond_vendita cv;
switch (tipor)
{
case 'M':
c = _qtaprezzo;
break;
case 'P':
case 'S':
{
const TSpesa_prest & s = spesa();
switch (s.tipo())
{
case 'Q':
c = _qtaprezzo;
break;
case 'V':
c = _valore;
break;
case 'P':
c = _percentuale;
field_perc = s.field_perc();
break;
default:
break;
}
}
break;
case 'C':
cv.set_sconto(get("SCONTO"));
if (cv.get_sconto().not_empty())
c = _scontoperc;
else
c = _scontoimp;
break;
case 'O':
if (iva_calc)
c = _qtaprezzo;
default:
break;
}
switch (c)
{
case _qtaprezzo:
importo = prezzo(scontato, lordo, ndec) * qta;
break;
case _valore:
importo = prezzo(scontato, lordo, ndec);
break;
case _percentuale:
importo = doc().get_real(field_perc) * get_real("PSPESA") / 100;
break;
case _scontoimp:
importo = -prezzo(FALSE, lordo, ndec);
break;
case _scontoperc:
importo = doc().basesconto() * (cv.sconto_val() - 1.0);
break;
default:
break;
}
importo.round(ndec);
return importo;
}
real TRiga_documento::imponibile() const
{
const TString16 field(tipo().imponibile());
if (field.not_empty())
return get_real(field);
else
return importo(TRUE, FALSE, doc().in_valuta() ? 3 : 0);
}
real TRiga_documento::imposta() const
{
const TString16 field(tipo().imposta());
if (field.not_empty())
return get_real(field);
else
return iva(doc().in_valuta() ? 3 : 0);
}
void TRiga_documento::dirty_fields(bool dirty_document)
{
for (TDocumento_variable_field * f = (TDocumento_variable_field *) first_variable_field();
f != NULL; f = (TDocumento_variable_field *) succ_variable_field())
f->set_dirty();
if (dirty_document)
((TDocumento &)doc()).dirty_fields();
}
bool TRiga_documento::doc_dependent() const
{
if (tipo_valido())
{
const char tipor = tipo().tipo();
if (tipor == 'S')
return spesa().tipo() == 'P';
else
if (tipor == 'C')
return get("SCONTO").not_empty();
}
return FALSE;
}
void TRiga_documento::put_str(const char* fieldname, const char* val)
{
TString v(val);
if (strcmp(fieldname, "TIPORIGA") == 0 && TRectype::get("TIPORIGA") != v)
{
TAuto_variable_rectype::put_str(fieldname, v);
reset_fields(*this);
set_fields(*this);
}
else
{
TAuto_variable_rectype::put_str(fieldname, v);
dirty_fields();
}
}
void TRiga_documento::zero(const char * fieldname)
{
if (strcmp(fieldname, "TIPORIGA") == 0)
reset_fields(*this);
TAuto_variable_rectype::zero(fieldname);
dirty_fields();
}
void TRiga_documento::zero(char c)
{
reset_fields(*this);
TAuto_variable_rectype::zero(c);
}
void TRiga_documento::autosave(TSheet_field & f)
{
const int num = numero() - 1;
if (num >= 0 && num < f.items())
{
TToken_string & row = f.row(num);
put( "STATORIGA", row.get( f.cid2index(FR_STATORIGA) ) );
put( "TIPORIGA", row.get( f.cid2index(FR_TIPORIGA )) );
TString16 codmag(row.get(f.cid2index(FR_CODMAG)));
codmag.left_just(3);
codmag << row.get( f.cid2index(FR_CODDEP ));
put( "CODMAG", codmag);
put( "CODART", row.get( f.cid2index(FR_CODART )) );
TString s(row.get(f.cid2index(FR_DESCR)));
int split_pos = s.find('\n');
const int descr_len = length("DESCR");
if (split_pos < 0 && s.len() > descr_len)
split_pos = descr_len;
if (split_pos > 0)
{
put( "DESCR", s.left(split_pos));
put("DESCLUNGA", "X");
put("DESCEST", s.mid(split_pos));
}
else
{
put("DESCR", s);
put("DESCLUNGA", "");
zero("DESCEST");
}
put( "PREZZO", row.get( f.cid2index(FR_PREZZO )) );
put( "UMQTA", row.get( f.cid2index(FR_UMQTA )) );
TMask * m = ((TTipo_riga_documento &)tipo()).mask();
const int pos = m->id2pos(FR_QTA);
if (pos >= 0 && m->fld(pos).field()->name() == "PSPESA")
put( "PSPESA", row.get( f.cid2index(FR_QTA )) );
else
put( "QTA", row.get( f.cid2index(FR_QTA )) );
put( "QTAEVASA", row.get( f.cid2index(FR_QTAEVASA )) );
put( "RIGAEVASA", row.get( f.cid2index(FR_RIGAEVASA )) );
put( "TARA", row.get( f.cid2index(FR_TARA )) );
put( "PNETTO", row.get( f.cid2index(FR_PNETTO )) );
put( "NCOLLI", row.get( f.cid2index(FR_NCOLLI )) );
put( "DAEVADERE", row.get( f.cid2index(FR_DAEVADERE )) );
put( "SCONTO", row.get( f.cid2index(FR_SCONTO )) );
put( "PERCPROV", row.get( f.cid2index(FR_PERCPROV )) );
put( "IMPFISSO", row.get( f.cid2index(FR_IMPFISSO )) );
put( "CODIVA", row.get( f.cid2index(FR_CODIVA )) );
put( "ADDIVA", row.get( f.cid2index(FR_ADDIVA )) );
put( "ASPBENI", row.get( f.cid2index(FR_ASPBENI )) );
}
}
void TRiga_documento::autoload(TSheet_field & f)
{
const int num = numero() - 1;
if (num >= 0 && num < f.items())
{
TToken_string & row = f.row(num);
row.add( get( "STATORIGA" ), f.cid2index(FR_STATORIGA ));
row.add( get( "TIPORIGA" ), f.cid2index(FR_TIPORIGA ));
const TString codmag(get("CODMAG"));
row.add( codmag.left(3), f.cid2index(FR_CODMAG ));
row.add( codmag.mid(3), f.cid2index(FR_CODDEP ));
row.add( get( "CODART" ), f.cid2index(FR_CODART ));
TString s(get("DESCR"));
if (get_bool("DESCLUNGA"))
s << get("DESCEST");
row.add(s, f.cid2index(FR_DESCR ));
row.add( get( "UMQTA" ), f.cid2index(FR_UMQTA ));
row.add( get( "PREZZO" ), f.cid2index(FR_PREZZO ));
TMask * m = ((TTipo_riga_documento &)tipo()).mask();
const int pos = m->id2pos(FR_QTA);
if (pos >= 0 && m->fld(pos).field()->name() == "PSPESA")
row.add( get( "PSPESA" ), f.cid2index(FR_QTA ));
else
row.add( get( "QTA" ), f.cid2index(FR_QTA ));
row.add( get( "QTAEVASA" ), f.cid2index(FR_QTAEVASA ));
row.add( get( "RIGAEVASA" ), f.cid2index(FR_RIGAEVASA ));
row.add( get( "TARA" ), f.cid2index(FR_TARA ));
row.add( get( "PNETTO" ), f.cid2index(FR_PNETTO ));
row.add( get( "NCOLLI" ), f.cid2index(FR_NCOLLI ));
row.add( get( "DAEVADERE" ), f.cid2index(FR_DAEVADERE ));
row.add( get( "SCONTO" ), f.cid2index(FR_SCONTO ));
row.add( get( "PERCPROV" ), f.cid2index(FR_PERCPROV ));
row.add( get( "IMPFISSO" ), f.cid2index(FR_IMPFISSO ));
row.add( get( "CODIVA" ), f.cid2index(FR_CODIVA ));
row.add( get( "ADDIVA" ), f.cid2index(FR_ADDIVA ));
row.add( get( "ASPBENI" ), f.cid2index(FR_ASPBENI ));
}
}
TDocumento_mask::TDocumento_mask(const char* name, TDocumento * doc, int num,
int max)
: TVariable_mask(name, num, max), _progs_page(-1), _last_prog(-1),
_doc(doc)
{
const int pos = id2pos(BASE_PIEDE + 1);
if (pos >= 0)
{
_progs_page = find_parent_page(fld(pos));
_last_prog = 0;
while (id2pos(BASE_PIEDE + _last_prog + 1) >= 0)
_last_prog++;
}
}
void TDocumento_mask::next_page(int p)
{
TMask::next_page(p);
if (curr_page() == _progs_page)
{
begin_wait();
autosave(get_relation());
for (int i = _last_prog; i > 0; i--)
{
const short id = BASE_PIEDE + i;
const TString16 name(field(id).field()->name());
set(id , doc().get(name));
}
end_wait();
}
}
bool TDocumento_mask::on_key(KEY key)
{
if (key == K_SHIFT + K_F12)
{
field(F_STATO).enable(!field(F_STATO).enabled());
return TRUE;
}
return TVariable_mask::on_key(key);
}
///////////////////////////////////////////////////////////
// Documento per vendite
///////////////////////////////////////////////////////////
TAssoc_array TDocumento::_tipi;
TDocumento::TDocumento()
: TAuto_variable_rectype(LF_DOC), _rows(LF_RIGHEDOC, "NRIGA"), _nuovo(TRUE),
_condv(NULL), _rel(NULL), _sconto(NULL)
{
set_memo_fld("G1");
}
TDocumento::TDocumento(char provv, int anno, const char* codnum, long numdoc,
TCond_vendita * condv, TRelation * rel)
: TAuto_variable_rectype(LF_DOC), _rows(LF_RIGHEDOC, "NRIGA"), _nuovo(TRUE),
_condv(condv), _rel(rel), _sconto(NULL)
{
set_memo_fld("G1");
if (numdoc <= 0)
{
numdoc = 0;
set_key(*this, provv, anno, codnum, numdoc);
TRiga_documento* key = new TRiga_documento(this);
set_key(*key, provv, anno, codnum, numdoc);
_rows.set_key(key); // ok
}
else
read(provv, anno, codnum, numdoc);
}
// Funzione statica utile a tutti gli utenti di LF_DOC e LF_RIGHEDOC
void TDocumento::set_key(TRectype& rec, char provv, int anno, const char* codnum, long numdoc)
{
CHECK(provv == 'D' || provv == 'P', "Provvisorio o Definitivo?");
CHECKD(anno > 1900, "Anno non valido: ", anno);
CHECK(codnum && *codnum, "Codice numerazione nullo");
CHECKD(numdoc >= 0, "Numero documento non valido ", numdoc);
rec.put("PROVV", provv);
rec.put("ANNO", anno);
rec.put("CODNUM", codnum);
rec.put("NDOC", numdoc);
}
// Funzione statica utile a tutti gli utenti di LF_DOC e LF_RIGHEDOC
void TDocumento::copy_data(TRectype& dst, const TRectype& src)
{
// Memorizza tutti i campi chiave
const char provv = dst.get_char("PROVV");
const int anno = dst.get_int("ANNO");
const TString16 codnum = dst.get("CODNUM");
const long numdoc = dst.get_long("NDOC");
const int nriga = dst.num() == LF_RIGHEDOC ? dst.get_int("NRIGA") : 0;
// Copia tutto il record
dst = src;
// Ripristina tutti i campi chiave
set_key(dst, provv, anno, codnum, numdoc);
if (nriga > 0)
dst.put("NRIGA", nriga);
}
TDocumento::TDocumento(const TRectype& rec, TCond_vendita * condv, TRelation * rel)
: TAuto_variable_rectype(LF_DOC), _rows(LF_RIGHEDOC, "NRIGA"), _nuovo(FALSE),
_condv(condv), _rel(rel), _sconto(NULL)
{
set_memo_fld("G1");
read(rec);
}
TRiga_documento& TDocumento::insert_row(int row, const char *tipo)
{
TRiga_documento * r = new TRiga_documento((const TRiga_documento &) _rows.key(), this); // ok
r->set_numero(row);
if (tipo)
r->set_tipo(tipo);
_rows.insert_row(r); // ok
return *r;
}
TRiga_documento& TDocumento::new_row(const char *tipo)
{
TRiga_documento & r = (TRiga_documento&)_rows.row(-1, TRUE); // ok
if (tipo)
r.set_tipo(tipo);
return r;
}
int TDocumento::read(const TRectype& rec)
{
head() = rec;
TRiga_documento* key = new TRiga_documento(this);
const char pr = tipo_numerazione();
const int an = anno();
const TString16 cn = numerazione();
const long nu = numero();
CHECK(nu > 0, "Numero documento nullo.");
set_key(*key, pr, an, cn, nu);
TLocalisamfile doc(LF_DOC);
int err = TRectype::read(doc);
if (err == NOERR)
{
_nuovo = FALSE;
_rows.read(key); //ok
}
else
{
_nuovo = TRUE;
head() = rec;
destroy_rows();
_rows.set_key(key); // ok
}
set_riga_sconto();
return err;
}
int TDocumento::read(char provv, int anno, const char* codnum, long numdoc)
{
TRectype rec(LF_DOC);
CHECK(numdoc > 0, "Numero documento nullo.");
set_key(rec, provv, anno, codnum, numdoc);
return read(rec);
}
long TDocumento::renum(long numdoc)
{
if (numdoc <= 0)
{
const char tn = tipo_numerazione();
const int an = anno();
const TString16 nu = numerazione();
numdoc = get_next_key(tn, an, nu);
}
char num[16]; sprintf(num, "%ld", numdoc);
renum_key("NDOC", num); // Aggiorna testata
_rows.renum_key("NDOC", num); // Aggiorna righe ok
return numdoc;
}
void TDocumento::set_riga_sconto()
{
const TString80 sconto(get("SCONTOPERC"));
if (sconto.empty())
{
if(_sconto != NULL)
delete _sconto;
_sconto = NULL;
}
else
{
if (_sconto == NULL)
{
static TString _tipo_riga;
static long firm = -1;
long new_firm = main_app().get_firm();
if (firm != new_firm)
{
TConfig conf(CONFIG_DITTA);
_tipo_riga = conf.get("SCOTRIGA", "ve");
firm = new_firm;
}
_sconto = new TRiga_documento(this, _tipo_riga);
_sconto->put("DESCR","Sconto");
}
_sconto->put("SCONTO", sconto);
}
}
void TDocumento::dirty_fields()
{
for (TDocumento_variable_field * f = (TDocumento_variable_field *) first_variable_field();
f != NULL; f = (TDocumento_variable_field *) succ_variable_field())
f->set_dirty();
for (int i = rows(); i > 0; i--)
{
TRiga_documento & r = (TRiga_documento &) row(i);
if (r.doc_dependent())
r.dirty_fields(FALSE);
}
}
int TDocumento::write(bool re) const
{
const bool nuovo = _nuovo || numero() <= 0; // E' nuovo di zecca!
if (nuovo && re) // quindi ...
re = FALSE; // ... non fare la rewrite
TLocalisamfile doc(LF_DOC);
int err = NOERR;
if (re)
{
err = _rows.write(re);
if (err == NOERR)
{
err = TRectype::rewrite(doc);
if (err != NOERR)
err = TRectype::write(doc);
}
}
else
{
if (nuovo)
{
TDocumento& myself = *(TDocumento*)this;
if (numero() <= 0)
myself.renum();
do
{
err = TRectype::write(doc);
if (err == _isreinsert)
myself.renum();
} while (err == _isreinsert);
myself._nuovo = FALSE;
}
else
{
err = TRectype::write(doc);
if (err != NOERR)
err = TRectype::rewrite(doc);
}
if (err == NOERR)
err = _rows.write(re);
}
return err;
}
int TDocumento::remove() const
{
TLocalisamfile doc(LF_DOC);
int err = _rows.remove();
if (err == NOERR)
err = TRectype::remove(doc);
return err;
}
const bool TDocumento::in_valuta() const
{
const TString& val = valuta();
return (val.not_empty() && val != "LIT");
}
TRiga_documento & TDocumento::row(int index)
{
const int nrows = _rows.rows();
if (index <= nrows)
return (TRiga_documento &) _rows.row(index, FALSE);
else
{
CHECKD(index == nrows + 1 &&_sconto != NULL, "Riga documento non esistente ", index);
return *_sconto;
}
}
long TDocumento::get_next_key(char provv, int anno, const char* codnum) const
{
static long n = 0;
if (n == 0)
{
TLocalisamfile doc(LF_DOC);
TRectype& curr = doc.curr();
set_key(curr, provv, anno, codnum, 9999999L);
const int err = doc.read(_isgreat);
if (err != _isemptyfile)
{
if (err == NOERR)
doc.prev();
if (curr.get_char("PROVV") == provv &&
curr.get_int("ANNO") == anno &&
curr.get("CODNUM") == codnum)
n = curr.get_long("NDOC");
}
}
n++;
return n;
}
const TTipo_documento& TDocumento::tipo() const
{
const TString16 tipodoc(get("TIPODOC"));
CHECK(tipodoc.not_empty(), "Tipo documento nullo");
TTipo_documento * o = (TTipo_documento*)_tipi.objptr(tipodoc);
if (o == NULL)
{
o = new TTipo_documento(tipodoc);
_tipi.add(tipodoc, o);
}
return *o;
}
bool TDocumento::raggruppabile(const TDocumento& doc, TToken_string& campi) const
{
bool ok = raggruppabile() && doc.raggruppabile();
if (ok)
{
TString campo;
for (const char* c = campi.get(0); c && ok; c = campi.get())
{
campo = get(c);
ok &= campo == doc.get(c);
}
}
return ok;
}
void TDocumento::set_fields(TAuto_variable_rectype & rec)
{
if (get("TIPODOC").not_empty())
{
TTipo_documento & tipo_doc = (TTipo_documento &) tipo();
const TString16 tot_doc(tipo_doc.totale_doc());
for (const TFormula_documento * f = tipo_doc.first_formula(); f; f = tipo_doc.succ_formula())
{
TExpr_documento * exp = f->expr();
if (tot_doc == f->name())
{
TString work_tot_doc(tot_doc);
work_tot_doc.insert("_");
add_field(new TDocumento_variable_field(work_tot_doc, exp));
TExpr_documento * new_exp = new TExpr_documento(
format("%s + _BOLLI(%s)", (const char *) work_tot_doc,
(const char *) work_tot_doc), _numexpr, this);
add_field(new TDocumento_variable_field(f->name(), new_exp));
}
else
add_field(new TDocumento_variable_field(f->name(), exp));
if (exp)
exp->set_doc(this);
}
}
}
real TDocumento::imponibile() const
{
const TString16 field(tipo().imponibile());
if (field.not_empty())
return get_real(field);
else
{
real val;
for (int i = rows(); i > 0; i--)
val += ((TRiga_documento &) ((TDocumento *)this)->row(i)).imponibile();
return val;
}
}
real TDocumento::imposta() const
{
const TString16 field(tipo().imposta());
if (field.not_empty())
return get_real(field);
else
{
real val;
for (int i = rows(); i > 0; i--)
val += ((TRiga_documento &) ((TDocumento *)this)->row(i)).imposta();
return val;
}
}
real TDocumento::totale_doc() const
{
const TString16 field(tipo().totale_doc());
if (field.not_empty())
return get_real(field);
else
{
real r = imponibile() + imposta();
r += spese_incasso(r, in_valuta() ? 3 : 0);
r += bolli(r, in_valuta() ? 3 : 0);
return r;
}
}
real TDocumento::totale_netto() const
{
const TString16 field(tipo().totale_netto());
if (field.not_empty())
return get_real(field);
else
return imponibile() + imposta();
}
real TDocumento::basesconto() const
{
const TString16 field(tipo().basesconto());
if (field.not_empty())
return get_real(field);
else
return ZERO;
}
real TDocumento::spese() const
{
const TString16 field(tipo().spese());
if (field.not_empty())
return get_real(field);
else
return ZERO;
}
TPagamento & TDocumento::pagamento()
{
const TString16 codpag(get("CODPAG"));
if (codpag != _pag.code())
{
_pag.set_code(codpag);
_pag.read();
}
return _pag;
}
void TDocumento::put_str(const char* fieldname, const char* val)
{
TString v(val);
if (strcmp(fieldname, "TIPODOC") == 0 && TRectype::get("TIPODOC") != v)
{
TAuto_variable_rectype::put_str(fieldname, v);
reset_fields(*this);
set_fields(*this);
}
else
{
TAuto_variable_rectype::put_str(fieldname, v);
dirty_fields();
if (strcmp(fieldname, "SCONTOPERC") == 0)
set_riga_sconto();
}
}
void TDocumento::zero(const char * fieldname)
{
if (strcmp(fieldname, "TIPODOC") == 0)
reset_fields(*this);
TAuto_variable_rectype::zero(fieldname);
dirty_fields();
}
void TDocumento::zero(char c)
{
reset_fields(*this);
TAuto_variable_rectype::zero(c);
}
TRectype & TDocumento::operator =(const TRectype & r)
{
TRectype::operator=(r);
reset_fields(*this);
set_fields(*this);
return *this;
}
TRectype & TDocumento::operator =(const char * r)
{
TRectype::operator=(r);
reset_fields(*this);
set_fields(*this);
return *this;
}
///////////////////////////////////////////////////////////
// Lista di documenti
///////////////////////////////////////////////////////////
TDate TLista_documenti::num2date(char provv, int anno, const char* codnum, long num) const
{
TLocalisamfile doc(LF_DOC);
CHECK(num > 0, "Numero documento nullo.");
TDocumento::set_key(doc.curr(), provv, anno, codnum, num);
if (doc.read(_isgteq) != NOERR) // In caso d'errore ...
doc.last(); // prendi l'ultimo
return doc.get("DATADOC");
}
int TLista_documenti::read(char provv, char tipocf, long clifo, int anno,
TToken_string& tipidoc, TToken_string& statidoc,
const TDate& dd, const TDate& ad,
const char* codnum, long dn, long an)
{
CHECK(provv == 'D' || provv == 'P', "Provvisorio o Definitivo?");
CHECK(tipocf == 'C' || tipocf == 'F', "Il tipo deve essere Cliente o Fornitore");
CHECKD(clifo > 0L, "Codice cliente non valido", clifo);
CHECKD(anno > 1900, "Anno non valido: ", anno);
CHECK(!tipidoc.empty_items(), "Lista dei tipi documento vuota");
CHECK(!statidoc.empty_items(), "Lista degli stati documento vuota");
TRelation doc(LF_DOC);
TRectype start(LF_DOC), stop(LF_DOC);
start.put("TIPOCF", tipocf);
stop.put("TIPOCF", tipocf);
start.put("CODCF", clifo);
stop.put("CODCF", clifo);
start.put("PROVV", provv);
stop.put("PROVV", provv);
start.put("ANNO", anno);
stop.put("ANNO", anno);
if (dn > 0)
{
start.put("DATADOC", num2date(provv, anno, codnum, dn));
start.put("NDOC", dn);
}
else
{
if (dd.ok() && dd > botime)
start.put("DATADOC", dd);
}
if (an > 0)
{
stop.put("DATADOC", num2date(provv, anno, codnum, an));
stop.put("NDOC", an);
}
else
{
if (ad.ok() && ad < eotime)
stop.put("DATADOC", ad);
}
TString filter(16);
if (codnum && *codnum)
{
bool numfilter = FALSE;
if (start.get("DATADOC").empty())
numfilter = TRUE;
else
start.put("CODNUM", codnum);
if (stop.get("DATADOC").empty())
numfilter = TRUE;
else
stop.put("CODNUM", codnum);
if (numfilter)
filter << "CODNUM=\"" << codnum << '"';
}
TCursor cur(&doc, filter, 2, &start, &stop);
const TRectype& head = cur.curr();
_documenti.destroy();
for (cur = 0; cur.ok(); ++cur)
{
const TString16 tipodoc = head.get("TIPODOC");
const TString16 statodoc = head.get("STATO");
if (tipidoc.get_pos(tipodoc) >= 0 && statidoc.get_pos(statodoc) >= 0)
{
TDocumento* d = new TDocumento(head);
_documenti.add(d);
}
}
return _documenti.items();
}
int TLista_documenti::write(bool re) const
{
int err = NOERR;
for (int i = 0; i < _documenti.items() && err == NOERR; i++)
err = doc(i).write(re);
return err;
}
///////////////////////////////////////////////////////////
// Cliente/Fornitore per vendite
///////////////////////////////////////////////////////////
void TLista_clifo::TClifo::init(const TRectype& rec, const TRectype& ven)
{
_codice = rec.get_long(CLI_CODCF);
CHECK(_codice > 0, "Codice cliente nullo");
if (!ven.empty())
{
_agente = ven.get_long(CLI_CODAG);
_zona = ven.get_long(CLI_CODZONA);
}
else
_agente = _zona = 0;
}
bool TLista_clifo::TClifo::read(char tipo, long cod)
{
TRelation clifo(LF_CLIFO);
clifo.add(LF_CFVEN, "TIPOCF=TIPOCF|CODCF=CODCF");
TRectype& curr = clifo.curr();
curr.put(CLI_TIPOCF, tipo);
curr.put(CLI_CODCF, cod);
if (clifo.read() == NOERR)
init(curr, clifo.curr(LF_CFVEN));
else
zero();
return ok();
}
TLista_clifo::TClifo::TClifo(const TRectype& rec)
{
CHECK(rec.num() == LF_CLIFO, "Record non clienti");
const char tipo = rec.get_char(CLI_TIPOCF);
const long codice = rec.get_long(CLI_CODCF);
read(tipo, codice);
}
int TLista_clifo::leggi(long dc, long ac, long da, long aa, long dz, long az)
{
TRelation clifo(LF_CLIFO);
clifo.add(LF_CFVEN, "TIPOCF=TIPOCF|CODCF=CODCF");
TRectype start(LF_CLIFO), stop(LF_CLIFO);
start.put(CLI_TIPOCF, tipo());
if (dc > 0)
start.put(CLI_CODCF, dc);
stop.put(CLI_TIPOCF, tipo());
if (ac > 0)
stop.put(CLI_CODCF, ac);
TString filter(32);
if (da > 0)
filter << '(' << LF_CFVEN << "->" << CLI_CODAG << ">=" << da << ')';
if (aa > 0)
{
if (filter.not_empty()) filter << "&&";
filter << '(' << LF_CFVEN << "->" << CLI_CODAG << "<=" << aa << ')';
}
if (dz > 0)
{
if (filter.not_empty()) filter << "&&";
filter << '(' << LF_CFVEN << "->" << CLI_CODZONA << ">=" << dz << ')';
}
if (az > 0)
{
if (filter.not_empty()) filter << "&&";
filter << '(' << LF_CFVEN << "->" << CLI_CODZONA << "<=" << az << ')';
}
TCursor cur(&clifo, filter, 1, &start, &stop);
const TRectype& cli = cur.curr();
const TRectype& ven = cur.curr(LF_CFVEN);
for (cur = 0; cur.ok(); ++cur)
{
TClifo* c = new TClifo(cli, ven);
_clifo.add(c);
}
if (dc > 0 || ac > 0) ordina_per_codice(); else
if (da > 0 || aa > 0) ordina_per_agente(); else
if (dz > 0 || az > 0) ordina_per_zona();
return _clifo.items();
}
int TLista_clifo::sort_by_code(const TObject** o1, const TObject** o2)
{
TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1;
TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2;
const long d = c1->codice() - c2->codice();
return d == 0L ? 0 : (d > 0 ? +1 : -1);
}
int TLista_clifo::sort_by_agent(const TObject** o1, const TObject** o2)
{
TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1;
TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2;
const long d = c1->agente() - c2->agente();
return d == 0L ? 0 : (d > 0 ? +1 : -1);
}
int TLista_clifo::sort_by_zone(const TObject** o1, const TObject** o2)
{
TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1;
TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2;
const long d = c1->zona() - c2->zona();
return d == 0L ? 0 : (d > 0 ? +1 : -1);
}
int TLista_clifo::ordina_per_codice()
{
_clifo.sort(sort_by_code);
return _clifo.items();
}
int TLista_clifo::ordina_per_agente()
{
_clifo.sort(sort_by_agent);
return _clifo.items();
}
int TLista_clifo::ordina_per_zona()
{
_clifo.sort(sort_by_zone);
return _clifo.items();
}
int TLista_clifo::find(long cod) const
{
for (int i = items()-1; i >= 0; i--)
if (clifo(i).codice() == cod) break;
return i;
}
int TLista_clifo::add(long cod)
{
int pos = find(cod);
if (pos < 0)
{
TClifo* c = new TClifo(tipo(), cod);
pos = _clifo.add(c);
}
return pos;
}
///////////////////////////////////////////////////////////
// TElaborazione
///////////////////////////////////////////////////////////
TElaborazione::TElaborazione(const char* cod) : TRectype(LF_TABCOM)
{
settab("ELD");
if (cod && *cod)
read(cod);
}
int TElaborazione::read(const char* cod)
{
CHECK(cod && *cod, "Codice elaborazione nullo");
TTable eld("%ELD");
put("CODTAB", cod);
const int err = TRectype::read(eld);
if (err != NOERR)
yesnofatal_box("Codice elaborazione non valido: %s", cod);
return err;
}
///////////////////////////////////////////////////////////
// TFatturazione bolle
///////////////////////////////////////////////////////////
TFatturazione_bolle::TFatturazione_bolle(const char* cod)
: TElaborazione(cod)
{
}
void TFatturazione_bolle::tipi_validi(TToken_string& tipi) const
{
const TString& s2 = get("S2");
tipi.cut(0);
TString16 t;
for (int i = 0; i < 5; i++)
{
t = s2.mid(i*4, 4);
t.trim();
if (t.not_empty())
tipi.add(t);
}
CHECK(!tipi.empty_items(), "Nessun tipo documento valido");
}
void TFatturazione_bolle::stati_validi(TToken_string& stati) const
{
const TString& s7 = get("S7");
stati.cut(0);
TString16 s;
for (int i = 0; i < 5; i++)
{
s = s7.mid(i*4, 1);
s.trim();
if (s.not_empty())
stati.add(s);
}
CHECK(!stati.empty_items(), "Nessuno stato documento valido");
}
bool TFatturazione_bolle::raggruppa(TDocumento& doc_in, TDocumento& doc_out)
{
#ifdef DBG
const TString tipi = get("S2");
const TString& tipodoc = doc_in.tipo().codice();
for (int i = 0; i < 5; i++)
{
if (tipodoc == tipi.mid(i*4, 4))
break;
}
if (i >= 5)
{
NFCHECK("Tipo documento non valido: '%s'", (const char*)tipodoc);
return FALSE;
}
#endif
const char stato_finale_in = get_char("S4");
doc_in.stato(stato_finale_in);
const TString& tipo_out = get("S8");
doc_out.put("TIPODOC", tipo_out);
const char stato_finale_out = get_char("S9");
doc_out.stato(stato_finale_out);
if (gestione_riferimenti())
{
// Determina ed eventualmente crea la riga di riferimento
const int riga_rif = riferimenti_in_testa() ? 1 : doc_out.rows()+1;
if (riga_rif > doc_out.rows())
{
TRiga_documento& rout = doc_out.new_row();
rout.forza_sola_descrizione();
}
TRiga_documento& rout = doc_out[riga_rif];
// Costruisce la stringa di riferimento
TString riferimento(80);
riferimento = doc_in.tipo().riferimento();
if (riferimento.empty())
riferimento = doc_in.tipo().descrizione();
riferimento << " n. " << doc_in.numero();
riferimento << " del " << doc_in.data().string();
// Setta la descrizione se vuota
if (rout.get("DESCR").empty())
rout.put("DESCR", riferimento);
else
{
// Altrimenti aggiungi il riferimento al memo
TString memo(1024);
memo = rout.get("DESCEST");
if (memo.empty())
rout.put("DESCLUNGA", "X");
else
memo << '\n';
memo << riferimento;
rout.put("DESCEST", memo);
}
}
const bool ignora_desc = ignora_descrizioni();
TToken_string campi_riga(80);
const bool ragg_rig = raggruppa_righe();
if (ragg_rig)
{
campi_riga = "CODART|UMQTA"; // Uguali sempre
// Uguali opzionalmente
if (riga_uguale(0)) campi_riga.add("CODMAG");
if (riga_uguale(1)) campi_riga.add("CODIVA");
if (riga_uguale(2)) campi_riga.add("PREZZO|SCONTO");
}
for (int r = 1; r <= doc_in.rows(); r++)
{
const TRiga_documento& rin = doc_in[r];
const bool rindesc = rin.sola_descrizione(); // La riga di input e' descrittiva
if (ignora_desc && rindesc)
continue;
bool elaborata = FALSE;
// Raggruppo le righe se e' settato il falg di raggruppamento e
// se la riga non contiene solo una descrizione
if (ragg_rig && !rindesc) // Se devo raggruppare le righe ...
{
const int last = doc_out.rows();
for (int o = 1; o <= last; o++) // ... cerca una riga compatibile
{
TRiga_documento& rout = doc_out[o];
if (rout.sola_descrizione()) // Ignora le righe descrittive
continue;
if (rin.raggruppabile(rout, campi_riga)) // Se esiste una riga compatibile ...
{
rout += rin; // ... sommaci la quantita' ecc.
elaborata = TRUE; // Ricorda di averla gia' elaborata
break;
}
}
}
if (!elaborata) // Se la riga non e' stata gia' sommata ...
{
TRiga_documento& rout = doc_out.new_row(); // ... crea una riga nuova e ...
doc_out.copy_data(rout, rin); // ... copiaci tutti i campi della riga sorgente.
}
}
return TRUE;
}
bool TFatturazione_bolle::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out,
const TDate& data_elab)
{
bool ok = TRUE;
TToken_string campi_doc(128); // Lista di campi che devono essere uguali
campi_doc = "TIPOCF|CODCF|CODVAL|CODLIN"; // Uguali sempre
// Uguali opzionalmente
const char* cond[] = { "CAMBIO", "SCONTO", "TIPODOC", "CODNUM",
"CODPAG", "CODABIA|CODCABA", "CODLIST", "CODAG",
"CODSPMEZZO", "CODPORTO", "CAUSTRASP", "CODVETT1|CODVETT2|CODVETT3",
NULL };
for (int u = 0; cond[u]; u++)
if (doc_uguale(u)) campi_doc.add(cond[u]);
for (int id = 0; id < doc_in.items() && ok; id++)
{
TDocumento& campione = doc_in[id];
const int tot = doc_out.items();
int od = tot;
if (campione.raggruppabile()) // Se il documento ha il flag di raggruppabilita' ...
{
for (od = 0; od < tot; od++) // ... cerca un documento compatibile.
{
if (campione.raggruppabile(doc_out[od], campi_doc))
break;
}
}
if (od >= tot) // Se non ho trovato un documento compatibile ...
{ // ... creane uno nuovo (certamente compatibile)
const char provv = tipo_numerazione();
const int anno = campione.anno();
const TString codnum = codice_numerazione_finale();
TDocumento* new_doc = new TDocumento(provv, anno, codnum, -1);
// Copia i dati della testata
TDocumento::copy_data(new_doc->head(), campione.head());
new_doc->put("DATADOC", data_elab);
// Aggiungilo alla lista dei documenti in uscita
od = doc_out.add(new_doc);
}
ok = raggruppa(campione, doc_out[od]);
}
return ok;
}