#include "lilib01.h" #include #include #define SOLUZIONE_UNICA 1 #define FINO_A_PLAFOND 2 void TLi_manager::elabTipiStati(TToken_string& tipi, TToken_string& stati) { for(int i = 0; i < tipidoc.items(); i++) { TString app(""); tipidoc.get(i, app); TToken_string statidoc(ini_get_string(CONFIG_DITTA, "li", app), ','); for(int j = statidoc.get_int(0); j <= statidoc.get_int(1); j++) { tipi.add(app); stati.add(j); } } } const TString& TLi_manager::consPlaf(real& plafUsed, const bool write) { TString& used = get_tmp_string(); if(!validPlafond || plafUsed > getPlafond()) { used << "ERRORE NEL CALCOLO DEL PLAFOND"; return used; } bool close = false; TToken_string thisPlaf("", ','); while(plafUsed > ZERO) { // Calcolo quanto plafond ho usato TString thisNumprot = plafondi.begin()->first; real thisAmount = plafondi.begin()->second; real thisUtilizzato; if(plafUsed >= thisAmount) { close = true; thisUtilizzato = thisAmount; // Rimuovo il plafond dalla lista, plafondi.erase(thisNumprot); if(write) { // lo chiudo changeStato(thisNumprot, true); } // e diminuisco tutto plafond -= thisAmount; plafUsed -= thisAmount; } else { close = false; thisUtilizzato = plafUsed; // e diminuisco tutto plafond -= plafUsed; plafondi[thisNumprot] -= plafUsed; plafUsed = ZERO; } // Segno di aver usato il plafond used << thisNumprot << "|" << thisUtilizzato.string() << "|" << (close? "X" : "") << ","; } // Controllo di avere ancora plafond rimanente if(plafond <= ZERO) validPlafond = false; // Tolgo la virgola finale used.cut(used.len()-1); return used; } /* Aggiungo al plafond quello che trovo */ const TString& TLi_manager::incrPlaf(TDocumento& d, real impNC, const bool write) { TString& used = get_tmp_string(); // Controllo se questa nota credito si riferisce a un singolo documento, in quel caso aggiorno faccio un aggiornamento sulle lettere di intento // Se si rifà a più documenti o non è specificato salta, meglio stare bassi if(d.get("NUMDOCRIF").blank() || d.get("CODNUMRIF").blank() || d.get("ANNORIF").blank() || iniDicInt.year() != d.get_int("ANNORIF")) { return used; } TDocumento ds('D', d.get_int("ANNORIF"), d.get("CODNUMRIF"), d.get_int("NUMDOCRIF")); // Se il documento di riferimento non ha nulla inserito nel plafond esco, non mi interessa TToken_string lePlafs(ds.get("PLAFOND"), ','); // [ANNO|NUMPROT|UTILIZZATO],... if(lePlafs.items() == 0) return used; // Controllo se non ho già ricevuto la quantità da stornare di plafond nella nota credito if(impNC < ZERO) { impNC = -impNC; } else { // In caso negativo la calcolo TAssoc_array tabIva = d.tabella_iva(true); for (TRiepilogo_iva * totali = (TRiepilogo_iva *) tabIva.get(); totali != NULL; totali = (TRiepilogo_iva *) tabIva.get()) { if(checkIva(totali->cod_iva().codice())) { impNC += -totali->imp_orig(); // +-+-+-+-+-+- } } } // Controllo se ho del plafond da stornare if(impNC <= ZERO) return used; bool open = false; TToken_string thisPlaf("", ','); // Sono abbastanza sicuro che non serve inizializzarlo for(int i = lePlafs.items() - 1; i >= 0 && impNC > ZERO; i--) { lePlafs.get(i, thisPlaf); real importoPlaf = thisPlaf.get(_plimporto); if(importoPlaf < impNC) { impNC -= importoPlaf; } else { importoPlaf = impNC; impNC = ZERO; } // Aggiungo a plafond static TString key; key.cut(0) << thisPlaf.get(_planno) << "|" << thisPlaf.get(_plnumprot); if(plafondi.find(key) != plafondi.end()) { open = false; // Incremento! plafondi[key] += importoPlaf; } else { // Va aggiunto ex novo! // Calcolo l'importo delle righe che rientrano nel plafond open = true; plafondi.insert(std::pair(key, importoPlaf)); // Se devo scrivere abilito il plafond if(write) { changeStato(key, false); } } // Segno di aver usato il plafond used << key << "|" << importoPlaf.string() << "|" << (open? "X" : "") << ","; } return used; } void TLi_manager::stornaDoc(TDocumento& d, const bool write) { // Devo ricaricare le righe sui plafond che ho TToken_string plafs(d.get("PLAFOND"), ','); for(int i = 0; i < plafs.items(); i++) { TToken_string thisPlafond = plafs.get(i); static TString key; key.cut(0) << thisPlafond.get(_planno) << "|" << thisPlafond.get(_plnumprot); real thisImporto = thisPlafond.get(_plimporto); TString asd = thisImporto.string(); if(d.is_nota_credito()) { if(plafondi.find(key) != plafondi.end()) { if(thisImporto < plafondi[key]) { // Sottraggo plafondi[key] -= thisImporto; } else { if(DEBUG_ENABLED) { if(thisImporto > plafondi[key]) error_box("Importo maggiore del plafond rimanente"); } plafondi.erase(key); } } else if(DEBUG_ENABLED) { error_box("Houston abbiamo un problema...perchè non trovo questo plafond attivo!?"); } } else { if(plafondi.find(key) != plafondi.end()) { //Sommo plafondi[key] += thisImporto; } else { // Aggiungo ai plafond plafondi.insert(std::pair(key, thisImporto)); // Se devo scrivere abilito il plafond if(write) { changeStato(key, false); } } } } } /* Faccio un analisi di tutti i plafond aperti e li sommo salvandomeli in plafonds */ void TLi_manager::elabPlafond() { TRelation letint(LF_LETINT); TRectype filtro(letint.curr()); filtro.add("CODCLI", codcli); // All'inizio passo in iniDicInt la data del documento QUINDI posso usarla come data limite, se non ho nulla metto l'ultimo dell'anno TDate today(TODAY); if(!iniDicInt.ok()) { filtro.add("ANNO", today.year()); } else { filtro.add("ANNO", iniDicInt.year()); } if(!finDicInt.ok()) finDicInt = TDate(31, 12, iniDicInt.ok() ? iniDicInt.year() : today.year()); // Creo un cursore ordinato e prelevo la prima riga non chiusa TCursor c_dicint(&letint, "", 2, &filtro, &filtro); validPlafond = false; if(c_dicint.items() > 0) { // Cerco finchè non arrivo alla fine o non trovo una soluzione for(c_dicint = 0; c_dicint.pos() < c_dicint.items() && !soluzione; ++c_dicint) { TRectype row = c_dicint.curr(); // Esco se raggiungo una data successiva al nostro documento if(row.get_date("DAL") > finDicInt) break; if(!row.get_bool("CHIUSA")) { if(row.get_int("TIPOOP") != FINO_A_PLAFOND && row.get_int("TIPOOP") != SOLUZIONE_UNICA) break; if(row.get_int("TIPOOP") == SOLUZIONE_UNICA) { // Faccio un controllo in più per bloccare un utente con plafond di diverso tipo if(validPlafond) { // ERRORE! Esiste già un plafond e ho trovato una soluzione unica! validPlafond = false; plafondi.clear(); plafond = -UNO; return; } soluzione = true; } if(!validPlafond) iniDicInt = row.get_date("DAL"); // Aggiungo il plafond trovato all'elenco dei plafond static TString key; key.cut(0) << row.get("ANNO") << "|" << row.get("NUMPROT"); plafondi.insert(std::pair(key, row.get_real("IMPORTO"))); // Aggiungo il valore del plafond al totale plafond += row.get_real("IMPORTO"); validPlafond = true; } } } if(!validPlafond) plafond = -UNO; } const real TLi_manager::getPlaRes() { TToken_string tipi, stati; elabTipiStati(tipi, stati); return elabPlaRes(tipi, stati); } const real TLi_manager::getPlaRes(TToken_string tipi, TToken_string stati) { return elabPlaRes(tipi, stati); } const real TLi_manager::elabPlaRes(TToken_string tipi, TToken_string stati, TDate ad) { if(!validPlafond) return -UNO; TLista_documenti din; // Legge tutti i documenti di input // Trovo tutti i documenti che mi interessano e sottraggo l'imponibile al plafond din.read('D', tipocf, codcli, iniDicInt.year(), tipi, stati, iniDicInt, ad); for(int i = 0; i < din.items(); i++) { TToken_string plaf(din[i].get("PLAFOND"), ','); for(int i = 0; i < plaf.items(); i++) { TToken_string thePla(plaf.get(i)); static TString key; key.cut(0) << "," << thePla.get(_planno) << "|" << thePla.get(_plnumprot); if(din[i].tipo().nota_credito()) { if(plafondi.find(key) != plafondi.end()) { plafondi[key] += (real)thePla.get(_plimporto); } else { // Va aggiunto ex novo! // Calcolo l'importo delle righe che rientrano nel plafond plafondi.insert(std::pair(key, (real)thePla.get(_plimporto))); } } if(!din[i].tipo().nota_credito()) // thePla.get(_plchiusura) != "X" { if(plafondi.find(key) != plafondi.end()) { // La tolgo! Ma prima controllo che siano uguali if(DEBUG_ENABLED) { if(plafondi[key] != (real)thePla.get(_plimporto)) { if(!yesno_box(TR("Questa lettera di intento è incongruente,\nTotale attivo: %s\nTotale da disattivare: %s\nContinuare?"), plafondi[key].string(), thePla.get(_plimporto))) { plafond = -UNO; validPlafond = false; return plafond; } } } plafondi.erase(key); } else { plafondi[key] -= (real)thePla.get(_plimporto); } } } /* // Controllo se stiamo lavorando con una nota credito if(din[i].tipo().nota_credito()) { incrPlaf(din[i]); } else { TAssoc_array tabIva = din[i].tabella_iva(true); for (TRiepilogo_iva * totali = (TRiepilogo_iva *) tabIva.get(); totali != NULL; totali = (TRiepilogo_iva *) tabIva.get()) { if(checkIva(totali->cod_iva().codice())) { { consPlaf(totali->imp_orig()); } } } // Nel caso il plafond trovato fosse una soluzione unica e ho già trovato dei documenti vuol dire che il plafond non è più valido if(soluzione) { plafond = -UNO; break; } } */ } return plafond; } const real TLi_manager::elabUtil(TToken_string tipi, TToken_string stati, TDate ad) { if(!validPlafond) return -UNO; if(tipi.items() == 0) return ZERO; real utilizzato = ZERO; TLista_documenti din; // Legge tutti i documenti di input // Trovo tutti i documenti che mi interessano e sottraggo l'imponibile al plafond din.read('D', tipocf, codcli, iniDicInt.year(), tipi, stati, iniDicInt, ad); for(int i = 0; i < din.items(); i++) { TRectype pollo = din[i].head(); int ndoc = pollo.get_int("NDOC"); TDate datadoc = pollo.get("DATADOC"); TString tipodoc = pollo.get("TIPODOC"); TAssoc_array tabIva = din[i].tabella_iva(true); for (TRiepilogo_iva * totali = (TRiepilogo_iva *) tabIva.get(); totali != NULL; totali = (TRiepilogo_iva *) tabIva.get()) { if(checkIva(totali->cod_iva().codice())) { utilizzato += cache().get("%TIP", din[i].tipo().codice()).get_bool("B7") ? -totali->imp_orig() : totali->imp_orig(); } } // Nel caso il plafond trovato fosse una soluzione unica e ho già trovato dei documenti vuol dire che il plafond non è più valido if(soluzione) { utilizzato = -UNO; break; } } return utilizzato; } bool TLi_manager::testPlafond(TLista_documenti dout, TLog_report& lerr) { lerr.log(2, "Funzione da rifare"); return true; bool err = false; real resPlafond = getPlaRes(); real testPlafond = getPlaRes(); real totFatt; int i = 0; // Faccio un ragionamento identico a getPlaRes, ma in input ho la lista di documenti appena elaborati for(int i = 0; i < dout.items(); i++) { TAssoc_array tabIva = dout[i].tabella_iva(true); for (TRiepilogo_iva * totali = (TRiepilogo_iva *) tabIva.get(); totali != NULL; totali = (TRiepilogo_iva *) tabIva.get()) { if(checkIva(totali->cod_iva().codice())) { resPlafond -= totali->imp_orig(); totFatt += totali->imp_orig(); } } } if(resPlafond < 0) { err = true; // Alzo il flag dell'errore TString msgerr; msgerr << "Superata dichiarazione di intento cliente N." << dout[i].codcf() << "\nPlafond rimanente: " << resPlafond + totFatt << "\nTotale fatture generate: " << totFatt << "\nSforato di: " << -resPlafond << "\n"; lerr.log(2, msgerr); // 2 <- Errore } return err; } int TLi_manager::checkEditability(TDocumento& d) { TToken_string tipi, stati; elabTipiStati(tipi, stati); TLista_documenti din; // Legge tutti i documenti di input int ret = NOERR; // Trovo tutti i documenti che mi interessano din.read('D', tipocf, codcli, iniDicInt.year(), tipi, stati, iniDicInt, d.data()); // Oltre al mio documento c'è altro? if(din.items() > 1) ret = 1; for(int i = 0; i < din.items() && ret != -1; i++) { if(d != din[i]) ret = din[i].modificabile() ? ret : -1; } return ret; } void TLi_manager::changeStato(const TString& key, const bool stato) { TRectype Jean_Baptiste_Le_Rond_dAlembert = cache().get(LF_LETINT, key); // Che nome di classe! Jean_Baptiste_Le_Rond_dAlembert.put("CHIUSA", stato); Jean_Baptiste_Le_Rond_dAlembert.rewrite(TLocalisamfile(LF_LETINT)); TString skey; skey << key << "|" << stato ? "" : "X"; // Ottimizzazione portami via... modifiche.insert(std::pair(modifiche.size()+1, skey)); } void TLi_manager::revertModifiche() { if(!hasModifiche()) return; TLocalisamfile baguette(LF_LETINT); for(auto it = modifiche.begin(); it != modifiche.end(); ++it) { TToken_string key = it->second; TRectype Jean_Baptiste_Le_Rond_dAlembert = cache().get(LF_LETINT, key.get(0)); // Che nome di classe! Jean_Baptiste_Le_Rond_dAlembert.put("CHIUSA", key.get(1)); Jean_Baptiste_Le_Rond_dAlembert.rewrite(baguette); } clearModifiche(); } // TIPOCF, CODCLI, ANNO TLi_manager::TLi_manager(const char t, const long c, TDate iniDic, TDate finDic) : tipocf(t), codcli(c), iniDicInt(iniDic), finDicInt(finDic), tipidoc(ini_get_string(CONFIG_DITTA, "li", "TIPIDOC")), codivaDef(ini_get_string(CONFIG_DITTA, "li", "CODIVA")), codivaAlt(ini_get_string(CONFIG_DITTA, "li", "CODIVALT")), plafond(ZERO), validPlafond(false), soluzione(false) { elabPlafond(); }