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.


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:

<packages>
              <gnrcore_sys pkgcode="gnrcore:sys"/>
              <gnrcore_adm pkgcode="gnrcore:adm"/>
              <gnr_it_glbl pkgcode="gnr_it:glbl"/>
              <sandbox pkgcode="sandbox"/>
              <fatt pkgcode="fatt" min_importo='1' />
</packages>

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 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 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).

Suggerimento

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 table , di un Widget, di un Container o di una 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.

Suggerimento

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.

Autore della sezione: Mauro Zanardi e Davide Paci