Stampa griglia 2: Prodotti

Supponiamo di voler stampare un elenco di record sulla base di una query con delle condizioni specifiche, raggruppando i risultati sulla base di un determinato criterio.

In quest’esempio vedremo come definire la risorsa di stampa relativa alle Statistiche di vendita dei prodotti in un esercizio, raggruppati per prodotto, eventualmente filtrabili per singolo cliente. La stampa verrà lanciata dalla tabella Prodotti del progetto Sandbox. In particolare, questo esempio ci permetterà di vedere come utilizzare il metodo gridData per definire i criteri di selezione dei record da stampare.

Definizione della print action

Per prima cosa andiamo a definire la risorsa print che chiamiamo stampa_prodotti.py all’interno della cartella resources/tables/prodotto/print, esattamente come abbiamo fatto nella Stampa con griglia 1: Fatturato per esercizio .

Non essendoci particolari variazioni sui parametri richiesti per la stampa rimandiamo al caso precedente per una trattazione più completa.

Definizione della risorsa html_res

Passiamo a questo punto alla definizione della risorsa html_res che chiamiamo stats_prodotti.py all’interno della cartella resources/tables/prodotto/html_res.

Rimandiamo alla Stampa con griglia 1: Fatturato per esercizio per la trattazione della definizione dei parametri della classe Main, dei metodi defineCustomStyles, docHeader, docFooter e outputDocName, che non variano in questo caso in modo significativo.

Ci concentriamo invece in questa stampa sull’utilizzo del metodo gridData per raccogliere i dati delle righe. In questo caso, diversamente dal precedente, il nostro obiettivo di raggruppamento delle vendite di ogni prodotto non può essere raggiunto in alcun modo dalla query di default, e non sarà quindi sufficiente limitarsi a stabilire delle condizioni tramite il metodo gridQueryParameters.

Andremo infatti a ridefinire direttamente il metodo gridData, intervenendo sulla query e imponendo i criteri di raggruppamento, nonché modificando poi l’esito della ricerca:

def gridData(self):
      condition=['@fattura_id.anno_fattura=:anno']
      if self.parameter('cliente_id'):
          condition.append('@fattura_id.cliente_id=:cliente')
      where=' AND '.join(condition)

      fatturato_grouped_by_prodotto = self.db.table('fatt.fattura_riga').query(columns="""
                                          SUM($prezzo_totale) AS prezzo_totale,
                                          SUM($iva) AS iva,
                                          @prodotto_id.codice AS codice,
                                          @prodotto_id.descrizione AS descrizione,
                                          @prodotto_id.@prodotto_tipo_id.hierarchical_descrizione AS prodotto_gerarchia,
                                          @prodotto_id.@prodotto_tipo_id.descrizione AS prodotto_tipo""",
                                          where=where,
                                          anno=self.parameter('anno'),
                                          cliente=self.parameter('cliente_id'),
                                          group_by="""@prodotto_id.codice, @prodotto_id.descrizione,
                                          @prodotto_id.@prodotto_tipo_id.hierarchical_descrizione,
                                          @prodotto_id.@prodotto_tipo_id.descrizione""").fetch()

      for prodotto in fatturato_grouped_by_prodotto:
          categoria_principale = prodotto['prodotto_gerarchia'].split('/')[0]
          prodotto['categoria_principale'] = categoria_principale

      return fatturato_grouped_by_prodotto

La prima parte sostanzialmente è in linea con quanto abbiamo fatto nel caso precedente con il metodo gridQueryParameters, imponendo cioè la corrispondenza tra l’anno della fattura e l’anno inserito nei parametri, ed eventualmente anche la corrispondenza con il cliente selezionato. Si noti che in questo caso la query verrà fatta su un’altra tabella, la fatt.fattura_riga, di conseguenza anche la condizione andrà applicata sulle colonne di questa tabella.

Nella query andremo a sommare i vari campi importo, mentre raggrupperemo tutti gli altri valori non sommati. A questo punto il risultato della query sarà una bag piatta, che però non ci limitiamo a prendere così com’è ma vogliamo andare a personalizzare. La tabella prodotto_tipo di Sandbox, infatti, è una tabella gerarchica, dalla quale andremo a metterci da parte innanzitutto il prodotto_tipo (che è l’ultimo livello «figlio» della gerarchia), ma anche la struttura gerarchica intera (prodotto_gerarchia). Infatti, siamo interessati a calcolare un subtotale per macro-categoria, ma non essendo la gerarchia necessariamente uniforme (alcune volte sono presenti 2 livelli, altre 3, ecc), l’unica strada che abbiamo per recuperare la macrocategoria è individuare il primo elemento della prodotto_gerarchia:

categoria_principale = prodotto['prodotto_gerarchia'].split('/')[0]

Ad es. «Giardinaggio/Mobili da Giardino/Sedie» darà come risultato di questa operazione «Giardinaggio». A questo punto andiamo a immagazzinare il dato della categoria_principale direttamente in questa bag piatta di risultati, rendendolo disponibile per l’utilizzo all’interno del nostro metodo gridStruct:

def gridStruct(self,struct):
      r = struct.view().rows()
      r.fieldcell('codice', mm_width=15)
      r.fieldcell('descrizione', mm_width=0)
      r.cell('prodotto_tipo', mm_width=20, name='Tipo prodotto')
      r.cell('categoria_principale', hidden=True, subtotal='Totale {breaker_value}')
      r.cell('prezzo_totale', mm_width=20, name='Fatturato tot.', totalize=True)
      r.cell('iva', mm_width=20, name='IVA tot.',totalize=True)

Puoi provare la stampa direttamente su Sandbox, oppure scaricare i file di stampa qui di seguito.


Allegati: