1806 lines
48 KiB
C++
Executable File
1806 lines
48 KiB
C++
Executable File
#include <utility.h>
|
|
|
|
#include "pagament.h"
|
|
|
|
#include <mov.h>
|
|
#include <partite.h>
|
|
#include <scadenze.h>
|
|
#include <pagsca.h>
|
|
|
|
int TPagamento::_rata_ifield(int n, int f) const
|
|
{
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
return t.get_int(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[6];
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
strcpy(kak,t.get(f));
|
|
return kak;
|
|
}
|
|
|
|
|
|
bool TPagamento::ratapagata(int n)
|
|
{
|
|
TToken_string& t = (TToken_string&)_rate[n];
|
|
return t.items() > 6;
|
|
}
|
|
|
|
|
|
|
|
void TPagamento::set_intervallo_rate(int in)
|
|
{
|
|
_dirty = TRUE;
|
|
_int_rate = in;
|
|
if (_mcomm && (in % 30) != 0)
|
|
_mcomm = FALSE;
|
|
for (int i = 0; i < n_rate(); i++)
|
|
{
|
|
TToken_string& ts = rata(i);
|
|
ts.add(i == 0 ? (scad_rata(0) == 0 ? "0" : format("%d",in))
|
|
: format("%d",in), 0);
|
|
}
|
|
}
|
|
|
|
void TPagamento::set_mese_commerciale(bool v, int& sscad)
|
|
{
|
|
_dirty = FALSE;
|
|
if (_mcomm == v) return;
|
|
if (sscad == -1) 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 (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.add(NULL,0);
|
|
_rate.pack();
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
_tpr = v;
|
|
_dirty = TRUE;
|
|
}
|
|
|
|
void TPagamento::set_numero_rate(int n, int sscad)
|
|
{
|
|
_dirty = FALSE;
|
|
if (n == 0 || n == n_rate()) return;
|
|
|
|
real p = real(100) / real(n);
|
|
p.round(2);
|
|
int nr = n_rate();
|
|
int first = _tpr < 4 ? 0 : 1;
|
|
real sum = 0.0;
|
|
|
|
for (int 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;
|
|
}
|
|
|
|
set_rata(i, real(p),
|
|
i == 0 ? (i < nr ? scad_rata(0) : 0):
|
|
(sscad == -1 ? (i < nr ? scad_rata(i) : scad_rata(nr-1)) : sscad),
|
|
(i < nr ? tipo_rata(i) : tipo_rata(nr-1)));
|
|
}
|
|
// erase remaining
|
|
for (; i < nr; i++)
|
|
_rate.add(NULL,i);
|
|
_rate.pack();
|
|
|
|
_dirty = TRUE;
|
|
}
|
|
|
|
|
|
void TPagamento::next_scad(TDate& d, int scad, bool mcomm, int rata)
|
|
{
|
|
if (mcomm)
|
|
{
|
|
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';
|
|
|
|
int dy = d.day();
|
|
|
|
// la palla del febbraio & c.
|
|
if (rata > 1)
|
|
{
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
d += scad;
|
|
}
|
|
|
|
// riaggiusta la minchia 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]);
|
|
d.set_month(d.month() == 12 ? 1 : d.month() + 1);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
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.add(NULL,i);
|
|
_rate.pack();
|
|
_dirty = TRUE;
|
|
}
|
|
|
|
TToken_string& TPagamento::add_rata(real perc, int day, int type, const char* ulc)
|
|
{
|
|
TToken_string* tt = new TToken_string(16);
|
|
tt->add(day); // scadenza
|
|
tt->add(perc.string()); // percentuale
|
|
tt->add(type); // tipo
|
|
tt->add("");
|
|
tt->add("");
|
|
tt->add(ulc);
|
|
_rate.add(tt);
|
|
_dirty = TRUE;
|
|
return *tt;
|
|
}
|
|
|
|
TToken_string& TPagamento::set_rata (int index, real perc, int day, int type,
|
|
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(16);
|
|
|
|
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,4);
|
|
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, real r)
|
|
{
|
|
TToken_string& tt = (TToken_string&)_rate[i];
|
|
TDate d = _inizio;
|
|
|
|
for (int n = 0; n <= i; n++)
|
|
next_scad(d, scad_rata(n), _mcomm, n);
|
|
|
|
tt.add((const char*)d, 3);
|
|
tt.add(r.string(), 4);
|
|
}
|
|
|
|
TToken_string& TPagamento::set_rata(int index, const real& howmuch,
|
|
const TDate& date, int type,const char* ulc, bool pagato)
|
|
{
|
|
// calcola percentuali e scadenze a partire dagli importi
|
|
TToken_string* tt = (TToken_string*)_rate.objptr(index);
|
|
|
|
const bool nwr = (tt == NULL); // nuova rata
|
|
|
|
if (nwr) tt = new TToken_string(16);
|
|
|
|
TDate oldd = index > 0 ? data_rata(index -1) : _inizio;
|
|
int day = date - oldd;
|
|
real toshare(_tpr < 4 ? _firstr : _secndr);
|
|
real perc = (_tpr > 3 && index == 0) ? ZERO : howmuch/toshare;
|
|
perc *= real(100.0);
|
|
perc.round(2);
|
|
|
|
tt->add(day,0); // scadenza
|
|
tt->add(perc.string(),1); // percentuale
|
|
tt->add(type,2); // tipo
|
|
tt->add(date.string(),3);
|
|
tt->add(howmuch.string(),4);
|
|
tt->add(ulc,5);
|
|
if (pagato) tt->add("X",6);
|
|
|
|
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;
|
|
real r(0.0);
|
|
|
|
int first = _tpr < 4 ? 0 : 1;
|
|
real toshare(_tpr < 4 ? _firstr : _secndr);
|
|
TDistrib ds(toshare,0);
|
|
|
|
// check percentages & prepare slicer
|
|
for (int i = first; i < n_rate(); i++)
|
|
{
|
|
real p(perc_rata(i));
|
|
ds.add(p);
|
|
r += p;
|
|
}
|
|
|
|
if (r != real(100.0))
|
|
res |= P_RSUM;
|
|
|
|
|
|
if (_inited)
|
|
{
|
|
ds.init(toshare);
|
|
// check importi rate consistenti con la percentuale
|
|
for (int i = first; i < n_rate(); i++)
|
|
{
|
|
real r1(tpay_rata(i));
|
|
real r2(ds.get());
|
|
if (r1 != r2)
|
|
{ res |= P_IMPNC; break; }
|
|
}
|
|
|
|
// check errori date scadenze (se istanziate)
|
|
TDate d(data_rata(0));
|
|
if (d < _inizio)
|
|
res |= P_INIZIO;
|
|
for (i = 1; i < n_rate(); i++)
|
|
{
|
|
if (data_rata(i) <= d)
|
|
{ res |= P_SCAD; break; }
|
|
d = data_rata(i);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
void TPagamento::strerr(word err, TString& s)
|
|
{
|
|
s = "Errore:";
|
|
if (err & P_RSUM)
|
|
s << "\n Le percentuali non sommano a 100";
|
|
if (err & P_IMPNC)
|
|
s << "\n Le percentuali sono inconsistenti con gli importi";
|
|
if (err & P_SCAD)
|
|
s << "\n Le scadenze non sono consecutive";
|
|
if (err & P_INIZIO)
|
|
s << "\n La prima rata e' antecedente alla data movimento";
|
|
}
|
|
|
|
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 = "Spese + merce su 1a"; break;
|
|
case 5: o = "Merce + imposte su 1a"; break;
|
|
case 6: o = "Tutta la merce su 1a"; break;
|
|
default: o = ""; break;
|
|
}
|
|
return o;
|
|
}
|
|
|
|
const char* TPagamento::desc_tipo(int i) const
|
|
{
|
|
const char* o;
|
|
switch (i)
|
|
{
|
|
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 interbancari diretti"; break;
|
|
case 9: o = "Bonifici"; break;
|
|
case 10: o = "Altro pagamento"; break;
|
|
}
|
|
return o;
|
|
}
|
|
|
|
word TPagamento::recalc_rate(int row, bool is_perc_modified,
|
|
const char* new_value, const char* scad,
|
|
const char* typ, 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 && !_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);
|
|
int oldtype = tipo_rata(0);
|
|
int oldscad = scad_rata(0);
|
|
TDate lastdate = data_rata(0);
|
|
int first = _tpr < 4 ? 0 : 1;
|
|
TArray srate(_rate); // rate come erano
|
|
|
|
|
|
if (srate.items() > 1)
|
|
{
|
|
// calcola defaults per tipo pagamento e scadenza
|
|
// nel caso di rate nuove
|
|
oldscad = scad_rata(1);
|
|
}
|
|
|
|
if (oldscad == 0) oldscad = 30;
|
|
if (oldtype == 0) oldtype = 1;
|
|
|
|
if (new_value != NULL)
|
|
{
|
|
newv = new_value;
|
|
rmax = is_perc_modified? (real) 100.0 : (_tpr < 4 ? _firstr : _secndr);
|
|
if (newv > rmax) return P_RSUM;
|
|
}
|
|
|
|
bool exhausted = FALSE;
|
|
|
|
for (int i = first; i < srate.items(); i++)
|
|
{
|
|
if (i == row)
|
|
{
|
|
if (typ != NULL)
|
|
{
|
|
TToken_string& tt = rata(row);
|
|
TToken_string& ss = (TToken_string&)srate[row];
|
|
tt.add(typ,2);
|
|
ss.add(typ,2);
|
|
// 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;
|
|
// controlla errore sulla data scadenza
|
|
if (i > 0)
|
|
{
|
|
oldscad = (int)(lastdate - data_rata(i-1));
|
|
if (oldscad <= 0l) return P_SCAD;
|
|
}
|
|
else if (lastdate < _inizio) return P_INIZIO;
|
|
tt.add(scad,3);
|
|
ss.add(scad,3);
|
|
// 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& tt = rata(j);
|
|
TToken_string& ss = (TToken_string&)srate[j];
|
|
next_scad(ddd,scad_rata(j),mcomm,j);
|
|
tt.add(ddd.string(),3);
|
|
ss.add(ddd.string(),3);
|
|
need_recalc = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// nulla di speciale visto che si memorizza la derivata
|
|
int sc = atoi(scad);
|
|
for (int i = 0; i < row; i ++)
|
|
sc -= scad_rata(i);
|
|
if (sc < 0 || (row > 0 && sc == 0)) return P_SCAD;
|
|
if (_mcomm && (sc % 30) != 0) _mcomm = FALSE;
|
|
TToken_string& tt = rata(row);
|
|
TToken_string& ss = (TToken_string&)srate[row];
|
|
tt.add(sc,0);
|
|
ss.add(sc,0);
|
|
need_recalc = TRUE;
|
|
}
|
|
}
|
|
|
|
// here's the bell
|
|
if (new_value != NULL)
|
|
{
|
|
if (newv == ZERO || (rsum+newv) > rmax)
|
|
return P_RSUM;
|
|
// did not sforate
|
|
rsum += newv;
|
|
TToken_string& rt = rata(row);
|
|
// setta nuovo valore e ricalcola cio' che ne consegue
|
|
if (is_perc_modified) rt.add(new_value,1);
|
|
else rt.add(new_value,4);
|
|
// riaggiusta le rate rimanenti
|
|
real remainder(0.0); remainder = rmax - rsum;
|
|
if (!(exhausted = (remainder == real(0.0))))
|
|
{
|
|
// se inited e scelto UGUALI (2) occorre dividere in N e
|
|
// aggiungere il resto sulla 1a rata
|
|
// controlla se rdiff e' compatibile con
|
|
// i dati e se e' il caso riaggiusta
|
|
if (rdiff == 3 && !((remainder % newv.integer()) == ZERO))
|
|
rdiff = 2;
|
|
// *** 10/8/95: se uguali e non e' multiplo intero lo teniamo cosi' e poi
|
|
// *** aggiungiamo alla prima rata utile
|
|
// if (rdiff == 2 && !((rmax % newv.integer()) == ZERO))
|
|
// rdiff = 1;
|
|
_rdiff = (rdiff == 1 || rdiff == 3 || rdiff == 4);
|
|
|
|
// procedi
|
|
if (rdiff == 1)
|
|
{
|
|
// cancella tutte le rate successive, aggiungi un'unica rata
|
|
// con il resto dell'importo
|
|
if (row < (srate.items()-1))
|
|
{
|
|
TToken_string& trt = rata(row+1);
|
|
trt.add(remainder.string(), is_perc_modified ? 1 : 4);
|
|
for(int j = row+2; j < srate.items(); j++)
|
|
_rate.add(NULL,j);
|
|
}
|
|
else
|
|
{
|
|
// l'importante e' esagerare
|
|
for(int j = row+1; j < srate.items(); j++)
|
|
_rate.add(NULL,j);
|
|
|
|
TToken_string& trt = add_rata(is_perc_modified ? remainder : (real) 0.0,
|
|
oldscad, oldtype);
|
|
if (!is_perc_modified) trt.add(remainder.string(),4);
|
|
if (_inited)
|
|
{
|
|
TDate dd = data_rata(row);
|
|
next_scad(dd,oldscad,mcomm,row);
|
|
trt.add(dd.string(),3);
|
|
}
|
|
}
|
|
}
|
|
else // rate non differenziate (dall'inizio o da row)
|
|
{
|
|
// ripartisci l'importo nel numero necessario di rate per
|
|
// mantenere costante il valore
|
|
real sum(0.0);
|
|
if (_inited) lastdate = data_rata(rdiff == 2 ? first : row);
|
|
|
|
TDate dd(lastdate);
|
|
int type = oldtype;
|
|
int nscd = oldscad;
|
|
|
|
int frs = (rdiff == 3 || rdiff == 4) ? row+1 : first;
|
|
real mx = (rdiff == 3 || rdiff == 4) ? remainder : rmax;
|
|
|
|
// cancelliamo tutto, va'
|
|
for (int j = frs; j < srate.items(); j++)
|
|
_rate.add(NULL,j);
|
|
|
|
if (rdiff != 4)
|
|
for (j = frs; sum < mx; j++)
|
|
{
|
|
// TBI: qui mod se rdiff == 2
|
|
// se c'e' la vecchia rata si tengono i parametri
|
|
// altrimenti si calcolano
|
|
if (j < srate.items())
|
|
{
|
|
TToken_string& trt = (TToken_string&)srate[j];
|
|
if (_inited) dd = trt.get(3);
|
|
type = atoi(trt.get(2));
|
|
nscd = j == 0 ? 0 : atoi(trt.get(0));
|
|
if (type == 0) type = 1;
|
|
if (j > 0 && nscd == 0) nscd = oldscad;
|
|
if (_inited && dd == lastdate && j > 0)
|
|
next_scad(dd,nscd,mcomm,j);
|
|
}
|
|
else if (_inited)
|
|
{
|
|
if (dd <= botime) dd = lastdate;
|
|
next_scad(dd,nscd,mcomm,j);
|
|
}
|
|
else nscd = _int_rate;
|
|
|
|
TToken_string& ttr = set_rata(j, is_perc_modified ? newv : ZERO,
|
|
nscd, type);
|
|
if (_inited)
|
|
ttr.add(dd.string(), 3);
|
|
if (!is_perc_modified)
|
|
{
|
|
ttr.add(newv.string(),4);
|
|
}
|
|
if ((mx - sum) < newv)
|
|
{
|
|
// add remainder on first rate
|
|
newv += (mx - sum);
|
|
if (!is_perc_modified)
|
|
set_imprata(frs, newv);
|
|
else {
|
|
TToken_string& t = rata(frs);
|
|
t.add(newv.string(), 1);
|
|
}
|
|
remove_rata(j);
|
|
break;
|
|
}
|
|
// }
|
|
sum += newv;
|
|
}
|
|
else // rdiff == 4; uguali finche' possibile
|
|
{
|
|
bool basta = FALSE;
|
|
for (j = frs; ; j++)
|
|
{
|
|
// ultima rata puo' differire dalle precedenti
|
|
if (mx - sum <= newv)
|
|
{
|
|
newv = mx - sum;
|
|
basta = TRUE;
|
|
}
|
|
// se c'e' la vecchia rata si tengono i parametri
|
|
// altrimenti si calcolano
|
|
if (j < srate.items())
|
|
{
|
|
TToken_string& trt = (TToken_string&)srate[j];
|
|
if (_inited) dd = trt.get(3);
|
|
type = atoi(trt.get(2));
|
|
nscd = j == 0 ? 0 : atoi(trt.get(0));
|
|
if (type == 0) type = 1;
|
|
if (j > 0 && nscd == 0) nscd = oldscad;
|
|
if (_inited && dd == lastdate && j > 0)
|
|
next_scad(dd,nscd,mcomm,j);
|
|
}
|
|
else if (_inited) next_scad(dd,nscd,mcomm,j);
|
|
|
|
TToken_string& ttr = set_rata(j, is_perc_modified ? newv : ZERO,
|
|
nscd, type);
|
|
if (_inited)
|
|
ttr.add(dd.string(), 3);
|
|
if (!is_perc_modified)
|
|
ttr.add(newv.string(),4);
|
|
if (basta) break;
|
|
sum += newv;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else // exhausted
|
|
{
|
|
for(int j = row+1; j < srate.items(); j++)
|
|
_rate.add(NULL,j);
|
|
}
|
|
|
|
|
|
if (_inited)
|
|
{
|
|
// ricalcola il valore secondario (non modificato)
|
|
real toshare(100.0);
|
|
if (is_perc_modified)
|
|
toshare = (_tpr < 4 ? _firstr : _secndr);
|
|
TDistrib dt(toshare, is_perc_modified ? _round : 3);
|
|
|
|
for (int j = first; j < _rate.items(); j++)
|
|
{
|
|
real rvl = is_perc_modified ? perc_rata(j) : tpay_rata(j);
|
|
real zpx = rvl/rmax; // percentuale
|
|
dt.add(zpx);
|
|
}
|
|
for (j = first; j < _rate.items(); j++)
|
|
{
|
|
TToken_string& tr = rata(j);
|
|
real rvl = dt.get();
|
|
tr.add(rvl.string(), is_perc_modified ? 4 : 1);
|
|
}
|
|
|
|
// se e' il caso aggiungi l'importo fisso sulla prima rata
|
|
if (_inited && _tpr > 0 && _tpr < 4)
|
|
{
|
|
TToken_string& tr = rata(0);
|
|
real tot = tpay_rata(0) + _firstr;
|
|
tr.add(tot.string(), 4);
|
|
}
|
|
|
|
}
|
|
|
|
need_recalc = TRUE;
|
|
return P_OK;
|
|
} // new_value != NULL
|
|
}
|
|
else // i != row modified
|
|
{
|
|
if (i > 0 && !((perc_rata(i-1) == perc_rata(i))))
|
|
{
|
|
if (rdiff == 2) rdiff = 1;
|
|
_rdiff = FALSE;
|
|
}
|
|
if (is_perc_modified)
|
|
rsum += perc_rata(i);
|
|
else
|
|
rsum += tpay_rata(i);
|
|
|
|
lastdate = data_rata(i);
|
|
oldtype = tipo_rata(i);
|
|
oldscad = scad_rata(i);
|
|
if (_inited && i > 0)
|
|
{
|
|
if (data_rata(i) <= data_rata(i-1))
|
|
return P_SCAD;
|
|
}
|
|
else if (lastdate < _inizio)
|
|
return P_INIZIO;
|
|
}
|
|
}
|
|
|
|
return P_OK;
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
// set everything
|
|
_rdiff = t->get_bool("B1");
|
|
_mcomm = t->get_bool("B0");
|
|
_tpr = atoi(t->get("S3"));
|
|
_inscad = *((const char*)(t->get("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");
|
|
|
|
// TBI aggiusta _inizio secondo INSCAD; vedi mese commerciale etc.
|
|
if (_inscad == 'M')
|
|
{
|
|
if (_mcomm) _inizio.set_month(_inizio.month() == 2 ? 28 : 30);
|
|
else _inizio.set_end_month();
|
|
}
|
|
else if (_inscad == 'F' && _mcomm && _inizio.month() == 31)
|
|
_inizio.set_month(30);
|
|
|
|
// leggi rate e scadenze
|
|
bool isrnew = FALSE;
|
|
if (r == NULL)
|
|
{
|
|
r = new TTable("%RPG");
|
|
isrnew = TRUE;
|
|
}
|
|
TString s(16);
|
|
|
|
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(16);
|
|
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"));
|
|
_slicer.add((real)r->get("R0"));
|
|
_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
|
|
|
|
TString s(16); 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", (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 = r.write();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int TPagamento::rewrite(TTable& r)
|
|
{
|
|
TString s(16); 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", (const char*)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 rates > current n. rates
|
|
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)
|
|
{
|
|
TString s(16); int err = NOERR;
|
|
for (int i = 0 ; 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;
|
|
}
|
|
|
|
void TPagamento::set_rate_auto()
|
|
{
|
|
// vedi rate esistenti e tipo prima rata
|
|
// deve fare riferimento ad un tipo pagamento esistente
|
|
// e sensato
|
|
int first = 0;
|
|
|
|
real toslice = _firstr;
|
|
|
|
if (n_rate() == 0 || !_inited || (_tpr > 3 && n_rate() == 1)) return;
|
|
if (_tpr > 3) // ripartisci _firstr su tutte le rate
|
|
{
|
|
first = 1;
|
|
toslice = _secndr;
|
|
}
|
|
|
|
_slicer.init(toslice);
|
|
|
|
if (_tpr > 3)
|
|
// prima rata obbligatoria
|
|
set_imprata(0, _firstr);
|
|
|
|
// se rate uguali dividi l'importo totale per il numero di rate
|
|
real r1(0.0), ro(0.0);
|
|
if (!_rdiff)
|
|
{
|
|
int rut = _tpr > 3 ? n_rate() - 1 : n_rate();
|
|
ro = toslice/real(rut); ro.trunc(_round);
|
|
r1 = ro + (toslice - (ro*real(rut)));
|
|
}
|
|
|
|
for (int i = first; i < n_rate(); i++)
|
|
// setta le fette e le date di scadenza
|
|
set_imprata(i, _rdiff ? _slicer.get() : (i == first ? r1 : ro));
|
|
|
|
// se e' nei primi tre casi, si somma l'importo da non dividere alla
|
|
// prima rata
|
|
if (_tpr > 0 && _tpr < 4)
|
|
set_imprata(0, tpay_rata(0) + _firstr);
|
|
}
|
|
|
|
|
|
|
|
void TPagamento::set_total(const real& imponibile, const real& imposta, const real& spese)
|
|
{
|
|
_imponibile = imponibile;
|
|
_imposta = imposta;
|
|
_spese = spese;
|
|
_inited = TRUE;
|
|
|
|
// istanzia _firstr e _secndr a seconda di _tpr
|
|
switch(_tpr)
|
|
{
|
|
case 0:
|
|
_firstr = _imponibile + _imposta + _spese;
|
|
_secndr = 0.0;
|
|
break;
|
|
case 1:
|
|
_firstr = _imposta;
|
|
_secndr = _imponibile + _spese;
|
|
break;
|
|
case 2:
|
|
_firstr = _spese;
|
|
_secndr = _imposta + _imponibile;
|
|
break;
|
|
case 3:
|
|
_firstr = _imposta + _spese;
|
|
_secndr = _imponibile;
|
|
break;
|
|
case 4:
|
|
_firstr = _spese + _imponibile;
|
|
_secndr = _imposta;
|
|
break;
|
|
case 5:
|
|
_firstr = _imponibile + _imposta;
|
|
_secndr = _spese;
|
|
break;
|
|
case 6:
|
|
_firstr = _imponibile;
|
|
_secndr = _imposta + _spese;
|
|
break;
|
|
}
|
|
|
|
real toslice = _tpr > 1 ? _secndr : _firstr;
|
|
|
|
_slicer.init(toslice, TRUE);
|
|
|
|
for (int i = 0; i < _rate.items(); i++)
|
|
{
|
|
TToken_string& t = (TToken_string&)_rate[i];
|
|
real rr(t.get(1));
|
|
_slicer.add(rr);
|
|
}
|
|
}
|
|
|
|
|
|
void TPagamento::set_sheet(TSheet_field& sf, int sscad)
|
|
{
|
|
sf.destroy(-1);
|
|
if (_inited && _rate.items() > 0)
|
|
{
|
|
// si istanzia uno sheet di primanota
|
|
for (int i = 0; i < n_rate(); i++)
|
|
{
|
|
TToken_string& ts = sf.row(-1);
|
|
// istanzia, o stronzo
|
|
ts.add((const char*)data_rata(i));
|
|
ts.add(perc_rata(i).string());
|
|
ts.add(tpay_rata(i).string());
|
|
ts.add(tipo_rata(i));
|
|
ts.add(desc_tipo(tipo_rata(i)));
|
|
if (ratapagata(i))
|
|
{
|
|
sf.disable_cell(1,1); // percentuale
|
|
sf.disable_cell(1,2); // importo
|
|
}
|
|
}
|
|
}
|
|
else if (_rate.items() > 0) // not inited: set edit sheet
|
|
{
|
|
for (int i = 0, scr = 0; i < n_rate(); i++)
|
|
{
|
|
TToken_string& s = sf.row(-1);
|
|
scr += scad_rata(i);
|
|
s.add(scr);
|
|
s.add(perc_rata(i).string());
|
|
s.add(tipo_rata(i));
|
|
s.add(desc_tipo(tipo_rata(i)));
|
|
s.add(ulc_rata(i));
|
|
}
|
|
}
|
|
else // new: set with 1 or 2 rates according to tpr
|
|
{
|
|
if (_tpr > 3)
|
|
add_rata(ZERO, sscad == -1 ? 0 : sscad, _def_tpr, _def_ulc);
|
|
add_rata(real(100.0), sscad == -1 ? (_tpr < 4 ? 0 : 30) : sscad, _def_tpr, _def_ulc);
|
|
|
|
_dirty = TRUE;
|
|
|
|
for (int i = 0, scr = 0; i < n_rate(); i++)
|
|
{
|
|
TToken_string& s = sf.row(-1);
|
|
scr += scad_rata(i);
|
|
s.add(scr);
|
|
s.add(perc_rata(i).string());
|
|
s.add(tipo_rata(i));
|
|
s.add(desc_tipo(tipo_rata(i)));
|
|
s.add(ulc_rata(i));
|
|
}
|
|
}
|
|
if (_tpr > 3)
|
|
{
|
|
// disabilita campi da non toccare sulla prima rata
|
|
if (_inited)
|
|
{
|
|
sf.disable_cell(0,1); // percentuale
|
|
sf.disable_cell(0,2); // importo
|
|
}
|
|
else
|
|
{
|
|
sf.disable_cell(0,1); // percentuale
|
|
}
|
|
}
|
|
sf.force_update();
|
|
}
|
|
|
|
TPagamento::TPagamento(const char* codtab, const char* data) :
|
|
_slicer(0.0,0), _new(FALSE), _imponibile(0.0), _imposta(0.0),
|
|
_spese(0.0), _code(codtab), _dirty(FALSE), _inited(FALSE),
|
|
_def_tpr(1), _def_ulc(""), _round(0), _int_rate(30)
|
|
{
|
|
_fixd[0] = _fixd[1] = _fixd[2] = 0;
|
|
if (data != NULL)
|
|
_inizio = data;
|
|
if (_code.blank() || !read())
|
|
_new = TRUE;
|
|
// if (_new && data != NULL) error_box("Modalita' pagamento inesistente");
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TTree_rectype
|
|
///////////////////////////////////////////////////////////
|
|
|
|
TTree_rectype::TTree_rectype(const TRectype& testa, const TRectype& riga, const char* num)
|
|
: TRectype(testa), _recarr(riga, num)
|
|
{
|
|
}
|
|
|
|
TTree_rectype::TTree_rectype(int testa, int riga, const char* num)
|
|
: TRectype(testa), _recarr(riga, num)
|
|
{
|
|
}
|
|
|
|
TTree_rectype::TTree_rectype(const TTree_rectype& t)
|
|
: TRectype(t), _recarr(t._recarr)
|
|
{
|
|
}
|
|
|
|
|
|
TObject* TTree_rectype::dup() const
|
|
{
|
|
TTree_rectype* r = new TTree_rectype(*this);
|
|
return r;
|
|
}
|
|
|
|
void TTree_rectype::copy_key_to_row(TRectype& row) const
|
|
{
|
|
const int numkey = 0; // Memento! Gli indici delle chiavi partono da zero!
|
|
RecDes* recd = rec_des(); // Descrizione del record della testata
|
|
|
|
row.zero();
|
|
for (int i = 0; i < recd->Ky[numkey].NkFields; i++)
|
|
{
|
|
const KeyDes& kd = recd->Ky[numkey];
|
|
const int nf = kd.FieldSeq[i] % MaxFields;
|
|
const RecFieldDes& rf = recd->Fd[nf];
|
|
const char* name = rf.Name;
|
|
const TString& val = get(name);
|
|
row.put(name, val);
|
|
}
|
|
}
|
|
|
|
int TTree_rectype::fill_array()
|
|
{
|
|
TRectype* row = (TRectype*)_recarr.key().dup();
|
|
copy_key_to_row(*row);
|
|
const int err = _recarr.read(row);
|
|
return err;
|
|
}
|
|
|
|
|
|
int TTree_rectype::read(TBaseisamfile& f, word op)
|
|
{
|
|
int err = TRectype::read(f, op);
|
|
if (err == NOERR)
|
|
fill_array();
|
|
else
|
|
_recarr.destroy_rows();
|
|
return err;
|
|
}
|
|
|
|
int TTree_rectype::next(TBaseisamfile& f)
|
|
{
|
|
int err = TRectype::next(f);
|
|
if (err == NOERR)
|
|
fill_array();
|
|
else
|
|
_recarr.destroy_rows();
|
|
return err;
|
|
}
|
|
|
|
int TTree_rectype::write(TBaseisamfile& f) const
|
|
{
|
|
int err = TRectype::write(f);
|
|
if (err == NOERR)
|
|
err = _recarr.write();
|
|
return err;
|
|
}
|
|
|
|
int TTree_rectype::rewrite(TBaseisamfile& f) const
|
|
{
|
|
int err = TRectype::rewrite(f);
|
|
if (err == NOERR)
|
|
err = _recarr.rewrite();
|
|
return err;
|
|
}
|
|
|
|
int TTree_rectype::remove(TBaseisamfile& f)
|
|
{
|
|
int err = TRectype::remove(f);
|
|
if (err == NOERR)
|
|
err = _recarr.remove();
|
|
return err;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TRiga_scadenze
|
|
///////////////////////////////////////////////////////////
|
|
|
|
TRiga_scadenze::TRiga_scadenze(TRiga_partite* r)
|
|
: TTree_rectype(LF_SCADENZE, LF_PAGSCA, "NRIGP"), _riga(r)
|
|
{
|
|
CHECK(_riga, "Riga nulla");
|
|
}
|
|
|
|
TRiga_scadenze::TRiga_scadenze(const TRiga_scadenze& s)
|
|
: TTree_rectype(s), _riga(s._riga)
|
|
|
|
{
|
|
CHECK(_riga, "Riga nulla");
|
|
}
|
|
|
|
TPartita& TRiga_scadenze::partita() const
|
|
{
|
|
return riga().partita();
|
|
}
|
|
|
|
|
|
// Controlla se la rata e' in valuta
|
|
bool TRiga_scadenze::in_valuta() const
|
|
{
|
|
return get(SCAD_CODVAL).not_empty();
|
|
}
|
|
|
|
// Controlla se la rata e' stata completamente pagata
|
|
int TRiga_scadenze::pagata() const
|
|
{
|
|
const TRecord_array& a = rows_array();
|
|
for (int p = a.last_row(); p > 0; p = a.pred_row(p))
|
|
{
|
|
const TRectype& pag = a.row(p);
|
|
if (pag.get_char("ACCSAL") == 'S')
|
|
return p;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Calcola il totale dei pagamenti (eventualmente in valuta)
|
|
TImporto TRiga_scadenze::importo_pagato(bool val) const
|
|
{
|
|
const TPartita& game = partita();
|
|
const char* imp_field = in_valuta() && val ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO;
|
|
TImporto totale;
|
|
const TRecord_array& a = rows_array();
|
|
for (int p = a.last_row(); p > 0; p = a.pred_row(p))
|
|
{
|
|
const TRectype& pag = a.row(p); // Riga pagamento
|
|
const TRiga_partite& sum = game.riga(p); // Riga partite
|
|
const TImporto imp(sum.get_char(PART_SEZ), pag.get_real(imp_field));
|
|
totale += imp;
|
|
}
|
|
|
|
return totale;
|
|
}
|
|
|
|
// Calcola l'importo da pagare (eventualmente in valuta)
|
|
TImporto TRiga_scadenze::importo_da_pagare(bool val) const
|
|
{
|
|
const char* imp_field = in_valuta() && val ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO;
|
|
const TRiga_partite& r = riga(); // Riga fattura
|
|
const TImporto totale(r.get_char(PART_SEZ), get_real(imp_field));
|
|
return totale;
|
|
}
|
|
|
|
// Calcola l'abbuono della rata e ritorna il suo tipo:
|
|
// 'A' abbuono attivo; 'P' abbuono passivo
|
|
// La sezione dell'abbuono calcolato e' quella della riga contabile in cui finira'
|
|
char TRiga_scadenze::calcola_abbuono(TImporto& abbuono, bool val) const
|
|
{
|
|
bool ap = ' ';
|
|
if (pagata())
|
|
{
|
|
abbuono = importo_da_pagare(TRUE);
|
|
abbuono += importo_pagato(TRUE);
|
|
|
|
const int sign = abbuono.valore().sign();
|
|
if (sign != 0)
|
|
{
|
|
if (sign > 0)
|
|
ap = abbuono.sezione() == 'D' ? 'P' : 'A';
|
|
else
|
|
ap = abbuono.sezione() == 'D' ? 'A' : 'P';
|
|
}
|
|
|
|
if (val && in_valuta())
|
|
{
|
|
abbuono.valore() *= get_real(SCAD_CAMBIO);
|
|
abbuono.valore().round();
|
|
}
|
|
}
|
|
else
|
|
abbuono.valore() = ZERO;
|
|
|
|
return ap;
|
|
}
|
|
|
|
// Calcola la differenza cambi con la sezione da mettere nella riga contabile corrispondente
|
|
TImporto TRiga_scadenze::calcola_differenza_cambio(bool update)
|
|
{
|
|
TImporto diffcam;
|
|
const int riga_saldo = pagata();
|
|
if (riga_saldo > 0)
|
|
{
|
|
TRectype& pag = row(riga_saldo, FALSE);
|
|
const TRiga_partite& sum = partita().riga(riga_saldo);
|
|
const char sez = sum.sezione();
|
|
|
|
if (update)
|
|
{
|
|
diffcam = importo_da_pagare(FALSE);
|
|
diffcam += importo_pagato(FALSE);
|
|
|
|
real a = pag.get_real(PAGSCA_ABBUONI);
|
|
if (in_valuta())
|
|
{
|
|
a *= get_real(SCAD_CAMBIO);
|
|
a.round();
|
|
}
|
|
|
|
const TImporto abb_lit(sez, a);
|
|
diffcam += abb_lit;
|
|
diffcam.normalize(sez);
|
|
pag.put(PAGSCA_DIFFCAM, diffcam.valore());
|
|
}
|
|
else
|
|
{
|
|
diffcam.set(sez, pag.get_real(PAGSCA_DIFFCAM));
|
|
}
|
|
}
|
|
return diffcam;
|
|
}
|
|
|
|
real TRiga_scadenze::residuo() const
|
|
{
|
|
const char* imp_field = get(SCAD_CODVAL).not_empty() ? SCAD_IMPORTOVAL : SCAD_IMPORTO;
|
|
const real da_pagare(get(imp_field));
|
|
const real pagato(get(SCAD_IMPORTOPAG));
|
|
const real residuo = da_pagare - pagato;
|
|
return residuo;
|
|
}
|
|
|
|
|
|
bool TRiga_scadenze::modifica_pagamento(const TRectype& new_pag,
|
|
char& old_ap, TImporto& old_abb, TImporto& old_diffcam,
|
|
char& new_ap, TImporto& new_abb, TImporto& new_diffcam)
|
|
{
|
|
const int nrigp = new_pag.get_int(PAGSCA_NRIGP);
|
|
const TRectype old_pag(row(nrigp));
|
|
TRiga_partite& sum = partita().riga(nrigp);
|
|
|
|
old_ap = calcola_abbuono(old_abb, FALSE);
|
|
old_diffcam = calcola_differenza_cambio(FALSE);
|
|
|
|
const char* imp_field = get(SCAD_CODVAL).not_empty() ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO;
|
|
const real importo(new_pag.get(imp_field));
|
|
const bool empty = importo.is_zero();
|
|
if (empty)
|
|
rows_array().destroy_row(nrigp);
|
|
else
|
|
row(nrigp, FALSE) = new_pag;
|
|
|
|
TImporto abbuono;
|
|
new_ap = calcola_abbuono(abbuono, TRUE); // Calcolo abbuono in valuta
|
|
|
|
TImporto imp(abbuono); imp.swap_section();
|
|
imp.normalize(sum.sezione());
|
|
if (new_ap != ' ')
|
|
{
|
|
CHECK(nrigp == pagata(), "Aggiornamento abbuoni inconsistente");
|
|
TRectype& pag = row(nrigp, FALSE);
|
|
pag.put(PAGSCA_ABBUONI, imp.valore());
|
|
|
|
new_abb = abbuono;
|
|
if (in_valuta())
|
|
{
|
|
new_abb.valore() *= get_real(SCAD_CAMBIO);
|
|
new_abb.valore().round();
|
|
}
|
|
}
|
|
else
|
|
new_abb.valore() = ZERO;
|
|
|
|
sum.update(old_abb, new_abb, PART_SEZABB, PART_ABBUONI);
|
|
|
|
new_diffcam = calcola_differenza_cambio(TRUE);
|
|
sum.update(old_diffcam, new_diffcam, PART_SEZDIFCAM, PART_DIFFCAM);
|
|
|
|
sum.update(old_pag, new_pag, PART_IMPORTO);
|
|
sum.update(old_pag, new_pag, PART_IMPORTOVAL);
|
|
sum.update(old_pag, new_pag, PART_RITENUTE);
|
|
|
|
return empty;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TRiga_partite
|
|
///////////////////////////////////////////////////////////
|
|
|
|
TRiga_partite::TRiga_partite(TPartita* game)
|
|
: TTree_rectype(LF_PARTITE, LF_SCADENZE, "NRATA"), _partita(game)
|
|
{
|
|
CHECK(_partita, "Partita nulla");
|
|
}
|
|
|
|
TRiga_partite::TRiga_partite(const TRiga_partite& r)
|
|
: TTree_rectype(r), _partita(r._partita)
|
|
{
|
|
CHECK(_partita, "Partita nulla");
|
|
}
|
|
|
|
|
|
int TRiga_partite::read(TBaseisamfile& f, word op)
|
|
{
|
|
int err = TRectype::read(f, op);
|
|
if (err == NOERR && get_int(PART_TIPOMOV) == 1)
|
|
{
|
|
TRiga_scadenze* s = new TRiga_scadenze(this);
|
|
copy_key_to_row(*s);
|
|
err = _recarr.read(s); // Deve esistere almento una scadenza
|
|
#ifdef DBG
|
|
if (_recarr.rows() == 0)
|
|
yesnofatal_box("Riga di fattura senza nessuna scadenza");
|
|
#endif
|
|
}
|
|
else
|
|
_recarr.destroy_rows();
|
|
return err;
|
|
}
|
|
|
|
int TRiga_partite::ultimo_pagamento(int r) const
|
|
{
|
|
const TRiga_scadenze& s = rata(r);
|
|
return s.rows_array().last_row();
|
|
}
|
|
|
|
bool TRiga_partite::update(const TRectype& vec, const TRectype& nuo, const char* field)
|
|
{
|
|
real totale(get(field));
|
|
totale -= vec.get_real(field);
|
|
totale += nuo.get_real(field);
|
|
put(field, totale);
|
|
return totale.is_zero();
|
|
}
|
|
|
|
bool TRiga_partite::update(const TImporto& vec, const TImporto& nuo,
|
|
const char* sez, const char* val)
|
|
{
|
|
bool zero = FALSE;
|
|
TImporto grow(nuo); grow -= vec; // Variazione al totale
|
|
|
|
if (!grow.is_zero())
|
|
{
|
|
const char sezione = get_char(sez); // Sezione del totale
|
|
TImporto totale;
|
|
if (sezione > ' ') // Se c'era una sezione (e quindi un importo) ...
|
|
totale.set(sezione, get_real(val)); // ... inizializza il totale
|
|
else
|
|
CHECKS(vec.is_zero(), "Sezione errata per l'importo ", val);
|
|
totale += grow; // incrementa il totale
|
|
totale.normalize();
|
|
put(sez, totale.sezione()); // Aggiorna il totale sul record
|
|
put(val, totale.valore());
|
|
zero = totale.is_zero();
|
|
}
|
|
else
|
|
zero = get_real(val).is_zero();
|
|
|
|
return zero;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TPartita
|
|
///////////////////////////////////////////////////////////
|
|
|
|
TPartita::TPartita(const TBill& clifo, int anno, const char* num)
|
|
: _part(LF_PARTITE, PART_NRIGA), _unassigned(LF_PAGSCA, "NRIGP")
|
|
{
|
|
read(clifo, anno, num);
|
|
}
|
|
|
|
TPartita::TPartita()
|
|
: _part(LF_PARTITE, PART_NRIGA), _unassigned(LF_PAGSCA, "NRIGP")
|
|
{}
|
|
|
|
// Costruisce le righe della partita
|
|
bool TPartita::read(const TBill& clifo, int anno, const char* num)
|
|
{
|
|
TRiga_partite* partita = new TRiga_partite(this); // Record campione della partita
|
|
partita->put(PART_TIPOCF, clifo.tipo()); // Tipo clifo
|
|
if (clifo.tipo() <= ' ')
|
|
{
|
|
partita->put(PART_GRUPPO, clifo.gruppo()); // Scrivi gruppo e conto solamente
|
|
partita->put(PART_CONTO, clifo.conto()); // nei conti normali (no clifo)
|
|
}
|
|
partita->put(PART_SOTTOCONTO, clifo.sottoconto()); // Sottoconto o codice clifo
|
|
partita->put(PART_ANNO, anno); // Anno partita
|
|
partita->put(PART_NUMPART, num); // Numero partita
|
|
_part.read(partita);
|
|
|
|
#ifdef DBG
|
|
for (int p = last(); p > 0; p = pred(p))
|
|
CHECKD(riga(p)._partita == this, "Riga partite inconsistente", p);
|
|
#endif
|
|
|
|
TRectype unas(LF_PAGSCA); // Record campione pagamenti non assegnati
|
|
unas.zero();
|
|
unas.put(PART_TIPOCF, partita->get(PART_TIPOCF)); // Copia chiave partite
|
|
unas.put(PART_GRUPPO, partita->get(PART_GRUPPO));
|
|
unas.put(PART_CONTO, partita->get(PART_CONTO));
|
|
unas.put(PART_SOTTOCONTO, partita->get(PART_SOTTOCONTO));
|
|
unas.put(PART_ANNO, partita->get(PART_ANNO));
|
|
unas.put(PART_NUMPART, partita->get(PART_NUMPART));
|
|
unas.put(PART_NRIGA, 0); // Numeri magici di non assegamento
|
|
unas.put(SCAD_NRATA, 0);
|
|
_unassigned.read(unas);
|
|
|
|
return ok();
|
|
}
|
|
|
|
bool TPartita::reread()
|
|
{
|
|
TBill zio;
|
|
conto(zio);
|
|
const int year = anno();
|
|
const TString16 num = numero();
|
|
return read(zio, year, num);
|
|
}
|
|
|
|
bool TPartita::write(bool re)
|
|
{
|
|
const bool ok = _part.write(re);
|
|
return ok;
|
|
}
|
|
|
|
TImporto TPartita::importo_speso(long nreg, int numrig) const
|
|
{
|
|
TImporto imp;
|
|
|
|
for (int r = _part.last_row(); r > 0; r = pred(r))
|
|
{
|
|
const TRectype& pag = riga(r);
|
|
|
|
const long reg = pag.get_long(PART_NREG);
|
|
if (reg == nreg)
|
|
{
|
|
const int num = pag.get_int(PART_NUMRIG);
|
|
if (num == numrig)
|
|
{
|
|
imp = TImporto(pag.get_char(PART_SEZ), pag.get_real(PART_IMPORTO));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return imp;
|
|
}
|
|
|
|
|
|
void TPartita::update_reg_num(long nreg, const TRectype& mov)
|
|
{
|
|
for (int r = _part.last_row(); r > 0; r = pred(r))
|
|
{
|
|
TRectype& pag = _part.row(r, FALSE);
|
|
|
|
const long reg = pag.get_long(PART_NREG);
|
|
if (reg == nreg)
|
|
{
|
|
pag.put(PART_NREG, mov.get(MOV_NUMREG));
|
|
pag.put(PART_DATAREG, mov.get(MOV_DATAREG));
|
|
pag.put(PART_NUMDOC, mov.get(MOV_NUMDOC));
|
|
pag.put(PART_DATADOC, mov.get(MOV_DATADOC));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calcola la riga di movimento relativa a una riga partita
|
|
int TPartita::rig2mov(int rp) const
|
|
{
|
|
const TRiga_partite& r = riga(rp);
|
|
return r.get_int(PART_NUMRIG);
|
|
}
|
|
|
|
// Calcola la riga di partita relativa a una riga movimento
|
|
int TPartita::mov2rig(long numreg, int rm) const
|
|
{
|
|
for (int r = _part.last_row(); r > 0; r = pred(r))
|
|
{
|
|
const TRiga_partite& row = riga(r);
|
|
if (row.get_long(PART_NREG) == numreg && row.get_int(PART_NUMRIG) == rm)
|
|
return r;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Trova la prima riga della partita contenente una fattura
|
|
int TPartita::prima_fattura() const
|
|
{
|
|
const int lastrow = last();
|
|
for (int r = first(); r <= lastrow; r = succ(r))
|
|
{
|
|
const TRiga_partite& row = riga(r);
|
|
const int tipomov = row.get_int(PART_TIPOMOV);
|
|
if (tipomov == 1 || tipomov == 2)
|
|
return r;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void TPartita::calcola_saldo(TImporto& saldo, TImporto& doc, TImporto& pag, TImporto& imp) const
|
|
{
|
|
doc = pag = imp = TImporto('D', ZERO);
|
|
|
|
for (int r = _part.last_row(); r > 0; r = pred(r))
|
|
{
|
|
const TRiga_partite& row = riga(r);
|
|
TImporto i(row.get_char(PART_SEZ), row.get_real(PART_IMPORTO));
|
|
switch (row.get_int(PART_TIPOMOV))
|
|
{
|
|
case 1:
|
|
case 2:
|
|
doc += i; // documenti
|
|
break;
|
|
case 3:
|
|
pag += i; // pagamenti
|
|
break;
|
|
default:
|
|
imp += i; // altri importi
|
|
break;
|
|
}
|
|
|
|
i.set(row.get_char(PART_SEZ), row.get_real(PART_ABBUONI));
|
|
imp += i;
|
|
|
|
i.set(row.get_char(PART_SEZ), row.get_real(PART_DIFFCAM));
|
|
imp += i;
|
|
}
|
|
|
|
saldo = doc;
|
|
saldo += pag;
|
|
saldo += imp;
|
|
}
|
|
|
|
|
|
bool TPartita::utilizzata(int nrigp) const
|
|
{
|
|
for (int p = _part.last_row(); p > 0; p = pred(p))
|
|
{
|
|
const TRiga_partite& fatt = riga(p);
|
|
const int tipomov = fatt.get_int(PART_TIPOMOV);
|
|
if (tipomov == 1)
|
|
{
|
|
for (int r = fatt.rate(); r > 0; r--)
|
|
{
|
|
const TRiga_scadenze& scad = fatt.rata(r);
|
|
if (scad.rows_array().exist(nrigp))
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool TPartita::modifica_pagamento(const TRectype& new_pag,
|
|
char& old_ap, TImporto& old_abb, TImporto& old_diffcam,
|
|
char& new_ap, TImporto& new_abb, TImporto& new_diffcam)
|
|
{
|
|
const int nriga = new_pag.get_int(PAGSCA_NRIGA);
|
|
const TRiga_partite& fattura = riga(nriga);
|
|
|
|
const int nrata = new_pag.get_int(PAGSCA_NRATA);
|
|
TRiga_scadenze& scaden = fattura.rata(nrata);
|
|
|
|
const int nrigp = new_pag.get_int(PAGSCA_NRIGP);
|
|
const TRectype& old_pag = scaden.row(nrigp);
|
|
|
|
const bool empty = scaden.modifica_pagamento(new_pag,
|
|
old_ap, old_abb, old_diffcam,
|
|
new_ap, new_abb, new_diffcam);
|
|
|
|
if (empty && !utilizzata(nrigp))
|
|
_part.destroy_row(nrigp);
|
|
|
|
return empty;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TPartite_array
|
|
///////////////////////////////////////////////////////////
|
|
|
|
// Certified 99%
|
|
const TString& TPartite_array::key(const TBill& clifo, int anno, const char* num)
|
|
{
|
|
if (clifo.tipo() > ' ')
|
|
_key.format("%c%3d%3d%6ld%4d%s", clifo.tipo(), 0, 0, clifo.sottoconto(), anno, num);
|
|
else
|
|
_key.format("%c%3d%3d%6ld%4d%s",
|
|
clifo.tipo(), clifo.gruppo(), clifo.conto(), clifo.sottoconto(), anno, num);
|
|
return _key;
|
|
}
|
|
|
|
// Certified 99%
|
|
TPartita* TPartite_array::find(const TBill& clifo, int anno, const char* num, bool create)
|
|
{
|
|
const TString& k = key(clifo, anno, num);
|
|
TPartita* p = (TPartita*)objptr(k);
|
|
if (p == NULL && create)
|
|
{
|
|
p = new TPartita(clifo, anno, num);
|
|
if (p->ok())
|
|
add(k, p);
|
|
else
|
|
{
|
|
delete p;
|
|
p = NULL;
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
TPartita* TPartite_array::find(const TRectype& r, bool create)
|
|
{
|
|
TBill zio; zio.get(r);
|
|
const int anno = r.get_int(PART_ANNO);
|
|
const char* num = r.get_str(PART_NUMPART);
|
|
return find(zio, anno, num, create);
|
|
}
|
|
|
|
TPartita& TPartite_array::partita(const TBill& clifo, int anno, const char* num)
|
|
{
|
|
TPartita* game = find(clifo, anno, num, TRUE);
|
|
CHECKS(game, "Partita errata ", num);
|
|
return *game;
|
|
}
|
|
|
|
TPartita& TPartite_array::partita(const TRectype& r)
|
|
{
|
|
TPartita* game = find(r, TRUE);
|
|
CHECK(game, "Partita errata");
|
|
return *game;
|
|
}
|
|
|
|
bool TPartite_array::write(bool re)
|
|
{
|
|
int err = NOERR;
|
|
|
|
TPartita* game;
|
|
restart();
|
|
while ((game = (TPartita*)get()) != NULL)
|
|
{
|
|
err = game->write(re);
|
|
if (err != NOERR) // L'errore viene gia' segnalato dalla partita
|
|
break;
|
|
}
|
|
|
|
return err == NOERR;
|
|
}
|
|
|
|
// Aggiunge all'array tutte le partite che si riferiscono alla registrazione nreg
|
|
int TPartite_array::add_reg_num(long nreg, int numrig)
|
|
{
|
|
TRelation rel(LF_PARTITE);
|
|
TRectype& part = rel.lfile().curr();
|
|
|
|
// Costruzione filtro del cursore
|
|
part.zero();
|
|
part.put(PART_NREG, nreg);
|
|
if (numrig > 0)
|
|
part.put(PART_NUMRIG, numrig);
|
|
|
|
const TRectype filter(part);
|
|
|
|
TCursor cur(&rel, "", 2, &filter, &filter);
|
|
|
|
for (cur = 0; cur.ok(); ++cur)
|
|
partita(part); // Aggiungi partita se non esiste gia'
|
|
|
|
return (int)cur.items();
|
|
}
|
|
|
|
TImporto TPartite_array::importo_speso(long nreg, int numrig)
|
|
{
|
|
TImporto imp;
|
|
add_reg_num(nreg, numrig);
|
|
for (TPartita* game = first(); game; game = next())
|
|
imp += game->importo_speso(nreg, numrig);
|
|
return imp;
|
|
}
|
|
|
|
void TPartite_array::update_reg_num(long nreg, const TRectype& mov)
|
|
{
|
|
add_reg_num(nreg, 0);
|
|
for (TPartita* game = first(); game; game = next())
|
|
game->update_reg_num(nreg, mov);
|
|
}
|
|
|
|
|