#include "tf0.h" #include "tf0100b.h" #include "cglib03.h" // is_split_payment() /* Utilities & Main App */ ///////////////////////////////////////////////////////////////////////////////////// // Utilities ///////////////////////////////////////////////////////////////////////////////////// // Le funzioni quelle belle TString getTipoDoc(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_CORRNINC: ret = "CN"; break; case B_TIPO_CORR: ret = "CR"; break; case B_TIPO_FATTSC: ret = "FS"; break; case B_TIPO_RICFIS: ret = "RF"; break; case B_TIPO_RICFISNI: ret = "RN"; break; case B_TIPO_SCONT: ret = "SC"; break; case B_TIPO_SCONTNI: ret = "SN"; break; */ default: ret = "ERR"; break; } return ret; } int getTipoDoc(TString id) { int ret = -1; if(id == "AF") ret = B_TIPO_AUTOFATT; else if(id == "BD") ret = B_TIPO_BOLLADOG; // else if(id == "CN") ret = B_TIPO_CORRNINC; // else if(id == "CR") ret = B_TIPO_CORR; else if(id == "FA") ret = B_TIPO_FATTACQ; else if(id == "FF") ret = B_TIPO_FATTFISC; // else if(id == "FS") ret = B_TIPO_FATTSC; 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 == "RF") ret = B_TIPO_RICFIS; // else if(id == "RN") ret = B_TIPO_RICFISNI; // else if(id == "SC") ret = B_TIPO_SCONT; // else if(id == "SN") ret = B_TIPO_SCONTNI; 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* decodTipo(TToken_string* strarr) { TRectype mov = cache().get(LF_MOV, strarr->get(_numero)); TCausale caus(mov.get("CODCAUS"), mov.get_int("ANNOIVA")); TString tipodoc; tipodoc << strarr->get(_codnum); // Le autofatture possono essere solo di tipo TDO1 e le bolle doganali nel dubbio pure if(tipodoc == "AF" || tipodoc == "BD" || tipodoc == "FF") return "TD01"; else if(tipodoc == "FA" || tipodoc == "FV") { // 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 TString keyAssoc; keyAssoc << row.get("CODIVA") << "|" << row.get("GRUPPO") << "|" << row.get("CONTO") << "|" << row.get("SOTTOCONTO"); if(intraval.is_key(keyAssoc)) { importo += *(real*)intraval.objptr(keyAssoc); intraval.add(keyAssoc, importo, true); } else { intraval.add(keyAssoc, importo); } } // Adesso che ho tutti i totali divisi per CODIVA e GCS vado a pescare il valore maggiore TString keyMax = ""; real max = ZERO; TString_array keys; intraval.get_keys(keys); for(int i = 0; i < keys.items(); i++) { TString key = *(TString*)keys.objptr(i); real valItem = *(real*)intraval.objptr(key); if(valItem > max) { keyMax = key; max = valItem; } } // Una volta che ho trovato il nostro vincitore vado a prendere il tipo di fattura dal GCS TString keyPCon = keyMax.ssub(keyMax.find('|') + 1); if(cache().get(LF_PCON, keyPCon, "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 saveRec(TToken_string row, bool esportato) { static TLocalisamfile trasfatt(LF_TRASFATT); TString key = row.get(_numero); key << "|"<< row.get(_aliquota); TRectype rCust = cache().get(LF_TRASFATT, key); // Se la riga non esiste metto la chiave if(rCust.empty()) { rCust.put("NUMREG", row.get(_numero)); } rCust.put("TIPO", row.get(_tipocf)); rCust.put("CODCF", row.get(_codcf)); rCust.put("OCCAS", row.get(_occas)); rCust.put("TIPODOC", row.get(_codnum)); rCust.put("NUMDOC", row.get(_numdoc)); rCust.put("DATAREG", row.get(_datareg)); rCust.put("DATADOC", row.get(_datadoc)); rCust.put("IMPONIBILE", row.get(_imponibile)); rCust.put("IMPOSTA", row.get(_importoIVA)); rCust.put("CODIVA", row.get(_aliquota)); rCust.put("AUTOFATT", row.get(_autofatt)); if(esportato) { TString invio = esportato? "I" : row.get(_invio); rCust.put("TFINVIO", invio); rCust.put("TFDATA", TDate(TODAY)); } return rCust.write_rewrite(trasfatt) == NOERR; } inline const char * noSpecial(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 ""; } bool bd2017() { static TDate today = TDate(TODAY), lastDay = TDate(31,12,2017); return today <= lastDay; } ///////////////////////////////////////////////////////////////////////////////////// // 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) << noSpecial(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) { _logTFF = msg; } else if (_log == NULL) { _log = new TLog_report; if (_logTFF.full()) { TString txt; txt << _logTFF << ": " << msg; _log->log(severity, txt); } else _log->log(severity, msg); } } bool TTrFa_app::show_log() { bool ok = true; if (_log) { _log->preview(); delete _log; _log = NULL; 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; if (xvt_sql_table_exists(_db, table)) { SLIST fields = xvt_sql_list_fields(_db, table); while (!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) { query.cut(0) << "ALTER TABLE " << table << " ADD COLUMN " << var << ' ' << val << " NOT NULL"; if (val.find("INT") >= 0 || val.find("NUM") >= 0) query << " DEFAULT 0"; else query << " DEFAULT ''"; query << ";"; xvt_sql_execute(_db, query, NULL, NULL); // Create table } } xvt_slist_destroy(fields); } else { query << "CREATE TABLE " << 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.cut(0); query << "CREATE UNIQUE INDEX " << 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 << ","; } } } 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; if(create) { createDB(); } return TSkeleton_application::create(); } // Sincronizzo il DB SQL con quello di campo bool TTrFa_app::syncronizeDB() { //xvt_sql_begin(_db); return true; } bool TTrFa_app::createDB() { 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) { // 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); } else return cantread_box(ini); return true; } bool TTrFa_app::copySSA() { 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 esattamente un file .ssa"), SPESOMETROBASE); return false; } 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 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 checkApp("cg1 -2 L"); checkApp.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(setEsportato(sheet)) message_box("Record segnati correttamente!"); else message_box("Ci sono stati degli errori durante la riscrittura dei records"); msk->setFilterChanged(); } } else message_box("Errore durante il salvataggio delle modifiche"); return true; } TString TTrFa_app::getKey(TToken_string* strarr) { return strarr->get_char(_tipocf) == 'C' ? DTE_PROVV : DTR_PROVV; } TString TTrFa_app::getHeader(TToken_string* strarr) { /* // Chiave header (20): TIPOCF(1) + NANANANANA(10) + CODCF(6) TString header; header.format("%c3753N4108E%06ld", strarr->get_char(_tipocf), strarr->get_int(_codcf)); return header; */ /* 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 idHeader = 0L; // Cerco/Aggiungo il Clifo all'std::map TString keyMap; keyMap << strarr->get_char(_tipocf) << "|" << strarr->get_int(_codcf); clifoDoc app; // Non è presente e lo inserisco per la chiave body if(mCliDoc.find(keyMap) == mCliDoc.end()) { idHeader++; app.contCliFo = idHeader; app.countDoc = 0L; mCliDoc.insert(std::pair(keyMap, app)); } TString header; header.format("%c%06ld", strarr->get_char(_tipocf), strarr->get_int(_codcf)); // Ritorno l'header return header; } TString TTrFa_app::getBody(TToken_string* strarr, bool add) { /* // Chiave body (20): TIPODOC(2) + DATADOC[YEAR](4) + NUMDOC(7) + AAA(3) + CODALIQUOTA(4) TDate datadoc(strarr->get(_datadoc)); TString body; body.format("%02s%04d%07s%04s", strarr->get(_codnum), datadoc.year(), strarr->get(_numdoc), strarr->get(_aliquota)); return body; */ /* 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 */ TString keyMap; keyMap << strarr->get_char(_tipocf) << "|" << strarr->get_int(_codcf); clifoDoc app = mCliDoc[keyMap]; if(add) app.countDoc += 1; mCliDoc[keyMap] = app; TString body; body.format("%010d%010d", app.contCliFo, app.countDoc); 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)) { bool sent = dte.get("P1_KEYPRGINVIO").as_string() == DTE_PROVV; if(sent) { TString msg = "É presente un'altra esportazione non ancora elaborata vuoi eliminarla?"; if(yesno_box(msg)) { if(!emptyTables(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)) { bool sent = dtr.get("P1_KEYPRGINVIO").as_string() == DTR_PROVV; TString msg = "É presente un'altra esportazione non ancora elaborata vuoi eliminarla?"; if(sent) { if(yesno_box(msg)) { if(!emptyTables(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(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(haveRFSO(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. TToken_string 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); // Controllo il clifo, se non c'è lo aggiungo altrimenti salto sto giro TString checkClifo; checkClifo << strarr->get_char(_tipocf) << strarr->get_long(_codcf); if(clifoSent.get_pos(checkClifo) < 0) clifoSent.add(checkClifo); else continue; TVariant vtipocf = strarr->get(_tipocf), vcodcf = strarr->get(_codcf), voccas = strarr->get(_occas); #ifdef DBG if(vtipocf.as_string() == "C" && vcodcf.as_string() == "316") 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(strcmp(strarr->get(_codnum),"BD") == 0) { TString codcf; // Attenzione! Se è una riga inserita a mano dall'utente prendo lo stesso il fornitore della riga! int movimento = strarr->get_int(_numero); if(movimento >= MOV_CUSTOM) codcf << strarr->get(_codcf); else codcf = cache().get(LF_MOV, strarr->get(_numero), "CFBOLLADOG"); r_cedeprest = getCli("F", codcf, ""); cedeprest.init('F', atol(codcf)); } else { cedeprest.init(vtipocf.as_string()[0], vcodcf.as_int(), voccas.as_string()); } TTrFa_record tff0400f("TFF0400F"); tff0400f.set("P4_KEYPRGINVIO", getKey(strarr)); tff0400f.set("P4_KEYHEADERFATT", getHeader(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 { if (cedeprest.stato_partita_IVA().full() && cedeprest.partita_IVA().full()) { tff0400f.set("P4_FISCIVAPAESE", cedeprest.stato_partita_IVA()); tff0400f.set("P4_FISCIVACOD", cedeprest.partita_IVA()); } else { // Ovviamente tutte le bolle doganali fatte prima del rilascio // non avranno questo campo compilato e quindi dovrò passare la partita IVA "OO99999999999" // Controllo anche di essere in una data entro il 31/12/2017, dopo tale data sto ragionamento non è valido if(strcmp(strarr->get(_codnum),"BD") == 0 && bd2017()) { tff0400f.set("P4_FISCIVAPAESE", "OO"); tff0400f.set("P4_FISCIVACOD", "99999999999"); } 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 char tipo = r_cedeprest.get_char(CLI_ALLEG); bool rsoc = cedeprest.giuridica() || (tipo == '3' || tipo == '7' || tipo == '8' || tipo == '\0'); bool privato = tipo == '6'; 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 if(rsoc) { 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 TToken_string fattSent = ""; bool ok = true; TProgress_monitor p(sheet.items(), "Caricamento Fatture"); TString oldKey = ""; int numRiga; FOR_EACH_SHEET_ROW(sheet, r, strarr) { if(!p.add_status()) return false; IF_IS_ENABLED(strarr); TString checkFatt; checkFatt << strarr->get_char(_tipocf) << "|" << strarr->get_long(_codcf) << "|" << strarr->get(_numdoc); if(fattSent.get_pos(checkFatt) < 0) { fattSent.add(checkFatt); // TTrFa_record tff0700f("TFF0700F"); tff0700f.set("P7_KEYPRGINVIO", getKey(strarr)); tff0700f.set("P7_KEYHEADERFATT", getHeader(strarr)); tff0700f.set("P7_KEYBODYFATT", getBody(strarr)); TString natura = strarr->get(_natura); tff0700f.set("P7_TIPODOC", decodTipo(strarr)); // Controllo il tipo di esigilità tff0700f.set("P7_DATA", toDate(strarr->get(_datadoc))); tff0700f.set("P7_NUMERO", strarr->get(_numdoc)); tff0700f.set("P7_DATAREG", toDate(strarr->get(_datareg))); // Obbligatoria nei DTR tff0700f.set("P7_GESTIONE", ""); 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! TString newKey = getBody(strarr, false); if(oldKey != newKey) { numRiga = 1; oldKey = newKey; } else 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", getKey(strarr)); tff2200f.set("PL_KEYHEADERFATT", getHeader(strarr)); tff2200f.set("PL_KEYBODYFATT", getBody(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)); 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", 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", getKey(strarr)); tff3100f.set("PH_KEYHEADERFATT", getHeader(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 = rfso.ragione_sociale(), 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::setEsportato(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 = saveRec(*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::emptyTables(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(!copySSA()) return; TTrFa_mask msk("tf0100a"); while (msk.run() == K_ENTER) { if(msk.checkNotEmpty()) { // Sistemo tutti i flag prima di inviare msk.theFinalCheckDown(); send(&msk); //ini_set_string(CONFIG_DITTA, "tf", "LastSend", ++TDate(msk.get(F_DATAFIN))); } } } 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; }