.. _package/adm/preference: Preferenze ========== Come impostare la gestione delle preferenze ------------------------------------------- Ci si trova spesso nella situazione di voler parametrizzare alcune informazioni che poi devono essere utilizzate direttamente nel codice: si tratta di variabili da utilizzare all'interno dell'applicativo per effettuare calcoli, dati di fatturazione dell'azienda, aliquote, e così via. .. raw:: html
Una prima opzione che abbiamo a disposizione è di impostare questi valori **direttamente nel file dell'istanza di Genropy**. Ipotizziamo per esempio, nel progetto `Sandbox `_, di voler inserire un parametro ``importo_min`` da confrontare con il totale della fattura: se il totale sarà inferiore a questo importo minimo, non sarà possibile salvare (o modificare) il record, e verrà mostrato un avviso di errore. Per seguire questa strada andiamo nel nostro file ``instanceconfig.xml`` e, accanto al package ``fatt``, aggiungiamo *importo_min* come semplice attributo:: Il valore qui inserito potrà essere poi utilizzato per il confronto in qualunque punto dell'applicativo in quanto *attributo* del package *fatt*, per esempio all'interno di un :ref:`Trigger` :: if record['totale_fattura'] < int(self.application.packages['fatt'].attributes['min_importo']): raise self.exception('standard', msg="Devi raggiungere l'importo minimo per salvare la fattura") Di per sé così facendo funzionerebbe, ma ogni volta che si dovrà fare una variazione del valore impostato bisognerà agire sul codice e riavviare il server, il che rende questa strada poco praticabile. L'alternativa migliore messa a disposizione da Genropy è quella della **gestione delle preferenze**. In questo modo si renderà accessibili queste preferenze direttamente all'interno dell'applicativo nell'apposita sezione `Preferenze del Footer `_. Per predisporre la gestione delle preferenze è sufficiente aggiungere un file ``preferences.py`` nelle ``resources`` del `package `_ interessato. Il file vedrà innanzitutto la definizione di una classe ``AppPref`` che eredita da *object*:: class AppPref(object): def permission_fatt(self, **kwargs): return 'admin' def prefpane_fatt(self, parent, **kwargs): pane = parent.contentPane(**kwargs) fb = pane.formbuilder(cols=1, border_spacing='3px') fb.numbertextbox('^.min_importo', lbl='Min. importo fatt.', width='5em') Con il primo metodo ``permission_nomedelpackage`` è possibile subordinare la gestione delle preferenze a un :ref:`Tag di Autorizzazione` utente: nel nostro esempio solo gli utenti di rango *admin* potranno apportare modifiche a queste preferenze. Il secondo metodo ``prefpane_nomedelpackage``, invece, permette di costruire, visivamente, il pannello di controllo delle preferenze da gestire. Queste preferenze saranno quelle **generali dell'applicativo**, valide per *tutti* gli utenti. Diverso discorso è invece il sistema delle preferenze dei singoli utenti, modificabili sempre nel `Footer `_ dell'applicativo in basso a destra in corrispondenza del bottone con il nome dell'utente. Quelle preferenze saranno esclusive del singolo utente e sono definibili in modo analogo come segue:: class UserPref(object): def prefpane_my_package(self, parent, **kwargs): pane = parent.contentPane(**kwargs) fb = pane.formbuilder(cols=1, border_spacing='3px') fb.textBox(value='^.user_value', lbl='User prefs') La classe non sarà quindi *AppPref* ma ``UserPref``, e funzionerà in modo del tutto analogo alla precedente. Come leggere le preferenze e usarne i valori -------------------------------------------- Una volta impostate le preferenze, in qualsiasi punto del codice dell'applicativo sarà possibile "leggere" i valori che sono stati impostati e determinare il comportamento da seguire. Per esempio, analogamente al caso precedente, avremo:: if record['totale_fattura'] < self.db.application.getPreference('generali.min_importo', pkg='fatt', mandatoryMsg='!![it]Non hai impostato un importo minimo per le fatture'): raise self.exception('standard', msg="Devi raggiungere l'importo minimo per salvare la fattura") Si utilizza quindi il metodo ``getPreference``, indicando come primo parametro non nominato il path del parametro (*min_importo*, come abbiamo indicato nella definizione delle preferenze), e poi il *package* dal quale leggere il file. Infine, con l'attributo ``mandatoryMsg``, è possibile inviare una notifica all'utente in merito all'obbligatorietà di aver preventivamente configurato le preferenze (in questo caso attraverso un *floatingMessage*). .. hint:: In alternativa alla richiesta di configurazione da parte dell'utente, si potrebbe valutare di inserire un valore di default nel file dell'istanza come abbiamo fatto precedentemente: in questo modo è possibile evitare di incappare in errori qualora i valori non fossero stati configurati nell'applicativo, utilizzando dei valori di default. Tabelle e colonne condizionate dalle preferenze: l'attributo checkPref ---------------------------------------------------------------------- Attraverso la gestione delle preferenze è anche possibile "condizionare" l'utilizzo di una :ref:`table` , di un `Widget `_, di un `Container `_ o di una :ref:`colonna` a quanto definito da una preferenza. Ipotizziamo per esempio di avere una tabella ``argomenti``, e di voler condizionare l'effettivo utilizzo all'interno dell'applicativo di questa tabella sulla base del fatto che nelle preferenze sia stata flaggata l'opzione ``abilita_argomenti``. Le preferenze saranno così definite:: def prefpane_dem(self,parent,**kwargs): pane = parent.contentPane(**kwargs) fb = pane.formbuilder(cols=1,border_spacing='3px', margin='10px') fb.checkbox(value='^.abilita_argomenti', lbl='Abilita argomenti') fb.checkbox(value='^.usa_comuni', lbl='Usa comuni') Nella *Table*, invece, andremo a utilizzare l'attributo ``checkpref``, grazie al quale subordineremo l'attivazione della tabella alla preferenza appena definita:: class Table(object): def config_db(self,pkg): tbl=pkg.table('argomento', pkey='id', name_long='Argomento', caption_field='descrizione', lookup=True, checkpref='dem.abilita_argomenti') L'attributo *checkpref* indica il ``package`` delle preferenze e il ``path``, separati dal punto. A questo punto se la `checkbox `_ è stata attivata, la *Table* verrà utilizzata, la *risorsa* sarà raggiungibile e la pagina sarà disponibile nel menu. In caso contrario, tutte queste opzioni verranno inibite automaticamente, senza necessità di ulteriori interventi manuali. Analogo discorso può essere affrontato anche per la subordinazione di una *colonna* a una preferenza. Ipotizziamo per esempio di condizionare la colonna ``comune_id`` all'attivazione dell'opzione ``usa_comuni`` precedentemente definita:: tbl.column('comune_id',size='22',name_long='!![it]Comune', checkpref='dem.usa_comuni' ).relation('glbl.comune.id') Anche in questo caso, solo se la *checkbox* sarà stata attivata verrà effettivamente mostrato il campo nelle `View e nelle Form `_. .. hint:: L'attributo ``checkPref`` influisce sulla visualizzazione o meno della *risorsa* e della *pagina* nel menù, non sull'effettiva esistenza della colonna o della tabella nel database. .. sectionauthor:: Mauro Zanardi e Davide Paci