campo-sirio/cg/cg2105.cpp
guy 6788cf17ed Migliorata gestione split payment
git-svn-id: svn://10.65.10.50/branches/R_10_00@23051 c028cbd2-c16b-5b4b-a496-9718f37d4682
2015-03-31 06:04:40 +00:00

2334 lines
71 KiB
C++
Executable File

#include "../cg/cg2100p.h" // Campi maschere partite e pagamenti
#ifdef __EXTRA__
#include "../cg/cgsaldac.h"
#include "sc0100p.h"
#else
#include "cg2100.h" // Campi maschere prima nota
#include "cg2102.h" // Applicazione di prima nota
#endif
#include "cg2105.h"
#include "cg2107.h"
#include <colors.h> // Colori righe
#include <defmask.h> // Serve per DLG_DELREC
#include <msksheet.h>
#include <relation.h>
#include <utility.h>
#include <causali.h> // Archivio causali
///////////////////////////////////////////////////////////
// Definizione Maschera partite
///////////////////////////////////////////////////////////
class TGame_mask : public TMask
{
TBill _conto; // Conto fisso del cliente/fornitore
long _numreg; // Numero movimento contabile
int _numrig; // Riga contabile corrente (prima = 1!)
TImporto _importo; // Importo su riga contabile
TImporto _residuo, _resval; // Residuo della riga contabile
int _riga_partite; // Riga corrente delle partite
bool _changed; // Flag di modifica partite
bool _valfirst; // La colonna della valuta precede le lire
bool _ignore_next_select; // Flag per ignorare la select(0) iniziale sulle partite
protected:
static bool annopart_handler(TMask_field& f, KEY k);
static bool numpart_handler(TMask_field& f, KEY k);
static bool partite_notify(TSheet_field& partite, int r, KEY k);
static bool scadenze_notify(TSheet_field& partite, int r, KEY k);
static bool show_all_handler(TMask_field& f, KEY k);
static bool sort_part_handler(TMask_field& f, KEY k);
static bool edit_scadenza_handler(TMask_field& f, KEY k);
static bool nuovo_handler(TMask_field& f, KEY k);
static bool cambio_handler(TMask_field& f, KEY k);
void add_importo(TToken_string& s, const TImporto& i, const char* val = NULL, int pos = -1);
void add_descrizione(TToken_string& s, const TRiga_partite& riga, int pos = -1);
TImporto get_importo(TToken_string& s, int pos) const;
TToken_string& add_colored_row(TSheet_field& sheet, char type) const;
void sort_partite();
void fill_partite();
void aggiorna_residuo();
int update_partita(const TRectype& game, const TImporto& s, const TImporto& d,
const TImporto& p, const TImporto& i, int prow);
int update_partita(const TPartita& game, int prow);
int update_partita(const TRectype& game, int prow);
bool partita_aperta(const TRectype& part) const;
void update_saldo_clifo();
int nuova_riga(TPartita& partita, tipo_movimento tm) const;
int nuovo_pagamento(TPartita& partita, int nriga, int rata, tipo_movimento tm) const;
bool edit_pagamento(TPartita& p, int nriga, int nrata, int nrigp) const;
char calcola_sezione(tipo_movimento tm = tm_pagamento) const;
long number_distance(const char* key, const char* num) const;
bool same_number(const char* key, const char* num) const;
void append_conto(TString& s) const;
#ifdef __EXTRA__
bool edit_fattura(TPartita& p, int nriga);
bool prima_nota(const long nreg);
#endif
const TRiga_partite* cerca_prima_riga() const;
void aggiorna_valuta(const TValuta& val);
public:
TSheet_field& partite() const { return sfield(P_PARTITE); }
TSheet_field& scadenze() const { return sfield(P_SCADENZE); }
const TBill& conto() const { return _conto; }
TPartita* partita_corrente() const;
const TImporto& residuo(bool val) const { return val ? _resval : _residuo; }
bool changed() const { return _changed; }
void init(const TBill& bill, long numreg, int riga);
TGame_mask(const TBill& bill, long numreg, int riga);
virtual ~TGame_mask() {}
};
///////////////////////////////////////////////////////////
// Maschera pagamenti
///////////////////////////////////////////////////////////
#ifdef __EXTRA__
const char* const PAYMASK = "sc0100b";
#else
const char* const PAYMASK = "cg2100s";
#endif
void TPay_mask::init(const TGame_mask* parent, int mod)
{
#ifndef __EXTRA__
_parent = parent;
#endif
set_mode(mod);
enable(DLG_DELREC, edit_mode());
#ifdef __EXTRA__
xvtil_statbar_set(mod == MODE_MOD ? TR("Modifica") : TR("Inserimento"), TRUE);
hide(E_CODPAG); hide(E_DESPAG);
set_handler(E_DATAREG, datareg_handler);
set_handler(E_DATADOC, datadoc_handler);
set_handler(E_NUMDOC, numdoc_handler);
set_handler(E_SEZIONE, sezione_handler);
set_handler(E_TOTALE, TSaldaconto_app::totale_handler);
if (app().gestione_valuta())
{
show(-3);
set_handler(E_TOTDOCVAL, TSaldaconto_app::totval_handler);
set_handler(E_VALUTA, TSaldaconto_app::valuta_handler);
set_handler(E_DATACAMBIO, TSaldaconto_app::datacambio_handler);
set_handler(E_CAMBIO, TSaldaconto_app::cambio_handler);
}
else
hide(-3);
hide(S_RESIDUOPAG);
hide(-2); // I campi relativi alla contropartita non vengono gestiti
hide(E_IMPOSTE);
set_handler(E_DESCR, descr_handler);
set_handler(S_DESCAGG, descr_handler);
const char tipocf = parent ? parent->conto().tipo() : 'C';
const char a = TPartita::allineamento_richiesto(tipocf);
field(E_NUMRIF).set_justify(a == 'R');
disable(E_ANNORIF);
disable(E_NUMRIF);
#endif
}
TPay_mask::TPay_mask(const TGame_mask* parent, int mod)
: TMask(PAYMASK)
{
init(parent, mod);
}
TPay_mask::~TPay_mask()
{ }
void TPay_mask::attiva_valuta(bool in_valuta)
{
if (in_valuta)
{
set_handler(S_IMPORTOVAL, importo_handler);
set_handler(S_IMPORTO, importolire_handler);
}
else
set_handler(S_IMPORTO, importo_handler);
enable(S_RITENUTE, !in_valuta); // dis/abilita ritenute
enable(S_RITSOC, !in_valuta);
enable(S_IMPORTOVAL, in_valuta);
if (in_valuta)
{
reset(S_RITENUTE);
reset(S_RITSOC);
}
else
{
reset(S_IMPORTOVAL_SCAD);
reset(S_IMPORTOVAL);
}
}
void TPay_mask::set_pag(const TRectype& oldpag, const TRiga_scadenze& scad,
const TImporto& residuo)
{
const TPartita& p = scad.partita();
const int nrigp = oldpag.get_int(PAGSCA_NRIGP);
const TRiga_partite& sum = p.riga(nrigp);
_assigned = oldpag.get_int(PAGSCA_NRIGA) != TPartita::UNASSIGNED;
_tipomov = sum.tipo();
_swap_ritsoc = sum.sezione() != sum.sezione_ritsoc();
const TRiga_partite& fatt = _assigned ? scad.riga() : sum;
TRelation rel(LF_PAGSCA); // Working relation
rel.add(LF_PARTITE, "ANNO==ANNO|NUMPART==NUMPART");
rel.curr() = oldpag;
rel.curr(LF_PARTITE) = sum;
set(S_CODVAL, fatt.get(PART_CODVAL)); // Importante settare la valuta per i TCurrency! CM500433
autoload(rel); // Load current record on mask
TMask_field& group = field(S_RATA);
TString prompt(80);
const TBill& k = p.conto();
switch (k.tipo())
{
case 'C': prompt << TR("Cliente"); break;
case 'F': prompt << TR("Fornitore"); break;
default : prompt << TR("Conto ") << k.gruppo() << ' ' << k.conto(); break;
}
prompt << ' ' << k.sottoconto() << ' ';
prompt << TR("Partita:") << p.anno() << ' ' << p.numero()
<< TR(" Riga:") << oldpag.get_int(PAGSCA_NRIGA)
<< TR(" Rata:") << oldpag.get_int(PAGSCA_NRATA);
if (assigned())
prompt << TR(" del ") << scad.get_date(SCAD_DATASCAD).string();
#ifndef __EXTRA__
else
prompt << TR(" del ") << sum.get_date(PART_DATAPAG).string();
#endif
group.set_prompt(prompt);
set(S_NUMDOC, fatt.get(PART_NUMDOC)); // Numero documento
set(S_DATADOC, fatt.get(PART_DATADOC)); // Data documento
set(S_NUMPROT, fatt.get(PART_PROTIVA)); // Protocollo IVA
TString desfat = fatt.get(PART_DESCR); // Descrizione fattura
if (desfat.empty()) // Se e' vuota ...
{
desfat = fatt.get(PART_CODCAUS);
desfat = cache().get(LF_CAUSALI, desfat, CAU_DESCR); // ... usa descrizione causale
}
set(S_DESCR, desfat);
bool in_valuta = fatt.in_valuta();
#ifdef __EXTRA__
const bool prima_riga = p.first() == p.last();
if (!in_valuta && prima_riga)
in_valuta = app().gestione_valuta();
enable(E_VALUTA, prima_riga); // La valuta puo' essere cambiata solo sulle partite nuove
#else
set(S_CODVAL, fatt.codice_valuta()); // Copia in maschera la valuta
#endif
show(-3, in_valuta); // Visualizza campi relativi alla valuta
attiva_valuta(in_valuta); // Attiva campi e handlers relativi alla valuta
const char sez_fat = fatt.sezione();
set(S_SEZIONE_SCAD, sez_fat == 'A' ? "A" : "D"); // Sezione della riga
if (assigned())
{
set(S_IMPORTO_SCAD, scad.get(SCAD_IMPORTO)); // Importo della rata
if (in_valuta)
set(S_IMPORTOVAL_SCAD, scad.get(SCAD_IMPORTOVAL)); // Importo in valuta
TImporto res_rat = scad.residuo(in_valuta);
res_rat.normalize(sez_fat);
_da_pagare = res_rat.valore(); // Calcola residuo in valuta
TEdit_field& resrat = efield(S_RESIDUORATA);
resrat.reset_driver();
if (in_valuta)
resrat.add_driver(S_CODVAL);
if (get(S_SALDOACC)[0] != 'S')
resrat.set(_da_pagare.string());
}
else
{
hide(S_RESIDUORATA); // Se non assegnato nascondi residuo rata
_da_pagare = ZERO;
}
set_handler(S_SALDOACC, saldo_handler);
real oldimp = oldpag.get_real(in_valuta ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO);
if (!in_valuta)
{
oldimp += oldpag.get_real(PAGSCA_RITENUTE);
if (_swap_ritsoc)
oldimp -= oldpag.get_real(PAGSCA_RITSOC);
else
oldimp += oldpag.get_real(PAGSCA_RITSOC);
}
// Ricorda l'importo da pagare
_da_pagare += oldimp;
#ifndef __EXTRA__
_pagabile = _parent->residuo(in_valuta).valore();
TEdit_field& respag = efield(S_RESIDUOPAG);
respag.reset_driver();
if (in_valuta)
respag.add_driver(S_CODVAL);
respag.set(_pagabile.string());
_pagabile += oldimp;
#endif
// Il flag di saldo/acconto e' attivo solo se non ci sono acconti, cioe':
// pagamento non assegnato o con data documento antecedente quella della fattura
_can_solder = _assigned;
if (_can_solder)
{
const tipo_movimento tm = sum.tipo();
_can_solder = !(tm == tm_nota_credito || tm == tm_insoluto);
/* if (_can_solder)
{
const TDate datasca(fatt.get(PART_DATADOC));
const TDate datapag(sum.get(PART_DATADOC));
_can_solder = datapag >= datasca;
} */
}
// Mostra saldo solo se non e' ne' un acconto, ne' una nota di credito
enable(S_SALDOACC, _can_solder);
#ifdef __EXTRA__
enable(E_SEZIONE, oldpag.get_char(PAGSCA_ACCSAL) != 'S');
#else
set_handler(S_GRUPPO, conto_handler);
set_handler(S_CONTO, conto_handler);
const bool mostra_conto = !sum.is_nota_credito() && app().curr_mask().get_real(F_TOTALE) != ZERO;
show(-2, mostra_conto); // mostra/nasconde conto contropartita
if (!mostra_conto)
reset(-2);
#endif
// Gestione data-pagamento: non puo' precedere la data del documento
_datadoc = sum.get_date(PART_DATADOC);
_datarat = _assigned ? scad.get(SCAD_DATASCAD) : EMPTY_STRING;
set_handler(S_DATAPAG, datapag_handler);
const bool mostra_ritenute = !sum.is_nota_credito();
show(S_RITENUTE, mostra_ritenute);
show(S_RITSOC, mostra_ritenute);
}
void TPay_mask::get_pag(TRectype& newpag, TRectype& sum) const
{
TRelation rel(LF_PAGSCA); // Working relation
rel.add(LF_PARTITE, "ANNO=ANNO|NUMPART=NUMPART");
rel.curr() = newpag;
rel.curr(LF_PARTITE) = sum;
autosave(rel); // Load current record from mask
newpag = rel.curr();
sum = rel.curr(LF_PARTITE);
}
// Riempie i campi valuta a zero in base agli altri
void TPay_mask::gioca_cambi(int force)
{
const real totale = get_real(S_IMPORTO);
const real totval = get_real(S_IMPORTOVAL);
#ifdef __EXTRA__
const TValuta cambio(*this, E_VALUTA, E_DATACAMBIO, E_CAMBIO);
#else
const TValuta cambio(*_parent, P_VALUTA, P_DATACAMBIO, P_CAMBIO);
#endif
if ( (force == 0x1 || totale.is_zero()) && !(totval.is_zero() || cambio.in_euro()) )
{
const real new_totale = cambio.val2eur(totval);
if (new_totale != totale)
set(S_IMPORTO, new_totale, TRUE);
}
if ( (force == 0x2 || totval.is_zero()) && !(totale.is_zero() || cambio.in_euro()))
{
const real new_totval = cambio.eur2val(totale);
if (new_totval != totval)
set(S_IMPORTOVAL, new_totval, TRUE);
}
#ifdef __EXTRA__
if ( (force == 0x4 || cambio.in_euro()) && !(totale.is_zero() || totval.is_zero()))
{
real new_cambio = totale / totval; new_cambio.round(6);
if (new_cambio != cambio.cambio())
set(E_CAMBIO, new_cambio, TRUE);
}
#endif
}
bool TPay_mask::importo_handler(TMask_field& f, KEY k)
{
TPay_mask& m = (TPay_mask&)f.mask();
if (k == K_F8)
{
real imp;
#ifdef __EXTRA__
const bool in_valuta = m.field(S_IMPORTOVAL).active();
m._pagabile = m.get_real(in_valuta ? E_TOTDOCVAL : E_TOTALE);
if (m._assigned)
imp = fnc_min(m._da_pagare, m._pagabile);
else
imp = m._pagabile;
#else
if (m.field(S_RESIDUORATA).shown() && m.field(S_RESIDUOPAG).shown())
imp = fnc_min(m._da_pagare, m._pagabile);
else
imp = m.field(S_RESIDUORATA).shown() ? m._da_pagare : m._pagabile;
#endif
if (m.field(S_RITENUTE).active())
imp -= m.get_real(S_RITENUTE);
if (m.field(S_RITSOC).active())
{
if (m._swap_ritsoc)
imp += m.get_real(S_RITSOC);
else
imp -= m.get_real(S_RITSOC);
}
f.set(imp.string());
k = K_TAB;
}
if (k == K_TAB && (f.focusdirty() || !m.is_running()))
{
const bool in_valuta = m.field(S_IMPORTOVAL).active();
if (in_valuta)
m.gioca_cambi();
real i(f.get());
if (m.field(S_RITENUTE).active())
i += m.get_real(S_RITENUTE);
if (m.field(S_RITSOC).active())
{
if (m._swap_ritsoc)
i -= m.get_real(S_RITSOC);
else
i += m.get_real(S_RITSOC);
}
TMask_field& sa = m.field(S_SALDOACC);
TMaskmode mod = (TMaskmode)m.mode();
if (m._can_solder && (mod == NO_MODE || mod == MODE_INS))
{
if (i >= m._da_pagare)
sa.set("S");
}
if (sa.get()[0] != 'S')
{
real residuo = m._da_pagare;
if (m.tipo() == tm_insoluto)
residuo += i;
else
residuo -= i;
m.set(S_RESIDUORATA, residuo);
}
else
m.reset(S_RESIDUORATA);
const real residuopag(m._pagabile - i);
m.set(S_RESIDUOPAG, residuopag);
}
return TRUE;
}
bool TPay_mask::importolire_handler(TMask_field& f, KEY k)
{
TPay_mask& m = (TPay_mask&)f.mask();
if (k == K_F8)
{
#ifdef __EXTRA__
if (m.unassigned())
f.set(m.get(E_TOTALE));
else
#endif
m.send_key(k, S_IMPORTOVAL);
}
if (f.to_check(k))
m.gioca_cambi();
return TRUE;
}
bool TPay_mask::saldo_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TMask& m = f.mask();
m.set_mode(MODE_QUERY);
const bool valuta = m.field(S_IMPORTOVAL).active();
TMask_field& imp = m.field(valuta ? S_IMPORTOVAL : S_IMPORTO);
imp.set_dirty();
imp.on_hit();
m.set_mode(NO_MODE);
}
return TRUE;
}
bool TPay_mask::datapag_handler(TMask_field& f, KEY k)
{
if (f.to_check(k) || k == K_ENTER)
{
const TDate datapag(f.get());
TPay_mask& m = (TPay_mask&)f.mask();
if (datapag < m._datadoc)
return f.error_box(FR("La data del pagamento e' inferiore alla data del documento %s"),
m._datadoc.string());
if (datapag < m._datarat)
warning_box(TR("Attenzione: la data del pagamento precede quella della rata"));
}
return TRUE;
}
bool TPay_mask::conto_handler(TMask_field& f, KEY k)
{
if (k == K_TAB && f.focusdirty())
{
TMask& m = f.mask();
TBill conto; conto.get(m, S_GRUPPO, S_CONTO, S_SOTTOCONTO);
const TString& desc = conto.descrizione();
if (desc.empty())
m.reset(S_SOTTOCONTO);
m.set(S_DESCRCONTO, desc);
}
return TRUE;
}
///////////////////////////////////////////////////////////
// Maschera gestione nuovo pagamento / fattura
///////////////////////////////////////////////////////////
bool TNew_mask::on_field_event(TOperable_field& f, TField_event e, long jolly)
{
switch (f.dlg())
{
case P_NUOVO:
if (e == fe_close && !_allow_fatt && f.get() == "1")
return error_box(TR("Non e' possibile utilizzare una fattura come pagamento"));
break;
default:
break;
}
return true;
}
void TNew_mask::init(char tipocf, bool fatt, bool edit)
{
_allow_fatt = fatt;
TMask_field& tipomov = field(P_NUOVO);
#ifdef __EXTRA__
tipomov.enable();
tipomov.set(_allow_fatt ? "1" : "3");
if (!_allow_fatt)
set_caption(TR("Nuovo pagamento"));
reset(P_NUMERO);
#else
tipomov.disable();
TMask& cm = app().curr_mask();
const TDate datareg = cm.get_date(F_DATAREG);
set(P_ANNO, datareg.year());
if (ini_get_bool(CONFIG_DITTA, "cg", "RifMonth"))
set(P_NUMERO, format("%02d", datareg.month()));
#endif
enable(P_ANNO, edit);
enable(P_NUMERO, edit);
if (edit) first_focus(P_NUMERO);
const char a = TPartita::allineamento_richiesto(tipocf);
field(P_NUMERO).set_justify(a == 'R');
}
TNew_mask::TNew_mask(char tipocf, bool fatt, bool edit)
: TAutomask("cg2100n")
{
init(tipocf, fatt, edit);
}
///////////////////////////////////////////////////////////
// Maschera partite
///////////////////////////////////////////////////////////
void TGame_mask::append_conto(TString& s) const
{
switch (conto().tipo())
{
case 'C':
s << TR("Cliente"); break;
case 'F':
s << TR("Fornitore"); break;
default:
s << TR("Conto") << ' ' << conto().gruppo() << ' ' << conto().conto(); break;
}
s << ' ' << conto().sottoconto();
}
void TGame_mask::init(const TBill& bill, long numreg, int riga)
{
_conto = bill;
_numreg = numreg; _numrig = riga;
_changed = FALSE;
TString descr(80);
append_conto(descr);
descr << ' ' << ((TBill&)_conto).descrizione();
set(P_DESCR, descr);
#ifdef __EXTRA__
xvtil_statbar_set(TR("Estratto conto"), TRUE);
disable(-3); // Disabilita gestione valuta
hide(P_RESIDUO);
hide(P_RESIDUOVAL);
#else
TValuta val;
const TRiga_partite* row = cerca_prima_riga();
if (row != NULL)
{
val.get(*row); // Legge valuta standard dalla partita
set(P_ANNO, row->get(PART_ANNO)); // Propone anno e partita
set(P_NUMERO, row->get(PART_NUMPART));
}
else
{
TMask& cm = app().curr_mask(); // Legge valuta dal movimento
val.get(cm, SK_VALUTA, SK_DATACAMBIO, SK_CAMBIO);
if (cm.id2pos(F_ANNORIF) > 0) // Se in testata c'e' l'anno di riferimento
{
set(P_ANNO, cm.get(F_ANNORIF)); // Propone anno e partita
set(P_NUMERO, cm.get(F_NUMRIF));
}
}
val.set(*this, P_VALUTA, P_DATACAMBIO, P_CAMBIO);
enable(-3, val.in_valuta());
#endif
set_handler(P_ANNO, annopart_handler);
set_handler(P_NUMERO, numpart_handler);
set_handler(P_SHOWALL, show_all_handler);
set_handler(P_SORT, sort_part_handler);
set_handler(P_NUOVO, nuovo_handler);
set_handler(P_CAMBIO, cambio_handler);
TSheet_field& games = partite();
games.set_notify(partite_notify);
scadenze().set_notify(scadenze_notify);
scadenze().sheet_mask().set_handler(100, edit_scadenza_handler);
fill_partite(); // Riempie sheet partite
}
TGame_mask::TGame_mask(const TBill& bill, long numreg, int riga)
: TMask("cg2100p"), _valfirst(FALSE), _ignore_next_select(FALSE)
{
init(bill, numreg, riga);
}
///////////////////////////////////////////////////////////
// Handlers dei campi e della maschera principale
///////////////////////////////////////////////////////////
bool TGame_mask::annopart_handler(TMask_field& f, KEY k)
{
if (k == K_TAB && f.focusdirty() && f.get().not_empty())
{
TMask_field& n = f.mask().field(P_NUMERO);
n.set_dirty();
numpart_handler(n, k);
}
return TRUE;
}
bool TGame_mask::numpart_handler(TMask_field& f, KEY k)
{
if (k == K_TAB && f.focusdirty())
{
const TGame_mask& m = (const TGame_mask&)f.mask();
const int anno = m.get_int(P_ANNO); // Anno partita da cercare
if (anno > 0)
{
const TString key = f.get(); // Numero partita da cercare
int best_match = 0; // Partita piu' somigliante
long min_dist = 10000000L; // Livello di somiglianza migliore
TSheet_field& sheet = m.partite();
for (int i = 0; i < sheet.items(); i++)
{
TToken_string& row = sheet.row(i);
if (anno == row.get_int(0)) // Se corrisponde l'anno e ...
{
const long dist = m.number_distance(key, row.get());
if (i == 0 || dist < min_dist)
{
min_dist = dist;
best_match = i;
if (dist == 0L)
break;
}
}
}
sheet.post_select(best_match);
}
}
return TRUE;
}
bool TGame_mask::show_all_handler(TMask_field& f, KEY k)
{
TGame_mask& gm = (TGame_mask&)f.mask();
if (k == K_SPACE && gm.is_running())
{
gm.fill_partite();
}
return TRUE;
}
bool TGame_mask::sort_part_handler(TMask_field& f, KEY k)
{
TGame_mask& gm = (TGame_mask&)f.mask();
if (k == K_SPACE && gm.is_running())
gm.sort_partite();
return TRUE;
}
bool TGame_mask::cambio_handler(TMask_field& f, KEY k)
{
if (k == K_TAB && f.focusdirty())
{
TGame_mask& gm = (TGame_mask&)f.mask();
const bool needed = app().partite().mov2rig(gm._numreg, gm._numrig) > 0;
if (needed && yesno_box(TR("Aggiornare il cambio di tutti i pagamenti effettuati in questa registrazione?")))
{
const TValuta val(gm, P_VALUTA, P_DATACAMBIO, P_CAMBIO);
gm.aggiorna_valuta(val);
}
gm.aggiorna_residuo();
}
return TRUE;
}
///////////////////////////////////////////////////////////
// Metodi dei campi e della maschera principale
///////////////////////////////////////////////////////////
// Aggiorna il campo con il residuo da spendere sui pagamenti
void TGame_mask::aggiorna_residuo()
{
#ifndef __EXTRA__
_importo = app().get_cgs_imp(_numrig-1); // Importo sulla riga contabile
_residuo = _importo;
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);
set(P_RESIDUO, _residuo.valore());
const TValuta cambio(*this, P_VALUTA, P_DATACAMBIO, P_CAMBIO);
if (cambio.in_valuta())
{
// Importo della riga contabile senza differenza cambi
_resval = _importo;
const TImporto abb_diff = giochi.importo_speso(_numreg, _numrig, FALSE, 0x6);
_resval -= abb_diff;
cambio.eur2val(_resval);
const TImporto spesoval = giochi.importo_speso(_numreg, _numrig, TRUE, 0x1);
_resval -= spesoval; // Residuo della riga
_resval.normalize(sez);
set(P_RESIDUOVAL, _resval.valore());
}
else
reset(P_RESIDUOVAL);
#endif
}
// Scandisce tutte le partite per cercare la prima del movimento corrente
const TRiga_partite* TGame_mask::cerca_prima_riga() const
{
const TRiga_partite* riga = app().partite().mov2rig(_numreg, _numrig);
return riga;
}
void TGame_mask::aggiorna_valuta(const TValuta& val)
{
TPartite_array& pa = app().partite();
for (TPartita* game = pa.first(); game; game = pa.next())
{
for (int r = game->last(); r > 0; r = game->pred(r))
{
const TRiga_partite& riga = game->riga(r);
for (int s = riga.rate(); s > 0; s--)
{
const TRiga_scadenze& scad = riga.rata(s);
for (int p = scad.last(); p > 0; p = scad.pred(p))
{
TRiga_partite& sum = game->riga(p);
if (sum.get_long(PART_NREG) == _numreg &&
sum.get_int(PART_NUMRIG) == _numrig)
{
TRectype pag(scad.row(p));
real imp(pag.get(PAGSCA_IMPORTOVAL));
val.val2eur(imp);
pag.put(PAGSCA_IMPORTO, imp); // Converte in lire l'importo in valuta
#ifdef __EXTRA__
game->modifica_pagamento(pag, val, TRUE);
#else
app().notify_edit_pagamento(*game, pag, val);
#endif
}
}
}
}
}
fill_partite();
}
TToken_string& TGame_mask::add_colored_row(TSheet_field& sheet, char type) const
{
int r = sheet.insert(-1, false, false);
COLOR back, fore;
app().type2colors(type, back, fore);
sheet.set_back_and_fore_color(back, fore, r);
return sheet.row(r);
}
TPartita* TGame_mask::partita_corrente() const
{
if (_riga_partite < 0)
return NULL;
TToken_string& row = partite().row(_riga_partite);
const int anno = row.get_int(0); // Anno partita
const TString16 num = row.get(); // Numero partita
const TBill& zio = conto();
TPartita* game = app().partite().exist(zio, anno, num);
return game;
}
bool TGame_mask::partite_notify(TSheet_field& partite, int r, KEY k)
{
TGame_mask& gm = (TGame_mask&)partite.mask();
if (k == K_TAB)
{
if (gm._ignore_next_select)
{
gm._ignore_next_select = FALSE;
return TRUE;
}
const bool changing_row = gm._riga_partite != r;
if (!changing_row)
return TRUE;
TWait_cursor hourglass;
gm._riga_partite = r;
TSheet_field& sheet = gm.scadenze();
sheet.destroy(-1, FALSE); // Azzera righe
TToken_string& row = partite.row(r);
const int anno = row.get_int(0); // Anno partita
const TString16 num = row.get(); // Numero partita
gm.set(P_ANNO, anno); // Aggiorna campi di ricerca
gm.set(P_NUMERO, num);
TValuta prima_valuta; // Codice prima valuta
if (anno > 0)
{
const TBill& zio = gm.conto(); // Conto cliente/fornitore
TPartita* game = app().partite().exist(zio, anno, num); // Cerca la partita tra quelle editate
const bool should_delete_game = (game == NULL); // Ricorda di fare delete
if (should_delete_game) // Se non c'era ...
game = new TPartita(zio, anno, num); // ... creane una temporanea
TImporto tot_lit, tot_val;
const int lastrow = game->last();
if (lastrow > 0)
prima_valuta.get(game->riga(lastrow));
const bool in_valuta = prima_valuta.in_valuta();
for (int ri = game->first(); ri <= lastrow; ri = game->succ(ri))
{
const TRiga_partite& riga = game->riga(ri);
if (!riga.is_fattura())
continue;
TToken_string& riga_fattura = gm.add_colored_row(sheet, 'K');
riga_fattura.add(ri);
riga_fattura.add("");
riga_fattura.add(riga.get(PART_DATADOC));
riga_fattura.add(""); // Data scad
gm.add_descrizione(riga_fattura, riga);
gm.add_importo(riga_fattura, riga.importo(FALSE, 0x1));
if (in_valuta)
gm.add_importo(riga_fattura, riga.importo(TRUE, 0x1), prima_valuta.codice());
else
riga_fattura.add("");
riga_fattura.add(riga.get(PART_NREG));
riga_fattura.add(riga.get(PART_DATAREG));
riga_fattura.add(riga.get(PART_NUMDOC));
riga_fattura.add(riga.get(PART_PROTIVA));
riga_fattura.add((int)riga.tipo());
for (int ra = 1; ra <= riga.rate(); ra++)
{
const TRiga_scadenze& scad = riga.rata(ra);
TToken_string& row = gm.add_colored_row(sheet, 'I');
row = riga_fattura;
row.add(ra, 1);
row.add(scad.get(SCAD_DATASCAD), 3);
gm.add_importo(row, scad.importo(false), NULL, 5);
if (in_valuta)
gm.add_importo(row, scad.importo(true), prima_valuta.codice(), 6);
const TString& descr = scad.get(SCAD_DESCR);
if (descr.full())
row.add(descr, 4);
const bool blocked = scad.get_bool(SCAD_BLOCCATA);
row.add(blocked ? "X" : " ", 13);
if (blocked)
{
const TString& cbp = scad.get(SCAD_MOTIVO);
row.add(cbp);
if (cbp.full())
row.add(cache().get("%CBP", cbp, "S0"));
}
const int lastp = scad.last();
for (int pa = scad.first(); pa <= lastp; pa = scad.succ(pa))
{
const TRectype& pag = scad.row(pa);
const TRiga_partite& sum = game->riga(pa);
const char sez = sum.sezione();
const long nreg = sum.get_long(PART_NREG);
const int nrig = sum.get_int(PART_NUMRIG);
const bool linked = nreg == gm._numreg && nrig == gm._numrig;
TToken_string& row = gm.add_colored_row(sheet, linked ? 'X' : ' ');
row.add(ri);
row.add(ra);
row.add(sum.get(PART_DATADOC));
row.add(sum.get(PART_DATAPAG));
gm.add_descrizione(row, sum);
const TImporto imp(sez, pag.get_real(PAGSCA_IMPORTO));
if (in_valuta)
{
gm.add_importo(row, imp);
gm.add_importo(row, TImporto(sez, pag.get_real(PAGSCA_IMPORTOVAL)), prima_valuta.codice());
}
else
{
gm.add_importo(row, imp);
row.add("");
}
row.add(nreg);
row.add(sum.get(PART_DATAREG));
row.add(sum.get(PART_NUMDOC));
row.add("");
row.add((int)sum.tipo());
row.add(pa);
// Le ritenute non possono esistere in valuta
if (!in_valuta)
{
const TImporto rit(sez, pag.get_real(PAGSCA_RITENUTE));
if (!rit.is_zero())
{
TToken_string& rrit = gm.add_colored_row(sheet, 'R');
rrit.add(TR("Ritenute professionali"), 4);
gm.add_importo(rrit, rit, FALSE);
rrit.add((int)sum.tipo(), 11);
}
const TImporto soc(sum.sezione_ritsoc(), pag.get_real(PAGSCA_RITSOC));
if (!soc.is_zero())
{
TToken_string& rrit = gm.add_colored_row(sheet, 'R');
rrit.add(TR("Ritenute sociali"), 4);
gm.add_importo(rrit, soc, FALSE);
rrit.add((int)sum.tipo(), 11);
}
}
// Gli abbuoni e le differenze cambio esistono solo se e' a saldo
if (pag.get_char(PAGSCA_ACCSAL) == 'S')
{
const TImporto abb(sez, pag.get_real(PAGSCA_ABBUONI));
if (!abb.is_zero())
{
const char tipo_abb = pag.get_char(PAGSCA_PASSATT);
TToken_string& rabb = gm.add_colored_row(sheet, tipo_abb);
rabb.add(tipo_abb == 'A' ? TR("Abbuoni attivi") : TR("Abbuoni passivi"), 4);
if (in_valuta)
{
TImporto abb_lit = abb;
prima_valuta.val2eur(abb_lit);
gm.add_importo(rabb, abb_lit);
gm.add_importo(rabb, abb, prima_valuta.codice());
}
else
{
gm.add_importo(rabb, abb);
rabb.add("");
}
rabb.add((int)sum.tipo(), 11);
}
// Le differenze cambio possono esistere solo in valuta
if (in_valuta)
{
const TImporto diff(sez, pag.get_real(PAGSCA_DIFFCAM));
if (!diff.is_zero())
{
TToken_string& rdiff = gm.add_colored_row(sheet, 'C');
rdiff.add(TR("Differenza cambio"), 4);
gm.add_importo(rdiff, diff);
rdiff.add((int)sum.tipo(), 11);
}
}
} // Il pagamento era a saldo
} // Fine ciclo sui pagamenti della rata
TToken_string& rsal = gm.add_colored_row(sheet, 'S');
rsal.add(TR("Saldo rata "), 4); rsal << ra;
if (!scad.chiusa())
{
TImporto sl = scad.residuo(false);
gm.add_importo(rsal, sl);
tot_lit += sl;
if (in_valuta)
{
sl = scad.residuo(true, 0xB);
gm.add_importo(rsal, sl, prima_valuta.codice());
tot_val += sl;
}
}
} // Fine ciclo sulle rate della fattura
}
TRecord_array& unas = game->unassigned();
const int lastp = unas.last_row();
for (int pa = unas.first_row(); pa <= lastp; pa = unas.succ_row(pa))
{
const TRectype& pag = unas.row(pa);
const TRiga_partite& sum = game->riga(pa);
const char sez = sum.sezione();
const long nreg = sum.get_long(PART_NREG);
const int nrig = sum.get_int(PART_NUMRIG);
const bool linked = nreg == gm._numreg && nrig == gm._numrig;
TToken_string& row = gm.add_colored_row(sheet, linked ? 'X' : ' ');
row.add(pag.get(PAGSCA_NRIGA));
row.add(pag.get(PAGSCA_NRATA));
row.add(sum.get(PART_DATADOC));
row.add(sum.get(PART_DATAPAG));
gm.add_descrizione(row, sum);
TImporto imp(sez, pag.get_real(PAGSCA_IMPORTO));
gm.add_importo(row, imp);
tot_lit += imp;
const real& impval = pag.get_real(PAGSCA_IMPORTOVAL);
if (!impval.is_zero())
{
imp.set(sum.sezione(), impval);
imp.normalize();
gm.add_importo(row, imp, prima_valuta.codice());
tot_val += imp;
}
else
row.add("");
row.add(nreg);
row.add(sum.get(PART_DATAREG));
row.add(sum.get(PART_NUMDOC));
row.add("");
row.add((int)sum.tipo());
row.add(pa);
const TImporto rit(sez, pag.get_real(PAGSCA_RITENUTE));
if (!rit.is_zero())
{
TToken_string& row = gm.add_colored_row(sheet, 'R');
row.add(TR("Ritenute professionali"), 4);
gm.add_importo(row, rit, FALSE);
row.add((int)sum.tipo(), 11);
tot_lit += rit;
}
const TImporto soc(sum.sezione_ritsoc(), pag.get_real(PAGSCA_RITSOC));
if (!soc.is_zero())
{
TToken_string& row = gm.add_colored_row(sheet, 'R');
row.add(TR("Ritenute sociali"), 4);
gm.add_importo(row, soc, FALSE);
row.add((int)sum.tipo(), 11);
tot_lit += soc;
}
// Gli abbuoni e le differenze cambio esistono solo se e' a saldo
// NON sarebbe possibile, ma la contabilizzazione potrebbe mettere a saldo i non assegnati
if (pag.get_char(PAGSCA_ACCSAL) == 'S' || !pag.get_real(PAGSCA_ABBUONI).is_zero())
{
const TImporto abb(sez, pag.get_real(PAGSCA_ABBUONI));
if (!abb.is_zero())
{
const char tipo_abb = pag.get_char(PAGSCA_PASSATT);
TToken_string& rabb = gm.add_colored_row(sheet, tipo_abb);
rabb.add(tipo_abb == 'A' ? TR("Abbuoni attivi") : TR("Abbuoni passivi"), 4);
if (in_valuta)
{
TImporto abb_lit = abb;
prima_valuta.val2eur(abb_lit);
gm.add_importo(rabb, abb_lit);
gm.add_importo(rabb, abb, prima_valuta.codice());
tot_lit += abb_lit;
tot_val += abb;
}
else
{
gm.add_importo(rabb, abb);
rabb.add("");
tot_lit += abb;
}
rabb.add((int)sum.tipo(), 11);
}
/* Continuo a ritenre impossibile ... per ora
// Le differenze cambio possono esistere solo in valuta
if (in_valuta)
{
const TImporto diff(sez, pag.get_real(PAGSCA_DIFFCAM));
if (!diff.is_zero())
{
TToken_string& rdiff = gm.add_colored_row(sheet, 'C');
rdiff.add(TR("Differenza cambio"), 4);
gm.add_importo(rdiff, diff);
rdiff.add((int)sum.tipo(), 11);
}
}
*/
} // Il pagamento era a saldo
} // Fine ciclo non assegnati
if (lastrow > 0)
{
TToken_string& sp = gm.add_colored_row(sheet, 'T');
sp.add(TR("Saldo partita"), 4);
if (prima_valuta.in_valuta())
sp << ' ' << prima_valuta.codice();
#ifdef __EXTRA__
prima_valuta.set(gm, P_VALUTA, P_DATACAMBIO, P_CAMBIO);
#endif
gm.add_importo(sp, tot_lit);
gm.add_importo(sp, tot_val, prima_valuta.codice());
}
if (should_delete_game)
delete game;
}
if (prima_valuta.in_valuta() != gm._valfirst)
{
sheet.swap_columns(106, 107); // Scambia le colonne dell'importo in lire e in valuta
gm._valfirst = !gm._valfirst;
}
TString80 header;
header = TR("Importo in "); header << TCurrency::get_firm_val();
sheet.set_column_header(106, header);
header = TR("Importo in ");
if (prima_valuta.in_valuta())
header << prima_valuta.codice();
else
header << TR("valuta");
sheet.set_column_header(107, header);
sheet.force_update();
if (sheet.items() > 0)
sheet.select(0, TRUE);
else
sheet.force_update();
}
if (k == K_INS)
{
gm.send_key(K_CTRL + 'N', 0, &partite); // Simula la pressione del tasto nuovo
return false; // Rifiuta l'aggiunta di una riga
}
return true;
}
static bool partita_bloccata(const TPartita& game)
{
int rate = 0, bloccate = 0;
for (int i = game.last(); i > 0; i = game.pred(i))
{
const TRiga_partite& riga = game.riga(i);
if (riga.tipo() == tm_fattura)
{
for (int r = riga.rate(); r > 0; r--)
{
rate++;
const TRiga_scadenze& rata = riga.rata(r);
if (rata.get_bool(SCAD_BLOCCATA))
bloccate++;
}
}
}
return bloccate > 0 && bloccate == rate;
}
bool TGame_mask::scadenze_notify(TSheet_field& scadenze, int r, KEY k)
{
if (k == K_INS)
{
TGame_mask& gm = (TGame_mask&)scadenze.mask();
#ifndef __EXTRA__
const TCausale& causale = app().causale();
const tipo_movimento tm = (tipo_movimento)causale.tipomov();
if (tm == tm_pagamento)
{
const TPartita* game = gm.partita_corrente();
if (game && partita_bloccata(*game))
return error_box(TR("Le rate della partita risultano bloccate"));
}
#endif
gm.send_key(K_CTRL + 'N', 0, &scadenze); // Simula la pressione del tasto nuovo
return false; // Rifiuta l'aggiunta di una riga
}
if (k == K_DEL || k == K_SPACE)
{
return false;
}
return true;
}
// Complesso algoritmo per calcolare la sezione di una nuova riga partita
char TGame_mask::calcola_sezione(tipo_movimento tm) const
{
char sezione = ' ';
const char tipoc = conto().tipo();
#ifndef __EXTRA__
const TCausale& causale = app().causale();
tm = (tipo_movimento)causale.tipomov();
sezione = causale.sezione(1); // Usa la sezione della causale
#endif
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';
}
#ifndef __EXTRA__
// 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'; // scambia segno
}
#endif
return sezione;
}
int TGame_mask::nuova_riga(TPartita& partita, tipo_movimento tm) const
{
const int una_riga = partita.last(); // Memorizza una riga valida
TRiga_partite& part = partita.new_row(); // Creazione nuova riga vuota
const int nriga = part.get_int(PART_NRIGA); // Nuova riga
// Copia dati movimento corrente
part.put(PART_NREG, _numreg); // Numero operazione
part.put(PART_NUMRIG, _numrig); // Riga su cui ho cliccato
// Forza il gruppo/conto cliente corretto
part.put(PART_GRUPPOCL, conto().gruppo());
part.put(PART_CONTOCL, conto().conto());
part.put(PART_TIPOMOV, (int)tm);
if (una_riga > 0)
{
const char* valuta = partita.riga(una_riga).get(PART_CODVAL);
part.put(PART_CODVAL, valuta);
}
#ifdef __EXTRA__
const TDate oggi(TODAY);
const char* s = oggi.string();
part.put(PART_DATADOC, s);
part.put(PART_DATAREG, s);
#else
// Setta il cambio corrente
const TValuta valuta(*this, P_VALUTA, P_DATACAMBIO, P_CAMBIO);
valuta.put(part);
TMask& cm = app().curr_mask();
const TCausale& causale = app().causale();
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, cm.get(F_DATAREG));
part.put(PART_TIPOPAG, 1);
const TRiga_partite* prima = (tm != tm_fattura) ? cerca_prima_riga() : NULL;
if (prima != NULL && prima != &part)
{
part.put(PART_DESCR, prima->get(PART_DESCR));
part.put(PART_DATAPAG, prima->get(PART_DATAPAG));
part.put(PART_TIPOPAG, prima->get(PART_TIPOPAG));
}
// Copia dati causale corrente
part.put(PART_CODCAUS, causale.codice());
if (causale.iva() != nessuna_iva)
{
part.put(PART_REG, cm.get(F_CODREG));
part.put(PART_PROTIVA, cm.get(F_PROTIVA));
}
#endif
const char sezione = calcola_sezione(tm);
// Memorizza solo la sezione (importi nulli)
part.put(PART_SEZ, sezione);
part.put(PART_SEZABB, sezione);
part.put(PART_SEZDIFCAM, sezione);
return nriga;
}
int TGame_mask::nuovo_pagamento(TPartita& partita, int nriga, int rata, tipo_movimento tm) const
{
#ifdef __EXTRA__
const int nrigp = nuova_riga(partita, tm);
#else
int nrigp = partita.mov2rig(_numreg, _numrig); // Cerca riga partita relativa alla riga rmov
const bool nuovo = nrigp <= 0;
if (nuovo) // Devo creare una nuova riga di partita
nrigp = nuova_riga(partita, tm);
#endif
TRectype& pagamento = partita.pagamento(nriga, rata, nrigp); // Crea nuovo pagamento
// Calcola riga causale per la contropartita in base al tipo pagamento
int caus = 2;
if (nriga != TPartita::UNASSIGNED)
{
const TRiga_partite& fatt = partita.riga(nriga);
const TRiga_scadenze& scad = fatt.rata(rata);
const int tp = scad.get_int(SCAD_TIPOPAG);
caus = partita.tipopag2causale(tp);
TRiga_partite& somma = partita.riga(nrigp);
somma.put(PART_TIPOPAG, tp);
somma.put(PART_CODVAL, fatt.get(PART_CODVAL));
pagamento.put(PAGSCA_CODABIPR, scad.get(SCAD_CODABIPR));
pagamento.put(PAGSCA_CODCABPR, scad.get(SCAD_CODCABPR));
pagamento.put(PAGSCA_CODABI, scad.get(SCAD_CODABI));
pagamento.put(PAGSCA_CODCAB, scad.get(SCAD_CODCAB));
pagamento.put(PAGSCA_CODAG, scad.get(SCAD_CODAG));
}
#ifndef __EXTRA__
if (pagamento.get_int(PAGSCA_GRUPPOC) == 0)
{
const TCausale& causale = app().causale();
TBill contro; causale.bill(caus, contro); // Legge conto contropartita
if (caus != 2 && contro.empty()) // Se non specificato ...
causale.bill(caus = 2, contro); // ... prende il primo
if (contro.sottoconto() == 0L)
{
const int nrow = app().type2pos('I');
if (nrow >= 0)
{
TSheet_field & cgs = app().cgs();
contro.get(cgs.row(nrow), 3);
}
}
contro.put(pagamento, TRUE); // Scrive conto contropartita
}
#endif
return nrigp;
}
bool TGame_mask::edit_scadenza_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TMask& m = f.mask();
const int nriga = m.get_int(101); // Numero riga fattura
if (nriga == 0)
return FALSE; // Ho cliccato su di un saldo (per sbaglio!)
TGame_mask& gm = (TGame_mask&)(m.get_sheet()->mask());
const TBill& bill = gm.conto(); // Clifo
TSheet_field& sp = gm.partite();
TToken_string& spr = sp.row(gm._riga_partite);
const int anno = spr.get_int(0); // Anno
const TString numero = spr.get(); // Numero
TPartite_array& giochi = app().partite();
TPartita* was = giochi.exist(bill, anno, numero); // Controlla esistenza nell'array
TPartita& game = was ? *was : giochi.partita(bill, anno, numero);
long nreg = m.get_long(108); // Numero registrazione
const int nrata = m.get_int(102); // Rata selezionata (puo' essere 0)
int nrigp = m.get_int(113); // Pagamento selezionato (puo' essere 0)
if (nrata != 0 && nrigp == 0)
{
if (m.get_bool(114))
{
if (was == NULL)
giochi.destroy(game);
return f.error_box(FR("La rata %d risulta bloccata."), nrata);
}
#ifndef __EXTRA__
const TValuta parval(game.riga(nriga));
const TValuta curval(gm, P_VALUTA, P_DATACAMBIO, P_CAMBIO);
if (parval != curval)
{
TString16 c = parval.codice();
if (c.empty()) c = TCurrency::get_firm_val();
if (was == NULL) giochi.destroy(game);
return f.error_box(FR("La fattura deve essere pagata in %s."), (const char*)c);
}
#endif
tipo_movimento tm = tm_pagamento;
#ifdef __EXTRA__
TMask* nm = new TNew_mask(gm.conto().tipo(), FALSE, FALSE);
nm->set(P_ANNO, game.anno());
// nm->set(P_NUMERO, game.numero()); // Non deve proporre nulla: CM000206
const KEY k = nm->run();
tm = (tipo_movimento)nm->get_int(P_NUOVO);
delete nm; nm = NULL;
if (k != K_ENTER)
{
if (was == NULL)
giochi.destroy(game);
return false;
}
#else
tm = (tipo_movimento)app().causale().tipomov();
#endif
nrigp = gm.nuovo_pagamento(game, nriga, nrata, tm);
nreg = gm._numreg;
}
bool cambiato = FALSE;
if (nrigp > 0) // Si vuole editare un pagamento
{
if (nreg == gm._numreg)
{
cambiato = gm.edit_pagamento(game, nriga, nrata, nrigp);
if (cambiato)
{
#ifdef __EXTRA__
game.rewrite(); // In extra-contabile salvo subito!
#endif
}
}
else
{
#ifdef __EXTRA__
gm.prima_nota(nreg);
if (m.is_running()) m.set_focus();
#else
if (was == NULL) giochi.destroy(game);
return f.error_box(FR("Modificare il movimento %ld"), nreg);
#endif
}
}
else
{ // Si vogliono editare le rate
#ifdef __EXTRA__
if (nreg > 0)
{
gm.prima_nota(nreg);
if (m.is_running()) m.set_focus();
}
else
cambiato = gm.edit_fattura(game, nriga);
#else
if (nreg != gm._numreg || nrata == 0)
{
if (nreg == 0)
f.error_box(TR("Utilizzare la gestione extra-contabile"));
else
f.error_box(FR("Modificare il movimento %ld"), nreg);
if (was == NULL) giochi.destroy(game);
return FALSE;
}
#endif
}
if (cambiato)
{
if (m.is_running()) // Se la maschera e' aperta la chiudo
m.stop_run(K_FORCE_CLOSE);
TSheet_field& ss = gm.scadenze();
const int rs = ss.selected(); // Memorizza la riga corrente
const int rt = ss.items(); // Memorizza numero righe correnti
gm.fill_partite(); // Aggiorna elenco partite
const int rn = ss.items(); // Memorizza nuovo numero righe
if (rs < rn) // Se esiste ancora ...
{
const bool scroll = rn > rt; // Scrolla solo se aggiungo righe
ss.select(rs, scroll); // ... riporta la selezione sulla riga corrente
}
gm._changed = TRUE;
gm.set_focus(); // A volte finisce sotto!
}
}
return TRUE;
}
bool TGame_mask::nuovo_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TGame_mask& gm = (TGame_mask&)f.mask();
int anno;
TString numero;
#ifdef __EXTRA__
const bool allow_fatt = TRUE;
#else
const bool allow_fatt = FALSE;
#endif
static TNew_mask* new_game = NULL;
if (new_game == NULL)
new_game = new TNew_mask(gm.conto().tipo(), allow_fatt, TRUE);
else
new_game->init(gm.conto().tipo(), allow_fatt, TRUE);
tipo_movimento tm = tm_pagamento;
#ifndef __EXTRA__
const TMask& cm = app().curr_mask();
tm = (tipo_movimento)app().causale().tipomov();
new_game->set(P_NUOVO, tm);
if (tm == tm_nota_credito)
{
new_game->set(P_ANNO, cm.get(F_ANNORIF));
new_game->set(P_NUMERO, cm.get(F_NUMRIF));
}
#endif
k = new_game->run();
tm = (tipo_movimento)new_game->get_int(P_NUOVO);
anno = new_game->get_int(P_ANNO);
numero = new_game->get(P_NUMERO);
// Distruzione maschera di richiesta
// delete new_game; new_game = NULL;
if (k == K_ENTER)
{
// Creazione nuova partita
TPartita& game = app().partite().partita(gm.conto(), anno, numero);
if (tm == tm_pagamento && partita_bloccata(game))
return error_box(TR("Le rate di questa partita risultano bloccate"));
bool edit = FALSE;
// N.B. Le fatture non possone essere editate in modo contabile
if (tm != tm_fattura)
{
const int nriga = TPartita::UNASSIGNED;
const int nrata = TPartita::UNASSIGNED;
const int nrigp = gm.nuovo_pagamento(game, nriga, nrata, tm);
edit = gm.edit_pagamento(game, nriga, nrata, nrigp);
#ifdef __EXTRA__
if (edit) game.rewrite();
#endif
}
#ifdef __EXTRA__
else
edit = gm.edit_fattura(game, 0);
#endif
if (edit)
{
gm.set(P_ANNO, anno);
gm.set(P_NUMERO, numero);
gm._changed = TRUE;
// Aggiorna sheet partite: aggiunge la nuova partita e lo riordina
gm.fill_partite();
} // Sono state apportate modifiche
}
}
return TRUE;
}
///////////////////////////////////////////////////////////
// Metodi della maschera delle partite
///////////////////////////////////////////////////////////
void TGame_mask::add_importo(TToken_string& s, const TImporto& i, const char* valuta, int pos)
{
if (i.is_zero())
s.add("", pos);
else
{
TImporto n(i); n.normalize();
const TCurrency curr(n.valore(), valuta);
TString80 v = curr.string(FALSE);
if (!real::is_null(v))
{
v.replace('.', ','); // Mette la virgola
v << ' ' << n.sezione();
s.add(v, pos);
}
else
s.add("", pos);
}
}
void TGame_mask::add_descrizione(TToken_string& s, const TRiga_partite& riga, int pos)
{
const TString& desc = riga.get(PART_DESCR);
if (desc.empty())
{
const TString& caus = riga.get(PART_CODCAUS);
if (caus.not_empty())
s.add(cache().get(LF_CAUSALI, caus, CAU_DESCR));
else
s.add("", pos);
}
else
s.add(desc, pos);
}
TImporto TGame_mask::get_importo(TToken_string& s, int pos) const
{
TFixed_string imp(s.get(pos)); imp.replace(',', '.');
const real i(imp);
const char sez = imp.right(1)[0];
return TImporto(sez, i);
}
int TGame_mask::update_partita(const TRectype& riga,
const TImporto& saldo, const TImporto& doc,
const TImporto& pag, const TImporto& imp,
int prow)
{
TSheet_field& games = partite();
TToken_string &r = games.row(prow); // Stringa di lavoro per lo sheet
if (!riga.empty()) // Esiste veramente
{
r.cut(0);
r.add(riga.get(PART_ANNO)); r.right_just(4); // Mette gli spazi se ce n'e' bisogno
r.add(riga.get(PART_NUMPART));
r.add(riga.get(PART_DATADOC));
r.add(riga.get(PART_NUMDOC));
add_importo(r, saldo);
add_importo(r, doc);
add_importo(r, pag);
add_importo(r, imp);
r.add(riga.get(PART_DESCR));
}
else
{
r.add("", 4);
r.add("", 5);
r.add("", 6);
r.add("", 7);
}
if (prow >= 0)
{
games.force_update(prow);
update_saldo_clifo();
games.force_update(games.items()-1);
aggiorna_residuo();
}
else
prow = partite().items()-1;
if (prow == 0)
{
const char all = TPartita::allineamento_richiesto(conto().tipo());
field(P_NUMERO).set_justify(all == 'R');
}
return prow;
}
int TGame_mask::update_partita(const TPartita& part, int prow)
{
int r = part.prima_fattura();
if (r <= 0) r = part.first();
TImporto saldo, doc, pag, imp;
part.calcola_saldo(saldo, doc, pag, imp);
prow = update_partita(part.riga(r), saldo, doc, pag, imp, prow);
return prow;
}
int TGame_mask::update_partita(const TRectype& riga, int prow)
{
TImporto saldo, doc, pag, imp;
TRectype rec = riga;
TPartita::read_saldo(rec, saldo, doc, pag, imp);
return update_partita(rec, saldo, doc, pag, imp, prow);
}
void TGame_mask::update_saldo_clifo()
{
TString_array& s = partite().rows_array();
TImporto sal, doc, pag, imp;
int i;
for (i = 0; i < s.items(); i++)
{
TToken_string& r = s.row(i);
if (r.get_int(0) > 0)
{
sal += get_importo(r, 4);
doc += get_importo(r, -1);
pag += get_importo(r, -1);
imp += get_importo(r, -1);
}
else
break;
}
TToken_string& r = s.row(s.add("", i));
r.add("");
r.add("");
r.add(TDate(TODAY).string());
r.add("");
add_importo(r, sal);
add_importo(r, doc);
add_importo(r, pag);
add_importo(r, imp);
r.add(TR("Saldo "));
append_conto(r);
COLOR back, fore;
app().type2colors('T', back, fore);
partite().set_back_and_fore_color(back, fore, i);
if (i > 0) // Se ho aggiunto una riga devo decolorare la precedente
partite().set_back_and_fore_color(NORMAL_BACK_COLOR, NORMAL_COLOR, i-1);
}
long TGame_mask::number_distance(const char* k, const char* n) const
{
TString16 key(k); key.upper(); key.trim();
const int kl = key.len();
TString16 num(n); num.upper(); num.trim();
const int nl = num.len();
long dist = 0;
for (int i = kl-1; i >= 0; i--)
{
const char kc = i < kl ? key[i] : 0;
const char nc = i < nl ? num[i] : 0;
const long d = abs(kc - nc) * (kl - i) * 32;
dist += d;
}
return dist;
}
bool TGame_mask::same_number(const char* key, const char* num) const
{
TString16 k(key); k.upper(); k.trim();
TString16 n(num); n.upper(); n.trim();
return k == n;
}
bool TGame_mask::partita_aperta(const TRectype& part) const
{
if (part.get_bool(PART_CHIUSA))
return FALSE;
TRectype sld(part);
TImporto saldo, doc, pag, imp;
const int err = TPartita::read_saldo(sld, saldo, doc, pag, imp);
if (err == NOERR && saldo.is_zero())
return FALSE;
return TRUE;
}
static int sort_games_num(const TObject** o1, const TObject** o2)
{
TToken_string& r1 = *(TToken_string*)*o1;
TToken_string& r2 = *(TToken_string*)*o2;
int diff = r1.get_int(0) - r2.get_int(0); // Anno
if (diff == 0)
{
diff = r1.get_long(1) - r2.get_long(1); // Numero Partita
if (diff == 0)
diff = r1.get_long(3) - r2.get_long(3); // Numero Documento
}
return diff;
}
static int sort_games_date(const TObject** o1, const TObject** o2)
{
TToken_string& r1 = *(TToken_string*)*o1;
TToken_string& r2 = *(TToken_string*)*o2;
int diff = r1.get_int(0) - r2.get_int(0); // Anno
if (diff == 0)
{
const TDate d1 = r1.get(2);
const TDate d2 = r2.get(2);
diff = d1 - d2; // Data documento
if (diff == 0)
diff = r1.get_long(3) - r2.get_long(3); // Numero Documento
}
return diff;
}
void TGame_mask::sort_partite()
{
TString_array& a = partite().rows_array();
// Elimina riga saldo se presente
int last = a.last();
if (last > 0 && a.row(last).get_int(0) == 0) // Se l'anno dell'ultima riga e' nullo ...
a.destroy(last--); // ... elimina riga saldo
// Ordina lista se necessario (ci sono almeno due partite)
if (last > 0)
{
switch (get(P_SORT)[0])
{
case 'N': a.TArray::sort(sort_games_num); break; // Ordine numerico
case 'D': a.TArray::sort(sort_games_date); break; // Ordine per data
default : a.sort(); break; // Ordine alfabetico
}
update_saldo_clifo(); // Ricrea riga saldo
}
partite().force_update(); // Aggiorna lo spreadsheet
}
void TGame_mask::fill_partite()
{
TWait_cursor hourglass;
const int annorif = get_int(P_ANNO); // Anno corrente
const TString16 numrif = get(P_NUMERO); // Partita corrente
const bool all = get(P_SHOWALL).not_empty(); // Visualizza anche partite chiuse
partite().destroy();
TString_array& a = partite().rows_array();
TPartite_array& giochi = app().partite();
for (TPartita* gioco = giochi.first(); gioco != NULL; gioco = giochi.next())
{
// Visualizza solo le partite con almeno una riga! Non posso scaricarle a priori in quanto
// potrebbero essere state cancellate proprio ora e quindi devo tenerle cosi' per aggiornare
// correttamente gli archivi.
if (gioco->ok())
{
const TBill& k = gioco->conto();
bool u = (k.tipo() > ' ' && k.sottoconto() == conto().sottoconto()) || k == conto();
if (u && !all && gioco->chiusa() && gioco->mov2rig(_numreg, _numrig) <= 0)
u = false;
if (u)
update_partita(*gioco, -1);
}
else
{ // Se la partita e' vuota ...
if (!gioco->is_on_file()) // ... e non esiste su file
giochi.destroy(*gioco); // posso eliminarla tranquillamente
}
}
TLocalisamfile partita(LF_PARTITE);
TRectype& curpar = partita.curr();
curpar.zero();
if (conto().tipo() > ' ') // Ignora gruppo e conto dei clifo
{
curpar.put(PART_TIPOCF, conto().tipo());
curpar.put(PART_SOTTOCONTO, conto().codclifo());
}
else
conto().put(curpar); // Scrive completamente i conti normali
const TRectype filter(curpar); // Record campione
for (int err = partita.read(_isgreat);
err == NOERR && curpar == filter;
err = partita.read(_isgreat))
{
if (!giochi.exist(curpar))
{
if (all || partita_aperta(curpar))
update_partita(curpar, -1);
}
// Forza lettura partita successiva nella prossima read
curpar.put(PART_NRIGA, (int)TPartita::UNASSIGNED);
}
sort_partite();
aggiorna_residuo();
if (!a.empty())
{
_riga_partite = -1;
int found = -1;
for (int r = a.last(); r >= 0; r--)
{
TToken_string& row = a.row(r);
const int anno = row.get_int(0);
const TString16 numero = row.get(1);
if (found < 0 && annorif == anno && same_number(numrif, numero))
found = r;
TPartita* gioco = app().partite().exist(conto(), anno, numero);
if (gioco != NULL && gioco->mov2rig(_numreg, _numrig) > 0)
{
COLOR back, fore;
app().type2colors('X', back, fore);
partite().set_back_and_fore_color(back, fore, r);
}
}
if (found < 0) found = 0;
partite().select(found, TRUE);
_ignore_next_select = !is_running();
}
else
{
scadenze().destroy();
}
}
bool TGame_mask::edit_pagamento(TPartita& p, int nriga, int nrata, int nrigp) const
{
if (nrigp <= 0)
return false;
TRectype oldpag = p.pagamento(nriga, nrata, nrigp);
TRiga_partite& somma = p.riga(nrigp);
const bool nuovo = oldpag.get_char(PAGSCA_ACCSAL) != 'S' &&
oldpag.get_real(PAGSCA_IMPORTO).is_zero() &&
oldpag.get_real(PAGSCA_RITENUTE).is_zero() &&
oldpag.get_real(PAGSCA_RITSOC).is_zero();
// We must create masks on the heap
static TPay_mask* pm = NULL;
if (pm == NULL)
pm = new TPay_mask(this, nuovo ? MODE_INS : MODE_MOD);
else
pm->init(this, nuovo ? MODE_INS : MODE_MOD);
TPay_mask& m = *pm;
if (nriga == TPartita::UNASSIGNED)
{
TRiga_scadenze& scaden = somma.new_row(); // Crea una rata falsa
scaden.put(SCAD_DATASCAD, somma.get(PART_DATADOC));
m.set_pag(oldpag, scaden, _residuo);
somma.destroy_rows(); // Distrugge la rata falsa
}
else
{
const TRiga_scadenze& scaden = p.rata(nriga, nrata);
m.set_pag(oldpag, scaden, _residuo);
}
if (nuovo) // Inizializza automaticamente l'importo
{
TMask_field& imp = m.field(S_IMPORTO);
imp.set_dirty();
imp.on_key(K_F8);
}
KEY key = m.run();
if (key == K_DEL)
{
const bool truly = yesno_box(TR("Confermare l'eliminazione"));
if (!truly) key = K_ESC;
}
if (key == K_ESC && nuovo)
key = K_DEL;
if (key != K_ESC)
{
TRectype newpag(oldpag);
if (key == K_DEL)
{
newpag.zero(PAGSCA_ACCSAL); // Non puo' essere un saldo
newpag.zero(PAGSCA_IMPORTO); // Azzera importo ...
newpag.zero(PAGSCA_IMPORTOVAL); // .. anche in valuta
newpag.zero(PAGSCA_RITENUTE); // Azzera ritenute
newpag.zero(PAGSCA_RITSOC);
}
else
{
m.get_pag(newpag, somma);
}
const TValuta val(somma);
#ifdef __EXTRA__
p.modifica_pagamento(newpag, val, TRUE);
#else
if (somma.is_nota_credito())
p.modifica_pagamento(newpag, val, TRUE);
else
app().notify_edit_pagamento(p, newpag, val);
#endif
}
// delete pm; pm = NULL; // commentata in quanto statica
#ifdef __EXTRA__
xvtil_statbar_set(TR("Estratto conto"), TRUE);
#endif
return key != K_ESC;
}
#ifndef __EXTRA__
///////////////////////////////////////////////////////////
// Edit delle partite
///////////////////////////////////////////////////////////
static bool genera_riferimento(int riga, TString& rif)
{
TToken_string& row = app().cgs().row(riga);
const char tipocf = row.get_char(CG_TIPO - 101);
if (tipocf != 'C' && tipocf != 'F')
return false;
rif = ini_get_string(CONFIG_DITTA, "cg", tipocf == 'C' ? "DescInc" : "DescPag");
if (rif.blank())
return false;
const TMask& mov_mask = app().curr_mask();
bool ok = true;
for (int p = rif.find('{'); p >= 0; p = rif.find('{'))
{
char conn = ' ';
int q = p + 1;
if (rif[q] == '\\' || rif[q] == '&' || rif[q] == '|')
conn = rif[q++];
const int last = rif.find('}', p);
const TString16 field_name(rif.sub(q, last));
const TFieldref field(field_name, LF_MOV);
if (last < 0)
rif.cut(p);
else
{
const int len = rif.len() - last;
for (int i = 0; i <= len; i++)
rif[p + i] = rif[last + i + 1];
}
TString val;
if (field.file() == LF_MOV)
{
const TMask_field* mf = mov_mask.find_by_fieldname(field.name());
if (mf != NULL)
{
val = mf->get();
if (field.to() > 0)
val = val.sub(field.from(), field.to());
rif.insert(val, p);
}
} else
if (field.file() == LF_RMOV)
{
TMask& row_mask = app().cgs().sheet_row_mask(riga);
const TMask_field* rf = row_mask.find_by_fieldname(field.name());
if (rf != NULL)
{
val = rf->get();
if (field.to() > 0)
val = val.sub(field.from(), field.to());
rif.insert(val, p);
}
} else
if (field.file() == LF_PARTITE)
{
TToken_string lista(50,',');
TPartite_array& games = app().partite();
const long nreg = mov_mask.insert_mode() ? 999999 : mov_mask.get_long(F_NUMREG);
for (TPartita* game = games.first(); game; game = games.next())
{
int nriga = game->mov2rig(nreg, riga+1);
if (nriga > 0)
{
nriga = game->prima_fattura();
if (nriga > 0)
{
val = field.read(game->riga(nriga));
if (val.full() && lista.get_pos(val) < 0)
lista.add(val);
}
}
}
val = lista;
rif.insert(val, p);
}
switch (conn)
{
case '\\' :
ok = val.full();
break;
case '&' :
ok &= val.full();
break;
case '|' :
ok |= val.full();
break;
default :
break;
}
}
if (!ok)
rif.cut(0);
return ok;
}
bool TPrimanota_application::edit_partite(const TMask& m, int riga)
{
const char tipo = m.get(CG_TIPO)[0];
const char rt = m.get(CG_ROWTYPE)[0];
if (rt == 'T' && tipo <= ' ') // Nelle note di credito DEVE essere un clifo
return false;
const int gruppo = m.get_int(CG_GRUPPO);
const int conto = m.get_int(CG_CONTO);
const long sottoconto = m.get_long(CG_SOTTOCONTO);
TBill b(gruppo, conto, sottoconto, tipo); // Legge il conto della riga selezionata
// Esci se il conto della riga cliente non e' valido
if (!b.ok() || !b.find())
return m.field(CG_SOTTOCONTO).error_box(TR("Conto assente"));
// Aggiorna conto sulla riga contabile
b.add_to(cgs().row(riga), 3, 0x0);
TMovimentoPN* pn = (TMovimentoPN*)get_relation();
curr_mask().autosave(*pn); // Aggiorna i dati della testata sulle partite
long numreg = pn->curr().get_long(MOV_NUMREG);
if (curr_mask().insert_mode())
numreg = NUMREG_PROVVISORIO;
partite().update_reg(pn->curr());
bool changed = false;
if (_easy_sal)
{
// Nuova maschera di gestione partite
static TEasySolder_mask* mask = NULL;
if (mask == NULL)
mask = new TEasySolder_mask(b, numreg, riga+1);
else
mask->init(b, numreg, riga+1);
changed = mask->run() != K_ESC;
}
else
{
// Maschera tradizionale di gestione partite
static TGame_mask* mask = NULL;
if (mask == NULL)
mask = new TGame_mask(b, numreg, riga+1);
else
mask->init(b, numreg, riga+1);
mask->run();
changed = mask->changed();
}
if (changed)
{
TSheet_field& s = cgs();
if (m.field(CG_DESCR).empty())
{
TString descr;
if (genera_riferimento(riga, descr))
{
const int idx = s.cid2index(CG_DESCR);
TToken_string& sr = s.row(riga);
sr.add(descr, idx);
TBill conto; conto.get(sr, 2, 0x3);
for (int r = riga+1; r < s.items(); r++)
{
TToken_string& sr = s.row(r);
TBill contro; contro.get(sr, 9, 0x3);
if (conto == contro)
sr.add(descr, idx);
}
}
}
s.force_update(); // Aggiornamento righe contabili
calcola_saldo();
_sal_dirty = true;
}
return changed;
}
bool TPrimanota_application::crea_partita(const TBill& bill, int anno, const TString& numero, int numrig, const TImporto& importo)
{
TMask& cm = curr_mask();
TPartita& partita = app().partite().partita(bill, anno, numero);
TRiga_partite& part = partita.new_row(); // Creazione nuova riga vuota
const int nriga = part.get_int(PART_NRIGA); // Nuova riga
// Copia dati movimento corrente
const long numreg = cm.insert_mode() ? NUMREG_PROVVISORIO : cm.get_long(F_NUMREG);
part.put(PART_NREG, numreg); // Numero operazione
part.put(PART_NUMRIG, numrig); // Riga su cui ho cliccato
// Forza il gruppo/conto cliente corretto (lo fa gia' anche la new_row)
part.put(PART_GRUPPOCL, bill.gruppo());
part.put(PART_CONTOCL, bill.conto());
const TCausale& causale = app().causale();
const tipo_movimento tm = (tipo_movimento)causale.tipomov();
part.put(PART_TIPOMOV, int(tm));
// Setta il cambio corrente
const TValuta valuta(cm, SK_VALUTA, SK_DATACAMBIO, SK_CAMBIO);
valuta.put(part);
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, cm.get(F_DATAREG));
part.put(PART_TIPOPAG, 1); // Rimessa diretta
// Copia dati causale corrente
part.put(PART_CODCAUS, causale.codice());
if (causale.iva() != nessuna_iva)
{
part.put(PART_REG, cm.get(F_CODREG));
part.put(PART_PROTIVA, cm.get(F_PROTIVA));
}
const char sezione = importo.sezione();
// Memorizza solo la sezione (importi nulli)
part.put(PART_SEZ, sezione);
part.put(PART_SEZABB, sezione);
part.put(PART_SEZDIFCAM, sezione);
if (tm != tm_fattura)
{
// Crea nuovo pagamento
TRectype pagamento = partita.pagamento(TPartita::UNASSIGNED, TPartita::UNASSIGNED, nriga);
const real implit = importo.valore();
pagamento.put(PAGSCA_IMPORTO, implit);
if (valuta.in_valuta())
{
const real impval = valuta.eur2val(implit);
pagamento.put(PAGSCA_IMPORTOVAL, impval);
}
partita.modifica_pagamento(pagamento, valuta, TRUE);
}
return TRUE;
}
#endif