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