// Esercizi contabili e registri IVA #include #include #include #include #include #include #include #include #include #include #include #include #include "cglib01.h" /////////////////////////////////////////////////////////// // 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; } 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(); CHECK(_esercizi.items() > 0, "Non esistono esercizi contabili!"); } int TEsercizi_contabili::date2index(const TDate& d) const { check(); for (int 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 { check(); for (int 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 { /* Vecchio modo error-prone che non funziona nel primo anno di attivitā int es=last()-1; while (es>0 && !esercizio(es).chiusura_mag()) es--; es++; */ check(); for (int 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 { const int i = esc2index(codice); return esc(i); } 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; } /////////////////////////////////////////////////////////// // Registro /////////////////////////////////////////////////////////// TRegistro::TRegistro(const char* cod, int year) : _rec(LF_TAB), _att(LF_ATTIV) { read(cod, year); } bool TRegistro::read(const char* cod, int year) { if (year <= 0) { const TDate oggi(TODAY); year = oggi.year(); } if (cod == NULL) cod = ""; TString16 chiave; chiave.format("%04d%s", year, cod); _rec = cache().get("REG", chiave); read_att(); return !_rec.empty(); } bool TRegistro::reread() { if (ok()) { const TString16 n(name()); const int y = year(); return read(n, y); } return FALSE; } int TRegistro::year() const { TString16 anno(_rec.get("CODTAB")); anno.cut(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; } int TRegistro::tipo() const { const int t = _rec.get_int("I0"); return t; } bool TRegistro::corrispettivi() const { const bool c = _rec.get_bool("B0"); return c; } 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() { if (!_att.empty()) return TRUE; TString16 chiave; chiave << prefix().get_codditta() << '|' << attivita(); _att = cache().get(LF_ATTIV, chiave); // Ditta - Anno - Attivita' - Tipo Attivita' (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 attivita' } return !_att.empty(); } bool TRegistro::agenzia_viaggi() { bool av = FALSE; if (iva() == iva_vendite) av = _att.get_bool("REG74TER"); return av; } const TString& TRegistro::tipo_attivita() { return _att.get("TIPOATT"); } real* TRegistro::read_prorata(int anno) const { TString16 chiave; // Ditta - Anno - Attivita' - Tipo Attivita' (fissata a 1) chiave.format("%05ld", prefix().get_codditta()); chiave << anno << attivita() << "1"; TTable pla("%PLA"); pla.put("CODTAB", chiave); real* prorata = NULL; const int err = pla.read(); if (err == NOERR) prorata = new real(pla.get("R8")); return prorata; } real TRegistro::prorata(int annodoc) { const int annoiva = year(); // const int annopro = (annoiva < 1998 || annodoc < 1900) ? annoiva : annodoc; 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 == NULL) { pr = read_prorata(annopro); if (pr == NULL && annopro != annoiva) pr = read_prorata(annoiva); if (pr == NULL) pr = new real(ZERO); _prorata.add(chiave, pr, TRUE); } return *pr; } void TRegistro::set_prorata(int annodoc, const real& pro) { int annoiva = year(); int annopro = (annoiva < 1998 || annodoc <= 0) ? annoiva : annodoc; TString16 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(_rec); // Forza rilettura registro in cache } return updated; } /////////////////////////////////////////////////////////// // Libro giornale /////////////////////////////////////////////////////////// // Legge il libro giornale dell'anno specificato bool TLibro_giornale::read(int y) { bool found = FALSE; if (y <= 0) { const TDate oggi(TODAY); y = oggi.year(); } TString16 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); } bool TCodiceIVA::read(const char* cod) { if (cod && *cod) *this = cache().get("%IVA", cod); else zero(); return !empty(); } real TCodiceIVA::imposta(const real & imponibile, int ndec, const char * codval) const { const real percent = percentuale(); real iva = imponibile * percent / 100.0; switch (ndec) { case AUTO_DECIMALS: ndec = TExchange(codval).decimals(FALSE); break; case AUTO_PRICES_DECIMALS: ndec = TExchange(codval).decimals(TRUE); break; default: break; } if (ndec < 20) { if (ndec == 0) { if (imponibile > ZERO) iva.ceil(ndec); else iva.floor(ndec); } else iva.round(ndec); } return iva; } real TCodiceIVA::scorpora(real& lordo, int ndec, const char* codval) const { const real percent = percentuale(); real iva = (lordo * percent) / (percent + 100.0); real imponibile = lordo - iva; switch (ndec) { case AUTO_DECIMALS: ndec = TExchange(codval).decimals(FALSE); break; case AUTO_PRICES_DECIMALS: ndec = TExchange(codval).decimals(TRUE); break; default: break; } if (ndec < 20) // E' richiesto un arrotondamento significativo? { lordo.round(ndec); // Arrotondo importo lordo if (ndec == 0) // Probabile caso Lire: arrotondo per eccesso l'IVA { if (imponibile > ZERO) iva.ceil(ndec); else iva.floor(ndec); } else iva.round(ndec); // Probabile caso Euro: arrotondo matematicamente l'IVA imponibile.round(ndec); // Arrotondo imponibile real diff = lordo - imponibile - iva; diff.round(ndec); // Arrotondo la differenza (importantissimo per evitare valori del tipo 1E-18) if (!diff.is_zero()) { if (iva.sign() == diff.sign()) // Faccio crescere l'iva o l'imponibile ? iva += diff; else imponibile += diff; } } lordo = imponibile; // lordo č 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 handler_data_cambio(TMask_field& f, KEY k) { return TRUE; } /////////////////////////////////////////////////////////// // 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 = ' '; #ifdef DBG if (strchr(" CF", _tipo) == NULL) { error_box(FR("Tipo conto errato: '%c'"), _tipo); _tipo = ' '; } #endif _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, bool contro) const { CHECKD(n >= 0 && n <= 3, "Invalid bill field ", n); const char* f; if (contro) { switch(n) { case 0: f = RMV_GRUPPOC; break; case 1: f = RMV_CONTOC; break; case 2: f = RMV_SOTTOCONTOC; break; default:f = RMV_TIPOCC; break; } } else { switch(n) { case 0: f = RMV_GRUPPO; break; case 1: f = RMV_CONTO; break; case 2: f = RMV_SOTTOCONTO; break; default:f = RMV_TIPOC; break; } } return f; } void TBill::put(TRectype& r, bool c) const { r.put(field_name(0, c), gruppo()); r.put(field_name(1, c), conto()); r.put(field_name(2, c), sottoconto()); r.put(field_name(3, c), tipo()); } bool TBill::get(const TRectype& r, bool c) { set(r.get_int(field_name(0, c)), r.get_int(field_name(1, c)), r.get_long(field_name(2, c)), r.get_char(field_name(3, c))); set_description(NULL); _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 { m.set(g, gruppo()); m.set(c, conto()); m.set(s, sottoconto()); if (t) { char typ[2] = { tipo(), '\0' }; m.set(t, typ); } if (d) 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 = m.get_long(s); 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) { TLocalisamfile clifo(LF_CLIFO); clifo.setkey(1); clifo.put("TIPOCF", _tipo); clifo.put("CODCF", _sottoconto); ok = clifo.read() == NOERR; if (ok) { set_description(clifo.get("RAGSOC")); if (_tipo_cr < 0) { _tipo_cr = 0; _sezione = ' '; } _sospeso = clifo.get_bool("SOSPESO"); const char tipoa = clifo.get_char("TIPOPERS"); if (tipoa == 'F') // Se persona fisica allora aggiusta la ragione sociale { TString nome(descrizione().mid(30)); if (nome.not_empty()) { _descrizione->cut(30); _descrizione->trim(); nome.trim(); *_descrizione << ' ' << nome; } } if (_gruppo == 0 || _conto == 0) { _gruppo = clifo.get_int("GRUPPO"); _conto = clifo.get_int("CONTO"); } } } return ok; } bool TBill::read(TRectype &r) { bool ok = FALSE; if (tipo() <= ' ' || sottoconto() <= 0) { TString16 key; key.format("%d|%d|%ld", gruppo(), conto(), sottoconto()); 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 == NULL || _descrizione->blank()) && gruppo() != 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; } 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 99% (uses __tmp_string) const char* TBill::string(int mode) const { TString& s = get_tmp_string(80); 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::default_cdc(TString& cdc, TString& fas) const { bool ok = tipo() <= ' ' && sottoconto() > 0; if (ok) { TString16 key; key.format("%d|%d|%ld", gruppo(), conto(), sottoconto()); const TRectype& pcon = cache().get(LF_PCON, key); ok = !pcon.empty(); if (ok) { cdc = pcon.get(PCN_CODCMS); fas = pcon.get(PCN_FASCMS); } } return ok && cdc.not_empty(); }