Metodo th_applymethod

Come elaborare righe in tempo reale con l’applymethod

Il metodo th_applymethod che fa parte dei metodi avanzati, consente di poter intervenire sui dati inviati dal server, prima che sia popolata la griglia, quindi consente di intervenire e di operare delle «elaborazioni» su ogni singola riga inviata dal server, consentendo inoltre di definire e gestire colonne calcolate.

Per il suo funzionamento, ha bisogno di un decoratore che andrà importato in testa al file tramite questa istruzione:

from gnr.core.gnrdecorator import public_method

Inoltre negli esempi verrà utilizzato anche un altro metodo che ha bisogno di un altro decoratore, che definiamo:

from gnr.core.gnrnumber import decimalRound

Anche per questa sezione gli esempi riguardano Sandbox ed in particolare la tabella fattura, quindi il file cliente corrispondente sarà th_cliente; dovremmo intervenire su due metodi della risorsa ed in particolare nella th_struct (come vedremo) e nel nuovo metodo che andiamo a descrivere nella sua definizione e funzionamento.

Iniziamo quindi col definire un nuovo metodo:

def th_applymethod(self,selection=None):

Nella th_struct della risorsa, definiamo poi una nuova colonna calcolata che verrà utilizzata in seguito:

r.cell('perc_fatturato',
      calculated=True,
      width='7em',
      name='Perc.fatt',
      dtype='N',
      format='###.00',
      totalize=True)

la colonna indica la percentuale del fatturato di ciascun cliente, rispetto al fatturato totale.

Riprendiamo quindi il nuovo metodo di cui poi andremo ad analizzarne il funzionamento:

#1.
@public_method
#2.
def th_applymethod(self,selection=None):
     #3.
     totale_finale = selection.sum('tot_fatturato')[0]
     #4.
     def cb(row):
     #5.
         return dict(perc_fatturato=decimalRound(row['tot_fatturato']/totale_finale*100))
     #6.
     selection.apply(cb)

#1. Aggiungiamo il decoratore

#2. Definiamo la funzione th_applymethod che riceve come parametro la selezione (l’insieme delle righe frutto del risultato della query)

#3. La somma (selection.sum('tot_fatturato'))ritorna una lista, quindi la selection.sum calcola il totale della colonna “tot_fatturato” e dato che si tratta di una lista si drovrà prendere il primo elemento [0]

#4. Viene definita all’interno del metodo una callback cb(row) che ritorna un dizionario nel quale possiamo far ritornare dei valori calcolati.

#5. In questo caso il dizionario ritorna un valore con chiave perc_fatturato e valore calcolato come totale fatturato della riga (row[“tot_fatturato”]) diviso per il totale della selezione corrente (totale_finale). Da osservare che il totale_finale, non è il totale del fatturato di tutti i clienti, ma il totale relativo ai clienti estratti dalla query ovvero dei dati presenti nella view.

#6. la selection.apply(cb) applica la funzione di callback a ciascuna riga, quindi in questo momento per ciascuna riga della grid viene eseguita la funzione e calcolato il valore della colonna perc_fatturato.

Suggerimento

Il metodo th_apply_method, essendo applicato alla selezione corrente, è estremamente dinamico e adattivo: basterà eseguire una query per effettuare il ricalcolo sulla base di una nuova selezione.

Abbiamo visto che in questo caso la percentuale fatturato per ciascuna riga viene calcolato in base al totale fatturato della selezione.

E se avessimo comunque la necessità di conoscere la percentuale del fatturato di ciascun cliente, non rispetto al totale della selezione ma rispetto al fatturato complessivo indipendente dalla selezione corrente, come potremmo arrivare a questo risultato?

Iniziamo aggiungendo una nuova colonna calcolata perc_glob nella th_struct…

r.cell('perc_glob',
      calculated=True,
      width='7em',
      name='Perc.glob',
      dtype='N',
      format='###.00',
      totalize=True)

e modifichiamo la funzione th_applymethod…

@public_method
def th_applymethod(self,selection=None):
    totale_finale = selection.sum('tot_fatturato')[0]

    #7.
    righe = self.db.table('fatt.fattura'
                    ).query(columns='SUM($totale_fattura) AS tot').fetch()
    #8.
    totale_complessivo = righe[0]['tot']

    def cb(row):
        #9.
        return dict(perc_fatturato=decimalRound(row['tot_fatturato']/totale_finale*100),
                    perc_glob=decimalRound(row['tot_fatturato']/totale_complessivo*100))
    selection.apply(cb)

#7. Viene calcolato, con una query, il totale generale del fatturato, quindi una query senza alcun parametro o condizione.

#8. Dal risultato (righe) si prende dalla «zeresima» riga, il valore con chiave “tot” (impostato nella query da… AS tot)

#9. Nel dizionario che ritorna i valori calcolati per ciascuna riga, viene aggiunta, rispetto alla versione precedente, un nuovo valore dato dal tot_fatturato (totale della selezione) diviso il totale_complessivo (totale generale fatturato)


Allegati:

Autore della sezione: Valter Vettorello