#ifndef __F901001_H #define __F901001_H #include #include #include #include "strings.h" #include "date.h" #include "real.h" #include "cglib.h" #include "sheet.h" #include "sqlset.h" #include "reprint.h" #define INI_PAR_MOD "F9" #define INI_CATDOC "CATDOC" #define INI_ANNESSI "ANNCAT" #define IS_ITALIANO(statopaiv) ((statopaiv) == "IT" || !(statopaiv).full()) // Controlla eventuali apostrofi e li raddoppia const char* check_str(const TString& str); const TDate today(TODAY); struct annesso_t { TString numreg; // TString ez-pz TString filename; TString catdocpad; TString catdocann; TDate loaddate; TString user; }; struct statistics { size_t total; size_t fa_skip; size_t fa_err; size_t fa_estr; size_t fa_nocatdoc; size_t fv_cart_skip; size_t fv_err; size_t fv_estr; size_t fv_nocatdoc; }; extern statistics _stats; struct drd { TString cod_soc; TString id_estr; bool flag_prov{ true }; TString descr; char tipo_doc{ 'A' }; TDate dal; TDate al; TString user; TString timestamp; TString4 stato_estr{ "01" }; TString addr_cart; }; enum result_estr { estr_ok = 1, // Estrazione e' avvenuta senza errori. estr_err_db_iva = 0, // Errore scrittura database iva. estr_stop = -1, // Non esistono movimenti estraibili in quel periodo, o periodo sovrapposto ad altra estrazione. estr_diag_err = -2, // La diagnostica ha riportato errori. estr_err_db_drd = -99 // Errore scrittura F9DRD. }; struct return_estr { result_estr result; size_t* fa_skip; size_t* fa_total; size_t* fa_err; size_t* fv_cart_skip; size_t* fv_err; size_t* fv_estr; }; enum state_fppro { correct = 1, reg_with_err = -1, // Movimento associato male con FPPRO not_fa = -10, // Non e' fattura acquisti guessed = 100, no_guessed = 0, null_state = -100, err_read_db = 999 // Errore lettura da fppro }; class TF9_config { // todo: controllare che siano sqlsafe // Config in f90100: TString _ambiente; // Codice ambiente (codsoc) TString _addr_doc; // Indirizzo documenti cartacei WebApp (Server) TString _addr_doc_loc; // Indirizzo documenti cartacei WebApp (Locale) bool _cartexp; // Config in f90300: TString _addr_cart; // Indirizzo cartella documenti cartacei TString _estensioni; // Estensioni valide per il caricamenti dei doc. cart. public: const TString& get_ambiente() const { return _ambiente; } const TString& get_addr_doc() const { return _addr_doc; } const TString& get_addr_doc_loc() const { return _addr_doc_loc; } bool get_has_cartexp() const { return _cartexp; } const TString& get_addr_cart() const { return _addr_cart; } const TString& get_estensioni() const { return _estensioni; } void set_ambiente(const TString& cod_amb); void set_addr_doc(const TString& path); void set_addr_doc_loc(const TString& path); void set_has_cartexp(bool flag); void set_addr_cart(const TString& path); void set_estensioni(const TString& ext); TF9_config(); }; extern TF9_config F9CONF; class TCategorie_doc { public: struct classe_doc { TString catdoc; // Codice cat. documentale. TString descr; // Descrizione documento. TString class_sost; // { FTA | FTV } - classe documentale sostitutiva. TString caus_sost; // causale per sostitutiva (TD01...). TString causcont; // Codice causale. TString tipocaus; // Usato come tipo documento (FA, FV, CR, ...). }; struct annesso { TString catdocpadre; TString catdoc; // Codice cat. documentale. TString descr; // Descrizione documento. TString opcee; // { RV | DC } - Usato come classificazione annesso (Reverse, ann. cartaceo). bool obblig{ false }; // Definisce se deve essere per forza presente l'annesso. }; private: std::vector> _rows; std::vector>> _sheets_annessi; std::shared_ptr _sheet_catdocs; std::shared_ptr> _name_catdocs; int _mode_sheet; std::shared_ptr find_causcont(const TString& caus); // OK std::shared_ptr find_tipodoc(const TString& tipodoc); // OK std::vector>>::iterator find_sheet_annessi(const TString& catdoc); // OK void load_all(); void save_ann(); void save_cat(); static const char* traduci_caus_sost(const TString& caus); static const char* traduci_class_ann(const TString& class_ann); static const char* traduci_class_sost(const TString& class_sost); protected: std::map _rows_annessi; std::map::iterator find_annesso(const TString& catdoc_padre, const char* catdoc_ann); public: void add_annesso(const TString& catdoc_padre, const TString& catdoc_ann, const TString& descr, const TString& class_ann, bool obblig = false); void add_categoria(const TString& catdoc, const TString& descr, const TString& class_sost, const TString& caus_sost, const TString& causcont, const TString& tipocaus); void del_annesso(const TString& catdoc, const char* catdoc_ann); bool get_ann(const TString& catann, _Out_ annesso& _Annesso_out); TString_array get_array_ann(const TString& catdoc); TString_array get_array_rows(bool traduci = false); std::shared_ptr get_classe_doc(const TString& catdoc); std::set& get_name_catdocs() { get_sheet_catdocs(); return *_name_catdocs; } std::shared_ptr get_sheet_catdocs(); std::shared_ptr get_sheet_ann(const TString& catdoc); std::shared_ptr mov2cat(int numreg); void reload(); static void remove_all(); static void remove_all_ann(); static void remove_all_cat(); void set_mode_sheet(const int mode) { _mode_sheet = mode; } TCategorie_doc(); }; class TRecord_categorie : public TCategorie_doc { public: enum type { catdocs = 0, annessi = 1 }; private: type _table; struct recordtype { TString_array head; TToken_string record; } _categorie, _annessi; TString_array _result_set; int _next_pos{ 0 }; public: TString get(const char* field); bool next(); void put(const char* field, const char* value); bool read(bool traduci = false); TRecord_categorie(type table = catdocs); }; inline TCategorie_doc& categorie_doc() { static unique_ptr cd = nullptr; if (cd == nullptr) cd = make_unique(); return *cd; } struct movimento_t { enum err_mov { no_err, // Estratto normalmente. escluso, // Movimento con flag escluso. no_catdoc, // Nessuna cat. doc. riconosciuta per questo movimento, o non e' una fattura. no_doc, // Il mov. di vendita non ha un documento generatore. notfound_elet, // Non trovata fatt. elettronica mov vendita. no_fa, // Movimento di acquisto non e' una fattura. no_fv, // Movimento di vendita non e' una fattura. no_cartaceo, // Movimento cartaceo che non ha bisogno di essere estratto. pura_iva, // Movimento di sola IVA (integrazione Rev. Charge) no_filecart, // Il documento cartaceo non ha associato un file, o questo non e' stato trovato. annesso_nexist // Un annesso obbligatorio e' mancante. }; bool err{ false }; int numreg; TDate datareg; TDate datadoc; TString codcaus; int meseliq; TString numdoc; real tot; int codcf; TString ragsoc; TString reg_protiva; TString descr; state_fppro state{ null_state }; TString descr_err{}; // Messaggio di errore visibile dal controllo estrazione. bool estratto{ true }; err_mov descr_estr{ no_err }; // Messaggio di informazioni visibile dal 'Apri Estr.' std::shared_ptr catdoc{ nullptr }; bool cartaceo{ false }; TFilename nomefilecart{}; vector annessi{}; static const char* err_mov2name(const err_mov descr_estr) { switch (descr_estr) { case no_err: return "OK"; case escluso: return "Il movimento e' segnato come escluso. Saltato."; case no_catdoc: return "Nessuna categoria documentale riconosciuta per questo movimento, o non e' una fattura."; case no_doc: return "Il mov. di vendita non ha un documento generatore"; case notfound_elet: return "Non trovata fatt. elettronica mov vendita"; case no_fa: return "Questo movimento di acquisto non e' una fattura"; case no_fv: return "Movimento di vendita non e' una fattura."; case no_cartaceo: return "Movimento cartaceo che non ha bisogno di essere estratto"; case pura_iva: return "Movimento di sola IVA. (Le integrazioni Rev. Charge sono gestite come annessi alle vendite)"; case annesso_nexist: return "Un annesso obbligatorio e' mancante."; default: return ""; } } const char* get_descr_estr() const { return err_mov2name(descr_estr); } TString get(const int i) const { TString a; switch (i) { case 0: return err; case 1: return a << numreg; case 2: return (const char*)datareg; case 3: return (const char*)datadoc; case 4: return codcaus; case 5: return a << meseliq; case 6: return numdoc; case 7: a << tot; if (a == "0") a << ".0"; return a; case 8: return a << codcf; case 9: return ragsoc; case 10: return reg_protiva; case 11: return descr; case 14: return descr_err; default: return ""; } } bool is_cartaceo() const { return false; } // todo }; class TEstrazione : public TObject { drd _head; vector _movs; ofstream* _error_sql; bool _escluso; const TString _descr; bool _has_cartacei; TFilename _spotlite_path; /** Aggiorna stato estrazione. Utilizzato ad esempio dopo la diagnostica per riportare * il nuovo stato sul db. */ bool update_drd_stato_estr() const; static const char* caus_sos(const TLocalisamfile& mov, TipoIVA iva); static void check_annessi(movimento_t& mov_i, int numreg); // Controllo se ci sono tutti gli annessi obbligatori. // Controllo se esistono tutti gli annessi cartacei obbligatori e se ci sono annessi reverse charge li genero. static bool check_annessi_oblig(const TString& catdoc, int numreg, _Out_ TToken_string& ann_nexist); static bool check_cartaceo_acq(const movimento_t& movimento); static bool check_documento_vendita(const TLocalisamfile& mov, _Out_ bool& exist_doc); /** CHECK RIFERIMENTO FPPRO * Per le fatture di acquisto controllo se ho il riferimento nell'FPPRO. * Altrimenti cerco di capire se riesco a trovare il corrispondente del movimento * nell'FPPRO ("Guessing"). * \return \a correct se ho gia' il riferimento e corrisponde effettivamente. * \return \a reg_with_err se ho il riferimento ma la corrispondenza e' sbagliata. * \return \a guessed se non ho il riferimento ma sono riuscito a trovarlo a manina. * \return \a no_guessed se non avevo il riferimento e non sono riuscito a trovarlo. * \return \a not_fa se il movimento passato non è una fattura. */ static state_fppro check_fppro(int numreg); bool check_periodo_def() const; void copy_file_to_webapp_fld(const movimento_t& movimento) const; static void fill_id(TLocalisamfile& clifo, TString& statopaiv, TString& idfisc, TString& paiv, TString& codfis); TipoIVA get_tipoiva() const { return _head.tipo_doc == 'A' ? iva_acquisti : iva_vendite; } static bool is_doc_xml(const TLocalisamfile& mov); static bool find_movcoll(int numreg, _Out_ TString& numreg_rev_vend); static bool load_annessi(movimento_t& movimento); // Se il movimento e' di vendita e ha i riferimenti al documento generatore provo a stamparlo con ve, e lo inserisco tra i cartacei F9. static bool stampa_documento(const movimento_t& movimento, TFilename& file); bool grab_pdf_from_spotlite(const movimento_t& movimento, TFilename& file) const; public: static bool make_prosp_int_revc(int numreg, TCategorie_doc::annesso& annesso); private: static TString& drd_attr(); TString& drd_tovalues() const; bool insert_into_drd() const; /**< Scrittura testata estrazione. Tabella F9DRD. */ bool insert_into_f9movestr() const; /**< Scrittura su db dell'elenco di movimenti presi. */ bool export_error_list() const; /**< Esporta sheet controllo fatture sul db. */ /** Controlla ultimo id estrazione della giornata e in base al tipo di estrazione, * genera il progressivo seguente. Chiamata da \a estrai() e \a estrai_single(). * \return Nuovo id estrazione. */ TString next_estr_today(char tipo) const; static bool pura_iva(const TLocalisamfile& mov); void write_errorsql_log(const TString& query) const; public: void add_mov(const movimento_t& movimento); /** DIAGNOSTICA GESTIONALE. * Controllo lo stato delle fatture: * Per le fatt. acquisto non collegate a fppro cerca di agganciarle. * Le fatture di vendita devono essere collegate ad un documento originario. * Automaticamente aggiorna lo stato nella dell'estrazione, anche sul db (chiama /a aggiorna_stato()). * * \return D_GEST_OK (03) se non ci sono errori e l'estrazione puo' continuare. * \return D_GEST_ERR (02) se la diagnostica ha riportato degli errori. */ const char* diagnostica_mov(); /** Estrazione per pacchetti "normali" (non da esclusi). * Viene chiamata dall'handler estrai_handler: bottone estrai nella maschera estrazione. * * \return estr_ok (1) Se l'estrazione e' avvenuta senza errori. * \return estr_err_db_iva (0) Errore scrittura database iva. * \return estr_stop (-1) Non esistono movimenti estraibili in quel periodo, o periodo sovrapposto ad altra estrazione. * \return estr_diag_err (-2) La diagnostica ha riportato errori. * \return estr_err_db_drd (-99) Errore scrittura F9DRD. */ result_estr estrai(); /** Estrazione dati IVA sia per pacch. normali che per esclusi. Scrittura tabella F9IVA. * \param escluso Settare a true se si sta estraendo un movimento escluso (estrazione pacchetto singolo, see estrai_single()). * \return true Scrittura sul db senza errori. * \return false Errore scrittura db. */ bool estrazione_iva(bool escluso = false); bool exist_prov() const; /**< Controllo che esista per questo stesso periodo una estrazione provvisoria. */ /** Controllo se esiste un periodo antecedente a questa estrazione che non e' mai stato estratto definitivamente. */ bool gap_periodo() const; // Getters TString get_id_estr() const { return _head.id_estr; } TString4 get_stato_estr() const { return _head.stato_estr; } const vector& get_movs() const { return _movs; } // Setters void set_provvisorio(bool flag_prov) { _head.flag_prov = flag_prov; } void set_dataini(const TDate& dal) { _head.dal = dal; } void set_dataend(const TDate& al) { _head.al = al; } void set_dates(); // Solo se e' escluso void set_tipodoc(char tipodoc) { _head.tipo_doc = tipodoc; } void set_ambiente(const TString& ambiente) { _head.cod_soc = ambiente; } void set_descr(const TString& descr) { _head.descr = descr; } void set_addrcart(const TString& addrcart) { _head.addr_cart = addrcart; } TEstrazione(const TString& ambiente, bool flag_prov, char tipodoc, const TString& descr, const TString& addrcart, bool escluso, TFilename& spotlite_path, const TDate* dal = nullptr, const TDate* al = nullptr, bool has_cartacei = false); }; class TF9_dberr { TString _str; TString _insert; ofstream* _fout; protected: void add_str(const TString& string); void write_sqlerrlog(const TString& query) const; public: void add(const TString& string); void add(const TDate& date); void add(const char* string) { add(TString(string)); } void add(long num); void add() { add_str("NULL"); } bool send(); static bool del_err(const TString& codsoc, const TString& id_estr, int numreg); static char get_errori(const TString& codsoc, const TString& id_estr, vector& controllo_mov); TF9_dberr(); }; class TIva_insert_prepared_stat { vector> _fields; bool _ok{ true }; TString _query; void add_value(const char* field, const TString& value); void write(); public: void add(const char* field, const TString& str, int len = -1); void add(const char* field, const char* str, int len = -1); void add(const char* field, const TDate& date); void add(const char* field, char c); void add(const char* field, long l); void add(const char* field, const int n) { add(field, (long)n); } void add_getdate(const char* field); bool get(TString& query); void reset(); }; class TF9_doccart { TLocalisamfile _tdocs; TLocalisamfile _tannessi; public: static bool add_cart(const TFilename& file, const TString& numreg, bool is_annesso = false, const TString& catannpadre = "", const TString& catdocann = "", bool suppress_errors = true); bool doc_already_exists(const TFilename& file, _Out_ TString& numreg, _Out_ bool& annesso); bool mov2doc(const TString& numreg, _Out_ TFilename& doc); bool mov2listann(const TString& numreg, _Out_ TString_array& list_annessi); bool mov2listann_vect(const TString& numreg, _Out_ vector& list_annessi); static TString get_full_path_file_cartaceo(const TString& filename) { return TString() << TFilename(F9CONF.get_addr_cart()).slash_terminate() << filename; } TF9_doccart() : _tdocs(LF_F9DOCS), _tannessi(LF_F9ANNESSI) { } }; /////////////////////////////////////////////////////////////////////////////// // TProspetto_recset /////////////////////////////////////////////////////////////////////////////// class TProspetto_recset final : public TSQL_recordset { TString _query; TString* _numreg; TString* _today; TString* _ragsoc; TString* _address; TString* _cap; TString* _citta; TString* _provin; TString* _codfisc; TString* _partiva; TString* _ndoc; TString* _datadoc; TString* _totdoc; TString* _codforn; TString* _ragsocforn; TString* _addrforn; TString* _capforn; TString* _cittaforn; TString* _provinforn; TString* _partivaforn; TString* _regacq; TString* _protivaacq; TString* _dataregacq; TString* _totale; TString* _totimponibile; TString* _totimposta; static void format_string(TString& str_out, const TString& str) { str_out.cut(0) << "'" << check_str(str) << "'"; } static void format_string(TString& str_out, const char* str) { format_string(str_out, TString(str)); } static void format_string(TString& str_out, const TDate& date) { TString dt; dt << date.date2ansi(); format_string(str_out, dt); } void precarica_tabelle(); public: const TString& get_query() const { return _query; } static void get_sum_imponibile_imposta(const char* numreg_ven, real& s_imponibili, real& s_imposte); TProspetto_recset(const char* numreg_acq, const char* numreg_ven); ~TProspetto_recset(); }; class TF9Prospetto_integr { static constexpr const char* _name = "f9ProspIntegr"; TReport_book _book; const TFilename _f_report; TRecnotype _items; TReport _rep; static TFilename get_path_rep(); public: bool export_pdf(TFilename& tmp); const char* make_name_rep(); bool preview(); const TFilename& filename() const { return _rep.filename(); } bool operator()(const char* numreg_acq, const char* numreg_ven); TF9Prospetto_integr(); }; #endif // #ifndef __F901001_H