Browse Source

refactor: Relatório de Estatísticas de Normas

- inclui no filtro meses e mais acessadas
- altera layout dos resultados html e pdf
- cria view table para otmizar e agilizar a computação dos dados
pull/3605/head
LeandroJatai 2 years ago
parent
commit
148cf63a1e
  1. 37
      sapl/base/forms.py
  2. 48
      sapl/base/views.py
  3. 56
      sapl/norma/migrations/0042_norma_viewnormasestatisticas.py
  4. 35
      sapl/norma/models.py
  5. 64
      sapl/templates/base/EstatisticasAcessoNormas_filter.html
  6. 6
      sapl/templates/relatorios/base_relatorio.html
  7. 64
      sapl/templates/relatorios/relatorio_estatisticas_acesso_normas.html

37
sapl/base/forms.py

@ -28,7 +28,7 @@ from sapl.crispy_layout_mixin import (form_actions, to_column, to_row,
from sapl.materia.models import (DocumentoAcessorio, MateriaEmTramitacao,
MateriaLegislativa, UnidadeTramitacao,
StatusTramitacao)
from sapl.norma.models import NormaJuridica
from sapl.norma.models import NormaJuridica, NormaEstatisticas
from sapl.parlamentares.models import Partido, SessaoLegislativa,\
Parlamentar, Votante
from sapl.protocoloadm.models import DocumentoAdministrativo
@ -40,7 +40,7 @@ from sapl.utils import (autor_label, autor_modal, ChoiceWithoutValidationField,
FilterOverridesMetaMixin, FileFieldCheckMixin,
ImageThumbnailFileInput, qs_override_django_filter,
RANGE_ANOS, YES_NO_CHOICES, choice_tipos_normas,
GoogleRecapthaMixin, parlamentares_ativos)
GoogleRecapthaMixin, parlamentares_ativos, RANGE_MESES)
from .models import AppConfig, CasaLegislativa
@ -903,11 +903,11 @@ class RelatorioNormasMesFilterSet(django_filters.FilterSet):
buttons = FormActions(
*[
HTML('''
<div class="form-check">
<input name="relatorio" type="checkbox" class="form-check-input" id="relatorio">
<label class="form-check-label" for="relatorio">Gerar relatório PDF</label>
</div>
''')
<div class="form-check col-auto">
<input name="relatorio" type="checkbox" class="form-check-input" id="relatorio">
<label class="form-check-label" for="relatorio">Gerar relatório PDF</label>
</div>
''')
],
Submit('pesquisar', _('Pesquisar'), css_class='float-right',
onclick='return true;'),
@ -934,14 +934,29 @@ class EstatisticasAcessoNormasForm(Form):
choices=RANGE_ANOS,
initial=timezone.now().year)
mes = forms.ChoiceField(required=False,
label='Mês de acesso',
choices=[('', 'Todos os Meses')] + RANGE_MESES,
initial='')
mais_acessadas = forms.ChoiceField(required=False,
label='Mais Acessadas',
choices=[
(5, '005 mais acessadas'),
(10, '010 mais acessadas'),
(50, '050 mais acessadas'),
(100, '100 mais acessadas'),
],
initial=5)
class Meta:
fields = ['ano']
fields = ['ano', 'mes', 'mais_acessadas']
def __init__(self, *args, **kwargs):
super(EstatisticasAcessoNormasForm, self).__init__(
*args, **kwargs)
row1 = to_row([('ano', 12)])
row1 = to_row([('ano', 3), ('mes', 6), ('mais_acessadas', 3), ])
buttons = FormActions(
*[
@ -963,6 +978,10 @@ class EstatisticasAcessoNormasForm(Form):
Fieldset(_('Normas por acessos nos meses do ano.'),
row1, buttons)
)
self.fields['ano'].choices = NormaEstatisticas.objects.order_by(
'-ano').distinct().values_list('ano', 'ano') or [
(timezone.now().year, timezone.now().year)
]
def clean(self):
super(EstatisticasAcessoNormasForm, self).clean()

48
sapl/base/views.py

@ -48,7 +48,8 @@ from sapl.crud.base import CrudAux, make_pagination, Crud,\
from sapl.materia.models import (Anexada, Autoria, DocumentoAcessorio, MateriaEmTramitacao, MateriaLegislativa,
Proposicao, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, UnidadeTramitacao,
MateriaAssunto)
from sapl.norma.models import NormaJuridica, TipoNormaJuridica
from sapl.norma.models import NormaJuridica, TipoNormaJuridica,\
NormaEstatisticas, ViewNormasEstatisticas
from sapl.parlamentares.models import (
Filiacao, Legislatura, Mandato, Parlamentar, SessaoLegislativa)
from sapl.protocoloadm.models import (Anexado, DocumentoAdministrativo, Protocolo, StatusTramitacaoAdministrativo,
@ -1191,7 +1192,7 @@ class EstatisticasAcessoNormas(TemplateView):
def get(self, request, *args, **kwargs):
context = super(EstatisticasAcessoNormas,
self).get_context_data(**kwargs)
context['title'] = _('Normas')
context['title'] = _('Estatísticas de Acesso às Normas Jurídicas')
form = EstatisticasAcessoNormasForm(request.GET or None)
context['form'] = form
@ -1200,33 +1201,32 @@ class EstatisticasAcessoNormas(TemplateView):
return self.render_to_response(context)
context['ano'] = self.request.GET['ano']
query = '''
select norma_id, ano, extract(month from horario_acesso) as mes, count(*)
from norma_normaestatisticas
where ano = {}
group by mes, ano, norma_id
order by mes desc;
'''.format(context['ano'])
cursor = connection.cursor()
cursor.execute(query)
rows = cursor.fetchall()
context['mes'] = self.request.GET.get('mes', '')
context['mais_acessadas'] = int(
self.request.GET.get('mais_acessadas', 5))
if not context['mes']:
context['mais_acessadas'] = 10
params = {
'ano_est': context['ano'],
'mais_acessadas__lte': context['mais_acessadas']
}
if context['mes']:
params['mes_est'] = context['mes']
estatisticas = ViewNormasEstatisticas.objects.filter(
**params
)
normas_mes = collections.OrderedDict()
meses = {1: 'Janeiro', 2: 'Fevereiro', 3: 'Março', 4: 'Abril', 5: 'Maio', 6: 'Junho',
7: 'Julho', 8: 'Agosto', 9: 'Setembro', 10: 'Outubro', 11: 'Novembro', 12: 'Dezembro'}
for row in rows:
if not meses[int(row[2])] in normas_mes:
normas_mes[meses[int(row[2])]] = []
norma_est = [NormaJuridica.objects.get(id=row[0]), row[3]]
normas_mes[meses[int(row[2])]].append(norma_est)
# Ordena por acesso e limita em 5
for n in normas_mes:
sorted_by_value = sorted(
normas_mes[n], key=lambda kv: kv[1], reverse=True)
normas_mes[n] = sorted_by_value[0:5]
for norma in estatisticas:
if not meses[norma.mes_est] in normas_mes:
normas_mes[meses[norma.mes_est]] = []
normas_mes[meses[norma.mes_est]].append(norma)
context['normas_mes'] = normas_mes

56
sapl/norma/migrations/0042_norma_viewnormasestatisticas.py

@ -0,0 +1,56 @@
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('norma', '0041_auto_20220814_2235'),
]
operations = [
migrations.RunSQL("""
drop view if exists norma_viewnormasestatisticas;
create or replace view norma_viewnormasestatisticas as
select row_number() OVER() as id, * from (
SELECT
ROW_NUMBER() OVER (
PARTITION BY ano_est, mes_est
ORDER BY ano_est, mes_est desc, norma_count desc
)::smallint AS "mais_acessadas"
,
*
from (
SELECT
"norma_normaestatisticas"."norma_id" as norma_id,
extract(year from horario_acesso) as ano_est,
extract(month from horario_acesso) as mes_est,
count(*) as norma_count,
"norma_normajuridica"."numero" as norma_numero,
"norma_normajuridica"."ano" as norma_ano,
"norma_normajuridica"."data" as norma_data,
"norma_tiponormajuridica"."sigla" as norma_tipo_sigla,
"norma_tiponormajuridica"."descricao" as norma_tipo_descricao,
"norma_normajuridica"."ementa" as norma_ementa,
"norma_normajuridica"."observacao" as norma_observacao
from norma_normaestatisticas
INNER JOIN "norma_normajuridica" ON ("norma_normaestatisticas"."norma_id" = "norma_normajuridica"."id")
INNER JOIN "norma_tiponormajuridica" ON ("norma_normajuridica"."tipo_id" = "norma_tiponormajuridica"."id")
group by
"norma_normaestatisticas"."norma_id",
ano_est,
mes_est,
norma_numero,
norma_ano,
norma_data,
norma_ementa,
norma_observacao,
norma_tipo_sigla,
norma_tipo_descricao
order by ano_est, mes_est desc, norma_count desc, norma_ano desc
) as subquery
) as query_final
order by ano_est, mes_est desc, mais_acessadas;
"""),
]

35
sapl/norma/models.py

@ -311,6 +311,41 @@ class NormaEstatisticas(models.Model):
'usuario': self.usuario, 'norma': self.norma}
class ViewNormasEstatisticas(models.Model):
mais_acessadas = models.PositiveSmallIntegerField(
verbose_name=_('Mais Acessadas'))
ano_est = models.PositiveSmallIntegerField(
verbose_name=_('Ano do Registro de Acesso'))
mes_est = models.PositiveSmallIntegerField(
verbose_name=_('Mês do Registro de Acesso'))
norma_id = models.BigIntegerField(verbose_name=_('Id da Norma'))
norma_count = models.PositiveSmallIntegerField(
verbose_name=_('Mês do Registro de Acesso'))
norma_numero = models.CharField(
max_length=8, verbose_name=_('Número da Norma'))
norma_ano = models.PositiveSmallIntegerField(
verbose_name=_('Ano da Norma'))
norma_ementa = models.TextField(verbose_name=_('Ementa'))
norma_observacao = models.TextField(
blank=True, verbose_name=_('Observação'))
norma_tipo_sigla = models.CharField(
max_length=3,
verbose_name=_('Sigla do Tipo da Norma'))
norma_tipo_descricao = models.CharField(
max_length=50, verbose_name=_('Descrição do Tipo da Norma'))
norma_data = models.DateField(verbose_name=_('Data da Norma'))
class Meta:
managed = False
db_table = "norma_viewnormasestatisticas"
@reversion.register()
class AutoriaNorma(models.Model):
autor = models.ForeignKey(Autor,

64
sapl/templates/base/EstatisticasAcessoNormas_filter.html

@ -19,30 +19,36 @@
{% else %}
{% for mes, normas in normas_mes.items %}
<div style="overflow:auto; ">
<table class="table table-bordered table-hover" style="margin-bottom: 0px;">
<thead class="thead-default">
<tr>
<th><h3 style="text-align:center;">Mês: {{ mes }}</h3></th>
</tr>
</thead>
</table>
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 30px;">
<thead class="thead-default" >
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 30px;">
<thead class="thead-default" >
<tr>
<th colspan=3><h3 style="text-align:center;">Mês: {{ mes }}</h3></th>
</tr>
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
<th>Posição</th>
<th>Acessos</th>
<th>Norma</th>
</tr>
</thead>
<tbody>
{% for n in normas %}
{% if n.1 > 0 %}
{% if n.norma_count > 0 %}
<tr>
<td><a href="{% url 'sapl.norma:normajuridica_detail' n.0.pk %}">
{{n.0.tipo.descricao}} - {{n.0.tipo.sigla}} {{n.0.numero}}/{{n.0.ano}}
</a></td>
<td>{{n.0.ementa}}<br>{{n.0.observacao}}</td>
<td>{{n.1}}</td>
<td align="center">{{n.mais_acessadas}}º</td>
<td align="center">{{n.norma_count}}</td>
<td>
<a href="{% url 'sapl.norma:normajuridica_detail' n.norma_id %}">
{{n.norma_tipo_descricao}} nº {{n.norma_numero}}, de {{n.norma_data}}
</a>
<br>{{n.norma_ementa}}
{% if n.norma_observacao %}
<small>
<i>
<br><strong>Observações:</strong> {{n.norma_observacao}}
</i>
</small>
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
@ -53,3 +59,27 @@
{% endif %}
{% endif %}
{% endblock base_content %}
{% block extra_js %}
<script type="text/javascript">
$(document).ready(function(){
$('#id_mes').change(function(event) {
if (event.currentTarget.selectedOptions[0].value === '') {
$('#id_mais_acessadas').val('5')
$('#id_mais_acessadas')[0].options[2].setAttribute('disabled', true)
$('#id_mais_acessadas')[0].options[3].setAttribute('disabled', true)
} else {
$('#id_mais_acessadas')[0].options[2].removeAttribute('disabled')
$('#id_mais_acessadas')[0].options[3].removeAttribute('disabled')
}
//$('#id_mais_acessadas').prop('disabled', event.currentTarget.selectedOptions[0].value === '')
}).trigger('change')
})
</script>
{% endblock extra_js %}

6
sapl/templates/relatorios/base_relatorio.html

@ -34,6 +34,8 @@
string-set: title content();
}
}
{% block head_extra_css %}
{% endblock head_extra_css %}
</style>
<link rel="stylesheet" href="{% static '/sapl/css/relatorio.css'%}">
</head>
@ -42,6 +44,6 @@
{% block content %}
{% endblock content %}
{% endblock content %}
</body>

64
sapl/templates/relatorios/relatorio_estatisticas_acesso_normas.html

@ -3,6 +3,32 @@
{% load common_tags %}
{% load static %}
{% block head_extra_css %}
@page {
margin-left: 1.5cm;
margin-right: 1.5cm;
}
table {
border-collapse: collapse;
font-size: 10pt;
margin-bottom: 30px
}
td, th {
border: 1px solid black;
padding: 5px;
vertical-align: middle;
}
th {
text-align: center;
padding: 10px 3px;
}
td:nth-child(1), td:nth-child(2) {
text-align: center;
}
{% endblock head_extra_css %}
{% block content %}
<h2>Estatísticas de acesso de normas</h2>
@ -15,30 +41,36 @@
{% else %}
{% for mes, normas in normas_mes.items %}
<div style="overflow:auto; ">
<table class="table table-bordered table-hover" style="margin-bottom: 0px;">
<thead class="thead-default">
<tr>
<th><h3 style="text-align:center;">Mês: {{ mes }}</h3></th>
</tr>
</thead>
</table>
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 30px;">
<thead class="thead-default" >
<table class="table table-bordered">
<thead class="thead-default">
<tr>
<th colspan=3><h3>Mês: {{ mes }}</h3></th>
</tr>
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
<th>Posição</th>
<th>Acessos</th>
<th>Norma</th>
</tr>
</thead>
<tbody>
{% for n in normas %}
{% if n.1 > 0 %}
{% if n.norma_count > 0 %}
<tr>
<td>{{n.mais_acessadas}}º</td>
<td>{{n.norma_count}}</td>
<td>
{{n.0.tipo.descricao}} - {{n.0.tipo.sigla}} {{n.0.numero}}/{{n.0.ano}}
<strong>
{{n.norma_tipo_descricao}} nº {{n.norma_numero}}, de {{n.norma_data}}
</strong>
<br>{{n.norma_ementa}}
{% if n.norma_observacao %}
<small>
<i>
<br><strong>Observações:</strong> {{n.norma_observacao}}
</i>
</small>
{% endif %}
</td>
<td>{{n.0.ementa}}<br>{{n.0.observacao}}</td>
<td>{{n.1}}</td>
</tr>
{% endif %}
{% endfor %}
@ -47,4 +79,4 @@
</div>
{% endfor %}
{% endif %}
{% endblock content %}
{% endblock content %}

Loading…
Cancel
Save