#include "tf0.h" #include "tf0100b.h" #include "../fp/fplib.h" /* Utilities & Main App */ ///////////////////////////////////////////////////////////////////////////////////// // Utilities ///////////////////////////////////////////////////////////////////////////////////// // Le funzioni quelle belle TString get_tipo_doc(int id) { TString ret; switch(id) { case B_TIPO_AUTOFATT: ret = "AF"; break; case B_TIPO_FATTACQ: ret = "FA"; break; case B_TIPO_FATTFISC: ret = "FF"; break; case B_TIPO_FATTVEN: ret = "FV"; break; case B_TIPO_NOTC: ret = "NC"; break; case B_TIPO_NOTD: ret = "ND"; break; case B_TIPO_STORDOC: ret = "ST"; break; case B_TIPO_BOLLADOG: ret = "BD"; break; case B_TIPO_FATTSCO: ret = "FS"; break; case B_ESTEROMETRO: ret = "ESTER"; break; case B_PAF_NOT_SENT: ret = "PAF_NS"; break; case B_PAF_SENT: ret = "PAF_S"; break; case B_PAF_SOG_FAT: ret = "PAF_SF"; break; case B_PAF_ESTERI: ret = "PAF_E"; break; case B_PAA_NOT_SENT: ret = "PAA_NS"; break; case B_PAA_SENT: ret = "PAA_S"; break; case B_PAA_ESTERI: ret = "PAA_E"; break; case B_PAA_SOG_FAT: ret = "PAA_SF"; break; default: ret = "ERR"; break; } return ret; } int get_tipo_doc(const TString id) { int ret = -1; if(id == "AF") ret = B_TIPO_AUTOFATT; else if(id == "BD") ret = B_TIPO_BOLLADOG; else if(id == "FA") ret = B_TIPO_FATTACQ; else if(id == "FF") ret = B_TIPO_FATTFISC; else if(id == "FS") ret = B_TIPO_FATTSCO; else if(id == "FV") ret = B_TIPO_FATTVEN; else if(id == "NC") ret = B_TIPO_NOTC; else if(id == "ND") ret = B_TIPO_NOTD; else if(id == "ST") ret = B_TIPO_STORDOC; return ret; } // Cerca una stringa all'interno di una SLIST (Potrebbe diventare una funzione di XVT.h) //static SLIST_ELT xvt_slist_find_str(SLIST list, const char* str) //{ // SLIST_ELT e = NULL; // for (e = xvt_slist_get_first(list); e; e = xvt_slist_get_next(list, e)) // { // const char* val = xvt_slist_get(list, e, NULL); // if (xvt_str_compare_ignoring_case(str, val) == 0) // break; // } // return e; //} // Aggiorna il file dst se più vecchio di src (Potrebbe diventare una funzione di XVT.h) //bool xvt_fsys_fupdate(const char* src, const char* dst) //{ // bool ok = false; // if (xvt_fsys_file_exists(src)) // { // const long tsrc = xvt_fsys_file_attr(src, XVT_FILE_ATTR_MTIME); // if (tsrc > 0) // { // long tdst = 0; // if (xvt_fsys_file_exists(dst)) // tdst = xvt_fsys_file_attr(dst, XVT_FILE_ATTR_MTIME); // if (tsrc > tdst) // ok = xvt_fsys_fcopy(src, dst) != 0; // } // } // // return ok; //} /* Ritorno il tipo di documento * TD01: Fattura * TD04: Nota di credito * TD05: Nota di debito * NO-> TD07: Fattura semplificata * NO-> TD08: NC semplificata * TD10: Fatt di acquisto intra beni * TD11: Fatt di acquisto intra servizi */ const char* decod_tipo(TToken_string & strarr) { const TString tipodoc = strarr.get(_codnum); TRectype mov = cache().get(LF_MOV, strarr.get(_numero)); TCausale caus = cached_causale(mov.get("CODCAUS"), mov.get_int("ANNOIVA")); // Le autofatture possono essere solo di tipo TDO1 e le bolle doganali nel dubbio pure if(tipodoc == "AF" || tipodoc == "BD" || tipodoc == "FF" || tipodoc == "FV" || tipodoc == "FS") return "TD01"; else if(tipodoc == "FA") { // Potrebbe essere normale o intra if(!caus.intra()) return "TD01"; else { // Controlliamo se è di beni o servizi // Per capire se sono beni o servizi devo prendere il movimento, e trovare quale dei due ha un importo più alto TAssoc_array intraval; TRelation r_moviva(LF_RMOVIVA); TRectype filter(r_moviva.curr()); filter.put("NUMREG", strarr.get(_numero)); TCursor c_moviva(&r_moviva, "", 1, &filter, &filter); for(c_moviva = 0; c_moviva.pos() < c_moviva.items(); ++c_moviva) { TRectype row = c_moviva.curr(); real importo = row.get_real("IMPONIBILE"); // La chiave deve essere formata da CODIVA, GRUPPO + CONTO + SOTTOCONTO TToken_string keyAssoc = row.get("CODIVA"); keyAssoc.add(row.get("GRUPPO")); keyAssoc.add(row.get("CONTO")); keyAssoc.add(row.get("SOTTOCONTO")); real *imp = (real*) intraval.objptr(keyAssoc); if (imp == nullptr) intraval.add(keyAssoc, imp = new real); *imp += importo; } // Adesso che ho tutti i totali divisi per CODIVA e GCS vado a pescare il valore maggiore TToken_string keyMax; real max; TString_array keys; intraval.get_keys(keys); for(int i = 0; i < keys.items(); i++) { const TToken_string & key = keys.row(i); real imp = *((real *) intraval.objptr(key)); if(imp > max) { keyMax = key; max = imp; } } // Una volta che ho trovato il nostro vincitore vado a prendere il tipo di fattura dal GCS TToken_string key_p_con = keyMax; key_p_con.destroy(0); if(cache().get(LF_PCON, key_p_con, "RICSER") == "1") return "TD11"; else return "TD10"; } } else if(tipodoc == "NC") return "TD04"; else if(tipodoc == "ND") return "TD05"; else if(tipodoc == "ST") { // Devo capire a che documento è associato TRelation r(LF_RMOV); TRectype filter(r.curr()); filter.put("NUMREG", strarr.get(_numero)); TCursor c(&r, "", 1, &filter, &filter); for(c = 0; c.pos() < c.items(); ++c) { TRectype r = c.curr(); if(r.get("TIPOC") == "C") { if(r.get("SEZIONE") == "D") return "TD01"; else return "TD04"; } else if(r.get("TIPOC") == "F") { if(r.get("SEZIONE") == "A") return "TD01"; else return "TD04"; } } } // Nel caso ritorno un valore che da errore return "ERR0"; } /* Salvo il record modificato in TFCustom */ bool save_rec(TToken_string row, const bool esportato) { static TLocalisamfile trasfatt(LF_TRASFATT); static TLocalisamfile mov(LF_MOV); static TString invio; invio.cut(0); static TString key; key.cut(0) << row.get(_numero) << "|"<< row.get(_aliquota); TRectype r_cust = cache().get(LF_TRASFATT, key); // Se la riga non esiste metto la chiave if(r_cust.empty()) { r_cust.put("NUMREG", row.get(_numero)); } r_cust.put("TIPO", row.get(_tipocf)); r_cust.put("CODCF", row.get(_codcf)); r_cust.put("OCCAS", row.get(_occas)); r_cust.put("TIPODOC", row.get(_codnum)); r_cust.put("TIPODOCAE", row.get(_codnumAE)); r_cust.put("NUMDOC", row.get(_numdoc)); r_cust.put("DATAREG", row.get(_datareg)); r_cust.put("DATADOC", row.get(_datadoc)); r_cust.put("IMPONIBILE", row.get(_imponibile)); r_cust.put("IMPOSTA", row.get(_importoIVA)); r_cust.put("CODIVA", row.get(_aliquota)); r_cust.put("NATURA", row.get(_natura)); r_cust.put("AUTOFATT", row.get(_autofatt)); if(esportato) { invio << "I"; r_cust.put("TFDATA", TDate(TODAY)); } else { invio << row.get(_invio); } r_cust.put("TFINVIO", invio); return r_cust.write_rewrite(trasfatt) == NOERR; } inline const char * no_special(const char a) { if(a == 'à') return "a''"; else if(a == 'è' || a == 'é') return "e''"; else if(a == 'ì') return "i''"; else if(a == 'ò') return "o''"; else if(a == 'ù') return "u''"; // Se non trovo nulla lo tolgo return ""; } TTrFa_mask& msk() { static TTrFa_mask* msk = nullptr; if (msk == nullptr) msk = new TTrFa_mask("tf0100a"); return *msk; } ///////////////////////////////////////////////////////////////////////////////////// // TTrFa_record ///////////////////////////////////////////////////////////////////////////////////// // Imposta il valore di un campo variant void TTrFa_record::set(const char* fld, const TVariant& var) { CHECK(fld && *fld, "Null field name"); if (var.is_null()) { _fields.remove(fld); } else { TVariant* obj = (TVariant*)_fields.objptr(fld); if (obj != NULL) *obj = var; else _fields.add(fld, new TVariant(var)); } } // Imposta il valore di un campo intero void TTrFa_record::set(const char* fld, long val) { const TVariant var(val); set(fld, var); } // Imposta il valore di un campo stringa void TTrFa_record::set(const char* fld, const char* val) { if (val == NULL) set(fld, NULL_VARIANT); else { const TVariant var(val); set(fld, var); } } // Imposta il valore di un campo stringa void TTrFa_record::set(const char* fld, const TString& val) { const TVariant var(val); set(fld, var); } // Imposta il valore di un campo numerico void TTrFa_record::set(const char* fld, const real& val) { const TVariant var(val); set(fld, var); } // Imposta il valore di un campo data in formato ISO void TTrFa_record::set(const char* fld, const TDate& val) { if (val.ok()) { const TVariant var(val); set(fld, var); } else set(fld, ""); } // Imposta il valore di un campo booleano void TTrFa_record::set(const char* fld, bool var) { set(fld, var ? "SI" : "NO"); } // Legge il valore di un campo variant const TVariant& TTrFa_record::get(const char* fld) const { const TVariant* var = (const TVariant*)_fields.objptr(fld); return var ? *var : NULL_VARIANT; } // Converte un variant in una stringa valida per SQLite const TString& TTrFa_record::var2str(const TString& fldname, const TVariant& var) const { const TFieldtypes vt = var.type(); if (vt == _realfld) { const real r = var.as_string(); TString& tmp = get_tmp_string(); tmp << '\'' << r.string() << '\''; return tmp; } if (vt == _datefld) { TString& tmp = get_tmp_string(); tmp << '\'' << var.as_date().string(full, '-', full, full, amg_date) << '\''; return tmp; } const TString& str = var.as_string(); bool apici = vt == _alfafld; if (apici && str[0] != '0' && real::is_natural(str)) apici = false; if (!apici) return str; TString& tmp = get_tmp_string(); TString& tmp2 = get_tmp_string(); tmp = str; TString speciali = CARATTERI_SPECIALI; for(int i = 0; i < speciali.len(); i++) { for (int a = str.rfind(speciali[i]); a >= 0; a--) { if (tmp[a] == speciali[i]) { tmp2.cut(0) << tmp.left(a) << no_special(speciali[i]) << tmp.mid(a+1); tmp = tmp2; } } } for (int a = str.rfind('\''); a >= 0; a--) { if (tmp[a] == '\'') tmp.insert("'", a); } tmp.insert("'", 0); tmp << '\''; return tmp; } // Elimina il record in base ai campi chiave bool TTrFa_record::remove() { TString256 query; query << "DELETE FROM " << _table << " WHERE "; int nkf = 0; FOR_EACH_TOKEN(_key, fld) { const TVariant& var = get(fld); if (!var.is_null()) { if (nkf++ > 0) query << " AND "; query << fld << '=' << var2str(fld, var) ; } } CHECKS(nkf >= 2, "Can't remove partial key on table ", (const char*)_table); query << ';'; return xvt_sql_execute(_db, query, NULL, 0L) > 0; } // Callback per la sottostante funzione search() static int tff_search_record(void* jolly, int cols, char** values, char** names) { TTrFa_record& rec = *(TTrFa_record*)jolly; for (int i = 0; i < cols; i++) rec.set(names[i], values[i]); return 0; } // Carica un record in base ai campi chiave bool TTrFa_record::search() { CHECKS(_fields.items() >= _key.items(), "Can't search partial key on table ", _table); TString256 query; query << "SELECT * FROM " << _table << " WHERE "; FOR_EACH_TOKEN(_key, fld) { const TVariant& var = get(fld); if (!var.is_null()) query << fld << '=' << var2str(fld, var) << " AND "; } query.rtrim(5); query << ';'; return xvt_sql_execute(_db, query, tff_search_record, this) == 1; } // Carica un record in base ad un massimo di 3 campi chiave bool TTrFa_record::search(const char* k1, const char* k2, const char* k3) { _fields.destroy(); set(_key.get(0), k1); if (k2 && *k2) set(_key.get(1), k2); if (k3 && *k3) set(_key.get(2), k3); return search(); } // Aggiunge un record al db bool TTrFa_record::insert() { CHECKS(_fields.items() > _key.items(), "Can't insert empty record on table ", _table); TString query, values; query << "INSERT INTO " << _table << "\n("; FOR_EACH_ASSOC_OBJECT(_fields, obj, fld, itm) { const TVariant& var = get(fld); if (!var.is_null()) { query << fld << ','; values << var2str(fld, var) << ','; } } query.rtrim(1); values.rtrim(1); query << ")\nVALUES (" << values << ");"; return xvt_sql_execute(_db, query, NULL, 0L) == 1; } // Crea un record della tabella data ed imposta i nomi dei campi chiave TTrFa_record::TTrFa_record(const char* table) : _table(table), _key(15, ',') { _key = ini_get_string("./tff.ini", table, "INDEX_1"); if (_key.empty()) { // Cerco di costruire i nomi della chiave cercando la K, come in P1_KEYHEADERFATT TConfig cfg("tff.ini", table); TAssoc_array& fields = cfg.list_variables(); FOR_EACH_ASSOC_STRING(fields, obj, key, str) { if (key[3] == 'K') _key.add(key); } } CHECKS(!_key.empty_items(), "Invalid primary key for table ", table); } ///////////////////////////////////////////////////////////////////////////////////// // TTrFa_app ///////////////////////////////////////////////////////////////////////////////////// void TTrFa_app::log(int severity, const char* msg) { if (severity < 0) { _log_tff = msg; } else if (_log == NULL) { _log = new TLog_report; if (_log_tff.full()) { TString txt; txt << _log_tff << ": " << msg; _log->log(severity, txt); } else _log->log(severity, msg); } } bool TTrFa_app::display_log() { bool ok = true; if (_log) { _log->preview(); safe_delete(_log); ok = noyes_box(TR("Si desidera procedere con la generazione file xml?")); } return ok; } int TTrFa_app::parse_line(const TString& line, TString& var, TString& val) const { if (line.blank()) return 0; if (line[0] == '[') { var = line.mid(1); var.rtrim(1); val.cut(0); return 1; } const int equal = line.find('='); if (equal < 6) return 0; var = line.left(equal); var.trim(); val = line.mid(equal+1); val.trim(); return 2; } bool TTrFa_app::create_table(TScanner& tff, const TString& table) { TString query, var, val; bool modified = false; TToken_string field_list("", ','); const bool new_table = !xvt_sql_table_exists(_db, table); streampos cur_pos = tff.pos(); if (!new_table) { SLIST fields = xvt_sql_list_fields(_db, table); while (!modified && !tff.eof()) { const TString& line = tff.line(); const int n = parse_line(line, var, val); if (n <= 0) break; if (var.starts_with("INDEX_")) break; if (xvt_slist_find_str(fields, var) == NULL) { modified = true; } else modified = (val != xvt_sql_field_type(_db, table, var)); } if (modified) { const int nfields = xvt_slist_count(fields); for (SLIST_ELT field = xvt_slist_get_first(fields); field != nullptr; field = xvt_slist_get_next(fields, field)) field_list.add(field->str); } xvt_slist_destroy(fields); if (modified) { query = "ALTER TABLE "; query << table << " RENAME TO " << table << "_OLD;"; xvt_sql_execute(_db, query, NULL, NULL); // rename table table query = "DROP INDEX "; query << table << "_1;"; xvt_sql_execute(_db, query, NULL, NULL); // rename table table tff.setpos(cur_pos); } } if (new_table || modified) { query = "CREATE TABLE "; query << table << " ("; while (!tff.eof()) { const TString& line = tff.line(); const int n = parse_line(line, var, val); if (n <= 0) break; if (n == 1) { tff.push(line); break; } if (var.starts_with("INDEX_")) { query.rtrim(1); // toglie ultima , query << ");"; xvt_sql_execute(_db, query, NULL, NULL); // Create table query = "CREATE UNIQUE INDEX "; query << table << "_1 ON " << table << " (" << val << ");"; xvt_sql_execute(_db, query, NULL, NULL); // Create index break; } else { query << "\n " << var << ' ' << val << " NOT NULL"; if (val.find("INT") >= 0 || val.find("NUM") >= 0) query << " DEFAULT 0"; else query << " DEFAULT ''"; query << ","; } } if (modified) { query = "INSERT INTO "; query << table << "(" << field_list << ") SELECT " << field_list << " FROM " << table << "_OLD;"; xvt_sql_execute(_db, query, NULL, NULL); // rename table table query = "DROP TABLE "; query << table << "_OLD;"; xvt_sql_execute(_db, query, NULL, NULL); // rename table table } } return true; } bool TTrFa_app::create() { open_files(LF_MOV, LF_RMOV, LF_RMOVIVA, LF_TABCOM, LF_ANAG, LF_CLIFO, LF_OCCAS, LF_CFVEN, LF_NDITTE, 0); // Controllo preventivo dell'avvenuta conversione del tracciato record TRectype rmoviva(LF_RMOVIVA); //if (rmoviva.type("TFINVIO") != _boolfld) //return error_box(TR("Database non convertito per il Trasferimento Elettronico")); _ditta.init(LF_NDITTE, prefix().get_codditta()); _dbname = prefix().get_studio(); // base direcotry _dbname.add("sql"); make_dir(_dbname); TString16 d; d.format("TF%05ld.db", prefix().get_codditta()); _dbname.add(d); bool create = !_dbname.exist(); _db = xvt_sql_open(_dbname, user(), "", _dbname.path()); if (_db == NULL) return false; // Questa funzione crea/verifica il DB verify_db(create); // Setto se ha il modulo FP msk().set_has_fp(has_module(FPAUT)); return TSkeleton_application::create(); } // Sincronizzo il DB SQL con quello di campo bool TTrFa_app::syncronize_db() { //xvt_sql_begin(_db); return true; } bool TTrFa_app::verify_db(const bool create) { const TFilename ini = "tff.ini"; bool ok = ini.exist(); if (ok) { xvt_sql_begin(_db); TScanner tff(ini); while (ok && !tff.eof()) { const TString& p = tff.line(); if (p.starts_with("[TF") && p.ends_with("F]")) { TString16 table = p; table.strip("[]"); ok = create_table(tff, table); } } if(ok && create) { // Aggiungo il valore di default in TFNUM TTrFa_record tfnum("TFNUM00F"); tfnum.set("PJNKEY", "00001"); tfnum.set("PJNINV", "0000000000"); ok = tfnum.insert(); } if (ok) xvt_sql_commit(_db); else { xvt_sql_rollback(_db); fatal_box("Fallita la creazione/aggiornamento del Database"); } } else return cantread_box(ini); return true; } bool TTrFa_app::copy_ssa() { TFilename tmp; // Copia eventuali protezioni software TString_array files; if (list_files(SPESOMETROBASE "/*.ssa", files) == 0) { list_files("*.ssa", files); FOR_EACH_ARRAY_ROW(files, i, row) { tmp = SPESOMETROBASE; tmp.add(*row); xvt_fsys_fupdate(*row, tmp); } } files.destroy(); if (list_files(SPESOMETROBASE "/*.ssa", files) != 1) { warning_box(FR("Nella cartella %s deve essere presente un file .ssa, ModuliSirio non è abilitato."), SPESOMETROBASE); } TFilename home; xvt_sys_get_env("USERPROFILE", home.get_buffer(), home.size()); home.add("SoftwareSirio"); home.add(SPESOMETROBASE); if (!dexist(home)) make_dir(home); return true; } bool TTrFa_app::send(TTrFa_mask* msk) { // Controllo se è la prima esecuzione, in caso positivo chiedo se vuole controllare p.iva e cf const bool first = ini_get_bool(CONFIG_DITTA, "tf", "FirstExec", true); if(first) { ini_set_bool(CONFIG_DITTA, "tf", "FirstExec", false); if(yesno_box("Stai eseguendo il programma per la prima volta,\nvuoi controllare di avere tutti i Codici Fiscali e Partite IVA corrette?")) { TExternal_app check_app("cg1 -2 L"); check_app.run(); if(!yesno_box("Desideri proseguire con l'esportazione?")) { return false; } } } // Mi carico i miei dati TSheet_field& sheet = msk->sfield(F_RIGHE); // Booleano per appendere i record nel db /*********************************************************************************************** * Esporto ***********************************************************************************************/ xvt_sql_begin(_db); // Eseguo l'esportazione bool ok = tff0100(sheet) && tff0400(sheet) && tff0700(sheet); if(!ok) { log(-1, "WTF!?"); xvt_sql_rollback(_db); message_box("Esportazione fallita"); return false; } if(xvt_sql_commit(_db)) { message_box("Ho esportato correttamente!"); // Imposto l'esportazione if(yesno_box("Vuoi segnare i record esportati?")) { if(set_esportato(sheet)) message_box("Record segnati correttamente!"); else message_box("Ci sono stati degli errori durante la riscrittura dei records"); msk->set_filter_changed(); } } else message_box("Errore durante il salvataggio delle modifiche"); return true; } TString TTrFa_app::get_key(TToken_string* strarr) { return strarr->get_char(_tipocf) == 'C' ? DTE_PROVV : DTR_PROVV; } TString TTrFa_app::get_header(TToken_string* strarr) { /* Devo crearmi una struttura dove immagazzino delle strutture di clienti e all'interno ci metto i numeratori che mi chiedono * Così facendo mando a puttane persino l'append che potevo tranquillamente implementare prima e creare fastidiose query per capire dove cazzo sto */ // Chiave header (20): TIPOCF(1) + CODCF(6) static long int id_header = 0L; // Cerco/Aggiungo il Clifo all'std::map static TString key_map; key_map.cut(0); static TString tipocf, codcf, occas; tipocf.cut(0); codcf.cut(0); occas.cut(0); // Controlli per bolladog if(strcmp(strarr->get(_codnum),"BD") == 0) { tipocf = "F"; codcf = cache().get(LF_MOV, strarr->get_long(_numero), "CFBOLLADOG"); if(codcf.blank()) codcf.cut(0) << strarr->get(_codcf); } else { tipocf << strarr->get_char(_tipocf); codcf << strarr->get(_codcf); occas << strarr->get(_occas); } key_map << tipocf << "|" << codcf << "|" << occas; clifo_doc app; // Non è presente e lo inserisco per la chiave body if(_m_cli_doc.find(key_map) == _m_cli_doc.end()) { id_header++; app._cont_cli_fo = id_header; app._count_doc = 0L; _m_cli_doc.insert(std::pair(key_map, app)); } static TString header; static TString format_string; format_string.cut(0) << "%c%0"; if(occas.blank()) { format_string << 13 - codcf.len() << "d"; header.format(format_string, tipocf[0], 0); header << codcf; // Perchè cazzo non va il %s!? } else { format_string << 13 - occas.len() << "d"; header.format(format_string, 'O', 0); header << occas; } // Ritorno l'header return header; } TString TTrFa_app::get_body(TToken_string* strarr, bool add) { /* Sembra che utilizzare identificatori chiari e sensati in questo mondo non è concesso, quindi adesso vi sbatto un bell'ID numerico * Ok per OGNI cliente devo assegnarli un identificativo del numero della fattura */ static TString key_map; key_map.cut(0) << strarr->get_char(_tipocf) << "|" << strarr->get_int(_codcf) << "|" << strarr->get(_occas); clifo_doc app = _m_cli_doc[key_map]; static TString num_doc; num_doc.cut(0) << strarr->get(_numdoc) << "|" << TDate(strarr->get(_datadoc)).year(); if(add) { app._count_doc += 1; app._doc_id.insert(std::pair(num_doc, app._count_doc)); } _m_cli_doc[key_map] = app; static TString body; body.format("%07d%07d", app._cont_cli_fo, app._doc_id[num_doc]); return body; } bool TTrFa_app::tff0100(TSheet_field& sheet) { const char* const paese = "IT"; static const TFirm& firm = prefix().firm(); // Controllo la presenza di clienti e fornitori // Scandisco in maniera ignorante sperando di beccare subito un cliente e un fornitore bool cli = false, fo = false; FOR_EACH_SHEET_ROW(sheet, r, strarr) { IF_IS_ENABLED(strarr); if(strarr->get_char(_tipocf) == 'C') cli = true; else fo = true; if(cli || fo) break; } bool ok = false; if(cli) { ok = true; TTrFa_record dte("TFF0100F"); // Controllo la presenza di un caricamento in attesa if(dte.search(DTE_PROVV)) { const bool sent = dte.get("P1_KEYPRGINVIO").as_string() == DTE_PROVV; if(sent) { static const TString msg = "É presente un'altra esportazione non ancora elaborata vuoi eliminarla?"; if(yesno_box(msg)) { if(!empty_tables(DTE_PROVV)) { error_box("Fallita eliminazione record!!!"); return false; } } else return false; } } dte.set("P1_KEYPRGINVIO", DTE_PROVV); dte.set("P1_TRASMITTPAESE", paese); dte.set("P1_TRASMITTCOD", ""); dte.set("P1_TIPOINVIO", "DTE"); dte.set("P1_GESTIONE", ""); ok = dte.insert(); if(!ok) return false; ok = tff0200(DTE_PROVV); if(!ok) return false; } if(fo) { ok = true; TTrFa_record dtr("TFF0100F"); // Controllo la presenza di un caricamento in attesa if(dtr.search(DTR_PROVV)) { const bool sent = dtr.get("P1_KEYPRGINVIO").as_string() == DTR_PROVV; static const TString msg = "É presente un'altra esportazione non ancora elaborata vuoi eliminarla?"; if(sent) { if(yesno_box(msg)) { if(!empty_tables(DTR_PROVV)) { error_box("Fallita eliminazione record!!!"); return false; } } else return false; } } dtr.set("P1_KEYPRGINVIO", DTR_PROVV); dtr.set("P1_TRASMITTPAESE", paese); dtr.set("P1_TRASMITTCOD", ""); dtr.set("P1_TIPOINVIO", "DTR"); dtr.set("P1_GESTIONE", ""); ok = dtr.insert(); if(!ok) return false; ok = tff0200(DTR_PROVV); if(!ok) return false; } return ok; } bool TTrFa_app::tff0200(const TString& key) { /******************************************************************************************************************** * Cedeprest * ********************************************************************************************************************/ // TTrFa_record tff0200f("TFF0200F"); tff0200f.set("P2_KEYPRGINVIO", key); if (_ditta.partita_IVA().full()) { tff0200f.set("P2_FISCIVAPAESE", _ditta.stato_partita_IVA()); // Sempre IT tff0200f.set("P2_FISCIVACOD", _ditta.partita_IVA()); } tff0200f.set("P2_CODFISCALE", _ditta.codice_fiscale()); if (_ditta.fisica()) { tff0200f.set("P2_ANANOME", _ditta.nome()); tff0200f.set("P2_ANACOGNOME", _ditta.cognome()); } else { tff0200f.set("P2_ANADENOMIN", _ditta.ragione_sociale()); } // DatiSede TString via = _ditta.via_residenza(), cap = _ditta.CAP_residenza(), nazione = _ditta.stato_residenza_ISO(); // Valori necessari, se non ci sono salto if(via.full() && cap.full() && nazione.full()) { tff0200f.set("P2_SEDEIND", via); tff0200f.set("P2_SEDENRCIVICO", _ditta.civico_residenza().left(7)); tff0200f.set("P2_SEDECAP", cap); tff0200f.set("P2_SEDECOMUNE", _ditta.comune_residenza()); if(_ditta.italiano()) // Campo ritornerebbe "EE" se estero tff0200f.set("P2_SEDEPROV", _ditta.provincia_residenza()); tff0200f.set("P2_SEDENAZ", nazione); } _myrfso = ""; if(have_rfso(_myrfso)) { TRectype r_ana = cache().get(LF_ANAG, TString(_myrfso.left(1)) << "|" << _myrfso.sub(1)); if(r_ana.get_char("TIPORFSO") == 'S') // Stabile Organizzazione { TAnagrafica rfso(r_ana); TString via = rfso.via_residenza(), cap = rfso.CAP_residenza(), nazione = rfso.stato_residenza_ISO(); tff0200f.set("P2_STABORGIND", via); tff0200f.set("P2_STABORGNRCIVICO", rfso.civico_residenza().left(7)); tff0200f.set("P2_STABORGCAP", cap); tff0200f.set("P2_STABORGCOMUNE", rfso.comune_residenza()); if(rfso.italiano()) tff0200f.set("P2_STABORGPROV", rfso.provincia_residenza()); tff0200f.set("P2_STABORGNAZ", nazione); } else // Rappresentante Fiscale { bool ok = tff0300(key, r_ana); if(!ok) return false; } } tff0200f.set("P2_GESTIONE", ""); return tff0200f.insert(); } bool TTrFa_app::tff0300(TString key, TRectype r_ana) { // Il copy constructor non è accessibile (e non sarò io a modificarlo) TAnagrafica rfso(r_ana); // Per il nome e cognome non mi faccio gli stessi problemi con i cli/fo in quanto stiamo parlando di cose "nuove" // Se il cliente ha messo nome e cognome insieme può bruciare nelle fiamme dei controlli dell'agenzia delle entrate TString paiv = rfso.partita_IVA(), ragsoc = rfso.ragione_sociale(), nom = rfso.nome(), cog = rfso.cognome(); TTrFa_record tff0300f("TFF0300F"); tff0300f.set("P3_KEYPRGINVIO", key); tff0300f.set("P3_FISCIVAPAESE", rfso.stato_residenza_ISO()); tff0300f.set("P3_FISCIVACODICE", paiv); if(r_ana.get_char("TIPOA") == 'G') { tff0300f.set("P3_ANADENOMI", ragsoc); } else { TString nomCom = r_ana.get("RAGSOC"); tff0300f.set("P3_ANANOME", nom); tff0300f.set("P3_ANACOGNOME", cog); } tff0300f.set("P3_GESTIONE", "D"); return tff0300f.insert(); } bool TTrFa_app::tff0400(TSheet_field& sheet) { // Siccome non siamo in grado di fare delle join devo in qualche modo evitare di caricare clienti già caricati quindi mi salvo tutto in un bel TToken_string e controllo // Era troppo complicato fare una join codice cliente con i documenti per prendere solo quelli valorizzati. std::map clifoSent; bool ok = true; TProgress_monitor p(sheet.items(),"Caricamento Clienti/Fornitori"); FOR_EACH_SHEET_ROW(sheet, r, strarr) { if(!p.add_status()) return false; IF_IS_ENABLED(strarr); static TString checkClifo; checkClifo.cut(0); // Per le bolle doganali devo fare sempre questo giro bool found_bolla = strcmp(strarr->get(_codnum),"BD") == 0, found_bolla_cli = false; static TString cfbolladog; if(found_bolla) { // Attenzione! Se è una riga inserita a mano dall'utente prendo lo stesso il fornitore della riga! cfbolladog = strarr->get_int(_numero) < MOV_CUSTOM ? cache().get(LF_MOV, strarr->get_long(_numero), "CFBOLLADOG") : strarr->get(_codcf); if(!cfbolladog.blank()) { found_bolla_cli = true; checkClifo << "F" << cfbolladog; } } if(!found_bolla_cli) { static TString tempOcfpi; tempOcfpi.cut(0) << strarr->get(_occas); if(tempOcfpi.blank()) checkClifo << strarr->get_char(_tipocf) << "|" << strarr->get_long(_codcf); else checkClifo << strarr->get_char(_tipocf) << "|" << strarr->get(_occas); } // Controllo il clifo, se non c'è lo aggiungo altrimenti salto sto giro if(clifoSent.find(checkClifo) == clifoSent.end()) clifoSent.insert(std::pair(checkClifo,true)); else continue; TVariant vtipocf = strarr->get(_tipocf), vcodcf = strarr->get(_codcf), voccas = strarr->get(_occas); #ifdef DBG if(vtipocf.as_string() == "F" && (vcodcf.as_string() == "55" || vcodcf.as_string() == "45")) //if(voccas.as_string().full()) bool tolla = true; #endif TRectype r_cedeprest = getCli(vtipocf.as_string(), vcodcf.as_string(), voccas.as_string()); TAnagrafica cedeprest; // Con l'uscita di questo programma è stato messo un collegamento in prima nota // per il fornitore a cui è riferita la bolla doganale if(found_bolla_cli) { r_cedeprest = getCli("F", cfbolladog, ""); cedeprest.init(r_cedeprest); } else { cedeprest.init(vtipocf.as_string()[0], vcodcf.as_int(), voccas.as_string()); } TTrFa_record tff0400f("TFF0400F"); tff0400f.set("P4_KEYPRGINVIO", get_key(strarr)); tff0400f.set("P4_KEYHEADERFATT", get_header(strarr)); // Autofattura if(strcmp(strarr->get(_autofatt),"X") == 0) { tff0400f.set("P4_FISCIVAPAESE", _ditta.stato_partita_IVA()); tff0400f.set("P4_FISCIVACOD", _ditta.partita_IVA()); tff0400f.set("P4_CODFISC", _ditta.codice_fiscale()); } else // Fattura normale, lascio più volte la funzione con il nome del campo per leggibilità { // Se la bolla doganale non ha un fornitore collegato posso passare come P.IVA OO99999999999 if(found_bolla && !found_bolla_cli) { tff0400f.set("P4_FISCIVAPAESE", "OO"); tff0400f.set("P4_FISCIVACOD", "99999999999"); } else if (cedeprest.stato_partita_IVA().full() && cedeprest.partita_IVA().full() && (cedeprest.partita_IVA()[0] != '8' && cedeprest.partita_IVA()[0] != '9' || !cedeprest.italiano())) { tff0400f.set("P4_FISCIVAPAESE", cedeprest.stato_partita_IVA()); tff0400f.set("P4_FISCIVACOD", cedeprest.partita_IVA()); } else { // Se è un estero non CEE prendo nella partita IVA metto l'identificativo fiscale if(cedeprest.estero_non_CEE()) { tff0400f.set("P4_FISCIVAPAESE", cedeprest.stato_partita_IVA()); tff0400f.set("P4_FISCIVACOD", cedeprest.codice_fiscale()); } else { tff0400f.set("P4_CODFISC", cedeprest.codice_fiscale()); } } } if(cedeprest.ok()) // Con bolle doganali non a posto impazzisce { // Sono sicuro che se è di tipo 3,7 o 8 ha la ragione sociale int tipo = cedeprest.inserimento_in_allegato();//r_cedeprest.get_char(CLI_ALLEG); bool rsoc = cedeprest.giuridica() || (tipo == 3 || tipo == 7 || tipo == 8 || tipo == 0); bool privato = tipo == 6 || (cedeprest.estero() && cedeprest.fisica()); if(found_bolla && !found_bolla_cli) { tff0400f.set("P4_ANADENOM", "Dato Assente"); } else if (!rsoc) { // Bisogna fare un ragionamento più complesso, esistono ancora record salvati con Nome e Cognome nella prima parte // e non divisi come si fa adesso quindi farò così: // Controllo se il nome è pieno if(cedeprest.nome().full()) { // La vita è bella faccio che scrivere tff0400f.set("P4_ANANOME", cedeprest.nome()); tff0400f.set("P4_ANACOGNOME", cedeprest.cognome()); } else { // Devo indovinare quale è il nome e il cognome TToken_string nomeCog(cedeprest.cognome(), ' '); // Notare il separatore spazio // Se ho solo un nominativo è una ditta per Diana if(nomeCog.items() == 1) { rsoc = true; } // Controllo se ho solo un nome e un cognome else if(nomeCog.items() == 2) { tff0400f.set("P4_ANANOME", nomeCog.get(1)); tff0400f.set("P4_ANACOGNOME", nomeCog.get(0)); } else { TString cognome; cognome << nomeCog.get(0); // Potrebbe essere un cognome tipo "De Fischello" // Dai quante persone hanno più di 4 parole per nome e cognome? if(privato || (cognome.len() >= 2 && cognome.len() <= 4)) { // Controllo che non sia una Ragione sociale! Tipo "ZG di Gianluigi Zibello" // Se è segnato privato me ne sbatto anche di sto controllo if(privato || TString(nomeCog.get(1)).len() > 2) { cognome << " " << nomeCog.get(1); TString nome; for(int i = 2; i < nomeCog.items(); i++) nome << nomeCog.get(i) << " "; tff0400f.set("P4_ANANOME", nome); tff0400f.set("P4_ANACOGNOME", cognome); } else rsoc = true; } else rsoc = true; } } } // Ricontrollo!!!! rsoc potrebbe essere cambiato sopra // Devo trovare rsoc e: // 1 - Non trovo la bolla // 2 - Trovo il cliente if(rsoc && (!found_bolla || found_bolla_cli)) { tff0400f.set("P4_ANADENOM", cedeprest.ragione_sociale()); } tff0400f.set("P4_SEDEIND", cedeprest.via_residenza()); tff0400f.set("P4_SEDENRCIVICO", cedeprest.civico_residenza().left(7)); tff0400f.set("P4_SEDECAP", cedeprest.CAP_residenza()); tff0400f.set("P4_SEDECOMUNE", cedeprest.comune_residenza()); if(cedeprest.italiano()) // Campo ritornerebbe "EE" se estero tff0400f.set("P4_SEDEPROV", cedeprest.provincia_residenza()); tff0400f.set("P4_SEDENAZ", cedeprest.stato_residenza_ISO()); } tff0400f.set("P4_GESTIONE", "D"); ok = tff0400f.insert(); // Controllo dopo l'inserimento del tff0400 if(!ok) return false; TString rfso = strarr->get(_rfso); if(rfso.full()) { TRectype r_ana = cache().get(LF_ANAG, TString(rfso.left(1)) << "|" << rfso.sub(1)); ok = r_ana.full() && tff3100(strarr, r_ana); } // E dopo l'inserimento del tff3100 if(!ok) return false; } return ok; } bool TTrFa_app::tff0700(TSheet_field& sheet) { /******************************************************************************************************************** * Fattura * ********************************************************************************************************************/ // Mentre per i clienti è una porcata per le fatture non posso fare altrimenti, potrebbe essere che i clienti mettono righe in fondo customizzate spezzando fatture std::map fattSent; std::map docRighe; bool ok = true; TProgress_monitor p(sheet.items(), "Caricamento Fatture"); TString oldKey = ""; int numRiga; FOR_EACH_SHEET_ROW(sheet, r, strarr) { #ifdef DBG if(strarr->get_char(_tipocf) == 'F' && strarr->get_long(_codcf) == 3) bool tolla = true; #endif if(!p.add_status()) return false; IF_IS_ENABLED(strarr); // Chiave: Tipo C/F, Cod C/F, Numero doc. anno doc static TString checkFatt; static TString codcf; // Prendo il cliente occasionale se c'è codcf.cut(0) << strarr->get(_occas); if(codcf.blank()) codcf.cut(0) << strarr->get(_codcf); checkFatt.cut(0) << codcf << "," << strarr->get(_numdoc) << "," << TString(strarr->get(_datadoc)).right(4); if(fattSent.find(checkFatt) == fattSent.end()) { fattSent.insert(std::pair(checkFatt,true)); // TTrFa_record tff0700f("TFF0700F"); tff0700f.set("P7_KEYPRGINVIO", get_key(strarr)); static TString header; header.cut(0) << get_header(strarr); tff0700f.set("P7_KEYHEADERFATT", header); tff0700f.set("P7_KEYBODYFATT", get_body(strarr)); TString natura = strarr->get(_natura); tff0700f.set("P7_TIPODOC", strarr->get(_codnumAE)); // Controllo il tipo di esigilità tff0700f.set("P7_DATA", to_date(strarr->get(_datadoc))); static TString ndoc; ndoc.cut(0) << cache().get(LF_MOV, strarr->get(_numero), "NUMDOCEXT").right(20); if(ndoc.blank()) ndoc.cut(0) << strarr->get(_numdoc); tff0700f.set("P7_NUMERO", ndoc); tff0700f.set("P7_DATAREG", to_date(strarr->get(_datareg))); // Obbligatoria nei DTR tff0700f.set("P7_GESTIONE", ""); // Campi di controllo tff0700f.set("P7_CLIFOR", header); tff0700f.set("P7_NRODOC", ndoc); tff0700f.set("P7_DTADOC", to_date(strarr->get(_datadoc))); ok = tff0700f.insert(); // Controllo dopo l'inserimento del tff0700f if(!ok) return false; } // In qualsiasi caso va messa la riga ma prima elaboro il numero della riga! static TString newKey; newKey.cut(0) << get_body(strarr, false); if(docRighe.find(newKey) == docRighe.end()) { numRiga = 1; docRighe.insert(std::pair(newKey, numRiga)); } else { // Incremento e aggiorno numRiga = docRighe[newKey] + 1; docRighe[newKey] = numRiga; } ok = tff2200(strarr, numRiga); // E dopo l'inserimento del tff2200 if(!ok) return false; } return ok; } bool TTrFa_app::tff2200(TToken_string* strarr, int nriga) { TTrFa_record tff2200f("TFF2200F"); tff2200f.set("PL_KEYPRGINVIO", get_key(strarr)); tff2200f.set("PL_KEYHEADERFATT", get_header(strarr)); tff2200f.set("PL_KEYBODYFATT", get_body(strarr, false)); TString numriga; numriga.format("%020d", nriga); tff2200f.set("PL_KEYBODYDETT", numriga); tff2200f.set("PL_IMPONIBILE", real(strarr->get(_imponibile))); // Se li converto in real una volta passati vengono parsati da var2str nel formato che vuole l'agenzia delle entrate tff2200f.set("PL_IMPOSTA", real(strarr->get(_importoIVA))); real aliquota = cache().get("%IVA", strarr->get(_aliquota), "R0"); tff2200f.set("PL_ALIQUOTAIVA", aliquota); TRectype thisMov = cache().get(LF_MOV, strarr->get(_numero)); tff2200f.set("PL_ESIGIVA", is_split_payment(thisMov) ? "S" : is_IVA_diff(thisMov) || is_IVAxCassa(thisMov) ? "D" : "I"); tff2200f.set("PL_NATURA", strarr->get(_natura)); /* Tutto disabilitato! ************************************* real det(strarr->get(_detraibile)); // Nella conversione la vigola viene persa e 100,00 diventa 10.000 quindi divido det /= CENTO; if(det > ZERO) { tff2200f.set("PL_DETRAIBILE", CENTO - det); } else if(false) // Sempre disabilitato! { tff2200f.set("PL_DEDUCIBILE", "SI"); } */ tff2200f.set("PL_GESTIONE", "D"); return tff2200f.insert(); } bool TTrFa_app::tff3100(TToken_string* strarr, TRectype r_ana) { TTrFa_record tff3100f("TFF3100F"); tff3100f.set("PH_KEYPRGINVIO", get_key(strarr)); tff3100f.set("PH_KEYHEADERFATT", get_header(strarr)); if(_append) tff3100f.remove(); TAnagrafica rfso(r_ana); if(r_ana.get_char("TIPORFSO") == 'S') // Stabile Organizzazione { TString via = rfso.via_residenza(), cap = rfso.CAP_residenza(), nazione = rfso.stato_residenza_ISO(); tff3100f.set("PH_STABORGIND", via); tff3100f.set("PH_STABORGNRCIVICO", rfso.civico_residenza().left(7)); tff3100f.set("PH_STABORGCAP", cap); tff3100f.set("PH_STABORGCOMUNE", rfso.comune_residenza()); if(rfso.italiano()) tff3100f.set("PH_STABORGPROV", rfso.provincia_residenza()); tff3100f.set("PH_STABORGNAZ", nazione); } else // Rappresentante Fiscale { // La P.IVA del rappresentante fiscale deve essere in AT quindi non faccio alcun controllo, // se il valore nullo perchè Extra CEE non è un errore di campo (Anche perchè che senso ha un RF extra CEE?) TString paiv = rfso.partita_IVA(), ragsoc, nom, cog; ragsoc = rfso.ragione_sociale(); if(ragsoc.blank()) { nom = rfso.nome(), cog = rfso.cognome(); } tff3100f.set("PH_FISCIVAPAESE", rfso.stato_residenza_ISO()); tff3100f.set("PH_FISCIVACODICE", paiv); if(r_ana.get_char("TIPOA") == 'G') { tff3100f.set("PH_ANADENOMI", ragsoc); } else { TString nomCom = r_ana.get("RAGSOC"); tff3100f.set("PH_ANANOME", nom); tff3100f.set("PH_ANACOGNOME", cog); } } tff3100f.set("PH_GESTIONE", "D"); return tff3100f.insert(); } bool TTrFa_app::set_esportato(TSheet_field& sheet) { bool ok = true; TProgress_monitor p(sheet.items(),"Segno l'esportazione sui records"); FOR_EACH_SHEET_ROW(sheet, r, strarr) { if(!p.add_status()) return false; TString modificato = strarr->get(_forzata); if(modificato == "X") { ok = save_rec(*strarr, true); if(!ok) return false; } else { TRectype row = cache().get(LF_MOV, TString(strarr->get(_numero))); char invio = strarr->get_char(_invio); if(invio == 'F' || invio == 'X') invio = 'I'; row.put("TFINVIO", invio); row.put("TFDATA", TDate(TODAY).string()); ok = row.rewrite(TLocalisamfile(LF_MOV)) == NOERR; if(!ok) return false; } } return ok; } bool TTrFa_app::empty_tables(TString key) { TString query; query << "DELETE FROM TFF0100F WHERE P1_KEYPRGINVIO = '" << key << "';\n"; query << "DELETE FROM TFF0200F WHERE P2_KEYPRGINVIO = '" << key << "';\n"; query << "DELETE FROM TFF0300F WHERE P3_KEYPRGINVIO = '" << key << "';\n"; query << "DELETE FROM TFF0400F WHERE P4_KEYPRGINVIO = '" << key << "';\n"; query << "DELETE FROM TFF0700F WHERE P7_KEYPRGINVIO = '" << key << "';\n"; query << "DELETE FROM TFF2200F WHERE PL_KEYPRGINVIO = '" << key << "';\n"; query << "DELETE FROM TFF3100F WHERE PH_KEYPRGINVIO = '" << key << "';\n"; return xvt_sql_execute(_db, query, NULL, NULL) >= 0; } void TTrFa_app::main_loop() { // Sposto SSA if(!copy_ssa()) return; while (msk().run() == K_ENTER) { if(msk().check_not_empty()) { send(&msk()); //ini_set_string(CONFIG_DITTA, "tf", "LastSend", ++TDate(msk.get(F_DATAFIN))); } } } bool TTrFa_app::is_new_tipodoc(const TString& tipodoc) { return tipodoc != "TD01" && tipodoc != "TD04" && tipodoc != "TD05" && tipodoc != "TD07" && tipodoc != "TD08" && tipodoc != "TD10" && tipodoc != "TD11"; } bool TTrFa_app::is_new_natura(const TString& natura) { return natura.full() && natura != "N1" && natura != "N2" && natura != "N3" && natura != "N4" && natura != "N5" && natura != "N6" && natura != "N7"; } bool TTrFa_app::destroy() { xvt_sql_close(_db); _db = NULL; return TSkeleton_application::destroy(); } int tf0100(int argc, char* argv[]) { TTrFa_app t2t; t2t.run(argc, argv, TR("Trasferimento Fatture Elettroniche")); return 0; }