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)
_images/2019-09-05-110536.gif

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.

_images/2019-09-05-111950.gif

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.

_images/2019-09-05-113213.gif

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.

_images/2019-09-05-114727.gif

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')
_images/2019-09-05-115216.gif

Attachments: