campo-sirio/pe/pe1400.cpp

1663 lines
43 KiB
C++

#include <automask.h>
#include <colors.h>
#include <controls.h>
#include <dongle.h>
#include <execp.h>
#include <printer.h>
#include <relapp.h>
#include <utility.h>
#include "../ca/calib01.h"
#include "../mg/mglib.h"
#include "../ve/velib.h"
#include "pe1400.h"
#include "pe1401.h"
#include "pe1500.h"
#include "../db/rdist.h"
#include "../mg/anamag.h"
#include "../ca/commesse.h"
static real ricarico2perc(const TString& exp)
{
real val_perc = UNO;
if (exp.full())
{
TString80 num;
bool dec = false; // Flag che indica se si attende l'inizio di un numero
bool startnum = true; // Flag che indica se siamo all'inizio di un numero
int errorchar = ' ';
bool valid = true;
// Flag che indica se sono nella parte decimale di un numero
for (const char* s = exp; *s && errorchar == ' '; s++)
{
const char c = *s;
switch(c)
{
case '+':
case '-':
// Se ero in in numero ...
if( !startnum )
{
// Aggiunge il numero alla sequenza
const real val = num;
val_perc *= ( CENTO + val ) / CENTO;
}
// Inizia il nuovo numero
num = (c == '-') ? "-" : "+";
startnum = true;
dec = false;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
num << c;
startnum = false;
break;
case '.':
case ',':
if(!dec)
{
if( startnum )
num << '0'; // Se occorreva un numero ci metto lo 0
num << '.'; // Interpreto la virgola come punto
dec = true;
startnum = true;
}
else
errorchar = c; // Se siamo già nella parte decimale segnala un errore
break;
case ' ':
break;
default:
errorchar = c;
break;
}
}
// Controlla la validità
valid = errorchar == ' ';
if (valid)
{
// Aggiunge l'ultimo numero preso
const real val = num;
val_perc *= ( CENTO + val ) / CENTO;
}
}
return val_perc;
}
///////////////////////////////////////////////////////////
// TPreventivo_app
///////////////////////////////////////////////////////////
class TPreventivo_app : public TRelation_application
{
TMask* _qmsk;
TMask* _emsk;
TRelation* _rel;
bool _revisioning;
TString8 _codelab;
protected:
int save_rows(const TMask& m);
virtual const char* extra_modules() const { return "ci"; }
bool save_and_print(TPrtype mode);
public:
virtual bool user_create();
virtual bool user_destroy();
virtual bool changing_mask(int mode) { return !(_revisioning && mode == MODE_INS); }
virtual TMask* get_mask(int mode) { return mode == MODE_QUERY ? _qmsk : _emsk; }
virtual TRelation* get_relation() const { return _rel; }
virtual bool get_next_key(TToken_string& key);
virtual bool has_filtered_cursor() const { return true; }
virtual TCursor& get_filtered_cursor() const;
virtual void init_insert_mode(TMask& m);
virtual void init_modify_mode(TMask& m);
virtual const char* record_description(const TRelation& rel) const;
virtual int read(TMask& m);
virtual int write(const TMask& m);
virtual int rewrite(const TMask& m);
virtual bool remove();
virtual void print();
virtual void preview();
void update_tools(TMask& m);
bool set_elab_code(const TString& cod) { _codelab = cod; return cod.full(); }
};
inline TPreventivo_app& app() { return (TPreventivo_app&)main_app(); }
///////////////////////////////////////////////////////////
// TPreventivo_nmsk
///////////////////////////////////////////////////////////
class TPreventivo_nmsk : public TAutomask
{
TString4 _codnum;
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
TPreventivo_nmsk(const TString& codnum);
};
bool TPreventivo_nmsk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch(o.dlg())
{
case F_ANNO:
if (e == fe_modify && !o.empty())
on_field_event(efield(F_NDOC), fe_init, 0L);
break;
case F_NDOC:
if (e == fe_init)
{
long n = 1;
TString query;
query << "USE DOC"
<< "\nFROM PROVV=D ANNO=#ANNO CODNUM=#CODNUM"
<< "\nTO PROVV=D ANNO=#ANNO CODNUM=#CODNUM";
TISAM_recordset recset(query);
recset.set_var("#ANNO", get(F_ANNO));
recset.set_var("#CODNUM", _codnum);
if (recset.move_last())
{
const TCodice_numerazione& num = cached_numerazione(_codnum);
const int revlen = num.revision_len();
TString8 ndoc = recset.get(DOC_NDOC).as_string();
if (revlen > 0) ndoc.rtrim(revlen);
n += atol(ndoc);
}
o.set(n);
} else
if (e == fe_modify || e == fe_close)
{
TString8 ndoc;
const TCodice_numerazione& num = cached_numerazione(_codnum);
const int revlen = num.revision_len();
if (revlen > 0)
ndoc.format("%d%0*d", atoi(o.get()), revlen, 1);
else
ndoc = o.get();
TLocalisamfile doc(LF_DOC);
doc.put(DOC_PROVV, "D");
doc.put(DOC_ANNO, get(F_ANNO));
doc.put(DOC_CODNUM, _codnum);
doc.put(DOC_NDOC, ndoc);
if (doc.read() == NOERR)
return error_box("Preventivo già esistente");
}
break;
default:
break;
}
return true;
}
TPreventivo_nmsk::TPreventivo_nmsk(const TString& codnum) : TAutomask(TR("Nuovo preventivo"), 1, 30, 6), _codnum(codnum)
{
const TCodice_numerazione& num = cached_numerazione(_codnum);
const int revlen = num.revision_len();
add_number(F_NDOC, 0, PR("Codice "), 13, 1, 7-revlen).check_type(CHECK_REQUIRED);
add_number(F_ANNO, 0, PR("Anno "), 1, 1, 4, "A").check_type(CHECK_REQUIRED);
add_button(DLG_OK, 0, "", -12, -1, 9, 2);
add_button(DLG_CANCEL, 0, "", -22, -1, 9, 2);
set_handlers();
}
///////////////////////////////////////////////////////////
// TPreventivo_msk
///////////////////////////////////////////////////////////
// Classe di base per maschere preventivi (query ed edit)
class TPreventivo_msk : public TAutomask
{
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
virtual TMask_field* parse_field(TScanner& s);
public:
int revision_length() const;
int split_ndoc(long ndoc, int& nprev, int& nrev) const;
int join_ndoc(int nprev, int nrev, long& ndoc) const;
TPreventivo_msk(const char* name) { read_mask(name, 0, 8); set_handlers(); }
};
TMask_field* TPreventivo_msk::parse_field(TScanner& s)
{
if (s.key() == "TL")
set_full_screen_interface(page_win(1), true);
return TAutomask::parse_field(s);
}
int TPreventivo_msk::revision_length() const
{
int rl = 0;
const TString& codnum = get(F_CODNUM);
if (codnum.full())
{
const TCodice_numerazione& num = cached_numerazione(codnum);
rl = num.revision_len();
}
return rl;
}
int TPreventivo_msk::split_ndoc(long ndoc, int& nprev, int& nrev) const
{
nprev = nrev = 0;
const int revlen = revision_length();
if (revlen > 0)
{
TString8 sdoc; sdoc << ndoc;
if (sdoc.len() > revlen)
{
nrev = atoi(sdoc.right(revlen));
nprev = atoi(sdoc.rtrim(revlen));
}
}
else
nprev = ndoc;
return revlen;
}
int TPreventivo_msk::join_ndoc(int nprev, int nrev, long& ndoc) const
{
ndoc = 0L;
const int revlen = revision_length();
if (revlen > 0)
{
ndoc = nprev;
for (int i = 0; i < revlen; i++)
ndoc *= 10;
ndoc += nrev > 0 ? nrev : 1;
}
else
ndoc = nprev;
return revlen;
}
bool TPreventivo_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case F_CODNUM:
if (e == fe_init || e == fe_modify)
{
if (o.empty())
{
TCursor& c = *((TEdit_field&)o).browse()->cursor();
c = 0L;
o.set(c.curr().get("CODTAB"));
o.check();
}
int revlen = 0;
if (!o.empty())
{
const TCodice_numerazione& num = cached_numerazione(o.get());
revlen = num.revision_len();
set(F_TIPODOC, num.tipo_doc(0), 0x3);
}
if (revlen > 0)
{
RCT rct;
TEdit_field& prv = efield(F_NPREV);
prv.set_len(7-revlen);
prv.get_rect(rct);
rct.right = rct.left + CHARX * (8-revlen);
prv.set_rect(rct);
TEdit_field& rev = efield(F_NREV);
rev.set_len(revlen);
rev.get_rect(rct);
rct.right = rct.left + CHARX * (revlen+1);
rev.set_rect(rct);
show(F_NREV);
}
else
hide(F_NREV);
}
break;
case F_NDOC:
if (!o.empty() && (e == fe_init || e == fe_modify))
{
const long ndoc = atol(o.get());
int nprev = 0, nrev = 0;
const int revlen = split_ndoc(ndoc, nprev, nrev);
set(F_NPREV, nprev);
set(F_NREV, nrev);
if (revlen == 0)
reset(F_NPREV);
}
break;
default:
if ((e == fe_modify || e == fe_close) && (!o.empty() && o.is_edit()))
{
const TFieldref* fr = o.field();
if (fr != NULL && fr->name() == RDOC_CODCMS)
{
TRelation rel(LF_RIGHEDOC);
o.mask().autosave(rel);
const TString& cms = rel.curr().get(RDOC_CODCMS);
const TRectype& rec = cache().get(LF_COMMESSE, cms);
if (rec.get_bool(COMMESSE_CHIUSA))
return error_box(FR("Impossibile utilizzare la commesa chiusa %s"), (const char*)cms);
}
}
break;
}
return true;
}
///////////////////////////////////////////////////////////
// TPreventivo_qmsk
///////////////////////////////////////////////////////////
class TPreventivo_qmsk : public TPreventivo_msk
{
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
TPreventivo_qmsk() : TPreventivo_msk("pe1400a") {}
};
bool TPreventivo_qmsk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
return TPreventivo_msk::on_field_event(o, e, jolly);
}
///////////////////////////////////////////////////////////
// TPreventivo_emsk
///////////////////////////////////////////////////////////
class TPreventivo_emsk : public TPreventivo_msk
{
TPreventivo_tree* _tree;
TString _idfase, _iddist;
int _edit_dist, _edit_dett, _edit_misu;
int _curr_dist, _curr_dett, _curr_misu;
bool _locked, _has_db;
private:
bool on_fasi_button(TOperable_field& btn, TField_event e, long jolly);
bool on_fasi_event(TTree_field& s, TField_event e, long jolly);
bool set_fase(const TString& idf);
bool set_dist(const TString& idd);
bool set_dist(int row);
void update_dist(const real& val, int column);
void update_dist_qta();
void update_dist_costo();
bool on_dett_event(TOperable_field& o, TField_event e, long jolly);
bool on_misu_event(TOperable_field& o, TField_event e, long jolly);
bool on_dist_event(TOperable_field& o, TField_event e, long jolly);
real get_costo(const TString& codart, TString& um, TString& iva) const;
protected:
virtual bool on_key(KEY k);
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
void set_sheet_color(short id, COLOR col);
bool sync_tree();
bool msk2rec(const TMask& msk, TRectype& rec) const;
public:
TPreventivo_tree& tree(bool reset = false);
TPreventivo_emsk();
};
TPreventivo_tree& TPreventivo_emsk::tree(bool reset)
{
if (_tree == NULL)
{
_tree = new TPreventivo_tree(tfield(F_FASI));
reset = true;
}
if (reset)
{
TRectype doc(LF_DOC);
doc.put(DOC_PROVV, 'D');
doc.put(DOC_ANNO, get(F_ANNO));
doc.put(DOC_CODNUM, get(F_CODNUM));
doc.put(DOC_NDOC, get(F_NDOC));
_tree->append_row(doc);
TTree_field& tf = tfield(F_FASI);
tf.set_tree(_tree);
tf.hide_leaves();
}
return *_tree;
}
static bool set_and_check(TMask_field& f, const TRectype& rec)
{
const TFieldref* fr = f.field();
if (fr == NULL)
{
if (f.ghost())
return f.on_hit();
return false;
}
if (fr->name() == RDOC_DESCR)
{
TString descr(255);
descr = rec.get(RDOC_DESCR);
if (rec.get_bool(RDOC_DESCLUNGA))
descr << rec.get(RDOC_DESCEST);
f.set(descr);
}
else
{
f.set(fr->read(rec));
if (!f.empty() && f.is_edit() && f.shown())
{
const TBrowse* b = ((TEdit_field&)f).browse();
if (b != NULL)
{
const TFixed_string of = b->get_output_fields();
if (of.find('|') > 0) // C'è un pipe nell'output, per cui ci sono almeno due campi di output
f.check(STARTING_CHECK);
}
}
}
return true;
}
// Riempie gli sheet di articoli e misure della distinta selezionata
bool TPreventivo_emsk::set_dist(const TString& idd)
{
TPreventivo_tree& t = tree();
bool ok = idd.full();
if (_iddist != idd)
{
_iddist = idd;
// Svuota sheet articoli
TSheet_field& a = sfield(F_ARTICOLI);
a.hide();
a.destroy();
// Svuota sheet misure
TSheet_field& m = sfield(F_MISURE);
m.hide();
m.destroy();
// Scandisce i figli della distinta e li smista tra i due sheet
ok = idd.full() && t.goto_node(idd);
if (ok)
{
_locked = true; // Diabilita ricalcolo prezzi
int n = 0;
for (bool ok = t.goto_firstson(); ok; ok = t.goto_rbrother())
{
const TRectype& rec = *t.curr_row();
TSheet_field& s = rec.get(RDOC_TIPORIGA) == t.tipo_dett() ? a : m;
TMask& m = s.sheet_row_mask(n);
FOR_EACH_MASK_FIELD(m, i, f)
set_and_check(*f, rec);
s.update_row(n++);
}
_locked = false;
}
// Visualizza nuovamente i due sheet eventualemente riempiti
a.force_update(); a.show();
m.force_update(); m.show();
}
_curr_dist = -1;
if (ok && t.goto_node(idd))
{
_curr_dist = 0;
while(t.goto_lbrother())
_curr_dist++;
}
return ok;
}
bool TPreventivo_emsk::set_dist(int row)
{
TPreventivo_tree& t = tree();
bool ok = _idfase.full() && t.dist(_idfase, row) != NULL;
if (ok)
{
TString16 idd; t.curr_id(idd);
ok = set_dist(idd);
CHECK(ok && row == _curr_dist, "Distinta sospetta");
}
return ok;
}
// Riempie lo sheet delle distinte della fase selezionata
bool TPreventivo_emsk::set_fase(const TString& idfase)
{
_idfase = idfase;
// Svuota lo sheet delle distinte
TSheet_field& d = sfield(F_DISTINTE);
d.destroy();
TString idd;
TPreventivo_tree& t = tree();
bool ok = idfase.full() && t.goto_node(idfase);
if (ok)
{
// Scandisce le distinte della fase corrente
if (t.goto_firstson())
{
t.curr_id(idd); // Memorizza la prima distinta per dopo...
int n = 0;
do
{
const TRectype& rec = *t.curr_row();
TMask& m = d.sheet_row_mask(n);
FOR_EACH_MASK_FIELD(m, i, f)
set_and_check(*f, rec);
d.update_row(n++);
} while (t.goto_rbrother());
}
}
d.force_update();
set_dist(idd);
return ok;
}
bool TPreventivo_emsk::msk2rec(const TMask& msk, TRectype& rec) const
{
TRelation rel(rec.num());
rel.curr() = rec;
msk.autosave(rel);
rec = rel.curr();
const TString& desc = msk.get(RDOC_DESCR);
const int maxlen = rec.length(RDOC_DESCR);
int spc = desc.find('\n');
if (spc >= 0 || desc.len() > maxlen)
{
if (spc < 0 || spc > maxlen)
{
spc = desc.left(maxlen).rfind(' ');
if (spc < maxlen/2)
spc = maxlen;
}
rec.put(RDOC_DESCR, desc.left(spc));
rec.put(RDOC_DESCLUNGA, "X");
rec.put(RDOC_DESCEST, desc.mid(spc));
}
else
{
rec.put(RDOC_DESCR, desc);
rec.zero(RDOC_DESCLUNGA);
rec.put(RDOC_DESCEST, "");
}
return !rec.empty();
}
bool TPreventivo_emsk::on_key(KEY k)
{
if (k == K_SHIFT + K_F12)
{
enable(F_STATO);
return true;
}
return TAutomask::on_key(k);
}
bool TPreventivo_emsk::on_fasi_button(TOperable_field& o, TField_event e, long jolly)
{
TPreventivo_tree& t = tree();
TTree_field& fasi = t.owner();
TPreventivo_level pl = pl_documento;
if (fasi.goto_selected())
pl = t.level();
else
return false;
if (pl == pl_documento && o.dlg() == F_FASENEW)
pl = pl_fase1;
if (pl < pl_fase1 || pl > pl_distinta)
return false;
o.disable();
switch (o.dlg())
{
case F_FASENEW:
{
TMask m("Nuovo", 1, 46, 7);
m.add_string(S_CODART, 0, "Codice ", 1, 1, 20).check_type(CHECK_REQUIRED);
m.add_string(S_DESCR, 0, "Descrizione ", 1, 2, 50, "", 30).check_type(CHECK_REQUIRED);
m.add_button(DLG_OK, 0, "", -12, -1, 10, 2);
m.add_button(DLG_CANCEL, 0, "", -22, -1, 10, 2);
if (m.run() == K_ENTER)
{
TRectype* rec = t.new_row(pl);
rec->put(RDOC_CODART, m.get(S_CODART));
rec->put(RDOC_DESCR, m.get(S_DESCR));
if (tree().level() == pl)
t.add_rbrother(rec);
else
{
t.append_row(*rec);
delete rec;
}
}
}
break;
case F_FASEDIT:
{
TRectype& rec = *t.curr_row();
TMask m("Modifica", 1, 46, 7);
m.add_string(S_CODART, 0, "Codice ", 1, 1, 20).check_type(CHECK_REQUIRED);
m.add_string(S_DESCR, 0, "Descrizione ", 1, 2, 50, "", 30).check_type(CHECK_REQUIRED);
m.add_button(DLG_OK, 0, "", -13, -1, 10, 2);
m.add_button(DLG_DELREC, 0, "", -23, -1, 10, 2);
m.add_button(DLG_CANCEL, 0, "", -33, -1, 10, 2);
m.set(S_CODART, rec.get(RDOC_CODART));
m.set(S_DESCR, rec.get(RDOC_DESCR));
switch (m.run())
{
case K_ENTER:
rec.put(RDOC_CODART, m.get(S_CODART));
rec.put(RDOC_DESCR, m.get(S_DESCR));
break;
case K_DEL:
t.kill_node();
break;
default:
break;
}
}
break;
case F_FASEUP:
t.swap_left();
if (pl == pl_distinta)
{
TString16 id; t.curr_id(id);
set_fase(_idfase);
t.goto_node(id);
}
break;
case F_FASEDN:
t.swap_right();
if (pl == pl_distinta)
{
TString16 id; t.curr_id(id);
set_fase(_idfase);
t.goto_node(id);
}
break;
case F_FASELT:
if (pl > pl_fase1 && pl < pl_distinta && t.push_up())
t.curr_row()->put(RPRV_LEVEL, t.curr_depth()-1);
break;
case F_FASERT:
if (pl >= pl_fase1 && pl < t.last_fase_level() && t.push_down())
t.curr_row()->put(RPRV_LEVEL, t.curr_depth()-1);
break;
default:
break;
}
o.enable();
fasi.select_current();
fasi.force_update();
return true;
}
bool TPreventivo_emsk::on_fasi_event(TTree_field& fasi, TField_event e, long jolly)
{
bool modified = false;
bool can_edit = false;
bool can_goup = false;
bool can_godn = false;
bool can_golt = false;
bool can_gort = false;
switch (e)
{
case fe_modify:
if (fasi.goto_selected())
{
modified = true;
TPreventivo_tree& t = tree();
TPreventivo_level td = t.level();
if (td > pl_documento)
{
can_edit = true;
can_goup = t.has_lbrother();
can_godn = t.has_rbrother();
if (td >= pl_fase1 && td < pl_distinta) // Cambio fase
{
can_golt = td > pl_fase1;
can_gort = td < t.last_fase_level();
TString16 id;
t.curr_id(id);
set_fase(id);
}
else
{
while (td > pl_distinta)
{
t.goto_father();
td = t.level();
}
TString idd; t.curr_id(idd);
if (t.goto_father())
{
TString idf; t.curr_id(idf);
if (idf != _idfase)
set_fase(idf);
}
set_dist(idd);
}
}
}
break;
default:
break;
}
if (modified)
{
enable(F_FASEDIT, can_edit);
enable(F_FASEUP, can_goup);
enable(F_FASEDN, can_godn);
enable(F_FASELT, can_golt);
enable(F_FASERT, can_gort);
}
return true;
}
bool TPreventivo_emsk::on_dist_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case D_CODDIS:
case D_CODART:
if (e == fe_modify && !o.empty())
{
const TString& codart = o.get();
TRecord_array rdist(codart, LF_RDIST);
if (rdist.rows() > 0 && sfield(F_ARTICOLI).empty())
{
TPreventivo_tree& t = tree();
while (t.dett(_iddist, 0))
t.kill_node();
const int last = rdist.last_row();
int n = 0;
for (int r = rdist.first_row(); r > 0 && r <= last; r = rdist.succ_row(r))
{
const TRectype& rd = rdist.row(r);
const TCodice_articolo codart = rd.get(RDIST_CODCOMP);
TString80 desc = rd.get(RDIST_DESCR);
if (desc.empty())
desc = cache().get(LF_ANAMAG, codart, ANAMAG_DESCR);
TRectype* rec = t.dett(_iddist, n++, true);
rec->put(RDOC_CODART, codart);
rec->put(RDOC_DESCR, desc);
rec->put(RDOC_UMQTA, rd.get(RDIST_UM));
rec->put(RDOC_QTA, rd.get(RDIST_EXPR));
}
t.goto_node(_iddist);
sync_tree();
// Forza aggiornamento dello sheet
const TString16 id = _iddist;
_iddist.cut(0);
set_dist(id);
}
TString4 um, iva;
const real costo = get_costo(codart, um, iva);
TMask& m = o.mask();
m.set(D_UM, um);
m.set(D_COSTO, costo, 0x3);
}
break;
case D_COSTO:
if (e == fe_modify && !o.empty())
{
const TString& ric = get(F_RICARICO);
if (ric.full())
{
TMask& m = o.mask();
const real k = ricarico2perc(ric);
const real prezzo = real(o.get()) * k;
m.set(o.dlg()+1, prezzo);
}
}
break;
case F_DISTINTE:
switch (e)
{
case se_enter:
_edit_dist = -1;
set_dist(_curr_dist = jolly);
break;
case se_query_add:
return _idfase.full();
case se_notify_add:
{
TPreventivo_tree& t = tree();
TRectype* rec = t.dist(_idfase, _curr_dist = jolly, true);
if (rec != NULL)
sync_tree();
}
break;
case se_query_modify:
if (jolly != _curr_dist)
set_dist(jolly);
_edit_dist = _curr_dist = jolly;
break;
case se_leave:
case se_notify_modify:
if (_edit_dist >= 0)
{
const int r = _edit_dist; // Memorizza numero riga corrente
_edit_dist = -1; // Annulla numero riga corrente
TRectype* rec = tree().dist(_idfase, r, true);
if (rec != NULL)
{
const TMask& m = ((TSheet_field&)o).sheet_row_mask(r);
msk2rec(m, *rec);
sync_tree();
}
}
break;
case se_notify_del:
if (_curr_dist >= 0)
{
TPreventivo_tree& t = tree();
TRectype* rec = t.dist(_idfase, _curr_dist);
if (rec != NULL)
{
t.kill_node();
sync_tree();
}
}
break;
default: break;
}
break;
default: break;
}
return true;
}
real TPreventivo_emsk::get_costo(const TString& codart, TString& um, TString& iva) const
{
real costo = ZERO;
const int tc = get_int(F_TIPOCOSTO);
const TArticolo_giacenza& art = cached_article_balances(codart);
TEsercizi_contabili esc;
const int annoes = esc.date2esc(get_date(F_DATADOC));
switch (tc)
{
case 1 : costo = art.ultimo_costo(annoes); break;
case 2 : costo = art.media_costi(annoes); break;
case 4 : costo = art.costo_standard(annoes); break;
case 5 : costo = art.costo_medio(annoes, "", ""); break;
case 6 : costo = art.costo_mediopond(annoes, "", ""); break;
default: break;
}
if (costo.is_zero())
costo = art.get_real(ANAMAG_COSTSTD);
um = art.um().row(1).get(UMART_UM);
iva = art.get(ANAMAG_CODIVA);
return costo;
}
bool TPreventivo_emsk::on_dett_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case S_CODART:
if (e == fe_modify && !o.empty() && !_locked)
{
const TString& codart = o.get();
TString4 um, iva;
const real costo = get_costo(codart, um, iva);
TMask& m = o.mask();
if (um.full())
m.set(S_UMART, um, 0x3);
if (iva.full() && m.get(S_CODIVA).blank())
m.set(S_CODIVA, iva, 0x3);
if (!costo.is_zero())
m.set(S_COSTO, costo, 0x3);
}
break;
case F_ARTICOLI:
switch (e)
{
case se_query_add:
return _iddist.full();
case se_notify_add:
{
TPreventivo_tree& t = tree();
TRectype* rec = t.dett(_iddist, _curr_dett = jolly, true);
if (rec != NULL)
sync_tree();
}
break;
case se_enter:
_edit_dett = -1;
_curr_dett = jolly;
break;
case se_query_modify:
_edit_dett = _curr_dett = jolly;
break;
case se_leave:
case se_notify_modify:
if (_edit_dett >= 0)
{
const int r = _edit_dett;
_edit_dett = -1;
TPreventivo_tree& t = tree();
TRectype* rec = t.dett(_iddist, r, true);
if (rec != NULL)
{
const TMask& m = ((TSheet_field&)o).sheet_row_mask(r);
msk2rec(m, *rec);
sync_tree();
update_dist_costo();
}
}
break;
case se_notify_del:
if (_curr_dett >= 0)
{
TPreventivo_tree& t = tree();
TRectype* rec = t.dett(_iddist, _curr_dett);
if (rec != NULL)
{
t.kill_node();
update_dist_costo();
sync_tree();
}
}
break;
default: break;
}
break;
default:
break;
}
return true;
}
bool TPreventivo_emsk::on_misu_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case 102:
case 103:
case 104:
case 105:
if (e == fe_modify && _curr_misu >= 0 && _curr_dist >= 0)
{
TSheet_field& misure = *o.mask().get_sheet();
TEdit_field& tot = o.mask().efield(106);
tot.validate(K_TAB);
misure.row(_curr_misu).add(tot.get(), 5);
update_dist_qta();
}
break;
case F_MISURE:
switch (e)
{
case se_query_add:
return _iddist.full();
case se_notify_add:
tree().misu(_iddist, _edit_misu = jolly, true);
break;
case se_enter:
_edit_misu = -1;
_curr_misu = jolly;
break;
case se_query_modify:
_edit_misu = _curr_misu = jolly;
break;
case se_leave:
case se_notify_modify:
if (_iddist.full() && _edit_misu >= 0)
{
TPreventivo_tree& t = tree();
TRectype* rec = t.misu(_iddist, _edit_misu, true);
if (rec != NULL)
{
TSheet_field& sheet = ((TSheet_field&)o);
const TMask& m = sheet.sheet_row_mask(_edit_misu);
msk2rec(m, *rec);
update_dist_qta();
}
_edit_misu = -1;
}
break;
case se_notify_del:
if (_curr_misu >= 0)
{
TPreventivo_tree& t = tree();
TRectype* rec = t.misu(_iddist, _curr_misu);
if (rec != NULL)
{
t.kill_node();
update_dist_qta();
}
}
break;
default: break;
}
default:
break;
}
return true;
}
void TPreventivo_emsk::update_dist(const real& val, int column)
{
TSheet_field& dist = sfield(F_DISTINTE);
dist.row(_curr_dist).add(val.string(), column);
dist.update_mask(_curr_dist);
TOperable_field& o = dist.sheet_row_mask(_curr_dist).efield(105);
on_dist_event(o, fe_modify, 1);
dist.force_update(_curr_dist);
TRectype* rec = tree().dist(_idfase, _curr_dist);
if (rec)
msk2rec(dist.sheet_row_mask(_curr_dist), *rec);
}
void TPreventivo_emsk::update_dist_costo()
{
if (_curr_dist >= 0)
{
TSheet_field& sheet = sfield(F_ARTICOLI);
real costo, prezzo;
FOR_EACH_SHEET_ROW(sheet, i, row)
{
const real q = row->get(3);
const real c = row->get();
const real p = row->get();
costo += q*c;
prezzo += q*p;
}
if (!costo.is_zero())
update_dist(costo, 4);
if (!prezzo.is_zero())
update_dist(prezzo, 5);
}
}
void TPreventivo_emsk::update_dist_qta()
{
if (_curr_dist >= 0)
{
TSheet_field& sheet = sfield(F_MISURE);
real tot;
FOR_EACH_SHEET_ROW(sheet, i, row)
tot += real(row->get(5));
update_dist(tot, 3);
}
}
bool TPreventivo_emsk::sync_tree()
{
TPreventivo_tree& t = tree();
TTree_field& tf = t.owner();
tf.force_update();
return true;
}
static bool ricarica(TTree& tree, void* jolly, word)
{
const TPreventivo_tree& t = (const TPreventivo_tree&)tree;
if (t.level() == pl_distinta)
{
TRectype* rec = t.curr_row();
const real cos = rec->get(RPRV_COSTO);
const real k = *(real*)jolly;
rec->put(RDOC_PREZZO, cos * k);
}
return false;
}
bool TPreventivo_emsk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case F_STATO:
if ((e == fe_init || e == fe_close) && o.empty())
o.set("1");
if (e == fe_modify && !o.empty())
app().update_tools(*this);
break;
case F_FASI:
return on_fasi_event((TTree_field&)o, e, jolly);
case F_FASENEW:
case F_FASEDIT:
case F_FASEDEL:
case F_FASEUP:
case F_FASEDN:
case F_FASERT:
case F_FASELT:
if (e == fe_button)
return on_fasi_button(o, e, jolly);
break;
case F_DISTINTE:
return on_dist_event(o, e, jolly);
case F_ARTICOLI:
return on_dett_event(o, e, jolly);
case F_MISURE:
return on_misu_event(o, e, jolly);
case DLG_COPY:
if (e == fe_button && edit_mode())
{
TPreventivo_nmsk m(get(F_CODNUM));
if (m.run() == K_ENTER)
{
const TDate datadoc(TODAY);
const int nprev = m.get_int(F_NDOC);
const int nrev = 1;
long ndoc = 0; join_ndoc(nprev, nrev, ndoc);
set(F_NPREV, nprev);
set(F_NREV, nrev);
set(F_NDOC, ndoc);
set(F_STATO, 1);
set(F_DATADOC, datadoc);
set(F_ANNO, m.get_int(F_ANNO));
set_mode(MODE_INS);
stop_run(K_SAVE);
}
return true;
}
break;
case DLG_PRINT:
if (e == fe_button)
main_app().print();
break;
case DLG_PREVIEW:
if (e == fe_button)
main_app().preview();
break;
case DLG_ELABORA:
if (e == fe_button)
{
const TString& cod = pe_trova_elaborazione(*this, 'O');
if (cod.full())
{
TPreventivo_app& relapp = (TPreventivo_app&)main_app();
if (relapp.set_elab_code(cod))
stop_run(K_SAVE);
}
}
break;
case DLG_ARCHIVE:
if (e == fe_button)
{
const TString& cod = pe_trova_elaborazione(*this, 'F');
if (cod.full())
{
TPreventivo_app& relapp = (TPreventivo_app&)main_app();
if (relapp.set_elab_code(cod))
stop_run(K_SAVE);
}
}
break;
case F_RICARICO:
if (e == fe_modify && !o.empty())
{
// Controllo che ci sia almeno una fase prima di ricalcolare tutto
TPreventivo_tree& t = tree();
if (t.goto_root() && t.has_son() && yesno_box(TR("Si desidera applicare il nuovo ricarico a tutte fasi?")))
{
if (t.goto_root())
{
const real perc = ricarico2perc(o.get());
t.scan_depth_first(ricarica, (void*)&perc);
sync_tree();
set_fase("");
}
}
}
break;
default:
if (jolly > 0 && o.dlg() >= 101 && o.dlg() < 300) // Sheet mask events
{
if (e == fe_modify)
{
switch (jolly)
{
case 1: return on_dist_event(o, e, jolly);
case 2: return on_dett_event(o, e, jolly);
case 3: return on_misu_event(o, e, jolly);
default: CHECK(false, "Unknown sheet field event"); break;
}
}
}
break;
}
return TPreventivo_msk::on_field_event(o, e, jolly);
}
void TPreventivo_emsk::set_sheet_color(short id, COLOR col)
{
const COLOR rgb = blend_colors(NORMAL_BACK_COLOR, col, 0.75);
TSheet_field& s = sfield(id);
s.set_back_and_fore_color(rgb, NORMAL_COLOR, -1);
}
TPreventivo_emsk::TPreventivo_emsk() : TPreventivo_msk("pe1400b"), _tree(NULL), _locked(false), _has_db(false)
{
int yca = 21; // Riga del primo campo di analitica
TMask_field* grp = find_by_id(F_CDC0);
if (grp)
{
RCT rct0; grp->get_rect(rct0);
yca = rct0.top / ROWY + 1;
}
short idcdc = 0, idcms = 0, idfase = 0, idconto = 0;
ca_create_fields_ext(*this, 0, 2, yca, F_CDC0+1, idcdc, idcms, idfase, idconto,
DOC_CODCOSTO, DOC_CODCMS, NULL); // Niente fasi qui!
set_sheet_color(F_DISTINTE, COLOR_YELLOW);
set_sheet_color(F_ARTICOLI, COLOR_GREEN);
set_sheet_color(F_MISURE, COLOR_GRAY);
_has_db = dongle().active(DBAUT);
if (_has_db)
{
TISAM_recordset dist("USE DIST");
_has_db = dist.items() >= 4;
}
TMask& dist = sfield(F_DISTINTE).sheet_mask();
TList_field& tipoa = dist.lfield(D_TIPOA);
const TToken_string cod = tipoa.get_codes();
if (!_has_db && cod.items() >= 2)
{
TToken_string* m1 = tipoa.message(1);
tipoa.replace_items("A", TR("Articolo"));
if (m1 != NULL)
{
TToken_string* m0 = tipoa.message(0);
if (m0 != NULL)
*m0 = *m1;
}
tipoa.disable();
}
}
///////////////////////////////////////////////////////////
// TPreventivo_app
///////////////////////////////////////////////////////////
bool TPreventivo_app::user_create()
{
if (ca_config().get_int("Authorizations") < 2)
return error_box("E' necessario configurare la contabilità analitica o industriale");
open_files(LF_TAB, LF_TABCOM, LF_CLIFO,
LF_DOC, LF_RIGHEDOC, LF_COMMESSE, LF_FASI, 0);
_rel = new TRelation(LF_DOC);
_qmsk = new TPreventivo_qmsk;
_emsk = new TPreventivo_emsk;
return true;
}
bool TPreventivo_app::user_destroy()
{
delete _emsk;
delete _qmsk;
delete _rel;
return true;
}
TCursor& TPreventivo_app::get_filtered_cursor() const
{
TEdit_field& f = _qmsk->efield(F_NDOC);
TCursor& cur = *f.browse()->cursor();
if (cur.items() == 0) // A volte deve scantarsi ...
f.check(); // ... forzo ricalcolo elementi
return cur;
}
bool TPreventivo_app::get_next_key(TToken_string& key)
{
TPreventivo_msk& m = (TPreventivo_msk&)curr_mask();
const TEdit_field& codnum = m.efield(F_CODNUM);
if (codnum.empty())
return codnum.error_box(TR("Inserire un codice numerazione"));
const int revlen = m.revision_length();
long ndoc = 0;
int nprev = 0, nrev = 0;
if (m.query_mode() || revlen == 0)
{
TCursor& cur = get_filtered_cursor();
const TRecnotype i = cur.items();
if (i > 0)
{
cur = i-1;
ndoc = cur.curr().get_long(DOC_NDOC);
m.split_ndoc(ndoc, nprev, nrev);
}
nprev++;
nrev = 1;
m.join_ndoc(nprev, nrev, ndoc);
}
else
{
// Trucchi per evitare l'azzeramento della maschera
_revisioning = true;
m.set_mode(MODE_QUERY);
ndoc = m.get_long(F_NDOC);
m.split_ndoc(ndoc, nprev, nrev);
nrev++;
m.join_ndoc(nprev, nrev, ndoc);
m.set(F_NDOC, ndoc, 0x3);
}
key.format("%d|%ld", F_NDOC, ndoc);
return true;
}
int TPreventivo_app::read(TMask& m)
{
int err = TRelation_application::read(m);
if (err == NOERR)
{
const TRectype& doc = get_relation()->curr();
TToken_string keytok;
keytok.add(doc.get(DOC_CODNUM));
keytok.add(doc.get(DOC_ANNO));
keytok.add(doc.get(DOC_PROVV));
keytok.add(doc.get(DOC_NDOC));
const TRecord_array rdoc(keytok, LF_RIGHEDOC);
TPreventivo_tree& t = ((TPreventivo_emsk&)m).tree();
t.append_row(doc);
const int last_row = rdoc.last_row();
for (int r = rdoc.first_row(); r > 0 && r <= last_row; r = rdoc.succ_row(r))
t.append_row(rdoc[r]);
t.shrink_all();
t.goto_root();
t.expand();
t.owner().force_update();
m.set(F_FASEMAX, pe_numero_fasi(rdoc));
}
_codelab.cut(0); // Azzera in ogni caso l'elaborazione
return err;
}
static bool tree_save_row(TTree& tree, void* jolly, word /*flags*/)
{
TPreventivo_tree& t = (TPreventivo_tree&)tree;
const TRectype* rec = t.curr_row();
if (rec && !rec->empty() && rec->num() == LF_RIGHEDOC)
{
const real costo = rec->get(RPRV_COSTO);
const real price = rec->get(RDOC_PREZZO);
const TString& descr = rec->get(RDOC_DESCR);
if (descr.full() || !costo.is_zero() || !price.is_zero())
{
TDocumento& doc = *(TDocumento*)jolly;
const TString4 tiporiga = rec->get(RDOC_TIPORIGA);
TRectype& row = doc.new_row(tiporiga);
const TString80 codart = rec->get(RDOC_CODART);
TString80 codartmag;
if (codart.full())
codartmag = cache().get(LF_ANAMAG, codart, ANAMAG_CODART);
for (int f = rec->items()-1; f > 5; f--)
{
const char* fld = rec->fieldname(f);
if (rec->type(fld) == _memofld)
break;
const TString& src = rec->get(fld);
if (src.full())
{
const TString& dst = row.get(fld);
if (dst.blank())
row.put(fld, src);
}
}
row.put(RDOC_IDRIGA, row.get(RDOC_NRIGA));
row.put(RDOC_TIPORIGA, rec->get(RDOC_TIPORIGA));
row.put(RDOC_QTA, rec->get(RDOC_QTA));
row.put(RDOC_DESCR, rec->get(RDOC_DESCR));
row.put(RDOC_DESCLUNGA, rec->get(RDOC_DESCLUNGA));
row.put(RDOC_DESCEST, rec->get(RDOC_DESCEST));
row.put(RDOC_CODART, codart);
row.put(RDOC_CODARTMAG, codartmag);
row.put(RDOC_CHECKED, codartmag.full());
row.put(RDOC_UMQTA, rec->get(RDOC_UMQTA));
row.put(RDOC_QTAGG1, rec->get(RDOC_QTAGG1));
row.put(RDOC_QTAGG2, rec->get(RDOC_QTAGG2));
row.put(RDOC_QTAGG3, rec->get(RDOC_QTAGG3));
row.put(RDOC_QTAGG4, rec->get(RDOC_QTAGG4));
row.put(RDOC_QTAGG5, rec->get(RDOC_QTAGG5));
row.put(RDOC_PREZZO, rec->get(RDOC_PREZZO));
// Make sure of coherent level on final record
const TPreventivo_level pl = t.level(*rec);
if (pl > pl_fase1 && pl < pl_distinta)
row.put(RPRV_LEVEL, int(t.curr_depth() - 1)); // Don't assume RPRV_LEVEL = pl-pl_fase1
else
row.zero(RPRV_LEVEL);
}
}
return false; // Don't stop scan
}
int TPreventivo_app::save_rows(const TMask& m)
{
TPreventivo_tree& tree = ((TPreventivo_emsk&)m).tree();
TDocumento doc(get_relation()->curr());
doc.destroy_rows();
if (tree.goto_root() && tree.goto_firstson())
tree.scan_depth_first(tree_save_row, &doc);
// Estrae campi analitica da maschera principale e li riporta sulle righe
TString cms, cos;
FOR_EACH_MASK_FIELD(m, i, f) if (f->active() && f->is_edit() && f->dlg() >= F_CDC0)
{
const TFieldref* fref = f->field();
if (fref != NULL)
{
if (fref->name() == DOC_CODCMS)
cms << f->get();
if (fref->name() == DOC_CODCOSTO)
cos << f->get();
}
}
TRecord_array& rdoc = doc.body();
rdoc.renum_key(RDOC_CODCMS, cms);
rdoc.renum_key(RDOC_CODCOSTO, cos);
const int err = doc.rewrite(get_relation()->file());
if (err == NOERR && _codelab.full())
pe_genera_documento(doc, _codelab, 'O');
_codelab.cut(0); // Azzera in ogni caso l'elaborazione
return err;
}
int TPreventivo_app::write(const TMask& m)
{
int err = TRelation_application::write(m);
if (err == NOERR)
err = save_rows(m);
return err;
}
int TPreventivo_app::rewrite(const TMask& m)
{
int err = TRelation_application::rewrite(m);
if (err == NOERR)
err = save_rows(m);
return err;
}
bool TPreventivo_app::remove()
{
bool done = TRelation_application::remove();
if (done)
{
const TRectype& rec = get_relation()->curr();
TToken_string keytok;
keytok.add(rec.get(DOC_CODNUM));
keytok.add(rec.get(DOC_ANNO));
keytok.add(rec.get(DOC_PROVV));
keytok.add(rec.get(DOC_NDOC));
TRecord_array rdoc(keytok, LF_RIGHEDOC);
rdoc.remove();
}
return done;
}
void TPreventivo_app::update_tools(TMask& m)
{
const bool is_edit = m.edit_mode();
const bool can_ord = is_edit && pe_trova_elaborazione(m, 'O').full();
const bool can_fab = is_edit && pe_trova_elaborazione(m, 'F').full();
bool can_print = is_edit;
if (can_print)
{
const TTipo_documento& tip = cached_tipodoc(m.get(DOC_TIPODOC));
TFilename rep;
can_print = tip.main_print_profile(rep, 0x2);
}
m.enable(DLG_COPY, is_edit);
m.enable(DLG_NEWREC, is_edit);
m.enable(DLG_ELABORA, can_ord);
m.enable(DLG_ARCHIVE, can_fab);
m.enable(DLG_PRINT, can_print);
m.enable(DLG_PREVIEW, can_print);
m.disable(F_STATO); // Enable with F12
}
void TPreventivo_app::init_insert_mode(TMask& m)
{
_revisioning = false;
TRelation_application::init_insert_mode(m);
m.set(F_DATADOC, TDate(TODAY));
update_tools(m);
const TMultilevel_code_info& fi = ca_multilevel_code_info(LF_FASI);
const int fasemax = fi.levels() - fi.parent_levels();
m.set(F_FASEMAX, fasemax);
}
void TPreventivo_app::init_modify_mode(TMask& m)
{
_revisioning = false;
TRelation_application::init_modify_mode(m);
update_tools(m);
}
bool TPreventivo_app::save_and_print(TPrtype mode)
{
static bool already_printing = false;
if (already_printing)
return false;
already_printing = true;
if (rewrite(*_emsk) != NOERR)
return already_printing = false;
TString commandline;
commandline << "ve1 -2" << ' ' << _emsk->get(F_CODNUM) << ' '
<< _emsk->get(F_ANNO) << " D " << _emsk->get(F_NDOC);
switch (mode)
{
case exportprinter: commandline << " E P"; break;
case fileprinter : commandline << " P P"; break;
case screenvis : commandline << " A P"; break;
default : commandline << " S D"; break;
}
TExternal_app interattivo( commandline );
if (interattivo.run() == NOERR)
{
TLocalisamfile& f = _rel->file();
f.zero();
f.put(DOC_PROVV, 'D');
f.put(DOC_ANNO, _emsk->get(F_ANNO));
f.put(DOC_CODNUM, _emsk->get(F_CODNUM));
f.put(DOC_NDOC, _emsk->get(F_NDOC));
f.read();
curr_mask().set(F_STATO, f.get(DOC_STATO));
}
already_printing = false;
return true;
}
void TPreventivo_app::print()
{
save_and_print(winprinter);
}
void TPreventivo_app::preview()
{
save_and_print(screenvis);
}
const char* TPreventivo_app::record_description(const TRelation& rel) const
{
const TString4 tipodoc = rel.curr().get(DOC_TIPODOC);
const TString& desc = cache().get("%TIP", tipodoc, "S0");
return desc.empty() ? title() : desc;
}
int pe1400(int argc, char* argv[])
{
TPreventivo_app a;
a.run(argc, argv, TR("Preventivi"));
return 0;
}