#include #include #include #include #include #include #include #include "velib04.h" #include "../ca/calib01.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "velib.h" #include "../cg/cg2103.h" #include "../cg/cglib02.h" #include "../cg/cgsaldac.h" #include "../in/inlib01.h" #include "../mg/anamag.h" #include "../ca/movana.h" #include "../m770/scperc.h" #include "../m770/rpag.h" #include "../m770/rver.h" #include "../m770/perc.h" #include #include void TMovimentoPN_VE::destroy_iva_row(int i) { if (i < 0) iva_rows().destroy_rows(); else iva_rows().destroy_row(i+1, true); } TImporto TMovimentoPN_VE::real2imp(const real& r, char row_type) { CHECK(_caus,"Orgggssbb..._caus pointer is NULL!"); bool dare = false; if (row_type == 'S') dare = _caus->sezione_ritsoc() == 'D'; else { if (row_type == 'F') dare = _caus->sezione_ritfis() == 'D'; else { dare = _caus->sezione_clifo() == 'D'; if (row_type != 'T' && row_type != 'F' && row_type != 'P') dare = !dare; } } TImporto importo(dare ? 'D' : 'A', r); return importo; } int TMovimentoPN_VE::bill2pos(const TBill& conto, char tipo) { const int items = cg_items(); for (int i = 0; i < items; i++) { TRectype& s = cg(i); const char t = s.get_char(RMV_ROWTYPE); if (t == tipo) { const int gr = s.get_int(RMV_GRUPPO); const int co = s.get_int(RMV_CONTO); const long so = s.get_long(RMV_SOTTOCONTO); const TBill c(gr,co,so); if (c == conto) return i; } } return -1; } int TMovimentoPN_VE::type2pos(char tipo) { const int items = cg_items(); for (int i = 0; i < items; i++) { TRectype& s = cg(i); const char t = s.get_char(RMV_ROWTYPE); if (t == tipo) return i; } return -1; } void TMovimentoPN_VE::set_cg_imp(int n, const TImporto& imp) { TRectype& rec = cg(n); rec.put(RMV_SEZIONE,imp.sezione()); rec.put(RMV_IMPORTO,imp.valore()); } TImporto TMovimentoPN_VE::get_cg_imp(int n) { const TRectype& rec = cg(n); const TImporto importo(rec.get_char(RMV_SEZIONE), rec.get_real(RMV_IMPORTO)); return importo; } bool TMovimentoPN_VE::add_cg_rec(int n, const TImporto& imp) { TImporto tot(get_cg_imp(n)); tot += imp; tot.normalize(); set_cg_imp(n, tot); return tot.is_zero(); } int TMovimentoPN_VE::set_cg_rec(int n, const TImporto& imp, const TBill& conto, const char* desc, char tipo) { const bool insert = n < 0; if (insert) n = cg_items(); // Questa e' la prima riga di contabilita' vuota e disponibile TRectype& rec = cg(n); if (insert) { TRectype& head = curr(); const int annoes = head.get_int(MOV_ANNOES); const long numreg = head.get_long(MOV_NUMREG); TDate datareg(head.get_date(MOV_DATAREG)); rec.put(RMV_ANNOES,annoes); rec.put(RMV_NUMREG,numreg); rec.put(RMV_DATAREG,datareg); } rec.put(RMV_SEZIONE,imp.sezione()); rec.put(RMV_IMPORTO,imp.valore()); conto.put(rec); rec.put(RMV_DESCR, desc); if (tipo != ' ') { if (tipo == 'T') // Calcolo contropartita { const TBill zio(iva(0)); zio.put(rec, true); } else { int pos = -1; if (tipo == 'F') { pos = type2pos('D'); if (pos == -1) pos = type2pos('N'); } else pos = type2pos('T'); if (pos >= 0) { const TBill zio(cg(pos)); zio.put(rec, true); } } } rec.put(RMV_ROWTYPE,tipo); return n; } int TMovimentoPN_VE::insert_cg_rec(int n, const TImporto& imp, TBill& conto, const char* desc, char tipo) { if (n >= 0 && n < cg_items()) { TRectype * row = new TRectype(LF_RMOV); TRectype& head = lfile().curr(); const int annoes = head.get_int(MOV_ANNOES); const long numreg = head.get_long(MOV_NUMREG); TDate datareg(head.get_date(MOV_DATAREG)); row->put(RMV_NUMREG,numreg); row->put(RMV_NUMRIG, n + 1); row->put(RMV_ANNOES,annoes); row->put(RMV_DATAREG,datareg); cg_rows().insert_row(row); } return set_cg_rec(n, imp, conto, desc, tipo); } void TMovimentoPN_VE::enter_row(int i, const TString & descr_cr) { CHECK(_caus,"Orgggssbb..._caus pointer is NULL!"); TRectype& cur = iva(i); real imponibile = cur.get_real(RMI_IMPONIBILE); real imposta = cur.get_real(RMI_IMPOSTA); const int anno = lfile().curr().get_date(MOV_DATAREG).year(); const TString4 tipodet = cur.get(RMI_TIPODET); const TString4 zanicchi(cur.get(RMI_CODIVA)); // Codice IVA if (imposta.is_zero() && _caus->corrispettivi()) // In caso di corrispettivi ... { const TCodiceIVA i(zanicchi); imposta = i.scorpora(imponibile); // ... scorpora imposta dall'imponibile } // Calcola riga causale col conto opportuno real imp, impind, iva, ivaind; int flag = analizza_riga_IVA(imponibile, imposta, *_caus, anno, zanicchi, tipodet, imp, iva, impind, ivaind); const TBill conto(cur); imponibile = imp + impind; if (conto.ok() && !imponibile.is_zero()) // Se c'e' imponibile ... { // crea una nuova riga contabile // Aggiorna conto sulla riga contabile const TImporto val(real2imp(imponibile, 'I')); const int newpos = bill2pos(conto, 'I'); // Riga in cui andra' l'imponibile if (newpos < 0) // conto non esistente: da inserire { const TString d(_caus->desc_agg(2)); set_cg_rec(-1, val, conto, d.empty() ? descr_cr : d, 'I'); } else add_cg_rec(newpos, val); cur.put(RMI_RIGAIMP, newpos+1); // Aggiorna riferimento alla riga contabile } // Aggiorna conto IVA sulla riga contabile if (!iva.is_zero()) // Se c'e' imposta ... { int newposiva = type2pos('D'); const TImporto val(real2imp(iva, 'I')); if (newposiva < 0) { int ri; TBill contoiva; const TRectype & head = lfile().curr(); if (head.get_bool(MOV_LIQDIFF)) _caus->bill(ri = RIGA_IVA_DIFFERITA, contoiva); if (!contoiva.ok()) _caus->bill(ri = RIGA_IVA_DETRAIBILE, contoiva); const TString80 d(_caus->desc_agg(ri)); if (contoiva.ok()) newposiva = set_cg_rec(-1, val, contoiva, d, 'D'); } else add_cg_rec(newposiva, val); } if (!ivaind.is_zero()) // Se c'e' imposta ... { int newposiva = type2pos('N'); const TImporto val(real2imp(ivaind, 'I')); if (newposiva < 0) { const TString80 d(_caus->desc_agg(RIGA_IVA_NON_DETRAIBILE)); TBill contoivaind; _caus->bill(RIGA_IVA_NON_DETRAIBILE, contoivaind); if (contoivaind.ok()) newposiva = set_cg_rec(-1, val, contoivaind, d, 'N'); } else add_cg_rec(newposiva, val); } } void TMovimentoPN_VE::add_row_re(int i) { TRectype& cur = iva(i); real imponibile = cur.get_real(RMI_IMPONIBILE); real imposta = cur.get_real(RMI_IMPOSTA); const int anno = lfile().curr().get_date(MOV_DATAREG).year(); const TString4 tipodet = cur.get(RMI_TIPODET); const TString4 zanicchi(cur.get(RMI_CODIVA)); // Codice IVA real imp, impind, iva, ivaind; analizza_riga_IVA(imponibile, imposta, *_caus, anno, zanicchi, tipodet, imp, iva, impind, ivaind); imponibile = imp + impind; if (!ivaind.is_zero()) { TBill contoivaind; _caus->bill(RIGA_IVA_NON_DETRAIBILE, contoivaind); const TImporto val(real2imp(ivaind, 'I')); int ivapos = bill2pos(contoivaind, 'I'); if (ivapos < 0) set_cg_rec(-1, val, contoivaind, "", 'I'); else add_cg_rec(ivapos, val); } const TBill conto(cur); int newpos = bill2pos(conto, ' '); // Riga in cui andra' l'imponibile if (conto.ok() && !imponibile.is_zero()) { const TImporto val(real2imp(imponibile, 'I')); if (newpos < 0) set_cg_rec(-1, val, conto, _caus->desc_agg(2), ' '); else add_cg_rec(newpos, val); } } void TMovimentoPN_VE::add_row_tot_re(TDocumento& doc) { TBill c; TImporto imp = real2imp(doc.imponibile(), 'T'); _caus->bill(1, c); if (c.tipo() > ' ') c.set(c.gruppo(), c.conto(), curr().get_long(MOV_CODCF), c.tipo()); imp.normalize(); insert_cg_rec(0, imp, c, _caus->desc_agg(1), ' '); } bool TMovimentoPN_VE::add_row_cp_re(int i) { TRectype& cur = cg(i); bool inserted_row = FALSE; TBill c; const int gr = cur.get_int(RMV_GRUPPO); const int co = cur.get_int(RMV_CONTO); const long so = cur.get_long(RMV_SOTTOCONTO); c.set(gr,co,so); TBill cp; map_conto_re(c); if (c.ok()) { int poscg = bill2pos(c, ' '); if (poscg < 0) { poscg = insert_cg_rec(0, real2imp(ZERO, 'P'), c, _caus->desc_agg(1), ' '); inserted_row = TRUE; } TImporto val(real2imp(cur.get_real(RMV_IMPORTO), 'P')); add_cg_rec(poscg, val); } return inserted_row; } void TMovimentoPN_VE::map_conto_re(TBill& c) { TString16 key; key.format("%3d%3d%6ld",c.gruppo(), c.conto(), c.sottoconto()); const TRectype* rs = &cache().get("&MRE", key); if (rs->empty()) { key.cut(6); rs = &cache().get("&MRE", key); if (rs->empty()) { key.cut(3); rs = &cache().get("&MRE", key); } } if (rs->empty()) _caus->bill(1, c); else { const int gr = rs->get_int("I0"); const int co = rs->get_int("I1"); const long so = rs->get_int("I2"); const char tipo = rs->get_char("S6"); c.set(gr, co, so, tipo); } if (c.tipo() > ' ') c.set(c.gruppo(), c.conto(), curr().get_long(MOV_CODCF), c.tipo()); } bool TMovimentoPN_VE::movement_ok() { TImporto tot_imp; TImporto imp; // Se siamo in valuta, forzera' la riga totale documento a cio' che si ottiene dalla somma // delle singole righe per evitare sbilanci nel movimento di 2,3,4,5 lire dovuti agli arrotondamenti const int max = cg_items(); for (int i = 0; i < max; i++) { if (i == 0 && _valuta) continue; TRectype& r = cg(i); const char sez = r.get_char(RMV_SEZIONE); const real val(r.get_real(RMV_IMPORTO)); imp.set(sez,val); tot_imp+=imp; } if (_valuta) //documento in valuta { TRectype& r = cg(0); // Setta la riga di totale documento... r.put(RMV_IMPORTO,tot_imp.valore()); r.put(RMV_SEZIONE,tot_imp.sezione() == 'D' ? 'A' : 'D'); // Sezione contraria // ...ed anche il totale documento sulla testata lfile().curr().put(MOV_TOTDOC,tot_imp.valore()); tot_imp.valore() = 0.0; if (_caus != NULL && _caus->intra()) { const TString& totdoc = curr().get(MOV_TOTDOC); curr().put(MOV_CORRLIRE, totdoc); } } else //documento senza valuta; nel campo CODVALI ci va il codice valuta della ditta bug368 { TString4 codval_ditta = TCurrency::get_firm_val(); curr().put(MOV_CODVALI, codval_ditta); } if (!tot_imp.is_zero()) return false; return true; } int TMovimentoPN_VE::recalc_cg_rows(const TString & descr_cr, TCausale & caus) { const int righe = iva_items(); const TRectype& head = curr(); set_caus(&caus); for (int i=0; iintra() && _caus->iva() == iva_acquisti) { TBill c; _caus->bill(RIGA_RITENUTE_FISCALI, c); ok = c.ok(); if (ok) { const TString80 d(_caus->desc_agg(RIGA_RITENUTE_FISCALI)); const char rowtype = 'F'; set_cg_rec(-1, real2imp(head.get_real(MOV_RITFIS), rowtype), c, d, rowtype); } else return 2; } else { real ritfis = head.get_real(MOV_RITFIS); if (ritfis != ZERO) { TBill c; _caus->bill(RIGA_RITENUTE_FISCALI, c); ok = c.ok(); if (ok) { const TString80 d(_caus->desc_agg(RIGA_RITENUTE_FISCALI)); const char rowtype = 'F'; set_cg_rec(-1, real2imp(ritfis, rowtype), c, d, rowtype); } else return 1; } real ritsoc = head.get_real(MOV_RITSOC); if (ritsoc != ZERO) { TBill c; _caus->bill(RIGA_RITENUTE_SOCIALI, c); ok = c.ok(); if (ok) { const TString80 d(_caus->desc_agg(RIGA_RITENUTE_SOCIALI)); const char rowtype = 'S'; set_cg_rec(-1, real2imp(ritsoc, rowtype), c, d, rowtype); } else return 1; } } if (_caus->tipomov() == 1) // Elimina eventuali righe vuote dalle fatture { for (int c = cg_items()-1; c >= 0; c--) { const TImporto imp = get_cg_imp(c); if (imp.is_zero()) destroy_cg_row(c); } } return ok && movement_ok() ? 0 : 1; } // Parametri da leggere all'inizio dell'elaborazione tramite load_parameters() static TBill _sco_perc_bill, _sco_imp_bill; // Conti per gli sconti a percentuale ed importi (dalla configurazione) static TBill _spin_billa, _spin_billv, _spbo_billa, _spbo_billv; static TBill _co_cliente, // conto clifo per movimento d'anticipo _co_controp; // conto di contropartita per il movimetno d'anticipo static bool _nump_cfg; // se true prende il numero rif. partita dal numero protocollo static bool _sc_enabled; // se true il saldaconto di ditta e' abilitato static bool _in_enabled; // se true l'intra e' abilitato static TToken_string* _search_seq = NULL; // Sequenza di ricerca del conto costo/ricavo la correttezza dell'ordinamento // va controllata nel programma di modifica parametri: // "" = fine ordinamento // CF = cliente fornitore // CA = causale // AR = articolo (costo/ricavo) // GM = gruppo merceologico // SM = sottogruppo merceologico // RF = raggruppamento fiscale // CV = categoria di vendita // CC = categoria contabile // Gli utlimi 6 fanno parte della ricerca per costi ricavi, in particolare AR,GM,SM e RF // non possono essere interrotti da CV o CC. Ad es. CA|CF|AR|CV|GM|CC|RF non e' valida come stringa // di ricerca. static TString16 _ivasto; // Codice IVA per storno articoli Omaggio static bool _contsclor; // Contabilizza sconti al netto o al lordo (sconti suddiviso per ogni contropartita) //static bool _loaded = false;// Flag per evitare di caricare i parametri più di una volta static TCausale *_caus = NULL; // causale del documento corrente static TMovimentoPN_VE *_movimento = NULL; // Movimento di prima nota documento vendita static TMovimentoPN *_anticipo = NULL; // Movimento di prima nota relativamente all'anticipo indicato sul documento class TIVA_array : public TAssoc_array { TCausale * _caus; // causale del documento corrente protected: void copy(const TIVA_array& a); TObject* dup() const { return new TIVA_array(*this); } public: error_type add(const TRiga_documento & r, const TBill& conto, const int ndec = ALL_DECIMALS, const real & p = 1.0); error_type add(const TRiga_documento * r, const TBill& conto, const int ndec = ALL_DECIMALS, const real & p = 1.0) { return add(*r, conto, ndec, p);} error_type add_omaggi(const TRiga_documento & r, const TBill& conto, const int ndec = ALL_DECIMALS, const real & p = 1.0); error_type add_omaggi(const TRiga_documento * r, const TBill& conto, const int ndec = ALL_DECIMALS, const real & p = 1.0) { return add_omaggi(*r, conto, ndec, p);} void set_caus(TCausale * caus) { _caus = caus; } TIVA_array() {} // @cmember Costruttore. Copia tutto l'array associativo e ne duplica gli elementi TIVA_array(const TIVA_array& a) { copy(a); } virtual ~TIVA_array() {} }; void TIVA_array::copy(const TIVA_array & a) { TAssoc_array::copy(a); _caus = a._caus; } error_type TIVA_array::add_omaggi(const TRiga_documento & r, const TBill& conto, const int ndec, const real & p) { if (_ivasto.empty()) return ivasto_error; add(r, conto, ndec, p); TRiga_documento r_storno(r); r_storno.set_tipo("01"); r_storno.put(RDOC_CODIVA, _ivasto); real prezzo = r_storno.get_real(RDOC_PREZZO); prezzo = -prezzo; r_storno.put(RDOC_PREZZO, prezzo); add(r_storno, conto, ndec, p); return no_error; } error_type TIVA_array::add(const TRiga_documento& r, const TBill& conto, const int ndec, const real& p) { const TTipo_riga_documento & t = r.tipo(); TString80 key; const TCodiceIVA& tiva = r.iva(); TString16 cod(tiva.codice()); TBill c(conto); int ord = 0; int detr = 0; real impon; const bool sconto_lordo = t.tipo() != RIGA_SCONTI && _contsclor && _sco_perc_bill.ok(); const int firmdec = TCurrency::get_firm_dec(); const TRectype * rdoc = r.find_original_rdoc(); if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty()) { TString80 key(rdoc->get(RDOC_CODNUM)); const TCodice_numerazione& num = cached_numerazione(key); if (num.fattura_emettere_ricevere()) { key.format("%3d%3d%6ld", c.gruppo(), c.conto(), c.sottoconto()); const TRectype* rs = &cache().get("&MRE", key); if (rs->empty()) { key.cut(6); rs = &cache().get("&MRE", key); if (rs->empty()) { key.cut(3); rs = &cache().get("&MRE", key); } } if (rs->empty()) { key = rdoc->get(RDOC_PROVV); key << '|' << rdoc->get(RDOC_ANNO); key << '|' << rdoc->get(RDOC_CODNUM); key << '|' << rdoc->get(RDOC_NDOC); const TRectype & doc = cache().get(LF_DOC, key); const TTipo_documento& td = cached_tipodoc(doc.get(DOC_TIPODOC)); const TString& codcau = td.causale(); const TCausale caus(codcau); caus.bill(1, c); } else { const int gr = rs->get_int("I0"); const int co = rs->get_int("I1"); const long so = rs->get_int("I2"); const char tipo = rs->get_char("S6"); c.set(gr, co, so, tipo); } if (c.tipo() > ' ') c.set(c.gruppo(), c.conto(), r.doc().get_long(DOC_CODCF), c.tipo()); } } if (!sconto_lordo) // Al netto dello sconto impon = r.imponibile(); else impon = r.importo(false,false,ndec); // Imponibile della riga al lordo dello sconto switch (t.tipo()) { case RIGA_MERCE: ord = 1; break; case RIGA_OMAGGI: impon = r.imponibile_omaggio(); ord = 2; break; case RIGA_SPESEDOC: ord = 3; break; case RIGA_PRESTAZIONI: ord = 4; break; case RIGA_SCONTI: ord = 5; break; case RIGA_DESCRIZIONI: default: return no_error; break; } impon *= p; impon.round(firmdec); // was ndec if (impon.is_zero()) return no_error; real imposta = tiva.imposta(impon, ndec); // Le righe di sconto ad importo o percentuale vanno saltate // Casistica sulle righe omaggio: // quelle che non hanno addebito IVA devono venire scartate, quelle che hanno // addebito IVA vengono aggiunte normalmente ed in piu' viene aggiunta // una riga IVA con lo stesso imponibile ma di segno opposto, con un cod. IVA // speciale per lo storno, proveniente da configurazione const TString4 tipodet(r.get(RDOC_TIPODET)); key.format("%d|%-4s|%c|%3d|%3d|%6ld|%s", ord,(const char*)cod,c.tipo(),c.gruppo(),c.conto(),c.sottoconto(), (const char *) tipodet); TRectype * iva = (TRectype *) objptr(key); if (iva == NULL) { iva = new TRectype(LF_RMOVIVA); iva->put(RMI_CODIVA,cod); iva->put(RMI_TIPOCR,c.tipo_cr()); iva->put(RMI_INTRA, _caus->intra()); iva->put(RMI_TIPOC, c.tipo()); iva->put(RMI_GRUPPO, c.gruppo()); iva->put(RMI_CONTO, c.conto()); iva->put(RMI_SOTTOCONTO, c.sottoconto()); TAssoc_array::add(key, iva, true); } real val = iva->get_real(RMI_IMPONIBILE); val += impon; iva->put(RMI_IMPONIBILE, val); iva->put(RMI_TIPODET, tipodet); val = iva->get_real(RMI_IMPOSTA); val += imposta; iva->put(RMI_IMPOSTA, val); if (ord != 5) { if (sconto_lordo) // Se e' settato il flag di contabilizzare anche gli sconti merce { const real sconto = -r.sconto(); // Imponibile dello sconto (positivo, quindi si cambia di segno) if (!sconto.is_zero()) // Le righe Omaggio con Addebito IVA hanno comunque sconto ZERO! { TRiga_documento r_sconto(r); r_sconto.put(RDOC_QTA, UNO); r_sconto.put(RDOC_PREZZO, sconto); add(r_sconto, _sco_perc_bill, ndec, p); } } } return no_error; } TContabilizzazione::TContabilizzazione(const char* cod) : TElaborazione(cod), _auto_data(false) { _fcaus = new TLocalisamfile(LF_CAUSALI); _frcaus = new TLocalisamfile(LF_RCAUSALI);// Per far andare TCausale _attiv = new TLocalisamfile(LF_ATTIV); // Altrimenti TRegistro non va! _part = new TLocalisamfile(LF_PARTITE); _scad = new TLocalisamfile(LF_SCADENZE); _pags = new TLocalisamfile(LF_PAGSCA); // Per far funzionare TPartita _intra = new TLocalisamfile(LF_INTRA); _rintra = new TLocalisamfile(LF_RINTRA); _occas = new TLocalisamfile(LF_OCCAS); _docfile = new TLocalisamfile(LF_DOC); _rdocfile = new TLocalisamfile(LF_RIGHEDOC); // Per far funzionare TDocumento,TPartita ecc.. _anamag = new TLocalisamfile(LF_ANAMAG); _saldi = new TLocalisamfile(LF_SALDI); _cpg = new TTable("%CPG"); _val = new TTable("%VAL"); _prs = new TTable("PRS"); _spp = new TTable("SPP"); _caa = new TTable("CAA"); _cra = new TTable("CRA"); _gmc = new TTable("GMC"); _rfa = new TTable("RFA"); _cve = new TTable("CVE"); _cco = new TTable("CCO"); _clifo = new TRelation(LF_CLIFO); _clifo->add(LF_CFVEN,"TIPOCF=TIPOCF|CODCF=CODCF"); _righe_iva = new TIVA_array; _nump_iva = get_bool("B4"); _can_write = true; _error = no_error; _nrow = 0; _total_docs = 0L; _caus = NULL; } TContabilizzazione::TContabilizzazione(const TRectype& rec) : TElaborazione(rec), _auto_data(false), _viswin(NULL) { _fcaus = new TLocalisamfile(LF_CAUSALI); _frcaus = new TLocalisamfile(LF_RCAUSALI);// Per far andare TCausale _attiv = new TLocalisamfile(LF_ATTIV); // Altrimenti TRegistro non va! _part = new TLocalisamfile(LF_PARTITE); _scad = new TLocalisamfile(LF_SCADENZE); _pags = new TLocalisamfile(LF_PAGSCA); // Per far funzionare TPartita _intra = new TLocalisamfile(LF_INTRA); _rintra = new TLocalisamfile(LF_RINTRA); _occas = new TLocalisamfile(LF_OCCAS); _docfile = new TLocalisamfile(LF_DOC); _rdocfile = new TLocalisamfile(LF_RIGHEDOC); // Per far funzionare TDocumento,TPartita ecc.. _anamag = new TLocalisamfile(LF_ANAMAG); _saldi = new TLocalisamfile(LF_SALDI); _cpg = new TTable("%CPG"); _val = new TTable("%VAL"); _prs = new TTable("PRS"); _spp = new TTable("SPP"); _caa = new TTable("CAA"); _cra = new TTable("CRA"); _gmc = new TTable("GMC"); _rfa = new TTable("RFA"); _cve = new TTable("CVE"); _cco = new TTable("CCO"); _clifo = new TRelation(LF_CLIFO); _clifo->add(LF_CFVEN,"TIPOCF=TIPOCF|CODCF=CODCF"); _righe_iva = new TIVA_array; _nump_iva = get_bool("B4"); _can_write = true; _error = no_error; _nrow = 0; _total_docs = 0L; _caus = NULL; } TContabilizzazione::~TContabilizzazione() { delete _clifo; delete _cpg; delete _val; delete _gmc; delete _rfa; delete _cve; delete _cco; delete _prs; delete _spp; delete _caa; delete _cra; delete _anamag; delete _saldi; delete _fcaus; delete _frcaus; delete _attiv; delete _part; delete _scad; delete _pags; delete _intra; delete _rintra; delete _occas; delete _docfile; delete _rdocfile; delete _righe_iva; } bool TContabilizzazione::load_parameters() { // if (_loaded) // return true; TConfig conf(CONFIG_DITTA, "ve"); _search_seq = new TToken_string(conf.get("RICERCACR")); // costruisce la stringa che controlla la ricerca del conto costo/ricavo // Attenzione! non esegue alcun controllo di consistenza sulla corretta sequenza // presuppone che il programma di configurazione abbia generato correttamente // il tutto. if (_search_seq->empty_items()) { error_box("Non e' abilitata alcuna ricerca per il conto di costo/ricavo in configurazione."); return false; } _sc_enabled = conf.get_bool("GesSal","cg"); _in_enabled = dongle().active(INAUT); _nump_cfg = conf.get_bool("RifPro","cg"); int gr,co; long so; gr = conf.get_int("SCOPRCODCON","ve",1); co = conf.get_int("SCOPRCODCON","ve",2); so = conf.get_long("SCOPRCODCON","ve",3); _sco_perc_bill.set(gr,co,so); gr = conf.get_int("SCOIMCODCON","ve",1); co = conf.get_int("SCOIMCODCON","ve",2); so = conf.get_long("SCOIMCODCON","ve",3); _sco_imp_bill.set(gr,co,so); _contsclor = conf.get_bool("CONTSCLOR","ve"); _ivasto = conf.get("IVASTO","ve"); gr = conf.get_int("SPINCODCONA","ve",1); co = conf.get_int("SPINCODCONA","ve",2); so = conf.get_long("SPINCODCONA","ve",3); _spin_billa.set(gr,co,so); gr = conf.get_int("SPINCODCONV","ve",1); co = conf.get_int("SPINCODCONV","ve",2); so = conf.get_long("SPINCODCONV","ve",3); _spin_billv.set(gr,co,so); gr = conf.get_int("SPBOCODCONA","ve",1); co = conf.get_int("SPBOCODCONA","ve",2); so = conf.get_long("SPBOCODCONA","ve",3); _spbo_billa.set(gr,co,so); gr = conf.get_int("SPBOCODCONV","ve",1); co = conf.get_int("SPBOCODCONV","ve",2); so = conf.get_long("SPBOCODCONV","ve",3); _spbo_billv.set(gr,co,so); _spin_cod = conf.get("SPINCODIVA","ve"); _spbo_cod = conf.get("SPBOCODIVA","ve"); _check_prev_cont = conf.get_bool("CHECKPREVCONT","ve"); _fld_cms_cont = conf.get("CMSCNTFIELD","ve"); return true; } bool TContabilizzazione::test_swap() { const char sez = _caus->sezione_clifo(); TipoIVA t = _caus->reg().iva(); if (t == nessuna_iva) { TBill c; _caus->bill(1, c); char tipocf = c.tipo(); if (tipocf == 'C') t = iva_vendite; else { if (tipocf == 'F') t = iva_acquisti; else { if (_caus->tipo_doc() == "FA") t = iva_acquisti; else t = iva_vendite; } } } const bool s = (t == iva_vendite) ^ (sez == 'D'); return s; } error_type TContabilizzazione::get_next_reg_num(long& nr) { // reperisce l'ultimo numero di registrazione disponibile _error = no_error; TLocalisamfile& mov = _movimento->lfile(); nr = 1L; if (mov.last() == NOERR) { nr += mov.get_long(MOV_NUMREG); if (nr <= 0) // Quando mai succede? _error = nr_reg_error; } return _error; } long TContabilizzazione::doc_contabilized(const TDocumento& doc, bool anticipo) const { long nreg = doc.get_long(anticipo ? DOC_NUMANT : DOC_NUMREG); if (nreg > 0) { // NON usare la cache qui!!!!!!!!!!!!!!!!!!!!!! TLocalisamfile mov(LF_MOV); mov.put(MOV_NUMREG, nreg); if (mov.read() == NOERR) // Il movimento esiste! { // Controlla che il movimento abbia ancora il riferimento esatto al documento const char* const key[4] = { DOC_PROVV, DOC_ANNO, DOC_CODNUM, DOC_NDOC }; TString8 dkey, dval; for (int k = 0; k < 4; k++) { dkey = "D"; dkey << key[k]; dval = mov.get(dkey); if (dval != doc.get(key[k])) { nreg = 0; // La chiave non corrisponde più: forse l'hanno cancellato e reinserito break; } } } else nreg = 0; // Il movimento non esiste più: l'hanno cancellato! } return nreg; } TCausale * TContabilizzazione::get_caus(const TDocumento& doc, const int year) { TString16 codcaus; TToken_string key; if (!_fld_cms_cont.blank()) { const TString & cms = doc.commessa_principale(); if (!cms.blank()) { key.add(cms); const TString16 fld_val = cache().get(LF_COMMESSE, key, _fld_cms_cont); if (!fld_val.blank()) { key = "CTCMS"; key.add(doc.tipo().codice()); key.add(fld_val); codcaus = cache().get(LF_MULTIREL, key, "DATA"); } } } if (codcaus.blank()) { key = doc.get(DOC_TIPOCF); key.add(doc.get(DOC_CODCF)); const TRectype& cfven = cache().get(LF_CFVEN, key); codcaus = cfven.get(doc.is_nota_credito() ? CFV_CODCAUSNC : CFV_CODCAUS); if (codcaus.blank()) codcaus = doc.tipo().causale(); // Istanzia la causale del documento corrente... } return codcaus.blank() ? NULL : new TCausale(codcaus, year); } error_type TContabilizzazione::compile_head_mov(TDocumento& doc) // Compila la testata { TRectype& mov_rec = _movimento->curr(); const bool acquisto = doc.get_char(DOC_TIPOCF) == 'F'; // Reperisce la data documento const TDate datadoc(doc.data()); if (!datadoc.ok()) { _error = datadoc_error; return _error; } // reperisce la data di registrazione, che e' anche la data di competenza ed // eventualmente la data74ter se nel registro della causale vi e' scritta l'informazione // sulle agenzie di viaggio. // se si e' specificata la data automatica prende invece la data del documento const TDate data_reg(_auto_data ? datadoc : _data_reg); // reperisce il codice anno esercizio, const int cod_es = esercizi().date2esc(data_reg); if (cod_es <= 0) { _error = nr_es_error; return _error; } // reperisce l'ultimo numero di registrazione disponibile long numreg = doc_contabilized(doc, false); const bool recontabilizing = numreg > 0; if (recontabilizing) { const TRectype& mov = cache().get(LF_MOV, numreg); TString msg; msg.format("*** Il movimento %ld è già stato ", numreg); if (mov.get_bool(MOV_REGST)) { msg << "stampato su bollato"; _viswin->add_line(msg); } if (mov.get_bool(MOV_STAMPATO)) { msg << "stampato sul giornale"; _viswin->add_line(msg); } if (mov.get_bool(MOV_INVIATO)) { msg << "inviato ad altra contabilità"; _viswin->add_line(msg); } msg.format("--- Il documento verrà ricontabilizzato nel movimento %ld", numreg); _viswin->add_line(msg); } else { _error = get_next_reg_num(numreg); if (_error != no_error) return _error; } const TCodice_numerazione cod_num(doc.numerazione()); // calcola il numero documento aggiungendo l'eventuale prefisso/postfisso. TString numdoc; cod_num.complete_num(doc.numero(), numdoc); if (acquisto) { const TString& numdocrif = doc.get(DOC_NUMDOCRIF); if (numdocrif.not_empty()) numdoc = numdocrif; } if (numdoc.empty() || !cod_num.ok()) { _error = nr_doc_error; return _error; } numdoc.upper(); // Il numero documento e' uppercase! // Istanzia la causale del documento corrente... const TTipo_documento& tipo = doc.tipo(); TString16 codcaus = tipo.causale(); TToken_string key; key.add(doc.get(DOC_TIPOCF)); key.add(doc.get(DOC_CODCF)); const TRectype& cfven = cache().get(LF_CFVEN, key); const TString& caus_cli = cfven.get(doc.is_nota_credito() ? CFV_CODCAUSNC : CFV_CODCAUS); if (caus_cli.not_empty()) codcaus = caus_cli; // La causale del cliente prevale su quella del tipo documento _caus = get_caus(doc, data_reg.year()); _righe_iva->set_caus(_caus); if (_caus == NULL || !_caus->ok()) { _error = caus_error; return _error; } _righe_iva->set_caus(_caus); if (doc.in_valuta() && !_caus->valuta()) { _error = cauval_error; return _error; } // per reperire il tipo documento ed il tipo movimento // reperisce la descrizione dal tipo documento e la completa con la data documento ed il // numero documento const bool short_rif = pack_rif(); TString descr; if (!short_rif) { doc.riferimento(descr); if (descr.empty()) descr = tipo.descrizione(); if (descr.full()) descr << ' '; } const TString16 rif = doc.get(DOC_NUMDOCRIF); const bool use_rif = _caus->iva() == iva_acquisti && rif.not_empty(); if (use_rif) { descr << "n. " << rif; const TString & data_rif = doc.get_date(DOC_DATADOCRIF).string(short_rif ? brief : full); descr << " del " << data_rif; } else { descr << "n. " << doc.numero(); descr << " del " << datadoc.string(short_rif ? brief : full); } if (doc.in_valuta()) { descr << " " << doc.get(DOC_CODVAL); descr << " " << doc.totale_doc().stringa(); } // Codice registro IVA TRegistro& registro = _caus->reg(); const bool iva_mov = registro.ok(); long ult_prot = 0; if (iva_mov) { if (recontabilizing) { const TRectype& mov = cache().get(LF_MOV, numreg); ult_prot = mov.get_long(MOV_PROTIVA); } else { if (_nump_iva == 1) // Reperisce l'ultimo numero di protocollo dal registro IVA { ult_prot = registro.protocol() + 1; if (ult_prot <= 0) { _error = ultprot_error; return _error; } } else // oppure dal numero di documento ult_prot = doc.numero(); } } // Reperisce la valuta TDate datacam(doc.get_date(DOC_DATACAMBIO)); real cambio(doc.cambio()); TString4 codval(doc.valuta()); codval.trim(); if (!doc.in_valuta()) { codval = ""; cambio = ZERO; } if (codval.not_empty()) { _val->put("CODTAB",codval); if (_val->read() != NOERR) { _error = val_error; return _error; } } // Reperisce il cambio if ((cambio != ZERO && codval.empty()) || cambio == ZERO && codval.not_empty()) { _error = change_error; return _error; } // Dati del cliente... TString4 tipocf(doc.get(DOC_TIPOCF)); long codcf = doc.get_long(DOC_CODCF); TString80 occas; { TLocalisamfile& cli_file = _clifo->lfile(); cli_file.put(CLI_TIPOCF,tipocf); cli_file.put(CLI_CODCF,codcf); if (_clifo->read(_isequal) == NOERR) // posiziona il cliente una volta per tutte { if (cli_file.get_bool(CLI_OCCAS)) { occas = doc.get(DOC_OCFPI); TLocalisamfile ocf(LF_OCCAS); ocf.put(OCC_CFPI,occas); if (ocf.read() != NOERR) { _error = clifo_error; return _error; } } } else { if (!doc.tipo().clifo_optional()) { _error = clifo_error; return _error; } } } // Codice pagamento const TString4 codpag(doc.get(DOC_CODPAG)); if (sc_enabled(data_reg) || codpag.not_empty()) // La condizione di pagamento va controllata { // se e' abilitato il saldaconto o se e' stata inserita _cpg->put("CODTAB",codpag); if (_cpg->read() != NOERR) { _error = codpag_error; return _error; } } // Mo' riempie il record della incornata (testata) mov_rec.zero(); mov_rec.put(MOV_ANNOES,cod_es); mov_rec.put(MOV_NUMREG,numreg); mov_rec.put(MOV_DATAREG,data_reg); mov_rec.put(MOV_DATACOMP,data_reg); if (use_rif) { mov_rec.put(MOV_NUMDOC, rif); const TString& data_rif = doc.get(DOC_DATADOCRIF); mov_rec.put(MOV_DATADOC, data_rif); } else { mov_rec.put(MOV_DATADOC,datadoc); mov_rec.put(MOV_NUMDOC,numdoc); } mov_rec.put(MOV_TIPODOC,_caus->tipo_doc()); mov_rec.put(MOV_CODCAUS,_caus->codice()); mov_rec.put(MOV_DESCR, descr); mov_rec.put(MOV_TIPOMOV,char(_caus->tipomov()+'0')); mov_rec.put(MOV_ANNOIVA,data_reg.year()); mov_rec.put(MOV_CODVAL,codval); mov_rec.put(MOV_CAMBIO,cambio); mov_rec.put(MOV_DATACAM,datacam); mov_rec.put(MOV_CODPAG,codpag); TCurrency_documento totdocval(doc.totale_doc(), doc); if (iva_mov) { if (registro.agenzia_viaggi()) mov_rec.put(MOV_DATA74TER,data_reg); mov_rec.put(MOV_REG, registro.name()); mov_rec.put(MOV_PROTIVA,ult_prot); mov_rec.put(MOV_TIPO,tipocf); mov_rec.put(MOV_CODCF,codcf); mov_rec.put(MOV_OCFPI,occas); TString4 codvali; real cambioi; if (_caus->iva() == iva_acquisti) { const TString& tdoc_cont = doc.tipo().totale_doc_cont(); if (tdoc_cont.not_empty()) totdocval.set_num(doc.get_real(tdoc_cont)); if (_caus->intra()) { TCurrency_documento imposta(doc.imposta(), doc); totdocval -= imposta; imposta.change_to_firm_val(); mov_rec.put(MOV_RITFIS, imposta.get_num()); codvali = _clifo->curr().get("VALINTRA"); cambioi = cambio; if (codvali.not_empty() && codvali != codval) { mov_rec.put(MOV_CODVALI,codvali); TExchange c(codvali); cambioi = c.get_base_change(); mov_rec.put(MOV_CAMBIOI, cambioi); } else { codvali = codval; cambioi = cambio; if (_caus->valintra() && codvali.empty()) { codvali = TCurrency::get_firm_val(); if (codvali.empty()) codvali = TCurrency::get_euro_val(); cambioi = UNO; } mov_rec.put(MOV_CODVALI,codval); mov_rec.put(MOV_CAMBIOI,cambioi); codvali = codval; } TCurrency corrval(totdocval); TCurrency corrlire(corrval); corrval.change_value(codvali, cambioi); corrlire.change_to_firm_val(); mov_rec.put(MOV_CORRLIRE,corrlire.get_num()); if (_caus->valintra()) mov_rec.put(MOV_CORRVALUTA,corrval.get_num()); TDate dataintra = data_reg; if (doc.tipo().nota_credito()) { TDate d = doc.get_date(DOC_DATADOCRIF); if (d.ok()) dataintra = d; } mov_rec.put(MOV_DATACOMPI, dataintra); } } else { if (_caus->intra()) { TCurrency corrval(totdocval); TCurrency corrlire(corrval); codvali = codval; cambioi = cambio; if (_caus->valintra() && codvali.empty()) { codvali = TCurrency::get_firm_val(); if (codvali.empty()) codvali = TCurrency::get_euro_val(); cambioi = 1.00; } mov_rec.put(MOV_CODVALI,codvali); mov_rec.put(MOV_CAMBIOI,cambioi); corrlire.change_to_firm_val(); mov_rec.put(MOV_CORRLIRE,corrlire.get_num()); if (_caus->valintra()) mov_rec.put(MOV_CORRVALUTA,corrval.get_num()); TDate dataintra = data_reg; if (doc.tipo().nota_credito()) { TDate d = doc.get_date(DOC_DATADOCRIF); if (d.ok()) dataintra = d; } mov_rec.put(MOV_DATACOMPI, dataintra); } } } if (doc.in_valuta()) { TCurrency totdoclit(totdocval); totdoclit.change_to_firm_val(); mov_rec.put(MOV_TOTDOC,totdoclit.get_num()); mov_rec.put(MOV_TOTDOCVAL,totdocval.get_num()); } else mov_rec.put(MOV_TOTDOC,totdocval.get_num()); // Memorizza il movimento contabile di destinazione! doc.put(DOC_NUMREG, numreg); // Scrive sulla testata del movimento il numero di documento originale mov_rec.put(MOV_DPROVV, doc.get(DOC_PROVV)); mov_rec.put(MOV_DANNO, doc.get(DOC_ANNO)); mov_rec.put(MOV_DCODNUM, doc.get(DOC_CODNUM)); mov_rec.put(MOV_DNDOC, doc.get(DOC_NDOC)); mov_rec.put(MOV_LIQDIFF, doc.get(DOC_LIQDIFF)); return _error; } error_type TContabilizzazione::compile_head_mov_re(TDocumento& doc) // Compila la testata { TRectype& mov_rec = _movimento->curr(); const bool acquisto = doc.get_char(DOC_TIPOCF) == 'F'; // Reperisce la data documento const TDate datadoc(doc.data()); if (!datadoc.ok()) { _error = datadoc_error; return _error; } // reperisce la data di registrazione, che e' anche la data di competenza ed // eventualmente la data74ter se nel registro della causale vi e' scritta l'informazione // sulle agenzie di viaggio. // se si e' specificata la data automatica prende invece la data del documento const TDate data_reg(_auto_data ? datadoc : _data_reg); // reperisce il codice anno esercizio, const int cod_es = esercizi().date2esc(data_reg); if (cod_es <= 0) { _error = nr_es_error; return _error; } // reperisce l'ultimo numero di registrazione disponibile long numreg = doc_contabilized(doc, false); const bool recontabilizing = numreg > 0; if (recontabilizing) { const TRectype& mov = cache().get(LF_MOV, numreg); TString msg; msg.format("*** Il movimento %ld è già stato ", numreg); if (mov.get_bool(MOV_REGST)) { msg << "stampato su bollato"; _viswin->add_line(msg); return no_error; } if (mov.get_bool(MOV_STAMPATO)) { msg << "stampato sul giornale"; _viswin->add_line(msg); return no_error; } if (mov.get_bool(MOV_INVIATO)) { msg << "inviato ad altra contabilità"; _viswin->add_line(msg); return no_error; } msg.format("--- Il documento verrà ricontabilizzato nel movimento contabile %ld", numreg); _viswin->add_line(msg); } else { _error = get_next_reg_num(numreg); if (_error != no_error) return _error; } const TCodice_numerazione cod_num(doc.numerazione()); // calcola il numero documento aggiungendo l'eventuale prefisso/postfisso. TString numdoc; cod_num.complete_num(doc.numero(), numdoc); if (acquisto) { TString16 numdocrif(doc.get(DOC_NUMDOCRIF)); if (numdocrif.not_empty()) numdoc = numdocrif; } if (numdoc.empty() || !cod_num.ok()) { _error = nr_doc_error; return _error; } numdoc.upper(); // Il numero documento e' uppercase! // Istanzia la causale del documento corrente... _caus = get_caus(doc, data_reg.year()); if (_caus == NULL || !_caus->ok() || _caus->iva() != nessuna_iva) { _error = causre_error; return _error; } _righe_iva->set_caus(_caus); _movimento->set_caus(_caus); // per reperire il tipo documento ed il tipo movimento // reperisce la descrizione dal tipo documento e la completa con la data documento ed il // numero documento const bool short_rif = pack_rif(); TString descr; if (!short_rif) { doc.riferimento(descr); if (descr.empty()) descr = doc.tipo().descrizione(); if (descr.full()) descr << ' '; } const TString16 rif = doc.get(DOC_NUMDOCRIF); const bool use_rif = _caus->iva() == iva_acquisti && rif.not_empty(); if (use_rif) { descr << "n. " << rif; const TString & data_rif = doc.get_date(DOC_DATADOCRIF).string(short_rif ? brief : full); descr << " del " << data_rif; } else { descr << "n. " << doc.numero(); descr << " del " << datadoc.string(short_rif ? brief : full); } // Dati del cliente... const TString4 tipocf(doc.get(DOC_TIPOCF)); const long codcf = doc.get_long(DOC_CODCF); TString80 occas; { TLocalisamfile& cli_file = _clifo->lfile(); cli_file.put(CLI_TIPOCF,tipocf); cli_file.put(CLI_CODCF,codcf); if (_clifo->read(_isequal) == NOERR) // posiziona il cliente una volta per tutte { if (cli_file.get_bool(CLI_OCCAS)) { occas = doc.get(DOC_OCFPI); TLocalisamfile ocf(LF_OCCAS); ocf.put(OCC_CFPI,occas); if (ocf.read() != NOERR) { _error = clifo_error; return _error; } } } else { if (!doc.tipo().clifo_optional()) { _error = clifo_error; return _error; } } } // Mo' riempie il record della incornata (testata) mov_rec.zero(); mov_rec.put(MOV_ANNOES,cod_es); mov_rec.put(MOV_NUMREG,numreg); mov_rec.put(MOV_DATAREG,data_reg); mov_rec.put(MOV_DATACOMP,data_reg); if (use_rif) { mov_rec.put(MOV_NUMDOC, rif); const TString & data_rif = doc.get(DOC_DATADOCRIF); mov_rec.put(MOV_DATADOC,data_rif); } else { mov_rec.put(MOV_DATADOC,datadoc); mov_rec.put(MOV_NUMDOC,numdoc); } mov_rec.put(MOV_CODCAUS,_caus->codice()); mov_rec.put(MOV_TIPODOC,_caus->tipo_doc()); mov_rec.put(MOV_DESCR,descr); mov_rec.put(MOV_CODCF,codcf); // Memorizza il movimento contabile di destinazione! doc.put(DOC_NUMREG, numreg); // Scrive sulla testata del movimento il numero di documento originale mov_rec.put(MOV_DPROVV, doc.get(DOC_PROVV)); mov_rec.put(MOV_DANNO, doc.get(DOC_ANNO)); mov_rec.put(MOV_DCODNUM, doc.get(DOC_CODNUM)); mov_rec.put(MOV_DNDOC, doc.get(DOC_NDOC)); mov_rec.put(MOV_LIQDIFF, doc.get(DOC_LIQDIFF)); return _error; } error_type TContabilizzazione::search_costo_ricavo(TBill& conto, const TRiga_documento& r, real & amount_to_split, const real & valore) { const int items = _search_seq->items(); TLocalisamfile & cli_file = _clifo->lfile(); // YES, arriva qui dentro quando la relazione e' gia' posizionata const bool is_cli = cli_file.get(CLI_TIPOCF) == "C"; bool skip_art_related = false; bool skip_clifo = _clifo->bad(); TCodiceIVA codiva(r.get(RDOC_CODIVA)); const char t = r.tipo().tipo(); switch (t) { case RIGA_OMAGGI: // righe omaggio come articoli spiaccicato identico (avranno imponibile 0) case RIGA_MERCE: // righe di merce { // posiziona l'anagrafica sull'articolo specificato sulla ..iga _anamag->put(ANAMAG_CODART,r.get(RDOC_CODARTMAG)); if (_anamag->read() != NOERR) // se non trova l'articolo saltera' anche gmc,smc,rfa. skip_art_related = true; TString16 tok; // Scorre la stringa di ricerca for (int i=0;good() && iget(i); if (tok == "CF") { if (skip_clifo) continue; int gr = cli_file.get_int(CLI_GRUPPORIC); int co = cli_file.get_int(CLI_CONTORIC); long so = cli_file.get_long(CLI_SOTTOCRIC); conto.set(gr,co,so); if (conto.ok()) break; // se lo trova esce (tutti != 0) } else if (tok == "CA") { CHECK(_caus,"Causale documento non valida"); if (_caus->IVA2bill(codiva,conto)) break; // se lo trova esce } else if (tok == "AR") { if (skip_art_related) continue; int gr = _anamag->get_int(is_cli ? ANAMAG_GRUPPOV : ANAMAG_GRUPPOA); int co = _anamag->get_int(is_cli ? ANAMAG_CONTOV : ANAMAG_CONTOA); long so = _anamag->get_long(is_cli ? ANAMAG_SOTTOCV : ANAMAG_SOTTOCA); conto.set(gr,co,so); if (!conto.ok()) // se il conto non c'e' guarda la categoria acquisti/vendite { TTable& t = is_cli ? *_cra : *_caa; t.put("CODTAB", _anamag->get(is_cli ? ANAMAG_CATCONV : ANAMAG_CATCONA)); if (t.read() == NOERR) { gr = t.get_int("I0"); co = t.get_int("I1"); so = t.get_long("I2"); conto.set(gr, co, so); } } if (conto.ok()) break; } else if (tok == "GM" || tok == "SM" || tok == "RF") { if (skip_art_related) continue; const bool is_fis = tok == "RF"; TTable& tab = is_fis ? *_rfa : *_gmc; TString16 codtab =_anamag->get(is_fis ? ANAMAG_RAGGFIS : ANAMAG_GRMERC); if (tok == "GM" && codtab.len() > 3) codtab.cut(3); // gli ultimi 2 si riferiscono al sottogruppo. tab.put("CODTAB",codtab); if (tab.read() == NOERR) { int gr = tab.get_int(is_cli ? "I3" : "I0"); int co = tab.get_int(is_cli ? "I4" : "I1"); long so = tab.get_long(is_cli ? "I5" : "I2"); conto.set(gr, co, so); } if (conto.ok()) break; } else if (tok == "CV" || tok == "CC") { const bool is_cve = tok == "CV"; if (is_cve && !is_cli) continue; // se e' un fornitore salta questa condizione TTable& t = is_cve ? *_cve : *_cco; TString16 cod = is_cve ? r.doc().get(DOC_CATVEN) : EMPTY_STRING; if (cod.empty()) { if (skip_clifo) continue; // se non aveva trovato il cliente salta al prossimo cod = _clifo->curr(LF_CFVEN).get(is_cve ? CFV_CATVEN : CFV_CODCATC); } t.put("CODTAB",cod); if (t.read() == NOERR) { const bool x = (is_cve || is_cli); const int gr = t.get_int(x ? "I3" : "I0"); const int co = t.get_int(x ? "I4" : "I1"); const long so = t.get_long(x ? "I5": "I2"); conto.set(gr,co,so); } if (conto.ok()) break; } else if (tok == "VM") { if (!is_cli) continue; // se non e' un cliente salta questa condizione // Costruisco il codice Categoria conto vendite artioli(3)+Categoria di vendita cliente(2) TString8 cod = _anamag->get(ANAMAG_CATCONV); cod << _clifo->curr(LF_CFVEN).get(CFV_CATVEN); const TRectype* t = &cache().get("&CVM", cod); if (!t->empty()) { const int gr = t->get_int("I0"); const int co = t->get_int("I1"); const long so = t->get_long("I2"); conto.set(gr,co,so); if (conto.ok()) break; } } } } break; // case 'M' case RIGA_PRESTAZIONI: // righe prestazione case RIGA_SPESEDOC: // righe spese { const TSpesa_prest & spesa = r.spesa(); int gr = spesa.get_int(is_cli ? "I0" : "I3"); int co = spesa.get_int(is_cli ? "I1" : "I4"); long so = spesa.get_long(is_cli ? "I2" : "I5"); conto.set(gr,co,so); if (!conto.ok()) { gr = r.get_int(RDOC_QTAGG1); co = r.get_int(RDOC_QTAGG2); so = r.get_long(RDOC_QTAGG3); conto.set(gr,co,so); if (!conto.ok()) // Cerca il conto nella stringa di ricerca (solo per prestazioni) { if (t == RIGA_PRESTAZIONI) // Cerca il conto nella stringa di ricerca (solo per prestazioni) { TString16 tok; // Scorre la stringa di ricerca ma solo per causale o CLI/FO for (int i=0;good() && iget(i); if (tok == "CF") { if (skip_clifo) continue; gr = cli_file.get_int(CLI_GRUPPORIC); co = cli_file.get_int(CLI_CONTORIC); so = cli_file.get_long(CLI_SOTTOCRIC); conto.set(gr,co,so); if (conto.ok()) break; } else if (tok == "CA") { CHECK(_caus,"Causale documento non valida"); if (_caus->IVA2bill(codiva,conto)) break; } } } static int __searching = false; if (!conto.ok() && t == RIGA_SPESEDOC && !__searching) { if (spalma_spese()) { amount_to_split += valore; return _error; } const int rows = r.doc().physical_rows(); int row = -1; for (int i = 1; row <0 && i <= rows; i++) { const char tipo = r.doc()[i].tipo().tipo(); if (tipo != RIGA_DESCRIZIONI && tipo != RIGA_SCONTI && tipo != RIGA_OMAGGI && tipo != RIGA_SPESEDOC) row = i; } if (row > 0) { __searching = true; search_costo_ricavo(conto, r.doc()[row], amount_to_split, valore); __searching = false; } } } } } break; // case 'P','S' case 'C': // righe sconti: vengono considerate in adjust_sconto_rows() case 'D': // righe descrizioni (saltare) default : break; } // end of switch if (good()) { if (!conto.ok() || !conto.find()) { _conto_errato = conto; _error = conto_error; _nrow = r.get_int(RDOC_NRIGA); } } return _error; } error_type TContabilizzazione::search_costo_ricavo_mat(TBill& conto, const TRiga_documento& r) { const char t = r.tipo().tipo(); switch (t) { case RIGA_OMAGGI: // righe omaggio come articoli spiaccicato identico (avranno imponibile 0) case RIGA_MERCE: // righe di merce { TString16 key; key.format("%03d%03d%06ld", conto.gruppo(), conto.conto(), conto.sottoconto()); const TRectype &t2 = cache().get("&CMT", key); if (t2.empty()) { key.format("%03d%03d", conto.gruppo(), conto.conto()); const TRectype &t1 = cache().get("&CMT", key); if (t1.empty()) { key.format("%03d", conto.gruppo()); const TRectype &t = cache().get("&CMT", key); if (!t.empty()) conto.set(t.get_int("I0"), t.get_int("I1"), t.get_int("I2")); } else conto.set(t1.get_int("I0"), t1.get_int("I1"), t1.get_int("I2")); } else conto.set(t2.get_int("I0"), t2.get_int("I1"), t2.get_int("I2")); } break; // case 'M' default : break; } // end of switch return _error; } void TContabilizzazione::calculate_spese(real& spese, real& sp_iva, int ndec, bool is_incasso, bool is_cli, const TString & codiva_es, const TDocumento & doc) { const TBill& zio = is_incasso ? (is_cli ? _spin_billv : _spin_billa) : (is_cli ? _spbo_billv : _spbo_billa); if (zio.ok()) { TRiga_documento r((TDocumento *) &doc, "02"); // il tipo riga 02 spese a valore r.put(RDOC_QTA, UNO); r.put(RDOC_PREZZO, spese); r.put(RDOC_CODIVA, codiva_es); _righe_iva->add(r, zio, ndec); sp_iva = r.imposta(false); sp_iva.round(ndec); if (doc.tipo().calcolo_lordo()) // Si ricorda che calcolo_lordo() e fattura_commerciale sono esclusivi. { // Totalizza per ogni codice iva il lordo if (!_totali_lordi.is_key(codiva_es)) _totali_lordi.add(codiva_es, new real); real& rl = (real&) _totali_lordi[codiva_es]; rl += spese + sp_iva; } } else _error = spinbo_error; } error_type TContabilizzazione::add_spese_inbo(TDocumento& doc, const int ndec) // Aggiunge le righe di spese incasso/bolli { real tot_netto, sp_incasso, sp_bolli; real iva_sp_incasso, iva_sp_bolli; const real rit = doc.ritenute(); const bool is_cli = doc.get_char(DOC_TIPOCF) == 'C'; // Aggiunge le spese d'incasso tot_netto = doc.totale_netto(); sp_incasso = doc.spese_incasso(tot_netto, ndec, _netto); TString4 codiva_es; doc.iva_esente(codiva_es); if (!sp_incasso.is_zero()) calculate_spese(sp_incasso,iva_sp_incasso,ndec,true,is_cli, codiva_es.not_empty() ? codiva_es : doc.codiva_spese(), doc); // Aggiunge le spese bolli tot_netto += sp_incasso + iva_sp_incasso - rit; sp_bolli = doc.bolli(tot_netto, ndec, _netto); if (!sp_bolli.is_zero()) calculate_spese(sp_bolli, iva_sp_bolli, ndec, false, is_cli, doc.codiva_bolli(), doc); return _error; } // Aggiorna le righe di sconto (importo o a percentuale) error_type TContabilizzazione::adjust_sconto_rows(TDocumento& doc) { if (!_sco_imp_bill.ok() || !_sco_perc_bill.ok()) { _error = sconto_error; return _error; } TAssoc_array aa = doc.tabella_iva(); // no reference real sconto; const int ndec = doc.decimals(); // Scorre tutti gli elementi della tabella IVA del documento (elementi per codice iva) for (const TRiepilogo_iva* riep = (const TRiepilogo_iva*) aa.first_item(); riep != NULL; riep = (const TRiepilogo_iva*) aa.succ_item()) { const TString4 cod = riep->cod_iva().codice(); // Codice IVA corrente for (int i = 0; i < 2; i++) // Ciclo per sconto a percentuale (i == 0) e ad importo (i == 1) { //Importo sconto (sconto_perc() o sconto_imp()) //Calcola ::iva() sullo sconto //Somma alla riga corrispondente o la crea se non esiste gia' //I conti per aggiustare l'iva vengono fatti in adjust_iva_rows() const bool perc = i == 0; const TBill& conto = perc ? _sco_perc_bill : _sco_imp_bill; sconto = perc ? -riep->sconto_perc() : -riep->sconto_imp(); if (sconto != ZERO) { TRiga_documento r(&doc, "07"); // il tipo riga 07 sconti r.put(RDOC_QTA, UNO); r.put(RDOC_PREZZO, sconto); r.put(RDOC_CODIVA, cod); _righe_iva->add(r, conto, ndec); if (doc.tipo().calcolo_lordo()) // Si ricorda che calcolo_lordo() e fattura_commerciale() sono esclusivi. { // Totalizza per ogni codice iva il lordo if (!_totali_lordi.is_key(cod)) _totali_lordi.add(cod, new real); real& rl = (real&) _totali_lordi[cod]; rl -= sconto; rl -= -riep->iva_sconto(); // Giochi strani sui segni :-) } } } } return no_error; } static real inc_field(TRectype& rec, const char* field, real diff) { real val = rec.get_real(field); val += diff; rec.put(field, val); return val; } // "Aggiusta" l'imposta sulle righe IVA secondo la tabella interna al documento // Tratta anche i documenti in valuta. DI solito si tratta di poche lire. error_type TContabilizzazione::adjust_iva_rows(TDocumento& doc) { TAssoc_array& aa = doc.tabella_iva(); TRiepilogo_iva * riep; const int items = _movimento->iva_items();// Numero di righe IVA const bool in_valuta = doc.in_valuta(); const bool calcolo_lordo = doc.tipo().calcolo_lordo(); real imponibile; const int ndec = TCurrency::get_firm_dec(); // Numero di decimali della valuta di ditta const TString4 codval(doc.get(DOC_CODVAL)); const real cambio = doc.cambio(); const exchange_type et = doc.get_bool(DOC_CONTROEURO) ? _exchange_contro : _exchange_base; // Scorre tutti gli elementi della tabella IVA del documento (elementi per codice iva) for (riep = (TRiepilogo_iva*) aa.first_item(); riep != NULL; riep = (TRiepilogo_iva*) aa.succ_item()) { const TCodiceIVA & cod = riep->cod_iva(); // Codice IVA const TString4 codiva(cod.codice()); real iva_g; if (calcolo_lordo) { imponibile = _totali_lordi.is_key(codiva) ? (real&)_totali_lordi[codiva] : ZERO; iva_g = cod.scorpora(imponibile, doc.decimals()); } else iva_g = riep->imposta(); if (in_valuta) { if (calcolo_lordo) { TCurrency_documento tot(imponibile + iva_g, doc); tot.change_to_firm_val(); imponibile = tot.get_num(); iva_g = cod.scorpora(imponibile, ndec); } else { TCurrency_documento tot(riep->imponibile() + iva_g, doc); tot.change_to_firm_val(); imponibile = tot.get_num(); iva_g = cod.scorpora(imponibile, ndec); } } else { if (ndec == 0) { TExchange cam(codval, cambio, et); iva_g *= cam.get_base_change(); if (iva_g < ZERO) iva_g.floor(0); else iva_g.ceil(0); } else { TCurrency_documento iva(iva_g); iva.change_to_firm_val(); iva_g = iva.get_num(); } } TGeneric_distrib gd_iva(iva_g, ndec); // Instanzia il TGeneric_ditrib con la vera Imposta TGeneric_distrib gd_imp(imponibile, ndec); // Adesso scorre tutte le righe IVA contabili con questo codice IVA int i; for (i = 0; i < items; i++) { const TRectype& ie = _movimento->iva(i); if (ie.get(RMI_CODIVA) == codiva) // Se il codice IVA e' uguale { gd_iva.add(ie.get_real(RMI_IMPOSTA)); // Aggiunge al TGeneric_distrib l'imposta corrente if (calcolo_lordo || in_valuta) gd_imp.add(ie.get_real(RMI_IMPONIBILE)); } } // Alla fine per performare tutto il calcolo (Thanx to TGeneric_distrib) si fanno le get // E le si mettono nel rispettivo record IVA for (i = 0; i < items; i++) { TRectype& ie = _movimento->iva(i); if (ie.get(RMI_CODIVA) == codiva) // Se il codice IVA e' uguale { ie.put(RMI_IMPOSTA,gd_iva.get()); // Sostituisce l'imposta con quella ricalcolata al fine di avere tutto giusto if (calcolo_lordo || in_valuta) ie.put(RMI_IMPONIBILE, gd_imp.get()); } } } // Visto che vengono restituiti nello stesso ordine in cui sono state chiamate le rispettive TGeneric_distrib::add() if (_caus->iva() == iva_acquisti && items > 0) { const TString16 tdoc_cont(doc.tipo().totale_doc_cont()); if (tdoc_cont.not_empty()) { real diffval = doc.get_real(tdoc_cont) - doc.totale_doc(); TCurrency_documento dv(diffval, doc); dv.change_to_firm_val(); real difflit = dv.get_num(); if (!difflit.is_zero()) // Controlla se c'è differenza { TRectype& rigaiva = _movimento->iva(0); const TCodiceIVA iva(rigaiva.get(RMI_CODIVA)); if (_caus->intra()) { const real imponibile = inc_field(rigaiva, RMI_IMPONIBILE, difflit); const real imposta = iva.imposta(imponibile); rigaiva.put(RMI_IMPOSTA, imposta); } else { real diffimp = iva.scorpora(difflit); inc_field(rigaiva, RMI_IMPONIBILE, difflit); inc_field(rigaiva, RMI_IMPOSTA, diffimp); } } if (_caus->intra()) { real ritfis; for (int i = 0; i < items; i++) ritfis += _movimento->iva(i).get_real(RMI_IMPOSTA); _movimento->curr().put(MOV_RITFIS, ritfis); } } } return no_error; } error_type TContabilizzazione::create_iva_rows(TDocumento& doc) { const int items = _righe_iva->items(); const bool in_valuta = doc.in_valuta(); TRectype& head = _movimento->curr(); TToken_string key; TString_array key_arr; TString4 codiva; TBill cur_conto; char tipo; int gruppo; int conto; long sottoconto; const int annoes = head.get_int(MOV_ANNOES); const long numreg = head.get_long(MOV_NUMREG); real cambio = head.get_real(MOV_CAMBIO); real imponibile,imposta; const TString4 valuta(doc.valuta()); _righe_iva->get_keys(key_arr); key_arr.sort(); for (int i = 0, nr = 0; i < items; i++) { key = key_arr.row(i); const TRectype& cur = (const TRectype &)(*_righe_iva)[key]; codiva = cur.get(RMI_CODIVA); tipo = cur.get_char(RMI_TIPOC); gruppo = cur.get_int(RMI_GRUPPO); conto = cur.get_int(RMI_CONTO); sottoconto = cur.get_long(RMI_SOTTOCONTO); cur_conto.set(gruppo, conto, sottoconto, tipo); cur_conto.find(); imponibile = cur.get_real(RMI_IMPONIBILE); imposta = cur.get_real(RMI_IMPOSTA); if (in_valuta) // I documenti vanno sempre contabilizzati in lire { TCurrency_documento imponval(imponibile, doc); imponval.change_to_firm_val(); imponibile = imponval.get_num(); // imponibile in lire TCurrency_documento impval(imposta, doc); impval.change_to_firm_val(); imposta = impval.get_num(); // questa e' l'imposta ricalcolata } if (imponibile != ZERO && codiva.not_empty()) { TRectype& rec_iva = _movimento->iva(nr); rec_iva.put(RMI_ANNOES,annoes); rec_iva.put(RMI_NUMREG,numreg); rec_iva.put(RMI_NUMRIG,nr+1); // La numerazione comincia da 1 rec_iva.put(RMI_CODIVA,codiva); rec_iva.put(RMI_IMPONIBILE,imponibile); rec_iva.put(RMI_IMPOSTA,imposta); rec_iva.put(RMI_TIPOCR,cur_conto.tipo_cr()); rec_iva.put(RMI_INTRA, _caus->intra()); rec_iva.put(RMI_TIPOC, tipo); rec_iva.put(RMI_GRUPPO, gruppo); rec_iva.put(RMI_CONTO, conto); rec_iva.put(RMI_SOTTOCONTO, sottoconto); rec_iva.put(RMI_TIPODET, cur.get(RMI_TIPODET)); nr++; } } return _error; } error_type TContabilizzazione::create_total_doc_row(TDocumento& doc) // Crea la riga contabile di totale documento { TRectype& rec_cg = _movimento->cg(0); TRectype& head = _movimento->curr(); const int annoes = head.get_int(MOV_ANNOES); const long numreg = head.get_long(MOV_NUMREG); const TDate datareg(head.get_date(MOV_DATAREG)); real totdoc(head.get_real(MOV_TOTDOC)); const TRectype& cli_file = _clifo->curr(); char tipocf = cli_file.get_char(CLI_TIPOCF); long codcf = cli_file.get_long(CLI_CODCF); int gruppo = 0, conto = 0; TString16 catven(doc.get(DOC_CATVEN)); if (search_clifo_bill(catven) == no_error) { tipocf = _co_cliente.tipo(); gruppo = _co_cliente.gruppo(); conto = _co_cliente.conto(); codcf = _co_cliente.sottoconto(); } else { _conto_errato = _co_cliente; _error = contocf_error; tipocf = _co_cliente.tipo(); gruppo = _co_cliente.gruppo(); conto = _co_cliente.conto(); codcf = _co_cliente.sottoconto(); _nrow = -1; } TConto contro; if (_movimento->iva_items() > 0) { const TRectype& first_iva_row = _movimento->iva(0); contro.get(first_iva_row); } rec_cg.put(RMV_ANNOES,annoes);rec_cg.put(RMV_NUMREG,numreg); const char sezione = _caus->sezione(1); rec_cg.put(RMV_NUMRIG,1); rec_cg.put(RMV_SEZIONE, sezione); rec_cg.put(RMV_DATAREG,datareg); rec_cg.put(RMV_TIPOC,tipocf); rec_cg.put(RMV_GRUPPO,gruppo);rec_cg.put(RMV_CONTO,conto); rec_cg.put(RMV_SOTTOCONTO,codcf); contro.put(rec_cg, true); rec_cg.put(RMV_CUP, doc.get(DOC_CUP)); rec_cg.put(RMV_CIG, doc.get(DOC_CIG)); rec_cg.put(RMV_IMPORTO,totdoc); rec_cg.put(RMV_ROWTYPE,"T"); if (tipocf <= ' ') { head.zero(MOV_TIPO); head.zero(MOV_CODCF); } return _error; } bool TContabilizzazione::valid_row_type(const char* rt) const { const TRectype& tri = cache().get("%TRI", rt); return !tri.empty(); } void TContabilizzazione::split_sp_amount(const real & amount, int decimals) { TGeneric_distrib d(amount, decimals); FOR_EACH_ASSOC_OBJECT((*_righe_iva), obj, key, itm) { const bool spese = key && *key == '3'; TRectype & r = (TRectype &)*itm; const real imp = r.get_real(RMI_IMPONIBILE); if (spese) d.add(ZERO); else d.add(imp); } FOR_EACH_ASSOC_OBJECT((*_righe_iva), obj1, key1, itm1) { const bool spese = key1 && *key1 == '3'; TRectype & r = (TRectype &)*itm1; if (spese) d.get(); else { real imp = r.get_real(RMI_IMPONIBILE); const TCodiceIVA i(r.get(RMI_CODIVA)); imp += d.get(); r.put(RMI_IMPONIBILE, imp); real const imposta = i.imposta(imp); r.put(RMI_IMPOSTA, imposta); } } } error_type TContabilizzazione::compile_rows_mov(TDocumento& doc) // Compila le righe { TString4 tiporiga, codiva1, codiva2; const int rows = doc.rows(); const int ndec = doc.decimals(); real amount_to_split; const bool fat_com = doc.tipo().fattura_commerciale(); static TString_array tabella_ripartizione; if (fat_com && tabella_ripartizione.empty()) { TConfig cnf(CONFIG_STUDIO, "ve"); for (int k = 1; k <= MAX_IVA_SLICES; k++) { TToken_string* tt = new TToken_string(); tt->add(cnf.get("EXCLUDE_PERC", "ve", k)); tt->add(cnf.get("EXCLUDE_IVA", "ve", k)); tabella_ripartizione.add(tt); } } _righe_iva->destroy(); // resetta l'assoc_array delle righe di iva _totali_lordi.destroy();// resetta l'assoc_array dei totali lordi for (int i=1; good() && i<=rows; i++) // browse all this fucked document rows { TRiga_documento& r = doc[i]; const TString4 tiporiga = r.get(RDOC_TIPORIGA); if (valid_row_type(tiporiga)) // controlla l'esistenza della riga { TBill conto, contomat; real pricemat; const char tipo = r.tipo().tipo(); // Le righe omaggio senza addebito IVA vanno saltate const bool riga_omaggio = tipo == RIGA_OMAGGI && r.get_bool(RDOC_ADDIVA); if ((tipo != RIGA_DESCRIZIONI && tipo != RIGA_SCONTI && tipo != RIGA_RETTIFICHE) || riga_omaggio) { const bool spesa = r.tipo().tipo() == RIGA_SPESEDOC; char tipo_rit = '\0'; if (spesa) tipo_rit = r.spesa().tipo_ritenuta(); const bool ritenuta = tipo_rit != '\0' && !_caus->intra(); TBill conto; if (!ritenuta) { if (!riga_omaggio && r.imponibile().is_zero()) continue; search_costo_ricavo(conto, r, amount_to_split, r.imponibile()); // l'errore eventuale viene settato qui dentro if (good()) { static TString16 fldvalmat("883"); if (fldvalmat == "883") fldvalmat = ini_get_string(CONFIG_DITTA, "ve", "FldValMat", ""); if (fldvalmat.full()) { pricemat = real(cache().get(LF_ANAMAG, r.get(RDOC_CODARTMAG), fldvalmat)); if (!pricemat.is_zero()) { contomat = conto; search_costo_ricavo_mat(contomat, r); // l'errore eventuale viene settato qui dentro } } } } if (good()) { if (fat_com) { const TString4 codiva2 = r.get(RDOC_CODIVA); // Save... for (int j=0; j < MAX_IVA_SLICES; j++) { const real perc = real(tabella_ripartizione.row(j).get(0)) / CENTO; codiva1 = tabella_ripartizione.row(j).get(1); if (perc == ZERO || codiva1.blank()) continue; r.put(RDOC_CODIVA, codiva1); if (riga_omaggio) { _error = _righe_iva->add_omaggi(r, conto, ALL_DECIMALS, perc); if (_error != no_error) _nrow = i; } else _righe_iva->add(r, conto, ALL_DECIMALS, perc); } r.put(RDOC_CODIVA, codiva2); //Restore } else { if (ritenuta) { TCurrency_documento c(r.ritenuta(tipo_rit)); TBill cnt; _caus->bill(tipo_rit == 'F' ? RIGA_RITENUTE_FISCALI : RIGA_RITENUTE_SOCIALI, cnt); if (cnt.ok()) { TRectype & h = _movimento->lfile().curr(); real val; if (r.doc().in_valuta()) { val = h.get_real(MOV_TOTDOCVAL) - c.get_num(); h.put(MOV_TOTDOCVAL, val); } c.change_to_firm_val(); val = h.get_real(MOV_TOTDOC) - c.get_num(); h.put(MOV_TOTDOC, val); const char * campo = tipo_rit == 'F' ? MOV_RITFIS : MOV_RITSOC; val = h.get_real(campo) + c.get_num(); h.put(campo, val); } } else if (riga_omaggio) { _error = _righe_iva->add_omaggi(r, conto); if (_error != no_error) _nrow = i; } else if (contomat.ok() && contomat != conto && pricemat != 0) { TRiga_documento rlav(r); TRiga_documento rmat(r); const real prezzo = r.get_real(RDOC_PREZZO); rmat.put(RDOC_PREZZO, pricemat); rmat.zero(RDOC_SCONTO); const real valmat = rmat.imponibile(); const real diff = r.imponibile() - valmat; rlav.put(RDOC_PREZZO, diff); rlav.put(RDOC_QTA, 1); rlav.zero(RDOC_SCONTO); rmat.put(RDOC_PREZZO, valmat); rmat.put(RDOC_QTA, 1); rmat.zero(RDOC_SCONTO); _righe_iva->add(rlav, conto); _righe_iva->add(rmat, contomat); } else if (conto.ok()) _righe_iva->add(r, conto); if (!ritenuta && r.doc().tipo().calcolo_lordo()) // Si ricorda che calcolo_lordo() e fattura_commerciale() sono esclusivi. { // Totalizza per ogni codice iva il lordo const TString& cod = r.get(RDOC_CODIVA); if (!_totali_lordi.is_key(cod)) _totali_lordi.add(cod, new real); real& rl = (real&) _totali_lordi[cod]; rl += r.imponibile(true); } } } } } else { _error = row_type_error; _nrow = i; } } if (amount_to_split != ZERO) split_sp_amount(amount_to_split, ndec); if (good() && _righe_iva->empty()) _error = no_rows_error; // Crea le righe per le spese d'incasso e bolli if (good()) add_spese_inbo(doc, doc.decimals()); // Aggiorna le righe di sconto (sconto ad importo o percentuale) if (good()) adjust_sconto_rows(doc); // Crea le righe di IVA if (good()) create_iva_rows(doc); // Controlla che le imposte per ogni aliquota ed eventualmente corregge le imposte stesse sulle righe if (good()) adjust_iva_rows(doc); // Crea la riga di totale documento if (good()) create_total_doc_row(doc); // crea le righe di contabilita' if (good()) { const TString descr_cr = doc.clifor().get(CLI_RAGSOC); // Probabile porcata ... che Pharmatex non vuole! switch (_movimento->recalc_cg_rows(descr_cr, *_caus)) { case 1 : _error = movement_error; break; case 2 : _error = cau_ritintra_error; break; default: break; } } const TRegistro& registro = _caus->reg(); const bool iva_mov = registro.ok(); if (!iva_mov) { static int __check_sez = -1; if (__check_sez < 0) __check_sez = ini_get_bool(CONFIG_DITTA, "ve", "CHECK_SEZ"); bool swap = false; if (__check_sez) { const TString4 sz = _movimento->cg(0).get(RMV_SEZIONE); for (int row = 1; !swap && row <= doc.physical_rows(); row++) { const TRiga_documento & r = doc[row]; if (r.is_spese()) { const TSpesa_prest s(r.get(RDOC_CODART)); const TString & sez = s.get("S11"); swap = sez == sz; } } } const int cgitems = _movimento->cg_items(); for (int i = cgitems - 1 ; i >= 0; i--) { TRectype& rec_cg = _movimento->cg(i); rec_cg.zero(RMV_ROWTYPE); if (__check_sez && swap) { const TString4 sez = rec_cg.get(RMV_SEZIONE); rec_cg.put(RMV_SEZIONE, sez == "D" ? "A" :"D"); } } _movimento->destroy_iva_row(); } return _error; } // Compila le righe error_type TContabilizzazione::compile_rows_mov_re(TDocumento& doc) { const int rows = doc.rows(); const int ndec = doc.decimals(); real amount_to_split; _righe_iva->destroy(); // resetta l'assoc_array delle righe di iva for (int i=1; good() && i<=rows; i++) // browse all this fucked document rows { const TRiga_documento& r = doc[i]; const TString4 tiporiga = r.get(RDOC_TIPORIGA); if (valid_row_type(tiporiga)) // controlla l'esistenza della riga { const char tipo = r.tipo().tipo(); // Le righe omaggio senza addebito IVA vanno saltate const bool riga_omaggio = tipo == RIGA_OMAGGI && r.get_bool(RDOC_ADDIVA); const bool spesa = r.tipo().tipo() == RIGA_SPESEDOC; if ((tipo != RIGA_DESCRIZIONI && tipo != RIGA_SCONTI && tipo != RIGA_RETTIFICHE) && !riga_omaggio) { TBill conto; search_costo_ricavo(conto, r, amount_to_split, r.imponibile()); // l'errore eventuale viene settato qui dentro if (good()) _righe_iva->add(r, conto); } } else { _error = row_type_error; _nrow = i; } } split_sp_amount(amount_to_split, ndec); if (good() && _righe_iva->items() == 0) _error = no_rows_error; // Crea le righe per le spese d'incasso e bolli if (good()) add_spese_inbo(doc,ndec); // Crea le righe di IVA if (good()) create_iva_rows(doc); // Aggiorna le righe di sconto (sconto ad importo o percentuale) if (good()) adjust_sconto_rows(doc); if (good()) adjust_iva_rows(doc); // Crea la riga di totale documento if (good()) { int righe = _movimento->iva_items(); for (int i=0; iadd_row_re(i); righe = _movimento->cg_items(); int row_to_add = righe - 1; for (int j = row_to_add; j >= 0; j--) if (!_movimento->add_row_cp_re(row_to_add)) row_to_add--; } _movimento->destroy_iva_row(); return _error; } error_type TContabilizzazione::change_doc_status(TDocumento& doc) // Cambia lo stato del documento { doc.stato(get_char("S4")); if (doc.rewrite() != NOERR) _error = chg_stat_error; return _error; } error_type TContabilizzazione::write_scadenze(TDocumento& doc) // Scrive le scadenze. Liberamente tratto da cg2104.cpp. { const TRectype& head = _movimento->curr(); const long nreg = head.get_long(MOV_NUMREG); // const real change(head.get_real(MOV_CAMBIO)); int anno = head.get_int(MOV_ANNOIVA); if (head.get_real(MOV_TOTDOC) == ZERO) return _error; TString16 numpart; if (_nump_cfg) numpart = head.get(MOV_PROTIVA); else { numpart = doc.get(DOC_NUMDOCRIF); if (_caus->iva() == iva_vendite && !doc.tipo().nota_credito()) numpart.cut(0); if (numpart.blank()) numpart = head.get(MOV_NUMDOC); else { TDate ddr = doc.get_date(DOC_DATADOCRIF); if (ddr.ok()) anno = ddr.year(); } } TPartita* newgame = NULL; if (anno > 0 && !numpart.blank()) { const int tmov = _caus->tipomov(); const TString80 desc(head.get(MOV_DESCR)); const TString4 codcaus(_caus->codice()); const TString4 v(head.get(MOV_CODVAL)); const TDate d(head.get_date(MOV_DATACAM)); const real c(head.get_real(MOV_CAMBIO)); const TValuta cambio(v, d, c); // verificare const TString8 agente(doc.get(DOC_CODAG)); const int ndec = doc.decimals(); const char sezione = _movimento->cg(0).get_char(RMV_SEZIONE); // Dare/Avere newgame = new TPartita(_co_cliente, anno, numpart); newgame->allinea(); // Rispettare sempre l'allineamento del numero partita! int row = 0; if (tmov == tm_fattura) row = newgame->prima_fattura(nreg); // Riga fattura di questo movimento TRiga_partite& partita = row <= 0 ? newgame->new_row() : newgame->riga(row); const int nuova_riga = partita.get_int(PART_NRIGA); // put data on partita partita.put(PART_TIPOMOV, tmov); partita.put(PART_NREG, nreg); // Riferimento alla registrazione contabile partita.put(PART_NUMRIG, 1); // Riferimento alla riga contabile del totale partita.put(PART_DATAREG, head.get(MOV_DATAREG)); partita.put(PART_DATADOC, head.get(MOV_DATADOC)); partita.put(PART_NUMDOC, head.get(MOV_NUMDOC)); partita.put(PART_DESCR, desc); partita.put(PART_CODCAUS, codcaus); partita.put(PART_REG, _caus->reg().name()); partita.put(PART_PROTIVA, head.get(MOV_PROTIVA)); partita.put(PART_SEZ, sezione); const real totdoc(head.get(MOV_TOTDOC)); const real totdocval(head.get(MOV_TOTDOCVAL)); const bool in_valuta = cambio.in_valuta(); const bool swapped = test_swap(); const TCurrency_documento td((in_valuta ? totdocval : totdoc) * (swapped ? -1 : 1), doc); partita.put(PART_IMPTOTDOC, totdoc); cambio.put(partita); if (in_valuta) partita.put(PART_IMPTOTVAL,totdocval); if (partita.is_fattura()) { TPagamento& pag = doc.pagamento(); const TCurrency_documento totspese(doc.spese(), doc); TCurrency_documento totimposte(doc.imposta(true), doc); real imposte; for (int j = _movimento->iva_items()-1; j >= 0; j--) imposte += _movimento->iva(j).get_real(RMI_IMPOSTA) * (swapped ? -1 : 1); if (_caus->iva() == iva_acquisti) // Ricalcola precisamente il totale imposte { real ti = imposte; if (in_valuta) cambio.lit2val(ti); totimposte.set_num(ti); } const TCurrency totimponibili = td - totimposte - totspese; TCurrency_documento anticipo(doc.get_real(DOC_IMPPAGATO), doc); if (anticipo.abs() < td.abs()) { TGeneric_distrib d(anticipo.get_num(), ndec); d.add(totimponibili.get_num()); d.add(totimposte.get_num()); d.add(totspese.get_num()); const TCurrency_documento pagtotimponibili(totimponibili.get_num() - d.get(), doc); TCurrency_documento diffiva(d.get(), doc); const TCurrency_documento pagtotimposte (totimposte.get_num() - diffiva.get_num(), doc); const TCurrency_documento pagtotspese (totspese.get_num() - d.get(), doc); if (in_valuta) { const real change = cambio.cambio(); //real val1 = totimponibili * change; TCurrency val2(imposte); diffiva.change_to_firm_val(); val2 -= diffiva; TCurrency_documento val3(pagtotspese); val3.change_to_firm_val(); TCurrency val1(totdoc); TCurrency_documento ant(anticipo.get_num(), doc); ant.change_to_firm_val(); val1 -= ant + val2 + val3; // Cosi' corregge eventuali scompensi di poche lirette pag.set_total_valuta(pagtotimponibili, pagtotimposte, pagtotspese, val1, val2, val3); } else pag.set_total( pagtotimponibili, pagtotimposte, pagtotspese); pag.set_rate_auto( ); } else pag.zap_rate(); if (!anticipo.is_zero()) { pag.add_rata(); TDate first_date(doc.data()); TDate first_scad(pag.data_rata(0)); if (first_date == first_scad) pag.set_datarata(0, ++first_scad); // Sposta in avanti la data della prima scadenza di un giorno. // Shift delle rate verso il basso for (int k=pag.n_rate()-1; k>0; k--) pag.rata(k) = pag.rata(k-1); // Sostituisce la prima rata con quella dell'anticipo // Se l'anticipo è più grande del totale, si crea una riga di scadenza // con l'importo del totale doc. if (anticipo.abs() >= td.abs()) anticipo = td; TCurrency_documento anticipo_base(anticipo); anticipo_base.change_to_firm_val(); // Crea una rimessa diretta con la data del documento per il valore dell'anticipo pag.set_rata(0, in_valuta ? anticipo.get_num() : ZERO, anticipo_base.get_num(), first_date, 1, "", false); } real imponibile, imponibile_val; int i; for (i = pag.n_rate()-1; i >= 0; i--) { if (in_valuta) imponibile_val += pag.tval_rata(i); imponibile += pag.tlit_rata(i); } partita.put(PART_IMPORTO, imponibile); partita.put(PART_IMPORTOVAL, imponibile_val); partita.put(PART_IMPOSTA, imposte); partita.put(PART_SPESE, totspese.get_num()); newgame->scollega_pagamenti(nuova_riga); // Sempre meglio che perderli, ma andrebbero ricollegati partita.elimina_rata(-1); // Elimina tutte le rate eventuali const TString8 abipr(doc.get(DOC_CODABIP)), cabpr(doc.get(DOC_CODCABP)), abi(doc.get(DOC_CODABIA)), cab(doc.get(DOC_CODCABA)); const int nr = pag.n_rate(); const TString16 codpag(head.get(MOV_CODPAG)); for (i = 0; i < nr; i++) { TRiga_scadenze& scadenza = partita.new_row(); scadenza.put(SCAD_CODPAG, codpag); // Codice pagamento scadenza.put(SCAD_CODAG, agente); // Codice agente scadenza.put(SCAD_DATASCAD, pag.data_rata(i)); // Data scadenza scadenza.put(SCAD_IMPORTO, pag.tlit_rata(i)); // Importo if (in_valuta) scadenza.put(SCAD_IMPORTOVAL, pag.tval_rata(i)); // Importo in valuta scadenza.put(SCAD_TIPOPAG, pag.tipo_rata(i)); // Tipo pagamento scadenza.put(SCAD_ULTCLASS, pag.ulc_rata(i)); // Ulteriore classificazione scadenza.put(SCAD_CODABIPR, abipr); // Ns ABI scadenza.put(SCAD_CODCABPR, cabpr); // Ns CAB scadenza.put(SCAD_CODABI, abi); // Vs ABI scadenza.put(SCAD_CODCAB, cab); // Vs CAB // scadenza.put(SCAD_DESCR, ????); // Note } } // if fattura else if (doc.is_nota_credito()) { TImporto residuoval(sezione, doc.totale_doc()); TImporto residuolit(sezione, abs(totdoc)); partita.put(PART_DATAPAG, doc.get(DOC_DATADOC)); partita.put(PART_TIPOPAG, doc.pagamento().tipo_rata(0)); // Attenzione: le note di credito possono avere in testata valori negativi! Qui vanno positivi. partita.put(PART_IMPTOTDOC, abs(totdoc)); partita.put(PART_IMPTOTVAL, abs(totdocval)); // Attenzione: l'importo giusto viene poi aggiornato dalla modifica pagamento partita.zero(PART_IMPORTO); partita.zero(PART_IMPORTOVAL); const TDate datadocrif = doc.get_date(DOC_DATADOCRIF); const TString16 numdocrif = doc.get(DOC_NUMDOCRIF); int p; for (p = newgame->prima_fattura(); p > 0 && p < nuova_riga; p++) { const TRiga_partite& fatt = newgame->riga(p); const TDate datadoc = fatt.get_date(PART_DATADOC); const TString16 numdoc = fatt.get(PART_NUMDOC); if (datadoc.year() == datadocrif.year() && numdoc == numdocrif) break; } if (p > 0 && p < nuova_riga) { TPagamento& pag = doc.pagamento(); TCurrency_documento totdoc(abs(doc.totale_doc()), doc); TCurrency_documento totspese(abs(doc.spese()), doc); TCurrency_documento totimposte(abs(doc.imposta(true)), doc); TCurrency_documento totimponibili = totdoc - totspese - totimposte; if (in_valuta) { TCurrency_documento val2(totimposte); val2.change_to_firm_val(); TCurrency_documento val3(totspese); val3.change_to_firm_val(); TCurrency_documento val1(totdoc); val1.change_to_firm_val(); val1 -= val2+val3; // Cosi' corregge eventuali scompensi di poche lirette pag.set_total_valuta(totimponibili, totimposte, totspese, val1, val2, val3); } else pag.set_total(totimponibili, totimposte, totspese); pag.set_rate_auto(); const TRiga_partite& fatt = newgame->riga(p); for (int r = 1; r <= fatt.rate() && r <= pag.n_rate(); r++) { const TRiga_scadenze& rata = fatt.rata(r); const real imprata = rata.residuo(false).valore(); const real imprataval = rata.residuo(true).valore(); real importo_rata_lit = pag.importo_rata(r-1, false); real importo_rata_val = in_valuta ? pag.importo_rata(r-1, true) : importo_rata_lit; real delta_lit = importo_rata_lit - imprata; real delta_val = in_valuta ? importo_rata_val - imprataval : ZERO; // Controlla se l'importo della nota di credito supera quello della fattura if (delta_lit > ZERO || delta_val > ZERO) { // Detrae l'eccedenza dalla rata corrente e la sposta nella rata successiva importo_rata_lit -= delta_lit; importo_rata_val -= delta_val; if (r == pag.n_rate()) { // Crea eventuale ultima rata mancante pag.add_rata(); } else { // Incrementa importo rata delta_lit += pag.importo_rata(r, false); delta_val += pag.importo_rata(r, true); } const TDate oggi(TODAY); const int tiporata = pag.tipo_rata(r-1); pag.set_rata(r, delta_val, delta_lit, oggi, tiporata, "", false); } if (!importo_rata_lit.is_zero() || (in_valuta && !importo_rata_val.is_zero())) { TRectype pag = newgame->pagamento(p, r, nuova_riga); pag.put(PAGSCA_IMPORTO, importo_rata_lit); if (in_valuta) { pag.put(PAGSCA_IMPORTOVAL, importo_rata_val); residuoval -= TImporto(sezione, importo_rata_val); } else residuoval -= TImporto(sezione, importo_rata_lit); residuolit -= TImporto(sezione, importo_rata_lit); pag.put(PAGSCA_ACCSAL, "A"); newgame->modifica_pagamento(pag, cambio, true); } } } if (!residuoval.is_zero()) { // Pagamento non assegnato TRectype unpag = newgame->pagamento(TPartita::UNASSIGNED, 0, nuova_riga); if (in_valuta) { unpag.put(PAGSCA_IMPORTOVAL, residuoval.valore()); unpag.put(PAGSCA_IMPORTO, residuolit.valore()); } else unpag.put(PAGSCA_IMPORTO, residuoval.valore()); unpag.put(PAGSCA_ACCSAL, "A"); newgame->modifica_pagamento(unpag, cambio, true); } } } if (newgame != NULL) // Se non ho cancellato il numero partita ... { if (!newgame->write()) // Salva nuova partita _error = write_part_error; delete newgame; } return _error; } error_type TContabilizzazione::write_all(TDocumento& doc, TMovimentoPN_VE & movimento) // Scrive il movimento e le scadenze, gestendo la rinumerazione se il movimento e' gia presente { // N.B: _error non viene settato, per non stampare il messaggio di errore 2 volte. // basta solo ritornare qualcosa di != da no_error, per evitare le operazioni successive // a write_all TRectype& head = movimento.curr(); const long numreg = head.get_long(MOV_NUMREG); if (test_swap()) { const real totdoc = -head.get_real(MOV_TOTDOC); head.put(MOV_TOTDOC, totdoc); // Non cambio segno! :-( LL700285 // const real totdocval = -head.get_real(MOV_TOTDOCVAL); // head.put(MOV_TOTDOCVAL, totdocval); const int items = movimento.iva_items(); for (int i = items - 1 ; i >= 0; i--) { TRectype & rec_iva = movimento.iva(i); const real imponibile = -rec_iva.get_real(RMI_IMPONIBILE); const real imposta = -rec_iva.get_real(RMI_IMPOSTA); rec_iva.put(RMI_IMPONIBILE, imponibile); rec_iva.put(RMI_IMPOSTA, imposta); } } TSaldo_agg saldo; int err = NOERR; const long old_numreg = doc_contabilized(doc, false); if (old_numreg > 0) { TMovimentoPN oldmov; oldmov.curr().put(MOV_NUMREG, old_numreg); if (oldmov.read() == NOERR) aggiorna_saldi(saldo, oldmov, false); // Leggo i vecchi saldi err = movimento.rewrite(); } else err = movimento.write(); if (err != NOERR) { error_box("*** Errore %d scrivendo il movimento contabile %ld.", err, numreg); return generic_error; } // Aggiorno subito i saldi aggiorna_saldi(saldo, movimento, true); if (sc_enabled(head.get_date(MOV_DATAREG))) write_scadenze(doc); if (good() && in_enabled()) write_intra(doc); if (good() && (dongle().active(CMAUT) || dongle().active(CAAUT))) write_anal(doc, movimento); const int tipocoll = _caus->link_m770(); const bool do_770 = tipocoll == 1 || tipocoll == 5 || tipocoll == 6; if (good() && dongle().active(M77AUT) && do_770) write_percip(doc, movimento); if (doc.get_real(DOC_IMPPAGATO) != ZERO) if (write_anticipo(doc) != no_error) movimento.remove(); // Se si è verificato un errore nella scrittura dell'anticipo rimuove il movimento di prima nota if (good()) { _total_docs++; change_doc_status(doc); const TRectype& mov = _movimento->curr(); TString80 msg; msg.format("--- Movimento contabile $[b,w]%ld$[n,w]", mov.get_long(MOV_NUMREG)); msg << " del " << mov.get(MOV_DATAREG); _viswin->add_line(msg); call_exe(doc, movimento); } return no_error; } error_type TContabilizzazione::write_all_re(TDocumento& doc, TMovimentoPN_VE & movimento) // Scrive il movimento e le scadenze, gestendo la rinumerazione se il movimento e' gia presente { // N.B: _error non viene settato, per non stampare il messaggio di errore 2 volte. // basta solo ritornare qualcosa di != da no_error, per evitare le operazioni successive // a write_all TRectype& head = movimento.curr(); long numreg = head.get_long(MOV_NUMREG); TSaldo_agg saldo; int err = NOERR; const long old_numreg = doc_contabilized(doc, false); if (old_numreg > 0) { TMovimentoPN oldmov; oldmov.curr().put(MOV_NUMREG, old_numreg); if (oldmov.read() == NOERR) aggiorna_saldi(saldo, oldmov, false); // Leggo i vecchi saldi err = movimento.rewrite(); } else err = movimento.write(); if (err != NOERR) { error_box("*** Errore %d scrivendo il movimento contabile %ld.", err, numreg); return generic_error; } // Aggiorno subito i saldi aggiorna_saldi(saldo, movimento, true); if (good() && (dongle().active(CMAUT) || dongle().active(CAAUT))) write_anal(doc, movimento); if (good()) { _total_docs++; change_doc_status(doc); TString msg(TR("--- Movimento contabile ")); msg << "$[b,w]" << _movimento->curr().get_long(MOV_NUMREG) << "$[n,w]"; msg << " del " << _movimento->curr().get(MOV_DATAREG); _viswin->add_line(msg); } return no_error; } error_type TContabilizzazione::compile_head_anticipo(TDocumento& doc) { TString descr; TString16 codcaus = doc.clifor().vendite().get(CFV_CODCAUSINC); if (codcaus.blank()) codcaus = doc.tipo().caus_anticipo(); const TDate datareg = _movimento->curr().get_date(MOV_DATAREG); if (!_caus->read(codcaus,datareg.year())) return caus_ant_error; long nr = doc_contabilized(doc, true); if (nr <= 0) { if (get_next_reg_num(nr) != no_error) return nr_reg_error; } _anticipo = new TMovimentoPN; TRectype& head = _anticipo->curr(); head = _movimento->curr(); // Copia tutti i campi... head.put(MOV_NUMREG,nr); head.zero(MOV_DATA74TER); head.put(MOV_TIPODOC,_caus->tipo_doc()); head.put(MOV_CODCAUS,_caus->codice()); descr = doc.get_bool(DOC_ACCSALDO) ? "Saldo fattura" : "Acconto fattura"; descr << " n. " << doc.numero(); descr << " del " << doc.get_date(DOC_DATADOC).string(); head.put(MOV_DESCR,descr); head.put(MOV_TIPOMOV,char(_caus->tipomov()+'0')); head.zero(MOV_REG); head.zero(MOV_PROTIVA); head.zero(MOV_CODPAG); head.zero(MOV_CORRLIRE); head.zero(MOV_CORRVALUTA); TString codval = head.get(MOV_CODVALI); // real cambio = head.get_real(MOV_CAMBIOI); head.zero(MOV_CODVALI); head.zero(MOV_CAMBIOI); if (sc_enabled(datareg)) { TCurrency_documento p(doc.get_real(DOC_IMPPAGATO), doc); TCurrency_documento plit(p); p.change_to_firm_val(); if (doc.in_valuta()) { head.put(MOV_TOTDOC,plit.get_num()); head.put(MOV_TOTDOCVAL,p.get_num()); } else { head.put(MOV_TOTDOC,p.get_num()); head.zero(MOV_TOTDOCVAL); } } else { head.zero(MOV_TOTDOC); head.zero(MOV_TOTDOCVAL); } // Memorizza il movimento contabile di destinazione! doc.put(DOC_NUMANT, nr); // Scrive sulla testata dell'anticipo il numero di documento originale head.put(MOV_DPROVV, doc.get(DOC_PROVV)); head.put(MOV_DANNO, doc.get(DOC_ANNO)); head.put(MOV_DCODNUM, doc.get(DOC_CODNUM)); head.put(MOV_DNDOC, doc.get(DOC_NDOC)); return no_error; } char TContabilizzazione::sezione() const { char sezione = ' '; const char tipoc = _co_cliente.tipo(); tipo_movimento tm = (tipo_movimento)_caus->tipomov(); sezione = _caus->sezione(1); // Usa la sezione della causale if (sezione <= ' ') // Se non c'e' la sezione bell'e' ch'e' pronta { if (tm == tm_fattura || tm == tm_insoluto) // calcola in base al tipo movimento e sezione = (tipoc == 'C') ? 'D' : 'A'; // al tipo cliente/fornitore else sezione = (tipoc == 'C') ? 'A' : 'D'; } return sezione; } error_type TContabilizzazione::search_clifo_bill(const TString& catven) { _error = no_error; const TRectype& clifo = _clifo->curr(); const long codcf = clifo.get_long(CLI_CODCF); const char tipocf = clifo.get_char(CLI_TIPOCF); _co_cliente.set(0,0,0); // Reperisce il conto del cliente nel seguente ordine, appena ne trova uno valido: // - Categoria vendita // - file clienti // - causale _cve->put("CODTAB", catven); if (_cve->read() == NOERR) _co_cliente.set(_cve->get_int("I1"), _cve->get_int("I2"),codcf,tipocf); if (!_co_cliente.ok()) { _co_cliente.set(clifo.get_int(CLI_GRUPPO),clifo.get_int(CLI_CONTO),codcf,tipocf); if (!_co_cliente.ok()) // se non e' valido, reperiscilo dalla riga #1 della causale { _caus->bill(1,_co_cliente); // conto della riga 1 if (_co_cliente.tipo() != ' ') _co_cliente.codclifo() = codcf; if (!_co_cliente.ok()) _error = clifo_error; } } return _error; } error_type TContabilizzazione::search_counter_bill(TDocumento& doc, const TDate& datareg) { _error = no_error; // cerca il conto relativo alla riga di causale: // 1 Rimessa diretta o contanti (banca) riga 2 // 2 Tratta riga 3 // 3 Ricevuta bancaria riga 4 // 4 Cessione riga 5 // 5 Paghero' riga 6 // 6 Lettera di credito riga 7 // 7 Tratta accettata riga 8 // 8 Rapporti interban. diretti riga 2 // 9 Bonifici riga 2 // Se il saldaconto e' attivo prende il conto relativo al tipo pagamento // Altrimenti sempre la riga 2 if (sc_enabled(datareg)) { int tipopag = doc.pagamento().tipo_rata(0); // Quello della prima rata... prolly is right .. ;P _caus->bill(tipopag>0 && tipopag<8 ? tipopag+1:2,_co_controp); if (!_co_controp.ok()) _caus->bill(2,_co_controp); } else _caus->bill(2,_co_controp); if (!_co_controp.ok()) _error = counter_p_ant_error; return _error; } error_type TContabilizzazione::compile_rows_anticipo(TDocumento& doc) { // Per compilare le righe ci si ispira alla contabilizzazione effetti // per reperire il conto clienti si guarda prima sul record cliente // e poi al limite la riga della causale // per il conto di contropartita se non c'e' il saldaconto lo si prende dalla // seconda riga. Se il saldaconto esiste si consulta la riga relativa al // tipo di pagamento. const TString4 codpag(doc.get(DOC_CODPAG)); const TString4 catven(doc.get(DOC_CATVEN)); const TRectype& mov = _anticipo->curr(); const TDate datareg = mov.get_date(MOV_DATAREG); if (search_clifo_bill(catven) == no_error && search_counter_bill(doc, datareg) == no_error) { TCurrency_documento importo(doc.get_real(DOC_IMPPAGATO), doc); importo.change_to_firm_val(); const TString4 codes = mov.get(MOV_ANNOES); const long numreg = mov.get_long(MOV_NUMREG); TRectype& c_rec = _anticipo->cg(0); // setta i valori per la riga cliente c_rec.put(RMV_ANNOES,codes); c_rec.put(RMV_DATAREG,datareg); c_rec.put(RMV_NUMREG,numreg); c_rec.put(RMV_NUMRIG,1); c_rec.put(RMV_SEZIONE,_caus->sezione_clifo()); c_rec.put(RMV_TIPOC,_co_cliente.tipo()); c_rec.put(RMV_GRUPPO,_co_cliente.gruppo()); c_rec.put(RMV_CONTO,_co_cliente.conto()); c_rec.put(RMV_SOTTOCONTO,_co_cliente.sottoconto()); c_rec.put(RMV_GRUPPOC,_co_controp.gruppo()); c_rec.put(RMV_CONTOC,_co_controp.conto()); c_rec.put(RMV_SOTTOCONTOC,_co_controp.sottoconto()); c_rec.put(RMV_ROWTYPE,sc_enabled(datareg) ? "K" : " "); c_rec.put(RMV_IMPORTO, importo.get_num()); TRectype& co_rec = _anticipo->cg(1); // setta i valori per la riga contropartita co_rec = c_rec; // Swappa i conti ed il numero di riga co_rec.put(RMV_NUMRIG,2); co_rec.put(RMV_TIPOC,""); co_rec.put(RMV_SEZIONE,_caus->sezione_clifo() == 'A' ? 'D' : 'A'); co_rec.put(RMV_GRUPPO,_co_controp.gruppo()); co_rec.put(RMV_CONTO,_co_controp.conto()); co_rec.put(RMV_SOTTOCONTO,_co_controp.sottoconto()); co_rec.put(RMV_TIPOCC,_co_cliente.tipo()); co_rec.put(RMV_GRUPPOC,_co_cliente.gruppo()); co_rec.put(RMV_CONTOC,_co_cliente.conto()); co_rec.put(RMV_SOTTOCONTOC,_co_cliente.sottoconto()); co_rec.put(RMV_ROWTYPE,sc_enabled(datareg) ? "I" : " "); } return _error; } error_type TContabilizzazione::write_pagamento_anticipo(TDocumento& doc) { TLocalisamfile& mov = _anticipo->lfile(); const int anno = mov.get_date(MOV_DATAREG).year(); TString numpart(mov.get(MOV_NUMDOC)); // Nessun controllo se prot.iva o numdoc xche' tanto proviene dal mov precedentemente scritto TPartita * partita = new TPartita(_co_cliente,anno,numpart); partita->allinea(); TRiga_partite& riga_part = partita->new_row(); // Compila la riga di partita per il pagamento riga_part.put(PART_TIPOMOV,_caus->tipomov()); riga_part.put(PART_TIPOPAG, 1 ); // Pagamento in contanti-> tipo 1 riga_part.put(PART_NREG,mov.get_long(MOV_NUMREG)); riga_part.put(PART_NUMRIG,1); // Riferimento alla riga 1 del movimento riga_part.put(PART_DATAREG,mov.get_date(MOV_DATAREG)); riga_part.put(PART_DATADOC,mov.get_date(MOV_DATADOC)); riga_part.put(PART_DATAPAG,mov.get_date(MOV_DATADOC)); riga_part.put(PART_NUMDOC,numpart); // E' lo stesso riferimento riga_part.put(PART_SEZ,sezione()); riga_part.put(PART_CODCAUS, _caus->codice()); TCurrency_documento impval(doc.get_real(DOC_IMPPAGATO), doc); TCurrency_documento imp(impval); imp.change_to_firm_val(); real cambio = doc.get_real(DOC_CAMBIO); TString16 val(doc.get(DOC_CODVAL)); TDate datacam(doc.get_date(DOC_DATACAMBIO)); const bool valuta = val.not_empty(); riga_part.put(PART_IMPORTO,imp.get_num()); riga_part.put(PART_IMPORTOVAL,impval.get_num()); riga_part.put(PART_IMPTOTDOC,imp.get_num()); riga_part.put(PART_IMPTOTVAL,impval.get_num()); riga_part.put(PART_CODVAL,val); riga_part.put(PART_CAMBIO,cambio); riga_part.put(PART_DATACAM,doc.get_date(DOC_DATACAMBIO)); riga_part.put(PART_TIPOCF,_co_cliente.tipo()); riga_part.put(PART_SOTTOCONTO,_co_cliente.sottoconto()); riga_part.put(PART_DESCR, mov.get(MOV_DESCR)); // Compila la riga di pagamento: // reperire il numero della riga partita (nrigp) appena aggiunta int nriga = (int) TPartita::UNASSIGNED, nrigp = riga_part.get_int(PART_NRIGA); // Cerca la riga di partita con riferimento alla fattura che si sta pagando for (int r = partita->last(); r > 0; r = partita->pred(r)) { TRiga_partite& rpart = partita->riga(r); if (rpart.is_fattura()) { TString16 s1 = rpart.get(PART_NUMDOC); s1.trim(); TString16 s2 = numpart; s2.trim(); if (s1 == s2) // Bisogna tener conto dell'allineamento! { nriga = r; break; } } } if (nriga == TPartita::UNASSIGNED) { delete partita; return write_part_error; } // Scorre le scadenze di questa fattura, e ne completa il pagamento partendo // dalla rata piu' vecchia. TRiga_partite& rpp = partita->riga(nriga); real abb; real ipp = (real) (valuta ? impval.get_num() : imp.get_num()); TValuta tval(val, datacam, cambio); char old_ap, new_ap; TImporto old_abb, old_diffcam, new_abb, new_diffcam; const int nrate = rpp.rate(); const bool is_saldo_doc = doc.get_bool(DOC_ACCSALDO); char s_a; for (int i=1; i<=nrate; i++) { TRiga_scadenze& rs = rpp.rata(i); real res = rs.residuo(valuta).valore(); // Sul residuo da pagare per questa rata TRectype& riga_pagamento = partita->pagamento(nriga,i,nrigp); // Nuova riga di pagamento // Compila la riga... e scala l'importo residuo partendo dalla piu' vecchia // setta i flags di saldato/acconto // ANNO, NUMPART, NRIGA, NRATA, NRIGP dovrebbero essere gia' compilati riga_pagamento.put(PAGSCA_TIPOC,_co_cliente.tipo()); riga_pagamento.put(PAGSCA_SOTTOCONTO,_co_cliente.sottoconto()); s_a = 'S'; if (ipp <= ZERO) ipp = ZERO; if (res > ipp || i == nrate) // sull'ultima rata mette tutto il resto... { res = ipp; imp.set_num(ZERO); if (!is_saldo_doc) s_a = 'A'; } else ipp -= res; riga_pagamento.put(PAGSCA_ACCSAL, s_a); riga_pagamento.put(valuta ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO, res); if (valuta) { TCurrency_documento impval(res); impval.change_to_firm_val(); riga_pagamento.put(PAGSCA_IMPORTO, impval.get_num()); } riga_pagamento.put(PAGSCA_TIPOCC,_co_controp.tipo()); riga_pagamento.put(PAGSCA_GRUPPOC,_co_controp.gruppo()); riga_pagamento.put(PAGSCA_CONTOC,_co_controp.conto()); riga_pagamento.put(PAGSCA_SOTTOCONTC,_co_controp.sottoconto()); TRectype rp(riga_pagamento); if (is_saldo_doc) rp.put(PAGSCA_ACCSAL, 'S'); partita->modifica_pagamento(rp, tval, old_ap, old_abb, old_diffcam, new_ap, new_abb, new_diffcam, true); abb += new_abb.valore(); } // Vediamo se vi sono abbuoni, in questo caso si completa il movimento // contabile di anticipo, con la riga appropriata, di abbuoni attivi/passivi cambiamo pure la riga relativa // all'importo cliente, ovvero lo settiamo al valore totale della fattura... ;) // Dentro new_ap avremo se l'abbuono e' attivo o passivo, in new_abb avremo l'importo TBill abb_bill; if (abb != ZERO) { // Reperisce il conto di contropartita per gli abbuoni dalla causale: 9 passivi 10 attivi const int nrigc = new_ap == 'A' ? RIGA_ABBUONI_ATTIVI : RIGA_ABBUONI_PASSIVI; _caus->bill(nrigc, abb_bill); if (abb_bill.ok()) { TRectype& first_row = _anticipo->cg(0); // Riga cli/fo first_row.put(RMV_IMPORTO, rpp.get_real(PART_IMPTOTDOC)); // Aggiusta l'importo totale TRectype& abb_row = _anticipo->cg(2); // Riga abbuoni ... abb_row = first_row; abb_row.put(RMV_NUMRIG,3); abb_row.put(RMV_TIPOC,""); char ab_sez = 'D'; const char cf_sez = _caus->sezione_clifo(); if (cf_sez == 'D' && new_ap == 'P' || cf_sez == 'A' && new_ap == 'A') ab_sez = 'A'; abb_row.put(RMV_SEZIONE, ab_sez); abb_row.put(RMV_GRUPPO,abb_bill.gruppo()); abb_row.put(RMV_CONTO,abb_bill.conto()); abb_row.put(RMV_SOTTOCONTO,abb_bill.sottoconto()); abb_row.put(RMV_TIPOCC,_co_cliente.tipo()); abb_row.put(RMV_GRUPPOC,_co_cliente.gruppo()); abb_row.put(RMV_CONTOC,_co_cliente.conto()); abb_row.put(RMV_SOTTOCONTOC,_co_cliente.sottoconto()); abb_row.put(RMV_IMPORTO, abs(abb)); abb_row.put(RMV_ROWTYPE, new_ap); } else _error = cau_abb_error; } // Infine scrive sta partita... if (good() && !partita->write()) //error_box("Si e' verificato un errore scrivendo il pagamento del movimento di anticipo"); _error = write_part_error; delete partita; return _error; } error_type TContabilizzazione::write_anticipo(TDocumento& doc) { // Questo movimento viene scritto solo se e' stato versato un anticipo di pagamento // Crea 1 testata, 1 riga contabile e la relativa riga di pagamento sulla partita a cui fa riferimento // La testata e' praticamente la stessa del movimento appena scritto, tranne che per il numero di // protocollo, il numero di registrazione la descrizione, i totali in lire/valuta, // la condizione pagamento... _error = no_error; _error = compile_head_anticipo(doc); if (_error == no_error) { // Una volta compilata la testa... compila le righe... if (_anticipo) { _error = compile_rows_anticipo(doc); if (_error == no_error) { // Scrive il movimento... gestendo la rinumerazione if (sc_enabled(_anticipo->curr().get_date(MOV_DATAREG))) // ... il pagamento vero e proprio, scrivendo la partita e modificando // il movimento se vi sono abbuoni write_pagamento_anticipo(doc); TSaldo_agg saldo; int err = NOERR; if (doc_contabilized(doc, true)) { TMovimentoPN oldant; oldant.curr().put(MOV_NUMREG, doc.get(DOC_NUMANT)); if (oldant.read() == NOERR) aggiorna_saldi(saldo, oldant, false); err = _anticipo->rewrite(); } else err = _anticipo->write(); if (err != NOERR) { error_box("Errore %d scrivendo il movimento di anticipo pagamento %ld.", err, _anticipo->curr().get_long(MOV_NUMREG)); return generic_error; } aggiorna_saldi(saldo, *_anticipo, true); } delete _anticipo; _anticipo = NULL; } } return _error; } error_type TContabilizzazione::write_intra(TDocumento& doc) { const TRectype& rm = _movimento->curr(); // Controllo la liceita' della scrittura del moviemnto intra const TDate data_reg = rm.get(MOV_DATAREG); TDate data_intra = rm.get(MOV_DATACOMPI); if (data_intra < data_reg) { TIntra_frequency freq; const char tipo_intra = _caus->iva() == iva_acquisti ? 'A' : 'C'; if (freq.compare_periodo(data_intra, data_reg, tipo_intra) < 0) { _error = intra_rett_error; display_error(doc); _error = no_error; return _error; // Non posso fare movimenti ma devo fare rettifiche } } // Scrive il movimento INTRA raggruppando per NATURA+NOMENCLATURA+CONSEGNA+TRASPORTO+PAESE+PAESEORIG+PROV // Siccome NATURA, CONSEGNA, TRASPORTO e PAESE sono relativi alla testata del documento, // il raggruppamento effettivo viene fatto solo per NOMENCLATURA+PAESEORIG+PROV // NB: per i profani (come me :P) NOMENCLATURA COMBINATA e CLASSE DOGANALE sono la medesima cosa. TLocalisamfile& intra = *_intra; // Un po' di cache... TDB_cache& cchh = cache(); TRecord_array rintra(LF_RINTRA, "NUMRIG"); TAssoc_array righe; const TString4 codvali(rm.get(MOV_CODVALI)); const real cambioi = rm.get(MOV_CAMBIOI); const TRectype& por_rec = cchh.get("%POR", doc.get(DOC_CODPORTO)); const TString16 consegna(por_rec.get("S3")); // condizioni di consegna const int trasporto = por_rec.get_int("I0"); // tipo di trasporto... const char natura = doc.tipo().get("S3")[3]; // natura della transazione, valida per tutte le righe del documento const long numreg = rm.get_long(MOV_NUMREG); TString16 nomenclatura, ums, paeseorig, provincia, paese; real totale_righe, massanun, unsuppun; const real cambio = doc.cambio(); const bool is_val = doc.in_valuta(); const bool is_cessione = rm.get_char(MOV_TIPO)=='C'; const bool nota_credito = doc.tipo().nota_credito(); paese = _clifo->lfile().get(CLI_STATOPAIV); // Paese del cliente/fornitore... // Scorre le righe documento (prendendo solamente quelle relative agli articoli veri e propri) // Effettuando il raggruppamento in un comodo TAssoc_array TToken_string key; const int items = doc.physical_rows(); int numrig = 1; for (int i=1; i<=items; i++) { const TRiga_documento& rr = doc[i]; if (rr.is_articolo()) { const TRectype& rec_anamag = cchh.get(LF_ANAMAG, rr.get(RDOC_CODARTMAG)); nomenclatura = rec_anamag.get(ANAMAG_CLASSDOG); ums = cchh.get("%NOC", nomenclatura, "S5"); massanun = rec_anamag.get_real(ANAMAG_MASSANUN); // Massa KG unsuppun = rec_anamag.get_real(ANAMAG_UNSUPPUN); // Massa UMS paeseorig = !is_cessione ? rec_anamag.get(ANAMAG_PAESE) : EMPTY_STRING; // Campo solo per Acquisti if (is_cessione) provincia = rec_anamag.get(ANAMAG_PROV); else { const TString8 codmag = rr.get(RDOC_CODMAG); TString4 com = cchh.get("MAG", codmag, "S5"); // Comune del magazzino if (com.empty()) { const long codditta = prefix().get_codditta(); TString8 codulc; codulc.format("%ld|1", codditta); const TRectype& unloc = cchh.get(LF_UNLOC, codulc); com = unloc.get(ULC_COMULC); } key.format(" |%s", (const char*)com); provincia = cchh.get(LF_COMUNI, key, COM_PROVCOM); } if (nomenclatura.blank() || unsuppun.is_zero() || massanun.is_zero() || provincia.blank()) { TString msg; msg << "--- L'articolo " << rec_anamag.get(ANAMAG_CODART) << " non riporta tutti i dati necessari per il movimento intracomunitario."; _viswin->add_line(msg); msg = " Si consiglia di verificare i seguenti valori sull'anagrafica:"; _viswin->add_line(msg); msg = " "; if (nomenclatura.blank()) msg << "nomenclatura combinata; "; if (unsuppun.is_zero()) msg << "unità di misura supplementare; "; if (massanun.is_zero()) msg << "massa netta unitaria; "; if (provincia.blank()) msg << (is_cessione ? "provincia d'origine; " : "provincia di destinazione; "); msg.rtrim(2); msg << '.'; // Sostituisce l'ultimo punto e virgola con un punto _viswin->add_line(msg); } key.cut(0); key.add(nomenclatura); key.add(paeseorig); key.add(provincia); TRectype* rc = (TRectype*) righe.objptr(key); if (rc == NULL) { rc = new TRectype(LF_RINTRA); rc->put("NUMREG", numreg); rc->put("NUMRIG", numrig++); rc->put("NATURA", natura); rc->put("CONSEGNA", consegna); rc->put("TRASPORTO", trasporto); rc->put("UMS", ums); rc->put("NOMENCL", nomenclatura); rc->put("PAESE", paese); rc->put("PAESEORIG", paeseorig); rc->put("PROV", provincia); righe.add(key, rc); } const real qta = rr.get_real(RDOC_QTA); TCurrency_documento imp_val(rr.exist("VALINTRA") ? rr.get_real("VALINTRA") : rr.importo(true, false), doc); TCurrency_documento imp(imp_val); imp.change_to_firm_val(); imp_val.change_value(codvali, cambioi); real ammlire = rc->get_real("AMMLIRE"); real ammvaluta = rc->get_real("AMMVALUTA"); real massakg = rc->get_real("MASSAKG"); real massaums = rc->get_real("MASSAUMS"); real valstat = rc->get_real("VALSTAT"); if (nota_credito) { ammlire -= imp.get_num(); ammvaluta -= is_val ? imp_val.get_num() : ZERO; } else { ammlire += imp.get_num(); ammvaluta += is_val ? imp_val.get_num() : ZERO; } massakg += qta * massanun; massaums += qta * unsuppun; if (rr.exist("VALSTAT")) { TCurrency_documento vstat(rr.get_real("VALSTAT"), doc); vstat.change_to_firm_val(); if (nota_credito) valstat -= vstat.get_num(); else valstat += vstat.get_num(); } else { if (nota_credito) valstat -= qta * rec_anamag.get_real(ANAMAG_VALSTATUN); else valstat += qta * rec_anamag.get_real(ANAMAG_VALSTATUN); } rc->put("AMMLIRE", ammlire); rc->put("AMMVALUTA", ammvaluta); rc->put("MASSAKG", massakg); rc->put("MASSAUMS", massaums); rc->put("VALSTAT", valstat); if (nota_credito) totale_righe -= imp.get_num(); // Il totale delle righe in Euro! else totale_righe += imp.get_num(); // Il totale delle righe in Euro! } } if (_error == no_error) { // Copia il contenuto dell'assoc nel record array TRectype* rc = new TRectype(LF_RINTRA); rc->put("NUMREG", numreg); rintra.set_key(rc); for(rc = (TRectype*) righe.first_item(); rc != NULL; rc = (TRectype*) righe.succ_item()) rintra.add_row(*rc); // Devo aggiungere una copia della riga dell'assoc array! // Testa (de coccio...) intra.zero(); intra.put("NUMREG", numreg); intra.put("DATAREG", rm.get_date(MOV_DATAREG)); intra.put("TIPOMOV", is_cessione ? 'C' : 'A'); // 'C' cessione 'A' acquisto intra.put("TIPOCF", rm.get(MOV_TIPO)); intra.put("CODCF", rm.get_long(MOV_CODCF)); intra.put("TOTDOC", totale_righe); // intra.put("TOTDOC", rm.get_real(MOV_TOTDOC)); intra.put("TOTDOCIMM", totale_righe); if (_caus->valintra() && codvali.empty()) { TString4 codval(TCurrency::get_firm_val()); if (codval.empty()) codval = TCurrency::get_euro_val(); intra.put("CODVAL", codval); } else intra.put("CODVAL", codvali); intra.put("CAMBIO", cambioi); if (intra.write() == _isreinsert) // Succede con le ricontabilizzazioni intra.rewrite(); // si effettua una riscrittura if (intra.status() == NOERR) { // righe! if (rintra.write(true) != NOERR) // Forza la riscrittura se necessario _error = intra_mov_error; } else _error = intra_mov_error; } return _error; } error_type TContabilizzazione::write_anal(TDocumento& doc, const TMovimentoPN& movimento) { // Controlla flag sulla causale if (!_caus->link_analitica()) return _error; TConfig& cfg = ca_config(); const TDate data_att = cfg.get("DtAttCa"); if (data_att.ok()) { const TDate data_cmp = movimento.curr().get(MOV_DATACOMP); if (data_cmp < data_att) // La data di competenza precede la data di attivazione analitica return _error; } bool has_anal_bill = false; for (int i = movimento.cg_items(); i > 0; i--) { const TRectype& cgrow = movimento.cg_rows().row(i); const TBill bill(cgrow); if (bill.is_analitico()) { has_anal_bill = true; break; } } if (has_anal_bill) { TContabilizzazione_analitica canal(*this); const long numreg_cg = movimento.curr().get_long(MOV_NUMREG); TAnal_mov mov; canal.elabora(doc, numreg_cg, _viswin, _can_write, mov); } return _error; } TRecnotype TContabilizzazione::kill_righe_percip(TIsam_handle logic, char tipopercip, long codpercip, long nprog) const { CHECKD(logic == LF_RVER || logic == LF_RPAG, "Invalid file number ", logic); CHECKD(nprog > 0, "Invalid NPROGR ", nprog); TRelation rel(logic); TRectype& riga = rel.curr(); riga.put(VER_CODDITTA, prefix().firm().codice()); riga.put(VER_TIPOA, tipopercip); riga.put(VER_CODANAGR, codpercip); riga.put(VER_NPROG, nprog); TCursor cur(&rel, "", 1, &riga, &riga); const TRecnotype tot = cur.items(); if (tot > 0) { cur.freeze(); for (cur = 0L; cur.pos() < tot; ++cur) cur.file().remove(); } return tot; } error_type TContabilizzazione::write_percip(TDocumento& doc, const TMovimentoPN& movimento) { const char tipopercip = doc.clifor().get_char(CLI_TIPOAPER); const long codpercip = doc.clifor().get_long(CLI_CODANAGPER); if (codpercip > 0L) { TBit_array to_delete; TArray schede; TLocalisamfile schperc(LF_SCPERC); TLocalisamfile perc(LF_PERC); const long numreg = movimento.curr().get_long(MOV_NUMREG); int numsch = 0; schperc.setkey(3); schperc.put(SCH_CODDITTA, prefix().firm().codice()); schperc.put(SCH_NUMREG, numreg); TRectype schcmp(schperc.curr()); int err; for (err = schperc.read(_isgteq); err == NOERR && schperc.curr() == schcmp; err = schperc.next()) { schede.add(schperc.curr()); to_delete.set(numsch++); } bool changed_percip = (numsch == 0) || (tipopercip != ((TRectype &) schede[0]).get_char(SCH_TIPOA)) || (codpercip != ((TRectype &) schede[0]).get_long(SCH_CODANAGR)); int newprog = 0L; const int orig_numsch = numsch; const int doc_rows = doc.physical_rows(); int i = 1; schperc.setkey(1); schperc.zero(); schperc.put(SCH_CODDITTA, prefix().firm().codice()); schperc.put(SCH_TIPOA, tipopercip); schperc.put(SCH_CODANAGR, codpercip); schcmp = schperc.curr(); schperc.put(SCH_NPROG, 9999); if (schperc.read(_isgteq) == NOERR) schperc.prev(); if (schperc.curr() == schcmp) newprog = schperc.get_int(SCH_NPROG); newprog++; for (i = 1; i <= doc_rows; i++) { const TRiga_documento & row = doc[i]; if (row.is_spese()) { const TSpesa_prest & sp = row.spesa(); if (sp.tipo_ritenuta() == 'F') { const int caus_770 = sp.caus_770(); if (caus_770 > 0) { TString val ; bool found = false; int j = 0; int recpos = -1; val.format("%02d", caus_770); if (!changed_percip) for (j = 0; recpos < 0 && j < numsch; j++) { TRectype & rec = (TRectype &) schede[j]; if (val == rec.get(SCH_CODCAUS)) recpos = j; } TRectype * schrow = NULL; bool reset_row = false; if (recpos >= 0) schrow = (TRectype *) schede.objptr(recpos); else { schrow = new TRectype(LF_SCPERC); schrow->put(SCH_CODDITTA, prefix().firm().codice()); schrow->put(SCH_TIPOA, tipopercip); schrow->put(SCH_CODANAGR, codpercip); schrow->put(SCH_NPROG, newprog++); schrow->put(SCH_NUMREG, numreg); schede.add(schrow); recpos = numsch++; } const TRectype & rec_caus = cache().get("%CA7", val); schrow->put(SCH_CODCAUS, val); const TDate datarif = doc.get_date(DOC_DATADOCRIF); schrow->put(SCH_DATADOC, datarif); const TString & docnum = doc.get(DOC_NUMDOCRIF); schrow->put(SCH_NUMDOC, docnum); const real ritenuta = doc.ritenute('F'); const real spese = doc.get_real("SP770"); schrow->put(SCH_COMPENSO, doc.imponibile() - spese); schrow->put(SCH_SPESE, spese); schrow->put(SCH_IVA, doc.imposta()); schrow->put(SCH_TOTALE, doc.totale_doc()); schrow->put(SCH_TOTRIT, ritenuta); schrow->put(SCH_RITSOC, doc.ritenute('S')); const TDate datadoc = doc.get_date(DOC_DATADOC); schrow->put(SCH_MESEC, datadoc.month()); schrow->put(SCH_ANNOC, datadoc.year()); schrow->put(SCH_CAUSQUA, rec_caus.get("S1")); schrow->put(SCH_FLAGTS, rec_caus.get("S4")); // i pagamenti non sono gestiti qui per ora to_delete.reset(recpos); } } } } err = NOERR; for (i = 0; err == NOERR && i < numsch; i++) { TRectype& rec = (TRectype&)schede[i]; const char tipo = rec.get_char(SCH_TIPOA); const long codanagr = rec.get_long(SCH_CODANAGR); if (to_delete[i]) { TToken_string msg(256, '.'); const int nprog = rec.get_int(SCH_NPROG); err = rec.remove(schperc); if (kill_righe_percip(LF_RVER, tipo, codanagr, nprog)) msg.format("Sono state eliminate le righe di versamento relative alla scheda %c/%ld/%d." "Dovranno quindi essere ripristinate dell'utente.", tipo, codanagr, nprog); if (kill_righe_percip(LF_RPAG, tipo, codanagr, nprog)) { TString m(128); m.format("Sono state eliminate le righe di pagamento relative alla scheda %c/%ld/%d." "Dovranno quindi essere ripristinate dell'utente.", tipo, codanagr, nprog); msg.add(m); } if (msg.full()) { if (_viswin) { TString riga; FOR_EACH_TOKEN(msg, line) if (*line) { riga = riga.empty() ? "*** " : " "; riga << line << '.'; _viswin->add_line(riga); } } else warning_box(msg); } } else if (i < orig_numsch) { err = rec.rewrite(schperc); if (err == _iskeynotfound) err = rec.write(schperc); } else { err = rec.write(schperc); while (err == _isreinsert) { int newprog = rec.get_int(SCH_NPROG) + 1; rec.put(SCH_NPROG, newprog); err = rec.rewrite(schperc); } } perc.zero(); perc.put(PRC_CODDITTA, prefix().firm().codice()); perc.put(PRC_TIPOA, tipo); perc.put(PRC_CODANAGR, codanagr); perc.write(); } if (err != NOERR) _error = m770_write_error; } return _error; } void TContabilizzazione::aggiorna_saldi(TSaldo_agg& saldo, TMovimentoPN& mv, bool save) { const TRectype& mov = mv.curr(); const TDate datareg = mov.get_date(MOV_DATAREG); const TString16 codcaus = mov.get(MOV_CODCAUS); tiposal tsal = normale; if (codcaus != _caus->codice()) // Should never happen, but ... { const TCausale caus(codcaus, datareg.year()); tsal = caus.apertura() ? apertura : (caus.chiusura() ? chiusura : normale); } else tsal = _caus->apertura() ? apertura : (_caus->chiusura() ? chiusura : normale); // if (save) saldo.reset(); // Bella ca%%ata: distrugge i saldi del vecchio movimento! saldo.set_movprovv(false); saldo.set_tipo_saldo(tsal); saldo.set_anno_es(mov.get_int(MOV_ANNOES)); saldo.set_num_ulmov(mov.get_long(MOV_NUMREG)); saldo.set_data_ulmov(datareg); saldo.set_movimentato(true); const int cgitems = mv.cg_items(); for (int i = 0; i < cgitems; i++) { const TRectype& r = mv.cg(i); const TBill conto(r); TImporto import(r.get_char(RMV_SEZIONE), r.get_real(RMV_IMPORTO)); saldo.aggiorna(conto, import, save); } if (save) saldo.registra(); } void TContabilizzazione::display_error(TDocumento& doc) { TToken_string msg(256, '.'); const TString4 numerazione = doc.numerazione(); const long numero = doc.numero(); const TString4 causale = _caus == NULL ? "" : _caus->codice(); switch (_error) { case nr_es_error: msg.format("Rilevato un codice esercizio errato contabilizzando il documento %s/%ld." "Verificare l'esistenza e la correttezza della tabella esercizi e della data del documento.",(const char*)numerazione,numero); break; case nr_reg_error: msg.format("Rilevato un numero di registrazione errato contabilizzando il documento %s/%ld." "Verificare l'integrita' del file movimenti.",(const char*)numerazione,numero); break; case nr_doc_error: msg.format("Rilevato un numero di documento errato contabilizzando il documento %s/%ld." "Verificare il numero documento e il codice numerazione inseriti in tabella.",(const char*)numerazione,numero); break; case chg_stat_error: msg.format("Rilevato un errore cambiando lo stato al documento %s/%ld." "Verificare l'integrita' del file documenti.",(const char*)numerazione,numero); break; case clifo_error: msg.format("Rilevato un errore caricando le informazioni del Cli/Fo sul documento %s/%ld." "Verificare l'esistenza delle informazioni inserite sul file documenti e Cli/Fo.",(const char*)numerazione,numero); break; case ultprot_error: msg.format("Rilevato un numero di protocollo IVA errato relativamente al documento %s/%ld." "Verificare le informazioni inserite sul registro %s/%d.",(const char*)numerazione,numero, (const char*) _caus->reg().name(),_caus->reg().year()); break; case datadoc_error: msg.format("Rilevato una data documento vuota relativamente al documento %s/%ld." "Verificare l'informazione inserita.",(const char*)numerazione,numero); break; case caus_ant_error: msg.format("Rilevato un errore caricando la causale per anticipo pagamento relativamente al documento %s/%ld." "Verificare l'esistenza del codice causale '%s'.",(const char*)numerazione,numero,(const char*)causale); break; case counter_p_ant_error: msg.format("Rilevato un errore cercando il conto di contropartita per il movimento di anticipo relativamente al documento %s/%ld." "Verificare l'esistenza e la correttezza della causale '%s'.",(const char*)numerazione,numero,(const char*)causale); break; case caus_error: msg.format("Rilevato un errore caricando la causale relativamente al documento %s/%ld." "Verificare l'esistenza del codice causale '%s' e del relativo registro.", (const char*)numerazione,numero,(const char*)causale); break; case causre_error: msg.format("Rilevato un errore caricando la causale relativamente al documento %s/%ld." "Non deve essere una causale IVA", (const char*)numerazione,numero,(const char*)causale); break; case cauval_error: msg.format("Il documento %s/%ld risulta essere in valuta mentre la causale non la supporta." "Verificare la correttezza della causale '%s'.",(const char*)numerazione,numero,(const char*)causale); break; case ivasto_error: msg.format("Impossibile determinare il codice IVA di storno per articoli omaggio relativamente al documento %s/%ld riga %d." "Verificare la configurazione contabilizzazione.",(const char*)numerazione,numero, _nrow); break; case register_error: msg.format("Rilevato un errore caricando il registro relativamente al documento %s/%ld." "Verificare la correttezza della causale '%s' e relativo registro.",(const char*)numerazione,numero,(const char*)causale); break; case change_error: msg.format("Rilevato un cambio senza valuta relativamente al documento %s/%ld." "Verificare la correttezza delle informazioni inserite.",(const char*)numerazione,numero); break; case val_error: msg.format("Rilevato un codice valuta inesistente relativamente al documento %s/%ld." "Verificare la correttezza della informazione inserita.",(const char*)numerazione,numero); break; case codpag_error: msg.format("Rilevato un codice pagamento non esistente relativamente al documento %s/%ld." "Verificare l'esistenza del codice pagamento inserito.",(const char*)numerazione,numero); break; case row_type_error: msg.format("Rilevato un codice tipo riga non esistente relativamente al documento %s/%ld riga %d." "Verificare l'esistenza dei vari codici riga inseriti.",(const char*)numerazione, numero, _nrow); break; case no_rows_error: msg.format("Nessuna riga iva contabile e' stata trovata relativamente al documento %s/%ld." "Verificare l'esistenza dei vari codici riga inseriti.",(const char*)numerazione,numero); break; case cau_ritintra_error: msg.format("Conto per il'IVA intracomunitaria errato o mancante." "Verificarlo sulla causale alla voce ritenute fiscali.\n"); break; case contocf_error: msg.format("Rilevato un conto di cliente/fornitore/cassa inesistente relativamente al documento %s/%ld." "Verificare l'esistenza del conto %c %d %d %ld.", (const char*)numerazione,numero, _conto_errato.tipo(), _conto_errato.gruppo(), _conto_errato.conto(), _conto_errato.sottoconto()); break; case conto_error: if (_nrow < 0) msg.format("Rilevato un conto cliente/fornitore relativamente al documento %s/%ld." "Verificare l'esistenza del conto %c %d %d %ld associato alle righe.", (const char*)numerazione,numero, _conto_errato.tipo(), _conto_errato.gruppo(), _conto_errato.conto(), _conto_errato.sottoconto()); else msg.format("Rilevato un conto di costo/ricavo inesistente relativamente al documento %s/%ld riga %d." "Verificare l'esistenza del conto %c %d %d %ld associato alle righe.", (const char*)numerazione,numero, _nrow, _conto_errato.tipo(), _conto_errato.gruppo(), _conto_errato.conto(), _conto_errato.sottoconto()); break; case sconto_error: msg.format("Non sono stati impostati i conti per la contabilizzazione degli sconti relativamente al documento %s/%ld." "Verificare i parametri in configurazione contabilizzazione.",(const char*)numerazione,numero); break; case spinbo_error: msg.format("Non sono stati impostati i conti per la contabilizzazione delle spese incasso e bolli relativamente al documento %s/%ld." "Verificare i parametri in configurazione contabilizzazione.",(const char*)numerazione,numero); break; case movement_error: msg.format("Rilevato uno sbilancio nel movimento relativamente al documento %s/%ld." "Verificare la correttezza degli importi delle righe.",(const char*)numerazione,numero); break; case write_error: msg.format("Rilevato un errore in scrittura movimento relativamente al documento %s/%ld." "Verificare la consistenza dei files.",(const char*)numerazione,numero); break; case write_part_error: msg.format("Rilevato un errore in scrittura partite relativamente al documento %s/%ld." "Verificare la consistenza dei files.",(const char*)numerazione,numero); break; case cau_abb_error: msg.format("Mancano i conti per gli abbuoni nella causale indicata per il pagamento anticipo relativamente al documento %s/%ld." "Verificare la correttezza della causale.",(const char*)numerazione,numero); break; case intra_mov_error: msg.format("Si è verificato un errore nella scrittura del movimento intracomunitario relativamente al documento %s/%ld." "Verificare la consistenza dei files relativi ai movimenti intracomunitari.",(const char*)numerazione,numero); break; case intra_rett_error: msg.format("La data di competenza INTRA del movimento intracomunitario relativo al documento %s/%ld" "appartiene ad un periodo il cui riepilogo deve essere rettificato manualmente",(const char*)numerazione,numero); break; case cont_seq_error: msg.format("Il documento precedente al %s/%ld non e' stato contabilizzato." "E' necessario contabilizzare tutti i documenti in sequenza.", (const char*)numerazione, numero); break; case m770_write_error: msg.format("Errore in scrittura della scheda percipiente relativa\nal documento %s/%ld.", (const char*)numerazione, numero); break; default: // errori generici o non indicati vengono visualizzati nel punto dell'errore //msg.format("E' stato rilevato un errore generico contabilizzando il documento %s/%ld.", // (const char*)numerazione,numero); break; } if (_viswin) { TString riga; FOR_EACH_TOKEN(msg, line) { if (*line) { riga = riga.empty() ? "*** " : " "; riga << line << '.'; _viswin->add_line(riga); } } } else error_box(msg); _error = no_error; // reset error, as any other one would do, so you can show me the other ones. _nrow = 0; _can_write = false; // But from now on u cannot write anymore. U must exit this program and repair errors occurred. } bool TContabilizzazione::sc_enabled(const TDate& data) const { bool rt = _sc_enabled; if (_caus != NULL) rt &= _caus->saldaconto(data); if (_clifo != NULL) rt &= !_clifo->curr().get_bool(CLI_OCCAS); // Saldaconto solo se C/F non occasionale return rt; } bool TContabilizzazione::in_enabled() const { bool rt = _in_enabled; if (_caus != NULL) rt &= _caus->intra(); return rt; } bool TContabilizzazione::prev_contabilized(const TDocumento& doc) const { const TString4 codnum = doc.get(DOC_CODNUM); const int anno = doc.get_int(DOC_ANNO); const char provv = doc.get_char(DOC_PROVV); long ndoc = doc.get_long(DOC_NDOC); TLocalisamfile documenti(LF_DOC); TRectype& rec = documenti.curr(); rec.put(DOC_CODNUM, codnum); rec.put(DOC_ANNO, anno); rec.put(DOC_PROVV, provv); rec.put(DOC_NDOC, ndoc-1); int err = rec.read(documenti); if (err != NOERR) { rec.zero(); rec.put(DOC_CODNUM, codnum); rec.put(DOC_ANNO, anno); rec.put(DOC_PROVV, provv); err = rec.read(documenti, _isgteq); return err == NOERR && rec.same_key(doc.head(), 1); } const TString4 stato_doc = rec.get(DOC_STATO); const TString4 stato_ok = stato_finale_doc_iniziale(); return stato_doc >= stato_ok; } static bool link_handler(int n, const char* nreg) { switch (n) { case 0: { TRectype mov(LF_MOV); mov.put(MOV_NUMREG, nreg); return mov.edit(); } break; case 1: { TRectype mov(LF_MOVANA); mov.put(MOVANA_NUMREG, nreg); return mov.edit(); } break; default: break; } return false; } bool TContabilizzazione::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab, bool interattivo) { TString msg; _error = no_error; _nrow = 0; _total_docs = 0L; _caus = NULL; _data_reg = data_elab; if (interattivo) { _auto_data = true; _nump_iva = 1; } esercizi().update(); _cpg->setkey(1); // Setta per sicurezza la chiave 1 nel caso l'elaborazione sia invocata da VE0 if (!load_parameters()) // Carica i parametri dalla configurazione return false; TPrinter& p = printer(); p.links().add("Movimento Prima Nota |b|w", 0); p.links().add("Movimento Analitico |r|w", 1); p.setlinkhandler(link_handler); pre_process_input(doc_in); _viswin = new TViswin(NULL, TR("Contabilizzazione documenti"), false, true, true); if (!exporting()) _viswin->open_modal(); const clock_t start_time = clock(); long txt_scrolled = -1; const int items = doc_in.items(); // Numero dei documenti in questa elaborazione if (items > 0) { const bool acquisto = doc_in[0].get_char(DOC_TIPOCF) == 'F'; if (acquisto) _check_prev_cont = false; } for (int i = 0; i < items; i++) // Scorriamo tutti i documenti nella lista { if (_viswin->frozen()) break; const long txt_pos = _viswin->lines(); TDocumento& doc = doc_in[i]; msg = TR("Elaborazione del documento"); msg << ' ' << doc.anno() << ' '; msg << doc.numerazione() << '/'; msg << doc.numero(); _viswin->add_line(msg); if (i > 0) { const clock_t time = (clock() - start_time) / CLOCKS_PER_SEC; if (time > 0) { TString80 stats; const int min = int(time / 60L); const int sec = int(time % 60L); stats.format(" (docs=%d time=%d:%02d docs/min=%ld)", i, min, sec, long(i*60L)/time); msg << stats; } } xvtil_statbar_set(msg); do_events(); _movimento = new TMovimentoPN_VE(doc.in_valuta()); if (_can_write && _check_prev_cont && !prev_contabilized(doc)) _error = cont_seq_error; const TCodice_numerazione num(doc.numerazione()); const bool ft_em_ric = num.fattura_emettere_ricevere(); if (good()) { if (ft_em_ric) { compile_head_mov_re(doc); if (good()) compile_rows_mov_re(doc); if (good() && _can_write) write_all_re(doc, *_movimento); // Se la scrittura e' andata ok... } else { compile_head_mov(doc); if (good()) compile_rows_mov(doc); if (good() && _can_write) write_all(doc, *_movimento); // Se la scrittura e' andata ok... } } if (!good()) { display_error(doc); if (_error == movement_error || !_movimento->movement_ok()) { TToken_string str(32, ' '); msg.format(FR("%24s %24s Conto"), TR("Dare"), TR("Avere")); _viswin->add_line(msg); const int imax = _movimento->cg_items(); for (int i = 0; i < imax; i++) { const TRectype& r = _movimento->cg(i); const char sez = r.get_char(RMV_SEZIONE); const TCurrency imp(r.get_real(RMV_IMPORTO)); if (sez == 'D') msg.format("%24s %24s", imp.string(true), ""); else msg.format("%24s %24s", "", imp.string(true)); TBill bill(r); str.cut(0); bill.add_to(str, 0, 0x2); msg << ' ' << str; _viswin->add_line(msg); } } if (txt_scrolled < 0) { txt_scrolled = txt_pos; _viswin->goto_pos(txt_pos, 0); do_events(); } } _viswin->add_line(""); if (_caus != NULL) { delete _caus; _caus = NULL; } export_movimento(*_movimento, *_viswin); delete _movimento; _movimento = NULL; // Let's free some valuable space if (!interattivo) doc_in.destroy(i, false); } _viswin->close_print(); if (!exporting()) _viswin->close_modal(); if (!interattivo) { if (_viswin->frozen()) warning_box(TR("Contabilizzazione interrotta dall'utente")); else message_box(TR("Contabilizzazione terminata")); } if (!exporting()) { KEY k = _viswin->run(); if (k == K_CTRL+'S') // Ho premuto Stampa printer().print_txt(_viswin->text()); } delete _viswin; _viswin = NULL; post_process_input(doc_in); post_process(doc_out, doc_in); return _can_write; // Se non ha riscontrato errori per nessun documento, _can_write = true } bool TContabilizzazione::call_exe(const TDocumento& doc, const TMovimentoPN& movimento) const { TFilename ae = applicazione_esterna(); if (ae.empty() || ae == "TC") // TC = Trasferimento a Contabilita residuato da AS400 return false; TFilename ininame; ininame.temp(); { TConfig ini(ininame, "Transaction"); ini.set("Action", "Contabilize"); TString8 para; para.format("%d", LF_DOC); ini.set_paragraph(para); ini.set(DOC_PROVV, doc.get(DOC_PROVV)); ini.set(DOC_ANNO, doc.get(DOC_ANNO)); ini.set(DOC_CODNUM, doc.get(DOC_CODNUM)); ini.set(DOC_NDOC, doc.get(DOC_NDOC)); para.format("%d", LF_MOV); ini.set_paragraph(para); ini.set(MOV_NUMREG, movimento.curr().get(MOV_NUMREG)); } ae << " /i" << ininame; TExternal_app app(ae); const bool ok = app.run() == 0; if (ininame.exist()) ::remove(ininame); return ok; }