#include "lilib01.h" #include "letint.h" #include #include "sqlset.h" #include #include #include #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 è 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("è stato superato di € ") << 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 è 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(); }