campo-sirio/src/li/lilib01.cpp

616 lines
14 KiB
C++
Raw Normal View History

#include "lilib01.h"
#include "letint.h"
#include <doc.h>
#include "sqlset.h"
#include <modaut.h>
#include <utility.h>
#include <progind.h>
#ifndef __VELIB04_H
#include "../ve/velib04.h"
#endif
#define INIZIO_LETINT 2017
// ritorna il codice iva del plafond
const TString & iva_plafond()
{
static TString codiva_plafond_def("*");
static TString codiva_plafond_alt;
if (codiva_plafond_def == "*")
{
codiva_plafond_def = ini_get_string(CONFIG_DITTA, "li", "CODIVA");
codiva_plafond_alt = ini_get_string(CONFIG_DITTA, "li", "CODIVALT");
}
if (codiva_plafond_def.full())
return codiva_plafond_def;
if (codiva_plafond_alt.full())
return codiva_plafond_alt;
return EMPTY_STRING;
}
// Controllo se il codice iva <20> uguale a quello impostato per il calcolo del plafond
bool check_iva_plafond(const TString& cod)
{
return cod == iva_plafond();
}
const TString & make_key(const int anno, const int numplaf)
{
TString & key = get_tmp_string(20);
key.format("%04d|%06d", anno, numplaf);
return key;
}
static TToken_string __tipidoc;
static TToken_string __statidoc;
void get_tipi_stati()
{
if (__tipidoc.blank())
{
TToken_string tipidoc = (TToken_string &)ini_get_string(CONFIG_DITTA, "li", "TIPIDOC");
for (const char * tipo = tipidoc.get(0); tipo && *tipo; tipo = tipidoc.get())
{
TToken_string statidoc(ini_get_string(CONFIG_DITTA, "li", tipo), ',');
const int stato_ini = statidoc.get_int(0);
const int stato_fin = statidoc.get_int();
for (int i = stato_ini; i <= stato_fin; i++)
{
__tipidoc.add(tipo);
__statidoc.add(i);
}
}
}
}
TToken_string & tipi()
{
if (__tipidoc.blank())
get_tipi_stati();
return __tipidoc;
}
TToken_string & stati()
{
if (__statidoc.blank())
get_tipi_stati();
return __statidoc;
}
#define LINT_MSG 0
#define LINT_ERROR 1
#define LINT_CONDITIONAL_ERROR 2
#define LINT_FATAL 3
static TToken_string __lint_msg("", '\n');
static bool __lint_batch = false;
void lint_batch(const bool on) { __lint_batch = on; }
bool lint_add_msg(const char * msg, const int msg_type = LINT_MSG, const char * question = "")
{
TString m(msg);
bool ok = msg_type == LINT_MSG;
if (msg_type > LINT_MSG)
m.insert(TR("Errore : "));
if (msg_type == LINT_FATAL)
fatal_box(m);
if (__lint_batch)
__lint_msg.add(m);
else
{
switch (msg_type)
{
case LINT_MSG :
message_box(m);
break;
case LINT_ERROR:
error_box(m);
break;
case LINT_CONDITIONAL_ERROR:
m << ' ' << question << " ?";
yesnocancel_box (m);
break;
default:
break;
}
}
return ok;
}
void lint_reset_msg() { __lint_msg.cut(0); }
const TToken_string & lint_get_msg() { return __lint_msg; }
void TLi_manager::set_anno(const int anno)
{
if (_anno != anno)
{
_anno = anno;
read();
}
}
void genera_li_storico(const int anno, const long from_cli, const long to_cli, const char tipocf)
{
// Apro la tabella dei plafonds con chiave 2 (CODCLI+ANNO+NUMPROT) e per ogni cliente calcolo i plafond dal 2017
const TDate dal(1, 1, anno);
TRelation rletint(LF_LETINT);
TRectype * from_let = nullptr;
TRectype * to_let = nullptr;
if (from_cli > 0L)
{
from_let = new TRectype(rletint.file().curr());
from_let->put(LETINT_CODCLI, from_cli);
}
if (to_cli > 0L)
{
to_let = new TRectype(rletint.file().curr());
to_let->put(LETINT_CODCLI, to_cli);
}
TString filter = LETINT_DAL ; filter << ">=" << dal.date2ansi();
TCursor letint(&rletint, filter , 2, from_let, to_let);
const int items = letint.items();
TAssoc_array cli;
bool ok = true;
TString msg(TR("Ricostruzione plafond dal "));
msg << dal.string();
TProgress_monitor status(items, msg);
TString16 curr_codcli;
lint_reset_msg();
lint_batch();
for (letint = 0; ok && letint.pos() < items; ++letint)
{
if (ok = status.add_status())
{
const TString16 codcli = letint.curr().get(LETINT_CODCLI);
TBit_array * years = nullptr;
if (codcli != curr_codcli)
{
curr_codcli = codcli;
cli.add(curr_codcli, years = new TBit_array);
}
if (years != nullptr)
years->set(letint.curr().get_int(LETINT_ANNO) - INIZIO_LETINT);
}
}
TString_array keys;
cli.get_keys(keys);
keys.sort();
const int cli_items = keys.items();
for (int i = 0; i < cli_items; i++)
{
const TString & codcli = keys[i];
const TBit_array & years = (const TBit_array &)cli[codcli];
if (years.some_one())
{
const int last = years.last_one();
for (int y = years.first_one(); y <= last; y++)
{
const int anno = INIZIO_LETINT + y;
TLi_manager li('C', atol(codcli), anno);
li.rebuild_plafond(true, anno);
}
}
}
const TString messages = lint_get_msg();
if (messages.full())
message_box(messages);
lint_batch(false);
}
void TLi_manager::read(const TRectype & filter)
{
TCursor c(new TRelation(LF_LETINT), "", 2, &filter, &filter);
const int items = c.items();
_plafonds.destroy();
for (c = 0L; c.pos() < items; ++c)
_plafonds.add(c.curr());
_valid_plafond = items > 0;
}
int TLi_manager::flush()
{
int err = NOERR;
if (_dirty)
{
TLocalisamfile letint(LF_LETINT);
const int rows = _plafonds.items();
for (int r = 0; r < rows; r++)
{
TRectype & row = (TRectype &)_plafonds[r];
int err = row.rewrite(letint);
}
_dirty = false;
}
return err;
}
TRectype & TLi_manager::get_lint(const int numprot)
{
const int rows = _plafonds.items();
static TRectype nullrec(LF_LETINT); // orrible static record for errors
for (int r = 0; r < rows; r++)
{
TRectype & rec = (TRectype &) _plafonds[r];
if (numprot == rec.get_int(LETINT_NUMPROT))
return rec;
}
nullrec.put(LETINT_CODCLI, _codcli);
nullrec.put(LETINT_ANNO, _anno);
nullrec.put(LETINT_NUMPROT, numprot);
return nullrec;
}
void TLi_manager::add2lint(TRectype & reclint, const real & utilizzo, const bool add)
{
TLocalisamfile letint(LF_LETINT);
const real valore = add ? utilizzo : -utilizzo;
reclint.add(LETINT_UTILIZZATO, valore);
const bool soluzione_unica = reclint.get_bool(LETINT_TIPOOP) == SOLUZIONE_UNICA;
const real utilizzato = reclint.get_real(LETINT_UTILIZZATO);
const real importo = reclint.get_real(LETINT_IMPORTO);
const bool chiusa = (soluzione_unica && (utilizzato) != ZERO) || (utilizzato >= importo);
reclint.put(LETINT_CHIUSA, chiusa);
_dirty = true;
}
bool TLi_manager::utilizza_plafond(const TDocumento & d, TToken_string & plafs, const real importo)
{
bool ok = true;
TDate dal(1, 1, _anno);
real imp_plafond = importo;
const TDate datadoc = d.get_date(DOC_DATADOC);
const int day = datadoc - dal;
TToken_string & letints = _days[day];
const int letitems = letints.items();
if (d.is_nota_credito())
{
if (d.get(DOC_PLAFOND).empty())
{
TString8 codnumdocrif = d.get(DOC_CODNUMRIF);
int annodocrif = d.get_int(DOC_ANNORIF);
const long numdocrif = d.get_long(DOC_NUMDOCRIF);
if (codnumdocrif.blank())
codnumdocrif = d.get(DOC_CODNUM);
if (annodocrif == 0)
annodocrif = d.get_int(DOC_ANNO);
TDocumento docrif('D', annodocrif, codnumdocrif, numdocrif);
if (!docrif.empty())
{
plafs = docrif.get(DOC_PLAFOND);
const int items = plafs.items();
for (int k = 0; k < items; k++)
{
TToken_string plaf = plafs.get(k);
plaf.add(ZERO, _plimporto);
plafs.add(plaf, k);
}
}
}
}
const int plafsitems = plafs.items();
if (plafsitems < letitems)
{
TToken_string new_plafs("", ',');
for (int j = 0; j < letitems; j++)
{
TRectype & rec = (TRectype &)_plafonds[letints.get_int(j)];
bool chiusa = rec.get_bool(LETINT_CHIUSA);
const int numprot = rec.get_int(LETINT_NUMPROT);
const int tipo = rec.get_int(LETINT_TIPOOP);
TToken_string new_plaf;
new_plaf.add(_anno, _planno);
new_plaf.add(numprot, _plnumprot);
real utilizzo;
for (int k = 0; utilizzo == ZERO && k < plafsitems; k++)
{
TToken_string plaf(plafs.get(k));
if (plaf.get_int(_plnumprot) == numprot)
utilizzo = plaf.get_real(_plimporto);
}
new_plaf.add(utilizzo, _plimporto);
new_plafs.add(new_plaf);
}
plafs = new_plafs;
}
const bool storna = imp_plafond < ZERO;
for (int k = storna ? letitems - 1 : 0; imp_plafond != ZERO && (storna ? k >= 0: k < letitems); storna ? k-- : k++)
{
TRectype & rec = (TRectype &) _plafonds[letints.get_int(k)];
bool chiusa = rec.get_bool(LETINT_CHIUSA);
if (!chiusa || storna)
{
real utilizzo = imp_plafond;
const real let_importo = rec.get_real(LETINT_IMPORTO);
const real totale_utilizzato = rec.get_real(LETINT_UTILIZZATO);
TToken_string plaf = plafs.get(k);
const real disponibile = let_importo - totale_utilizzato;
const real totale = totale_utilizzato + utilizzo;
const real utilizzo_plaf = plaf.get_real(_plimporto);
if (d.is_nota_credito())
{
if (utilizzo > ZERO)
{
if (utilizzo + utilizzo_plaf > ZERO)
utilizzo = -utilizzo_plaf;
}
if (totale < ZERO)
utilizzo -= totale;
}
else
{
if (totale > let_importo)
utilizzo = disponibile;
if (totale < ZERO)
utilizzo += totale;
}
imp_plafond -= utilizzo;
plaf.add(utilizzo + utilizzo_plaf, _plimporto);
plafs.add(plaf, k);
add2lint(rec, utilizzo);
}
}
if (imp_plafond > ZERO)
{
TString msg(TR("Attenzione il plafond del cliente "));
msg << _codcli << ' ' << TR("il plafond per l'anno ") << _anno << ' ' <<
TR("<EFBFBD> stato superato di <20> ") << imp_plafond;
lint_add_msg(msg, LINT_ERROR);
ok = false;
}
return ok;
}
void TLi_manager::clear_letint()
{
const int rows = _plafonds.items();
for (int r = 0; r < rows; r++)
{
TRectype & row = (TRectype &) _plafonds[r];
row.zero(LETINT_UTILIZZATO);
row.zero(LETINT_CHIUSA);
}
_dirty = true;
flush();
}
void TLi_manager::rebuild_plafond(bool update_docs, const int anno)
{
TLista_documenti din;
TDate dal; dal.set_start_year(anno);
TDate al; al.set_end_year(anno);
set_anno(anno);
din.read('D', 'C', _codcli, anno, tipi(), stati(), dal, al);
const int items = din.items();
if (_valid_plafond)
{
TProgress_monitor status(items, "Aggiornamento plafond : Ricostuzione");
bool ok = true;
clear_letint();
for (int i = 0; ok && i < items; i++)
{
if (ok = status.add_status())
{
TToken_string plafs("", ',');
din[i].zero(DOC_PLAFOND);
if (update_docs)
din[i].rewrite();
else
utilizza_plafond(din[i], plafs, din[i].importo_plafond());
}
}
flush();
}
else
{
bool has_plafond = false;
for (int i = 0; !has_plafond && i < items; i++)
has_plafond = din[i].importo_plafond() != ZERO;
if (has_plafond)
{
TString msg(TR("Attenzione il cliente "));
msg << _codcli << TR(" per l'anno") << dal.year() << TR("ha documenti con esenzione plafond ma non ha plafond registrati");
lint_add_msg(msg);
}
}
}
void TLi_manager::read(const char t, const long c, TDate inidic, TDate findic)
{
TRectype reclint(LF_LETINT);
flush();
_plafond = ZERO;
_dirty = false;
_days.destroy();
TDate inizio_anno; inizio_anno.set_start_year(_anno);
TDate fine_anno; fine_anno.set_end_year(_anno);
const int last_day = fine_anno - inizio_anno;
for (int d = 0; d <= last_day; d++)
_days.add(new TToken_string);
if (t != ' ')
_tipocf = t;
if (c != 0)
_codcli = c;
if (_anno == 0)
_anno = TDate(TODAY).year();
reclint.put(LETINT_CODCLI, _codcli);
reclint.put(LETINT_ANNO, _anno);
read(reclint);
const int rows = _plafonds.items();
for (int r = 0; r < rows; r++)
{
const TRectype & row = (const TRectype &)_plafonds[r];
const real & importo = row.get_real(LETINT_IMPORTO);
const real & utilizzato = row.get_real(LETINT_UTILIZZATO);
_plafond += importo;
_utilizzato += utilizzato;
TDate inizio = row.get_date(LETINT_DAL);
TDate fine = row.get_date(LETINT_AL);
if (!inizio.ok())
inizio = inizio_anno;
if (!fine.ok())
fine = fine_anno;
const int from_day = inizio - inizio_anno;
const int to_day = fine - inizio_anno;
for (int d = from_day; d <= to_day; d++)
{
TToken_string & list = _days[d];
list.add(r);
}
}
}
bool TLi_manager::doc_ok(const TDocumento & doc) const
{
const TString8 tipodoc = doc.tipo().codice();
const TString4 stato = doc.get(DOC_STATO);
return (tipi().find(tipodoc) >= 0) && (stati().find(stato) >= 0);
}
bool TLi_manager::plafond_write(TDocumento& d)
{
bool ok = true;
real importo_plafond = d.importo_plafond();
if (doc_ok(d) && has_valid_plafond()) // Se il cliente non mi interessa
{
if (importo_plafond != ZERO)
{
TToken_string plafs("", ',');
// Il controllo <20> andato bene, adesso mi segno i plafond che ho utilizzato nel memo del documento
ok = utilizza_plafond(d, plafs, importo_plafond);
d.put(DOC_PLAFOND, plafs);
flush();
}
}
return ok;
}
bool TLi_manager::plafond_rewrite(TDocumento& d)
{
bool ok = true;
TToken_string plafs(d.get(DOC_PLAFOND), ',');
const TString8 tipodoc = d.tipo().codice();
const TString4 stato = d.get(DOC_STATO);
real diff = (doc_ok(d) && has_valid_plafond() ? d.importo_plafond() : ZERO) - d.importo_plafond_salvato();
// Calcolo le differenze tra il plafond attuale da verificare e quello precedente
if (diff != ZERO)
{
ok = utilizza_plafond(d, plafs, diff);
d.put(DOC_PLAFOND, plafs);
flush();
}
return ok;
}
bool TLi_manager::write_rewrite(TDocumento& d, bool rewrite)
{
bool ok = true;
// Aggiunte per il controllo plafond
if (main_app().has_module(LIAUT, CHK_DONGLE) && _valid_plafond)
{
if (rewrite)
ok = plafond_rewrite(d);
else
ok = plafond_write(d);
}
else
d.zero(DOC_PLAFOND);
return ok;
}
bool TLi_manager::remove(TDocumento& d)
{
bool ok = true;
TToken_string plafs(d.get(DOC_PLAFOND), ',');
if (main_app().has_module(LIAUT, CHK_DONGLE) && has_valid_plafond() && plafs.full())
{
ok = utilizza_plafond(d, plafs, -d.importo_plafond());
flush();
}
return ok;
}
TLi_manager::TLi_manager(const char t, const long c, const int anno)
: _tipocf(t), _codcli(c), _anno(anno), _plafond(),
_utilizzato(), _valid_plafond(false),
_dirty(false), _plafonds()
{
read();
}
TLi_manager::~TLi_manager()
{
flush();
}