diff --git a/ve/velib.h b/ve/velib.h index 8546ec197..688876606 100755 --- a/ve/velib.h +++ b/ve/velib.h @@ -673,7 +673,7 @@ public: virtual ~TConsegna_ordini() { } }; -class TFatturazione_bolle : public TElaborazione // velib04 +class TFatturazione_bolle : public TElaborazione // velib04a { TToken_string _cod_desc; @@ -690,15 +690,130 @@ public: virtual ~TFatturazione_bolle() { } }; -class TContabilizzazione : public TElaborazione // velib04 +// Tipi di errore validi solo per TContabilizzazione e TGenerazione_effetti + +enum error_type { + no_error, + nr_es_error, + nr_reg_error, + nr_doc_error, + chg_stat_error, + clifo_error, + ultprot_error, + datadoc_error, + caus_error, + register_error, + change_error, + val_error, + codpag_error, + row_type_error, + no_rows_error, + conto_error, + movement_error, + write_error, + scadenze_error, + generic_error +}; + +class TBill; + +class TContabilizzazione : public TElaborazione // velib04b { + bool _auto_data; // Flag per data di registrazione automatica + byte _nump_iva; // se 1 prende il numero protocollo da registro iva, se 2 prende il numero protocollo dal numero doc. + TDate _data_reg; // Data di registrazione documenti + long _total_docs;// Numero di documenti contabilizzati + error_type _error; // Errore rilevato durante l'elaborazione + bool _can_write; // se TRUE e' abilitata la scrittura. Non appena rileva un errore rimane a FALSE for this instance + TString16 _spin_cod, // codice iva spese d'incasso + _spbo_cod; // codice iva spese bolli + TAssoc_array _righe_iva; // array per la memorizzazione delle righe iva raggruppate in codesto modo: + // CODICE_IVA+TIPOCF+GRUPPO+CONTO+SOTTOCONTO + // una volta completo, tale array viene scorso per comporre le righe IVA + // del movimento + + // Files, tabelle, oggetti contabili ed altre amenita'... + TLocalisamfile *_anamag, // file delle anagrafiche di magazzino + *_fcaus, + *_frcaus, + *_attiv, + *_part, + *_scad, + *_pags, + *_occas, + *_docfile, + *_rdocfile; + + TTable *_cpg, // tabella condizioni di pagamento + *_gmc, // tabella gruppi/sottogruppi merceologici + *_rfa, // tabella raggruppamenti fiscali + *_cve, // tabella categorie di vendita + *_val, // tabella valute estere + *_tri, // tabella tipi di riga + *_prs, // tabella prestazioni + *_spp, // tabella spese + *_caa, // tabella categorie acquisto articoli + *_cra, // tabella categorie ricavo articoli + *_cco; // tabella categorie contabili + TRelation *_clifo; // relazione dei clienti e fornitori + cfven + + // Parametri da leggere all'inizio dell'elaborazione tramite load_parameters() + bool _nump_cfg; // se TRUE prende il numero rif. partita dal numero protocollo + bool _sc_enabled;// se TRUE il saldaconto di ditta e' abilitato + TToken_string _search_seq; // Sequenza di ricerca del conto costo/ricavo la correttezza dell'ordinamento + // va controllata nel programma di modifica parametri: + // "" = fine ordinamento + // CF = cliente fornitore + // CA = causale + // AR = articolo (costo/ricavo) + // GM = gruppo merceologico + // SM = sottogruppo merceologico + // RF = raggruppamento fiscale + // CV = categoria di vendita + // CC = categoria contabile + // Gli utlimi 6 fanno parte della ricerca per costi ricavi, in particolare AR,GM,SM e RF + // non possono essere interrotti da CV o CC. Ad es. CA|CF|AR|CV|GM|CC|RF non e' valida come stringa + // di ricerca. +protected: + // Carica i parametri dalla configurazione + bool load_parameters(); + // Compila la testata del movimento + error_type compile_head_mov(TDocumento&); + // Funzione per ricercare il conto di costo/ricavo + error_type search_costo_ricavo(TBill&, const TRiga_documento&); + // Funzione per aggiungere la riga iva al TAssoc_array _righe_iva + error_type add_iva_row(const TBill&, const TRiga_documento&); + // Funzione atomica per aggiungere le righe di spese d'incasso e bolli al TAssoc_array _righe_iva + void calculate_spese(real&, real&, int, bool, bool); + // Funzione per aggiungere le righe di spese d'incasso e bolli al TAssoc_array _righe_iva (chiama calculate_spese()) + error_type add_spese_inbo(TDocumento&); + // Crea le righe iva sul movimento + error_type create_iva_rows(TDocumento&); + // Crea la riga di totale documento + error_type create_total_doc_row(); + // Compila le righe del movimento + error_type compile_rows_mov(TDocumento&); + // scrive le scadenze + error_type write_scadenze(TDocumento&); + // scrive il movimento e le scadenze + error_type write_all(TDocumento&); + // Cambia lo stato del documento + error_type change_doc_status(TDocumento&); + // Visualizza l'ultimo errore rilevato + void display_error(TDocumento&); + // Verifica se non ci sono stati errori + bool good() const { return _error == no_error;} + // Ritorna TRUE se il saldaconto e' abilitato (verifica anche la causale del documento corrente) + bool sc_enabled() const ; public: virtual bool elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab); - + void set_auto(const bool a) { _auto_data = a; } + void set_nump(const byte n) { _nump_iva = n; } + const long docs() { return _total_docs; } TContabilizzazione(const char* cod); - TContabilizzazione(const TRectype& rec) : TElaborazione(rec) { } - virtual ~TContabilizzazione() { } + TContabilizzazione(const TRectype& rec); + virtual ~TContabilizzazione(); }; class TCopia_documento : public TElaborazione // velib04 @@ -713,15 +828,56 @@ public: }; -class TGenerazione_effetti : public TElaborazione // velib04 +class TGenerazione_effetti : public TElaborazione // velib04c { + error_type _error; // Errore rilevato durante l'elaborazione + long _total_bills; // Totale effetti generati + bool _can_write; // se TRUE e' abilitata la scrittura. Non appena rileva un errore rimane a FALSE for this instance + TBit_array _valid_array; // array dei tipi di pagamento validi per la generazione di effetti + + TLocalisamfile *_efffile, // file effetti + *_refffile, // file righe di effetti + *_cessfile, + *_docfile, + *_rdocfile, + *_clifo, + *_cfven, + *_tab, + *_occas; + TTable *_cpg; // tabella condizioni di pagamento + TArray _effetti_array;//Array di effetti (TEffetto) da scrivere + TAssoc_array _group_array; // Assoc_array dei documenti da raggruppare. La chiave di ogni elemento + // e composta dagli stessi criteri di raggruppamento (vedi sotto) + // Ogni elemento e una TToken_string. Ogni elemento della TToken_string contiene + // la chiave per identificare il documento che fa parte di quel raggruppamento +protected: + // Visualizza l'ultimo errore rilevato + void display_error(TDocumento& doc); + // Restituisce TRUE se il tipo di pagamento passato e' valido per generare l'effetto + bool valid_type(int) const ; + // Genera l'effetto + void generate_bill(TDocumento&); + // Effettua il raggruppamento vero e proprio degli effetti (solo se ci sono elementi nell'assoc_array + void group_bills(TDocumento&); + // Istanzia il pagamento corrente + void calc_pagamento(TDocumento&, TString16&, TString16&); + // Scrive i record array degli effetti raggruppati + error_type write_groups(); + // Cambia lo stato dei gruppi di documenti raggruppati in effetti + error_type change_group_status(TDocumento&); + // Cambia lo stato del documento + error_type change_doc_status(TDocumento&); + // Verifica se non ci sono stati errori + bool good() const { return _error == no_error;} public: virtual bool elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab); - + + const long bills() { return _total_bills; } + void set_group(TAssoc_array& a) { _group_array = a; } TGenerazione_effetti(const char* cod); - TGenerazione_effetti(const TRectype& rec) : TElaborazione(rec) { } - virtual ~TGenerazione_effetti() { } + TGenerazione_effetti(const TRectype& rec); + virtual ~TGenerazione_effetti(); }; class TLista_elaborazioni : public TObject // velib04 diff --git a/ve/velib04.cpp b/ve/velib04.cpp index a0c9067f8..85b522620 100755 --- a/ve/velib04.cpp +++ b/ve/velib04.cpp @@ -401,225 +401,6 @@ bool TConsegna_ordini::elabora(TLista_documenti& doc_in, TLista_documenti& doc_o return TRUE; } -/////////////////////////////////////////////////////////// -// TFatturazione bolle -/////////////////////////////////////////////////////////// - -TFatturazione_bolle::TFatturazione_bolle(const char* cod) - : TElaborazione(cod) -{ -} - -void TFatturazione_bolle::tipi_validi(TToken_string& tipi) const -{ - const TString& s2 = get("S2"); - tipi.cut(0); - TString16 t; - for (int i = 0; i < 5; i++) - { - t = s2.mid(i*4, 4); - t.trim(); - if (t.not_empty()) - tipi.add(t); - } - CHECK(!tipi.empty_items(), "Nessun tipo documento valido"); -} - -void TFatturazione_bolle::stati_validi(TToken_string& stati) const -{ - const TString& s7 = get("S7"); - stati.cut(0); - TString16 s; - for (int i = 0; i < 5; i++) - { - s = s7.mid(i*4, 1); - s.trim(); - if (s.not_empty()) - stati.add(s); - } - CHECK(!stati.empty_items(), "Nessuno stato documento valido"); -} - - -bool TFatturazione_bolle::raggruppa(TDocumento& doc_in, TDocumento& doc_out) -{ -#ifdef DBG - const TString tipi = get("S2"); - const TString& tipodoc = doc_in.tipo().codice(); - for (int i = 0; i < 5; i++) - { - if (tipodoc == tipi.mid(i*4, 4)) - break; - } - if (i >= 5) - { - NFCHECK("Tipo documento non valido: '%s'", (const char*)tipodoc); - return FALSE; - } -#endif - - const char stato_finale_in = get_char("S4"); - doc_in.stato(stato_finale_in); - - const TString& tipo_out = get("S8"); - doc_out.put("TIPODOC", tipo_out); - - const char stato_finale_out = get_char("S9"); - doc_out.stato(stato_finale_out); - - if (gestione_riferimenti()) - { - // Determina ed eventualmente crea la riga di riferimento - const int riga_rif = riferimenti_in_testa() ? 1 : doc_out.rows()+1; - if (riga_rif > doc_out.rows()) - { - TRiga_documento& rout = doc_out.new_row(); - rout.forza_sola_descrizione(); - } - - TRiga_documento& rout = doc_out[riga_rif]; - - // Costruisce la stringa di riferimento - TString riferimento(80); - riferimento = doc_in.tipo().riferimento(); - if (riferimento.empty()) - riferimento = doc_in.tipo().descrizione(); - riferimento << " n. " << doc_in.numero(); - riferimento << " del " << doc_in.data().string(); - - // Setta la descrizione se vuota - if (rout.get("DESCR").empty()) - rout.put("DESCR", riferimento); - else - { - // Altrimenti aggiungi il riferimento al memo - TString memo(1024); - memo = rout.get("DESCEST"); - if (memo.empty()) - rout.put("DESCLUNGA", "X"); - else - memo << '\n'; - memo << riferimento; - rout.put("DESCEST", memo); - } - } - - const bool ignora_desc = ignora_descrizioni(); - - TToken_string campi_riga(80); - const bool ragg_rig = raggruppa_righe(); - if (ragg_rig) - { - campi_riga = "CODART|UMQTA"; // Uguali sempre - // Uguali opzionalmente - if (riga_uguale(0)) campi_riga.add("CODMAG"); - if (riga_uguale(1)) campi_riga.add("CODIVA"); - if (riga_uguale(2)) campi_riga.add("PREZZO|SCONTO"); - } - - for (int r = 1; r <= doc_in.rows(); r++) - { - const TRiga_documento& rin = doc_in[r]; - const bool rindesc = rin.sola_descrizione(); // La riga di input e' descrittiva - if (ignora_desc && rindesc) - continue; - - bool elaborata = FALSE; - - // Raggruppo le righe se e' settato il falg di raggruppamento e - // se la riga non contiene solo una descrizione - if (ragg_rig && !rindesc) // Se devo raggruppare le righe ... - { - const int last = doc_out.rows(); - for (int o = 1; o <= last; o++) // ... cerca una riga compatibile - { - TRiga_documento& rout = doc_out[o]; - if (rout.sola_descrizione()) // Ignora le righe descrittive - continue; - if (rin.raggruppabile(rout, campi_riga)) // Se esiste una riga compatibile ... - { - rout += rin; // ... sommaci la quantita' ecc. - elaborata = TRUE; // Ricorda di averla gia' elaborata - break; - } - } - } - if (!elaborata) // Se la riga non e' stata gia' sommata ... - { - TRiga_documento& rout = doc_out.new_row(); // ... crea una riga nuova e ... - doc_out.copy_data(rout, rin); // ... copiaci tutti i campi della riga sorgente. - } - } - - return TRUE; -} - -bool TFatturazione_bolle::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, - const TDate& data_elab) -{ - bool ok = TRUE; - - TToken_string campi_doc(128); // Lista di campi che devono essere uguali - campi_doc = "TIPOCF|CODCF|CODVAL|CODLIN"; // Uguali sempre - - // Uguali opzionalmente - const char* cond[] = { "CAMBIO", "SCONTO", "TIPODOC", "CODNUM", - "CODPAG", "CODABIA|CODCABA", "CODLIST", "CODAG", - "CODSPMEZZO", "CODPORTO", "CAUSTRASP", "CODVETT1|CODVETT2|CODVETT3", - NULL }; - for (int u = 0; cond[u]; u++) - if (doc_uguale(u)) campi_doc.add(cond[u]); - - for (int id = 0; id < doc_in.items() && ok; id++) - { - TDocumento& campione = doc_in[id]; - const int tot = doc_out.items(); - int od = tot; - - if (campione.raggruppabile()) // Se il documento ha il flag di raggruppabilita' ... - { - for (od = 0; od < tot; od++) // ... cerca un documento compatibile. - { - if (campione.raggruppabile(doc_out[od], campi_doc)) - break; - } - } - if (od >= tot) // Se non ho trovato un documento compatibile ... - { // ... creane uno nuovo (certamente compatibile) - const char provv = tipo_numerazione(); - const int anno = campione.anno(); - const TString codnum = codice_numerazione_finale(); - TDocumento* new_doc = new TDocumento(provv, anno, codnum, -1); - // Copia i dati della testata - TDocumento::copy_data(new_doc->head(), campione.head()); - - new_doc->put("DATADOC", data_elab); - - // Aggiungilo alla lista dei documenti in uscita - od = doc_out.add(new_doc); - } - - ok = raggruppa(campione, doc_out[od]); - } - return ok; -} - -/////////////////////////////////////////////////////////// -// TContabilizzazione -/////////////////////////////////////////////////////////// - -TContabilizzazione::TContabilizzazione(const char* cod) - : TElaborazione(cod) -{ -} - -bool TContabilizzazione::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, - const TDate& data_elab) -{ - CHECK(doc_in.items() == 1, "Si deve specificare uno e un solo documento in entrata"); - CHECK(doc_out.items() == 1, "Si deve specificare uno e un solo documento in uscita"); - return TRUE; -} /////////////////////////////////////////////////////////// // TCopia_documento /////////////////////////////////////////////////////////// @@ -641,24 +422,6 @@ bool TCopia_documento::elabora(TLista_documenti& doc_in, TLista_documenti& doc_o return TRUE; } - -/////////////////////////////////////////////////////////// -// TGenerazione_effetti -/////////////////////////////////////////////////////////// - -TGenerazione_effetti::TGenerazione_effetti(const char* cod) - : TElaborazione(cod) -{ -} - -bool TGenerazione_effetti::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, - const TDate& data_elab) -{ - CHECK(doc_in.items() == 1, "Si deve specificare uno e un solo documento in entrata"); - CHECK(doc_out.items() == 1, "Si deve specificare uno e un solo documento in uscita"); - return TRUE; -} - /////////////////////////////////////////////////////////// // TLista_elaborazioni /////////////////////////////////////////////////////////// diff --git a/ve/velib04a.cpp b/ve/velib04a.cpp new file mode 100755 index 000000000..bb977b720 --- /dev/null +++ b/ve/velib04a.cpp @@ -0,0 +1,205 @@ +#include "velib.h" + +/////////////////////////////////////////////////////////// +// TFatturazione bolle +/////////////////////////////////////////////////////////// + +TFatturazione_bolle::TFatturazione_bolle(const char* cod) + : TElaborazione(cod) +{ +} + +void TFatturazione_bolle::tipi_validi(TToken_string& tipi) const +{ + const TString& s2 = get("S2"); + tipi.cut(0); + TString16 t; + for (int i = 0; i < 5; i++) + { + t = s2.mid(i*4, 4); + t.trim(); + if (t.not_empty()) + tipi.add(t); + } + CHECK(!tipi.empty_items(), "Nessun tipo documento valido"); +} + +void TFatturazione_bolle::stati_validi(TToken_string& stati) const +{ + const TString& s7 = get("S7"); + stati.cut(0); + TString16 s; + for (int i = 0; i < 5; i++) + { + s = s7.mid(i*4, 1); + s.trim(); + if (s.not_empty()) + stati.add(s); + } + CHECK(!stati.empty_items(), "Nessuno stato documento valido"); +} + + +bool TFatturazione_bolle::raggruppa(TDocumento& doc_in, TDocumento& doc_out) +{ +#ifdef DBG + const TString tipi = get("S2"); + const TString& tipodoc = doc_in.tipo().codice(); + for (int i = 0; i < 5; i++) + { + if (tipodoc == tipi.mid(i*4, 4)) + break; + } + if (i >= 5) + { + NFCHECK("Tipo documento non valido: '%s'", (const char*)tipodoc); + return FALSE; + } +#endif + + const char stato_finale_in = get_char("S4"); + doc_in.stato(stato_finale_in); + + const TString& tipo_out = get("S8"); + doc_out.put("TIPODOC", tipo_out); + + const char stato_finale_out = get_char("S9"); + doc_out.stato(stato_finale_out); + + if (gestione_riferimenti()) + { + // Determina ed eventualmente crea la riga di riferimento + const int riga_rif = riferimenti_in_testa() ? 1 : doc_out.rows()+1; + if (riga_rif > doc_out.rows()) + { + TRiga_documento& rout = doc_out.new_row(); + rout.forza_sola_descrizione(); + } + + TRiga_documento& rout = doc_out[riga_rif]; + + // Costruisce la stringa di riferimento + TString riferimento(80); + riferimento = doc_in.tipo().riferimento(); + if (riferimento.empty()) + riferimento = doc_in.tipo().descrizione(); + riferimento << " n. " << doc_in.numero(); + riferimento << " del " << doc_in.data().string(); + + // Setta la descrizione se vuota + if (rout.get("DESCR").empty()) + rout.put("DESCR", riferimento); + else + { + // Altrimenti aggiungi il riferimento al memo + TString memo(1024); + memo = rout.get("DESCEST"); + if (memo.empty()) + rout.put("DESCLUNGA", "X"); + else + memo << '\n'; + memo << riferimento; + rout.put("DESCEST", memo); + } + } + + const bool ignora_desc = ignora_descrizioni(); + + TToken_string campi_riga(80); + const bool ragg_rig = raggruppa_righe(); + if (ragg_rig) + { + campi_riga = "CODART|UMQTA"; // Uguali sempre + // Uguali opzionalmente + if (riga_uguale(0)) campi_riga.add("CODMAG"); + if (riga_uguale(1)) campi_riga.add("CODIVA"); + if (riga_uguale(2)) campi_riga.add("PREZZO|SCONTO"); + } + + for (int r = 1; r <= doc_in.rows(); r++) + { + const TRiga_documento& rin = doc_in[r]; + const bool rindesc = rin.sola_descrizione(); // La riga di input e' descrittiva + if (ignora_desc && rindesc) + continue; + + bool elaborata = FALSE; + + // Raggruppo le righe se e' settato il falg di raggruppamento e + // se la riga non contiene solo una descrizione + if (ragg_rig && !rindesc) // Se devo raggruppare le righe ... + { + const int last = doc_out.rows(); + for (int o = 1; o <= last; o++) // ... cerca una riga compatibile + { + TRiga_documento& rout = doc_out[o]; + if (rout.sola_descrizione()) // Ignora le righe descrittive + continue; + if (rin.raggruppabile(rout, campi_riga)) // Se esiste una riga compatibile ... + { + rout += rin; // ... sommaci la quantita' ecc. + elaborata = TRUE; // Ricorda di averla gia' elaborata + break; + } + } + } + if (!elaborata) // Se la riga non e' stata gia' sommata ... + { + TRiga_documento& rout = doc_out.new_row(); // ... crea una riga nuova e ... + doc_out.copy_data(rout, rin); // ... copiaci tutti i campi della riga sorgente. + } + } + + return TRUE; +} + +bool TFatturazione_bolle::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, + const TDate& data_elab) +{ + bool ok = TRUE; + + TToken_string campi_doc(128); // Lista di campi che devono essere uguali + campi_doc = "TIPOCF|CODCF|CODVAL|CODLIN"; // Uguali sempre + + // Uguali opzionalmente + const char* cond[] = { "CAMBIO", "SCONTO", "TIPODOC", "CODNUM", + "CODPAG", "CODABIA|CODCABA", "CODLIST", "CODAG", + "CODSPMEZZO", "CODPORTO", "CAUSTRASP", "CODVETT1|CODVETT2|CODVETT3", + NULL }; + for (int u = 0; cond[u]; u++) + if (doc_uguale(u)) campi_doc.add(cond[u]); + + for (int id = 0; id < doc_in.items() && ok; id++) + { + TDocumento& campione = doc_in[id]; + const int tot = doc_out.items(); + int od = tot; + + if (campione.raggruppabile()) // Se il documento ha il flag di raggruppabilita' ... + { + for (od = 0; od < tot; od++) // ... cerca un documento compatibile. + { + if (campione.raggruppabile(doc_out[od], campi_doc)) + break; + } + } + if (od >= tot) // Se non ho trovato un documento compatibile ... + { // ... creane uno nuovo (certamente compatibile) + const char provv = tipo_numerazione(); + const int anno = campione.anno(); + const TString codnum = codice_numerazione_finale(); + TDocumento* new_doc = new TDocumento(provv, anno, codnum, -1); + // Copia i dati della testata + TDocumento::copy_data(new_doc->head(), campione.head()); + + new_doc->put("DATADOC", data_elab); + + // Aggiungilo alla lista dei documenti in uscita + od = doc_out.add(new_doc); + } + + ok = raggruppa(campione, doc_out[od]); + } + return ok; +} + diff --git a/ve/velib04b.cpp b/ve/velib04b.cpp new file mode 100755 index 000000000..8a5e2a437 --- /dev/null +++ b/ve/velib04b.cpp @@ -0,0 +1,1475 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../mg/anamag.h" + + +#include "velib.h" +#include "../cg/cg2101.h" +#include "../cg/cg2103.h" +#include "../cg/cgsaldac.h" + +/////////////////////////////////////////////////////////// +// TContabilizzazione +/////////////////////////////////////////////////////////// + +// TMovimentoPN_VE +// Classe derivata da TMovimentoPN per calcolare automaticamente le righe contabili +// una volta settate le righe iva e la riga di totale documento +// Sostanzialmente di tratta di aggiungere un metodo in piu' : +// recalc_cg_rows(), liberamente ispirato alla notify_iva() in cg2102.cpp + +class TMovimentoPN_VE : public TMovimentoPN +{ + TCausale * _caus; + bool _valuta; + +protected: + // simula il K_SPACE di iva_notify + void create_row(int i); + // simula il K_ENTER di iva_notify + void enter_row(int i); + // verifica se si tratta di iva indetraibile + bool detraibile(TRectype& rec) const ; + // cerca la prima tra quelle di contabilita' che corrisponde al tipo indicato + int type2pos(char tipo); + // Trova nelle righe contabili un conto nelle righe di tipo prescelto + int bill2pos(const TBill& conto, char tipo); + // trasforma un real in TImporto, in base al tipo riga + TImporto real2imp(const real& r, char row_type); + // setta il record delle righe di contabilita' + int set_cg_rec(int n, const TImporto& imp, TBill& conto, const char* desc, char tipo); + // aggiunge l'importo indicato alla n-esima riga di contabilita' + bool add_cg_rec(int n, const TImporto& imp); + // Legge l'importo della riga n e lo ritorna col segno dovuto + TImporto get_cg_imp(int n); + // Setta l'importo della riga n + void set_cg_imp(int n, const TImporto& imp); + // verifica se il movimento e' quadrato oppure ha qualche maledetto sbilancio + // ritorna TRUE, ovviamente, se everything's alright. + bool movement_ok() ; +public: + // ricalcola le righe di contabilita' dalle righe iva presenti + // e verifica la quadratura del movimento. Ritorna TRUE se il movimento e' scrivibile + bool recalc_cg_rows(TCausale* caus = NULL); + TMovimentoPN_VE(bool valuta) : _valuta(valuta) {}; + virtual ~TMovimentoPN_VE() {} +}; + +TImporto TMovimentoPN_VE::real2imp(const real& r, char row_type) +{ + CHECK(_caus,"Orgggssbb..._caus pointer is NULL!"); + bool dare; + if (row_type == 'S') + { + dare = _caus->sezione_ritsoc() == 'D'; + } + else + { + dare = _caus->sezione_clifo() == 'D'; + if (row_type != 'T' && row_type != 'F') + dare = !dare; + } + + TImporto importo(dare ? 'D' : 'A', r); + return importo; +} + +bool TMovimentoPN_VE::detraibile(TRectype& rec) const +{ + CHECK(_caus,"Orgggssbb..._caus pointer is NULL!"); + if (_caus->iva() == iva_vendite) + return TRUE; + + if (rec.get_int(RMI_TIPODET) != 0) + return FALSE; + + const real & p = _caus->reg().prorata(); + return p < 100.0; +} + +int TMovimentoPN_VE::bill2pos(const TBill& conto, char tipo) +{ + const int items = cg_items(); + for (int i = 0; i < items; i++) + { + TRectype& s = cg(i); + const char t = s.get_char(RMV_ROWTYPE); + if (t == tipo) + { + TBill c; + const int gr = s.get_int(RMV_GRUPPO); + const int co = s.get_int(RMV_CONTO); + const long so = s.get_long(RMV_SOTTOCONTO); + c.set(gr,co,so); + if (c == conto) + return i; + } + } + return -1; +} + +int TMovimentoPN_VE::type2pos(char tipo) +{ + const int items = cg_items(); + for (int i = 0; i < items; i++) + { + TRectype& s = cg(i); + const char t = s.get_char(RMV_ROWTYPE); + if (t == tipo) + return i; + } + return -1; +} + +void TMovimentoPN_VE::set_cg_imp(int n, const TImporto& imp) +{ + TRectype& rec = cg(n); + rec.put(RMV_SEZIONE,imp.sezione()); + rec.put(RMV_IMPORTO,imp.valore()); +} + +TImporto TMovimentoPN_VE::get_cg_imp(int n) +{ + TRectype& rec = cg(n); + TImporto importo; + const char sez = rec.get_char(RMV_SEZIONE); + const real valore(rec.get_real(RMV_IMPORTO)); + importo.set(sez,valore); + return importo; +} + +bool TMovimentoPN_VE::add_cg_rec(int n, const TImporto& imp) +{ + TImporto tot(get_cg_imp(n)); + tot += imp; + //tot.normalize(); + set_cg_imp(n, tot); + return tot.is_zero(); +} + +int TMovimentoPN_VE::set_cg_rec(int n, const TImporto& imp, TBill& conto, + const char* desc, char tipo) +{ + const bool insert = n < 0; + if (insert) n = cg_items(); // Questa e' la prima riga di contabilita' vuota e disponibile + TRectype& rec = cg(n); + + if (insert) + { + TRectype& head = lfile().curr(); + const int annoes = head.get_int(MOV_ANNOES); + const long numreg = head.get_long(MOV_NUMREG); + TDate datareg(head.get_date(MOV_DATAREG)); + rec.put(RMV_ANNOES,annoes); + rec.put(RMV_NUMREG,numreg); + rec.put(RMV_DATAREG,datareg); + } + rec.put(RMV_SEZIONE,imp.sezione()); + rec.put(RMV_IMPORTO,imp.valore()); + rec.put(RMV_TIPOC,conto.tipo()); + rec.put(RMV_GRUPPO,conto.gruppo()); + rec.put(RMV_CONTO,conto.conto()); + rec.put(RMV_SOTTOCONTO,conto.sottoconto()); + //rec.put(RMV_DESCR,conto.descrizione()); + + if (tipo == 'T') // Calcolo contropartita + { + TRectype& irec = iva(0); + const char t = irec.get_char(RMI_TIPOC); + const int gr = irec.get_int(RMI_GRUPPO); + const int co = irec.get_int(RMI_CONTO); + const long so = irec.get_long(RMI_SOTTOCONTO); + rec.put(RMV_TIPOCC,t); + rec.put(RMV_GRUPPOC,gr); + rec.put(RMV_CONTOC,co); + rec.put(RMV_SOTTOCONTOC,so); + } + else + { + const int pos = type2pos('T'); + if (pos >= 0) + { + TRectype& crec = cg(pos); + const char t = crec.get_char(RMV_TIPOC); + const int gr = crec.get_int(RMV_GRUPPO); + const int co = crec.get_int(RMV_CONTO); + const long so = crec.get_long(RMV_SOTTOCONTO); + rec.put(RMV_TIPOCC,t); + rec.put(RMV_GRUPPOC,gr); + rec.put(RMV_CONTOC,co); + rec.put(RMV_SOTTOCONTOC,so); + } + } + + rec.put(RMV_ROWTYPE,tipo); + return n; +} + +void TMovimentoPN_VE::create_row(int i) +{ + CHECK(_caus,"Orgggssbb..._caus pointer is NULL!"); + TRectype& cur = iva(i); + real oldimp = cur.get_real(RMI_IMPONIBILE); + real oldiva = cur.get_real(RMI_IMPOSTA); + + if (oldiva.is_zero() && _caus->corrispettivi()) // In caso di corrispettivi ... + { + const TString zanicchi(cur.get(RMI_CODIVA)); // Codice IVA + const TCodiceIVA i(zanicchi); + oldiva = i.scorpora(oldimp); // ... scorpora imposta dall'imponibile + } + + const char tipod = detraibile(cur) ? 'D' : 'N'; + + if (type2pos(tipod) < 0 && !oldiva.is_zero()) + { + const int ri = tipod == 'D' ? 3 : 4; // Calcola riga causale per l'IVA + TBill c; _caus->bill(ri, c); + if (c.ok()) + { + const TString80 d(_caus->desc_agg(ri)); + set_cg_rec(-1, real2imp(ZERO, 'I'), c, d, tipod); + } + else + if (ri == 4) // Se non esiste il conto IVA indetraibile ... + { // ... somma imponibile e imposta + oldimp += oldiva; + oldiva = 0.0; + } + } + + TBill oldconto; + const int gr = cur.get_int(RMI_GRUPPO); + const int co = cur.get_int(RMI_CONTO); + const long so = cur.get_long(RMI_SOTTOCONTO); + oldconto.set(gr,co,so); + if (oldconto.ok()) + { + if (bill2pos(oldconto, 'I') < 0) + { + const TString d(_caus->desc_agg(2)); + set_cg_rec(-1, real2imp(ZERO, 'I'), oldconto, d, 'I'); + } + } +} + +void TMovimentoPN_VE::enter_row(int i) +{ + CHECK(_caus,"Orgggssbb..._caus pointer is NULL!"); + TRectype& cur = iva(i); + real imponibile = cur.get_real(RMI_IMPONIBILE); + real imposta = cur.get_real(RMI_IMPOSTA); + + if (imposta.is_zero() && _caus->corrispettivi()) // In caso di corrispettivi ... + { + const TString zanicchi(cur.get(RMI_CODIVA)); + const TCodiceIVA i(zanicchi); + imposta = i.scorpora(imponibile); // ... scorpora imposta dall'imponibile + } + + TBill conto; + const char t = cur.get_char(RMI_TIPOC); + const int gr = cur.get_int(RMI_GRUPPO); + const int co = cur.get_int(RMI_CONTO); + const long so = cur.get_long(RMI_SOTTOCONTO); + conto.set(gr,co,so,t); + + int newpos = bill2pos(conto, 'I'); // Riga in cui andra' l'imponibile + + const bool detrarre = detraibile(cur); // Determina se IVA detraibile + + // Calcola riga causale col conto opportuno + const int ri = detrarre ? RIGA_IVA_DETRAIBILE : RIGA_IVA_NON_DETRAIBILE; + TBill contoiva; _caus->bill(ri, contoiva); + + if (ri == 4 && !contoiva.ok()) // Se non c'e' il conto IVA indetraibile ... + { // ... somma imponibile e imposta + imponibile += imposta; + imposta = 0.0; + } + + // Aggiorna conto sulla riga contabile + if (newpos < 0) // conto non esistente: da inserire + { + const TImporto val(real2imp(imponibile, 'I')); + if (conto.ok() && !val.is_zero()) // Se c'e' imponibile ... + { // crea una nuova riga contabile + const TString d(_caus->desc_agg(2)); + set_cg_rec(-1, val, conto, d, 'I'); + } + } + else + { + TImporto val(real2imp(imponibile, 'I')); + add_cg_rec(newpos, val); + } + + // Aggiorna conto IVA sulla riga contabile + + const char tipod = detrarre ? 'D' : 'N'; + int newposiva = type2pos(tipod); + + if (newposiva < 0) + { + if (!imposta.is_zero()) // Se c'e' imposta ... + { // ... crea nuova riga per l'IVA + const TImporto val(real2imp(imposta, 'I')); + const TString d(_caus->desc_agg(ri)); + set_cg_rec(-1, val, contoiva, d, tipod); + } + } + else + { + const TImporto val(real2imp(imposta, 'I')); + add_cg_rec(newposiva, val); + } +} + +bool TMovimentoPN_VE::movement_ok() +{ + TImporto tot_imp; + TImporto imp; + + // Se siamo in valuta, forzera' la riga totale documento a cio' che si ottiene dalla somma + // delle singole righe per evitare sbilanci nel movimento di 2,3,4,5 lire dovuti agli arrotondamenti + const int max = cg_items(); + for (int i = 0; i < max; i++) + { + if (i == 0 && _valuta) + continue; + TRectype& r = cg(i); + const char sez = r.get_char(RMV_SEZIONE); + const real val(r.get_real(RMV_IMPORTO)); + imp.set(sez,val); + tot_imp+=imp; + } + + if (_valuta) + { + TRectype& r = cg(0); + // Setta la riga di totale documento... + r.put(RMV_IMPORTO,tot_imp.valore()); + r.put(RMV_SEZIONE,tot_imp.sezione() == 'D' ? 'A' : 'D'); // Sezione contraria + // ...ed anche il totale documento sulla testata + lfile().curr().put(MOV_TOTDOC,tot_imp.valore()); + tot_imp.valore() = 0.0; + } + + if (!tot_imp.is_zero()) + return FALSE; + return TRUE; +} + +bool TMovimentoPN_VE::recalc_cg_rows(TCausale* caus) +{ + const int righe = iva_items(); + bool external_caus = TRUE; + if (caus == NULL) + { + external_caus = FALSE; + TRectype& head = lfile().curr(); + TString16 codcau(head.get(MOV_CODCAUS)); + int year = head.get_int(MOV_ANNOIVA); + _caus = new TCausale (codcau,year); + } + else + _caus = caus; + for (int i=0; iadd(LF_CFVEN,"TIPOCF=TIPOCF|CODCF=CODCF"); +} + +TContabilizzazione::TContabilizzazione(const TRectype& rec) + : TElaborazione(rec), _auto_data(FALSE), _nump_iva(2) +{ + _fcaus = new TLocalisamfile(LF_CAUSALI); + _frcaus = new TLocalisamfile(LF_RCAUSALI);// Per far andare TCausale + _attiv = new TLocalisamfile(LF_ATTIV); // Altrimenti TRegistro non va! + _part = new TLocalisamfile(LF_PARTITE); + _scad = new TLocalisamfile(LF_SCADENZE); + _pags = new TLocalisamfile(LF_PAGSCA); // Per far funzionare TPartita + _occas = new TLocalisamfile(LF_OCCAS); + _docfile = new TLocalisamfile(LF_DOC); + _rdocfile = new TLocalisamfile(LF_RIGHEDOC); // Per far funzionare TDocumento,TPartita ecc.. + _anamag = new TLocalisamfile(LF_ANAMAG); + + _cpg = new TTable("%CPG"); + _tri = new TTable("%TRI"); + _val = new TTable("%VAL"); + _prs = new TTable("PRS"); + _spp = new TTable("SPP"); + _caa = new TTable("CAA"); + _cra = new TTable("CRA"); + _gmc = new TTable("GMC"); + _rfa = new TTable("RFA"); + _cve = new TTable("CVE"); + _cco = new TTable("CCO"); + _clifo = new TRelation(LF_CLIFO); + _clifo->add(LF_CFVEN,"TIPOCF=TIPOCF|CODCF=CODCF"); +} + +TContabilizzazione::~TContabilizzazione() +{ + delete _clifo; + delete _cpg; + delete _tri; + delete _val; + delete _gmc; + delete _rfa; + delete _cve; + delete _cco; + delete _prs; + delete _spp; + delete _caa; + delete _cra; + delete _anamag; + delete _fcaus; + delete _frcaus; + delete _attiv; + delete _part; + delete _scad; + delete _pags; + delete _occas; + delete _docfile; + delete _rdocfile; +} + +bool TContabilizzazione::load_parameters() +{ + TConfig conf(CONFIG_DITTA); + + _search_seq = conf.get("RICERCACR","ve"); + + // costruisce la stringa che controlla la ricerca del conto costo/ricavo + // Attenzione! non esegue alcun controllo di consistenza sulla corretta sequenza + // presuppone che il programma di configurazione abbia generato correttamente + // il tutto. + + if (_search_seq.items() == 0) + { + error_box("Non e' abilitata alcuna ricerca per il conto di costo/ricavo in configurazione."); + return FALSE; + } + _sc_enabled = conf.get_bool("GesSal","cg"); + _nump_cfg = conf.get_bool("RifPro","cg"); + + int gr,co; + long so; + + gr = conf.get_int("SCOPRCODCON","ve",1); + co = conf.get_int("SCOPRCODCON","ve",2); + so = conf.get_long("SCOPRCODCON","ve",3); + _sco_perc_bill.set(gr,co,so); + + gr = conf.get_int("SCOIMCODCON","ve",1); + co = conf.get_int("SCOIMCODCON","ve",2); + so = conf.get_long("SCOIMCODCON","ve",3); + _sco_imp_bill.set(gr,co,so); + + gr = conf.get_int("SPINCODCONA","ve",1); + co = conf.get_int("SPINCODCONA","ve",2); + so = conf.get_long("SPINCODCONA","ve",3); + _spin_billa.set(gr,co,so); + + gr = conf.get_int("SPINCODCONV","ve",1); + co = conf.get_int("SPINCODCONV","ve",2); + so = conf.get_long("SPINCODCONV","ve",3); + _spin_billv.set(gr,co,so); + + gr = conf.get_int("SPBOCODCONA","ve",1); + co = conf.get_int("SPBOCODCONA","ve",2); + so = conf.get_long("SPBOCODCONA","ve",3); + _spbo_billa.set(gr,co,so); + + gr = conf.get_int("SPBOCODCONV","ve",1); + co = conf.get_int("SPBOCODCONV","ve",2); + so = conf.get_long("SPBOCODCONV","ve",3); + _spbo_billv.set(gr,co,so); + + _spin_cod = conf.get("SPINCODIVA","ve"); + _spbo_cod = conf.get("SPBOCODIVA","ve"); + + return TRUE; +} + +error_type TContabilizzazione::compile_head_mov(TDocumento& doc) +// Compila la testata +{ + TLocalisamfile& mov = _movimento->lfile(); + TRectype& mov_rec = mov.curr(); + + // Reperisce la data documento + TDate datadoc(doc.data()); + if (!datadoc.ok()) + { + _error = datadoc_error; + return _error; + } + + // reperisce la data di registrazione, che e' anche la data di competenza ed + // eventualmente la data74ter se nel registro della causale vi e' scritta l'informazione + // sulle agenzie di viaggio. + // se si e' specificata la data automatica prende invece la data del documento + TDate data_reg(_auto_data ? datadoc : _data_reg); + + // reperisce il codice anno esercizio, + int cod_es = _esc.date2esc(data_reg); + if (cod_es <= 0) + { + _error = nr_es_error; + return _error; + } + + // reperisce l'ultimo numero di registrazione disponibile + mov.last(); + const long numreg = mov.get_int(MOV_NUMREG) + 1; + if (mov.status() != NOERR || numreg < 1) + { + _error = nr_reg_error; + return _error; + } + + TCodice_numerazione cod_num(doc.numerazione()); + // calcola il numero documento aggiungendo l'eventuale prefisso/postfisso. + TString numdoc(cod_num.complete_num(doc.numero())); + if (numdoc.empty() || cod_num.status() != NOERR) + { + _error = nr_doc_error; + return _error; + } + numdoc.upper(); // Il numero documento e' uppercase! + + // Istanzia la causale del documento corrente... + const TTipo_documento& tipo = doc.tipo(); + const TString codcaus(tipo.causale()); + _caus = new TCausale(codcaus,data_reg.year()); + if (!_caus->ok()) + { + _error = caus_error; + return _error; + } + // per reperire il tipo documento ed il tipo movimento + // reperisce la descrizione dal tipo documento e la completa con la data documento ed il + // numero documento + TString descr(tipo.riferimento()); + if (descr.empty()) descr = tipo.descrizione(); + descr << " n. " << doc.numero(); + descr << " del " << datadoc.string(); + + // Codice registro IVA + TRegistro& registro = _caus->reg(); + if (!registro.ok()) + { + _error = register_error; + return _error; + } + + long ult_prot; + if (_nump_iva == 1) // Reperisce l'ultimo numero di protocollo dal registro IVA + { + ult_prot = registro.protocol() +1; + if (ult_prot < 1) + { + _error = ultprot_error; + return _error; + } + } + else // oppure dal numero di documento + ult_prot = doc.numero(); + // Reperisce la valuta + TDate datacam(doc.get_date(DOC_DATACAMBIO)); + TString codval(doc.valuta()); + real cambio(doc.cambio()); + codval.trim(); + if (codval == "LIT") + { + codval = ""; + cambio = ZERO; + } + if (codval.not_empty()) + { + _val->put("CODTAB",codval); + if (_val->read() != NOERR) + { + _error = val_error; + return _error; + } + } + // Reperisce il cambio + if ((cambio != ZERO && codval.empty()) || + cambio == ZERO && codval.not_empty()) + { + _error = change_error; + return _error; + } + + // Dati del cliente... + TString tipocf(doc.get(DOC_TIPOCF)); + long codcf = doc.get_long(DOC_CODCF); + TString occas; + { + TLocalisamfile& cli_file = _clifo->lfile(); + cli_file.put(CLI_TIPOCF,tipocf); cli_file.put(CLI_CODCF,codcf); + if (_clifo->read(_isequal) == NOERR) // posiziona il cliente una volta per tutte + { + if (cli_file.get_bool(CLI_OCCAS)) + { + occas = doc.get(DOC_OCFPI); + TLocalisamfile ocf(LF_OCCAS); + ocf.put(OCC_CFPI,occas); + if (ocf.read() != NOERR) + { + _error = clifo_error; + return _error; + } + } + } + else + { + _error = clifo_error; + return _error; + } + } + + // Codice pagamento + TString codpag(doc.get(DOC_CODPAG)); + if (sc_enabled() || codpag.not_empty()) // La condizione di pagamento va controllata + { // se e' abilitato il saldaconto o se e' stata inserita + _cpg->put("CODTAB",codpag); + if (_cpg->read() != NOERR) + { + _error = codpag_error; + return _error; + } + } + + // Mo' riempie il record della incornata (testata) + mov_rec.zero(); + mov_rec.put(MOV_ANNOES,cod_es); mov_rec.put(MOV_NUMREG,numreg); + mov_rec.put(MOV_DATAREG,data_reg); mov_rec.put(MOV_DATACOMP,data_reg); + mov_rec.put(MOV_DATADOC,datadoc); + if (registro.agenzia_viaggi()) mov_rec.put(MOV_DATA74TER,data_reg); + mov_rec.put(MOV_NUMDOC,numdoc); mov_rec.put(MOV_TIPODOC,_caus->tipo_doc()); + mov_rec.put(MOV_CODCAUS,_caus->codice()); mov_rec.put(MOV_DESCR,descr); + mov_rec.put(MOV_TIPOMOV,char(_caus->tipomov()+'0')); mov_rec.put(MOV_ANNOIVA,data_reg.year()); + mov_rec.put(MOV_REG,registro.name()); + mov_rec.put(MOV_PROTIVA,ult_prot); mov_rec.put(MOV_CODVAL,codval); + mov_rec.put(MOV_CAMBIO,cambio); mov_rec.put(MOV_TIPO,tipocf); + mov_rec.put(MOV_DATACAM,datacam); + mov_rec.put(MOV_CODCF,codcf); mov_rec.put(MOV_OCFPI,occas); + mov_rec.put(MOV_CODPAG,codpag); + if (_caus->intra()) + { + mov_rec.put(MOV_CODVALI,codval);mov_rec.put(MOV_CAMBIOI,cambio); + real corrval(doc.imponibile()); + real corrlire = corrval*cambio; + if (codval.not_empty() && codval != "LIT") + { + mov_rec.put(MOV_CORRLIRE,corrlire); + mov_rec.put(MOV_CORRVALUTA,corrval); + } else + mov_rec.put(MOV_CORRLIRE,corrval); + } + real totdocval(doc.totale_doc()); + real totdoclit = totdocval * cambio; + if (codval.not_empty() && codval != "LIT") + { + mov_rec.put(MOV_TOTDOC,totdoclit); + mov_rec.put(MOV_TOTDOCVAL,totdocval); + } else + mov_rec.put(MOV_TOTDOC,totdocval); + return _error; +} + +error_type TContabilizzazione::search_costo_ricavo(TBill& conto, const TRiga_documento& r) +{ + const int items = _search_seq.items(); + TLocalisamfile & cli_file = _clifo->lfile(); // YES, arriva qui dentro quando la relazione e' gia' posizionata + const bool is_cli = cli_file.get(CLI_TIPOCF) == "C"; + bool skip_art_related = FALSE; + bool skip_clifo = _clifo->bad(); + TCodiceIVA codiva(r.get(RDOC_CODIVA)); + const char t = r.tipo().tipo(); + int gr,co; + long so; + + switch (t) + { + case 'O': // righe omaggio come articoli spiaccicato identico (avranno imponibile 0) + case 'M': // righe di merce + { + // posiziona l'anagrafica sull'articolo specificato sulla ..iga + _anamag->put(ANAMAG_CODART,r.get(RDOC_CODART)); + if (_anamag->read() != NOERR) // se non trova l'articolo saltera' anche gmc,smc,rfa. + skip_art_related = TRUE; + + // Scorre la stringa di ricerca + for (int i=0;good() && iIVA2bill(codiva,conto)) break; // se lo trova esce + } + else + if (tok == "AR") + { + if (skip_art_related) continue; + gr = _anamag->get_int(is_cli ? ANAMAG_GRUPPOV : ANAMAG_GRUPPOA); + co = _anamag->get_int(is_cli ? ANAMAG_CONTOV : ANAMAG_CONTOA); + so = _anamag->get_long(is_cli ? ANAMAG_SOTTOCV : ANAMAG_SOTTOCA); + conto.set(gr,co,so); + if (!conto.ok()) // se il conto non c'e' guarda la categoria acquisti/vendite + { + TTable *t = is_cli ? _cra : _caa; + + t->put("CODTAB",_anamag->get(is_cli ? ANAMAG_CATCONV : ANAMAG_CATCONA)); + if (t->read() == NOERR) + { + gr = atoi(t->get("S1")); + co = atoi(t->get("S2")); + so = atol(t->get("S3")); + conto.set(gr,co,so); + } + } + if (conto.ok()) break; + } + else + if (tok == "GM" || tok == "SM" || tok == "RF") + { + if (skip_art_related) continue; + const bool is_fis = tok == "RF"; + TTable * tab = is_fis ? _rfa : _gmc; + TString codtab(_anamag->get(is_fis ? ANAMAG_GRMERC : ANAMAG_RAGGFIS)); + if (tok == "GM") + codtab.cut(2); // gli ultimi 2 si riferiscono al sottogruppo. + tab->put("CODTAB",codtab); + if (tab->read() == NOERR) + { + gr = tab->get_int(is_cli ? "I3" : "I0"); + co = tab->get_int(is_cli ? "I4" : "I1"); + so = tab->get_long(is_cli ? "I5" : "I2"); + conto.set(gr,co,so); + } + if (conto.ok()) break; + } + else + if (tok == "CV" || tok == "CC") + { + const bool is_cve = tok == "CV"; + if (is_cve && !is_cli) continue; // se e' un fornitore salta questa condizione + TTable* t = is_cve ? _cve : _cco; + TString cod(is_cve ? r.doc().get(DOC_CATVEN) : ""); + if (cod.empty()) + { + if (skip_clifo) continue; // se non aveva trovato il cliente salta al prossimo + cod = _clifo->lfile(LF_CFVEN).get(is_cve ? CFV_CATVEN : CFV_CODCATC); + } + t->put("CODTAB",cod); + if (t->read() == NOERR) + { + const bool x =(is_cve || is_cli); + gr = t->get_int(x ? "I3" : "I0"); + co = t->get_int(x ? "I4" : "I1"); + so = t->get_long(x ? "I5": "I2"); + conto.set(gr,co,so); + } + if (conto.ok()) break; + } + } + break; // case 'M' + } + case 'P': // righe prestazione + case 'S': // righe spese + { + TTable* tab = t == 'P' ? _prs : _spp; + tab->put("CODTAB",r.get(RDOC_CODART)); + if (tab->read()==NOERR) + { + gr = tab->get_int(is_cli ? "I0" : "I3"); + co = tab->get_int(is_cli ? "I1" : "I4"); + so = tab->get_long(is_cli ? "I2" : "I5"); + conto.set(gr,co,so); + } + break; // case 'P','S' + } + case 'C': // righe sconti (TBI) (reperire l'imposta e l'imponibile normalizzare. Il conto e' nei parametri) + // quale sconto deve reperire dalla configurazione? Sconto ad importo o sconto a percentuale? + if (!r.get(RDOC_SCONTO).empty()) // se c'e' la percentuale reperisce il conto dello sconto a percentuale + conto = _sco_perc_bill; + else // altrimenti quello dello sconto ad importo + conto = _sco_imp_bill; + break; // case 'C' + case 'D': // righe descrizioni (saltare) + default : + break; + } // end of switch + if (good() && !conto.find()) + _error = conto_error; + return _error; +} + +error_type TContabilizzazione::add_iva_row(const TBill& conto, const TRiga_documento& r) +// Aggiunge le righe iva all'assoc_array di raggruppamento +{ + TIVA_element el_tmp; + TString cod(r.iva().codice()); + const char tipo = conto.tipo(); + const int gr = conto.gruppo(); + const int co = conto.conto(); + const long so = conto.sottoconto(); + TString key; + const char tipo_r = r.tipo().tipo(); + int ord=0; + // Ordine con cui vengono immesse le righe IVA: + // merce, omaggi, prestazioni, spese, bolli/spese d'incasso, sconti. + + switch (tipo_r) + { + case 'M': + ord = 1; + break; + case 'O': + ord = 2; + break; + case 'P': + ord = 3; + break; + case 'S': + ord = 4; + break; + case 'C': + ord = 6; + break; + default: break; + } + key.format("%d|%-4s|%c|%3d|%3d|%6ld",ord,(const char*)cod,tipo,gr,co,so); + const bool exists = _righe_iva.is_key(key); + TIVA_element& el = (exists ? (TIVA_element&)_righe_iva[key] : el_tmp); + el += r; + _righe_iva.add(key,el,exists); + return no_error; +} + +void TContabilizzazione::calculate_spese(real& spese, real& sp_iva, int ndec, bool is_incasso, bool is_cli) +{ + char tipo; + int gr,co; + long so; + const TBill& zio = is_incasso ? (is_cli ? _spin_billv : _spin_billa) : (is_cli ? _spbo_billv : _spbo_billa); + TIVA sp_cod(is_incasso ? _spin_cod : _spbo_cod); + TIVA_element el_tmp; + TString key; + + sp_iva = iva(spese,sp_cod,ndec); + tipo = zio.tipo(); + gr = zio.gruppo(); + co = zio.conto(); + so = zio.sottoconto(); + key.format("5|%-4s|%c|%3d|%3d|%6ld",(const char*)sp_cod.codice(),tipo,gr,co,so); + const bool exists = _righe_iva.is_key(key); + TIVA_element& el = (exists ? (TIVA_element&)_righe_iva[key] : el_tmp); + el.imp() = spese; + el.iva() = sp_iva; + el.ali() = sp_cod.aliquota(); + _righe_iva.add(key,el,exists); +} + +error_type TContabilizzazione::add_spese_inbo(TDocumento& doc) +// Aggiunge le righe di spese incasso/bolli +{ + real tot_netto, sp_incasso, sp_bolli; + real iva_sp_incasso, iva_sp_bolli; + const int ndec = doc.in_valuta() ? 3 : 0; + bool is_cli = doc.get(DOC_TIPOCF) == "C"; + // Aggiunge le spese d'incasso + tot_netto = doc.totale_netto(); + sp_incasso = doc.spese_incasso(tot_netto,ndec,_netto); + if (sp_incasso != 0.0) + calculate_spese(sp_incasso,iva_sp_incasso,ndec,TRUE,is_cli); + + // Aggiunge le spese bolli + tot_netto += sp_incasso + iva_sp_incasso; + sp_bolli = doc.bolli(tot_netto,ndec, _netto); + if (sp_bolli != 0) + calculate_spese(sp_bolli,iva_sp_bolli,ndec,FALSE,is_cli); + + return _error; +} + +error_type TContabilizzazione::create_iva_rows(TDocumento& doc) +{ + const int items = _righe_iva.items(); + const bool in_valuta = doc.in_valuta(); + TRectype& head = _movimento->lfile().curr(); + int gr,co; + long so; + char tipo; + TToken_string key; + TString_array key_arr; + TString16 codiva; + TBill conto; + + const int annoes = head.get_int(MOV_ANNOES); + const long numreg = head.get_long(MOV_NUMREG); + real cambio = head.get_real(MOV_CAMBIO); + real imponibile,imposta; + + _righe_iva.get_keys(key_arr); + key_arr.sort(); + TIVA_element cur; + for (int i = 0; i < items; i++) + { + key = key_arr.row(i); + cur = (TIVA_element&) _righe_iva[key]; + codiva = key.get(1); + tipo = key.get_char(2); + gr = key.get_int(3); + co = key.get_int(4); + so = atol(key.get(5)); + conto.set(gr,co,so,tipo); + conto.find(); + imponibile = cur.imp(); + if (in_valuta) + { + imponibile = cur.imp() * cambio; // imponibile in lire + imponibile.round(); + imposta = abs(imponibile) * cur.ali() / 100.0; // questa e' l'imposta ricalcolata + imposta.ceil(); + if (imponibile < 0.0) + imposta = -imposta; + } + else + imposta = cur.iva(); + TRectype& rec_iva = _movimento->iva(i); + rec_iva.put(RMI_ANNOES,annoes); + rec_iva.put(RMI_NUMREG,numreg); + rec_iva.put(RMI_NUMRIG,i+1); // La numerazione comincia da 1 + rec_iva.put(RMI_CODIVA,codiva); + rec_iva.put(RMI_IMPONIBILE,imponibile); + rec_iva.put(RMI_IMPOSTA,imposta); + rec_iva.put(RMI_TIPOCR,conto.tipo_cr()); + rec_iva.put(RMI_INTRA,_caus->intra()); + rec_iva.put(RMI_TIPOC,conto.tipo()); + rec_iva.put(RMI_GRUPPO,conto.gruppo()); + rec_iva.put(RMI_CONTO,conto.conto()); + rec_iva.put(RMI_SOTTOCONTO,conto.sottoconto()); + } + return _error; +} + +error_type TContabilizzazione::create_total_doc_row() +// Crea la riga contabile di totale documento +{ + TRectype& rec_cg = _movimento->cg(0); + TRectype& head = _movimento->lfile().curr(); + const int annoes = head.get_int(MOV_ANNOES); + const long numreg = head.get_long(MOV_NUMREG); + TDate datareg(head.get_date(MOV_DATAREG)); + real totdoc(head.get_real(MOV_TOTDOC)); + char rowtype = 'T'; + TLocalisamfile& cli_file = _clifo->lfile(); + TString16 tipocf(cli_file.get(CLI_TIPOCF)); + const long codcf = cli_file.get_long(CLI_CODCF); + int gruppo = 0, conto = 0; + + // Trova il mastro del cliente/fornitore + // cerca prima sul record del cliente/fornitore + if (_clifo->good()) + { + gruppo = cli_file.get_int(CLI_GRUPPO); + conto = cli_file.get_int(CLI_CONTO); + } + + // poi sulla categoria di vendita (solo per i clienti) + if ((gruppo == 0 || conto == 0) && tipocf == "C") + { + TString16 cod_cve(_clifo->lfile(LF_CFVEN).get(CFV_CATVEN)); + _cve->put("CODTAB",cod_cve); + if (_cve->read() == NOERR) + { + gruppo = _cve->get_int("I3"); + conto = _cve->get_int("I4"); + } + } + + TString descr; + descr = head.get(MOV_DESCR);// La descrizione della riga di totale documento la prende dalla testata + // se ancora non e' stato trovato piglia quello della causale + if (gruppo == 0 || conto == 0) + { + TBill zio; + _caus->bill(1,zio); + gruppo = zio.gruppo(); + conto = zio.conto(); + } + + if (gruppo == 0 || conto == 0) + _error = conto_error; + + TRectype& first_iva_row = _movimento->iva(0); + const char tc = first_iva_row.get_char(RMI_TIPOC); + const int grc = first_iva_row.get_int(RMI_GRUPPO); + const int coc = first_iva_row.get_int(RMI_CONTO); + const long soc =first_iva_row.get_long(RMI_SOTTOCONTO); + rec_cg.put(RMV_ANNOES,annoes);rec_cg.put(RMV_NUMREG,numreg); + rec_cg.put(RMV_NUMRIG,1); rec_cg.put(RMV_SEZIONE,tipocf == "C" ? "D" : "A"); + rec_cg.put(RMV_DATAREG,datareg); rec_cg.put(RMV_TIPOC,tipocf); + rec_cg.put(RMV_GRUPPO,gruppo);rec_cg.put(RMV_CONTO,conto); + rec_cg.put(RMV_SOTTOCONTO,codcf); rec_cg.put(RMV_DESCR,descr); + rec_cg.put(RMV_TIPOCC,tc); rec_cg.put(RMV_GRUPPOC,grc); + rec_cg.put(RMV_CONTOC,coc);rec_cg.put(RMV_SOTTOCONTOC,soc); + rec_cg.put(RMV_IMPORTO,totdoc); rec_cg.put(RMV_ROWTYPE,rowtype); + + return _error; +} + +error_type TContabilizzazione::compile_rows_mov(TDocumento& doc) +// Compila le righe +{ + const int rows = doc.rows(); + + _righe_iva.destroy(); // resetta l'assoc_array delle righe di iva + for (int i=1; good() && i<=rows; i++) // browse all this fucked document rows + { + const TRiga_documento& r = doc[i]; + TString16 tiporiga(r.get(RDOC_TIPORIGA)); + _tri->put("CODTAB",tiporiga); + if (_tri->read() == NOERR) // controlla l'esistenza della riga + { + TBill conto; + const char tipo = r.tipo().tipo(); + if (tipo != 'D') + { + search_costo_ricavo(conto,r); // l'errore eventuale viene settato qui dentro + if (good()) + add_iva_row(conto,r); + } + } + else + _error = row_type_error; + } + + if (good() && _righe_iva.items() == 0) + _error = no_rows_error; + + // Crea le righe per le spese d'incasso e bolli + if (good()) + add_spese_inbo(doc); + + // Crea le righe di IVA + if (good()) + create_iva_rows(doc); + // Crea la riga di totale documento + if (good()) + create_total_doc_row(); + // crea le righe di contabilita' + if (good()) + if (!_movimento->recalc_cg_rows(_caus)) + _error = movement_error; + return _error; +} + +error_type TContabilizzazione::change_doc_status(TDocumento& doc) +// Cambia lo stato del documento +{ + doc.stato(get("S4")[0]); + if (doc.rewrite() != NOERR) + _error = chg_stat_error; + return _error; +} + +error_type TContabilizzazione::write_scadenze(TDocumento& doc) +// Scrive le scadenze. Liberamente tratto da cg2104.cpp. +{ + TRectype& head = _movimento->lfile().curr(); + const TString16 codpag(head.get(MOV_CODPAG)); + TString16 data(doc.get(DOC_DATAINSC));// Il costruttore di TPagamento vuole un const char * + // Se la data di scadenza non e' compilata prende quella del documento + if (data.empty()) + data = doc.get(DOC_DATADOC); + + TPagamento * pagamento = new TPagamento(codpag, data); + real totspese = doc.spese(); + real totimposte = doc.imposta(); + real totimponibili = doc.totale_doc() - totimposte - totspese; + const bool valuta = head.get(MOV_CODVAL).not_empty(); + if (valuta) + { + const real change(head.get_real(MOV_CAMBIO)); + //real val1 = totimponibili * change; + real val2 = totimposte * change; + real val3 = totspese * change; + real val1 = head.get_real(MOV_TOTDOC) - val2 - val3; // Cosi' corregge eventuali scompensi di poche lirette + pagamento->set_total_valuta( totimponibili, totimposte, totspese, change, val1, val2 ,val3); + } + else + pagamento->set_total( totimponibili, totimposte, totspese ); + pagamento->set_rate_auto( ); + + const long nreg = head.get_long(MOV_NUMREG); + const int anno = head.get_int(MOV_ANNOIVA); + const TString numpart(head.get(_nump_cfg ? MOV_PROTIVA : MOV_NUMDOC)); + + TPartita* newgame = NULL; + + int nuova_riga = 0; + + if (anno > 0 && !numpart.blank()) + { + const int tmov = _caus->tipomov(); + const TString desc(head.get(MOV_DESCR)); + const TString codcaus(_caus->codice()); + const TString v(head.get(MOV_CODVAL)); + const TDate d(head.get_date(MOV_DATACAM)); + const real c(head.get_real(MOV_CAMBIO)); + const TValuta cambio(v, d, c); + const TString agente(doc.get(DOC_CODAG)); + const char sezione = _movimento->cg(0).get_char(RMV_SEZIONE); // Dare/Avere + + TBill clifo; + const char tipocf = head.get_char(MOV_TIPO); + const long codcf = head.get_long(MOV_CODCF); + clifo.set(0,0,codcf,tipocf); + newgame = new TPartita(clifo, anno, numpart); + + const int row = newgame->prima_fattura(nreg); // Riga fattura di questo movimento + TRiga_partite& partita = row <= 0 ? newgame->new_row() : newgame->riga(row); + nuova_riga = partita.get_int(PART_NRIGA); + + TPagamento& pag = *pagamento; + + // put data on partita + partita.put(PART_TIPOMOV, tmov); + partita.put(PART_NREG, nreg); + partita.put(PART_NUMRIG, 1); + partita.put(PART_DATAREG, head.get_date(MOV_DATAREG)); + partita.put(PART_DATADOC, head.get_date(MOV_DATADOC)); + partita.put(PART_NUMDOC, head.get(MOV_NUMDOC)); + partita.put(PART_DESCR, desc); + partita.put(PART_CODCAUS, codcaus); + partita.put(PART_REG, _caus->reg().name()); + partita.put(PART_PROTIVA, head.get_long(MOV_PROTIVA)); + partita.put(PART_SEZ, sezione); + + const real totdoc(head.get_real(MOV_TOTDOC)); + partita.put(PART_IMPTOTDOC, totdoc); + + cambio.put(partita); + const bool in_valuta = cambio.in_valuta(); + + if (in_valuta) + { + const real totdocval(head.get_real(MOV_TOTDOCVAL)); + partita.put(PART_IMPTOTVAL,totdocval); + } + + real imponibile, imponibile_val; + for (int i = pag.n_rate()-1; i >= 0; i--) + { + if (in_valuta) + imponibile_val += pag.tval_rata(i); + imponibile += pag.tlit_rata(i); + } + + partita.put(PART_IMPORTO, imponibile); + partita.put(PART_IMPORTOVAL, imponibile_val); + partita.put(PART_IMPOSTA, pag.imposta()); + partita.put(PART_SPESE, pag.spese()); + + const TString abipr(doc.get(DOC_CODABIP)), + cabpr(doc.get(DOC_CODCABP)), + abi(doc.get(DOC_CODABIA)), + cab(doc.get(DOC_CODCABA)); + + + partita.elimina_rata(-1); // Elimina tutte le rate eventuali + const int nr = pag.n_rate(); + for (i = 0; i < nr; i++) + { + TRiga_scadenze& scadenza = partita.new_row(); + + scadenza.put(SCAD_CODPAG, codpag); // Codice pagamento + scadenza.put(SCAD_CODAG, agente); // Codice agente + + scadenza.put(SCAD_DATASCAD, pag.data_rata(i)); // Data scadenza + scadenza.put(SCAD_IMPORTO, pag.tlit_rata(i)); // Importo + if (in_valuta) + scadenza.put(SCAD_IMPORTOVAL, pag.tval_rata(i)); // Importo in valuta + scadenza.put(SCAD_TIPOPAG, pag.tipo_rata(i)); // Tipo pagamento + scadenza.put(SCAD_ULTCLASS, pag.ulc_rata(i)); // Ulteriore classificazione + scadenza.put(SCAD_CODABIPR, abipr); // Ns ABI + scadenza.put(SCAD_CODCABPR, cabpr); // Ns CAB + scadenza.put(SCAD_CODABI, abi); // Vs ABI + scadenza.put(SCAD_CODCAB, cab); // Vs CAB +// scadenza.put(SCAD_DESCR, ????); // Note + } + } + + if (newgame != NULL) // Se non ho cancellato il numero partita ... + { + if (!newgame->write()) // Salva nuova partita + error_box("Si e' verificato un errore scrivendo le scadenze del documento."); + delete newgame; + } + + delete pagamento; + return _error; +} + +error_type TContabilizzazione::write_all(TDocumento& doc) +// Scrive il movimento e le scadenze, gestendo la rinumerazione se il movimento e' gia presente +{ + // N.B: _error non viene settato, per non stampare il messaggio di errore 2 volte. + // basta solo ritornare qualcosa di != da no_error, per evitare le operazioni successive + // a write_all + TRectype& head = _movimento->lfile().curr(); + long numreg = head.get_long(MOV_NUMREG); + while (_movimento->write() == _isreinsert) + head.put(MOV_NUMREG,++numreg); + if (_movimento->status() != NOERR) + { + error_box("Errore %d scrivendo il movimento %ld.",_movimento->status(),numreg); + return generic_error; + } + if (sc_enabled()) + write_scadenze(doc); + + return no_error; +} + +void TContabilizzazione::display_error(TDocumento& doc) +{ + TString msg; + TString numerazione = doc.numerazione(); + const long numero = doc.numero(); + + switch (_error) + { + case nr_es_error: + msg.format("Rilevato un codice esercizio errato contabilizzando il documento %s/%ld." + "Verificare l'esistenza e la correttezza della tabella esercizi e della data del documento.",(const char*)numerazione,numero); + break; + case nr_reg_error: + msg.format("Rilevato un numero di registrazione errato contabilizzando il documento %s/%ld." + "Verificare l'integrita' del file movimenti.",(const char*)numerazione,numero); + break; + case nr_doc_error: + msg.format("Rilevato un numero di documento errato contabilizzando il documento %s/%ld." + "Verificare il numero documento e il codice numerazione inseriti in tabella.",(const char*)numerazione,numero); + break; + case chg_stat_error: + msg.format("Rilevato un errore cambiando lo stato al documento %s/%ld." + "Verificare l'integrita' del file documenti.",(const char*)numerazione,numero); + break; + case clifo_error: + msg.format("Rilevato un errore caricando le informazioni del Cli/Fo sul documento %s/%ld." + "Verificare l'esistenza delle informazioni inserite sul file documenti e Cli/Fo.",(const char*)numerazione,numero); + break; + case ultprot_error: + msg.format("Rilevato un numero di protocollo IVA errato relativamente al documento %s/%ld." + "Verificare le informazioni inserite sul registro %s/%d.",(const char*)numerazione,numero, + (const char*) _caus->reg().name(),_caus->reg().year()); + break; + case datadoc_error: + msg.format("Rilevato una data documento vuota relativamente al documento %s/%ld." + "Verificare l'informazione inserita.",(const char*)numerazione,numero); + break; + case caus_error: + msg.format("Rilevato un errore caricando la causale relativamente al documento %s/%ld." + "Verificare l'esistenza del codice causale inserito.",(const char*)numerazione,numero); + break; + case register_error: + msg.format("Rilevato un errore caricando il registro relativamente al documento %s/%ld." + "Verificare l'esistenza del codice causale/registro inseriti.",(const char*)numerazione,numero); + break; + case change_error: + msg.format("Rilevato un cambio senza valuta relativamente al documento %s/%ld." + "Verificare la correttezza delle informazioni inserite.",(const char*)numerazione,numero); + break; + case val_error: + msg.format("Rilevato un codice valuta inesistente relativamente al documento %s/%ld." + "Verificare la correttezza della informazione inserita.",(const char*)numerazione,numero); + break; + case codpag_error: + msg.format("Rilevato un codice pagamento non esistente relativamente al documento %s/%ld." + "Verificare l'esistenza del codice pagamento inserito.",(const char*)numerazione,numero); + break; + case row_type_error: + msg.format("Rilevato un codice tipo riga non esistente relativamente al documento %s/%ld." + "Verificare l'esistenza dei vari codici riga inseriti.",(const char*)numerazione,numero); + break; + case no_rows_error: + msg.format("Nessuna riga iva contabile e' stata trovata relativamente al documento %s/%ld." + "Verificare l'esistenza dei vari codici riga inseriti.",(const char*)numerazione,numero); + break; + case conto_error: + msg.format("Rilevato un conto di costo/ricavo inesistente relativamente al documento %s/%ld." + "Verificare l'esistenza dei conti associati alle righe.",(const char*)numerazione,numero); + break; + case movement_error: + msg.format("Rilevato uno sbilancio nel movimento relativamente al documento %s/%ld." + "Verificare la correttezza degli importi delle righe.",(const char*)numerazione,numero); + break; + case write_error: + msg.format("Rilevato un errore in scrittura movimento relativamente al documento %s/%ld." + "Verificare la consistenza dei files.",(const char*)numerazione,numero); + break; + default: // errori generici o non indicati vengono visualizzati nel punto dell'errore + //msg.format("E' stato rilevato un errore generico contabilizzando il documento %s/%ld.", + // (const char*)numerazione,numero); + break; + } + warning_box(msg); + _error = no_error; // reset error, as any other one would do, so you can show me the other ones. + _can_write = FALSE; // But from now on u cannot write anymore. U must exit this program and repair errors occurred. +} + +bool TContabilizzazione::sc_enabled() const +{ + bool rt = _sc_enabled; + if (_caus != NULL) rt &= _caus->saldaconto(); + return rt; +} + +bool TContabilizzazione::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, + const TDate& data_elab) +{ + if (!load_parameters()) // Carica i parametri dalla configurazione + return FALSE; + + _error = no_error; + _can_write = TRUE; + _total_docs = 0L; + _caus = NULL; + _data_reg = data_elab; + _esc.update(); + + const int items = doc_in.items(); // Numero dei documenti in questa elaborazione + TProgind p(items,"Contabilizzazione documenti",FALSE,TRUE,1); + for (int i = 0; i < items ; i++) // Scorriamo tutti i documenti nella lista + { + p.setstatus(i+1); + TDocumento& doc = doc_in[i]; + _movimento = new TMovimentoPN_VE(doc.in_valuta()); + + compile_head_mov(doc); + if (good()) + compile_rows_mov(doc); + + if (good() && _can_write) + if (write_all(doc) == no_error) // Se la scrittura e' andata ok... + { + _total_docs++; + change_doc_status(doc); + } + if (_caus != NULL) + { + delete _caus; + _caus = NULL; + } + if (!good()) + display_error(doc); + delete _movimento; + } + + return _can_write; // Se non ha riscontrato errori per nessun documento, _can_write = TRUE +} + diff --git a/ve/velib04c.cpp b/ve/velib04c.cpp new file mode 100755 index 000000000..3225cb6ac --- /dev/null +++ b/ve/velib04c.cpp @@ -0,0 +1,561 @@ +#include +#include + +#include +#include +#include +#include + +#include "../cg/cgsaldac.h" +#include "../ef/ef0101.h" + +#include "velib.h" + +/////////////////////////////////////////////////////////// +// TGenerazione_effetti +/////////////////////////////////////////////////////////// + +static TPagamento* _pagamento = NULL; + +TGenerazione_effetti::TGenerazione_effetti(const char* cod) + : TElaborazione(cod) +{ + _valid_array.set(2); // tratta + _valid_array.set(3); // riba + _valid_array.set(5); // paghero' + _valid_array.set(7); // tratta accettata + _valid_array.set(8); // rapporti interbancari diretti (rid) + _valid_array.reset(9); // bonifici + + _docfile = new TLocalisamfile(LF_DOC); + _rdocfile = new TLocalisamfile(LF_RIGHEDOC); + _cessfile = new TLocalisamfile(LF_CESS); + _occas = new TLocalisamfile(LF_OCCAS); + _clifo = new TLocalisamfile(LF_CLIFO); + _cfven = new TLocalisamfile(LF_CFVEN); + _tab = new TLocalisamfile(LF_TAB); + _efffile = new TLocalisamfile(LF_EFFETTI); + _refffile = new TLocalisamfile(LF_REFFETTI); + _cpg = new TTable("%CPG"); +} + +TGenerazione_effetti::TGenerazione_effetti(const TRectype& rec) + : TElaborazione(rec) +{ + _valid_array.set(2); // tratta + _valid_array.set(3); // riba + _valid_array.set(5); // paghero' + _valid_array.set(7); // tratta accettata + _valid_array.set(8); // rapporti interbancari diretti (rid) + _valid_array.reset(9); // bonifici + _docfile = new TLocalisamfile(LF_DOC); + _rdocfile = new TLocalisamfile(LF_RIGHEDOC); + _cessfile = new TLocalisamfile(LF_CESS); + _occas = new TLocalisamfile(LF_OCCAS); + _clifo = new TLocalisamfile(LF_CLIFO); + _cfven = new TLocalisamfile(LF_CFVEN); + _tab = new TLocalisamfile(LF_TAB); + _efffile = new TLocalisamfile(LF_EFFETTI); + _refffile = new TLocalisamfile(LF_REFFETTI); + _cpg = new TTable("%CPG"); +} + +TGenerazione_effetti::~TGenerazione_effetti() +{ + delete _docfile; + delete _rdocfile; + delete _cessfile; + delete _occas; + delete _clifo; + delete _cfven; + delete _efffile; + delete _refffile; + delete _tab; + delete _cpg; +} + +void TGenerazione_effetti::display_error(TDocumento& doc) +{ + TString msg; + TString numerazione = doc.numerazione(); + const long numero = doc.numero(); + + switch (_error) + { + case nr_doc_error: + msg.format("Rilevato un numero di documento errato contabilizzando il documento %s/%ld." + "Verificare il numero documento e il codice numerazione inseriti in tabella.",(const char*)numerazione,numero); + break; + case chg_stat_error: + msg.format("Rilevato un errore cambiando lo stato al documento %s/%ld." + "Verificare l'integrita' del file documenti.",(const char*)numerazione,numero); + break; + case datadoc_error: + msg.format("Rilevato una data documento vuota relativamente al documento %s/%ld." + "Verificare l'informazione inserita.",(const char*)numerazione,numero); + break; + case codpag_error: + msg.format("Rilevato un codice pagamento non esistente relativamente al documento %s/%ld." + "Verificare l'esistenza del codice pagamento inserito.",(const char*)numerazione,numero); + break; + case scadenze_error: + msg.format("Calcolate 0 scadenze relativamente al documento %s/%ld." + "Verificare la correttezza del codice pagamento inserito.",(const char*)numerazione,numero); + break; + case write_error: + if (_efffile->status() != NOERR) + msg.format("Si e' verificato l' errore %d in scrittura sul file effetti relativamente al documento %s/%ld" + "Verificare la consistenza del file.",_efffile->status(),(const char*)numerazione,numero); + else + msg.format("Si e' verificato l' errore %d in scrittura sul file righe effetti relativamente al documento %s/%ld" + "Verificare la consistenza del file.",_refffile->status(),(const char*)numerazione,numero); + break; + default: + msg.format("E' stato rilevato un errore generico contabilizzando il documento %s/%ld.", + (const char*)numerazione,numero); + break; + } + warning_box(msg); + _error = no_error; // reset error, as any other one would do, so you can show me the other ones. + _can_write = FALSE; // But from now on u cannot write anymore. U must exit this program and repair errors occurred. +} + +error_type TGenerazione_effetti::change_doc_status(TDocumento& doc) +// Cambia lo stato del documento +{ + doc.stato(get("S4")[0]); + if (doc.rewrite() != NOERR) + _error = chg_stat_error; + return _error; +} + +error_type TGenerazione_effetti::change_group_status(TDocumento& doc) +// Cambia lo stato dei documenti raggruppati +{ + const int items = _group_array.items(); + if (items > 0) + { + _error = no_error; + TToken_string * group_element; + int i=0; + // Ciclo sugli elementi dell'assoc_array + for (group_element = (TToken_string *) _group_array.first_item(); group_element != NULL && i < items; i++,group_element = (TToken_string*)_group_array.succ_item()) + { + group_element->restart(); + const int doc_items = group_element->items(); + for (int j=0;jget(j),'$'); + char provv = t.get_char(0); + int anno = t.get_int(1); + TString codnum(t.get(2)); + long numdoc = t.get_long(3); + if (doc.read(provv,anno,codnum,numdoc) == NOERR) // Legge il documento + { + doc.put(DOC_STATO,get("S4")[0]); + doc.rewrite(); + } + } + } + } + return _error; +} + +error_type TGenerazione_effetti::write_groups() +{ + const int items = _effetti_array.items(); + int err = NOERR; + _error = no_error; + for (int i = 0; irestart(); + const int doc_items = group_element->items(); + for (j=0;jget(j),'$'); + char provv = t.get_char(0); + int anno = t.get_int(1); + TString codnum(t.get(2)); + long numdoc = t.get_long(3); + if (doc.read(provv,anno,codnum,numdoc) != NOERR) continue; // Legge il documento (giusto saltare e proseguire se non lo trova?) + + msg2 = "Documento: "; + msg2 << codnum << "/" << numdoc; + xvt_statbar_set(msg2); + do_events(); + // Ricalcola le scadenze + codpag = doc.get(DOC_CODPAG); + + _cpg->put("CODTAB",codpag); + if (_cpg->read()!= NOERR) + { + _error = codpag_error; + return; + } + TString16 data(doc.get(DOC_DATAINSC)); + + if (data.empty()) + data = doc.get(DOC_DATADOC); + + const real totale_fatt = doc.totale_doc(); + const bool valuta = doc.in_valuta(); + const real change = doc.cambio(); + const TDate datafatt = doc.get_date(DOC_DATADOC); + + calc_pagamento(doc,codpag,data); + CHECK(_pagamento,"Failed to create a TPagamento"); + const int numrate = _pagamento->n_rate( ); + if (numrate < 1) + { + _error = scadenze_error; + delete _pagamento; + _pagamento = NULL; + return; + } + + // Scorre le scadenze + for (n = 1; n <= numrate && good(); n++) + { + // Se non esiste effetto n-esimo (corrisponde al numero di rata corrente+offset) + // lo genera con la relativa riga. Se esiste vi somma gli importi ed accoda la riga + const bool is_new = n+offset > _effetti_array.items(); + if (is_new) // Nuovo effetto: crea effetto con i dati di questo documento (e' il primo che incontro nella scansione) + { + TEffetto effetto; + // Setta i dati della testata; + effetto.put(EFF_DATASCAD, _pagamento->data_rata(n-1)); + effetto.put(EFF_TIPOPAG,_pagamento->tipo_rata(n-1)); + effetto.put(EFF_ULTCLASS,_pagamento->ulc_rata(n-1)); + effetto.put(EFF_CODCF, doc.get_long(DOC_CODCF)); + effetto.put(EFF_CODVAL, doc.get(DOC_CODVAL)); + effetto.put(EFF_CAMBIO, change); + effetto.put(EFF_DATACAMBIO,doc.get_date(DOC_DATACAMBIO)); + effetto.put(EFF_CODABI,doc.get(DOC_CODABIA)); + effetto.put(EFF_CODCAB,doc.get(DOC_CODCABA)); + effetto.put(EFF_EFFCOMP,TRUE); + _effetti_array.add(effetto); + } + // aggiorna totale effetto (testata) + TEffetto& effetto=(TEffetto&)_effetti_array[n+offset-1]; + importo = effetto.get_real(EFF_IMPORTO); + imprata = _pagamento->importo_rata(n-1,FALSE); + importo += imprata; + effetto.put(EFF_IMPORTO,importo); + if (valuta) + { + importoval = effetto.get_real(EFF_IMPORTOVAL); + imprataval = _pagamento->importo_rata(n-1,TRUE); + importoval += imprataval; + effetto.put(EFF_IMPORTOVAL,importoval); + } + // Crea la nuova riga di questo effetto + const int rows = effetto.rows_r(); + TRectype& riga = effetto.row_r(rows+1,TRUE); +// reffetto.put(REFF_NPROGTR,nprog); + riga.put(REFF_NRIGATR,rows+1); + riga.put(REFF_NRATA,n); + riga.put(REFF_DATAFATT, datafatt); + riga.put(REFF_PROVV,provv); + riga.put(REFF_ANNODOC,anno); + riga.put(REFF_CODNUM,codnum); + riga.put(REFF_NFATT,numdoc); + riga.put(REFF_IMPFATT,totale_fatt); + riga.put(REFF_IMPORTO,imprata); + if (valuta) + { + riga.put(REFF_IMPFATTVAL,totale_fatt); + real totfatlit = totale_fatt*change; + riga.put(REFF_IMPFATT,totfatlit); + riga.put(REFF_IMPORTOVAL,imprataval); + } + } // Ciclo sulle scadenze + if (_pagamento) + { + delete _pagamento; + _pagamento = NULL; + } + } // Ciclo sui documenti di questo gruppo + offset=_effetti_array.items(); + } // Ciclo sui gruppi + + // Cambia lo stato a tutti i documenti raggruppati + if (good() && _can_write) + if (write_groups() == no_error) + { + _total_bills += _effetti_array.items(); + change_group_status(doc); + } + _effetti_array.destroy(); + _group_array.destroy(); +} + +bool TGenerazione_effetti::valid_type(int pag) const +{ + return _valid_array[pag]; +} + +void TGenerazione_effetti::calc_pagamento(TDocumento& doc, TString16& codpag, TString16& data) +{ + _pagamento = new TPagamento(codpag, data); + const real change = doc.cambio(); + real totspese = doc.spese(); + real totimposte = doc.imposta(); + real totimponibili = doc.totale_doc() - totimposte - totspese; + if (doc.in_valuta) + { + real val1 = totimponibili * change; + real val2 = totimposte * change; + real val3 = totspese * change; + _pagamento->set_total_valuta( totimponibili, totimposte, totspese, change, val1, val2 ,val3); + } + else + _pagamento->set_total( totimponibili, totimposte, totspese ); + _pagamento->set_rate_auto(); +} + +void TGenerazione_effetti::generate_bill(TDocumento& doc) // bill in inglese significa anche effetto eheheh ;-) +{ +// That's my JOB! +// Ogni rata della fattura (si parla di effetti attivi per ora) genera 1 effetto. +// con almeno una riga. +// Ad es. Se ho una fattura suddivisa in 3 rate essa generera' 3 effetti con una riga. +// Nel caso si decida di raggruppare gli effetti (vedi criteri di raggruppamento) +// avro' un effetto con tante righe quante scadenze di fattura sono raggruppabili +// Le fatture possono generare effetti solo per i seguenti tipi di pagamento: +// 2 - Tratta +// 3 - Ri.Ba. +// 5 - Paghero' +// 7 - Tratta accettata +// 8 - Rapporti interbancari diretti +// Caso mai tale insieme risultasse incompleto od errato basta solo modificare l'enum posto all'inizio del programma + + TString16 codpag(doc.get(DOC_CODPAG)); + + _cpg->put("CODTAB",codpag); + if (_cpg->read()!= NOERR) + { + _error = codpag_error; + return; + } + TString16 data(doc.get(DOC_DATAINSC)); + + if (data.empty()) + data = doc.get(DOC_DATADOC); + + const real totale_fatt = doc.totale_doc(); // Importo in valuta + if (totale_fatt > ZERO) + { + const bool valuta = doc.in_valuta(); + const real change = doc.cambio(); + + // calcolo delle scadenze + calc_pagamento(doc,codpag,data); + + CHECK(_pagamento,"Failed to create a TPagamento"); + const int numrate = _pagamento->n_rate( ); + if (numrate < 1) + { + _error = scadenze_error; + return; + } + + _efffile->last(); + // Variabili per la scrittura dell'effetto + long nprog = _efffile->get_long(EFF_NPROGTR)+1; + const long codcf = doc.get_long(DOC_CODCF); + const TString16 codval(doc.get(DOC_CODVAL)); + const TDate data_cambio = doc.get_date(DOC_DATACAMBIO); + const long codabi = doc.get_long(DOC_CODABIA); + const long codcab = doc.get_long(DOC_CODCABA); + const TString16 provv(doc.get(DOC_PROVV)); + const int anno = doc.get_int(DOC_ANNO); + const TString16 codnum(doc.get(DOC_CODNUM)); + const long nfatt = doc.get_long(DOC_NDOC); + const TDate datafatt = doc.get_date(DOC_DATADOC); + TRectype& effetto = _efffile->curr(); + TRectype& reffetto = _refffile->curr(); + real importo; + for (int i = 0; i < numrate && good(); i++) + { + if (valid_type(_pagamento->tipo_rata(i))) + { + effetto.zero(); + reffetto.zero(); + effetto.put(EFF_NPROGTR,nprog); + effetto.put(EFF_DATASCAD, _pagamento->data_rata(i)); + effetto.put(EFF_TIPOPAG,_pagamento->tipo_rata(i)); + effetto.put(EFF_ULTCLASS,_pagamento->ulc_rata(i)); + effetto.put(EFF_CODCF, codcf); + effetto.put(EFF_CODVAL, codval); + if (valuta) + { + effetto.put(EFF_CAMBIO, change); + effetto.put(EFF_DATACAMBIO,data_cambio); + } + effetto.put(EFF_CODABI,codabi); + effetto.put(EFF_CODCAB,codcab); + effetto.put(EFF_EFFCOMP,TRUE); + if (i == numrate - 1) effetto.put(EFF_ULTRATA,TRUE); + // Put sulla riga dell'effetto + reffetto.put(REFF_NPROGTR,nprog); + reffetto.put(REFF_NRIGATR,1); + reffetto.put(REFF_DATAFATT, datafatt); + reffetto.put(REFF_NRATA,i+1); + reffetto.put(REFF_PROVV,provv); + reffetto.put(REFF_ANNODOC,anno); + reffetto.put(REFF_CODNUM,codnum); + reffetto.put(REFF_NFATT,nfatt); + importo = _pagamento->importo_rata(i,FALSE); + effetto.put(EFF_IMPORTO,importo); + reffetto.put(REFF_IMPFATT,totale_fatt); + reffetto.put(REFF_IMPORTO,importo); + if (valuta) + { + importo = _pagamento->importo_rata(i,TRUE); // Importo in valuta + real totfatlit = totale_fatt*change; //Not sure about this... + effetto.put(EFF_IMPORTOVAL,importo); + reffetto.put(REFF_IMPFATTVAL,totale_fatt); + reffetto.put(REFF_IMPFATT,totfatlit); + reffetto.put(REFF_IMPORTOVAL,importo); + } + + if (_efffile->write() == NOERR && _refffile->write() == NOERR) + { + _total_bills++; + nprog++; + } + else _error = write_error; + } + } + } + + if (_pagamento) + { + delete _pagamento; + _pagamento = NULL; + } + if (good() && _can_write) + change_doc_status(doc); +} + +bool TGenerazione_effetti::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, + const TDate& data_elab) +{ + _pagamento = NULL; + _error = no_error; + _can_write = TRUE; + _total_bills = 0L; + + const int items = doc_in.items(); // Numero dei documenti in questa elaborazione + TProgind p(items,"Generazione effetti",FALSE,TRUE,1); + for (int i = 0; i < items ; i++) // Scorriamo tutti i documenti nella lista + { + generate_bill(doc_in[i]); // Genera gli effetti corrispondenti + p.setstatus(i+1); + if (!good()) + display_error(doc_in[i]); + } + + // Effettua il raggruppamento di eventuali documenti rimasti + TDocumento doc; + + if (good()) + group_bills(doc); + + // Mostra eventuali errori residui + if (!good()) + display_error(doc); + + return _can_write; +} +