#include "../cg/saldacon.h" #include #include #include #include #include "sc21pec.h" #include "sc2403.h" #include TESSL_mask::TESSL_mask(const char *name) : TSelection_mask(name), _ditta(LF_NDITTE) { _ditta.add(LF_ANAG, "TIPOA==TIPOA|CODANAGR==CODANAGR"); _ditta.add(LF_COMUNI, "COM==COMRF(COMRES)", 1, LF_ANAG, 101); _ditta.add(LF_COMUNI, "COM==COMRES", 1, LF_ANAG, 102); } TESSL_mask::~TESSL_mask() {} void TESSL_mask::on_firm_change() { TMask::on_firm_change(); _ditta[0].put("CODDITTA", prefix().get_codditta()); if (_ditta.read() == NOERR) { const int alias = _ditta[LF_ANAG].get_char("TIPOA") == 'F' ? -101 : -102; set(F_LUOGOSEND, _ditta.lfile(alias).get("DENCOM")); } } void TESSL_mask::start_run() { on_firm_change(); } const char *TESSL_mask::get_prof_base() const { return BASE_EC_PROFILE; } const TString &TESSL_mask::get_prof_code() const { return get(F_CODPROF); } const TString &TESSL_mask::get_prof_lang() const { return get(F_LINPROF); } /////////////////////////////////////////////////////////// // TESSL_row /////////////////////////////////////////////////////////// TESSL_row::TESSL_row(const TRiga_partite& row, const TDate& data, const TImporto& imp, int rata): _num_prot(0) { _riga = row.get_int(PART_NRIGA); _rata = rata; _data = data; _causale = row.get(PART_CODCAUS); _data_doc = row.get(PART_DATADOC); _num_prot = row.get_long(PART_PROTIVA); _importo = imp; _importo.normalize(); _totale = row.get_real(PART_IMPTOTPAG); _valuta.get(row); } TESSL_row::TESSL_row(const char* desc, const TImporto& imp) : _riga(9999), _rata(9999), _num_prot(0), _salvo_buon_fine(FALSE) { _descrizione = desc; _importo = imp; _importo.normalize(); } // le righe dell'estratto conto sono ordinate per data, riga partita, numero rata, // posizione iniziale nell'array (in caso di uguaglianza di tutto il resto) int TESSL_row::compare(const TSortable& s) const { const TESSL_row& r = (const TESSL_row&)s; int c = 0; if (_data == r._data) { c = r._riga - _riga; if (c == 0) c = r._rata - _rata; } else c = _data < r._data ? +1 : -1; return c; } void TESSL_row::set_imp(TForm_item& fi, const real& imp, bool valuta) const { TString old_picture; if (valuta) { old_picture = fi.picture(); TString new_picture(20); new_picture = old_picture; if (old_picture.find(',') > 0) new_picture << ".###"; else new_picture << ",###"; fi.set_picture(new_picture); } fi.set(imp.string()); if (valuta) { fi.set_picture(old_picture); } } void TESSL_row::print_on(TPrint_section& body) { TESSL_form& form = (TESSL_form&)body.form(); TForm_item& causale = body.find_field(PEC_CODCAUS); causale.set(_causale); if (_causale.not_empty() && _descrizione.empty()) { TDecoder& causali = form.causali(); _descrizione = causali.decode(_causale); } TForm_item& descr = body.find_field(PEC_DESCR1); descr.set(_descrizione); TForm_item& datadoc = body.find_field(PEC_DATADOC); datadoc.set(_data_doc.string()); TForm_item& numdoc = body.find_field(PEC_NUMDOC); numdoc.set(_num_doc); TForm_item& numprot = body.find_field(PEC_PROTIVA); TString16 protiva; protiva << _num_prot; numprot.set(protiva); TForm_item& datapag = body.find_field(PEC_DATAPAG); datapag.set(_data.string()); const real& imp = _importo.valore(); TForm_item& dare = body.find_field(PEC_DARE); TForm_item& avere = body.find_field(PEC_AVERE); if (_importo.sezione() == 'D') { dare.set(imp.string()); avere.set(""); } else { avere.set(imp.string()); dare.set(""); } TForm_item& importo_in_lire = body.find_field(PEC_IMPLIRE); importo_in_lire.set(_importo_lire.string()); TForm_item& scaduto = body.find_field(PEC_SCADUTO); scaduto.set(_scaduto.string()); TForm_item& esposto = body.find_field(PEC_ESPOSTO); esposto.set(_esposto.string()); TForm_item& sbf = body.find_field(PEC_SBF); sbf.set(_salvo_buon_fine ? "*" : " "); TForm_item& cambio = body.find_field(PEC_CAMBIO); cambio.set(_valuta.cambio().string()); TForm_item& datacambio = body.find_field(PEC_DATACAM); datacambio.set(_valuta.data().string()); body.update(); } static int val_compare(const void* o1, const void* o2) { const THash_object* h1 = (const THash_object*)o1; const THash_object* h2 = (const THash_object*)o2; const TString& s1 = (const TString&)h1->obj(); const TString& s2 = (const TString&)h2->obj(); return s2.compare(s1, -1, TRUE); // same as stricmp(s1, s2) in reverse order } /////////////////////////////////////////////////////////// // TESSL_array /////////////////////////////////////////////////////////// // Calcola l'importo su di una riga di pagamento TImporto TESSL_array::importo(const TPartita& game, const TRectype& pag, bool valuta) const { const int nriga = pag.get_int(PAGSCA_NRIGA); const TRiga_partite& fat = game.riga(nriga); const bool fat_val = fat.in_valuta(); const int nrigp = pag.get_int(PAGSCA_NRIGP); const TRiga_partite& sum = game.riga(nrigp); const char sez = sum.sezione(); const char* const field = valuta && fat_val ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO; TImporto imp(sez, pag.get_real(PAGSCA_IMPORTO)); if (!fat_val) imp.valore() += pag.get_real(PAGSCA_RITENUTE); if (pag.get_char(PAGSCA_ACCSAL) == 'S') { real abb(pag.get(PAGSCA_ABBUONI)); if (!valuta && fat_val) { const TValuta val(sum); val.val2lit(abb); abb += pag.get_real(PAGSCA_DIFFCAM); } imp.valore() += abb; } return imp; } // Certified 100% TImporto& TESSL_array::importo_riga_scaduto(int n) { CHECKD(n > 0 && n < 9999, "Riga scaduto errata ", n); TImporto* imp = importo_riga_scaduto_ptr(n); if (imp == NULL) { imp = new TImporto; _scaduto.add(imp, n); } return *imp; } real TESSL_array::calcola_scaduto(const TRiga_scadenze& rata, bool valuta) { const TPartita& game = rata.partita(); const char sezione = _form->sezione_normale(); TImporto scaduto_rata = rata.importo(TRUE); int riga_corrente_scaduto = 0; const int lastp = rata.last(); // Ultimo pagamento sulla rata corrente for (int p = rata.first(); p <= lastp; p = rata.succ(p)) // Qui bisogna andare in avanti! { const TRectype& pag = rata.row(p); const int nrigp = pag.get_int(PAGSCA_NRIGP); const TRiga_partite& sum = game.riga(nrigp); TImporto imp = importo(game, pag, valuta); tipo_movimento tm = sum.tipo(); // Determina tipo riga // Normalmente gli utenti non usano il tipo pagamento insoluto, per cui devo // riconoscere i pagamenti che in realta' sono a fronte di insoluti: // 1) hanno tipo movimento = tm_pagamento // 2) ho gia' incontrato un insoluto // 3) il saldo della rata e' a zero o sommando l'importo arriva sotto zero if (tm == tm_pagamento && riga_corrente_scaduto != 0) { if (scaduto_rata.is_zero()) { tm = tm_pagamento_insoluto; } else { TImporto p(scaduto_rata); p += imp; p.normalize(sezione); if (p.valore() < ZERO) { scaduto_rata.set('D', ZERO); imp += p; tm = tm_pagamento_insoluto; } } } if (tm == tm_insoluto || tm == tm_pagamento_insoluto) { if (tm == tm_insoluto) riga_corrente_scaduto = nrigp; else CHECKD(riga_corrente_scaduto > 0, "Pagamento insoluto senza insoluto ", p); importo_riga_scaduto(riga_corrente_scaduto) += imp; } else { scaduto_rata += imp; } } scaduto_rata.normalize(sezione); return scaduto_rata.valore(); } TESSL_row& TESSL_array::new_row(const TRiga_partite& row, const TDate& data, const TImporto& imp, int n) { CHECKD(n > 0, "Numero rata errato: ", n); TESSL_row* riga = new TESSL_row(row, data, imp, n); add(riga, n); return *riga; } void TESSL_array::add_row(const TRiga_partite& row) { const bool in_valuta = form().in_valuta(); real importo_in_lire(ZERO); const char sezione = form().sezione_normale(); if (row.is_fattura()) { for (int r = 1; r <= row.rate(); r++) { const TRiga_scadenze& rata = row.rata(r); const TDate data(rata.get(SCAD_DATASCAD)); if (data <= form().data_limite_operazione()) { TESSL_row& rec = new_row(row, data, rata.importo(in_valuta), r); if (in_valuta) { TImporto i(rata.importo(FALSE)); i.normalize(sezione); rec.importo_in_lire(i.valore()); } if (data <= form().data_limite_scaduto()) { const real s = calcola_scaduto(rata, in_valuta); rec.scaduto(s); } } } } else { const TDate data(row.get(PART_DATAPAG)); if (data <= form().data_limite_operazione()) { const TImporto imp(row.importo(in_valuta, 0x1)); TESSL_row& riga = new_row(row, data, imp, 1); if (in_valuta) { TImporto i(row.importo(FALSE, 0x1)); i.normalize(sezione); riga.importo_in_lire(i.valore()); } const int tipo_pag = row.get_int(PART_TIPOPAG); if (tipo_pag >= 2 && tipo_pag <= 7) // Controlla se e' un pagamento con effetti { const TDate data_pag(row.get(PART_DATAPAG)); const TDate& dls = form().data_limite_scaduto(); const int gr = form().giorni_rischio(); bool sbf = FALSE; if (gr > 0) { const TDate& dir = form().data_inizio_rischio(); sbf = data_pag > dir && data_pag <= dls; riga.salvo_buon_fine(sbf); // Esposto salvo buon fine } bool esp = sbf; if (!esp) { esp = gr > 0 ? data_pag >= dls : data_pag > dls; // Esposto normale } if (esp) { TImporto esposto(imp); esposto.normalize(sezione); riga.esposto(esposto.valore()); } } const TImporto abbuoni(row.importo(in_valuta, 0x2)); if (!abbuoni.is_zero()) { TESSL_row& r = new_row(row, data, abbuoni, 2); r.descrizione(form().describe(302)); if (in_valuta) { TImporto i(row.importo(FALSE, 0x2)); i.normalize(sezione); r.importo_in_lire(i.valore()); } } TImporto diffcam(row.importo(FALSE, 0x4)); if (!diffcam.is_zero()) { if (in_valuta) { TESSL_row& r = new_row(row, data, TImporto('D', ZERO), 3); r.descrizione(form().describe(303)); diffcam.normalize(sezione); r.importo_in_lire(diffcam.valore()); } else { TESSL_row& r = new_row(row, data, diffcam, 3); r.descrizione(form().describe(303)); } } TImporto ritenute(row.importo(FALSE, 0x8)); if (!ritenute.is_zero()) { if (in_valuta) { TESSL_row& r = new_row(row, data, TImporto('D', ZERO), 3); r.descrizione(form().describe(304)); ritenute.normalize(sezione); r.importo_in_lire(ritenute.valore()); } else { TESSL_row& r = new_row(row, data, ritenute, 3); r.descrizione(form().describe(304)); } } } } } TESSL_array::TESSL_array(const TPartita& game, const TESSL_form* f) :_form(f) { for (int r = game.last(); r > 0; r = game.pred(r)) add_row(game.riga(r)); const char sezione = f->sezione_normale(); for (r = items()-1; r >= 0; r--) { TESSL_row& s = row(r); if (s.rata() == 1) { TImporto* imp = importo_riga_scaduto_ptr(s.riga()); if (imp != NULL) { imp->normalize(sezione); s.scaduto(imp->valore()); } } } sort(); } /////////////////////////////////////////////////////////// // TESSL_form: form speciale per estratti conto e solleciti /////////////////////////////////////////////////////////// void TESSL_form:: header_handler(TPrinter& pr) { TPrint_section& head = _form->section('H'); head.reset(); pr.resetheader(); head.update(); for (word j = 0; j < head.height(); j++) pr.setheaderline(j, head.row(j)); } static int tot_compare(const void* o1, const void* o2) { if (o1 == o2) // Sfrutto una piccola debolezza di qsort: return 0; // ogni tanto confronta oggetti con se stessi const THash_object* h1 = (const THash_object*)o1; const THash_object* h2 = (const THash_object*)o2; return stricmp(h1->key(), h2->key()); } void TESSL_form::footer_handler(TPrinter& pr) { TPrint_section& foot = _form->section('F'); pr.resetfooter(); const word MAXTOT = 16; THash_object* tot[MAXTOT]; // I totali sono in un assoc array disordinato per cui li copio in un array e li ordino // alfabeticamente in base al loro codice valuta TTotalizer& totali = _form->totali(); totali.restart(); word numtot = 0; for (THash_object* obj = totali.get_hashobj(); numtot < MAXTOT && obj != NULL; obj = totali.get_hashobj()) tot[numtot++] = obj; qsort(tot, numtot, sizeof(THash_object*), tot_compare); const word maxtot = foot.height() / _form->_footer_used; if (numtot > maxtot) numtot = maxtot; const TString& riporto = _form->describe(301, 'F'); TString desc(80); TPrint_section& body = _form->section('B'); for (word j = 0; j < numtot; j++) { const word line = j * _form->_footer_used; const TString& key = tot[j]->key(); TTotal& t = (TTotal&)(tot[j]->obj()); desc = riporto; if (key.not_empty()) desc << ' ' << key; TESSL_row rip(desc, t.importo().normalize()); rip.scaduto(t.scaduto()); rip.esposto(t.esposto()); rip.print_on(body); for (int fl = 0; fl < _form->_footer_used; fl++) pr.setfooterline(line, body.row(fl)); } } bool TESSL_form::print_game(const TPartita& game) { bool ok = FALSE; TESSL_array righe(game, this); TPrinter& pr = printer(); TPrintrow prow; TPrint_section& body = section('B'); TImporto saldo; real scaduto, esposto; // Stampa le righe di partita int ultima_riga = 0; int ultima_rata = 0; for (int r = 0; r < righe.items(); r++) { TESSL_row& riga = righe.row(r); if (pr.rows_left() < body.height()) pr.formfeed(); const int ri = riga.riga(); const int ra = riga.rata(); if (ri == ultima_riga && ra == ultima_rata+1) riga.reset_causale(); ultima_riga = ri; ultima_rata = ra; riga.print_on(body); pr.print(body.row(0)); totali().add(riga.importo(), riga.scaduto(), riga.esposto(), riga.valuta().codice()); saldo += riga.importo(); scaduto += riga.scaduto(); esposto += riga.esposto(); ok = TRUE; } if (ok) { saldo.normalize(); TESSL_row sld(describe(301), saldo); sld.scaduto(scaduto); sld.esposto(esposto); sld.print_on(body); pr.print(body.row(0)); // Salta una riga vuota TPrintrow vuota; pr.print(vuota); } return ok; } const TString& TESSL_form::describe(short id, char sez) const { const TForm_item& fi = find_field(sez, odd_page, id); return fi.prompt(); } TESSL_form::TESSL_form(const TESSL_mask& m, short id_datalim, short id_datascad, short id_giorni_rischio) :TForm(BASE_EC_PROFILE, m.get_prof_code()), _causali(LF_CAUSALI, CAU_CODCAUS, CAU_DESCR) { _form = this; TForm_item& imp_lire = find_field('B', odd_page, PEC_IMPLIRE); _in_valuta = imp_lire.shown(); // Il profilo e' in valuta se c'e' la colonna importo in lire _lingua = m.get_prof_lang(); TCursor_sheet& cs = m.cur_sheet(); _cursore = cs.cursor(); _dlo = m.get(id_datalim); if (id_datascad > 0) _dls = m.get(id_datascad); else _dls = _dlo; if (id_giorni_rischio > 0) _giorni_rischio = m.get_int(id_giorni_rischio); _dir = _dls; _dir -= _giorni_rischio; TPrinter& pr = printer(); pr.setheaderhandler(header_handler); pr.headerlen(section('H').height()); pr.setfooterhandler(footer_handler); pr.footerlen(section('F').height()); const TPrint_section& foot = section('F'); pr.footerlen(foot.height()); for (int i = foot.fields()-1; i >= 0; i--) { TForm_item& fi = foot.field(i); if (fi.y() > _footer_used) _footer_used = fi.y(); } } TESSL_form::~TESSL_form() { TPrinter& pr = printer(); pr.setheaderhandler(NULL); pr.setfooterhandler(NULL); _form = NULL; }