Files correlati : lv0, lv0400a.msk Ricompilazione Demo : [ ] Commento : Contratti - Testata Tipo canone È un listbox con valori: 0|Nessuno 1|Importo fisso 2|% su valore convenzionale per cliente Se viene selezionata lopzione Importo fisso, devo attivare un listbox con valori: 0|Nessuno 1|Elenco articoli con quantità 2| Elenco articoli senza quantità Se viene selezionata lopzione % su valore convenzionale per cliente, allora fisso su tutte le righe del contratto questo valore La voce % su valore convenzionale per articolo va eliminata dalle testate La voce Raggruppato su unico articolo diventa un checkbox, cliccabile solo se Tipo canone vale Nessuno Tipo forfait Il campo Tipo forfait e i campi a lui associati vanno eliminati delle testate dei contratti Note: in fatturazione vanno gestiti Elenco articoli senza quantità il raggruppamento su unico articolo come checkbox; va gestito inoltre Importo minimo fatturabile [imponibile] Flag vari - Il flag stampa riepilogo consegne è sempre attivo - I flags riferimenti bolle e stampa come da elenco consegne sono esclusivi Varie Eliminare la causale di default dalle testate Aggiungere la voce Misto tra le voci del Tipo imballo Eliminare i campi Num. Utente e Num. Etichette Se Ritiro automatico dotazione temporanea non è flaggato in testata e cerco di flaggarlo su una riga, emettere un warning Contratti - Righe Prezzo Il campo prezzo è sempre abilitato ma non obbligatorio Proposta prezzo: Quando carico un articolo su un contratto controllo il listino del cliente (CFVEN), poi cerco larticolo su RCONDV in base al codice listino Se qui trovo il prezzo lo prendo e lo propongo sul contratto; altrimenti scrivo sul contratto quello salvato in anagrafica articoli, segnalando con un warning; se larticolo non appartiene a nessun listino, allora prendo il prezzo dallanagrafica articoli senza segnalare niente. Valore convenzionale Il campo valore convenzionale è sempre imputabile e varrà salvato nel costo standard in anagrafica (campo che cambierà nome per le lavanderie) Pezzi per confezione Il campo Pezzi per confezione diventa Pezzi per pacco Tipo forfait Il campo Tipo forfait rimane solo sulle righe e: - Nessuno: nessun comportamento particolare - Valore fisso: Importo fisso obbligatorio - Nolo: Prezzo nolo obbligatorio - Ciclaggio: nessun comportamento particolare - % su valore convenzionale per articolo: nessun comportamento particolare - Fisso su dotazione iniziale: importo fisso obbligatorio Modifica dotazioni In realtà sono sempre modificabili, ma quando li modifico manualmente devo emettere un warning Non lamentarti se poi i conti non tornano git-svn-id: svn://10.65.10.50/trunk@19010 c028cbd2-c16b-5b4b-a496-9718f37d4682
958 lines
30 KiB
C++
Executable File
958 lines
30 KiB
C++
Executable File
#include <automask.h>
|
|
#include <defmask.h>
|
|
#include <execp.h>
|
|
#include <progind.h>
|
|
|
|
#include "lvlib.h"
|
|
#include "../cg/cglib01.h"
|
|
#include "../mg/clifogiac.h"
|
|
#include "../ve/rcondv.h"
|
|
|
|
#include "lv0400.h"
|
|
|
|
//LV_NEW_CONTRACT: metodo generale utilizzato sia nella maschera che nell'applicazione
|
|
//che restituisce il primo codcont libero
|
|
long lv_new_contract(long cliente, int indsped)
|
|
{
|
|
//leggo dalla configurazione se la numerazione dei contratti
|
|
//è sequenziale per ditta o per cliente
|
|
TConfig ini(CONFIG_DITTA, "lv");
|
|
const bool unicont=ini.get_bool("UniCont");
|
|
|
|
long codcont=0;
|
|
|
|
if (unicont) //se la numerazione è per ditta, cerco in tutto LVCONDV il codcont più grande
|
|
{
|
|
TISAM_recordset recset ("USE LVCONDV");
|
|
for (bool ok=recset.move_first(); ok; ok = recset.move_next())
|
|
{
|
|
const long codice=recset.get("CODCONT").as_int();
|
|
if (codice>codcont)
|
|
codcont=codice;
|
|
}
|
|
}
|
|
else //altrimenti cerco il codcont più grande di un determinato cliente
|
|
{
|
|
TString query;
|
|
query<<"USE LVCONDV\n"
|
|
<<"FROM CODCF=#CLIENTE\n"
|
|
<<"TO CODCF=#CLIENTE\n";
|
|
TISAM_recordset recset (query);
|
|
recset.set_var("#CLIENTE",cliente);
|
|
if (recset.move_last())
|
|
codcont=recset.get("CODCONT").as_int();
|
|
}
|
|
codcont++;
|
|
return codcont;
|
|
}
|
|
|
|
//////////////////////////////
|
|
//// TCONTRATTI_MSK ////
|
|
//////////////////////////////
|
|
|
|
//classe TContratti_msk
|
|
class TContratti_msk: public TAutomask
|
|
{
|
|
long _post_contr;
|
|
TString80 _artrig;
|
|
|
|
protected:
|
|
bool on_art_select();
|
|
virtual void on_idle();
|
|
virtual bool on_field_event(TOperable_field& o,TField_event e,long jolly);
|
|
|
|
public:
|
|
TContratti_msk();
|
|
};
|
|
|
|
//ON_ART_SELECT: metodo che riempie i campi delle dotazioni e del consegnato sullo sheet e sulla maschera
|
|
//e riporta i dati dello sheet nel dettaglio sulla maschera (sotto lo sheet)
|
|
bool TContratti_msk::on_art_select()
|
|
{
|
|
//dallo sheet identifico la riga selezionata e estraggo i dati di interesse
|
|
TSheet_field& ss = sfield(F_RIGHE);
|
|
TToken_string& row = ss.row(ss.selected());
|
|
const TString80 codart(row.get(ss.cid2index(S_CODART)));
|
|
const long codcf = get_long(F_CODCF);
|
|
const int indsped = get_int(F_INDSPED);
|
|
|
|
//instanzio un TArticolo_lavanderie per poter recuperare i dati di interesse
|
|
TArticolo_lavanderie& artrec = cached_article_laundry(codart, 'C', codcf, indsped);
|
|
|
|
//setto datasc a oggi e fisso l'anno esercizio
|
|
TDate datasc(TODAY);
|
|
const int annoes = esercizi().date2esc(datasc);
|
|
|
|
//estraggo il record corrispondente su LF_CLIFOGIAC
|
|
const TRecmag_lavanderie& reclav = artrec.find_rec(annoes);
|
|
//recupero la maschera di riga
|
|
TMask& rowmask = ss.sheet_mask();
|
|
|
|
if (ini_get_string(CONFIG_DITTA, "lv", "Qtamodi") != "X")
|
|
{
|
|
field(F_DOTTMP).disable();
|
|
rowmask.field(S_DOTIN).disable();
|
|
rowmask.field(S_DOTOD).disable();
|
|
rowmask.field(S_DOTTMP).disable();
|
|
}
|
|
|
|
if (rowmask.get(S_UM).blank() && artrec.um().rows() > 0)
|
|
{
|
|
const TString& um = artrec.um()[1].get(UMART_UM);
|
|
rowmask.set(S_UM, um);
|
|
}
|
|
|
|
//se esiste il record su LF_CLIFOGIAC, recupero l'unità di misura dalla riga dello sheet selezionata
|
|
//e setto i campi delle dotazioni e dei consegnati ai valori corretti riportati alla giusta unità di misura
|
|
if (!reclav.empty())
|
|
{
|
|
if (rowmask.get(S_DOTIN).blank())
|
|
{
|
|
//calcolo dotazione iniziale, scritta sia sulla maschera che sullo sheet
|
|
const real dotin = reclav.get_real(CLIFOGIAC_DOTIN);
|
|
rowmask.set(S_DOTIN, dotin);
|
|
//calcolo dotazione odierna, scritta sia sulla maschera che sullo sheet
|
|
const real dotod = reclav.get_real(CLIFOGIAC_DOTOD);
|
|
rowmask.set(S_DOTOD, dotod);
|
|
//calcolo dotazione temporanea, scritta sia sulla maschera che sullo sheet
|
|
const real dottmp = reclav.get_real(CLIFOGIAC_DOTTM);
|
|
rowmask.set(S_DOTTMP, dottmp);
|
|
}
|
|
//calcolo consegnato anno, scritto sia sulla maschera che sullo sheet
|
|
const real consyear = reclav.get_real("CONSANNO");
|
|
rowmask.set(S_CONSANNO, consyear);
|
|
//calcolo consegnato mese, scritto sia sulla maschera che sullo sheet
|
|
const real consmonth = reclav.get_real("CONSMESE");
|
|
rowmask.set(S_CONSMESE, consmonth);
|
|
}
|
|
|
|
//instanzio una cache sull'anagrafica di magazzino
|
|
//per leggere il valore di PPCONF corretto e sempre aggiornato
|
|
const TRectype& anamag = cache().get(LF_ANAMAG, codart);
|
|
rowmask.set(S_PPCONF, anamag.get_int(ANAMAG_PPCONF));
|
|
row.add(anamag.get(ANAMAG_PPCONF), ss.cid2index(S_PPCONF));
|
|
|
|
//ciclo i dati di interesse della riga selezionata nel dettaglio
|
|
//sulla maschera principale
|
|
for (short id = F_CODART; id <= F_CODART + 36; id++)
|
|
{
|
|
const int pos = id2pos(id);
|
|
if (pos > 0)
|
|
{
|
|
TMask_field& f = fld(pos);
|
|
const TString& oldval = f.get();
|
|
const char* newval = row.get(ss.cid2index(id - 400));
|
|
if (oldval != newval)
|
|
{
|
|
f.set(newval);
|
|
if (f.is_kind_of(CLASS_LIST_FIELD))
|
|
f.on_hit();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (field(F_PPCONF).empty())
|
|
{
|
|
set(F_CALCCONS, "0");
|
|
set(F_ARROT, "");
|
|
disable(F_CALCCONS);
|
|
disable(F_ARROT);
|
|
rowmask.field(S_CALCCONS).disable();
|
|
rowmask.field(S_ARROT).disable();
|
|
}
|
|
else
|
|
{
|
|
enable(F_CALCCONS);
|
|
enable(F_ARROT);
|
|
rowmask.field(S_CALCCONS).enable();
|
|
rowmask.field(S_ARROT).enable();
|
|
set(F_ARROT, "X");
|
|
|
|
TToken_string row = ss.row(ss.selected());
|
|
row.add("X", ss.cid2index(S_ARROT));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//ON_IDLE: ridefinizione del metodo on_idle() delle TAutomask per settare il focus
|
|
//nel posto desiderato
|
|
void TContratti_msk::on_idle()
|
|
{
|
|
if (_post_contr > 0)
|
|
{
|
|
set(F_CODCONT, _post_contr);
|
|
_post_contr = 0;
|
|
efield(F_CODCONT).set_focus();
|
|
}
|
|
TAutomask::on_idle();
|
|
}
|
|
|
|
//ON_FIELD_EVENT: definizione del metodo che setta i comportamenti dei vari campi della mashera
|
|
bool TContratti_msk::on_field_event(TOperable_field& o,TField_event e,long jolly)
|
|
{
|
|
switch(o.dlg())
|
|
{
|
|
case F_CODCF:
|
|
case F_RICALT:
|
|
//se sono in query_mode e se il campo risulta pieno e modificato,
|
|
//e il codcont vuoto, allora riempio in automatico l'indirizzo di spedizione
|
|
//e propongo il contratto valido nella giornata di oggi
|
|
if (query_mode())
|
|
{
|
|
if (e == fe_modify && !o.empty() && efield(F_CODCONT).empty())
|
|
{
|
|
const long codcf = atol(o.get());
|
|
const int indsped = get_int(F_INDSPED);
|
|
const TDate oggi(TODAY);
|
|
_post_contr = lv_find_contract(codcf, indsped, oggi);
|
|
}
|
|
}
|
|
break;
|
|
case F_RIGHE:
|
|
//se lo sheet ha ricevuto un se_enter, allora aggiorno i campi del dettaglio sulla mashera principale
|
|
if (e == se_enter)
|
|
{
|
|
TSheet_field& ss = (TSheet_field&)o;
|
|
TToken_string& row = ss.row(ss.selected());
|
|
|
|
for (short id = F_CODART; id <= F_CODART+35; id++)
|
|
{
|
|
const int pos=id2pos(id);
|
|
if (pos>0)
|
|
{
|
|
TMask_field& f = fld(pos);
|
|
const TString& oldval = f.get();
|
|
const char* newval = row.get(ss.cid2index(id - 400));
|
|
if (oldval != newval)
|
|
{
|
|
f.set(newval);
|
|
if (f.is_kind_of(CLASS_LIST_FIELD))
|
|
f.on_hit();
|
|
}
|
|
f.set_dirty(false);
|
|
}
|
|
}
|
|
|
|
//questo pezzo serve per gestire enable e disable dei campi in modo corretto
|
|
//senza massage in maschera, sia sullo sheet che sul dettaglio
|
|
if (field(F_PPCONF).empty())
|
|
{
|
|
set(F_CALCCONS, "0");
|
|
set(F_ARROT, "");
|
|
disable(F_CALCCONS);
|
|
disable(F_ARROT);
|
|
}
|
|
else
|
|
{
|
|
enable(F_CALCCONS);
|
|
enable(F_ARROT);
|
|
set(F_ARROT, "X");
|
|
row.add("X", ss.cid2index(S_ARROT));
|
|
ss.force_update();
|
|
}
|
|
_artrig=row.get(0); //salvo nella variabile globale il codart della riga selezionata
|
|
}
|
|
//se ho cancellato una riga dello sheet, chiedo conferma che sia effettivamente quello che si vuole fare
|
|
if (e == se_query_del)
|
|
{
|
|
TSheet_field& ss = (TSheet_field&)o;
|
|
TToken_string& row = ss.row(ss.selected());
|
|
const TString codart = row.get(ss.cid2index(S_CODART));
|
|
const long dotin = row.get_long(ss.cid2index(S_DOTIN));
|
|
if (dotin > 0)
|
|
{
|
|
warning_box("Impossibile cancellare l'articolo %s perchè ha una dotazione iniziale non nulla", (const char*) codart);
|
|
return false;
|
|
}
|
|
if (!yesno_box("Si desidera veramente cancellare l'articolo %s",(const char*) codart))
|
|
return false;
|
|
}
|
|
break;
|
|
case F_TIPOCAN:
|
|
{
|
|
//copio il valore del campo in questione della testata su tutte le righe se F_TIPOCAN vale
|
|
//% su valore convenzionale per cliente, altrimente lascio quello che c'è
|
|
const int tipocan = atoi(get(F_TIPOCAN));
|
|
if (e == fe_modify || e == fe_init)
|
|
{
|
|
TSheet_field& ss = sfield(F_RIGHE);
|
|
|
|
//recupero le posizioni dei campi che devo modificare
|
|
const int pos_tipoforf = ss.cid2index(S_TIPOFORF);
|
|
const int pos_vcartcli = ss.cid2index(S_VCARTCLI);
|
|
|
|
if (tipocan == 2)
|
|
{
|
|
FOR_EACH_SHEET_ROW(ss, r, row)
|
|
{
|
|
TToken_string& riga = ss.row(r);
|
|
//scrivo i valori alle posizioni corrette
|
|
riga.add(4, pos_tipoforf);
|
|
riga.add('C', pos_vcartcli);
|
|
//disabilito le celle interessate
|
|
ss.disable_cell(r, pos_tipoforf);
|
|
ss.disable_cell(r, pos_vcartcli);
|
|
}
|
|
field(F_TIPOFORF).disable();
|
|
field(F_VCARTCLI).disable();
|
|
}
|
|
else
|
|
{
|
|
FOR_EACH_SHEET_ROW(ss, r, row)
|
|
{
|
|
TToken_string& riga = ss.row(r);
|
|
//scrivo i valori alle posizioni corrette
|
|
riga.add(0, pos_tipoforf);
|
|
ss.enable_cell(r, pos_tipoforf);
|
|
ss.enable_cell(r, pos_vcartcli);
|
|
}
|
|
field(F_TIPOFORF).enable();
|
|
field(F_VCARTCLI).enable();
|
|
}
|
|
ss.force_update();
|
|
if (ss.items() >= 0)
|
|
ss.select(0);
|
|
}
|
|
}
|
|
break;
|
|
case F_TIPOFORF:
|
|
{
|
|
//se questo campo risulta modificato, lo copio in alto e forzo l'update
|
|
if (e == fe_modify || e == fe_init)
|
|
{
|
|
TSheet_field& ss = sfield(F_RIGHE);
|
|
TToken_string& riga = ss.row(ss.selected());
|
|
riga.add(o.get(), ss.cid2index(S_TIPOFORF));
|
|
if (ss.mask().get_int(F_TIPOCAN) != 2)
|
|
{
|
|
riga.add('A', ss.cid2index(S_VCARTCLI));
|
|
ss.disable_cell(ss.selected(), ss.cid2index(S_VCARTCLI));
|
|
}
|
|
ss.force_update();
|
|
}
|
|
}
|
|
break;
|
|
case F_RITAUDTTMPRIG:
|
|
{
|
|
//obbligo a settare il flag prima in testata, altrimenti non lo lascio settare per le righe
|
|
if (e == fe_modify || e == fe_init)
|
|
{
|
|
if (o.get()[0] == 'X')
|
|
{
|
|
if (field(F_RITAUDTTMP).get()[0] != 'X')
|
|
{
|
|
warning_box("E' necessario prima attivare il ritiro automatico della dotazione temporanea in testata");
|
|
o.set("");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case S_CODART:
|
|
if (!o.empty()) //se il campo risulta pieno
|
|
{
|
|
if (e == fe_modify) //e se risulta modificato
|
|
{
|
|
const TString& codart = o.get();
|
|
TSheet_field& ss = sfield(F_RIGHE);
|
|
TMask& m = o.mask(); // maschera di riga!
|
|
|
|
//PROPONI PREZZO
|
|
TToken_string key;
|
|
key.add('C');
|
|
key.add(field(F_CODCF).get());
|
|
const TRectype& cfven = cache().get(LF_CFVEN, key);
|
|
|
|
bool trvlst = false;
|
|
|
|
if (!cfven.empty())
|
|
{
|
|
//se è settata la categoria merceologica, leggo sia il listino che la cat merc, altrimenti solo il listino
|
|
TString8 codlis = cfven.get(CFV_CODLIST);
|
|
TString8 catven;
|
|
TConfig* configve = new TConfig(CONFIG_DITTA,"ve");
|
|
const char gesliscv = configve->get_char("GESLISCV");
|
|
if (gesliscv != 'X')
|
|
catven = "";
|
|
else
|
|
catven = cfven.get(CFV_CATVEN);
|
|
|
|
//cerco il prezzo sul listino
|
|
key.cut(0);
|
|
key.add('L'); //tipo
|
|
key.add(catven); //catven
|
|
key.add(""); //tipocf
|
|
key.add(""); //codcf
|
|
key.add(codlis); //codlis
|
|
key.add('A'); //tiporiga
|
|
key.add(codart); //codriga
|
|
key.add(""); //um
|
|
key.add(""); //nscagl
|
|
const TRectype& rcondv = cache().get(LF_RCONDV, key);
|
|
|
|
if (!rcondv.empty())
|
|
{
|
|
m.set(S_PREZZOST, rcondv.get_real(RCONDV_PREZZO));
|
|
trvlst = true;
|
|
}
|
|
else
|
|
warning_box("Non esiste questo articolo sul listino; "
|
|
"come prezzo verrà proposto il valore convenzionale dell'articolo");
|
|
}
|
|
else
|
|
trvlst = false; //probabilmente istruzione inutile
|
|
|
|
//se non ho trovato un listino, o se non c'è un listino impostato
|
|
//propongo come prezzo il valore convenzionale
|
|
if (!trvlst)
|
|
{
|
|
const TRectype& anamag = cache().get(LF_ANAMAG, codart);
|
|
m.set(S_PREZZOST, anamag.get_real(ANAMAG_COSTSTD));
|
|
}
|
|
|
|
//se ho scritto un articolo diverso da quello che esisteva prima
|
|
//e se si desidera veramente modificarlo, allora permetto la modifica
|
|
//e forzo l'updatre della riga, altrimenti riscrivo l'articolo che c'era prima
|
|
//e lascio tutto invariato
|
|
if (_artrig.full() && codart != _artrig)
|
|
{
|
|
if (!yesno_box("Si desidera veramente modificare l'articolo %s",(const char*) _artrig))
|
|
{
|
|
m.set(S_CODART,_artrig);
|
|
TToken_string& row = ss.row(ss.selected());
|
|
row.add(_artrig, 0);
|
|
ss.force_update(ss.selected());
|
|
}
|
|
else
|
|
_artrig = codart;
|
|
}
|
|
|
|
//se all'articolo è associata un'unità di misura, la propongo
|
|
//in automatico e richiamo il metodo ON_ART_SELECT(); altrimenti lo richiamo
|
|
//solo se è arrivato un fe_init al campo
|
|
on_art_select();
|
|
}
|
|
else
|
|
if (e == fe_init)
|
|
on_art_select();
|
|
}
|
|
break;
|
|
case S_CONG:
|
|
case S_DOTIN:
|
|
case S_DOTOD:
|
|
case S_DOTTMP:
|
|
{
|
|
if (e == fe_modify)
|
|
{
|
|
TString str;
|
|
str << "ATTENZIONE: Una quantità risulta modificata a mano; dopo questa operazione i totali dei movimenti"
|
|
<< "di magazzino potrebbero non corrispondere ai numeri qui salvati";
|
|
warning_box(str);
|
|
}
|
|
}
|
|
break;
|
|
case DLG_PLANNING:
|
|
//se viene premuto il bottone "Giri", lancia lv0500 (generatore automatico dei giri)
|
|
if (e == fe_button && edit_mode())
|
|
{
|
|
TRelation_application& app = (TRelation_application&) main_app();
|
|
app.get_relation()->read(_isequal,_unlock);
|
|
TString str;
|
|
str << "lv0 -4 " << get(F_CODCF) << " " << get(F_CODCONT);
|
|
TExternal_app planning(str);
|
|
planning.run();
|
|
app.get_relation()->read(_isequal,_lock);
|
|
}
|
|
break;
|
|
case DLG_NEWREC:
|
|
if (e == fe_button)
|
|
{
|
|
//se sono in edit_mode, forzo l'uscita dal contratto attuale
|
|
if (edit_mode())
|
|
{
|
|
send_key(K_ESC, 0);
|
|
return false;
|
|
}
|
|
|
|
//se sono in query_mode e esiste già un cliente selzionato, allora richiamo il metodo LV_NEW_CONTRACT()
|
|
//e calcolo il primo codcont libero proponendolo in automatico
|
|
if (query_mode())
|
|
{
|
|
const long codcf = get_long(F_CODCF);
|
|
if (codcf > 0)
|
|
{
|
|
const int indsped = get_int(F_INDSPED);
|
|
const long codcont = lv_new_contract(codcf, indsped);
|
|
if (codcont > 0)
|
|
set(F_CODCONT, codcont);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
//se sto modificando un campo con indice > 500 e diverso da F_CAUSLAVDESCRIG
|
|
//allora forzo l'update dello sheet sulla riga selezionata
|
|
if (e == fe_modify && is_running() && o.dlg() > 500/*&& o.dlg() != F_CAUSLAVDESCRIG*/)
|
|
{
|
|
TSheet_field& ss = sfield(F_RIGHE);
|
|
const int sel = ss.selected();
|
|
if (sel >= 0)
|
|
{
|
|
const short rowid = o.dlg() - 400;
|
|
const int index = ss.cid2index(rowid);
|
|
|
|
const char* oldval = ss.row(sel).get(index);
|
|
const TString& newval = o.get();
|
|
if (newval != oldval)
|
|
{
|
|
ss.sheet_mask().set(rowid,newval);
|
|
ss.row(sel).add(newval,index);
|
|
ss.force_update(sel);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//Costruttore; nasconde o mostra il campo F_INDSPED a seconda di cosa è scritto in configurazione
|
|
TContratti_msk::TContratti_msk():TAutomask("lv0400a"), _post_contr(0)
|
|
{
|
|
TConfig* configlv = new TConfig(CONFIG_DITTA,"lv");
|
|
char indir = configlv->get_char("Useindsp");
|
|
if (indir != 'X')
|
|
field(F_INDSPED).hide();
|
|
}
|
|
|
|
//////////////////////////////
|
|
//// TCONTRATTI_APP ////
|
|
//////////////////////////////
|
|
|
|
//classe TContratti_app
|
|
class TContratti_app: public TRelation_application
|
|
{
|
|
TContratti_msk* _msk;
|
|
TRelation* _rel;
|
|
|
|
private:
|
|
void save_rows(const TMask& m);
|
|
TString build_query(const TMask& m) const;
|
|
int find_art(TSheet_field& s,const TString& art) const;
|
|
|
|
protected:
|
|
virtual TMask* get_mask (int mode) {return _msk; }
|
|
virtual TRelation* get_relation() const {return _rel;}
|
|
|
|
virtual bool user_create();
|
|
virtual bool user_destroy();
|
|
virtual void on_config_change(); //METODO VUOTO
|
|
virtual bool get_next_key(TToken_string& key); //METODO MAI UTILIZZATO?
|
|
virtual int read(TMask& m);
|
|
virtual int write(const TMask& m);
|
|
virtual int rewrite(const TMask& m);
|
|
virtual bool protected_record(TRectype & rec); //METODO MAI UTILIZZATO?
|
|
virtual bool remove();
|
|
virtual void init_query_mode(TMask& m);
|
|
virtual void init_insert_mode(TMask& m);
|
|
virtual void init_modify_mode(TMask& m);
|
|
bool elimina_planning(const long& codcont, const long& codcf) const;
|
|
bool kill_planning (TISAM_recordset& selrighe) const;
|
|
};
|
|
|
|
//SAVE_ROWS: questo metodo salva effettivamente le righe vislualizzate sullo sheet sul file
|
|
//LF_LVRCONDV e aggiorna e/o aggiunge record su LF_CLIFOGIAC
|
|
void TContratti_app::save_rows(const TMask& m)
|
|
{
|
|
//instanzio un TISAM_recordset sulle righe contratto
|
|
TISAM_recordset righeset(build_query(m));
|
|
//instazio un TLocalisamfile partendo dal recordset che ho appena creato
|
|
//(cioè su LF_LVRCONDV)
|
|
TLocalisamfile& file = righeset.cursor()->file();
|
|
|
|
//recupero lo sheet
|
|
TSheet_field& righe = m.sfield(F_RIGHE);
|
|
|
|
//scorro tutte le righe contratto e elimino tutte quelle che non ci sono più sullo sheet
|
|
for (bool ok = righeset.move_first(); ok; ok = righeset.move_next())
|
|
{
|
|
const TString& art = righeset.get("CODART").as_string();
|
|
if (find_art(righe, art) < 0)
|
|
file.remove();
|
|
}
|
|
|
|
//instanzio un TLocalisamfile su LF_CLIFOGIAC
|
|
TLocalisamfile magcli(LF_CLIFOGIAC);
|
|
|
|
//setto alcune variabili di interesse
|
|
const TDate oggi(TODAY);
|
|
const int year = oggi.year();
|
|
const long clifo = m.get_long(F_CODCF);
|
|
const int indsp = m.get_int(F_INDSPED);
|
|
|
|
//recupero la maschera di riga
|
|
TMask& msk = righe.sheet_mask();
|
|
|
|
//per ogni riga dello sheet
|
|
FOR_EACH_SHEET_ROW(righe, r, row)
|
|
{
|
|
file.zero();
|
|
file.put("CODCF",clifo);
|
|
file.put("CODCONT",m.get(F_CODCONT));
|
|
|
|
//per ogni campo della maschera scrivi setta all'interno del record corrente di file
|
|
//il valore di quei campi che hanno un field
|
|
FOR_EACH_MASK_FIELD(msk,i,f)
|
|
{
|
|
const TFieldref* fr = f->field();
|
|
if (fr != NULL)
|
|
{
|
|
const int pos = righe.cid2index(f->dlg());
|
|
fr->write(row->get(pos), file.curr());
|
|
}
|
|
}
|
|
|
|
//leggo il codart
|
|
const TString80 codart = row->get(righe.cid2index(S_CODART));
|
|
if (codart.full())
|
|
{
|
|
file.rewrite_write();
|
|
//se il codart è pieno e le quantità sono modificabili (da configurazione)
|
|
if (ini_get_string(CONFIG_DITTA, "lv", "Qtamodi") == "X")
|
|
{
|
|
TArticolo_lavanderie& artrec = cached_article_laundry(codart, 'C', clifo, indsp);
|
|
TRecmag_lavanderie& reclav = (TRecmag_lavanderie&)artrec.find_rec(year);
|
|
|
|
//gestione LF_CLIFOGIAC
|
|
if(!reclav.empty())
|
|
{
|
|
//riscrivo la dotazione iniziale convertita nell'unità di misura principale
|
|
const real dotin = row->get(righe.cid2index(S_DOTIN));
|
|
reclav.put(CLIFOGIAC_DOTIN, dotin);
|
|
|
|
//riscrivo la dotazione odierna convertita nell'unità di misura principale
|
|
const real dotod = row->get(righe.cid2index(S_DOTOD));
|
|
reclav.put(CLIFOGIAC_DOTOD, dotod);
|
|
|
|
//riscrivo la dotazione temporanea convertita nell'unità di misura principale
|
|
const real dottm = row->get(righe.cid2index(S_DOTTMP));
|
|
reclav.put(CLIFOGIAC_DOTTM, dottm);
|
|
|
|
//riscrivo il consegnato anno convertito nell'unità di misura principale
|
|
const real conan = row->get(righe.cid2index(S_CONSANNO));
|
|
reclav.put(CLIFOGIAC_CONSANNO, conan);
|
|
|
|
reclav.rewrite_write(magcli);
|
|
}
|
|
}
|
|
}
|
|
} //fine FOR_EACH_ROW
|
|
}
|
|
|
|
//BUILD_QUERY: metodo che crea la query sulle righe contratti
|
|
//recuperando i dati di interesse dalla maschera
|
|
TString TContratti_app:: build_query(const TMask& m) const
|
|
{
|
|
TString query="";
|
|
query << "USE LVRCONDV\n"
|
|
<< "FROM CODCF=" << m.get(F_CODCF) << " CODCONT=" << m.get(F_CODCONT) << "\n"
|
|
<< "TO CODCF=" << m.get(F_CODCF) << " CODCONT=" << m.get(F_CODCONT);
|
|
return query;
|
|
}
|
|
|
|
//FIND_ART: metodo che restituisce l'indice della riga dello sheet che contiene
|
|
//l'articolo desiderato (-1 se non lo trova)
|
|
int TContratti_app::find_art(TSheet_field& s, const TString& art) const
|
|
{
|
|
int r = -1;
|
|
//scorro le righe dello sheet partendo dall'ultima
|
|
for (r = s.items()-1 ; r>=0 ; r--)
|
|
{
|
|
const char* codart = s.row(r).get(0);
|
|
if (art == codart)
|
|
break;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
//USER_CREATE: metodo che crea TRelation e TContratti_msk solo se si è in un esercizio valido
|
|
//e che setta i comportamenti sulle righe aggiunte agli sheet
|
|
bool TContratti_app:: user_create()
|
|
{
|
|
TDate datasc(TODAY);
|
|
if (esercizi().date2esc(datasc) == 0)
|
|
return error_box("Attenzione non esiste l'esercizio corrispondente al %s", datasc.string());
|
|
|
|
_rel=new TRelation (LF_LVCONDV);
|
|
_msk= new TContratti_msk;
|
|
|
|
TSheet_field& ss = _msk->sfield(F_RIGHE);
|
|
|
|
ss.set_auto_append();
|
|
ss.set_append(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
//USER_DESTROY: metodo che distrugge le variabili globali alla fine dell'esecuzione
|
|
bool TContratti_app:: user_destroy()
|
|
{
|
|
delete _msk;
|
|
delete _rel;
|
|
return true;
|
|
}
|
|
|
|
|
|
//ON_CONFIG_CHANGE: per adesso un semplice segnaposto
|
|
void TContratti_app:: on_config_change()
|
|
{
|
|
}
|
|
|
|
//GET_NEXT_KEY: metodo che restituisce la chiave di ricerca sui contratti prendendo il prossimo codcont libero
|
|
bool TContratti_app:: get_next_key(TToken_string& key)
|
|
{
|
|
const long cliente=_msk->get_long(F_CODCF);
|
|
if (cliente <= 0)
|
|
return false;
|
|
|
|
key.add(F_CODCF);
|
|
key.add(cliente);
|
|
key.add(F_CODCONT);
|
|
|
|
long codcont= lv_new_contract(cliente, _msk->get_int(F_INDSPED));
|
|
key.add(codcont);
|
|
|
|
return true;
|
|
}
|
|
|
|
//READ: ridefinizione del metodo read() delle TRealtion_application
|
|
int TContratti_app::read(TMask& m)
|
|
{
|
|
//eseguo la read() standard
|
|
int err = TRelation_application::read(m);
|
|
//se la read va a buon fine
|
|
if(err == NOERR)
|
|
{
|
|
//instanzio un TISAM_recordset sulle righe contratto
|
|
TISAM_recordset righeset(build_query(m));
|
|
const TRectype& rec = righeset.cursor()->curr();
|
|
|
|
//instanzio un TLcalisamfile su LF_CLIFOGIAC
|
|
TLocalisamfile magcli(LF_CLIFOGIAC);
|
|
//setto alcune variabili di interesse
|
|
const TDate oggi(TODAY);
|
|
const int year = oggi.year();
|
|
const long clifo = m.get_long(F_CODCF);
|
|
const int indsp = m.get_int(F_INDSPED);
|
|
//recupero sheet e realtiva mashera di riga
|
|
TSheet_field& righe = m.sfield(F_RIGHE);
|
|
TMask& msk = righe.sheet_mask();
|
|
righe.destroy();
|
|
|
|
//per ogni riga dello sheet
|
|
for (bool ok = righeset.move_first(); ok; ok = righeset.move_next())
|
|
{
|
|
TToken_string& row = righe.row(-1);
|
|
//per ogni campo della maschera scrivi setta all'interno del record corrente di file
|
|
//il valore di quei campi che hanno un field
|
|
FOR_EACH_MASK_FIELD(msk,i,f)
|
|
{
|
|
const TFieldref*fr=f->field();
|
|
if (fr!= NULL)
|
|
row.add(fr->read(rec),righe.cid2index(f->dlg()));
|
|
}
|
|
|
|
const TString80 codart(row.get(righe.cid2index(S_CODART)));
|
|
|
|
//estraggo il record corrispondente su LF_CLIFOGIAC
|
|
TArticolo_lavanderie& artrec = cached_article_laundry(codart, 'C', clifo, indsp);
|
|
const TRecmag_lavanderie& reclav = artrec.find_rec(year);
|
|
//lettura dei dati da LF_CLIFOGIAC
|
|
//se esiste il record su LF_CLIFOGIAC, recupero l'unità di misura dalla riga dello sheet selezionata
|
|
//e setto i campi delle dotazioni e dei consegnati ai valori corretti riportati alla giusta unità di misura
|
|
if (!reclav.empty())
|
|
{
|
|
if (msk.get(S_DOTIN).blank())
|
|
{
|
|
//calcolo dotazione iniziale, scritta sia sulla maschera che sullo sheet
|
|
const real dotin = reclav.get_real(CLIFOGIAC_DOTIN);
|
|
|
|
row.add(dotin.stringa(), righe.cid2index(S_DOTIN));
|
|
}
|
|
//calcolo dotazione odierna, scritta sia sulla maschera che sullo sheet
|
|
const real dotod = reclav.get_real(CLIFOGIAC_DOTOD);
|
|
|
|
row.add(dotod.stringa(), righe.cid2index(S_DOTOD));
|
|
//calcolo dotazione temporanea, scritta sia sulla maschera che sullo sheet
|
|
const real dottmp = reclav.get_real(CLIFOGIAC_DOTTM);
|
|
|
|
row.add(dottmp.stringa(), righe.cid2index(S_DOTTMP));
|
|
}
|
|
//forzo una check_row
|
|
righe.check_row(righe.items()-1, 3);
|
|
}
|
|
//forzo l'update dello sheet
|
|
righe.force_update();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
//WRITE: ridefinizione del metodo write() delle TRelation_application
|
|
int TContratti_app::write(const TMask& m)
|
|
{
|
|
//esegui la write standard
|
|
int err = TRelation_application::write(m);
|
|
//se va a buon fine esegui la save_rows() e ricorda all'utente i passaggi per planning
|
|
if(err == NOERR)
|
|
{
|
|
save_rows(m);
|
|
warning_box(TR("Ricordarsi di inserire i passaggi per planning"));
|
|
}
|
|
return err;
|
|
}
|
|
|
|
//REWRITE: ridefinizione del metodo rewrite() delle TRelation_application
|
|
int TContratti_app::rewrite(const TMask& m)
|
|
{
|
|
//esegui la rewrite standard
|
|
int err = TRelation_application::rewrite(m);
|
|
//se va a buon fine esegui la save_rows()
|
|
if(err == NOERR)
|
|
save_rows(m);
|
|
return err;
|
|
}
|
|
|
|
//PROTECTED_RECORD: metodo che rendo un record non cancellabile
|
|
bool TContratti_app::protected_record(TRectype & rec)
|
|
{
|
|
TLaundry_contract cont(rec);
|
|
return !cont.can_be_deleted();
|
|
}
|
|
|
|
//REMOVE: ridefinizione del metodo remove() delle TRelartion_application
|
|
bool TContratti_app::remove()
|
|
{
|
|
//eseguo la remove standard
|
|
bool ok = TRelation_application::remove();
|
|
|
|
//se va a buon fine, elimino anche le righe contratto dal file specifico
|
|
if(ok)
|
|
{
|
|
TISAM_recordset righeset(build_query(*_msk));
|
|
TLocalisamfile& file=righeset.cursor()->file();
|
|
|
|
for (bool ok = righeset.move_first(); ok; ok = righeset.move_next())
|
|
{
|
|
file.remove();
|
|
}
|
|
//elimino i planning esistenti per quel cliente - contratto
|
|
elimina_planning(_msk->get_long(F_CODCONT),_msk->get_long(F_CODCF));
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
//INIT_QUERY_MODE: ridefinizione del metodo init_query_mode() standard
|
|
void TContratti_app::init_query_mode(TMask& m)
|
|
{
|
|
//abilita il campo F_RAGSOC se il campo F_CODCF è abilitato
|
|
m.field(F_RAGSOC).enable(m.field(F_CODCF).enabled());
|
|
m.reset();
|
|
}
|
|
|
|
//INIT_MODIFY_MODE: ridefinizione del metodo init_modify_mode() standard
|
|
void TContratti_app::init_modify_mode(TMask& m)
|
|
{
|
|
//setto alcune variabili di interesse
|
|
const TDate oggi(TODAY);
|
|
const int year=oggi.year();
|
|
const long clifo=m.get_long(F_CODCF);
|
|
const int indsp=m.get_int(F_INDSPED);
|
|
|
|
//instanzio un TLocaisamfile su LF_CLIFOGIAC
|
|
TLocalisamfile magcli(LF_CLIFOGIAC);
|
|
//recupero lo sheet
|
|
TSheet_field& righe = m.sfield(F_RIGHE);
|
|
|
|
//per ogni riga dello sheet aggiorno le dotazioni su LF_CLIFOGIAC
|
|
//per tutti ????, se il record esiste già
|
|
FOR_EACH_SHEET_ROW(righe,r,row)
|
|
{
|
|
const TString80 codart=row->get(righe.cid2index(S_CODART));
|
|
// righe.disable_cell(r, righe.cid2index(S_CODART));
|
|
// righe.disable_cell(r, righe.cid2index(S_DESCR));
|
|
// righe.disable_cell(r, righe.cid2index(S_UM));
|
|
|
|
for (int y = year + oggi.month() == 12; y >= year; y--)
|
|
{
|
|
magcli.put(CLIFOGIAC_ANNOES, y);
|
|
magcli.put(CLIFOGIAC_TIPOCF, 'C');
|
|
magcli.put(CLIFOGIAC_CODCF, clifo);
|
|
magcli.put(CLIFOGIAC_INDSPED, indsp);
|
|
magcli.put(CLIFOGIAC_CODART, codart);
|
|
|
|
if (magcli.read() == NOERR)
|
|
{
|
|
row->add(magcli.get(CLIFOGIAC_DOTIN), righe.cid2index(S_DOTIN));
|
|
row->add(magcli.get(CLIFOGIAC_DOTOD), righe.cid2index(S_DOTOD));
|
|
row->add(magcli.get(CLIFOGIAC_DOTTM), righe.cid2index(S_DOTTMP));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//INIT_INSERT_MODE: ridefinizione del metodo init_insert_mode() standard
|
|
void TContratti_app::init_insert_mode(TMask& m)
|
|
{
|
|
//se esiste già un contratto in essere alla data odierna per questo cliente,
|
|
//contrassegna quello attuale come "PROPOSTA"
|
|
const long codcf = m.get_long(F_CODCF);
|
|
const long indsp = m.get_int(F_INDSPED);
|
|
const TDate oggi(TODAY);
|
|
const long old_contr = lv_find_contract(codcf, indsp, oggi);
|
|
const long cur_contr = m.get_long(F_CODCONT);
|
|
if (old_contr > 0 && old_contr < cur_contr)
|
|
m.set(F_PROPOSTA, "X");
|
|
}
|
|
|
|
//ELIMINA PLANNING: metodo che prepara il recordset sui planning con le righe da eliminare
|
|
bool TContratti_app::elimina_planning(const long& codcont, const long& codcf) const
|
|
{
|
|
//creo il recordset
|
|
TISAM_recordset selrighe("USE LVRCONSPLAN KEY 3\nFROM CODCF=#CODCF CODCONT=#CODCONT \nTO CODCF=#CODCF CODCONT=#CODCONT");
|
|
//setto le variabili
|
|
selrighe.set_var("#CODCF",codcf);
|
|
selrighe.set_var("#CODCONT",codcont);
|
|
|
|
//richiamo la funzione che effettivamente fa la cancellazione delle righe interessate
|
|
kill_planning(selrighe);
|
|
|
|
return true;
|
|
}
|
|
|
|
//KILL_PLANNING: metodo che effettivamente fa la cancellazione dei planning interessati
|
|
bool TContratti_app::kill_planning (TISAM_recordset& selrighe) const
|
|
{
|
|
//se effettivamente ci sono delle righe da cancellare, allora le cancello
|
|
const int righe = selrighe.items();
|
|
if (righe > 0)
|
|
{
|
|
TProgind pi(righe, TR("Eliminazione planning in corso..."), true, true);
|
|
TLocalisamfile& rplan = selrighe.cursor()->file();
|
|
for (bool ok = selrighe.move_last(); ok; ok = selrighe.move_prev())
|
|
{
|
|
if (!pi.addstatus(1))
|
|
break;
|
|
rplan.remove();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int lv0400(int argc, char* argv[])
|
|
{
|
|
TContratti_app app;
|
|
app.run (argc,argv,TR("Gestione contratti"));
|
|
return 0;
|
|
} |