#include "f9lib01.h" #include "f1lib.h" #include "f901tab.h" #include "progind.h" #include "clifo.h" #include #include "mov.h" #include "../fp/fplib.h" const char* check_str(const TString& str); //////////////////////////////////////////////////////// // TEstrazione //////////////////////////////////////////////////////// const char* TEstrazione::categoria_doc() { return ""; // todo: } const char* TEstrazione::caus_sos(const TLocalisamfile& mov, TipoIVA acquisti) { if (acquisti == iva_acquisti) { TToken_string keys(mov.get(MOV_KEYFPPRO)); fppro_db().set_keys(keys); return fppro_db().get_tipodoc(); } if (acquisti == iva_vendite) { const TDocumento doc(mov.get(MOV_DPROVV)[0], mov.get_int(MOV_DANNO), mov.get(MOV_DCODNUM), mov.get_int(MOV_DNDOC)); static TString tipo_doc_sdi; return tipo_doc_sdi = doc.tipo().tipo_doc_sdi(); } return ""; } state_fppro TEstrazione::check_fppro(int numreg) { TLocalisamfile mov(LF_MOV); mov.put(MOV_NUMREG, numreg); if (mov.read() == NOERR && check_causale(mov.get(MOV_CODCAUS))) { // Controllo se ho i riferimenti all'FPPRO e verifico che sia tutto ok const TString& keys_fppro = mov.get(MOV_KEYFPPRO); if (keys_fppro.full()) { TToken_string keys(keys_fppro, ';'); if (fppro_db().check_reg(keys, numreg)) return correct; TString err(fppro_db().get_last_error()); if (!err.empty()) error_box(err.cut(0) << "Errore durante il controllo del movimento n. " << numreg << "\n" << err); return reg_with_err; } else // Se non ho i riferimenti faccio guessing { if (fppro_db().guess_the_doc(mov)) return guessed; return no_guessed; } } return not_fa; } bool TEstrazione::check_periodo_def() const { TString query; // Controllo se ci sono estrazioni (definitive) che si sovrappongono di periodo (con lo stesso tipo) e che non siano in stato di errore // Nel caso di stato di errore e' invece possibile la ri-estrazione query << "SELECT *\nFROM F9DRD00K\n" << "WHERE " << DRD_DATAA << " >= '" << _head.dal.date2ansi() << "' AND " DRD_DATADA " <= '" << _head.al.date2ansi() << "' AND " DRD_FLAG_PD " = 'D' AND\n " DRD_STATO " <> '" D_GEST_ERR "' AND " DRD_STATO " <> '" D_WA_ERR "' AND " DRD_STATO " <> '" D_ERR_SOS "' AND " DRD_TIPODOC " = '" << _head.tipo_doc << "';"; fp_db().sq_set_exec(query); return fp_db().sq_items() == 0; } bool TEstrazione::is_doc_xml(const TLocalisamfile& mov) { const char provv = mov.get(MOV_DPROVV)[0]; const int anno = mov.get_int(MOV_DANNO); const TString& codnum = mov.get(MOV_DCODNUM); const int numdoc = mov.get_int(MOV_DNDOC); const TDocumento doc(provv, anno, codnum, numdoc); TString hfatt(20), bfatt(50), query; if (chiave_paf(doc, hfatt, bfatt)) { query << "SELECT * FROM PAF0100F WHERE P1_KEYHEADERFATT = '" << hfatt << "' AND P1_KEYBODYFATT = '" << bfatt << "';"; fp_db().sq_set_exec(query); return fp_db().sq_items() > 0; } return false; } TString& TEstrazione::drd_attr() { static TString attr; attr.cut(0) << DRD_CODSOC ", " DRD_ID_EST ", " DRD_FLAG_PD ", " DRD_DESC ", " DRD_TIPODOC ", " DRD_DATADA ", " DRD_DATAA ", " DRD_UTENTE ", " DRD_TIME ", " DRD_STATO ", " DRD_PERC; return attr; } TString& TEstrazione::drd_tovalues() const { static TString str; return str.cut(0) << "'" << _head.cod_soc << "', '" << _head.id_estr << "', '" << (_head.flag_prov ? "P" : "D") << "', '" << _head.descr << "', '" << _head.tipo_doc << "', '" << _head.dal.date2ansi() << "', '" << _head.al.date2ansi() << "', '" << _head.user << "', CURRENT_TIMESTAMP, '" << _head.stato_estr << "', '" << _head.addr_cart << "'"; } bool TEstrazione::new_extr() const { TString query; query << "INSERT INTO " F9_DRD " ( " << drd_attr() << " ) \nVALUES ( " << drd_tovalues() << " );"; bool ok = fp_db().sq_set_exec(query); ok = ok && fp_db().sq_commit(); if (!ok) write_errorsql_log(query); return ok; } bool TEstrazione::scrivi_testata_su_db() const { return new_extr(); } bool TEstrazione::export_error_list() const { TF9_dberr dberr; const vector& movs = _movs; bool ok = true; int count = 0; for (auto it = movs.begin(); it != movs.end(); ++it) { if (it->err) { #ifdef DBG if (count == 25) bool simo = true; if (it->numreg == 187680) bool simo = true; #endif dberr.add(_head.id_estr); for (int i = 1; i < 15; i++) { TString string(it->get(i)); if (i == 2 || i == 3) // Sono obbligato a far cosi' per aggiungere le date dberr.add(TDate(it->get(i))); else if (string.full()) { string.replace("'", "''"); dberr.add(string); } else dberr.add(); // Se vuoto metto NULL } if (!(ok &= dberr.send())) break; ++count; } } return ok; } TString TEstrazione::next_estr_today(char tipo) const { char estr[] = { 0,0,0,0,0,0,0,0,0 }; TString query; query << "SELECT TOP 1 " DRD_ID_EST " AS IDESTR\n" "FROM " F9_DRD "\n" "WHERE " DRD_ID_EST " LIKE '" << today.date2ansi() << "%'\n" << "ORDER BY " DRD_ID_EST " DESC"; fp_db().sq_set_exec(query); const int last_estr = fp_db().sq_items() > 0 ? real(fp_db().sq_get("IDESTR").ltrim(10)).integer() : -1; if (last_estr < -1 || last_estr == 99999999) { ofstream fout; fout.open("f9err_nextestr.txt"); if (fout.is_open()) { fout << "Errore progressivo nuova estrazione!\n" << today << "\nn:" << last_estr << "\n" << query << "\n"; fout.close(); } TString msg; fatal_box(msg << "database error: progressivo nuova estrazione. Ultima estrazione: " << last_estr); } sprintf_s(estr, 9, "%08d", last_estr + 1); return TString(estr); } void TEstrazione::write_errorsql_log(const TString& query) const { TString msg; msg << query << "\n" << fp_db().sq_get_string_error() << "\n" << fp_db().sq_get_text_error(); if (_error_sql->is_open()) *_error_sql << msg << "\n\n"; #ifdef DBG else warning_box("Impossibile aprire il file f9_TEstrazione_error_sql.txt\nper scrivere errori scrittura db."); #endif } // Public methods ///////////////////////////////////////////////////////////////////////////////////////////// void TEstrazione::add_mov(const movimento_t& movimento) { _movs.insert(_movs.end(), movimento); } void TEstrazione::aggiorna_stato() const { bool ok; do { TString query; query << "UPDATE " F9_DRD "\n" \ "SET " DRD_STATO " = '" << _head.stato_estr << "'\n" \ "WHERE " DRD_CODSOC " = '" << _head.cod_soc << "'" \ " AND " DRD_ID_EST " = '" << _head.id_estr << "'" \ " AND " DRD_FLAG_PD " = '" << _head.flag_prov << "'"; ok = fp_db().sq_set_exec(query); ok = ok && fp_db().sq_commit(); if (!ok) write_errorsql_log(query); } while (!ok && yesno_box("Impossibile aggiornare stato dell'estrazione.\nRiprovare?")); } const char* TEstrazione::diagnostica_mov() { bool ok = true; const TipoIVA tipo = get_tipoiva(); if (tipo == iva_acquisti) { // Controlli per le fatture di acquisto TProgress_monitor bar(_movs.size(), "Controllo stato movimenti di acquisto"); for (auto it = _movs.begin(); it != _movs.end(); ++it) { if (!bar.add_status()) break; movimento_t& mov_i = *it; //const int numreg = row.get_int(cid2index(F_NUMREG)); const int numreg = mov_i.numreg; switch (check_fppro(numreg)) { case guessed: ok &= fppro_db().associa_mov(numreg); //row.add(fppro_db().get_keys_fppro()); case correct: ok &= true; mov_i.state = correct; break; case not_fa: mov_i.descr_err = "Non fattura"; mov_i.state = not_fa; case reg_with_err: mov_i.descr_err = "Registrazione con errori"; mov_i.state = reg_with_err; case no_guessed: ok &= false; mov_i.err = true; // Mi segno il movimento che ha un problema mov_i.descr_err = "Non associato a fattura elettr. abbinamento automatico non riuscito. Abbinare manualmente, o escludere"; mov_i.state = no_guessed; default: break; } } } else if (tipo == iva_vendite) { // Controlli per le fatture di vendita // Vendite senza controlli. // C'e' chi se le importa da altri gestionali!!! Sad :( // Li mortacci loro! // Bisogna pensare i casi in cui le fatture sono da escludere e non le posso escludere // Ripensare esclusione vendite TProgress_monitor bar(_movs.size(), "Controllo stato movimenti di vendita"); for (auto it = _movs.begin(); it != _movs.end(); ++it) { if (!bar.add_status()) break; //TToken_string& row = *it; movimento_t& row = *it; TString numreg(row.numreg); TLocalisamfile mov(LF_MOV); mov.put(MOV_NUMREG, numreg); mov.read(); // Controllo che abbia il riferimento al documento originale generatore del movimento // todo: modificare controllo in base al flag in configurazione if (mov.get(MOV_DPROVV).empty() || mov.get(MOV_DANNO).empty() || mov.get(MOV_DCODNUM).empty() || mov.get(MOV_DNDOC).empty()) { row.err = true; row.descr_err = "Movimento non collegato a un documento originale. Impossibile estrarre. Escludere?"; ok &= false; } else if (!is_doc_xml(mov)) // Quindi controllo che sia un documento xml, se no lo metto in errore e te lo escludi a mano, se e' da escludere { row.err = true; row.descr_err = "Movimento collegato a un documento senza fatturazione elettronica. Escludere?"; ok &= false; } } } _head.stato_estr = ok ? D_GEST_OK : D_GEST_ERR; aggiorna_stato(); return _head.stato_estr; } result_estr TEstrazione::estrai() { // Se non c'e' nessun movimento non sto nemmeno a scrivere il record di estrazione. // Se estrazione definitiva controllo che il periodo non si sovrapponga alle altre estrazioni def. // Do' errore ed esco subito. if (_movs.empty()) { warning_box("Non esistono movimenti estraibili per il periodo selezionato."); return estr_stop; } if (!_escluso && !_head.flag_prov && !check_periodo_def()) { error_box("Attenzione e' stato inserito un periodo che si sovrappone\nad un'estrazione definitiva gia' esistente. Impossibile procedere."); return estr_stop; } // Non so come usare questi 18 caaratteri... // Ci metto un po' di roba anche se sono dati gia' noti in altri campi (I know..) + un numero incrementale. _head.id_estr.cut(0) << today.date2ansi() << (_head.flag_prov ? "P" : "D") << (!_escluso ? "N" : "X") << next_estr_today(_head.tipo_doc); _head.user = user(); // Eseguo controllo sui movimenti e segno in testata lo stato _head.stato_estr = IN_DIAGN; // "01" che verra' quasi subito rimpiazzato dal risultato della diagnostica. if (_escluso) set_dates(); // Se escluso imposto data inizio e fine uguali // Scrivo record estrazione in stato '01'. const bool ok = scrivi_testata_su_db(); if (!ok) { TString msg; msg << "Errore database: impossibile scrivere nuova estrazione.\n" << fp_db().sq_get_text_error(false); error_box(msg); return estr_err_db_drd; } // Faccio partire la diagnostica e mi salvo il nuovo stato. diagnostica_mov(); //_esclusi.clear(); //_esclusi.insert(_esclusi.end(), row); if (_head.stato_estr == D_GEST_ERR) { warning_box("Attenzione l'estrazione ha prodotto degli errori.\n" \ "Controllare e correggere eventuali problemi\ndal Controllo Estrazione."); // Se in errore, esporto lista errori sul db if (!export_error_list()) warning_box("Errore scrittura db. Controllare log errori."); return estr_diag_err; // Errore diagnostica gestionale } // Se va tutto ben fino a qui, posso andare a scrivere nella // tabella IVA i movimenti. return estrazione_iva() ? estr_ok : estr_err_db_iva; } bool TEstrazione::estrazione_iva(bool escluso) { bool stato = true; TString query; TProgress_monitor bar(_movs.size(), "Estrazione dati IVA"); for (auto it = _movs.begin(); it != _movs.end() && stato; ++it) { if (!bar.add_status()) break; TLocalisamfile mov(LF_MOV); TLocalisamfile cli(LF_CLIFO); mov.put(MOV_NUMREG, it->numreg); mov.read(); cli.put(CLI_TIPOCF, mov.get(MOV_TIPO)); cli.put(CLI_CODCF, mov.get(MOV_CODCF)); cli.read(); TString statopaiv; statopaiv << cli.get(CLI_STATOPAIV); TString idfisc; TString numdoc; numdoc << (mov.get(MOV_NUMDOCEXT).full() ? mov.get(MOV_NUMDOCEXT) : mov.get(MOV_NUMDOC)); if (statopaiv == "IT" || statopaiv.empty()) { idfisc << "IT"; if (cli.get(CLI_PAIV).full()) // Se non ho la partita IVA e' privato quindi non metto niente solo cod. ISO idfisc << cli.get(CLI_PAIV); } else idfisc << statopaiv << cli.get(CLI_COFI); // Esteri query.cut(0) << "INSERT INTO " F9_IVA " (\n" IVA_CODSOC ", " IVA_IDLAN ", " IVA_FLAG_PD ",\n" IVA_ANNOES ", " IVA_GIVA ", " IVA_TIPOG ",\n" IVA_DOCXML ", " IVA_TIPOCF ", " IVA_CODCF ",\n" IVA_RAGSOC ", " IVA_IDFISC ", " IVA_PIVA ",\n" IVA_CODFIS ", " IVA_CATDOC ", " IVA_CAUSSOS ",\n" IVA_NUMDOC ", " IVA_DATADOC ", " IVA_SEZIVA ",\n" IVA_TIPOREG ", " IVA_NPROT ", " IVA_DATPROT; /*if(is_autofattura(mov)) { query << ",\n" IVA_FORNOR ", " IVA_REGOR ", " IVA_NUMOR ", " IVA_DATAOR; }*/ query << ",\n" IVA_CLASDOC ", " IVA_USERELA ", " IVA_TIMEELA; if (_head.tipo_doc == 'A') { query << ",\n" IVA_TIPPROT ", " IVA_NUMPROT ", " IVA_ANNPROT ", " IVA_TIMERIC; } const long datadoc = mov.get_date(MOV_DATADOC).date2ansi(); const long datareg = mov.get_date(MOV_DATAREG).date2ansi(); const TString& name_reg = TRegistro(TCausale(mov.get(MOV_CODCAUS)).reg()).name(); query << "\n)\n" << "VALUES (\n" << "'" << _head.cod_soc << "', '" << _head.id_estr << "', '" << (_head.flag_prov ? "P" : "D") << "',\n" << "'" << mov.get(MOV_ANNOES) << "', '" << _head.tipo_doc << "', '" << name_reg << "',\n" << "'" << 'S' << "', '" << mov.get(MOV_TIPO) << "', '" << mov.get(MOV_CODCF) << "',\n" << "'" << check_str(cli.get(CLI_RAGSOC)) << "', '" << idfisc << "', '" << cli.get(CLI_PAIV) << "',\n" << "'" << cli.get(CLI_COFI) << "', '" << categoria_doc() << "', '" << caus_sos(mov, get_tipoiva()) << "',\n" << "'" << numdoc << "', '" << datadoc << "', '" << mov.get(MOV_REG) << "',\n" << "'" << "" << "', '" << mov.get(MOV_PROTIVA) << "', '" << datareg << "'"; //if (is_autofattura(mov)) //{ // query << ",\n" << // "'" << "" << "', '" << "" << "', '" << "N ORI" << "', '" << "20010101" << "'"; //} query << ",\n" << "'" << (_head.tipo_doc == 'A' ? "FTA" : "FTV") << "', '" << user() << "', " << "GETDATE()"; if (_head.tipo_doc == 'A') { TToken_string keys(mov.get(MOV_KEYFPPRO), ';'); fppro_db().set_keys(keys); query << ",\n" << "'" << fppro_db().get_tipoprot() << "', '" << fppro_db().get_numprot() << "', '" << fppro_db().get_annoprot() << "', '" << fppro_db().get_dataoraric() << "'"; } query << "\n)"; const bool ok = fp_db().sq_set_exec(query); if (!ok) write_errorsql_log(query); stato &= ok; } return stato; } void TEstrazione::set_dates() { if (_escluso) { set_dataini(_movs[0].datareg); set_dataend(_movs[0].datareg); } } TEstrazione::TEstrazione(const TString& ambiente, const bool flag_prov, const char tipodoc, const TString& descr, const TString& addrcart, const bool escluso, const TDate* const dal, const TDate* const al) : _descr(descr) { _head.cod_soc = ambiente; _head.flag_prov = flag_prov; _head.descr = descr; _head.tipo_doc = tipodoc; if (!escluso && dal != nullptr && al != nullptr) { _head.dal = *dal; _head.al = *al; } _head.addr_cart = addrcart; _escluso = escluso; _error_sql = new fstream; _error_sql->open("f9_TEstrazione_error_sql.txt"); } ////////////////////////////////////////////////////// // TF9_dberr ////////////////////////////////////////////////////// void TF9_dberr::add_str(const TString& string) { _insert.rtrim(1); if (_insert[_insert.len() - 1] != '(') _insert << ", "; _insert << string << ")"; } void TF9_dberr::write_sqlerrlog(const TString& query) const { if (_fout->is_open()) { TString msg; msg << query << "\n" << fp_db().sq_get_string_error() << "\n" << fp_db().sq_get_text_error(); *_fout << msg << "\n"; } } void TF9_dberr::add(const TString& string) { TString str; add_str(str << "'" << string << "'"); } void TF9_dberr::add(const long num) { TString app; app << num; add(app); } bool TF9_dberr::send() { fp_db().sq_set_exec(_insert); write_sqlerrlog(_insert); _insert.cut(0) << "INSERT INTO " F9_ERR " VALUES ()"; return true; } void TF9_dberr::del_err(const TString& id_estr, int numreg) { TString query; query << "DELETE FROM " F9_ERR " WHERE IDESTR = '" << id_estr << "' AND NUMREG = '" << numreg << "';"; fp_db().sq_set_exec(query); } char TF9_dberr::get_errori(const TString& id_estr, vector& controllo_mov) { TString query; query << "SELECT * FROM " F9_ERR " WHERE IDESTR = '" << id_estr << "';"; fp_db().sq_set_exec(query, false); for (bool ok = fp_db().sq_next(); ok; ok = fp_db().sq_next()) { TToken_string row("", '|'); row.add("X"); for (int i = 1; i < 15; i++) { if (fp_db().sq_get_type_field(i) == _datefld) row.add(fp_db().sq_get_date(fp_db().sq_get_name_field(i))); else row.add(fp_db().sq_get(i)); } controllo_mov.insert(controllo_mov.end(), row); } query.cut(0) << "SELECT " DRD_TIPODOC " FROM " F9_DRD "\n" << "WHERE " DRD_ID_EST " = '" << id_estr << "'"; fp_db().sq_set_exec(query); return fp_db().sq_get((unsigned)0)[0]; } TF9_dberr::TF9_dberr() { _insert.cut(0) << "INSERT INTO " F9_ERR " VALUES ()"; _fout = new ofstream; _fout->open("f9_dberr.txt"); } /////////////////////////////////////////////////////////////////////////////////////////// // TCategorie_doc /////////////////////////////////////////////////////////////////////////////////////////// vector::iterator TCategorie_doc::find(const TString& class_sost, const TString& caus_sost, const TString& op_cee) { vector::iterator a = _rows.end(); for(auto it = _rows.begin(); it != _rows.end(); ++it) { classe_doc& cd = *it; if(cd.class_sost == class_sost && cd.caus_sost == caus_sost && cd.opcee == op_cee) { a = it; break; } } return a; } void TCategorie_doc::load_all() { int idx = 0; while (true) { const TString& appo = ini_get_string(CONFIG_DITTA, "F9", "CATDOC", "", idx++); if (appo == "STOP" || appo.empty()) /* STOP: Riga terminatrice */ break; TToken_string row(appo); classe_doc cd = { row.get(1), row.get(), row.get(), row.get(), row.get(), row.get(), row.get(), row.get() }; _rows.emplace_back(cd); } } TCategorie_doc::classe_doc* TCategorie_doc::causcont2cat(const char* caus) { const TCausale c(caus); const TString& tipodoc = c.tipo_doc(); const tipo_movimento tipomov = c.tipomov(); const int reg_speciva = c.regime_speciale(); const bool op_intra = c.intra(); TString class_sost, caus_sost, op_cee; if(tipodoc == "FA") { class_sost = "FTA"; } else if(tipodoc == "FV") { class_sost = "FTV"; } else if(tipodoc == "BD") { class_sost = "FTA"; op_cee = "BD"; } if(tipomov == tm_fattura) { caus_sost = "TD01"; } else if(tipomov == tm_nota_credito) { caus_sost = "TD04"; } const vector::iterator it = find(class_sost, caus_sost, op_cee); classe_doc* cd = nullptr; if (it != _rows.end()) cd = &*it; // todo: Test it! return cd; } /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// const char* check_str(const TString& str) { static TString n_str; n_str.cut(0) << str; n_str.replace("'", "\'\'"); n_str.replace(" ", " "); return (const char*)n_str; }