diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 292548b18..a0a88ac10 100644 --- a/sapl/base/forms.py +++ b/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(''' -
- - -
- ''') +
+ + +
+ ''') ], 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() diff --git a/sapl/base/views.py b/sapl/base/views.py index e61ce624d..b9bc1f2b0 100644 --- a/sapl/base/views.py +++ b/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 diff --git a/sapl/norma/migrations/0042_norma_viewnormasestatisticas.py b/sapl/norma/migrations/0042_norma_viewnormasestatisticas.py new file mode 100644 index 000000000..3179bd6ac --- /dev/null +++ b/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; + """), + ] \ No newline at end of file diff --git a/sapl/norma/models.py b/sapl/norma/models.py index 2fbd96ccf..d4c258d5a 100644 --- a/sapl/norma/models.py +++ b/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, diff --git a/sapl/templates/base/EstatisticasAcessoNormas_filter.html b/sapl/templates/base/EstatisticasAcessoNormas_filter.html index fc094f625..85348960a 100644 --- a/sapl/templates/base/EstatisticasAcessoNormas_filter.html +++ b/sapl/templates/base/EstatisticasAcessoNormas_filter.html @@ -19,30 +19,36 @@ {% else %} {% for mes, normas in normas_mes.items %}
- - - - - - -

Mês: {{ mes }}

- - +
+ + + + - - + + {% for n in normas %} - {% if n.1 > 0 %} + {% if n.norma_count > 0 %} - - - + + + {% endif %} {% endfor %} @@ -53,3 +59,27 @@ {% endif %} {% endif %} {% endblock base_content %} + +{% block extra_js %} + + +{% endblock extra_js %} + + diff --git a/sapl/templates/relatorios/base_relatorio.html b/sapl/templates/relatorios/base_relatorio.html index 542642182..f71508d34 100644 --- a/sapl/templates/relatorios/base_relatorio.html +++ b/sapl/templates/relatorios/base_relatorio.html @@ -34,6 +34,8 @@ string-set: title content(); } } + {% block head_extra_css %} + {% endblock head_extra_css %} @@ -42,6 +44,6 @@ {% block content %} - {% endblock content %} - + {% endblock content %} + \ No newline at end of file diff --git a/sapl/templates/relatorios/relatorio_estatisticas_acesso_normas.html b/sapl/templates/relatorios/relatorio_estatisticas_acesso_normas.html index 06788f4d7..4af79cfb8 100644 --- a/sapl/templates/relatorios/relatorio_estatisticas_acesso_normas.html +++ b/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 %}

Estatísticas de acesso de normas

@@ -15,30 +41,36 @@ {% else %} {% for mes, normas in normas_mes.items %}
-

Mês: {{ mes }}

NormaEmentaPosição AcessosNorma
- {{n.0.tipo.descricao}} - {{n.0.tipo.sigla}} {{n.0.numero}}/{{n.0.ano}} - {{n.0.ementa}}
{{n.0.observacao}}
{{n.1}}{{n.mais_acessadas}}º{{n.norma_count}} + + {{n.norma_tipo_descricao}} nº {{n.norma_numero}}, de {{n.norma_data}} + +
{{n.norma_ementa}} + {% if n.norma_observacao %} + + +
Observações: {{n.norma_observacao}} +
+
+ {% endif %} +
- - - - - -

Mês: {{ mes }}

- - +
+ + + + - - + + {% for n in normas %} - {% if n.1 > 0 %} + {% if n.norma_count > 0 %} + + - - {% endif %} {% endfor %} @@ -47,4 +79,4 @@ {% endfor %} {% endif %} -{% endblock content %} +{% endblock content %}

Mês: {{ mes }}

NormaEmentaPosição AcessosNorma
{{n.mais_acessadas}}º{{n.norma_count}} - {{n.0.tipo.descricao}} - {{n.0.tipo.sigla}} {{n.0.numero}}/{{n.0.ano}} + + {{n.norma_tipo_descricao}} nº {{n.norma_numero}}, de {{n.norma_data}} + +
{{n.norma_ementa}} + {% if n.norma_observacao %} + + +
Observações: {{n.norma_observacao}} +
+
+ {% endif %}
{{n.0.ementa}}
{{n.0.observacao}}
{{n.1}}