Patch level : 12.0 no-patch

Files correlati     : ve (tutti quelli che calcolano il conai)
Commento            : Implemented #54
- Aggiunto nuovo calcolo COANI
- Aggiunti warning in funzioni che non si dovrebbero più accedere
- Aggiunta classe TConai con tutte le informazioni su Conai e codice spesa
This commit is contained in:
Mattia Tollari 2019-07-29 11:48:40 +02:00
parent 5024861411
commit a01cedd0ae
4 changed files with 261 additions and 97 deletions

View File

@ -78,5 +78,5 @@
#define RDOC_VALC "VALC"
#define RDOC_VALV "VALV"
#define RDOC_PPROV "PPROV"
#define RDOC_TIPOCON "TIPOCON" // Con questo campo capisco a quale sottocategoria conai si riferisce la riga autogenerata
#endif

View File

@ -54,6 +54,8 @@ class TSelect_color_mask;
#include <rdoc.h>
#endif
#include <map>
#define RIGA_MERCE 'M'
#define RIGA_SPESEDOC 'S'
#define RIGA_PRESTAZIONI 'P'
@ -536,7 +538,8 @@ enum TCONAI_class { CONAI_NONE=-1, CONAI_FIRST=0,
CONAI_LAST=5, CONAI_CLASSES=6
};
TCONAI_class conai_str2class(const char* class_or_subclass);
TCONAI_class conai_str2class(const char* class_or_subclass);
const char* conai_class2str(TCONAI_class cc);
const char* conai_material(TCONAI_class cc);
bool conai_configured_class(TCONAI_class cc);
const char* conai_peso_name(TCONAI_class cc, int logic_num = LF_RIGHEDOC);
@ -547,13 +550,35 @@ const char* conai_esenzione_name(TCONAI_class cc, int logicnum = LF_RIGHEDOC);
#define FOR_EACH_CONAI_CLASS(cc) for (TCONAI_class cc = CONAI_FIRST; cc < CONAI_CLASSES; cc=TCONAI_class(cc+1))
#define FOR_EACH_CONFIGURED_CONAI_CLASS(cc) FOR_EACH_CONAI_CLASS(cc) if (conai_configured_class(cc))
class TConai : public TObject
{
private:
/* It's a trap!
* Design mappa 1:
* Codice CONAI, mappa2
* Design mappa 1:
* Sottocategoria CONAI, classe spesa
*/
std::map<TString, std::map<TString, TSpesa_prest>> _conais;
std::map<TString, TCONAI_class> _tipo_spesa;
public:
const TSpesa_prest& get_spesa(const TString& cat, const TString& sottocat) { return _conais[cat][sottocat]; }
const TSpesa_prest& get_spesa(const TString& full_sottocat) { return get_spesa(full_sottocat.left(2), full_sottocat.right(2)); }
const std::map<TString, TSpesa_prest> get_categoria(const TString& cat) { return _conais[cat]; }
const bool find(const TString& cod_spesa) { return _conais.find(cod_spesa.left(2)) != _conais.end() && _conais[cod_spesa.left(2)].find(cod_spesa.right(2)) != _conais[cod_spesa.left(2)].end(); }
const TString_array get_lista_cod_spesa();
TConai();
};
///////////////////////////////////////////////////////////
// TRiga_documento
///////////////////////////////////////////////////////////
class TRiga_documento : public TAuto_variable_rectype // velib02
{
TDocumento* _doc;
TDocumento* _doc;
static long _firm;
static TAssoc_array _tipi;
static TAssoc_array _spese;
@ -667,7 +692,7 @@ public:
virtual real quantita_mag() const;
virtual real qtaevasa_mag() const;
virtual real qtaresidua_mag() const;
real calc_conai_qta(TCONAI_class type) const;
real calc_conai_qta(TCONAI_class type, const int num_field) const;
real valore(bool totale, bool lordo = false, int ndec = AUTO_DECIMALS) const;
const TString& codice_costo() const;
@ -750,7 +775,7 @@ class TDocumento : public TMultiple_rectype // velib03
TString8 _old_agente; // Agente originale
TString8 _old_agente1; // Secondo Agente originale
TRiga_documento * _sconto; // Riga per lo sconto di testata
TRiga_documento * _sconto; // Riga per lo sconto di testata
TRiga_documento * _esenzione; // Riga per l' esenzione iva
TRiga_documento * _valfisc; // Riga di valenza fiscale per fatture 2019+
@ -764,6 +789,9 @@ class TDocumento : public TMultiple_rectype // velib03
static short _has_provv;
static TCodgiac_livelli *_livelli;
TConai _conai;
std::map<TString, real> _conaiqta; // Per ogni sottocategoria CONAI mi calcola la qta
protected:
virtual TRectype * new_body_record(int logicnum = 0)
{ return new TRiga_documento(this); }
@ -918,8 +946,10 @@ public:
TPagamento& pagamento();
void update_spese_aut(TString_array & spese, bool preserve_old = false, TSheet_field * sh = NULL, bool force = false);
real calc_conai_qta(TCONAI_class type);
void update_conai_qta();
//real calc_conai_qta(TCONAI_class type);
void update_conai();
void old_update_conai();
bool is_generic() const { return tipo_valido() && tipo().is_generic(); }
bool is_fattura() const { return tipo_valido() && tipo().is_fattura(); }
@ -1105,6 +1135,7 @@ public:
static bool num_handler( TMask_field& f, KEY key );
static bool tipo_handler( TMask_field& f, KEY key );
static bool numdocrif_search_handler( TMask_field& f, KEY key );
static bool ragsoc_search_handler( TMask_field& f, KEY key );
static bool rif_search_handler( TMask_field& f, KEY key );
static bool datadocrif_handler(TMask_field& f, KEY key);
static bool sheet_handler(TMask_field& f, KEY key);

View File

@ -1,3 +1,4 @@
#include "velib.h"
#include "sconti.h"
#include "vepriv.h"
#include "../ca/commesse.h"
@ -5,6 +6,7 @@
#include <config.h>
#include <recset.h>
#include <utility.h>
#include <memory>
///////////////////////////////////////////////////////////
// Tipo riga di un documento
@ -886,6 +888,12 @@ TCONAI_class conai_str2class(const char* code)
return ct;
}
const char * conai_class2str(TCONAI_class cc)
{
static const char* conai_str[CONAI_CLASSES] = { "AC", "AL", "CA", "PL", "LE", "VE" };
return conai_str[cc];
}
const char* conai_material(TCONAI_class cc)
{
CHECK_CONAI(cc);
@ -924,6 +932,27 @@ bool conai_configured_class(TCONAI_class cc)
return cc>=CONAI_FIRST && cc<=CONAI_LAST && __con_conf[cc];
}
TString conai_configured_spesa(TCONAI_class cc)
{
CHECK_CONAI(cc);
static TToken_string* __con_conf = NULL;
if (__con_conf == NULL)
{
__con_conf = new TToken_string[CONAI_CLASSES];
static const char* const __conai_suffixes[CONAI_CLASSES] = { "ACC", "ALL", "CAR", "PLA", "LEG", "VET" };
TConfig c(CONFIG_DITTA, "ve");
TString8 name_conf, name_cods, cod_spesa;
FOR_EACH_CONAI_CLASS(i)
{
name_cods.cut(0) << "COD" << __conai_suffixes[i];
__con_conf->add(c.get(name_cods), i);
}
}
return __con_conf->get(cc);
}
// Campi virtuali per peso CONAI su RDOC e ANAMAG in Kg
const char* conai_peso_name(TCONAI_class type, int logicnum)
{
@ -937,8 +966,11 @@ const char* conai_peso_name(TCONAI_class type, int logicnum)
switch (logicnum)
{
case LF_ANAMAG : return __conai_peso_anmg[type];
case LF_RIGHEDOC: return __conai_peso_rdoc[type];
case LF_ANAMAG :
error_box("La gestione conai è stata modificata! Impossibile determinare il campo");
return __conai_peso_anmg[type];
case LF_RIGHEDOC:
return __conai_peso_rdoc[type];
default : break;
}
}
@ -957,7 +989,9 @@ const char* conai_sottocat_name(TCONAI_class type, int logicnum)
ANAMAG_CONAISC"[13,16]", ANAMAG_CONAISC"[17,20]", ANAMAG_CONAISC"[21,24]" };
switch (logicnum)
{
case LF_ANAMAG : return __conai_scat_anmg[type];
case LF_ANAMAG :
error_box("La gestione conai è stata modificata! Impossibile determinare il campo");
return __conai_scat_anmg[type];
case LF_RIGHEDOC: return __conai_scat_rdoc[type];
default : break;
}
@ -982,16 +1016,63 @@ const char* conai_esenzione_name(TCONAI_class cc, int logicnum)
return "";
}
///////////////////////////////////////////////////////////
// TConai
///////////////////////////////////////////////////////////
const TString_array TConai::get_lista_cod_spesa()
{
TString_array ret;
for (auto i = _conais.begin(); i != _conais.end(); ++i)
{
/*for (auto j = i->second.begin(); j != i->second().end(); ++j)
{
if (ret.find(j->second.codice()) == -1)
ret.add(j->second.codice());
}
*/
}
return ret;
}
TConai::TConai()
{
TRelation rel(LF_TABMOD);
TRectype rec(LF_TABMOD);
rec.put("MOD", "VE");
rec.put("COD", "SCC");
TCursor conais(&rel, "", 1, &rec, &rec);
for (conais = 0; conais.pos() < conais.items(); ++conais)
{
TRectype row = conais.curr();
const TString& con_class = row.get("CODTAB").left(2);
const TString& con_sub = row.get("CODTAB").mid(2);
const TString& cod_spesa = row.get("S1").blank() ? conai_configured_spesa(conai_str2class(con_class)) : row.get("S1");
if (conai_configured_class(conai_str2class(con_class)))
{
// Aggiungo
_conais[con_class][con_sub] = TSpesa_prest(cod_spesa);
}
}
}
///////////////////////////////////////////////////////////
// TRiga_documento
///////////////////////////////////////////////////////////
// Calcola il peso in Kg di una componente (carta, palstica, ecc.) dell'imballo della riga corrente
real TRiga_documento::calc_conai_qta(TCONAI_class type) const
real TRiga_documento::calc_conai_qta(TCONAI_class type, const int num_field) const
{
real kg;
if (is_merce() || is_omaggio())
{
const char* weight_name = conai_peso_name(type, LF_RIGHEDOC);
if (weight_name && *weight_name) // Se la categoria conai e' gestita
TString weight_name = conai_peso_name(type, LF_RIGHEDOC);
if (weight_name.full()) // Se la categoria conai e' gestita
{
const real peso = get_real(weight_name); // Peso unitario imballo
weight_name << "(%d)";
const real peso = get_real(weight_name.format(weight_name, num_field)); // Peso unitario imballo
real qta = quantita(); // Quantita' merce
if (peso > ZERO && !qta.is_zero()) // Verifica se ha un peso valido
{

View File

@ -21,6 +21,7 @@
#include "sconti.h"
#include "vepriv.h"
#include "veuml.h"
#include <set>
///////////////////////////////////////////////////////////
// TTipo_documento_cache
@ -1056,11 +1057,11 @@ void TDocumento::set_riga_esenzione()
if(multi_plaf)
{
d << " come dalle vostre dichiarazioni:\n";
TToken_string lePlafs(get("PLAFOND"), ',');
for(int i = 0; i < lePlafs.items(); i++)
TToken_string le_plafs(get("PLAFOND"), ',');
for(int i = 0; i < le_plafs.items(); i++)
{
static TToken_string thisPlaf; thisPlaf.cut(0) << lePlafs.get(i);
static TString key; key.cut(0) << thisPlaf.get(0) << "|" << thisPlaf.get(1);
static TToken_string this_plaf; this_plaf.cut(0) << le_plafs.get(i);
static TString key; key.cut(0) << this_plaf.get(0) << "|" << this_plaf.get(1);
TRectype plaf = cache().get(LF_LETINT, key);
d << "N. " << plaf.get(LETINT_VSPROT) << " del " << plaf.get(LETINT_VSDATA)
<< " da noi annotata al n. " << plaf.get(LETINT_NUMPROT) << " il " << plaf.get(LETINT_DATAREG) << "\n";
@ -2998,45 +2999,83 @@ void TDocumento::update_spese_aut(TString_array & spese_aut, bool preserve_old,
put(DOC_SPESEUPD, true);
}
// Calcola il peso in Kg degli imballaggi di una data categoria CONAI
real TDocumento::calc_conai_qta(TCONAI_class cc)
{
real qta;
if (conai_configured_class(cc))
{
FOR_EACH_PHYSICAL_RDOC(*this, i, r) if (r->is_merce() || r->is_omaggio())
{
const real rowqty = r->calc_conai_qta(cc);
qta += rowqty;
}
qta.round(5); // Arrotondamento al centigrammo
}
return qta;
}
void TDocumento::update_conai_qta()
{
_conaiqta.clear();
FOR_EACH_PHYSICAL_RDOC(*this, i, r) if (r->is_merce() || r->is_omaggio())
{
FOR_EACH_CONFIGURED_CONAI_CLASS(cc)
{
TString catconai = conai_sottocat_name(cc, LF_RIGHEDOC); catconai << "(%d)";
int row_conai = 1;
bool ok = true;
while(ok)
{
static TString current_cat; current_cat.cut(0);
current_cat.format(catconai, row_conai);
if (r->get(current_cat).full())
{
const real rowqty = r->calc_conai_qta(cc, row_conai);
if (rowqty.is_zero()) continue;
_conaiqta[r->get(current_cat)] += rowqty;
row_conai++;
}
else
ok = false;
}
}
}
}
const char* get_cf_esenz(const TString& tipo_conai)
{
if (tipo_conai == "AC")
return "ESACC";
if (tipo_conai == "AL")
return "ESALL";
if (tipo_conai == "CA")
return "ESCAR";
if (tipo_conai == "PL")
return "ESPLA";
if (tipo_conai == "LE")
return "ESLEG";
if (tipo_conai == "VE")
return "ESVET";
// Non dovrebbe mai succedere!
return nullptr;
}
bool has_new_conai(const TDocumento& doc)
{
FOR_EACH_PHYSICAL_RDOC(doc, r, rdoc)
{
if (rdoc->get(RDOC_TIPOCON).full())
return true;
}
return false;
}
/* La gestione CONAI adesso è diversa, non ci sarà più un codice spesa per categoria CONAI
* ma si potrà specificarne uno per sottocategoria che vincerà su quello di categoria.
*/
void TDocumento::update_conai()
{
if (main_app().has_module(DCAUT, CHK_DONGLE) && tipo().add_conai() && tipo().stati_iniziali_modifica().find(stato()) >= 0)
{
set<TString> conai_aggiornati;
const TRectype& cfven = clifor().vendite();
const bool cli_add_conai = cfven.get_bool("ADDCONAI");
const char * const __conai_cf_names[] = {"ESACC", "ESALL", "ESCAR", "ESPLA", "ESLEG", "ESVET"};
const TDate datadoc = get(DOC_DATADOC);
const TDate dataes = cfven.get(CFV_DATAECONAI);
bool esponi_esenti = false;
TString_array conai_sp(CONAI_CLASSES); // Codici spesa conai
{
const char* const conai_cod[CONAI_CLASSES] = { "CODACC", "CODALL", "CODCAR", "CODPLA", "CODLEG", "CODVET" };
TConfig c(CONFIG_DITTA, "ve");
for (int i = 0; i < CONAI_CLASSES; i++)
conai_sp.add(c.get(conai_cod[i]));
esponi_esenti = c.get_bool("ESPONIESENTI");
}
bool esponi_esenti = ini_get_bool(CONFIG_DITTA, "ve", "ESPONIESENTI");
// Come prima cosa mi calcolo le qta conai
update_conai_qta();
bool updated[CONAI_CLASSES] = {false,false,false,false,false,false};
for (int i = physical_rows(); i > 0; i--)
{
TRiga_documento& r = row(i);
@ -3045,15 +3084,21 @@ void TDocumento::update_conai()
// Elimina righe generate
if (tipo_conai)
{
// Controllo se il documento ha il metodo nuovo, in caso negativo skippo tutto
// Cancella le righe generate e poi ti ricalcolo tutto
if(!has_new_conai(*this))
{
return;
}
const TString& cod = r.get(RDOC_CODART);
const TCONAI_class pos = (TCONAI_class)conai_sp.find(cod);
if (pos >= CONAI_FIRST && pos <= CONAI_LAST)
const TString& sottocat = r.get(RDOC_TIPOCON);
if (_conai.find(sottocat))
{
if (cli_add_conai)
{
real perc_esenz = cfven.get_real(__conai_cf_names[pos]);
real qta = calc_conai_qta(pos);
real perc_esenz = cfven.get_real(get_cf_esenz(sottocat.left(2)));
real qta = _conaiqta[sottocat];
if (dataes.ok() && datadoc > dataes)
perc_esenz = ZERO;
const bool cli_esente = esponi_esenti && (perc_esenz >= CENTO);
@ -3069,8 +3114,8 @@ void TDocumento::update_conai()
destroy_row(i, true);
}
else
destroy_row(i, true);
updated[pos] = true;
destroy_row(i, true);
conai_aggiornati.insert(sottocat);
}
}
}
@ -3079,54 +3124,61 @@ void TDocumento::update_conai()
if (cli_add_conai)
{
const TString4 cod_iva_cli = codesiva();
TSpesa_prest sp;
FOR_EACH_CONFIGURED_CONAI_CLASS(ct) if (!updated[ct])
std::map<TString, TRiga_documento> righe_spesa;
for(auto cp = _conaiqta.begin(); cp != _conaiqta.end(); ++cp)
{
const real perc_esenz = cfven.get_real(__conai_cf_names[ct]);
const bool cli_esente = (esponi_esenti) && (perc_esenz >= CENTO);
const real qta_lorda = calc_conai_qta(ct);
real qta = qta_lorda;
if (!cli_esente && !qta_lorda.is_zero() && !perc_esenz.is_zero())
{
qta = qta_lorda * (CENTO - perc_esenz) / CENTO;
qta.round(5);
}
const TString cod_sottocat = cp->first;
// Se l'ho già fatto skippo
if (conai_aggiornati.find(cod_sottocat) != conai_aggiornati.end())
continue;
TSpesa_prest sp = _conai.get_spesa(cod_sottocat);
if (qta > ZERO)
{
const TString& s = conai_sp.row(ct);
if (sp.read(s) != NOERR)
message_box(FR("Il codice spesa CONAI %s specificato nei parametri ditta è assente: '%s'"),
conai_material(ct), (const char*)s);
else
{
const TString4 tipo = sp.tipo_riga();
TRiga_documento& riga = new_row(tipo);
riga.put(RDOC_CODART, s);
riga.generata();
riga.put(RDOC_GENTIPO, 'C');
riga.put(RDOC_DESCR, sp.descrizione());
riga.put(RDOC_QTA, qta);
const real cambio = get_real(DOC_CAMBIO);
const TString4 valuta = get(DOC_CODVAL);
real prezzo = cli_esente ? ZERO : sp.prezzo();
sppr_calc(sp, valuta, cambio, prezzo);
if (this->tipo().calcolo_lordo())
prezzo = riga.iva().lordo(prezzo, ALL_DECIMALS);
riga.put(RDOC_PREZZO, prezzo);
riga.put(RDOC_UMQTA, sp.um());
if (cod_iva_cli.empty())
riga.put(RDOC_CODIVA, sp.cod_iva());
else
riga.put(RDOC_CODIVA, cod_iva_cli);
}
// Aggiungo la spesa
const real perc_esenz = cfven.get_real(get_cf_esenz(cod_sottocat.left(2)));
const bool cli_esente = (esponi_esenti) && (perc_esenz >= CENTO);
const real qta_lorda = _conaiqta[cod_sottocat];
real qta = qta_lorda;
if (!cli_esente && !qta_lorda.is_zero() && !perc_esenz.is_zero())
{
qta = qta_lorda * (CENTO - perc_esenz) / CENTO;
qta.round(5);
}
}
if (qta > ZERO)
{
const TString4 tipo = sp.tipo_riga();
TRiga_documento& riga = new_row(tipo);
riga.put(RDOC_CODART, sp.codice());
riga.generata();
riga.put(RDOC_GENTIPO, 'C');
static TString descrizione;
descrizione.cut(0) << sp.descrizione() << " (" << cod_sottocat << ")";
riga.put(RDOC_DESCR, descrizione);
riga.put(RDOC_QTA, qta);
// Mi salvo anche la sottocategoria in questione
riga.put(RDOC_TIPOCON, cod_sottocat);
const real cambio = get_real(DOC_CAMBIO);
const TString4 valuta = get(DOC_CODVAL);
real prezzo = cli_esente ? ZERO : sp.prezzo();
sppr_calc(sp, valuta, cambio, prezzo);
if (this->tipo().calcolo_lordo())
prezzo = riga.iva().lordo(prezzo, ALL_DECIMALS);
riga.put(RDOC_PREZZO, prezzo);
riga.put(RDOC_UMQTA, sp.um());
if (cod_iva_cli.empty())
riga.put(RDOC_CODIVA, sp.cod_iva());
else
riga.put(RDOC_CODIVA, cod_iva_cli);
}
}
}
}
}