/************************************************************************************************************************************************ * Author: Tolla * * Date: 12/2016 * * Questo programma serve a calcolare tutti i pagamenti fatti da privati in un determinato anno (e nel precedente in caso di fatture arretrate) * * per la detrazione dalle tasse delle spese del Cigno. Tutto ciò va fatto perchè non usano la gestione del saldaconto. * * Ma non temete! Il sacro e prepotente Campo vi salverà anche questa volta! * ************************************************************************************************************************************************/ #include #include #include #include #include #include "../cg/cglib.h" #include "../mg/mglib.h" #include "ps0430600a.h" #include "../ca/calib01.h" #include "../ca/commesse.h" #include "../ca/movana.h" #include "../ca/rmovana.h" /////////////////////////////////////////////////////////// // TClifo /////////////////////////////////////////////////////////// class TClifo : public TObject { public: long codcf; // Codice del cliente real p98; // > 0 se trovo un P98 per quel cliente // Viene già inizializzata a 0? real importoPagato; // Importo pagato per quest'anno dal cliente TString nome; // Nome TString cognome; // Cognome TString indirizzo; // Indirizzo TString citta; // Città TString provincia; // Provincia TString codF; // Codice Fiscale real totale; // Totale pagato durante l'anno real p98Ini; TClifo(): codcf(0), p98(ZERO), p98Ini(ZERO), importoPagato(ZERO), nome(""), cognome(""), indirizzo (""), citta(""), provincia(""), codF(""), totale(ZERO){} TClifo(long cod, TString nom, TString cog, TString ind, TString cit, TString prov, TString codFisc) : codcf(cod), nome(nom), cognome(cog), indirizzo(ind), citta(cit), provincia(prov), codF(codFisc){} virtual ~TClifo(){} TClifo & operator = (const TClifo& r); }; TClifo& TClifo::operator =(const TClifo& r) { codcf = r.codcf; p98 = r.p98; p98Ini = r.p98Ini; importoPagato = r.importoPagato; nome = r.nome; cognome = r.cognome; indirizzo = r.indirizzo; citta = r.citta; provincia = r.provincia; codF = r.codF; totale = r.totale; return *this; } /////////////////////////////////////////////////////////// // TTessan_mask /////////////////////////////////////////////////////////// class TTessan_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TTessan_mask() : TAutomask("ps0430600a") {set(F_USER_PATH, ini_get_string(CONFIG_DITTA, "Tessera sanitaria", "Percorso"));} }; bool TTessan_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { return true; } /////////////////////////////////////////////////////////// // TTessan_app /////////////////////////////////////////////////////////// class TTessan_app : public TSkeleton_application { private: TToken_string p, p98; protected: bool elabPayment(int anno, TString userPath); TString toEur(real val); bool findErase(TToken_string *tn, long val); void splitName(TString ragsoc, TString &nome, TString &cognome); void getLocalita(TString cod, TString &comune, TString &provincia); public: virtual void main_loop(); }; TString TTessan_app::toEur(real val) { return TString(TCurrency(val).string(true)) << " €"; } bool TTessan_app::findErase(TToken_string *tn, long find) { // La token_string deve essere in ordine decrescente tn->restart(); long val = atoi(tn->get()); for(int k = 0;k <= tn->items() && val <= find; k++) { if(val == find) { for(int j = 0; j < k; j++) tn->destroy(0); return true; } val = atoi(tn->get()); } return false; } void TTessan_app::splitName(TString ragsoc, TString &nome, TString &cognome) { /* Casi: * COGNOME NOME * COGNOME NOME * Prima cerco più di uno spazio così da mantenere eventuali nomi/cognomi multipli (come GUIDI GIORGI GABRIELLA ANNUNZIATA FILOMENA) */ int f , l = -1, offset = 2; for(int i = 0; i < ragsoc.len(); i++) { if(ragsoc[i] == ' ' && ragsoc[i + 1] == ' ') l = i; } if(l == -1) { f = ragsoc.find(' '); cognome = ragsoc.sub(0, f); nome = ragsoc.sub(f + 1); } else { f = ragsoc.find(" "); cognome = ragsoc.sub(0, f); nome = ragsoc.sub(l + 2); } } void TTessan_app::getLocalita(TString cod, TString &comune, TString &provincia) { TRelation com(LF_COMUNI); TRectype filCom(com.curr()); filCom.put("STATO", ""); filCom.put("COM", cod); TCursor curCom(&com, "", 1, &filCom, &filCom); curCom.items(); curCom = 0; TRectype rowCom = curCom.curr(); comune = rowCom.get("DENCOM"); provincia = rowCom.get("PROVCOM"); // Teoricamente le province saranno sempre di 2 ma non si sa mai } bool TTessan_app::elabPayment(int anno, TString userPath) { // Calcolo tutti i pagamenti da mov con codice P* tranne P099 TRelation clifo(LF_CLIFO), mov(LF_MOV), rmov(LF_RMOV); // Creo filtro e cursore per i clienti TRectype filClifo(clifo.curr()); filClifo.put("TIPOCF", "C"); TCursor curClifo(&clifo, "ALLEG = \"6\"", 1, &filClifo, &filClifo); int numCli = curClifo.items(); // Mi creo un array di SClifo TClifo * clienti = new TClifo[numCli]; // Mi creo un array dei movimenti che iniziano con P per velocizzare il processo //TToken_string p98, p; TProgress_monitor a(numCli, "Caricamento clienti"); for(curClifo = 0; curClifo.pos() < numCli && !a.is_cancelled(); ++curClifo) { if (!a.add_status()) break; // Riga cliente attuale TRectype rowClifo = curClifo.curr(); TString nome, cognome, comune, provincia; splitName(rowClifo.get("RAGSOC"), nome, cognome); getLocalita(rowClifo.get("COMCF"), comune, provincia); TClifo cliente(rowClifo.get_long("CODCF"), nome, cognome, (TString)rowClifo.get("INDCF") << " " << rowClifo.get("CIVCF"), comune, provincia, rowClifo.get("COFI")); clienti[curClifo.pos()] = cliente; } // Creo il cursore di Mov // Creo la stringa per i filtri TString first("01-01-"),last("31-12-"); first << anno; last << anno; // Creo i filtri e assegno TRectype filFirst(mov.curr()), filLast(mov.curr()); filFirst.put("DATAREG", first); filLast.put("DATAREG", last); // Creo il cursore e conto gli elementi TSorted_cursor curMov(&mov, "NUMREG", "", 2, &filFirst, &filLast); int numMov = curMov.items(); TProgress_monitor b(numMov, "Carico i movimenti"); // Azzero le token string p.cut(0); p98.cut(0); // Le carico for(curMov = 0; curMov.pos() < numMov && !b.is_cancelled(); ++curMov) { if (!b.add_status()) break; // Movimento attuale TRectype rowMov = curMov.curr(); TString codcaus(rowMov.get("CODCAUS")); if(codcaus.starts_with("P") || codcaus == "I03" || codcaus == "I05") { if(codcaus == "P98") p98.add(rowMov.get("NUMREG")); else if(codcaus != "P99") p.add(rowMov.get("NUMREG")); } } // Adesso che ho tutti i movimenti prima cerco i vari P98 e li salvo in clienti // Filtro TRectype filP98Ini(rmov.curr()), filP98Fin(rmov.curr()); filP98Ini.put("NUMREG", p98.get(0)); filP98Fin.put("NUMREG", p98.get(p98.items()-1)); TCursor curRMov(&rmov, "", 1, &filP98Ini, &filP98Fin); int p98items = curRMov.items(); int nump98 = 0; TProgress_monitor c(p98items, "Elaboro i movimenti P98"); for(curRMov = 0; curRMov.pos() < p98items && !c.is_cancelled() && p98.items() > 0; ++curRMov) { if(!c.add_status()) break; // Riga del movimento attuale TRectype rowRMov = curRMov.curr(); // Controllo che è di una persona fisica TString cod(rowRMov.get("NUMREG")),rig(rowRMov.get("NUMRIG")),gruppo(rowRMov.get("GRUPPO")), conto(rowRMov.get("CONTO")); if(rowRMov.get("GRUPPO") != "2" || rowRMov.get("CONTO") != "1") continue; if(!findErase(&p98, rowRMov.get_long("NUMREG"))) continue; //trovato = false; for(int i = 0; i < numCli; i++) { TClifo cliente = clienti[i]; if(clienti[i].codcf == rowRMov.get_long("SOTTOCONTO")) // N.B. Teoricamente si fa solo una volta a cliente { nump98++; if(rowRMov.get("SEZIONE") == "D") { clienti[i].p98 += rowRMov.get_real("IMPORTO"); // Aggiungo a P98 per sapere quanto è dell'anno scorso clienti[i].p98Ini += rowRMov.get_real("IMPORTO"); clienti[i].importoPagato -= rowRMov.get_real("IMPORTO"); // Sottraggo all'importo di quest'anno per vedere quanto è di quest'anno } else { clienti[i].importoPagato += rowRMov.get_real("IMPORTO"); // Sommo se è in avere } break; } } } // Adesso che ho calcolato i P98 analizzo i pagamenti // Filtro TRectype filPIni(rmov.curr()), filPFin(rmov.curr()); filPIni.put("NUMREG", p.get(0)); filPFin.put("NUMREG", p.get(p.items()-1)); TCursor curRMovP(&rmov, "", 1, &filPIni, &filPFin); int pitems = curRMovP.items(); TProgress_monitor d(pitems, "Analizzo i pagamenti di quest'anno"); for(curRMovP = 0; curRMovP.pos() < pitems && !d.is_cancelled() && p.items() > 0; ++curRMovP) { if(!d.add_status()) break; // Riga del movimento attuale TRectype rowRMov = curRMovP.curr(); // Controllo che è di una persona fisica if(rowRMov.get("GRUPPO") != "2" || rowRMov.get("CONTO") != "1") continue; if(!findErase(&p, rowRMov.get_long("NUMREG"))) continue; //bool trovato = false; for(int i = 0; i < numCli; i++) { TClifo cliente = clienti[i]; if(clienti[i].codcf == rowRMov.get_long("SOTTOCONTO")) { if(rowRMov.get("SEZIONE") == "A") { clienti[i].importoPagato += rowRMov.get_real("IMPORTO"); // Aggiunto l'importo a quanto è stato pagato quest'anno clienti[i].totale += rowRMov.get_real("IMPORTO"); // Calcolo l'importo totale di quell'anno } else { clienti[i].importoPagato -= rowRMov.get_real("IMPORTO"); // Sottraggo all'importo di quest'anno per vedere quanto è di quest'anno clienti[i].totale -= rowRMov.get_real("IMPORTO"); // Calcolo l'importo totale di quell'anno } break; } } } // Creo il file di output ********************************************************** ofstream outputFile; outputFile.open(userPath << "tessera_sanitaria.csv"); // Controllo l'apertura if(!outputFile.is_open()) return false; //*********************************************************************************** // Inizio a scriverci outputFile << "CodiceAnagrafico;CodiceFiscale;Cognome;Nome;Indirizzo;Citta;Provincia;NumeroDocumento;DataDocumento;DataPagamento;Dispositivo;TipoOperazione;NumeroDocumentoOriginale;DataDocumentoOriginale;DispositivoDocumentoOriginale;TipoSpesa;FlagSpesa;Importo;OperazioneEsclusa\n"; int clientsSatisfied = 0; // Numero di clienti con P98 <= 0 (Quindi ho trovato tutte le fatture vecchie) // Creo il cursore di Mov Vecchio // Creo la stringa per i filtri TString firstOld("01-01-"),lastOld("31-12-"); firstOld << anno-1; lastOld << anno-1; // Creo i filtri e assegno TRectype filFirstOld(mov.curr()), filLastOld(mov.curr()); filFirstOld.put("DATAREG", firstOld); filLastOld.put("DATAREG", lastOld); // Creo il cursore e conto gli elementi TSorted_cursor curMovOld(&mov, "DATAREG-", "", 2, &filFirstOld, &filLastOld); int numMovOld = curMovOld.items(); TProgress_monitor e(numMovOld, (TString)"Aggiungo al file i movimenti del " << anno -1); for(curMovOld = 0; curMovOld.pos() < numMovOld && clientsSatisfied < numCli && !e.is_cancelled(); ++curMovOld) { if(!e.add_status()) break; // Movimento attuale TRectype rowMovOld = curMovOld.curr(); if(rowMovOld.get("TIPO") != "C") continue; // Non riesco a metterlo nel filtro if(rowMovOld.get("CODCAUS") != "V01" && rowMovOld.get("CODCAUS") != "V02") continue; for(int i = 0; i < numCli; i++) { #ifdef DBG if (rowMovOld.get_long("CODCF") == clienti[i].codcf && clienti[i].codcf == 1669) { TString asd = clienti[i].importoPagato.string(); bool tolla = true; } #endif // DBG if(clienti[i].codcf == rowMovOld.get_long("CODCF") && clienti[i].p98 > 0 && clienti[i].importoPagato > 0) // Trova più spesso il cliente diverso dal codice all'inizio { // Aggiungo il documento al file TString codcfFilled; codcfFilled << rowMovOld.get("CODCF"); for(int j = codcfFilled.len(); j <= 6; j++) codcfFilled.insert("0",0); real totdoc = rowMovOld.get_real("TOTDOC"); real importo = clienti[i].p98 - totdoc >= 0 ? totdoc : clienti[i].p98; outputFile << rowMovOld.get("CODCF") << ";" << clienti[i].codF << ";" << clienti[i].cognome << ";" << clienti[i].nome << ";" << clienti[i].indirizzo << ";" << clienti[i].citta << ";" << clienti[i].provincia << ";" << rowMovOld.get("NUMDOC") << ";" << rowMovOld.get("DATADOC") << ";" << rowMovOld.get("DATAREG") << ";1;I;;;;AA;;" << toEur(importo) << ";\n"; clienti[i].p98 -= totdoc; // Se ha trovato tutti i documenti incremento la variabile sentinella if(clienti[i].p98 <= 0) clientsSatisfied ++; break; } } } // Creo il cursore di Mov Nuovo // Creo la stringa per i filtri TString firstNew("01-01-"),lastNew("31-12-"); firstNew << anno; lastNew << anno; // Creo i filtri e assegno TRectype filFirstNew(mov.curr()), filLastNew(mov.curr()); filFirstNew.put("DATAREG", firstNew); filLastNew.put("DATAREG", lastNew); // Creo il cursore e conto gli elementi TSorted_cursor curMovNew(&mov, "DATAREG", "", 2, &filFirstNew, &filLastNew); //TCursor curMov(&mov, "", 3, &filFirst, &filLast); int numMovNew = curMovNew.items(); TProgress_monitor f(numMovNew, (TString)"Aggiungo al file i movimenti del " << anno); for(curMovNew = 0; curMovNew.pos() < numMovNew && clientsSatisfied < numCli && !f.is_cancelled(); ++curMovNew) { if(!f.add_status()) break; // Movimento attuale TRectype rowMovNew = curMovNew.curr(); if(rowMovNew.get("TIPO") != "C") continue; // Non riesco a metterlo nel filtro if(rowMovNew.get("CODCAUS") != "V01" && rowMovNew.get("CODCAUS") != "V02") continue; for(int i = 0; i < numCli; i++) { if(rowMovNew.get_long("CODCF") == clienti[i].codcf && clienti[i].importoPagato >= 0) { // Sottraggo quanto ha pagato // Scrivo su file TString codcfFilled; codcfFilled << rowMovNew.get("CODCF"); for(int j = codcfFilled.len(); j <= 6; j++) codcfFilled.insert("0",0); real totdoc = rowMovNew.get_real("TOTDOC"); real importo = clienti[i].importoPagato - totdoc >= 0 ? totdoc : clienti[i].importoPagato; outputFile << rowMovNew.get("CODCF") << ";" << clienti[i].codF << ";" << clienti[i].cognome << ";" << clienti[i].nome << ";" << clienti[i].indirizzo << ";" << clienti[i].citta << ";" << clienti[i].provincia << ";" << rowMovNew.get("NUMDOC") << ";" << rowMovNew.get("DATADOC") << ";" << rowMovNew.get("DATAREG") << ";1;I;;;;AA;;" << toEur(importo) << ";\n"; clienti[i].importoPagato -= totdoc; //outputFile << rowMovNew.get("DATADOC") << ";" << rowMovNew.get("NUMDOC") << ";" << toEur(rowMovNew.get_real("TOTDOC")) << ";" << toEur(clienti[i].importoPagato) << ";" << "001 002 " << codcfFilled << ";" << rowMovNew.get("CODCF") << ";" << clienti[i].nome << ";" << clienti[i].codF << "\n"; break; } } } outputFile.close(); /* // Creo il file di output test ********************************************************** ofstream outTest; outTest.open("C:\\Users\\mtollari\\Desktop\\test_sanitaria.csv"); // Controllo l'apertura if(!outTest.is_open()) return false; //*************************************************************************************** outTest << "Cod.;Totale;p98 Iniziale;p98;importo pagato;\n"; for(int i = 0; i < numCli; i++) { //if(clienti[i].totale <= 0) continue; outTest << clienti[i].codcf << ";" << toEur(clienti[i].totale) << ";" << toEur(clienti[i].p98Ini) << ";" << toEur(clienti[i].p98) << ";" << toEur(clienti[i].importoPagato) << ";\n" ; } outTest.close(); */ return true; } void TTessan_app::main_loop() { TTessan_mask m; while (m.run() == K_ENTER) { TString path(m.get(F_USER_PATH)); ini_set_string(CONFIG_DITTA, "Tessera sanitaria", "Percorso",path); if(elabPayment(m.get_int(F_ANNO), path)) message_box("File creato!"); else message_box("Creazione file non riuscita"); } } int ps0430600(int argc, char* argv[]) { TTessan_app a; a.run(argc, argv, TR("Sistema tessera sanitaria")); return 0; }