From 2b2a1c95674fc361cd720dfb9b1973f2beff7baf Mon Sep 17 00:00:00 2001 From: angelo Date: Mon, 5 Aug 1996 13:45:27 +0000 Subject: [PATCH] Stampa bolle e fatture. git-svn-id: svn://10.65.10.50/trunk@3329 c028cbd2-c16b-5b4b-a496-9718f37d4682 --- ve/ve1100.cpp | 317 +++++++++++++++++++++++++++++++++++++++++++++++-- ve/ve1100a.uml | 9 +- 2 files changed, 315 insertions(+), 11 deletions(-) diff --git a/ve/ve1100.cpp b/ve/ve1100.cpp index 8479c85d7..df48f1d1d 100755 --- a/ve/ve1100.cpp +++ b/ve/ve1100.cpp @@ -13,6 +13,7 @@ #include #include "righedoc.h" +#include "sconti.h" #include "tclifor.h" #include "ve1100.h" @@ -25,7 +26,14 @@ // !! __VE1100_DOWNSIZE, altrimenti in righedoc.cpp si creano degli // !! unresolved reference in fase di link - + +struct num_of_decimals_to_round { + int pri_lit, + pri_val, + qta, + imp_lit, + imp_val; +}; //////////////////////////////////////////////////////////////////////////// // classe TDocVen_Form customizzata dalla Form per i documenti di vendita @@ -38,6 +46,7 @@ class TDocVen_Form: public TForm { TRiga *_riga; // oggetto per la gestione della singola riga del documento TCliFor *_cliente; // oggetto per le informazioni sul cliente bool _cli_loaded; // flag che indica se l'oggetto cliente è già stato caricato + num_of_decimals_to_round par_dec; // struct che contiene il numero di decimali che servono per l'arrotondamento 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 @@ -66,21 +75,42 @@ TDocVen_Form::~TDocVen_Form() { 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 + + // 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(); + + // Stessa cosa per le quantita' + if (scanner.popkey() == "QT") + par_dec.qta = scanner.integer(); + else scanner.push(); + + // 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(); + } bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { const TString code(s.get(0)); // prende il primo parametro, il codice del messaggio + TString valore; if (code== "_ISAMREAD") { // lettura generica di un file del database @@ -128,6 +158,8 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { if (poseq== -1) { const TString &dat= file->get(curr); // preleva il nome del campo del file e lo legge dal record cf.set(dat); // setta il campo letto dal file nel campo corrente della form + cf.put_paragraph(dat); + cf.set(""); // Resetta il campo per la prossima stampa di questo item } else { TString fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale const TString &dat= file->get(curr.mid(posrv)); // preleva il nome del campo del file alla destra dell'uguale e lo legge dal record @@ -147,11 +179,13 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { TForm_item &fi= section(sec, pt).field(j); fi.set(dat); // ...il contenuto viene settato al valore del file fi.put_paragraph(dat); + fi.set(""); // Resetta il campo per la prossima stampa di questo item } } else { TForm_item &fi= cf.find_field(fld); fi.set(dat); fi.put_paragraph(dat); + fi.set(""); // Resetta il campo per la prossima stampa di questo item } } } @@ -177,11 +211,35 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { tab.put("CODTAB", in); // setta la chiave nella tabella if (tab.read()== NOERR) { const TString &fld= s.get(); // prende il nome del campo da leggere... + valore = tab.get(fld); cf.set(tab.get(fld)); // ...e lo scrive nel campo del form + cf.put_paragraph(valore); + cf.set(""); // Resetta il campo per la prossima stampa di questo item } return (TRUE); } // fine _TABLEREAD - + if (code == "_DESCRIGA") { + // Messaggio per reperire la descrizione estesa sulle righe del documento + TLocalisamfile &rdoc= (cursor())->file(LF_RIGHEDOC); + TString descrizione = rdoc.get("DESCR"); + const bool desclunga = rdoc.get_bool("DESCLUNGA"); + if (desclunga) { + TTextfile t; + rdoc.get_memo("DESCEST",t); + const long l = t.lines(); + for (long i = 0; i[,][,...] @@ -195,8 +253,19 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { TString in(s.get()); if (in[0]== '#') in.ltrim(1); TForm_item &fi= cf.find_field(in); + const int width = cf.width(); + valore = cf.get(); + TString clear(width); + TString picture(cf.picture()); + clear.spaces(); int i= 2; - while (iset(_total_prog->get(tot16).string()); } + valore = fi->get(); + fi->put_paragraph(valore); + fi->set(""); // Resetta il campo per la prossima stampa di questo item return (TRUE); } // fine _TOTAL_xxx @@ -332,6 +437,7 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { // !RAGSOC ragione sociale // !IND indirizzo // !NUM numero civico + // !INDNUM indirizzo + numero civico // !LOC località // !CAP CAP // !COM comune @@ -364,6 +470,11 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { if (in=="RAGSOC") cf.set(_cliente->get(LF_CLIFO, "RAGSOC")); if (in=="IND") cf.set(_cliente->get(LF_CLIFO, "INDCF")); if (in=="NUM") cf.set(_cliente->get(LF_CLIFO, "CIVCF")); + if (in=="INDNUM") { + TString indnum(_cliente->get(LF_CLIFO, "INDCF")); + indnum << " " << _cliente->get(LF_CLIFO,"CIVCF"); + cf.set(indnum); + } if (in=="LOC") cf.set(_cliente->get(LF_CLIFO, "LOCALITACF")); if (in=="CAP") cf.set(_cliente->get(LF_CLIFO, "CAPCF")); if (in=="COM") cf.set(_cliente->get(-(100+LF_COMUNI), "DENCOM")); @@ -397,6 +508,9 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { TFieldref fref(s.get(), 0); cf.set(fref.read(*_cliente)); // l'oggetto cliente è figlio della TRelation, quindi lo passo al fieldref semplicemente con un typecast } + valore = cf.get(); + cf.put_paragraph(valore); + cf.set(""); // Resetta il campo per la prossima stampa di questo item return (TRUE); } // fine _CLIENTE @@ -448,14 +562,177 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) { out << curr; // aggiunge la riga corrente alla colonna } 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 } return (TRUE); } // fine _RIEPILOGOIVA + // Messaggio per stampare il numero di pagina corrente + if (code== "_PAGENO") { + TString16 pg; pg << int(printer().getcurrentpage()); + cf.set(pg); cf.put_paragraph(pg); + cf.set(""); + } 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 @@ -489,6 +766,7 @@ protected: virtual behaviour on_module_change(const TString &, TString &); // funzione chiamata ad ogni cambio modulo durante la stampa 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); }; @@ -526,6 +804,23 @@ bool TStampa_Doc_Vendita::date2num_handler(TMask_field& f, KEY key) return TRUE; } +bool TStampa_Doc_Vendita::range_handler(TMask_field& f, KEY key) +{ + int rt = TRUE; + TMask& m = f.mask(); + if (key == K_TAB && f.focusdirty()) + { + const long lim_sup = atol(f.get()); + const long lim_inf = m.get_long(F_DA_NDOC); + if (lim_sup < lim_inf) + { + f.error_box("Il limite superiore deve essere maggiore del limite inferiore"); + rt = FALSE; + } + } + return rt; +} + bool TStampa_Doc_Vendita::create() { TApplication::create(); _firmrel= new TRelation(LF_NDITTE); // istanziamento e impostazione della relazione di gestione della ditta corrente @@ -564,6 +859,7 @@ int TStampa_Doc_Vendita::select() { TString wdate; m.set_handler(F_DA_DATADOC, date2num_handler); m.set_handler(F_A_DATADOC, date2num_handler); + m.set_handler(F_A_NDOC, range_handler); if (m.run() == K_ENTER) { _codnum= m.get(F_CODNUM); // lettura dei dati dalla maschera _anno= m.get_int(F_ANNO); @@ -589,8 +885,6 @@ bool TStampa_Doc_Vendita::menu(MENU_TAG) { // procedura di dispatch dei menu } void TStampa_Doc_Vendita::print() { - _definitiva= query_final_print(); // legge il flag di stampa definitiva - printer().open(); // apre la stampante TFilename nomeform, profilo; // istanzia le stringhe per il nome del form di stampa e del profilo di configurazione TString modulo_prec; // istanzia la stringa per l'inseguimento del modulo di carta TTable tip("%TIP"); // istanzia la tabella dei tipi di documento per i profili @@ -613,6 +907,15 @@ void TStampa_Doc_Vendita::print() { doc.put("NDOC", _alnum); if (!_order_by_num) doc.put("DATADOC", _adata); doc.read(); // posiziona il file sul record + const long num_lim_sup = doc.get_int("NDOC"); + const TDate date_lim_sup = doc.get_date("DATADOC"); + if (num_lim_sup > _alnum || (!_order_by_num && date_lim_sup < _adata)) + { + error_box("Non vi sono documenti da stampare nell'intervallo indicato"); + return; + } + _definitiva= query_final_print(); // legge il flag di stampa definitiva + printer().open(); // apre la stampante TRectype arec= doc.curr(); // copia il record di fine cursore cur.setregion(darec, arec); // imposta il filtro sul cursore di stampa (nell'ordine giusto :-) for (cur= 0; cur.pos()