#include #include #include #include #include #include "../ve/velib05.h" #include "pa0.h" #include "pa0100a.h" #include "../fe/felib.h" #include ///////////////////////////////////////////////////////////////////////////////////// // Globals ///////////////////////////////////////////////////////////////////////////////////// XVT_SQLDB _db = NULL; // PAF sqlite db ///////////////////////////////////////////////////////////////////////////////////// // TPaf_record ///////////////////////////////////////////////////////////////////////////////////// class TPaf_record : public TObject { TString8 _table; TToken_string _key; TAssoc_array _fields; protected: void copy(const TPaf_record& rec) { _table = rec._table; _key = rec._key; _fields = rec._fields; } const TString& var2str(const TVariant& var) const; public: void reset() { _fields.destroy(); } void set(const char* fld, const TVariant& var); void set(const char* fld, long var); void set(const char* fld, const char* var); void set(const char* fld, const real& var); void set(const char* fld, const TString& var); void set(const char* fld, const TDate& var); void set(const char* fld, bool var); const TVariant& get(const char* fld) const; bool insert(); bool remove(); bool search(); bool search(const char* k1, const char* k2, const char* k3 = NULL); virtual TObject* dup() const { return new TPaf_record(*this); } virtual bool ok() const { return _table.not_empty(); } TPaf_record& operator=(const TPaf_record& rec) { copy(rec); return *this; } TPaf_record(const TPaf_record& rec) { copy(rec); } TPaf_record(const char* table); }; void TPaf_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)); } } void TPaf_record::set(const char* fld, long val) { const TVariant var(val); set(fld, var); } void TPaf_record::set(const char* fld, const char* val) { if (val == NULL) set(fld, NULL_VARIANT); else { const TVariant var(val); set(fld, var); } } void TPaf_record::set(const char* fld, const TString& val) { const TVariant var(val); set(fld, var); } void TPaf_record::set(const char* fld, const real& val) { const char* str = val.string(0, 2); set(fld, str); } void TPaf_record::set(const char* fld, const TDate& var) { const char* str = var.string(full, '-', full, full, amg_date); set(fld, str); } void TPaf_record::set(const char* fld, bool var) { set(fld, var ? "SI" : "NO"); } const TVariant& TPaf_record::get(const char* fld) const { const TVariant* var = (const TVariant*)_fields.objptr(fld); return var ? *var : NULL_VARIANT; } const TString& TPaf_record::var2str(const TVariant& var) const { const TString& str = var.as_string(); bool apici = var.type() == _alfafld; if (apici && str[0] != '0' && real::is_natural(str)) apici = false; if (!apici) return str; TString& tmp = get_tmp_string(); tmp = str; for (int a = str.rfind('\''); a >= 0; a--) { if (tmp[a] == '\'') tmp.insert("'", a); } tmp.insert("'", 0); tmp << '\''; return tmp; } bool TPaf_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(var) ; } } CHECKS(nkf >= 2, "Can't remove partial key on table ", (const char*)_table); query << ';'; return xvt_sql_execute(_db, query, NULL, 0L) > 0; } static int paf_search_record(void* jolly, int cols, char** names, char** values) { TPaf_record& rec = *(TPaf_record*)jolly; for (int i = 0; i < cols; i++) rec.set(names[i], values[i]); return 0; } bool TPaf_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(var) << " AND "; } query.rtrim(5); query << ';'; return xvt_sql_execute(_db, query, paf_search_record, this) == 1; } bool TPaf_record::search(const char* k1, const char* k2, const char* k3) { _fields.destroy(); set(_key.get(0), k1); set(_key.get(1), k2); if (k3 && *k3) set(_key.get(2), k3); return search(); } bool TPaf_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(var) << ','; } } query.rtrim(1); values.rtrim(1); query << ")\nVALUES (" << values << ");"; return xvt_sql_execute(_db, query, NULL, 0L) == 1; } TPaf_record::TPaf_record(const char* table) : _table(table), _key(15, ',') { _key = ini_get_string("./paf.ini", table, "INDEX_1"); if (_key.empty()) { TConfig cfg("paf.ini", table); TAssoc_array& fields = cfg.list_variables(); FOR_EACH_ASSOC_STRING(fields, obj, key, str) { if (key[2] == 'K') _key.add(key); } } CHECKS(_key.full(), "Invalid primary key for table ", table); } ///////////////////////////////////////////////////////////////////////////////////// // TPa_mask ///////////////////////////////////////////////////////////////////////////////////// class TPA_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); void fill(); public: TPA_mask() : TAutomask("pa0100a") {} }; void TPA_mask::fill() { TSheet_field& docs = sfield(F_DOCS); TString_array& sht = docs.rows_array(); docs.hide(); sht.destroy(); TString query; query << "USE 17 SELECT (PADESTIN!='')&&(PARIFAMM!='')" << "\nJOIN 20 INTO TIPOCF=TIPOCF CODCF==CODCF" << "\nFROM TIPOCF=C\nTO TIPOCF=C"; TISAM_recordset clifo_pa(query); const TRecnotype n = clifo_pa.items(); if (n > 0) { const TDate dal = get(F_DATAINI); TProgress_monitor pi(n, NULL); for (bool okc = clifo_pa.move_first(); okc; okc = clifo_pa.move_next()) { if (!pi.addstatus(1)) break; query.cut(0); query << "USE 33 KEY 2\nSELECT (BETWEEN(STATO,2,8))"; if (!get_bool(F_SHOWALL)) query << "&&(PAF!='X')"; query << "\nFROM TIPOCF=C CODCF=#CLIENTE PROVV=D ANNO=2014 DATADOC=" << dal.date2ansi() << "\nTO TIPOCF=C CODCF=#CLIENTE PROVV=D"; TISAM_recordset doc_pa(query); doc_pa.set_var("#CLIENTE", clifo_pa.get(CLI_CODCF)); for (bool okd = doc_pa.move_first(); okd; okd = doc_pa.move_next()) { const TTipo_documento& td = cached_tipodoc(doc_pa.get(DOC_TIPODOC).as_string()); if (!td.is_fattura()) continue; TToken_string* row = new TToken_string; *row = doc_pa.get(DOC_PAF).as_bool() ? " " : "X"; row->add(doc_pa.get(DOC_ANNO).as_int(), 1); row->add(doc_pa.get(DOC_CODNUM).as_string()); row->add(doc_pa.get(DOC_NDOC).as_int()); row->add(doc_pa.get(DOC_DATADOC).as_date()); row->add(clifo_pa.get(CFV_CODCF).as_int()); row->add(clifo_pa.get("20."CLI_RAGSOC).as_string()); row->add(clifo_pa.get(CFV_PADESTIN).as_string()); row->add(clifo_pa.get(CFV_PARIFAMM).as_string()); sht.add(row); } } } docs.force_update(); docs.show(); } bool TPA_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_DATAINI: if (e == fe_init) o.set("01-06-2014"); if (e == fe_modify) fill(); break; case F_SHOWALL: if (e == fe_modify) fill(); break; case F_DOCS: if (e == fe_init) fill(); if (e == se_query_add || e == se_query_del) return false; break; default: break; } return true; } ///////////////////////////////////////////////////////////////////////////////////// // TDoc2Paf ///////////////////////////////////////////////////////////////////////////////////// class TDoc2Paf : public TSkeleton_application { TAnagrafica _ditta; private: int parse_line(const TString& line, TString& var, TString& val) const; void create_table(TScanner& paf, const TString& table); protected: const TString& cessionario(const TDocumento& doc); const TString& fattura(const TDocumento& doc); void elabora(TDocumentoEsteso& doc); void elabora(const TRectype& rec); void elabora(const TDoc_key& key); void elabora(const TFilename& ini); public: virtual bool create(); virtual bool destroy(); virtual void main_loop(); }; const TString& TDoc2Paf::cessionario(const TDocumento& doc) { const TString& cess = doc.clifor().vendite().get(CFV_PADESTIN); CHECK(cess.full(), "Destinatario fattura elettronica non valido"); return cess; } const TString& TDoc2Paf::fattura(const TDocumento& doc) { TString& key = get_tmp_string(); key << doc.get_date(DOC_DATADOC).date2ansi() << '/' << doc.numerazione() << '/' << doc.numero(); return key; } void TDoc2Paf::elabora(TDocumentoEsteso& doc) { const TFirm& firm = prefix().firm(); TString8 prginv; prginv.format("%08d", ini_get_int("./paf.ini", "Main", "PRGINV") + 1); const TString8 hfatt = cessionario(doc); // Codice univoco di 6 caratteri dell'ufficio P.A. const TString80 bfatt = fattura(doc); // Codice univoco di 20 caratteri del documento // TPaf_record paf0100f("PAF0100F"); paf0100f.set("P1KHFATT", hfatt); paf0100f.set("P1KBFATT", bfatt); paf0100f.remove(); paf0100f.set("P1PAESE", "IT"); paf0100f.set("P1CODICE", _ditta.partita_IVA()); paf0100f.set("P1PRGINV", prginv); paf0100f.set("P1FTRASM", "SDI10"); paf0100f.set("P1CDEST", hfatt); TString80 tel; tel << firm.get(NDT_PTEL) << firm.get(NDT_TEL); paf0100f.set("P1TELEF", tel); paf0100f.set("P1MAIL", firm.get(NDT_MAIL)); paf0100f.insert(); // // TPaf_record paf0200f("PAF0200F"); paf0200f.set("P2KHFATT", hfatt); paf0200f.set("P2KBFATT", bfatt); paf0200f.remove(); paf0200f.set("P2PAESE", paf0100f.get("P1PAESE")); // Sempre IT paf0200f.set("P2CODICE", _ditta.partita_IVA()); paf0200f.set("P2FISCA", _ditta.codice_fiscale()); if (_ditta.fisica()) { paf0200f.set("P2NOME", _ditta.nome()); paf0200f.set("P2COGN", _ditta.cognome()); } else { paf0200f.set("P2DENOM", _ditta.ragione_sociale()); } paf0200f.set("P2RFISC", "RF01"); // DatiSede paf0200f.set("P2SINDI", _ditta.indirizzo_residenza()); paf0200f.set("P2SCOMU", _ditta.comune_residenza()); paf0200f.set("P2SPROV", _ditta.provincia_residenza()); paf0200f.set("P2SNAZI", paf0100f.get("P1PAESE")); /* // DatiStabile paf0200f.set("P2OINDI", _ditta.indirizzo_residenza()); paf0200f.set("P2OCOMU", _ditta.comune_residenza()); paf0200f.set("P2OPROV", _ditta.provincia_residenza()); paf0200f.set("P2ONAZI", paf0100f.get("P1PAESE")); paf0200f.insert(); */ // // TAnagrafica cliente(doc.clifor()); TPaf_record paf0400f("PAF0400F"); paf0400f.set("P4KHFATT", hfatt); paf0400f.set("P4KBFATT", bfatt); paf0400f.remove(); paf0400f.set("P4PAESE", "IT"); paf0400f.set("P4CODICE", cliente.partita_IVA()); paf0400f.set("P4FISCA", cliente.codice_fiscale()); if (cliente.fisica()) { paf0400f.set("P4NOME", cliente.nome()); paf0400f.set("P4COGN", cliente.cognome()); } else { paf0400f.set("P4DENOM", cliente.ragione_sociale()); } paf0400f.set("P4RFISC", "RF01"); // DatiSede paf0400f.set("P4SINDI", cliente.indirizzo_residenza()); paf0400f.set("P4SCOMU", cliente.comune_residenza()); paf0400f.set("P4SPROV", cliente.provincia_residenza()); paf0400f.set("P4SNAZI", "IT"); paf0400f.insert(); // // TPaf_record paf0700f("PAF0700F"); paf0700f.set("P7KHFATT", hfatt); paf0700f.set("P7KBFATT", bfatt); paf0700f.remove(); paf0700f.set("P7TDOC", doc.is_nota_credito() ? "TD04" : "TD01"); paf0700f.set("P7DIVISA", "EUR"); // Aggiungere codice ISO 4217 a tabella divise (%VAL) paf0700f.set("P7DATA", doc.data()); paf0700f.set("P7NUME", doc.numero()); paf0700f.insert(); // TPaf_record paf0900f("PAF0900F"); paf0900f.set("P9KHFATT", hfatt); paf0900f.set("P9KBFATT", bfatt); paf0900f.remove(); TToken_string sconto(doc.get(DOC_SCONTOPERC), '+'); sconto.strip_spaces(); long nlin_sconto = 1; FOR_EACH_TOKEN(sconto, str) { const real sconto = str; if (!sconto.is_zero()) { paf0900f.set("P9NLIN", nlin_sconto++); paf0900f.set("P9TSCO", sconto > ZERO ? "SC" : "MG"); paf0900f.set("P9PSCO", sconto); } paf0900f.insert(); } // TPaf_record paf2700f("PAF2700F"); paf2700f.set("PQKHFATT", hfatt); paf2700f.set("PQKBFATT", bfatt); paf2700f.remove(); paf2700f.set("PQITDOC", doc.totale_doc()); paf2700f.set("PQCAUS", doc.tipo().descrizione()); paf2700f.set("PQART73", true); paf2700f.insert(); // // TPaf_record paf1800f("PAF1800F"); paf1800f.set("PIKHFATT", hfatt); paf1800f.set("PIKBFATT", bfatt); paf1800f.remove(); // Cancella tutte le righe documento long pinlin = 0; const int nrows = doc.rows(); FOR_EACH_PHYSICAL_RDOC(doc, r, rdoc) { paf1800f.reset(); paf1800f.set("PIKHFATT", hfatt); paf1800f.set("PIKBFATT", bfatt); paf1800f.set("PINLIN", ++pinlin); paf1800f.set("PIDESC", rdoc->get(RDOC_DESCR)); if (rdoc->is_merce()) { paf1800f.set("PIQTA", rdoc->quantita()); paf1800f.set("PIUNMIS", rdoc->get(RDOC_UMQTA)); paf1800f.set("PIPREZ", rdoc->prezzo(true, false)); paf1800f.set("PIPRZT", rdoc->importo(true, false)); const real aliquota = cache().get("%IVA", rdoc->get(RDOC_CODIVA), "R0"); paf1800f.set("PIAIVA", aliquota); // TPaf_record paf2000f("PAF2000F"); paf2000f.set("PJKHFATT", hfatt); paf2000f.set("PJKBFATT", bfatt); paf2000f.remove(); TToken_string sconto(rdoc->get(RDOC_SCONTO), '+'); sconto.strip_spaces(); if (sconto.items()) { /* long nlin_sconto = 1; FOR_EACH_TOKEN(sconto, str) { const real perc = str; if (!perc.is_zero()) { paf2000f.set("PJNLIN", nlin_sconto++); paf2000f.set("PJTSCO", perc > ZERO ? "SC" : "MG"); paf2000f.set("PJPSCO", perc); paf2000f.insert(); } } */ const real perc = sconto; if (!perc.is_zero()) { paf2000f.set("PJKNLIN", pinlin); paf2000f.set("PJTSCO", perc > ZERO ? "SC" : "MG"); paf2000f.set("PJPSCO", perc); paf2000f.insert(); } } // } paf1800f.insert(); } // // TPaf_record paf2200f("PAF2200F"); paf2200f.set("PLKHFATT", hfatt); paf2200f.set("PLKBFATT", bfatt); paf2200f.remove(); // Cancella tutte le righe di riepilogo IVA TAssoc_array& tiva = doc.tabella_iva(false); FOR_EACH_ASSOC_OBJECT(tiva, obj, key, itm) { const TRiepilogo_iva& riva = *(const TRiepilogo_iva*)itm; const real aliquota = riva.cod_iva().percentuale(); paf2200f.set("PLALIVA", aliquota); const TString& tipo = riva.cod_iva().tipo(); if (tipo.full()) { if (tipo == "NS") paf2200f.set("PLNATU", "N2"); else if (tipo == "NI") paf2200f.set("PLNATU", "N3"); else if (tipo == "ES") paf2200f.set("PLNATU", "N4"); } paf2200f.set("PLIMPO", riva.imponibile()); paf2200f.set("PLIMPS", riva.imposta()); // Esigibilità IVA: immediata o no? const char* eiva = doc.get_bool(DOC_LIQDIFF) || doc.get_bool(DOC_IVAXCASSA) ? "D" : "I"; paf2200f.set("PLEIVA", eiva); paf2200f.insert(); } // // TPaf_record paf2400f("PAF2400F"); paf2400f.set("PNKHFATT", hfatt); paf2400f.set("PNKBFATT", bfatt); paf2400f.remove(); // Cancella i dati pagamento const TPagamento& pag = doc.pagamento(); doc.scadenze_recalc(); // Ricalcola array delle rate TString_array& scad = doc.scadenze(); const int nrate = scad.items(); // Conta rate generate paf2400f.set("PNCPAG", nrate > 1 ? "TP01" : "TP02"); // A rate (TP01) o una soluzione(TP02)? paf2400f.insert(); TPaf_record paf2500f("PAF2500F"); paf2500f.set("POKHFATT", hfatt); paf2500f.set("POKBFATT", bfatt); paf2500f.remove(); // Cancella tutte le rate for (int nr = 0; nr < nrate; nr++) { paf2500f.set("POKNLIN", long(nr+1)); // Numero riga const char* mod_pag = "MP01"; // Modalità di pagamento const int n = nr < pag.n_rate() ? nr : 0; // Si assicura che il numero riga sia accettabile switch (pag.tipo_rata(n)) { case _bonfico: mod_pag = "MP05"; break; // bonifico case _rid : mod_pag = "MP09"; break; // RID case _ric_ban: mod_pag = "MP12"; break; // RIBA default : mod_pag = "MP01"; break; // contanti } paf2500f.set("POMPAGAM", mod_pag); TToken_string& riga = scad.row(nr); // Data|Importo paf2500f.set("POUSCAD", TDate(riga.get(0))); // Data scadenza paf2500f.set("POIMPO", real(riga.get())); // Importo rata paf2500f.set("POCPAG", pag.code()); // Codice pagamento di CAMPO paf2500f.insert(); } // ini_set_string("./paf.ini", "Main", "PRGINV", prginv); } void TDoc2Paf::elabora(const TRectype& rec) { TDocumentoEsteso doc; if (doc.read(rec) == NOERR) elabora(doc); } void TDoc2Paf::elabora(const TDoc_key& key) { TRectype rec(LF_DOC); rec.put(DOC_PROVV, key.provv()); rec.put(DOC_ANNO, key.anno()); rec.put(DOC_CODNUM, key.codnum()); rec.put(DOC_NDOC, key.ndoc()); elabora(rec); } void TDoc2Paf::elabora(const TFilename& ini) { TConfig cfg(ini, "33"); const int anno = cfg.get_int(DOC_ANNO); const long ndoc = cfg.get_long(DOC_NDOC); const TFixed_string codnum(cfg.get(DOC_CODNUM)); // lascio sapientemente per ultima la get di una stringa const TDoc_key key(anno, codnum, ndoc); elabora(key); } void TDoc2Paf::main_loop() { bool is_batch = false; for (int a = 1; a < argc(); a++) { TFilename ini = argv(a); if (ini.starts_with("-i", true) || ini.starts_with("/i", true)) ini.ltrim(2); if (ini.exist()) { is_batch = true; elabora(ini); } else { if (ini.find('*') >= 0 || ini.find('?') >= 0) { TString_array f; list_files(ini, f); FOR_EACH_ARRAY_ROW(f, r, row) { ini = *row; if (ini.exist()) { is_batch = true; elabora(ini); } } } } } if (!is_batch) { TPA_mask mask; for (;;) { if (mask.run() == K_ENTER) { TString_array& sht = mask.sfield(F_DOCS).rows_array(); TProgress_monitor pi(sht.items(), NULL); int ndocs = 0; FOR_EACH_ARRAY_ROW(sht, r, riga) { if (!pi.add_status(1)) break; if (riga->starts_with("X")) { const int anno = riga->get_int(1); const long ndoc = riga->get_long(3); const TFixed_string codnum(riga->get(2)); // lascio sapientemente per ultima la get di una stringa const TDoc_key key(anno, codnum, ndoc); elabora(key); ndocs++; } } message_box(FR("Sono stati elborati %d documenti"), ndocs); } else break; } } } int TDoc2Paf::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; } 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; } void TDoc2Paf::create_table(TScanner& paf, const TString& table) { TString query, var, val; if (xvt_sql_table_exists(_db, table)) { SLIST fields = xvt_sql_list_fields(_db, table); while (!paf.eof()) { const TString& line = paf.line(); const int n = parse_line(line, var, val); if (n <= 0) break; if (n == 1) // paragraph! { paf.push(line); break; } if (var.starts_with("INDEX_")) continue; if (xvt_slist_find_str(fields, var) == NULL) { query.cut(0) << "ALTER TABLE " << table << " ADD COLUMN " << var << ' ' << val << ';'; xvt_sql_execute(_db, query, NULL, NULL); // Create table } } xvt_slist_destroy(fields); } else { query << "CREATE TABLE " << table << " ("; while (!paf.eof()) { const TString& line = paf.line(); const int n = parse_line(line, var, val); if (n <= 0) break; if (n == 1) { paf.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 << ','; } } } } bool TDoc2Paf::create() { TFilename n = prefix().get_studio(); // base direcotry n.add("sql"); make_dir(n); n.add("paf.db"); _db = xvt_sql_open(n, user(), "", n.path()); if (_db == NULL) return false; n = "paf.ini"; if (n.exist()) { TScanner paf(n); while (!paf.eof()) { const TString& p = paf.line(); if (p.starts_with("[PAF")) { const TString8 table = p.mid(1, 8); create_table(paf, table); } } } else return cantread_box(n); TRectype cfven(LF_CFVEN); if (cfven.type(CFV_PARIFAMM) != _alfafld) return error_box(TR("Database non convertito per fatturazione elettronica")); _ditta.init(LF_NDITTE, prefix().get_codditta()); return TSkeleton_application::create(); } bool TDoc2Paf::destroy() { xvt_sql_close(_db); _db = NULL; return TSkeleton_application::destroy(); } int pa0100(int argc, char* argv[]) { TDoc2Paf d2p; d2p.run(argc, argv, TR("Fatturazione P.A.")); return 0; }