#include #include #include #include #include "cgsaldac.h" #include #include /////////////////////////////////////////////////////////// // 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::renum_key(const char* field, const char* val) { TRectype::renum_key(field, val); _recarr.renum_key(field, val); } void TTree_rectype::copy_key_to_row(TRectype& row) const { RecDes* recd = rec_des(); // Descrizione del record della testata row.zero(); const KeyDes& kd = recd->Ky[0]; // Memento! Gli indici delle chiavi partono da zero! for (int i = kd.NkFields-1; i >= 0; i--) { const int nf = kd.FieldSeq[i] % MaxFields; const RecFieldDes& rf = recd->Fd[nf]; const char* name = rf.Name; const TString& val = get(name); row.renum_key(name, val); } } TRectype& TTree_rectype::new_row(int r) { if (r <= 0) r = last()+1; CHECKD(!exist(r), "Ue' pirla! Esiste gia' la riga ", r); TRectype& row = rows_array().row(r, TRUE); return row; } 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, word lockop) { int err = TRectype::read(f, op, lockop); 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) const { int err = TRectype::remove(f); if (err == NOERR) err = _recarr.remove(); return err; } /////////////////////////////////////////////////////////// // Valuta /////////////////////////////////////////////////////////// TValuta::TValuta(const char* cod, const TDate& dat, const real& cam, exchange_type eur) : _cod(cod), _dat(dat), _cam(cam), _et(eur) { adjust(); } TValuta::TValuta() : _cod(""), _dat(TODAY), _cam(ZERO), _et(_exchange_undefined) { adjust(); } void TValuta::adjust() { const TCurrency this_cur(ZERO, _cod, _cam, _et); if (this_cur.is_firm_value()) { _cod.cut(0); _cam = ZERO; _et = _exchange_undefined; } else { if (_cam < ZERO) _cam = ZERO; _cod = this_cur.get_value(); } if (_et == _exchange_undefined) this_cur.get_change(_et); } int TValuta::compare(const TSortable& s) const { const TValuta& v = (const TValuta&)s; return stricmp(_cod, v._cod); } void TValuta::get(const TRectype& rec) { _cod = rec.get("CODVAL"); _dat = rec.get("DATACAM"); _cam = rec.get_real("CAMBIO"); if (rec.exist("CONTROEURO")) _et = rec.get_bool("CONTROEURO") ? _exchange_contro : _exchange_base; else _et = _exchange_undefined; adjust(); } void TValuta::put(TRectype& rec) const { if (in_lire()) { rec.zero("CODVAL"); rec.zero("DATACAM"); rec.zero("CAMBIO"); if (rec.exist("CONTROEURO")) rec.zero("CONTROEURO"); } else { rec.put("CODVAL", _cod); rec.put("DATACAM", _dat); rec.put("CAMBIO", _cam); if (rec.exist("CONTROEURO")) rec.put("CONTROEURO", _et == _exchange_contro ? "X" : ""); } } void TValuta::set(TMask& m, short v, short d, short c, short e) const { if (in_lire()) { m.reset(v); m.reset(d); m.reset(c); if (e && m.id2pos(e) >= 0) m.reset(e); } else { m.set(v, _cod); m.set(d, _dat.string()); m.set(c, _cam.string()); if (e && m.id2pos(e) >= 0) m.set(e, _et == _exchange_contro ? "X" : ""); } } void TValuta::get(const TMask& m, short v, short d, short c, short e) { _cod = m.get(v); _dat = m.get(d); _cam = m.get_real(c); if (e && m.id2pos(e) >= 0) _et = m.get_bool(e) ? _exchange_contro : _exchange_base; else _et = _exchange_undefined; adjust(); } void TValuta::set(const TValuta& v) { _cod = v._cod; _dat = v._dat; _cam = v._cam; _et = v._et; } real TValuta::lit2val(const real& lit) const { TCurrency cur(lit); cur.change_value(_cod, _cam, _et); return cur.get_num(); } real TValuta::val2lit(const real& val) const { TCurrency cur(val, _cod, _cam, _et); cur.change_to_firm_val(); return cur.get_num(); } void TValuta::val2lit(real& val) const { TCurrency cur(val, _cod, _cam, _et); cur.change_to_firm_val(); val = cur.get_num(); } void TValuta::lit2val(real& lit) const { TCurrency cur(lit); cur.change_value(_cod, _cam, _et); lit = cur.get_num(); } void TValuta::val2lit(TImporto& imp) const { val2lit(imp.valore()); } void TValuta::lit2val(TImporto& imp) const { lit2val(imp.valore()); } /////////////////////////////////////////////////////////// // TRiga_scadenze /////////////////////////////////////////////////////////// TRiga_scadenze::TRiga_scadenze(TRiga_partite* r) : TTree_rectype(LF_SCADENZE, LF_PAGSCA, "NRIGP"), _riga(r) { CHECK(_riga, "Riga nulla"); r->copy_key_to_row(*this); } TRiga_scadenze::TRiga_scadenze(const TRiga_scadenze& s) : TTree_rectype(s), _riga(s._riga) {} TRiga_scadenze::~TRiga_scadenze() { } TObject* TRiga_scadenze::dup() const { TRiga_scadenze* r = new TRiga_scadenze(*this); return r; } TPartita& TRiga_scadenze::partita() const { return riga().partita(); } // Controlla se la fattura della rata e' in valuta bool TRiga_scadenze::in_valuta() const { return riga().in_valuta(); } // Controlla se la fattura della rata e' in valuta const TString& TRiga_scadenze::codice_valuta() const { return riga().codice_valuta(); } // Controlla se la rata e' stata completamente pagata bool TRiga_scadenze::chiusa(bool update) const { bool chiusa; if (update) { TImporto imp(importo(TRUE)); imp += importo_pagato(TRUE); chiusa = imp.is_zero(); ((TRectype*)this)->put(SCAD_PAGATA, chiusa ? "X" : ""); } else chiusa = get_bool(SCAD_PAGATA); return chiusa; } // Calcola il totale dei pagamenti (eventualmente in valuta) TImporto TRiga_scadenze::importo_pagato(bool val, int mode) const { CHECKD(mode > 0x0 && mode <= 0xFF, "Bad importo_pagato mode ", mode); const TPartita& game = partita(); const bool in_val = in_valuta(); const char* imp_field = (val && in_val) ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO; TImporto totale; for (int p = last(); p > 0; p = pred(p)) { const TRectype& pag = row(p); // Riga pagamento const TRiga_partite& sum = game.riga(p); // Riga partite const char sez = sum.sezione(); if (mode & 0x1) totale += TImporto(sez, pag.get_real(imp_field)); if (!in_val && (mode & 0x8)) // Le ritenute non esistono nei pagamenti in valuta totale += TImporto(sez, pag.get_real(PAGSCA_RITENUTE)); if (mode & 0x2) // Voglio anche gli abbuoni { real abb = pag.get_real(PAGSCA_ABBUONI); if (!abb.is_zero()) { if (in_val && !val) // Gli abbuoni sono sempre in valuta e quindi { // devono essere convertiti opportunamente const TExchange cmb(sum); TCurrency cur(abb, cmb); cur.change_to_firm_val(); abb = cur.get_num(); } totale += TImporto(sez, abb); } } if (in_val && !val && (mode & 0x4)) // Voglio anche le differenze cambio { // Esse esistono solo nei pagamenti in valuta const TImporto diffcam(sez, pag.get_real(PAGSCA_DIFFCAM)); totale += diffcam; } } return totale.normalize(); } // Calcola l'importo da pagare (eventualmente in valuta) TImporto TRiga_scadenze::importo(bool val) const { const TRiga_partite& fatt = riga(); // Riga fattura const char* const imp = val && in_valuta() ? SCAD_IMPORTOVAL : SCAD_IMPORTO; const TImporto i(fatt.sezione(), get_real(imp)); return i; } // Calcola l'abbuono in valuta della rata e ritorna il suo tipo: // 'A' abbuono attivo; 'P' abbuono passivo char TRiga_scadenze::calcola_abbuono(int p, TImporto& abbuono, bool update) { char ap = ' '; TRectype& pag = row(p); const char sez = partita().riga(p).sezione(); if (update) { if (pag.get_char(PAGSCA_ACCSAL) == 'S') { abbuono = importo(TRUE); pag.zero(PAGSCA_ABBUONI); abbuono += importo_pagato(TRUE, 0x0B); // Somma di importi, abbuoni e ritenute abbuono.swap_section(); const int sign = abbuono.valore().sign(); if (sign != 0) { if (sign > 0) ap = abbuono.sezione() == 'D' ? 'A' : 'P'; else ap = abbuono.sezione() == 'D' ? 'P' : 'A'; } } else abbuono.valore() = ZERO; if (ap > ' ') { abbuono.normalize(sez); pag.put(PAGSCA_ABBUONI, abbuono.valore()); pag.put(PAGSCA_PASSATT, ap); } else { pag.zero(PAGSCA_ABBUONI); pag.zero(PAGSCA_PASSATT); } } else { abbuono.set(sez, pag.get_real(PAGSCA_ABBUONI)); ap = pag.get_char(PAGSCA_PASSATT); if (ap < ' ') ap = ' '; } return ap; } // Calcola la differenza cambi con la sezione da mettere nella riga contabile corrispondente TImporto TRiga_scadenze::calcola_differenza_cambio(int p, bool update) { TImporto diffcam; TRectype& pag = row(p); if (pag.get_char(PAGSCA_ACCSAL) == 'S' && in_valuta()) { const char sez = partita().riga(p).sezione(); if (update) { diffcam = importo(FALSE); pag.zero(PAGSCA_DIFFCAM); diffcam += importo_pagato(FALSE); // Conta anche gli abbuoni e le altre diffcam diffcam.swap_section(); diffcam.normalize(sez); pag.put(PAGSCA_DIFFCAM, diffcam.valore()); } else { diffcam.set(sez, pag.get_real(PAGSCA_DIFFCAM)); } } else { if (update) pag.zero(PAGSCA_DIFFCAM); } return diffcam; } TImporto TRiga_scadenze::residuo(bool val, int mode) const { TImporto residuo(importo(val)); residuo += importo_pagato(val, mode); // Somma con sezione opposta residuo.normalize(); return residuo; } bool TRiga_scadenze::modifica_pagamento(const TRectype& new_pag, const TValuta& valuta, char& old_ap, TImporto& old_abb, TImporto& old_diffcam, char& new_ap, TImporto& new_abb, TImporto& new_diffcam, bool update) { const bool in_val = in_valuta(); const int nrigp = new_pag.get_int(PAGSCA_NRIGP); const TRectype old_pag(row(nrigp)); TRiga_partite& sum = partita().riga(nrigp); TImporto old_abbuono; old_ap = calcola_abbuono(nrigp, old_abbuono, FALSE); // Vecchio abbuono in valuta old_abb = old_abbuono; // Vecchio abbuono in lire if (in_val) { const TString4 codval = sum.codice_valuta(); exchange_type et = _exchange_undefined; if (((TRectype&)sum).exist(PART_CONTROEURO)) et = sum.get_bool(PART_CONTROEURO) ? _exchange_contro : _exchange_base; TCurrency cur(old_abb.valore(), codval, sum.get_real(PART_CAMBIO), et); cur.change_to_firm_val(); old_abb.valore() = cur.get_num(); } old_diffcam = calcola_differenza_cambio(nrigp, FALSE); if (in_val && !valuta.in_lire()) valuta.put(sum); row(nrigp) = new_pag; TImporto new_abbuono; new_ap = calcola_abbuono(nrigp, new_abbuono, update); // Calcolo abbuono in valuta new_abb = new_abbuono; // Calcola nuovo abbuono in lire if (in_valuta()) { const TString4 codval = sum.codice_valuta(); exchange_type et = _exchange_undefined; if (((TRectype&)sum).exist(PART_CONTROEURO)) et = sum.get_bool(PART_CONTROEURO) ? _exchange_contro : _exchange_base; TCurrency cur(new_abb.valore(), codval, sum.get_real(PART_CAMBIO), et); cur.change_to_firm_val(); new_abb.valore() = cur.get_num(); } new_diffcam = calcola_differenza_cambio(nrigp, update); sum.update(old_abbuono, new_abbuono, PART_SEZABB, PART_ABBUONI); 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); const bool empty = new_pag.get_char(PAGSCA_ACCSAL) != 'S' && new_pag.get_real(PAGSCA_IMPORTO).is_zero() && new_pag.get_real(PAGSCA_RITENUTE).is_zero(); if (empty) rows_array().destroy_row(nrigp); // Aggiorna flags di chiusura chiusa(TRUE); partita().chiusa(TRUE); return empty; } bool TRiga_scadenze::esistono_abbuoni_diffcam() const { bool ad = FALSE; for (int p = last(); p > 0; p = pred(p)) { const TRectype& pag = row(p); if (pag.get_char(PAGSCA_ACCSAL) == 'S') { if (!pag.get_real(PAGSCA_ABBUONI).is_zero() || !pag.get_real(PAGSCA_DIFFCAM).is_zero()) { ad = TRUE; break; } } } return ad; } bool TRiga_scadenze::elimina_pagamento(int p) { TRectype old_pag(row(p)); old_pag.put(PAGSCA_ACCSAL, "A"); old_pag.zero(PAGSCA_IMPORTO); old_pag.zero(PAGSCA_IMPORTOVAL); old_pag.zero(PAGSCA_RITENUTE); TValuta val; return partita().modifica_pagamento(old_pag, val, TRUE); } /////////////////////////////////////////////////////////// // TRiga_partite /////////////////////////////////////////////////////////// TRiga_partite::TRiga_partite(TPartita* game) : TTree_rectype(LF_PARTITE, LF_SCADENZE, SCAD_NRATA), _partita(game) { CHECK(_partita, "Partita nulla"); TRiga_scadenze* scad = new TRiga_scadenze(this); copy_key_to_row(*this); rows_array().set_key(scad); // Altrimenti le righe sarebbero dei TRectype! } TRiga_partite::TRiga_partite(const TRiga_partite& r) : TTree_rectype(r), _partita(r._partita) { update_rigaptr(); } TRiga_partite::~TRiga_partite() {} void TRiga_partite::update_rigaptr() { for (int i = rate(); i >= 0; i--) { TRiga_scadenze& scad = i == 0 ? (TRiga_scadenze&)rows_array().key() : rata(i); scad._riga = this; } } TRiga_scadenze& TRiga_partite::new_row(int r) { TRiga_scadenze& scad = (TRiga_scadenze&)TTree_rectype::new_row(r); scad._riga = this; return scad; } // Elimina la rata r ed i suoi pagamenti, se r < 1 allora elimina tutte le rate // Certified 99% void TRiga_partite::elimina_rata(int r) { const int from = r <= 0 ? 1 : r; const int to = r <= 0 ? rate() : r; for (r = to; r >= from; r--) // E' necessario andare all'indietro perche' { // il metodo rate() funzioni sempre correttamente TRiga_scadenze& scad = rata(r); for (int p = scad.last(); p > 0; p = scad.pred(p)) scad.elimina_pagamento(p); // Elimina pagamento rows_array().destroy_row(r); // Elimina rata } } // Ritorna il numero dell'ultima rata pagata o 0 se non ce ne sono // Certified 100% int TRiga_partite::ultima_ratapagata() const { for (int r = rate(); r > 0; r--) if (rata(r).chiusa()) break; return r; } // Ritorna il tipo movimento di una riga di partita // Certified 100% tipo_movimento TRiga_partite::tipo() const { const tipo_movimento tm = (tipo_movimento)(get_char(PART_TIPOMOV)-'0'); #ifdef DBG if (tm == tm_nessuno && get_int(PART_NRIGA) != TPartita::UNASSIGNED) yesnofatal_box("Riga partite con un tipo losco."); #endif return tm; } // Legge le rate relative ad una riga di fattura // Certified 99% int TRiga_partite::read(TBaseisamfile& f, word op, word lock) { int err = TRectype::read(f, op, lock); if (err == NOERR && is_fattura()) { TRiga_scadenze* s = new TRiga_scadenze(this); err = rows_array().read(s); // Deve esistere almento una scadenza update_rigaptr(); } else rows_array().destroy_rows(); return err; } // Registra una riga e le sue eventuali rate // Certified 100% int TRiga_partite::write(TBaseisamfile& f) const { const int err = is_fattura() ? TTree_rectype::write(f) : TRectype::write(f); return err; } // Aggiorna una riga e le sue eventuali rate // Certified 100% int TRiga_partite::rewrite(TBaseisamfile& f) const { const int err = is_fattura() ? TTree_rectype::rewrite(f) : TRectype::rewrite(f); return err; } // Elimina una riga e le sue eventuali rate // Certified 100% int TRiga_partite::remove(TBaseisamfile& f) const { const int err = is_fattura() ? TTree_rectype::remove(f) : TRectype::remove(f); return err; } // Ritorna l'indice dell'ultimo pagamento della rata r o 0 se non ce ne sono // Certified 100% int TRiga_partite::ultimo_pagamento(int r) const { const TRiga_scadenze& s = rata(r); return s.last(); } // Aggiorna il campo field contenente un totale sottraendo il corrispondente valore di // un record prima (vec) e dopo la sua modifica (nuo) // Certified 100% 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 growth(nuo); growth -= vec; // Variazione al totale if (!growth.is_zero()) { TImporto totale(get_char(sez), get_real(val)); totale += growth; // 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; } // Cerca una rata con abbuoni o differenze cambio // Certified 99% int TRiga_partite::ultima_rata_con_abbuoni_diffcam() const { for (int s = rate(); s > 0; s--) { const TRiga_scadenze& scad = rata(s); if (scad.esistono_abbuoni_diffcam()) break; } return s; } // Determina il codice valuta const TString& TRiga_partite::codice_valuta() const { return get(PART_CODVAL); } // Determina se una riga e' in valuta in base al codice valuta bool TRiga_partite::in_valuta() const { return codice_valuta().not_empty(); } // Calcola l'importo in lire o in valuta su di una riga di partita // E' possibile considerare o meno IMPORTO, ABBUONI e DIFFCAM TImporto TRiga_partite::importo(bool valuta, int mode) const { CHECKD(mode > 0x0 && mode <= 0xF, "Bad importo mode ", mode); const bool in_lire = !in_valuta(); // Partita in lire if (valuta && in_lire) valuta = FALSE; TImporto i; if (mode & 0x1) { const char* const field = valuta ? PART_IMPORTOVAL : PART_IMPORTO; i.set(sezione(), get_real(field)); } if (!is_fattura() && (mode & 0xE)) // Ci sono abbuoni, differenze cambio o ritenute? { if (valuta) // Desidero gli abbuoni in valuta { if (mode & 0x2) { const TImporto abbuoni(get_char(PART_SEZABB), get_real(PART_ABBUONI)); i += abbuoni; } // In valuta ignoro completamente le differenze cambio } else // Desidero gli abbuoni in lire { if (in_lire && (mode & 0x8)) i.valore() += get_real(PART_RITENUTE); if (mode & 0x2) { TImporto abbuoni(get_char(PART_SEZABB), get_real(PART_ABBUONI)); if (!in_lire) // Converto in lire gli abbuoni che sono memorizzati in valuta { const real cambio(get(PART_CAMBIO)); TCurrency cur(abbuoni.valore(), codice_valuta(), cambio); cur.change_to_firm_val(); abbuoni.valore() = cur.get_num(); } i += abbuoni; } if (!in_lire && (mode & 0x4)) // Se ci sono e desidero le differenze cambio { const TImporto diffcam(get_char(PART_SEZDIFCAM), get_real(PART_DIFFCAM)); i += diffcam; } } } return i; } // Calcola l'esposto e l' esposto SBF TImporto TRiga_partite::esposto(bool valuta, const TDate & data_scad, const TDate & data_rischio, bool & sbf) const { TImporto esposto; sbf = FALSE; const int nrigp = get_int(PART_NRIGA); const char sez = sezione(); const int last = _partita->last(); const TDate datapag(get_date(PART_DATAPAG)); const bool rischio = data_scad != data_rischio; bool found_pag = FALSE; for (int row = last; row > 0; row = _partita->pred(row)) { const TRiga_partite & riga = _partita->riga(row); if (riga.is_fattura()) { const int lastr = riga.rate(); for (int rata = lastr; rata > 0; rata--) { const TRiga_scadenze& scad = riga.rata(rata); if (scad.exist(nrigp)) { const TRectype & pag = scad.row(nrigp); const TImporto imp(sez, pag.get_real(valuta ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO)); TDate data(scad.get(SCAD_DATASCAD)); const int lasts = scad.last(); found_pag = TRUE; for (int p = scad.first(); p <= lasts; p = scad.succ(p)) { if (p != nrigp) { const TRiga_partite & prow = partita().riga(p); const int tp = prow.get_int(PART_TIPOPAG); if (tp >= 2 && tp <= 7) { const TDate dataprow = prow.get(PART_DATAPAG); if (dataprow < datapag) { data = datapag; break; } } } } if (rischio && data > data_rischio && data <= data_scad) { esposto += imp; sbf = TRUE; } else if (data > data_scad) esposto += imp; } } } } if (!found_pag) { const TImporto imp(importo(valuta, 0x1)); if (rischio && datapag > data_rischio && datapag <= data_scad) { esposto += imp; sbf = TRUE; } else if (datapag > data_scad) esposto += imp; } return esposto; } /////////////////////////////////////////////////////////// // TPartita /////////////////////////////////////////////////////////// char TPartita::_cli_align = ' '; char TPartita::_for_align = ' '; TPartita::TPartita(const TBill& clifo, int anno, const char* num) : _part(LF_PARTITE, PART_NRIGA), _unassigned(LF_PAGSCA, "NRIGP"), _align(' ') { read(clifo, anno, num); } TPartita::TPartita(const TRectype& r) : _part(LF_PARTITE, PART_NRIGA), _unassigned(LF_PAGSCA, "NRIGP"), _align(' ') { TBill clifo; clifo.get(r); if (clifo.gruppo() == 0) { clifo.set(r.get_int(PART_GRUPPOCL), r.get_int(PART_CONTOCL), clifo.sottoconto(), clifo.tipo()); } const int anno = r.get_int(PART_ANNO); const TString num(r.get(PART_NUMPART)); read(clifo, anno, num); } TPartita::~TPartita() { } const char* TPartita::build_key(TString& key) const { if (_conto.tipo() > ' ') key.format("%c%3d%3d%6ld%4d%*s", _conto.tipo(), 0, 0, _conto.sottoconto(), _anno, NUMLEN, (const char*)_num); else key.format("%c%3d%3d%6ld%4d%*s", _conto.tipo(), _conto.gruppo(), _conto.conto(), _conto.sottoconto(), _anno, NUMLEN, (const char*)_num); return key; } int TPartita::compare(const TSortable& s) const { TString80 key; build_key(key); const TPartita& p = (const TPartita&)s; TString80 par; p.build_key(par); return strcmp(key, par); } void TPartita::carica_allineamento() { TConfig cd(CONFIG_DITTA, "cg"); _cli_align = cd.get_bool("NrCliDx") ? 'R' : 'L'; _for_align = cd.get_bool("NrForDx") ? 'R' : 'L'; } char TPartita::allineamento_richiesto(char tipocf) { // Controlla se e' gia' stato caricato l'allineamento if (_cli_align <= ' ' || _for_align <= ' ') carica_allineamento(); char all; switch (tipocf) { case 'C': all = _cli_align; break; case 'F': all = _for_align; break; default : all = (_cli_align == _for_align) ? _cli_align : 'L'; break; } return all; } // Ritorna l'allineamento corrente del numero partita // L = Sinistra, R = Destra, ' ' = indeterminato char TPartita::allineamento_corrente() const { const TString& n = numero(); char all = n[0] == ' ' ? 'R' : 'L'; if (all == 'L' && n.len() == NUMLEN && n[NUMLEN-1] != ' ') all = ' '; return all; } void TPartita::allinea(char all) { if (all <= ' ') all = allineamento_richiesto(conto().tipo()); if (all == 'R') _num.right_just(NUMLEN); else _num.trim(); if (ok()) { _part.renum_key(PART_NUMPART, _num); _unassigned.renum_key(PAGSCA_NUMPART, _num); } } bool TPartita::is_on_file() const { TLocalisamfile partite(LF_PARTITE); TRectype& part = partite.curr(); part.zero(); part.put(PART_TIPOCF, _conto.tipo()); if (_conto.tipo() <= ' ') { part.put(PART_GRUPPO, _conto.gruppo()); part.put(PART_CONTO, _conto.conto()); } part.put(PART_SOTTOCONTO, _conto.sottoconto()); part.put(PART_ANNO, _anno); part.put(PART_NUMPART, _num); const TRectype filter(part); // Cerca la partita usando l'allineamento richiesto dall'utente const bool found = partite.read(_isgteq) == NOERR && part.compare_key(filter, 1, 1) == 0; return found; } // Costruisce le righe della partita bool TPartita::read(const TBill& clifo, int year, const char* num) { _conto = clifo; _anno = year; _num = num; if (allineamento_corrente() > ' ') { // Cerca la partita usando l'allineamento richiesto dall'utente if (!is_on_file()) { // Se non la trova inverte l'allineamento if (allineamento_corrente() == 'R') _num.trim(); else _num.right_just(NUMLEN); // Riprova a cercarla col nuovo allineamento if (!is_on_file()) allinea(); // Non esite: e' una nuova partita! } } else _num.trim(); _align = allineamento_corrente(); TRiga_partite* partita = new TRiga_partite(this); // Record campione della partita TString16 str; str << clifo.tipo(); partita->renum_key(PART_TIPOCF, str); // Tipo clifo if (clifo.tipo() <= ' ') { str.cut(0); str << clifo.gruppo(); partita->renum_key(PART_GRUPPO, str); // Scrivi gruppo e conto solamente str.cut(0); str << clifo.conto(); // nei conti normali (no clifo) partita->renum_key(PART_CONTO, str); } str.cut(0); str << clifo.sottoconto(); partita->renum_key(PART_SOTTOCONTO, str); // Sottoconto o codice clifo str.cut(0); str << _anno; partita->renum_key(PART_ANNO, str); // Anno partita partita->renum_key(PART_NUMPART, _num); // Numero partita _part.read(partita); if (_part.exist(UNASSIGNED)) _part.destroy_row(UNASSIGNED); // Elimina riga saldo; TRectype* unas = new TRectype(LF_PAGSCA); // Record pagamenti non assegnati partita->copy_key_to_row(*unas); unas->put(PART_NRIGA, (int)UNASSIGNED); unas->put(SCAD_NRATA, (int)UNASSIGNED); _unassigned.read(unas); return ok(); } bool TPartita::reread() { return read(conto(), anno(), numero()); } int TPartita::write_saldo(bool re, TRectype* rec) const { TImporto saldo, doc, pag, imp; calcola_saldo(saldo, doc, pag, imp); TLocalisamfile part(LF_PARTITE); TRectype& sld = part.curr(); sld = _part.key(); // Copia conto, anno e numero partita sld.put(PART_NRIGA, (int)UNASSIGNED); // Assegna magic line number sld.put(PART_SEZ, saldo.sezione()); // Sezione saldo sld.put(PART_IMPORTO, saldo.valore()); // Saldo sld.put(PART_SEZABB, doc.sezione()); // Sezione documenti sld.put(PART_ABBUONI, doc.valore()); // Documenti sld.put(PART_SEZDIFCAM, pag.sezione()); // Sezione pagamenti sld.put(PART_DIFFCAM, pag.valore()); // Pagamenti sld.put(PART_REG, imp.sezione()); // Sezione altri importi sld.put(PART_IMPOSTA, imp.valore()); // Altri importi int r = prima_fattura(); // Cerca la prima fattura ... if (r <= 0) r = first(); // ... o la prima riga valida const TRiga_partite& row = riga(r); sld.put(PART_NUMDOC, row.get(PART_NUMDOC)); // Copia estremi documento sld.put(PART_DATADOC, row.get(PART_DATADOC)); sld.put(PART_DESCR, row.get(PART_DESCR)); const TValuta valuta(row); // Copia la valuta valuta.put(sld); sld.put(PART_CHIUSA, row.get(PART_CHIUSA)); // Copia il flag di chiusura if (rec != NULL) *rec = sld; // Scrittura del record di saldo int err = re ? part.rewrite() : part.write(); if (err != NOERR) err = re ? part.write() : part.rewrite(); return err; } int TPartita::read_saldo(TRectype& riga, TImporto& saldo, TImporto& doc, TImporto& pag, TImporto& imp) { int err = NOERR; if (riga.get_int(PART_NRIGA) != UNASSIGNED) { TLocalisamfile part(LF_PARTITE); TRectype& sld = part.curr(); sld = riga; sld.put(PART_NRIGA, (int)UNASSIGNED); err = part.read(); if (err != NOERR) { const TPartita p(riga); err = p.write_saldo(FALSE, &sld); } if (err == NOERR) riga = sld; else riga.zero(); } if (err == NOERR) { saldo.set(riga.get_char(PART_SEZ), riga.get_real(PART_IMPORTO)); doc.set(riga.get_char(PART_SEZABB), riga.get_real(PART_ABBUONI)); pag.set(riga.get_char(PART_SEZDIFCAM), riga.get_real(PART_DIFFCAM)); imp.set(riga.get_char(PART_REG), riga.get_real(PART_IMPOSTA)); } return err; } bool TPartita::write(bool re) const { if (ok()) { chiusa(TRUE); // Aggiorna flag di chiusura (non si sa mai) if (conto().tipo() > ' ' && conto().gruppo() > 0) { // Aggiunge conti cliente/fornitore mancanti for (int r = last(); r > 0; r = pred(r)) { TRiga_partite& row = riga(r); if (row.get(PART_GRUPPOCL).empty()) { row.put(PART_GRUPPOCL, conto().gruppo()); row.put(PART_CONTOCL, conto().conto()); } } } const char cur_align = allineamento_corrente(); const char req_align = allineamento_richiesto(conto().tipo()); if (cur_align > ' ' && cur_align != req_align) { if (yesno_box("La partita %d '%s' non rispetta l'allineamento " "specificato nei parametri ditta: si desidera correggerlo?", anno(), (const char*)numero())) { // Riallinea tutti i numeri partita nelle righe. rate e pagamenti ((TPartita*)this)->allinea(req_align); } } } int err = _part.write(re); if (err == NOERR) err = _unassigned.write(re); if (err == NOERR) { // Se esiste almeno una riga scrive la riga riepilogativa della partita if (ok()) write_saldo(re); // Se l'allineamento e' cambiato cancello la vecchia partita if (allineamento_corrente() != allineamento_iniziale()) { // Costruisce il vecchio numero partita TString16 num = numero(); if (allineamento_iniziale() == 'R') num.right_just(NUMLEN); else num.trim(); // Cancella vecchia partita TPartita canc(conto(), anno(), num); canc.remove(); } } return err == NOERR; } // Cancella tutta una partita bool TPartita::remove() const { const int err = _part.remove(); if (err == NOERR) _unassigned.remove(); return err == NOERR; } // Crea un nuova riga partite TRiga_partite& TPartita::new_row(int r) { if (r <= 0) for (r = 1; esiste(r); r++); CHECKD(!esiste(r), "Ue' pirla!, esiste gia' la riga ", r); TRiga_partite& nuova = (TRiga_partite&)_part.row(r, TRUE); nuova.put(PART_GRUPPOCL, conto().gruppo()); nuova.put(PART_CONTOCL, conto().conto()); return nuova; } TRiga_partite& TPartita::riga(int r) const { if (!_part.exist(r)) { yesnofatal_box("La partita %d %s del conto %c %d %d %ld (%s) è incoerente: manca la riga %d", anno(), (const char*)numero(), _conto.tipo(), _conto.gruppo(), _conto.conto(), _conto.sottoconto(), (const char*)_conto.descrizione(), r); // Ricreiamo una riga fasulla tanto per non bloccare il programma TRiga_partite& newrow = ((TPartita*)this)->new_row(r); for (int p = last(); p > 0; p = pred(p)) { const TRiga_partite& par = riga(p); for (int rr = par.rate(); rr > 0; rr--) { TRiga_scadenze& rat = par.rata(rr); if (rat.exist(r)) // Ho trovato un pagamento assegnato alla nuova riga! { newrow.put(PART_TIPOMOV, (int)tm_pagamento); // Imposta il tipo movimento newrow.put(PART_SEZ, par.sezione() == 'D' ? 'A' : 'D'); // Imposta sezione al contrario della fattura TValuta val(par); val.put(newrow); // Copia valuta da fattura } } } } return (TRiga_partite&)_part.row(r); } TRiga_scadenze& TPartita::rata(int nriga, int nrata) const { const TRiga_partite& r = riga(nriga); return r.rata(nrata); } bool TPartita::rata_chiusa(int nriga, int nrata) const { bool pag = FALSE; if (nriga != UNASSIGNED) { const TRiga_scadenze& r = rata(nriga, nrata); pag = r.chiusa(); } return pag; } bool TPartita::esistono_abbuoni_diffcam(long nreg) const { int nrata = 0; const int nriga = prima_fattura(nreg); if (nriga > 0) nrata = riga(nriga).ultima_rata_con_abbuoni_diffcam(); return nrata > 0; } const TString& TPartita::codice_valuta() const { const int ultima = last(); return ultima > 0 ? riga(ultima).codice_valuta() : (const TString &) EMPTY_STRING; } bool TPartita::in_valuta() const { const int ultima = last(); return ultima > 0 ? riga(ultima).in_valuta() : FALSE; } TRectype& TPartita::pagamento(int nriga, int nrata, int nrigp) { if (nriga == UNASSIGNED) return _unassigned.row(nrigp, TRUE); TRiga_scadenze& r = rata(nriga, nrata); return r.row(nrigp); } // Controlla l'esistenza di una riga, rata, pagamento. // Gli ultimi parametri possono essere nulli per poter testare una singola riga o rata bool TPartita::esiste(int nriga, int nrata, int nrigp) const { if (nriga == UNASSIGNED) // Cerca solo pagamento non assegnato return _unassigned.exist(nrigp); const bool esiste_riga = _part.exist(nriga); if (!esiste_riga || nrata <= 0) // Riga non esistente o rata nulla return esiste_riga; const TRiga_partite& r = riga(nriga); const bool esiste_rata = r.exist(nrata); if (!esiste_rata || nrigp <= 0) // Rata inesistente o pagamento nullo return esiste_rata; const TRiga_scadenze& scad = r.rata(nrata); return scad.exist(nrigp); // Cerca pagamento vero e proprio } bool TPartita::elimina_pagamento(int nriga, int nrata, int nrigp) { const bool ok = esiste(nriga, nrata, nrigp); if (ok) { if (nriga == UNASSIGNED) { TRectype old_pag(_unassigned.row(nrigp)); old_pag.put(PAGSCA_ACCSAL, "A"); old_pag.zero(PAGSCA_IMPORTO); old_pag.zero(PAGSCA_IMPORTOVAL); old_pag.zero(PAGSCA_RITENUTE); const TValuta val; modifica_pagamento(old_pag, val, TRUE); } else { TRiga_scadenze& scad = rata(nriga, nrata); scad.elimina_pagamento(nrigp); } } return TRUE; } // Ritorna l'importo in lire speso su di una riga contabile TImporto TPartita::importo_speso(long nreg, int numrig, bool valuta, int mode) const { TImporto imp; for (int r = last(); r > 0; r = pred(r)) { const TRiga_partite& row = riga(r); if (nreg == row.get_long(PART_NREG) && numrig == row.get_int(PART_NUMRIG)) imp += row.importo(valuta, mode); } return imp; } void TPartita::update_reg(long nreg, const TRectype& mov, TPartite_array& pa) { for (int r = last(); r > 0; r = pred(r)) { TRiga_partite& rig = riga(r); if (rig.get_long(PART_NREG) == nreg) { rig.put(PART_NREG, mov.get(MOV_NUMREG)); rig.put(PART_DATAREG, mov.get(MOV_DATAREG)); rig.put(PART_DATADOC, mov.get(MOV_DATADOC)); rig.put(PART_NUMDOC, mov.get(MOV_NUMDOC)); rig.put(PART_REG, mov.get(MOV_REG)); rig.put(PART_PROTIVA, mov.get(MOV_PROTIVA)); rig.put(PART_CODCAUS, mov.get(MOV_CODCAUS)); if (rig.tipo() == tm_fattura) { rig.put(PART_IMPTOTDOC, mov.get(MOV_TOTDOC)); if (rig.in_valuta()) rig.put(PART_IMPTOTVAL, mov.get(MOV_TOTDOCVAL)); else rig.zero(PART_IMPTOTVAL); } else { const int numrig = rig.get_int(PART_NUMRIG); CHECK(numrig > 0, "Bad NUMRIG"); const TImporto imptotdoc = pa.importo_speso(nreg, numrig, FALSE, 0x9); rig.put(PART_IMPTOTDOC, imptotdoc.valore()); if (rig.in_valuta()) { const TImporto imptotval = pa.importo_speso(nreg, numrig, TRUE, 0x1); rig.put(PART_IMPTOTVAL, imptotval.valore()); } else rig.zero(PART_IMPTOTVAL); } } } } // 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 = last(); r > 0; r = pred(r)) { const TRiga_partite& row = riga(r); if (numreg == row.get_long(PART_NREG)) { if (rm <= 0 || rm == row.get_int(PART_NUMRIG)) return r; } } return 0; } // Trova la prima riga della partita corrispondente alla registrazione nreg int TPartita::prima_riga(long nreg, tipo_movimento tipo) const { const int lastrow = last(); for (int r = first(); r <= lastrow; r = succ(r)) { const TRiga_partite& row = riga(r); if (tipo == tm_nessuno || tipo == row.tipo()) if (nreg <= 0 || nreg == row.get_long(PART_NREG)) return r; } return -1; } // Trova la prima riga della partita contenente una fattura int TPartita::prima_fattura(long nreg) const { return prima_riga(nreg, tm_fattura); } // Trova la prima riga della partita contenente una pagamento int TPartita::primo_pagamento(long nreg) const { return prima_riga(nreg, tm_pagamento); } void TPartita::calcola_saldo(TImporto& saldo, TImporto& doc, TImporto& pag, TImporto& imp) const { doc = pag = imp = TImporto('D', ZERO); for (int r = last(); r > 0; r = pred(r)) { const TRiga_partite& row = riga(r); const TImporto i(row.importo(FALSE, 0x9)); const tipo_movimento tipo = row.tipo(); switch (tipo) { case tm_fattura: case tm_nota_credito: doc += i; // documenti break; case tm_pagamento: pag += i; // pagamenti break; default: imp += i; // altri importi break; } if (tipo >= tm_pagamento) { const TImporto abbuoni(row.importo(FALSE, 0x2)); imp += abbuoni; const TImporto diffcam(row.importo(FALSE, 0x4)); imp += diffcam; } } saldo = doc; saldo += pag; saldo += imp; saldo.normalize(); doc.normalize(); pag.normalize(); imp.normalize(); } TImporto TPartita::calcola_saldo(bool valuta) const { TImporto saldo; for (int r = last(); r > 0; r = pred(r)) { const TRiga_partite& row = riga(r); saldo += row.importo(valuta); } return saldo; } TImporto TPartita::calcola_saldo_al(bool valuta,const TDate& al, const TDate & data_scaduto, const TDate& data_rischio) const { TImporto saldo; // const bool calcolo_rischio = data_rischio.ok(); for (int r = last(); r > 0; r = pred(r)) { const TRiga_partite& row = riga(r); /* vecchia implementazione if (row.is_fattura()) { for (int s = row.rate(); s > 0 ;s--) { const TRiga_scadenze & rata = row.rata(s); const TDate data(rata.get(SCAD_DATASCAD)); if (data <= al) saldo += rata.importo(valuta); } } else { const TDate data = row.get(PART_DATAPAG); if (calcolo_rischio) { const int tipopag = row.get_int(PART_TIPOPAG); if (tipopag < 2 || tipopag > 7) { if (data <= al) saldo += row.importo(valuta); } else if (data <= data_rischio) saldo += row.importo(valuta); } else if (data <= al) saldo += row.importo(valuta); */ const TDate data(row.get(PART_DATAREG)); if (data <= al) { saldo += row.importo(valuta); if (!row.is_fattura()) { const int tipopag = row.get_int(PART_TIPOPAG); if (tipopag >= 2 && tipopag <= 7) { bool sbf = FALSE; saldo -= row.esposto(valuta, data_scaduto, data_rischio, sbf); } } } } return saldo; } real TPartita::calcola_scaduto_al(bool valuta,const TDate& al) const { const int ultima = last(); if (ultima > 0) { TImporto scaduto; const TBill & c = conto(); char sezione = ' '; if (c.tipo() == 'C') sezione = 'D'; else if (c.tipo() == 'F') sezione = 'A'; else { const TRiga_partite& row = riga(ultima); const tipo_movimento t = row.tipo(); if (t == tm_fattura || t == tm_insoluto) sezione = row.sezione(); else sezione = row.sezione() == 'D' ? 'A' : 'D'; } for (int r = ultima; r > 0; r = pred(r)) { const TRiga_partite& row = riga(r); if (row.is_fattura()) { for (int s = row.rate(); s > 0 ;s--) { const TRiga_scadenze & rata = row.rata(s); const TDate data(rata.get(SCAD_DATASCAD)); if (data <= al) { scaduto += rata.importo(valuta); scaduto += rata.importo_pagato(valuta); } } } } scaduto.normalize(sezione); if (scaduto.valore() > 0) scaduto += importo_pagato_unassigned(valuta); scaduto.normalize(sezione); if (scaduto.valore() > 0) return scaduto.valore(); else return ZERO; } else return ZERO; } // Calcola il totale dei pagamenti non assegnati (eventualmente in valuta) TImporto TPartita::importo_pagato_unassigned(bool val, int mode) const { CHECKD(mode > 0x0 && mode <= 0xF, "Bad importo_pagato mode ", mode); const bool in_val = in_valuta(); const char* imp_field = (val && in_val) ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO; TImporto totale; const int last_row = _unassigned.last_row(); for (int p = _unassigned.first_row(); p <= last_row; p = _unassigned.succ_row(p)) { const TRectype& pag = _unassigned.row(p); // Riga pagamento const TRiga_partite& sum = riga(pag.get_int(PAGSCA_NRIGP)); // Riga partite const char sez = sum.sezione(); // const int tipo = sum.get_int(PART_TIPOPAG); if (mode & 0x1) totale += TImporto(sez, pag.get_real(imp_field)); if (!in_val && (mode & 0x8)) // Le ritenute non esistono nei pagamenti in valuta totale += TImporto(sez, pag.get_real(PAGSCA_RITENUTE)); if (mode & 0x2) // Voglio anche gli abbuoni { real abb(pag.get_real(PAGSCA_ABBUONI)); if (in_val && !val) // Gli abbuoni sono sempre in valuta e quindi { // devono essere convertiti opportunamente const TExchange cmb(sum); TCurrency cur(abb, cmb); cur.change_to_firm_val(); abb = cur.get_num(); } totale += TImporto(sez, abb); } if (in_val && !val && (mode & 0x4)) // Voglio anche le differenze cambio { // Esse esistono solo nei pagamenti in valuta const TImporto diffcam(sez, pag.get_real(PAGSCA_DIFFCAM)); totale += diffcam; } } return totale.normalize(); } // Controlla se esistono pagamenti riferiti alla riga nrigp bool TPartita::utilizzata(int nrigp) const { for (int p = last(); p > 0; p = pred(p)) { const TRiga_partite& fatt = riga(p); for (int r = fatt.rate(); r > 0; r--) { const TRiga_scadenze& scad = fatt.rata(r); if (scad.rows_array().exist(nrigp)) return TRUE; } } return _unassigned.exist(nrigp); } bool TPartita::modifica_pagamento(const TRectype& new_pag, const TValuta& valuta, char& old_ap, TImporto& old_abb, TImporto& old_diffcam, char& new_ap, TImporto& new_abb, TImporto& new_diffcam, bool update) { const int nriga = new_pag.get_int(PAGSCA_NRIGA); const int nrata = new_pag.get_int(PAGSCA_NRATA); const int nrigp = new_pag.get_int(PAGSCA_NRIGP); bool empty = FALSE; if (nriga != UNASSIGNED) { TRiga_scadenze& scaden = rata(nriga, nrata); empty = scaden.modifica_pagamento(new_pag, valuta, old_ap, old_abb, old_diffcam, new_ap, new_abb, new_diffcam, update); } else { const TRectype& old_pag = pagamento(nriga, nrata, nrigp); TRiga_partite& sum = riga(nrigp); empty = sum.update(old_pag, new_pag, PART_IMPORTO); sum.update(old_pag, new_pag, PART_IMPORTOVAL); sum.update(old_pag, new_pag, PART_RITENUTE); if (new_pag.get_real(PAGSCA_IMPORTO).is_zero()) _unassigned.destroy_row(nrigp); else _unassigned.row(nrigp, FALSE) = new_pag; // Non ci possono essere abbuoni o differenze cambio di sorta! old_ap = new_ap = ' '; old_abb = new_abb = old_diffcam = new_diffcam = TImporto('D', ZERO); } if (empty && !utilizzata(nrigp)) rimuovi_riga(nrigp); return empty; } bool TPartita::modifica_pagamento(const TRectype& new_pag, const TValuta& valuta, bool update) { char old_ap, new_ap; TImporto old_abbuono, new_abbuono, old_diffcam, new_diffcam; return modifica_pagamento(new_pag, valuta, old_ap, old_abbuono, old_diffcam, new_ap, new_abbuono, new_diffcam, update); } bool TPartita::chiusa(bool update) const { bool chiusa = TRUE; const int ultima = last(); if (update) { const TImporto saldo = calcola_saldo(TRUE); // Saldo in valuta chiusa = saldo.is_zero(); for (int p = ultima; p > 0; p = pred(p)) { TRiga_partite& part = riga(p); part.put(PART_CHIUSA, chiusa); } } else { if (ultima > 0) { const TRiga_partite& row = riga(ultima); chiusa = row.get_bool(PART_CHIUSA); } } return chiusa; } void TPartita::rimuovi_riga(int r) { TRiga_partite& row = riga(r); if (row.rate() > 0) row.elimina_rata(-1); else CHECKD(!utilizzata(r), "Can't remove still referenced row ", r); _part.destroy_row(r); chiusa(TRUE); } static void somma(const TRectype& vec, TRectype& nuo, const char* field) { real totale(vec.get(field)); totale += nuo.get_real(field); nuo.put(field, totale); } void TPartita::sposta_riga(int from_row, TPartita& part, int to_row) { const TRiga_partite& row = riga(from_row); TRiga_partite& nrw = part.riga(to_row); const int address_size = last()+1; int* address = new int[address_size]; memset(address, 0, address_size*sizeof(int)); TToken_string knames(64); knames.add(PART_TIPOCF); knames.add(PART_GRUPPO); knames.add(PART_CONTO); knames.add(PART_SOTTOCONTO); knames.add(PART_ANNO); knames.add(PART_NUMPART); knames.add(PART_NRIGA); knames.add(SCAD_NRATA); knames.add(PAGSCA_NRIGP); for (int i = 1; i <= row.rate(); i++) { TRiga_scadenze& scd = row.rata(i); for (int j = scd.last(); j > 0; j = scd.pred(j)) { const TRectype& pag = scd.row(j); CHECK(j < address_size, "Bad nrigp address"); if (address[j] == 0) { const TRiga_partite& vecchia = riga(j); TRiga_partite& nuova = part.new_row(part.esiste(j) ? 0 : j); for (int n = vecchia.items()-1; n >= 0; n--) // Copia tutti i campi non chiave { const char* f = vecchia.fieldname(n); if (knames.get_pos(f) < 0) nuova.put(f, vecchia.get(f)); } nuova.zero(PART_IMPORTO); nuova.zero(PART_IMPORTOVAL); nuova.zero(PART_ABBUONI); nuova.zero(PART_DIFFCAM); nuova.zero(PART_RITENUTE); address[j] = nuova.get_int(PART_NRIGA); } int new_row = to_row; // Nuova riga fattura int new_sca = i; // Nuovo numero rata (uguale a prima) const int nrigp = address[j]; // Nuova riga somma (e pagamento) if (!part.esiste(new_row, new_sca)) // Se la nuova partita non ha la rata new_row = new_sca = UNASSIGNED; // allora sposta sui non asseganti TRectype npg(LF_PAGSCA); // Nuovo record di pagamento if (part.esiste(new_row, new_sca, nrigp)) // Se il pagamento esiste di gia' { npg = part.pagamento(new_row, new_sca, nrigp); somma(pag, npg, PART_IMPORTO); somma(pag, npg, PART_IMPORTOVAL); somma(pag, npg, PART_RITENUTE); } else { if (new_sca == UNASSIGNED) npg = part.unassigned().row(nrigp, TRUE); else npg = nrw.rata(new_sca).new_row(nrigp); for (int n = pag.items()-1; n >= 0; n--) // Copia tutti i campi non chiave { const char* f = pag.fieldname(n); if (knames.get_pos(f) < 0) npg.put(f, pag.get(f)); } } const TValuta val; part.modifica_pagamento(npg, val, FALSE); scd.elimina_pagamento(j); } } delete address; rimuovi_riga(from_row); } // Sposta i pagamenti della riga r, dalla rata s compresa in poi, sui non assegnati void TPartita::scollega_pagamenti(int r, int s) { CHECKD(s > 0, "Impossibile scollegare la rata ", s); const TRiga_partite& row = riga(r); for (int i = row.rate(); i >= s; i--) { TRiga_scadenze& sc = row.rata(i); for (int j = sc.last(); j > 0; j = sc.pred(j)) { TRectype& pag = sc.row(j); CHECK(pag.get_real(PAGSCA_ABBUONI).is_zero(), "Can't detach payment with ABBUONI"); CHECK(pag.get_real(PAGSCA_DIFFCAM).is_zero(), "Can't detach payment with DIFFCAM"); pag.put(PAGSCA_NRIGA, (int)TPartita::UNASSIGNED); pag.put(PAGSCA_NRATA, (int)TPartita::UNASSIGNED); pag.put(PAGSCA_ACCSAL, 'A'); if (_unassigned.exist(j)) { TRectype& unas = _unassigned.row(j, FALSE); somma(pag, unas, PAGSCA_IMPORTO); somma(pag, unas, PAGSCA_IMPORTOVAL); } else _unassigned.add_row(pag); sc.rows_array().destroy_row(j); } } } // Trova la riga di causale corrispondente ad un tipo di pagamento int TPartita::tipopag2causale(int tipo) const { int caus = 2; switch (tipo) { case 2: // Tratta caus = 3; break; case 3: // Ricevuta bancaria caus = 4; break; case 4: // Cessione caus = 5; break; case 5: // Paghero' caus = 6; break; case 6: // Fattura di credito caus = 7; break; case 7: // Tratta accettata caus = 8; break; case 1: // Rimessa case 8: // Rapporti interbancari diretti case 9: // Bonifico default: caus = 2; break; } return caus; } /////////////////////////////////////////////////////////// // 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, TPartita::NUMLEN, num); else _key.format("%c%3d%3d%6ld%4d%*s", clifo.tipo(), clifo.gruppo(), clifo.conto(), clifo.sottoconto(), anno, TPartita::NUMLEN, 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); add(k, p); } return p; } TPartita* TPartite_array::find(const TRectype& r, bool create) { TBill zio; zio.get(r); if (zio.gruppo() == 0) { zio.set(r.get_int(PART_GRUPPOCL), r.get_int(PART_CONTOCL), zio.codclifo(), zio.tipo()); } const int anno = r.get_int(PART_ANNO); const TString num(r.get(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); CHECK(game, "Partita errata"); return *game; } TPartita& TPartite_array::partita(const TRectype& r) { TPartita* game = find(r, TRUE); CHECK(game, "Partita errata"); return *game; } bool TPartite_array::insert(TPartita* p) { const TString& k = key(p->conto(), p->anno(), p->numero()); TPartita* old = (TPartita*)objptr(k); if (old != NULL) remove(k); add(k, p); return old != NULL; } bool TPartite_array::destroy(const TBill& clifo, int anno, const char* num) { const TString& k = key(clifo, anno, num); return remove(k); } bool TPartite_array::destroy(TPartita& game) { const TString& k = key(game.conto(), game.anno(), game.numero()); return remove(k); } bool TPartite_array::write(bool re) { bool ok = TRUE; TPartita* game; restart(); while ((game = (TPartita*)get()) != NULL) { ok = game->write(re); if (!ok) // L'errore viene gia' segnalato dalla partita break; } return ok; } void TPartite_array::destroy() { TAssoc_array::destroy(); _numreg = 0; } // Aggiunge all'array tutte le partite che si riferiscono alla registrazione nreg int TPartite_array::add_numreg(long nreg) { if (nreg != _numreg) { TRelation rel(LF_PARTITE); TRectype& part = rel.curr(); part.zero(); part.put(PART_NREG, nreg); // Uso un cursore per evitare conflitti di lettura con l'oggetta partita TCursor cur(&rel, "", 2, &part, &part); cur.freeze(); for (cur = 0; cur.ok(); ++cur) partita(part); // Aggiungi partita se non esiste gia' _numreg = nreg; } return items(); } bool TPartite_array::utilizzata(long numreg, int numrig) { bool ok = FALSE; for (TPartita* game = first(); game; game = next()) { ok = game->mov2rig(numreg, numrig) > 0; if (ok) break; } return ok; } TImporto TPartite_array::importo_speso(long nreg, int numrig, bool valuta, int mode) { TImporto imp; // add_numreg(nreg); // Gia' fatto nella read del movimento nreg for (TPartita* game = first(); game; game = next()) imp += game->importo_speso(nreg, numrig, valuta, mode); imp.normalize(); return imp; } void TPartite_array::update_reg(const TRectype& mov, long old_nreg) { if (old_nreg <= 0 && old_nreg != NUMREG_PROVVISORIO) old_nreg = mov.get_long(MOV_NUMREG); // add_numreg(nreg); // Non farlo mai piu', carica movimenti registrati contemporaneamente! const int tot = items(); if (tot > 0) { TPartita** giochi = new TPartita*[tot]; int i = 0; for (TPartita* game = first(); game; game = next()) giochi[i++] = game; while (--i >= 0) giochi[i]->update_reg(old_nreg, mov, *this); delete [] giochi; } } TRiga_partite* TPartite_array::mov2rig(long numreg, int numrig) { for (TPartita* game = first(); game; game = next()) { const int r = game->mov2rig(numreg, numrig); if (r > 0) return &game->riga(r); } return NULL; }