campo-sirio/cg/cgpagame.cpp

1996 lines
56 KiB
C++
Executable File
Raw Blame History

#include "cgpagame.h"
#include <diction.h>
#include <msksheet.h>
#include <recarray.h>
#include <tabutil.h>
#include "cg2100.h"
#include <cfven.h>
#include <mov.h>
#include <partite.h>
#include <scadenze.h>
#include <pagsca.h>
// se settato, si usa per rate nuove l'intervallo rate default (letto da tab. pagamenti)
#define USE_DEFAULT_INT_RATE 1
#define PERC_DECIMALS 2
inline void swap(int& x, int& y) {int tmp = x; x = y; y = tmp; }
int TPagamento::_rata_ifield(int n, int f) const
{
int v = 0;
_rate.row(n).get(f, v);
return v;
}
long TPagamento::_rata_lfield(int n, int f) const
{
long v = 0;
_rate.row(n).get(f, v);
return v;
}
real TPagamento::_rata_rfield(int n, int f) const
{
real v;
_rate.row(n).get(f, v);
return v;
}
TDate TPagamento::_rata_dfield(int n, int f) const
{
const TDate v = _rata_sfield(n, f);
return v;
}
/* Funzione sgradita al nuovo C ed anche a Guy: static bleah!
const char* TPagamento::_rata_sfield(int n, int f) const
{
TToken_string& t = (TToken_string&)_rate[n];
TString & s = get_tmp_string(30);
s = t.get(f);
return s;
}
*/
// Funzione digeribile dal nuovo C
const TString& TPagamento::_rata_sfield(int n, int f) const
{
const TToken_string& t = _rate.row(n);
TString& kak = get_tmp_string();
t.get(f, kak);
return kak;
}
void TPagamento::set_inizio(const TDate& d, bool rispetta_date)
{
if (_rate.items() == 0)
return;
_datadoc = d;
_inizio = d;
_inited = true;
// aggiusta _inizio secondo INSCAD; vedi mese commerciale etc.
if (_inscad == 'M')
_inizio.set_end_month();
else
{
if (_inscad == 'F' && _mcomm && _inizio.day() == 31)
_inizio.set_day(30);
}
TDate data(rispetta_date ? data_rata(0) : _inizio); // Aggiusta data iniziale con i giorni prima rata
if (!rispetta_date)
next_scad(data, scad_rata(0), _mcomm, 0);
bool dummy;
recalc_rate(0, false, NULL, NULL, data.string(), NULL, NULL, _rdiff, _mcomm, dummy);
}
void TPagamento::set_intervallo_rate(int in)
{
if (_mcomm && (in % 30) != 0)
{
if (yesno_box("E' specificato \"mese commerciale\". Si desidera annullarlo?"))
_mcomm = false;
else
return;
}
for (int i = 1; i < n_rate(); i++)
{
TToken_string& ts = rata(i);
ts.add(in, 0);
}
_int_rate = in;
_dirty = true;
}
void TPagamento::set_mese_commerciale(bool v, int& sscad)
{
_dirty = false;
if (_mcomm == v) return;
if (sscad < 0) sscad = 30;
if ((sscad % 30) != 0) sscad = 30 * ((sscad/30)+1);
set_intervallo_rate(sscad);
_mcomm = v;
}
void TPagamento::set_rate_differenziate(int v)
{
_dirty = false;
if ((int(_rdiff) ^ v) == 2) return;
if (v == 2 && (100 % n_rate()) == 0)
{
int p = 100 / n_rate();
for (int i = _tpr < 4 ? 0 : 1; i < n_rate(); i++)
{
TToken_string& tt = rata(i);
tt.add(p,1);
}
}
_rdiff = (v != 2);
_dirty = true;
}
void TPagamento::set_tipo_prima_rata(int v, int sscad)
{
_dirty = false;
if (_tpr == v) return;
if (!_inited)
{
if (v < 4 && _tpr > 3)
{
for (int i = n_rate() - 1; i > 0; i--)
{
TToken_string& tt = rata(i);
tt.add(scad_rata(i-1),0);
tt.add(tipo_rata(i-1),2);
tt.add(ulc_rata(i-1),5);
}
_rate.destroy(0, true);
}
else if ( _tpr < 4 && v > 3)
{
TToken_string* ttn = new TToken_string(32);
ttn->add(0, 0);
ttn->add(0, 1);
ttn->add(1, 2);
ttn->add("", 3);
ttn->add("", 4);
ttn->add("", 5);
_rate.insert(ttn,0);
for (int i = 0; i < (n_rate()-1); i++)
{
TToken_string& tt = rata(i);
tt.add(scad_rata(i+1),0);
tt.add(tipo_rata(i+1),2);
tt.add(ulc_rata(i+1), 5);
}
if (n_rate() == 2 && scad_rata(1) == 0)
{
// l'unica rata aveva scadenza 0; ci mettiamo n.giorni default
TToken_string& tt = rata(1);
tt.add(_int_rate, 0);
}
}
}
else
{
if ((_tpr > 3 && (v > 0 && v < 3)) || (v > 3 && (_tpr > 0 && _tpr < 3)))
{
// swap _firstr and _secndr
real tmp(_firstr);
_firstr = _secndr;
_secndr = tmp;
tmp = _firstl;
_firstl = _secndl;
_secndl = tmp;
}
}
_tpr = v;
_dirty = true;
}
void TPagamento::set_numero_rate(int n, int sscad, int rdiff)
{
if (n <= 0) return;
_dirty = false;
const int nr = n_rate();
const int first = _tpr < 4 ? 0 : 1;
real sum = 0.0;
int i = 0;
bool inv = in_valuta();
// diciamo che gli diciamo il numero giusto
if (first == 1 && n < 2) return;
int nact = first == 1 ? n - 1 : n;
real p = CENTO / real(nact);
p.round(PERC_DECIMALS);
if (_inited || (!_inited && rdiff == 1)) // se e' inited rdiff e' 2 per forza
{
real tot = _inited ? importo_da_dividere(false) : CENTO;
real oot;
if (inv)
oot = importo_da_dividere(true);
if (nact == 1)
{
if (_inited)
{
set_imprata(first, tot, false);
if (inv) set_imprata(first, oot, true);
}
set_percrata(first, CENTO);
if (_inited && _tpr > 0 && _tpr < 4)
{
set_imprata(first, importo_rata(first,false) + importo_da_non_dividere(false), false);
if (inv)
set_imprata(first, importo_rata(first,true) + importo_da_non_dividere(true), true);
}
i = first + 1; // per rimozione successiva
}
else
{
if (nr == first + 1)
{
// suddividi equamente e riaggiusta la percentuale di conseguenza
real div = tot / real(nact);
real oiv;
if (inv)
oiv = oot/real(nact);
if (_inited)
{
div.round(_roundlit);
if (inv) oiv.round(_roundval);
}
real perc = (CENTO * div) / tot;
real rem(tot);
real oem(oot);
real p(perc);
p.round(PERC_DECIMALS);
for (i = first; i < n; i++)
{
if (i > first)
{
int scd = sscad == -1 ? scad_rata(first) : sscad;
#ifdef USE_DEFAULT_INT_RATE
if (scd == 0)
scd = _int_rate;
#endif
add_rata(perc, scd, tipo_rata(0), ulc_rata(0));
}
if (_inited)
{
set_imprata (i, div, false);
rem -= importo_rata(i,false);
if (inv)
{
set_imprata (i, oiv, true);
oem -= importo_rata(i,true);
}
}
else
rem -= p;
set_percrata(i, perc);
}
if (_inited && _tpr > 0 && _tpr < 4)
{
set_imprata(0, importo_rata(0,false) + importo_da_non_dividere(false), false);
if (inv)
set_imprata(0, importo_rata(0,true) + importo_da_non_dividere(true), true);
}
if (rem != ZERO || oem != ZERO)
{
if (_inited)
{
real r(importo_rata(first,false) + rem);
real oldr;
if (inv) oldr = importo_rata(first,true) + oem;
set_imprata(first, r, false);
if (inv) set_imprata(first, oldr, true);
if (_inited && _tpr > 0 && _tpr < 4)
{
r -= importo_da_non_dividere(false);
if (inv) oldr -= importo_da_non_dividere(true);
}
set_percrata(first, CENTO * r / tot);
}
else
{
const real r(perc_rata(first) + rem);
set_percrata(first, r);
}
}
}
else if (nr > first + 1)
{
// dalla prima nota e' abilitato solo se rdiff == 2
// e' selezionato UGUALI: devo: lasciare la prima
// rata com'e' (a meno che non ce ne sia una sola) e
// suddividere il resto dell'importo tra le altre
real rfirst = _inited ? importo_rata(0,false) : perc_rata(0);
real ofirst;
if (inv)
ofirst = importo_rata(0,true);
if (_inited && _tpr > 0 && _tpr < 4)
{
rfirst -= importo_da_non_dividere(false);
if (inv)
ofirst -= importo_da_non_dividere(true);
}
real rest = tot - (_tpr >= 4 ? ZERO : rfirst);
real oest;
if (inv)
oest = oot - (_tpr >= 4 ? ZERO : ofirst);
real div = rest / real(nact - (first > 0 ? 0 : 1));
real oiv;
if (inv)
oiv = oest / real(nact - (first > 0 ? 0 : 1));
if (_inited)
{
div.round(_roundlit);
if (inv)
oiv.round(_roundval);
}
real perc = (CENTO * div)/tot;
real rem(rest);
real oem(oest);
real p(perc);
p.round(PERC_DECIMALS);
for (i = 1; i < n; i++)
{
if (i >= nr)
{
int scd = sscad == -1 ? scad_rata(first) : sscad;
#ifdef USE_DEFAULT_INT_RATE
if (scd == 0)
scd = _int_rate;
#endif
add_rata(perc, (sscad == -1 ? scad_rata(nr-1) : sscad),
tipo_rata(nr-1), ulc_rata(nr-1));
}
if (_inited)
{
set_imprata (i, div, false);
rem -= div;
if (inv)
{
set_imprata (i, oiv, true);
oem -= oiv;
}
}
else
rem -= p;
set_percrata(i, perc);
}
if (rem != ZERO)
{
if (_inited)
{
real r(importo_rata(first,false) + rem);
real oldr;
if (inv) oldr = importo_rata(first,true) + oem;
set_imprata(first, r, false);
if (inv) set_imprata(first, oldr, true);
if (_inited && _tpr > 0 && _tpr < 4)
r -= importo_da_non_dividere(false);
set_percrata(first, CENTO * r / tot);
}
else
{
const real r(perc_rata(first) + rem);
set_percrata(first, r);
}
}
}
}
}
else
{
for (i = first; sum < CENTO; i++)
{
if ((CENTO - sum) < p)
p = CENTO - sum;
sum += p;
// if necessary add remainder on first one
if ((CENTO - sum) /* still */ < p)
{
real prc = perc_rata(first);
prc += CENTO - sum;
TToken_string& rt = rata(first);
rt.add(prc.string(),1),
sum = CENTO;
}
int scd = i == 0 ? (i < nr ? scad_rata(0) : 0) :
(sscad == -1 ? (i < nr ? scad_rata(i) : scad_rata(nr-1)) : sscad);
#ifdef USE_DEFAULT_INT_RATE
if (i != 0 && scd == 0)
scd = _int_rate;
#endif
set_rata(i, real(p), scd, (i < nr ? tipo_rata(i) : tipo_rata(nr-1)), false);
}
}
// erase remaining
remove_rate_from(i);
if (_inited)
{
set_inizio(_datadoc, true);
adjust_perc(rdiff, inv);
}
adjust_fixed_scad();
_dirty = true;
}
void TPagamento::next_scad(TDate& d, int scad, bool mcomm, int rata)
{
if (mcomm && (rata > 0 || (scad % 30) == 0))
{
int nm = scad / 30;
int ny = nm / 12;
nm %= 12;
int newm = d.month() + nm;
if (newm > 12) { newm -= 12; ny++; }
int dy = d.day();
// la palla del febbraio & c. ???
if (rata > 1)
{
const TDate oldd(data_rata(rata-2));
if (oldd.day() > dy) dy = oldd.day();
}
d.set_day(1); // il giorno 1 ce l'hanno tutti
d.set_month(newm);
d.set_year(d.year()+ny);
// bool last = d.is_end_month() && inizio_scadenza() == 'M';
const bool last = inizio_scadenza() == 'M' || _datadoc.is_end_month();
/*
d.set_end_month();
if (!last && dy < d.day())
d.set_day(dy);
*/
if (last)
d.set_end_month();
else
{
int last_day = d.last_day(d.month(),d.year());
if (dy > last_day) dy = last_day;
d.set_day(dy);
}
}
else
{
d += scad;
}
}
void TPagamento::set_default_type(int type, bool change_existing)
{
_def_tpr = type;
if (change_existing)
{
for (int i = 0; i < n_rate(); i++)
{
TToken_string& tt = rata(i);
tt.add(type, 2);
}
_dirty = true;
}
}
void TPagamento::set_default_ulc(const char* ulc, bool change_existing)
{
_def_ulc = ulc;
if (change_existing)
{
for (int i = 0; i < n_rate(); i++)
{
TToken_string& tt = rata(i);
tt.add(ulc, 5);
}
_dirty = true;
}
}
void TPagamento::remove_rata(int i)
{
// non fa nessun ricalcolo, si limita ad impacchettare se necessario
_rate.destroy(i, true);
_dirty = true;
}
void TPagamento::remove_rate_from(int i)
{
// elimina dall'ultima a quella indicata (compresa)
for (int j = n_rate() - 1; j >= i; j--)
_rate.destroy(j);
_dirty = true;
}
TToken_string& TPagamento::add_rata()
{
// rata vuota, con -1 sulla scadenza per segnalare
TToken_string* tt = new TToken_string("-1| | | | | | | ");
_rate.add(tt);
_dirty = true;
return *tt;
}
TToken_string& TPagamento::add_rata(real perc, int day, int type, const char* ulc)
{
TToken_string* tt = new TToken_string(64);
tt->add(day); // scadenza
tt->add(perc.string()); // percentuale
tt->add(type); // tipo
tt->add(""); // data
tt->add(""); // importo valuta
tt->add(ulc); // ulc
tt->add(""); // ratapagata
tt->add(""); // importo lire
_rate.add(tt);
_dirty = true;
return *tt;
}
TToken_string& TPagamento::set_rata (int index, real perc, int day, int type,
bool val, const char* ulc, const char* imp, const char* data)
{
TToken_string* tt = (TToken_string*)_rate.objptr(index);
const bool nwr = (tt == NULL);
if (nwr) tt = new TToken_string(64);
tt->add(day,0); // scadenza
tt->add(perc.string(),1); // percentuale
tt->add(type,2); // tipo
tt->add(data == NULL ? "" : data, 3);
tt->add(imp == NULL ? "" : imp, val ? 4 : 7);
tt->add(ulc == NULL ? "" : ulc, 5);
if (!nwr)
{
if (index > _rate.items())
{
error_box("Rate non contigue");
delete tt;
}
}
else
{
_rate.add(tt,index);
_dirty = true;
}
return *tt;
}
void TPagamento::set_imprata(int i, const real& r, bool v)
{
TToken_string& tt = (TToken_string&)_rate[i];
tt.add(r.string(), v ? 4 : 7);
}
void TPagamento::set_percrata(int i, real perc)
{
TToken_string& tt = (TToken_string&)_rate[i];
perc.round(PERC_DECIMALS);
tt.add(perc.string(), 1);
}
void TPagamento::set_datarata(int i, const TDate & d)
{
TToken_string& tt = (TToken_string&)_rate[i];
tt.add((const char *) d, 3);
}
real TPagamento::recalc_percrata(int i, bool v)
{
if (i == 0 && _tpr > 3)
return ZERO;
const real hm = importo_da_dividere(v);
real tpay = importo_rata(i,v);
if (i == 0 && _tpr > 0 && _tpr < 4)
tpay -= importo_da_non_dividere(v);
const real perc = tpay * CENTO / hm;
set_percrata(i, perc);
return perc;
}
TToken_string& TPagamento::set_rata(int index, const real& impval, const real& implit,
const TDate& date, int type,const char* ulc, bool pagato)
{
// calcola percentuali e scadenze a partire dagli importi
TToken_string* tt = _rate.rowptr(index);
const int first = _tpr < 4 ? 0 : 1;
const bool nwr = (tt == NULL); // nuova rata
if (nwr) tt = new TToken_string(64);
const TDate oldd = index > 0 ? data_rata(index -1) : _inizio;
const long day = date - oldd;
const real toshare = importo_da_dividere(in_valuta());
real hm = in_valuta() ? impval : implit;
if (index == first && _tpr > 0 && _tpr < 4)
hm -= importo_da_non_dividere(in_valuta());
real perc = (_tpr > 3 && index == 0) ? ZERO : hm/toshare;
perc *= CENTO;
perc.round(PERC_DECIMALS);
tt->cut(0);
tt->add(day); // 0 - scadenza
tt->add(perc.string()); // 1 - percentuale
tt->add(type); // 2 - tipo
tt->add(date.string()); // 3 - data
tt->add(impval.string()); // 4 - importo
tt->add(ulc); // 5 - ulc(era?)
tt->add(pagato ? "X" : " "); // 6 - pagata
tt->add(implit.string()); // 7 - Importo in lire
if (!nwr)
{
if (index > _rate.items())
{
error_box("Rate non contigue");
delete tt;
}
}
else
{
_rate.add(tt, index);
_dirty = true;
}
return *tt;
}
word TPagamento::validate() const
{
word res = 0x0000;
int warnscad = 0;
real r;
int first = _tpr < 4 ? 0 : 1;
// check percentages & prepare slicer
for (int i = first; i < n_rate(); i++)
r += perc_rata(i);
r -= CENTO;
real delta(0.005);
delta = delta * real(n_rate());
r = abs(r);
if (r > delta)
res |= P_RSUM;
if (_inited)
{
real tot;
int i;
for (i = 0; i < n_rate(); i++)
{
const real tpay(tlit_rata(i));
if (tpay.is_zero())
res |= P_ZEROLIT;
tot += tpay;
}
tot.round(_roundlit);
// serve per fatture in valuta, onde evitare cazzi e canguri
real tmax = importo_da_dividere(false) + importo_da_non_dividere(false);
tmax.round(_roundlit);
if (tot != tmax) res |= P_TOTNCLIT;
if (in_valuta())
{
tot = 0.0;
for (int i = 0; i < n_rate(); i++)
{
const real tpay = tval_rata(i);
if (tpay.is_zero())
res |= P_ZEROVAL;
tot += tpay;
}
tot.round(_roundval);
// serve per fatture in valuta, onde evitare cazzi e canguri
real tmax = importo_da_dividere(true) + importo_da_non_dividere(true);
tmax.round(_roundval);
if (tot != tmax)
res |= P_TOTNCVAL;
}
// check errori date scadenze (se istanziate)
TDate d(data_rata(0));
if (d < _datadoc) // _inizio
res |= P_INIZIO;
for (i = 1; i < n_rate(); i++)
{
if (data_rata(i) < d)
{ res |= P_SCAD; break; }
if (data_rata(i) == d)
warnscad++;
d = data_rata(i);
}
}
if (warnscad && !yesno_box("N. %d rate cadono nello stesso giorno. Si desidera proseguire?", warnscad+1))
res |= P_SCAD;
return res;
}
void TPagamento::strerr(word err, TString& s)
{
s = "Errore:\n";
if (err & P_RSUM)
s << "- le percentuali non sommano a 100\n";
if (err & P_IMPNC)
s << "- le percentuali sono inconsistenti con gli importi\n";
if (err & P_SCAD)
s << "- le scadenze non sono consecutive\n";
if (err & P_INIZIO)
s << "- la prima rata e' antecedente alla data del documento (" << _datadoc << ")\n"; // _inizio
if (err & P_NEG)
s << "- l'importo dato e' inferiore al minimo possibile\n";
if (err & P_TROP)
s << "- l'importo dato e' superiore al massimo possibile\n";
if (err & P_TOTNCLIT)
{
const real tot = importo_da_dividere(false) + importo_da_non_dividere(false);
real imp;
for (int i = 0; i < n_rate(); i++)
imp += tlit_rata(i);
char pic[3] = ".0";
pic[1] += _roundlit;
s << "- la somma degli importi in lire (" << imp.string(pic);
s << ") e' diversa dal\ntotale del documento in lire(" << tot.string(pic) << ")\n";
}
if (err & P_TOTNCVAL)
{
const real tot = importo_da_dividere(true) + importo_da_non_dividere(true);
real imp;
for (int i = 0; i < n_rate(); i++)
imp += tval_rata(i);
char pic[3] = ".0";
pic[1] += _roundval;
s << "- la somma degli importi in valuta (" << imp.string(pic);
s << ") e' diversa dal\ntotale del documento in valuta(" << tot.string(pic) << ")\n";
}
if (err & P_MCOMM)
s << "- scadenze incompatibili con il mese commerciale\n";
if (err & P_ZEROLIT)
s << "- almeno una rata ha importo in lire uguale a zero\n";
if (err & P_ZEROVAL)
s << "- almeno una rata ha importo in valuta uguale a zero\n";
if (err & P_SCWIDE)
s << "- le scadenze sono troppo distanti\n";
if (err & P_TOOMANY)
s << "- il calcolo genera piu' di 999 rate!\n";
}
const char* TPagamento::desc_tpr() const
{
const char* o;
switch (_tpr)
{
case 0: o = "Totale su tutte le rate"; break;
case 1: o = "Tutte le imposte su 1a"; break;
case 2: o = "Tutte le spese su 1a"; break;
case 3: o = "Imposte + spese su 1a"; break;
case 4: o = "Solo imposte"; break;
case 5: o = "Solo spese"; break;
case 6: o = "Imposte + spese"; break;
default: o = ""; break;
}
return o;
}
const char* TPagamento::desc_tipo(int tipo, char ulc, bool* ok) const
{
const char* o = "";
if (ok != NULL) *ok = true;
if (ulc > ' ')
{
const char key[3] = { tipo+'0', toupper(ulc), '\0' };
o = cache().get("%CLR", key).get("S0");
}
if (*o == '\0')
{
switch (tipo)
{
case 0: o = TR("Altro pagamento"); break;
case 1: o = TR("Rimessa diretta o contanti"); break;
case 2: o = TR("Tratta"); break;
case 3: o = TR("Ricevuta Bancaria"); break;
case 4: o = TR("Cessione"); break;
case 5: o = TR("Paghero'"); break;
case 6: o = TR("Lettera di credito"); break;
case 7: o = TR("Tratta accettata"); break;
case 8: o = TR("Rapporti interban. diretti"); break;
case 9: o = TR("Bonifici"); break;
default: if (ok != NULL) *ok = false; break;
}
}
return o;
}
word TPagamento::recalc_rate(int row, bool is_perc_modified,
const char* new_value, const char* new_lire,
const char* scad, const char* typ, const char* ulc,
int rdiff, bool mcomm, bool& need_recalc)
// ricalcola le rate sulla base di parametri modificati sulla riga row
// parametri: tutti i const char* possono essere NULL, il che vuol dire
// che i dati corrispondenti non sono stati modificati;
// se new_value non e' NULL puo' essere la percentuale (e
// allora is_perc_modified e' true) o l'importo. Non e'
// possibile modificare entrambi; se succede viene data
// priorita' alla percentuale.
{
CHECK(!(!is_perc_modified && (new_value != NULL || new_lire != NULL) && !_inited),
"A'stronzo! E famme 'na pippa! Me dai n'importo che nun ce sta? Ma Vaffanculo!");
if (_rate.items() == 0) return P_OK;
real rsum(0.0), newv(0.0), rmax(0.0);
const int last_rata = _rate.items() - 1;
int oldtype = tipo_rata(last_rata);
TString8 oldulc = ulc_rata(last_rata);
int oldscad = scad_rata(last_rata);
TDate lastdate = data_rata(0);
const TString_array srate(_rate); // rate come erano
if (oldscad <= 0) oldscad = _int_rate;
if (oldtype <= 0) oldtype = _def_tpr;
for (int i = 0; i < srate.items(); i++)
{
if (i == row)
{
if (typ != NULL)
{
for (int k = 0; k < srate.items(); k++)
{
// deve farlo per tutte dalla 1 in poi se rdiff == 2,
// soltanto per row diversamente
if ((rdiff == 2 && row > 0 && k > 0) || k == row)
{
TToken_string& tt = rata(k);
TToken_string& ss = (TToken_string&)srate[k];
tt.add(typ,2);
ss.add(typ,2);
tt.add(ulc,5);
ss.add(ulc,5);
need_recalc = true;
// no error is possible
}
}
}
if (ulc != NULL)
{
for (int k = 0; k < srate.items(); k++)
{
// deve farlo per tutte dalla 1 in poi se rdiff == 2,
// soltanto per row diversamente
if ((rdiff == 2 && row > 0 && k > 0) || k == row)
{
TToken_string& tt = rata(k);
TToken_string& ss = (TToken_string&)srate[k];
tt.add(ulc,5);
ss.add(ulc,5);
need_recalc = true;
// no error is possible
}
}
}
if (scad != NULL)
{
// if !_inited scad e' il n. giorni, se no e' la rata
if (_inited)
{
TToken_string& tt = rata(row);
TToken_string& ss = (TToken_string&)srate[row];
lastdate = scad;
int lastscad = oldscad;
// controlla errore sulla data scadenza
if (i > 0)
{
oldscad = lastscad = (int)(lastdate - data_rata(i-1));
if (oldscad < 0l) return P_SCAD;
}
else
{
if (lastdate < _datadoc)
return P_INIZIO; // _inizio
lastscad = scad_rata(0);
}
tt.add(scad,3); tt.add(lastscad, 0);
ss.add(scad,3); ss.add(lastscad, 0);
// ricalcola rate successive: se si vuole modificarne solo una
// ci si fotte e si disabilita il ricalcolo
TDate ddd (lastdate);
for (int j = row+1; j < srate.items(); j++)
{
TToken_string& ttt = rata(j);
TToken_string& sss = (TToken_string&)srate[j];
next_scad(ddd,scad_rata(j), mcomm,j);
ttt.add(ddd.string(),3);
sss.add(ddd.string(),3);
need_recalc = true;
}
}
else
{
// nulla di speciale visto che si memorizza la derivata
long sc = atol(scad);
for (int i = 0; i < row; i ++)
sc -= scad_rata(i);
if (sc < 0) return P_SCAD;
if (row > 0 && sc == 0 &&
!yesno_box("Due o pi<70> rate cadranno nello stesso giorno. Si conferma l'immissione?"))
return P_SCAD;
if (sc > 10000L) return P_SCWIDE;
if (_mcomm && row > 0 && (sc % 30) != 0)
return P_MCOMM;
TToken_string& tt = rata(row);
TToken_string& ss = (TToken_string&)srate[row];
tt.add(sc,0);
ss.add(sc,0);
need_recalc = true;
}
}
if (new_value != NULL)
{
need_recalc = true;
// questa la subappaltiamo, per evitare l'inferno
return change_value(row, real(new_value), rdiff, is_perc_modified, mcomm, true);
}
if (new_lire != NULL)
{
need_recalc = true;
// questa pure la subappaltiamo, sempre per evitare l'inferno
return change_value(row, real(new_lire), rdiff, is_perc_modified, mcomm, false);
}
}
else // i != row modified
{
if (rdiff == 2)
continue;
if (scad != NULL)
{
// check sulle scadenze solo se si sono modificate
lastdate = data_rata(i);
if (_inited && i > 0)
{
if (data_rata(i) < data_rata(i-1))
return P_SCAD;
}
else if (_inited && lastdate < _inizio)
return P_INIZIO;
}
}
}
adjust_fixed_scad();
return P_OK;
}
word TPagamento::change_value(int rata, real user_val, int rdiff, bool is_perc,
bool mcomm, bool valuta)
{
word err = 0;
switch (rdiff)
{
case 1:
err = change_value_differenziate(rata, user_val, is_perc, valuta);
break;
case 2:
err = change_value_uguali(rata, user_val, is_perc, valuta);
break;
case 3:
err = change_value_uguali_prossima(rata, user_val, is_perc, valuta);
break;
case 4:
err = change_value_uguali_possible(rata, user_val, is_perc, valuta);
break;
}
if (!err)
{
// riaggiusta gli altri parametri se si sono create rate nuove
adjust_parameters(mcomm);
// risistema scadenze fisse se necessario
adjust_fixed_scad();
// riaggiusta le percentuali o gli importi rispetto al dato modificato
if (_inited)
{
// questa aggiusta anche l'eventuale importo in lire se si e' in valuta
// e si e' modificato l'importo in valuta
adjust_perc_imp(is_perc, rdiff, valuta);
// se era in valuta e ho modificato le percentuali aggiustalo anche in lire
if (valuta && is_perc) adjust_perc_imp(is_perc, rdiff, false);
}
_dirty = true;
}
return err;
}
// Sulla prima riga, se il tipo rata e > 0 il valore (importo o percentuale)
// puo' anche essere nullo, altrimenti deve essere positivo
bool TPagamento::sign_ok(const real& val, int row) const
{
const bool ok = val.sign() > (row == 0 && _tpr > 0 ? -1 : 0);
return ok;
}
// le quattro che seguono modificano le rate (solo importi o percentuali), e
// lasciano in last_old l'indice dell'ultima rata rimasta dalle vecchie che
// hanno adoperato
word TPagamento::change_value_differenziate(int row, real user_val, bool is_perc, bool v)
{
// importi totali, da non suddividere, da suddividere
real to_share = is_perc ? CENTO : importo_da_dividere(v);
real to_subtract = ZERO;
if (row == 0 && _tpr > 0 && _tpr < 4 && !is_perc)
to_subtract = importo_da_non_dividere(v);
real user_div = user_val - to_subtract;
const int first = _tpr > 3 ? 1 : 0;
_rdiff = true;
if (!sign_ok(user_div, row))
return P_NEG;
// togli rate gia' presenti
for (int i = first; i < row; i++)
{
to_share -= (is_perc ? perc_rata(i): importo_rata(i,v));
if (i == 0 && !is_perc && _tpr > 0 && _tpr < 4)
to_share += importo_da_non_dividere(v);
}
real remainder = to_share - user_div;
if (remainder.sign() < 0) return P_TROP;
const int tok_ind = is_perc ? 1 : (v ? 4 : 7);
rata(row).add(user_val.string(), tok_ind);
if (!remainder.is_zero())
{
if (n_rate() <= row + 1) add_rata();
rata(row+1).add(remainder.string(), tok_ind);
}
// elimina rate successive
remove_rate_from(remainder.is_zero() ? row +1 : row+2);
return 0;
}
word TPagamento::change_value_uguali(int row, real user_val, bool is_perc, bool v)
{
// importi totali, da non suddividere, da suddividere
real to_share = is_perc ? CENTO : importo_da_dividere(v);
real to_subtract = ZERO;
if (row == 0 && _tpr > 0 && _tpr < 4 && !is_perc)
to_subtract = importo_da_non_dividere(v);
real user_div = user_val - to_subtract;
real remainder = to_share - user_div;
const int tok_ind = is_perc ? 1 : (v ? 4 : 7);
const int first = _tpr > 3 ? 1 : 0;
_rdiff = false;
if (!sign_ok(user_div, row))
return P_NEG;
// la prima viene mantenuta uguale (vale solo per la 0 anche se _tpr > 4)
// se si modifica la prima, si suddivide l'importo rimanente tra tutte le
// altre e si aggiunge il residuo alla prima; il n. rate viene mantenuto
if (row == 0)
{
if (n_rate() == 1)
{
// se il numero rate e' 1 si aggiungono rate uguali a coprire l'importo
if ((to_share - user_div) < user_div) return 0;
real div = to_share / user_div;
real delta = to_share - (user_div * div.integer());
if (div > real(999.0)) return P_TOOMANY;
for (int i = 0; i < div.integer(); i++)
{
if (n_rate() <= i) add_rata();
rata(i).add(i == 0 ? user_val.string() : user_div.string(), tok_ind);
}
// add residuo
if (!delta.is_zero())
{
real tp = is_perc ? perc_rata(first) : importo_rata(first,v);
tp += delta;
rata(first).add(tp.string(), tok_ind);
}
}
else // n. rate > 1, modificata la rata 0: _tpr e' per forza < 4
{
real div = remainder / real(n_rate() - 1);
div.round(is_perc ? PERC_DECIMALS : round(v));
real delta = remainder - (div * real(n_rate() - 1));
rata(0).add(user_val.string(), tok_ind);
if (remainder.is_zero())
{
remove_rate_from(1);
return 0;
}
// ripartisci il resto
for (int i = 1; i < n_rate(); i++)
rata(i).add(div.string(), tok_ind);
if (!delta.is_zero())
{
user_val += delta;
rata(0).add(user_val.string(), tok_ind);
}
}
}
// dalla seconda in poi, tutte le rate devono essere uguali a quella indicata
// (a meno dell'importo non suddivisibile se c'e' (to_subtract); il numero rate
// puo' cambiare. Si rispetta il valore della rata 0
// se c'e' un residuo lo metto sulla prima calcolabile (dipende da _tpr)
else
{
real first_imp;
if (_tpr < 4)
{
first_imp = is_perc ? perc_rata(0) : importo_rata(0,v);
if (_tpr > 0 && !is_perc) first_imp -= importo_da_non_dividere(v);
}
real div = (to_share - first_imp)/user_val;
if (div < real(1.0)) return P_TROP;
if (div > real(999.0)) return P_TOOMANY;
real delta = (to_share - first_imp) - user_val * real(div.integer());
int i;
for (i = 1; i < div.integer()+1l; i++)
{
if (n_rate() <= i) add_rata();
rata(i).add(user_val.string(), tok_ind);
}
remove_rate_from(i);
if (!delta.is_zero())
{
real tp = is_perc ? perc_rata(first) : importo_rata(first,v);
tp += delta;
rata(first).add(tp.string(), tok_ind);
}
}
return 0;
}
word TPagamento::change_value_uguali_prossima(int row, real user_val, bool is_perc, bool v)
{
_rdiff = true;
// uguali finche' possibile da row in poi; residuo su first
// importi totali, da non suddividere, da suddividere
real to_share = is_perc ? CENTO : importo_da_dividere(v);
real to_subtract = ZERO;
if (row == 0 && _tpr > 0 && _tpr < 4 && !is_perc)
to_subtract = importo_da_non_dividere(v);
real user_div = user_val - to_subtract;
const int tok_ind = is_perc ? 1 : (v ? 4 : 7);
const int first = _tpr > 3 ? 1 : 0;
if (!sign_ok(user_div, row))
return P_NEG;
// togli rate gia' presenti
int i;
for (i = first; i < row; i++)
{
to_share -= (is_perc ? perc_rata(i): importo_rata(i,v));
if (i == 0 && !is_perc && _tpr > 0 && _tpr < 4)
to_share += importo_da_non_dividere(v);
}
real div = to_share/user_div;
if (div < real(1.0)) return P_TROP;
if (div > real(999.0)) return P_TOOMANY;
real delta = to_share - (user_div * div.integer());
for (i = row; i < (row + div.integer()); i++)
{
if (n_rate() <= i) add_rata();
rata(i).add(user_div.string(), tok_ind);
}
remove_rate_from(i);
if (!delta.is_zero())
{
real r = is_perc ? perc_rata(first) : importo_rata(first,v);
r += delta;
rata(first).add(r.string(), tok_ind);
}
return 0;
}
word TPagamento::change_value_uguali_possible(int row, real user_val, bool is_perc, bool v)
{
_rdiff = true;
// uguali finche' possibile da row in poi; residuo come rata a parte
real to_share = is_perc ? CENTO : importo_da_dividere(v);
real to_subtract = ZERO;
if (row == 0 && _tpr > 0 && _tpr < 4 && !is_perc)
to_subtract = importo_da_non_dividere(v);
real user_div = user_val - to_subtract;
const int tok_ind = is_perc ? 1 : (v ? 4 : 7);
const int first = _tpr > 3 ? 1 : 0;
if (!sign_ok(user_div, row))
return P_NEG;
// togli rate gia' presenti
int i;
for (i = first; i < row; i++)
{
to_share -= (is_perc ? perc_rata(i): importo_rata(i,v));
if (i == 0 && !is_perc && _tpr > 0 && _tpr < 4)
to_share += importo_da_non_dividere(v);
}
real div = to_share/user_div;
if (div < real(1.0)) return P_TROP;
if (div > real(999.0)) return P_TOOMANY;
real delta = to_share - (user_div * div.integer());
for (i = row; i < (row + div.integer()); i++)
{
if (n_rate() <= i) add_rata();
rata(i).add(user_div.string(), tok_ind);
}
if (!delta.is_zero())
{
if (n_rate() <= i) add_rata();
rata(i++).add(delta.string(), tok_ind);
}
remove_rate_from(i);
return 0;
}
void TPagamento::adjust_parameters(bool mcomm)
{
TDate last_date;
int last_type = 0;
TString16 last_ulc;
int last_scad = 0;
for (int i = 0; i < n_rate(); i++)
{
if (scad_rata(i) != -1)
{
last_date = data_rata(i);
last_type = tipo_rata(i);
last_ulc = ulc_rata(i);
last_scad = scad_rata(i);
}
else
{
TToken_string& r = rata(i);
#ifdef USE_DEFAULT_INT_RATE
r.add(last_scad == 0 ? _int_rate : last_scad, 0);
#else
r.add(last_scad, 0);
#endif
r.add(last_type, 2);
r.add(last_ulc, 5);
if (_inited)
{
#ifdef USE_DEFAULT_INT_RATE
next_scad(last_date, last_scad == 0 ? _int_rate : last_scad, mcomm, i);
#else
next_scad(last_date, last_scad, mcomm, i);
#endif
r.add(last_date, 3);
}
}
}
}
void TPagamento::adjust_perc(int rdiff, bool v)
{
const real other = importo_da_dividere(v);
if (other.is_zero())
return;
const int first = _tpr > 3 ? 1 : 0;
int j;
for (j = first; j < _rate.items(); j++)
{
real rvl = importo_rata(j,v);
// togli pezzo di troppo
if (j == first && _tpr > 0 && _tpr < 4)
rvl -= importo_da_non_dividere(v);
real zpx = (rvl * CENTO) / other; // percentuale
zpx.round(PERC_DECIMALS);
set_percrata(j, zpx);
}
if (in_valuta())
{
// riaggiusta l'importo rimanente
real tot = importo_da_dividere(!v);
TDistrib dt(tot); dt.set_dec(round(!v));
for (j = first; j < _rate.items(); j++)
{
real rvl = importo_rata(j,v);
// togli pezzo di troppo
if (j == first && _tpr > 0 && _tpr < 4)
rvl -= importo_da_non_dividere(v);
dt.add(rvl/other);
}
for (j = first; j < _rate.items(); j++)
{
real rvl = dt.get();
// aggiungi pezzo mancante
if (j == first && _tpr > 0 && _tpr < 4)
rvl += importo_da_non_dividere(!v);
set_imprata(j, rvl, !v);
}
}
}
void TPagamento::adjust_perc_imp(bool is_perc, int rdiff, bool v)
{
if (!is_perc)
{
adjust_perc(rdiff, v);
return;
}
real toshare(importo_da_dividere(v));
const real other = CENTO;
bool inv = in_valuta();
TDistrib dt(toshare, round(v));
const int first = _tpr > 3 ? 1 : 0;
TDistrib ot(0.0, 0); // slicer per l'importo non modificato
if (inv)
{
ot.init(importo_da_dividere(!v));
ot.set_dec(round(v));
}
int j;
for (j = _rate.items() - 1; j >= first ; j--)
{
real rvl = perc_rata(j);
// togli pezzo di troppo
real zpx = rvl/other; // percentuale
dt.add(zpx);
if (inv) ot.add(zpx);
}
real rem(toshare);
real oem(0.0);
if (inv) oem = importo_da_dividere(!v);
for (j = n_rate() - 1; j >= first ; j--)
{
real rfirst(0.0);
real ofirst(0.0);
TToken_string& tr = rata(j);
real rvl = dt.get();
rem -= rvl;
real ovl;
if (inv)
{
ovl = ot.get();
oem -= ovl;
}
if (j == first)
{
rfirst = rvl;
if (!rem.is_zero()) rfirst += rem;
if (inv)
{
ofirst = ovl;
if (!oem.is_zero()) ofirst += oem;
}
}
if (j == first && _tpr > 0 && _tpr < 4)
{
rfirst += importo_da_non_dividere(v);
if (inv)
ofirst += importo_da_non_dividere(!v);
}
tr.add((j == first ? rfirst.string() : rvl.string()), v ? 4 : 7);
if (inv)
tr.add((j == first ? ofirst.string() : ovl.string()), v ? 7 : 4);
}
}
bool TPagamento::read(TTable* t, TTable* r)
{
// puo' chiamarla chiunque
bool istnew = false;
if (t == NULL)
{
t = new TTable("%CPG");
istnew = true;
}
_rate.destroy();
t->zero(); t->put("CODTAB", _code);
if (t->read() != NOERR) return false;
// set everything
_rdiff = t->get_bool("B1");
_mcomm = t->get_bool("B0");
_tpr = t->get_int("S3");
_inscad = t->get_char("S1");
_code = t->get("CODTAB");
_name = t->get("S0");
_fixd[0] = t->get_int("I0");
_fixd[1] = t->get_int("I1");
_fixd[2] = t->get_int("I2");
_int_rate = t->get_int("I3");
// aggiusta _inizio secondo INSCAD; vedi mese commerciale etc.
if (_inscad == 'M')
_inizio.set_end_month();
else if (_inscad == 'F' && _mcomm && _inizio.day() == 31)
_inizio.set_day(30);
// leggi rate e scadenze
bool isrnew = false;
if (r == NULL)
{
r = new TTable("%RPG");
isrnew = true;
}
TString16 s;
for (int i = 0; ;i++)
{
r->zero(); s.format("%s%3d",(const char*)_code, i);
r->put("CODTAB", (const char*)s);
if (r->read() != NOERR)
break;
TToken_string* tt = new TToken_string(48);
tt->add((const char*)(r->get("I0"))); // scadenza
tt->add((const char*)(r->get("R0"))); // percentuale
tt->add((const char*)(r->get("I1"))); // tipo
// data e importo
TDate d = _inizio;
next_scad(d,(int)(r->get_long("I0")),_mcomm,i);
tt->add((const char*)d);
tt->add("");
tt->add(r->get("S1")); // ulteriore classificazione
_rate.add(tt);
}
if (istnew) delete t;
if (isrnew) delete r;
return true;
}
int TPagamento::write(TTable& r)
{
// Scrive soltanto le righe di pagamento; si assume sia stata chiamata da una
// relapp, che ha scritto il file principale
TString16 s;
int err = NOERR;
for (int i = 0; err == NOERR && i < n_rate(); i++)
{
r.zero(); s.format("%s%3d",(const char*)_code, i);
r.put("CODTAB", s);
r.put("I0", (long)scad_rata(i));
r.put("R0", perc_rata(i).string());
r.put("I1", (long)tipo_rata(i));
r.put("S1", ulc_rata(i));
err = r.write();
}
return err;
}
int TPagamento::rewrite(TTable& r)
{
TString16 s; int err = NOERR;
int i;
for (i = 0; err == NOERR && i < n_rate(); i++)
{
r.zero(); s.format("%s%3d",(const char*)_code, i);
r.put("CODTAB", s);
bool was = (r.read() == NOERR);
r.zero(); s.format("%s%3d",(const char*)_code, i);
r.put("CODTAB", (const char*)s);
r.put("I0", (long)scad_rata(i));
r.put("R0", perc_rata(i).string());
r.put("I1", (long)tipo_rata(i));
r.put("S1", ulc_rata(i));
err = (was ? r.rewrite() : r.write());
}
// erase possible rate > current n. rate
for (;err == NOERR;i++)
{
r.zero(); s.format("%s%3d",(const char*)_code, i);
r.put("CODTAB", (const char*)s);
if (r.read() == NOERR) err = r.remove();
else break;
}
return err;
}
int TPagamento::remove(TTable& r)
{
TString16 s; int err = NOERR;
for (int i = 0 ; err == NOERR; i++)
{
r.zero(); s.format("%s%3d", (const char*)_code, i);
r.put("CODTAB", s);
if (r.read() == NOERR)
err = r.remove();
else break;
}
return err;
}
void TPagamento::set_rate_auto()
{
TWait_cursor hourglass;
// vedi rate esistenti e tipo prima rata
// deve fare riferimento ad un tipo pagamento esistente
// e sensato
if (n_rate() == 0 || !_inited || (_tpr > 3 && n_rate() == 1))
return;
int first = _tpr > 3 ? 1 : 0;
set_inizio(_datadoc);
for (int va = 0; va < (in_valuta() ? 2 : 1); va++)
{
const bool v = va != 0;
real toslice = importo_da_dividere(v);
if (_tpr > 3)
set_imprata(0, importo_da_non_dividere(v), v);
real r1(0.0), ro(0.0);
if (!_rdiff)
{
const int rut = _tpr > 3 ? n_rate() - 1 : n_rate();
if (rut > 1) // Guy was here! Don't kill me for this
{
real refrata = CENTO/real(rut); refrata.round(PERC_DECIMALS);
if (perc_rata(first+1) == refrata) // tutte uguali nonostante perc arrotondate
{
ro = toslice / real(rut);
ro.round(round(v));
r1 = toslice - (ro * real(rut-1));
}
else // la prima e' diversa
{
// usa la percentuale per la prima rata
r1 = (toslice * perc_rata(first))/CENTO;
const real reminder = toslice - r1;
if (!reminder.is_zero())
{
ro = reminder/real(rut-1); ro.round(round(v));
r1 = (toslice - (ro*real(rut-1)));
}
}
}
else
r1 = toslice;
r1.round(round(v));
}
real rdi, rdsum;
for (int i = first; i < n_rate(); i++)
// setta le fette e le date di scadenza
{
if (_rdiff)
{
rdi = toslice*(perc_rata(i)/CENTO);
rdi.round(round(v));
if (i > first) rdsum += rdi;
}
set_imprata(i, _rdiff ? rdi : (i == first ? r1 : ro), v);
}
if (_rdiff)
set_imprata(first, toslice - rdsum, v);
// se e' nei primi tre casi, si somma l'importo da non dividere alla
// prima rata
if (_tpr > 0 && _tpr < 4)
set_imprata(0, importo_rata(0,v) + importo_da_non_dividere(v), v);
}
}
const real& TPagamento::importo_da_dividere(bool v) const
{
if (_tpr < 4) return v ? _firstr : _firstl;
else return v ? _secndr : _secndl;
}
const real& TPagamento::importo_da_non_dividere(bool v) const
{
if (_tpr < 4) return v ? _secndr : _secndl;
else return v ? _firstr : _firstl;
}
void TPagamento::set_total(const real& ib, const real& im, const real& sp)
{
_in_valuta = false;
_firstr = _secndr = ZERO; // Azzera importi in valuta
init_total(ib, im, sp, NULL); // setta regolarmente totali in lire
}
void TPagamento::set_total_valuta(const real& ib, const real& im, const real& sp, const real& c,
const real& ibl, const real& iml, const real& spl, const char* codval)
{
CHECKS(is_true_value(codval), "Valuta non valida ", codval);
const bool era_valuta = _in_valuta;
_in_valuta = true;
// setta regolarmente totali in lire
init_total(ibl, iml, spl, NULL);
// ripeti tutto con la valuta
init_total(ib, im, sp, codval);
if (!era_valuta && _in_valuta)
adjust_perc_imp(true, _rdiff, true);
}
void TPagamento::init_total(const real& ib, const real& im, const real& sp, const char* codval)
{
const bool valuta = (codval != NULL) && *codval && TCurrency::get_firm_val() != codval;
if (valuta)
{
const TCurrency cur(ZERO, codval);
_roundval = cur.decimals();
}
else
_roundlit = TCurrency::get_firm_dec();
const int round = valuta ? _roundval : _roundlit;
real& ibp = valuta ? _imponval : _imponlit;
real& imp = valuta ? _imposval : _imposlit;
real& spp = valuta ? _speseval : _speselit;
real& frs = valuta ? _firstr : _firstl;
real& scn = valuta ? _secndr : _secndl;
ibp = ib; ibp.round(round);
imp = im; imp.round(round);
spp = sp; spp.round(round);
_inited = true;
// istanzia _firstr e _secndr a seconda di _tpr
switch(_tpr)
{
case 0:
frs = ibp + imp + spp;
scn = 0.0;
break;
case 1:
scn = imp;
frs = ibp + spp;
break;
case 2:
scn = spp;
frs = ibp + imp;
break;
case 3:
scn = imp + spp;
frs = ibp;
break;
case 4:
scn = spp + ibp;
frs = imp;
break;
case 5:
scn = ibp + imp;
frs = spp;
break;
case 6:
scn = ibp;
frs = imp + spp;
break;
}
}
void TPagamento::set_sheet(TSheet_field& sf, int sscad)
{
TWait_cursor hourglass;
if (_rate.items() == 0)
{
if (_tpr > 3)
add_rata(ZERO, sscad <= 0 ? 0 : sscad, _def_tpr, _def_ulc);
add_rata(CENTO, sscad <= 0 ? (_tpr < 4 ? 0 : 30) : sscad, _def_tpr, _def_ulc);
_dirty = true;
}
if (_inited)
{
// si istanzia uno sheet di primanota
int i;
for (i = 0; i < n_rate(); i++)
{
TToken_string& ts = sf.row(i);
ts.add(data_rata(i), 0); // 0 - Data scadenza
if (in_valuta())
{
ts.add(tlit_rata(i).string(), 1); // 1 - Importo in lire
ts.add(tval_rata(i).string(), 2); // 2 - Importo in valuta
}
else
{
ts.add(tlit_rata(i).string(), 1); // 1 - Importo
ts.add("", 2);
}
ts.add(perc_rata(i).string(), 3); // 3 - Percentuale
const int tr = tipo_rata(i);
const char uc = ulc_rata(i)[0];
ts.add(tr, 4); // 4 - Tipo rata
ts.add(uc, 5); // 5 - Ulteriore classificazione
ts.add(desc_tipo(tr, uc), 6); // 6 - Descrizione tipo rata
}
for (int d = sf.items()-1; d >= i; d--)
sf.destroy(d, false);
sf.enable_column(2, in_valuta());
}
else
{
long scr = 0L;
int i;
for (i = 0; i < n_rate(); i++)
{
TToken_string& s = sf.row(i);
scr += scad_rata(i);
s = "";
s.add(scr);
s.add(perc_rata(i).string());
const int tr = tipo_rata(i);
const char uc = ulc_rata(i)[0];
s.add(tr);
s.add(uc);
s.add(desc_tipo(tr, uc));
}
for (int d = sf.items()-1; d >= i; d--)
sf.destroy(d, false);
}
const bool abilita = _tpr <= 3;
// disabilita campi da non toccare sulla prima rata
if (_inited)
{
// sf.enable_cell(0, 1, abilita); // importo
// sf.enable_cell(0, 2, abilita); // in valuta
// sf.enable_cell(0, 3, abilita); // percentuale
sf.force_update();
}
else
{
sf.enable_cell(0, 1, abilita); // percentuale
}
}
void TPagamento::adjust_fixed_scad()
{
if (!_inited) return;
const bool are_fixed = _fixd[0] != 0 || _fixd[1] != 0 || _fixd[2] != 0;
int i;
for (i = 0; i < n_rate(); i++)
{
TDate d = data_rata(i);
// riaggiusta se ci sono scadenze fissate
if (are_fixed)
{
int i;
for (i = 0; i < 3; i++)
{
if (_fixd[i] >= d.day())
{
if (d.last_day(d.month(), d.year()) >= _fixd[i])
d.set_day(_fixd[i]);
else
d.set_end_month();
break;
}
}
if (i == 3)
{
if (_fixd[0] > 0 && _fixd[0] < d.day())
{
d.set_day(_fixd[0]);
const bool chyear = d.month() == 12;
d.set_month(chyear ? 1 : d.month() + 1);
if (chyear) d.set_year(d.year() + 1);
}
}
}
TToken_string& tt = rata(i);
tt.add(d.string(), 3);
}
adjust_refused_scad();
}
void TPagamento::adjust_refused_scad()
{
if (_codcf <= 0L)
return;
CHECK(_tipocf == 'C' || _tipocf == 'F', "Bad tipocf in pagament");
TString8 codice;
codice << _tipocf << '|' << _codcf;
const TRectype& clifo = cache().get(LF_CFVEN, codice);
const TToken_string nonacceff(clifo.get(CFV_NONACCEFF), ';');
if (nonacceff.empty_items())
return;
const TToken_string nonscadeff(clifo.get(CFV_NONSCADEFF), ';');
TToken_string intervallo(12, ',');
TToken_string dalgiorno(5, '-'), algiorno(5, '-');
for (int i = 0; i < n_rate(); i++)
{
TTipo_pag tipo = tipo_rata(i);
if (tipo == _tratta ||
tipo == _ric_ban ||
tipo == _cessione ||
tipo == _paghero ||
tipo == _tratta_acc)
{
const TDate d = data_rata(i);
int inter = 0;
for (bool good = nonacceff.get(inter, intervallo);
good; good = nonacceff.get(++inter, intervallo))
{
intervallo.get(0, dalgiorno);
int gio = dalgiorno.get_int(0);
int mes = dalgiorno.get_int(1);
if (mes <= 0 || mes > 12) mes = 1;
int ann = d.year();
int max_gio = TDate::last_day(mes, ann);
if (gio <= 0) gio = 1; else
if (gio > max_gio) gio = max_gio;
const TDate frd(gio, mes, ann);
if (d < frd)
continue;
intervallo.get(1, algiorno);
gio = algiorno.get_int(0);
mes = algiorno.get_int(1);
if (mes <= 0 || mes > 12) mes = 1;
ann += (mes < frd.month()) ? 1 : 0;
max_gio = TDate::last_day(mes, ann);
if (gio <= 0 || gio > max_gio)
gio = max_gio;
const TDate tod(gio, mes, ann);
if (d > tod)
continue;
nonscadeff.get(inter, algiorno);
gio = algiorno.get_int(0);
mes = algiorno.get_int(1);
ann += (mes < tod.month()) ? 1 : 0;
if (mes <= 0 || mes > 12) mes = 1;
max_gio = TDate::last_day(mes, ann);
if (gio <= 0 || gio > max_gio)
gio = max_gio;
const TDate nd(gio, mes, ann);
TToken_string& tt = rata(i);
tt.add(nd.string(), 3);
break;
}
}
}
}
TPagamento::TPagamento(const char* codtab, const char* data) :
_code(codtab), _imponval(0.0), _imposval(0.0), _speseval(0.0),
_imponlit(0.0), _imposlit(0.0), _speselit(0.0), _new(false), _mcomm(false), // _cambio(1.0),
_rdiff(false), _tpr(0), _dirty(false), _inited(false), _roundlit(0), _roundval(3), _int_rate(30),
_def_tpr(1), _def_ulc(""), _was_tpr4(false), _in_valuta(false), _tipocf('C'), _codcf(0L)
{
_fixd[0] = _fixd[1] = _fixd[2] = 0;
if (data != NULL && *data)
_inizio = data;
else
_inizio = TDate(TODAY);
_datadoc = _inizio;
if (_code.blank() || !read())
_new = true;
}