#include #include #include #include #include #include #include #include #include #include "../mg/umart.h" #include "halib.h" class THardy_config : public TConfig { public: virtual const TString& get(const char* var, const char* section = NULL, int index = -1, const char* def = ""); THardy_config(const char* ini_name); }; const TString& THardy_config::get(const char* var, const char* section, int index, const char* def) { const TString& original_val = TConfig::get(var, section, index, def); if (original_val[0] == '"' && original_val.ends_with("\"")) { TString& val = get_tmp_string(); val = original_val; val.rtrim(1); val.ltrim(1); val.trim(); return val; } return original_val; } THardy_config::THardy_config(const char* ini_name) : TConfig(ini_name, "Transaction") { } ///////////////////////////////////////////////////////////// // Applicazione ///////////////////////////////////////////////////////////// class TIni2Txt: public TSkeleton_application { TFilename _output_dir; protected: //metodi di infimo livello TString4 ricava_segno(TConfig& ini); //metodi di medio livello void crea_nome_txt(const TString& prefisso, TFilename& output_path); void get_part_key(TConfig& ini, TToken_string& key) const; bool find_part_key(TConfig& ini, const TString_array& ini_paragraphs, const int logicnum, const TToken_string& key) const; //metodi di alto livello void genera_cliente_txt(TConfig& ini); void genera_riga_listino_txt(TConfig& ini); void genera_prodotto_txt(TConfig& ini); void genera_sospeso_txt(TConfig& ini, TString_array& ini_paragraphs); virtual void main_loop(); public: TIni2Txt(); }; TIni2Txt::TIni2Txt() { if (user().blank()) user() = dongle().administrator(); } //metodo che genera in automatico il nome del file .txt in output (maggggico) void TIni2Txt::crea_nome_txt(const TString& prefisso, TFilename& output_path) { TString_array lista_files; output_path = _output_dir; TString wrkstring; wrkstring << prefisso << "??????.txt"; output_path.add(wrkstring); const int items = list_files(output_path, lista_files); long n = 1; if (items > 0) { lista_files.sort(); TFilename ultimo_txt = lista_files.row(items - 1); ultimo_txt = ultimo_txt.name(); const long last_txt = atol(ultimo_txt.mid(prefisso.len(), 6)); n += last_txt; } //risfruttiamo lo stesso filename che risparmiamo output_path = _output_dir; output_path.add(prefisso); TString8 numero; numero.format("%06ld", n); output_path << numero; output_path.ext("txt"); } TString4 TIni2Txt::ricava_segno(TConfig& ini) { TString4 segno = "+"; const TString& action = ini.get("Action", "Transaction"); if (action == "R") segno = "-"; return segno; } /////////////////////////////////////////////// // metodi di alto livello /////////////////////////////////////////////// void TIni2Txt::genera_cliente_txt(TConfig& ini) { //recordset per i clienti TEsporta_clientiVAR_recordset clienti; clienti.new_rec(""); //controlla il tipo di transazione... const TString4 segno = ricava_segno(ini); //...e poi si lancia a capofitto a riempire il recordset! //campi da clifo (20) //------------------- ini.set_paragraph("20"); const long codcf = ini.get_long(CLI_CODCF); //il codice terminale è il codagente legato al cliente clienti.set("CodiceTerminale", find_codag(codcf)); clienti.set("Segno", segno); clienti.set(CLI_CODCF, codcf); clienti.set(CLI_RAGSOC, ini.get(CLI_RAGSOC)); //l'indirizzo va numerato TString80 indcf = ini.get(CLI_INDCF); indcf << " " << ini.get(CLI_CIVCF); clienti.set(CLI_INDCF, indcf); //panegirico per comune e provincia const TString& statocf = ini.get(CLI_STATOCF); if (statocf.blank()) { const TString& comcf = ini.get(CLI_COMCF); TToken_string key; key.add(statocf); key.add(comcf); const TRectype& rec_comuni = cache().get(LF_COMUNI, key); TString80 dencom = rec_comuni.get(COM_DENCOM); //dencom.cut(20); //il campo sul .txt è lungo 20! clienti.set("Localita", dencom); const TString& provcf = rec_comuni.get(COM_PROVCOM); clienti.set("Provincia", provcf); } clienti.set(CLI_CAPCF, ini.get(CLI_CAPCF)); clienti.set(CLI_PAIV, ini.get(CLI_PAIV)); //attenzione alla lunghezza del codpag TString4 codpag = ini.get(CLI_CODPAG); //codpag.cut(2); //il campo sul .txt è lungo 2! clienti.set(CLI_CODPAG, codpag); TString query; query << "USE CONDV"; query << "\nFROM TIPO=C TIPOCF=C CODCF=#CODCF"; query << "\nTO TIPO=C TIPOCF=C CODCF=#CODCF"; TISAM_recordset contratti(query); contratti.set_var("#CODCF", ini.get_long(CLI_CODCF)); if (contratti.move_last()) { const TString& cod_contr = contratti.get(CONDV_COD).as_string(); clienti.set("CodiceListino", cod_contr); } TString16 ntel = ini.get(CLI_PTEL); ntel << ini.get(CLI_TEL); //ntel.cut(10); clienti.set(CLI_TEL, ntel); clienti.set(CLI_CODCFFATT, ini.get(CLI_CODCFFATT)); //panegirico del fido! //poichè il formato di output prevede comunque 2 decimali -> provvediamo a riempire eventuali buchi real fido = ini.get(CLI_FIDO); fido *= CENTO; fido.round(); clienti.set(CLI_FIDO, fido); //no consegna = sospeso (forse) const TString& sospeso = ini.get_bool(CLI_SOSPESO) ? "S" : ""; clienti.set("NoConsegna", sospeso); clienti.set(CLI_COFI, ini.get(CLI_COFI)); //campi da cfven(17) //------------------ ini.set_paragraph("17"); const TString& str_sconto = ini.get(CFV_SCONTO); clienti.set("ScontoFineFattura", find_sconto(str_sconto)); TString4 assfis = ini.get(CFV_ASSFIS); //assfis.cut(2); //il loro è lungo 2! clienti.set(CFV_ASSFIS, assfis); //prepara il nome corretto del file .txt e lo genera //-------------------------------------------------- const TString prefisso = "clientivar"; TFilename output_path; crea_nome_txt(prefisso, output_path); //..e alla fine della fiera salva il file di testo nell directory selezionata clienti.save_as(output_path, fmt_text); } void TIni2Txt::genera_riga_listino_txt(TConfig& ini) { TEsporta_listiniVAR_recordset riga_listino; const TString4 segno = ricava_segno(ini); //campi da condv (52) //------------------- //ini.set_paragraph("52"); //campi da rcondv (53) //-------------------- //ATTENZIONE!!! Ci sono N righe di tipo 53 per ogni testata, quindi dobbiamo fare il giro for (int r = 1;; r++) { TString8 paragraph; paragraph.format("%d,%d", LF_RCONDV, r); if (!ini.set_paragraph(paragraph)) break; riga_listino.new_rec(""); riga_listino.set("CodiceTerminale", 0L); //nel caso del listino non si sa come comportarsi riga_listino.set("Segno", segno); riga_listino.set(RCONDV_COD, ini.get(RCONDV_COD)); TString80 codart = ini.get(RCONDV_CODRIGA); //codart.cut(5); //il codart è lungo 5 sul txt! riga_listino.set(RCONDV_CODRIGA, codart); //prezzo real prezzo = ini.get(RCONDV_PREZZO); if (prezzo.is_zero()) { TToken_string key_umart; key_umart.add(codart); key_umart.add(1); const TRectype& rec_umart = cache().get(LF_UMART, key_umart); prezzo = rec_umart.get_real(UMART_PREZZO); } prezzo *= 1000; prezzo.round(); riga_listino.set(RCONDV_PREZZO, prezzo.integer()); //sconto const TString& str_sconto = ini.get(RCONDV_SCONTO); riga_listino.set(RCONDV_SCONTO, find_sconto(str_sconto)); } //for(int r=1;;... //prepara il nome corretto del file .txt e lo genera //-------------------------------------------------- const TString prefisso = "listvar"; TFilename output_path; crea_nome_txt(prefisso, output_path); riga_listino.save_as(output_path, fmt_text); } void TIni2Txt::genera_prodotto_txt(TConfig& ini) { TEsporta_prodottiVAR_recordset prodotto; prodotto.new_rec(""); const TString4 segno = ricava_segno(ini); //campi da anamag (47) //------------------- ini.set_paragraph("47"); prodotto.set("Segno", segno); TString80 codart = ini.get(ANAMAG_CODART); //codart.cut(5); //solito problema della lunghezza ridotta prodotto.set(ANAMAG_CODART, codart); TString80 descr = ini.get(ANAMAG_DESCR); //descr.cut(30); prodotto.set(ANAMAG_DESCR, descr); TString4 codiva = ini.get(ANAMAG_CODIVA); //codiva.cut(2); //solito problema della lungh ridotta prodotto.set(ANAMAG_CODIVA, codiva); //sconto const TString& str_sconto = ini.get(ANAMAG_SCONTO); prodotto.set(ANAMAG_SCONTO, find_sconto(str_sconto)); //campi da umart (49) (per ora una sola riga) //------------------------------------------- ini.set_paragraph("49,1"); real prezzo = ini.get(UMART_PREZZO); prezzo *= 1000; prezzo.round(); prodotto.set(UMART_PREZZO, prezzo.integer()); prodotto.set(UMART_UM, ini.get(UMART_UM)); //prepara il nome corretto del file .txt da generare //-------------------------------------------------- const TString prefisso = "prodottivar"; TFilename output_path; crea_nome_txt(prefisso, output_path); prodotto.save_as(output_path, fmt_text); } void TIni2Txt::get_part_key(TConfig& ini, TToken_string& key) const { //tracciato: tipocf-sottoconto(=codcf)-anno-numpart-nriga key.cut(0); key.add(ini.get(PART_TIPOCF)); key.add(ini.get(PART_SOTTOCONTO)); key.add(ini.get_int(PART_ANNO)); key.add(ini.get(PART_NUMPART)); key.add(ini.get_int(PART_NRIGA)); } bool TIni2Txt::find_part_key(TConfig& ini, const TString_array& ini_paragraphs, const int logicnum, const TToken_string& key) const { TString4 start; start << logicnum << ','; //cerca i pagamenti della partita FOR_EACH_ARRAY_ROW(ini_paragraphs, t, row) { if (row->starts_with(start)) { TToken_string key_row; ini.set_paragraph(*row); get_part_key(ini, key_row); if (key_row == key) return true; } //if (part_row->starts_with("30... } //FOR_EACH_ARRAY_ROW(ini_paragraphs, t... return false; } void TIni2Txt::genera_sospeso_txt(TConfig& ini, TString_array& ini_paragraphs) { TEsporta_sospesiVAR_recordset sospeso; sospeso.new_rec(""); const TString4 segno = ricava_segno(ini); //delirio di campi da part (28) pagsca (29) scad(30) //-------------------------------------------------- //ricava il numreg dal mov const long numreg = ini.get_long(MOV_NUMREG, "23"); TAssoc_array clienti; //costruisce la lista dei clienti presenti nel .ini FOR_EACH_ARRAY_ROW(ini_paragraphs, r, riga) { if (riga->starts_with("28,")) { const long part_numreg = ini.get_long(PART_NREG, *riga); //va specificata il paragrafo alla prima get const char tipocf = ini.get_char(PART_TIPOCF); if (numreg == part_numreg && tipocf == 'C') clienti.add(ini.get(PART_SOTTOCONTO)); } } FOR_EACH_ARRAY_ROW(ini_paragraphs, s, part_row) { if (part_row->starts_with("28,")) { const int tipomov = ini.get_int(PART_TIPOMOV, *part_row); const char tipocf = ini.get_char(PART_TIPOCF); const TString8 codcf = ini.get(PART_SOTTOCONTO); const bool part_chiusa = ini.get_bool(PART_CHIUSA); //cerca le partite, derivanti da fatture, dei soli clienti che ha nella lista clienti if (!part_chiusa && tipomov == 1 && tipocf == 'C' && clienti.is_key(codcf)) { TToken_string key; get_part_key(ini, key); const long numfatt = ini.get_long(PART_NUMDOC); const TDate datadoc = ini.get(PART_DATADOC); const TString8 numpart = key.get(3); //cerca i pagamenti della rata if (find_part_key(ini, ini_paragraphs, LF_SCADENZE, key)) { real imp_rata = ini.get(SCAD_IMPORTO); const TDate data_rata = ini.get(SCAD_DATASCAD); real imp_pag; if (find_part_key(ini, ini_paragraphs, LF_PAGSCA, key)) { const char acc_sal = ini.get(PAGSCA_ACCSAL)[0]; imp_pag = acc_sal == 'S' ? imp_rata : real(ini.get(PAGSCA_IMPORTO)); } //se il pagamento non chiude la rata -> il saldo resta in sospeso e il record va aggiunto if (imp_pag < imp_rata) { real residuo = imp_rata - imp_pag; //riempie il record da esportare sospeso.set("CodiceTerminale", 0L); sospeso.set("Segno", segno); sospeso.set("CodiceCliente", codcf); sospeso.set("NumeroFattura", numfatt); sospeso.set("DataFattura", format_data_6(datadoc)); residuo *= CENTO; residuo.round(); sospeso.set("ImportoResiduo", residuo); imp_rata.round(); sospeso.set("ImpOriginalDoc", imp_rata); sospeso.set("DataScadenza", format_data_6(data_rata)); sospeso.set("TipoDocumento", "F"); } } //if (find_part_key(ini, ini_paragraphs, LF_SCADENZE... } //if (tipomov == 1 && tipocf... } //if (part_row->starts_with("28,... } //FOR_EACH_ARRAY_ROW(ini_paragraphs, s... //prepara il nome corretto del file .txt da generare //-------------------------------------------------- const TString prefisso = "sospesivar"; TFilename output_path; crea_nome_txt(prefisso, output_path); sospeso.save_as(output_path, fmt_text); } void TIni2Txt::main_loop() { //stabilisce una volta per tutte ad inizio programma quale cavolo è la directory dove sbattere i .txt generati TConfig hardy(CONFIG_DITTA, "ha"); _output_dir = hardy.get("OutputPath"); //dalla riga di comando raccatta il path completo del file .ini da tradurre TFilename path = argv(2); if (path.exist()) { //crea un config del .ini di tipo Hardy_config con le get astute! THardy_config input_ini_file(path); //elabora il .ini TString_array ini_paragraphs; input_ini_file.list_paragraphs(ini_paragraphs); //clienti if (ini_paragraphs.find("20") >= 0) genera_cliente_txt(input_ini_file); //sospesi if (ini_paragraphs.find("28,1,1") >= 0) genera_sospeso_txt(input_ini_file, ini_paragraphs); //listino if (ini_paragraphs.find("52") >= 0) genera_riga_listino_txt(input_ini_file); //prodotti if (ini_paragraphs.find("47") >= 0) genera_prodotto_txt(input_ini_file); } } int ha1100(int argc, char* argv[]) { TIni2Txt a; a.run(argc, argv, "Generazione .txt da .ini"); return 0; }