Patch level : 12.0 476

Files correlati     : li
Commento            : Rivista in maniera approfondita la classe TLi_manager
- le TToken_string tipi e stati adesso sono di classe, vengono inizializzate dal costruttore a meno che non vengano passati esplicitamente da elabPlaRes.
- creata funzione getUse che richiama consPlaf o incrPlaf in autonomia
- Anche se non utilizzate committo le funzioni stornaDocs e recalcAfter (teoricamente al 100% funzionanti) che permettono di sornare + documenti e ricalcolare dopo una certa data
- sostituito checkEditability con checkUtilizzo per verificare se una Nota Credito è stata utilizzata
- Sistemati i costruttori, adesso richiedono la data finale obbligatoria, per quella iniziale se non la passo in automatico si imposta su 01/01/dataFinale.anno()
- Sistemate incrPlaf, consPlaf
- Aggiornata testPlaf secondo le nuove regole

git-svn-id: svn://10.65.10.50/branches/R_10_00@24194 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
mtollari 2017-11-20 08:52:18 +00:00
parent f152762e16
commit e3edfe411f
2 changed files with 299 additions and 100 deletions

View File

@ -5,24 +5,60 @@
#define SOLUZIONE_UNICA 1
#define FINO_A_PLAFOND 2
void TLi_manager::elabTipiStati(TToken_string& tipi, TToken_string& stati)
void TLi_manager::elabTipiStati()
{
for(int i = 0; i < tipidoc.items(); i++)
if(tipi.blank() && stati.blank())
{
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++)
for(int i = 0; i < tipidoc.items(); i++)
{
tipi.add(app);
stati.add(j);
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 TToken_string& TLi_manager::getUse(TDocumento& d, const bool write)
{
static TToken_string& ret = get_tmp_string();
TAssoc_array tabIva = d.tabella_iva(true);
real plaUtil = ZERO;
for (TRiepilogo_iva * totali = (TRiepilogo_iva *) tabIva.get(); totali != NULL; totali = (TRiepilogo_iva *) tabIva.get())
{
if(checkIva(totali->cod_iva().codice())) // Se l'iva del documento è diversa non mi interessa
{
plaUtil += totali->imp_orig();
}
}
if(plaUtil > ZERO)
{
if(d.is_nota_credito())
{
ret.cut(0) << incrPlaf(d, plaUtil, write);
}
else
{
ret.cut(0) << consPlaf(plaUtil, write);
if(ret.starts_with("ERRORE"))
ret << " al documento " << d.numerazione() << " n." << d.numero() << "\nTotale plafond da consumare: " << plaUtil.string() << "\nTotale rimasto: " << getPlafond().string();
}
}
return ret;
}
const TToken_string& TLi_manager::consPlaf(real& plafUsed, const bool write)
{
TToken_string& used(get_tmp_string()); used.separator(',');
static TToken_string used("", ','); used.cut(0);
if(!validPlafond || plafUsed > getPlafond())
{
used << "ERRORE NEL CALCOLO DEL PLAFOND";
@ -88,7 +124,7 @@ const TToken_string& TLi_manager::consPlaf(real& plafUsed, const bool write)
/* Aggiungo al plafond quello che trovo */
const TToken_string& TLi_manager::incrPlaf(TDocumento& d, real impNC, const bool write)
{
TToken_string& used = get_tmp_string(); used.separator(',');
static TToken_string used("", ','); used.cut(0);
// 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"))
@ -97,10 +133,9 @@ const TToken_string& TLi_manager::incrPlaf(TDocumento& d, real impNC, const bool
}
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],...
// Se il documento di riferimento non ha nulla inserito nel plafond esco, non mi interessa
if(lePlafs.items() == 0)
return used;
@ -114,7 +149,6 @@ const TToken_string& TLi_manager::incrPlaf(TDocumento& d, real impNC, const bool
if(checkIva(totali->cod_iva().codice()))
{
impNC += totali->imp_orig();
message_box("Hey guarda il mio segno e dillo a Tolla! %s", totali->imp_orig().string());
}
}
}
@ -161,14 +195,14 @@ const TToken_string& TLi_manager::incrPlaf(TDocumento& d, real impNC, const bool
{
open = false;
// Incremento!
plafondi[key] += importoPlaf;
plafondi[key] += rimanente;
}
else
{
// Va aggiunto ex novo!
// Calcolo l'importo delle righe che rientrano nel plafond
open = true;
plafondi.insert(std::pair<TString,real>(key, importoPlaf));
plafondi.insert(std::pair<TString,real>(key, rimanente));
// Se devo scrivere abilito il plafond
if(write)
@ -179,11 +213,16 @@ const TToken_string& TLi_manager::incrPlaf(TDocumento& d, real impNC, const bool
// Segno di aver usato il plafond
static TToken_string u; u.cut(0);
u.add(key, _planno);
u.add(importoPlaf.string(), _plimporto);
u.add(rimanente.string(), _plimporto);
u.add(open? "X" : "", _plchiusura);
used.add(u);
}
// Rigiro used, nelle note credito sono invertiti i plafond
static TToken_string usedApp("", ','); usedApp.cut(0);
for(int i = used.items(); i > 0; i--)
usedApp.add(used.get(used.items()-i), i-1);
// Sovrascrivo il documento
ds.put("PLAFOND", lePlafs);
ds.rewrite();
@ -191,10 +230,11 @@ const TToken_string& TLi_manager::incrPlaf(TDocumento& d, real impNC, const bool
// Tolgo la virgola finale
used.cut(used.len()-1);
return used;
// Succedono cose in memoria, devo rimediare così
return usedApp;
}
void TLi_manager::stornaDoc(TDocumento& d, const bool write)
/*
void TLi_manager::stornaDoc(const TDocumento& d, const bool write)
{
// Devo ricaricare le righe sui plafond che ho
TToken_string plafs(d.get("PLAFOND"), ',');
@ -249,7 +289,141 @@ void TLi_manager::stornaDoc(TDocumento& d, const bool write)
}
}
// Storna i documenti dopo a quello che riceve
void TLi_manager::stornaDocs(const TDocumento& d, const bool write)
{
TLista_documenti din; // Legge tutti i documenti di input
// Trovo tutti i documenti che mi interessano
din.read('D', tipocf, codcli, iniDicInt.year(), tipi, stati, d.data(), finDicInt);
for(int i = 0; i < din.items(); i++)
{
if(d.numero() < din[i].numero())
{
stornaDoc(din[i], write);
}
}
}
*/
const TToken_string& TLi_manager::stornaDoc(const TDocumento& d, real impDC, const bool write)
{
static TToken_string used("", ','); used.cut(0);
// True se devo stornare tutto il Doc
bool totale = impDC.is_zero();
bool ok = true;
// Devo ricaricare le righe sui plafond che ho
TToken_string plafs(d.get("PLAFOND"), ',');
for(int i = 0; i < plafs.items() && impDC > ZERO; i++)
{
TToken_string thisPlafond = plafs.get(i);
static TString key; key.cut(0) << thisPlafond.get(_planno) << "|" << thisPlafond.get(_plnumprot);
real thisImporto = thisPlafond.get(_plimporto);
if(totale)
{
if(thisImporto >= impDC)
{
thisImporto = impDC;
// Controllo se vado a stornare solo una parte o tutto, nel primo caso cambio la Token, nel secondo elimino normalmente
if(thisImporto > impDC)
{
thisPlafond.add(impDC, _plimporto);
plafs.add(thisPlafond, i);
}
else
plafs.destroy(i);
impDC = ZERO;
}
else
{
impDC -= thisImporto;
plafs.destroy(i);
}
}
TString asd = thisImporto.string();
if(d.is_nota_credito())
{
if(plafondi.find(key) != plafondi.end())
{
if(thisImporto < plafondi[key])
{
// Sottraggo
plafondi[key] -= thisImporto;
}
else
{
// Errore
used.cut(0) << "ERRORE: Non è presente abbastanza plafond rimanente per stornare la Nota Credito";
return used;
}
}
else
{
// Errore
if(DEBUG_ENABLED)
error_box("Houston abbiamo un problema...perchè non trovo questo plafond attivo!?");
used.cut(0) << "ERRORE: La lettera d'intento a cui si rifà questa Nota Credito non è aperta";
return used;
}
}
else
{
if(plafondi.find(key) != plafondi.end())
{
//Sommo
plafondi[key] += thisImporto;
}
else
{
// Aggiungo ai plafond
plafondi.insert(std::pair<TString, real>(key, thisImporto));
// Se devo scrivere abilito il plafond
if(write)
{
changeStato(key, false);
}
}
}
}
used.cut(0) << plafs;
return used;
}
// Where did you come from Cotton Eye Joe!
/*
bool TLi_manager::recalcAfter(const TDocumento& d, TLog_report& lerr)
{
TLista_documenti din; // Legge tutti i documenti di input
bool ok = true;
int first = -1;
// Trovo tutti i documenti che mi interessano
din.read('D', tipocf, codcli, iniDicInt.year(), tipi, stati, d.data(), finDicInt);
for(int i = 0; i < din.items() && ok; i++)
{
if(d.numero() < din[i].numero())
{
if(first == -1) first = i;
const TToken_string& use = getUse(din[i], true);
if(use.starts_with("ERRORE"))
{
ok = false;
lerr.log(2, use);
}
else
din[i].put("PLAFOND", use);
}
}
if(ok)
{
// Se va tutto bene scrivo tutti i documenti
for(; first < din.items(); first++)
din[first].rewrite();
}
return ok;
}
*/
/* Faccio un analisi di tutti i plafond aperti e li sommo salvandomeli in plafonds */
void TLi_manager::elabPlafond()
@ -257,19 +431,7 @@ 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());
filtro.add("ANNO", iniDicInt.year());
// Creo un cursore ordinato e prelevo la prima riga non chiusa
TCursor c_dicint(&letint, "", 2, &filtro, &filtro);
@ -323,9 +485,7 @@ void TLi_manager::elabPlafond()
const real TLi_manager::getPlaRes()
{
TToken_string tipi, stati;
elabTipiStati(tipi, stati);
return elabPlaRes(tipi, stati);
return elabPlaRes();
}
const real TLi_manager::getPlaRes(TToken_string tipi, TToken_string stati)
@ -333,8 +493,20 @@ 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)
const real TLi_manager::elabPlaRes(TToken_string t, TToken_string s, TDate ad)
{
if(elabPR)
return plafond;
else
elabPR = true;
if(t.full() && s.full())
{
tipi = t;
stati = s;
}
if(!ad.ok())
ad = finDicInt;
plafond = -UNO;
if(!validPlafond)
return plafond;
@ -360,7 +532,7 @@ const real TLi_manager::elabPlaRes(TToken_string tipi, TToken_string stati, TDat
{
plafondi[key] = ZERO;
}
plafondi[key] += (real)thePla.get(_plimporto);
plafondi[key] += static_cast<real>(thePla.get(_plimporto));
}
else
{
@ -371,7 +543,7 @@ const real TLi_manager::elabPlaRes(TToken_string tipi, TToken_string stati, TDat
return plafond;
}
// Calcolo l'importo delle righe che rientrano nel plafond
plafondi.insert(std::pair<TString,real>(key, (real)thePla.get(_plimporto)));
plafondi.insert(std::pair<TString,real>(key, static_cast<real>(thePla.get(_plimporto))));
}
}
else
@ -380,7 +552,7 @@ const real TLi_manager::elabPlaRes(TToken_string tipi, TToken_string stati, TDat
{
if(chiusura == "X")
{
if(DEBUG_ENABLED && plafondi[key] != (real)thePla.get(_plimporto) &&
if(DEBUG_ENABLED && plafondi[key] != static_cast<real>(thePla.get(_plimporto)) &&
!yesno_box(TR("Questa lettera di intento è incongruente,\nTotale attivo: %s\nTotale da disattivare: %s\nContinuare?"), plafondi[key].string(), thePla.get(_plimporto)))
{
validPlafond = false;
@ -390,7 +562,7 @@ const real TLi_manager::elabPlaRes(TToken_string tipi, TToken_string stati, TDat
}
else
{
plafondi[key] -= (real)thePla.get(_plimporto);
plafondi[key] -= static_cast<real>(thePla.get(_plimporto));
}
}
}
@ -423,10 +595,6 @@ const real TLi_manager::elabUtil(TToken_string tipi, TToken_string stati, TDate
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())
{
@ -447,61 +615,65 @@ const real TLi_manager::elabUtil(TToken_string tipi, TToken_string stati, TDate
return utilizzato;
}
bool TLi_manager::testPlafond(TLista_documenti dout, TLog_report& lerr)
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;
static TToken_string& use = get_tmp_string();
// Faccio un ragionamento identico a getPlaRes, ma in input ho la lista di documenti appena elaborati
for(int i = 0; i < dout.items(); i++)
for(int i = 0; i < dout.items() && !err; i++)
{
TAssoc_array tabIva = dout[i].tabella_iva(true);
for (TRiepilogo_iva * totali = (TRiepilogo_iva *) tabIva.get(); totali != NULL; totali = (TRiepilogo_iva *) tabIva.get())
use.cut(0) << getUse(dout[i], true);
if(use.starts_with("ERRORE"))
{
if(checkIva(totali->cod_iva().codice()))
{
resPlafond -= totali->imp_orig();
totFatt += totali->imp_orig();
}
TString msgerr;
msgerr << "Superata dichiarazione di intento cliente N." << dout[i].codcf() << "\n" << use;
lerr.log(2, msgerr);
revertModifiche();
clearModifiche();
err = true;
}
else
{
dout[i].put("PLAFOND", use);
}
}
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)
/* Per scelte implementative non ha una accuratezza del 100% */
bool TLi_manager::checkUtilizzo(TDocumento& d, real impNC)
{
TToken_string tipi, stati;
elabTipiStati(tipi, stati);
TLista_documenti din; // Legge tutti i documenti di input
int ret = NOERR;
TLista_documenti din;
bool ok;
TToken_string lePlafs(d.get("PLAFOND"), ',');
// 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++)
// Se me lo passa la funzione evito di calcolarlo
if(impNC.is_zero())
{
if(d != din[i])
ret = din[i].modificabile() ? ret : -1;
for (TRiepilogo_iva * totali = (TRiepilogo_iva *) d.tabella_iva(true).get(); totali != NULL; totali = (TRiepilogo_iva *) d.tabella_iva(true).get())
if(checkIva(totali->cod_iva().codice())) // Se l'iva del documento è diversa non mi interessa
impNC += totali->imp_orig();
}
return ret;
/* Per sapere se non ho usato il plafond di questa NC controllo innanzitutto se c'è ne abbastanza
* rimasto per coprire la NC, non è il controllo della vita ma toglie già un po' di calcoli */
ok = getPlaRes() > impNC;
// Sucessivamente vado in dettaglio a verificare se sono sempre maggiori (getPlaRes() mi carica anche la variabile "plafondi" per gli altri calcoli)
for(int i = 0; i < lePlafs.items() && ok; i++)
{
TToken_string thisPlaf(lePlafs.get(i));
static TString key; key.cut(0) << thisPlaf.get(_planno) << "|" << thisPlaf.get(_plnumprot);
if(plafondi.find(key) != plafondi.end())
{
ok = plafondi[key] > static_cast<real>(lePlafs.get(_plimporto));
}
else
ok = false;
}
return ok;
}
void TLi_manager::changeStato(const TString& key, const bool stato)
@ -530,11 +702,27 @@ void TLi_manager::revertModifiche()
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)
: 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), elabPR(false)
{
elabTipiStati();
elabPlafond();
}
TLi_manager::TLi_manager(const char t, const long c, TDate finDic)
: tipocf (t), codcli(c), 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), elabPR(false)
{
iniDicInt.set_day(01);
iniDicInt.set_month(01);
iniDicInt.set_year(finDic.year());
elabTipiStati();
elabPlafond();
}

View File

@ -23,8 +23,11 @@ enum plafStruct { _planno, _plnumprot, _plimporto, _plchiusura, _plNC };
class TLi_manager : TObject
{
TToken_string tipi;
TToken_string stati;
bool validPlafond;
bool soluzione;
bool elabPR;
const char tipocf;
const long codcli;
@ -38,8 +41,7 @@ class TLi_manager : TObject
// Elenco di plafond con eventuale
std::map<TString, real> plafondi;
std::map<int, TString> modifiche; // Progressivo, TToken_string(chiave,stato);
void elabTipiStati(TToken_string& tipi, TToken_string& stati); // Preparo due token string con le tipi[0] -> stati[0], ...
void elabTipiStati(); // Preparo due token string con tipi[0] -> stati[0], ...
public:
// Getters
@ -50,29 +52,37 @@ public:
// Ritorna se è una dichiarazione di tipo soluzione
bool isSoluzione() { return soluzione; }
// Funzione che unisce consPlaf e incrPlaf
const TToken_string& getUse(TDocumento& d, const bool write = false);
// "Consuma" il plafond
const TToken_string& consPlaf(real& plafUsed, const bool write = false);
// Da una nota credito passata incremento il plafond
const TToken_string& incrPlaf(TDocumento& d, real impNC = ZERO, const bool write = false);
// Storna un documento che riceve
void stornaDoc(TDocumento& d, const bool write = false);
const TToken_string& stornaDoc(const TDocumento& d, real impDC = ZERO, const bool write = false);
// Storna i documenti dopo a quello che riceve
//void stornaDocs(const TDocumento& d, const bool write = false);
// Ricalcola i documenti dopo quello che riceve
//bool recalcAfter(const TDocumento& d, TLog_report& lerr);
// Functions
// Vado a estrapolare il plafond
void elabPlafond();
// Testo se con i documenti passati supero il plafond
bool testPlafond(TLista_documenti dout, TLog_report& lerr);
bool testPlafond(TLista_documenti& dout, TLog_report& lerr);
// Controllo se il codice iva è uguale a quello impostato per il calcolo del plafond
bool checkIva(TString cod) { return cod == codivaDef || cod == codivaAlt; }
// Controllo se il documento passato non ha successori con plafonds assegnati, in tal caso se ce ne sono definitivi
// 0 -> Tutto OK, -1 -> Avvistato documento definitivo!, 1-> Avvistati documenti ma non definitivi
int checkEditability(TDocumento& d);
// Controllo se il plafond che la NC passata rilascia non è già stato utilizzato
bool checkUtilizzo(TDocumento& d, real impNC = ZERO);
// Calcolo il rimanente del plafond
const real getPlaRes();
// Calcolo il rimanente del plafond su tipi e stati documento passati
const real getPlaRes(TToken_string tipi, TToken_string stati);
// Funzione che effettivamente effettua il calcolodalla data della dichiarazione alla data passata
const real elabPlaRes(TToken_string tipi, TToken_string stati, TDate ad = 0L);
const real elabPlaRes(TToken_string t = "", TToken_string s = "", TDate ad = 0L);
// Ritorna la quantità di plafond utilizzato dalla data della dichiarazione alla data passata
const real elabUtil(TToken_string tipi, TToken_string stati, TDate ad = 0L);
// Modifica una lettera e salva la modifica in "modifiche"
@ -85,7 +95,8 @@ public:
void clearModifiche() { modifiche.clear(); }
// Costructors/Destructors
TLi_manager(const char t, const long c, TDate iniDic = 0L, TDate finDic = 0L);
TLi_manager(const char t, const long c, TDate iniDic, TDate finDic);
TLi_manager(const char t, const long c, TDate finDic); // Sets iniDicInt as 01/01/finDic.year()
virtual ~TLi_manager() {}
};