#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../ce/ammce.h" #include "../ce/cespi.h" #include "../ce/salce.h" #include "../cg/cg2103.h" #include "../cg/cglib01.h" #include "lv4.h" #include "lv4100.h" #include "lv4500a.h" #include "lvlib.h" #define T_N "N" #define T_X "X" ///////////////////////////////// //// LAUNDRY_RECORDSET //// ///////////////////////////////// //Classe TLaundry_recordset: è un TAS400_recordset "intelligente" class TLaundry_recordset : public TAS400_recordset { public: void add_field(const char* name, const char* tipo, int pos, int len); TLaundry_recordset(const int rec_length); }; //ADD_FIELD: aggiunge i campi al recordset void TLaundry_recordset::add_field(const char* name, const char* tipo, int pos, int len) { CHECK(name[1]=='.', "Campo orfano di tracciato"); const TFixed_string str_tipo(tipo); TFieldtypes ft = _alfafld; if (str_tipo.ends_with("N")) ft = _intzerofld; create_field(name, -1, len, ft); } //costruttore TLaundry_recordset::TLaundry_recordset(const int rec_lenght) : TAS400_recordset("AS400()") { TString16 query; query << "AS400(" << rec_lenght << ")"; TFilename cazzone; parse_query(query, cazzone); } //////////////////////////// //// TCONTI_CACHE //// //////////////////////////// //classe TConti_cache class TConti_cache : public TCache { TLog_report * _log; bool _errors; protected: virtual TObject* key2obj(const char* key); public: const bool errors() const { return _errors; } const TBill& decodifica_conti(const long mastro, const long conto); TConti_cache(TLog_report * log) : _log(log), _errors(false) {} }; //KEY2OBJ: ridefinisco il metodo virtuale key2obj in modo che mi restituisca quello di cui ho bisogno TObject* TConti_cache::key2obj(const char* key) { TLocalisamfile riclpdc(LF_RICLPDC); riclpdc.setkey(3); riclpdc.put("TIPORIC", "CGCONTI"); riclpdc.put("CODICE", key); if(riclpdc.read(_isgteq) == NOERR && riclpdc.get("CODICE") == key) return new TBill(riclpdc.get_int("GRUPPO"), riclpdc.get_int("CONTO"), riclpdc.get_long("SOTTOCONTO")); TString mastro(key); TString conto(mastro.mid(6)); mastro = mastro.left(6); _log->log(2, format(FR("Mastro %6s Conto %6s assente"), (const char *) mastro, (const char *) conto)); _errors = true; return new TBill; } //DECODIFICA_CONTI: restituisce il TBill dato codice mastro e conto del COGECO const TBill& TConti_cache::decodifica_conti(const long mastro, const long conto) { TString16 codice; codice.format("%06ld%06ld", mastro, conto); const TBill* bill = (TBill*)objptr(codice); return *bill; } ////////////////////////////////// //// TDECODIFICA_CODICI //// ////////////////////////////////// //classe TDecodifica_codici class TDecodifica_codici : public TObject { TAssoc_array _tab; TConti_cache _conti; TLog_report * _log; bool _errors; protected: void riempi_array(); const TString& decodifica(const char* tabella, const int codice); public: const TString& decodifica_causali(const int cau_cog); const TString& decodifica_condpag(const int condpag_cog); const TString& decodifica_codiva(const int codiva_cog); const TString& decodifica_regiva(const int regiva_cog); const TString& decodifica_valute(const int val_cog); const TBill& decodifica_conto(const long mastro, const long conto); const bool errors() const { return _errors || _conti.errors(); } TDecodifica_codici(TLog_report * log); }; //RIEMPI_ARRAY: riempe l'Assoc_array che contiene i dati per fare la decodifica void TDecodifica_codici::riempi_array() { TString query; query << "USE MULTIREL\n" << "FROM COD=\"CG\"\n" << "TO COD=\"CG\""; TISAM_recordset recset(query); for(bool ok = recset.move_first(); ok; ok = recset.move_next()) { const TString& codice = recset.get("COD").as_string().mid(2); const TString& data = recset.get("DATA").as_string(); const TString& first = recset.get("FIRST").as_string(); //faccio un Assoc_array di Assoc_array TAssoc_array* tab = (TAssoc_array*)_tab.objptr(codice); if(tab == NULL) { tab = new TAssoc_array; _tab.add(codice, tab); } tab->add(data, first); } } //DECODIFICA: fa la decodica vera e propria const TString& TDecodifica_codici::decodifica(const char* tabella, const int codice) { //se non ho ancora caricato l'array, lo faccio if(_tab.empty()) riempi_array(); TAssoc_array* tab = (TAssoc_array*)_tab.objptr(tabella); //se esite, restituisco la decodifica, altrimenti stringa vuota if(tab != NULL && codice > 0) { TString8 cod; cod << codice; const TString* data = (const TString*)tab->objptr(cod); if(data != NULL) return *data; } _log->log(2, format(FR("Tabella %s codice %ld assente"), tabella, codice)); _errors = true; return EMPTY_STRING; } //DECODIFICA_CAUSALI: decodifico da COGECO a Campo la causale const TString& TDecodifica_codici::decodifica_causali(const int cau_cog) { return decodifica("CAU", cau_cog); } //DECODIFICA_CONDPAG: decodifico da COGECO a Campo la condizione di pagamento const TString& TDecodifica_codici::decodifica_condpag(const int condpag_cog) { return decodifica("CDP", condpag_cog); } //DECODIFICA_CODIVA: decodifico da COGECO a Campo il codice IVA const TString& TDecodifica_codici::decodifica_codiva(const int codiva_cog) { return decodifica("IVA", codiva_cog); } //DECODIFICA_REGIVA: decodifico da COGECO a Campo il registro IVA const TString& TDecodifica_codici::decodifica_regiva(const int regiva_cog) { return decodifica("REG", regiva_cog); } //DECODIFICA_VALUTE: decodifico da COGECO a Campo la valuta const TString& TDecodifica_codici::decodifica_valute(const int val_cog) { return decodifica("VAL", val_cog); } //DECODIFICA_CONTO: decodifico da COGECO a Campo il conto const TBill& TDecodifica_codici::decodifica_conto(const long mastro, const long conto) { return _conti.decodifica_conti(mastro, conto); } //costruttore TDecodifica_codici::TDecodifica_codici(TLog_report * log) : _log(log), _conti(log), _errors(false) {} //////////////////////////////// //// TIMPORTA_FAT_REC //// //////////////////////////////// //Classe TImporta_fat_rec class TImporta_fat_rec : public TLaundry_recordset { protected: virtual TRecnotype new_rec(const char* trc); public: TImporta_fat_rec(const TFilename& filename); }; ///////////////////////////////////////////////////////////// // Recordset specifici per i dati da trasferire INPUT ///////////////////////////////////////////////////////////// TRecnotype TImporta_fat_rec::new_rec(const char* trc) { if (trc && *trc > ' ') { TString rec; rec << trc << "\r\n"; return TText_recordset::new_rec(rec); } return -1; } //questo invece è il metodo magico che vale per il caricamento da file esterno TImporta_fat_rec::TImporta_fat_rec(const TFilename& filename) : TLaundry_recordset(89) { TFilename cazzone; //as400 con lunghezza 89 e chiave lunga 1 (a partire dal ventesimo carattere): è il tipo record parse_query("AS400(89,1,20)", cazzone); //Tipo record C add_field("C.NDOC", T_N, 1, 6); add_field("C.DATADOC", T_N, 7, 8); add_field("C.NPART", T_N, 15, 6); add_field("C.TIPOMOV", T_X, 21, 1); add_field("C.SEZIONE", T_X, 22, 1); add_field("C.CODCF", T_N, 23, 6); add_field("C.IMPORTO", T_X, 29, 13); add_field("C.CODVAL", T_X, 42, 4); add_field("C.CODPAG", T_X, 46, 4); add_field("C.DATASCAD", T_N, 50, 8); add_field("C.ABI", T_X, 58, 6); add_field("C.CAB", T_X, 64, 6); add_field("C.CODCAU", T_N, 70, 4); add_field("C.REGIVA", T_X, 74, 1); add_field("C.NREGIVA", T_N, 75, 2); add_field("C.NPROG", T_N, 77, 11); //Tipo record G add_field("G.NDOC", T_N, 1, 6); add_field("G.DATADOC", T_N, 7, 8); add_field("G.NPART", T_N, 15, 6); add_field("G.TIPOMOV", T_X, 21, 1); add_field("G.SEZIONE", T_X, 22, 1); add_field("G.IMPORTO", T_X, 23, 13); add_field("G.CODMASTRO", T_N, 36, 6); add_field("G.CODCONTO", T_N, 42, 6); //Tipo record I add_field("I.NDOC", T_N, 1, 6); add_field("I.DATADOC", T_N, 7, 8); add_field("I.NPART", T_N, 15, 6); add_field("I.TIPOMOV", T_X, 21, 1); add_field("I.SEZIONE", T_X, 22, 1); add_field("I.IMPONIBILE", T_X, 23, 13); add_field("I.IMPOSTA", T_X, 36, 11); add_field("I.CODIVA", T_N, 47, 4); add_field("I.CODMASTRO", T_N, 36, 6); add_field("I.CODCONTO", T_N, 42, 6); //Tipo record R add_field("R.NDOC", T_N, 1, 6); add_field("R.DATADOC", T_N, 7, 8); add_field("R.NPART", T_N, 15, 6); add_field("R.TIPOMOV", T_X, 21, 1); add_field("R.NRATA", T_N, 22, 6); add_field("R.IMPRATA", T_X, 28, 13); add_field("R.TIPORATA", T_X, 41, 1); add_field("R.DATASCAD", T_N, 42, 8); TText_recordset::load_file(filename); } //////////////////////////////// //// TIMPORTA_FAT_MSK //// //////////////////////////////// //Classe TImporta_fat_msk class TImporta_fat_msk : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TImporta_fat_msk(); }; TImporta_fat_msk::TImporta_fat_msk() :TAutomask ("lv4500a") {} bool TImporta_fat_msk::on_field_event(TOperable_field& f, TField_event e, long jolly) { return true; } //////////////////////////////// //// TIMPORTA_FAT_APP //// //////////////////////////////// //Classe TImporta_fat_app class TImporta_fat_app : public TSkeleton_application { TImporta_fat_msk* _msk; TDecodifica_codici* _codici; TArray _conti; TArray _importi; TLog_report * _log; int _prog; long _codcf; TString8 _abi; TString8 _cab; long _numdoc; protected: bool search_gr_sp_ca(const int gruppo, const char* specie, const int categoria); const TFilename crea_tmpdir() const; const TFilename crea_tmpdireff() const; const TFilename crea_nomefile(const long ndoc) const; const int segno_testata(const char sezione, const TCausale& cau) const; const int segno_riga(const char sezione, const TCausale& cau) const; const TString16 genera_real(const TVariant importo, const int segno = 1) const; const TString80 riclassifica_pconti(); TConfig* genera_testata(TImporta_fat_rec& recset, TFilename& tmpdir); void leggi_righe_cg(TImporta_fat_rec& recset, const TString& codcau); void genera_righe_iva(TImporta_fat_rec& recset, TConfig& conf, int & nriga, const TString& codcau); void genera_rate(TImporta_fat_rec& recset, TConfig& conf, int & nriga, const TString & tmpdireff); void elabora_file(const TFilename& tmpdir); void elabora_effetti(const TFilename& tmpdir); void elimina_file(const TFilename& tmpdir); public: virtual bool create(); virtual bool destroy(); virtual void main_loop(); void transfer(const TFilename& file); }; bool TImporta_fat_app::search_gr_sp_ca(const int gruppo, const char* specie, const int categoria) { return true; } //CREA_TMPDIR: crea la directory temporanea e restituisce il suo nome const TFilename TImporta_fat_app::crea_tmpdir() const { TFilename tmpdir; tmpdir.tempdir(); tmpdir.add("fatture"); make_dir(tmpdir); return tmpdir; } const TFilename TImporta_fat_app::crea_tmpdireff() const { TFilename tmpdir; tmpdir.tempdir(); tmpdir.add("effetti"); make_dir(tmpdir); return tmpdir; } //CREA_NOMEFILE: genera il nome del file dal numero documento const TFilename TImporta_fat_app::crea_nomefile(const long ndoc) const { TString strname; strname.format("%06ld", ndoc); strname << ".ini"; return strname; } //SEGNO_TESTATA: restituisce + o - uno a seconda che la sezione della riga in esame //e quella della prima riga della causale siano uguali o opposte const int TImporta_fat_app::segno_testata(const char sezione, const TCausale& cau) const { return cau.sezione_clifo() == sezione ? 1 : -1; } //SEGNO_TESTATA: restituisce + o - uno a seconda che la sezione della riga in esame //e quella della prima riga della causale siano opposte o uguali const int TImporta_fat_app::segno_riga(const char sezione, const TCausale& cau) const { return cau.sezione_clifo() == sezione ? -1 : 1; } //GENERA_REAL: crea il numero reale, aggiungendo i decimali e tenendo conto del segno corretto const TString16 TImporta_fat_app::genera_real(const TVariant importo, const int segno) const { real imp = importo.as_real(); imp /= CENTO; imp *= segno; return imp.string(); } //GENERA_TESTATA: genero il paragrafo testata TConfig* TImporta_fat_app::genera_testata(TImporta_fat_rec& recset, TFilename& tmpdir) { const long ndoc = recset.get("C.NDOC").as_int(); const TDate datadoc = recset.get("C.DATADOC").as_date(); const TCausale cau(recset.get("C.CODCAU").as_string()); const int segno = segno_testata(recset.get("C.SEZIONE").as_string()[0], cau); TFilename nomefile = tmpdir; nomefile << '\\' << crea_nomefile(ndoc); TConfig* conf = new TConfig(nomefile); conf->set_paragraph("Transaction"); //setto il paragrafo [Transaction] del file ini conf->set("Action","INSERT"); conf->set("Mode", "AUTO"); TString paragraph; paragraph.format("%d", LF_MOV); conf->set_paragraph(paragraph); //setto il paragrafo [23] del file ini (testata) conf->set(MOV_ANNOES, datadoc.year()); conf->set(MOV_DATAREG, datadoc); conf->set(MOV_DATACOMP, datadoc); conf->set(MOV_DATADOC, datadoc); _numdoc = ndoc; conf->set(MOV_NUMDOC, ndoc); conf->set(MOV_CODCAUS, _msk->get_bool(F_DECCAU) ? atol(_codici->decodifica_causali(recset.get("C.CODCAU").as_int())) : recset.get("C.CODCAU").as_int()); conf->set(MOV_ANNOIVA, datadoc.year()); TString regiva(recset.get("C.REGIVA").as_string()); regiva << format("%02d", recset.get("C.NREGIVA").as_int()); conf->set(MOV_REG, _codici->decodifica_regiva(atoi(regiva))); const TString & codval = _msk->get_bool(F_DECVAL) ? _codici->decodifica_valute(recset.get("C.CODVAL").as_int()) : recset.get("C.CODVAL").as_string(); if (!::is_firm_value(codval) && codval != "EURO") conf->set(MOV_CODVAL, codval); conf->set(MOV_TIPO, 'C'); _codcf = recset.get("C.CODCF").as_int(); conf->set(MOV_CODCF, _codcf); _abi = recset.get("C.ABI").as_string().mid(1); _cab = recset.get("C.CAB").as_string().mid(1); conf->set(MOV_TOTDOC, genera_real(recset.get("C.IMPORTO"), segno)); conf->set(MOV_CODPAG, _msk->get_bool(F_DECCDP) ? atol(_codici->decodifica_condpag(recset.get("C.CODPAG").as_int())) : recset.get("C.CODPAG").as_int()); conf->set(PART_ANNO, datadoc.year()); conf->set(PART_NUMPART, datadoc.month()); _conti.destroy(); _importi.destroy(); return conf; } //GENERA_RIGHE_IVA: genero le righe IVA void TImporta_fat_app::leggi_righe_cg(TImporta_fat_rec& recset, const TString& codcau) { const char sezione = recset.get("G.SEZIONE").as_string()[0]; const TCausale cau(codcau); const int segno = segno_riga(sezione, cau); const TBill& conto = _codici->decodifica_conto(recset.get("G.CODMASTRO").as_int(), recset.get("G.CODCONTO").as_int()); const real importo = genera_real(recset.get("G.IMPORTO"), segno); _conti.add(new TBill(conto)); _importi.add(importo); } //GENERA_RIGHE_IVA: genero le righe IVA void TImporta_fat_app::genera_righe_iva(TImporta_fat_rec& recset, TConfig& conf, int & nriga, const TString& codcau) { const TDate datadoc = recset.get("I.DATADOC").as_date(); const char sezione = recset.get("I.SEZIONE").as_string()[0]; const TCausale cau(codcau); const int segno = segno_riga(sezione, cau); // const TBill& conto = _codici->decodifica_conto(recset.get("I.CODMASTRO").as_int(), recset.get("I.CODCONTO").as_int()); TGeneric_distrib dm(recset.get("I.IMPONIBILE").as_real() * segno / CENTO, 2); TGeneric_distrib dv(recset.get("I.IMPOSTA").as_real() * segno / CENTO, 2); FOR_EACH_ARRAY_ITEM(_importi, r, obj) { real * slice = (real *) obj; dm.add(*slice); dv.add(*slice); } real imp; real iva; FOR_EACH_ARRAY_ITEM(_conti, r1, obj1) { TString paragraph; paragraph.format("%d,%d", LF_RMOVIVA, ++nriga); conf.set_paragraph(paragraph); conf.set(RMI_ANNOES, datadoc.year()); conf.set(RMI_CODIVA, _msk->get_bool(F_DECCODIVA) ? atol(_codici->decodifica_codiva(recset.get("I.CODIVA").as_int())) : recset.get("I.CODIVA").as_int()); conf.set(RMI_IMPONIBILE, dm.get().string(0, 2)); conf.set(RMI_IMPOSTA, dv.get().string(0, 2)); TBill * conto = (TBill *) obj1; conf.set(RMI_GRUPPO, conto->gruppo()); conf.set(RMI_CONTO, conto->conto()); conf.set(RMI_SOTTOCONTO, conto->sottoconto()); } } //GENERA_RATE: genero le righe su SCAD void TImporta_fat_app::genera_rate(TImporta_fat_rec& recset, TConfig& conf, int & nriga, const TString & tmpdireff) { const TDate datadoc = recset.get("R.DATADOC").as_date(); TString paragraph; paragraph.format("%d,%d", LF_SCADENZE, ++nriga); conf.set_paragraph(paragraph); conf.set(SCAD_ANNO, datadoc.year()); conf.set(SCAD_NUMPART, datadoc.month()); conf.set(SCAD_NRIGA, nriga); conf.set(SCAD_NRATA, recset.get("R.NRATA").as_int()); //??? CODPAG ???// int tipopag = recset.get("R.TIPORATA").as_int(); if (tipopag == 3) tipopag = 0; else if (tipopag == 2) tipopag = 3; conf.set(SCAD_TIPOPAG, tipopag); conf.set(SCAD_IMPORTO, genera_real(recset.get("R.IMPRATA"))); // conf.set(SCAD_IMPORTOVAL, genera_real(recset.get("R.IMPORTO"))); //NON SO IN QUALE DEI DUE VADA conf.set(SCAD_DATASCAD, recset.get("R.DATASCAD").as_date()); //??? ABI CAB GRUPPO CONTO SOTTOCONTO ???// if (tipopag == 3) { TString tmp(tmpdireff); tmp << "/" << ++_prog << ".ini" ; TConfig confeff(tmp); confeff.set_paragraph("Transaction"); //setto il paragrafo [Transaction] del file ini confeff.set("Action","INSERT"); confeff.set("Mode", "AUTO"); TString paragraph; paragraph.format("%d", LF_EFFETTI); confeff.set_paragraph(paragraph); confeff.set(EFF_DATASCAD, recset.get("R.DATASCAD").as_date()); confeff.set(EFF_TIPOPAG, tipopag); confeff.set(EFF_TIPOCF, "C"); confeff.set(EFF_CODCF, _codcf); confeff.set(EFF_CODABI, _abi); confeff.set(EFF_CODCAB, _cab); confeff.set(EFF_EFFCOMP, "X"); confeff.set(REFF_IMPORTO, genera_real(recset.get("R.IMPRATA"))); confeff.set(REFF_NFATT, _numdoc); confeff.set(REFF_ANNO, datadoc.year()); confeff.set(REFF_NUMPART, datadoc.month()); confeff.set(REFF_NRATA, recset.get("R.NRATA").as_int()); } } //ELABORA_FILE: chiamo la prima nota su tutti gli ini che ho generato void TImporta_fat_app::elabora_file(const TFilename& tmpdir) { TString_array res; TString files; files << tmpdir << "/*.ini"; list_files(files, res); if (res.items() > 0) { TString app; app << "cg2 -0 -i" << tmpdir << "/*.ini"; TExternal_app primanota(app); primanota.run(); FOR_EACH_ARRAY_ROW(res, r, f) remove_file((const char *) *f); } } void TImporta_fat_app::elabora_effetti(const TFilename& tmpdir) { TString_array res; TString files; files << tmpdir << "/*.ini"; list_files(files, res); if (res.items() > 0) { TString app; app << "ef0 -0 -i" << tmpdir << "/*.ini"; TExternal_app effetti(app); effetti.run(); FOR_EACH_ARRAY_ROW(res, r, f) remove_file((const char *) *f); } } void TImporta_fat_app::transfer(const TFilename& file) { TImporta_fat_rec recset(file); TConfig* configfile = NULL; TFilename tmpdir = crea_tmpdir(); TFilename tmpdireff = crea_tmpdireff(); int nrigai, nrigar; _prog = 0; TProgind pi(recset.items(), "Importazione in corso...", true, true); TString16 codcau; for(bool ok = recset.move_first(); ok; ok = recset.move_next()) { if (!pi.addstatus(1)) break; const char tipomov = recset.get("TIPOMOV").as_string()[0]; switch(tipomov) { case 'C': { if(configfile != NULL) delete configfile; codcau = recset.get("C.CODCAU").as_string(); configfile = genera_testata(recset, tmpdir); nrigai = nrigar = 0; } break; case 'G': leggi_righe_cg(recset, codcau); break; case 'I': genera_righe_iva(recset, *configfile, nrigai, codcau); break; case 'R': genera_rate(recset, *configfile, nrigar, tmpdireff); break; default: break; } } if(configfile != NULL) delete configfile; TReport_book book; book.add(*_log); book.print_or_preview(); _log->reset(); bool ok = true; if (_codici->errors()) ok = yesno_box("Sono stati rilevati errori, si desidera proseguire con l'importazione"); if (ok) { elabora_file(tmpdir); elabora_effetti(tmpdireff); } } bool TImporta_fat_app::create() { _msk = new TImporta_fat_msk(); _log = new TLog_report("Importazione fatture vecchio COGECO"); _codici = new TDecodifica_codici(_log); return TSkeleton_application::create(); } bool TImporta_fat_app::destroy() { delete _msk; delete _log; return TApplication::destroy(); } void TImporta_fat_app::main_loop() { if ( _msk->run() == K_ENTER) { //genero il nome del file da caricare TFilename file = _msk->get(F_NAME); if(!file.exist()) { error_box(TR("Il file selezionato non esiste; si prega di controllare")); return; } transfer(file); } } int lv4500 (int argc, char* argv[]) { TImporta_fat_app main_app; main_app.run(argc, argv, TR("Importazione fatture Vecchio COGECO")); return true; }