/* ef0800.cpp: programma di contabilizzazione effetti Ho visto ombre di sconforto riemergere dal passato... al largo dei bastioni di Orione _|_|_ ^/ . ..\^ ___[=========]___ ___-==++""" . /. . . \ . """++==-___ __-+"" __\ .. . . | .. . | . . . /__ ""+-__ /\__+-"" `-----=====\_ _/=====-----' ""-+__/\ _/_/ ""="" \_\_ _________ .-~~~-..---..-~~~-. __________ -~.--<<<<<<<`-...--'.---.`--...-'>>>>>>>--.~- =~~.-~ ````\\_`(`._.')'_//'''' ~-.~~= [(o)/ ``.._..'' \(o) .___________________ _-_ .\==============_=_/ ____.---'---`---.____ . \_ \ \----._________.----/ . \ \ / / `-_-' . __,--`.`-'..'-_ . /____ || . `--.____,-' Did you see my apogee ? */ #include #include #include #include #include #include #include #include "../cg/cg2101.h" #include "../cg/cg2103.h" #include "../cg/cgsaldac.h" #include "../ve/velib.h" #include "ef0301.h" #include "ef0800a.h" #include #include #include #include #include #include #include #define CGROWS_LIMIT 96 // Limite imposto da invii/ricezioni #define DIST_INCASSO 'I' #define DIST_SBF 'B' #define DIST_SCONTO 'S' // TContabilizzazione_effetti_app // Applicazione di contabilizzazione effetti class TContabilizzazione_effetti_app : public TSkeleton_application { TDate _data_op; // Data operazione TString16 _cod_caus; // Codice causale TString16 _cod_caus_pag; // Codice causale pagamenti int _cod_es; // Codice/anno esercizio bool _sc_enabled; // se TRUE il saldaconto di ditta e' abilitato bool _can_write; // se TRUE e' abilitata la scrittura. Non appena rileva un errore rimane a FALSE for this instance real _total_mov, // Totale del movimento corrente _total_mov_val;// Same as above but in valuta TString _desc_inc, _desc_pag; // Descrizioni movimento generato TMask *_msk; // maschera di selezione dati TLocalisamfile *_attiv, // file delle attivita' (per far funzionare TRegistro) *_fcaus, // file delle causale (per far funzionare TCausale) *_frcaus, // file delle righe causali (per far funzionare TCausale) *_effetti, // file degli effetti (per TDistinta) *_reffetti, // file delle righe effetti (per TDistinta) *_cessionari, // file dei cessionari (per TDistinta) *_part, // file delle partite (per far funzionare TPartita) *_scad, // file delle scadenze (per far funzionare TPartita) *_pags, // file dei pagamenti (per far funzionare TPartita) *_clifo, // file dei clienti *_doc, // file dei documenti *_pcon; // file piano dei conti TTable *_cpg, // tabella condizioni di pagamento *_bnp; // tabella banca presentazione effetti TBill _banca, // conto di contropartita della banca _cliente; // conto di contropartita del cliente TArray_sheet *_dist_sheet; // array_sheet di distinte selezionabili per la conatabilizzazione TDistinta *_distinta; // Distinta per le elaborazioni TPartite_array *_part_array; // Array di partite da scrivere TMovimentoPN *_movimento; // Movimento di prima nota TCausale *_caus; // Causale contabile per le elaborazioni error_type _error; // Errore rilevato durante l'elaborazione long _total_bills; // Totale distinte contabilizzate. int _cur_dist_row;// Numero di riga distinta corrente (per visualizzazione errore) protected: // TApplication // Compila la testata del movimento void compile_head_mov(); // Compila la riga di partita void compile_riga_partita(TRiga_partite& riga, const TEffetto& effetto, const TRectype& riga_effetto); // Compila la riga di pagamento void compile_riga_pagamento(TRectype& riga_pagamento, const TEffetto& effetto, const TRectype& riga_effetto, char acc_sal); // scrive il movimento e le scadenze error_type write_all(bool chage_status = TRUE); // cerca il conto di contropartita per la distinta corrente (setta _banca) error_type search_bank_counter_bill(int tipopag=0); // cerca il conto clienti error_type search_clifo_bill(char tipo, const long codcf); // ritorna la sezione corretta per la riga di partita char sezione() const; // aggiunge una riga all'array dei clienti da una riga effetto bool add_cg_row(const TEffetto& eff, const TRectype& reff, TArray& customers, TAssoc_array& banks, bool add_desc); // aggiunge riga pagamento da riga effetto void compile_saldac(const TEffetto& eff, const TRectype& reff, TImporto& abbuoni_att, TImporto& abbuoni_pas, TImporto& differenze_cam, TArray& customers); // Controlla se il pagamento dell'effetto avra' differenze cambio bool has_diffcam(const TEffetto& eff) const; // unisce gli array clienti/banche nel record array delle righe contabili void join_rows(TArray& customers, TAssoc_array& banks, const TImporto& abbuoni_att, const TImporto& abbuoni_pas, const TImporto& differenze_cam); // Visualizza l'ultimo errore rilevato void display_error(); // Contabilizza l'effetto corrente void contabilize_bill(const char tipo, const long numero); // Contabilizza gli effetti void contabilize(); // costruisce lo sheet delle distinte void build_dist_sheet(); // Handler della selezione distinte static bool handle_select(TMask_field& f, KEY k); // Handler del pulsante di reset static bool handle_reset(TMask_field& f, KEY k); // Le 4 seguenti non hanno bisogno di commenti virtual void main_loop(); virtual bool create(); virtual bool destroy(); virtual void on_config_change(); public: // Verifica se non ci sono stati errori bool good() const { return _error == no_error;} error_type status() { return _error; } void set_status(error_type e) { _error = e; } TContabilizzazione_effetti_app() : _msk(NULL) {} virtual ~TContabilizzazione_effetti_app() { } }; inline TContabilizzazione_effetti_app& app() { return (TContabilizzazione_effetti_app&) main_app(); } void TContabilizzazione_effetti_app::build_dist_sheet() { TRelation eff_rel(LF_EFFETTI); // TRectype da(LF_EFFETTI),a(LF_EFFETTI); TCursor cur_dist(&eff_rel,"TIPODIST!=\"\"",4); //,&da,&a); TRectype& rec = cur_dist.curr(); const long items = cur_dist.items(); _dist_sheet->destroy(); // resetta lo sheet delle distinte if (items > 0) { cur_dist = 0; long ndist_prec = rec.get_long(EFF_NDIST); char tipo_prec = rec.get_char(EFF_TIPODIST); TString16 codabi; TString16 codcab; bool enabled = TRUE; int num_eff = 0; for (long i = 0; i< items; i++) { cur_dist = i; const long ndist = rec.get_long(EFF_NDIST); const char tipo = rec.get_char(EFF_TIPODIST); if (ndist != ndist_prec || tipo != tipo_prec) { TToken_string * t = new TToken_string; t->add(" ");t->add(tipo_prec); t->add(ndist_prec); t->add(num_eff); t->add(codabi); t->add(codcab); const long pos = _dist_sheet->add(t); //aggiunge una riga allo sheet delle distinte _dist_sheet->enable_row(pos, enabled); ndist_prec = ndist; tipo_prec = tipo; enabled = TRUE; num_eff = 0; } num_eff++; // numero di effetti che compongono la distinta codabi = rec.get(EFF_CODABIP); codcab = rec.get(EFF_CODCABP); enabled &= !rec.get_bool(EFF_EFFCONT); } TToken_string * t = new TToken_string; t->add(" ");t->add(tipo_prec); t->add(ndist_prec); t->add(num_eff); t->add(codabi); t->add(codcab); const long pos = _dist_sheet->add(t); //aggiunge una riga allo sheet delle distinte _dist_sheet->enable_row(pos, enabled); } } bool TContabilizzazione_effetti_app::handle_reset(TMask_field& f, KEY k) { if (k == K_SPACE) { app()._dist_sheet->check(-1, FALSE); f.mask().reset(F_DISTINTE); } return TRUE; } bool TContabilizzazione_effetti_app::handle_select(TMask_field& f, KEY k) { if (k==K_SPACE) // ricerca { TArray_sheet* sh = app()._dist_sheet; if (sh->run() == K_ENTER) f.mask().set(F_DISTINTE,sh->checked()); } return TRUE; } void TContabilizzazione_effetti_app::on_config_change() { TPartita::carica_allineamento(); } bool TContabilizzazione_effetti_app::create() { TConfig conf(CONFIG_DITTA, "ef"); _cod_caus = conf.get("CODCAUS"); // implementare programma di gestione parametri effetti _cod_caus_pag = conf.get("CODCAUSPAG"); // implementare programma di gestione parametri effetti _desc_inc = conf.get("DESCINC", NULL, -1, "Distinta d'incasso"); _desc_pag = conf.get("DESCPAG", NULL, -1, "Ordine di pagamento"); _caus = NULL; _sc_enabled = conf.get_bool("GesSal","cg"); if (!has_module(CGAUT) && _sc_enabled) { error_box("Impossibile eseguire il programma se il modulo Contabilita' Generale non e' abilitato"); return FALSE; } _error = no_error; _can_write = TRUE; _msk = new TMask("ef0800a"); _msk->set_handler(F_SELECT,handle_select); _msk->set_handler(F_RESET,handle_reset); _cpg = new TTable("%CPG"); _bnp = new TTable("BNP"); _fcaus = new TLocalisamfile(LF_CAUSALI); _frcaus = new TLocalisamfile(LF_RCAUSALI); _effetti = new TLocalisamfile(LF_EFFETTI); _reffetti = new TLocalisamfile(LF_REFFETTI); _cessionari = new TLocalisamfile(LF_CESS); _part = new TLocalisamfile(LF_PARTITE); _scad = new TLocalisamfile(LF_SCADENZE); _pags = new TLocalisamfile(LF_PAGSCA); _attiv = new TLocalisamfile(LF_ATTIV); // Altrimenti TRegistro non va! _clifo = new TLocalisamfile(LF_CLIFO); _doc = new TLocalisamfile(LF_DOC); _pcon = new TLocalisamfile(LF_PCON); _distinta = new TDistinta; _movimento = new TMovimentoPN; _dist_sheet = new TArray_sheet(-1, -1, -4, -4, "Selezione distinte", "@1|Tipo|Numero distinta@R|Numero effetti@R|ABI@5|CAB@5"); _part_array = new TPartite_array; return TSkeleton_application::create(); } bool TContabilizzazione_effetti_app::destroy() { if (_msk) delete _msk; if (_cpg) delete _cpg; if (_bnp) delete _bnp; if (_fcaus) delete _fcaus; if (_frcaus) delete _frcaus; if (_effetti) delete _effetti; if (_reffetti) delete _reffetti; if (_cessionari) delete _cessionari; if (_part) delete _part; if (_scad) delete _scad; if (_pags) delete _pags; if (_attiv) delete _attiv; if (_clifo)delete _clifo; if (_doc)delete _doc; if (_pcon)delete _pcon; if (_caus) delete _caus; if (_distinta) delete _distinta; if (_movimento) delete _movimento; if (_dist_sheet) delete _dist_sheet; if (_part_array) delete _part_array; return TApplication::destroy(); } void TContabilizzazione_effetti_app::main_loop() { build_dist_sheet(); // Preselezione della distinta specificata sulla riga di comando if (argc() >= 4) { const char tip = *argv(2); const long num = atol(argv(3)); for (int r = 0; r < _dist_sheet->items(); r++) { TToken_string& row = _dist_sheet->row(r); if (row.get_char(1) == tip && row.get_long(2) == num) { _dist_sheet->check(r); break; } } _msk->set(F_DISTINTE, _dist_sheet->checked()); } while (_msk->run() == K_ENTER) { if (!_dist_sheet->one_checked()) { error_box("Nessuna distinta selezionata"); continue; } _data_op = _msk->get_date(F_DATA_OP); if (!_data_op.ok()) _data_op = TODAY; // if (_caus != NULL) delete _caus; // _caus = new TCausale(_cod_caus,_data_op.year()); // if (!_caus->ok()) // { // error_box("Causale contabile non valida o non presente in parametri effetti"); // continue; // } TEsercizi_contabili esc; esc.update(); _cod_es = esc.date2esc(_data_op); if (_cod_es <= 0) { error_box("La data operazione non appartiene a nessun esercizio"); continue; } contabilize(); _msk->reset(F_DISTINTE); build_dist_sheet(); } } void TContabilizzazione_effetti_app::display_error() { TString msg; switch (_error) { case clifo_error: msg.format("Non e' possibile reperire il cliente/fornitore relativamente alla distinta %c %ld. " "Controllare la riga %d",_distinta->tipodist(), _distinta->ndist(),_cur_dist_row+1); break; case bank_error: msg.format("Non e' possibile reperire i conti di contropartita per la banca di presentazione " "relativamente alla distinta %c %ld. Controllare la tabella e la causale.",_distinta->tipodist(), _distinta->ndist()); break; case cau_abb_error: msg.format("Non e' possibile reperire i conti per gli abbuoni\n" " o le differenze cambi dalla causale '%s'", _caus->codice()); break; default: // Errori generici o non indicati vengono visualizzati nel punto dell'errore break; } warning_box(msg); _error = no_error; // reset error, as any other one would do, so you can show me the other ones. _can_write = FALSE; // But from now on u cannot write anymore. U must exit this program and repair errors occurred. } bool TContabilizzazione_effetti_app::add_cg_row(const TEffetto& eff, const TRectype& reff, TArray& customers, TAssoc_array& banks, bool add_desc) { const long numreg = _movimento->curr().get_long(MOV_NUMREG); real imp = reff.get_real(REFF_IMPORTO); TRectype* c_rec = new TRectype(LF_RMOV); // setta i valori per la riga cliente c_rec->put(RMV_ANNOES,_cod_es); c_rec->put(RMV_DATAREG,_data_op); c_rec->put(RMV_NUMREG,numreg); c_rec->put(RMV_SEZIONE,_caus->sezione_clifo()); c_rec->put(RMV_TIPOC,_cliente.tipo()); c_rec->put(RMV_GRUPPO,_cliente.gruppo()); c_rec->put(RMV_CONTO,_cliente.conto()); c_rec->put(RMV_SOTTOCONTO,_cliente.sottoconto()); c_rec->put(RMV_ROWTYPE,"K"); TString80 desc = _cliente.tipo() == 'F' ? "Pag. ft." : "Inc. ft."; desc << ' ' << reff.get(REFF_NFATT); c_rec->put(RMV_DESCR, desc); if (add_desc) { TString80 head_desc = _movimento->curr().get(MOV_DESCR); head_desc << ' ' << desc; _movimento->curr().put(MOV_DESCR, head_desc); } // setta i valori per la riga banca TRectype b_r(*c_rec); TString16 key; key.format("%3d%3d%6ld",_banca.gruppo(),_banca.conto(),_banca.sottoconto()); const bool is_present = banks.is_key(key); TRectype& b_rec = is_present ? (TRectype&)banks.find(key) : b_r; // setta i valori if (!is_present) // nuova banca? allora setta la sezione ed il conto { const int tipopag = eff.get_int(EFF_TIPOPAG); int nriga = 2; if (_sc_enabled && tipopag>1 && tipopag<8) nriga = tipopag+1; b_rec.put(RMV_SEZIONE,_caus->sezione(nriga)); b_rec.put(RMV_TIPOC,_banca.tipo()); b_rec.put(RMV_GRUPPO,_banca.gruppo()); b_rec.put(RMV_CONTO,_banca.conto()); b_rec.put(RMV_SOTTOCONTO,_banca.sottoconto()); b_rec.put(RMV_ROWTYPE,"I"); b_rec.zero(RMV_DESCR); } real b_imp = b_rec.get_real(RMV_IMPORTO) + imp; // aggiorna l'importo per questa banca b_rec.put(RMV_IMPORTO,b_imp); banks.add(key,b_rec,is_present); c_rec->put(RMV_IMPORTO,imp); customers.add(c_rec); return !is_present; } void TContabilizzazione_effetti_app::join_rows(TArray& customers, TAssoc_array& banks, const TImporto& abbuoni_att, const TImporto& abbuoni_pas, const TImporto& differenze_cam) { // aggiunge prima i record delle righe relative ai clienti int j=0,i=0; const int customer_items = customers.items(); for (j=0; jcg(i++) = (TRectype&) customers[j]; _movimento->cg(i-1).put(RMV_NUMRIG,i); } // e poi i record delle righe relative alle banche const int bank_items = banks.items(); TRectype* row; for (j=0,row = (TRectype *)banks.first_item(); row != NULL && jcg(i++) = *row; _movimento->cg(i-1).put(RMV_NUMRIG,i); } // infine abbuoni e differenze cambio if (i > 0 && _sc_enabled) { TBill zio; TRectype riga(_movimento->cg(0)); if (!abbuoni_pas.is_zero()) { _caus->bill(9, zio); zio.put(riga); if (!zio.ok()) _error = cau_abb_error; riga.put(RMV_SEZIONE, abbuoni_pas.sezione()); riga.put(RMV_IMPORTO, abbuoni_pas.valore()); riga.put(RMV_ROWTYPE, "P"); _movimento->cg(i++) = riga; _movimento->cg(i-1).put(RMV_NUMRIG,i); } if (!abbuoni_att.is_zero()) { _caus->bill(10, zio); zio.put(riga); if (!zio.ok()) _error = cau_abb_error; riga.put(RMV_SEZIONE, abbuoni_att.sezione()); riga.put(RMV_IMPORTO, abbuoni_att.valore()); riga.put(RMV_ROWTYPE, "A"); _movimento->cg(i++) = riga; _movimento->cg(i-1).put(RMV_NUMRIG,i); } if (!differenze_cam.is_zero()) { _caus->bill(13, zio); zio.put(riga); if (!zio.ok()) _error = cau_abb_error; riga.put(RMV_SEZIONE, differenze_cam.sezione()); riga.put(RMV_IMPORTO, differenze_cam.valore()); riga.put(RMV_ROWTYPE, "C"); _movimento->cg(i++) = riga; _movimento->cg(i-1).put(RMV_NUMRIG,i); } } } error_type TContabilizzazione_effetti_app::search_clifo_bill(char tipo, const long codcf) { _error = no_error; _clifo->put(CLI_TIPOCF, tipo); _clifo->put(CLI_CODCF,codcf); _cliente.set(0,0,0); if (_clifo->read() == NOERR) _cliente.set(_clifo->get_int(CLI_GRUPPO),_clifo->get_int(CLI_CONTO),codcf, tipo); if (!_cliente.ok()) // se non e' valido, reperiscilo dalla riga #1 della causale { _caus->bill(1,_cliente); // conto della riga 1 _cliente.codclifo() = codcf; if (!_cliente.ok()) _error = clifo_error; } return _error; } error_type TContabilizzazione_effetti_app::search_bank_counter_bill(int tipopag) { // reperisce i codici ABI e CAB della banca presentazione effetti dalla // distinta e va a cercarli sulla tabella BNP di ditta. // La banca di presentazione effetti e' una unica per tutta la distinta // e non puo' essere vuota _error = no_error; if (tipopag == 0) // cerca sulla tabella e poi sulla 2a riga di causale { TString16 codtab(_distinta->abip()); codtab << _distinta->cabp(); const char tipodist = _distinta->tipodist(); _banca.set(0,0,0); // resetta il conto... _bnp->put("CODTAB",codtab); if (_bnp->read() == NOERR) { TString16 fg("I0"),fc("I1"),fs("I2"); // nel caso tipodist == DIST_INCASSO if (tipodist == DIST_SBF) { fg = "I3"; fc = "I4"; fs = "I5"; } else if (tipodist == DIST_SCONTO) { fg = "I6"; fc = "I7"; fs = "I8"; } const int g = (int) _bnp->get_long(fg); const int c = (int) _bnp->get_long(fc); const long s = _bnp->get_long(fs); _banca.set(g,c,s); } // se non ha trovato la banca oppure il conto, verifica che vi sia // il conto sulla riga 2 della causale (solo se SC non abilitato) if (!_banca.ok() && !_sc_enabled) _caus->bill(2,_banca); // conto della riga 2 // se il saldaconto non e' abilitato, il conto di contropartita sulla causale // va verificato per ogni riga di distinta, a seconda del tipo di pagamento. } else { // 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 _caus->bill(tipopag>0 && tipopag<8 ? tipopag+1:2,_banca); } if (!_banca.ok()) _error = bank_error; return _error; } char TContabilizzazione_effetti_app::sezione() const { char sezione = ' '; const char tipoc = _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; } void TContabilizzazione_effetti_app::compile_head_mov() { CHECK(_caus,"Causale non allocata"); TLocalisamfile& mov = _movimento->lfile(); mov.last(); const long numreg = mov.get_long(MOV_NUMREG)+1; // Calcola il numero di registrazione const TDate datadist = _distinta->data_dist(); const TDate datacam = _distinta->data_cam(); const TString16 codval = _distinta->codval(); const real cambio = _distinta->cambio(); const bool eurocambio = _distinta->contro_euro(); const long ndist = _distinta->ndist(); TString des; des = (_distinta->tipocf() == 'F') ? _desc_pag : _desc_inc; des << ' '; switch (_distinta->tipopag()) { case 1: des << "rimessa diretta"; break; case 2: des << "tratta"; break; case 3: des << "ricevuta bancaria"; break; case 4: des << "cessione"; break; case 5: des << "paghero'"; break; case 6: des << "lettera di credito"; break; case 7: des << "tratta accettata"; break; case 8: des << "rapp. interb. dir."; break; case 9: des << "bonifico"; break; default: des.rtrim(); break; } des << " n." << ndist; mov.zero(); mov.put(MOV_DESCR,des); mov.put(MOV_NUMREG,numreg); mov.put(MOV_ANNOES,_cod_es); mov.put(MOV_DATAREG,_data_op); mov.put(MOV_DATACOMP,_data_op); mov.put(MOV_DATADOC,datadist); mov.put(MOV_NUMDOC,ndist); mov.put(MOV_TIPODOC,_caus->tipo_doc()); mov.put(MOV_CODCAUS,_caus->codice()); mov.put(MOV_CODVAL,codval); mov.put(MOV_DATACAM,datacam); mov.put(MOV_CAMBIO,cambio); if (eurocambio && cambio > ZERO) { if (mov.curr().exist(MOV_CONTROEURO)) mov.put(MOV_CONTROEURO, eurocambio); else mov.put(MOV_CAMBIO, real(1936.27) / cambio); } // MOV_TOTDOC e MOV_TOTDOCVAL vengono completati prima della scrittura del movimento } void TContabilizzazione_effetti_app::compile_riga_partita(TRiga_partite& riga, const TEffetto& effetto, const TRectype& riga_effetto) { TLocalisamfile& head_mov = _movimento->lfile(); riga.put(PART_TIPOMOV,_caus->tipomov()); riga.put(PART_TIPOPAG,effetto.get_int(EFF_TIPOPAG)); riga.put(PART_NREG,head_mov.get_long(MOV_NUMREG)); riga.put(PART_NUMRIG,_cur_dist_row+1); // Nelle righe del movimento le righe clienti vengono prima delle banche // percio' vi e' una corrispondenza 1 a 1 riga.put(PART_DATAREG,head_mov.get_date(MOV_DATAREG)); riga.put(PART_DATADOC,head_mov.get_date(MOV_DATADOC)); riga.put(PART_DATAPAG,effetto.get_date(EFF_DATASCAD)); riga.put(PART_NUMDOC,head_mov.get(MOV_NUMDOC)); // Sarebbe il numero della distinta... // La descrizione della riga (PART_DESCR) la lascio vuota. // Verificare con Guy le regole necessarie per la sua compilazione eventuale riga.put(PART_SEZ,sezione()); const real imp = riga_effetto.get_real(REFF_IMPORTO); const real imp_val = riga_effetto.get_real(REFF_IMPORTOVAL); /* Non scrivo qui gli importi: li sommo quando faccio i pagamenti riga.put(PART_IMPORTO,imp); riga.put(PART_IMPORTOVAL,imp_val); */ riga.put(PART_CODVAL,effetto.get(EFF_CODVAL)); riga.put(PART_DATACAM,effetto.get_date(EFF_DATACAMBIO)); real cambio = effetto.get(EFF_CAMBIO); riga.put(PART_CAMBIO, cambio); if (effetto.get_bool(EFF_CONTROEURO)) { if (!((TRectype&)riga).exist(PART_CONTROEURO)) { if (cambio > ZERO) { cambio = real(1936.27) / cambio; riga.put(PART_CAMBIO, cambio); } } else riga.put(PART_CONTROEURO, TRUE); } riga.put(PART_TIPOCF,_cliente.tipo()); riga.put(PART_SOTTOCONTO,_cliente.sottoconto()); riga.put(PART_IMPTOTDOC,effetto.get(EFF_IMPORTO)); riga.put(PART_IMPTOTVAL,effetto.get(EFF_IMPORTOVAL)); // PART_GRUPPOCL e PART_CONTOCL sono gia' compilati dalla TPartita::new_row() // Aggiorna il totale movimento in lire e totale movimento in valuta (solo con saldaconto abilitato) if (_sc_enabled) { _total_mov += imp; _total_mov_val += imp_val; } } void TContabilizzazione_effetti_app::compile_riga_pagamento(TRectype& riga_pagamento, const TEffetto& effetto, const TRectype& riga_effetto, char acc_sal) { // ANNO, NUMPART, NRIGA, NRATA, NRIGP dovrebbero essere gia' compilati riga_pagamento.put(PAGSCA_TIPOC,_cliente.tipo()); riga_pagamento.put(PAGSCA_SOTTOCONTO,_cliente.sottoconto()); riga_pagamento.put(PAGSCA_ACCSAL,acc_sal); riga_pagamento.put(PAGSCA_IMPORTO,riga_effetto.get_real(REFF_IMPORTO)); riga_pagamento.put(PAGSCA_IMPORTOVAL,riga_effetto.get_real(REFF_IMPORTOVAL)); riga_pagamento.put(PAGSCA_TIPOCC,_banca.tipo()); riga_pagamento.put(PAGSCA_GRUPPOC,_banca.gruppo()); riga_pagamento.put(PAGSCA_CONTOC,_banca.conto()); riga_pagamento.put(PAGSCA_SOTTOCONTC,_banca.sottoconto()); riga_pagamento.put(PAGSCA_CODABI, effetto.get(EFF_CODABI)); riga_pagamento.put(PAGSCA_CODCAB, effetto.get(EFF_CODCAB)); riga_pagamento.put(PAGSCA_CODABIPR, effetto.get(EFF_CODABIP)); riga_pagamento.put(PAGSCA_CODCABPR, effetto.get(EFF_CODCABP)); // Cerca l'eventuale codice agente sul documento _doc->put(DOC_PROVV,riga_effetto.get(REFF_PROVV)); _doc->put(DOC_ANNO,riga_effetto.get(REFF_ANNODOC)); _doc->put(DOC_CODNUM,riga_effetto.get(REFF_CODNUM)); _doc->put(DOC_NDOC,riga_effetto.get(REFF_NFATT)); if (_doc->read() == NOERR) riga_pagamento.put(PAGSCA_CODAG,_doc->get(DOC_CODAG)); } void TContabilizzazione_effetti_app::compile_saldac(const TEffetto& eff, const TRectype& reff, TImporto& abbuoni_att, TImporto& abbuoni_pas, TImporto& differenze_cam, TArray& customers) { int anno = reff.get_int(REFF_ANNO); TString16 numpart = reff.get(REFF_NUMPART); // Ricava il numero della fattura.. TString16 numdoc_to_search = reff.get(REFF_CODNUM); long nfatt = reff.get_long(REFF_NFATT); TCodice_numerazione cn; if (numdoc_to_search.not_empty() && nfatt > 0L) { cn.read(numdoc_to_search); numdoc_to_search = cn.complete_num(nfatt); } else // se gli estremi della fattura non sono compilati si piglia il numero della partita numdoc_to_search = numpart; if (anno == 0 || numpart.empty()) // Se non sono gia' settati sulla riga effetto... { anno = reff.get_int(REFF_ANNODOC);// ... li va prendere dagli estremi fattura... if (numdoc_to_search.not_empty()) { numpart = numdoc_to_search; } else // ...oppure dalla testata movimento. { // Appunto: da verificare se facciamo cosi' o generiamo un errore... anno = eff.get_date(EFF_DATADIST).year(); const char all = TPartita::allineamento_richiesto(eff.get_char(EFF_TIPOCF)); if (all == 'R') numpart.format("%7ld", eff.get_long(EFF_NDIST)); else numpart.format("%ld", eff.get_long(EFF_NDIST)); numdoc_to_search = numpart; // A mali estremi... estremi rimedi } } TPartita * partita = _part_array->exist(_cliente,anno,numpart); if (partita == NULL) // Se la partita non esiste nell'array la aggiunge { partita = new TPartita(_cliente,anno,numpart); _part_array->insert(partita); } TRiga_partite& riga_part = partita->new_row(); // Compila la riga di partita compile_riga_partita(riga_part,eff,reff); // Compila la riga di pagamento: // reperire il numero della riga partita (nrigp) appena aggiunta const int nrigp = riga_part.get_int(PART_NRIGA); ((TRectype&)reff).put(REFF_NRIGP, nrigp); // scorrere le righe della partita (nriga) per trovare il riferimento alla fattura di cui si sta effettuando il pagamento // se non la si trova allora... nriga = UNASSIGNED const int uns = (int) TPartita::UNASSIGNED; int nriga = reff.get_int(REFF_NRIGA); if (nriga == 0 || nriga == uns) { nriga = uns; for (int r = partita->last(); r > 0; r = partita->pred(r)) { const TRiga_partite& rpart = partita->riga(r); const TString16 numdoc = rpart.get(PART_NUMDOC); if (numdoc == numdoc_to_search && rpart.is_fattura()) { nriga = r; break; } } } // reperire il numero di rata (nrata) dalla riga effetto int nrata = reff.get_int(REFF_NRATA); char acc_sal = 'A'; if (partita->esiste(nriga,nrata)) // calcola se e' a saldo o in acconto della rata { acc_sal = reff.get_char(REFF_ACCSAL); if (acc_sal != 'S') { TRiga_scadenze& riga_scadenza = partita->rata(nriga,nrata); TImporto residuo_scadenza(riga_scadenza.residuo(FALSE)); if (residuo_scadenza.valore() <= reff.get_real(REFF_IMPORTO)) acc_sal = 'S'; else acc_sal = 'A'; // Potrebbe succedere che il ACCSAL sia vuoto } } else { if (nriga != uns) nriga = uns; // E' praticamente impossibile che si trovi la fattura // senza le proprie scadenze. Al limite settiamo il numero di riga per non assegnati. } // Creo una nuova riga di pagamento TRectype& old_riga_pagamento = partita->pagamento(nriga,nrata,nrigp); // compilo i campi di riga_pagamento TRectype riga_pagamento(old_riga_pagamento); compile_riga_pagamento(riga_pagamento,eff,reff, acc_sal); // Aggiorno il pagamento generando eventuali abbuoni char old_ap, new_ap; TImporto old_abb, new_abb, old_diffcam, new_diffcam; const TString16 codval = eff.get(EFF_CODVAL); const TDate datacam = eff.get(EFF_DATACAMBIO); const real cambio = eff.get(EFF_CAMBIO); const TValuta valuta_eff(codval, datacam, cambio); partita->modifica_pagamento(riga_pagamento, valuta_eff, old_ap, old_abb, old_diffcam, new_ap, new_abb, new_diffcam, TRUE); // Se ci sono abbuoni o differenze cambio... if (!new_abb.is_zero() || !new_diffcam.is_zero()) { if (new_ap == 'A') { abbuoni_att -= new_abb; // Sottraggo perche' va in sezione opposta abbuoni_att.normalize(); } if (new_ap == 'P') { abbuoni_pas -= new_abb; // Sottraggo perche' va in sezione opposta abbuoni_pas.normalize(); } if (!new_diffcam.is_zero()) { differenze_cam -= new_diffcam; // Sottraggo perche' va in sezione opposta differenze_cam.normalize(); } TRectype& last = (TRectype&)customers[customers.last()]; TImporto imp(last.get_char(RMV_SEZIONE), last.get_real(RMV_IMPORTO)); imp += new_abb; // Incremento con abbuoni imp += new_diffcam; // Incremento con differenze cambi last.put(RMV_SEZIONE, imp.sezione()); last.put(RMV_IMPORTO, imp.valore()); } } error_type TContabilizzazione_effetti_app::write_all(bool change_status) { TRectype& head = _movimento->lfile().curr(); head.put(MOV_TOTDOC,_total_mov); head.put(MOV_TOTDOCVAL,_total_mov_val); long orig_numreg, numreg = head.get_long(MOV_NUMREG); orig_numreg = numreg; while (_movimento->write() == _isreinsert) head.put(MOV_NUMREG,++numreg); if (_movimento->status() != NOERR) { error_box("E' stato rilevato l'errore %d scrivendo il movimento %ld.",_movimento->status(),numreg); _error = generic_error; } if (good()) // nessun errore ? { if (_sc_enabled) // Debbo scrivere anche le partite ? { if (numreg > orig_numreg) // Ha effettuato una rinumerazione ? { // Allora scorre le partite in _part_array e aggiorna il campo NREG delle righe di ognuna for (TPartita * p = _part_array->first(); p != NULL; p = _part_array->next()) // Scorre le righe della partita corrente for (int n = p->last(); n > 0; n = p->pred(n)) { TRiga_partite& riga = p->riga(n); if (riga.get_long(PART_NREG) == orig_numreg) // sostituisce il numero registrazione con quello nuovo riga.put(PART_NREG, numreg); } } if (!_part_array->write()) // L'errore viene gia' segnalato dalla partita _error = generic_error; } if (good() && change_status) // deve anche cambiare lo stato alla distinta ? { TDistinta& distinta = *_distinta; const int items = distinta.items(); for (int n = 0; n < items; n++) { TRectype& eff = distinta[n]; eff.put(EFF_EFFCONT, TRUE); eff.put(EFF_NUMREG, numreg); } int err = distinta.rewrite(); if (err != NOERR) { error_box("E' stato rilevato l'errore %d aggiornando lo stato della distinta %c %ld.",err,distinta.tipodist(),distinta.ndist()); _error = generic_error; } } } return _error; } bool TContabilizzazione_effetti_app::has_diffcam(const TEffetto& eff) const { bool yes = FALSE; real cambio = eff.get(EFF_CAMBIO); if (cambio > ZERO) { if (eff.get_bool(EFF_CONTROEURO)) { cambio = real(1936.27) / cambio; cambio.round(5); } TLocalisamfile partite(LF_PARTITE); for (int n = 1; yes == FALSE && n <= eff.rows_r(); n++) { const TRectype& riga = eff.row_r(n); partite.put(PART_TIPOCF, eff.get(EFF_TIPOCF)); partite.put(PART_GRUPPO, 0); partite.put(PART_CONTO, 0); partite.put(PART_SOTTOCONTO, eff.get(EFF_CODCF)); partite.put(PART_ANNO, riga.get(REFF_ANNO)); partite.put(PART_NUMPART, riga.get(REFF_NUMPART)); partite.put(PART_NRIGA, riga.get(REFF_NRIGA)); int err = partite.read(); if (err == NOERR) { const real cambiofatt = partite.get(PART_CAMBIO); yes = cambiofatt != cambio; } else NFCHECK("Effetto pagante fattura fantasma"); } } return yes; } void TContabilizzazione_effetti_app::contabilize_bill(const char tipo, const long numero) { TDistinta& distinta = *_distinta; TLocalisamfile& mov = _movimento->lfile(); // tiene 2 array di record separati: uno per i clienti ed uno per le banche, // alla fine, prima di scrivere il movimento, li riunisce nel record array di // _movimento, per metterli in ordine, prima le righe clienti e poi le righe delle banche // L'array delle banche e' un assoc_array, con indice sul gruppo/conto/sottoconto // per effettuare il raggruppamento TArray customers; TAssoc_array banks; TImporto abbuoni_att, abbuoni_pas, differenze_cam; bool reset_bank = FALSE; _total_mov = 0.0; _total_mov_val = 0.0; distinta.read(tipo,numero,_lock); // Sblocca da solo quella precedente if (_caus != NULL) delete _caus; const char* cc = distinta.tipocf() == 'C' ? _cod_caus : _cod_caus_pag; _caus = new TCausale(cc, _data_op.year()); if (!_caus->ok()) { error_box("Causale '%s' non valida o non presente in parametri effetti", cc); return; } //Cerca il conto della contropartita della banca di presentazione. //Nel caso in cui sia presente sulla tabella BNP (selezione anche per //tipo distinta) il conto sara' unico per tutti; se invece non e' presente sul file oppure il conto //di contropartita e' vuoto, andra' reperito per ogni effetto, a seconda della causale //impostata e del tipo di pagamento (quest'ultimo solo nel caso di saldaconto abilitato); altrimenti si //terra' per buono sempre quello della seconda riga della casuale . //E' chiaro che nella maggioranza dei casi si avra' sempre un unico conto di contropartita, definito //nella tabella BNP. //Non meno importante: nel caso avessimo piu' conti di contropartita per le banche //si dovra' procedere ad un raggruppamento, sommando gli importi (mentre invece le righe //clienti non dovranno subire tale procedimento. //Infine: a causa del cazzutissimo limite di 99 righe contabili settato in invii/ricezioni //si dovranno generare piu' movimenti per un stessa distinta se le righe eccedono tale //valore (come avere le palle sopra un'incudine ed una mazza ferrata che sta per piombare a tutta forza...) search_bank_counter_bill(); if (!good()) return; // _error's already set const int items = distinta.items(); // Perche' sul file effetti il numero riga distinta e' un long ?? int nrows=0; // numero di righe contabili generate // compila la testata compile_head_mov(); // _cur_dist_row e' un int sebbene su file sia un long: TArray::items() ritorna un int!! for (_cur_dist_row = 0; _cur_dist_row ZERO && eff.get_bool(EFF_CONTROEURO)) cambio = real(1936.27) / cambio; if (!good()) break; // se la banca non e' stata settata cerca il conto sulla causale a seconda del tipo di pagamento di questo effetto if (!_banca.ok()) { search_bank_counter_bill(eff.get_int(EFF_TIPOPAG)); reset_bank = TRUE; // forza la ricerca del conto della banca ad ogni riga distinta } // incrementa il numero di righe contabili generate fino ad ora. // per i clienti e' sempre vero, mentre per le banche dipende se e' stato fatto un // raggruppamento if (!good()) break; const bool diff_cam = has_diffcam(eff); for (int n = 1; n <= eff.rows_r(); n++) { if (nrows > 0 && diff_cam) // Se ci sono differenze cambio ... nrows = CGROWS_LIMIT; // ... allora forza cambio movimento if (nrows >= CGROWS_LIMIT) // se sono arrivato al limite massimo, scrivo questo movimento { // Unisce le righe banche e clienti nel record_array delle righe contabili if (good() && _can_write) { join_rows(customers, banks, abbuoni_att, abbuoni_pas, differenze_cam); if (good()) write_all(FALSE); // non cambiare lo stato della distinta, cambialo solo alla fine } if (good()) { _movimento->destroy_rows(mov.get_long(MOV_NUMREG)); // azzera le righe.. _part_array->destroy(); // e l'array delle partite customers.destroy(); banks.destroy(); abbuoni_att = abbuoni_pas = differenze_cam = TImporto('A', ZERO); _total_mov = 0.0; _total_mov_val = 0.0; // compila la testata del nuovo movimento compile_head_mov(); } } if (!good()) break; const TRectype& riga = eff.row_r(n); add_cg_row(eff, riga, customers, banks, diff_cam); if (_sc_enabled) compile_saldac(eff, riga,abbuoni_att, abbuoni_pas, differenze_cam, customers); nrows = customers.items() + banks.items(); if (_sc_enabled) { if (!abbuoni_att.is_zero()) nrows++; if (!abbuoni_pas.is_zero()) nrows++; if (!differenze_cam.is_zero()) nrows++; } } if (reset_bank) _banca.set(0,0,0); } // Ciclo su effetti if (good() && _can_write) // scrive il movimento residuo ... { join_rows(customers, banks, abbuoni_att, abbuoni_pas, differenze_cam); if (good() && write_all() == no_error) // Se la scrittura e' andata ok... _total_bills++; // incrementa il numero di distinte contabilizzate } _movimento->destroy_rows(mov.get_long(MOV_NUMREG)); // azzera le righe.. _part_array->destroy(); // e l'array delle partite } void TContabilizzazione_effetti_app::contabilize() { _total_bills = 0; const long cur_items = _dist_sheet->items(); // Quante distinte in totale ? TProgind p(cur_items, "Contabilizzazione effetti", FALSE, TRUE); for (long j = 0; j < cur_items; j++) { p.setstatus(j+1); if (_dist_sheet->checked(j)) { TToken_string& t = _dist_sheet->row(j); const char tipo = t.get_char(1); const long numero = t.get_long(2); contabilize_bill(tipo,numero); if (!good()) display_error(); } } if (_total_bills > 0) message_box("Totale effetti contabilizzati: %ld",_total_bills); } int ef0800 (int argc, char* argv[]) { TContabilizzazione_effetti_app a; a.run(argc,argv,"Contabilizzazione effetti"); return TRUE; }