.. _tutorial_fatturazione/invoice_3:
Lezione 7: Miglioramenti fattura
================================
In questa lezione miglioreremo la form della fattura.
Inoltre vedremo come assegnare a un nuovo record valori di default e valori basati su contatori progressivi automatici.
.. raw:: html
Testata fattura
-----------------
Al termine della lezione precedente abbiamo lasciato la form della fattura ancora molto grezza ed incompleta.
Procediamo ora a dividere la parte superiore in una zona di sinistra ed una di destra, e per far ciò utilizzeremo un ``borderContainer``. In quella di sinistra posizioneremo i campi ``protocollo``, ``data``, ``totale_imponibile``, ``totale_iva`` e ``totale_fattura``. Questi ultimi tre campi avranno l'attributo ``readOnly=True`` dal momento che vengono calcolati automaticamente dai trigger.
La parte sinistra che accoglie i campi appena visti viene inserita in un elemento ``roundedGroup`` che incornicia un gruppo di campi con un titolo.
Nella parte di destra inseriremo un ``linkerBox`` per la selezione del cliente con i seguenti paramentri:
- ``openIfEmpty=True``, mostra il linkerBox aperto all'inserimento di una nuova fattura
- ``newRecordOnly=True``, non permette il cambiamento del cliente alla fattura una volta salvata
::
def th_form(self, form):
bc = form.center.borderContainer()
self.fatturaTestata(bc.borderContainer(region='top', datapath='.record', height='150px'))
self.fatturaRighe(bc.contentPane(region='center'))
def fatturaTestata(self, bc):
left = bc.roundedGroup(title='Dati fattura',
region='left', width='300px')
fb = left.formbuilder(cols=1, border_spacing='4px')
fb.field('protocollo')
fb.field('data')
fb.field('totale_imponibile', readOnly=True)
fb.field('totale_iva', readOnly=True)
fb.field('totale_fattura', readOnly=True)
bc.contentPane(region='center').linkerBox('cliente_id',
margin='2px',
openIfEmpty=True,
newRecordOnly=True)
Il linkerBox
--------------
Fino ad ora per selezionare il cliente avevamo usato un widget chiamato ``dbselect`` che è un widget che viene inserito in modo automatico dalla funzione ``field`` ogni volta che si riferisce ad un campo in relazione.
Infatti se un ``formbuilder`` è associato ad una tabella di database l'elemento ``field`` riconosce dal nome del campo il widget più adatto per l'input a seconda del tipo di dato.
La ``dbselect`` fa egregiamente il suo lavoro e ci consente di selezionare il cliente desiderato. Non ci consente però di richiamare alla vista i suoi dati anagrafici ed evenutalmente modificarli se necessario.
Per questo esiste il component ``linkerBox``, che si compone di una ``dbselect`` e di una zona template per visualizzare i dati del record selezionato opportunamente formattati. Per un approfondimento sul funzionamento dei widget **dbselect** e **linkerbox** vi rimandiamo alla spiegazione fornita nel `Manuale utente di Genropy `_.
Andiamo ora a vedere come si presenta la pagina della fattura e notiamo che in alto a destra c'è un riquadro che ci avvisa che non esiste ancora un template collegato.
Dal momento che il nostro utente *admin* ha i permessi necessari, con **shift + doppio click** andiamo a modificare il template.
.. raw:: html
Il templateEditor
------------------
Per creare il template richiesto dal linkerBox utilizzeremo uno strumento chiamato **templateEditor** che si apre in una palette e ci consente di svolgere alcuni compiti.
In primo luogo dall'albero nella colonna di sinistra della palette trasciniamo i campi che vorremmo usare nella griglia delle variabili in uso. Possiamo trascinare campi dalla tabella principale (cliente in questo caso), o da altre tabelle collegate. Il sistema provvederà automaticamente ad effettuare le query necessarie in modo da darci i dati richiesti.
Andiamo poi nella pagina del template e trasciniamo le variabili precedentemente selezionate, formattandole a nostro gradimento e inserendo le parti di testo che desideriamo.
Il salvataggio del template dal **templateEditor**, andrà a creare nella directory ``resources/tables/cliente/tpl`` il file ``default.xml`` (vedi allegato).
defaultValues
--------------
Al caricamento di una nuova fattura desideriamo assegnare la data di lavoro come data fattura. Per fare questo andiamo a modificare il model di ``fattura``, ed aggiungiamo il metodo ``defaultValues``. Questo deve restituire un *dict* che ha come chiavi i campi e come valori i loro default. ::
def defaultValues(self):
return dict(data=self.db.workdate)
.. image:: /_static/images/2019-08-30-104724.gif
:width: 700px
:align: center
Gestione automatica contatori
------------------------------
Nelle applicazioni gestionali è prassi frequente assegnare a dei documenti dei contatori progressivi per avere un riferimento univoco. Potremmo avere contatori per fatture cliente, note credito, documenti di trasporto, ordini ricevuti e via dicendo.
Gestire questi contatori, verificando che sia rispettata la cronologia e che non si creino salti di numerazione, è un compito noioso e che richiede molta pazienza.
In *Genropy* esiste un sottosistema di gestione contatori che fa capo al package **adm** che abbiamo incluso nel progetto.
Per indicare che la nostra fattura desidera usare il gestore dei contatori definiamo un metodo ``counter_protocollo`` che ci dovrà restituire i parametri di gestione del contatore in questo contesto. Si tratta di un metodo *hook* formato dal prefisso **counter** seguito dal nome della colonna che utilizzerà il contatore.
In particolare abbiamo qui deciso che il protocollo ovvero, il numero di fattura, sarà prefissato dalla lettera **F** (per distinguerlo ad esempio da una bolla che potrebbe usare la lettera **B**), conterrà poi le **ultime 2 cifre dell'anno** e di seguito **un numero di 6 cifre**.
Gli elementi detti sono definiti in un un parametro stringa ``format``, secondo una sintassi dove si usano degli elementi *placeholder* preceduti da **$**.
- **$K** è una parte di prefisso che viene riempita a partire dal parametro ``code``
- **$YY** (oppure potrebbe essere **$YYYY** o **$MM** o **$DD** o una loro combinazione) è l'elemento ottenuto dalla data di riferimento passata nel parametro ``date``
- **$N** rappresenta il numero restituito dal contatore
::
def counter_protocollo(self, record=None):
##Formato desiderato F19/000001
return dict(format='$K$YY/$NNNNNN', code='F', period='YY',
date_field='data', showOnLoad=True, recycle=True)
Il gestore dei contatori è anche in grado, per una nuova fattura, di mostrarci il numero che verrà poi assegnato al salvataggio. Per fare questo utilizziamo il parametro ``showOnLoad`` .
Se desideriamo che in caso di cancellazione il numero disponibile sia riutilizzato per evitare buchi di numerazione, utilizziamo il parametro ``recycle``.
Collaudo finale
----------------
Possiamo ora vedere come all'aggiunta di una nuova fattura il numero di protocollo venga assegnato in modo automatico. E potremo pertanto mettere anche questo campo ``readOnly=True``.
.. hint::
Nel video è anche mostrato come si effettuano le azioni di riallineamento dei contatori. Ma se avete eseguito correttamente le istruzioni finora riportate non dovrebbe essere necessario effettuare questa azione. A meno che non abbiate inserito delle fatture di prova.
.. raw:: html
.. raw:: html
**Allegati:**
- `default `_
- `fattura `_
- `th_fattura `_