.. _tutorial_fatturazione/product:
Lezione 4: Tabelle gerarchiche
==============================
In questa lezione verranno create le tabelle ``prodotto``, ``prodotto_tipo`` e le rispettive risorse di form.
.. raw:: html
Tabella prodotto
-----------------
In analogia a quanto fatto per il cliente creiamo il modulo ``prodotto.py`` e provvediamo a creare le colonne desiderate. In particolare desideriamo che il nostro archivio prodotti sia diviso in categorie gerarchiche e a tal fine definiamo una colonna ``prodotto_tipo_id``.::
class Table(object):
def config_db(self, pkg):
tbl = pkg.table('prodotto', pkey='id',
name_long='Prodotto', name_plural='Prodotti', caption_field='descrizione')
self.sysFields(tbl)
tbl.column('codice', size=':10', name_long='Codice')
tbl.column('descrizione', size=':50', name_long='Descrizione')
tbl.column('prodotto_tipo_id', size='22', group='_', name_long='Tipo Prodotto', name_short='Tipo').relation(
'prodotto_tipo.id', relation_name='prodotti', mode='foreignkey', onDelete='raise')
Tabella prodotto_tipo
---------------------
Nelle applicazioni gestionali ci si trova spesso a dover gestire gerarchie. In Genropy esiste una tipologia di tabelle specifica per questo scopo.
In genropy si definisce tabella gerarchica o **hierarchical table** una tabella i cui record hanno una relazione verso un altro record *padre*, appartenente alla tabella stessa. Tale relazione è associata alla foreignkey parent_id.
Questo modello si adatta ad entità che sono intrinsecamente gerarchiche, ovvero in cui gli elementi sono contenuti gli uni negli altri.
Definiamo quindi la tabella gerarchica prodotto_tipo creando il modulo ``prodotto_tipo.py``.
In esso definiamo come al solito la classe Table ma alla chiamata ``self.sysFields`` aggiungiamo il parametro ``hierarchical="descrizione"`` per indicare che intendiamo creare una gerarchia e che vogliamo avere un campo descrizione gerarchica basato sulla colonna descrizione.
L'uso del parametro ``hierarchical`` farà sì che vengano aggiunte automaticamente le colonne necessarie per rendere la tabella *gerarchica*, in particolare la relazione interna sulla colonna ``parent_id``.::
class Table(object):
def config_db(self, pkg):
tbl = pkg.table('prodotto_tipo', pkey='id', name_long='Tipo prodotto',
name_plural='!!Tipi prodotto',
caption_field='hierarchical_descrizione')
self.sysFields(tbl, hierarchical='descrizione', counter=True, df=True)
tbl.column('descrizione', size=':50', name_long='Descrizione')
Risorsa tabella prodotto_tipo
-----------------------------
Come già visto nella :ref:`Lezione 2` generiamo automaticamente con l'istruzione ``gnrmkthresource`` le risorse mancanti ed andiamo a lavorare sul modulo ``th_prodotto_tipo.py``.
::
gnrmkthresource fatturazione:fatt
Notiamo che il costruttore aggiunge molti campi che in realtà sono di uso interno; procediamo quindi a toglierli sia dalla view che dalla form. Per segnalare che desideriamo editare in modalità gerarchica, alla form aggiungiamo tra i valori restituiti da ``th_options`` l'attributo ``hierarchical=True``.
::
class View(BaseComponent):
def th_struct(self,struct):
r = struct.view().rows()
r.fieldcell('hierarchical_descrizione')
def th_order(self):
return 'hierarchical_descrizione'
def th_query(self):
return dict(column='hierarchical_descrizione', op='contains', val='')
class Form(BaseComponent):
def th_form(self, form):
pane = form.record
fb = pane.formbuilder(cols=2, border_spacing='4px')
fb.field('descrizione')
def th_options(self):
return dict(dialog_height='400px', dialog_width='600px', hierarchical=True)
Test delle tabelle prodotto e prodotto_tipo
-------------------------------------------
Dopo aver modificato il menu di package per includere le due tabelle appena create riallineamo il db e riavviamo il server.
Iniziamo a creare un record di ``prodotto_tipo`` e ci accorgiamo che nelle tabelle gerarchiche abbiamo una colonna di destra con un albero per visualizzarne gli elementi.
Creiamo alcuni record e notiamo la presenza di due distinti bottoni di +. Uno al termine di un **breadcrumb** che rappresenta il **path corrente** e che serve per aggiungere elementi **figli** dell'elemento corrente. L'altro bottone di + collocato nella solita posizione invece aggiunge elementi **fratelli** di quello corrente.
Nel caso caricassimo elementi in posizioni errate potremo facilmente riorganizzarli semplicemente **trascinando** i nodi dell'albero. Il sistema automaticamente farà le scritture necessarie a riallineare la gerarchia. Trascinando nell'albero con il **tasto maiuscolo** potremo anche riordinare gli elementi nell'ordine preferito.
Per un approfondimento sull'utilizzo delle pagine di gestione delle tabelle gerarchiche rimandiamo alla spiegazione fornita dal `manuale utente di Genropy `_.
.. raw:: html
Modifichiamo prodotto e prodotto_tipo
-------------------------------------
Nel collaudo della tabella ``prodotto_tipo`` ci accorgiamo che non esiste una validazione su descrizione e pertanto provvediamo ad aggiungere al campo *descrizione* l'attributo ``validate_notnull=True``
Vengono poi aggiunti alla tabella ``prodotto``
- il campo ``prezzo_unitario`` sia nel model che nelle resouces
- il parametro ``validate_case='U'`` per convertire automaticamente in maiuscolo il codice caricato, ed il parametro ``validate_nodup=True`` per chiedere al sistema di controllare che non esistano prodotti con lo stesso codice, al campo *codice* nella form
- il parametro ``validate_notnull=True`` per dire che è obbligatorio, su tutti i campi nella form
- l'attributo ``tag='hdbselect'`` al campo *prodotto_tipo_id* nella form, che consente di ricercare il tipo prodotto sia in modo gerarchico che per descrizione.
Collaudo finale
-----------------
Testiamo ora la form dei prodotti e possiamo caricare alcune voci verificando che il controllo sulla duplicazione di codici prevenga effettivamente questo tipo di problema.
.. raw:: html
.. raw:: html
**Allegati:**
- `prodotto `_
- `th_prodotto_tipo `_
- `prodotto_tipo `_
- `th_prodotto `_
- `menu `_