ceb86a9c6b
cg2100.cpp Rifatta gestione pagamento immediato cg2102.cpp COrretto handler della data di registrazione cg2104.cpp Corretta gestione numero di riferimento partita cg2105.cpp Proposto in automatico l'importo dei pagamenti cg2200.cpp Azzerata ad ogni ciclo la maschera dei provisori cg3100.cpp Eliminati tutti gli accessi diretti alla tabella esercizi cg3600.cpp Aggiunta gestione e salvataggio colonne cglib04.cpp Tolti accessi diretti alla tabella degli esercizi pagament.cpp Corretta creazione nuove rate rispettando le classificazioni git-svn-id: svn://10.65.10.50/trunk@3985 c028cbd2-c16b-5b4b-a496-9718f37d4682
1890 lines
53 KiB
C++
Executable File
1890 lines
53 KiB
C++
Executable File
#include <applicat.h>
|
|
#include <utility.h>
|
|
#include "pagament.h"
|
|
|
|
#include "cg2100.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
|
|
|
|
inline void swap(int& x, int& y) {int tmp = x; x = y; y = tmp; }
|
|
|
|
int TPagamento::_rata_ifield(int n, int f) const
|
|
{
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
return t.get_int(f);
|
|
}
|
|
|
|
long TPagamento::_rata_lfield(int n, int f) const
|
|
{
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
return t.get_long(f);
|
|
}
|
|
|
|
real TPagamento::_rata_rfield(int n, int f) const
|
|
{
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
return real(t.get(f));
|
|
}
|
|
|
|
TDate TPagamento::_rata_dfield(int n, int f) const
|
|
{
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
return TDate(t.get(f));
|
|
}
|
|
|
|
const char* TPagamento::_rata_sfield(int n, int f) const
|
|
{
|
|
static char kak[16];
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
const char* k = t.get(f);
|
|
if (k != NULL)
|
|
strncpy(kak, k, 16);
|
|
else
|
|
kak[0] = '\0';
|
|
return kak;
|
|
}
|
|
|
|
void TPagamento::set_inizio(const TDate& d, bool rispetta_date)
|
|
{
|
|
_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 gironi 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 (_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 = real(100) / real(nact);
|
|
p.round(2);
|
|
|
|
if (_inited || (!_inited && rdiff == 1)) // se e' inited rdiff e' 2 per forza
|
|
{
|
|
real tot = _inited ? importo_da_dividere(FALSE) : real(100.0);
|
|
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, real(100.0));
|
|
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 = (100.0 * div) / tot;
|
|
|
|
real rem(tot);
|
|
real oem(oot);
|
|
real p(perc);
|
|
|
|
p.round(2);
|
|
|
|
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 or;
|
|
if (inv) or = importo_rata(first,TRUE) + oem;
|
|
set_imprata(first, r, FALSE);
|
|
if (inv) set_imprata(first, or, TRUE);
|
|
|
|
if (_inited && _tpr > 0 && _tpr < 4)
|
|
{
|
|
r -= importo_da_non_dividere(FALSE);
|
|
if (inv) or -= importo_da_non_dividere(TRUE);
|
|
}
|
|
set_percrata(first, 100 * 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 = (100.0 * div)/tot;
|
|
real rem(rest);
|
|
real oem(oest);
|
|
real p(perc);
|
|
|
|
p.round(2);
|
|
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 or;
|
|
if (inv) or = importo_rata(first,TRUE) + oem;
|
|
set_imprata(first, r, FALSE);
|
|
if (inv) set_imprata(first, or, TRUE);
|
|
if (_inited && _tpr > 0 && _tpr < 4)
|
|
r -= importo_da_non_dividere(FALSE);
|
|
set_percrata(first, 100 * r / tot);
|
|
}
|
|
else
|
|
{
|
|
const real r(perc_rata(first) + rem);
|
|
|
|
set_percrata(first, r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = first; sum < real(100.0); i++)
|
|
{
|
|
if ((real(100.0) - sum) < p)
|
|
p = real(100.0) - sum;
|
|
|
|
sum += p;
|
|
|
|
// if necessary add remainder on first one
|
|
if ((real(100.0) - sum) /* still */ < p)
|
|
{
|
|
real prc = perc_rata(first);
|
|
prc += real(100.0) - sum;
|
|
TToken_string& rt = rata(first);
|
|
rt.add(prc.string(),1),
|
|
sum = 100;
|
|
}
|
|
|
|
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++; }
|
|
|
|
// bool last = d.is_end_month() && inizio_scadenza() == 'M';
|
|
const bool last = inizio_scadenza() == 'M' || _datadoc.is_end_month();
|
|
|
|
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);
|
|
/*
|
|
d.set_end_month();
|
|
if (!last && dy < d.day())
|
|
d.set_day(dy);
|
|
*/
|
|
if (last)
|
|
d.set_end_month();
|
|
else
|
|
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 r)
|
|
{
|
|
TToken_string& tt = (TToken_string&)_rate[i];
|
|
tt.add(r.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)
|
|
{
|
|
real hm(importo_da_dividere(v));
|
|
|
|
if (i == 0 && _tpr > 3) return ZERO;
|
|
|
|
real tpay(importo_rata(i,v));
|
|
if (i == 0 && _tpr > 0 && _tpr < 4)
|
|
tpay -= importo_da_non_dividere(v);
|
|
real perc = tpay * 100.0 / hm;
|
|
perc.round(2);
|
|
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 *= real(100.0);
|
|
perc.round(2);
|
|
|
|
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(0.0);
|
|
|
|
int first = _tpr < 4 ? 0 : 1;
|
|
|
|
// check percentages & prepare slicer
|
|
for (int i = first; i < n_rate(); i++)
|
|
r += perc_rata(i);
|
|
r -= real(100.0);
|
|
real delta(0.005);
|
|
delta = delta * real(n_rate());
|
|
r = abs(r);
|
|
if (r > delta)
|
|
res |= P_RSUM;
|
|
|
|
|
|
if (_inited)
|
|
{
|
|
real tot;
|
|
|
|
for (int 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[] = { tipo+'0', toupper(ulc), '\0' };
|
|
TTable clr("%CLR");
|
|
clr.put("CODTAB", key);
|
|
|
|
const int err = clr.read();
|
|
if (err == NOERR)
|
|
o = clr.get("S0");
|
|
else if (ok != NULL)
|
|
*ok = FALSE;
|
|
}
|
|
if (*o == '\0')
|
|
{
|
|
switch (tipo)
|
|
{
|
|
case 0: o = "Altro pagamento"; break;
|
|
case 1: o = "Rimessa diretta o contanti"; break;
|
|
case 2: o = "Tratta"; break;
|
|
case 3: o = "Ricevuta Bancaria"; break;
|
|
case 4: o = "Cessione"; break;
|
|
case 5: o = "Paghero'"; break;
|
|
case 6: o = "Lettera di credito"; break;
|
|
case 7: o = "Tratta accettata"; break;
|
|
case 8: o = "Rapporti interban. diretti"; break;
|
|
case 9: o = "Bonifici"; break;
|
|
default: o = ""; 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);
|
|
TString oldulc = ulc_rata(last_rata);
|
|
int oldscad = scad_rata(last_rata);
|
|
TDate lastdate = data_rata(0);
|
|
int first = _tpr < 4 ? 0 : 1;
|
|
TString_array srate(_rate); // rate come erano
|
|
int warnscad = 0;
|
|
|
|
if (oldscad <= 0) oldscad = _int_rate;
|
|
if (oldtype <= 0) oldtype = _def_tpr;
|
|
|
|
bool exhausted = FALSE;
|
|
|
|
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 piu' 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 ? real(100.0) : 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 ? real(100.0) : 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 ? 2 : 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());
|
|
for (int 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 ? real(100.0) : 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
|
|
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 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 ? real(100.0) : 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
|
|
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 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;
|
|
TString16 last_ulc;
|
|
int last_scad;
|
|
|
|
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)
|
|
{
|
|
real other = importo_da_dividere(v);
|
|
|
|
const int first = _tpr > 3 ? 1 : 0;
|
|
|
|
for (int 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 * 100.0)/other; // percentuale
|
|
zpx.round(2);
|
|
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(100.0);
|
|
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));
|
|
}
|
|
|
|
for (int j = _rate.items() - 1; j >= first ; j--)
|
|
{
|
|
real rvl = perc_rata(j);
|
|
// togli pezxo 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;
|
|
}
|
|
t->zero(); t->put("CODTAB", _code);
|
|
if (t->read() != NOERR) return FALSE;
|
|
|
|
_rate.destroy();
|
|
|
|
// 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");
|
|
|
|
#ifdef USE_DEFAULT_INT_RATE
|
|
// if (_int_rate == 0) _int_rate = 30;
|
|
#endif
|
|
|
|
// 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;
|
|
|
|
for (int 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()
|
|
{
|
|
// 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;
|
|
|
|
main_app().begin_wait();
|
|
set_inizio(_datadoc);
|
|
|
|
for (int v = 0; v < (in_valuta() ? 2 : 1); v++)
|
|
{
|
|
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 = real(100.0)/real(rut); refrata.round(2);
|
|
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))/real(100.0);
|
|
|
|
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)/real(100.0));
|
|
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);
|
|
}
|
|
|
|
// risistema rate per scadenze fisse
|
|
adjust_fixed_scad();
|
|
main_app().end_wait();
|
|
}
|
|
|
|
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;
|
|
_cambio = 1.0;
|
|
|
|
_firstr = _secndr = ZERO; // Azzera importi in valuta
|
|
init_total(ib, im, sp, FALSE); // 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 bool era_valuta = _in_valuta;
|
|
|
|
_in_valuta = TRUE;
|
|
_cambio = c;
|
|
if (_cambio.sign() <= 0)
|
|
_cambio = real(1.0);
|
|
|
|
// setta regolarmente totali in lire
|
|
init_total(ibl, iml, spl, FALSE);
|
|
// ripeti tutto con la valuta
|
|
init_total(ib, im, sp, TRUE);
|
|
|
|
if (!era_valuta && _in_valuta)
|
|
adjust_perc_imp(TRUE, _rdiff, TRUE);
|
|
}
|
|
|
|
void TPagamento::init_total(const real& ib, const real& im, const real& sp, bool valuta)
|
|
{
|
|
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)
|
|
{
|
|
main_app().begin_wait();
|
|
|
|
if (_rate.items() == 0)
|
|
{
|
|
if (_tpr > 3)
|
|
add_rata(ZERO, sscad <= 0 ? 0 : sscad, _def_tpr, _def_ulc);
|
|
add_rata(real(100.0), sscad <= 0 ? (_tpr < 4 ? 0 : 30) : sscad, _def_tpr, _def_ulc);
|
|
_dirty = TRUE;
|
|
}
|
|
|
|
if (_inited)
|
|
{
|
|
// si istanzia uno sheet di primanota
|
|
for (int 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;
|
|
for (int 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
|
|
}
|
|
|
|
main_app().end_wait();
|
|
}
|
|
|
|
void TPagamento::adjust_fixed_scad()
|
|
{
|
|
if (!_inited) return;
|
|
|
|
for (int i = 0; i < n_rate(); i++)
|
|
{
|
|
TDate d = data_rata(i);
|
|
|
|
// riaggiusta se ci sono scadenze fissate
|
|
if (_fixd[0] != 0 || _fixd[1] != 0 || _fixd[2] != 0)
|
|
{
|
|
for (int 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);
|
|
}
|
|
}
|
|
|
|
TPagamento::TPagamento(const char* codtab, const char* data) :
|
|
_new(FALSE), _mcomm(FALSE), _imponlit(0.0), _imposlit(0.0),
|
|
_speselit(0.0), _cambio(1.0), _in_valuta(FALSE),
|
|
_code(codtab), _dirty(FALSE), _inited(FALSE),
|
|
_def_tpr(1), _def_ulc(""), _roundval(3), _int_rate(30), _tpr(0), _rdiff(FALSE),
|
|
_was_tpr4(FALSE), _roundlit(0), _imponval(0.0), _imposval(0.0), _speseval(0.0)
|
|
{
|
|
_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;
|
|
}
|