Lezione 8: Modifiche alle viste¶
In questa lezione vedremo:
Come aggiungere ad una form griglie di dati in relazioni con il record primario.
Aggiungere sotto una griglia una riga che totalizzi gli importi numerici
Definire nel model delle formulaColumn, ovvero colonne astratte che riportano valori calcolati via espressioni SQL
Definire dei bottoni di sections su una View.
Vista fatture cliente¶
Per mostrare le fatture di un cliente, dall’interno della form cliente, andiamo a modificare il modulo th_cliente.py
. Ricordiamo che nella parte superiore della form era stato definito un formbuilder con i dati del cliente mentre al centro avevamo le note.
Provvediamo ora ad aggiungere un TabContainer
in modo da avere più pannelli nella parte centrale. Nel primo rimetteremo le note mentre per riempire il secondo creeremo il metodo fattureCliente
.
In tale metodo utilizzeremo il component plainTableHandler
che ci darà modo di visualizzare i record di fattura in relazione con il cliente correntemente visualizzato. Passiamo come unico parametro relation='@fatture'
per indicare che seguiamo la relazione definita in fattura fattura.py
con relation_name='fatture'
.
def th_form(self, form):
bc = form.center.borderContainer()
self.datiCliente(bc.roundedGroupFrame(
title='Dati cliente', region='top', datapath='.record', height='160px'))
tc = bc.tabContainer(region='center', margin='2px')
self.noteCliente(tc.contentPane(title='Note', datapath='.record'))
self.fattureCliente(tc.contentPane(title='Fatture'))
def fattureCliente(self, pane):
pane.plainTableHandler(relation='@fatture')
Totali su una vista¶
Ci piacerebbe che il nostro utente potesse immediatamente conoscere il totale del fatturato, dell’imponibile e dell’iva per il cliente corrente e decidiamo quindi di aggiungere al piede della griglia questi totali.
Andiamo a modificare th_fattura.py e creiamo una classe ViewFromCliente
, inizialmente copiando la classe View
togliendo il campo r.fieldcell('cliente_id')
. Semplicemente aggiungiamo totalize=True
alle colonne della griglia che vogliamo totalizzare.
class ViewFromCliente(BaseComponent):
def th_struct(self, struct):
r = struct.view().rows()
r.fieldcell('protocollo', width='10em')
r.fieldcell('data', width='7em')
r.fieldcell('totale_imponibile', totalize=True)
r.fieldcell('totale_iva', totalize=True)
r.fieldcell('totale_fattura', totalize=True)
Ora specifichiamo nella form del cliente che il plainTableHandler
delle fatture deve riferirsi alla classe ViewFromCliente
.
pane.plainTableHandler(relation='@fatture', viewResource='ViewFromCliente')
Infine in modo semplice e veloce ai fini del tutorial andiamo a definire la formattazione dei campi che rappresentano un importo. Modifichiamo il model di fattura e fattura_riga come segue:
tbl.column('totale_imponibile', dtype='N', size='14,2',format='#,###.00',
name_long='Totale imponibile')
tbl.column('totale_iva', dtype='N', name_long='Totale Iva', size='14,2',format='#,###.00')
tbl.column('totale_fattura', dtype='N', name_long='Totale', size='14,2',format='#,###.00')
-----------------------------------------------------------------------------------------------------
tbl.column('prezzo_unitario', dtype='N',size='14,2',format='#,###.00',
name_long='Prezzo unitario', name_short='P.U.')
tbl.column('aliquota_iva', dtype='N', size='14,2',format='#,###.00',
name_long='Aliquota iva', name_short='Iva')
tbl.column('prezzo_totale', dtype='N', size='14,2',format='#,###.00',
name_long='Prezzo totale', name_short='P.T.')
tbl.column('iva', dtype='N', size='14,2',format='#,###.00', name_long='Tot.Iva')
In una reale applicazione avremmo definito nel main una tipologia, per poi richiamarla sui campi interessati:
def custom_type_money(self):
return dict(dtype='N',size='14,2',format='#,###.00')
-----------------------------------------------------------------------------------------------------
tbl.column('totale_imponibile','money',name_long = 'Totale Imponibile')
tbl.column('totale_iva','money',name_long = 'Totale Iva')
tbl.column('totale_fattura', 'money', name_long='Totale)
Vista prodotti acquistati¶
Vogliamo offrire all’utente la possibilità di vedere immediatamente quali prodotti siano stati acquistati dal cliente. Per questa ragione torniamo a modificare th_cliente.py
e aggiungiamo al tabContainer
una nuova scheda, il cui contenuto sarà definito nel metodo prodottiCliente
.
Qui usiamo nuovamente il component plainTableHandler
ma, questa volta, non abbiamo una relazione diretta da seguire tra cliente e prodotto. Pertanto useremo una sintassi alternativa che prevede di indicare come parametri
self.prodottiCliente(tc.contentPane(title='Prodotti Acquistati'))
table (in questo caso
prodotto
)condition , che corrisponde ad una clausola WHERE per la query che selezionerà gli elementi della griglia
def prodottiCliente(self, pane):
pane.plainTableHandler(table='fatt.prodotto',
condition='@righe_fattura.@fattura_id.cliente_id =:cl_id',
condition_cl_id='^#FORM.record.id', export=True)
Il significato di questa sintassi è di imporre che i prodotti selezionati abbiano almeno una riga di fattura in cui il cliente_id della fattura stessa sia quello corrente. Il parametro formale cl_id viene passato al tablehandler come condition_cl_id per indicare che fa parte integrante della condition.
Con il parametro export=True
viene aggiunto il bottone per l’export della tabella come worksheet .xls.
Le formulaColumn¶
Apriamo ora il modulo di model cliente.py
e mostriamo come sia possibile aggiungere ad una table non solo colonne reali ma anche colonne calcolate.
In particolare desideriamo che per ogni cliente sia calcolato il numero delle fatture presenti e il valore del fatturato.
A tale scopo aggiungiamo a tbl una formulaColumn il cui nome è n_fatture
e il cui valore è il risultato di una subselection nella tabella fattura.
tbl.formulaColumn('n_fatture', select=dict(table='fatt.fattura',
columns='COUNT(*)',
where='$cliente_id=#THIS.id'),
dtype='L',
name_long='N.Fatture')
Per il totale fatturato al cliente si procede in modo analogo.
Dal momento che le colonne sono solo calcolate non è necessario riallineare il database ma potremo tornare alla pagina cliente e senza nemmeno ricaricarla trascinare dal configuratore nel cassetto laterale della griglia le colonne n_fatture
e tot_fatturato
che abbbiamo appena creato.
Sections¶
Desideriamo offrire all’utente la possiblità di suddividere l’archivio dei clienti tra quelli che hanno già fatto acquisti e quelli che abbiamo caricato ma non hanno ancora acquistato.
Sfruttiamo a tale scopo una particolare feature di Genropy andando a modificare la classe View
in th_cliente.py
.
Per prima cosa aggiungiamo alla vista le colonne n_fatture
e tot_fatturato
e poi definiamo il metodo th_sections_acquisti
.
def th_struct(self, struct):
r = struct.view().rows()
r.fieldcell('ragione_sociale')
r.fieldcell('cliente_tipo_codice')
r.fieldcell('pagamento_tipo_codice')
r.fieldcell('indirizzo')
r.fieldcell('provincia')
r.fieldcell('comune_id')
r.fieldcell('n_fatture')
r.fieldcell('tot_fatturato', format='#,###.00')
def th_sections_acquisti(self):
return [dict(code='tutti', caption='Tutti'),
dict(code='con_acquisti', caption='Con Acquisti', condition='$n_fatture>0'),
dict(code='senza_acquisti', caption='Senza Acquisti', condition='$n_fatture=0')]
I metodi di una classe di tipo view che iniziano per th_sections
servono a definire le sezioni in cui vogliamo ripartire i record della table. Tali sezioni vengono chiamate in Genropy sections, e si presentano come bottoni che aggiungono alla query corrente una condizione particolare specificata dal parametro condition
.
Dovremo a tal fine rendere una lista di dizionari dove ogni elemento rappresenta una section e nel dizionario sono definiti i parametri di sezionamento. In particolare creiamo 3 sezioni:
Tutti: che mostra tutti i clienti selezionati senza restrizioni aggiuntive
Con Acquisti: la quale aggiunge come condizione che il numero di fatture del cliente sia maggiore di zero.
Senza Acquisti: la quale aggiunge come condizione che il numero di fatture del cliente sia zero.
Procediamo quindi ad utilizzare come visto in precedenza un metodo th_top
per aggiungere una slotBar
. In questa slotBar porremo i bottoni per selezionare le sections.
def th_top_toolbarsuperiore(self, top):
top.slotToolbar('5,sections@acquisti,*', childname='superiore', _position='<bar')
Ricaricando la pagina del cliente notiamo la presenza dei bottoni di sections e notiamo che il titolo della vista cambia a seconda della section selezionata.
Desideriamo introdurre ora anche delle sections basate sul tipo_cliente
. In questo caso non occorre definire una section con una condition. Basterà aggiungere nella slotToolbar
un elemento sections@cliente_tipo_codice
dove cliente_tipo_codice è la colonna sulla quale vogliamo suddividere i record. Automaticamente vengono creati i bottoni corrispondenti a tutti i tipi cliente che sono stati creati nel database e ad essi viene associata l’opporotuna condition.
top.slotToolbar('5,sections@acquisti,*,sections@cliente_tipo_codice,5', childname='superiore', _position='<bar')
Allegati: