campo-sirio/ef/ef0800.cpp

1018 lines
38 KiB
C++
Raw Normal View History

/*
ef0800.cpp: programma di contabilizzazione effetti
Ho visto ombre di sconforto riemergere dal passato...
al largo dei bastioni di Orione
_|_|_
^/ . ..\^
___[=========]___
___-==++""" . /. . . \ . """++==-___
__-+"" __\ .. . . | .. . | . . . /__ ""+-__
/\__+-"" `-----=====\_ <O> _/=====-----' ""-+__/\
_/_/ ""="" \_\_
_________ .-~~~-..---..-~~~-. __________
-~.--<<<<<<<`-...--'.---.`--...-'>>>>>>>--.~-
=~~.-~ ````\\_`(`._.')'_//'''' ~-.~~=
[(o)/ ``.._..'' \(o)
.___________________ _-_
.\==============_=_/ ____.---'---`---.____
. \_ \ \----._________.----/
. \ \ / / `-_-'
. __,--`.`-'..'-_
. /____ ||
. `--.____,-'
Did you see my apogee ?
*/
#include <applicat.h>
#include <relation.h>
#include <tabutil.h>
#include <mask.h>
#include <sheet.h>
#include <urldefid.h>
#include <progind.h>
#include <modaut.h>
#include "../cg/cg2101.h"
#include "../cg/cg2103.h"
#include "../cg/cgsaldac.h"
#include "../ve/velib.h"
#include "ef0301.h"
#include "ef0800a.h"
#include <mov.h>
#include <rmov.h>
#include <rmoviva.h>
#include <clifo.h>
#include <effetti.h>
#include <pagsca.h>
#include <doc.h>
#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 TApplication
{
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
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
bool add_cg_row(const TRectype& eff, TArray& customers, TAssoc_array& _banks);
// 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 bool menu(MENU_TAG mt);
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()
{
TApplication::create();
TConfig conf(CONFIG_DITTA);
_cod_caus = conf.get("CODCAUS","ef"); // implementare programma di gestione parametri effetti
_cod_caus_pag = conf.get("CODCAUSPAG","ef"); // implementare programma di gestione parametri effetti
_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;
dispatch_e_menu(BAR_ITEM(1));
return TRUE;
}
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();
}
bool TContabilizzazione_effetti_app::menu(MENU_TAG mt)
{
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();
}
return FALSE;
}
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 TRectype& eff, TArray& customers, TAssoc_array& banks)
{
const long numreg = _movimento->curr().get_long(MOV_NUMREG);
real imp = eff.get_real(EFF_IMPORTO);
const int tipopag = eff.get_int(EFF_TIPOPAG);
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");
// 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
{
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");
}
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; j<customer_items;j++)
{
_movimento->cg(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 && j<bank_items;j++,row = (TRectype *)banks.succ_item())
{
_movimento->cg(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 long ndist = _distinta->ndist();
TString des;
des.format("Contabilizzazione distinta nr. %ld ",ndist, datadist.string());
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);
// MOV_TOTDOC e MOV_TOTDOCVAL vengono completati prima della scrittura del movimento
// e solo nel caso di saldaconto abilitato
}
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
real imp = riga_effetto.get_real(REFF_IMPORTO);
real imp_val = riga_effetto.get_real(REFF_IMPORTOVAL);
riga.put(PART_SEZ,sezione());
/* 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_CAMBIO,effetto.get_real(EFF_CAMBIO));
riga.put(PART_DATACAM,effetto.get_date(EFF_DATACAMBIO));
riga.put(PART_TIPOCF,_cliente.tipo());
riga.put(PART_SOTTOCONTO,_cliente.sottoconto());
riga.put(PART_IMPTOTDOC,effetto.get_real(EFF_IMPORTO));
riga.put(PART_IMPTOTVAL,effetto.get_real(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));
}
error_type TContabilizzazione_effetti_app::write_all(bool change_status)
{
TRectype& head = _movimento->lfile().curr();
head.put(MOV_TOTDOC,_total_mov); // Se il saldaconto non e' abilitato sono entrambi a 0.0
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);
}
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;
}
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<items; _cur_dist_row++) // scorre le righe della distinta (effetti)
{
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
//di _movimento
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);
nrows = 0;
_total_mov = 0.0;
_total_mov_val = 0.0;
// compila la testata del nuovo movimento
compile_head_mov();
}
}
if (!good()) break;
const TEffetto& eff = distinta[_cur_dist_row];
const long codcf = eff.get_long(EFF_CODCF);
const char tipo = eff.get_tipo();
search_clifo_bill(tipo, codcf);
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);
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;
if (add_cg_row(eff,customers,banks)) nrows++;
// Scorre le righe di effetto e setta il TPartite_array
if (_sc_enabled)
{
const int rows = eff.rows_r();
TCodice_numerazione cn;
TString16 numpart,numdoc_to_search;
int anno;
long nfatt;
for (int k = 1; k <= rows; k++)
{
// reperisce gli estremi della partita eventualmente pre-settati sulla riga
const TRectype& reff = eff.row_r(k);
anno = reff.get_int(REFF_ANNO);
numpart = reff.get(REFF_NUMPART);
// Ricava il numero della fattura..
numdoc_to_search = reff.get(REFF_CODNUM);
nfatt = reff.get_long(REFF_NFATT);
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_date(REFF_DATAFATT).year();
anno = reff.get_int(REFF_ANNODOC);// ... li va prendere dagli estremi fattura...
//numpart = reff.get(REFF_CODNUM);
//nfatt = reff.get_long(REFF_NFATT);
//if (numpart.not_empty() && nfatt > 0L)
if (numdoc_to_search.not_empty())
//{
// cn.read(numpart);
// numpart = cn.complete_num(nfatt);
//}
numpart = numdoc_to_search;
else // ...oppure dalla testata movimento.
{ // Appunto: da verificare se facciamo cosi' o generiamo un errore...
anno = distinta.data_dist().year();
numpart.format("%7ld", numero);
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
int nrigp = riga_part.get_int(PART_NRIGA);
// 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 = uns;
for (int r = partita->last(); r > 0; r = partita->pred(r))
{
TRiga_partite& rpart = partita->riga(r);
if (rpart.is_fattura() && rpart.get(PART_NUMDOC) == numdoc_to_search)
{
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;
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());
}
// completare se necessario i campi della riga effetto corrente (ANNO-NUMPART-NRIGA)
}
if (reset_bank)
_banca.set(0,0,0);
}
nrows++;
}
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()
{
TString msg;
_total_bills = 0;
const long cur_items = _dist_sheet->items(); // Quante distinte in totale ?
msg = "Contabilizzazione effetti";
#ifdef DBG
TProgind p(cur_items,msg,TRUE,TRUE,1);
#else
TProgind p(cur_items,msg,FALSE,TRUE,1);
#endif
long j = 0;
#ifdef DBG
for (;j<cur_items && !p.iscancelled();j++)
#else
for (;j<cur_items;j++)
#endif
{
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;
}