#include #include #include "../cg/cgsaldac.h" #include "sc2.h" #include "sc2200.h" #include "sc2201.h" #include #include #include #include #define SCADCLIFO_ALIAS 51 #define CLIFOSCAD_ALIAS 52 #define SCADPCON_ALIAS 53 #define PCONSCAD_ALIAS 54 #define MaxRowsForTotal 17 #define TPString TParagraph_string // Comodita'... struct _LinearTotal : public TObject // Oggetto base per gli elementi di tlg, tlm, tlp { // Contiene i totali da stampare su una linea real _is, // Importo in scadenza _ip, // Importo pagato _rd, // Rimesse dirette _ri, // Ri.ba/Tratte _al; // Altri virtual TObject* dup() const { return new _LinearTotal(*this); } _LinearTotal() {_is = 0.0; _ip = 0.0; _rd = 0.0; _ri = 0.0; _al = 0.0; } }; enum tipo_st {nessuno=0, tutti=1, clienti=2, fornitori=3, altri=4}; enum tipo_pe {daily, monthly, period, single}; const char * tipi_tab[10] = {"Altro","Rimesse dirette","Tratte","Ricevute bancarie","Cessioni","Paghero'", "Lettere di acc.","Tratte accettate","Rapp. interb. dir.","Bonifici"} ; class TStampaScadenzario : public TPrintapp { TRelation *_rel1, *_rel2, *_rel3; // Relazioni di lavoro... int _cur1, _cur11, // Identificatori dei cursori di lavoro... _cur2, _cur3, _cur4, _cur41, // piu' avanti spiega tutto. _cur5, _cur6, _cur7; TSelection_ext_mask *_m; TPartita *_p; // Oggetto partita corrente. Viene ricaricato ad ogni cambio partita, // ovvero ogni volta che la rata corrente cambia i "connotati" TLocalisamfile *_caus, *_partite, *_pagsca; // File delle causali, serve per reperire le descrizioni, nel caso non ci siano sul file parite TString _annopart,_datareg,_numdoc,_datadoc, // Anno partita (2 cifre), data registrazione, nr. documento, data doc. _protiva, _codval; // Numero di protocollo IVA (TString perche' se vale 0 non stampa nulla), e codice valuta TPString *_descrizione,*_ragsoc,*_des_conto; // Descrizione (da LF_PARTITE), ragione sociale (da LF_CLIFO) // Descrizione conto (da LF_PCON) TString _imp_scad,_imp_pag,_rimdir,_riba,_altri, // Valori calcolati in preprocess_page: rimesse dirette, Ri.ba e altri _cur_gr_s, _cur_co_s, _cur_codcf_s; // _imp_scad e _imp_pag vengono anch'essi calcolati in preprocess_page. TDate _datai, _dataf, _datas, // Data inizio, fine e stampa _cur_data; // Data di scadenza riferita al record corrente long _cur_codcf; // Cli/Fo riferito al record corrente int _cur_gr,_cur_co; // Gruppo/Conto riferito al record corrente. tipo_st _tipost; // Tipo di stampa impostato bool _modified, // VERO=E' stato stampato il totale giornaliero (mensile) _end_printed, // VERO=riepilogo finale da stampare _ratesald, // VERO=stampa anche le rate saldate _ordata, // VERO=ordine primario per data, FALSO=ordine primario impostato da _ordcod _ordcod, // VERO=ordine per codice, FALSO=ordine per ragione sociale _striepilogo, // VERO=stampa il riepilogo mensile per pagamento _stvaluta; // Vero se abilitata la stampa in valuta; // Se _tipost=tutti non e' possibile impostare l'ordine primario per // ragione sociale o descrizione. L'unico tipo stampa possibile e' quello // in ordine di data scadenza // Se _tipost=altri scorre il piano dei conti. // Se _tipost=clienti || fornitori scorre clifo. real _w_imp_pag, _w_imp_res; // Qui dentro memorizza i valori calcolati in calcola_pagamenti, // rispettivamente l'importo pagato e l'importo residuo, relativo alla rata. TAssoc_array _tm, _tp; // Dentro a codesti array vi sono i totali per la stampa prospetti: // durante l'elaborazione cerca la chiave relativa, aggiungendo o // aggiornando l'elemento se necessario; una volta pronto per stampare // il prospetto viene "ordinato" tramite la TAssoc_array::get_keys() // e il sort di TArray_string. _tm e' il totale del mese o del cli/fo/conto // (nel caso di ordinamento diversa da data), _tp e' il totale del periodo. // La chiave e' cosi' composta: Tipo pag.+ult. class.+cod valuta // // Qui memorizza i totali "lineari". Analogamente ai 2 precedenti // TAssoc_array, durante l'elaborazione cerca la chiave relativa, aggiungendo o // aggiornando l'elemento se necessario; esegue un sort prima di stamparlo. // Se l'ordinamento principale non e' per data utilizza tlm per i totali // del cli/fo/conto e tlp per i totali del periodo. La chiave e' per: // codice valuta TArray _tl; // Contiene tlg, tlm, tlp (vedi user_create()), cosi' vi accedo tramite un indice. TArray _uns_cache; // cache dei non assegnati: l'elemento [0] contiene un TAssoc_array dei non assegnati normali, // l'elemento [1] contiene un TAssoc_array dei non assegnati relativi a nonte dei credito. La // chiave per tali TAssoc_array e': TIPO+GRUPPO+CONTO+SOTTOCONTO+ANNO+NUMPART. // prima di ricalcolare i non assegnati e' necessario guardare in questa cache, se esiste la // chiave relativa alla partita, ed eventualmente utilizzare tale valore in memoria. static bool filter_func(const TRelation *); // Funzione di filtro [_datai.._dataf] public: // print functions virtual bool preprocess_page(int file, int counter); // Qui stampa i totali e i riepiloghi virtual bool preprocess_print(int file, int counter); // Qui non fa proprio nulla! virtual print_action postprocess_print(int file, int counter); // Qui setta i flags per stampare il riepilogo finale! virtual print_action postprocess_page(int file, int counter); // Qui fa molte cose... virtual void preprocess_header() {}; // Very Very Dummy... virtual bool user_create(); // Qui creo i cursori... virtual bool user_destroy(); // e qui li distruggo. virtual bool set_print(int); // Qui c'e' la maschera di selezione. virtual void set_page (int file, int counter); // Setta le righe di stampa. void set_page_clifo(int nriga); // Frammenti di set_page void set_page_pcon (int nriga); void print_header(); // Stampa l'header. // Le seguenti funzioni valgono con ordinamento principale per data. void print_rows_riepilogo(int& nriga, bool type, TAssoc_array& tot); // Stampa effettivamente lo specchietto void print_riepilogo(int &nriga, bool type); // type == FALSE prints month totals, type == TRUE prints period totals. void print_rows_totali(int &nriga, tipo_pe p); void print_totali(int &nriga, bool month_changed, bool ended); // month_changed indica se il mese e' cambiato. //ended indica il raggiungimento di fine periodo. // La seguente funzione serve per il riepilogo dei totali nel caso l'ordinamento principale non sia per data. void print_totali_c(int &nriga, bool ended); // ended indica di stampare anche il riepilogo del periodo // Funzioni per calcolo dei pagamenti e di aggiornamento totali void check_add_key_to_tp(int t, char u); // controlla e aggiunge i valori relativi alla chiave k ai totali del prospetto void check_add_key_to_tl(tipo_pe p, int t); // controlla e aggiunge i valori elaborati all'assoc array indicato dal periodo (_tlxxx) // Ritorna TRUE se la partita corrente _p non e' piu' riferita alla scadenza corrente bool scad_changed(char tipo, int gruppo, int conto, long codcf, int anno, TString& nump); // Totalizza i pagamenti non assegnati per la partita corrente (NB si spera che siano tutti nella stessa valuta) bool in_cache(TString& k); // ritorna vero se ci sono gia' non assegnati in _uns_cache; void look_in_cache(real& a, real& b, TAssoc_array& uns, TAssoc_array& unsnc, TString& k); void calcola_unassigned(TString& k); void calcola_pagamenti(real& imp_scad, int riga, int rata, TBill& bill); // calcola i pagamenti effettuati per questa rata e il residuo eventuale TStampaScadenzario(); }; inline TStampaScadenzario& app() {return (TStampaScadenzario&)main_app();} bool TStampaScadenzario::filter_func(const TRelation *r) { // Filtro per rate saldate: se e' saldata e' ok solo quando // e' abilitato il flag; se non e' saldata va sempre bene. /* const TRectype& scad = r->curr(LF_SCADENZE); const bool saldata = scad.get_bool(SCAD_PAGATA); const bool ok = !saldata || (saldata && app()._ratesald); */ bool ok = app()._ratesald; if (!ok) { const TRectype& scad = r->curr(); ok = !scad.get_bool(SCAD_PAGATA); } return ok; } void TStampaScadenzario::check_add_key_to_tl(tipo_pe p, int t) // Aggiorna i totali per i totali sulla linea { TString kl(_codval); _LinearTotal newtot; int index = 0; // Default DAILY switch (p) // Seleziona l'assoc array da usare { case monthly: case single: index = 1; break; case period: index = 2; break; default: // Se p == daily e' gia settato di default (vedi sopra) break; } TAssoc_array& xassoc = (TAssoc_array&) _tl[index]; const bool is_key = xassoc.is_key(kl); // Esiste l'elemento ? // Se si' allora prendi quello, altrimenti prendine uno nuovo (newtot) _LinearTotal& xtotal = (is_key ? (_LinearTotal&) xassoc[kl] : newtot); //Aggiorna xtotal (importi in scadenza, pagati, riba, rimesse e altri) xtotal._is += (_w_imp_pag + _w_imp_res); xtotal._ip += _w_imp_pag; switch (t) { case 1: xtotal._rd += _w_imp_res; break; case 2: case 3: xtotal._ri += _w_imp_res; break; default: xtotal._al += _w_imp_res; break; } xassoc.add(kl,xtotal,is_key); } void TStampaScadenzario::check_add_key_to_tp(int t, char u) // Aggiorna i totali per i prospetti finali { TString k; // compone la chiave, valida per _tm e _tp k << t; if (u == '\0') u = ' '; // Per indicare che non c'e' ult class k << u << _codval ; if (_tm.is_key(k)) // Se esiste gia' in _tm allora { // gli aggiunge il valore attuale real& r=(real&)_tm[k]; r += _w_imp_res; _tm.add(k,r,TRUE); } else _tm.add(k,_w_imp_res); if (_tp.is_key(k)) // Se esiste gia' in _tp allora { // gli aggiunge il valore attuale real& r=(real&)_tp[k]; r += _w_imp_res; _tp.add(k,r,TRUE); } else _tp.add(k,_w_imp_res); } bool TStampaScadenzario::scad_changed(char tipo, int gruppo, int conto, long codcf, int anno, TString& nump) { if (_p == NULL) return TRUE; TRiga_partite& rp = _p->riga(_p->first()); if (tipo != rp.get_char(PART_TIPOCF) || gruppo != rp.get_int(PART_GRUPPO) || conto != rp.get_int(PART_CONTO) || codcf != rp.get_long(PART_SOTTOCONTO) || anno != rp.get_int(PART_ANNO) || nump != rp.get(PART_NUMPART)) return TRUE; return FALSE; } bool TStampaScadenzario::in_cache(TString& k) { int rt = FALSE; TAssoc_array& uns = (TAssoc_array&) _uns_cache[0]; TAssoc_array& unsnc = (TAssoc_array&) _uns_cache[1]; if (uns.is_key(k) || unsnc.is_key(k)) rt =TRUE; return rt; } void TStampaScadenzario::calcola_unassigned(TString& k) // Calcola i pagamenti non assegnati normali, e quelli riferiti a note di credito // ovvero quelli con tipo di movimento 2. Vanno percio' tenuti separati due totali: // _uns_cache[0] per i non assegnati normali, utilizzato per i pagamenti; // _uns_cache[1] per i non assegnati, riferiti a note di credito, da scalare all'importo in scadenza { TAssoc_array& uns = (TAssoc_array&) _uns_cache[0]; TAssoc_array& unsnc = (TAssoc_array&) _uns_cache[1]; TRecord_array& ra = _p->unassigned(); real a,b; a = 0.0; b = 0.0; for (int r = ra.last_row(); r > 0; r = ra.pred_row(r)) { const TRectype& rec = ra.row(r); const TRiga_partite& sum = _p->riga(rec.get_int(PAGSCA_NRIGP)); const char * field = (_stvaluta && sum.in_valuta() ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO); if (sum.get_int(PART_TIPOMOV) == 2) // Is it a credit note ? b += rec.get_real(field); else a += rec.get_real(field); } if (a != 0.0) // Aggiungilo a TAssoc_array dei non assegnati uns.add(k,a,TRUE); if (b != 0.0) // Aggiungilo a TAssoc_array delle note di credito unsnc.add(k,b,TRUE); } void TStampaScadenzario::look_in_cache(real& a, real& b, TAssoc_array& uns, TAssoc_array& unsnc, TString& k) //Estrae dai tassoc_array i valori, relativi alla partita corrente, di uns e unsnc, mettendoli in a e b { a = 0.0; b = 0.0; TRiga_partite& rp = _p->riga(_p->first()); k << rp.get_char(PART_TIPOCF) << rp.get_int(PART_GRUPPO) ; k << rp.get_int(PART_CONTO) << rp.get_long(PART_SOTTOCONTO); k << rp.get_int(PART_ANNO); k << rp.get(PART_NUMPART); if (uns.is_key(k)) a = (real&)uns[k]; if (unsnc.is_key(k)) b = (real&)unsnc[k]; } void TStampaScadenzario::calcola_pagamenti(real& imp_scad, int riga, int rata, TBill& bill) { TAssoc_array& uns = (TAssoc_array&) _uns_cache[0]; TAssoc_array& unsnc = (TAssoc_array&) _uns_cache[1]; TRiga_scadenze& rs = _p->rata(riga,rata); const char ssez = _p->riga(riga).sezione(); const char* field = (_stvaluta && rs.in_valuta()) ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO; const char* sfield = (_stvaluta && rs.in_valuta()) ? SCAD_IMPORTOVAL : SCAD_IMPORTO; TImporto work_imp, totalep, // Totale dei pagamenti scdz; // Importo in scadenza scdz += TImporto(ssez,rs.get_real(sfield)); totalep += rs.importo_pagato(_stvaluta); // Quanto e' stato pagato per questa scadenza? for (int p = rs.last(); p > 0; p = rs.pred(p)) // Calcola il totale pagamenti e discrimina { // Il TIPOMOV: 1,5 : fattura insoluto const TRectype pag = rs.row(p); // 2 : nota di credito const TRiga_partite& sum = _p->riga(p); // 3,4,6 : incasso/pagamento/abbuono/pag.insoluto/diff.cambio/rit.prof const char sez = sum.sezione(); const int tipomov = sum.get_int(PART_TIPOMOV); // se tipomov e' 2 (Nota di credito assegnata) // storna da scdz. In entrambi i casi si ha l'operatore +=, perche' nel TImporto e' gia' // compresa la sezione opposta if (tipomov == 2) { work_imp = TImporto(sez,pag.get_real(field)); scdz += work_imp; totalep -= work_imp; } } char norm = 'D'; if (_tipost == fornitori) norm = 'A'; else if (_tipost == altri && bill.find()) norm = bill.sezione(); totalep.normalize((norm=='D') ? 'A' : 'D'); scdz.normalize(norm); _w_imp_pag = totalep.valore(); imp_scad = scdz.valore(); real a,b; TString k; k.cut(0); look_in_cache(a,b,uns,unsnc,k); if (b > 0.0) // Scala le note di credito dalle scadenze { real gap = (b > imp_scad ? imp_scad : b); imp_scad -= gap; b -= gap; if (b > 0.0) unsnc.add(k,b,TRUE); else unsnc.remove(k); // Free some space when 0 reached. } if (a > 0.0 && imp_scad > _w_imp_pag) { // Lo scalare dei non assegnati e' progressivo a partire dalla rata piu' vecchia. // Se ce n'e' in piu' vengono ignorati. real gap = (a > imp_scad ? imp_scad : a); _w_imp_pag += gap; a -= gap; if (a > 0.0) uns.add(k,a,TRUE); else uns.remove(k); // Free some space when 0 reached } _w_imp_res = imp_scad - _w_imp_pag; } bool TStampaScadenzario::preprocess_page(int file, int counter) // Se ritorna FALSE salta questa scadenza e va alla prossima. { const TRectype &rc = current_cursor()->curr(LF_SCADENZE); char tipoc = rc.get_char(SCAD_TIPOCF); // Tipo int gruppo = rc.get_int(SCAD_GRUPPO); // Gruppo int conto = rc.get_int(SCAD_CONTO); // Conto long codcf = rc.get_long(SCAD_SOTTOCONTO); // Codice Cliente/Fornitore/Conto int annop = rc.get_int(SCAD_ANNO); // Anno partita TString nump ( rc.get(SCAD_NUMPART)); // Nr partita int nrigap = rc.get_int(SCAD_NRIGA); // Nr riga int nratap = rc.get_int(SCAD_NRATA); // Nr rata TDate datascad = rc.get_date(SCAD_DATASCAD); // Data scadenza int tipo_pag = rc.get_int(SCAD_TIPOPAG); // Tipo di pagamento char ult_cla = rc.get_char(SCAD_ULTCLASS); // Ulteriore classificazione real imp_scad ; // Importo in scadenza (vale IMPORTO o // IMPORTOVAL a seconda sia stata impostata la // stampa in valuta. if (_end_printed && (file == LF_CLIFO || file == LF_PCON)) return FALSE; // Dopo aver stampato i totali finali non deve rientrare per stampare // LF_CLIFO o LF_PCON if (_end_printed) { // Qui controlla se ci sono totali da stampare TAssoc_array& tp = (TAssoc_array&)_tl[2]; if (tp.items() == 0) return FALSE; } if (file == LF_SCADENZE && !_end_printed) { /* TCursor_sheet& cs = _m->cur_sheet(); // Sheet di selezione (CLI/FO/PCON) TCursor* c = cs.cursor(); TRectype& rec = c->curr(); if (_tipost == clienti || _tipost == fornitori) rec = current_cursor()->curr(LF_CLIFO); else if (_tipost == altri) rec = current_cursor()->curr(LF_PCON); if (!cs.checked(c->read(_isequal))) // Se non e' stato selezionato salta alla prossima scdz return FALSE; */ TBill bill(rc); if (!_m->selected(bill)) return FALSE; _descrizione->restart(); if (scad_changed(tipoc,gruppo,conto,codcf,annop,nump)) { TRectype rp(LF_PARTITE); rp.zero(); rp.put(PART_TIPOCF,tipoc); rp.put(PART_GRUPPO,gruppo); rp.put(PART_CONTO,conto); rp.put(PART_SOTTOCONTO,codcf); rp.put(PART_ANNO,annop); rp.put(PART_NUMPART,nump); if (_p) delete _p; _p = new TPartita(rp); TString k; // compone la chiave dei tassoc_array dentro a _uns_cache k << tipoc << gruppo ; k << conto << codcf; k << annop << nump; if (!in_cache(k)) calcola_unassigned(k); TRiga_partite& row = _p->riga(nrigap); _datareg = row.get_date(PART_DATAREG).string(brief); _datadoc = row.get_date(PART_DATADOC).string(brief); _numdoc = row.get(PART_NUMDOC); _protiva.format("%5ld",row.get_long(PART_PROTIVA)); *_descrizione = row.get(PART_DESCR); _codval = row.get(PART_CODVAL); //Per indicare che non e' indicata la valuta o e' LIRA (se la stampa in valuta is disabled) if (_codval.empty() || !_stvaluta) _codval = " "; if (_descrizione->items() == 0) // Se sulla partita non c'e' descrizione { // allora va leggerla sulla causale. _caus->zero(); _caus->put(CAU_CODCAUS,row.get(PART_CODCAUS)); if (_caus->read() == NOERR) *_descrizione = _caus->get(CAU_DESCR); } } calcola_pagamenti(imp_scad,nrigap,nratap, bill); if (_w_imp_res == 0.0 && ! _ratesald || imp_scad == 0.0) // Se la rata e' stata saldata e non e' abilitato il flag di stampa return FALSE; // oppure l'importo in scadenza e' 0 allora salta alla prossima scadenza _annopart.format("%d",annop); _annopart.ltrim(2); _rimdir=""; _riba=""; _altri=""; _imp_pag = ""; if (_stvaluta && _codval != " ") { _imp_scad = imp_scad.string(".3"); if (_w_imp_pag != 0.0) _imp_pag=_w_imp_pag.string(".3"); } else { _imp_scad=imp_scad.string("."); if (_w_imp_pag != 0.0) _imp_pag=_w_imp_pag.string("."); } switch (tipo_pag) { case 1: // Rimesse dirette if (_w_imp_res != 0.0) { if (_stvaluta && _codval != " ") _rimdir = _w_imp_res.string(".3"); else _rimdir=_w_imp_res.string("."); } break; case 2: // ri.ba / Tratte case 3: if (_w_imp_res != 0.0) { if (_stvaluta && _codval != " ") _riba = _w_imp_res.string(".3"); else _riba=_w_imp_res.string("."); } break; default: // Altri if (_w_imp_res != 0.0) { if (_stvaluta && _codval != " ") _altri = _w_imp_res.string(".3"); else _altri=_w_imp_res.string("."); } break; } } if (file==LF_CLIFO) { TString xxx(current_cursor()->curr(LF_CLIFO).get(CLI_RAGSOC)); *_ragsoc = xxx.strip_d_spaces(); } if (file ==LF_PCON) *_des_conto = current_cursor()->curr(LF_PCON).get(PCN_DESCR); // Se l'ordinamento principale e' per data scadenza stampa il totale del giorno e del mese if (_ordata && !_end_printed) if ((file == LF_SCADENZE && _tipost == tutti) || (file == LF_PCON && _tipost == altri) || (file ==LF_CLIFO && (_tipost == clienti || _tipost == fornitori))) { if (_cur_data != botime && _cur_data != datascad) { // Se la data di scadenza e' cambiata e non e' il primo record della relazione // allora stampa i totali del giorno. // Controlla poi se e' cambiato il mese, in caso affermativo stampa anche i // totali del mese e lo schema riepilogativo mensile bool month_changed = _cur_data.month() != datascad.month(); for (int n=1; nadd(LF_CLIFO,"TIPOCF=TIPOC|CODCF=SOTTOCONTO",1,0,SCADCLIFO_ALIAS); _cur1 = add_cursor(new TSorted_cursor(_rel1,"DATASCAD|SOTTOCONTO|ANNO|NUMPART|NRIGA|NRATA","",2)); // Per data scadenza + ragione sociale e' necessario un TSorted_cursor con update del file collegato: _cur11 = add_cursor(new TSorted_cursor(_rel1,"DATASCAD|UPPER(20->RAGSOC)|ANNO|NUMPART|NRIGA|NRATA","",2)); // Scadenze per CliFo (Codice & Ragione sociale) + data scadenza _cur2 = add_cursor(new TSorted_cursor(_rel1,"SOTTOCONTO|DATASCAD|ANNO|NUMPART|NRIGA|NRATA","",2)); _cur3 = add_cursor(new TSorted_cursor(_rel1,"UPPER(20->RAGSOC)|DATASCAD|ANNO|NUMPART|NRIGA|NRATA","",2)); _rel2 = new TRelation(LF_SCADENZE); // Scadenze per data scadenza + piano dei conti (Codice & Descrizione) _rel2->add(LF_PCON,"GRUPPO=GRUPPO|CONTO=CONTO|SOTTOCONTO=SOTTOCONTO",1,0,SCADPCON_ALIAS); _cur4 = add_cursor(new TSorted_cursor(_rel2,"DATASCAD|GRUPPO|CONTO|SOTTOCONTO|ANNO|NUMPART|NRIGA|NRATA","",2)); // Per data scadenza + descrizione e' necessario un TSorted_cursor con update del file collegato: _cur41 = add_cursor(new TSorted_cursor(_rel2,"DATASCAD|UPPER(19->DESCR)|ANNO|NUMPART|NRIGA|NRATA","",2)); // Scadenze per Conti (Codice & descrizione) + data scadenza _cur5 = add_cursor(new TSorted_cursor(_rel2,"GRUPPO|CONTO|SOTTOCONTO|DATASCAD|ANNO|NUMPART|NRIGA|NRATA","",2)); _cur6 = add_cursor(new TSorted_cursor(_rel2,"UPPER(19->DESCR)|DATASCAD|ANNO|NUMPART|NRIGA|NRATA","",2)); _rel3 = new TRelation(LF_SCADENZE); // Scadenze (Tutte) per data scadenza _cur7 = add_cursor(new TCursor(_rel3,"",2)); _caus = new TLocalisamfile(LF_CAUSALI); _partite = new TLocalisamfile(LF_PARTITE); _pagsca = new TLocalisamfile(LF_PAGSCA); _descrizione = new TParagraph_string("",17); _ragsoc = new TParagraph_string("",17); _des_conto = new TParagraph_string("",17); _tl.add(new TAssoc_array);_tl.add(new TAssoc_array);_tl.add(new TAssoc_array); _uns_cache.add(new TAssoc_array);_uns_cache.add(new TAssoc_array); TConfig conf (CONFIG_DITTA,"cg"); _m = new TSelection_ext_mask("sc2200a"); _m->enable(F_VALUTA,conf.get_bool("GesVal")); enable_print_menu(); return TRUE; } bool TStampaScadenzario::user_destroy() { // // Color che di Printapp conoscon nulla, // evitar, dovrebber, il delete che trastulla // onde la nausea, ch'assale il tuo fardello, // mejo la new lasciar nel suo castello. // // Nota del trastullatore: // Mai fare la delete di un cursore usato // dalla printapp, poiche' e' lei stessa che // effettua tale operazione nella propria destroy(). // if (_rel1) delete _rel1; if (_rel2) delete _rel2; if (_rel3) delete _rel3; if (_caus) delete _caus; if (_partite) delete _partite; if (_pagsca) delete _pagsca; if (_descrizione) delete _descrizione; if (_des_conto) delete _des_conto; if (_ragsoc) delete _ragsoc; _tl.destroy(); _uns_cache.destroy(); _tm.destroy(); _tp.destroy(); if (_m) delete _m; // la delete di _tl viene fatta nel distruttore dell'applicazione. return TRUE; } bool TStampaScadenzario::set_print(int) { const bool ok = _m->run() == K_ENTER; if (ok) { _end_printed = FALSE; reset_files(); reset_print(); // Inizializza i membri necessari al calcolo totali nel caso sia stato scelto l'ordine // primario secondo la data di scadenza. if (_m->get_who() == 'P') _tipost = altri; else if (_m->get_who() == 'C') _tipost = clienti; else _tipost = fornitori; if (_m->get_key() == 1) _ordcod = TRUE; else _ordcod = FALSE; _cur_data = botime; _tm.destroy(); _tp.destroy(); // Totali per i prospetti for (int it=0; it < _tl.items(); it++) { TAssoc_array& aa = (TAssoc_array&) _tl[it]; aa.destroy(); // Totali lineari (tlg, tlm, tlp) } // Inizializza i membri necessari al calcolo totali nel caso sia stato scelto l'ordine // primario per codice/gr.co.so. ragione sociale/descrizione _cur_codcf = -1; _cur_gr=_cur_co = -1; // Per calcolare i totali nel caso l'ordine primario non sia per data scadenze // utilizzera' le variabili _tp_* per il totale generale e _tm_* per i singoli totali. // E' necessario resettare anche queste TParagraph_string... Puo' servire in futuro... *_ragsoc = ""; *_des_conto = ""; *_descrizione = ""; _ratesald = _m->get_bool(F_RATESALDATE); _ordata = _m->get_bool(F_ORDDATA); _stvaluta = _m->get_bool(F_VALUTA); _striepilogo = _m->get_bool(F_RIEPILOGO); _datai = (const char *)(_m->get(F_DATASCADENZAI)); _dataf = (const char *)(_m->get(F_DATASCADENZAF)); _datas = (const char *)(_m->get(F_DATASTAMPA)); // N.B I cursori sono tutti TSorted_cursor; alcuni di questi(_cur11 e _cur41) referenziano a campi di sort // presenti anche su altri file (LF_CLIFO o LF_PCON), percio' e' necessario che il metodo filtercursor() // (v. TCursor o TSorted_cursor) forzi un update della relazione ad ogni record che viene processato. // I cursori 1,2,4 e 6 sono TSorted_cursor anch'essi, siccome la funzione di filtro deve reperire il nr. // di record del file inerente alla selezione, e' necessario fare l'update ogni volta. // I cursori hanno tutti la stessa funzione di filtro, per la stampa della rate saldate. // L'unico TCursor e' _cur7, poiche' e' utilizzato per stampare solo i record di LF_SCADENZE. get_cursor(_cur1)->set_filterfunction(filter_func,TRUE); // Cursore 1: Datascad + Clifo (codice) get_cursor(_cur11)->set_filterfunction(filter_func,TRUE);// Cursore 1.1: Datascad + Clifo (ragione sociale) get_cursor(_cur2)->set_filterfunction(filter_func,TRUE); // Cursore 2: Clifo(codice) + Datascad get_cursor(_cur3)->set_filterfunction(filter_func,TRUE); // Cursore 3: Clifo(ragione sociale) + Datascad get_cursor(_cur4)->set_filterfunction(filter_func,TRUE); // Cursore 4: Datascad + PCon (codice) get_cursor(_cur41)->set_filterfunction(filter_func,TRUE);// Cursore 4.1: Datascad + PCon (descrizione) get_cursor(_cur5)->set_filterfunction(filter_func,TRUE); // Cursore 5: PCon (Codice) + Datascad get_cursor(_cur6)->set_filterfunction(filter_func,TRUE); // Cursore 6: PCon (descrizione) + Datascad get_cursor(_cur7)->set_filterfunction(filter_func); // Cursore 7: Datascad // Setta l'intervallo di data. Si puo' fare per tutti i cursori, poiche' // il file principale e' sempre LF_SCADENZE. TRectype da_data(LF_SCADENZE), a_data(LF_SCADENZE); da_data.put(SCAD_DATASCAD,_datai); a_data.put(SCAD_DATASCAD,_dataf); get_cursor(_cur1)->setregion(da_data,a_data); get_cursor(_cur11)->setregion(da_data,a_data); get_cursor(_cur2)->setregion(da_data,a_data); get_cursor(_cur3)->setregion(da_data,a_data); get_cursor(_cur4)->setregion(da_data,a_data); get_cursor(_cur41)->setregion(da_data,a_data); get_cursor(_cur5)->setregion(da_data,a_data); get_cursor(_cur6)->setregion(da_data,a_data); get_cursor(_cur7)->setregion(da_data,a_data); switch (_tipost) { case tutti: select_cursor(_cur7); add_file(LF_SCADENZE); break; case clienti: case fornitori: if (_ordata) // Ordine primario per data { // Controlla l'ordine secondario (codice o ragione sociale) if (_ordcod) // Per codice... { select_cursor(_cur1); if (_tipost==clienti) get_cursor(_cur1)->setfilter("(TIPOC=\"C\")"); else get_cursor(_cur1)->setfilter("(TIPOC=\"F\")"); } else { select_cursor(_cur11); // Per ragione sociale if (_tipost==clienti) get_cursor(_cur11)->setfilter("(TIPOC=\"C\")"); else get_cursor(_cur11)->setfilter("(TIPOC=\"F\")"); } } else // Ordine primario per codice o ragione sociale { if (_ordcod) // Codice... { select_cursor(_cur2); if (_tipost==clienti) get_cursor(_cur2)->setfilter("(TIPOC=\"C\")"); else get_cursor(_cur2)->setfilter("(TIPOC=\"F\")"); } else // Ragione sociale { select_cursor(_cur3); if (_tipost==clienti) get_cursor(_cur3)->setfilter("(TIPOC=\"C\")"); else get_cursor(_cur3)->setfilter("(TIPOC=\"F\")"); } } add_file(LF_SCADENZE); add_file(LF_CLIFO,LF_SCADENZE); break; case altri: if (_ordata) // Ordine primario per data { // Controlla l'ordine secondario (Codice o descrizione) if (_ordcod) // Per codice ... { select_cursor(_cur4); get_cursor(_cur4)->setfilter("(TIPOC=\"\")"); // Filtro per i conti normali! } else { select_cursor(_cur41); // Per descrizione. get_cursor(_cur41)->setfilter("(TIPOC=\"\")"); } } else // Ordine primario per codice o descrizione { if (_ordcod) // Codice... { select_cursor(_cur5); get_cursor(_cur5)->setfilter("(TIPOC=\"\")"); // Filtro per i conti normali! } else // Descrizione { select_cursor(_cur6); get_cursor(_cur6)->setfilter("(TIPOC=\"\")"); // Filtro per i conti normali! } } add_file(LF_SCADENZE); add_file(LF_PCON,LF_SCADENZE); break; default: break; } } if (_p) delete _p; // Questo deve essere cancellato, altrimenti rimane in memoria, _p = NULL; // provocando casini al prossimo "giro" TAssoc_array& a =(TAssoc_array&) _uns_cache[0]; TAssoc_array& b =(TAssoc_array&) _uns_cache[1]; a.destroy(); b.destroy(); // Libera i TAssoc_array impiegati. return ok; } void TStampaScadenzario::print_header() // Setta le righe dell'intestazione { int soh = 1; const long firm = get_firm(); reset_header (); TLocalisamfile ditte(LF_NDITTE); ditte.zero(); ditte.put(NDT_CODDITTA, firm); ditte.read(); if (ditte.bad()) ditte.zero(); TString s; s = ditte.get(NDT_RAGSOC); TString data = _datas.string(); TString datai = _datai.string(); TString dataf = _dataf.string(); switch (_tipost) { case fornitori: case clienti: { TString rw(201); TString s1,s2; set_header (soh++, "Ditta : %ld %s@148gData@153g%s @190gPag. @#", firm, (const char *)s, (const char *)data); if (_tipost==fornitori) { set_header(soh++,"@72g** SCADENZARIO FORNITORI **"); s1 = "Ns."; s2 = "Banca"; } else { set_header(soh++,"@73g** SCADENZARIO CLIENTI **"); s1 =""; s2 = ""; } set_header (soh++,"@64gPer il periodo dal %s al %s",(const char*)datai,(const char*)dataf); rw.fill('-'); set_header(soh++, (const char *) rw); set_header(soh++,"@28gRif.@38gData@47gData@77gCd/Tp@91g%s",(const char*)s1); set_header(soh++,"Codice@9gRagione sociale@28gpartita@38gscadenza@47gRegistr." "@56gDescrizione@77gPag.@86gRata@91g%s@97gVal." "@106gImp. in sca.@125gImp. pagati@144gRimesse dir.@163gRi.ba./Tratte@182gAltri",(const char*)s2); set_header(soh++,"@28gData e Nr doc. @46gProt. IVA"); set_header(soh++,(const char *)rw); break; } case altri: // Piano dei conti { TString rw(201); set_header (soh++, "Ditta : %ld %s@152gData@157g%s @190gPag. @#", firm, (const char *)s, (const char *)data); set_header(soh++,"@79g** SCADENZARIO **"); set_header (soh++,"@66gPer il periodo dal %s al %s",(const char*)datai,(const char*)dataf); rw.fill('-'); set_header(soh++, (const char *) rw); set_header(soh++,"@33gRif.@43gData@53gData@82gCd/Tp"); set_header(soh++,"Gr. Co. So.@16gDescrizione@33gpartita@43gscadenza@53gRegistr." "@61gDescrizione@82gPag.@89gRata@97gVal." "@106gImp. in sca.@125gImp. pagati@144gRimesse dir.@163gRi.ba./Tratte@182gAltri"); set_header(soh++,"@36gData e Nr doc. @54gProt. IVA"); set_header(soh++,(const char *)rw); break; } default: break; } set_header(soh,""); } void TStampaScadenzario::set_page_clifo(int nriga) // Setta le righe per stampare le scadenze clienti/fornitori { set_row(nriga++,""); set_row(nriga,"@b#6t@r",&_cur_codcf_s); set_row(nriga,"@b@9g#a@r",_ragsoc); set_row(nriga,"@28g#2t",&_annopart); set_row(nriga,"@30g/@7s",FLD(LF_SCADENZE,SCAD_NUMPART)); set_row(nriga,"@38g@d",FLD(LF_SCADENZE,SCAD_DATASCAD)); set_row(nriga,"@47g#t",&_datareg); set_row(nriga,"@56g#a",_descrizione); set_row(nriga,"@77g@4,rs/@1n",FLD(LF_SCADENZE,SCAD_CODPAG),FLD(LF_SCADENZE,SCAD_TIPOPAG)); set_row(nriga,"@86g@4n",FLD(LF_SCADENZE,SCAD_NRATA)); if (_tipost == fornitori) set_row(nriga,"@91g@5pn",FLD(LF_SCADENZE,SCAD_CODABIPR,"@@@@@")); set_row(nriga,"@97g#t", &_codval); set_row(nriga,"@101g#18t",&_imp_scad); set_row(nriga,"@120g#18t",&_imp_pag); set_row(nriga,"@139g#18t",&_rimdir); // rimesse dirette set_row(nriga,"@158g#18t",&_riba); // Ri.ba. / tratte set_row(nriga++,"@177g#18t",&_altri); // Altri tipi di pagamento set_row(nriga,"@31g#t",&_datadoc); set_row(nriga,"@40g#t",&_numdoc); set_row(nriga,"@49g#-5t",&_protiva); } void TStampaScadenzario::set_page_pcon(int nriga) // Setta le righe per stampare le scadenze degli altri conti. { set_row(nriga++,""); set_row(nriga,"@b#3t@5g#3t@9g#6t@r",&_cur_gr_s,&_cur_co_s,&_cur_codcf_s); set_row(nriga,"@b@16g#a@r",_des_conto); set_row(nriga,"@33g#2t/@7s",&_annopart,FLD(LF_SCADENZE,SCAD_NUMPART)); set_row(nriga,"@43g@d@53g#t",FLD(LF_SCADENZE,SCAD_DATASCAD),&_datareg); set_row(nriga,"@61g#a",_descrizione); set_row(nriga,"@82g@4,rs/@1n@89g@4n",FLD(LF_SCADENZE,SCAD_CODPAG),FLD(LF_SCADENZE,SCAD_TIPOPAG), FLD(LF_SCADENZE,SCAD_NRATA)); set_row(nriga,"@97g#t", &_codval); set_row(nriga,"@101g#18t",&_imp_scad); set_row(nriga,"@120g#18t",&_imp_pag); set_row(nriga,"@139g#18t",&_rimdir); // rimesse dirette set_row(nriga,"@158g#18t",&_riba); // Ri.ba. / tratte set_row(nriga++,"@177g#17t",&_altri); // Altri tipi di pagamento set_row(nriga,"@36g#t@45g#t@54g#-5t",&_datadoc,&_numdoc,&_protiva); } void TStampaScadenzario::set_page(int file, int counter) { int nriga =1; print_header(); switch (_tipost) { case fornitori: case clienti: if (file == LF_CLIFO) set_page_clifo(nriga); break; case altri: if (file == LF_PCON) set_page_pcon(nriga); break; default: break; } } void TStampaScadenzario::print_rows_riepilogo(int& nriga, bool type, TAssoc_array& tot) { TString_array as; TAssoc_array& t = (type ? _tp : _tm); const int items = t.items(); t.get_keys(as); as.sort(); for (int i=0; i < items; i++) { TString k (as.row(i)); TString val(k.right(3)); TString value; real& v = (real&)t[k]; const int tipo = k[0]-'0'; const char ult = k[1]; if (_stvaluta && val != " ") value = v.string(".3"); else value = v.string("."); if (v != 0.0) set_row(nriga++,"@0g!@3g%s@25g!@27g%c@32g!@34g%s@39g!@42g%18s@60g!", tipi_tab[tipo], ult, (const char*) val, (const char*) value); // Cerca la valuta "val" nell'assoc array dei totali per il prospetto if (tot.is_key(val)) { real& tv = (real&) tot[val]; tv += v; tot.add(val,tv,TRUE); } else // Se non esiste aggiunge il valore tot.add(val,v); } } void TStampaScadenzario::print_riepilogo(int &nriga, bool type) // Setta le righe di stampa per lo schema riepilogativo con ordinamento primario per data // Con type == 1 stampa il riepilogo del periodo; viceversa quello del mese. { TString s(61); TAssoc_array totali; // Assoc array per i totali distinti per valuta TString_array as; s.fill('-'); nriga++; set_row(nriga++,"%s",(const char *)s); if (!type) { if (_ordata) { set_row(nriga++,"@0g!@2g%s@60g!",itom(_cur_data.month())); set_row(nriga++,"%s",(const char*)s); } } else { set_row(nriga,"!@5gTotali dal %s al ",_datai.string(brief)); set_row(nriga++,"%s@60g!",_dataf.string(brief)); set_row(nriga++,"%s",(const char *)s); } print_rows_riepilogo(nriga, type, totali); totali.get_keys(as); as.sort(); const int items = totali.items(); for (int i=0; i < items; i++) { TString val(as.row(i)); TString value; real& tot = (real&)totali[val]; if (_stvaluta && val != " ") value = tot.string(".3"); else value = tot.string("."); if (tot != 0.0) { if (i == 0) set_row(nriga++,"%s",(const char *)s); // Se c'e' almeno un totale != 0 allora stampa il separe' set_row(nriga++,"!@34g%s@42g%18s@60g!",(const char*) val, (const char*) value); } else { if (val == " ") val = "LIT"; set_row(nriga++,"! Partite pareggiate in %s. @60g!",(const char*) val); } } set_row(nriga++,"%s",(const char *)s); } void TStampaScadenzario::print_rows_totali(int &nriga, tipo_pe p) { int index = 0; // Default of DAILY switch (p) { case monthly: case single: index = 1; break; case period: index = 2; break; default: break; } TAssoc_array& xassoc = (TAssoc_array&) _tl[index]; TString_array as; const int items = xassoc.items(); xassoc.get_keys(as); as.sort(); for (int i=0; i < items; i++) { TString k(as.row(i)); // Chiave di ordinamento(valuta) TString value; _LinearTotal& v = (_LinearTotal&)xassoc[k]; if (k != " ") set_row(nriga,"@97g%3s",(const char*)k); if (_stvaluta && k != " ") value = v._is.string(".3"); else value = v._is.string("."); if (v._is != 0.0) set_row(nriga,"@101g%18s",(const char*) value); if (_stvaluta && k != " ") value = v._ip.string(".3"); else value = v._ip.string("."); if (v._ip != 0.0) set_row(nriga,"@120g%18s",(const char*) value); if (_stvaluta && k != " ") value = v._rd.string(".3"); else value = v._rd.string("."); if (v._rd != 0.0) set_row(nriga,"@139g%18s",(const char*) value); if (_stvaluta && k != " ") value = v._ri.string(".3"); else value = v._ri.string("."); if (v._ri != 0.0) set_row(nriga,"@158g%18s",(const char*) value); if (_stvaluta && k != " ") value = v._al.string(".3"); else value = v._al.string("."); if (v._al != 0.0) set_row(nriga,"@177g%18s",(const char*) value); set_row(++nriga,""); } set_row(++nriga,""); } void TStampaScadenzario::print_totali(int &nriga, bool month_changed, bool ended) // Setta le righe per stampare i totali (giorno e mese) delle scadenze clienti/fornitori // Ordinamento primario per data! { set_row(nriga,"@36g** TOTALI DEL @51g%s",_cur_data.string(brief)); print_rows_totali(nriga, daily); if (month_changed) { set_row(nriga,"@36g** TOTALI DI @51g%s",itom(_cur_data.month())); print_rows_totali(nriga, monthly); if (_striepilogo) print_riepilogo(nriga,FALSE); } if (ended) { set_row(nriga++,""); set_row(nriga,"@36g** TOTALI PERIODO"); print_rows_totali(nriga, period); if (_striepilogo) print_riepilogo(nriga,TRUE); set_row(nriga++,"");set_row(nriga++,""); set_row(nriga++,"");set_row(nriga++,""); } } void TStampaScadenzario::print_totali_c(int &nriga, bool ended) // Setta le righe per stampare i totali delle scadenze clienti/fornitori/conti // Ordinamento primario per codice o ragione sociale! { if (_tipost==clienti) set_row(nriga,"@70g** TOTALE CLIENTE"); else if (_tipost ==fornitori) set_row(nriga,"@70g** TOTALE FORNITORE"); else // altri... set_row(nriga,"@70g** TOTALE CONTO"); print_rows_totali(nriga, single); if (_striepilogo) print_riepilogo(nriga,FALSE); if (ended) { set_row(nriga,"@70g** TOTALE GENERALE"); print_rows_totali(nriga, period); if (_striepilogo) print_riepilogo(nriga,TRUE); set_row(nriga++,"");set_row(nriga++,""); set_row(nriga++,"");set_row(nriga++,""); } } TStampaScadenzario::TStampaScadenzario() { _rel1=_rel2=_rel3=NULL; _p = NULL; } int sc2200(int argc, char** argv) { TStampaScadenzario app; app.run(argc, argv, "Stampa Scadenzario"); return 0; }