// Bonomo #include #include #include #include #include #include #include #include #include #include "pg0214.h" #include "pg0214200a.h" #include "../cg/cg2103.h" #include "../cg/cglib02.h" #include "../cg/cgpagame.h" #include "../cg/cgsaldac.h" #include "../ve/velib.h" #include "clifo.h" #include "comuni.h" #include #include #include #include #include //////////////////////////////////////// // TAutomask //////////////////////////////////////// class TBonomo_mask : public TAutomask { protected: bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TBonomo_mask(); virtual ~TBonomo_mask(){}; }; TBonomo_mask::TBonomo_mask() :TAutomask ("pg0214200a") { } bool TBonomo_mask::on_field_event(TOperable_field& f, TField_event e, long jolly) { switch (f.dlg()) { //giochetto per avere la lista dei files validi nella directory di trasferimento! case F_NAME: if (e == fe_button) { TArray_sheet as(-1, -1, 72, 20, TR("Selezione file"), "File@32"); TFilename path = get(F_PATH); path.add("*.txt"); //files delle testate list_files(path, as.rows_array()); TFilename name; FOR_EACH_ARRAY_ROW(as.rows_array(), i, row) { name = *row; *row = name.name(); } if (as.run() == K_ENTER) { f.set(as.row(as.selected())); } } break; default: break; } return true; } /////////////////////////////////////// // TSkeleton_application /////////////////////////////////////// class TBonomo : public TSkeleton_application { virtual bool check_autorization() const {return false;} virtual const char * extra_modules() const {return "ve";} TBonomo_mask* _msk; TSaldo_agg _saldi; TEsercizi_contabili _esc; TCausale* _caus; TAssoc_array _numdocs; TString4 _codiva; real _perciva; protected: void carica_numeri_documento(); long aggiorna_cliente(TToken_string& curr); void aggiorna_movimento(TToken_string& curr, const long codcf); long carica_movimento(TMovimentoPN_VE& movpn, const TString& numdoc, const long codcf, const TDate& datareg) const; void aggiorna_saldi(TMovimentoPN_VE& movpn, bool save); void crea_righe_iva(TMovimentoPN_VE& movpn, TToken_string& curr, const long numreg); void crea_righe_cg(TMovimentoPN_VE& movpn, TToken_string& curr); void crea_scadenze(TToken_string& curr, TRectype& mov); bool create_total_doc_row(TMovimentoPN_VE& movpn); real get_imp(TToken_string& curr, int pos) const; bool safe_put(TLocalisamfile& clienti, const char* field, const char* val) const; long find_last_client() const; public: virtual bool create(); virtual bool destroy(); virtual void main_loop(); bool transfer(); TBonomo() {} }; TBonomo& app() { return (TBonomo&) main_app(); } ///////////////////////////////// // aggiornamento clienti ///////////////////////////////// bool TBonomo::safe_put(TLocalisamfile& file, const char* field, const char* val) const { const bool ok = val && *val; if (ok) file.put(field, val); return ok; } long TBonomo::find_last_client() const { TLocalisamfile clifo(LF_CLIFO); long codcf = 1L ; if (!clifo.empty()) { clifo.put(CLI_TIPOCF, 'F'); if (clifo.read(_isgteq) == NOERR) clifo.prev(); else clifo.last(); if (clifo.get_char(CLI_TIPOCF) == 'C') codcf += clifo.get_long(CLI_CODCF); } return codcf; } long TBonomo::aggiorna_cliente(TToken_string& curr) { TLocalisamfile clienti(LF_CLIFO); TString piva = curr.get(6); //partita iva if (piva.full() && piva.len() < 11) piva.right_just(11, '0'); TString cofi = curr.get(7); //codice fiscale //se il cofi e' piu' corto di 11 -> e' una p.iva! if (cofi.full() && cofi.len() < 11) cofi.right_just(11, '0'); bool client_found = false; if (safe_put(clienti, CLI_PAIV, piva)) { clienti.put(CLI_TIPOCF, "C"); //deve rimettere il valore di TIPOCF che si e' perso nella.. //..read fallita precedentemente! clienti.zero(CLI_STATOPAIV); //nessuno statopaiv previsto clienti.setkey(5); //tipocf+statopaiv+paiv client_found = clienti.read() == NOERR; } if (!client_found) //se non lo trova con p.va prova con il codice fiscale { if (safe_put(clienti, CLI_COFI, cofi)) { clienti.put(CLI_TIPOCF, "C"); //deve rimettere il valore di TIPOCF che si e' perso nella.. //..read fallita precedentemente! clienti.setkey(4); //tipocf+cofi client_found = clienti.read() == NOERR; } } //aggiunge tutti i campi relativi al cliente //le prime 2 righe vanno rifatte per evitare che venga vuotato il record in caso di.. //..fallimento della read() (vedi discorso nei due if precedenti) safe_put(clienti, CLI_TIPOCF, "C"); safe_put(clienti, CLI_PAIV, piva); //p.iva safe_put(clienti, CLI_COFI, cofi); //cod. fisc. safe_put(clienti, CLI_RAGSOC, curr.get(2)); //ragsoc //elaborazione dell'indirizzo //potrebbe servire per estrarre il numero civico dall'indirizzo /*TString indirizzo = curr.get(3); TString ind; TString civ; //estraggo il numero civico for (int i = indirizzo.len()-1; i>=0; i--) { if (indirizzo[i] != ' ') civ << indirizzo[i]; else break; } //estraggo l'indirizzo vero e proprio ind = indirizzo.sub(0,i-1); safe_put(clienti, CLI_INDCF, ind); //indirizzo safe_put(clienti, CLI_CIVCF, civ); //indirizzo*/ safe_put(clienti, CLI_INDCF, curr.get(3)); //indirizzo TString16 cap = curr.get(6); cap.trim(); TString80 comune = curr.get(5); //comune o localita' comune.trim(); safe_put(clienti, CLI_CAPCF, cap); //cap const TString& codcom = cap2comune(cap, comune); if (codcom.blank()) safe_put(clienti, CLI_LOCCF, comune); else safe_put(clienti, CLI_COMCF, codcom); //scrive 'sto benedetto file dei clienti! long codcf = clienti.get_long(CLI_CODCF); if (client_found) //se trova il record con il codice cliente immesso lo riscrive.. clienti.rewrite(); else //..se invece e' nuovo lo scrive { codcf = find_last_client(); clienti.put(CLI_CODCF, codcf); clienti.write(); } return codcf; } //////////////////////////////////////////// // aggiornamento movimenti (testate) //////////////////////////////////////////// long TBonomo::carica_movimento(TMovimentoPN_VE& movpn, const TString& numdoc, const long codcf, const TDate& datareg) const { long numreg = 0L; movpn.lfile().setkey(1); TRectype& mov = movpn.curr(); TToken_string key; key.add(datareg.year()); key.add(numdoc); //cerca se il numreg del numdoc corrente esiste gia' nel file MOV (il documento e' gia' stato.. //..contabilizzato in precedenza,deve solo aggiornarlo) const TString* strnumreg = (const TString*) _numdocs.objptr(key); if (strnumreg != NULL) { mov.put(MOV_NUMREG, *strnumreg); if (movpn.read() == NOERR) numreg = mov.get_long(MOV_NUMREG); } //se non lo trova, si incazza e lo crea con un numero in piu' dell'ultimo! if (numreg == 0) { movpn.last(); numreg = mov.get_long(MOV_NUMREG) + 1; mov.zero(); //azzera la testata movpn.destroy_rows(numreg); //azzera le righe mov.put(MOV_NUMREG, numreg); mov.put(MOV_TIPO, 'C'); mov.put(MOV_CODCF, codcf); mov.put(MOV_DATAREG, datareg); mov.put(MOV_ANNOES, _esc.date2esc(datareg)); movpn.write(); } return numreg; } //metodo per l'aggiornamento saldi al caricamento del movimento void TBonomo::aggiorna_saldi(TMovimentoPN_VE& movpn, bool save) { _saldi.set_anno_es(movpn.curr().get_int(MOV_ANNOES)); const int righemov = movpn.cg_items(); for (int i = 0; i < righemov; i++) { const TRectype& rmov = movpn.cg(i); const TBill conto(rmov); const TImporto importo(rmov.get_char(RMV_SEZIONE), rmov.get_real(RMV_IMPORTO)); _saldi.aggiorna(conto, importo, save); } if (save) { _saldi.set_data_ulmov(movpn.curr().get_date(MOV_DATAREG)); _saldi.set_num_ulmov(movpn.curr().get_long(MOV_NUMREG)); _saldi.registra(); _saldi.reset(); } } //decisivo metodo per non farsi infinocchiare dalle virgole di separazione decimale real TBonomo::get_imp(TToken_string& curr, int pos) const { TString16 impstring = curr.get(pos); impstring.replace(',', '.'); const real imp = impstring; return imp; } //metodo per la generazione del saldaconto in caso di pagamenti con scadenzario void TBonomo::crea_scadenze(TToken_string& curr, TRectype& mov) { //crea l'oggetto pagamento dal record del file da trasferire e genera le scadenze TString80 codpag = curr.get(9); codpag = codpag.sub(0,4); TPagamento pagamento(codpag); const real imponibile = get_imp(curr, 8) - get_imp(curr, 10); // totale documento meno imposta const real imposta = get_imp(curr, 10); const real spese = ZERO; pagamento.set_total(imponibile, imposta, spese); pagamento.set_datadoc(mov.get_date(MOV_DATAREG)); pagamento.set_rate_auto(); const long codcf = mov.get_long(MOV_CODCF); TBill zio(0, 0, codcf, mov.get_char(MOV_TIPO)); zio.find(); //metodo che completa la creazione del conto if (!zio.ok()) // se non e' valido, reperiscilo dalla riga #1 della causale { _caus->bill(1,zio); // conto della riga 1 zio.codclifo() = codcf; } const int anno = mov.get_int(MOV_ANNOES); const TString& numdoc = mov.get(MOV_NUMDOC); TPartita match (zio, anno, numdoc); //parte riportata da cg2104 TRiga_partite& riga_partita = match.new_row(); const int nuova_riga = riga_partita.get_int(PART_NRIGA); // put data on riga_partita riga_partita.put(PART_TIPOMOV, mov.get_int(MOV_TIPOMOV)); riga_partita.put(PART_NREG, mov.get_long(MOV_NUMREG)); riga_partita.put(PART_NUMRIG, 1); riga_partita.put(PART_DATAREG, mov.get_date(MOV_DATAREG)); riga_partita.put(PART_DATADOC, mov.get_date(MOV_DATADOC)); riga_partita.put(PART_NUMDOC, numdoc); riga_partita.put(PART_DESCR, mov.get(MOV_DESCR)); riga_partita.put(PART_CODCAUS, mov.get(MOV_CODCAUS)); riga_partita.put(PART_REG, mov.get(MOV_REG)); riga_partita.put(PART_SEZ, _caus->sezione_clifo()); //dare o avere e' nella causale riga_partita.put(PART_PROTIVA, mov.get(MOV_PROTIVA)); riga_partita.put(PART_IMPTOTDOC, mov.get(MOV_TOTDOC)); riga_partita.put(PART_IMPORTO, imponibile + imposta); riga_partita.put(PART_SPESE, spese); riga_partita.put(PART_IMPOSTA, imposta); for (int i = 0; i < pagamento.n_rate(); i++) { TRiga_scadenze& scadenza = riga_partita.new_row(); scadenza.put(SCAD_CODPAG, codpag); // Codice pagamento scadenza.put(SCAD_DATASCAD, pagamento.data_rata(i)); // 0 = Data scadenza scadenza.put(SCAD_IMPORTO, pagamento.importo_rata(i)); // 1 = Importo scadenza.put(SCAD_TIPOPAG, pagamento.tipo_rata(i)); // 4 = Tipo pagamento scadenza.put(SCAD_ULTCLASS, pagamento.ulc_rata(i)); // 5 = Ulteriore classificazione // 6 = Descrizione pagamento } match.write(); } void TBonomo::aggiorna_movimento(TToken_string& curr, const long codcf) { TString16 numdoc = curr.get(0); //numdoc sul file (lunghezza casuale!) numdoc.cut(7); //il nostro numdoc al max e' lungo 7 caratteri TString16 str = curr.get(1); if (str.len() < 10) str.insert("20", 6); const TDate datareg(str); //const TDate datareg(curr.get(1)); const int anno = datareg.year(); //movimento p.n. che servira' un po' ovunque... TMovimentoPN_VE movpn(false); TRectype& mov = movpn.curr(); movpn.set_caus(_caus); //cerca se un movimento generato dal documento corrente esiste gia' negli archivi; //se non lo trova lo crea const long numreg = carica_movimento(movpn, numdoc, codcf, datareg); //aggiorna i saldi aggiorna_saldi(movpn, false); //comincia a riempire i campi del record (se nuovo li crea, se vecchio li aggiorna) mov.put(MOV_DATAREG, datareg); //datareg mov.put(MOV_DATACOMP, datareg); //datacomp mov.put(MOV_DATADOC, datareg); //datadoc mov.put(MOV_NUMDOC, numdoc); //numdoc mov.put(MOV_ANNOIVA, anno); //annoiva mov.put(MOV_ANNOES, _esc.date2esc(datareg)); //annoes //adesso tocca a tutti i campi discendenti dalla causale _caus->read(_msk->get(F_CODCAUS), anno); mov.put(MOV_TIPODOC, _caus->tipo_doc()); //tipodoc mov.put(MOV_CODCAUS, _msk->get(F_CODCAUS)); //codcaus TString descr = "Fattura n. "; descr << numdoc << " del " << datareg; mov.put(MOV_DESCR, descr); //descr mov.put(MOV_TIPOMOV, _caus->tipomov()); //tipomov TRegistro& regiva = _caus->reg(); //registro iva mov.put(MOV_REG, regiva.name()); //codice registro iva long protiva = regiva.protocol() + 1; mov.put(MOV_PROTIVA, protiva); //protocollo iva const real totdoc = get_imp(curr, 8); //totale documento mov.put(MOV_TOTDOC, totdoc); TString80 codpag = curr.get(9); //codice pagamento codpag = codpag.sub(0,4); if (codpag.full()) { mov.put(MOV_CODPAG, codpag); crea_scadenze(curr, mov); //genera lo scadenziario } movpn.destroy_rows(numreg); //elimina le righe del movimento usato fino adesso crea_righe_iva(movpn, curr, numreg); crea_righe_cg(movpn, curr); //e' sempre rewrite perche' se movimento nuovo viene creato nella carica_movimento if (movpn.rewrite() == NOERR) { regiva.update(protiva, datareg); //updata il registro iva aggiorna_saldi(movpn, true); } } //////////////////////////////////////// // aggiornamento righe movimenti //////////////////////////////////////// //aggiornamento righe iva void TBonomo::crea_righe_iva(TMovimentoPN_VE& movpn, TToken_string& curr, const long numreg) { //parametri iva sulla maschera const TString4 iva_esente = _msk->get(F_CODIVA_ES); TString16 str = curr.get(1); if (str.len() < 10) str.insert("20", 6); const TDate datareg(str); //const TDate datareg(curr.get(1)); const int annoes = _esc.date2esc(datareg); //anche datareg int i = 0; //solo le righe con netto !=0 possono essere trattate const real netto = get_imp(curr, 8) - get_imp(curr, 10); if (netto != ZERO) { TRectype& rmviva = movpn.iva(i++); rmviva.put(RMI_ANNOES, annoes); rmviva.put(RMI_NUMREG, numreg); rmviva.put(RMI_NUMRIG, i); rmviva.put(RMI_IMPONIBILE, netto); const real imposta = get_imp(curr, 10); rmviva.put(RMI_IMPOSTA, imposta); //notare la figata del controllo sul vecchio codice iva che accelera la ricerca! if (imposta != ZERO) { real perciva = imposta / netto * CENTO; perciva.round(1); if (perciva != _perciva) { //cerca nella tabella iva il primo codice corrispondente a questa % TTable iva ("%IVA"); for (int err = iva.first(); err == NOERR ; err = iva.next()) { const real perc = iva.curr().get_real("R0"); if (perc == perciva) { _perciva = perc; _codiva = iva.curr().get("CODTAB"); break; } } } rmviva.put(RMI_CODIVA, _codiva); } else { rmviva.put(RMI_CODIVA, iva_esente); } TBill zio; _caus->bill(2,zio); zio.put(rmviva); //il conto sa scriversi sulle righe iva!E' veramente figo... } } bool TBonomo::create_total_doc_row(TMovimentoPN_VE& movpn) // Crea la riga contabile di totale documento { const TRectype& head = movpn.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)); const real totdoc(head.get_real(MOV_TOTDOC)); const int annoiva = head.get_int(MOV_ANNOIVA); const char tipocf = head.get_char(MOV_TIPO); const long codcf = head.get_long(MOV_CODCF); TToken_string keycf; keycf.format("%c|%ld", tipocf, codcf); const TRectype& cli_file = cache().get(LF_CLIFO, keycf); int gruppo = cli_file.get_int(CLI_GRUPPO); int conto = cli_file.get_int(CLI_CONTO); TBill co_cliente(gruppo, 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()) return false; } //contropartita TConto contro; if (movpn.iva_items() > 0) { const TRectype& first_iva_row = movpn.iva(0); contro.get(first_iva_row); } TRectype& rec_cg = movpn.cg(0); 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); co_cliente.put(rec_cg); contro.put(rec_cg, TRUE); rec_cg.put(RMV_IMPORTO,totdoc); rec_cg.put(RMV_ROWTYPE,"T"); return true; } void TBonomo::crea_righe_cg(TMovimentoPN_VE& movpn, TToken_string& curr) { //crea la riga contabile con il totale documento create_total_doc_row(movpn); TToken_string keycf; keycf = "C"; keycf.add(movpn.curr().get(MOV_CODCF)); const TRectype& cli = cache().get(LF_CLIFO, keycf); movpn.recalc_cg_rows(EMPTY_STRING, *_caus); //la descrizione la mettera' il metodo } //////////////////////////////// // main //////////////////////////////// static bool update_numdoc(const TRelation& rel, void* pJolly) { const TRectype& curr = rel.curr(); TToken_string key; key.add(curr.get(MOV_ANNOIVA)); key.add(curr.get(MOV_NUMDOC)); TAssoc_array* ass = (TAssoc_array*)pJolly; ass->add(key, curr.get(MOV_NUMREG)); return true; } void TBonomo::carica_numeri_documento() { //metodo che legge il file mov e registra in un assocarray tutti i mov con... //tipo=C,causale=_caus; TString filter; const TString& codcaus = _msk->get(F_CODCAUS); filter.format("%s=='%s'",MOV_CODCAUS, (const char*)codcaus); TRelation rel_mov(LF_MOV); TCursor cur_mov(&rel_mov, filter); //svuota il vecchio _numdocs... _numdocs.destroy(); //...poi riempie l'assoc _numdocs cur_mov.scan(update_numdoc, &_numdocs, "Scansione preliminare archivi..."); } bool TBonomo::transfer() { TFilename file = _msk->get(F_PATH); file.add(_msk->get(F_NAME)); file.ext("txt"); //precarica dal file MOV tutti i movimenti con causale=quella sulla msk(accelera le ricerche) carica_numeri_documento(); const long dimension = fsize(file); TProgind pi(dimension,"Importazione documenti in corso..."); TScanner scanner(file); TToken_string curr(1024, '\t'); //curr = scanner.line(); //lettura della prima riga del file che contiene solo i titoli dei campi scanner.getline(curr.get_buffer(), curr.size(), '\r'); while (scanner.ok()) { //curr = scanner.line(); scanner.getline(curr.get_buffer(), curr.size(), '\r'); curr.rtrim(); //se ha un record vuoto sul file lo salta! if (curr.blank()) break; pi.setstatus(scanner.tellg()); //aggiorna il file dei clifo e ritorna il codice cliente const long codcf = aggiorna_cliente(curr); //finche' c'e' riga c'e' speranza.... TString riga = curr.get(0); if (riga.not_empty()) aggiorna_movimento(curr, codcf); else break; } return true; } bool TBonomo::create() { _msk = new TBonomo_mask(); _caus = new TCausale(); return TSkeleton_application::create(); } bool TBonomo::destroy() { delete _msk; return TApplication::destroy(); } void TBonomo::main_loop() { KEY tasto; tasto = _msk->run(); if (tasto == K_ENTER) { if (transfer()) { message_box(TR("Importazione documenti completata")); } } } int pg0214200 (int argc, char* argv[]) { TBonomo main_app; main_app.run(argc, argv, TR("Importazione documenti in contabilita'")); return true; }