diff --git a/ve/ve1100.cpp b/ve/ve1100.cpp index df48f1d1d..99b7bfff2 100755 --- a/ve/ve1100.cpp +++ b/ve/ve1100.cpp @@ -1,111 +1,584 @@ - #include #include #include #include -#include #include -#include #include #include -#include +#include #include -#include +#include -#include "righedoc.h" #include "sconti.h" #include "tclifor.h" +#include "velib01.h" #include "ve1100.h" #include "ve0100b.h" -#include "ve0100c.h" +#include "..\cg\pagament.h" -// !! Attenzione: per la compilazione di questo programma deve essere definito il simbolo -// !! __VE1100_DOWNSIZE, altrimenti in righedoc.cpp si creano degli -// !! unresolved reference in fase di link - - -struct num_of_decimals_to_round { +struct dec_parm { int pri_lit, pri_val, - qta, + qta_lit, + qta_val, // si lo so non ha senso, ma lo faccio lo stesso imp_lit, imp_val; -}; + // add other groups here +}; + +////////////////////////////////////////////////////////////////////////////////////////////// +// classe TDocumentoEsteso: oggetto che ha come finalita' il calcolo dei riepiloghi IVA +////////////////////////////////////////////////////////////////////////////////////////////// + +class Riepilogo_Iva : public TObject +{ + real _imp; + real _iva; + real _ali; + byte _tipo; + TString16 _cod; + TString _des; + +protected: + +public: + real& imp() { return _imp;} // Imponibile + real& iva() { return _iva;} // Iva + real& ali() { return _ali;} // Aliquota + TString& cod() { return _cod;} // Descrizione + TString& des() { return _des;} // Descrizione + byte& tipo(){ return _tipo;}// Tipo (Vedi opzioni per la selzione di filtro nella validate()) + void zero(){ _imp = 0.0; _iva = 0.0; _ali = 0.0; _tipo = 0; _cod = ""; _des = ""; } + virtual TObject* dup() const { return new Riepilogo_Iva(*this); } + Riepilogo_Iva& operator = (Riepilogo_Iva& a); + Riepilogo_Iva() {_imp = 0.0; _iva = 0.0; _ali = 0.0; _tipo = 0;} + ~Riepilogo_Iva() {}; +}; + +Riepilogo_Iva& Riepilogo_Iva::operator=(Riepilogo_Iva& a) +{ + _imp = a.imp(); _iva = a.iva(); _ali = a.ali(); + _cod = a.cod(); _tipo = a.tipo(); _des = a.des(); + return *this; +} + +class TDocumentoEsteso : public TDocumento +{ + // Parametri del documento + dec_parm _parm; // Parametri per gli arrotondamenti + TTable * _iva; // Tabella codici IVA + TCond_vendita * _condv; // Condizioni di vendita per lo sconto + + // Totali del documento ricalcolati non appena la tabellina di riepilogo IVA e' completa + real _importi_netti, _imposte; + + // membri per il calcolo del riepilogo IVA + bool _sum_selected; // TRUE se ha selezionato una riga del riepilogo, funge da semaforo per leggere la prossima + int _sum_filter; // Filtro corrente della riga Riepilogo_Iva in corso di stampa (-1 se non ha ancora calcolato la tabella) + TString_array _order_array; // Array di TToken_string contenenti i codici IVA soddisfacenti ad ogni tipo di filtro + TAssoc_array _summary_table; // Array dove vengono memorizzate le imposte per aliquota + Riepilogo_Iva _sum_current; // Riga corrente del riepilogo + + // membri per il calcolo del riepilogo scadenze + TString_array _scadenze_array;// Array che contiene le scadenze ("|") + int _scadenze_current; // indice per identificare l'elementi corrente sull'array (-1 se non ha ancora calcolato) + +public: + + + // Funzioni per il riepilogo IVA + const bool summary_compiled() { return _sum_filter > -1; } + void compile_summary(); // Aggiorna la tabella riepilogativa + void summary_filter(byte selector); // filtra la tabellina secondo il filtro corrente se non e' gia' stato fatto + void summary_set_next(); // seleziona il prossimo elemento del filtro + Riepilogo_Iva& sum_current() { return _sum_current; } // ritorna la riga corrente del filtro corrente + const char * summary_get(const TString& w); // ritorna l'informazione richiesta estratta dall'elemento corrente + int summary_items() { return _summary_table.items();} // ritorna il numero di righe in totale della tabellina + TAssoc_array& summary() { return _summary_table; } + + // Funzioni per il ricalcolo delle scadenze + void scadenze_recalc(); // resetta e ricalcola le scadenze + void scadenze_set_next(); // seleziona il prossimo elemento dell'array delle scadenze + const char * scadenze_get(const TString& w); // reperisce l'informazione richiesta dall'elemento corrente + int scadenze_items() { return _scadenze_array.items(); } // restituisce il numero di scadenze + TString_array& scadenze() { return _scadenze_array; } + + // Funzioni di totalizzazione + real& tot_importi_netti(); + real& tot_imposte(); + real tot_spese(); + real tot_documento(); + // restituisce tot_imponibili, tot_esenti, tot_nonsoggetti a seconda del selettore: + // 1 = regime normale + // 2 = da ventilare (non usato) + // 4 = esenti + // 8 = non imponibili + // 16 = non soggetti + // pertanto i non imponibili avranno selettore 1 e gli esenti selettore 4. + // per avere esenti + non soggetti il selettore sara' 20 e cosi' via. + real tot_imponibili(byte selector); + + // Reperisce l'informazione dal campo G1 della testata + const char* get_head_info(const TString& what); + + // Funzioni per settare i parametri + void set_decimals(dec_parm & parm) { _parm = parm ; } + void set_condv(TCliFor * cli); // Cambia le condizioni di vendita + TDocumentoEsteso (const TRectype & rec, dec_parm & parm, TCliFor * cli = NULL) ; + TDocumentoEsteso (const TRectype & rec, TCliFor * cli = NULL) ; + ~TDocumentoEsteso(); +}; + +void TDocumentoEsteso::compile_summary() +{ + _sum_filter = 0; + const int items = rows(); + + _summary_table.destroy(); + _imposte = 0.0; + _importi_netti = 0.0; + const bool val = in_valuta(); + // Scorre tutte le righe e compila la tabellina _summary_table + for (int i = 1; i <= items; i++) + { + TRectype& r = row(i); + int nriga = r.get_int("NRIGA"); + real price = r.get_real("PREZZO"); + real qta = r.get_real("QTA"); + real aliquota, sc, imponibile, iva; + TString sconto(r.get("SCONTO")); + TString codiva(r.get("CODIVA")); + _iva->put("CODTAB", codiva); + if (_iva->read() != NOERR) continue; // Se non trova il codice salta questa riga + + aliquota = _iva->get_real("R0"); + if (_condv != NULL && sconto.not_empty()) // Se c'e' la condizione di vendita, calcola lo sconto... + { + _condv->set_sconto(sconto); + sc = 100.0 - _condv->sconto_val(); + price = ((price * sc) / 100.0); + } + price.round(val ? _parm.pri_val : _parm.pri_lit); // prezzo scontato + qta.round(val ? _parm.qta_val : _parm.qta_lit); + imponibile = price * qta; + imponibile.round (val? _parm.imp_val : _parm.imp_lit); // imponibile di riga + iva = (imponibile * aliquota) / 100.0; + iva.ceil(val ? _parm.imp_val : _parm.imp_lit); // imposta calcolata + + // Aggiorna o aggiunge l'elemento se non esiste + Riepilogo_Iva riepilogo_tmp; + const bool exists = _summary_table.is_key(codiva); + Riepilogo_Iva& riepilogo = (exists ? (Riepilogo_Iva&)_summary_table[codiva] : riepilogo_tmp); + // Aggiorna anche il totale importi netti ed il totale imposte + _importi_netti += imponibile; + _imposte += iva; + riepilogo.imp() += imponibile; riepilogo.iva() += iva; + riepilogo.ali() = aliquota; riepilogo.cod() = codiva; + TString16 tipo(_iva->get("S1")); + if (tipo == "VE") riepilogo.tipo() = 2; + else if (tipo == "ES") riepilogo.tipo() = 4; + else if (tipo == "NI") riepilogo.tipo() = 8; + else if (tipo == "NS") riepilogo.tipo() = 16; + else riepilogo.tipo() = 1; // Regime IVA normale + if (riepilogo.tipo() != 1) // Se non e' regime normale salva anche la descrizione + riepilogo.des() = _iva->get("S0"); + _summary_table.add(codiva,riepilogo,exists); + } + // Inizializza l'array di ordine + for (i = 0; i<32;i++) + { + TToken_string s; + _order_array.add(s); + } +} + +void TDocumentoEsteso::summary_filter(byte selector) +{ + if (_sum_filter == -1) compile_summary(); // Crea la tabella se deve ancora farlo + // se ha selezionato una riga in precedenza deve finire di stamparla + // ovvero non seleziona il filtro fino a quando non ha ricevuto una summary_set_next() + if (_sum_selected) return; + // + // Procedimento: + // Memorizza in un TString_array tante TToken_string quanti sono i filtri possibili + // (al massimo 31 [1+2+4+8+16]). Ogni TToken_string contiene i codici IVA + // delle righe di Riepilogo_Iva che soddisfano la condizione di filtro + _sum_selected = TRUE; + _sum_filter = selector; + TToken_string& codici = _order_array.row(_sum_filter-1); + if (codici.items() == 0) // Se non c'e' nemmeno un codice IVA allora deve effettuare il filtro + { // ovvero mette in <> tutti i codici IVA che soffisfano tale filtro + // sara' poi la summary_set_next() a selezionare sequenzialmente il giusto codice a seconda del filtro corrente + + // Scorre sequenzialmente la tabella _summary_table e compone la TToken_string coni codici IVA + const int items = _summary_table.items(); + Riepilogo_Iva* curr = (Riepilogo_Iva *) _summary_table.first_item(); + for (int i = 0; i < items && curr != NULL; i++) + { + if (curr->tipo() & _sum_filter) // se fa parte del filtro selezionato schiaffa il codice nella TToken_string + codici.add(curr->cod()); + curr = (Riepilogo_Iva*) _summary_table.succ_item(); + } + codici.restart(); + summary_set_next(); // setta l'elemento corrente + } +} + +void TDocumentoEsteso::summary_set_next() +{ + _sum_selected = FALSE; + TToken_string& codici = _order_array.row(_sum_filter-1); + + TString16 codiva(codici.get()); // Reperisce il prossimo codice nella lista. (son gia' ordinati per codice) + if (codiva.not_empty() && _summary_table.is_key(codiva)) + { + // Estrae da _summary_table i dati relativio al codice corrispondente. + Riepilogo_Iva& riep= (Riepilogo_Iva&) _summary_table[codiva]; + _sum_current = riep; + } + else + _sum_current.zero(); // se non esiste il codice azzera l'elemento corrente (non stampera' nulla) +} + +const char * TDocumentoEsteso::summary_get(const TString& w) +{ + TString ret; + if (w == "COD") ret = _sum_current.cod(); // Ritorna il codice IVA + if (w == "IMP" && _sum_current.imp() != 0.0) ret = _sum_current.imp().string(); // Ritorna l'imponibile + if (w == "IVA" && _sum_current.iva() != 0.0) ret = _sum_current.iva().string(); // Ritorna l'imposta + if (w == "ALI" && _sum_current.ali() != 0.0) ret = _sum_current.ali().string(); // Ritorna l'aliquota % + if (w == "DES") ret = _sum_current.des(); // Ritorna la descrizione ( se il codice e' regime normale la descr. e' vuota) + return (const char *)ret; +} + +void TDocumentoEsteso::scadenze_recalc() +{ + _scadenze_array.destroy(); + _scadenze_current = -1; + TString16 codpag(head().get("CODPAG")); + TString16 data(head().get("DATAINSC")); + TPagamento pag( codpag, data); + real totspese = tot_spese(); + real totimposte = tot_imposte(); + real totimponibili = tot_documento() - totimposte - totspese; + const bool valuta = in_valuta(); + if (valuta) + { + real change(cambio()); + real val1 = totimponibili * change; + real val2 = totimposte * change; + real val3 = totspese * change; + pag.set_total_valuta( totimponibili, totimposte, totspese, change, val1, val2 ,val3); + } + else + pag.set_total( totimponibili, totimposte, totspese ); + pag.set_rate_auto( ); + const int numrate = pag.n_rate( ); + for (int i = 0; i< numrate; i++) + { + TToken_string t; + t.add(pag.data_rata(i)); + t.add(pag.importo_rata(i,valuta).string()); + _scadenze_array.add(t); + } + if (numrate > 0) _scadenze_current++; +} + +const char * TDocumentoEsteso::scadenze_get(const TString& w) +{ + TString ret; + + if (_scadenze_current == -1) + // calcola le scadenze e le mette in _scadenze_array + scadenze_recalc(); + if (_scadenze_current > -1 && _scadenze_current < _scadenze_array.items()) + { + if (w == "DATA") ret = _scadenze_array.row(_scadenze_current).get(0); // ritorna la data di scadenza + if (w == "IMPORTO") ret = _scadenze_array.row(_scadenze_current).get(1); // ritorna l'importo in scadenza + } + return (const char*)ret; +} + +void TDocumentoEsteso::scadenze_set_next() +{ + if (_scadenze_current < _scadenze_array.items() && _scadenze_current >= 0) + _scadenze_current++; +} + +real& TDocumentoEsteso::tot_importi_netti() +{ + if (!summary_compiled()) compile_summary(); + return _importi_netti; +} + +real& TDocumentoEsteso::tot_imposte() +{ + if (!summary_compiled()) compile_summary(); + return _imposte; +} + +real TDocumentoEsteso::tot_spese() +{ + TString16 t("TOTSP"); + real number(get_head_info(t)); + return number; +} + +real TDocumentoEsteso::tot_documento() +{ + if (!summary_compiled()) compile_summary(); + real number = _imposte + _importi_netti; + return number; +} + +real TDocumentoEsteso::tot_imponibili(byte selector) +{ + if (!summary_compiled()) compile_summary(); + + real number = 0.0; + const int items = _summary_table.items(); + Riepilogo_Iva* curr = (Riepilogo_Iva *) _summary_table.first_item(); + for (int i = 0; i < items && curr != NULL; i++) + { + if (curr->tipo() & selector) // se fa parte del filtro selezionato schiaffa il codice nella TToken_string + number += curr->imp(); + curr = (Riepilogo_Iva*) _summary_table.succ_item(); + } + return number; +} + + +const char* TDocumentoEsteso::get_head_info(const TString & what) +{ + TToken_string memo(head().get("G1"),'\n'); // prende il campo memo con i totalizzatori. Un totalizzatore per riga nella forma = + TString rt; + const int items = memo.items(); + for (int i = 0; i + // Dove e' il numero del gruppo + // e' il numero di decimali per i documenti in lire + // e' il numero di decimali per i documenti in valuta + // ATTENZIONE: e' importante che i nomi dei gruppi utilizzati per modificare le pictures non siano usati per + // per altri messaggi. Inoltre un TForm_item che appartiene ad un gruppo di modifica picture + // non puo' appartenere ad un altro gruppo dello stesso tipo, ad esempio i gruppi 29 e 30 contemporaneamente. + // Puo' pero' appartenere anche ad altri gruppi che non siano utilizzati per lo scopo qui definito protected: virtual void extended_parse_general(TScanner &); // gestione dei parametri estesi nella sezione general virtual bool validate(TForm_item &, TToken_string &); // gestione dei messaggi estesi nei campi virtual word set_body(word p, bool u); // derivata per la gestione del totalizzatore + void edit_picture(TForm_item & f, const int dec); + void modify_pictures(); public: const TString &get_module_code() { return _module; } // ritorna il codice del modulo di carta - TDocVen_Form(const char *, TRelation &); + TString_array & exclude_list() { return _exclude_array; } + TDocVen_Form(const char *, TRelation &, TDocumentoEsteso * ); virtual ~TDocVen_Form(); }; -TDocVen_Form::TDocVen_Form(const char* name, TRelation &rel): TForm(), _firmrel(rel) { +TDocVen_Form::TDocVen_Form(const char* name, TRelation &rel, TDocumentoEsteso * doc): TForm(), _firmrel(rel) { read(name); - _total_prog= new TPiede_documento; - _riga= new TRiga; _cliente= new TCliFor; _cli_loaded= FALSE; + _doc = doc; + modify_pictures(); + dec_parm p; + const int items = _group_decimals.items(); + for (int i = 0; i< items; i++) + { + TToken_string& t = _group_decimals.row(i); + int gruppo = t.get_int(0); + switch (gruppo) + { + case 29: p.pri_lit = t.get_int(1);p.pri_val = t.get_int(2); + break; + case 30: p.qta_lit = t.get_int(1);p.qta_val = t.get_int(2); + break; + case 31: p.imp_lit = t.get_int(1);p.imp_val = t.get_int(2); + break; + // add other groups here + default: + break; + } + } + _doc->set_decimals(p); } TDocVen_Form::~TDocVen_Form() { - delete _total_prog; - delete _riga; delete _cliente; + if (_doc) delete _doc; +} + +void TDocVen_Form::edit_picture(TForm_item & fi, const int dec) +{ + TString old_picture(20); + old_picture = fi.picture(); + TString new_picture(20); + + if (old_picture.empty()) // picture di default + { + new_picture = "."; // in lire + if (dec != 0) new_picture << dec; // in valuta + } + else + { + if (dec == 0) return; // 0 non cambia la picture + + TString16 dec_to_add; + for (int i = 0; i < dec; i++) dec_to_add << "@"; // aggiunge tanti "@" quanti sono i decimali voluti + new_picture = old_picture; + if (old_picture.find(',') > 0) + new_picture << "."; // se ha trovato la virgola come separatore di migliaia significa che deve aggiungere il punto decimale + else + new_picture << ","; // altrimenti aggiunge la solita virgola + new_picture << dec_to_add; // infine aggiunge i decimali richiesti + } + const int w = fi.width(); // se la picture eccede la dimensione, toglie i caratteri piu' a sx + int exceed = w - new_picture.len(); + if (exceed<0 && w>0) + { + exceed=::abs(exceed); + new_picture = new_picture.mid(exceed,new_picture.len()-exceed); + } + fi.set_picture(new_picture); // setta la nuova picture +} + +void TDocVen_Form::modify_pictures() +{ + const bool valuta = _doc->in_valuta(); + const char sechar[4] = { 'B', 'F', 'G', 'H' }; + for (int sn = 0; sn < 4 ; sn++) + { + const char sc = sechar[sn]; + for (pagetype pt = odd_page; pt <= last_page; pt = pagetype(pt+1)) + { + TPrint_section* sec = exist(sc, pt); + if (sec != NULL) + for (word i = 0; i < sec->fields() ; i++) + { + TForm_item& fi = sec->field(i); + const int items = _group_decimals.items(); // numero di gruppi definiti + for (int j = 0; j < items; j++) + { + TToken_string& r = _group_decimals.row(j); + const int group = r.get_int(0); + if (fi.in_group(group)) // trova se appartiene al gruppo, modifica la picture + { + edit_picture(fi,valuta ? r.get_int(2) : r.get_int(1)); + break; // considera solo il primo gruppo trovato + } + } + } + } + } } word TDocVen_Form::set_body(word p, bool u) { - if (u) { // se si sta effettivamente generando il body viene fatto anche il calcolo del totalizzatore - - TLocalisamfile &rdoc= (cursor())->file(LF_RIGHEDOC); - TRectype &recriga= rdoc.curr(); - _riga->load(rdoc.curr()); - _riga->somma(*_total_prog); - } TPrint_section& body = section('B', p); return TForm::set_body(p, u); } void TDocVen_Form::extended_parse_general(TScanner &scanner) { - if (scanner.popkey() == "MO") _module= scanner.string(); // se viene riconosciuto il token per l'impostazione del modulo legge il codice... - else scanner.push(); // ...altrimenti rimette il token nella coda dello scanner + // se viene riconosciuto il token per l'impostazione del modulo legge il codice... + if (scanner.key() == "MO") _module= scanner.string(); // Legge i decimali necessari per gli arrotondamenti (il primo per gli importi in lire, l'altro per quelli in valuta) - if (scanner.popkey() == "PR") { - par_dec.pri_lit = scanner.integer(); - par_dec.pri_val = scanner.integer(); - } else scanner.push(); + if (scanner.key() == "PR") { + TToken_string t; + t.add(29);t.add(scanner.integer());t.add(scanner.integer()); + _group_decimals.add(t); + } // Stessa cosa per le quantita' - if (scanner.popkey() == "QT") - par_dec.qta = scanner.integer(); - else scanner.push(); + if (scanner.key() == "QT") + { + TToken_string t; + t.add(30);t.add(scanner.integer());t.add(scanner.integer()); + _group_decimals.add(t); + } // Stessa cosa per gli importi in genere - if (scanner.popkey() == "IM") { - par_dec.imp_lit = scanner.integer(); - par_dec.imp_val = scanner.integer(); - } else scanner.push(); - + if (scanner.key() == "IM") { + TToken_string t; + t.add(31);t.add(scanner.integer());t.add(scanner.integer()); + _group_decimals.add(t); + } + + if (scanner.key() == "NE") { + TToken_string t; + t.add(scanner.integer());t.add(scanner.integer());t.add(scanner.integer()); + _group_decimals.add(t); + } + + // Esclude certi tipi riga e codici articolo + if (scanner.key() == "EX") { + TToken_string s(scanner.string(),','); + _exclude_array.add(s); + } } bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { @@ -352,14 +825,14 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { cf.set(tel); } if (in=="REGSOC") { - TString reg(_firmrel.lfile().get("REGTRIB")); - reg << " Vol. " << _firmrel.lfile().get("VOLTRIB"); - reg << " Fasc. " << _firmrel.lfile().get("FASCTRIB"); + TString reg(_firmrel[LF_UNLOC].get("REGTRIB")); + reg << " Vol. " << _firmrel[LF_UNLOC].get("VOLTRIB"); + reg << " Fasc. " << _firmrel[LF_UNLOC].get("FASCTRIB"); cf.set(reg); } if (in=="CCIAA") { - TString cod(_firmrel.lfile().get("NUMCCIAA")); - cod << " del " << _firmrel.lfile().get("DATAICCIAA"); + TString cod(_firmrel[LF_UNLOC].get("NUMCCIAA")); + cod << " del " << _firmrel[LF_UNLOC].get("DATAICCIAA"); cf.set(cod); } } else { @@ -394,36 +867,61 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { if (code.left(6) == "_TOTAL") { // totalizzatori di testata/coda, riga e progressione - // sintassi: _TOTAL_{CODA|RIGA|PROGRES},[,] + // sintassi: _TOTAL_{CODA|RIGA|PROGRES},[,] // dove: è il codice del totalizzatore richiesto - // è il campo della form che riceve il valore del totalizzatore, se non è specificato è scritto nel campo corrente static real zero("0.0"); // 0 sotto forma di real per i casi in cui il totalizzatore non viene trovato + if (!_doc->summary_compiled() &&_cli_loaded) _doc->set_condv(_cliente); TString tot= s.get(); // prende il codice del totalizzatore richiesto TForm_item *fi; // puntatore al campo della form in cui scrivere il valore del totalizzatore - if (s.items()==2) { - TString c= s.get(); // prende il codice del campo della form - if (c[0]== '#') c.ltrim(1); - fi= &(cf.find_field(c)); // prende il puntatore al campo specificato - } else fi= &cf; // prende il puntatore al campo corrente + fi= &cf; // prende il puntatore al campo corrente if (code.mid(6) == "_CODA") { - TLocalisamfile &doc= (cursor())->file(LF_DOC); - TToken_string totcoda(doc.get("G1")); // prende il campo memo con i totalizzatori sotto forma di token string - int pos= totcoda.get_pos(tot); // cerca il totalizzatore richiesto, il suo valore è nel token successivo - if (pos>=0) fi->set(totcoda.get(pos+1)); // setta il campo della form - else fi->set(zero.string()); + TString value; + if (tot == "TOTDOC") value = _doc->tot_documento().string(); + else if (tot == "TIMPNETTI") value = _doc->tot_importi_netti().string(); + else if (tot == "TIMPOSTE") value = _doc->tot_imposte().string(); + else if (tot == "TIMPONIBILI") + { + byte sel = atoi(s.get()); + value = _doc->tot_imponibili(sel).string(); + } + else + value = _doc->get_head_info(tot); + if (value.not_empty()) + fi->set(value); // setta il campo della form + else + fi->set(zero.string()); } if (code.mid(6) == "_RIGA") { TLocalisamfile &rdoc= (cursor())->file(LF_RIGHEDOC); - TToken_string totriga(rdoc.get("G1")); // prende il campo memo con i totalizzatori sotto forma di token string - int pos= totriga.get_pos(tot); // cerca il totalizzatore richiesto, il suo valore è nel token successivo - if (pos>=0) fi->set(totriga.get(pos+1)); // setta il campo della form - else fi->set(zero.string()); + TToken_string totriga(rdoc.get("G1"),'\n'); // prende il campo memo con i totalizzatori sotto forma di token string + TString value; + const int items = totriga.items(); + for (int i = 0; i vale 0 o 1 se indica di rendere corrente la prossima scadenza + if (s.items() == 3) + { + TString what(s.get()); + TString value(_doc->scadenze_get(what)); + cf.set(value); + + real x(value); + if (x.is_real(value)) + { + TString picture(cf.picture()); + if (x != 0.0) + value = x.string(picture); // Riformatta il valore + else + value = ""; + } + + what = s.get(); + const bool next = what == "1"; + if (next) _doc->scadenze_set_next(); + cf.put_paragraph(value); + cf.set(""); // Resetta il campo per la prossima stampa di questo item + } + } if (code== "_RIEPILOGOIVA") { // tabella riepilogo aliquote iva e relative imposte - // sintassi: _RIEPILOGOIVA, + // sintassi: _RIEPILOGOIVA,,, + // dove: è uno dei seguenti: + // 1 = codici IVA a regime normale + // 2 = codici IVA da ventilare + // 4 = codici IVA esenti + // 8 = codici IVA non imponibili + // 16 = codici IVA non soggetti + // oppure la combinazione di uno o piu' di essi: + // 12 = 4+8, 19 = 1+2+16, 29 = 1+4+8+16 ecc... // dove: è uno dei seguenti: - // !IMPONIB colonna degli imponibili - // !ALIQ colonna delle aliquote - // !IMPOSTE colonna delle imposte - // !DESCR colonna delle descrizioni - TString in= s.get(); // prende l'indicatore della colonna da creare - TLocalisamfile &doc= (cursor())->file(LF_DOC); - TToken_string totaliz(doc.get("G1")); // prende il campo memo con i totalizzatori sotto forma di token string - if (in[0]=='!') { - in.ltrim(1); - int w= cf.width(), num= totaliz.items(); - TString out, curr, tot; - for (int i=0; i è uno dei seguenti: + // 0 indica di non leggere il successivo codice IVA nella tabella riepilogativa + // 1 indica di leggere il successivo codice IVA nella tabella riepilogativa + + if (!_doc->summary_compiled() &&_cli_loaded) _doc->set_condv(_cliente); + + if (s.items() == 4) + { + byte selector = byte(atoi(s.get())); // il primo parametro e' il selettore del tipo di codice + if (selector != 0) + { + _doc->summary_filter(selector); + + TString what(s.get()); // cosa deve stampare ? + TString value(_doc->summary_get(what)); // Piglia il valore dalla riga selezionata sullatabellina + + what = s.get(); + const bool next = what == "1"; // deve cambiare elemento ? + if (next) _doc->summary_set_next(); + cf.set(value); + + real x(value); + if (x.is_real(value)) + { + TString picture(cf.picture()); + if (x != 0.0) + value = x.string(picture); // Riformatta il valore + else + value = ""; } - if (in=="IMPOSTE") { - if (tot.match("IVAV_????")) curr.right_just(w); - } - if ((in=="ALIQ") || (in=="DESCR")) { - if (tot.match("IVAI_????")) { - TString code= tot.mid(5); // prende il codice dell'aliquota per la tabella iva - TTable iva("%IVA"); // inizializza la tabella, imposta il codice e tenta una lettura - iva.put("CODTAB", code); - if (iva.read()==NOERR) { - if (in=="ALIQ") { - curr= iva.get("R0"); // legge l'aliquota - curr.right_just(w); - } - if (in=="DESCR") { - if (iva.get("S1").not_empty()) { // il tipo di aliquota è diverso da "regime iva normale" ? - curr= iva.get("S0"); // legge la descrizione - curr.left_just(w); - } - } - } else curr.spaces(w); - } - } - if (out.not_empty()) out << "|"; // aggiunge il separatore di riga per le paragraph string preformattate - out << curr; // aggiunge la riga corrente alla colonna + cf.put_paragraph(value); + cf.set(""); // Resetta il campo per la prossima stampa di questo item } - cf.set(out); // scrive la colonna nel campo corrente - cf.put_paragraph(out); - cf.set(""); // Resetta il campo per la prossima stampa di questo item } + else + error_box("Numero di parametri non corretto in _RIEPILOGOIVA"); return (TRUE); } // fine _RIEPILOGOIVA @@ -577,163 +1108,6 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { return TForm::validate(cf, s); // se il codice del messaggio non è identificato viene passato alla funzione standard } - -////////////////////////////////////////////////////////////////////////////////////////////// -// classe TRighe_Doc_Vendita: contenitore per righe documenti di vendita, al fine dei calcoli -// per stampare i riepiloghi IVA in fondo alle fatture -////////////////////////////////////////////////////////////////////////////////////////////// - -struct Riepilogo_Iva : public TObject -{ - real _imp; - real _iva; - real _ali; - TString _des; - virtual TObject* dup() const { return new Riepilogo_Iva(*this); } - Riepilogo_Iva() {_imp = 0.0; _iva = 0.0; _ali = 0.0; } -}; - -class TDoc_vendita : public TObject -{ - TRectype* _header; // Record di testata - TArray _rows; // Array di TRectype per le righe documenti di vendita. - TAssoc_array _summary_table; // Array dove vengono memorizzate le imposte per aliquota - num_of_decimals_to_round* _parm; // Parametri per gli arrotondamenti - TRelation* _rel; // Relazione Testata->Righe - TCliFor* _cli; // Oggetto cliente fornitore per elaborare gli sconti - TTable* _iva; // Tabella codici IVA - TCond_vendita* _condv; // Condizioni di vendita per lo sconto - bool _is_valuta; // flag per saper se il documento e' in valuta - - protected: - - void update_summary(const TRectype& riga); // Aggiorna la tabella riepilogativa - - public: - - int rows() { return _rows.items() - 1 ; } // Meno 1 perche' il primo e' la testata del documento - bool is_valuta() { return _is_valuta; } - const TRectype& header() const { return *_header ; } // Ritorna la testata del documento - const TRectype& operator[] (int index) const { return (const TRectype&)_rows[index];} // Ritorna la riga n-esima del documento - void add(const TRectype& riga, bool force = FALSE); // Aggiunge la riga in memoria e aggiorna la tabella riepilogativa per aliquota. force serve a forzare la lettura dal record passato - void replace(const TRectype& riga, int n) {_rows.add(riga,n);} // sostituisce la riga n-esima - void remove(int n) { _rows.remove(n); } // cancella la riga n-esima - void insert(const TRectype& riga, int n) { _rows.insert(riga,n); } // inserisce la riga n-esima - //const Riepilogo_Iva& get(int index) {return (const Riepilogo_Iva&)_summary_table[index];} // Ritorna l'elemento - void set_decimals(num_of_decimals_to_round* parm) { _parm = parm ; } - void set_relation(TRelation* rel) { _rel = rel ; } - void set_clifor(TCliFor* cli); - void set_header(const TRectype& h) { *_header = h; } - void destroy() { _rows.destroy(); _summary_table.destroy(); } // Azzera il contenuto - TDoc_vendita (num_of_decimals_to_round* parm = NULL, TRelation* rel = NULL, TCliFor* cli = NULL) ; - ~TDoc_vendita(); -}; - -void TDoc_vendita::update_summary(const TRectype& riga) -{ - TRectype r(_rel == NULL ? riga : _rel->lfile(LF_RIGHEDOC).curr()); - if (r.num() == LF_RIGHEDOC) - { - int nriga = r.get_int("NRIGA"); - real price = r.get_real("PREZZO"); - real qta = r.get_real("QTA"); - real aliquota, sc, imponibile, iva; - TString sconto(r.get("SCONTO")); - TString codiva(r.get("CODIVA")); - _iva->put("CODTAB", codiva); - if (_iva->read() != NOERR) - { - warning_box("Codice iva %s non trovato relativamente alla riga %d.", (const char*) codiva, nriga); - return ; - } - - aliquota = _iva->get_real("R0"); - _condv->set_sconto(sconto); - sc = 100.0 - _condv->sconto_val(); - price = ((price * sc) / 100.0); - price.round(_is_valuta ? _parm->pri_val : _parm->pri_lit); // prezzo scontato - qta.round(_parm->qta); - imponibile = price * qta; - imponibile.round (_is_valuta ? _parm->imp_val : _parm->imp_lit); // imponibile di riga - iva = (imponibile * aliquota) / 100.0; - iva.ceil(_is_valuta ? _parm->imp_val : _parm->imp_lit); // imposta calcolata - - Riepilogo_Iva riepilogo; - const bool exists = _summary_table.is_key(codiva); - Riepilogo_Iva& riepilogo_tmp = (exists ? (Riepilogo_Iva&)_summary_table[codiva] : riepilogo); - riepilogo_tmp._imp += imponibile; riepilogo_tmp._iva += iva; - riepilogo_tmp._ali = aliquota; - if (_iva->get("S1").not_empty()) // Se non e' regime normale salva anche la descrizione - riepilogo_tmp._des = _iva->get("S0"); - _summary_table.add(codiva,riepilogo_tmp,exists); - } -} - -void TDoc_vendita::add(const TRectype& riga, bool force) // force forza la memorizzazione della riga passata -{ - - // Memorizza i record se la relazione non e' valida (righe e testata vengono passati dall'esterno) - if (force || _rel == NULL) - { - const bool is_doc = riga.num() == LF_DOC; // Flag per vedere se il record passato e' di testata - if (is_doc) - { - *_header = riga; - TString valuta(riga.get("CODVAL")); - _is_valuta = valuta.trim().not_empty(); - } - else - { - if (_rows.items() == 0) // Se l'array e' vuoto ed il record passato e' una riga - { // memorizza prima una testata vuota - TRectype r(LF_DOC); - *_header = r; - } - _rows.add(riga); - } - } - else // Memorizza i record se la relazione e' valida (si accorge da solo se la testata e' gia' presente) - { - const bool store_header = _rows.items() == 0; - TRectype r(_rel->lfile(store_header ? LF_DOC : LF_RIGHEDOC).curr()); - if (store_header) // Se non c'e' la testata la memorizza e poi aggiunge la riga - { - *_header = r; - r = _rel->lfile(LF_RIGHEDOC).curr(); - } - _rows.add(r); - } - - if (_parm != NULL && _cli != NULL) // Se sono stati impostati i parametri necessari alla compilazione del riepilgo - update_summary(riga); // effettua i calcoli -} - -void TDoc_vendita::set_clifor(TCliFor* cli) -{ - _cli = cli ; - if (_condv != NULL) - delete _condv; - _condv = new TCond_vendita(*_cli); -} - -TDoc_vendita::TDoc_vendita(num_of_decimals_to_round* parm, TRelation* rel, TCliFor* cli) -{ - _parm = parm; _rel = rel; _cli = cli; - _condv = NULL; - _is_valuta = FALSE; - destroy(); - _header = new TRectype(LF_DOC); - _iva = new TTable("%IVA"); - if (_cli != NULL) _condv = new TCond_vendita(*_cli); -} - -TDoc_vendita::~TDoc_vendita() -{ - if (_header != NULL) delete _header; - if (_iva != NULL) delete _iva; - if (_condv != NULL) delete _condv; -} - ////////////////////////////////////////////////////////////////////////////////////////////// // classe TStampa_Doc_Vendita customizzata dalla TApplication per l'applicazione principale ////////////////////////////////////////////////////////////////////////////////////////////// @@ -756,6 +1130,7 @@ class TStampa_Doc_Vendita: public TApplication { bool _interattivo; // flag che indica se il prog. funziona in interattivo o in batch bool _definitiva; // flag che indica se la stampa è definitiva o no TRelation *_firmrel; // puntatore alla relazione che gestisce i dati della ditta corrente + TDocVen_Form *_form; // puntatore al form di stampa protected: virtual bool create(void); virtual bool destroy(void); @@ -767,8 +1142,10 @@ protected: virtual bool query_final_print(void); // funzione chiamata all'inizializzazione per sapere se la stampa è definitiva static bool date2num_handler(TMask_field& f, KEY key); static bool range_handler(TMask_field& f, KEY key); + static bool filter_rows(const TRelation * r); }; +inline TStampa_Doc_Vendita& app() { return (TStampa_Doc_Vendita&) main_app(); } bool TStampa_Doc_Vendita::date2num_handler(TMask_field& f, KEY key) { @@ -821,10 +1198,35 @@ bool TStampa_Doc_Vendita::range_handler(TMask_field& f, KEY key) return rt; } +bool TStampa_Doc_Vendita::filter_rows(const TRelation * r) +{ + TLocalisamfile& righe = r->lfile(LF_RIGHEDOC); + bool rt = TRUE; + TString tiporiga(righe.get("TIPORIGA")); + TString codart(righe.get("CODART")); + TString_array& a = app()._form->exclude_list(); + const int items = a.items(); + + for (int i = 0; i < items && rt; i++) + { + TToken_string& s=a.row(i); + TString tr(s.get(0)); + TString ar(s.get(1)); + tr.trim();ar.trim(); + if (tr.empty() && ar == codart) rt = FALSE; + else if (tr == tiporiga) + if (ar.empty() || (ar.not_empty() && ar == codart)) rt = FALSE; + } + + return rt; +} + bool TStampa_Doc_Vendita::create() { TApplication::create(); + _form = NULL; _firmrel= new TRelation(LF_NDITTE); // istanziamento e impostazione della relazione di gestione della ditta corrente _firmrel->add(LF_ANAG, "TIPOA=TIPOA|CODANAGR=CODANAGR"); + _firmrel->add(LF_UNLOC,"CODDITTA=CODDITTA"); // si posiziona sulla prima unita' locale della ditta _firmrel->add(LF_COMUNI, "COM=STATORES+COMRES", 1, LF_ANAG, 100+LF_COMUNI); _firmrel->add(LF_COMUNI, "COM=STATORES+COMRF", 1, LF_ANAG, 200+LF_COMUNI); if (argc()>2) { // lettura dei parametri iniziali dalla linea di comando @@ -844,6 +1246,7 @@ bool TStampa_Doc_Vendita::create() { } bool TStampa_Doc_Vendita::destroy() { + if (_form) delete _form; delete _firmrel; // distruzione della relazione di gestione della ditta corrente return TApplication::destroy(); } @@ -936,13 +1339,16 @@ void TStampa_Doc_Vendita::print() { break; // ...e la stampa viene interrotta } behaviour whattodo= go; // istanzia la variabile di comportamento - TDocVen_Form f(nomeform, *_firmrel); // istanzia il form - const TString &modulo= f.get_module_code(); // legge dal form il codice del modulo di carta per la stampa + + TDocumentoEsteso * doc_est = new TDocumentoEsteso(cur.curr()); // istanzia TDocumentoEsteso sulla testata attuale + + _form = new TDocVen_Form(nomeform, *_firmrel, doc_est); // istanzia il form, passandogli il documento. (la delete del documento e' nel ditruttore + const TString &modulo= _form->get_module_code(); // legge dal form il codice del modulo di carta per la stampa if (modulo_prec.empty()) modulo_prec= modulo; // se siamo al primo passaggio la variabile di modulo precedente viene riempita if (modulo != modulo_prec) whattodo= on_module_change(modulo, modulo_prec); // se il modulo è cambiato dalla stampa precedente interroga la funzione per sapere che comportamento tenere - if (whattodo==cancel) break; // se non si può procedere la stampa viene interrotta + if (whattodo==cancel) break; // se non si può procedere la stampa viene interrotta else if (whattodo==go) { // altrimenti prosegue - TCursor &fcur= *(f.cursor()); // ricava il riferimento al cursore originale del form + TCursor &fcur= *(_form->cursor()); // ricava il riferimento al cursore originale del form TLocalisamfile &rdoc= fcur.file(LF_RIGHEDOC); // ricava il riferimento al file principale del cursore del form TRectype darec_r(rdoc.curr()); // istanzia il record di filtro per il cursore darec_r.zero(); // vuota il record @@ -952,17 +1358,28 @@ void TStampa_Doc_Vendita::print() { darec_r.put("NDOC", doc.get("NDOC")); TRectype arec_r(darec_r); // istanzia il secondo record per il filtro sul cursore fcur.setregion(darec_r, arec_r); // setta il filtro sul cursore del form - f.print(); // stampa il form corrente + fcur.set_filterfunction(filter_rows); // setta il filtro per escludere alcuni tipi riga indicati nel form + _form->print(); // stampa il form corrente if (_definitiva && (numerazione_definitiva(doc) != NOERR)) { // se la stampa è definitiva viene lanciata la procedura di rinumerazione if (_interattivo) error_box("Non è possibile completare la procedura di numerazione definitiva dei documenti"); break; } } + if (_form) + { + delete _form; + _form = NULL; + } } else { error_box("Il documento corrente non è stato trovato nella tabella dei tipi di documento (errore %d)", err); break; } } + if (_form) + { + delete _form; + _form = NULL; + } printer().close(); // chiude la stampante } @@ -1001,3 +1418,4 @@ int ve1100(int argc, char* argv[]) { a.run(argc, argv, "Stampa documenti di vendita"); return (0); } +