#include #include #include #include #include #include #include #include "../ca/calib01.h" #include "../ca/movana.h" #include "../ca/rmovana.h" #include "../cg/cglib01.h" #include "ps1001.h" #include "ps1001100a.h" /////////////////////////////////////////////////////////// // TAutomask /////////////////////////////////////////////////////////// class TImporta_movana_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TImporta_movana_mask(); }; TImporta_movana_mask::TImporta_movana_mask() :TAutomask ("ps1001100a") { } bool TImporta_movana_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { //giochetto per avere la lista dei files validi nella directory di trasferimento! case F_NAME: 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) { o.set(as.row(as.selected())); } } break; //controlli sui campi della testata documento case F_DATAREG: if ((e == fe_modify || e == fe_close) && !query_mode()) { const TDate datareg = o.get(); const TEsercizi_contabili ec; if (ec.date2esc(datareg) <= 0) return error_box(((TEdit_field&)o).get_warning()); if (e == fe_close && field(F_DATACOMP).empty()) set(F_DATACOMP, datareg); } break; case F_DATACOMP: if ((e == fe_modify || e == fe_close) && !query_mode()) { const TDate datareg = get(F_DATAREG); TDate datacomp = o.get(); if (!datacomp.ok()) datacomp = datareg; const bool preventivo = get(F_TIPO).full(); //i movimenti normali devono avere data competenza nel presente o passato!! if (!preventivo && datacomp > datareg) return error_box(TR("La data di competenza non puo' superare la data di registrazione")); const TEsercizi_contabili ec; int ae = ec.date2esc(datacomp); //movimenti preventivi in esercizi futuri if (ae <= 0 && preventivo && datacomp > datareg) ae = ec.date2esc(datareg) + datacomp.year() - datareg.year(); if (ae > 0) set(F_ANNOES, ae, 0x1); else return error_box(((TEdit_field&)o).get_warning()); const int ar = ec.date2esc(datareg); const int ap = ec.pred(ar); //preventivi un anno indietro, nel presente o nel futuro if (preventivo) { if (ae < ap) return error_box(FR("La data di competenza non può precedere l'esercizio %d"), ap); } else //normali solo un anno indietro o nel presente { if (ae != ar && ae != ap) return error_box(FR("La data di competenza deve appartenere all'esercizio in corso o al precedente")); } } break; case F_DATAFCOMP: if (e == fe_modify || e == fe_close) { const TDate datacomp = get(F_DATACOMP); const TDate datafcomp = o.get(); if (datafcomp.ok()) { if (datafcomp < datacomp) return error_box(((TEdit_field&)o).get_warning()); } else o.set(datacomp.string()); //se la data fine competenza viene lasciata vuota -> e' uguale alla datacomp } break; default: break; } return true; } ///////////////////////////////////////////////////////////// // Recordset specifici per i dati da trasferire ///////////////////////////////////////////////////////////// class TImporta_movana_recordset : public TCSV_recordset { char _sep_field; protected: virtual TRecnotype new_rec(const char* buf = NULL); public: TImporta_movana_recordset(const char * fileName, char sep); }; TRecnotype TImporta_movana_recordset::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 == _sep_field) //tipo di separatore dei campi che si trova nel record di origine { 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; } TImporta_movana_recordset::TImporta_movana_recordset(const char * filename, char sep_field) : TCSV_recordset("CSV(;)"), _sep_field(sep_field) //separatore campi { load_file(filename); } /////////////////////////////////////// // TSkeleton_application /////////////////////////////////////// class TImporta_movana : public TSkeleton_application { virtual bool check_autorization() const { return false; } virtual const char * extra_modules() const { return "ca"; } TImporta_movana_mask* _msk; protected: public: virtual bool create(); virtual bool destroy(); virtual void main_loop(); bool transfer(const TFilename& file); TImporta_movana() {}; }; bool TImporta_movana::transfer(const TFilename& file) { //roba dalla maschera //parametri di importazione const char sep_field = _msk->get(F_SEP_FIELD)[0]; //separatore dei campi const char sep_dec = _msk->get(F_SEP_DEC)[0]; //separatore decimali //parametri del movana const long numreg = _msk->get_long(F_NUMREGCA); const int annoes = _msk->get_int(F_ANNOES); const TDate datareg = _msk->get_date(F_DATAREG); const TDate datacomp = _msk->get_date(F_DATACOMP); const TDate datafcomp = _msk->get_date(F_DATAFCOMP); const bool autofcomp = _msk->get_bool(F_AUTOFCOMP); const TString descrizione = _msk->get(F_DESCR); const char tipomov = _msk->get(F_TIPO)[0]; const TString4 codcaus = _msk->get(F_CODCAUS); const real ori_totimp = _msk->get_real(F_TOTMOV); const char ori_totsez = _msk->get(F_TOTMOV_SEZ)[0]; //crea il recordset sul file di input utilizzando il separatore TImporta_movana_recordset s(file, sep_field); const long recset_items = s.items(); //un po' di roba iniziale TProgind pi(s.items(),"Importazione movimento in corso ...",true,true); TLog_report log("ERRORI DI TRASFERIMENTO"); int curr_line = 0; //testata //------- //movimento analitico che sarà generato TAnal_mov movana; //il movana esisteva già o è nuovo? const int err = movana.read(numreg); //se esisteva già deve accoppare tutte le righe visto che le sostituirà if (err == NOERR) movana.destroy_rows(LF_RMOVANA); else movana.put(MOVANA_NUMREG, numreg); movana.put(MOVANA_DATAREG, datareg); movana.put(MOVANA_DATACOMP, datacomp); movana.put(MOVANA_DATAFCOMP, datafcomp); movana.put(MOVANA_ANNOES, annoes); movana.put(MOVANA_DESCR, descrizione); movana.put(MOVANA_TIPOMOV, tipomov); movana.put(MOVANA_CODCAUS, codcaus); movana.put(MOVANA_AUTOFCOMP, autofcomp); TImporto totale; //giro su tutti i record del recordset per importarli; ogni record è una riga //TRACCIATO RECORD all'ultima moda (21/09/2010): codcms/cdc/importo/sezione/gr/co/sott/fase (valido per crpa e dinamica) //righe analitiche //---------------- for (bool ok = s.move_first(); ok; ok = s.move_next()) { if (!pi.addstatus(1)) break; curr_line ++; //prende i dati dal record di input del file csv //---------------------------------------------- //CODCMS ci deve essere e va maiuscolizzato; se non c'è va segnalato sul log.. //..ed impedirà la write del movana TString80 codcms = s.get(0).as_string(); if (codcms.blank()) { //controllo necessario e decisivo per evitare l'errore dovuto all'ultimo 'a capo' che pretendeva una riga ulteriore if (curr_line < recset_items) { TString msg; msg.format("Manca la commessa nella riga %ld", curr_line); log.log(2, msg); } continue; } codcms.upper(); //altra modifica all'ultima moda: se c'è un '_' in realtà vorrebbe un '/' (21/09/2010) codcms.replace('_', '/'); //CDC ci deve essere e va maiuscolizzato; se non c'è va segnalato sul log.. //..ed impedirà la write del movana TString80 cdc = s.get(1).as_string(); if (cdc.blank()) { TString msg; msg.format("Manca la sede nella riga %ld", curr_line); log.log(2, msg); continue; } cdc.upper(); //IMPORTO (inizialmente come stringa x poter fare le replace); se nullo va segnalato.. //..ma niente bloccaggio della write TString80 str_importo = s.get(2).as_string(); if (sep_dec == ',') { str_importo.strip("."); //togle il separatore delle migliaia str_importo.replace(',','.'); //sostituisce il separatore decimale } else str_importo.strip(","); const real importo = str_importo; /*if (importo == ZERO) { TString msg; msg.format("Importo nullo nella riga %ld", curr_line); log.log(0, msg); }*/ //SEZIONE TString8 str_sezione = s.get(3).as_string(); if (str_sezione.blank()) { TString msg; msg.format("Manca la sezione nella riga %ld", curr_line); log.log(2, msg); continue; } str_sezione.upper(); const char sezione = str_sezione[0]; //CONTO const int gr = s.get(4).as_int(); const int co = s.get(5).as_int(); const long so = s.get(6).as_int(); TString80 conto; conto.format("%03d%03d%06ld", gr, co, so); if (conto.blank()) { TString msg; msg.format("Manca il conto nella riga %ld", curr_line); log.log(2, msg); continue; } //FASE ci può essere e va maiuscolizzata; TString80 fase = s.get(7).as_string(); /*if (fase.blank()) { TString msg; msg.format("Manca la fase nella riga %ld", curr_line); log.log(2, msg); continue; }*/ fase.upper(); //riempie la riga analitica //------------------------- //nuova riga del movana (sfrutta il fatto che è un multiple rectype) TRectype& rmovana = movana.new_row(); rmovana.put(RMOVANA_DESCR, "Riga importata"); rmovana.put(RMOVANA_CODCONTO, conto); rmovana.put(RMOVANA_CODCMS, codcms); rmovana.put(RMOVANA_CODCCOSTO, cdc); rmovana.put(RMOVANA_CODFASE, fase); rmovana.put(RMOVANA_SEZIONE, sezione); rmovana.put(RMOVANA_IMPORTO, importo); //aggiorna anche il totale documento.. TImporto importo_riga(sezione, importo); totale += importo_riga; } //completa la testata //------------------- totale.normalize(); const char totsez = totale.sezione(); const real totimp = totale.valore(); //controllo sul totmov in caso di riscrittura if (ori_totimp != totimp || (ori_totimp == ZERO && ori_totsez != totsez)) { TString str_totimp; str_totimp << totimp; TString str_ori_totimp; str_ori_totimp << ori_totimp; TString msg; msg.format("Il totale movimento originale e' %s %c, quello importato e' %s %c.\n" "Registrare il movimento con il totale delle righe importate?", (const char*)str_totimp, totsez, (const char*)str_ori_totimp, ori_totsez); if (!yesno_box(msg)) log.log(2, "Totale movimento originale NON coincidente con quello importato !"); } movana.put(MOVANA_SEZIONE, totale.sezione()); movana.put(MOVANA_TOTDOC, totale.valore()); //solo se non ci sono errori procede alla registrazione del movimento const int items = log.recordset()->items(); if (items > 0) log.preview(); else { TLocalisamfile fmovana(LF_MOVANA); int err = movana.rewrite_write(fmovana); if (err != NOERR) error_box("Impossibile registrare il movimento analitico !"); } return true; } bool TImporta_movana::create() { _msk = new TImporta_movana_mask(); return TSkeleton_application::create(); } bool TImporta_movana::destroy() { delete _msk; return TApplication::destroy(); } void TImporta_movana::main_loop() { KEY tasto; tasto = _msk->run(); TConfig& cfg = ca_config(); const bool use_pdcc = cfg.get_bool("UsePdcc"); if (use_pdcc) { if (tasto == K_ENTER) { //genero il nome del file da caricare TFilename name = _msk->get(F_PATH); name.add(_msk->get(F_NAME)); if (transfer(name)) { message_box(TR("Elaborazione completata")); } } } else error_box("Il programma richiede che sia impostato l'uso del piano dei conti contabile in analitica!"); } TImporta_movana& app() { return (TImporta_movana&) main_app(); } int ps1001100 (int argc, char* argv[]) { TImporta_movana main_app; main_app.run(argc, argv, TR("Importazione movimento analitico da CSV")); return true; }