campo-sirio/cg/cg2107.cpp
guy cabf66ad4e Corretto calcolo prorata escludendo i beni ammortizzabili
git-svn-id: svn://10.65.10.50/branches/R_10_00@22992 c028cbd2-c16b-5b4b-a496-9718f37d4682
2014-09-22 13:53:19 +00:00

1171 lines
34 KiB
C++
Executable File

#include "cg2100.h"
#include "cg2102.h"
#include "cg2107.h"
#include "cg2100e.h"
#include "cgsalda3.h"
#include <urldefid.h>
#include <toolfld.h>
#include <treectrl.h>
///////////////////////////////////////////////////////////
// TNew_game_mask
///////////////////////////////////////////////////////////
class TNew_game_mask : public TAutomask
{
const TBill& _conto;
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
TNew_game_mask(const TBill& conto);
};
bool TNew_game_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
bool ok = true;
switch (o.dlg())
{
case 102: // Numero partita
if (e == fe_close)
{
const int anno = get_int(101); // ANNO
const TString& part = o.get(); // NUMPART
// Controlla partita in memoria
ok = !app().partite().exist(_conto, anno, part) || // Non esiste
app().partite().partita(_conto, anno, part).last()<=0; // Esiste ma non ha righe
if (ok)
{
const TPartita p(_conto, anno, part); // Controlla partita su disco
ok = p.last() <= 0;
}
if (!ok)
error_box(FR("La partita %d/%s esiste già"), anno, (const char*)part);
}
break;
default:
break;
}
return ok;
}
TNew_game_mask::TNew_game_mask(const TBill& conto)
: TAutomask(TR("Nuova partita"), 1, 24, 4), _conto(conto)
{
add_button_tool(DLG_OK, "", TOOL_OK);
add_button_tool(DLG_CANCEL, "", TOOL_CANCEL);
const char* flags = TPartita::allineamento_richiesto(_conto.tipo()) == 'R' ? "UR" : "U";
TEdit_field& partita = add_string(102, 0, PR("Partita "), 1, 2, 6, flags);
partita.set_field(TFixed_string(PART_NUMPART));
partita.check_type(CHECK_REQUIRED);
TReal_field& anno = add_number(101, 0, PR("Anno "), 1, 1, 4, "AU");
anno.set_field(TFixed_string(PART_ANNO));
anno.check_type(CHECK_REQUIRED);
set_handlers();
}
///////////////////////////////////////////////////////////
// TEasySolder_mask
///////////////////////////////////////////////////////////
// Forse andrebbe in libreria!
void TEasySolder_mask::set_imp(short id, const TImporto& imp)
{
TEdit_field& e = efield(id);
CHECK(e.size() >= 15, "Campo troppo piccolo per contenere un importo");
if (!imp.is_zero())
{
const TCurrency c(imp.valore());
TString80 str;
str << c.string(true) << ' ' << imp.sezione();
e.set(str);
}
else
e.reset();
}
#define get_row_bool(sheet, row, id) (row).get_char(sheet.cid2index(id))=='X'
#define get_row_int(sheet, row, id) (row).get_int(sheet.cid2index(id))
#define get_row_str(sheet, row, id) (row).get(sheet.cid2index(id))
#define get_row_real(sheet, row, id) real((row).get(sheet.cid2index(id)))
#define set_row_bool(sheet, row, id, n) (row).add(n ? "X" : "", sheet.cid2index(id))
#define set_row_int(sheet, row, id, n) (row).add(n, sheet.cid2index(id))
#define set_row_str(sheet, row, id, n) (row).add(n, sheet.cid2index(id))
static bool set_row_currency(const TSheet_field& sheet, TToken_string& row, short id, const real& n)
{
const TMask& m = sheet.sheet_mask();
const TCurrency_field& cf = (const TCurrency_field&)m.field(id);
TOperable_field* vf = cf.driver(0);
if (vf != NULL && !vf->empty()) // E' un importo in valuta?
{
const TString& codval = vf->get();
if (is_true_value(codval)) // La valuta e' diversa dall'euro?
{
if (n.is_zero())
set_row_str(sheet, row, id, "");
else
{
const TCurrency cur(n, codval);
set_row_str(sheet, row, id, cur.get_num().string());
}
return true;
}
}
if (n.is_zero())
set_row_str(sheet, row, id, "");
else
set_row_str(sheet, row, id, n.string(-1, 2));
return false;
}
void TEasySolder_mask::save_sheet()
{
// Memorizza i dati del cambio da salvare sulle righe di partita
TValuta valuta; valuta.get(*this, G_VALUTA, G_DATACAMBIO, G_CAMBIO);
const TCausale& causale = app().causale();
TSheet_field& s = sfield(G_SHEET);
FOR_EACH_SHEET_ROW(s, r, row_ptr)
{
TToken_string& row = *row_ptr;
const int anno = get_row_int(s, row, S_ANNO);
const TString8 numpart = get_row_str(s, row, S_PARTITA);
const int rigaf = get_row_int(s, row, S_RIGAF);
const int nrata = get_row_int(s, row, S_RATA);
const bool goodrat = nrata > 0 && nrata < TPartita::UNASSIGNED;
int nrigp = get_row_int(s, row, S_RIGAP);
const real importo = get_row_real(s, row, S_IMPORTO);
const real ritfis = valuta.in_valuta() ? ZERO : get_row_real(s, row, S_RITFIS);
const real ritsoc = valuta.in_valuta() ? ZERO : get_row_real(s, row, S_RITSOC);
const bool a_saldo = goodrat && get_row_bool(s, row, S_SALDO);
const TTipo_pag tipopag = (TTipo_pag)get_row_int(s, row, S_MODOPAG);
const TDate datapag = get_row_str(s, row, S_DATAPAG);
if (a_saldo || !importo.is_zero() || !ritfis.is_zero() || !ritsoc.is_zero() || nrigp > 0)
{
TPartita& partita = app().partite().partita(_conto, anno, numpart);
if (nrigp <= 0)
{
TRiga_partite& part = partita.new_row(); // Creazione nuova riga vuota
nrigp = part.get_int(PART_NRIGA); // Nuova riga
set_row_int(s, row, S_RIGAP, nrigp);
part.put(PART_SEZ, calcola_sezione());
}
TRiga_partite& part = partita.riga(nrigp); // Riga pagamento
// Setta il cambio corrente
valuta.put(part);
// Copia dati di testata movimento
TMask& cm = app().curr_mask();
part.put(PART_NREG, _numreg); // Numero operazione
part.put(PART_NUMRIG, _numrig); // Riga su cui ho cliccato
part.put(PART_NUMDOC, cm.get(F_NUMDOC));
part.put(PART_DATADOC, cm.get(F_DATADOC));
part.put(PART_DATAREG, cm.get(F_DATAREG));
part.put(PART_DESCR, cm.get(F_DESCR));
part.put(PART_DATAPAG, datapag);
part.put(PART_TIPOPAG, tipopag);
// Copia dati causale corrente
part.put(PART_CODCAUS, causale.codice());
part.put(PART_TIPOMOV, causale.tipomov());
if (causale.iva() != nessuna_iva)
{
part.put(PART_REG, cm.get(F_CODREG));
part.put(PART_PROTIVA, cm.get(F_PROTIVA));
}
TRectype newpag = partita.pagamento(rigaf, nrata, nrigp);
newpag.put(PAGSCA_ACCSAL, a_saldo ? 'S' : 'A');
if (valuta.in_valuta())
{
newpag.put(PAGSCA_IMPORTOVAL, importo);
const real impeur = get_row_str(s, row, S_IMPORTO_EUR);
newpag.put(PAGSCA_IMPORTO, impeur);
}
else
{
newpag.put(PAGSCA_IMPORTO, importo);
newpag.zero(PAGSCA_IMPORTOVAL);
newpag.put(PAGSCA_RITENUTE, ritfis);
newpag.put(PAGSCA_RITSOC, ritsoc);
}
if (part.tipo() == tm_nota_credito)
{
const TBill conto_nullo;
conto_nullo.put(newpag, true); // Azzera conto
newpag.zero(PAGSCA_CODABIPR);
newpag.zero(PAGSCA_CODCABPR);
app().notify_edit_pagamento(partita, newpag, valuta, importo.is_zero() ? _numrig : 0);
}
else
{
TBill conto_banca;
conto_banca.get(*this, G_GRUPPOC, G_CONTOC, G_SOTTOCONTOC);
conto_banca.put(newpag, true);
newpag.put(PAGSCA_CODABIPR, get(G_ABI));
newpag.put(PAGSCA_CODCABPR, get(G_CAB));
app().notify_edit_pagamento(partita, newpag, valuta, importo.is_zero() ? _numrig : 0);
}
}
}
app().cgs().force_update();
}
long TEasySolder_mask::handler(WINDOW w, EVENT* ep)
{
// Ordinamento col click destro sull'intestazione colonna
if (ep->type == E_MOUSE_DOWN && ep->v.mouse.button == 1)
{
short id = DLG_NULL;
long rec = -1;
FOR_EACH_MASK_SHEET(*this, i, s)
{
if (s->parent() == w && s->point2cell(ep->v.mouse.where, id, rec) && rec < 0)
{
const char* st = NULL;
switch (id)
{
case S_DATADOC :
case S_NUMDOC : st = "C"; break; // Data+Numero documento
case S_IMPORTO : st = "I"; break; // Importo pagamento (o insoluto)
case S_MODOPAG : st = "M"; break; // Modalità di pagamento
case S_RESIDUO : st = "R"; break; // Residuo rata
case S_TOTALE : st = "T"; break; // Totale rata
case S_DATASCAD: st = "D"; break; // Data scadenza
default: if (id >= S_ANNO && id <= S_RIGAP) st = "P"; break; // Anno+Partita+Riga
}
if (st && *st)
set(G_SORT, st, 0x1);
return 0;
}
}
}
return TAutomask::handler(w, ep);
}
static int sort_by_fields(TSheet_field& sheet, int r1, int r2, const short* const ids)
{
const TToken_string& row1 = sheet.row(r1);
const TToken_string& row2 = sheet.row(r2);
long diff = 0;
for (int i = 0; ids[i]>0 && diff==0; i++)
{
const int idx = sheet.cid2index(ids[i]);
switch (ids[i])
{
case S_DATASCAD:
case S_DATADOC:
{
TDate d1; row1.get(idx, d1);
TDate d2; row2.get(idx, d2);
long n1 = d1.date2ansi();
long n2 = d2.date2ansi();
diff = n1-n2;
}
break;
case S_PARTITA:
{
TString8 p1; row1.get(idx, p1);
TString8 p2; row2.get(idx, p2);
diff = p1.compare(p2, -1, true);
}
break;
case S_IMPORTO:
case S_RESIDUO:
case S_TOTALE:
{
real n1, n2;
row1.get(idx, n1);
row2.get(idx, n2);
diff = real(n1-n2).sign();
}
break;
default:
{
long n1, n2;
row1.get(idx, n1);
row2.get(idx, n2);
diff = n1-n2;
}
break;
}
}
return diff;
}
static int sort_by_date(TSheet_field& sheet, int r1, int r2)
{
// Elenco dei campi da confrontare in ordine di priorita'
const short ids[8] = { S_DATASCAD, S_ANNO, S_PARTITA, S_RIGAF, S_RATA, S_RIGAP, DLG_NULL };
return sort_by_fields(sheet, r1, r2, ids);
}
static int sort_by_game(TSheet_field& sheet, int r1, int r2)
{
// Elenco dei campi da confrontare in ordine di priorita'
const short ids[8] = { S_ANNO, S_PARTITA, S_RIGAF, S_RATA, S_RIGAP, DLG_NULL };
return sort_by_fields(sheet, r1, r2, ids);
}
static int sort_by_doc(TSheet_field& sheet, int r1, int r2)
{
// Elenco dei campi da confrontare in ordine di priorita'
const short ids[8] = { S_DATADOC, S_NUMDOC, S_ANNO, S_PARTITA, S_RIGAF, S_RATA, S_RIGAP, DLG_NULL };
return sort_by_fields(sheet, r1, r2, ids);
}
static int sort_by_imp(TSheet_field& sheet, int r1, int r2)
{
// Elenco dei campi da confrontare in ordine di priorita'
const short ids[8] = { S_IMPORTO, S_DATASCAD, S_ANNO, S_PARTITA, S_RIGAF, S_RATA, S_RIGAP, DLG_NULL };
return sort_by_fields(sheet, r1, r2, ids);
}
static int sort_by_tot(TSheet_field& sheet, int r1, int r2)
{
// Elenco dei campi da confrontare in ordine di priorita'
const short ids[8] = { S_TOTALE, S_DATASCAD, S_ANNO, S_PARTITA, S_RIGAF, S_RATA, S_RIGAP, DLG_NULL };
return sort_by_fields(sheet, r1, r2, ids);
}
static int sort_by_res(TSheet_field& sheet, int r1, int r2)
{
// Elenco dei campi da confrontare in ordine di priorita'
const short ids[8] = { S_RESIDUO, S_DATASCAD, S_ANNO, S_PARTITA, S_RIGAF, S_RATA, S_RIGAP, DLG_NULL };
return sort_by_fields(sheet, r1, r2, ids);
}
static int sort_by_moda(TSheet_field& sheet, int r1, int r2)
{
// Elenco dei campi da confrontare in ordine di priorita'
const short ids[8] = { S_MODOPAG, S_DATASCAD, S_ANNO, S_PARTITA, S_RIGAF, S_RATA, S_RIGAP, DLG_NULL };
return sort_by_fields(sheet, r1, r2, ids);
}
real TEasySolder_mask::val2eur(const real& val) const
{
real eur;
const TMask& mm = app().curr_mask();
const real toteur = mm.get(F_TOTALE);
const real totval = mm.get(SK_TOTDOCVAL);
if (toteur.is_zero() || totval.is_zero())
{
const TValuta valuta(mm, SK_VALUTA, SK_DATACAMBIO, SK_CAMBIO);
eur = valuta.val2eur(val);
}
else
{
eur = val * toteur / totval;
eur.round(2);
}
return eur;
}
real TEasySolder_mask::eur2val(const real& eur) const
{
real val;
const TMask& mm = app().curr_mask();
const real toteur = mm.get(F_TOTALE);
const real totval = mm.get(SK_TOTDOCVAL);
if (toteur.is_zero() || totval.is_zero())
{
const TValuta valuta(mm, SK_VALUTA, SK_DATACAMBIO, SK_CAMBIO);
val = valuta.eur2val(eur);
}
else
{
val = eur * totval / toteur;
val.round(2);
}
return val;
}
TImporto TEasySolder_mask::eur2val(const TImporto& imp) const
{
TImporto eur = imp;
eur.valore() = eur2val(imp.valore());
return eur;
}
bool TEasySolder_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case DLG_SAVEREC:
if (e == fe_button)
{
if (!check_fields())
return false;
save_sheet();
}
break;
case G_SORT:
if (e == fe_modify)
{
TSheet_field& s = sfield(G_SHEET);
switch (o.get()[0])
{
case 'C': s.sort(sort_by_doc); break;
case 'I': s.sort(sort_by_imp); break;
case 'M': s.sort(sort_by_moda); break;
case 'P': s.sort(sort_by_game); break;
case 'R': s.sort(sort_by_res); break;
case 'T': s.sort(sort_by_tot); break;
default : s.sort(sort_by_date); break;
}
s.force_update();
}
break;
case G_SHEET:
switch (e)
{
case se_enter:
{
TSheet_field& s = (TSheet_field&)o;
TToken_string& row = s.row(jolly);
_anno = get_row_int(s, row, S_ANNO);
_numpart = get_row_str(s, row, S_PARTITA);
const int rigaf = get_row_int(s, row, S_RIGAF);
const int nrata = get_row_int(s, row, S_RATA);
const int nrigp = get_row_int(s, row, S_RIGAP);
if (_tree->goto_single_game(_anno, _numpart, rigaf, nrata, nrigp))
{
TTree_field& tf = tfield(G_PARTITE);
tf.select_current();
tf.win().force_update();
reset(G_TUTTE);
}
}
break;
case se_query_add:
{
TNew_game_mask m(_conto);
if (m.run() == K_ENTER)
{
// Memorizzo il codice partita in modo da poterlo mettere nella nuova riga
_anno = atoi(m.get(PART_ANNO));
_numpart = m.get(PART_NUMPART);
return true;
}
return false;
}
break;
case se_notify_add:
{
// Metto nella nuova riga il codice partita memorizzato sopra
TSheet_field& sheet = (TSheet_field&)o;
TToken_string& row = sheet.row(jolly);
set_row_int(sheet, row, S_ANNO, _anno);
set_row_str(sheet, row, S_PARTITA, _numpart);
set_row_int(sheet, row, S_RIGAF, TPartita::UNASSIGNED);
set_row_int(sheet, row, S_RATA, TPartita::UNASSIGNED);
sheet.disable_cell(jolly, S_SALDO);
}
break;
case se_notify_modify:
aggiorna_residuo();
break;
case se_query_del:
return false;
default:
break;
}
break;
case G_CAB:
if (e == fe_modify && !o.empty() && is_running())
{
TString16 codtab; codtab << get(G_ABI) << get(G_CAB);
const TRectype& bnp = cache().get("BNP", codtab);
if (!bnp.empty())
{
const int g = bnp.get_int("I9");
const int c = bnp.get_int("I10");
const long s = bnp.get_long("I11");
if (g > 0 && c > 0 && s > 0)
{
set(G_GRUPPOC, g);
set(G_CONTOC, c);
set(G_SOTTOCONTOC, s, 0x2); // Decodifica descrizione
}
}
}
break;
case S_SPUNTA:
if (e == fe_modify)
{
TMask& m = o.mask();
TSheet_field& s = sfield(G_SHEET);
if (o.get().full())
{
const real importo = m.get(S_IMPORTO);
if (importo.is_zero())
{
real residuo = m.get(S_RESIDUO);
if (residuo.is_zero())
{
const int anno = m.get_int(S_ANNO);
const TString8 num = m.get(S_PARTITA);
const int nriga = m.get_int(S_RIGAF);
const int nrata = m.get_int(S_RATA);
const TPartita& game = app().partite().partita(_conto, anno, num);
if (game.esiste(nriga, nrata))
residuo = game.rata(nriga, nrata).residuo(true).valore();
}
if (!residuo.is_zero())
{
m.set(S_IMPORTO, residuo);
if (_tipomov != tm_insoluto && _tipomov != tm_nota_credito)
m.set(S_SALDO, true);
if (in_valuta())
{
const real residuo_eur = val2eur(residuo);
m.set(S_IMPORTO_EUR, residuo_eur);
}
}
}
}
else
{
m.reset(S_IMPORTO);
m.reset(S_IMPORTO_EUR);
m.reset(S_SALDO);
}
if (!m.is_running())
{
const int r = s.selected();
s.update_row(r);
aggiorna_residuo();
}
}
break;
case S_IMPORTO:
case S_IMPORTO_EUR:
if (e == fe_modify)
{
if (in_valuta())
{
const short buddy_id = S_IMPORTO + S_IMPORTO_EUR - o.dlg(); // :-)
TEdit_field& buddy_imp = o.mask().efield(buddy_id);
if (buddy_imp.empty())
{
const real imp = o.get();
if (buddy_id == S_IMPORTO_EUR)
buddy_imp.set(val2eur(imp).string());
else
buddy_imp.set(eur2val(imp).string());
}
}
if (!o.mask().is_running())
{
TSheet_field& s = sfield(G_SHEET);
const int r = s.selected();
s.update_row(r);
aggiorna_residuo();
}
}
break;
case G_TUTTE:
case G_INVALUTA:
if (e == fe_modify)
{
TSolder_tree_flags flags = (TSolder_tree_flags)get_int(G_TUTTE);
const TString& codval = get(G_VALUTA);
real cambio;
if (is_true_value(codval))
{
cambio = get_real(G_CAMBIO);
if (get_bool(G_INVALUTA))
flags = TSolder_tree_flags(flags | sct_show_val);
}
_tree->set_root(app().partite(), _conto, _numreg, _numrig, codval, cambio, flags);
if ((flags & sct_all_games) == sct_single_game)
{
TSheet_field& s = sfield(G_SHEET);
const int sel = s.selected();
if (sel >= 0 && sel < s.items())
on_field_event(s, se_enter, sel);
}
else // Partite aperte, chiuse o tutte
{
if (_tree->goto_root())
{
if (_tree->has_rbrother())
_tree->shrink_all();
else
_tree->expand_all();
}
TTree_field& tfp = tfield(G_PARTITE);
tfp.win().force_update();
}
}
break;
case G_PARTITE:
if (e == fe_modify)
{
TToken_string curr; _tree->curr_id(curr);
const int level = curr.items();
}
break;
default: break;
}
return true;
}
static int nrigp_pagamento_locale(const TSolder_tree& st)
{
const TToken_string& curr = *(TToken_string*)st.curr_node();
const int level = curr.items();
if (level >= 3)
{
const long nreg_mov = st.num_reg();
const int nrig_mov = st.num_rig();
if (level == 3)
{
const TRiga_scadenze* scad = st.scadenza();
if (scad != NULL) // Vera scadenza
{
for (int nrigp = scad->last(); nrigp > 0; nrigp = scad->pred(nrigp))
{
const TRiga_partite& riga = scad->partita().riga(nrigp);
const long nreg_riga = riga.get_long(PART_NREG);
const int nrig_riga = riga.get_int(PART_NUMRIG);
if (nreg_riga == nreg_mov && nrig_riga == nrig_mov)
return nrigp;
}
}
} else
if (level == 4)
{
// const int nrigp = st.pagamento()->get_int(PAGSCA_NRIGP);
int nrigp = 0; curr.get(3, nrigp);
const TRiga_partite& riga = st.partita()->riga(nrigp);
const long nreg_riga = riga.get_long(PART_NREG);
const int nrig_riga = riga.get_int(PART_NUMRIG);
if (nreg_riga == nreg_mov && nrig_riga == nrig_mov)
return nrigp;
}
}
return 0;
}
static int has_lonely_nc(TPartita& game)
{
int ncs = 0;
const TRecord_array& u = game.unassigned();
for (int i = u.last_row(); i > 0; i = u.pred_row(i))
{
const TRiga_partite& r = game.riga(i);
if (r.tipo() == tm_nota_credito)
{
ncs = i;
break;
}
}
return ncs;
}
// Aggiunge una nota di credito non associata a fattura
static bool add_lonely_nc(TPartita& game, TSheet_field& sheet, int rigasheet)
{
int nrigp = has_lonely_nc(game);
if (nrigp <= 0)
return false;
const TRiga_partite& riga = game.riga(nrigp);
TToken_string& row = sheet.row(rigasheet);
const TCausale& causale = app().causale();
const char expected_section = causale.sezione_clifo() == 'D' ? 'A' : 'D';
TImporto res = game.calcola_saldo(true);
res.normalize(expected_section);
set_row_currency(sheet, row, S_RESIDUO, res.valore());
TImporto tot = riga.importo(true);
tot.normalize(expected_section);
set_row_currency(sheet, row, S_TOTALE, tot.valore());
set_row_int(sheet, row, S_ANNO, game.anno());
set_row_str(sheet, row, S_PARTITA, game.numero());
set_row_int(sheet, row, S_RIGAF, TPartita::UNASSIGNED);
set_row_int(sheet, row, S_RATA, TPartita::UNASSIGNED);
set_row_int(sheet, row, S_RIGAP, 0); // Lasciare 0 e NON mettere assultamente nrigp o la scambia per pagamento!
set_row_str(sheet, row, S_DATASCAD, riga.get(PART_DATAPAG));
if (game.in_valuta())
{
row.add(game.codice_valuta(), sheet.cid2index(S_VALUTA));
TImporto reseur = riga.importo(false);
reseur.normalize(expected_section);
set_row_currency(sheet, row, S_RESIDUO_EUR, reseur.valore());
}
set_row_str(sheet, row, S_NUMDOC, riga.get(PART_NUMDOC));
set_row_str(sheet, row, S_DATADOC, riga.get(PART_DATADOC));
const int nrow = sheet.items()-1;
sheet.disable_cell(nrow, S_SALDO);
return true;
}
// static callback function
bool TEasySolder_mask::sheet_rate_filler(TTree& tree, void* jolly, word /* flags */)
{
const TSolder_tree& st = (const TSolder_tree&)tree;
const TToken_string& curr = *(TToken_string*)st.curr_node();
const int level = curr.items();
if (level < 3)
return false;
int nriga; curr.get(1, nriga);
int nrata; curr.get(2, nrata);
if (level == 3 && nrata >= TPartita::UNASSIGNED)
return false; // Falso nodo dell'albero padre dei non assegnati
TPartita& game = *st.partita();
if (!same_values(st.codval(), game.codice_valuta()))
return false; // Scadenza in valuta diversa da quella selezionata
int nrigp = nrigp_pagamento_locale(st);
bool good_rat = level >= 3 && nrata > 0 && nrata < TPartita::UNASSIGNED;
bool good_pag = level == 4 && nrigp > 0;
const TRiga_scadenze* scad = good_rat ? st.scadenza() : NULL;
if (good_rat && scad == NULL)
{
CHECKD(false, "Rata nulla inattesa ", nrata); // Segnalazione 1867
return false;
}
TSheet_field& sheet = *(TSheet_field*)jolly;
const TCausale& causale = app().causale();
const tipo_movimento tm = causale.tipomov();
const char pag_section = ((TEasySolder_mask&)sheet.mask()).calcola_sezione();
const char rat_section = pag_section == 'D' ? 'A' : 'D';
switch (tm)
{
case tm_nota_credito:
case tm_pagamento:
case tm_pagamento_insoluto:
if (level == 3)
{
if (good_rat)
{
good_rat = nrigp <= 0 && !scad->chiusa() && !scad->get_bool(SCAD_BLOCCATA);
/* Commentato in quanto impedisce di saldare le note di credito
if (good_rat)
{
const char expected_section = scad->get_char(SCAD_TIPOCF) == 'C' ? 'D' : 'A';
TImporto res = scad->residuo(true);
res.normalize(expected_section); // res.normalize(scad->riga().sezione());
if (res.valore () <= ZERO) // In realtà è chiusa!
good_rat = false;
}
*/
}
}
else
good_rat &= good_pag;
break;
case tm_insoluto:
if (level == 3)
{
if (good_rat && nrigp <= 0)
good_rat = !scad->importo_pagato(true).is_zero();
else
good_rat = false;
}
else
good_rat &= good_pag;
break;
default:
good_rat = good_pag = false;
break;
}
if (good_rat || good_pag) // Creo una nuova riga solo se necessario
{
TToken_string& row = sheet.row(-1);
row.add(game.codice_valuta(), sheet.cid2index(S_VALUTA));
if (good_rat)
{
TImporto res;
if (tm == tm_insoluto)
{
res = scad->importo_pagato(true);
}
else
{
res = scad->residuo(true);
res.normalize(rat_section);
}
set_row_currency(sheet, row, S_RESIDUO, res.valore());
const TImporto tot = scad->importo(true);
set_row_currency(sheet, row, S_TOTALE, tot.valore());
set_row_int(sheet, row, S_ANNO, game.anno());
set_row_str(sheet, row, S_PARTITA, game.numero());
set_row_int(sheet, row, S_RIGAF, nriga);
set_row_int(sheet, row, S_RATA, nrata);
set_row_str(sheet, row, S_DATASCAD, scad->get(SCAD_DATASCAD));
set_row_str(sheet, row, S_MODOPAG, scad->get(SCAD_TIPOPAG)); // Solo proposta
if (game.in_valuta())
{
// Calcola il residuo rata utilizzando il cambio della fattura e non quello del pagamento
const TImporto reseur = tm == tm_insoluto ? scad->importo_pagato(false) : scad->residuo(false);
set_row_currency(sheet, row, S_RESIDUO_EUR, reseur.valore());
}
if (nriga > 0 && nriga < TPartita::UNASSIGNED) // Dovrebbe sempre essere vero, ma ...
{
const TRiga_partite& riga = game.riga(nriga);
set_row_str(sheet, row, S_NUMDOC, riga.get(PART_NUMDOC));
set_row_str(sheet, row, S_DATADOC, riga.get(PART_DATADOC));
}
// Propone data di pagamento per le RIBA
if (!good_pag)
{
TDate dp(TODAY);
if (scad->get_int(SCAD_TIPOPAG) > 1)
{
const TDate ds = scad->get(SCAD_DATASCAD);
if (ds > dp)
dp = ds;
}
set_row_str(sheet, row, S_DATAPAG, dp);
}
}
if (good_pag)
{
if (!good_rat && nrigp > 1 && has_lonely_nc(game))
add_lonely_nc(game, sheet, sheet.items()-1);
const TRiga_partite& rigp = game.riga(nrigp);
set_row_int(sheet, row, S_RIGAP, nrigp);
set_row_int(sheet, row, S_NREG, rigp.get_long(PART_NREG));
set_row_int(sheet, row, S_NRIG, rigp.get_int(PART_NUMRIG));
const TRectype& pag = *st.pagamento();
const real imp = pag.get_real(PAGSCA_IMPORTO);
if (!imp.is_zero())
{
set_row_bool(sheet, row, S_SPUNTA, true);
if (rigp.in_valuta())
{
const real impval = pag.get_real(PAGSCA_IMPORTOVAL);
set_row_currency(sheet, row, S_IMPORTO, impval);
set_row_currency(sheet, row, S_IMPORTO_EUR, imp);
}
else
set_row_currency(sheet, row, S_IMPORTO, imp);
}
set_row_str(sheet, row, S_SALDO, (good_rat && pag.get_char(PAGSCA_ACCSAL)=='S') ? "X" : "");
set_row_int(sheet, row, S_MODOPAG, rigp.get_int(PART_TIPOPAG));
set_row_currency(sheet, row, S_RITFIS, pag.get_real(PAGSCA_RITENUTE));
set_row_currency(sheet, row, S_RITSOC, pag.get_real(PAGSCA_RITSOC));
set_row_int(sheet, row, S_ANNO, game.anno());
set_row_str(sheet, row, S_PARTITA, game.numero());
set_row_int(sheet, row, S_RIGAF, nriga);
set_row_int(sheet, row, S_RATA, nrata);
set_row_str(sheet, row, S_MODOPAG, rigp.get(PART_TIPOPAG));
if (good_rat)
{
set_row_str(sheet, row, S_DATAPAG, rigp.get(PART_DATAPAG));
}
else
{
set_row_str(sheet, row, S_DATASCAD, rigp.get(PART_DATAPAG));
const int nrow = sheet.items()-1;
sheet.disable_cell(nrow, S_SALDO);
}
}
}
else
{
// Nota di credito non assegnata e senza pagamenti n questo movimento
if (level == 4 && nriga == TPartita::UNASSIGNED && nrigp == 0 && has_lonely_nc(game))
{
const TImporto sld = game.calcola_saldo(true);
if (!sld.is_zero())
add_lonely_nc(game, sheet, -1);
}
}
return false;
}
// Complesso algoritmo per calcolare la sezione di una nuova riga partita
char TEasySolder_mask::calcola_sezione() const
{
const char tipoc = _conto.tipo();
const TCausale& causale = app().causale();
char sezione = causale.sezione_clifo(); // Usa la sezione della causale
if (sezione != 'A' && sezione != 'D') // Se non c'e' la sezione bell'e' ch'e' pronta
{
const tipo_movimento tm = causale.tipomov();
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';
}
// Gestione compensazioni
if (tipoc > ' ') // Se il tipo e' C o F
{
TBill bill; causale.bill(1, bill); // Legge primo conto causale
const char tc = bill.tipo();
if (tc > ' ' && tc != tipoc)
sezione = (sezione == 'D') ? 'A' : 'D'; // inverti sezione
}
return sezione;
}
bool TEasySolder_mask::in_valuta() const
{
const TString& codval = get(G_VALUTA);
return is_true_value(codval);
}
void TEasySolder_mask::calcola_residuo()
{
TImporto impriga = app().get_cgs_imp(_numrig-1); // Importo sulla riga contabile
set(G_TOTALE, impriga.valore());
TImporto residuo = impriga;
TPartite_array& giochi = app().partite();
const TImporto speso = giochi.importo_speso(_numreg, _numrig);
residuo -= speso; // Residuo della riga
const char sez = calcola_sezione(); // Sezione di riferimento
residuo.normalize(sez);
const real segno_ritsoc = app().causale().sezione_ritsoc() == sez ? UNO : -UNO;
_res_eur = residuo.valore();
set(G_RESIDUO_EUR, _res_eur);
const bool in_val = in_valuta();
if (in_val)
{
// Importo della riga contabile senza differenza cambi
TImporto resval = impriga;
const TImporto abb_diff = giochi.importo_speso(_numreg, _numrig, false, 0x6);
resval -= abb_diff;
resval = eur2val(resval);
TImporto spesoval = giochi.importo_speso(_numreg, _numrig, true, 0x1);
resval -= spesoval; // Residuo della riga
resval.normalize(sez);
_res_val = resval.valore();
set(G_RESIDUO_VAL, _res_val);
}
else
{
_res_val = _res_eur;
reset(G_RESIDUO_VAL);
}
TSheet_field& s = sfield(G_SHEET);
_tot_val = _tot_eur = ZERO;
FOR_EACH_SHEET_ROW(s, i, row)
{
if (in_val)
{
_tot_val += get_row_real(s, *row, S_IMPORTO);
_tot_eur += get_row_real(s, *row, S_IMPORTO_EUR);
}
else
{
_tot_eur += get_row_real(s, *row, S_IMPORTO);
_tot_eur += get_row_real(s, *row, S_RITFIS);
_tot_eur += get_row_real(s, *row, S_RITSOC) * segno_ritsoc;
_tot_val = _tot_eur;
}
}
}
void TEasySolder_mask::aggiorna_residuo()
{
const TCausale& caus = app().causale();
const real segno_ritsoc = caus.sezione_clifo() == caus.sezione_ritsoc() ? UNO : -UNO;
const TSheet_field& s = sfield(G_SHEET);
const bool in_val = in_valuta();
real totval, toteur;
FOR_EACH_SHEET_ROW(s, i, row)
{
if (in_val)
{
totval += get_row_real(s, *row, S_IMPORTO);
toteur += get_row_real(s, *row, S_IMPORTO_EUR);
}
else
{
toteur += get_row_real(s, *row, S_IMPORTO);
// Gestisco le ritenute solo per i movimenti in Euro
toteur += get_row_real(s, *row, S_RITFIS); // Ritfis ha sempre la sezione dell'importo
toteur += get_row_real(s, *row, S_RITSOC) * segno_ritsoc; // Ritsoc puo' avere segno contrario
}
}
const real reseur = _res_eur + _tot_eur - toteur;
set(G_RESIDUO_EUR, reseur);
if (in_val)
{
const real resval = _res_val + _tot_val - totval;
set(G_RESIDUO_VAL, resval);
}
else
reset(G_RESIDUO_VAL);
}
void TEasySolder_mask::fill_sheet()
{
TSheet_field& s = sfield(G_SHEET);
s.destroy();
const TString& codval = get(G_VALUTA);
const real cambio = get(G_CAMBIO);
s.enable_column(S_SALDO, _tipomov != tm_insoluto && _tipomov != tm_nota_credito);
const bool in_val = in_valuta();
s.enable_column(S_IMPORTO_EUR, in_val);
s.enable_column(S_RITFIS, !in_val);
s.enable_column(S_RITSOC, !in_val);
if (_tipomov == tm_insoluto)
{
s.set_column_header(S_IMPORTO, HR("Importo\nInsoluto"));
s.set_column_header(S_RESIDUO, HR("Importo\nPagato"));
}
else
{
s.set_column_header(S_IMPORTO, HR("Importo\nPagamento"));
s.set_column_header(S_RESIDUO, HR("Residuo\nScadenza"));
}
s.set_column_justify(S_PARTITA, TPartita::allineamento_richiesto(_conto.tipo()) == 'R');
TSolder_tree_flags flags = sct_open_games;
if (_tipomov == tm_insoluto || _tipomov == tm_nota_credito)
flags = sct_all_games;
_tree->set_root(app().partite(), _conto, _numreg, _numrig, codval, cambio, flags);
_tree->scan_depth_first(sheet_rate_filler, &s);
on_field_event(lfield(G_SORT), fe_modify, 0);
FOR_EACH_SHEET_ROW_BACK(s, r, riga)
{
if (riga->get_char(0) == 'X')
{
s.post_select(r);
first_focus(G_SHEET);
break;
}
}
calcola_residuo();
}
void TEasySolder_mask::init(const TBill& conto, long numreg, int numrig)
{
_conto = conto;
_numreg= numreg;
_numrig = numrig;
_tipomov = app().causale().tipomov();
_changed = false;
if (_conto.tipo() > ' ')
_conto.set(*this, 0, 0, G_CODCF, G_TIPOCF, G_RAGSOC);
else
_conto.set(*this, 0, 0, 0, G_TIPOCF, G_RAGSOC);
TMask& cm = app().curr_mask();
const TString& codval = cm.get(SK_VALUTA);
if (is_true_value(codval))
{
set(G_VALUTA, codval);
set(G_CAMBIO, cm.get(SK_CAMBIO));
set(G_DATACAMBIO, cm.get(SK_DATACAMBIO));
set(G_INVALUTA, "X");
}
else
{
reset(G_VALUTA);
reset(G_CAMBIO);
reset(G_DATACAMBIO);
reset(G_INVALUTA);
}
reset(G_TUTTE);
TBill controbill;
const int riga_i = app().type2pos('I');
if (riga_i >= 0)
{
TToken_string& row = app().cgs().row(riga_i);
controbill.get(row, 2, 0xF);
}
else
app().causale().bill(2, controbill);
if (controbill.gruppo() > 0) // con controbill.ok() non presentava assolutamente i conti parziali
{
controbill.set(*this, G_GRUPPOC, G_CONTOC, G_SOTTOCONTOC, 0, G_DESCONTOC);
}
else
{
for (short id = G_ABI; id <= G_DESCONTOC; id++)
reset(id);
}
// Nel caso di nota di credito devo nascondere il conto (fuorviante)
for (short id = G_ABI; id <= G_DESCONTOC; id++)
show(id, _tipomov != tm_nota_credito);
if (_tree == NULL)
{
_tree = new TSolder_tree;
tfield(G_PARTITE).set_tree(_tree);
}
fill_sheet();
}
TEasySolder_mask::TEasySolder_mask(const TBill& conto, long numreg, int numrig)
: TAutomask("cg2100e"), _tree(NULL)
{ init(conto, numreg, numrig); }
TEasySolder_mask::~TEasySolder_mask()
{
if (_tree != NULL)
delete _tree;
}