.. _tutorial_fatturazione/invoice_1:
Lezione 5: Fattura e righe fattura
==================================
In questa lezione verranno create le tabelle ``fattura``, ``fattura_riga`` e le rispettive risorse.
.. raw:: html
Tabella fattura
---------------
Creiamo ora la tabella ``fattura.py`` e mettiamo la colonna ``protocollo`` (ovvero un numero progressivo che dovrà ripartire ad ogni anno), ``cliente_id`` per collegare la tabella ``cliente``, e poi le colonne ``data``, ``totale_imponibile``, ``totale_iva`` e ``totale_fattura``.
::
class Table(object):
def config_db(self, pkg):
tbl = pkg.table('fattura', pkey='id',
name_long='Fattura', name_plural='Fattura', caption_field='protocollo')
self.sysFields(tbl)
tbl.column('protocollo', size='10', name_long='Protocollo')
tbl.column('cliente_id', size='22', group='_', name_long='Cliente'
).relation('cliente.id',
relation_name='fatture',
mode='foreignkey', onDelete='raise')
tbl.column('data', dtype='D', name_long='Data')
tbl.column('totale_imponibile', dtype='N',
name_long='Totale imponibile')
tbl.column('totale_iva', dtype='N', name_long='Totale Iva')
tbl.column('totale_fattura', dtype='N', name_long='Totale')
Tabella fattura_riga
----------------------
Procediamo quindi a creare la tabella ``fattura_riga`` definendo le colonne necessarie. ::
class Table(object):
def config_db(self, pkg):
tbl = pkg.table('fattura_riga', pkey='id',
name_long='Fattura riga', name_plural='Fattura righe')
self.sysFields(tbl)
tbl.column('fattura_id', size='22', group='_',
name_long='Fattura'
).relation('fattura.id', relation_name='righe', mode='foreignkey', onDelete='cascade')
tbl.column('prodotto_id', size='22', group='_', name_long='Prodotto').relation(
'prodotto.id', relation_name='righe_fattura', mode='foreignkey', onDelete='raise')
tbl.column('quantita', dtype='I',
name_long=u'Quantità', name_short='Q.')
tbl.column('prezzo_unitario', dtype='N',
name_long='Prezzo unitario', name_short='P.U.')
tbl.column('aliquota_iva', dtype='N',
name_long='Aliquota iva', name_short='Iva')
tbl.column('prezzo_totale', dtype='N',
name_long='Prezzo totale', name_short='P.T.')
tbl.column('iva', dtype='N', name_long='Tot.Iva')
In particolare la colonna ``fattura_id`` rappresenta il collegamento con la fattura. Notiamo che nel descrivere la relazione aggiungeremo l'attributo ``onDelete='cascade'`` per indicare che in caso di cancellazione della fattura le righe fattura dovranno parimenti essere cancellate.
Al contrario nella relazione con il ``prodotto_id`` useremo ``onDelete='raise'`` per indicare che il sistema dovrà impedire la cancellazione del record prodotto, se questo è referenziato da una riga fattura.
Creazione tabella tipo_iva
--------------------------
Per tenere conto del possibile diverso trattamento fiscale dei vari prodotti provvediamo a modificare la table ``prodotto`` aggiungendo la colonna ``tipo_iva_codice``
::
tbl.column('tipo_iva_codice', size=':5', group='_', name_long='!![it]Tipo iva').relation(
'tipo_iva.codice', relation_name='prodotti', mode='foreignkey', onDelete='raise')
in relazione con l'apposita tabella di lookup ``tipo_iva`` che provvediamo a creare, come già visto nella :ref:`Lezione 3`
::
class Table(object):
def config_db(self, pkg):
tbl = pkg.table('tipo_iva', pkey='codice', name_long='Tipo iva',
name_plural='Tipi iva', caption_field='descrizione', lookup=True)
self.sysFields(tbl, id=False)
tbl.column('codice', size=':5', name_long='Codice')
tbl.column('descrizione', name_long='Descrizione')
tbl.column('aliquota', dtype='N', name_long='Aliquota')
Inoltre modificheremo la form del prodotto per aggiungere il campo ``tipo_iva``
::
fb.field('tipo_iva_codice', validate_notnull=True)
Quindi dopo aver
- riallineato il database
- resettato il server
Procediamo a popolare la tabella ``tipo_iva`` e ad assegnare i valori di ``tipo_iva_codice`` ai prodotti già creati.
.. raw:: html
Form fattura
--------------
Adesso facciamo generare le risorse ``th_fattura`` e ``th_fattura_riga`` e modifichiamole per migliorarle.
Come già visto precedentemente per il cliente, usiamo un ``BorderContainer`` per dividere la form in 2 regioni: quella superiore che conterrà i dati di testata e quella centrale dove verranno caricate le righe fattura.
Creiamo quindi il metodo ``fatturaTestata`` che andrà a definire la form in un ``contentPane`` posto nella regione superiore.
Eliminiamo quindi i campi relativi ai totali, infatti questi saranno calcolati in modo automatico.
::
def th_form(self, form):
bc = form.center.borderContainer()
self.fatturaTestata(bc.contentPane(region='top', datapath='.record', height='150px'))
self.fatturaRighe(bc.contentPane(region='center'))
def fatturaTestata(self, pane):
fb = pane.formbuilder(cols=2, border_spacing='4px')
fb.field('protocollo')
fb.field('data')
fb.field('cliente_id')
Le righe della fattura
----------------------
Definiamo poi il metodo ``fatturaRighe``. In questo ``contentPane`` inseriremo il component ``inlineTableHandler`` che è un gestore completo di tabella con editing in linea dei dati. Questo component si occuperà di gestire la tabella, ci darà modo di aggiungere righe, cancellarle e modificarle. ::
def fatturaRighe(self, pane):
pane.inlineTableHandler(relation='@righe', viewResource='ViewFromFattura')
In seguito torneremo ampiamente sui ``tableHandler`` ma per il momento ci limitiamo a crearlo dando come parametro la relazione ``relation='@righe'`` che deve essere seguita al fine di riempire la griglia con le righe relative al record di fattura corrente.
Inoltre mettiamo anche un attributo ``viewResource='ViewFromFattura'`` per specificare che useremo una classe di view della risorsa ``th_fattura_riga`` creata appositamente per essere visualizzata dalla form di fattura.
la classe ViewFromFattura
-------------------------
Procediamo a modificare il modulo ``th_fattura_riga`` creando la classe ``ViewFromFattura``.
Nella struttura eliminiamo la colonna fattura_id in quanto non sarà necessario mostararla. Andiamo poi ad aggiungere sulle colonne **prodotto_id** e **quantita** l'attributo **edit=True** per indicare che desideriamo editare le celle corrispondenti.
::
class ViewFromFattura(BaseComponent):
def th_struct(self, struct):
r = struct.view().rows()
r.fieldcell('prodotto_id', edit=True)
r.fieldcell('quantita', edit=True)
r.fieldcell('prezzo_unitario')
Primo collaudo
----------------
Procediamo a collaudare la fattura modificando prima il menu
::
fatt.thpage(u"Fattura", table="fatt.fattura")
e caricando il primo record. Per il momento non ci sono ancora automatismi e quindi metteremo manualmente un numero di fattura e la data.
Sceglieremo quindi un cliente e con il bottone + della vista delle righe creeremo una riga nella quale scegliamo un prodotto e mettiamo una quantità. Salviamo quindi la fattura con la riga creata. Nel prossimo capitolo vedremo come migliorare la nostra pagina per la creazione delle fatture.
.. raw:: html
.. raw:: html
**Allegati:**
- `fattura_riga `_
- `tipo_iva `_
- `th_fattura_riga `_
- `th_prodotto `_
- `prodotto `_
- `fattura `_
- `menu `_
- `th_fattura `_