#include #include #include #include #include // cache() #include // TISAM_recordset #include #include #include // TExternal_app #include // dongle() #include "cglib03.h" #include "tf0.h" #include "tf0200a.h" #define CAMPI_CON_BOOLEAN F_TOTOPATT #define REG_ATT 1 #define REG_PAS 2 // ComLiqPerIva: Comunicazione Liquidazioni Periodiche IVA /** Utilities **/ // Ritorna un cursore di tab.PRM const TCursor getPRM(int anno) { static TRelation rprm(LF_TAB); TRectype from(rprm.curr()); from.put("COD", "PRM");from.put("CODTAB", anno); TRectype to(rprm.curr()); to.put("COD" , "PRM");to.put("CODTAB", anno); TCursor cprm(&rprm, "", 1, &from, &to); return cprm; } const TRectype getLIM(int anno, int mese) { TString key; key << anno; if(mese < 10) key << "0"; key << mese; return cache().get("LIM", key); } // Ritorna il record richiesto di tabcom.LIA const TRectype getLIA(int anno) { TString key; key << format("%05d", prefix().firm().codice()) << anno; // %05d Crea un numero di 5 cifre partendo dal codice e mettendoci 0 davanti return cache().get("%LIA", key); } // Ritorna il record richiesto di tabcom.LIM const TRectype getLAM(int anno, int mese) { TString key; key << anno; if(mese < 10) key << "0"; key << mese; return cache().get("LAM", key); } // Ritorna il record valido richiesto di tabcom.VER const TRectype getVER(int anno, int mese) { // Questa tabella ha come chiave l'inizio validità, creo un cursore e scorro finche non trovo l'ultimo periodo valido static TRelation rver(LF_TABCOM); static TRectype from(rver.curr()); from.put("COD", "VER"); static TRectype to(rver.curr()); to.put("COD" , "VER"); static TCursor cver(&rver, "", 1, &from, &to); // Costruisco il controllo sulla chiave TString key; key << anno; if(mese < 10) key << "0" << mese; else key << mese; TRectype rowRet(LF_TABCOM); for(cver = 0; cver.pos() < cver.items(); ++cver) { TRectype rowVer = cver.curr(); if(rowVer.get("CODTAB") < key) { rowRet = rowVer; } else break; } return rowRet; } /* Scopiazzata e divisa in due da cg4304.cpp * Calcola solo le imposte, aggiunto controllo indetraibilità, non devono essere presi in considerazione * i movimenti se indetraibili */ int calc_inc_diff(int anno, int mese, int tipoiva, real& imposta_diff, real& imposta_xcas) { CHECKD(tipoiva == 1 || tipoiva == 2, "Bad tipo iva:", tipoiva); int flag = 0; imposta_diff = imposta_xcas = ZERO; TString limit; limit << "ANNOLIQ=" << anno; if (mese < 13) limit << " MESELIQ=" << mese; TString query; // righe pagamento (TIPOMOV>=3) ed escluse NC! query << "USE IVADIFF KEY 2 SELECT (TIPOMOV>2)&&(TIPOIVA=" << tipoiva << ")" << "\nFROM " << limit << "\nTO " << limit; TISAM_recordset id(query); const TRectype& rec = id.cursor()->curr(); for (bool ok = id.move_first(); ok; ok = id.move_next()) { const real iva = rec.get_real(RMI_IMPOSTA); if (!iva.is_zero() && !rec.get_bool("INDETR")) { const int tipodiff = rec.get_int("TIPODIFF"); switch (tipodiff) { case 1: imposta_diff += iva; break; case 2: imposta_xcas += iva; break; default: break; } flag |= tipodiff; } } if (tipoiva == 2 && !rec.get_bool("INDETR")) { real perc_prorata; query = "USE PLM"; query << "\nFROM CODTAB=" << anno << "\nTO CODTAB=" << anno; TISAM_recordset ip(query); const TRectype& recp = ip.cursor()->curr(); for (bool ok = ip.move_first(); ok && perc_prorata == ZERO; ok = ip.move_next()) { int m = atoi(ip.get("CODTAB").as_string().mid(10)); real p = ip.get("R12").as_real(); if (m == mese && p != ZERO) perc_prorata = p; } if (perc_prorata > ZERO) { real ind = imposta_diff * perc_prorata / CENTO; ind.round(TCurrency::get_firm_dec()); imposta_diff -= ind; ind = imposta_xcas * perc_prorata / CENTO; ind.round(TCurrency::get_firm_dec()); imposta_xcas -= ind; } } return flag; } /* Funzione per determinare il credito dell'anno precedente delle dichiarazioni precedenti */ void calcolaCreditoPrec(real& creprec, real& creaprec, bool mensile, int anno, int mese) { // Credito anno precedente /* Per calcolare il credito dell'anno precedente inizio a leggere i record precedenti su IVALIQ * fino a quando ne trovo uno >= 0. */ TRectype rowLia = getLIA(anno); if(mensile || (!mensile && ((mese - 1) % 3) == 0)) { TRelation ivaLiq(LF_IVALIQ); TRectype from(ivaLiq.curr()); from.put("ANNO", anno); from.put("MESE", 1); // Fino al mese precedente TRectype to(ivaLiq.curr()); to.put("ANNO", anno); to.put("MESE", mese - 1); TCursor curLiq(&ivaLiq, "GENERATA!=\"G\"", 1, &from, &to); bool trovato = false; for(curLiq = 0; curLiq.pos() < curLiq.items(); ++curLiq) { TRectype rowLiq = curLiq.curr(); if(rowLiq.get_int("MESE") >= mese) break; // Perchè li prende lo stesso? trovato = trovato || rowLiq.get_real("CREAPREC") > ZERO; creprec = rowLiq.get_real("IVAVERC"); } /* Se non ho trovato nessun valore positivo (i negativi senza nessun positivo prima non sono validi) * vado a leggere la liquidazione di quest'anno */ if(!trovato) { creaprec = rowLia.get_real("R0"); } } } class ComLiqPerIva_mask : public TAutomask { protected: bool mensile; // Aggiunta questa variabile per specificare se è stato impostato un tipo di liquidazione. // In Release sembra che durante la ricerca salta l'inizializzazione e imposta prima gli altri campi bool initLiq; TRectype trueData; virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); void extractinator(); void checkOldValue(int field, real val); public: ComLiqPerIva_mask() : TAutomask("tf0200a"), trueData(LF_IVALIQ), initLiq(false) { first_focus(F_ANNO); } void saveGen(); }; bool ComLiqPerIva_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_ANNO: if(e == fe_modify) { TString cod = get(F_CODDITTA); cod << get_int(F_ANNO); if(cache().get("%LIA", cod).empty()) { warning_box("Attenzione anno di liquidazione non presente"); set(F_ANNO, ""); break; } if(cache().get("%LIA", cod, "S7") == "M") { mensile = true; initLiq = true; enable(F_MESE); disable(F_TRIMESTRE); } else { mensile = false; initLiq = true; disable(F_MESE); enable(F_TRIMESTRE); } } break; case F_MESE: if(e == fe_modify && mensile && initLiq) set(F_TRIMESTRE, (get_int(F_MESE) - 1) / 3 + 1); break; case F_TRIMESTRE: if(e == fe_init && !query_mode()) disable(F_TRIMESTRE); if(e == fe_modify && !mensile && initLiq && query_mode()) { set(F_MESE, get_int(F_TRIMESTRE) * 3); disable(F_TRIMESTRE); send_key(K_TAB, F_ANNO); } break; case DLG_CANCEL: enable(F_TRIMESTRE); break; case DLG_RECALC: // Vado a prendere i dati di quel mese dalla liquidazione IVA if(e == fe_button) { // Controllo che non ci sia già if(!cache().get(LF_IVALIQ, TString(get(F_ANNO)) << "|" << get(F_MESE) << "|U").empty()) { if(!yesno_box("Sono già stati elaborati questi dati, si desidera ricalcolarli?")) break; } extractinator(); } break; case DLG_EMAIL: { if(e == fe_button) { // Richiamo il programma di invio TExternal_app invioApp("tf0 -4"); invioApp.run(); } } break; case DLG_SAVEREC: if(e != fe_init && !trueData.empty()) trueData.write_rewrite(TLocalisamfile(LF_IVALIQ)); } if(o.dlg() >= CAMPI_CON_BOOLEAN && o.dlg() <= F_IMPNOVER && e == fe_modify) // Se l'utente modifica manualmente uno dei campi calcolati da Campo flaggo il DB { checkOldValue(o.dlg(), get_real(o.dlg())); } // Controllo sull'aggiornamento di campi collegati ad altri if(e == fe_modify) { switch(o.dlg()) { // Iva Esigibile VS Iva Detratta case F_IVAES : case F_IVAESXC : case F_IVAESDIFF : case F_IVADET : case F_IVADETXC : case F_IVADETDIFF : { real ivaes = get_real(F_IVAES); real ivadet = get_real(F_IVADET); if((ivaes - ivadet) >= ZERO) { set(F_IVADOV, ivaes - ivadet); set(F_IVADOVC, ZERO); checkOldValue(F_IVADOV, ivaes - ivadet); checkOldValue(F_IVADOVC, ""); } else { set(F_IVADOV, ZERO); set(F_IVADOVC, (ivaes - ivadet) * -UNO); checkOldValue(F_IVADOV, ""); checkOldValue(F_IVADOVC, (ivaes - ivadet) * -UNO); } } // IVA da versare VS a credito case F_IVADOV : case F_DEBPREC : case F_INTLIQTRI : case F_IVADOVC : case F_CREPREC : case F_CREAPREC : case F_VEAUE : case F_CREIMP : case F_ACCDOV : { // Ricalcolo VP13 e VP14 real debito = get_real(F_IVADOV) + get_real(F_DEBPREC) + get_real(F_INTLIQTRI); /* Se il credito anno precedente è negativo devo mantenerlo tale ma sottrarlo al credito dell'anno precedente delle dichiarazioni precedenti */ real creaprec = get_real(F_CREAPREC); if(creaprec < ZERO) { real creprec = ZERO; real appcreaprec; calcolaCreditoPrec(creprec, appcreaprec, mensile, get_int(F_ANNO), get_int(F_MESE)); creaprec = appcreaprec + creaprec; // Controllo che il credito non sia sforato sotto 0 if (creaprec < ZERO) { TString msg = "Attenzione! Capienza del credito dell'anno precedente esaurita di "; msg << (creaprec * - UNO).stringa(0,2) << "€"; warning_box(msg); } } real credito = get_real(F_IVADOVC) + get_real(F_CREPREC) + creaprec + get_real(F_VEAUE) + get_real(F_CREIMP) + get_real(F_ACCDOV); if(debito - credito >= ZERO) { set(F_IVAVER, debito - credito); set(F_IVAVERC, ZERO); checkOldValue(F_IVAVER, debito - credito); checkOldValue(F_IVAVERC, ""); } else { set(F_IVAVER, ZERO); set(F_IVAVERC, credito - debito); checkOldValue(F_IVAVER, ""); checkOldValue(F_IVAVERC, credito - debito); } } break; } } return true; } // Funzione che effettivamente estrapola i dati necessari void ComLiqPerIva_mask::extractinator() // Per gli amici GTFO { /* Devo estrapolare più mesi, per farlo vado ciclo n volte (1 o 3) in base se stiamo parlando di trimestralità o meno * I dati da prelevare saranno in PRM, LIM e %LIA * In PRM e LIM troverò le informazioni suddivise per mese, mentre in %LIA ho l'anno di liquidazione */ int start = mensile ? get_int(F_MESE) : (((get_int(F_TRIMESTRE) - 1) * 3) + 1); int end = mensile ? start : start + 2; int anno = get_int(F_ANNO); // Valori da calcolare real totopatt = ZERO; real totopattxc = ZERO; real totoppas = ZERO; real totoppasxc = ZERO; real ivaes = ZERO; real ivaesxc = ZERO; real ivaesdiff = ZERO; real ivadet = ZERO; real ivadetxc = ZERO; real ivadetdiff = ZERO; real rettifiche = ZERO; real varimp = ZERO; real rimborsi = ZERO; real impnover = ZERO; real crespec = ZERO; real vereff = ZERO; real ivadov = ZERO; real ivadovc = ZERO; real debprec = ZERO; real creprec = ZERO; real creaprec = ZERO; real intliqtri = ZERO; real accdov = ZERO; real ivaver = ZERO; real ivaverc = ZERO; for(; start <= end; start++) { TDate data_da(1, start, anno); TDate data_a(1, start, anno); data_a.set_end_month(); bool hasIXC = gestione_IVAxCassa(data_da); /**************************************************************************************************************** * TOTOPATT, TOTOPATTXC, TOTOPPAS, TOTOPPASXC, IVAES, IVAESXC, IVAESDIFF, * IVADET , IVADETXC, IVADETDIFF ****************************************************************************************************************/ // Riga LIM const TRectype rowLim = getLIM(anno, start); // Controllo che la liquidazione è stata effettuata, controllo da fare solo nella 12 if(dongle().year_assist() > 2121 && (rowLim.empty() || rowLim.get_bool("B0"))) { error_box("Attenzione non è stata calcolata la liquidazione del periodo corrente"); return; } // Riga LIA const TRectype rowLia = getLIA(anno); TString queryIva = "USE RMOVIVA\n"; queryIva << "SELECT (23.REG!=\"\")&&BETWEEN(23.DATAREG,#DADATAREG,#ADATAREG)"; queryIva << "\nJOIN MOV INTO NUMREG==NUMREG\n"; TISAM_recordset curIva(queryIva); curIva.set_var("#DADATAREG", data_da); curIva.set_var("#ADATAREG", data_a); for(bool ok = curIva.move_first(); ok; ok = curIva.move_next()) { TString totat, totpas, i; // Controllo che sia un movimento con codice non "non soggetto" TCodiceIVA codiva(curIva.get("25.CODIVA").as_string()); if(codiva.tipo() == "NS") continue; // Prendo il tipo di registro int tiporeg = TRegistro(curIva.get("23.REG").as_string()).tipo(); // Prendiamo l'imponibile real imp = curIva.get("25.IMPONIBILE").as_real(); // Se è un movimento IvaXCassa o LiqDiff if(hasIXC && (curIva.get("23.IVAXCASSA").as_bool() || curIva.get("23.LIQDIFF").as_bool())) { if(tiporeg == REG_ATT) totopattxc += imp; else totoppasxc += imp; } else { if(tiporeg == REG_ATT) { // Controllo il reverse charge, non va calcolato nel totale delle operazioni attive! // Se non ha una riga di movimento non lo sommo TString keyRC = curIva.get("23.NUMREG").as_string(); keyRC << "|1"; if(!cache().get(LF_RMOV, keyRC).empty()) totopatt += imp; } else totoppas += imp; } } // Se ha attiva l'IVA x cassa calcolo le imposte (imponibili per comodità già calcolati sopra) if(hasIXC) { // IVA esigibile real imposta_diff, imposta_xcas; imposta_diff = imposta_xcas = ZERO; // 1 = Vendite calc_inc_diff(anno, start, REG_ATT, imposta_diff, imposta_xcas); ivaesxc = ivaesxc + imposta_xcas; ivaesdiff = ivaesdiff + imposta_diff; // IVA detraibile imposta_diff = imposta_xcas = ZERO; // 2 = Acquisti calc_inc_diff(anno, start, REG_PAS, imposta_diff, imposta_xcas); ivadetxc = ivadetxc + imposta_xcas; ivadetdiff = ivadetdiff + imposta_diff; } /** Resto *****************************************************************************************************/ TRectype rowLam = getLAM(anno, start); /* É saltato fuori che in caso di liquidazione trimestrale l'importo ivaes e ivadet * viene scritto su ogni mese, quindi prendo solo quando * start == end -> iva mensile o ultimo mese della trimestrale */ if(start == end) { ivaes += rowLam.get_real("R0"); ivadet += rowLam.get_real("R1"); } ivaes += ivaesxc + ivaesdiff; ivadet += ivadetxc + ivadetdiff; rettifiche = rettifiche + rowLim.get_real("R5"); varimp = varimp + rowLim.get_real("R17"); rimborsi = rimborsi + rowLim.get_real("R1"); impnover = impnover + rowLim.get_real("R18"); crespec = crespec + rowLim.get_real("R19"); vereff = vereff + rowLim.get_real("R8"); debprec = debprec + rowLim.get_real("S2"); real appReal = ZERO; // Credito periodo precedente e anno precedente calcolaCreditoPrec(creprec, creaprec, mensile, anno, start); if(creaprec < ZERO) creaprec = ZERO; intliqtri = intliqtri + rowLim.get_real("R14"); accdov = accdov + rowLim.get_real("R11"); } // Controllo debprec // Calcolo prendendo dalla tabella %VER TRectype rowVer = getVER(anno, start); if(rowVer.empty() || rowVer.get_real("R5") == ZERO) { error_box("Non è stata valorizzato correttamente il campo \"Periodico\" in \"Versamenti ed interessi IVA\""); return; } else { if(debprec > rowVer.get_real("R5")) // Se è maggiore di 25.82€ va azzerato debprec = ZERO; } // Calcolo ivadov/ivadovc ivadov = ivaes - ivadet; ivadovc = ivadet - ivaes; if(ivadov > ZERO) { ivadovc = ZERO; } else { ivadov = ZERO; } // Calcolo l'IVA da versare o a Credito ivaver = (ivadov + debprec + intliqtri) - (ivadovc + creprec + creaprec + get_real(F_VEAUE) + get_real(F_CREIMP) + accdov); ivaverc = (ivadovc + creprec + creaprec + get_real(F_VEAUE) + get_real(F_CREIMP) + accdov) - (ivadov + debprec + intliqtri); // Controllo quale va sotto zero e la tolgo if(ivaver >= ZERO) { ivaverc = ZERO; } else { ivaver = ZERO; } // Sommo i totali con i totali xc totopatt += totopattxc; totoppas += totoppasxc; // Imposto tutti i campi set(F_TOTOPATT, totopatt); set(F_TOTOPATTXC, totopattxc); set(F_TOTOPPAS, totoppas); set(F_TOTOPPASXC, totoppasxc); set(F_IVAES, ivaes); set(F_IVAESXC, ivaesxc); set(F_IVAESDIFF, ivaesdiff); set(F_IVADET, ivadet); set(F_IVADETXC, ivadetxc); set(F_IVADETDIFF, ivadetdiff); set(F_IVADOV, ivadov); set(F_IVADOVC, ivadovc); set(F_DEBPREC, debprec); set(F_CREPREC, creprec); set(F_CREAPREC, creaprec); //set(F_VEAUE, veaue); // Campi non calcolati, messi qua per un eventuale futuro //set(F_CREIMP, creimp); set(F_INTLIQTRI, intliqtri); set(F_ACCDOV, accdov); set(F_IVAVER, ivaver); set(F_IVAVERC, ivaverc); set(F_RETTIFICHE, rettifiche); set(F_VARIMP, varimp); set(F_RIMBORSI, rimborsi); set(F_IMPNOVER, impnover); set(F_CRESPEC, crespec); set(F_VEREFF, vereff); // Preparo il record saveGen(); // Azzero i booleani for(int i = B_TOTOPATT; i <= B_CRESPEC; i++) { set(i, ""); } } void ComLiqPerIva_mask::saveGen() { // Assegno tutti i campi trueData.put("ANNO", get(F_ANNO)); trueData.put("MESE", get(F_MESE)); trueData.put("TRIMESTRE", get(F_TRIMESTRE)); trueData.put("GENERATA", 'G'); // Segno che è generata da campo trueData.put("TOTOPATT", get(F_TOTOPATT)); trueData.put("TOTOPATTXC", get(F_TOTOPATTXC)); trueData.put("TOTOPPAS", get(F_TOTOPPAS)); trueData.put("TOTOPPASXC", get(F_TOTOPPASXC)); trueData.put("IVAES", get(F_IVAES)); trueData.put("IVAESXC", get(F_IVAESXC)); trueData.put("IVAESDIFF", get(F_IVAESDIFF)); trueData.put("IVADET", get(F_IVADET)); trueData.put("IVADETXC", get(F_IVADETXC)); trueData.put("IVADETDIFF", get(F_IVADETDIFF)); trueData.put("IVADOV", get(F_IVADOV)); trueData.put("IVADOVC", get(F_IVADOVC)); trueData.put("DEBPREC", get(F_DEBPREC)); trueData.put("CREPREC", get(F_CREPREC)); trueData.put("CREAPREC", get(F_CREAPREC)); trueData.put("VEAUE", get(F_VEAUE)); trueData.put("CREIMP", get(F_CREIMP)); trueData.put("INTLIQTRI", get(F_INTLIQTRI)); trueData.put("ACCDOV", get(F_ACCDOV)); trueData.put("IVAVER", get(F_IVAVER)); trueData.put("IVAVERC", get(F_IVAVERC)); trueData.put("RETTIFICHE", get(F_RETTIFICHE)); trueData.put("VARIMP", get(F_VARIMP)); trueData.put("RIMBORSI", get(F_RIMBORSI)); trueData.put("CRESPEC", get(F_CRESPEC)); trueData.put("IMPNOVER", get(F_IMPNOVER)); trueData.put("VEREFF", get(F_VEREFF)); } void ComLiqPerIva_mask::checkOldValue(int field, real val) { if(trueData.empty()) { TString key; key << get(F_ANNO) << "|" << get(F_MESE) << "|G"; trueData = cache().get(LF_IVALIQ, key); } real trueVal = ZERO; // Modo più intelligente di uno stupido switch case? switch(field) { case F_TOTOPATT: trueVal = trueData.get_real("TOTOPATT"); break; case F_TOTOPATTXC: trueVal = trueData.get_real("TOTOPATTXC"); break; case F_TOTOPPAS: trueVal = trueData.get_real("TOTOPPAS"); break; case F_TOTOPPASXC: trueVal = trueData.get_real("TOTOPPASXC"); break; case F_IVAES: trueVal = trueData.get_real("IVAES"); break; case F_IVAESXC: trueVal = trueData.get_real("IVAESXC"); break; case F_IVAESDIFF: trueVal = trueData.get_real("IVAESDIFF"); break; case F_IVADET: trueVal = trueData.get_real("IVADET"); break; case F_IVADETXC: trueVal = trueData.get_real("IVADETXC"); break; case F_IVADETDIFF: trueVal = trueData.get_real("IVADETDIFF"); break; case F_IVADOV: trueVal = trueData.get_real("IVADOV"); break; case F_IVADOVC: trueVal = trueData.get_real("IVADOVC"); break; case F_DEBPREC: trueVal = trueData.get_real("DEBPREC"); break; case F_CREPREC: trueVal = trueData.get_real("CREPREC"); break; case F_CREAPREC: trueVal = trueData.get_real("CREAPREC"); break; case F_VEAUE: trueVal = trueData.get_real("VEAUE"); break; case F_CREIMP: trueVal = trueData.get_real("CREIMP"); break; case F_INTLIQTRI: trueVal = trueData.get_real("INTLIQTRI"); break; case F_ACCDOV: trueVal = trueData.get_real("ACCDOV"); break; case F_IVAVER: trueVal = trueData.get_real("IVAVER"); break; case F_IVAVERC: trueVal = trueData.get_real("IVAVERC"); break; case F_RETTIFICHE: trueVal = trueData.get_real("RETTIFICHE"); break; case F_VARIMP: trueVal = trueData.get_real("VARIMP"); break; case F_RIMBORSI: trueVal = trueData.get_real("RIMBORSI"); break; case F_CRESPEC: trueVal = trueData.get_real("CRESPEC"); break; case F_IMPNOVER: trueVal = trueData.get_real("IMPNOVER"); break; case F_VEREFF: trueVal = trueData.get_real("VEREFF"); break; } set(field + 50, trueVal != val ? "X" : ""); } class ComLiqPerIva_app : public TRelation_application { private: ComLiqPerIva_mask* _mask; TRelation* _rel; protected: bool user_create(); bool user_destroy(); virtual TMask* get_mask(int mode) { return _mask; } public: virtual TRelation* get_relation() const {return (TRelation*)_rel;} }; bool ComLiqPerIva_app::user_create() { _rel = new TRelation(LF_IVALIQ); _mask = new ComLiqPerIva_mask; set_search_field(F_ANNO); return true; } bool ComLiqPerIva_app::user_destroy() { delete _mask; return true; } int tf0200(int argc, char* argv[]) { ComLiqPerIva_app app; app.run(argc, argv, TR("Trasferimento dati liquidazione IVA")); return 0; }