.. _tutorial_fatturazione/view: 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. .. raw:: html
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') .. raw:: html
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) .. image:: /_static/images/2019-09-05-110536.gif :width: 700px :align: center 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**. .. image:: /_static/images/2019-09-05-111950.gif :width: 700px :align: center 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. .. image:: /_static/images/2019-09-05-113213.gif :width: 700px :align: center 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=' **Allegati:** - `th_cliente `_ - `fattura `_ - `th_fattura `_ - `fattura_riga `_ - `cliente `_