#include #include #include "saldacon.h" #include #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) { 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) 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) : _cod(cod), _dat(dat), _cam(cam) { adjust(); } TValuta::TValuta() : _cod(""), _dat(TODAY), _cam(1.0) {} void TValuta::adjust() { _cod.upper(); if (_cod.empty() || _cod == "LIT" || _cam.is_zero()) _cam = 1.0; } int TValuta::compare(const TSortable& s) const { const TValuta& v = (const TValuta&)s; real c(_cam); c -= v._cam; return c.sign(); } void TValuta::get(const TRectype& rec) { _cod = rec.get("CODVAL"); _dat = rec.get("DATACAM"); _cam = rec.get_real("CAMBIO"); adjust(); } void TValuta::put(TRectype& rec) const { if (in_lire()) { rec.zero("CODVAL"); rec.zero("DATACAM"); rec.zero("CAMBIO"); } else { rec.put("CODVAL", _cod); rec.put("DATACAM", _dat); rec.put("CAMBIO", _cam); } } void TValuta::set(TMask& m, short v, short d, short c) const { if (in_lire()) { m.reset(v); m.reset(d); m.reset(c); } else { m.set(v, _cod); m.set(d, _dat.string()); m.set(c, _cam.string()); } } void TValuta::get(const TMask& m, short v, short d, short c) { _cod = m.get(v); _dat = m.get(d); _cam = real(m.get(c)); adjust(); } real TValuta::lit2val(const real& lit) const { real val(lit); val /= _cam; val.round(2); return val; } real TValuta::val2lit(const real& val) const { real lit(val); lit *= _cam; lit.round(); return lit; } void TValuta::val2lit(real& val) const { val *= _cam; val.round(); } void TValuta::val2lit(TImporto& imp) const { val2lit(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) {} 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 rata e' stata completamente pagata bool TRiga_scadenze::chiusa(bool update) const { bool chiusa; if (update) { TImporto imp(importo_da_pagare(TRUE)); imp += importo_pagato(TRUE, 0x3); 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 > 0 && mode < 8, "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 (mode & 0x2) // Voglio anche gli abbuoni { real abb(pag.get_real(PAGSCA_ABBUONI)); if (!val && in_val) { abb *= sum.get_real(PART_CAMBIO); abb.round(); } totale += TImporto(sez, abb); } if (!val && (mode & 0x4)) // Voglio anche le differenze cambi { 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_da_pagare(bool val) const { const char* imp_field = (val && in_valuta()) ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO; const TRiga_partite& fatt = riga(); // Riga fattura const TImporto totale(fatt.sezione(), get_real(imp_field)); return totale; } // 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_da_pagare(TRUE); pag.zero(PAGSCA_ABBUONI); abbuono += importo_pagato(TRUE, 0x3); // Conta anche altri abbuoni 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_da_pagare(FALSE); pag.zero(PAGSCA_DIFFCAM); diffcam += importo_pagato(FALSE, 0x7); // 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_da_pagare(val)); residuo += importo_pagato(val, mode); // Somma con sezione opposta 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) { old_abb.valore() *= sum.get_real(PART_CAMBIO); old_abb.valore().round(); } 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()) { new_abb.valore() *= sum.get_real(PART_CAMBIO); new_abb.valore().round(); } 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); // Aggiorna flags di chiusura chiusa(TRUE); partita().chiusa(TRUE); const bool empty = new_pag.get_char(PAGSCA_ACCSAL) != 'S' && new_pag.get_real(PAGSCA_IMPORTO).is_zero(); if (empty) rows_array().destroy_row(nrigp); return empty; } 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); return partita().modifica_pagamento(old_pag); } /////////////////////////////////////////////////////////// // 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(); } 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; } void TRiga_partite::elimina_rata(int r) { const int from = r <= 0 ? 1 : r; const int to = r <= 0 ? rate() : r; for (r = from; r <= to; r++) { TRiga_scadenze& scad = rata(r); for (int p = scad.last(); p > 0; p = scad.pred(p)) scad.elimina_pagamento(p); rows_array().destroy_row(r); } } int TRiga_partite::ultima_ratapagata() const { for (int r = rate(); r > 0; r--) if (rata(r).chiusa()) break; return r; } bool TRiga_partite::is_fattura() const { return get_int(PART_TIPOMOV) == 1; } int TRiga_partite::read(TBaseisamfile& f, word op) { int err = TRectype::read(f, op); 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; } int TRiga_partite::write(TBaseisamfile& f) const { const int err = is_fattura() ? TTree_rectype::write(f) : TRectype::write(f); return err; } int TRiga_partite::rewrite(TBaseisamfile& f) const { const int err = is_fattura() ? TTree_rectype::rewrite(f) : TRectype::rewrite(f); return err; } int TRiga_partite::remove(TBaseisamfile& f) const { const int err = is_fattura() ? TTree_rectype::remove(f) : TRectype::remove(f); return err; } int TRiga_partite::ultimo_pagamento(int r) const { const TRiga_scadenze& s = rata(r); return s.last(); } 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; } int TRiga_partite::rata_con_abbuoni_diffcam() const { int found = 0; for (int s = rate(); s > 0 && found == 0; s--) { const TRiga_scadenze& scad = rata(s); for (int p = scad.last(); p > 0; p = scad.pred(p)) { const TRectype& pag = scad.row(p); if (!pag.get_real(PART_ABBUONI).is_zero() || !pag.get_real(PART_DIFFCAM).is_zero()) { found = s; break; } } } return found; } /////////////////////////////////////////////////////////// // 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 char* num = r.get_str(PART_NUMPART); read(clifo, anno, num); } 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() const { char all; if (_cli_align <= ' ' || _for_align <= ' ') { #ifdef DBG warning_box("Questa applicazione usa le partite ma ignora i " "parametri ditta relativi al loro allineamento: " "continuiamo pure cosi', facciamoci del male!"); #endif carica_allineamento(); } switch (conto().tipo()) { case 'C': all = _cli_align; break; case 'F': all = _for_align; break; default : all = ' '; 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[6] != ' ') all = ' '; return all; } void TPartita::allinea(char all) { if (all <= ' ') all = allineamento_richiesto(); if (all == 'R') _num.right_just(NUMLEN); else _num.trim(); if (ok()) { _part.renum_key(PART_NUMPART, _num); _unassigned.renum_key(PAGSCA_NUMPART, _num); } } // Costruisce le righe della partita bool TPartita::read(const TBill& clifo, int year, const char* num) { _conto = clifo; _anno = year; _num = num; if (_conto.tipo() > ' ' && allineamento_corrente() > ' ') { // Prepara la chiave per verificare l'esistenza della partita specificata TLocalisamfile part(LF_PARTITE); part.zero(); part.put(PART_TIPOCF, _conto.tipo()); part.put(PART_SOTTOCONTO, _conto.codclifo()); part.put(PART_ANNO, _anno); part.put(PART_NUMPART, _num); TRectype filter(part.curr()); // Cerca la partita usando l'allineamento richiesto dall'utente if (part.read(_isgteq) == NOERR && part.curr() == filter) { // Trovata! } else { // Se non la trova inverte l'allineamento if (allineamento_corrente() == 'R') _num.trim(); else _num.right_just(NUMLEN); // Riprova a cercarla col nuovo allineamento filter.put(PART_NUMPART, _num); if (part.read(_isgteq) == NOERR && part.curr() == filter) { // Esiste: memorizzo l'allineamento } else { 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); 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()); } bool TPartita::write(bool re) const { if (ok() && conto().tipo() > ' ') { 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(); 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); // Se l'allineamento e' cambiato cancello la vecchia partita if (err == NOERR && 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_scadenze& TPartita::rata(int nriga, int nrata) const { // if (nriga <= 0) nriga = prima_fattura(); 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 (_part.exist(nriga)) nrata = riga(nriga).rata_con_abbuoni_diffcam(); return nrata > 0; } 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); } bool TPartita::esiste(int nriga, int nrata, int nrigp) const { if (nriga == UNASSIGNED) return _unassigned.exist(nrigp); if (nrata <= 0) return _part.exist(nriga); if (nrigp <= 0) { const TRiga_partite& r = riga(nriga); return r.exist(nrata); } const TRiga_scadenze& r = rata(nriga, nrata); return r.exist(nrigp); } // Ritorna l'importo in lire speso su di una riga contabile TImporto TPartita::importo_speso(long nreg, int numrig) const { TImporto imp; for (int r = last(); r > 0; r = pred(r)) { const TRiga_partite& part = riga(r); if (nreg == part.get_long(PART_NREG) && numrig == part.get_int(PART_NUMRIG)) { imp += TImporto(part.sezione(), part.get_real(PART_IMPORTO)); TImporto abbuoni(part.get_char(PART_SEZABB), part.get_real(PART_ABBUONI)); const TValuta valuta(part); if (!valuta.in_lire()) { valuta.val2lit(abbuoni); imp += TImporto(part.get_char(PART_SEZDIFCAM), part.get_real(PART_DIFFCAM)); } imp += abbuoni; } } return imp; } void TPartita::update_reg(long nreg, const TRectype& mov) { 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)); } } } // 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 (row.get_long(PART_NREG) == numreg) { if (rm <= 0 || row.get_int(PART_NUMRIG) == rm) return r; } } return 0; } // Trova la prima riga della partita contenente una fattura int TPartita::prima_fattura(long nreg) 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) if (nreg <= 0 || nreg == row.get_long(PART_NREG)) return r; } return -1; } // Trova la prima riga della partita contenente una fattura int TPartita::primo_pagamento(long nreg) 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) if (nreg <= 0 || nreg == row.get_long(PART_NREG)) 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 = last(); 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; } TImporto abbuoni(row.get_char(PART_SEZABB), row.get_real(PART_ABBUONI)); if (row.get(PART_CODVAL).not_empty()) { abbuoni.valore() *= row.get_real(PART_CAMBIO); abbuoni.valore().round(); } imp += abbuoni; imp += TImporto(row.get_char(PART_SEZDIFCAM), row.get_real(PART_DIFFCAM)); } saldo = doc; saldo += pag; saldo += imp; saldo.normalize(); doc.normalize(); pag.normalize(); imp.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) { char old_ap, new_ap; TImporto old_abbuono, new_abbuono, old_diffcam, new_diffcam; TValuta valuta; return modifica_pagamento(new_pag, valuta, old_ap, old_abbuono, old_diffcam, new_ap, new_abbuono, new_diffcam, FALSE); } bool TPartita::chiusa(bool update) { bool chiusa = FALSE; const int ultima = last(); if (ultima > 0) { const TRiga_partite& row = riga(ultima); chiusa = row.get_bool(PART_CHIUSA); } if (update) { TImporto saldo, doc, pag, imp; calcola_saldo(saldo, doc, pag, imp); const bool ora_chiusa = saldo.is_zero(); if (chiusa != ora_chiusa) { chiusa = ora_chiusa; for (int p = last(); p > 0; p = pred(p)) { TRiga_partite& part = riga(p); part.put(PART_CHIUSA, 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 r, TPartita& part) { const TRiga_partite& row = riga(r); const long nreg = row.get_long(PART_NREG); const int prima = part.prima_fattura(nreg); TRiga_partite& nrw = part.riga(prima); 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 f = 0; f < vecchia.items(); f++) { const char* fnam = vecchia.fieldname(f); if (knames.get_pos(fnam) < 0) nuova.put(fnam, vecchia.get(fnam)); } nuova.zero(PART_IMPORTO); nuova.zero(PART_IMPORTOVAL); nuova.zero(PART_ABBUONI); nuova.zero(PART_DIFFCAM); address[j] = nuova.get_int(PART_NRIGA); } const int nrigp = address[j]; TRectype npg(LF_PAGSCA); if (part.esiste(r, i, nrigp)) { npg = part.pagamento(r, i, nrigp); CHECK(npg.get_char(PAGSCA_ACCSAL) != 'S', "Can't add to soldered payment"); somma(pag, npg, PART_IMPORTO); somma(pag, npg, PART_IMPORTOVAL); } else { if (nrw.exist(i)) npg = nrw.rata(i).new_row(nrigp); else npg = part.unassigned().row(nrigp, TRUE); for (int f = 0; f < pag.items(); f++) { const char* fnam = pag.fieldname(f); if (knames.get_pos(fnam) < 0) npg.put(fnam, pag.get(fnam)); } } part.modifica_pagamento(npg); scd.elimina_pagamento(j); } } delete address; rimuovi_riga(r); } // 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); } } } /////////////////////////////////////////////////////////// // 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 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); 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::destroy(const TBill& clifo, int anno, const char* num) { const TString& k = key(clifo, anno, num); 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(); // Costruzione cursore filtrato part.zero(); part.put(PART_NREG, nreg); const TRectype filter(part); TCursor cur(&rel, "", 2, &filter, &filter); 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) { TImporto imp; add_numreg(nreg); for (TPartita* game = first(); game; game = next()) imp += game->importo_speso(nreg, numrig); imp.normalize(); return imp; } void TPartite_array::update_reg(const TRectype& mov, long old_nreg) { if (old_nreg <= 0) old_nreg = mov.get_long(MOV_NUMREG); add_numreg(old_nreg); for (TPartita* game = first(); game; game = next()) game->update_reg(old_nreg, mov); }