campo-sirio/src/cg/cglib01.cpp
smen 0fe88a6973 Patch level : 12.0
Files correlati     : cg2100.cpp cg2102.cpp cglib01.cpp

Commento:
Sistemati errori in prima nota. nei documenti automatici delle integrazioni non veniva riportato il numero di documento
2022-10-11 11:30:03 +02:00

2358 lines
56 KiB
C++
Executable File
Raw Blame History

// Esercizi contabili e registri IVA
#include "cglib.h"
#include <config.h>
#include <diction.h>
#include <mask.h>
#include <recset.h>
#include <relation.h>
#include <tabutil.h>
#include <clifo.h>
#include <comuni.h>
#include <mov.h>
#include <pconti.h>
#include <causali.h>
#include <rcausali.h>
#include <rmoviva.h>
#include <rmov.h>
#include <comuni.h>
#include "cgsaldac.h"
///////////////////////////////////////////////////////////
// Causale
///////////////////////////////////////////////////////////
TCausale::TCausale(const char* cod, int year)
: TArray(12), _rec(LF_CAUSALI),
_iva(iva_errata), _corrisp(false),
_sezione_clifo(' '), _provvisorio(' '),
_sezione_ritsoc(' '), _sezione_ritfis(' '), _sezione_revcharge(' '),
_regolarizzazione(false)
{
if (cod && *cod)
read(cod, year);
if (soloiva())
{
TCursor c(new TRelation(LF_CAUSALI));
int items = c.items();
for (c = 0L; c.pos() < items && !_regolarizzazione; ++c)
_regolarizzazione = c.curr().get(CAU_CODCAUREG) == codice();
}
}
bool TCausale::reread()
{
const TString4 cod = codice();
if (cod.full() && _year > 0)
return read(cod, _year);
return false;
}
// Legge le righe della causale attualmente selezionata sulla maschera
bool TCausale::read(const char* cod, int year)
{
_rec.zero(); // Delete header
destroy(); // Delete all rows
_iva = iva_errata; // Delete misc info
_sezione_clifo = _sezione_ritsoc = _provvisorio = ' ';
_corrisp = false;
_year = year;
if (_year <= 0)
_year = today.year();
if (cod && *cod > ' ')
{
_rec = cache().get(LF_CAUSALI, cod);
if (_rec.empty())
return false;
_provvisorio = _rec.get_char(CAU_PROVV);
TLocalisamfile rcaus(LF_RCAUSALI);
rcaus.put(CAU_CODCAUS, cod);
rcaus.put(CAU_NRIGA, 0);
int err;
for (err = rcaus.read(_isgteq); // Find first line
err == NOERR && rcaus.get(CAU_CODCAUS) == cod;
err = rcaus.next()) // Read next line
{
const int riga = rcaus.get_int(CAU_NRIGA);
add(rcaus.curr(), riga);
}
/* const TString4 codreg(_rec.get(CAU_REG));
const bool ok = _reg.read(codreg, year); // Read register
if (!ok && codreg.not_empty())
return error_box(FR("Non esiste il registro '%s' del %d"),
(const char*)codreg, year); */
calcIVA();
}
else
{
_iva = nessuna_iva; // Clear IVA data
_corrisp = false;
// _reg.read("", year);
}
return true;
}
TBill& TCausale::bill(int num, TBill& conto) const
{
const TRectype* rec = row(num);
if (rec != nullptr)
conto.set(rec->get_int(RCA_GRUPPO), rec->get_int(RCA_CONTO),
rec->get_long(RCA_SOTTOCONTO), rec->get_char(RCA_TIPOCF));
return conto;
}
const char* TCausale::cod_desc_agg(int num) const
{
const TRectype* rec = row(num);
if (rec)
return rec->get(RCA_CODDESC);
return ""; // ho problemi con ? :
}
const char* TCausale::desc_agg(int num) const
{
const char* cod = cod_desc_agg(num);
if (cod && *cod)
return cache().get("%DPN", cod, "S0");
return ""; // ho problemi con ? :
}
const char* TCausale::descrizione() const
{
return _rec.get(CAU_DESCR);
}
const char* TCausale::codice() const
{
return _rec.get(CAU_CODCAUS);
}
bool TCausale::data_doc() const
{
return _rec.get_bool(CAU_DATADOC);
}
bool TCausale::num_doc() const
{
return _rec.get_bool(CAU_NUMDOC);
}
bool TCausale::apertura() const
{
return _rec.get_char(CAU_MOVAP) == 'A';
}
bool TCausale::chiusura() const
{
return _rec.get_char(CAU_MOVAP) == 'C';
}
bool TCausale::sezionale() const
{
return _rec.get_bool(CAU_MOVSEZ);
}
bool TCausale::valuta() const
{
return _rec.get_bool(CAU_MOVVAL);
}
bool TCausale::intra() const
{
return _rec.get_bool(CAU_INTRACOM);
}
bool TCausale::valintra() const
{
return _rec.get_bool(CAU_VALINTRA);
}
bool TCausale::soloiva() const
{
return _rec.get_bool(CAU_SOLOIVA);
}
int TCausale::regime_speciale() const
{
return _rec.get_int(CAU_REGSPIVA);
}
bool TCausale::regolarizzazione() const
{
return _regolarizzazione;
}
bool TCausale::ril_fat_em_ric() const
{
return _rec.get_bool(CAU_RILFTEMRI);
}
bool TCausale::datareg_prec() const
{
return _rec.get_bool(CAU_DATAREGPR);
}
bool TCausale::reverse_charge() const
{
const int rsi = regime_speciale();
return rsi == 3 || (rsi >= 13 && rsi <= 18) || rsi == 50 || rsi == 51; // Reverse charge!
}
bool TCausale::reverse_charge_pubb() const
{
return reverse_charge() || regime_speciale() == 19; // Reverse charge!
}
bool TCausale::esclusione_allegati() const
{
return _rec.get_bool(CAU_ALLEG);
}
const TString& TCausale::causale_collegata() const
{
return _rec.get(CAU_CODCAUSIM);
}
const TString& TCausale::causale_reg_iva() const
{
return _rec.get(CAU_CODCAUREG);
}
const TString& TCausale::tipo_doc() const
{
return _rec.get(CAU_TIPODOC);
}
tipo_movimento TCausale::tipomov() const
{
return tipo_movimento(_rec.get_int(CAU_TIPOMOV));
}
const TString& TCausale::tipodoc() const
{
return _rec.get(CAU_TIPODOC);
}
const TString& TCausale::tipodocsdi() const
{
return _rec.get(CAU_TIPODOCSDI);
}
const bool TCausale::is_reg_autof() const
{
bool ok = reverse_charge_pubb();
if (ok)
{
const TString & tipodoc = tipodocsdi();
ok &= (tipodoc <= "TD17") && (tipodoc <= "TD19") ;
}
return ok;
}
bool TCausale::saldaconto(const TDate& datareg) const
{
bool yes = tipomov() > 0;
if (yes && datareg.ok())
{
static TDate _data_sal = ini_get_string(CONFIG_DITTA, "cg", "DatSal");
yes = datareg >= _data_sal;
}
return yes;
}
int TCausale::link_m770() const
{
return _rec.get_int(CAU_M770);
}
char TCausale::link_cespiti() const
{
return _rec.get_char(CAU_COLLCESP);
}
bool TCausale::link_analitica() const
{
return _rec.get_bool(CAU_MOVIND);
}
bool TCausale::link_industriale() const
{
return _rec.exist(CAU_MOVCGIND) && _rec.get_bool(CAU_MOVCGIND);
}
bool TCausale::ok() const
{
return iva() != iva_errata;
}
char TCausale::sezione(int riga, bool low_level) const
{
const TRectype* rec = row(riga);
char sez = rec ? toupper(rec->get_char(RCA_SEZIONE)) : ' ';
if (sez <= ' ' && !low_level) // Guess section on tipocf
{
const TRectype* uno = row(1);
char tipocf = uno ? toupper(uno->get_char(RCA_TIPOCF)) : ' ';
if (tipocf <= ' ')
tipocf = (iva() == iva_vendite) ? 'C' : 'F'; // Guess tipocf on IVA
sez = (tipocf == 'C') ? 'D' : 'A';
}
return sez;
}
char TCausale::sezione_clifo() const
{
if (_sezione_clifo <= ' ')
(char&)_sezione_clifo = sezione(1);
return _sezione_clifo;
}
char TCausale::sezione_ritsoc() const
{
if (_sezione_ritsoc <= ' ')
{
const tipo_movimento tm = tipomov();
(char&)_sezione_ritsoc = sezione(tm <= tm_nota_credito ? RIGA_RITENUTE_SOCIALI : RIGA_PAG_RITSOC, true);
if (_sezione_ritsoc < 'A')
(char&)_sezione_ritsoc = (tm <= tm_nota_credito ? sezione_clifo() : (sezione_clifo() == 'D' ? 'A' : 'D'));
}
return _sezione_ritsoc;
}
char TCausale::sezione_ritfis() const
{
if (_sezione_ritfis == ' ')
{
const tipo_movimento tm = tipomov();
(char&)_sezione_ritfis = sezione(tm <= tm_nota_credito ? RIGA_RITENUTE_FISCALI : RIGA_PAG_RITFIS, true); // Fatture o Pagamenti
if (_sezione_ritfis < 'A')
(char&)_sezione_ritfis = (tm <= tm_nota_credito ? sezione_clifo() : (sezione_clifo() == 'D' ? 'A' : 'D'));
}
return _sezione_ritfis;
}
char TCausale::sezione_revcharge() const
{
if (_sezione_revcharge <= ' ')
{
(char&)_sezione_revcharge = sezione(RIGA_REVERSE_CHARGE);
if (_sezione_revcharge < 'A')
(char&)_sezione_revcharge = sezione_clifo();
}
return _sezione_revcharge;
}
bool TCausale::fattura_in_ritardo() const
{
return _rec.get_bool(CAU_RITFATT);
}
void TCausale::calcIVA()
{
TipoIVA i = nessuna_iva; // Tipo IVA di default
bool c = false; // Corrispettivi di default
const TString& td = tipo_doc();
if (td.full())
{
const TRectype& tpd = cache().get("%TPD", td);
if (!tpd.empty())
{
i = (TipoIVA) tpd.get_int("I0"); // IVA acquisti, vendite, generica
const TipoIVA ri = reg().iva();
if (i == iva_generica)
i = ri;
if (i != ri)
{
error_box(FR("Tipo documento '%s' incompatibile con tipo registro (registro %s)"), (const char*) td, (const char*) codice_registro());
i = iva_errata;
}
c = tpd.get_bool("B0"); // B0 flag corrispettivi
}
else
error_box(FR("Tipo documento sconosciuto: '%s'"), (const char*)td);
}
_iva = i;
_corrisp = c;
}
const TString& TCausale::compatible(const TCausale& c) const
{
const char* err = nullptr;
if (sezionale() != c.sezionale())
err = TR("il segnale di sezionale");
if (intra() != c.intra())
err = TR("la gestione dei movimenti intra");
if (valuta() != c.valuta())
err = TR("la gestione valuta");
if (valintra() != c.valintra())
err = TR("la gestione valuta intracomunitaria");
if (corrispettivi() != c.corrispettivi())
err = TR("la gestione dei corrispettivi");
if (iva() != c.iva())
err = TR("il tipo di IVA");
if (tipomov() != c.tipomov())
err = TR("il tipo di movimento");
if (err != nullptr)
{
TString& msg = get_tmp_string();
msg.format(FR("Causale incompatibile per %s"), err);
return msg;
}
return EMPTY_STRING;
}
bool TCausale::IVA2bill(const TCodiceIVA& iva, TBill& c) const
{
const TString& tipo = iva.tipo();
if (tipo.not_empty())
{
if (tipo == "ES") bill(5, c); else
if (tipo == "NI") bill(6, c); else
if (tipo == "NS") bill(7, c);
}
if (!c.ok())
bill(2, c);
const int spric = c.tipo_cr();
if (spric == 2 || spric == 3)
{
const TString& td = tipo_doc();
if (td == "FV" || td == "NC")
c.tipo_cr(4);
}
return c.ok();
}
///////////////////////////////////////////////////////////
// TCache_causali
///////////////////////////////////////////////////////////
class TCache_causale : public TFile_cache
{
int _year;
protected:
virtual TObject* rec2obj(const TRectype & rec) const;
public:
const TCausale & caus(const char* cod, const int anno = 0);
TCache_causale() : TFile_cache(LF_CAUSALI), _year(0) { }
virtual ~TCache_causale() { }
};
TObject* TCache_causale::rec2obj(const TRectype & rec) const
{
TString4 cod = rec.get(CAU_CODCAUS);
cod.trim();
return new TCausale(cod, _year);
}
const TCausale & TCache_causale::caus(const char* cod, const int anno)
{
TToken_string key;
key.add(cod);
key.add(anno, 1);
_year = anno;
return (const TCausale &)query(key);
}
const TCausale & cached_causale(const char * codcaus, int year)
{
HIDDEN TCache_causale __cache_causale;
return __cache_causale.caus(codcaus, year);
}
///////////////////////////////////////////////////////////
// Gestione Tabella esercizi
///////////////////////////////////////////////////////////
TArray TEsercizi_contabili::_esercizi;
long TEsercizi_contabili::_firm = 0;
TEsercizio::TEsercizio(const TRectype& rec)
{
_codice = rec.get_int("CODTAB");
_inizio = rec.get("D0");
_fine = rec.get("D1");
_scarico = rec.get("D2");
_chiusura = rec.get("D3");
_chiusura_mag = rec.get("D4");
}
int TEsercizio::compare(const TSortable& s) const
{
const TEsercizio& e = (const TEsercizio&)s;
int c = 0;
if (_inizio != e._inizio)
c = _inizio > e._inizio ? +1 : -1;
return c;
}
const TDate& TEsercizio::chiusura() const
{
if (!_chiusura.ok() && fine() < TDate(TODAY))
{
TAssoc_array chiusure; // Lista delle causali di chiusura (solitamente una!)
TISAM_recordset caus("USE CAUS SELECT MOVAP='C'");
for (bool ok = caus.move_first(); ok; ok = caus.move_next())
{
const TString& codcaus = caus.get(CAU_CODCAUS).as_string();
chiusure.add(codcaus, codcaus);
}
const TDate presto = fine(); // Prima data utile per chiusura esercizio
TDate tardi = presto; tardi.addyear(); // Ultima data utile per chiusura esercizio
TString query;
query = "USE MOV KEY 2";
if (chiusure.items() == 1)
{
const TString& codcaus = *(TString*)chiusure.first_item();
query << " SELECT CODCAUS='" << codcaus << '\'';
}
query << "\nFROM DATAREG=#PRESTO\nTO DATAREG=#TARDI";
TISAM_recordset mov(query);
mov.set_var("#PRESTO", presto);
mov.set_var("#TARDI", tardi);
for (bool ok = mov.move_first(); ok; ok = mov.move_next())
{
const TString& codcaus = mov.get(MOV_CODCAUS).as_string();
if (chiusure.is_key(codcaus))
{
const TDate datacomp = mov.get(MOV_DATACOMP).as_date();
if (datacomp <= presto)
{
((TDate&)_chiusura) = datacomp; // Forzatura
TTable esc("ESC");
esc.put("CODTAB", codice());
if (esc.read(_isequal, _lock) == NOERR)
{
esc.put("D3", datacomp);
esc.rewrite();
}
}
break;
}
}
}
return _chiusura;
}
TEsercizi_contabili::TEsercizi_contabili()
{ }
void TEsercizi_contabili::update()
{
_firm = prefix().get_codditta();
_esercizi.destroy();
TTable tab_esc("ESC");
for (int err = tab_esc.first(); err == NOERR; err = tab_esc.next())
{
TEsercizio* e = new TEsercizio(tab_esc.curr());
_esercizi.add(e);
}
_esercizi.sort();
}
void TEsercizi_contabili::check()
{
if (_firm != prefix().get_codditta())
update();
}
int TEsercizi_contabili::date2index(const TDate& d) const
{
int i = -1;
if (d.ok())
{
check();
for (i = items()-1; i >= 0; i--)
{
const TEsercizio& e = esc(i);
if (d >= e.inizio() && d <= e.fine())
break;
}
}
return i;
}
int TEsercizi_contabili::esc2index(int codice) const
{
int i = -1;
if (codice > 0)
{
check();
for (i = items()-1; i >= 0; i--)
{
const TEsercizio& e = esc(i);
if (codice == e.codice())
break;
}
}
return i;
}
int TEsercizi_contabili::date2esc(const TDate& d) const
{
const int i = date2index(d);
return i >= 0 ? esc(i).codice() : 0;
}
int TEsercizi_contabili::date2prevesc(const TDate& d) const
{
const int i = date2index(d);
return i > 0 ? esc(i - 1).codice() : 0;
}
int TEsercizi_contabili::date2nextesc(const TDate& d) const
{
const int i = date2index(d);
return i >= 0 && i < items()-1 ? esc(i+1).codice() : 0;
}
int TEsercizi_contabili::first() const
{
check();
return items() ? esc(0).codice() : 0;
}
int TEsercizi_contabili::last() const
{
check();
return items() ? esc(items()-1).codice() : 0;
}
// Certified 99%
int TEsercizi_contabili::last_mag() const
{
check();
int i;
for (i = items()-1; i >= 0; i--)
{
const TEsercizio& e = esc(i);
if (e.chiusura_mag().ok())
break;
}
return esc(i+1).codice();
}
int TEsercizi_contabili::pred(int codice) const
{
const int i = esc2index(codice);
return i > 0 ? esc(i-1).codice() : 0;
}
int TEsercizi_contabili::next(int anno) const
{
const int i = esc2index(anno);
return i < items()-1 ? esc(i+1).codice() : 0;
}
bool TEsercizi_contabili::exist(int codice) const
{
const int i = esc2index(codice);
return i >= 0;
}
const TEsercizio& TEsercizi_contabili::esercizio(int codice) const
{
int i = esc2index(codice);
if (i < 0 && codice > 0)
{
error_box(FR("Attenzione! E' necessario aprire l'esercizio %d"), codice);
const int last_index = items()-1;
if (last_index >= 0)
{
TRectype rec(LF_TAB); rec.settab("ESC");
const TEsercizio& last = esc(last_index);
const int last_code = last.codice();
for (int k = last_code+1; k <= codice; k++)
{
rec.put("CODTAB", k);
TDate ini = last.inizio(); ini.set_year(ini.year()+k-last_code);
TDate fin = last.fine(); fin.set_year(fin.year()+k-last_code);
rec.put("D0", ini);
rec.put("D1", fin);
_esercizi.add(new TEsercizio(rec));
}
}
else
{
if (codice > 2000)
{
TRectype rec(LF_TAB); rec.settab("ESC");
rec.put("CODTAB", codice);
rec.put("D0", TDate(1,1,codice));
rec.put("D1", TDate(31,12,codice));
_esercizi.add(new TEsercizio(rec));
}
}
i = esc2index(codice); // Dovrei ritrovare l'ultimo
}
return esc(i);
}
bool TEsercizi_contabili::code2range(int codice, TDate& dal, TDate& al) const
{
bool ok = exist(codice);
if (ok)
{
const TEsercizio& e = esercizio(codice);
dal = e.inizio();
al = e.fine();
}
else
{
const int primo_esercizio = first();
const int ultimo_esercizio = last();
if (codice < primo_esercizio)
{
const TEsercizio& e = esercizio(primo_esercizio);
dal = e.inizio();
al = e.fine();
dal.addyear(primo_esercizio - codice);
al.addyear(primo_esercizio - codice);
ok = true;
}
if (codice > ultimo_esercizio)
{
const TEsercizio& e = esercizio(ultimo_esercizio);
dal = e.inizio();
al = e.fine();
dal.addyear(codice - ultimo_esercizio);
al.addyear(codice - ultimo_esercizio);
ok = true;
}
if (!ok)
{
if (codice > 1900)
{
dal = TDate(1, 1, codice);
al = TDate(31, 12, codice);
ok = true;
}
else
dal = al = TDate();
}
}
return ok;
}
TEsercizi_contabili& esercizi()
{
HIDDEN TEsercizi_contabili __esercizi;
return __esercizi;
}
/////////////////////////////////////////////////////////
// Simpatici metodi jolly
/////////////////////////////////////////////////////////
const char* iva2name(TipoIVA iva)
{
const char* i;
switch(iva)
{
case nessuna_iva:
i = TR("Nessuna IVA"); break;
case iva_acquisti:
i = TR("IVA Acquisti"); break;
case iva_vendite:
i = TR("IVA Vendite"); break;
case iva_generica:
i = TR("IVA Generica"); break;
default:
i = TR("IVA ERRATA!"); break;
}
return i;
}
const TString& cap2comune(const TString& cap, const TString& denom)
{
TString80 up_denom = denom;
up_denom.upper();
TString4 codone;
if (cap.len() == 5 && up_denom.full())
{
TString8 cappone = cap;
if (cappone[2] == '1') //e' un capoluogo di provincia
cappone.overwrite("00", 3, 2);
TRelation relcom(LF_COMUNI);
TRectype& comrec = relcom.curr();
comrec.put(COM_CAPCOM, cappone);
TCursor comuni (&relcom, "", 3, &comrec, &comrec);
const TRecnotype items = comuni.items();
comuni.freeze();
double cmp = 0.69;
for (comuni = 0L; comuni.pos() < items; ++comuni)
{
TString80 denominazione = comrec.get(COM_DENCOM);
denominazione.upper();
const double fc = xvt_str_fuzzy_compare (up_denom, denominazione);
if (fc > cmp)
{
codone = comrec.get(COM_COM);
cmp = fc;
}
}
}
if (codone.blank() && denom.full())
{
TLocalisamfile comuni(LF_COMUNI);
comuni.setkey(2);
comuni.put(COM_DENCOM, denom);
if (comuni.read() == NOERR)
codone = comuni.get(COM_COM);
else
{
double cmp = 0.9;
comuni.zero();
const TString4 pref = up_denom.left(4);
comuni.put(COM_DENCOM, pref);
for (int err = comuni.read(_isgteq); err == NOERR; err = comuni.next())
{
TString80 denominazione = comuni.get(COM_DENCOM);
denominazione.upper();
if (!denominazione.starts_with(pref))
break;
const double fc = xvt_str_fuzzy_compare(up_denom, denominazione);
if (fc > cmp)
{
cmp = fc;
codone = comuni.get(COM_COM);
}
}
}
}
return codone.full() ? (get_tmp_string() = codone) : EMPTY_STRING;
}
///////////////////////////////////////////////////////////
// Registro
///////////////////////////////////////////////////////////
TRegistro::TRegistro(const char* cod, int year)
: _rec(LF_TAB), _att(LF_ATTIV)
{ read(cod, year); }
TRegistro::TRegistro(const TRegistro & reg)
: _rec(LF_TAB), _att(LF_ATTIV)
{
const int year = atoi(reg._rec.get("CODTAB").sleft(4));
const TString8 cod = reg._rec.get("CODTAB").smid(4);
read(cod, year);
}
bool TRegistro::read(const char* cod, int year)
{
if (year <= 0)
{
const TDate oggi(TODAY);
year = oggi.year();
}
if (cod == nullptr)
cod = "";
TString8 chiave; chiave.format("%04d%s", year, cod);
_rec = cache().get("REG", chiave);
read_att();
return !_rec.empty();
}
bool TRegistro::force_read(const char* cod, int year)
{
TString8 chiave; chiave.format("%04d%s", year, cod);
cache().discard("REG", chiave);
return read(cod, year);
}
bool TRegistro::reread()
{
if (ok())
{
const TString8 n(name());
const int y = year();
return read(n, y);
}
return false;
}
int TRegistro::year() const
{
const TString& anno = _rec.get("CODTAB").left(4);
return atoi(anno);
}
const TString& TRegistro::name() const
{
return _rec.get("CODTAB").mid(4);
}
TRegistro& TRegistro::operator =(const TRegistro& r)
{
_rec = r._rec;
_att = r._att;
_prorata = r._prorata;
return *this;
}
TipoIVA TRegistro::iva() const
{
TipoIVA i = (TipoIVA)tipo();
switch (i)
{
case nessuna_iva:
case iva_vendite:
case iva_acquisti:
break;
case libro_giornale:
i = nessuna_iva;
break;
default:
error_box(FR("Il registro '%s' non e' un registro IVA o contabile: tipo %d"),
(const char*)name(), i);
i = nessuna_iva;
break;
}
return i;
}
bool TRegistro::read_att()
{
TString16 chiave;
chiave << prefix().get_codditta() << '|' << attivita();
_att = cache().get(LF_ATTIV, chiave);
// Ditta - Anno - Attivit<69> - Tipo Attivit<69> (fissata a 1)
chiave.format("%05ld", prefix().get_codditta());
chiave << year(); // non fare << year() << attivita()
chiave << attivita() << "1";
_prorata.destroy();
const TRectype& pla = cache().get("%PLA", chiave);
if (!pla.empty())
{
chiave.format("%d", year());
_prorata.add(chiave, pla.get_real("R8"));
_att.put("TIPOATT", pla.get("S7")); // Aggiorna tipo attivit<69>
}
return !_att.empty();
}
bool TRegistro::agenzia_viaggi() const
{
return _att.get_bool("REG74TER") && (iva() == iva_vendite);
}
const TString& TRegistro::tipo_attivita() const
{
return _att.get("TIPOATT");
}
real* TRegistro::read_prorata(int anno) const
{
TString16 chiave; // Ditta - Anno - Attivit<69> - Tipo Attivit<69> (fissata a 1)
chiave.format("%05ld", prefix().get_codditta());
chiave << anno << attivita() << "1";
real* prorata = nullptr;
const TRectype& pla = cache().get("%PLA", chiave);
if (!pla.empty())
prorata = new real(pla.get("R8"));
return prorata;
}
real TRegistro::prorata(int annodoc)
{
const int annoiva = year();
if (annodoc <= 1900) annodoc = annoiva; // Test per anno documento non specificato
const int annopro = annoiva >= 1998 && annodoc < annoiva ? annodoc+1 : annoiva;
TString16 chiave; chiave << annopro;
real* pr = (real*)_prorata.objptr(chiave);
if (pr == nullptr)
{
pr = read_prorata(annopro);
if (pr == nullptr && annopro != annoiva)
pr = read_prorata(annoiva);
if (pr == nullptr)
pr = new real(ZERO);
_prorata.add(chiave, pr, true);
}
return *pr;
}
void TRegistro::set_prorata(int annodoc, const real& pro)
{
const int annoiva = year();
if (annodoc <= 2000) annodoc = annoiva; // Test per anno documento non specificato
const int annopro = annodoc < annoiva ? annodoc+1 : annoiva;
TString4 chiave; chiave << annopro;
_prorata.add(chiave, pro, true);
}
// Certified 99%
bool TRegistro::update(long protiva, const TDate& datareg)
{
bool updated = true;
if (protiva > _rec.get_long("I5"))
{
_rec.put("I5", protiva);
updated = false;
}
if (datareg > _rec.get_date("D2"))
{
_rec.put("D2", datareg);
updated = false;
}
if (!updated)
{
TTable reg("REG");
updated = reg.rewrite(_rec) == NOERR;
cache().discard("REG", _rec.get("CODTAB")); // Forza rilettura registro in cache
}
return updated;
}
///////////////////////////////////////////////////////////
// TCache_registri
///////////////////////////////////////////////////////////
class TCache_registri : public TFile_cache
{
protected:
virtual TObject* rec2obj(const TRectype& rec) const;
public:
const TRegistro & registro(const char* cod, const int anno = 0);
TCache_registri() : TFile_cache("REG") { }
virtual ~TCache_registri() { }
};
TObject* TCache_registri::rec2obj(const TRectype& rec) const
{
TString k = rec.get("CODTAB");
return new TRegistro(k.mid(4), atoi(k.left(4)));
}
const TRegistro & TCache_registri::registro(const char* cod, const int anno)
{
TToken_string key("REG");
int year = anno;
if (year == 0)
year = ini_get_int(CONFIG_DITTA, "cg", "AnLiIv");
TString16 codtab;
codtab << format("%04d", year) << cod;
key.add(codtab);
return (const TRegistro &)query(key);
}
const TRegistro & cached_registro(const char * codreg, int year)
{
HIDDEN TCache_registri __cache_registri;
return __cache_registri.registro(codreg, year);
}
///////////////////////////////////////////////////////////
// Libro giornale
///////////////////////////////////////////////////////////
// Legge il libro giornale dell'anno specificato
bool TLibro_giornale::read(int y)
{
bool found = false;
if (y <= 0)
{
TEsercizi_contabili esc;
const int lastes = esc.last();
if (lastes > 0)
y = esc[lastes].inizio().year();
else
y = TDate(TODAY).year();
}
TString4 anno; anno.format("%04d", y);
TTable reg("REG");
reg.put("CODTAB", anno); // Cerca il primo registro dell'anno
for (int err = reg.read(_isgteq); err == NOERR; err = reg.next())
{
if (reg.get("CODTAB").compare(anno, 4) != 0)
break; // Sono arrivato all'anno dopo
if (reg.get_int("I0") == libro_giornale)
{
found = true;
break;
}
}
if (!found) reg.zero(); // Memorizza record (anche vuoto)
_rec = reg.curr();
return found;
}
TLibro_giornale::TLibro_giornale(int y)
{
read(y);
}
///////////////////////////////////////////////////////////
// Codice IVA
///////////////////////////////////////////////////////////
TCodiceIVA::TCodiceIVA(const char* cod) : TRectype(LF_TABCOM)
{
read(cod);
}
int TCodiceIVA::tipo_indetraibilita() const
{
int tipo = 0;
const TString& codind = indetraibilita(); // Codice indetraibilit<69> alfanumerico (ex. 1, 3, 9)
if (codind.full())
{
const TRectype& det = cache().get("%DET", codind);
if (det.empty())
tipo = atoi(codind);
else
tipo = det.get_int("I0");
}
return tipo; // Tipo indetraibilit<69>: 1,3,9
}
bool TCodiceIVA::read(const char* cod)
{
if (cod && *cod)
*this = cache().get("%IVA", cod);
else
zero();
return !empty();
}
void TCodiceIVA::round(real& n, int ndec, const char* codval) const
{
switch (ndec)
{
case AUTO_DECIMALS : ndec = (codval && *codval) ? TExchange(codval).decimals(false) : 2; break;
case AUTO_PRICES_DECIMALS: ndec = TExchange(codval).decimals(true); break;
default : break;
}
if (ndec < 10)
n.round(ndec);
}
real TCodiceIVA::imposta(const real& imponibile, int ndec, const char* codval) const
{
real iva = imponibile * percentuale() / CENTO;
round(iva, ndec, codval);
return iva;
}
real TCodiceIVA::imponibile(const real& imposta, int ndec, const char* codval) const
{
real imp = imposta * CENTO / percentuale() ;
round(imp, ndec, codval);
return imp;
}
real TCodiceIVA::scorpora(real& lordo, int ndec, const char* codval) const
{
round(lordo, ndec, codval); // Arrotondo importo lordo
real imponibile = lordo * CENTO / (CENTO + percentuale());
round(imponibile, ndec, codval); // Arrotondo importo netto
const real iva = lordo - imponibile;
lordo = imponibile; // lordo <20> un reference da aggiornare con l'imponibile!
return iva;
}
real TCodiceIVA::lordo(const real& imponibile, int ndec, const char* codval) const
{ return imponibile + imposta(imponibile, ndec, codval); }
/* bool TCodiceIVA::reverse_charge() const
{
const int rsi = regime_speciale();
return rsi == 13 || rsi == 50 || rsi == 51; // Reverse charge!
}
bool TCodiceIVA::reverse_charge_pubb() const
{
const int rsi = regime_speciale();
return rsi == 13 || rsi == 19 || rsi == 50 || rsi == 51; // Reverse charge! con aggiunta dienti pubblici
} */
///////////////////////////////////////////////////////////
// TCache_codIVA
///////////////////////////////////////////////////////////
class TCache_codIVA : public TFile_cache
{
protected:
virtual TObject* rec2obj(const TRectype & rec) const { return new TCodiceIVA(rec.get("CODTAB")); }
public:
const TCodiceIVA & codIVA(const char * codice);
TCache_codIVA() : TFile_cache("%IVA") { }
virtual ~TCache_codIVA() { }
};
const TCodiceIVA & TCache_codIVA::codIVA(const char * codice)
{
TToken_string key("IVA");
key.add(codice);
return (const TCodiceIVA &)query(key);
}
const TCodiceIVA & cached_codIVA(const char * codiva)
{
HIDDEN TCache_codIVA __cache_codIVA;
return __cache_codIVA.codIVA(codiva);
}
///////////////////////////////////////////////////////////
// TBill
///////////////////////////////////////////////////////////
TBill::~TBill()
{
if (_descrizione)
delete _descrizione;
}
void TBill::set_description(const char* d)
{
if (_descrizione || (d && *d))
{
if (_descrizione)
*_descrizione = d;
else
_descrizione = new TString(d);
}
}
// Certified 90%
const TBill& TBill::get(TToken_string& s, int from, int mode)
{
const char* first = s.get(from);
if (mode & 0x1)
{
_tipo = first ? char(toupper(*first)) : ' ';
first = s.get();
}
else
_tipo = ' ';
if (strchr(" CF", _tipo) == nullptr)
{
#ifdef DBG
error_box(FR("Tipo conto errato: '%c'"), _tipo);
#endif
_tipo = ' ';
}
_gruppo = first ? atoi(first) : 0;
_conto = s.get_int();
_sottoconto = s.get_long();
if (mode & 0x2)
set_description(s.get());
_tipo_cr = -1;
_sezione = ' ';
return *this;
}
const TBill& TBill::copy(const TBill& bill)
{
_tipo = bill._tipo;
_gruppo = bill._gruppo;
_conto = bill._conto;
_sottoconto = bill._sottoconto;
set_description(bill.descrizione());
_tipo_cr = bill._tipo_cr;
_sospeso = bill._sospeso;
_sezione = bill._sezione;
return *this;
}
// Certified 100%
const TBill& TBill::set(int g, int c, long s, char t, const char* d, int r)
{
_tipo = (t > ' ') ? char(toupper(t)) : ' ';
_gruppo = g;
_conto = c;
_sottoconto = s;
set_description(d);
_tipo_cr = r;
return *this;
}
const TBill& TBill::add_to(TToken_string& ts, int from, int mode)
{
if (mode & 0x4)
{
const int cr = tipo_cr();
if (cr > 0) ts.add(cr, from++); else ts.add(" ", from++);
}
if (mode & 0x1)
ts.add(_tipo, from++);
if (_gruppo > 0) ts.add(_gruppo, from++); else ts.add(" ", from++);
if (_conto > 0) ts.add(_conto, from++); else ts.add(" ", from++);
if (_sottoconto > 0L) ts.add(_sottoconto, from++); else ts.add(" ", from++);
if (mode & 0x2)
ts.add(descrizione(), from++);
return *this;
}
const char* TBill::field_name(int n, const TRectype& r, bool contro) const
{
CHECKD(n >= 0 && n <= 3, "Invalid bill field ", n);
if (contro)
{
CHECKD(r.num() == LF_RMOV || r.num() == LF_PAGSCA, "Record non valido per contropartita: ", r.num());
switch(n)
{
case 0: return RMV_GRUPPOC; break;
case 1: return RMV_CONTOC; break;
case 2: return RMV_SOTTOCONTOC; break;
default:return RMV_TIPOCC; break;
}
}
else
{
switch(n)
{
case 0: return RMV_GRUPPO; break;
case 1: return RMV_CONTO; break;
case 2:
if (r.num() == LF_CLIFO)
return CLI_CODCF;
else
return RMV_SOTTOCONTO;
break;
default:
switch(r.num())
{
case LF_CLIFO : return CLI_TIPOCF; break;
case LF_RCAUSALI: return RCA_TIPOCF; break;
default : return RMV_TIPOC; break;
}
break;
}
}
return "";
}
void TBill::put(TRectype& r, bool c) const
{
r.put(field_name(0, r, c), gruppo());
r.put(field_name(1, r, c), conto());
r.put(field_name(2, r, c), sottoconto());
r.put(field_name(3, r, c), tipo());
}
bool TBill::get(const TRectype& r, bool c)
{
char t = ' ';
if (r.type(field_name(3, r, c)) != _nullfld)
t = r.get_char(field_name(3, r, c));
set(r.get_int(field_name(0, r, c)),
r.get_int(field_name(1, r, c)),
r.get_long(field_name(2, r, c)),
t);
set_description(nullptr);
_tipo_cr = -1;
_sezione = ' ';
if (r.num() == LF_RMOVIVA)
tipo_cr(r.get_int(RMI_TIPOCR));
return ok();
}
void TBill::set(TMask& m, short g, short c, short s, short t, short d) const
{
if (g > 0)
m.set(g, gruppo());
if (c > 0)
m.set(c, conto());
if (s > 0)
m.set(s, sottoconto());
if (t > 0)
{
char typ[2] = { tipo(), '\0' };
m.set(t, typ);
}
if (d > 0)
m.set(d, descrizione());
}
void TBill::get(const TMask& m, short g, short c, short s, short t, short d)
{
const int gr = m.get_int(g);
const int co = m.get_int(c);
const long so = s > 0 ? m.get_long(s) : 0L;
char ti = ' ';
if (t)
ti = m.get(t)[0];
TString80 de;
if (d)
de = m.get(d);
set(gr, co, so, ti, de);
}
// Certified 100%
bool TBill::ok() const
{
return _gruppo != 0 && _conto != 0 && _sottoconto != 0L;
}
// Certified 99%
int TBill::compare(const TSortable& s) const
{
CHECK(class_name()==s.class_name(), "Can't compare TBill with TObject");
const TBill& c = (const TBill&)s;
int res = _gruppo - c._gruppo;
if (res) return res;
res = _conto - c._conto;
if (res) return res;
const long lres = _sottoconto - c._sottoconto;
if (lres < 0L) res = -1; else
if (lres > 0L) res = +1;
return res;
}
// Certified 95%
bool TBill::find()
{
bool ok = false;
if ((_tipo != 'C' && _tipo != 'F') || _sottoconto == 0L)
{
TRectype pcon(LF_PCON);
ok = read(pcon);
if (!ok && _sottoconto != 0L)
{
const long sotto = _sottoconto;
_sottoconto = 0L;
if (read(pcon))
_tipo = char(toupper(pcon.get_char(PCN_TMCF)));
_sottoconto = sotto;
}
}
if ((_tipo == 'C' || _tipo == 'F') && _sottoconto != 0L)
{
TString16 key;
key.format("%c|%ld", _tipo, _sottoconto);
const TRectype& clifo = cache().get(LF_CLIFO, key);
ok = !clifo.empty();
if (ok)
{
set_description(clifo.get(CLI_RAGSOC));
if (_tipo_cr < 0)
{
_tipo_cr = 0;
_sezione = ' ';
}
_sospeso = clifo.get_bool(CLI_SOSPESO);
const char tipoa = clifo.get_char(CLI_TIPOPERS);
if (tipoa == 'F') // Se persona fisica allora aggiusta la ragione sociale
{
TString nome(descrizione().mid(30));
if (nome.full())
{
_descrizione->cut(30);
_descrizione->trim(); nome.trim();
*_descrizione << ' ' << nome;
}
}
if (_gruppo == 0 || _conto == 0)
{
_gruppo = clifo.get_int(CLI_GRUPPO);
_conto = clifo.get_int(CLI_CONTO);
}
}
}
return ok;
}
bool TBill::read(TRectype &r)
{
bool ok = false;
if (tipo() <= ' ' || sottoconto() <= 0)
{
const char* key = string();
const TRectype& pcon = cache().get(LF_PCON, key);
if (!pcon.empty())
{
r = pcon;
ok = true;
}
}
if (ok)
{
_tipo_cr = r.get_int(PCN_TIPOSPRIC);
_sezione = r.get_char(PCN_SEZSALDI);
set_description(r.get(PCN_DESCR));
_sospeso = r.get_bool(PCN_SOSPESO);
}
else
r.zero();
return ok;
}
int TBill::tipo_att()
{
int tipo_att = 1;
if (tipo() <= ' ' && ok())
{
TBill bill(gruppo(), conto());
TRectype rec(LF_PCON); bill.read(rec);
const TIndbil ib = (TIndbil)rec.get_int(PCN_INDBIL);
if (ib == ib_passivita || ib == ib_ricavi)
{
read(rec);
const int ricser = rec.get_int(PCN_RICSER); // 0 = Altre attivita 1 = Servizi
tipo_att = (ricser == 1) ? 1 : 2;
}
}
return tipo_att;
}
// Certified 99%
const TString& TBill::descrizione() const
{
TBill& myself = (TBill&)*this;
// Se il conto e' valido (c'e' almeno il gruppo) cerca la sua descrizione su file
if ((_descrizione == nullptr || _descrizione->blank()) &&
(gruppo() != 0 || (tipo() > ' ' && codclifo()>0)))
{
if (!myself.find())
myself.set_description(TR("Sconosciuto"));
}
return _descrizione ? *_descrizione : (const TString&) EMPTY_STRING;
}
int TBill::tipo_cr() const
{
if (_tipo_cr < 0)
{
TBill& myself = (TBill&)*this;
myself.find();
}
return _tipo_cr;
}
int TBill::indicatore_bilancio() const
{
TString8 str;
str.format("%d|%d", gruppo(), conto());
const int ib = atoi(cache().get(LF_PCON, str, PCN_INDBIL));
if (ib <= 0)
{
TString msg = str;
msg.replace('|', '.');
msg.insert(TR("Impossibile stabilire l'indicatore di bilancio del conto "));
NFCHECK(msg);
}
return ib;
}
bool TBill::sospeso() const
{
if (_tipo_cr < 0) tipo_cr(); // trick to load _sospeso
return _sospeso;
}
char TBill::sezione() const
{
if (_sezione == ' ') tipo_cr(); // trick to load _sezione
return _sezione;
}
// Certified 100%
const char* TBill::string(int mode) const
{
TString& s = get_tmp_string();
if (mode & 0x8)
{
if (_sottoconto != 0)
s.format("%03d%03d%06ld", _gruppo, _conto, _sottoconto); else
if (_conto != 0)
s.format("%03d%03d", _gruppo, _conto); else
if (_gruppo != 0)
s.format("%03d", _gruppo);
return s;
}
if (mode & 0x4)
{
const int cr = tipo_cr();
if (cr > 0) s << cr << '|';
else s << " |";
}
if (mode & 0x1)
s << _tipo << '|';
if (_gruppo > 0) s << _gruppo << '|';
else s << " |";
if (_conto > 0) s << _conto << '|';
else s << " |";
if (_sottoconto > 0L) s << _sottoconto;
else s << ' ';
if (mode & 0x2)
s << '|' << descrizione();
return s;
}
bool TBill::required_cdc() const
{
TString16 key;
for (int i = 2; i >= 0; i--)
{
key.format("%d|%d|%ld", gruppo(), i > 0 ? conto() : 0, i > 1 ? sottoconto() : 0);
const TRectype& sottoc = cache().get(LF_PCON, key);
if (sottoc.get_bool(PCN_CMSNEEDED))
return true;
}
return false;
}
bool TBill::default_cdc(TString& cdc, TString& fas) const
{
bool ok = tipo() <= ' ' && sottoconto() > 0;
if (ok)
{
TString16 key;
for (int i = 2; i >= 0; i--)
{
key.format("%d|%d|%ld", gruppo(), i > 0 ? conto() : 0, i > 1 ? sottoconto() : 0);
const TRectype& pcon = cache().get(LF_PCON, key);
if (!pcon.empty())
{
cdc = pcon.get(PCN_CODCMS);
fas = pcon.get(PCN_FASCMS);
if (cdc.not_empty() || fas.not_empty())
break;
}
}
}
return ok && (cdc.not_empty() || fas.not_empty());
}
bool TBill::is_analitico() const
{
TString16 key;
for (int i = 2; i >= 0; i--)
{
key.format("%d|%d|%ld", gruppo(), i > 0 ? conto() : 0, i > 1 ? sottoconto() : 0);
const TRectype& picone = cache().get(LF_PCON, key);
if (picone.get_bool(PCN_ANALITICA))
return true;
}
return false;
}
const char* num2str(const TString& s)
{
TString& str = get_tmp_string(20);
str = s;
str.trim();
if (str.len() > 2)
{
str = s.left(2);
const int sub = atoi(s.mid(2, 2));
switch (sub)
{
case 2: str << " bis"; break;
case 3: str << " ter";break;
case 4: str << " quater"; break;
case 5: str << " quinquies"; break;
case 6: str << " sexies"; break;
default: break;
}
const TString& sotsub = s.mid(4);
if (sotsub.full())
str << ' ' << sotsub;
}
return (const char*)str;
}
///////////////////////////////////////////////////////////
// Movimento di prima nota
///////////////////////////////////////////////////////////
TMovimentoPN::TMovimentoPN()
: TRelation(LF_MOV), _cg(LF_RMOV, RMV_NUMRIG), _iva(LF_RMOVIVA, RMI_NUMRIG), _old_iva(LF_RMOVIVA, RMI_NUMRIG)
{
add(LF_RMOV, "NUMREG=NUMREG");
add(LF_RMOVIVA, "NUMREG=NUMREG");
}
void TMovimentoPN::destroy_rows(long num)
{
_cg.destroy_rows();
_cg.renum_key(RMV_NUMREG, num);
_iva.destroy_rows();
_iva.renum_key(RMI_NUMREG, num);
}
TRectype& TMovimentoPN::cg(int i)
{
return _cg.row(i >= 0 ? i + 1 : -1, true);
}
TRectype& TMovimentoPN::iva(int i)
{
return _iva.row(i >= 0 ? i + 1 : -1, true);
}
void TMovimentoPN::destroy_cg_row(int i)
{
if (i < 0)
_cg.destroy_rows();
else
_cg.destroy_row(i + 1, true);
}
void TMovimentoPN::destroy_iva_row(int i)
{
if (i < 0)
_iva.destroy_rows();
else
_iva.destroy_row(i + 1, true);
}
void TMovimentoPN::update_rev_charge()
{
const int year = lfile().get_int(MOV_ANNOIVA);
const TString & codcaus = lfile().get(MOV_CODCAUS);
const TCausale & caus = cached_causale(codcaus, year);
const TipoIVA t = caus.iva();
if (t == iva_acquisti)
{
const bool rev_charge = caus.reverse_charge_pubb();
if (rev_charge)
{
int rows = _iva.rows();
real imp_revcharge;
bool has_revcharge = false;
for (int i = _iva.first_row(); !has_revcharge && i <= rows; i = _iva.succ_row(i))
{
has_revcharge |= _iva[i].get_bool(RMI_REVCHARGE);
imp_revcharge += _iva[i].get_real(RMI_IMPOSTA);
}
if (!has_revcharge)
{
TRectype & h = head();
if (h.get_real(MOV_REVCHARGE) <= ZERO)
{
h.put(MOV_REVCHARGE, imp_revcharge);
h.sub(MOV_RITFIS, imp_revcharge);
if (h.get_real(MOV_RITFIS) < ZERO)
h.zero(MOV_RITFIS);
}
for (int i = _iva.first_row(); i <= rows; i = _iva.succ_row(i))
_iva[i].put(RMI_REVCHARGE, true);
}
}
}
}
int TMovimentoPN::read_mov_rows()
{
const TRectype& mov = curr();
const long numreg = mov.get_long(MOV_NUMREG);
TRectype* cgfilter = new TRectype(LF_RMOV);
cgfilter->put(RMV_NUMREG, numreg);
_cg.read(cgfilter);
TRectype* ivafilter = new TRectype(LF_RMOVIVA);
ivafilter->put(RMI_NUMREG, numreg);
_iva.read(ivafilter);
update_rev_charge();
_old_iva = _iva;
/*
if (_cg.rows() > 0 && _iva.rows() > 0 && cg(0).get_char(RMV_ROWTYPE) != 'T')
adjust_row_types();
*/
return _cg.rows();
}
int TMovimentoPN::read(TIsamop op, TReclock lockop)
{
const int err = TRelation::read(op, lockop);
if (err == NOERR)
{
_olddataliq = file().get(MOV_DATAREG); // Memorizza data liquidazione
const int meseliq = file().get_int(MOV_MESELIQ);
if (meseliq > 0 && meseliq != _olddataliq.month())
{
_olddataliq.set_day(1); // Evita problemi coi mesi corti!
_olddataliq.set_month(meseliq);
}
read_mov_rows(); // Riempie i due record array
}
return err;
}
char TMovimentoPN::frequenza_versamenti(int year) const
{
static int last_year = 0;
static long last_firm = 0;
static char last_freq = ' ';
const long firm = prefix().get_codditta();
if (firm != last_firm || year != last_year)
{
TString16 key; key.format("%05ld%d", firm, year);
TTable lia("%LIA");
lia.put("CODTAB", key);
if (lia.read() != NOERR)
{
TLocalisamfile nditte(LF_NDITTE);
nditte.put("CODDITTA", firm);
nditte.read();
last_freq = nditte.get_char("FREQVIVA");
}
else
last_freq = lia.get_char("S7");
if (last_freq != 'M' && last_freq != 'T')
{
error_box(FR("La frequenza versamenti IVA per la ditta %ld\n"
"non e' valida: la si considera mensile."), firm);
last_freq = 'M';
}
last_firm = firm;
last_year = year;
}
return last_freq;
}
int TMovimentoPN::date2liq(const TDate& data) const
{
const int anno = data.year();
int mese = data.month();
if (frequenza_versamenti(anno) == 'T')
mese += 2 - ((mese - 1) % 3);
return mese;
}
bool TMovimentoPN::controlla_liquidazione(const TDate& data, TRegistro& registro, bool reset) const
{
bool calcolata = false;
const int anno = data.year();
const int mese = date2liq(data);
// Chiave di LIM: Anno (1-4), Mese (5-6)
TString16 key; key.format("%04d%02d", anno, mese);
TTable lim("LIM");
lim.setkey(1);
lim.put("CODTAB", key);
if (lim.read() == NOERR)
{
calcolata = data.month() <= registro.mese_stampa_ultima_liq(); // Controlla se progressivi ricalcolati (registri)
if (reset)
{
// Resetta i flag di calcolato sulla liquidazione IVA del mese di registrazione
lim.zero("B0"); // calcolato
lim.rewrite();
}
}
if (reset)
{
const bool att_mista = registro.name().empty() ? FALSE : registro.attivita_mista();
const int att = att_mista ? 2 : 1;
// Chiave di PLM: Anno (1-4), Cod. Att. (5-9), Tipo att. (10-10), Mese (11-12)
TTable plm("PLM");
for (int a = 1; a <= att; a++)
{
TString16 chiave;
TString8 attivita(registro.attivita()); attivita.right_just(5, '0');
TString4 mese; mese.format("%02d", data.month());
chiave << data.year() << attivita << a << mese;
plm.put("CODTAB", chiave);
if (plm.read() == NOERR)
{
const bool calcolato = plm.get_bool("B0");
if (calcolato)
{
plm.zero("B0");
plm.rewrite();
}
}
}
}
return calcolata;
}
int TMovimentoPN::registra(bool re, bool force)
{
const TRectype& m = curr();
long numreg = m.get_long(MOV_NUMREG);
if (numreg <= 0)
{
if (!re) // Tento di numerare automaticamente in caso di write
{
TLocalisamfile mov(LF_MOV); // Non sposto il file principale della relazione!
numreg = 1;
if (mov.last() == NOERR)
numreg += mov.get_long(MOV_NUMREG);
curr().put(MOV_NUMREG, numreg);
}
else
return _isnocurkey;
}
int err = re ? TRelation::rewrite(force) : TRelation::write(force);
if (err != NOERR)
return err;
_cg.renum_key(MOV_NUMREG, numreg);
err = _cg.write(re);
if (err != NOERR)
return err;
const int annoiva = m.get_int(MOV_ANNOIVA);
const TString4 reg(m.get(MOV_REG));
TRegistro registro(reg, annoiva);
const bool att_mista = reg.empty() ? false : registro.attivita_mista();
update_rev_charge();
for (int i = 0; i < iva_items(); i++)
{
TRectype& r = iva(i);
int tipoatt = 1;
if (att_mista)
{
const char tipo = r.get_char(RMI_TIPOC);
if (tipo <= ' ')
{
TBill c(r.get_int(RMI_GRUPPO), r.get_int(RMI_CONTO), r.get_long(RMI_SOTTOCONTO));
tipoatt = c.tipo_att();
}
}
r.put(RMI_TIPOATT, tipoatt);
const TString & indetr = r.get(RMI_TIPODET);
if (indetr.full())
{
const TRectype& det = cache().get("%DET", indetr);
if (!det.empty() && !det.get_bool("FPC"))
{
TTable tab("%DET");
tab.curr() = det;
tab.curr().put("FPC", true);
tab.rewrite();
}
}
}
_iva.renum_key(MOV_NUMREG, numreg);
err = _iva.write(re);
if (err != NOERR)
return err;
// Aggiorna data registrazione e protocollo IVA sul registro
const TDate datareg(m.get(MOV_DATAREG));
if (reg.full())
{
const long protiva = m.get_long(MOV_PROTIVA);
const long uprotiva = m.get_long(MOV_UPROTIVA);
const long max = protiva > uprotiva ? protiva : uprotiva;
registro.update(max, datareg);
}
// Aggiorna flags di ricalcolo liquidazione
TDate dataliq(datareg);
const int mese_liq = m.get_int(MOV_MESELIQ);
if (mese_liq > 0 && mese_liq != dataliq.month())
{
dataliq.set_day(1); // Evita problemi coi mesi corti!
dataliq.set_month(mese_liq);
}
bool reset = !re;
if (reg.full())
{
reset = (dataliq.month() != _olddataliq.month() || _old_iva != _iva);
if (dataliq.month() != _olddataliq.month())
controlla_liquidazione(_olddataliq, registro, true);
}
else
{
const TCausale causale(m.get(MOV_CODCAUS), annoiva);
if (causale.saldaconto(datareg) && causale.tipomov() != tm_fattura)
{
TPartite_array partarray;
partarray.add_numreg(numreg);
const int npart = partarray.items();
for (TPartita * part = partarray.first(); !reset && part != nullptr; part = partarray.next())
{
const int nrpart = part->last();
for (int r = part->prima_fattura(); !reset && r >= 0 && r <= nrpart; r = part->succ(r))
{
TRiga_partite & rp = part->riga(r);
if (rp.is_fattura())
{
const TRectype & mov = cache().get(LF_MOV, rp.get(PART_NREG));
reset = mov.get_bool(MOV_LIQDIFF) || mov.get_bool(MOV_IVAXCASSA);
}
}
}
}
}
if (reset)
controlla_liquidazione(dataliq, registro, reset);
return err;
}
int TMovimentoPN::write(bool force)
{
return registra(FALSE, force);
}
int TMovimentoPN::rewrite(bool force)
{
return registra(true, force);
}
int TMovimentoPN::remove()
{
int err = _cg.remove();
if (err == NOERR)
err = _iva.remove();
if (err == NOERR)
err = TRelation::remove();
if (err == NOERR)
{
const TRectype& m = curr();
const TString4 reg(m.get(MOV_REG));
const int annoiva = m.get_int(MOV_ANNOIVA);
TRegistro registro(reg, annoiva);
controlla_liquidazione(_olddataliq, registro, true);
}
return err;
}
///////////////////////////////////////////////////////////
// Aggiustamento movimenti rovinati o convertiti male
///////////////////////////////////////////////////////////
bool TConti_array::add(const TBill& conto, const real& importo)
{
const char* key = conto.string();
real* imp = (real*)objptr(key);
if (imp == nullptr)
TAssoc_array::add(key, importo);
else
*imp += importo;
return imp != nullptr;
}
real TConti_array::importo(const TBill& conto)
{
const char* key = conto.string();
const real* imp = (real*)objptr(key);
return imp ? *imp : ZERO;
}
bool TConti_array::remove(const TBill& conto)
{
const char* key = conto.string();
return TAssoc_array::remove(key);
}
bool TConti_array::add_iva(bool det, const real& importo)
{
real* imp = nullptr;
if (!importo.is_zero())
{
const char* const key = det ? "D" : "N";
imp = (real*)objptr(key);
if (imp == nullptr)
TAssoc_array::add(key, importo);
else
*imp += importo;
}
return imp != nullptr;
}
real TConti_array::importo_iva(bool det)
{
const char* const key = det ? "D" : "N";
const real* imp = (real*)objptr(key);
return imp ? *imp : ZERO;
}
bool TConti_array::remove_iva(bool det)
{
const char* const key = det ? "D" : "N";
return TAssoc_array::remove(key);
}
real TMovimentoPN::indetraibile_al(const TString& codind, const TCausale& caus, int annodoc) const
{
int tipodet = 0;
return ::indetraibile_al(codind, caus, annodoc, tipodet);
}
int TMovimentoPN::analizza_riga_IVA(const real& imptot, const real& ivatot, const TCausale& caus,
int annodoc, const TString& codiva, const TString& codind,
real& imp_det, real& iva_det, real& imp_ind, real& iva_ind) const
{
const real perc_ind = indetraibile_al(codind, caus, annodoc);
const bool corrispettivo = caus.corrispettivi();
TBill billind; caus.bill(RIGA_IVA_NON_DETRAIBILE, billind);
const bool iva_ind_al_costo = !billind.ok();
return analizza_IVA(imptot, ivatot, perc_ind, corrispettivo, iva_ind_al_costo,
codiva, imp_det, iva_det, imp_ind, iva_ind);
}
// Aggiusta i row types se sono andati persi o non sono stati convertiti
void TMovimentoPN::adjust_rowtypes()
{
const TRectype& mov = curr();
const char tipo = mov.get_char(MOV_TIPO);
const long codice = mov.get_long(MOV_CODCF);
const int annoiva = mov.get_int(MOV_ANNOIVA);
const int annodoc = mov.get_date(MOV_DATADOC).year();
const TCausale causale(mov.get(MOV_CODCAUS), annoiva);
TConti_array conti;
int r;
for (r = 0; r < _iva.rows(); r++)
{
const TRectype& row = iva(r);
const TBill bill(row);
const real imponibile(row.get(RMI_IMPONIBILE));
const real imposta(row.get(RMI_IMPOSTA));
const TString4 codiva = row.get(RMI_CODIVA);
const TString4 codind = row.get(RMI_TIPODET);
real imp_det, iva_det, imp_ind, iva_ind;
analizza_riga_IVA(imponibile, imposta, causale, annodoc, codiva, codind,
imp_det, iva_det, imp_ind, iva_ind);
conti.add(bill, imp_det + imp_ind);
conti.add_iva(false, iva_ind);
conti.add_iva(true, iva_det);
}
bool totale = FALSE;
bool ritfis = mov.get_real(MOV_RITFIS).is_zero();
bool ritsoc = mov.get_real(MOV_RITSOC).is_zero();
bool ivadet = conti.importo_iva(true).is_zero();
bool ivanon = conti.importo_iva(FALSE).is_zero();
for (r = 0; r < _cg.rows(); r++)
{
TRectype& row = cg(r);
const char rt = row.get_char(RMV_ROWTYPE);
switch (rt)
{
case 'F': ritfis = true; break;
case 'S': ritsoc = true; break;
case 'T': totale = true; break;
default: break;
}
if (rt > ' ') continue;
if (!totale && row.get_char(RMV_TIPOC) == tipo && row.get_long(RMV_SOTTOCONTO) == codice)
{
row.put(RMV_ROWTYPE, 'T');
totale = true;
continue;
}
const real importo(row.get(RMV_IMPORTO));
const TBill bill(row);
if (!ritfis && importo == mov.get_real(MOV_RITFIS))
{
TBill conto_rit; causale.bill(RIGA_PAG_RITFIS, conto_rit);
if (!conto_rit.ok() || conto_rit == bill)
{
row.put(RMV_ROWTYPE, 'F');
ritfis = true;
continue;
}
}
if (!ritsoc && importo == mov.get_real(MOV_RITSOC))
{
TBill conto_rit; causale.bill(RIGA_PAG_RITSOC, conto_rit);
if (!conto_rit.ok() || conto_rit == bill)
{
row.put(RMV_ROWTYPE, 'S');
ritsoc = true;
continue;
}
}
if (!conti.ok())
continue; // Ho esaurito i conti IVA
if (importo == conti.importo(bill))
{
row.put(RMV_ROWTYPE, 'I');
conti.remove(bill);
continue;
}
if (!ivadet && importo == conti.importo_iva(true))
{
row.put(RMV_ROWTYPE, 'D');
conti.remove_iva(true);
continue;
}
if (!ivanon && importo == conti.importo_iva(FALSE))
{
row.put(RMV_ROWTYPE, 'N');
conti.remove_iva(FALSE);
continue;
}
}
}
TMovimentoPN& TMovimentoPN::get_sum_imponibile_imposta(real& s_imponibili, real& s_imposte)
{
TRecord_array& iva = iva_rows();
s_imponibili = ZERO;
s_imposte = ZERO;
for (int i = iva.first_row(); i <= iva.rows(); ++i)
{
TRectype& r = iva[i];
s_imponibili += r.get_real("IMPONIBILE");
s_imposte += r.get_real("IMPOSTA");
}
return *this;
}