#include #include #include #include #include #include #include "tc8.h" #include "tc8100a.h" #include "../ve/velib.h" #include "comuni.h" /////////////////////////////////////////////////////////// // TClient_textset /////////////////////////////////////////////////////////// class TClifo_recset : public TCSV_recordset { TAssoc_array _index; protected: virtual TRecnotype new_rec(const char* buf = NULL); public: const TString& rag_sociale(const char& tipocli) const; const TString& crea_indirizzo(const char& tipocli) const; TClifo_recset(const char * query); }; TRecnotype TClifo_recset::new_rec(const char* buf) { TToken_string str(256,'\t'); //nuovo record tab separator if(buf && *buf) { bool apici=false; for (const char* c = buf; *c ; c++) { if (*c == '"') { apici = !apici; } else { if (*c == ';') { if (!apici) str << str.separator(); else str << *c; } else str << *c; } } } const TRecnotype n = TText_recordset::new_rec(str); if (n >= 0) row(n).separator(str.separator()); return n; } //funzione che crea il campo ragione sociale dai campi opportuni del file csv const TString& TClifo_recset::rag_sociale(const char& tipocli) const { const TString& nome = get(7).as_string(); TString ragsoc = get(6).as_string(); if (tipocli == 'F') { ragsoc.cut(30); ragsoc.left_just(30); ragsoc << nome; } else { ragsoc << " " << nome; } ragsoc.cut(50); return get_tmp_string() = ragsoc; } //funzione che costruisce l'indirizzo dai campi opportuni del file csv const TString& TClifo_recset::crea_indirizzo(const char& tipocli) const { TString via; if (tipocli == 'F') { via << get(23).as_string() << " " << get(24).as_string(); } else { via << get(19).as_string() << " " << get(20).as_string(); } return get_tmp_string() = via; } TClifo_recset::TClifo_recset(const char * fileName) : TCSV_recordset("CSV(;)\n") { load_file(fileName); } /////////////////////////////////////////////////////////// // TAutomask /////////////////////////////////////////////////////////// class TImportaClifo_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TImportaClifo_mask(); }; TImportaClifo_mask::TImportaClifo_mask() :TAutomask ("tc8100a") { } bool TImportaClifo_mask::on_field_event(TOperable_field& f, TField_event e, long jolly) { switch (f.dlg()) { //giochetto per avere la lista dei files validi nella directory di trasferimento! case F_CLIFIS: if (e == fe_button) { TArray_sheet as(-1, -1, 72, 20, TR("Selezione file"), "File@32"); TFilename path = get(F_PATH); path.add("*.csv"); //files delle testate list_files(path, as.rows_array()); TFilename name; FOR_EACH_ARRAY_ROW(as.rows_array(), i, row) { name = *row; *row = name.name(); } if (as.run() == K_ENTER) { f.set(as.row(as.selected())); } } break; case F_CLIGIU: if (e == fe_button) { TArray_sheet as(-1, -1, 72, 20, TR("Selezione file"), "File@32"); TFilename path = get(F_PATH); path.add("*.csv"); //files delle testate list_files(path, as.rows_array()); TFilename name; FOR_EACH_ARRAY_ROW(as.rows_array(), i, row) { name = *row; *row = name.name(); } if (as.run() == K_ENTER) { f.set(as.row(as.selected())); } } break; default: break; } return true; } /////////////////////////////////////// // TSkeleton_application /////////////////////////////////////// class TClifoCSV : public TSkeleton_application { virtual bool check_autorization() const {return false;} virtual const char * extra_modules() const {return "ve";} TImportaClifo_mask* _msk; protected: //metodi per la ricerca dei clienti / fornitori bool find_clifo(const char tipo, const long cod) const; //metodi per la gestione dei dati dell'anagrafica void pulisci_cap(TString& cap) const; void estrai_numero(TString& telefono, TString& pref, TString& num) const; const TString comune2cap(TString& comune) const; void gest_localita(TString& comune, TString& cap, TString& codcom, const TString& prov, const TString& stato = EMPTY_STRING) const; //metodi per la gestione dei dati documenti const char statodoc(const TString4& tipo) const; void add_riga_spese(TDocumento& doc, const TClifo_recset& s, int spesa) const; //metodi per l'inserimento dei dati sulle tabelle corrette void upload_clifis(const TFilename& file, TLog_report& log) const; void upload_cligiu(const TFilename& file, TLog_report& log) const; void upload_fattEric(const TFilename& file, TLog_report& log, const int ti) const; public: virtual bool create(); virtual bool destroy(); virtual void main_loop(); bool transfer(); TClifoCSV() {}; }; TClifoCSV& app() { return (TClifoCSV&) main_app(); } ///////////////////////////////// // GESTIONE ANAGRAFICHE // ///////////////////////////////// ///////////////////////////////// // ricerca clifo ///////////////////////////////// //funzione che ricerca un cliente o un fornitore nel file clifo di campo in base al CODCF bool TClifoCSV::find_clifo(const char tipo, const long cod) const { TString16 key; key.format("%c|%ld", tipo, cod); return !cache().get(LF_CLIFO, key).empty(); } ///////////////////////////////// // gestione dati anagrafici ///////////////////////////////// //funzione che elimina eventuali caratteri non numerici dalla stringa del CAP void TClifoCSV::pulisci_cap(TString& cap) const { TString8 str; for (int i = 0; cap[i] && str.len() < 5; i++) if (isdigit(cap[i])) str << cap[i]; cap = str; } //funzione che separa il prefisso dal numero di telefono void TClifoCSV::estrai_numero(TString& telefono, TString& pref, TString& num) const { bool pre = true; TString str1; TString str2; telefono.trim(); for (int i = 0; telefono[i]; i++) { if(isdigit(telefono[i])) //se il carattere letto č una cifra numerica, allora concatenalo alla stringa corretta { if (pre) str1 << telefono[i]; else str2 << telefono[i]; } else { if (pre) pre = i<=1; //considero il prefisso finito se č composto da almeno 2 caratteri else { if (str2.len() >= 6) //considero il numero finito se č composto da alemno 6 cifre break; } } } if (str2.full()) { pref = str1; num = str2; } else { pref.cut(0); num = str1; } } //funzione che estrae il cap dalla tabella comuni dato il nome del comune const TString TClifoCSV::comune2cap(TString& comune) const { TLocalisamfile comuni(LF_COMUNI); TRectype& rec = comuni.curr(); TString up_comune = comune; up_comune.upper(); TString cap; comuni.setkey(2); rec.put(COM_DENCOM,up_comune); comuni.read(); cap = rec.get(COM_CAPCOM); return get_tmp_string() = cap; } //funzione che gestisce le localitā void TClifoCSV::gest_localita(TString& comune, TString& cap, TString& codcom, const TString& prov, const TString& stato) const { comune.trim(); //se stato č settato vuol dire stato estero, e lo scrivo cosė com'č nella localitā if (stato.full()) { comune << " - " << stato; return; } //se sto inserendo una cittā italiana, cerco di riempire il CAP se č vuoto if (cap.empty()) cap = comune2cap(comune); //se sono riuscito a riempirlo, o era giā pieno, ricerca il codice comune if (cap.full()) { pulisci_cap(cap); codcom = cap2comune(cap,comune); } //se non sono riuscito a trovare il codice comune, prepara aggiungi al comune la provincia (dove esiste) if (codcom.blank()) { if (prov.full()) comune << " (" << prov << ")"; } return; } ///////////////////////////////// // inserimento clifo ///////////////////////////////// //funzione che effettua l'inserimento delle persone fisiche sulla tabella CLIFO void TClifoCSV::upload_clifis(const TFilename& file, TLog_report& log) const { char tipo = 'C'; char tipocli = 'F'; TClifo_recset s(file); TLocalisamfile clifo(LF_CLIFO); TProgind pi(s.items(),"Importazione anagrafiche persone fisiche in corso...",true,true); for (bool ok=s.move_first();ok;ok=s.move_next()) { if (!pi.addstatus(1)) break; long cod; TString ragsoc; //salto la prima riga del file, che contiene le intestazioni delle colonne //salto tutte le righe dei fornitori (inserisco solo clienti) if ((!s.get(0).as_int()) || (s.get(5).as_string().full() && s.get(4).as_string().empty())) { continue; } if (s.get(4).as_string().full()) { cod = s.get(4).as_int(); } ragsoc = s.rag_sociale(tipocli); //eseguo tutto SOLO se riesco a riempire la ragione sociale if (ragsoc.full()) { const TString16 cofi = s.get(3).as_string(); //get da file del cod. fisc. const TString16 paiv = s.get(2).as_string(); //get da file della p. iva const bool var = find_clifo(tipo,cod); //controllo se il clifo esiste giā clifo.zero(); clifo.put(CLI_TIPOCF, tipo); clifo.put(CLI_CODCF,cod); if (var) { clifo.read(); } clifo.put(CLI_RAGSOC, ragsoc); //ragsoc clifo.put(CLI_TIPOAPER, tipocli); //tipocliente (F o G) clifo.put(CLI_PAIV, paiv); //p.iva clifo.put(CLI_COFI, cofi); //cod. fisc. //inserisci di dati della residenza TString indirizzo = s.crea_indirizzo(tipocli); clifo.put(CLI_INDCF, indirizzo); //indirizzo clifo.put(CLI_CIVCF, s.get(25).as_string()); //num. civico TString80 comune = s.get(18).as_string(); //comune o localita' TString cap = s.get(21).as_string(); TString prov = s.get(22).as_string(); TString codcom; gest_localita(comune, cap, codcom, prov); //se cap č pieno, allora inseriscilo if (cap.full()) clifo.put(CLI_CAPCF, cap); //cap //se codcom č vuoto, allora o il cap č rimasto vuoto, oppure č una frazione; //in entrambi i casi bisogna inserire tutto in localitā if (codcom.blank()) clifo.put(CLI_LOCCF, comune); else { clifo.put(CLI_COMCF, codcom); //inserisci il codice del comune, recuperato tramite il cap clifo.put(CLI_LOCCF, s.get(20).as_string()); //inserisci la frazione se č indicata } //inserisci i numeri di telefono (telefono, altro telefono, fax) for (int i = 27; i<30; i++) { TString telefono = s.get(i).as_string(); //esegui le operazioni sul numero solo se č presente sul file da importare if (telefono.full()) { TString pref; TString num; estrai_numero(telefono, pref, num); switch (i) { case 27: clifo.put(CLI_PTEL,pref); clifo.put(CLI_TEL,num); break; //inserisci il numero di telefono case 28: clifo.put(CLI_PTEL2,pref); clifo.put(CLI_TEL2,num); break; //inserisci il secondo numero di telefono case 29: clifo.put(CLI_PFAX,pref); clifo.put(CLI_FAX,num); break; //inserisci il numero di fax default: break; } } } //inserisci l'indrizzo e-mail clifo.put(CLI_MAIL,s.get(30).as_string()); //inserisci dati di nascita TString stato = s.get(14).as_string(); comune = s.get(11).as_string(); //comune o localita' cap = s.get(12).as_string(); prov = s.get(13).as_string(); codcom.cut(0); gest_localita(comune, cap, codcom, prov, stato); //questo modo di gestire le cose ignora le localitā estere; visto il modo in cui sono codificati //gli stati esteri non c'č modo di risalire al rispettivo codice internazionale //Si rimanda ad ulteriori chiarimenti la trattazione degli stati esteri //se codcom č pieno, allora č nato in italia in un comune riconosciuto if (codcom.full()) clifo.put(CLI_COMNASC, codcom); //inserisci il codice del comune, se sei riuscito a recuperarlo //inserisci la data di nascita TDate datan = s.get(10).as_date(); clifo.put(CLI_DATANASC,datan); const char* tp = tipo == 'C' ? TR("Cliente") : TR("Fornitore"); TString str; str << "Il "<< tp << " codice (" << clifo.get(CLI_CODCF) <<") " << ragsoc << " "; if (var) { const int err = clifo.rewrite(); if (err == NOERR) { str << "č stato aggiornato"; log.log(0, str); } else { str << "NON č stato aggiornato. Errore " << err; log.log(2, str); } } else { const int err = clifo.write(); if (err == NOERR) { str << "č stato inserito"; log.log(0, str); } else { str << "NON č stato inserito. Errore " << err; log.log(2, str); } } if (cofi.empty() && paiv.empty()) { TString str; str << "Il " << tp << ' ' << ragsoc << " non ha nč CODICE FISCALE nč PARTITA IVA"; log.log(1, str); } } } return; } //funzione che effettua l'inserimento delle persone giuridiche sulla tabella CLIFO void TClifoCSV::upload_cligiu(const TFilename& file, TLog_report& log) const { char tipo = 'C'; char tipocli = 'G'; TClifo_recset s(file); TLocalisamfile clifo(LF_CLIFO); TProgind pi(s.items(),"Importazione anagrafiche persone giuridiche in corso...",true,true); for (bool ok=s.move_first();ok;ok=s.move_next()) { if (!pi.addstatus(1)) break; long cod; TString ragsoc; //salto la prima riga del file, che contiene le intestazioni delle colonne //salto tutte le righe dei fornitori (inserisco solo clienti) if ((!s.get(0).as_int()) || (s.get(5).as_string().full() && s.get(4).as_string().empty())) { continue; } //leggo il codice cliente if (s.get(4).as_string().full()) { cod = s.get(4).as_int(); } ragsoc = s.rag_sociale(tipocli); //eseguo tutto SOLO se riesco a riempire la ragione sociale if (ragsoc.full()) { const TString16 cofi = s.get(3).as_string(); //get da file del cod. fisc. const TString16 paiv = s.get(2).as_string(); //get da file della p. iva const bool var = find_clifo(tipo,cod); //controllo se il clifo esiste giā clifo.zero(); clifo.put(CLI_TIPOCF, tipo); clifo.put(CLI_CODCF,cod); if (var) { //se esiste leggo il record corrispondente clifo.read(); } clifo.put(CLI_RAGSOC, ragsoc); //ragsoc clifo.put(CLI_TIPOAPER, tipocli); //tipo cliente (F o G) clifo.put(CLI_PAIV, paiv); //p.iva clifo.put(CLI_COFI, cofi); //cod. fisc. //inserisci di dati della residenza TString indirizzo = s.crea_indirizzo(tipocli); clifo.put(CLI_INDCF, indirizzo); //indirizzo clifo.put(CLI_CIVCF, s.get(21).as_string()); //num. civico TString80 comune = s.get(14).as_string(); //comune o localita' TString cap = s.get(17).as_string(); TString prov = s.get(18).as_string(); TString codcom; gest_localita(comune, cap, codcom, prov); //se cap č pieno, allora inseriscilo if (cap.full()) clifo.put(CLI_CAPCF, cap); //cap //se codcom č vuoto, allora o il cap č rimasto vuoto, oppure č una frazione; //in entrambi i casi bisogna inserire tutto in localitā if (codcom.blank()) clifo.put(CLI_LOCCF, comune); else { clifo.put(CLI_COMCF, codcom); //inserisci il codice del comune, recuperato tramite il cap clifo.put(CLI_LOCCF, s.get(16).as_string()); //inserisci la frazione se č indicata } //inserisci i numeri di telefono (telefono, altro telefono, fax) for (int i = 23; i<26; i++) { TString telefono = s.get(i).as_string(); //esegui le operazioni sul numero solo se č presente sul file da importare if (telefono.full()) { TString pref; TString num; estrai_numero(telefono, pref, num); switch (i) { case 27: clifo.put(CLI_PTEL,pref); clifo.put(CLI_TEL,num); break; //inserisci il numero di telefono case 28: clifo.put(CLI_PTEL2,pref); clifo.put(CLI_TEL2,num); break; //inserisci il secondo numero di telefono case 29: clifo.put(CLI_PFAX,pref); clifo.put(CLI_FAX,num); break; //inserisci il numero di fax default: break; } } } //inserisci l'indrizzo e-mail clifo.put(CLI_MAIL,s.get(26).as_string()); const char* tp = tipo == 'C' ? TR("Cliente") : TR("Fornitore"); TString str; str << "Il "<< tp << " codice (" << clifo.get(CLI_CODCF) <<") " << ragsoc << " "; if (var) { const int err = clifo.rewrite(); if (err == NOERR) { str << "č stato aggiornato"; log.log(0, str); } else { str << "NON č stato aggiornato. Errore " << err; log.log(2, str); } } else { const int err = clifo.write(); if (err == NOERR) { str << "č stato inserito"; log.log(0, str); } else { str << "NON č stato inserito. Errore " << err; log.log(2, str); } } if (cofi.empty() && paiv.empty()) { TString str; str << "Il " << tp << ' ' << ragsoc << " non ha nč CODICE FISCALE nč PARTITA IVA"; log.log(1, str); } } } return; } ///////////////////////////////// // GESTIONE DOCUMENTI // ///////////////////////////////// //funzione che preleva lo stato del documento direttamente dalla tabella TIP const char TClifoCSV::statodoc(const TString4& tipodoc) const { char stato; //prendo lo stato del documento dai parametri del tipo documento //se non riesco a trovarlo lo setto di default a 1 const TString80 stringa = cache().get("%TIP", tipodoc, "S2"); // stato inserimento del tipodoc if (isdigit(stringa[0])) stato = stringa[0]; else stato = 1; return stato; } //funzione che aggiunge una riga spesa al documento void TClifoCSV::add_riga_spese(TDocumento& doc, const TClifo_recset& s, int spesa) const { TString tiposp; int colonna = 0; switch (spesa) { case 2: tiposp = _msk->get(F_SPESEIVA); colonna = 13; break; //tipo spesa per Spese soggette IVA case 3: tiposp = _msk->get(F_MBOLLO); colonna = 20; break; //tipo spesa per Marca da bollo default: tiposp = _msk->get(F_TOT10E15); colonna = 11; break; //tipo spesa per tot. art. 10e15 } //inserisco l'ammontare della fattura const TCurrency tmp = s.get(colonna).as_real() / CENTO; if (!tmp.is_zero()) { const TRectype& rec_spp = cache().get("SPP", tiposp); //leggi il record della tabella SPP corrispondente al codice spesa inserito const TString& tipo_riga_spp = rec_spp.get("S8"); //leggi dalla tabella il tipo della spesa // Crea una riga del tipo corretto TRiga_documento& rdoc = doc.new_row(tipo_riga_spp); //inserisco il codice articolo //CODARTMAG va riempito SOLO se si tratta di una riga merce rdoc.put(RDOC_CODART, tiposp); rdoc.put(RDOC_CHECKED, "X"); //inserisco la quantitā rdoc.put(RDOC_QTA,1); rdoc.put(RDOC_PREZZO,tmp); //inserisco l'importo della spesa //inserisco il codice IVA rdoc.put(RDOC_CODIVA,rec_spp.get("S3")); } } /////////////////////////////////////////////// // importazione fatture e delle ricevute /////////////////////////////////////////////// //funzione che effettua l'inserimento sulla tabella DOCUMENTI e RIGA DOCUMENTI (inserisce le fatture e/o le ricevute) void TClifoCSV::upload_fattEric(const TFilename& file, TLog_report& log, const int ti) const { TClifo_recset s(file); char stato = 1; char* head; TString numerazione; TString tipodoc; if (ti == 1) { numerazione = _msk->get(F_NUMFAT); tipodoc = _msk->get(F_TIPODOC1); head = "Importazione fatture in corso ..."; } else { numerazione = _msk->get(F_NUMRIC); tipodoc = _msk->get(F_TIPODOC2); head = "Importazione ricevute in corso ..."; } //tipo prestazione TString tipoprs = _msk->get(F_COMPETENZE); TAssoc_array codiva; // per ogni riga letta dallo sheet TSheet_field& st = _msk->sfield(F_TIPI); //carico tutti le righe dello sheet che ho creato nella maschera FOR_EACH_SHEET_ROW(st, i, row) { //prendo la percentuale IVA scritta da loro e la uso come chiave dell'array real aliquota = row->get(0); aliquota *= CENTO; TString4 periv = aliquota.string(4, 0, '0'); TString4 codiv = row->get(1); codiva.add(periv, codiv); //prendo in codice IVA di campo corrispondente e lo metto nell'array } TProgind pi(s.items(),head,true,true); for (bool ok=s.move_first();ok;ok=s.move_next()) { if (!pi.addstatus(1)) break; //salto la prima riga del file, che contiene le intestazioni delle colonne if (!s.get(0).as_int()) { continue; } const long cod = s.get(4).as_int(); //estrai dal file il codice utente if (!find_clifo('C',cod)) //controllo se il cliente esiste sulla tabella delle anagrafiche { TString str; str << "Il cliente con codice " << cod << " non č presente in anagrafica "; log.log(1, str); } // creo il documento e inserisco tutti i dati relativi alla testata //N.B.: il campo 6 del file da importare contiene l'anno di emissione della fattura o della ricevuta, //il 7 il numero della fattura o della ricevuta TDocumento* doc = new TDocumento('D', s.get(6).as_int(), numerazione, s.get(7).as_int()); doc->destroy_rows(); TDate datafat = s.get(8).as_date(); doc->put(DOC_DATADOC,datafat); //inserisco la data di emissione della fattura o della fasttura const char stato = statodoc(tipodoc); doc->put(DOC_STATO,stato); //inserisco lo stato del documento doc->put(DOC_TIPODOC, tipodoc); //inserisco il tipo documento doc->put(DOC_TIPOCF, 'C'); //specifico il TIPOCF doc->put(DOC_CODCF, cod); //inserisco il codice cliente //se devo inserire una spesa relativa alla voce Tot. Art. 10e15, allora if (!s.get(11).is_zero()) add_riga_spese(*doc, s, 1); //se devo inserire una spesa relativa alla voce Spese soggette IVA, allora if (!s.get(13).is_zero()) add_riga_spese(*doc, s, 2); //se devo inserire una spesa relativa alla voce Marche da bollo, allora if (!s.get(20).is_zero()) add_riga_spese(*doc, s, 3); //inserisco la riga prestazione delle competenze TRiga_documento& rdoc = doc->new_row("06"); //crea una riga del tipo corretto relativa alle prestazioni //inserisco il codice articolo rdoc.put(RDOC_CODART, tipoprs); rdoc.put(RDOC_CHECKED, "X"); //inserisco la quantitā rdoc.put(RDOC_QTA,1); //inserisco l'ammontare dell'Imponibile const TCurrency imp = s.get(23).as_real() / CENTO; rdoc.put(RDOC_PREZZO,imp); const TString& perivfile = s.get(16).as_string(); //prendo dal file la percentuale IVA sull'imponibile const TString* pcodimp = (TString*)codiva.objptr(perivfile); const TString& codimp = pcodimp ? *pcodimp : st.cell(0, 1); rdoc.put(RDOC_CODIVA, codimp); doc->write(); delete doc; } } bool TClifoCSV::transfer() { TLog_report log("Trasferimento Anagrafiche"); TLog_report log1("Trasferimento Fatture e Ricevute"); //prelevo il path dei file da caricare dalla maschera TFilename path = _msk->get(F_PATH); const short ids [] = {F_CLIFIS,F_CLIGIU,F_NAMEFAT,F_NAMERIC,0}; //eseguo tutte le importazioni (una alla volta) for (int i = 0; ids[i]; i++) { //prelevo di volta in volta il nome del file giusto dalla maschera: //prima il file Anagrafiche, poi quello delle fatture e poi quello delle ricevute TFilename name = _msk->get(ids[i]); //se sono riuscito a prelevare un nome di file, allora: if (name.full()) { //costruisco il nome del file TFilename full = path; full.add(name); //se eiste il file, esegui l'elaborazione corretta if (full.exist()) { switch (i) { case 0: upload_clifis(full, log); break; case 1: upload_cligiu(full, log); break; case 2: upload_fattEric(full, log1, 1); break; case 3: upload_fattEric(full, log1, 2); break; default: break; } } } } TReport_book buc; TReport_book buc1; buc.add(log); if (buc.pages()>0) buc.preview(); //visualizzo il log di importazione delle anagrafiche buc1.add(log1); if (buc1.pages()>0) buc1.preview(); //visualizzo il log di importazione dei documenti return true; } bool TClifoCSV::create() { _msk = new TImportaClifo_mask(); return TSkeleton_application::create(); } bool TClifoCSV::destroy() { delete _msk; return TApplication::destroy(); } void TClifoCSV::main_loop() { KEY tasto; tasto = _msk->run(); if (tasto == K_ENTER) { if (transfer()) { message_box(TR("Importazione completata")); } } } int tc8100 (int argc, char* argv[]) { TClifoCSV main_app; main_app.run(argc, argv, TR("Importazione da Semetra")); return true; }