@ -1,5 +1,7 @@
import csv
from functools import wraps
from functools import wraps
import hashlib
import hashlib
import io
from itertools import groupby , chain
from itertools import groupby , chain
import logging
import logging
from operator import itemgetter
from operator import itemgetter
@ -30,6 +32,7 @@ from django.db.models import Q
from django . db . models . fields . related import ForeignKey
from django . db . models . fields . related import ForeignKey
from django . forms import BaseForm
from django . forms import BaseForm
from django . forms . widgets import SplitDateTimeWidget
from django . forms . widgets import SplitDateTimeWidget
from django . http . response import JsonResponse , HttpResponse
from django . utils import six , timezone
from django . utils import six , timezone
from django . utils . safestring import mark_safe
from django . utils . safestring import mark_safe
from django . utils . translation import ugettext_lazy as _
from django . utils . translation import ugettext_lazy as _
@ -39,6 +42,7 @@ from floppyforms import ClearableFileInput
import magic
import magic
import requests
import requests
from unipath . path import Path
from unipath . path import Path
from xlsxwriter . workbook import Workbook
from sapl . crispy_layout_mixin import ( form_actions , SaplFormHelper ,
from sapl . crispy_layout_mixin import ( form_actions , SaplFormHelper ,
SaplFormLayout , to_row )
SaplFormLayout , to_row )
@ -1242,7 +1246,7 @@ def get_report_urls_map():
dst_url = reverse ( f " { NAMESPACE } { url . name } " )
dst_url = reverse ( f " { NAMESPACE } { url . name } " )
url_map [ dst_url ] = { " name " : url . name ,
url_map [ dst_url ] = { " name " : url . name ,
" public " : True ,
" public " : True ,
" internal " : True } #TODO: get permissions from AppConfig and fine grained permissions
" internal " : True } # TODO: get permissions from AppConfig and fine grained permissions
return url_map
return url_map
@ -1290,3 +1294,217 @@ def get_path_to_name_report_map():
' /sistema/relatorios/documentos_acessorios ' : ' Documentos Acessórios de Matérias Legislativas ' ,
' /sistema/relatorios/documentos_acessorios ' : ' Documentos Acessórios de Matérias Legislativas ' ,
' /sistema/relatorios/normas-por-autor ' : ' Normas Por Autor '
' /sistema/relatorios/normas-por-autor ' : ' Normas Por Autor '
}
}
class MultiFormatOutputMixin :
formats_impl = ' csv ' , ' xlsx ' , ' json '
queryset_values_for_formats = True
def render_to_response ( self , context , * * response_kwargs ) :
format_result = getattr ( self . request , self . request . method ) . get (
' format ' , None )
if format_result :
if format_result not in self . formats_impl :
raise ValidationError (
' Formato Inválido e/ou não implementado! ' )
object_list = context [ ' object_list ' ]
object_list . query . low_mark = 0
object_list . query . high_mark = 0
return getattr ( self , f ' render_to_ { format_result } ' ) ( context )
return super ( ) . render_to_response ( context , * * response_kwargs )
def render_to_json ( self , context ) :
object_list = context [ ' object_list ' ]
if self . queryset_values_for_formats :
object_list = object_list . values (
* self . fields_report [ ' json ' ] )
data = [ ]
for obj in object_list :
wr = list ( self . _write_row ( obj , ' json ' ) )
if not data :
data . append ( [ wr ] )
continue
if wr [ 0 ] != data [ - 1 ] [ 0 ] [ 0 ] :
data . append ( [ wr ] )
else :
data [ - 1 ] . append ( wr )
for mri , multirows in enumerate ( data ) :
if len ( multirows ) == 1 :
v = multirows [ 0 ]
else :
v = multirows [ 0 ]
for ri , cols in enumerate ( multirows [ 1 : ] ) :
for rc , cell in enumerate ( cols ) :
if v [ rc ] != cell :
v [ rc ] = f ' { v [ rc ] } \r \n { cell } '
data [ mri ] = dict (
map ( lambda i , j : ( i , j ) , self . fields_report [ ' json ' ] , v ) )
json_metadata = {
' headers ' : dict (
map ( lambda i , j : ( i , j ) , self . fields_report [ ' json ' ] , self . _headers ( ' json ' ) ) ) ,
' results ' : data
}
response = JsonResponse ( json_metadata )
response [ ' Content-Disposition ' ] = f ' attachment; filename= " sapl_ { self . request . resolver_match . url_name } .json " '
response [ ' Cache-Control ' ] = ' no-cache '
response [ ' Pragma ' ] = ' no-cache '
response [ ' Expires ' ] = 0
return response
def render_to_csv ( self , context ) :
response = HttpResponse ( content_type = ' text/csv ' )
response [ ' Content-Disposition ' ] = f ' attachment; filename= " sapl_ { self . request . resolver_match . url_name } .csv " '
response [ ' Cache-Control ' ] = ' no-cache '
response [ ' Pragma ' ] = ' no-cache '
response [ ' Expires ' ] = 0
writer = csv . writer ( response , delimiter = " ; " ,
quoting = csv . QUOTE_NONNUMERIC )
object_list = context [ ' object_list ' ]
if self . queryset_values_for_formats :
object_list = object_list . values (
* self . fields_report [ ' csv ' ] )
data = [ [ list ( self . _headers ( ' csv ' ) ) ] , ]
for obj in object_list :
wr = list ( self . _write_row ( obj , ' csv ' ) )
if wr [ 0 ] != data [ - 1 ] [ 0 ] [ 0 ] :
data . append ( [ wr ] )
else :
data [ - 1 ] . append ( wr )
for mri , multirows in enumerate ( data ) :
if len ( multirows ) == 1 :
writer . writerow ( multirows [ 0 ] )
else :
v = multirows [ 0 ]
for ri , cols in enumerate ( multirows [ 1 : ] ) :
for rc , cell in enumerate ( cols ) :
if v [ rc ] != cell :
v [ rc ] = f ' { v [ rc ] } \r \n { cell } '
writer . writerow ( v )
return response
def render_to_xlsx ( self , context ) :
object_list = context [ ' object_list ' ]
if self . queryset_values_for_formats :
object_list = object_list . values (
* self . fields_report [ ' xlsx ' ] )
data = [ [ list ( self . _headers ( ' xlsx ' ) ) ] , ]
for obj in object_list :
wr = list ( self . _write_row ( obj , ' xlsx ' ) )
if wr [ 0 ] != data [ - 1 ] [ 0 ] [ 0 ] :
data . append ( [ wr ] )
else :
data [ - 1 ] . append ( wr )
output = io . BytesIO ( )
wb = Workbook ( output , { ' in_memory ' : True } )
ws = wb . add_worksheet ( )
for mri , multirows in enumerate ( data ) :
if len ( multirows ) == 1 :
for rc , cell in enumerate ( multirows [ 0 ] ) :
ws . write ( mri , rc , cell )
else :
v = multirows [ 0 ]
for ri , cols in enumerate ( multirows [ 1 : ] ) :
for rc , cell in enumerate ( cols ) :
if v [ rc ] != cell :
v [ rc ] = f ' { v [ rc ] } \r \n { cell } '
for rc , cell in enumerate ( v ) :
ws . write ( mri , rc , cell )
ws . autofit ( )
wb . close ( )
output . seek ( 0 )
response = HttpResponse ( output . read (
) , content_type = " application/vnd.openxmlformats-officedocument.spreadsheetml.sheet " )
response [ ' Content-Disposition ' ] = f ' attachment; filename= " sapl_ { self . request . resolver_match . url_name } .xlsx " '
response [ ' Cache-Control ' ] = ' no-cache '
response [ ' Pragma ' ] = ' no-cache '
response [ ' Expires ' ] = 0
output . close ( )
return response
def _write_row ( self , obj , format_result ) :
for fname in self . fields_report [ format_result ] :
if hasattr ( self , f ' hook_ { fname } ' ) :
v = getattr ( self , f ' hook_ { fname } ' ) ( obj )
yield v
continue
if isinstance ( obj , dict ) :
yield obj [ fname ]
continue
fname = fname . split ( ' __ ' )
v = obj
for fp in fname :
v = getattr ( v , fp )
if hasattr ( v , ' all ' ) :
v = ' - ' . join ( map ( lambda x : str ( x ) , v . all ( ) ) )
yield v
def _headers ( self , format_result ) :
for fname in self . fields_report [ format_result ] :
verbose_name = [ ]
if hasattr ( self , f ' hook_header_ { fname } ' ) :
h = getattr ( self , f ' hook_header_ { fname } ' ) ( )
yield h
continue
fname = fname . split ( ' __ ' )
m = self . model
for fp in fname :
f = m . _meta . get_field ( fp )
vn = str ( f . verbose_name ) if hasattr ( f , ' verbose_name ' ) else fp
if f . is_relation :
m = f . related_model
if m == self . model :
m = f . field . model
if vn == fp :
vn = str ( m . _meta . verbose_name_plural )
verbose_name . append ( vn . strip ( ) )
verbose_name = ' / ' . join ( verbose_name ) . strip ( )
yield f ' { verbose_name } '